#!/usr/bin/env php  phar-versions.phpW f0gؤdictionaries/CallMap.phpW fׯ!dictionaries/CallMap_71_delta.phpW f0!dictionaries/CallMap_72_delta.php{LW f{L1>"dictionaries/ManualPropertyMap.phpW f[ۤ!dictionaries/CallMap_80_delta.php.sW f.s.X8<dictionaries/scripts/update_signaturemap_from_other_tool.phpW f}!dictionaries/CallMap_73_delta.php4 W f4 XnQ#dictionaries/CallMap_historical.php@W f@d-!dictionaries/CallMap_82_delta.phpW f,O%dictionaries/InternalTaintSinkMap.phpYW fYa!dictionaries/CallMap_74_delta.php_W f_Adictionaries/PropertyMap.phpEW fE0}$dictionaries/ImpureFunctionsList.phpW fǤ!dictionaries/CallMap_81_delta.phpW fQP!dictionaries/CallMap_83_delta.phpW f=vendor/fidry/cpu-core-counter/src/NumberOfCpuCoreNotFound.php(W f(Mf ;vendor/fidry/cpu-core-counter/src/ParallelisationResult.phpW f4"4vendor/fidry/cpu-core-counter/src/CpuCoreCounter.php!W f!i?vendor/fidry/cpu-core-counter/src/Executor/ProcOpenExecutor.phpW fɤ>vendor/fidry/cpu-core-counter/src/Executor/ProcessExecutor.phpW f,M;vendor/fidry/cpu-core-counter/src/Finder/FinderRegistry.phpW fYCvendor/fidry/cpu-core-counter/src/Finder/OnlyInPowerShellFinder.phpW fJAvendor/fidry/cpu-core-counter/src/Finder/OnlyOnOSFamilyFinder.phpW fHb:vendor/fidry/cpu-core-counter/src/Finder/CpuCoreFinder.phpW fO&{?vendor/fidry/cpu-core-counter/src/Finder/LscpuLogicalFinder.phpQW fQDvendor/fidry/cpu-core-counter/src/Finder/CmiCmdletPhysicalFinder.phpW fBCvendor/fidry/cpu-core-counter/src/Finder/CmiCmdletLogicalFinder.phpW f|Ť@vendor/fidry/cpu-core-counter/src/Finder/LscpuPhysicalFinder.php|W f|Ť>vendor/fidry/cpu-core-counter/src/Finder/WmicLogicalFinder.phpW f%w0>vendor/fidry/cpu-core-counter/src/Finder/EnvVariableFinder.phpW foNlۤ=vendor/fidry/cpu-core-counter/src/Finder/HwPhysicalFinder.php~W f~X=vendor/fidry/cpu-core-counter/src/Finder/NProcessorFinder.phpW fT&?vendor/fidry/cpu-core-counter/src/Finder/DummyCpuCoreFinder.phpEW fE <vendor/fidry/cpu-core-counter/src/Finder/HwLogicalFinder.phpzW fzs >vendor/fidry/cpu-core-counter/src/Finder/_NProcessorFinder.phpW f¤>vendor/fidry/cpu-core-counter/src/Finder/NullCpuCoreFinder.phpW fG`?vendor/fidry/cpu-core-counter/src/Finder/WmicPhysicalFinder.phpW fY Ivendor/fidry/cpu-core-counter/src/Finder/WindowsRegistryLogicalFinder.phpW f'H!Avendor/fidry/cpu-core-counter/src/Finder/SkipOnOSFamilyFinder.phpW fW6":vendor/fidry/cpu-core-counter/src/Finder/CpuInfoFinder.php" W f" d@vendor/fidry/cpu-core-counter/src/Finder/ProcOpenBasedFinder.php W f $'n8vendor/fidry/cpu-core-counter/src/Finder/NProcFinder.phpW fv N/vendor/fidry/cpu-core-counter/src/Diagnoser.phpW fUC.vendor/fidry/cpu-core-counter/bin/diagnose.phpW f;Ȥ+vendor/fidry/cpu-core-counter/bin/trace.phpNW fNhN-vendor/fidry/cpu-core-counter/bin/execute.phpwW fw%vendor/netresearch/jsonmapper/LICENSER(W fR((}0vendor/netresearch/jsonmapper/src/JsonMapper.php'yW f'y16:vendor/netresearch/jsonmapper/src/JsonMapper/Exception.php0W f0('vendor/dnoegel/php-xdg-base-dir/LICENSE!W f!W&+vendor/dnoegel/php-xdg-base-dir/src/Xdg.php W f ܆ܤvendor/psr/log/LICENSE=W f=pO%vendor/psr/log/Psr/Log/NullLogger.phpW f};)vendor/psr/log/Psr/Log/AbstractLogger.php0 W f0 aW+vendor/psr/log/Psr/Log/LoggerAwareTrait.phpW fb{٤#vendor/psr/log/Psr/Log/LogLevel.phpPW fP]&vendor/psr/log/Psr/Log/LoggerTrait.phpf W ff X/vendor/psr/log/Psr/Log/LoggerAwareInterface.php@W f@V *vendor/psr/log/Psr/Log/LoggerInterface.php9 W f9 *!3vendor/psr/log/Psr/Log/InvalidArgumentException.phpwW fwvendor/psr/container/LICENSEyW fyOp/vendor/psr/container/src/ContainerInterface.php&W f&DJ7vendor/psr/container/src/NotFoundExceptionInterface.phpW f{z8vendor/psr/container/src/ContainerExceptionInterface.phpW f[4vendor/felixfbecker/language-server-protocol/LICENSEW f>9=vendor/felixfbecker/language-server-protocol/src/Location.php)W f)ܖFvendor/felixfbecker/language-server-protocol/src/PackageDescriptor.phpW fѤjvendor/felixfbecker/language-server-protocol/src/ShowMessageRequestClientCapabilitiesMessageActionItem.php W f DWvendor/felixfbecker/language-server-protocol/src/TextDocumentSyncClientCapabilities.phpJW fJRIvendor/felixfbecker/language-server-protocol/src/ReferenceInformation.php`W f`ҤEvendor/felixfbecker/language-server-protocol/src/TextDocumentItem.phpW ft`vendor/felixfbecker/language-server-protocol/src/WorkspaceSymbolClientCapabilitiesTagSupport.phpW fֺOvendor/felixfbecker/language-server-protocol/src/MarkdownClientCapabilities.phpW fL̤Cvendor/felixfbecker/language-server-protocol/src/CodeActionKind.phpW fUvendor/felixfbecker/language-server-protocol/src/SelectionRangeClientCapabilities.phpJW fJudGmvendor/felixfbecker/language-server-protocol/src/CompletionClientCapabilitiesCompletionItemResolveSupport.phpW fCvendor/felixfbecker/language-server-protocol/src/CompletionItem.phpW f?yNvendor/felixfbecker/language-server-protocol/src/MonikerClientCapabilities.phpAW fA-'$=vendor/felixfbecker/language-server-protocol/src/Position.phpW fH9R#_vendor/felixfbecker/language-server-protocol/src/CompletionClientCapabilitiesCompletionItem.phpW fSJvendor/felixfbecker/language-server-protocol/src/CompletionTriggerKind.php6W f6ewUvendor/felixfbecker/language-server-protocol/src/DocumentSymbolClientCapabilities.phpW fp?vendor/felixfbecker/language-server-protocol/src/Diagnostic.php W f lMQvendor/felixfbecker/language-server-protocol/src/DefinitionClientCapabilities.phpoW foFvendor/felixfbecker/language-server-protocol/src/CompletionContext.php$W f$WBvendor/felixfbecker/language-server-protocol/src/WorkspaceEdit.php> W f> y*fFvendor/felixfbecker/language-server-protocol/src/DocumentHighlight.phpW f7Ĥ:vendor/felixfbecker/language-server-protocol/src/Hover.phpW f'Ivendor/felixfbecker/language-server-protocol/src/ParameterInformation.phpW fS0?vendor/felixfbecker/language-server-protocol/src/ClientInfo.php W f Lvendor/felixfbecker/language-server-protocol/src/TextDocumentSyncOptions.phpW f@f?vendor/felixfbecker/language-server-protocol/src/LogMessage.php6W f6dN?vendor/felixfbecker/language-server-protocol/src/CodeAction.phpW f/PNvendor/felixfbecker/language-server-protocol/src/SymbolLocationInformation.phpzW fzqEvendor/felixfbecker/language-server-protocol/src/InitializeResult.phpW fȝ^vendor/felixfbecker/language-server-protocol/src/SemanticTokensWorkspaceClientCapabilities.phpW fHXvendor/felixfbecker/language-server-protocol/src/CodeLensWorkspaceClientCapabilities.phpW fPvendor/felixfbecker/language-server-protocol/src/ReferenceClientCapabilities.phpwW fw lGCvendor/felixfbecker/language-server-protocol/src/FileChangeType.phpTW fTͣb=Evendor/felixfbecker/language-server-protocol/src/InsertTextFormat.phpW f0E|vendor/felixfbecker/language-server-protocol/src/SignatureHelpClientCapabilitiesSignatureInformationParameterInformation.php!W f!t*Hvendor/felixfbecker/language-server-protocol/src/DependencyReference.phpW fP*mJvendor/felixfbecker/language-server-protocol/src/ResourceOperationKind.phpW f/zLvendor/felixfbecker/language-server-protocol/src/HoverClientCapabilities.phpEW fE >vendor/felixfbecker/language-server-protocol/src/SymbolTag.php-W f-]S>vendor/felixfbecker/language-server-protocol/src/FileEvent.phpW f" Dvendor/felixfbecker/language-server-protocol/src/CodeDescription.phpW f_vendor/felixfbecker/language-server-protocol/src/DocumentSymbolClientCapabilitiesTagSupport.phpKW fKV?tvendor/felixfbecker/language-server-protocol/src/CompletionClientCapabilitiesCompletionItemInsertTextModeSupport.phpW f=ҙKvendor/felixfbecker/language-server-protocol/src/TextDocumentIdentifier.phpW fJvendor/felixfbecker/language-server-protocol/src/ExecuteCommandOptions.phpgW fgXFvendor/felixfbecker/language-server-protocol/src/CompletionItemTag.phpW fn&Svendor/felixfbecker/language-server-protocol/src/ShowDocumentClientCapabilities.phpVW fVJÆwGvendor/felixfbecker/language-server-protocol/src/DiagnosticSeverity.phpkW fk HEvendor/felixfbecker/language-server-protocol/src/ReferenceContext.phpW fĤEvendor/felixfbecker/language-server-protocol/src/SymbolDescriptor.phpW fĤ:vendor/felixfbecker/language-server-protocol/src/Range.phpW f|g'Gvendor/felixfbecker/language-server-protocol/src/ClientCapabilities.phpW fOFvendor/felixfbecker/language-server-protocol/src/CodeActionContext.php,W f,VQvendor/felixfbecker/language-server-protocol/src/CodeActionClientCapabilities.php W f ۤ<vendor/felixfbecker/language-server-protocol/src/Command.phpW f(Rvendor/felixfbecker/language-server-protocol/src/PrepareSupportDefaultBehavior.php W f -)@vendor/felixfbecker/language-server-protocol/src/SaveOptions.php'W f'iiNvendor/felixfbecker/language-server-protocol/src/ClientCapabilitiesGeneral.phpW f[ ܤ_vendor/felixfbecker/language-server-protocol/src/CodeActionClientCapabilitiesResolveSupport.phpW f+\LTvendor/felixfbecker/language-server-protocol/src/DocumentColorClientCapabilities.phpW fG=Bvendor/felixfbecker/language-server-protocol/src/SignatureHelp.php$W f$Hvendor/felixfbecker/language-server-protocol/src/FailureHandlingKind.php=W f=(^ ^vendor/felixfbecker/language-server-protocol/src/ClientCapabilitiesWorkspaceFileOperations.phpnW fn7=vendor/felixfbecker/language-server-protocol/src/CodeLens.phpW fd]Ovendor/felixfbecker/language-server-protocol/src/CompletionItemLabelDetails.php~W f~u*ROvendor/felixfbecker/language-server-protocol/src/InitializeResultServerInfo.phpW f֫IBvendor/felixfbecker/language-server-protocol/src/MarkupContent.phpW f\yPvendor/felixfbecker/language-server-protocol/src/ClientCapabilitiesWorkspace.phpiW fi oXvendor/felixfbecker/language-server-protocol/src/DocumentHighlightClientCapabilities.phpW fF.rivendor/felixfbecker/language-server-protocol/src/CodeActionClientCapabilitiesCodeActionLiteralSupport.phpW fbTvendor/felixfbecker/language-server-protocol/src/WorkspaceEditClientCapabilities.phpW f]Ivendor/felixfbecker/language-server-protocol/src/TextDocumentSyncKind.php>W f>>Mvendor/felixfbecker/language-server-protocol/src/RenameClientCapabilities.phpW fOYvendor/felixfbecker/language-server-protocol/src/ShowMessageRequestClientCapabilities.phpW fWVGvendor/felixfbecker/language-server-protocol/src/CompletionItemKind.phpW f_Tvendor/felixfbecker/language-server-protocol/src/SignatureHelpClientCapabilities.phpW fr]vendor/felixfbecker/language-server-protocol/src/SemanticTokensClientCapabilitiesRequests.phpW f6ȻDvendor/felixfbecker/language-server-protocol/src/CodeLensOptions.phpqW fq|`vendor/felixfbecker/language-server-protocol/src/WorkspaceSymbolClientCapabilitiesSymbolKind.phpW f9Svendor/felixfbecker/language-server-protocol/src/TextDocumentContentChangeEvent.phprW frTvendor/felixfbecker/language-server-protocol/src/CallHierarchyClientCapabilities.phpHW fHD8BdVvendor/felixfbecker/language-server-protocol/src/WorkspaceSymbolClientCapabilities.phpW fٱXBvendor/felixfbecker/language-server-protocol/src/DiagnosticTag.php@W f@ٓihvendor/felixfbecker/language-server-protocol/src/SignatureHelpClientCapabilitiesSignatureInformation.phpW f_ӤFvendor/felixfbecker/language-server-protocol/src/SymbolInformation.phpW fδuTvendor/felixfbecker/language-server-protocol/src/DocumentOnTypeFormattingOptions.phpW fwcMvendor/felixfbecker/language-server-protocol/src/ClientCapabilitiesWindow.phpEW fE-_vendor/felixfbecker/language-server-protocol/src/CompletionClientCapabilitiesCompletionList.phpW f' Ĥ?vendor/felixfbecker/language-server-protocol/src/SymbolKind.phpW fcvendor/felixfbecker/language-server-protocol/src/PublishDiagnosticsClientCapabilitiesTagSupport.phpW f@o]vendor/felixfbecker/language-server-protocol/src/DidChangeConfigurationClientCapabilities.phpW fFqRvendor/felixfbecker/language-server-protocol/src/DeclarationClientCapabilities.phpW fmUvendor/felixfbecker/language-server-protocol/src/SemanticTokensClientCapabilities.phpW f>vendor/felixfbecker/language-server-protocol/src/ErrorCode.phpiW fif~\vendor/felixfbecker/language-server-protocol/src/DidChangeWatchedFilesClientCapabilities.phpW fYvendor/felixfbecker/language-server-protocol/src/RegularExpressionsClientCapabilities.php[W f[ ESvendor/felixfbecker/language-server-protocol/src/FoldingRangeClientCapabilities.phpW fѷIvendor/felixfbecker/language-server-protocol/src/SignatureHelpOptions.phpW fm_vendor/felixfbecker/language-server-protocol/src/DocumentOnTypeFormattingClientCapabilities.phpW f8Gvendor/felixfbecker/language-server-protocol/src/ContentChangeEvent.phpfW ff2.Svendor/felixfbecker/language-server-protocol/src/DocumentLinkClientCapabilities.phpW fP kUvendor/felixfbecker/language-server-protocol/src/TypeDefinitionClientCapabilities.phpW fKdOvendor/felixfbecker/language-server-protocol/src/CodeLensClientCapabilities.phpW fkxYvendor/felixfbecker/language-server-protocol/src/LinkedEditingRangeClientCapabilities.phpLW fLKJvendor/felixfbecker/language-server-protocol/src/CodeActionTriggerKind.phpW f Svendor/felixfbecker/language-server-protocol/src/TextDocumentClientCapabilities.php+W f+vtFvendor/felixfbecker/language-server-protocol/src/FormattingOptions.phpW fr{ZJAvendor/felixfbecker/language-server-protocol/src/MarkedString.phpW fڧUGvendor/felixfbecker/language-server-protocol/src/ServerCapabilities.php W f y`Dvendor/felixfbecker/language-server-protocol/src/WorkspaceFolder.phpW fAYvendor/felixfbecker/language-server-protocol/src/PublishDiagnosticsClientCapabilities.phpW fssJvendor/felixfbecker/language-server-protocol/src/DocumentHighlightKind.phpW f?vendor/felixfbecker/language-server-protocol/src/MarkupKind.php$W f$qEvendor/felixfbecker/language-server-protocol/src/ChangeAnnotation.phpW f^Cvendor/felixfbecker/language-server-protocol/src/InsertTextMode.phpW fe=vendor/felixfbecker/language-server-protocol/src/LogTrace.phpW fW >^vendor/felixfbecker/language-server-protocol/src/DocumentRangeFormattingClientCapabilities.phpW fATivendor/felixfbecker/language-server-protocol/src/CompletionClientCapabilitiesCompletionItemTagSupport.phpW fEgQvendor/felixfbecker/language-server-protocol/src/DiagnosticRelatedInformation.phpW f*EFvendor/felixfbecker/language-server-protocol/src/CompletionOptions.phpW fg,kvendor/felixfbecker/language-server-protocol/src/WorkspaceEditClientCapabilitiesChangeAnnotationSupport.phpW fYwQvendor/felixfbecker/language-server-protocol/src/CompletionClientCapabilities.phplW fl dvendor/felixfbecker/language-server-protocol/src/WorkspaceSymbolClientCapabilitiesResolveSupport.phpW f<ߤUvendor/felixfbecker/language-server-protocol/src/ImplementationClientCapabilities.phpW fV Yvendor/felixfbecker/language-server-protocol/src/DocumentFormattingClientCapabilities.phpW f&)@@vendor/felixfbecker/language-server-protocol/src/TokenFormat.phpW ftTFvendor/felixfbecker/language-server-protocol/src/MessageActionItem.phpqW fq=JxCvendor/felixfbecker/language-server-protocol/src/CompletionList.phpW ff=5Tvendor/felixfbecker/language-server-protocol/src/VersionedTextDocumentIdentifier.phpW flUvendor/felixfbecker/language-server-protocol/src/ExecuteCommandClientCapabilities.phpyW fyI`=vendor/felixfbecker/language-server-protocol/src/TextEdit.phpzW fzkk_vendor/felixfbecker/language-server-protocol/src/DocumentSymbolClientCapabilitiesSymbolKind.phpW fci@vendor/felixfbecker/language-server-protocol/src/MessageType.phpkW fk_wvendor/felixfbecker/language-server-protocol/src/CodeActionClientCapabilitiesCodeActionLiteralSupportcodeActionKind.phpW f}פIvendor/felixfbecker/language-server-protocol/src/SignatureInformation.phpW f^Gvendor/felixfbecker/language-server-protocol/src/CodeActionDisabled.phpW fOV>vendor/felixfbecker/language-server-protocol/package-lock.jsonNW fNj\9vendor/felixfbecker/language-server-protocol/package.jsonNW fN2W>-vendor/felixfbecker/advanced-json-rpc/LICENSEW f>9=vendor/felixfbecker/advanced-json-rpc/lib/SuccessResponse.phphW fh硼8vendor/felixfbecker/advanced-json-rpc/lib/Dispatcher.phpW fkBb6vendor/felixfbecker/advanced-json-rpc/lib/Response.phpW f:5vendor/felixfbecker/advanced-json-rpc/lib/Request.phpW fDl7vendor/felixfbecker/advanced-json-rpc/lib/ErrorCode.php W f Y;vendor/felixfbecker/advanced-json-rpc/lib/ErrorResponse.phprW frd̒Q:vendor/felixfbecker/advanced-json-rpc/lib/Notification.phpW f$3vendor/felixfbecker/advanced-json-rpc/lib/Error.phpW fvendor/sebastian/diff/src/Exception/ConfigurationException.phpMW fM A@vendor/sebastian/diff/src/Exception/InvalidArgumentException.phpW fEOvendor/sebastian/diff/src/MemoryEfficientLongestCommonSubsequenceCalculator.php W f ^"vendor/sebastian/diff/src/Line.php[W f[4ä9vendor/symfony/console/Formatter/OutputFormatterStyle.php W f kV}>vendor/symfony/console/Formatter/OutputFormatterStyleStack.php7 W f7 64vendor/symfony/console/Formatter/OutputFormatter.php W f zZ8vendor/symfony/console/Formatter/NullOutputFormatter.phpsW fs_FDFFvendor/symfony/console/Formatter/WrappableOutputFormatterInterface.phpW fyؤ=vendor/symfony/console/Formatter/NullOutputFormatterStyle.phpW f+Bvendor/symfony/console/Formatter/OutputFormatterStyleInterface.phpmW fm7n=vendor/symfony/console/Formatter/OutputFormatterInterface.phpHW fHNO1vendor/symfony/console/Helper/FormatterHelper.php W f s(vendor/symfony/console/Helper/Dumper.phplW flʘ2vendor/symfony/console/Helper/DescriptorHelper.php W f +`+vendor/symfony/console/Helper/HelperSet.phpQ W fQ ^$b-vendor/symfony/console/Helper/ProgressBar.phpkHW fkHli'vendor/symfony/console/Helper/Table.php+sW f+sפ,vendor/symfony/console/Helper/TableStyle.php0W f0[s3vendor/symfony/console/Helper/ProgressIndicator.phpW fxmS/vendor/symfony/console/Helper/ProcessHelper.phpW fw6vendor/symfony/console/Helper/DebugFormatterHelper.php` W f` m2vendor/symfony/console/Helper/InputAwareHelper.php-W f-~df7vendor/symfony/console/Helper/SymfonyQuestionHelper.phpc W fc g^(vendor/symfony/console/Helper/Helper.phpW f%0vendor/symfony/console/Helper/TableSeparator.php)W f) ;(0vendor/symfony/console/Helper/QuestionHelper.php/MW f/M- 1vendor/symfony/console/Helper/HelperInterface.phpbW fb a+vendor/symfony/console/Helper/TableRows.phpZW fZO?¤+vendor/symfony/console/Helper/TableCell.phpW fު00vendor/symfony/console/Helper/TableCellStyle.phplW flXvendor/symfony/console/LICENSE,W f,U3vendor/symfony/console/SingleCommandApplication.phpIW fIO$B0vendor/symfony/console/Completion/Suggestion.phpW f;vendor/symfony/console/Completion/CompletionSuggestions.phpvW fvtpFvendor/symfony/console/Completion/Output/CompletionOutputInterface.phpW f Avendor/symfony/console/Completion/Output/BashCompletionOutput.php!W f!45vendor/symfony/console/Completion/CompletionInput.phpo W fo +7V.vendor/symfony/console/Attribute/AsCommand.phpRW fR 3vendor/symfony/console/Tester/ApplicationTester.php W f F/vendor/symfony/console/Tester/CommandTester.phpV W fV @vendor/symfony/console/Tester/Constraint/CommandIsSuccessful.phpW f :ڤ9vendor/symfony/console/Tester/CommandCompletionTester.php\W f\B-vendor/symfony/console/Tester/TesterTrait.phpW f],vendor/symfony/console/Style/OutputStyle.php` W f` N@-vendor/symfony/console/Style/SymfonyStyle.php.:W f.:b2Ť/vendor/symfony/console/Style/StyleInterface.phpV W fV "4vendor/symfony/console/Resources/bin/hiddeninput.exe$W f$v0vendor/symfony/console/Resources/completion.bash W f 'r8vendor/symfony/console/Descriptor/MarkdownDescriptor.phpW fa9vendor/symfony/console/Descriptor/DescriptorInterface.phpYW fYQj4vendor/symfony/console/Descriptor/JsonDescriptor.phpW f9ܤ3vendor/symfony/console/Descriptor/XmlDescriptor.phpF'W fF'T<vendor/symfony/console/Descriptor/ApplicationDescription.php5W f5',f0vendor/symfony/console/Descriptor/Descriptor.php: W f: &(4vendor/symfony/console/Descriptor/TextDescriptor.php.2W f.2Y vendor/symfony/console/Color.phpbW fbUĤ6vendor/symfony/console/EventListener/ErrorListener.phpz W fz gr 8vendor/symfony/console/SignalRegistry/SignalRegistry.phpHW fH^h#vendor/symfony/console/Terminal.phpqW fq/:&vendor/symfony/console/Application.phpW ffˤ=vendor/symfony/console/Command/SignalableCommandInterface.phpW fc/.vendor/symfony/console/Command/ListCommand.php9 W f9 BE.vendor/symfony/console/Command/LazyCommand.phpfW ffk80vendor/symfony/console/Command/LockableTrait.php<W f<jAK*vendor/symfony/console/Command/Command.phpPW fP?2vendor/symfony/console/Command/CompleteCommand.php!W f!Sc.vendor/symfony/console/Command/HelpCommand.phpB W fB ; Ť8vendor/symfony/console/Command/DumpCompletionCommand.phpW ft [?vendor/symfony/console/CommandLoader/ContainerCommandLoader.php"W f"(ä=vendor/symfony/console/CommandLoader/FactoryCommandLoader.phpmW fm9?vendor/symfony/console/CommandLoader/CommandLoaderInterface.phpW f46vendor/symfony/console/Output/ConsoleSectionOutput.phpW f0vendor/symfony/console/Output/BufferedOutput.phpgW fg^(GΤ.vendor/symfony/console/Output/StreamOutput.phpW f}8vendor/symfony/console/Output/ConsoleOutputInterface.php5W f5=5vendor/symfony/console/Output/TrimmedBufferOutput.php{W f{Kz 1vendor/symfony/console/Output/OutputInterface.php| W f| ,،Ҥ/vendor/symfony/console/Output/ConsoleOutput.php1W f1 Ę(vendor/symfony/console/Output/Output.phpsW fsr)\,vendor/symfony/console/Output/NullOutput.phpD W fD  2vendor/symfony/console/CI/GithubActionReporter.php+ W f+ 30vendor/symfony/console/Input/InputDefinition.php`.W f`."-+vendor/symfony/console/Input/ArrayInput.phpW fW^.vendor/symfony/console/Input/InputArgument.php W f xZ,vendor/symfony/console/Input/InputOption.phplW flR*vendor/symfony/console/Input/ArgvInput.php0W f044vendor/symfony/console/Input/InputAwareInterface.phpPW fP頒,vendor/symfony/console/Input/StringInput.php W f 5&vendor/symfony/console/Input/Input.phpIW fIm9vendor/symfony/console/Input/StreamableInputInterface.php~W f~Q!tҤ/vendor/symfony/console/Input/InputInterface.phpW f,md3vendor/symfony/console/Event/ConsoleSignalEvent.phpW fbAͤ6vendor/symfony/console/Event/ConsoleTerminateEvent.phpzW fz'Iґ4vendor/symfony/console/Event/ConsoleCommandEvent.phpAW fA3v2vendor/symfony/console/Event/ConsoleErrorEvent.php2W f2 -vendor/symfony/console/Event/ConsoleEvent.phpW fRDvendor/symfony/console/DependencyInjection/AddConsoleCommandPass.phpW f8vendor/symfony/console/Question/ConfirmationQuestion.php-W f-6),vendor/symfony/console/Question/Question.phpW fiT2vendor/symfony/console/Question/ChoiceQuestion.phpW f ƃ;vendor/symfony/console/Exception/InvalidOptionException.phpW f 07vendor/symfony/console/Exception/ExceptionInterface.phpW f&3vendor/symfony/console/Exception/LogicException.phpW fR?vendor/symfony/console/Exception/NamespaceNotFoundException.phpW f3 :vendor/symfony/console/Exception/MissingInputException.phpW fWX=vendor/symfony/console/Exception/CommandNotFoundException.phpW fv5vendor/symfony/console/Exception/RuntimeException.phpW f};=vendor/symfony/console/Exception/InvalidArgumentException.phpW f2Ť(vendor/symfony/console/ConsoleEvents.phpW fNʤ/vendor/symfony/console/Logger/ConsoleLogger.phpW f c!vendor/symfony/console/Cursor.phpGW fGNEݤ(vendor/symfony/service-contracts/LICENSE,W f,7vendor/symfony/service-contracts/Attribute/Required.phpW f4"@vendor/symfony/service-contracts/Attribute/SubscribedService.phpBW fBmѹ;vendor/symfony/service-contracts/ServiceSubscriberTrait.phpW f,@3vendor/symfony/service-contracts/ResetInterface.phpW f[=vendor/symfony/service-contracts/ServiceProviderInterface.phpW fb8vendor/symfony/service-contracts/ServiceLocatorTrait.phpW fHx<?vendor/symfony/service-contracts/ServiceSubscriberInterface.phpW f.@(vendor/symfony/polyfill-mbstring/LICENSE,W f,H@vendor/symfony/polyfill-mbstring/Resources/unidata/lowerCase.phpUW fUsbڤBvendor/symfony/polyfill-mbstring/Resources/unidata/caseFolding.phpW fq@vendor/symfony/polyfill-mbstring/Resources/unidata/upperCase.phpW[W fW[EҤFvendor/symfony/polyfill-mbstring/Resources/unidata/titleCaseRegexp.phpW f7Ť-vendor/symfony/polyfill-mbstring/Mbstring.phpɋW fɋTK.0vendor/symfony/polyfill-mbstring/bootstrap80.php+W f+Iw.vendor/symfony/polyfill-mbstring/bootstrap.php$W f$q@%vendor/symfony/polyfill-php73/LICENSE,W f,?vendor/symfony/polyfill-php73/Resources/stubs/JsonException.phphW fh8'vendor/symfony/polyfill-php73/Php73.phpW f+vendor/symfony/polyfill-php73/bootstrap.phpW f4P%vendor/symfony/polyfill-php80/LICENSE,W f, K'vendor/symfony/polyfill-php80/Php80.php W f cH:vendor/symfony/polyfill-php80/Resources/stubs/PhpToken.phpwW fw=7T8;vendor/symfony/polyfill-php80/Resources/stubs/Attribute.phpW fMK<<vendor/symfony/polyfill-php80/Resources/stubs/ValueError.phpaW fa] <vendor/symfony/polyfill-php80/Resources/stubs/Stringable.phpW ft]\ڤEvendor/symfony/polyfill-php80/Resources/stubs/UnhandledMatchError.phpjW fjL/*vendor/symfony/polyfill-php80/PhpToken.phpW f]f+vendor/symfony/polyfill-php80/bootstrap.phpW foO,vendor/symfony/deprecation-contracts/LICENSE,W f, K1vendor/symfony/deprecation-contracts/function.php4W f4 "vendor/symfony/filesystem/Path.php8fW f8fcT!vendor/symfony/filesystem/LICENSE,W f,U:vendor/symfony/filesystem/Exception/ExceptionInterface.phpW f{:<vendor/symfony/filesystem/Exception/IOExceptionInterface.phpW fBzȤ3vendor/symfony/filesystem/Exception/IOException.phpW f,=vendor/symfony/filesystem/Exception/FileNotFoundException.phpW fl8vendor/symfony/filesystem/Exception/RuntimeException.phpW fM@vendor/symfony/filesystem/Exception/InvalidArgumentException.phpW f٠G(vendor/symfony/filesystem/Filesystem.phpuW fuj/vendor/symfony/polyfill-intl-normalizer/LICENSE,W f,HXvendor/symfony/polyfill-intl-normalizer/Resources/unidata/compatibilityDecomposition.phpW fSL'Rvendor/symfony/polyfill-intl-normalizer/Resources/unidata/canonicalComposition.php=W f=`Lvendor/symfony/polyfill-intl-normalizer/Resources/unidata/combiningClass.php.W f.IxTvendor/symfony/polyfill-intl-normalizer/Resources/unidata/canonicalDecomposition.phpW fHnlFvendor/symfony/polyfill-intl-normalizer/Resources/stubs/Normalizer.phpW f+7vendor/symfony/polyfill-intl-normalizer/bootstrap80.php+W f+5vendor/symfony/polyfill-intl-normalizer/bootstrap.php0W f0l46vendor/symfony/polyfill-intl-normalizer/Normalizer.phpO$W fO$ᦚB%vendor/symfony/polyfill-ctype/LICENSE,W f,'vendor/symfony/polyfill-ctype/Ctype.phpW f*Y>M-vendor/symfony/polyfill-ctype/bootstrap80.phppW fpͤ<vendor/symfony/string/Exception/InvalidArgumentException.phpW f|s )vendor/symfony/string/CodePointString.phpW f@H(vendor/symfony/string/AbstractString.phpOW fOGZ-vendor/spatie/array-to-xml/src/ArrayToXml.phpW f! vendor/amphp/byte-stream/LICENSE6W f6\>W/vendor/amphp/byte-stream/lib/IteratorStream.phpW fC|m*vendor/amphp/byte-stream/lib/functions.phpW frBvendor/amphp/byte-stream/lib/Base64/Base64EncodingOutputStream.phpW fǝ[Avendor/amphp/byte-stream/lib/Base64/Base64DecodingInputStream.phpPW fP`Bvendor/amphp/byte-stream/lib/Base64/Base64DecodingOutputStream.phpW fOAvendor/amphp/byte-stream/lib/Base64/Base64EncodingInputStream.phpW f1vendor/amphp/byte-stream/lib/PendingReadError.phpW f{@(vendor/amphp/byte-stream/lib/Payload.php W f 1vendor/amphp/byte-stream/lib/ZlibOutputStream.phpg W fg +,vendor/amphp/byte-stream/lib/InputStream.phpOW fO00vendor/amphp/byte-stream/lib/ZlibInputStream.php W f \0vendor/amphp/byte-stream/lib/StreamException.phpfW ffdL0+vendor/amphp/byte-stream/lib/LineReader.php W f W f>J!vendor/amphp/amp/lib/Producer.phpW fA1vendor/amphp/amp/lib/TimeoutCancellationToken.php3W f3R.vendor/amphp/amp/lib/NullCancellationToken.phpW f=f vendor/amphp/amp/lib/Emitter.phpW fhH vendor/amphp/amp/lib/Failure.phpW f.\sx!vendor/amphp/amp/lib/Iterator.php\W f\#*vendor/amphp/amp/lib/InvalidYieldError.phpW fV:9vendor/amphp/amp/lib/Loop/UnsupportedFeatureException.php(W f(:sX+vendor/amphp/amp/lib/Loop/DriverFactory.phpW fʤ+vendor/amphp/amp/lib/Loop/TracingDriver.phpjW fj|1vendor/amphp/amp/lib/Loop/Internal/TimerQueue.phpJW fJݤ*vendor/amphp/amp/lib/Loop/NativeDriver.php8W f8{J9)vendor/amphp/amp/lib/Loop/EventDriver.phpL%W fL%uv&vendor/amphp/amp/lib/Loop/UvDriver.php(W f(W%vendor/amphp/amp/lib/Loop/Watcher.phpW f2$vendor/amphp/amp/lib/Loop/Driver.phpDgW fDg9=ͤ&vendor/amphp/amp/lib/Loop/EvDriver.php!W f!A|M\1vendor/amphp/amp/lib/Loop/InvalidWatcherError.php*W f*㖁 vendor/amphp/amp/lib/Success.phpW f:Rn )vendor/amphp/amp/lib/TimeoutException.phpW fw$}-vendor/amphp/amp/lib/MultiReasonException.phpW f"PH.vendor/phpdocumentor/reflection-common/LICENSE9W f9*2Ȑ3vendor/phpdocumentor/reflection-common/src/File.phpW f˭7vendor/phpdocumentor/reflection-common/src/Location.phpW f!GQ/6vendor/phpdocumentor/reflection-common/src/Project.phpW f 6vendor/phpdocumentor/reflection-common/src/Element.phpW f[!=vendor/phpdocumentor/reflection-common/src/ProjectFactory.phpnW fn4vendor/phpdocumentor/reflection-common/src/Fqsen.phpW f܊*vendor/phpdocumentor/type-resolver/LICENSE8W f8ʤ5vendor/phpdocumentor/type-resolver/src/PseudoType.phpW fN ä8vendor/phpdocumentor/type-resolver/src/FqsenResolver.php W f wҤ/vendor/phpdocumentor/type-resolver/src/Type.phpW fQtϤ7vendor/phpdocumentor/type-resolver/src/TypeResolver.phpXW fXCvendor/phpdocumentor/type-resolver/src/PseudoTypes/IntegerValue.phpW f냤=vendor/phpdocumentor/type-resolver/src/PseudoTypes/False_.phpW f'CCFvendor/phpdocumentor/type-resolver/src/PseudoTypes/LowercaseString.phpW fuEvendor/phpdocumentor/type-resolver/src/PseudoTypes/CallableString.phpW fICvendor/phpdocumentor/type-resolver/src/PseudoTypes/NonEmptyList.phpW fUFvendor/phpdocumentor/type-resolver/src/PseudoTypes/NegativeInteger.phpW f4<vendor/phpdocumentor/type-resolver/src/PseudoTypes/True_.phpW fn?&?vendor/phpdocumentor/type-resolver/src/PseudoTypes/Numeric_.php`W f`Evendor/phpdocumentor/type-resolver/src/PseudoTypes/ArrayShapeItem.phpW fp<vendor/phpdocumentor/type-resolver/src/PseudoTypes/List_.phpW f7Fvendor/phpdocumentor/type-resolver/src/PseudoTypes/ConstExpression.phpW fCޤDvendor/phpdocumentor/type-resolver/src/PseudoTypes/NumericString.phpW fZMMDvendor/phpdocumentor/type-resolver/src/PseudoTypes/LiteralString.phpW f;WCvendor/phpdocumentor/type-resolver/src/PseudoTypes/IntegerRange.phpaW fa,Nvendor/phpdocumentor/type-resolver/src/PseudoTypes/NonEmptyLowercaseString.phpW f]Fvendor/phpdocumentor/type-resolver/src/PseudoTypes/PositiveInteger.phpW fF!Bvendor/phpdocumentor/type-resolver/src/PseudoTypes/StringValue.phpW f"~Bvendor/phpdocumentor/type-resolver/src/PseudoTypes/TraitString.phpW fpAvendor/phpdocumentor/type-resolver/src/PseudoTypes/ArrayShape.phpW fgHvendor/phpdocumentor/type-resolver/src/PseudoTypes/HtmlEscapedString.phpW f8_Avendor/phpdocumentor/type-resolver/src/PseudoTypes/FloatValue.phpW f_O Evendor/phpdocumentor/type-resolver/src/PseudoTypes/NonEmptyString.phpW fOb$ 8vendor/phpdocumentor/type-resolver/src/Types/Static_.php#W f#@U88vendor/phpdocumentor/type-resolver/src/Types/String_.phpW fr5vendor/phpdocumentor/type-resolver/src/Types/This.phpwW fw(gBvendor/phpdocumentor/type-resolver/src/Types/CallableParameter.phpW f-Ĥ;vendor/phpdocumentor/type-resolver/src/Types/Expression.phpVW fVާ7vendor/phpdocumentor/type-resolver/src/Types/Never_.phpW f:vendor/phpdocumentor/type-resolver/src/Types/Iterable_.phpNW fN6B8vendor/phpdocumentor/type-resolver/src/Types/Integer.phpW f̤6vendor/phpdocumentor/type-resolver/src/Types/Null_.phpW f&ʁ7vendor/phpdocumentor/type-resolver/src/Types/Scalar.phpW f-7vendor/phpdocumentor/type-resolver/src/Types/Float_.phpW fFg9vendor/phpdocumentor/type-resolver/src/Types/ArrayKey.phpW fL=vendor/phpdocumentor/type-resolver/src/Types/Intersection.php4W f4ۏF7?vendor/phpdocumentor/type-resolver/src/Types/AggregatedType.php W f <vendor/phpdocumentor/type-resolver/src/Types/ClassString.phpW f;8vendor/phpdocumentor/type-resolver/src/Types/Object_.phpW fG6a8vendor/phpdocumentor/type-resolver/src/Types/Context.php W f BBˤ6vendor/phpdocumentor/type-resolver/src/Types/Void_.php%W f%Ɓ9vendor/phpdocumentor/type-resolver/src/Types/Compound.php%W f%7vendor/phpdocumentor/type-resolver/src/Types/Array_.phpW f(:vendor/phpdocumentor/type-resolver/src/Types/Callable_.phpW ftF5'=vendor/phpdocumentor/type-resolver/src/Types/AbstractList.phpW f98vendor/phpdocumentor/type-resolver/src/Types/Boolean.phpW f7vendor/phpdocumentor/type-resolver/src/Types/Mixed_.phpW f0;vendor/phpdocumentor/type-resolver/src/Types/Collection.phpW fN6vendor/phpdocumentor/type-resolver/src/Types/Self_.phpW fY:@vendor/phpdocumentor/type-resolver/src/Types/InterfaceString.phpW fJK19vendor/phpdocumentor/type-resolver/src/Types/Nullable.phppW fphE8vendor/phpdocumentor/type-resolver/src/Types/Parent_.phpW fߤ:vendor/phpdocumentor/type-resolver/src/Types/Resource_.phpW f1}ľ?vendor/phpdocumentor/type-resolver/src/Types/ContextFactory.php7W f7n0vendor/phpdocumentor/reflection-docblock/LICENSE8W f8ʤ6vendor/phpdocumentor/reflection-docblock/src/Utils.php W f ]Ivendor/phpdocumentor/reflection-docblock/src/DocBlockFactoryInterface.phpW f >@vendor/phpdocumentor/reflection-docblock/src/DocBlockFactory.php3,W f3,'9vendor/phpdocumentor/reflection-docblock/src/DocBlock.php"W f"y =Lvendor/phpdocumentor/reflection-docblock/src/DocBlock/DescriptionFactory.php\W f\גLvendor/phpdocumentor/reflection-docblock/src/DocBlock/StandardTagFactory.php4W f4;Dvendor/phpdocumentor/reflection-docblock/src/DocBlock/Serializer.php_W f_L'Dvendor/phpdocumentor/reflection-docblock/src/DocBlock/TagFactory.php/ W f/ \ =vendor/phpdocumentor/reflection-docblock/src/DocBlock/Tag.phpW ffdDvendor/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Since.php W f /̢Wvendor/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Formatter/AlignFormatter.phpW f|ɤ]vendor/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Formatter/PassthroughFormatter.phpW fdӤFvendor/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Version.php W f T2:Fvendor/phpdocumentor/reflection-docblock/src/DocBlock/Tags/BaseTag.phpW fʤBvendor/phpdocumentor/reflection-docblock/src/DocBlock/Tags/See.php W f Jvendor/phpdocumentor/reflection-docblock/src/DocBlock/Tags/TagWithType.phpW f9Fvendor/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Example.phpW fni Lvendor/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Reference/Url.phpW f.Rvendor/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Reference/Reference.phpW f 9Nvendor/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Reference/Fqsen.php:W f:?ucEvendor/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Source.php W f 5Evendor/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Throws.phpyW fyn, Evendor/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Author.php W f DDvendor/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Param.phpZW fZդCvendor/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Link.phpW fɤFvendor/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Return_.php] W f] 6K ФIvendor/phpdocumentor/reflection-docblock/src/DocBlock/Tags/InvalidTag.phpW fgIvendor/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Deprecated.php5 W f5 2%wEvendor/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Covers.php W f Cvendor/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Uses.php W f WoCvendor/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Var_.php W f +PԤLvendor/phpdocumentor/reflection-docblock/src/DocBlock/Tags/PropertyWrite.php$W f$SNvendor/phpdocumentor/reflection-docblock/src/DocBlock/Tags/MethodParameter.php5W f5:Evendor/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Method.php\(W f\(&5Gvendor/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Property.phpW f0Kvendor/phpdocumentor/reflection-docblock/src/DocBlock/Tags/PropertyRead.php)W f)@Zvendor/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Factory/PropertyReadFactory.phprW fr աNvendor/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Factory/Factory.phpbW fbCbUvendor/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Factory/PHPStanFactory.phpW f`B!Svendor/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Factory/ParamFactory.php, W f, }SZSvendor/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Factory/StaticMethod.php-W f-]vendor/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Factory/AbstractPHPStanFactory.phpW fyTvendor/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Factory/MethodFactory.phpo W fo Vvendor/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Factory/PropertyFactory.phpaW fa_0[vendor/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Factory/PropertyWriteFactory.phpvW fvQd:Qvendor/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Factory/VarFactory.php&W f&KTvendor/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Factory/ReturnFactory.phpW f0iƤFvendor/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Generic.php W f >ؤHvendor/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Formatter.php<W f<d,اGvendor/phpdocumentor/reflection-docblock/src/DocBlock/ExampleFinder.php@W f@MEvendor/phpdocumentor/reflection-docblock/src/DocBlock/Description.phpTW fTkHvendor/phpdocumentor/reflection-docblock/src/Exception/PcreException.phpW f2;vendor/webmozart/assert/LICENSE<W f<t}&vendor/webmozart/assert/src/Assert.phpW fV%vendor/webmozart/assert/src/Mixin.php=W f=[28vendor/webmozart/assert/src/InvalidArgumentException.phpqW fq\rvendor/nikic/php-parser/LICENSEW f*%vendor/nikic/php-parser/bin/php-parsezW fzj5vendor/nikic/php-parser/lib/PhpParser/Comment/Doc.phpW f ?vendor/nikic/php-parser/lib/PhpParser/PrettyPrinterAbstract.phpW f)D7vendor/nikic/php-parser/lib/PhpParser/ParserFactory.php W f K?vendor/nikic/php-parser/lib/PhpParser/ErrorHandler/Throwing.phpW f'ֿAvendor/nikic/php-parser/lib/PhpParser/ErrorHandler/Collecting.phpW fML/vendor/nikic/php-parser/lib/PhpParser/Lexer.phpZW fZ3a<vendor/nikic/php-parser/lib/PhpParser/ConstExprEvaluator.php%W f%$r*a9vendor/nikic/php-parser/lib/PhpParser/Internal/Differ.php<W f<yH>vendor/nikic/php-parser/lib/PhpParser/Internal/TokenStream.php $W f $;vendor/nikic/php-parser/lib/PhpParser/Internal/DiffElem.phpFW fFLvendor/nikic/php-parser/lib/PhpParser/Internal/PrintableNewAnonClassNode.phpW f< B8vendor/nikic/php-parser/lib/PhpParser/ParserAbstract.phpW fKn⍤1vendor/nikic/php-parser/lib/PhpParser/Comment.phpW f&5vendor/nikic/php-parser/lib/PhpParser/NodeVisitor.phpW f,Dvendor/nikic/php-parser/lib/PhpParser/NodeVisitor/FindingVisitor.phpW fH6Mvendor/nikic/php-parser/lib/PhpParser/NodeVisitor/ParentConnectingVisitor.phpW f CIvendor/nikic/php-parser/lib/PhpParser/NodeVisitor/FirstFindingVisitor.php8W f8X̤Dvendor/nikic/php-parser/lib/PhpParser/NodeVisitor/CloningVisitor.php?W f?rBvendor/nikic/php-parser/lib/PhpParser/NodeVisitor/NameResolver.php{'W f{'K\ yKvendor/nikic/php-parser/lib/PhpParser/NodeVisitor/NodeConnectingVisitor.phpW fФ5vendor/nikic/php-parser/lib/PhpParser/NameContext.php,&W f,&qs6vendor/nikic/php-parser/lib/PhpParser/ErrorHandler.php>W f>k11vendor/nikic/php-parser/lib/PhpParser/Builder.phpW fØ5vendor/nikic/php-parser/lib/PhpParser/JsonDecoder.php/ W f/ ܤ7vendor/nikic/php-parser/lib/PhpParser/NodeTraverser.phpl'W fl'H8vendor/nikic/php-parser/lib/PhpParser/BuilderFactory.php+W f+9벤6vendor/nikic/php-parser/lib/PhpParser/NodeAbstract.phpiW fic7 4vendor/nikic/php-parser/lib/PhpParser/NodeDumper.phpW f-Y4vendor/nikic/php-parser/lib/PhpParser/NodeFinder.php W f R(<vendor/nikic/php-parser/lib/PhpParser/Builder/ClassConst.phpBW fBCl7vendor/nikic/php-parser/lib/PhpParser/Builder/Param.phpW f8vendor/nikic/php-parser/lib/PhpParser/Builder/Trait_.php!W f!Ua,>vendor/nikic/php-parser/lib/PhpParser/Builder/FunctionLike.phpW fYDvendor/nikic/php-parser/lib/PhpParser/Builder/TraitUseAdaptation.phpW fJ\7vendor/nikic/php-parser/lib/PhpParser/Builder/Enum_.php W f )<vendor/nikic/php-parser/lib/PhpParser/Builder/Namespace_.phpW f7 S<vendor/nikic/php-parser/lib/PhpParser/Builder/Interface_.php" W f" Py:vendor/nikic/php-parser/lib/PhpParser/Builder/EnumCase.phpW f2\=vendor/nikic/php-parser/lib/PhpParser/Builder/Declaration.php W f %8vendor/nikic/php-parser/lib/PhpParser/Builder/Method.phpW f_:vendor/nikic/php-parser/lib/PhpParser/Builder/Property.phpW f4U;vendor/nikic/php-parser/lib/PhpParser/Builder/Function_.phpW f48vendor/nikic/php-parser/lib/PhpParser/Builder/Class_.phpW fA@6vendor/nikic/php-parser/lib/PhpParser/Builder/Use_.php*W f*LR[:vendor/nikic/php-parser/lib/PhpParser/Builder/TraitUse.phpW f0vendor/nikic/php-parser/lib/PhpParser/Parser.phpW fn.vendor/nikic/php-parser/lib/PhpParser/Node.phpW fj=vendor/nikic/php-parser/lib/PhpParser/Node/AttributeGroup.phpW f7l;vendor/nikic/php-parser/lib/PhpParser/Node/NullableType.phpW f/4vendor/nikic/php-parser/lib/PhpParser/Node/Param.phpW f\3C@vendor/nikic/php-parser/lib/PhpParser/Node/Expr/BinaryOp/Div.php`W f`g/[Ivendor/nikic/php-parser/lib/PhpParser/Node/Expr/BinaryOp/NotIdentical.phptW ft'\Dvendor/nikic/php-parser/lib/PhpParser/Node/Expr/BinaryOp/Smaller.phphW fhoDvendor/nikic/php-parser/lib/PhpParser/Node/Expr/BinaryOp/Greater.phphW fh.Gvendor/nikic/php-parser/lib/PhpParser/Node/Expr/BinaryOp/LogicalAnd.phppW fp"6Fvendor/nikic/php-parser/lib/PhpParser/Node/Expr/BinaryOp/Identical.phpnW fnaGvendor/nikic/php-parser/lib/PhpParser/Node/Expr/BinaryOp/BitwiseAnd.phpnW fnTFvendor/nikic/php-parser/lib/PhpParser/Node/Expr/BinaryOp/BooleanOr.phpmW fm$ Fvendor/nikic/php-parser/lib/PhpParser/Node/Expr/BinaryOp/ShiftLeft.phpmW fmGvendor/nikic/php-parser/lib/PhpParser/Node/Expr/BinaryOp/BitwiseXor.phpnW fnd@vendor/nikic/php-parser/lib/PhpParser/Node/Expr/BinaryOp/Mod.php`W f`GDAvendor/nikic/php-parser/lib/PhpParser/Node/Expr/BinaryOp/Plus.phpbW fbo,ɤKvendor/nikic/php-parser/lib/PhpParser/Node/Expr/BinaryOp/SmallerOrEqual.phpwW fwh/Evendor/nikic/php-parser/lib/PhpParser/Node/Expr/BinaryOp/Coalesce.phpkW fkQ6wFvendor/nikic/php-parser/lib/PhpParser/Node/Expr/BinaryOp/Spaceship.phpnW fnL@vendor/nikic/php-parser/lib/PhpParser/Node/Expr/BinaryOp/Pow.phpaW fa_@vendor/nikic/php-parser/lib/PhpParser/Node/Expr/BinaryOp/Mul.php`W f`rnͤGvendor/nikic/php-parser/lib/PhpParser/Node/Expr/BinaryOp/BooleanAnd.phpoW fox Fvendor/nikic/php-parser/lib/PhpParser/Node/Expr/BinaryOp/LogicalOr.phpmW fm\Fvendor/nikic/php-parser/lib/PhpParser/Node/Expr/BinaryOp/BitwiseOr.phplW fl=IWEvendor/nikic/php-parser/lib/PhpParser/Node/Expr/BinaryOp/NotEqual.phpkW fk|Cvendor/nikic/php-parser/lib/PhpParser/Node/Expr/BinaryOp/Concat.phpfW ff AqBvendor/nikic/php-parser/lib/PhpParser/Node/Expr/BinaryOp/Minus.phpdW fd"Kvendor/nikic/php-parser/lib/PhpParser/Node/Expr/BinaryOp/GreaterOrEqual.phpwW fw_8Gvendor/nikic/php-parser/lib/PhpParser/Node/Expr/BinaryOp/ShiftRight.phpoW foaФBvendor/nikic/php-parser/lib/PhpParser/Node/Expr/BinaryOp/Equal.phpeW fe<ˤGvendor/nikic/php-parser/lib/PhpParser/Node/Expr/BinaryOp/LogicalXor.phppW fpsR0>vendor/nikic/php-parser/lib/PhpParser/Node/Expr/ClosureUse.phpW f O=vendor/nikic/php-parser/lib/PhpParser/Node/Expr/AssignRef.phpfW ffɏ=vendor/nikic/php-parser/lib/PhpParser/Node/Expr/YieldFrom.phpW f[|ܤIvendor/nikic/php-parser/lib/PhpParser/Node/Expr/NullsafePropertyFetch.phpW faɤ8vendor/nikic/php-parser/lib/PhpParser/Node/Expr/New_.phpW fg%Avendor/nikic/php-parser/lib/PhpParser/Node/Expr/ArrowFunction.php W f I찤:vendor/nikic/php-parser/lib/PhpParser/Node/Expr/Yield_.php|W f|FrC@vendor/nikic/php-parser/lib/PhpParser/Node/Expr/Cast/String_.phpW f?vendor/nikic/php-parser/lib/PhpParser/Node/Expr/Cast/Unset_.phpW fW=vendor/nikic/php-parser/lib/PhpParser/Node/Expr/Cast/Int_.phpW fo@vendor/nikic/php-parser/lib/PhpParser/Node/Expr/Cast/Object_.phpW frx?vendor/nikic/php-parser/lib/PhpParser/Node/Expr/Cast/Double.phpW fMNc:?vendor/nikic/php-parser/lib/PhpParser/Node/Expr/Cast/Array_.phpW f>vendor/nikic/php-parser/lib/PhpParser/Node/Expr/Cast/Bool_.phpW fm <vendor/nikic/php-parser/lib/PhpParser/Node/Expr/AssignOp.phpW fn:vendor/nikic/php-parser/lib/PhpParser/Node/Expr/Isset_.phpW f<s:vendor/nikic/php-parser/lib/PhpParser/Node/Expr/Clone_.phpW fn+?:vendor/nikic/php-parser/lib/PhpParser/Node/Expr/PreInc.phpW fe!;vendor/nikic/php-parser/lib/PhpParser/Node/Expr/PostDec.phpW f_oXAvendor/nikic/php-parser/lib/PhpParser/Node/Expr/ErrorSuppress.phpW fCvendor/nikic/php-parser/lib/PhpParser/Node/Expr/ClassConstFetch.phpDW fDKڒ?vendor/nikic/php-parser/lib/PhpParser/Node/Expr/Instanceof_.phpW fs=vendor/nikic/php-parser/lib/PhpParser/Node/Expr/ShellExec.phpW fFvendor/nikic/php-parser/lib/PhpParser/Node/Expr/NullsafeMethodCall.phpW fI/Avendor/nikic/php-parser/lib/PhpParser/Node/Expr/PropertyFetch.phpW f+<vendor/nikic/php-parser/lib/PhpParser/Node/Expr/BinaryOp.phpW f9vendor/nikic/php-parser/lib/PhpParser/Node/Expr/Eval_.phpW f}^>vendor/nikic/php-parser/lib/PhpParser/Node/Expr/StaticCall.phpW fYTR9vendor/nikic/php-parser/lib/PhpParser/Node/Expr/List_.phpW fƏ;vendor/nikic/php-parser/lib/PhpParser/Node/Expr/Closure.php W f L@ʤ:vendor/nikic/php-parser/lib/PhpParser/Node/Expr/Match_.phpW f#S<vendor/nikic/php-parser/lib/PhpParser/Node/Expr/FuncCall.php`W f`Gvendor/nikic/php-parser/lib/PhpParser/Node/Expr/StaticPropertyFetch.phpbW fbNݤ<vendor/nikic/php-parser/lib/PhpParser/Node/Expr/Include_.phpW f@:vendor/nikic/php-parser/lib/PhpParser/Node/Expr/Array_.phpVW fV>vendor/nikic/php-parser/lib/PhpParser/Node/Expr/BooleanNot.phpW fu:vendor/nikic/php-parser/lib/PhpParser/Node/Expr/Print_.phpW f:>vendor/nikic/php-parser/lib/PhpParser/Node/Expr/BitwiseNot.phpW fAvendor/nikic/php-parser/lib/PhpParser/Node/Expr/ArrayDimFetch.phplW fl4݇9vendor/nikic/php-parser/lib/PhpParser/Node/Expr/Error.php W f %Y>vendor/nikic/php-parser/lib/PhpParser/Node/Expr/MethodCall.phpW fy8:vendor/nikic/php-parser/lib/PhpParser/Node/Expr/Empty_.phpW f\:vendor/nikic/php-parser/lib/PhpParser/Node/Expr/PreDec.phpW fW=vendor/nikic/php-parser/lib/PhpParser/Node/Expr/UnaryPlus.phpW fYp掤8vendor/nikic/php-parser/lib/PhpParser/Node/Expr/Cast.php_W f_f 9vendor/nikic/php-parser/lib/PhpParser/Node/Expr/Exit_.php$W f$3d@vendor/nikic/php-parser/lib/PhpParser/Node/Expr/AssignOp/Div.phpW fiAPJGvendor/nikic/php-parser/lib/PhpParser/Node/Expr/AssignOp/BitwiseAnd.phpW f#9 Fvendor/nikic/php-parser/lib/PhpParser/Node/Expr/AssignOp/ShiftLeft.phpW fKp.Gvendor/nikic/php-parser/lib/PhpParser/Node/Expr/AssignOp/BitwiseXor.phpW faBG@vendor/nikic/php-parser/lib/PhpParser/Node/Expr/AssignOp/Mod.phpW f)0Avendor/nikic/php-parser/lib/PhpParser/Node/Expr/AssignOp/Plus.phpW fj.Evendor/nikic/php-parser/lib/PhpParser/Node/Expr/AssignOp/Coalesce.phpW fɾ@vendor/nikic/php-parser/lib/PhpParser/Node/Expr/AssignOp/Pow.phpW fa@vendor/nikic/php-parser/lib/PhpParser/Node/Expr/AssignOp/Mul.phpW f_oFvendor/nikic/php-parser/lib/PhpParser/Node/Expr/AssignOp/BitwiseOr.phpW f|C+Cvendor/nikic/php-parser/lib/PhpParser/Node/Expr/AssignOp/Concat.phpW fF,Bvendor/nikic/php-parser/lib/PhpParser/Node/Expr/AssignOp/Minus.phpW f>@CGvendor/nikic/php-parser/lib/PhpParser/Node/Expr/AssignOp/ShiftRight.phpW f[;vendor/nikic/php-parser/lib/PhpParser/Node/Expr/PostInc.phpW fvendor/nikic/php-parser/lib/PhpParser/Node/Expr/ConstFetch.phpW fNӱ-:vendor/nikic/php-parser/lib/PhpParser/Node/Expr/Throw_.phpW f΍:vendor/nikic/php-parser/lib/PhpParser/Node/Expr/Assign.php5W f5i<̤<vendor/nikic/php-parser/lib/PhpParser/Node/Expr/CallLike.phpbW fb*=vendor/nikic/php-parser/lib/PhpParser/Node/Expr/ArrayItem.phpW f\F<vendor/nikic/php-parser/lib/PhpParser/Node/Expr/Variable.phpW fi^>vendor/nikic/php-parser/lib/PhpParser/Node/Expr/UnaryMinus.phpW fVR;vendor/nikic/php-parser/lib/PhpParser/Node/FunctionLike.phpW fI5vendor/nikic/php-parser/lib/PhpParser/Node/Scalar.phpzW fz-8vendor/nikic/php-parser/lib/PhpParser/Node/Attribute.phpuW fu~+=?vendor/nikic/php-parser/lib/PhpParser/Node/IntersectionType.phpW f4Z;vendor/nikic/php-parser/lib/PhpParser/Node/Stmt/Static_.phpW fSڤ;vendor/nikic/php-parser/lib/PhpParser/Node/Stmt/Switch_.phpSW fSd=vendor/nikic/php-parser/lib/PhpParser/Node/Stmt/ClassLike.php W f :vendor/nikic/php-parser/lib/PhpParser/Node/Stmt/Unset_.phpW f'0>vendor/nikic/php-parser/lib/PhpParser/Node/Stmt/Expression.phpW f !:vendor/nikic/php-parser/lib/PhpParser/Node/Stmt/Catch_.phpW f >vendor/nikic/php-parser/lib/PhpParser/Node/Stmt/ClassConst.php W f kzD8vendor/nikic/php-parser/lib/PhpParser/Node/Stmt/For_.php\W f\դLvendor/nikic/php-parser/lib/PhpParser/Node/Stmt/TraitUseAdaptation/Alias.php_W f_Qvendor/nikic/php-parser/lib/PhpParser/Node/Stmt/TraitUseAdaptation/Precedence.phpxW fxX3:vendor/nikic/php-parser/lib/PhpParser/Node/Stmt/Trait_.php!W f!4yDf9vendor/nikic/php-parser/lib/PhpParser/Node/Stmt/Case_.phpW fiwZBvendor/nikic/php-parser/lib/PhpParser/Node/Stmt/DeclareDeclare.phpW fK.'Fvendor/nikic/php-parser/lib/PhpParser/Node/Stmt/TraitUseAdaptation.php8W f8p>vendor/nikic/php-parser/lib/PhpParser/Node/Stmt/InlineHTML.phpW f%B;vendor/nikic/php-parser/lib/PhpParser/Node/Stmt/Return_.phpW f4HDvendor/nikic/php-parser/lib/PhpParser/Node/Stmt/PropertyProperty.phpW f$qh:vendor/nikic/php-parser/lib/PhpParser/Node/Stmt/UseUse.phpW f{V;vendor/nikic/php-parser/lib/PhpParser/Node/Stmt/Global_.phpW f;ݚ:vendor/nikic/php-parser/lib/PhpParser/Node/Stmt/Const_.phpW f4ߤ9vendor/nikic/php-parser/lib/PhpParser/Node/Stmt/Enum_.php[W f[5m<vendor/nikic/php-parser/lib/PhpParser/Node/Stmt/TryCatch.phpCW fCvendor/nikic/php-parser/lib/PhpParser/Node/Stmt/Namespace_.phpW fh-A>vendor/nikic/php-parser/lib/PhpParser/Node/Stmt/Interface_.phpW f`?vendor/nikic/php-parser/lib/PhpParser/Node/Stmt/ClassMethod.php*W f*=vendor/nikic/php-parser/lib/PhpParser/Node/Stmt/Continue_.phpW f=<vendor/nikic/php-parser/lib/PhpParser/Node/Stmt/EnumCase.phpW f9vendor/nikic/php-parser/lib/PhpParser/Node/Stmt/Goto_.php=W f=Ti:;vendor/nikic/php-parser/lib/PhpParser/Node/Stmt/ElseIf_.phpgW fg/5:9vendor/nikic/php-parser/lib/PhpParser/Node/Stmt/Else_.phpW fӃ7<vendor/nikic/php-parser/lib/PhpParser/Node/Stmt/GroupUse.php7W f7j4,@<vendor/nikic/php-parser/lib/PhpParser/Node/Stmt/Property.php W f YX?7vendor/nikic/php-parser/lib/PhpParser/Node/Stmt/Nop.php^W f^@vendor/nikic/php-parser/lib/PhpParser/Node/Stmt/HaltCompiler.php%W f%=XW=vendor/nikic/php-parser/lib/PhpParser/Node/Stmt/Function_.phpY W fY Q7vendor/nikic/php-parser/lib/PhpParser/Node/Stmt/Do_.php`W f` (X=vendor/nikic/php-parser/lib/PhpParser/Node/Stmt/StaticVar.phpW fG><vendor/nikic/php-parser/lib/PhpParser/Node/Stmt/Finally_.phpW f0[:vendor/nikic/php-parser/lib/PhpParser/Node/Stmt/Class_.phpW f4P8vendor/nikic/php-parser/lib/PhpParser/Node/Stmt/Use_.phpW fу:vendor/nikic/php-parser/lib/PhpParser/Node/Stmt/While_.phpcW fcN499vendor/nikic/php-parser/lib/PhpParser/Node/Stmt/Label.phpW f)Tf<vendor/nikic/php-parser/lib/PhpParser/Node/Stmt/TraitUse.phpW fɤ:vendor/nikic/php-parser/lib/PhpParser/Node/Stmt/Throw_.phpW f|@ 7vendor/nikic/php-parser/lib/PhpParser/Node/Stmt/If_.phpXW fXJ9vendor/nikic/php-parser/lib/PhpParser/Node/Stmt/Echo_.phpW f89 E<vendor/nikic/php-parser/lib/PhpParser/Node/Stmt/Foreach_.phpW fl:vendor/nikic/php-parser/lib/PhpParser/Node/ComplexType.phpqW fqt"%2vendor/nikic/php-parser/lib/PhpParser/Node/Arg.php^W f^x aBvendor/nikic/php-parser/lib/PhpParser/Node/Name/FullyQualified.phpW f<vendor/nikic/php-parser/lib/PhpParser/Node/Name/Relative.phpW f;}5vendor/nikic/php-parser/lib/PhpParser/Node/Const_.phpW f8Nu8vendor/nikic/php-parser/lib/PhpParser/Node/UnionType.phpW fK=vendor/nikic/php-parser/lib/PhpParser/Node/Scalar/String_.phpW f+<=vendor/nikic/php-parser/lib/PhpParser/Node/Scalar/DNumber.phpW fR,@vendor/nikic/php-parser/lib/PhpParser/Node/Scalar/MagicConst.phpW f򛫤>vendor/nikic/php-parser/lib/PhpParser/Node/Scalar/Encapsed.phpW f9Hvendor/nikic/php-parser/lib/PhpParser/Node/Scalar/EncapsedStringPart.phpW f.q=vendor/nikic/php-parser/lib/PhpParser/Node/Scalar/LNumber.php W f IEvendor/nikic/php-parser/lib/PhpParser/Node/Scalar/MagicConst/File.phpnW fn 1dGvendor/nikic/php-parser/lib/PhpParser/Node/Scalar/MagicConst/Trait_.phprW fr>"Kvendor/nikic/php-parser/lib/PhpParser/Node/Scalar/MagicConst/Namespace_.php~W f~פGvendor/nikic/php-parser/lib/PhpParser/Node/Scalar/MagicConst/Method.phptW ftԽDvendor/nikic/php-parser/lib/PhpParser/Node/Scalar/MagicConst/Dir.phpkW fkФJvendor/nikic/php-parser/lib/PhpParser/Node/Scalar/MagicConst/Function_.php{W f{Gvendor/nikic/php-parser/lib/PhpParser/Node/Scalar/MagicConst/Class_.phprW fŕEvendor/nikic/php-parser/lib/PhpParser/Node/Scalar/MagicConst/Line.phpnW fng3vendor/nikic/php-parser/lib/PhpParser/Node/Expr.phpW f(@vendor/nikic/php-parser/lib/PhpParser/Node/VarLikeIdentifier.phpW fA)Bvendor/nikic/php-parser/lib/PhpParser/Node/VariadicPlaceholder.phpW fZ7vendor/nikic/php-parser/lib/PhpParser/Node/MatchArm.phpW f%$q!3vendor/nikic/php-parser/lib/PhpParser/Node/Stmt.phpW f"J9vendor/nikic/php-parser/lib/PhpParser/Node/Identifier.php W f y>O3vendor/nikic/php-parser/lib/PhpParser/Node/Name.php?W f?x/vendor/nikic/php-parser/lib/PhpParser/Error.phpW fk5=vendor/nikic/php-parser/lib/PhpParser/NodeVisitorAbstract.phpW fOFvendor/nikic/php-parser/lib/PhpParser/ConstExprEvaluationException.phpnW fnAŤ@vendor/nikic/php-parser/lib/PhpParser/NodeTraverserInterface.phpW fY5vendor/nikic/php-parser/lib/PhpParser/Parser/Php7.phpcUW fcUs5vendor/nikic/php-parser/lib/PhpParser/Parser/Php5.phpa,W fa,׮9vendor/nikic/php-parser/lib/PhpParser/Parser/Multiple.phpW fL]n7vendor/nikic/php-parser/lib/PhpParser/Parser/Tokens.php5W f5[@vendor/nikic/php-parser/lib/PhpParser/PrettyPrinter/Standard.phpХW fХ8vendor/nikic/php-parser/lib/PhpParser/BuilderHelpers.php%W f%ûOvendor/nikic/php-parser/lib/PhpParser/Lexer/TokenEmulator/AttributeEmulator.phpW fN0[vendor/nikic/php-parser/lib/PhpParser/Lexer/TokenEmulator/ReadonlyFunctionTokenEmulator.phpW fMSvendor/nikic/php-parser/lib/PhpParser/Lexer/TokenEmulator/ReadonlyTokenEmulator.phpjW fjςSvendor/nikic/php-parser/lib/PhpParser/Lexer/TokenEmulator/NullsafeTokenEmulator.phpW fHꓤWvendor/nikic/php-parser/lib/PhpParser/Lexer/TokenEmulator/FlexibleDocStringEmulator.php W f jMMvendor/nikic/php-parser/lib/PhpParser/Lexer/TokenEmulator/KeywordEmulator.phpW f^MSvendor/nikic/php-parser/lib/PhpParser/Lexer/TokenEmulator/ExplicitOctalEmulator.phpW f yOvendor/nikic/php-parser/lib/PhpParser/Lexer/TokenEmulator/EnumTokenEmulator.phpW fGMvendor/nikic/php-parser/lib/PhpParser/Lexer/TokenEmulator/FnTokenEmulator.phpW fHMvendor/nikic/php-parser/lib/PhpParser/Lexer/TokenEmulator/ReverseEmulator.phpW f Wvendor/nikic/php-parser/lib/PhpParser/Lexer/TokenEmulator/CoaleseEqualTokenEmulator.php)W f)p0AKvendor/nikic/php-parser/lib/PhpParser/Lexer/TokenEmulator/TokenEmulator.phpW fM]vendor/nikic/php-parser/lib/PhpParser/Lexer/TokenEmulator/NumericLiteralSeparatorEmulator.phptW ft jePvendor/nikic/php-parser/lib/PhpParser/Lexer/TokenEmulator/MatchTokenEmulator.phpW f K9vendor/nikic/php-parser/lib/PhpParser/Lexer/Emulative.phpO$W fO$ 1vendor/autoload.phpW fSS$vendor/phpstan/phpdoc-parser/LICENSE.W f.-:vendor/phpstan/phpdoc-parser/src/Ast/Type/ThisTypeNode.php7W f7 Eqͤ;vendor/phpstan/phpdoc-parser/src/Ast/Type/ArrayTypeNode.phpW f6vendor/phpstan/phpdoc-parser/src/Ast/Type/TypeNode.phpW fIMvendor/phpstan/phpdoc-parser/src/Ast/Type/ConditionalTypeForParameterNode.phpW fIT>vendor/phpstan/phpdoc-parser/src/Ast/Type/CallableTypeNode.phpW fLƤAvendor/phpstan/phpdoc-parser/src/Ast/Type/ObjectShapeItemNode.php!W f!Bvendor/phpstan/phpdoc-parser/src/Ast/Type/OffsetAccessTypeNode.phpW f1ܤ>vendor/phpstan/phpdoc-parser/src/Ast/Type/NullableTypeNode.phpW fLۤHvendor/phpstan/phpdoc-parser/src/Ast/Type/ArrayShapeUnsealedTypeNode.php(W f(Gvendor/phpstan/phpdoc-parser/src/Ast/Type/CallableTypeParameterNode.phpW f&*;vendor/phpstan/phpdoc-parser/src/Ast/Type/ConstTypeNode.php>W f>H0@vendor/phpstan/phpdoc-parser/src/Ast/Type/IdentifierTypeNode.phpW fQ Avendor/phpstan/phpdoc-parser/src/Ast/Type/ConditionalTypeNode.phpW f G\@vendor/phpstan/phpdoc-parser/src/Ast/Type/ArrayShapeItemNode.phpW fZL=vendor/phpstan/phpdoc-parser/src/Ast/Type/InvalidTypeNode.phpyW fyV<vendor/phpstan/phpdoc-parser/src/Ast/Type/ArrayShapeNode.phpW f|=vendor/phpstan/phpdoc-parser/src/Ast/Type/GenericTypeNode.phpBW fBj}=vendor/phpstan/phpdoc-parser/src/Ast/Type/ObjectShapeNode.php\W f\Bvendor/phpstan/phpdoc-parser/src/Ast/Type/IntersectionTypeNode.phpW f-;vendor/phpstan/phpdoc-parser/src/Ast/Type/UnionTypeNode.phpW fvXԤ4vendor/phpstan/phpdoc-parser/src/Ast/NodeVisitor.php W f Cvendor/phpstan/phpdoc-parser/src/Ast/NodeVisitor/CloningVisitor.php%W f%@7vendor/phpstan/phpdoc-parser/src/Ast/NodeAttributes.phpW f2vendor/phpstan/phpdoc-parser/src/Ast/Attribute.phpPW fPKvendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/TypeAliasImportTagValueNode.phpW f4Dvendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/PropertyTagValueNode.phpQW fQBvendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/ReturnTagValueNode.phpW fBvendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/MethodTagValueNode.phpW f螳Kvendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/MethodTagValueParameterNode.phpW fhHvendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/AssertTagMethodValueNode.php W f $~R;Lvendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/ParamClosureThisTagValueNode.php^W f^1Ϥ=vendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/PhpDocTagNode.php+W f+N[vendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/ParamImmediatelyInvokedCallableTagValueNode.phpW f8PܤCvendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/ExtendsTagValueNode.phpW fF:\?vendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/PhpDocChildNode.phpW fCvendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/GenericTagValueNode.phpW f_>5Ivendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/TypelessParamTagValueNode.phpW f7l$Fvendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/ImplementsTagValueNode.phpW ftLBvendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/AssertTagValueNode.phpW f \Cvendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/InvalidTagValueNode.phpW f@vendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/UsesTagValueNode.phpW fGVDvendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/TemplateTagValueNode.phptW ftyB.Avendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/ParamTagValueNode.phpW feϤEvendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/TypeAliasTagValueNode.phpW f=[פ>vendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/PhpDocTextNode.phpW f*I_Bvendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/ThrowsTagValueNode.phpW fFvendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/DeprecatedTagValueNode.phpW fBvendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/PhpDocTagValueNode.phpW f 4?vendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/VarTagValueNode.phpfW ff|E;Dvendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/ParamOutTagValueNode.phpVW fVrJvendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/AssertTagPropertyValueNode.phpW f1Jvendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/RequireExtendsTagValueNode.phpW f6Avendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/MixinTagValueNode.phpW f& Jvendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/Doctrine/DoctrineArrayItem.phpW f)Fvendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/Doctrine/DoctrineArray.phpW firMvendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/Doctrine/DoctrineTagValueNode.phpW fΑ]SKvendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/Doctrine/DoctrineAnnotation.phpW fimIvendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/Doctrine/DoctrineArgument.php W f <:vendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/PhpDocNode.php,W f,Uvendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/ParamLaterInvokedCallableTagValueNode.phpW f`Mvendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/RequireImplementsTagValueNode.phpW f,~Cvendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/SelfOutTagValueNode.phpW fH 6vendor/phpstan/phpdoc-parser/src/Ast/NodeTraverser.php4*W f4*.k-vendor/phpstan/phpdoc-parser/src/Ast/Node.phpW fP<vendor/phpstan/phpdoc-parser/src/Ast/AbstractNodeVisitor.phpW fXa7Evendor/phpstan/phpdoc-parser/src/Ast/ConstExpr/ConstExprFalseNode.phpGW fGBEvendor/phpstan/phpdoc-parser/src/Ast/ConstExpr/ConstExprFloatNode.phpW fMhڤGvendor/phpstan/phpdoc-parser/src/Ast/ConstExpr/ConstExprIntegerNode.phpW f:DDvendor/phpstan/phpdoc-parser/src/Ast/ConstExpr/ConstExprNullNode.phpEW fE+:Ivendor/phpstan/phpdoc-parser/src/Ast/ConstExpr/ConstExprArrayItemNode.phpW fžEvendor/phpstan/phpdoc-parser/src/Ast/ConstExpr/ConstExprArrayNode.phpPW fP ǗAvendor/phpstan/phpdoc-parser/src/Ast/ConstExpr/ConstFetchNode.phpW fPvendor/phpstan/phpdoc-parser/src/Ast/ConstExpr/QuoteAwareConstExprStringNode.php6 W f6 WѤ@vendor/phpstan/phpdoc-parser/src/Ast/ConstExpr/ConstExprNode.phpW fFvendor/phpstan/phpdoc-parser/src/Ast/ConstExpr/ConstExprStringNode.phpW f{# Dvendor/phpstan/phpdoc-parser/src/Ast/ConstExpr/ConstExprTrueNode.phpEW fEL4Nvendor/phpstan/phpdoc-parser/src/Ast/ConstExpr/DoctrineConstExprStringNode.phpW fW3vendor/phpstan/phpdoc-parser/src/Printer/Differ.phprW frIt5vendor/phpstan/phpdoc-parser/src/Printer/DiffElem.phpW fhusz4vendor/phpstan/phpdoc-parser/src/Printer/Printer.phpW f)ǡ);vendor/phpstan/phpdoc-parser/src/Parser/StringUnescaper.phpl W fl :8vendor/phpstan/phpdoc-parser/src/Parser/PhpDocParser.phpW f;vendor/phpstan/phpdoc-parser/src/Parser/ParserException.php W f 2716vendor/phpstan/phpdoc-parser/src/Parser/TypeParser.phppW fpv9vendor/phpstan/phpdoc-parser/src/Parser/TokenIterator.php#W f#J;vendor/phpstan/phpdoc-parser/src/Parser/ConstExprParser.php&W f&vk#Y0vendor/phpstan/phpdoc-parser/src/Lexer/Lexer.phpW f!$vendor/doctrine/deprecations/LICENSE)W f)"0Fvendor/doctrine/deprecations/lib/Doctrine/Deprecations/Deprecation.phpl$W fl$o7Uvendor/doctrine/deprecations/lib/Doctrine/Deprecations/PHPUnit/VerifyDeprecations.php W f "vendor/composer/autoload_files.phpW fkP&vendor/composer/xdebug-handler/LICENSE)W f)#;^0vendor/composer/xdebug-handler/src/PhpConfig.phpW fI Ǥ.vendor/composer/xdebug-handler/src/Process.phpv W fv djҤ4vendor/composer/xdebug-handler/src/XdebugHandler.phpTW fT4-vendor/composer/xdebug-handler/src/Status.phpqW fq*vendor/composer/LICENSE.W f. 'vendor/composer/autoload_namespaces.phpW f/tvendor/composer/installed.phpUW fUFJCvendor/composer/ClassLoader.php?W f?2@u!vendor/composer/autoload_real.phpW fq7"vendor/composer/platform_check.phpW fqK\#vendor/composer/autoload_static.phpW fg vendor/composer/semver/LICENSEW fBh,vendor/composer/semver/src/VersionParser.phpUW fUe)vendor/composer/semver/src/Comparator.phpj W fj r,Ĥ(vendor/composer/semver/src/Intervals.phpNW fN*e/vendor/composer/semver/src/CompilingMatcher.php5 W f5 ۫'vendor/composer/semver/src/Interval.phpW f:4vendor/composer/semver/src/Constraint/Constraint.php0W f0>Ӥ=vendor/composer/semver/src/Constraint/ConstraintInterface.phpW f;9vendor/composer/semver/src/Constraint/MultiConstraint.phpD#W fD#`~:=vendor/composer/semver/src/Constraint/MatchNoneConstraint.phpW f{,|<vendor/composer/semver/src/Constraint/MatchAllConstraint.phpW f9/vendor/composer/semver/src/Constraint/Bound.phpI W fI դ%vendor/composer/semver/src/Semver.php\ W f\ YFKĤ%vendor/composer/autoload_classmap.php-W f-U%vendor/composer/InstalledVersions.phpK?W fK?`!vendor/composer/autoload_psr4.php W f O+Avendor/composer/pcre/LICENSEW fhg^6vendor/composer/pcre/src/MatchAllWithOffsetsResult.phpW f:3vendor/composer/pcre/src/MatchWithOffsetsResult.phpW fR賓*vendor/composer/pcre/src/PcreException.php W f h$!vendor/composer/pcre/src/Preg.phpYEW fYEy9vendor/composer/pcre/src/UnexpectedNullMatchException.phpW fQ+vendor/composer/pcre/src/MatchAllResult.phpW f/ݱ7vendor/composer/pcre/src/MatchAllStrictGroupsResult.phpW fcY"(vendor/composer/pcre/src/MatchResult.phpW fj<vendor/composer/pcre/src/PHPStan/InvalidRegexPatternRule.phpW f܎3vendor/composer/pcre/src/PHPStan/PregMatchFlags.phpx W fx ҤLvendor/composer/pcre/src/PHPStan/PregReplaceCallbackClosureTypeExtension.php W f ?vendor/composer/pcre/src/PHPStan/UnsafeStrictGroupsCallRule.php}W f})5/Gvendor/composer/pcre/src/PHPStan/PregMatchParameterOutTypeExtension.phpW f<꼤Evendor/composer/pcre/src/PHPStan/PregMatchTypeSpecifyingExtension.php W f tɤ"vendor/composer/pcre/src/Regex.phpW f^*vendor/composer/pcre/src/ReplaceResult.phpW f61Ij4vendor/composer/pcre/src/MatchStrictGroupsResult.phpW f.`#vendor/composer/pcre/extension.neonW f&&1assets/psalm-phar/dot-gitignoreW fP sTassets/psalm-phar/composer.jsonW f+assets/psalm-phar/README.mdnW fn+E+src/Psalm/Plugin/DynamicFunctionStorage.phpW f2#src/Psalm/Plugin/ArgTypeInferer.phpsW fsT\ ,src/Psalm/Plugin/FileExtensionsInterface.php6W f6j2src/Psalm/Plugin/PluginFileExtensionsInterface.phpW f*src/Psalm/Plugin/RegistrationInterface.phpW f%դ.src/Psalm/Plugin/PluginEntryPointInterface.phpW fDsrc/Psalm/Plugin/EventHandler/AfterFunctionLikeAnalysisInterface.phpfW ff4`>src/Psalm/Plugin/EventHandler/AfterClassLikeVisitInterface.phpQW fQݷAsrc/Psalm/Plugin/EventHandler/AfterCodebasePopulatedInterface.phpW f+m7Gsrc/Psalm/Plugin/EventHandler/AfterClassLikeExistenceCheckInterface.phpW f<==src/Psalm/Plugin/EventHandler/BeforeFileAnalysisInterface.php&W f& 5Isrc/Psalm/Plugin/EventHandler/AfterEveryFunctionCallAnalysisInterface.phpW f7tAsrc/Psalm/Plugin/EventHandler/FunctionParamsProviderInterface.phpW fUDsrc/Psalm/Plugin/EventHandler/AfterFunctionCallAnalysisInterface.phpW f,Asrc/Psalm/Plugin/EventHandler/AfterStatementAnalysisInterface.php]W f]&Esrc/Psalm/Plugin/EventHandler/PropertyVisibilityProviderInterface.phpgW fg/Isrc/Psalm/Plugin/EventHandler/DynamicFunctionStorageProviderInterface.phpW f7ߍBsrc/Psalm/Plugin/EventHandler/AfterMethodCallAnalysisInterface.phpW f<4src/Psalm/Plugin/EventHandler/AddTaintsInterface.php7W f7hBsrc/Psalm/Plugin/EventHandler/BeforeStatementAnalysisInterface.php W f V&<src/Psalm/Plugin/EventHandler/AfterFileAnalysisInterface.php!W f!o?src/Psalm/Plugin/EventHandler/PropertyTypeProviderInterface.phpjW fjYިDsrc/Psalm/Plugin/EventHandler/PropertyExistenceProviderInterface.phpW f+ǤEsrc/Psalm/Plugin/EventHandler/FunctionReturnTypeProviderInterface.phpW fs?src/Psalm/Plugin/EventHandler/MethodParamsProviderInterface.phpW fʫCsrc/Psalm/Plugin/EventHandler/BeforeExpressionAnalysisInterface.php[W f['ua7src/Psalm/Plugin/EventHandler/RemoveTaintsInterface.php?W f?暤Csrc/Psalm/Plugin/EventHandler/MethodReturnTypeProviderInterface.phpW fف Bsrc/Psalm/Plugin/EventHandler/MethodExistenceProviderInterface.phpW f'8src/Psalm/Plugin/EventHandler/AfterAnalysisInterface.phpW fAXAsrc/Psalm/Plugin/EventHandler/AfterClassLikeAnalysisInterface.phpW fM79src/Psalm/Plugin/EventHandler/BeforeAddIssueInterface.phpW f١EGsrc/Psalm/Plugin/EventHandler/Event/FunctionReturnTypeProviderEvent.phpW fͤCsrc/Psalm/Plugin/EventHandler/Event/AfterCodebasePopulatedEvent.phpW f@$Asrc/Psalm/Plugin/EventHandler/Event/PropertyTypeProviderEvent.phpW fKbKsrc/Psalm/Plugin/EventHandler/Event/AfterEveryFunctionCallAnalysisEvent.phpW f/ۤFsrc/Psalm/Plugin/EventHandler/Event/FunctionExistenceProviderEvent.phpW fCFsrc/Psalm/Plugin/EventHandler/Event/AfterFunctionCallAnalysisEvent.phpW fy;src/Psalm/Plugin/EventHandler/Event/BeforeAddIssueEvent.phpW f A>src/Psalm/Plugin/EventHandler/Event/AfterFileAnalysisEvent.phpW fW/vFsrc/Psalm/Plugin/EventHandler/Event/AfterFunctionLikeAnalysisEvent.php' W f' Ň;Fsrc/Psalm/Plugin/EventHandler/Event/PropertyExistenceProviderEvent.phpW fbA]@src/Psalm/Plugin/EventHandler/Event/AfterClassLikeVisitEvent.phpW fa8HCsrc/Psalm/Plugin/EventHandler/Event/FunctionParamsProviderEvent.phpW fc>src/Psalm/Plugin/EventHandler/Event/StringInterpreterEvent.phpdW fdlaIsrc/Psalm/Plugin/EventHandler/Event/AfterClassLikeExistenceCheckEvent.phpW f>ۤ<src/Psalm/Plugin/EventHandler/Event/AddRemoveTaintsEvent.php:W f:RmCsrc/Psalm/Plugin/EventHandler/Event/AfterStatementAnalysisEvent.phpW fݤDsrc/Psalm/Plugin/EventHandler/Event/MethodExistenceProviderEvent.phpW f&Dsrc/Psalm/Plugin/EventHandler/Event/AfterExpressionAnalysisEvent.phpW f"ӤKsrc/Psalm/Plugin/EventHandler/Event/DynamicFunctionStorageProviderEvent.phpgW fg?src/Psalm/Plugin/EventHandler/Event/BeforeFileAnalysisEvent.phpW f` Dsrc/Psalm/Plugin/EventHandler/Event/BeforeStatementAnalysisEvent.php&W f&'+EEsrc/Psalm/Plugin/EventHandler/Event/MethodVisibilityProviderEvent.php W f ֓Gsrc/Psalm/Plugin/EventHandler/Event/PropertyVisibilityProviderEvent.phpW f3:src/Psalm/Plugin/EventHandler/Event/AfterAnalysisEvent.php^W f^؂)Dsrc/Psalm/Plugin/EventHandler/Event/AfterMethodCallAnalysisEvent.php W f ^zEsrc/Psalm/Plugin/EventHandler/Event/MethodReturnTypeProviderEvent.php W f J~Esrc/Psalm/Plugin/EventHandler/Event/BeforeExpressionAnalysisEvent.phpW fl5ڤAsrc/Psalm/Plugin/EventHandler/Event/MethodParamsProviderEvent.phpW f53Csrc/Psalm/Plugin/EventHandler/Event/AfterClassLikeAnalysisEvent.php5W f5Qh<src/Psalm/Plugin/EventHandler/StringInterpreterInterface.phpWW fWn2Csrc/Psalm/Plugin/EventHandler/MethodVisibilityProviderInterface.php_W f_Bsrc/Psalm/Plugin/EventHandler/AfterExpressionAnalysisInterface.phpcW fc(uDsrc/Psalm/Plugin/EventHandler/FunctionExistenceProviderInterface.phpW f^I*src/Psalm/Plugin/Shepherd.php'W f'}5,src/Psalm/Plugin/DynamicTemplateProvider.phpW f |$src/Psalm/Plugin/PluginInterface.php>W f>Ѓ src/Psalm/Config.phpVW fVnGsrc/Psalm/Type/TypeNode.phpW fY Rsrc/Psalm/Type/TypeVisitor.phpW fʡb&src/Psalm/Type/Atomic/TNamedObject.phpW f src/Psalm/Type/Atomic/TVoid.phpW fXx1src/Psalm/Type/Atomic/TAnonymousClassInstance.phpW f1Z+src/Psalm/Type/Atomic/TDependentListKey.phpW fNyX'src/Psalm/Type/Atomic/TEmptyNumeric.phpqW fqO̙6)src/Psalm/Type/Atomic/TNonFalsyString.phpW f;,src/Psalm/Type/Atomic/TDependentGetClass.phpW f/lsrc/Psalm/Type/Atomic/TTrue.phpW f݆)src/Psalm/Type/Atomic/TCallableString.phpW f W)src/Psalm/Type/Atomic/TClassStringMap.phpW fj, src/Psalm/Type/Atomic/TFalse.phpW fm (src/Psalm/Type/Atomic/TNumericString.phpW f;msrc/Psalm/Type/Atomic/TNull.phpnW fn\ !|*src/Psalm/Type/Atomic/TLowercaseString.phpxW fx٤$src/Psalm/Type/Atomic/TTypeAlias.php W f @Ɂ src/Psalm/Type/Atomic/Scalar.phpW fJч-src/Psalm/Type/Atomic/TUnknownClassString.phpW fE_"src/Psalm/Type/Atomic/TClosure.php W f k&src/Psalm/Type/Atomic/TConditional.phpW f 0Ǥ*src/Psalm/Type/Atomic/TTemplateValueOf.phpW fCQĤ;src/Psalm/Type/Atomic/TNonEmptyNonspecificLiteralString.phpW f78'src/Psalm/Type/Atomic/TPropertiesOf.php W f aX)src/Psalm/Type/Atomic/TCallableObject.phpCW fC>򂣤(src/Psalm/Type/Atomic/TLiteralString.phpB W fB >i.src/Psalm/Type/Atomic/HasIntersectionTrait.phpLW fLê)src/Psalm/Type/Atomic/TClosedResource.phpW fyoJ+src/Psalm/Type/Atomic/TDependentGetType.phpW fIT src/Psalm/Type/Atomic/TArray.phpFW fF7 src/Psalm/Type/Atomic/TFloat.phpCW fCj6#src/Psalm/Type/Atomic/TIterable.phpW f9(src/Psalm/Type/Atomic/TTemplateKeyOf.phpW f)#src/Psalm/Type/Atomic/TResource.phpW faf-src/Psalm/Type/Atomic/TTemplateParamClass.phpW fL|0src/Psalm/Type/Atomic/TDependentGetDebugType.phpW f|X-src/Psalm/Type/Atomic/TLiteralClassString.php W f :'src/Psalm/Type/Atomic/TLiteralFloat.phpW fI)src/Psalm/Type/Atomic/TNonEmptyString.phpW f6 src/Psalm/Type/Atomic/TNever.phpW fĤsrc/Psalm/Type/Atomic/TInt.php;W f;[[%#src/Psalm/Type/Atomic/TArrayKey.phpW f" src/Psalm/Type/Atomic/TMixed.phpFW fF-K(src/Psalm/Type/Atomic/TClassConstant.phpyW fyqݤ/src/Psalm/Type/Atomic/TObjectWithProperties.phpW fݷL&src/Psalm/Type/Atomic/TClassString.phpW f̭˺'src/Psalm/Type/Atomic/TCallableList.php?W f?ˡ%src/Psalm/Type/Atomic/TLiteralInt.phpUW fUG" src/Psalm/Type/Atomic/TKeyOf.php9 W f9 z,3src/Psalm/Type/Atomic/TNonspecificLiteralString.phpW fes,(src/Psalm/Type/Atomic/TNonEmptyArray.phpW fd)src/Psalm/Type/Atomic/TNonEmptyScalar.php8W f8ge-src/Psalm/Type/Atomic/TCallableKeyedArray.php_W f_w%src/Psalm/Type/Atomic/TEmptyMixed.phpW fFv#src/Psalm/Type/Atomic/TEnumCase.php W f m,src/Psalm/Type/Atomic/TBool.php>W f>$&src/Psalm/Type/Atomic/TEmptyScalar.php-W f-a-̤2src/Psalm/Type/Atomic/TNonEmptyLowercaseString.phpmW fm(VMa,src/Psalm/Type/Atomic/TCallableInterface.phpFW fFZ $src/Psalm/Type/Atomic/TIntMaskOf.phpW f'&src/Psalm/Type/Atomic/GenericTrait.phpW fV(src/Psalm/Type/Atomic/TTemplateParam.phpW fN7'src/Psalm/Type/Atomic/DependentType.php.W f.RI!src/Psalm/Type/Atomic/TString.phpGW fG-7#src/Psalm/Type/Atomic/TIntRange.phpW f`'src/Psalm/Type/Atomic/CallableTrait.phpr$W fr$\(src/Psalm/Type/Atomic/TCallableArray.php6W f6s"src/Psalm/Type/Atomic/TIntMask.phpW fOzYTsrc/Psalm/Type/Atomic/TList.php7W f7xu"src/Psalm/Type/Atomic/TNumeric.phpW f0src/Psalm/Type/Atomic/TNonspecificLiteralInt.phpCW fCil'src/Psalm/Type/Atomic/TNonEmptyList.phpjW fj3V#src/Psalm/Type/Atomic/TCallable.php W f &src/Psalm/Type/Atomic/TTraitString.phpW fT(src/Psalm/Type/Atomic/TGenericObject.phpW f|j%src/Psalm/Type/Atomic/TKeyedArray.phpRW fRJ2<"src/Psalm/Type/Atomic/TValueOf.phpW fם4$!src/Psalm/Type/Atomic/TObject.phpW fiY̤(src/Psalm/Type/Atomic/TNonEmptyMixed.phpW f/src/Psalm/Type/Atomic/TTemplatePropertiesOf.php W f 4o!src/Psalm/Type/Atomic/TScalar.php8W f8MԤ'src/Psalm/Type/Atomic/TSingleLetter.phpW fDg0src/Psalm/Type/Atomic/TTemplateIndexedAccess.phpW f*%src/Psalm/Type/MutableTypeVisitor.phpW fO!src/Psalm/Type/TaintKindGroup.phpW fγsrc/Psalm/Type/Reconciler.phpW flsrc/Psalm/Type/MutableUnion.php8W f84src/Psalm/Type/TaintKind.phpW f\wksrc/Psalm/Type/UnionTrait.phpW f<src/Psalm/Type/Atomic.phpdW fdꃩsrc/Psalm/Type/Union.php+W f+Lsrc/Psalm/DocComment.php W f src/Psalm/Aliases.phpW fjsrc/Psalm/Report.php W f p/src/Psalm/Issue/UndefinedMagicPropertyFetch.phpW f6K(src/Psalm/Issue/PropertyTypeCoercion.phpW fNi(src/Psalm/Issue/UndefinedMagicMethod.phpW fڥ-src/Psalm/Issue/InvalidFalsableReturnType.phpW f1D%src/Psalm/Issue/MutableDependency.phpW f5mݤ+src/Psalm/Issue/PossiblyUndefinedMethod.phpW f%src/Psalm/Issue/MixedFunctionCall.phpW fӭ(src/Psalm/Issue/PossiblyNullIterator.phpW f'src/Psalm/Issue/ContinueOutsideLoop.phpW f KA!src/Psalm/Issue/InvalidGlobal.phpW fY@.8src/Psalm/Issue/PossiblyFalsePropertyAssignmentValue.phpW fJ8*src/Psalm/Issue/PossiblyFalseReference.phpW fWϤ+src/Psalm/Issue/NamedArgumentNotAllowed.phpW f2G{'src/Psalm/Issue/UnusedPsalmSuppress.phpW fġ)%src/Psalm/Issue/DuplicateFunction.phpW fҴ8K&src/Psalm/Issue/InvalidStringClass.phpW f5J$src/Psalm/Issue/InvalidAttribute.phpW fŻ src/Psalm/Issue/NullArgument.phpW fMl#src/Psalm/Issue/DeprecatedClass.phpW fHnsrc/Psalm/Issue/ClassIssue.phpW fnۤ%src/Psalm/Issue/ParamNameMismatch.phpW fT'src/Psalm/Issue/UnsafeInstantiation.phpW fw&%src/Psalm/Issue/InvalidTypeImport.phpW fR*src/Psalm/Issue/OverriddenMethodAccess.phpW fˡ"src/Psalm/Issue/TaintedInclude.phpW f`-src/Psalm/Issue/PossiblyUnusedReturnValue.phpW f8src/Psalm/Issue/MethodSignatureMustProvideReturnType.phpW f11썤0src/Psalm/Issue/ReferenceConstraintViolation.phpW f#src/Psalm/Issue/TooFewArguments.phpW fiH8src/Psalm/Issue/UnusedParam.phpW f/i!src/Psalm/Issue/NullReference.phpW fФ%src/Psalm/Issue/UnusedConstructor.phpW fي%src/Psalm/Issue/NullPropertyFetch.php+W f+#src/Psalm/Issue/InvalidArgument.phpW fdYԪ*src/Psalm/Issue/UndefinedDocblockClass.phpW f(#src/Psalm/Issue/MixedMethodCall.phpW f?Eͤ%src/Psalm/Issue/UnusedReturnValue.phpW fY+src/Psalm/Issue/PossiblyNullArrayAccess.php8W f8*'M2src/Psalm/Issue/InvalidPropertyAssignmentValue.phpW fm#src/Psalm/Issue/DuplicateMethod.phpW fʤUsrc/Psalm/Issue/NoValue.phpW f`w(src/Psalm/Issue/InaccessibleProperty.phpW f@"src/Psalm/Issue/UnusedVariable.phpW f&)src/Psalm/Issue/AbstractInstantiation.phpW f%ɤ src/Psalm/Issue/TaintedShell.phpW fQ"src/Psalm/Issue/DuplicateClass.phpW f77*4src/Psalm/Issue/NonInvariantDocblockPropertyType.phpW f2 ¤+src/Psalm/Issue/MixedReturnTypeCoercion.phpW fc+ src/Psalm/Issue/UnusedMethod.phpW fcѳ+src/Psalm/Issue/OverriddenFinalConstant.phpW fw7!src/Psalm/Issue/PropertyIssue.phpW f̨src/Psalm/Issue/TaintedLdap.phpW f:0src/Psalm/Issue/ImplementedParamTypeMismatch.phpW fe#src/Psalm/Issue/NullArrayAccess.php)W f)bNw*src/Psalm/Issue/PossiblyInvalidOperand.phpW fȤ-src/Psalm/Issue/MixedArgumentTypeCoercion.phpW f+src/Psalm/Issue/MissingClosureParamType.phpW fR,src/Psalm/Issue/InvalidClassConstantType.phpW f4N&src/Psalm/Issue/DeprecatedConstant.phpW fp'+դ src/Psalm/Issue/InvalidCatch.phpW fUYje#src/Psalm/Issue/InvalidDocblock.phpW fQ}J.src/Psalm/Issue/PossiblyInvalidArrayOffset.phpW fuۤsrc/Psalm/Issue/CodeIssue.php' W f' j.src/Psalm/Issue/RiskyTruthyFalsyComparison.phpW fԤ'src/Psalm/Issue/MissingPropertyType.phpW f#src/Psalm/Issue/NullArrayOffset.phpW f6'src/Psalm/Issue/InvalidParamDefault.phpW f q:*src/Psalm/Issue/InvalidArrayAssignment.phpW fj!+src/Psalm/Issue/PossiblyInvalidArgument.phpW fo#(src/Psalm/Issue/InvalidNamedArgument.phpW f)פ)src/Psalm/Issue/MissingThrowsDocblock.phpW fHjQ/src/Psalm/Issue/OverriddenInterfaceConstant.phpW fQ$src/Psalm/Issue/DeprecatedMethod.phpW f5src/Psalm/Issue/PossiblyInvalidPropertyAssignment.phpW fZϙ1src/Psalm/Issue/ImplementedReturnTypeMismatch.phpW f5 src/Psalm/Issue/ReservedWord.phpW f=F*src/Psalm/Issue/UnrecognizedExpression.phpW f0 0src/Psalm/Issue/MismatchingDocblockParamType.phpW f(src/Psalm/Issue/ImplicitToStringCast.phpW fnUv-src/Psalm/Issue/PossiblyInvalidMethodCall.phpW f-u ,src/Psalm/Issue/OverriddenPropertyAccess.phpW fl *"src/Psalm/Issue/UndefinedTrait.phpW fϤ$src/Psalm/Issue/TooManyArguments.phpW fU0&src/Psalm/Issue/InvalidArrayOffset.phpW fPZ%src/Psalm/Issue/UndefinedConstant.phpW fȊФ(src/Psalm/Issue/MixedReturnStatement.phpW f!src/Psalm/Issue/ArgumentIssue.phpW f,%src/Psalm/Issue/DuplicateEnumCase.phpW f%*Ť src/Psalm/Issue/InvalidScope.phpW fߏǤ,src/Psalm/Issue/PossiblyNullFunctionCall.phpW f'src/Psalm/Issue/MissingDocblockType.phpW fL.src/Psalm/Issue/Trace.phpW f)/src/Psalm/Issue/PropertyNotSetInConstructor.phpW f 0&src/Psalm/Issue/DeprecatedProperty.phpW fh z%src/Psalm/Issue/MissingReturnType.phpW f׊&src/Psalm/Issue/UnusedFunctionCall.phpW fOԅ-src/Psalm/Issue/RedundantIdentityWithTrue.phpW fy*src/Psalm/Issue/InvalidLiteralArgument.phpW fT%src/Psalm/Issue/DuplicateArrayKey.phpW f6&src/Psalm/Issue/RawObjectIteration.phpW f4@b*src/Psalm/Issue/TypeDoesNotContainNull.phpW f淽Ф*src/Psalm/Issue/MixedArrayTypeCoercion.phpW fљ&%src/Psalm/Issue/TaintedUserSecret.phpW fn'src/Psalm/Issue/ImpurePropertyFetch.phpW fȤ"src/Psalm/Issue/ParentNotFound.phpW fޤ#src/Psalm/Issue/MixedIssueTrait.phpW fq*src/Psalm/Issue/InvalidReturnStatement.phpW fqaT$src/Psalm/Issue/AssignmentToVoid.phpW fvx(8src/Psalm/Issue/RedundantPropertyInitializationCheck.phpW f֕'src/Psalm/Issue/UnusedDocblockParam.phpW fF#src/Psalm/Issue/DeprecatedTrait.phpW fIݰ+src/Psalm/Issue/UndefinedGlobalVariable.phpW fGW턤5src/Psalm/Issue/ReferenceReusedFromConfusingScope.phpW fݪD.src/Psalm/Issue/PossiblyInvalidDocblockTag.phpW fT-2src/Psalm/Issue/InvalidInterfaceImplementation.phpW fx#,src/Psalm/Issue/MissingOverrideAttribute.phpW fp2src/Psalm/Issue/PossiblyNullPropertyAssignment.php?W f?*&src/Psalm/Issue/AbstractMethodCall.phpW fd*src/Psalm/Issue/PossiblyUnusedProperty.phpW fsrc/Psalm/Issue/UnusedClass.phpW f#src/Psalm/Issue/UnevaluatedCode.phpW f"+src/Psalm/Issue/UndefinedAttributeClass.phpW f'src/Psalm/Issue/PossiblyUnusedParam.phpW fH&src/Psalm/Issue/TaintedUnserialize.phpW f>ͤ%src/Psalm/Issue/UndefinedVariable.phpW fG6%src/Psalm/Issue/InvalidEnumMethod.phpW fsxP src/Psalm/Issue/InvalidClass.phpW fe$src/Psalm/Issue/NoEnumProperties.phpW f2src/Psalm/Issue/PossiblyInvalidArrayAssignment.phpW f &src/Psalm/Issue/MissingConstructor.phpW fQ$src/Psalm/Issue/InternalProperty.phpW f`w0src/Psalm/Issue/PossiblyUndefinedArrayOffset.phpW f1&src/Psalm/Issue/MixedPropertyFetch.phpW fĤΤ+src/Psalm/Issue/NullableReturnStatement.phpW f )+src/Psalm/Issue/InvalidStaticInvocation.phpW f$src/Psalm/Issue/ImpureMethodCall.phpW f"src/Psalm/Issue/InternalMethod.phpW f!13src/Psalm/Issue/UndefinedThisPropertyAssignment.phpW f֤src/Psalm/Issue/CheckType.phpW f>#C&src/Psalm/Issue/ClassConstantIssue.php}W f}`0ڤ+src/Psalm/Issue/PossiblyNullArrayOffset.phpW fxm#src/Psalm/Issue/InvalidOverride.phpW f src/Psalm/Issue/ConfigIssue.phpW fµ :src/Psalm/Issue/PossiblyInvalidPropertyAssignmentValue.phpW fT1src/Psalm/Issue/LessSpecificClassConstantType.phpW ff3src/Psalm/Issue/PossiblyUndefinedGlobalVariable.phpW fߤ"src/Psalm/Issue/DuplicateParam.phpW fM5src/Psalm/Issue/MethodSignatureMustOmitReturnType.phpW fi#src/Psalm/Issue/StringIncrement.phpW fkq$src/Psalm/Issue/NullFunctionCall.phpW fјu0src/Psalm/Issue/PossiblyInvalidPropertyFetch.phpW fY9k!src/Psalm/Issue/InternalClass.phpW f#src/Psalm/Issue/InvalidToString.phpW f -src/Psalm/Issue/UnsupportedReferenceUsage.phpW fy6#src/Psalm/Issue/TaintedCallable.phpW f\ˤ)src/Psalm/Issue/DirectConstructorCall.phpW fQ_&src/Psalm/Issue/InvalidArrayAccess.phpW fͤ0src/Psalm/Issue/TraitMethodSignatureMismatch.phpW f7¤src/Psalm/Issue/ParseError.phpW f1src/Psalm/Issue/ExtensionRequirementViolation.phpW fIsrc/Psalm/Issue/MixedClone.phpW f֤)src/Psalm/Issue/TaintedTextWithQuotes.phpW fpLX9(src/Psalm/Issue/InvalidEnumCaseValue.phpW fܤ%src/Psalm/Issue/MissingDependency.phpW fӬ+src/Psalm/Issue/PossiblyInvalidIterator.phpW f|;B(src/Psalm/Issue/MixedArrayAssignment.phpW f4&src/Psalm/Issue/InvalidExtendClass.phpW fa Ȥ*src/Psalm/Issue/InvalidEnumBackingType.phpW for!src/Psalm/Issue/FunctionIssue.phpW fCN1src/Psalm/Issue/MismatchingDocblockReturnType.phpW fOy+src/Psalm/Issue/MethodSignatureMismatch.phpW fūM6src/Psalm/Issue/ImplementationRequirementViolation.phpW f-Ϥ0src/Psalm/Issue/AmbiguousConstantInheritance.phpW fK src/Psalm/Issue/MixedOperand.phpW f|\src/Psalm/Issue/MixedIssue.phpW f!Ϥsrc/Psalm/Issue/InvalidCast.phpW fye-src/Psalm/Issue/InvalidPropertyAssignment.phpW f&f.(src/Psalm/Issue/PossiblyUnusedMethod.phpW f'src/Psalm/Issue/PossiblyInvalidCast.phpW fl:)src/Psalm/Issue/MissingClassConstType.phpW fI/src/Psalm/Issue/LessSpecificReturnStatement.phpW f^s-src/Psalm/Issue/MixedPropertyTypeCoercion.phpW fp/=̤)src/Psalm/Issue/UnrecognizedStatement.phpW f5w/src/Psalm/Issue/PossiblyNullArrayAssignment.phpW fc"=&src/Psalm/Issue/PsalmInternalError.phpW fa3'src/Psalm/Issue/DeprecatedInterface.phpW fD-src/Psalm/Issue/DocblockTypeContradiction.phpW f21.src/Psalm/Issue/PossiblyInvalidArrayAccess.phpW fQr<&src/Psalm/Issue/UnusedForeachValue.phpW fp-src/Psalm/Issue/InvalidNullableReturnType.phpW fDH)src/Psalm/Issue/NoInterfaceProperties.phpW fX7f src/Psalm/Issue/FalseOperand.phpW f&src/Psalm/Issue/PrivateFinalMethod.phpW fm$src/Psalm/Issue/UnusedMethodCall.phpW fr*src/Psalm/Issue/LessSpecificReturnType.phpW fyp-src/Psalm/Issue/InaccessibleClassConstant.phpW f"src/Psalm/Issue/UndefinedClass.phpW fsrc/Psalm/Issue/NullOperand.phpW fEwV!src/Psalm/Issue/MixedArgument.phpW fx  src/Psalm/Issue/NullIterator.phpW fQyhsrc/Psalm/Issue/MethodIssue.phpW fLup#src/Psalm/Issue/UndefinedMethod.phpW f%Ӥ+src/Psalm/Issue/MixedInferredReturnType.phpW f)b!src/Psalm/Issue/TaintedCustom.phpW fiT4src/Psalm/Issue/UndefinedMagicPropertyAssignment.phpW f޾פsrc/Psalm/Issue/RiskyCast.phpW fW˖!src/Psalm/Issue/RedundantCast.phpW fb"src/Psalm/Issue/UnusedProperty.phpW fU.src/Psalm/Issue/MissingImmutableAnnotation.phpW f/m$src/Psalm/Issue/IfThisIsMismatch.phpW faŔ#src/Psalm/Issue/MixedAssignment.phpW f¿7src/Psalm/Issue/RedundantConditionGivenDocblockType.phpW fD<&src/Psalm/Issue/InaccessibleMethod.phpW f-_&src/Psalm/Issue/ImpureFunctionCall.phpW fe?e3src/Psalm/Issue/PossiblyUndefinedIntArrayOffset.phpW fIMΤ(src/Psalm/Issue/PossiblyFalseOperand.phpW fΤ$src/Psalm/Issue/MixedArrayAccess.phpW f\OѤ/src/Psalm/Issue/UndefinedPropertyAssignment.phpW f+M7"src/Psalm/Issue/InvalidOperand.phpW fgū(src/Psalm/Issue/InvalidPropertyFetch.phpW fRFO,src/Psalm/Issue/NonInvariantPropertyType.phpW fc +src/Psalm/Issue/MixedPropertyAssignment.phpW fX(src/Psalm/Issue/MissingTemplateParam.phpW f9=௤+src/Psalm/Issue/FalsableReturnStatement.phpW f.src/Psalm/Issue/ConstantDeclarationInTrait.phpW f7l#src/Psalm/Issue/ComplexFunction.phpW fE:src/Psalm/Issue/RedundantFunctionCallGivenDocblockType.phpW fR!src/Psalm/Issue/TaintedHeader.phpW f[ݤ4src/Psalm/Issue/MoreSpecificImplementedParamType.phpW f¤0src/Psalm/Issue/UnimplementedInterfaceMethod.phpW f2&src/Psalm/Issue/UnusedClosureParam.phpW fR 0/ src/Psalm/Issue/TaintedInput.phpW f *src/Psalm/Issue/UndefinedPropertyFetch.phpW fMn&src/Psalm/Issue/InheritorViolation.phpW f'5L?2src/Psalm/Issue/InvalidConstantAssignmentValue.phpW f Z)src/Psalm/Issue/PossiblyFalseIterator.phpW ffG,src/Psalm/Issue/ImpurePropertyAssignment.phpW fh)src/Psalm/Issue/TaintedSql.php~W f~="src/Psalm/Issue/UndefinedTrace.phpW f$'src/Psalm/Issue/PossiblyNullOperand.phpW f R[src/Psalm/Issue/TaintedSSRF.phpW fj_6src/Psalm/Issue/PossiblyUndefinedStringArrayOffset.phpW fu)src/Psalm/Issue/InvalidScalarArgument.phpW f@A9%src/Psalm/Issue/CircularReference.phpW fYj)src/Psalm/Issue/PossiblyNullReference.phpW f20src/Psalm/Issue/ConstructorSignatureMismatch.phpW fyg֤-src/Psalm/Issue/PossiblyNullPropertyFetch.php:W f:o*src/Psalm/Issue/DuplicateEnumCaseValue.phpW fe2src/Psalm/Issue/ConflictingReferenceConstraint.phpW ftN src/Psalm/Issue/InvalidClone.phpW f?$src/Psalm/Issue/MissingParamType.phpW fj5src/Psalm/Issue/LessSpecificImplementedReturnType.phpW f!3)src/Psalm/Issue/TooManyTemplateParams.phpW f^*src/Psalm/Issue/MoreSpecificReturnType.phpW f%src/Psalm/Issue/InvalidReturnType.phpW f((src/Psalm/Issue/ImpureStaticProperty.phpW f0i/src/Psalm/Issue/ImpureByReferenceAssignment.phpW f|ҍ7src/Psalm/Issue/PossiblyNullPropertyAssignmentValue.phpW f0*src/Psalm/Issue/InterfaceInstantiation.phpW f^ᔤ"src/Psalm/Issue/ImpureVariable.phpW fk (src/Psalm/Issue/ArgumentTypeCoercion.phpW fӖ!src/Psalm/Issue/VariableIssue.phpW f"vG!src/Psalm/Issue/TaintedCookie.phpW f5R&src/Psalm/Issue/DeprecatedFunction.phpW f_Ĥ)src/Psalm/Issue/UninitializedProperty.phpW f[J41!src/Psalm/Issue/RedundantFlag.phpW f_E {%src/Psalm/Issue/InvalidMethodCall.phpW fHE3src/Psalm/Issue/MismatchingDocblockPropertyType.phpW fg42src/Psalm/Issue/RedundantCastGivenDocblockType.phpW fYߤ*src/Psalm/Issue/InvalidPassByReference.phpW f src/Psalm/Issue/InvalidThrow.phpW f23!src/Psalm/Issue/ComplexMethod.phpW f0ZBsrc/Psalm/Issue/TaintedHtml.phpW f$+src/Psalm/Issue/UnhandledMatchCondition.phpW fCah,src/Psalm/Issue/UnnecessaryVarAnnotation.phpW f6zb]5src/Psalm/Issue/UnsupportedPropertyReferenceUsage.phpW fxN!ڤ,src/Psalm/Issue/InvalidDocblockParamName.phpW fZ(src/Psalm/Issue/UnresolvableConstant.phpW fЯt%src/Psalm/Issue/NonStaticSelfCall.phpW fR'src/Psalm/Issue/InvalidFunctionCall.phpW fN)src/Psalm/Issue/RedundantFunctionCall.phpW f !src/Psalm/Issue/InvalidParent.phpW f7'src/Psalm/Issue/UnresolvableInclude.phpW f $k.src/Psalm/Issue/PossibleRawObjectIteration.phpW fM!#src/Psalm/Issue/InvalidIterator.phpW f.Q/src/Psalm/Issue/UnimplementedAbstractMethod.phpW f src/Psalm/Issue/MissingFile.php|W f|,)src/Psalm/Issue/PossiblyFalseArgument.phpW f]!src/Psalm/Issue/ForbiddenCode.phpW fy6'src/Psalm/Issue/UnusedBaselineEntry.phpW f ),src/Psalm/Issue/UndefinedInterfaceMethod.phpW fhL(src/Psalm/Issue/ParadoxicalCondition.phpW f -src/Psalm/Issue/PossiblyUndefinedVariable.phpW f$&src/Psalm/Issue/UndefinedInterface.phpW fo%src/Psalm/Issue/DuplicateConstant.phpW f$\'src/Psalm/Issue/TaintedSystemSecret.phpW f(src/Psalm/Issue/PossiblyInvalidClone.phpW fjŐsrc/Psalm/Issue/PluginIssue.php]W f]䕿H.src/Psalm/Issue/UndefinedThisPropertyFetch.phpW fD(src/Psalm/Issue/PossiblyNullArgument.phpW f4>c4src/Psalm/Issue/InvalidTraversableImplementation.phpW f.src/Psalm/Issue/UnsafeGenericInstantiation.phpW f&/src/Psalm/Issue/PossiblyInvalidFunctionCall.phpW fң`%src/Psalm/Issue/UndefinedFunction.phpW fN*src/Psalm/Issue/NullPropertyAssignment.php0W f06src/Psalm/Issue/TaintedEval.phpW f&sxP&src/Psalm/Issue/RedundantCondition.phpW fX|Ϥ$src/Psalm/Issue/MixedArrayOffset.phpW fI,src/Psalm/Issue/MissingClosureReturnType.phpW fKIsrc/Psalm/Issue/TaintedFile.phpW f¤(src/Psalm/Issue/InvalidTemplateParam.phpW f!a*src/Psalm/Issue/TypeDoesNotContainType.phpW fz`I(src/Psalm/Issue/ImpureStaticVariable.phpW f2B$src/Psalm/Issue/LoopInvalidation.phpW f2.src/Psalm/Issue/UncaughtThrowInGlobalScope.phpW f/src/Psalm/Issue/MixedStringOffsetAssignment.phpW f>$src/Psalm/Issue/EmptyArrayAccess.phpW fRXRCsrc/Psalm/Internal/FileManipulation/PropertyDocblockManipulator.phpW fR[p5src/Psalm/Internal/FileManipulation/CodeMigration.phpW f >src/Psalm/Internal/FileManipulation/FileManipulationBuffer.phpW fz@src/Psalm/Internal/FileManipulation/ClassDocblockManipulator.php W f Csrc/Psalm/Internal/FileManipulation/FunctionDocblockManipulator.phpJW fJ-Ҳsrc/Psalm/Internal/Algebra.php`W f`-#src/Psalm/Internal/VersionUtils.php W f p2src/Psalm/Internal/Scanner/PhpStormMetaScanner.phpL8W fL8 s6src/Psalm/Internal/Scanner/FunctionDocblockComment.php W f ;u-src/Psalm/Internal/Scanner/DocblockParser.php(W f(:src/Psalm/Internal/Scanner/UnresolvedConstantComponent.phpW fC*src/Psalm/Internal/Scanner/FileScanner.php W f m7src/Psalm/Internal/Scanner/ClassLikeDocblockComment.phpW f+(k-src/Psalm/Internal/Scanner/ParsedDocblock.php W f z<1src/Psalm/Internal/Scanner/VarDocblockComment.phpCW fC>src/Psalm/Internal/Scanner/UnresolvedConstant/KeyValuePair.phpW f3פ=src/Psalm/Internal/Scanner/UnresolvedConstant/ScalarValue.phpW f̓dDsrc/Psalm/Internal/Scanner/UnresolvedConstant/UnresolvedBinaryOp.phpFW fFՖäFsrc/Psalm/Internal/Scanner/UnresolvedConstant/UnresolvedAdditionOp.phpW fΧEEsrc/Psalm/Internal/Scanner/UnresolvedConstant/UnresolvedBitwiseOr.phpW f#Bsrc/Psalm/Internal/Scanner/UnresolvedConstant/ArrayOffsetFetch.phpW fK ?src/Psalm/Internal/Scanner/UnresolvedConstant/ClassConstant.phpW f+Dsrc/Psalm/Internal/Scanner/UnresolvedConstant/UnresolvedConcatOp.php!W f!ѤCsrc/Psalm/Internal/Scanner/UnresolvedConstant/EnumPropertyFetch.phpW fAmcFsrc/Psalm/Internal/Scanner/UnresolvedConstant/UnresolvedDivisionOp.php#W f#gFsrc/Psalm/Internal/Scanner/UnresolvedConstant/UnresolvedBitwiseXor.phpW f9|bCsrc/Psalm/Internal/Scanner/UnresolvedConstant/UnresolvedTernary.phpW f Lsrc/Psalm/Internal/Scanner/UnresolvedConstant/UnresolvedMultiplicationOp.php)W f)kնFsrc/Psalm/Internal/Scanner/UnresolvedConstant/UnresolvedBitwiseAnd.phpW f_<src/Psalm/Internal/Scanner/UnresolvedConstant/ArrayValue.phpW f>2?src/Psalm/Internal/Scanner/UnresolvedConstant/EnumNameFetch.phpW fIsrc/Psalm/Internal/Scanner/UnresolvedConstant/UnresolvedSubtractionOp.php&W f&ܯؤ@src/Psalm/Internal/Scanner/UnresolvedConstant/EnumValueFetch.phpW f,Ǥ=src/Psalm/Internal/Scanner/UnresolvedConstant/ArraySpread.php|W f|@m:src/Psalm/Internal/Scanner/UnresolvedConstant/Constant.phpW f) src/Psalm/Internal/Clause.phpW fCC4src/Psalm/Internal/TypeVisitor/ClasslikeReplacer.phppW fpRc8src/Psalm/Internal/TypeVisitor/ContainsStaticVisitor.phprW fr=Ĥ.src/Psalm/Internal/TypeVisitor/TypeScanner.php W f eᆤ9src/Psalm/Internal/TypeVisitor/ContainsLiteralVisitor.phpW fR00src/Psalm/Internal/TypeVisitor/TypeLocalizer.php) W f) I5src/Psalm/Internal/TypeVisitor/FromDocblockSetter.php W f |>src/Psalm/Internal/TypeVisitor/CanContainObjectTypeVisitor.phpW f  8src/Psalm/Internal/TypeVisitor/TemplateTypeCollector.phpW f^/.src/Psalm/Internal/TypeVisitor/TypeChecker.php-W f-;src/Psalm/Internal/TypeVisitor/ContainsClassLikeVisitor.phpW fa/src/Psalm/Internal/Type/ParseTree/UnionTree.phpW f5~F+src/Psalm/Internal/Type/ParseTree/Value.php\W f\䫚Ӥ@src/Psalm/Internal/Type/ParseTree/CallableWithReturnTypeTree.phpW fxo;97src/Psalm/Internal/Type/ParseTree/CallableParamTree.phpjW fjS!*src/Psalm/Internal/Type/ParseTree/Root.phpW fLj֤1src/Psalm/Internal/Type/ParseTree/GenericTree.phpmW fmK6src/Psalm/Internal/Type/ParseTree/IntersectionTree.phpW f) Ϥ3src/Psalm/Internal/Type/ParseTree/FieldEllipsis.phpW fWkH2src/Psalm/Internal/Type/ParseTree/CallableTree.phpnW fn,Lm0src/Psalm/Internal/Type/ParseTree/MethodTree.phpFW fF7src/Psalm/Internal/Type/ParseTree/IndexedAccessTree.phpMW fMO%"4src/Psalm/Internal/Type/ParseTree/KeyedArrayTree.phppW fp^l] 7src/Psalm/Internal/Type/ParseTree/EncapsulationTree.phpW fցU֤4src/Psalm/Internal/Type/ParseTree/TemplateAsTree.phpW fʫ.<src/Psalm/Internal/Type/ParseTree/KeyedArrayPropertyTree.phpRW fRp>src/Psalm/Internal/Type/ParseTree/MethodWithReturnTypeTree.phpW f55src/Psalm/Internal/Type/ParseTree/MethodParamTree.phpW fw Τ2src/Psalm/Internal/Type/ParseTree/NullableTree.phpW fT_4src/Psalm/Internal/Type/ParseTree/TemplateIsTree.php^W f^Ϥ5src/Psalm/Internal/Type/ParseTree/ConditionalTree.phpW f*VKv4src/Psalm/Internal/Type/ClosedInheritanceToUnion.php5 W f5 $5&4src/Psalm/Internal/Type/TypeAlias/ClassTypeAlias.phpW f)%5src/Psalm/Internal/Type/TypeAlias/InlineTypeAlias.phpNW fNb} 7src/Psalm/Internal/Type/TypeAlias/LinkableTypeAlias.php<W f<&/src/Psalm/Internal/Type/AssertionReconciler.phpgW fg <src/Psalm/Internal/Type/SimpleNegatedAssertionReconciler.phpW fk|)src/Psalm/Internal/Type/TemplateBound.phpW f|%src/Psalm/Internal/Type/ArrayType.phpW f̤7src/Psalm/Internal/Type/TemplateStandinTypeReplacer.phpW fyo@(src/Psalm/Internal/Type/TypeCombiner.php9W f9g?+src/Psalm/Internal/Type/TypeCombination.php W f `&src/Psalm/Internal/Type/TypeParser.php_W f_W*6src/Psalm/Internal/Type/NegatedAssertionReconciler.php2?W f2?4)src/Psalm/Internal/Type/TypeTokenizer.php5W f5f&0I5src/Psalm/Internal/Type/SimpleAssertionReconciler.php^W f^IZ*src/Psalm/Internal/Type/TemplateResult.php+ W f+ eF%src/Psalm/Internal/Type/ParseTree.php~W f~U-n,src/Psalm/Internal/Type/ParseTreeCreator.phppW fp$Z%src/Psalm/Internal/Type/TypeAlias.php?W f?48src/Psalm/Internal/Type/TemplateInferredTypeReplacer.phpAW fAap f:src/Psalm/Internal/Type/Comparator/UnionTypeComparator.phpCW fCͼt;src/Psalm/Internal/Type/Comparator/TypeComparisonResult.php\W f\mt7src/Psalm/Internal/Type/Comparator/ObjectComparator.phpw3W fw3m;src/Psalm/Internal/Type/Comparator/AtomicTypeComparator.phpdW fd颬;src/Psalm/Internal/Type/Comparator/ScalarTypeComparator.php*HW f*H~@src/Psalm/Internal/Type/Comparator/ClassLikeStringComparator.php W f &x<src/Psalm/Internal/Type/Comparator/GenericTypeComparator.phpkW fkkG֤=src/Psalm/Internal/Type/Comparator/IntegerRangeComparator.phpW fSR;src/Psalm/Internal/Type/Comparator/KeyedArrayComparator.php9W f9nnq:src/Psalm/Internal/Type/Comparator/ArrayTypeComparator.phpcW fcW=src/Psalm/Internal/Type/Comparator/CallableTypeComparator.phpGW fG[i(src/Psalm/Internal/Type/TypeExpander.php}W f}]X'src/Psalm/Internal/IncludeCollector.phpW fsrc/Psalm/Internal/CliUtils.php@W f@;3src/Psalm/Internal/PhpTraverser/CustomTraverser.phpW f)*src/Psalm/Internal/ReferenceConstraint.phpW fi=src/Psalm/Internal/Stubs/Generator/ClassLikeStubGenerator.phpV"W fV"MR5src/Psalm/Internal/Stubs/Generator/StubsGenerator.php9.W f9.4src/Psalm/Internal/Provider/MethodParamsProvider.php W f Aw8src/Psalm/Internal/Provider/MethodReturnTypeProvider.php W f & 8src/Psalm/Internal/Provider/FileStorageCacheProvider.phpW f[V8src/Psalm/Internal/Provider/MethodVisibilityProvider.php]W f]}>7src/Psalm/Internal/Provider/MethodExistenceProvider.phppW fpi\9src/Psalm/Internal/Provider/FunctionExistenceProvider.phphW fh0src/Psalm/Internal/Provider/FakeFileProvider.phpZ W fZ uZ:src/Psalm/Internal/Provider/PropertyVisibilityProvider.phpW fܤ3src/Psalm/Internal/Provider/ParserCacheProvider.php+W f+nŝȤ=src/Psalm/Internal/Provider/ClassLikeStorageCacheProvider.php%W f%괤:src/Psalm/Internal/Provider/FileReferenceCacheProvider.php.W f. 5src/Psalm/Internal/Provider/FileReferenceProvider.phpW fm,6src/Psalm/Internal/Provider/FunctionParamsProvider.phpc W fc SHsrc/Psalm/Internal/Provider/ParamsProvider/ArrayFilterParamsProvider.phpW fJKsrc/Psalm/Internal/Provider/ParamsProvider/ArrayMultisortParamsProvider.php#W f#Q$kTsrc/Psalm/Internal/Provider/PropertyTypeProvider/DomDocumentPropertyTypeProvider.phpW fS''>src/Psalm/Internal/Provider/DynamicFunctionStorageProvider.php W f 3G4J0src/Psalm/Internal/Provider/NodeDataProvider.phpW fe8h,src/Psalm/Internal/Provider/FileProvider.phpW fST֤Csrc/Psalm/Internal/Provider/AddRemoveTaints/HtmlFunctionTainter.phpW f9)src/Psalm/Internal/Provider/Providers.php W f pV!2src/Psalm/Internal/Provider/StatementsProvider.phpI8W fI82OE3src/Psalm/Internal/Provider/FileStorageProvider.php W f Ӥ4src/Psalm/Internal/Provider/PropertyTypeProvider.phpW f4Pf9src/Psalm/Internal/Provider/PropertyExistenceProvider.phpW f7[i8src/Psalm/Internal/Provider/ClassLikeStorageProvider.php(W f(A4src/Psalm/Internal/Provider/ProjectCacheProvider.phpIW fIjӤ:src/Psalm/Internal/Provider/FunctionReturnTypeProvider.phpUW fU)Qsrc/Psalm/Internal/Provider/ReturnTypeProvider/TriggerErrorReturnTypeProvider.php W f Esrc/Psalm/Internal/Provider/ReturnTypeProvider/DomNodeAppendChild.phpgW fgMsrc/Psalm/Internal/Provider/ReturnTypeProvider/BasenameReturnTypeProvider.php W f igKsrc/Psalm/Internal/Provider/ReturnTypeProvider/MktimeReturnTypeProvider.phpHW fH栦Nsrc/Psalm/Internal/Provider/ReturnTypeProvider/ArrayRandReturnTypeProvider.phpW f?-Psrc/Psalm/Internal/Provider/ReturnTypeProvider/ArrayColumnReturnTypeProvider.php%W f%Ssrc/Psalm/Internal/Provider/ReturnTypeProvider/VersionCompareReturnTypeProvider.php W f DNsrc/Psalm/Internal/Provider/ReturnTypeProvider/FilterVarReturnTypeProvider.php\W f\Osrc/Psalm/Internal/Provider/ReturnTypeProvider/ArrayMergeReturnTypeProvider.php'W f'|)Msrc/Psalm/Internal/Provider/ReturnTypeProvider/ArrayPopReturnTypeProvider.php W f O{Lsrc/Psalm/Internal/Provider/ReturnTypeProvider/InArrayReturnTypeProvider.phpe W fe 8Osrc/Psalm/Internal/Provider/ReturnTypeProvider/ArraySliceReturnTypeProvider.php W f r5Psrc/Psalm/Internal/Provider/ReturnTypeProvider/ArraySpliceReturnTypeProvider.phpW f󨭤Hsrc/Psalm/Internal/Provider/ReturnTypeProvider/PowReturnTypeProvider.php W f /sRsrc/Psalm/Internal/Provider/ReturnTypeProvider/ArrayFillKeysReturnTypeProvider.php> W f> B32Xsrc/Psalm/Internal/Provider/ReturnTypeProvider/ClosureFromCallableReturnTypeProvider.phpW fKsrc/Psalm/Internal/Provider/ReturnTypeProvider/MinMaxReturnTypeProvider.phpuW fu SIsrc/Psalm/Internal/Provider/ReturnTypeProvider/RandReturnTypeProvider.phpBW fBwCQsrc/Psalm/Internal/Provider/ReturnTypeProvider/PdoStatementReturnTypeProvider.phpW fAbMsrc/Psalm/Internal/Provider/ReturnTypeProvider/ParseUrlReturnTypeProvider.php(W f(Nsrc/Psalm/Internal/Provider/ReturnTypeProvider/ArrayFillReturnTypeProvider.phpW f:Lsrc/Psalm/Internal/Provider/ReturnTypeProvider/DirnameReturnTypeProvider.php W f Ӗ蹤Ssrc/Psalm/Internal/Provider/ReturnTypeProvider/FirstArgStringReturnTypeProvider.phpW f0Jsrc/Psalm/Internal/Provider/ReturnTypeProvider/RoundReturnTypeProvider.php= W f= k;*zTsrc/Psalm/Internal/Provider/ReturnTypeProvider/IteratorToArrayReturnTypeProvider.phpW f}[src/Psalm/Internal/Provider/ReturnTypeProvider/ArrayPointerAdjustmentReturnTypeProvider.phpW fL Ksrc/Psalm/Internal/Provider/ReturnTypeProvider/PdoStatementSetFetchMode.php9 W f9 `=Ksrc/Psalm/Internal/Provider/ReturnTypeProvider/HexdecReturnTypeProvider.phpXW fX=-Qsrc/Psalm/Internal/Provider/ReturnTypeProvider/ArrayReverseReturnTypeProvider.php8 W f8 V)fQsrc/Psalm/Internal/Provider/ReturnTypeProvider/ArrayCombineReturnTypeProvider.phpeW fe3nPLsrc/Psalm/Internal/Provider/ReturnTypeProvider/SprintfReturnTypeProvider.php84W f84 Y܃Msrc/Psalm/Internal/Provider/ReturnTypeProvider/ArrayMapReturnTypeProvider.php2BW f2BBPsrc/Psalm/Internal/Provider/ReturnTypeProvider/FilterInputReturnTypeProvider.phph W fh ESsrc/Psalm/Internal/Provider/ReturnTypeProvider/DateTimeModifyReturnTypeProvider.php[W f[4Osrc/Psalm/Internal/Provider/ReturnTypeProvider/ArrayChunkReturnTypeProvider.php W f Isrc/Psalm/Internal/Provider/ReturnTypeProvider/DateReturnTypeProvider.phpW fjWsrc/Psalm/Internal/Provider/ReturnTypeProvider/MbInternalEncodingReturnTypeProvider.php: W f: T Vsrc/Psalm/Internal/Provider/ReturnTypeProvider/ImagickPixelColorReturnTypeProvider.php W f L֤>src/Psalm/Internal/Provider/ReturnTypeProvider/FilterUtils.phpRW fRQJsrc/Psalm/Internal/Provider/ReturnTypeProvider/StrTrReturnTypeProvider.phpW f gPsrc/Psalm/Internal/Provider/ReturnTypeProvider/ArrayFilterReturnTypeProvider.php )W f )nMsrc/Psalm/Internal/Provider/ReturnTypeProvider/ArrayPadReturnTypeProvider.phpW f1Tsrc/Psalm/Internal/Provider/ReturnTypeProvider/GetClassMethodsReturnTypeProvider.phpW f{Psrc/Psalm/Internal/Provider/ReturnTypeProvider/ArrayReduceReturnTypeProvider.php$W f$ƬOsrc/Psalm/Internal/Provider/ReturnTypeProvider/StrReplaceReturnTypeProvider.phpW fURsrc/Psalm/Internal/Provider/ReturnTypeProvider/GetObjectVarsReturnTypeProvider.php6W f6[:3src/Psalm/Internal/Fork/ForkProcessErrorMessage.phprW frQ/src/Psalm/Internal/Fork/ForkTaskDoneMessage.phpW f+*src/Psalm/Internal/Fork/PsalmRestarter.phpW f1 src/Psalm/Internal/Fork/Pool.php>W f>oC,2src/Psalm/Internal/Fork/ForkProcessDoneMessage.phpW f:'src/Psalm/Internal/Fork/ForkMessage.phpAW fA#src/Psalm/Internal/ErrorHandler.phpA W fA ßNu6src/Psalm/Internal/PluginManager/PluginListFactory.php{ W f{ פ/src/Psalm/Internal/PluginManager/ConfigFile.phpxW fxR1src/Psalm/Internal/PluginManager/ComposerLock.php& W f& uF8src/Psalm/Internal/PluginManager/Command/ShowCommand.phpw W fw 3ޤ:src/Psalm/Internal/PluginManager/Command/EnableCommand.php W f |d6;src/Psalm/Internal/PluginManager/Command/DisableCommand.php W f >e/src/Psalm/Internal/PluginManager/PluginList.php W f #lդ>src/Psalm/Internal/ExecutionEnvironment/BuildInfoCollector.php)W f)5M<src/Psalm/Internal/ExecutionEnvironment/GitInfoCollector.php W f Asrc/Psalm/Internal/ExecutionEnvironment/SystemCommandExecutor.phpW fƤۤ'src/Psalm/Internal/MethodIdentifier.phpW fĤ9src/Psalm/Internal/PhpVisitor/ParamReplacementVisitor.php W f +[-src/Psalm/Internal/PhpVisitor/TraitFinder.phpn W fn 84src/Psalm/Internal/PhpVisitor/TypeMappingVisitor.phpfW ff9src/Psalm/Internal/PhpVisitor/CheckTrivialExprVisitor.phpe W fe P6src/Psalm/Internal/PhpVisitor/OffsetShifterVisitor.phpW f`5src/Psalm/Internal/PhpVisitor/ShortClosureVisitor.phpW fYl6src/Psalm/Internal/PhpVisitor/AssignmentMapVisitor.phpW f 0src/Psalm/Internal/PhpVisitor/CloningVisitor.php W f 44src/Psalm/Internal/PhpVisitor/NodeCounterVisitor.php@W f@9src/Psalm/Internal/PhpVisitor/ConditionCloningVisitor.phpW f>|K4src/Psalm/Internal/PhpVisitor/NodeCleanerVisitor.phpiW fi^@src/Psalm/Internal/PhpVisitor/Reflector/ClassLikeNodeScanner.phpW fפ<src/Psalm/Internal/PhpVisitor/Reflector/TypeHintResolver.phpKW fKC PCsrc/Psalm/Internal/PhpVisitor/Reflector/FunctionLikeNodeScanner.phpW f!sCsrc/Psalm/Internal/PhpVisitor/Reflector/ClassLikeDocblockParser.phpxTW fxTۇ]Fsrc/Psalm/Internal/PhpVisitor/Reflector/FunctionLikeDocblockParser.phpzhW fzhg-=src/Psalm/Internal/PhpVisitor/Reflector/ExpressionScanner.php|/W f|/",dGsrc/Psalm/Internal/PhpVisitor/Reflector/FunctionLikeDocblockScanner.php)W f)src/Psalm/Internal/PhpVisitor/Reflector/ExpressionResolver.php:EW f:E6src/Psalm/Internal/PhpVisitor/PartialParserVisitor.php^3W f^3,24src/Psalm/Internal/PhpVisitor/SimpleNameResolver.php_W f_4]2src/Psalm/Internal/PhpVisitor/ReflectorVisitor.phpVW fVw?4src/Psalm/Internal/PhpVisitor/YieldTypeCollector.phpW f/U/src/Psalm/Internal/Algebra/FormulaGenerator.phpy0W fy0|:ۤ src/Psalm/Internal/Json/Json.php" W f" ,5"src/Psalm/Internal/Cli/Psalter.php0JW f0J-] src/Psalm/Internal/Cli/Psalm.phpW f]-ȿ!src/Psalm/Internal/Cli/Plugin.phpW fc#src/Psalm/Internal/Cli/Refactor.php(W f(HՒ)src/Psalm/Internal/Cli/LanguageServer.php7W f71j6src/Psalm/Internal/LanguageServer/EmitterInterface.phpW fx01src/Psalm/Internal/LanguageServer/IdGenerator.phpUW fU>4src/Psalm/Internal/LanguageServer/ProtocolWriter.phpW fR4src/Psalm/Internal/LanguageServer/ProtocolReader.php<W f<o1fGsrc/Psalm/Internal/LanguageServer/Provider/FileStorageCacheProvider.phpW fׂBsrc/Psalm/Internal/LanguageServer/Provider/ParserCacheProvider.phpq W fq qZLsrc/Psalm/Internal/LanguageServer/Provider/ClassLikeStorageCacheProvider.phphW fh)ԁIsrc/Psalm/Internal/LanguageServer/Provider/FileReferenceCacheProvider.phpW f@ߤCsrc/Psalm/Internal/LanguageServer/Provider/ProjectCacheProvider.phpW f[Τ2src/Psalm/Internal/LanguageServer/EmitterTrait.phpW fm8src/Psalm/Internal/LanguageServer/PHPMarkdownContent.phpiW fiq 0src/Psalm/Internal/LanguageServer/PathMapper.phpW f/src/Psalm/Internal/LanguageServer/Reference.phpW f3src/Psalm/Internal/LanguageServer/ClientHandler.php W f v:src/Psalm/Internal/LanguageServer/ProtocolStreamReader.php_W f_Τ4src/Psalm/Internal/LanguageServer/LanguageClient.phpjW fjy09src/Psalm/Internal/LanguageServer/ClientConfiguration.php W f "|.src/Psalm/Internal/LanguageServer/Progress.phpW f͹Τ9src/Psalm/Internal/LanguageServer/Server/TextDocument.phpCW fCBVF6src/Psalm/Internal/LanguageServer/Server/Workspace.phpW fM :src/Psalm/Internal/LanguageServer/ProtocolStreamWriter.phpW fp8U4src/Psalm/Internal/LanguageServer/LanguageServer.phpW f1Ǥ9src/Psalm/Internal/LanguageServer/Client/TextDocument.phpW fm,6src/Psalm/Internal/LanguageServer/Client/Workspace.phpW faHGsrc/Psalm/Internal/LanguageServer/Client/Progress/ProgressInterface.phpcW fcoDsrc/Psalm/Internal/LanguageServer/Client/Progress/LegacyProgress.phpW fq>src/Psalm/Internal/LanguageServer/Client/Progress/Progress.php W f vo-src/Psalm/Internal/LanguageServer/Message.phpJW fJAsrc/Psalm/Internal/Codebase/AssertionsFromInheritanceResolver.php=W f=X0src/Psalm/Internal/Codebase/VariableUseGraph.phpW fu'(4src/Psalm/Internal/Codebase/ConstantTypeResolver.php1W f1@p)src/Psalm/Internal/Codebase/Functions.php?W f?t0CӤ6src/Psalm/Internal/Codebase/InternalCallMapHandler.php6W f6#'src/Psalm/Internal/Codebase/Scanner.phpfW ffR(src/Psalm/Internal/Codebase/Analyzer.phpDW fDs'src/Psalm/Internal/Codebase/Methods.phpW f?src/Psalm/Internal/Codebase/ClassConstantByWildcardResolver.phppW fptQ+src/Psalm/Internal/Codebase/PropertyMap.phpW f{3src/Psalm/Internal/Codebase/ImpureFunctionsList.phpW f9*src/Psalm/Internal/Codebase/ClassLikes.php2CW f2Cس}.src/Psalm/Internal/Codebase/TaintFlowGraph.php<W f<_5src/Psalm/Internal/Codebase/ReferenceMapGenerator.phpW f&-8src/Psalm/Internal/Codebase/StorageByPatternResolver.phpW fI#u-src/Psalm/Internal/Codebase/DataFlowGraph.phpRW fR*src/Psalm/Internal/Codebase/Properties.php6)W f6)f)src/Psalm/Internal/Codebase/Populator.phpޜW fޜ*src/Psalm/Internal/Codebase/Reflection.phpGW fG{m$src/Psalm/Internal/Scope/IfScope.phpW fb&src/Psalm/Internal/Scope/CaseScope.phpW f!٤/src/Psalm/Internal/Scope/IfConditionalScope.phpcW fc@k(src/Psalm/Internal/Scope/SwitchScope.phpW f7&src/Psalm/Internal/Scope/LoopScope.phpW f|H)src/Psalm/Internal/Scope/FinallyScope.phpzW fz3ޤ$src/Psalm/Internal/Diff/DiffElem.php*W f*C&src/Psalm/Internal/Diff/FileDiffer.php!W f!_1src/Psalm/Internal/Diff/ClassStatementsDiffer.php*W f*O5src/Psalm/Internal/Diff/NamespaceStatementsDiffer.phpW f4x*0src/Psalm/Internal/Diff/FileStatementsDiffer.phpW fg9%src/Psalm/Internal/Diff/AstDiffer.php] W f] {Dxsrc/Psalm/Internal/Cache.php W f H~src/Psalm/Internal/Composer.phpjW fjp&src/Psalm/Internal/EventDispatcher.phpD:W fD:I1src/Psalm/Internal/Analyzer/NamespaceAnalyzer.php#W f#0.src/Psalm/Internal/Analyzer/SourceAnalyzer.php|W f|ĉ\-src/Psalm/Internal/Analyzer/ClassAnalyzer.php2W f244׵-src/Psalm/Internal/Analyzer/TraitAnalyzer.phpW f"Y/src/Psalm/Internal/Analyzer/ClosureAnalyzer.php'W f'vO1src/Psalm/Internal/Analyzer/InterfaceAnalyzer.phpW f>#D4src/Psalm/Internal/Analyzer/FunctionLikeAnalyzer.phpW flg,src/Psalm/Internal/Analyzer/FileAnalyzer.php2QW f2QѤ.src/Psalm/Internal/Analyzer/MethodAnalyzer.php(W f(K]30src/Psalm/Internal/Analyzer/FunctionAnalyzer.phpW f4v?src/Psalm/Internal/Analyzer/FunctionLike/ReturnTypeAnalyzer.phpzW fz駇ؤ@src/Psalm/Internal/Analyzer/FunctionLike/ReturnTypeCollector.php}!W f}!W":src/Psalm/Internal/Analyzer/Statements/DeclareAnalyzer.phpd W fd (8src/Psalm/Internal/Analyzer/Statements/UnsetAnalyzer.phpW f߼;src/Psalm/Internal/Analyzer/Statements/ContinueAnalyzer.php W f src/Psalm/Internal/Analyzer/Statements/Block/WhileAnalyzer.phpKW fKCߤ;src/Psalm/Internal/Analyzer/Statements/Block/DoAnalyzer.phpW fS= 8src/Psalm/Internal/Analyzer/Statements/ThrowAnalyzer.php W f 9src/Psalm/Internal/Analyzer/Statements/StaticAnalyzer.php W f DyVsrc/Psalm/Internal/Analyzer/Statements/Expression/BinaryOp/NonComparisonOpAnalyzer.phpa W fa cSsrc/Psalm/Internal/Analyzer/Statements/Expression/BinaryOp/ArithmeticOpAnalyzer.phpW ftjJsrc/Psalm/Internal/Analyzer/Statements/Expression/BinaryOp/AndAnalyzer.phpW fJeOsrc/Psalm/Internal/Analyzer/Statements/Expression/BinaryOp/CoalesceAnalyzer.php W f >x9Msrc/Psalm/Internal/Analyzer/Statements/Expression/BinaryOp/ConcatAnalyzer.php@W f@wIsrc/Psalm/Internal/Analyzer/Statements/Expression/BinaryOp/OrAnalyzer.php`1W f`19|Hsrc/Psalm/Internal/Analyzer/Statements/Expression/BitwiseNotAnalyzer.phpCW fCceEsrc/Psalm/Internal/Analyzer/Statements/Expression/AssertionFinder.php8/W f8/YHsrc/Psalm/Internal/Analyzer/Statements/Expression/AssignmentAnalyzer.phpW f׌[Bsrc/Psalm/Internal/Analyzer/Statements/Expression/EvalAnalyzer.php W f 1Lsrc/Psalm/Internal/Analyzer/Statements/Expression/Call/ArgumentsAnalyzer.phpW fMDMsrc/Psalm/Internal/Analyzer/Statements/Expression/Call/MethodCallAnalyzer.php6W f6ۮKsrc/Psalm/Internal/Analyzer/Statements/Expression/Call/FunctionCallInfo.phpW f ֤Osrc/Psalm/Internal/Analyzer/Statements/Expression/Call/ArgumentMapPopulator.phpW fk(ܤVsrc/Psalm/Internal/Analyzer/Statements/Expression/Call/ClassTemplateParamCollector.php$W f$GMsrc/Psalm/Internal/Analyzer/Statements/Expression/Call/StaticCallAnalyzer.php1W f1WFsrc/Psalm/Internal/Analyzer/Statements/Expression/Call/NewAnalyzer.php2vW f2v҃SVsrc/Psalm/Internal/Analyzer/Statements/Expression/Call/HighOrderFunctionArgHandler.php,W f,b)/Ksrc/Psalm/Internal/Analyzer/Statements/Expression/Call/ArgumentAnalyzer.phpsW fskOsrc/Psalm/Internal/Analyzer/Statements/Expression/Call/FunctionCallAnalyzer.php;W f;Khsrc/Psalm/Internal/Analyzer/Statements/Expression/Call/StaticMethod/ExistingAtomicStaticCallAnalyzer.phpRQW fRQ.I`src/Psalm/Internal/Analyzer/Statements/Expression/Call/StaticMethod/AtomicStaticCallAnalyzer.phpW f箳Xsrc/Psalm/Internal/Analyzer/Statements/Expression/Call/FunctionCallReturnTypeFetcher.php*fW f*f|$Zsrc/Psalm/Internal/Analyzer/Statements/Expression/Call/Method/AtomicMethodCallAnalyzer.php~qW f~q,5]src/Psalm/Internal/Analyzer/Statements/Expression/Call/Method/MethodCallReturnTypeFetcher.phpHW fHrSsrc/Psalm/Internal/Analyzer/Statements/Expression/Call/Method/AtomicCallContext.phpW f%6bsrc/Psalm/Internal/Analyzer/Statements/Expression/Call/Method/ExistingAtomicMethodCallAnalyzer.phpTW fTk_src/Psalm/Internal/Analyzer/Statements/Expression/Call/Method/MethodCallProhibitionAnalyzer.phpW fT=NZsrc/Psalm/Internal/Analyzer/Statements/Expression/Call/Method/MethodCallPurityAnalyzer.phpW fd$ؤ`src/Psalm/Internal/Analyzer/Statements/Expression/Call/Method/AtomicMethodCallAnalysisResult.phpW fEZsrc/Psalm/Internal/Analyzer/Statements/Expression/Call/Method/MethodVisibilityAnalyzer.phpW f#Zsrc/Psalm/Internal/Analyzer/Statements/Expression/Call/Method/MissingMethodCallHandler.phpE3W fE3AYYsrc/Psalm/Internal/Analyzer/Statements/Expression/Call/ArrayFunctionArgumentsAnalyzer.phpW fXN&Ssrc/Psalm/Internal/Analyzer/Statements/Expression/Call/HighOrderFunctionArgInfo.phpW fqDޤSsrc/Psalm/Internal/Analyzer/Statements/Expression/Call/NamedFunctionCallHandler.phpedW fed9'&Esrc/Psalm/Internal/Analyzer/Statements/Expression/IncludeAnalyzer.php9W f9ITYsrc/Psalm/Internal/Analyzer/Statements/Expression/Fetch/InstancePropertyFetchAnalyzer.phpW:W fW:Wsrc/Psalm/Internal/Analyzer/Statements/Expression/Fetch/StaticPropertyFetchAnalyzer.php9W f94Wsrc/Psalm/Internal/Analyzer/Statements/Expression/Fetch/AtomicPropertyFetchAnalyzer.phpW fDnNsrc/Psalm/Internal/Analyzer/Statements/Expression/Fetch/ConstFetchAnalyzer.phpG&W fG&GVANsrc/Psalm/Internal/Analyzer/Statements/Expression/Fetch/ArrayFetchAnalyzer.phpW f Qsrc/Psalm/Internal/Analyzer/Statements/Expression/Fetch/VariableFetchAnalyzer.phpgW fg?Esrc/Psalm/Internal/Analyzer/Statements/Expression/TernaryAnalyzer.php.)W f.)n8ۤCsrc/Psalm/Internal/Analyzer/Statements/Expression/PrintAnalyzer.php% W f% (Y Csrc/Psalm/Internal/Analyzer/Statements/Expression/IssetAnalyzer.php- W f- @asrc/Psalm/Internal/Analyzer/Statements/Expression/Assignment/StaticPropertyAssignmentAnalyzer.phpk(W fk(Gcsrc/Psalm/Internal/Analyzer/Statements/Expression/Assignment/InstancePropertyAssignmentAnalyzer.phpmW fm0DXsrc/Psalm/Internal/Analyzer/Statements/Expression/Assignment/ArrayAssignmentAnalyzer.phpGW fGUgeQsrc/Psalm/Internal/Analyzer/Statements/Expression/Assignment/AssignedProperty.phpW f \Csrc/Psalm/Internal/Analyzer/Statements/Expression/EmptyAnalyzer.phpW fpGsrc/Psalm/Internal/Analyzer/Statements/Expression/YieldFromAnalyzer.php W f |Hsrc/Psalm/Internal/Analyzer/Statements/Expression/MagicConstAnalyzer.phpW f Gsrc/Psalm/Internal/Analyzer/Statements/Expression/SimpleTypeInferer.phpfW ff9țDJsrc/Psalm/Internal/Analyzer/Statements/Expression/ExpressionIdentifier.phpW fBsrc/Psalm/Internal/Analyzer/Statements/Expression/CastAnalyzer.phpExW fEx3sLsrc/Psalm/Internal/Analyzer/Statements/Expression/UnaryPlusMinusAnalyzer.phpfW ff^POHsrc/Psalm/Internal/Analyzer/Statements/Expression/ClassConstAnalyzer.php>{W f>{:&EBsrc/Psalm/Internal/Analyzer/Statements/Expression/CallAnalyzer.phpFW fF!*Csrc/Psalm/Internal/Analyzer/Statements/Expression/YieldAnalyzer.php7W f7AդGsrc/Psalm/Internal/Analyzer/Statements/Expression/ArrayCreationInfo.phpAW fACsrc/Psalm/Internal/Analyzer/Statements/Expression/MatchAnalyzer.php&W f&UrBsrc/Psalm/Internal/Analyzer/Statements/Expression/ExitAnalyzer.phpbW fbFsrc/Psalm/Internal/Analyzer/Statements/Expression/BinaryOpAnalyzer.php_FW f_FCsrc/Psalm/Internal/Analyzer/Statements/Expression/CloneAnalyzer.phpmW fmפFsrc/Psalm/Internal/Analyzer/Statements/Expression/NullsafeAnalyzer.phpQ W fQ bդHsrc/Psalm/Internal/Analyzer/Statements/Expression/BooleanNotAnalyzer.php@W f@CHsrc/Psalm/Internal/Analyzer/Statements/Expression/InstanceofAnalyzer.php W f 8Csrc/Psalm/Internal/Analyzer/Statements/Expression/ArrayAnalyzer.php]W f]ݐNsrc/Psalm/Internal/Analyzer/Statements/Expression/IncDecExpressionAnalyzer.phpW fΆPsrc/Psalm/Internal/Analyzer/Statements/Expression/EncapsulatedStringAnalyzer.phpW f=src/Psalm/Internal/Analyzer/Statements/ExpressionAnalyzer.phpJW fJ!9src/Psalm/Internal/Analyzer/Statements/GlobalAnalyzer.php>W f>` 8src/Psalm/Internal/Analyzer/Statements/BreakAnalyzer.php? W f? /src/Psalm/Internal/Analyzer/CommentAnalyzer.php>W f>}*)src/Psalm/Internal/Analyzer/IssueData.php] W f] L84src/Psalm/Internal/Analyzer/ClassLikeNameOptions.phpW f0src/Psalm/Internal/Analyzer/MethodComparator.php7W f7K];e0src/Psalm/Internal/Analyzer/DataFlowNodeData.phpUW fUm2src/Psalm/Internal/Analyzer/AttributesAnalyzer.phpk0W fk0191src/Psalm/Internal/Analyzer/ClassLikeAnalyzer.php\W f\g5g/src/Psalm/Internal/Analyzer/ProjectAnalyzer.phpMW fM~-src/Psalm/Internal/Analyzer/ScopeAnalyzer.phpz6W fz62src/Psalm/Internal/Analyzer/StatementsAnalyzer.php%W f%%=$`(src/Psalm/Internal/Analyzer/CanAlias.phpLW fLr.^/src/Psalm/Internal/Analyzer/AlgebraAnalyzer.phpW fmrqƤ,src/Psalm/Internal/Analyzer/TypeAnalyzer.phpW fN|$src/Psalm/Internal/DataFlow/Path.phpW f~ˌ+src/Psalm/Internal/DataFlow/TaintSource.phpW f(,src/Psalm/Internal/DataFlow/DataFlowNode.phpX W fX ]H)src/Psalm/Internal/DataFlow/TaintSink.phpW fF$src/Psalm/Internal/RuntimeCaches.phpW f9V_-src/Psalm/CodeLocation/ParseErrorLocation.phpW f/src/Psalm/CodeLocation/DocblockTypeLocation.phpW fKsrc/Psalm/CodeLocation/Raw.phpW f4usrc/Psalm/Config/Creator.phpP!W fP! src/Psalm/Config/FileFilter.php(RW f(R]*Τ)src/Psalm/Config/ErrorLevelFileFilter.phpW fYǤ,src/Psalm/Config/TaintAnalysisFileFilter.phpzW fz" &src/Psalm/Config/ProjectFileFilter.php W f !src/Psalm/Config/IssueHandler.phpW f\&src/Psalm/PluginRegistrationSocket.php W f `Nsrc/Psalm/NodeTypeProvider.phpW fϠ(src/Psalm/PluginFileExtensionsSocket.php W f y}a%src/Psalm/Storage/FunctionStorage.php0W f0|#Ĥ%src/Psalm/Storage/EnumCaseStorage.phpW ffM+;)src/Psalm/Storage/FunctionLikeStorage.phpNW fNP#src/Psalm/Storage/MethodStorage.phpW fa1#src/Psalm/Storage/Possibilities.phpW fxG[+src/Psalm/Storage/FunctionLikeParameter.phpBW fBM,src/Psalm/Storage/HasAttributesInterface.phpW f src/Psalm/Storage/Assertion.phpW fPoAD<src/Psalm/Storage/UnserializeMemoryUsageSuppressionTrait.phpZW fZޭ&src/Psalm/Storage/ClassLikeStorage.php'/W f'/b[&src/Psalm/Storage/AttributeStorage.phpW fWq*src/Psalm/Storage/ClassConstantStorage.php W f `+src/Psalm/Storage/Assertion/IsNotAClass.phpW f*src/Psalm/Storage/Assertion/IsNotIsset.php/W f/#F6src/Psalm/Storage/Assertion/IsGreaterThanOrEqualTo.phpKW fKr+src/Psalm/Storage/Assertion/HasArrayKey.php_W f_"fg4src/Psalm/Storage/Assertion/NotNonEmptyCountable.phpyW fyE+src/Psalm/Storage/Assertion/IsIdentical.phpW fDȚ3src/Psalm/Storage/Assertion/IsLessThanOrEqualTo.phpBW fBO+src/Psalm/Storage/Assertion/IsCountable.phpW fPV).src/Psalm/Storage/Assertion/ArrayKeyExists.php W f n0src/Psalm/Storage/Assertion/NestedAssertions.php=W f=@.src/Psalm/Storage/Assertion/IsNotCountable.phpW fSRl)src/Psalm/Storage/Assertion/HasMethod.phpW fF/71src/Psalm/Storage/Assertion/NonEmptyCountable.phpfW ff6$?1src/Psalm/Storage/Assertion/IsNotLooselyEqual.phpUW fUl_)src/Psalm/Storage/Assertion/IsNotType.phpW fFb-src/Psalm/Storage/Assertion/HasExactCount.phpEW fE2'src/Psalm/Storage/Assertion/IsIsset.phpW fMw,src/Psalm/Storage/Assertion/IsClassEqual.phpW fF!7src/Psalm/Storage/Assertion/DoesNotHaveAtLeastCount.php?W f?&src/Psalm/Storage/Assertion/Truthy.phpW fev3*src/Psalm/Storage/Assertion/IsLessThan.php W f hs,src/Psalm/Storage/Assertion/IsEqualIsset.phpW f=m&4src/Psalm/Storage/Assertion/HasStringArrayAccess.phpW f!0.src/Psalm/Storage/Assertion/IsLooselyEqual.php W f MGw/src/Psalm/Storage/Assertion/HasAtLeastCount.phpW f쎤(src/Psalm/Storage/Assertion/IsAClass.phpWW fWnar/src/Psalm/Storage/Assertion/IsClassNotEqual.phpW fO=p/&src/Psalm/Storage/Assertion/Empty_.php.W f.uؤ5src/Psalm/Storage/Assertion/DoesNotHaveExactCount.php<W f<ZϤ.src/Psalm/Storage/Assertion/IsNotIdentical.phpLW fLic-src/Psalm/Storage/Assertion/IsGreaterThan.phpW f@Ŏ&src/Psalm/Storage/Assertion/IsType.phpW f0-^'src/Psalm/Storage/Assertion/InArray.phpW f#*src/Psalm/Storage/Assertion/NotInArray.php$W f$R/#src/Psalm/Storage/Assertion/Any.phpW fq3src/Psalm/Storage/Assertion/NotNestedAssertions.phpW fJ7h%src/Psalm/Storage/Assertion/Falsy.php$W f$ÃQ9src/Psalm/Storage/Assertion/HasIntOrStringArrayAccess.php W f ZE\4src/Psalm/Storage/Assertion/ArrayKeyDoesNotExist.phpOW fOaDW(src/Psalm/Storage/Assertion/NonEmpty.phpW f:Efx1src/Psalm/Storage/Assertion/DoesNotHaveMethod.phpW fe"src/Psalm/Storage/AttributeArg.phpW f?%src/Psalm/Storage/PropertyStorage.phpm W fm K)src/Psalm/Storage/CustomMetadataTrait.phpW f}ѕ0src/Psalm/Storage/ImmutableNonCloneableTrait.phpW fخ!src/Psalm/Storage/FileStorage.phpW fEcsrc/Psalm/Codebase.phpt!W ft!src/Psalm/Type.php}sW f}s src/Psalm/Context.phpgW fgN*src/Psalm/SourceControl/Git/RemoteInfo.phpW f[EФ*src/Psalm/SourceControl/Git/CommitInfo.php W f `/'src/Psalm/SourceControl/Git/GitInfo.phpW fuYl-src/Psalm/SourceControl/SourceControlInfo.php|W f|Tsrc/Psalm/FileSource.phpW f=;src/Psalm/IssueBuffer.php}W f}5src/Psalm/StatementsSource.phpW flĤsrc/Psalm/ErrorBaseline.php#W f#YXsrc/Psalm/CodeLocation.php4W f4}!src/Psalm/Node/VirtualConst.phpW fCH#src/Psalm/Node/VirtualUnionType.phpW fz<1src/Psalm/Node/Expr/BinaryOp/VirtualBitwiseOr.phpW fr-src/Psalm/Node/Expr/BinaryOp/VirtualEqual.phpW f??/src/Psalm/Node/Expr/BinaryOp/VirtualGreater.phpW fEփE,src/Psalm/Node/Expr/BinaryOp/VirtualPlus.phpW fڞ2src/Psalm/Node/Expr/BinaryOp/VirtualBitwiseXor.phpW fp.src/Psalm/Node/Expr/BinaryOp/VirtualConcat.phpW f w0src/Psalm/Node/Expr/BinaryOp/VirtualNotEqual.phpW f)src/Psalm/Node/Expr/VirtualInstanceof.phpW fʼniݤ$src/Psalm/Node/Expr/VirtualClone.phpW f 4$src/Psalm/Node/Expr/VirtualIsset.phpW f(src/Psalm/Node/Expr/VirtualYieldFrom.phpW fbG٤$src/Psalm/Node/Expr/VirtualThrow.phpW fr,src/Psalm/Node/Expr/VirtualArrowFunction.phpW f73%src/Psalm/Node/Expr/VirtualPreDec.phpW fp2src/Psalm/Node/Expr/VirtualStaticPropertyFetch.phpW f^)src/Psalm/Node/Expr/VirtualClosureUse.phpW f)src/Psalm/Node/Expr/VirtualUnaryMinus.phpW f DU#src/Psalm/Node/Expr/VirtualList.phpW fѵ'src/Psalm/Node/Expr/VirtualFuncCall.phpW fײ?{&src/Psalm/Node/Expr/VirtualTernary.phpW f؊6+)src/Psalm/Node/Expr/VirtualStaticCall.phpW fϤ,src/Psalm/Node/Expr/VirtualArrayDimFetch.phpW fמ&1src/Psalm/Node/Expr/AssignOp/VirtualBitwiseOr.phpW fGG~,src/Psalm/Node/Expr/AssignOp/VirtualPlus.phpW f2src/Psalm/Node/Expr/AssignOp/VirtualBitwiseXor.phpW f .src/Psalm/Node/Expr/AssignOp/VirtualConcat.phpW fy-2src/Psalm/Node/Expr/AssignOp/VirtualBitwiseAnd.phpW fT[1src/Psalm/Node/Expr/AssignOp/VirtualShiftLeft.phpW f&I+src/Psalm/Node/Expr/AssignOp/VirtualDiv.phpW fIŸ+src/Psalm/Node/Expr/AssignOp/VirtualMul.phpW f76읤+src/Psalm/Node/Expr/AssignOp/VirtualPow.phpW f%h2-src/Psalm/Node/Expr/AssignOp/VirtualMinus.phpW fFO+src/Psalm/Node/Expr/AssignOp/VirtualMod.phpW fƆ 0src/Psalm/Node/Expr/AssignOp/VirtualCoalesce.phpW fe2src/Psalm/Node/Expr/AssignOp/VirtualShiftRight.phpW f B&src/Psalm/Node/Expr/VirtualPostInc.phpW fTv(src/Psalm/Node/Expr/VirtualAssignRef.phpW f̈́'src/Psalm/Node/Expr/VirtualVariable.phpW f5&src/Psalm/Node/Expr/VirtualPostDec.phpW fHG%src/Psalm/Node/Expr/VirtualAssign.phpW f>&src/Psalm/Node/Expr/VirtualInclude.phpW f$<#src/Psalm/Node/Expr/VirtualExit.phpW f=|rsrc/Psalm/Node/VirtualName.phpW f왤src/Psalm/Node/VirtualParam.phpW fՏ&src/Psalm/Node/Stmt/VirtualFinally.phpW fW$src/Psalm/Node/Stmt/VirtualConst.phpW fL#src/Psalm/Node/Stmt/VirtualCase.phpW fJⓤ!src/Psalm/Node/Stmt/VirtualIf.phpW fN%src/Psalm/Node/Stmt/VirtualSwitch.phpW fK'src/Psalm/Node/Stmt/VirtualTryCatch.phpW f-$src/Psalm/Node/Stmt/VirtualCatch.phpW fO#(src/Psalm/Node/Stmt/VirtualInterface.phpW fR<src/Psalm/Node/Stmt/TraitUseAdaptation/VirtualPrecedence.phpW fyD/7src/Psalm/Node/Stmt/TraitUseAdaptation/VirtualAlias.phpW fP9*src/Psalm/Node/Stmt/VirtualClassMethod.phpW f!$src/Psalm/Node/Stmt/VirtualLabel.phpW f&"src/Psalm/Node/Stmt/VirtualFor.phpW fT{ۤ"src/Psalm/Node/Stmt/VirtualUse.phpW f窤%src/Psalm/Node/Stmt/VirtualGlobal.phpW fJ'src/Psalm/Node/Stmt/VirtualProperty.phpW fЍ 'src/Psalm/Node/Stmt/VirtualGroupUse.phpW f$src/Psalm/Node/Stmt/VirtualUnset.phpW fC!src/Psalm/Node/Stmt/VirtualDo.phpW fI†&src/Psalm/Node/Stmt/VirtualForeach.phpW f\3֤/src/Psalm/Node/Stmt/VirtualPropertyProperty.phpW fȳ$src/Psalm/Node/Stmt/VirtualThrow.phpW fz'src/Psalm/Node/Stmt/VirtualContinue.phpW fa~=(src/Psalm/Node/Stmt/VirtualStaticVar.phpW fPڛ$src/Psalm/Node/Stmt/VirtualClass.phpW f'9Ԥ+src/Psalm/Node/Stmt/VirtualHaltCompiler.phpW f/UϤ%src/Psalm/Node/Stmt/VirtualReturn.phpW f&&src/Psalm/Node/Stmt/VirtualDeclare.phpW f:pԤ%src/Psalm/Node/Stmt/VirtualUseUse.phpW f$src/Psalm/Node/Stmt/VirtualBreak.phpW fd\$src/Psalm/Node/Stmt/VirtualWhile.phpW f5x%src/Psalm/Node/Stmt/VirtualElseIf.phpW fU)src/Psalm/Node/Stmt/VirtualExpression.phpW fkZ#src/Psalm/Node/Stmt/VirtualGoto.phpW f*pf"src/Psalm/Node/Stmt/VirtualNop.phpW f|U'src/Psalm/Node/Stmt/VirtualFunction.phpW f܎)src/Psalm/Node/Stmt/VirtualClassConst.phpW fQd)src/Psalm/Node/Stmt/VirtualInlineHTML.phpW fwԤ#src/Psalm/Node/Stmt/VirtualElse.phpW fԠ8w%src/Psalm/Node/Stmt/VirtualStatic.phpW f@q-src/Psalm/Node/Stmt/VirtualDeclareDeclare.phpW fUq#src/Psalm/Node/Stmt/VirtualEcho.phpW f\'src/Psalm/Node/Stmt/VirtualTraitUse.phpW f}(src/Psalm/Node/Stmt/VirtualNamespace.phpW f俹$src/Psalm/Node/Stmt/VirtualTrait.phpW f)&src/Psalm/Node/VirtualNullableType.phpW fl+](src/Psalm/Node/VirtualAttributeGroup.phpW frsrc/Psalm/Node/VirtualArg.phpW fE src/Psalm/Node/VirtualNode.phpW fdښD'src/Psalm/Node/Name/VirtualRelative.phpW f -src/Psalm/Node/Name/VirtualFullyQualified.phpW fn.)src/Psalm/Node/Scalar/VirtualEncapsed.phpW f((src/Psalm/Node/Scalar/VirtualLNumber.phpW fS(src/Psalm/Node/Scalar/VirtualDNumber.phpW f'src/Psalm/Node/Scalar/VirtualString.phpW fD0src/Psalm/Node/Scalar/MagicConst/VirtualFile.phpW fA ʤ/src/Psalm/Node/Scalar/MagicConst/VirtualDir.phpW f=90src/Psalm/Node/Scalar/MagicConst/VirtualLine.phpW fɈ71src/Psalm/Node/Scalar/MagicConst/VirtualClass.phpW fP$2src/Psalm/Node/Scalar/MagicConst/VirtualMethod.phpW f4src/Psalm/Node/Scalar/MagicConst/VirtualFunction.phpW f5src/Psalm/Node/Scalar/MagicConst/VirtualNamespace.phpW fR1src/Psalm/Node/Scalar/MagicConst/VirtualTrait.phpW fA٤3src/Psalm/Node/Scalar/VirtualEncapsedStringPart.phpW f*/ɤ+src/Psalm/Node/VirtualVarLikeIdentifier.phpW f1}#src/Psalm/Node/VirtualAttribute.phpW fH_$src/Psalm/Node/VirtualIdentifier.php&W f&dV"src/Psalm/Node/VirtualMatchArm.phpW fݤ src/Psalm/Report/EmacsReport.phpSW fSQ$Y"src/Psalm/Report/ReportOptions.php\W f\bx src/Psalm/Report/CountReport.phpW f̚.src/Psalm/Report/ByIssueLevelAndTypeReport.phpW fi&src/Psalm/Report/JsonSummaryReport.phpW fTۤ%src/Psalm/Report/CheckstyleReport.phpW fy src/Psalm/Report/SarifReport.php% W f% _src/Psalm/Report/JsonReport.phpW fmࢶ$src/Psalm/Report/SonarqubeReport.phpW fVˤ#src/Psalm/Report/PhpStormReport.phpv W fv DK{"src/Psalm/Report/ConsoleReport.php'W f' ρ& src/Psalm/Report/JunitReport.phpW fىn(src/Psalm/Report/GithubActionsReport.phpW f "src/Psalm/Report/CompactReport.php W f r&src/Psalm/Report/CodeClimateReport.phpZ W fZ + src/Psalm/Report/TextReport.php6W f6Y'!src/Psalm/Report/PylintReport.php+W f+%/asrc/Psalm/Report/XmlReport.phpW fr-l$src/Psalm/FileBasedPluginAdapter.phpW fx[6src/Psalm/Exception/InvalidMethodOverrideException.phpsW fs/src/Psalm/Exception/ConfigCreationException.phplW fl2#'src/Psalm/Exception/ConfigException.php^W f^G9src/Psalm/Exception/InvalidClasslikeOverrideException.phpvW fvd>.src/Psalm/Exception/ScopeAnalysisException.phpkW fkUg/src/Psalm/Exception/ConfigNotFoundException.phptW ft=g%src/Psalm/Exception/CodeException.phpbW fb'$/src/Psalm/Exception/UnanalyzedFileException.phplW flP>2src/Psalm/Exception/IncorrectDocblockException.php~W f~ޤ.src/Psalm/Exception/TypeParseTreeException.phpkW fkȤ,src/Psalm/Exception/FileIncludeException.phpiW fiJݤ.src/Psalm/Exception/DocblockParseException.phpeW fe^٤6src/Psalm/Exception/ComplicatedExpressionException.phpsW fs{?u5src/Psalm/Exception/UnpopulatedClasslikeException.phpqW fq6src/Psalm/Exception/UnsupportedIssueToFixException.phpsW fs<3src/Psalm/Exception/UnpreparedAnalysisException.phppW fp2*\)src/Psalm/Exception/RefactorException.phpfW ff>Rh5src/Psalm/Exception/UnresolvableConstantException.phpW f%Ф2src/Psalm/Exception/CircularReferenceException.phpoW fo9ػsrc/Psalm/FileManipulation.phpW fuN| #src/Psalm/Progress/VoidProgress.phpW f_&src/Psalm/Progress/DefaultProgress.phpW f mm$src/Psalm/Progress/DebugProgress.phpW frF Esrc/Psalm/Progress/Progress.phpUW fUV#src/Psalm/Progress/LongProgress.php" W f" q config.xsd}W f}E DpsalmW f( stubs/CoreGenericClasses.phpstubB@W fB@X"stubs/CoreImmutableClasses.phpstubEW fEXy;stubs/Php80.phpstub.W f.{Nstubs/Php81.phpstub W f stubs/Reflection.phpstub8W f8T[[stubs/Php82.phpstubmW fm 9w"stubs/CoreGenericIterators.phpstubjW fjQstubs/SPL.phpstubtiW fti=l#stubs/CoreGenericAttributes.phpstubW fstubs/phpparser.phpstub/W f/ifĤ"stubs/CoreGenericFunctions.phpstubQW fQoǤstubs/Php74.phpstubW fstubs/extensions/ffi.phpstub$W f$GG stubs/extensions/ibm_db2.phpstubW f3^:stubs/extensions/ds.phpstub4cW f4cNQ٤ stubs/extensions/mongodb.phpstubFW fF๐ߤstubs/extensions/redis.phpstubZPW fZPTstubs/extensions/soap.phpstub{+W f{+lNstubs/extensions/geos.phpstubW fSstubs/extensions/xdebug.phpstubW fȤstubs/extensions/dom.phpstub]W f]Яstubs/extensions/random.phpstubK W fK Cstubs/extensions/pdo.phpstubKW fKSEstubs/extensions/mysqli.phpstubW fΤ"stubs/extensions/simplexml.phpstubW fvxФ stubs/extensions/rdkafka.phpstubvW fvG stubs/extensions/decimal.phpstubAW fApstubs/extensions/apcu.phpstubW fͤstubs/extensions/gmp.phpstubW frU.box/vendor/autoload.phpW fs.box/vendor/composer/LICENSE.W f. ,.box/vendor/composer/autoload_namespaces.phpW ft!פ$.box/vendor/composer/ClassLoader.php>W f>5Ky&.box/vendor/composer/autoload_real.phpW fyi\(.box/vendor/composer/autoload_static.phpKW fK?1.box/vendor/composer/semver/src/VersionParser.php9W f9Wz ..box/vendor/composer/semver/src/Comparator.phpuW fu 749.box/vendor/composer/semver/src/Constraint/Constraint.php'&W f'&`B.box/vendor/composer/semver/src/Constraint/ConstraintInterface.phpW fwQ>.box/vendor/composer/semver/src/Constraint/MultiConstraint.php~W f~5[e*.box/vendor/composer/semver/src/Semver.phpW fׯ*.box/vendor/composer/autoload_classmap.php, W f, ӽǤ&.box/vendor/composer/autoload_psr4.php6W f60Ӥ.box/src/Terminal.php W f %V.box/src/Printer.php W f )8AV.box/src/IO.php W f [l%".box/src/RequirementCollection.phpW fWb?.box/src/IsFulfilled.phpvW fv%*H.box/src/Requirement.phpmW fmB".box/src/IsPhpVersionFulfilled.phpW f!83!.box/src/IsExtensionFulfilled.phpvW fv'0Ҥ.box/src/Checker.phpW f)W>.box/bin/check-requirements.phpW f^ʨ.box/.requirements.phpW fzC(docs/running_psalm/issues/TaintedHtml.mdW fvB)1docs/running_psalm/issues/PossiblyInvalidClone.mdW fd8docs/running_psalm/issues/PropertyNotSetInConstructor.mdW fwä6docs/running_psalm/issues/UnsupportedReferenceUsage.mdW fXd\>2docs/running_psalm/issues/AbstractInstantiation.mdW f!Ȥ,docs/running_psalm/issues/MixedAssignment.mdW f='docs/running_psalm/issues/TaintedSql.mdyW fy-docs/running_psalm/issues/EmptyArrayAccess.mdxW fx-B-docs/running_psalm/issues/NoEnumProperties.mdW f0lѤ9docs/running_psalm/issues/UnimplementedInterfaceMethod.mdW f_פ*docs/running_psalm/issues/TaintedCookie.mdW f*docs/running_psalm/issues/ComplexMethod.mdcW fcX)docs/running_psalm/issues/ReservedWord.md|W f|>,docs/running_psalm/issues/InvalidDocblock.mdtW ft%Fz8docs/running_psalm/issues/PossiblyNullArrayAssignment.mdW fǤ-docs/running_psalm/issues/InternalProperty.mdW fy6Q1docs/running_psalm/issues/PropertyTypeCoercion.mdW f /docs/running_psalm/issues/TaintedUnserialize.mdW fc.docs/running_psalm/issues/UnusedConstructor.mdW f3n: &docs/running_psalm/issues/CheckType.md{W f{WRo,docs/running_psalm/issues/TaintedCallable.md4W f49Qפ,docs/running_psalm/issues/UndefinedMethod.mdmW fm^2docs/running_psalm/issues/InvalidScalarArgument.mdW fa 4docs/running_psalm/issues/UndefinedGlobalVariable.mdnW fns1docs/running_psalm/issues/UndefinedMagicMethod.mdW f(docs/running_psalm/issues/TaintedEval.mdAW fA<$docs/running_psalm/issues/NoValue.mdBW fBI4docs/running_psalm/issues/PossiblyInvalidIterator.mdW fD1/docs/running_psalm/issues/UnusedForeachValue.mdW fW,docs/running_psalm/issues/MixedMethodCall.mdfW ffx!0docs/running_psalm/issues/PossiblyInvalidCast.mdW fS"docs/running_psalm/issues/Trace.mdW fDդ7docs/running_psalm/issues/PossiblyInvalidArrayAccess.mdW fci,)docs/running_psalm/issues/FalseOperand.mdW fy3docs/running_psalm/issues/PossiblyFalseReference.mdW fW\]4+docs/running_psalm/issues/InternalMethod.mdW f@docs/running_psalm/issues/PossiblyNullPropertyAssignmentValue.md$W f$-}(docs/running_psalm/issues/PluginIssue.md*W f*xͤ*docs/running_psalm/issues/MixedArgument.mdW ffD1docs/running_psalm/issues/PossiblyUnusedMethod.mdbW fb`4docs/running_psalm/issues/UndefinedAttributeClass.mdW f]22docs/running_psalm/issues/TooManyTemplateParams.mdEW fELQڤ(docs/running_psalm/issues/MissingFile.mdW fH3G+docs/running_psalm/issues/UnusedProperty.mdW fsP^:docs/running_psalm/issues/LessSpecificClassConstantType.mdKW fKi7a^4docs/running_psalm/issues/PossiblyNullArrayAccess.mdW f=4docs/running_psalm/issues/MissingClosureParamType.mdW f"&f0docs/running_psalm/issues/UnresolvableInclude.mdW f-docs/running_psalm/issues/MixedArrayAccess.mdW fRࣤ-docs/running_psalm/issues/MixedArrayOffset.mdW fT4docs/running_psalm/issues/NamedArgumentNotAllowed.mdW f8Ѥ,docs/running_psalm/issues/StringIncrement.mdW f$/docs/running_psalm/issues/UnusedClosureParam.mdW fz<9docs/running_psalm/issues/TraitMethodSignatureMismatch.mdW f,9docs/running_psalm/issues/ReferenceConstraintViolation.mdW f sϤ3docs/running_psalm/issues/MoreSpecificReturnType.mdMW fM+&0docs/running_psalm/issues/UnusedPsalmSuppress.mdW fW0,docs/running_psalm/issues/UnevaluatedCode.mdW fߒ7docs/running_psalm/issues/PossibleRawObjectIteration.mdW fe2docs/running_psalm/issues/RedundantFunctionCall.mdW f-docs/running_psalm/issues/NullFunctionCall.mdsW fsY*docs/running_psalm/issues/TaintedCustom.mdhW fh%0docs/running_psalm/issues/MissingDocblockType.mdW fOf*docs/running_psalm/issues/NullReference.mdmW fmߍ&/docs/running_psalm/issues/AbstractMethodCall.mdW fW8Τ3docs/running_psalm/issues/InterfaceInstantiation.mdW fZ6docs/running_psalm/issues/PossiblyNullPropertyFetch.mdW fuŤ3docs/running_psalm/issues/DuplicateEnumCaseValue.mdRW fRhqA/docs/running_psalm/issues/InaccessibleMethod.mdW fwb)docs/running_psalm/issues/InvalidScope.mdaW fal#8docs/running_psalm/issues/UndefinedMagicPropertyFetch.mdW f8docs/running_psalm/issues/PossiblyInvalidFunctionCall.mdW fJj3docs/running_psalm/issues/UndefinedPropertyFetch.mdW f~h.docs/running_psalm/issues/InvalidMethodCall.mdtW ftlq ;docs/running_psalm/issues/PossiblyNullPropertyAssignment.mdW fA,docs/running_psalm/issues/InvalidArgument.mdzW fzɤ;docs/running_psalm/issues/PossiblyInvalidArrayAssignment.mdW f,6docs/running_psalm/issues/InvalidNullableReturnType.mdW fDŤ2docs/running_psalm/issues/MissingThrowsDocblock.mdW f *"1docs/running_psalm/issues/MixedReturnStatement.mdW fDm4docs/running_psalm/issues/PossiblyUndefinedMethod.mdW f)docs/running_psalm/issues/NullIterator.md^W f^Vj9docs/running_psalm/issues/PossiblyInvalidPropertyFetch.mdYW fYϾӤ+docs/running_psalm/issues/UndefinedTrait.mdqW fqݹͤ)docs/running_psalm/issues/UnusedMethod.mdW f:V:docs/running_psalm/issues/ExtensionRequirementViolation.mdiW fiKZ(docs/running_psalm/issues/TaintedFile.mdW fȤ3docs/running_psalm/issues/PossiblyUnusedProperty.mdW fy5docs/running_psalm/issues/OverriddenPropertyAccess.md W f 7.docs/running_psalm/issues/UndefinedFunction.mdfW ffT6docs/running_psalm/issues/PossiblyInvalidMethodCall.mdW f~ ,docs/running_psalm/issues/InvalidToString.mdW f۱3docs/running_psalm/issues/PossiblyInvalidOperand.mdW fL/+docs/running_psalm/issues/InvalidOperand.mdW fjVz3docs/running_psalm/issues/MixedArrayTypeCoercion.md2W f2{5docs/running_psalm/issues/NonInvariantPropertyType.mdNW fN43docs/running_psalm/issues/InvalidEnumBackingType.mdW f8K+docs/running_psalm/issues/TaintedInclude.mdW f#5docs/running_psalm/issues/MissingOverrideAttribute.mdW fe;docs/running_psalm/issues/RedundantCastGivenDocblockType.mdW f$6v<docs/running_psalm/issues/PossiblyUndefinedGlobalVariable.mdW ftf@?docs/running_psalm/issues/PossiblyUndefinedStringArrayOffset.md)W f)V0;docs/running_psalm/issues/ConflictingReferenceConstraint.mdW f -5docs/running_psalm/issues/MissingClosureReturnType.mdW fmj3docs/running_psalm/issues/TypeDoesNotContainType.mdW fm7docs/running_psalm/issues/RiskyTruthyFalsyComparison.mdW fd?docs/running_psalm/issues/ImplementationRequirementViolation.mdW fդ1docs/running_psalm/issues/UnresolvableConstant.mdW f0ۤ2docs/running_psalm/issues/DirectConstructorCall.mdW fnW,docs/running_psalm/issues/InvalidOverride.mdgW fg#$[6docs/running_psalm/issues/MixedPropertyTypeCoercion.md2W f29A1docs/running_psalm/issues/ArgumentTypeCoercion.md]W f]?&^*docs/running_psalm/issues/InvalidParent.mdW fӤ0docs/running_psalm/issues/UnusedBaselineEntry.mdW fl_2docs/running_psalm/issues/PossiblyFalseIterator.mdW fI.docs/running_psalm/issues/DuplicateConstant.mdW fB1docs/running_psalm/issues/InvalidNamedArgument.mdW fM.docs/running_psalm/issues/MixedFunctionCall.mdW f$6docs/running_psalm/issues/PossiblyUndefinedVariable.mdW f -docs/running_psalm/issues/ImpureMethodCall.mdzW fzw1w(docs/running_psalm/issues/UnusedClass.mdW fHYڤ2docs/running_psalm/issues/PossiblyFalseArgument.mdTW fTM-docs/running_psalm/issues/AssignmentToVoid.mdW fPɤ;docs/running_psalm/issues/InvalidConstantAssignmentValue.mdW f>docs/running_psalm/issues/PossiblyInvalidPropertyAssignment.md`W f`bݤ4docs/running_psalm/issues/MethodSignatureMismatch.md'W f'd:8docs/running_psalm/issues/MixedStringOffsetAssignment.mdW f;docs/running_psalm/issues/InvalidPropertyAssignmentValue.mdW fX3,docs/running_psalm/issues/InvalidIterator.mdW fG%*docs/running_psalm/issues/InternalClass.mdW fዂ0docs/running_psalm/issues/TaintedSystemSecret.mdW fG@6docs/running_psalm/issues/DocblockTypeContradiction.mdyW fy\=docs/running_psalm/issues/MoreSpecificImplementedParamType.mdW fYt>docs/running_psalm/issues/ReferenceReusedFromConfusingScope.mdW f+h2docs/running_psalm/issues/UninitializedProperty.mdW f }*docs/running_psalm/issues/RedundantFlag.md/W f/y1'docs/running_psalm/issues/MixedClone.mdxW fx;ɮ)docs/running_psalm/issues/InvalidCatch.mdW f,>docs/running_psalm/issues/MethodSignatureMustOmitReturnType.mdW f#2docs/running_psalm/issues/MissingClassConstType.mdW fX4docs/running_psalm/issues/MixedPropertyAssignment.mdW fK`=docs/running_psalm/issues/InvalidTraversableImplementation.md>W f>iM8docs/running_psalm/issues/UndefinedPropertyAssignment.mdW fuȐ7docs/running_psalm/issues/PossiblyInvalidArrayOffset.mdW f(;%.docs/running_psalm/issues/MissingReturnType.mdW fLƤ(docs/running_psalm/issues/TaintedSSRF.mdOW fO82docs/running_psalm/issues/UnrecognizedStatement.mdW fC7docs/running_psalm/issues/UncaughtThrowInGlobalScope.mdW f^5docs/running_psalm/issues/InvalidClassConstantType.mdIW fI/L-docs/running_psalm/issues/DeprecatedMethod.mdcW fc^ӂ@docs/running_psalm/issues/RedundantConditionGivenDocblockType.md{W f{tޤ3docs/running_psalm/issues/OverriddenMethodAccess.mdW fn.docs/running_psalm/issues/UnusedReturnValue.md4W f43Yۤ4docs/running_psalm/issues/NullableReturnStatement.mdW f 7docs/running_psalm/issues/PossiblyInvalidDocblockTag.mdW fE).docs/running_psalm/issues/CircularReference.mdW fp.docs/running_psalm/issues/NullPropertyFetch.md{W f{=]X3docs/running_psalm/issues/LessSpecificReturnType.mdW fL6e0docs/running_psalm/issues/UnusedDocblockParam.mdPW fPao٪4docs/running_psalm/issues/MixedReturnTypeCoercion.mdW fLj1docs/running_psalm/issues/ImpureStaticVariable.mdW f 8docs/running_psalm/issues/UnimplementedAbstractMethod.mdW f+a4docs/running_psalm/issues/InvalidStaticInvocation.mdW fAĤ+docs/running_psalm/issues/DuplicateClass.mdW f'docs/running_psalm/issues/ParseError.mdW fuAf>docs/running_psalm/issues/LessSpecificImplementedReturnType.mdW f8(R/docs/running_psalm/issues/InvalidArrayOffset.mdW fyyڤ,docs/running_psalm/issues/NullArrayOffset.mdW f%SCdocs/running_psalm/issues/PossiblyInvalidPropertyAssignmentValue.md5W f5Z3docs/running_psalm/issues/UnrecognizedExpression.mdW fcB1docs/running_psalm/issues/ImpureStaticProperty.md7W f7U7+docs/running_psalm/issues/UnusedVariable.md:W f:b2docs/running_psalm/issues/TaintedTextWithQuotes.mdW fkb(docs/running_psalm/issues/ConfigIssue.mdW f3docs/running_psalm/issues/TypeDoesNotContainNull.mdW f:^=docs/running_psalm/issues/NonInvariantDocblockPropertyType.mdW f 1docs/running_psalm/issues/InvalidTemplateParam.mdtW ft|K)1docs/running_psalm/issues/MissingTemplateParam.mdW f:-docs/running_psalm/issues/TooManyArguments.mdW f4.docs/running_psalm/issues/ParamNameMismatch.md W f 30docs/running_psalm/issues/InvalidFunctionCall.mdxW fxѶs6docs/running_psalm/issues/PossiblyUnusedReturnValue.md W f 0 .docs/running_psalm/issues/InvalidReturnType.mdW fȸ64docs/running_psalm/issues/MixedInferredReturnType.mdW f>1docs/running_psalm/issues/ParadoxicalCondition.mdW fX1docs/running_psalm/issues/MixedArrayAssignment.mdW f;l4docs/running_psalm/issues/PossiblyNullArrayOffset.mdW f13docs/running_psalm/issues/InvalidReturnStatement.mdW f/docs/running_psalm/issues/UnusedFunctionCall.mdW f=q5docs/running_psalm/issues/PossiblyNullFunctionCall.mdW fR>'(docs/running_psalm/issues/UnusedParam.mdpW fp,docs/running_psalm/issues/DeprecatedTrait.md0W f0Xz)docs/running_psalm/issues/TaintedShell.mdW fQ6docs/running_psalm/issues/InaccessibleClassConstant.mdW f )docs/running_psalm/issues/MixedOperand.mdWW fWT 7docs/running_psalm/issues/ConstantDeclarationInTrait.mdW f9[-docs/running_psalm/issues/UnusedMethodCall.mdW f0T+docs/running_psalm/issues/ParentNotFound.mdW f3docs/running_psalm/issues/UndefinedDocblockClass.mdW f^/docs/running_psalm/issues/DeprecatedConstant.mdW fdnj:docs/running_psalm/issues/ImplementedReturnTypeMismatch.mdW fO<docs/running_psalm/issues/MismatchingDocblockPropertyType.mdW fN.docs/running_psalm/issues/InvalidTypeImport.mdW fK4docs/running_psalm/issues/OverriddenFinalConstant.mdW fΌv=docs/running_psalm/issues/UndefinedMagicPropertyAssignment.md3W f3731docs/running_psalm/issues/PossiblyNullArgument.mdW f;Y4<docs/running_psalm/issues/UndefinedThisPropertyAssignment.mdW fG_},docs/running_psalm/issues/DeprecatedClass.md"W f"2C;docs/running_psalm/issues/InvalidInterfaceImplementation.mdW fi;RAdocs/running_psalm/issues/MethodSignatureMustProvideReturnType.mdW f&9docs/running_psalm/issues/ImplementedParamTypeMismatch.md W f 6J.docs/running_psalm/issues/MissingDependency.mdW fC(docs/running_psalm/issues/InvalidCast.mdW fM/docs/running_psalm/issues/DeprecatedFunction.md2W f2/%B/docs/running_psalm/issues/UndefinedInterface.mdW fg@vV/docs/running_psalm/issues/RedundantCondition.mdW faI9docs/running_psalm/issues/PossiblyUndefinedArrayOffset.mdMW fM֚]l7docs/running_psalm/issues/MissingImmutableAnnotation.mdW f>մz1docs/running_psalm/issues/PossiblyFalseOperand.mdW f״.docs/running_psalm/issues/UndefinedVariable.mdW f_5docs/running_psalm/issues/ImpurePropertyAssignment.mdW fa3"5docs/running_psalm/issues/InvalidDocblockParamName.md W f $\.docs/running_psalm/issues/DuplicateFunction.mdW f/docs/running_psalm/issues/InvalidExtendClass.mdpW fp="(docs/running_psalm/issues/NullOperand.mdW fp$6docs/running_psalm/issues/InvalidFalsableReturnType.mdW f-docs/running_psalm/issues/IfThisIsMismatch.md7W f7a.docs/running_psalm/issues/DuplicateEnumCase.mdW fÿq&docs/running_psalm/issues/RiskyCast.md3W f3;0docs/running_psalm/issues/PossiblyUnusedParam.mdW f6ˤ9docs/running_psalm/issues/ConstructorSignatureMismatch.mdW ftn7docs/running_psalm/issues/UnsafeGenericInstantiation.md5 W f5 ZNj>,docs/running_psalm/issues/NullArrayAccess.mdxW fx6Mx13docs/running_psalm/issues/InvalidPassByReference.mdW fp/docs/running_psalm/issues/MissingConstructor.mdW fKX.docs/running_psalm/issues/MutableDependency.mdPW fPv8docs/running_psalm/issues/ImpureByReferenceAssignment.mdW fӬF-docs/running_psalm/issues/MissingParamType.mdW f_@d1docs/running_psalm/issues/InvalidEnumCaseValue.mdYW fYxw1docs/running_psalm/issues/InaccessibleProperty.mdW f&ؤ/docs/running_psalm/issues/InvalidArrayAccess.mdW f[H3docs/running_psalm/issues/NullPropertyAssignment.mdyW fy p/docs/running_psalm/issues/RawObjectIteration.mdmW fm𒮤:docs/running_psalm/issues/MismatchingDocblockReturnType.mdW fB s)docs/running_psalm/issues/TaintedInput.mdBW fB8docs/running_psalm/issues/LessSpecificReturnStatement.mdW f1(docs/running_psalm/issues/TaintedLdap.mdW fֵ+docs/running_psalm/issues/DuplicateParam.mdW f .docs/running_psalm/issues/InvalidEnumMethod.mdW fŇѤ,docs/running_psalm/issues/DuplicateMethod.mdW f)7docs/running_psalm/issues/UndefinedThisPropertyFetch.mdW fGvk1docs/running_psalm/issues/ImplicitToStringCast.mdtW ft!4docs/running_psalm/issues/FalsableReturnStatement.mdW fY//docs/running_psalm/issues/InheritorViolation.mdW fYI5docs/running_psalm/issues/UndefinedInterfaceMethod.mdW f6ܬ.docs/running_psalm/issues/NonStaticSelfCall.mdW f̄3docs/running_psalm/issues/InvalidLiteralArgument.mdW fbgK6docs/running_psalm/issues/InvalidPropertyAssignment.mdW fD0docs/running_psalm/issues/UnsafeInstantiation.md=W f=+docs/running_psalm/issues/ImpureVariable.mdW fȉ2docs/running_psalm/issues/PossiblyNullReference.mdW f9n(6*docs/running_psalm/issues/TaintedHeader.mdW f &)docs/running_psalm/issues/InvalidClone.mdzW fzx&%*docs/running_psalm/issues/InvalidGlobal.mdZW fZ)docs/running_psalm/issues/InvalidClass.mdbW fbn;0docs/running_psalm/issues/MissingPropertyType.mdW f`6docs/running_psalm/issues/MixedArgumentTypeCoercion.md&W f&>@#Adocs/running_psalm/issues/RedundantPropertyInitializationCheck.md3W f3rA+docs/running_psalm/issues/UndefinedTrace.mdW f%N5docs/running_psalm/issues/UnnecessaryVarAnnotation.mdW fuf>docs/running_psalm/issues/UnsupportedPropertyReferenceUsage.mdpW fpF/docs/running_psalm/issues/DeprecatedProperty.mdW fG`0docs/running_psalm/issues/InvalidParamDefault.mdW f}/docs/running_psalm/issues/MixedPropertyFetch.mdW fFF8docs/running_psalm/issues/OverriddenInterfaceConstant.mdW fN1docs/running_psalm/issues/PossiblyNullIterator.mdW fia)0docs/running_psalm/issues/ContinueOutsideLoop.mdW fO9Y֤)docs/running_psalm/issues/InvalidThrow.mdW f)Ԥ.docs/running_psalm/issues/TaintedUserSecret.mdW fZ9docs/running_psalm/issues/AmbiguousConstantInheritance.md(W f( ;f 0docs/running_psalm/issues/DeprecatedInterface.mdAW fA7U/docs/running_psalm/issues/PrivateFinalMethod.mdW fx,docs/running_psalm/issues/TooFewArguments.mdW f&Vڤ0docs/running_psalm/issues/ImpurePropertyFetch.mdW fRV2docs/running_psalm/issues/NoInterfaceProperties.md-W f-/1docs/running_psalm/issues/InvalidPropertyFetch.mdW f`&Cdocs/running_psalm/issues/RedundantFunctionCallGivenDocblockType.mdeW fe(94docs/running_psalm/issues/UnhandledMatchCondition.mdWW fW9*docs/running_psalm/issues/ForbiddenCode.mdW f(g.docs/running_psalm/issues/UndefinedConstant.mdnW fny}3docs/running_psalm/issues/InvalidArrayAssignment.md}W f}Q,docs/running_psalm/issues/ComplexFunction.mdiW fi{Τ.docs/running_psalm/issues/DuplicateArrayKey.mdW f_)docs/running_psalm/issues/NullArgument.mdW fϥŤ-docs/running_psalm/issues/InvalidAttribute.md+W f+)֫ɤAdocs/running_psalm/issues/PossiblyFalsePropertyAssignmentValue.md3W f3f큤9docs/running_psalm/issues/MismatchingDocblockParamType.mdW fX/docs/running_psalm/issues/InvalidStringClass.mdW f*q4docs/running_psalm/issues/PossiblyInvalidArgument.mdW f0docs/running_psalm/issues/PossiblyNullOperand.mdW f פ+docs/running_psalm/issues/UndefinedClass.mdhW fh -docs/running_psalm/issues/LoopInvalidation.mdW f|/docs/running_psalm/issues/ImpureFunctionCall.md@W f@U6docs/running_psalm/issues/RedundantIdentityWithTrue.md9W f9q`*docs/running_psalm/issues/RedundantCast.mdW f /1<docs/running_psalm/issues/PossiblyUndefinedIntArrayOffset.mdW fy7 '5.26.1@d747f6500b38ac4f7dfc5edbcae6e4b637d7add0', 'nikic/php-parser' => 'v4.19.1@4e1b88d21c69391150ace211e9eaf05810858d0b'); ' => [', ''=>''] * alternative signature for the same function * '' => [', ''=>''] * * A '&' in front of the means the arg is always passed by reference. * (i.e. ReflectionParameter->isPassedByReference()) * This was previously only used in cases where the function actually created the * variable in the local scope. * Some reference arguments will have prefixes in to indicate the way the argument is used. * Currently, the only prefixes with meaning are 'rw_' (read-write) and 'w_' (write). * Those prefixes don't mean anything for non-references. * Code using these signatures should remove those prefixes from messages rendered to the user. * 1. '&rw_' indicates that a parameter with a value is expected to be passed in, and may be modified. * Phan will warn if the variable has an incompatible type, or is undefined. * 2. '&w_' indicates that a parameter is expected to be passed in, and the value will be ignored, and may be overwritten. * 3. The absence of a prefix is treated by Phan the same way as having the prefix 'w_' (Some may be changed to 'rw_name'). These will have prefixes added later. * * So, for functions like sort() where technically the arg is by-ref, * indicate the reference param's signature by-ref and read-write, * as `'&rw_array'=>'array'` * so that Phan won't create it in the local scope * * However, for a function like preg_match() where the 3rd arg is an array of sub-pattern matches (and optional), * this arg needs to be marked as by-ref and write-only, as `'&w_matches='=>'array'`. * * A '=' following the indicates this arg is optional. * * The can begin with '...' to indicate the arg is variadic. * '...args=' indicates it is both variadic and optional. * * Some reference arguments will have prefixes in to indicate the way the argument is used. * Currently, the only prefixes with meaning are 'rw_' and 'w_'. * Code using these signatures should remove those prefixes from messages rendered to the user. * 1. '&rw_name' indicates that a parameter with a value is expected to be passed in, and may be modified. * 2. '&w_name' indicates that a parameter is expected to be passed in, and the value will be ignored, and may be overwritten. * * This file contains the signatures for the most recent minor release of PHP supported by phan (php 7.2) * * Changes: * * In Phan 0.12.3, * * - This started using array shapes for union types (array{...}). * * \Phan\Language\UnionType->withFlattenedArrayShapeOrLiteralTypeInstances() may be of help to programmatically convert these to array|array * * - This started using array shapes with optional fields for union types (array{key?:int}). * A `?` after the array shape field's key indicates that the field is optional. * * - This started adding param signatures and return signatures to `callable` types. * E.g. 'usort' => ['bool', '&rw_array_arg'=>'array', 'cmp_function'=>'callable(mixed,mixed):int']. * See NEWS.md for 0.12.3 for possible syntax. A suffix of `=` within `callable(...)` means that a parameter is optional. * * (Phan assumes that callbacks with optional arguments can be cast to callbacks with/without those args (Similar to inheritance checks) * (e.g. callable(T1,T2=) can be cast to callable(T1) or callable(T1,T2), in the same way that a subclass would check). * For some signatures, e.g. set_error_handler, this results in repetition, because callable(T1=) can't cast to callable(T1). * * Sources of stub info: * * 1. Reflection * 2. docs.php.net's SVN repo or website, and examples (See internal/internalsignatures.php) * * See https://secure.php.net/manual/en/copyright.php * * The PHP manual text and comments are covered by the [Creative Commons Attribution 3.0 License](http://creativecommons.org/licenses/by/3.0/legalcode), * copyright (c) the PHP Documentation Group * 3. Various websites documenting individual extensions * 4. PHPStorm stubs (For anything missing from the above sources) * See internal/internalsignatures.php * * Available from https://github.com/JetBrains/phpstorm-stubs under the [Apache 2 license](https://www.apache.org/licenses/LICENSE-2.0) * * @phan-file-suppress PhanPluginMixedKeyNoKey (read by Phan when analyzing this file) * * Note: Some of Phan's inferences about return types are written as plugins for functions/methods where the return type depends on the parameter types. * E.g. src/Phan/Plugin/Internal/DependentReturnTypeOverridePlugin.php is one plugin */ return [ '_' => ['string', 'message'=>'string'], '__halt_compiler' => ['void'], 'abs' => ['0|positive-int', 'num'=>'int'], 'abs\'1' => ['float', 'num'=>'float'], 'abs\'2' => ['numeric', 'num'=>'numeric'], 'accelerator_get_configuration' => ['array'], 'accelerator_get_scripts' => ['array'], 'accelerator_get_status' => ['array', 'fetch_scripts'=>'bool'], 'accelerator_reset' => [''], 'accelerator_set_status' => ['void', 'status'=>'bool'], 'acos' => ['float', 'num'=>'float'], 'acosh' => ['float', 'num'=>'float'], 'addcslashes' => ['string', 'string'=>'string', 'characters'=>'string'], 'addslashes' => ['string', 'string'=>'string'], 'AMQPBasicProperties::__construct' => ['void', 'content_type='=>'string', 'content_encoding='=>'string', 'headers='=>'array', 'delivery_mode='=>'int', 'priority='=>'int', 'correlation_id='=>'string', 'reply_to='=>'string', 'expiration='=>'string', 'message_id='=>'string', 'timestamp='=>'int', 'type='=>'string', 'user_id='=>'string', 'app_id='=>'string', 'cluster_id='=>'string'], 'AMQPBasicProperties::getAppId' => ['string'], 'AMQPBasicProperties::getClusterId' => ['string'], 'AMQPBasicProperties::getContentEncoding' => ['string'], 'AMQPBasicProperties::getContentType' => ['string'], 'AMQPBasicProperties::getCorrelationId' => ['string'], 'AMQPBasicProperties::getDeliveryMode' => ['int'], 'AMQPBasicProperties::getExpiration' => ['string'], 'AMQPBasicProperties::getHeaders' => ['array'], 'AMQPBasicProperties::getMessageId' => ['string'], 'AMQPBasicProperties::getPriority' => ['int'], 'AMQPBasicProperties::getReplyTo' => ['string'], 'AMQPBasicProperties::getTimestamp' => ['string'], 'AMQPBasicProperties::getType' => ['string'], 'AMQPBasicProperties::getUserId' => ['string'], 'AMQPChannel::__construct' => ['void', 'amqp_connection'=>'AMQPConnection'], 'AMQPChannel::basicRecover' => ['', 'requeue='=>'bool'], 'AMQPChannel::close' => [''], 'AMQPChannel::commitTransaction' => ['bool'], 'AMQPChannel::confirmSelect' => [''], 'AMQPChannel::getChannelId' => ['int'], 'AMQPChannel::getConnection' => ['AMQPConnection'], 'AMQPChannel::getConsumers' => ['AMQPQueue[]'], 'AMQPChannel::getPrefetchCount' => ['int'], 'AMQPChannel::getPrefetchSize' => ['int'], 'AMQPChannel::isConnected' => ['bool'], 'AMQPChannel::qos' => ['bool', 'size'=>'int', 'count'=>'int'], 'AMQPChannel::rollbackTransaction' => ['bool'], 'AMQPChannel::setConfirmCallback' => ['', 'ack_callback='=>'?callable', 'nack_callback='=>'?callable'], 'AMQPChannel::setPrefetchCount' => ['bool', 'count'=>'int'], 'AMQPChannel::setPrefetchSize' => ['bool', 'size'=>'int'], 'AMQPChannel::setReturnCallback' => ['', 'return_callback='=>'?callable'], 'AMQPChannel::startTransaction' => ['bool'], 'AMQPChannel::waitForBasicReturn' => ['', 'timeout='=>'float'], 'AMQPChannel::waitForConfirm' => ['', 'timeout='=>'float'], 'AMQPConnection::__construct' => ['void', 'credentials='=>'array'], 'AMQPConnection::connect' => ['bool'], 'AMQPConnection::disconnect' => ['bool'], 'AMQPConnection::getCACert' => ['string'], 'AMQPConnection::getCert' => ['string'], 'AMQPConnection::getHeartbeatInterval' => ['int'], 'AMQPConnection::getHost' => ['string'], 'AMQPConnection::getKey' => ['string'], 'AMQPConnection::getLogin' => ['string'], 'AMQPConnection::getMaxChannels' => ['?int'], 'AMQPConnection::getMaxFrameSize' => ['int'], 'AMQPConnection::getPassword' => ['string'], 'AMQPConnection::getPort' => ['int'], 'AMQPConnection::getReadTimeout' => ['float'], 'AMQPConnection::getTimeout' => ['float'], 'AMQPConnection::getUsedChannels' => ['int'], 'AMQPConnection::getVerify' => ['bool'], 'AMQPConnection::getVhost' => ['string'], 'AMQPConnection::getWriteTimeout' => ['float'], 'AMQPConnection::isConnected' => ['bool'], 'AMQPConnection::isPersistent' => ['?bool'], 'AMQPConnection::pconnect' => ['bool'], 'AMQPConnection::pdisconnect' => ['bool'], 'AMQPConnection::preconnect' => ['bool'], 'AMQPConnection::reconnect' => ['bool'], 'AMQPConnection::setCACert' => ['', 'cacert'=>'string'], 'AMQPConnection::setCert' => ['', 'cert'=>'string'], 'AMQPConnection::setHost' => ['bool', 'host'=>'string'], 'AMQPConnection::setKey' => ['', 'key'=>'string'], 'AMQPConnection::setLogin' => ['bool', 'login'=>'string'], 'AMQPConnection::setPassword' => ['bool', 'password'=>'string'], 'AMQPConnection::setPort' => ['bool', 'port'=>'int'], 'AMQPConnection::setReadTimeout' => ['bool', 'timeout'=>'int'], 'AMQPConnection::setTimeout' => ['bool', 'timeout'=>'int'], 'AMQPConnection::setVerify' => ['', 'verify'=>'bool'], 'AMQPConnection::setVhost' => ['bool', 'vhost'=>'string'], 'AMQPConnection::setWriteTimeout' => ['bool', 'timeout'=>'int'], 'AMQPDecimal::__construct' => ['void', 'exponent'=>'', 'significand'=>''], 'AMQPDecimal::getExponent' => ['int'], 'AMQPDecimal::getSignificand' => ['int'], 'AMQPEnvelope::__construct' => ['void'], 'AMQPEnvelope::getAppId' => ['string'], 'AMQPEnvelope::getBody' => ['string'], 'AMQPEnvelope::getClusterId' => ['string'], 'AMQPEnvelope::getConsumerTag' => ['string'], 'AMQPEnvelope::getContentEncoding' => ['string'], 'AMQPEnvelope::getContentType' => ['string'], 'AMQPEnvelope::getCorrelationId' => ['string'], 'AMQPEnvelope::getDeliveryMode' => ['int'], 'AMQPEnvelope::getDeliveryTag' => ['string'], 'AMQPEnvelope::getExchangeName' => ['string'], 'AMQPEnvelope::getExpiration' => ['string'], 'AMQPEnvelope::getHeader' => ['string|false', 'header_key'=>'string'], 'AMQPEnvelope::getHeaders' => ['array'], 'AMQPEnvelope::getMessageId' => ['string'], 'AMQPEnvelope::getPriority' => ['int'], 'AMQPEnvelope::getReplyTo' => ['string'], 'AMQPEnvelope::getRoutingKey' => ['string'], 'AMQPEnvelope::getTimeStamp' => ['string'], 'AMQPEnvelope::getType' => ['string'], 'AMQPEnvelope::getUserId' => ['string'], 'AMQPEnvelope::hasHeader' => ['bool', 'header_key'=>'string'], 'AMQPEnvelope::isRedelivery' => ['bool'], 'AMQPExchange::__construct' => ['void', 'amqp_channel'=>'AMQPChannel'], 'AMQPExchange::bind' => ['bool', 'exchange_name'=>'string', 'routing_key='=>'string', 'arguments='=>'array'], 'AMQPExchange::declareExchange' => ['bool'], 'AMQPExchange::delete' => ['bool', 'exchangeName='=>'string', 'flags='=>'int'], 'AMQPExchange::getArgument' => ['int|string|false', 'key'=>'string'], 'AMQPExchange::getArguments' => ['array'], 'AMQPExchange::getChannel' => ['AMQPChannel'], 'AMQPExchange::getConnection' => ['AMQPConnection'], 'AMQPExchange::getFlags' => ['int'], 'AMQPExchange::getName' => ['string'], 'AMQPExchange::getType' => ['string'], 'AMQPExchange::hasArgument' => ['bool', 'key'=>'string'], 'AMQPExchange::publish' => ['bool', 'message'=>'string', 'routing_key='=>'string', 'flags='=>'int', 'attributes='=>'array'], 'AMQPExchange::setArgument' => ['bool', 'key'=>'string', 'value'=>'int|string'], 'AMQPExchange::setArguments' => ['bool', 'arguments'=>'array'], 'AMQPExchange::setFlags' => ['bool', 'flags'=>'int'], 'AMQPExchange::setName' => ['bool', 'exchange_name'=>'string'], 'AMQPExchange::setType' => ['bool', 'exchange_type'=>'string'], 'AMQPExchange::unbind' => ['bool', 'exchange_name'=>'string', 'routing_key='=>'string', 'arguments='=>'array'], 'AMQPQueue::__construct' => ['void', 'amqp_channel'=>'AMQPChannel'], 'AMQPQueue::ack' => ['bool', 'delivery_tag'=>'string', 'flags='=>'int'], 'AMQPQueue::bind' => ['bool', 'exchange_name'=>'string', 'routing_key='=>'string', 'arguments='=>'array'], 'AMQPQueue::cancel' => ['bool', 'consumer_tag='=>'string'], 'AMQPQueue::consume' => ['void', 'callback='=>'?callable', 'flags='=>'int', 'consumerTag='=>'string'], 'AMQPQueue::declareQueue' => ['int'], 'AMQPQueue::delete' => ['int', 'flags='=>'int'], 'AMQPQueue::get' => ['AMQPEnvelope|false', 'flags='=>'int'], 'AMQPQueue::getArgument' => ['int|string|false', 'key'=>'string'], 'AMQPQueue::getArguments' => ['array'], 'AMQPQueue::getChannel' => ['AMQPChannel'], 'AMQPQueue::getConnection' => ['AMQPConnection'], 'AMQPQueue::getConsumerTag' => ['?string'], 'AMQPQueue::getFlags' => ['int'], 'AMQPQueue::getName' => ['string'], 'AMQPQueue::hasArgument' => ['bool', 'key'=>'string'], 'AMQPQueue::nack' => ['bool', 'delivery_tag'=>'string', 'flags='=>'int'], 'AMQPQueue::purge' => ['bool'], 'AMQPQueue::reject' => ['bool', 'delivery_tag'=>'string', 'flags='=>'int'], 'AMQPQueue::setArgument' => ['bool', 'key'=>'string', 'value'=>'mixed'], 'AMQPQueue::setArguments' => ['bool', 'arguments'=>'array'], 'AMQPQueue::setFlags' => ['bool', 'flags'=>'int'], 'AMQPQueue::setName' => ['bool', 'queue_name'=>'string'], 'AMQPQueue::unbind' => ['bool', 'exchange_name'=>'string', 'routing_key='=>'string', 'arguments='=>'array'], 'AMQPTimestamp::__construct' => ['void', 'timestamp'=>'string'], 'AMQPTimestamp::__toString' => ['string'], 'AMQPTimestamp::getTimestamp' => ['string'], 'apache_child_terminate' => ['bool'], 'apache_get_modules' => ['array'], 'apache_get_version' => ['string|false'], 'apache_getenv' => ['string|false', 'variable'=>'string', 'walk_to_top='=>'bool'], 'apache_lookup_uri' => ['object', 'filename'=>'string'], 'apache_note' => ['string|false', 'note_name'=>'string', 'note_value='=>'string'], 'apache_request_headers' => ['array|false'], 'apache_reset_timeout' => ['bool'], 'apache_response_headers' => ['array|false'], 'apache_setenv' => ['bool', 'variable'=>'string', 'value'=>'string', 'walk_to_top='=>'bool'], 'apc_add' => ['bool', 'key'=>'string', 'var'=>'mixed', 'ttl='=>'int'], 'apc_add\'1' => ['array', 'values'=>'array', 'unused='=>'', 'ttl='=>'int'], 'apc_bin_dump' => ['string|false|null', 'files='=>'array', 'user_vars='=>'array'], 'apc_bin_dumpfile' => ['int|false', 'files'=>'array', 'user_vars'=>'array', 'filename'=>'string', 'flags='=>'int', 'context='=>'resource'], 'apc_bin_load' => ['bool', 'data'=>'string', 'flags='=>'int'], 'apc_bin_loadfile' => ['bool', 'filename'=>'string', 'context='=>'resource', 'flags='=>'int'], 'apc_cache_info' => ['array|false', 'cache_type='=>'string', 'limited='=>'bool'], 'apc_cas' => ['bool', 'key'=>'string', 'old'=>'int', 'new'=>'int'], 'apc_clear_cache' => ['bool', 'cache_type='=>'string'], 'apc_compile_file' => ['bool', 'filename'=>'string', 'atomic='=>'bool'], 'apc_dec' => ['int|false', 'key'=>'string', 'step='=>'int', '&w_success='=>'bool'], 'apc_define_constants' => ['bool', 'key'=>'string', 'constants'=>'array', 'case_sensitive='=>'bool'], 'apc_delete' => ['bool', 'key'=>'string|string[]|APCIterator'], 'apc_delete_file' => ['bool|string[]', 'keys'=>'mixed'], 'apc_exists' => ['bool', 'keys'=>'string'], 'apc_exists\'1' => ['array', 'keys'=>'string[]'], 'apc_fetch' => ['mixed|false', 'key'=>'string', '&w_success='=>'bool'], 'apc_fetch\'1' => ['array|false', 'key'=>'string[]', '&w_success='=>'bool'], 'apc_inc' => ['int|false', 'key'=>'string', 'step='=>'int', '&w_success='=>'bool'], 'apc_load_constants' => ['bool', 'key'=>'string', 'case_sensitive='=>'bool'], 'apc_sma_info' => ['array|false', 'limited='=>'bool'], 'apc_store' => ['bool', 'key'=>'string', 'var'=>'', 'ttl='=>'int'], 'apc_store\'1' => ['array', 'values'=>'array', 'unused='=>'', 'ttl='=>'int'], 'APCIterator::__construct' => ['void', 'cache'=>'string', 'search='=>'null|string|string[]', 'format='=>'int', 'chunk_size='=>'int', 'list='=>'int'], 'APCIterator::current' => ['mixed|false'], 'APCIterator::getTotalCount' => ['int|false'], 'APCIterator::getTotalHits' => ['int|false'], 'APCIterator::getTotalSize' => ['int|false'], 'APCIterator::key' => ['string'], 'APCIterator::next' => ['void'], 'APCIterator::rewind' => ['void'], 'APCIterator::valid' => ['bool'], 'apcu_add' => ['bool', 'key'=>'string', 'var'=>'', 'ttl='=>'int'], 'apcu_add\'1' => ['array', 'values'=>'array', 'unused='=>'', 'ttl='=>'int'], 'apcu_cache_info' => ['array|false', 'limited='=>'bool'], 'apcu_cas' => ['bool', 'key'=>'string', 'old'=>'int', 'new'=>'int'], 'apcu_clear_cache' => ['bool'], 'apcu_dec' => ['int|false', 'key'=>'string', 'step='=>'int', '&w_success='=>'bool', 'ttl='=>'int'], 'apcu_delete' => ['bool', 'key'=>'string|APCuIterator'], 'apcu_delete\'1' => ['list', 'key'=>'string[]'], 'apcu_enabled' => ['bool'], 'apcu_entry' => ['mixed', 'key'=>'string', 'generator'=>'callable(string):mixed', 'ttl='=>'int'], 'apcu_exists' => ['bool', 'keys'=>'string'], 'apcu_exists\'1' => ['array', 'keys'=>'string[]'], 'apcu_fetch' => ['mixed|false', 'key'=>'string', '&w_success='=>'bool'], 'apcu_fetch\'1' => ['array|false', 'key'=>'string[]', '&w_success='=>'bool'], 'apcu_inc' => ['int|false', 'key'=>'string', 'step='=>'int', '&w_success='=>'bool', 'ttl='=>'int'], 'apcu_key_info' => ['?array', 'key'=>'string'], 'apcu_sma_info' => ['array|false', 'limited='=>'bool'], 'apcu_store' => ['bool', 'key'=>'string', 'var='=>'', 'ttl='=>'int'], 'apcu_store\'1' => ['array', 'values'=>'array', 'unused='=>'', 'ttl='=>'int'], 'APCuIterator::__construct' => ['void', 'search='=>'string|string[]|null', 'format='=>'int', 'chunk_size='=>'int', 'list='=>'int'], 'APCuIterator::current' => ['mixed'], 'APCuIterator::getTotalCount' => ['int'], 'APCuIterator::getTotalHits' => ['int'], 'APCuIterator::getTotalSize' => ['int'], 'APCuIterator::key' => ['string'], 'APCuIterator::next' => ['void'], 'APCuIterator::rewind' => ['void'], 'APCuIterator::valid' => ['bool'], 'apd_breakpoint' => ['bool', 'debug_level'=>'int'], 'apd_callstack' => ['array'], 'apd_clunk' => ['void', 'warning'=>'string', 'delimiter='=>'string'], 'apd_continue' => ['bool', 'debug_level'=>'int'], 'apd_croak' => ['void', 'warning'=>'string', 'delimiter='=>'string'], 'apd_dump_function_table' => ['void'], 'apd_dump_persistent_resources' => ['array'], 'apd_dump_regular_resources' => ['array'], 'apd_echo' => ['bool', 'output'=>'string'], 'apd_get_active_symbols' => ['array'], 'apd_set_pprof_trace' => ['string', 'dump_directory='=>'string', 'fragment='=>'string'], 'apd_set_session' => ['void', 'debug_level'=>'int'], 'apd_set_session_trace' => ['void', 'debug_level'=>'int', 'dump_directory='=>'string'], 'apd_set_session_trace_socket' => ['bool', 'tcp_server'=>'string', 'socket_type'=>'int', 'port'=>'int', 'debug_level'=>'int'], 'AppendIterator::__construct' => ['void'], 'AppendIterator::append' => ['void', 'iterator'=>'Iterator'], 'AppendIterator::current' => ['mixed'], 'AppendIterator::getArrayIterator' => ['ArrayIterator'], 'AppendIterator::getInnerIterator' => ['Iterator'], 'AppendIterator::getIteratorIndex' => ['int'], 'AppendIterator::key' => ['int|string|float|bool'], 'AppendIterator::next' => ['void'], 'AppendIterator::rewind' => ['void'], 'AppendIterator::valid' => ['bool'], 'ArgumentCountError::__construct' => ['void', 'message='=>'string', 'code='=>'int', 'previous='=>'?Throwable'], 'ArgumentCountError::__toString' => ['string'], 'ArgumentCountError::__wakeup' => ['void'], 'ArgumentCountError::getCode' => ['int'], 'ArgumentCountError::getFile' => ['string'], 'ArgumentCountError::getLine' => ['int'], 'ArgumentCountError::getMessage' => ['string'], 'ArgumentCountError::getPrevious' => ['?Throwable'], 'ArgumentCountError::getTrace' => ['list\',args?:array}>'], 'ArgumentCountError::getTraceAsString' => ['string'], 'ArithmeticError::__construct' => ['void', 'message='=>'string', 'code='=>'int', 'previous='=>'?Throwable'], 'ArithmeticError::__toString' => ['string'], 'ArithmeticError::__wakeup' => ['void'], 'ArithmeticError::getCode' => ['int'], 'ArithmeticError::getFile' => ['string'], 'ArithmeticError::getLine' => ['int'], 'ArithmeticError::getMessage' => ['string'], 'ArithmeticError::getPrevious' => ['?Throwable'], 'ArithmeticError::getTrace' => ['list\',args?:array}>'], 'ArithmeticError::getTraceAsString' => ['string'], 'array_change_key_case' => ['array', 'array'=>'array', 'case='=>'int'], 'array_chunk' => ['list', 'array'=>'array', 'length'=>'int', 'preserve_keys='=>'bool'], 'array_column' => ['array', 'array'=>'array', 'column_key'=>'int|string|null', 'index_key='=>'int|string|null'], 'array_combine' => ['array', 'keys'=>'string[]|int[]', 'values'=>'array'], 'array_count_values' => ['array', 'array'=>'array'], 'array_diff' => ['array', 'array'=>'array', '...arrays='=>'array'], 'array_diff_assoc' => ['array', 'array'=>'array', '...arrays='=>'array'], 'array_diff_key' => ['array', 'array'=>'array', '...arrays='=>'array'], 'array_diff_uassoc' => ['array', 'array'=>'array', 'rest'=>'array', 'data_comp_func'=>'callable(mixed,mixed):int'], 'array_diff_uassoc\'1' => ['array', 'array'=>'array', 'rest'=>'array', 'arr3'=>'array', 'arg4'=>'array|callable(mixed,mixed):int', '...rest='=>'array|callable(mixed,mixed):int'], 'array_diff_ukey' => ['array', 'array'=>'array', 'rest'=>'array', 'key_comp_func'=>'callable(mixed,mixed):int'], 'array_diff_ukey\'1' => ['array', 'array'=>'array', 'rest'=>'array', 'arr3'=>'array', 'arg4'=>'array|callable(mixed,mixed):int', '...rest='=>'array|callable(mixed,mixed):int'], 'array_fill' => ['array', 'start_index'=>'int', 'count'=>'int', 'value'=>'mixed'], 'array_fill_keys' => ['array', 'keys'=>'array', 'value'=>'mixed'], 'array_filter' => ['array', 'array'=>'array', 'callback='=>'callable(mixed,array-key=):mixed|null', 'mode='=>'int'], 'array_flip' => ['array', 'array'=>'array'], 'array_intersect' => ['array', 'array'=>'array', '...arrays='=>'array'], 'array_intersect_assoc' => ['array', 'array'=>'array', '...arrays='=>'array'], 'array_intersect_key' => ['array', 'array'=>'array', '...arrays='=>'array'], 'array_intersect_uassoc' => ['array', 'array'=>'array', 'rest'=>'array', 'key_compare_func'=>'callable(mixed,mixed):int'], 'array_intersect_uassoc\'1' => ['array', 'array'=>'array', 'rest'=>'array', 'arr3'=>'array', 'arg4'=>'array|callable(mixed,mixed):int', '...rest'=>'array|callable(mixed,mixed):int'], 'array_intersect_ukey' => ['array', 'array'=>'array', 'rest'=>'array', 'key_compare_func'=>'callable(mixed,mixed):int'], 'array_intersect_ukey\'1' => ['array', 'array'=>'array', 'rest'=>'array', 'arr3'=>'array', 'arg4'=>'array|callable(mixed,mixed):int', '...rest'=>'array|callable(mixed,mixed):int'], 'array_is_list' => ['bool', 'array'=>'array'], 'array_key_exists' => ['bool', 'key'=>'string|int', 'array'=>'array'], 'array_key_first' => ['int|string|null', 'array'=>'array'], 'array_key_last' => ['int|string|null', 'array'=>'array'], 'array_keys' => ['list', 'array'=>'array', 'filter_value='=>'mixed', 'strict='=>'bool'], 'array_map' => ['array', 'callback'=>'?callable', 'array'=>'array', '...arrays='=>'array'], 'array_merge' => ['array', '...arrays='=>'array'], 'array_merge_recursive' => ['array', '...arrays='=>'array'], 'array_multisort' => ['bool', '&rw_array'=>'array', 'rest='=>'array|int', 'array1_sort_flags='=>'array|int', '...args='=>'array|int'], 'array_pad' => ['array', 'array'=>'array', 'length'=>'int', 'value'=>'mixed'], 'array_pop' => ['mixed', '&rw_array'=>'array'], 'array_product' => ['int|float', 'array'=>'array'], 'array_push' => ['int', '&rw_array'=>'array', '...values='=>'mixed'], 'array_rand' => ['int|string|array|array', 'array'=>'non-empty-array', 'num'=>'int'], 'array_rand\'1' => ['int|string', 'array'=>'array'], 'array_reduce' => ['mixed', 'array'=>'array', 'callback'=>'callable(mixed,mixed):mixed', 'initial='=>'mixed'], 'array_replace' => ['array', 'array'=>'array', '...replacements='=>'array'], 'array_replace_recursive' => ['array', 'array'=>'array', '...replacements='=>'array'], 'array_reverse' => ['array', 'array'=>'array', 'preserve_keys='=>'bool'], 'array_search' => ['int|string|false', 'needle'=>'mixed', 'haystack'=>'array', 'strict='=>'bool'], 'array_shift' => ['mixed|null', '&rw_array'=>'array'], 'array_slice' => ['array', 'array'=>'array', 'offset'=>'int', 'length='=>'?int', 'preserve_keys='=>'bool'], 'array_splice' => ['array', '&rw_array'=>'array', 'offset'=>'int', 'length='=>'?int', 'replacement='=>'array|string'], 'array_sum' => ['int|float', 'array'=>'array'], 'array_udiff' => ['array', 'array'=>'array', 'rest'=>'array', 'data_comp_func'=>'callable(mixed,mixed):int'], 'array_udiff\'1' => ['array', 'array'=>'array', 'rest'=>'array', 'arr3'=>'array', 'arg4'=>'array|callable(mixed,mixed):int', '...rest='=>'array|callable(mixed,mixed):int'], 'array_udiff_assoc' => ['array', 'array'=>'array', 'rest'=>'array', 'key_comp_func'=>'callable(mixed,mixed):int'], 'array_udiff_assoc\'1' => ['array', 'array'=>'array', 'rest'=>'array', 'arr3'=>'array', 'arg4'=>'array|callable(mixed,mixed):int', '...rest='=>'array|callable(mixed,mixed):int'], 'array_udiff_uassoc' => ['array', 'array'=>'array', 'rest'=>'array', 'data_comp_func'=>'callable(mixed,mixed):int', 'key_comp_func'=>'callable(mixed,mixed):int'], 'array_udiff_uassoc\'1' => ['array', 'array'=>'array', 'rest'=>'array', 'arr3'=>'array', 'arg4'=>'array|callable(mixed,mixed):int', 'arg5'=>'array|callable(mixed,mixed):int', '...rest='=>'array|callable(mixed,mixed):int'], 'array_uintersect' => ['array', 'array'=>'array', 'rest'=>'array', 'data_compare_func'=>'callable(mixed,mixed):int'], 'array_uintersect\'1' => ['array', 'array'=>'array', 'rest'=>'array', 'arr3'=>'array', 'arg4'=>'array|callable(mixed,mixed):int', '...rest='=>'array|callable(mixed,mixed):int'], 'array_uintersect_assoc' => ['array', 'array'=>'array', 'rest'=>'array', 'data_compare_func'=>'callable(mixed,mixed):int'], 'array_uintersect_assoc\'1' => ['array', 'array'=>'array', 'rest'=>'array', 'arr3'=>'array', 'arg4'=>'array|callable', '...rest='=>'array|callable(mixed,mixed):int'], 'array_uintersect_uassoc' => ['array', 'array'=>'array', 'rest'=>'array', 'data_compare_func'=>'callable(mixed,mixed):int', 'key_compare_func'=>'callable(mixed,mixed):int'], 'array_uintersect_uassoc\'1' => ['array', 'array'=>'array', 'rest'=>'array', 'arr3'=>'array', 'arg4'=>'array|callable(mixed,mixed):int', 'arg5'=>'array|callable(mixed,mixed):int', '...rest='=>'array|callable(mixed,mixed):int'], 'array_unique' => ['array', 'array'=>'array', 'flags='=>'int'], 'array_unshift' => ['int', '&rw_array'=>'array', '...values='=>'mixed'], 'array_values' => ['list', 'array'=>'array'], 'array_walk' => ['bool', '&rw_array'=>'array', 'callback'=>'callable', 'arg='=>'mixed'], 'array_walk\'1' => ['bool', '&rw_array'=>'object', 'callback'=>'callable', 'arg='=>'mixed'], 'array_walk_recursive' => ['bool', '&rw_array'=>'array', 'callback'=>'callable', 'arg='=>'mixed'], 'array_walk_recursive\'1' => ['bool', '&rw_array'=>'object', 'callback'=>'callable', 'arg='=>'mixed'], 'ArrayAccess::offsetExists' => ['bool', 'offset'=>'int|string'], 'ArrayAccess::offsetGet' => ['mixed', 'offset'=>'int|string'], 'ArrayAccess::offsetSet' => ['void', 'offset'=>'int|string|null', 'value'=>'mixed'], 'ArrayAccess::offsetUnset' => ['void', 'offset'=>'int|string'], 'ArrayIterator::__construct' => ['void', 'array='=>'array|object', 'flags='=>'int'], 'ArrayIterator::append' => ['void', 'value'=>'mixed'], 'ArrayIterator::asort' => ['true', 'flags='=>'int'], 'ArrayIterator::count' => ['int'], 'ArrayIterator::current' => ['mixed'], 'ArrayIterator::getArrayCopy' => ['array'], 'ArrayIterator::getFlags' => ['int'], 'ArrayIterator::key' => ['int|string|null'], 'ArrayIterator::ksort' => ['true', 'flags='=>'int'], 'ArrayIterator::natcasesort' => ['true'], 'ArrayIterator::natsort' => ['true'], 'ArrayIterator::next' => ['void'], 'ArrayIterator::offsetExists' => ['bool', 'key'=>'string|int'], 'ArrayIterator::offsetGet' => ['mixed', 'key'=>'string|int'], 'ArrayIterator::offsetSet' => ['void', 'key'=>'string|int|null', 'value'=>'mixed'], 'ArrayIterator::offsetUnset' => ['void', 'key'=>'string|int'], 'ArrayIterator::rewind' => ['void'], 'ArrayIterator::seek' => ['void', 'offset'=>'int'], 'ArrayIterator::serialize' => ['string'], 'ArrayIterator::setFlags' => ['void', 'flags'=>'int'], 'ArrayIterator::uasort' => ['true', 'callback'=>'callable(mixed,mixed):int'], 'ArrayIterator::uksort' => ['true', 'callback'=>'callable(mixed,mixed):int'], 'ArrayIterator::unserialize' => ['void', 'data'=>'string'], 'ArrayIterator::valid' => ['bool'], 'ArrayObject::__construct' => ['void', 'array='=>'array|object', 'flags='=>'int', 'iteratorClass='=>'class-string'], 'ArrayObject::append' => ['void', 'value'=>'mixed'], 'ArrayObject::asort' => ['true', 'flags='=>'int'], 'ArrayObject::count' => ['int'], 'ArrayObject::exchangeArray' => ['array', 'array'=>'array|object'], 'ArrayObject::getArrayCopy' => ['array'], 'ArrayObject::getFlags' => ['int'], 'ArrayObject::getIterator' => ['ArrayIterator'], 'ArrayObject::getIteratorClass' => ['string'], 'ArrayObject::ksort' => ['true', 'flags='=>'int'], 'ArrayObject::natcasesort' => ['true'], 'ArrayObject::natsort' => ['true'], 'ArrayObject::offsetExists' => ['bool', 'key'=>'int|string'], 'ArrayObject::offsetGet' => ['mixed|null', 'key'=>'int|string'], 'ArrayObject::offsetSet' => ['void', 'key'=>'int|string|null', 'value'=>'mixed'], 'ArrayObject::offsetUnset' => ['void', 'key'=>'int|string'], 'ArrayObject::serialize' => ['string'], 'ArrayObject::setFlags' => ['void', 'flags'=>'int'], 'ArrayObject::setIteratorClass' => ['void', 'iteratorClass'=>'class-string'], 'ArrayObject::uasort' => ['true', 'callback'=>'callable(mixed,mixed):int'], 'ArrayObject::uksort' => ['true', 'callback'=>'callable(mixed,mixed):int'], 'ArrayObject::unserialize' => ['void', 'data'=>'string'], 'arsort' => ['true', '&rw_array'=>'array', 'flags='=>'int'], 'asin' => ['float', 'num'=>'float'], 'asinh' => ['float', 'num'=>'float'], 'asort' => ['true', '&rw_array'=>'array', 'flags='=>'int'], 'assert' => ['bool', 'assertion'=>'string|bool|int', 'description='=>'string|Throwable|null'], 'assert_options' => ['mixed|false', 'option'=>'int', 'value='=>'mixed'], 'ast\get_kind_name' => ['string', 'kind'=>'int'], 'ast\get_metadata' => ['array'], 'ast\get_supported_versions' => ['array', 'exclude_deprecated='=>'bool'], 'ast\kind_uses_flags' => ['bool', 'kind'=>'int'], 'ast\Node::__construct' => ['void', 'kind='=>'int', 'flags='=>'int', 'children='=>'ast\Node\Decl[]|ast\Node[]|int[]|string[]|float[]|bool[]|null[]', 'start_line='=>'int'], 'ast\parse_code' => ['ast\Node', 'code'=>'string', 'version'=>'int', 'filename='=>'string'], 'ast\parse_file' => ['ast\Node', 'filename'=>'string', 'version'=>'int'], 'atan' => ['float', 'num'=>'float'], 'atan2' => ['float', 'y'=>'float', 'x'=>'float'], 'atanh' => ['float', 'num'=>'float'], 'BadFunctionCallException::__construct' => ['void', 'message='=>'string', 'code='=>'int', 'previous='=>'?Throwable'], 'BadFunctionCallException::__toString' => ['string'], 'BadFunctionCallException::getCode' => ['int'], 'BadFunctionCallException::getFile' => ['string'], 'BadFunctionCallException::getLine' => ['int'], 'BadFunctionCallException::getMessage' => ['string'], 'BadFunctionCallException::getPrevious' => ['?Throwable'], 'BadFunctionCallException::getTrace' => ['list\',args?:array}>'], 'BadFunctionCallException::getTraceAsString' => ['string'], 'BadMethodCallException::__construct' => ['void', 'message='=>'string', 'code='=>'int', 'previous='=>'?Throwable'], 'BadMethodCallException::__toString' => ['string'], 'BadMethodCallException::getCode' => ['int'], 'BadMethodCallException::getFile' => ['string'], 'BadMethodCallException::getLine' => ['int'], 'BadMethodCallException::getMessage' => ['string'], 'BadMethodCallException::getPrevious' => ['?Throwable'], 'BadMethodCallException::getTrace' => ['list\',args?:array}>'], 'BadMethodCallException::getTraceAsString' => ['string'], 'base64_decode' => ['string', 'string'=>'string', 'strict='=>'false'], 'base64_decode\'1' => ['string|false', 'string'=>'string', 'strict='=>'true'], 'base64_encode' => ['string', 'string'=>'string'], 'base_convert' => ['string', 'num'=>'string', 'from_base'=>'int', 'to_base'=>'int'], 'basename' => ['string', 'path'=>'string', 'suffix='=>'string'], 'bbcode_add_element' => ['bool', 'bbcode_container'=>'resource', 'tag_name'=>'string', 'tag_rules'=>'array'], 'bbcode_add_smiley' => ['bool', 'bbcode_container'=>'resource', 'smiley'=>'string', 'replace_by'=>'string'], 'bbcode_create' => ['resource', 'bbcode_initial_tags='=>'array'], 'bbcode_destroy' => ['bool', 'bbcode_container'=>'resource'], 'bbcode_parse' => ['string', 'bbcode_container'=>'resource', 'to_parse'=>'string'], 'bbcode_set_arg_parser' => ['bool', 'bbcode_container'=>'resource', 'bbcode_arg_parser'=>'resource'], 'bbcode_set_flags' => ['bool', 'bbcode_container'=>'resource', 'flags'=>'int', 'mode='=>'int'], 'bcadd' => ['numeric-string', 'num1'=>'numeric-string', 'num2'=>'numeric-string', 'scale='=>'int|null'], 'bccomp' => ['int', 'num1'=>'numeric-string', 'num2'=>'numeric-string', 'scale='=>'int|null'], 'bcdiv' => ['numeric-string', 'num1'=>'numeric-string', 'num2'=>'numeric-string', 'scale='=>'int|null'], 'bcmod' => ['numeric-string', 'num1'=>'numeric-string', 'num2'=>'numeric-string', 'scale='=>'int|null'], 'bcmul' => ['numeric-string', 'num1'=>'numeric-string', 'num2'=>'numeric-string', 'scale='=>'int|null'], 'bcompiler_load' => ['bool', 'filename'=>'string'], 'bcompiler_load_exe' => ['bool', 'filename'=>'string'], 'bcompiler_parse_class' => ['bool', 'class'=>'string', 'callback'=>'string'], 'bcompiler_read' => ['bool', 'filehandle'=>'resource'], 'bcompiler_write_class' => ['bool', 'filehandle'=>'resource', 'classname'=>'string', 'extends='=>'string'], 'bcompiler_write_constant' => ['bool', 'filehandle'=>'resource', 'constantname'=>'string'], 'bcompiler_write_exe_footer' => ['bool', 'filehandle'=>'resource', 'startpos'=>'int'], 'bcompiler_write_file' => ['bool', 'filehandle'=>'resource', 'filename'=>'string'], 'bcompiler_write_footer' => ['bool', 'filehandle'=>'resource'], 'bcompiler_write_function' => ['bool', 'filehandle'=>'resource', 'functionname'=>'string'], 'bcompiler_write_functions_from_file' => ['bool', 'filehandle'=>'resource', 'filename'=>'string'], 'bcompiler_write_header' => ['bool', 'filehandle'=>'resource', 'write_ver='=>'string'], 'bcompiler_write_included_filename' => ['bool', 'filehandle'=>'resource', 'filename'=>'string'], 'bcpow' => ['numeric-string', 'num'=>'numeric-string', 'exponent'=>'numeric-string', 'scale='=>'int|null'], 'bcpowmod' => ['numeric-string', 'num'=>'numeric-string', 'exponent'=>'numeric-string', 'modulus'=>'numeric-string', 'scale='=>'int|null'], 'bcscale' => ['int', 'scale='=>'int|null'], 'bcsqrt' => ['numeric-string', 'num'=>'numeric-string', 'scale='=>'int|null'], 'bcsub' => ['numeric-string', 'num1'=>'numeric-string', 'num2'=>'numeric-string', 'scale='=>'int|null'], 'bin2hex' => ['string', 'string'=>'string'], 'bind_textdomain_codeset' => ['string', 'domain'=>'string', 'codeset'=>'?string'], 'bindec' => ['float|int', 'binary_string'=>'string'], 'bindtextdomain' => ['string', 'domain'=>'string', 'directory'=>'?string'], 'birdstep_autocommit' => ['bool', 'index'=>'int'], 'birdstep_close' => ['bool', 'id'=>'int'], 'birdstep_commit' => ['bool', 'index'=>'int'], 'birdstep_connect' => ['int', 'server'=>'string', 'user'=>'string', 'pass'=>'string'], 'birdstep_exec' => ['int', 'index'=>'int', 'exec_str'=>'string'], 'birdstep_fetch' => ['bool', 'index'=>'int'], 'birdstep_fieldname' => ['string', 'index'=>'int', 'col'=>'int'], 'birdstep_fieldnum' => ['int', 'index'=>'int'], 'birdstep_freeresult' => ['bool', 'index'=>'int'], 'birdstep_off_autocommit' => ['bool', 'index'=>'int'], 'birdstep_result' => ['', 'index'=>'int', 'col'=>''], 'birdstep_rollback' => ['bool', 'index'=>'int'], 'blenc_encrypt' => ['string', 'plaintext'=>'string', 'encodedfile'=>'string', 'encryption_key='=>'string'], 'boolval' => ['bool', 'value'=>'mixed'], 'bson_decode' => ['array', 'bson'=>'string'], 'bson_encode' => ['string', 'anything'=>'mixed'], 'bzclose' => ['bool', 'bz'=>'resource'], 'bzcompress' => ['string|int', 'data'=>'string', 'block_size='=>'int', 'work_factor='=>'int'], 'bzdecompress' => ['string|int|false', 'data'=>'string', 'use_less_memory='=>'bool'], 'bzerrno' => ['int', 'bz'=>'resource'], 'bzerror' => ['array', 'bz'=>'resource'], 'bzerrstr' => ['string', 'bz'=>'resource'], 'bzflush' => ['bool', 'bz'=>'resource'], 'bzopen' => ['resource|false', 'file'=>'string|resource', 'mode'=>'string'], 'bzread' => ['string|false', 'bz'=>'resource', 'length='=>'int'], 'bzwrite' => ['int|false', 'bz'=>'resource', 'data'=>'string', 'length='=>'?int'], 'CachingIterator::__construct' => ['void', 'iterator'=>'Iterator', 'flags='=>''], 'CachingIterator::__toString' => ['string'], 'CachingIterator::count' => ['int'], 'CachingIterator::current' => ['mixed'], 'CachingIterator::getCache' => ['array'], 'CachingIterator::getFlags' => ['int'], 'CachingIterator::getInnerIterator' => ['Iterator'], 'CachingIterator::hasNext' => ['bool'], 'CachingIterator::key' => ['int|string|float|bool'], 'CachingIterator::next' => ['void'], 'CachingIterator::offsetExists' => ['bool', 'key'=>'string'], 'CachingIterator::offsetGet' => ['mixed', 'key'=>'string'], 'CachingIterator::offsetSet' => ['void', 'key'=>'string', 'value'=>'mixed'], 'CachingIterator::offsetUnset' => ['void', 'key'=>'string'], 'CachingIterator::rewind' => ['void'], 'CachingIterator::setFlags' => ['void', 'flags'=>'int'], 'CachingIterator::valid' => ['bool'], 'cal_days_in_month' => ['int', 'calendar'=>'int', 'month'=>'int', 'year'=>'int'], 'cal_from_jd' => ['array{date:string,month:int,day:int,year:int,dow:int,abbrevdayname:string,dayname:string,abbrevmonth:string,monthname:string}', 'julian_day'=>'int', 'calendar'=>'int'], 'cal_info' => ['array', 'calendar='=>'int'], 'cal_to_jd' => ['int', 'calendar'=>'int', 'month'=>'int', 'day'=>'int', 'year'=>'int'], 'calcul_hmac' => ['string', 'clent'=>'string', 'siretcode'=>'string', 'price'=>'string', 'reference'=>'string', 'validity'=>'string', 'taxation'=>'string', 'devise'=>'string', 'language'=>'string'], 'calculhmac' => ['string', 'clent'=>'string', 'data'=>'string'], 'call_user_func' => ['mixed|false', 'callback'=>'callable', '...args='=>'mixed'], 'call_user_func_array' => ['mixed|false', 'callback'=>'callable', 'args'=>'list'], 'call_user_method' => ['mixed', 'method_name'=>'string', 'object'=>'object', 'parameter='=>'mixed', '...args='=>'mixed'], 'call_user_method_array' => ['mixed', 'method_name'=>'string', 'object'=>'object', 'params'=>'list'], 'CallbackFilterIterator::__construct' => ['void', 'iterator'=>'Iterator', 'callback'=>'callable(mixed,mixed=,mixed=):bool'], 'CallbackFilterIterator::accept' => ['bool'], 'CallbackFilterIterator::current' => ['mixed'], 'CallbackFilterIterator::getInnerIterator' => ['Iterator'], 'CallbackFilterIterator::key' => ['mixed'], 'CallbackFilterIterator::next' => ['void'], 'CallbackFilterIterator::rewind' => ['void'], 'CallbackFilterIterator::valid' => ['bool'], 'ceil' => ['float', 'num'=>'float|int'], 'chdb::__construct' => ['void', 'pathname'=>'string'], 'chdb::get' => ['string', 'key'=>'string'], 'chdb_create' => ['bool', 'pathname'=>'string', 'data'=>'array'], 'chdir' => ['bool', 'directory'=>'string'], 'checkdate' => ['bool', 'month'=>'int', 'day'=>'int', 'year'=>'int'], 'checkdnsrr' => ['bool', 'hostname'=>'string', 'type='=>'string'], 'chgrp' => ['bool', 'filename'=>'string', 'group'=>'string|int'], 'chmod' => ['bool', 'filename'=>'string', 'permissions'=>'int'], 'chop' => ['string', 'string'=>'string', 'characters='=>'string'], 'chown' => ['bool', 'filename'=>'string', 'user'=>'string|int'], 'chr' => ['non-empty-string', 'codepoint'=>'int'], 'chroot' => ['bool', 'directory'=>'string'], 'chunk_split' => ['string', 'string'=>'string', 'length='=>'int', 'separator='=>'string'], 'class_alias' => ['bool', 'class'=>'string', 'alias'=>'string', 'autoload='=>'bool'], 'class_exists' => ['bool', 'class'=>'string', 'autoload='=>'bool'], 'class_implements' => ['array|false', 'object_or_class'=>'object|string', 'autoload='=>'bool'], 'class_parents' => ['array|false', 'object_or_class'=>'object|string', 'autoload='=>'bool'], 'class_uses' => ['array|false', 'object_or_class'=>'object|string', 'autoload='=>'bool'], 'classkit_import' => ['array', 'filename'=>'string'], 'classkit_method_add' => ['bool', 'classname'=>'string', 'methodname'=>'string', 'args'=>'string', 'code'=>'string', 'flags='=>'int'], 'classkit_method_copy' => ['bool', 'dclass'=>'string', 'dmethod'=>'string', 'sclass'=>'string', 'smethod='=>'string'], 'classkit_method_redefine' => ['bool', 'classname'=>'string', 'methodname'=>'string', 'args'=>'string', 'code'=>'string', 'flags='=>'int'], 'classkit_method_remove' => ['bool', 'classname'=>'string', 'methodname'=>'string'], 'classkit_method_rename' => ['bool', 'classname'=>'string', 'methodname'=>'string', 'newname'=>'string'], 'classObj::__construct' => ['void', 'layer'=>'layerObj', 'class'=>'classObj'], 'classObj::addLabel' => ['int', 'label'=>'labelObj'], 'classObj::convertToString' => ['string'], 'classObj::createLegendIcon' => ['imageObj', 'width'=>'int', 'height'=>'int'], 'classObj::deletestyle' => ['int', 'index'=>'int'], 'classObj::drawLegendIcon' => ['int', 'width'=>'int', 'height'=>'int', 'im'=>'imageObj', 'dstX'=>'int', 'dstY'=>'int'], 'classObj::free' => ['void'], 'classObj::getExpressionString' => ['string'], 'classObj::getLabel' => ['labelObj', 'index'=>'int'], 'classObj::getMetaData' => ['int', 'name'=>'string'], 'classObj::getStyle' => ['styleObj', 'index'=>'int'], 'classObj::getTextString' => ['string'], 'classObj::movestyledown' => ['int', 'index'=>'int'], 'classObj::movestyleup' => ['int', 'index'=>'int'], 'classObj::ms_newClassObj' => ['classObj', 'layer'=>'layerObj', 'class'=>'classObj'], 'classObj::removeLabel' => ['labelObj', 'index'=>'int'], 'classObj::removeMetaData' => ['int', 'name'=>'string'], 'classObj::set' => ['int', 'property_name'=>'string', 'new_value'=>''], 'classObj::setExpression' => ['int', 'expression'=>'string'], 'classObj::setMetaData' => ['int', 'name'=>'string', 'value'=>'string'], 'classObj::settext' => ['int', 'text'=>'string'], 'classObj::updateFromString' => ['int', 'snippet'=>'string'], 'clearstatcache' => ['void', 'clear_realpath_cache='=>'bool', 'filename='=>'string'], 'cli_get_process_title' => ['?string'], 'cli_set_process_title' => ['bool', 'title'=>'string'], 'ClosedGeneratorException::__toString' => ['string'], 'ClosedGeneratorException::getCode' => ['int'], 'ClosedGeneratorException::getFile' => ['string'], 'ClosedGeneratorException::getLine' => ['int'], 'ClosedGeneratorException::getMessage' => ['string'], 'ClosedGeneratorException::getPrevious' => ['?Throwable'], 'ClosedGeneratorException::getTrace' => ['list\',args?:array}>'], 'ClosedGeneratorException::getTraceAsString' => ['string'], 'closedir' => ['void', 'dir_handle='=>'resource'], 'closelog' => ['true'], 'Closure::__construct' => ['void'], 'Closure::__invoke' => ['', '...args='=>''], 'Closure::bind' => ['?Closure', 'closure'=>'Closure', 'newThis'=>'?object', 'newScope='=>'object|string|null'], 'Closure::bindTo' => ['?Closure', 'newThis'=>'?object', 'newScope='=>'object|string|null'], 'Closure::call' => ['mixed', 'newThis'=>'object', '...args='=>'mixed'], 'Closure::fromCallable' => ['Closure', 'callback'=>'callable'], 'clusterObj::convertToString' => ['string'], 'clusterObj::getFilterString' => ['string'], 'clusterObj::getGroupString' => ['string'], 'clusterObj::setFilter' => ['int', 'expression'=>'string'], 'clusterObj::setGroup' => ['int', 'expression'=>'string'], 'Collator::__construct' => ['void', 'locale'=>'string'], 'Collator::asort' => ['bool', '&rw_array'=>'array', 'flags='=>'int'], 'Collator::compare' => ['int|false', 'string1'=>'string', 'string2'=>'string'], 'Collator::create' => ['?Collator', 'locale'=>'string'], 'Collator::getAttribute' => ['int|false', 'attribute'=>'int'], 'Collator::getErrorCode' => ['int'], 'Collator::getErrorMessage' => ['string'], 'Collator::getLocale' => ['string', 'type'=>'int'], 'Collator::getSortKey' => ['string|false', 'string'=>'string'], 'Collator::getStrength' => ['int'], 'Collator::setAttribute' => ['bool', 'attribute'=>'int', 'value'=>'int'], 'Collator::setStrength' => ['bool', 'strength'=>'int'], 'Collator::sort' => ['bool', '&rw_array'=>'array', 'flags='=>'int'], 'Collator::sortWithSortKeys' => ['bool', '&rw_array'=>'array'], 'collator_asort' => ['bool', 'object'=>'collator', '&rw_array'=>'array', 'flags='=>'int'], 'collator_compare' => ['int', 'object'=>'collator', 'string1'=>'string', 'string2'=>'string'], 'collator_create' => ['?Collator', 'locale'=>'string'], 'collator_get_attribute' => ['int|false', 'object'=>'collator', 'attribute'=>'int'], 'collator_get_error_code' => ['int', 'object'=>'collator'], 'collator_get_error_message' => ['string', 'object'=>'collator'], 'collator_get_locale' => ['string', 'object'=>'collator', 'type'=>'int'], 'collator_get_sort_key' => ['string', 'object'=>'collator', 'string'=>'string'], 'collator_get_strength' => ['int', 'object'=>'collator'], 'collator_set_attribute' => ['bool', 'object'=>'collator', 'attribute'=>'int', 'value'=>'int'], 'collator_set_strength' => ['bool', 'object'=>'collator', 'strength'=>'int'], 'collator_sort' => ['bool', 'object'=>'collator', '&rw_array'=>'array', 'flags='=>'int'], 'collator_sort_with_sort_keys' => ['bool', 'object'=>'collator', '&rw_array'=>'array'], 'Collectable::isGarbage' => ['bool'], 'Collectable::setGarbage' => ['void'], 'colorObj::setHex' => ['int', 'hex'=>'string'], 'colorObj::toHex' => ['string'], 'COM::__call' => ['', 'name'=>'', 'args'=>''], 'COM::__construct' => ['void', 'module_name'=>'string', 'server_name='=>'mixed', 'codepage='=>'int', 'typelib='=>'string'], 'COM::__get' => ['', 'name'=>''], 'COM::__set' => ['void', 'name'=>'', 'value'=>''], 'com_addref' => [''], 'com_create_guid' => ['string'], 'com_event_sink' => ['bool', 'variant'=>'VARIANT', 'sink_object'=>'object', 'sink_interface='=>'mixed'], 'com_get_active_object' => ['VARIANT', 'prog_id'=>'string', 'codepage='=>'int'], 'com_isenum' => ['bool', 'com_module'=>'variant'], 'com_load_typelib' => ['bool', 'typelib_name'=>'string', 'case_insensitive='=>'true'], 'com_message_pump' => ['bool', 'timeout_milliseconds='=>'int'], 'com_print_typeinfo' => ['bool', 'variant'=>'object', 'dispatch_interface='=>'string', 'display_sink='=>'bool'], 'commonmark\cql::__invoke' => ['', 'root'=>'CommonMark\Node', 'handler'=>'callable'], 'commonmark\interfaces\ivisitable::accept' => ['void', 'visitor'=>'CommonMark\Interfaces\IVisitor'], 'commonmark\interfaces\ivisitor::enter' => ['?int|IVisitable', 'visitable'=>'IVisitable'], 'commonmark\interfaces\ivisitor::leave' => ['?int|IVisitable', 'visitable'=>'IVisitable'], 'commonmark\node::accept' => ['void', 'visitor'=>'CommonMark\Interfaces\IVisitor'], 'commonmark\node::appendChild' => ['CommonMark\Node', 'child'=>'CommonMark\Node'], 'commonmark\node::insertAfter' => ['CommonMark\Node', 'sibling'=>'CommonMark\Node'], 'commonmark\node::insertBefore' => ['CommonMark\Node', 'sibling'=>'CommonMark\Node'], 'commonmark\node::prependChild' => ['CommonMark\Node', 'child'=>'CommonMark\Node'], 'commonmark\node::replace' => ['CommonMark\Node', 'target'=>'CommonMark\Node'], 'commonmark\node::unlink' => ['void'], 'commonmark\parse' => ['CommonMark\Node', 'content'=>'string', 'options='=>'int'], 'commonmark\parser::finish' => ['CommonMark\Node'], 'commonmark\parser::parse' => ['void', 'buffer'=>'string'], 'commonmark\render' => ['string', 'node'=>'CommonMark\Node', 'options='=>'int', 'width='=>'int'], 'commonmark\render\html' => ['string', 'node'=>'CommonMark\Node', 'options='=>'int'], 'commonmark\render\latex' => ['string', 'node'=>'CommonMark\Node', 'options='=>'int', 'width='=>'int'], 'commonmark\render\man' => ['string', 'node'=>'CommonMark\Node', 'options='=>'int', 'width='=>'int'], 'commonmark\render\xml' => ['string', 'node'=>'CommonMark\Node', 'options='=>'int'], 'compact' => ['array', 'var_name'=>'string|array', '...var_names='=>'string|array'], 'COMPersistHelper::__construct' => ['void', 'variant'=>'object'], 'COMPersistHelper::GetCurFile' => ['string'], 'COMPersistHelper::GetCurFileName' => ['string'], 'COMPersistHelper::GetMaxStreamSize' => ['int'], 'COMPersistHelper::InitNew' => ['int'], 'COMPersistHelper::LoadFromFile' => ['bool', 'filename'=>'string', 'flags'=>'int'], 'COMPersistHelper::LoadFromStream' => ['', 'stream'=>''], 'COMPersistHelper::SaveToFile' => ['bool', 'filename'=>'string', 'remember'=>'bool'], 'COMPersistHelper::SaveToStream' => ['int', 'stream'=>''], 'componere\abstract\definition::addInterface' => ['Componere\Abstract\Definition', 'interface'=>'string'], 'componere\abstract\definition::addMethod' => ['Componere\Abstract\Definition', 'name'=>'string', 'method'=>'Componere\Method'], 'componere\abstract\definition::addTrait' => ['Componere\Abstract\Definition', 'trait'=>'string'], 'componere\abstract\definition::getReflector' => ['ReflectionClass'], 'componere\cast' => ['object', 'arg1'=>'string', 'object'=>'object'], 'componere\cast_by_ref' => ['object', 'arg1'=>'string', 'object'=>'object'], 'componere\definition::addConstant' => ['Componere\Definition', 'name'=>'string', 'value'=>'Componere\Value'], 'componere\definition::addProperty' => ['Componere\Definition', 'name'=>'string', 'value'=>'Componere\Value'], 'componere\definition::getClosure' => ['Closure', 'name'=>'string'], 'componere\definition::getClosures' => ['Closure[]'], 'componere\definition::isRegistered' => ['bool'], 'componere\definition::register' => ['void'], 'componere\method::getReflector' => ['ReflectionMethod'], 'componere\method::setPrivate' => ['Method'], 'componere\method::setProtected' => ['Method'], 'componere\method::setStatic' => ['Method'], 'componere\patch::apply' => ['void'], 'componere\patch::derive' => ['Componere\Patch', 'instance'=>'object'], 'componere\patch::getClosure' => ['Closure', 'name'=>'string'], 'componere\patch::getClosures' => ['Closure[]'], 'componere\patch::isApplied' => ['bool'], 'componere\patch::revert' => ['void'], 'componere\value::hasDefault' => ['bool'], 'componere\value::isPrivate' => ['bool'], 'componere\value::isProtected' => ['bool'], 'componere\value::isStatic' => ['bool'], 'componere\value::setPrivate' => ['Value'], 'componere\value::setProtected' => ['Value'], 'componere\value::setStatic' => ['Value'], 'Cond::broadcast' => ['bool', 'condition'=>'long'], 'Cond::create' => ['long'], 'Cond::destroy' => ['bool', 'condition'=>'long'], 'Cond::signal' => ['bool', 'condition'=>'long'], 'Cond::wait' => ['bool', 'condition'=>'long', 'mutex'=>'long', 'timeout='=>'long'], 'confirm_pdo_ibm_compiled' => [''], 'connection_aborted' => ['int'], 'connection_status' => ['int'], 'connection_timeout' => ['int'], 'constant' => ['mixed', 'name'=>'string'], 'convert_cyr_string' => ['string', 'string'=>'string', 'from'=>'string', 'to'=>'string'], 'convert_uudecode' => ['string', 'string'=>'string'], 'convert_uuencode' => ['string', 'string'=>'string'], 'copy' => ['bool', 'from'=>'string', 'to'=>'string', 'context='=>'resource'], 'cos' => ['float', 'num'=>'float'], 'cosh' => ['float', 'num'=>'float'], 'Couchbase\AnalyticsQuery::__construct' => ['void'], 'Couchbase\AnalyticsQuery::fromString' => ['Couchbase\AnalyticsQuery', 'statement'=>'string'], 'Couchbase\basicDecoderV1' => ['mixed', 'bytes'=>'string', 'flags'=>'int', 'datatype'=>'int', 'options'=>'array'], 'Couchbase\basicEncoderV1' => ['array', 'value'=>'mixed', 'options'=>'array'], 'Couchbase\BooleanFieldSearchQuery::__construct' => ['void'], 'Couchbase\BooleanFieldSearchQuery::boost' => ['Couchbase\BooleanFieldSearchQuery', 'boost'=>'float'], 'Couchbase\BooleanFieldSearchQuery::field' => ['Couchbase\BooleanFieldSearchQuery', 'field'=>'string'], 'Couchbase\BooleanFieldSearchQuery::jsonSerialize' => ['array'], 'Couchbase\BooleanSearchQuery::__construct' => ['void'], 'Couchbase\BooleanSearchQuery::boost' => ['Couchbase\BooleanSearchQuery', 'boost'=>'float'], 'Couchbase\BooleanSearchQuery::jsonSerialize' => ['array'], 'Couchbase\BooleanSearchQuery::must' => ['Couchbase\BooleanSearchQuery', '...queries='=>'array'], 'Couchbase\BooleanSearchQuery::mustNot' => ['Couchbase\BooleanSearchQuery', '...queries='=>'array'], 'Couchbase\BooleanSearchQuery::should' => ['Couchbase\BooleanSearchQuery', '...queries='=>'array'], 'Couchbase\Bucket::__construct' => ['void'], 'Couchbase\Bucket::__get' => ['int', 'name'=>'string'], 'Couchbase\Bucket::__set' => ['int', 'name'=>'string', 'value'=>'int'], 'Couchbase\Bucket::append' => ['Couchbase\Document|array', 'ids'=>'array|string', 'value'=>'mixed', 'options='=>'array'], 'Couchbase\Bucket::counter' => ['Couchbase\Document|array', 'ids'=>'array|string', 'delta='=>'int', 'options='=>'array'], 'Couchbase\Bucket::decryptFields' => ['array', 'document'=>'array', 'fieldOptions'=>'', 'prefix='=>'string'], 'Couchbase\Bucket::diag' => ['array', 'reportId='=>'string'], 'Couchbase\Bucket::encryptFields' => ['array', 'document'=>'array', 'fieldOptions'=>'', 'prefix='=>'string'], 'Couchbase\Bucket::get' => ['Couchbase\Document|array', 'ids'=>'array|string', 'options='=>'array'], 'Couchbase\Bucket::getAndLock' => ['Couchbase\Document|array', 'ids'=>'array|string', 'lockTime'=>'int', 'options='=>'array'], 'Couchbase\Bucket::getAndTouch' => ['Couchbase\Document|array', 'ids'=>'array|string', 'expiry'=>'int', 'options='=>'array'], 'Couchbase\Bucket::getFromReplica' => ['Couchbase\Document|array', 'ids'=>'array|string', 'options='=>'array'], 'Couchbase\Bucket::getName' => ['string'], 'Couchbase\Bucket::insert' => ['Couchbase\Document|array', 'ids'=>'array|string', 'value'=>'mixed', 'options='=>'array'], 'Couchbase\Bucket::listExists' => ['bool', 'id'=>'string', 'value'=>'mixed'], 'Couchbase\Bucket::listGet' => ['mixed', 'id'=>'string', 'index'=>'int'], 'Couchbase\Bucket::listPush' => ['', 'id'=>'string', 'value'=>'mixed'], 'Couchbase\Bucket::listRemove' => ['', 'id'=>'string', 'index'=>'int'], 'Couchbase\Bucket::listSet' => ['', 'id'=>'string', 'index'=>'int', 'value'=>'mixed'], 'Couchbase\Bucket::listShift' => ['', 'id'=>'string', 'value'=>'mixed'], 'Couchbase\Bucket::listSize' => ['int', 'id'=>'string'], 'Couchbase\Bucket::lookupIn' => ['Couchbase\LookupInBuilder', 'id'=>'string'], 'Couchbase\Bucket::manager' => ['Couchbase\BucketManager'], 'Couchbase\Bucket::mapAdd' => ['', 'id'=>'string', 'key'=>'string', 'value'=>'mixed'], 'Couchbase\Bucket::mapGet' => ['mixed', 'id'=>'string', 'key'=>'string'], 'Couchbase\Bucket::mapRemove' => ['', 'id'=>'string', 'key'=>'string'], 'Couchbase\Bucket::mapSize' => ['int', 'id'=>'string'], 'Couchbase\Bucket::mutateIn' => ['Couchbase\MutateInBuilder', 'id'=>'string', 'cas'=>'string'], 'Couchbase\Bucket::ping' => ['array', 'services='=>'int', 'reportId='=>'string'], 'Couchbase\Bucket::prepend' => ['Couchbase\Document|array', 'ids'=>'array|string', 'value'=>'mixed', 'options='=>'array'], 'Couchbase\Bucket::query' => ['object', 'query'=>'Couchbase\AnalyticsQuery|Couchbase\N1qlQuery|Couchbase\SearchQuery|Couchbase\SpatialViewQuery|Couchbase\ViewQuery', 'jsonAsArray='=>'bool'], 'Couchbase\Bucket::queueAdd' => ['', 'id'=>'string', 'value'=>'mixed'], 'Couchbase\Bucket::queueExists' => ['bool', 'id'=>'string', 'value'=>'mixed'], 'Couchbase\Bucket::queueRemove' => ['mixed', 'id'=>'string'], 'Couchbase\Bucket::queueSize' => ['int', 'id'=>'string'], 'Couchbase\Bucket::remove' => ['Couchbase\Document|array', 'ids'=>'array|string', 'options='=>'array'], 'Couchbase\Bucket::replace' => ['Couchbase\Document|array', 'ids'=>'array|string', 'value'=>'mixed', 'options='=>'array'], 'Couchbase\Bucket::retrieveIn' => ['Couchbase\DocumentFragment', 'id'=>'string', '...paths='=>'array'], 'Couchbase\Bucket::setAdd' => ['', 'id'=>'string', 'value'=>'bool|float|int|string'], 'Couchbase\Bucket::setExists' => ['bool', 'id'=>'string', 'value'=>'bool|float|int|string'], 'Couchbase\Bucket::setRemove' => ['', 'id'=>'string', 'value'=>'bool|float|int|string'], 'Couchbase\Bucket::setSize' => ['int', 'id'=>'string'], 'Couchbase\Bucket::setTranscoder' => ['', 'encoder'=>'callable', 'decoder'=>'callable'], 'Couchbase\Bucket::touch' => ['Couchbase\Document|array', 'ids'=>'array|string', 'expiry'=>'int', 'options='=>'array'], 'Couchbase\Bucket::unlock' => ['Couchbase\Document|array', 'ids'=>'array|string', 'options='=>'array'], 'Couchbase\Bucket::upsert' => ['Couchbase\Document|array', 'ids'=>'array|string', 'value'=>'mixed', 'options='=>'array'], 'Couchbase\BucketManager::__construct' => ['void'], 'Couchbase\BucketManager::createN1qlIndex' => ['', 'name'=>'string', 'fields'=>'array', 'whereClause='=>'string', 'ignoreIfExist='=>'bool', 'defer='=>'bool'], 'Couchbase\BucketManager::createN1qlPrimaryIndex' => ['', 'customName='=>'string', 'ignoreIfExist='=>'bool', 'defer='=>'bool'], 'Couchbase\BucketManager::dropN1qlIndex' => ['', 'name'=>'string', 'ignoreIfNotExist='=>'bool'], 'Couchbase\BucketManager::dropN1qlPrimaryIndex' => ['', 'customName='=>'string', 'ignoreIfNotExist='=>'bool'], 'Couchbase\BucketManager::flush' => [''], 'Couchbase\BucketManager::getDesignDocument' => ['array', 'name'=>'string'], 'Couchbase\BucketManager::info' => ['array'], 'Couchbase\BucketManager::insertDesignDocument' => ['', 'name'=>'string', 'document'=>'array'], 'Couchbase\BucketManager::listDesignDocuments' => ['array'], 'Couchbase\BucketManager::listN1qlIndexes' => ['array'], 'Couchbase\BucketManager::removeDesignDocument' => ['', 'name'=>'string'], 'Couchbase\BucketManager::upsertDesignDocument' => ['', 'name'=>'string', 'document'=>'array'], 'Couchbase\ClassicAuthenticator::bucket' => ['', 'name'=>'string', 'password'=>'string'], 'Couchbase\ClassicAuthenticator::cluster' => ['', 'username'=>'string', 'password'=>'string'], 'Couchbase\Cluster::__construct' => ['void', 'connstr'=>'string'], 'Couchbase\Cluster::authenticate' => ['null', 'authenticator'=>'Couchbase\Authenticator'], 'Couchbase\Cluster::authenticateAs' => ['null', 'username'=>'string', 'password'=>'string'], 'Couchbase\Cluster::manager' => ['Couchbase\ClusterManager', 'username='=>'string', 'password='=>'string'], 'Couchbase\Cluster::openBucket' => ['Couchbase\Bucket', 'name='=>'string', 'password='=>'string'], 'Couchbase\ClusterManager::__construct' => ['void'], 'Couchbase\ClusterManager::createBucket' => ['', 'name'=>'string', 'options='=>'array'], 'Couchbase\ClusterManager::getUser' => ['array', 'username'=>'string', 'domain='=>'int'], 'Couchbase\ClusterManager::info' => ['array'], 'Couchbase\ClusterManager::listBuckets' => ['array'], 'Couchbase\ClusterManager::listUsers' => ['array', 'domain='=>'int'], 'Couchbase\ClusterManager::removeBucket' => ['', 'name'=>'string'], 'Couchbase\ClusterManager::removeUser' => ['', 'name'=>'string', 'domain='=>'int'], 'Couchbase\ClusterManager::upsertUser' => ['', 'name'=>'string', 'settings'=>'Couchbase\UserSettings', 'domain='=>'int'], 'Couchbase\ConjunctionSearchQuery::__construct' => ['void'], 'Couchbase\ConjunctionSearchQuery::boost' => ['Couchbase\ConjunctionSearchQuery', 'boost'=>'float'], 'Couchbase\ConjunctionSearchQuery::every' => ['Couchbase\ConjunctionSearchQuery', '...queries='=>'array'], 'Couchbase\ConjunctionSearchQuery::jsonSerialize' => ['array'], 'Couchbase\DateRangeSearchFacet::__construct' => ['void'], 'Couchbase\DateRangeSearchFacet::addRange' => ['Couchbase\DateRangeSearchFacet', 'name'=>'string', 'start'=>'int|string', 'end'=>'int|string'], 'Couchbase\DateRangeSearchFacet::jsonSerialize' => ['array'], 'Couchbase\DateRangeSearchQuery::__construct' => ['void'], 'Couchbase\DateRangeSearchQuery::boost' => ['Couchbase\DateRangeSearchQuery', 'boost'=>'float'], 'Couchbase\DateRangeSearchQuery::dateTimeParser' => ['Couchbase\DateRangeSearchQuery', 'dateTimeParser'=>'string'], 'Couchbase\DateRangeSearchQuery::end' => ['Couchbase\DateRangeSearchQuery', 'end'=>'int|string', 'inclusive='=>'bool'], 'Couchbase\DateRangeSearchQuery::field' => ['Couchbase\DateRangeSearchQuery', 'field'=>'string'], 'Couchbase\DateRangeSearchQuery::jsonSerialize' => ['array'], 'Couchbase\DateRangeSearchQuery::start' => ['Couchbase\DateRangeSearchQuery', 'start'=>'int|string', 'inclusive='=>'bool'], 'Couchbase\defaultDecoder' => ['mixed', 'bytes'=>'string', 'flags'=>'int', 'datatype'=>'int'], 'Couchbase\defaultEncoder' => ['array', 'value'=>'mixed'], 'Couchbase\DisjunctionSearchQuery::__construct' => ['void'], 'Couchbase\DisjunctionSearchQuery::boost' => ['Couchbase\DisjunctionSearchQuery', 'boost'=>'float'], 'Couchbase\DisjunctionSearchQuery::either' => ['Couchbase\DisjunctionSearchQuery', '...queries='=>'array'], 'Couchbase\DisjunctionSearchQuery::jsonSerialize' => ['array'], 'Couchbase\DisjunctionSearchQuery::min' => ['Couchbase\DisjunctionSearchQuery', 'min'=>'int'], 'Couchbase\DocIdSearchQuery::__construct' => ['void'], 'Couchbase\DocIdSearchQuery::boost' => ['Couchbase\DocIdSearchQuery', 'boost'=>'float'], 'Couchbase\DocIdSearchQuery::docIds' => ['Couchbase\DocIdSearchQuery', '...documentIds='=>'array'], 'Couchbase\DocIdSearchQuery::field' => ['Couchbase\DocIdSearchQuery', 'field'=>'string'], 'Couchbase\DocIdSearchQuery::jsonSerialize' => ['array'], 'Couchbase\fastlzCompress' => ['string', 'data'=>'string'], 'Couchbase\fastlzDecompress' => ['string', 'data'=>'string'], 'Couchbase\GeoBoundingBoxSearchQuery::__construct' => ['void'], 'Couchbase\GeoBoundingBoxSearchQuery::boost' => ['Couchbase\GeoBoundingBoxSearchQuery', 'boost'=>'float'], 'Couchbase\GeoBoundingBoxSearchQuery::field' => ['Couchbase\GeoBoundingBoxSearchQuery', 'field'=>'string'], 'Couchbase\GeoBoundingBoxSearchQuery::jsonSerialize' => ['array'], 'Couchbase\GeoDistanceSearchQuery::__construct' => ['void'], 'Couchbase\GeoDistanceSearchQuery::boost' => ['Couchbase\GeoDistanceSearchQuery', 'boost'=>'float'], 'Couchbase\GeoDistanceSearchQuery::field' => ['Couchbase\GeoDistanceSearchQuery', 'field'=>'string'], 'Couchbase\GeoDistanceSearchQuery::jsonSerialize' => ['array'], 'Couchbase\LookupInBuilder::__construct' => ['void'], 'Couchbase\LookupInBuilder::execute' => ['Couchbase\DocumentFragment'], 'Couchbase\LookupInBuilder::exists' => ['Couchbase\LookupInBuilder', 'path'=>'string', 'options='=>'array'], 'Couchbase\LookupInBuilder::get' => ['Couchbase\LookupInBuilder', 'path'=>'string', 'options='=>'array'], 'Couchbase\LookupInBuilder::getCount' => ['Couchbase\LookupInBuilder', 'path'=>'string', 'options='=>'array'], 'Couchbase\MatchAllSearchQuery::__construct' => ['void'], 'Couchbase\MatchAllSearchQuery::boost' => ['Couchbase\MatchAllSearchQuery', 'boost'=>'float'], 'Couchbase\MatchAllSearchQuery::jsonSerialize' => ['array'], 'Couchbase\MatchNoneSearchQuery::__construct' => ['void'], 'Couchbase\MatchNoneSearchQuery::boost' => ['Couchbase\MatchNoneSearchQuery', 'boost'=>'float'], 'Couchbase\MatchNoneSearchQuery::jsonSerialize' => ['array'], 'Couchbase\MatchPhraseSearchQuery::__construct' => ['void'], 'Couchbase\MatchPhraseSearchQuery::analyzer' => ['Couchbase\MatchPhraseSearchQuery', 'analyzer'=>'string'], 'Couchbase\MatchPhraseSearchQuery::boost' => ['Couchbase\MatchPhraseSearchQuery', 'boost'=>'float'], 'Couchbase\MatchPhraseSearchQuery::field' => ['Couchbase\MatchPhraseSearchQuery', 'field'=>'string'], 'Couchbase\MatchPhraseSearchQuery::jsonSerialize' => ['array'], 'Couchbase\MatchSearchQuery::__construct' => ['void'], 'Couchbase\MatchSearchQuery::analyzer' => ['Couchbase\MatchSearchQuery', 'analyzer'=>'string'], 'Couchbase\MatchSearchQuery::boost' => ['Couchbase\MatchSearchQuery', 'boost'=>'float'], 'Couchbase\MatchSearchQuery::field' => ['Couchbase\MatchSearchQuery', 'field'=>'string'], 'Couchbase\MatchSearchQuery::fuzziness' => ['Couchbase\MatchSearchQuery', 'fuzziness'=>'int'], 'Couchbase\MatchSearchQuery::jsonSerialize' => ['array'], 'Couchbase\MatchSearchQuery::prefixLength' => ['Couchbase\MatchSearchQuery', 'prefixLength'=>'int'], 'Couchbase\MutateInBuilder::__construct' => ['void'], 'Couchbase\MutateInBuilder::arrayAddUnique' => ['Couchbase\MutateInBuilder', 'path'=>'string', 'value'=>'mixed', 'options='=>'array|bool'], 'Couchbase\MutateInBuilder::arrayAppend' => ['Couchbase\MutateInBuilder', 'path'=>'string', 'value'=>'mixed', 'options='=>'array|bool'], 'Couchbase\MutateInBuilder::arrayAppendAll' => ['Couchbase\MutateInBuilder', 'path'=>'string', 'values'=>'array', 'options='=>'array|bool'], 'Couchbase\MutateInBuilder::arrayInsert' => ['Couchbase\MutateInBuilder', 'path'=>'string', 'value'=>'mixed', 'options='=>'array'], 'Couchbase\MutateInBuilder::arrayInsertAll' => ['Couchbase\MutateInBuilder', 'path'=>'string', 'values'=>'array', 'options='=>'array'], 'Couchbase\MutateInBuilder::arrayPrepend' => ['Couchbase\MutateInBuilder', 'path'=>'string', 'value'=>'mixed', 'options='=>'array|bool'], 'Couchbase\MutateInBuilder::arrayPrependAll' => ['Couchbase\MutateInBuilder', 'path'=>'string', 'values'=>'array', 'options='=>'array|bool'], 'Couchbase\MutateInBuilder::counter' => ['Couchbase\MutateInBuilder', 'path'=>'string', 'delta'=>'int', 'options='=>'array|bool'], 'Couchbase\MutateInBuilder::execute' => ['Couchbase\DocumentFragment'], 'Couchbase\MutateInBuilder::insert' => ['Couchbase\MutateInBuilder', 'path'=>'string', 'value'=>'mixed', 'options='=>'array|bool'], 'Couchbase\MutateInBuilder::modeDocument' => ['', 'mode'=>'int'], 'Couchbase\MutateInBuilder::remove' => ['Couchbase\MutateInBuilder', 'path'=>'string', 'options='=>'array'], 'Couchbase\MutateInBuilder::replace' => ['Couchbase\MutateInBuilder', 'path'=>'string', 'value'=>'mixed', 'options='=>'array'], 'Couchbase\MutateInBuilder::upsert' => ['Couchbase\MutateInBuilder', 'path'=>'string', 'value'=>'mixed', 'options='=>'array|bool'], 'Couchbase\MutateInBuilder::withExpiry' => ['Couchbase\MutateInBuilder', 'expiry'=>'Couchbase\expiry'], 'Couchbase\MutationState::__construct' => ['void'], 'Couchbase\MutationState::add' => ['', 'source'=>'Couchbase\Document|Couchbase\DocumentFragment|array'], 'Couchbase\MutationState::from' => ['Couchbase\MutationState', 'source'=>'Couchbase\Document|Couchbase\DocumentFragment|array'], 'Couchbase\MutationToken::__construct' => ['void'], 'Couchbase\MutationToken::bucketName' => ['string'], 'Couchbase\MutationToken::from' => ['', 'bucketName'=>'string', 'vbucketId'=>'int', 'vbucketUuid'=>'string', 'sequenceNumber'=>'string'], 'Couchbase\MutationToken::sequenceNumber' => ['string'], 'Couchbase\MutationToken::vbucketId' => ['int'], 'Couchbase\MutationToken::vbucketUuid' => ['string'], 'Couchbase\N1qlIndex::__construct' => ['void'], 'Couchbase\N1qlQuery::__construct' => ['void'], 'Couchbase\N1qlQuery::adhoc' => ['Couchbase\N1qlQuery', 'adhoc'=>'bool'], 'Couchbase\N1qlQuery::consistency' => ['Couchbase\N1qlQuery', 'consistency'=>'int'], 'Couchbase\N1qlQuery::consistentWith' => ['Couchbase\N1qlQuery', 'state'=>'Couchbase\MutationState'], 'Couchbase\N1qlQuery::crossBucket' => ['Couchbase\N1qlQuery', 'crossBucket'=>'bool'], 'Couchbase\N1qlQuery::fromString' => ['Couchbase\N1qlQuery', 'statement'=>'string'], 'Couchbase\N1qlQuery::maxParallelism' => ['Couchbase\N1qlQuery', 'maxParallelism'=>'int'], 'Couchbase\N1qlQuery::namedParams' => ['Couchbase\N1qlQuery', 'params'=>'array'], 'Couchbase\N1qlQuery::pipelineBatch' => ['Couchbase\N1qlQuery', 'pipelineBatch'=>'int'], 'Couchbase\N1qlQuery::pipelineCap' => ['Couchbase\N1qlQuery', 'pipelineCap'=>'int'], 'Couchbase\N1qlQuery::positionalParams' => ['Couchbase\N1qlQuery', 'params'=>'array'], 'Couchbase\N1qlQuery::profile' => ['', 'profileType'=>'string'], 'Couchbase\N1qlQuery::readonly' => ['Couchbase\N1qlQuery', 'readonly'=>'bool'], 'Couchbase\N1qlQuery::scanCap' => ['Couchbase\N1qlQuery', 'scanCap'=>'int'], 'Couchbase\NumericRangeSearchFacet::__construct' => ['void'], 'Couchbase\NumericRangeSearchFacet::addRange' => ['Couchbase\NumericRangeSearchFacet', 'name'=>'string', 'min'=>'float', 'max'=>'float'], 'Couchbase\NumericRangeSearchFacet::jsonSerialize' => ['array'], 'Couchbase\NumericRangeSearchQuery::__construct' => ['void'], 'Couchbase\NumericRangeSearchQuery::boost' => ['Couchbase\NumericRangeSearchQuery', 'boost'=>'float'], 'Couchbase\NumericRangeSearchQuery::field' => ['Couchbase\NumericRangeSearchQuery', 'field'=>'string'], 'Couchbase\NumericRangeSearchQuery::jsonSerialize' => ['array'], 'Couchbase\NumericRangeSearchQuery::max' => ['Couchbase\NumericRangeSearchQuery', 'max'=>'float', 'inclusive='=>'bool'], 'Couchbase\NumericRangeSearchQuery::min' => ['Couchbase\NumericRangeSearchQuery', 'min'=>'float', 'inclusive='=>'bool'], 'Couchbase\passthruDecoder' => ['string', 'bytes'=>'string', 'flags'=>'int', 'datatype'=>'int'], 'Couchbase\passthruEncoder' => ['array', 'value'=>'string'], 'Couchbase\PasswordAuthenticator::password' => ['Couchbase\PasswordAuthenticator', 'password'=>'string'], 'Couchbase\PasswordAuthenticator::username' => ['Couchbase\PasswordAuthenticator', 'username'=>'string'], 'Couchbase\PhraseSearchQuery::__construct' => ['void'], 'Couchbase\PhraseSearchQuery::boost' => ['Couchbase\PhraseSearchQuery', 'boost'=>'float'], 'Couchbase\PhraseSearchQuery::field' => ['Couchbase\PhraseSearchQuery', 'field'=>'string'], 'Couchbase\PhraseSearchQuery::jsonSerialize' => ['array'], 'Couchbase\PrefixSearchQuery::__construct' => ['void'], 'Couchbase\PrefixSearchQuery::boost' => ['Couchbase\PrefixSearchQuery', 'boost'=>'float'], 'Couchbase\PrefixSearchQuery::field' => ['Couchbase\PrefixSearchQuery', 'field'=>'string'], 'Couchbase\PrefixSearchQuery::jsonSerialize' => ['array'], 'Couchbase\QueryStringSearchQuery::__construct' => ['void'], 'Couchbase\QueryStringSearchQuery::boost' => ['Couchbase\QueryStringSearchQuery', 'boost'=>'float'], 'Couchbase\QueryStringSearchQuery::jsonSerialize' => ['array'], 'Couchbase\RegexpSearchQuery::__construct' => ['void'], 'Couchbase\RegexpSearchQuery::boost' => ['Couchbase\RegexpSearchQuery', 'boost'=>'float'], 'Couchbase\RegexpSearchQuery::field' => ['Couchbase\RegexpSearchQuery', 'field'=>'string'], 'Couchbase\RegexpSearchQuery::jsonSerialize' => ['array'], 'Couchbase\SearchQuery::__construct' => ['void', 'indexName'=>'string', 'queryPart'=>'Couchbase\SearchQueryPart'], 'Couchbase\SearchQuery::addFacet' => ['Couchbase\SearchQuery', 'name'=>'string', 'facet'=>'Couchbase\SearchFacet'], 'Couchbase\SearchQuery::boolean' => ['Couchbase\BooleanSearchQuery'], 'Couchbase\SearchQuery::booleanField' => ['Couchbase\BooleanFieldSearchQuery', 'value'=>'bool'], 'Couchbase\SearchQuery::conjuncts' => ['Couchbase\ConjunctionSearchQuery', '...queries='=>'array'], 'Couchbase\SearchQuery::consistentWith' => ['Couchbase\SearchQuery', 'state'=>'Couchbase\MutationState'], 'Couchbase\SearchQuery::dateRange' => ['Couchbase\DateRangeSearchQuery'], 'Couchbase\SearchQuery::dateRangeFacet' => ['Couchbase\DateRangeSearchFacet', 'field'=>'string', 'limit'=>'int'], 'Couchbase\SearchQuery::disjuncts' => ['Couchbase\DisjunctionSearchQuery', '...queries='=>'array'], 'Couchbase\SearchQuery::docId' => ['Couchbase\DocIdSearchQuery', '...documentIds='=>'array'], 'Couchbase\SearchQuery::explain' => ['Couchbase\SearchQuery', 'explain'=>'bool'], 'Couchbase\SearchQuery::fields' => ['Couchbase\SearchQuery', '...fields='=>'array'], 'Couchbase\SearchQuery::geoBoundingBox' => ['Couchbase\GeoBoundingBoxSearchQuery', 'topLeftLongitude'=>'float', 'topLeftLatitude'=>'float', 'bottomRightLongitude'=>'float', 'bottomRightLatitude'=>'float'], 'Couchbase\SearchQuery::geoDistance' => ['Couchbase\GeoDistanceSearchQuery', 'longitude'=>'float', 'latitude'=>'float', 'distance'=>'string'], 'Couchbase\SearchQuery::highlight' => ['Couchbase\SearchQuery', 'style'=>'string', '...fields='=>'array'], 'Couchbase\SearchQuery::jsonSerialize' => ['array'], 'Couchbase\SearchQuery::limit' => ['Couchbase\SearchQuery', 'limit'=>'int'], 'Couchbase\SearchQuery::match' => ['Couchbase\MatchSearchQuery', 'match'=>'string'], 'Couchbase\SearchQuery::matchAll' => ['Couchbase\MatchAllSearchQuery'], 'Couchbase\SearchQuery::matchNone' => ['Couchbase\MatchNoneSearchQuery'], 'Couchbase\SearchQuery::matchPhrase' => ['Couchbase\MatchPhraseSearchQuery', '...terms='=>'array'], 'Couchbase\SearchQuery::numericRange' => ['Couchbase\NumericRangeSearchQuery'], 'Couchbase\SearchQuery::numericRangeFacet' => ['Couchbase\NumericRangeSearchFacet', 'field'=>'string', 'limit'=>'int'], 'Couchbase\SearchQuery::prefix' => ['Couchbase\PrefixSearchQuery', 'prefix'=>'string'], 'Couchbase\SearchQuery::queryString' => ['Couchbase\QueryStringSearchQuery', 'queryString'=>'string'], 'Couchbase\SearchQuery::regexp' => ['Couchbase\RegexpSearchQuery', 'regexp'=>'string'], 'Couchbase\SearchQuery::serverSideTimeout' => ['Couchbase\SearchQuery', 'serverSideTimeout'=>'int'], 'Couchbase\SearchQuery::skip' => ['Couchbase\SearchQuery', 'skip'=>'int'], 'Couchbase\SearchQuery::sort' => ['Couchbase\SearchQuery', '...sort='=>'array'], 'Couchbase\SearchQuery::term' => ['Couchbase\TermSearchQuery', 'term'=>'string'], 'Couchbase\SearchQuery::termFacet' => ['Couchbase\TermSearchFacet', 'field'=>'string', 'limit'=>'int'], 'Couchbase\SearchQuery::termRange' => ['Couchbase\TermRangeSearchQuery'], 'Couchbase\SearchQuery::wildcard' => ['Couchbase\WildcardSearchQuery', 'wildcard'=>'string'], 'Couchbase\SearchSort::__construct' => ['void'], 'Couchbase\SearchSort::field' => ['Couchbase\SearchSortField', 'field'=>'string'], 'Couchbase\SearchSort::geoDistance' => ['Couchbase\SearchSortGeoDistance', 'field'=>'string', 'longitude'=>'float', 'latitude'=>'float'], 'Couchbase\SearchSort::id' => ['Couchbase\SearchSortId'], 'Couchbase\SearchSort::score' => ['Couchbase\SearchSortScore'], 'Couchbase\SearchSortField::__construct' => ['void'], 'Couchbase\SearchSortField::descending' => ['Couchbase\SearchSortField', 'descending'=>'bool'], 'Couchbase\SearchSortField::field' => ['Couchbase\SearchSortField', 'field'=>'string'], 'Couchbase\SearchSortField::geoDistance' => ['Couchbase\SearchSortGeoDistance', 'field'=>'string', 'longitude'=>'float', 'latitude'=>'float'], 'Couchbase\SearchSortField::id' => ['Couchbase\SearchSortId'], 'Couchbase\SearchSortField::jsonSerialize' => ['mixed'], 'Couchbase\SearchSortField::missing' => ['', 'missing'=>'string'], 'Couchbase\SearchSortField::mode' => ['', 'mode'=>'string'], 'Couchbase\SearchSortField::score' => ['Couchbase\SearchSortScore'], 'Couchbase\SearchSortField::type' => ['', 'type'=>'string'], 'Couchbase\SearchSortGeoDistance::__construct' => ['void'], 'Couchbase\SearchSortGeoDistance::descending' => ['Couchbase\SearchSortGeoDistance', 'descending'=>'bool'], 'Couchbase\SearchSortGeoDistance::field' => ['Couchbase\SearchSortField', 'field'=>'string'], 'Couchbase\SearchSortGeoDistance::geoDistance' => ['Couchbase\SearchSortGeoDistance', 'field'=>'string', 'longitude'=>'float', 'latitude'=>'float'], 'Couchbase\SearchSortGeoDistance::id' => ['Couchbase\SearchSortId'], 'Couchbase\SearchSortGeoDistance::jsonSerialize' => ['mixed'], 'Couchbase\SearchSortGeoDistance::score' => ['Couchbase\SearchSortScore'], 'Couchbase\SearchSortGeoDistance::unit' => ['Couchbase\SearchSortGeoDistance', 'unit'=>'string'], 'Couchbase\SearchSortId::__construct' => ['void'], 'Couchbase\SearchSortId::descending' => ['Couchbase\SearchSortId', 'descending'=>'bool'], 'Couchbase\SearchSortId::field' => ['Couchbase\SearchSortField', 'field'=>'string'], 'Couchbase\SearchSortId::geoDistance' => ['Couchbase\SearchSortGeoDistance', 'field'=>'string', 'longitude'=>'float', 'latitude'=>'float'], 'Couchbase\SearchSortId::id' => ['Couchbase\SearchSortId'], 'Couchbase\SearchSortId::jsonSerialize' => ['mixed'], 'Couchbase\SearchSortId::score' => ['Couchbase\SearchSortScore'], 'Couchbase\SearchSortScore::__construct' => ['void'], 'Couchbase\SearchSortScore::descending' => ['Couchbase\SearchSortScore', 'descending'=>'bool'], 'Couchbase\SearchSortScore::field' => ['Couchbase\SearchSortField', 'field'=>'string'], 'Couchbase\SearchSortScore::geoDistance' => ['Couchbase\SearchSortGeoDistance', 'field'=>'string', 'longitude'=>'float', 'latitude'=>'float'], 'Couchbase\SearchSortScore::id' => ['Couchbase\SearchSortId'], 'Couchbase\SearchSortScore::jsonSerialize' => ['mixed'], 'Couchbase\SearchSortScore::score' => ['Couchbase\SearchSortScore'], 'Couchbase\SpatialViewQuery::__construct' => ['void'], 'Couchbase\SpatialViewQuery::bbox' => ['Couchbase\SpatialViewQuery', 'bbox'=>'array'], 'Couchbase\SpatialViewQuery::consistency' => ['Couchbase\SpatialViewQuery', 'consistency'=>'int'], 'Couchbase\SpatialViewQuery::custom' => ['', 'customParameters'=>'array'], 'Couchbase\SpatialViewQuery::encode' => ['array'], 'Couchbase\SpatialViewQuery::endRange' => ['Couchbase\SpatialViewQuery', 'range'=>'array'], 'Couchbase\SpatialViewQuery::limit' => ['Couchbase\SpatialViewQuery', 'limit'=>'int'], 'Couchbase\SpatialViewQuery::order' => ['Couchbase\SpatialViewQuery', 'order'=>'int'], 'Couchbase\SpatialViewQuery::skip' => ['Couchbase\SpatialViewQuery', 'skip'=>'int'], 'Couchbase\SpatialViewQuery::startRange' => ['Couchbase\SpatialViewQuery', 'range'=>'array'], 'Couchbase\TermRangeSearchQuery::__construct' => ['void'], 'Couchbase\TermRangeSearchQuery::boost' => ['Couchbase\TermRangeSearchQuery', 'boost'=>'float'], 'Couchbase\TermRangeSearchQuery::field' => ['Couchbase\TermRangeSearchQuery', 'field'=>'string'], 'Couchbase\TermRangeSearchQuery::jsonSerialize' => ['array'], 'Couchbase\TermRangeSearchQuery::max' => ['Couchbase\TermRangeSearchQuery', 'max'=>'string', 'inclusive='=>'bool'], 'Couchbase\TermRangeSearchQuery::min' => ['Couchbase\TermRangeSearchQuery', 'min'=>'string', 'inclusive='=>'bool'], 'Couchbase\TermSearchFacet::__construct' => ['void'], 'Couchbase\TermSearchFacet::jsonSerialize' => ['array'], 'Couchbase\TermSearchQuery::__construct' => ['void'], 'Couchbase\TermSearchQuery::boost' => ['Couchbase\TermSearchQuery', 'boost'=>'float'], 'Couchbase\TermSearchQuery::field' => ['Couchbase\TermSearchQuery', 'field'=>'string'], 'Couchbase\TermSearchQuery::fuzziness' => ['Couchbase\TermSearchQuery', 'fuzziness'=>'int'], 'Couchbase\TermSearchQuery::jsonSerialize' => ['array'], 'Couchbase\TermSearchQuery::prefixLength' => ['Couchbase\TermSearchQuery', 'prefixLength'=>'int'], 'Couchbase\UserSettings::fullName' => ['Couchbase\UserSettings', 'fullName'=>'string'], 'Couchbase\UserSettings::password' => ['Couchbase\UserSettings', 'password'=>'string'], 'Couchbase\UserSettings::role' => ['Couchbase\UserSettings', 'role'=>'string', 'bucket='=>'string'], 'Couchbase\ViewQuery::__construct' => ['void'], 'Couchbase\ViewQuery::consistency' => ['Couchbase\ViewQuery', 'consistency'=>'int'], 'Couchbase\ViewQuery::custom' => ['Couchbase\ViewQuery', 'customParameters'=>'array'], 'Couchbase\ViewQuery::encode' => ['array'], 'Couchbase\ViewQuery::from' => ['Couchbase\ViewQuery', 'designDocumentName'=>'string', 'viewName'=>'string'], 'Couchbase\ViewQuery::fromSpatial' => ['Couchbase\SpatialViewQuery', 'designDocumentName'=>'string', 'viewName'=>'string'], 'Couchbase\ViewQuery::group' => ['Couchbase\ViewQuery', 'group'=>'bool'], 'Couchbase\ViewQuery::groupLevel' => ['Couchbase\ViewQuery', 'groupLevel'=>'int'], 'Couchbase\ViewQuery::idRange' => ['Couchbase\ViewQuery', 'startKeyDocumentId'=>'string', 'endKeyDocumentId'=>'string'], 'Couchbase\ViewQuery::key' => ['Couchbase\ViewQuery', 'key'=>'mixed'], 'Couchbase\ViewQuery::keys' => ['Couchbase\ViewQuery', 'keys'=>'array'], 'Couchbase\ViewQuery::limit' => ['Couchbase\ViewQuery', 'limit'=>'int'], 'Couchbase\ViewQuery::order' => ['Couchbase\ViewQuery', 'order'=>'int'], 'Couchbase\ViewQuery::range' => ['Couchbase\ViewQuery', 'startKey'=>'mixed', 'endKey'=>'mixed', 'inclusiveEnd='=>'bool'], 'Couchbase\ViewQuery::reduce' => ['Couchbase\ViewQuery', 'reduce'=>'bool'], 'Couchbase\ViewQuery::skip' => ['Couchbase\ViewQuery', 'skip'=>'int'], 'Couchbase\ViewQueryEncodable::encode' => ['array'], 'Couchbase\WildcardSearchQuery::__construct' => ['void'], 'Couchbase\WildcardSearchQuery::boost' => ['Couchbase\WildcardSearchQuery', 'boost'=>'float'], 'Couchbase\WildcardSearchQuery::field' => ['Couchbase\WildcardSearchQuery', 'field'=>'string'], 'Couchbase\WildcardSearchQuery::jsonSerialize' => ['array'], 'Couchbase\zlibCompress' => ['string', 'data'=>'string'], 'Couchbase\zlibDecompress' => ['string', 'data'=>'string'], 'count' => ['int<0, max>', 'value'=>'Countable|array', 'mode='=>'int'], 'count_chars' => ['array', 'input'=>'string', 'mode='=>'0|1|2'], 'count_chars\'1' => ['string', 'input'=>'string', 'mode='=>'3|4'], 'Countable::count' => ['int'], 'crack_check' => ['bool', 'dictionary'=>'', 'password'=>'string'], 'crack_closedict' => ['bool', 'dictionary='=>'resource'], 'crack_getlastmessage' => ['string'], 'crack_opendict' => ['resource|false', 'dictionary'=>'string'], 'crash' => [''], 'crc32' => ['int', 'string'=>'string'], 'crypt' => ['string', 'string'=>'string', 'salt'=>'string'], 'ctype_alnum' => ['bool', 'text'=>'string'], 'ctype_alpha' => ['bool', 'text'=>'string'], 'ctype_cntrl' => ['bool', 'text'=>'string'], 'ctype_digit' => ['bool', 'text'=>'string'], 'ctype_graph' => ['bool', 'text'=>'string'], 'ctype_lower' => ['bool', 'text'=>'string'], 'ctype_print' => ['bool', 'text'=>'string'], 'ctype_punct' => ['bool', 'text'=>'string'], 'ctype_space' => ['bool', 'text'=>'string'], 'ctype_upper' => ['bool', 'text'=>'string'], 'ctype_xdigit' => ['bool', 'text'=>'string'], 'cubrid_affected_rows' => ['int', 'req_identifier='=>''], 'cubrid_bind' => ['bool', 'req_identifier'=>'resource', 'bind_param'=>'int', 'bind_value'=>'mixed', 'bind_value_type='=>'string'], 'cubrid_client_encoding' => ['string', 'conn_identifier='=>''], 'cubrid_close' => ['bool', 'conn_identifier='=>''], 'cubrid_close_prepare' => ['bool', 'req_identifier'=>'resource'], 'cubrid_close_request' => ['bool', 'req_identifier'=>'resource'], 'cubrid_col_get' => ['array', 'conn_identifier'=>'resource', 'oid'=>'string', 'attr_name'=>'string'], 'cubrid_col_size' => ['int', 'conn_identifier'=>'resource', 'oid'=>'string', 'attr_name'=>'string'], 'cubrid_column_names' => ['array', 'req_identifier'=>'resource'], 'cubrid_column_types' => ['array', 'req_identifier'=>'resource'], 'cubrid_commit' => ['bool', 'conn_identifier'=>'resource'], 'cubrid_connect' => ['resource', 'host'=>'string', 'port'=>'int', 'dbname'=>'string', 'userid='=>'string', 'passwd='=>'string'], 'cubrid_connect_with_url' => ['resource', 'conn_url'=>'string', 'userid='=>'string', 'passwd='=>'string'], 'cubrid_current_oid' => ['string', 'req_identifier'=>'resource'], 'cubrid_data_seek' => ['bool', 'req_identifier'=>'', 'row_number'=>'int'], 'cubrid_db_name' => ['string', 'result'=>'array', 'index'=>'int'], 'cubrid_db_parameter' => ['array', 'conn_identifier'=>'resource'], 'cubrid_disconnect' => ['bool', 'conn_identifier'=>'resource'], 'cubrid_drop' => ['bool', 'conn_identifier'=>'resource', 'oid'=>'string'], 'cubrid_errno' => ['int', 'conn_identifier='=>''], 'cubrid_error' => ['string', 'connection='=>''], 'cubrid_error_code' => ['int'], 'cubrid_error_code_facility' => ['int'], 'cubrid_error_msg' => ['string'], 'cubrid_execute' => ['bool', 'conn_identifier'=>'', 'sql'=>'string', 'option='=>'int', 'request_identifier='=>''], 'cubrid_fetch' => ['mixed', 'result'=>'resource', 'type='=>'int'], 'cubrid_fetch_array' => ['array', 'result'=>'resource', 'type='=>'int'], 'cubrid_fetch_assoc' => ['array', 'result'=>'resource'], 'cubrid_fetch_field' => ['object', 'result'=>'resource', 'field_offset='=>'int'], 'cubrid_fetch_lengths' => ['array', 'result'=>'resource'], 'cubrid_fetch_object' => ['object', 'result'=>'resource', 'class_name='=>'string', 'params='=>'array'], 'cubrid_fetch_row' => ['array', 'result'=>'resource'], 'cubrid_field_flags' => ['string', 'result'=>'resource', 'field_offset'=>'int'], 'cubrid_field_len' => ['int', 'result'=>'resource', 'field_offset'=>'int'], 'cubrid_field_name' => ['string', 'result'=>'resource', 'field_offset'=>'int'], 'cubrid_field_seek' => ['bool', 'result'=>'resource', 'field_offset='=>'int'], 'cubrid_field_table' => ['string', 'result'=>'resource', 'field_offset'=>'int'], 'cubrid_field_type' => ['string', 'result'=>'resource', 'field_offset'=>'int'], 'cubrid_free_result' => ['bool', 'req_identifier'=>'resource'], 'cubrid_get' => ['mixed', 'conn_identifier'=>'resource', 'oid'=>'string', 'attr='=>'mixed'], 'cubrid_get_autocommit' => ['bool', 'conn_identifier'=>'resource'], 'cubrid_get_charset' => ['string', 'conn_identifier'=>'resource'], 'cubrid_get_class_name' => ['string', 'conn_identifier'=>'resource', 'oid'=>'string'], 'cubrid_get_client_info' => ['string'], 'cubrid_get_db_parameter' => ['array', 'conn_identifier'=>'resource'], 'cubrid_get_query_timeout' => ['int', 'req_identifier'=>'resource'], 'cubrid_get_server_info' => ['string', 'conn_identifier'=>'resource'], 'cubrid_insert_id' => ['string', 'conn_identifier='=>'resource'], 'cubrid_is_instance' => ['int', 'conn_identifier'=>'resource', 'oid'=>'string'], 'cubrid_list_dbs' => ['array', 'conn_identifier'=>'resource'], 'cubrid_load_from_glo' => ['int', 'conn_identifier'=>'', 'oid'=>'string', 'file_name'=>'string'], 'cubrid_lob2_bind' => ['bool', 'req_identifier'=>'resource', 'bind_index'=>'int', 'bind_value'=>'mixed', 'bind_value_type='=>'string'], 'cubrid_lob2_close' => ['bool', 'lob_identifier'=>'resource'], 'cubrid_lob2_export' => ['bool', 'lob_identifier'=>'resource', 'file_name'=>'string'], 'cubrid_lob2_import' => ['bool', 'lob_identifier'=>'resource', 'file_name'=>'string'], 'cubrid_lob2_new' => ['resource', 'conn_identifier='=>'resource', 'type='=>'string'], 'cubrid_lob2_read' => ['string', 'lob_identifier'=>'resource', 'length'=>'int'], 'cubrid_lob2_seek' => ['bool', 'lob_identifier'=>'resource', 'offset'=>'int', 'origin='=>'int'], 'cubrid_lob2_seek64' => ['bool', 'lob_identifier'=>'resource', 'offset'=>'string', 'origin='=>'int'], 'cubrid_lob2_size' => ['int', 'lob_identifier'=>'resource'], 'cubrid_lob2_size64' => ['string', 'lob_identifier'=>'resource'], 'cubrid_lob2_tell' => ['int', 'lob_identifier'=>'resource'], 'cubrid_lob2_tell64' => ['string', 'lob_identifier'=>'resource'], 'cubrid_lob2_write' => ['bool', 'lob_identifier'=>'resource', 'buf'=>'string'], 'cubrid_lob_close' => ['bool', 'lob_identifier_array'=>'array'], 'cubrid_lob_export' => ['bool', 'conn_identifier'=>'resource', 'lob_identifier'=>'resource', 'path_name'=>'string'], 'cubrid_lob_get' => ['array', 'conn_identifier'=>'resource', 'sql'=>'string'], 'cubrid_lob_send' => ['bool', 'conn_identifier'=>'resource', 'lob_identifier'=>'resource'], 'cubrid_lob_size' => ['string', 'lob_identifier'=>'resource'], 'cubrid_lock_read' => ['bool', 'conn_identifier'=>'resource', 'oid'=>'string'], 'cubrid_lock_write' => ['bool', 'conn_identifier'=>'resource', 'oid'=>'string'], 'cubrid_move_cursor' => ['int', 'req_identifier'=>'resource', 'offset'=>'int', 'origin='=>'int'], 'cubrid_new_glo' => ['string', 'conn_identifier'=>'', 'class_name'=>'string', 'file_name'=>'string'], 'cubrid_next_result' => ['bool', 'result'=>'resource'], 'cubrid_num_cols' => ['int', 'req_identifier'=>'resource'], 'cubrid_num_fields' => ['int', 'result'=>'resource'], 'cubrid_num_rows' => ['int', 'req_identifier'=>'resource'], 'cubrid_pconnect' => ['resource', 'host'=>'string', 'port'=>'int', 'dbname'=>'string', 'userid='=>'string', 'passwd='=>'string'], 'cubrid_pconnect_with_url' => ['resource', 'conn_url'=>'string', 'userid='=>'string', 'passwd='=>'string'], 'cubrid_ping' => ['bool', 'conn_identifier='=>''], 'cubrid_prepare' => ['resource', 'conn_identifier'=>'resource', 'prepare_stmt'=>'string', 'option='=>'int'], 'cubrid_put' => ['bool', 'conn_identifier'=>'resource', 'oid'=>'string', 'attr='=>'string', 'value='=>'mixed'], 'cubrid_query' => ['resource', 'query'=>'string', 'conn_identifier='=>''], 'cubrid_real_escape_string' => ['string', 'unescaped_string'=>'string', 'conn_identifier='=>''], 'cubrid_result' => ['string', 'result'=>'resource', 'row'=>'int', 'field='=>''], 'cubrid_rollback' => ['bool', 'conn_identifier'=>'resource'], 'cubrid_save_to_glo' => ['int', 'conn_identifier'=>'', 'oid'=>'string', 'file_name'=>'string'], 'cubrid_schema' => ['array', 'conn_identifier'=>'resource', 'schema_type'=>'int', 'class_name='=>'string', 'attr_name='=>'string'], 'cubrid_send_glo' => ['int', 'conn_identifier'=>'', 'oid'=>'string'], 'cubrid_seq_add' => ['bool', 'conn_identifier'=>'resource', 'oid'=>'string', 'attr_name'=>'string', 'seq_element'=>'string'], 'cubrid_seq_drop' => ['bool', 'conn_identifier'=>'resource', 'oid'=>'string', 'attr_name'=>'string', 'index'=>'int'], 'cubrid_seq_insert' => ['bool', 'conn_identifier'=>'resource', 'oid'=>'string', 'attr_name'=>'string', 'index'=>'int', 'seq_element'=>'string'], 'cubrid_seq_put' => ['bool', 'conn_identifier'=>'resource', 'oid'=>'string', 'attr_name'=>'string', 'index'=>'int', 'seq_element'=>'string'], 'cubrid_set_add' => ['bool', 'conn_identifier'=>'resource', 'oid'=>'string', 'attr_name'=>'string', 'set_element'=>'string'], 'cubrid_set_autocommit' => ['bool', 'conn_identifier'=>'resource', 'mode'=>'bool'], 'cubrid_set_db_parameter' => ['bool', 'conn_identifier'=>'resource', 'param_type'=>'int', 'param_value'=>'int'], 'cubrid_set_drop' => ['bool', 'conn_identifier'=>'resource', 'oid'=>'string', 'attr_name'=>'string', 'set_element'=>'string'], 'cubrid_set_query_timeout' => ['bool', 'req_identifier'=>'resource', 'timeout'=>'int'], 'cubrid_unbuffered_query' => ['resource', 'query'=>'string', 'conn_identifier='=>''], 'cubrid_version' => ['string'], 'curl_close' => ['void', 'handle'=>'CurlHandle'], 'curl_copy_handle' => ['CurlHandle|false', 'handle'=>'CurlHandle'], 'curl_errno' => ['int', 'handle'=>'CurlHandle'], 'curl_error' => ['string', 'handle'=>'CurlHandle'], 'curl_escape' => ['string|false', 'handle'=>'CurlHandle', 'string'=>'string'], 'curl_exec' => ['bool|string', 'handle'=>'CurlHandle'], 'curl_file_create' => ['CURLFile', 'filename'=>'string', 'mime_type='=>'string|null', 'posted_filename='=>'string|null'], 'curl_getinfo' => ['mixed', 'handle'=>'CurlHandle', 'option='=>'?int'], 'curl_init' => ['CurlHandle|false', 'url='=>'?string'], 'curl_multi_add_handle' => ['int', 'multi_handle'=>'CurlMultiHandle', 'handle'=>'CurlHandle'], 'curl_multi_close' => ['void', 'multi_handle'=>'CurlMultiHandle'], 'curl_multi_errno' => ['int', 'multi_handle'=>'CurlMultiHandle'], 'curl_multi_exec' => ['int', 'multi_handle'=>'CurlMultiHandle', '&w_still_running'=>'int'], 'curl_multi_getcontent' => ['string', 'handle'=>'CurlHandle'], 'curl_multi_info_read' => ['array|false', 'multi_handle'=>'CurlMultiHandle', '&w_queued_messages='=>'int'], 'curl_multi_init' => ['CurlMultiHandle'], 'curl_multi_remove_handle' => ['int', 'multi_handle'=>'CurlMultiHandle', 'handle'=>'CurlHandle'], 'curl_multi_select' => ['int', 'multi_handle'=>'CurlMultiHandle', 'timeout='=>'float'], 'curl_multi_setopt' => ['bool', 'multi_handle'=>'CurlMultiHandle', 'option'=>'int', 'value'=>'mixed'], 'curl_multi_strerror' => ['?string', 'error_code'=>'int'], 'curl_pause' => ['int', 'handle'=>'CurlHandle', 'flags'=>'int'], 'curl_reset' => ['void', 'handle'=>'CurlHandle'], 'curl_setopt' => ['bool', 'handle'=>'CurlHandle', 'option'=>'int', 'value'=>'callable|mixed'], 'curl_setopt_array' => ['bool', 'handle'=>'CurlHandle', 'options'=>'array'], 'curl_share_close' => ['void', 'share_handle'=>'CurlShareHandle'], 'curl_share_errno' => ['int', 'share_handle'=>'CurlShareHandle'], 'curl_share_init' => ['CurlShareHandle'], 'curl_share_setopt' => ['bool', 'share_handle'=>'CurlShareHandle', 'option'=>'int', 'value'=>'mixed'], 'curl_share_strerror' => ['?string', 'error_code'=>'int'], 'curl_strerror' => ['?string', 'error_code'=>'int'], 'curl_upkeep' => ['bool', 'handle'=>'CurlHandle'], 'curl_unescape' => ['string|false', 'handle'=>'CurlHandle', 'string'=>'string'], 'curl_version' => ['array', 'version='=>'int'], 'CURLFile::__construct' => ['void', 'filename'=>'string', 'mime_type='=>'?string', 'posted_filename='=>'?string'], 'CURLFile::getFilename' => ['string'], 'CURLFile::getMimeType' => ['string'], 'CURLFile::getPostFilename' => ['string'], 'CURLFile::setMimeType' => ['void', 'mime_type'=>'string'], 'CURLFile::setPostFilename' => ['void', 'posted_filename'=>'string'], 'CURLStringFile::__construct' => ['void', 'data'=>'string', 'postname'=>'string', 'mime='=>'string'], 'current' => ['mixed|false', 'array'=>'array'], 'cyrus_authenticate' => ['void', 'connection'=>'resource', 'mechlist='=>'string', 'service='=>'string', 'user='=>'string', 'minssf='=>'int', 'maxssf='=>'int', 'authname='=>'string', 'password='=>'string'], 'cyrus_bind' => ['bool', 'connection'=>'resource', 'callbacks'=>'array'], 'cyrus_close' => ['bool', 'connection'=>'resource'], 'cyrus_connect' => ['resource', 'host='=>'string', 'port='=>'string', 'flags='=>'int'], 'cyrus_query' => ['array', 'connection'=>'resource', 'query'=>'string'], 'cyrus_unbind' => ['bool', 'connection'=>'resource', 'trigger_name'=>'string'], 'date' => ['string', 'format'=>'string', 'timestamp='=>'?int'], 'date_add' => ['DateTime', 'object'=>'DateTime', 'interval'=>'DateInterval'], 'date_create' => ['DateTime|false', 'datetime='=>'string', 'timezone='=>'?DateTimeZone'], 'date_create_from_format' => ['DateTime|false', 'format'=>'string', 'datetime'=>'string', 'timezone='=>'?\DateTimeZone'], 'date_create_immutable' => ['DateTimeImmutable|false', 'datetime='=>'string', 'timezone='=>'?DateTimeZone'], 'date_create_immutable_from_format' => ['DateTimeImmutable|false', 'format'=>'string', 'datetime'=>'string', 'timezone='=>'?DateTimeZone'], 'date_date_set' => ['DateTime', 'object'=>'DateTime', 'year'=>'int', 'month'=>'int', 'day'=>'int'], 'date_default_timezone_get' => ['non-empty-string'], 'date_default_timezone_set' => ['bool', 'timezoneId'=>'non-empty-string'], 'date_diff' => ['DateInterval', 'baseObject'=>'DateTimeInterface', 'targetObject'=>'DateTimeInterface', 'absolute='=>'bool'], 'date_format' => ['string', 'object'=>'DateTimeInterface', 'format'=>'string'], 'date_get_last_errors' => ['array{warning_count:int,warnings:array,error_count:int,errors:array}|false'], 'date_interval_create_from_date_string' => ['DateInterval', 'datetime'=>'string'], 'date_interval_format' => ['string', 'object'=>'DateInterval', 'format'=>'string'], 'date_isodate_set' => ['DateTime', 'object'=>'DateTime', 'year'=>'int', 'week'=>'int', 'dayOfWeek='=>'int'], 'date_modify' => ['DateTime|false', 'object'=>'DateTime', 'modifier'=>'string'], 'date_offset_get' => ['int', 'object'=>'DateTimeInterface'], 'date_parse' => ['array', 'datetime'=>'string'], 'date_parse_from_format' => ['array', 'format'=>'string', 'datetime'=>'string'], 'date_sub' => ['DateTime', 'object'=>'DateTime', 'interval'=>'DateInterval'], 'date_sun_info' => ['array', 'timestamp'=>'int', 'latitude'=>'float', 'longitude'=>'float'], 'date_sunrise' => ['string|int|float|false', 'timestamp'=>'int', 'returnFormat='=>'int', 'latitude='=>'?float', 'longitude='=>'?float', 'zenith='=>'?float', 'utcOffset='=>'?float'], 'date_sunset' => ['string|int|float|false', 'timestamp'=>'int', 'returnFormat='=>'int', 'latitude='=>'?float', 'longitude='=>'?float', 'zenith='=>'?float', 'utcOffset='=>'?float'], 'date_time_set' => ['DateTime', 'object'=>'', 'hour'=>'', 'minute'=>'', 'second='=>'', 'microsecond='=>''], 'date_timestamp_get' => ['int', 'object'=>'DateTimeInterface'], 'date_timestamp_set' => ['DateTime', 'object'=>'DateTime', 'timestamp'=>'int'], 'date_timezone_get' => ['DateTimeZone|false', 'object'=>'DateTimeInterface'], 'date_timezone_set' => ['DateTime', 'object'=>'DateTime', 'timezone'=>'DateTimeZone'], 'datefmt_create' => ['?IntlDateFormatter', 'locale'=>'?string', 'dateType='=>'int', 'timeType='=>'int', 'timezone='=>'DateTimeZone|IntlTimeZone|string|null', 'calendar='=>'IntlCalendar|int|null', 'pattern='=>'?string'], 'datefmt_format' => ['string|false', 'formatter'=>'IntlDateFormatter', 'datetime'=>'DateTime|IntlCalendar|array|int'], 'datefmt_format_object' => ['string|false', 'datetime'=>'object', 'format='=>'mixed', 'locale='=>'?string'], 'datefmt_get_calendar' => ['int', 'formatter'=>'IntlDateFormatter'], 'datefmt_get_calendar_object' => ['IntlCalendar|false|null', 'formatter'=>'IntlDateFormatter'], 'datefmt_get_datetype' => ['int', 'formatter'=>'IntlDateFormatter'], 'datefmt_get_error_code' => ['int', 'formatter'=>'IntlDateFormatter'], 'datefmt_get_error_message' => ['string', 'formatter'=>'IntlDateFormatter'], 'datefmt_get_locale' => ['string|false', 'formatter'=>'IntlDateFormatter', 'type='=>'int'], 'datefmt_get_pattern' => ['string', 'formatter'=>'IntlDateFormatter'], 'datefmt_get_timetype' => ['int', 'formatter'=>'IntlDateFormatter'], 'datefmt_get_timezone' => ['IntlTimeZone|false', 'formatter'=>'IntlDateFormatter'], 'datefmt_get_timezone_id' => ['string|false', 'formatter'=>'IntlDateFormatter'], 'datefmt_is_lenient' => ['bool', 'formatter'=>'IntlDateFormatter'], 'datefmt_localtime' => ['array|false', 'formatter'=>'IntlDateFormatter', 'string'=>'string', '&rw_offset='=>'int'], 'datefmt_parse' => ['float|int|false', 'formatter'=>'IntlDateFormatter', 'string'=>'string', '&rw_offset='=>'int'], 'datefmt_set_calendar' => ['bool', 'formatter'=>'IntlDateFormatter', 'calendar'=>'IntlCalendar|int|null'], 'datefmt_set_lenient' => ['void', 'formatter'=>'IntlDateFormatter', 'lenient'=>'bool'], 'datefmt_set_pattern' => ['bool', 'formatter'=>'IntlDateFormatter', 'pattern'=>'string'], 'datefmt_set_timezone' => ['bool', 'formatter'=>'IntlDateFormatter', 'timezone'=>'IntlTimeZone|DateTimeZone|string|null'], 'DateInterval::__construct' => ['void', 'duration'=>'string'], 'DateInterval::__set_state' => ['DateInterval', 'array'=>'array'], 'DateInterval::__wakeup' => ['void'], 'DateInterval::createFromDateString' => ['DateInterval|false', 'datetime'=>'string'], 'DateInterval::format' => ['string', 'format'=>'string'], 'DatePeriod::__construct' => ['void', 'start'=>'DateTimeInterface', 'interval'=>'DateInterval', 'recur'=>'int', 'options='=>'int'], 'DatePeriod::__construct\'1' => ['void', 'start'=>'DateTimeInterface', 'interval'=>'DateInterval', 'end'=>'DateTimeInterface', 'options='=>'int'], 'DatePeriod::__construct\'2' => ['void', 'iso'=>'string', 'options='=>'int'], 'DatePeriod::__wakeup' => ['void'], 'DatePeriod::getDateInterval' => ['DateInterval'], 'DatePeriod::getEndDate' => ['?DateTimeInterface'], 'DatePeriod::getStartDate' => ['DateTimeInterface'], 'DateTime::__construct' => ['void', 'time='=>'string'], 'DateTime::__construct\'1' => ['void', 'time'=>'?string', 'timezone'=>'?DateTimeZone'], 'DateTime::__wakeup' => ['void'], 'DateTime::add' => ['static', 'interval'=>'DateInterval'], 'DateTime::createFromFormat' => ['static|false', 'format'=>'string', 'datetime'=>'string', 'timezone='=>'?DateTimeZone'], 'DateTime::createFromImmutable' => ['static', 'object'=>'DateTimeImmutable'], 'DateTime::createFromInterface' => ['static', 'object' => 'DateTimeInterface'], 'DateTime::diff' => ['DateInterval', 'targetObject'=>'DateTimeInterface', 'absolute='=>'bool'], 'DateTime::format' => ['string', 'format'=>'string'], 'DateTime::getLastErrors' => ['array{warning_count:int,warnings:array,error_count:int,errors:array}|false'], 'DateTime::getOffset' => ['int'], 'DateTime::getTimestamp' => ['int'], 'DateTime::getTimezone' => ['DateTimeZone|false'], 'DateTime::modify' => ['static|false', 'modifier'=>'string'], 'DateTime::setDate' => ['static', 'year'=>'int', 'month'=>'int', 'day'=>'int'], 'DateTime::setISODate' => ['static', 'year'=>'int', 'week'=>'int', 'dayOfWeek='=>'int'], 'DateTime::setTime' => ['static', 'hour'=>'int', 'minute'=>'int', 'second='=>'int', 'microsecond='=>'int'], 'DateTime::setTimestamp' => ['static', 'timestamp'=>'int'], 'DateTime::setTimezone' => ['static', 'timezone'=>'DateTimeZone'], 'DateTime::sub' => ['static', 'interval'=>'DateInterval'], 'DateTimeImmutable::__wakeup' => ['void'], 'DateTimeImmutable::createFromInterface' => ['static', 'object' => 'DateTimeInterface'], 'DateTimeImmutable::getLastErrors' => ['array{warning_count:int,warnings:array,error_count:int,errors:array}|false'], 'DateTimeInterface::diff' => ['DateInterval', 'datetime2'=>'DateTimeInterface', 'absolute='=>'bool'], 'DateTimeInterface::format' => ['string', 'format'=>'string'], 'DateTimeInterface::getOffset' => ['int'], 'DateTimeInterface::getTimestamp' => ['int'], 'DateTimeInterface::getTimezone' => ['DateTimeZone|false'], 'DateTimeInterface::__serialize' => ['array'], 'DateTimeInterface::__unserialize' => ['void', 'data'=>'array'], 'DateTimeZone::__construct' => ['void', 'timezone'=>'non-empty-string'], 'DateTimeZone::__set_state' => ['DateTimeZone', 'array'=>'array'], 'DateTimeZone::__wakeup' => ['void'], 'DateTimeZone::getLocation' => ['array|false'], 'DateTimeZone::getName' => ['non-empty-string'], 'DateTimeZone::getOffset' => ['int', 'datetime'=>'DateTimeInterface'], 'DateTimeZone::getTransitions' => ['list|false', 'timestampBegin='=>'int', 'timestampEnd='=>'int'], 'DateTimeZone::listAbbreviations' => ['array>'], 'DateTimeZone::listIdentifiers' => ['list', 'timezoneGroup='=>'int', 'countryCode='=>'string|null'], 'db2_autocommit' => ['0|1|bool', 'connection'=>'resource', 'value='=>'0|1'], 'db2_bind_param' => ['bool', 'stmt'=>'resource', 'parameter_number'=>'int', 'variable_name'=>'string', 'parameter_type='=>'int', 'data_type='=>'int', 'precision='=>'int', 'scale='=>'int'], 'db2_client_info' => ['stdClass|false', 'connection'=>'resource'], 'db2_close' => ['bool', 'connection'=>'resource'], 'db2_column_privileges' => ['resource|false', 'connection'=>'resource', 'qualifier='=>'?string', 'schema='=>'?string', 'table_name='=>'?string', 'column_name='=>'?string'], 'db2_columns' => ['resource|false', 'connection'=>'resource', 'qualifier='=>'?string', 'schema='=>'?string', 'table_name='=>'?string', 'column_name='=>'?string'], 'db2_commit' => ['bool', 'connection'=>'resource'], 'db2_conn_error' => ['string', 'connection='=>'resource'], 'db2_conn_errormsg' => ['string', 'connection='=>'resource'], 'db2_connect' => ['resource|false', 'database'=>'string', 'username'=>'?string', 'password'=>'?string', 'options='=>'array'], 'db2_cursor_type' => ['int', 'stmt'=>'resource'], 'db2_escape_string' => ['string', 'string_literal'=>'string'], 'db2_exec' => ['resource|false', 'connection'=>'resource', 'statement'=>'string', 'options='=>'array'], 'db2_execute' => ['bool', 'stmt'=>'resource', 'parameters='=>'array'], 'db2_fetch_array' => ['array|false', 'stmt'=>'resource', 'row_number='=>'?int'], 'db2_fetch_assoc' => ['array|false', 'stmt'=>'resource', 'row_number='=>'?int'], 'db2_fetch_both' => ['array|false', 'stmt'=>'resource', 'row_number='=>'?int'], 'db2_fetch_object' => ['stdClass|false', 'stmt'=>'resource', 'row_number='=>'?int'], 'db2_fetch_row' => ['bool', 'stmt'=>'resource', 'row_number='=>'?int'], 'db2_field_display_size' => ['int|false', 'stmt'=>'resource', 'column'=>'string|int'], 'db2_field_name' => ['string|false', 'stmt'=>'resource', 'column'=>'string|int'], 'db2_field_num' => ['int|false', 'stmt'=>'resource', 'column'=>'string|int'], 'db2_field_precision' => ['int|false', 'stmt'=>'resource', 'column'=>'string|int'], 'db2_field_scale' => ['int|false', 'stmt'=>'resource', 'column'=>'string|int'], 'db2_field_type' => ['string|false', 'stmt'=>'resource', 'column'=>'string|int'], 'db2_field_width' => ['int|false', 'stmt'=>'resource', 'column'=>'string|int'], 'db2_foreign_keys' => ['resource|false', 'connection'=>'resource', 'qualifier'=>'?string', 'schema'=>'?string', 'table_name'=>'string'], 'db2_free_result' => ['bool', 'stmt'=>'resource'], 'db2_free_stmt' => ['bool', 'stmt'=>'resource'], 'db2_get_option' => ['string|false', 'resource'=>'resource', 'option'=>'string'], 'db2_last_insert_id' => ['string|null', 'resource'=>'resource'], 'db2_lob_read' => ['string|false', 'stmt'=>'resource', 'colnum'=>'int', 'length'=>'int'], 'db2_next_result' => ['resource|false', 'stmt'=>'resource'], 'db2_num_fields' => ['int|false', 'stmt'=>'resource'], 'db2_num_rows' => ['int|false', 'stmt'=>'resource'], 'db2_pclose' => ['bool', 'resource'=>'resource'], 'db2_pconnect' => ['resource|false', 'database'=>'string', 'username'=>'?string', 'password'=>'?string', 'options='=>'array'], 'db2_prepare' => ['resource|false', 'connection'=>'resource', 'statement'=>'string', 'options='=>'array'], 'db2_primary_keys' => ['resource|false', 'connection'=>'resource', 'qualifier'=>'?string', 'schema'=>'?string', 'table_name'=>'string'], 'db2_primarykeys' => [''], 'db2_procedure_columns' => ['resource|false', 'connection'=>'resource', 'qualifier'=>'?string', 'schema'=>'string', 'procedure'=>'string', 'parameter'=>'?string'], 'db2_procedurecolumns' => [''], 'db2_procedures' => ['resource|false', 'connection'=>'resource', 'qualifier'=>'?string', 'schema'=>'string', 'procedure'=>'string'], 'db2_result' => ['mixed', 'stmt'=>'resource', 'column'=>'string|int'], 'db2_rollback' => ['bool', 'connection'=>'resource'], 'db2_server_info' => ['stdClass|false', 'connection'=>'resource'], 'db2_set_option' => ['bool', 'resource'=>'resource', 'options'=>'array', 'type'=>'int'], 'db2_setoption' => [''], 'db2_special_columns' => ['resource|false', 'connection'=>'resource', 'qualifier'=>'?string', 'schema'=>'string', 'table_name'=>'string', 'scope'=>'int'], 'db2_specialcolumns' => [''], 'db2_statistics' => ['resource|false', 'connection'=>'resource', 'qualifier'=>'?string', 'schema'=>'?string', 'table_name'=>'string', 'unique'=>'bool'], 'db2_stmt_error' => ['string', 'stmt='=>'resource'], 'db2_stmt_errormsg' => ['string', 'stmt='=>'resource'], 'db2_table_privileges' => ['resource|false', 'connection'=>'resource', 'qualifier='=>'?string', 'schema='=>'?string', 'table_name='=>'?string'], 'db2_tableprivileges' => [''], 'db2_tables' => ['resource|false', 'connection'=>'resource', 'qualifier='=>'?string', 'schema='=>'?string', 'table_name='=>'?string', 'table_type='=>'?string'], 'dba_close' => ['void', 'dba'=>'resource'], 'dba_delete' => ['bool', 'key'=>'array|string', 'dba'=>'resource'], 'dba_exists' => ['bool', 'key'=>'array|string', 'dba'=>'resource'], 'dba_fetch' => ['string|false', 'key'=>'array|string', 'skip'=>'int', 'dba'=>'resource'], 'dba_fetch\'1' => ['string|false', 'key'=>'array|string', 'skip'=>'resource'], 'dba_firstkey' => ['string', 'dba'=>'resource'], 'dba_handlers' => ['array', 'full_info='=>'bool'], 'dba_insert' => ['bool', 'key'=>'array|string', 'value'=>'string', 'dba'=>'resource'], 'dba_key_split' => ['array|false', 'key'=>'string|false|null'], 'dba_list' => ['array'], 'dba_nextkey' => ['string', 'dba'=>'resource'], 'dba_open' => ['resource', 'path'=>'string', 'mode'=>'string', 'handler='=>'?string', 'permission='=>'int', 'map_size='=>'int', 'flags='=>'?int'], 'dba_optimize' => ['bool', 'dba'=>'resource'], 'dba_popen' => ['resource', 'path'=>'string', 'mode'=>'string', 'handler='=>'?string', 'permission='=>'int', 'map_size='=>'int', 'flags='=>'?int'], 'dba_replace' => ['bool', 'key'=>'array|string', 'value'=>'string', 'dba'=>'resource'], 'dba_sync' => ['bool', 'dba'=>'resource'], 'dbase_add_record' => ['bool', 'dbase_identifier'=>'resource', 'record'=>'array'], 'dbase_close' => ['bool', 'dbase_identifier'=>'resource'], 'dbase_create' => ['resource|false', 'filename'=>'string', 'fields'=>'array'], 'dbase_delete_record' => ['bool', 'dbase_identifier'=>'resource', 'record_number'=>'int'], 'dbase_get_header_info' => ['array', 'dbase_identifier'=>'resource'], 'dbase_get_record' => ['array', 'dbase_identifier'=>'resource', 'record_number'=>'int'], 'dbase_get_record_with_names' => ['array', 'dbase_identifier'=>'resource', 'record_number'=>'int'], 'dbase_numfields' => ['int', 'dbase_identifier'=>'resource'], 'dbase_numrecords' => ['int', 'dbase_identifier'=>'resource'], 'dbase_open' => ['resource|false', 'filename'=>'string', 'mode'=>'int'], 'dbase_pack' => ['bool', 'dbase_identifier'=>'resource'], 'dbase_replace_record' => ['bool', 'dbase_identifier'=>'resource', 'record'=>'array', 'record_number'=>'int'], 'dbplus_add' => ['int', 'relation'=>'resource', 'tuple'=>'array'], 'dbplus_aql' => ['resource', 'query'=>'string', 'server='=>'string', 'dbpath='=>'string'], 'dbplus_chdir' => ['string', 'newdir='=>'string'], 'dbplus_close' => ['mixed', 'relation'=>'resource'], 'dbplus_curr' => ['int', 'relation'=>'resource', 'tuple'=>'array'], 'dbplus_errcode' => ['string', 'errno='=>'int'], 'dbplus_errno' => ['int'], 'dbplus_find' => ['int', 'relation'=>'resource', 'constraints'=>'array', 'tuple'=>'mixed'], 'dbplus_first' => ['int', 'relation'=>'resource', 'tuple'=>'array'], 'dbplus_flush' => ['int', 'relation'=>'resource'], 'dbplus_freealllocks' => ['int'], 'dbplus_freelock' => ['int', 'relation'=>'resource', 'tuple'=>'string'], 'dbplus_freerlocks' => ['int', 'relation'=>'resource'], 'dbplus_getlock' => ['int', 'relation'=>'resource', 'tuple'=>'string'], 'dbplus_getunique' => ['int', 'relation'=>'resource', 'uniqueid'=>'int'], 'dbplus_info' => ['int', 'relation'=>'resource', 'key'=>'string', 'result'=>'array'], 'dbplus_last' => ['int', 'relation'=>'resource', 'tuple'=>'array'], 'dbplus_lockrel' => ['int', 'relation'=>'resource'], 'dbplus_next' => ['int', 'relation'=>'resource', 'tuple'=>'array'], 'dbplus_open' => ['resource', 'name'=>'string'], 'dbplus_prev' => ['int', 'relation'=>'resource', 'tuple'=>'array'], 'dbplus_rchperm' => ['int', 'relation'=>'resource', 'mask'=>'int', 'user'=>'string', 'group'=>'string'], 'dbplus_rcreate' => ['resource', 'name'=>'string', 'domlist'=>'mixed', 'overwrite='=>'bool'], 'dbplus_rcrtexact' => ['mixed', 'name'=>'string', 'relation'=>'resource', 'overwrite='=>'bool'], 'dbplus_rcrtlike' => ['mixed', 'name'=>'string', 'relation'=>'resource', 'overwrite='=>'int'], 'dbplus_resolve' => ['array', 'relation_name'=>'string'], 'dbplus_restorepos' => ['int', 'relation'=>'resource', 'tuple'=>'array'], 'dbplus_rkeys' => ['mixed', 'relation'=>'resource', 'domlist'=>'mixed'], 'dbplus_ropen' => ['resource', 'name'=>'string'], 'dbplus_rquery' => ['resource', 'query'=>'string', 'dbpath='=>'string'], 'dbplus_rrename' => ['int', 'relation'=>'resource', 'name'=>'string'], 'dbplus_rsecindex' => ['mixed', 'relation'=>'resource', 'domlist'=>'mixed', 'type'=>'int'], 'dbplus_runlink' => ['int', 'relation'=>'resource'], 'dbplus_rzap' => ['int', 'relation'=>'resource'], 'dbplus_savepos' => ['int', 'relation'=>'resource'], 'dbplus_setindex' => ['int', 'relation'=>'resource', 'idx_name'=>'string'], 'dbplus_setindexbynumber' => ['int', 'relation'=>'resource', 'idx_number'=>'int'], 'dbplus_sql' => ['resource', 'query'=>'string', 'server='=>'string', 'dbpath='=>'string'], 'dbplus_tcl' => ['string', 'sid'=>'int', 'script'=>'string'], 'dbplus_tremove' => ['int', 'relation'=>'resource', 'tuple'=>'array', 'current='=>'array'], 'dbplus_undo' => ['int', 'relation'=>'resource'], 'dbplus_undoprepare' => ['int', 'relation'=>'resource'], 'dbplus_unlockrel' => ['int', 'relation'=>'resource'], 'dbplus_unselect' => ['int', 'relation'=>'resource'], 'dbplus_update' => ['int', 'relation'=>'resource', 'old'=>'array', 'new'=>'array'], 'dbplus_xlockrel' => ['int', 'relation'=>'resource'], 'dbplus_xunlockrel' => ['int', 'relation'=>'resource'], 'dbx_close' => ['int', 'link_identifier'=>'object'], 'dbx_compare' => ['int', 'row_a'=>'array', 'row_b'=>'array', 'column_key'=>'string', 'flags='=>'int'], 'dbx_connect' => ['object', 'module'=>'mixed', 'host'=>'string', 'database'=>'string', 'username'=>'string', 'password'=>'string', 'persistent='=>'int'], 'dbx_error' => ['string', 'link_identifier'=>'object'], 'dbx_escape_string' => ['string', 'link_identifier'=>'object', 'text'=>'string'], 'dbx_fetch_row' => ['mixed', 'result_identifier'=>'object'], 'dbx_query' => ['mixed', 'link_identifier'=>'object', 'sql_statement'=>'string', 'flags='=>'int'], 'dbx_sort' => ['bool', 'result'=>'object', 'user_compare_function'=>'string'], 'dcgettext' => ['string', 'domain'=>'string', 'message'=>'string', 'category'=>'int'], 'dcngettext' => ['string', 'domain'=>'string', 'singular'=>'string', 'plural'=>'string', 'count'=>'int', 'category'=>'int'], 'deaggregate' => ['', 'object'=>'object', 'class_name='=>'string'], 'debug_backtrace' => ['list', 'options='=>'int', 'limit='=>'int'], 'debug_print_backtrace' => ['void', 'options='=>'int', 'limit='=>'int'], 'debug_zval_dump' => ['void', 'value'=>'mixed', '...values='=>'mixed'], 'debugger_connect' => [''], 'debugger_connector_pid' => [''], 'debugger_get_server_start_time' => [''], 'debugger_print' => [''], 'debugger_start_debug' => [''], 'decbin' => ['string', 'num'=>'int'], 'dechex' => ['string', 'num'=>'int'], 'decoct' => ['string', 'num'=>'int'], 'define' => ['bool', 'constant_name'=>'string', 'value'=>'array|scalar|null', 'case_insensitive='=>'false'], 'define_syslog_variables' => ['void'], 'defined' => ['bool', 'constant_name'=>'string'], 'deflate_add' => ['string|false', 'context'=>'DeflateContext', 'data'=>'string', 'flush_mode='=>'int'], 'deflate_init' => ['DeflateContext|false', 'encoding'=>'int', 'options='=>'array'], 'deg2rad' => ['float', 'num'=>'float'], 'dgettext' => ['string', 'domain'=>'string', 'message'=>'string'], 'dio_close' => ['void', 'fd'=>'resource'], 'dio_fcntl' => ['mixed', 'fd'=>'resource', 'cmd'=>'int', 'args='=>'mixed'], 'dio_open' => ['resource|false', 'filename'=>'string', 'flags'=>'int', 'mode='=>'int'], 'dio_read' => ['string', 'fd'=>'resource', 'length='=>'int'], 'dio_seek' => ['int', 'fd'=>'resource', 'pos'=>'int', 'whence='=>'int'], 'dio_stat' => ['?array', 'fd'=>'resource'], 'dio_tcsetattr' => ['bool', 'fd'=>'resource', 'options'=>'array'], 'dio_truncate' => ['bool', 'fd'=>'resource', 'offset'=>'int'], 'dio_write' => ['int', 'fd'=>'resource', 'data'=>'string', 'length='=>'int'], 'dir' => ['Directory|false', 'directory'=>'string', 'context='=>'resource'], 'Directory::close' => ['void'], 'Directory::read' => ['string|false'], 'Directory::rewind' => ['void'], 'DirectoryIterator::__construct' => ['void', 'directory'=>'string'], 'DirectoryIterator::__toString' => ['string'], 'DirectoryIterator::current' => ['DirectoryIterator'], 'DirectoryIterator::getATime' => ['int'], 'DirectoryIterator::getBasename' => ['string', 'suffix='=>'string'], 'DirectoryIterator::getCTime' => ['int'], 'DirectoryIterator::getExtension' => ['string'], 'DirectoryIterator::getFileInfo' => ['SplFileInfo', 'class='=>'?class-string'], 'DirectoryIterator::getFilename' => ['string'], 'DirectoryIterator::getGroup' => ['int'], 'DirectoryIterator::getInode' => ['int'], 'DirectoryIterator::getLinkTarget' => ['string'], 'DirectoryIterator::getMTime' => ['int'], 'DirectoryIterator::getOwner' => ['int'], 'DirectoryIterator::getPath' => ['string'], 'DirectoryIterator::getPathInfo' => ['?SplFileInfo', 'class='=>'?class-string'], 'DirectoryIterator::getPathname' => ['string'], 'DirectoryIterator::getPerms' => ['int'], 'DirectoryIterator::getRealPath' => ['non-falsy-string'], 'DirectoryIterator::getSize' => ['int'], 'DirectoryIterator::getType' => ['string'], 'DirectoryIterator::isDir' => ['bool'], 'DirectoryIterator::isDot' => ['bool'], 'DirectoryIterator::isExecutable' => ['bool'], 'DirectoryIterator::isFile' => ['bool'], 'DirectoryIterator::isLink' => ['bool'], 'DirectoryIterator::isReadable' => ['bool'], 'DirectoryIterator::isWritable' => ['bool'], 'DirectoryIterator::key' => ['string'], 'DirectoryIterator::next' => ['void'], 'DirectoryIterator::openFile' => ['SplFileObject', 'mode='=>'string', 'useIncludePath='=>'bool', 'context='=>'?resource'], 'DirectoryIterator::rewind' => ['void'], 'DirectoryIterator::seek' => ['void', 'offset'=>'int'], 'DirectoryIterator::setFileClass' => ['void', 'class='=>'class-string'], 'DirectoryIterator::setInfoClass' => ['void', 'class='=>'class-string'], 'DirectoryIterator::valid' => ['bool'], 'dirname' => ['string', 'path'=>'string', 'levels='=>'int<1, max>'], 'disk_free_space' => ['float|false', 'directory'=>'string'], 'disk_total_space' => ['float|false', 'directory'=>'string'], 'diskfreespace' => ['float|false', 'directory'=>'string'], 'display_disabled_function' => [''], 'dl' => ['bool', 'extension_filename'=>'string'], 'dngettext' => ['string', 'domain'=>'string', 'singular'=>'string', 'plural'=>'string', 'count'=>'int'], 'dns_check_record' => ['bool', 'hostname'=>'string', 'type='=>'string'], 'dns_get_mx' => ['bool', 'hostname'=>'string', '&w_hosts'=>'array', '&w_weights='=>'array'], 'dns_get_record' => ['list|false', 'hostname'=>'string', 'type='=>'int', '&w_authoritative_name_servers='=>'array', '&w_additional_records='=>'array', 'raw='=>'bool'], 'dom_document_relaxNG_validate_file' => ['bool', 'filename'=>'string'], 'dom_document_relaxNG_validate_xml' => ['bool', 'source'=>'string'], 'dom_document_schema_validate' => ['bool', 'source'=>'string', 'flags'=>'int'], 'dom_document_schema_validate_file' => ['bool', 'filename'=>'string', 'flags'=>'int'], 'dom_document_xinclude' => ['int', 'options'=>'int'], 'dom_import_simplexml' => ['DOMElement', 'node'=>'SimpleXMLElement'], 'dom_xpath_evaluate' => ['', 'expr'=>'string', 'context'=>'DOMNode', 'registernodens'=>'bool'], 'dom_xpath_query' => ['DOMNodeList', 'expr'=>'string', 'context'=>'DOMNode', 'registernodens'=>'bool'], 'dom_xpath_register_ns' => ['bool', 'prefix'=>'string', 'uri'=>'string'], 'dom_xpath_register_php_functions' => [''], 'DomainException::__construct' => ['void', 'message='=>'string', 'code='=>'int', 'previous='=>'?Throwable'], 'DomainException::__toString' => ['string'], 'DomainException::__wakeup' => ['void'], 'DomainException::getCode' => ['int'], 'DomainException::getFile' => ['string'], 'DomainException::getLine' => ['int'], 'DomainException::getMessage' => ['string'], 'DomainException::getPrevious' => ['?Throwable'], 'DomainException::getTrace' => ['list\',args?:array}>'], 'DomainException::getTraceAsString' => ['string'], 'DOMAttr::__construct' => ['void', 'name'=>'string', 'value='=>'string'], 'DOMAttr::getLineNo' => ['int'], 'DOMAttr::getNodePath' => ['?string'], 'DOMAttr::hasAttributes' => ['bool'], 'DOMAttr::hasChildNodes' => ['bool'], 'DOMAttr::insertBefore' => ['DOMNode|false', 'node'=>'DOMNode', 'child='=>'?DOMNode'], 'DOMAttr::isDefaultNamespace' => ['bool', 'namespace'=>'string'], 'DOMAttr::isId' => ['bool'], 'DOMAttr::isSameNode' => ['bool', 'otherNode'=>'DOMNode'], 'DOMAttr::isSupported' => ['bool', 'feature'=>'string', 'version'=>'string'], 'DOMAttr::lookupNamespaceUri' => ['string|null', 'prefix'=>'string|null'], 'DOMAttr::lookupPrefix' => ['string|null', 'namespace'=>'string'], 'DOMAttr::normalize' => ['void'], 'DOMAttr::removeChild' => ['DOMNode|false', 'child'=>'DOMNode'], 'DOMAttr::replaceChild' => ['DOMNode|false', 'node'=>'DOMNode', 'child'=>'DOMNode'], 'DomAttribute::name' => ['string'], 'DomAttribute::set_value' => ['bool', 'content'=>'string'], 'DomAttribute::specified' => ['bool'], 'DomAttribute::value' => ['string'], 'DOMCdataSection::__construct' => ['void', 'data'=>'string'], 'DOMCharacterData::appendData' => ['true', 'data'=>'string'], 'DOMCharacterData::deleteData' => ['bool', 'offset'=>'int', 'count'=>'int'], 'DOMCharacterData::insertData' => ['bool', 'offset'=>'int', 'data'=>'string'], 'DOMCharacterData::replaceData' => ['bool', 'offset'=>'int', 'count'=>'int', 'data'=>'string'], 'DOMCharacterData::substringData' => ['string', 'offset'=>'int', 'count'=>'int'], 'DOMComment::__construct' => ['void', 'data='=>'string'], 'DOMDocument::__construct' => ['void', 'version='=>'string', 'encoding='=>'string'], 'DOMDocument::createAttribute' => ['DOMAttr|false', 'localName'=>'string'], 'DOMDocument::createAttributeNS' => ['DOMAttr|false', 'namespace'=>'string|null', 'qualifiedName'=>'string'], 'DOMDocument::createCDATASection' => ['DOMCDATASection|false', 'data'=>'string'], 'DOMDocument::createComment' => ['DOMComment', 'data'=>'string'], 'DOMDocument::createDocumentFragment' => ['DOMDocumentFragment'], 'DOMDocument::createElement' => ['DOMElement|false', 'localName'=>'string', 'value='=>'string'], 'DOMDocument::createElementNS' => ['DOMElement|false', 'namespace'=>'string|null', 'qualifiedName'=>'string', 'value='=>'string'], 'DOMDocument::createEntityReference' => ['DOMEntityReference|false', 'name'=>'string'], 'DOMDocument::createProcessingInstruction' => ['DOMProcessingInstruction|false', 'target'=>'string', 'data='=>'string'], 'DOMDocument::createTextNode' => ['DOMText', 'data'=>'string'], 'DOMDocument::getElementById' => ['?DOMElement', 'elementId'=>'string'], 'DOMDocument::getElementsByTagName' => ['DOMNodeList', 'qualifiedName'=>'string'], 'DOMDocument::getElementsByTagNameNS' => ['DOMNodeList', 'namespace'=>'?string', 'localName'=>'string'], 'DOMDocument::importNode' => ['DOMNode|false', 'node'=>'DOMNode', 'deep='=>'bool'], 'DOMDocument::load' => ['bool', 'filename'=>'string', 'options='=>'int'], 'DOMDocument::loadHTML' => ['bool', 'source'=>'non-empty-string', 'options='=>'int'], 'DOMDocument::loadHTMLFile' => ['bool', 'filename'=>'string', 'options='=>'int'], 'DOMDocument::loadXML' => ['bool', 'source'=>'non-empty-string', 'options='=>'int'], 'DOMDocument::normalizeDocument' => ['void'], 'DOMDocument::registerNodeClass' => ['bool', 'baseClass'=>'string', 'extendedClass'=>'?string'], 'DOMDocument::relaxNGValidate' => ['bool', 'filename'=>'string'], 'DOMDocument::relaxNGValidateSource' => ['bool', 'source'=>'string'], 'DOMDocument::save' => ['int|false', 'filename'=>'string', 'options='=>'int'], 'DOMDocument::saveHTML' => ['string|false', 'node='=>'?DOMNode'], 'DOMDocument::saveHTMLFile' => ['int|false', 'filename'=>'string'], 'DOMDocument::saveXML' => ['string|false', 'node='=>'?DOMNode', 'options='=>'int'], 'DOMDocument::schemaValidate' => ['bool', 'filename'=>'string', 'flags='=>'int'], 'DOMDocument::schemaValidateSource' => ['bool', 'source'=>'string', 'flags='=>'int'], 'DOMDocument::validate' => ['bool'], 'DOMDocument::xinclude' => ['int', 'options='=>'int'], 'DOMDocumentFragment::__construct' => ['void'], 'DOMDocumentFragment::appendXML' => ['bool', 'data'=>'string'], 'DOMElement::__construct' => ['void', 'qualifiedName'=>'string', 'value='=>'?string', 'namespace='=>'string'], 'DOMElement::getAttribute' => ['string', 'qualifiedName'=>'string'], 'DOMElement::getAttributeNode' => ['DOMAttr', 'qualifiedName'=>'string'], 'DOMElement::getAttributeNodeNS' => ['DOMAttr', 'namespace'=>'string|null', 'localName'=>'string'], 'DOMElement::getAttributeNS' => ['string', 'namespace'=>'string|null', 'localName'=>'string'], 'DOMElement::getElementsByTagName' => ['DOMNodeList', 'qualifiedName'=>'string'], 'DOMElement::getElementsByTagNameNS' => ['DOMNodeList', 'namespace'=>'string|null', 'localName'=>'string'], 'DOMElement::hasAttribute' => ['bool', 'qualifiedName'=>'string'], 'DOMElement::hasAttributeNS' => ['bool', 'namespace'=>'string|null', 'localName'=>'string'], 'DOMElement::removeAttribute' => ['bool', 'qualifiedName'=>'string'], 'DOMElement::removeAttributeNode' => ['DOMAttr|false', 'attr'=>'DOMAttr'], 'DOMElement::removeAttributeNS' => ['void', 'namespace'=>'string|null', 'localName'=>'string'], 'DOMElement::setAttribute' => ['DOMAttr|false', 'qualifiedName'=>'string', 'value'=>'string'], 'DOMElement::setAttributeNode' => ['?DOMAttr', 'attr'=>'DOMAttr'], 'DOMElement::setAttributeNodeNS' => ['DOMAttr', 'attr'=>'DOMAttr'], 'DOMElement::setAttributeNS' => ['void', 'namespace'=>'string|null', 'qualifiedName'=>'string', 'value'=>'string'], 'DOMElement::setIdAttribute' => ['void', 'qualifiedName'=>'string', 'isId'=>'bool'], 'DOMElement::setIdAttributeNode' => ['void', 'attr'=>'DOMAttr', 'isId'=>'bool'], 'DOMElement::setIdAttributeNS' => ['void', 'namespace'=>'string', 'qualifiedName'=>'string', 'isId'=>'bool'], 'DOMEntityReference::__construct' => ['void', 'name'=>'string'], 'DOMImplementation::__construct' => ['void'], 'DOMImplementation::createDocument' => ['DOMDocument|false', 'namespace='=>'?string', 'qualifiedName='=>'string', 'doctype='=>'?DOMDocumentType'], 'DOMImplementation::createDocumentType' => ['DOMDocumentType|false', 'qualifiedName'=>'string', 'publicId='=>'string', 'systemId='=>'string'], 'DOMImplementation::hasFeature' => ['bool', 'feature'=>'string', 'version'=>'string'], 'DOMNamedNodeMap::count' => ['int'], 'DOMNamedNodeMap::getNamedItem' => ['?DOMNode', 'qualifiedName'=>'string'], 'DOMNamedNodeMap::getNamedItemNS' => ['?DOMNode', 'namespace'=>'?string', 'localName'=>'string'], 'DOMNamedNodeMap::item' => ['?DOMNode', 'index'=>'int'], 'DOMNode::appendChild' => ['DOMNode|false', 'node'=>'DOMNode'], 'DOMNode::C14N' => ['string|false', 'exclusive='=>'bool', 'withComments='=>'bool', 'xpath='=>'?array', 'nsPrefixes='=>'?array'], 'DOMNode::C14NFile' => ['int|false', 'uri'=>'string', 'exclusive='=>'bool', 'withComments='=>'bool', 'xpath='=>'?array', 'nsPrefixes='=>'?array'], 'DOMNode::cloneNode' => ['DOMNode', 'deep='=>'bool'], 'DOMNode::getLineNo' => ['int'], 'DOMNode::getNodePath' => ['?string'], 'DOMNode::hasAttributes' => ['bool'], 'DOMNode::hasChildNodes' => ['bool'], 'DOMNode::insertBefore' => ['DOMNode|false', 'node'=>'DOMNode', 'child='=>'?DOMNode'], 'DOMNode::isDefaultNamespace' => ['bool', 'namespace'=>'string'], 'DOMNode::isSameNode' => ['bool', 'otherNode'=>'DOMNode'], 'DOMNode::isSupported' => ['bool', 'feature'=>'string', 'version'=>'string'], 'DOMNode::lookupNamespaceURI' => ['string|null', 'prefix'=>'string|null'], 'DOMNode::lookupPrefix' => ['string|null', 'namespace'=>'string'], 'DOMNode::normalize' => ['void'], 'DOMNode::removeChild' => ['DOMNode|false', 'child'=>'DOMNode'], 'DOMNode::replaceChild' => ['DOMNode|false', 'node'=>'DOMNode', 'child'=>'DOMNode'], 'DOMNodeList::count' => ['int'], 'DOMNodeList::item' => ['?DOMNode', 'index'=>'int'], 'DOMProcessingInstruction::__construct' => ['void', 'name'=>'string', 'value='=>'string'], 'DOMText::__construct' => ['void', 'data='=>'string'], 'DOMText::isElementContentWhitespace' => ['bool'], 'DOMText::isWhitespaceInElementContent' => ['bool'], 'DOMText::splitText' => ['DOMText', 'offset'=>'int'], 'domxml_new_doc' => ['DomDocument', 'version'=>'string'], 'domxml_open_file' => ['DomDocument', 'filename'=>'string', 'mode='=>'int', 'error='=>'array'], 'domxml_open_mem' => ['DomDocument', 'string'=>'string', 'mode='=>'int', 'error='=>'array'], 'domxml_version' => ['string'], 'domxml_xmltree' => ['DomDocument', 'string'=>'string'], 'domxml_xslt_stylesheet' => ['DomXsltStylesheet', 'xsl_buf'=>'string'], 'domxml_xslt_stylesheet_doc' => ['DomXsltStylesheet', 'xsl_doc'=>'DOMDocument'], 'domxml_xslt_stylesheet_file' => ['DomXsltStylesheet', 'xsl_file'=>'string'], 'domxml_xslt_version' => ['int'], 'DOMXPath::__construct' => ['void', 'document'=>'DOMDocument', 'registerNodeNS='=>'bool'], 'DOMXPath::evaluate' => ['mixed', 'expression'=>'string', 'contextNode='=>'?DOMNode', 'registerNodeNS='=>'bool'], 'DOMXPath::query' => ['DOMNodeList|false', 'expression'=>'string', 'contextNode='=>'?DOMNode', 'registerNodeNS='=>'bool'], 'DOMXPath::registerNamespace' => ['bool', 'prefix'=>'string', 'namespace'=>'string'], 'DOMXPath::registerPhpFunctions' => ['void', 'restrict='=>'array|string|null'], 'DomXsltStylesheet::process' => ['DomDocument', 'xml_doc'=>'DOMDocument', 'xslt_params='=>'array', 'is_xpath_param='=>'bool', 'profile_filename='=>'string'], 'DomXsltStylesheet::result_dump_file' => ['string', 'xmldoc'=>'DOMDocument', 'filename'=>'string'], 'DomXsltStylesheet::result_dump_mem' => ['string', 'xmldoc'=>'DOMDocument'], 'DOTNET::__call' => ['mixed', 'name'=>'string', 'args'=>''], 'DOTNET::__construct' => ['void', 'assembly_name'=>'string', 'datatype_name'=>'string', 'codepage='=>'int'], 'DOTNET::__get' => ['mixed', 'name'=>'string'], 'DOTNET::__set' => ['void', 'name'=>'string', 'value'=>''], 'dotnet_load' => ['int', 'assembly_name'=>'string', 'datatype_name='=>'string', 'codepage='=>'int'], 'doubleval' => ['float', 'value'=>'mixed'], 'Ds\Collection::clear' => ['void'], 'Ds\Collection::copy' => ['Ds\Collection'], 'Ds\Collection::isEmpty' => ['bool'], 'Ds\Collection::toArray' => ['array'], 'Ds\Deque::__construct' => ['void', 'values='=>'mixed'], 'Ds\Deque::allocate' => ['void', 'capacity'=>'int'], 'Ds\Deque::apply' => ['void', 'callback'=>'callable'], 'Ds\Deque::capacity' => ['int'], 'Ds\Deque::clear' => ['void'], 'Ds\Deque::contains' => ['bool', '...values='=>'mixed'], 'Ds\Deque::copy' => ['Ds\Deque'], 'Ds\Deque::count' => ['int'], 'Ds\Deque::filter' => ['Ds\Deque', 'callback='=>'callable'], 'Ds\Deque::find' => ['mixed', 'value'=>'mixed'], 'Ds\Deque::first' => ['mixed'], 'Ds\Deque::get' => ['void', 'index'=>'int'], 'Ds\Deque::insert' => ['void', 'index'=>'int', '...values='=>'mixed'], 'Ds\Deque::isEmpty' => ['bool'], 'Ds\Deque::join' => ['string', 'glue='=>'string'], 'Ds\Deque::jsonSerialize' => ['array'], 'Ds\Deque::last' => ['mixed'], 'Ds\Deque::map' => ['Ds\Deque', 'callback'=>'callable'], 'Ds\Deque::merge' => ['Ds\Deque', 'values'=>'mixed'], 'Ds\Deque::pop' => ['mixed'], 'Ds\Deque::push' => ['void', '...values='=>'mixed'], 'Ds\Deque::reduce' => ['mixed', 'callback'=>'callable', 'initial='=>'mixed'], 'Ds\Deque::remove' => ['mixed', 'index'=>'int'], 'Ds\Deque::reverse' => ['void'], 'Ds\Deque::reversed' => ['Ds\Deque'], 'Ds\Deque::rotate' => ['void', 'rotations'=>'int'], 'Ds\Deque::set' => ['void', 'index'=>'int', 'value'=>'mixed'], 'Ds\Deque::shift' => ['mixed'], 'Ds\Deque::slice' => ['Ds\Deque', 'index'=>'int', 'length='=>'?int'], 'Ds\Deque::sort' => ['void', 'comparator='=>'callable'], 'Ds\Deque::sorted' => ['Ds\Deque', 'comparator='=>'callable'], 'Ds\Deque::sum' => ['int|float'], 'Ds\Deque::toArray' => ['array'], 'Ds\Deque::unshift' => ['void', '...values='=>'mixed'], 'Ds\Hashable::equals' => ['bool', 'object'=>'mixed'], 'Ds\Hashable::hash' => ['mixed'], 'Ds\Map::__construct' => ['void', 'values='=>'mixed'], 'Ds\Map::allocate' => ['void', 'capacity'=>'int'], 'Ds\Map::apply' => ['void', 'callback'=>'callable'], 'Ds\Map::capacity' => ['int'], 'Ds\Map::clear' => ['void'], 'Ds\Map::copy' => ['Ds\Map'], 'Ds\Map::count' => ['int'], 'Ds\Map::diff' => ['Ds\Map', 'map'=>'Ds\Map'], 'Ds\Map::filter' => ['Ds\Map', 'callback='=>'callable'], 'Ds\Map::first' => ['Ds\Pair'], 'Ds\Map::get' => ['mixed', 'key'=>'mixed', 'default='=>'mixed'], 'Ds\Map::hasKey' => ['bool', 'key'=>'mixed'], 'Ds\Map::hasValue' => ['bool', 'value'=>'mixed'], 'Ds\Map::intersect' => ['Ds\Map', 'map'=>'Ds\Map'], 'Ds\Map::isEmpty' => ['bool'], 'Ds\Map::jsonSerialize' => ['array'], 'Ds\Map::keys' => ['Ds\Set'], 'Ds\Map::ksort' => ['void', 'comparator='=>'callable'], 'Ds\Map::ksorted' => ['Ds\Map', 'comparator='=>'callable'], 'Ds\Map::last' => ['Ds\Pair'], 'Ds\Map::map' => ['Ds\Map', 'callback'=>'callable'], 'Ds\Map::merge' => ['Ds\Map', 'values'=>'mixed'], 'Ds\Map::pairs' => ['Ds\Sequence'], 'Ds\Map::put' => ['void', 'key'=>'mixed', 'value'=>'mixed'], 'Ds\Map::putAll' => ['void', 'values'=>'mixed'], 'Ds\Map::reduce' => ['mixed', 'callback'=>'callable', 'initial='=>'mixed'], 'Ds\Map::remove' => ['mixed', 'key'=>'mixed', 'default='=>'mixed'], 'Ds\Map::reverse' => ['void'], 'Ds\Map::reversed' => ['Ds\Map'], 'Ds\Map::skip' => ['Ds\Pair', 'position'=>'int'], 'Ds\Map::slice' => ['Ds\Map', 'index'=>'int', 'length='=>'?int'], 'Ds\Map::sort' => ['void', 'comparator='=>'callable'], 'Ds\Map::sorted' => ['Ds\Map', 'comparator='=>'callable'], 'Ds\Map::sum' => ['int|float'], 'Ds\Map::toArray' => ['array'], 'Ds\Map::union' => ['Ds\Map', 'map'=>'Ds\Map'], 'Ds\Map::values' => ['Ds\Sequence'], 'Ds\Map::xor' => ['Ds\Map', 'map'=>'Ds\Map'], 'Ds\Pair::__construct' => ['void', 'key='=>'mixed', 'value='=>'mixed'], 'Ds\Pair::clear' => ['void'], 'Ds\Pair::copy' => ['Ds\Pair'], 'Ds\Pair::isEmpty' => ['bool'], 'Ds\Pair::jsonSerialize' => ['array'], 'Ds\Pair::toArray' => ['array'], 'Ds\PriorityQueue::__construct' => ['void'], 'Ds\PriorityQueue::allocate' => ['void', 'capacity'=>'int'], 'Ds\PriorityQueue::capacity' => ['int'], 'Ds\PriorityQueue::clear' => ['void'], 'Ds\PriorityQueue::copy' => ['Ds\PriorityQueue'], 'Ds\PriorityQueue::count' => ['int'], 'Ds\PriorityQueue::isEmpty' => ['bool'], 'Ds\PriorityQueue::jsonSerialize' => ['array'], 'Ds\PriorityQueue::peek' => ['mixed'], 'Ds\PriorityQueue::pop' => ['mixed'], 'Ds\PriorityQueue::push' => ['void', 'value'=>'mixed', 'priority'=>'int'], 'Ds\PriorityQueue::toArray' => ['array'], 'Ds\Queue::__construct' => ['void', 'values='=>'mixed'], 'Ds\Queue::allocate' => ['void', 'capacity'=>'int'], 'Ds\Queue::capacity' => ['int'], 'Ds\Queue::clear' => ['void'], 'Ds\Queue::copy' => ['Ds\Queue'], 'Ds\Queue::count' => ['int'], 'Ds\Queue::isEmpty' => ['bool'], 'Ds\Queue::jsonSerialize' => ['array'], 'Ds\Queue::peek' => ['mixed'], 'Ds\Queue::pop' => ['mixed'], 'Ds\Queue::push' => ['void', '...values='=>'mixed'], 'Ds\Queue::toArray' => ['array'], 'Ds\Sequence::allocate' => ['void', 'capacity'=>'int'], 'Ds\Sequence::apply' => ['void', 'callback'=>'callable'], 'Ds\Sequence::capacity' => ['int'], 'Ds\Sequence::contains' => ['bool', '...values='=>'mixed'], 'Ds\Sequence::filter' => ['Ds\Sequence', 'callback='=>'callable'], 'Ds\Sequence::find' => ['mixed', 'value'=>'mixed'], 'Ds\Sequence::first' => ['mixed'], 'Ds\Sequence::get' => ['mixed', 'index'=>'int'], 'Ds\Sequence::insert' => ['void', 'index'=>'int', '...values='=>'mixed'], 'Ds\Sequence::join' => ['string', 'glue='=>'string'], 'Ds\Sequence::last' => ['void'], 'Ds\Sequence::map' => ['Ds\Sequence', 'callback'=>'callable'], 'Ds\Sequence::merge' => ['Ds\Sequence', 'values'=>'mixed'], 'Ds\Sequence::pop' => ['mixed'], 'Ds\Sequence::push' => ['void', '...values='=>'mixed'], 'Ds\Sequence::reduce' => ['mixed', 'callback'=>'callable', 'initial='=>'mixed'], 'Ds\Sequence::remove' => ['mixed', 'index'=>'int'], 'Ds\Sequence::reverse' => ['void'], 'Ds\Sequence::reversed' => ['Ds\Sequence'], 'Ds\Sequence::rotate' => ['void', 'rotations'=>'int'], 'Ds\Sequence::set' => ['void', 'index'=>'int', 'value'=>'mixed'], 'Ds\Sequence::shift' => ['mixed'], 'Ds\Sequence::slice' => ['Ds\Sequence', 'index'=>'int', 'length='=>'?int'], 'Ds\Sequence::sort' => ['void', 'comparator='=>'callable'], 'Ds\Sequence::sorted' => ['Ds\Sequence', 'comparator='=>'callable'], 'Ds\Sequence::sum' => ['int|float'], 'Ds\Sequence::unshift' => ['void', '...values='=>'mixed'], 'Ds\Set::__construct' => ['void', 'values='=>'mixed'], 'Ds\Set::add' => ['void', '...values='=>'mixed'], 'Ds\Set::allocate' => ['void', 'capacity'=>'int'], 'Ds\Set::capacity' => ['int'], 'Ds\Set::clear' => ['void'], 'Ds\Set::contains' => ['bool', '...values='=>'mixed'], 'Ds\Set::copy' => ['Ds\Set'], 'Ds\Set::count' => ['int'], 'Ds\Set::diff' => ['Ds\Set', 'set'=>'Ds\Set'], 'Ds\Set::filter' => ['Ds\Set', 'callback='=>'callable'], 'Ds\Set::first' => ['mixed'], 'Ds\Set::get' => ['mixed', 'index'=>'int'], 'Ds\Set::intersect' => ['Ds\Set', 'set'=>'Ds\Set'], 'Ds\Set::isEmpty' => ['bool'], 'Ds\Set::join' => ['string', 'glue='=>'string'], 'Ds\Set::jsonSerialize' => ['array'], 'Ds\Set::last' => ['mixed'], 'Ds\Set::merge' => ['Ds\Set', 'values'=>'mixed'], 'Ds\Set::reduce' => ['mixed', 'callback'=>'callable', 'initial='=>'mixed'], 'Ds\Set::remove' => ['void', '...values='=>'mixed'], 'Ds\Set::reverse' => ['void'], 'Ds\Set::reversed' => ['Ds\Set'], 'Ds\Set::slice' => ['Ds\Set', 'index'=>'int', 'length='=>'?int'], 'Ds\Set::sort' => ['void', 'comparator='=>'callable'], 'Ds\Set::sorted' => ['Ds\Set', 'comparator='=>'callable'], 'Ds\Set::sum' => ['int|float'], 'Ds\Set::toArray' => ['array'], 'Ds\Set::union' => ['Ds\Set', 'set'=>'Ds\Set'], 'Ds\Set::xor' => ['Ds\Set', 'set'=>'Ds\Set'], 'Ds\Stack::__construct' => ['void', 'values='=>'mixed'], 'Ds\Stack::allocate' => ['void', 'capacity'=>'int'], 'Ds\Stack::capacity' => ['int'], 'Ds\Stack::clear' => ['void'], 'Ds\Stack::copy' => ['Ds\Stack'], 'Ds\Stack::count' => ['int'], 'Ds\Stack::isEmpty' => ['bool'], 'Ds\Stack::jsonSerialize' => ['array'], 'Ds\Stack::peek' => ['mixed'], 'Ds\Stack::pop' => ['mixed'], 'Ds\Stack::push' => ['void', '...values='=>'mixed'], 'Ds\Stack::toArray' => ['array'], 'Ds\Vector::__construct' => ['void', 'values='=>'mixed'], 'Ds\Vector::allocate' => ['void', 'capacity'=>'int'], 'Ds\Vector::apply' => ['void', 'callback'=>'callable'], 'Ds\Vector::capacity' => ['int'], 'Ds\Vector::clear' => ['void'], 'Ds\Vector::contains' => ['bool', '...values='=>'mixed'], 'Ds\Vector::copy' => ['Ds\Vector'], 'Ds\Vector::count' => ['int'], 'Ds\Vector::filter' => ['Ds\Vector', 'callback='=>'callable'], 'Ds\Vector::find' => ['mixed', 'value'=>'mixed'], 'Ds\Vector::first' => ['mixed'], 'Ds\Vector::get' => ['mixed', 'index'=>'int'], 'Ds\Vector::insert' => ['void', 'index'=>'int', '...values='=>'mixed'], 'Ds\Vector::isEmpty' => ['bool'], 'Ds\Vector::join' => ['string', 'glue='=>'string'], 'Ds\Vector::jsonSerialize' => ['array'], 'Ds\Vector::last' => ['mixed'], 'Ds\Vector::map' => ['Ds\Vector', 'callback'=>'callable'], 'Ds\Vector::merge' => ['Ds\Vector', 'values'=>'mixed'], 'Ds\Vector::pop' => ['mixed'], 'Ds\Vector::push' => ['void', '...values='=>'mixed'], 'Ds\Vector::reduce' => ['mixed', 'callback'=>'callable', 'initial='=>'mixed'], 'Ds\Vector::remove' => ['mixed', 'index'=>'int'], 'Ds\Vector::reverse' => ['void'], 'Ds\Vector::reversed' => ['Ds\Vector'], 'Ds\Vector::rotate' => ['void', 'rotations'=>'int'], 'Ds\Vector::set' => ['void', 'index'=>'int', 'value'=>'mixed'], 'Ds\Vector::shift' => ['mixed'], 'Ds\Vector::slice' => ['Ds\Vector', 'index'=>'int', 'length='=>'?int'], 'Ds\Vector::sort' => ['void', 'comparator='=>'callable'], 'Ds\Vector::sorted' => ['Ds\Vector', 'comparator='=>'callable'], 'Ds\Vector::sum' => ['int|float'], 'Ds\Vector::toArray' => ['array'], 'Ds\Vector::unshift' => ['void', '...values='=>'mixed'], 'easter_date' => ['int', 'year='=>'?int', 'mode='=>'int'], 'easter_days' => ['int', 'year='=>'?int', 'mode='=>'int'], 'echo' => ['void', 'arg1'=>'string', '...args='=>'string'], 'eio_busy' => ['resource', 'delay'=>'int', 'pri='=>'int', 'callback='=>'callable', 'data='=>'mixed'], 'eio_cancel' => ['void', 'req'=>'resource'], 'eio_chmod' => ['resource', 'path'=>'string', 'mode'=>'int', 'pri='=>'int', 'callback='=>'callable', 'data='=>'mixed'], 'eio_chown' => ['resource', 'path'=>'string', 'uid'=>'int', 'gid='=>'int', 'pri='=>'int', 'callback='=>'callable', 'data='=>'mixed'], 'eio_close' => ['resource', 'fd'=>'mixed', 'pri='=>'int', 'callback='=>'callable', 'data='=>'mixed'], 'eio_custom' => ['resource', 'execute'=>'callable', 'pri'=>'int', 'callback'=>'callable', 'data='=>'mixed'], 'eio_dup2' => ['resource', 'fd'=>'mixed', 'fd2'=>'mixed', 'pri='=>'int', 'callback='=>'callable', 'data='=>'mixed'], 'eio_event_loop' => ['bool'], 'eio_fallocate' => ['resource', 'fd'=>'mixed', 'mode'=>'int', 'offset'=>'int', 'length'=>'int', 'pri='=>'int', 'callback='=>'callable', 'data='=>'mixed'], 'eio_fchmod' => ['resource', 'fd'=>'mixed', 'mode'=>'int', 'pri='=>'int', 'callback='=>'callable', 'data='=>'mixed'], 'eio_fchown' => ['resource', 'fd'=>'mixed', 'uid'=>'int', 'gid='=>'int', 'pri='=>'int', 'callback='=>'callable', 'data='=>'mixed'], 'eio_fdatasync' => ['resource', 'fd'=>'mixed', 'pri='=>'int', 'callback='=>'callable', 'data='=>'mixed'], 'eio_fstat' => ['resource', 'fd'=>'mixed', 'pri'=>'int', 'callback'=>'callable', 'data='=>'mixed'], 'eio_fstatvfs' => ['resource', 'fd'=>'mixed', 'pri'=>'int', 'callback'=>'callable', 'data='=>'mixed'], 'eio_fsync' => ['resource', 'fd'=>'mixed', 'pri='=>'int', 'callback='=>'callable', 'data='=>'mixed'], 'eio_ftruncate' => ['resource', 'fd'=>'mixed', 'offset='=>'int', 'pri='=>'int', 'callback='=>'callable', 'data='=>'mixed'], 'eio_futime' => ['resource', 'fd'=>'mixed', 'atime'=>'float', 'mtime'=>'float', 'pri='=>'int', 'callback='=>'callable', 'data='=>'mixed'], 'eio_get_event_stream' => ['mixed'], 'eio_get_last_error' => ['string', 'req'=>'resource'], 'eio_grp' => ['resource', 'callback'=>'callable', 'data='=>'string'], 'eio_grp_add' => ['void', 'grp'=>'resource', 'req'=>'resource'], 'eio_grp_cancel' => ['void', 'grp'=>'resource'], 'eio_grp_limit' => ['void', 'grp'=>'resource', 'limit'=>'int'], 'eio_init' => ['void'], 'eio_link' => ['resource', 'path'=>'string', 'new_path'=>'string', 'pri='=>'int', 'callback='=>'callable', 'data='=>'mixed'], 'eio_lstat' => ['resource', 'path'=>'string', 'pri'=>'int', 'callback'=>'callable', 'data='=>'mixed'], 'eio_mkdir' => ['resource', 'path'=>'string', 'mode'=>'int', 'pri='=>'int', 'callback='=>'callable', 'data='=>'mixed'], 'eio_mknod' => ['resource', 'path'=>'string', 'mode'=>'int', 'dev'=>'int', 'pri='=>'int', 'callback='=>'callable', 'data='=>'mixed'], 'eio_nop' => ['resource', 'pri='=>'int', 'callback='=>'callable', 'data='=>'mixed'], 'eio_npending' => ['int'], 'eio_nready' => ['int'], 'eio_nreqs' => ['int'], 'eio_nthreads' => ['int'], 'eio_open' => ['resource', 'path'=>'string', 'flags'=>'int', 'mode'=>'int', 'pri'=>'int', 'callback'=>'callable', 'data='=>'mixed'], 'eio_poll' => ['int'], 'eio_read' => ['resource', 'fd'=>'mixed', 'length'=>'int', 'offset'=>'int', 'pri'=>'int', 'callback'=>'callable', 'data='=>'mixed'], 'eio_readahead' => ['resource', 'fd'=>'mixed', 'offset'=>'int', 'length'=>'int', 'pri='=>'int', 'callback='=>'callable', 'data='=>'mixed'], 'eio_readdir' => ['resource', 'path'=>'string', 'flags'=>'int', 'pri'=>'int', 'callback'=>'callable', 'data='=>'string'], 'eio_readlink' => ['resource', 'path'=>'string', 'pri'=>'int', 'callback'=>'callable', 'data='=>'string'], 'eio_realpath' => ['resource', 'path'=>'string', 'pri'=>'int', 'callback'=>'callable', 'data='=>'string'], 'eio_rename' => ['resource', 'path'=>'string', 'new_path'=>'string', 'pri='=>'int', 'callback='=>'callable', 'data='=>'mixed'], 'eio_rmdir' => ['resource', 'path'=>'string', 'pri='=>'int', 'callback='=>'callable', 'data='=>'mixed'], 'eio_seek' => ['resource', 'fd'=>'mixed', 'offset'=>'int', 'whence'=>'int', 'pri='=>'int', 'callback='=>'callable', 'data='=>'mixed'], 'eio_sendfile' => ['resource', 'out_fd'=>'mixed', 'in_fd'=>'mixed', 'offset'=>'int', 'length'=>'int', 'pri='=>'int', 'callback='=>'callable', 'data='=>'string'], 'eio_set_max_idle' => ['void', 'nthreads'=>'int'], 'eio_set_max_parallel' => ['void', 'nthreads'=>'int'], 'eio_set_max_poll_reqs' => ['void', 'nreqs'=>'int'], 'eio_set_max_poll_time' => ['void', 'nseconds'=>'float'], 'eio_set_min_parallel' => ['void', 'nthreads'=>'string'], 'eio_stat' => ['resource', 'path'=>'string', 'pri'=>'int', 'callback'=>'callable', 'data='=>'mixed'], 'eio_statvfs' => ['resource', 'path'=>'string', 'pri'=>'int', 'callback'=>'callable', 'data='=>'mixed'], 'eio_symlink' => ['resource', 'path'=>'string', 'new_path'=>'string', 'pri='=>'int', 'callback='=>'callable', 'data='=>'mixed'], 'eio_sync' => ['resource', 'pri='=>'int', 'callback='=>'callable', 'data='=>'mixed'], 'eio_sync_file_range' => ['resource', 'fd'=>'mixed', 'offset'=>'int', 'nbytes'=>'int', 'flags'=>'int', 'pri='=>'int', 'callback='=>'callable', 'data='=>'mixed'], 'eio_syncfs' => ['resource', 'fd'=>'mixed', 'pri='=>'int', 'callback='=>'callable', 'data='=>'mixed'], 'eio_truncate' => ['resource', 'path'=>'string', 'offset='=>'int', 'pri='=>'int', 'callback='=>'callable', 'data='=>'mixed'], 'eio_unlink' => ['resource', 'path'=>'string', 'pri='=>'int', 'callback='=>'callable', 'data='=>'mixed'], 'eio_utime' => ['resource', 'path'=>'string', 'atime'=>'float', 'mtime'=>'float', 'pri='=>'int', 'callback='=>'callable', 'data='=>'mixed'], 'eio_write' => ['resource', 'fd'=>'mixed', 'string'=>'string', 'length='=>'int', 'offset='=>'int', 'pri='=>'int', 'callback='=>'callable', 'data='=>'mixed'], 'empty' => ['bool', 'value'=>'mixed'], 'EmptyIterator::current' => ['never'], 'EmptyIterator::key' => ['never'], 'EmptyIterator::next' => ['void'], 'EmptyIterator::rewind' => ['void'], 'EmptyIterator::valid' => ['false'], 'enchant_broker_describe' => ['array', 'broker'=>'EnchantBroker'], 'enchant_broker_dict_exists' => ['bool', 'broker'=>'EnchantBroker', 'tag'=>'string'], 'enchant_broker_free' => ['bool', 'broker'=>'EnchantBroker'], 'enchant_broker_free_dict' => ['bool', 'dictionary'=>'EnchantBroker'], 'enchant_broker_get_dict_path' => ['string', 'broker'=>'EnchantBroker', 'type'=>'int'], 'enchant_broker_get_error' => ['string|false', 'broker'=>'EnchantBroker'], 'enchant_broker_init' => ['EnchantBroker|false'], 'enchant_broker_list_dicts' => ['array', 'broker'=>'EnchantBroker'], 'enchant_broker_request_dict' => ['EnchantDictionary|false', 'broker'=>'EnchantBroker', 'tag'=>'string'], 'enchant_broker_request_pwl_dict' => ['EnchantDictionary|false', 'broker'=>'EnchantBroker', 'filename'=>'string'], 'enchant_broker_set_dict_path' => ['bool', 'broker'=>'EnchantBroker', 'type'=>'int', 'path'=>'string'], 'enchant_broker_set_ordering' => ['bool', 'broker'=>'EnchantBroker', 'tag'=>'string', 'ordering'=>'string'], 'enchant_dict_add_to_personal' => ['void', 'dictionary'=>'EnchantDictionary', 'word'=>'string'], 'enchant_dict_add_to_session' => ['void', 'dictionary'=>'EnchantDictionary', 'word'=>'string'], 'enchant_dict_check' => ['bool', 'dictionary'=>'EnchantDictionary', 'word'=>'string'], 'enchant_dict_describe' => ['array', 'dictionary'=>'EnchantDictionary'], 'enchant_dict_get_error' => ['string', 'dictionary'=>'EnchantDictionary'], 'enchant_dict_is_in_session' => ['bool', 'dictionary'=>'EnchantDictionary', 'word'=>'string'], 'enchant_dict_quick_check' => ['bool', 'dictionary'=>'EnchantDictionary', 'word'=>'string', '&w_suggestions='=>'array'], 'enchant_dict_store_replacement' => ['void', 'dictionary'=>'EnchantDictionary', 'misspelled'=>'string', 'correct'=>'string'], 'enchant_dict_suggest' => ['array', 'dictionary'=>'EnchantDictionary', 'word'=>'string'], 'end' => ['mixed|false', '&r_array'=>'array|object'], 'enum_exists' => ['bool', 'enum' => 'string', 'autoload=' => 'bool'], 'Error::__clone' => ['void'], 'Error::__construct' => ['void', 'message='=>'string', 'code='=>'int', 'previous='=>'?Throwable'], 'Error::__toString' => ['string'], 'Error::getCode' => ['int'], 'Error::getFile' => ['string'], 'Error::getLine' => ['int'], 'Error::getMessage' => ['string'], 'Error::getPrevious' => ['?Throwable'], 'Error::getTrace' => ['list\',args?:array}>'], 'Error::getTraceAsString' => ['string'], 'error_clear_last' => ['void'], 'error_get_last' => ['?array{type:int,message:string,file:string,line:int}'], 'error_log' => ['bool', 'message'=>'string', 'message_type='=>'int', 'destination='=>'?string', 'additional_headers='=>'?string'], 'error_reporting' => ['int', 'error_level='=>'?int'], 'ErrorException::__construct' => ['void', 'message='=>'string', 'code='=>'int', 'severity='=>'int', 'filename='=>'?string', 'line='=>'?int', 'previous='=>'?Throwable'], 'ErrorException::__toString' => ['string'], 'ErrorException::getCode' => ['int'], 'ErrorException::getFile' => ['string'], 'ErrorException::getLine' => ['int'], 'ErrorException::getMessage' => ['string'], 'ErrorException::getPrevious' => ['?Throwable'], 'ErrorException::getSeverity' => ['int'], 'ErrorException::getTrace' => ['list\',args?:array}>'], 'ErrorException::getTraceAsString' => ['string'], 'escapeshellarg' => ['string', 'arg'=>'string'], 'escapeshellcmd' => ['string', 'command'=>'string'], 'Ev::backend' => ['int'], 'Ev::depth' => ['int'], 'Ev::embeddableBackends' => ['int'], 'Ev::feedSignal' => ['void', 'signum'=>'int'], 'Ev::feedSignalEvent' => ['void', 'signum'=>'int'], 'Ev::iteration' => ['int'], 'Ev::now' => ['float'], 'Ev::nowUpdate' => ['void'], 'Ev::recommendedBackends' => ['int'], 'Ev::resume' => ['void'], 'Ev::run' => ['void', 'flags='=>'int'], 'Ev::sleep' => ['void', 'seconds'=>'float'], 'Ev::stop' => ['void', 'how='=>'int'], 'Ev::supportedBackends' => ['int'], 'Ev::suspend' => ['void'], 'Ev::time' => ['float'], 'Ev::verify' => ['void'], 'eval' => ['mixed', 'code_str'=>'string'], 'EvCheck::__construct' => ['void', 'callback'=>'callable', 'data='=>'mixed', 'priority='=>'int'], 'EvCheck::clear' => ['int'], 'EvCheck::createStopped' => ['EvCheck', 'callback'=>'callable', 'data='=>'mixed', 'priority='=>'int'], 'EvCheck::feed' => ['void', 'events'=>'int'], 'EvCheck::getLoop' => ['EvLoop'], 'EvCheck::invoke' => ['void', 'events'=>'int'], 'EvCheck::keepAlive' => ['void', 'value'=>'bool'], 'EvCheck::setCallback' => ['void', 'callback'=>'callable'], 'EvCheck::start' => ['void'], 'EvCheck::stop' => ['void'], 'EvChild::__construct' => ['void', 'pid'=>'int', 'trace'=>'bool', 'callback'=>'callable', 'data='=>'mixed', 'priority='=>'int'], 'EvChild::clear' => ['int'], 'EvChild::createStopped' => ['EvChild', 'pid'=>'int', 'trace'=>'bool', 'callback'=>'callable', 'data='=>'mixed', 'priority='=>'int'], 'EvChild::feed' => ['void', 'events'=>'int'], 'EvChild::getLoop' => ['EvLoop'], 'EvChild::invoke' => ['void', 'events'=>'int'], 'EvChild::keepAlive' => ['void', 'value'=>'bool'], 'EvChild::set' => ['void', 'pid'=>'int', 'trace'=>'bool'], 'EvChild::setCallback' => ['void', 'callback'=>'callable'], 'EvChild::start' => ['void'], 'EvChild::stop' => ['void'], 'EvEmbed::__construct' => ['void', 'other'=>'object', 'callback='=>'callable', 'data='=>'mixed', 'priority='=>'int'], 'EvEmbed::clear' => ['int'], 'EvEmbed::createStopped' => ['EvEmbed', 'other'=>'object', 'callback='=>'callable', 'data='=>'mixed', 'priority='=>'int'], 'EvEmbed::feed' => ['void', 'events'=>'int'], 'EvEmbed::getLoop' => ['EvLoop'], 'EvEmbed::invoke' => ['void', 'events'=>'int'], 'EvEmbed::keepAlive' => ['void', 'value'=>'bool'], 'EvEmbed::set' => ['void', 'other'=>'object'], 'EvEmbed::setCallback' => ['void', 'callback'=>'callable'], 'EvEmbed::start' => ['void'], 'EvEmbed::stop' => ['void'], 'EvEmbed::sweep' => ['void'], 'Event::__construct' => ['void', 'base'=>'EventBase', 'fd'=>'mixed', 'what'=>'int', 'cb'=>'callable', 'arg='=>'mixed'], 'Event::add' => ['bool', 'timeout='=>'float'], 'Event::addSignal' => ['bool', 'timeout='=>'float'], 'Event::addTimer' => ['bool', 'timeout='=>'float'], 'Event::del' => ['bool'], 'Event::delSignal' => ['bool'], 'Event::delTimer' => ['bool'], 'Event::free' => ['void'], 'Event::getSupportedMethods' => ['array'], 'Event::pending' => ['bool', 'flags'=>'int'], 'Event::set' => ['bool', 'base'=>'EventBase', 'fd'=>'mixed', 'what='=>'int', 'cb='=>'callable', 'arg='=>'mixed'], 'Event::setPriority' => ['bool', 'priority'=>'int'], 'Event::setTimer' => ['bool', 'base'=>'EventBase', 'cb'=>'callable', 'arg='=>'mixed'], 'Event::signal' => ['Event', 'base'=>'EventBase', 'signum'=>'int', 'cb'=>'callable', 'arg='=>'mixed'], 'Event::timer' => ['Event', 'base'=>'EventBase', 'cb'=>'callable', 'arg='=>'mixed'], 'event_add' => ['bool', 'event'=>'resource', 'timeout='=>'int'], 'event_base_free' => ['void', 'event_base'=>'resource'], 'event_base_loop' => ['int', 'event_base'=>'resource', 'flags='=>'int'], 'event_base_loopbreak' => ['bool', 'event_base'=>'resource'], 'event_base_loopexit' => ['bool', 'event_base'=>'resource', 'timeout='=>'int'], 'event_base_new' => ['resource|false'], 'event_base_priority_init' => ['bool', 'event_base'=>'resource', 'npriorities'=>'int'], 'event_base_reinit' => ['bool', 'event_base'=>'resource'], 'event_base_set' => ['bool', 'event'=>'resource', 'event_base'=>'resource'], 'event_buffer_base_set' => ['bool', 'bevent'=>'resource', 'event_base'=>'resource'], 'event_buffer_disable' => ['bool', 'bevent'=>'resource', 'events'=>'int'], 'event_buffer_enable' => ['bool', 'bevent'=>'resource', 'events'=>'int'], 'event_buffer_fd_set' => ['void', 'bevent'=>'resource', 'fd'=>'resource'], 'event_buffer_free' => ['void', 'bevent'=>'resource'], 'event_buffer_new' => ['resource|false', 'stream'=>'resource', 'readcb'=>'callable|null', 'writecb'=>'callable|null', 'errorcb'=>'callable', 'arg='=>'mixed'], 'event_buffer_priority_set' => ['bool', 'bevent'=>'resource', 'priority'=>'int'], 'event_buffer_read' => ['string', 'bevent'=>'resource', 'data_size'=>'int'], 'event_buffer_set_callback' => ['bool', 'event'=>'resource', 'readcb'=>'mixed', 'writecb'=>'mixed', 'errorcb'=>'mixed', 'arg='=>'mixed'], 'event_buffer_timeout_set' => ['void', 'bevent'=>'resource', 'read_timeout'=>'int', 'write_timeout'=>'int'], 'event_buffer_watermark_set' => ['void', 'bevent'=>'resource', 'events'=>'int', 'lowmark'=>'int', 'highmark'=>'int'], 'event_buffer_write' => ['bool', 'bevent'=>'resource', 'data'=>'string', 'data_size='=>'int'], 'event_del' => ['bool', 'event'=>'resource'], 'event_free' => ['void', 'event'=>'resource'], 'event_new' => ['resource|false'], 'event_priority_set' => ['bool', 'event'=>'resource', 'priority'=>'int'], 'event_set' => ['bool', 'event'=>'resource', 'fd'=>'int|resource', 'events'=>'int', 'callback'=>'callable', 'arg='=>'mixed'], 'event_timer_add' => ['bool', 'event'=>'resource', 'timeout='=>'int'], 'event_timer_del' => ['bool', 'event'=>'resource'], 'event_timer_new' => ['resource|false'], 'event_timer_pending' => ['bool', 'event'=>'resource', 'timeout='=>'int'], 'event_timer_set' => ['bool', 'event'=>'resource', 'callback'=>'callable', 'arg='=>'mixed'], 'EventBase::__construct' => ['void', 'cfg='=>'EventConfig'], 'EventBase::dispatch' => ['void'], 'EventBase::exit' => ['bool', 'timeout='=>'float'], 'EventBase::free' => ['void'], 'EventBase::getFeatures' => ['int'], 'EventBase::getMethod' => ['string', 'cfg='=>'EventConfig'], 'EventBase::getTimeOfDayCached' => ['float'], 'EventBase::gotExit' => ['bool'], 'EventBase::gotStop' => ['bool'], 'EventBase::loop' => ['bool', 'flags='=>'int'], 'EventBase::priorityInit' => ['bool', 'n_priorities'=>'int'], 'EventBase::reInit' => ['bool'], 'EventBase::stop' => ['bool'], 'EventBuffer::__construct' => ['void'], 'EventBuffer::add' => ['bool', 'data'=>'string'], 'EventBuffer::addBuffer' => ['bool', 'buf'=>'EventBuffer'], 'EventBuffer::appendFrom' => ['int', 'buf'=>'EventBuffer', 'length'=>'int'], 'EventBuffer::copyout' => ['int', '&w_data'=>'string', 'max_bytes'=>'int'], 'EventBuffer::drain' => ['bool', 'length'=>'int'], 'EventBuffer::enableLocking' => ['void'], 'EventBuffer::expand' => ['bool', 'length'=>'int'], 'EventBuffer::freeze' => ['bool', 'at_front'=>'bool'], 'EventBuffer::lock' => ['void'], 'EventBuffer::prepend' => ['bool', 'data'=>'string'], 'EventBuffer::prependBuffer' => ['bool', 'buf'=>'EventBuffer'], 'EventBuffer::pullup' => ['string', 'size'=>'int'], 'EventBuffer::read' => ['string', 'max_bytes'=>'int'], 'EventBuffer::readFrom' => ['int', 'fd'=>'mixed', 'howmuch'=>'int'], 'EventBuffer::readLine' => ['string', 'eol_style'=>'int'], 'EventBuffer::search' => ['mixed', 'what'=>'string', 'start='=>'int', 'end='=>'int'], 'EventBuffer::searchEol' => ['mixed', 'start='=>'int', 'eol_style='=>'int'], 'EventBuffer::substr' => ['string', 'start'=>'int', 'length='=>'int'], 'EventBuffer::unfreeze' => ['bool', 'at_front'=>'bool'], 'EventBuffer::unlock' => ['bool'], 'EventBuffer::write' => ['int', 'fd'=>'mixed', 'howmuch='=>'int'], 'EventBufferEvent::__construct' => ['void', 'base'=>'EventBase', 'socket='=>'mixed', 'options='=>'int', 'readcb='=>'callable', 'writecb='=>'callable', 'eventcb='=>'callable'], 'EventBufferEvent::close' => ['void'], 'EventBufferEvent::connect' => ['bool', 'addr'=>'string'], 'EventBufferEvent::connectHost' => ['bool', 'dns_base'=>'EventDnsBase', 'hostname'=>'string', 'port'=>'int', 'family='=>'int'], 'EventBufferEvent::createPair' => ['array', 'base'=>'EventBase', 'options='=>'int'], 'EventBufferEvent::disable' => ['bool', 'events'=>'int'], 'EventBufferEvent::enable' => ['bool', 'events'=>'int'], 'EventBufferEvent::free' => ['void'], 'EventBufferEvent::getDnsErrorString' => ['string'], 'EventBufferEvent::getEnabled' => ['int'], 'EventBufferEvent::getInput' => ['EventBuffer'], 'EventBufferEvent::getOutput' => ['EventBuffer'], 'EventBufferEvent::read' => ['string', 'size'=>'int'], 'EventBufferEvent::readBuffer' => ['bool', 'buf'=>'EventBuffer'], 'EventBufferEvent::setCallbacks' => ['void', 'readcb'=>'callable', 'writecb'=>'callable', 'eventcb'=>'callable', 'arg='=>'string'], 'EventBufferEvent::setPriority' => ['bool', 'priority'=>'int'], 'EventBufferEvent::setTimeouts' => ['bool', 'timeout_read'=>'float', 'timeout_write'=>'float'], 'EventBufferEvent::setWatermark' => ['void', 'events'=>'int', 'lowmark'=>'int', 'highmark'=>'int'], 'EventBufferEvent::sslError' => ['string'], 'EventBufferEvent::sslFilter' => ['EventBufferEvent', 'base'=>'EventBase', 'underlying'=>'EventBufferEvent', 'ctx'=>'EventSslContext', 'state'=>'int', 'options='=>'int'], 'EventBufferEvent::sslGetCipherInfo' => ['string'], 'EventBufferEvent::sslGetCipherName' => ['string'], 'EventBufferEvent::sslGetCipherVersion' => ['string'], 'EventBufferEvent::sslGetProtocol' => ['string'], 'EventBufferEvent::sslRenegotiate' => ['void'], 'EventBufferEvent::sslSocket' => ['EventBufferEvent', 'base'=>'EventBase', 'socket'=>'mixed', 'ctx'=>'EventSslContext', 'state'=>'int', 'options='=>'int'], 'EventBufferEvent::write' => ['bool', 'data'=>'string'], 'EventBufferEvent::writeBuffer' => ['bool', 'buf'=>'EventBuffer'], 'EventConfig::__construct' => ['void'], 'EventConfig::avoidMethod' => ['bool', 'method'=>'string'], 'EventConfig::requireFeatures' => ['bool', 'feature'=>'int'], 'EventConfig::setMaxDispatchInterval' => ['void', 'max_interval'=>'int', 'max_callbacks'=>'int', 'min_priority'=>'int'], 'EventDnsBase::__construct' => ['void', 'base'=>'EventBase', 'initialize'=>'bool'], 'EventDnsBase::addNameserverIp' => ['bool', 'ip'=>'string'], 'EventDnsBase::addSearch' => ['void', 'domain'=>'string'], 'EventDnsBase::clearSearch' => ['void'], 'EventDnsBase::countNameservers' => ['int'], 'EventDnsBase::loadHosts' => ['bool', 'hosts'=>'string'], 'EventDnsBase::parseResolvConf' => ['bool', 'flags'=>'int', 'filename'=>'string'], 'EventDnsBase::setOption' => ['bool', 'option'=>'string', 'value'=>'string'], 'EventDnsBase::setSearchNdots' => ['bool', 'ndots'=>'int'], 'EventHttp::__construct' => ['void', 'base'=>'EventBase', 'ctx='=>'EventSslContext'], 'EventHttp::accept' => ['bool', 'socket'=>'mixed'], 'EventHttp::addServerAlias' => ['bool', 'alias'=>'string'], 'EventHttp::bind' => ['void', 'address'=>'string', 'port'=>'int'], 'EventHttp::removeServerAlias' => ['bool', 'alias'=>'string'], 'EventHttp::setAllowedMethods' => ['void', 'methods'=>'int'], 'EventHttp::setCallback' => ['void', 'path'=>'string', 'cb'=>'string', 'arg='=>'string'], 'EventHttp::setDefaultCallback' => ['void', 'cb'=>'string', 'arg='=>'string'], 'EventHttp::setMaxBodySize' => ['void', 'value'=>'int'], 'EventHttp::setMaxHeadersSize' => ['void', 'value'=>'int'], 'EventHttp::setTimeout' => ['void', 'value'=>'int'], 'EventHttpConnection::__construct' => ['void', 'base'=>'EventBase', 'dns_base'=>'EventDnsBase', 'address'=>'string', 'port'=>'int', 'ctx='=>'EventSslContext'], 'EventHttpConnection::getBase' => ['EventBase'], 'EventHttpConnection::getPeer' => ['void', '&w_address'=>'string', '&w_port'=>'int'], 'EventHttpConnection::makeRequest' => ['bool', 'req'=>'EventHttpRequest', 'type'=>'int', 'uri'=>'string'], 'EventHttpConnection::setCloseCallback' => ['void', 'callback'=>'callable', 'data='=>'mixed'], 'EventHttpConnection::setLocalAddress' => ['void', 'address'=>'string'], 'EventHttpConnection::setLocalPort' => ['void', 'port'=>'int'], 'EventHttpConnection::setMaxBodySize' => ['void', 'max_size'=>'string'], 'EventHttpConnection::setMaxHeadersSize' => ['void', 'max_size'=>'string'], 'EventHttpConnection::setRetries' => ['void', 'retries'=>'int'], 'EventHttpConnection::setTimeout' => ['void', 'timeout'=>'int'], 'EventHttpRequest::__construct' => ['void', 'callback'=>'callable', 'data='=>'mixed'], 'EventHttpRequest::addHeader' => ['bool', 'key'=>'string', 'value'=>'string', 'type'=>'int'], 'EventHttpRequest::cancel' => ['void'], 'EventHttpRequest::clearHeaders' => ['void'], 'EventHttpRequest::closeConnection' => ['void'], 'EventHttpRequest::findHeader' => ['void', 'key'=>'string', 'type'=>'string'], 'EventHttpRequest::free' => ['void'], 'EventHttpRequest::getBufferEvent' => ['EventBufferEvent'], 'EventHttpRequest::getCommand' => ['void'], 'EventHttpRequest::getConnection' => ['EventHttpConnection'], 'EventHttpRequest::getHost' => ['string'], 'EventHttpRequest::getInputBuffer' => ['EventBuffer'], 'EventHttpRequest::getInputHeaders' => ['array'], 'EventHttpRequest::getOutputBuffer' => ['EventBuffer'], 'EventHttpRequest::getOutputHeaders' => ['void'], 'EventHttpRequest::getResponseCode' => ['int'], 'EventHttpRequest::getUri' => ['string'], 'EventHttpRequest::removeHeader' => ['void', 'key'=>'string', 'type'=>'string'], 'EventHttpRequest::sendError' => ['void', 'error'=>'int', 'reason='=>'string'], 'EventHttpRequest::sendReply' => ['void', 'code'=>'int', 'reason'=>'string', 'buf='=>'EventBuffer'], 'EventHttpRequest::sendReplyChunk' => ['void', 'buf'=>'EventBuffer'], 'EventHttpRequest::sendReplyEnd' => ['void'], 'EventHttpRequest::sendReplyStart' => ['void', 'code'=>'int', 'reason'=>'string'], 'EventListener::__construct' => ['void', 'base'=>'EventBase', 'cb'=>'callable', 'data'=>'mixed', 'flags'=>'int', 'backlog'=>'int', 'target'=>'mixed'], 'EventListener::disable' => ['bool'], 'EventListener::enable' => ['bool'], 'EventListener::getBase' => ['void'], 'EventListener::getSocketName' => ['bool', '&w_address'=>'string', '&w_port='=>'mixed'], 'EventListener::setCallback' => ['void', 'cb'=>'callable', 'arg='=>'mixed'], 'EventListener::setErrorCallback' => ['void', 'cb'=>'string'], 'EventSslContext::__construct' => ['void', 'method'=>'string', 'options'=>'string'], 'EventUtil::__construct' => ['void'], 'EventUtil::getLastSocketErrno' => ['int', 'socket='=>'mixed'], 'EventUtil::getLastSocketError' => ['string', 'socket='=>'mixed'], 'EventUtil::getSocketFd' => ['int', 'socket'=>'mixed'], 'EventUtil::getSocketName' => ['bool', 'socket'=>'mixed', '&w_address'=>'string', '&w_port='=>'mixed'], 'EventUtil::setSocketOption' => ['bool', 'socket'=>'mixed', 'level'=>'int', 'optname'=>'int', 'optval'=>'mixed'], 'EventUtil::sslRandPoll' => ['void'], 'EvFork::__construct' => ['void', 'callback'=>'callable', 'data='=>'mixed', 'priority='=>'int'], 'EvFork::clear' => ['int'], 'EvFork::createStopped' => ['EvFork', 'callback'=>'callable', 'data='=>'string', 'priority='=>'string'], 'EvFork::feed' => ['void', 'events'=>'int'], 'EvFork::getLoop' => ['EvLoop'], 'EvFork::invoke' => ['void', 'events'=>'int'], 'EvFork::keepAlive' => ['void', 'value'=>'bool'], 'EvFork::setCallback' => ['void', 'callback'=>'callable'], 'EvFork::start' => ['void'], 'EvFork::stop' => ['void'], 'EvIdle::__construct' => ['void', 'callback'=>'callable', 'data='=>'mixed', 'priority='=>'int'], 'EvIdle::clear' => ['int'], 'EvIdle::createStopped' => ['EvIdle', 'callback'=>'callable', 'data='=>'mixed', 'priority='=>'int'], 'EvIdle::feed' => ['void', 'events'=>'int'], 'EvIdle::getLoop' => ['EvLoop'], 'EvIdle::invoke' => ['void', 'events'=>'int'], 'EvIdle::keepAlive' => ['void', 'value'=>'bool'], 'EvIdle::setCallback' => ['void', 'callback'=>'callable'], 'EvIdle::start' => ['void'], 'EvIdle::stop' => ['void'], 'EvIo::__construct' => ['void', 'fd'=>'mixed', 'events'=>'int', 'callback'=>'callable', 'data='=>'mixed', 'priority='=>'int'], 'EvIo::clear' => ['int'], 'EvIo::createStopped' => ['EvIo', 'fd'=>'resource', 'events'=>'int', 'callback'=>'callable', 'data='=>'mixed', 'priority='=>'int'], 'EvIo::feed' => ['void', 'events'=>'int'], 'EvIo::getLoop' => ['EvLoop'], 'EvIo::invoke' => ['void', 'events'=>'int'], 'EvIo::keepAlive' => ['void', 'value'=>'bool'], 'EvIo::set' => ['void', 'fd'=>'resource', 'events'=>'int'], 'EvIo::setCallback' => ['void', 'callback'=>'callable'], 'EvIo::start' => ['void'], 'EvIo::stop' => ['void'], 'EvLoop::__construct' => ['void', 'flags='=>'int', 'data='=>'mixed', 'io_interval='=>'float', 'timeout_interval='=>'float'], 'EvLoop::backend' => ['int'], 'EvLoop::check' => ['EvCheck', 'callback'=>'callable', 'data='=>'mixed', 'priority='=>'int'], 'EvLoop::child' => ['EvChild', 'pid'=>'int', 'trace'=>'bool', 'callback'=>'callable', 'data='=>'mixed', 'priority='=>'int'], 'EvLoop::defaultLoop' => ['EvLoop', 'flags='=>'int', 'data='=>'mixed', 'io_interval='=>'float', 'timeout_interval='=>'float'], 'EvLoop::embed' => ['EvEmbed', 'other'=>'EvLoop', 'callback='=>'callable', 'data='=>'mixed', 'priority='=>'int'], 'EvLoop::fork' => ['EvFork', 'callback'=>'callable', 'data='=>'mixed', 'priority='=>'int'], 'EvLoop::idle' => ['EvIdle', 'callback'=>'callable', 'data='=>'mixed', 'priority='=>'int'], 'EvLoop::invokePending' => ['void'], 'EvLoop::io' => ['EvIo', 'fd'=>'resource', 'events'=>'int', 'callback'=>'callable', 'data='=>'mixed', 'priority='=>'int'], 'EvLoop::loopFork' => ['void'], 'EvLoop::now' => ['float'], 'EvLoop::nowUpdate' => ['void'], 'EvLoop::periodic' => ['EvPeriodic', 'offset'=>'float', 'interval'=>'float', 'callback'=>'callable', 'data='=>'mixed', 'priority='=>'int'], 'EvLoop::prepare' => ['EvPrepare', 'callback'=>'callable', 'data='=>'mixed', 'priority='=>'int'], 'EvLoop::resume' => ['void'], 'EvLoop::run' => ['void', 'flags='=>'int'], 'EvLoop::signal' => ['EvSignal', 'signum'=>'int', 'callback'=>'callable', 'data='=>'mixed', 'priority='=>'int'], 'EvLoop::stat' => ['EvStat', 'path'=>'string', 'interval'=>'float', 'callback'=>'callable', 'data='=>'mixed', 'priority='=>'int'], 'EvLoop::stop' => ['void', 'how='=>'int'], 'EvLoop::suspend' => ['void'], 'EvLoop::timer' => ['EvTimer', 'after'=>'float', 'repeat'=>'float', 'callback'=>'callable', 'data='=>'mixed', 'priority='=>'int'], 'EvLoop::verify' => ['void'], 'EvPeriodic::__construct' => ['void', 'offset'=>'float', 'interval'=>'string', 'reschedule_cb'=>'callable', 'callback'=>'callable', 'data='=>'mixed', 'priority='=>'int'], 'EvPeriodic::again' => ['void'], 'EvPeriodic::at' => ['float'], 'EvPeriodic::clear' => ['int'], 'EvPeriodic::createStopped' => ['EvPeriodic', 'offset'=>'float', 'interval'=>'float', 'reschedule_cb'=>'callable', 'callback'=>'callable', 'data='=>'mixed', 'priority='=>'int'], 'EvPeriodic::feed' => ['void', 'events'=>'int'], 'EvPeriodic::getLoop' => ['EvLoop'], 'EvPeriodic::invoke' => ['void', 'events'=>'int'], 'EvPeriodic::keepAlive' => ['void', 'value'=>'bool'], 'EvPeriodic::set' => ['void', 'offset'=>'float', 'interval'=>'float'], 'EvPeriodic::setCallback' => ['void', 'callback'=>'callable'], 'EvPeriodic::start' => ['void'], 'EvPeriodic::stop' => ['void'], 'EvPrepare::__construct' => ['void', 'callback'=>'string', 'data='=>'string', 'priority='=>'string'], 'EvPrepare::clear' => ['int'], 'EvPrepare::createStopped' => ['EvPrepare', 'callback'=>'callable', 'data='=>'mixed', 'priority='=>'int'], 'EvPrepare::feed' => ['void', 'events'=>'int'], 'EvPrepare::getLoop' => ['EvLoop'], 'EvPrepare::invoke' => ['void', 'events'=>'int'], 'EvPrepare::keepAlive' => ['void', 'value'=>'bool'], 'EvPrepare::setCallback' => ['void', 'callback'=>'callable'], 'EvPrepare::start' => ['void'], 'EvPrepare::stop' => ['void'], 'EvSignal::__construct' => ['void', 'signum'=>'int', 'callback'=>'callable', 'data='=>'mixed', 'priority='=>'int'], 'EvSignal::clear' => ['int'], 'EvSignal::createStopped' => ['EvSignal', 'signum'=>'int', 'callback'=>'callable', 'data='=>'mixed', 'priority='=>'int'], 'EvSignal::feed' => ['void', 'events'=>'int'], 'EvSignal::getLoop' => ['EvLoop'], 'EvSignal::invoke' => ['void', 'events'=>'int'], 'EvSignal::keepAlive' => ['void', 'value'=>'bool'], 'EvSignal::set' => ['void', 'signum'=>'int'], 'EvSignal::setCallback' => ['void', 'callback'=>'callable'], 'EvSignal::start' => ['void'], 'EvSignal::stop' => ['void'], 'EvStat::__construct' => ['void', 'path'=>'string', 'interval'=>'float', 'callback'=>'callable', 'data='=>'mixed', 'priority='=>'int'], 'EvStat::attr' => ['array'], 'EvStat::clear' => ['int'], 'EvStat::createStopped' => ['EvStat', 'path'=>'string', 'interval'=>'float', 'callback'=>'callable', 'data='=>'mixed', 'priority='=>'int'], 'EvStat::feed' => ['void', 'events'=>'int'], 'EvStat::getLoop' => ['EvLoop'], 'EvStat::invoke' => ['void', 'events'=>'int'], 'EvStat::keepAlive' => ['void', 'value'=>'bool'], 'EvStat::prev' => ['array'], 'EvStat::set' => ['void', 'path'=>'string', 'interval'=>'float'], 'EvStat::setCallback' => ['void', 'callback'=>'callable'], 'EvStat::start' => ['void'], 'EvStat::stat' => ['bool'], 'EvStat::stop' => ['void'], 'EvTimer::__construct' => ['void', 'after'=>'float', 'repeat'=>'float', 'callback'=>'callable', 'data='=>'mixed', 'priority='=>'int'], 'EvTimer::again' => ['void'], 'EvTimer::clear' => ['int'], 'EvTimer::createStopped' => ['EvTimer', 'after'=>'float', 'repeat'=>'float', 'callback'=>'callable', 'data='=>'mixed', 'priority='=>'int'], 'EvTimer::feed' => ['void', 'events'=>'int'], 'EvTimer::getLoop' => ['EvLoop'], 'EvTimer::invoke' => ['void', 'events'=>'int'], 'EvTimer::keepAlive' => ['void', 'value'=>'bool'], 'EvTimer::set' => ['void', 'after'=>'float', 'repeat'=>'float'], 'EvTimer::setCallback' => ['void', 'callback'=>'callable'], 'EvTimer::start' => ['void'], 'EvTimer::stop' => ['void'], 'EvWatcher::__construct' => ['void'], 'EvWatcher::clear' => ['int'], 'EvWatcher::feed' => ['void', 'revents'=>'int'], 'EvWatcher::getLoop' => ['EvLoop'], 'EvWatcher::invoke' => ['void', 'revents'=>'int'], 'EvWatcher::keepalive' => ['bool', 'value='=>'bool'], 'EvWatcher::setCallback' => ['void', 'callback'=>'callable'], 'EvWatcher::start' => ['void'], 'EvWatcher::stop' => ['void'], 'Exception::__clone' => ['void'], 'Exception::__construct' => ['void', 'message='=>'string', 'code='=>'int', 'previous='=>'?Throwable'], 'Exception::__toString' => ['string'], 'Exception::getCode' => ['int|string'], 'Exception::getFile' => ['string'], 'Exception::getLine' => ['int'], 'Exception::getMessage' => ['string'], 'Exception::getPrevious' => ['?Throwable'], 'Exception::getTrace' => ['list\',args?:array}>'], 'Exception::getTraceAsString' => ['string'], 'exec' => ['string|false', 'command'=>'string', '&w_output='=>'array', '&w_result_code='=>'int'], 'exif_imagetype' => ['int|false', 'filename'=>'string'], 'exif_read_data' => ['array|false', 'file'=>'string|resource', 'required_sections='=>'?string', 'as_arrays='=>'bool', 'read_thumbnail='=>'bool'], 'exif_tagname' => ['string|false', 'index'=>'int'], 'exif_thumbnail' => ['string|false', 'file'=>'string', '&w_width='=>'int', '&w_height='=>'int', '&w_image_type='=>'int'], 'exit' => ['', 'status'=>'string|int'], 'exp' => ['float', 'num'=>'float'], 'expect_expectl' => ['int', 'expect'=>'resource', 'cases'=>'array', 'match='=>'array'], 'expect_popen' => ['resource|false', 'command'=>'string'], 'explode' => ['list', 'separator'=>'string', 'string'=>'string', 'limit='=>'int'], 'expm1' => ['float', 'num'=>'float'], 'extension_loaded' => ['bool', 'extension'=>'string'], 'extract' => ['int', '&rw_array'=>'array', 'flags='=>'int', 'prefix='=>'string'], 'ezmlm_hash' => ['int', 'addr'=>'string'], 'fam_cancel_monitor' => ['bool', 'fam'=>'resource', 'fam_monitor'=>'resource'], 'fam_close' => ['void', 'fam'=>'resource'], 'fam_monitor_collection' => ['resource', 'fam'=>'resource', 'dirname'=>'string', 'depth'=>'int', 'mask'=>'string'], 'fam_monitor_directory' => ['resource', 'fam'=>'resource', 'dirname'=>'string'], 'fam_monitor_file' => ['resource', 'fam'=>'resource', 'filename'=>'string'], 'fam_next_event' => ['array', 'fam'=>'resource'], 'fam_open' => ['resource|false', 'appname='=>'string'], 'fam_pending' => ['int', 'fam'=>'resource'], 'fam_resume_monitor' => ['bool', 'fam'=>'resource', 'fam_monitor'=>'resource'], 'fam_suspend_monitor' => ['bool', 'fam'=>'resource', 'fam_monitor'=>'resource'], 'fann_cascadetrain_on_data' => ['bool', 'ann'=>'resource', 'data'=>'resource', 'max_neurons'=>'int', 'neurons_between_reports'=>'int', 'desired_error'=>'float'], 'fann_cascadetrain_on_file' => ['bool', 'ann'=>'resource', 'filename'=>'string', 'max_neurons'=>'int', 'neurons_between_reports'=>'int', 'desired_error'=>'float'], 'fann_clear_scaling_params' => ['bool', 'ann'=>'resource'], 'fann_copy' => ['resource|false', 'ann'=>'resource'], 'fann_create_from_file' => ['resource', 'configuration_file'=>'string'], 'fann_create_shortcut' => ['resource|false', 'num_layers'=>'int', 'num_neurons1'=>'int', 'num_neurons2'=>'int', '...args='=>'int'], 'fann_create_shortcut_array' => ['resource|false', 'num_layers'=>'int', 'layers'=>'array'], 'fann_create_sparse' => ['resource|false', 'connection_rate'=>'float', 'num_layers'=>'int', 'num_neurons1'=>'int', 'num_neurons2'=>'int', '...args='=>'int'], 'fann_create_sparse_array' => ['resource|false', 'connection_rate'=>'float', 'num_layers'=>'int', 'layers'=>'array'], 'fann_create_standard' => ['resource|false', 'num_layers'=>'int', 'num_neurons1'=>'int', 'num_neurons2'=>'int', '...args='=>'int'], 'fann_create_standard_array' => ['resource|false', 'num_layers'=>'int', 'layers'=>'array'], 'fann_create_train' => ['resource', 'num_data'=>'int', 'num_input'=>'int', 'num_output'=>'int'], 'fann_create_train_from_callback' => ['resource', 'num_data'=>'int', 'num_input'=>'int', 'num_output'=>'int', 'user_function'=>'callable'], 'fann_descale_input' => ['bool', 'ann'=>'resource', 'input_vector'=>'array'], 'fann_descale_output' => ['bool', 'ann'=>'resource', 'output_vector'=>'array'], 'fann_descale_train' => ['bool', 'ann'=>'resource', 'train_data'=>'resource'], 'fann_destroy' => ['bool', 'ann'=>'resource'], 'fann_destroy_train' => ['bool', 'train_data'=>'resource'], 'fann_duplicate_train_data' => ['resource', 'data'=>'resource'], 'fann_get_activation_function' => ['int|false', 'ann'=>'resource', 'layer'=>'int', 'neuron'=>'int'], 'fann_get_activation_steepness' => ['float|false', 'ann'=>'resource', 'layer'=>'int', 'neuron'=>'int'], 'fann_get_bias_array' => ['array', 'ann'=>'resource'], 'fann_get_bit_fail' => ['int|false', 'ann'=>'resource'], 'fann_get_bit_fail_limit' => ['float|false', 'ann'=>'resource'], 'fann_get_cascade_activation_functions' => ['array|false', 'ann'=>'resource'], 'fann_get_cascade_activation_functions_count' => ['int|false', 'ann'=>'resource'], 'fann_get_cascade_activation_steepnesses' => ['array|false', 'ann'=>'resource'], 'fann_get_cascade_activation_steepnesses_count' => ['int|false', 'ann'=>'resource'], 'fann_get_cascade_candidate_change_fraction' => ['float|false', 'ann'=>'resource'], 'fann_get_cascade_candidate_limit' => ['float|false', 'ann'=>'resource'], 'fann_get_cascade_candidate_stagnation_epochs' => ['float|false', 'ann'=>'resource'], 'fann_get_cascade_max_cand_epochs' => ['int|false', 'ann'=>'resource'], 'fann_get_cascade_max_out_epochs' => ['int|false', 'ann'=>'resource'], 'fann_get_cascade_min_cand_epochs' => ['int|false', 'ann'=>'resource'], 'fann_get_cascade_min_out_epochs' => ['int|false', 'ann'=>'resource'], 'fann_get_cascade_num_candidate_groups' => ['int|false', 'ann'=>'resource'], 'fann_get_cascade_num_candidates' => ['int|false', 'ann'=>'resource'], 'fann_get_cascade_output_change_fraction' => ['float|false', 'ann'=>'resource'], 'fann_get_cascade_output_stagnation_epochs' => ['int|false', 'ann'=>'resource'], 'fann_get_cascade_weight_multiplier' => ['float|false', 'ann'=>'resource'], 'fann_get_connection_array' => ['array', 'ann'=>'resource'], 'fann_get_connection_rate' => ['float|false', 'ann'=>'resource'], 'fann_get_errno' => ['int|false', 'errdat'=>'resource'], 'fann_get_errstr' => ['string|false', 'errdat'=>'resource'], 'fann_get_layer_array' => ['array', 'ann'=>'resource'], 'fann_get_learning_momentum' => ['float|false', 'ann'=>'resource'], 'fann_get_learning_rate' => ['float|false', 'ann'=>'resource'], 'fann_get_MSE' => ['float|false', 'ann'=>'resource'], 'fann_get_network_type' => ['int|false', 'ann'=>'resource'], 'fann_get_num_input' => ['int|false', 'ann'=>'resource'], 'fann_get_num_layers' => ['int|false', 'ann'=>'resource'], 'fann_get_num_output' => ['int|false', 'ann'=>'resource'], 'fann_get_quickprop_decay' => ['float|false', 'ann'=>'resource'], 'fann_get_quickprop_mu' => ['float|false', 'ann'=>'resource'], 'fann_get_rprop_decrease_factor' => ['float|false', 'ann'=>'resource'], 'fann_get_rprop_delta_max' => ['float|false', 'ann'=>'resource'], 'fann_get_rprop_delta_min' => ['float|false', 'ann'=>'resource'], 'fann_get_rprop_delta_zero' => ['float|false', 'ann'=>'resource'], 'fann_get_rprop_increase_factor' => ['float|false', 'ann'=>'resource'], 'fann_get_sarprop_step_error_shift' => ['float|false', 'ann'=>'resource'], 'fann_get_sarprop_step_error_threshold_factor' => ['float|false', 'ann'=>'resource'], 'fann_get_sarprop_temperature' => ['float|false', 'ann'=>'resource'], 'fann_get_sarprop_weight_decay_shift' => ['float|false', 'ann'=>'resource'], 'fann_get_total_connections' => ['int|false', 'ann'=>'resource'], 'fann_get_total_neurons' => ['int|false', 'ann'=>'resource'], 'fann_get_train_error_function' => ['int|false', 'ann'=>'resource'], 'fann_get_train_stop_function' => ['int|false', 'ann'=>'resource'], 'fann_get_training_algorithm' => ['int|false', 'ann'=>'resource'], 'fann_init_weights' => ['bool', 'ann'=>'resource', 'train_data'=>'resource'], 'fann_length_train_data' => ['int|false', 'data'=>'resource'], 'fann_merge_train_data' => ['resource|false', 'data1'=>'resource', 'data2'=>'resource'], 'fann_num_input_train_data' => ['int|false', 'data'=>'resource'], 'fann_num_output_train_data' => ['int|false', 'data'=>'resource'], 'fann_print_error' => ['void', 'errdat'=>'string'], 'fann_randomize_weights' => ['bool', 'ann'=>'resource', 'min_weight'=>'float', 'max_weight'=>'float'], 'fann_read_train_from_file' => ['resource', 'filename'=>'string'], 'fann_reset_errno' => ['void', 'errdat'=>'resource'], 'fann_reset_errstr' => ['void', 'errdat'=>'resource'], 'fann_reset_MSE' => ['bool', 'ann'=>'string'], 'fann_run' => ['array|false', 'ann'=>'resource', 'input'=>'array'], 'fann_save' => ['bool', 'ann'=>'resource', 'configuration_file'=>'string'], 'fann_save_train' => ['bool', 'data'=>'resource', 'file_name'=>'string'], 'fann_scale_input' => ['bool', 'ann'=>'resource', 'input_vector'=>'array'], 'fann_scale_input_train_data' => ['bool', 'train_data'=>'resource', 'new_min'=>'float', 'new_max'=>'float'], 'fann_scale_output' => ['bool', 'ann'=>'resource', 'output_vector'=>'array'], 'fann_scale_output_train_data' => ['bool', 'train_data'=>'resource', 'new_min'=>'float', 'new_max'=>'float'], 'fann_scale_train' => ['bool', 'ann'=>'resource', 'train_data'=>'resource'], 'fann_scale_train_data' => ['bool', 'train_data'=>'resource', 'new_min'=>'float', 'new_max'=>'float'], 'fann_set_activation_function' => ['bool', 'ann'=>'resource', 'activation_function'=>'int', 'layer'=>'int', 'neuron'=>'int'], 'fann_set_activation_function_hidden' => ['bool', 'ann'=>'resource', 'activation_function'=>'int'], 'fann_set_activation_function_layer' => ['bool', 'ann'=>'resource', 'activation_function'=>'int', 'layer'=>'int'], 'fann_set_activation_function_output' => ['bool', 'ann'=>'resource', 'activation_function'=>'int'], 'fann_set_activation_steepness' => ['bool', 'ann'=>'resource', 'activation_steepness'=>'float', 'layer'=>'int', 'neuron'=>'int'], 'fann_set_activation_steepness_hidden' => ['bool', 'ann'=>'resource', 'activation_steepness'=>'float'], 'fann_set_activation_steepness_layer' => ['bool', 'ann'=>'resource', 'activation_steepness'=>'float', 'layer'=>'int'], 'fann_set_activation_steepness_output' => ['bool', 'ann'=>'resource', 'activation_steepness'=>'float'], 'fann_set_bit_fail_limit' => ['bool', 'ann'=>'resource', 'bit_fail_limit'=>'float'], 'fann_set_callback' => ['bool', 'ann'=>'resource', 'callback'=>'callable'], 'fann_set_cascade_activation_functions' => ['bool', 'ann'=>'resource', 'cascade_activation_functions'=>'array'], 'fann_set_cascade_activation_steepnesses' => ['bool', 'ann'=>'resource', 'cascade_activation_steepnesses_count'=>'array'], 'fann_set_cascade_candidate_change_fraction' => ['bool', 'ann'=>'resource', 'cascade_candidate_change_fraction'=>'float'], 'fann_set_cascade_candidate_limit' => ['bool', 'ann'=>'resource', 'cascade_candidate_limit'=>'float'], 'fann_set_cascade_candidate_stagnation_epochs' => ['bool', 'ann'=>'resource', 'cascade_candidate_stagnation_epochs'=>'int'], 'fann_set_cascade_max_cand_epochs' => ['bool', 'ann'=>'resource', 'cascade_max_cand_epochs'=>'int'], 'fann_set_cascade_max_out_epochs' => ['bool', 'ann'=>'resource', 'cascade_max_out_epochs'=>'int'], 'fann_set_cascade_min_cand_epochs' => ['bool', 'ann'=>'resource', 'cascade_min_cand_epochs'=>'int'], 'fann_set_cascade_min_out_epochs' => ['bool', 'ann'=>'resource', 'cascade_min_out_epochs'=>'int'], 'fann_set_cascade_num_candidate_groups' => ['bool', 'ann'=>'resource', 'cascade_num_candidate_groups'=>'int'], 'fann_set_cascade_output_change_fraction' => ['bool', 'ann'=>'resource', 'cascade_output_change_fraction'=>'float'], 'fann_set_cascade_output_stagnation_epochs' => ['bool', 'ann'=>'resource', 'cascade_output_stagnation_epochs'=>'int'], 'fann_set_cascade_weight_multiplier' => ['bool', 'ann'=>'resource', 'cascade_weight_multiplier'=>'float'], 'fann_set_error_log' => ['void', 'errdat'=>'resource', 'log_file'=>'string'], 'fann_set_input_scaling_params' => ['bool', 'ann'=>'resource', 'train_data'=>'resource', 'new_input_min'=>'float', 'new_input_max'=>'float'], 'fann_set_learning_momentum' => ['bool', 'ann'=>'resource', 'learning_momentum'=>'float'], 'fann_set_learning_rate' => ['bool', 'ann'=>'resource', 'learning_rate'=>'float'], 'fann_set_output_scaling_params' => ['bool', 'ann'=>'resource', 'train_data'=>'resource', 'new_output_min'=>'float', 'new_output_max'=>'float'], 'fann_set_quickprop_decay' => ['bool', 'ann'=>'resource', 'quickprop_decay'=>'float'], 'fann_set_quickprop_mu' => ['bool', 'ann'=>'resource', 'quickprop_mu'=>'float'], 'fann_set_rprop_decrease_factor' => ['bool', 'ann'=>'resource', 'rprop_decrease_factor'=>'float'], 'fann_set_rprop_delta_max' => ['bool', 'ann'=>'resource', 'rprop_delta_max'=>'float'], 'fann_set_rprop_delta_min' => ['bool', 'ann'=>'resource', 'rprop_delta_min'=>'float'], 'fann_set_rprop_delta_zero' => ['bool', 'ann'=>'resource', 'rprop_delta_zero'=>'float'], 'fann_set_rprop_increase_factor' => ['bool', 'ann'=>'resource', 'rprop_increase_factor'=>'float'], 'fann_set_sarprop_step_error_shift' => ['bool', 'ann'=>'resource', 'sarprop_step_error_shift'=>'float'], 'fann_set_sarprop_step_error_threshold_factor' => ['bool', 'ann'=>'resource', 'sarprop_step_error_threshold_factor'=>'float'], 'fann_set_sarprop_temperature' => ['bool', 'ann'=>'resource', 'sarprop_temperature'=>'float'], 'fann_set_sarprop_weight_decay_shift' => ['bool', 'ann'=>'resource', 'sarprop_weight_decay_shift'=>'float'], 'fann_set_scaling_params' => ['bool', 'ann'=>'resource', 'train_data'=>'resource', 'new_input_min'=>'float', 'new_input_max'=>'float', 'new_output_min'=>'float', 'new_output_max'=>'float'], 'fann_set_train_error_function' => ['bool', 'ann'=>'resource', 'error_function'=>'int'], 'fann_set_train_stop_function' => ['bool', 'ann'=>'resource', 'stop_function'=>'int'], 'fann_set_training_algorithm' => ['bool', 'ann'=>'resource', 'training_algorithm'=>'int'], 'fann_set_weight' => ['bool', 'ann'=>'resource', 'from_neuron'=>'int', 'to_neuron'=>'int', 'weight'=>'float'], 'fann_set_weight_array' => ['bool', 'ann'=>'resource', 'connections'=>'array'], 'fann_shuffle_train_data' => ['bool', 'train_data'=>'resource'], 'fann_subset_train_data' => ['resource', 'data'=>'resource', 'pos'=>'int', 'length'=>'int'], 'fann_test' => ['bool', 'ann'=>'resource', 'input'=>'array', 'desired_output'=>'array'], 'fann_test_data' => ['float|false', 'ann'=>'resource', 'data'=>'resource'], 'fann_train' => ['bool', 'ann'=>'resource', 'input'=>'array', 'desired_output'=>'array'], 'fann_train_epoch' => ['float|false', 'ann'=>'resource', 'data'=>'resource'], 'fann_train_on_data' => ['bool', 'ann'=>'resource', 'data'=>'resource', 'max_epochs'=>'int', 'epochs_between_reports'=>'int', 'desired_error'=>'float'], 'fann_train_on_file' => ['bool', 'ann'=>'resource', 'filename'=>'string', 'max_epochs'=>'int', 'epochs_between_reports'=>'int', 'desired_error'=>'float'], 'FANNConnection::__construct' => ['void', 'from_neuron'=>'int', 'to_neuron'=>'int', 'weight'=>'float'], 'FANNConnection::getFromNeuron' => ['int'], 'FANNConnection::getToNeuron' => ['int'], 'FANNConnection::getWeight' => ['void'], 'FANNConnection::setWeight' => ['bool', 'weight'=>'float'], 'fastcgi_finish_request' => ['bool'], 'fbsql_affected_rows' => ['int', 'link_identifier='=>'?resource'], 'fbsql_autocommit' => ['bool', 'link_identifier'=>'resource', 'onoff='=>'bool'], 'fbsql_blob_size' => ['int', 'blob_handle'=>'string', 'link_identifier='=>'?resource'], 'fbsql_change_user' => ['bool', 'user'=>'string', 'password'=>'string', 'database='=>'string', 'link_identifier='=>'?resource'], 'fbsql_clob_size' => ['int', 'clob_handle'=>'string', 'link_identifier='=>'?resource'], 'fbsql_close' => ['bool', 'link_identifier='=>'?resource'], 'fbsql_commit' => ['bool', 'link_identifier='=>'?resource'], 'fbsql_connect' => ['resource', 'hostname='=>'string', 'username='=>'string', 'password='=>'string'], 'fbsql_create_blob' => ['string', 'blob_data'=>'string', 'link_identifier='=>'?resource'], 'fbsql_create_clob' => ['string', 'clob_data'=>'string', 'link_identifier='=>'?resource'], 'fbsql_create_db' => ['bool', 'database_name'=>'string', 'link_identifier='=>'?resource', 'database_options='=>'string'], 'fbsql_data_seek' => ['bool', 'result'=>'resource', 'row_number'=>'int'], 'fbsql_database' => ['string', 'link_identifier'=>'resource', 'database='=>'string'], 'fbsql_database_password' => ['string', 'link_identifier'=>'resource', 'database_password='=>'string'], 'fbsql_db_query' => ['resource', 'database'=>'string', 'query'=>'string', 'link_identifier='=>'?resource'], 'fbsql_db_status' => ['int', 'database_name'=>'string', 'link_identifier='=>'?resource'], 'fbsql_drop_db' => ['bool', 'database_name'=>'string', 'link_identifier='=>'?resource'], 'fbsql_errno' => ['int', 'link_identifier='=>'?resource'], 'fbsql_error' => ['string', 'link_identifier='=>'?resource'], 'fbsql_fetch_array' => ['array', 'result'=>'resource', 'result_type='=>'int'], 'fbsql_fetch_assoc' => ['array', 'result'=>'resource'], 'fbsql_fetch_field' => ['object', 'result'=>'resource', 'field_offset='=>'int'], 'fbsql_fetch_lengths' => ['array', 'result'=>'resource'], 'fbsql_fetch_object' => ['object', 'result'=>'resource'], 'fbsql_fetch_row' => ['array', 'result'=>'resource'], 'fbsql_field_flags' => ['string', 'result'=>'resource', 'field_offset='=>'int'], 'fbsql_field_len' => ['int', 'result'=>'resource', 'field_offset='=>'int'], 'fbsql_field_name' => ['string', 'result'=>'resource', 'field_index='=>'int'], 'fbsql_field_seek' => ['bool', 'result'=>'resource', 'field_offset='=>'int'], 'fbsql_field_table' => ['string', 'result'=>'resource', 'field_offset='=>'int'], 'fbsql_field_type' => ['string', 'result'=>'resource', 'field_offset='=>'int'], 'fbsql_free_result' => ['bool', 'result'=>'resource'], 'fbsql_get_autostart_info' => ['array', 'link_identifier='=>'?resource'], 'fbsql_hostname' => ['string', 'link_identifier'=>'resource', 'host_name='=>'string'], 'fbsql_insert_id' => ['int', 'link_identifier='=>'?resource'], 'fbsql_list_dbs' => ['resource', 'link_identifier='=>'?resource'], 'fbsql_list_fields' => ['resource', 'database_name'=>'string', 'table_name'=>'string', 'link_identifier='=>'?resource'], 'fbsql_list_tables' => ['resource', 'database'=>'string', 'link_identifier='=>'?resource'], 'fbsql_next_result' => ['bool', 'result'=>'resource'], 'fbsql_num_fields' => ['int', 'result'=>'resource'], 'fbsql_num_rows' => ['int', 'result'=>'resource'], 'fbsql_password' => ['string', 'link_identifier'=>'resource', 'password='=>'string'], 'fbsql_pconnect' => ['resource', 'hostname='=>'string', 'username='=>'string', 'password='=>'string'], 'fbsql_query' => ['resource', 'query'=>'string', 'link_identifier='=>'?resource', 'batch_size='=>'int'], 'fbsql_read_blob' => ['string', 'blob_handle'=>'string', 'link_identifier='=>'?resource'], 'fbsql_read_clob' => ['string', 'clob_handle'=>'string', 'link_identifier='=>'?resource'], 'fbsql_result' => ['mixed', 'result'=>'resource', 'row='=>'int', 'field='=>'mixed'], 'fbsql_rollback' => ['bool', 'link_identifier='=>'?resource'], 'fbsql_rows_fetched' => ['int', 'result'=>'resource'], 'fbsql_select_db' => ['bool', 'database_name='=>'string', 'link_identifier='=>'?resource'], 'fbsql_set_characterset' => ['void', 'link_identifier'=>'resource', 'characterset'=>'int', 'in_out_both='=>'int'], 'fbsql_set_lob_mode' => ['bool', 'result'=>'resource', 'lob_mode'=>'int'], 'fbsql_set_password' => ['bool', 'link_identifier'=>'resource', 'user'=>'string', 'password'=>'string', 'old_password'=>'string'], 'fbsql_set_transaction' => ['void', 'link_identifier'=>'resource', 'locking'=>'int', 'isolation'=>'int'], 'fbsql_start_db' => ['bool', 'database_name'=>'string', 'link_identifier='=>'?resource', 'database_options='=>'string'], 'fbsql_stop_db' => ['bool', 'database_name'=>'string', 'link_identifier='=>'?resource'], 'fbsql_table_name' => ['string', 'result'=>'resource', 'index'=>'int'], 'fbsql_username' => ['string', 'link_identifier'=>'resource', 'username='=>'string'], 'fbsql_warnings' => ['bool', 'onoff='=>'bool'], 'fclose' => ['bool', 'stream'=>'resource'], 'fdf_add_doc_javascript' => ['bool', 'fdf_document'=>'resource', 'script_name'=>'string', 'script_code'=>'string'], 'fdf_add_template' => ['bool', 'fdf_document'=>'resource', 'newpage'=>'int', 'filename'=>'string', 'template'=>'string', 'rename'=>'int'], 'fdf_close' => ['void', 'fdf_document'=>'resource'], 'fdf_create' => ['resource'], 'fdf_enum_values' => ['bool', 'fdf_document'=>'resource', 'function'=>'callable', 'userdata='=>'mixed'], 'fdf_errno' => ['int'], 'fdf_error' => ['string', 'error_code='=>'int'], 'fdf_get_ap' => ['bool', 'fdf_document'=>'resource', 'field'=>'string', 'face'=>'int', 'filename'=>'string'], 'fdf_get_attachment' => ['array', 'fdf_document'=>'resource', 'fieldname'=>'string', 'savepath'=>'string'], 'fdf_get_encoding' => ['string', 'fdf_document'=>'resource'], 'fdf_get_file' => ['string', 'fdf_document'=>'resource'], 'fdf_get_flags' => ['int', 'fdf_document'=>'resource', 'fieldname'=>'string', 'whichflags'=>'int'], 'fdf_get_opt' => ['mixed', 'fdf_document'=>'resource', 'fieldname'=>'string', 'element='=>'int'], 'fdf_get_status' => ['string', 'fdf_document'=>'resource'], 'fdf_get_value' => ['mixed', 'fdf_document'=>'resource', 'fieldname'=>'string', 'which='=>'int'], 'fdf_get_version' => ['string', 'fdf_document='=>'resource'], 'fdf_header' => ['void'], 'fdf_next_field_name' => ['string', 'fdf_document'=>'resource', 'fieldname='=>'string'], 'fdf_open' => ['resource|false', 'filename'=>'string'], 'fdf_open_string' => ['resource', 'fdf_data'=>'string'], 'fdf_remove_item' => ['bool', 'fdf_document'=>'resource', 'fieldname'=>'string', 'item'=>'int'], 'fdf_save' => ['bool', 'fdf_document'=>'resource', 'filename='=>'string'], 'fdf_save_string' => ['string', 'fdf_document'=>'resource'], 'fdf_set_ap' => ['bool', 'fdf_document'=>'resource', 'field_name'=>'string', 'face'=>'int', 'filename'=>'string', 'page_number'=>'int'], 'fdf_set_encoding' => ['bool', 'fdf_document'=>'resource', 'encoding'=>'string'], 'fdf_set_file' => ['bool', 'fdf_document'=>'resource', 'url'=>'string', 'target_frame='=>'string'], 'fdf_set_flags' => ['bool', 'fdf_document'=>'resource', 'fieldname'=>'string', 'whichflags'=>'int', 'newflags'=>'int'], 'fdf_set_javascript_action' => ['bool', 'fdf_document'=>'resource', 'fieldname'=>'string', 'trigger'=>'int', 'script'=>'string'], 'fdf_set_on_import_javascript' => ['bool', 'fdf_document'=>'resource', 'script'=>'string', 'before_data_import'=>'bool'], 'fdf_set_opt' => ['bool', 'fdf_document'=>'resource', 'fieldname'=>'string', 'element'=>'int', 'string1'=>'string', 'string2'=>'string'], 'fdf_set_status' => ['bool', 'fdf_document'=>'resource', 'status'=>'string'], 'fdf_set_submit_form_action' => ['bool', 'fdf_document'=>'resource', 'fieldname'=>'string', 'trigger'=>'int', 'script'=>'string', 'flags'=>'int'], 'fdf_set_target_frame' => ['bool', 'fdf_document'=>'resource', 'frame_name'=>'string'], 'fdf_set_value' => ['bool', 'fdf_document'=>'resource', 'fieldname'=>'string', 'value'=>'mixed', 'isname='=>'int'], 'fdf_set_version' => ['bool', 'fdf_document'=>'resource', 'version'=>'string'], 'fdiv' => ['float', 'num1'=>'float', 'num2'=>'float'], 'feof' => ['bool', 'stream'=>'resource'], 'fflush' => ['bool', 'stream'=>'resource'], 'fsync' => ['bool', 'stream'=>'resource'], 'fdatasync' => ['bool', 'stream'=>'resource'], 'ffmpeg_animated_gif::__construct' => ['void', 'output_file_path'=>'string', 'width'=>'int', 'height'=>'int', 'frame_rate'=>'int', 'loop_count='=>'int'], 'ffmpeg_animated_gif::addFrame' => ['', 'frame_to_add'=>'ffmpeg_frame'], 'ffmpeg_frame::__construct' => ['void', 'gd_image'=>'resource'], 'ffmpeg_frame::crop' => ['', 'crop_top'=>'int', 'crop_bottom='=>'int', 'crop_left='=>'int', 'crop_right='=>'int'], 'ffmpeg_frame::getHeight' => ['int'], 'ffmpeg_frame::getPresentationTimestamp' => ['int'], 'ffmpeg_frame::getPTS' => ['int'], 'ffmpeg_frame::getWidth' => ['int'], 'ffmpeg_frame::resize' => ['', 'width'=>'int', 'height'=>'int', 'crop_top='=>'int', 'crop_bottom='=>'int', 'crop_left='=>'int', 'crop_right='=>'int'], 'ffmpeg_frame::toGDImage' => ['resource'], 'ffmpeg_movie::__construct' => ['void', 'path_to_media'=>'string', 'persistent'=>'bool'], 'ffmpeg_movie::getArtist' => ['string'], 'ffmpeg_movie::getAudioBitRate' => ['int'], 'ffmpeg_movie::getAudioChannels' => ['int'], 'ffmpeg_movie::getAudioCodec' => ['string'], 'ffmpeg_movie::getAudioSampleRate' => ['int'], 'ffmpeg_movie::getAuthor' => ['string'], 'ffmpeg_movie::getBitRate' => ['int'], 'ffmpeg_movie::getComment' => ['string'], 'ffmpeg_movie::getCopyright' => ['string'], 'ffmpeg_movie::getDuration' => ['int'], 'ffmpeg_movie::getFilename' => ['string'], 'ffmpeg_movie::getFrame' => ['ffmpeg_frame|false', 'framenumber'=>'int'], 'ffmpeg_movie::getFrameCount' => ['int'], 'ffmpeg_movie::getFrameHeight' => ['int'], 'ffmpeg_movie::getFrameNumber' => ['int'], 'ffmpeg_movie::getFrameRate' => ['int'], 'ffmpeg_movie::getFrameWidth' => ['int'], 'ffmpeg_movie::getGenre' => ['string'], 'ffmpeg_movie::getNextKeyFrame' => ['ffmpeg_frame|false'], 'ffmpeg_movie::getPixelFormat' => [''], 'ffmpeg_movie::getTitle' => ['string'], 'ffmpeg_movie::getTrackNumber' => ['int|string'], 'ffmpeg_movie::getVideoBitRate' => ['int'], 'ffmpeg_movie::getVideoCodec' => ['string'], 'ffmpeg_movie::getYear' => ['int|string'], 'ffmpeg_movie::hasAudio' => ['bool'], 'ffmpeg_movie::hasVideo' => ['bool'], 'fgetc' => ['string|false', 'stream'=>'resource'], 'fgetcsv' => ['list|array{0: null}|false', 'stream'=>'resource', 'length='=>'?int', 'separator='=>'string', 'enclosure='=>'string', 'escape='=>'string'], 'fgets' => ['string|false', 'stream'=>'resource', 'length='=>'?int'], 'Fiber::__construct' => ['void', 'callback'=>'callable'], 'Fiber::start' => ['mixed', '...args'=>'mixed'], 'Fiber::resume' => ['mixed', 'value='=>'null|mixed'], 'Fiber::throw' => ['mixed', 'exception'=>'Throwable'], 'Fiber::isStarted' => ['bool'], 'Fiber::isSuspended' => ['bool'], 'Fiber::isRunning' => ['bool'], 'Fiber::isTerminated' => ['bool'], 'Fiber::getReturn' => ['mixed'], 'Fiber::getCurrent' => ['?self'], 'Fiber::suspend' => ['mixed', 'value='=>'null|mixed'], 'FiberError::__construct' => ['void'], 'file' => ['list|false', 'filename'=>'string', 'flags='=>'int', 'context='=>'resource'], 'file_exists' => ['bool', 'filename'=>'string'], 'file_get_contents' => ['string|false', 'filename'=>'string', 'use_include_path='=>'bool', 'context='=>'?resource', 'offset='=>'int', 'length='=>'?int'], 'file_put_contents' => ['int<0, max>|false', 'filename'=>'string', 'data'=>'string|resource|array', 'flags='=>'int', 'context='=>'resource'], 'fileatime' => ['int|false', 'filename'=>'string'], 'filectime' => ['int|false', 'filename'=>'string'], 'filegroup' => ['int|false', 'filename'=>'string'], 'fileinode' => ['int|false', 'filename'=>'string'], 'filemtime' => ['int|false', 'filename'=>'string'], 'fileowner' => ['int|false', 'filename'=>'string'], 'fileperms' => ['int|false', 'filename'=>'string'], 'filepro' => ['bool', 'directory'=>'string'], 'filepro_fieldcount' => ['int'], 'filepro_fieldname' => ['string', 'field_number'=>'int'], 'filepro_fieldtype' => ['string', 'field_number'=>'int'], 'filepro_fieldwidth' => ['int', 'field_number'=>'int'], 'filepro_retrieve' => ['string', 'row_number'=>'int', 'field_number'=>'int'], 'filepro_rowcount' => ['int'], 'filesize' => ['int|false', 'filename'=>'string'], 'FilesystemIterator::__construct' => ['void', 'directory'=>'string', 'flags='=>'int'], 'FilesystemIterator::__toString' => ['string'], 'FilesystemIterator::current' => ['SplFileInfo|FilesystemIterator|string'], 'FilesystemIterator::getATime' => ['int'], 'FilesystemIterator::getBasename' => ['string', 'suffix='=>'string'], 'FilesystemIterator::getCTime' => ['int'], 'FilesystemIterator::getExtension' => ['string'], 'FilesystemIterator::getFileInfo' => ['SplFileInfo', 'class='=>'?class-string'], 'FilesystemIterator::getFilename' => ['string'], 'FilesystemIterator::getFlags' => ['int'], 'FilesystemIterator::getGroup' => ['int'], 'FilesystemIterator::getInode' => ['int'], 'FilesystemIterator::getLinkTarget' => ['string'], 'FilesystemIterator::getMTime' => ['int'], 'FilesystemIterator::getOwner' => ['int'], 'FilesystemIterator::getPath' => ['string'], 'FilesystemIterator::getPathInfo' => ['?SplFileInfo', 'class='=>'?class-string'], 'FilesystemIterator::getPathname' => ['string'], 'FilesystemIterator::getPerms' => ['int'], 'FilesystemIterator::getRealPath' => ['non-falsy-string'], 'FilesystemIterator::getSize' => ['int'], 'FilesystemIterator::getType' => ['string'], 'FilesystemIterator::isDir' => ['bool'], 'FilesystemIterator::isDot' => ['bool'], 'FilesystemIterator::isExecutable' => ['bool'], 'FilesystemIterator::isFile' => ['bool'], 'FilesystemIterator::isLink' => ['bool'], 'FilesystemIterator::isReadable' => ['bool'], 'FilesystemIterator::isWritable' => ['bool'], 'FilesystemIterator::key' => ['string'], 'FilesystemIterator::next' => ['void'], 'FilesystemIterator::openFile' => ['SplFileObject', 'mode='=>'string', 'useIncludePath='=>'bool', 'context='=>'?resource'], 'FilesystemIterator::rewind' => ['void'], 'FilesystemIterator::seek' => ['void', 'offset'=>'int'], 'FilesystemIterator::setFileClass' => ['void', 'class='=>'class-string'], 'FilesystemIterator::setFlags' => ['void', 'flags'=>'int'], 'FilesystemIterator::setInfoClass' => ['void', 'class='=>'class-string'], 'FilesystemIterator::valid' => ['bool'], 'filetype' => ['string|false', 'filename'=>'string'], 'filter_has_var' => ['bool', 'input_type'=>'0|1|2|4|5', 'var_name'=>'string'], 'filter_id' => ['int|false', 'name'=>'string'], 'filter_input' => ['mixed|false|null', 'type'=>'0|1|2|4|5', 'var_name'=>'string', 'filter='=>'int', 'options='=>'array|int'], 'filter_input_array' => ['array|false|null', 'type'=>'0|1|2|4|5', 'options='=>'int|array', 'add_empty='=>'bool'], 'filter_list' => ['non-empty-list'], 'filter_var' => ['mixed|false', 'value'=>'mixed', 'filter='=>'int', 'options='=>'array|int'], 'filter_var_array' => ['array|false|null', 'array'=>'array', 'options='=>'array|int', 'add_empty='=>'bool'], 'FilterIterator::__construct' => ['void', 'iterator'=>'Iterator'], 'FilterIterator::accept' => ['bool'], 'FilterIterator::current' => ['mixed'], 'FilterIterator::getInnerIterator' => ['Iterator'], 'FilterIterator::key' => ['mixed'], 'FilterIterator::next' => ['void'], 'FilterIterator::rewind' => ['void'], 'FilterIterator::valid' => ['bool'], 'finfo::__construct' => ['void', 'flags='=>'int', 'magic_database='=>'?string'], 'finfo::buffer' => ['string|false', 'string'=>'string', 'flags='=>'int', 'context='=>'?resource'], 'finfo::file' => ['string|false', 'filename'=>'string', 'flags='=>'int', 'context='=>'?resource'], 'finfo::set_flags' => ['bool', 'flags'=>'int'], 'finfo_buffer' => ['string|false', 'finfo'=>'finfo', 'string'=>'string', 'flags='=>'int', 'context='=>'resource'], 'finfo_close' => ['bool', 'finfo'=>'finfo'], 'finfo_file' => ['string|false', 'finfo'=>'finfo', 'filename'=>'string', 'flags='=>'int', 'context='=>'resource'], 'finfo_open' => ['finfo|false', 'flags='=>'int', 'magic_database='=>'?string'], 'finfo_set_flags' => ['bool', 'finfo'=>'finfo', 'flags'=>'int'], 'floatval' => ['float', 'value'=>'mixed'], 'flock' => ['bool', 'stream'=>'resource', 'operation'=>'int', '&w_would_block='=>'int'], 'floor' => ['float', 'num'=>'float|int'], 'flush' => ['void'], 'fmod' => ['float', 'num1'=>'float', 'num2'=>'float'], 'fnmatch' => ['bool', 'pattern'=>'string', 'filename'=>'string', 'flags='=>'int'], 'fopen' => ['resource|false', 'filename'=>'string', 'mode'=>'string', 'use_include_path='=>'bool', 'context='=>'resource|null'], 'forward_static_call' => ['mixed|false', 'callback'=>'callable', '...args='=>'mixed'], 'forward_static_call_array' => ['mixed|false', 'callback'=>'callable', 'args'=>'list'], 'fpassthru' => ['int', 'stream'=>'resource'], 'fpm_get_status' => ['array|false'], 'fprintf' => ['int', 'stream'=>'resource', 'format'=>'string', '...values='=>'string|int|float'], 'fputcsv' => ['int|false', 'stream'=>'resource', 'fields'=>'array', 'separator='=>'string', 'enclosure='=>'string', 'escape='=>'string', 'eol='=>'string'], 'fputs' => ['int|false', 'stream'=>'resource', 'data'=>'string', 'length='=>'?int'], 'fread' => ['string|false', 'stream'=>'resource', 'length'=>'int'], 'frenchtojd' => ['int', 'month'=>'int', 'day'=>'int', 'year'=>'int'], 'fribidi_log2vis' => ['string', 'string'=>'string', 'direction'=>'string', 'charset'=>'int'], 'fscanf' => ['list', 'stream'=>'resource', 'format'=>'string'], 'fscanf\'1' => ['int', 'stream'=>'resource', 'format'=>'string', '&...w_vars='=>'string|int|float'], 'fseek' => ['int', 'stream'=>'resource', 'offset'=>'int', 'whence='=>'int'], 'fsockopen' => ['resource|false', 'hostname'=>'string', 'port='=>'int', '&w_error_code='=>'int', '&w_error_message='=>'string', 'timeout='=>'?float'], 'fstat' => ['array{0: int, 1: int, 2: int, 3: int, 4: int, 5: int, 6: int, 7: int, 8: int, 9: int, 10: int, 11: int, 12: int, dev: int, ino: int, mode: int, nlink: int, uid: int, gid: int, rdev: int, size: int, atime: int, mtime: int, ctime: int, blksize: int, blocks: int}|false', 'stream'=>'resource'], 'ftell' => ['int|false', 'stream'=>'resource'], 'ftok' => ['int', 'filename'=>'string', 'project_id'=>'string'], 'ftp_alloc' => ['bool', 'ftp'=>'FTP\Connection', 'size'=>'int', '&w_response='=>'string'], 'ftp_append' => ['bool', 'ftp'=>'FTP\Connection', 'remote_filename'=>'string', 'local_filename'=>'string', 'mode='=>'int'], 'ftp_cdup' => ['bool', 'ftp'=>'FTP\Connection'], 'ftp_chdir' => ['bool', 'ftp'=>'FTP\Connection', 'directory'=>'string'], 'ftp_chmod' => ['int|false', 'ftp'=>'FTP\Connection', 'permissions'=>'int', 'filename'=>'string'], 'ftp_close' => ['bool', 'ftp'=>'FTP\Connection'], 'ftp_connect' => ['FTP\Connection|false', 'hostname'=>'string', 'port='=>'int', 'timeout='=>'int'], 'ftp_delete' => ['bool', 'ftp'=>'FTP\Connection', 'filename'=>'string'], 'ftp_exec' => ['bool', 'ftp'=>'FTP\Connection', 'command'=>'string'], 'ftp_fget' => ['bool', 'ftp'=>'FTP\Connection', 'stream'=>'resource', 'remote_filename'=>'string', 'mode='=>'int', 'offset='=>'int'], 'ftp_fput' => ['bool', 'ftp'=>'FTP\Connection', 'remote_filename'=>'string', 'stream'=>'resource', 'mode='=>'int', 'offset='=>'int'], 'ftp_get' => ['bool', 'ftp'=>'FTP\Connection', 'local_filename'=>'string', 'remote_filename'=>'string', 'mode='=>'int', 'offset='=>'int'], 'ftp_get_option' => ['int|false', 'ftp'=>'FTP\Connection', 'option'=>'int'], 'ftp_login' => ['bool', 'ftp'=>'FTP\Connection', 'username'=>'string', 'password'=>'string'], 'ftp_mdtm' => ['int', 'ftp'=>'FTP\Connection', 'filename'=>'string'], 'ftp_mkdir' => ['string|false', 'ftp'=>'FTP\Connection', 'directory'=>'string'], 'ftp_mlsd' => ['array|false', 'ftp'=>'FTP\Connection', 'directory'=>'string'], 'ftp_nb_continue' => ['int', 'ftp'=>'FTP\Connection'], 'ftp_nb_fget' => ['int', 'ftp'=>'FTP\Connection', 'stream'=>'resource', 'remote_filename'=>'string', 'mode='=>'int', 'offset='=>'int'], 'ftp_nb_fput' => ['int', 'ftp'=>'FTP\Connection', 'remote_filename'=>'string', 'stream'=>'resource', 'mode='=>'int', 'offset='=>'int'], 'ftp_nb_get' => ['int', 'ftp'=>'FTP\Connection', 'local_filename'=>'string', 'remote_filename'=>'string', 'mode='=>'int', 'offset='=>'int'], 'ftp_nb_put' => ['int', 'ftp'=>'FTP\Connection', 'remote_filename'=>'string', 'local_filename'=>'string', 'mode='=>'int', 'offset='=>'int'], 'ftp_nlist' => ['array|false', 'ftp'=>'FTP\Connection', 'directory'=>'string'], 'ftp_pasv' => ['bool', 'ftp'=>'FTP\Connection', 'enable'=>'bool'], 'ftp_put' => ['bool', 'ftp'=>'FTP\Connection', 'remote_filename'=>'string', 'local_filename'=>'string', 'mode='=>'int', 'offset='=>'int'], 'ftp_pwd' => ['string|false', 'ftp'=>'FTP\Connection'], 'ftp_quit' => ['bool', 'ftp'=>'FTP\Connection'], 'ftp_raw' => ['?array', 'ftp'=>'FTP\Connection', 'command'=>'string'], 'ftp_rawlist' => ['array|false', 'ftp'=>'FTP\Connection', 'directory'=>'string', 'recursive='=>'bool'], 'ftp_rename' => ['bool', 'ftp'=>'FTP\Connection', 'from'=>'string', 'to'=>'string'], 'ftp_rmdir' => ['bool', 'ftp'=>'FTP\Connection', 'directory'=>'string'], 'ftp_set_option' => ['bool', 'ftp'=>'FTP\Connection', 'option'=>'int', 'value'=>'mixed'], 'ftp_site' => ['bool', 'ftp'=>'FTP\Connection', 'command'=>'string'], 'ftp_size' => ['int', 'ftp'=>'FTP\Connection', 'filename'=>'string'], 'ftp_ssl_connect' => ['FTP\Connection|false', 'hostname'=>'string', 'port='=>'int', 'timeout='=>'int'], 'ftp_systype' => ['string|false', 'ftp'=>'FTP\Connection'], 'ftruncate' => ['bool', 'stream'=>'resource', 'size'=>'int'], 'func_get_arg' => ['mixed|false', 'position'=>'int'], 'func_get_args' => ['list'], 'func_num_args' => ['int'], 'function_exists' => ['bool', 'function'=>'string'], 'fwrite' => ['int|false', 'stream'=>'resource', 'data'=>'string', 'length='=>'?int'], 'gc_collect_cycles' => ['int'], 'gc_disable' => ['void'], 'gc_enable' => ['void'], 'gc_enabled' => ['bool'], 'gc_mem_caches' => ['int'], 'gc_status' => ['array{runs:int,collected:int,threshold:int,roots:int,running:bool,protected:bool,full:bool,buffer_size:int,application_time:float,collector_time:float,destructor_time:float,free_time:float}'], 'gd_info' => ['array'], 'gearman_bugreport' => [''], 'gearman_client_add_options' => ['', 'client_object'=>'', 'option'=>''], 'gearman_client_add_server' => ['', 'client_object'=>'', 'host'=>'', 'port'=>''], 'gearman_client_add_servers' => ['', 'client_object'=>'', 'servers'=>''], 'gearman_client_add_task' => ['', 'client_object'=>'', 'function_name'=>'', 'workload'=>'', 'context'=>'', 'unique'=>''], 'gearman_client_add_task_background' => ['', 'client_object'=>'', 'function_name'=>'', 'workload'=>'', 'context'=>'', 'unique'=>''], 'gearman_client_add_task_high' => ['', 'client_object'=>'', 'function_name'=>'', 'workload'=>'', 'context'=>'', 'unique'=>''], 'gearman_client_add_task_high_background' => ['', 'client_object'=>'', 'function_name'=>'', 'workload'=>'', 'context'=>'', 'unique'=>''], 'gearman_client_add_task_low' => ['', 'client_object'=>'', 'function_name'=>'', 'workload'=>'', 'context'=>'', 'unique'=>''], 'gearman_client_add_task_low_background' => ['', 'client_object'=>'', 'function_name'=>'', 'workload'=>'', 'context'=>'', 'unique'=>''], 'gearman_client_add_task_status' => ['', 'client_object'=>'', 'job_handle'=>'', 'context'=>''], 'gearman_client_clear_fn' => ['', 'client_object'=>''], 'gearman_client_clone' => ['', 'client_object'=>''], 'gearman_client_context' => ['', 'client_object'=>''], 'gearman_client_create' => ['', 'client_object'=>''], 'gearman_client_do' => ['', 'client_object'=>'', 'function_name'=>'', 'workload'=>'', 'unique'=>''], 'gearman_client_do_background' => ['', 'client_object'=>'', 'function_name'=>'', 'workload'=>'', 'unique'=>''], 'gearman_client_do_high' => ['', 'client_object'=>'', 'function_name'=>'', 'workload'=>'', 'unique'=>''], 'gearman_client_do_high_background' => ['', 'client_object'=>'', 'function_name'=>'', 'workload'=>'', 'unique'=>''], 'gearman_client_do_job_handle' => ['', 'client_object'=>''], 'gearman_client_do_low' => ['', 'client_object'=>'', 'function_name'=>'', 'workload'=>'', 'unique'=>''], 'gearman_client_do_low_background' => ['', 'client_object'=>'', 'function_name'=>'', 'workload'=>'', 'unique'=>''], 'gearman_client_do_normal' => ['', 'client_object'=>'', 'function_name'=>'string', 'workload'=>'string', 'unique'=>'string'], 'gearman_client_do_status' => ['', 'client_object'=>''], 'gearman_client_echo' => ['', 'client_object'=>'', 'workload'=>''], 'gearman_client_errno' => ['', 'client_object'=>''], 'gearman_client_error' => ['', 'client_object'=>''], 'gearman_client_job_status' => ['', 'client_object'=>'', 'job_handle'=>''], 'gearman_client_options' => ['', 'client_object'=>''], 'gearman_client_remove_options' => ['', 'client_object'=>'', 'option'=>''], 'gearman_client_return_code' => ['', 'client_object'=>''], 'gearman_client_run_tasks' => ['', 'data'=>''], 'gearman_client_set_complete_fn' => ['', 'client_object'=>'', 'callback'=>''], 'gearman_client_set_context' => ['', 'client_object'=>'', 'context'=>''], 'gearman_client_set_created_fn' => ['', 'client_object'=>'', 'callback'=>''], 'gearman_client_set_data_fn' => ['', 'client_object'=>'', 'callback'=>''], 'gearman_client_set_exception_fn' => ['', 'client_object'=>'', 'callback'=>''], 'gearman_client_set_fail_fn' => ['', 'client_object'=>'', 'callback'=>''], 'gearman_client_set_options' => ['', 'client_object'=>'', 'option'=>''], 'gearman_client_set_status_fn' => ['', 'client_object'=>'', 'callback'=>''], 'gearman_client_set_timeout' => ['', 'client_object'=>'', 'timeout'=>''], 'gearman_client_set_warning_fn' => ['', 'client_object'=>'', 'callback'=>''], 'gearman_client_set_workload_fn' => ['', 'client_object'=>'', 'callback'=>''], 'gearman_client_timeout' => ['', 'client_object'=>''], 'gearman_client_wait' => ['', 'client_object'=>''], 'gearman_job_function_name' => ['', 'job_object'=>''], 'gearman_job_handle' => ['string'], 'gearman_job_return_code' => ['', 'job_object'=>''], 'gearman_job_send_complete' => ['', 'job_object'=>'', 'result'=>''], 'gearman_job_send_data' => ['', 'job_object'=>'', 'data'=>''], 'gearman_job_send_exception' => ['', 'job_object'=>'', 'exception'=>''], 'gearman_job_send_fail' => ['', 'job_object'=>''], 'gearman_job_send_status' => ['', 'job_object'=>'', 'numerator'=>'', 'denominator'=>''], 'gearman_job_send_warning' => ['', 'job_object'=>'', 'warning'=>''], 'gearman_job_status' => ['array', 'job_handle'=>'string'], 'gearman_job_unique' => ['', 'job_object'=>''], 'gearman_job_workload' => ['', 'job_object'=>''], 'gearman_job_workload_size' => ['', 'job_object'=>''], 'gearman_task_data' => ['', 'task_object'=>''], 'gearman_task_data_size' => ['', 'task_object'=>''], 'gearman_task_denominator' => ['', 'task_object'=>''], 'gearman_task_function_name' => ['', 'task_object'=>''], 'gearman_task_is_known' => ['', 'task_object'=>''], 'gearman_task_is_running' => ['', 'task_object'=>''], 'gearman_task_job_handle' => ['', 'task_object'=>''], 'gearman_task_numerator' => ['', 'task_object'=>''], 'gearman_task_recv_data' => ['', 'task_object'=>'', 'data_len'=>''], 'gearman_task_return_code' => ['', 'task_object'=>''], 'gearman_task_send_workload' => ['', 'task_object'=>'', 'data'=>''], 'gearman_task_unique' => ['', 'task_object'=>''], 'gearman_verbose_name' => ['', 'verbose'=>''], 'gearman_version' => [''], 'gearman_worker_add_function' => ['', 'worker_object'=>'', 'function_name'=>'', 'function'=>'', 'data'=>'', 'timeout'=>''], 'gearman_worker_add_options' => ['', 'worker_object'=>'', 'option'=>''], 'gearman_worker_add_server' => ['', 'worker_object'=>'', 'host'=>'', 'port'=>''], 'gearman_worker_add_servers' => ['', 'worker_object'=>'', 'servers'=>''], 'gearman_worker_clone' => ['', 'worker_object'=>''], 'gearman_worker_create' => [''], 'gearman_worker_echo' => ['', 'worker_object'=>'', 'workload'=>''], 'gearman_worker_errno' => ['', 'worker_object'=>''], 'gearman_worker_error' => ['', 'worker_object'=>''], 'gearman_worker_grab_job' => ['', 'worker_object'=>''], 'gearman_worker_options' => ['', 'worker_object'=>''], 'gearman_worker_register' => ['', 'worker_object'=>'', 'function_name'=>'', 'timeout'=>''], 'gearman_worker_remove_options' => ['', 'worker_object'=>'', 'option'=>''], 'gearman_worker_return_code' => ['', 'worker_object'=>''], 'gearman_worker_set_options' => ['', 'worker_object'=>'', 'option'=>''], 'gearman_worker_set_timeout' => ['', 'worker_object'=>'', 'timeout'=>''], 'gearman_worker_timeout' => ['', 'worker_object'=>''], 'gearman_worker_unregister' => ['', 'worker_object'=>'', 'function_name'=>''], 'gearman_worker_unregister_all' => ['', 'worker_object'=>''], 'gearman_worker_wait' => ['', 'worker_object'=>''], 'gearman_worker_work' => ['', 'worker_object'=>''], 'GearmanClient::__construct' => ['void'], 'GearmanClient::addOptions' => ['bool', 'options'=>'int'], 'GearmanClient::addServer' => ['bool', 'host='=>'string', 'port='=>'int'], 'GearmanClient::addServers' => ['bool', 'servers='=>'string'], 'GearmanClient::addTask' => ['GearmanTask|false', 'function_name'=>'string', 'workload'=>'string', 'context='=>'mixed', 'unique='=>'string'], 'GearmanClient::addTaskBackground' => ['GearmanTask|false', 'function_name'=>'string', 'workload'=>'string', 'context='=>'mixed', 'unique='=>'string'], 'GearmanClient::addTaskHigh' => ['GearmanTask|false', 'function_name'=>'string', 'workload'=>'string', 'context='=>'mixed', 'unique='=>'string'], 'GearmanClient::addTaskHighBackground' => ['GearmanTask|false', 'function_name'=>'string', 'workload'=>'string', 'context='=>'mixed', 'unique='=>'string'], 'GearmanClient::addTaskLow' => ['GearmanTask|false', 'function_name'=>'string', 'workload'=>'string', 'context='=>'mixed', 'unique='=>'string'], 'GearmanClient::addTaskLowBackground' => ['GearmanTask|false', 'function_name'=>'string', 'workload'=>'string', 'context='=>'mixed', 'unique='=>'string'], 'GearmanClient::addTaskStatus' => ['GearmanTask', 'job_handle'=>'string', 'context='=>'string'], 'GearmanClient::clearCallbacks' => ['bool'], 'GearmanClient::clone' => ['GearmanClient'], 'GearmanClient::context' => ['string'], 'GearmanClient::data' => ['string'], 'GearmanClient::do' => ['string', 'function_name'=>'string', 'workload'=>'string', 'unique='=>'string'], 'GearmanClient::doBackground' => ['string', 'function_name'=>'string', 'workload'=>'string', 'unique='=>'string'], 'GearmanClient::doHigh' => ['string', 'function_name'=>'string', 'workload'=>'string', 'unique='=>'string'], 'GearmanClient::doHighBackground' => ['string', 'function_name'=>'string', 'workload'=>'string', 'unique='=>'string'], 'GearmanClient::doJobHandle' => ['string'], 'GearmanClient::doLow' => ['string', 'function_name'=>'string', 'workload'=>'string', 'unique='=>'string'], 'GearmanClient::doLowBackground' => ['string', 'function_name'=>'string', 'workload'=>'string', 'unique='=>'string'], 'GearmanClient::doNormal' => ['string', 'function_name'=>'string', 'workload'=>'string', 'unique='=>'string'], 'GearmanClient::doStatus' => ['array'], 'GearmanClient::echo' => ['bool', 'workload'=>'string'], 'GearmanClient::error' => ['string'], 'GearmanClient::getErrno' => ['int'], 'GearmanClient::jobStatus' => ['array', 'job_handle'=>'string'], 'GearmanClient::options' => [''], 'GearmanClient::ping' => ['bool', 'workload'=>'string'], 'GearmanClient::removeOptions' => ['bool', 'options'=>'int'], 'GearmanClient::returnCode' => ['int'], 'GearmanClient::runTasks' => ['bool'], 'GearmanClient::setClientCallback' => ['void', 'callback'=>'callable'], 'GearmanClient::setCompleteCallback' => ['bool', 'callback'=>'callable'], 'GearmanClient::setContext' => ['bool', 'context'=>'string'], 'GearmanClient::setCreatedCallback' => ['bool', 'callback'=>'string'], 'GearmanClient::setData' => ['bool', 'data'=>'string'], 'GearmanClient::setDataCallback' => ['bool', 'callback'=>'callable'], 'GearmanClient::setExceptionCallback' => ['bool', 'callback'=>'callable'], 'GearmanClient::setFailCallback' => ['bool', 'callback'=>'callable'], 'GearmanClient::setOptions' => ['bool', 'options'=>'int'], 'GearmanClient::setStatusCallback' => ['bool', 'callback'=>'callable'], 'GearmanClient::setTimeout' => ['bool', 'timeout'=>'int'], 'GearmanClient::setWarningCallback' => ['bool', 'callback'=>'callable'], 'GearmanClient::setWorkloadCallback' => ['bool', 'callback'=>'callable'], 'GearmanClient::timeout' => ['int'], 'GearmanClient::wait' => [''], 'GearmanJob::__construct' => ['void'], 'GearmanJob::complete' => ['bool', 'result'=>'string'], 'GearmanJob::data' => ['bool', 'data'=>'string'], 'GearmanJob::exception' => ['bool', 'exception'=>'string'], 'GearmanJob::fail' => ['bool'], 'GearmanJob::functionName' => ['string'], 'GearmanJob::handle' => ['string'], 'GearmanJob::returnCode' => ['int'], 'GearmanJob::sendComplete' => ['bool', 'result'=>'string'], 'GearmanJob::sendData' => ['bool', 'data'=>'string'], 'GearmanJob::sendException' => ['bool', 'exception'=>'string'], 'GearmanJob::sendFail' => ['bool'], 'GearmanJob::sendStatus' => ['bool', 'numerator'=>'int', 'denominator'=>'int'], 'GearmanJob::sendWarning' => ['bool', 'warning'=>'string'], 'GearmanJob::setReturn' => ['bool', 'gearman_return_t'=>'string'], 'GearmanJob::status' => ['bool', 'numerator'=>'int', 'denominator'=>'int'], 'GearmanJob::unique' => ['string'], 'GearmanJob::warning' => ['bool', 'warning'=>'string'], 'GearmanJob::workload' => ['string'], 'GearmanJob::workloadSize' => ['int'], 'GearmanTask::__construct' => ['void'], 'GearmanTask::create' => ['GearmanTask'], 'GearmanTask::data' => ['string|false'], 'GearmanTask::dataSize' => ['int|false'], 'GearmanTask::function' => ['string'], 'GearmanTask::functionName' => ['string'], 'GearmanTask::isKnown' => ['bool'], 'GearmanTask::isRunning' => ['bool'], 'GearmanTask::jobHandle' => ['string'], 'GearmanTask::recvData' => ['array|false', 'data_len'=>'int'], 'GearmanTask::returnCode' => ['int'], 'GearmanTask::sendData' => ['int', 'data'=>'string'], 'GearmanTask::sendWorkload' => ['int|false', 'data'=>'string'], 'GearmanTask::taskDenominator' => ['int|false'], 'GearmanTask::taskNumerator' => ['int|false'], 'GearmanTask::unique' => ['string|false'], 'GearmanTask::uuid' => ['string'], 'GearmanWorker::__construct' => ['void'], 'GearmanWorker::addFunction' => ['bool', 'function_name'=>'string', 'function'=>'callable', 'context='=>'mixed', 'timeout='=>'int'], 'GearmanWorker::addOptions' => ['bool', 'option'=>'int'], 'GearmanWorker::addServer' => ['bool', 'host='=>'string', 'port='=>'int'], 'GearmanWorker::addServers' => ['bool', 'servers'=>'string'], 'GearmanWorker::clone' => ['void'], 'GearmanWorker::echo' => ['bool', 'workload'=>'string'], 'GearmanWorker::error' => ['string'], 'GearmanWorker::getErrno' => ['int'], 'GearmanWorker::grabJob' => [''], 'GearmanWorker::options' => ['int'], 'GearmanWorker::register' => ['bool', 'function_name'=>'string', 'timeout='=>'int'], 'GearmanWorker::removeOptions' => ['bool', 'option'=>'int'], 'GearmanWorker::returnCode' => ['int'], 'GearmanWorker::setId' => ['bool', 'id'=>'string'], 'GearmanWorker::setOptions' => ['bool', 'option'=>'int'], 'GearmanWorker::setTimeout' => ['bool', 'timeout'=>'int'], 'GearmanWorker::timeout' => ['int'], 'GearmanWorker::unregister' => ['bool', 'function_name'=>'string'], 'GearmanWorker::unregisterAll' => ['bool'], 'GearmanWorker::wait' => ['bool'], 'GearmanWorker::work' => ['bool'], 'Gender\Gender::__construct' => ['void', 'dsn='=>'string'], 'Gender\Gender::connect' => ['bool', 'dsn'=>'string'], 'Gender\Gender::country' => ['array', 'country'=>'int'], 'Gender\Gender::get' => ['int', 'name'=>'string', 'country='=>'int'], 'Gender\Gender::isNick' => ['array', 'name0'=>'string', 'name1'=>'string', 'country='=>'int'], 'Gender\Gender::similarNames' => ['array', 'name'=>'string', 'country='=>'int'], 'Generator::current' => ['mixed'], 'Generator::getReturn' => ['mixed'], 'Generator::key' => ['mixed'], 'Generator::next' => ['void'], 'Generator::rewind' => ['void'], 'Generator::send' => ['mixed', 'value'=>'mixed'], 'Generator::throw' => ['mixed', 'exception'=>'Throwable'], 'Generator::valid' => ['bool'], 'geoip_asnum_by_name' => ['string|false', 'hostname'=>'string'], 'geoip_continent_code_by_name' => ['string|false', 'hostname'=>'string'], 'geoip_country_code3_by_name' => ['string|false', 'hostname'=>'string'], 'geoip_country_code_by_name' => ['string|false', 'hostname'=>'string'], 'geoip_country_name_by_name' => ['string|false', 'hostname'=>'string'], 'geoip_database_info' => ['string', 'database='=>'int'], 'geoip_db_avail' => ['bool', 'database'=>'int'], 'geoip_db_filename' => ['string', 'database'=>'int'], 'geoip_db_get_all_info' => ['array'], 'geoip_domain_by_name' => ['string', 'hostname'=>'string'], 'geoip_id_by_name' => ['int', 'hostname'=>'string'], 'geoip_isp_by_name' => ['string|false', 'hostname'=>'string'], 'geoip_netspeedcell_by_name' => ['string|false', 'hostname'=>'string'], 'geoip_org_by_name' => ['string|false', 'hostname'=>'string'], 'geoip_record_by_name' => ['array|false', 'hostname'=>'string'], 'geoip_region_by_name' => ['array|false', 'hostname'=>'string'], 'geoip_region_name_by_code' => ['string|false', 'country_code'=>'string', 'region_code'=>'string'], 'geoip_setup_custom_directory' => ['void', 'path'=>'string'], 'geoip_time_zone_by_country_and_region' => ['string|false', 'country_code'=>'string', 'region_code='=>'string'], 'GEOSGeometry::__toString' => ['string'], 'GEOSGeometry::project' => ['float', 'other'=>'GEOSGeometry', 'normalized'=>'bool'], 'GEOSGeometry::interpolate' => ['GEOSGeometry', 'dist'=>'float', 'normalized'=>'bool'], 'GEOSGeometry::buffer' => ['GEOSGeometry', 'dist'=>'float', 'styleArray='=>'array'], 'GEOSGeometry::offsetCurve' => ['GEOSGeometry', 'dist'=>'float', 'styleArray'=>'array'], 'GEOSGeometry::envelope' => ['GEOSGeometry'], 'GEOSGeometry::intersection' => ['GEOSGeometry', 'geom'=>'GEOSGeometry'], 'GEOSGeometry::convexHull' => ['GEOSGeometry'], 'GEOSGeometry::difference' => ['GEOSGeometry', 'geom'=>'GEOSGeometry'], 'GEOSGeometry::symDifference' => ['GEOSGeometry', 'geom'=>'GEOSGeometry'], 'GEOSGeometry::boundary' => ['GEOSGeometry'], 'GEOSGeometry::union' => ['GEOSGeometry', 'otherGeom='=>'GEOSGeometry'], 'GEOSGeometry::pointOnSurface' => ['GEOSGeometry'], 'GEOSGeometry::centroid' => ['GEOSGeometry'], 'GEOSGeometry::relate' => ['string|bool', 'otherGeom'=>'GEOSGeometry', 'pattern'=>'string'], 'GEOSGeometry::relateBoundaryNodeRule' => ['string', 'otherGeom'=>'GEOSGeometry', 'rule'=>'int'], 'GEOSGeometry::simplify' => ['GEOSGeometry', 'tolerance'=>'float', 'preserveTopology='=>'bool'], 'GEOSGeometry::normalize' => ['GEOSGeometry'], 'GEOSGeometry::extractUniquePoints' => ['GEOSGeometry'], 'GEOSGeometry::disjoint' => ['bool', 'geom'=>'GEOSGeometry'], 'GEOSGeometry::touches' => ['bool', 'geom'=>'GEOSGeometry'], 'GEOSGeometry::intersects' => ['bool', 'geom'=>'GEOSGeometry'], 'GEOSGeometry::crosses' => ['bool', 'geom'=>'GEOSGeometry'], 'GEOSGeometry::within' => ['bool', 'geom'=>'GEOSGeometry'], 'GEOSGeometry::contains' => ['bool', 'geom'=>'GEOSGeometry'], 'GEOSGeometry::overlaps' => ['bool', 'geom'=>'GEOSGeometry'], 'GEOSGeometry::covers' => ['bool', 'geom'=>'GEOSGeometry'], 'GEOSGeometry::coveredBy' => ['bool', 'geom'=>'GEOSGeometry'], 'GEOSGeometry::equals' => ['bool', 'geom'=>'GEOSGeometry'], 'GEOSGeometry::equalsExact' => ['bool', 'geom'=>'GEOSGeometry', 'tolerance'=>'float'], 'GEOSGeometry::isEmpty' => ['bool'], 'GEOSGeometry::checkValidity' => ['array{valid: bool, reason?: string, location?: GEOSGeometry}'], 'GEOSGeometry::isSimple' => ['bool'], 'GEOSGeometry::isRing' => ['bool'], 'GEOSGeometry::hasZ' => ['bool'], 'GEOSGeometry::isClosed' => ['bool'], 'GEOSGeometry::typeName' => ['string'], 'GEOSGeometry::typeId' => ['int'], 'GEOSGeometry::getSRID' => ['int'], 'GEOSGeometry::setSRID' => ['void', 'srid'=>'int'], 'GEOSGeometry::numGeometries' => ['int'], 'GEOSGeometry::geometryN' => ['GEOSGeometry', 'num'=>'int'], 'GEOSGeometry::numInteriorRings' => ['int'], 'GEOSGeometry::numPoints' => ['int'], 'GEOSGeometry::getX' => ['float'], 'GEOSGeometry::getY' => ['float'], 'GEOSGeometry::interiorRingN' => ['GEOSGeometry', 'num'=>'int'], 'GEOSGeometry::exteriorRing' => ['GEOSGeometry'], 'GEOSGeometry::numCoordinates' => ['int'], 'GEOSGeometry::dimension' => ['int'], 'GEOSGeometry::coordinateDimension' => ['int'], 'GEOSGeometry::pointN' => ['GEOSGeometry', 'num'=>'int'], 'GEOSGeometry::startPoint' => ['GEOSGeometry'], 'GEOSGeometry::endPoint' => ['GEOSGeometry'], 'GEOSGeometry::area' => ['float'], 'GEOSGeometry::length' => ['float'], 'GEOSGeometry::distance' => ['float', 'geom'=>'GEOSGeometry'], 'GEOSGeometry::hausdorffDistance' => ['float', 'geom'=>'GEOSGeometry'], 'GEOSGeometry::snapTo' => ['GEOSGeometry', 'geom'=>'GEOSGeometry', 'tolerance'=>'float'], 'GEOSGeometry::node' => ['GEOSGeometry'], 'GEOSGeometry::delaunayTriangulation' => ['GEOSGeometry', 'tolerance'=>'float', 'onlyEdges'=>'bool'], 'GEOSGeometry::voronoiDiagram' => ['GEOSGeometry', 'tolerance'=>'float', 'onlyEdges'=>'bool', 'extent'=>'GEOSGeometry|null'], 'GEOSLineMerge' => ['array', 'geom'=>'GEOSGeometry'], 'GEOSPolygonize' => ['array{rings: GEOSGeometry[], cut_edges?: GEOSGeometry[], dangles: GEOSGeometry[], invalid_rings: GEOSGeometry[]}', 'geom'=>'GEOSGeometry'], 'GEOSRelateMatch' => ['bool', 'matrix'=>'string', 'pattern'=>'string'], 'GEOSSharedPaths' => ['GEOSGeometry', 'geom1'=>'GEOSGeometry', 'geom2'=>'GEOSGeometry'], 'GEOSVersion' => ['string'], 'GEOSWKBReader::__construct' => ['void'], 'GEOSWKBReader::read' => ['GEOSGeometry', 'wkb'=>'string'], 'GEOSWKBReader::readHEX' => ['GEOSGeometry', 'wkb'=>'string'], 'GEOSWKBWriter::__construct' => ['void'], 'GEOSWKBWriter::getOutputDimension' => ['int'], 'GEOSWKBWriter::setOutputDimension' => ['void', 'dim'=>'int'], 'GEOSWKBWriter::getByteOrder' => ['int'], 'GEOSWKBWriter::setByteOrder' => ['void', 'byteOrder'=>'int'], 'GEOSWKBWriter::getIncludeSRID' => ['bool'], 'GEOSWKBWriter::setIncludeSRID' => ['void', 'inc'=>'bool'], 'GEOSWKBWriter::write' => ['string', 'geom'=>'GEOSGeometry'], 'GEOSWKBWriter::writeHEX' => ['string', 'geom'=>'GEOSGeometry'], 'GEOSWKTReader::__construct' => ['void'], 'GEOSWKTReader::read' => ['GEOSGeometry', 'wkt'=>'string'], 'GEOSWKTWriter::__construct' => ['void'], 'GEOSWKTWriter::write' => ['string', 'geom'=>'GEOSGeometry'], 'GEOSWKTWriter::setTrim' => ['void', 'trim'=>'bool'], 'GEOSWKTWriter::setRoundingPrecision' => ['void', 'prec'=>'int'], 'GEOSWKTWriter::setOutputDimension' => ['void', 'dim'=>'int'], 'GEOSWKTWriter::getOutputDimension' => ['int'], 'GEOSWKTWriter::setOld3D' => ['void', 'val'=>'bool'], 'get_browser' => ['array|object|false', 'user_agent='=>'?string', 'return_array='=>'bool'], 'get_call_stack' => [''], 'get_called_class' => ['class-string'], 'get_cfg_var' => ['string|false', 'option'=>'string'], 'get_class' => ['class-string', 'object'=>'object'], 'get_class_methods' => ['list', 'object_or_class'=>'object|class-string'], 'get_class_vars' => ['array', 'class'=>'string'], 'get_current_user' => ['string'], 'get_debug_type' => ['string', 'value'=>'mixed'], 'get_declared_classes' => ['list'], 'get_declared_interfaces' => ['list'], 'get_declared_traits' => ['list'], 'get_defined_constants' => ['array', 'categorize='=>'bool'], 'get_defined_functions' => ['array{internal: list, user: list}', 'exclude_disabled='=>'bool'], 'get_defined_vars' => ['array'], 'get_extension_funcs' => ['list|false', 'extension'=>'string'], 'get_headers' => ['array|false', 'url'=>'string', 'associative='=>'bool', 'context='=>'?resource'], 'get_html_translation_table' => ['array', 'table='=>'int', 'flags='=>'int', 'encoding='=>'string'], 'get_include_path' => ['string'], 'get_included_files' => ['list'], 'get_loaded_extensions' => ['list', 'zend_extensions='=>'bool'], 'get_magic_quotes_gpc' => ['int|false'], 'get_magic_quotes_runtime' => ['int|false'], 'get_meta_tags' => ['array', 'filename'=>'string', 'use_include_path='=>'bool'], 'get_object_vars' => ['array', 'object'=>'object'], 'get_parent_class' => ['class-string|false', 'object_or_class'=>'object|class-string'], 'get_required_files' => ['list'], 'get_resource_id' => ['int', 'resource'=>'resource'], 'get_resource_type' => ['string', 'resource'=>'resource'], 'get_resources' => ['array', 'type='=>'?string'], 'getallheaders' => ['array|false'], 'getcwd' => ['non-falsy-string|false'], 'getdate' => ['array{seconds: int<0, 59>, minutes: int<0, 59>, hours: int<0, 23>, mday: int<1, 31>, wday: int<0, 6>, mon: int<1, 12>, year: int, yday: int<0, 365>, weekday: "Monday"|"Tuesday"|"Wednesday"|"Thursday"|"Friday"|"Saturday"|"Sunday", month: "January"|"February"|"March"|"April"|"May"|"June"|"July"|"August"|"September"|"October"|"November"|"December", 0: int}', 'timestamp='=>'?int'], 'getenv' => ['string|false', 'name'=>'string', 'local_only='=>'bool'], 'getenv\'1' => ['array'], 'gethostbyaddr' => ['string|false', 'ip'=>'string'], 'gethostbyname' => ['string', 'hostname'=>'string'], 'gethostbynamel' => ['list|false', 'hostname'=>'string'], 'gethostname' => ['string|false'], 'getimagesize' => ['array{0:int, 1: int, 2: int, 3: string, mime: string, channels?: 3|4, bits?: int}|false', 'filename'=>'string', '&w_image_info='=>'array'], 'getimagesizefromstring' => ['array{0:int, 1: int, 2: int, 3: string, mime: string, channels?: 3|4, bits?: int}|false', 'string'=>'string', '&w_image_info='=>'array'], 'getlastmod' => ['int|false'], 'getmxrr' => ['bool', 'hostname'=>'string', '&w_hosts'=>'array', '&w_weights='=>'array'], 'getmygid' => ['int|false'], 'getmyinode' => ['int|false'], 'getmypid' => ['int|false'], 'getmyuid' => ['int|false'], 'getopt' => ['array>|false', 'short_options'=>'string', 'long_options='=>'array', '&w_rest_index='=>'int'], 'getprotobyname' => ['int|false', 'protocol'=>'string'], 'getprotobynumber' => ['string', 'protocol'=>'int'], 'getrandmax' => ['int<1, max>'], 'getrusage' => ['array', 'mode='=>'int'], 'getservbyname' => ['int|false', 'service'=>'string', 'protocol'=>'string'], 'getservbyport' => ['string|false', 'port'=>'int', 'protocol'=>'string'], 'gettext' => ['string', 'message'=>'string'], 'gettimeofday' => ['array'], 'gettimeofday\'1' => ['float', 'as_float='=>'true'], 'gettype' => ['string', 'value'=>'mixed'], 'glob' => ['false|list{0?:string, ...}', 'pattern'=>'string', 'flags='=>'int<0, max>'], 'GlobIterator::__construct' => ['void', 'pattern'=>'string', 'flags='=>'int'], 'GlobIterator::count' => ['int'], 'GlobIterator::current' => ['FilesystemIterator|SplFileInfo|string'], 'GlobIterator::getATime' => ['int'], 'GlobIterator::getBasename' => ['string', 'suffix='=>'string'], 'GlobIterator::getCTime' => ['int'], 'GlobIterator::getExtension' => ['string'], 'GlobIterator::getFileInfo' => ['SplFileInfo', 'class='=>'?class-string'], 'GlobIterator::getFilename' => ['string'], 'GlobIterator::getFlags' => ['int'], 'GlobIterator::getGroup' => ['int'], 'GlobIterator::getInode' => ['int'], 'GlobIterator::getLinkTarget' => ['string|false'], 'GlobIterator::getMTime' => ['int'], 'GlobIterator::getOwner' => ['int'], 'GlobIterator::getPath' => ['string'], 'GlobIterator::getPathInfo' => ['?SplFileInfo', 'class='=>'?class-string'], 'GlobIterator::getPathname' => ['string'], 'GlobIterator::getPerms' => ['int'], 'GlobIterator::getRealPath' => ['non-falsy-string|false'], 'GlobIterator::getSize' => ['int'], 'GlobIterator::getType' => ['string|false'], 'GlobIterator::isDir' => ['bool'], 'GlobIterator::isDot' => ['bool'], 'GlobIterator::isExecutable' => ['bool'], 'GlobIterator::isFile' => ['bool'], 'GlobIterator::isLink' => ['bool'], 'GlobIterator::isReadable' => ['bool'], 'GlobIterator::isWritable' => ['bool'], 'GlobIterator::key' => ['string'], 'GlobIterator::next' => ['void'], 'GlobIterator::openFile' => ['SplFileObject', 'mode='=>'string', 'useIncludePath='=>'bool', 'context='=>'?resource'], 'GlobIterator::rewind' => ['void'], 'GlobIterator::seek' => ['void', 'offset'=>'int'], 'GlobIterator::setFileClass' => ['void', 'class='=>'class-string'], 'GlobIterator::setFlags' => ['void', 'flags'=>'int'], 'GlobIterator::setInfoClass' => ['void', 'class='=>'class-string'], 'GlobIterator::valid' => ['bool'], 'Gmagick::__construct' => ['void', 'filename='=>'string'], 'Gmagick::addimage' => ['Gmagick', 'gmagick'=>'gmagick'], 'Gmagick::addnoiseimage' => ['Gmagick', 'noise'=>'int'], 'Gmagick::annotateimage' => ['Gmagick', 'gmagickdraw'=>'gmagickdraw', 'x'=>'float', 'y'=>'float', 'angle'=>'float', 'text'=>'string'], 'Gmagick::blurimage' => ['Gmagick', 'radius'=>'float', 'sigma'=>'float', 'channel='=>'int'], 'Gmagick::borderimage' => ['Gmagick', 'color'=>'gmagickpixel', 'width'=>'int', 'height'=>'int'], 'Gmagick::charcoalimage' => ['Gmagick', 'radius'=>'float', 'sigma'=>'float'], 'Gmagick::chopimage' => ['Gmagick', 'width'=>'int', 'height'=>'int', 'x'=>'int', 'y'=>'int'], 'Gmagick::clear' => ['Gmagick'], 'Gmagick::commentimage' => ['Gmagick', 'comment'=>'string'], 'Gmagick::compositeimage' => ['Gmagick', 'source'=>'gmagick', 'compose'=>'int', 'x'=>'int', 'y'=>'int'], 'Gmagick::cropimage' => ['Gmagick', 'width'=>'int', 'height'=>'int', 'x'=>'int', 'y'=>'int'], 'Gmagick::cropthumbnailimage' => ['Gmagick', 'width'=>'int', 'height'=>'int'], 'Gmagick::current' => ['Gmagick'], 'Gmagick::cyclecolormapimage' => ['Gmagick', 'displace'=>'int'], 'Gmagick::deconstructimages' => ['Gmagick'], 'Gmagick::despeckleimage' => ['Gmagick'], 'Gmagick::destroy' => ['bool'], 'Gmagick::drawimage' => ['Gmagick', 'gmagickdraw'=>'gmagickdraw'], 'Gmagick::edgeimage' => ['Gmagick', 'radius'=>'float'], 'Gmagick::embossimage' => ['Gmagick', 'radius'=>'float', 'sigma'=>'float'], 'Gmagick::enhanceimage' => ['Gmagick'], 'Gmagick::equalizeimage' => ['Gmagick'], 'Gmagick::flipimage' => ['Gmagick'], 'Gmagick::flopimage' => ['Gmagick'], 'Gmagick::frameimage' => ['Gmagick', 'color'=>'gmagickpixel', 'width'=>'int', 'height'=>'int', 'inner_bevel'=>'int', 'outer_bevel'=>'int'], 'Gmagick::gammaimage' => ['Gmagick', 'gamma'=>'float'], 'Gmagick::getcopyright' => ['string'], 'Gmagick::getfilename' => ['string'], 'Gmagick::getimagebackgroundcolor' => ['GmagickPixel'], 'Gmagick::getimageblueprimary' => ['array'], 'Gmagick::getimagebordercolor' => ['GmagickPixel'], 'Gmagick::getimagechanneldepth' => ['int', 'channel_type'=>'int'], 'Gmagick::getimagecolors' => ['int'], 'Gmagick::getimagecolorspace' => ['int'], 'Gmagick::getimagecompose' => ['int'], 'Gmagick::getimagedelay' => ['int'], 'Gmagick::getimagedepth' => ['int'], 'Gmagick::getimagedispose' => ['int'], 'Gmagick::getimageextrema' => ['array'], 'Gmagick::getimagefilename' => ['string'], 'Gmagick::getimageformat' => ['string'], 'Gmagick::getimagegamma' => ['float'], 'Gmagick::getimagegreenprimary' => ['array'], 'Gmagick::getimageheight' => ['int'], 'Gmagick::getimagehistogram' => ['array'], 'Gmagick::getimageindex' => ['int'], 'Gmagick::getimageinterlacescheme' => ['int'], 'Gmagick::getimageiterations' => ['int'], 'Gmagick::getimagematte' => ['int'], 'Gmagick::getimagemattecolor' => ['GmagickPixel'], 'Gmagick::getimageprofile' => ['string', 'name'=>'string'], 'Gmagick::getimageredprimary' => ['array'], 'Gmagick::getimagerenderingintent' => ['int'], 'Gmagick::getimageresolution' => ['array'], 'Gmagick::getimagescene' => ['int'], 'Gmagick::getimagesignature' => ['string'], 'Gmagick::getimagetype' => ['int'], 'Gmagick::getimageunits' => ['int'], 'Gmagick::getimagewhitepoint' => ['array'], 'Gmagick::getimagewidth' => ['int'], 'Gmagick::getpackagename' => ['string'], 'Gmagick::getquantumdepth' => ['array'], 'Gmagick::getreleasedate' => ['string'], 'Gmagick::getsamplingfactors' => ['array'], 'Gmagick::getsize' => ['array'], 'Gmagick::getversion' => ['array'], 'Gmagick::hasnextimage' => ['bool'], 'Gmagick::haspreviousimage' => ['bool'], 'Gmagick::implodeimage' => ['mixed', 'radius'=>'float'], 'Gmagick::labelimage' => ['mixed', 'label'=>'string'], 'Gmagick::levelimage' => ['mixed', 'blackpoint'=>'float', 'gamma'=>'float', 'whitepoint'=>'float', 'channel='=>'int'], 'Gmagick::magnifyimage' => ['mixed'], 'Gmagick::mapimage' => ['Gmagick', 'gmagick'=>'gmagick', 'dither'=>'bool'], 'Gmagick::medianfilterimage' => ['void', 'radius'=>'float'], 'Gmagick::minifyimage' => ['Gmagick'], 'Gmagick::modulateimage' => ['Gmagick', 'brightness'=>'float', 'saturation'=>'float', 'hue'=>'float'], 'Gmagick::motionblurimage' => ['Gmagick', 'radius'=>'float', 'sigma'=>'float', 'angle'=>'float'], 'Gmagick::newimage' => ['Gmagick', 'width'=>'int', 'height'=>'int', 'background'=>'string', 'format='=>'string'], 'Gmagick::nextimage' => ['bool'], 'Gmagick::normalizeimage' => ['Gmagick', 'channel='=>'int'], 'Gmagick::oilpaintimage' => ['Gmagick', 'radius'=>'float'], 'Gmagick::previousimage' => ['bool'], 'Gmagick::profileimage' => ['Gmagick', 'name'=>'string', 'profile'=>'string'], 'Gmagick::quantizeimage' => ['Gmagick', 'numcolors'=>'int', 'colorspace'=>'int', 'treedepth'=>'int', 'dither'=>'bool', 'measureerror'=>'bool'], 'Gmagick::quantizeimages' => ['Gmagick', 'numcolors'=>'int', 'colorspace'=>'int', 'treedepth'=>'int', 'dither'=>'bool', 'measureerror'=>'bool'], 'Gmagick::queryfontmetrics' => ['array', 'draw'=>'gmagickdraw', 'text'=>'string'], 'Gmagick::queryfonts' => ['array', 'pattern='=>'string'], 'Gmagick::queryformats' => ['array', 'pattern='=>'string'], 'Gmagick::radialblurimage' => ['Gmagick', 'angle'=>'float', 'channel='=>'int'], 'Gmagick::raiseimage' => ['Gmagick', 'width'=>'int', 'height'=>'int', 'x'=>'int', 'y'=>'int', 'raise'=>'bool'], 'Gmagick::read' => ['Gmagick', 'filename'=>'string'], 'Gmagick::readimage' => ['Gmagick', 'filename'=>'string'], 'Gmagick::readimageblob' => ['Gmagick', 'imagecontents'=>'string', 'filename='=>'string'], 'Gmagick::readimagefile' => ['Gmagick', 'fp'=>'resource', 'filename='=>'string'], 'Gmagick::reducenoiseimage' => ['Gmagick', 'radius'=>'float'], 'Gmagick::removeimage' => ['Gmagick'], 'Gmagick::removeimageprofile' => ['string', 'name'=>'string'], 'Gmagick::resampleimage' => ['Gmagick', 'xresolution'=>'float', 'yresolution'=>'float', 'filter'=>'int', 'blur'=>'float'], 'Gmagick::resizeimage' => ['Gmagick', 'width'=>'int', 'height'=>'int', 'filter'=>'int', 'blur'=>'float', 'fit='=>'bool'], 'Gmagick::rollimage' => ['Gmagick', 'x'=>'int', 'y'=>'int'], 'Gmagick::rotateimage' => ['Gmagick', 'color'=>'mixed', 'degrees'=>'float'], 'Gmagick::scaleimage' => ['Gmagick', 'width'=>'int', 'height'=>'int', 'fit='=>'bool'], 'Gmagick::separateimagechannel' => ['Gmagick', 'channel'=>'int'], 'Gmagick::setCompressionQuality' => ['Gmagick', 'quality'=>'int'], 'Gmagick::setfilename' => ['Gmagick', 'filename'=>'string'], 'Gmagick::setimagebackgroundcolor' => ['Gmagick', 'color'=>'gmagickpixel'], 'Gmagick::setimageblueprimary' => ['Gmagick', 'x'=>'float', 'y'=>'float'], 'Gmagick::setimagebordercolor' => ['Gmagick', 'color'=>'gmagickpixel'], 'Gmagick::setimagechanneldepth' => ['Gmagick', 'channel'=>'int', 'depth'=>'int'], 'Gmagick::setimagecolorspace' => ['Gmagick', 'colorspace'=>'int'], 'Gmagick::setimagecompose' => ['Gmagick', 'composite'=>'int'], 'Gmagick::setimagedelay' => ['Gmagick', 'delay'=>'int'], 'Gmagick::setimagedepth' => ['Gmagick', 'depth'=>'int'], 'Gmagick::setimagedispose' => ['Gmagick', 'disposetype'=>'int'], 'Gmagick::setimagefilename' => ['Gmagick', 'filename'=>'string'], 'Gmagick::setimageformat' => ['Gmagick', 'imageformat'=>'string'], 'Gmagick::setimagegamma' => ['Gmagick', 'gamma'=>'float'], 'Gmagick::setimagegreenprimary' => ['Gmagick', 'x'=>'float', 'y'=>'float'], 'Gmagick::setimageindex' => ['Gmagick', 'index'=>'int'], 'Gmagick::setimageinterlacescheme' => ['Gmagick', 'interlace'=>'int'], 'Gmagick::setimageiterations' => ['Gmagick', 'iterations'=>'int'], 'Gmagick::setimageprofile' => ['Gmagick', 'name'=>'string', 'profile'=>'string'], 'Gmagick::setimageredprimary' => ['Gmagick', 'x'=>'float', 'y'=>'float'], 'Gmagick::setimagerenderingintent' => ['Gmagick', 'rendering_intent'=>'int'], 'Gmagick::setimageresolution' => ['Gmagick', 'xresolution'=>'float', 'yresolution'=>'float'], 'Gmagick::setimagescene' => ['Gmagick', 'scene'=>'int'], 'Gmagick::setimagetype' => ['Gmagick', 'imgtype'=>'int'], 'Gmagick::setimageunits' => ['Gmagick', 'resolution'=>'int'], 'Gmagick::setimagewhitepoint' => ['Gmagick', 'x'=>'float', 'y'=>'float'], 'Gmagick::setsamplingfactors' => ['Gmagick', 'factors'=>'array'], 'Gmagick::setsize' => ['Gmagick', 'columns'=>'int', 'rows'=>'int'], 'Gmagick::shearimage' => ['Gmagick', 'color'=>'mixed', 'xshear'=>'float', 'yshear'=>'float'], 'Gmagick::solarizeimage' => ['Gmagick', 'threshold'=>'int'], 'Gmagick::spreadimage' => ['Gmagick', 'radius'=>'float'], 'Gmagick::stripimage' => ['Gmagick'], 'Gmagick::swirlimage' => ['Gmagick', 'degrees'=>'float'], 'Gmagick::thumbnailimage' => ['Gmagick', 'width'=>'int', 'height'=>'int', 'fit='=>'bool'], 'Gmagick::trimimage' => ['Gmagick', 'fuzz'=>'float'], 'Gmagick::write' => ['Gmagick', 'filename'=>'string'], 'Gmagick::writeimage' => ['Gmagick', 'filename'=>'string', 'all_frames='=>'bool'], 'GmagickDraw::annotate' => ['GmagickDraw', 'x'=>'float', 'y'=>'float', 'text'=>'string'], 'GmagickDraw::arc' => ['GmagickDraw', 'sx'=>'float', 'sy'=>'float', 'ex'=>'float', 'ey'=>'float', 'sd'=>'float', 'ed'=>'float'], 'GmagickDraw::bezier' => ['GmagickDraw', 'coordinate_array'=>'array'], 'GmagickDraw::ellipse' => ['GmagickDraw', 'ox'=>'float', 'oy'=>'float', 'rx'=>'float', 'ry'=>'float', 'start'=>'float', 'end'=>'float'], 'GmagickDraw::getfillcolor' => ['GmagickPixel'], 'GmagickDraw::getfillopacity' => ['float'], 'GmagickDraw::getfont' => ['string|false'], 'GmagickDraw::getfontsize' => ['float'], 'GmagickDraw::getfontstyle' => ['int'], 'GmagickDraw::getfontweight' => ['int'], 'GmagickDraw::getstrokecolor' => ['GmagickPixel'], 'GmagickDraw::getstrokeopacity' => ['float'], 'GmagickDraw::getstrokewidth' => ['float'], 'GmagickDraw::gettextdecoration' => ['int'], 'GmagickDraw::gettextencoding' => ['string|false'], 'GmagickDraw::line' => ['GmagickDraw', 'sx'=>'float', 'sy'=>'float', 'ex'=>'float', 'ey'=>'float'], 'GmagickDraw::point' => ['GmagickDraw', 'x'=>'float', 'y'=>'float'], 'GmagickDraw::polygon' => ['GmagickDraw', 'coordinates'=>'array'], 'GmagickDraw::polyline' => ['GmagickDraw', 'coordinate_array'=>'array'], 'GmagickDraw::rectangle' => ['GmagickDraw', 'x1'=>'float', 'y1'=>'float', 'x2'=>'float', 'y2'=>'float'], 'GmagickDraw::rotate' => ['GmagickDraw', 'degrees'=>'float'], 'GmagickDraw::roundrectangle' => ['GmagickDraw', 'x1'=>'float', 'y1'=>'float', 'x2'=>'float', 'y2'=>'float', 'rx'=>'float', 'ry'=>'float'], 'GmagickDraw::scale' => ['GmagickDraw', 'x'=>'float', 'y'=>'float'], 'GmagickDraw::setfillcolor' => ['GmagickDraw', 'color'=>'string'], 'GmagickDraw::setfillopacity' => ['GmagickDraw', 'fill_opacity'=>'float'], 'GmagickDraw::setfont' => ['GmagickDraw', 'font'=>'string'], 'GmagickDraw::setfontsize' => ['GmagickDraw', 'pointsize'=>'float'], 'GmagickDraw::setfontstyle' => ['GmagickDraw', 'style'=>'int'], 'GmagickDraw::setfontweight' => ['GmagickDraw', 'weight'=>'int'], 'GmagickDraw::setstrokecolor' => ['GmagickDraw', 'color'=>'gmagickpixel'], 'GmagickDraw::setstrokeopacity' => ['GmagickDraw', 'stroke_opacity'=>'float'], 'GmagickDraw::setstrokewidth' => ['GmagickDraw', 'width'=>'float'], 'GmagickDraw::settextdecoration' => ['GmagickDraw', 'decoration'=>'int'], 'GmagickDraw::settextencoding' => ['GmagickDraw', 'encoding'=>'string'], 'GmagickPixel::__construct' => ['void', 'color='=>'string'], 'GmagickPixel::getcolor' => ['mixed', 'as_array='=>'bool', 'normalize_array='=>'bool'], 'GmagickPixel::getcolorcount' => ['int'], 'GmagickPixel::getcolorvalue' => ['float', 'color'=>'int'], 'GmagickPixel::setcolor' => ['GmagickPixel', 'color'=>'string'], 'GmagickPixel::setcolorvalue' => ['GmagickPixel', 'color'=>'int', 'value'=>'float'], 'gmdate' => ['string', 'format'=>'string', 'timestamp='=>'int|null'], 'gmmktime' => ['int|false', 'hour'=>'int', 'minute='=>'int|null', 'second='=>'int|null', 'month='=>'int|null', 'day='=>'int|null', 'year='=>'int|null'], 'GMP::__serialize' => ['array'], 'GMP::__unserialize' => ['void', 'data'=>'array'], 'gmp_abs' => ['GMP', 'num'=>'GMP|string|int'], 'gmp_add' => ['GMP', 'num1'=>'GMP|string|int', 'num2'=>'GMP|string|int'], 'gmp_and' => ['GMP', 'num1'=>'GMP|string|int', 'num2'=>'GMP|string|int'], 'gmp_binomial' => ['GMP', 'n'=>'GMP|string|int', 'k'=>'int'], 'gmp_clrbit' => ['void', 'num'=>'GMP', 'index'=>'int'], 'gmp_cmp' => ['int', 'num1'=>'GMP|string|int', 'num2'=>'GMP|string|int'], 'gmp_com' => ['GMP', 'num'=>'GMP|string|int'], 'gmp_div' => ['GMP', 'num1'=>'GMP|string|int', 'num2'=>'GMP|string|int', 'rounding_mode='=>'int'], 'gmp_div_q' => ['GMP', 'num1'=>'GMP|string|int', 'num2'=>'GMP|string|int', 'rounding_mode='=>'int'], 'gmp_div_qr' => ['array{0: GMP, 1: GMP}', 'num1'=>'GMP|string|int', 'num2'=>'GMP|string|int', 'rounding_mode='=>'int'], 'gmp_div_r' => ['GMP', 'num1'=>'GMP|string|int', 'num2'=>'GMP|string|int', 'rounding_mode='=>'int'], 'gmp_divexact' => ['GMP', 'num1'=>'GMP|string|int', 'num2'=>'GMP|string|int'], 'gmp_export' => ['string', 'num'=>'GMP|string|int', 'word_size='=>'int', 'flags='=>'int'], 'gmp_fact' => ['GMP', 'num'=>'int'], 'gmp_gcd' => ['GMP', 'num1'=>'GMP|string|int', 'num2'=>'GMP|string|int'], 'gmp_gcdext' => ['array', 'num1'=>'GMP|string|int', 'num2'=>'GMP|string|int'], 'gmp_hamdist' => ['int', 'num1'=>'GMP|string|int', 'num2'=>'GMP|string|int'], 'gmp_import' => ['GMP', 'data'=>'string', 'word_size='=>'int', 'flags='=>'int'], 'gmp_init' => ['GMP', 'num'=>'int|string', 'base='=>'int'], 'gmp_intval' => ['int', 'num'=>'GMP|string|int'], 'gmp_invert' => ['GMP|false', 'num1'=>'GMP|string|int', 'num2'=>'GMP|string|int'], 'gmp_jacobi' => ['int', 'num1'=>'GMP|string|int', 'num2'=>'GMP|string|int'], 'gmp_kronecker' => ['int', 'num1'=>'GMP|string|int', 'num2'=>'GMP|string|int'], 'gmp_lcm' => ['GMP', 'num1'=>'GMP|string|int', 'num2'=>'GMP|string|int'], 'gmp_legendre' => ['int', 'num1'=>'GMP|string|int', 'num2'=>'GMP|string|int'], 'gmp_mod' => ['GMP', 'num1'=>'GMP|string|int', 'num2'=>'GMP|string|int'], 'gmp_mul' => ['GMP', 'num1'=>'GMP|string|int', 'num2'=>'GMP|string|int'], 'gmp_neg' => ['GMP', 'num'=>'GMP|string|int'], 'gmp_nextprime' => ['GMP', 'num'=>'GMP|string|int'], 'gmp_or' => ['GMP', 'num1'=>'GMP|string|int', 'num2'=>'GMP|string|int'], 'gmp_perfect_power' => ['bool', 'num'=>'GMP|string|int'], 'gmp_perfect_square' => ['bool', 'num'=>'GMP|string|int'], 'gmp_popcount' => ['int', 'num'=>'GMP|string|int'], 'gmp_pow' => ['GMP', 'num'=>'GMP|string|int', 'exponent'=>'int'], 'gmp_powm' => ['GMP', 'num'=>'GMP|string|int', 'exponent'=>'GMP|string|int', 'modulus'=>'GMP|string|int'], 'gmp_prob_prime' => ['int', 'num'=>'GMP|string|int', 'repetitions='=>'int'], 'gmp_random_bits' => ['GMP', 'bits'=>'int'], 'gmp_random_range' => ['GMP', 'min'=>'GMP|string|int', 'max'=>'GMP|string|int'], 'gmp_random_seed' => ['void', 'seed'=>'GMP|string|int'], 'gmp_root' => ['GMP', 'num'=>'GMP|string|int', 'nth'=>'int'], 'gmp_rootrem' => ['array{0: GMP, 1: GMP}', 'num'=>'GMP|string|int', 'nth'=>'int'], 'gmp_scan0' => ['int', 'num1'=>'GMP|string|int', 'start'=>'int'], 'gmp_scan1' => ['int', 'num1'=>'GMP|string|int', 'start'=>'int'], 'gmp_setbit' => ['void', 'num'=>'GMP', 'index'=>'int', 'value='=>'bool'], 'gmp_sign' => ['int', 'num'=>'GMP|string|int'], 'gmp_sqrt' => ['GMP', 'num'=>'GMP|string|int'], 'gmp_sqrtrem' => ['array{0: GMP, 1: GMP}', 'num'=>'GMP|string|int'], 'gmp_strval' => ['numeric-string', 'num'=>'GMP|string|int', 'base='=>'int'], 'gmp_sub' => ['GMP', 'num1'=>'GMP|string|int', 'num2'=>'GMP|string|int'], 'gmp_testbit' => ['bool', 'num'=>'GMP|string|int', 'index'=>'int'], 'gmp_xor' => ['GMP', 'num1'=>'GMP|string|int', 'num2'=>'GMP|string|int'], 'gmstrftime' => ['string|false', 'format'=>'string', 'timestamp='=>'?int'], 'gnupg::adddecryptkey' => ['bool', 'fingerprint'=>'string', 'passphrase'=>'string'], 'gnupg::addencryptkey' => ['bool', 'fingerprint'=>'string'], 'gnupg::addsignkey' => ['bool', 'fingerprint'=>'string', 'passphrase='=>'string'], 'gnupg::cleardecryptkeys' => ['bool'], 'gnupg::clearencryptkeys' => ['bool'], 'gnupg::clearsignkeys' => ['bool'], 'gnupg::decrypt' => ['string|false', 'text'=>'string'], 'gnupg::decryptverify' => ['array|false', 'text'=>'string', '&plaintext'=>'string'], 'gnupg::encrypt' => ['string|false', 'plaintext'=>'string'], 'gnupg::encryptsign' => ['string|false', 'plaintext'=>'string'], 'gnupg::export' => ['string|false', 'fingerprint'=>'string'], 'gnupg::geterror' => ['string|false'], 'gnupg::getprotocol' => ['int'], 'gnupg::import' => ['array|false', 'keydata'=>'string'], 'gnupg::keyinfo' => ['array', 'pattern'=>'string'], 'gnupg::setarmor' => ['bool', 'armor'=>'int'], 'gnupg::seterrormode' => ['void', 'errormode'=>'int'], 'gnupg::setsignmode' => ['bool', 'signmode'=>'int'], 'gnupg::sign' => ['string|false', 'plaintext'=>'string'], 'gnupg::verify' => ['array|false', 'signed_text'=>'string', 'signature'=>'string', '&plaintext='=>'string'], 'gnupg_adddecryptkey' => ['bool', 'identifier'=>'resource', 'fingerprint'=>'string', 'passphrase'=>'string'], 'gnupg_addencryptkey' => ['bool', 'identifier'=>'resource', 'fingerprint'=>'string'], 'gnupg_addsignkey' => ['bool', 'identifier'=>'resource', 'fingerprint'=>'string', 'passphrase='=>'string'], 'gnupg_cleardecryptkeys' => ['bool', 'identifier'=>'resource'], 'gnupg_clearencryptkeys' => ['bool', 'identifier'=>'resource'], 'gnupg_clearsignkeys' => ['bool', 'identifier'=>'resource'], 'gnupg_decrypt' => ['string', 'identifier'=>'resource', 'text'=>'string'], 'gnupg_decryptverify' => ['array', 'identifier'=>'resource', 'text'=>'string', 'plaintext'=>'string'], 'gnupg_encrypt' => ['string', 'identifier'=>'resource', 'plaintext'=>'string'], 'gnupg_encryptsign' => ['string', 'identifier'=>'resource', 'plaintext'=>'string'], 'gnupg_export' => ['string', 'identifier'=>'resource', 'fingerprint'=>'string'], 'gnupg_geterror' => ['string', 'identifier'=>'resource'], 'gnupg_getprotocol' => ['int', 'identifier'=>'resource'], 'gnupg_import' => ['array', 'identifier'=>'resource', 'keydata'=>'string'], 'gnupg_init' => ['resource'], 'gnupg_keyinfo' => ['array', 'identifier'=>'resource', 'pattern'=>'string'], 'gnupg_setarmor' => ['bool', 'identifier'=>'resource', 'armor'=>'int'], 'gnupg_seterrormode' => ['void', 'identifier'=>'resource', 'errormode'=>'int'], 'gnupg_setsignmode' => ['bool', 'identifier'=>'resource', 'signmode'=>'int'], 'gnupg_sign' => ['string', 'identifier'=>'resource', 'plaintext'=>'string'], 'gnupg_verify' => ['array', 'identifier'=>'resource', 'signed_text'=>'string', 'signature'=>'string', 'plaintext='=>'string'], 'gopher_parsedir' => ['array', 'dirent'=>'string'], 'grapheme_extract' => ['string|false', 'haystack'=>'string', 'size'=>'int', 'type='=>'int', 'offset='=>'int', '&w_next='=>'int'], 'grapheme_stripos' => ['int|false', 'haystack'=>'string', 'needle'=>'string', 'offset='=>'int'], 'grapheme_stristr' => ['string|false', 'haystack'=>'string', 'needle'=>'string', 'beforeNeedle='=>'bool'], 'grapheme_strlen' => ['0|positive-int|false|null', 'string'=>'string'], 'grapheme_strpos' => ['int|false', 'haystack'=>'string', 'needle'=>'string', 'offset='=>'int'], 'grapheme_strripos' => ['int|false', 'haystack'=>'string', 'needle'=>'string', 'offset='=>'int'], 'grapheme_strrpos' => ['int|false', 'haystack'=>'string', 'needle'=>'string', 'offset='=>'int'], 'grapheme_strstr' => ['string|false', 'haystack'=>'string', 'needle'=>'string', 'beforeNeedle='=>'bool'], 'grapheme_substr' => ['string|false', 'string'=>'string', 'offset'=>'int', 'length='=>'?int'], 'gregoriantojd' => ['int', 'month'=>'int', 'day'=>'int', 'year'=>'int'], 'gridObj::set' => ['int', 'property_name'=>'string', 'new_value'=>''], 'Grpc\Call::__construct' => ['void', 'channel'=>'Grpc\Channel', 'method'=>'string', 'absolute_deadline'=>'Grpc\Timeval', 'host_override='=>'mixed'], 'Grpc\Call::cancel' => [''], 'Grpc\Call::getPeer' => ['string'], 'Grpc\Call::setCredentials' => ['int', 'creds_obj'=>'Grpc\CallCredentials'], 'Grpc\Call::startBatch' => ['object', 'batch'=>'array'], 'Grpc\CallCredentials::createComposite' => ['Grpc\CallCredentials', 'cred1'=>'Grpc\CallCredentials', 'cred2'=>'Grpc\CallCredentials'], 'Grpc\CallCredentials::createFromPlugin' => ['Grpc\CallCredentials', 'callback'=>'Closure'], 'Grpc\Channel::__construct' => ['void', 'target'=>'string', 'args='=>'array'], 'Grpc\Channel::close' => [''], 'Grpc\Channel::getConnectivityState' => ['int', 'try_to_connect='=>'bool'], 'Grpc\Channel::getTarget' => ['string'], 'Grpc\Channel::watchConnectivityState' => ['bool', 'last_state'=>'int', 'deadline_obj'=>'Grpc\Timeval'], 'Grpc\ChannelCredentials::createComposite' => ['Grpc\ChannelCredentials', 'cred1'=>'Grpc\ChannelCredentials', 'cred2'=>'Grpc\CallCredentials'], 'Grpc\ChannelCredentials::createDefault' => ['Grpc\ChannelCredentials'], 'Grpc\ChannelCredentials::createInsecure' => ['null'], 'Grpc\ChannelCredentials::createSsl' => ['Grpc\ChannelCredentials', 'pem_root_certs'=>'string', 'pem_private_key='=>'string', 'pem_cert_chain='=>'string'], 'Grpc\ChannelCredentials::setDefaultRootsPem' => ['', 'pem_roots'=>'string'], 'Grpc\Server::__construct' => ['void', 'args'=>'array'], 'Grpc\Server::addHttp2Port' => ['bool', 'addr'=>'string'], 'Grpc\Server::addSecureHttp2Port' => ['bool', 'addr'=>'string', 'creds_obj'=>'Grpc\ServerCredentials'], 'Grpc\Server::requestCall' => ['', 'tag_new'=>'int', 'tag_cancel'=>'int'], 'Grpc\Server::start' => [''], 'Grpc\ServerCredentials::createSsl' => ['object', 'pem_root_certs'=>'string', 'pem_private_key'=>'string', 'pem_cert_chain'=>'string'], 'Grpc\Timeval::__construct' => ['void', 'usec'=>'int'], 'Grpc\Timeval::add' => ['Grpc\Timeval', 'other'=>'Grpc\Timeval'], 'Grpc\Timeval::compare' => ['int', 'a'=>'Grpc\Timeval', 'b'=>'Grpc\Timeval'], 'Grpc\Timeval::infFuture' => ['Grpc\Timeval'], 'Grpc\Timeval::infPast' => ['Grpc\Timeval'], 'Grpc\Timeval::now' => ['Grpc\Timeval'], 'Grpc\Timeval::similar' => ['bool', 'a'=>'Grpc\Timeval', 'b'=>'Grpc\Timeval', 'threshold'=>'Grpc\Timeval'], 'Grpc\Timeval::sleepUntil' => [''], 'Grpc\Timeval::subtract' => ['Grpc\Timeval', 'other'=>'Grpc\Timeval'], 'Grpc\Timeval::zero' => ['Grpc\Timeval'], 'gupnp_context_get_host_ip' => ['string', 'context'=>'resource'], 'gupnp_context_get_port' => ['int', 'context'=>'resource'], 'gupnp_context_get_subscription_timeout' => ['int', 'context'=>'resource'], 'gupnp_context_host_path' => ['bool', 'context'=>'resource', 'local_path'=>'string', 'server_path'=>'string'], 'gupnp_context_new' => ['resource', 'host_ip='=>'string', 'port='=>'int'], 'gupnp_context_set_subscription_timeout' => ['void', 'context'=>'resource', 'timeout'=>'int'], 'gupnp_context_timeout_add' => ['bool', 'context'=>'resource', 'timeout'=>'int', 'callback'=>'mixed', 'arg='=>'mixed'], 'gupnp_context_unhost_path' => ['bool', 'context'=>'resource', 'server_path'=>'string'], 'gupnp_control_point_browse_start' => ['bool', 'cpoint'=>'resource'], 'gupnp_control_point_browse_stop' => ['bool', 'cpoint'=>'resource'], 'gupnp_control_point_callback_set' => ['bool', 'cpoint'=>'resource', 'signal'=>'int', 'callback'=>'mixed', 'arg='=>'mixed'], 'gupnp_control_point_new' => ['resource', 'context'=>'resource', 'target'=>'string'], 'gupnp_device_action_callback_set' => ['bool', 'root_device'=>'resource', 'signal'=>'int', 'action_name'=>'string', 'callback'=>'mixed', 'arg='=>'mixed'], 'gupnp_device_info_get' => ['array', 'root_device'=>'resource'], 'gupnp_device_info_get_service' => ['resource', 'root_device'=>'resource', 'type'=>'string'], 'gupnp_root_device_get_available' => ['bool', 'root_device'=>'resource'], 'gupnp_root_device_get_relative_location' => ['string', 'root_device'=>'resource'], 'gupnp_root_device_new' => ['resource', 'context'=>'resource', 'location'=>'string', 'description_dir'=>'string'], 'gupnp_root_device_set_available' => ['bool', 'root_device'=>'resource', 'available'=>'bool'], 'gupnp_root_device_start' => ['bool', 'root_device'=>'resource'], 'gupnp_root_device_stop' => ['bool', 'root_device'=>'resource'], 'gupnp_service_action_get' => ['mixed', 'action'=>'resource', 'name'=>'string', 'type'=>'int'], 'gupnp_service_action_return' => ['bool', 'action'=>'resource'], 'gupnp_service_action_return_error' => ['bool', 'action'=>'resource', 'error_code'=>'int', 'error_description='=>'string'], 'gupnp_service_action_set' => ['bool', 'action'=>'resource', 'name'=>'string', 'type'=>'int', 'value'=>'mixed'], 'gupnp_service_freeze_notify' => ['bool', 'service'=>'resource'], 'gupnp_service_info_get' => ['array', 'proxy'=>'resource'], 'gupnp_service_info_get_introspection' => ['mixed', 'proxy'=>'resource', 'callback='=>'mixed', 'arg='=>'mixed'], 'gupnp_service_introspection_get_state_variable' => ['array', 'introspection'=>'resource', 'variable_name'=>'string'], 'gupnp_service_notify' => ['bool', 'service'=>'resource', 'name'=>'string', 'type'=>'int', 'value'=>'mixed'], 'gupnp_service_proxy_action_get' => ['mixed', 'proxy'=>'resource', 'action'=>'string', 'name'=>'string', 'type'=>'int'], 'gupnp_service_proxy_action_set' => ['bool', 'proxy'=>'resource', 'action'=>'string', 'name'=>'string', 'value'=>'mixed', 'type'=>'int'], 'gupnp_service_proxy_add_notify' => ['bool', 'proxy'=>'resource', 'value'=>'string', 'type'=>'int', 'callback'=>'mixed', 'arg='=>'mixed'], 'gupnp_service_proxy_callback_set' => ['bool', 'proxy'=>'resource', 'signal'=>'int', 'callback'=>'mixed', 'arg='=>'mixed'], 'gupnp_service_proxy_get_subscribed' => ['bool', 'proxy'=>'resource'], 'gupnp_service_proxy_remove_notify' => ['bool', 'proxy'=>'resource', 'value'=>'string'], 'gupnp_service_proxy_send_action' => ['array', 'proxy'=>'resource', 'action'=>'string', 'in_params'=>'array', 'out_params'=>'array'], 'gupnp_service_proxy_set_subscribed' => ['bool', 'proxy'=>'resource', 'subscribed'=>'bool'], 'gupnp_service_thaw_notify' => ['bool', 'service'=>'resource'], 'gzclose' => ['bool', 'stream'=>'resource'], 'gzcompress' => ['string|false', 'data'=>'string', 'level='=>'int', 'encoding='=>'int'], 'gzdecode' => ['string|false', 'data'=>'string', 'max_length='=>'int'], 'gzdeflate' => ['string|false', 'data'=>'string', 'level='=>'int', 'encoding='=>'int'], 'gzencode' => ['string|false', 'data'=>'string', 'level='=>'int', 'encoding='=>'int'], 'gzeof' => ['bool', 'stream'=>'resource'], 'gzfile' => ['list|false', 'filename'=>'string', 'use_include_path='=>'int'], 'gzgetc' => ['string|false', 'stream'=>'resource'], 'gzgets' => ['string|false', 'stream'=>'resource', 'length='=>'?int'], 'gzinflate' => ['string|false', 'data'=>'string', 'max_length='=>'int'], 'gzopen' => ['resource|false', 'filename'=>'string', 'mode'=>'string', 'use_include_path='=>'int'], 'gzpassthru' => ['int', 'stream'=>'resource'], 'gzputs' => ['int|false', 'stream'=>'resource', 'data'=>'string', 'length='=>'?int'], 'gzread' => ['string|false', 'stream'=>'resource', 'length'=>'int'], 'gzrewind' => ['bool', 'stream'=>'resource'], 'gzseek' => ['int', 'stream'=>'resource', 'offset'=>'int', 'whence='=>'int'], 'gztell' => ['int|false', 'stream'=>'resource'], 'gzuncompress' => ['string|false', 'data'=>'string', 'max_length='=>'int'], 'gzwrite' => ['int|false', 'stream'=>'resource', 'data'=>'string', 'length='=>'?int'], 'HaruAnnotation::setBorderStyle' => ['bool', 'width'=>'float', 'dash_on'=>'int', 'dash_off'=>'int'], 'HaruAnnotation::setHighlightMode' => ['bool', 'mode'=>'int'], 'HaruAnnotation::setIcon' => ['bool', 'icon'=>'int'], 'HaruAnnotation::setOpened' => ['bool', 'opened'=>'bool'], 'HaruDestination::setFit' => ['bool'], 'HaruDestination::setFitB' => ['bool'], 'HaruDestination::setFitBH' => ['bool', 'top'=>'float'], 'HaruDestination::setFitBV' => ['bool', 'left'=>'float'], 'HaruDestination::setFitH' => ['bool', 'top'=>'float'], 'HaruDestination::setFitR' => ['bool', 'left'=>'float', 'bottom'=>'float', 'right'=>'float', 'top'=>'float'], 'HaruDestination::setFitV' => ['bool', 'left'=>'float'], 'HaruDestination::setXYZ' => ['bool', 'left'=>'float', 'top'=>'float', 'zoom'=>'float'], 'HaruDoc::__construct' => ['void'], 'HaruDoc::addPage' => ['object'], 'HaruDoc::addPageLabel' => ['bool', 'first_page'=>'int', 'style'=>'int', 'first_num'=>'int', 'prefix='=>'string'], 'HaruDoc::createOutline' => ['object', 'title'=>'string', 'parent_outline='=>'object', 'encoder='=>'object'], 'HaruDoc::getCurrentEncoder' => ['object'], 'HaruDoc::getCurrentPage' => ['object'], 'HaruDoc::getEncoder' => ['object', 'encoding'=>'string'], 'HaruDoc::getFont' => ['object', 'fontname'=>'string', 'encoding='=>'string'], 'HaruDoc::getInfoAttr' => ['string', 'type'=>'int'], 'HaruDoc::getPageLayout' => ['int'], 'HaruDoc::getPageMode' => ['int'], 'HaruDoc::getStreamSize' => ['int'], 'HaruDoc::insertPage' => ['object', 'page'=>'object'], 'HaruDoc::loadJPEG' => ['object', 'filename'=>'string'], 'HaruDoc::loadPNG' => ['object', 'filename'=>'string', 'deferred='=>'bool'], 'HaruDoc::loadRaw' => ['object', 'filename'=>'string', 'width'=>'int', 'height'=>'int', 'color_space'=>'int'], 'HaruDoc::loadTTC' => ['string', 'fontfile'=>'string', 'index'=>'int', 'embed='=>'bool'], 'HaruDoc::loadTTF' => ['string', 'fontfile'=>'string', 'embed='=>'bool'], 'HaruDoc::loadType1' => ['string', 'afmfile'=>'string', 'pfmfile='=>'string'], 'HaruDoc::output' => ['bool'], 'HaruDoc::readFromStream' => ['string', 'bytes'=>'int'], 'HaruDoc::resetError' => ['bool'], 'HaruDoc::resetStream' => ['bool'], 'HaruDoc::save' => ['bool', 'file'=>'string'], 'HaruDoc::saveToStream' => ['bool'], 'HaruDoc::setCompressionMode' => ['bool', 'mode'=>'int'], 'HaruDoc::setCurrentEncoder' => ['bool', 'encoding'=>'string'], 'HaruDoc::setEncryptionMode' => ['bool', 'mode'=>'int', 'key_len='=>'int'], 'HaruDoc::setInfoAttr' => ['bool', 'type'=>'int', 'info'=>'string'], 'HaruDoc::setInfoDateAttr' => ['bool', 'type'=>'int', 'year'=>'int', 'month'=>'int', 'day'=>'int', 'hour'=>'int', 'min'=>'int', 'sec'=>'int', 'ind'=>'string', 'off_hour'=>'int', 'off_min'=>'int'], 'HaruDoc::setOpenAction' => ['bool', 'destination'=>'object'], 'HaruDoc::setPageLayout' => ['bool', 'layout'=>'int'], 'HaruDoc::setPageMode' => ['bool', 'mode'=>'int'], 'HaruDoc::setPagesConfiguration' => ['bool', 'page_per_pages'=>'int'], 'HaruDoc::setPassword' => ['bool', 'owner_password'=>'string', 'user_password'=>'string'], 'HaruDoc::setPermission' => ['bool', 'permission'=>'int'], 'HaruDoc::useCNSEncodings' => ['bool'], 'HaruDoc::useCNSFonts' => ['bool'], 'HaruDoc::useCNTEncodings' => ['bool'], 'HaruDoc::useCNTFonts' => ['bool'], 'HaruDoc::useJPEncodings' => ['bool'], 'HaruDoc::useJPFonts' => ['bool'], 'HaruDoc::useKREncodings' => ['bool'], 'HaruDoc::useKRFonts' => ['bool'], 'HaruEncoder::getByteType' => ['int', 'text'=>'string', 'index'=>'int'], 'HaruEncoder::getType' => ['int'], 'HaruEncoder::getUnicode' => ['int', 'character'=>'int'], 'HaruEncoder::getWritingMode' => ['int'], 'HaruFont::getAscent' => ['int'], 'HaruFont::getCapHeight' => ['int'], 'HaruFont::getDescent' => ['int'], 'HaruFont::getEncodingName' => ['string'], 'HaruFont::getFontName' => ['string'], 'HaruFont::getTextWidth' => ['array', 'text'=>'string'], 'HaruFont::getUnicodeWidth' => ['int', 'character'=>'int'], 'HaruFont::getXHeight' => ['int'], 'HaruFont::measureText' => ['int', 'text'=>'string', 'width'=>'float', 'font_size'=>'float', 'char_space'=>'float', 'word_space'=>'float', 'word_wrap='=>'bool'], 'HaruImage::getBitsPerComponent' => ['int'], 'HaruImage::getColorSpace' => ['string'], 'HaruImage::getHeight' => ['int'], 'HaruImage::getSize' => ['array'], 'HaruImage::getWidth' => ['int'], 'HaruImage::setColorMask' => ['bool', 'rmin'=>'int', 'rmax'=>'int', 'gmin'=>'int', 'gmax'=>'int', 'bmin'=>'int', 'bmax'=>'int'], 'HaruImage::setMaskImage' => ['bool', 'mask_image'=>'object'], 'HaruOutline::setDestination' => ['bool', 'destination'=>'object'], 'HaruOutline::setOpened' => ['bool', 'opened'=>'bool'], 'HaruPage::arc' => ['bool', 'x'=>'float', 'y'=>'float', 'ray'=>'float', 'ang1'=>'float', 'ang2'=>'float'], 'HaruPage::beginText' => ['bool'], 'HaruPage::circle' => ['bool', 'x'=>'float', 'y'=>'float', 'ray'=>'float'], 'HaruPage::closePath' => ['bool'], 'HaruPage::concat' => ['bool', 'a'=>'float', 'b'=>'float', 'c'=>'float', 'd'=>'float', 'x'=>'float', 'y'=>'float'], 'HaruPage::createDestination' => ['object'], 'HaruPage::createLinkAnnotation' => ['object', 'rectangle'=>'array', 'destination'=>'object'], 'HaruPage::createTextAnnotation' => ['object', 'rectangle'=>'array', 'text'=>'string', 'encoder='=>'object'], 'HaruPage::createURLAnnotation' => ['object', 'rectangle'=>'array', 'url'=>'string'], 'HaruPage::curveTo' => ['bool', 'x1'=>'float', 'y1'=>'float', 'x2'=>'float', 'y2'=>'float', 'x3'=>'float', 'y3'=>'float'], 'HaruPage::curveTo2' => ['bool', 'x2'=>'float', 'y2'=>'float', 'x3'=>'float', 'y3'=>'float'], 'HaruPage::curveTo3' => ['bool', 'x1'=>'float', 'y1'=>'float', 'x3'=>'float', 'y3'=>'float'], 'HaruPage::drawImage' => ['bool', 'image'=>'object', 'x'=>'float', 'y'=>'float', 'width'=>'float', 'height'=>'float'], 'HaruPage::ellipse' => ['bool', 'x'=>'float', 'y'=>'float', 'xray'=>'float', 'yray'=>'float'], 'HaruPage::endPath' => ['bool'], 'HaruPage::endText' => ['bool'], 'HaruPage::eofill' => ['bool'], 'HaruPage::eoFillStroke' => ['bool', 'close_path='=>'bool'], 'HaruPage::fill' => ['bool'], 'HaruPage::fillStroke' => ['bool', 'close_path='=>'bool'], 'HaruPage::getCharSpace' => ['float'], 'HaruPage::getCMYKFill' => ['array'], 'HaruPage::getCMYKStroke' => ['array'], 'HaruPage::getCurrentFont' => ['object'], 'HaruPage::getCurrentFontSize' => ['float'], 'HaruPage::getCurrentPos' => ['array'], 'HaruPage::getCurrentTextPos' => ['array'], 'HaruPage::getDash' => ['array'], 'HaruPage::getFillingColorSpace' => ['int'], 'HaruPage::getFlatness' => ['float'], 'HaruPage::getGMode' => ['int'], 'HaruPage::getGrayFill' => ['float'], 'HaruPage::getGrayStroke' => ['float'], 'HaruPage::getHeight' => ['float'], 'HaruPage::getHorizontalScaling' => ['float'], 'HaruPage::getLineCap' => ['int'], 'HaruPage::getLineJoin' => ['int'], 'HaruPage::getLineWidth' => ['float'], 'HaruPage::getMiterLimit' => ['float'], 'HaruPage::getRGBFill' => ['array'], 'HaruPage::getRGBStroke' => ['array'], 'HaruPage::getStrokingColorSpace' => ['int'], 'HaruPage::getTextLeading' => ['float'], 'HaruPage::getTextMatrix' => ['array'], 'HaruPage::getTextRenderingMode' => ['int'], 'HaruPage::getTextRise' => ['float'], 'HaruPage::getTextWidth' => ['float', 'text'=>'string'], 'HaruPage::getTransMatrix' => ['array'], 'HaruPage::getWidth' => ['float'], 'HaruPage::getWordSpace' => ['float'], 'HaruPage::lineTo' => ['bool', 'x'=>'float', 'y'=>'float'], 'HaruPage::measureText' => ['int', 'text'=>'string', 'width'=>'float', 'wordwrap='=>'bool'], 'HaruPage::moveTextPos' => ['bool', 'x'=>'float', 'y'=>'float', 'set_leading='=>'bool'], 'HaruPage::moveTo' => ['bool', 'x'=>'float', 'y'=>'float'], 'HaruPage::moveToNextLine' => ['bool'], 'HaruPage::rectangle' => ['bool', 'x'=>'float', 'y'=>'float', 'width'=>'float', 'height'=>'float'], 'HaruPage::setCharSpace' => ['bool', 'char_space'=>'float'], 'HaruPage::setCMYKFill' => ['bool', 'c'=>'float', 'm'=>'float', 'y'=>'float', 'k'=>'float'], 'HaruPage::setCMYKStroke' => ['bool', 'c'=>'float', 'm'=>'float', 'y'=>'float', 'k'=>'float'], 'HaruPage::setDash' => ['bool', 'pattern'=>'array', 'phase'=>'int'], 'HaruPage::setFlatness' => ['bool', 'flatness'=>'float'], 'HaruPage::setFontAndSize' => ['bool', 'font'=>'object', 'size'=>'float'], 'HaruPage::setGrayFill' => ['bool', 'value'=>'float'], 'HaruPage::setGrayStroke' => ['bool', 'value'=>'float'], 'HaruPage::setHeight' => ['bool', 'height'=>'float'], 'HaruPage::setHorizontalScaling' => ['bool', 'scaling'=>'float'], 'HaruPage::setLineCap' => ['bool', 'cap'=>'int'], 'HaruPage::setLineJoin' => ['bool', 'join'=>'int'], 'HaruPage::setLineWidth' => ['bool', 'width'=>'float'], 'HaruPage::setMiterLimit' => ['bool', 'limit'=>'float'], 'HaruPage::setRGBFill' => ['bool', 'r'=>'float', 'g'=>'float', 'b'=>'float'], 'HaruPage::setRGBStroke' => ['bool', 'r'=>'float', 'g'=>'float', 'b'=>'float'], 'HaruPage::setRotate' => ['bool', 'angle'=>'int'], 'HaruPage::setSize' => ['bool', 'size'=>'int', 'direction'=>'int'], 'HaruPage::setSlideShow' => ['bool', 'type'=>'int', 'disp_time'=>'float', 'trans_time'=>'float'], 'HaruPage::setTextLeading' => ['bool', 'text_leading'=>'float'], 'HaruPage::setTextMatrix' => ['bool', 'a'=>'float', 'b'=>'float', 'c'=>'float', 'd'=>'float', 'x'=>'float', 'y'=>'float'], 'HaruPage::setTextRenderingMode' => ['bool', 'mode'=>'int'], 'HaruPage::setTextRise' => ['bool', 'rise'=>'float'], 'HaruPage::setWidth' => ['bool', 'width'=>'float'], 'HaruPage::setWordSpace' => ['bool', 'word_space'=>'float'], 'HaruPage::showText' => ['bool', 'text'=>'string'], 'HaruPage::showTextNextLine' => ['bool', 'text'=>'string', 'word_space='=>'float', 'char_space='=>'float'], 'HaruPage::stroke' => ['bool', 'close_path='=>'bool'], 'HaruPage::textOut' => ['bool', 'x'=>'float', 'y'=>'float', 'text'=>'string'], 'HaruPage::textRect' => ['bool', 'left'=>'float', 'top'=>'float', 'right'=>'float', 'bottom'=>'float', 'text'=>'string', 'align='=>'int'], 'hash' => ['non-empty-string', 'algo'=>'string', 'data'=>'string', 'binary='=>'bool', 'options='=>'array{seed:scalar}'], 'hash_algos' => ['list'], 'hash_copy' => ['HashContext', 'context'=>'HashContext'], 'hash_equals' => ['bool', 'known_string'=>'string', 'user_string'=>'string'], 'hash_file' => ['non-empty-string|false', 'algo'=>'string', 'filename'=>'string', 'binary='=>'bool', 'options='=>'array{seed:scalar}'], 'hash_final' => ['non-empty-string', 'context'=>'HashContext', 'binary='=>'bool'], 'hash_hkdf' => ['non-empty-string', 'algo'=>'string', 'key'=>'string', 'length='=>'int', 'info='=>'string', 'salt='=>'string'], 'hash_hmac' => ['non-empty-string', 'algo'=>'string', 'data'=>'string', 'key'=>'string', 'binary='=>'bool'], 'hash_hmac_algos' => ['list'], 'hash_hmac_file' => ['non-empty-string', 'algo'=>'string', 'filename'=>'string', 'key'=>'string', 'binary='=>'bool'], 'hash_init' => ['HashContext', 'algo'=>'string', 'flags='=>'int', 'key='=>'string', 'options='=>'array{seed:scalar}'], 'hash_pbkdf2' => ['non-empty-string', 'algo'=>'string', 'password'=>'string', 'salt'=>'string', 'iterations'=>'int', 'length='=>'int', 'binary='=>'bool', 'options=' => 'array'], 'hash_update' => ['bool', 'context'=>'HashContext', 'data'=>'string'], 'hash_update_file' => ['bool', 'context'=>'HashContext', 'filename'=>'string', 'stream_context='=>'?resource'], 'hash_update_stream' => ['int', 'context'=>'HashContext', 'stream'=>'resource', 'length='=>'int'], 'hashTableObj::clear' => ['void'], 'hashTableObj::get' => ['string', 'key'=>'string'], 'hashTableObj::nextkey' => ['string', 'previousKey'=>'string'], 'hashTableObj::remove' => ['int', 'key'=>'string'], 'hashTableObj::set' => ['int', 'key'=>'string', 'value'=>'string'], 'header' => ['void', 'header'=>'string', 'replace='=>'bool', 'response_code='=>'int'], 'header_register_callback' => ['bool', 'callback'=>'callable():void'], 'header_remove' => ['void', 'name='=>'?string'], 'headers_list' => ['list'], 'headers_sent' => ['bool', '&w_filename='=>'string', '&w_line='=>'int'], 'hebrev' => ['string', 'string'=>'string', 'max_chars_per_line='=>'int'], 'hebrevc' => ['string', 'string'=>'string', 'max_chars_per_line='=>'int'], 'hex2bin' => ['string|false', 'string'=>'string'], 'hexdec' => ['int|float', 'hex_string'=>'string'], 'highlight_file' => ['string|bool', 'filename'=>'string', 'return='=>'bool'], 'highlight_string' => ['string|bool', 'string'=>'string', 'return='=>'bool'], 'hrtime' => ['array{0:int,1:int}|false', 'as_number='=>'false'], 'hrtime\'1' => ['int|float|false', 'as_number='=>'true'], 'HRTime\PerformanceCounter::getElapsedTicks' => ['int'], 'HRTime\PerformanceCounter::getFrequency' => ['int'], 'HRTime\PerformanceCounter::getLastElapsedTicks' => ['int'], 'HRTime\PerformanceCounter::getTicks' => ['int'], 'HRTime\PerformanceCounter::getTicksSince' => ['int', 'start'=>'int'], 'HRTime\PerformanceCounter::isRunning' => ['bool'], 'HRTime\PerformanceCounter::start' => ['void'], 'HRTime\PerformanceCounter::stop' => ['void'], 'HRTime\StopWatch::getElapsedTicks' => ['int'], 'HRTime\StopWatch::getElapsedTime' => ['float', 'unit='=>'int'], 'HRTime\StopWatch::getLastElapsedTicks' => ['int'], 'HRTime\StopWatch::getLastElapsedTime' => ['float', 'unit='=>'int'], 'HRTime\StopWatch::isRunning' => ['bool'], 'HRTime\StopWatch::start' => ['void'], 'HRTime\StopWatch::stop' => ['void'], 'html_entity_decode' => ['string', 'string'=>'string', 'flags='=>'int', 'encoding='=>'?string'], 'htmlentities' => ['string', 'string'=>'string', 'flags='=>'int', 'encoding='=>'?string', 'double_encode='=>'bool'], 'htmlspecialchars' => ['string', 'string'=>'string', 'flags='=>'int', 'encoding='=>'string|null', 'double_encode='=>'bool'], 'htmlspecialchars_decode' => ['string', 'string'=>'string', 'flags='=>'int'], 'http\Client::__construct' => ['void', 'driver='=>'string', 'persistent_handle_id='=>'string'], 'http\Client::addCookies' => ['http\Client', 'cookies='=>'?array'], 'http\Client::addSslOptions' => ['http\Client', 'ssl_options='=>'?array'], 'http\Client::attach' => ['void', 'observer'=>'SplObserver'], 'http\Client::configure' => ['http\Client', 'settings'=>'array'], 'http\Client::count' => ['int'], 'http\Client::dequeue' => ['http\Client', 'request'=>'http\Client\Request'], 'http\Client::detach' => ['void', 'observer'=>'SplObserver'], 'http\Client::enableEvents' => ['http\Client', 'enable='=>'mixed'], 'http\Client::enablePipelining' => ['http\Client', 'enable='=>'mixed'], 'http\Client::enqueue' => ['http\Client', 'request'=>'http\Client\Request', 'callable='=>'mixed'], 'http\Client::getAvailableConfiguration' => ['array'], 'http\Client::getAvailableDrivers' => ['array'], 'http\Client::getAvailableOptions' => ['array'], 'http\Client::getCookies' => ['array'], 'http\Client::getHistory' => ['http\Message'], 'http\Client::getObservers' => ['SplObjectStorage'], 'http\Client::getOptions' => ['array'], 'http\Client::getProgressInfo' => ['null|object', 'request'=>'http\Client\Request'], 'http\Client::getResponse' => ['http\Client\Response|null', 'request='=>'?http\Client\Request'], 'http\Client::getSslOptions' => ['array'], 'http\Client::getTransferInfo' => ['object', 'request'=>'http\Client\Request'], 'http\Client::notify' => ['void', 'request='=>'?http\Client\Request'], 'http\Client::once' => ['bool'], 'http\Client::requeue' => ['http\Client', 'request'=>'http\Client\Request', 'callable='=>'mixed'], 'http\Client::reset' => ['http\Client'], 'http\Client::send' => ['http\Client'], 'http\Client::setCookies' => ['http\Client', 'cookies='=>'?array'], 'http\Client::setDebug' => ['http\Client', 'callback'=>'callable'], 'http\Client::setOptions' => ['http\Client', 'options='=>'?array'], 'http\Client::setSslOptions' => ['http\Client', 'ssl_option='=>'?array'], 'http\Client::wait' => ['bool', 'timeout='=>'mixed'], 'http\Client\Curl\User::init' => ['', 'run'=>'callable'], 'http\Client\Curl\User::once' => [''], 'http\Client\Curl\User::send' => [''], 'http\Client\Curl\User::socket' => ['', 'socket'=>'resource', 'action'=>'int'], 'http\Client\Curl\User::timer' => ['', 'timeout_ms'=>'int'], 'http\Client\Curl\User::wait' => ['', 'timeout_ms='=>'mixed'], 'http\Client\Request::__construct' => ['void', 'method='=>'mixed', 'url='=>'mixed', 'headers='=>'?array', 'body='=>'?http\Message\Body'], 'http\Client\Request::__toString' => ['string'], 'http\Client\Request::addBody' => ['http\Message', 'body'=>'http\Message\Body'], 'http\Client\Request::addHeader' => ['http\Message', 'header'=>'string', 'value'=>'mixed'], 'http\Client\Request::addHeaders' => ['http\Message', 'headers'=>'array', 'append='=>'mixed'], 'http\Client\Request::addQuery' => ['http\Client\Request', 'query_data'=>'mixed'], 'http\Client\Request::addSslOptions' => ['http\Client\Request', 'ssl_options='=>'?array'], 'http\Client\Request::count' => ['int'], 'http\Client\Request::current' => ['mixed'], 'http\Client\Request::detach' => ['http\Message'], 'http\Client\Request::getBody' => ['http\Message\Body'], 'http\Client\Request::getContentType' => ['null|string'], 'http\Client\Request::getHeader' => ['http\Header|mixed', 'header'=>'string', 'into_class='=>'mixed'], 'http\Client\Request::getHeaders' => ['array'], 'http\Client\Request::getHttpVersion' => ['string'], 'http\Client\Request::getInfo' => ['null|string'], 'http\Client\Request::getOptions' => ['array'], 'http\Client\Request::getParentMessage' => ['http\Message'], 'http\Client\Request::getQuery' => ['null|string'], 'http\Client\Request::getRequestMethod' => ['false|string'], 'http\Client\Request::getRequestUrl' => ['false|string'], 'http\Client\Request::getResponseCode' => ['false|int'], 'http\Client\Request::getResponseStatus' => ['false|string'], 'http\Client\Request::getSslOptions' => ['array'], 'http\Client\Request::getType' => ['int'], 'http\Client\Request::isMultipart' => ['bool', '&boundary='=>'mixed'], 'http\Client\Request::key' => ['int|string'], 'http\Client\Request::next' => ['void'], 'http\Client\Request::prepend' => ['http\Message', 'message'=>'http\Message', 'top='=>'mixed'], 'http\Client\Request::reverse' => ['http\Message'], 'http\Client\Request::rewind' => ['void'], 'http\Client\Request::serialize' => ['string'], 'http\Client\Request::setBody' => ['http\Message', 'body'=>'http\Message\Body'], 'http\Client\Request::setContentType' => ['http\Client\Request', 'content_type'=>'string'], 'http\Client\Request::setHeader' => ['http\Message', 'header'=>'string', 'value='=>'mixed'], 'http\Client\Request::setHeaders' => ['http\Message', 'headers'=>'array'], 'http\Client\Request::setHttpVersion' => ['http\Message', 'http_version'=>'string'], 'http\Client\Request::setInfo' => ['http\Message', 'http_info'=>'string'], 'http\Client\Request::setOptions' => ['http\Client\Request', 'options='=>'?array'], 'http\Client\Request::setQuery' => ['http\Client\Request', 'query_data='=>'mixed'], 'http\Client\Request::setRequestMethod' => ['http\Message', 'request_method'=>'string'], 'http\Client\Request::setRequestUrl' => ['http\Message', 'url'=>'string'], 'http\Client\Request::setResponseCode' => ['http\Message', 'response_code'=>'int', 'strict='=>'mixed'], 'http\Client\Request::setResponseStatus' => ['http\Message', 'response_status'=>'string'], 'http\Client\Request::setSslOptions' => ['http\Client\Request', 'ssl_options='=>'?array'], 'http\Client\Request::setType' => ['http\Message', 'type'=>'int'], 'http\Client\Request::splitMultipartBody' => ['http\Message'], 'http\Client\Request::toCallback' => ['http\Message', 'callback'=>'callable'], 'http\Client\Request::toStream' => ['http\Message', 'stream'=>'resource'], 'http\Client\Request::toString' => ['string', 'include_parent='=>'mixed'], 'http\Client\Request::unserialize' => ['void', 'serialized'=>'string'], 'http\Client\Request::valid' => ['bool'], 'http\Client\Response::__construct' => ['Iterator'], 'http\Client\Response::__toString' => ['string'], 'http\Client\Response::addBody' => ['http\Message', 'body'=>'http\Message\Body'], 'http\Client\Response::addHeader' => ['http\Message', 'header'=>'string', 'value'=>'mixed'], 'http\Client\Response::addHeaders' => ['http\Message', 'headers'=>'array', 'append='=>'mixed'], 'http\Client\Response::count' => ['int'], 'http\Client\Response::current' => ['mixed'], 'http\Client\Response::detach' => ['http\Message'], 'http\Client\Response::getBody' => ['http\Message\Body'], 'http\Client\Response::getCookies' => ['array', 'flags='=>'mixed', 'allowed_extras='=>'mixed'], 'http\Client\Response::getHeader' => ['http\Header|mixed', 'header'=>'string', 'into_class='=>'mixed'], 'http\Client\Response::getHeaders' => ['array'], 'http\Client\Response::getHttpVersion' => ['string'], 'http\Client\Response::getInfo' => ['null|string'], 'http\Client\Response::getParentMessage' => ['http\Message'], 'http\Client\Response::getRequestMethod' => ['false|string'], 'http\Client\Response::getRequestUrl' => ['false|string'], 'http\Client\Response::getResponseCode' => ['false|int'], 'http\Client\Response::getResponseStatus' => ['false|string'], 'http\Client\Response::getTransferInfo' => ['mixed|object', 'element='=>'mixed'], 'http\Client\Response::getType' => ['int'], 'http\Client\Response::isMultipart' => ['bool', '&boundary='=>'mixed'], 'http\Client\Response::key' => ['int|string'], 'http\Client\Response::next' => ['void'], 'http\Client\Response::prepend' => ['http\Message', 'message'=>'http\Message', 'top='=>'mixed'], 'http\Client\Response::reverse' => ['http\Message'], 'http\Client\Response::rewind' => ['void'], 'http\Client\Response::serialize' => ['string'], 'http\Client\Response::setBody' => ['http\Message', 'body'=>'http\Message\Body'], 'http\Client\Response::setHeader' => ['http\Message', 'header'=>'string', 'value='=>'mixed'], 'http\Client\Response::setHeaders' => ['http\Message', 'headers'=>'array'], 'http\Client\Response::setHttpVersion' => ['http\Message', 'http_version'=>'string'], 'http\Client\Response::setInfo' => ['http\Message', 'http_info'=>'string'], 'http\Client\Response::setRequestMethod' => ['http\Message', 'request_method'=>'string'], 'http\Client\Response::setRequestUrl' => ['http\Message', 'url'=>'string'], 'http\Client\Response::setResponseCode' => ['http\Message', 'response_code'=>'int', 'strict='=>'mixed'], 'http\Client\Response::setResponseStatus' => ['http\Message', 'response_status'=>'string'], 'http\Client\Response::setType' => ['http\Message', 'type'=>'int'], 'http\Client\Response::splitMultipartBody' => ['http\Message'], 'http\Client\Response::toCallback' => ['http\Message', 'callback'=>'callable'], 'http\Client\Response::toStream' => ['http\Message', 'stream'=>'resource'], 'http\Client\Response::toString' => ['string', 'include_parent='=>'mixed'], 'http\Client\Response::unserialize' => ['void', 'serialized'=>'string'], 'http\Client\Response::valid' => ['bool'], 'http\Cookie::__construct' => ['void', 'cookie_string='=>'mixed', 'parser_flags='=>'int', 'allowed_extras='=>'array'], 'http\Cookie::__toString' => ['string'], 'http\Cookie::addCookie' => ['http\Cookie', 'cookie_name'=>'string', 'cookie_value'=>'string'], 'http\Cookie::addCookies' => ['http\Cookie', 'cookies'=>'array'], 'http\Cookie::addExtra' => ['http\Cookie', 'extra_name'=>'string', 'extra_value'=>'string'], 'http\Cookie::addExtras' => ['http\Cookie', 'extras'=>'array'], 'http\Cookie::getCookie' => ['null|string', 'name'=>'string'], 'http\Cookie::getCookies' => ['array'], 'http\Cookie::getDomain' => ['string'], 'http\Cookie::getExpires' => ['int'], 'http\Cookie::getExtra' => ['string', 'name'=>'string'], 'http\Cookie::getExtras' => ['array'], 'http\Cookie::getFlags' => ['int'], 'http\Cookie::getMaxAge' => ['int'], 'http\Cookie::getPath' => ['string'], 'http\Cookie::setCookie' => ['http\Cookie', 'cookie_name'=>'string', 'cookie_value='=>'mixed'], 'http\Cookie::setCookies' => ['http\Cookie', 'cookies='=>'mixed'], 'http\Cookie::setDomain' => ['http\Cookie', 'value='=>'mixed'], 'http\Cookie::setExpires' => ['http\Cookie', 'value='=>'mixed'], 'http\Cookie::setExtra' => ['http\Cookie', 'extra_name'=>'string', 'extra_value='=>'mixed'], 'http\Cookie::setExtras' => ['http\Cookie', 'extras='=>'mixed'], 'http\Cookie::setFlags' => ['http\Cookie', 'value='=>'mixed'], 'http\Cookie::setMaxAge' => ['http\Cookie', 'value='=>'mixed'], 'http\Cookie::setPath' => ['http\Cookie', 'value='=>'mixed'], 'http\Cookie::toArray' => ['array'], 'http\Cookie::toString' => ['string'], 'http\Encoding\Stream::__construct' => ['void', 'flags='=>'mixed'], 'http\Encoding\Stream::done' => ['bool'], 'http\Encoding\Stream::finish' => ['string'], 'http\Encoding\Stream::flush' => ['string'], 'http\Encoding\Stream::update' => ['string', 'data'=>'string'], 'http\Encoding\Stream\Debrotli::__construct' => ['void', 'flags='=>'int'], 'http\Encoding\Stream\Debrotli::decode' => ['string', 'data'=>'string'], 'http\Encoding\Stream\Debrotli::done' => ['bool'], 'http\Encoding\Stream\Debrotli::finish' => ['string'], 'http\Encoding\Stream\Debrotli::flush' => ['string'], 'http\Encoding\Stream\Debrotli::update' => ['string', 'data'=>'string'], 'http\Encoding\Stream\Dechunk::__construct' => ['void', 'flags='=>'mixed'], 'http\Encoding\Stream\Dechunk::decode' => ['false|string', 'data'=>'string', '&decoded_len='=>'mixed'], 'http\Encoding\Stream\Dechunk::done' => ['bool'], 'http\Encoding\Stream\Dechunk::finish' => ['string'], 'http\Encoding\Stream\Dechunk::flush' => ['string'], 'http\Encoding\Stream\Dechunk::update' => ['string', 'data'=>'string'], 'http\Encoding\Stream\Deflate::__construct' => ['void', 'flags='=>'mixed'], 'http\Encoding\Stream\Deflate::done' => ['bool'], 'http\Encoding\Stream\Deflate::encode' => ['string', 'data'=>'string', 'flags='=>'mixed'], 'http\Encoding\Stream\Deflate::finish' => ['string'], 'http\Encoding\Stream\Deflate::flush' => ['string'], 'http\Encoding\Stream\Deflate::update' => ['string', 'data'=>'string'], 'http\Encoding\Stream\Enbrotli::__construct' => ['void', 'flags='=>'int'], 'http\Encoding\Stream\Enbrotli::done' => ['bool'], 'http\Encoding\Stream\Enbrotli::encode' => ['string', 'data'=>'string', 'flags='=>'int'], 'http\Encoding\Stream\Enbrotli::finish' => ['string'], 'http\Encoding\Stream\Enbrotli::flush' => ['string'], 'http\Encoding\Stream\Enbrotli::update' => ['string', 'data'=>'string'], 'http\Encoding\Stream\Inflate::__construct' => ['void', 'flags='=>'mixed'], 'http\Encoding\Stream\Inflate::decode' => ['string', 'data'=>'string'], 'http\Encoding\Stream\Inflate::done' => ['bool'], 'http\Encoding\Stream\Inflate::finish' => ['string'], 'http\Encoding\Stream\Inflate::flush' => ['string'], 'http\Encoding\Stream\Inflate::update' => ['string', 'data'=>'string'], 'http\Env::getRequestBody' => ['http\Message\Body', 'body_class_name='=>'mixed'], 'http\Env::getRequestHeader' => ['array|null|string', 'header_name='=>'mixed'], 'http\Env::getResponseCode' => ['int'], 'http\Env::getResponseHeader' => ['array|null|string', 'header_name='=>'mixed'], 'http\Env::getResponseStatusForAllCodes' => ['array'], 'http\Env::getResponseStatusForCode' => ['string', 'code'=>'int'], 'http\Env::negotiate' => ['null|string', 'params'=>'string', 'supported'=>'array', 'primary_type_separator='=>'mixed', '&result_array='=>'mixed'], 'http\Env::negotiateCharset' => ['null|string', 'supported'=>'array', '&result_array='=>'mixed'], 'http\Env::negotiateContentType' => ['null|string', 'supported'=>'array', '&result_array='=>'mixed'], 'http\Env::negotiateEncoding' => ['null|string', 'supported'=>'array', '&result_array='=>'mixed'], 'http\Env::negotiateLanguage' => ['null|string', 'supported'=>'array', '&result_array='=>'mixed'], 'http\Env::setResponseCode' => ['bool', 'code'=>'int'], 'http\Env::setResponseHeader' => ['bool', 'header_name'=>'string', 'header_value='=>'mixed', 'response_code='=>'mixed', 'replace_header='=>'mixed'], 'http\Env\Request::__construct' => ['void'], 'http\Env\Request::__toString' => ['string'], 'http\Env\Request::addBody' => ['http\Message', 'body'=>'http\Message\Body'], 'http\Env\Request::addHeader' => ['http\Message', 'header'=>'string', 'value'=>'mixed'], 'http\Env\Request::addHeaders' => ['http\Message', 'headers'=>'array', 'append='=>'mixed'], 'http\Env\Request::count' => ['int'], 'http\Env\Request::current' => ['mixed'], 'http\Env\Request::detach' => ['http\Message'], 'http\Env\Request::getBody' => ['http\Message\Body'], 'http\Env\Request::getCookie' => ['mixed', 'name='=>'string', 'type='=>'mixed', 'defval='=>'mixed', 'delete='=>'bool'], 'http\Env\Request::getFiles' => ['array'], 'http\Env\Request::getForm' => ['mixed', 'name='=>'string', 'type='=>'mixed', 'defval='=>'mixed', 'delete='=>'bool'], 'http\Env\Request::getHeader' => ['http\Header|mixed', 'header'=>'string', 'into_class='=>'mixed'], 'http\Env\Request::getHeaders' => ['array'], 'http\Env\Request::getHttpVersion' => ['string'], 'http\Env\Request::getInfo' => ['null|string'], 'http\Env\Request::getParentMessage' => ['http\Message'], 'http\Env\Request::getQuery' => ['mixed', 'name='=>'string', 'type='=>'mixed', 'defval='=>'mixed', 'delete='=>'bool'], 'http\Env\Request::getRequestMethod' => ['false|string'], 'http\Env\Request::getRequestUrl' => ['false|string'], 'http\Env\Request::getResponseCode' => ['false|int'], 'http\Env\Request::getResponseStatus' => ['false|string'], 'http\Env\Request::getType' => ['int'], 'http\Env\Request::isMultipart' => ['bool', '&boundary='=>'mixed'], 'http\Env\Request::key' => ['int|string'], 'http\Env\Request::next' => ['void'], 'http\Env\Request::prepend' => ['http\Message', 'message'=>'http\Message', 'top='=>'mixed'], 'http\Env\Request::reverse' => ['http\Message'], 'http\Env\Request::rewind' => ['void'], 'http\Env\Request::serialize' => ['string'], 'http\Env\Request::setBody' => ['http\Message', 'body'=>'http\Message\Body'], 'http\Env\Request::setHeader' => ['http\Message', 'header'=>'string', 'value='=>'mixed'], 'http\Env\Request::setHeaders' => ['http\Message', 'headers'=>'array'], 'http\Env\Request::setHttpVersion' => ['http\Message', 'http_version'=>'string'], 'http\Env\Request::setInfo' => ['http\Message', 'http_info'=>'string'], 'http\Env\Request::setRequestMethod' => ['http\Message', 'request_method'=>'string'], 'http\Env\Request::setRequestUrl' => ['http\Message', 'url'=>'string'], 'http\Env\Request::setResponseCode' => ['http\Message', 'response_code'=>'int', 'strict='=>'mixed'], 'http\Env\Request::setResponseStatus' => ['http\Message', 'response_status'=>'string'], 'http\Env\Request::setType' => ['http\Message', 'type'=>'int'], 'http\Env\Request::splitMultipartBody' => ['http\Message'], 'http\Env\Request::toCallback' => ['http\Message', 'callback'=>'callable'], 'http\Env\Request::toStream' => ['http\Message', 'stream'=>'resource'], 'http\Env\Request::toString' => ['string', 'include_parent='=>'mixed'], 'http\Env\Request::unserialize' => ['void', 'serialized'=>'string'], 'http\Env\Request::valid' => ['bool'], 'http\Env\Response::__construct' => ['void'], 'http\Env\Response::__invoke' => ['bool', 'data'=>'string', 'ob_flags='=>'int'], 'http\Env\Response::__toString' => ['string'], 'http\Env\Response::addBody' => ['http\Message', 'body'=>'http\Message\Body'], 'http\Env\Response::addHeader' => ['http\Message', 'header'=>'string', 'value'=>'mixed'], 'http\Env\Response::addHeaders' => ['http\Message', 'headers'=>'array', 'append='=>'mixed'], 'http\Env\Response::count' => ['int'], 'http\Env\Response::current' => ['mixed'], 'http\Env\Response::detach' => ['http\Message'], 'http\Env\Response::getBody' => ['http\Message\Body'], 'http\Env\Response::getHeader' => ['http\Header|mixed', 'header'=>'string', 'into_class='=>'mixed'], 'http\Env\Response::getHeaders' => ['array'], 'http\Env\Response::getHttpVersion' => ['string'], 'http\Env\Response::getInfo' => ['?string'], 'http\Env\Response::getParentMessage' => ['http\Message'], 'http\Env\Response::getRequestMethod' => ['false|string'], 'http\Env\Response::getRequestUrl' => ['false|string'], 'http\Env\Response::getResponseCode' => ['false|int'], 'http\Env\Response::getResponseStatus' => ['false|string'], 'http\Env\Response::getType' => ['int'], 'http\Env\Response::isCachedByETag' => ['int', 'header_name='=>'string'], 'http\Env\Response::isCachedByLastModified' => ['int', 'header_name='=>'string'], 'http\Env\Response::isMultipart' => ['bool', '&boundary='=>'mixed'], 'http\Env\Response::key' => ['int|string'], 'http\Env\Response::next' => ['void'], 'http\Env\Response::prepend' => ['http\Message', 'message'=>'http\Message', 'top='=>'mixed'], 'http\Env\Response::reverse' => ['http\Message'], 'http\Env\Response::rewind' => ['void'], 'http\Env\Response::send' => ['bool', 'stream='=>'resource'], 'http\Env\Response::serialize' => ['string'], 'http\Env\Response::setBody' => ['http\Message', 'body'=>'http\Message\Body'], 'http\Env\Response::setCacheControl' => ['http\Env\Response', 'cache_control'=>'string'], 'http\Env\Response::setContentDisposition' => ['http\Env\Response', 'disposition_params'=>'array'], 'http\Env\Response::setContentEncoding' => ['http\Env\Response', 'content_encoding'=>'int'], 'http\Env\Response::setContentType' => ['http\Env\Response', 'content_type'=>'string'], 'http\Env\Response::setCookie' => ['http\Env\Response', 'cookie'=>'mixed'], 'http\Env\Response::setEnvRequest' => ['http\Env\Response', 'env_request'=>'http\Message'], 'http\Env\Response::setEtag' => ['http\Env\Response', 'etag'=>'string'], 'http\Env\Response::setHeader' => ['http\Message', 'header'=>'string', 'value='=>'mixed'], 'http\Env\Response::setHeaders' => ['http\Message', 'headers'=>'array'], 'http\Env\Response::setHttpVersion' => ['http\Message', 'http_version'=>'string'], 'http\Env\Response::setInfo' => ['http\Message', 'http_info'=>'string'], 'http\Env\Response::setLastModified' => ['http\Env\Response', 'last_modified'=>'int'], 'http\Env\Response::setRequestMethod' => ['http\Message', 'request_method'=>'string'], 'http\Env\Response::setRequestUrl' => ['http\Message', 'url'=>'string'], 'http\Env\Response::setResponseCode' => ['http\Message', 'response_code'=>'int', 'strict='=>'mixed'], 'http\Env\Response::setResponseStatus' => ['http\Message', 'response_status'=>'string'], 'http\Env\Response::setThrottleRate' => ['http\Env\Response', 'chunk_size'=>'int', 'delay='=>'float|int'], 'http\Env\Response::setType' => ['http\Message', 'type'=>'int'], 'http\Env\Response::splitMultipartBody' => ['http\Message'], 'http\Env\Response::toCallback' => ['http\Message', 'callback'=>'callable'], 'http\Env\Response::toStream' => ['http\Message', 'stream'=>'resource'], 'http\Env\Response::toString' => ['string', 'include_parent='=>'mixed'], 'http\Env\Response::unserialize' => ['void', 'serialized'=>'string'], 'http\Env\Response::valid' => ['bool'], 'http\Header::__construct' => ['void', 'name='=>'mixed', 'value='=>'mixed'], 'http\Header::__toString' => ['string'], 'http\Header::getParams' => ['http\Params', 'param_sep='=>'mixed', 'arg_sep='=>'mixed', 'val_sep='=>'mixed', 'flags='=>'mixed'], 'http\Header::match' => ['bool', 'value'=>'string', 'flags='=>'mixed'], 'http\Header::negotiate' => ['null|string', 'supported'=>'array', '&result='=>'mixed'], 'http\Header::parse' => ['array|false', 'string'=>'string', 'header_class='=>'mixed'], 'http\Header::serialize' => ['string'], 'http\Header::toString' => ['string'], 'http\Header::unserialize' => ['void', 'serialized'=>'string'], 'http\Header\Parser::getState' => ['int'], 'http\Header\Parser::parse' => ['int', 'data'=>'string', 'flags'=>'int', '&headers'=>'array'], 'http\Header\Parser::stream' => ['int', 'stream'=>'resource', 'flags'=>'int', '&headers'=>'array'], 'http\Message::__construct' => ['void', 'message='=>'mixed', 'greedy='=>'bool'], 'http\Message::__toString' => ['string'], 'http\Message::addBody' => ['http\Message', 'body'=>'http\Message\Body'], 'http\Message::addHeader' => ['http\Message', 'header'=>'string', 'value'=>'mixed'], 'http\Message::addHeaders' => ['http\Message', 'headers'=>'array', 'append='=>'mixed'], 'http\Message::count' => ['int'], 'http\Message::current' => ['mixed'], 'http\Message::detach' => ['http\Message'], 'http\Message::getBody' => ['http\Message\Body'], 'http\Message::getHeader' => ['http\Header|mixed', 'header'=>'string', 'into_class='=>'mixed'], 'http\Message::getHeaders' => ['array'], 'http\Message::getHttpVersion' => ['string'], 'http\Message::getInfo' => ['null|string'], 'http\Message::getParentMessage' => ['http\Message'], 'http\Message::getRequestMethod' => ['false|string'], 'http\Message::getRequestUrl' => ['false|string'], 'http\Message::getResponseCode' => ['false|int'], 'http\Message::getResponseStatus' => ['false|string'], 'http\Message::getType' => ['int'], 'http\Message::isMultipart' => ['bool', '&boundary='=>'mixed'], 'http\Message::key' => ['int|string'], 'http\Message::next' => ['void'], 'http\Message::prepend' => ['http\Message', 'message'=>'http\Message', 'top='=>'mixed'], 'http\Message::reverse' => ['http\Message'], 'http\Message::rewind' => ['void'], 'http\Message::serialize' => ['string'], 'http\Message::setBody' => ['http\Message', 'body'=>'http\Message\Body'], 'http\Message::setHeader' => ['http\Message', 'header'=>'string', 'value='=>'mixed'], 'http\Message::setHeaders' => ['http\Message', 'headers'=>'array'], 'http\Message::setHttpVersion' => ['http\Message', 'http_version'=>'string'], 'http\Message::setInfo' => ['http\Message', 'http_info'=>'string'], 'http\Message::setRequestMethod' => ['http\Message', 'request_method'=>'string'], 'http\Message::setRequestUrl' => ['http\Message', 'url'=>'string'], 'http\Message::setResponseCode' => ['http\Message', 'response_code'=>'int', 'strict='=>'mixed'], 'http\Message::setResponseStatus' => ['http\Message', 'response_status'=>'string'], 'http\Message::setType' => ['http\Message', 'type'=>'int'], 'http\Message::splitMultipartBody' => ['http\Message'], 'http\Message::toCallback' => ['http\Message', 'callback'=>'callable'], 'http\Message::toStream' => ['http\Message', 'stream'=>'resource'], 'http\Message::toString' => ['string', 'include_parent='=>'mixed'], 'http\Message::unserialize' => ['void', 'serialized'=>'string'], 'http\Message::valid' => ['bool'], 'http\Message\Body::__construct' => ['void', 'stream='=>'resource'], 'http\Message\Body::__toString' => ['string'], 'http\Message\Body::addForm' => ['http\Message\Body', 'fields='=>'?array', 'files='=>'?array'], 'http\Message\Body::addPart' => ['http\Message\Body', 'message'=>'http\Message'], 'http\Message\Body::append' => ['http\Message\Body', 'string'=>'string'], 'http\Message\Body::etag' => ['false|string'], 'http\Message\Body::getBoundary' => ['null|string'], 'http\Message\Body::getResource' => ['resource'], 'http\Message\Body::serialize' => ['string'], 'http\Message\Body::stat' => ['int|object', 'field='=>'mixed'], 'http\Message\Body::toCallback' => ['http\Message\Body', 'callback'=>'callable', 'offset='=>'mixed', 'maxlen='=>'mixed'], 'http\Message\Body::toStream' => ['http\Message\Body', 'stream'=>'resource', 'offset='=>'mixed', 'maxlen='=>'mixed'], 'http\Message\Body::toString' => ['string'], 'http\Message\Body::unserialize' => ['void', 'serialized'=>'string'], 'http\Message\Parser::getState' => ['int'], 'http\Message\Parser::parse' => ['int', 'data'=>'string', 'flags'=>'int', '&message'=>'http\Message'], 'http\Message\Parser::stream' => ['int', 'stream'=>'resource', 'flags'=>'int', '&message'=>'http\Message'], 'http\Params::__construct' => ['void', 'params='=>'mixed', 'param_sep='=>'mixed', 'arg_sep='=>'mixed', 'val_sep='=>'mixed', 'flags='=>'mixed'], 'http\Params::__toString' => ['string'], 'http\Params::offsetExists' => ['bool', 'name'=>'int|string'], 'http\Params::offsetGet' => ['mixed', 'name'=>'int|string'], 'http\Params::offsetSet' => ['void', 'name'=>'int|string|null', 'value'=>'mixed'], 'http\Params::offsetUnset' => ['void', 'name'=>'int|string'], 'http\Params::toArray' => ['array'], 'http\Params::toString' => ['string'], 'http\QueryString::__construct' => ['void', 'querystring'=>'string'], 'http\QueryString::__toString' => ['string'], 'http\QueryString::get' => ['http\QueryString|string|mixed', 'name='=>'string', 'type='=>'mixed', 'defval='=>'mixed', 'delete='=>'bool|false'], 'http\QueryString::getArray' => ['array|mixed', 'name'=>'string', 'defval='=>'mixed', 'delete='=>'bool|false'], 'http\QueryString::getBool' => ['bool|mixed', 'name'=>'string', 'defval='=>'mixed', 'delete='=>'bool|false'], 'http\QueryString::getFloat' => ['float|mixed', 'name'=>'string', 'defval='=>'mixed', 'delete='=>'bool|false'], 'http\QueryString::getGlobalInstance' => ['http\QueryString'], 'http\QueryString::getInt' => ['int|mixed', 'name'=>'string', 'defval='=>'mixed', 'delete='=>'bool|false'], 'http\QueryString::getIterator' => ['IteratorAggregate'], 'http\QueryString::getObject' => ['object|mixed', 'name'=>'string', 'defval='=>'mixed', 'delete='=>'bool|false'], 'http\QueryString::getString' => ['string|mixed', 'name'=>'string', 'defval='=>'mixed', 'delete='=>'bool|false'], 'http\QueryString::mod' => ['http\QueryString', 'params='=>'mixed'], 'http\QueryString::offsetExists' => ['bool', 'offset'=>'int|string'], 'http\QueryString::offsetGet' => ['mixed|null', 'offset'=>'int|string'], 'http\QueryString::offsetSet' => ['void', 'offset'=>'int|string|null', 'value'=>'mixed'], 'http\QueryString::offsetUnset' => ['void', 'offset'=>'int|string'], 'http\QueryString::serialize' => ['string'], 'http\QueryString::set' => ['http\QueryString', 'params'=>'mixed'], 'http\QueryString::toArray' => ['array'], 'http\QueryString::toString' => ['string'], 'http\QueryString::unserialize' => ['void', 'serialized'=>'string'], 'http\QueryString::xlate' => ['http\QueryString'], 'http\Url::__construct' => ['void', 'old_url='=>'mixed', 'new_url='=>'mixed', 'flags='=>'int'], 'http\Url::__toString' => ['string'], 'http\Url::mod' => ['http\Url', 'parts'=>'mixed', 'flags='=>'float|int|mixed'], 'http\Url::toArray' => ['string[]'], 'http\Url::toString' => ['string'], 'http_build_cookie' => ['string', 'cookie'=>'array'], 'http_build_query' => ['string', 'data'=>'array|object', 'numeric_prefix='=>'string', 'arg_separator='=>'?string', 'encoding_type='=>'int'], 'http_build_str' => ['string', 'query'=>'array', 'prefix='=>'?string', 'arg_separator='=>'string'], 'http_build_url' => ['string', 'url='=>'string|array', 'parts='=>'string|array', 'flags='=>'int', 'new_url='=>'array'], 'http_cache_etag' => ['bool', 'etag='=>'string'], 'http_cache_last_modified' => ['bool', 'timestamp_or_expires='=>'int'], 'http_chunked_decode' => ['string|false', 'encoded'=>'string'], 'http_date' => ['string', 'timestamp='=>'int'], 'http_deflate' => ['?string', 'data'=>'string', 'flags='=>'int'], 'http_get' => ['string', 'url'=>'string', 'options='=>'array', 'info='=>'array'], 'http_get_request_body' => ['?string'], 'http_get_request_body_stream' => ['?resource'], 'http_get_request_headers' => ['array'], 'http_head' => ['string', 'url'=>'string', 'options='=>'array', 'info='=>'array'], 'http_inflate' => ['?string', 'data'=>'string'], 'http_match_etag' => ['bool', 'etag'=>'string', 'for_range='=>'bool'], 'http_match_modified' => ['bool', 'timestamp='=>'int', 'for_range='=>'bool'], 'http_match_request_header' => ['bool', 'header'=>'string', 'value'=>'string', 'match_case='=>'bool'], 'http_negotiate_charset' => ['string', 'supported'=>'array', 'result='=>'array'], 'http_negotiate_content_type' => ['string', 'supported'=>'array', 'result='=>'array'], 'http_negotiate_language' => ['string', 'supported'=>'array', 'result='=>'array'], 'http_parse_cookie' => ['stdClass|false', 'cookie'=>'string', 'flags='=>'int', 'allowed_extras='=>'array'], 'http_parse_headers' => ['array|false', 'header'=>'string'], 'http_parse_message' => ['object', 'message'=>'string'], 'http_parse_params' => ['stdClass', 'param'=>'string', 'flags='=>'int'], 'http_persistent_handles_clean' => ['string', 'ident='=>'string'], 'http_persistent_handles_count' => ['stdClass|false'], 'http_persistent_handles_ident' => ['string|false', 'ident='=>'string'], 'http_post_data' => ['string', 'url'=>'string', 'data'=>'string', 'options='=>'array', 'info='=>'array'], 'http_post_fields' => ['string', 'url'=>'string', 'data'=>'array', 'files='=>'array', 'options='=>'array', 'info='=>'array'], 'http_put_data' => ['string', 'url'=>'string', 'data'=>'string', 'options='=>'array', 'info='=>'array'], 'http_put_file' => ['string', 'url'=>'string', 'file'=>'string', 'options='=>'array', 'info='=>'array'], 'http_put_stream' => ['string', 'url'=>'string', 'stream'=>'resource', 'options='=>'array', 'info='=>'array'], 'http_redirect' => ['int|false', 'url='=>'string', 'params='=>'array', 'session='=>'bool', 'status='=>'int'], 'http_request' => ['string', 'method'=>'int', 'url'=>'string', 'body='=>'string', 'options='=>'array', 'info='=>'array'], 'http_request_body_encode' => ['string|false', 'fields'=>'array', 'files'=>'array'], 'http_request_method_exists' => ['bool', 'method'=>'mixed'], 'http_request_method_name' => ['string|false', 'method'=>'int'], 'http_request_method_register' => ['int|false', 'method'=>'string'], 'http_request_method_unregister' => ['bool', 'method'=>'mixed'], 'http_response_code' => ['int|bool', 'response_code='=>'int'], 'http_send_content_disposition' => ['bool', 'filename'=>'string', 'inline='=>'bool'], 'http_send_content_type' => ['bool', 'content_type='=>'string'], 'http_send_data' => ['bool', 'data'=>'string'], 'http_send_file' => ['bool', 'file'=>'string'], 'http_send_last_modified' => ['bool', 'timestamp='=>'int'], 'http_send_status' => ['bool', 'status'=>'int'], 'http_send_stream' => ['bool', 'stream'=>'resource'], 'http_support' => ['int', 'feature='=>'int'], 'http_throttle' => ['void', 'sec'=>'float', 'bytes='=>'int'], 'HttpDeflateStream::__construct' => ['void', 'flags='=>'int'], 'HttpDeflateStream::factory' => ['HttpDeflateStream', 'flags='=>'int', 'class_name='=>'string'], 'HttpDeflateStream::finish' => ['string', 'data='=>'string'], 'HttpDeflateStream::flush' => ['string|false', 'data='=>'string'], 'HttpDeflateStream::update' => ['string|false', 'data'=>'string'], 'HttpInflateStream::__construct' => ['void', 'flags='=>'int'], 'HttpInflateStream::factory' => ['HttpInflateStream', 'flags='=>'int', 'class_name='=>'string'], 'HttpInflateStream::finish' => ['string', 'data='=>'string'], 'HttpInflateStream::flush' => ['string|false', 'data='=>'string'], 'HttpInflateStream::update' => ['string|false', 'data'=>'string'], 'HttpMessage::__construct' => ['void', 'message='=>'string'], 'HttpMessage::__toString' => ['string'], 'HttpMessage::addHeaders' => ['void', 'headers'=>'array', 'append='=>'bool'], 'HttpMessage::count' => ['int'], 'HttpMessage::current' => ['mixed'], 'HttpMessage::detach' => ['HttpMessage'], 'HttpMessage::factory' => ['?HttpMessage', 'raw_message='=>'string', 'class_name='=>'string'], 'HttpMessage::fromEnv' => ['?HttpMessage', 'message_type'=>'int', 'class_name='=>'string'], 'HttpMessage::fromString' => ['?HttpMessage', 'raw_message='=>'string', 'class_name='=>'string'], 'HttpMessage::getBody' => ['string'], 'HttpMessage::getHeader' => ['?string', 'header'=>'string'], 'HttpMessage::getHeaders' => ['array'], 'HttpMessage::getHttpVersion' => ['string'], 'HttpMessage::getInfo' => [''], 'HttpMessage::getParentMessage' => ['HttpMessage'], 'HttpMessage::getRequestMethod' => ['string|false'], 'HttpMessage::getRequestUrl' => ['string|false'], 'HttpMessage::getResponseCode' => ['int'], 'HttpMessage::getResponseStatus' => ['string'], 'HttpMessage::getType' => ['int'], 'HttpMessage::guessContentType' => ['string|false', 'magic_file'=>'string', 'magic_mode='=>'int'], 'HttpMessage::key' => ['int|string'], 'HttpMessage::next' => ['void'], 'HttpMessage::prepend' => ['void', 'message'=>'HttpMessage', 'top='=>'bool'], 'HttpMessage::reverse' => ['HttpMessage'], 'HttpMessage::rewind' => ['void'], 'HttpMessage::send' => ['bool'], 'HttpMessage::serialize' => ['string'], 'HttpMessage::setBody' => ['void', 'body'=>'string'], 'HttpMessage::setHeaders' => ['void', 'headers'=>'array'], 'HttpMessage::setHttpVersion' => ['bool', 'version'=>'string'], 'HttpMessage::setInfo' => ['', 'http_info'=>''], 'HttpMessage::setRequestMethod' => ['bool', 'method'=>'string'], 'HttpMessage::setRequestUrl' => ['bool', 'url'=>'string'], 'HttpMessage::setResponseCode' => ['bool', 'code'=>'int'], 'HttpMessage::setResponseStatus' => ['bool', 'status'=>'string'], 'HttpMessage::setType' => ['void', 'type'=>'int'], 'HttpMessage::toMessageTypeObject' => ['HttpRequest|HttpResponse|null'], 'HttpMessage::toString' => ['string', 'include_parent='=>'bool'], 'HttpMessage::unserialize' => ['void', 'serialized'=>'string'], 'HttpMessage::valid' => ['bool'], 'HttpQueryString::__construct' => ['void', 'global='=>'bool', 'add='=>'mixed'], 'HttpQueryString::__toString' => ['string'], 'HttpQueryString::factory' => ['', 'global'=>'', 'params'=>'', 'class_name'=>''], 'HttpQueryString::get' => ['mixed', 'key='=>'string', 'type='=>'mixed', 'defval='=>'mixed', 'delete='=>'bool'], 'HttpQueryString::getArray' => ['', 'name'=>'', 'defval'=>'', 'delete'=>''], 'HttpQueryString::getBool' => ['', 'name'=>'', 'defval'=>'', 'delete'=>''], 'HttpQueryString::getFloat' => ['', 'name'=>'', 'defval'=>'', 'delete'=>''], 'HttpQueryString::getInt' => ['', 'name'=>'', 'defval'=>'', 'delete'=>''], 'HttpQueryString::getObject' => ['', 'name'=>'', 'defval'=>'', 'delete'=>''], 'HttpQueryString::getString' => ['', 'name'=>'', 'defval'=>'', 'delete'=>''], 'HttpQueryString::mod' => ['HttpQueryString', 'params'=>'mixed'], 'HttpQueryString::offsetExists' => ['bool', 'offset'=>'int|string'], 'HttpQueryString::offsetGet' => ['mixed', 'offset'=>'int|string'], 'HttpQueryString::offsetSet' => ['void', 'offset'=>'int|string|null', 'value'=>'mixed'], 'HttpQueryString::offsetUnset' => ['void', 'offset'=>'int|string'], 'HttpQueryString::serialize' => ['string'], 'HttpQueryString::set' => ['string', 'params'=>'mixed'], 'HttpQueryString::singleton' => ['HttpQueryString', 'global='=>'bool'], 'HttpQueryString::toArray' => ['array'], 'HttpQueryString::toString' => ['string'], 'HttpQueryString::unserialize' => ['void', 'serialized'=>'string'], 'HttpQueryString::xlate' => ['bool', 'ie'=>'string', 'oe'=>'string'], 'HttpRequest::__construct' => ['void', 'url='=>'string', 'request_method='=>'int', 'options='=>'array'], 'HttpRequest::addBody' => ['', 'request_body_data'=>''], 'HttpRequest::addCookies' => ['bool', 'cookies'=>'array'], 'HttpRequest::addHeaders' => ['bool', 'headers'=>'array'], 'HttpRequest::addPostFields' => ['bool', 'post_data'=>'array'], 'HttpRequest::addPostFile' => ['bool', 'name'=>'string', 'file'=>'string', 'content_type='=>'string'], 'HttpRequest::addPutData' => ['bool', 'put_data'=>'string'], 'HttpRequest::addQueryData' => ['bool', 'query_params'=>'array'], 'HttpRequest::addRawPostData' => ['bool', 'raw_post_data'=>'string'], 'HttpRequest::addSslOptions' => ['bool', 'options'=>'array'], 'HttpRequest::clearHistory' => ['void'], 'HttpRequest::enableCookies' => ['bool'], 'HttpRequest::encodeBody' => ['', 'fields'=>'', 'files'=>''], 'HttpRequest::factory' => ['', 'url'=>'', 'method'=>'', 'options'=>'', 'class_name'=>''], 'HttpRequest::flushCookies' => [''], 'HttpRequest::get' => ['', 'url'=>'', 'options'=>'', '&info'=>''], 'HttpRequest::getBody' => [''], 'HttpRequest::getContentType' => ['string'], 'HttpRequest::getCookies' => ['array'], 'HttpRequest::getHeaders' => ['array'], 'HttpRequest::getHistory' => ['HttpMessage'], 'HttpRequest::getMethod' => ['int'], 'HttpRequest::getOptions' => ['array'], 'HttpRequest::getPostFields' => ['array'], 'HttpRequest::getPostFiles' => ['array'], 'HttpRequest::getPutData' => ['string'], 'HttpRequest::getPutFile' => ['string'], 'HttpRequest::getQueryData' => ['string'], 'HttpRequest::getRawPostData' => ['string'], 'HttpRequest::getRawRequestMessage' => ['string'], 'HttpRequest::getRawResponseMessage' => ['string'], 'HttpRequest::getRequestMessage' => ['HttpMessage'], 'HttpRequest::getResponseBody' => ['string'], 'HttpRequest::getResponseCode' => ['int'], 'HttpRequest::getResponseCookies' => ['stdClass[]', 'flags='=>'int', 'allowed_extras='=>'array'], 'HttpRequest::getResponseData' => ['array'], 'HttpRequest::getResponseHeader' => ['mixed', 'name='=>'string'], 'HttpRequest::getResponseInfo' => ['mixed', 'name='=>'string'], 'HttpRequest::getResponseMessage' => ['HttpMessage'], 'HttpRequest::getResponseStatus' => ['string'], 'HttpRequest::getSslOptions' => ['array'], 'HttpRequest::getUrl' => ['string'], 'HttpRequest::head' => ['', 'url'=>'', 'options'=>'', '&info'=>''], 'HttpRequest::methodExists' => ['', 'method'=>''], 'HttpRequest::methodName' => ['', 'method_id'=>''], 'HttpRequest::methodRegister' => ['', 'method_name'=>''], 'HttpRequest::methodUnregister' => ['', 'method'=>''], 'HttpRequest::postData' => ['', 'url'=>'', 'data'=>'', 'options'=>'', '&info'=>''], 'HttpRequest::postFields' => ['', 'url'=>'', 'data'=>'', 'options'=>'', '&info'=>''], 'HttpRequest::putData' => ['', 'url'=>'', 'data'=>'', 'options'=>'', '&info'=>''], 'HttpRequest::putFile' => ['', 'url'=>'', 'file'=>'', 'options'=>'', '&info'=>''], 'HttpRequest::putStream' => ['', 'url'=>'', 'stream'=>'', 'options'=>'', '&info'=>''], 'HttpRequest::resetCookies' => ['bool', 'session_only='=>'bool'], 'HttpRequest::send' => ['HttpMessage'], 'HttpRequest::setBody' => ['bool', 'request_body_data='=>'string'], 'HttpRequest::setContentType' => ['bool', 'content_type'=>'string'], 'HttpRequest::setCookies' => ['bool', 'cookies='=>'array'], 'HttpRequest::setHeaders' => ['bool', 'headers='=>'array'], 'HttpRequest::setMethod' => ['bool', 'request_method'=>'int'], 'HttpRequest::setOptions' => ['bool', 'options='=>'array'], 'HttpRequest::setPostFields' => ['bool', 'post_data'=>'array'], 'HttpRequest::setPostFiles' => ['bool', 'post_files'=>'array'], 'HttpRequest::setPutData' => ['bool', 'put_data='=>'string'], 'HttpRequest::setPutFile' => ['bool', 'file='=>'string'], 'HttpRequest::setQueryData' => ['bool', 'query_data'=>'mixed'], 'HttpRequest::setRawPostData' => ['bool', 'raw_post_data='=>'string'], 'HttpRequest::setSslOptions' => ['bool', 'options='=>'array'], 'HttpRequest::setUrl' => ['bool', 'url'=>'string'], 'HttpRequestDataShare::__construct' => ['void'], 'HttpRequestDataShare::__destruct' => ['void'], 'HttpRequestDataShare::attach' => ['', 'request'=>'HttpRequest'], 'HttpRequestDataShare::count' => ['int'], 'HttpRequestDataShare::detach' => ['', 'request'=>'HttpRequest'], 'HttpRequestDataShare::factory' => ['', 'global'=>'', 'class_name'=>''], 'HttpRequestDataShare::reset' => [''], 'HttpRequestDataShare::singleton' => ['', 'global'=>''], 'HttpRequestPool::__construct' => ['void', 'request='=>'HttpRequest'], 'HttpRequestPool::__destruct' => ['void'], 'HttpRequestPool::attach' => ['bool', 'request'=>'HttpRequest'], 'HttpRequestPool::count' => ['int'], 'HttpRequestPool::current' => ['mixed'], 'HttpRequestPool::detach' => ['bool', 'request'=>'HttpRequest'], 'HttpRequestPool::enableEvents' => ['', 'enable'=>''], 'HttpRequestPool::enablePipelining' => ['', 'enable'=>''], 'HttpRequestPool::getAttachedRequests' => ['array'], 'HttpRequestPool::getFinishedRequests' => ['array'], 'HttpRequestPool::key' => ['int|string'], 'HttpRequestPool::next' => ['void'], 'HttpRequestPool::reset' => ['void'], 'HttpRequestPool::rewind' => ['void'], 'HttpRequestPool::send' => ['bool'], 'HttpRequestPool::socketPerform' => ['bool'], 'HttpRequestPool::socketSelect' => ['bool', 'timeout='=>'float'], 'HttpRequestPool::valid' => ['bool'], 'HttpResponse::capture' => ['void'], 'HttpResponse::getBufferSize' => ['int'], 'HttpResponse::getCache' => ['bool'], 'HttpResponse::getCacheControl' => ['string'], 'HttpResponse::getContentDisposition' => ['string'], 'HttpResponse::getContentType' => ['string'], 'HttpResponse::getData' => ['string'], 'HttpResponse::getETag' => ['string'], 'HttpResponse::getFile' => ['string'], 'HttpResponse::getGzip' => ['bool'], 'HttpResponse::getHeader' => ['mixed', 'name='=>'string'], 'HttpResponse::getLastModified' => ['int'], 'HttpResponse::getRequestBody' => ['string'], 'HttpResponse::getRequestBodyStream' => ['resource'], 'HttpResponse::getRequestHeaders' => ['array'], 'HttpResponse::getStream' => ['resource'], 'HttpResponse::getThrottleDelay' => ['float'], 'HttpResponse::guessContentType' => ['string|false', 'magic_file'=>'string', 'magic_mode='=>'int'], 'HttpResponse::redirect' => ['void', 'url='=>'string', 'params='=>'array', 'session='=>'bool', 'status='=>'int'], 'HttpResponse::send' => ['bool', 'clean_ob='=>'bool'], 'HttpResponse::setBufferSize' => ['bool', 'bytes'=>'int'], 'HttpResponse::setCache' => ['bool', 'cache'=>'bool'], 'HttpResponse::setCacheControl' => ['bool', 'control'=>'string', 'max_age='=>'int', 'must_revalidate='=>'bool'], 'HttpResponse::setContentDisposition' => ['bool', 'filename'=>'string', 'inline='=>'bool'], 'HttpResponse::setContentType' => ['bool', 'content_type'=>'string'], 'HttpResponse::setData' => ['bool', 'data'=>'mixed'], 'HttpResponse::setETag' => ['bool', 'etag'=>'string'], 'HttpResponse::setFile' => ['bool', 'file'=>'string'], 'HttpResponse::setGzip' => ['bool', 'gzip'=>'bool'], 'HttpResponse::setHeader' => ['bool', 'name'=>'string', 'value='=>'mixed', 'replace='=>'bool'], 'HttpResponse::setLastModified' => ['bool', 'timestamp'=>'int'], 'HttpResponse::setStream' => ['bool', 'stream'=>'resource'], 'HttpResponse::setThrottleDelay' => ['bool', 'seconds'=>'float'], 'HttpResponse::status' => ['bool', 'status'=>'int'], 'HttpUtil::buildCookie' => ['', 'cookie_array'=>''], 'HttpUtil::buildStr' => ['', 'query'=>'', 'prefix'=>'', 'arg_sep'=>''], 'HttpUtil::buildUrl' => ['', 'url'=>'', 'parts'=>'', 'flags'=>'', '&composed'=>''], 'HttpUtil::chunkedDecode' => ['', 'encoded_string'=>''], 'HttpUtil::date' => ['', 'timestamp'=>''], 'HttpUtil::deflate' => ['', 'plain'=>'', 'flags'=>''], 'HttpUtil::inflate' => ['', 'encoded'=>''], 'HttpUtil::matchEtag' => ['', 'plain_etag'=>'', 'for_range'=>''], 'HttpUtil::matchModified' => ['', 'last_modified'=>'', 'for_range'=>''], 'HttpUtil::matchRequestHeader' => ['', 'header_name'=>'', 'header_value'=>'', 'case_sensitive'=>''], 'HttpUtil::negotiateCharset' => ['', 'supported'=>'', '&result'=>''], 'HttpUtil::negotiateContentType' => ['', 'supported'=>'', '&result'=>''], 'HttpUtil::negotiateLanguage' => ['', 'supported'=>'', '&result'=>''], 'HttpUtil::parseCookie' => ['', 'cookie_string'=>''], 'HttpUtil::parseHeaders' => ['', 'headers_string'=>''], 'HttpUtil::parseMessage' => ['', 'message_string'=>''], 'HttpUtil::parseParams' => ['', 'param_string'=>'', 'flags'=>''], 'HttpUtil::support' => ['', 'feature'=>''], 'hw_api::checkin' => ['bool', 'parameter'=>'array'], 'hw_api::checkout' => ['bool', 'parameter'=>'array'], 'hw_api::children' => ['array', 'parameter'=>'array'], 'hw_api::content' => ['HW_API_Content', 'parameter'=>'array'], 'hw_api::copy' => ['hw_api_content', 'parameter'=>'array'], 'hw_api::dbstat' => ['hw_api_object', 'parameter'=>'array'], 'hw_api::dcstat' => ['hw_api_object', 'parameter'=>'array'], 'hw_api::dstanchors' => ['array', 'parameter'=>'array'], 'hw_api::dstofsrcanchor' => ['hw_api_object', 'parameter'=>'array'], 'hw_api::find' => ['array', 'parameter'=>'array'], 'hw_api::ftstat' => ['hw_api_object', 'parameter'=>'array'], 'hw_api::hwstat' => ['hw_api_object', 'parameter'=>'array'], 'hw_api::identify' => ['bool', 'parameter'=>'array'], 'hw_api::info' => ['array', 'parameter'=>'array'], 'hw_api::insert' => ['hw_api_object', 'parameter'=>'array'], 'hw_api::insertanchor' => ['hw_api_object', 'parameter'=>'array'], 'hw_api::insertcollection' => ['hw_api_object', 'parameter'=>'array'], 'hw_api::insertdocument' => ['hw_api_object', 'parameter'=>'array'], 'hw_api::link' => ['bool', 'parameter'=>'array'], 'hw_api::lock' => ['bool', 'parameter'=>'array'], 'hw_api::move' => ['bool', 'parameter'=>'array'], 'hw_api::object' => ['hw_api_object', 'parameter'=>'array'], 'hw_api::objectbyanchor' => ['hw_api_object', 'parameter'=>'array'], 'hw_api::parents' => ['array', 'parameter'=>'array'], 'hw_api::remove' => ['bool', 'parameter'=>'array'], 'hw_api::replace' => ['hw_api_object', 'parameter'=>'array'], 'hw_api::setcommittedversion' => ['hw_api_object', 'parameter'=>'array'], 'hw_api::srcanchors' => ['array', 'parameter'=>'array'], 'hw_api::srcsofdst' => ['array', 'parameter'=>'array'], 'hw_api::unlock' => ['bool', 'parameter'=>'array'], 'hw_api::user' => ['hw_api_object', 'parameter'=>'array'], 'hw_api::userlist' => ['array', 'parameter'=>'array'], 'hw_api_attribute' => ['HW_API_Attribute', 'name='=>'string', 'value='=>'string'], 'hw_api_attribute::key' => ['string'], 'hw_api_attribute::langdepvalue' => ['string', 'language'=>'string'], 'hw_api_attribute::value' => ['string'], 'hw_api_attribute::values' => ['array'], 'hw_api_content' => ['HW_API_Content', 'content'=>'string', 'mimetype'=>'string'], 'hw_api_content::mimetype' => ['string'], 'hw_api_content::read' => ['string', 'buffer'=>'string', 'length'=>'int'], 'hw_api_error::count' => ['int'], 'hw_api_error::reason' => ['HW_API_Reason'], 'hw_api_object' => ['hw_api_object', 'parameter'=>'array'], 'hw_api_object::assign' => ['bool', 'parameter'=>'array'], 'hw_api_object::attreditable' => ['bool', 'parameter'=>'array'], 'hw_api_object::count' => ['int', 'parameter'=>'array'], 'hw_api_object::insert' => ['bool', 'attribute'=>'hw_api_attribute'], 'hw_api_object::remove' => ['bool', 'name'=>'string'], 'hw_api_object::title' => ['string', 'parameter'=>'array'], 'hw_api_object::value' => ['string', 'name'=>'string'], 'hw_api_reason::description' => ['string'], 'hw_api_reason::type' => ['HW_API_Reason'], 'hw_Array2Objrec' => ['string', 'object_array'=>'array'], 'hw_changeobject' => ['bool', 'link'=>'int', 'objid'=>'int', 'attributes'=>'array'], 'hw_Children' => ['array', 'connection'=>'int', 'objectid'=>'int'], 'hw_ChildrenObj' => ['array', 'connection'=>'int', 'objectid'=>'int'], 'hw_Close' => ['bool', 'connection'=>'int'], 'hw_Connect' => ['int', 'host'=>'string', 'port'=>'int', 'username='=>'string', 'password='=>'string'], 'hw_connection_info' => ['', 'link'=>'int'], 'hw_cp' => ['int', 'connection'=>'int', 'object_id_array'=>'array', 'destination_id'=>'int'], 'hw_Deleteobject' => ['bool', 'connection'=>'int', 'object_to_delete'=>'int'], 'hw_DocByAnchor' => ['int', 'connection'=>'int', 'anchorid'=>'int'], 'hw_DocByAnchorObj' => ['string', 'connection'=>'int', 'anchorid'=>'int'], 'hw_Document_Attributes' => ['string', 'hw_document'=>'int'], 'hw_Document_BodyTag' => ['string', 'hw_document'=>'int', 'prefix='=>'string'], 'hw_Document_Content' => ['string', 'hw_document'=>'int'], 'hw_Document_SetContent' => ['bool', 'hw_document'=>'int', 'content'=>'string'], 'hw_Document_Size' => ['int', 'hw_document'=>'int'], 'hw_dummy' => ['string', 'link'=>'int', 'id'=>'int', 'msgid'=>'int'], 'hw_EditText' => ['bool', 'connection'=>'int', 'hw_document'=>'int'], 'hw_Error' => ['int', 'connection'=>'int'], 'hw_ErrorMsg' => ['string', 'connection'=>'int'], 'hw_Free_Document' => ['bool', 'hw_document'=>'int'], 'hw_GetAnchors' => ['array', 'connection'=>'int', 'objectid'=>'int'], 'hw_GetAnchorsObj' => ['array', 'connection'=>'int', 'objectid'=>'int'], 'hw_GetAndLock' => ['string', 'connection'=>'int', 'objectid'=>'int'], 'hw_GetChildColl' => ['array', 'connection'=>'int', 'objectid'=>'int'], 'hw_GetChildCollObj' => ['array', 'connection'=>'int', 'objectid'=>'int'], 'hw_GetChildDocColl' => ['array', 'connection'=>'int', 'objectid'=>'int'], 'hw_GetChildDocCollObj' => ['array', 'connection'=>'int', 'objectid'=>'int'], 'hw_GetObject' => ['', 'connection'=>'int', 'objectid'=>'', 'query='=>'string'], 'hw_GetObjectByQuery' => ['array', 'connection'=>'int', 'query'=>'string', 'max_hits'=>'int'], 'hw_GetObjectByQueryColl' => ['array', 'connection'=>'int', 'objectid'=>'int', 'query'=>'string', 'max_hits'=>'int'], 'hw_GetObjectByQueryCollObj' => ['array', 'connection'=>'int', 'objectid'=>'int', 'query'=>'string', 'max_hits'=>'int'], 'hw_GetObjectByQueryObj' => ['array', 'connection'=>'int', 'query'=>'string', 'max_hits'=>'int'], 'hw_GetParents' => ['array', 'connection'=>'int', 'objectid'=>'int'], 'hw_GetParentsObj' => ['array', 'connection'=>'int', 'objectid'=>'int'], 'hw_getrellink' => ['string', 'link'=>'int', 'rootid'=>'int', 'sourceid'=>'int', 'destid'=>'int'], 'hw_GetRemote' => ['int', 'connection'=>'int', 'objectid'=>'int'], 'hw_getremotechildren' => ['', 'connection'=>'int', 'object_record'=>'string'], 'hw_GetSrcByDestObj' => ['array', 'connection'=>'int', 'objectid'=>'int'], 'hw_GetText' => ['int', 'connection'=>'int', 'objectid'=>'int', 'prefix='=>''], 'hw_getusername' => ['string', 'connection'=>'int'], 'hw_Identify' => ['string', 'link'=>'int', 'username'=>'string', 'password'=>'string'], 'hw_InCollections' => ['array', 'connection'=>'int', 'object_id_array'=>'array', 'collection_id_array'=>'array', 'return_collections'=>'int'], 'hw_Info' => ['string', 'connection'=>'int'], 'hw_InsColl' => ['int', 'connection'=>'int', 'objectid'=>'int', 'object_array'=>'array'], 'hw_InsDoc' => ['int', 'connection'=>'', 'parentid'=>'int', 'object_record'=>'string', 'text='=>'string'], 'hw_insertanchors' => ['bool', 'hwdoc'=>'int', 'anchorecs'=>'array', 'dest'=>'array', 'urlprefixes='=>'array'], 'hw_InsertDocument' => ['int', 'connection'=>'int', 'parent_id'=>'int', 'hw_document'=>'int'], 'hw_InsertObject' => ['int', 'connection'=>'int', 'object_rec'=>'string', 'parameter'=>'string'], 'hw_mapid' => ['int', 'connection'=>'int', 'server_id'=>'int', 'object_id'=>'int'], 'hw_Modifyobject' => ['bool', 'connection'=>'int', 'object_to_change'=>'int', 'remove'=>'array', 'add'=>'array', 'mode='=>'int'], 'hw_mv' => ['int', 'connection'=>'int', 'object_id_array'=>'array', 'source_id'=>'int', 'destination_id'=>'int'], 'hw_New_Document' => ['int', 'object_record'=>'string', 'document_data'=>'string', 'document_size'=>'int'], 'hw_objrec2array' => ['array', 'object_record'=>'string', 'format='=>'array'], 'hw_Output_Document' => ['bool', 'hw_document'=>'int'], 'hw_pConnect' => ['int', 'host'=>'string', 'port'=>'int', 'username='=>'string', 'password='=>'string'], 'hw_PipeDocument' => ['int', 'connection'=>'int', 'objectid'=>'int', 'url_prefixes='=>'array'], 'hw_Root' => ['int'], 'hw_setlinkroot' => ['int', 'link'=>'int', 'rootid'=>'int'], 'hw_stat' => ['string', 'link'=>'int'], 'hw_Unlock' => ['bool', 'connection'=>'int', 'objectid'=>'int'], 'hw_Who' => ['array', 'connection'=>'int'], 'hwapi_attribute_new' => ['HW_API_Attribute', 'name='=>'string', 'value='=>'string'], 'hwapi_content_new' => ['HW_API_Content', 'content'=>'string', 'mimetype'=>'string'], 'hwapi_hgcsp' => ['HW_API', 'hostname'=>'string', 'port='=>'int'], 'hwapi_object_new' => ['hw_api_object', 'parameter'=>'array'], 'hypot' => ['float', 'x'=>'float', 'y'=>'float'], 'ibase_add_user' => ['bool', 'service_handle'=>'resource', 'user_name'=>'string', 'password'=>'string', 'first_name='=>'string', 'middle_name='=>'string', 'last_name='=>'string'], 'ibase_affected_rows' => ['int', 'link_identifier='=>'resource'], 'ibase_backup' => ['mixed', 'service_handle'=>'resource', 'source_db'=>'string', 'dest_file'=>'string', 'options='=>'int', 'verbose='=>'bool'], 'ibase_blob_add' => ['void', 'blob_handle'=>'resource', 'data'=>'string'], 'ibase_blob_cancel' => ['bool', 'blob_handle'=>'resource'], 'ibase_blob_close' => ['string|bool', 'blob_handle'=>'resource'], 'ibase_blob_create' => ['resource', 'link_identifier='=>'resource'], 'ibase_blob_echo' => ['bool', 'link_identifier'=>'', 'blob_id'=>'string'], 'ibase_blob_echo\'1' => ['bool', 'blob_id'=>'string'], 'ibase_blob_get' => ['string|false', 'blob_handle'=>'resource', 'length'=>'int'], 'ibase_blob_import' => ['string|false', 'link_identifier'=>'resource', 'file_handle'=>'resource'], 'ibase_blob_info' => ['array', 'link_identifier'=>'resource', 'blob_id'=>'string'], 'ibase_blob_info\'1' => ['array', 'blob_id'=>'string'], 'ibase_blob_open' => ['resource|false', 'link_identifier'=>'', 'blob_id'=>'string'], 'ibase_blob_open\'1' => ['resource', 'blob_id'=>'string'], 'ibase_close' => ['bool', 'link_identifier='=>'resource'], 'ibase_commit' => ['bool', 'link_identifier='=>'resource'], 'ibase_commit_ret' => ['bool', 'link_identifier='=>'resource'], 'ibase_connect' => ['resource|false', 'database='=>'string', 'username='=>'string', 'password='=>'string', 'charset='=>'string', 'buffers='=>'int', 'dialect='=>'int', 'role='=>'string'], 'ibase_db_info' => ['string', 'service_handle'=>'resource', 'db'=>'string', 'action'=>'int', 'argument='=>'int'], 'ibase_delete_user' => ['bool', 'service_handle'=>'resource', 'user_name'=>'string', 'password='=>'string', 'first_name='=>'string', 'middle_name='=>'string', 'last_name='=>'string'], 'ibase_drop_db' => ['bool', 'link_identifier='=>'resource'], 'ibase_errcode' => ['int|false'], 'ibase_errmsg' => ['string|false'], 'ibase_execute' => ['resource|false', 'query'=>'resource', 'bind_arg='=>'mixed', '...args='=>'mixed'], 'ibase_fetch_assoc' => ['array|false', 'result'=>'resource', 'fetch_flags='=>'int'], 'ibase_fetch_object' => ['object|false', 'result'=>'resource', 'fetch_flags='=>'int'], 'ibase_fetch_row' => ['array|false', 'result'=>'resource', 'fetch_flags='=>'int'], 'ibase_field_info' => ['array', 'query_result'=>'resource', 'field_number'=>'int'], 'ibase_free_event_handler' => ['bool', 'event'=>'resource'], 'ibase_free_query' => ['bool', 'query'=>'resource'], 'ibase_free_result' => ['bool', 'result'=>'resource'], 'ibase_gen_id' => ['int|string', 'generator'=>'string', 'increment='=>'int', 'link_identifier='=>'resource'], 'ibase_maintain_db' => ['bool', 'service_handle'=>'resource', 'db'=>'string', 'action'=>'int', 'argument='=>'int'], 'ibase_modify_user' => ['bool', 'service_handle'=>'resource', 'user_name'=>'string', 'password'=>'string', 'first_name='=>'string', 'middle_name='=>'string', 'last_name='=>'string'], 'ibase_name_result' => ['bool', 'result'=>'resource', 'name'=>'string'], 'ibase_num_fields' => ['int', 'query_result'=>'resource'], 'ibase_num_params' => ['int', 'query'=>'resource'], 'ibase_num_rows' => ['int', 'result_identifier'=>''], 'ibase_param_info' => ['array', 'query'=>'resource', 'field_number'=>'int'], 'ibase_pconnect' => ['resource|false', 'database='=>'string', 'username='=>'string', 'password='=>'string', 'charset='=>'string', 'buffers='=>'int', 'dialect='=>'int', 'role='=>'string'], 'ibase_prepare' => ['resource|false', 'link_identifier'=>'', 'query'=>'string', 'trans_identifier'=>''], 'ibase_query' => ['resource|false', 'link_identifier='=>'resource', 'string='=>'string', 'bind_arg='=>'int', '...args='=>''], 'ibase_restore' => ['mixed', 'service_handle'=>'resource', 'source_file'=>'string', 'dest_db'=>'string', 'options='=>'int', 'verbose='=>'bool'], 'ibase_rollback' => ['bool', 'link_identifier='=>'resource'], 'ibase_rollback_ret' => ['bool', 'link_identifier='=>'resource'], 'ibase_server_info' => ['string', 'service_handle'=>'resource', 'action'=>'int'], 'ibase_service_attach' => ['resource', 'host'=>'string', 'dba_username'=>'string', 'dba_password'=>'string'], 'ibase_service_detach' => ['bool', 'service_handle'=>'resource'], 'ibase_set_event_handler' => ['resource', 'link_identifier'=>'', 'callback'=>'callable', 'event='=>'string', '...args='=>''], 'ibase_set_event_handler\'1' => ['resource', 'callback'=>'callable', 'event'=>'string', '...args'=>''], 'ibase_timefmt' => ['bool', 'format'=>'string', 'columntype='=>'int'], 'ibase_trans' => ['resource|false', 'trans_args='=>'int', 'link_identifier='=>'', '...args='=>''], 'ibase_wait_event' => ['string', 'link_identifier'=>'', 'event='=>'string', '...args='=>''], 'ibase_wait_event\'1' => ['string', 'event'=>'string', '...args'=>''], 'iconv' => ['string|false', 'from_encoding'=>'string', 'to_encoding'=>'string', 'string'=>'string'], 'iconv_get_encoding' => ['array|string|false', 'type='=>'string'], 'iconv_mime_decode' => ['string|false', 'string'=>'string', 'mode='=>'int', 'encoding='=>'?string'], 'iconv_mime_decode_headers' => ['array|false', 'headers'=>'string', 'mode='=>'int', 'encoding='=>'?string'], 'iconv_mime_encode' => ['string|false', 'field_name'=>'string', 'field_value'=>'string', 'options='=>'array'], 'iconv_set_encoding' => ['bool', 'type'=>'string', 'encoding'=>'string'], 'iconv_strlen' => ['0|positive-int|false', 'string'=>'string', 'encoding='=>'?string'], 'iconv_strpos' => ['int|false', 'haystack'=>'string', 'needle'=>'string', 'offset='=>'int', 'encoding='=>'?string'], 'iconv_strrpos' => ['int|false', 'haystack'=>'string', 'needle'=>'string', 'encoding='=>'?string'], 'iconv_substr' => ['string|false', 'string'=>'string', 'offset'=>'int', 'length='=>'?int', 'encoding='=>'?string'], 'id3_get_frame_long_name' => ['string', 'frameid'=>'string'], 'id3_get_frame_short_name' => ['string', 'frameid'=>'string'], 'id3_get_genre_id' => ['int', 'genre'=>'string'], 'id3_get_genre_list' => ['array'], 'id3_get_genre_name' => ['string', 'genre_id'=>'int'], 'id3_get_tag' => ['array', 'filename'=>'string', 'version='=>'int'], 'id3_get_version' => ['int', 'filename'=>'string'], 'id3_remove_tag' => ['bool', 'filename'=>'string', 'version='=>'int'], 'id3_set_tag' => ['bool', 'filename'=>'string', 'tag'=>'array', 'version='=>'int'], 'idate' => ['int', 'format'=>'string', 'timestamp='=>'?int'], 'idn_strerror' => ['string', 'errorcode'=>'int'], 'idn_to_ascii' => ['string|false', 'domain'=>'string', 'flags='=>'int', 'variant='=>'int', '&w_idna_info='=>'array'], 'idn_to_utf8' => ['string|false', 'domain'=>'string', 'flags='=>'int', 'variant='=>'int', '&w_idna_info='=>'array'], 'ifx_affected_rows' => ['int', 'result_id'=>'resource'], 'ifx_blobinfile_mode' => ['bool', 'mode'=>'int'], 'ifx_byteasvarchar' => ['bool', 'mode'=>'int'], 'ifx_close' => ['bool', 'link_identifier='=>'resource'], 'ifx_connect' => ['resource', 'database='=>'string', 'userid='=>'string', 'password='=>'string'], 'ifx_copy_blob' => ['int', 'bid'=>'int'], 'ifx_create_blob' => ['int', 'type'=>'int', 'mode'=>'int', 'param'=>'string'], 'ifx_create_char' => ['int', 'param'=>'string'], 'ifx_do' => ['bool', 'result_id'=>'resource'], 'ifx_error' => ['string', 'link_identifier='=>'resource'], 'ifx_errormsg' => ['string', 'errorcode='=>'int'], 'ifx_fetch_row' => ['array', 'result_id'=>'resource', 'position='=>'mixed'], 'ifx_fieldproperties' => ['array', 'result_id'=>'resource'], 'ifx_fieldtypes' => ['array', 'result_id'=>'resource'], 'ifx_free_blob' => ['bool', 'bid'=>'int'], 'ifx_free_char' => ['bool', 'bid'=>'int'], 'ifx_free_result' => ['bool', 'result_id'=>'resource'], 'ifx_get_blob' => ['string', 'bid'=>'int'], 'ifx_get_char' => ['string', 'bid'=>'int'], 'ifx_getsqlca' => ['array', 'result_id'=>'resource'], 'ifx_htmltbl_result' => ['int', 'result_id'=>'resource', 'html_table_options='=>'string'], 'ifx_nullformat' => ['bool', 'mode'=>'int'], 'ifx_num_fields' => ['int', 'result_id'=>'resource'], 'ifx_num_rows' => ['int', 'result_id'=>'resource'], 'ifx_pconnect' => ['resource', 'database='=>'string', 'userid='=>'string', 'password='=>'string'], 'ifx_prepare' => ['resource', 'query'=>'string', 'link_identifier'=>'resource', 'cursor_def='=>'int', 'blobidarray='=>'mixed'], 'ifx_query' => ['resource', 'query'=>'string', 'link_identifier'=>'resource', 'cursor_type='=>'int', 'blobidarray='=>'mixed'], 'ifx_textasvarchar' => ['bool', 'mode'=>'int'], 'ifx_update_blob' => ['bool', 'bid'=>'int', 'content'=>'string'], 'ifx_update_char' => ['bool', 'bid'=>'int', 'content'=>'string'], 'ifxus_close_slob' => ['bool', 'bid'=>'int'], 'ifxus_create_slob' => ['int', 'mode'=>'int'], 'ifxus_free_slob' => ['bool', 'bid'=>'int'], 'ifxus_open_slob' => ['int', 'bid'=>'int', 'mode'=>'int'], 'ifxus_read_slob' => ['string', 'bid'=>'int', 'nbytes'=>'int'], 'ifxus_seek_slob' => ['int', 'bid'=>'int', 'mode'=>'int', 'offset'=>'int'], 'ifxus_tell_slob' => ['int', 'bid'=>'int'], 'ifxus_write_slob' => ['int', 'bid'=>'int', 'content'=>'string'], 'igbinary_serialize' => ['string|false', 'value'=>'mixed'], 'igbinary_unserialize' => ['mixed', 'str'=>'string'], 'ignore_user_abort' => ['int', 'enable='=>'?bool'], 'iis_add_server' => ['int', 'path'=>'string', 'comment'=>'string', 'server_ip'=>'string', 'port'=>'int', 'host_name'=>'string', 'rights'=>'int', 'start_server'=>'int'], 'iis_get_dir_security' => ['int', 'server_instance'=>'int', 'virtual_path'=>'string'], 'iis_get_script_map' => ['string', 'server_instance'=>'int', 'virtual_path'=>'string', 'script_extension'=>'string'], 'iis_get_server_by_comment' => ['int', 'comment'=>'string'], 'iis_get_server_by_path' => ['int', 'path'=>'string'], 'iis_get_server_rights' => ['int', 'server_instance'=>'int', 'virtual_path'=>'string'], 'iis_get_service_state' => ['int', 'service_id'=>'string'], 'iis_remove_server' => ['int', 'server_instance'=>'int'], 'iis_set_app_settings' => ['int', 'server_instance'=>'int', 'virtual_path'=>'string', 'application_scope'=>'string'], 'iis_set_dir_security' => ['int', 'server_instance'=>'int', 'virtual_path'=>'string', 'directory_flags'=>'int'], 'iis_set_script_map' => ['int', 'server_instance'=>'int', 'virtual_path'=>'string', 'script_extension'=>'string', 'engine_path'=>'string', 'allow_scripting'=>'int'], 'iis_set_server_rights' => ['int', 'server_instance'=>'int', 'virtual_path'=>'string', 'directory_flags'=>'int'], 'iis_start_server' => ['int', 'server_instance'=>'int'], 'iis_start_service' => ['int', 'service_id'=>'string'], 'iis_stop_server' => ['int', 'server_instance'=>'int'], 'iis_stop_service' => ['int', 'service_id'=>'string'], 'image_type_to_extension' => ['string', 'image_type'=>'int', 'include_dot='=>'bool'], 'image_type_to_mime_type' => ['string', 'image_type'=>'int'], 'imageaffine' => ['false|GdImage', 'image'=>'GdImage', 'affine'=>'array', 'clip='=>'?array'], 'imageaffinematrixconcat' => ['array{0:float,1:float,2:float,3:float,4:float,5:float}|false', 'matrix1'=>'array', 'matrix2'=>'array'], 'imageaffinematrixget' => ['array{0:float,1:float,2:float,3:float,4:float,5:float}|false', 'type'=>'int', 'options'=>'array|float'], 'imagealphablending' => ['bool', 'image'=>'GdImage', 'enable'=>'bool'], 'imageantialias' => ['bool', 'image'=>'GdImage', 'enable'=>'bool'], 'imagearc' => ['bool', 'image'=>'GdImage', 'center_x'=>'int', 'center_y'=>'int', 'width'=>'int', 'height'=>'int', 'start_angle'=>'int', 'end_angle'=>'int', 'color'=>'int'], 'imageavif' => ['bool', 'image'=>'GdImage', 'file='=>'resource|string|null', 'quality='=>'int', 'speed='=>'int'], 'imagebmp' => ['bool', 'image'=>'GdImage', 'file='=>'resource|string|null', 'compressed='=>'bool'], 'imagechar' => ['bool', 'image'=>'GdImage', 'font'=>'int', 'x'=>'int', 'y'=>'int', 'char'=>'string', 'color'=>'int'], 'imagecharup' => ['bool', 'image'=>'GdImage', 'font'=>'int', 'x'=>'int', 'y'=>'int', 'char'=>'string', 'color'=>'int'], 'imagecolorallocate' => ['int|false', 'image'=>'GdImage', 'red'=>'int', 'green'=>'int', 'blue'=>'int'], 'imagecolorallocatealpha' => ['int|false', 'image'=>'GdImage', 'red'=>'int', 'green'=>'int', 'blue'=>'int', 'alpha'=>'int'], 'imagecolorat' => ['int|false', 'image'=>'GdImage', 'x'=>'int', 'y'=>'int'], 'imagecolorclosest' => ['int', 'image'=>'GdImage', 'red'=>'int', 'green'=>'int', 'blue'=>'int'], 'imagecolorclosestalpha' => ['int', 'image'=>'GdImage', 'red'=>'int', 'green'=>'int', 'blue'=>'int', 'alpha'=>'int'], 'imagecolorclosesthwb' => ['int', 'image'=>'GdImage', 'red'=>'int', 'green'=>'int', 'blue'=>'int'], 'imagecolordeallocate' => ['bool', 'image'=>'GdImage', 'color'=>'int'], 'imagecolorexact' => ['int', 'image'=>'GdImage', 'red'=>'int', 'green'=>'int', 'blue'=>'int'], 'imagecolorexactalpha' => ['int', 'image'=>'GdImage', 'red'=>'int', 'green'=>'int', 'blue'=>'int', 'alpha'=>'int'], 'imagecolormatch' => ['bool', 'image1'=>'GdImage', 'image2'=>'GdImage'], 'imagecolorresolve' => ['int', 'image'=>'GdImage', 'red'=>'int', 'green'=>'int', 'blue'=>'int'], 'imagecolorresolvealpha' => ['int', 'image'=>'GdImage', 'red'=>'int', 'green'=>'int', 'blue'=>'int', 'alpha'=>'int'], 'imagecolorset' => ['false|null', 'image'=>'GdImage', 'color'=>'int', 'red'=>'int', 'green'=>'int', 'blue'=>'int', 'alpha='=>'int'], 'imagecolorsforindex' => ['array', 'image'=>'GdImage', 'color'=>'int'], 'imagecolorstotal' => ['int', 'image'=>'GdImage'], 'imagecolortransparent' => ['int', 'image'=>'GdImage', 'color='=>'?int'], 'imageconvolution' => ['bool', 'image'=>'GdImage', 'matrix'=>'array', 'divisor'=>'float', 'offset'=>'float'], 'imagecopy' => ['bool', 'dst_image'=>'GdImage', 'src_image'=>'GdImage', 'dst_x'=>'int', 'dst_y'=>'int', 'src_x'=>'int', 'src_y'=>'int', 'src_width'=>'int', 'src_height'=>'int'], 'imagecopymerge' => ['bool', 'dst_image'=>'GdImage', 'src_image'=>'GdImage', 'dst_x'=>'int', 'dst_y'=>'int', 'src_x'=>'int', 'src_y'=>'int', 'src_width'=>'int', 'src_height'=>'int', 'pct'=>'int'], 'imagecopymergegray' => ['bool', 'dst_image'=>'GdImage', 'src_image'=>'GdImage', 'dst_x'=>'int', 'dst_y'=>'int', 'src_x'=>'int', 'src_y'=>'int', 'src_width'=>'int', 'src_height'=>'int', 'pct'=>'int'], 'imagecopyresampled' => ['bool', 'dst_image'=>'GdImage', 'src_image'=>'GdImage', 'dst_x'=>'int', 'dst_y'=>'int', 'src_x'=>'int', 'src_y'=>'int', 'dst_width'=>'int', 'dst_height'=>'int', 'src_width'=>'int', 'src_height'=>'int'], 'imagecopyresized' => ['bool', 'dst_image'=>'GdImage', 'src_image'=>'GdImage', 'dst_x'=>'int', 'dst_y'=>'int', 'src_x'=>'int', 'src_y'=>'int', 'dst_width'=>'int', 'dst_height'=>'int', 'src_width'=>'int', 'src_height'=>'int'], 'imagecreate' => ['false|GdImage', 'width'=>'int', 'height'=>'int'], 'imagecreatefromavif' => ['false|GdImage', 'filename'=>'string'], 'imagecreatefrombmp' => ['false|GdImage', 'filename'=>'string'], 'imagecreatefromgd' => ['false|GdImage', 'filename'=>'string'], 'imagecreatefromgd2' => ['false|GdImage', 'filename'=>'string'], 'imagecreatefromgd2part' => ['false|GdImage', 'filename'=>'string', 'x'=>'int', 'y'=>'int', 'width'=>'int', 'height'=>'int'], 'imagecreatefromgif' => ['false|GdImage', 'filename'=>'string'], 'imagecreatefromjpeg' => ['false|GdImage', 'filename'=>'string'], 'imagecreatefrompng' => ['false|GdImage', 'filename'=>'string'], 'imagecreatefromstring' => ['false|GdImage', 'data'=>'string'], 'imagecreatefromwbmp' => ['false|GdImage', 'filename'=>'string'], 'imagecreatefromwebp' => ['false|GdImage', 'filename'=>'string'], 'imagecreatefromxbm' => ['false|GdImage', 'filename'=>'string'], 'imagecreatefromxpm' => ['false|GdImage', 'filename'=>'string'], 'imagecreatetruecolor' => ['false|GdImage', 'width'=>'int', 'height'=>'int'], 'imagecrop' => ['false|GdImage', 'image'=>'GdImage', 'rectangle'=>'array'], 'imagecropauto' => ['false|GdImage', 'image'=>'GdImage', 'mode='=>'int', 'threshold='=>'float', 'color='=>'int'], 'imagedashedline' => ['bool', 'image'=>'GdImage', 'x1'=>'int', 'y1'=>'int', 'x2'=>'int', 'y2'=>'int', 'color'=>'int'], 'imagedestroy' => ['bool', 'image'=>'GdImage'], 'imageellipse' => ['bool', 'image'=>'GdImage', 'center_x'=>'int', 'center_y'=>'int', 'width'=>'int', 'height'=>'int', 'color'=>'int'], 'imagefill' => ['bool', 'image'=>'GdImage', 'x'=>'int', 'y'=>'int', 'color'=>'int'], 'imagefilledarc' => ['bool', 'image'=>'GdImage', 'center_x'=>'int', 'center_y'=>'int', 'width'=>'int', 'height'=>'int', 'start_angle'=>'int', 'end_angle'=>'int', 'color'=>'int', 'style'=>'int'], 'imagefilledellipse' => ['bool', 'image'=>'GdImage', 'center_x'=>'int', 'center_y'=>'int', 'width'=>'int', 'height'=>'int', 'color'=>'int'], 'imagefilledpolygon' => ['bool', 'image'=>'GdImage', 'points'=>'array', 'num_points_or_color'=>'int', 'color'=>'int'], 'imagefilledrectangle' => ['bool', 'image'=>'GdImage', 'x1'=>'int', 'y1'=>'int', 'x2'=>'int', 'y2'=>'int', 'color'=>'int'], 'imagefilltoborder' => ['bool', 'image'=>'GdImage', 'x'=>'int', 'y'=>'int', 'border_color'=>'int', 'color'=>'int'], 'imagefilter' => ['bool', 'image'=>'GdImage', 'filter'=>'int', '...args='=>'array|int|float|bool'], 'imageflip' => ['bool', 'image'=>'GdImage', 'mode'=>'int'], 'imagefontheight' => ['int', 'font'=>'int'], 'imagefontwidth' => ['int', 'font'=>'int'], 'imageftbbox' => ['array|false', 'size'=>'float', 'angle'=>'float', 'font_filename'=>'string', 'string'=>'string', 'options='=>'array'], 'imagefttext' => ['array|false', 'image'=>'GdImage', 'size'=>'float', 'angle'=>'float', 'x'=>'int', 'y'=>'int', 'color'=>'int', 'font_filename'=>'string', 'text'=>'string', 'options='=>'array'], 'imagegammacorrect' => ['bool', 'image'=>'GdImage', 'input_gamma'=>'float', 'output_gamma'=>'float'], 'imagegd' => ['bool', 'image'=>'GdImage', 'file='=>'string|resource|null'], 'imagegd2' => ['bool', 'image'=>'GdImage', 'file='=>'string|resource|null', 'chunk_size='=>'int', 'mode='=>'int'], 'imagegetclip' => ['array', 'image'=>'GdImage'], 'imagegetinterpolation' => ['int', 'image'=>'GdImage'], 'imagegif' => ['bool', 'image'=>'GdImage', 'file='=>'string|resource|null'], 'imagegrabscreen' => ['false|GdImage'], 'imagegrabwindow' => ['false|GdImage', 'handle'=>'int', 'client_area='=>'int'], 'imageinterlace' => ['bool', 'image'=>'GdImage', 'enable='=>'bool|null'], 'imageistruecolor' => ['bool', 'image'=>'GdImage'], 'imagejpeg' => ['bool', 'image'=>'GdImage', 'file='=>'string|resource|null', 'quality='=>'int'], 'imagelayereffect' => ['bool', 'image'=>'GdImage', 'effect'=>'int'], 'imageline' => ['bool', 'image'=>'GdImage', 'x1'=>'int', 'y1'=>'int', 'x2'=>'int', 'y2'=>'int', 'color'=>'int'], 'imageloadfont' => ['GdFont|false', 'filename'=>'string'], 'imageObj::pasteImage' => ['void', 'srcImg'=>'imageObj', 'transparentColorHex'=>'int', 'dstX'=>'int', 'dstY'=>'int', 'angle'=>'int'], 'imageObj::saveImage' => ['int', 'filename'=>'string', 'oMap'=>'mapObj'], 'imageObj::saveWebImage' => ['string'], 'imageopenpolygon' => ['bool', 'image'=>'GdImage', 'points'=>'array', 'num_points'=>'int', 'color'=>'int'], 'imagepalettecopy' => ['void', 'dst'=>'GdImage', 'src'=>'GdImage'], 'imagepalettetotruecolor' => ['bool', 'image'=>'GdImage'], 'imagepng' => ['bool', 'image'=>'GdImage', 'file='=>'string|resource|null', 'quality='=>'int', 'filters='=>'int'], 'imagepolygon' => ['bool', 'image'=>'GdImage', 'points'=>'array', 'num_points_or_color'=>'int', 'color'=>'int'], 'imagerectangle' => ['bool', 'image'=>'GdImage', 'x1'=>'int', 'y1'=>'int', 'x2'=>'int', 'y2'=>'int', 'color'=>'int'], 'imageresolution' => ['array|bool', 'image'=>'GdImage', 'resolution_x='=>'?int', 'resolution_y='=>'?int'], 'imagerotate' => ['false|GdImage', 'image'=>'GdImage', 'angle'=>'float', 'background_color'=>'int', 'ignore_transparent='=>'bool'], 'imagesavealpha' => ['bool', 'image'=>'GdImage', 'enable'=>'bool'], 'imagescale' => ['false|GdImage', 'image'=>'GdImage', 'width'=>'int', 'height='=>'int', 'mode='=>'int'], 'imagesetbrush' => ['bool', 'image'=>'GdImage', 'brush'=>'GdImage'], 'imagesetclip' => ['bool', 'image'=>'GdImage', 'x1'=>'int', 'x2'=>'int', 'y1'=>'int', 'y2'=>'int'], 'imagesetinterpolation' => ['bool', 'image'=>'GdImage', 'method='=>'int'], 'imagesetpixel' => ['bool', 'image'=>'GdImage', 'x'=>'int', 'y'=>'int', 'color'=>'int'], 'imagesetstyle' => ['bool', 'image'=>'GdImage', 'style'=>'non-empty-array'], 'imagesetthickness' => ['bool', 'image'=>'GdImage', 'thickness'=>'int'], 'imagesettile' => ['bool', 'image'=>'GdImage', 'tile'=>'GdImage'], 'imagestring' => ['bool', 'image'=>'GdImage', 'font'=>'int', 'x'=>'int', 'y'=>'int', 'string'=>'string', 'color'=>'int'], 'imagestringup' => ['bool', 'image'=>'GdImage', 'font'=>'int', 'x'=>'int', 'y'=>'int', 'string'=>'string', 'color'=>'int'], 'imagesx' => ['int', 'image'=>'GdImage'], 'imagesy' => ['int', 'image'=>'GdImage'], 'imagetruecolortopalette' => ['bool', 'image'=>'GdImage', 'dither'=>'bool', 'num_colors'=>'int'], 'imagettfbbox' => ['false|array', 'size'=>'float', 'angle'=>'float', 'font_filename'=>'string', 'string'=>'string', 'options='=>'array'], 'imagettftext' => ['false|array', 'image'=>'GdImage', 'size'=>'float', 'angle'=>'float', 'x'=>'int', 'y'=>'int', 'color'=>'int', 'font_filename'=>'string', 'text'=>'string', 'options='=>'array'], 'imagetypes' => ['int'], 'imagewbmp' => ['bool', 'image'=>'GdImage', 'file='=>'string|resource|null', 'foreground_color='=>'?int'], 'imagewebp' => ['bool', 'image'=>'GdImage', 'file='=>'string|resource|null', 'quality='=>'int'], 'imagexbm' => ['bool', 'image'=>'GdImage', 'filename'=>'?string', 'foreground_color='=>'?int'], 'Imagick::__construct' => ['void', 'files='=>'string|string[]'], 'Imagick::__toString' => ['string'], 'Imagick::adaptiveBlurImage' => ['bool', 'radius'=>'float', 'sigma'=>'float', 'channel='=>'int'], 'Imagick::adaptiveResizeImage' => ['bool', 'columns'=>'int', 'rows'=>'int', 'bestfit='=>'bool'], 'Imagick::adaptiveSharpenImage' => ['bool', 'radius'=>'float', 'sigma'=>'float', 'channel='=>'int'], 'Imagick::adaptiveThresholdImage' => ['bool', 'width'=>'int', 'height'=>'int', 'offset'=>'int'], 'Imagick::addImage' => ['bool', 'source'=>'Imagick'], 'Imagick::addNoiseImage' => ['bool', 'noise_type'=>'int', 'channel='=>'int'], 'Imagick::affineTransformImage' => ['bool', 'matrix'=>'ImagickDraw'], 'Imagick::animateImages' => ['bool', 'x_server'=>'string'], 'Imagick::annotateImage' => ['bool', 'draw_settings'=>'ImagickDraw', 'x'=>'float', 'y'=>'float', 'angle'=>'float', 'text'=>'string'], 'Imagick::appendImages' => ['Imagick', 'stack'=>'bool'], 'Imagick::autoGammaImage' => ['bool', 'channel='=>'int'], 'Imagick::autoLevelImage' => ['void', 'CHANNEL='=>'string'], 'Imagick::autoOrient' => ['bool'], 'Imagick::averageImages' => ['Imagick'], 'Imagick::blackThresholdImage' => ['bool', 'threshold'=>'mixed'], 'Imagick::blueShiftImage' => ['void', 'factor='=>'float'], 'Imagick::blurImage' => ['bool', 'radius'=>'float', 'sigma'=>'float', 'channel='=>'int'], 'Imagick::borderImage' => ['bool', 'bordercolor'=>'mixed', 'width'=>'int', 'height'=>'int'], 'Imagick::brightnessContrastImage' => ['void', 'brightness'=>'string', 'contrast'=>'string', 'CHANNEL='=>'string'], 'Imagick::charcoalImage' => ['bool', 'radius'=>'float', 'sigma'=>'float'], 'Imagick::chopImage' => ['bool', 'width'=>'int', 'height'=>'int', 'x'=>'int', 'y'=>'int'], 'Imagick::clampImage' => ['void', 'CHANNEL='=>'string'], 'Imagick::clear' => ['bool'], 'Imagick::clipImage' => ['bool'], 'Imagick::clipImagePath' => ['void', 'pathname'=>'string', 'inside'=>'string'], 'Imagick::clipPathImage' => ['bool', 'pathname'=>'string', 'inside'=>'bool'], 'Imagick::clone' => ['Imagick'], 'Imagick::clutImage' => ['bool', 'lookup_table'=>'Imagick', 'channel='=>'float'], 'Imagick::coalesceImages' => ['Imagick'], 'Imagick::colorFloodfillImage' => ['bool', 'fill'=>'mixed', 'fuzz'=>'float', 'bordercolor'=>'mixed', 'x'=>'int', 'y'=>'int'], 'Imagick::colorizeImage' => ['bool', 'colorize'=>'mixed', 'opacity'=>'mixed'], 'Imagick::colorMatrixImage' => ['void', 'color_matrix'=>'string'], 'Imagick::combineImages' => ['Imagick', 'channeltype'=>'int'], 'Imagick::commentImage' => ['bool', 'comment'=>'string'], 'Imagick::compareImageChannels' => ['array{Imagick, float}', 'image'=>'Imagick', 'channeltype'=>'int', 'metrictype'=>'int'], 'Imagick::compareImageLayers' => ['Imagick', 'method'=>'int'], 'Imagick::compareImages' => ['array{Imagick, float}', 'compare'=>'Imagick', 'metric'=>'int'], 'Imagick::compositeImage' => ['bool', 'composite_object'=>'Imagick', 'composite'=>'int', 'x'=>'int', 'y'=>'int', 'channel='=>'int'], 'Imagick::compositeImageGravity' => ['bool', 'Imagick'=>'Imagick', 'COMPOSITE_CONSTANT'=>'int', 'GRAVITY_CONSTANT'=>'int'], 'Imagick::contrastImage' => ['bool', 'sharpen'=>'bool'], 'Imagick::contrastStretchImage' => ['bool', 'black_point'=>'float', 'white_point'=>'float', 'channel='=>'int'], 'Imagick::convolveImage' => ['bool', 'kernel'=>'array', 'channel='=>'int'], 'Imagick::count' => ['void', 'mode='=>'string'], 'Imagick::cropImage' => ['bool', 'width'=>'int', 'height'=>'int', 'x'=>'int', 'y'=>'int'], 'Imagick::cropThumbnailImage' => ['bool', 'width'=>'int', 'height'=>'int', 'legacy='=>'bool'], 'Imagick::current' => ['Imagick'], 'Imagick::cycleColormapImage' => ['bool', 'displace'=>'int'], 'Imagick::decipherImage' => ['bool', 'passphrase'=>'string'], 'Imagick::deconstructImages' => ['Imagick'], 'Imagick::deleteImageArtifact' => ['bool', 'artifact'=>'string'], 'Imagick::deleteImageProperty' => ['void', 'name'=>'string'], 'Imagick::deskewImage' => ['bool', 'threshold'=>'float'], 'Imagick::despeckleImage' => ['bool'], 'Imagick::destroy' => ['bool'], 'Imagick::displayImage' => ['bool', 'servername'=>'string'], 'Imagick::displayImages' => ['bool', 'servername'=>'string'], 'Imagick::distortImage' => ['bool', 'method'=>'int', 'arguments'=>'array', 'bestfit'=>'bool'], 'Imagick::drawImage' => ['bool', 'draw'=>'ImagickDraw'], 'Imagick::edgeImage' => ['bool', 'radius'=>'float'], 'Imagick::embossImage' => ['bool', 'radius'=>'float', 'sigma'=>'float'], 'Imagick::encipherImage' => ['bool', 'passphrase'=>'string'], 'Imagick::enhanceImage' => ['bool'], 'Imagick::equalizeImage' => ['bool'], 'Imagick::evaluateImage' => ['bool', 'op'=>'int', 'constant'=>'float', 'channel='=>'int'], 'Imagick::evaluateImages' => ['bool', 'EVALUATE_CONSTANT'=>'int'], 'Imagick::exportImagePixels' => ['list', 'x'=>'int', 'y'=>'int', 'width'=>'int', 'height'=>'int', 'map'=>'string', 'storage'=>'int'], 'Imagick::extentImage' => ['bool', 'width'=>'int', 'height'=>'int', 'x'=>'int', 'y'=>'int'], 'Imagick::filter' => ['void', 'ImagickKernel'=>'ImagickKernel', 'CHANNEL='=>'int'], 'Imagick::flattenImages' => ['Imagick'], 'Imagick::flipImage' => ['bool'], 'Imagick::floodFillPaintImage' => ['bool', 'fill'=>'mixed', 'fuzz'=>'float', 'target'=>'mixed', 'x'=>'int', 'y'=>'int', 'invert'=>'bool', 'channel='=>'int'], 'Imagick::flopImage' => ['bool'], 'Imagick::forwardFourierTransformimage' => ['void', 'magnitude'=>'bool'], 'Imagick::frameImage' => ['bool', 'matte_color'=>'mixed', 'width'=>'int', 'height'=>'int', 'inner_bevel'=>'int', 'outer_bevel'=>'int'], 'Imagick::functionImage' => ['bool', 'function'=>'int', 'arguments'=>'array', 'channel='=>'int'], 'Imagick::fxImage' => ['Imagick', 'expression'=>'string', 'channel='=>'int'], 'Imagick::gammaImage' => ['bool', 'gamma'=>'float', 'channel='=>'int'], 'Imagick::gaussianBlurImage' => ['bool', 'radius'=>'float', 'sigma'=>'float', 'channel='=>'int'], 'Imagick::getColorspace' => ['int'], 'Imagick::getCompression' => ['int'], 'Imagick::getCompressionQuality' => ['int'], 'Imagick::getConfigureOptions' => ['string'], 'Imagick::getCopyright' => ['string'], 'Imagick::getFeatures' => ['string'], 'Imagick::getFilename' => ['string'], 'Imagick::getFont' => ['string|false'], 'Imagick::getFormat' => ['string'], 'Imagick::getGravity' => ['int'], 'Imagick::getHDRIEnabled' => ['int'], 'Imagick::getHomeURL' => ['string'], 'Imagick::getImage' => ['Imagick'], 'Imagick::getImageAlphaChannel' => ['int'], 'Imagick::getImageArtifact' => ['string', 'artifact'=>'string'], 'Imagick::getImageAttribute' => ['string', 'key'=>'string'], 'Imagick::getImageBackgroundColor' => ['ImagickPixel'], 'Imagick::getImageBlob' => ['string'], 'Imagick::getImageBluePrimary' => ['array{x:float, y:float}'], 'Imagick::getImageBorderColor' => ['ImagickPixel'], 'Imagick::getImageChannelDepth' => ['int', 'channel'=>'int'], 'Imagick::getImageChannelDistortion' => ['float', 'reference'=>'Imagick', 'channel'=>'int', 'metric'=>'int'], 'Imagick::getImageChannelDistortions' => ['float', 'reference'=>'Imagick', 'metric'=>'int', 'channel='=>'int'], 'Imagick::getImageChannelExtrema' => ['array{minima:int, maxima:int}', 'channel'=>'int'], 'Imagick::getImageChannelKurtosis' => ['array{kurtosis:float, skewness:float}', 'channel='=>'int'], 'Imagick::getImageChannelMean' => ['array{mean:float, standardDeviation:float}', 'channel'=>'int'], 'Imagick::getImageChannelRange' => ['array{minima:float, maxima:float}', 'channel'=>'int'], 'Imagick::getImageChannelStatistics' => ['array'], 'Imagick::getImageClipMask' => ['Imagick'], 'Imagick::getImageColormapColor' => ['ImagickPixel', 'index'=>'int'], 'Imagick::getImageColors' => ['int'], 'Imagick::getImageColorspace' => ['int'], 'Imagick::getImageCompose' => ['int'], 'Imagick::getImageCompression' => ['int'], 'Imagick::getImageCompressionQuality' => ['int'], 'Imagick::getImageDelay' => ['int'], 'Imagick::getImageDepth' => ['int'], 'Imagick::getImageDispose' => ['int'], 'Imagick::getImageDistortion' => ['float', 'reference'=>'magickwand', 'metric'=>'int'], 'Imagick::getImageExtrema' => ['array{min:int, max:int}'], 'Imagick::getImageFilename' => ['string'], 'Imagick::getImageFormat' => ['string'], 'Imagick::getImageGamma' => ['float'], 'Imagick::getImageGeometry' => ['array{width:int, height:int}'], 'Imagick::getImageGravity' => ['int'], 'Imagick::getImageGreenPrimary' => ['array{x:float, y:float}'], 'Imagick::getImageHeight' => ['int'], 'Imagick::getImageHistogram' => ['list'], 'Imagick::getImageIndex' => ['int'], 'Imagick::getImageInterlaceScheme' => ['int'], 'Imagick::getImageInterpolateMethod' => ['int'], 'Imagick::getImageIterations' => ['int'], 'Imagick::getImageLength' => ['int'], 'Imagick::getImageMagickLicense' => ['string'], 'Imagick::getImageMatte' => ['bool'], 'Imagick::getImageMatteColor' => ['ImagickPixel'], 'Imagick::getImageMimeType' => ['string'], 'Imagick::getImageOrientation' => ['int'], 'Imagick::getImagePage' => ['array{width:int, height:int, x:int, y:int}'], 'Imagick::getImagePixelColor' => ['ImagickPixel', 'x'=>'int', 'y'=>'int'], 'Imagick::getImageProfile' => ['string', 'name'=>'string'], 'Imagick::getImageProfiles' => ['array', 'pattern='=>'string', 'only_names='=>'bool'], 'Imagick::getImageProperties' => ['array', 'pattern='=>'string', 'only_names='=>'bool'], 'Imagick::getImageProperty' => ['string|false', 'name'=>'string'], 'Imagick::getImageRedPrimary' => ['array{x:float, y:float}'], 'Imagick::getImageRegion' => ['Imagick', 'width'=>'int', 'height'=>'int', 'x'=>'int', 'y'=>'int'], 'Imagick::getImageRenderingIntent' => ['int'], 'Imagick::getImageResolution' => ['array{x:float, y:float}'], 'Imagick::getImagesBlob' => ['string'], 'Imagick::getImageScene' => ['int'], 'Imagick::getImageSignature' => ['string'], 'Imagick::getImageSize' => ['int'], 'Imagick::getImageTicksPerSecond' => ['int'], 'Imagick::getImageTotalInkDensity' => ['float'], 'Imagick::getImageType' => ['int'], 'Imagick::getImageUnits' => ['int'], 'Imagick::getImageVirtualPixelMethod' => ['int'], 'Imagick::getImageWhitePoint' => ['array{x:float, y:float}'], 'Imagick::getImageWidth' => ['int'], 'Imagick::getInterlaceScheme' => ['int'], 'Imagick::getIteratorIndex' => ['int'], 'Imagick::getNumberImages' => ['int'], 'Imagick::getOption' => ['string', 'key'=>'string'], 'Imagick::getPackageName' => ['string'], 'Imagick::getPage' => ['array{width:int, height:int, x:int, y:int}'], 'Imagick::getPixelIterator' => ['ImagickPixelIterator'], 'Imagick::getPixelRegionIterator' => ['ImagickPixelIterator', 'x'=>'int', 'y'=>'int', 'columns'=>'int', 'rows'=>'int'], 'Imagick::getPointSize' => ['float'], 'Imagick::getQuantum' => ['int'], 'Imagick::getQuantumDepth' => ['array{quantumDepthLong:int, quantumDepthString:string}'], 'Imagick::getQuantumRange' => ['array{quantumRangeLong:int, quantumRangeString:string}'], 'Imagick::getRegistry' => ['string|false', 'key'=>'string'], 'Imagick::getReleaseDate' => ['string'], 'Imagick::getResource' => ['int', 'type'=>'int'], 'Imagick::getResourceLimit' => ['int', 'type'=>'int'], 'Imagick::getSamplingFactors' => ['array'], 'Imagick::getSize' => ['array{columns:int, rows: int}'], 'Imagick::getSizeOffset' => ['int'], 'Imagick::getVersion' => ['array{versionNumber: int, versionString:string}'], 'Imagick::haldClutImage' => ['bool', 'clut'=>'Imagick', 'channel='=>'int'], 'Imagick::hasNextImage' => ['bool'], 'Imagick::hasPreviousImage' => ['bool'], 'Imagick::identifyFormat' => ['string|false', 'embedText'=>'string'], 'Imagick::identifyImage' => ['array', 'appendrawoutput='=>'bool'], 'Imagick::identifyImageType' => ['int'], 'Imagick::implodeImage' => ['bool', 'radius'=>'float'], 'Imagick::importImagePixels' => ['bool', 'x'=>'int', 'y'=>'int', 'width'=>'int', 'height'=>'int', 'map'=>'string', 'storage'=>'int', 'pixels'=>'list'], 'Imagick::inverseFourierTransformImage' => ['void', 'complement'=>'string', 'magnitude'=>'string'], 'Imagick::key' => ['int|string'], 'Imagick::labelImage' => ['bool', 'label'=>'string'], 'Imagick::levelImage' => ['bool', 'blackpoint'=>'float', 'gamma'=>'float', 'whitepoint'=>'float', 'channel='=>'int'], 'Imagick::linearStretchImage' => ['bool', 'blackpoint'=>'float', 'whitepoint'=>'float'], 'Imagick::liquidRescaleImage' => ['bool', 'width'=>'int', 'height'=>'int', 'delta_x'=>'float', 'rigidity'=>'float'], 'Imagick::listRegistry' => ['array'], 'Imagick::localContrastImage' => ['bool', 'radius'=>'float', 'strength'=>'float'], 'Imagick::magnifyImage' => ['bool'], 'Imagick::mapImage' => ['bool', 'map'=>'Imagick', 'dither'=>'bool'], 'Imagick::matteFloodfillImage' => ['bool', 'alpha'=>'float', 'fuzz'=>'float', 'bordercolor'=>'mixed', 'x'=>'int', 'y'=>'int'], 'Imagick::medianFilterImage' => ['bool', 'radius'=>'float'], 'Imagick::mergeImageLayers' => ['Imagick', 'layer_method'=>'int'], 'Imagick::minifyImage' => ['bool'], 'Imagick::modulateImage' => ['bool', 'brightness'=>'float', 'saturation'=>'float', 'hue'=>'float'], 'Imagick::montageImage' => ['Imagick', 'draw'=>'ImagickDraw', 'tile_geometry'=>'string', 'thumbnail_geometry'=>'string', 'mode'=>'int', 'frame'=>'string'], 'Imagick::morphImages' => ['Imagick', 'number_frames'=>'int'], 'Imagick::morphology' => ['void', 'morphologyMethod'=>'int', 'iterations'=>'int', 'ImagickKernel'=>'ImagickKernel', 'CHANNEL='=>'string'], 'Imagick::mosaicImages' => ['Imagick'], 'Imagick::motionBlurImage' => ['bool', 'radius'=>'float', 'sigma'=>'float', 'angle'=>'float', 'channel='=>'int'], 'Imagick::negateImage' => ['bool', 'gray'=>'bool', 'channel='=>'int'], 'Imagick::newImage' => ['bool', 'cols'=>'int', 'rows'=>'int', 'background'=>'mixed', 'format='=>'string'], 'Imagick::newPseudoImage' => ['bool', 'columns'=>'int', 'rows'=>'int', 'pseudostring'=>'string'], 'Imagick::next' => ['void'], 'Imagick::nextImage' => ['bool'], 'Imagick::normalizeImage' => ['bool', 'channel='=>'int'], 'Imagick::oilPaintImage' => ['bool', 'radius'=>'float'], 'Imagick::opaquePaintImage' => ['bool', 'target'=>'mixed', 'fill'=>'mixed', 'fuzz'=>'float', 'invert'=>'bool', 'channel='=>'int'], 'Imagick::optimizeImageLayers' => ['bool'], 'Imagick::orderedPosterizeImage' => ['bool', 'threshold_map'=>'string', 'channel='=>'int'], 'Imagick::paintFloodfillImage' => ['bool', 'fill'=>'mixed', 'fuzz'=>'float', 'bordercolor'=>'mixed', 'x'=>'int', 'y'=>'int', 'channel='=>'int'], 'Imagick::paintOpaqueImage' => ['bool', 'target'=>'mixed', 'fill'=>'mixed', 'fuzz'=>'float', 'channel='=>'int'], 'Imagick::paintTransparentImage' => ['bool', 'target'=>'mixed', 'alpha'=>'float', 'fuzz'=>'float'], 'Imagick::pingImage' => ['bool', 'filename'=>'string'], 'Imagick::pingImageBlob' => ['bool', 'image'=>'string'], 'Imagick::pingImageFile' => ['bool', 'filehandle'=>'resource', 'filename='=>'string'], 'Imagick::polaroidImage' => ['bool', 'properties'=>'ImagickDraw', 'angle'=>'float'], 'Imagick::posterizeImage' => ['bool', 'levels'=>'int', 'dither'=>'bool'], 'Imagick::previewImages' => ['bool', 'preview'=>'int'], 'Imagick::previousImage' => ['bool'], 'Imagick::profileImage' => ['bool', 'name'=>'string', 'profile'=>'string'], 'Imagick::quantizeImage' => ['bool', 'numbercolors'=>'int', 'colorspace'=>'int', 'treedepth'=>'int', 'dither'=>'bool', 'measureerror'=>'bool'], 'Imagick::quantizeImages' => ['bool', 'numbercolors'=>'int', 'colorspace'=>'int', 'treedepth'=>'int', 'dither'=>'bool', 'measureerror'=>'bool'], 'Imagick::queryFontMetrics' => ['array', 'properties'=>'ImagickDraw', 'text'=>'string', 'multiline='=>'bool'], 'Imagick::queryFonts' => ['array', 'pattern='=>'string'], 'Imagick::queryFormats' => ['list', 'pattern='=>'string'], 'Imagick::radialBlurImage' => ['bool', 'angle'=>'float', 'channel='=>'int'], 'Imagick::raiseImage' => ['bool', 'width'=>'int', 'height'=>'int', 'x'=>'int', 'y'=>'int', 'raise'=>'bool'], 'Imagick::randomThresholdImage' => ['bool', 'low'=>'float', 'high'=>'float', 'channel='=>'int'], 'Imagick::readImage' => ['bool', 'filename'=>'string'], 'Imagick::readImageBlob' => ['bool', 'image'=>'string', 'filename='=>'string'], 'Imagick::readImageFile' => ['bool', 'filehandle'=>'resource', 'filename='=>'string'], 'Imagick::readImages' => ['Imagick', 'filenames'=>'string'], 'Imagick::recolorImage' => ['bool', 'matrix'=>'list'], 'Imagick::reduceNoiseImage' => ['bool', 'radius'=>'float'], 'Imagick::remapImage' => ['bool', 'replacement'=>'Imagick', 'dither'=>'int'], 'Imagick::removeImage' => ['bool'], 'Imagick::removeImageProfile' => ['string', 'name'=>'string'], 'Imagick::render' => ['bool'], 'Imagick::resampleImage' => ['bool', 'x_resolution'=>'float', 'y_resolution'=>'float', 'filter'=>'int', 'blur'=>'float'], 'Imagick::resetImagePage' => ['bool', 'page'=>'string'], 'Imagick::resetIterator' => [''], 'Imagick::resizeImage' => ['bool', 'columns'=>'int', 'rows'=>'int', 'filter'=>'int', 'blur'=>'float', 'bestfit='=>'bool'], 'Imagick::rewind' => ['void'], 'Imagick::rollImage' => ['bool', 'x'=>'int', 'y'=>'int'], 'Imagick::rotateImage' => ['bool', 'background'=>'mixed', 'degrees'=>'float'], 'Imagick::rotationalBlurImage' => ['void', 'angle'=>'string', 'CHANNEL='=>'string'], 'Imagick::roundCorners' => ['bool', 'x_rounding'=>'float', 'y_rounding'=>'float', 'stroke_width='=>'float', 'displace='=>'float', 'size_correction='=>'float'], 'Imagick::roundCornersImage' => ['', 'xRounding'=>'', 'yRounding'=>'', 'strokeWidth'=>'', 'displace'=>'', 'sizeCorrection'=>''], 'Imagick::sampleImage' => ['bool', 'columns'=>'int', 'rows'=>'int'], 'Imagick::scaleImage' => ['bool', 'cols'=>'int', 'rows'=>'int', 'bestfit='=>'bool'], 'Imagick::segmentImage' => ['bool', 'colorspace'=>'int', 'cluster_threshold'=>'float', 'smooth_threshold'=>'float', 'verbose='=>'bool'], 'Imagick::selectiveBlurImage' => ['void', 'radius'=>'float', 'sigma'=>'float', 'threshold'=>'float', 'CHANNEL'=>'int'], 'Imagick::separateImageChannel' => ['bool', 'channel'=>'int'], 'Imagick::sepiaToneImage' => ['bool', 'threshold'=>'float'], 'Imagick::setAntiAlias' => ['int', 'antialias'=>'bool'], 'Imagick::setBackgroundColor' => ['bool', 'background'=>'mixed'], 'Imagick::setColorspace' => ['bool', 'colorspace'=>'int'], 'Imagick::setCompression' => ['bool', 'compression'=>'int'], 'Imagick::setCompressionQuality' => ['bool', 'quality'=>'int'], 'Imagick::setFilename' => ['bool', 'filename'=>'string'], 'Imagick::setFirstIterator' => ['bool'], 'Imagick::setFont' => ['bool', 'font'=>'string'], 'Imagick::setFormat' => ['bool', 'format'=>'string'], 'Imagick::setGravity' => ['bool', 'gravity'=>'int'], 'Imagick::setImage' => ['bool', 'replace'=>'Imagick'], 'Imagick::setImageAlpha' => ['bool', 'alpha'=>'float'], 'Imagick::setImageAlphaChannel' => ['bool', 'mode'=>'int'], 'Imagick::setImageArtifact' => ['bool', 'artifact'=>'string', 'value'=>'string'], 'Imagick::setImageAttribute' => ['void', 'key'=>'string', 'value'=>'string'], 'Imagick::setImageBackgroundColor' => ['bool', 'background'=>'mixed'], 'Imagick::setImageBias' => ['bool', 'bias'=>'float'], 'Imagick::setImageBiasQuantum' => ['void', 'bias'=>'string'], 'Imagick::setImageBluePrimary' => ['bool', 'x'=>'float', 'y'=>'float'], 'Imagick::setImageBorderColor' => ['bool', 'border'=>'mixed'], 'Imagick::setImageChannelDepth' => ['bool', 'channel'=>'int', 'depth'=>'int'], 'Imagick::setImageChannelMask' => ['', 'channel'=>'int'], 'Imagick::setImageClipMask' => ['bool', 'clip_mask'=>'Imagick'], 'Imagick::setImageColormapColor' => ['bool', 'index'=>'int', 'color'=>'ImagickPixel'], 'Imagick::setImageColorspace' => ['bool', 'colorspace'=>'int'], 'Imagick::setImageCompose' => ['bool', 'compose'=>'int'], 'Imagick::setImageCompression' => ['bool', 'compression'=>'int'], 'Imagick::setImageCompressionQuality' => ['bool', 'quality'=>'int'], 'Imagick::setImageDelay' => ['bool', 'delay'=>'int'], 'Imagick::setImageDepth' => ['bool', 'depth'=>'int'], 'Imagick::setImageDispose' => ['bool', 'dispose'=>'int'], 'Imagick::setImageExtent' => ['bool', 'columns'=>'int', 'rows'=>'int'], 'Imagick::setImageFilename' => ['bool', 'filename'=>'string'], 'Imagick::setImageFormat' => ['bool', 'format'=>'string'], 'Imagick::setImageGamma' => ['bool', 'gamma'=>'float'], 'Imagick::setImageGravity' => ['bool', 'gravity'=>'int'], 'Imagick::setImageGreenPrimary' => ['bool', 'x'=>'float', 'y'=>'float'], 'Imagick::setImageIndex' => ['bool', 'index'=>'int'], 'Imagick::setImageInterlaceScheme' => ['bool', 'interlace_scheme'=>'int'], 'Imagick::setImageInterpolateMethod' => ['bool', 'method'=>'int'], 'Imagick::setImageIterations' => ['bool', 'iterations'=>'int'], 'Imagick::setImageMatte' => ['bool', 'matte'=>'bool'], 'Imagick::setImageMatteColor' => ['bool', 'matte'=>'mixed'], 'Imagick::setImageOpacity' => ['bool', 'opacity'=>'float'], 'Imagick::setImageOrientation' => ['bool', 'orientation'=>'int'], 'Imagick::setImagePage' => ['bool', 'width'=>'int', 'height'=>'int', 'x'=>'int', 'y'=>'int'], 'Imagick::setImageProfile' => ['bool', 'name'=>'string', 'profile'=>'string'], 'Imagick::setImageProgressMonitor' => ['', 'filename'=>''], 'Imagick::setImageProperty' => ['bool', 'name'=>'string', 'value'=>'string'], 'Imagick::setImageRedPrimary' => ['bool', 'x'=>'float', 'y'=>'float'], 'Imagick::setImageRenderingIntent' => ['bool', 'rendering_intent'=>'int'], 'Imagick::setImageResolution' => ['bool', 'x_resolution'=>'float', 'y_resolution'=>'float'], 'Imagick::setImageScene' => ['bool', 'scene'=>'int'], 'Imagick::setImageTicksPerSecond' => ['bool', 'ticks_per_second'=>'int'], 'Imagick::setImageType' => ['bool', 'image_type'=>'int'], 'Imagick::setImageUnits' => ['bool', 'units'=>'int'], 'Imagick::setImageVirtualPixelMethod' => ['bool', 'method'=>'int'], 'Imagick::setImageWhitePoint' => ['bool', 'x'=>'float', 'y'=>'float'], 'Imagick::setInterlaceScheme' => ['bool', 'interlace_scheme'=>'int'], 'Imagick::setIteratorIndex' => ['bool', 'index'=>'int'], 'Imagick::setLastIterator' => ['bool'], 'Imagick::setOption' => ['bool', 'key'=>'string', 'value'=>'string'], 'Imagick::setPage' => ['bool', 'width'=>'int', 'height'=>'int', 'x'=>'int', 'y'=>'int'], 'Imagick::setPointSize' => ['bool', 'point_size'=>'float'], 'Imagick::setProgressMonitor' => ['void', 'callback'=>'callable'], 'Imagick::setRegistry' => ['void', 'key'=>'string', 'value'=>'string'], 'Imagick::setResolution' => ['bool', 'x_resolution'=>'float', 'y_resolution'=>'float'], 'Imagick::setResourceLimit' => ['bool', 'type'=>'int', 'limit'=>'int'], 'Imagick::setSamplingFactors' => ['bool', 'factors'=>'list'], 'Imagick::setSize' => ['bool', 'columns'=>'int', 'rows'=>'int'], 'Imagick::setSizeOffset' => ['bool', 'columns'=>'int', 'rows'=>'int', 'offset'=>'int'], 'Imagick::setType' => ['bool', 'image_type'=>'int'], 'Imagick::shadeImage' => ['bool', 'gray'=>'bool', 'azimuth'=>'float', 'elevation'=>'float'], 'Imagick::shadowImage' => ['bool', 'opacity'=>'float', 'sigma'=>'float', 'x'=>'int', 'y'=>'int'], 'Imagick::sharpenImage' => ['bool', 'radius'=>'float', 'sigma'=>'float', 'channel='=>'int'], 'Imagick::shaveImage' => ['bool', 'columns'=>'int', 'rows'=>'int'], 'Imagick::shearImage' => ['bool', 'background'=>'mixed', 'x_shear'=>'float', 'y_shear'=>'float'], 'Imagick::sigmoidalContrastImage' => ['bool', 'sharpen'=>'bool', 'alpha'=>'float', 'beta'=>'float', 'channel='=>'int'], 'Imagick::similarityImage' => ['Imagick', 'Imagick'=>'Imagick', '&bestMatch'=>'array', '&similarity'=>'float', 'similarity_threshold'=>'float', 'metric'=>'int'], 'Imagick::sketchImage' => ['bool', 'radius'=>'float', 'sigma'=>'float', 'angle'=>'float'], 'Imagick::smushImages' => ['Imagick', 'stack'=>'string', 'offset'=>'string'], 'Imagick::solarizeImage' => ['bool', 'threshold'=>'int'], 'Imagick::sparseColorImage' => ['bool', 'sparse_method'=>'int', 'arguments'=>'array', 'channel='=>'int'], 'Imagick::spliceImage' => ['bool', 'width'=>'int', 'height'=>'int', 'x'=>'int', 'y'=>'int'], 'Imagick::spreadImage' => ['bool', 'radius'=>'float'], 'Imagick::statisticImage' => ['void', 'type'=>'int', 'width'=>'int', 'height'=>'int', 'CHANNEL='=>'string'], 'Imagick::steganoImage' => ['Imagick', 'watermark_wand'=>'Imagick', 'offset'=>'int'], 'Imagick::stereoImage' => ['bool', 'offset_wand'=>'Imagick'], 'Imagick::stripImage' => ['bool'], 'Imagick::subImageMatch' => ['Imagick', 'Imagick'=>'Imagick', '&w_offset='=>'array', '&w_similarity='=>'float'], 'Imagick::swirlImage' => ['bool', 'degrees'=>'float'], 'Imagick::textureImage' => ['bool', 'texture_wand'=>'Imagick'], 'Imagick::thresholdImage' => ['bool', 'threshold'=>'float', 'channel='=>'int'], 'Imagick::thumbnailImage' => ['bool', 'columns'=>'int', 'rows'=>'int', 'bestfit='=>'bool', 'fill='=>'bool', 'legacy='=>'bool'], 'Imagick::tintImage' => ['bool', 'tint'=>'mixed', 'opacity'=>'mixed'], 'Imagick::transformImage' => ['Imagick', 'crop'=>'string', 'geometry'=>'string'], 'Imagick::transformImageColorspace' => ['bool', 'colorspace'=>'int'], 'Imagick::transparentPaintImage' => ['bool', 'target'=>'mixed', 'alpha'=>'float', 'fuzz'=>'float', 'invert'=>'bool'], 'Imagick::transposeImage' => ['bool'], 'Imagick::transverseImage' => ['bool'], 'Imagick::trimImage' => ['bool', 'fuzz'=>'float'], 'Imagick::uniqueImageColors' => ['bool'], 'Imagick::unsharpMaskImage' => ['bool', 'radius'=>'float', 'sigma'=>'float', 'amount'=>'float', 'threshold'=>'float', 'channel='=>'int'], 'Imagick::valid' => ['bool'], 'Imagick::vignetteImage' => ['bool', 'blackpoint'=>'float', 'whitepoint'=>'float', 'x'=>'int', 'y'=>'int'], 'Imagick::waveImage' => ['bool', 'amplitude'=>'float', 'length'=>'float'], 'Imagick::whiteThresholdImage' => ['bool', 'threshold'=>'mixed'], 'Imagick::writeImage' => ['bool', 'filename='=>'string'], 'Imagick::writeImageFile' => ['bool', 'filehandle'=>'resource'], 'Imagick::writeImages' => ['bool', 'filename'=>'string', 'adjoin'=>'bool'], 'Imagick::writeImagesFile' => ['bool', 'filehandle'=>'resource'], 'ImagickDraw::__construct' => ['void'], 'ImagickDraw::affine' => ['bool', 'affine'=>'array'], 'ImagickDraw::annotation' => ['bool', 'x'=>'float', 'y'=>'float', 'text'=>'string'], 'ImagickDraw::arc' => ['bool', 'sx'=>'float', 'sy'=>'float', 'ex'=>'float', 'ey'=>'float', 'sd'=>'float', 'ed'=>'float'], 'ImagickDraw::bezier' => ['bool', 'coordinates'=>'list'], 'ImagickDraw::circle' => ['bool', 'ox'=>'float', 'oy'=>'float', 'px'=>'float', 'py'=>'float'], 'ImagickDraw::clear' => ['bool'], 'ImagickDraw::clone' => ['ImagickDraw'], 'ImagickDraw::color' => ['bool', 'x'=>'float', 'y'=>'float', 'paintmethod'=>'int'], 'ImagickDraw::comment' => ['bool', 'comment'=>'string'], 'ImagickDraw::composite' => ['bool', 'compose'=>'int', 'x'=>'float', 'y'=>'float', 'width'=>'float', 'height'=>'float', 'compositewand'=>'Imagick'], 'ImagickDraw::destroy' => ['bool'], 'ImagickDraw::ellipse' => ['bool', 'ox'=>'float', 'oy'=>'float', 'rx'=>'float', 'ry'=>'float', 'start'=>'float', 'end'=>'float'], 'ImagickDraw::getBorderColor' => ['ImagickPixel'], 'ImagickDraw::getClipPath' => ['string|false'], 'ImagickDraw::getClipRule' => ['int'], 'ImagickDraw::getClipUnits' => ['int'], 'ImagickDraw::getDensity' => ['?string'], 'ImagickDraw::getFillColor' => ['ImagickPixel'], 'ImagickDraw::getFillOpacity' => ['float'], 'ImagickDraw::getFillRule' => ['int'], 'ImagickDraw::getFont' => ['string|false'], 'ImagickDraw::getFontFamily' => ['string|false'], 'ImagickDraw::getFontResolution' => ['array'], 'ImagickDraw::getFontSize' => ['float'], 'ImagickDraw::getFontStretch' => ['int'], 'ImagickDraw::getFontStyle' => ['int'], 'ImagickDraw::getFontWeight' => ['int'], 'ImagickDraw::getGravity' => ['int'], 'ImagickDraw::getOpacity' => ['float'], 'ImagickDraw::getStrokeAntialias' => ['bool'], 'ImagickDraw::getStrokeColor' => ['ImagickPixel'], 'ImagickDraw::getStrokeDashArray' => ['array'], 'ImagickDraw::getStrokeDashOffset' => ['float'], 'ImagickDraw::getStrokeLineCap' => ['int'], 'ImagickDraw::getStrokeLineJoin' => ['int'], 'ImagickDraw::getStrokeMiterLimit' => ['int'], 'ImagickDraw::getStrokeOpacity' => ['float'], 'ImagickDraw::getStrokeWidth' => ['float'], 'ImagickDraw::getTextAlignment' => ['int'], 'ImagickDraw::getTextAntialias' => ['bool'], 'ImagickDraw::getTextDecoration' => ['int'], 'ImagickDraw::getTextDirection' => ['bool'], 'ImagickDraw::getTextEncoding' => ['string'], 'ImagickDraw::getTextInterlineSpacing' => ['float'], 'ImagickDraw::getTextInterwordSpacing' => ['float'], 'ImagickDraw::getTextKerning' => ['float'], 'ImagickDraw::getTextUnderColor' => ['ImagickPixel'], 'ImagickDraw::getVectorGraphics' => ['string'], 'ImagickDraw::line' => ['bool', 'sx'=>'float', 'sy'=>'float', 'ex'=>'float', 'ey'=>'float'], 'ImagickDraw::matte' => ['bool', 'x'=>'float', 'y'=>'float', 'paintmethod'=>'int'], 'ImagickDraw::pathClose' => ['bool'], 'ImagickDraw::pathCurveToAbsolute' => ['bool', 'x1'=>'float', 'y1'=>'float', 'x2'=>'float', 'y2'=>'float', 'x'=>'float', 'y'=>'float'], 'ImagickDraw::pathCurveToQuadraticBezierAbsolute' => ['bool', 'x1'=>'float', 'y1'=>'float', 'x'=>'float', 'y'=>'float'], 'ImagickDraw::pathCurveToQuadraticBezierRelative' => ['bool', 'x1'=>'float', 'y1'=>'float', 'x'=>'float', 'y'=>'float'], 'ImagickDraw::pathCurveToQuadraticBezierSmoothAbsolute' => ['bool', 'x'=>'float', 'y'=>'float'], 'ImagickDraw::pathCurveToQuadraticBezierSmoothRelative' => ['bool', 'x'=>'float', 'y'=>'float'], 'ImagickDraw::pathCurveToRelative' => ['bool', 'x1'=>'float', 'y1'=>'float', 'x2'=>'float', 'y2'=>'float', 'x'=>'float', 'y'=>'float'], 'ImagickDraw::pathCurveToSmoothAbsolute' => ['bool', 'x2'=>'float', 'y2'=>'float', 'x'=>'float', 'y'=>'float'], 'ImagickDraw::pathCurveToSmoothRelative' => ['bool', 'x2'=>'float', 'y2'=>'float', 'x'=>'float', 'y'=>'float'], 'ImagickDraw::pathEllipticArcAbsolute' => ['bool', 'rx'=>'float', 'ry'=>'float', 'x_axis_rotation'=>'float', 'large_arc_flag'=>'bool', 'sweep_flag'=>'bool', 'x'=>'float', 'y'=>'float'], 'ImagickDraw::pathEllipticArcRelative' => ['bool', 'rx'=>'float', 'ry'=>'float', 'x_axis_rotation'=>'float', 'large_arc_flag'=>'bool', 'sweep_flag'=>'bool', 'x'=>'float', 'y'=>'float'], 'ImagickDraw::pathFinish' => ['bool'], 'ImagickDraw::pathLineToAbsolute' => ['bool', 'x'=>'float', 'y'=>'float'], 'ImagickDraw::pathLineToHorizontalAbsolute' => ['bool', 'x'=>'float'], 'ImagickDraw::pathLineToHorizontalRelative' => ['bool', 'x'=>'float'], 'ImagickDraw::pathLineToRelative' => ['bool', 'x'=>'float', 'y'=>'float'], 'ImagickDraw::pathLineToVerticalAbsolute' => ['bool', 'y'=>'float'], 'ImagickDraw::pathLineToVerticalRelative' => ['bool', 'y'=>'float'], 'ImagickDraw::pathMoveToAbsolute' => ['bool', 'x'=>'float', 'y'=>'float'], 'ImagickDraw::pathMoveToRelative' => ['bool', 'x'=>'float', 'y'=>'float'], 'ImagickDraw::pathStart' => ['bool'], 'ImagickDraw::point' => ['bool', 'x'=>'float', 'y'=>'float'], 'ImagickDraw::polygon' => ['bool', 'coordinates'=>'list'], 'ImagickDraw::polyline' => ['bool', 'coordinates'=>'list'], 'ImagickDraw::pop' => ['bool'], 'ImagickDraw::popClipPath' => ['bool'], 'ImagickDraw::popDefs' => ['bool'], 'ImagickDraw::popPattern' => ['bool'], 'ImagickDraw::push' => ['bool'], 'ImagickDraw::pushClipPath' => ['bool', 'clip_mask_id'=>'string'], 'ImagickDraw::pushDefs' => ['bool'], 'ImagickDraw::pushPattern' => ['bool', 'pattern_id'=>'string', 'x'=>'float', 'y'=>'float', 'width'=>'float', 'height'=>'float'], 'ImagickDraw::rectangle' => ['bool', 'x1'=>'float', 'y1'=>'float', 'x2'=>'float', 'y2'=>'float'], 'ImagickDraw::render' => ['bool'], 'ImagickDraw::resetVectorGraphics' => ['void'], 'ImagickDraw::rotate' => ['bool', 'degrees'=>'float'], 'ImagickDraw::roundRectangle' => ['bool', 'x1'=>'float', 'y1'=>'float', 'x2'=>'float', 'y2'=>'float', 'rx'=>'float', 'ry'=>'float'], 'ImagickDraw::scale' => ['bool', 'x'=>'float', 'y'=>'float'], 'ImagickDraw::setBorderColor' => ['bool', 'color'=>'ImagickPixel|string'], 'ImagickDraw::setClipPath' => ['bool', 'clip_mask'=>'string'], 'ImagickDraw::setClipRule' => ['bool', 'fill_rule'=>'int'], 'ImagickDraw::setClipUnits' => ['bool', 'clip_units'=>'int'], 'ImagickDraw::setDensity' => ['bool', 'density_string'=>'string'], 'ImagickDraw::setFillAlpha' => ['bool', 'opacity'=>'float'], 'ImagickDraw::setFillColor' => ['bool', 'fill_pixel'=>'ImagickPixel|string'], 'ImagickDraw::setFillOpacity' => ['bool', 'fillopacity'=>'float'], 'ImagickDraw::setFillPatternURL' => ['bool', 'fill_url'=>'string'], 'ImagickDraw::setFillRule' => ['bool', 'fill_rule'=>'int'], 'ImagickDraw::setFont' => ['bool', 'font_name'=>'string'], 'ImagickDraw::setFontFamily' => ['bool', 'font_family'=>'string'], 'ImagickDraw::setFontResolution' => ['bool', 'x'=>'float', 'y'=>'float'], 'ImagickDraw::setFontSize' => ['bool', 'pointsize'=>'float'], 'ImagickDraw::setFontStretch' => ['bool', 'fontstretch'=>'int'], 'ImagickDraw::setFontStyle' => ['bool', 'style'=>'int'], 'ImagickDraw::setFontWeight' => ['bool', 'font_weight'=>'int'], 'ImagickDraw::setGravity' => ['bool', 'gravity'=>'int'], 'ImagickDraw::setOpacity' => ['void', 'opacity'=>'float'], 'ImagickDraw::setResolution' => ['void', 'x_resolution'=>'float', 'y_resolution'=>'float'], 'ImagickDraw::setStrokeAlpha' => ['bool', 'opacity'=>'float'], 'ImagickDraw::setStrokeAntialias' => ['bool', 'stroke_antialias'=>'bool'], 'ImagickDraw::setStrokeColor' => ['bool', 'stroke_pixel'=>'ImagickPixel|string'], 'ImagickDraw::setStrokeDashArray' => ['bool', 'dasharray'=>'list'], 'ImagickDraw::setStrokeDashOffset' => ['bool', 'dash_offset'=>'float'], 'ImagickDraw::setStrokeLineCap' => ['bool', 'linecap'=>'int'], 'ImagickDraw::setStrokeLineJoin' => ['bool', 'linejoin'=>'int'], 'ImagickDraw::setStrokeMiterLimit' => ['bool', 'miterlimit'=>'int'], 'ImagickDraw::setStrokeOpacity' => ['bool', 'stroke_opacity'=>'float'], 'ImagickDraw::setStrokePatternURL' => ['bool', 'stroke_url'=>'string'], 'ImagickDraw::setStrokeWidth' => ['bool', 'stroke_width'=>'float'], 'ImagickDraw::setTextAlignment' => ['bool', 'alignment'=>'int'], 'ImagickDraw::setTextAntialias' => ['bool', 'antialias'=>'bool'], 'ImagickDraw::setTextDecoration' => ['bool', 'decoration'=>'int'], 'ImagickDraw::setTextDirection' => ['bool', 'direction'=>'int'], 'ImagickDraw::setTextEncoding' => ['bool', 'encoding'=>'string'], 'ImagickDraw::setTextInterlineSpacing' => ['void', 'spacing'=>'float'], 'ImagickDraw::setTextInterwordSpacing' => ['void', 'spacing'=>'float'], 'ImagickDraw::setTextKerning' => ['void', 'kerning'=>'float'], 'ImagickDraw::setTextUnderColor' => ['bool', 'under_color'=>'ImagickPixel|string'], 'ImagickDraw::setVectorGraphics' => ['bool', 'xml'=>'string'], 'ImagickDraw::setViewbox' => ['bool', 'x1'=>'int', 'y1'=>'int', 'x2'=>'int', 'y2'=>'int'], 'ImagickDraw::skewX' => ['bool', 'degrees'=>'float'], 'ImagickDraw::skewY' => ['bool', 'degrees'=>'float'], 'ImagickDraw::translate' => ['bool', 'x'=>'float', 'y'=>'float'], 'ImagickKernel::addKernel' => ['void', 'ImagickKernel'=>'ImagickKernel'], 'ImagickKernel::addUnityKernel' => ['void'], 'ImagickKernel::fromBuiltin' => ['ImagickKernel', 'kernelType'=>'string', 'kernelString'=>'string'], 'ImagickKernel::fromMatrix' => ['ImagickKernel', 'matrix'=>'list>', 'origin='=>'array'], 'ImagickKernel::getMatrix' => ['list>'], 'ImagickKernel::scale' => ['void'], 'ImagickKernel::separate' => ['ImagickKernel[]'], 'ImagickKernel::seperate' => ['void'], 'ImagickPixel::__construct' => ['void', 'color='=>'string'], 'ImagickPixel::clear' => ['bool'], 'ImagickPixel::clone' => ['void'], 'ImagickPixel::destroy' => ['bool'], 'ImagickPixel::getColor' => ['array{r: int|float, g: int|float, b: int|float, a: int|float}', 'normalized='=>'0|1|2'], 'ImagickPixel::getColorAsString' => ['string'], 'ImagickPixel::getColorCount' => ['int'], 'ImagickPixel::getColorQuantum' => ['mixed'], 'ImagickPixel::getColorValue' => ['float', 'color'=>'int'], 'ImagickPixel::getColorValueQuantum' => ['mixed'], 'ImagickPixel::getHSL' => ['array{hue: float, saturation: float, luminosity: float}'], 'ImagickPixel::getIndex' => ['int'], 'ImagickPixel::isPixelSimilar' => ['bool', 'color'=>'ImagickPixel', 'fuzz'=>'float'], 'ImagickPixel::isPixelSimilarQuantum' => ['bool', 'color'=>'string', 'fuzz='=>'string'], 'ImagickPixel::isSimilar' => ['bool', 'color'=>'ImagickPixel', 'fuzz'=>'float'], 'ImagickPixel::setColor' => ['bool', 'color'=>'string'], 'ImagickPixel::setcolorcount' => ['void', 'colorCount'=>'string'], 'ImagickPixel::setColorFromPixel' => ['bool', 'srcPixel'=>'ImagickPixel'], 'ImagickPixel::setColorValue' => ['bool', 'color'=>'int', 'value'=>'float'], 'ImagickPixel::setColorValueQuantum' => ['void', 'color'=>'int', 'value'=>'mixed'], 'ImagickPixel::setHSL' => ['bool', 'hue'=>'float', 'saturation'=>'float', 'luminosity'=>'float'], 'ImagickPixel::setIndex' => ['void', 'index'=>'int'], 'ImagickPixelIterator::__construct' => ['void', 'wand'=>'Imagick'], 'ImagickPixelIterator::clear' => ['bool'], 'ImagickPixelIterator::current' => ['mixed'], 'ImagickPixelIterator::destroy' => ['bool'], 'ImagickPixelIterator::getCurrentIteratorRow' => ['array'], 'ImagickPixelIterator::getIteratorRow' => ['int'], 'ImagickPixelIterator::getNextIteratorRow' => ['array'], 'ImagickPixelIterator::getpixeliterator' => ['', 'Imagick'=>'Imagick'], 'ImagickPixelIterator::getpixelregioniterator' => ['', 'Imagick'=>'Imagick', 'x'=>'', 'y'=>'', 'columns'=>'', 'rows'=>''], 'ImagickPixelIterator::getPreviousIteratorRow' => ['array'], 'ImagickPixelIterator::key' => ['int|string'], 'ImagickPixelIterator::newPixelIterator' => ['bool', 'wand'=>'Imagick'], 'ImagickPixelIterator::newPixelRegionIterator' => ['bool', 'wand'=>'Imagick', 'x'=>'int', 'y'=>'int', 'columns'=>'int', 'rows'=>'int'], 'ImagickPixelIterator::next' => ['void'], 'ImagickPixelIterator::resetIterator' => ['bool'], 'ImagickPixelIterator::rewind' => ['void'], 'ImagickPixelIterator::setIteratorFirstRow' => ['bool'], 'ImagickPixelIterator::setIteratorLastRow' => ['bool'], 'ImagickPixelIterator::setIteratorRow' => ['bool', 'row'=>'int'], 'ImagickPixelIterator::syncIterator' => ['bool'], 'ImagickPixelIterator::valid' => ['bool'], 'imap_8bit' => ['string|false', 'string'=>'string'], 'imap_alerts' => ['array|false'], 'imap_append' => ['bool', 'imap'=>'IMAP\Connection', 'folder'=>'string', 'message'=>'string', 'options='=>'?string', 'internal_date='=>'?string'], 'imap_base64' => ['string|false', 'string'=>'string'], 'imap_binary' => ['string|false', 'string'=>'string'], 'imap_body' => ['string|false', 'imap'=>'IMAP\Connection', 'message_num'=>'int', 'flags='=>'int'], 'imap_bodystruct' => ['stdClass|false', 'imap'=>'IMAP\Connection', 'message_num'=>'int', 'section'=>'string'], 'imap_check' => ['stdClass|false', 'imap'=>'IMAP\Connection'], 'imap_clearflag_full' => ['true', 'imap'=>'IMAP\Connection', 'sequence'=>'string', 'flag'=>'string', 'options='=>'int'], 'imap_close' => ['true', 'imap'=>'IMAP\Connection', 'flags='=>'int'], 'imap_create' => ['bool', 'imap'=>'IMAP\Connection', 'mailbox'=>'string'], 'imap_createmailbox' => ['bool', 'imap'=>'IMAP\Connection', 'mailbox'=>'string'], 'imap_delete' => ['true', 'imap'=>'IMAP\Connection', 'message_nums'=>'string', 'flags='=>'int'], 'imap_deletemailbox' => ['bool', 'imap'=>'IMAP\Connection', 'mailbox'=>'string'], 'imap_errors' => ['array|false'], 'imap_expunge' => ['true', 'imap'=>'IMAP\Connection'], 'imap_fetch_overview' => ['array|false', 'imap'=>'IMAP\Connection', 'sequence'=>'string', 'flags='=>'int'], 'imap_fetchbody' => ['string|false', 'imap'=>'IMAP\Connection', 'message_num'=>'int', 'section'=>'string', 'flags='=>'int'], 'imap_fetchheader' => ['string|false', 'imap'=>'IMAP\Connection', 'message_num'=>'int', 'flags='=>'int'], 'imap_fetchmime' => ['string|false', 'imap'=>'IMAP\Connection', 'message_num'=>'int', 'section'=>'string', 'flags='=>'int'], 'imap_fetchstructure' => ['stdClass|false', 'imap'=>'IMAP\Connection', 'message_num'=>'int', 'flags='=>'int'], 'imap_fetchtext' => ['string|false', 'imap'=>'IMAP\Connection', 'message_num'=>'int', 'flags='=>'int'], 'imap_gc' => ['true', 'imap'=>'IMAP\Connection', 'flags'=>'int'], 'imap_get_quota' => ['array|false', 'imap'=>'IMAP\Connection', 'quota_root'=>'string'], 'imap_get_quotaroot' => ['array|false', 'imap'=>'IMAP\Connection', 'mailbox'=>'string'], 'imap_getacl' => ['array|false', 'imap'=>'IMAP\Connection', 'mailbox'=>'string'], 'imap_getmailboxes' => ['array|false', 'imap'=>'IMAP\Connection', 'reference'=>'string', 'pattern'=>'string'], 'imap_getsubscribed' => ['array|false', 'imap'=>'IMAP\Connection', 'reference'=>'string', 'pattern'=>'string'], 'imap_header' => ['stdClass|false', 'stream_id'=>'resource', 'msg_no'=>'int', 'from_length='=>'int', 'subject_length='=>'int', 'default_host='=>'string'], 'imap_headerinfo' => ['stdClass|false', 'imap'=>'IMAP\Connection', 'message_num'=>'int', 'from_length='=>'int', 'subject_length='=>'int'], 'imap_headers' => ['array|false', 'imap'=>'IMAP\Connection'], 'imap_is_open' => ['bool', 'imap'=>'IMAP\Connection'], 'imap_last_error' => ['string|false'], 'imap_list' => ['array|false', 'imap'=>'IMAP\Connection', 'reference'=>'string', 'pattern'=>'string'], 'imap_listmailbox' => ['array|false', 'imap'=>'IMAP\Connection', 'reference'=>'string', 'pattern'=>'string'], 'imap_listscan' => ['array|false', 'imap'=>'IMAP\Connection', 'reference'=>'string', 'pattern'=>'string', 'content'=>'string'], 'imap_listsubscribed' => ['array|false', 'imap'=>'IMAP\Connection', 'reference'=>'string', 'pattern'=>'string'], 'imap_lsub' => ['array|false', 'imap'=>'IMAP\Connection', 'reference'=>'string', 'pattern'=>'string'], 'imap_mail' => ['bool', 'to'=>'string', 'subject'=>'string', 'message'=>'string', 'additional_headers='=>'?string', 'cc='=>'?string', 'bcc='=>'?string', 'return_path='=>'?string'], 'imap_mail_compose' => ['string|false', 'envelope'=>'array', 'bodies'=>'array'], 'imap_mail_copy' => ['bool', 'imap'=>'IMAP\Connection', 'message_nums'=>'string', 'mailbox'=>'string', 'flags='=>'int'], 'imap_mail_move' => ['bool', 'imap'=>'IMAP\Connection', 'message_nums'=>'string', 'mailbox'=>'string', 'flags='=>'int'], 'imap_mailboxmsginfo' => ['stdClass', 'imap'=>'IMAP\Connection'], 'imap_mime_header_decode' => ['array|false', 'string'=>'string'], 'imap_msgno' => ['int', 'imap'=>'IMAP\Connection', 'message_uid'=>'int'], 'imap_mutf7_to_utf8' => ['string|false', 'string'=>'string'], 'imap_num_msg' => ['int|false', 'imap'=>'IMAP\Connection'], 'imap_num_recent' => ['int', 'imap'=>'IMAP\Connection'], 'imap_open' => ['IMAP\Connection|false', 'mailbox'=>'string', 'user'=>'string', 'password'=>'string', 'flags='=>'int', 'retries='=>'int', 'options='=>'array'], 'imap_ping' => ['bool', 'imap'=>'IMAP\Connection'], 'imap_qprint' => ['string|false', 'string'=>'string'], 'imap_rename' => ['bool', 'imap'=>'IMAP\Connection', 'from'=>'string', 'to'=>'string'], 'imap_renamemailbox' => ['bool', 'imap'=>'IMAP\Connection', 'from'=>'string', 'to'=>'string'], 'imap_reopen' => ['bool', 'imap'=>'IMAP\Connection', 'mailbox'=>'string', 'flags='=>'int', 'retries='=>'int'], 'imap_rfc822_parse_adrlist' => ['array', 'string'=>'string', 'default_hostname'=>'string'], 'imap_rfc822_parse_headers' => ['stdClass', 'headers'=>'string', 'default_hostname='=>'string'], 'imap_rfc822_write_address' => ['string|false', 'mailbox'=>'string', 'hostname'=>'string', 'personal'=>'string'], 'imap_savebody' => ['bool', 'imap'=>'IMAP\Connection', 'file'=>'string|resource', 'message_num'=>'int', 'section='=>'string', 'flags='=>'int'], 'imap_scan' => ['array|false', 'imap'=>'IMAP\Connection', 'reference'=>'string', 'pattern'=>'string', 'content'=>'string'], 'imap_scanmailbox' => ['array|false', 'imap'=>'IMAP\Connection', 'reference'=>'string', 'pattern'=>'string', 'content'=>'string'], 'imap_search' => ['array|false', 'imap'=>'IMAP\Connection', 'criteria'=>'string', 'flags='=>'int', 'charset='=>'string'], 'imap_set_quota' => ['bool', 'imap'=>'IMAP\Connection', 'quota_root'=>'string', 'mailbox_size'=>'int'], 'imap_setacl' => ['bool', 'imap'=>'IMAP\Connection', 'mailbox'=>'string', 'user_id'=>'string', 'rights'=>'string'], 'imap_setflag_full' => ['true', 'imap'=>'IMAP\Connection', 'sequence'=>'string', 'flag'=>'string', 'options='=>'int'], 'imap_sort' => ['array|false', 'imap'=>'IMAP\Connection', 'criteria'=>'int', 'reverse'=>'bool', 'flags='=>'int', 'search_criteria='=>'?string', 'charset='=>'?string'], 'imap_status' => ['stdClass|false', 'imap'=>'IMAP\Connection', 'mailbox'=>'string', 'flags'=>'int'], 'imap_subscribe' => ['bool', 'imap'=>'IMAP\Connection', 'mailbox'=>'string'], 'imap_thread' => ['array|false', 'imap'=>'IMAP\Connection', 'flags='=>'int'], 'imap_timeout' => ['int|bool', 'timeout_type'=>'int', 'timeout='=>'int'], 'imap_uid' => ['int|false', 'imap'=>'IMAP\Connection', 'message_num'=>'int'], 'imap_undelete' => ['true', 'imap'=>'IMAP\Connection', 'message_nums'=>'string', 'flags='=>'int'], 'imap_unsubscribe' => ['bool', 'imap'=>'IMAP\Connection', 'mailbox'=>'string'], 'imap_utf7_decode' => ['string|false', 'string'=>'string'], 'imap_utf7_encode' => ['string', 'string'=>'string'], 'imap_utf8' => ['string', 'mime_encoded_text'=>'string'], 'imap_utf8_to_mutf7' => ['string|false', 'string'=>'string'], 'implode' => ['string', 'separator'=>'string', 'array'=>'array'], 'implode\'1' => ['string', 'separator'=>'array'], 'import_request_variables' => ['bool', 'types'=>'string', 'prefix='=>'string'], 'in_array' => ['bool', 'needle'=>'mixed', 'haystack'=>'array', 'strict='=>'bool'], 'inclued_get_data' => ['array'], 'inet_ntop' => ['string|false', 'ip'=>'string'], 'inet_pton' => ['string|false', 'ip'=>'string'], 'InfiniteIterator::__construct' => ['void', 'iterator'=>'Iterator'], 'InfiniteIterator::current' => ['mixed'], 'InfiniteIterator::getInnerIterator' => ['Iterator'], 'InfiniteIterator::key' => ['bool|float|int|string'], 'InfiniteIterator::next' => ['void'], 'InfiniteIterator::rewind' => ['void'], 'InfiniteIterator::valid' => ['bool'], 'inflate_add' => ['string|false', 'context'=>'InflateContext', 'data'=>'string', 'flush_mode='=>'int'], 'inflate_get_read_len' => ['int', 'context'=>'InflateContext'], 'inflate_get_status' => ['int', 'context'=>'InflateContext'], 'inflate_init' => ['InflateContext|false', 'encoding'=>'int', 'options='=>'array'], 'ingres_autocommit' => ['bool', 'link'=>'resource'], 'ingres_autocommit_state' => ['bool', 'link'=>'resource'], 'ingres_charset' => ['string', 'link'=>'resource'], 'ingres_close' => ['bool', 'link'=>'resource'], 'ingres_commit' => ['bool', 'link'=>'resource'], 'ingres_connect' => ['resource', 'database='=>'string', 'username='=>'string', 'password='=>'string', 'options='=>'array'], 'ingres_cursor' => ['string', 'result'=>'resource'], 'ingres_errno' => ['int', 'link='=>'resource'], 'ingres_error' => ['string', 'link='=>'resource'], 'ingres_errsqlstate' => ['string', 'link='=>'resource'], 'ingres_escape_string' => ['string', 'link'=>'resource', 'source_string'=>'string'], 'ingres_execute' => ['bool', 'result'=>'resource', 'params='=>'array', 'types='=>'string'], 'ingres_fetch_array' => ['array', 'result'=>'resource', 'result_type='=>'int'], 'ingres_fetch_assoc' => ['array', 'result'=>'resource'], 'ingres_fetch_object' => ['object', 'result'=>'resource', 'result_type='=>'int'], 'ingres_fetch_proc_return' => ['int', 'result'=>'resource'], 'ingres_fetch_row' => ['array', 'result'=>'resource'], 'ingres_field_length' => ['int', 'result'=>'resource', 'index'=>'int'], 'ingres_field_name' => ['string', 'result'=>'resource', 'index'=>'int'], 'ingres_field_nullable' => ['bool', 'result'=>'resource', 'index'=>'int'], 'ingres_field_precision' => ['int', 'result'=>'resource', 'index'=>'int'], 'ingres_field_scale' => ['int', 'result'=>'resource', 'index'=>'int'], 'ingres_field_type' => ['string', 'result'=>'resource', 'index'=>'int'], 'ingres_free_result' => ['bool', 'result'=>'resource'], 'ingres_next_error' => ['bool', 'link='=>'resource'], 'ingres_num_fields' => ['int', 'result'=>'resource'], 'ingres_num_rows' => ['int', 'result'=>'resource'], 'ingres_pconnect' => ['resource', 'database='=>'string', 'username='=>'string', 'password='=>'string', 'options='=>'array'], 'ingres_prepare' => ['mixed', 'link'=>'resource', 'query'=>'string'], 'ingres_query' => ['mixed', 'link'=>'resource', 'query'=>'string', 'params='=>'array', 'types='=>'string'], 'ingres_result_seek' => ['bool', 'result'=>'resource', 'position'=>'int'], 'ingres_rollback' => ['bool', 'link'=>'resource'], 'ingres_set_environment' => ['bool', 'link'=>'resource', 'options'=>'array'], 'ingres_unbuffered_query' => ['mixed', 'link'=>'resource', 'query'=>'string', 'params='=>'array', 'types='=>'string'], 'ini_alter' => ['string|false', 'option'=>'string', 'value'=>'string|int|float|bool|null'], 'ini_get' => ['string|false', 'option'=>'string'], 'ini_get_all' => ['array|false', 'extension='=>'?string', 'details='=>'bool'], 'ini_restore' => ['void', 'option'=>'string'], 'ini_parse_quantity' => ['int', 'shorthand'=>'non-empty-string'], 'ini_set' => ['string|false', 'option'=>'string', 'value'=>'string|int|float|bool|null'], 'inotify_add_watch' => ['int|false', 'inotify_instance'=>'resource', 'pathname'=>'string', 'mask'=>'int'], 'inotify_init' => ['resource|false'], 'inotify_queue_len' => ['int', 'inotify_instance'=>'resource'], 'inotify_read' => ['array{wd: int, mask: int, cookie: int, name: string}[]|false', 'inotify_instance'=>'resource'], 'inotify_rm_watch' => ['bool', 'inotify_instance'=>'resource', 'watch_descriptor'=>'int'], 'intdiv' => ['int', 'num1'=>'int', 'num2'=>'int'], 'interface_exists' => ['bool', 'interface'=>'string', 'autoload='=>'bool'], 'intl_error_name' => ['string', 'errorCode'=>'int'], 'intl_get_error_code' => ['int'], 'intl_get_error_message' => ['string'], 'intl_is_failure' => ['bool', 'errorCode'=>'int'], 'IntlBreakIterator::__construct' => ['void'], 'IntlBreakIterator::createCharacterInstance' => ['?IntlRuleBasedBreakIterator', 'locale='=>'?string'], 'IntlBreakIterator::createCodePointInstance' => ['IntlCodePointBreakIterator'], 'IntlBreakIterator::createLineInstance' => ['?IntlRuleBasedBreakIterator', 'locale='=>'?string'], 'IntlBreakIterator::createSentenceInstance' => ['?IntlRuleBasedBreakIterator', 'locale='=>'?string'], 'IntlBreakIterator::createTitleInstance' => ['?IntlRuleBasedBreakIterator', 'locale='=>'?string'], 'IntlBreakIterator::createWordInstance' => ['?IntlRuleBasedBreakIterator', 'locale='=>'?string'], 'IntlBreakIterator::current' => ['int'], 'IntlBreakIterator::first' => ['int'], 'IntlBreakIterator::following' => ['int', 'offset'=>'int'], 'IntlBreakIterator::getErrorCode' => ['int'], 'IntlBreakIterator::getErrorMessage' => ['string'], 'IntlBreakIterator::getLocale' => ['string|false', 'type'=>'int'], 'IntlBreakIterator::getPartsIterator' => ['IntlPartsIterator', 'type='=>'string'], 'IntlBreakIterator::getText' => ['?string'], 'IntlBreakIterator::isBoundary' => ['bool', 'offset'=>'int'], 'IntlBreakIterator::last' => ['int'], 'IntlBreakIterator::next' => ['int', 'offset='=>'?int'], 'IntlBreakIterator::preceding' => ['int', 'offset'=>'int'], 'IntlBreakIterator::previous' => ['int'], 'IntlBreakIterator::setText' => ['bool', 'text'=>'string'], 'intlcal_add' => ['bool', 'calendar'=>'IntlCalendar', 'field'=>'int', 'value'=>'int'], 'intlcal_after' => ['bool', 'calendar'=>'IntlCalendar', 'other'=>'IntlCalendar'], 'intlcal_before' => ['bool', 'calendar'=>'IntlCalendar', 'other'=>'IntlCalendar'], 'intlcal_clear' => ['true', 'calendar'=>'IntlCalendar', 'field='=>'?int'], 'intlcal_create_instance' => ['?IntlCalendar', 'timezone='=>'mixed', 'locale='=>'?string'], 'intlcal_equals' => ['bool', 'calendar'=>'IntlCalendar', 'other'=>'IntlCalendar'], 'intlcal_field_difference' => ['int|false', 'calendar'=>'IntlCalendar', 'timestamp'=>'float', 'field'=>'int'], 'intlcal_from_date_time' => ['?IntlCalendar', 'datetime'=>'DateTime|string', 'locale='=>'?string'], 'intlcal_get' => ['int|false', 'calendar'=>'IntlCalendar', 'field'=>'int'], 'intlcal_get_actual_maximum' => ['int', 'calendar'=>'IntlCalendar', 'field'=>'int'], 'intlcal_get_actual_minimum' => ['int', 'calendar'=>'IntlCalendar', 'field'=>'int'], 'intlcal_get_available_locales' => ['array'], 'intlcal_get_day_of_week_type' => ['int', 'calendar'=>'IntlCalendar', 'dayOfWeek'=>'int'], 'intlcal_get_first_day_of_week' => ['int', 'calendar'=>'IntlCalendar'], 'intlcal_get_greatest_minimum' => ['int', 'calendar'=>'IntlCalendar', 'field'=>'int'], 'intlcal_get_keyword_values_for_locale' => ['IntlIterator|false', 'keyword'=>'string', 'locale'=>'string', 'onlyCommon'=>'bool'], 'intlcal_get_least_maximum' => ['int', 'calendar'=>'IntlCalendar', 'field'=>'int'], 'intlcal_get_locale' => ['string', 'calendar'=>'IntlCalendar', 'type'=>'int'], 'intlcal_get_maximum' => ['int|false', 'calendar'=>'IntlCalendar', 'field'=>'int'], 'intlcal_get_minimal_days_in_first_week' => ['int', 'calendar'=>'IntlCalendar'], 'intlcal_get_minimum' => ['int', 'calendar'=>'IntlCalendar', 'field'=>'int'], 'intlcal_get_now' => ['float'], 'intlcal_get_repeated_wall_time_option' => ['int', 'calendar'=>'IntlCalendar'], 'intlcal_get_skipped_wall_time_option' => ['int', 'calendar'=>'IntlCalendar'], 'intlcal_get_time' => ['float', 'calendar'=>'IntlCalendar'], 'intlcal_get_time_zone' => ['IntlTimeZone', 'calendar'=>'IntlCalendar'], 'intlcal_get_type' => ['string', 'calendar'=>'IntlCalendar'], 'intlcal_get_weekend_transition' => ['int|false', 'calendar'=>'IntlCalendar', 'dayOfWeek'=>'int'], 'intlcal_in_daylight_time' => ['bool', 'calendar'=>'IntlCalendar'], 'intlcal_is_equivalent_to' => ['bool', 'calendar'=>'IntlCalendar', 'other'=>'IntlCalendar'], 'intlcal_is_lenient' => ['bool', 'calendar'=>'IntlCalendar'], 'intlcal_is_set' => ['bool', 'calendar'=>'IntlCalendar', 'field'=>'int'], 'intlcal_is_weekend' => ['bool', 'calendar'=>'IntlCalendar', 'timestamp='=>'?float'], 'intlcal_roll' => ['bool', 'calendar'=>'IntlCalendar', 'field'=>'int', 'value'=>'mixed'], 'intlcal_set' => ['bool', 'calendar'=>'IntlCalendar', 'year'=>'int', 'month'=>'int'], 'intlcal_set\'1' => ['bool', 'calendar'=>'IntlCalendar', 'year'=>'int', 'month'=>'int', 'dayOfMonth='=>'int', 'hour='=>'int', 'minute='=>'int', 'second='=>'int'], 'intlcal_set_first_day_of_week' => ['true', 'calendar'=>'IntlCalendar', 'dayOfWeek'=>'int'], 'intlcal_set_lenient' => ['true', 'calendar'=>'IntlCalendar', 'lenient'=>'bool'], 'intlcal_set_repeated_wall_time_option' => ['true', 'calendar'=>'IntlCalendar', 'option'=>'int'], 'intlcal_set_skipped_wall_time_option' => ['true', 'calendar'=>'IntlCalendar', 'option'=>'int'], 'intlcal_set_time' => ['bool', 'calendar'=>'IntlCalendar', 'timestamp'=>'float'], 'intlcal_set_time_zone' => ['bool', 'calendar'=>'IntlCalendar', 'timezone'=>'mixed'], 'intlcal_to_date_time' => ['DateTime|false', 'calendar'=>'IntlCalendar'], 'IntlCalendar::__construct' => ['void'], 'IntlCalendar::add' => ['bool', 'field'=>'int', 'value'=>'int'], 'IntlCalendar::after' => ['bool', 'other'=>'IntlCalendar'], 'IntlCalendar::before' => ['bool', 'other'=>'IntlCalendar'], 'IntlCalendar::clear' => ['bool', 'field='=>'?int'], 'IntlCalendar::createInstance' => ['?IntlCalendar', 'timezone='=>'IntlTimeZone|DateTimeZone|string|null', 'locale='=>'?string'], 'IntlCalendar::equals' => ['bool', 'other'=>'IntlCalendar'], 'IntlCalendar::fieldDifference' => ['int|false', 'timestamp'=>'float', 'field'=>'int'], 'IntlCalendar::fromDateTime' => ['?IntlCalendar', 'datetime'=>'DateTime|string', 'locale='=>'?string'], 'IntlCalendar::get' => ['int', 'field'=>'int'], 'IntlCalendar::getActualMaximum' => ['int', 'field'=>'int'], 'IntlCalendar::getActualMinimum' => ['int', 'field'=>'int'], 'IntlCalendar::getAvailableLocales' => ['array'], 'IntlCalendar::getDayOfWeekType' => ['int', 'dayOfWeek'=>'int'], 'IntlCalendar::getErrorCode' => ['int'], 'IntlCalendar::getErrorMessage' => ['string'], 'IntlCalendar::getFirstDayOfWeek' => ['int'], 'IntlCalendar::getGreatestMinimum' => ['int', 'field'=>'int'], 'IntlCalendar::getKeywordValuesForLocale' => ['IntlIterator|false', 'keyword'=>'string', 'locale'=>'string', 'onlyCommon'=>'bool'], 'IntlCalendar::getLeastMaximum' => ['int', 'field'=>'int'], 'IntlCalendar::getLocale' => ['string|false', 'type'=>'int'], 'IntlCalendar::getMaximum' => ['int|false', 'field'=>'int'], 'IntlCalendar::getMinimalDaysInFirstWeek' => ['int'], 'IntlCalendar::getMinimum' => ['int', 'field'=>'int'], 'IntlCalendar::getNow' => ['float'], 'IntlCalendar::getRepeatedWallTimeOption' => ['int'], 'IntlCalendar::getSkippedWallTimeOption' => ['int'], 'IntlCalendar::getTime' => ['float'], 'IntlCalendar::getTimeZone' => ['IntlTimeZone'], 'IntlCalendar::getType' => ['string'], 'IntlCalendar::getWeekendTransition' => ['int|false', 'dayOfWeek'=>'int'], 'IntlCalendar::inDaylightTime' => ['bool'], 'IntlCalendar::isEquivalentTo' => ['bool', 'other'=>'IntlCalendar'], 'IntlCalendar::isLenient' => ['bool'], 'IntlCalendar::isSet' => ['bool', 'field'=>'int'], 'IntlCalendar::isWeekend' => ['bool', 'timestamp='=>'?float'], 'IntlCalendar::roll' => ['bool', 'field'=>'int', 'value'=>'int|bool'], 'IntlCalendar::set' => ['bool', 'field'=>'int', 'value'=>'int'], 'IntlCalendar::set\'1' => ['bool', 'year'=>'int', 'month'=>'int', 'dayOfMonth='=>'int', 'hour='=>'int', 'minute='=>'int', 'second='=>'int'], 'IntlCalendar::setFirstDayOfWeek' => ['bool', 'dayOfWeek'=>'int'], 'IntlCalendar::setLenient' => ['true', 'lenient'=>'bool'], 'IntlCalendar::setMinimalDaysInFirstWeek' => ['bool', 'days'=>'int'], 'IntlCalendar::setRepeatedWallTimeOption' => ['true', 'option'=>'int'], 'IntlCalendar::setSkippedWallTimeOption' => ['true', 'option'=>'int'], 'IntlCalendar::setTime' => ['bool', 'timestamp'=>'float'], 'IntlCalendar::setTimeZone' => ['bool', 'timezone'=>'IntlTimeZone|DateTimeZone|string|null'], 'IntlCalendar::toDateTime' => ['DateTime|false'], 'IntlChar::charAge' => ['?array', 'codepoint'=>'int|string'], 'IntlChar::charDigitValue' => ['?int', 'codepoint'=>'int|string'], 'IntlChar::charDirection' => ['?int', 'codepoint'=>'int|string'], 'IntlChar::charFromName' => ['?int', 'name'=>'string', 'type='=>'int'], 'IntlChar::charMirror' => ['int|string|null', 'codepoint'=>'int|string'], 'IntlChar::charName' => ['?string', 'codepoint'=>'int|string', 'type='=>'int'], 'IntlChar::charType' => ['?int', 'codepoint'=>'int|string'], 'IntlChar::chr' => ['?string', 'codepoint'=>'int|string'], 'IntlChar::digit' => ['int|false|null', 'codepoint'=>'int|string', 'base='=>'int'], 'IntlChar::enumCharNames' => ['bool', 'start'=>'string|int', 'end'=>'string|int', 'callback'=>'callable(int,int,int):void', 'type='=>'int'], 'IntlChar::enumCharTypes' => ['void', 'callback'=>'callable(int,int,int):void'], 'IntlChar::foldCase' => ['int|string|null', 'codepoint'=>'int|string', 'options='=>'int'], 'IntlChar::forDigit' => ['int', 'digit'=>'int', 'base='=>'int'], 'IntlChar::getBidiPairedBracket' => ['int|string|null', 'codepoint'=>'int|string'], 'IntlChar::getBlockCode' => ['?int', 'codepoint'=>'int|string'], 'IntlChar::getCombiningClass' => ['?int', 'codepoint'=>'int|string'], 'IntlChar::getFC_NFKC_Closure' => ['?string', 'codepoint'=>'int|string'], 'IntlChar::getIntPropertyMaxValue' => ['int', 'property'=>'int'], 'IntlChar::getIntPropertyMinValue' => ['int', 'property'=>'int'], 'IntlChar::getIntPropertyValue' => ['?int', 'codepoint'=>'int|string', 'property'=>'int'], 'IntlChar::getNumericValue' => ['?float', 'codepoint'=>'int|string'], 'IntlChar::getPropertyEnum' => ['int', 'alias'=>'string'], 'IntlChar::getPropertyName' => ['string|false', 'property'=>'int', 'type='=>'int'], 'IntlChar::getPropertyValueEnum' => ['int', 'property'=>'int', 'name'=>'string'], 'IntlChar::getPropertyValueName' => ['string|false', 'property'=>'int', 'value'=>'int', 'type='=>'int'], 'IntlChar::getUnicodeVersion' => ['array'], 'IntlChar::hasBinaryProperty' => ['?bool', 'codepoint'=>'int|string', 'property'=>'int'], 'IntlChar::isalnum' => ['?bool', 'codepoint'=>'int|string'], 'IntlChar::isalpha' => ['?bool', 'codepoint'=>'int|string'], 'IntlChar::isbase' => ['?bool', 'codepoint'=>'int|string'], 'IntlChar::isblank' => ['?bool', 'codepoint'=>'int|string'], 'IntlChar::iscntrl' => ['?bool', 'codepoint'=>'int|string'], 'IntlChar::isdefined' => ['?bool', 'codepoint'=>'int|string'], 'IntlChar::isdigit' => ['?bool', 'codepoint'=>'int|string'], 'IntlChar::isgraph' => ['?bool', 'codepoint'=>'int|string'], 'IntlChar::isIDIgnorable' => ['?bool', 'codepoint'=>'int|string'], 'IntlChar::isIDPart' => ['?bool', 'codepoint'=>'int|string'], 'IntlChar::isIDStart' => ['?bool', 'codepoint'=>'int|string'], 'IntlChar::isISOControl' => ['?bool', 'codepoint'=>'int|string'], 'IntlChar::isJavaIDPart' => ['?bool', 'codepoint'=>'int|string'], 'IntlChar::isJavaIDStart' => ['?bool', 'codepoint'=>'int|string'], 'IntlChar::isJavaSpaceChar' => ['?bool', 'codepoint'=>'int|string'], 'IntlChar::islower' => ['?bool', 'codepoint'=>'int|string'], 'IntlChar::isMirrored' => ['?bool', 'codepoint'=>'int|string'], 'IntlChar::isprint' => ['?bool', 'codepoint'=>'int|string'], 'IntlChar::ispunct' => ['?bool', 'codepoint'=>'int|string'], 'IntlChar::isspace' => ['?bool', 'codepoint'=>'int|string'], 'IntlChar::istitle' => ['?bool', 'codepoint'=>'int|string'], 'IntlChar::isUAlphabetic' => ['?bool', 'codepoint'=>'int|string'], 'IntlChar::isULowercase' => ['?bool', 'codepoint'=>'int|string'], 'IntlChar::isupper' => ['?bool', 'codepoint'=>'int|string'], 'IntlChar::isUUppercase' => ['?bool', 'codepoint'=>'int|string'], 'IntlChar::isUWhiteSpace' => ['?bool', 'codepoint'=>'int|string'], 'IntlChar::isWhitespace' => ['?bool', 'codepoint'=>'int|string'], 'IntlChar::isxdigit' => ['?bool', 'codepoint'=>'int|string'], 'IntlChar::ord' => ['?int', 'character'=>'int|string'], 'IntlChar::tolower' => ['int|string|null', 'codepoint'=>'int|string'], 'IntlChar::totitle' => ['int|string|null', 'codepoint'=>'int|string'], 'IntlChar::toupper' => ['int|string|null', 'codepoint'=>'int|string'], 'IntlCodePointBreakIterator::createCharacterInstance' => ['?IntlRuleBasedBreakIterator', 'locale='=>'?string'], 'IntlCodePointBreakIterator::createCodePointInstance' => ['IntlCodePointBreakIterator'], 'IntlCodePointBreakIterator::createLineInstance' => ['?IntlRuleBasedBreakIterator', 'locale='=>'?string'], 'IntlCodePointBreakIterator::createSentenceInstance' => ['?IntlRuleBasedBreakIterator', 'locale='=>'?string'], 'IntlCodePointBreakIterator::createTitleInstance' => ['?IntlRuleBasedBreakIterator', 'locale='=>'?string'], 'IntlCodePointBreakIterator::createWordInstance' => ['?IntlRuleBasedBreakIterator', 'locale='=>'?string'], 'IntlCodePointBreakIterator::current' => ['int'], 'IntlCodePointBreakIterator::first' => ['int'], 'IntlCodePointBreakIterator::following' => ['int', 'offset'=>'int'], 'IntlCodePointBreakIterator::getErrorCode' => ['int'], 'IntlCodePointBreakIterator::getErrorMessage' => ['string'], 'IntlCodePointBreakIterator::getLastCodePoint' => ['int'], 'IntlCodePointBreakIterator::getLocale' => ['string|false', 'type'=>'int'], 'IntlCodePointBreakIterator::getPartsIterator' => ['IntlPartsIterator', 'type='=>'string'], 'IntlCodePointBreakIterator::getText' => ['?string'], 'IntlCodePointBreakIterator::isBoundary' => ['bool', 'offset'=>'int'], 'IntlCodePointBreakIterator::last' => ['int'], 'IntlCodePointBreakIterator::next' => ['int', 'offset='=>'?int'], 'IntlCodePointBreakIterator::preceding' => ['int', 'offset'=>'int'], 'IntlCodePointBreakIterator::previous' => ['int'], 'IntlCodePointBreakIterator::setText' => ['bool', 'text'=>'string'], 'IntlDateFormatter::__construct' => ['void', 'locale'=>'?string', 'dateType='=>'int', 'timeType='=>'int', 'timezone='=>'IntlTimeZone|DateTimeZone|string|null', 'calendar='=>'IntlCalendar|int|null', 'pattern='=>'?string'], 'IntlDateFormatter::create' => ['?IntlDateFormatter', 'locale'=>'?string', 'dateType='=>'int', 'timeType='=>'int', 'timezone='=>'IntlTimeZone|DateTimeZone|string|null', 'calendar='=>'IntlCalendar|int|null', 'pattern='=>'?string'], 'IntlDateFormatter::format' => ['string|false', 'datetime'=>'IntlCalendar|DateTimeInterface|array{0: int, 1: int, 2: int, 3: int, 4: int, 5: int, 6: int, 7: int, 8: int}|array{tm_sec: int, tm_min: int, tm_hour: int, tm_mday: int, tm_mon: int, tm_year: int, tm_wday: int, tm_yday: int, tm_isdst: int}|string|int|float'], 'IntlDateFormatter::formatObject' => ['string|false', 'datetime'=>'IntlCalendar|DateTimeInterface', 'format='=>'array{0: int, 1: int}|int|string|null', 'locale='=>'?string'], 'IntlDateFormatter::getCalendar' => ['int|false'], 'IntlDateFormatter::getCalendarObject' => ['IntlCalendar|false|null'], 'IntlDateFormatter::getDateType' => ['int|false'], 'IntlDateFormatter::getErrorCode' => ['int'], 'IntlDateFormatter::getErrorMessage' => ['string'], 'IntlDateFormatter::getLocale' => ['string|false', 'type='=>'int'], 'IntlDateFormatter::getPattern' => ['string|false'], 'IntlDateFormatter::getTimeType' => ['int|false'], 'IntlDateFormatter::getTimeZone' => ['IntlTimeZone|false'], 'IntlDateFormatter::getTimeZoneId' => ['string|false'], 'IntlDateFormatter::isLenient' => ['bool'], 'IntlDateFormatter::localtime' => ['array|false', 'string'=>'string', '&rw_offset='=>'int'], 'IntlDateFormatter::parse' => ['int|float|false', 'string'=>'string', '&rw_offset='=>'int'], 'IntlDateFormatter::setCalendar' => ['bool', 'calendar'=>'IntlCalendar|int|null'], 'IntlDateFormatter::setLenient' => ['void', 'lenient'=>'bool'], 'IntlDateFormatter::setPattern' => ['bool', 'pattern'=>'string'], 'IntlDateFormatter::setTimeZone' => ['bool', 'timezone'=>'IntlTimeZone|DateTimeZone|string|null'], 'IntlException::__construct' => ['void', 'message='=>'string', 'code='=>'int', 'previous='=>'?Throwable'], 'IntlException::__toString' => ['string'], 'IntlException::__wakeup' => ['void'], 'IntlException::getCode' => ['int'], 'IntlException::getFile' => ['string'], 'IntlException::getLine' => ['int'], 'IntlException::getMessage' => ['string'], 'IntlException::getPrevious' => ['?Throwable'], 'IntlException::getTrace' => ['list\',args?:array}>'], 'IntlException::getTraceAsString' => ['string'], 'intlgregcal_create_instance' => ['?IntlGregorianCalendar', 'timezoneOrYear='=>'IntlTimeZone|DateTimeZone|string|null', 'localeOrMonth='=>'string|int|null', 'day='=>'int', 'hour='=>'int', 'minute='=>'int', 'second='=>'int'], 'intlgregcal_get_gregorian_change' => ['float', 'calendar'=>'IntlGregorianCalendar'], 'intlgregcal_is_leap_year' => ['bool', 'calendar'=>'IntlGregorianCalendar', 'year'=>'int'], 'intlgregcal_set_gregorian_change' => ['bool', 'calendar'=>'IntlGregorianCalendar', 'timestamp'=>'float'], 'IntlGregorianCalendar::__construct' => ['void'], 'IntlGregorianCalendar::add' => ['bool', 'field'=>'int', 'value'=>'int'], 'IntlGregorianCalendar::after' => ['bool', 'other'=>'IntlCalendar'], 'IntlGregorianCalendar::before' => ['bool', 'other'=>'IntlCalendar'], 'IntlGregorianCalendar::clear' => ['bool', 'field='=>'?int'], 'IntlGregorianCalendar::createInstance' => ['?IntlGregorianCalendar', 'timezone='=>'IntlTimeZone|DateTimeZone|string|null', 'locale='=>'?string'], 'IntlGregorianCalendar::equals' => ['bool', 'other'=>'IntlCalendar'], 'IntlGregorianCalendar::fieldDifference' => ['int|false', 'timestamp'=>'float', 'field'=>'int'], 'IntlGregorianCalendar::fromDateTime' => ['?IntlCalendar', 'datetime'=>'DateTime|string', 'locale='=>'?string'], 'IntlGregorianCalendar::get' => ['int', 'field'=>'int'], 'IntlGregorianCalendar::getActualMaximum' => ['int', 'field'=>'int'], 'IntlGregorianCalendar::getActualMinimum' => ['int', 'field'=>'int'], 'IntlGregorianCalendar::getAvailableLocales' => ['array'], 'IntlGregorianCalendar::getDayOfWeekType' => ['int', 'dayOfWeek'=>'int'], 'IntlGregorianCalendar::getErrorCode' => ['int'], 'IntlGregorianCalendar::getErrorMessage' => ['string'], 'IntlGregorianCalendar::getFirstDayOfWeek' => ['int'], 'IntlGregorianCalendar::getGreatestMinimum' => ['int', 'field'=>'int'], 'IntlGregorianCalendar::getGregorianChange' => ['float'], 'IntlGregorianCalendar::getKeywordValuesForLocale' => ['IntlIterator|false', 'keyword'=>'string', 'locale'=>'string', 'onlyCommon'=>'bool'], 'IntlGregorianCalendar::getLeastMaximum' => ['int', 'field'=>'int'], 'IntlGregorianCalendar::getLocale' => ['string|false', 'type'=>'int'], 'IntlGregorianCalendar::getMaximum' => ['int', 'field'=>'int'], 'IntlGregorianCalendar::getMinimalDaysInFirstWeek' => ['int'], 'IntlGregorianCalendar::getMinimum' => ['int', 'field'=>'int'], 'IntlGregorianCalendar::getNow' => ['float'], 'IntlGregorianCalendar::getRepeatedWallTimeOption' => ['int'], 'IntlGregorianCalendar::getSkippedWallTimeOption' => ['int'], 'IntlGregorianCalendar::getTime' => ['float'], 'IntlGregorianCalendar::getTimeZone' => ['IntlTimeZone'], 'IntlGregorianCalendar::getType' => ['string'], 'IntlGregorianCalendar::getWeekendTransition' => ['int|false', 'dayOfWeek'=>'int'], 'IntlGregorianCalendar::inDaylightTime' => ['bool'], 'IntlGregorianCalendar::isEquivalentTo' => ['bool', 'other'=>'IntlCalendar'], 'IntlGregorianCalendar::isLeapYear' => ['bool', 'year'=>'int'], 'IntlGregorianCalendar::isLenient' => ['bool'], 'IntlGregorianCalendar::isSet' => ['bool', 'field'=>'int'], 'IntlGregorianCalendar::isWeekend' => ['bool', 'timestamp='=>'?float'], 'IntlGregorianCalendar::roll' => ['bool', 'field'=>'int', 'value'=>'int|bool'], 'IntlGregorianCalendar::set' => ['bool', 'field'=>'int', 'value'=>'int'], 'IntlGregorianCalendar::set\'1' => ['bool', 'year'=>'int', 'month'=>'int', 'dayOfMonth='=>'int', 'hour='=>'int', 'minute='=>'int', 'second='=>'int'], 'IntlGregorianCalendar::setFirstDayOfWeek' => ['bool', 'dayOfWeek'=>'int'], 'IntlGregorianCalendar::setGregorianChange' => ['bool', 'timestamp'=>'float'], 'IntlGregorianCalendar::setLenient' => ['true', 'lenient'=>'bool'], 'IntlGregorianCalendar::setMinimalDaysInFirstWeek' => ['bool', 'days'=>'int'], 'IntlGregorianCalendar::setRepeatedWallTimeOption' => ['true', 'option'=>'int'], 'IntlGregorianCalendar::setSkippedWallTimeOption' => ['true', 'option'=>'int'], 'IntlGregorianCalendar::setTime' => ['bool', 'timestamp'=>'float'], 'IntlGregorianCalendar::setTimeZone' => ['bool', 'timezone'=>'IntlTimeZone|DateTimeZone|string|null'], 'IntlGregorianCalendar::toDateTime' => ['DateTime'], 'IntlIterator::__construct' => ['void'], 'IntlIterator::current' => ['mixed'], 'IntlIterator::key' => ['string'], 'IntlIterator::next' => ['void'], 'IntlIterator::rewind' => ['void'], 'IntlIterator::valid' => ['bool'], 'IntlPartsIterator::getBreakIterator' => ['IntlBreakIterator'], 'IntlRuleBasedBreakIterator::__construct' => ['void', 'rules'=>'string', 'compiled='=>'bool'], 'IntlRuleBasedBreakIterator::createCharacterInstance' => ['?IntlRuleBasedBreakIterator', 'locale='=>'?string'], 'IntlRuleBasedBreakIterator::createCodePointInstance' => ['IntlCodePointBreakIterator'], 'IntlRuleBasedBreakIterator::createLineInstance' => ['?IntlRuleBasedBreakIterator', 'locale='=>'?string'], 'IntlRuleBasedBreakIterator::createSentenceInstance' => ['?IntlRuleBasedBreakIterator', 'locale='=>'?string'], 'IntlRuleBasedBreakIterator::createTitleInstance' => ['?IntlRuleBasedBreakIterator', 'locale='=>'?string'], 'IntlRuleBasedBreakIterator::createWordInstance' => ['?IntlRuleBasedBreakIterator', 'locale='=>'?string'], 'IntlRuleBasedBreakIterator::current' => ['int'], 'IntlRuleBasedBreakIterator::first' => ['int'], 'IntlRuleBasedBreakIterator::following' => ['int', 'offset'=>'int'], 'IntlRuleBasedBreakIterator::getBinaryRules' => ['string'], 'IntlRuleBasedBreakIterator::getErrorCode' => ['int'], 'IntlRuleBasedBreakIterator::getErrorMessage' => ['string'], 'IntlRuleBasedBreakIterator::getLocale' => ['string|false', 'type'=>'int'], 'IntlRuleBasedBreakIterator::getPartsIterator' => ['IntlPartsIterator', 'type='=>'string'], 'IntlRuleBasedBreakIterator::getRules' => ['string'], 'IntlRuleBasedBreakIterator::getRuleStatus' => ['int'], 'IntlRuleBasedBreakIterator::getRuleStatusVec' => ['array'], 'IntlRuleBasedBreakIterator::getText' => ['?string'], 'IntlRuleBasedBreakIterator::isBoundary' => ['bool', 'offset'=>'int'], 'IntlRuleBasedBreakIterator::last' => ['int'], 'IntlRuleBasedBreakIterator::next' => ['int', 'offset='=>'?int'], 'IntlRuleBasedBreakIterator::preceding' => ['int', 'offset'=>'int'], 'IntlRuleBasedBreakIterator::previous' => ['int'], 'IntlRuleBasedBreakIterator::setText' => ['bool', 'text'=>'string'], 'IntlTimeZone::countEquivalentIDs' => ['int|false', 'timezoneId'=>'string'], 'IntlTimeZone::createDefault' => ['IntlTimeZone'], 'IntlTimeZone::createEnumeration' => ['IntlIterator|false', 'countryOrRawOffset='=>'IntlTimeZone|string|int|float|null'], 'IntlTimeZone::createTimeZone' => ['?IntlTimeZone', 'timezoneId'=>'string'], 'IntlTimeZone::createTimeZoneIDEnumeration' => ['IntlIterator|false', 'type'=>'int', 'region='=>'?string', 'rawOffset='=>'?int'], 'IntlTimeZone::fromDateTimeZone' => ['?IntlTimeZone', 'timezone'=>'DateTimeZone'], 'IntlTimeZone::getCanonicalID' => ['string|false', 'timezoneId'=>'string', '&w_isSystemId='=>'bool'], 'IntlTimeZone::getDisplayName' => ['string|false', 'dst='=>'bool', 'style='=>'int', 'locale='=>'?string'], 'IntlTimeZone::getDSTSavings' => ['int'], 'IntlTimeZone::getEquivalentID' => ['string|false', 'timezoneId'=>'string', 'offset'=>'int'], 'IntlTimeZone::getErrorCode' => ['int'], 'IntlTimeZone::getErrorMessage' => ['string'], 'IntlTimeZone::getGMT' => ['IntlTimeZone'], 'IntlTimeZone::getID' => ['string'], 'IntlTimeZone::getIDForWindowsID' => ['string|false', 'timezoneId'=>'string', 'region='=>'?string'], 'IntlTimeZone::getOffset' => ['bool', 'timestamp'=>'float', 'local'=>'bool', '&w_rawOffset'=>'int', '&w_dstOffset'=>'int'], 'IntlTimeZone::getRawOffset' => ['int'], 'IntlTimeZone::getRegion' => ['string|false', 'timezoneId'=>'string'], 'IntlTimeZone::getTZDataVersion' => ['string'], 'IntlTimeZone::getUnknown' => ['IntlTimeZone'], 'IntlTimeZone::getWindowsID' => ['string|false', 'timezoneId'=>'string'], 'IntlTimeZone::hasSameRules' => ['bool', 'other'=>'IntlTimeZone'], 'IntlTimeZone::toDateTimeZone' => ['DateTimeZone|false'], 'IntlTimeZone::useDaylightTime' => ['bool'], 'intltz_count_equivalent_ids' => ['int', 'timezoneId'=>'string'], 'intltz_create_enumeration' => ['IntlIterator|false', 'countryOrRawOffset='=>'IntlTimeZone|string|int|float|null'], 'intltz_create_time_zone' => ['?IntlTimeZone', 'timezoneId'=>'string'], 'intltz_from_date_time_zone' => ['?IntlTimeZone', 'timezone'=>'DateTimeZone'], 'intltz_get_canonical_id' => ['string|false', 'timezoneId'=>'string', '&isSystemId='=>'bool'], 'intltz_get_display_name' => ['string|false', 'timezone'=>'IntlTimeZone', 'dst='=>'bool', 'style='=>'int', 'locale='=>'?string'], 'intltz_get_dst_savings' => ['int', 'timezone'=>'IntlTimeZone'], 'intltz_get_equivalent_id' => ['string', 'timezoneId'=>'string', 'offset'=>'int'], 'intltz_get_error_code' => ['int', 'timezone'=>'IntlTimeZone'], 'intltz_get_error_message' => ['string', 'timezone'=>'IntlTimeZone'], 'intltz_get_id' => ['string', 'timezone'=>'IntlTimeZone'], 'intltz_get_offset' => ['bool', 'timezone'=>'IntlTimeZone', 'timestamp'=>'float', 'local'=>'bool', '&rawOffset'=>'int', '&dstOffset'=>'int'], 'intltz_get_raw_offset' => ['int', 'timezone'=>'IntlTimeZone'], 'intltz_get_tz_data_version' => ['string', 'object'=>'IntlTimeZone'], 'intltz_getGMT' => ['IntlTimeZone'], 'intltz_has_same_rules' => ['bool', 'timezone'=>'IntlTimeZone', 'other'=>'IntlTimeZone'], 'intltz_to_date_time_zone' => ['DateTimeZone', 'timezone'=>'IntlTimeZone'], 'intltz_use_daylight_time' => ['bool', 'timezone'=>'IntlTimeZone'], 'intlz_create_default' => ['IntlTimeZone'], 'intval' => ['int', 'value'=>'mixed', 'base='=>'int'], 'InvalidArgumentException::__construct' => ['void', 'message='=>'string', 'code='=>'int', 'previous='=>'?Throwable'], 'InvalidArgumentException::__toString' => ['string'], 'InvalidArgumentException::getCode' => ['int'], 'InvalidArgumentException::getFile' => ['string'], 'InvalidArgumentException::getLine' => ['int'], 'InvalidArgumentException::getMessage' => ['string'], 'InvalidArgumentException::getPrevious' => ['?Throwable'], 'InvalidArgumentException::getTrace' => ['list\',args?:array}>'], 'InvalidArgumentException::getTraceAsString' => ['string'], 'ip2long' => ['int|false', 'ip'=>'string'], 'iptcembed' => ['string|bool', 'iptc_data'=>'string', 'filename'=>'string', 'spool='=>'int'], 'iptcparse' => ['array|false', 'iptc_block'=>'string'], 'is_a' => ['bool', 'object_or_class'=>'mixed', 'class'=>'string', 'allow_string='=>'bool'], 'is_array' => ['bool', 'value'=>'mixed'], 'is_bool' => ['bool', 'value'=>'mixed'], 'is_callable' => ['bool', 'value'=>'callable|mixed', 'syntax_only='=>'bool', '&w_callable_name='=>'string'], 'is_countable' => ['bool', 'value'=>'mixed'], 'is_dir' => ['bool', 'filename'=>'string'], 'is_double' => ['bool', 'value'=>'mixed'], 'is_executable' => ['bool', 'filename'=>'string'], 'is_file' => ['bool', 'filename'=>'string'], 'is_finite' => ['bool', 'num'=>'float'], 'is_float' => ['bool', 'value'=>'mixed'], 'is_infinite' => ['bool', 'num'=>'float'], 'is_int' => ['bool', 'value'=>'mixed'], 'is_integer' => ['bool', 'value'=>'mixed'], 'is_iterable' => ['bool', 'value'=>'mixed'], 'is_link' => ['bool', 'filename'=>'string'], 'is_long' => ['bool', 'value'=>'mixed'], 'is_nan' => ['bool', 'num'=>'float'], 'is_null' => ['bool', 'value'=>'mixed'], 'is_numeric' => ['bool', 'value'=>'mixed'], 'is_object' => ['bool', 'value'=>'mixed'], 'is_readable' => ['bool', 'filename'=>'string'], 'is_real' => ['bool', 'value'=>'mixed'], 'is_resource' => ['bool', 'value'=>'mixed'], 'is_scalar' => ['bool', 'value'=>'mixed'], 'is_soap_fault' => ['bool', 'object'=>'mixed'], 'is_string' => ['bool', 'value'=>'mixed'], 'is_subclass_of' => ['bool', 'object_or_class'=>'object|string', 'class'=>'class-string', 'allow_string='=>'bool'], 'is_tainted' => ['bool', 'string'=>'string'], 'is_uploaded_file' => ['bool', 'filename'=>'string'], 'is_writable' => ['bool', 'filename'=>'string'], 'is_writeable' => ['bool', 'filename'=>'string'], 'isset' => ['bool', 'value'=>'mixed', '...rest='=>'mixed'], 'Iterator::current' => ['mixed'], 'Iterator::key' => ['mixed'], 'Iterator::next' => ['void'], 'Iterator::rewind' => ['void'], 'Iterator::valid' => ['bool'], 'iterator_apply' => ['0|positive-int', 'iterator'=>'Traversable', 'callback'=>'callable(mixed):bool', 'args='=>'?array'], 'iterator_count' => ['0|positive-int', 'iterator'=>'Traversable|array'], 'iterator_to_array' => ['array', 'iterator'=>'Traversable|array', 'preserve_keys='=>'bool'], 'IteratorAggregate::getIterator' => ['Traversable'], 'IteratorIterator::__construct' => ['void', 'iterator'=>'Traversable', 'class='=>'?string'], 'IteratorIterator::current' => ['mixed'], 'IteratorIterator::getInnerIterator' => ['Iterator'], 'IteratorIterator::key' => ['mixed'], 'IteratorIterator::next' => ['void'], 'IteratorIterator::rewind' => ['void'], 'IteratorIterator::valid' => ['bool'], 'java_last_exception_clear' => ['void'], 'java_last_exception_get' => ['object'], 'java_reload' => ['array', 'new_jarpath'=>'string'], 'java_require' => ['array', 'new_classpath'=>'string'], 'java_set_encoding' => ['array', 'encoding'=>'string'], 'java_set_ignore_case' => ['void', 'ignore'=>'bool'], 'java_throw_exceptions' => ['void', 'throw'=>'bool'], 'JavaException::getCause' => ['object'], 'jddayofweek' => ['string|int', 'julian_day'=>'int', 'mode='=>'int'], 'jdmonthname' => ['string', 'julian_day'=>'int', 'mode'=>'int'], 'jdtofrench' => ['string', 'julian_day'=>'int'], 'jdtogregorian' => ['string', 'julian_day'=>'int'], 'jdtojewish' => ['string', 'julian_day'=>'int', 'hebrew='=>'bool', 'flags='=>'int'], 'jdtojulian' => ['string', 'julian_day'=>'int'], 'jdtounix' => ['int', 'julian_day'=>'int'], 'jewishtojd' => ['int', 'month'=>'int', 'day'=>'int', 'year'=>'int'], 'jobqueue_license_info' => ['array'], 'join' => ['string', 'separator'=>'string', 'array'=>'array'], 'join\'1' => ['string', 'separator'=>'array'], 'json_decode' => ['mixed', 'json'=>'string', 'associative='=>'?bool', 'depth='=>'int', 'flags='=>'int'], 'json_encode' => ['non-empty-string|false', 'value'=>'mixed', 'flags='=>'int', 'depth='=>'int'], 'json_last_error' => ['int'], 'json_last_error_msg' => ['string'], 'json_validate' => ['bool', 'json'=>'string', 'depth='=>'positive-int', 'flags='=>'int'], 'JsonException::__construct' => ['void', "message="=>"string", 'code='=>'int', 'previous='=>'?Throwable'], 'JsonException::__toString' => ['string'], 'JsonException::__wakeup' => ['void'], 'JsonException::getCode' => ['int'], 'JsonException::getFile' => ['string'], 'JsonException::getLine' => ['int'], 'JsonException::getMessage' => ['string'], 'JsonException::getPrevious' => ['?Throwable'], 'JsonException::getTrace' => ['list\',args?:array}>'], 'JsonException::getTraceAsString' => ['string'], 'JsonIncrementalParser::__construct' => ['void', 'depth'=>'', 'options'=>''], 'JsonIncrementalParser::get' => ['', 'options'=>''], 'JsonIncrementalParser::getError' => [''], 'JsonIncrementalParser::parse' => ['', 'json'=>''], 'JsonIncrementalParser::parseFile' => ['', 'filename'=>''], 'JsonIncrementalParser::reset' => [''], 'JsonSerializable::jsonSerialize' => ['mixed'], 'Judy::__construct' => ['void', 'judy_type'=>'int'], 'Judy::__destruct' => ['void'], 'Judy::byCount' => ['int', 'nth_index'=>'int'], 'Judy::count' => ['int', 'index_start='=>'int', 'index_end='=>'int'], 'Judy::first' => ['mixed', 'index='=>'mixed'], 'Judy::firstEmpty' => ['mixed', 'index='=>'mixed'], 'Judy::free' => ['int'], 'Judy::getType' => ['int'], 'Judy::last' => ['mixed', 'index='=>'string'], 'Judy::lastEmpty' => ['mixed', 'index='=>'int'], 'Judy::memoryUsage' => ['int'], 'Judy::next' => ['mixed', 'index'=>'mixed'], 'Judy::nextEmpty' => ['mixed', 'index'=>'mixed'], 'Judy::offsetExists' => ['bool', 'offset'=>'int|string'], 'Judy::offsetGet' => ['mixed', 'offset'=>'int|string'], 'Judy::offsetSet' => ['bool', 'offset'=>'int|string|null', 'value'=>'mixed'], 'Judy::offsetUnset' => ['bool', 'offset'=>'int|string'], 'Judy::prev' => ['mixed', 'index'=>'mixed'], 'Judy::prevEmpty' => ['mixed', 'index'=>'mixed'], 'Judy::size' => ['int'], 'judy_type' => ['int', 'array'=>'judy'], 'judy_version' => ['string'], 'juliantojd' => ['int', 'month'=>'int', 'day'=>'int', 'year'=>'int'], 'kadm5_chpass_principal' => ['bool', 'handle'=>'resource', 'principal'=>'string', 'password'=>'string'], 'kadm5_create_principal' => ['bool', 'handle'=>'resource', 'principal'=>'string', 'password='=>'string', 'options='=>'array'], 'kadm5_delete_principal' => ['bool', 'handle'=>'resource', 'principal'=>'string'], 'kadm5_destroy' => ['bool', 'handle'=>'resource'], 'kadm5_flush' => ['bool', 'handle'=>'resource'], 'kadm5_get_policies' => ['array', 'handle'=>'resource'], 'kadm5_get_principal' => ['array', 'handle'=>'resource', 'principal'=>'string'], 'kadm5_get_principals' => ['array', 'handle'=>'resource'], 'kadm5_init_with_password' => ['resource', 'admin_server'=>'string', 'realm'=>'string', 'principal'=>'string', 'password'=>'string'], 'kadm5_modify_principal' => ['bool', 'handle'=>'resource', 'principal'=>'string', 'options'=>'array'], 'key' => ['int|string|null', 'array'=>'array'], 'key_exists' => ['bool', 'key'=>'string|int', 'array'=>'array'], 'krsort' => ['true', '&rw_array'=>'array', 'flags='=>'int'], 'ksort' => ['true', '&rw_array'=>'array', 'flags='=>'int'], 'KTaglib_ID3v2_AttachedPictureFrame::getDescription' => ['string'], 'KTaglib_ID3v2_AttachedPictureFrame::getMimeType' => ['string'], 'KTaglib_ID3v2_AttachedPictureFrame::getType' => ['int'], 'KTaglib_ID3v2_AttachedPictureFrame::savePicture' => ['bool', 'filename'=>'string'], 'KTaglib_ID3v2_AttachedPictureFrame::setMimeType' => ['string', 'type'=>'string'], 'KTaglib_ID3v2_AttachedPictureFrame::setPicture' => ['', 'filename'=>'string'], 'KTaglib_ID3v2_AttachedPictureFrame::setType' => ['', 'type'=>'int'], 'KTaglib_ID3v2_Frame::__toString' => ['string'], 'KTaglib_ID3v2_Frame::getDescription' => ['string'], 'KTaglib_ID3v2_Frame::getMimeType' => ['string'], 'KTaglib_ID3v2_Frame::getSize' => ['int'], 'KTaglib_ID3v2_Frame::getType' => ['int'], 'KTaglib_ID3v2_Frame::savePicture' => ['bool', 'filename'=>'string'], 'KTaglib_ID3v2_Frame::setMimeType' => ['string', 'type'=>'string'], 'KTaglib_ID3v2_Frame::setPicture' => ['void', 'filename'=>'string'], 'KTaglib_ID3v2_Frame::setType' => ['void', 'type'=>'int'], 'KTaglib_ID3v2_Tag::addFrame' => ['bool', 'frame'=>'KTaglib_ID3v2_Frame'], 'KTaglib_ID3v2_Tag::getFrameList' => ['array'], 'KTaglib_MPEG_AudioProperties::getBitrate' => ['int'], 'KTaglib_MPEG_AudioProperties::getChannels' => ['int'], 'KTaglib_MPEG_AudioProperties::getLayer' => ['int'], 'KTaglib_MPEG_AudioProperties::getLength' => ['int'], 'KTaglib_MPEG_AudioProperties::getSampleBitrate' => ['int'], 'KTaglib_MPEG_AudioProperties::getVersion' => ['int'], 'KTaglib_MPEG_AudioProperties::isCopyrighted' => ['bool'], 'KTaglib_MPEG_AudioProperties::isOriginal' => ['bool'], 'KTaglib_MPEG_AudioProperties::isProtectionEnabled' => ['bool'], 'KTaglib_MPEG_File::getAudioProperties' => ['KTaglib_MPEG_File'], 'KTaglib_MPEG_File::getID3v1Tag' => ['KTaglib_ID3v1_Tag', 'create='=>'bool'], 'KTaglib_MPEG_File::getID3v2Tag' => ['KTaglib_ID3v2_Tag', 'create='=>'bool'], 'KTaglib_Tag::getAlbum' => ['string'], 'KTaglib_Tag::getArtist' => ['string'], 'KTaglib_Tag::getComment' => ['string'], 'KTaglib_Tag::getGenre' => ['string'], 'KTaglib_Tag::getTitle' => ['string'], 'KTaglib_Tag::getTrack' => ['int'], 'KTaglib_Tag::getYear' => ['int'], 'KTaglib_Tag::isEmpty' => ['bool'], 'labelcacheObj::freeCache' => ['bool'], 'labelObj::__construct' => ['void'], 'labelObj::convertToString' => ['string'], 'labelObj::deleteStyle' => ['int', 'index'=>'int'], 'labelObj::free' => ['void'], 'labelObj::getBinding' => ['string', 'labelbinding'=>'mixed'], 'labelObj::getExpressionString' => ['string'], 'labelObj::getStyle' => ['styleObj', 'index'=>'int'], 'labelObj::getTextString' => ['string'], 'labelObj::moveStyleDown' => ['int', 'index'=>'int'], 'labelObj::moveStyleUp' => ['int', 'index'=>'int'], 'labelObj::removeBinding' => ['int', 'labelbinding'=>'mixed'], 'labelObj::set' => ['int', 'property_name'=>'string', 'new_value'=>''], 'labelObj::setBinding' => ['int', 'labelbinding'=>'mixed', 'value'=>'string'], 'labelObj::setExpression' => ['int', 'expression'=>'string'], 'labelObj::setText' => ['int', 'text'=>'string'], 'labelObj::updateFromString' => ['int', 'snippet'=>'string'], 'Lapack::eigenValues' => ['array', 'a'=>'array', 'left='=>'array', 'right='=>'array'], 'Lapack::identity' => ['array', 'n'=>'int'], 'Lapack::leastSquaresByFactorisation' => ['array', 'a'=>'array', 'b'=>'array'], 'Lapack::leastSquaresBySVD' => ['array', 'a'=>'array', 'b'=>'array'], 'Lapack::pseudoInverse' => ['array', 'a'=>'array'], 'Lapack::singularValues' => ['array', 'a'=>'array'], 'Lapack::solveLinearEquation' => ['array', 'a'=>'array', 'b'=>'array'], 'layerObj::addFeature' => ['int', 'shape'=>'shapeObj'], 'layerObj::applySLD' => ['int', 'sldxml'=>'string', 'namedlayer'=>'string'], 'layerObj::applySLDURL' => ['int', 'sldurl'=>'string', 'namedlayer'=>'string'], 'layerObj::clearProcessing' => ['void'], 'layerObj::close' => ['void'], 'layerObj::convertToString' => ['string'], 'layerObj::draw' => ['int', 'image'=>'imageObj'], 'layerObj::drawQuery' => ['int', 'image'=>'imageObj'], 'layerObj::free' => ['void'], 'layerObj::generateSLD' => ['string'], 'layerObj::getClass' => ['classObj', 'classIndex'=>'int'], 'layerObj::getClassIndex' => ['int', 'shape'=>'', 'classgroup'=>'', 'numclasses'=>''], 'layerObj::getExtent' => ['rectObj'], 'layerObj::getFilterString' => ['?string'], 'layerObj::getGridIntersectionCoordinates' => ['array'], 'layerObj::getItems' => ['array'], 'layerObj::getMetaData' => ['int', 'name'=>'string'], 'layerObj::getNumResults' => ['int'], 'layerObj::getProcessing' => ['array'], 'layerObj::getProjection' => ['string'], 'layerObj::getResult' => ['resultObj', 'index'=>'int'], 'layerObj::getResultsBounds' => ['rectObj'], 'layerObj::getShape' => ['shapeObj', 'result'=>'resultObj'], 'layerObj::getWMSFeatureInfoURL' => ['string', 'clickX'=>'int', 'clickY'=>'int', 'featureCount'=>'int', 'infoFormat'=>'string'], 'layerObj::isVisible' => ['bool'], 'layerObj::moveclassdown' => ['int', 'index'=>'int'], 'layerObj::moveclassup' => ['int', 'index'=>'int'], 'layerObj::ms_newLayerObj' => ['layerObj', 'map'=>'mapObj', 'layer'=>'layerObj'], 'layerObj::nextShape' => ['shapeObj'], 'layerObj::open' => ['int'], 'layerObj::queryByAttributes' => ['int', 'qitem'=>'string', 'qstring'=>'string', 'mode'=>'int'], 'layerObj::queryByFeatures' => ['int', 'slayer'=>'int'], 'layerObj::queryByPoint' => ['int', 'point'=>'pointObj', 'mode'=>'int', 'buffer'=>'float'], 'layerObj::queryByRect' => ['int', 'rect'=>'rectObj'], 'layerObj::queryByShape' => ['int', 'shape'=>'shapeObj'], 'layerObj::removeClass' => ['?classObj', 'index'=>'int'], 'layerObj::removeMetaData' => ['int', 'name'=>'string'], 'layerObj::set' => ['int', 'property_name'=>'string', 'new_value'=>''], 'layerObj::setConnectionType' => ['int', 'connectiontype'=>'int', 'plugin_library'=>'string'], 'layerObj::setFilter' => ['int', 'expression'=>'string'], 'layerObj::setMetaData' => ['int', 'name'=>'string', 'value'=>'string'], 'layerObj::setProjection' => ['int', 'proj_params'=>'string'], 'layerObj::setWKTProjection' => ['int', 'proj_params'=>'string'], 'layerObj::updateFromString' => ['int', 'snippet'=>'string'], 'lcfirst' => ['string', 'string'=>'string'], 'lcg_value' => ['float'], 'lchgrp' => ['bool', 'filename'=>'string', 'group'=>'string|int'], 'lchown' => ['bool', 'filename'=>'string', 'user'=>'string|int'], 'ldap_8859_to_t61' => ['string', 'value'=>'string'], 'ldap_add' => ['bool', 'ldap'=>'LDAP\Connection', 'dn'=>'string', 'entry'=>'array', 'controls='=>'?array'], 'ldap_add_ext' => ['LDAP\Result|false', 'ldap'=>'LDAP\Connection', 'dn'=>'string', 'entry'=>'array', 'controls='=>'?array'], 'ldap_bind' => ['bool', 'ldap'=>'LDAP\Connection', 'dn='=>'string|null', 'password='=>'string|null'], 'ldap_bind_ext' => ['LDAP\Result|false', 'ldap'=>'LDAP\Connection', 'dn='=>'string|null', 'password='=>'string|null', 'controls='=>'?array'], 'ldap_close' => ['bool', 'ldap'=>'LDAP\Connection'], 'ldap_compare' => ['bool|int', 'ldap'=>'LDAP\Connection', 'dn'=>'string', 'attribute'=>'string', 'value'=>'string', 'controls='=>'?array'], 'ldap_connect' => ['LDAP\Connection|false', 'uri='=>'?string', 'port='=>'int', 'wallet='=>'string', 'password='=>'string', 'auth_mode='=>'int'], 'ldap_count_entries' => ['int', 'ldap'=>'LDAP\Connection', 'result'=>'LDAP\Result'], 'ldap_delete' => ['bool', 'ldap'=>'LDAP\Connection', 'dn'=>'string', 'controls='=>'?array'], 'ldap_delete_ext' => ['LDAP\Result|false', 'ldap'=>'LDAP\Connection', 'dn'=>'string', 'controls='=>'?array'], 'ldap_dn2ufn' => ['string|false', 'dn'=>'string'], 'ldap_err2str' => ['string', 'errno'=>'int'], 'ldap_errno' => ['int', 'ldap'=>'LDAP\Connection'], 'ldap_error' => ['string', 'ldap'=>'LDAP\Connection'], 'ldap_escape' => ['string', 'value'=>'string', 'ignore='=>'string', 'flags='=>'int'], 'ldap_exop' => ['LDAP\Result|bool', 'ldap'=>'LDAP\Connection', 'request_oid'=>'string', 'request_data='=>'?string', 'controls='=>'?array', '&w_response_data='=>'string', '&w_response_oid='=>'string'], 'ldap_exop_passwd' => ['bool|string', 'ldap'=>'LDAP\Connection', 'user='=>'string', 'old_password='=>'string', 'new_password='=>'string', '&w_controls='=>'array|null'], 'ldap_exop_refresh' => ['int|false', 'ldap'=>'LDAP\Connection', 'dn'=>'string', 'ttl'=>'int'], 'ldap_exop_whoami' => ['string|false', 'ldap'=>'LDAP\Connection'], 'ldap_explode_dn' => ['array|false', 'dn'=>'string', 'with_attrib'=>'int'], 'ldap_first_attribute' => ['string|false', 'ldap'=>'LDAP\Connection', 'entry'=>'LDAP\ResultEntry'], 'ldap_first_entry' => ['LDAP\ResultEntry|false', 'ldap'=>'LDAP\Connection', 'result'=>'LDAP\Result'], 'ldap_first_reference' => ['LDAP\ResultEntry|false', 'ldap'=>'LDAP\Connection', 'result'=>'LDAP\Result'], 'ldap_free_result' => ['bool', 'result'=>'LDAP\Result'], 'ldap_get_attributes' => ['array', 'ldap'=>'LDAP\Connection', 'entry'=>'LDAP\ResultEntry'], 'ldap_get_dn' => ['string|false', 'ldap'=>'LDAP\Connection', 'entry'=>'LDAP\ResultEntry'], 'ldap_get_entries' => ['array|false', 'ldap'=>'LDAP\Connection', 'result'=>'LDAP\Result'], 'ldap_get_option' => ['bool', 'ldap'=>'LDAP\Connection', 'option'=>'int', '&w_value='=>'array|string|int'], 'ldap_get_values' => ['array|false', 'ldap'=>'LDAP\Connection', 'entry'=>'LDAP\ResultEntry', 'attribute'=>'string'], 'ldap_get_values_len' => ['array|false', 'ldap'=>'LDAP\Connection', 'entry'=>'LDAP\ResultEntry', 'attribute'=>'string'], 'ldap_list' => ['LDAP\Result|LDAP\Result[]|false', 'ldap'=>'LDAP\Connection|LDAP\Connection[]', 'base'=>'array|string', 'filter'=>'array|string', 'attributes='=>'array', 'attributes_only='=>'int', 'sizelimit='=>'int', 'timelimit='=>'int', 'deref='=>'int', 'controls='=>'?array'], 'ldap_mod_add' => ['bool', 'ldap'=>'LDAP\Connection', 'dn'=>'string', 'entry'=>'array', 'controls='=>'?array'], 'ldap_mod_add_ext' => ['LDAP\Result|false', 'ldap'=>'LDAP\Connection', 'dn'=>'string', 'entry'=>'array', 'controls='=>'?array'], 'ldap_mod_del' => ['bool', 'ldap'=>'LDAP\Connection', 'dn'=>'string', 'entry'=>'array', 'controls='=>'?array'], 'ldap_mod_del_ext' => ['LDAP\Result|false', 'ldap'=>'LDAP\Connection', 'dn'=>'string', 'entry'=>'array', 'controls='=>'?array'], 'ldap_mod_replace' => ['bool', 'ldap'=>'LDAP\Connection', 'dn'=>'string', 'entry'=>'array', 'controls='=>'?array'], 'ldap_mod_replace_ext' => ['LDAP\Result|false', 'ldap'=>'LDAP\Connection', 'dn'=>'string', 'entry'=>'array', 'controls='=>'?array'], 'ldap_modify' => ['bool', 'ldap'=>'LDAP\Connection', 'dn'=>'string', 'entry'=>'array', 'controls='=>'?array'], 'ldap_modify_batch' => ['bool', 'ldap'=>'LDAP\Connection', 'dn'=>'string', 'modifications_info'=>'array', 'controls='=>'?array'], 'ldap_next_attribute' => ['string|false', 'ldap'=>'LDAP\Connection', 'entry'=>'LDAP\ResultEntry'], 'ldap_next_entry' => ['LDAP\ResultEntry|false', 'ldap'=>'LDAP\Connection', 'entry'=>'LDAP\ResultEntry'], 'ldap_next_reference' => ['LDAP\ResultEntry|false', 'ldap'=>'LDAP\Connection', 'entry'=>'LDAP\ResultEntry'], 'ldap_parse_exop' => ['bool', 'ldap'=>'LDAP\Connection', 'result'=>'LDAP\Result', '&w_response_data='=>'string', '&w_response_oid='=>'string'], 'ldap_parse_reference' => ['bool', 'ldap'=>'LDAP\Connection', 'entry'=>'LDAP\ResultEntry', '&w_referrals'=>'array'], 'ldap_parse_result' => ['bool', 'ldap'=>'LDAP\Connection', 'result'=>'LDAP\Result', '&w_error_code'=>'int', '&w_matched_dn='=>'string', '&w_error_message='=>'string', '&w_referrals='=>'array', '&w_controls='=>'array'], 'ldap_read' => ['LDAP\Result|LDAP\Result[]|false', 'ldap'=>'LDAP\Connection|LDAP\Connection[]', 'base'=>'array|string', 'filter'=>'array|string', 'attributes='=>'array', 'attributes_only='=>'int', 'sizelimit='=>'int', 'timelimit='=>'int', 'deref='=>'int', 'controls='=>'?array'], 'ldap_rename' => ['bool', 'ldap'=>'LDAP\Connection', 'dn'=>'string', 'new_rdn'=>'string', 'new_parent'=>'string', 'delete_old_rdn'=>'bool', 'controls='=>'?array'], 'ldap_rename_ext' => ['LDAP\Result|false', 'ldap'=>'LDAP\Connection', 'dn'=>'string', 'new_rdn'=>'string', 'new_parent'=>'string', 'delete_old_rdn'=>'bool', 'controls='=>'?array'], 'ldap_sasl_bind' => ['bool', 'ldap'=>'LDAP\Connection', 'dn='=>'?string', 'password='=>'?string', 'mech='=>'?string', 'realm='=>'?string', 'authc_id='=>'?string', 'authz_id='=>'?string', 'props='=>'?string'], 'ldap_search' => ['LDAP\Result|LDAP\Result[]|false', 'ldap'=>'LDAP\Connection|LDAP\Connection[]', 'base'=>'array|string', 'filter'=>'array|string', 'attributes='=>'array', 'attributes_only='=>'int', 'sizelimit='=>'int', 'timelimit='=>'int', 'deref='=>'int', 'controls='=>'?array'], 'ldap_set_option' => ['bool', 'ldap'=>'LDAP\Connection|null', 'option'=>'int', 'value'=>'mixed'], 'ldap_set_rebind_proc' => ['bool', 'ldap'=>'LDAP\Connection', 'callback'=>'?callable'], 'ldap_start_tls' => ['bool', 'ldap'=>'LDAP\Connection'], 'ldap_t61_to_8859' => ['string', 'value'=>'string'], 'ldap_unbind' => ['bool', 'ldap'=>'LDAP\Connection'], 'leak' => ['', 'num_bytes'=>'int'], 'leak_variable' => ['', 'variable'=>'', 'leak_data'=>'bool'], 'legendObj::convertToString' => ['string'], 'legendObj::free' => ['void'], 'legendObj::set' => ['int', 'property_name'=>'string', 'new_value'=>''], 'legendObj::updateFromString' => ['int', 'snippet'=>'string'], 'LengthException::__construct' => ['void', 'message='=>'string', 'code='=>'int', 'previous='=>'?Throwable'], 'LengthException::__toString' => ['string'], 'LengthException::getCode' => ['int'], 'LengthException::getFile' => ['string'], 'LengthException::getLine' => ['int'], 'LengthException::getMessage' => ['string'], 'LengthException::getPrevious' => ['?Throwable'], 'LengthException::getTrace' => ['list\',args?:array}>'], 'LengthException::getTraceAsString' => ['string'], 'LevelDB::__construct' => ['void', 'name'=>'string', 'options='=>'array', 'read_options='=>'array', 'write_options='=>'array'], 'LevelDB::close' => [''], 'LevelDB::compactRange' => ['', 'start'=>'', 'limit'=>''], 'LevelDB::delete' => ['bool', 'key'=>'string', 'write_options='=>'array'], 'LevelDB::destroy' => ['', 'name'=>'', 'options='=>'array'], 'LevelDB::get' => ['bool|string', 'key'=>'string', 'read_options='=>'array'], 'LevelDB::getApproximateSizes' => ['', 'start'=>'', 'limit'=>''], 'LevelDB::getIterator' => ['LevelDBIterator', 'options='=>'array'], 'LevelDB::getProperty' => ['mixed', 'name'=>'string'], 'LevelDB::getSnapshot' => ['LevelDBSnapshot'], 'LevelDB::put' => ['', 'key'=>'string', 'value'=>'string', 'write_options='=>'array'], 'LevelDB::repair' => ['', 'name'=>'', 'options='=>'array'], 'LevelDB::set' => ['', 'key'=>'string', 'value'=>'string', 'write_options='=>'array'], 'LevelDB::write' => ['', 'batch'=>'LevelDBWriteBatch', 'write_options='=>'array'], 'LevelDBIterator::__construct' => ['void', 'db'=>'LevelDB', 'read_options='=>'array'], 'LevelDBIterator::current' => ['mixed'], 'LevelDBIterator::destroy' => [''], 'LevelDBIterator::getError' => [''], 'LevelDBIterator::key' => ['int|string'], 'LevelDBIterator::last' => [''], 'LevelDBIterator::next' => ['void'], 'LevelDBIterator::prev' => [''], 'LevelDBIterator::rewind' => ['void'], 'LevelDBIterator::seek' => ['', 'key'=>''], 'LevelDBIterator::valid' => ['bool'], 'LevelDBSnapshot::__construct' => ['void', 'db'=>'LevelDB'], 'LevelDBSnapshot::release' => [''], 'LevelDBWriteBatch::__construct' => ['void', 'name'=>'', 'options='=>'array', 'read_options='=>'array', 'write_options='=>'array'], 'LevelDBWriteBatch::clear' => [''], 'LevelDBWriteBatch::delete' => ['', 'key'=>'', 'write_options='=>'array'], 'LevelDBWriteBatch::put' => ['', 'key'=>'', 'value'=>'', 'write_options='=>'array'], 'LevelDBWriteBatch::set' => ['', 'key'=>'', 'value'=>'', 'write_options='=>'array'], 'levenshtein' => ['int', 'string1'=>'string', 'string2'=>'string'], 'levenshtein\'1' => ['int', 'string1'=>'string', 'string2'=>'string', 'insertion_cost'=>'int', 'repetition_cost'=>'int', 'deletion_cost'=>'int'], 'libxml_clear_errors' => ['void'], 'libxml_disable_entity_loader' => ['bool', 'disable='=>'bool'], 'libxml_get_errors' => ['list'], 'libxml_get_last_error' => ['LibXMLError|false'], 'libxml_get_external_entity_loader' => ['(callable(string,string,array{directory:?string,intSubName:?string,extSubURI:?string,extSubSystem:?string}):(resource|string|null))|null'], 'libxml_set_external_entity_loader' => ['bool', 'resolver_function'=>'(callable(string,string,array{directory:?string,intSubName:?string,extSubURI:?string,extSubSystem:?string}):(resource|string|null))|null'], 'libxml_set_streams_context' => ['void', 'context'=>'resource'], 'libxml_use_internal_errors' => ['bool', 'use_errors='=>'?bool'], 'LimitIterator::__construct' => ['void', 'iterator'=>'Iterator', 'offset='=>'int', 'limit='=>'int'], 'LimitIterator::current' => ['mixed'], 'LimitIterator::getInnerIterator' => ['Iterator'], 'LimitIterator::getPosition' => ['int'], 'LimitIterator::key' => ['mixed'], 'LimitIterator::next' => ['void'], 'LimitIterator::rewind' => ['void'], 'LimitIterator::seek' => ['int', 'offset'=>'int'], 'LimitIterator::valid' => ['bool'], 'lineObj::__construct' => ['void'], 'lineObj::add' => ['int', 'point'=>'pointObj'], 'lineObj::addXY' => ['int', 'x'=>'float', 'y'=>'float', 'm'=>'float'], 'lineObj::addXYZ' => ['int', 'x'=>'float', 'y'=>'float', 'z'=>'float', 'm'=>'float'], 'lineObj::ms_newLineObj' => ['lineObj'], 'lineObj::point' => ['pointObj', 'i'=>'int'], 'lineObj::project' => ['int', 'in'=>'projectionObj', 'out'=>'projectionObj'], 'link' => ['bool', 'target'=>'string', 'link'=>'string'], 'linkinfo' => ['int|false', 'path'=>'string'], 'litespeed_request_headers' => ['array'], 'litespeed_response_headers' => ['array'], 'Locale::acceptFromHttp' => ['string|false', 'header'=>'string'], 'Locale::canonicalize' => ['?string', 'locale'=>'string'], 'Locale::composeLocale' => ['string', 'subtags'=>'array'], 'Locale::filterMatches' => ['?bool', 'languageTag'=>'string', 'locale'=>'string', 'canonicalize='=>'bool'], 'Locale::getAllVariants' => ['array', 'locale'=>'string'], 'Locale::getDefault' => ['string'], 'Locale::getDisplayLanguage' => ['string', 'locale'=>'string', 'displayLocale='=>'?string'], 'Locale::getDisplayName' => ['string', 'locale'=>'string', 'displayLocale='=>'?string'], 'Locale::getDisplayRegion' => ['string', 'locale'=>'string', 'displayLocale='=>'?string'], 'Locale::getDisplayScript' => ['string', 'locale'=>'string', 'displayLocale='=>'?string'], 'Locale::getDisplayVariant' => ['string', 'locale'=>'string', 'displayLocale='=>'?string'], 'Locale::getKeywords' => ['array|false', 'locale'=>'string'], 'Locale::getPrimaryLanguage' => ['string', 'locale'=>'string'], 'Locale::getRegion' => ['string', 'locale'=>'string'], 'Locale::getScript' => ['string', 'locale'=>'string'], 'Locale::lookup' => ['?string', 'languageTag'=>'array', 'locale'=>'string', 'canonicalize='=>'bool', 'defaultLocale='=>'?string'], 'Locale::parseLocale' => ['array', 'locale'=>'string'], 'Locale::setDefault' => ['bool', 'locale'=>'string'], 'locale_accept_from_http' => ['string|false', 'header'=>'string'], 'locale_canonicalize' => ['?string', 'locale'=>'string'], 'locale_compose' => ['string|false', 'subtags'=>'array'], 'locale_filter_matches' => ['?bool', 'languageTag'=>'string', 'locale'=>'string', 'canonicalize='=>'bool'], 'locale_get_all_variants' => ['?array', 'locale'=>'string'], 'locale_get_default' => ['string'], 'locale_get_display_language' => ['string', 'locale'=>'string', 'displayLocale='=>'?string'], 'locale_get_display_name' => ['string', 'locale'=>'string', 'displayLocale='=>'?string'], 'locale_get_display_region' => ['string', 'locale'=>'string', 'displayLocale='=>'?string'], 'locale_get_display_script' => ['string', 'locale'=>'string', 'displayLocale='=>'?string'], 'locale_get_display_variant' => ['string', 'locale'=>'string', 'displayLocale='=>'?string'], 'locale_get_keywords' => ['array|false|null', 'locale'=>'string'], 'locale_get_primary_language' => ['?string', 'locale'=>'string'], 'locale_get_region' => ['?string', 'locale'=>'string'], 'locale_get_script' => ['?string', 'locale'=>'string'], 'locale_lookup' => ['?string', 'languageTag'=>'array', 'locale'=>'string', 'canonicalize='=>'bool', 'defaultLocale='=>'?string'], 'locale_parse' => ['?array', 'locale'=>'string'], 'locale_set_default' => ['bool', 'locale'=>'string'], 'localeconv' => ['array'], 'localtime' => ['array', 'timestamp='=>'?int', 'associative='=>'bool'], 'log' => ['float', 'num'=>'float', 'base='=>'float'], 'log10' => ['float', 'num'=>'float'], 'log1p' => ['float', 'num'=>'float'], 'LogicException::__construct' => ['void', 'message='=>'string', 'code='=>'int', 'previous='=>'?Throwable'], 'LogicException::__toString' => ['string'], 'LogicException::getCode' => ['int'], 'LogicException::getFile' => ['string'], 'LogicException::getLine' => ['int'], 'LogicException::getMessage' => ['string'], 'LogicException::getPrevious' => ['?Throwable'], 'LogicException::getTrace' => ['list\',args?:array}>'], 'LogicException::getTraceAsString' => ['string'], 'long2ip' => ['string', 'ip'=>'int'], 'lstat' => ['array{0: int, 1: int, 2: int, 3: int, 4: int, 5: int, 6: int, 7: int, 8: int, 9: int, 10: int, 11: int, 12: int, dev: int, ino: int, mode: int, nlink: int, uid: int, gid: int, rdev: int, size: int, atime: int, mtime: int, ctime: int, blksize: int, blocks: int}|false', 'filename'=>'string'], 'ltrim' => ['string', 'string'=>'string', 'characters='=>'string'], 'Lua::__call' => ['mixed', 'lua_func'=>'callable', 'args='=>'array', 'use_self='=>'int'], 'Lua::__construct' => ['void', 'lua_script_file'=>'string'], 'Lua::assign' => ['?Lua', 'name'=>'string', 'value'=>'mixed'], 'Lua::call' => ['mixed', 'lua_func'=>'callable', 'args='=>'array', 'use_self='=>'int'], 'Lua::eval' => ['mixed', 'statements'=>'string'], 'Lua::getVersion' => ['string'], 'Lua::include' => ['mixed', 'file'=>'string'], 'Lua::registerCallback' => ['Lua|null|false', 'name'=>'string', 'function'=>'callable'], 'LuaClosure::__invoke' => ['void', 'arg'=>'mixed', '...args='=>'mixed'], 'lzf_compress' => ['string', 'data'=>'string'], 'lzf_decompress' => ['string', 'data'=>'string'], 'lzf_optimized_for' => ['int'], 'magic_quotes_runtime' => ['bool', 'new_setting'=>'bool'], 'mail' => ['bool', 'to'=>'string', 'subject'=>'string', 'message'=>'string', 'additional_headers='=>'string|array', 'additional_params='=>'string'], 'mailparse_determine_best_xfer_encoding' => ['string', 'fp'=>'resource'], 'mailparse_msg_create' => ['resource'], 'mailparse_msg_extract_part' => ['void', 'mimemail'=>'resource', 'msgbody'=>'string', 'callbackfunc='=>'callable'], 'mailparse_msg_extract_part_file' => ['string', 'mimemail'=>'resource', 'filename'=>'mixed', 'callbackfunc='=>'callable'], 'mailparse_msg_extract_whole_part_file' => ['string', 'mimemail'=>'resource', 'filename'=>'string', 'callbackfunc='=>'callable'], 'mailparse_msg_free' => ['bool', 'mimemail'=>'resource'], 'mailparse_msg_get_part' => ['resource', 'mimemail'=>'resource', 'mimesection'=>'string'], 'mailparse_msg_get_part_data' => ['array', 'mimemail'=>'resource'], 'mailparse_msg_get_structure' => ['array', 'mimemail'=>'resource'], 'mailparse_msg_parse' => ['bool', 'mimemail'=>'resource', 'data'=>'string'], 'mailparse_msg_parse_file' => ['resource|false', 'filename'=>'string'], 'mailparse_rfc822_parse_addresses' => ['array', 'addresses'=>'string'], 'mailparse_stream_encode' => ['bool', 'sourcefp'=>'resource', 'destfp'=>'resource', 'encoding'=>'string'], 'mailparse_uudecode_all' => ['array', 'fp'=>'resource'], 'mapObj::__construct' => ['void', 'map_file_name'=>'string', 'new_map_path'=>'string'], 'mapObj::appendOutputFormat' => ['int', 'outputFormat'=>'outputformatObj'], 'mapObj::applyconfigoptions' => ['int'], 'mapObj::applySLD' => ['int', 'sldxml'=>'string'], 'mapObj::applySLDURL' => ['int', 'sldurl'=>'string'], 'mapObj::convertToString' => ['string'], 'mapObj::draw' => ['?imageObj'], 'mapObj::drawLabelCache' => ['int', 'image'=>'imageObj'], 'mapObj::drawLegend' => ['imageObj'], 'mapObj::drawQuery' => ['?imageObj'], 'mapObj::drawReferenceMap' => ['imageObj'], 'mapObj::drawScaleBar' => ['imageObj'], 'mapObj::embedLegend' => ['int', 'image'=>'imageObj'], 'mapObj::embedScalebar' => ['int', 'image'=>'imageObj'], 'mapObj::free' => ['void'], 'mapObj::generateSLD' => ['string'], 'mapObj::getAllGroupNames' => ['array'], 'mapObj::getAllLayerNames' => ['array'], 'mapObj::getColorbyIndex' => ['colorObj', 'iCloIndex'=>'int'], 'mapObj::getConfigOption' => ['string', 'key'=>'string'], 'mapObj::getLabel' => ['labelcacheMemberObj', 'index'=>'int'], 'mapObj::getLayer' => ['layerObj', 'index'=>'int'], 'mapObj::getLayerByName' => ['layerObj', 'layer_name'=>'string'], 'mapObj::getLayersDrawingOrder' => ['array'], 'mapObj::getLayersIndexByGroup' => ['array', 'groupname'=>'string'], 'mapObj::getMetaData' => ['int', 'name'=>'string'], 'mapObj::getNumSymbols' => ['int'], 'mapObj::getOutputFormat' => ['?outputformatObj', 'index'=>'int'], 'mapObj::getProjection' => ['string'], 'mapObj::getSymbolByName' => ['int', 'symbol_name'=>'string'], 'mapObj::getSymbolObjectById' => ['symbolObj', 'symbolid'=>'int'], 'mapObj::loadMapContext' => ['int', 'filename'=>'string', 'unique_layer_name'=>'bool'], 'mapObj::loadOWSParameters' => ['int', 'request'=>'OwsrequestObj', 'version'=>'string'], 'mapObj::moveLayerDown' => ['int', 'layerindex'=>'int'], 'mapObj::moveLayerUp' => ['int', 'layerindex'=>'int'], 'mapObj::ms_newMapObjFromString' => ['mapObj', 'map_file_string'=>'string', 'new_map_path'=>'string'], 'mapObj::offsetExtent' => ['int', 'x'=>'float', 'y'=>'float'], 'mapObj::owsDispatch' => ['int', 'request'=>'OwsrequestObj'], 'mapObj::prepareImage' => ['imageObj'], 'mapObj::prepareQuery' => ['void'], 'mapObj::processLegendTemplate' => ['string', 'params'=>'array'], 'mapObj::processQueryTemplate' => ['string', 'params'=>'array', 'generateimages'=>'bool'], 'mapObj::processTemplate' => ['string', 'params'=>'array', 'generateimages'=>'bool'], 'mapObj::queryByFeatures' => ['int', 'slayer'=>'int'], 'mapObj::queryByIndex' => ['int', 'layerindex'=>'', 'tileindex'=>'', 'shapeindex'=>'', 'addtoquery'=>''], 'mapObj::queryByPoint' => ['int', 'point'=>'pointObj', 'mode'=>'int', 'buffer'=>'float'], 'mapObj::queryByRect' => ['int', 'rect'=>'rectObj'], 'mapObj::queryByShape' => ['int', 'shape'=>'shapeObj'], 'mapObj::removeLayer' => ['layerObj', 'nIndex'=>'int'], 'mapObj::removeMetaData' => ['int', 'name'=>'string'], 'mapObj::removeOutputFormat' => ['int', 'name'=>'string'], 'mapObj::save' => ['int', 'filename'=>'string'], 'mapObj::saveMapContext' => ['int', 'filename'=>'string'], 'mapObj::saveQuery' => ['int', 'filename'=>'string', 'results'=>'int'], 'mapObj::scaleExtent' => ['int', 'zoomfactor'=>'float', 'minscaledenom'=>'float', 'maxscaledenom'=>'float'], 'mapObj::selectOutputFormat' => ['int', 'type'=>'string'], 'mapObj::set' => ['int', 'property_name'=>'string', 'new_value'=>''], 'mapObj::setCenter' => ['int', 'center'=>'pointObj'], 'mapObj::setConfigOption' => ['int', 'key'=>'string', 'value'=>'string'], 'mapObj::setExtent' => ['void', 'minx'=>'float', 'miny'=>'float', 'maxx'=>'float', 'maxy'=>'float'], 'mapObj::setFontSet' => ['int', 'fileName'=>'string'], 'mapObj::setMetaData' => ['int', 'name'=>'string', 'value'=>'string'], 'mapObj::setProjection' => ['int', 'proj_params'=>'string', 'bSetUnitsAndExtents'=>'bool'], 'mapObj::setRotation' => ['int', 'rotation_angle'=>'float'], 'mapObj::setSize' => ['int', 'width'=>'int', 'height'=>'int'], 'mapObj::setSymbolSet' => ['int', 'fileName'=>'string'], 'mapObj::setWKTProjection' => ['int', 'proj_params'=>'string', 'bSetUnitsAndExtents'=>'bool'], 'mapObj::zoomPoint' => ['int', 'nZoomFactor'=>'int', 'oPixelPos'=>'pointObj', 'nImageWidth'=>'int', 'nImageHeight'=>'int', 'oGeorefExt'=>'rectObj'], 'mapObj::zoomRectangle' => ['int', 'oPixelExt'=>'rectObj', 'nImageWidth'=>'int', 'nImageHeight'=>'int', 'oGeorefExt'=>'rectObj'], 'mapObj::zoomScale' => ['int', 'nScaleDenom'=>'float', 'oPixelPos'=>'pointObj', 'nImageWidth'=>'int', 'nImageHeight'=>'int', 'oGeorefExt'=>'rectObj', 'oMaxGeorefExt'=>'rectObj'], 'max' => ['mixed', 'value'=>'non-empty-array'], 'max\'1' => ['mixed', 'value'=>'', 'values'=>'', '...args='=>''], 'mb_check_encoding' => ['bool', 'value'=>'array|string', 'encoding='=>'string|null'], 'mb_chr' => ['non-empty-string|false', 'codepoint'=>'int', 'encoding='=>'string|null'], 'mb_convert_case' => ['string', 'string'=>'string', 'mode'=>'int', 'encoding='=>'string|null'], 'mb_convert_encoding' => ['string|false', 'string'=>'string', 'to_encoding'=>'string', 'from_encoding='=>'array|string|null'], 'mb_convert_encoding\'1' => ['array', 'string'=>'array', 'to_encoding'=>'string', 'from_encoding='=>'array|string|null'], 'mb_convert_kana' => ['string', 'string'=>'string', 'mode='=>'string', 'encoding='=>'string|null'], 'mb_convert_variables' => ['string|false', 'to_encoding'=>'string', 'from_encoding'=>'array|string', '&rw_var'=>'string|array|object', '&...rw_vars='=>'string|array|object'], 'mb_decode_mimeheader' => ['string', 'string'=>'string'], 'mb_decode_numericentity' => ['string', 'string'=>'string', 'map'=>'array', 'encoding='=>'string|null'], 'mb_detect_encoding' => ['string|false', 'string'=>'string', 'encodings='=>'array|string|null', 'strict='=>'bool'], 'mb_detect_order' => ['bool|list', 'encoding='=>'array|string|null'], 'mb_encode_mimeheader' => ['string', 'string'=>'string', 'charset='=>'string|null', 'transfer_encoding='=>'string|null', 'newline='=>'string', 'indent='=>'int'], 'mb_encode_numericentity' => ['string', 'string'=>'string', 'map'=>'array', 'encoding='=>'string|null', 'hex='=>'bool'], 'mb_encoding_aliases' => ['list', 'encoding'=>'string'], 'mb_ereg' => ['bool', 'pattern'=>'string', 'string'=>'string', '&w_matches='=>'array|null'], 'mb_ereg_match' => ['bool', 'pattern'=>'string', 'string'=>'string', 'options='=>'string|null'], 'mb_ereg_replace' => ['string|false|null', 'pattern'=>'string', 'replacement'=>'string', 'string'=>'string', 'options='=>'string|null'], 'mb_ereg_replace_callback' => ['string|false|null', 'pattern'=>'string', 'callback'=>'callable', 'string'=>'string', 'options='=>'string|null'], 'mb_ereg_search' => ['bool', 'pattern='=>'string|null', 'options='=>'string|null'], 'mb_ereg_search_getpos' => ['int'], 'mb_ereg_search_getregs' => ['string[]|false'], 'mb_ereg_search_init' => ['bool', 'string'=>'string', 'pattern='=>'string|null', 'options='=>'string|null'], 'mb_ereg_search_pos' => ['int[]|false', 'pattern='=>'string|null', 'options='=>'string|null'], 'mb_ereg_search_regs' => ['string[]|false', 'pattern='=>'string|null', 'options='=>'string|null'], 'mb_ereg_search_setpos' => ['bool', 'offset'=>'int'], 'mb_eregi' => ['bool', 'pattern'=>'string', 'string'=>'string', '&w_matches='=>'array|null'], 'mb_eregi_replace' => ['string|false|null', 'pattern'=>'string', 'replacement'=>'string', 'string'=>'string', 'options='=>'string|null'], 'mb_get_info' => ['array|string|int|false|null', 'type='=>'string'], 'mb_http_input' => ['array|string|false', 'type='=>'string|null'], 'mb_http_output' => ['string|bool', 'encoding='=>'string|null'], 'mb_internal_encoding' => ['string|bool', 'encoding='=>'string|null'], 'mb_language' => ['string|bool', 'language='=>'string|null'], 'mb_list_encodings' => ['list'], 'mb_ord' => ['int|false', 'string'=>'string', 'encoding='=>'string|null'], 'mb_output_handler' => ['string', 'string'=>'string', 'status'=>'int'], 'mb_parse_str' => ['bool', 'string'=>'string', '&w_result'=>'array'], 'mb_preferred_mime_name' => ['string|false', 'encoding'=>'string'], 'mb_regex_encoding' => ['string|bool', 'encoding='=>'string|null'], 'mb_regex_set_options' => ['string', 'options='=>'string|null'], 'mb_scrub' => ['string', 'string'=>'string', 'encoding='=>'string|null'], 'mb_send_mail' => ['bool', 'to'=>'string', 'subject'=>'string', 'message'=>'string', 'additional_headers='=>'string|array', 'additional_params='=>'string|null'], 'mb_split' => ['list|false', 'pattern'=>'string', 'string'=>'string', 'limit='=>'int'], 'mb_str_split' => ['list', 'string'=>'string', 'length='=>'positive-int', 'encoding='=>'string|null'], 'mb_strcut' => ['string', 'string'=>'string', 'start'=>'int', 'length='=>'?int', 'encoding='=>'string|null'], 'mb_strimwidth' => ['string', 'string'=>'string', 'start'=>'int', 'width'=>'int', 'trim_marker='=>'string', 'encoding='=>'string|null'], 'mb_stripos' => ['int|false', 'haystack'=>'string', 'needle'=>'string', 'offset='=>'int', 'encoding='=>'string|null'], 'mb_stristr' => ['string|false', 'haystack'=>'string', 'needle'=>'string', 'before_needle='=>'bool', 'encoding='=>'string|null'], 'mb_strlen' => ['0|positive-int', 'string'=>'string', 'encoding='=>'string|null'], 'mb_strpos' => ['int|false', 'haystack'=>'string', 'needle'=>'string', 'offset='=>'int', 'encoding='=>'string|null'], 'mb_strrchr' => ['string|false', 'haystack'=>'string', 'needle'=>'string', 'before_needle='=>'bool', 'encoding='=>'string|null'], 'mb_strrichr' => ['string|false', 'haystack'=>'string', 'needle'=>'string', 'before_needle='=>'bool', 'encoding='=>'string|null'], 'mb_strripos' => ['int|false', 'haystack'=>'string', 'needle'=>'string', 'offset='=>'int', 'encoding='=>'string|null'], 'mb_strrpos' => ['int|false', 'haystack'=>'string', 'needle'=>'string', 'offset='=>'int', 'encoding='=>'string|null'], 'mb_strstr' => ['string|false', 'haystack'=>'string', 'needle'=>'string', 'before_needle='=>'bool', 'encoding='=>'string|null'], 'mb_strtolower' => ['lowercase-string', 'string'=>'string', 'encoding='=>'string|null'], 'mb_strtoupper' => ['string', 'string'=>'string', 'encoding='=>'string|null'], 'mb_strwidth' => ['int', 'string'=>'string', 'encoding='=>'string|null'], 'mb_substitute_character' => ['bool|int|string', 'substitute_character='=>'int|string|null'], 'mb_substr' => ['string', 'string'=>'string', 'start'=>'int', 'length='=>'?int', 'encoding='=>'string|null'], 'mb_substr_count' => ['int', 'haystack'=>'string', 'needle'=>'string', 'encoding='=>'string|null'], 'mcrypt_cbc' => ['string', 'cipher'=>'string|int', 'key'=>'string', 'data'=>'string', 'mode'=>'int', 'iv='=>'string'], 'mcrypt_cfb' => ['string', 'cipher'=>'string|int', 'key'=>'string', 'data'=>'string', 'mode'=>'int', 'iv='=>'string'], 'mcrypt_create_iv' => ['string|false', 'size'=>'int', 'source='=>'int'], 'mcrypt_decrypt' => ['string', 'cipher'=>'string', 'key'=>'string', 'data'=>'string', 'mode'=>'string', 'iv='=>'string'], 'mcrypt_ecb' => ['string', 'cipher'=>'string|int', 'key'=>'string', 'data'=>'string', 'mode'=>'int', 'iv='=>'string'], 'mcrypt_enc_get_algorithms_name' => ['string', 'td'=>'resource'], 'mcrypt_enc_get_block_size' => ['int', 'td'=>'resource'], 'mcrypt_enc_get_iv_size' => ['int', 'td'=>'resource'], 'mcrypt_enc_get_key_size' => ['int', 'td'=>'resource'], 'mcrypt_enc_get_modes_name' => ['string', 'td'=>'resource'], 'mcrypt_enc_get_supported_key_sizes' => ['array', 'td'=>'resource'], 'mcrypt_enc_is_block_algorithm' => ['bool', 'td'=>'resource'], 'mcrypt_enc_is_block_algorithm_mode' => ['bool', 'td'=>'resource'], 'mcrypt_enc_is_block_mode' => ['bool', 'td'=>'resource'], 'mcrypt_enc_self_test' => ['int|false', 'td'=>'resource'], 'mcrypt_encrypt' => ['string', 'cipher'=>'string', 'key'=>'string', 'data'=>'string', 'mode'=>'string', 'iv='=>'string'], 'mcrypt_generic' => ['string', 'td'=>'resource', 'data'=>'string'], 'mcrypt_generic_deinit' => ['bool', 'td'=>'resource'], 'mcrypt_generic_end' => ['bool', 'td'=>'resource'], 'mcrypt_generic_init' => ['int|false', 'td'=>'resource', 'key'=>'string', 'iv'=>'string'], 'mcrypt_get_block_size' => ['int', 'cipher'=>'int|string', 'module'=>'string'], 'mcrypt_get_cipher_name' => ['string|false', 'cipher'=>'int|string'], 'mcrypt_get_iv_size' => ['int|false', 'cipher'=>'int|string', 'module'=>'string'], 'mcrypt_get_key_size' => ['int', 'cipher'=>'int|string', 'module'=>'string'], 'mcrypt_list_algorithms' => ['array', 'lib_dir='=>'string'], 'mcrypt_list_modes' => ['array', 'lib_dir='=>'string'], 'mcrypt_module_close' => ['bool', 'td'=>'resource'], 'mcrypt_module_get_algo_block_size' => ['int', 'algorithm'=>'string', 'lib_dir='=>'string'], 'mcrypt_module_get_algo_key_size' => ['int', 'algorithm'=>'string', 'lib_dir='=>'string'], 'mcrypt_module_get_supported_key_sizes' => ['array', 'algorithm'=>'string', 'lib_dir='=>'string'], 'mcrypt_module_is_block_algorithm' => ['bool', 'algorithm'=>'string', 'lib_dir='=>'string'], 'mcrypt_module_is_block_algorithm_mode' => ['bool', 'mode'=>'string', 'lib_dir='=>'string'], 'mcrypt_module_is_block_mode' => ['bool', 'mode'=>'string', 'lib_dir='=>'string'], 'mcrypt_module_open' => ['resource|false', 'cipher'=>'string', 'cipher_directory'=>'string', 'mode'=>'string', 'mode_directory'=>'string'], 'mcrypt_module_self_test' => ['bool', 'algorithm'=>'string', 'lib_dir='=>'string'], 'mcrypt_ofb' => ['string', 'cipher'=>'int|string', 'key'=>'string', 'data'=>'string', 'mode'=>'int', 'iv='=>'string'], 'md5' => ['non-falsy-string', 'string'=>'string', 'binary='=>'bool'], 'md5_file' => ['non-falsy-string|false', 'filename'=>'string', 'binary='=>'bool'], 'mdecrypt_generic' => ['string', 'td'=>'resource', 'data'=>'string'], 'Memcache::add' => ['bool', 'key'=>'string', 'var'=>'mixed', 'flag='=>'int', 'expire='=>'int'], 'Memcache::addServer' => ['bool', 'host'=>'string', 'port='=>'int', 'persistent='=>'bool', 'weight='=>'int', 'timeout='=>'int', 'retry_interval='=>'int', 'status='=>'bool', 'failure_callback='=>'callable', 'timeoutms='=>'int'], 'Memcache::append' => [''], 'Memcache::cas' => [''], 'Memcache::close' => ['bool'], 'Memcache::connect' => ['bool', 'host'=>'string', 'port='=>'int', 'timeout='=>'int'], 'Memcache::decrement' => ['int', 'key'=>'string', 'value='=>'int'], 'Memcache::delete' => ['bool', 'key'=>'string', 'timeout='=>'int'], 'Memcache::findServer' => [''], 'Memcache::flush' => ['bool'], 'Memcache::get' => ['string|array|false', 'key'=>'string', 'flags='=>'array', 'keys='=>'array'], 'Memcache::get\'1' => ['array', 'key'=>'string[]', 'flags='=>'int[]'], 'Memcache::getExtendedStats' => ['false|array>', 'type='=>'string', 'slabid='=>'int', 'limit='=>'int'], 'Memcache::getServerStatus' => ['int', 'host'=>'string', 'port='=>'int'], 'Memcache::getStats' => ['array', 'type='=>'string', 'slabid='=>'int', 'limit='=>'int'], 'Memcache::getVersion' => ['string'], 'Memcache::increment' => ['int', 'key'=>'string', 'value='=>'int'], 'Memcache::pconnect' => ['bool', 'host'=>'string', 'port='=>'int', 'timeout='=>'int'], 'Memcache::prepend' => ['string'], 'Memcache::replace' => ['bool', 'key'=>'string', 'var'=>'mixed', 'flag='=>'int', 'expire='=>'int'], 'Memcache::set' => ['bool', 'key'=>'string', 'var'=>'mixed', 'flag='=>'int', 'expire='=>'int'], 'Memcache::setCompressThreshold' => ['bool', 'threshold'=>'int', 'min_savings='=>'float'], 'Memcache::setFailureCallback' => [''], 'Memcache::setServerParams' => ['bool', 'host'=>'string', 'port='=>'int', 'timeout='=>'int', 'retry_interval='=>'int', 'status='=>'bool', 'failure_callback='=>'callable'], 'memcache_add' => ['bool', 'memcache_obj'=>'Memcache', 'key'=>'string', 'var'=>'mixed', 'flag='=>'int', 'expire='=>'int'], 'memcache_add_server' => ['bool', 'memcache_obj'=>'Memcache', 'host'=>'string', 'port='=>'int', 'persistent='=>'bool', 'weight='=>'int', 'timeout='=>'int', 'retry_interval='=>'int', 'status='=>'bool', 'failure_callback='=>'callable', 'timeoutms='=>'int'], 'memcache_append' => ['', 'memcache_obj'=>'Memcache'], 'memcache_cas' => ['', 'memcache_obj'=>'Memcache'], 'memcache_close' => ['bool', 'memcache_obj'=>'Memcache'], 'memcache_connect' => ['Memcache|false', 'host'=>'string', 'port='=>'int', 'timeout='=>'int'], 'memcache_debug' => ['bool', 'on_off'=>'bool'], 'memcache_decrement' => ['int', 'memcache_obj'=>'Memcache', 'key'=>'string', 'value='=>'int'], 'memcache_delete' => ['bool', 'memcache_obj'=>'Memcache', 'key'=>'string', 'timeout='=>'int'], 'memcache_flush' => ['bool', 'memcache_obj'=>'Memcache'], 'memcache_get' => ['string', 'memcache_obj'=>'Memcache', 'key'=>'string', 'flags='=>'int'], 'memcache_get\'1' => ['array', 'memcache_obj'=>'Memcache', 'key'=>'string[]', 'flags='=>'int[]'], 'memcache_get_extended_stats' => ['array', 'memcache_obj'=>'Memcache', 'type='=>'string', 'slabid='=>'int', 'limit='=>'int'], 'memcache_get_server_status' => ['int', 'memcache_obj'=>'Memcache', 'host'=>'string', 'port='=>'int'], 'memcache_get_stats' => ['array', 'memcache_obj'=>'Memcache', 'type='=>'string', 'slabid='=>'int', 'limit='=>'int'], 'memcache_get_version' => ['string', 'memcache_obj'=>'Memcache'], 'memcache_increment' => ['int', 'memcache_obj'=>'Memcache', 'key'=>'string', 'value='=>'int'], 'memcache_pconnect' => ['Memcache|false', 'host'=>'string', 'port='=>'int', 'timeout='=>'int'], 'memcache_prepend' => ['string', 'memcache_obj'=>'Memcache'], 'memcache_replace' => ['bool', 'memcache_obj'=>'Memcache', 'key'=>'string', 'var'=>'mixed', 'flag='=>'int', 'expire='=>'int'], 'memcache_set' => ['bool', 'memcache_obj'=>'Memcache', 'key'=>'string', 'var'=>'mixed', 'flag='=>'int', 'expire='=>'int'], 'memcache_set_compress_threshold' => ['bool', 'memcache_obj'=>'Memcache', 'threshold'=>'int', 'min_savings='=>'float'], 'memcache_set_failure_callback' => ['', 'memcache_obj'=>'Memcache'], 'memcache_set_server_params' => ['bool', 'memcache_obj'=>'Memcache', 'host'=>'string', 'port='=>'int', 'timeout='=>'int', 'retry_interval='=>'int', 'status='=>'bool', 'failure_callback='=>'callable'], 'Memcached::__construct' => ['void', 'persistent_id='=>'?string', 'callback='=>'?callable', 'connection_str='=>'?string'], 'Memcached::add' => ['bool', 'key'=>'string', 'value'=>'mixed', 'expiration='=>'int'], 'Memcached::addByKey' => ['bool', 'server_key'=>'string', 'key'=>'string', 'value'=>'mixed', 'expiration='=>'int'], 'Memcached::addServer' => ['bool', 'host'=>'string', 'port'=>'int', 'weight='=>'int'], 'Memcached::addServers' => ['bool', 'servers'=>'array'], 'Memcached::append' => ['?bool', 'key'=>'string', 'value'=>'string'], 'Memcached::appendByKey' => ['?bool', 'server_key'=>'string', 'key'=>'string', 'value'=>'string'], 'Memcached::cas' => ['bool', 'cas_token'=>'string|int|float', 'key'=>'string', 'value'=>'mixed', 'expiration='=>'int'], 'Memcached::casByKey' => ['bool', 'cas_token'=>'string|int|float', 'server_key'=>'string', 'key'=>'string', 'value'=>'mixed', 'expiration='=>'int'], 'Memcached::decrement' => ['int|false', 'key'=>'string', 'offset='=>'int', 'initial_value='=>'int', 'expiry='=>'int'], 'Memcached::decrementByKey' => ['int|false', 'server_key'=>'string', 'key'=>'string', 'offset='=>'int', 'initial_value='=>'int', 'expiry='=>'int'], 'Memcached::delete' => ['bool', 'key'=>'string', 'time='=>'int'], 'Memcached::deleteByKey' => ['bool', 'server_key'=>'string', 'key'=>'string', 'time='=>'int'], 'Memcached::deleteMulti' => ['array', 'keys'=>'array', 'time='=>'int'], 'Memcached::deleteMultiByKey' => ['array', 'server_key'=>'string', 'keys'=>'array', 'time='=>'int'], 'Memcached::fetch' => ['array|false'], 'Memcached::fetchAll' => ['array|false'], 'Memcached::flush' => ['bool', 'delay='=>'int'], 'Memcached::flushBuffers' => ['bool'], 'Memcached::get' => ['mixed|false', 'key'=>'string', 'cache_cb='=>'?callable', 'get_flags='=>'int'], 'Memcached::getAllKeys' => ['array|false'], 'Memcached::getByKey' => ['mixed|false', 'server_key'=>'string', 'key'=>'string', 'cache_cb='=>'?callable', 'get_flags='=>'int'], 'Memcached::getDelayed' => ['bool', 'keys'=>'array', 'with_cas='=>'bool', 'value_cb='=>'?callable'], 'Memcached::getDelayedByKey' => ['bool', 'server_key'=>'string', 'keys'=>'array', 'with_cas='=>'bool', 'value_cb='=>'?callable'], 'Memcached::getLastDisconnectedServer' => ['array|false'], 'Memcached::getLastErrorCode' => ['int'], 'Memcached::getLastErrorErrno' => ['int'], 'Memcached::getLastErrorMessage' => ['string'], 'Memcached::getMulti' => ['array|false', 'keys'=>'array', 'get_flags='=>'int'], 'Memcached::getMultiByKey' => ['array|false', 'server_key'=>'string', 'keys'=>'array', 'get_flags='=>'int'], 'Memcached::getOption' => ['mixed|false', 'option'=>'int'], 'Memcached::getResultCode' => ['int'], 'Memcached::getResultMessage' => ['string'], 'Memcached::getServerByKey' => ['array', 'server_key'=>'string'], 'Memcached::getServerList' => ['array'], 'Memcached::getStats' => ['false|array>', 'type='=>'?string'], 'Memcached::getVersion' => ['array'], 'Memcached::increment' => ['int|false', 'key'=>'string', 'offset='=>'int', 'initial_value='=>'int', 'expiry='=>'int'], 'Memcached::incrementByKey' => ['int|false', 'server_key'=>'string', 'key'=>'string', 'offset='=>'int', 'initial_value='=>'int', 'expiry='=>'int'], 'Memcached::isPersistent' => ['bool'], 'Memcached::isPristine' => ['bool'], 'Memcached::prepend' => ['?bool', 'key'=>'string', 'value'=>'string'], 'Memcached::prependByKey' => ['?bool', 'server_key'=>'string', 'key'=>'string', 'value'=>'string'], 'Memcached::quit' => ['bool'], 'Memcached::replace' => ['bool', 'key'=>'string', 'value'=>'mixed', 'expiration='=>'int'], 'Memcached::replaceByKey' => ['bool', 'server_key'=>'string', 'key'=>'string', 'value'=>'mixed', 'expiration='=>'int'], 'Memcached::resetServerList' => ['bool'], 'Memcached::set' => ['bool', 'key'=>'string', 'value'=>'mixed', 'expiration='=>'int'], 'Memcached::setBucket' => ['bool', 'host_map'=>'array', 'forward_map'=>'?array', 'replicas'=>'int'], 'Memcached::setByKey' => ['bool', 'server_key'=>'string', 'key'=>'string', 'value'=>'mixed', 'expiration='=>'int'], 'Memcached::setEncodingKey' => ['bool', 'key'=>'string'], 'Memcached::setMulti' => ['bool', 'items'=>'array', 'expiration='=>'int'], 'Memcached::setMultiByKey' => ['bool', 'server_key'=>'string', 'items'=>'array', 'expiration='=>'int'], 'Memcached::setOption' => ['bool', 'option'=>'int', 'value'=>'mixed'], 'Memcached::setOptions' => ['bool', 'options'=>'array'], 'Memcached::setSaslAuthData' => ['bool', 'username'=>'string', 'password'=>'string'], 'Memcached::touch' => ['bool', 'key'=>'string', 'expiration='=>'int'], 'Memcached::touchByKey' => ['bool', 'server_key'=>'string', 'key'=>'string', 'expiration='=>'int'], 'MemcachePool::add' => ['bool', 'key'=>'string', 'var'=>'mixed', 'flag='=>'int', 'expire='=>'int'], 'MemcachePool::addServer' => ['bool', 'host'=>'string', 'port='=>'int', 'persistent='=>'bool', 'weight='=>'int', 'timeout='=>'int', 'retry_interval='=>'int', 'status='=>'bool', 'failure_callback='=>'?callable', 'timeoutms='=>'int'], 'MemcachePool::append' => [''], 'MemcachePool::cas' => [''], 'MemcachePool::close' => ['bool'], 'MemcachePool::connect' => ['bool', 'host'=>'string', 'port'=>'int', 'timeout='=>'int'], 'MemcachePool::decrement' => ['int|false', 'key'=>'', 'value='=>'int|mixed'], 'MemcachePool::delete' => ['bool', 'key'=>'', 'timeout='=>'int|mixed'], 'MemcachePool::findServer' => [''], 'MemcachePool::flush' => ['bool'], 'MemcachePool::get' => ['array|string|false', 'key'=>'array|string', '&flags='=>'array|int'], 'MemcachePool::getExtendedStats' => ['false|array>', 'type='=>'string', 'slabid='=>'int', 'limit='=>'int'], 'MemcachePool::getServerStatus' => ['int', 'host'=>'string', 'port='=>'int'], 'MemcachePool::getStats' => ['array|false', 'type='=>'string', 'slabid='=>'int', 'limit='=>'int'], 'MemcachePool::getVersion' => ['string|false'], 'MemcachePool::increment' => ['int|false', 'key'=>'', 'value='=>'int|mixed'], 'MemcachePool::prepend' => ['string'], 'MemcachePool::replace' => ['bool', 'key'=>'string', 'var'=>'mixed', 'flag='=>'int', 'expire='=>'int'], 'MemcachePool::set' => ['bool', 'key'=>'string', 'var'=>'mixed', 'flag='=>'int', 'expire='=>'int'], 'MemcachePool::setCompressThreshold' => ['bool', 'thresold'=>'int', 'min_saving='=>'float'], 'MemcachePool::setFailureCallback' => [''], 'MemcachePool::setServerParams' => ['bool', 'host'=>'string', 'port='=>'int', 'timeout='=>'int', 'retry_interval='=>'int', 'status='=>'bool', 'failure_callback='=>'?callable'], 'memory_get_peak_usage' => ['int', 'real_usage='=>'bool'], 'memory_get_usage' => ['int', 'real_usage='=>'bool'], 'memory_reset_peak_usage' => ['void'], 'MessageFormatter::__construct' => ['void', 'locale'=>'string', 'pattern'=>'string'], 'MessageFormatter::create' => ['MessageFormatter', 'locale'=>'string', 'pattern'=>'string'], 'MessageFormatter::format' => ['false|string', 'values'=>'array'], 'MessageFormatter::formatMessage' => ['false|string', 'locale'=>'string', 'pattern'=>'string', 'values'=>'array'], 'MessageFormatter::getErrorCode' => ['int'], 'MessageFormatter::getErrorMessage' => ['string'], 'MessageFormatter::getLocale' => ['string'], 'MessageFormatter::getPattern' => ['string'], 'MessageFormatter::parse' => ['array|false', 'string'=>'string'], 'MessageFormatter::parseMessage' => ['array|false', 'locale'=>'string', 'pattern'=>'string', 'message'=>'string'], 'MessageFormatter::setPattern' => ['bool', 'pattern'=>'string'], 'metaphone' => ['string', 'string'=>'string', 'max_phonemes='=>'int'], 'method_exists' => ['bool', 'object_or_class'=>'object|class-string|interface-string|enum-string', 'method'=>'string'], 'mhash' => ['string', 'algo'=>'int', 'data'=>'string', 'key='=>'?string'], 'mhash_count' => ['int'], 'mhash_get_block_size' => ['int|false', 'algo'=>'int'], 'mhash_get_hash_name' => ['string|false', 'algo'=>'int'], 'mhash_keygen_s2k' => ['string|false', 'algo'=>'int', 'password'=>'string', 'salt'=>'string', 'length'=>'int'], 'microtime' => ['string', 'as_float='=>'false'], 'microtime\'1' => ['float', 'as_float='=>'true'], 'mime_content_type' => ['string|false', 'filename'=>'string|resource'], 'min' => ['mixed', 'value'=>'non-empty-array'], 'min\'1' => ['mixed', 'value'=>'', 'values'=>'', '...args='=>''], 'ming_keypress' => ['int', 'char'=>'string'], 'ming_setcubicthreshold' => ['void', 'threshold'=>'int'], 'ming_setscale' => ['void', 'scale'=>'float'], 'ming_setswfcompression' => ['void', 'level'=>'int'], 'ming_useconstants' => ['void', 'use'=>'int'], 'ming_useswfversion' => ['void', 'version'=>'int'], 'mkdir' => ['bool', 'directory'=>'string', 'permissions='=>'int', 'recursive='=>'bool', 'context='=>'null|resource'], 'mktime' => ['int|false', 'hour'=>'int', 'minute='=>'int|null', 'second='=>'int|null', 'month='=>'int|null', 'day='=>'int|null', 'year='=>'int|null'], 'money_format' => ['string', 'format'=>'string', 'value'=>'float'], 'Mongo::__construct' => ['void', 'server='=>'string', 'options='=>'array', 'driver_options='=>'array'], 'Mongo::__get' => ['MongoDB', 'dbname'=>'string'], 'Mongo::__toString' => ['string'], 'Mongo::close' => ['bool'], 'Mongo::connect' => ['bool'], 'Mongo::connectUtil' => ['bool'], 'Mongo::dropDB' => ['array', 'db'=>'mixed'], 'Mongo::forceError' => ['bool'], 'Mongo::getConnections' => ['array'], 'Mongo::getHosts' => ['array'], 'Mongo::getPoolSize' => ['int'], 'Mongo::getReadPreference' => ['array'], 'Mongo::getSlave' => ['?string'], 'Mongo::getSlaveOkay' => ['bool'], 'Mongo::getWriteConcern' => ['array'], 'Mongo::killCursor' => ['', 'server_hash'=>'string', 'id'=>'MongoInt64|int'], 'Mongo::lastError' => ['?array'], 'Mongo::listDBs' => ['array'], 'Mongo::pairConnect' => ['bool'], 'Mongo::pairPersistConnect' => ['bool', 'username='=>'string', 'password='=>'string'], 'Mongo::persistConnect' => ['bool', 'username='=>'string', 'password='=>'string'], 'Mongo::poolDebug' => ['array'], 'Mongo::prevError' => ['array'], 'Mongo::resetError' => ['array'], 'Mongo::selectCollection' => ['MongoCollection', 'db'=>'string', 'collection'=>'string'], 'Mongo::selectDB' => ['MongoDB', 'name'=>'string'], 'Mongo::setPoolSize' => ['bool', 'size'=>'int'], 'Mongo::setReadPreference' => ['bool', 'readPreference'=>'string', 'tags='=>'array'], 'Mongo::setSlaveOkay' => ['bool', 'ok='=>'bool'], 'Mongo::switchSlave' => ['string'], 'MongoBinData::__construct' => ['void', 'data'=>'string', 'type='=>'int'], 'MongoBinData::__toString' => ['string'], 'MongoClient::__construct' => ['void', 'server='=>'string', 'options='=>'array', 'driver_options='=>'array'], 'MongoClient::__get' => ['MongoDB', 'dbname'=>'string'], 'MongoClient::__toString' => ['string'], 'MongoClient::close' => ['bool', 'connection='=>'bool|string'], 'MongoClient::connect' => ['bool'], 'MongoClient::dropDB' => ['array', 'db'=>'mixed'], 'MongoClient::getConnections' => ['array'], 'MongoClient::getHosts' => ['array'], 'MongoClient::getReadPreference' => ['array'], 'MongoClient::getWriteConcern' => ['array'], 'MongoClient::killCursor' => ['bool', 'server_hash'=>'string', 'id'=>'int|MongoInt64'], 'MongoClient::listDBs' => ['array'], 'MongoClient::selectCollection' => ['MongoCollection', 'db'=>'string', 'collection'=>'string'], 'MongoClient::selectDB' => ['MongoDB', 'name'=>'string'], 'MongoClient::setReadPreference' => ['bool', 'read_preference'=>'string', 'tags='=>'array'], 'MongoClient::setWriteConcern' => ['bool', 'w'=>'mixed', 'wtimeout='=>'int'], 'MongoClient::switchSlave' => ['string'], 'MongoCode::__construct' => ['void', 'code'=>'string', 'scope='=>'array'], 'MongoCode::__toString' => ['string'], 'MongoCollection::__construct' => ['void', 'db'=>'MongoDB', 'name'=>'string'], 'MongoCollection::__get' => ['MongoCollection', 'name'=>'string'], 'MongoCollection::__toString' => ['string'], 'MongoCollection::aggregate' => ['array', 'op'=>'array', 'op='=>'array', '...args='=>'array'], 'MongoCollection::aggregate\'1' => ['array', 'pipeline'=>'array', 'options='=>'array'], 'MongoCollection::aggregateCursor' => ['MongoCommandCursor', 'command'=>'array', 'options='=>'array'], 'MongoCollection::batchInsert' => ['array|bool', 'a'=>'array', 'options='=>'array'], 'MongoCollection::count' => ['int', 'query='=>'array', 'limit='=>'int', 'skip='=>'int'], 'MongoCollection::createDBRef' => ['array', 'a'=>'array'], 'MongoCollection::createIndex' => ['array', 'keys'=>'array', 'options='=>'array'], 'MongoCollection::deleteIndex' => ['array', 'keys'=>'string|array'], 'MongoCollection::deleteIndexes' => ['array'], 'MongoCollection::distinct' => ['array|false', 'key'=>'string', 'query='=>'array'], 'MongoCollection::drop' => ['array'], 'MongoCollection::ensureIndex' => ['bool', 'keys'=>'array', 'options='=>'array'], 'MongoCollection::find' => ['MongoCursor', 'query='=>'array', 'fields='=>'array'], 'MongoCollection::findAndModify' => ['array', 'query'=>'array', 'update='=>'array', 'fields='=>'array', 'options='=>'array'], 'MongoCollection::findOne' => ['?array', 'query='=>'array', 'fields='=>'array'], 'MongoCollection::getDBRef' => ['array', 'ref'=>'array'], 'MongoCollection::getIndexInfo' => ['array'], 'MongoCollection::getName' => ['string'], 'MongoCollection::getReadPreference' => ['array'], 'MongoCollection::getSlaveOkay' => ['bool'], 'MongoCollection::getWriteConcern' => ['array'], 'MongoCollection::group' => ['array', 'keys'=>'mixed', 'initial'=>'array', 'reduce'=>'MongoCode', 'options='=>'array'], 'MongoCollection::insert' => ['bool|array', 'a'=>'array|object', 'options='=>'array'], 'MongoCollection::parallelCollectionScan' => ['MongoCommandCursor[]', 'num_cursors'=>'int'], 'MongoCollection::remove' => ['bool|array', 'criteria='=>'array', 'options='=>'array'], 'MongoCollection::save' => ['bool|array', 'a'=>'array|object', 'options='=>'array'], 'MongoCollection::setReadPreference' => ['bool', 'read_preference'=>'string', 'tags='=>'array'], 'MongoCollection::setSlaveOkay' => ['bool', 'ok='=>'bool'], 'MongoCollection::setWriteConcern' => ['bool', 'w'=>'mixed', 'wtimeout='=>'int'], 'MongoCollection::toIndexString' => ['string', 'keys'=>'mixed'], 'MongoCollection::update' => ['bool', 'criteria'=>'array', 'newobj'=>'array', 'options='=>'array'], 'MongoCollection::validate' => ['array', 'scan_data='=>'bool'], 'MongoCommandCursor::__construct' => ['void', 'connection'=>'MongoClient', 'ns'=>'string', 'command'=>'array'], 'MongoCommandCursor::batchSize' => ['MongoCommandCursor', 'batchSize'=>'int'], 'MongoCommandCursor::createFromDocument' => ['MongoCommandCursor', 'connection'=>'MongoClient', 'hash'=>'string', 'document'=>'array'], 'MongoCommandCursor::current' => ['array'], 'MongoCommandCursor::dead' => ['bool'], 'MongoCommandCursor::getReadPreference' => ['array'], 'MongoCommandCursor::info' => ['array'], 'MongoCommandCursor::key' => ['int'], 'MongoCommandCursor::next' => ['void'], 'MongoCommandCursor::rewind' => ['array'], 'MongoCommandCursor::setReadPreference' => ['MongoCommandCursor', 'read_preference'=>'string', 'tags='=>'array'], 'MongoCommandCursor::timeout' => ['MongoCommandCursor', 'ms'=>'int'], 'MongoCommandCursor::valid' => ['bool'], 'MongoCursor::__construct' => ['void', 'connection'=>'MongoClient', 'ns'=>'string', 'query='=>'array', 'fields='=>'array'], 'MongoCursor::addOption' => ['MongoCursor', 'key'=>'string', 'value'=>'mixed'], 'MongoCursor::awaitData' => ['MongoCursor', 'wait='=>'bool'], 'MongoCursor::batchSize' => ['MongoCursor', 'num'=>'int'], 'MongoCursor::count' => ['int', 'foundonly='=>'bool'], 'MongoCursor::current' => ['array'], 'MongoCursor::dead' => ['bool'], 'MongoCursor::doQuery' => ['void'], 'MongoCursor::explain' => ['array'], 'MongoCursor::fields' => ['MongoCursor', 'f'=>'array'], 'MongoCursor::getNext' => ['array'], 'MongoCursor::getReadPreference' => ['array'], 'MongoCursor::hasNext' => ['bool'], 'MongoCursor::hint' => ['MongoCursor', 'key_pattern'=>'string|array|object'], 'MongoCursor::immortal' => ['MongoCursor', 'liveforever='=>'bool'], 'MongoCursor::info' => ['array'], 'MongoCursor::key' => ['string'], 'MongoCursor::limit' => ['MongoCursor', 'num'=>'int'], 'MongoCursor::maxTimeMS' => ['MongoCursor', 'ms'=>'int'], 'MongoCursor::next' => ['array'], 'MongoCursor::partial' => ['MongoCursor', 'okay='=>'bool'], 'MongoCursor::reset' => ['void'], 'MongoCursor::rewind' => ['void'], 'MongoCursor::setFlag' => ['MongoCursor', 'flag'=>'int', 'set='=>'bool'], 'MongoCursor::setReadPreference' => ['MongoCursor', 'read_preference'=>'string', 'tags='=>'array'], 'MongoCursor::skip' => ['MongoCursor', 'num'=>'int'], 'MongoCursor::slaveOkay' => ['MongoCursor', 'okay='=>'bool'], 'MongoCursor::snapshot' => ['MongoCursor'], 'MongoCursor::sort' => ['MongoCursor', 'fields'=>'array'], 'MongoCursor::tailable' => ['MongoCursor', 'tail='=>'bool'], 'MongoCursor::timeout' => ['MongoCursor', 'ms'=>'int'], 'MongoCursor::valid' => ['bool'], 'MongoCursorException::__clone' => ['void'], 'MongoCursorException::__construct' => ['void', 'message='=>'string', 'code='=>'int', 'previous='=>'?Exception|?Throwable'], 'MongoCursorException::__toString' => ['string'], 'MongoCursorException::__wakeup' => ['void'], 'MongoCursorException::getCode' => ['int'], 'MongoCursorException::getFile' => ['string'], 'MongoCursorException::getHost' => ['string'], 'MongoCursorException::getLine' => ['int'], 'MongoCursorException::getMessage' => ['string'], 'MongoCursorException::getPrevious' => ['Exception|Throwable'], 'MongoCursorException::getTrace' => ['list\',args?:array}>'], 'MongoCursorException::getTraceAsString' => ['string'], 'MongoCursorInterface::__construct' => ['void'], 'MongoCursorInterface::batchSize' => ['MongoCursorInterface', 'batchSize'=>'int'], 'MongoCursorInterface::current' => ['mixed'], 'MongoCursorInterface::dead' => ['bool'], 'MongoCursorInterface::getReadPreference' => ['array'], 'MongoCursorInterface::info' => ['array'], 'MongoCursorInterface::key' => ['int|string'], 'MongoCursorInterface::next' => ['void'], 'MongoCursorInterface::rewind' => ['void'], 'MongoCursorInterface::setReadPreference' => ['MongoCursorInterface', 'read_preference'=>'string', 'tags='=>'array'], 'MongoCursorInterface::timeout' => ['MongoCursorInterface', 'ms'=>'int'], 'MongoCursorInterface::valid' => ['bool'], 'MongoDate::__construct' => ['void', 'second='=>'int', 'usecond='=>'int'], 'MongoDate::__toString' => ['string'], 'MongoDate::toDateTime' => ['DateTime'], 'MongoDB::__construct' => ['void', 'conn'=>'MongoClient', 'name'=>'string'], 'MongoDB::__get' => ['MongoCollection', 'name'=>'string'], 'MongoDB::__toString' => ['string'], 'MongoDB::authenticate' => ['array', 'username'=>'string', 'password'=>'string'], 'MongoDB::command' => ['array', 'command'=>'array'], 'MongoDB::createCollection' => ['MongoCollection', 'name'=>'string', 'capped='=>'bool', 'size='=>'int', 'max='=>'int'], 'MongoDB::createDBRef' => ['array', 'collection'=>'string', 'a'=>'mixed'], 'MongoDB::drop' => ['array'], 'MongoDB::dropCollection' => ['array', 'coll'=>'MongoCollection|string'], 'MongoDB::execute' => ['array', 'code'=>'MongoCode|string', 'args='=>'array'], 'MongoDB::forceError' => ['bool'], 'MongoDB::getCollectionInfo' => ['array', 'options='=>'array'], 'MongoDB::getCollectionNames' => ['array', 'options='=>'array'], 'MongoDB::getDBRef' => ['array', 'ref'=>'array'], 'MongoDB::getGridFS' => ['MongoGridFS', 'prefix='=>'string'], 'MongoDB::getProfilingLevel' => ['int'], 'MongoDB::getReadPreference' => ['array'], 'MongoDB::getSlaveOkay' => ['bool'], 'MongoDB::getWriteConcern' => ['array'], 'MongoDB::lastError' => ['array'], 'MongoDB::listCollections' => ['array'], 'MongoDB::prevError' => ['array'], 'MongoDB::repair' => ['array', 'preserve_cloned_files='=>'bool', 'backup_original_files='=>'bool'], 'MongoDB::resetError' => ['array'], 'MongoDB::selectCollection' => ['MongoCollection', 'name'=>'string'], 'MongoDB::setProfilingLevel' => ['int', 'level'=>'int'], 'MongoDB::setReadPreference' => ['bool', 'read_preference'=>'string', 'tags='=>'array'], 'MongoDB::setSlaveOkay' => ['bool', 'ok='=>'bool'], 'MongoDB::setWriteConcern' => ['bool', 'w'=>'mixed', 'wtimeout='=>'int'], 'MongoDB\BSON\fromJSON' => ['string', 'json' => 'string'], 'MongoDB\BSON\fromPHP' => ['string', 'value' => 'object|array'], 'MongoDB\BSON\toCanonicalExtendedJSON' => ['string', 'bson' => 'string'], 'MongoDB\BSON\toJSON' => ['string', 'bson' => 'string'], 'MongoDB\BSON\toPHP' => ['object|array', 'bson' => 'string', 'typemap=' => '?array'], 'MongoDB\BSON\toRelaxedExtendedJSON' => ['string', 'bson' => 'string'], 'MongoDB\Driver\Monitoring\addSubscriber' => ['void', 'subscriber' => 'MongoDB\Driver\Monitoring\Subscriber'], 'MongoDB\Driver\Monitoring\removeSubscriber' => ['void', 'subscriber' => 'MongoDB\Driver\Monitoring\Subscriber'], 'MongoDB\BSON\Binary::__construct' => ['void', 'data' => 'string', 'type=' => 'int'], 'MongoDB\BSON\Binary::getData' => ['string'], 'MongoDB\BSON\Binary::getType' => ['int'], 'MongoDB\BSON\Binary::__toString' => ['string'], 'MongoDB\BSON\Binary::serialize' => ['string'], 'MongoDB\BSON\Binary::unserialize' => ['void', 'data' => 'string'], 'MongoDB\BSON\Binary::jsonSerialize' => ['mixed'], 'MongoDB\BSON\BinaryInterface::getData' => ['string'], 'MongoDB\BSON\BinaryInterface::getType' => ['int'], 'MongoDB\BSON\BinaryInterface::__toString' => ['string'], 'MongoDB\BSON\DBPointer::__toString' => ['string'], 'MongoDB\BSON\DBPointer::serialize' => ['string'], 'MongoDB\BSON\DBPointer::unserialize' => ['void', 'data' => 'string'], 'MongoDB\BSON\DBPointer::jsonSerialize' => ['mixed'], 'MongoDB\BSON\Decimal128::__construct' => ['void', 'value' => 'string'], 'MongoDB\BSON\Decimal128::__toString' => ['string'], 'MongoDB\BSON\Decimal128::serialize' => ['string'], 'MongoDB\BSON\Decimal128::unserialize' => ['void', 'data' => 'string'], 'MongoDB\BSON\Decimal128::jsonSerialize' => ['mixed'], 'MongoDB\BSON\Decimal128Interface::__toString' => ['string'], 'MongoDB\BSON\Document::fromBSON' => ['MongoDB\BSON\Document', 'bson' => 'string'], 'MongoDB\BSON\Document::fromJSON' => ['MongoDB\BSON\Document', 'json' => 'string'], 'MongoDB\BSON\Document::fromPHP' => ['MongoDB\BSON\Document', 'value' => 'object|array'], 'MongoDB\BSON\Document::get' => ['mixed', 'key' => 'string'], 'MongoDB\BSON\Document::getIterator' => ['MongoDB\BSON\Iterator'], 'MongoDB\BSON\Document::has' => ['bool', 'key' => 'string'], 'MongoDB\BSON\Document::toPHP' => ['object|array', 'typeMap=' => '?array'], 'MongoDB\BSON\Document::toCanonicalExtendedJSON' => ['string'], 'MongoDB\BSON\Document::toRelaxedExtendedJSON' => ['string'], 'MongoDB\BSON\Document::offsetExists' => ['bool', 'offset' => 'mixed'], 'MongoDB\BSON\Document::offsetGet' => ['mixed', 'offset' => 'mixed'], 'MongoDB\BSON\Document::offsetSet' => ['void', 'offset' => 'mixed', 'value' => 'mixed'], 'MongoDB\BSON\Document::offsetUnset' => ['void', 'offset' => 'mixed'], 'MongoDB\BSON\Document::__toString' => ['string'], 'MongoDB\BSON\Document::serialize' => ['string'], 'MongoDB\BSON\Document::unserialize' => ['void', 'data' => 'string'], 'MongoDB\BSON\Int64::__construct' => ['void', 'value' => 'string|int'], 'MongoDB\BSON\Int64::__toString' => ['string'], 'MongoDB\BSON\Int64::serialize' => ['string'], 'MongoDB\BSON\Int64::unserialize' => ['void', 'data' => 'string'], 'MongoDB\BSON\Int64::jsonSerialize' => ['mixed'], 'MongoDB\BSON\Iterator::current' => ['mixed'], 'MongoDB\BSON\Iterator::key' => ['string|int'], 'MongoDB\BSON\Iterator::next' => ['void'], 'MongoDB\BSON\Iterator::rewind' => ['void'], 'MongoDB\BSON\Iterator::valid' => ['bool'], 'MongoDB\BSON\Javascript::__construct' => ['void', 'code' => 'string', 'scope=' => 'object|array|null'], 'MongoDB\BSON\Javascript::getCode' => ['string'], 'MongoDB\BSON\Javascript::getScope' => ['?object'], 'MongoDB\BSON\Javascript::__toString' => ['string'], 'MongoDB\BSON\Javascript::serialize' => ['string'], 'MongoDB\BSON\Javascript::unserialize' => ['void', 'data' => 'string'], 'MongoDB\BSON\Javascript::jsonSerialize' => ['mixed'], 'MongoDB\BSON\JavascriptInterface::getCode' => ['string'], 'MongoDB\BSON\JavascriptInterface::getScope' => ['?object'], 'MongoDB\BSON\JavascriptInterface::__toString' => ['string'], 'MongoDB\BSON\MaxKey::serialize' => ['string'], 'MongoDB\BSON\MaxKey::unserialize' => ['void', 'data' => 'string'], 'MongoDB\BSON\MaxKey::jsonSerialize' => ['mixed'], 'MongoDB\BSON\MinKey::serialize' => ['string'], 'MongoDB\BSON\MinKey::unserialize' => ['void', 'data' => 'string'], 'MongoDB\BSON\MinKey::jsonSerialize' => ['mixed'], 'MongoDB\BSON\ObjectId::__construct' => ['void', 'id=' => '?string'], 'MongoDB\BSON\ObjectId::getTimestamp' => ['int'], 'MongoDB\BSON\ObjectId::__toString' => ['string'], 'MongoDB\BSON\ObjectId::serialize' => ['string'], 'MongoDB\BSON\ObjectId::unserialize' => ['void', 'data' => 'string'], 'MongoDB\BSON\ObjectId::jsonSerialize' => ['mixed'], 'MongoDB\BSON\ObjectIdInterface::getTimestamp' => ['int'], 'MongoDB\BSON\ObjectIdInterface::__toString' => ['string'], 'MongoDB\BSON\PackedArray::fromPHP' => ['MongoDB\BSON\PackedArray', 'value' => 'array'], 'MongoDB\BSON\PackedArray::get' => ['mixed', 'index' => 'int'], 'MongoDB\BSON\PackedArray::getIterator' => ['MongoDB\BSON\Iterator'], 'MongoDB\BSON\PackedArray::has' => ['bool', 'index' => 'int'], 'MongoDB\BSON\PackedArray::toPHP' => ['object|array', 'typeMap=' => '?array'], 'MongoDB\BSON\PackedArray::offsetExists' => ['bool', 'offset' => 'mixed'], 'MongoDB\BSON\PackedArray::offsetGet' => ['mixed', 'offset' => 'mixed'], 'MongoDB\BSON\PackedArray::offsetSet' => ['void', 'offset' => 'mixed', 'value' => 'mixed'], 'MongoDB\BSON\PackedArray::offsetUnset' => ['void', 'offset' => 'mixed'], 'MongoDB\BSON\PackedArray::__toString' => ['string'], 'MongoDB\BSON\PackedArray::serialize' => ['string'], 'MongoDB\BSON\PackedArray::unserialize' => ['void', 'data' => 'string'], 'MongoDB\BSON\Persistable::bsonSerialize' => ['stdClass|MongoDB\BSON\Document|array'], 'MongoDB\BSON\Regex::__construct' => ['void', 'pattern' => 'string', 'flags=' => 'string'], 'MongoDB\BSON\Regex::getPattern' => ['string'], 'MongoDB\BSON\Regex::getFlags' => ['string'], 'MongoDB\BSON\Regex::__toString' => ['string'], 'MongoDB\BSON\Regex::serialize' => ['string'], 'MongoDB\BSON\Regex::unserialize' => ['void', 'data' => 'string'], 'MongoDB\BSON\Regex::jsonSerialize' => ['mixed'], 'MongoDB\BSON\RegexInterface::getPattern' => ['string'], 'MongoDB\BSON\RegexInterface::getFlags' => ['string'], 'MongoDB\BSON\RegexInterface::__toString' => ['string'], 'MongoDB\BSON\Serializable::bsonSerialize' => ['stdClass|MongoDB\BSON\Document|MongoDB\BSON\PackedArray|array'], 'MongoDB\BSON\Symbol::__toString' => ['string'], 'MongoDB\BSON\Symbol::serialize' => ['string'], 'MongoDB\BSON\Symbol::unserialize' => ['void', 'data' => 'string'], 'MongoDB\BSON\Symbol::jsonSerialize' => ['mixed'], 'MongoDB\BSON\Timestamp::__construct' => ['void', 'increment' => 'string|int', 'timestamp' => 'string|int'], 'MongoDB\BSON\Timestamp::getTimestamp' => ['int'], 'MongoDB\BSON\Timestamp::getIncrement' => ['int'], 'MongoDB\BSON\Timestamp::__toString' => ['string'], 'MongoDB\BSON\Timestamp::serialize' => ['string'], 'MongoDB\BSON\Timestamp::unserialize' => ['void', 'data' => 'string'], 'MongoDB\BSON\Timestamp::jsonSerialize' => ['mixed'], 'MongoDB\BSON\TimestampInterface::getTimestamp' => ['int'], 'MongoDB\BSON\TimestampInterface::getIncrement' => ['int'], 'MongoDB\BSON\TimestampInterface::__toString' => ['string'], 'MongoDB\BSON\UTCDateTime::__construct' => ['void', 'milliseconds=' => 'DateTimeInterface|string|int|float|null'], 'MongoDB\BSON\UTCDateTime::toDateTime' => ['DateTime'], 'MongoDB\BSON\UTCDateTime::__toString' => ['string'], 'MongoDB\BSON\UTCDateTime::serialize' => ['string'], 'MongoDB\BSON\UTCDateTime::unserialize' => ['void', 'data' => 'string'], 'MongoDB\BSON\UTCDateTime::jsonSerialize' => ['mixed'], 'MongoDB\BSON\UTCDateTimeInterface::toDateTime' => ['DateTime'], 'MongoDB\BSON\UTCDateTimeInterface::__toString' => ['string'], 'MongoDB\BSON\Undefined::__toString' => ['string'], 'MongoDB\BSON\Undefined::serialize' => ['string'], 'MongoDB\BSON\Undefined::unserialize' => ['void', 'data' => 'string'], 'MongoDB\BSON\Undefined::jsonSerialize' => ['mixed'], 'MongoDB\BSON\Unserializable::bsonUnserialize' => ['void', 'data' => 'array'], 'MongoDB\Driver\BulkWrite::__construct' => ['void', 'options=' => '?array'], 'MongoDB\Driver\BulkWrite::count' => ['int'], 'MongoDB\Driver\BulkWrite::delete' => ['void', 'filter' => 'object|array', 'deleteOptions=' => '?array'], 'MongoDB\Driver\BulkWrite::insert' => ['mixed', 'document' => 'object|array'], 'MongoDB\Driver\BulkWrite::update' => ['void', 'filter' => 'object|array', 'newObj' => 'object|array', 'updateOptions=' => '?array'], 'MongoDB\Driver\ClientEncryption::__construct' => ['void', 'options' => 'array'], 'MongoDB\Driver\ClientEncryption::addKeyAltName' => ['?object', 'keyId' => 'MongoDB\BSON\Binary', 'keyAltName' => 'string'], 'MongoDB\Driver\ClientEncryption::createDataKey' => ['MongoDB\BSON\Binary', 'kmsProvider' => 'string', 'options=' => '?array'], 'MongoDB\Driver\ClientEncryption::decrypt' => ['mixed', 'value' => 'MongoDB\BSON\Binary'], 'MongoDB\Driver\ClientEncryption::deleteKey' => ['object', 'keyId' => 'MongoDB\BSON\Binary'], 'MongoDB\Driver\ClientEncryption::encrypt' => ['MongoDB\BSON\Binary', 'value' => 'mixed', 'options=' => '?array'], 'MongoDB\Driver\ClientEncryption::encryptExpression' => ['object', 'expr' => 'object|array', 'options=' => '?array'], 'MongoDB\Driver\ClientEncryption::getKey' => ['?object', 'keyId' => 'MongoDB\BSON\Binary'], 'MongoDB\Driver\ClientEncryption::getKeyByAltName' => ['?object', 'keyAltName' => 'string'], 'MongoDB\Driver\ClientEncryption::getKeys' => ['MongoDB\Driver\Cursor'], 'MongoDB\Driver\ClientEncryption::removeKeyAltName' => ['?object', 'keyId' => 'MongoDB\BSON\Binary', 'keyAltName' => 'string'], 'MongoDB\Driver\ClientEncryption::rewrapManyDataKey' => ['object', 'filter' => 'object|array', 'options=' => '?array'], 'MongoDB\Driver\Command::__construct' => ['void', 'document' => 'object|array', 'commandOptions=' => '?array'], 'MongoDB\Driver\Cursor::current' => ['object|array|null'], 'MongoDB\Driver\Cursor::getId' => ['MongoDB\Driver\CursorId'], 'MongoDB\Driver\Cursor::getServer' => ['MongoDB\Driver\Server'], 'MongoDB\Driver\Cursor::isDead' => ['bool'], 'MongoDB\Driver\Cursor::key' => ['?int'], 'MongoDB\Driver\Cursor::next' => ['void'], 'MongoDB\Driver\Cursor::rewind' => ['void'], 'MongoDB\Driver\Cursor::setTypeMap' => ['void', 'typemap' => 'array'], 'MongoDB\Driver\Cursor::toArray' => ['array'], 'MongoDB\Driver\Cursor::valid' => ['bool'], 'MongoDB\Driver\CursorId::__toString' => ['string'], 'MongoDB\Driver\CursorId::serialize' => ['string'], 'MongoDB\Driver\CursorId::unserialize' => ['void', 'data' => 'string'], 'MongoDB\Driver\CursorInterface::getId' => ['MongoDB\Driver\CursorId'], 'MongoDB\Driver\CursorInterface::getServer' => ['MongoDB\Driver\Server'], 'MongoDB\Driver\CursorInterface::isDead' => ['bool'], 'MongoDB\Driver\CursorInterface::setTypeMap' => ['void', 'typemap' => 'array'], 'MongoDB\Driver\CursorInterface::toArray' => ['array'], 'MongoDB\Driver\Exception\AuthenticationException::__toString' => ['string'], 'MongoDB\Driver\Exception\BulkWriteException::__toString' => ['string'], 'MongoDB\Driver\Exception\CommandException::getResultDocument' => ['object'], 'MongoDB\Driver\Exception\CommandException::__toString' => ['string'], 'MongoDB\Driver\Exception\ConnectionException::__toString' => ['string'], 'MongoDB\Driver\Exception\ConnectionTimeoutException::__toString' => ['string'], 'MongoDB\Driver\Exception\EncryptionException::__toString' => ['string'], 'MongoDB\Driver\Exception\Exception::__toString' => ['string'], 'MongoDB\Driver\Exception\ExecutionTimeoutException::__toString' => ['string'], 'MongoDB\Driver\Exception\InvalidArgumentException::__toString' => ['string'], 'MongoDB\Driver\Exception\LogicException::__toString' => ['string'], 'MongoDB\Driver\Exception\RuntimeException::hasErrorLabel' => ['bool', 'errorLabel' => 'string'], 'MongoDB\Driver\Exception\RuntimeException::__toString' => ['string'], 'MongoDB\Driver\Exception\SSLConnectionException::__toString' => ['string'], 'MongoDB\Driver\Exception\ServerException::__toString' => ['string'], 'MongoDB\Driver\Exception\UnexpectedValueException::__toString' => ['string'], 'MongoDB\Driver\Exception\WriteException::getWriteResult' => ['MongoDB\Driver\WriteResult'], 'MongoDB\Driver\Exception\WriteException::__toString' => ['string'], 'MongoDB\Driver\Manager::__construct' => ['void', 'uri=' => '?string', 'uriOptions=' => '?array', 'driverOptions=' => '?array'], 'MongoDB\Driver\Manager::addSubscriber' => ['void', 'subscriber' => 'MongoDB\Driver\Monitoring\Subscriber'], 'MongoDB\Driver\Manager::createClientEncryption' => ['MongoDB\Driver\ClientEncryption', 'options' => 'array'], 'MongoDB\Driver\Manager::executeBulkWrite' => ['MongoDB\Driver\WriteResult', 'namespace' => 'string', 'bulk' => 'MongoDB\Driver\BulkWrite', 'options=' => 'MongoDB\Driver\WriteConcern|array|null'], 'MongoDB\Driver\Manager::executeCommand' => ['MongoDB\Driver\Cursor', 'db' => 'string', 'command' => 'MongoDB\Driver\Command', 'options=' => 'MongoDB\Driver\ReadPreference|array|null'], 'MongoDB\Driver\Manager::executeQuery' => ['MongoDB\Driver\Cursor', 'namespace' => 'string', 'query' => 'MongoDB\Driver\Query', 'options=' => 'MongoDB\Driver\ReadPreference|array|null'], 'MongoDB\Driver\Manager::executeReadCommand' => ['MongoDB\Driver\Cursor', 'db' => 'string', 'command' => 'MongoDB\Driver\Command', 'options=' => '?array'], 'MongoDB\Driver\Manager::executeReadWriteCommand' => ['MongoDB\Driver\Cursor', 'db' => 'string', 'command' => 'MongoDB\Driver\Command', 'options=' => '?array'], 'MongoDB\Driver\Manager::executeWriteCommand' => ['MongoDB\Driver\Cursor', 'db' => 'string', 'command' => 'MongoDB\Driver\Command', 'options=' => '?array'], 'MongoDB\Driver\Manager::getEncryptedFieldsMap' => ['object|array|null'], 'MongoDB\Driver\Manager::getReadConcern' => ['MongoDB\Driver\ReadConcern'], 'MongoDB\Driver\Manager::getReadPreference' => ['MongoDB\Driver\ReadPreference'], 'MongoDB\Driver\Manager::getServers' => ['array'], 'MongoDB\Driver\Manager::getWriteConcern' => ['MongoDB\Driver\WriteConcern'], 'MongoDB\Driver\Manager::removeSubscriber' => ['void', 'subscriber' => 'MongoDB\Driver\Monitoring\Subscriber'], 'MongoDB\Driver\Manager::selectServer' => ['MongoDB\Driver\Server', 'readPreference=' => '?MongoDB\Driver\ReadPreference'], 'MongoDB\Driver\Manager::startSession' => ['MongoDB\Driver\Session', 'options=' => '?array'], 'MongoDB\Driver\Monitoring\CommandFailedEvent::getCommandName' => ['string'], 'MongoDB\Driver\Monitoring\CommandFailedEvent::getDurationMicros' => ['int'], 'MongoDB\Driver\Monitoring\CommandFailedEvent::getError' => ['Exception'], 'MongoDB\Driver\Monitoring\CommandFailedEvent::getOperationId' => ['string'], 'MongoDB\Driver\Monitoring\CommandFailedEvent::getReply' => ['object'], 'MongoDB\Driver\Monitoring\CommandFailedEvent::getRequestId' => ['string'], 'MongoDB\Driver\Monitoring\CommandFailedEvent::getServer' => ['MongoDB\Driver\Server'], 'MongoDB\Driver\Monitoring\CommandFailedEvent::getServiceId' => ['?MongoDB\BSON\ObjectId'], 'MongoDB\Driver\Monitoring\CommandFailedEvent::getServerConnectionId' => ['?int'], 'MongoDB\Driver\Monitoring\CommandStartedEvent::getCommand' => ['object'], 'MongoDB\Driver\Monitoring\CommandStartedEvent::getCommandName' => ['string'], 'MongoDB\Driver\Monitoring\CommandStartedEvent::getDatabaseName' => ['string'], 'MongoDB\Driver\Monitoring\CommandStartedEvent::getOperationId' => ['string'], 'MongoDB\Driver\Monitoring\CommandStartedEvent::getRequestId' => ['string'], 'MongoDB\Driver\Monitoring\CommandStartedEvent::getServer' => ['MongoDB\Driver\Server'], 'MongoDB\Driver\Monitoring\CommandStartedEvent::getServiceId' => ['?MongoDB\BSON\ObjectId'], 'MongoDB\Driver\Monitoring\CommandStartedEvent::getServerConnectionId' => ['?int'], 'MongoDB\Driver\Monitoring\CommandSubscriber::commandStarted' => ['void', 'event' => 'MongoDB\Driver\Monitoring\CommandStartedEvent'], 'MongoDB\Driver\Monitoring\CommandSubscriber::commandSucceeded' => ['void', 'event' => 'MongoDB\Driver\Monitoring\CommandSucceededEvent'], 'MongoDB\Driver\Monitoring\CommandSubscriber::commandFailed' => ['void', 'event' => 'MongoDB\Driver\Monitoring\CommandFailedEvent'], 'MongoDB\Driver\Monitoring\CommandSucceededEvent::getCommandName' => ['string'], 'MongoDB\Driver\Monitoring\CommandSucceededEvent::getDurationMicros' => ['int'], 'MongoDB\Driver\Monitoring\CommandSucceededEvent::getOperationId' => ['string'], 'MongoDB\Driver\Monitoring\CommandSucceededEvent::getReply' => ['object'], 'MongoDB\Driver\Monitoring\CommandSucceededEvent::getRequestId' => ['string'], 'MongoDB\Driver\Monitoring\CommandSucceededEvent::getServer' => ['MongoDB\Driver\Server'], 'MongoDB\Driver\Monitoring\CommandSucceededEvent::getServiceId' => ['?MongoDB\BSON\ObjectId'], 'MongoDB\Driver\Monitoring\CommandSucceededEvent::getServerConnectionId' => ['?int'], 'MongoDB\Driver\Monitoring\LogSubscriber::log' => ['void', 'level' => 'int', 'domain' => 'string', 'message' => 'string'], 'MongoDB\Driver\Monitoring\SDAMSubscriber::serverChanged' => ['void', 'event' => 'MongoDB\Driver\Monitoring\ServerChangedEvent'], 'MongoDB\Driver\Monitoring\SDAMSubscriber::serverClosed' => ['void', 'event' => 'MongoDB\Driver\Monitoring\ServerClosedEvent'], 'MongoDB\Driver\Monitoring\SDAMSubscriber::serverOpening' => ['void', 'event' => 'MongoDB\Driver\Monitoring\ServerOpeningEvent'], 'MongoDB\Driver\Monitoring\SDAMSubscriber::serverHeartbeatFailed' => ['void', 'event' => 'MongoDB\Driver\Monitoring\ServerHeartbeatFailedEvent'], 'MongoDB\Driver\Monitoring\SDAMSubscriber::serverHeartbeatStarted' => ['void', 'event' => 'MongoDB\Driver\Monitoring\ServerHeartbeatStartedEvent'], 'MongoDB\Driver\Monitoring\SDAMSubscriber::serverHeartbeatSucceeded' => ['void', 'event' => 'MongoDB\Driver\Monitoring\ServerHeartbeatSucceededEvent'], 'MongoDB\Driver\Monitoring\SDAMSubscriber::topologyChanged' => ['void', 'event' => 'MongoDB\Driver\Monitoring\TopologyChangedEvent'], 'MongoDB\Driver\Monitoring\SDAMSubscriber::topologyClosed' => ['void', 'event' => 'MongoDB\Driver\Monitoring\TopologyClosedEvent'], 'MongoDB\Driver\Monitoring\SDAMSubscriber::topologyOpening' => ['void', 'event' => 'MongoDB\Driver\Monitoring\TopologyOpeningEvent'], 'MongoDB\Driver\Monitoring\ServerChangedEvent::getPort' => ['int'], 'MongoDB\Driver\Monitoring\ServerChangedEvent::getHost' => ['string'], 'MongoDB\Driver\Monitoring\ServerChangedEvent::getNewDescription' => ['MongoDB\Driver\ServerDescription'], 'MongoDB\Driver\Monitoring\ServerChangedEvent::getPreviousDescription' => ['MongoDB\Driver\ServerDescription'], 'MongoDB\Driver\Monitoring\ServerChangedEvent::getTopologyId' => ['MongoDB\BSON\ObjectId'], 'MongoDB\Driver\Monitoring\ServerClosedEvent::getPort' => ['int'], 'MongoDB\Driver\Monitoring\ServerClosedEvent::getHost' => ['string'], 'MongoDB\Driver\Monitoring\ServerClosedEvent::getTopologyId' => ['MongoDB\BSON\ObjectId'], 'MongoDB\Driver\Monitoring\ServerHeartbeatFailedEvent::getDurationMicros' => ['int'], 'MongoDB\Driver\Monitoring\ServerHeartbeatFailedEvent::getError' => ['Exception'], 'MongoDB\Driver\Monitoring\ServerHeartbeatFailedEvent::getPort' => ['int'], 'MongoDB\Driver\Monitoring\ServerHeartbeatFailedEvent::getHost' => ['string'], 'MongoDB\Driver\Monitoring\ServerHeartbeatFailedEvent::isAwaited' => ['bool'], 'MongoDB\Driver\Monitoring\ServerHeartbeatStartedEvent::getPort' => ['int'], 'MongoDB\Driver\Monitoring\ServerHeartbeatStartedEvent::getHost' => ['string'], 'MongoDB\Driver\Monitoring\ServerHeartbeatStartedEvent::isAwaited' => ['bool'], 'MongoDB\Driver\Monitoring\ServerHeartbeatSucceededEvent::getDurationMicros' => ['int'], 'MongoDB\Driver\Monitoring\ServerHeartbeatSucceededEvent::getReply' => ['object'], 'MongoDB\Driver\Monitoring\ServerHeartbeatSucceededEvent::getPort' => ['int'], 'MongoDB\Driver\Monitoring\ServerHeartbeatSucceededEvent::getHost' => ['string'], 'MongoDB\Driver\Monitoring\ServerHeartbeatSucceededEvent::isAwaited' => ['bool'], 'MongoDB\Driver\Monitoring\ServerOpeningEvent::getPort' => ['int'], 'MongoDB\Driver\Monitoring\ServerOpeningEvent::getHost' => ['string'], 'MongoDB\Driver\Monitoring\ServerOpeningEvent::getTopologyId' => ['MongoDB\BSON\ObjectId'], 'MongoDB\Driver\Monitoring\TopologyChangedEvent::getNewDescription' => ['MongoDB\Driver\TopologyDescription'], 'MongoDB\Driver\Monitoring\TopologyChangedEvent::getPreviousDescription' => ['MongoDB\Driver\TopologyDescription'], 'MongoDB\Driver\Monitoring\TopologyChangedEvent::getTopologyId' => ['MongoDB\BSON\ObjectId'], 'MongoDB\Driver\Monitoring\TopologyClosedEvent::getTopologyId' => ['MongoDB\BSON\ObjectId'], 'MongoDB\Driver\Monitoring\TopologyOpeningEvent::getTopologyId' => ['MongoDB\BSON\ObjectId'], 'MongoDB\Driver\Query::__construct' => ['void', 'filter' => 'object|array', 'queryOptions=' => '?array'], 'MongoDB\Driver\ReadConcern::__construct' => ['void', 'level=' => '?string'], 'MongoDB\Driver\ReadConcern::getLevel' => ['?string'], 'MongoDB\Driver\ReadConcern::isDefault' => ['bool'], 'MongoDB\Driver\ReadConcern::bsonSerialize' => ['stdClass'], 'MongoDB\Driver\ReadConcern::serialize' => ['string'], 'MongoDB\Driver\ReadConcern::unserialize' => ['void', 'data' => 'string'], 'MongoDB\Driver\ReadPreference::__construct' => ['void', 'mode' => 'string|int', 'tagSets=' => '?array', 'options=' => '?array'], 'MongoDB\Driver\ReadPreference::getHedge' => ['?object'], 'MongoDB\Driver\ReadPreference::getMaxStalenessSeconds' => ['int'], 'MongoDB\Driver\ReadPreference::getMode' => ['int'], 'MongoDB\Driver\ReadPreference::getModeString' => ['string'], 'MongoDB\Driver\ReadPreference::getTagSets' => ['array'], 'MongoDB\Driver\ReadPreference::bsonSerialize' => ['stdClass'], 'MongoDB\Driver\ReadPreference::serialize' => ['string'], 'MongoDB\Driver\ReadPreference::unserialize' => ['void', 'data' => 'string'], 'MongoDB\Driver\Server::executeBulkWrite' => ['MongoDB\Driver\WriteResult', 'namespace' => 'string', 'bulkWrite' => 'MongoDB\Driver\BulkWrite', 'options=' => 'MongoDB\Driver\WriteConcern|array|null'], 'MongoDB\Driver\Server::executeCommand' => ['MongoDB\Driver\Cursor', 'db' => 'string', 'command' => 'MongoDB\Driver\Command', 'options=' => 'MongoDB\Driver\ReadPreference|array|null'], 'MongoDB\Driver\Server::executeQuery' => ['MongoDB\Driver\Cursor', 'namespace' => 'string', 'query' => 'MongoDB\Driver\Query', 'options=' => 'MongoDB\Driver\ReadPreference|array|null'], 'MongoDB\Driver\Server::executeReadCommand' => ['MongoDB\Driver\Cursor', 'db' => 'string', 'command' => 'MongoDB\Driver\Command', 'options=' => '?array'], 'MongoDB\Driver\Server::executeReadWriteCommand' => ['MongoDB\Driver\Cursor', 'db' => 'string', 'command' => 'MongoDB\Driver\Command', 'options=' => '?array'], 'MongoDB\Driver\Server::executeWriteCommand' => ['MongoDB\Driver\Cursor', 'db' => 'string', 'command' => 'MongoDB\Driver\Command', 'options=' => '?array'], 'MongoDB\Driver\Server::getHost' => ['string'], 'MongoDB\Driver\Server::getInfo' => ['array'], 'MongoDB\Driver\Server::getLatency' => ['?int'], 'MongoDB\Driver\Server::getPort' => ['int'], 'MongoDB\Driver\Server::getServerDescription' => ['MongoDB\Driver\ServerDescription'], 'MongoDB\Driver\Server::getTags' => ['array'], 'MongoDB\Driver\Server::getType' => ['int'], 'MongoDB\Driver\Server::isArbiter' => ['bool'], 'MongoDB\Driver\Server::isHidden' => ['bool'], 'MongoDB\Driver\Server::isPassive' => ['bool'], 'MongoDB\Driver\Server::isPrimary' => ['bool'], 'MongoDB\Driver\Server::isSecondary' => ['bool'], 'MongoDB\Driver\ServerApi::__construct' => ['void', 'version' => 'string', 'strict=' => '?bool', 'deprecationErrors=' => '?bool'], 'MongoDB\Driver\ServerApi::bsonSerialize' => ['stdClass'], 'MongoDB\Driver\ServerApi::serialize' => ['string'], 'MongoDB\Driver\ServerApi::unserialize' => ['void', 'data' => 'string'], 'MongoDB\Driver\ServerDescription::getHelloResponse' => ['array'], 'MongoDB\Driver\ServerDescription::getHost' => ['string'], 'MongoDB\Driver\ServerDescription::getLastUpdateTime' => ['int'], 'MongoDB\Driver\ServerDescription::getPort' => ['int'], 'MongoDB\Driver\ServerDescription::getRoundTripTime' => ['?int'], 'MongoDB\Driver\ServerDescription::getType' => ['string'], 'MongoDB\Driver\Session::abortTransaction' => ['void'], 'MongoDB\Driver\Session::advanceClusterTime' => ['void', 'clusterTime' => 'object|array'], 'MongoDB\Driver\Session::advanceOperationTime' => ['void', 'operationTime' => 'MongoDB\BSON\TimestampInterface'], 'MongoDB\Driver\Session::commitTransaction' => ['void'], 'MongoDB\Driver\Session::endSession' => ['void'], 'MongoDB\Driver\Session::getClusterTime' => ['?object'], 'MongoDB\Driver\Session::getLogicalSessionId' => ['object'], 'MongoDB\Driver\Session::getOperationTime' => ['?MongoDB\BSON\Timestamp'], 'MongoDB\Driver\Session::getServer' => ['?MongoDB\Driver\Server'], 'MongoDB\Driver\Session::getTransactionOptions' => ['?array'], 'MongoDB\Driver\Session::getTransactionState' => ['string'], 'MongoDB\Driver\Session::isDirty' => ['bool'], 'MongoDB\Driver\Session::isInTransaction' => ['bool'], 'MongoDB\Driver\Session::startTransaction' => ['void', 'options=' => '?array'], 'MongoDB\Driver\TopologyDescription::getServers' => ['array'], 'MongoDB\Driver\TopologyDescription::getType' => ['string'], 'MongoDB\Driver\TopologyDescription::hasReadableServer' => ['bool', 'readPreference=' => '?MongoDB\Driver\ReadPreference'], 'MongoDB\Driver\TopologyDescription::hasWritableServer' => ['bool'], 'MongoDB\Driver\WriteConcern::__construct' => ['void', 'w' => 'string|int', 'wtimeout=' => '?int', 'journal=' => '?bool'], 'MongoDB\Driver\WriteConcern::getJournal' => ['?bool'], 'MongoDB\Driver\WriteConcern::getW' => ['string|int|null'], 'MongoDB\Driver\WriteConcern::getWtimeout' => ['int'], 'MongoDB\Driver\WriteConcern::isDefault' => ['bool'], 'MongoDB\Driver\WriteConcern::bsonSerialize' => ['stdClass'], 'MongoDB\Driver\WriteConcern::serialize' => ['string'], 'MongoDB\Driver\WriteConcern::unserialize' => ['void', 'data' => 'string'], 'MongoDB\Driver\WriteConcernError::getCode' => ['int'], 'MongoDB\Driver\WriteConcernError::getInfo' => ['?object'], 'MongoDB\Driver\WriteConcernError::getMessage' => ['string'], 'MongoDB\Driver\WriteError::getCode' => ['int'], 'MongoDB\Driver\WriteError::getIndex' => ['int'], 'MongoDB\Driver\WriteError::getInfo' => ['?object'], 'MongoDB\Driver\WriteError::getMessage' => ['string'], 'MongoDB\Driver\WriteResult::getInsertedCount' => ['?int'], 'MongoDB\Driver\WriteResult::getMatchedCount' => ['?int'], 'MongoDB\Driver\WriteResult::getModifiedCount' => ['?int'], 'MongoDB\Driver\WriteResult::getDeletedCount' => ['?int'], 'MongoDB\Driver\WriteResult::getUpsertedCount' => ['?int'], 'MongoDB\Driver\WriteResult::getServer' => ['MongoDB\Driver\Server'], 'MongoDB\Driver\WriteResult::getUpsertedIds' => ['array'], 'MongoDB\Driver\WriteResult::getWriteConcernError' => ['?MongoDB\Driver\WriteConcernError'], 'MongoDB\Driver\WriteResult::getWriteErrors' => ['array'], 'MongoDB\Driver\WriteResult::getErrorReplies' => ['array'], 'MongoDB\Driver\WriteResult::isAcknowledged' => ['bool'], 'MongoDBRef::create' => ['array', 'collection'=>'string', 'id'=>'mixed', 'database='=>'string'], 'MongoDBRef::get' => ['?array', 'db'=>'MongoDB', 'ref'=>'array'], 'MongoDBRef::isRef' => ['bool', 'ref'=>'mixed'], 'MongoDeleteBatch::__construct' => ['void', 'collection'=>'MongoCollection', 'write_options='=>'array'], 'MongoException::__clone' => ['void'], 'MongoException::__construct' => ['void', 'message='=>'string', 'code='=>'int', 'previous='=>'?Exception|?Throwable'], 'MongoException::__toString' => ['string'], 'MongoException::__wakeup' => ['void'], 'MongoException::getCode' => ['int'], 'MongoException::getFile' => ['string'], 'MongoException::getLine' => ['int'], 'MongoException::getMessage' => ['string'], 'MongoException::getPrevious' => ['Exception|Throwable'], 'MongoException::getTrace' => ['list\',args?:array}>'], 'MongoException::getTraceAsString' => ['string'], 'MongoGridFS::__construct' => ['void', 'db'=>'MongoDB', 'prefix='=>'string', 'chunks='=>'mixed'], 'MongoGridFS::__get' => ['MongoCollection', 'name'=>'string'], 'MongoGridFS::__toString' => ['string'], 'MongoGridFS::aggregate' => ['array', 'pipeline'=>'array', 'op'=>'array', 'pipelineOperators'=>'array'], 'MongoGridFS::aggregateCursor' => ['MongoCommandCursor', 'pipeline'=>'array', 'options'=>'array'], 'MongoGridFS::batchInsert' => ['mixed', 'a'=>'array', 'options='=>'array'], 'MongoGridFS::count' => ['int', 'query='=>'stdClass|array'], 'MongoGridFS::createDBRef' => ['array', 'a'=>'array'], 'MongoGridFS::createIndex' => ['array', 'keys'=>'array', 'options='=>'array'], 'MongoGridFS::delete' => ['bool', 'id'=>'mixed'], 'MongoGridFS::deleteIndex' => ['array', 'keys'=>'array|string'], 'MongoGridFS::deleteIndexes' => ['array'], 'MongoGridFS::distinct' => ['array|bool', 'key'=>'string', 'query='=>'?array'], 'MongoGridFS::drop' => ['array'], 'MongoGridFS::ensureIndex' => ['bool', 'keys'=>'array', 'options='=>'array'], 'MongoGridFS::find' => ['MongoGridFSCursor', 'query='=>'array', 'fields='=>'array'], 'MongoGridFS::findAndModify' => ['array', 'query'=>'array', 'update='=>'?array', 'fields='=>'?array', 'options='=>'?array'], 'MongoGridFS::findOne' => ['?MongoGridFSFile', 'query='=>'mixed', 'fields='=>'mixed'], 'MongoGridFS::get' => ['?MongoGridFSFile', 'id'=>'mixed'], 'MongoGridFS::getDBRef' => ['array', 'ref'=>'array'], 'MongoGridFS::getIndexInfo' => ['array'], 'MongoGridFS::getName' => ['string'], 'MongoGridFS::getReadPreference' => ['array'], 'MongoGridFS::getSlaveOkay' => ['bool'], 'MongoGridFS::group' => ['array', 'keys'=>'mixed', 'initial'=>'array', 'reduce'=>'MongoCode', 'condition='=>'array'], 'MongoGridFS::insert' => ['array|bool', 'a'=>'array|object', 'options='=>'array'], 'MongoGridFS::put' => ['mixed', 'filename'=>'string', 'extra='=>'array'], 'MongoGridFS::remove' => ['bool', 'criteria='=>'array', 'options='=>'array'], 'MongoGridFS::save' => ['array|bool', 'a'=>'array|object', 'options='=>'array'], 'MongoGridFS::setReadPreference' => ['bool', 'read_preference'=>'string', 'tags'=>'array'], 'MongoGridFS::setSlaveOkay' => ['bool', 'ok='=>'bool'], 'MongoGridFS::storeBytes' => ['mixed', 'bytes'=>'string', 'extra='=>'array', 'options='=>'array'], 'MongoGridFS::storeFile' => ['mixed', 'filename'=>'string', 'extra='=>'array', 'options='=>'array'], 'MongoGridFS::storeUpload' => ['mixed', 'name'=>'string', 'filename='=>'string'], 'MongoGridFS::toIndexString' => ['string', 'keys'=>'mixed'], 'MongoGridFS::update' => ['bool', 'criteria'=>'array', 'newobj'=>'array', 'options='=>'array'], 'MongoGridFS::validate' => ['array', 'scan_data='=>'bool'], 'MongoGridFSCursor::__construct' => ['void', 'gridfs'=>'MongoGridFS', 'connection'=>'resource', 'ns'=>'string', 'query'=>'array', 'fields'=>'array'], 'MongoGridFSCursor::addOption' => ['MongoCursor', 'key'=>'string', 'value'=>'mixed'], 'MongoGridFSCursor::awaitData' => ['MongoCursor', 'wait='=>'bool'], 'MongoGridFSCursor::batchSize' => ['MongoCursor', 'batchSize'=>'int'], 'MongoGridFSCursor::count' => ['int', 'all='=>'bool'], 'MongoGridFSCursor::current' => ['MongoGridFSFile'], 'MongoGridFSCursor::dead' => ['bool'], 'MongoGridFSCursor::doQuery' => ['void'], 'MongoGridFSCursor::explain' => ['array'], 'MongoGridFSCursor::fields' => ['MongoCursor', 'f'=>'array'], 'MongoGridFSCursor::getNext' => ['MongoGridFSFile'], 'MongoGridFSCursor::getReadPreference' => ['array'], 'MongoGridFSCursor::hasNext' => ['bool'], 'MongoGridFSCursor::hint' => ['MongoCursor', 'key_pattern'=>'mixed'], 'MongoGridFSCursor::immortal' => ['MongoCursor', 'liveForever='=>'bool'], 'MongoGridFSCursor::info' => ['array'], 'MongoGridFSCursor::key' => ['string'], 'MongoGridFSCursor::limit' => ['MongoCursor', 'num'=>'int'], 'MongoGridFSCursor::maxTimeMS' => ['MongoCursor', 'ms'=>'int'], 'MongoGridFSCursor::next' => ['void'], 'MongoGridFSCursor::partial' => ['MongoCursor', 'okay='=>'bool'], 'MongoGridFSCursor::reset' => ['void'], 'MongoGridFSCursor::rewind' => ['void'], 'MongoGridFSCursor::setFlag' => ['MongoCursor', 'flag'=>'int', 'set='=>'bool'], 'MongoGridFSCursor::setReadPreference' => ['MongoCursor', 'read_preference'=>'string', 'tags'=>'array'], 'MongoGridFSCursor::skip' => ['MongoCursor', 'num'=>'int'], 'MongoGridFSCursor::slaveOkay' => ['MongoCursor', 'okay='=>'bool'], 'MongoGridFSCursor::snapshot' => ['MongoCursor'], 'MongoGridFSCursor::sort' => ['MongoCursor', 'fields'=>'array'], 'MongoGridFSCursor::tailable' => ['MongoCursor', 'tail='=>'bool'], 'MongoGridFSCursor::timeout' => ['MongoCursor', 'ms'=>'int'], 'MongoGridFSCursor::valid' => ['bool'], 'MongoGridfsFile::__construct' => ['void', 'gridfs'=>'MongoGridFS', 'file'=>'array'], 'MongoGridFSFile::getBytes' => ['string'], 'MongoGridFSFile::getFilename' => ['string'], 'MongoGridFSFile::getResource' => ['resource'], 'MongoGridFSFile::getSize' => ['int'], 'MongoGridFSFile::write' => ['int', 'filename='=>'string'], 'MongoId::__construct' => ['void', 'id='=>'string|MongoId'], 'MongoId::__set_state' => ['MongoId', 'props'=>'array'], 'MongoId::__toString' => ['string'], 'MongoId::getHostname' => ['string'], 'MongoId::getInc' => ['int'], 'MongoId::getPID' => ['int'], 'MongoId::getTimestamp' => ['int'], 'MongoId::isValid' => ['bool', 'value'=>'mixed'], 'MongoInsertBatch::__construct' => ['void', 'collection'=>'MongoCollection', 'write_options='=>'array'], 'MongoInt32::__construct' => ['void', 'value'=>'string'], 'MongoInt32::__toString' => ['string'], 'MongoInt64::__construct' => ['void', 'value'=>'string'], 'MongoInt64::__toString' => ['string'], 'MongoLog::getCallback' => ['callable'], 'MongoLog::getLevel' => ['int'], 'MongoLog::getModule' => ['int'], 'MongoLog::setCallback' => ['void', 'log_function'=>'callable'], 'MongoLog::setLevel' => ['void', 'level'=>'int'], 'MongoLog::setModule' => ['void', 'module'=>'int'], 'MongoPool::getSize' => ['int'], 'MongoPool::info' => ['array'], 'MongoPool::setSize' => ['bool', 'size'=>'int'], 'MongoRegex::__construct' => ['void', 'regex'=>'string'], 'MongoRegex::__toString' => ['string'], 'MongoResultException::__clone' => ['void'], 'MongoResultException::__construct' => ['void', 'message='=>'string', 'code='=>'int', 'previous='=>'?Exception|?Throwable'], 'MongoResultException::__toString' => ['string'], 'MongoResultException::__wakeup' => ['void'], 'MongoResultException::getCode' => ['int'], 'MongoResultException::getDocument' => ['array'], 'MongoResultException::getFile' => ['string'], 'MongoResultException::getLine' => ['int'], 'MongoResultException::getMessage' => ['string'], 'MongoResultException::getPrevious' => ['Exception|Throwable'], 'MongoResultException::getTrace' => ['list\',args?:array}>'], 'MongoResultException::getTraceAsString' => ['string'], 'MongoTimestamp::__construct' => ['void', 'second='=>'int', 'inc='=>'int'], 'MongoTimestamp::__toString' => ['string'], 'MongoUpdateBatch::__construct' => ['void', 'collection'=>'MongoCollection', 'write_options='=>'array'], 'MongoUpdateBatch::add' => ['bool', 'item'=>'array'], 'MongoUpdateBatch::execute' => ['array', 'write_options'=>'array'], 'MongoWriteBatch::__construct' => ['void', 'collection'=>'MongoCollection', 'batch_type'=>'string', 'write_options'=>'array'], 'MongoWriteBatch::add' => ['bool', 'item'=>'array'], 'MongoWriteBatch::execute' => ['array', 'write_options'=>'array'], 'MongoWriteConcernException::__clone' => ['void'], 'MongoWriteConcernException::__construct' => ['void', 'message='=>'string', 'code='=>'int', 'previous='=>'?Exception|?Throwable'], 'MongoWriteConcernException::__toString' => ['string'], 'MongoWriteConcernException::__wakeup' => ['void'], 'MongoWriteConcernException::getCode' => ['int'], 'MongoWriteConcernException::getDocument' => ['array'], 'MongoWriteConcernException::getFile' => ['string'], 'MongoWriteConcernException::getLine' => ['int'], 'MongoWriteConcernException::getMessage' => ['string'], 'MongoWriteConcernException::getPrevious' => ['Exception|Throwable'], 'MongoWriteConcernException::getTrace' => ['list\',args?:array}>'], 'MongoWriteConcernException::getTraceAsString' => ['string'], 'monitor_custom_event' => ['void', 'class'=>'string', 'text'=>'string', 'severe='=>'int', 'user_data='=>'mixed'], 'monitor_httperror_event' => ['void', 'error_code'=>'int', 'url'=>'string', 'severe='=>'int'], 'monitor_license_info' => ['array'], 'monitor_pass_error' => ['void', 'errno'=>'int', 'errstr'=>'string', 'errfile'=>'string', 'errline'=>'int'], 'monitor_set_aggregation_hint' => ['void', 'hint'=>'string'], 'move_uploaded_file' => ['bool', 'from'=>'string', 'to'=>'string'], 'mqseries_back' => ['void', 'hconn'=>'resource', 'compcode'=>'resource', 'reason'=>'resource'], 'mqseries_begin' => ['void', 'hconn'=>'resource', 'beginoptions'=>'array', 'compcode'=>'resource', 'reason'=>'resource'], 'mqseries_close' => ['void', 'hconn'=>'resource', 'hobj'=>'resource', 'options'=>'int', 'compcode'=>'resource', 'reason'=>'resource'], 'mqseries_cmit' => ['void', 'hconn'=>'resource', 'compcode'=>'resource', 'reason'=>'resource'], 'mqseries_conn' => ['void', 'qmanagername'=>'string', 'hconn'=>'resource', 'compcode'=>'resource', 'reason'=>'resource'], 'mqseries_connx' => ['void', 'qmanagername'=>'string', 'connoptions'=>'array', 'hconn'=>'resource', 'compcode'=>'resource', 'reason'=>'resource'], 'mqseries_disc' => ['void', 'hconn'=>'resource', 'compcode'=>'resource', 'reason'=>'resource'], 'mqseries_get' => ['void', 'hconn'=>'resource', 'hobj'=>'resource', 'md'=>'array', 'gmo'=>'array', 'bufferlength'=>'int', 'msg'=>'string', 'data_length'=>'int', 'compcode'=>'resource', 'reason'=>'resource'], 'mqseries_inq' => ['void', 'hconn'=>'resource', 'hobj'=>'resource', 'selectorcount'=>'int', 'selectors'=>'array', 'intattrcount'=>'int', 'intattr'=>'resource', 'charattrlength'=>'int', 'charattr'=>'resource', 'compcode'=>'resource', 'reason'=>'resource'], 'mqseries_open' => ['void', 'hconn'=>'resource', 'objdesc'=>'array', 'option'=>'int', 'hobj'=>'resource', 'compcode'=>'resource', 'reason'=>'resource'], 'mqseries_put' => ['void', 'hconn'=>'resource', 'hobj'=>'resource', 'md'=>'array', 'pmo'=>'array', 'message'=>'string', 'compcode'=>'resource', 'reason'=>'resource'], 'mqseries_put1' => ['void', 'hconn'=>'resource', 'objdesc'=>'resource', 'msgdesc'=>'resource', 'pmo'=>'resource', 'buffer'=>'string', 'compcode'=>'resource', 'reason'=>'resource'], 'mqseries_set' => ['void', 'hconn'=>'resource', 'hobj'=>'resource', 'selectorcount'=>'int', 'selectors'=>'array', 'intattrcount'=>'int', 'intattrs'=>'array', 'charattrlength'=>'int', 'charattrs'=>'array', 'compcode'=>'resource', 'reason'=>'resource'], 'mqseries_strerror' => ['string', 'reason'=>'int'], 'ms_GetErrorObj' => ['errorObj'], 'ms_GetVersion' => ['string'], 'ms_GetVersionInt' => ['int'], 'ms_iogetStdoutBufferBytes' => ['int'], 'ms_iogetstdoutbufferstring' => ['void'], 'ms_ioinstallstdinfrombuffer' => ['void'], 'ms_ioinstallstdouttobuffer' => ['void'], 'ms_ioresethandlers' => ['void'], 'ms_iostripstdoutbuffercontentheaders' => ['void'], 'ms_iostripstdoutbuffercontenttype' => ['string'], 'ms_ResetErrorList' => ['void'], 'ms_TokenizeMap' => ['array', 'map_file_name'=>'string'], 'msession_connect' => ['bool', 'host'=>'string', 'port'=>'string'], 'msession_count' => ['int'], 'msession_create' => ['bool', 'session'=>'string', 'classname='=>'string', 'data='=>'string'], 'msession_destroy' => ['bool', 'name'=>'string'], 'msession_disconnect' => ['void'], 'msession_find' => ['array', 'name'=>'string', 'value'=>'string'], 'msession_get' => ['string', 'session'=>'string', 'name'=>'string', 'value'=>'string'], 'msession_get_array' => ['array', 'session'=>'string'], 'msession_get_data' => ['string', 'session'=>'string'], 'msession_inc' => ['string', 'session'=>'string', 'name'=>'string'], 'msession_list' => ['array'], 'msession_listvar' => ['array', 'name'=>'string'], 'msession_lock' => ['int', 'name'=>'string'], 'msession_plugin' => ['string', 'session'=>'string', 'value'=>'string', 'param='=>'string'], 'msession_randstr' => ['string', 'param'=>'int'], 'msession_set' => ['bool', 'session'=>'string', 'name'=>'string', 'value'=>'string'], 'msession_set_array' => ['void', 'session'=>'string', 'tuples'=>'array'], 'msession_set_data' => ['bool', 'session'=>'string', 'value'=>'string'], 'msession_timeout' => ['int', 'session'=>'string', 'param='=>'int'], 'msession_uniq' => ['string', 'param'=>'int', 'classname='=>'string', 'data='=>'string'], 'msession_unlock' => ['int', 'session'=>'string', 'key'=>'int'], 'msg_get_queue' => ['SysvMessageQueue|false', 'key'=>'int', 'permissions='=>'int'], 'msg_queue_exists' => ['bool', 'key'=>'int'], 'msg_receive' => ['bool', 'queue'=>'SysvMessageQueue', 'desired_message_type'=>'int', '&w_received_message_type'=>'int', 'max_message_size'=>'int', '&w_message'=>'mixed', 'unserialize='=>'bool', 'flags='=>'int', '&w_error_code='=>'int'], 'msg_remove_queue' => ['bool', 'queue'=>'SysvMessageQueue'], 'msg_send' => ['bool', 'queue'=>'SysvMessageQueue', 'message_type'=>'int', 'message'=>'mixed', 'serialize='=>'bool', 'blocking='=>'bool', '&w_error_code='=>'int'], 'msg_set_queue' => ['bool', 'queue'=>'SysvMessageQueue', 'data'=>'array'], 'msg_stat_queue' => ['array', 'queue'=>'SysvMessageQueue'], 'msgfmt_create' => ['?MessageFormatter', 'locale'=>'string', 'pattern'=>'string'], 'msgfmt_format' => ['string|false', 'formatter'=>'MessageFormatter', 'values'=>'array'], 'msgfmt_format_message' => ['string|false', 'locale'=>'string', 'pattern'=>'string', 'values'=>'array'], 'msgfmt_get_error_code' => ['int', 'formatter'=>'MessageFormatter'], 'msgfmt_get_error_message' => ['string', 'formatter'=>'MessageFormatter'], 'msgfmt_get_locale' => ['string', 'formatter'=>'MessageFormatter'], 'msgfmt_get_pattern' => ['string', 'formatter'=>'MessageFormatter'], 'msgfmt_parse' => ['array|false', 'formatter'=>'MessageFormatter', 'string'=>'string'], 'msgfmt_parse_message' => ['array|false', 'locale'=>'string', 'pattern'=>'string', 'message'=>'string'], 'msgfmt_set_pattern' => ['bool', 'formatter'=>'MessageFormatter', 'pattern'=>'string'], 'msql_affected_rows' => ['int', 'result'=>'resource'], 'msql_close' => ['bool', 'link_identifier='=>'?resource'], 'msql_connect' => ['resource', 'hostname='=>'string'], 'msql_create_db' => ['bool', 'database_name'=>'string', 'link_identifier='=>'?resource'], 'msql_data_seek' => ['bool', 'result'=>'resource', 'row_number'=>'int'], 'msql_db_query' => ['resource', 'database'=>'string', 'query'=>'string', 'link_identifier='=>'?resource'], 'msql_drop_db' => ['bool', 'database_name'=>'string', 'link_identifier='=>'?resource'], 'msql_error' => ['string'], 'msql_fetch_array' => ['array', 'result'=>'resource', 'result_type='=>'int'], 'msql_fetch_field' => ['object', 'result'=>'resource', 'field_offset='=>'int'], 'msql_fetch_object' => ['object', 'result'=>'resource'], 'msql_fetch_row' => ['array', 'result'=>'resource'], 'msql_field_flags' => ['string', 'result'=>'resource', 'field_offset'=>'int'], 'msql_field_len' => ['int', 'result'=>'resource', 'field_offset'=>'int'], 'msql_field_name' => ['string', 'result'=>'resource', 'field_offset'=>'int'], 'msql_field_seek' => ['bool', 'result'=>'resource', 'field_offset'=>'int'], 'msql_field_table' => ['int', 'result'=>'resource', 'field_offset'=>'int'], 'msql_field_type' => ['string', 'result'=>'resource', 'field_offset'=>'int'], 'msql_free_result' => ['bool', 'result'=>'resource'], 'msql_list_dbs' => ['resource', 'link_identifier='=>'?resource'], 'msql_list_fields' => ['resource', 'database'=>'string', 'tablename'=>'string', 'link_identifier='=>'?resource'], 'msql_list_tables' => ['resource', 'database'=>'string', 'link_identifier='=>'?resource'], 'msql_num_fields' => ['int', 'result'=>'resource'], 'msql_num_rows' => ['int', 'query_identifier'=>'resource'], 'msql_pconnect' => ['resource', 'hostname='=>'string'], 'msql_query' => ['resource', 'query'=>'string', 'link_identifier='=>'?resource'], 'msql_result' => ['string', 'result'=>'resource', 'row'=>'int', 'field='=>'mixed'], 'msql_select_db' => ['bool', 'database_name'=>'string', 'link_identifier='=>'?resource'], 'mt_getrandmax' => ['int<1, max>'], 'mt_rand' => ['int', 'min'=>'int', 'max'=>'int'], 'mt_rand\'1' => ['int'], 'mt_srand' => ['void', 'seed='=>'?int', 'mode='=>'int'], 'MultipleIterator::__construct' => ['void', 'flags='=>'int'], 'MultipleIterator::attachIterator' => ['void', 'iterator'=>'Iterator', 'info='=>'string|int|null'], 'MultipleIterator::containsIterator' => ['bool', 'iterator'=>'Iterator'], 'MultipleIterator::countIterators' => ['int'], 'MultipleIterator::current' => ['array|false'], 'MultipleIterator::detachIterator' => ['void', 'iterator'=>'Iterator'], 'MultipleIterator::getFlags' => ['int'], 'MultipleIterator::key' => ['array'], 'MultipleIterator::next' => ['void'], 'MultipleIterator::rewind' => ['void'], 'MultipleIterator::setFlags' => ['void', 'flags'=>'int'], 'MultipleIterator::valid' => ['bool'], 'Mutex::create' => ['long', 'lock='=>'bool'], 'Mutex::destroy' => ['bool', 'mutex'=>'long'], 'Mutex::lock' => ['bool', 'mutex'=>'long'], 'Mutex::trylock' => ['bool', 'mutex'=>'long'], 'Mutex::unlock' => ['bool', 'mutex'=>'long', 'destroy='=>'bool'], 'mysql_xdevapi\baseresult::getWarnings' => ['array'], 'mysql_xdevapi\baseresult::getWarningsCount' => ['integer'], 'mysql_xdevapi\collection::add' => ['mysql_xdevapi\CollectionAdd', 'document'=>'mixed'], 'mysql_xdevapi\collection::addOrReplaceOne' => ['mysql_xdevapi\Result', 'id'=>'string', 'doc'=>'string'], 'mysql_xdevapi\collection::count' => ['integer'], 'mysql_xdevapi\collection::createIndex' => ['void', 'index_name'=>'string', 'index_desc_json'=>'string'], 'mysql_xdevapi\collection::dropIndex' => ['bool', 'index_name'=>'string'], 'mysql_xdevapi\collection::existsInDatabase' => ['bool'], 'mysql_xdevapi\collection::find' => ['mysql_xdevapi\CollectionFind', 'search_condition='=>'string'], 'mysql_xdevapi\collection::getName' => ['string'], 'mysql_xdevapi\collection::getOne' => ['Document', 'id'=>'string'], 'mysql_xdevapi\collection::getSchema' => ['mysql_xdevapi\schema'], 'mysql_xdevapi\collection::getSession' => ['Session'], 'mysql_xdevapi\collection::modify' => ['mysql_xdevapi\CollectionModify', 'search_condition'=>'string'], 'mysql_xdevapi\collection::remove' => ['mysql_xdevapi\CollectionRemove', 'search_condition'=>'string'], 'mysql_xdevapi\collection::removeOne' => ['mysql_xdevapi\Result', 'id'=>'string'], 'mysql_xdevapi\collection::replaceOne' => ['mysql_xdevapi\Result', 'id'=>'string', 'doc'=>'string'], 'mysql_xdevapi\collectionadd::execute' => ['mysql_xdevapi\Result'], 'mysql_xdevapi\collectionfind::bind' => ['mysql_xdevapi\CollectionFind', 'placeholder_values'=>'array'], 'mysql_xdevapi\collectionfind::execute' => ['mysql_xdevapi\DocResult'], 'mysql_xdevapi\collectionfind::fields' => ['mysql_xdevapi\CollectionFind', 'projection'=>'string'], 'mysql_xdevapi\collectionfind::groupBy' => ['mysql_xdevapi\CollectionFind', 'sort_expr'=>'string'], 'mysql_xdevapi\collectionfind::having' => ['mysql_xdevapi\CollectionFind', 'sort_expr'=>'string'], 'mysql_xdevapi\collectionfind::limit' => ['mysql_xdevapi\CollectionFind', 'rows'=>'integer'], 'mysql_xdevapi\collectionfind::lockExclusive' => ['mysql_xdevapi\CollectionFind', 'lock_waiting_option='=>'integer'], 'mysql_xdevapi\collectionfind::lockShared' => ['mysql_xdevapi\CollectionFind', 'lock_waiting_option='=>'integer'], 'mysql_xdevapi\collectionfind::offset' => ['mysql_xdevapi\CollectionFind', 'position'=>'integer'], 'mysql_xdevapi\collectionfind::sort' => ['mysql_xdevapi\CollectionFind', 'sort_expr'=>'string'], 'mysql_xdevapi\collectionmodify::arrayAppend' => ['mysql_xdevapi\CollectionModify', 'collection_field'=>'string', 'expression_or_literal'=>'string'], 'mysql_xdevapi\collectionmodify::arrayInsert' => ['mysql_xdevapi\CollectionModify', 'collection_field'=>'string', 'expression_or_literal'=>'string'], 'mysql_xdevapi\collectionmodify::bind' => ['mysql_xdevapi\CollectionModify', 'placeholder_values'=>'array'], 'mysql_xdevapi\collectionmodify::execute' => ['mysql_xdevapi\Result'], 'mysql_xdevapi\collectionmodify::limit' => ['mysql_xdevapi\CollectionModify', 'rows'=>'integer'], 'mysql_xdevapi\collectionmodify::patch' => ['mysql_xdevapi\CollectionModify', 'document'=>'string'], 'mysql_xdevapi\collectionmodify::replace' => ['mysql_xdevapi\CollectionModify', 'collection_field'=>'string', 'expression_or_literal'=>'string'], 'mysql_xdevapi\collectionmodify::set' => ['mysql_xdevapi\CollectionModify', 'collection_field'=>'string', 'expression_or_literal'=>'string'], 'mysql_xdevapi\collectionmodify::skip' => ['mysql_xdevapi\CollectionModify', 'position'=>'integer'], 'mysql_xdevapi\collectionmodify::sort' => ['mysql_xdevapi\CollectionModify', 'sort_expr'=>'string'], 'mysql_xdevapi\collectionmodify::unset' => ['mysql_xdevapi\CollectionModify', 'fields'=>'array'], 'mysql_xdevapi\collectionremove::bind' => ['mysql_xdevapi\CollectionRemove', 'placeholder_values'=>'array'], 'mysql_xdevapi\collectionremove::execute' => ['mysql_xdevapi\Result'], 'mysql_xdevapi\collectionremove::limit' => ['mysql_xdevapi\CollectionRemove', 'rows'=>'integer'], 'mysql_xdevapi\collectionremove::sort' => ['mysql_xdevapi\CollectionRemove', 'sort_expr'=>'string'], 'mysql_xdevapi\columnresult::getCharacterSetName' => ['string'], 'mysql_xdevapi\columnresult::getCollationName' => ['string'], 'mysql_xdevapi\columnresult::getColumnLabel' => ['string'], 'mysql_xdevapi\columnresult::getColumnName' => ['string'], 'mysql_xdevapi\columnresult::getFractionalDigits' => ['integer'], 'mysql_xdevapi\columnresult::getLength' => ['integer'], 'mysql_xdevapi\columnresult::getSchemaName' => ['string'], 'mysql_xdevapi\columnresult::getTableLabel' => ['string'], 'mysql_xdevapi\columnresult::getTableName' => ['string'], 'mysql_xdevapi\columnresult::getType' => ['integer'], 'mysql_xdevapi\columnresult::isNumberSigned' => ['integer'], 'mysql_xdevapi\columnresult::isPadded' => ['integer'], 'mysql_xdevapi\crudoperationbindable::bind' => ['mysql_xdevapi\CrudOperationBindable', 'placeholder_values'=>'array'], 'mysql_xdevapi\crudoperationlimitable::limit' => ['mysql_xdevapi\CrudOperationLimitable', 'rows'=>'integer'], 'mysql_xdevapi\crudoperationskippable::skip' => ['mysql_xdevapi\CrudOperationSkippable', 'skip'=>'integer'], 'mysql_xdevapi\crudoperationsortable::sort' => ['mysql_xdevapi\CrudOperationSortable', 'sort_expr'=>'string'], 'mysql_xdevapi\databaseobject::existsInDatabase' => ['bool'], 'mysql_xdevapi\databaseobject::getName' => ['string'], 'mysql_xdevapi\databaseobject::getSession' => ['mysql_xdevapi\Session'], 'mysql_xdevapi\docresult::fetchAll' => ['Array'], 'mysql_xdevapi\docresult::fetchOne' => ['Object'], 'mysql_xdevapi\docresult::getWarnings' => ['Array'], 'mysql_xdevapi\docresult::getWarningsCount' => ['integer'], 'mysql_xdevapi\executable::execute' => ['mysql_xdevapi\Result'], 'mysql_xdevapi\getsession' => ['mysql_xdevapi\Session', 'uri'=>'string'], 'mysql_xdevapi\result::getAutoIncrementValue' => ['int'], 'mysql_xdevapi\result::getGeneratedIds' => ['ArrayOfInt'], 'mysql_xdevapi\result::getWarnings' => ['array'], 'mysql_xdevapi\result::getWarningsCount' => ['integer'], 'mysql_xdevapi\rowresult::fetchAll' => ['array'], 'mysql_xdevapi\rowresult::fetchOne' => ['object'], 'mysql_xdevapi\rowresult::getColumnCount' => ['integer'], 'mysql_xdevapi\rowresult::getColumnNames' => ['array'], 'mysql_xdevapi\rowresult::getColumns' => ['array'], 'mysql_xdevapi\rowresult::getWarnings' => ['array'], 'mysql_xdevapi\rowresult::getWarningsCount' => ['integer'], 'mysql_xdevapi\schema::createCollection' => ['mysql_xdevapi\Collection', 'name'=>'string'], 'mysql_xdevapi\schema::dropCollection' => ['bool', 'collection_name'=>'string'], 'mysql_xdevapi\schema::existsInDatabase' => ['bool'], 'mysql_xdevapi\schema::getCollection' => ['mysql_xdevapi\Collection', 'name'=>'string'], 'mysql_xdevapi\schema::getCollectionAsTable' => ['mysql_xdevapi\Table', 'name'=>'string'], 'mysql_xdevapi\schema::getCollections' => ['array'], 'mysql_xdevapi\schema::getName' => ['string'], 'mysql_xdevapi\schema::getSession' => ['mysql_xdevapi\Session'], 'mysql_xdevapi\schema::getTable' => ['mysql_xdevapi\Table', 'name'=>'string'], 'mysql_xdevapi\schema::getTables' => ['array'], 'mysql_xdevapi\schemaobject::getSchema' => ['mysql_xdevapi\Schema'], 'mysql_xdevapi\session::close' => ['bool'], 'mysql_xdevapi\session::commit' => ['Object'], 'mysql_xdevapi\session::createSchema' => ['mysql_xdevapi\Schema', 'schema_name'=>'string'], 'mysql_xdevapi\session::dropSchema' => ['bool', 'schema_name'=>'string'], 'mysql_xdevapi\session::executeSql' => ['Object', 'statement'=>'string'], 'mysql_xdevapi\session::generateUUID' => ['string'], 'mysql_xdevapi\session::getClientId' => ['integer'], 'mysql_xdevapi\session::getSchema' => ['mysql_xdevapi\Schema', 'schema_name'=>'string'], 'mysql_xdevapi\session::getSchemas' => ['array'], 'mysql_xdevapi\session::getServerVersion' => ['integer'], 'mysql_xdevapi\session::killClient' => ['object', 'client_id'=>'integer'], 'mysql_xdevapi\session::listClients' => ['array'], 'mysql_xdevapi\session::quoteName' => ['string', 'name'=>'string'], 'mysql_xdevapi\session::releaseSavepoint' => ['void', 'name'=>'string'], 'mysql_xdevapi\session::rollback' => ['void'], 'mysql_xdevapi\session::rollbackTo' => ['void', 'name'=>'string'], 'mysql_xdevapi\session::setSavepoint' => ['string', 'name='=>'string'], 'mysql_xdevapi\session::sql' => ['mysql_xdevapi\SqlStatement', 'query'=>'string'], 'mysql_xdevapi\session::startTransaction' => ['void'], 'mysql_xdevapi\sqlstatement::bind' => ['mysql_xdevapi\SqlStatement', 'param'=>'string'], 'mysql_xdevapi\sqlstatement::execute' => ['mysql_xdevapi\Result'], 'mysql_xdevapi\sqlstatement::getNextResult' => ['mysql_xdevapi\Result'], 'mysql_xdevapi\sqlstatement::getResult' => ['mysql_xdevapi\Result'], 'mysql_xdevapi\sqlstatement::hasMoreResults' => ['bool'], 'mysql_xdevapi\sqlstatementresult::fetchAll' => ['array'], 'mysql_xdevapi\sqlstatementresult::fetchOne' => ['object'], 'mysql_xdevapi\sqlstatementresult::getAffectedItemsCount' => ['integer'], 'mysql_xdevapi\sqlstatementresult::getColumnCount' => ['integer'], 'mysql_xdevapi\sqlstatementresult::getColumnNames' => ['array'], 'mysql_xdevapi\sqlstatementresult::getColumns' => ['Array'], 'mysql_xdevapi\sqlstatementresult::getGeneratedIds' => ['array'], 'mysql_xdevapi\sqlstatementresult::getLastInsertId' => ['String'], 'mysql_xdevapi\sqlstatementresult::getWarnings' => ['array'], 'mysql_xdevapi\sqlstatementresult::getWarningsCount' => ['integer'], 'mysql_xdevapi\sqlstatementresult::hasData' => ['bool'], 'mysql_xdevapi\sqlstatementresult::nextResult' => ['mysql_xdevapi\Result'], 'mysql_xdevapi\statement::getNextResult' => ['mysql_xdevapi\Result'], 'mysql_xdevapi\statement::getResult' => ['mysql_xdevapi\Result'], 'mysql_xdevapi\statement::hasMoreResults' => ['bool'], 'mysql_xdevapi\table::count' => ['integer'], 'mysql_xdevapi\table::delete' => ['mysql_xdevapi\TableDelete'], 'mysql_xdevapi\table::existsInDatabase' => ['bool'], 'mysql_xdevapi\table::getName' => ['string'], 'mysql_xdevapi\table::getSchema' => ['mysql_xdevapi\Schema'], 'mysql_xdevapi\table::getSession' => ['mysql_xdevapi\Session'], 'mysql_xdevapi\table::insert' => ['mysql_xdevapi\TableInsert', 'columns'=>'mixed', '...args='=>'mixed'], 'mysql_xdevapi\table::isView' => ['bool'], 'mysql_xdevapi\table::select' => ['mysql_xdevapi\TableSelect', 'columns'=>'mixed', '...args='=>'mixed'], 'mysql_xdevapi\table::update' => ['mysql_xdevapi\TableUpdate'], 'mysql_xdevapi\tabledelete::bind' => ['mysql_xdevapi\TableDelete', 'placeholder_values'=>'array'], 'mysql_xdevapi\tabledelete::execute' => ['mysql_xdevapi\Result'], 'mysql_xdevapi\tabledelete::limit' => ['mysql_xdevapi\TableDelete', 'rows'=>'integer'], 'mysql_xdevapi\tabledelete::offset' => ['mysql_xdevapi\TableDelete', 'position'=>'integer'], 'mysql_xdevapi\tabledelete::orderby' => ['mysql_xdevapi\TableDelete', 'orderby_expr'=>'string'], 'mysql_xdevapi\tabledelete::where' => ['mysql_xdevapi\TableDelete', 'where_expr'=>'string'], 'mysql_xdevapi\tableinsert::execute' => ['mysql_xdevapi\Result'], 'mysql_xdevapi\tableinsert::values' => ['mysql_xdevapi\TableInsert', 'row_values'=>'array'], 'mysql_xdevapi\tableselect::bind' => ['mysql_xdevapi\TableSelect', 'placeholder_values'=>'array'], 'mysql_xdevapi\tableselect::execute' => ['mysql_xdevapi\RowResult'], 'mysql_xdevapi\tableselect::groupBy' => ['mysql_xdevapi\TableSelect', 'sort_expr'=>'mixed'], 'mysql_xdevapi\tableselect::having' => ['mysql_xdevapi\TableSelect', 'sort_expr'=>'string'], 'mysql_xdevapi\tableselect::limit' => ['mysql_xdevapi\TableSelect', 'rows'=>'integer'], 'mysql_xdevapi\tableselect::lockExclusive' => ['mysql_xdevapi\TableSelect', 'lock_waiting_option='=>'integer'], 'mysql_xdevapi\tableselect::lockShared' => ['mysql_xdevapi\TableSelect', 'lock_waiting_option='=>'integer'], 'mysql_xdevapi\tableselect::offset' => ['mysql_xdevapi\TableSelect', 'position'=>'integer'], 'mysql_xdevapi\tableselect::orderby' => ['mysql_xdevapi\TableSelect', 'sort_expr'=>'mixed', '...args='=>'mixed'], 'mysql_xdevapi\tableselect::where' => ['mysql_xdevapi\TableSelect', 'where_expr'=>'string'], 'mysql_xdevapi\tableupdate::bind' => ['mysql_xdevapi\TableUpdate', 'placeholder_values'=>'array'], 'mysql_xdevapi\tableupdate::execute' => ['mysql_xdevapi\TableUpdate'], 'mysql_xdevapi\tableupdate::limit' => ['mysql_xdevapi\TableUpdate', 'rows'=>'integer'], 'mysql_xdevapi\tableupdate::orderby' => ['mysql_xdevapi\TableUpdate', 'orderby_expr'=>'mixed', '...args='=>'mixed'], 'mysql_xdevapi\tableupdate::set' => ['mysql_xdevapi\TableUpdate', 'table_field'=>'string', 'expression_or_literal'=>'string'], 'mysql_xdevapi\tableupdate::where' => ['mysql_xdevapi\TableUpdate', 'where_expr'=>'string'], 'mysqli::__construct' => ['void', 'hostname='=>'string|null', 'username='=>'string|null', 'password='=>'string|null', 'database='=>'string|null', 'port='=>'int|null', 'socket='=>'string|null'], 'mysqli::autocommit' => ['bool', 'enable'=>'bool'], 'mysqli::begin_transaction' => ['bool', 'flags='=>'int', 'name='=>'?string'], 'mysqli::change_user' => ['bool', 'username'=>'string', 'password'=>'string', 'database'=>'?string'], 'mysqli::character_set_name' => ['string'], 'mysqli::close' => ['true'], 'mysqli::commit' => ['bool', 'flags='=>'int', 'name='=>'?string'], 'mysqli::connect' => ['bool', 'hostname='=>'string|null', 'username='=>'string|null', 'password='=>'string|null', 'database='=>'string|null', 'port='=>'int|null', 'socket='=>'string|null'], 'mysqli::debug' => ['true', 'options'=>'string'], 'mysqli::dump_debug_info' => ['bool'], 'mysqli::escape_string' => ['string', 'string'=>'string'], 'mysqli::execute_query' => ['mysqli_result|bool', 'query'=>'non-empty-string', 'params='=>'list|null'], 'mysqli::get_charset' => ['object'], 'mysqli::get_client_info' => ['string'], 'mysqli::get_connection_stats' => ['array'], 'mysqli::get_warnings' => ['mysqli_warning'], 'mysqli::init' => ['false|null'], 'mysqli::kill' => ['bool', 'process_id'=>'int'], 'mysqli::more_results' => ['bool'], 'mysqli::multi_query' => ['bool', 'query'=>'string'], 'mysqli::next_result' => ['bool'], 'mysqli::options' => ['bool', 'option'=>'int', 'value'=>'string|int'], 'mysqli::ping' => ['bool'], 'mysqli::poll' => ['int|false', '&w_read'=>'?array', '&w_error'=>'?array', '&w_reject'=>'array', 'seconds'=>'int', 'microseconds='=>'int'], 'mysqli::prepare' => ['mysqli_stmt|false', 'query'=>'string'], 'mysqli::query' => ['bool|mysqli_result', 'query'=>'string', 'result_mode='=>'int'], 'mysqli::real_connect' => ['bool', 'hostname='=>'?string', 'username='=>'?string', 'password='=>'?string', 'database='=>'?string', 'port='=>'?int', 'socket='=>'?string', 'flags='=>'int'], 'mysqli::real_escape_string' => ['string', 'string'=>'string'], 'mysqli::real_query' => ['bool', 'query'=>'string'], 'mysqli::reap_async_query' => ['mysqli_result|false'], 'mysqli::refresh' => ['bool', 'flags'=>'int'], 'mysqli::release_savepoint' => ['bool', 'name'=>'string'], 'mysqli::rollback' => ['bool', 'flags='=>'int', 'name='=>'?string'], 'mysqli::savepoint' => ['bool', 'name'=>'string'], 'mysqli::select_db' => ['bool', 'database'=>'string'], 'mysqli::set_charset' => ['bool', 'charset'=>'string'], 'mysqli::set_opt' => ['bool', 'option'=>'int', 'value'=>'string|int'], 'mysqli::ssl_set' => ['true', 'key'=>'?string', 'certificate'=>'?string', 'ca_certificate'=>'?string', 'ca_path'=>'?string', 'cipher_algos'=>'?string'], 'mysqli::stat' => ['string|false'], 'mysqli::stmt_init' => ['mysqli_stmt'], 'mysqli::store_result' => ['mysqli_result|false', 'mode='=>'int'], 'mysqli::thread_safe' => ['bool'], 'mysqli::use_result' => ['mysqli_result|false'], 'mysqli_affected_rows' => ['int<-1, max>|numeric-string', 'mysql'=>'mysqli'], 'mysqli_autocommit' => ['bool', 'mysql'=>'mysqli', 'enable'=>'bool'], 'mysqli_begin_transaction' => ['bool', 'mysql'=>'mysqli', 'flags='=>'int', 'name='=>'?string'], 'mysqli_change_user' => ['bool', 'mysql'=>'mysqli', 'username'=>'string', 'password'=>'string', 'database'=>'?string'], 'mysqli_character_set_name' => ['string', 'mysql'=>'mysqli'], 'mysqli_close' => ['true', 'mysql'=>'mysqli'], 'mysqli_commit' => ['bool', 'mysql'=>'mysqli', 'flags='=>'int', 'name='=>'?string'], 'mysqli_connect' => ['mysqli|false', 'hostname='=>'string|null', 'username='=>'string|null', 'password='=>'string|null', 'database='=>'string|null', 'port='=>'int|null', 'socket='=>'string|null'], 'mysqli_connect_errno' => ['int'], 'mysqli_connect_error' => ['?string'], 'mysqli_data_seek' => ['bool', 'result'=>'mysqli_result', 'offset'=>'int'], 'mysqli_debug' => ['true', 'options'=>'string'], 'mysqli_disable_reads_from_master' => ['bool', 'link'=>'mysqli'], 'mysqli_disable_rpl_parse' => ['bool', 'link'=>'mysqli'], 'mysqli_dump_debug_info' => ['bool', 'mysql'=>'mysqli'], 'mysqli_embedded_server_end' => ['void'], 'mysqli_embedded_server_start' => ['bool', 'start'=>'int', 'arguments'=>'array', 'groups'=>'array'], 'mysqli_enable_reads_from_master' => ['bool', 'link'=>'mysqli'], 'mysqli_enable_rpl_parse' => ['bool', 'link'=>'mysqli'], 'mysqli_errno' => ['int', 'mysql'=>'mysqli'], 'mysqli_error' => ['string', 'mysql'=>'mysqli'], 'mysqli_error_list' => ['array', 'mysql'=>'mysqli'], 'mysqli_escape_string' => ['string', 'mysql'=>'mysqli', 'string'=>'string'], 'mysqli_execute' => ['bool', 'statement'=>'mysqli_stmt', 'params='=>'list|null'], 'mysqli_execute_query' => ['mysqli_result|bool', 'mysql'=>'mysqli', 'query'=>'non-empty-string', 'params='=>'list|null'], 'mysqli_fetch_all' => ['list>', 'result'=>'mysqli_result', 'mode='=>'3'], 'mysqli_fetch_all\'1' => ['list>', 'result'=>'mysqli_result', 'mode='=>'1'], 'mysqli_fetch_all\'2' => ['list>', 'result'=>'mysqli_result', 'mode='=>'2'], 'mysqli_fetch_array' => ['array|false|null', 'result'=>'mysqli_result', 'mode='=>'3'], 'mysqli_fetch_array\'1' => ['array|false|null', 'result'=>'mysqli_result', 'mode='=>'1'], 'mysqli_fetch_array\'2' => ['list|false|null', 'result'=>'mysqli_result', 'mode='=>'2'], 'mysqli_fetch_assoc' => ['array|false|null', 'result'=>'mysqli_result'], 'mysqli_fetch_column' => ['null|int|float|string|false', 'result'=>'mysqli_result', 'column='=>'int'], 'mysqli_fetch_field' => ['object{name:string,orgname:string,table:string,orgtable:string,max_length:0,length:int,charsetnr:int,flags:int,type:int,decimals:int,db:string,def:\'\',catalog:\'def\'}|false', 'result'=>'mysqli_result'], 'mysqli_fetch_field_direct' => ['object{name:string,orgname:string,table:string,orgtable:string,max_length:0,length:int,charsetnr:int,flags:int,type:int,decimals:int,db:string,def:\'\',catalog:\'def\'}|false', 'result'=>'mysqli_result', 'index'=>'int'], 'mysqli_fetch_fields' => ['list', 'result'=>'mysqli_result'], 'mysqli_fetch_lengths' => ['array|false', 'result'=>'mysqli_result'], 'mysqli_fetch_object' => ['object|false|null', 'result'=>'mysqli_result', 'class='=>'string', 'constructor_args='=>'array'], 'mysqli_fetch_row' => ['list|false|null', 'result'=>'mysqli_result'], 'mysqli_field_count' => ['int', 'mysql'=>'mysqli'], 'mysqli_field_seek' => ['true', 'result'=>'mysqli_result', 'index'=>'int'], 'mysqli_field_tell' => ['int', 'result'=>'mysqli_result'], 'mysqli_free_result' => ['void', 'result'=>'mysqli_result'], 'mysqli_get_cache_stats' => ['array|false'], 'mysqli_get_charset' => ['?object', 'mysql'=>'mysqli'], 'mysqli_get_client_info' => ['string', 'mysql='=>'?mysqli'], 'mysqli_get_client_stats' => ['array'], 'mysqli_get_client_version' => ['int'], 'mysqli_get_connection_stats' => ['array', 'mysql'=>'mysqli'], 'mysqli_get_host_info' => ['string', 'mysql'=>'mysqli'], 'mysqli_get_links_stats' => ['array'], 'mysqli_get_proto_info' => ['int', 'mysql'=>'mysqli'], 'mysqli_get_server_info' => ['string', 'mysql'=>'mysqli'], 'mysqli_get_server_version' => ['int', 'mysql'=>'mysqli'], 'mysqli_get_warnings' => ['mysqli_warning', 'mysql'=>'mysqli'], 'mysqli_info' => ['?string', 'mysql'=>'mysqli'], 'mysqli_init' => ['mysqli|false'], 'mysqli_insert_id' => ['int|string', 'mysql'=>'mysqli'], 'mysqli_kill' => ['bool', 'mysql'=>'mysqli', 'process_id'=>'int'], 'mysqli_link_construct' => ['object'], 'mysqli_master_query' => ['bool', 'link'=>'mysqli', 'query'=>'string'], 'mysqli_more_results' => ['bool', 'mysql'=>'mysqli'], 'mysqli_multi_query' => ['bool', 'mysql'=>'mysqli', 'query'=>'string'], 'mysqli_next_result' => ['bool', 'mysql'=>'mysqli'], 'mysqli_num_fields' => ['int', 'result'=>'mysqli_result'], 'mysqli_num_rows' => ['int<0, max>|numeric-string', 'result'=>'mysqli_result'], 'mysqli_options' => ['bool', 'mysql'=>'mysqli', 'option'=>'int', 'value'=>'string|int'], 'mysqli_ping' => ['bool', 'mysql'=>'mysqli'], 'mysqli_poll' => ['int|false', '&w_read'=>'?array', '&w_error'=>'?array', '&w_reject'=>'array', 'seconds'=>'int', 'microseconds='=>'int'], 'mysqli_prepare' => ['mysqli_stmt|false', 'mysql'=>'mysqli', 'query'=>'string'], 'mysqli_query' => ['mysqli_result|bool', 'mysql'=>'mysqli', 'query'=>'string', 'result_mode='=>'int'], 'mysqli_real_connect' => ['bool', 'mysql'=>'mysqli', 'hostname='=>'?string', 'username='=>'?string', 'password='=>'?string', 'database='=>'?string', 'port='=>'?int', 'socket='=>'?string', 'flags='=>'int'], 'mysqli_real_escape_string' => ['string', 'mysql'=>'mysqli', 'string'=>'string'], 'mysqli_real_query' => ['bool', 'mysql'=>'mysqli', 'query'=>'string'], 'mysqli_reap_async_query' => ['mysqli_result|false', 'mysql'=>'mysqli'], 'mysqli_refresh' => ['bool', 'mysql'=>'mysqli', 'flags'=>'int'], 'mysqli_release_savepoint' => ['bool', 'mysql'=>'mysqli', 'name'=>'string'], 'mysqli_report' => ['bool', 'flags'=>'int'], 'mysqli_result::__construct' => ['void', 'mysql'=>'mysqli', 'result_mode='=>'int'], 'mysqli_result::close' => ['void'], 'mysqli_result::data_seek' => ['bool', 'offset'=>'int'], 'mysqli_result::fetch_all' => ['list>', 'mode='=>'3'], 'mysqli_result::fetch_all\'1' => ['list>', 'mode='=>'1'], 'mysqli_result::fetch_all\'2' => ['list>', 'mode='=>'2'], 'mysqli_result::fetch_array' => ['array|false|null', 'mode='=>'3'], 'mysqli_result::fetch_array\'1' => ['array|false|null', 'mode='=>'1'], 'mysqli_result::fetch_array\'2' => ['list|false|null', 'mode='=>'2'], 'mysqli_result::fetch_assoc' => ['array|false|null'], 'mysqli_result::fetch_column' => ['null|int|float|string|false', 'column='=>'int'], 'mysqli_result::fetch_field' => ['object{name:string,orgname:string,table:string,orgtable:string,max_length:0,length:int,charsetnr:int,flags:int,type:int,decimals:int,db:string,def:\'\',catalog:\'def\'}|false'], 'mysqli_result::fetch_field_direct' => ['object{name:string,orgname:string,table:string,orgtable:string,max_length:0,length:int,charsetnr:int,flags:int,type:int,decimals:int,db:string,def:\'\',catalog:\'def\'}|false', 'index'=>'int'], 'mysqli_result::fetch_fields' => ['list'], 'mysqli_result::fetch_object' => ['object|false|null', 'class='=>'string', 'constructor_args='=>'array'], 'mysqli_result::fetch_row' => ['list|false|null'], 'mysqli_result::field_seek' => ['true', 'index'=>'int'], 'mysqli_result::free' => ['void'], 'mysqli_result::free_result' => ['void'], 'mysqli_rollback' => ['bool', 'mysql'=>'mysqli', 'flags='=>'int', 'name='=>'?string'], 'mysqli_rpl_parse_enabled' => ['int', 'link'=>'mysqli'], 'mysqli_rpl_probe' => ['bool', 'link'=>'mysqli'], 'mysqli_rpl_query_type' => ['int', 'link'=>'mysqli', 'query'=>'string'], 'mysqli_savepoint' => ['bool', 'mysql'=>'mysqli', 'name'=>'string'], 'mysqli_savepoint_libmysql' => ['bool'], 'mysqli_select_db' => ['bool', 'mysql'=>'mysqli', 'database'=>'string'], 'mysqli_send_query' => ['bool', 'link'=>'mysqli', 'query'=>'string'], 'mysqli_set_charset' => ['bool', 'mysql'=>'mysqli', 'charset'=>'string'], 'mysqli_set_local_infile_default' => ['void', 'link'=>'mysqli'], 'mysqli_set_local_infile_handler' => ['bool', 'link'=>'mysqli', 'read_func'=>'callable'], 'mysqli_set_opt' => ['bool', 'mysql'=>'mysqli', 'option'=>'int', 'value'=>'string|int'], 'mysqli_slave_query' => ['bool', 'link'=>'mysqli', 'query'=>'string'], 'mysqli_sqlstate' => ['string', 'mysql'=>'mysqli'], 'mysqli_ssl_set' => ['true', 'mysql'=>'mysqli', 'key'=>'?string', 'certificate'=>'?string', 'ca_certificate'=>'?string', 'ca_path'=>'?string', 'cipher_algos'=>'?string'], 'mysqli_stat' => ['string|false', 'mysql'=>'mysqli'], 'mysqli_stmt::__construct' => ['void', 'mysql'=>'mysqli', 'query='=>'?string'], 'mysqli_stmt::attr_get' => ['int', 'attribute'=>'int'], 'mysqli_stmt::attr_set' => ['bool', 'attribute'=>'int', 'value'=>'int'], 'mysqli_stmt::bind_param' => ['bool', 'types'=>'string', '&var'=>'mixed', '&...vars='=>'mixed'], 'mysqli_stmt::bind_result' => ['bool', '&w_var1'=>'', '&...w_vars='=>''], 'mysqli_stmt::close' => ['true'], 'mysqli_stmt::data_seek' => ['void', 'offset'=>'int'], 'mysqli_stmt::execute' => ['bool', 'params='=>'list|null'], 'mysqli_stmt::fetch' => ['bool|null'], 'mysqli_stmt::free_result' => ['void'], 'mysqli_stmt::get_result' => ['mysqli_result|false'], 'mysqli_stmt::get_warnings' => ['object'], 'mysqli_stmt::more_results' => ['bool'], 'mysqli_stmt::next_result' => ['bool'], 'mysqli_stmt::num_rows' => ['int<0, max>|numeric-string'], 'mysqli_stmt::prepare' => ['bool', 'query'=>'string'], 'mysqli_stmt::reset' => ['bool'], 'mysqli_stmt::result_metadata' => ['mysqli_result|false'], 'mysqli_stmt::send_long_data' => ['bool', 'param_num'=>'int', 'data'=>'string'], 'mysqli_stmt::store_result' => ['bool'], 'mysqli_stmt_affected_rows' => ['int<-1, max>|numeric-string', 'statement'=>'mysqli_stmt'], 'mysqli_stmt_attr_get' => ['int', 'statement'=>'mysqli_stmt', 'attribute'=>'int'], 'mysqli_stmt_attr_set' => ['bool', 'statement'=>'mysqli_stmt', 'attribute'=>'int', 'value'=>'int'], 'mysqli_stmt_bind_param' => ['bool', 'statement'=>'mysqli_stmt', 'types'=>'string', '&var'=>'mixed', '&...vars='=>'mixed'], 'mysqli_stmt_bind_result' => ['bool', 'statement'=>'mysqli_stmt', '&w_var1'=>'', '&...w_vars='=>''], 'mysqli_stmt_close' => ['true', 'statement'=>'mysqli_stmt'], 'mysqli_stmt_data_seek' => ['void', 'statement'=>'mysqli_stmt', 'offset'=>'int'], 'mysqli_stmt_errno' => ['int', 'statement'=>'mysqli_stmt'], 'mysqli_stmt_error' => ['string', 'statement'=>'mysqli_stmt'], 'mysqli_stmt_error_list' => ['array', 'statement'=>'mysqli_stmt'], 'mysqli_stmt_execute' => ['bool', 'statement'=>'mysqli_stmt', 'params='=>'list|null'], 'mysqli_stmt_fetch' => ['bool|null', 'statement'=>'mysqli_stmt'], 'mysqli_stmt_field_count' => ['int', 'statement'=>'mysqli_stmt'], 'mysqli_stmt_free_result' => ['void', 'statement'=>'mysqli_stmt'], 'mysqli_stmt_get_result' => ['mysqli_result|false', 'statement'=>'mysqli_stmt'], 'mysqli_stmt_get_warnings' => ['object', 'statement'=>'mysqli_stmt'], 'mysqli_stmt_init' => ['mysqli_stmt', 'mysql'=>'mysqli'], 'mysqli_stmt_insert_id' => ['mixed', 'statement'=>'mysqli_stmt'], 'mysqli_stmt_more_results' => ['bool', 'statement'=>'mysqli_stmt'], 'mysqli_stmt_next_result' => ['bool', 'statement'=>'mysqli_stmt'], 'mysqli_stmt_num_rows' => ['int', 'statement'=>'mysqli_stmt'], 'mysqli_stmt_param_count' => ['int', 'statement'=>'mysqli_stmt'], 'mysqli_stmt_prepare' => ['bool', 'statement'=>'mysqli_stmt', 'query'=>'string'], 'mysqli_stmt_reset' => ['bool', 'statement'=>'mysqli_stmt'], 'mysqli_stmt_result_metadata' => ['mysqli_result|false', 'statement'=>'mysqli_stmt'], 'mysqli_stmt_send_long_data' => ['bool', 'statement'=>'mysqli_stmt', 'param_num'=>'int', 'data'=>'string'], 'mysqli_stmt_sqlstate' => ['string', 'statement'=>'mysqli_stmt'], 'mysqli_stmt_store_result' => ['bool', 'statement'=>'mysqli_stmt'], 'mysqli_store_result' => ['mysqli_result|false', 'mysql'=>'mysqli', 'mode='=>'int'], 'mysqli_thread_id' => ['int', 'mysql'=>'mysqli'], 'mysqli_thread_safe' => ['bool'], 'mysqli_use_result' => ['mysqli_result|false', 'mysql'=>'mysqli'], 'mysqli_warning::__construct' => ['void'], 'mysqli_warning::next' => ['bool'], 'mysqli_warning_count' => ['int', 'mysql'=>'mysqli'], 'mysqlnd_memcache_get_config' => ['array', 'connection'=>'mixed'], 'mysqlnd_memcache_set' => ['bool', 'mysql_connection'=>'mixed', 'memcache_connection='=>'Memcached', 'pattern='=>'string', 'callback='=>'callable'], 'mysqlnd_ms_dump_servers' => ['array', 'connection'=>'mixed'], 'mysqlnd_ms_fabric_select_global' => ['array', 'connection'=>'mixed', 'table_name'=>'mixed'], 'mysqlnd_ms_fabric_select_shard' => ['array', 'connection'=>'mixed', 'table_name'=>'mixed', 'shard_key'=>'mixed'], 'mysqlnd_ms_get_last_gtid' => ['string', 'connection'=>'mixed'], 'mysqlnd_ms_get_last_used_connection' => ['array', 'connection'=>'mixed'], 'mysqlnd_ms_get_stats' => ['array'], 'mysqlnd_ms_match_wild' => ['bool', 'table_name'=>'string', 'wildcard'=>'string'], 'mysqlnd_ms_query_is_select' => ['int', 'query'=>'string'], 'mysqlnd_ms_set_qos' => ['bool', 'connection'=>'mixed', 'service_level'=>'int', 'service_level_option='=>'int', 'option_value='=>'mixed'], 'mysqlnd_ms_set_user_pick_server' => ['bool', 'function'=>'string'], 'mysqlnd_ms_xa_begin' => ['int', 'connection'=>'mixed', 'gtrid'=>'string', 'timeout='=>'int'], 'mysqlnd_ms_xa_commit' => ['int', 'connection'=>'mixed', 'gtrid'=>'string'], 'mysqlnd_ms_xa_gc' => ['int', 'connection'=>'mixed', 'gtrid='=>'string', 'ignore_max_retries='=>'bool'], 'mysqlnd_ms_xa_rollback' => ['int', 'connection'=>'mixed', 'gtrid'=>'string'], 'mysqlnd_qc_change_handler' => ['bool', 'handler'=>''], 'mysqlnd_qc_clear_cache' => ['bool'], 'mysqlnd_qc_get_available_handlers' => ['array'], 'mysqlnd_qc_get_cache_info' => ['array'], 'mysqlnd_qc_get_core_stats' => ['array'], 'mysqlnd_qc_get_handler' => ['array'], 'mysqlnd_qc_get_normalized_query_trace_log' => ['array'], 'mysqlnd_qc_get_query_trace_log' => ['array'], 'mysqlnd_qc_set_cache_condition' => ['bool', 'condition_type'=>'int', 'condition'=>'mixed', 'condition_option'=>'mixed'], 'mysqlnd_qc_set_is_select' => ['mixed', 'callback'=>'string'], 'mysqlnd_qc_set_storage_handler' => ['bool', 'handler'=>'string'], 'mysqlnd_qc_set_user_handlers' => ['bool', 'get_hash'=>'string', 'find_query_in_cache'=>'string', 'return_to_cache'=>'string', 'add_query_to_cache_if_not_exists'=>'string', 'query_is_select'=>'string', 'update_query_run_time_stats'=>'string', 'get_stats'=>'string', 'clear_cache'=>'string'], 'mysqlnd_uh_convert_to_mysqlnd' => ['resource', '&rw_mysql_connection'=>'mysqli'], 'mysqlnd_uh_set_connection_proxy' => ['bool', '&rw_connection_proxy'=>'MysqlndUhConnection', '&rw_mysqli_connection='=>'mysqli'], 'mysqlnd_uh_set_statement_proxy' => ['bool', '&rw_statement_proxy'=>'MysqlndUhStatement'], 'MysqlndUhConnection::__construct' => ['void'], 'MysqlndUhConnection::changeUser' => ['bool', 'connection'=>'mysqlnd_connection', 'user'=>'string', 'password'=>'string', 'database'=>'string', 'silent'=>'bool', 'passwd_len'=>'int'], 'MysqlndUhConnection::charsetName' => ['string', 'connection'=>'mysqlnd_connection'], 'MysqlndUhConnection::close' => ['bool', 'connection'=>'mysqlnd_connection', 'close_type'=>'int'], 'MysqlndUhConnection::connect' => ['bool', 'connection'=>'mysqlnd_connection', 'host'=>'string', 'use'=>'string', 'password'=>'string', 'database'=>'string', 'port'=>'int', 'socket'=>'string', 'mysql_flags'=>'int'], 'MysqlndUhConnection::endPSession' => ['bool', 'connection'=>'mysqlnd_connection'], 'MysqlndUhConnection::escapeString' => ['string', 'connection'=>'mysqlnd_connection', 'escape_string'=>'string'], 'MysqlndUhConnection::getAffectedRows' => ['int', 'connection'=>'mysqlnd_connection'], 'MysqlndUhConnection::getErrorNumber' => ['int', 'connection'=>'mysqlnd_connection'], 'MysqlndUhConnection::getErrorString' => ['string', 'connection'=>'mysqlnd_connection'], 'MysqlndUhConnection::getFieldCount' => ['int', 'connection'=>'mysqlnd_connection'], 'MysqlndUhConnection::getHostInformation' => ['string', 'connection'=>'mysqlnd_connection'], 'MysqlndUhConnection::getLastInsertId' => ['int', 'connection'=>'mysqlnd_connection'], 'MysqlndUhConnection::getLastMessage' => ['void', 'connection'=>'mysqlnd_connection'], 'MysqlndUhConnection::getProtocolInformation' => ['string', 'connection'=>'mysqlnd_connection'], 'MysqlndUhConnection::getServerInformation' => ['string', 'connection'=>'mysqlnd_connection'], 'MysqlndUhConnection::getServerStatistics' => ['string', 'connection'=>'mysqlnd_connection'], 'MysqlndUhConnection::getServerVersion' => ['int', 'connection'=>'mysqlnd_connection'], 'MysqlndUhConnection::getSqlstate' => ['string', 'connection'=>'mysqlnd_connection'], 'MysqlndUhConnection::getStatistics' => ['array', 'connection'=>'mysqlnd_connection'], 'MysqlndUhConnection::getThreadId' => ['int', 'connection'=>'mysqlnd_connection'], 'MysqlndUhConnection::getWarningCount' => ['int', 'connection'=>'mysqlnd_connection'], 'MysqlndUhConnection::init' => ['bool', 'connection'=>'mysqlnd_connection'], 'MysqlndUhConnection::killConnection' => ['bool', 'connection'=>'mysqlnd_connection', 'pid'=>'int'], 'MysqlndUhConnection::listFields' => ['array', 'connection'=>'mysqlnd_connection', 'table'=>'string', 'achtung_wild'=>'string'], 'MysqlndUhConnection::listMethod' => ['void', 'connection'=>'mysqlnd_connection', 'query'=>'string', 'achtung_wild'=>'string', 'par1'=>'string'], 'MysqlndUhConnection::moreResults' => ['bool', 'connection'=>'mysqlnd_connection'], 'MysqlndUhConnection::nextResult' => ['bool', 'connection'=>'mysqlnd_connection'], 'MysqlndUhConnection::ping' => ['bool', 'connection'=>'mysqlnd_connection'], 'MysqlndUhConnection::query' => ['bool', 'connection'=>'mysqlnd_connection', 'query'=>'string'], 'MysqlndUhConnection::queryReadResultsetHeader' => ['bool', 'connection'=>'mysqlnd_connection', 'mysqlnd_stmt'=>'mysqlnd_statement'], 'MysqlndUhConnection::reapQuery' => ['bool', 'connection'=>'mysqlnd_connection'], 'MysqlndUhConnection::refreshServer' => ['bool', 'connection'=>'mysqlnd_connection', 'options'=>'int'], 'MysqlndUhConnection::restartPSession' => ['bool', 'connection'=>'mysqlnd_connection'], 'MysqlndUhConnection::selectDb' => ['bool', 'connection'=>'mysqlnd_connection', 'database'=>'string'], 'MysqlndUhConnection::sendClose' => ['bool', 'connection'=>'mysqlnd_connection'], 'MysqlndUhConnection::sendQuery' => ['bool', 'connection'=>'mysqlnd_connection', 'query'=>'string'], 'MysqlndUhConnection::serverDumpDebugInformation' => ['bool', 'connection'=>'mysqlnd_connection'], 'MysqlndUhConnection::setAutocommit' => ['bool', 'connection'=>'mysqlnd_connection', 'mode'=>'int'], 'MysqlndUhConnection::setCharset' => ['bool', 'connection'=>'mysqlnd_connection', 'charset'=>'string'], 'MysqlndUhConnection::setClientOption' => ['bool', 'connection'=>'mysqlnd_connection', 'option'=>'int', 'value'=>'int'], 'MysqlndUhConnection::setServerOption' => ['void', 'connection'=>'mysqlnd_connection', 'option'=>'int'], 'MysqlndUhConnection::shutdownServer' => ['void', 'MYSQLND_UH_RES_MYSQLND_NAME'=>'string', 'level'=>'string'], 'MysqlndUhConnection::simpleCommand' => ['bool', 'connection'=>'mysqlnd_connection', 'command'=>'int', 'arg'=>'string', 'ok_packet'=>'int', 'silent'=>'bool', 'ignore_upsert_status'=>'bool'], 'MysqlndUhConnection::simpleCommandHandleResponse' => ['bool', 'connection'=>'mysqlnd_connection', 'ok_packet'=>'int', 'silent'=>'bool', 'command'=>'int', 'ignore_upsert_status'=>'bool'], 'MysqlndUhConnection::sslSet' => ['bool', 'connection'=>'mysqlnd_connection', 'key'=>'string', 'cert'=>'string', 'ca'=>'string', 'capath'=>'string', 'cipher'=>'string'], 'MysqlndUhConnection::stmtInit' => ['resource', 'connection'=>'mysqlnd_connection'], 'MysqlndUhConnection::storeResult' => ['resource', 'connection'=>'mysqlnd_connection'], 'MysqlndUhConnection::txCommit' => ['bool', 'connection'=>'mysqlnd_connection'], 'MysqlndUhConnection::txRollback' => ['bool', 'connection'=>'mysqlnd_connection'], 'MysqlndUhConnection::useResult' => ['resource', 'connection'=>'mysqlnd_connection'], 'MysqlndUhPreparedStatement::__construct' => ['void'], 'MysqlndUhPreparedStatement::execute' => ['bool', 'statement'=>'mysqlnd_prepared_statement'], 'MysqlndUhPreparedStatement::prepare' => ['bool', 'statement'=>'mysqlnd_prepared_statement', 'query'=>'string'], 'natcasesort' => ['true', '&rw_array'=>'array'], 'natsort' => ['true', '&rw_array'=>'array'], 'net_get_interfaces' => ['array>|false'], 'newrelic_add_custom_parameter' => ['bool', 'key'=>'string', 'value'=>'bool|float|int|string'], 'newrelic_add_custom_tracer' => ['bool', 'function_name'=>'string'], 'newrelic_background_job' => ['void', 'flag='=>'bool'], 'newrelic_capture_params' => ['void', 'enable='=>'bool'], 'newrelic_custom_metric' => ['bool', 'metric_name'=>'string', 'value'=>'float'], 'newrelic_disable_autorum' => ['true'], 'newrelic_end_of_transaction' => ['void'], 'newrelic_end_transaction' => ['bool', 'ignore='=>'bool'], 'newrelic_get_browser_timing_footer' => ['string', 'include_tags='=>'bool'], 'newrelic_get_browser_timing_header' => ['string', 'include_tags='=>'bool'], 'newrelic_ignore_apdex' => ['void'], 'newrelic_ignore_transaction' => ['void'], 'newrelic_name_transaction' => ['bool', 'name'=>'string'], 'newrelic_notice_error' => ['void', 'message'=>'string', 'exception='=>'Exception|Throwable'], 'newrelic_notice_error\'1' => ['void', 'unused_1'=>'string', 'message'=>'string', 'unused_2'=>'string', 'unused_3'=>'int', 'unused_4='=>''], 'newrelic_record_custom_event' => ['void', 'name'=>'string', 'attributes'=>'array'], 'newrelic_record_datastore_segment' => ['mixed', 'func'=>'callable', 'parameters'=>'array'], 'newrelic_set_appname' => ['bool', 'name'=>'string', 'license='=>'string', 'xmit='=>'bool'], 'newrelic_set_user_attributes' => ['bool', 'user'=>'string', 'account'=>'string', 'product'=>'string'], 'newrelic_start_transaction' => ['bool', 'appname'=>'string', 'license='=>'string'], 'next' => ['mixed', '&r_array'=>'array'], 'ngettext' => ['string', 'singular'=>'string', 'plural'=>'string', 'count'=>'int'], 'nl2br' => ['string', 'string'=>'string', 'use_xhtml='=>'bool'], 'nl_langinfo' => ['string|false', 'item'=>'int'], 'NoRewindIterator::__construct' => ['void', 'iterator'=>'Iterator'], 'NoRewindIterator::current' => ['mixed'], 'NoRewindIterator::getInnerIterator' => ['Iterator'], 'NoRewindIterator::key' => ['mixed'], 'NoRewindIterator::next' => ['void'], 'NoRewindIterator::rewind' => ['void'], 'NoRewindIterator::valid' => ['bool'], 'Normalizer::getRawDecomposition' => ['?string', 'string'=>'string', 'form='=>'int'], 'Normalizer::isNormalized' => ['bool', 'string'=>'string', 'form='=>'int'], 'Normalizer::normalize' => ['string|false', 'string'=>'string', 'form='=>'int'], 'normalizer_get_raw_decomposition' => ['string|null', 'string'=>'string', 'form='=>'int'], 'normalizer_is_normalized' => ['bool', 'string'=>'string', 'form='=>'int'], 'normalizer_normalize' => ['string|false', 'string'=>'string', 'form='=>'int'], 'notes_body' => ['array', 'server'=>'string', 'mailbox'=>'string', 'msg_number'=>'int'], 'notes_copy_db' => ['bool', 'from_database_name'=>'string', 'to_database_name'=>'string'], 'notes_create_db' => ['bool', 'database_name'=>'string'], 'notes_create_note' => ['bool', 'database_name'=>'string', 'form_name'=>'string'], 'notes_drop_db' => ['bool', 'database_name'=>'string'], 'notes_find_note' => ['int', 'database_name'=>'string', 'name'=>'string', 'type='=>'string'], 'notes_header_info' => ['object', 'server'=>'string', 'mailbox'=>'string', 'msg_number'=>'int'], 'notes_list_msgs' => ['bool', 'db'=>'string'], 'notes_mark_read' => ['bool', 'database_name'=>'string', 'user_name'=>'string', 'note_id'=>'string'], 'notes_mark_unread' => ['bool', 'database_name'=>'string', 'user_name'=>'string', 'note_id'=>'string'], 'notes_nav_create' => ['bool', 'database_name'=>'string', 'name'=>'string'], 'notes_search' => ['array', 'database_name'=>'string', 'keywords'=>'string'], 'notes_unread' => ['array', 'database_name'=>'string', 'user_name'=>'string'], 'notes_version' => ['float', 'database_name'=>'string'], 'nsapi_request_headers' => ['array'], 'nsapi_response_headers' => ['array'], 'nsapi_virtual' => ['bool', 'uri'=>'string'], 'nthmac' => ['string', 'clent'=>'string', 'data'=>'string'], 'number_format' => ['string', 'num'=>'float', 'decimals='=>'int', 'decimal_separator='=>'?string', 'thousands_separator='=>'?string'], 'NumberFormatter::__construct' => ['void', 'locale'=>'string', 'style'=>'int', 'pattern='=>'?string'], 'NumberFormatter::create' => ['NumberFormatter|null', 'locale'=>'string', 'style'=>'int', 'pattern='=>'?string'], 'NumberFormatter::format' => ['string|false', 'num'=>'', 'type='=>'int'], 'NumberFormatter::formatCurrency' => ['string|false', 'amount'=>'float', 'currency'=>'string'], 'NumberFormatter::getAttribute' => ['int|float|false', 'attribute'=>'int'], 'NumberFormatter::getErrorCode' => ['int'], 'NumberFormatter::getErrorMessage' => ['string'], 'NumberFormatter::getLocale' => ['string', 'type='=>'int'], 'NumberFormatter::getPattern' => ['string|false'], 'NumberFormatter::getSymbol' => ['string|false', 'symbol'=>'int'], 'NumberFormatter::getTextAttribute' => ['string|false', 'attribute'=>'int'], 'NumberFormatter::parse' => ['int|float|false', 'string'=>'string', 'type='=>'int', '&rw_offset='=>'int'], 'NumberFormatter::parseCurrency' => ['float|false', 'string'=>'string', '&w_currency'=>'string', '&rw_offset='=>'int'], 'NumberFormatter::setAttribute' => ['bool', 'attribute'=>'int', 'value'=>'int|float'], 'NumberFormatter::setPattern' => ['bool', 'pattern'=>'string'], 'NumberFormatter::setSymbol' => ['bool', 'symbol'=>'int', 'value'=>'string'], 'NumberFormatter::setTextAttribute' => ['bool', 'attribute'=>'int', 'value'=>'string'], 'numfmt_create' => ['NumberFormatter|null', 'locale'=>'string', 'style'=>'int', 'pattern='=>'?string'], 'numfmt_format' => ['string|false', 'formatter'=>'NumberFormatter', 'num'=>'int|float', 'type='=>'int'], 'numfmt_format_currency' => ['string|false', 'formatter'=>'NumberFormatter', 'amount'=>'float', 'currency'=>'string'], 'numfmt_get_attribute' => ['float|int|false', 'formatter'=>'NumberFormatter', 'attribute'=>'int'], 'numfmt_get_error_code' => ['int', 'formatter'=>'NumberFormatter'], 'numfmt_get_error_message' => ['string', 'formatter'=>'NumberFormatter'], 'numfmt_get_locale' => ['string', 'formatter'=>'NumberFormatter', 'type='=>'int'], 'numfmt_get_pattern' => ['string|false', 'formatter'=>'NumberFormatter'], 'numfmt_get_symbol' => ['string|false', 'formatter'=>'NumberFormatter', 'symbol'=>'int'], 'numfmt_get_text_attribute' => ['string|false', 'formatter'=>'NumberFormatter', 'attribute'=>'int'], 'numfmt_parse' => ['float|int|false', 'formatter'=>'NumberFormatter', 'string'=>'string', 'type='=>'int', '&rw_offset='=>'int'], 'numfmt_parse_currency' => ['float|false', 'formatter'=>'NumberFormatter', 'string'=>'string', '&w_currency'=>'string', '&rw_offset='=>'int'], 'numfmt_set_attribute' => ['bool', 'formatter'=>'NumberFormatter', 'attribute'=>'int', 'value'=>'float|int'], 'numfmt_set_pattern' => ['bool', 'formatter'=>'NumberFormatter', 'pattern'=>'string'], 'numfmt_set_symbol' => ['bool', 'formatter'=>'NumberFormatter', 'symbol'=>'int', 'value'=>'string'], 'numfmt_set_text_attribute' => ['bool', 'formatter'=>'NumberFormatter', 'attribute'=>'int', 'value'=>'string'], 'OAuth::__construct' => ['void', 'consumer_key'=>'string', 'consumer_secret'=>'string', 'signature_method='=>'string', 'auth_type='=>'int'], 'OAuth::disableDebug' => ['bool'], 'OAuth::disableRedirects' => ['bool'], 'OAuth::disableSSLChecks' => ['bool'], 'OAuth::enableDebug' => ['bool'], 'OAuth::enableRedirects' => ['bool'], 'OAuth::enableSSLChecks' => ['bool'], 'OAuth::fetch' => ['mixed', 'protected_resource_url'=>'string', 'extra_parameters='=>'array', 'http_method='=>'string', 'http_headers='=>'array'], 'OAuth::generateSignature' => ['string', 'http_method'=>'string', 'url'=>'string', 'extra_parameters='=>'mixed'], 'OAuth::getAccessToken' => ['array|false', 'access_token_url'=>'string', 'auth_session_handle='=>'string', 'verifier_token='=>'string', 'http_method='=>'string'], 'OAuth::getCAPath' => ['array'], 'OAuth::getLastResponse' => ['string'], 'OAuth::getLastResponseHeaders' => ['string|false'], 'OAuth::getLastResponseInfo' => ['array'], 'OAuth::getRequestHeader' => ['string|false', 'http_method'=>'string', 'url'=>'string', 'extra_parameters='=>'mixed'], 'OAuth::getRequestToken' => ['array|false', 'request_token_url'=>'string', 'callback_url='=>'string', 'http_method='=>'string'], 'OAuth::setAuthType' => ['bool', 'auth_type'=>'int'], 'OAuth::setCAPath' => ['mixed', 'ca_path='=>'string', 'ca_info='=>'string'], 'OAuth::setNonce' => ['mixed', 'nonce'=>'string'], 'OAuth::setRequestEngine' => ['void', 'reqengine'=>'int'], 'OAuth::setRSACertificate' => ['mixed', 'cert'=>'string'], 'OAuth::setSSLChecks' => ['bool', 'sslcheck'=>'int'], 'OAuth::setTimeout' => ['void', 'timeout'=>'int'], 'OAuth::setTimestamp' => ['mixed', 'timestamp'=>'string'], 'OAuth::setToken' => ['bool', 'token'=>'string', 'token_secret'=>'string'], 'OAuth::setVersion' => ['bool', 'version'=>'string'], 'oauth_get_sbs' => ['string', 'http_method'=>'string', 'uri'=>'string', 'parameters'=>'array'], 'oauth_urlencode' => ['string', 'uri'=>'string'], 'OAuthProvider::__construct' => ['void', 'params_array='=>'array'], 'OAuthProvider::addRequiredParameter' => ['bool', 'req_params'=>'string'], 'OAuthProvider::callconsumerHandler' => ['void'], 'OAuthProvider::callTimestampNonceHandler' => ['void'], 'OAuthProvider::calltokenHandler' => ['void'], 'OAuthProvider::checkOAuthRequest' => ['void', 'uri='=>'string', 'method='=>'string'], 'OAuthProvider::consumerHandler' => ['void', 'callback_function'=>'callable'], 'OAuthProvider::generateToken' => ['string', 'size'=>'int', 'strong='=>'bool'], 'OAuthProvider::is2LeggedEndpoint' => ['void', 'params_array'=>'mixed'], 'OAuthProvider::isRequestTokenEndpoint' => ['void', 'will_issue_request_token'=>'bool'], 'OAuthProvider::removeRequiredParameter' => ['bool', 'req_params'=>'string'], 'OAuthProvider::reportProblem' => ['string', 'oauthexception'=>'string', 'send_headers='=>'bool'], 'OAuthProvider::setParam' => ['bool', 'param_key'=>'string', 'param_val='=>'mixed'], 'OAuthProvider::setRequestTokenPath' => ['bool', 'path'=>'string'], 'OAuthProvider::timestampNonceHandler' => ['void', 'callback_function'=>'callable'], 'OAuthProvider::tokenHandler' => ['void', 'callback_function'=>'callable'], 'ob_clean' => ['bool'], 'ob_deflatehandler' => ['string', 'data'=>'string', 'mode'=>'int'], 'ob_end_clean' => ['bool'], 'ob_end_flush' => ['bool'], 'ob_etaghandler' => ['string', 'data'=>'string', 'mode'=>'int'], 'ob_flush' => ['bool'], 'ob_get_clean' => ['string|false'], 'ob_get_contents' => ['string|false'], 'ob_get_flush' => ['string|false'], 'ob_get_length' => ['int|false'], 'ob_get_level' => ['int'], 'ob_get_status' => ['array', 'full_status='=>'bool'], 'ob_gzhandler' => ['string|false', 'data'=>'string', 'flags'=>'int'], 'ob_iconv_handler' => ['string', 'contents'=>'string', 'status'=>'int'], 'ob_implicit_flush' => ['void', 'enable='=>'bool'], 'ob_inflatehandler' => ['string', 'data'=>'string', 'mode'=>'int'], 'ob_list_handlers' => ['list'], 'ob_start' => ['bool', 'callback='=>'string|array|?callable', 'chunk_size='=>'int', 'flags='=>'int'], 'ob_tidyhandler' => ['string', 'input'=>'string', 'mode='=>'int'], 'oci_bind_array_by_name' => ['bool', 'statement'=>'resource', 'param'=>'string', '&rw_var'=>'array', 'max_array_length'=>'int', 'max_item_length='=>'int', 'type='=>'int'], 'oci_bind_by_name' => ['bool', 'statement'=>'resource', 'param'=>'string', '&rw_var'=>'mixed', 'max_length='=>'int', 'type='=>'int'], 'oci_cancel' => ['bool', 'statement'=>'resource'], 'oci_client_version' => ['string'], 'oci_close' => ['bool', 'connection'=>'resource'], 'OCICollection::append' => ['bool', 'value'=>'mixed'], 'OCICollection::assign' => ['bool', 'from'=>'OCI_Collection'], 'OCICollection::assignElem' => ['bool', 'index'=>'int', 'value'=>'mixed'], 'OCICollection::free' => ['bool'], 'OCICollection::getElem' => ['mixed', 'index'=>'int'], 'OCICollection::max' => ['int|false'], 'OCICollection::size' => ['int|false'], 'OCICollection::trim' => ['bool', 'num'=>'int'], 'oci_collection_append' => ['bool', 'collection'=>'string'], 'oci_collection_assign' => ['bool', 'to'=>'object'], 'oci_collection_element_assign' => ['bool', 'collection'=>'int', 'index'=>'string'], 'oci_collection_element_get' => ['string', 'collection'=>'int'], 'oci_collection_max' => ['int'], 'oci_collection_size' => ['int'], 'oci_collection_trim' => ['bool', 'collection'=>'int'], 'oci_commit' => ['bool', 'connection'=>'resource'], 'oci_connect' => ['resource|false', 'username'=>'string', 'password'=>'string', 'connection_string='=>'string', 'encoding='=>'string', 'session_mode='=>'int'], 'oci_define_by_name' => ['bool', 'statement'=>'resource', 'column'=>'string', '&w_var'=>'mixed', 'type='=>'int'], 'oci_error' => ['array|false', 'connection_or_statement='=>'resource'], 'oci_execute' => ['bool', 'statement'=>'resource', 'mode='=>'int'], 'oci_fetch' => ['bool', 'statement'=>'resource'], 'oci_fetch_all' => ['int|false', 'statement'=>'resource', '&w_output'=>'array', 'offset='=>'int', 'limit='=>'int', 'flags='=>'int'], 'oci_fetch_array' => ['array|false', 'statement'=>'resource', 'mode='=>'int'], 'oci_fetch_assoc' => ['array|false', 'statement'=>'resource'], 'oci_fetch_object' => ['object|false', 'statement'=>'resource'], 'oci_fetch_row' => ['array|false', 'statement'=>'resource'], 'oci_field_is_null' => ['bool', 'statement'=>'resource', 'column'=>'mixed'], 'oci_field_name' => ['string|false', 'statement'=>'resource', 'column'=>'mixed'], 'oci_field_precision' => ['int|false', 'statement'=>'resource', 'column'=>'mixed'], 'oci_field_scale' => ['int|false', 'statement'=>'resource', 'column'=>'mixed'], 'oci_field_size' => ['int|false', 'statement'=>'resource', 'column'=>'mixed'], 'oci_field_type' => ['mixed|false', 'statement'=>'resource', 'column'=>'mixed'], 'oci_field_type_raw' => ['int|false', 'statement'=>'resource', 'column'=>'mixed'], 'oci_free_collection' => ['bool'], 'oci_free_cursor' => ['bool', 'statement'=>'resource'], 'oci_free_descriptor' => ['bool'], 'oci_free_statement' => ['bool', 'statement'=>'resource'], 'oci_get_implicit' => ['bool', 'stmt'=>''], 'oci_get_implicit_resultset' => ['resource|false', 'statement'=>'resource'], 'oci_internal_debug' => ['void', 'onoff'=>'bool'], 'OCILob::append' => ['bool', 'lob_from'=>'OCILob'], 'OCILob::close' => ['bool'], 'OCILob::eof' => ['bool'], 'OCILob::erase' => ['int|false', 'offset='=>'int', 'length='=>'int'], 'OCILob::export' => ['bool', 'filename'=>'string', 'start='=>'int', 'length='=>'int'], 'OCILob::flush' => ['bool', 'flag='=>'int'], 'OCILob::free' => ['bool'], 'OCILob::getbuffering' => ['bool'], 'OCILob::import' => ['bool', 'filename'=>'string'], 'OCILob::load' => ['string|false'], 'OCILob::read' => ['string|false', 'length'=>'int'], 'OCILob::rewind' => ['bool'], 'OCILob::save' => ['bool', 'data'=>'string', 'offset='=>'int'], 'OCILob::savefile' => ['bool', 'filename'=>''], 'OCILob::seek' => ['bool', 'offset'=>'int', 'whence='=>'int'], 'OCILob::setbuffering' => ['bool', 'on_off'=>'bool'], 'OCILob::size' => ['int|false'], 'OCILob::tell' => ['int|false'], 'OCILob::truncate' => ['bool', 'length='=>'int'], 'OCILob::write' => ['int|false', 'data'=>'string', 'length='=>'int'], 'OCILob::writeTemporary' => ['bool', 'data'=>'string', 'lob_type='=>'int'], 'OCILob::writetofile' => ['bool', 'filename'=>'', 'start'=>'', 'length'=>''], 'oci_lob_append' => ['bool', 'to'=>'object'], 'oci_lob_close' => ['bool'], 'oci_lob_copy' => ['bool', 'to'=>'OCILob', 'from'=>'OCILob', 'length='=>'int'], 'oci_lob_eof' => ['bool'], 'oci_lob_erase' => ['int', 'lob'=>'int', 'offset'=>'int'], 'oci_lob_export' => ['bool', 'lob'=>'string', 'filename'=>'int', 'offset'=>'int'], 'oci_lob_flush' => ['bool', 'lob'=>'int'], 'oci_lob_import' => ['bool', 'lob'=>'string'], 'oci_lob_is_equal' => ['bool', 'lob1'=>'OCILob', 'lob2'=>'OCILob'], 'oci_lob_load' => ['string'], 'oci_lob_read' => ['string', 'lob'=>'int'], 'oci_lob_rewind' => ['bool'], 'oci_lob_save' => ['bool', 'lob'=>'string', 'data'=>'int'], 'oci_lob_seek' => ['bool', 'lob'=>'int', 'offset'=>'int'], 'oci_lob_size' => ['int'], 'oci_lob_tell' => ['int'], 'oci_lob_truncate' => ['bool', 'lob'=>'int'], 'oci_lob_write' => ['int', 'lob'=>'string', 'data'=>'int'], 'oci_lob_write_temporary' => ['bool', 'value'=>'string', 'lob_type'=>'int'], 'oci_new_collection' => ['OCICollection|false', 'connection'=>'resource', 'type_name'=>'string', 'schema='=>'string'], 'oci_new_connect' => ['resource|false', 'username'=>'string', 'password'=>'string', 'connection_string='=>'string', 'encoding='=>'string', 'session_mode='=>'int'], 'oci_new_cursor' => ['resource|false', 'connection'=>'resource'], 'oci_new_descriptor' => ['OCILob|false', 'connection'=>'resource', 'type='=>'int'], 'oci_num_fields' => ['int|false', 'statement'=>'resource'], 'oci_num_rows' => ['int|false', 'statement'=>'resource'], 'oci_parse' => ['resource|false', 'connection'=>'resource', 'sql'=>'string'], 'oci_password_change' => ['bool', 'connection'=>'resource', 'username'=>'string', 'old_password'=>'string', 'new_password'=>'string'], 'oci_pconnect' => ['resource|false', 'username'=>'string', 'password'=>'string', 'connection_string='=>'string', 'encoding='=>'string', 'session_mode='=>'int'], 'oci_register_taf_callback' => ['bool', 'connection'=>'resource', 'callback='=>'callable'], 'oci_result' => ['mixed|false', 'statement'=>'resource', 'column'=>'mixed'], 'oci_rollback' => ['bool', 'connection'=>'resource'], 'oci_server_version' => ['string|false', 'connection'=>'resource'], 'oci_set_action' => ['bool', 'connection'=>'resource', 'action'=>'string'], 'oci_set_call_timeout' => ['bool', 'connection'=>'resource', 'timeout'=>'int'], 'oci_set_client_identifier' => ['bool', 'connection'=>'resource', 'client_id'=>'string'], 'oci_set_client_info' => ['bool', 'connection'=>'resource', 'client_info'=>'string'], 'oci_set_db_operation' => ['bool', 'connection'=>'resource', 'action'=>'string'], 'oci_set_edition' => ['bool', 'edition'=>'string'], 'oci_set_module_name' => ['bool', 'connection'=>'resource', 'name'=>'string'], 'oci_set_prefetch' => ['bool', 'statement'=>'resource', 'rows'=>'int'], 'oci_statement_type' => ['string|false', 'statement'=>'resource'], 'oci_unregister_taf_callback' => ['bool', 'connection'=>'resource'], 'ocifetchinto' => ['int|bool', 'statement'=>'resource', '&w_result'=>'array', 'mode='=>'int'], 'ocigetbufferinglob' => ['bool'], 'ocisetbufferinglob' => ['bool', 'lob'=>'bool'], 'octdec' => ['int|float', 'octal_string'=>'string'], 'odbc_autocommit' => ['int|bool', 'odbc'=>'resource', 'enable='=>'bool'], 'odbc_binmode' => ['bool', 'statement'=>'resource', 'mode'=>'int'], 'odbc_close' => ['void', 'odbc'=>'resource'], 'odbc_close_all' => ['void'], 'odbc_columnprivileges' => ['resource|false', 'odbc'=>'resource', 'catalog'=>'?string', 'schema'=>'string', 'table'=>'string', 'column'=>'string'], 'odbc_columns' => ['resource|false', 'odbc'=>'resource', 'catalog='=>'?string', 'schema='=>'?string', 'table='=>'?string', 'column='=>'?string'], 'odbc_commit' => ['bool', 'odbc'=>'resource'], 'odbc_connect' => ['resource|false', 'dsn'=>'string', 'user'=>'string', 'password'=>'string', 'cursor_option='=>'int'], 'odbc_cursor' => ['string', 'statement'=>'resource'], 'odbc_data_source' => ['array|false', 'odbc'=>'resource', 'fetch_type'=>'int'], 'odbc_do' => ['resource', 'odbc'=>'resource', 'query'=>'string'], 'odbc_error' => ['string', 'odbc='=>'resource'], 'odbc_errormsg' => ['string', 'odbc='=>'resource'], 'odbc_exec' => ['resource', 'odbc'=>'resource', 'query'=>'string'], 'odbc_execute' => ['bool', 'statement'=>'resource', 'params='=>'array'], 'odbc_fetch_array' => ['array|false', 'statement'=>'resource', 'row='=>'int'], 'odbc_fetch_into' => ['int', 'statement'=>'resource', '&w_array'=>'array', 'row='=>'int'], 'odbc_fetch_object' => ['stdClass|false', 'statement'=>'resource', 'row='=>'int'], 'odbc_fetch_row' => ['bool', 'statement'=>'resource', 'row='=>'?int'], 'odbc_field_len' => ['int|false', 'statement'=>'resource', 'field'=>'int'], 'odbc_field_name' => ['string|false', 'statement'=>'resource', 'field'=>'int'], 'odbc_field_num' => ['int|false', 'statement'=>'resource', 'field'=>'string'], 'odbc_field_precision' => ['int', 'statement'=>'resource', 'field'=>'int'], 'odbc_field_scale' => ['int|false', 'statement'=>'resource', 'field'=>'int'], 'odbc_field_type' => ['string|false', 'statement'=>'resource', 'field'=>'int'], 'odbc_foreignkeys' => ['resource|false', 'odbc'=>'resource', 'pk_catalog'=>'?string', 'pk_schema'=>'string', 'pk_table'=>'string', 'fk_catalog'=>'string', 'fk_schema'=>'string', 'fk_table'=>'string'], 'odbc_free_result' => ['bool', 'statement'=>'resource'], 'odbc_gettypeinfo' => ['resource', 'odbc'=>'resource', 'data_type='=>'int'], 'odbc_longreadlen' => ['bool', 'statement'=>'resource', 'length'=>'int'], 'odbc_next_result' => ['bool', 'statement'=>'resource'], 'odbc_num_fields' => ['int', 'statement'=>'resource'], 'odbc_num_rows' => ['int', 'statement'=>'resource'], 'odbc_pconnect' => ['resource|false', 'dsn'=>'string', 'user'=>'string', 'password'=>'string', 'cursor_option='=>'int'], 'odbc_prepare' => ['resource|false', 'odbc'=>'resource', 'query'=>'string'], 'odbc_primarykeys' => ['resource|false', 'odbc'=>'resource', 'catalog'=>'?string', 'schema'=>'string', 'table'=>'string'], 'odbc_procedurecolumns' => ['resource|false', 'odbc'=>'resource', 'catalog='=>'?string', 'schema='=>'?string', 'procedure='=>'?string', 'column='=>'?string'], 'odbc_procedures' => ['resource|false', 'odbc'=>'resource', 'catalog='=>'?string', 'schema='=>'?string', 'procedure='=>'?string'], 'odbc_result' => ['string|bool|null', 'statement'=>'resource', 'field'=>'string|int'], 'odbc_result_all' => ['int|false', 'statement'=>'resource', 'format='=>'string'], 'odbc_rollback' => ['bool', 'odbc'=>'resource'], 'odbc_setoption' => ['bool', 'odbc'=>'resource', 'which'=>'int', 'option'=>'int', 'value'=>'int'], 'odbc_specialcolumns' => ['resource|false', 'odbc'=>'resource', 'type'=>'int', 'catalog'=>'?string', 'schema'=>'string', 'table'=>'string', 'scope'=>'int', 'nullable'=>'int'], 'odbc_statistics' => ['resource|false', 'odbc'=>'resource', 'catalog'=>'?string', 'schema'=>'string', 'table'=>'string', 'unique'=>'int', 'accuracy'=>'int'], 'odbc_tableprivileges' => ['resource|false', 'odbc'=>'resource', 'catalog'=>'?string', 'schema'=>'string', 'table'=>'string'], 'odbc_tables' => ['resource|false', 'odbc'=>'resource', 'catalog='=>'?string', 'schema='=>'?string', 'table='=>'?string', 'types='=>'?string'], 'opcache_compile_file' => ['bool', 'filename'=>'string'], 'opcache_get_configuration' => ['array'], 'opcache_get_status' => ['array|false', 'include_scripts='=>'bool'], 'opcache_invalidate' => ['bool', 'filename'=>'string', 'force='=>'bool'], 'opcache_is_script_cached' => ['bool', 'filename'=>'string'], 'opcache_reset' => ['bool'], 'openal_buffer_create' => ['resource'], 'openal_buffer_data' => ['bool', 'buffer'=>'resource', 'format'=>'int', 'data'=>'string', 'freq'=>'int'], 'openal_buffer_destroy' => ['bool', 'buffer'=>'resource'], 'openal_buffer_get' => ['int', 'buffer'=>'resource', 'property'=>'int'], 'openal_buffer_loadwav' => ['bool', 'buffer'=>'resource', 'wavfile'=>'string'], 'openal_context_create' => ['resource', 'device'=>'resource'], 'openal_context_current' => ['bool', 'context'=>'resource'], 'openal_context_destroy' => ['bool', 'context'=>'resource'], 'openal_context_process' => ['bool', 'context'=>'resource'], 'openal_context_suspend' => ['bool', 'context'=>'resource'], 'openal_device_close' => ['bool', 'device'=>'resource'], 'openal_device_open' => ['resource|false', 'device_desc='=>'string'], 'openal_listener_get' => ['mixed', 'property'=>'int'], 'openal_listener_set' => ['bool', 'property'=>'int', 'setting'=>'mixed'], 'openal_source_create' => ['resource'], 'openal_source_destroy' => ['bool', 'source'=>'resource'], 'openal_source_get' => ['mixed', 'source'=>'resource', 'property'=>'int'], 'openal_source_pause' => ['bool', 'source'=>'resource'], 'openal_source_play' => ['bool', 'source'=>'resource'], 'openal_source_rewind' => ['bool', 'source'=>'resource'], 'openal_source_set' => ['bool', 'source'=>'resource', 'property'=>'int', 'setting'=>'mixed'], 'openal_source_stop' => ['bool', 'source'=>'resource'], 'openal_stream' => ['resource', 'source'=>'resource', 'format'=>'int', 'rate'=>'int'], 'opendir' => ['resource|false', 'directory'=>'string', 'context='=>'resource'], 'openlog' => ['true', 'prefix'=>'string', 'flags'=>'int', 'facility'=>'int'], 'openssl_cipher_iv_length' => ['int|false', 'cipher_algo'=>'string'], 'openssl_cipher_key_length' => ['positive-int|false', 'cipher_algo'=>'non-empty-string'], 'openssl_csr_export' => ['bool', 'csr'=>'OpenSSLCertificateSigningRequest|string', '&w_output'=>'string', 'no_text='=>'bool'], 'openssl_csr_export_to_file' => ['bool', 'csr'=>'OpenSSLCertificateSigningRequest|string', 'output_filename'=>'string', 'no_text='=>'bool'], 'openssl_csr_get_public_key' => ['OpenSSLAsymmetricKey|false', 'csr'=>'OpenSSLCertificateSigningRequest|string', 'short_names='=>'bool'], 'openssl_csr_get_subject' => ['array|false', 'csr'=>'OpenSSLCertificateSigningRequest|string', 'short_names='=>'bool'], 'openssl_csr_new' => ['OpenSSLCertificateSigningRequest|false', 'distinguished_names'=>'array', '&w_private_key'=>'OpenSSLAsymmetricKey', 'options='=>'array|null', 'extra_attributes='=>'array|null'], 'openssl_csr_sign' => ['OpenSSLCertificate|false', 'csr'=>'OpenSSLCertificateSigningRequest|string', 'ca_certificate'=>'OpenSSLCertificate|string|null', 'private_key'=>'OpenSSLAsymmetricKey|OpenSSLCertificate|array{OpenSSLAsymmetricKey|OpenSSLCertificate|string, string}|string', 'days'=>'int', 'options='=>'array|null', 'serial='=>'int'], 'openssl_decrypt' => ['string|false', 'data'=>'string', 'cipher_algo'=>'string', 'passphrase'=>'string', 'options='=>'int', 'iv='=>'string', 'tag='=>'?string', 'aad='=>'string'], 'openssl_dh_compute_key' => ['string|false', 'public_key'=>'string', 'private_key'=>'OpenSSLAsymmetricKey'], 'openssl_digest' => ['string|false', 'data'=>'string', 'digest_algo'=>'string', 'binary='=>'bool'], 'openssl_encrypt' => ['string|false', 'data'=>'string', 'cipher_algo'=>'string', 'passphrase'=>'string', 'options='=>'int', 'iv='=>'string', '&w_tag='=>'string', 'aad='=>'string', 'tag_length='=>'int'], 'openssl_error_string' => ['string|false'], 'openssl_free_key' => ['void', 'key'=>'OpenSSLAsymmetricKey'], 'openssl_get_cert_locations' => ['array'], 'openssl_get_cipher_methods' => ['array', 'aliases='=>'bool'], 'openssl_get_curve_names' => ['list'], 'openssl_get_md_methods' => ['array', 'aliases='=>'bool'], 'openssl_get_privatekey' => ['OpenSSLAsymmetricKey|false', 'private_key'=>'OpenSSLAsymmetricKey|OpenSSLCertificate|array{OpenSSLAsymmetricKey|OpenSSLCertificate|string, string}|string', 'passphrase='=>'?string'], 'openssl_get_publickey' => ['OpenSSLAsymmetricKey|false', 'public_key'=>'OpenSSLAsymmetricKey|OpenSSLCertificate|array{OpenSSLAsymmetricKey|OpenSSLCertificate|string, string}|string'], 'openssl_open' => ['bool', 'data'=>'string', '&w_output'=>'string', 'encrypted_key'=>'string', 'private_key'=>'OpenSSLAsymmetricKey|OpenSSLCertificate|array{OpenSSLAsymmetricKey|OpenSSLCertificate|string, string}|string', 'cipher_algo'=>'string', 'iv='=>'string|null'], 'openssl_pbkdf2' => ['string|false', 'password'=>'string', 'salt'=>'string', 'key_length'=>'int', 'iterations'=>'int', 'digest_algo='=>'string'], 'openssl_pkcs12_export' => ['bool', 'certificate'=>'OpenSSLCertificate|string', '&w_output'=>'string', 'private_key'=>'OpenSSLAsymmetricKey|OpenSSLCertificate|array{OpenSSLAsymmetricKey|OpenSSLCertificate|string, string}|string', 'passphrase'=>'string', 'options='=>'array'], 'openssl_pkcs12_export_to_file' => ['bool', 'certificate'=>'OpenSSLCertificate|string', 'output_filename'=>'string', 'private_key'=>'OpenSSLAsymmetricKey|OpenSSLCertificate|array{OpenSSLAsymmetricKey|OpenSSLCertificate|string, string}|string', 'passphrase'=>'string', 'options='=>'array'], 'openssl_pkcs12_read' => ['bool', 'pkcs12'=>'string', '&w_certificates'=>'array', 'passphrase'=>'string'], 'openssl_pkcs7_decrypt' => ['bool', 'input_filename'=>'string', 'output_filename'=>'string', 'certificate'=>'OpenSSLCertificate|string', 'private_key='=>'OpenSSLAsymmetricKey|OpenSSLCertificate|array{OpenSSLAsymmetricKey|OpenSSLCertificate|string, string}|string|null'], 'openssl_pkcs7_encrypt' => ['bool', 'input_filename'=>'string', 'output_filename'=>'string', 'certificate'=>'OpenSSLCertificate|list|string', 'headers'=>'array|null', 'flags='=>'int', 'cipher_algo='=>'int'], 'openssl_pkcs7_read' => ['bool', 'data'=>'string', '&w_certificates'=>'array'], 'openssl_pkcs7_sign' => ['bool', 'input_filename'=>'string', 'output_filename'=>'string', 'certificate'=>'OpenSSLCertificate|string', 'private_key'=>'OpenSSLAsymmetricKey|OpenSSLCertificate|array{OpenSSLAsymmetricKey|OpenSSLCertificate|string, string}|string', 'headers'=>'array|null', 'flags='=>'int', 'untrusted_certificates_filename='=>'string|null'], 'openssl_pkcs7_verify' => ['bool|int', 'input_filename'=>'string', 'flags'=>'int', 'signers_certificates_filename='=>'?string', 'ca_info='=>'array', 'untrusted_certificates_filename='=>'?string', 'content='=>'?string', 'output_filename='=>'?string'], 'openssl_pkey_derive' => ['string|false', 'public_key'=>'OpenSSLAsymmetricKey|OpenSSLCertificate|array{OpenSSLAsymmetricKey|OpenSSLCertificate|string, string}|string', 'private_key'=>'OpenSSLAsymmetricKey|OpenSSLCertificate|array{OpenSSLAsymmetricKey|OpenSSLCertificate|string, string}|string', 'key_length='=>'int'], 'openssl_pkey_export' => ['bool', 'key'=>'OpenSSLAsymmetricKey|OpenSSLCertificate|array{OpenSSLAsymmetricKey|OpenSSLCertificate|string, string}|string', '&w_output'=>'string', 'passphrase='=>'string|null', 'options='=>'array|null'], 'openssl_pkey_export_to_file' => ['bool', 'key'=>'OpenSSLAsymmetricKey|OpenSSLCertificate|array{OpenSSLAsymmetricKey|OpenSSLCertificate|string, string}|string', 'output_filename'=>'string', 'passphrase='=>'string|null', 'options='=>'array|null'], 'openssl_pkey_free' => ['void', 'key'=>'OpenSSLAsymmetricKey'], 'openssl_pkey_get_details' => ['array|false', 'key'=>'OpenSSLAsymmetricKey'], 'openssl_pkey_get_private' => ['OpenSSLAsymmetricKey|false', 'private_key'=>'OpenSSLAsymmetricKey|OpenSSLCertificate|array|string', 'passphrase='=>'?string'], 'openssl_pkey_get_public' => ['OpenSSLAsymmetricKey|false', 'public_key'=>'OpenSSLAsymmetricKey|OpenSSLCertificate|array{OpenSSLAsymmetricKey|OpenSSLCertificate|string, string}|string'], 'openssl_pkey_new' => ['OpenSSLAsymmetricKey|false', 'options='=>'array|null'], 'openssl_private_decrypt' => ['bool', 'data'=>'string', '&w_decrypted_data'=>'string', 'private_key'=>'OpenSSLAsymmetricKey|OpenSSLCertificate|array{OpenSSLAsymmetricKey|OpenSSLCertificate|string, string}|string', 'padding='=>'int'], 'openssl_private_encrypt' => ['bool', 'data'=>'string', '&w_encrypted_data'=>'string', 'private_key'=>'OpenSSLAsymmetricKey|OpenSSLCertificate|array{OpenSSLAsymmetricKey|OpenSSLCertificate|string, string}|string', 'padding='=>'int'], 'openssl_public_decrypt' => ['bool', 'data'=>'string', '&w_decrypted_data'=>'string', 'public_key'=>'OpenSSLAsymmetricKey|OpenSSLCertificate|array{OpenSSLAsymmetricKey|OpenSSLCertificate|string, string}|string', 'padding='=>'int'], 'openssl_public_encrypt' => ['bool', 'data'=>'string', '&w_encrypted_data'=>'string', 'public_key'=>'OpenSSLAsymmetricKey|OpenSSLCertificate|array{OpenSSLAsymmetricKey|OpenSSLCertificate|string, string}|string', 'padding='=>'int'], 'openssl_random_pseudo_bytes' => ['string', 'length'=>'int', '&w_strong_result='=>'bool'], 'openssl_seal' => ['int|false', 'data'=>'string', '&w_sealed_data'=>'string', '&w_encrypted_keys'=>'array', 'public_key'=>'list', 'cipher_algo'=>'string', '&rw_iv='=>'string'], 'openssl_sign' => ['bool', 'data'=>'string', '&w_signature'=>'string', 'private_key'=>'OpenSSLAsymmetricKey|OpenSSLCertificate|array{OpenSSLAsymmetricKey|OpenSSLCertificate|string, string}|string', 'algorithm='=>'int|string'], 'openssl_spki_export' => ['string|false', 'spki'=>'string'], 'openssl_spki_export_challenge' => ['string|false', 'spki'=>'string'], 'openssl_spki_new' => ['string|false', 'private_key'=>'OpenSSLAsymmetricKey', 'challenge'=>'string', 'digest_algo='=>'int'], 'openssl_spki_verify' => ['bool', 'spki'=>'string'], 'openssl_verify' => ['-1|0|1|false', 'data'=>'string', 'signature'=>'string', 'public_key'=>'OpenSSLAsymmetricKey|OpenSSLCertificate|array{OpenSSLAsymmetricKey|OpenSSLCertificate|string, string}|string', 'algorithm='=>'int|string'], 'openssl_x509_check_private_key' => ['bool', 'certificate'=>'OpenSSLCertificate|string', 'private_key'=>'OpenSSLAsymmetricKey|OpenSSLCertificate|array{OpenSSLAsymmetricKey|OpenSSLCertificate|string, string}|string'], 'openssl_x509_checkpurpose' => ['bool|int', 'certificate'=>'OpenSSLCertificate|string', 'purpose'=>'int', 'ca_info='=>'array', 'untrusted_certificates_file='=>'string|null'], 'openssl_x509_export' => ['bool', 'certificate'=>'OpenSSLCertificate|string', '&w_output'=>'string', 'no_text='=>'bool'], 'openssl_x509_export_to_file' => ['bool', 'certificate'=>'OpenSSLCertificate|string', 'output_filename'=>'string', 'no_text='=>'bool'], 'openssl_x509_fingerprint' => ['string|false', 'certificate'=>'OpenSSLCertificate|string', 'digest_algo='=>'string', 'binary='=>'bool'], 'openssl_x509_free' => ['void', 'certificate'=>'OpenSSLCertificate'], 'openssl_x509_parse' => ['array|false', 'certificate'=>'OpenSSLCertificate|string', 'short_names='=>'bool'], 'openssl_x509_read' => ['OpenSSLCertificate|false', 'certificate'=>'OpenSSLCertificate|string'], 'openssl_x509_verify' => ['int', 'certificate'=>'string|OpenSSLCertificate', 'public_key'=>'string|OpenSSLCertificate|OpenSSLAsymmetricKey|array'], 'ord' => ['int<0,255>', 'character'=>'string'], 'OuterIterator::current' => ['mixed'], 'OuterIterator::getInnerIterator' => ['Iterator'], 'OuterIterator::key' => ['int|string'], 'OuterIterator::next' => ['void'], 'OuterIterator::rewind' => ['void'], 'OuterIterator::valid' => ['bool'], 'OutOfBoundsException::__construct' => ['void', 'message='=>'string', 'code='=>'int', 'previous='=>'?Throwable'], 'OutOfBoundsException::__toString' => ['string'], 'OutOfBoundsException::getCode' => ['int'], 'OutOfBoundsException::getFile' => ['string'], 'OutOfBoundsException::getLine' => ['int'], 'OutOfBoundsException::getMessage' => ['string'], 'OutOfBoundsException::getPrevious' => ['?Throwable'], 'OutOfBoundsException::getTrace' => ['list\',args?:array}>'], 'OutOfBoundsException::getTraceAsString' => ['string'], 'OutOfRangeException::__construct' => ['void', 'message='=>'string', 'code='=>'int', 'previous='=>'?Throwable'], 'OutOfRangeException::__toString' => ['string'], 'OutOfRangeException::getCode' => ['int'], 'OutOfRangeException::getFile' => ['string'], 'OutOfRangeException::getLine' => ['int'], 'OutOfRangeException::getMessage' => ['string'], 'OutOfRangeException::getPrevious' => ['?Throwable'], 'OutOfRangeException::getTrace' => ['list\',args?:array}>'], 'OutOfRangeException::getTraceAsString' => ['string'], 'output_add_rewrite_var' => ['bool', 'name'=>'string', 'value'=>'string'], 'output_cache_disable' => ['void'], 'output_cache_disable_compression' => ['void'], 'output_cache_exists' => ['bool', 'key'=>'string', 'lifetime'=>'int'], 'output_cache_fetch' => ['string', 'key'=>'string', 'function'=>'', 'lifetime'=>'int'], 'output_cache_get' => ['mixed|false', 'key'=>'string', 'lifetime'=>'int'], 'output_cache_output' => ['string', 'key'=>'string', 'function'=>'', 'lifetime'=>'int'], 'output_cache_put' => ['bool', 'key'=>'string', 'data'=>'mixed'], 'output_cache_remove' => ['bool', 'filename'=>''], 'output_cache_remove_key' => ['bool', 'key'=>'string'], 'output_cache_remove_url' => ['bool', 'url'=>'string'], 'output_cache_stop' => ['void'], 'output_reset_rewrite_vars' => ['bool'], 'outputformatObj::getOption' => ['string', 'property_name'=>'string'], 'outputformatObj::set' => ['int', 'property_name'=>'string', 'new_value'=>''], 'outputformatObj::setOption' => ['void', 'property_name'=>'string', 'new_value'=>'string'], 'outputformatObj::validate' => ['int'], 'OverflowException::__construct' => ['void', 'message='=>'string', 'code='=>'int', 'previous='=>'?Throwable'], 'OverflowException::__toString' => ['string'], 'OverflowException::getCode' => ['int'], 'OverflowException::getFile' => ['string'], 'OverflowException::getLine' => ['int'], 'OverflowException::getMessage' => ['string'], 'OverflowException::getPrevious' => ['?Throwable'], 'OverflowException::getTrace' => ['list\',args?:array}>'], 'OverflowException::getTraceAsString' => ['string'], 'overload' => ['', 'class_name'=>'string'], 'override_function' => ['bool', 'function_name'=>'string', 'function_args'=>'string', 'function_code'=>'string'], 'OwsrequestObj::__construct' => ['void'], 'OwsrequestObj::addParameter' => ['int', 'name'=>'string', 'value'=>'string'], 'OwsrequestObj::getName' => ['string', 'index'=>'int'], 'OwsrequestObj::getValue' => ['string', 'index'=>'int'], 'OwsrequestObj::getValueByName' => ['string', 'name'=>'string'], 'OwsrequestObj::loadParams' => ['int'], 'OwsrequestObj::setParameter' => ['int', 'name'=>'string', 'value'=>'string'], 'pack' => ['string', 'format'=>'string', '...values='=>'mixed'], 'parallel\Future::done' => ['bool'], 'parallel\Future::select' => ['mixed', '&resolving'=>'parallel\Future[]', '&w_resolved'=>'parallel\Future[]', '&w_errored'=>'parallel\Future[]', '&w_timedout='=>'parallel\Future[]', 'timeout='=>'int'], 'parallel\Future::value' => ['mixed', 'timeout='=>'int'], 'parallel\Runtime::__construct' => ['void', 'arg'=>'string|array'], 'parallel\Runtime::__construct\'1' => ['void', 'bootstrap'=>'string', 'configuration'=>'array'], 'parallel\Runtime::close' => ['void'], 'parallel\Runtime::kill' => ['void'], 'parallel\Runtime::run' => ['?parallel\Future', 'closure'=>'Closure', 'args='=>'array'], 'ParentIterator::__construct' => ['void', 'iterator'=>'RecursiveIterator'], 'ParentIterator::accept' => ['bool'], 'ParentIterator::getChildren' => ['?ParentIterator'], 'ParentIterator::hasChildren' => ['bool'], 'ParentIterator::next' => ['void'], 'ParentIterator::rewind' => ['void'], 'ParentIterator::valid' => ['bool'], 'Parle\Lexer::advance' => ['void'], 'Parle\Lexer::build' => ['void'], 'Parle\Lexer::callout' => ['void', 'id'=>'int', 'callback'=>'callable'], 'Parle\Lexer::consume' => ['void', 'data'=>'string'], 'Parle\Lexer::dump' => ['void'], 'Parle\Lexer::getToken' => ['Parle\Token'], 'Parle\Lexer::insertMacro' => ['void', 'name'=>'string', 'regex'=>'string'], 'Parle\Lexer::push' => ['void', 'regex'=>'string', 'id'=>'int'], 'Parle\Lexer::reset' => ['void', 'pos'=>'int'], 'Parle\Parser::advance' => ['void'], 'Parle\Parser::build' => ['void'], 'Parle\Parser::consume' => ['void', 'data'=>'string', 'lexer'=>'Parle\Lexer'], 'Parle\Parser::dump' => ['void'], 'Parle\Parser::errorInfo' => ['Parle\ErrorInfo'], 'Parle\Parser::left' => ['void', 'token'=>'string'], 'Parle\Parser::nonassoc' => ['void', 'token'=>'string'], 'Parle\Parser::precedence' => ['void', 'token'=>'string'], 'Parle\Parser::push' => ['int', 'name'=>'string', 'rule'=>'string'], 'Parle\Parser::reset' => ['void', 'tokenId'=>'int'], 'Parle\Parser::right' => ['void', 'token'=>'string'], 'Parle\Parser::sigil' => ['string', 'idx'=>'array'], 'Parle\Parser::token' => ['void', 'token'=>'string'], 'Parle\Parser::tokenId' => ['int', 'token'=>'string'], 'Parle\Parser::trace' => ['string'], 'Parle\Parser::validate' => ['bool', 'data'=>'string', 'lexer'=>'Parle\Lexer'], 'Parle\RLexer::advance' => ['void'], 'Parle\RLexer::build' => ['void'], 'Parle\RLexer::callout' => ['void', 'id'=>'int', 'callback'=>'callable'], 'Parle\RLexer::consume' => ['void', 'data'=>'string'], 'Parle\RLexer::dump' => ['void'], 'Parle\RLexer::getToken' => ['Parle\Token'], 'parle\rlexer::insertMacro' => ['void', 'name'=>'string', 'regex'=>'string'], 'Parle\RLexer::push' => ['void', 'state'=>'string', 'regex'=>'string', 'newState'=>'string'], 'Parle\RLexer::pushState' => ['int', 'state'=>'string'], 'Parle\RLexer::reset' => ['void', 'pos'=>'int'], 'Parle\RParser::advance' => ['void'], 'Parle\RParser::build' => ['void'], 'Parle\RParser::consume' => ['void', 'data'=>'string', 'lexer'=>'Parle\Lexer'], 'Parle\RParser::dump' => ['void'], 'Parle\RParser::errorInfo' => ['Parle\ErrorInfo'], 'Parle\RParser::left' => ['void', 'token'=>'string'], 'Parle\RParser::nonassoc' => ['void', 'token'=>'string'], 'Parle\RParser::precedence' => ['void', 'token'=>'string'], 'Parle\RParser::push' => ['int', 'name'=>'string', 'rule'=>'string'], 'Parle\RParser::reset' => ['void', 'tokenId'=>'int'], 'Parle\RParser::right' => ['void', 'token'=>'string'], 'Parle\RParser::sigil' => ['string', 'idx'=>'array'], 'Parle\RParser::token' => ['void', 'token'=>'string'], 'Parle\RParser::tokenId' => ['int', 'token'=>'string'], 'Parle\RParser::trace' => ['string'], 'Parle\RParser::validate' => ['bool', 'data'=>'string', 'lexer'=>'Parle\Lexer'], 'Parle\Stack::pop' => ['void'], 'Parle\Stack::push' => ['void', 'item'=>'mixed'], 'parse_ini_file' => ['array|false', 'filename'=>'string', 'process_sections='=>'bool', 'scanner_mode='=>'int'], 'parse_ini_string' => ['array|false', 'ini_string'=>'string', 'process_sections='=>'bool', 'scanner_mode='=>'int'], 'parse_str' => ['void', 'string'=>'string', '&w_result'=>'array'], 'parse_url' => ['int|string|array|null|false', 'url'=>'string', 'component='=>'int'], 'ParseError::__construct' => ['void', 'message='=>'string', 'code='=>'int', 'previous='=>'?Throwable'], 'ParseError::__toString' => ['string'], 'ParseError::getCode' => ['int'], 'ParseError::getFile' => ['string'], 'ParseError::getLine' => ['int'], 'ParseError::getMessage' => ['string'], 'ParseError::getPrevious' => ['?Throwable'], 'ParseError::getTrace' => ['list\',args?:array}>'], 'ParseError::getTraceAsString' => ['string'], 'parsekit_compile_file' => ['array', 'filename'=>'string', 'errors='=>'array', 'options='=>'int'], 'parsekit_compile_string' => ['array', 'phpcode'=>'string', 'errors='=>'array', 'options='=>'int'], 'parsekit_func_arginfo' => ['array', 'function'=>'mixed'], 'passthru' => ['void', 'command'=>'string', '&w_result_code='=>'int'], 'password_get_info' => ['array', 'hash'=>'string'], 'password_hash' => ['string', 'password'=>'string', 'algo'=>'int|string|null', 'options='=>'array'], 'password_make_salt' => ['bool', 'password'=>'string', 'hash'=>'string'], 'password_needs_rehash' => ['bool', 'hash'=>'string', 'algo'=>'int|string|null', 'options='=>'array'], 'password_verify' => ['bool', 'password'=>'string', 'hash'=>'string'], 'pathinfo' => ['array|string', 'path'=>'string', 'flags='=>'int'], 'pclose' => ['int', 'handle'=>'resource'], 'pcnlt_sigwaitinfo' => ['int', 'set'=>'array', '&w_siginfo'=>'array'], 'pcntl_alarm' => ['int', 'seconds'=>'int'], 'pcntl_async_signals' => ['bool', 'enable='=>'?bool'], 'pcntl_errno' => ['int'], 'pcntl_exec' => ['false', 'path'=>'string', 'args='=>'array', 'env_vars='=>'array'], 'pcntl_fork' => ['int'], 'pcntl_get_last_error' => ['int'], 'pcntl_getpriority' => ['int', 'process_id='=>'?int', 'mode='=>'int'], 'pcntl_setpriority' => ['bool', 'priority'=>'int', 'process_id='=>'?int', 'mode='=>'int'], 'pcntl_signal' => ['bool', 'signal'=>'int', 'handler'=>'callable():void|callable(int):void|callable(int,array):void|int', 'restart_syscalls='=>'bool'], 'pcntl_signal_dispatch' => ['bool'], 'pcntl_signal_get_handler' => ['int|string', 'signal'=>'int'], 'pcntl_sigprocmask' => ['bool', 'mode'=>'int', 'signals'=>'array', '&w_old_signals='=>'array'], 'pcntl_sigtimedwait' => ['int', 'signals'=>'array', '&w_info='=>'array', 'seconds='=>'int', 'nanoseconds='=>'int'], 'pcntl_sigwaitinfo' => ['int', 'signals'=>'array', '&w_info='=>'array'], 'pcntl_strerror' => ['string', 'error_code'=>'int'], 'pcntl_wait' => ['int', '&w_status'=>'int', 'flags='=>'int', '&w_resource_usage='=>'array'], 'pcntl_waitpid' => ['int', 'process_id'=>'int', '&w_status'=>'int', 'flags='=>'int', '&w_resource_usage='=>'array'], 'pcntl_wexitstatus' => ['int', 'status'=>'int'], 'pcntl_wifcontinued' => ['bool', 'status'=>'int'], 'pcntl_wifexited' => ['bool', 'status'=>'int'], 'pcntl_wifsignaled' => ['bool', 'status'=>'int'], 'pcntl_wifstopped' => ['bool', 'status'=>'int'], 'pcntl_wstopsig' => ['int', 'status'=>'int'], 'pcntl_wtermsig' => ['int', 'status'=>'int'], 'PDF_activate_item' => ['bool', 'pdfdoc'=>'resource', 'id'=>'int'], 'PDF_add_launchlink' => ['bool', 'pdfdoc'=>'resource', 'llx'=>'float', 'lly'=>'float', 'urx'=>'float', 'ury'=>'float', 'filename'=>'string'], 'PDF_add_locallink' => ['bool', 'pdfdoc'=>'resource', 'lowerleftx'=>'float', 'lowerlefty'=>'float', 'upperrightx'=>'float', 'upperrighty'=>'float', 'page'=>'int', 'dest'=>'string'], 'PDF_add_nameddest' => ['bool', 'pdfdoc'=>'resource', 'name'=>'string', 'optlist'=>'string'], 'PDF_add_note' => ['bool', 'pdfdoc'=>'resource', 'llx'=>'float', 'lly'=>'float', 'urx'=>'float', 'ury'=>'float', 'contents'=>'string', 'title'=>'string', 'icon'=>'string', 'open'=>'int'], 'PDF_add_pdflink' => ['bool', 'pdfdoc'=>'resource', 'bottom_left_x'=>'float', 'bottom_left_y'=>'float', 'up_right_x'=>'float', 'up_right_y'=>'float', 'filename'=>'string', 'page'=>'int', 'dest'=>'string'], 'PDF_add_table_cell' => ['int', 'pdfdoc'=>'resource', 'table'=>'int', 'column'=>'int', 'row'=>'int', 'text'=>'string', 'optlist'=>'string'], 'PDF_add_textflow' => ['int', 'pdfdoc'=>'resource', 'textflow'=>'int', 'text'=>'string', 'optlist'=>'string'], 'PDF_add_thumbnail' => ['bool', 'pdfdoc'=>'resource', 'image'=>'int'], 'PDF_add_weblink' => ['bool', 'pdfdoc'=>'resource', 'lowerleftx'=>'float', 'lowerlefty'=>'float', 'upperrightx'=>'float', 'upperrighty'=>'float', 'url'=>'string'], 'PDF_arc' => ['bool', 'p'=>'resource', 'x'=>'float', 'y'=>'float', 'r'=>'float', 'alpha'=>'float', 'beta'=>'float'], 'PDF_arcn' => ['bool', 'p'=>'resource', 'x'=>'float', 'y'=>'float', 'r'=>'float', 'alpha'=>'float', 'beta'=>'float'], 'PDF_attach_file' => ['bool', 'pdfdoc'=>'resource', 'llx'=>'float', 'lly'=>'float', 'urx'=>'float', 'ury'=>'float', 'filename'=>'string', 'description'=>'string', 'author'=>'string', 'mimetype'=>'string', 'icon'=>'string'], 'PDF_begin_document' => ['int', 'pdfdoc'=>'resource', 'filename'=>'string', 'optlist'=>'string'], 'PDF_begin_font' => ['bool', 'pdfdoc'=>'resource', 'filename'=>'string', 'a'=>'float', 'b'=>'float', 'c'=>'float', 'd'=>'float', 'e'=>'float', 'f'=>'float', 'optlist'=>'string'], 'PDF_begin_glyph' => ['bool', 'pdfdoc'=>'resource', 'glyphname'=>'string', 'wx'=>'float', 'llx'=>'float', 'lly'=>'float', 'urx'=>'float', 'ury'=>'float'], 'PDF_begin_item' => ['int', 'pdfdoc'=>'resource', 'tag'=>'string', 'optlist'=>'string'], 'PDF_begin_layer' => ['bool', 'pdfdoc'=>'resource', 'layer'=>'int'], 'PDF_begin_page' => ['bool', 'pdfdoc'=>'resource', 'width'=>'float', 'height'=>'float'], 'PDF_begin_page_ext' => ['bool', 'pdfdoc'=>'resource', 'width'=>'float', 'height'=>'float', 'optlist'=>'string'], 'PDF_begin_pattern' => ['int', 'pdfdoc'=>'resource', 'width'=>'float', 'height'=>'float', 'xstep'=>'float', 'ystep'=>'float', 'painttype'=>'int'], 'PDF_begin_template' => ['int', 'pdfdoc'=>'resource', 'width'=>'float', 'height'=>'float'], 'PDF_begin_template_ext' => ['int', 'pdfdoc'=>'resource', 'width'=>'float', 'height'=>'float', 'optlist'=>'string'], 'PDF_circle' => ['bool', 'pdfdoc'=>'resource', 'x'=>'float', 'y'=>'float', 'r'=>'float'], 'PDF_clip' => ['bool', 'p'=>'resource'], 'PDF_close' => ['bool', 'p'=>'resource'], 'PDF_close_image' => ['bool', 'p'=>'resource', 'image'=>'int'], 'PDF_close_pdi' => ['bool', 'p'=>'resource', 'doc'=>'int'], 'PDF_close_pdi_page' => ['bool', 'p'=>'resource', 'page'=>'int'], 'PDF_closepath' => ['bool', 'p'=>'resource'], 'PDF_closepath_fill_stroke' => ['bool', 'p'=>'resource'], 'PDF_closepath_stroke' => ['bool', 'p'=>'resource'], 'PDF_concat' => ['bool', 'p'=>'resource', 'a'=>'float', 'b'=>'float', 'c'=>'float', 'd'=>'float', 'e'=>'float', 'f'=>'float'], 'PDF_continue_text' => ['bool', 'p'=>'resource', 'text'=>'string'], 'PDF_create_3dview' => ['int', 'pdfdoc'=>'resource', 'username'=>'string', 'optlist'=>'string'], 'PDF_create_action' => ['int', 'pdfdoc'=>'resource', 'type'=>'string', 'optlist'=>'string'], 'PDF_create_annotation' => ['bool', 'pdfdoc'=>'resource', 'llx'=>'float', 'lly'=>'float', 'urx'=>'float', 'ury'=>'float', 'type'=>'string', 'optlist'=>'string'], 'PDF_create_bookmark' => ['int', 'pdfdoc'=>'resource', 'text'=>'string', 'optlist'=>'string'], 'PDF_create_field' => ['bool', 'pdfdoc'=>'resource', 'llx'=>'float', 'lly'=>'float', 'urx'=>'float', 'ury'=>'float', 'name'=>'string', 'type'=>'string', 'optlist'=>'string'], 'PDF_create_fieldgroup' => ['bool', 'pdfdoc'=>'resource', 'name'=>'string', 'optlist'=>'string'], 'PDF_create_gstate' => ['int', 'pdfdoc'=>'resource', 'optlist'=>'string'], 'PDF_create_pvf' => ['bool', 'pdfdoc'=>'resource', 'filename'=>'string', 'data'=>'string', 'optlist'=>'string'], 'PDF_create_textflow' => ['int', 'pdfdoc'=>'resource', 'text'=>'string', 'optlist'=>'string'], 'PDF_curveto' => ['bool', 'p'=>'resource', 'x1'=>'float', 'y1'=>'float', 'x2'=>'float', 'y2'=>'float', 'x3'=>'float', 'y3'=>'float'], 'PDF_define_layer' => ['int', 'pdfdoc'=>'resource', 'name'=>'string', 'optlist'=>'string'], 'PDF_delete' => ['bool', 'pdfdoc'=>'resource'], 'PDF_delete_pvf' => ['int', 'pdfdoc'=>'resource', 'filename'=>'string'], 'PDF_delete_table' => ['bool', 'pdfdoc'=>'resource', 'table'=>'int', 'optlist'=>'string'], 'PDF_delete_textflow' => ['bool', 'pdfdoc'=>'resource', 'textflow'=>'int'], 'PDF_encoding_set_char' => ['bool', 'pdfdoc'=>'resource', 'encoding'=>'string', 'slot'=>'int', 'glyphname'=>'string', 'uv'=>'int'], 'PDF_end_document' => ['bool', 'pdfdoc'=>'resource', 'optlist'=>'string'], 'PDF_end_font' => ['bool', 'pdfdoc'=>'resource'], 'PDF_end_glyph' => ['bool', 'pdfdoc'=>'resource'], 'PDF_end_item' => ['bool', 'pdfdoc'=>'resource', 'id'=>'int'], 'PDF_end_layer' => ['bool', 'pdfdoc'=>'resource'], 'PDF_end_page' => ['bool', 'p'=>'resource'], 'PDF_end_page_ext' => ['bool', 'pdfdoc'=>'resource', 'optlist'=>'string'], 'PDF_end_pattern' => ['bool', 'p'=>'resource'], 'PDF_end_template' => ['bool', 'p'=>'resource'], 'PDF_endpath' => ['bool', 'p'=>'resource'], 'PDF_fill' => ['bool', 'p'=>'resource'], 'PDF_fill_imageblock' => ['int', 'pdfdoc'=>'resource', 'page'=>'int', 'blockname'=>'string', 'image'=>'int', 'optlist'=>'string'], 'PDF_fill_pdfblock' => ['int', 'pdfdoc'=>'resource', 'page'=>'int', 'blockname'=>'string', 'contents'=>'int', 'optlist'=>'string'], 'PDF_fill_stroke' => ['bool', 'p'=>'resource'], 'PDF_fill_textblock' => ['int', 'pdfdoc'=>'resource', 'page'=>'int', 'blockname'=>'string', 'text'=>'string', 'optlist'=>'string'], 'PDF_findfont' => ['int', 'p'=>'resource', 'fontname'=>'string', 'encoding'=>'string', 'embed'=>'int'], 'PDF_fit_image' => ['bool', 'pdfdoc'=>'resource', 'image'=>'int', 'x'=>'float', 'y'=>'float', 'optlist'=>'string'], 'PDF_fit_pdi_page' => ['bool', 'pdfdoc'=>'resource', 'page'=>'int', 'x'=>'float', 'y'=>'float', 'optlist'=>'string'], 'PDF_fit_table' => ['string', 'pdfdoc'=>'resource', 'table'=>'int', 'llx'=>'float', 'lly'=>'float', 'urx'=>'float', 'ury'=>'float', 'optlist'=>'string'], 'PDF_fit_textflow' => ['string', 'pdfdoc'=>'resource', 'textflow'=>'int', 'llx'=>'float', 'lly'=>'float', 'urx'=>'float', 'ury'=>'float', 'optlist'=>'string'], 'PDF_fit_textline' => ['bool', 'pdfdoc'=>'resource', 'text'=>'string', 'x'=>'float', 'y'=>'float', 'optlist'=>'string'], 'PDF_get_apiname' => ['string', 'pdfdoc'=>'resource'], 'PDF_get_buffer' => ['string', 'p'=>'resource'], 'PDF_get_errmsg' => ['string', 'pdfdoc'=>'resource'], 'PDF_get_errnum' => ['int', 'pdfdoc'=>'resource'], 'PDF_get_majorversion' => ['int'], 'PDF_get_minorversion' => ['int'], 'PDF_get_parameter' => ['string', 'p'=>'resource', 'key'=>'string', 'modifier'=>'float'], 'PDF_get_pdi_parameter' => ['string', 'p'=>'resource', 'key'=>'string', 'doc'=>'int', 'page'=>'int', 'reserved'=>'int'], 'PDF_get_pdi_value' => ['float', 'p'=>'resource', 'key'=>'string', 'doc'=>'int', 'page'=>'int', 'reserved'=>'int'], 'PDF_get_value' => ['float', 'p'=>'resource', 'key'=>'string', 'modifier'=>'float'], 'PDF_info_font' => ['float', 'pdfdoc'=>'resource', 'font'=>'int', 'keyword'=>'string', 'optlist'=>'string'], 'PDF_info_matchbox' => ['float', 'pdfdoc'=>'resource', 'boxname'=>'string', 'num'=>'int', 'keyword'=>'string'], 'PDF_info_table' => ['float', 'pdfdoc'=>'resource', 'table'=>'int', 'keyword'=>'string'], 'PDF_info_textflow' => ['float', 'pdfdoc'=>'resource', 'textflow'=>'int', 'keyword'=>'string'], 'PDF_info_textline' => ['float', 'pdfdoc'=>'resource', 'text'=>'string', 'keyword'=>'string', 'optlist'=>'string'], 'PDF_initgraphics' => ['bool', 'p'=>'resource'], 'PDF_lineto' => ['bool', 'p'=>'resource', 'x'=>'float', 'y'=>'float'], 'PDF_load_3ddata' => ['int', 'pdfdoc'=>'resource', 'filename'=>'string', 'optlist'=>'string'], 'PDF_load_font' => ['int', 'pdfdoc'=>'resource', 'fontname'=>'string', 'encoding'=>'string', 'optlist'=>'string'], 'PDF_load_iccprofile' => ['int', 'pdfdoc'=>'resource', 'profilename'=>'string', 'optlist'=>'string'], 'PDF_load_image' => ['int', 'pdfdoc'=>'resource', 'imagetype'=>'string', 'filename'=>'string', 'optlist'=>'string'], 'PDF_makespotcolor' => ['int', 'p'=>'resource', 'spotname'=>'string'], 'PDF_moveto' => ['bool', 'p'=>'resource', 'x'=>'float', 'y'=>'float'], 'PDF_new' => ['resource'], 'PDF_open_ccitt' => ['int', 'pdfdoc'=>'resource', 'filename'=>'string', 'width'=>'int', 'height'=>'int', 'bitreverse'=>'int', 'k'=>'int', 'blackls1'=>'int'], 'PDF_open_file' => ['bool', 'p'=>'resource', 'filename'=>'string'], 'PDF_open_image' => ['int', 'p'=>'resource', 'imagetype'=>'string', 'source'=>'string', 'data'=>'string', 'length'=>'int', 'width'=>'int', 'height'=>'int', 'components'=>'int', 'bpc'=>'int', 'params'=>'string'], 'PDF_open_image_file' => ['int', 'p'=>'resource', 'imagetype'=>'string', 'filename'=>'string', 'stringparam'=>'string', 'intparam'=>'int'], 'PDF_open_memory_image' => ['int', 'p'=>'resource', 'image'=>'resource'], 'PDF_open_pdi' => ['int', 'pdfdoc'=>'resource', 'filename'=>'string', 'optlist'=>'string', 'length'=>'int'], 'PDF_open_pdi_document' => ['int', 'p'=>'resource', 'filename'=>'string', 'optlist'=>'string'], 'PDF_open_pdi_page' => ['int', 'p'=>'resource', 'doc'=>'int', 'pagenumber'=>'int', 'optlist'=>'string'], 'PDF_pcos_get_number' => ['float', 'p'=>'resource', 'doc'=>'int', 'path'=>'string'], 'PDF_pcos_get_stream' => ['string', 'p'=>'resource', 'doc'=>'int', 'optlist'=>'string', 'path'=>'string'], 'PDF_pcos_get_string' => ['string', 'p'=>'resource', 'doc'=>'int', 'path'=>'string'], 'PDF_place_image' => ['bool', 'pdfdoc'=>'resource', 'image'=>'int', 'x'=>'float', 'y'=>'float', 'scale'=>'float'], 'PDF_place_pdi_page' => ['bool', 'pdfdoc'=>'resource', 'page'=>'int', 'x'=>'float', 'y'=>'float', 'sx'=>'float', 'sy'=>'float'], 'PDF_process_pdi' => ['int', 'pdfdoc'=>'resource', 'doc'=>'int', 'page'=>'int', 'optlist'=>'string'], 'PDF_rect' => ['bool', 'p'=>'resource', 'x'=>'float', 'y'=>'float', 'width'=>'float', 'height'=>'float'], 'PDF_restore' => ['bool', 'p'=>'resource'], 'PDF_resume_page' => ['bool', 'pdfdoc'=>'resource', 'optlist'=>'string'], 'PDF_rotate' => ['bool', 'p'=>'resource', 'phi'=>'float'], 'PDF_save' => ['bool', 'p'=>'resource'], 'PDF_scale' => ['bool', 'p'=>'resource', 'sx'=>'float', 'sy'=>'float'], 'PDF_set_border_color' => ['bool', 'p'=>'resource', 'red'=>'float', 'green'=>'float', 'blue'=>'float'], 'PDF_set_border_dash' => ['bool', 'pdfdoc'=>'resource', 'black'=>'float', 'white'=>'float'], 'PDF_set_border_style' => ['bool', 'pdfdoc'=>'resource', 'style'=>'string', 'width'=>'float'], 'PDF_set_gstate' => ['bool', 'pdfdoc'=>'resource', 'gstate'=>'int'], 'PDF_set_info' => ['bool', 'p'=>'resource', 'key'=>'string', 'value'=>'string'], 'PDF_set_layer_dependency' => ['bool', 'pdfdoc'=>'resource', 'type'=>'string', 'optlist'=>'string'], 'PDF_set_parameter' => ['bool', 'p'=>'resource', 'key'=>'string', 'value'=>'string'], 'PDF_set_text_pos' => ['bool', 'p'=>'resource', 'x'=>'float', 'y'=>'float'], 'PDF_set_value' => ['bool', 'p'=>'resource', 'key'=>'string', 'value'=>'float'], 'PDF_setcolor' => ['bool', 'p'=>'resource', 'fstype'=>'string', 'colorspace'=>'string', 'c1'=>'float', 'c2'=>'float', 'c3'=>'float', 'c4'=>'float'], 'PDF_setdash' => ['bool', 'pdfdoc'=>'resource', 'b'=>'float', 'w'=>'float'], 'PDF_setdashpattern' => ['bool', 'pdfdoc'=>'resource', 'optlist'=>'string'], 'PDF_setflat' => ['bool', 'pdfdoc'=>'resource', 'flatness'=>'float'], 'PDF_setfont' => ['bool', 'pdfdoc'=>'resource', 'font'=>'int', 'fontsize'=>'float'], 'PDF_setgray' => ['bool', 'p'=>'resource', 'g'=>'float'], 'PDF_setgray_fill' => ['bool', 'p'=>'resource', 'g'=>'float'], 'PDF_setgray_stroke' => ['bool', 'p'=>'resource', 'g'=>'float'], 'PDF_setlinecap' => ['bool', 'p'=>'resource', 'linecap'=>'int'], 'PDF_setlinejoin' => ['bool', 'p'=>'resource', 'value'=>'int'], 'PDF_setlinewidth' => ['bool', 'p'=>'resource', 'width'=>'float'], 'PDF_setmatrix' => ['bool', 'p'=>'resource', 'a'=>'float', 'b'=>'float', 'c'=>'float', 'd'=>'float', 'e'=>'float', 'f'=>'float'], 'PDF_setmiterlimit' => ['bool', 'pdfdoc'=>'resource', 'miter'=>'float'], 'PDF_setrgbcolor' => ['bool', 'p'=>'resource', 'red'=>'float', 'green'=>'float', 'blue'=>'float'], 'PDF_setrgbcolor_fill' => ['bool', 'p'=>'resource', 'red'=>'float', 'green'=>'float', 'blue'=>'float'], 'PDF_setrgbcolor_stroke' => ['bool', 'p'=>'resource', 'red'=>'float', 'green'=>'float', 'blue'=>'float'], 'PDF_shading' => ['int', 'pdfdoc'=>'resource', 'shtype'=>'string', 'x0'=>'float', 'y0'=>'float', 'x1'=>'float', 'y1'=>'float', 'c1'=>'float', 'c2'=>'float', 'c3'=>'float', 'c4'=>'float', 'optlist'=>'string'], 'PDF_shading_pattern' => ['int', 'pdfdoc'=>'resource', 'shading'=>'int', 'optlist'=>'string'], 'PDF_shfill' => ['bool', 'pdfdoc'=>'resource', 'shading'=>'int'], 'PDF_show' => ['bool', 'pdfdoc'=>'resource', 'text'=>'string'], 'PDF_show_boxed' => ['int', 'p'=>'resource', 'text'=>'string', 'left'=>'float', 'top'=>'float', 'width'=>'float', 'height'=>'float', 'mode'=>'string', 'feature'=>'string'], 'PDF_show_xy' => ['bool', 'p'=>'resource', 'text'=>'string', 'x'=>'float', 'y'=>'float'], 'PDF_skew' => ['bool', 'p'=>'resource', 'alpha'=>'float', 'beta'=>'float'], 'PDF_stringwidth' => ['float', 'p'=>'resource', 'text'=>'string', 'font'=>'int', 'fontsize'=>'float'], 'PDF_stroke' => ['bool', 'p'=>'resource'], 'PDF_suspend_page' => ['bool', 'pdfdoc'=>'resource', 'optlist'=>'string'], 'PDF_translate' => ['bool', 'p'=>'resource', 'tx'=>'float', 'ty'=>'float'], 'PDF_utf16_to_utf8' => ['string', 'pdfdoc'=>'resource', 'utf16string'=>'string'], 'PDF_utf32_to_utf16' => ['string', 'pdfdoc'=>'resource', 'utf32string'=>'string', 'ordering'=>'string'], 'PDF_utf8_to_utf16' => ['string', 'pdfdoc'=>'resource', 'utf8string'=>'string', 'ordering'=>'string'], 'PDFlib::activate_item' => ['bool', 'id'=>''], 'PDFlib::add_launchlink' => ['bool', 'llx'=>'float', 'lly'=>'float', 'urx'=>'float', 'ury'=>'float', 'filename'=>'string'], 'PDFlib::add_locallink' => ['bool', 'lowerleftx'=>'float', 'lowerlefty'=>'float', 'upperrightx'=>'float', 'upperrighty'=>'float', 'page'=>'int', 'dest'=>'string'], 'PDFlib::add_nameddest' => ['bool', 'name'=>'string', 'optlist'=>'string'], 'PDFlib::add_note' => ['bool', 'llx'=>'float', 'lly'=>'float', 'urx'=>'float', 'ury'=>'float', 'contents'=>'string', 'title'=>'string', 'icon'=>'string', 'open'=>'int'], 'PDFlib::add_pdflink' => ['bool', 'bottom_left_x'=>'float', 'bottom_left_y'=>'float', 'up_right_x'=>'float', 'up_right_y'=>'float', 'filename'=>'string', 'page'=>'int', 'dest'=>'string'], 'PDFlib::add_table_cell' => ['int', 'table'=>'int', 'column'=>'int', 'row'=>'int', 'text'=>'string', 'optlist'=>'string'], 'PDFlib::add_textflow' => ['int', 'textflow'=>'int', 'text'=>'string', 'optlist'=>'string'], 'PDFlib::add_thumbnail' => ['bool', 'image'=>'int'], 'PDFlib::add_weblink' => ['bool', 'lowerleftx'=>'float', 'lowerlefty'=>'float', 'upperrightx'=>'float', 'upperrighty'=>'float', 'url'=>'string'], 'PDFlib::arc' => ['bool', 'x'=>'float', 'y'=>'float', 'r'=>'float', 'alpha'=>'float', 'beta'=>'float'], 'PDFlib::arcn' => ['bool', 'x'=>'float', 'y'=>'float', 'r'=>'float', 'alpha'=>'float', 'beta'=>'float'], 'PDFlib::attach_file' => ['bool', 'llx'=>'float', 'lly'=>'float', 'urx'=>'float', 'ury'=>'float', 'filename'=>'string', 'description'=>'string', 'author'=>'string', 'mimetype'=>'string', 'icon'=>'string'], 'PDFlib::begin_document' => ['int', 'filename'=>'string', 'optlist'=>'string'], 'PDFlib::begin_font' => ['bool', 'filename'=>'string', 'a'=>'float', 'b'=>'float', 'c'=>'float', 'd'=>'float', 'e'=>'float', 'f'=>'float', 'optlist'=>'string'], 'PDFlib::begin_glyph' => ['bool', 'glyphname'=>'string', 'wx'=>'float', 'llx'=>'float', 'lly'=>'float', 'urx'=>'float', 'ury'=>'float'], 'PDFlib::begin_item' => ['int', 'tag'=>'string', 'optlist'=>'string'], 'PDFlib::begin_layer' => ['bool', 'layer'=>'int'], 'PDFlib::begin_page' => ['bool', 'width'=>'float', 'height'=>'float'], 'PDFlib::begin_page_ext' => ['bool', 'width'=>'float', 'height'=>'float', 'optlist'=>'string'], 'PDFlib::begin_pattern' => ['int', 'width'=>'float', 'height'=>'float', 'xstep'=>'float', 'ystep'=>'float', 'painttype'=>'int'], 'PDFlib::begin_template' => ['int', 'width'=>'float', 'height'=>'float'], 'PDFlib::begin_template_ext' => ['int', 'width'=>'float', 'height'=>'float', 'optlist'=>'string'], 'PDFlib::circle' => ['bool', 'x'=>'float', 'y'=>'float', 'r'=>'float'], 'PDFlib::clip' => ['bool'], 'PDFlib::close' => ['bool'], 'PDFlib::close_image' => ['bool', 'image'=>'int'], 'PDFlib::close_pdi' => ['bool', 'doc'=>'int'], 'PDFlib::close_pdi_page' => ['bool', 'page'=>'int'], 'PDFlib::closepath' => ['bool'], 'PDFlib::closepath_fill_stroke' => ['bool'], 'PDFlib::closepath_stroke' => ['bool'], 'PDFlib::concat' => ['bool', 'a'=>'float', 'b'=>'float', 'c'=>'float', 'd'=>'float', 'e'=>'float', 'f'=>'float'], 'PDFlib::continue_text' => ['bool', 'text'=>'string'], 'PDFlib::create_3dview' => ['int', 'username'=>'string', 'optlist'=>'string'], 'PDFlib::create_action' => ['int', 'type'=>'string', 'optlist'=>'string'], 'PDFlib::create_annotation' => ['bool', 'llx'=>'float', 'lly'=>'float', 'urx'=>'float', 'ury'=>'float', 'type'=>'string', 'optlist'=>'string'], 'PDFlib::create_bookmark' => ['int', 'text'=>'string', 'optlist'=>'string'], 'PDFlib::create_field' => ['bool', 'llx'=>'float', 'lly'=>'float', 'urx'=>'float', 'ury'=>'float', 'name'=>'string', 'type'=>'string', 'optlist'=>'string'], 'PDFlib::create_fieldgroup' => ['bool', 'name'=>'string', 'optlist'=>'string'], 'PDFlib::create_gstate' => ['int', 'optlist'=>'string'], 'PDFlib::create_pvf' => ['bool', 'filename'=>'string', 'data'=>'string', 'optlist'=>'string'], 'PDFlib::create_textflow' => ['int', 'text'=>'string', 'optlist'=>'string'], 'PDFlib::curveto' => ['bool', 'x1'=>'float', 'y1'=>'float', 'x2'=>'float', 'y2'=>'float', 'x3'=>'float', 'y3'=>'float'], 'PDFlib::define_layer' => ['int', 'name'=>'string', 'optlist'=>'string'], 'PDFlib::delete' => ['bool'], 'PDFlib::delete_pvf' => ['int', 'filename'=>'string'], 'PDFlib::delete_table' => ['bool', 'table'=>'int', 'optlist'=>'string'], 'PDFlib::delete_textflow' => ['bool', 'textflow'=>'int'], 'PDFlib::encoding_set_char' => ['bool', 'encoding'=>'string', 'slot'=>'int', 'glyphname'=>'string', 'uv'=>'int'], 'PDFlib::end_document' => ['bool', 'optlist'=>'string'], 'PDFlib::end_font' => ['bool'], 'PDFlib::end_glyph' => ['bool'], 'PDFlib::end_item' => ['bool', 'id'=>'int'], 'PDFlib::end_layer' => ['bool'], 'PDFlib::end_page' => ['bool', 'p'=>''], 'PDFlib::end_page_ext' => ['bool', 'optlist'=>'string'], 'PDFlib::end_pattern' => ['bool', 'p'=>''], 'PDFlib::end_template' => ['bool', 'p'=>''], 'PDFlib::endpath' => ['bool', 'p'=>''], 'PDFlib::fill' => ['bool'], 'PDFlib::fill_imageblock' => ['int', 'page'=>'int', 'blockname'=>'string', 'image'=>'int', 'optlist'=>'string'], 'PDFlib::fill_pdfblock' => ['int', 'page'=>'int', 'blockname'=>'string', 'contents'=>'int', 'optlist'=>'string'], 'PDFlib::fill_stroke' => ['bool'], 'PDFlib::fill_textblock' => ['int', 'page'=>'int', 'blockname'=>'string', 'text'=>'string', 'optlist'=>'string'], 'PDFlib::findfont' => ['int', 'fontname'=>'string', 'encoding'=>'string', 'embed'=>'int'], 'PDFlib::fit_image' => ['bool', 'image'=>'int', 'x'=>'float', 'y'=>'float', 'optlist'=>'string'], 'PDFlib::fit_pdi_page' => ['bool', 'page'=>'int', 'x'=>'float', 'y'=>'float', 'optlist'=>'string'], 'PDFlib::fit_table' => ['string', 'table'=>'int', 'llx'=>'float', 'lly'=>'float', 'urx'=>'float', 'ury'=>'float', 'optlist'=>'string'], 'PDFlib::fit_textflow' => ['string', 'textflow'=>'int', 'llx'=>'float', 'lly'=>'float', 'urx'=>'float', 'ury'=>'float', 'optlist'=>'string'], 'PDFlib::fit_textline' => ['bool', 'text'=>'string', 'x'=>'float', 'y'=>'float', 'optlist'=>'string'], 'PDFlib::get_apiname' => ['string'], 'PDFlib::get_buffer' => ['string'], 'PDFlib::get_errmsg' => ['string'], 'PDFlib::get_errnum' => ['int'], 'PDFlib::get_majorversion' => ['int'], 'PDFlib::get_minorversion' => ['int'], 'PDFlib::get_parameter' => ['string', 'key'=>'string', 'modifier'=>'float'], 'PDFlib::get_pdi_parameter' => ['string', 'key'=>'string', 'doc'=>'int', 'page'=>'int', 'reserved'=>'int'], 'PDFlib::get_pdi_value' => ['float', 'key'=>'string', 'doc'=>'int', 'page'=>'int', 'reserved'=>'int'], 'PDFlib::get_value' => ['float', 'key'=>'string', 'modifier'=>'float'], 'PDFlib::info_font' => ['float', 'font'=>'int', 'keyword'=>'string', 'optlist'=>'string'], 'PDFlib::info_matchbox' => ['float', 'boxname'=>'string', 'num'=>'int', 'keyword'=>'string'], 'PDFlib::info_table' => ['float', 'table'=>'int', 'keyword'=>'string'], 'PDFlib::info_textflow' => ['float', 'textflow'=>'int', 'keyword'=>'string'], 'PDFlib::info_textline' => ['float', 'text'=>'string', 'keyword'=>'string', 'optlist'=>'string'], 'PDFlib::initgraphics' => ['bool'], 'PDFlib::lineto' => ['bool', 'x'=>'float', 'y'=>'float'], 'PDFlib::load_3ddata' => ['int', 'filename'=>'string', 'optlist'=>'string'], 'PDFlib::load_font' => ['int', 'fontname'=>'string', 'encoding'=>'string', 'optlist'=>'string'], 'PDFlib::load_iccprofile' => ['int', 'profilename'=>'string', 'optlist'=>'string'], 'PDFlib::load_image' => ['int', 'imagetype'=>'string', 'filename'=>'string', 'optlist'=>'string'], 'PDFlib::makespotcolor' => ['int', 'spotname'=>'string'], 'PDFlib::moveto' => ['bool', 'x'=>'float', 'y'=>'float'], 'PDFlib::open_ccitt' => ['int', 'filename'=>'string', 'width'=>'int', 'height'=>'int', 'BitReverse'=>'int', 'k'=>'int', 'Blackls1'=>'int'], 'PDFlib::open_file' => ['bool', 'filename'=>'string'], 'PDFlib::open_image' => ['int', 'imagetype'=>'string', 'source'=>'string', 'data'=>'string', 'length'=>'int', 'width'=>'int', 'height'=>'int', 'components'=>'int', 'bpc'=>'int', 'params'=>'string'], 'PDFlib::open_image_file' => ['int', 'imagetype'=>'string', 'filename'=>'string', 'stringparam'=>'string', 'intparam'=>'int'], 'PDFlib::open_memory_image' => ['int', 'image'=>'resource'], 'PDFlib::open_pdi' => ['int', 'filename'=>'string', 'optlist'=>'string', 'length'=>'int'], 'PDFlib::open_pdi_document' => ['int', 'filename'=>'string', 'optlist'=>'string'], 'PDFlib::open_pdi_page' => ['int', 'doc'=>'int', 'pagenumber'=>'int', 'optlist'=>'string'], 'PDFlib::pcos_get_number' => ['float', 'doc'=>'int', 'path'=>'string'], 'PDFlib::pcos_get_stream' => ['string', 'doc'=>'int', 'optlist'=>'string', 'path'=>'string'], 'PDFlib::pcos_get_string' => ['string', 'doc'=>'int', 'path'=>'string'], 'PDFlib::place_image' => ['bool', 'image'=>'int', 'x'=>'float', 'y'=>'float', 'scale'=>'float'], 'PDFlib::place_pdi_page' => ['bool', 'page'=>'int', 'x'=>'float', 'y'=>'float', 'sx'=>'float', 'sy'=>'float'], 'PDFlib::process_pdi' => ['int', 'doc'=>'int', 'page'=>'int', 'optlist'=>'string'], 'PDFlib::rect' => ['bool', 'x'=>'float', 'y'=>'float', 'width'=>'float', 'height'=>'float'], 'PDFlib::restore' => ['bool', 'p'=>''], 'PDFlib::resume_page' => ['bool', 'optlist'=>'string'], 'PDFlib::rotate' => ['bool', 'phi'=>'float'], 'PDFlib::save' => ['bool', 'p'=>''], 'PDFlib::scale' => ['bool', 'sx'=>'float', 'sy'=>'float'], 'PDFlib::set_border_color' => ['bool', 'red'=>'float', 'green'=>'float', 'blue'=>'float'], 'PDFlib::set_border_dash' => ['bool', 'black'=>'float', 'white'=>'float'], 'PDFlib::set_border_style' => ['bool', 'style'=>'string', 'width'=>'float'], 'PDFlib::set_gstate' => ['bool', 'gstate'=>'int'], 'PDFlib::set_info' => ['bool', 'key'=>'string', 'value'=>'string'], 'PDFlib::set_layer_dependency' => ['bool', 'type'=>'string', 'optlist'=>'string'], 'PDFlib::set_parameter' => ['bool', 'key'=>'string', 'value'=>'string'], 'PDFlib::set_text_pos' => ['bool', 'x'=>'float', 'y'=>'float'], 'PDFlib::set_value' => ['bool', 'key'=>'string', 'value'=>'float'], 'PDFlib::setcolor' => ['bool', 'fstype'=>'string', 'colorspace'=>'string', 'c1'=>'float', 'c2'=>'float', 'c3'=>'float', 'c4'=>'float'], 'PDFlib::setdash' => ['bool', 'b'=>'float', 'w'=>'float'], 'PDFlib::setdashpattern' => ['bool', 'optlist'=>'string'], 'PDFlib::setflat' => ['bool', 'flatness'=>'float'], 'PDFlib::setfont' => ['bool', 'font'=>'int', 'fontsize'=>'float'], 'PDFlib::setgray' => ['bool', 'g'=>'float'], 'PDFlib::setgray_fill' => ['bool', 'g'=>'float'], 'PDFlib::setgray_stroke' => ['bool', 'g'=>'float'], 'PDFlib::setlinecap' => ['bool', 'linecap'=>'int'], 'PDFlib::setlinejoin' => ['bool', 'value'=>'int'], 'PDFlib::setlinewidth' => ['bool', 'width'=>'float'], 'PDFlib::setmatrix' => ['bool', 'a'=>'float', 'b'=>'float', 'c'=>'float', 'd'=>'float', 'e'=>'float', 'f'=>'float'], 'PDFlib::setmiterlimit' => ['bool', 'miter'=>'float'], 'PDFlib::setrgbcolor' => ['bool', 'red'=>'float', 'green'=>'float', 'blue'=>'float'], 'PDFlib::setrgbcolor_fill' => ['bool', 'red'=>'float', 'green'=>'float', 'blue'=>'float'], 'PDFlib::setrgbcolor_stroke' => ['bool', 'red'=>'float', 'green'=>'float', 'blue'=>'float'], 'PDFlib::shading' => ['int', 'shtype'=>'string', 'x0'=>'float', 'y0'=>'float', 'x1'=>'float', 'y1'=>'float', 'c1'=>'float', 'c2'=>'float', 'c3'=>'float', 'c4'=>'float', 'optlist'=>'string'], 'PDFlib::shading_pattern' => ['int', 'shading'=>'int', 'optlist'=>'string'], 'PDFlib::shfill' => ['bool', 'shading'=>'int'], 'PDFlib::show' => ['bool', 'text'=>'string'], 'PDFlib::show_boxed' => ['int', 'text'=>'string', 'left'=>'float', 'top'=>'float', 'width'=>'float', 'height'=>'float', 'mode'=>'string', 'feature'=>'string'], 'PDFlib::show_xy' => ['bool', 'text'=>'string', 'x'=>'float', 'y'=>'float'], 'PDFlib::skew' => ['bool', 'alpha'=>'float', 'beta'=>'float'], 'PDFlib::stringwidth' => ['float', 'text'=>'string', 'font'=>'int', 'fontsize'=>'float'], 'PDFlib::stroke' => ['bool', 'p'=>''], 'PDFlib::suspend_page' => ['bool', 'optlist'=>'string'], 'PDFlib::translate' => ['bool', 'tx'=>'float', 'ty'=>'float'], 'PDFlib::utf16_to_utf8' => ['string', 'utf16string'=>'string'], 'PDFlib::utf32_to_utf16' => ['string', 'utf32string'=>'string', 'ordering'=>'string'], 'PDFlib::utf8_to_utf16' => ['string', 'utf8string'=>'string', 'ordering'=>'string'], 'PDO::__construct' => ['void', 'dsn'=>'string', 'username='=>'?string', 'password='=>'?string', 'options='=>'?array'], 'PDO::beginTransaction' => ['bool'], 'PDO::commit' => ['bool'], 'PDO::cubrid_schema' => ['array', 'schema_type'=>'int', 'table_name='=>'string', 'col_name='=>'string'], 'PDO::errorCode' => ['?string'], 'PDO::errorInfo' => ['array{0: ?string, 1: ?int, 2: ?string, 3?: mixed, 4?: mixed}'], 'PDO::exec' => ['int|false', 'statement'=>'string'], 'PDO::getAttribute' => ['mixed', 'attribute'=>'int'], 'PDO::getAvailableDrivers' => ['array'], 'PDO::inTransaction' => ['bool'], 'PDO::lastInsertId' => ['string', 'name='=>'string|null'], 'PDO::pgsqlCopyFromArray' => ['bool', 'table_name'=>'string', 'rows'=>'array', 'delimiter'=>'string', 'null_as'=>'string', 'fields'=>'string'], 'PDO::pgsqlCopyFromFile' => ['bool', 'table_name'=>'string', 'filename'=>'string', 'delimiter'=>'string', 'null_as'=>'string', 'fields'=>'string'], 'PDO::pgsqlCopyToArray' => ['array', 'table_name'=>'string', 'delimiter'=>'string', 'null_as'=>'string', 'fields'=>'string'], 'PDO::pgsqlCopyToFile' => ['bool', 'table_name'=>'string', 'filename'=>'string', 'delimiter'=>'string', 'null_as'=>'string', 'fields'=>'string'], 'PDO::pgsqlGetNotify' => ['array{message:string,pid:int,payload?:string}|false', 'result_type='=>'PDO::FETCH_*', 'ms_timeout='=>'int'], 'PDO::pgsqlGetPid' => ['int'], 'PDO::pgsqlLOBCreate' => ['string'], 'PDO::pgsqlLOBOpen' => ['resource', 'oid'=>'string', 'mode='=>'string'], 'PDO::pgsqlLOBUnlink' => ['bool', 'oid'=>'string'], 'PDO::prepare' => ['PDOStatement|false', 'query'=>'string', 'options='=>'array'], 'PDO::query' => ['PDOStatement|false', 'query'=>'string'], 'PDO::query\'1' => ['PDOStatement|false', 'query'=>'string', 'fetch_column'=>'int', 'colno='=>'int'], 'PDO::query\'2' => ['PDOStatement|false', 'query'=>'string', 'fetch_class'=>'int', 'classname'=>'string', 'constructorArgs'=>'array'], 'PDO::query\'3' => ['PDOStatement|false', 'query'=>'string', 'fetch_into'=>'int', 'object'=>'object'], 'PDO::quote' => ['string|false', 'string'=>'string', 'type='=>'int'], 'PDO::rollBack' => ['bool'], 'PDO::setAttribute' => ['bool', 'attribute'=>'int', 'value'=>''], 'PDO::sqliteCreateAggregate' => ['bool', 'function_name'=>'string', 'step_func'=>'callable', 'finalize_func'=>'callable', 'num_args='=>'int'], 'PDO::sqliteCreateCollation' => ['bool', 'name'=>'string', 'callback'=>'callable'], 'PDO::sqliteCreateFunction' => ['bool', 'function_name'=>'string', 'callback'=>'callable', 'num_args='=>'int'], 'pdo_drivers' => ['array'], 'PDOException::getCode' => ['int|string'], 'PDOException::getFile' => ['string'], 'PDOException::getLine' => ['int'], 'PDOException::getMessage' => ['string'], 'PDOException::getPrevious' => ['?Throwable'], 'PDOException::getTrace' => ['list\',args?:array}>'], 'PDOException::getTraceAsString' => ['string'], 'PDOStatement::bindColumn' => ['bool', 'column'=>'string|int', '&rw_var'=>'mixed', 'type='=>'int', 'maxLength='=>'int', 'driverOptions='=>'mixed'], 'PDOStatement::bindParam' => ['bool', 'param'=>'string|int', '&rw_var'=>'mixed', 'type='=>'int', 'maxLength='=>'int', 'driverOptions='=>'mixed'], 'PDOStatement::bindValue' => ['bool', 'param'=>'string|int', 'value'=>'mixed', 'type='=>'int'], 'PDOStatement::closeCursor' => ['bool'], 'PDOStatement::columnCount' => ['int'], 'PDOStatement::debugDumpParams' => ['bool|null'], 'PDOStatement::errorCode' => ['string|null'], 'PDOStatement::errorInfo' => ['array{0: ?string, 1: ?int, 2: ?string, 3?: mixed, 4?: mixed}'], 'PDOStatement::execute' => ['bool', 'params='=>'?array'], 'PDOStatement::fetch' => ['mixed', 'mode='=>'int', 'cursorOrientation='=>'int', 'cursorOffset='=>'int'], 'PDOStatement::fetchAll' => ['array', 'mode='=>'int', '...args='=>'mixed'], 'PDOStatement::fetchColumn' => ['mixed', 'column='=>'int'], 'PDOStatement::fetchObject' => ['object|false', 'class='=>'?class-string', 'constructorArgs='=>'array'], 'PDOStatement::getAttribute' => ['mixed', 'name'=>'int'], 'PDOStatement::getColumnMeta' => ['array|false', 'column'=>'int'], 'PDOStatement::nextRowset' => ['bool'], 'PDOStatement::rowCount' => ['int'], 'PDOStatement::setAttribute' => ['bool', 'attribute'=>'int', 'value'=>'mixed'], 'PDOStatement::setFetchMode' => ['bool', 'mode'=>'int', '...args='=> 'mixed'], 'pfsockopen' => ['resource|false', 'hostname'=>'string', 'port='=>'int', '&w_error_code='=>'int', '&w_error_message='=>'string', 'timeout='=>'?float'], 'pg_affected_rows' => ['int', 'result'=>'\PgSql\Result'], 'pg_cancel_query' => ['bool', 'connection'=>'\PgSql\Connection'], 'pg_client_encoding' => ['string', 'connection='=>'?\PgSql\Connection'], 'pg_close' => ['bool', 'connection='=>'?\PgSql\Connection'], 'pg_connect' => ['\PgSql\Connection|false', 'connection_string'=>'string', 'flags='=>'int'], 'pg_connect_poll' => ['int', 'connection'=>'\PgSql\Connection'], 'pg_connection_busy' => ['bool', 'connection'=>'\PgSql\Connection'], 'pg_connection_reset' => ['bool', 'connection'=>'\PgSql\Connection'], 'pg_connection_status' => ['int', 'connection'=>'\PgSql\Connection'], 'pg_consume_input' => ['bool', 'connection'=>'\PgSql\Connection'], 'pg_convert' => ['array|false', 'connection'=>'\PgSql\Connection', 'table_name'=>'string', 'values'=>'array', 'flags='=>'int'], 'pg_copy_from' => ['bool', 'connection'=>'\PgSql\Connection', 'table_name'=>'string', 'rows'=>'array', 'separator='=>'string', 'null_as='=>'string'], 'pg_copy_to' => ['array|false', 'connection'=>'\PgSql\Connection', 'table_name'=>'string', 'separator='=>'string', 'null_as='=>'string'], 'pg_dbname' => ['string', 'connection='=>'?\PgSql\Connection'], 'pg_delete' => ['string|bool', 'connection'=>'\PgSql\Connection', 'table_name'=>'string', 'conditions'=>'array', 'flags='=>'int'], 'pg_end_copy' => ['bool', 'connection='=>'?\PgSql\Connection'], 'pg_escape_bytea' => ['string', 'connection'=>'\PgSql\Connection', 'string'=>'string'], 'pg_escape_bytea\'1' => ['string', 'connection'=>'string'], 'pg_escape_identifier' => ['string|false', 'connection'=>'\PgSql\Connection', 'string'=>'string'], 'pg_escape_identifier\'1' => ['string|false', 'connection'=>'string'], 'pg_escape_literal' => ['string|false', 'connection'=>'\PgSql\Connection', 'string'=>'string'], 'pg_escape_literal\'1' => ['string|false', 'connection'=>'string'], 'pg_escape_string' => ['string', 'connection'=>'\PgSql\Connection', 'string'=>'string'], 'pg_escape_string\'1' => ['string', 'connection'=>'string'], 'pg_exec' => ['\PgSql\Result|false', 'connection'=>'\PgSql\Connection', 'query'=>'string'], 'pg_exec\'1' => ['\PgSql\Result|false', 'connection'=>'string'], 'pg_execute' => ['\PgSql\Result|false', 'connection'=>'\PgSql\Connection', 'statement_name'=>'string', 'params'=>'array'], 'pg_execute\'1' => ['\PgSql\Result|false', 'connection'=>'string', 'statement_name'=>'array'], 'pg_fetch_all' => ['array', 'result'=>'\PgSql\Result', 'mode='=>'int'], 'pg_fetch_all_columns' => ['array', 'result'=>'\PgSql\Result', 'field='=>'int'], 'pg_fetch_array' => ['array|false', 'result'=>'\PgSql\Result', 'row='=>'?int', 'mode='=>'int'], 'pg_fetch_assoc' => ['array|false', 'result'=>'\PgSql\Result', 'row='=>'?int'], 'pg_fetch_object' => ['object|false', 'result'=>'\PgSql\Result', 'row='=>'?int', 'class='=>'string', 'constructor_args='=>'array'], 'pg_fetch_result' => ['string|false|null', 'result'=>'\PgSql\Result', 'row'=>'string|int'], 'pg_fetch_result\'1' => ['string|false|null', 'result'=>'\PgSql\Result', 'row'=>'?int', 'field'=>'string|int'], 'pg_fetch_row' => ['array|false', 'result'=>'\PgSql\Result', 'row='=>'?int', 'mode='=>'int'], 'pg_field_is_null' => ['int|false', 'result'=>'\PgSql\Result', 'row'=>'string|int'], 'pg_field_is_null\'1' => ['int|false', 'result'=>'\PgSql\Result', 'row'=>'int', 'field'=>'string|int'], 'pg_field_name' => ['string', 'result'=>'\PgSql\Result', 'field'=>'int'], 'pg_field_num' => ['int', 'result'=>'\PgSql\Result', 'field'=>'string'], 'pg_field_prtlen' => ['int|false', 'result'=>'\PgSql\Result', 'row'=>'string|int'], 'pg_field_prtlen\'1' => ['int|false', 'result'=>'\PgSql\Result', 'row'=>'int', 'field'=>'string|int'], 'pg_field_size' => ['int', 'result'=>'\PgSql\Result', 'field'=>'int'], 'pg_field_table' => ['string|int|false', 'result'=>'\PgSql\Result', 'field'=>'int', 'oid_only='=>'bool'], 'pg_field_type' => ['string', 'result'=>'\PgSql\Result', 'field'=>'int'], 'pg_field_type_oid' => ['int|string', 'result'=>'\PgSql\Result', 'field'=>'int'], 'pg_flush' => ['int|bool', 'connection'=>'\PgSql\Connection'], 'pg_free_result' => ['bool', 'result'=>'\PgSql\Result'], 'pg_get_notify' => ['array|false', 'connection'=>'\PgSql\Connection', 'mode='=>'int'], 'pg_get_pid' => ['int', 'connection'=>'\PgSql\Connection'], 'pg_get_result' => ['\PgSql\Result|false', 'connection'=>'\PgSql\Connection'], 'pg_host' => ['string', 'connection='=>'?\PgSql\Connection'], 'pg_insert' => ['\PgSql\Result|string|false', 'connection'=>'\PgSql\Connection', 'table_name'=>'string', 'values'=>'array', 'flags='=>'int'], 'pg_last_error' => ['string', 'connection='=>'?\PgSql\Connection'], 'pg_last_notice' => ['string|array|bool', 'connection'=>'\PgSql\Connection', 'mode='=>'int'], 'pg_last_oid' => ['string|int|false', 'result'=>'\PgSql\Result'], 'pg_lo_close' => ['bool', 'lob'=>'\PgSql\Lob'], 'pg_lo_create' => ['int|string|false', 'connection='=>'\PgSql\Connection', 'oid='=>'int|string'], 'pg_lo_export' => ['bool', 'connection'=>'\PgSql\Connection', 'oid'=>'int|string', 'filename'=>'string'], 'pg_lo_export\'1' => ['bool', 'connection'=>'int|string', 'oid'=>'string'], 'pg_lo_import' => ['int|string|false', 'connection'=>'\PgSql\Connection', 'filename'=>'string', 'oid'=>'string|int'], 'pg_lo_import\'1' => ['int|string|false', 'connection'=>'string', 'filename'=>'string|int'], 'pg_lo_open' => ['\PgSql\Lob|false', 'connection'=>'\PgSql\Connection', 'oid'=>'int|string', 'mode'=>'string'], 'pg_lo_open\'1' => ['\PgSql\Lob|false', 'connection'=>'int|string', 'oid'=>'string'], 'pg_lo_read' => ['string|false', 'lob'=>'\PgSql\Lob', 'length='=>'int'], 'pg_lo_read_all' => ['int', 'lob'=>'\PgSql\Lob'], 'pg_lo_seek' => ['bool', 'lob'=>'\PgSql\Lob', 'offset'=>'int', 'whence='=>'int'], 'pg_lo_tell' => ['int', 'lob'=>'\PgSql\Lob'], 'pg_lo_truncate' => ['bool', 'lob'=>'\PgSql\Lob', 'size'=>'int'], 'pg_lo_unlink' => ['bool', 'connection'=>'\PgSql\Connection', 'oid'=>'int|string'], 'pg_lo_unlink\'1' => ['bool', 'connection'=>'int|string'], 'pg_lo_write' => ['int|false', 'lob'=>'\PgSql\Lob', 'data'=>'string', 'length='=>'?int'], 'pg_meta_data' => ['array|false', 'connection'=>'\PgSql\Connection', 'table_name'=>'string', 'extended='=>'bool'], 'pg_num_fields' => ['int', 'result'=>'\PgSql\Result'], 'pg_num_rows' => ['int', 'result'=>'\PgSql\Result'], 'pg_options' => ['string', 'connection='=>'?\PgSql\Connection'], 'pg_parameter_status' => ['string|false', 'connection'=>'\PgSql\Connection', 'name'=>'string'], 'pg_parameter_status\'1' => ['string|false', 'connection'=>'string'], 'pg_pconnect' => ['\PgSql\Connection|false', 'connection_string'=>'string', 'flags='=>'int'], 'pg_ping' => ['bool', 'connection='=>'?\PgSql\Connection'], 'pg_port' => ['string', 'connection='=>'?\PgSql\Connection'], 'pg_prepare' => ['\PgSql\Result|false', 'connection'=>'\PgSql\Connection', 'statement_name'=>'string', 'query'=>'string'], 'pg_prepare\'1' => ['\PgSql\Result|false', 'connection'=>'string', 'statement_name'=>'string'], 'pg_put_line' => ['bool', 'connection'=>'\PgSql\Connection', 'data'=>'string'], 'pg_put_line\'1' => ['bool', 'connection'=>'string'], 'pg_query' => ['\PgSql\Result|false', 'connection'=>'\PgSql\Connection', 'query'=>'string'], 'pg_query\'1' => ['\PgSql\Result|false', 'connection'=>'string'], 'pg_query_params' => ['\PgSql\Result|false', 'connection'=>'\PgSql\Connection', 'query'=>'string', 'params'=>'array'], 'pg_query_params\'1' => ['\PgSql\Result|false', 'connection'=>'string', 'query'=>'array'], 'pg_result_error' => ['string|false', 'result'=>'\PgSql\Result'], 'pg_result_error_field' => ['string|false|null', 'result'=>'\PgSql\Result', 'field_code'=>'int'], 'pg_result_seek' => ['bool', 'result'=>'\PgSql\Result', 'row'=>'int'], 'pg_result_status' => ['string|int', 'result'=>'\PgSql\Result', 'mode='=>'int'], 'pg_select' => ['string|array|false', 'connection'=>'\PgSql\Connection', 'table_name'=>'string', 'conditions'=>'array', 'flags='=>'int', 'mode='=>'int'], 'pg_send_execute' => ['bool|int', 'connection'=>'\PgSql\Connection', 'statement_name'=>'string', 'params'=>'array'], 'pg_send_prepare' => ['bool|int', 'connection'=>'\PgSql\Connection', 'statement_name'=>'string', 'query'=>'string'], 'pg_send_query' => ['bool|int', 'connection'=>'\PgSql\Connection', 'query'=>'string'], 'pg_send_query_params' => ['bool|int', 'connection'=>'\PgSql\Connection', 'query'=>'string', 'params'=>'array'], 'pg_set_client_encoding' => ['int', 'connection'=>'\PgSql\Connection', 'encoding'=>'string'], 'pg_set_client_encoding\'1' => ['int', 'connection'=>'string'], 'pg_set_error_verbosity' => ['int|false', 'connection'=>'\PgSql\Connection', 'verbosity'=>'int'], 'pg_set_error_verbosity\'1' => ['int|false', 'connection'=>'int'], 'pg_socket' => ['resource|false', 'connection'=>'\PgSql\Connection'], 'pg_trace' => ['bool', 'filename'=>'string', 'mode='=>'string', 'connection='=>'?\PgSql\Connection'], 'pg_transaction_status' => ['int', 'connection'=>'\PgSql\Connection'], 'pg_tty' => ['string', 'connection='=>'?\PgSql\Connection'], 'pg_unescape_bytea' => ['string', 'string'=>'string'], 'pg_untrace' => ['bool', 'connection='=>'?\PgSql\Connection'], 'pg_update' => ['string|bool', 'connection'=>'\PgSql\Connection', 'table_name'=>'string', 'values'=>'array', 'conditions'=>'array', 'flags='=>'int'], 'pg_version' => ['array', 'connection='=>'?\PgSql\Connection'], 'Phar::__construct' => ['void', 'filename'=>'string', 'flags='=>'int', 'alias='=>'?string'], 'Phar::addEmptyDir' => ['void', 'directory'=>'string'], 'Phar::addFile' => ['void', 'filename'=>'string', 'localName='=>'?string'], 'Phar::addFromString' => ['void', 'localName'=>'string', 'contents'=>'string'], 'Phar::apiVersion' => ['string'], 'Phar::buildFromDirectory' => ['array', 'directory'=>'string', 'pattern='=>'string'], 'Phar::buildFromIterator' => ['array', 'iterator'=>'Traversable', 'baseDirectory='=>'?string'], 'Phar::canCompress' => ['bool', 'compression='=>'int'], 'Phar::canWrite' => ['bool'], 'Phar::compress' => ['?Phar', 'compression'=>'int', 'extension='=>'?string'], 'Phar::compressFiles' => ['void', 'compression'=>'int'], 'Phar::convertToData' => ['?PharData', 'format='=>'?int', 'compression='=>'?int', 'extension='=>'?string'], 'Phar::convertToExecutable' => ['?Phar', 'format='=>'?int', 'compression='=>'?int', 'extension='=>'?string'], 'Phar::copy' => ['bool', 'from'=>'string', 'to'=>'string'], 'Phar::count' => ['int', 'mode='=>'int'], 'Phar::createDefaultStub' => ['string', 'index='=>'?string', 'webIndex='=>'?string'], 'Phar::decompress' => ['?Phar', 'extension='=>'?string'], 'Phar::decompressFiles' => ['bool'], 'Phar::delete' => ['bool', 'localName'=>'string'], 'Phar::delMetadata' => ['bool'], 'Phar::extractTo' => ['bool', 'directory'=>'string', 'files='=>'string|array|null', 'overwrite='=>'bool'], 'Phar::getAlias' => ['?string'], 'Phar::getMetadata' => ['mixed', 'unserializeOptions='=>'array'], 'Phar::getModified' => ['bool'], 'Phar::getPath' => ['string'], 'Phar::getSignature' => ['array{hash:string, hash_type:string}'], 'Phar::getStub' => ['string'], 'Phar::getSupportedCompression' => ['array'], 'Phar::getSupportedSignatures' => ['array'], 'Phar::getVersion' => ['string'], 'Phar::hasMetadata' => ['bool'], 'Phar::interceptFileFuncs' => ['void'], 'Phar::isBuffering' => ['bool'], 'Phar::isCompressed' => ['int|false'], 'Phar::isFileFormat' => ['bool', 'format'=>'int'], 'Phar::isValidPharFilename' => ['bool', 'filename'=>'string', 'executable='=>'bool'], 'Phar::isWritable' => ['bool'], 'Phar::loadPhar' => ['bool', 'filename'=>'string', 'alias='=>'?string'], 'Phar::mapPhar' => ['bool', 'alias='=>'?string', 'offset='=>'int'], 'Phar::mount' => ['void', 'pharPath'=>'string', 'externalPath'=>'string'], 'Phar::mungServer' => ['void', 'variables'=>'list'], 'Phar::offsetExists' => ['bool', 'localName'=>'string'], 'Phar::offsetGet' => ['PharFileInfo', 'localName'=>'string'], 'Phar::offsetSet' => ['void', 'localName'=>'string', 'value'=>'resource|string'], 'Phar::offsetUnset' => ['void', 'localName'=>'string'], 'Phar::running' => ['string', 'returnPhar='=>'bool'], 'Phar::setAlias' => ['bool', 'alias'=>'string'], 'Phar::setDefaultStub' => ['bool', 'index='=>'?string', 'webIndex='=>'?string'], 'Phar::setMetadata' => ['void', 'metadata'=>''], 'Phar::setSignatureAlgorithm' => ['void', 'algo'=>'int', 'privateKey='=>'?string'], 'Phar::setStub' => ['bool', 'stub'=>'string', 'length='=>'int'], 'Phar::startBuffering' => ['void'], 'Phar::stopBuffering' => ['void'], 'Phar::unlinkArchive' => ['bool', 'filename'=>'string'], 'Phar::webPhar' => ['void', 'alias='=>'?string', 'index='=>'?string', 'fileNotFoundScript='=>'?string', 'mimeTypes='=>'array', 'rewrite='=>'?callable'], 'PharData::__construct' => ['void', 'filename'=>'string', 'flags='=>'int', 'alias='=>'?string', 'format='=>'int'], 'PharData::addEmptyDir' => ['void', 'directory'=>'string'], 'PharData::addFile' => ['void', 'filename'=>'string', 'localName='=>'?string'], 'PharData::addFromString' => ['void', 'localName'=>'string', 'contents'=>'string'], 'PharData::buildFromDirectory' => ['array', 'directory'=>'string', 'pattern='=>'string'], 'PharData::buildFromIterator' => ['array', 'iterator'=>'Traversable', 'baseDirectory='=>'?string'], 'PharData::compress' => ['?PharData', 'compression'=>'int', 'extension='=>'?string'], 'PharData::compressFiles' => ['void', 'compression'=>'int'], 'PharData::convertToData' => ['?PharData', 'format='=>'?int', 'compression='=>'?int', 'extension='=>'?string'], 'PharData::convertToExecutable' => ['?Phar', 'format='=>'?int', 'compression='=>'?int', 'extension='=>'?string'], 'PharData::copy' => ['bool', 'from'=>'string', 'to'=>'string'], 'PharData::decompress' => ['?PharData', 'extension='=>'?string'], 'PharData::decompressFiles' => ['bool'], 'PharData::delete' => ['bool', 'localName'=>'string'], 'PharData::delMetadata' => ['bool'], 'PharData::extractTo' => ['bool', 'directory'=>'string', 'files='=>'string|array|null', 'overwrite='=>'bool'], 'PharData::isWritable' => ['bool'], 'PharData::offsetExists' => ['bool', 'localName'=>'string'], 'PharData::offsetGet' => ['PharFileInfo', 'localName'=>'string'], 'PharData::offsetSet' => ['void', 'localName'=>'string', 'value'=>'string'], 'PharData::offsetUnset' => ['void', 'localName'=>'string'], 'PharData::setAlias' => ['bool', 'alias'=>'string'], 'PharData::setDefaultStub' => ['bool', 'index='=>'?string', 'webIndex='=>'?string'], 'PharData::setMetadata' => ['void', 'metadata'=>'mixed'], 'PharData::setSignatureAlgorithm' => ['void', 'algo'=>'int', 'privateKey='=>'?string'], 'PharData::setStub' => ['bool', 'stub'=>'string', 'length='=>'int'], 'PharFileInfo::__construct' => ['void', 'filename'=>'string'], 'PharFileInfo::chmod' => ['void', 'perms'=>'int'], 'PharFileInfo::compress' => ['bool', 'compression'=>'int'], 'PharFileInfo::decompress' => ['bool'], 'PharFileInfo::delMetadata' => ['bool'], 'PharFileInfo::getCompressedSize' => ['int'], 'PharFileInfo::getContent' => ['string'], 'PharFileInfo::getCRC32' => ['int'], 'PharFileInfo::getMetadata' => ['mixed', 'unserializeOptions='=>'array'], 'PharFileInfo::getPharFlags' => ['int'], 'PharFileInfo::hasMetadata' => ['bool'], 'PharFileInfo::isCompressed' => ['bool', 'compression='=>'?int'], 'PharFileInfo::isCRCChecked' => ['bool'], 'PharFileInfo::setMetadata' => ['void', 'metadata'=>'mixed'], 'phdfs::__construct' => ['void', 'ip'=>'string', 'port'=>'string'], 'phdfs::__destruct' => ['void'], 'phdfs::connect' => ['bool'], 'phdfs::copy' => ['bool', 'source_file'=>'string', 'destination_file'=>'string'], 'phdfs::create_directory' => ['bool', 'path'=>'string'], 'phdfs::delete' => ['bool', 'path'=>'string'], 'phdfs::disconnect' => ['bool'], 'phdfs::exists' => ['bool', 'path'=>'string'], 'phdfs::file_info' => ['array', 'path'=>'string'], 'phdfs::list_directory' => ['array', 'path'=>'string'], 'phdfs::read' => ['string', 'path'=>'string', 'length='=>'string'], 'phdfs::rename' => ['bool', 'old_path'=>'string', 'new_path'=>'string'], 'phdfs::tell' => ['int', 'path'=>'string'], 'phdfs::write' => ['bool', 'path'=>'string', 'buffer'=>'string', 'mode='=>'string'], 'php_check_syntax' => ['bool', 'filename'=>'string', 'error_message='=>'string'], 'php_ini_loaded_file' => ['string|false'], 'php_ini_scanned_files' => ['string|false'], 'php_logo_guid' => ['string'], 'php_sapi_name' => ['string'], 'php_strip_whitespace' => ['string', 'filename'=>'string'], 'php_uname' => ['string', 'mode='=>'string'], 'php_user_filter::filter' => ['int', 'in'=>'resource', 'out'=>'resource', '&rw_consumed'=>'int', 'closing'=>'bool'], 'php_user_filter::onClose' => ['void'], 'php_user_filter::onCreate' => ['bool'], 'phpcredits' => ['true', 'flags='=>'int'], 'phpdbg_break_file' => ['void', 'file'=>'string', 'line'=>'int'], 'phpdbg_break_function' => ['void', 'function'=>'string'], 'phpdbg_break_method' => ['void', 'class'=>'string', 'method'=>'string'], 'phpdbg_break_next' => ['void'], 'phpdbg_clear' => ['void'], 'phpdbg_color' => ['void', 'element'=>'int', 'color'=>'string'], 'phpdbg_end_oplog' => ['array', 'options='=>'array'], 'phpdbg_exec' => ['mixed', 'context='=>'string'], 'phpdbg_get_executable' => ['array', 'options='=>'array'], 'phpdbg_prompt' => ['void', 'string'=>'string'], 'phpdbg_start_oplog' => ['void'], 'phpinfo' => ['true', 'flags='=>'int'], 'PhpToken::tokenize' => ['list', 'code'=>'string', 'flags='=>'int'], 'PhpToken::is' => ['bool', 'kind'=>'string|int|string[]|int[]'], 'PhpToken::isIgnorable' => ['bool'], 'PhpToken::getTokenName' => ['?string'], 'phpversion' => ['string|false', 'extension='=>'?string'], 'pht\AtomicInteger::__construct' => ['void', 'value='=>'int'], 'pht\AtomicInteger::dec' => ['void'], 'pht\AtomicInteger::get' => ['int'], 'pht\AtomicInteger::inc' => ['void'], 'pht\AtomicInteger::lock' => ['void'], 'pht\AtomicInteger::set' => ['void', 'value'=>'int'], 'pht\AtomicInteger::unlock' => ['void'], 'pht\HashTable::lock' => ['void'], 'pht\HashTable::size' => ['int'], 'pht\HashTable::unlock' => ['void'], 'pht\Queue::front' => ['mixed'], 'pht\Queue::lock' => ['void'], 'pht\Queue::pop' => ['mixed'], 'pht\Queue::push' => ['void', 'value'=>'mixed'], 'pht\Queue::size' => ['int'], 'pht\Queue::unlock' => ['void'], 'pht\Runnable::run' => ['void'], 'pht\thread::addClassTask' => ['void', 'className'=>'string', '...ctorArgs='=>'mixed'], 'pht\thread::addFileTask' => ['void', 'fileName'=>'string', '...globals='=>'mixed'], 'pht\thread::addFunctionTask' => ['void', 'func'=>'callable', '...funcArgs='=>'mixed'], 'pht\thread::join' => ['void'], 'pht\thread::start' => ['void'], 'pht\thread::taskCount' => ['int'], 'pht\threaded::lock' => ['void'], 'pht\threaded::unlock' => ['void'], 'pht\Vector::__construct' => ['void', 'size='=>'int', 'value='=>'mixed'], 'pht\Vector::deleteAt' => ['void', 'offset'=>'int'], 'pht\Vector::insertAt' => ['void', 'value'=>'mixed', 'offset'=>'int'], 'pht\Vector::lock' => ['void'], 'pht\Vector::pop' => ['mixed'], 'pht\Vector::push' => ['void', 'value'=>'mixed'], 'pht\Vector::resize' => ['void', 'size'=>'int', 'value='=>'mixed'], 'pht\Vector::shift' => ['mixed'], 'pht\Vector::size' => ['int'], 'pht\Vector::unlock' => ['void'], 'pht\Vector::unshift' => ['void', 'value'=>'mixed'], 'pht\Vector::updateAt' => ['void', 'value'=>'mixed', 'offset'=>'int'], 'pi' => ['float'], 'pointObj::__construct' => ['void'], 'pointObj::distanceToLine' => ['float', 'p1'=>'pointObj', 'p2'=>'pointObj'], 'pointObj::distanceToPoint' => ['float', 'poPoint'=>'pointObj'], 'pointObj::distanceToShape' => ['float', 'shape'=>'shapeObj'], 'pointObj::draw' => ['int', 'map'=>'mapObj', 'layer'=>'layerObj', 'img'=>'imageObj', 'class_index'=>'int', 'text'=>'string'], 'pointObj::ms_newPointObj' => ['pointObj'], 'pointObj::project' => ['int', 'in'=>'projectionObj', 'out'=>'projectionObj'], 'pointObj::setXY' => ['int', 'x'=>'float', 'y'=>'float', 'm'=>'float'], 'pointObj::setXYZ' => ['int', 'x'=>'float', 'y'=>'float', 'z'=>'float', 'm'=>'float'], 'Pool::__construct' => ['void', 'size'=>'int', 'class'=>'string', 'ctor='=>'array'], 'Pool::collect' => ['int', 'collector='=>'Callable'], 'Pool::resize' => ['void', 'size'=>'int'], 'Pool::shutdown' => ['void'], 'Pool::submit' => ['int', 'task'=>'Threaded'], 'Pool::submitTo' => ['int', 'worker'=>'int', 'task'=>'Threaded'], 'popen' => ['resource|false', 'command'=>'string', 'mode'=>'string'], 'pos' => ['mixed', 'array'=>'array'], 'posix_access' => ['bool', 'filename'=>'string', 'flags='=>'int'], 'posix_ctermid' => ['string|false'], 'posix_errno' => ['int'], 'posix_get_last_error' => ['int'], 'posix_getcwd' => ['string|false'], 'posix_getegid' => ['int'], 'posix_geteuid' => ['int'], 'posix_getgid' => ['int'], 'posix_getgrgid' => ['array{name: string, passwd: string, gid: int, members: list}|false', 'group_id'=>'int'], 'posix_getgrnam' => ['array{name: string, passwd: string, gid: int, members: list}|false', 'name'=>'string'], 'posix_getgroups' => ['list|false'], 'posix_getlogin' => ['string|false'], 'posix_getpgid' => ['int|false', 'process_id'=>'int'], 'posix_getpgrp' => ['int'], 'posix_getpid' => ['int'], 'posix_getppid' => ['int'], 'posix_getpwnam' => ['array{name: string, passwd: string, uid: int, gid: int, gecos: string, dir: string, shell: string}|false', 'username'=>'string'], 'posix_getpwuid' => ['array{name: string, passwd: string, uid: int, gid: int, gecos: string, dir: string, shell: string}|false', 'user_id'=>'int'], 'posix_getrlimit' => ['array{"soft core": string, "hard core": string, "soft data": string, "hard data": string, "soft stack": integer, "hard stack": string, "soft totalmem": string, "hard totalmem": string, "soft rss": string, "hard rss": string, "soft maxproc": integer, "hard maxproc": integer, "soft memlock": integer, "hard memlock": integer, "soft cpu": string, "hard cpu": string, "soft filesize": string, "hard filesize": string, "soft openfiles": integer, "hard openfiles": integer}|false', 'resource=' => '?int'], 'posix_getsid' => ['int|false', 'process_id'=>'int'], 'posix_getuid' => ['int'], 'posix_initgroups' => ['bool', 'username'=>'string', 'group_id'=>'int'], 'posix_isatty' => ['bool', 'file_descriptor'=>'resource|int'], 'posix_kill' => ['bool', 'process_id'=>'int', 'signal'=>'int'], 'posix_mkfifo' => ['bool', 'filename'=>'string', 'permissions'=>'int'], 'posix_mknod' => ['bool', 'filename'=>'string', 'flags'=>'int', 'major='=>'int', 'minor='=>'int'], 'posix_setegid' => ['bool', 'group_id'=>'int'], 'posix_seteuid' => ['bool', 'user_id'=>'int'], 'posix_setgid' => ['bool', 'group_id'=>'int'], 'posix_setpgid' => ['bool', 'process_id'=>'int', 'process_group_id'=>'int'], 'posix_setrlimit' => ['bool', 'resource'=>'int', 'soft_limit'=>'int', 'hard_limit'=>'int'], 'posix_setsid' => ['int'], 'posix_setuid' => ['bool', 'user_id'=>'int'], 'posix_strerror' => ['string', 'error_code'=>'int'], 'posix_times' => ['array{ticks: int, utime: int, stime: int, cutime: int, cstime: int}|false'], 'posix_ttyname' => ['string|false', 'file_descriptor'=>'resource|int'], 'posix_uname' => ['array{sysname: string, nodename: string, release: string, version: string, machine: string, domainname: string}|false'], 'Postal\Expand::expand_address' => ['string[]', 'address'=>'string', 'options='=>'array'], 'Postal\Parser::parse_address' => ['array', 'address'=>'string', 'options='=>'array'], 'pow' => ['float|int', 'num'=>'int|float', 'exponent'=>'int|float'], 'preg_filter' => ['string|string[]|null', 'pattern'=>'string|string[]', 'replacement'=>'string|string[]', 'subject'=>'string|string[]', 'limit='=>'int', '&w_count='=>'int'], 'preg_grep' => ['array|false', 'pattern'=>'string', 'array'=>'array', 'flags='=>'int'], 'preg_last_error' => ['int'], 'preg_match' => ['0|1|false', 'pattern'=>'string', 'subject'=>'string', '&w_matches='=>'string[]', 'flags='=>'0', 'offset='=>'int'], 'preg_match\'1' => ['0|1|false', 'pattern'=>'string', 'subject'=>'string', '&w_matches='=>'array', 'flags='=>'int', 'offset='=>'int'], 'preg_match_all' => ['int<0,max>|false', 'pattern'=>'string', 'subject'=>'string', '&w_matches='=>'array', 'flags='=>'int', 'offset='=>'int'], 'preg_quote' => ['string', 'str'=>'string', 'delimiter='=>'?string'], 'preg_replace' => ['string|string[]|null', 'pattern'=>'string|array', 'replacement'=>'string|array', 'subject'=>'string|array', 'limit='=>'int', '&w_count='=>'int'], 'preg_replace_callback' => ['string|null', 'pattern'=>'string|array', 'callback'=>'callable(string[]):string', 'subject'=>'string', 'limit='=>'int', '&w_count='=>'int', 'flags='=>'int'], 'preg_replace_callback\'1' => ['string[]|null', 'pattern'=>'string|array', 'callback'=>'callable(string[]):string', 'subject'=>'string[]', 'limit='=>'int', '&w_count='=>'int', 'flags='=>'int'], 'preg_replace_callback_array' => ['string|null', 'pattern'=>'array', 'subject'=>'string', 'limit='=>'int', '&w_count='=>'int', 'flags='=>'int'], 'preg_replace_callback_array\'1' => ['string[]|null', 'pattern'=>'array', 'subject'=>'string[]', 'limit='=>'int', '&w_count='=>'int', 'flags='=>'int'], 'preg_split' => ['list|false', 'pattern'=>'string', 'subject'=>'string', 'limit'=>'int', 'flags='=>'null'], 'preg_split\'1' => ['list|list>|false', 'pattern'=>'string', 'subject'=>'string', 'limit='=>'int', 'flags='=>'int'], 'prev' => ['mixed', '&r_array'=>'array'], 'print' => ['int', 'arg'=>'string'], 'print_r' => ['string', 'value'=>'mixed'], 'print_r\'1' => ['true', 'value'=>'mixed', 'return='=>'bool'], 'printf' => ['int<0, max>', 'format'=>'string', '...values='=>'string|int|float'], 'proc_close' => ['int', 'process'=>'resource'], 'proc_get_status' => ['array{command: string, pid: int, running: bool, signaled: bool, stopped: bool, exitcode: int, termsig: int, stopsig: int}', 'process'=>'resource'], 'proc_nice' => ['bool', 'priority'=>'int'], 'proc_open' => ['resource|false', 'command'=>'string|array', 'descriptor_spec'=>'array', '&pipes'=>'resource[]', 'cwd='=>'?string', 'env_vars='=>'?array', 'options='=>'?array'], 'proc_terminate' => ['bool', 'process'=>'resource', 'signal='=>'int'], 'projectionObj::__construct' => ['void', 'projectionString'=>'string'], 'projectionObj::getUnits' => ['int'], 'projectionObj::ms_newProjectionObj' => ['projectionObj', 'projectionString'=>'string'], 'property_exists' => ['bool', 'object_or_class'=>'object|string', 'property'=>'string'], 'ps_add_bookmark' => ['int', 'psdoc'=>'resource', 'text'=>'string', 'parent='=>'int', 'open='=>'int'], 'ps_add_launchlink' => ['bool', 'psdoc'=>'resource', 'llx'=>'float', 'lly'=>'float', 'urx'=>'float', 'ury'=>'float', 'filename'=>'string'], 'ps_add_locallink' => ['bool', 'psdoc'=>'resource', 'llx'=>'float', 'lly'=>'float', 'urx'=>'float', 'ury'=>'float', 'page'=>'int', 'dest'=>'string'], 'ps_add_note' => ['bool', 'psdoc'=>'resource', 'llx'=>'float', 'lly'=>'float', 'urx'=>'float', 'ury'=>'float', 'contents'=>'string', 'title'=>'string', 'icon'=>'string', 'open'=>'int'], 'ps_add_pdflink' => ['bool', 'psdoc'=>'resource', 'llx'=>'float', 'lly'=>'float', 'urx'=>'float', 'ury'=>'float', 'filename'=>'string', 'page'=>'int', 'dest'=>'string'], 'ps_add_weblink' => ['bool', 'psdoc'=>'resource', 'llx'=>'float', 'lly'=>'float', 'urx'=>'float', 'ury'=>'float', 'url'=>'string'], 'ps_arc' => ['bool', 'psdoc'=>'resource', 'x'=>'float', 'y'=>'float', 'radius'=>'float', 'alpha'=>'float', 'beta'=>'float'], 'ps_arcn' => ['bool', 'psdoc'=>'resource', 'x'=>'float', 'y'=>'float', 'radius'=>'float', 'alpha'=>'float', 'beta'=>'float'], 'ps_begin_page' => ['bool', 'psdoc'=>'resource', 'width'=>'float', 'height'=>'float'], 'ps_begin_pattern' => ['int', 'psdoc'=>'resource', 'width'=>'float', 'height'=>'float', 'xstep'=>'float', 'ystep'=>'float', 'painttype'=>'int'], 'ps_begin_template' => ['int', 'psdoc'=>'resource', 'width'=>'float', 'height'=>'float'], 'ps_circle' => ['bool', 'psdoc'=>'resource', 'x'=>'float', 'y'=>'float', 'radius'=>'float'], 'ps_clip' => ['bool', 'psdoc'=>'resource'], 'ps_close' => ['bool', 'psdoc'=>'resource'], 'ps_close_image' => ['void', 'psdoc'=>'resource', 'imageid'=>'int'], 'ps_closepath' => ['bool', 'psdoc'=>'resource'], 'ps_closepath_stroke' => ['bool', 'psdoc'=>'resource'], 'ps_continue_text' => ['bool', 'psdoc'=>'resource', 'text'=>'string'], 'ps_curveto' => ['bool', 'psdoc'=>'resource', 'x1'=>'float', 'y1'=>'float', 'x2'=>'float', 'y2'=>'float', 'x3'=>'float', 'y3'=>'float'], 'ps_delete' => ['bool', 'psdoc'=>'resource'], 'ps_end_page' => ['bool', 'psdoc'=>'resource'], 'ps_end_pattern' => ['bool', 'psdoc'=>'resource'], 'ps_end_template' => ['bool', 'psdoc'=>'resource'], 'ps_fill' => ['bool', 'psdoc'=>'resource'], 'ps_fill_stroke' => ['bool', 'psdoc'=>'resource'], 'ps_findfont' => ['int', 'psdoc'=>'resource', 'fontname'=>'string', 'encoding'=>'string', 'embed='=>'bool'], 'ps_get_buffer' => ['string', 'psdoc'=>'resource'], 'ps_get_parameter' => ['string', 'psdoc'=>'resource', 'name'=>'string', 'modifier='=>'float'], 'ps_get_value' => ['float', 'psdoc'=>'resource', 'name'=>'string', 'modifier='=>'float'], 'ps_hyphenate' => ['array', 'psdoc'=>'resource', 'text'=>'string'], 'ps_include_file' => ['bool', 'psdoc'=>'resource', 'file'=>'string'], 'ps_lineto' => ['bool', 'psdoc'=>'resource', 'x'=>'float', 'y'=>'float'], 'ps_makespotcolor' => ['int', 'psdoc'=>'resource', 'name'=>'string', 'reserved='=>'int'], 'ps_moveto' => ['bool', 'psdoc'=>'resource', 'x'=>'float', 'y'=>'float'], 'ps_new' => ['resource'], 'ps_open_file' => ['bool', 'psdoc'=>'resource', 'filename='=>'string'], 'ps_open_image' => ['int', 'psdoc'=>'resource', 'type'=>'string', 'source'=>'string', 'data'=>'string', 'length'=>'int', 'width'=>'int', 'height'=>'int', 'components'=>'int', 'bpc'=>'int', 'params'=>'string'], 'ps_open_image_file' => ['int', 'psdoc'=>'resource', 'type'=>'string', 'filename'=>'string', 'stringparam='=>'string', 'intparam='=>'int'], 'ps_open_memory_image' => ['int', 'psdoc'=>'resource', 'gd'=>'int'], 'ps_place_image' => ['bool', 'psdoc'=>'resource', 'imageid'=>'int', 'x'=>'float', 'y'=>'float', 'scale'=>'float'], 'ps_rect' => ['bool', 'psdoc'=>'resource', 'x'=>'float', 'y'=>'float', 'width'=>'float', 'height'=>'float'], 'ps_restore' => ['bool', 'psdoc'=>'resource'], 'ps_rotate' => ['bool', 'psdoc'=>'resource', 'rot'=>'float'], 'ps_save' => ['bool', 'psdoc'=>'resource'], 'ps_scale' => ['bool', 'psdoc'=>'resource', 'x'=>'float', 'y'=>'float'], 'ps_set_border_color' => ['bool', 'psdoc'=>'resource', 'red'=>'float', 'green'=>'float', 'blue'=>'float'], 'ps_set_border_dash' => ['bool', 'psdoc'=>'resource', 'black'=>'float', 'white'=>'float'], 'ps_set_border_style' => ['bool', 'psdoc'=>'resource', 'style'=>'string', 'width'=>'float'], 'ps_set_info' => ['bool', 'p'=>'resource', 'key'=>'string', 'value'=>'string'], 'ps_set_parameter' => ['bool', 'psdoc'=>'resource', 'name'=>'string', 'value'=>'string'], 'ps_set_text_pos' => ['bool', 'psdoc'=>'resource', 'x'=>'float', 'y'=>'float'], 'ps_set_value' => ['bool', 'psdoc'=>'resource', 'name'=>'string', 'value'=>'float'], 'ps_setcolor' => ['bool', 'psdoc'=>'resource', 'type'=>'string', 'colorspace'=>'string', 'c1'=>'float', 'c2'=>'float', 'c3'=>'float', 'c4'=>'float'], 'ps_setdash' => ['bool', 'psdoc'=>'resource', 'on'=>'float', 'off'=>'float'], 'ps_setflat' => ['bool', 'psdoc'=>'resource', 'value'=>'float'], 'ps_setfont' => ['bool', 'psdoc'=>'resource', 'fontid'=>'int', 'size'=>'float'], 'ps_setgray' => ['bool', 'psdoc'=>'resource', 'gray'=>'float'], 'ps_setlinecap' => ['bool', 'psdoc'=>'resource', 'type'=>'int'], 'ps_setlinejoin' => ['bool', 'psdoc'=>'resource', 'type'=>'int'], 'ps_setlinewidth' => ['bool', 'psdoc'=>'resource', 'width'=>'float'], 'ps_setmiterlimit' => ['bool', 'psdoc'=>'resource', 'value'=>'float'], 'ps_setoverprintmode' => ['bool', 'psdoc'=>'resource', 'mode'=>'int'], 'ps_setpolydash' => ['bool', 'psdoc'=>'resource', 'arr'=>'float'], 'ps_shading' => ['int', 'psdoc'=>'resource', 'type'=>'string', 'x0'=>'float', 'y0'=>'float', 'x1'=>'float', 'y1'=>'float', 'c1'=>'float', 'c2'=>'float', 'c3'=>'float', 'c4'=>'float', 'optlist'=>'string'], 'ps_shading_pattern' => ['int', 'psdoc'=>'resource', 'shadingid'=>'int', 'optlist'=>'string'], 'ps_shfill' => ['bool', 'psdoc'=>'resource', 'shadingid'=>'int'], 'ps_show' => ['bool', 'psdoc'=>'resource', 'text'=>'string'], 'ps_show2' => ['bool', 'psdoc'=>'resource', 'text'=>'string', 'length'=>'int'], 'ps_show_boxed' => ['int', 'psdoc'=>'resource', 'text'=>'string', 'left'=>'float', 'bottom'=>'float', 'width'=>'float', 'height'=>'float', 'hmode'=>'string', 'feature='=>'string'], 'ps_show_xy' => ['bool', 'psdoc'=>'resource', 'text'=>'string', 'x'=>'float', 'y'=>'float'], 'ps_show_xy2' => ['bool', 'psdoc'=>'resource', 'text'=>'string', 'length'=>'int', 'xcoor'=>'float', 'ycoor'=>'float'], 'ps_string_geometry' => ['array', 'psdoc'=>'resource', 'text'=>'string', 'fontid='=>'int', 'size='=>'float'], 'ps_stringwidth' => ['float', 'psdoc'=>'resource', 'text'=>'string', 'fontid='=>'int', 'size='=>'float'], 'ps_stroke' => ['bool', 'psdoc'=>'resource'], 'ps_symbol' => ['bool', 'psdoc'=>'resource', 'ord'=>'int'], 'ps_symbol_name' => ['string', 'psdoc'=>'resource', 'ord'=>'int', 'fontid='=>'int'], 'ps_symbol_width' => ['float', 'psdoc'=>'resource', 'ord'=>'int', 'fontid='=>'int', 'size='=>'float'], 'ps_translate' => ['bool', 'psdoc'=>'resource', 'x'=>'float', 'y'=>'float'], 'pspell_add_to_personal' => ['bool', 'dictionary'=>'PSpell\Dictionary', 'word'=>'string'], 'pspell_add_to_session' => ['bool', 'dictionary'=>'PSpell\Dictionary', 'word'=>'string'], 'pspell_check' => ['bool', 'dictionary'=>'PSpell\Dictionary', 'word'=>'string'], 'pspell_clear_session' => ['bool', 'dictionary'=>'PSpell\Dictionary'], 'pspell_config_create' => ['PSpell\Config', 'language'=>'string', 'spelling='=>'string', 'jargon='=>'string', 'encoding='=>'string'], 'pspell_config_data_dir' => ['bool', 'config'=>'PSpell\Config', 'directory'=>'string'], 'pspell_config_dict_dir' => ['bool', 'config'=>'PSpell\Config', 'directory'=>'string'], 'pspell_config_ignore' => ['bool', 'config'=>'PSpell\Config', 'min_length'=>'int'], 'pspell_config_mode' => ['bool', 'config'=>'PSpell\Config', 'mode'=>'int'], 'pspell_config_personal' => ['bool', 'config'=>'PSpell\Config', 'filename'=>'string'], 'pspell_config_repl' => ['bool', 'config'=>'PSpell\Config', 'filename'=>'string'], 'pspell_config_runtogether' => ['bool', 'config'=>'PSpell\Config', 'allow'=>'bool'], 'pspell_config_save_repl' => ['bool', 'config'=>'PSpell\Config', 'save'=>'bool'], 'pspell_new' => ['PSpell\Dictionary|false', 'language'=>'string', 'spelling='=>'string', 'jargon='=>'string', 'encoding='=>'string', 'mode='=>'int'], 'pspell_new_config' => ['PSpell\Dictionary|false', 'config'=>'PSpell\Config'], 'pspell_new_personal' => ['PSpell\Dictionary|false', 'filename'=>'string', 'language'=>'string', 'spelling='=>'string', 'jargon='=>'string', 'encoding='=>'string', 'mode='=>'int'], 'pspell_save_wordlist' => ['bool', 'dictionary'=>'PSpell\Dictionary'], 'pspell_store_replacement' => ['bool', 'dictionary'=>'PSpell\Dictionary', 'misspelled'=>'string', 'correct'=>'string'], 'pspell_suggest' => ['array', 'dictionary'=>'PSpell\Dictionary', 'word'=>'string'], 'putenv' => ['bool', 'assignment'=>'string'], 'px_close' => ['bool', 'pxdoc'=>'resource'], 'px_create_fp' => ['bool', 'pxdoc'=>'resource', 'file'=>'resource', 'fielddesc'=>'array'], 'px_date2string' => ['string', 'pxdoc'=>'resource', 'value'=>'int', 'format'=>'string'], 'px_delete' => ['bool', 'pxdoc'=>'resource'], 'px_delete_record' => ['bool', 'pxdoc'=>'resource', 'num'=>'int'], 'px_get_field' => ['array', 'pxdoc'=>'resource', 'fieldno'=>'int'], 'px_get_info' => ['array', 'pxdoc'=>'resource'], 'px_get_parameter' => ['string', 'pxdoc'=>'resource', 'name'=>'string'], 'px_get_record' => ['array', 'pxdoc'=>'resource', 'num'=>'int', 'mode='=>'int'], 'px_get_schema' => ['array', 'pxdoc'=>'resource', 'mode='=>'int'], 'px_get_value' => ['float', 'pxdoc'=>'resource', 'name'=>'string'], 'px_insert_record' => ['int', 'pxdoc'=>'resource', 'data'=>'array'], 'px_new' => ['resource'], 'px_numfields' => ['int', 'pxdoc'=>'resource'], 'px_numrecords' => ['int', 'pxdoc'=>'resource'], 'px_open_fp' => ['bool', 'pxdoc'=>'resource', 'file'=>'resource'], 'px_put_record' => ['bool', 'pxdoc'=>'resource', 'record'=>'array', 'recpos='=>'int'], 'px_retrieve_record' => ['array', 'pxdoc'=>'resource', 'num'=>'int', 'mode='=>'int'], 'px_set_blob_file' => ['bool', 'pxdoc'=>'resource', 'filename'=>'string'], 'px_set_parameter' => ['bool', 'pxdoc'=>'resource', 'name'=>'string', 'value'=>'string'], 'px_set_tablename' => ['void', 'pxdoc'=>'resource', 'name'=>'string'], 'px_set_targetencoding' => ['bool', 'pxdoc'=>'resource', 'encoding'=>'string'], 'px_set_value' => ['bool', 'pxdoc'=>'resource', 'name'=>'string', 'value'=>'float'], 'px_timestamp2string' => ['string', 'pxdoc'=>'resource', 'value'=>'float', 'format'=>'string'], 'px_update_record' => ['bool', 'pxdoc'=>'resource', 'data'=>'array', 'num'=>'int'], 'qdom_error' => ['string'], 'qdom_tree' => ['QDomDocument', 'doc'=>'string'], 'querymapObj::convertToString' => ['string'], 'querymapObj::free' => ['void'], 'querymapObj::set' => ['int', 'property_name'=>'string', 'new_value'=>''], 'querymapObj::updateFromString' => ['int', 'snippet'=>'string'], 'QuickHashIntHash::__construct' => ['void', 'size'=>'int', 'options='=>'int'], 'QuickHashIntHash::add' => ['bool', 'key'=>'int', 'value='=>'int'], 'QuickHashIntHash::delete' => ['bool', 'key'=>'int'], 'QuickHashIntHash::exists' => ['bool', 'key'=>'int'], 'QuickHashIntHash::get' => ['int', 'key'=>'int'], 'QuickHashIntHash::getSize' => ['int'], 'QuickHashIntHash::loadFromFile' => ['QuickHashIntHash', 'filename'=>'string', 'options='=>'int'], 'QuickHashIntHash::loadFromString' => ['QuickHashIntHash', 'contents'=>'string', 'options='=>'int'], 'QuickHashIntHash::saveToFile' => ['void', 'filename'=>'string'], 'QuickHashIntHash::saveToString' => ['string'], 'QuickHashIntHash::set' => ['bool', 'key'=>'int', 'value'=>'int'], 'QuickHashIntHash::update' => ['bool', 'key'=>'int', 'value'=>'int'], 'QuickHashIntSet::__construct' => ['void', 'size'=>'int', 'options='=>'int'], 'QuickHashIntSet::add' => ['bool', 'key'=>'int'], 'QuickHashIntSet::delete' => ['bool', 'key'=>'int'], 'QuickHashIntSet::exists' => ['bool', 'key'=>'int'], 'QuickHashIntSet::getSize' => ['int'], 'QuickHashIntSet::loadFromFile' => ['QuickHashIntSet', 'filename'=>'string', 'size='=>'int', 'options='=>'int'], 'QuickHashIntSet::loadFromString' => ['QuickHashIntSet', 'contents'=>'string', 'size='=>'int', 'options='=>'int'], 'QuickHashIntSet::saveToFile' => ['void', 'filename'=>'string'], 'QuickHashIntSet::saveToString' => ['string'], 'QuickHashIntStringHash::__construct' => ['void', 'size'=>'int', 'options='=>'int'], 'QuickHashIntStringHash::add' => ['bool', 'key'=>'int', 'value'=>'string'], 'QuickHashIntStringHash::delete' => ['bool', 'key'=>'int'], 'QuickHashIntStringHash::exists' => ['bool', 'key'=>'int'], 'QuickHashIntStringHash::get' => ['mixed', 'key'=>'int'], 'QuickHashIntStringHash::getSize' => ['int'], 'QuickHashIntStringHash::loadFromFile' => ['QuickHashIntStringHash', 'filename'=>'string', 'size='=>'int', 'options='=>'int'], 'QuickHashIntStringHash::loadFromString' => ['QuickHashIntStringHash', 'contents'=>'string', 'size='=>'int', 'options='=>'int'], 'QuickHashIntStringHash::saveToFile' => ['void', 'filename'=>'string'], 'QuickHashIntStringHash::saveToString' => ['string'], 'QuickHashIntStringHash::set' => ['int', 'key'=>'int', 'value'=>'string'], 'QuickHashIntStringHash::update' => ['bool', 'key'=>'int', 'value'=>'string'], 'QuickHashStringIntHash::__construct' => ['void', 'size'=>'int', 'options='=>'int'], 'QuickHashStringIntHash::add' => ['bool', 'key'=>'string', 'value'=>'int'], 'QuickHashStringIntHash::delete' => ['bool', 'key'=>'string'], 'QuickHashStringIntHash::exists' => ['bool', 'key'=>'string'], 'QuickHashStringIntHash::get' => ['mixed', 'key'=>'string'], 'QuickHashStringIntHash::getSize' => ['int'], 'QuickHashStringIntHash::loadFromFile' => ['QuickHashStringIntHash', 'filename'=>'string', 'size='=>'int', 'options='=>'int'], 'QuickHashStringIntHash::loadFromString' => ['QuickHashStringIntHash', 'contents'=>'string', 'size='=>'int', 'options='=>'int'], 'QuickHashStringIntHash::saveToFile' => ['void', 'filename'=>'string'], 'QuickHashStringIntHash::saveToString' => ['string'], 'QuickHashStringIntHash::set' => ['int', 'key'=>'string', 'value'=>'int'], 'QuickHashStringIntHash::update' => ['bool', 'key'=>'string', 'value'=>'int'], 'quoted_printable_decode' => ['string', 'string'=>'string'], 'quoted_printable_encode' => ['string', 'string'=>'string'], 'quotemeta' => ['string', 'string'=>'string'], 'rad2deg' => ['float', 'num'=>'float'], 'radius_acct_open' => ['resource|false'], 'radius_add_server' => ['bool', 'radius_handle'=>'resource', 'hostname'=>'string', 'port'=>'int', 'secret'=>'string', 'timeout'=>'int', 'max_tries'=>'int'], 'radius_auth_open' => ['resource|false'], 'radius_close' => ['bool', 'radius_handle'=>'resource'], 'radius_config' => ['bool', 'radius_handle'=>'resource', 'file'=>'string'], 'radius_create_request' => ['bool', 'radius_handle'=>'resource', 'type'=>'int'], 'radius_cvt_addr' => ['string', 'data'=>'string'], 'radius_cvt_int' => ['int', 'data'=>'string'], 'radius_cvt_string' => ['string', 'data'=>'string'], 'radius_demangle' => ['string', 'radius_handle'=>'resource', 'mangled'=>'string'], 'radius_demangle_mppe_key' => ['string', 'radius_handle'=>'resource', 'mangled'=>'string'], 'radius_get_attr' => ['mixed', 'radius_handle'=>'resource'], 'radius_get_tagged_attr_data' => ['string', 'data'=>'string'], 'radius_get_tagged_attr_tag' => ['int', 'data'=>'string'], 'radius_get_vendor_attr' => ['array', 'data'=>'string'], 'radius_put_addr' => ['bool', 'radius_handle'=>'resource', 'type'=>'int', 'addr'=>'string'], 'radius_put_attr' => ['bool', 'radius_handle'=>'resource', 'type'=>'int', 'value'=>'string'], 'radius_put_int' => ['bool', 'radius_handle'=>'resource', 'type'=>'int', 'value'=>'int'], 'radius_put_string' => ['bool', 'radius_handle'=>'resource', 'type'=>'int', 'value'=>'string'], 'radius_put_vendor_addr' => ['bool', 'radius_handle'=>'resource', 'vendor'=>'int', 'type'=>'int', 'addr'=>'string'], 'radius_put_vendor_attr' => ['bool', 'radius_handle'=>'resource', 'vendor'=>'int', 'type'=>'int', 'value'=>'string'], 'radius_put_vendor_int' => ['bool', 'radius_handle'=>'resource', 'vendor'=>'int', 'type'=>'int', 'value'=>'int'], 'radius_put_vendor_string' => ['bool', 'radius_handle'=>'resource', 'vendor'=>'int', 'type'=>'int', 'value'=>'string'], 'radius_request_authenticator' => ['string', 'radius_handle'=>'resource'], 'radius_salt_encrypt_attr' => ['string', 'radius_handle'=>'resource', 'data'=>'string'], 'radius_send_request' => ['int|false', 'radius_handle'=>'resource'], 'radius_server_secret' => ['string', 'radius_handle'=>'resource'], 'radius_strerror' => ['string', 'radius_handle'=>'resource'], 'rand' => ['int', 'min'=>'int', 'max'=>'int'], 'rand\'1' => ['int'], 'random_bytes' => ['non-empty-string', 'length'=>'positive-int'], 'random_int' => ['int', 'min'=>'int', 'max'=>'int'], 'range' => ['non-empty-array', 'start'=>'string|int|float', 'end'=>'string|int|float', 'step='=>'int<1, max>|float'], 'RangeException::__construct' => ['void', 'message='=>'string', 'code='=>'int', 'previous='=>'?Throwable'], 'RangeException::__toString' => ['string'], 'RangeException::getCode' => ['int'], 'RangeException::getFile' => ['string'], 'RangeException::getLine' => ['int'], 'RangeException::getMessage' => ['string'], 'RangeException::getPrevious' => ['?Throwable'], 'RangeException::getTrace' => ['list\',args?:array}>'], 'RangeException::getTraceAsString' => ['string'], 'rar_allow_broken_set' => ['bool', 'rarfile'=>'RarArchive', 'allow_broken'=>'bool'], 'rar_broken_is' => ['bool', 'rarfile'=>'rararchive'], 'rar_close' => ['bool', 'rarfile'=>'rararchive'], 'rar_comment_get' => ['string', 'rarfile'=>'rararchive'], 'rar_entry_get' => ['RarEntry', 'rarfile'=>'RarArchive', 'entryname'=>'string'], 'rar_list' => ['RarArchive', 'rarfile'=>'rararchive'], 'rar_open' => ['RarArchive', 'filename'=>'string', 'password='=>'string', 'volume_callback='=>'callable'], 'rar_solid_is' => ['bool', 'rarfile'=>'rararchive'], 'rar_wrapper_cache_stats' => ['string'], 'RarArchive::__toString' => ['string'], 'RarArchive::close' => ['bool'], 'RarArchive::getComment' => ['string|null'], 'RarArchive::getEntries' => ['RarEntry[]|false'], 'RarArchive::getEntry' => ['RarEntry|false', 'entryname'=>'string'], 'RarArchive::isBroken' => ['bool'], 'RarArchive::isSolid' => ['bool'], 'RarArchive::open' => ['RarArchive|false', 'filename'=>'string', 'password='=>'string', 'volume_callback='=>'callable'], 'RarArchive::setAllowBroken' => ['bool', 'allow_broken'=>'bool'], 'RarEntry::__toString' => ['string'], 'RarEntry::extract' => ['bool', 'dir'=>'string', 'filepath='=>'string', 'password='=>'string', 'extended_data='=>'bool'], 'RarEntry::getAttr' => ['int|false'], 'RarEntry::getCrc' => ['string|false'], 'RarEntry::getFileTime' => ['string|false'], 'RarEntry::getHostOs' => ['int|false'], 'RarEntry::getMethod' => ['int|false'], 'RarEntry::getName' => ['string|false'], 'RarEntry::getPackedSize' => ['int|false'], 'RarEntry::getStream' => ['resource|false', 'password='=>'string'], 'RarEntry::getUnpackedSize' => ['int|false'], 'RarEntry::getVersion' => ['int|false'], 'RarEntry::isDirectory' => ['bool'], 'RarEntry::isEncrypted' => ['bool'], 'RarException::getCode' => ['int'], 'RarException::getFile' => ['string'], 'RarException::getLine' => ['int'], 'RarException::getMessage' => ['string'], 'RarException::getPrevious' => ['Exception|Throwable'], 'RarException::getTrace' => ['list\',args?:array}>'], 'RarException::getTraceAsString' => ['string'], 'RarException::isUsingExceptions' => ['bool'], 'RarException::setUsingExceptions' => ['RarEntry', 'using_exceptions'=>'bool'], 'rawurldecode' => ['string', 'string'=>'string'], 'rawurlencode' => ['string', 'string'=>'string'], 'readdir' => ['string|false', 'dir_handle='=>'resource'], 'readfile' => ['int|false', 'filename'=>'string', 'use_include_path='=>'bool', 'context='=>'resource'], 'readgzfile' => ['int|false', 'filename'=>'string', 'use_include_path='=>'int'], 'readline' => ['string|false', 'prompt='=>'?string'], 'readline_add_history' => ['bool', 'prompt'=>'string'], 'readline_callback_handler_install' => ['bool', 'prompt'=>'string', 'callback'=>'callable'], 'readline_callback_handler_remove' => ['bool'], 'readline_callback_read_char' => ['void'], 'readline_clear_history' => ['bool'], 'readline_completion_function' => ['bool', 'callback'=>'callable'], 'readline_info' => ['mixed', 'var_name='=>'?string', 'value='=>'string|int|bool|null'], 'readline_list_history' => ['array'], 'readline_on_new_line' => ['void'], 'readline_read_history' => ['bool', 'filename='=>'?string'], 'readline_redisplay' => ['void'], 'readline_write_history' => ['bool', 'filename='=>'?string'], 'readlink' => ['non-falsy-string|false', 'path'=>'string'], 'realpath' => ['non-falsy-string|false', 'path'=>'string'], 'realpath_cache_get' => ['array'], 'realpath_cache_size' => ['int'], 'recode' => ['string', 'request'=>'string', 'string'=>'string'], 'recode_file' => ['bool', 'request'=>'string', 'input'=>'resource', 'output'=>'resource'], 'recode_string' => ['string|false', 'request'=>'string', 'string'=>'string'], 'rectObj::__construct' => ['void'], 'rectObj::draw' => ['int', 'map'=>'mapObj', 'layer'=>'layerObj', 'img'=>'imageObj', 'class_index'=>'int', 'text'=>'string'], 'rectObj::fit' => ['float', 'width'=>'int', 'height'=>'int'], 'rectObj::ms_newRectObj' => ['rectObj'], 'rectObj::project' => ['int', 'in'=>'projectionObj', 'out'=>'projectionObj'], 'rectObj::set' => ['int', 'property_name'=>'string', 'new_value'=>''], 'rectObj::setextent' => ['void', 'minx'=>'float', 'miny'=>'float', 'maxx'=>'float', 'maxy'=>'float'], 'RecursiveArrayIterator::__construct' => ['void', 'array='=>'array|object', 'flags='=>'int'], 'RecursiveArrayIterator::append' => ['void', 'value'=>'mixed'], 'RecursiveArrayIterator::asort' => ['true', 'flags='=>'int'], 'RecursiveArrayIterator::count' => ['int'], 'RecursiveArrayIterator::current' => ['mixed'], 'RecursiveArrayIterator::getArrayCopy' => ['array'], 'RecursiveArrayIterator::getChildren' => ['?RecursiveArrayIterator'], 'RecursiveArrayIterator::getFlags' => ['int'], 'RecursiveArrayIterator::hasChildren' => ['bool'], 'RecursiveArrayIterator::key' => ['string|int|null'], 'RecursiveArrayIterator::ksort' => ['true', 'flags='=>'int'], 'RecursiveArrayIterator::natcasesort' => ['true'], 'RecursiveArrayIterator::natsort' => ['true'], 'RecursiveArrayIterator::next' => ['void'], 'RecursiveArrayIterator::offsetExists' => ['bool', 'key'=>'string|int'], 'RecursiveArrayIterator::offsetGet' => ['mixed', 'key'=>'string|int'], 'RecursiveArrayIterator::offsetSet' => ['void', 'key'=>'string|int|null', 'value'=>'string'], 'RecursiveArrayIterator::offsetUnset' => ['void', 'key'=>'string|int'], 'RecursiveArrayIterator::rewind' => ['void'], 'RecursiveArrayIterator::seek' => ['void', 'offset'=>'int'], 'RecursiveArrayIterator::serialize' => ['string'], 'RecursiveArrayIterator::setFlags' => ['void', 'flags'=>'int'], 'RecursiveArrayIterator::uasort' => ['true', 'callback'=>'callable(mixed,mixed):int'], 'RecursiveArrayIterator::uksort' => ['true', 'callback'=>'callable(mixed,mixed):int'], 'RecursiveArrayIterator::unserialize' => ['void', 'data'=>'string'], 'RecursiveArrayIterator::valid' => ['bool'], 'RecursiveCachingIterator::__construct' => ['void', 'iterator'=>'Iterator', 'flags='=>'int'], 'RecursiveCachingIterator::__toString' => ['string'], 'RecursiveCachingIterator::count' => ['int'], 'RecursiveCachingIterator::current' => ['void'], 'RecursiveCachingIterator::getCache' => ['array'], 'RecursiveCachingIterator::getChildren' => ['?RecursiveCachingIterator'], 'RecursiveCachingIterator::getFlags' => ['int'], 'RecursiveCachingIterator::getInnerIterator' => ['Iterator'], 'RecursiveCachingIterator::hasChildren' => ['bool'], 'RecursiveCachingIterator::hasNext' => ['bool'], 'RecursiveCachingIterator::key' => ['bool|float|int|string'], 'RecursiveCachingIterator::next' => ['void'], 'RecursiveCachingIterator::offsetExists' => ['bool', 'key'=>'string'], 'RecursiveCachingIterator::offsetGet' => ['string', 'key'=>'string'], 'RecursiveCachingIterator::offsetSet' => ['void', 'key'=>'string', 'value'=>'string'], 'RecursiveCachingIterator::offsetUnset' => ['void', 'key'=>'string'], 'RecursiveCachingIterator::rewind' => ['void'], 'RecursiveCachingIterator::setFlags' => ['void', 'flags'=>'int'], 'RecursiveCachingIterator::valid' => ['bool'], 'RecursiveCallbackFilterIterator::__construct' => ['void', 'iterator'=>'RecursiveIterator', 'callback'=>'callable(mixed,mixed=,mixed=):bool'], 'RecursiveCallbackFilterIterator::accept' => ['bool'], 'RecursiveCallbackFilterIterator::current' => ['mixed'], 'RecursiveCallbackFilterIterator::getChildren' => ['RecursiveCallbackFilterIterator'], 'RecursiveCallbackFilterIterator::getInnerIterator' => ['Iterator'], 'RecursiveCallbackFilterIterator::hasChildren' => ['bool'], 'RecursiveCallbackFilterIterator::key' => ['bool|float|int|string'], 'RecursiveCallbackFilterIterator::next' => ['void'], 'RecursiveCallbackFilterIterator::rewind' => ['void'], 'RecursiveCallbackFilterIterator::valid' => ['bool'], 'RecursiveDirectoryIterator::__construct' => ['void', 'directory'=>'string', 'flags='=>'int'], 'RecursiveDirectoryIterator::__toString' => ['string'], 'RecursiveDirectoryIterator::current' => ['string|SplFileInfo|FilesystemIterator'], 'RecursiveDirectoryIterator::getATime' => ['int'], 'RecursiveDirectoryIterator::getBasename' => ['string', 'suffix='=>'string'], 'RecursiveDirectoryIterator::getChildren' => ['RecursiveDirectoryIterator'], 'RecursiveDirectoryIterator::getCTime' => ['int'], 'RecursiveDirectoryIterator::getExtension' => ['string'], 'RecursiveDirectoryIterator::getFileInfo' => ['SplFileInfo', 'class='=>'?class-string'], 'RecursiveDirectoryIterator::getFilename' => ['string'], 'RecursiveDirectoryIterator::getFlags' => ['int'], 'RecursiveDirectoryIterator::getGroup' => ['int'], 'RecursiveDirectoryIterator::getInode' => ['int'], 'RecursiveDirectoryIterator::getLinkTarget' => ['string'], 'RecursiveDirectoryIterator::getMTime' => ['int'], 'RecursiveDirectoryIterator::getOwner' => ['int'], 'RecursiveDirectoryIterator::getPath' => ['string'], 'RecursiveDirectoryIterator::getPathInfo' => ['?SplFileInfo', 'class='=>'?class-string'], 'RecursiveDirectoryIterator::getPathname' => ['string'], 'RecursiveDirectoryIterator::getPerms' => ['int'], 'RecursiveDirectoryIterator::getRealPath' => ['non-falsy-string'], 'RecursiveDirectoryIterator::getSize' => ['int'], 'RecursiveDirectoryIterator::getSubPath' => ['string'], 'RecursiveDirectoryIterator::getSubPathname' => ['string'], 'RecursiveDirectoryIterator::getType' => ['string'], 'RecursiveDirectoryIterator::hasChildren' => ['bool', 'allowLinks='=>'bool'], 'RecursiveDirectoryIterator::isDir' => ['bool'], 'RecursiveDirectoryIterator::isDot' => ['bool'], 'RecursiveDirectoryIterator::isExecutable' => ['bool'], 'RecursiveDirectoryIterator::isFile' => ['bool'], 'RecursiveDirectoryIterator::isLink' => ['bool'], 'RecursiveDirectoryIterator::isReadable' => ['bool'], 'RecursiveDirectoryIterator::isWritable' => ['bool'], 'RecursiveDirectoryIterator::key' => ['string'], 'RecursiveDirectoryIterator::next' => ['void'], 'RecursiveDirectoryIterator::openFile' => ['SplFileObject', 'mode='=>'string', 'useIncludePath='=>'bool', 'context='=>'?resource'], 'RecursiveDirectoryIterator::rewind' => ['void'], 'RecursiveDirectoryIterator::seek' => ['void', 'offset'=>'int'], 'RecursiveDirectoryIterator::setFileClass' => ['void', 'class='=>'class-string'], 'RecursiveDirectoryIterator::setFlags' => ['void', 'flags'=>'int'], 'RecursiveDirectoryIterator::setInfoClass' => ['void', 'class='=>'class-string'], 'RecursiveDirectoryIterator::valid' => ['bool'], 'RecursiveFilterIterator::__construct' => ['void', 'iterator'=>'RecursiveIterator'], 'RecursiveFilterIterator::accept' => ['bool'], 'RecursiveFilterIterator::current' => ['mixed'], 'RecursiveFilterIterator::getChildren' => ['?RecursiveFilterIterator'], 'RecursiveFilterIterator::getInnerIterator' => ['Iterator'], 'RecursiveFilterIterator::hasChildren' => ['bool'], 'RecursiveFilterIterator::key' => ['mixed'], 'RecursiveFilterIterator::next' => ['void'], 'RecursiveFilterIterator::rewind' => ['void'], 'RecursiveFilterIterator::valid' => ['bool'], 'RecursiveIterator::__construct' => ['void'], 'RecursiveIterator::current' => ['mixed'], 'RecursiveIterator::getChildren' => ['?RecursiveIterator'], 'RecursiveIterator::hasChildren' => ['bool'], 'RecursiveIterator::key' => ['int|string'], 'RecursiveIterator::next' => ['void'], 'RecursiveIterator::rewind' => ['void'], 'RecursiveIterator::valid' => ['bool'], 'RecursiveIteratorIterator::__construct' => ['void', 'iterator'=>'RecursiveIterator|IteratorAggregate', 'mode='=>'int', 'flags='=>'int'], 'RecursiveIteratorIterator::beginChildren' => ['void'], 'RecursiveIteratorIterator::beginIteration' => ['void'], 'RecursiveIteratorIterator::callGetChildren' => ['?RecursiveIterator'], 'RecursiveIteratorIterator::callHasChildren' => ['bool'], 'RecursiveIteratorIterator::current' => ['mixed'], 'RecursiveIteratorIterator::endChildren' => ['void'], 'RecursiveIteratorIterator::endIteration' => ['void'], 'RecursiveIteratorIterator::getDepth' => ['int'], 'RecursiveIteratorIterator::getInnerIterator' => ['RecursiveIterator'], 'RecursiveIteratorIterator::getMaxDepth' => ['int|false'], 'RecursiveIteratorIterator::getSubIterator' => ['?RecursiveIterator', 'level='=>'?int'], 'RecursiveIteratorIterator::key' => ['mixed'], 'RecursiveIteratorIterator::next' => ['void'], 'RecursiveIteratorIterator::nextElement' => ['void'], 'RecursiveIteratorIterator::rewind' => ['void'], 'RecursiveIteratorIterator::setMaxDepth' => ['void', 'maxDepth='=>'int'], 'RecursiveIteratorIterator::valid' => ['bool'], 'RecursiveRegexIterator::__construct' => ['void', 'iterator'=>'RecursiveIterator', 'pattern'=>'string', 'mode='=>'int', 'flags='=>'int', 'pregFlags='=>'int'], 'RecursiveRegexIterator::accept' => ['bool'], 'RecursiveRegexIterator::current' => ['mixed'], 'RecursiveRegexIterator::getChildren' => ['RecursiveRegexIterator'], 'RecursiveRegexIterator::getFlags' => ['int'], 'RecursiveRegexIterator::getInnerIterator' => ['Iterator'], 'RecursiveRegexIterator::getMode' => ['int'], 'RecursiveRegexIterator::getPregFlags' => ['int'], 'RecursiveRegexIterator::getRegex' => ['string'], 'RecursiveRegexIterator::hasChildren' => ['bool'], 'RecursiveRegexIterator::key' => ['mixed'], 'RecursiveRegexIterator::next' => ['void'], 'RecursiveRegexIterator::rewind' => ['void'], 'RecursiveRegexIterator::setFlags' => ['void', 'flags'=>'int'], 'RecursiveRegexIterator::setMode' => ['void', 'mode'=>'int'], 'RecursiveRegexIterator::setPregFlags' => ['void', 'pregFlags'=>'int'], 'RecursiveRegexIterator::valid' => ['bool'], 'RecursiveTreeIterator::__construct' => ['void', 'iterator'=>'RecursiveIterator|IteratorAggregate', 'flags='=>'int', 'cachingIteratorFlags='=>'int', 'mode='=>'int'], 'RecursiveTreeIterator::beginChildren' => ['void'], 'RecursiveTreeIterator::beginIteration' => ['void'], 'RecursiveTreeIterator::callGetChildren' => ['?RecursiveIterator'], 'RecursiveTreeIterator::callHasChildren' => ['bool'], 'RecursiveTreeIterator::current' => ['string'], 'RecursiveTreeIterator::endChildren' => ['void'], 'RecursiveTreeIterator::endIteration' => ['void'], 'RecursiveTreeIterator::getDepth' => ['int'], 'RecursiveTreeIterator::getEntry' => ['string'], 'RecursiveTreeIterator::getInnerIterator' => ['RecursiveIterator'], 'RecursiveTreeIterator::getMaxDepth' => ['false|int'], 'RecursiveTreeIterator::getPostfix' => ['string'], 'RecursiveTreeIterator::getPrefix' => ['string'], 'RecursiveTreeIterator::getSubIterator' => ['?RecursiveIterator', 'level='=>'?int'], 'RecursiveTreeIterator::key' => ['string'], 'RecursiveTreeIterator::next' => ['void'], 'RecursiveTreeIterator::nextElement' => ['void'], 'RecursiveTreeIterator::rewind' => ['void'], 'RecursiveTreeIterator::setMaxDepth' => ['void', 'maxDepth='=>'int'], 'RecursiveTreeIterator::setPostfix' => ['void', 'postfix'=>'string'], 'RecursiveTreeIterator::setPrefixPart' => ['void', 'part'=>'int', 'value'=>'string'], 'RecursiveTreeIterator::valid' => ['bool'], 'Redis::__construct' => ['void'], 'Redis::__destruct' => ['void'], 'Redis::_prefix' => ['string', 'value'=>'mixed'], 'Redis::_serialize' => ['mixed', 'value'=>'mixed'], 'Redis::_unserialize' => ['mixed', 'value'=>'string'], 'Redis::append' => ['int', 'key'=>'string', 'value'=>'string'], 'Redis::auth' => ['bool', 'password'=>'string'], 'Redis::bgRewriteAOF' => ['bool'], 'Redis::bgSave' => ['bool'], 'Redis::bitCount' => ['int', 'key'=>'string'], 'Redis::bitOp' => ['int', 'operation'=>'string', 'ret_key'=>'string', 'key'=>'string', '...other_keys='=>'string'], 'Redis::bitpos' => ['int', 'key'=>'string', 'bit'=>'int', 'start='=>'int', 'end='=>'int'], 'Redis::blPop' => ['array', 'keys'=>'string[]', 'timeout'=>'int'], 'Redis::blPop\'1' => ['array', 'key'=>'string', 'timeout_or_key'=>'int|string', '...extra_args'=>'int|string'], 'Redis::brPop' => ['array', 'keys'=>'string[]', 'timeout'=>'int'], 'Redis::brPop\'1' => ['array', 'key'=>'string', 'timeout_or_key'=>'int|string', '...extra_args'=>'int|string'], 'Redis::brpoplpush' => ['string|false', 'srcKey'=>'string', 'dstKey'=>'string', 'timeout'=>'int'], 'Redis::clearLastError' => ['bool'], 'Redis::client' => ['mixed', 'command'=>'string', 'arg='=>'string'], 'Redis::close' => ['bool'], 'Redis::command' => ['', '...args'=>''], 'Redis::config' => ['string', 'operation'=>'string', 'key'=>'string', 'value='=>'string'], 'Redis::connect' => ['bool', 'host'=>'string', 'port='=>'int', 'timeout='=>'float', 'reserved='=>'null', 'retry_interval='=>'?int', 'read_timeout='=>'float'], 'Redis::dbSize' => ['int'], 'Redis::debug' => ['', 'key'=>''], 'Redis::decr' => ['int', 'key'=>'string'], 'Redis::decrBy' => ['int', 'key'=>'string', 'value'=>'int'], 'Redis::decrByFloat' => ['float', 'key'=>'string', 'value'=>'float'], 'Redis::del' => ['int', 'key'=>'string', '...args'=>'string'], 'Redis::del\'1' => ['int', 'key'=>'string[]'], 'Redis::delete' => ['int', 'key'=>'string', '...args'=>'string'], 'Redis::delete\'1' => ['int', 'key'=>'string[]'], 'Redis::discard' => [''], 'Redis::dump' => ['string|false', 'key'=>'string'], 'Redis::echo' => ['string', 'message'=>'string'], 'Redis::eval' => ['mixed', 'script'=>'', 'args='=>'', 'numKeys='=>''], 'Redis::evalSha' => ['mixed', 'scriptSha'=>'string', 'args='=>'array', 'numKeys='=>'int'], 'Redis::evaluate' => ['mixed', 'script'=>'string', 'args='=>'array', 'numKeys='=>'int'], 'Redis::evaluateSha' => ['', 'scriptSha'=>'string', 'args='=>'array', 'numKeys='=>'int'], 'Redis::exec' => ['array'], 'Redis::exists' => ['int', 'keys'=>'string|string[]'], 'Redis::exists\'1' => ['int', '...keys'=>'string'], 'Redis::expire' => ['bool', 'key'=>'string', 'ttl'=>'int'], 'Redis::expireAt' => ['bool', 'key'=>'string', 'expiry'=>'int'], 'Redis::flushAll' => ['bool', 'async='=>'bool'], 'Redis::flushDb' => ['bool', 'async='=>'bool'], 'Redis::geoAdd' => ['int', 'key'=>'string', 'longitude'=>'float', 'latitude'=>'float', 'member'=>'string', '...other_triples='=>'string|int|float'], 'Redis::geoDist' => ['float', 'key'=>'string', 'member1'=>'string', 'member2'=>'string', 'unit='=>'string'], 'Redis::geoHash' => ['array', 'key'=>'string', 'member'=>'string', '...other_members='=>'string'], 'Redis::geoPos' => ['array', 'key'=>'string', 'member'=>'string', '...members='=>'string'], 'Redis::geoRadius' => ['array|int', 'key'=>'string', 'longitude'=>'float', 'latitude'=>'float', 'radius'=>'float', 'unit'=>'float', 'options='=>'array'], 'Redis::geoRadiusByMember' => ['array|int', 'key'=>'string', 'member'=>'string', 'radius'=>'float', 'units'=>'string', 'options='=>'array'], 'Redis::get' => ['string|false', 'key'=>'string'], 'Redis::getAuth' => ['string|false|null'], 'Redis::getBit' => ['int', 'key'=>'string', 'offset'=>'int'], 'Redis::getDBNum' => ['int|false'], 'Redis::getHost' => ['string|false'], 'Redis::getKeys' => ['array', 'pattern'=>'string'], 'Redis::getLastError' => ['?string'], 'Redis::getMode' => ['int'], 'Redis::getMultiple' => ['array', 'keys'=>'string[]'], 'Redis::getOption' => ['int', 'name'=>'int'], 'Redis::getPersistentID' => ['string|false|null'], 'Redis::getPort' => ['int|false'], 'Redis::getRange' => ['int', 'key'=>'string', 'start'=>'int', 'end'=>'int'], 'Redis::getReadTimeout' => ['float|false'], 'Redis::getSet' => ['string', 'key'=>'string', 'string'=>'string'], 'Redis::getTimeout' => ['float|false'], 'Redis::hDel' => ['int|false', 'key'=>'string', 'hashKey1'=>'string', '...otherHashKeys='=>'string'], 'Redis::hExists' => ['bool', 'key'=>'string', 'hashKey'=>'string'], 'Redis::hGet' => ['string|false', 'key'=>'string', 'hashKey'=>'string'], 'Redis::hGetAll' => ['array', 'key'=>'string'], 'Redis::hIncrBy' => ['int', 'key'=>'string', 'hashKey'=>'string', 'value'=>'int'], 'Redis::hIncrByFloat' => ['float', 'key'=>'string', 'field'=>'string', 'increment'=>'float'], 'Redis::hKeys' => ['array', 'key'=>'string'], 'Redis::hLen' => ['int|false', 'key'=>'string'], 'Redis::hMGet' => ['array', 'key'=>'string', 'hashKeys'=>'array'], 'Redis::hMSet' => ['bool', 'key'=>'string', 'hashKeys'=>'array'], 'Redis::hScan' => ['array', 'key'=>'string', '&iterator'=>'int', 'pattern='=>'string', 'count='=>'int'], 'Redis::hSet' => ['int|false', 'key'=>'string', 'hashKey'=>'string', 'value'=>'string'], 'Redis::hSetNx' => ['bool', 'key'=>'string', 'hashKey'=>'string', 'value'=>'string'], 'Redis::hStrLen' => ['', 'key'=>'', 'member'=>''], 'Redis::hVals' => ['array', 'key'=>'string'], 'Redis::incr' => ['int', 'key'=>'string'], 'Redis::incrBy' => ['int', 'key'=>'string', 'value'=>'int'], 'Redis::incrByFloat' => ['float', 'key'=>'string', 'value'=>'float'], 'Redis::info' => ['array', 'option='=>'string'], 'Redis::isConnected' => ['bool'], 'Redis::keys' => ['array', 'pattern'=>'string'], 'Redis::lastSave' => ['int'], 'Redis::lGet' => ['string', 'key'=>'string', 'index'=>'int'], 'Redis::lGetRange' => ['array', 'key'=>'string', 'start'=>'int', 'end'=>'int'], 'Redis::lIndex' => ['string|false', 'key'=>'string', 'index'=>'int'], 'Redis::lInsert' => ['int', 'key'=>'string', 'position'=>'int', 'pivot'=>'string', 'value'=>'string'], 'Redis::listTrim' => ['', 'key'=>'string', 'start'=>'int', 'stop'=>'int'], 'Redis::lLen' => ['int|false', 'key'=>'string'], 'Redis::lPop' => ['string|false', 'key'=>'string'], 'Redis::lPush' => ['int|false', 'key'=>'string', 'value1'=>'string', 'value2='=>'string', 'valueN='=>'string'], 'Redis::lPushx' => ['int|false', 'key'=>'string', 'value'=>'string'], 'Redis::lRange' => ['array', 'key'=>'string', 'start'=>'int', 'end'=>'int'], 'Redis::lRem' => ['int|false', 'key'=>'string', 'value'=>'string', 'count'=>'int'], 'Redis::lRemove' => ['int', 'key'=>'string', 'value'=>'string', 'count'=>'int'], 'Redis::lSet' => ['bool', 'key'=>'string', 'index'=>'int', 'value'=>'string'], 'Redis::lSize' => ['int', 'key'=>'string'], 'Redis::lTrim' => ['array|false', 'key'=>'string', 'start'=>'int', 'stop'=>'int'], 'Redis::mGet' => ['array', 'keys'=>'string[]'], 'Redis::migrate' => ['bool', 'host'=>'string', 'port'=>'int', 'key'=>'string|string[]', 'db'=>'int', 'timeout'=>'int', 'copy='=>'bool', 'replace='=>'bool'], 'Redis::move' => ['bool', 'key'=>'string', 'dbindex'=>'int'], 'Redis::mSet' => ['bool', 'pairs'=>'array'], 'Redis::mSetNx' => ['bool', 'pairs'=>'array'], 'Redis::multi' => ['Redis', 'mode='=>'int'], 'Redis::object' => ['string|long|false', 'info'=>'string', 'key'=>'string'], 'Redis::open' => ['bool', 'host'=>'string', 'port='=>'int', 'timeout='=>'float', 'reserved='=>'null', 'retry_interval='=>'?int', 'read_timeout='=>'float'], 'Redis::pconnect' => ['bool', 'host'=>'string', 'port='=>'int', 'timeout='=>'float', 'persistent_id='=>'string', 'retry_interval='=>'?int'], 'Redis::persist' => ['bool', 'key'=>'string'], 'Redis::pExpire' => ['bool', 'key'=>'string', 'ttl'=>'int'], 'Redis::pexpireAt' => ['bool', 'key'=>'string', 'expiry'=>'int'], 'Redis::pfAdd' => ['bool', 'key'=>'string', 'elements'=>'array'], 'Redis::pfCount' => ['int', 'key'=>'array|string'], 'Redis::pfMerge' => ['bool', 'destkey'=>'string', 'sourcekeys'=>'array'], 'Redis::ping' => ['string'], 'Redis::pipeline' => ['Redis'], 'Redis::popen' => ['bool', 'host'=>'string', 'port='=>'int', 'timeout='=>'float', 'persistent_id='=>'string', 'retry_interval='=>'?int'], 'Redis::psetex' => ['bool', 'key'=>'string', 'ttl'=>'int', 'value'=>'string'], 'Redis::psubscribe' => ['', 'patterns'=>'array', 'callback'=>'array|string'], 'Redis::pttl' => ['int|false', 'key'=>'string'], 'Redis::publish' => ['int', 'channel'=>'string', 'message'=>'string'], 'Redis::pubsub' => ['array|int', 'keyword'=>'string', 'argument='=>'array|string'], 'Redis::punsubscribe' => ['', 'pattern'=>'string', '...other_patterns='=>'string'], 'Redis::randomKey' => ['string'], 'Redis::rawCommand' => ['mixed', 'command'=>'string', '...arguments='=>'mixed'], 'Redis::rename' => ['bool', 'srckey'=>'string', 'dstkey'=>'string'], 'Redis::renameKey' => ['bool', 'srckey'=>'string', 'dstkey'=>'string'], 'Redis::renameNx' => ['bool', 'srckey'=>'string', 'dstkey'=>'string'], 'Redis::resetStat' => ['bool'], 'Redis::restore' => ['bool', 'key'=>'string', 'ttl'=>'int', 'value'=>'string'], 'Redis::role' => ['array', 'nodeParams'=>'string|array{0:string,1:int}'], 'Redis::rPop' => ['string|false', 'key'=>'string'], 'Redis::rpoplpush' => ['string', 'srcKey'=>'string', 'dstKey'=>'string'], 'Redis::rPush' => ['int|false', 'key'=>'string', 'value1'=>'string', 'value2='=>'string', 'valueN='=>'string'], 'Redis::rPushx' => ['int|false', 'key'=>'string', 'value'=>'string'], 'Redis::sAdd' => ['int|false', 'key'=>'string', 'value1'=>'string', 'value2='=>'string', 'valueN='=>'string'], 'Redis::sAddArray' => ['bool', 'key'=>'string', 'values'=>'array'], 'Redis::save' => ['bool'], 'Redis::scan' => ['array|false', '&rw_iterator'=>'?int', 'pattern='=>'?string', 'count='=>'?int'], 'Redis::sCard' => ['int', 'key'=>'string'], 'Redis::sContains' => ['', 'key'=>'string', 'value'=>'string'], 'Redis::script' => ['mixed', 'command'=>'string', '...args='=>'mixed'], 'Redis::sDiff' => ['array', 'key1'=>'string', '...other_keys='=>'string'], 'Redis::sDiffStore' => ['int|false', 'dstKey'=>'string', 'key'=>'string', '...other_keys='=>'string'], 'Redis::select' => ['bool', 'dbindex'=>'int'], 'Redis::sendEcho' => ['string', 'msg'=>'string'], 'Redis::set' => ['bool', 'key'=>'string', 'value'=>'mixed', 'options='=>'array'], 'Redis::set\'1' => ['bool', 'key'=>'string', 'value'=>'mixed', 'timeout='=>'int'], 'Redis::setBit' => ['int', 'key'=>'string', 'offset'=>'int', 'value'=>'int'], 'Redis::setEx' => ['bool', 'key'=>'string', 'ttl'=>'int', 'value'=>'string'], 'Redis::setNx' => ['bool', 'key'=>'string', 'value'=>'string'], 'Redis::setOption' => ['bool', 'name'=>'int', 'value'=>'mixed'], 'Redis::setRange' => ['int', 'key'=>'string', 'offset'=>'int', 'end'=>'int'], 'Redis::setTimeout' => ['', 'key'=>'string', 'ttl'=>'int'], 'Redis::sGetMembers' => ['', 'key'=>'string'], 'Redis::sInter' => ['array|false', 'key'=>'string', '...other_keys='=>'string'], 'Redis::sInterStore' => ['int|false', 'dstKey'=>'string', 'key'=>'string', '...other_keys='=>'string'], 'Redis::sIsMember' => ['bool', 'key'=>'string', 'value'=>'string'], 'Redis::slave' => ['bool', 'host'=>'string', 'port'=>'int'], 'Redis::slave\'1' => ['bool', 'host'=>'string', 'port'=>'int'], 'Redis::slaveof' => ['bool', 'host='=>'string', 'port='=>'int'], 'Redis::slowLog' => ['mixed', 'operation'=>'string', 'length='=>'int'], 'Redis::sMembers' => ['array', 'key'=>'string'], 'Redis::sMove' => ['bool', 'srcKey'=>'string', 'dstKey'=>'string', 'member'=>'string'], 'Redis::sort' => ['array|int', 'key'=>'string', 'options='=>'array'], 'Redis::sortAsc' => ['array', 'key'=>'string', 'pattern='=>'string', 'get='=>'string', 'start='=>'int', 'end='=>'int', 'getList='=>'bool'], 'Redis::sortAscAlpha' => ['array', 'key'=>'string', 'pattern='=>'', 'get='=>'string', 'start='=>'int', 'end='=>'int', 'getList='=>'bool'], 'Redis::sortDesc' => ['array', 'key'=>'string', 'pattern='=>'', 'get='=>'string', 'start='=>'int', 'end='=>'int', 'getList='=>'bool'], 'Redis::sortDescAlpha' => ['array', 'key'=>'string', 'pattern='=>'', 'get='=>'string', 'start='=>'int', 'end='=>'int', 'getList='=>'bool'], 'Redis::sPop' => ['string|false', 'key'=>'string'], 'Redis::sRandMember' => ['array|string|false', 'key'=>'string', 'count='=>'int'], 'Redis::sRem' => ['int', 'key'=>'string', 'member1'=>'string', '...other_members='=>'string'], 'Redis::sRemove' => ['int', 'key'=>'string', 'member1'=>'string', '...other_members='=>'string'], 'Redis::sScan' => ['array|bool', 'key'=>'string', '&iterator'=>'int', 'pattern='=>'string', 'count='=>'int'], 'Redis::sSize' => ['int', 'key'=>'string'], 'Redis::strLen' => ['int', 'key'=>'string'], 'Redis::subscribe' => ['mixed|null', 'channels'=>'array', 'callback'=>'string|array'], 'Redis::substr' => ['', 'key'=>'string', 'start'=>'int', 'end'=>'int'], 'Redis::sUnion' => ['array', 'key'=>'string', '...other_keys='=>'string'], 'Redis::sUnionStore' => ['int', 'dstKey'=>'string', 'key'=>'string', '...other_keys='=>'string'], 'Redis::swapdb' => ['bool', 'srcdb'=>'int', 'dstdb'=>'int'], 'Redis::time' => ['array'], 'Redis::ttl' => ['int|false', 'key'=>'string'], 'Redis::type' => ['int', 'key'=>'string'], 'Redis::unlink' => ['int', 'key'=>'string', '...args'=>'string'], 'Redis::unlink\'1' => ['int', 'key'=>'string[]'], 'Redis::unsubscribe' => ['', 'channel'=>'string', '...other_channels='=>'string'], 'Redis::unwatch' => [''], 'Redis::wait' => ['int', 'numSlaves'=>'int', 'timeout'=>'int'], 'Redis::watch' => ['void', 'key'=>'string', '...other_keys='=>'string'], 'Redis::xack' => ['', 'str_key'=>'string', 'str_group'=>'string', 'arr_ids'=>'array'], 'Redis::xadd' => ['', 'str_key'=>'string', 'str_id'=>'string', 'arr_fields'=>'array', 'i_maxlen='=>'', 'boo_approximate='=>''], 'Redis::xclaim' => ['', 'str_key'=>'string', 'str_group'=>'string', 'str_consumer'=>'string', 'i_min_idle'=>'', 'arr_ids'=>'array', 'arr_opts='=>'array'], 'Redis::xdel' => ['', 'str_key'=>'string', 'arr_ids'=>'array'], 'Redis::xgroup' => ['', 'str_operation'=>'string', 'str_key='=>'string', 'str_arg1='=>'', 'str_arg2='=>'', 'str_arg3='=>''], 'Redis::xinfo' => ['', 'str_cmd'=>'string', 'str_key='=>'string', 'str_group='=>'string'], 'Redis::xlen' => ['', 'key'=>''], 'Redis::xpending' => ['', 'str_key'=>'string', 'str_group'=>'string', 'str_start='=>'', 'str_end='=>'', 'i_count='=>'', 'str_consumer='=>'string'], 'Redis::xrange' => ['', 'str_key'=>'string', 'str_start'=>'', 'str_end'=>'', 'i_count='=>''], 'Redis::xread' => ['', 'arr_streams'=>'array', 'i_count='=>'', 'i_block='=>''], 'Redis::xreadgroup' => ['', 'str_group'=>'string', 'str_consumer'=>'string', 'arr_streams'=>'array', 'i_count='=>'', 'i_block='=>''], 'Redis::xrevrange' => ['', 'str_key'=>'string', 'str_start'=>'', 'str_end'=>'', 'i_count='=>''], 'Redis::xtrim' => ['', 'str_key'=>'string', 'i_maxlen'=>'', 'boo_approximate='=>''], 'Redis::zAdd' => ['int', 'key'=>'string', 'score1'=>'float', 'value1'=>'string', 'score2='=>'float', 'value2='=>'string', 'scoreN='=>'float', 'valueN='=>'string'], 'Redis::zAdd\'1' => ['int', 'options'=>'array', 'key'=>'string', 'score1'=>'float', 'value1'=>'string', 'score2='=>'float', 'value2='=>'string', 'scoreN='=>'float', 'valueN='=>'string'], 'Redis::zCard' => ['int', 'key'=>'string'], 'Redis::zCount' => ['int', 'key'=>'string', 'start'=>'string', 'end'=>'string'], 'Redis::zDelete' => ['int', 'key'=>'string', 'member'=>'string', '...other_members='=>'string'], 'Redis::zDeleteRangeByRank' => ['', 'key'=>'string', 'start'=>'int', 'end'=>'int'], 'Redis::zDeleteRangeByScore' => ['', 'key'=>'string', 'start'=>'float', 'end'=>'float'], 'Redis::zIncrBy' => ['float', 'key'=>'string', 'value'=>'float', 'member'=>'string'], 'Redis::zInter' => ['int', 'Output'=>'string', 'ZSetKeys'=>'array', 'Weights='=>'?array', 'aggregateFunction='=>'string'], 'Redis::zInterStore' => ['int', 'Output'=>'string', 'ZSetKeys'=>'array', 'Weights='=>'?array', 'aggregateFunction='=>'string'], 'Redis::zLexCount' => ['int', 'key'=>'string', 'min'=>'string', 'max'=>'string'], 'Redis::zRange' => ['array', 'key'=>'string', 'start'=>'int', 'end'=>'int', 'withscores='=>'bool'], 'Redis::zRangeByLex' => ['array|false', 'key'=>'string', 'min'=>'int', 'max'=>'int', 'offset='=>'int', 'limit='=>'int'], 'Redis::zRangeByScore' => ['array', 'key'=>'string', 'start'=>'int|string', 'end'=>'int|string', 'options='=>'array'], 'Redis::zRank' => ['int', 'key'=>'string', 'member'=>'string'], 'Redis::zRem' => ['int', 'key'=>'string', 'member'=>'string', '...other_members='=>'string'], 'Redis::zRemove' => ['int', 'key'=>'string', 'member'=>'string', '...other_members='=>'string'], 'Redis::zRemoveRangeByRank' => ['int', 'key'=>'string', 'start'=>'int', 'end'=>'int'], 'Redis::zRemoveRangeByScore' => ['int', 'key'=>'string', 'start'=>'float|string', 'end'=>'float|string'], 'Redis::zRemRangeByLex' => ['int', 'key'=>'string', 'min'=>'string', 'max'=>'string'], 'Redis::zRemRangeByRank' => ['int', 'key'=>'string', 'start'=>'int', 'end'=>'int'], 'Redis::zRemRangeByScore' => ['int', 'key'=>'string', 'start'=>'float|string', 'end'=>'float|string'], 'Redis::zReverseRange' => ['array', 'key'=>'string', 'start'=>'int', 'end'=>'int', 'withscore='=>'bool'], 'Redis::zRevRange' => ['array', 'key'=>'string', 'start'=>'int', 'end'=>'int', 'withscore='=>'bool'], 'Redis::zRevRangeByLex' => ['array', 'key'=>'string', 'min'=>'string', 'max'=>'string', 'offset='=>'int', 'limit='=>'int'], 'Redis::zRevRangeByScore' => ['array', 'key'=>'string', 'start'=>'string', 'end'=>'string', 'options='=>'array'], 'Redis::zRevRank' => ['int', 'key'=>'string', 'member'=>'string'], 'Redis::zScan' => ['array|bool', 'key'=>'string', '&iterator'=>'int', 'pattern='=>'string', 'count='=>'int'], 'Redis::zScore' => ['float|false', 'key'=>'string', 'member'=>'string'], 'Redis::zSize' => ['', 'key'=>'string'], 'Redis::zUnion' => ['int', 'Output'=>'string', 'ZSetKeys'=>'array', 'Weights='=>'?array', 'aggregateFunction='=>'string'], 'Redis::zUnionStore' => ['int', 'Output'=>'string', 'ZSetKeys'=>'array', 'Weights='=>'?array', 'aggregateFunction='=>'string'], 'RedisArray::__call' => ['mixed', 'function_name'=>'string', 'arguments'=>'array'], 'RedisArray::__construct' => ['void', 'name='=>'string', 'hosts='=>'?array', 'opts='=>'?array'], 'RedisArray::_continuum' => [''], 'RedisArray::_distributor' => [''], 'RedisArray::_function' => ['string'], 'RedisArray::_hosts' => ['array'], 'RedisArray::_instance' => ['', 'host'=>''], 'RedisArray::_rehash' => ['', 'callable='=>'callable'], 'RedisArray::_target' => ['string', 'key'=>'string'], 'RedisArray::bgsave' => [''], 'RedisArray::del' => ['bool', 'key'=>'string', '...args'=>'string'], 'RedisArray::delete' => ['bool', 'key'=>'string', '...args'=>'string'], 'RedisArray::delete\'1' => ['bool', 'key'=>'string[]'], 'RedisArray::discard' => [''], 'RedisArray::exec' => ['array'], 'RedisArray::flushAll' => ['bool', 'async='=>'bool'], 'RedisArray::flushDb' => ['bool', 'async='=>'bool'], 'RedisArray::getMultiple' => ['', 'keys'=>''], 'RedisArray::getOption' => ['', 'opt'=>''], 'RedisArray::info' => ['array'], 'RedisArray::keys' => ['array', 'pattern'=>''], 'RedisArray::mGet' => ['array', 'keys'=>'string[]'], 'RedisArray::mSet' => ['bool', 'pairs'=>'array'], 'RedisArray::multi' => ['RedisArray', 'host'=>'string', 'mode='=>'int'], 'RedisArray::ping' => ['string'], 'RedisArray::save' => ['bool'], 'RedisArray::select' => ['', 'index'=>''], 'RedisArray::setOption' => ['', 'opt'=>'', 'value'=>''], 'RedisArray::unlink' => ['int', 'key'=>'string', '...other_keys='=>'string'], 'RedisArray::unlink\'1' => ['int', 'key'=>'string[]'], 'RedisArray::unwatch' => [''], 'RedisCluster::__construct' => ['void', 'name'=>'?string', 'seeds='=>'string[]', 'timeout='=>'float', 'readTimeout='=>'float', 'persistent='=>'bool', 'auth='=>'?string'], 'RedisCluster::_masters' => ['array'], 'RedisCluster::_prefix' => ['string', 'value'=>'mixed'], 'RedisCluster::_redir' => [''], 'RedisCluster::_serialize' => ['mixed', 'value'=>'mixed'], 'RedisCluster::_unserialize' => ['mixed', 'value'=>'string'], 'RedisCluster::append' => ['int', 'key'=>'string', 'value'=>'string'], 'RedisCluster::bgrewriteaof' => ['bool', 'nodeParams'=>'string|array{0:string,1:int}'], 'RedisCluster::bgsave' => ['bool', 'nodeParams'=>'string|array{0:string,1:int}'], 'RedisCluster::bitCount' => ['int', 'key'=>'string'], 'RedisCluster::bitOp' => ['int', 'operation'=>'string', 'retKey'=>'string', 'key1'=>'string', '...other_keys='=>'string'], 'RedisCluster::bitpos' => ['int', 'key'=>'string', 'bit'=>'int', 'start='=>'int', 'end='=>'int'], 'RedisCluster::blPop' => ['array', 'keys'=>'array', 'timeout'=>'int'], 'RedisCluster::brPop' => ['array', 'keys'=>'array', 'timeout'=>'int'], 'RedisCluster::brpoplpush' => ['string|false', 'srcKey'=>'string', 'dstKey'=>'string', 'timeout'=>'int'], 'RedisCluster::clearLastError' => ['bool'], 'RedisCluster::client' => ['', 'nodeParams'=>'string|array{0:string,1:int}', 'subCmd='=>'string', '...args='=>''], 'RedisCluster::close' => [''], 'RedisCluster::cluster' => ['mixed', 'nodeParams'=>'string|array{0:string,1:int}', 'command'=>'string', 'arguments='=>'mixed'], 'RedisCluster::command' => ['array|bool'], 'RedisCluster::config' => ['array|bool', 'nodeParams'=>'string|array{0:string,1:int}', 'operation'=>'string', 'key'=>'string', 'value='=>'string'], 'RedisCluster::dbSize' => ['int', 'nodeParams'=>'string|array{0:string,1:int}'], 'RedisCluster::decr' => ['int', 'key'=>'string'], 'RedisCluster::decrBy' => ['int', 'key'=>'string', 'value'=>'int'], 'RedisCluster::del' => ['int', 'key'=>'string', '...other_keys='=>'string'], 'RedisCluster::del\'1' => ['int', 'key'=>'string[]'], 'RedisCluster::discard' => [''], 'RedisCluster::dump' => ['string|false', 'key'=>'string'], 'RedisCluster::echo' => ['string', 'nodeParams'=>'string|array{0:string,1:int}', 'msg'=>'string'], 'RedisCluster::eval' => ['mixed', 'script'=>'', 'args='=>'', 'numKeys='=>''], 'RedisCluster::evalSha' => ['mixed', 'scriptSha'=>'string', 'args='=>'array', 'numKeys='=>'int'], 'RedisCluster::exec' => ['array|void'], 'RedisCluster::exists' => ['bool', 'key'=>'string'], 'RedisCluster::expire' => ['bool', 'key'=>'string', 'ttl'=>'int'], 'RedisCluster::expireAt' => ['bool', 'key'=>'string', 'timestamp'=>'int'], 'RedisCluster::flushAll' => ['bool', 'nodeParams'=>'string|array{0:string,1:int}', 'async='=>'bool'], 'RedisCluster::flushDB' => ['bool', 'nodeParams'=>'string|array{0:string,1:int}', 'async='=>'bool'], 'RedisCluster::geoAdd' => ['int', 'key'=>'string', 'longitude'=>'float', 'latitude'=>'float', 'member'=>'string', '...other_members='=>'float|string'], 'RedisCluster::geoDist' => ['', 'key'=>'string', 'member1'=>'string', 'member2'=>'string', 'unit='=>'string'], 'RedisCluster::geohash' => ['array', 'key'=>'string', 'member'=>'string', '...other_members='=>'string'], 'RedisCluster::geopos' => ['array', 'key'=>'string', 'member'=>'string', '...other_members='=>'string'], 'RedisCluster::geoRadius' => ['', 'key'=>'string', 'longitude'=>'float', 'latitude'=>'float', 'radius'=>'float', 'radiusUnit'=>'string', 'options='=>'array'], 'RedisCluster::geoRadiusByMember' => ['string[]', 'key'=>'string', 'member'=>'string', 'radius'=>'float', 'radiusUnit'=>'string', 'options='=>'array'], 'RedisCluster::get' => ['string|false', 'key'=>'string'], 'RedisCluster::getBit' => ['int', 'key'=>'string', 'offset'=>'int'], 'RedisCluster::getLastError' => ['?string'], 'RedisCluster::getMode' => ['int'], 'RedisCluster::getOption' => ['int', 'option'=>'int'], 'RedisCluster::getRange' => ['string', 'key'=>'string', 'start'=>'int', 'end'=>'int'], 'RedisCluster::getSet' => ['string', 'key'=>'string', 'value'=>'string'], 'RedisCluster::hDel' => ['int|false', 'key'=>'string', 'hashKey'=>'string', '...other_hashKeys='=>'string[]'], 'RedisCluster::hExists' => ['bool', 'key'=>'string', 'hashKey'=>'string'], 'RedisCluster::hGet' => ['string|false', 'key'=>'string', 'hashKey'=>'string'], 'RedisCluster::hGetAll' => ['array', 'key'=>'string'], 'RedisCluster::hIncrBy' => ['int', 'key'=>'string', 'hashKey'=>'string', 'value'=>'int'], 'RedisCluster::hIncrByFloat' => ['float', 'key'=>'string', 'field'=>'string', 'increment'=>'float'], 'RedisCluster::hKeys' => ['array', 'key'=>'string'], 'RedisCluster::hLen' => ['int|false', 'key'=>'string'], 'RedisCluster::hMGet' => ['array', 'key'=>'string', 'hashKeys'=>'array'], 'RedisCluster::hMSet' => ['bool', 'key'=>'string', 'hashKeys'=>'array'], 'RedisCluster::hScan' => ['array', 'key'=>'string', '&iterator'=>'int', 'pattern='=>'string', 'count='=>'int'], 'RedisCluster::hSet' => ['int', 'key'=>'string', 'hashKey'=>'string', 'value'=>'string'], 'RedisCluster::hSetNx' => ['bool', 'key'=>'string', 'hashKey'=>'string', 'value'=>'string'], 'RedisCluster::hStrlen' => ['int', 'key'=>'string', 'member'=>'string'], 'RedisCluster::hVals' => ['array', 'key'=>'string'], 'RedisCluster::incr' => ['int', 'key'=>'string'], 'RedisCluster::incrBy' => ['int', 'key'=>'string', 'value'=>'int'], 'RedisCluster::incrByFloat' => ['float', 'key'=>'string', 'increment'=>'float'], 'RedisCluster::info' => ['array', 'nodeParams'=>'string|array{0:string,1:int}', 'option='=>'string'], 'RedisCluster::keys' => ['array', 'pattern'=>'string'], 'RedisCluster::lastSave' => ['int', 'nodeParams'=>'string|array{0:string,1:int}'], 'RedisCluster::lGet' => ['', 'key'=>'string', 'index'=>'int'], 'RedisCluster::lIndex' => ['string|false', 'key'=>'string', 'index'=>'int'], 'RedisCluster::lInsert' => ['int', 'key'=>'string', 'position'=>'int', 'pivot'=>'string', 'value'=>'string'], 'RedisCluster::lLen' => ['int', 'key'=>'string'], 'RedisCluster::lPop' => ['string|false', 'key'=>'string'], 'RedisCluster::lPush' => ['int|false', 'key'=>'string', 'value1'=>'string', 'value2='=>'string', 'valueN='=>'string'], 'RedisCluster::lPushx' => ['int|false', 'key'=>'string', 'value'=>'string'], 'RedisCluster::lRange' => ['array', 'key'=>'string', 'start'=>'int', 'end'=>'int'], 'RedisCluster::lRem' => ['int|false', 'key'=>'string', 'value'=>'string', 'count'=>'int'], 'RedisCluster::lSet' => ['bool', 'key'=>'string', 'index'=>'int', 'value'=>'string'], 'RedisCluster::lTrim' => ['array|false', 'key'=>'string', 'start'=>'int', 'stop'=>'int'], 'RedisCluster::mget' => ['array', 'array'=>'array'], 'RedisCluster::mset' => ['bool', 'array'=>'array'], 'RedisCluster::msetnx' => ['int', 'array'=>'array'], 'RedisCluster::multi' => ['Redis', 'mode='=>'int'], 'RedisCluster::object' => ['string|int|false', 'string'=>'string', 'key'=>'string'], 'RedisCluster::persist' => ['bool', 'key'=>'string'], 'RedisCluster::pExpire' => ['bool', 'key'=>'string', 'ttl'=>'int'], 'RedisCluster::pExpireAt' => ['bool', 'key'=>'string', 'timestamp'=>'int'], 'RedisCluster::pfAdd' => ['bool', 'key'=>'string', 'elements'=>'array'], 'RedisCluster::pfCount' => ['int', 'key'=>'string'], 'RedisCluster::pfMerge' => ['bool', 'destKey'=>'string', 'sourceKeys'=>'array'], 'RedisCluster::ping' => ['string', 'nodeParams'=>'string|array{0:string,1:int}'], 'RedisCluster::psetex' => ['bool', 'key'=>'string', 'ttl'=>'int', 'value'=>'string'], 'RedisCluster::psubscribe' => ['mixed', 'patterns'=>'array', 'callback'=>'string'], 'RedisCluster::pttl' => ['int', 'key'=>'string'], 'RedisCluster::publish' => ['int', 'channel'=>'string', 'message'=>'string'], 'RedisCluster::pubsub' => ['array', 'nodeParams'=>'string', 'keyword'=>'string', '...argument='=>'string'], 'RedisCluster::punSubscribe' => ['', 'channels'=>'', 'callback'=>''], 'RedisCluster::randomKey' => ['string', 'nodeParams'=>'string|array{0:string,1:int}'], 'RedisCluster::rawCommand' => ['mixed', 'nodeParams'=>'string|array{0:string,1:int}', 'command'=>'string', 'arguments='=>'mixed'], 'RedisCluster::rename' => ['bool', 'srcKey'=>'string', 'dstKey'=>'string'], 'RedisCluster::renameNx' => ['bool', 'srcKey'=>'string', 'dstKey'=>'string'], 'RedisCluster::restore' => ['bool', 'key'=>'string', 'ttl'=>'int', 'value'=>'string'], 'RedisCluster::role' => ['array'], 'RedisCluster::rPop' => ['string|false', 'key'=>'string'], 'RedisCluster::rpoplpush' => ['string|false', 'srcKey'=>'string', 'dstKey'=>'string'], 'RedisCluster::rPush' => ['int|false', 'key'=>'string', 'value1'=>'string', 'value2='=>'string', 'valueN='=>'string'], 'RedisCluster::rPushx' => ['int|false', 'key'=>'string', 'value'=>'string'], 'RedisCluster::sAdd' => ['int|false', 'key'=>'string', 'value1'=>'string', 'value2='=>'string', 'valueN='=>'string'], 'RedisCluster::sAddArray' => ['int|false', 'key'=>'string', 'valueArray'=>'array'], 'RedisCluster::save' => ['bool', 'nodeParams'=>'string|array{0:string,1:int}'], 'RedisCluster::scan' => ['array|false', '&iterator'=>'int', 'nodeParams'=>'string|array{0:string,1:int}', 'pattern='=>'string', 'count='=>'int'], 'RedisCluster::sCard' => ['int', 'key'=>'string'], 'RedisCluster::script' => ['string|bool|array', 'nodeParams'=>'string|array{0:string,1:int}', 'command'=>'string', 'script='=>'string', '...other_scripts='=>'string[]'], 'RedisCluster::sDiff' => ['list', 'key1'=>'string', 'key2'=>'string', '...other_keys='=>'string'], 'RedisCluster::sDiffStore' => ['int', 'dstKey'=>'string', 'key1'=>'string', '...other_keys='=>'string'], 'RedisCluster::set' => ['bool', 'key'=>'string', 'value'=>'string', 'timeout='=>'array|int'], 'RedisCluster::setBit' => ['int', 'key'=>'string', 'offset'=>'int', 'value'=>'bool|int'], 'RedisCluster::setex' => ['bool', 'key'=>'string', 'ttl'=>'int', 'value'=>'string'], 'RedisCluster::setnx' => ['bool', 'key'=>'string', 'value'=>'string'], 'RedisCluster::setOption' => ['bool', 'option'=>'int', 'value'=>'string|int'], 'RedisCluster::setRange' => ['string', 'key'=>'string', 'offset'=>'int', 'value'=>'string'], 'RedisCluster::sInter' => ['list', 'key'=>'string', '...other_keys='=>'string'], 'RedisCluster::sInterStore' => ['int', 'dstKey'=>'string', 'key'=>'string', '...other_keys='=>'string'], 'RedisCluster::sIsMember' => ['bool', 'key'=>'string', 'value'=>'string'], 'RedisCluster::slowLog' => ['array|int|bool', 'nodeParams'=>'string|array{0:string,1:int}', 'command'=>'string', 'length='=>'int'], 'RedisCluster::sMembers' => ['list', 'key'=>'string'], 'RedisCluster::sMove' => ['bool', 'srcKey'=>'string', 'dstKey'=>'string', 'member'=>'string'], 'RedisCluster::sort' => ['array', 'key'=>'string', 'option='=>'array'], 'RedisCluster::sPop' => ['string', 'key'=>'string'], 'RedisCluster::sRandMember' => ['array|string', 'key'=>'string', 'count='=>'int'], 'RedisCluster::sRem' => ['int', 'key'=>'string', 'member1'=>'string', '...other_members='=>'string'], 'RedisCluster::sScan' => ['array|false', 'key'=>'string', '&iterator'=>'int', 'pattern='=>'null', 'count='=>'int'], 'RedisCluster::strlen' => ['int', 'key'=>'string'], 'RedisCluster::subscribe' => ['mixed', 'channels'=>'array', 'callback'=>'string'], 'RedisCluster::sUnion' => ['list', 'key1'=>'string', '...other_keys='=>'string'], 'RedisCluster::sUnion\'1' => ['list', 'keys'=>'string[]'], 'RedisCluster::sUnionStore' => ['int', 'dstKey'=>'string', 'key1'=>'string', '...other_keys='=>'string'], 'RedisCluster::time' => ['array'], 'RedisCluster::ttl' => ['int', 'key'=>'string'], 'RedisCluster::type' => ['int', 'key'=>'string'], 'RedisCluster::unlink' => ['int', 'key'=>'string', '...other_keys='=>'string'], 'RedisCluster::unSubscribe' => ['', 'channels'=>'', '...other_channels='=>''], 'RedisCluster::unwatch' => [''], 'RedisCluster::watch' => ['void', 'key'=>'string', '...other_keys='=>'string'], 'RedisCluster::xack' => ['', 'str_key'=>'string', 'str_group'=>'string', 'arr_ids'=>'array'], 'RedisCluster::xadd' => ['', 'str_key'=>'string', 'str_id'=>'string', 'arr_fields'=>'array', 'i_maxlen='=>'', 'boo_approximate='=>''], 'RedisCluster::xclaim' => ['', 'str_key'=>'string', 'str_group'=>'string', 'str_consumer'=>'string', 'i_min_idle'=>'', 'arr_ids'=>'array', 'arr_opts='=>'array'], 'RedisCluster::xdel' => ['', 'str_key'=>'string', 'arr_ids'=>'array'], 'RedisCluster::xgroup' => ['', 'str_operation'=>'string', 'str_key='=>'string', 'str_arg1='=>'', 'str_arg2='=>'', 'str_arg3='=>''], 'RedisCluster::xinfo' => ['', 'str_cmd'=>'string', 'str_key='=>'string', 'str_group='=>'string'], 'RedisCluster::xlen' => ['', 'key'=>''], 'RedisCluster::xpending' => ['', 'str_key'=>'string', 'str_group'=>'string', 'str_start='=>'', 'str_end='=>'', 'i_count='=>'', 'str_consumer='=>'string'], 'RedisCluster::xrange' => ['', 'str_key'=>'string', 'str_start'=>'', 'str_end'=>'', 'i_count='=>''], 'RedisCluster::xread' => ['', 'arr_streams'=>'array', 'i_count='=>'', 'i_block='=>''], 'RedisCluster::xreadgroup' => ['', 'str_group'=>'string', 'str_consumer'=>'string', 'arr_streams'=>'array', 'i_count='=>'', 'i_block='=>''], 'RedisCluster::xrevrange' => ['', 'str_key'=>'string', 'str_start'=>'', 'str_end'=>'', 'i_count='=>''], 'RedisCluster::xtrim' => ['', 'str_key'=>'string', 'i_maxlen'=>'', 'boo_approximate='=>''], 'RedisCluster::zAdd' => ['int', 'key'=>'string', 'score1'=>'float', 'value1'=>'string', 'score2='=>'float', 'value2='=>'string', 'scoreN='=>'float', 'valueN='=>'string'], 'RedisCluster::zCard' => ['int', 'key'=>'string'], 'RedisCluster::zCount' => ['int', 'key'=>'string', 'start'=>'string', 'end'=>'string'], 'RedisCluster::zIncrBy' => ['float', 'key'=>'string', 'value'=>'float', 'member'=>'string'], 'RedisCluster::zInterStore' => ['int', 'Output'=>'string', 'ZSetKeys'=>'array', 'Weights='=>'?array', 'aggregateFunction='=>'string'], 'RedisCluster::zLexCount' => ['int', 'key'=>'string', 'min'=>'int', 'max'=>'int'], 'RedisCluster::zRange' => ['array', 'key'=>'string', 'start'=>'int', 'end'=>'int', 'withscores='=>'bool'], 'RedisCluster::zRangeByLex' => ['array', 'key'=>'string', 'min'=>'int', 'max'=>'int', 'offset='=>'int', 'limit='=>'int'], 'RedisCluster::zRangeByScore' => ['array', 'key'=>'string', 'start'=>'int', 'end'=>'int', 'options='=>'array'], 'RedisCluster::zRank' => ['int', 'key'=>'string', 'member'=>'string'], 'RedisCluster::zRem' => ['int', 'key'=>'string', 'member1'=>'string', '...other_members='=>'string'], 'RedisCluster::zRemRangeByLex' => ['array', 'key'=>'string', 'min'=>'int', 'max'=>'int'], 'RedisCluster::zRemRangeByRank' => ['int', 'key'=>'string', 'start'=>'int', 'end'=>'int'], 'RedisCluster::zRemRangeByScore' => ['int', 'key'=>'string', 'start'=>'float|string', 'end'=>'float|string'], 'RedisCluster::zRevRange' => ['array', 'key'=>'string', 'start'=>'int', 'end'=>'int', 'withscore='=>'bool'], 'RedisCluster::zRevRangeByLex' => ['array', 'key'=>'string', 'min'=>'int', 'max'=>'int', 'offset='=>'int', 'limit='=>'int'], 'RedisCluster::zRevRangeByScore' => ['array', 'key'=>'string', 'start'=>'int', 'end'=>'int', 'options='=>'array'], 'RedisCluster::zRevRank' => ['int', 'key'=>'string', 'member'=>'string'], 'RedisCluster::zScan' => ['array|false', 'key'=>'string', '&iterator'=>'int', 'pattern='=>'string', 'count='=>'int'], 'RedisCluster::zScore' => ['float', 'key'=>'string', 'member'=>'string'], 'RedisCluster::zUnionStore' => ['int', 'Output'=>'string', 'ZSetKeys'=>'array', 'Weights='=>'?array', 'aggregateFunction='=>'string'], 'Reflection::getModifierNames' => ['list', 'modifiers'=>'int'], 'ReflectionClass::__clone' => ['void'], 'ReflectionClass::__construct' => ['void', 'objectOrClass'=>'object|class-string'], 'ReflectionClass::__toString' => ['string'], 'ReflectionClass::getAttributes' => ['list', 'name='=>'?string', 'flags='=>'int'], 'ReflectionClass::getConstant' => ['mixed', 'name'=>'string'], 'ReflectionClass::getConstants' => ['array', 'filter=' => '?int'], 'ReflectionClass::getConstructor' => ['?ReflectionMethod'], 'ReflectionClass::getDefaultProperties' => ['array'], 'ReflectionClass::getDocComment' => ['string|false'], 'ReflectionClass::getEndLine' => ['int|false'], 'ReflectionClass::getExtension' => ['?ReflectionExtension'], 'ReflectionClass::getExtensionName' => ['string|false'], 'ReflectionClass::getFileName' => ['string|false'], 'ReflectionClass::getInterfaceNames' => ['list'], 'ReflectionClass::getInterfaces' => ['array'], 'ReflectionClass::getMethod' => ['ReflectionMethod', 'name'=>'string'], 'ReflectionClass::getMethods' => ['list', 'filter='=>'?int'], 'ReflectionClass::getModifiers' => ['int'], 'ReflectionClass::getName' => ['class-string'], 'ReflectionClass::getNamespaceName' => ['string'], 'ReflectionClass::getParentClass' => ['ReflectionClass|false'], 'ReflectionClass::getProperties' => ['list', 'filter='=>'?int'], 'ReflectionClass::getProperty' => ['ReflectionProperty', 'name'=>'string'], 'ReflectionClass::getReflectionConstant' => ['ReflectionClassConstant|false', 'name'=>'string'], 'ReflectionClass::getReflectionConstants' => ['list', 'filter='=>'?int'], 'ReflectionClass::getShortName' => ['string'], 'ReflectionClass::getStartLine' => ['int|false'], 'ReflectionClass::getStaticProperties' => ['array'], 'ReflectionClass::getStaticPropertyValue' => ['mixed', 'name'=>'string', 'default='=>'mixed'], 'ReflectionClass::getTraitAliases' => ['array'], 'ReflectionClass::getTraitNames' => ['list'], 'ReflectionClass::getTraits' => ['array'], 'ReflectionClass::hasConstant' => ['bool', 'name'=>'string'], 'ReflectionClass::hasMethod' => ['bool', 'name'=>'string'], 'ReflectionClass::hasProperty' => ['bool', 'name'=>'string'], 'ReflectionClass::implementsInterface' => ['bool', 'interface'=>'interface-string|ReflectionClass'], 'ReflectionClass::inNamespace' => ['bool'], 'ReflectionClass::isAbstract' => ['bool'], 'ReflectionClass::isAnonymous' => ['bool'], 'ReflectionClass::isCloneable' => ['bool'], 'ReflectionClass::isEnum' => ['bool'], 'ReflectionClass::isFinal' => ['bool'], 'ReflectionClass::isInstance' => ['bool', 'object'=>'object'], 'ReflectionClass::isInstantiable' => ['bool'], 'ReflectionClass::isInterface' => ['bool'], 'ReflectionClass::isInternal' => ['bool'], 'ReflectionClass::isIterable' => ['bool'], 'ReflectionClass::isIterateable' => ['bool'], 'ReflectionClass::isSubclassOf' => ['bool', 'class'=>'class-string|ReflectionClass'], 'ReflectionClass::isTrait' => ['bool'], 'ReflectionClass::isUserDefined' => ['bool'], 'ReflectionClass::newInstance' => ['object', '...args='=>'mixed'], 'ReflectionClass::newInstanceArgs' => ['object', 'args='=>'list|array'], 'ReflectionClass::newInstanceWithoutConstructor' => ['object'], 'ReflectionClass::setStaticPropertyValue' => ['void', 'name'=>'string', 'value'=>'mixed'], 'ReflectionClassConstant::__construct' => ['void', 'class'=>'object|class-string', 'constant'=>'string'], 'ReflectionClassConstant::__toString' => ['string'], 'ReflectionClassConstant::getAttributes' => ['list', 'name='=>'?string', 'flags='=>'int'], 'ReflectionClassConstant::getDeclaringClass' => ['ReflectionClass'], 'ReflectionClassConstant::getDocComment' => ['string|false'], 'ReflectionClassConstant::getModifiers' => ['int'], 'ReflectionClassConstant::getName' => ['string'], 'ReflectionClassConstant::getValue' => ['scalar|array|null'], 'ReflectionClassConstant::isPrivate' => ['bool'], 'ReflectionClassConstant::isProtected' => ['bool'], 'ReflectionClassConstant::isPublic' => ['bool'], 'ReflectionEnum::getBackingType' => ['?ReflectionType'], 'ReflectionEnum::getCase' => ['ReflectionEnumUnitCase', 'name' => 'string'], 'ReflectionEnum::getCases' => ['list'], 'ReflectionEnum::hasCase' => ['bool', 'name' => 'string'], 'ReflectionEnum::isBacked' => ['bool'], 'ReflectionEnumUnitCase::getEnum' => ['ReflectionEnum'], 'ReflectionEnumUnitCase::getValue' => ['UnitEnum'], 'ReflectionEnumBackedCase::getBackingValue' => ['string|int'], 'ReflectionExtension::__clone' => ['void'], 'ReflectionExtension::__construct' => ['void', 'name'=>'string'], 'ReflectionExtension::__toString' => ['string'], 'ReflectionExtension::getClasses' => ['array'], 'ReflectionExtension::getClassNames' => ['list'], 'ReflectionExtension::getConstants' => ['array'], 'ReflectionExtension::getDependencies' => ['array'], 'ReflectionExtension::getFunctions' => ['array'], 'ReflectionExtension::getINIEntries' => ['array'], 'ReflectionExtension::getName' => ['string'], 'ReflectionExtension::getVersion' => ['?string'], 'ReflectionExtension::info' => ['void'], 'ReflectionExtension::isPersistent' => ['bool'], 'ReflectionExtension::isTemporary' => ['bool'], 'ReflectionFunction::__construct' => ['void', 'function'=>'callable-string|Closure'], 'ReflectionFunction::__toString' => ['string'], 'ReflectionFunction::getClosure' => ['Closure'], 'ReflectionFunction::getClosureScopeClass' => ['ReflectionClass'], 'ReflectionFunction::getClosureThis' => ['object'], 'ReflectionFunction::getDocComment' => ['string|false'], 'ReflectionFunction::getEndLine' => ['int|false'], 'ReflectionFunction::getExtension' => ['?ReflectionExtension'], 'ReflectionFunction::getExtensionName' => ['string|false'], 'ReflectionFunction::getFileName' => ['string|false'], 'ReflectionFunction::getName' => ['callable-string'], 'ReflectionFunction::getNamespaceName' => ['string'], 'ReflectionFunction::getNumberOfParameters' => ['int'], 'ReflectionFunction::getNumberOfRequiredParameters' => ['int'], 'ReflectionFunction::getParameters' => ['list'], 'ReflectionFunction::getReturnType' => ['?ReflectionType'], 'ReflectionFunction::getShortName' => ['string'], 'ReflectionFunction::getStartLine' => ['int|false'], 'ReflectionFunction::getStaticVariables' => ['array'], 'ReflectionFunction::hasReturnType' => ['bool'], 'ReflectionFunction::inNamespace' => ['bool'], 'ReflectionFunction::invoke' => ['mixed', '...args='=>'mixed'], 'ReflectionFunction::invokeArgs' => ['mixed', 'args'=>'array'], 'ReflectionFunction::isClosure' => ['bool'], 'ReflectionFunction::isDeprecated' => ['bool'], 'ReflectionFunction::isDisabled' => ['bool'], 'ReflectionFunction::isGenerator' => ['bool'], 'ReflectionFunction::isInternal' => ['bool'], 'ReflectionFunction::isUserDefined' => ['bool'], 'ReflectionFunction::isVariadic' => ['bool'], 'ReflectionFunction::returnsReference' => ['bool'], 'ReflectionFunctionAbstract::__clone' => ['void'], 'ReflectionFunctionAbstract::__toString' => ['string'], 'ReflectionFunctionAbstract::getAttributes' => ['list', 'name='=>'?string', 'flags='=>'int'], 'ReflectionFunctionAbstract::getClosureScopeClass' => ['ReflectionClass|null'], 'ReflectionFunctionAbstract::getClosureThis' => ['object|null'], 'ReflectionFunctionAbstract::getDocComment' => ['string|false'], 'ReflectionFunctionAbstract::getEndLine' => ['int|false'], 'ReflectionFunctionAbstract::getExtension' => ['?ReflectionExtension'], 'ReflectionFunctionAbstract::getExtensionName' => ['string|false'], 'ReflectionFunctionAbstract::getFileName' => ['string|false'], 'ReflectionFunctionAbstract::getName' => ['string'], 'ReflectionFunctionAbstract::getNamespaceName' => ['string'], 'ReflectionFunctionAbstract::getNumberOfParameters' => ['int'], 'ReflectionFunctionAbstract::getNumberOfRequiredParameters' => ['int'], 'ReflectionFunctionAbstract::getParameters' => ['list'], 'ReflectionFunctionAbstract::getReturnType' => ['?ReflectionType'], 'ReflectionFunctionAbstract::getShortName' => ['string'], 'ReflectionFunctionAbstract::getStartLine' => ['int|false'], 'ReflectionFunctionAbstract::getStaticVariables' => ['array'], 'ReflectionFunctionAbstract::getTentativeReturnType' => ['?ReflectionType'], 'ReflectionFunctionAbstract::hasReturnType' => ['bool'], 'ReflectionFunctionAbstract::hasTentativeReturnType' => ['bool'], 'ReflectionFunctionAbstract::inNamespace' => ['bool'], 'ReflectionFunctionAbstract::isClosure' => ['bool'], 'ReflectionFunctionAbstract::isDeprecated' => ['bool'], 'ReflectionFunctionAbstract::isGenerator' => ['bool'], 'ReflectionFunctionAbstract::isInternal' => ['bool'], 'ReflectionFunctionAbstract::isStatic' => ['bool'], 'ReflectionFunctionAbstract::isUserDefined' => ['bool'], 'ReflectionFunctionAbstract::isVariadic' => ['bool'], 'ReflectionFunctionAbstract::returnsReference' => ['bool'], 'ReflectionGenerator::__construct' => ['void', 'generator'=>'Generator'], 'ReflectionGenerator::getExecutingFile' => ['string'], 'ReflectionGenerator::getExecutingGenerator' => ['Generator'], 'ReflectionGenerator::getExecutingLine' => ['int'], 'ReflectionGenerator::getFunction' => ['ReflectionFunctionAbstract'], 'ReflectionGenerator::getThis' => ['?object'], 'ReflectionGenerator::getTrace' => ['array', 'options='=>'int'], 'ReflectionMethod::__construct' => ['void', 'class'=>'class-string|object', 'name'=>'string'], 'ReflectionMethod::__construct\'1' => ['void', 'class_method'=>'string'], 'ReflectionMethod::__toString' => ['string'], 'ReflectionMethod::getClosure' => ['Closure', 'object='=>'?object'], 'ReflectionMethod::getClosureScopeClass' => ['ReflectionClass'], 'ReflectionMethod::getClosureThis' => ['object'], 'ReflectionMethod::getDeclaringClass' => ['ReflectionClass'], 'ReflectionMethod::getDocComment' => ['false|string'], 'ReflectionMethod::getEndLine' => ['false|int'], 'ReflectionMethod::getExtension' => ['?ReflectionExtension'], 'ReflectionMethod::getExtensionName' => ['string|false'], 'ReflectionMethod::getFileName' => ['false|string'], 'ReflectionMethod::getModifiers' => ['int'], 'ReflectionMethod::getName' => ['string'], 'ReflectionMethod::getNamespaceName' => ['string'], 'ReflectionMethod::getNumberOfParameters' => ['int'], 'ReflectionMethod::getNumberOfRequiredParameters' => ['int'], 'ReflectionMethod::getParameters' => ['list<\ReflectionParameter>'], 'ReflectionMethod::getPrototype' => ['ReflectionMethod'], 'ReflectionMethod::getReturnType' => ['?ReflectionType'], 'ReflectionMethod::getShortName' => ['string'], 'ReflectionMethod::getStartLine' => ['false|int'], 'ReflectionMethod::getStaticVariables' => ['array'], 'ReflectionMethod::hasReturnType' => ['bool'], 'ReflectionMethod::inNamespace' => ['bool'], 'ReflectionMethod::invoke' => ['mixed', 'object'=>'?object', '...args='=>'mixed'], 'ReflectionMethod::invokeArgs' => ['mixed', 'object'=>'?object', 'args'=>'array'], 'ReflectionMethod::isAbstract' => ['bool'], 'ReflectionMethod::isClosure' => ['bool'], 'ReflectionMethod::isConstructor' => ['bool'], 'ReflectionMethod::isDeprecated' => ['bool'], 'ReflectionMethod::isDestructor' => ['bool'], 'ReflectionMethod::isFinal' => ['bool'], 'ReflectionMethod::isGenerator' => ['bool'], 'ReflectionMethod::isInternal' => ['bool'], 'ReflectionMethod::isPrivate' => ['bool'], 'ReflectionMethod::isProtected' => ['bool'], 'ReflectionMethod::isPublic' => ['bool'], 'ReflectionMethod::isUserDefined' => ['bool'], 'ReflectionMethod::isVariadic' => ['bool'], 'ReflectionMethod::returnsReference' => ['bool'], 'ReflectionMethod::setAccessible' => ['void', 'accessible'=>'bool'], 'ReflectionNamedType::__toString' => ['string'], 'ReflectionNamedType::allowsNull' => ['bool'], 'ReflectionNamedType::getName' => ['string'], 'ReflectionNamedType::isBuiltin' => ['bool'], 'ReflectionObject::__construct' => ['void', 'object'=>'object'], 'ReflectionObject::__toString' => ['string'], 'ReflectionObject::getConstant' => ['mixed', 'name'=>'string'], 'ReflectionObject::getConstants' => ['array', 'filter='=>'?int'], 'ReflectionObject::getConstructor' => ['?ReflectionMethod'], 'ReflectionObject::getDefaultProperties' => ['array'], 'ReflectionObject::getDocComment' => ['false|string'], 'ReflectionObject::getEndLine' => ['false|int'], 'ReflectionObject::getExtension' => ['?ReflectionExtension'], 'ReflectionObject::getExtensionName' => ['false|string'], 'ReflectionObject::getFileName' => ['false|string'], 'ReflectionObject::getInterfaceNames' => ['class-string[]'], 'ReflectionObject::getInterfaces' => ['array'], 'ReflectionObject::getMethod' => ['ReflectionMethod', 'name'=>'string'], 'ReflectionObject::getMethods' => ['ReflectionMethod[]', 'filter='=>'?int'], 'ReflectionObject::getModifiers' => ['int'], 'ReflectionObject::getName' => ['string'], 'ReflectionObject::getNamespaceName' => ['string'], 'ReflectionObject::getParentClass' => ['ReflectionClass|false'], 'ReflectionObject::getProperties' => ['ReflectionProperty[]', 'filter='=>'?int'], 'ReflectionObject::getProperty' => ['ReflectionProperty', 'name'=>'string'], 'ReflectionObject::getReflectionConstant' => ['ReflectionClassConstant', 'name'=>'string'], 'ReflectionObject::getReflectionConstants' => ['list<\ReflectionClassConstant>', 'filter='=>'?int'], 'ReflectionObject::getShortName' => ['string'], 'ReflectionObject::getStartLine' => ['false|int'], 'ReflectionObject::getStaticProperties' => ['ReflectionProperty[]'], 'ReflectionObject::getStaticPropertyValue' => ['mixed', 'name'=>'string', 'default='=>'mixed'], 'ReflectionObject::getTraitAliases' => ['array'], 'ReflectionObject::getTraitNames' => ['list'], 'ReflectionObject::getTraits' => ['array'], 'ReflectionObject::hasConstant' => ['bool', 'name'=>'string'], 'ReflectionObject::hasMethod' => ['bool', 'name'=>'string'], 'ReflectionObject::hasProperty' => ['bool', 'name'=>'string'], 'ReflectionObject::implementsInterface' => ['bool', 'interface'=>'ReflectionClass|interface-string'], 'ReflectionObject::inNamespace' => ['bool'], 'ReflectionObject::isAbstract' => ['bool'], 'ReflectionObject::isAnonymous' => ['bool'], 'ReflectionObject::isCloneable' => ['bool'], 'ReflectionObject::isEnum' => ['bool'], 'ReflectionObject::isFinal' => ['bool'], 'ReflectionObject::isInstance' => ['bool', 'object'=>'object'], 'ReflectionObject::isInstantiable' => ['bool'], 'ReflectionObject::isInterface' => ['bool'], 'ReflectionObject::isInternal' => ['bool'], 'ReflectionObject::isIterable' => ['bool'], 'ReflectionObject::isIterateable' => ['bool'], 'ReflectionObject::isSubclassOf' => ['bool', 'class'=>'ReflectionClass|string'], 'ReflectionObject::isTrait' => ['bool'], 'ReflectionObject::isUserDefined' => ['bool'], 'ReflectionObject::newInstance' => ['object', 'args='=>'mixed', '...args='=>'array'], 'ReflectionObject::newInstanceArgs' => ['object', 'args='=>'list|array'], 'ReflectionObject::newInstanceWithoutConstructor' => ['object'], 'ReflectionObject::setStaticPropertyValue' => ['void', 'name'=>'string', 'value'=>'string'], 'ReflectionParameter::__clone' => ['void'], 'ReflectionParameter::__construct' => ['void', 'function'=>'string|array|object', 'param'=>'int|string'], 'ReflectionParameter::__toString' => ['string'], 'ReflectionParameter::allowsNull' => ['bool'], 'ReflectionParameter::canBePassedByValue' => ['bool'], 'ReflectionParameter::getAttributes' => ['list', 'name='=>'?string', 'flags='=>'int'], 'ReflectionParameter::getClass' => ['?ReflectionClass'], 'ReflectionParameter::getDeclaringClass' => ['?ReflectionClass'], 'ReflectionParameter::getDeclaringFunction' => ['ReflectionFunctionAbstract'], 'ReflectionParameter::getDefaultValue' => ['mixed'], 'ReflectionParameter::getDefaultValueConstantName' => ['?string'], 'ReflectionParameter::getName' => ['non-empty-string'], 'ReflectionParameter::getPosition' => ['int<0, max>'], 'ReflectionParameter::getType' => ['?ReflectionType'], 'ReflectionParameter::hasType' => ['bool'], 'ReflectionParameter::isArray' => ['bool'], 'ReflectionParameter::isCallable' => ['bool'], 'ReflectionParameter::isDefaultValueAvailable' => ['bool'], 'ReflectionParameter::isDefaultValueConstant' => ['bool'], 'ReflectionParameter::isOptional' => ['bool'], 'ReflectionParameter::isPassedByReference' => ['bool'], 'ReflectionParameter::isVariadic' => ['bool'], 'ReflectionProperty::__clone' => ['void'], 'ReflectionProperty::__construct' => ['void', 'class'=>'object|class-string', 'property'=>'string'], 'ReflectionProperty::__toString' => ['string'], 'ReflectionProperty::getAttributes' => ['list', 'name='=>'?string', 'flags='=>'int'], 'ReflectionProperty::getDeclaringClass' => ['ReflectionClass'], 'ReflectionProperty::getDefaultValue' => ['mixed'], 'ReflectionProperty::getDocComment' => ['string|false'], 'ReflectionProperty::getModifiers' => ['int'], 'ReflectionProperty::getName' => ['string'], 'ReflectionProperty::getType' => ['?ReflectionType'], 'ReflectionProperty::getValue' => ['mixed', 'object='=>'null|object'], 'ReflectionProperty::hasDefaultValue' => ['bool'], 'ReflectionProperty::hasType' => ['bool'], 'ReflectionProperty::isDefault' => ['bool'], 'ReflectionProperty::isInitialized' => ['bool', 'object='=>'null|object'], 'ReflectionProperty::isPrivate' => ['bool'], 'ReflectionProperty::isPromoted' => ['bool'], 'ReflectionProperty::isProtected' => ['bool'], 'ReflectionProperty::isPublic' => ['bool'], 'ReflectionProperty::isReadonly' => ['bool'], 'ReflectionProperty::isStatic' => ['bool'], 'ReflectionProperty::setAccessible' => ['void', 'accessible'=>'bool'], 'ReflectionProperty::setValue' => ['void', 'object'=>'null|object', 'value'=>''], 'ReflectionProperty::setValue\'1' => ['void', 'value'=>''], 'ReflectionType::__clone' => ['void'], 'ReflectionType::__toString' => ['string'], 'ReflectionType::allowsNull' => ['bool'], 'ReflectionUnionType::getTypes' => ['list'], 'ReflectionZendExtension::__clone' => ['void'], 'ReflectionZendExtension::__construct' => ['void', 'name'=>'string'], 'ReflectionZendExtension::__toString' => ['string'], 'ReflectionZendExtension::getAuthor' => ['string'], 'ReflectionZendExtension::getCopyright' => ['string'], 'ReflectionZendExtension::getName' => ['string'], 'ReflectionZendExtension::getURL' => ['string'], 'ReflectionZendExtension::getVersion' => ['string'], 'Reflector::__toString' => ['string'], 'Reflector::export' => ['?string'], 'RegexIterator::__construct' => ['void', 'iterator'=>'Iterator', 'pattern'=>'string', 'mode='=>'int', 'flags='=>'int', 'pregFlags='=>'int'], 'RegexIterator::accept' => ['bool'], 'RegexIterator::current' => ['mixed'], 'RegexIterator::getFlags' => ['int'], 'RegexIterator::getInnerIterator' => ['Iterator'], 'RegexIterator::getMode' => ['int'], 'RegexIterator::getPregFlags' => ['int'], 'RegexIterator::getRegex' => ['string'], 'RegexIterator::key' => ['mixed'], 'RegexIterator::next' => ['void'], 'RegexIterator::rewind' => ['void'], 'RegexIterator::setFlags' => ['void', 'flags'=>'int'], 'RegexIterator::setMode' => ['void', 'mode'=>'int'], 'RegexIterator::setPregFlags' => ['void', 'pregFlags'=>'int'], 'RegexIterator::valid' => ['bool'], 'register_event_handler' => ['bool', 'event_handler_func'=>'string', 'handler_register_name'=>'string', 'event_type_mask'=>'int'], 'register_shutdown_function' => ['void', 'callback'=>'callable', '...args='=>'mixed'], 'register_tick_function' => ['bool', 'callback'=>'callable():void', '...args='=>'mixed'], 'rename' => ['bool', 'from'=>'string', 'to'=>'string', 'context='=>'resource'], 'rename_function' => ['bool', 'original_name'=>'string', 'new_name'=>'string'], 'reset' => ['mixed|false', '&r_array'=>'array'], 'ResourceBundle::__construct' => ['void', 'locale'=>'?string', 'bundle'=>'?string', 'fallback='=>'bool'], 'ResourceBundle::count' => ['int'], 'ResourceBundle::create' => ['?ResourceBundle', 'locale'=>'?string', 'bundle'=>'?string', 'fallback='=>'bool'], 'ResourceBundle::get' => ['mixed', 'index'=>'string|int', 'fallback='=>'bool'], 'ResourceBundle::getErrorCode' => ['int'], 'ResourceBundle::getErrorMessage' => ['string'], 'ResourceBundle::getLocales' => ['array|false', 'bundle'=>'string'], 'resourcebundle_count' => ['int', 'bundle'=>'ResourceBundle'], 'resourcebundle_create' => ['?ResourceBundle', 'locale'=>'?string', 'bundle'=>'?string', 'fallback='=>'bool'], 'resourcebundle_get' => ['mixed|null', 'bundle'=>'ResourceBundle', 'index'=>'string|int', 'fallback='=>'bool'], 'resourcebundle_get_error_code' => ['int', 'bundle'=>'ResourceBundle'], 'resourcebundle_get_error_message' => ['string', 'bundle'=>'ResourceBundle'], 'resourcebundle_locales' => ['array', 'bundle'=>'string'], 'restore_error_handler' => ['true'], 'restore_exception_handler' => ['true'], 'restore_include_path' => ['void'], 'rewind' => ['bool', 'stream'=>'resource'], 'rewinddir' => ['void', 'dir_handle='=>'resource'], 'rmdir' => ['bool', 'directory'=>'string', 'context='=>'resource'], 'round' => ['float', 'num'=>'float|int', 'precision='=>'int', 'mode='=>'0|positive-int'], 'rpm_close' => ['bool', 'rpmr'=>'resource'], 'rpm_get_tag' => ['mixed', 'rpmr'=>'resource', 'tagnum'=>'int'], 'rpm_is_valid' => ['bool', 'filename'=>'string'], 'rpm_open' => ['resource|false', 'filename'=>'string'], 'rpm_version' => ['string'], 'rpmaddtag' => ['bool', 'tag'=>'int'], 'rpmdbinfo' => ['array', 'nevr'=>'string', 'full='=>'bool'], 'rpmdbsearch' => ['array', 'pattern'=>'string', 'rpmtag='=>'int', 'rpmmire='=>'int', 'full='=>'bool'], 'rpminfo' => ['array', 'path'=>'string', 'full='=>'bool', 'error='=>'string'], 'rpmvercmp' => ['int', 'evr1'=>'string', 'evr2'=>'string'], 'rrd_create' => ['bool', 'filename'=>'string', 'options'=>'array'], 'rrd_disconnect' => ['void'], 'rrd_error' => ['string'], 'rrd_fetch' => ['array', 'filename'=>'string', 'options'=>'array'], 'rrd_first' => ['int|false', 'file'=>'string', 'raaindex='=>'int'], 'rrd_graph' => ['array|false', 'filename'=>'string', 'options'=>'array'], 'rrd_info' => ['array|false', 'filename'=>'string'], 'rrd_last' => ['int', 'filename'=>'string'], 'rrd_lastupdate' => ['array|false', 'filename'=>'string'], 'rrd_restore' => ['bool', 'xml_file'=>'string', 'rrd_file'=>'string', 'options='=>'array'], 'rrd_tune' => ['bool', 'filename'=>'string', 'options'=>'array'], 'rrd_update' => ['bool', 'filename'=>'string', 'options'=>'array'], 'rrd_version' => ['string'], 'rrd_xport' => ['array|false', 'options'=>'array'], 'rrdc_disconnect' => ['void'], 'RRDCreator::__construct' => ['void', 'path'=>'string', 'starttime='=>'string', 'step='=>'int'], 'RRDCreator::addArchive' => ['void', 'description'=>'string'], 'RRDCreator::addDataSource' => ['void', 'description'=>'string'], 'RRDCreator::save' => ['bool'], 'RRDGraph::__construct' => ['void', 'path'=>'string'], 'RRDGraph::save' => ['array|false'], 'RRDGraph::saveVerbose' => ['array|false'], 'RRDGraph::setOptions' => ['void', 'options'=>'array'], 'RRDUpdater::__construct' => ['void', 'path'=>'string'], 'RRDUpdater::update' => ['bool', 'values'=>'array', 'time='=>'string'], 'rsort' => ['true', '&rw_array'=>'array', 'flags='=>'int'], 'rtrim' => ['string', 'string'=>'string', 'characters='=>'string'], 'runkit7_constant_add' => ['bool', 'constant_name'=>'string', 'value'=>'mixed', 'new_visibility='=>'int'], 'runkit7_constant_redefine' => ['bool', 'constant_name'=>'string', 'value'=>'mixed', 'new_visibility='=>'?int'], 'runkit7_constant_remove' => ['bool', 'constant_name'=>'string'], 'runkit7_function_add' => ['bool', 'function_name'=>'string', 'argument_list_or_closure'=>'Closure|string', 'code_or_doc_comment='=>'?string', 'return_by_reference='=>'?bool', 'doc_comment='=>'?string', 'return_type='=>'?string', 'is_strict='=>'?bool'], 'runkit7_function_copy' => ['bool', 'source_name'=>'string', 'target_name'=>'string'], 'runkit7_function_redefine' => ['bool', 'function_name'=>'string', 'argument_list_or_closure'=>'Closure|string', 'code_or_doc_comment='=>'?string', 'return_by_reference='=>'?bool', 'doc_comment='=>'?string', 'return_type='=>'?string', 'is_strict='=>'?bool'], 'runkit7_function_remove' => ['bool', 'function_name'=>'string'], 'runkit7_function_rename' => ['bool', 'source_name'=>'string', 'target_name'=>'string'], 'runkit7_import' => ['bool', 'filename'=>'string', 'flags='=>'?int'], 'runkit7_method_add' => ['bool', 'class_name'=>'string', 'method_name'=>'string', 'argument_list_or_closure'=>'Closure|string', 'code_or_flags='=>'int|null|string', 'flags_or_doc_comment='=>'int|null|string', 'doc_comment='=>'?string', 'return_type='=>'?string', 'is_strict='=>'?bool'], 'runkit7_method_copy' => ['bool', 'destination_class'=>'string', 'destination_method'=>'string', 'source_class'=>'string', 'source_method='=>'?string'], 'runkit7_method_redefine' => ['bool', 'class_name'=>'string', 'method_name'=>'string', 'argument_list_or_closure'=>'Closure|string', 'code_or_flags='=>'int|null|string', 'flags_or_doc_comment='=>'int|null|string', 'doc_comment='=>'?string', 'return_type='=>'?string', 'is_strict='=>'?bool'], 'runkit7_method_remove' => ['bool', 'class_name'=>'string', 'method_name'=>'string'], 'runkit7_method_rename' => ['bool', 'class_name'=>'string', 'source_method_name'=>'string', 'source_target_name'=>'string'], 'runkit7_superglobals' => ['array'], 'runkit7_zval_inspect' => ['array', 'value'=>'mixed'], 'runkit_class_adopt' => ['bool', 'classname'=>'string', 'parentname'=>'string'], 'runkit_class_emancipate' => ['bool', 'classname'=>'string'], 'runkit_constant_add' => ['bool', 'constname'=>'string', 'value'=>'mixed'], 'runkit_constant_redefine' => ['bool', 'constname'=>'string', 'newvalue'=>'mixed'], 'runkit_constant_remove' => ['bool', 'constname'=>'string'], 'runkit_function_add' => ['bool', 'funcname'=>'string', 'arglist'=>'string', 'code'=>'string', 'doccomment='=>'?string'], 'runkit_function_add\'1' => ['bool', 'funcname'=>'string', 'closure'=>'Closure', 'doccomment='=>'?string'], 'runkit_function_copy' => ['bool', 'funcname'=>'string', 'targetname'=>'string'], 'runkit_function_redefine' => ['bool', 'funcname'=>'string', 'arglist'=>'string', 'code'=>'string', 'doccomment='=>'?string'], 'runkit_function_redefine\'1' => ['bool', 'funcname'=>'string', 'closure'=>'Closure', 'doccomment='=>'?string'], 'runkit_function_remove' => ['bool', 'funcname'=>'string'], 'runkit_function_rename' => ['bool', 'funcname'=>'string', 'newname'=>'string'], 'runkit_import' => ['bool', 'filename'=>'string', 'flags='=>'int'], 'runkit_lint' => ['bool', 'code'=>'string'], 'runkit_lint_file' => ['bool', 'filename'=>'string'], 'runkit_method_add' => ['bool', 'classname'=>'string', 'methodname'=>'string', 'args'=>'string', 'code'=>'string', 'flags='=>'int', 'doccomment='=>'?string'], 'runkit_method_add\'1' => ['bool', 'classname'=>'string', 'methodname'=>'string', 'closure'=>'Closure', 'flags='=>'int', 'doccomment='=>'?string'], 'runkit_method_copy' => ['bool', 'dclass'=>'string', 'dmethod'=>'string', 'sclass'=>'string', 'smethod='=>'string'], 'runkit_method_redefine' => ['bool', 'classname'=>'string', 'methodname'=>'string', 'args'=>'string', 'code'=>'string', 'flags='=>'int', 'doccomment='=>'?string'], 'runkit_method_redefine\'1' => ['bool', 'classname'=>'string', 'methodname'=>'string', 'closure'=>'Closure', 'flags='=>'int', 'doccomment='=>'?string'], 'runkit_method_remove' => ['bool', 'classname'=>'string', 'methodname'=>'string'], 'runkit_method_rename' => ['bool', 'classname'=>'string', 'methodname'=>'string', 'newname'=>'string'], 'runkit_return_value_used' => ['bool'], 'Runkit_Sandbox::__construct' => ['void', 'options='=>'array'], 'runkit_sandbox_output_handler' => ['mixed', 'sandbox'=>'object', 'callback='=>'mixed'], 'Runkit_Sandbox_Parent' => [''], 'Runkit_Sandbox_Parent::__construct' => ['void'], 'runkit_superglobals' => ['array'], 'runkit_zval_inspect' => ['array', 'value'=>'mixed'], 'RuntimeException::__construct' => ['void', 'message='=>'string', 'code='=>'int', 'previous='=>'?Throwable'], 'RuntimeException::__toString' => ['string'], 'RuntimeException::getCode' => ['int'], 'RuntimeException::getFile' => ['string'], 'RuntimeException::getLine' => ['int'], 'RuntimeException::getMessage' => ['string'], 'RuntimeException::getPrevious' => ['?Throwable'], 'RuntimeException::getTrace' => ['list\',args?:array}>'], 'RuntimeException::getTraceAsString' => ['string'], 'SAMConnection::commit' => ['bool'], 'SAMConnection::connect' => ['bool', 'protocol'=>'string', 'properties='=>'array'], 'SAMConnection::disconnect' => ['bool'], 'SAMConnection::errno' => ['int'], 'SAMConnection::error' => ['string'], 'SAMConnection::isConnected' => ['bool'], 'SAMConnection::peek' => ['SAMMessage', 'target'=>'string', 'properties='=>'array'], 'SAMConnection::peekAll' => ['array', 'target'=>'string', 'properties='=>'array'], 'SAMConnection::receive' => ['SAMMessage', 'target'=>'string', 'properties='=>'array'], 'SAMConnection::remove' => ['SAMMessage', 'target'=>'string', 'properties='=>'array'], 'SAMConnection::rollback' => ['bool'], 'SAMConnection::send' => ['string', 'target'=>'string', 'msg'=>'sammessage', 'properties='=>'array'], 'SAMConnection::setDebug' => ['', 'switch'=>'bool'], 'SAMConnection::subscribe' => ['string', 'targettopic'=>'string'], 'SAMConnection::unsubscribe' => ['bool', 'subscriptionid'=>'string', 'targettopic='=>'string'], 'SAMMessage::body' => ['string'], 'SAMMessage::header' => ['object'], 'sapi_windows_cp_conv' => ['?string', 'in_codepage'=>'int|string', 'out_codepage'=>'int|string', 'subject'=>'string'], 'sapi_windows_cp_get' => ['int', 'kind='=>'string'], 'sapi_windows_cp_is_utf8' => ['bool'], 'sapi_windows_cp_set' => ['bool', 'codepage'=>'int'], 'sapi_windows_vt100_support' => ['bool', 'stream'=>'resource', 'enable='=>'?bool'], 'Saxon\SaxonProcessor::__construct' => ['void', 'license='=>'bool', 'cwd='=>'string'], 'Saxon\SaxonProcessor::createAtomicValue' => ['Saxon\XdmValue', 'primitive_type_val'=>'bool|float|int|string'], 'Saxon\SaxonProcessor::newSchemaValidator' => ['Saxon\SchemaValidator'], 'Saxon\SaxonProcessor::newXPathProcessor' => ['Saxon\XPathProcessor'], 'Saxon\SaxonProcessor::newXQueryProcessor' => ['Saxon\XQueryProcessor'], 'Saxon\SaxonProcessor::newXsltProcessor' => ['Saxon\XsltProcessor'], 'Saxon\SaxonProcessor::parseXmlFromFile' => ['Saxon\XdmNode', 'fileName'=>'string'], 'Saxon\SaxonProcessor::parseXmlFromString' => ['Saxon\XdmNode', 'value'=>'string'], 'Saxon\SaxonProcessor::registerPHPFunctions' => ['void', 'library'=>'string'], 'Saxon\SaxonProcessor::setConfigurationProperty' => ['void', 'name'=>'string', 'value'=>'string'], 'Saxon\SaxonProcessor::setcwd' => ['void', 'cwd'=>'string'], 'Saxon\SaxonProcessor::setResourceDirectory' => ['void', 'dir'=>'string'], 'Saxon\SaxonProcessor::version' => ['string'], 'Saxon\SchemaValidator::clearParameters' => ['void'], 'Saxon\SchemaValidator::clearProperties' => ['void'], 'Saxon\SchemaValidator::exceptionClear' => ['void'], 'Saxon\SchemaValidator::getErrorCode' => ['string', 'i'=>'int'], 'Saxon\SchemaValidator::getErrorMessage' => ['string', 'i'=>'int'], 'Saxon\SchemaValidator::getExceptionCount' => ['int'], 'Saxon\SchemaValidator::getValidationReport' => ['Saxon\XdmNode'], 'Saxon\SchemaValidator::registerSchemaFromFile' => ['void', 'fileName'=>'string'], 'Saxon\SchemaValidator::registerSchemaFromString' => ['void', 'schemaStr'=>'string'], 'Saxon\SchemaValidator::setOutputFile' => ['void', 'fileName'=>'string'], 'Saxon\SchemaValidator::setParameter' => ['void', 'name'=>'string', 'value'=>'Saxon\XdmValue'], 'Saxon\SchemaValidator::setProperty' => ['void', 'name'=>'string', 'value'=>'string'], 'Saxon\SchemaValidator::setSourceNode' => ['void', 'node'=>'Saxon\XdmNode'], 'Saxon\SchemaValidator::validate' => ['void', 'filename='=>'?string'], 'Saxon\SchemaValidator::validateToNode' => ['Saxon\XdmNode', 'filename='=>'?string'], 'Saxon\XdmAtomicValue::addXdmItem' => ['', 'item'=>'Saxon\XdmItem'], 'Saxon\XdmAtomicValue::getAtomicValue' => ['?Saxon\XdmAtomicValue'], 'Saxon\XdmAtomicValue::getBooleanValue' => ['bool'], 'Saxon\XdmAtomicValue::getDoubleValue' => ['float'], 'Saxon\XdmAtomicValue::getHead' => ['Saxon\XdmItem'], 'Saxon\XdmAtomicValue::getLongValue' => ['int'], 'Saxon\XdmAtomicValue::getNodeValue' => ['?Saxon\XdmNode'], 'Saxon\XdmAtomicValue::getStringValue' => ['string'], 'Saxon\XdmAtomicValue::isAtomic' => ['true'], 'Saxon\XdmAtomicValue::isNode' => ['bool'], 'Saxon\XdmAtomicValue::itemAt' => ['Saxon\XdmItem', 'index'=>'int'], 'Saxon\XdmAtomicValue::size' => ['int'], 'Saxon\XdmItem::addXdmItem' => ['', 'item'=>'Saxon\XdmItem'], 'Saxon\XdmItem::getAtomicValue' => ['?Saxon\XdmAtomicValue'], 'Saxon\XdmItem::getHead' => ['Saxon\XdmItem'], 'Saxon\XdmItem::getNodeValue' => ['?Saxon\XdmNode'], 'Saxon\XdmItem::getStringValue' => ['string'], 'Saxon\XdmItem::isAtomic' => ['bool'], 'Saxon\XdmItem::isNode' => ['bool'], 'Saxon\XdmItem::itemAt' => ['Saxon\XdmItem', 'index'=>'int'], 'Saxon\XdmItem::size' => ['int'], 'Saxon\XdmNode::addXdmItem' => ['', 'item'=>'Saxon\XdmItem'], 'Saxon\XdmNode::getAtomicValue' => ['?Saxon\XdmAtomicValue'], 'Saxon\XdmNode::getAttributeCount' => ['int'], 'Saxon\XdmNode::getAttributeNode' => ['?Saxon\XdmNode', 'index'=>'int'], 'Saxon\XdmNode::getAttributeValue' => ['?string', 'index'=>'int'], 'Saxon\XdmNode::getChildCount' => ['int'], 'Saxon\XdmNode::getChildNode' => ['?Saxon\XdmNode', 'index'=>'int'], 'Saxon\XdmNode::getHead' => ['Saxon\XdmItem'], 'Saxon\XdmNode::getNodeKind' => ['int'], 'Saxon\XdmNode::getNodeName' => ['string'], 'Saxon\XdmNode::getNodeValue' => ['?Saxon\XdmNode'], 'Saxon\XdmNode::getParent' => ['?Saxon\XdmNode'], 'Saxon\XdmNode::getStringValue' => ['string'], 'Saxon\XdmNode::isAtomic' => ['false'], 'Saxon\XdmNode::isNode' => ['bool'], 'Saxon\XdmNode::itemAt' => ['Saxon\XdmItem', 'index'=>'int'], 'Saxon\XdmNode::size' => ['int'], 'Saxon\XdmValue::addXdmItem' => ['', 'item'=>'Saxon\XdmItem'], 'Saxon\XdmValue::getHead' => ['Saxon\XdmItem'], 'Saxon\XdmValue::itemAt' => ['Saxon\XdmItem', 'index'=>'int'], 'Saxon\XdmValue::size' => ['int'], 'Saxon\XPathProcessor::clearParameters' => ['void'], 'Saxon\XPathProcessor::clearProperties' => ['void'], 'Saxon\XPathProcessor::declareNamespace' => ['void', 'prefix'=>'', 'namespace'=>''], 'Saxon\XPathProcessor::effectiveBooleanValue' => ['bool', 'xpathStr'=>'string'], 'Saxon\XPathProcessor::evaluate' => ['Saxon\XdmValue', 'xpathStr'=>'string'], 'Saxon\XPathProcessor::evaluateSingle' => ['Saxon\XdmItem', 'xpathStr'=>'string'], 'Saxon\XPathProcessor::exceptionClear' => ['void'], 'Saxon\XPathProcessor::getErrorCode' => ['string', 'i'=>'int'], 'Saxon\XPathProcessor::getErrorMessage' => ['string', 'i'=>'int'], 'Saxon\XPathProcessor::getExceptionCount' => ['int'], 'Saxon\XPathProcessor::setBaseURI' => ['void', 'uri'=>'string'], 'Saxon\XPathProcessor::setContextFile' => ['void', 'fileName'=>'string'], 'Saxon\XPathProcessor::setContextItem' => ['void', 'item'=>'Saxon\XdmItem'], 'Saxon\XPathProcessor::setParameter' => ['void', 'name'=>'string', 'value'=>'Saxon\XdmValue'], 'Saxon\XPathProcessor::setProperty' => ['void', 'name'=>'string', 'value'=>'string'], 'Saxon\XQueryProcessor::clearParameters' => ['void'], 'Saxon\XQueryProcessor::clearProperties' => ['void'], 'Saxon\XQueryProcessor::declareNamespace' => ['void', 'prefix'=>'string', 'namespace'=>'string'], 'Saxon\XQueryProcessor::exceptionClear' => ['void'], 'Saxon\XQueryProcessor::getErrorCode' => ['string', 'i'=>'int'], 'Saxon\XQueryProcessor::getErrorMessage' => ['string', 'i'=>'int'], 'Saxon\XQueryProcessor::getExceptionCount' => ['int'], 'Saxon\XQueryProcessor::runQueryToFile' => ['void', 'outfilename'=>'string'], 'Saxon\XQueryProcessor::runQueryToString' => ['?string'], 'Saxon\XQueryProcessor::runQueryToValue' => ['?Saxon\XdmValue'], 'Saxon\XQueryProcessor::setContextItem' => ['void', 'object'=>'Saxon\XdmAtomicValue|Saxon\XdmItem|Saxon\XdmNode|Saxon\XdmValue'], 'Saxon\XQueryProcessor::setContextItemFromFile' => ['void', 'fileName'=>'string'], 'Saxon\XQueryProcessor::setParameter' => ['void', 'name'=>'string', 'value'=>'Saxon\XdmValue'], 'Saxon\XQueryProcessor::setProperty' => ['void', 'name'=>'string', 'value'=>'string'], 'Saxon\XQueryProcessor::setQueryBaseURI' => ['void', 'uri'=>'string'], 'Saxon\XQueryProcessor::setQueryContent' => ['void', 'string'=>'string'], 'Saxon\XQueryProcessor::setQueryFile' => ['void', 'filename'=>'string'], 'Saxon\XQueryProcessor::setQueryItem' => ['void', 'item'=>'Saxon\XdmItem'], 'Saxon\XsltProcessor::clearParameters' => ['void'], 'Saxon\XsltProcessor::clearProperties' => ['void'], 'Saxon\XsltProcessor::compileFromFile' => ['void', 'fileName'=>'string'], 'Saxon\XsltProcessor::compileFromString' => ['void', 'string'=>'string'], 'Saxon\XsltProcessor::compileFromValue' => ['void', 'node'=>'Saxon\XdmNode'], 'Saxon\XsltProcessor::exceptionClear' => ['void'], 'Saxon\XsltProcessor::getErrorCode' => ['string', 'i'=>'int'], 'Saxon\XsltProcessor::getErrorMessage' => ['string', 'i'=>'int'], 'Saxon\XsltProcessor::getExceptionCount' => ['int'], 'Saxon\XsltProcessor::setOutputFile' => ['void', 'fileName'=>'string'], 'Saxon\XsltProcessor::setParameter' => ['void', 'name'=>'string', 'value'=>'Saxon\XdmValue'], 'Saxon\XsltProcessor::setProperty' => ['void', 'name'=>'string', 'value'=>'string'], 'Saxon\XsltProcessor::setSourceFromFile' => ['void', 'filename'=>'string'], 'Saxon\XsltProcessor::setSourceFromXdmValue' => ['void', 'value'=>'Saxon\XdmValue'], 'Saxon\XsltProcessor::transformFileToFile' => ['void', 'sourceFileName'=>'string', 'stylesheetFileName'=>'string', 'outputfileName'=>'string'], 'Saxon\XsltProcessor::transformFileToString' => ['?string', 'sourceFileName'=>'string', 'stylesheetFileName'=>'string'], 'Saxon\XsltProcessor::transformFileToValue' => ['Saxon\XdmValue', 'fileName'=>'string'], 'Saxon\XsltProcessor::transformToFile' => ['void'], 'Saxon\XsltProcessor::transformToString' => ['string'], 'Saxon\XsltProcessor::transformToValue' => ['?Saxon\XdmValue'], 'SCA::createDataObject' => ['SDO_DataObject', 'type_namespace_uri'=>'string', 'type_name'=>'string'], 'SCA::getService' => ['', 'target'=>'string', 'binding='=>'string', 'config='=>'array'], 'SCA_LocalProxy::createDataObject' => ['SDO_DataObject', 'type_namespace_uri'=>'string', 'type_name'=>'string'], 'SCA_SoapProxy::createDataObject' => ['SDO_DataObject', 'type_namespace_uri'=>'string', 'type_name'=>'string'], 'scalebarObj::convertToString' => ['string'], 'scalebarObj::free' => ['void'], 'scalebarObj::set' => ['int', 'property_name'=>'string', 'new_value'=>''], 'scalebarObj::setImageColor' => ['int', 'red'=>'int', 'green'=>'int', 'blue'=>'int'], 'scalebarObj::updateFromString' => ['int', 'snippet'=>'string'], 'scandir' => ['list|false', 'directory'=>'string', 'sorting_order='=>'int', 'context='=>'resource'], 'SDO_DAS_ChangeSummary::beginLogging' => [''], 'SDO_DAS_ChangeSummary::endLogging' => [''], 'SDO_DAS_ChangeSummary::getChangedDataObjects' => ['SDO_List'], 'SDO_DAS_ChangeSummary::getChangeType' => ['int', 'dataobject'=>'sdo_dataobject'], 'SDO_DAS_ChangeSummary::getOldContainer' => ['SDO_DataObject', 'data_object'=>'sdo_dataobject'], 'SDO_DAS_ChangeSummary::getOldValues' => ['SDO_List', 'data_object'=>'sdo_dataobject'], 'SDO_DAS_ChangeSummary::isLogging' => ['bool'], 'SDO_DAS_DataFactory::addPropertyToType' => ['', 'parent_type_namespace_uri'=>'string', 'parent_type_name'=>'string', 'property_name'=>'string', 'type_namespace_uri'=>'string', 'type_name'=>'string', 'options='=>'array'], 'SDO_DAS_DataFactory::addType' => ['', 'type_namespace_uri'=>'string', 'type_name'=>'string', 'options='=>'array'], 'SDO_DAS_DataFactory::getDataFactory' => ['SDO_DAS_DataFactory'], 'SDO_DAS_DataObject::getChangeSummary' => ['SDO_DAS_ChangeSummary'], 'SDO_DAS_Relational::__construct' => ['void', 'database_metadata'=>'array', 'application_root_type='=>'string', 'sdo_containment_references_metadata='=>'array'], 'SDO_DAS_Relational::applyChanges' => ['', 'database_handle'=>'pdo', 'root_data_object'=>'sdodataobject'], 'SDO_DAS_Relational::createRootDataObject' => ['SDODataObject'], 'SDO_DAS_Relational::executePreparedQuery' => ['SDODataObject', 'database_handle'=>'pdo', 'prepared_statement'=>'pdostatement', 'value_list'=>'array', 'column_specifier='=>'array'], 'SDO_DAS_Relational::executeQuery' => ['SDODataObject', 'database_handle'=>'pdo', 'sql_statement'=>'string', 'column_specifier='=>'array'], 'SDO_DAS_Setting::getListIndex' => ['int'], 'SDO_DAS_Setting::getPropertyIndex' => ['int'], 'SDO_DAS_Setting::getPropertyName' => ['string'], 'SDO_DAS_Setting::getValue' => [''], 'SDO_DAS_Setting::isSet' => ['bool'], 'SDO_DAS_XML::addTypes' => ['', 'xsd_file'=>'string'], 'SDO_DAS_XML::create' => ['SDO_DAS_XML', 'xsd_file='=>'mixed', 'key='=>'string'], 'SDO_DAS_XML::createDataObject' => ['SDO_DataObject', 'namespace_uri'=>'string', 'type_name'=>'string'], 'SDO_DAS_XML::createDocument' => ['SDO_DAS_XML_Document', 'document_element_name'=>'string', 'document_element_namespace_uri'=>'string', 'dataobject='=>'sdo_dataobject'], 'SDO_DAS_XML::loadFile' => ['SDO_XMLDocument', 'xml_file'=>'string'], 'SDO_DAS_XML::loadString' => ['SDO_DAS_XML_Document', 'xml_string'=>'string'], 'SDO_DAS_XML::saveFile' => ['', 'xdoc'=>'sdo_xmldocument', 'xml_file'=>'string', 'indent='=>'int'], 'SDO_DAS_XML::saveString' => ['string', 'xdoc'=>'sdo_xmldocument', 'indent='=>'int'], 'SDO_DAS_XML_Document::getRootDataObject' => ['SDO_DataObject'], 'SDO_DAS_XML_Document::getRootElementName' => ['string'], 'SDO_DAS_XML_Document::getRootElementURI' => ['string'], 'SDO_DAS_XML_Document::setEncoding' => ['', 'encoding'=>'string'], 'SDO_DAS_XML_Document::setXMLDeclaration' => ['', 'xmldeclatation'=>'bool'], 'SDO_DAS_XML_Document::setXMLVersion' => ['', 'xmlversion'=>'string'], 'SDO_DataFactory::create' => ['void', 'type_namespace_uri'=>'string', 'type_name'=>'string'], 'SDO_DataObject::clear' => ['void'], 'SDO_DataObject::createDataObject' => ['SDO_DataObject', 'identifier'=>''], 'SDO_DataObject::getContainer' => ['SDO_DataObject'], 'SDO_DataObject::getSequence' => ['SDO_Sequence'], 'SDO_DataObject::getTypeName' => ['string'], 'SDO_DataObject::getTypeNamespaceURI' => ['string'], 'SDO_Exception::getCause' => [''], 'SDO_List::insert' => ['void', 'value'=>'mixed', 'index='=>'int'], 'SDO_Model_Property::getContainingType' => ['SDO_Model_Type'], 'SDO_Model_Property::getDefault' => [''], 'SDO_Model_Property::getName' => ['string'], 'SDO_Model_Property::getType' => ['SDO_Model_Type'], 'SDO_Model_Property::isContainment' => ['bool'], 'SDO_Model_Property::isMany' => ['bool'], 'SDO_Model_ReflectionDataObject::__construct' => ['void', 'data_object'=>'sdo_dataobject'], 'SDO_Model_ReflectionDataObject::export' => ['mixed', 'rdo'=>'sdo_model_reflectiondataobject', 'return='=>'bool'], 'SDO_Model_ReflectionDataObject::getContainmentProperty' => ['SDO_Model_Property'], 'SDO_Model_ReflectionDataObject::getInstanceProperties' => ['array'], 'SDO_Model_ReflectionDataObject::getType' => ['SDO_Model_Type'], 'SDO_Model_Type::getBaseType' => ['SDO_Model_Type'], 'SDO_Model_Type::getName' => ['string'], 'SDO_Model_Type::getNamespaceURI' => ['string'], 'SDO_Model_Type::getProperties' => ['array'], 'SDO_Model_Type::getProperty' => ['SDO_Model_Property', 'identifier'=>''], 'SDO_Model_Type::isAbstractType' => ['bool'], 'SDO_Model_Type::isDataType' => ['bool'], 'SDO_Model_Type::isInstance' => ['bool', 'data_object'=>'sdo_dataobject'], 'SDO_Model_Type::isOpenType' => ['bool'], 'SDO_Model_Type::isSequencedType' => ['bool'], 'SDO_Sequence::getProperty' => ['SDO_Model_Property', 'sequence_index'=>'int'], 'SDO_Sequence::insert' => ['void', 'value'=>'mixed', 'sequenceindex='=>'int', 'propertyidentifier='=>'mixed'], 'SDO_Sequence::move' => ['void', 'toindex'=>'int', 'fromindex'=>'int'], 'SeasLog::__destruct' => ['void'], 'SeasLog::alert' => ['bool', 'message'=>'string', 'content='=>'array', 'logger='=>'string'], 'SeasLog::analyzerCount' => ['mixed', 'level'=>'string', 'log_path='=>'string', 'key_word='=>'string'], 'SeasLog::analyzerDetail' => ['mixed', 'level'=>'string', 'log_path='=>'string', 'key_word='=>'string', 'start='=>'int', 'limit='=>'int', 'order='=>'int'], 'SeasLog::closeLoggerStream' => ['bool', 'model'=>'int', 'logger'=>'string'], 'SeasLog::critical' => ['bool', 'message'=>'string', 'content='=>'array', 'logger='=>'string'], 'SeasLog::debug' => ['bool', 'message'=>'string', 'content='=>'array', 'logger='=>'string'], 'SeasLog::emergency' => ['bool', 'message'=>'string', 'content='=>'array', 'logger='=>'string'], 'SeasLog::error' => ['bool', 'message'=>'string', 'content='=>'array', 'logger='=>'string'], 'SeasLog::flushBuffer' => ['bool'], 'SeasLog::getBasePath' => ['string'], 'SeasLog::getBuffer' => ['array'], 'SeasLog::getBufferEnabled' => ['bool'], 'SeasLog::getDatetimeFormat' => ['string'], 'SeasLog::getLastLogger' => ['string'], 'SeasLog::getRequestID' => ['string'], 'SeasLog::getRequestVariable' => ['bool', 'key'=>'int'], 'SeasLog::info' => ['bool', 'message'=>'string', 'content='=>'array', 'logger='=>'string'], 'SeasLog::log' => ['bool', 'level'=>'string', 'message='=>'string', 'content='=>'array', 'logger='=>'string'], 'SeasLog::notice' => ['bool', 'message'=>'string', 'content='=>'array', 'logger='=>'string'], 'SeasLog::setBasePath' => ['bool', 'base_path'=>'string'], 'SeasLog::setDatetimeFormat' => ['bool', 'format'=>'string'], 'SeasLog::setLogger' => ['bool', 'logger'=>'string'], 'SeasLog::setRequestID' => ['bool', 'request_id'=>'string'], 'SeasLog::setRequestVariable' => ['bool', 'key'=>'int', 'value'=>'string'], 'SeasLog::warning' => ['bool', 'message'=>'string', 'content='=>'array', 'logger='=>'string'], 'seaslog_get_author' => ['string'], 'seaslog_get_version' => ['string'], 'SeekableIterator::__construct' => ['void'], 'SeekableIterator::current' => ['mixed'], 'SeekableIterator::key' => ['int|string'], 'SeekableIterator::next' => ['void'], 'SeekableIterator::rewind' => ['void'], 'SeekableIterator::seek' => ['void', 'position'=>'int'], 'SeekableIterator::valid' => ['bool'], 'sem_acquire' => ['bool', 'semaphore'=>'SysvSemaphore', 'non_blocking='=>'bool'], 'sem_get' => ['SysvSemaphore|false', 'key'=>'int', 'max_acquire='=>'int', 'permissions='=>'int', 'auto_release='=>'bool'], 'sem_release' => ['bool', 'semaphore'=>'SysvSemaphore'], 'sem_remove' => ['bool', 'semaphore'=>'SysvSemaphore'], 'Serializable::__construct' => ['void'], 'Serializable::serialize' => ['?string'], 'Serializable::unserialize' => ['void', 'serialized'=>'string'], 'serialize' => ['string', 'value'=>'mixed'], 'ServerRequest::withInput' => ['ServerRequest', 'input'=>'mixed'], 'ServerRequest::withoutParams' => ['ServerRequest', 'params'=>'int|string'], 'ServerRequest::withParam' => ['ServerRequest', 'key'=>'int|string', 'value'=>'mixed'], 'ServerRequest::withParams' => ['ServerRequest', 'params'=>'mixed'], 'ServerRequest::withUrl' => ['ServerRequest', 'url'=>'array'], 'ServerResponse::addHeader' => ['void', 'label'=>'string', 'value'=>'string'], 'ServerResponse::date' => ['string', 'date'=>'string|DateTimeInterface'], 'ServerResponse::getHeader' => ['string', 'label'=>'string'], 'ServerResponse::getHeaders' => ['string[]'], 'ServerResponse::getStatus' => ['int'], 'ServerResponse::getVersion' => ['string'], 'ServerResponse::setHeader' => ['void', 'label'=>'string', 'value'=>'string'], 'ServerResponse::setStatus' => ['void', 'status'=>'int'], 'ServerResponse::setVersion' => ['void', 'version'=>'string'], 'session_abort' => ['bool'], 'session_cache_expire' => ['int|false', 'value='=>'?int'], 'session_cache_limiter' => ['string|false', 'value='=>'?string'], 'session_commit' => ['bool'], 'session_create_id' => ['string|false', 'prefix='=>'string'], 'session_decode' => ['bool', 'data'=>'string'], 'session_destroy' => ['bool'], 'session_encode' => ['string|false'], 'session_gc' => ['int|false'], 'session_get_cookie_params' => ['array{lifetime:?int,path:?string,domain:?string,secure:?bool,httponly:?bool,samesite:?string}'], 'session_id' => ['string|false', 'id='=>'?string'], 'session_is_registered' => ['bool', 'name'=>'string'], 'session_module_name' => ['string|false', 'module='=>'?string'], 'session_name' => ['string|false', 'name='=>'?string'], 'session_pgsql_add_error' => ['bool', 'error_level'=>'int', 'error_message='=>'string'], 'session_pgsql_get_error' => ['array', 'with_error_message='=>'bool'], 'session_pgsql_get_field' => ['string'], 'session_pgsql_reset' => ['bool'], 'session_pgsql_set_field' => ['bool', 'value'=>'string'], 'session_pgsql_status' => ['array'], 'session_regenerate_id' => ['bool', 'delete_old_session='=>'bool'], 'session_register' => ['bool', 'name'=>'mixed', '...args='=>'mixed'], 'session_register_shutdown' => ['void'], 'session_reset' => ['bool'], 'session_save_path' => ['string|false', 'path='=>'?string'], 'session_set_cookie_params' => ['bool', 'lifetime'=>'int', 'path='=>'?string', 'domain='=>'?string', 'secure='=>'?bool', 'httponly='=>'?bool'], 'session_set_cookie_params\'1' => ['bool', 'options'=>'array{lifetime?:?int,path?:?string,domain?:?string,secure?:?bool,httponly?:?bool,samesite?:?string}'], 'session_set_save_handler' => ['bool', 'open'=>'callable(string,string):bool', 'close'=>'callable():bool', 'read'=>'callable(string):string', 'write'=>'callable(string,string):bool', 'destroy'=>'callable(string):bool', 'gc'=>'callable(string):bool', 'create_sid='=>'callable():string', 'validate_sid='=>'callable(string):bool', 'update_timestamp='=>'callable(string):bool'], 'session_set_save_handler\'1' => ['bool', 'open'=>'SessionHandlerInterface', 'close='=>'bool'], 'session_start' => ['bool', 'options='=>'array'], 'session_status' => ['int'], 'session_unregister' => ['bool', 'name'=>'string'], 'session_unset' => ['bool'], 'session_write_close' => ['bool'], 'SessionHandler::close' => ['bool'], 'SessionHandler::create_sid' => ['string'], 'SessionHandler::destroy' => ['bool', 'id'=>'string'], 'SessionHandler::gc' => ['int|false', 'max_lifetime'=>'int'], 'SessionHandler::open' => ['bool', 'path'=>'string', 'name'=>'string'], 'SessionHandler::read' => ['string|false', 'id'=>'string'], 'SessionHandler::write' => ['bool', 'id'=>'string', 'data'=>'string'], 'SessionHandlerInterface::close' => ['bool'], 'SessionHandlerInterface::destroy' => ['bool', 'id'=>'string'], 'SessionHandlerInterface::gc' => ['int|false', 'max_lifetime'=>'int'], 'SessionHandlerInterface::open' => ['bool', 'path'=>'string', 'name'=>'string'], 'SessionHandlerInterface::read' => ['string|false', 'id'=>'string'], 'SessionHandlerInterface::write' => ['bool', 'id'=>'string', 'data'=>'string'], 'SessionIdInterface::create_sid' => ['string'], 'SessionUpdateTimestampHandler::updateTimestamp' => ['bool', 'id'=>'string', 'data'=>'string'], 'SessionUpdateTimestampHandler::validateId' => ['char', 'id'=>'string'], 'SessionUpdateTimestampHandlerInterface::updateTimestamp' => ['bool', 'id'=>'string', 'data'=>'string'], 'SessionUpdateTimestampHandlerInterface::validateId' => ['bool', 'id'=>'string'], 'set_error_handler' => ['null|callable(int,string,string=,int=,array=):bool', 'callback'=>'null|callable(int,string,string=,int=,array=):bool', 'error_levels='=>'int'], 'set_exception_handler' => ['null|callable(Throwable):void', 'callback'=>'null|callable(Throwable):void'], 'set_file_buffer' => ['int', 'stream'=>'resource', 'size'=>'int'], 'set_include_path' => ['string|false', 'include_path'=>'string'], 'set_magic_quotes_runtime' => ['bool', 'new_setting'=>'bool'], 'set_time_limit' => ['bool', 'seconds'=>'int'], 'setcookie' => ['bool', 'name'=>'string', 'value='=>'string', 'expires='=>'int', 'path='=>'string', 'domain='=>'string', 'secure='=>'bool', 'httponly='=>'bool', 'samesite='=>'string', 'url_encode='=>'int'], 'setcookie\'1' => ['bool', 'name'=>'string', 'value='=>'string', 'options='=>'array'], 'setLeftFill' => ['void', 'red'=>'int', 'green'=>'int', 'blue'=>'int', 'a='=>'int'], 'setLine' => ['void', 'width'=>'int', 'red'=>'int', 'green'=>'int', 'blue'=>'int', 'a='=>'int'], 'setlocale' => ['string|false', 'category'=>'int', 'locales'=>'string|0|null', '...rest='=>'string'], 'setlocale\'1' => ['string|false', 'category'=>'int', 'locales'=>'?array'], 'setproctitle' => ['void', 'title'=>'string'], 'setrawcookie' => ['bool', 'name'=>'string', 'value='=>'string', 'expires='=>'int', 'path='=>'string', 'domain='=>'string', 'secure='=>'bool', 'httponly='=>'bool'], 'setrawcookie\'1' => ['bool', 'name'=>'string', 'value='=>'string', 'options='=>'array'], 'setRightFill' => ['void', 'red'=>'int', 'green'=>'int', 'blue'=>'int', 'a='=>'int'], 'setthreadtitle' => ['bool', 'title'=>'string'], 'settype' => ['bool', '&rw_var'=>'mixed', 'type'=>'string'], 'sha1' => ['string', 'string'=>'string', 'binary='=>'bool'], 'sha1_file' => ['string|false', 'filename'=>'string', 'binary='=>'bool'], 'sha256' => ['string', 'string'=>'string', 'raw_output='=>'bool'], 'sha256_file' => ['string', 'filename'=>'string', 'raw_output='=>'bool'], 'shapefileObj::__construct' => ['void', 'filename'=>'string', 'type'=>'int'], 'shapefileObj::addPoint' => ['int', 'point'=>'pointObj'], 'shapefileObj::addShape' => ['int', 'shape'=>'shapeObj'], 'shapefileObj::free' => ['void'], 'shapefileObj::getExtent' => ['rectObj', 'i'=>'int'], 'shapefileObj::getPoint' => ['shapeObj', 'i'=>'int'], 'shapefileObj::getShape' => ['shapeObj', 'i'=>'int'], 'shapefileObj::getTransformed' => ['shapeObj', 'map'=>'mapObj', 'i'=>'int'], 'shapefileObj::ms_newShapefileObj' => ['shapefileObj', 'filename'=>'string', 'type'=>'int'], 'shapeObj::__construct' => ['void', 'type'=>'int'], 'shapeObj::add' => ['int', 'line'=>'lineObj'], 'shapeObj::boundary' => ['shapeObj'], 'shapeObj::contains' => ['bool', 'point'=>'pointObj'], 'shapeObj::containsShape' => ['int', 'shape2'=>'shapeObj'], 'shapeObj::convexhull' => ['shapeObj'], 'shapeObj::crosses' => ['int', 'shape'=>'shapeObj'], 'shapeObj::difference' => ['shapeObj', 'shape'=>'shapeObj'], 'shapeObj::disjoint' => ['int', 'shape'=>'shapeObj'], 'shapeObj::draw' => ['int', 'map'=>'mapObj', 'layer'=>'layerObj', 'img'=>'imageObj'], 'shapeObj::equals' => ['int', 'shape'=>'shapeObj'], 'shapeObj::free' => ['void'], 'shapeObj::getArea' => ['float'], 'shapeObj::getCentroid' => ['pointObj'], 'shapeObj::getLabelPoint' => ['pointObj'], 'shapeObj::getLength' => ['float'], 'shapeObj::getPointUsingMeasure' => ['pointObj', 'm'=>'float'], 'shapeObj::getValue' => ['string', 'layer'=>'layerObj', 'filedname'=>'string'], 'shapeObj::intersection' => ['shapeObj', 'shape'=>'shapeObj'], 'shapeObj::intersects' => ['bool', 'shape'=>'shapeObj'], 'shapeObj::line' => ['lineObj', 'i'=>'int'], 'shapeObj::ms_shapeObjFromWkt' => ['shapeObj', 'wkt'=>'string'], 'shapeObj::overlaps' => ['int', 'shape'=>'shapeObj'], 'shapeObj::project' => ['int', 'in'=>'projectionObj', 'out'=>'projectionObj'], 'shapeObj::set' => ['int', 'property_name'=>'string', 'new_value'=>''], 'shapeObj::setBounds' => ['int'], 'shapeObj::simplify' => ['shapeObj|null', 'tolerance'=>'float'], 'shapeObj::symdifference' => ['shapeObj', 'shape'=>'shapeObj'], 'shapeObj::topologyPreservingSimplify' => ['shapeObj|null', 'tolerance'=>'float'], 'shapeObj::touches' => ['int', 'shape'=>'shapeObj'], 'shapeObj::toWkt' => ['string'], 'shapeObj::union' => ['shapeObj', 'shape'=>'shapeObj'], 'shapeObj::within' => ['int', 'shape2'=>'shapeObj'], 'shell_exec' => ['string|false|null', 'command'=>'string'], 'shm_attach' => ['SysvSharedMemory|false', 'key'=>'int', 'size='=>'?int', 'permissions='=>'int'], 'shm_detach' => ['bool', 'shm'=>'SysvSharedMemory'], 'shm_get_var' => ['mixed', 'shm'=>'SysvSharedMemory', 'key'=>'int'], 'shm_has_var' => ['bool', 'shm'=>'SysvSharedMemory', 'key'=>'int'], 'shm_put_var' => ['bool', 'shm'=>'SysvSharedMemory', 'key'=>'int', 'value'=>'mixed'], 'shm_remove' => ['bool', 'shm'=>'SysvSharedMemory'], 'shm_remove_var' => ['bool', 'shm'=>'SysvSharedMemory', 'key'=>'int'], 'shmop_close' => ['void', 'shmop'=>'Shmop'], 'shmop_delete' => ['bool', 'shmop'=>'Shmop'], 'shmop_open' => ['Shmop|false', 'key'=>'int', 'mode'=>'string', 'permissions'=>'int', 'size'=>'int'], 'shmop_read' => ['string', 'shmop'=>'Shmop', 'offset'=>'int', 'size'=>'int'], 'shmop_size' => ['int', 'shmop'=>'Shmop'], 'shmop_write' => ['int', 'shmop'=>'Shmop', 'data'=>'string', 'offset'=>'int'], 'show_source' => ['string|bool', 'filename'=>'string', 'return='=>'bool'], 'shuffle' => ['true', '&rw_array'=>'array'], 'signeurlpaiement' => ['string', 'clent'=>'string', 'data'=>'string'], 'similar_text' => ['int', 'string1'=>'string', 'string2'=>'string', '&w_percent='=>'float'], 'simplexml_import_dom' => ['?SimpleXMLElement', 'node'=>'DOMNode', 'class_name='=>'?string'], 'simplexml_load_file' => ['SimpleXMLElement|false', 'filename'=>'string', 'class_name='=>'?string', 'options='=>'int', 'namespace_or_prefix='=>'string', 'is_prefix='=>'bool'], 'simplexml_load_string' => ['SimpleXMLElement|false', 'data'=>'string', 'class_name='=>'?string', 'options='=>'int', 'namespace_or_prefix='=>'string', 'is_prefix='=>'bool'], 'SimpleXMLElement::__construct' => ['void', 'data'=>'string', 'options='=>'int', 'dataIsURL='=>'bool', 'namespaceOrPrefix='=>'string', 'isPrefix='=>'bool'], 'SimpleXMLElement::__get' => ['SimpleXMLElement', 'name'=>'string'], 'SimpleXMLElement::__toString' => ['string'], 'SimpleXMLElement::addAttribute' => ['void', 'qualifiedName'=>'string', 'value'=>'string', 'namespace='=>'?string'], 'SimpleXMLElement::addChild' => ['?SimpleXMLElement', 'qualifiedName'=>'string', 'value='=>'?string', 'namespace='=>'?string'], 'SimpleXMLElement::asXML' => ['string|bool', 'filename='=>'?string'], 'SimpleXMLElement::asXML\'1' => ['string|false'], 'SimpleXMLElement::attributes' => ['?SimpleXMLElement', 'namespaceOrPrefix='=>'?string', 'isPrefix='=>'bool'], 'SimpleXMLElement::children' => ['?SimpleXMLElement', 'namespaceOrPrefix='=>'?string', 'isPrefix='=>'bool'], 'SimpleXMLElement::count' => ['int'], 'SimpleXMLElement::getDocNamespaces' => ['array', 'recursive='=>'bool', 'fromRoot='=>'bool'], 'SimpleXMLElement::getName' => ['string'], 'SimpleXMLElement::getNamespaces' => ['array', 'recursive='=>'bool'], 'SimpleXMLElement::offsetExists' => ['bool', 'offset'=>'int|string'], 'SimpleXMLElement::offsetGet' => ['SimpleXMLElement', 'offset'=>'int|string'], 'SimpleXMLElement::offsetSet' => ['void', 'offset'=>'int|string|null', 'value'=>'mixed'], 'SimpleXMLElement::offsetUnset' => ['void', 'offset'=>'int|string'], 'SimpleXMLElement::registerXPathNamespace' => ['bool', 'prefix'=>'string', 'namespace'=>'string'], 'SimpleXMLElement::saveXML' => ['string|bool', 'filename='=>'?string'], 'SimpleXMLElement::xpath' => ['SimpleXMLElement[]|false|null', 'expression'=>'string'], 'sin' => ['float', 'num'=>'float'], 'sinh' => ['float', 'num'=>'float'], 'sizeof' => ['int<0, max>', 'value'=>'Countable|array', 'mode='=>'int'], 'sleep' => ['int', 'seconds'=>'0|positive-int'], 'snmp2_get' => ['string|false', 'hostname'=>'string', 'community'=>'string', 'object_id'=>'array|string', 'timeout='=>'int', 'retries='=>'int'], 'snmp2_getnext' => ['string|false', 'hostname'=>'string', 'community'=>'string', 'object_id'=>'array|string', 'timeout='=>'int', 'retries='=>'int'], 'snmp2_real_walk' => ['array|false', 'hostname'=>'string', 'community'=>'string', 'object_id'=>'array|string', 'timeout='=>'int', 'retries='=>'int'], 'snmp2_set' => ['bool', 'hostname'=>'string', 'community'=>'string', 'object_id'=>'array|string', 'type'=>'array|string', 'value'=>'array|string', 'timeout='=>'int', 'retries='=>'int'], 'snmp2_walk' => ['array|false', 'hostname'=>'string', 'community'=>'string', 'object_id'=>'array|string', 'timeout='=>'int', 'retries='=>'int'], 'snmp3_get' => ['string|false', 'hostname'=>'string', 'security_name'=>'string', 'security_level'=>'string', 'auth_protocol'=>'string', 'auth_passphrase'=>'string', 'privacy_protocol'=>'string', 'privacy_passphrase'=>'string', 'object_id'=>'array|string', 'timeout='=>'int', 'retries='=>'int'], 'snmp3_getnext' => ['string|false', 'hostname'=>'string', 'security_name'=>'string', 'security_level'=>'string', 'auth_protocol'=>'string', 'auth_passphrase'=>'string', 'privacy_protocol'=>'string', 'privacy_passphrase'=>'string', 'object_id'=>'array|string', 'timeout='=>'int', 'retries='=>'int'], 'snmp3_real_walk' => ['array|false', 'hostname'=>'string', 'security_name'=>'string', 'security_level'=>'string', 'auth_protocol'=>'string', 'auth_passphrase'=>'string', 'privacy_protocol'=>'string', 'privacy_passphrase'=>'string', 'object_id'=>'array|string', 'timeout='=>'int', 'retries='=>'int'], 'snmp3_set' => ['bool', 'hostname'=>'string', 'security_name'=>'string', 'security_level'=>'string', 'auth_protocol'=>'string', 'auth_passphrase'=>'string', 'privacy_protocol'=>'string', 'privacy_passphrase'=>'string', 'object_id'=>'array|string', 'type'=>'array|string', 'value'=>'array|string', 'timeout='=>'int', 'retries='=>'int'], 'snmp3_walk' => ['array|false', 'hostname'=>'string', 'security_name'=>'string', 'security_level'=>'string', 'auth_protocol'=>'string', 'auth_passphrase'=>'string', 'privacy_protocol'=>'string', 'privacy_passphrase'=>'string', 'object_id'=>'array|string', 'timeout='=>'int', 'retries='=>'int'], 'SNMP::__construct' => ['void', 'version'=>'int', 'hostname'=>'string', 'community'=>'string', 'timeout='=>'int', 'retries='=>'int'], 'SNMP::close' => ['bool'], 'SNMP::get' => ['array|string|false', 'objectId'=>'string|array', 'preserveKeys='=>'bool'], 'SNMP::getErrno' => ['int'], 'SNMP::getError' => ['string'], 'SNMP::getnext' => ['string|array|false', 'objectId'=>'string|array'], 'SNMP::set' => ['bool', 'objectId'=>'string|array', 'type'=>'string|array', 'value'=>'string|array'], 'SNMP::setSecurity' => ['bool', 'securityLevel'=>'string', 'authProtocol='=>'string', 'authPassphrase='=>'string', 'privacyProtocol='=>'string', 'privacyPassphrase='=>'string', 'contextName='=>'string', 'contextEngineId='=>'string'], 'SNMP::walk' => ['array|false', 'objectId'=>'array|string', 'suffixAsKey='=>'bool', 'maxRepetitions='=>'int', 'nonRepeaters='=>'int'], 'snmp_get_quick_print' => ['bool'], 'snmp_get_valueretrieval' => ['int'], 'snmp_read_mib' => ['bool', 'filename'=>'string'], 'snmp_set_enum_print' => ['true', 'enable'=>'bool'], 'snmp_set_oid_numeric_print' => ['true', 'format'=>'int'], 'snmp_set_oid_output_format' => ['true', 'format'=>'int'], 'snmp_set_quick_print' => ['bool', 'enable'=>'bool'], 'snmp_set_valueretrieval' => ['true', 'method'=>'int'], 'snmpget' => ['string|false', 'hostname'=>'string', 'community'=>'string', 'object_id'=>'array|string', 'timeout='=>'int', 'retries='=>'int'], 'snmpgetnext' => ['string|false', 'hostname'=>'string', 'community'=>'string', 'object_id'=>'array|string', 'timeout='=>'int', 'retries='=>'int'], 'snmprealwalk' => ['array|false', 'hostname'=>'string', 'community'=>'string', 'object_id'=>'array|string', 'timeout='=>'int', 'retries='=>'int'], 'snmpset' => ['bool', 'hostname'=>'string', 'community'=>'string', 'object_id'=>'array|string', 'type'=>'string|string[]', 'value'=>'string|string[]', 'timeout='=>'int', 'retries='=>'int'], 'snmpwalk' => ['array|false', 'hostname'=>'string', 'community'=>'string', 'object_id'=>'array|string', 'timeout='=>'int', 'retries='=>'int'], 'snmpwalkoid' => ['array|false', 'hostname'=>'string', 'community'=>'string', 'object_id'=>'array|string', 'timeout='=>'int', 'retries='=>'int'], 'SoapClient::__call' => ['', 'function_name'=>'string', 'arguments'=>'array'], 'SoapClient::__construct' => ['void', 'wsdl'=>'mixed', 'options='=>'array|null'], 'SoapClient::__doRequest' => ['?string', 'request'=>'string', 'location'=>'string', 'action'=>'string', 'version'=>'int', 'one_way='=>'bool'], 'SoapClient::__getCookies' => ['array'], 'SoapClient::__getFunctions' => ['?array'], 'SoapClient::__getLastRequest' => ['?string'], 'SoapClient::__getLastRequestHeaders' => ['?string'], 'SoapClient::__getLastResponse' => ['?string'], 'SoapClient::__getLastResponseHeaders' => ['?string'], 'SoapClient::__getTypes' => ['?array'], 'SoapClient::__setCookie' => ['', 'name'=>'string', 'value='=>'string'], 'SoapClient::__setLocation' => ['string', 'new_location='=>'string'], 'SoapClient::__setSoapHeaders' => ['bool', 'soapheaders='=>''], 'SoapClient::__soapCall' => ['', 'function_name'=>'string', 'arguments'=>'array', 'options='=>'array', 'input_headers='=>'SoapHeader|array', '&w_output_headers='=>'array'], 'SoapClient::SoapClient' => ['object', 'wsdl'=>'mixed', 'options='=>'array|null'], 'SoapFault::__clone' => ['void'], 'SoapFault::__construct' => ['void', 'code'=>'array|string|null', 'string'=>'string', 'actor='=>'?string', 'details='=>'?mixed', 'name='=>'?string', 'headerFault='=>'?mixed'], 'SoapFault::__toString' => ['string'], 'SoapFault::__wakeup' => ['void'], 'SoapFault::getCode' => ['int'], 'SoapFault::getFile' => ['string'], 'SoapFault::getLine' => ['int'], 'SoapFault::getMessage' => ['string'], 'SoapFault::getPrevious' => ['?Exception|?Throwable'], 'SoapFault::getTrace' => ['list\',args?:array}>'], 'SoapFault::getTraceAsString' => ['string'], 'SoapFault::SoapFault' => ['object', 'faultcode'=>'string', 'faultstring'=>'string', 'faultactor='=>'?string', 'detail='=>'?mixed', 'faultname='=>'?string', 'headerfault='=>'?mixed'], 'SoapHeader::__construct' => ['void', 'namespace'=>'string', 'name'=>'string', 'data='=>'mixed', 'mustunderstand='=>'bool', 'actor='=>'string'], 'SoapHeader::SoapHeader' => ['object', 'namespace'=>'string', 'name'=>'string', 'data='=>'mixed', 'mustunderstand='=>'bool', 'actor='=>'string'], 'SoapParam::__construct' => ['void', 'data'=>'mixed', 'name'=>'string'], 'SoapParam::SoapParam' => ['object', 'data'=>'mixed', 'name'=>'string'], 'SoapServer::__construct' => ['void', 'wsdl'=>'?string', 'options='=>'array'], 'SoapServer::addFunction' => ['void', 'functions'=>'mixed'], 'SoapServer::addSoapHeader' => ['void', 'object'=>'SoapHeader'], 'SoapServer::fault' => ['void', 'code'=>'string', 'string'=>'string', 'actor='=>'string', 'details='=>'string', 'name='=>'string'], 'SoapServer::getFunctions' => ['array'], 'SoapServer::handle' => ['void', 'soap_request='=>'string'], 'SoapServer::setClass' => ['void', 'class_name'=>'string', '...args='=>'mixed'], 'SoapServer::setObject' => ['void', 'object'=>'object'], 'SoapServer::setPersistence' => ['void', 'mode'=>'int'], 'SoapServer::SoapServer' => ['object', 'wsdl'=>'?string', 'options='=>'array'], 'SoapVar::__construct' => ['void', 'data'=>'mixed', 'encoding'=>'int', 'type_name='=>'string|null', 'type_namespace='=>'string|null', 'node_name='=>'string|null', 'node_namespace='=>'string|null'], 'SoapVar::SoapVar' => ['object', 'data'=>'mixed', 'encoding'=>'int', 'type_name='=>'string|null', 'type_namespace='=>'string|null', 'node_name='=>'string|null', 'node_namespace='=>'string|null'], 'socket_accept' => ['Socket|false', 'socket'=>'Socket'], 'socket_addrinfo_bind' => ['Socket|false', 'address'=>'AddressInfo'], 'socket_addrinfo_connect' => ['Socket|false', 'address'=>'AddressInfo'], 'socket_addrinfo_explain' => ['array', 'address'=>'AddressInfo'], 'socket_addrinfo_lookup' => ['false|AddressInfo[]', 'host'=>'string', 'service='=>'?string', 'hints='=>'array'], 'socket_bind' => ['bool', 'socket'=>'Socket', 'address'=>'string', 'port='=>'int'], 'socket_clear_error' => ['void', 'socket='=>'?Socket'], 'socket_close' => ['void', 'socket'=>'Socket'], 'socket_cmsg_space' => ['?int', 'level'=>'int', 'type'=>'int', 'num='=>'int'], 'socket_connect' => ['bool', 'socket'=>'Socket', 'address'=>'string', 'port='=>'?int'], 'socket_create' => ['Socket|false', 'domain'=>'int', 'type'=>'int', 'protocol'=>'int'], 'socket_create_listen' => ['Socket|false', 'port'=>'int', 'backlog='=>'int'], 'socket_create_pair' => ['bool', 'domain'=>'int', 'type'=>'int', 'protocol'=>'int', '&w_pair'=>'Socket[]'], 'socket_export_stream' => ['resource|false', 'socket'=>'Socket'], 'socket_get_option' => ['array|int|false', 'socket'=>'Socket', 'level'=>'int', 'option'=>'int'], 'socket_get_status' => ['array', 'stream'=>'Socket'], 'socket_getopt' => ['array|int|false', 'socket'=>'Socket', 'level'=>'int', 'option'=>'int'], 'socket_getpeername' => ['bool', 'socket'=>'Socket', '&w_address'=>'string', '&w_port='=>'int'], 'socket_getsockname' => ['bool', 'socket'=>'Socket', '&w_address'=>'string', '&w_port='=>'int'], 'socket_import_stream' => ['Socket|false', 'stream'=>'resource'], 'socket_last_error' => ['int', 'socket='=>'?Socket'], 'socket_listen' => ['bool', 'socket'=>'Socket', 'backlog='=>'int'], 'socket_read' => ['string|false', 'socket'=>'Socket', 'length'=>'int', 'mode='=>'int'], 'socket_recv' => ['int|false', 'socket'=>'Socket', '&w_data'=>'string', 'length'=>'int', 'flags'=>'int'], 'socket_recvfrom' => ['int|false', 'socket'=>'Socket', '&w_data'=>'string', 'length'=>'int', 'flags'=>'int', '&w_address'=>'string', '&w_port='=>'int'], 'socket_recvmsg' => ['int|false', 'socket'=>'Socket', '&w_message'=>'array', 'flags='=>'int'], 'socket_select' => ['int|false', '&rw_read'=>'Socket[]|null', '&rw_write'=>'Socket[]|null', '&rw_except'=>'Socket[]|null', 'seconds'=>'int|null', 'microseconds='=>'int'], 'socket_send' => ['int|false', 'socket'=>'Socket', 'data'=>'string', 'length'=>'int', 'flags'=>'int'], 'socket_sendmsg' => ['int|false', 'socket'=>'Socket', 'message'=>'array', 'flags='=>'int'], 'socket_sendto' => ['int|false', 'socket'=>'Socket', 'data'=>'string', 'length'=>'int', 'flags'=>'int', 'address'=>'string', 'port='=>'?int'], 'socket_set_block' => ['bool', 'socket'=>'Socket'], 'socket_set_blocking' => ['bool', 'stream'=>'Socket', 'enable'=>'bool'], 'socket_set_nonblock' => ['bool', 'socket'=>'Socket'], 'socket_set_option' => ['bool', 'socket'=>'Socket', 'level'=>'int', 'option'=>'int', 'value'=>'int|string|array'], 'socket_set_timeout' => ['bool', 'stream'=>'resource', 'seconds'=>'int', 'microseconds='=>'int'], 'socket_setopt' => ['bool', 'socket'=>'Socket', 'level'=>'int', 'option'=>'int', 'value'=>'int|string|array'], 'socket_shutdown' => ['bool', 'socket'=>'Socket', 'mode='=>'int'], 'socket_strerror' => ['string', 'error_code'=>'int'], 'socket_write' => ['int|false', 'socket'=>'Socket', 'data'=>'string', 'length='=>'int|null'], 'socket_wsaprotocol_info_export' => ['string|false', 'socket'=>'Socket', 'process_id'=>'int'], 'socket_wsaprotocol_info_import' => ['Socket|false', 'info_id'=>'string'], 'socket_wsaprotocol_info_release' => ['bool', 'info_id'=>'string'], 'sodium_add' => ['void', '&rw_string1'=>'string', 'string2'=>'string'], 'sodium_base642bin' => ['string', 'string'=>'string', 'id'=>'int', 'ignore='=>'string'], 'sodium_bin2base64' => ['string', 'string'=>'string', 'id'=>'int'], 'sodium_bin2hex' => ['string', 'string'=>'string'], 'sodium_compare' => ['int', 'string1'=>'string', 'string2'=>'string'], 'sodium_crypto_aead_aes256gcm_decrypt' => ['string|false', 'ciphertext'=>'string', 'additional_data'=>'string', 'nonce'=>'string', 'key'=>'string'], 'sodium_crypto_aead_aes256gcm_encrypt' => ['string', 'message'=>'string', 'additional_data'=>'string', 'nonce'=>'string', 'key'=>'string'], 'sodium_crypto_aead_aes256gcm_is_available' => ['bool'], 'sodium_crypto_aead_aes256gcm_keygen' => ['non-empty-string'], 'sodium_crypto_aead_chacha20poly1305_decrypt' => ['string|false', 'ciphertext'=>'string', 'additional_data'=>'string', 'nonce'=>'string', 'key'=>'string'], 'sodium_crypto_aead_chacha20poly1305_encrypt' => ['string', 'message'=>'string', 'additional_data'=>'string', 'nonce'=>'string', 'key'=>'string'], 'sodium_crypto_aead_chacha20poly1305_ietf_decrypt' => ['string|false', 'ciphertext'=>'string', 'additional_data'=>'string', 'nonce'=>'string', 'key'=>'string'], 'sodium_crypto_aead_chacha20poly1305_ietf_encrypt' => ['string', 'message'=>'string', 'additional_data'=>'string', 'nonce'=>'string', 'key'=>'string'], 'sodium_crypto_aead_chacha20poly1305_ietf_keygen' => ['non-empty-string'], 'sodium_crypto_aead_chacha20poly1305_keygen' => ['non-empty-string'], 'sodium_crypto_aead_xchacha20poly1305_ietf_decrypt' => ['string|false', 'ciphertext'=>'string', 'additional_data'=>'string', 'nonce'=>'string', 'key'=>'string'], 'sodium_crypto_aead_xchacha20poly1305_ietf_encrypt' => ['string', 'message'=>'string', 'additional_data'=>'string', 'nonce'=>'string', 'key'=>'string'], 'sodium_crypto_aead_xchacha20poly1305_ietf_keygen' => ['non-empty-string'], 'sodium_crypto_auth' => ['string', 'message'=>'string', 'key'=>'string'], 'sodium_crypto_auth_keygen' => ['non-empty-string'], 'sodium_crypto_auth_verify' => ['bool', 'mac'=>'string', 'message'=>'string', 'key'=>'string'], 'sodium_crypto_box' => ['string', 'message'=>'string', 'nonce'=>'string', 'key_pair'=>'string'], 'sodium_crypto_box_keypair' => ['string'], 'sodium_crypto_box_keypair_from_secretkey_and_publickey' => ['string', 'secret_key'=>'string', 'public_key'=>'string'], 'sodium_crypto_box_open' => ['string|false', 'ciphertext'=>'string', 'nonce'=>'string', 'key_pair'=>'string'], 'sodium_crypto_box_publickey' => ['string', 'key_pair'=>'string'], 'sodium_crypto_box_publickey_from_secretkey' => ['string', 'secret_key'=>'string'], 'sodium_crypto_box_seal' => ['string', 'message'=>'string', 'public_key'=>'string'], 'sodium_crypto_box_seal_open' => ['string|false', 'ciphertext'=>'string', 'key_pair'=>'string'], 'sodium_crypto_box_secretkey' => ['string', 'key_pair'=>'string'], 'sodium_crypto_box_seed_keypair' => ['string', 'seed'=>'string'], 'sodium_crypto_generichash' => ['string', 'message'=>'string', 'key='=>'string', 'length='=>'int'], 'sodium_crypto_generichash_final' => ['string', '&state'=>'string', 'length='=>'int'], 'sodium_crypto_generichash_init' => ['string', 'key='=>'string', 'length='=>'int'], 'sodium_crypto_generichash_keygen' => ['non-empty-string'], 'sodium_crypto_generichash_update' => ['true', '&rw_state'=>'string', 'message'=>'string'], 'sodium_crypto_kdf_derive_from_key' => ['string', 'subkey_length'=>'int', 'subkey_id'=>'int', 'context'=>'string', 'key'=>'string'], 'sodium_crypto_kdf_keygen' => ['non-empty-string'], 'sodium_crypto_kx_client_session_keys' => ['array', 'client_key_pair'=>'string', 'server_key'=>'string'], 'sodium_crypto_kx_keypair' => ['string'], 'sodium_crypto_kx_publickey' => ['string', 'key_pair'=>'string'], 'sodium_crypto_kx_secretkey' => ['string', 'key_pair'=>'string'], 'sodium_crypto_kx_seed_keypair' => ['string', 'seed'=>'string'], 'sodium_crypto_kx_server_session_keys' => ['array', 'server_key_pair'=>'string', 'client_key'=>'string'], 'sodium_crypto_pwhash' => ['string', 'length'=>'int', 'password'=>'string', 'salt'=>'string', 'opslimit'=>'int', 'memlimit'=>'int', 'algo='=>'int'], 'sodium_crypto_pwhash_scryptsalsa208sha256' => ['string', 'length'=>'int', 'password'=>'string', 'salt'=>'string', 'opslimit'=>'int', 'memlimit'=>'int'], 'sodium_crypto_pwhash_scryptsalsa208sha256_str' => ['string', 'password'=>'string', 'opslimit'=>'int', 'memlimit'=>'int'], 'sodium_crypto_pwhash_scryptsalsa208sha256_str_verify' => ['bool', 'hash'=>'string', 'password'=>'string'], 'sodium_crypto_pwhash_str' => ['string', 'password'=>'string', 'opslimit'=>'int', 'memlimit'=>'int'], 'sodium_crypto_pwhash_str_needs_rehash' => ['bool', 'password'=>'string', 'opslimit'=>'int', 'memlimit'=>'int'], 'sodium_crypto_pwhash_str_verify' => ['bool', 'hash'=>'string', 'password'=>'string'], 'sodium_crypto_scalarmult' => ['string', 'n'=>'string', 'p'=>'string'], 'sodium_crypto_scalarmult_base' => ['string', 'secret_key'=>'string'], 'sodium_crypto_secretbox' => ['string', 'message'=>'string', 'nonce'=>'string', 'key'=>'string'], 'sodium_crypto_secretbox_keygen' => ['non-empty-string'], 'sodium_crypto_secretbox_open' => ['string|false', 'ciphertext'=>'string', 'nonce'=>'string', 'key'=>'string'], 'sodium_crypto_secretstream_xchacha20poly1305_init_pull' => ['string', 'header'=>'string', 'key'=>'string'], 'sodium_crypto_secretstream_xchacha20poly1305_init_push' => ['array', 'key'=>'string'], 'sodium_crypto_secretstream_xchacha20poly1305_keygen' => ['non-empty-string'], 'sodium_crypto_secretstream_xchacha20poly1305_pull' => ['array|false', '&r_state'=>'string', 'ciphertext'=>'string', 'additional_data='=>'string'], 'sodium_crypto_secretstream_xchacha20poly1305_push' => ['string', '&w_state'=>'string', 'message'=>'string', 'additional_data='=>'string', 'tag='=>'int'], 'sodium_crypto_secretstream_xchacha20poly1305_rekey' => ['void', '&w_state'=>'string'], 'sodium_crypto_shorthash' => ['string', 'message'=>'string', 'key'=>'string'], 'sodium_crypto_shorthash_keygen' => ['non-empty-string'], 'sodium_crypto_sign' => ['string', 'message'=>'string', 'secret_key'=>'string'], 'sodium_crypto_sign_detached' => ['string', 'message'=>'string', 'secret_key'=>'string'], 'sodium_crypto_sign_ed25519_pk_to_curve25519' => ['string', 'public_key'=>'string'], 'sodium_crypto_sign_ed25519_sk_to_curve25519' => ['string', 'secret_key'=>'string'], 'sodium_crypto_sign_keypair' => ['string'], 'sodium_crypto_sign_keypair_from_secretkey_and_publickey' => ['string', 'secret_key'=>'string', 'public_key'=>'string'], 'sodium_crypto_sign_open' => ['string|false', 'signed_message'=>'string', 'public_key'=>'string'], 'sodium_crypto_sign_publickey' => ['string', 'key_pair'=>'string'], 'sodium_crypto_sign_publickey_from_secretkey' => ['string', 'secret_key'=>'string'], 'sodium_crypto_sign_secretkey' => ['string', 'key_pair'=>'string'], 'sodium_crypto_sign_seed_keypair' => ['string', 'seed'=>'string'], 'sodium_crypto_sign_verify_detached' => ['bool', 'signature'=>'string', 'message'=>'string', 'public_key'=>'string'], 'sodium_crypto_stream' => ['string', 'length'=>'int', 'nonce'=>'string', 'key'=>'string'], 'sodium_crypto_stream_keygen' => ['non-empty-string'], 'sodium_crypto_stream_xor' => ['string', 'message'=>'string', 'nonce'=>'string', 'key'=>'string'], 'sodium_crypto_stream_xchacha20' => ['non-empty-string', 'length'=>'positive-int', 'nonce'=>'non-empty-string', 'key'=>'non-empty-string'], 'sodium_crypto_stream_xchacha20_keygen' => ['non-empty-string'], 'sodium_crypto_stream_xchacha20_xor' => ['string', 'message'=>'string', 'nonce'=>'non-empty-string', 'key'=>'non-empty-string'], 'sodium_crypto_stream_xchacha20_xor_ic' => ['string', 'message'=>'string', 'nonce'=>'non-empty-string', 'counter'=>'int', 'key'=>'non-empty-string'], 'sodium_hex2bin' => ['string', 'string'=>'string', 'ignore='=>'string'], 'sodium_increment' => ['void', '&rw_string'=>'string'], 'sodium_memcmp' => ['int', 'string1'=>'string', 'string2'=>'string'], 'sodium_memzero' => ['void', '&w_string'=>'string'], 'sodium_pad' => ['string', 'string'=>'string', 'block_size'=>'int'], 'sodium_unpad' => ['string', 'string'=>'string', 'block_size'=>'int'], 'solid_fetch_prev' => ['bool', 'result_id'=>''], 'solr_get_version' => ['string|false'], 'SolrClient::__construct' => ['void', 'clientOptions'=>'array'], 'SolrClient::__destruct' => ['void'], 'SolrClient::addDocument' => ['SolrUpdateResponse', 'doc'=>'SolrInputDocument', 'allowdups='=>'bool', 'commitwithin='=>'int'], 'SolrClient::addDocuments' => ['SolrUpdateResponse', 'docs'=>'array', 'allowdups='=>'bool', 'commitwithin='=>'int'], 'SolrClient::commit' => ['SolrUpdateResponse', 'maxsegments='=>'int', 'waitflush='=>'bool', 'waitsearcher='=>'bool'], 'SolrClient::deleteById' => ['SolrUpdateResponse', 'id'=>'string'], 'SolrClient::deleteByIds' => ['SolrUpdateResponse', 'ids'=>'array'], 'SolrClient::deleteByQueries' => ['SolrUpdateResponse', 'queries'=>'array'], 'SolrClient::deleteByQuery' => ['SolrUpdateResponse', 'query'=>'string'], 'SolrClient::getById' => ['SolrQueryResponse', 'id'=>'string'], 'SolrClient::getByIds' => ['SolrQueryResponse', 'ids'=>'array'], 'SolrClient::getDebug' => ['string'], 'SolrClient::getOptions' => ['array'], 'SolrClient::optimize' => ['SolrUpdateResponse', 'maxsegments='=>'int', 'waitflush='=>'bool', 'waitsearcher='=>'bool'], 'SolrClient::ping' => ['SolrPingResponse'], 'SolrClient::query' => ['SolrQueryResponse', 'query'=>'SolrParams'], 'SolrClient::request' => ['SolrUpdateResponse', 'raw_request'=>'string'], 'SolrClient::rollback' => ['SolrUpdateResponse'], 'SolrClient::setResponseWriter' => ['void', 'responsewriter'=>'string'], 'SolrClient::setServlet' => ['bool', 'type'=>'int', 'value'=>'string'], 'SolrClient::system' => ['SolrGenericResponse'], 'SolrClient::threads' => ['SolrGenericResponse'], 'SolrClientException::__clone' => ['void'], 'SolrClientException::__construct' => ['void', 'message='=>'string', 'code='=>'int', 'previous='=>'?Exception|?Throwable'], 'SolrClientException::__toString' => ['string'], 'SolrClientException::__wakeup' => ['void'], 'SolrClientException::getCode' => ['int'], 'SolrClientException::getFile' => ['string'], 'SolrClientException::getInternalInfo' => ['array'], 'SolrClientException::getLine' => ['int'], 'SolrClientException::getMessage' => ['string'], 'SolrClientException::getPrevious' => ['?Exception|?Throwable'], 'SolrClientException::getTrace' => ['list\',args?:array}>'], 'SolrClientException::getTraceAsString' => ['string'], 'SolrCollapseFunction::__construct' => ['void', 'field'=>'string'], 'SolrCollapseFunction::__toString' => ['string'], 'SolrCollapseFunction::getField' => ['string'], 'SolrCollapseFunction::getHint' => ['string'], 'SolrCollapseFunction::getMax' => ['string'], 'SolrCollapseFunction::getMin' => ['string'], 'SolrCollapseFunction::getNullPolicy' => ['string'], 'SolrCollapseFunction::getSize' => ['int'], 'SolrCollapseFunction::setField' => ['SolrCollapseFunction', 'fieldName'=>'string'], 'SolrCollapseFunction::setHint' => ['SolrCollapseFunction', 'hint'=>'string'], 'SolrCollapseFunction::setMax' => ['SolrCollapseFunction', 'max'=>'string'], 'SolrCollapseFunction::setMin' => ['SolrCollapseFunction', 'min'=>'string'], 'SolrCollapseFunction::setNullPolicy' => ['SolrCollapseFunction', 'nullPolicy'=>'string'], 'SolrCollapseFunction::setSize' => ['SolrCollapseFunction', 'size'=>'int'], 'SolrDisMaxQuery::__construct' => ['void', 'q='=>'string'], 'SolrDisMaxQuery::__destruct' => ['void'], 'SolrDisMaxQuery::add' => ['SolrParams', 'name'=>'string', 'value'=>'string'], 'SolrDisMaxQuery::addBigramPhraseField' => ['SolrDisMaxQuery', 'field'=>'string', 'boost'=>'string', 'slop='=>'string'], 'SolrDisMaxQuery::addBoostQuery' => ['SolrDisMaxQuery', 'field'=>'string', 'value'=>'string', 'boost='=>'string'], 'SolrDisMaxQuery::addExpandFilterQuery' => ['SolrQuery', 'fq'=>'string'], 'SolrDisMaxQuery::addExpandSortField' => ['SolrQuery', 'field'=>'string', 'order'=>'string'], 'SolrDisMaxQuery::addFacetDateField' => ['SolrQuery', 'dateField'=>'string'], 'SolrDisMaxQuery::addFacetDateOther' => ['SolrQuery', 'value'=>'string', 'field_override'=>'string'], 'SolrDisMaxQuery::addFacetField' => ['SolrQuery', 'field'=>'string'], 'SolrDisMaxQuery::addFacetQuery' => ['SolrQuery', 'facetQuery'=>'string'], 'SolrDisMaxQuery::addField' => ['SolrQuery', 'field'=>'string'], 'SolrDisMaxQuery::addFilterQuery' => ['SolrQuery', 'fq'=>'string'], 'SolrDisMaxQuery::addGroupField' => ['SolrQuery', 'value'=>'string'], 'SolrDisMaxQuery::addGroupFunction' => ['SolrQuery', 'value'=>'string'], 'SolrDisMaxQuery::addGroupQuery' => ['SolrQuery', 'value'=>'string'], 'SolrDisMaxQuery::addGroupSortField' => ['SolrQuery', 'field'=>'string', 'order'=>'int'], 'SolrDisMaxQuery::addHighlightField' => ['SolrQuery', 'field'=>'string'], 'SolrDisMaxQuery::addMltField' => ['SolrQuery', 'field'=>'string'], 'SolrDisMaxQuery::addMltQueryField' => ['SolrQuery', 'field'=>'string', 'boost'=>'float'], 'SolrDisMaxQuery::addParam' => ['SolrParams', 'name'=>'string', 'value'=>'string'], 'SolrDisMaxQuery::addPhraseField' => ['SolrDisMaxQuery', 'field'=>'string', 'boost'=>'string', 'slop='=>'string'], 'SolrDisMaxQuery::addQueryField' => ['SolrDisMaxQuery', 'field'=>'string', 'boost='=>'string'], 'SolrDisMaxQuery::addSortField' => ['SolrQuery', 'field'=>'string', 'order='=>'int'], 'SolrDisMaxQuery::addStatsFacet' => ['SolrQuery', 'field'=>'string'], 'SolrDisMaxQuery::addStatsField' => ['SolrQuery', 'field'=>'string'], 'SolrDisMaxQuery::addTrigramPhraseField' => ['SolrDisMaxQuery', 'field'=>'string', 'boost'=>'string', 'slop='=>'string'], 'SolrDisMaxQuery::addUserField' => ['SolrDisMaxQuery', 'field'=>'string'], 'SolrDisMaxQuery::collapse' => ['SolrQuery', 'collapseFunction'=>'SolrCollapseFunction'], 'SolrDisMaxQuery::get' => ['mixed', 'param_name'=>'string'], 'SolrDisMaxQuery::getExpand' => ['bool'], 'SolrDisMaxQuery::getExpandFilterQueries' => ['array'], 'SolrDisMaxQuery::getExpandQuery' => ['array'], 'SolrDisMaxQuery::getExpandRows' => ['int'], 'SolrDisMaxQuery::getExpandSortFields' => ['array'], 'SolrDisMaxQuery::getFacet' => ['bool'], 'SolrDisMaxQuery::getFacetDateEnd' => ['string', 'field_override'=>'string'], 'SolrDisMaxQuery::getFacetDateFields' => ['array'], 'SolrDisMaxQuery::getFacetDateGap' => ['string', 'field_override'=>'string'], 'SolrDisMaxQuery::getFacetDateHardEnd' => ['string', 'field_override'=>'string'], 'SolrDisMaxQuery::getFacetDateOther' => ['string', 'field_override'=>'string'], 'SolrDisMaxQuery::getFacetDateStart' => ['string', 'field_override'=>'string'], 'SolrDisMaxQuery::getFacetFields' => ['array'], 'SolrDisMaxQuery::getFacetLimit' => ['int', 'field_override'=>'string'], 'SolrDisMaxQuery::getFacetMethod' => ['string', 'field_override'=>'string'], 'SolrDisMaxQuery::getFacetMinCount' => ['int', 'field_override'=>'string'], 'SolrDisMaxQuery::getFacetMissing' => ['string', 'field_override'=>'string'], 'SolrDisMaxQuery::getFacetOffset' => ['int', 'field_override'=>'string'], 'SolrDisMaxQuery::getFacetPrefix' => ['string', 'field_override'=>'string'], 'SolrDisMaxQuery::getFacetQueries' => ['string'], 'SolrDisMaxQuery::getFacetSort' => ['int', 'field_override'=>'string'], 'SolrDisMaxQuery::getFields' => ['string'], 'SolrDisMaxQuery::getFilterQueries' => ['string'], 'SolrDisMaxQuery::getGroup' => ['bool'], 'SolrDisMaxQuery::getGroupCachePercent' => ['int'], 'SolrDisMaxQuery::getGroupFacet' => ['bool'], 'SolrDisMaxQuery::getGroupFields' => ['array'], 'SolrDisMaxQuery::getGroupFormat' => ['string'], 'SolrDisMaxQuery::getGroupFunctions' => ['array'], 'SolrDisMaxQuery::getGroupLimit' => ['int'], 'SolrDisMaxQuery::getGroupMain' => ['bool'], 'SolrDisMaxQuery::getGroupNGroups' => ['bool'], 'SolrDisMaxQuery::getGroupOffset' => ['bool'], 'SolrDisMaxQuery::getGroupQueries' => ['array'], 'SolrDisMaxQuery::getGroupSortFields' => ['array'], 'SolrDisMaxQuery::getGroupTruncate' => ['bool'], 'SolrDisMaxQuery::getHighlight' => ['bool'], 'SolrDisMaxQuery::getHighlightAlternateField' => ['string', 'field_override'=>'string'], 'SolrDisMaxQuery::getHighlightFields' => ['array'], 'SolrDisMaxQuery::getHighlightFormatter' => ['string', 'field_override'=>'string'], 'SolrDisMaxQuery::getHighlightFragmenter' => ['string', 'field_override'=>'string'], 'SolrDisMaxQuery::getHighlightFragsize' => ['int', 'field_override'=>'string'], 'SolrDisMaxQuery::getHighlightHighlightMultiTerm' => ['bool'], 'SolrDisMaxQuery::getHighlightMaxAlternateFieldLength' => ['int', 'field_override'=>'string'], 'SolrDisMaxQuery::getHighlightMaxAnalyzedChars' => ['int'], 'SolrDisMaxQuery::getHighlightMergeContiguous' => ['bool', 'field_override'=>'string'], 'SolrDisMaxQuery::getHighlightRegexMaxAnalyzedChars' => ['int'], 'SolrDisMaxQuery::getHighlightRegexPattern' => ['string'], 'SolrDisMaxQuery::getHighlightRegexSlop' => ['float'], 'SolrDisMaxQuery::getHighlightRequireFieldMatch' => ['bool'], 'SolrDisMaxQuery::getHighlightSimplePost' => ['string', 'field_override'=>'string'], 'SolrDisMaxQuery::getHighlightSimplePre' => ['string', 'field_override'=>'string'], 'SolrDisMaxQuery::getHighlightSnippets' => ['int', 'field_override'=>'string'], 'SolrDisMaxQuery::getHighlightUsePhraseHighlighter' => ['bool'], 'SolrDisMaxQuery::getMlt' => ['bool'], 'SolrDisMaxQuery::getMltBoost' => ['bool'], 'SolrDisMaxQuery::getMltCount' => ['int'], 'SolrDisMaxQuery::getMltFields' => ['array'], 'SolrDisMaxQuery::getMltMaxNumQueryTerms' => ['int'], 'SolrDisMaxQuery::getMltMaxNumTokens' => ['int'], 'SolrDisMaxQuery::getMltMaxWordLength' => ['int'], 'SolrDisMaxQuery::getMltMinDocFrequency' => ['int'], 'SolrDisMaxQuery::getMltMinTermFrequency' => ['int'], 'SolrDisMaxQuery::getMltMinWordLength' => ['int'], 'SolrDisMaxQuery::getMltQueryFields' => ['array'], 'SolrDisMaxQuery::getParam' => ['mixed', 'param_name'=>'string'], 'SolrDisMaxQuery::getParams' => ['array'], 'SolrDisMaxQuery::getPreparedParams' => ['array'], 'SolrDisMaxQuery::getQuery' => ['string'], 'SolrDisMaxQuery::getRows' => ['int'], 'SolrDisMaxQuery::getSortFields' => ['array'], 'SolrDisMaxQuery::getStart' => ['int'], 'SolrDisMaxQuery::getStats' => ['bool'], 'SolrDisMaxQuery::getStatsFacets' => ['array'], 'SolrDisMaxQuery::getStatsFields' => ['array'], 'SolrDisMaxQuery::getTerms' => ['bool'], 'SolrDisMaxQuery::getTermsField' => ['string'], 'SolrDisMaxQuery::getTermsIncludeLowerBound' => ['bool'], 'SolrDisMaxQuery::getTermsIncludeUpperBound' => ['bool'], 'SolrDisMaxQuery::getTermsLimit' => ['int'], 'SolrDisMaxQuery::getTermsLowerBound' => ['string'], 'SolrDisMaxQuery::getTermsMaxCount' => ['int'], 'SolrDisMaxQuery::getTermsMinCount' => ['int'], 'SolrDisMaxQuery::getTermsPrefix' => ['string'], 'SolrDisMaxQuery::getTermsReturnRaw' => ['bool'], 'SolrDisMaxQuery::getTermsSort' => ['int'], 'SolrDisMaxQuery::getTermsUpperBound' => ['string'], 'SolrDisMaxQuery::getTimeAllowed' => ['int'], 'SolrDisMaxQuery::removeBigramPhraseField' => ['SolrDisMaxQuery', 'field'=>'string'], 'SolrDisMaxQuery::removeBoostQuery' => ['SolrDisMaxQuery', 'field'=>'string'], 'SolrDisMaxQuery::removeExpandFilterQuery' => ['SolrQuery', 'fq'=>'string'], 'SolrDisMaxQuery::removeExpandSortField' => ['SolrQuery', 'field'=>'string'], 'SolrDisMaxQuery::removeFacetDateField' => ['SolrQuery', 'field'=>'string'], 'SolrDisMaxQuery::removeFacetDateOther' => ['SolrQuery', 'value'=>'string', 'field_override'=>'string'], 'SolrDisMaxQuery::removeFacetField' => ['SolrQuery', 'field'=>'string'], 'SolrDisMaxQuery::removeFacetQuery' => ['SolrQuery', 'value'=>'string'], 'SolrDisMaxQuery::removeField' => ['SolrQuery', 'field'=>'string'], 'SolrDisMaxQuery::removeFilterQuery' => ['SolrQuery', 'fq'=>'string'], 'SolrDisMaxQuery::removeHighlightField' => ['SolrQuery', 'field'=>'string'], 'SolrDisMaxQuery::removeMltField' => ['SolrQuery', 'field'=>'string'], 'SolrDisMaxQuery::removeMltQueryField' => ['SolrQuery', 'queryField'=>'string'], 'SolrDisMaxQuery::removePhraseField' => ['SolrDisMaxQuery', 'field'=>'string'], 'SolrDisMaxQuery::removeQueryField' => ['SolrDisMaxQuery', 'field'=>'string'], 'SolrDisMaxQuery::removeSortField' => ['SolrQuery', 'field'=>'string'], 'SolrDisMaxQuery::removeStatsFacet' => ['SolrQuery', 'value'=>'string'], 'SolrDisMaxQuery::removeStatsField' => ['SolrQuery', 'field'=>'string'], 'SolrDisMaxQuery::removeTrigramPhraseField' => ['SolrDisMaxQuery', 'field'=>'string'], 'SolrDisMaxQuery::removeUserField' => ['SolrDisMaxQuery', 'field'=>'string'], 'SolrDisMaxQuery::serialize' => ['string'], 'SolrDisMaxQuery::set' => ['SolrParams', 'name'=>'string', 'value'=>''], 'SolrDisMaxQuery::setBigramPhraseFields' => ['SolrDisMaxQuery', 'fields'=>'string'], 'SolrDisMaxQuery::setBigramPhraseSlop' => ['SolrDisMaxQuery', 'slop'=>'string'], 'SolrDisMaxQuery::setBoostFunction' => ['SolrDisMaxQuery', 'function'=>'string'], 'SolrDisMaxQuery::setBoostQuery' => ['SolrDisMaxQuery', 'q'=>'string'], 'SolrDisMaxQuery::setEchoHandler' => ['SolrQuery', 'flag'=>'bool'], 'SolrDisMaxQuery::setEchoParams' => ['SolrQuery', 'type'=>'string'], 'SolrDisMaxQuery::setExpand' => ['SolrQuery', 'value'=>'bool'], 'SolrDisMaxQuery::setExpandQuery' => ['SolrQuery', 'q'=>'string'], 'SolrDisMaxQuery::setExpandRows' => ['SolrQuery', 'value'=>'int'], 'SolrDisMaxQuery::setExplainOther' => ['SolrQuery', 'query'=>'string'], 'SolrDisMaxQuery::setFacet' => ['SolrQuery', 'flag'=>'bool'], 'SolrDisMaxQuery::setFacetDateEnd' => ['SolrQuery', 'value'=>'string', 'field_override'=>'string'], 'SolrDisMaxQuery::setFacetDateGap' => ['SolrQuery', 'value'=>'string', 'field_override'=>'string'], 'SolrDisMaxQuery::setFacetDateHardEnd' => ['SolrQuery', 'value'=>'string', 'field_override'=>'string'], 'SolrDisMaxQuery::setFacetDateStart' => ['SolrQuery', 'value'=>'string', 'field_override'=>'string'], 'SolrDisMaxQuery::setFacetEnumCacheMinDefaultFrequency' => ['SolrQuery', 'frequency'=>'int', 'field_override'=>'string'], 'SolrDisMaxQuery::setFacetLimit' => ['SolrQuery', 'limit'=>'int', 'field_override'=>'string'], 'SolrDisMaxQuery::setFacetMethod' => ['SolrQuery', 'method'=>'string', 'field_override'=>'string'], 'SolrDisMaxQuery::setFacetMinCount' => ['SolrQuery', 'mincount'=>'int', 'field_override'=>'string'], 'SolrDisMaxQuery::setFacetMissing' => ['SolrQuery', 'flag'=>'bool', 'field_override'=>'string'], 'SolrDisMaxQuery::setFacetOffset' => ['SolrQuery', 'offset'=>'int', 'field_override'=>'string'], 'SolrDisMaxQuery::setFacetPrefix' => ['SolrQuery', 'prefix'=>'string', 'field_override'=>'string'], 'SolrDisMaxQuery::setFacetSort' => ['SolrQuery', 'facetSort'=>'int', 'field_override'=>'string'], 'SolrDisMaxQuery::setGroup' => ['SolrQuery', 'value'=>'bool'], 'SolrDisMaxQuery::setGroupCachePercent' => ['SolrQuery', 'percent'=>'int'], 'SolrDisMaxQuery::setGroupFacet' => ['SolrQuery', 'value'=>'bool'], 'SolrDisMaxQuery::setGroupFormat' => ['SolrQuery', 'value'=>'string'], 'SolrDisMaxQuery::setGroupLimit' => ['SolrQuery', 'value'=>'int'], 'SolrDisMaxQuery::setGroupMain' => ['SolrQuery', 'value'=>'string'], 'SolrDisMaxQuery::setGroupNGroups' => ['SolrQuery', 'value'=>'bool'], 'SolrDisMaxQuery::setGroupOffset' => ['SolrQuery', 'value'=>'int'], 'SolrDisMaxQuery::setGroupTruncate' => ['SolrQuery', 'value'=>'bool'], 'SolrDisMaxQuery::setHighlight' => ['SolrQuery', 'flag'=>'bool'], 'SolrDisMaxQuery::setHighlightAlternateField' => ['SolrQuery', 'field'=>'string', 'field_override'=>'string'], 'SolrDisMaxQuery::setHighlightFormatter' => ['SolrQuery', 'formatter'=>'string', 'field_override'=>'string'], 'SolrDisMaxQuery::setHighlightFragmenter' => ['SolrQuery', 'fragmenter'=>'string', 'field_override'=>'string'], 'SolrDisMaxQuery::setHighlightFragsize' => ['SolrQuery', 'size'=>'int', 'field_override'=>'string'], 'SolrDisMaxQuery::setHighlightHighlightMultiTerm' => ['SolrQuery', 'flag'=>'bool'], 'SolrDisMaxQuery::setHighlightMaxAlternateFieldLength' => ['SolrQuery', 'fieldLength'=>'string', 'field_override'=>'string'], 'SolrDisMaxQuery::setHighlightMaxAnalyzedChars' => ['SolrQuery', 'value'=>'int'], 'SolrDisMaxQuery::setHighlightMergeContiguous' => ['SolrQuery', 'flag'=>'bool', 'field_override'=>'string'], 'SolrDisMaxQuery::setHighlightRegexMaxAnalyzedChars' => ['SolrQuery', 'maxAnalyzedChars'=>'int'], 'SolrDisMaxQuery::setHighlightRegexPattern' => ['SolrQuery', 'value'=>'string'], 'SolrDisMaxQuery::setHighlightRegexSlop' => ['SolrQuery', 'factor'=>'float'], 'SolrDisMaxQuery::setHighlightRequireFieldMatch' => ['SolrQuery', 'flag'=>'bool'], 'SolrDisMaxQuery::setHighlightSimplePost' => ['SolrQuery', 'simplePost'=>'string', 'field_override'=>'string'], 'SolrDisMaxQuery::setHighlightSimplePre' => ['SolrQuery', 'simplePre'=>'string', 'field_override'=>'string'], 'SolrDisMaxQuery::setHighlightSnippets' => ['SolrQuery', 'value'=>'int', 'field_override'=>'string'], 'SolrDisMaxQuery::setHighlightUsePhraseHighlighter' => ['SolrQuery', 'flag'=>'bool'], 'SolrDisMaxQuery::setMinimumMatch' => ['SolrDisMaxQuery', 'value'=>'string'], 'SolrDisMaxQuery::setMlt' => ['SolrQuery', 'flag'=>'bool'], 'SolrDisMaxQuery::setMltBoost' => ['SolrQuery', 'flag'=>'bool'], 'SolrDisMaxQuery::setMltCount' => ['SolrQuery', 'count'=>'int'], 'SolrDisMaxQuery::setMltMaxNumQueryTerms' => ['SolrQuery', 'value'=>'int'], 'SolrDisMaxQuery::setMltMaxNumTokens' => ['SolrQuery', 'value'=>'int'], 'SolrDisMaxQuery::setMltMaxWordLength' => ['SolrQuery', 'maxWordLength'=>'int'], 'SolrDisMaxQuery::setMltMinDocFrequency' => ['SolrQuery', 'minDocFrequency'=>'int'], 'SolrDisMaxQuery::setMltMinTermFrequency' => ['SolrQuery', 'minTermFrequency'=>'int'], 'SolrDisMaxQuery::setMltMinWordLength' => ['SolrQuery', 'minWordLength'=>'int'], 'SolrDisMaxQuery::setOmitHeader' => ['SolrQuery', 'flag'=>'bool'], 'SolrDisMaxQuery::setParam' => ['SolrParams', 'name'=>'string', 'value'=>''], 'SolrDisMaxQuery::setPhraseFields' => ['SolrDisMaxQuery', 'fields'=>'string'], 'SolrDisMaxQuery::setPhraseSlop' => ['SolrDisMaxQuery', 'slop'=>'string'], 'SolrDisMaxQuery::setQuery' => ['SolrQuery', 'query'=>'string'], 'SolrDisMaxQuery::setQueryAlt' => ['SolrDisMaxQuery', 'q'=>'string'], 'SolrDisMaxQuery::setQueryPhraseSlop' => ['SolrDisMaxQuery', 'slop'=>'string'], 'SolrDisMaxQuery::setRows' => ['SolrQuery', 'rows'=>'int'], 'SolrDisMaxQuery::setShowDebugInfo' => ['SolrQuery', 'flag'=>'bool'], 'SolrDisMaxQuery::setStart' => ['SolrQuery', 'start'=>'int'], 'SolrDisMaxQuery::setStats' => ['SolrQuery', 'flag'=>'bool'], 'SolrDisMaxQuery::setTerms' => ['SolrQuery', 'flag'=>'bool'], 'SolrDisMaxQuery::setTermsField' => ['SolrQuery', 'fieldname'=>'string'], 'SolrDisMaxQuery::setTermsIncludeLowerBound' => ['SolrQuery', 'flag'=>'bool'], 'SolrDisMaxQuery::setTermsIncludeUpperBound' => ['SolrQuery', 'flag'=>'bool'], 'SolrDisMaxQuery::setTermsLimit' => ['SolrQuery', 'limit'=>'int'], 'SolrDisMaxQuery::setTermsLowerBound' => ['SolrQuery', 'lowerBound'=>'string'], 'SolrDisMaxQuery::setTermsMaxCount' => ['SolrQuery', 'frequency'=>'int'], 'SolrDisMaxQuery::setTermsMinCount' => ['SolrQuery', 'frequency'=>'int'], 'SolrDisMaxQuery::setTermsPrefix' => ['SolrQuery', 'prefix'=>'string'], 'SolrDisMaxQuery::setTermsReturnRaw' => ['SolrQuery', 'flag'=>'bool'], 'SolrDisMaxQuery::setTermsSort' => ['SolrQuery', 'sortType'=>'int'], 'SolrDisMaxQuery::setTermsUpperBound' => ['SolrQuery', 'upperBound'=>'string'], 'SolrDisMaxQuery::setTieBreaker' => ['SolrDisMaxQuery', 'tieBreaker'=>'string'], 'SolrDisMaxQuery::setTimeAllowed' => ['SolrQuery', 'timeAllowed'=>'int'], 'SolrDisMaxQuery::setTrigramPhraseFields' => ['SolrDisMaxQuery', 'fields'=>'string'], 'SolrDisMaxQuery::setTrigramPhraseSlop' => ['SolrDisMaxQuery', 'slop'=>'string'], 'SolrDisMaxQuery::setUserFields' => ['SolrDisMaxQuery', 'fields'=>'string'], 'SolrDisMaxQuery::toString' => ['string', 'url_encode='=>'bool'], 'SolrDisMaxQuery::unserialize' => ['void', 'serialized'=>'string'], 'SolrDisMaxQuery::useDisMaxQueryParser' => ['SolrDisMaxQuery'], 'SolrDisMaxQuery::useEDisMaxQueryParser' => ['SolrDisMaxQuery'], 'SolrDocument::__clone' => ['void'], 'SolrDocument::__construct' => ['void'], 'SolrDocument::__destruct' => ['void'], 'SolrDocument::__get' => ['SolrDocumentField', 'fieldname'=>'string'], 'SolrDocument::__isset' => ['bool', 'fieldname'=>'string'], 'SolrDocument::__set' => ['bool', 'fieldname'=>'string', 'fieldvalue'=>'string'], 'SolrDocument::__unset' => ['bool', 'fieldname'=>'string'], 'SolrDocument::addField' => ['bool', 'fieldname'=>'string', 'fieldvalue'=>'string'], 'SolrDocument::clear' => ['bool'], 'SolrDocument::current' => ['SolrDocumentField'], 'SolrDocument::deleteField' => ['bool', 'fieldname'=>'string'], 'SolrDocument::fieldExists' => ['bool', 'fieldname'=>'string'], 'SolrDocument::getChildDocuments' => ['SolrInputDocument[]'], 'SolrDocument::getChildDocumentsCount' => ['int'], 'SolrDocument::getField' => ['SolrDocumentField|false', 'fieldname'=>'string'], 'SolrDocument::getFieldCount' => ['int|false'], 'SolrDocument::getFieldNames' => ['array|false'], 'SolrDocument::getInputDocument' => ['SolrInputDocument'], 'SolrDocument::hasChildDocuments' => ['bool'], 'SolrDocument::key' => ['string'], 'SolrDocument::merge' => ['bool', 'sourcedoc'=>'solrdocument', 'overwrite='=>'bool'], 'SolrDocument::next' => ['void'], 'SolrDocument::offsetExists' => ['bool', 'fieldname'=>'string'], 'SolrDocument::offsetGet' => ['SolrDocumentField', 'fieldname'=>'string'], 'SolrDocument::offsetSet' => ['void', 'fieldname'=>'string', 'fieldvalue'=>'string'], 'SolrDocument::offsetUnset' => ['void', 'fieldname'=>'string'], 'SolrDocument::reset' => ['bool'], 'SolrDocument::rewind' => ['void'], 'SolrDocument::serialize' => ['string'], 'SolrDocument::sort' => ['bool', 'sortorderby'=>'int', 'sortdirection='=>'int'], 'SolrDocument::toArray' => ['array'], 'SolrDocument::unserialize' => ['void', 'serialized'=>'string'], 'SolrDocument::valid' => ['bool'], 'SolrDocumentField::__construct' => ['void'], 'SolrDocumentField::__destruct' => ['void'], 'SolrException::__clone' => ['void'], 'SolrException::__construct' => ['void', 'message='=>'string', 'code='=>'int', 'previous='=>'?Exception|?Throwable'], 'SolrException::__toString' => ['string'], 'SolrException::__wakeup' => ['void'], 'SolrException::getCode' => ['int'], 'SolrException::getFile' => ['string'], 'SolrException::getInternalInfo' => ['array'], 'SolrException::getLine' => ['int'], 'SolrException::getMessage' => ['string'], 'SolrException::getPrevious' => ['Exception|Throwable'], 'SolrException::getTrace' => ['list\',args?:array}>'], 'SolrException::getTraceAsString' => ['string'], 'SolrGenericResponse::__construct' => ['void'], 'SolrGenericResponse::__destruct' => ['void'], 'SolrGenericResponse::getDigestedResponse' => ['string'], 'SolrGenericResponse::getHttpStatus' => ['int'], 'SolrGenericResponse::getHttpStatusMessage' => ['string'], 'SolrGenericResponse::getRawRequest' => ['string'], 'SolrGenericResponse::getRawRequestHeaders' => ['string'], 'SolrGenericResponse::getRawResponse' => ['string'], 'SolrGenericResponse::getRawResponseHeaders' => ['string'], 'SolrGenericResponse::getRequestUrl' => ['string'], 'SolrGenericResponse::getResponse' => ['SolrObject'], 'SolrGenericResponse::setParseMode' => ['bool', 'parser_mode='=>'int'], 'SolrGenericResponse::success' => ['bool'], 'SolrIllegalArgumentException::__clone' => ['void'], 'SolrIllegalArgumentException::__construct' => ['void', 'message='=>'string', 'code='=>'int', 'previous='=>'?Exception|?Throwable'], 'SolrIllegalArgumentException::__toString' => ['string'], 'SolrIllegalArgumentException::__wakeup' => ['void'], 'SolrIllegalArgumentException::getCode' => ['int'], 'SolrIllegalArgumentException::getFile' => ['string'], 'SolrIllegalArgumentException::getInternalInfo' => ['array'], 'SolrIllegalArgumentException::getLine' => ['int'], 'SolrIllegalArgumentException::getMessage' => ['string'], 'SolrIllegalArgumentException::getPrevious' => ['Exception|Throwable'], 'SolrIllegalArgumentException::getTrace' => ['list\',args?:array}>'], 'SolrIllegalArgumentException::getTraceAsString' => ['string'], 'SolrIllegalOperationException::__clone' => ['void'], 'SolrIllegalOperationException::__construct' => ['void', 'message='=>'string', 'code='=>'int', 'previous='=>'?Exception|?Throwable'], 'SolrIllegalOperationException::__toString' => ['string'], 'SolrIllegalOperationException::__wakeup' => ['void'], 'SolrIllegalOperationException::getCode' => ['int'], 'SolrIllegalOperationException::getFile' => ['string'], 'SolrIllegalOperationException::getInternalInfo' => ['array'], 'SolrIllegalOperationException::getLine' => ['int'], 'SolrIllegalOperationException::getMessage' => ['string'], 'SolrIllegalOperationException::getPrevious' => ['Exception|Throwable'], 'SolrIllegalOperationException::getTrace' => ['list\',args?:array}>'], 'SolrIllegalOperationException::getTraceAsString' => ['string'], 'SolrInputDocument::__clone' => ['void'], 'SolrInputDocument::__construct' => ['void'], 'SolrInputDocument::__destruct' => ['void'], 'SolrInputDocument::addChildDocument' => ['void', 'child'=>'SolrInputDocument'], 'SolrInputDocument::addChildDocuments' => ['void', 'docs'=>'array'], 'SolrInputDocument::addField' => ['bool', 'fieldname'=>'string', 'fieldvalue'=>'string', 'fieldboostvalue='=>'float'], 'SolrInputDocument::clear' => ['bool'], 'SolrInputDocument::deleteField' => ['bool', 'fieldname'=>'string'], 'SolrInputDocument::fieldExists' => ['bool', 'fieldname'=>'string'], 'SolrInputDocument::getBoost' => ['float|false'], 'SolrInputDocument::getChildDocuments' => ['SolrInputDocument[]'], 'SolrInputDocument::getChildDocumentsCount' => ['int'], 'SolrInputDocument::getField' => ['SolrDocumentField|false', 'fieldname'=>'string'], 'SolrInputDocument::getFieldBoost' => ['float|false', 'fieldname'=>'string'], 'SolrInputDocument::getFieldCount' => ['int|false'], 'SolrInputDocument::getFieldNames' => ['array|false'], 'SolrInputDocument::hasChildDocuments' => ['bool'], 'SolrInputDocument::merge' => ['bool', 'sourcedoc'=>'SolrInputDocument', 'overwrite='=>'bool'], 'SolrInputDocument::reset' => ['bool'], 'SolrInputDocument::setBoost' => ['bool', 'documentboostvalue'=>'float'], 'SolrInputDocument::setFieldBoost' => ['bool', 'fieldname'=>'string', 'fieldboostvalue'=>'float'], 'SolrInputDocument::sort' => ['bool', 'sortorderby'=>'int', 'sortdirection='=>'int'], 'SolrInputDocument::toArray' => ['array|false'], 'SolrModifiableParams::__construct' => ['void'], 'SolrModifiableParams::__destruct' => ['void'], 'SolrModifiableParams::add' => ['SolrParams', 'name'=>'string', 'value'=>'string'], 'SolrModifiableParams::addParam' => ['SolrParams', 'name'=>'string', 'value'=>'string'], 'SolrModifiableParams::get' => ['mixed', 'param_name'=>'string'], 'SolrModifiableParams::getParam' => ['mixed', 'param_name'=>'string'], 'SolrModifiableParams::getParams' => ['array'], 'SolrModifiableParams::getPreparedParams' => ['array'], 'SolrModifiableParams::serialize' => ['string'], 'SolrModifiableParams::set' => ['SolrParams', 'name'=>'string', 'value'=>''], 'SolrModifiableParams::setParam' => ['SolrParams', 'name'=>'string', 'value'=>''], 'SolrModifiableParams::toString' => ['string', 'url_encode='=>'bool'], 'SolrModifiableParams::unserialize' => ['void', 'serialized'=>'string'], 'SolrObject::__construct' => ['void'], 'SolrObject::__destruct' => ['void'], 'SolrObject::getPropertyNames' => ['array'], 'SolrObject::offsetExists' => ['bool', 'property_name'=>'string'], 'SolrObject::offsetGet' => ['SolrDocumentField', 'property_name'=>'string'], 'SolrObject::offsetSet' => ['void', 'property_name'=>'string', 'property_value'=>'string'], 'SolrObject::offsetUnset' => ['void', 'property_name'=>'string'], 'SolrParams::__construct' => ['void'], 'SolrParams::add' => ['SolrParams|false', 'name'=>'string', 'value'=>'string'], 'SolrParams::addParam' => ['SolrParams|false', 'name'=>'string', 'value'=>'string'], 'SolrParams::get' => ['mixed', 'param_name'=>'string'], 'SolrParams::getParam' => ['mixed', 'param_name='=>'string'], 'SolrParams::getParams' => ['array'], 'SolrParams::getPreparedParams' => ['array'], 'SolrParams::serialize' => ['string'], 'SolrParams::set' => ['SolrParams|false', 'name'=>'string', 'value'=>'string'], 'SolrParams::setParam' => ['SolrParams|false', 'name'=>'string', 'value'=>'string'], 'SolrParams::toString' => ['string|false', 'url_encode='=>'bool'], 'SolrParams::unserialize' => ['void', 'serialized'=>'string'], 'SolrPingResponse::__construct' => ['void'], 'SolrPingResponse::__destruct' => ['void'], 'SolrPingResponse::getDigestedResponse' => ['string'], 'SolrPingResponse::getHttpStatus' => ['int'], 'SolrPingResponse::getHttpStatusMessage' => ['string'], 'SolrPingResponse::getRawRequest' => ['string'], 'SolrPingResponse::getRawRequestHeaders' => ['string'], 'SolrPingResponse::getRawResponse' => ['string'], 'SolrPingResponse::getRawResponseHeaders' => ['string'], 'SolrPingResponse::getRequestUrl' => ['string'], 'SolrPingResponse::getResponse' => ['string'], 'SolrPingResponse::setParseMode' => ['bool', 'parser_mode='=>'int'], 'SolrPingResponse::success' => ['bool'], 'SolrQuery::__construct' => ['void', 'q='=>'string'], 'SolrQuery::__destruct' => ['void'], 'SolrQuery::add' => ['SolrParams', 'name'=>'string', 'value'=>'string'], 'SolrQuery::addExpandFilterQuery' => ['SolrQuery', 'fq'=>'string'], 'SolrQuery::addExpandSortField' => ['SolrQuery', 'field'=>'string', 'order='=>'string'], 'SolrQuery::addFacetDateField' => ['SolrQuery', 'datefield'=>'string'], 'SolrQuery::addFacetDateOther' => ['SolrQuery', 'value'=>'string', 'field_override='=>'string'], 'SolrQuery::addFacetField' => ['SolrQuery', 'field'=>'string'], 'SolrQuery::addFacetQuery' => ['SolrQuery', 'facetquery'=>'string'], 'SolrQuery::addField' => ['SolrQuery', 'field'=>'string'], 'SolrQuery::addFilterQuery' => ['SolrQuery', 'fq'=>'string'], 'SolrQuery::addGroupField' => ['SolrQuery', 'value'=>'string'], 'SolrQuery::addGroupFunction' => ['SolrQuery', 'value'=>'string'], 'SolrQuery::addGroupQuery' => ['SolrQuery', 'value'=>'string'], 'SolrQuery::addGroupSortField' => ['SolrQuery', 'field'=>'string', 'order='=>'int'], 'SolrQuery::addHighlightField' => ['SolrQuery', 'field'=>'string'], 'SolrQuery::addMltField' => ['SolrQuery', 'field'=>'string'], 'SolrQuery::addMltQueryField' => ['SolrQuery', 'field'=>'string', 'boost'=>'float'], 'SolrQuery::addParam' => ['SolrParams', 'name'=>'string', 'value'=>'string'], 'SolrQuery::addSortField' => ['SolrQuery', 'field'=>'string', 'order='=>'int'], 'SolrQuery::addStatsFacet' => ['SolrQuery', 'field'=>'string'], 'SolrQuery::addStatsField' => ['SolrQuery', 'field'=>'string'], 'SolrQuery::collapse' => ['SolrQuery', 'collapseFunction'=>'SolrCollapseFunction'], 'SolrQuery::get' => ['mixed', 'param_name'=>'string'], 'SolrQuery::getExpand' => ['bool'], 'SolrQuery::getExpandFilterQueries' => ['array'], 'SolrQuery::getExpandQuery' => ['array'], 'SolrQuery::getExpandRows' => ['int'], 'SolrQuery::getExpandSortFields' => ['array'], 'SolrQuery::getFacet' => ['?bool'], 'SolrQuery::getFacetDateEnd' => ['?string', 'field_override='=>'string'], 'SolrQuery::getFacetDateFields' => ['array'], 'SolrQuery::getFacetDateGap' => ['?string', 'field_override='=>'string'], 'SolrQuery::getFacetDateHardEnd' => ['?string', 'field_override='=>'string'], 'SolrQuery::getFacetDateOther' => ['?string', 'field_override='=>'string'], 'SolrQuery::getFacetDateStart' => ['?string', 'field_override='=>'string'], 'SolrQuery::getFacetFields' => ['array'], 'SolrQuery::getFacetLimit' => ['?int', 'field_override='=>'string'], 'SolrQuery::getFacetMethod' => ['?string', 'field_override='=>'string'], 'SolrQuery::getFacetMinCount' => ['?int', 'field_override='=>'string'], 'SolrQuery::getFacetMissing' => ['?bool', 'field_override='=>'string'], 'SolrQuery::getFacetOffset' => ['?int', 'field_override='=>'string'], 'SolrQuery::getFacetPrefix' => ['?string', 'field_override='=>'string'], 'SolrQuery::getFacetQueries' => ['?array'], 'SolrQuery::getFacetSort' => ['int', 'field_override='=>'string'], 'SolrQuery::getFields' => ['?array'], 'SolrQuery::getFilterQueries' => ['?array'], 'SolrQuery::getGroup' => ['bool'], 'SolrQuery::getGroupCachePercent' => ['int'], 'SolrQuery::getGroupFacet' => ['bool'], 'SolrQuery::getGroupFields' => ['array'], 'SolrQuery::getGroupFormat' => ['string'], 'SolrQuery::getGroupFunctions' => ['array'], 'SolrQuery::getGroupLimit' => ['int'], 'SolrQuery::getGroupMain' => ['bool'], 'SolrQuery::getGroupNGroups' => ['bool'], 'SolrQuery::getGroupOffset' => ['int'], 'SolrQuery::getGroupQueries' => ['array'], 'SolrQuery::getGroupSortFields' => ['array'], 'SolrQuery::getGroupTruncate' => ['bool'], 'SolrQuery::getHighlight' => ['bool'], 'SolrQuery::getHighlightAlternateField' => ['?string', 'field_override='=>'string'], 'SolrQuery::getHighlightFields' => ['?array'], 'SolrQuery::getHighlightFormatter' => ['?string', 'field_override='=>'string'], 'SolrQuery::getHighlightFragmenter' => ['?string', 'field_override='=>'string'], 'SolrQuery::getHighlightFragsize' => ['?int', 'field_override='=>'string'], 'SolrQuery::getHighlightHighlightMultiTerm' => ['?bool'], 'SolrQuery::getHighlightMaxAlternateFieldLength' => ['?int', 'field_override='=>'string'], 'SolrQuery::getHighlightMaxAnalyzedChars' => ['?int'], 'SolrQuery::getHighlightMergeContiguous' => ['?bool', 'field_override='=>'string'], 'SolrQuery::getHighlightRegexMaxAnalyzedChars' => ['?int'], 'SolrQuery::getHighlightRegexPattern' => ['?string'], 'SolrQuery::getHighlightRegexSlop' => ['?float'], 'SolrQuery::getHighlightRequireFieldMatch' => ['?bool'], 'SolrQuery::getHighlightSimplePost' => ['?string', 'field_override='=>'string'], 'SolrQuery::getHighlightSimplePre' => ['?string', 'field_override='=>'string'], 'SolrQuery::getHighlightSnippets' => ['?int', 'field_override='=>'string'], 'SolrQuery::getHighlightUsePhraseHighlighter' => ['?bool'], 'SolrQuery::getMlt' => ['?bool'], 'SolrQuery::getMltBoost' => ['?bool'], 'SolrQuery::getMltCount' => ['?int'], 'SolrQuery::getMltFields' => ['?array'], 'SolrQuery::getMltMaxNumQueryTerms' => ['?int'], 'SolrQuery::getMltMaxNumTokens' => ['?int'], 'SolrQuery::getMltMaxWordLength' => ['?int'], 'SolrQuery::getMltMinDocFrequency' => ['?int'], 'SolrQuery::getMltMinTermFrequency' => ['?int'], 'SolrQuery::getMltMinWordLength' => ['?int'], 'SolrQuery::getMltQueryFields' => ['?array'], 'SolrQuery::getParam' => ['?mixed', 'param_name'=>'string'], 'SolrQuery::getParams' => ['?array'], 'SolrQuery::getPreparedParams' => ['?array'], 'SolrQuery::getQuery' => ['?string'], 'SolrQuery::getRows' => ['?int'], 'SolrQuery::getSortFields' => ['?array'], 'SolrQuery::getStart' => ['?int'], 'SolrQuery::getStats' => ['?bool'], 'SolrQuery::getStatsFacets' => ['?array'], 'SolrQuery::getStatsFields' => ['?array'], 'SolrQuery::getTerms' => ['?bool'], 'SolrQuery::getTermsField' => ['?string'], 'SolrQuery::getTermsIncludeLowerBound' => ['?bool'], 'SolrQuery::getTermsIncludeUpperBound' => ['?bool'], 'SolrQuery::getTermsLimit' => ['?int'], 'SolrQuery::getTermsLowerBound' => ['?string'], 'SolrQuery::getTermsMaxCount' => ['?int'], 'SolrQuery::getTermsMinCount' => ['?int'], 'SolrQuery::getTermsPrefix' => ['?string'], 'SolrQuery::getTermsReturnRaw' => ['?bool'], 'SolrQuery::getTermsSort' => ['?int'], 'SolrQuery::getTermsUpperBound' => ['?string'], 'SolrQuery::getTimeAllowed' => ['?int'], 'SolrQuery::removeExpandFilterQuery' => ['SolrQuery', 'fq'=>'string'], 'SolrQuery::removeExpandSortField' => ['SolrQuery', 'field'=>'string'], 'SolrQuery::removeFacetDateField' => ['SolrQuery', 'field'=>'string'], 'SolrQuery::removeFacetDateOther' => ['SolrQuery', 'value'=>'string', 'field_override='=>'string'], 'SolrQuery::removeFacetField' => ['SolrQuery', 'field'=>'string'], 'SolrQuery::removeFacetQuery' => ['SolrQuery', 'value'=>'string'], 'SolrQuery::removeField' => ['SolrQuery', 'field'=>'string'], 'SolrQuery::removeFilterQuery' => ['SolrQuery', 'fq'=>'string'], 'SolrQuery::removeHighlightField' => ['SolrQuery', 'field'=>'string'], 'SolrQuery::removeMltField' => ['SolrQuery', 'field'=>'string'], 'SolrQuery::removeMltQueryField' => ['SolrQuery', 'queryfield'=>'string'], 'SolrQuery::removeSortField' => ['SolrQuery', 'field'=>'string'], 'SolrQuery::removeStatsFacet' => ['SolrQuery', 'value'=>'string'], 'SolrQuery::removeStatsField' => ['SolrQuery', 'field'=>'string'], 'SolrQuery::serialize' => ['string'], 'SolrQuery::set' => ['SolrParams', 'name'=>'string', 'value'=>''], 'SolrQuery::setEchoHandler' => ['SolrQuery', 'flag'=>'bool'], 'SolrQuery::setEchoParams' => ['SolrQuery', 'type'=>'string'], 'SolrQuery::setExpand' => ['SolrQuery', 'value'=>'bool'], 'SolrQuery::setExpandQuery' => ['SolrQuery', 'q'=>'string'], 'SolrQuery::setExpandRows' => ['SolrQuery', 'value'=>'int'], 'SolrQuery::setExplainOther' => ['SolrQuery', 'query'=>'string'], 'SolrQuery::setFacet' => ['SolrQuery', 'flag'=>'bool'], 'SolrQuery::setFacetDateEnd' => ['SolrQuery', 'value'=>'string', 'field_override='=>'string'], 'SolrQuery::setFacetDateGap' => ['SolrQuery', 'value'=>'string', 'field_override='=>'string'], 'SolrQuery::setFacetDateHardEnd' => ['SolrQuery', 'value'=>'bool', 'field_override='=>'string'], 'SolrQuery::setFacetDateStart' => ['SolrQuery', 'value'=>'string', 'field_override='=>'string'], 'SolrQuery::setFacetEnumCacheMinDefaultFrequency' => ['SolrQuery', 'frequency'=>'int', 'field_override='=>'string'], 'SolrQuery::setFacetLimit' => ['SolrQuery', 'limit'=>'int', 'field_override='=>'string'], 'SolrQuery::setFacetMethod' => ['SolrQuery', 'method'=>'string', 'field_override='=>'string'], 'SolrQuery::setFacetMinCount' => ['SolrQuery', 'mincount'=>'int', 'field_override='=>'string'], 'SolrQuery::setFacetMissing' => ['SolrQuery', 'flag'=>'bool', 'field_override='=>'string'], 'SolrQuery::setFacetOffset' => ['SolrQuery', 'offset'=>'int', 'field_override='=>'string'], 'SolrQuery::setFacetPrefix' => ['SolrQuery', 'prefix'=>'string', 'field_override='=>'string'], 'SolrQuery::setFacetSort' => ['SolrQuery', 'facetsort'=>'int', 'field_override='=>'string'], 'SolrQuery::setGroup' => ['SolrQuery', 'value'=>'bool'], 'SolrQuery::setGroupCachePercent' => ['SolrQuery', 'percent'=>'int'], 'SolrQuery::setGroupFacet' => ['SolrQuery', 'value'=>'bool'], 'SolrQuery::setGroupFormat' => ['SolrQuery', 'value'=>'string'], 'SolrQuery::setGroupLimit' => ['SolrQuery', 'value'=>'int'], 'SolrQuery::setGroupMain' => ['SolrQuery', 'value'=>'string'], 'SolrQuery::setGroupNGroups' => ['SolrQuery', 'value'=>'bool'], 'SolrQuery::setGroupOffset' => ['SolrQuery', 'value'=>'int'], 'SolrQuery::setGroupTruncate' => ['SolrQuery', 'value'=>'bool'], 'SolrQuery::setHighlight' => ['SolrQuery', 'flag'=>'bool'], 'SolrQuery::setHighlightAlternateField' => ['SolrQuery', 'field'=>'string', 'field_override='=>'string'], 'SolrQuery::setHighlightFormatter' => ['SolrQuery', 'formatter'=>'string', 'field_override='=>'string'], 'SolrQuery::setHighlightFragmenter' => ['SolrQuery', 'fragmenter'=>'string', 'field_override='=>'string'], 'SolrQuery::setHighlightFragsize' => ['SolrQuery', 'size'=>'int', 'field_override='=>'string'], 'SolrQuery::setHighlightHighlightMultiTerm' => ['SolrQuery', 'flag'=>'bool'], 'SolrQuery::setHighlightMaxAlternateFieldLength' => ['SolrQuery', 'fieldlength'=>'int', 'field_override='=>'string'], 'SolrQuery::setHighlightMaxAnalyzedChars' => ['SolrQuery', 'value'=>'int'], 'SolrQuery::setHighlightMergeContiguous' => ['SolrQuery', 'flag'=>'bool', 'field_override='=>'string'], 'SolrQuery::setHighlightRegexMaxAnalyzedChars' => ['SolrQuery', 'maxanalyzedchars'=>'int'], 'SolrQuery::setHighlightRegexPattern' => ['SolrQuery', 'value'=>'string'], 'SolrQuery::setHighlightRegexSlop' => ['SolrQuery', 'factor'=>'float'], 'SolrQuery::setHighlightRequireFieldMatch' => ['SolrQuery', 'flag'=>'bool'], 'SolrQuery::setHighlightSimplePost' => ['SolrQuery', 'simplepost'=>'string', 'field_override='=>'string'], 'SolrQuery::setHighlightSimplePre' => ['SolrQuery', 'simplepre'=>'string', 'field_override='=>'string'], 'SolrQuery::setHighlightSnippets' => ['SolrQuery', 'value'=>'int', 'field_override='=>'string'], 'SolrQuery::setHighlightUsePhraseHighlighter' => ['SolrQuery', 'flag'=>'bool'], 'SolrQuery::setMlt' => ['SolrQuery', 'flag'=>'bool'], 'SolrQuery::setMltBoost' => ['SolrQuery', 'flag'=>'bool'], 'SolrQuery::setMltCount' => ['SolrQuery', 'count'=>'int'], 'SolrQuery::setMltMaxNumQueryTerms' => ['SolrQuery', 'value'=>'int'], 'SolrQuery::setMltMaxNumTokens' => ['SolrQuery', 'value'=>'int'], 'SolrQuery::setMltMaxWordLength' => ['SolrQuery', 'maxwordlength'=>'int'], 'SolrQuery::setMltMinDocFrequency' => ['SolrQuery', 'mindocfrequency'=>'int'], 'SolrQuery::setMltMinTermFrequency' => ['SolrQuery', 'mintermfrequency'=>'int'], 'SolrQuery::setMltMinWordLength' => ['SolrQuery', 'minwordlength'=>'int'], 'SolrQuery::setOmitHeader' => ['SolrQuery', 'flag'=>'bool'], 'SolrQuery::setParam' => ['SolrParams', 'name'=>'string', 'value'=>''], 'SolrQuery::setQuery' => ['SolrQuery', 'query'=>'string'], 'SolrQuery::setRows' => ['SolrQuery', 'rows'=>'int'], 'SolrQuery::setShowDebugInfo' => ['SolrQuery', 'flag'=>'bool'], 'SolrQuery::setStart' => ['SolrQuery', 'start'=>'int'], 'SolrQuery::setStats' => ['SolrQuery', 'flag'=>'bool'], 'SolrQuery::setTerms' => ['SolrQuery', 'flag'=>'bool'], 'SolrQuery::setTermsField' => ['SolrQuery', 'fieldname'=>'string'], 'SolrQuery::setTermsIncludeLowerBound' => ['SolrQuery', 'flag'=>'bool'], 'SolrQuery::setTermsIncludeUpperBound' => ['SolrQuery', 'flag'=>'bool'], 'SolrQuery::setTermsLimit' => ['SolrQuery', 'limit'=>'int'], 'SolrQuery::setTermsLowerBound' => ['SolrQuery', 'lowerbound'=>'string'], 'SolrQuery::setTermsMaxCount' => ['SolrQuery', 'frequency'=>'int'], 'SolrQuery::setTermsMinCount' => ['SolrQuery', 'frequency'=>'int'], 'SolrQuery::setTermsPrefix' => ['SolrQuery', 'prefix'=>'string'], 'SolrQuery::setTermsReturnRaw' => ['SolrQuery', 'flag'=>'bool'], 'SolrQuery::setTermsSort' => ['SolrQuery', 'sorttype'=>'int'], 'SolrQuery::setTermsUpperBound' => ['SolrQuery', 'upperbound'=>'string'], 'SolrQuery::setTimeAllowed' => ['SolrQuery', 'timeallowed'=>'int'], 'SolrQuery::toString' => ['string', 'url_encode='=>'bool'], 'SolrQuery::unserialize' => ['void', 'serialized'=>'string'], 'SolrQueryResponse::__construct' => ['void'], 'SolrQueryResponse::__destruct' => ['void'], 'SolrQueryResponse::getDigestedResponse' => ['string'], 'SolrQueryResponse::getHttpStatus' => ['int'], 'SolrQueryResponse::getHttpStatusMessage' => ['string'], 'SolrQueryResponse::getRawRequest' => ['string'], 'SolrQueryResponse::getRawRequestHeaders' => ['string'], 'SolrQueryResponse::getRawResponse' => ['string'], 'SolrQueryResponse::getRawResponseHeaders' => ['string'], 'SolrQueryResponse::getRequestUrl' => ['string'], 'SolrQueryResponse::getResponse' => ['SolrObject'], 'SolrQueryResponse::setParseMode' => ['bool', 'parser_mode='=>'int'], 'SolrQueryResponse::success' => ['bool'], 'SolrResponse::getDigestedResponse' => ['string'], 'SolrResponse::getHttpStatus' => ['int'], 'SolrResponse::getHttpStatusMessage' => ['string'], 'SolrResponse::getRawRequest' => ['string'], 'SolrResponse::getRawRequestHeaders' => ['string'], 'SolrResponse::getRawResponse' => ['string'], 'SolrResponse::getRawResponseHeaders' => ['string'], 'SolrResponse::getRequestUrl' => ['string'], 'SolrResponse::getResponse' => ['SolrObject'], 'SolrResponse::setParseMode' => ['bool', 'parser_mode='=>'int'], 'SolrResponse::success' => ['bool'], 'SolrServerException::__clone' => ['void'], 'SolrServerException::__construct' => ['void', 'message='=>'string', 'code='=>'int', 'previous='=>'?Exception|?Throwable'], 'SolrServerException::__toString' => ['string'], 'SolrServerException::__wakeup' => ['void'], 'SolrServerException::getCode' => ['int'], 'SolrServerException::getFile' => ['string'], 'SolrServerException::getInternalInfo' => ['array'], 'SolrServerException::getLine' => ['int'], 'SolrServerException::getMessage' => ['string'], 'SolrServerException::getPrevious' => ['Exception|Throwable'], 'SolrServerException::getTrace' => ['list\',args?:array}>'], 'SolrServerException::getTraceAsString' => ['string'], 'SolrUpdateResponse::__construct' => ['void'], 'SolrUpdateResponse::__destruct' => ['void'], 'SolrUpdateResponse::getDigestedResponse' => ['string'], 'SolrUpdateResponse::getHttpStatus' => ['int'], 'SolrUpdateResponse::getHttpStatusMessage' => ['string'], 'SolrUpdateResponse::getRawRequest' => ['string'], 'SolrUpdateResponse::getRawRequestHeaders' => ['string'], 'SolrUpdateResponse::getRawResponse' => ['string'], 'SolrUpdateResponse::getRawResponseHeaders' => ['string'], 'SolrUpdateResponse::getRequestUrl' => ['string'], 'SolrUpdateResponse::getResponse' => ['SolrObject'], 'SolrUpdateResponse::setParseMode' => ['bool', 'parser_mode='=>'int'], 'SolrUpdateResponse::success' => ['bool'], 'SolrUtils::digestXmlResponse' => ['SolrObject', 'xmlresponse'=>'string', 'parse_mode='=>'int'], 'SolrUtils::escapeQueryChars' => ['string|false', 'string'=>'string'], 'SolrUtils::getSolrVersion' => ['string'], 'SolrUtils::queryPhrase' => ['string', 'string'=>'string'], 'sort' => ['true', '&rw_array'=>'array', 'flags='=>'int'], 'soundex' => ['string', 'string'=>'string'], 'SphinxClient::__construct' => ['void'], 'SphinxClient::addQuery' => ['int', 'query'=>'string', 'index='=>'string', 'comment='=>'string'], 'SphinxClient::buildExcerpts' => ['array', 'docs'=>'array', 'index'=>'string', 'words'=>'string', 'opts='=>'array'], 'SphinxClient::buildKeywords' => ['array', 'query'=>'string', 'index'=>'string', 'hits'=>'bool'], 'SphinxClient::close' => ['bool'], 'SphinxClient::escapeString' => ['string', 'string'=>'string'], 'SphinxClient::getLastError' => ['string'], 'SphinxClient::getLastWarning' => ['string'], 'SphinxClient::open' => ['bool'], 'SphinxClient::query' => ['array', 'query'=>'string', 'index='=>'string', 'comment='=>'string'], 'SphinxClient::resetFilters' => ['void'], 'SphinxClient::resetGroupBy' => ['void'], 'SphinxClient::runQueries' => ['array'], 'SphinxClient::setArrayResult' => ['bool', 'array_result'=>'bool'], 'SphinxClient::setConnectTimeout' => ['bool', 'timeout'=>'float'], 'SphinxClient::setFieldWeights' => ['bool', 'weights'=>'array'], 'SphinxClient::setFilter' => ['bool', 'attribute'=>'string', 'values'=>'array', 'exclude='=>'bool'], 'SphinxClient::setFilterFloatRange' => ['bool', 'attribute'=>'string', 'min'=>'float', 'max'=>'float', 'exclude='=>'bool'], 'SphinxClient::setFilterRange' => ['bool', 'attribute'=>'string', 'min'=>'int', 'max'=>'int', 'exclude='=>'bool'], 'SphinxClient::setGeoAnchor' => ['bool', 'attrlat'=>'string', 'attrlong'=>'string', 'latitude'=>'float', 'longitude'=>'float'], 'SphinxClient::setGroupBy' => ['bool', 'attribute'=>'string', 'func'=>'int', 'groupsort='=>'string'], 'SphinxClient::setGroupDistinct' => ['bool', 'attribute'=>'string'], 'SphinxClient::setIDRange' => ['bool', 'min'=>'int', 'max'=>'int'], 'SphinxClient::setIndexWeights' => ['bool', 'weights'=>'array'], 'SphinxClient::setLimits' => ['bool', 'offset'=>'int', 'limit'=>'int', 'max_matches='=>'int', 'cutoff='=>'int'], 'SphinxClient::setMatchMode' => ['bool', 'mode'=>'int'], 'SphinxClient::setMaxQueryTime' => ['bool', 'qtime'=>'int'], 'SphinxClient::setOverride' => ['bool', 'attribute'=>'string', 'type'=>'int', 'values'=>'array'], 'SphinxClient::setRankingMode' => ['bool', 'ranker'=>'int'], 'SphinxClient::setRetries' => ['bool', 'count'=>'int', 'delay='=>'int'], 'SphinxClient::setSelect' => ['bool', 'clause'=>'string'], 'SphinxClient::setServer' => ['bool', 'server'=>'string', 'port'=>'int'], 'SphinxClient::setSortMode' => ['bool', 'mode'=>'int', 'sortby='=>'string'], 'SphinxClient::status' => ['array'], 'SphinxClient::updateAttributes' => ['int', 'index'=>'string', 'attributes'=>'array', 'values'=>'array', 'mva='=>'bool'], 'spl_autoload' => ['void', 'class'=>'string', 'file_extensions='=>'?string'], 'spl_autoload_call' => ['void', 'class'=>'string'], 'spl_autoload_extensions' => ['string', 'file_extensions='=>'?string'], 'spl_autoload_functions' => ['list'], 'spl_autoload_register' => ['bool', 'callback='=>'callable(string):void|null', 'throw='=>'bool', 'prepend='=>'bool'], 'spl_autoload_unregister' => ['bool', 'callback'=>'callable(string):void'], 'spl_classes' => ['array'], 'spl_object_hash' => ['string', 'object'=>'object'], 'spl_object_id' => ['int', 'object'=>'object'], 'SplDoublyLinkedList::__construct' => ['void'], 'SplDoublyLinkedList::add' => ['void', 'index'=>'int', 'value'=>'mixed'], 'SplDoublyLinkedList::bottom' => ['mixed'], 'SplDoublyLinkedList::count' => ['int'], 'SplDoublyLinkedList::current' => ['mixed'], 'SplDoublyLinkedList::getIteratorMode' => ['int'], 'SplDoublyLinkedList::isEmpty' => ['bool'], 'SplDoublyLinkedList::key' => ['int'], 'SplDoublyLinkedList::next' => ['void'], 'SplDoublyLinkedList::offsetExists' => ['bool', 'index'=>'int'], 'SplDoublyLinkedList::offsetGet' => ['mixed', 'index'=>'int'], 'SplDoublyLinkedList::offsetSet' => ['void', 'index'=>'?int', 'value'=>'mixed'], 'SplDoublyLinkedList::offsetUnset' => ['void', 'index'=>'int'], 'SplDoublyLinkedList::pop' => ['mixed'], 'SplDoublyLinkedList::prev' => ['void'], 'SplDoublyLinkedList::push' => ['void', 'value'=>'mixed'], 'SplDoublyLinkedList::rewind' => ['void'], 'SplDoublyLinkedList::serialize' => ['string'], 'SplDoublyLinkedList::setIteratorMode' => ['int', 'mode'=>'int'], 'SplDoublyLinkedList::shift' => ['mixed'], 'SplDoublyLinkedList::top' => ['mixed'], 'SplDoublyLinkedList::unserialize' => ['void', 'data'=>'string'], 'SplDoublyLinkedList::unshift' => ['void', 'value'=>'mixed'], 'SplDoublyLinkedList::valid' => ['bool'], 'SplEnum::__construct' => ['void', 'initial_value='=>'mixed', 'strict='=>'bool'], 'SplEnum::getConstList' => ['array', 'include_default='=>'bool'], 'SplFileInfo::__construct' => ['void', 'filename'=>'string'], 'SplFileInfo::__toString' => ['string'], 'SplFileInfo::getATime' => ['int|false'], 'SplFileInfo::getBasename' => ['string', 'suffix='=>'string'], 'SplFileInfo::getCTime' => ['int|false'], 'SplFileInfo::getExtension' => ['string'], 'SplFileInfo::getFileInfo' => ['SplFileInfo', 'class='=>'?class-string'], 'SplFileInfo::getFilename' => ['string'], 'SplFileInfo::getGroup' => ['int|false'], 'SplFileInfo::getInode' => ['int|false'], 'SplFileInfo::getLinkTarget' => ['string|false'], 'SplFileInfo::getMTime' => ['int|false'], 'SplFileInfo::getOwner' => ['int|false'], 'SplFileInfo::getPath' => ['string'], 'SplFileInfo::getPathInfo' => ['SplFileInfo|null', 'class='=>'?class-string'], 'SplFileInfo::getPathname' => ['string'], 'SplFileInfo::getPerms' => ['int|false'], 'SplFileInfo::getRealPath' => ['non-falsy-string|false'], 'SplFileInfo::getSize' => ['int|false'], 'SplFileInfo::getType' => ['string|false'], 'SplFileInfo::isDir' => ['bool'], 'SplFileInfo::isExecutable' => ['bool'], 'SplFileInfo::isFile' => ['bool'], 'SplFileInfo::isLink' => ['bool'], 'SplFileInfo::isReadable' => ['bool'], 'SplFileInfo::isWritable' => ['bool'], 'SplFileInfo::openFile' => ['SplFileObject', 'mode='=>'string', 'useIncludePath='=>'bool', 'context='=>'?resource'], 'SplFileInfo::setFileClass' => ['void', 'class='=>'class-string'], 'SplFileInfo::setInfoClass' => ['void', 'class='=>'class-string'], 'SplFileObject::__construct' => ['void', 'filename'=>'string', 'mode='=>'string', 'useIncludePath='=>'bool', 'context='=>'?resource'], 'SplFileObject::__toString' => ['string'], 'SplFileObject::current' => ['string|array|false'], 'SplFileObject::eof' => ['bool'], 'SplFileObject::fflush' => ['bool'], 'SplFileObject::fgetc' => ['string|false'], 'SplFileObject::fgetcsv' => ['list|array{0: null}|false', 'separator='=>'string', 'enclosure='=>'string', 'escape='=>'string'], 'SplFileObject::fgets' => ['string'], 'SplFileObject::flock' => ['bool', 'operation'=>'int', '&w_wouldBlock='=>'int'], 'SplFileObject::fpassthru' => ['int'], 'SplFileObject::fputcsv' => ['int|false', 'fields'=>'array', 'separator='=>'string', 'enclosure='=>'string', 'escape='=>'string', 'eol='=>'string', 'eol='=>'string'], 'SplFileObject::fread' => ['string|false', 'length'=>'int'], 'SplFileObject::fscanf' => ['array|int', 'format'=>'string', '&...w_vars='=>'string|int|float'], 'SplFileObject::fseek' => ['int', 'offset'=>'int', 'whence='=>'int'], 'SplFileObject::fstat' => ['array{0: int, 1: int, 2: int, 3: int, 4: int, 5: int, 6: int, 7: int, 8: int, 9: int, 10: int, 11: int, 12: int, dev: int, ino: int, mode: int, nlink: int, uid: int, gid: int, rdev: int, size: int, atime: int, mtime: int, ctime: int, blksize: int, blocks: int}'], 'SplFileObject::ftell' => ['int|false'], 'SplFileObject::ftruncate' => ['bool', 'size'=>'int'], 'SplFileObject::fwrite' => ['int|false', 'data'=>'string', 'length='=>'int'], 'SplFileObject::getATime' => ['int|false'], 'SplFileObject::getBasename' => ['string', 'suffix='=>'string'], 'SplFileObject::getChildren' => ['null'], 'SplFileObject::getCsvControl' => ['array'], 'SplFileObject::getCTime' => ['int|false'], 'SplFileObject::getCurrentLine' => ['string'], 'SplFileObject::getExtension' => ['string'], 'SplFileObject::getFileInfo' => ['SplFileInfo', 'class='=>'?class-string'], 'SplFileObject::getFilename' => ['string'], 'SplFileObject::getFlags' => ['int'], 'SplFileObject::getGroup' => ['int|false'], 'SplFileObject::getInode' => ['int|false'], 'SplFileObject::getLinkTarget' => ['string|false'], 'SplFileObject::getMaxLineLen' => ['int'], 'SplFileObject::getMTime' => ['int|false'], 'SplFileObject::getOwner' => ['int|false'], 'SplFileObject::getPath' => ['string'], 'SplFileObject::getPathInfo' => ['SplFileInfo|null', 'class='=>'?class-string'], 'SplFileObject::getPathname' => ['string'], 'SplFileObject::getPerms' => ['int|false'], 'SplFileObject::getRealPath' => ['false|non-falsy-string'], 'SplFileObject::getSize' => ['int|false'], 'SplFileObject::getType' => ['string|false'], 'SplFileObject::hasChildren' => ['false'], 'SplFileObject::isDir' => ['bool'], 'SplFileObject::isExecutable' => ['bool'], 'SplFileObject::isFile' => ['bool'], 'SplFileObject::isLink' => ['bool'], 'SplFileObject::isReadable' => ['bool'], 'SplFileObject::isWritable' => ['bool'], 'SplFileObject::key' => ['int'], 'SplFileObject::next' => ['void'], 'SplFileObject::openFile' => ['SplFileObject', 'mode='=>'string', 'useIncludePath='=>'bool', 'context='=>'?resource'], 'SplFileObject::rewind' => ['void'], 'SplFileObject::seek' => ['void', 'line'=>'int'], 'SplFileObject::setCsvControl' => ['void', 'separator='=>'string', 'enclosure='=>'string', 'escape='=>'string'], 'SplFileObject::setFileClass' => ['void', 'class='=>'class-string'], 'SplFileObject::setFlags' => ['void', 'flags'=>'int'], 'SplFileObject::setInfoClass' => ['void', 'class='=>'class-string'], 'SplFileObject::setMaxLineLen' => ['void', 'maxLength'=>'int'], 'SplFileObject::valid' => ['bool'], 'SplFixedArray::__construct' => ['void', 'size='=>'int'], 'SplFixedArray::__wakeup' => ['void'], 'SplFixedArray::count' => ['int'], 'SplFixedArray::fromArray' => ['SplFixedArray', 'array'=>'array', 'preserveKeys='=>'bool'], 'SplFixedArray::getIterator' => ['Iterator'], 'SplFixedArray::getSize' => ['int'], 'SplFixedArray::offsetExists' => ['bool', 'index'=>'int'], 'SplFixedArray::offsetGet' => ['mixed', 'index'=>'int'], 'SplFixedArray::offsetSet' => ['void', 'index'=>'int', 'value'=>'mixed'], 'SplFixedArray::offsetUnset' => ['void', 'index'=>'int'], 'SplFixedArray::setSize' => ['bool', 'size'=>'int'], 'SplFixedArray::toArray' => ['array'], 'SplHeap::__construct' => ['void'], 'SplHeap::compare' => ['int', 'value1'=>'mixed', 'value2'=>'mixed'], 'SplHeap::count' => ['int'], 'SplHeap::current' => ['mixed'], 'SplHeap::extract' => ['mixed'], 'SplHeap::insert' => ['bool', 'value'=>'mixed'], 'SplHeap::isCorrupted' => ['bool'], 'SplHeap::isEmpty' => ['bool'], 'SplHeap::key' => ['int'], 'SplHeap::next' => ['void'], 'SplHeap::recoverFromCorruption' => ['true'], 'SplHeap::rewind' => ['void'], 'SplHeap::top' => ['mixed'], 'SplHeap::valid' => ['bool'], 'SplMaxHeap::__construct' => ['void'], 'SplMaxHeap::compare' => ['int', 'value1'=>'mixed', 'value2'=>'mixed'], 'SplMinHeap::compare' => ['int', 'value1'=>'mixed', 'value2'=>'mixed'], 'SplMinHeap::count' => ['int'], 'SplMinHeap::current' => ['mixed'], 'SplMinHeap::extract' => ['mixed'], 'SplMinHeap::insert' => ['true', 'value'=>'mixed'], 'SplMinHeap::isCorrupted' => ['bool'], 'SplMinHeap::isEmpty' => ['bool'], 'SplMinHeap::key' => ['int'], 'SplMinHeap::next' => ['void'], 'SplMinHeap::recoverFromCorruption' => ['true'], 'SplMinHeap::rewind' => ['void'], 'SplMinHeap::top' => ['mixed'], 'SplMinHeap::valid' => ['bool'], 'SplObjectStorage::__construct' => ['void'], 'SplObjectStorage::addAll' => ['int', 'storage'=>'SplObjectStorage'], 'SplObjectStorage::attach' => ['void', 'object'=>'object', 'info='=>'mixed'], 'SplObjectStorage::contains' => ['bool', 'object'=>'object'], 'SplObjectStorage::count' => ['int', 'mode='=>'int'], 'SplObjectStorage::current' => ['object'], 'SplObjectStorage::detach' => ['void', 'object'=>'object'], 'SplObjectStorage::getHash' => ['string', 'object'=>'object'], 'SplObjectStorage::getInfo' => ['mixed'], 'SplObjectStorage::key' => ['int'], 'SplObjectStorage::next' => ['void'], 'SplObjectStorage::offsetExists' => ['bool', 'object'=>'object'], 'SplObjectStorage::offsetGet' => ['mixed', 'object'=>'object'], 'SplObjectStorage::offsetSet' => ['void', 'object'=>'object', 'info='=>'mixed'], 'SplObjectStorage::offsetUnset' => ['void', 'object'=>'object'], 'SplObjectStorage::removeAll' => ['int', 'storage'=>'SplObjectStorage'], 'SplObjectStorage::removeAllExcept' => ['int', 'storage'=>'SplObjectStorage'], 'SplObjectStorage::rewind' => ['void'], 'SplObjectStorage::serialize' => ['string'], 'SplObjectStorage::setInfo' => ['void', 'info'=>'mixed'], 'SplObjectStorage::unserialize' => ['void', 'data'=>'string'], 'SplObjectStorage::valid' => ['bool'], 'SplObserver::update' => ['void', 'subject'=>'SplSubject'], 'SplPriorityQueue::__construct' => ['void'], 'SplPriorityQueue::compare' => ['int', 'priority1'=>'mixed', 'priority2'=>'mixed'], 'SplPriorityQueue::count' => ['int'], 'SplPriorityQueue::current' => ['mixed'], 'SplPriorityQueue::extract' => ['mixed'], 'SplPriorityQueue::getExtractFlags' => ['int'], 'SplPriorityQueue::insert' => ['bool', 'value'=>'mixed', 'priority'=>'mixed'], 'SplPriorityQueue::isCorrupted' => ['bool'], 'SplPriorityQueue::isEmpty' => ['bool'], 'SplPriorityQueue::key' => ['int'], 'SplPriorityQueue::next' => ['void'], 'SplPriorityQueue::recoverFromCorruption' => ['void'], 'SplPriorityQueue::rewind' => ['void'], 'SplPriorityQueue::setExtractFlags' => ['int', 'flags'=>'int'], 'SplPriorityQueue::top' => ['mixed'], 'SplPriorityQueue::valid' => ['bool'], 'SplQueue::dequeue' => ['mixed'], 'SplQueue::enqueue' => ['void', 'value'=>'mixed'], 'SplQueue::getIteratorMode' => ['int'], 'SplQueue::isEmpty' => ['bool'], 'SplQueue::key' => ['int'], 'SplQueue::next' => ['void'], 'SplQueue::offsetExists' => ['bool', 'index'=>'mixed'], 'SplQueue::offsetGet' => ['mixed', 'index'=>'mixed'], 'SplQueue::offsetSet' => ['void', 'index'=>'?int', 'value'=>'mixed'], 'SplQueue::offsetUnset' => ['void', 'index'=>'mixed'], 'SplQueue::pop' => ['mixed'], 'SplQueue::prev' => ['void'], 'SplQueue::push' => ['void', 'value'=>'mixed'], 'SplQueue::rewind' => ['void'], 'SplQueue::serialize' => ['string'], 'SplQueue::setIteratorMode' => ['int', 'mode'=>'int'], 'SplQueue::shift' => ['mixed'], 'SplQueue::top' => ['mixed'], 'SplQueue::unserialize' => ['void', 'data'=>'string'], 'SplQueue::unshift' => ['void', 'value'=>'mixed'], 'SplQueue::valid' => ['bool'], 'SplStack::__construct' => ['void'], 'SplStack::add' => ['void', 'index'=>'int', 'value'=>'mixed'], 'SplStack::bottom' => ['mixed'], 'SplStack::count' => ['int'], 'SplStack::current' => ['mixed'], 'SplStack::getIteratorMode' => ['int'], 'SplStack::isEmpty' => ['bool'], 'SplStack::key' => ['int'], 'SplStack::next' => ['void'], 'SplStack::offsetExists' => ['bool', 'index'=>'mixed'], 'SplStack::offsetGet' => ['mixed', 'index'=>'mixed'], 'SplStack::offsetSet' => ['void', 'index'=>'?int', 'value'=>'mixed'], 'SplStack::offsetUnset' => ['void', 'index'=>'mixed'], 'SplStack::pop' => ['mixed'], 'SplStack::prev' => ['void'], 'SplStack::push' => ['void', 'value'=>'mixed'], 'SplStack::rewind' => ['void'], 'SplStack::serialize' => ['string'], 'SplStack::setIteratorMode' => ['int', 'mode'=>'int'], 'SplStack::shift' => ['mixed'], 'SplStack::top' => ['mixed'], 'SplStack::unserialize' => ['void', 'data'=>'string'], 'SplStack::unshift' => ['void', 'value'=>'mixed'], 'SplStack::valid' => ['bool'], 'SplSubject::attach' => ['void', 'observer'=>'SplObserver'], 'SplSubject::detach' => ['void', 'observer'=>'SplObserver'], 'SplSubject::notify' => ['void'], 'SplTempFileObject::__construct' => ['void', 'maxMemory='=>'int'], 'SplTempFileObject::__toString' => ['string'], 'SplTempFileObject::current' => ['string|array|false'], 'SplTempFileObject::eof' => ['bool'], 'SplTempFileObject::fflush' => ['bool'], 'SplTempFileObject::fgetc' => ['string|false'], 'SplTempFileObject::fgetcsv' => ['list|array{0: null}|false', 'separator='=>'string', 'enclosure='=>'string', 'escape='=>'string'], 'SplTempFileObject::fgets' => ['string'], 'SplTempFileObject::flock' => ['bool', 'operation'=>'int', '&w_wouldBlock='=>'int'], 'SplTempFileObject::fpassthru' => ['int'], 'SplTempFileObject::fputcsv' => ['int|false', 'fields'=>'array', 'separator='=>'string', 'enclosure='=>'string', 'escape='=>'string', 'eol='=>'string'], 'SplTempFileObject::fread' => ['string|false', 'length'=>'int'], 'SplTempFileObject::fscanf' => ['array|int', 'format'=>'string', '&...w_vars='=>'string|int|float'], 'SplTempFileObject::fseek' => ['int', 'offset'=>'int', 'whence='=>'int'], 'SplTempFileObject::fstat' => ['array{0: int, 1: int, 2: int, 3: int, 4: int, 5: int, 6: int, 7: int, 8: int, 9: int, 10: int, 11: int, 12: int, dev: int, ino: int, mode: int, nlink: int, uid: int, gid: int, rdev: int, size: int, atime: int, mtime: int, ctime: int, blksize: int, blocks: int}'], 'SplTempFileObject::ftell' => ['int|false'], 'SplTempFileObject::ftruncate' => ['bool', 'size'=>'int'], 'SplTempFileObject::fwrite' => ['int|false', 'data'=>'string', 'length='=>'int'], 'SplTempFileObject::getATime' => ['int|false'], 'SplTempFileObject::getBasename' => ['string', 'suffix='=>'string'], 'SplTempFileObject::getChildren' => ['null'], 'SplTempFileObject::getCsvControl' => ['array'], 'SplTempFileObject::getCTime' => ['int|false'], 'SplTempFileObject::getCurrentLine' => ['string'], 'SplTempFileObject::getExtension' => ['string'], 'SplTempFileObject::getFileInfo' => ['SplFileInfo', 'class='=>'?class-string'], 'SplTempFileObject::getFilename' => ['string'], 'SplTempFileObject::getFlags' => ['int'], 'SplTempFileObject::getGroup' => ['int|false'], 'SplTempFileObject::getInode' => ['int|false'], 'SplTempFileObject::getLinkTarget' => ['string|false'], 'SplTempFileObject::getMaxLineLen' => ['int'], 'SplTempFileObject::getMTime' => ['int|false'], 'SplTempFileObject::getOwner' => ['int|false'], 'SplTempFileObject::getPath' => ['string'], 'SplTempFileObject::getPathInfo' => ['SplFileInfo|null', 'class='=>'?class-string'], 'SplTempFileObject::getPathname' => ['string'], 'SplTempFileObject::getPerms' => ['int|false'], 'SplTempFileObject::getRealPath' => ['false|non-falsy-string'], 'SplTempFileObject::getSize' => ['int|false'], 'SplTempFileObject::getType' => ['string|false'], 'SplTempFileObject::hasChildren' => ['false'], 'SplTempFileObject::isDir' => ['bool'], 'SplTempFileObject::isExecutable' => ['bool'], 'SplTempFileObject::isFile' => ['bool'], 'SplTempFileObject::isLink' => ['bool'], 'SplTempFileObject::isReadable' => ['bool'], 'SplTempFileObject::isWritable' => ['bool'], 'SplTempFileObject::key' => ['int'], 'SplTempFileObject::next' => ['void'], 'SplTempFileObject::openFile' => ['SplTempFileObject', 'mode='=>'string', 'useIncludePath='=>'bool', 'context='=>'?resource'], 'SplTempFileObject::rewind' => ['void'], 'SplTempFileObject::seek' => ['void', 'line'=>'int'], 'SplTempFileObject::setCsvControl' => ['void', 'separator='=>'string', 'enclosure='=>'string', 'escape='=>'string'], 'SplTempFileObject::setFileClass' => ['void', 'class='=>'class-string'], 'SplTempFileObject::setFlags' => ['void', 'flags'=>'int'], 'SplTempFileObject::setInfoClass' => ['void', 'class='=>'class-string'], 'SplTempFileObject::setMaxLineLen' => ['void', 'maxLength'=>'int'], 'SplTempFileObject::valid' => ['bool'], 'SplType::__construct' => ['void', 'initial_value='=>'mixed', 'strict='=>'bool'], 'Spoofchecker::__construct' => ['void'], 'Spoofchecker::areConfusable' => ['bool', 'string1'=>'string', 'string2'=>'string', '&w_errorCode='=>'int'], 'Spoofchecker::isSuspicious' => ['bool', 'string'=>'string', '&w_errorCode='=>'int'], 'Spoofchecker::setAllowedLocales' => ['void', 'locales'=>'string'], 'Spoofchecker::setChecks' => ['void', 'checks'=>'int'], 'Spoofchecker::setRestrictionLevel' => ['void', 'level'=>'int'], 'sprintf' => ['string', 'format'=>'string', '...values='=>'string|int|float'], 'SQLite3::__construct' => ['void', 'filename'=>'string', 'flags='=>'int', 'encryptionKey='=>'string'], 'SQLite3::busyTimeout' => ['bool', 'milliseconds'=>'int'], 'SQLite3::changes' => ['int'], 'SQLite3::close' => ['bool'], 'SQLite3::createAggregate' => ['bool', 'name'=>'string', 'stepCallback'=>'callable', 'finalCallback'=>'callable', 'argCount='=>'int'], 'SQLite3::createCollation' => ['bool', 'name'=>'string', 'callback'=>'callable'], 'SQLite3::createFunction' => ['bool', 'name'=>'string', 'callback'=>'callable', 'argCount='=>'int', 'flags='=>'int'], 'SQLite3::enableExceptions' => ['bool', 'enable='=>'bool'], 'SQLite3::escapeString' => ['string', 'string'=>'string'], 'SQLite3::exec' => ['bool', 'query'=>'string'], 'SQLite3::lastErrorCode' => ['int'], 'SQLite3::lastErrorMsg' => ['string'], 'SQLite3::lastInsertRowID' => ['int'], 'SQLite3::loadExtension' => ['bool', 'name'=>'string'], 'SQLite3::open' => ['void', 'filename'=>'string', 'flags='=>'int', 'encryptionKey='=>'string'], 'SQLite3::openBlob' => ['resource|false', 'table'=>'string', 'column'=>'string', 'rowid'=>'int', 'database='=>'string', 'flags='=>'int'], 'SQLite3::prepare' => ['SQLite3Stmt|false', 'query'=>'string'], 'SQLite3::query' => ['SQLite3Result|false', 'query'=>'string'], 'SQLite3::querySingle' => ['array|int|string|bool|float|null|false', 'query'=>'string', 'entireRow='=>'bool'], 'SQLite3::version' => ['array'], 'SQLite3Result::__construct' => ['void'], 'SQLite3Result::columnName' => ['string', 'column'=>'int'], 'SQLite3Result::columnType' => ['int', 'column'=>'int'], 'SQLite3Result::fetchArray' => ['array|false', 'mode='=>'int'], 'SQLite3Result::finalize' => ['bool'], 'SQLite3Result::numColumns' => ['int'], 'SQLite3Result::reset' => ['bool'], 'SQLite3Stmt::__construct' => ['void', 'sqlite3'=>'sqlite3', 'query'=>'string'], 'SQLite3Stmt::bindParam' => ['bool', 'param'=>'string|int', '&rw_var'=>'mixed', 'type='=>'int'], 'SQLite3Stmt::bindValue' => ['bool', 'param'=>'string|int', 'value'=>'mixed', 'type='=>'int'], 'SQLite3Stmt::clear' => ['bool'], 'SQLite3Stmt::close' => ['bool'], 'SQLite3Stmt::execute' => ['false|SQLite3Result'], 'SQLite3Stmt::getSQL' => ['string', 'expand='=>'bool'], 'SQLite3Stmt::paramCount' => ['int'], 'SQLite3Stmt::readOnly' => ['bool'], 'SQLite3Stmt::reset' => ['bool'], 'sqlite_array_query' => ['array|false', 'dbhandle'=>'resource', 'query'=>'string', 'result_type='=>'int', 'decode_binary='=>'bool'], 'sqlite_busy_timeout' => ['void', 'dbhandle'=>'resource', 'milliseconds'=>'int'], 'sqlite_changes' => ['int', 'dbhandle'=>'resource'], 'sqlite_close' => ['void', 'dbhandle'=>'resource'], 'sqlite_column' => ['mixed', 'result'=>'resource', 'index_or_name'=>'mixed', 'decode_binary='=>'bool'], 'sqlite_create_aggregate' => ['void', 'dbhandle'=>'resource', 'function_name'=>'string', 'step_func'=>'callable', 'finalize_func'=>'callable', 'num_args='=>'int'], 'sqlite_create_function' => ['void', 'dbhandle'=>'resource', 'function_name'=>'string', 'callback'=>'callable', 'num_args='=>'int'], 'sqlite_current' => ['array|false', 'result'=>'resource', 'result_type='=>'int', 'decode_binary='=>'bool'], 'sqlite_error_string' => ['string', 'error_code'=>'int'], 'sqlite_escape_string' => ['string', 'item'=>'string'], 'sqlite_exec' => ['bool', 'dbhandle'=>'resource', 'query'=>'string', 'error_msg='=>'string'], 'sqlite_factory' => ['SQLiteDatabase', 'filename'=>'string', 'mode='=>'int', 'error_message='=>'string'], 'sqlite_fetch_all' => ['array', 'result'=>'resource', 'result_type='=>'int', 'decode_binary='=>'bool'], 'sqlite_fetch_array' => ['array|false', 'result'=>'resource', 'result_type='=>'int', 'decode_binary='=>'bool'], 'sqlite_fetch_column_types' => ['array|false', 'table_name'=>'string', 'dbhandle'=>'resource', 'result_type='=>'int'], 'sqlite_fetch_object' => ['object', 'result'=>'resource', 'class_name='=>'string', 'ctor_params='=>'array', 'decode_binary='=>'bool'], 'sqlite_fetch_single' => ['string', 'result'=>'resource', 'decode_binary='=>'bool'], 'sqlite_fetch_string' => ['string', 'result'=>'resource', 'decode_binary'=>'bool'], 'sqlite_field_name' => ['string', 'result'=>'resource', 'field_index'=>'int'], 'sqlite_has_more' => ['bool', 'result'=>'resource'], 'sqlite_has_prev' => ['bool', 'result'=>'resource'], 'sqlite_key' => ['int', 'result'=>'resource'], 'sqlite_last_error' => ['int', 'dbhandle'=>'resource'], 'sqlite_last_insert_rowid' => ['int', 'dbhandle'=>'resource'], 'sqlite_libencoding' => ['string'], 'sqlite_libversion' => ['string'], 'sqlite_next' => ['bool', 'result'=>'resource'], 'sqlite_num_fields' => ['int', 'result'=>'resource'], 'sqlite_num_rows' => ['int', 'result'=>'resource'], 'sqlite_open' => ['resource|false', 'filename'=>'string', 'mode='=>'int', 'error_message='=>'string'], 'sqlite_popen' => ['resource|false', 'filename'=>'string', 'mode='=>'int', 'error_message='=>'string'], 'sqlite_prev' => ['bool', 'result'=>'resource'], 'sqlite_query' => ['resource|false', 'dbhandle'=>'resource', 'query'=>'resource|string', 'result_type='=>'int', 'error_msg='=>'string'], 'sqlite_rewind' => ['bool', 'result'=>'resource'], 'sqlite_seek' => ['bool', 'result'=>'resource', 'rownum'=>'int'], 'sqlite_single_query' => ['array', 'db'=>'resource', 'query'=>'string', 'first_row_only='=>'bool', 'decode_binary='=>'bool'], 'sqlite_udf_decode_binary' => ['string', 'data'=>'string'], 'sqlite_udf_encode_binary' => ['string', 'data'=>'string'], 'sqlite_unbuffered_query' => ['SQLiteUnbuffered|false', 'dbhandle'=>'resource', 'query'=>'string', 'result_type='=>'int', 'error_msg='=>'string'], 'sqlite_valid' => ['bool', 'result'=>'resource'], 'SQLiteDatabase::__construct' => ['void', 'filename'=>'', 'mode='=>'int|mixed', '&error_message'=>''], 'SQLiteDatabase::arrayQuery' => ['array', 'query'=>'string', 'result_type='=>'int', 'decode_binary='=>'bool'], 'SQLiteDatabase::busyTimeout' => ['int', 'milliseconds'=>'int'], 'SQLiteDatabase::changes' => ['int'], 'SQLiteDatabase::createAggregate' => ['', 'function_name'=>'string', 'step_func'=>'callable', 'finalize_func'=>'callable', 'num_args='=>'int'], 'SQLiteDatabase::createFunction' => ['', 'function_name'=>'string', 'callback'=>'callable', 'num_args='=>'int'], 'SQLiteDatabase::exec' => ['bool', 'query'=>'string', 'error_msg='=>'string'], 'SQLiteDatabase::fetchColumnTypes' => ['array', 'table_name'=>'string', 'result_type='=>'int'], 'SQLiteDatabase::lastError' => ['int'], 'SQLiteDatabase::lastInsertRowid' => ['int'], 'SQLiteDatabase::query' => ['SQLiteResult|false', 'query'=>'string', 'result_type='=>'int', 'error_msg='=>'string'], 'SQLiteDatabase::queryExec' => ['bool', 'query'=>'string', '&w_error_msg='=>'string'], 'SQLiteDatabase::singleQuery' => ['array', 'query'=>'string', 'first_row_only='=>'bool', 'decode_binary='=>'bool'], 'SQLiteDatabase::unbufferedQuery' => ['SQLiteUnbuffered|false', 'query'=>'string', 'result_type='=>'int', 'error_msg='=>'string'], 'SQLiteException::__clone' => ['void'], 'SQLiteException::__construct' => ['void', 'message'=>'', 'code'=>'', 'previous'=>''], 'SQLiteException::__toString' => ['string'], 'SQLiteException::__wakeup' => ['void'], 'SQLiteException::getCode' => ['int'], 'SQLiteException::getFile' => ['string'], 'SQLiteException::getLine' => ['int'], 'SQLiteException::getMessage' => ['string'], 'SQLiteException::getPrevious' => ['RuntimeException|Throwable|null'], 'SQLiteException::getTrace' => ['list\',args?:array}>'], 'SQLiteException::getTraceAsString' => ['string'], 'SQLiteResult::__construct' => ['void'], 'SQLiteResult::column' => ['mixed', 'index_or_name'=>'', 'decode_binary='=>'bool'], 'SQLiteResult::count' => ['int'], 'SQLiteResult::current' => ['array', 'result_type='=>'int', 'decode_binary='=>'bool'], 'SQLiteResult::fetch' => ['array', 'result_type='=>'int', 'decode_binary='=>'bool'], 'SQLiteResult::fetchAll' => ['array', 'result_type='=>'int', 'decode_binary='=>'bool'], 'SQLiteResult::fetchObject' => ['object', 'class_name='=>'string', 'ctor_params='=>'array', 'decode_binary='=>'bool'], 'SQLiteResult::fetchSingle' => ['string', 'decode_binary='=>'bool'], 'SQLiteResult::fieldName' => ['string', 'field_index'=>'int'], 'SQLiteResult::hasPrev' => ['bool'], 'SQLiteResult::key' => ['mixed|null'], 'SQLiteResult::next' => ['bool'], 'SQLiteResult::numFields' => ['int'], 'SQLiteResult::numRows' => ['int'], 'SQLiteResult::prev' => ['bool'], 'SQLiteResult::rewind' => ['bool'], 'SQLiteResult::seek' => ['bool', 'rownum'=>'int'], 'SQLiteResult::valid' => ['bool'], 'SQLiteUnbuffered::column' => ['void', 'index_or_name'=>'', 'decode_binary='=>'bool'], 'SQLiteUnbuffered::current' => ['array', 'result_type='=>'int', 'decode_binary='=>'bool'], 'SQLiteUnbuffered::fetch' => ['array', 'result_type='=>'int', 'decode_binary='=>'bool'], 'SQLiteUnbuffered::fetchAll' => ['array', 'result_type='=>'int', 'decode_binary='=>'bool'], 'SQLiteUnbuffered::fetchObject' => ['object', 'class_name='=>'string', 'ctor_params='=>'array', 'decode_binary='=>'bool'], 'SQLiteUnbuffered::fetchSingle' => ['string', 'decode_binary='=>'bool'], 'SQLiteUnbuffered::fieldName' => ['string', 'field_index'=>'int'], 'SQLiteUnbuffered::next' => ['bool'], 'SQLiteUnbuffered::numFields' => ['int'], 'SQLiteUnbuffered::valid' => ['bool'], 'sqlsrv_begin_transaction' => ['bool', 'conn'=>'resource'], 'sqlsrv_cancel' => ['bool', 'stmt'=>'resource'], 'sqlsrv_client_info' => ['array|false', 'conn'=>'resource'], 'sqlsrv_close' => ['bool', 'conn'=>'?resource'], 'sqlsrv_commit' => ['bool', 'conn'=>'resource'], 'sqlsrv_configure' => ['bool', 'setting'=>'string', 'value'=>'mixed'], 'sqlsrv_connect' => ['resource|false', 'server_name'=>'string', 'connection_info='=>'array'], 'sqlsrv_errors' => ['?array', 'errors_and_or_warnings='=>'int'], 'sqlsrv_execute' => ['bool', 'stmt'=>'resource'], 'sqlsrv_fetch' => ['?bool', 'stmt'=>'resource', 'row='=>'int', 'offset='=>'int'], 'sqlsrv_fetch_array' => ['array|null|false', 'stmt'=>'resource', 'fetchType='=>'int', 'row='=>'int', 'offset='=>'int'], 'sqlsrv_fetch_object' => ['object|null|false', 'stmt'=>'resource', 'className='=>'string', 'ctorParams='=>'array', 'row='=>'int', 'offset='=>'int'], 'sqlsrv_field_metadata' => ['array|false', 'stmt'=>'resource'], 'sqlsrv_free_stmt' => ['bool', 'stmt'=>'resource'], 'sqlsrv_get_config' => ['mixed', 'setting'=>'string'], 'sqlsrv_get_field' => ['mixed', 'stmt'=>'resource', 'fieldIndex'=>'int', 'getAsType='=>'int'], 'sqlsrv_has_rows' => ['bool', 'stmt'=>'resource'], 'sqlsrv_next_result' => ['?bool', 'stmt'=>'resource'], 'sqlsrv_num_fields' => ['int|false', 'stmt'=>'resource'], 'sqlsrv_num_rows' => ['int|false', 'stmt'=>'resource'], 'sqlsrv_prepare' => ['resource|false', 'conn'=>'resource', 'sql'=>'string', 'params='=>'array', 'options='=>'array'], 'sqlsrv_query' => ['resource|false', 'conn'=>'resource', 'sql'=>'string', 'params='=>'array', 'options='=>'array'], 'sqlsrv_rollback' => ['bool', 'conn'=>'resource'], 'sqlsrv_rows_affected' => ['int|false', 'stmt'=>'resource'], 'sqlsrv_send_stream_data' => ['bool', 'stmt'=>'resource'], 'sqlsrv_server_info' => ['array', 'conn'=>'resource'], 'sqrt' => ['float', 'num'=>'float'], 'srand' => ['void', 'seed='=>'?int', 'mode='=>'int'], 'sscanf' => ['list|int|null', 'string'=>'string', 'format'=>'string', '&...w_vars='=>'string|int|float|null'], 'ssdeep_fuzzy_compare' => ['int', 'signature1'=>'string', 'signature2'=>'string'], 'ssdeep_fuzzy_hash' => ['string', 'to_hash'=>'string'], 'ssdeep_fuzzy_hash_filename' => ['string', 'file_name'=>'string'], 'ssh2_auth_agent' => ['bool', 'session'=>'resource', 'username'=>'string'], 'ssh2_auth_hostbased_file' => ['bool', 'session'=>'resource', 'username'=>'string', 'hostname'=>'string', 'pubkeyfile'=>'string', 'privkeyfile'=>'string', 'passphrase='=>'string', 'local_username='=>'string'], 'ssh2_auth_none' => ['bool|string[]', 'session'=>'resource', 'username'=>'string'], 'ssh2_auth_password' => ['bool', 'session'=>'resource', 'username'=>'string', 'password'=>'string'], 'ssh2_auth_pubkey_file' => ['bool', 'session'=>'resource', 'username'=>'string', 'pubkeyfile'=>'string', 'privkeyfile'=>'string', 'passphrase='=>'string'], 'ssh2_connect' => ['resource|false', 'host'=>'string', 'port='=>'int', 'methods='=>'array', 'callbacks='=>'array'], 'ssh2_disconnect' => ['bool', 'session'=>'resource'], 'ssh2_exec' => ['resource|false', 'session'=>'resource', 'command'=>'string', 'pty='=>'string', 'env='=>'array', 'width='=>'int', 'height='=>'int', 'width_height_type='=>'int'], 'ssh2_fetch_stream' => ['resource|false', 'channel'=>'resource', 'streamid'=>'int'], 'ssh2_fingerprint' => ['string|false', 'session'=>'resource', 'flags='=>'int'], 'ssh2_forward_accept' => ['resource|false', 'listener'=>'resource'], 'ssh2_forward_listen' => ['resource|false', 'session'=>'resource', 'port'=>'int', 'host='=>'string', 'max_connections='=>'string'], 'ssh2_methods_negotiated' => ['array|false', 'session'=>'resource'], 'ssh2_poll' => ['int', '&polldes'=>'array', 'timeout='=>'int'], 'ssh2_publickey_add' => ['bool', 'pkey'=>'resource', 'algoname'=>'string', 'blob'=>'string', 'overwrite='=>'bool', 'attributes='=>'array'], 'ssh2_publickey_init' => ['resource|false', 'session'=>'resource'], 'ssh2_publickey_list' => ['array|false', 'pkey'=>'resource'], 'ssh2_publickey_remove' => ['bool', 'pkey'=>'resource', 'algoname'=>'string', 'blob'=>'string'], 'ssh2_scp_recv' => ['bool', 'session'=>'resource', 'remote_file'=>'string', 'local_file'=>'string'], 'ssh2_scp_send' => ['bool', 'session'=>'resource', 'local_file'=>'string', 'remote_file'=>'string', 'create_mode='=>'int'], 'ssh2_sftp' => ['resource|false', 'session'=>'resource'], 'ssh2_sftp_chmod' => ['bool', 'sftp'=>'resource', 'filename'=>'string', 'mode'=>'int'], 'ssh2_sftp_lstat' => ['array{0: int, 1: int, 2: int, 3: int, 4: int, 5: int, 6: int, 7: int, 8: int, 9: int, 10: int, 11: int, 12: int, dev: int, ino: int, mode: int, nlink: int, uid: int, gid: int, rdev: int, size: int, atime: int, mtime: int, ctime: int, blksize: int, blocks: int}|false', 'sftp'=>'resource', 'path'=>'string'], 'ssh2_sftp_mkdir' => ['bool', 'sftp'=>'resource', 'dirname'=>'string', 'mode='=>'int', 'recursive='=>'bool'], 'ssh2_sftp_readlink' => ['non-falsy-string|false', 'sftp'=>'resource', 'link'=>'string'], 'ssh2_sftp_realpath' => ['non-falsy-string|false', 'sftp'=>'resource', 'filename'=>'string'], 'ssh2_sftp_rename' => ['bool', 'sftp'=>'resource', 'from'=>'string', 'to'=>'string'], 'ssh2_sftp_rmdir' => ['bool', 'sftp'=>'resource', 'dirname'=>'string'], 'ssh2_sftp_stat' => ['array{0: int, 1: int, 2: int, 3: int, 4: int, 5: int, 6: int, 7: int, 8: int, 9: int, 10: int, 11: int, 12: int, dev: int, ino: int, mode: int, nlink: int, uid: int, gid: int, rdev: int, size: int, atime: int, mtime: int, ctime: int, blksize: int, blocks: int}|false', 'sftp'=>'resource', 'path'=>'string'], 'ssh2_sftp_symlink' => ['bool', 'sftp'=>'resource', 'target'=>'string', 'link'=>'string'], 'ssh2_sftp_unlink' => ['bool', 'sftp'=>'resource', 'filename'=>'string'], 'ssh2_shell' => ['resource|false', 'session'=>'resource', 'termtype='=>'string', 'env='=>'array', 'width='=>'int', 'height='=>'int', 'width_height_type='=>'int'], 'ssh2_tunnel' => ['resource|false', 'session'=>'resource', 'host'=>'string', 'port'=>'int'], 'stat' => ['array{0: int, 1: int, 2: int, 3: int, 4: int, 5: int, 6: int, 7: int, 8: int, 9: int, 10: int, 11: int, 12: int, dev: int, ino: int, mode: int, nlink: int, uid: int, gid: int, rdev: int, size: int, atime: int, mtime: int, ctime: int, blksize: int, blocks: int}|false', 'filename'=>'string'], 'stats_absolute_deviation' => ['float', 'a'=>'array'], 'stats_cdf_beta' => ['float', 'par1'=>'float', 'par2'=>'float', 'par3'=>'float', 'which'=>'int'], 'stats_cdf_binomial' => ['float', 'par1'=>'float', 'par2'=>'float', 'par3'=>'float', 'which'=>'int'], 'stats_cdf_cauchy' => ['float', 'par1'=>'float', 'par2'=>'float', 'par3'=>'float', 'which'=>'int'], 'stats_cdf_chisquare' => ['float', 'par1'=>'float', 'par2'=>'float', 'which'=>'int'], 'stats_cdf_exponential' => ['float', 'par1'=>'float', 'par2'=>'float', 'which'=>'int'], 'stats_cdf_f' => ['float', 'par1'=>'float', 'par2'=>'float', 'par3'=>'float', 'which'=>'int'], 'stats_cdf_gamma' => ['float', 'par1'=>'float', 'par2'=>'float', 'par3'=>'float', 'which'=>'int'], 'stats_cdf_laplace' => ['float', 'par1'=>'float', 'par2'=>'float', 'par3'=>'float', 'which'=>'int'], 'stats_cdf_logistic' => ['float', 'par1'=>'float', 'par2'=>'float', 'par3'=>'float', 'which'=>'int'], 'stats_cdf_negative_binomial' => ['float', 'par1'=>'float', 'par2'=>'float', 'par3'=>'float', 'which'=>'int'], 'stats_cdf_noncentral_chisquare' => ['float', 'par1'=>'float', 'par2'=>'float', 'par3'=>'float', 'which'=>'int'], 'stats_cdf_noncentral_f' => ['float', 'par1'=>'float', 'par2'=>'float', 'par3'=>'float', 'par4'=>'float', 'which'=>'int'], 'stats_cdf_noncentral_t' => ['float', 'par1'=>'float', 'par2'=>'float', 'par3'=>'float', 'which'=>'int'], 'stats_cdf_normal' => ['float', 'par1'=>'float', 'par2'=>'float', 'par3'=>'float', 'which'=>'int'], 'stats_cdf_poisson' => ['float', 'par1'=>'float', 'par2'=>'float', 'which'=>'int'], 'stats_cdf_t' => ['float', 'par1'=>'float', 'par2'=>'float', 'which'=>'int'], 'stats_cdf_uniform' => ['float', 'par1'=>'float', 'par2'=>'float', 'par3'=>'float', 'which'=>'int'], 'stats_cdf_weibull' => ['float', 'par1'=>'float', 'par2'=>'float', 'par3'=>'float', 'which'=>'int'], 'stats_covariance' => ['float', 'a'=>'array', 'b'=>'array'], 'stats_den_uniform' => ['float', 'x'=>'float', 'a'=>'float', 'b'=>'float'], 'stats_dens_beta' => ['float', 'x'=>'float', 'a'=>'float', 'b'=>'float'], 'stats_dens_cauchy' => ['float', 'x'=>'float', 'ave'=>'float', 'stdev'=>'float'], 'stats_dens_chisquare' => ['float', 'x'=>'float', 'dfr'=>'float'], 'stats_dens_exponential' => ['float', 'x'=>'float', 'scale'=>'float'], 'stats_dens_f' => ['float', 'x'=>'float', 'dfr1'=>'float', 'dfr2'=>'float'], 'stats_dens_gamma' => ['float', 'x'=>'float', 'shape'=>'float', 'scale'=>'float'], 'stats_dens_laplace' => ['float', 'x'=>'float', 'ave'=>'float', 'stdev'=>'float'], 'stats_dens_logistic' => ['float', 'x'=>'float', 'ave'=>'float', 'stdev'=>'float'], 'stats_dens_negative_binomial' => ['float', 'x'=>'float', 'n'=>'float', 'pi'=>'float'], 'stats_dens_normal' => ['float', 'x'=>'float', 'ave'=>'float', 'stdev'=>'float'], 'stats_dens_pmf_binomial' => ['float', 'x'=>'float', 'n'=>'float', 'pi'=>'float'], 'stats_dens_pmf_hypergeometric' => ['float', 'n1'=>'float', 'n2'=>'float', 'N1'=>'float', 'N2'=>'float'], 'stats_dens_pmf_negative_binomial' => ['float', 'x'=>'float', 'n'=>'float', 'pi'=>'float'], 'stats_dens_pmf_poisson' => ['float', 'x'=>'float', 'lb'=>'float'], 'stats_dens_t' => ['float', 'x'=>'float', 'dfr'=>'float'], 'stats_dens_uniform' => ['float', 'x'=>'float', 'a'=>'float', 'b'=>'float'], 'stats_dens_weibull' => ['float', 'x'=>'float', 'a'=>'float', 'b'=>'float'], 'stats_harmonic_mean' => ['float', 'a'=>'array'], 'stats_kurtosis' => ['float', 'a'=>'array'], 'stats_rand_gen_beta' => ['float', 'a'=>'float', 'b'=>'float'], 'stats_rand_gen_chisquare' => ['float', 'df'=>'float'], 'stats_rand_gen_exponential' => ['float', 'av'=>'float'], 'stats_rand_gen_f' => ['float', 'dfn'=>'float', 'dfd'=>'float'], 'stats_rand_gen_funiform' => ['float', 'low'=>'float', 'high'=>'float'], 'stats_rand_gen_gamma' => ['float', 'a'=>'float', 'r'=>'float'], 'stats_rand_gen_ibinomial' => ['int', 'n'=>'int', 'pp'=>'float'], 'stats_rand_gen_ibinomial_negative' => ['int', 'n'=>'int', 'p'=>'float'], 'stats_rand_gen_int' => ['int'], 'stats_rand_gen_ipoisson' => ['int', 'mu'=>'float'], 'stats_rand_gen_iuniform' => ['int', 'low'=>'int', 'high'=>'int'], 'stats_rand_gen_noncenral_chisquare' => ['float', 'df'=>'float', 'xnonc'=>'float'], 'stats_rand_gen_noncentral_chisquare' => ['float', 'df'=>'float', 'xnonc'=>'float'], 'stats_rand_gen_noncentral_f' => ['float', 'dfn'=>'float', 'dfd'=>'float', 'xnonc'=>'float'], 'stats_rand_gen_noncentral_t' => ['float', 'df'=>'float', 'xnonc'=>'float'], 'stats_rand_gen_normal' => ['float', 'av'=>'float', 'sd'=>'float'], 'stats_rand_gen_t' => ['float', 'df'=>'float'], 'stats_rand_get_seeds' => ['array'], 'stats_rand_phrase_to_seeds' => ['array', 'phrase'=>'string'], 'stats_rand_ranf' => ['float'], 'stats_rand_setall' => ['void', 'iseed1'=>'int', 'iseed2'=>'int'], 'stats_skew' => ['float', 'a'=>'array'], 'stats_standard_deviation' => ['float', 'a'=>'array', 'sample='=>'bool'], 'stats_stat_binomial_coef' => ['float', 'x'=>'int', 'n'=>'int'], 'stats_stat_correlation' => ['float', 'array1'=>'array', 'array2'=>'array'], 'stats_stat_factorial' => ['float', 'n'=>'int'], 'stats_stat_gennch' => ['float', 'n'=>'int'], 'stats_stat_independent_t' => ['float', 'array1'=>'array', 'array2'=>'array'], 'stats_stat_innerproduct' => ['float', 'array1'=>'array', 'array2'=>'array'], 'stats_stat_noncentral_t' => ['float', 'par1'=>'float', 'par2'=>'float', 'par3'=>'float', 'which'=>'int'], 'stats_stat_paired_t' => ['float', 'array1'=>'array', 'array2'=>'array'], 'stats_stat_percentile' => ['float', 'arr'=>'array', 'perc'=>'float'], 'stats_stat_powersum' => ['float', 'arr'=>'array', 'power'=>'float'], 'stats_variance' => ['float', 'a'=>'array', 'sample='=>'bool'], 'Stomp::__construct' => ['void', 'broker='=>'string', 'username='=>'string', 'password='=>'string', 'headers='=>'?array'], 'Stomp::abort' => ['bool', 'transaction_id'=>'string', 'headers='=>'?array'], 'Stomp::ack' => ['bool', 'msg'=>'', 'headers='=>'?array'], 'Stomp::begin' => ['bool', 'transaction_id'=>'string', 'headers='=>'?array'], 'Stomp::commit' => ['bool', 'transaction_id'=>'string', 'headers='=>'?array'], 'Stomp::error' => ['string'], 'Stomp::getReadTimeout' => ['array'], 'Stomp::getSessionId' => ['string'], 'Stomp::hasFrame' => ['bool'], 'Stomp::readFrame' => ['array', 'class_name='=>'string'], 'Stomp::send' => ['bool', 'destination'=>'string', 'msg'=>'', 'headers='=>'?array'], 'Stomp::setReadTimeout' => ['void', 'seconds'=>'int', 'microseconds='=>'?int'], 'Stomp::subscribe' => ['bool', 'destination'=>'string', 'headers='=>'?array'], 'Stomp::unsubscribe' => ['bool', 'destination'=>'string', 'headers='=>'?array'], 'stomp_abort' => ['bool', 'link'=>'resource', 'transaction_id'=>'string', 'headers='=>'?array'], 'stomp_ack' => ['bool', 'link'=>'resource', 'msg'=>'', 'headers='=>'?array'], 'stomp_begin' => ['bool', 'link'=>'resource', 'transaction_id'=>'string', 'headers='=>'?array'], 'stomp_close' => ['bool', 'link'=>'resource'], 'stomp_commit' => ['bool', 'link'=>'resource', 'transaction_id'=>'string', 'headers='=>'?array'], 'stomp_connect' => ['resource', 'link'=>'resource', 'broker='=>'string', 'username='=>'string', 'password='=>'string', 'headers='=>'?array'], 'stomp_connect_error' => ['string'], 'stomp_error' => ['string', 'link'=>'resource'], 'stomp_get_read_timeout' => ['array', 'link'=>'resource'], 'stomp_get_session_id' => ['string', 'link'=>'resource'], 'stomp_has_frame' => ['bool', 'link'=>'resource'], 'stomp_read_frame' => ['array', 'link'=>'resource', 'class_name='=>'string'], 'stomp_send' => ['bool', 'link'=>'resource', 'destination'=>'string', 'msg'=>'', 'headers='=>'?array'], 'stomp_set_read_timeout' => ['void', 'link'=>'resource', 'seconds'=>'int', 'microseconds='=>'?int'], 'stomp_subscribe' => ['bool', 'link'=>'resource', 'destination'=>'string', 'headers='=>'?array'], 'stomp_unsubscribe' => ['bool', 'link'=>'resource', 'destination'=>'string', 'headers='=>'?array'], 'stomp_version' => ['string'], 'StompException::getDetails' => ['string'], 'StompFrame::__construct' => ['void', 'command='=>'string', 'headers='=>'?array', 'body='=>'string'], 'str_contains' => ['bool', 'haystack'=>'string', 'needle'=>'string'], 'str_ends_with' => ['bool', 'haystack'=>'string', 'needle'=>'string'], 'str_getcsv' => ['non-empty-list', 'string'=>'string', 'separator='=>'string', 'enclosure='=>'string', 'escape='=>'string'], 'str_ireplace' => ['string', 'search'=>'string', 'replace'=>'string', 'subject'=>'string', '&w_count='=>'int'], 'str_ireplace\'1' => ['string[]', 'search'=>'string', 'replace'=>'string', 'subject'=>'array', '&w_count='=>'int'], 'str_ireplace\'2' => ['string', 'search'=>'array', 'replace'=>'string|string[]', 'subject'=>'string', '&w_count='=>'int'], 'str_ireplace\'3' => ['string[]', 'search'=>'array', 'replace'=>'string|string[]', 'subject'=>'array', '&w_count='=>'int'], 'str_pad' => ['string', 'string'=>'string', 'length'=>'int', 'pad_string='=>'string', 'pad_type='=>'int'], 'str_repeat' => ['string', 'string'=>'string', 'times'=>'int'], 'str_replace' => ['string', 'search'=>'string', 'replace'=>'string', 'subject'=>'string', '&w_count='=>'int'], 'str_replace\'1' => ['string[]', 'search'=>'string', 'replace'=>'string', 'subject'=>'array', '&w_count='=>'int'], 'str_replace\'2' => ['string', 'search'=>'array', 'replace'=>'string|string[]', 'subject'=>'string', '&w_count='=>'int'], 'str_replace\'3' => ['string[]', 'search'=>'array', 'replace'=>'string|string[]', 'subject'=>'array', '&w_count='=>'int'], 'str_rot13' => ['string', 'string'=>'string'], 'str_shuffle' => ['string', 'string'=>'string'], 'str_split' => ['list', 'string'=>'string', 'length='=>'positive-int'], 'str_starts_with' => ['bool', 'haystack'=>'string', 'needle'=>'string'], 'str_word_count' => ['array|int', 'string'=>'string', 'format='=>'int', 'characters='=>'?string'], 'strcasecmp' => ['int<-1,1>', 'string1'=>'string', 'string2'=>'string'], 'strchr' => ['string|false', 'haystack'=>'string', 'needle'=>'string', 'before_needle='=>'bool'], 'strcmp' => ['int<-1,1>', 'string1'=>'string', 'string2'=>'string'], 'strcoll' => ['int', 'string1'=>'string', 'string2'=>'string'], 'strcspn' => ['int', 'string'=>'string', 'characters'=>'string', 'offset='=>'int', 'length='=>'?int'], 'stream_bucket_append' => ['void', 'brigade'=>'resource', 'bucket'=>'object'], 'stream_bucket_make_writeable' => ['?object', 'brigade'=>'resource'], 'stream_bucket_new' => ['object', 'stream'=>'resource', 'buffer'=>'string'], 'stream_bucket_prepend' => ['void', 'brigade'=>'resource', 'bucket'=>'object'], 'stream_context_create' => ['resource', 'options='=>'?array', 'params='=>'?array'], 'stream_context_get_default' => ['resource', 'options='=>'?array'], 'stream_context_get_options' => ['array', 'stream_or_context'=>'resource'], 'stream_context_get_params' => ['array{notification:string,options:array}', 'context'=>'resource'], 'stream_context_set_default' => ['resource', 'options'=>'array'], 'stream_context_set_option' => ['bool', 'context'=>'', 'wrapper_or_options'=>'string', 'option_name'=>'string', 'value'=>''], 'stream_context_set_option\'1' => ['bool', 'context'=>'', 'wrapper_or_options'=>'array'], 'stream_context_set_params' => ['bool', 'context'=>'resource', 'params'=>'array'], 'stream_copy_to_stream' => ['int|false', 'from'=>'resource', 'to'=>'resource', 'length='=>'?int', 'offset='=>'int'], 'stream_encoding' => ['bool', 'stream'=>'resource', 'encoding='=>'string'], 'stream_filter_append' => ['resource|false', 'stream'=>'resource', 'filter_name'=>'string', 'mode='=>'int', 'params='=>'mixed'], 'stream_filter_prepend' => ['resource|false', 'stream'=>'resource', 'filter_name'=>'string', 'mode='=>'int', 'params='=>'mixed'], 'stream_filter_register' => ['bool', 'filter_name'=>'string', 'class'=>'string'], 'stream_filter_remove' => ['bool', 'stream_filter'=>'resource'], 'stream_get_contents' => ['string|false', 'stream'=>'resource', 'length='=>'?int', 'offset='=>'int'], 'stream_get_filters' => ['array'], 'stream_get_line' => ['string|false', 'stream'=>'resource', 'length'=>'int', 'ending='=>'string'], 'stream_get_meta_data' => ['array{timed_out:bool,blocked:bool,eof:bool,unread_bytes:int,stream_type:string,wrapper_type:string,wrapper_data:mixed,mode:string,seekable:bool,uri:string,mediatype:string,crypto?:array{protocol:string,cipher_name:string,cipher_bits:int,cipher_version:string}}', 'stream'=>'resource'], 'stream_get_transports' => ['list'], 'stream_get_wrappers' => ['list'], 'stream_is_local' => ['bool', 'stream'=>'resource|string'], 'stream_isatty' => ['bool', 'stream'=>'resource'], 'stream_notification_callback' => ['callback', 'notification_code'=>'int', 'severity'=>'int', 'message'=>'string', 'message_code'=>'int', 'bytes_transferred'=>'int', 'bytes_max'=>'int'], 'stream_register_wrapper' => ['bool', 'protocol'=>'string', 'class'=>'string', 'flags='=>'int'], 'stream_resolve_include_path' => ['string|false', 'filename'=>'string'], 'stream_select' => ['int|false', '&rw_read'=>'?resource[]', '&rw_write'=>'?resource[]', '&rw_except'=>'?resource[]', 'seconds'=>'?int', 'microseconds='=>'?int'], 'stream_set_blocking' => ['bool', 'stream'=>'resource', 'enable'=>'bool'], 'stream_set_chunk_size' => ['int', 'stream'=>'resource', 'size'=>'int'], 'stream_set_read_buffer' => ['int', 'stream'=>'resource', 'size'=>'int'], 'stream_set_timeout' => ['bool', 'stream'=>'resource', 'seconds'=>'int', 'microseconds='=>'int'], 'stream_set_write_buffer' => ['int', 'stream'=>'resource', 'size'=>'int'], 'stream_socket_accept' => ['resource|false', 'socket'=>'resource', 'timeout='=>'?float', '&w_peer_name='=>'string'], 'stream_socket_client' => ['resource|false', 'address'=>'string', '&w_error_code='=>'int', '&w_error_message='=>'string', 'timeout='=>'?float', 'flags='=>'int', 'context='=>'?resource'], 'stream_socket_enable_crypto' => ['int|bool', 'stream'=>'resource', 'enable'=>'bool', 'crypto_method='=>'?int', 'session_stream='=>'?resource'], 'stream_socket_get_name' => ['string|false', 'socket'=>'resource', 'remote'=>'bool'], 'stream_socket_pair' => ['resource[]|false', 'domain'=>'int', 'type'=>'int', 'protocol'=>'int'], 'stream_socket_recvfrom' => ['string|false', 'socket'=>'resource', 'length'=>'int', 'flags='=>'int', '&w_address='=>'string'], 'stream_socket_sendto' => ['int|false', 'socket'=>'resource', 'data'=>'string', 'flags='=>'int', 'address='=>'string'], 'stream_socket_server' => ['resource|false', 'address'=>'string', '&w_error_code='=>'int', '&w_error_message='=>'string', 'flags='=>'int', 'context='=>'resource'], 'stream_socket_shutdown' => ['bool', 'stream'=>'resource', 'mode'=>'int'], 'stream_supports_lock' => ['bool', 'stream'=>'resource'], 'stream_wrapper_register' => ['bool', 'protocol'=>'string', 'class'=>'string', 'flags='=>'int'], 'stream_wrapper_restore' => ['bool', 'protocol'=>'string'], 'stream_wrapper_unregister' => ['bool', 'protocol'=>'string'], 'streamWrapper::__construct' => ['void'], 'streamWrapper::__destruct' => ['void'], 'streamWrapper::dir_closedir' => ['bool'], 'streamWrapper::dir_opendir' => ['bool', 'path'=>'string', 'options'=>'int'], 'streamWrapper::dir_readdir' => ['string'], 'streamWrapper::dir_rewinddir' => ['bool'], 'streamWrapper::mkdir' => ['bool', 'path'=>'string', 'mode'=>'int', 'options'=>'int'], 'streamWrapper::rename' => ['bool', 'path_from'=>'string', 'path_to'=>'string'], 'streamWrapper::rmdir' => ['bool', 'path'=>'string', 'options'=>'int'], 'streamWrapper::stream_cast' => ['resource', 'cast_as'=>'int'], 'streamWrapper::stream_close' => ['void'], 'streamWrapper::stream_eof' => ['bool'], 'streamWrapper::stream_flush' => ['bool'], 'streamWrapper::stream_lock' => ['bool', 'operation'=>'mode'], 'streamWrapper::stream_metadata' => ['bool', 'path'=>'string', 'option'=>'int', 'value'=>'mixed'], 'streamWrapper::stream_open' => ['bool', 'path'=>'string', 'mode'=>'string', 'options'=>'int', 'opened_path'=>'string'], 'streamWrapper::stream_read' => ['string', 'count'=>'int'], 'streamWrapper::stream_seek' => ['bool', 'offset'=>'int', 'whence'=>'int'], 'streamWrapper::stream_set_option' => ['bool', 'option'=>'int', 'arg1'=>'int', 'arg2'=>'int'], 'streamWrapper::stream_stat' => ['array'], 'streamWrapper::stream_tell' => ['int'], 'streamWrapper::stream_truncate' => ['bool', 'new_size'=>'int'], 'streamWrapper::stream_write' => ['int', 'data'=>'string'], 'streamWrapper::unlink' => ['bool', 'path'=>'string'], 'streamWrapper::url_stat' => ['array', 'path'=>'string', 'flags'=>'int'], 'strftime' => ['string|false', 'format'=>'string', 'timestamp='=>'?int'], 'strip_tags' => ['string', 'string'=>'string', 'allowed_tags='=>'string|list|null'], 'stripcslashes' => ['string', 'string'=>'string'], 'stripos' => ['int|false', 'haystack'=>'string', 'needle'=>'string', 'offset='=>'int'], 'stripslashes' => ['string', 'string'=>'string'], 'stristr' => ['string|false', 'haystack'=>'string', 'needle'=>'string', 'before_needle='=>'bool'], 'strlen' => ['0|positive-int', 'string'=>'string'], 'strnatcasecmp' => ['int<-1,1>', 'string1'=>'string', 'string2'=>'string'], 'strnatcmp' => ['int<-1,1>', 'string1'=>'string', 'string2'=>'string'], 'strncasecmp' => ['int<-1,1>', 'string1'=>'string', 'string2'=>'string', 'length'=>'positive-int|0'], 'strncmp' => ['int<-1,1>', 'string1'=>'string', 'string2'=>'string', 'length'=>'positive-int|0'], 'strpbrk' => ['string|false', 'string'=>'string', 'characters'=>'string'], 'strpos' => ['int|false', 'haystack'=>'string', 'needle'=>'string', 'offset='=>'int'], 'strptime' => ['array|false', 'timestamp'=>'string', 'format'=>'string'], 'strrchr' => ['string|false', 'haystack'=>'string', 'needle'=>'string', 'before_needle='=>'bool'], 'strrev' => ['string', 'string'=>'string'], 'strripos' => ['int|false', 'haystack'=>'string', 'needle'=>'string', 'offset='=>'int'], 'strrpos' => ['int|false', 'haystack'=>'string', 'needle'=>'string', 'offset='=>'int'], 'strspn' => ['int', 'string'=>'string', 'characters'=>'string', 'offset='=>'int', 'length='=>'?int'], 'strstr' => ['string|false', 'haystack'=>'string', 'needle'=>'string', 'before_needle='=>'bool'], 'strtok' => ['non-empty-string|false', 'string'=>'string', 'token'=>'string'], 'strtok\'1' => ['non-empty-string|false', 'string'=>'string'], 'strtolower' => ['lowercase-string', 'string'=>'string'], 'strtotime' => ['int|false', 'datetime'=>'string', 'baseTimestamp='=>'?int'], 'strtoupper' => ['string', 'string'=>'string'], 'strtr' => ['string', 'string'=>'string', 'from'=>'string', 'to'=>'string'], 'strtr\'1' => ['string', 'string'=>'string', 'from'=>'array'], 'strval' => ['string', 'value'=>'mixed'], 'styleObj::__construct' => ['void', 'label'=>'labelObj', 'style'=>'styleObj'], 'styleObj::convertToString' => ['string'], 'styleObj::free' => ['void'], 'styleObj::getBinding' => ['string', 'stylebinding'=>'mixed'], 'styleObj::getGeomTransform' => ['string'], 'styleObj::ms_newStyleObj' => ['styleObj', 'class'=>'classObj', 'style'=>'styleObj'], 'styleObj::removeBinding' => ['int', 'stylebinding'=>'mixed'], 'styleObj::set' => ['int', 'property_name'=>'string', 'new_value'=>''], 'styleObj::setBinding' => ['int', 'stylebinding'=>'mixed', 'value'=>'string'], 'styleObj::setGeomTransform' => ['int', 'value'=>'string'], 'styleObj::updateFromString' => ['int', 'snippet'=>'string'], 'substr' => ['string', 'string'=>'string', 'offset'=>'int', 'length='=>'?int'], 'substr_compare' => ['int', 'haystack'=>'string', 'needle'=>'string', 'offset'=>'int', 'length='=>'?int', 'case_insensitive='=>'bool'], 'substr_count' => ['int', 'haystack'=>'string', 'needle'=>'string', 'offset='=>'int', 'length='=>'?int'], 'substr_replace' => ['string', 'string'=>'string', 'replace'=>'string|string[]', 'offset'=>'int|int[]', 'length='=>'int|int[]|null'], 'substr_replace\'1' => ['string[]', 'string'=>'string[]', 'replace'=>'string|string[]', 'offset'=>'int|int[]', 'length='=>'int|int[]|null'], 'suhosin_encrypt_cookie' => ['string|false', 'name'=>'string', 'value'=>'string'], 'suhosin_get_raw_cookies' => ['array'], 'SVM::__construct' => ['void'], 'svm::crossvalidate' => ['float', 'problem'=>'array', 'number_of_folds'=>'int'], 'SVM::getOptions' => ['array'], 'SVM::setOptions' => ['bool', 'params'=>'array'], 'svm::train' => ['SVMModel', 'problem'=>'array', 'weights='=>'array'], 'SVMModel::__construct' => ['void', 'filename='=>'string'], 'SVMModel::checkProbabilityModel' => ['bool'], 'SVMModel::getLabels' => ['array'], 'SVMModel::getNrClass' => ['int'], 'SVMModel::getSvmType' => ['int'], 'SVMModel::getSvrProbability' => ['float'], 'SVMModel::load' => ['bool', 'filename'=>'string'], 'SVMModel::predict' => ['float', 'data'=>'array'], 'SVMModel::predict_probability' => ['float', 'data'=>'array'], 'SVMModel::save' => ['bool', 'filename'=>'string'], 'svn_add' => ['bool', 'path'=>'string', 'recursive='=>'bool', 'force='=>'bool'], 'svn_auth_get_parameter' => ['?string', 'key'=>'string'], 'svn_auth_set_parameter' => ['void', 'key'=>'string', 'value'=>'string'], 'svn_blame' => ['array', 'repository_url'=>'string', 'revision_no='=>'int'], 'svn_cat' => ['string', 'repos_url'=>'string', 'revision_no='=>'int'], 'svn_checkout' => ['bool', 'repos'=>'string', 'targetpath'=>'string', 'revision='=>'int', 'flags='=>'int'], 'svn_cleanup' => ['bool', 'workingdir'=>'string'], 'svn_client_version' => ['string'], 'svn_commit' => ['array', 'log'=>'string', 'targets'=>'array', 'dontrecurse='=>'bool'], 'svn_delete' => ['bool', 'path'=>'string', 'force='=>'bool'], 'svn_diff' => ['array', 'path1'=>'string', 'rev1'=>'int', 'path2'=>'string', 'rev2'=>'int'], 'svn_export' => ['bool', 'frompath'=>'string', 'topath'=>'string', 'working_copy='=>'bool', 'revision_no='=>'int'], 'svn_fs_abort_txn' => ['bool', 'txn'=>'resource'], 'svn_fs_apply_text' => ['resource', 'root'=>'resource', 'path'=>'string'], 'svn_fs_begin_txn2' => ['resource', 'repos'=>'resource', 'rev'=>'int'], 'svn_fs_change_node_prop' => ['bool', 'root'=>'resource', 'path'=>'string', 'name'=>'string', 'value'=>'string'], 'svn_fs_check_path' => ['int', 'fsroot'=>'resource', 'path'=>'string'], 'svn_fs_contents_changed' => ['bool', 'root1'=>'resource', 'path1'=>'string', 'root2'=>'resource', 'path2'=>'string'], 'svn_fs_copy' => ['bool', 'from_root'=>'resource', 'from_path'=>'string', 'to_root'=>'resource', 'to_path'=>'string'], 'svn_fs_delete' => ['bool', 'root'=>'resource', 'path'=>'string'], 'svn_fs_dir_entries' => ['array', 'fsroot'=>'resource', 'path'=>'string'], 'svn_fs_file_contents' => ['resource', 'fsroot'=>'resource', 'path'=>'string'], 'svn_fs_file_length' => ['int', 'fsroot'=>'resource', 'path'=>'string'], 'svn_fs_is_dir' => ['bool', 'root'=>'resource', 'path'=>'string'], 'svn_fs_is_file' => ['bool', 'root'=>'resource', 'path'=>'string'], 'svn_fs_make_dir' => ['bool', 'root'=>'resource', 'path'=>'string'], 'svn_fs_make_file' => ['bool', 'root'=>'resource', 'path'=>'string'], 'svn_fs_node_created_rev' => ['int', 'fsroot'=>'resource', 'path'=>'string'], 'svn_fs_node_prop' => ['string', 'fsroot'=>'resource', 'path'=>'string', 'propname'=>'string'], 'svn_fs_props_changed' => ['bool', 'root1'=>'resource', 'path1'=>'string', 'root2'=>'resource', 'path2'=>'string'], 'svn_fs_revision_prop' => ['string', 'fs'=>'resource', 'revnum'=>'int', 'propname'=>'string'], 'svn_fs_revision_root' => ['resource', 'fs'=>'resource', 'revnum'=>'int'], 'svn_fs_txn_root' => ['resource', 'txn'=>'resource'], 'svn_fs_youngest_rev' => ['int', 'fs'=>'resource'], 'svn_import' => ['bool', 'path'=>'string', 'url'=>'string', 'nonrecursive'=>'bool'], 'svn_log' => ['array', 'repos_url'=>'string', 'start_revision='=>'int', 'end_revision='=>'int', 'limit='=>'int', 'flags='=>'int'], 'svn_ls' => ['array', 'repos_url'=>'string', 'revision_no='=>'int', 'recurse='=>'bool', 'peg='=>'bool'], 'svn_mkdir' => ['bool', 'path'=>'string', 'log_message='=>'string'], 'svn_move' => ['mixed', 'src_path'=>'string', 'dst_path'=>'string', 'force='=>'bool'], 'svn_propget' => ['mixed', 'path'=>'string', 'property_name'=>'string', 'recurse='=>'bool', 'revision'=>'int'], 'svn_proplist' => ['mixed', 'path'=>'string', 'recurse='=>'bool', 'revision'=>'int'], 'svn_repos_create' => ['resource', 'path'=>'string', 'config='=>'array', 'fsconfig='=>'array'], 'svn_repos_fs' => ['resource', 'repos'=>'resource'], 'svn_repos_fs_begin_txn_for_commit' => ['resource', 'repos'=>'resource', 'rev'=>'int', 'author'=>'string', 'log_msg'=>'string'], 'svn_repos_fs_commit_txn' => ['int', 'txn'=>'resource'], 'svn_repos_hotcopy' => ['bool', 'repospath'=>'string', 'destpath'=>'string', 'cleanlogs'=>'bool'], 'svn_repos_open' => ['resource', 'path'=>'string'], 'svn_repos_recover' => ['bool', 'path'=>'string'], 'svn_revert' => ['bool', 'path'=>'string', 'recursive='=>'bool'], 'svn_status' => ['array', 'path'=>'string', 'flags='=>'int'], 'svn_update' => ['int|false', 'path'=>'string', 'revno='=>'int', 'recurse='=>'bool'], 'swf_actiongeturl' => ['', 'url'=>'string', 'target'=>'string'], 'swf_actiongotoframe' => ['', 'framenumber'=>'int'], 'swf_actiongotolabel' => ['', 'label'=>'string'], 'swf_actionnextframe' => [''], 'swf_actionplay' => [''], 'swf_actionprevframe' => [''], 'swf_actionsettarget' => ['', 'target'=>'string'], 'swf_actionstop' => [''], 'swf_actiontogglequality' => [''], 'swf_actionwaitforframe' => ['', 'framenumber'=>'int', 'skipcount'=>'int'], 'swf_addbuttonrecord' => ['', 'states'=>'int', 'shapeid'=>'int', 'depth'=>'int'], 'swf_addcolor' => ['', 'r'=>'float', 'g'=>'float', 'b'=>'float', 'a'=>'float'], 'swf_closefile' => ['', 'return_file='=>'int'], 'swf_definebitmap' => ['', 'objid'=>'int', 'image_name'=>'string'], 'swf_definefont' => ['', 'fontid'=>'int', 'fontname'=>'string'], 'swf_defineline' => ['', 'objid'=>'int', 'x1'=>'float', 'y1'=>'float', 'x2'=>'float', 'y2'=>'float', 'width'=>'float'], 'swf_definepoly' => ['', 'objid'=>'int', 'coords'=>'array', 'npoints'=>'int', 'width'=>'float'], 'swf_definerect' => ['', 'objid'=>'int', 'x1'=>'float', 'y1'=>'float', 'x2'=>'float', 'y2'=>'float', 'width'=>'float'], 'swf_definetext' => ['', 'objid'=>'int', 'string'=>'string', 'docenter'=>'int'], 'swf_endbutton' => [''], 'swf_enddoaction' => [''], 'swf_endshape' => [''], 'swf_endsymbol' => [''], 'swf_fontsize' => ['', 'size'=>'float'], 'swf_fontslant' => ['', 'slant'=>'float'], 'swf_fonttracking' => ['', 'tracking'=>'float'], 'swf_getbitmapinfo' => ['array', 'bitmapid'=>'int'], 'swf_getfontinfo' => ['array'], 'swf_getframe' => ['int'], 'swf_labelframe' => ['', 'name'=>'string'], 'swf_lookat' => ['', 'view_x'=>'float', 'view_y'=>'float', 'view_z'=>'float', 'reference_x'=>'float', 'reference_y'=>'float', 'reference_z'=>'float', 'twist'=>'float'], 'swf_modifyobject' => ['', 'depth'=>'int', 'how'=>'int'], 'swf_mulcolor' => ['', 'r'=>'float', 'g'=>'float', 'b'=>'float', 'a'=>'float'], 'swf_nextid' => ['int'], 'swf_oncondition' => ['', 'transition'=>'int'], 'swf_openfile' => ['', 'filename'=>'string', 'width'=>'float', 'height'=>'float', 'framerate'=>'float', 'r'=>'float', 'g'=>'float', 'b'=>'float'], 'swf_ortho' => ['', 'xmin'=>'float', 'xmax'=>'float', 'ymin'=>'float', 'ymax'=>'float', 'zmin'=>'float', 'zmax'=>'float'], 'swf_ortho2' => ['', 'xmin'=>'float', 'xmax'=>'float', 'ymin'=>'float', 'ymax'=>'float'], 'swf_perspective' => ['', 'fovy'=>'float', 'aspect'=>'float', 'near'=>'float', 'far'=>'float'], 'swf_placeobject' => ['', 'objid'=>'int', 'depth'=>'int'], 'swf_polarview' => ['', 'dist'=>'float', 'azimuth'=>'float', 'incidence'=>'float', 'twist'=>'float'], 'swf_popmatrix' => [''], 'swf_posround' => ['', 'round'=>'int'], 'swf_pushmatrix' => [''], 'swf_removeobject' => ['', 'depth'=>'int'], 'swf_rotate' => ['', 'angle'=>'float', 'axis'=>'string'], 'swf_scale' => ['', 'x'=>'float', 'y'=>'float', 'z'=>'float'], 'swf_setfont' => ['', 'fontid'=>'int'], 'swf_setframe' => ['', 'framenumber'=>'int'], 'swf_shapearc' => ['', 'x'=>'float', 'y'=>'float', 'r'=>'float', 'ang1'=>'float', 'ang2'=>'float'], 'swf_shapecurveto' => ['', 'x1'=>'float', 'y1'=>'float', 'x2'=>'float', 'y2'=>'float'], 'swf_shapecurveto3' => ['', 'x1'=>'float', 'y1'=>'float', 'x2'=>'float', 'y2'=>'float', 'x3'=>'float', 'y3'=>'float'], 'swf_shapefillbitmapclip' => ['', 'bitmapid'=>'int'], 'swf_shapefillbitmaptile' => ['', 'bitmapid'=>'int'], 'swf_shapefilloff' => [''], 'swf_shapefillsolid' => ['', 'r'=>'float', 'g'=>'float', 'b'=>'float', 'a'=>'float'], 'swf_shapelinesolid' => ['', 'r'=>'float', 'g'=>'float', 'b'=>'float', 'a'=>'float', 'width'=>'float'], 'swf_shapelineto' => ['', 'x'=>'float', 'y'=>'float'], 'swf_shapemoveto' => ['', 'x'=>'float', 'y'=>'float'], 'swf_showframe' => [''], 'swf_startbutton' => ['', 'objid'=>'int', 'type'=>'int'], 'swf_startdoaction' => [''], 'swf_startshape' => ['', 'objid'=>'int'], 'swf_startsymbol' => ['', 'objid'=>'int'], 'swf_textwidth' => ['float', 'string'=>'string'], 'swf_translate' => ['', 'x'=>'float', 'y'=>'float', 'z'=>'float'], 'swf_viewport' => ['', 'xmin'=>'float', 'xmax'=>'float', 'ymin'=>'float', 'ymax'=>'float'], 'SWFAction::__construct' => ['void', 'script'=>'string'], 'SWFBitmap::__construct' => ['void', 'file'=>'', 'alphafile='=>''], 'SWFBitmap::getHeight' => ['float'], 'SWFBitmap::getWidth' => ['float'], 'SWFButton::__construct' => ['void'], 'SWFButton::addAction' => ['void', 'action'=>'swfaction', 'flags'=>'int'], 'SWFButton::addASound' => ['SWFSoundInstance', 'sound'=>'swfsound', 'flags'=>'int'], 'SWFButton::addShape' => ['void', 'shape'=>'swfshape', 'flags'=>'int'], 'SWFButton::setAction' => ['void', 'action'=>'swfaction'], 'SWFButton::setDown' => ['void', 'shape'=>'swfshape'], 'SWFButton::setHit' => ['void', 'shape'=>'swfshape'], 'SWFButton::setMenu' => ['void', 'flag'=>'int'], 'SWFButton::setOver' => ['void', 'shape'=>'swfshape'], 'SWFButton::setUp' => ['void', 'shape'=>'swfshape'], 'SWFDisplayItem::addAction' => ['void', 'action'=>'swfaction', 'flags'=>'int'], 'SWFDisplayItem::addColor' => ['void', 'red'=>'int', 'green'=>'int', 'blue'=>'int', 'a='=>'int'], 'SWFDisplayItem::endMask' => ['void'], 'SWFDisplayItem::getRot' => ['float'], 'SWFDisplayItem::getX' => ['float'], 'SWFDisplayItem::getXScale' => ['float'], 'SWFDisplayItem::getXSkew' => ['float'], 'SWFDisplayItem::getY' => ['float'], 'SWFDisplayItem::getYScale' => ['float'], 'SWFDisplayItem::getYSkew' => ['float'], 'SWFDisplayItem::move' => ['void', 'dx'=>'float', 'dy'=>'float'], 'SWFDisplayItem::moveTo' => ['void', 'x'=>'float', 'y'=>'float'], 'SWFDisplayItem::multColor' => ['void', 'red'=>'float', 'green'=>'float', 'blue'=>'float', 'a='=>'float'], 'SWFDisplayItem::remove' => ['void'], 'SWFDisplayItem::rotate' => ['void', 'angle'=>'float'], 'SWFDisplayItem::rotateTo' => ['void', 'angle'=>'float'], 'SWFDisplayItem::scale' => ['void', 'dx'=>'float', 'dy'=>'float'], 'SWFDisplayItem::scaleTo' => ['void', 'x'=>'float', 'y='=>'float'], 'SWFDisplayItem::setDepth' => ['void', 'depth'=>'int'], 'SWFDisplayItem::setMaskLevel' => ['void', 'level'=>'int'], 'SWFDisplayItem::setMatrix' => ['void', 'a'=>'float', 'b'=>'float', 'c'=>'float', 'd'=>'float', 'x'=>'float', 'y'=>'float'], 'SWFDisplayItem::setName' => ['void', 'name'=>'string'], 'SWFDisplayItem::setRatio' => ['void', 'ratio'=>'float'], 'SWFDisplayItem::skewX' => ['void', 'ddegrees'=>'float'], 'SWFDisplayItem::skewXTo' => ['void', 'degrees'=>'float'], 'SWFDisplayItem::skewY' => ['void', 'ddegrees'=>'float'], 'SWFDisplayItem::skewYTo' => ['void', 'degrees'=>'float'], 'SWFFill::moveTo' => ['void', 'x'=>'float', 'y'=>'float'], 'SWFFill::rotateTo' => ['void', 'angle'=>'float'], 'SWFFill::scaleTo' => ['void', 'x'=>'float', 'y='=>'float'], 'SWFFill::skewXTo' => ['void', 'x'=>'float'], 'SWFFill::skewYTo' => ['void', 'y'=>'float'], 'SWFFont::__construct' => ['void', 'filename'=>'string'], 'SWFFont::getAscent' => ['float'], 'SWFFont::getDescent' => ['float'], 'SWFFont::getLeading' => ['float'], 'SWFFont::getShape' => ['string', 'code'=>'int'], 'SWFFont::getUTF8Width' => ['float', 'string'=>'string'], 'SWFFont::getWidth' => ['float', 'string'=>'string'], 'SWFFontChar::addChars' => ['void', 'char'=>'string'], 'SWFFontChar::addUTF8Chars' => ['void', 'char'=>'string'], 'SWFGradient::__construct' => ['void'], 'SWFGradient::addEntry' => ['void', 'ratio'=>'float', 'red'=>'int', 'green'=>'int', 'blue'=>'int', 'alpha='=>'int'], 'SWFMorph::__construct' => ['void'], 'SWFMorph::getShape1' => ['SWFShape'], 'SWFMorph::getShape2' => ['SWFShape'], 'SWFMovie::__construct' => ['void', 'version='=>'int'], 'SWFMovie::add' => ['mixed', 'instance'=>'object'], 'SWFMovie::addExport' => ['void', 'char'=>'swfcharacter', 'name'=>'string'], 'SWFMovie::addFont' => ['mixed', 'font'=>'swffont'], 'SWFMovie::importChar' => ['SWFSprite', 'libswf'=>'string', 'name'=>'string'], 'SWFMovie::importFont' => ['SWFFontChar', 'libswf'=>'string', 'name'=>'string'], 'SWFMovie::labelFrame' => ['void', 'label'=>'string'], 'SWFMovie::namedAnchor' => [''], 'SWFMovie::nextFrame' => ['void'], 'SWFMovie::output' => ['int', 'compression='=>'int'], 'SWFMovie::protect' => [''], 'SWFMovie::remove' => ['void', 'instance'=>'object'], 'SWFMovie::save' => ['int', 'filename'=>'string', 'compression='=>'int'], 'SWFMovie::saveToFile' => ['int', 'x'=>'resource', 'compression='=>'int'], 'SWFMovie::setbackground' => ['void', 'red'=>'int', 'green'=>'int', 'blue'=>'int'], 'SWFMovie::setDimension' => ['void', 'width'=>'float', 'height'=>'float'], 'SWFMovie::setFrames' => ['void', 'number'=>'int'], 'SWFMovie::setRate' => ['void', 'rate'=>'float'], 'SWFMovie::startSound' => ['SWFSoundInstance', 'sound'=>'swfsound'], 'SWFMovie::stopSound' => ['void', 'sound'=>'swfsound'], 'SWFMovie::streamMP3' => ['int', 'mp3file'=>'mixed', 'skip='=>'float'], 'SWFMovie::writeExports' => ['void'], 'SWFPrebuiltClip::__construct' => ['void', 'file'=>''], 'SWFShape::__construct' => ['void'], 'SWFShape::addFill' => ['SWFFill', 'red'=>'int', 'green'=>'int', 'blue'=>'int', 'alpha='=>'int', 'bitmap='=>'swfbitmap', 'flags='=>'int', 'gradient='=>'swfgradient'], 'SWFShape::addFill\'1' => ['SWFFill', 'bitmap'=>'SWFBitmap', 'flags='=>'int'], 'SWFShape::addFill\'2' => ['SWFFill', 'gradient'=>'SWFGradient', 'flags='=>'int'], 'SWFShape::drawArc' => ['void', 'r'=>'float', 'startangle'=>'float', 'endangle'=>'float'], 'SWFShape::drawCircle' => ['void', 'r'=>'float'], 'SWFShape::drawCubic' => ['int', 'bx'=>'float', 'by'=>'float', 'cx'=>'float', 'cy'=>'float', 'dx'=>'float', 'dy'=>'float'], 'SWFShape::drawCubicTo' => ['int', 'bx'=>'float', 'by'=>'float', 'cx'=>'float', 'cy'=>'float', 'dx'=>'float', 'dy'=>'float'], 'SWFShape::drawCurve' => ['int', 'controldx'=>'float', 'controldy'=>'float', 'anchordx'=>'float', 'anchordy'=>'float', 'targetdx='=>'float', 'targetdy='=>'float'], 'SWFShape::drawCurveTo' => ['int', 'controlx'=>'float', 'controly'=>'float', 'anchorx'=>'float', 'anchory'=>'float', 'targetx='=>'float', 'targety='=>'float'], 'SWFShape::drawGlyph' => ['void', 'font'=>'swffont', 'character'=>'string', 'size='=>'int'], 'SWFShape::drawLine' => ['void', 'dx'=>'float', 'dy'=>'float'], 'SWFShape::drawLineTo' => ['void', 'x'=>'float', 'y'=>'float'], 'SWFShape::movePen' => ['void', 'dx'=>'float', 'dy'=>'float'], 'SWFShape::movePenTo' => ['void', 'x'=>'float', 'y'=>'float'], 'SWFShape::setLeftFill' => ['', 'fill'=>'swfgradient', 'red'=>'int', 'green'=>'int', 'blue'=>'int', 'a='=>'int'], 'SWFShape::setLine' => ['', 'shape'=>'swfshape', 'width'=>'int', 'red'=>'int', 'green'=>'int', 'blue'=>'int', 'a='=>'int'], 'SWFShape::setRightFill' => ['', 'fill'=>'swfgradient', 'red'=>'int', 'green'=>'int', 'blue'=>'int', 'a='=>'int'], 'SWFSound' => ['SWFSound', 'filename'=>'string', 'flags='=>'int'], 'SWFSound::__construct' => ['void', 'filename'=>'string', 'flags='=>'int'], 'SWFSoundInstance::loopCount' => ['void', 'point'=>'int'], 'SWFSoundInstance::loopInPoint' => ['void', 'point'=>'int'], 'SWFSoundInstance::loopOutPoint' => ['void', 'point'=>'int'], 'SWFSoundInstance::noMultiple' => ['void'], 'SWFSprite::__construct' => ['void'], 'SWFSprite::add' => ['void', 'object'=>'object'], 'SWFSprite::labelFrame' => ['void', 'label'=>'string'], 'SWFSprite::nextFrame' => ['void'], 'SWFSprite::remove' => ['void', 'object'=>'object'], 'SWFSprite::setFrames' => ['void', 'number'=>'int'], 'SWFSprite::startSound' => ['SWFSoundInstance', 'sount'=>'swfsound'], 'SWFSprite::stopSound' => ['void', 'sount'=>'swfsound'], 'SWFText::__construct' => ['void'], 'SWFText::addString' => ['void', 'string'=>'string'], 'SWFText::addUTF8String' => ['void', 'text'=>'string'], 'SWFText::getAscent' => ['float'], 'SWFText::getDescent' => ['float'], 'SWFText::getLeading' => ['float'], 'SWFText::getUTF8Width' => ['float', 'string'=>'string'], 'SWFText::getWidth' => ['float', 'string'=>'string'], 'SWFText::moveTo' => ['void', 'x'=>'float', 'y'=>'float'], 'SWFText::setColor' => ['void', 'red'=>'int', 'green'=>'int', 'blue'=>'int', 'a='=>'int'], 'SWFText::setFont' => ['void', 'font'=>'swffont'], 'SWFText::setHeight' => ['void', 'height'=>'float'], 'SWFText::setSpacing' => ['void', 'spacing'=>'float'], 'SWFTextField::__construct' => ['void', 'flags='=>'int'], 'SWFTextField::addChars' => ['void', 'chars'=>'string'], 'SWFTextField::addString' => ['void', 'string'=>'string'], 'SWFTextField::align' => ['void', 'alignement'=>'int'], 'SWFTextField::setBounds' => ['void', 'width'=>'float', 'height'=>'float'], 'SWFTextField::setColor' => ['void', 'red'=>'int', 'green'=>'int', 'blue'=>'int', 'a='=>'int'], 'SWFTextField::setFont' => ['void', 'font'=>'swffont'], 'SWFTextField::setHeight' => ['void', 'height'=>'float'], 'SWFTextField::setIndentation' => ['void', 'width'=>'float'], 'SWFTextField::setLeftMargin' => ['void', 'width'=>'float'], 'SWFTextField::setLineSpacing' => ['void', 'height'=>'float'], 'SWFTextField::setMargins' => ['void', 'left'=>'float', 'right'=>'float'], 'SWFTextField::setName' => ['void', 'name'=>'string'], 'SWFTextField::setPadding' => ['void', 'padding'=>'float'], 'SWFTextField::setRightMargin' => ['void', 'width'=>'float'], 'SWFVideoStream::__construct' => ['void', 'file='=>'string'], 'SWFVideoStream::getNumFrames' => ['int'], 'SWFVideoStream::setDimension' => ['void', 'x'=>'int', 'y'=>'int'], 'Swish::__construct' => ['void', 'index_names'=>'string'], 'Swish::getMetaList' => ['array', 'index_name'=>'string'], 'Swish::getPropertyList' => ['array', 'index_name'=>'string'], 'Swish::prepare' => ['object', 'query='=>'string'], 'Swish::query' => ['object', 'query'=>'string'], 'SwishResult::getMetaList' => ['array'], 'SwishResult::stem' => ['array', 'word'=>'string'], 'SwishResults::getParsedWords' => ['array', 'index_name'=>'string'], 'SwishResults::getRemovedStopwords' => ['array', 'index_name'=>'string'], 'SwishResults::nextResult' => ['object'], 'SwishResults::seekResult' => ['int', 'position'=>'int'], 'SwishSearch::execute' => ['object', 'query='=>'string'], 'SwishSearch::resetLimit' => [''], 'SwishSearch::setLimit' => ['', 'property'=>'string', 'low'=>'string', 'high'=>'string'], 'SwishSearch::setPhraseDelimiter' => ['', 'delimiter'=>'string'], 'SwishSearch::setSort' => ['', 'sort'=>'string'], 'SwishSearch::setStructure' => ['', 'structure'=>'int'], 'swoole\async::dnsLookup' => ['void', 'hostname'=>'string', 'callback'=>'callable'], 'swoole\async::read' => ['bool', 'filename'=>'string', 'callback'=>'callable', 'chunk_size='=>'integer', 'offset='=>'integer'], 'swoole\async::readFile' => ['void', 'filename'=>'string', 'callback'=>'callable'], 'swoole\async::set' => ['void', 'settings'=>'array'], 'swoole\async::write' => ['void', 'filename'=>'string', 'content'=>'string', 'offset='=>'integer', 'callback='=>'callable'], 'swoole\async::writeFile' => ['void', 'filename'=>'string', 'content'=>'string', 'callback='=>'callable', 'flags='=>'string'], 'swoole\atomic::add' => ['integer', 'add_value='=>'integer'], 'swoole\atomic::cmpset' => ['integer', 'cmp_value'=>'integer', 'new_value'=>'integer'], 'swoole\atomic::get' => ['integer'], 'swoole\atomic::set' => ['integer', 'value'=>'integer'], 'swoole\atomic::sub' => ['integer', 'sub_value='=>'integer'], 'swoole\buffer::__destruct' => ['void'], 'swoole\buffer::__toString' => ['string'], 'swoole\buffer::append' => ['integer', 'data'=>'string'], 'swoole\buffer::clear' => ['void'], 'swoole\buffer::expand' => ['integer', 'size'=>'integer'], 'swoole\buffer::read' => ['string', 'offset'=>'integer', 'length'=>'integer'], 'swoole\buffer::recycle' => ['void'], 'swoole\buffer::substr' => ['string', 'offset'=>'integer', 'length='=>'integer', 'remove='=>'bool'], 'swoole\buffer::write' => ['void', 'offset'=>'integer', 'data'=>'string'], 'swoole\channel::__destruct' => ['void'], 'swoole\channel::pop' => ['mixed'], 'swoole\channel::push' => ['bool', 'data'=>'string'], 'swoole\channel::stats' => ['array'], 'swoole\client::__destruct' => ['void'], 'swoole\client::close' => ['bool', 'force='=>'bool'], 'swoole\client::connect' => ['bool', 'host'=>'string', 'port='=>'integer', 'timeout='=>'integer', 'flag='=>'integer'], 'swoole\client::getpeername' => ['array'], 'swoole\client::getsockname' => ['array'], 'swoole\client::isConnected' => ['bool'], 'swoole\client::on' => ['void', 'event'=>'string', 'callback'=>'callable'], 'swoole\client::pause' => ['void'], 'swoole\client::pipe' => ['void', 'socket'=>'string'], 'swoole\client::recv' => ['void', 'size='=>'string', 'flag='=>'string'], 'swoole\client::resume' => ['void'], 'swoole\client::send' => ['integer', 'data'=>'string', 'flag='=>'string'], 'swoole\client::sendfile' => ['bool', 'filename'=>'string', 'offset='=>'int'], 'swoole\client::sendto' => ['bool', 'ip'=>'string', 'port'=>'integer', 'data'=>'string'], 'swoole\client::set' => ['void', 'settings'=>'array'], 'swoole\client::sleep' => ['void'], 'swoole\client::wakeup' => ['void'], 'swoole\connection\iterator::count' => ['int'], 'swoole\connection\iterator::current' => ['Connection'], 'swoole\connection\iterator::key' => ['int'], 'swoole\connection\iterator::next' => ['Connection'], 'swoole\connection\iterator::offsetExists' => ['bool', 'index'=>'int'], 'swoole\connection\iterator::offsetGet' => ['Connection', 'index'=>'string'], 'swoole\connection\iterator::offsetSet' => ['void', 'offset'=>'int', 'connection'=>'mixed'], 'swoole\connection\iterator::offsetUnset' => ['void', 'offset'=>'int'], 'swoole\connection\iterator::rewind' => ['void'], 'swoole\connection\iterator::valid' => ['bool'], 'swoole\coroutine::call_user_func' => ['mixed', 'callback'=>'callable', 'parameter='=>'mixed', '...args='=>'mixed'], 'swoole\coroutine::call_user_func_array' => ['mixed', 'callback'=>'callable', 'param_array'=>'array'], 'swoole\coroutine::cli_wait' => ['ReturnType'], 'swoole\coroutine::create' => ['ReturnType'], 'swoole\coroutine::getuid' => ['ReturnType'], 'swoole\coroutine::resume' => ['ReturnType'], 'swoole\coroutine::suspend' => ['ReturnType'], 'swoole\coroutine\client::__destruct' => ['ReturnType'], 'swoole\coroutine\client::close' => ['ReturnType'], 'swoole\coroutine\client::connect' => ['ReturnType'], 'swoole\coroutine\client::getpeername' => ['ReturnType'], 'swoole\coroutine\client::getsockname' => ['ReturnType'], 'swoole\coroutine\client::isConnected' => ['ReturnType'], 'swoole\coroutine\client::recv' => ['ReturnType'], 'swoole\coroutine\client::send' => ['ReturnType'], 'swoole\coroutine\client::sendfile' => ['ReturnType'], 'swoole\coroutine\client::sendto' => ['ReturnType'], 'swoole\coroutine\client::set' => ['ReturnType'], 'swoole\coroutine\http\client::__destruct' => ['ReturnType'], 'swoole\coroutine\http\client::addFile' => ['ReturnType'], 'swoole\coroutine\http\client::close' => ['ReturnType'], 'swoole\coroutine\http\client::execute' => ['ReturnType'], 'swoole\coroutine\http\client::get' => ['ReturnType'], 'swoole\coroutine\http\client::getDefer' => ['ReturnType'], 'swoole\coroutine\http\client::isConnected' => ['ReturnType'], 'swoole\coroutine\http\client::post' => ['ReturnType'], 'swoole\coroutine\http\client::recv' => ['ReturnType'], 'swoole\coroutine\http\client::set' => ['ReturnType'], 'swoole\coroutine\http\client::setCookies' => ['ReturnType'], 'swoole\coroutine\http\client::setData' => ['ReturnType'], 'swoole\coroutine\http\client::setDefer' => ['ReturnType'], 'swoole\coroutine\http\client::setHeaders' => ['ReturnType'], 'swoole\coroutine\http\client::setMethod' => ['ReturnType'], 'swoole\coroutine\mysql::__destruct' => ['ReturnType'], 'swoole\coroutine\mysql::close' => ['ReturnType'], 'swoole\coroutine\mysql::connect' => ['ReturnType'], 'swoole\coroutine\mysql::getDefer' => ['ReturnType'], 'swoole\coroutine\mysql::query' => ['ReturnType'], 'swoole\coroutine\mysql::recv' => ['ReturnType'], 'swoole\coroutine\mysql::setDefer' => ['ReturnType'], 'swoole\event::add' => ['bool', 'fd'=>'int', 'read_callback'=>'callable', 'write_callback='=>'callable', 'events='=>'string'], 'swoole\event::defer' => ['void', 'callback'=>'mixed'], 'swoole\event::del' => ['bool', 'fd'=>'string'], 'swoole\event::exit' => ['void'], 'swoole\event::set' => ['bool', 'fd'=>'int', 'read_callback='=>'string', 'write_callback='=>'string', 'events='=>'string'], 'swoole\event::wait' => ['void'], 'swoole\event::write' => ['void', 'fd'=>'string', 'data'=>'string'], 'swoole\http\client::__destruct' => ['void'], 'swoole\http\client::addFile' => ['void', 'path'=>'string', 'name'=>'string', 'type='=>'string', 'filename='=>'string', 'offset='=>'string'], 'swoole\http\client::close' => ['void'], 'swoole\http\client::download' => ['void', 'path'=>'string', 'file'=>'string', 'callback'=>'callable', 'offset='=>'integer'], 'swoole\http\client::execute' => ['void', 'path'=>'string', 'callback'=>'string'], 'swoole\http\client::get' => ['void', 'path'=>'string', 'callback'=>'callable'], 'swoole\http\client::isConnected' => ['bool'], 'swoole\http\client::on' => ['void', 'event_name'=>'string', 'callback'=>'callable'], 'swoole\http\client::post' => ['void', 'path'=>'string', 'data'=>'string', 'callback'=>'callable'], 'swoole\http\client::push' => ['void', 'data'=>'string', 'opcode='=>'string', 'finish='=>'string'], 'swoole\http\client::set' => ['void', 'settings'=>'array'], 'swoole\http\client::setCookies' => ['void', 'cookies'=>'array'], 'swoole\http\client::setData' => ['ReturnType', 'data'=>'string'], 'swoole\http\client::setHeaders' => ['void', 'headers'=>'array'], 'swoole\http\client::setMethod' => ['void', 'method'=>'string'], 'swoole\http\client::upgrade' => ['void', 'path'=>'string', 'callback'=>'string'], 'swoole\http\request::__destruct' => ['void'], 'swoole\http\request::rawcontent' => ['string'], 'swoole\http\response::__destruct' => ['void'], 'swoole\http\response::cookie' => ['string', 'name'=>'string', 'value='=>'string', 'expires='=>'string', 'path='=>'string', 'domain='=>'string', 'secure='=>'string', 'httponly='=>'string'], 'swoole\http\response::end' => ['void', 'content='=>'string'], 'swoole\http\response::gzip' => ['ReturnType', 'compress_level='=>'string'], 'swoole\http\response::header' => ['void', 'key'=>'string', 'value'=>'string', 'ucwords='=>'string'], 'swoole\http\response::initHeader' => ['ReturnType'], 'swoole\http\response::rawcookie' => ['ReturnType', 'name'=>'string', 'value='=>'string', 'expires='=>'string', 'path='=>'string', 'domain='=>'string', 'secure='=>'string', 'httponly='=>'string'], 'swoole\http\response::sendfile' => ['ReturnType', 'filename'=>'string', 'offset='=>'int'], 'swoole\http\response::status' => ['ReturnType', 'http_code'=>'string'], 'swoole\http\response::write' => ['void', 'content'=>'string'], 'swoole\http\server::on' => ['void', 'event_name'=>'string', 'callback'=>'callable'], 'swoole\http\server::start' => ['void'], 'swoole\lock::__destruct' => ['void'], 'swoole\lock::lock' => ['void'], 'swoole\lock::lock_read' => ['void'], 'swoole\lock::trylock' => ['void'], 'swoole\lock::trylock_read' => ['void'], 'swoole\lock::unlock' => ['void'], 'swoole\mmap::open' => ['ReturnType', 'filename'=>'string', 'size='=>'string', 'offset='=>'string'], 'swoole\mysql::__destruct' => ['void'], 'swoole\mysql::close' => ['void'], 'swoole\mysql::connect' => ['void', 'server_config'=>'array', 'callback'=>'callable'], 'swoole\mysql::getBuffer' => ['ReturnType'], 'swoole\mysql::on' => ['void', 'event_name'=>'string', 'callback'=>'callable'], 'swoole\mysql::query' => ['ReturnType', 'sql'=>'string', 'callback'=>'callable'], 'swoole\process::__destruct' => ['void'], 'swoole\process::alarm' => ['void', 'interval_usec'=>'integer'], 'swoole\process::close' => ['void'], 'swoole\process::daemon' => ['void', 'nochdir='=>'bool', 'noclose='=>'bool'], 'swoole\process::exec' => ['ReturnType', 'exec_file'=>'string', 'args'=>'string'], 'swoole\process::exit' => ['void', 'exit_code='=>'string'], 'swoole\process::freeQueue' => ['void'], 'swoole\process::kill' => ['void', 'pid'=>'integer', 'signal_no='=>'string'], 'swoole\process::name' => ['void', 'process_name'=>'string'], 'swoole\process::pop' => ['mixed', 'maxsize='=>'integer'], 'swoole\process::push' => ['bool', 'data'=>'string'], 'swoole\process::read' => ['string', 'maxsize='=>'integer'], 'swoole\process::signal' => ['void', 'signal_no'=>'string', 'callback'=>'callable'], 'swoole\process::start' => ['void'], 'swoole\process::statQueue' => ['array'], 'swoole\process::useQueue' => ['bool', 'key'=>'integer', 'mode='=>'integer'], 'swoole\process::wait' => ['array', 'blocking='=>'bool'], 'swoole\process::write' => ['integer', 'data'=>'string'], 'swoole\redis\server::format' => ['ReturnType', 'type'=>'string', 'value='=>'string'], 'swoole\redis\server::setHandler' => ['ReturnType', 'command'=>'string', 'callback'=>'string', 'number_of_string_param='=>'string', 'type_of_array_param='=>'string'], 'swoole\redis\server::start' => ['ReturnType'], 'swoole\serialize::pack' => ['ReturnType', 'data'=>'string', 'is_fast='=>'int'], 'swoole\serialize::unpack' => ['ReturnType', 'data'=>'string', 'args='=>'string'], 'swoole\server::addlistener' => ['void', 'host'=>'string', 'port'=>'integer', 'socket_type'=>'string'], 'swoole\server::addProcess' => ['bool', 'process'=>'swoole_process'], 'swoole\server::after' => ['ReturnType', 'after_time_ms'=>'integer', 'callback'=>'callable', 'param='=>'string'], 'swoole\server::bind' => ['bool', 'fd'=>'integer', 'uid'=>'integer'], 'swoole\server::close' => ['bool', 'fd'=>'integer', 'reset='=>'bool'], 'swoole\server::confirm' => ['bool', 'fd'=>'integer'], 'swoole\server::connection_info' => ['array', 'fd'=>'integer', 'reactor_id='=>'integer'], 'swoole\server::connection_list' => ['array', 'start_fd'=>'integer', 'pagesize='=>'integer'], 'swoole\server::defer' => ['void', 'callback'=>'callable'], 'swoole\server::exist' => ['bool', 'fd'=>'integer'], 'swoole\server::finish' => ['void', 'data'=>'string'], 'swoole\server::getClientInfo' => ['ReturnType', 'fd'=>'integer', 'reactor_id='=>'integer'], 'swoole\server::getClientList' => ['array', 'start_fd'=>'integer', 'pagesize='=>'integer'], 'swoole\server::getLastError' => ['integer'], 'swoole\server::heartbeat' => ['mixed', 'if_close_connection'=>'bool'], 'swoole\server::listen' => ['bool', 'host'=>'string', 'port'=>'integer', 'socket_type'=>'string'], 'swoole\server::on' => ['void', 'event_name'=>'string', 'callback'=>'callable'], 'swoole\server::pause' => ['void', 'fd'=>'integer'], 'swoole\server::protect' => ['void', 'fd'=>'integer', 'is_protected='=>'bool'], 'swoole\server::reload' => ['bool'], 'swoole\server::resume' => ['void', 'fd'=>'integer'], 'swoole\server::send' => ['bool', 'fd'=>'integer', 'data'=>'string', 'reactor_id='=>'integer'], 'swoole\server::sendfile' => ['bool', 'fd'=>'integer', 'filename'=>'string', 'offset='=>'integer'], 'swoole\server::sendMessage' => ['bool', 'worker_id'=>'integer', 'data'=>'string'], 'swoole\server::sendto' => ['bool', 'ip'=>'string', 'port'=>'integer', 'data'=>'string', 'server_socket='=>'string'], 'swoole\server::sendwait' => ['bool', 'fd'=>'integer', 'data'=>'string'], 'swoole\server::set' => ['ReturnType', 'settings'=>'array'], 'swoole\server::shutdown' => ['void'], 'swoole\server::start' => ['void'], 'swoole\server::stats' => ['array'], 'swoole\server::stop' => ['bool', 'worker_id='=>'integer'], 'swoole\server::task' => ['mixed', 'data'=>'string', 'dst_worker_id='=>'integer', 'callback='=>'callable'], 'swoole\server::taskwait' => ['void', 'data'=>'string', 'timeout='=>'float', 'worker_id='=>'integer'], 'swoole\server::taskWaitMulti' => ['void', 'tasks'=>'array', 'timeout_ms='=>'double'], 'swoole\server::tick' => ['void', 'interval_ms'=>'integer', 'callback'=>'callable'], 'swoole\server\port::__destruct' => ['void'], 'swoole\server\port::on' => ['ReturnType', 'event_name'=>'string', 'callback'=>'callable'], 'swoole\server\port::set' => ['void', 'settings'=>'array'], 'swoole\table::column' => ['ReturnType', 'name'=>'string', 'type'=>'string', 'size='=>'integer'], 'swoole\table::count' => ['integer'], 'swoole\table::create' => ['void'], 'swoole\table::current' => ['array'], 'swoole\table::decr' => ['ReturnType', 'key'=>'string', 'column'=>'string', 'decrby='=>'integer'], 'swoole\table::del' => ['void', 'key'=>'string'], 'swoole\table::destroy' => ['void'], 'swoole\table::exist' => ['bool', 'key'=>'string'], 'swoole\table::get' => ['integer', 'row_key'=>'string', 'column_key'=>'string'], 'swoole\table::incr' => ['void', 'key'=>'string', 'column'=>'string', 'incrby='=>'integer'], 'swoole\table::key' => ['string'], 'swoole\table::next' => ['ReturnType'], 'swoole\table::rewind' => ['void'], 'swoole\table::set' => ['VOID', 'key'=>'string', 'value'=>'array'], 'swoole\table::valid' => ['bool'], 'swoole\timer::after' => ['void', 'after_time_ms'=>'int', 'callback'=>'callable'], 'swoole\timer::clear' => ['void', 'timer_id'=>'integer'], 'swoole\timer::exists' => ['bool', 'timer_id'=>'integer'], 'swoole\timer::tick' => ['void', 'interval_ms'=>'integer', 'callback'=>'callable', 'param='=>'string'], 'swoole\websocket\server::exist' => ['bool', 'fd'=>'integer'], 'swoole\websocket\server::on' => ['ReturnType', 'event_name'=>'string', 'callback'=>'callable'], 'swoole\websocket\server::pack' => ['binary', 'data'=>'string', 'opcode='=>'string', 'finish='=>'string', 'mask='=>'string'], 'swoole\websocket\server::push' => ['void', 'fd'=>'string', 'data'=>'string', 'opcode='=>'string', 'finish='=>'string'], 'swoole\websocket\server::unpack' => ['string', 'data'=>'binary'], 'swoole_async_dns_lookup' => ['bool', 'hostname'=>'string', 'callback'=>'callable'], 'swoole_async_read' => ['bool', 'filename'=>'string', 'callback'=>'callable', 'chunk_size='=>'int', 'offset='=>'int'], 'swoole_async_readfile' => ['bool', 'filename'=>'string', 'callback'=>'string'], 'swoole_async_set' => ['void', 'settings'=>'array'], 'swoole_async_write' => ['bool', 'filename'=>'string', 'content'=>'string', 'offset='=>'int', 'callback='=>'callable'], 'swoole_async_writefile' => ['bool', 'filename'=>'string', 'content'=>'string', 'callback='=>'callable', 'flags='=>'int'], 'swoole_client_select' => ['int', 'read_array'=>'array', 'write_array'=>'array', 'error_array'=>'array', 'timeout='=>'float'], 'swoole_cpu_num' => ['int'], 'swoole_errno' => ['int'], 'swoole_event_add' => ['int', 'fd'=>'int', 'read_callback='=>'callable', 'write_callback='=>'callable', 'events='=>'int'], 'swoole_event_defer' => ['bool', 'callback'=>'callable'], 'swoole_event_del' => ['bool', 'fd'=>'int'], 'swoole_event_exit' => ['void'], 'swoole_event_set' => ['bool', 'fd'=>'int', 'read_callback='=>'callable', 'write_callback='=>'callable', 'events='=>'int'], 'swoole_event_wait' => ['void'], 'swoole_event_write' => ['bool', 'fd'=>'int', 'data'=>'string'], 'swoole_get_local_ip' => ['array'], 'swoole_last_error' => ['int'], 'swoole_load_module' => ['mixed', 'filename'=>'string'], 'swoole_select' => ['int', 'read_array'=>'array', 'write_array'=>'array', 'error_array'=>'array', 'timeout='=>'float'], 'swoole_set_process_name' => ['void', 'process_name'=>'string', 'size='=>'int'], 'swoole_strerror' => ['string', 'errno'=>'int', 'error_type='=>'int'], 'swoole_timer_after' => ['int', 'ms'=>'int', 'callback'=>'callable', 'param='=>'mixed'], 'swoole_timer_exists' => ['bool', 'timer_id'=>'int'], 'swoole_timer_tick' => ['int', 'ms'=>'int', 'callback'=>'callable', 'param='=>'mixed'], 'swoole_version' => ['string'], 'symbolObj::__construct' => ['void', 'map'=>'mapObj', 'symbolname'=>'string'], 'symbolObj::free' => ['void'], 'symbolObj::getPatternArray' => ['array'], 'symbolObj::getPointsArray' => ['array'], 'symbolObj::ms_newSymbolObj' => ['int', 'map'=>'mapObj', 'symbolname'=>'string'], 'symbolObj::set' => ['int', 'property_name'=>'string', 'new_value'=>''], 'symbolObj::setImagePath' => ['int', 'filename'=>'string'], 'symbolObj::setPattern' => ['int', 'int'=>'array'], 'symbolObj::setPoints' => ['int', 'double'=>'array'], 'symlink' => ['bool', 'target'=>'string', 'link'=>'string'], 'SyncEvent::__construct' => ['void', 'name='=>'string', 'manual='=>'bool'], 'SyncEvent::fire' => ['bool'], 'SyncEvent::reset' => ['bool'], 'SyncEvent::wait' => ['bool', 'wait='=>'int'], 'SyncMutex::__construct' => ['void', 'name='=>'string'], 'SyncMutex::lock' => ['bool', 'wait='=>'int'], 'SyncMutex::unlock' => ['bool', 'all='=>'bool'], 'SyncReaderWriter::__construct' => ['void', 'name='=>'string', 'autounlock='=>'bool'], 'SyncReaderWriter::readlock' => ['bool', 'wait='=>'int'], 'SyncReaderWriter::readunlock' => ['bool'], 'SyncReaderWriter::writelock' => ['bool', 'wait='=>'int'], 'SyncReaderWriter::writeunlock' => ['bool'], 'SyncSemaphore::__construct' => ['void', 'name='=>'string', 'initialval='=>'int', 'autounlock='=>'bool'], 'SyncSemaphore::lock' => ['bool', 'wait='=>'int'], 'SyncSemaphore::unlock' => ['bool', '&w_prevcount='=>'int'], 'SyncSharedMemory::__construct' => ['void', 'name'=>'string', 'size'=>'int'], 'SyncSharedMemory::first' => ['bool'], 'SyncSharedMemory::read' => ['string', 'start='=>'int', 'length='=>'int'], 'SyncSharedMemory::size' => ['int'], 'SyncSharedMemory::write' => ['int', 'string='=>'string', 'start='=>'int'], 'sys_get_temp_dir' => ['string'], 'sys_getloadavg' => ['array|false'], 'syslog' => ['true', 'priority'=>'int', 'message'=>'string'], 'system' => ['string|false', 'command'=>'string', '&w_result_code='=>'int'], 'taint' => ['bool', '&rw_string'=>'string', '&...w_other_strings='=>'string'], 'tan' => ['float', 'num'=>'float'], 'tanh' => ['float', 'num'=>'float'], 'tcpwrap_check' => ['bool', 'daemon'=>'string', 'address'=>'string', 'user='=>'string', 'nodns='=>'bool'], 'tempnam' => ['string|false', 'directory'=>'string', 'prefix'=>'string'], 'textdomain' => ['string', 'domain'=>'?string'], 'Thread::__construct' => ['void'], 'Thread::addRef' => ['void'], 'Thread::chunk' => ['array', 'size'=>'int', 'preserve'=>'bool'], 'Thread::count' => ['int'], 'Thread::delRef' => ['void'], 'Thread::detach' => ['void'], 'Thread::extend' => ['bool', 'class'=>'string'], 'Thread::getCreatorId' => ['int'], 'Thread::getCurrentThread' => ['Thread'], 'Thread::getCurrentThreadId' => ['int'], 'Thread::getRefCount' => ['int'], 'Thread::getTerminationInfo' => ['array'], 'Thread::getThreadId' => ['int'], 'Thread::globally' => ['mixed'], 'Thread::isGarbage' => ['bool'], 'Thread::isJoined' => ['bool'], 'Thread::isRunning' => ['bool'], 'Thread::isStarted' => ['bool'], 'Thread::isTerminated' => ['bool'], 'Thread::isWaiting' => ['bool'], 'Thread::join' => ['bool'], 'Thread::kill' => ['void'], 'Thread::lock' => ['bool'], 'Thread::merge' => ['bool', 'from'=>'', 'overwrite='=>'mixed'], 'Thread::notify' => ['bool'], 'Thread::notifyOne' => ['bool'], 'Thread::offsetExists' => ['bool', 'offset'=>'int|string'], 'Thread::offsetGet' => ['mixed', 'offset'=>'int|string'], 'Thread::offsetSet' => ['void', 'offset'=>'int|string|null', 'value'=>'mixed'], 'Thread::offsetUnset' => ['void', 'offset'=>'int|string'], 'Thread::pop' => ['bool'], 'Thread::run' => ['void'], 'Thread::setGarbage' => ['void'], 'Thread::shift' => ['bool'], 'Thread::start' => ['bool', 'options='=>'int'], 'Thread::synchronized' => ['mixed', 'block'=>'Closure', '_='=>'mixed'], 'Thread::unlock' => ['bool'], 'Thread::wait' => ['bool', 'timeout='=>'int'], 'Threaded::__construct' => ['void'], 'Threaded::addRef' => ['void'], 'Threaded::chunk' => ['array', 'size'=>'int', 'preserve'=>'bool'], 'Threaded::count' => ['int'], 'Threaded::delRef' => ['void'], 'Threaded::extend' => ['bool', 'class'=>'string'], 'Threaded::from' => ['Threaded', 'run'=>'Closure', 'construct='=>'Closure', 'args='=>'array'], 'Threaded::getRefCount' => ['int'], 'Threaded::getTerminationInfo' => ['array'], 'Threaded::isGarbage' => ['bool'], 'Threaded::isRunning' => ['bool'], 'Threaded::isTerminated' => ['bool'], 'Threaded::isWaiting' => ['bool'], 'Threaded::lock' => ['bool'], 'Threaded::merge' => ['bool', 'from'=>'mixed', 'overwrite='=>'bool'], 'Threaded::notify' => ['bool'], 'Threaded::notifyOne' => ['bool'], 'Threaded::offsetExists' => ['bool', 'offset'=>'int|string'], 'Threaded::offsetGet' => ['mixed', 'offset'=>'int|string'], 'Threaded::offsetSet' => ['void', 'offset'=>'int|string|null', 'value'=>'mixed'], 'Threaded::offsetUnset' => ['void', 'offset'=>'int|string'], 'Threaded::pop' => ['bool'], 'Threaded::run' => ['void'], 'Threaded::setGarbage' => ['void'], 'Threaded::shift' => ['mixed'], 'Threaded::synchronized' => ['mixed', 'block'=>'Closure', '...args='=>'mixed'], 'Threaded::unlock' => ['bool'], 'Threaded::wait' => ['bool', 'timeout='=>'int'], 'Throwable::__toString' => ['string'], 'Throwable::getCode' => ['int|string'], 'Throwable::getFile' => ['string'], 'Throwable::getLine' => ['int'], 'Throwable::getMessage' => ['string'], 'Throwable::getPrevious' => ['?Throwable'], 'Throwable::getTrace' => ['list\',args?:array}>'], 'Throwable::getTraceAsString' => ['string'], 'tidy::__construct' => ['void', 'filename='=>'?string', 'config='=>'array|string|null', 'encoding='=>'?string', 'useIncludePath='=>'bool'], 'tidy::body' => ['?tidyNode'], 'tidy::cleanRepair' => ['bool'], 'tidy::diagnose' => ['bool'], 'tidy::getConfig' => ['array'], 'tidy::getHtmlVer' => ['int'], 'tidy::getOpt' => ['string|int|bool', 'option'=>'string'], 'tidy::getOptDoc' => ['string', 'option'=>'string'], 'tidy::getRelease' => ['string'], 'tidy::getStatus' => ['int'], 'tidy::head' => ['?tidyNode'], 'tidy::html' => ['?tidyNode'], 'tidy::isXhtml' => ['bool'], 'tidy::isXml' => ['bool'], 'tidy::parseFile' => ['bool', 'filename'=>'string', 'config='=>'array|string|null', 'encoding='=>'?string', 'useIncludePath='=>'bool'], 'tidy::parseString' => ['bool', 'string'=>'string', 'config='=>'array|string|null', 'encoding='=>'?string'], 'tidy::repairFile' => ['string', 'filename'=>'string', 'config='=>'array|string|null', 'encoding='=>'?string', 'useIncludePath='=>'bool'], 'tidy::repairString' => ['string', 'string'=>'string', 'config='=>'array|string|null', 'encoding='=>'?string'], 'tidy::root' => ['?tidyNode'], 'tidy_access_count' => ['int', 'tidy'=>'tidy'], 'tidy_clean_repair' => ['bool', 'tidy'=>'tidy'], 'tidy_config_count' => ['int', 'tidy'=>'tidy'], 'tidy_diagnose' => ['bool', 'tidy'=>'tidy'], 'tidy_error_count' => ['int', 'tidy'=>'tidy'], 'tidy_get_body' => ['?tidyNode', 'tidy'=>'tidy'], 'tidy_get_config' => ['array', 'tidy'=>'tidy'], 'tidy_get_error_buffer' => ['string', 'tidy'=>'tidy'], 'tidy_get_head' => ['?tidyNode', 'tidy'=>'tidy'], 'tidy_get_html' => ['?tidyNode', 'tidy'=>'tidy'], 'tidy_get_html_ver' => ['int', 'tidy'=>'tidy'], 'tidy_get_opt_doc' => ['string', 'tidy'=>'tidy', 'option'=>'string'], 'tidy_get_output' => ['string', 'tidy'=>'tidy'], 'tidy_get_release' => ['string'], 'tidy_get_root' => ['?tidyNode', 'tidy'=>'tidy'], 'tidy_get_status' => ['int', 'tidy'=>'tidy'], 'tidy_getopt' => ['string|int|bool', 'tidy'=>'tidy', 'option'=>'string'], 'tidy_is_xhtml' => ['bool', 'tidy'=>'tidy'], 'tidy_is_xml' => ['bool', 'tidy'=>'tidy'], 'tidy_load_config' => ['void', 'filename'=>'string', 'encoding'=>'string'], 'tidy_parse_file' => ['tidy', 'filename'=>'string', 'config='=>'array|string|null', 'encoding='=>'?string', 'useIncludePath='=>'bool'], 'tidy_parse_string' => ['tidy', 'string'=>'string', 'config='=>'array|string|null', 'encoding='=>'?string'], 'tidy_repair_file' => ['string', 'filename'=>'string', 'config='=>'array|string|null', 'encoding='=>'?string', 'useIncludePath='=>'bool'], 'tidy_repair_string' => ['string', 'string'=>'string', 'config='=>'array|string|null', 'encoding='=>'?string'], 'tidy_reset_config' => ['bool'], 'tidy_save_config' => ['bool', 'filename'=>'string'], 'tidy_set_encoding' => ['bool', 'encoding'=>'string'], 'tidy_setopt' => ['bool', 'option'=>'string', 'value'=>'mixed'], 'tidy_warning_count' => ['int', 'tidy'=>'tidy'], 'tidyNode::__construct' => ['void'], 'tidyNode::getParent' => ['?tidyNode'], 'tidyNode::hasChildren' => ['bool'], 'tidyNode::hasSiblings' => ['bool'], 'tidyNode::isAsp' => ['bool'], 'tidyNode::isComment' => ['bool'], 'tidyNode::isHtml' => ['bool'], 'tidyNode::isJste' => ['bool'], 'tidyNode::isPhp' => ['bool'], 'tidyNode::isText' => ['bool'], 'time' => ['positive-int'], 'time_nanosleep' => ['array{0:0|positive-int,1:0|positive-int}|bool', 'seconds'=>'positive-int', 'nanoseconds'=>'positive-int'], 'time_sleep_until' => ['bool', 'timestamp'=>'float'], 'timezone_abbreviations_list' => ['array>'], 'timezone_identifiers_list' => ['list', 'timezoneGroup='=>'int', 'countryCode='=>'?string'], 'timezone_location_get' => ['array|false', 'object'=>'DateTimeZone'], 'timezone_name_from_abbr' => ['string|false', 'abbr'=>'string', 'utcOffset='=>'int', 'isDST='=>'int'], 'timezone_name_get' => ['string', 'object'=>'DateTimeZone'], 'timezone_offset_get' => ['int', 'object'=>'DateTimeZone', 'datetime'=>'DateTimeInterface'], 'timezone_open' => ['DateTimeZone|false', 'timezone'=>'string'], 'timezone_transitions_get' => ['list|false', 'object'=>'DateTimeZone', 'timestampBegin='=>'int', 'timestampEnd='=>'int'], 'timezone_version_get' => ['string'], 'tmpfile' => ['resource|false'], 'token_get_all' => ['list', 'code'=>'string', 'flags='=>'int'], 'token_name' => ['string', 'id'=>'int'], 'TokyoTyrant::__construct' => ['void', 'host='=>'string', 'port='=>'int', 'options='=>'array'], 'TokyoTyrant::add' => ['int|float', 'key'=>'string', 'increment'=>'float', 'type='=>'int'], 'TokyoTyrant::connect' => ['TokyoTyrant', 'host'=>'string', 'port='=>'int', 'options='=>'array'], 'TokyoTyrant::connectUri' => ['TokyoTyrant', 'uri'=>'string'], 'TokyoTyrant::copy' => ['TokyoTyrant', 'path'=>'string'], 'TokyoTyrant::ext' => ['string', 'name'=>'string', 'options'=>'int', 'key'=>'string', 'value'=>'string'], 'TokyoTyrant::fwmKeys' => ['array', 'prefix'=>'string', 'max_recs'=>'int'], 'TokyoTyrant::get' => ['array', 'keys'=>'mixed'], 'TokyoTyrant::getIterator' => ['TokyoTyrantIterator'], 'TokyoTyrant::num' => ['int'], 'TokyoTyrant::out' => ['string', 'keys'=>'mixed'], 'TokyoTyrant::put' => ['TokyoTyrant', 'keys'=>'mixed', 'value='=>'string'], 'TokyoTyrant::putCat' => ['TokyoTyrant', 'keys'=>'mixed', 'value='=>'string'], 'TokyoTyrant::putKeep' => ['TokyoTyrant', 'keys'=>'mixed', 'value='=>'string'], 'TokyoTyrant::putNr' => ['TokyoTyrant', 'keys'=>'mixed', 'value='=>'string'], 'TokyoTyrant::putShl' => ['mixed', 'key'=>'string', 'value'=>'string', 'width'=>'int'], 'TokyoTyrant::restore' => ['mixed', 'log_dir'=>'string', 'timestamp'=>'int', 'check_consistency='=>'bool'], 'TokyoTyrant::setMaster' => ['mixed', 'host'=>'string', 'port'=>'int', 'timestamp'=>'int', 'check_consistency='=>'bool'], 'TokyoTyrant::size' => ['int', 'key'=>'string'], 'TokyoTyrant::stat' => ['array'], 'TokyoTyrant::sync' => ['mixed'], 'TokyoTyrant::tune' => ['TokyoTyrant', 'timeout'=>'float', 'options='=>'int'], 'TokyoTyrant::vanish' => ['mixed'], 'TokyoTyrantIterator::__construct' => ['void', 'object'=>'mixed'], 'TokyoTyrantIterator::current' => ['mixed'], 'TokyoTyrantIterator::key' => ['mixed'], 'TokyoTyrantIterator::next' => ['mixed'], 'TokyoTyrantIterator::rewind' => ['void'], 'TokyoTyrantIterator::valid' => ['bool'], 'TokyoTyrantQuery::__construct' => ['void', 'table'=>'TokyoTyrantTable'], 'TokyoTyrantQuery::addCond' => ['mixed', 'name'=>'string', 'op'=>'int', 'expr'=>'string'], 'TokyoTyrantQuery::count' => ['int'], 'TokyoTyrantQuery::current' => ['array'], 'TokyoTyrantQuery::hint' => ['string'], 'TokyoTyrantQuery::key' => ['string'], 'TokyoTyrantQuery::metaSearch' => ['array', 'queries'=>'array', 'type'=>'int'], 'TokyoTyrantQuery::next' => ['array'], 'TokyoTyrantQuery::out' => ['TokyoTyrantQuery'], 'TokyoTyrantQuery::rewind' => ['bool'], 'TokyoTyrantQuery::search' => ['array'], 'TokyoTyrantQuery::setLimit' => ['mixed', 'max='=>'int', 'skip='=>'int'], 'TokyoTyrantQuery::setOrder' => ['mixed', 'name'=>'string', 'type'=>'int'], 'TokyoTyrantQuery::valid' => ['bool'], 'TokyoTyrantTable::add' => ['void', 'key'=>'string', 'increment'=>'mixed', 'type='=>'string'], 'TokyoTyrantTable::genUid' => ['int'], 'TokyoTyrantTable::get' => ['array', 'keys'=>'mixed'], 'TokyoTyrantTable::getIterator' => ['TokyoTyrantIterator'], 'TokyoTyrantTable::getQuery' => ['TokyoTyrantQuery'], 'TokyoTyrantTable::out' => ['void', 'keys'=>'mixed'], 'TokyoTyrantTable::put' => ['int', 'key'=>'string', 'columns'=>'array'], 'TokyoTyrantTable::putCat' => ['void', 'key'=>'string', 'columns'=>'array'], 'TokyoTyrantTable::putKeep' => ['void', 'key'=>'string', 'columns'=>'array'], 'TokyoTyrantTable::putNr' => ['void', 'keys'=>'mixed', 'value='=>'string'], 'TokyoTyrantTable::putShl' => ['void', 'key'=>'string', 'value'=>'string', 'width'=>'int'], 'TokyoTyrantTable::setIndex' => ['mixed', 'column'=>'string', 'type'=>'int'], 'touch' => ['bool', 'filename'=>'string', 'mtime='=>'?int', 'atime='=>'?int'], 'trader_acos' => ['array', 'real'=>'array'], 'trader_ad' => ['array', 'high'=>'array', 'low'=>'array', 'close'=>'array', 'volume'=>'array'], 'trader_add' => ['array', 'real0'=>'array', 'real1'=>'array'], 'trader_adosc' => ['array', 'high'=>'array', 'low'=>'array', 'close'=>'array', 'volume'=>'array', 'fastPeriod='=>'int', 'slowPeriod='=>'int'], 'trader_adx' => ['array', 'high'=>'array', 'low'=>'array', 'close'=>'array', 'timePeriod='=>'int'], 'trader_adxr' => ['array', 'high'=>'array', 'low'=>'array', 'close'=>'array', 'timePeriod='=>'int'], 'trader_apo' => ['array', 'real'=>'array', 'fastPeriod='=>'int', 'slowPeriod='=>'int', 'mAType='=>'int'], 'trader_aroon' => ['array', 'high'=>'array', 'low'=>'array', 'timePeriod='=>'int'], 'trader_aroonosc' => ['array', 'high'=>'array', 'low'=>'array', 'timePeriod='=>'int'], 'trader_asin' => ['array', 'real'=>'array'], 'trader_atan' => ['array', 'real'=>'array'], 'trader_atr' => ['array', 'high'=>'array', 'low'=>'array', 'close'=>'array', 'timePeriod='=>'int'], 'trader_avgprice' => ['array', 'open'=>'array', 'high'=>'array', 'low'=>'array', 'close'=>'array'], 'trader_bbands' => ['array', 'real'=>'array', 'timePeriod='=>'int', 'nbDevUp='=>'float', 'nbDevDn='=>'float', 'mAType='=>'int'], 'trader_beta' => ['array', 'real0'=>'array', 'real1'=>'array', 'timePeriod='=>'int'], 'trader_bop' => ['array', 'open'=>'array', 'high'=>'array', 'low'=>'array', 'close'=>'array'], 'trader_cci' => ['array', 'high'=>'array', 'low'=>'array', 'close'=>'array', 'timePeriod='=>'int'], 'trader_cdl2crows' => ['array', 'open'=>'array', 'high'=>'array', 'low'=>'array', 'close'=>'array'], 'trader_cdl3blackcrows' => ['array', 'open'=>'array', 'high'=>'array', 'low'=>'array', 'close'=>'array'], 'trader_cdl3inside' => ['array', 'open'=>'array', 'high'=>'array', 'low'=>'array', 'close'=>'array'], 'trader_cdl3linestrike' => ['array', 'open'=>'array', 'high'=>'array', 'low'=>'array', 'close'=>'array'], 'trader_cdl3outside' => ['array', 'open'=>'array', 'high'=>'array', 'low'=>'array', 'close'=>'array'], 'trader_cdl3starsinsouth' => ['array', 'open'=>'array', 'high'=>'array', 'low'=>'array', 'close'=>'array'], 'trader_cdl3whitesoldiers' => ['array', 'open'=>'array', 'high'=>'array', 'low'=>'array', 'close'=>'array'], 'trader_cdlabandonedbaby' => ['array', 'open'=>'array', 'high'=>'array', 'low'=>'array', 'close'=>'array', 'penetration='=>'float'], 'trader_cdladvanceblock' => ['array', 'open'=>'array', 'high'=>'array', 'low'=>'array', 'close'=>'array'], 'trader_cdlbelthold' => ['array', 'open'=>'array', 'high'=>'array', 'low'=>'array', 'close'=>'array'], 'trader_cdlbreakaway' => ['array', 'open'=>'array', 'high'=>'array', 'low'=>'array', 'close'=>'array'], 'trader_cdlclosingmarubozu' => ['array', 'open'=>'array', 'high'=>'array', 'low'=>'array', 'close'=>'array'], 'trader_cdlconcealbabyswall' => ['array', 'open'=>'array', 'high'=>'array', 'low'=>'array', 'close'=>'array'], 'trader_cdlcounterattack' => ['array', 'open'=>'array', 'high'=>'array', 'low'=>'array', 'close'=>'array'], 'trader_cdldarkcloudcover' => ['array', 'open'=>'array', 'high'=>'array', 'low'=>'array', 'close'=>'array', 'penetration='=>'float'], 'trader_cdldoji' => ['array', 'open'=>'array', 'high'=>'array', 'low'=>'array', 'close'=>'array'], 'trader_cdldojistar' => ['array', 'open'=>'array', 'high'=>'array', 'low'=>'array', 'close'=>'array'], 'trader_cdldragonflydoji' => ['array', 'open'=>'array', 'high'=>'array', 'low'=>'array', 'close'=>'array'], 'trader_cdlengulfing' => ['array', 'open'=>'array', 'high'=>'array', 'low'=>'array', 'close'=>'array'], 'trader_cdleveningdojistar' => ['array', 'open'=>'array', 'high'=>'array', 'low'=>'array', 'close'=>'array', 'penetration='=>'float'], 'trader_cdleveningstar' => ['array', 'open'=>'array', 'high'=>'array', 'low'=>'array', 'close'=>'array', 'penetration='=>'float'], 'trader_cdlgapsidesidewhite' => ['array', 'open'=>'array', 'high'=>'array', 'low'=>'array', 'close'=>'array'], 'trader_cdlgravestonedoji' => ['array', 'open'=>'array', 'high'=>'array', 'low'=>'array', 'close'=>'array'], 'trader_cdlhammer' => ['array', 'open'=>'array', 'high'=>'array', 'low'=>'array', 'close'=>'array'], 'trader_cdlhangingman' => ['array', 'open'=>'array', 'high'=>'array', 'low'=>'array', 'close'=>'array'], 'trader_cdlharami' => ['array', 'open'=>'array', 'high'=>'array', 'low'=>'array', 'close'=>'array'], 'trader_cdlharamicross' => ['array', 'open'=>'array', 'high'=>'array', 'low'=>'array', 'close'=>'array'], 'trader_cdlhighwave' => ['array', 'open'=>'array', 'high'=>'array', 'low'=>'array', 'close'=>'array'], 'trader_cdlhikkake' => ['array', 'open'=>'array', 'high'=>'array', 'low'=>'array', 'close'=>'array'], 'trader_cdlhikkakemod' => ['array', 'open'=>'array', 'high'=>'array', 'low'=>'array', 'close'=>'array'], 'trader_cdlhomingpigeon' => ['array', 'open'=>'array', 'high'=>'array', 'low'=>'array', 'close'=>'array'], 'trader_cdlidentical3crows' => ['array', 'open'=>'array', 'high'=>'array', 'low'=>'array', 'close'=>'array'], 'trader_cdlinneck' => ['array', 'open'=>'array', 'high'=>'array', 'low'=>'array', 'close'=>'array'], 'trader_cdlinvertedhammer' => ['array', 'open'=>'array', 'high'=>'array', 'low'=>'array', 'close'=>'array'], 'trader_cdlkicking' => ['array', 'open'=>'array', 'high'=>'array', 'low'=>'array', 'close'=>'array'], 'trader_cdlkickingbylength' => ['array', 'open'=>'array', 'high'=>'array', 'low'=>'array', 'close'=>'array'], 'trader_cdlladderbottom' => ['array', 'open'=>'array', 'high'=>'array', 'low'=>'array', 'close'=>'array'], 'trader_cdllongleggeddoji' => ['array', 'open'=>'array', 'high'=>'array', 'low'=>'array', 'close'=>'array'], 'trader_cdllongline' => ['array', 'open'=>'array', 'high'=>'array', 'low'=>'array', 'close'=>'array'], 'trader_cdlmarubozu' => ['array', 'open'=>'array', 'high'=>'array', 'low'=>'array', 'close'=>'array'], 'trader_cdlmatchinglow' => ['array', 'open'=>'array', 'high'=>'array', 'low'=>'array', 'close'=>'array'], 'trader_cdlmathold' => ['array', 'open'=>'array', 'high'=>'array', 'low'=>'array', 'close'=>'array', 'penetration='=>'float'], 'trader_cdlmorningdojistar' => ['array', 'open'=>'array', 'high'=>'array', 'low'=>'array', 'close'=>'array', 'penetration='=>'float'], 'trader_cdlmorningstar' => ['array', 'open'=>'array', 'high'=>'array', 'low'=>'array', 'close'=>'array', 'penetration='=>'float'], 'trader_cdlonneck' => ['array', 'open'=>'array', 'high'=>'array', 'low'=>'array', 'close'=>'array'], 'trader_cdlpiercing' => ['array', 'open'=>'array', 'high'=>'array', 'low'=>'array', 'close'=>'array'], 'trader_cdlrickshawman' => ['array', 'open'=>'array', 'high'=>'array', 'low'=>'array', 'close'=>'array'], 'trader_cdlrisefall3methods' => ['array', 'open'=>'array', 'high'=>'array', 'low'=>'array', 'close'=>'array'], 'trader_cdlseparatinglines' => ['array', 'open'=>'array', 'high'=>'array', 'low'=>'array', 'close'=>'array'], 'trader_cdlshootingstar' => ['array', 'open'=>'array', 'high'=>'array', 'low'=>'array', 'close'=>'array'], 'trader_cdlshortline' => ['array', 'open'=>'array', 'high'=>'array', 'low'=>'array', 'close'=>'array'], 'trader_cdlspinningtop' => ['array', 'open'=>'array', 'high'=>'array', 'low'=>'array', 'close'=>'array'], 'trader_cdlstalledpattern' => ['array', 'open'=>'array', 'high'=>'array', 'low'=>'array', 'close'=>'array'], 'trader_cdlsticksandwich' => ['array', 'open'=>'array', 'high'=>'array', 'low'=>'array', 'close'=>'array'], 'trader_cdltakuri' => ['array', 'open'=>'array', 'high'=>'array', 'low'=>'array', 'close'=>'array'], 'trader_cdltasukigap' => ['array', 'open'=>'array', 'high'=>'array', 'low'=>'array', 'close'=>'array'], 'trader_cdlthrusting' => ['array', 'open'=>'array', 'high'=>'array', 'low'=>'array', 'close'=>'array'], 'trader_cdltristar' => ['array', 'open'=>'array', 'high'=>'array', 'low'=>'array', 'close'=>'array'], 'trader_cdlunique3river' => ['array', 'open'=>'array', 'high'=>'array', 'low'=>'array', 'close'=>'array'], 'trader_cdlupsidegap2crows' => ['array', 'open'=>'array', 'high'=>'array', 'low'=>'array', 'close'=>'array'], 'trader_cdlxsidegap3methods' => ['array', 'open'=>'array', 'high'=>'array', 'low'=>'array', 'close'=>'array'], 'trader_ceil' => ['array', 'real'=>'array'], 'trader_cmo' => ['array', 'real'=>'array', 'timePeriod='=>'int'], 'trader_correl' => ['array', 'real0'=>'array', 'real1'=>'array', 'timePeriod='=>'int'], 'trader_cos' => ['array', 'real'=>'array'], 'trader_cosh' => ['array', 'real'=>'array'], 'trader_dema' => ['array', 'real'=>'array', 'timePeriod='=>'int'], 'trader_div' => ['array', 'real0'=>'array', 'real1'=>'array'], 'trader_dx' => ['array', 'high'=>'array', 'low'=>'array', 'close'=>'array', 'timePeriod='=>'int'], 'trader_ema' => ['array', 'real'=>'array', 'timePeriod='=>'int'], 'trader_errno' => ['int'], 'trader_exp' => ['array', 'real'=>'array'], 'trader_floor' => ['array', 'real'=>'array'], 'trader_get_compat' => ['int'], 'trader_get_unstable_period' => ['int', 'functionId'=>'int'], 'trader_ht_dcperiod' => ['array', 'real'=>'array'], 'trader_ht_dcphase' => ['array', 'real'=>'array'], 'trader_ht_phasor' => ['array', 'real'=>'array'], 'trader_ht_sine' => ['array', 'real'=>'array'], 'trader_ht_trendline' => ['array', 'real'=>'array'], 'trader_ht_trendmode' => ['array', 'real'=>'array'], 'trader_kama' => ['array', 'real'=>'array', 'timePeriod='=>'int'], 'trader_linearreg' => ['array', 'real'=>'array', 'timePeriod='=>'int'], 'trader_linearreg_angle' => ['array', 'real'=>'array', 'timePeriod='=>'int'], 'trader_linearreg_intercept' => ['array', 'real'=>'array', 'timePeriod='=>'int'], 'trader_linearreg_slope' => ['array', 'real'=>'array', 'timePeriod='=>'int'], 'trader_ln' => ['array', 'real'=>'array'], 'trader_log10' => ['array', 'real'=>'array'], 'trader_ma' => ['array', 'real'=>'array', 'timePeriod='=>'int', 'mAType='=>'int'], 'trader_macd' => ['array', 'real'=>'array', 'fastPeriod='=>'int', 'slowPeriod='=>'int', 'signalPeriod='=>'int'], 'trader_macdext' => ['array', 'real'=>'array', 'fastPeriod='=>'int', 'fastMAType='=>'int', 'slowPeriod='=>'int', 'slowMAType='=>'int', 'signalPeriod='=>'int', 'signalMAType='=>'int'], 'trader_macdfix' => ['array', 'real'=>'array', 'signalPeriod='=>'int'], 'trader_mama' => ['array', 'real'=>'array', 'fastLimit='=>'float', 'slowLimit='=>'float'], 'trader_mavp' => ['array', 'real'=>'array', 'periods'=>'array', 'minPeriod='=>'int', 'maxPeriod='=>'int', 'mAType='=>'int'], 'trader_max' => ['array', 'real'=>'array', 'timePeriod='=>'int'], 'trader_maxindex' => ['array', 'real'=>'array', 'timePeriod='=>'int'], 'trader_medprice' => ['array', 'high'=>'array', 'low'=>'array'], 'trader_mfi' => ['array', 'high'=>'array', 'low'=>'array', 'close'=>'array', 'volume'=>'array', 'timePeriod='=>'int'], 'trader_midpoint' => ['array', 'real'=>'array', 'timePeriod='=>'int'], 'trader_midprice' => ['array', 'high'=>'array', 'low'=>'array', 'timePeriod='=>'int'], 'trader_min' => ['array', 'real'=>'array', 'timePeriod='=>'int'], 'trader_minindex' => ['array', 'real'=>'array', 'timePeriod='=>'int'], 'trader_minmax' => ['array', 'real'=>'array', 'timePeriod='=>'int'], 'trader_minmaxindex' => ['array', 'real'=>'array', 'timePeriod='=>'int'], 'trader_minus_di' => ['array', 'high'=>'array', 'low'=>'array', 'close'=>'array', 'timePeriod='=>'int'], 'trader_minus_dm' => ['array', 'high'=>'array', 'low'=>'array', 'timePeriod='=>'int'], 'trader_mom' => ['array', 'real'=>'array', 'timePeriod='=>'int'], 'trader_mult' => ['array', 'real0'=>'array', 'real1'=>'array'], 'trader_natr' => ['array', 'high'=>'array', 'low'=>'array', 'close'=>'array', 'timePeriod='=>'int'], 'trader_obv' => ['array', 'real'=>'array', 'volume'=>'array'], 'trader_plus_di' => ['array', 'high'=>'array', 'low'=>'array', 'close'=>'array', 'timePeriod='=>'int'], 'trader_plus_dm' => ['array', 'high'=>'array', 'low'=>'array', 'timePeriod='=>'int'], 'trader_ppo' => ['array', 'real'=>'array', 'fastPeriod='=>'int', 'slowPeriod='=>'int', 'mAType='=>'int'], 'trader_roc' => ['array', 'real'=>'array', 'timePeriod='=>'int'], 'trader_rocp' => ['array', 'real'=>'array', 'timePeriod='=>'int'], 'trader_rocr' => ['array', 'real'=>'array', 'timePeriod='=>'int'], 'trader_rocr100' => ['array', 'real'=>'array', 'timePeriod='=>'int'], 'trader_rsi' => ['array', 'real'=>'array', 'timePeriod='=>'int'], 'trader_sar' => ['array', 'high'=>'array', 'low'=>'array', 'acceleration='=>'float', 'maximum='=>'float'], 'trader_sarext' => ['array', 'high'=>'array', 'low'=>'array', 'startValue='=>'float', 'offsetOnReverse='=>'float', 'accelerationInitLong='=>'float', 'accelerationLong='=>'float', 'accelerationMaxLong='=>'float', 'accelerationInitShort='=>'float', 'accelerationShort='=>'float', 'accelerationMaxShort='=>'float'], 'trader_set_compat' => ['void', 'compatId'=>'int'], 'trader_set_unstable_period' => ['void', 'functionId'=>'int', 'timePeriod'=>'int'], 'trader_sin' => ['array', 'real'=>'array'], 'trader_sinh' => ['array', 'real'=>'array'], 'trader_sma' => ['array', 'real'=>'array', 'timePeriod='=>'int'], 'trader_sqrt' => ['array', 'real'=>'array'], 'trader_stddev' => ['array', 'real'=>'array', 'timePeriod='=>'int', 'nbDev='=>'float'], 'trader_stoch' => ['array', 'high'=>'array', 'low'=>'array', 'close'=>'array', 'fastK_Period='=>'int', 'slowK_Period='=>'int', 'slowK_MAType='=>'int', 'slowD_Period='=>'int', 'slowD_MAType='=>'int'], 'trader_stochf' => ['array', 'high'=>'array', 'low'=>'array', 'close'=>'array', 'fastK_Period='=>'int', 'fastD_Period='=>'int', 'fastD_MAType='=>'int'], 'trader_stochrsi' => ['array', 'real'=>'array', 'timePeriod='=>'int', 'fastK_Period='=>'int', 'fastD_Period='=>'int', 'fastD_MAType='=>'int'], 'trader_sub' => ['array', 'real0'=>'array', 'real1'=>'array'], 'trader_sum' => ['array', 'real'=>'array', 'timePeriod='=>'int'], 'trader_t3' => ['array', 'real'=>'array', 'timePeriod='=>'int', 'vFactor='=>'float'], 'trader_tan' => ['array', 'real'=>'array'], 'trader_tanh' => ['array', 'real'=>'array'], 'trader_tema' => ['array', 'real'=>'array', 'timePeriod='=>'int'], 'trader_trange' => ['array', 'high'=>'array', 'low'=>'array', 'close'=>'array'], 'trader_trima' => ['array', 'real'=>'array', 'timePeriod='=>'int'], 'trader_trix' => ['array', 'real'=>'array', 'timePeriod='=>'int'], 'trader_tsf' => ['array', 'real'=>'array', 'timePeriod='=>'int'], 'trader_typprice' => ['array', 'high'=>'array', 'low'=>'array', 'close'=>'array'], 'trader_ultosc' => ['array', 'high'=>'array', 'low'=>'array', 'close'=>'array', 'timePeriod1='=>'int', 'timePeriod2='=>'int', 'timePeriod3='=>'int'], 'trader_var' => ['array', 'real'=>'array', 'timePeriod='=>'int', 'nbDev='=>'float'], 'trader_wclprice' => ['array', 'high'=>'array', 'low'=>'array', 'close'=>'array'], 'trader_willr' => ['array', 'high'=>'array', 'low'=>'array', 'close'=>'array', 'timePeriod='=>'int'], 'trader_wma' => ['array', 'real'=>'array', 'timePeriod='=>'int'], 'trait_exists' => ['bool', 'trait'=>'string', 'autoload='=>'bool'], 'Transliterator::create' => ['?Transliterator', 'id'=>'string', 'direction='=>'int'], 'Transliterator::createFromRules' => ['?Transliterator', 'rules'=>'string', 'direction='=>'int'], 'Transliterator::createInverse' => ['?Transliterator'], 'Transliterator::getErrorCode' => ['int'], 'Transliterator::getErrorMessage' => ['string'], 'Transliterator::listIDs' => ['array'], 'Transliterator::transliterate' => ['string|false', 'string'=>'string', 'start='=>'int', 'end='=>'int'], 'transliterator_create' => ['?Transliterator', 'id'=>'string', 'direction='=>'int'], 'transliterator_create_from_rules' => ['?Transliterator', 'rules'=>'string', 'direction='=>'int'], 'transliterator_create_inverse' => ['?Transliterator', 'transliterator'=>'Transliterator'], 'transliterator_get_error_code' => ['int', 'transliterator'=>'Transliterator'], 'transliterator_get_error_message' => ['string', 'transliterator'=>'Transliterator'], 'transliterator_list_ids' => ['array'], 'transliterator_transliterate' => ['string|false', 'transliterator'=>'Transliterator|string', 'string'=>'string', 'start='=>'int', 'end='=>'int'], 'trigger_error' => ['bool', 'message'=>'string', 'error_level='=>'256|512|1024|16384'], 'trim' => ['string', 'string'=>'string', 'characters='=>'string'], 'TypeError::__construct' => ['void', 'message='=>'string', 'code='=>'int', 'previous='=>'?Throwable'], 'TypeError::__toString' => ['string'], 'TypeError::getCode' => ['int'], 'TypeError::getFile' => ['string'], 'TypeError::getLine' => ['int'], 'TypeError::getMessage' => ['string'], 'TypeError::getPrevious' => ['?Throwable'], 'TypeError::getTrace' => ['list\',args?:array}>'], 'TypeError::getTraceAsString' => ['string'], 'uasort' => ['true', '&rw_array'=>'array', 'callback'=>'callable(mixed,mixed):int'], 'ucfirst' => ['string', 'string'=>'string'], 'UConverter::__construct' => ['void', 'destination_encoding='=>'?string', 'source_encoding='=>'?string'], 'UConverter::convert' => ['string', 'str'=>'string', 'reverse='=>'bool'], 'UConverter::fromUCallback' => ['string|int|array|null', 'reason'=>'int', 'source'=>'array', 'codePoint'=>'int', '&w_error'=>'int'], 'UConverter::getAliases' => ['array|false|null', 'name'=>'string'], 'UConverter::getAvailable' => ['array'], 'UConverter::getDestinationEncoding' => ['string|false|null'], 'UConverter::getDestinationType' => ['int|false|null'], 'UConverter::getErrorCode' => ['int'], 'UConverter::getErrorMessage' => ['?string'], 'UConverter::getSourceEncoding' => ['string|false|null'], 'UConverter::getSourceType' => ['int|false|null'], 'UConverter::getStandards' => ['?array'], 'UConverter::getSubstChars' => ['string|false|null'], 'UConverter::reasonText' => ['string', 'reason'=>'int'], 'UConverter::setDestinationEncoding' => ['bool', 'encoding'=>'string'], 'UConverter::setSourceEncoding' => ['bool', 'encoding'=>'string'], 'UConverter::setSubstChars' => ['bool', 'chars'=>'string'], 'UConverter::toUCallback' => ['string|int|array|null', 'reason'=>'int', 'source'=>'string', 'codeUnits'=>'string', '&w_error'=>'int'], 'UConverter::transcode' => ['string', 'str'=>'string', 'toEncoding'=>'string', 'fromEncoding'=>'string', 'options='=>'?array'], 'ucwords' => ['string', 'string'=>'string', 'separators='=>'string'], 'udm_add_search_limit' => ['bool', 'agent'=>'resource', 'var'=>'int', 'value'=>'string'], 'udm_alloc_agent' => ['resource', 'dbaddr'=>'string', 'dbmode='=>'string'], 'udm_alloc_agent_array' => ['resource', 'databases'=>'array'], 'udm_api_version' => ['int'], 'udm_cat_list' => ['array', 'agent'=>'resource', 'category'=>'string'], 'udm_cat_path' => ['array', 'agent'=>'resource', 'category'=>'string'], 'udm_check_charset' => ['bool', 'agent'=>'resource', 'charset'=>'string'], 'udm_check_stored' => ['int', 'agent'=>'', 'link'=>'int', 'doc_id'=>'string'], 'udm_clear_search_limits' => ['bool', 'agent'=>'resource'], 'udm_close_stored' => ['int', 'agent'=>'', 'link'=>'int'], 'udm_crc32' => ['int', 'agent'=>'resource', 'string'=>'string'], 'udm_errno' => ['int', 'agent'=>'resource'], 'udm_error' => ['string', 'agent'=>'resource'], 'udm_find' => ['resource', 'agent'=>'resource', 'query'=>'string'], 'udm_free_agent' => ['int', 'agent'=>'resource'], 'udm_free_ispell_data' => ['bool', 'agent'=>'int'], 'udm_free_res' => ['bool', 'res'=>'resource'], 'udm_get_doc_count' => ['int', 'agent'=>'resource'], 'udm_get_res_field' => ['string', 'res'=>'resource', 'row'=>'int', 'field'=>'int'], 'udm_get_res_param' => ['string', 'res'=>'resource', 'param'=>'int'], 'udm_hash32' => ['int', 'agent'=>'resource', 'string'=>'string'], 'udm_load_ispell_data' => ['bool', 'agent'=>'resource', 'var'=>'int', 'val1'=>'string', 'val2'=>'string', 'flag'=>'int'], 'udm_open_stored' => ['int', 'agent'=>'', 'storedaddr'=>'string'], 'udm_set_agent_param' => ['bool', 'agent'=>'resource', 'var'=>'int', 'val'=>'string'], 'ui\area::onDraw' => ['', 'pen'=>'UI\Draw\Pen', 'areaSize'=>'UI\Size', 'clipPoint'=>'UI\Point', 'clipSize'=>'UI\Size'], 'ui\area::onKey' => ['', 'key'=>'string', 'ext'=>'int', 'flags'=>'int'], 'ui\area::onMouse' => ['', 'areaPoint'=>'UI\Point', 'areaSize'=>'UI\Size', 'flags'=>'int'], 'ui\area::redraw' => [''], 'ui\area::scrollTo' => ['', 'point'=>'UI\Point', 'size'=>'UI\Size'], 'ui\area::setSize' => ['', 'size'=>'UI\Size'], 'ui\control::destroy' => [''], 'ui\control::disable' => [''], 'ui\control::enable' => [''], 'ui\control::getParent' => ['UI\Control'], 'ui\control::getTopLevel' => ['int'], 'ui\control::hide' => [''], 'ui\control::isEnabled' => ['bool'], 'ui\control::isVisible' => ['bool'], 'ui\control::setParent' => ['', 'parent'=>'UI\Control'], 'ui\control::show' => [''], 'ui\controls\box::append' => ['int', 'control'=>'Control', 'stretchy='=>'bool'], 'ui\controls\box::delete' => ['bool', 'index'=>'int'], 'ui\controls\box::getOrientation' => ['int'], 'ui\controls\box::isPadded' => ['bool'], 'ui\controls\box::setPadded' => ['', 'padded'=>'bool'], 'ui\controls\button::getText' => ['string'], 'ui\controls\button::onClick' => [''], 'ui\controls\button::setText' => ['', 'text'=>'string'], 'ui\controls\check::getText' => ['string'], 'ui\controls\check::isChecked' => ['bool'], 'ui\controls\check::onToggle' => [''], 'ui\controls\check::setChecked' => ['', 'checked'=>'bool'], 'ui\controls\check::setText' => ['', 'text'=>'string'], 'ui\controls\colorbutton::getColor' => ['UI\Color'], 'ui\controls\colorbutton::onChange' => [''], 'ui\controls\combo::append' => ['', 'text'=>'string'], 'ui\controls\combo::getSelected' => ['int'], 'ui\controls\combo::onSelected' => [''], 'ui\controls\combo::setSelected' => ['', 'index'=>'int'], 'ui\controls\editablecombo::append' => ['', 'text'=>'string'], 'ui\controls\editablecombo::getText' => ['string'], 'ui\controls\editablecombo::onChange' => [''], 'ui\controls\editablecombo::setText' => ['', 'text'=>'string'], 'ui\controls\entry::getText' => ['string'], 'ui\controls\entry::isReadOnly' => ['bool'], 'ui\controls\entry::onChange' => [''], 'ui\controls\entry::setReadOnly' => ['', 'readOnly'=>'bool'], 'ui\controls\entry::setText' => ['', 'text'=>'string'], 'ui\controls\form::append' => ['int', 'label'=>'string', 'control'=>'UI\Control', 'stretchy='=>'bool'], 'ui\controls\form::delete' => ['bool', 'index'=>'int'], 'ui\controls\form::isPadded' => ['bool'], 'ui\controls\form::setPadded' => ['', 'padded'=>'bool'], 'ui\controls\grid::append' => ['', 'control'=>'UI\Control', 'left'=>'int', 'top'=>'int', 'xspan'=>'int', 'yspan'=>'int', 'hexpand'=>'bool', 'halign'=>'int', 'vexpand'=>'bool', 'valign'=>'int'], 'ui\controls\grid::isPadded' => ['bool'], 'ui\controls\grid::setPadded' => ['', 'padding'=>'bool'], 'ui\controls\group::append' => ['', 'control'=>'UI\Control'], 'ui\controls\group::getTitle' => ['string'], 'ui\controls\group::hasMargin' => ['bool'], 'ui\controls\group::setMargin' => ['', 'margin'=>'bool'], 'ui\controls\group::setTitle' => ['', 'title'=>'string'], 'ui\controls\label::getText' => ['string'], 'ui\controls\label::setText' => ['', 'text'=>'string'], 'ui\controls\multilineentry::append' => ['', 'text'=>'string'], 'ui\controls\multilineentry::getText' => ['string'], 'ui\controls\multilineentry::isReadOnly' => ['bool'], 'ui\controls\multilineentry::onChange' => [''], 'ui\controls\multilineentry::setReadOnly' => ['', 'readOnly'=>'bool'], 'ui\controls\multilineentry::setText' => ['', 'text'=>'string'], 'ui\controls\progress::getValue' => ['int'], 'ui\controls\progress::setValue' => ['', 'value'=>'int'], 'ui\controls\radio::append' => ['', 'text'=>'string'], 'ui\controls\radio::getSelected' => ['int'], 'ui\controls\radio::onSelected' => [''], 'ui\controls\radio::setSelected' => ['', 'index'=>'int'], 'ui\controls\slider::getValue' => ['int'], 'ui\controls\slider::onChange' => [''], 'ui\controls\slider::setValue' => ['', 'value'=>'int'], 'ui\controls\spin::getValue' => ['int'], 'ui\controls\spin::onChange' => [''], 'ui\controls\spin::setValue' => ['', 'value'=>'int'], 'ui\controls\tab::append' => ['int', 'name'=>'string', 'control'=>'UI\Control'], 'ui\controls\tab::delete' => ['bool', 'index'=>'int'], 'ui\controls\tab::hasMargin' => ['bool', 'page'=>'int'], 'ui\controls\tab::insertAt' => ['', 'name'=>'string', 'page'=>'int', 'control'=>'UI\Control'], 'ui\controls\tab::pages' => ['int'], 'ui\controls\tab::setMargin' => ['', 'page'=>'int', 'margin'=>'bool'], 'ui\draw\brush::getColor' => ['UI\Draw\Color'], 'ui\draw\brush\gradient::delStop' => ['int', 'index'=>'int'], 'ui\draw\color::getChannel' => ['float', 'channel'=>'int'], 'ui\draw\color::setChannel' => ['void', 'channel'=>'int', 'value'=>'float'], 'ui\draw\matrix::invert' => [''], 'ui\draw\matrix::isInvertible' => ['bool'], 'ui\draw\matrix::multiply' => ['UI\Draw\Matrix', 'matrix'=>'UI\Draw\Matrix'], 'ui\draw\matrix::rotate' => ['', 'point'=>'UI\Point', 'amount'=>'float'], 'ui\draw\matrix::scale' => ['', 'center'=>'UI\Point', 'point'=>'UI\Point'], 'ui\draw\matrix::skew' => ['', 'point'=>'UI\Point', 'amount'=>'UI\Point'], 'ui\draw\matrix::translate' => ['', 'point'=>'UI\Point'], 'ui\draw\path::addRectangle' => ['', 'point'=>'UI\Point', 'size'=>'UI\Size'], 'ui\draw\path::arcTo' => ['', 'point'=>'UI\Point', 'radius'=>'float', 'angle'=>'float', 'sweep'=>'float', 'negative'=>'float'], 'ui\draw\path::bezierTo' => ['', 'point'=>'UI\Point', 'radius'=>'float', 'angle'=>'float', 'sweep'=>'float', 'negative'=>'float'], 'ui\draw\path::closeFigure' => [''], 'ui\draw\path::end' => [''], 'ui\draw\path::lineTo' => ['', 'point'=>'UI\Point', 'radius'=>'float', 'angle'=>'float', 'sweep'=>'float', 'negative'=>'float'], 'ui\draw\path::newFigure' => ['', 'point'=>'UI\Point'], 'ui\draw\path::newFigureWithArc' => ['', 'point'=>'UI\Point', 'radius'=>'float', 'angle'=>'float', 'sweep'=>'float', 'negative'=>'float'], 'ui\draw\pen::clip' => ['', 'path'=>'UI\Draw\Path'], 'ui\draw\pen::restore' => [''], 'ui\draw\pen::save' => [''], 'ui\draw\pen::transform' => ['', 'matrix'=>'UI\Draw\Matrix'], 'ui\draw\pen::write' => ['', 'point'=>'UI\Point', 'layout'=>'UI\Draw\Text\Layout'], 'ui\draw\stroke::getCap' => ['int'], 'ui\draw\stroke::getJoin' => ['int'], 'ui\draw\stroke::getMiterLimit' => ['float'], 'ui\draw\stroke::getThickness' => ['float'], 'ui\draw\stroke::setCap' => ['', 'cap'=>'int'], 'ui\draw\stroke::setJoin' => ['', 'join'=>'int'], 'ui\draw\stroke::setMiterLimit' => ['', 'limit'=>'float'], 'ui\draw\stroke::setThickness' => ['', 'thickness'=>'float'], 'ui\draw\text\font::getAscent' => ['float'], 'ui\draw\text\font::getDescent' => ['float'], 'ui\draw\text\font::getLeading' => ['float'], 'ui\draw\text\font::getUnderlinePosition' => ['float'], 'ui\draw\text\font::getUnderlineThickness' => ['float'], 'ui\draw\text\font\descriptor::getFamily' => ['string'], 'ui\draw\text\font\descriptor::getItalic' => ['int'], 'ui\draw\text\font\descriptor::getSize' => ['float'], 'ui\draw\text\font\descriptor::getStretch' => ['int'], 'ui\draw\text\font\descriptor::getWeight' => ['int'], 'ui\draw\text\font\fontfamilies' => ['array'], 'ui\draw\text\layout::setWidth' => ['', 'width'=>'float'], 'ui\executor::kill' => ['void'], 'ui\executor::onExecute' => ['void'], 'ui\menu::append' => ['UI\MenuItem', 'name'=>'string', 'type='=>'string'], 'ui\menu::appendAbout' => ['UI\MenuItem', 'type='=>'string'], 'ui\menu::appendCheck' => ['UI\MenuItem', 'name'=>'string', 'type='=>'string'], 'ui\menu::appendPreferences' => ['UI\MenuItem', 'type='=>'string'], 'ui\menu::appendQuit' => ['UI\MenuItem', 'type='=>'string'], 'ui\menu::appendSeparator' => [''], 'ui\menuitem::disable' => [''], 'ui\menuitem::enable' => [''], 'ui\menuitem::isChecked' => ['bool'], 'ui\menuitem::onClick' => [''], 'ui\menuitem::setChecked' => ['', 'checked'=>'bool'], 'ui\point::getX' => ['float'], 'ui\point::getY' => ['float'], 'ui\point::setX' => ['', 'point'=>'float'], 'ui\point::setY' => ['', 'point'=>'float'], 'ui\quit' => ['void'], 'ui\run' => ['void', 'flags='=>'int'], 'ui\size::getHeight' => ['float'], 'ui\size::getWidth' => ['float'], 'ui\size::setHeight' => ['', 'size'=>'float'], 'ui\size::setWidth' => ['', 'size'=>'float'], 'ui\window::add' => ['', 'control'=>'UI\Control'], 'ui\window::error' => ['', 'title'=>'string', 'msg'=>'string'], 'ui\window::getSize' => ['UI\Size'], 'ui\window::getTitle' => ['string'], 'ui\window::hasBorders' => ['bool'], 'ui\window::hasMargin' => ['bool'], 'ui\window::isFullScreen' => ['bool'], 'ui\window::msg' => ['', 'title'=>'string', 'msg'=>'string'], 'ui\window::onClosing' => ['int'], 'ui\window::open' => ['string'], 'ui\window::save' => ['string'], 'ui\window::setBorders' => ['', 'borders'=>'bool'], 'ui\window::setFullScreen' => ['', 'full'=>'bool'], 'ui\window::setMargin' => ['', 'margin'=>'bool'], 'ui\window::setSize' => ['', 'size'=>'UI\Size'], 'ui\window::setTitle' => ['', 'title'=>'string'], 'uksort' => ['true', '&rw_array'=>'array', 'callback'=>'callable(mixed,mixed):int'], 'umask' => ['int', 'mask='=>'?int'], 'UnderflowException::__construct' => ['void', 'message='=>'string', 'code='=>'int', 'previous='=>'?Throwable'], 'UnderflowException::__toString' => ['string'], 'UnderflowException::getCode' => ['int'], 'UnderflowException::getFile' => ['string'], 'UnderflowException::getLine' => ['int'], 'UnderflowException::getMessage' => ['string'], 'UnderflowException::getPrevious' => ['?Throwable'], 'UnderflowException::getTrace' => ['list\',args?:array}>'], 'UnderflowException::getTraceAsString' => ['string'], 'UnexpectedValueException::__construct' => ['void', 'message='=>'string', 'code='=>'int', 'previous='=>'?Throwable'], 'UnexpectedValueException::__toString' => ['string'], 'UnexpectedValueException::getCode' => ['int'], 'UnexpectedValueException::getFile' => ['string'], 'UnexpectedValueException::getLine' => ['int'], 'UnexpectedValueException::getMessage' => ['string'], 'UnexpectedValueException::getPrevious' => ['?Throwable'], 'UnexpectedValueException::getTrace' => ['list\',args?:array}>'], 'UnexpectedValueException::getTraceAsString' => ['string'], 'uniqid' => ['non-empty-string', 'prefix='=>'string', 'more_entropy='=>'bool'], 'unixtojd' => ['int|false', 'timestamp='=>'?int'], 'unlink' => ['bool', 'filename'=>'string', 'context='=>'resource'], 'unpack' => ['array|false', 'format'=>'string', 'string'=>'string', 'offset='=>'int'], 'unregister_tick_function' => ['void', 'callback'=>'callable'], 'unserialize' => ['mixed', 'data'=>'string', 'options='=>'array{allowed_classes?:class-string[]|bool}'], 'unset' => ['void', 'var='=>'mixed', '...args='=>'mixed'], 'untaint' => ['bool', '&rw_string'=>'string', '&...rw_strings='=>'string'], 'uopz_allow_exit' => ['void', 'allow'=>'bool'], 'uopz_backup' => ['void', 'class'=>'string', 'function'=>'string'], 'uopz_backup\'1' => ['void', 'function'=>'string'], 'uopz_compose' => ['void', 'name'=>'string', 'classes'=>'array', 'methods='=>'array', 'properties='=>'array', 'flags='=>'int'], 'uopz_copy' => ['Closure', 'class'=>'string', 'function'=>'string'], 'uopz_copy\'1' => ['Closure', 'function'=>'string'], 'uopz_delete' => ['void', 'class'=>'string', 'function'=>'string'], 'uopz_delete\'1' => ['void', 'function'=>'string'], 'uopz_extend' => ['bool', 'class'=>'string', 'parent'=>'string'], 'uopz_flags' => ['int', 'class'=>'string', 'function'=>'string', 'flags'=>'int'], 'uopz_flags\'1' => ['int', 'function'=>'string', 'flags'=>'int'], 'uopz_function' => ['void', 'class'=>'string', 'function'=>'string', 'handler'=>'Closure', 'modifiers='=>'int'], 'uopz_function\'1' => ['void', 'function'=>'string', 'handler'=>'Closure', 'modifiers='=>'int'], 'uopz_get_exit_status' => ['?int'], 'uopz_get_hook' => ['?Closure', 'class'=>'string', 'function'=>'string'], 'uopz_get_hook\'1' => ['?Closure', 'function'=>'string'], 'uopz_get_mock' => ['string|object|null', 'class'=>'string'], 'uopz_get_property' => ['mixed', 'class'=>'object|string', 'property'=>'string'], 'uopz_get_return' => ['mixed', 'class='=>'class-string', 'function='=>'string'], 'uopz_get_static' => ['?array', 'class'=>'string', 'function'=>'string'], 'uopz_implement' => ['bool', 'class'=>'string', 'interface'=>'string'], 'uopz_overload' => ['void', 'opcode'=>'int', 'callable'=>'Callable'], 'uopz_redefine' => ['bool', 'class'=>'string', 'constant'=>'string', 'value'=>'mixed'], 'uopz_redefine\'1' => ['bool', 'constant'=>'string', 'value'=>'mixed'], 'uopz_rename' => ['void', 'class'=>'string', 'function'=>'string', 'rename'=>'string'], 'uopz_rename\'1' => ['void', 'function'=>'string', 'rename'=>'string'], 'uopz_restore' => ['void', 'class'=>'string', 'function'=>'string'], 'uopz_restore\'1' => ['void', 'function'=>'string'], 'uopz_set_hook' => ['bool', 'class'=>'string', 'function'=>'string', 'hook'=>'Closure'], 'uopz_set_hook\'1' => ['bool', 'function'=>'string', 'hook'=>'Closure'], 'uopz_set_mock' => ['void', 'class'=>'string', 'mock'=>'object|string'], 'uopz_set_property' => ['void', 'class'=>'object|string', 'property'=>'string', 'value'=>'mixed'], 'uopz_set_return' => ['bool', 'class'=>'string', 'function'=>'string', 'value'=>'mixed', 'execute='=>'bool'], 'uopz_set_return\'1' => ['bool', 'function'=>'string', 'value'=>'mixed', 'execute='=>'bool'], 'uopz_set_static' => ['void', 'class'=>'string', 'function'=>'string', 'static'=>'array'], 'uopz_undefine' => ['bool', 'class'=>'string', 'constant'=>'string'], 'uopz_undefine\'1' => ['bool', 'constant'=>'string'], 'uopz_unset_hook' => ['bool', 'class'=>'string', 'function'=>'string'], 'uopz_unset_hook\'1' => ['bool', 'function'=>'string'], 'uopz_unset_mock' => ['void', 'class'=>'string'], 'uopz_unset_return' => ['bool', 'class='=>'class-string', 'function='=>'string'], 'uopz_unset_return\'1' => ['bool', 'function'=>'string'], 'urldecode' => ['string', 'string'=>'string'], 'urlencode' => ['string', 'string'=>'string'], 'use_soap_error_handler' => ['bool', 'enable='=>'bool'], 'user_error' => ['bool', 'message'=>'string', 'error_level='=>'int'], 'usleep' => ['void', 'microseconds'=>'positive-int|0'], 'usort' => ['true', '&rw_array'=>'array', 'callback'=>'callable(mixed,mixed):int'], 'utf8_decode' => ['string', 'string'=>'string'], 'utf8_encode' => ['string', 'string'=>'string'], 'V8Js::__construct' => ['void', 'object_name='=>'string', 'variables='=>'array', 'extensions='=>'array', 'report_uncaught_exceptions='=>'bool', 'snapshot_blob='=>'string'], 'V8Js::clearPendingException' => [''], 'V8Js::compileString' => ['resource', 'script'=>'', 'identifier='=>'string'], 'V8Js::createSnapshot' => ['false|string', 'embed_source'=>'string'], 'V8Js::executeScript' => ['', 'script'=>'resource', 'flags='=>'int', 'time_limit='=>'int', 'memory_limit='=>'int'], 'V8Js::executeString' => ['mixed', 'script'=>'string', 'identifier='=>'string', 'flags='=>'int'], 'V8Js::getExtensions' => ['string[]'], 'V8Js::getPendingException' => ['?V8JsException'], 'V8Js::registerExtension' => ['bool', 'extension_name'=>'string', 'script'=>'string', 'dependencies='=>'array', 'auto_enable='=>'bool'], 'V8Js::setAverageObjectSize' => ['', 'average_object_size'=>'int'], 'V8Js::setMemoryLimit' => ['', 'limit'=>'int'], 'V8Js::setModuleLoader' => ['', 'loader'=>'callable'], 'V8Js::setModuleNormaliser' => ['', 'normaliser'=>'callable'], 'V8Js::setTimeLimit' => ['', 'limit'=>'int'], 'V8JsException::getJsFileName' => ['string'], 'V8JsException::getJsLineNumber' => ['int'], 'V8JsException::getJsSourceLine' => ['int'], 'V8JsException::getJsTrace' => ['string'], 'V8JsScriptException::__clone' => ['void'], 'V8JsScriptException::__construct' => ['void', 'message='=>'string', 'code='=>'int', 'previous='=>'?Exception|?Throwable'], 'V8JsScriptException::__toString' => ['string'], 'V8JsScriptException::__wakeup' => ['void'], 'V8JsScriptException::getCode' => ['int'], 'V8JsScriptException::getFile' => ['string'], 'V8JsScriptException::getJsEndColumn' => ['int'], 'V8JsScriptException::getJsFileName' => ['string'], 'V8JsScriptException::getJsLineNumber' => ['int'], 'V8JsScriptException::getJsSourceLine' => ['string'], 'V8JsScriptException::getJsStartColumn' => ['int'], 'V8JsScriptException::getJsTrace' => ['string'], 'V8JsScriptException::getLine' => ['int'], 'V8JsScriptException::getMessage' => ['string'], 'V8JsScriptException::getPrevious' => ['Exception|Throwable'], 'V8JsScriptException::getTrace' => ['list\',args?:array}>'], 'V8JsScriptException::getTraceAsString' => ['string'], 'var_dump' => ['void', 'value'=>'mixed', '...values='=>'mixed'], 'var_export' => ['?string', 'value'=>'mixed', 'return='=>'bool'], 'VARIANT::__construct' => ['void', 'value='=>'mixed', 'type='=>'int', 'codepage='=>'int'], 'variant_abs' => ['mixed', 'value'=>'mixed'], 'variant_add' => ['mixed', 'left'=>'mixed', 'right'=>'mixed'], 'variant_and' => ['mixed', 'left'=>'mixed', 'right'=>'mixed'], 'variant_cast' => ['VARIANT', 'variant'=>'VARIANT', 'type'=>'int'], 'variant_cat' => ['mixed', 'left'=>'mixed', 'right'=>'mixed'], 'variant_cmp' => ['int', 'left'=>'mixed', 'right'=>'mixed', 'locale_id='=>'int', 'flags='=>'int'], 'variant_date_from_timestamp' => ['VARIANT', 'timestamp'=>'int'], 'variant_date_to_timestamp' => ['int', 'variant'=>'VARIANT'], 'variant_div' => ['mixed', 'left'=>'mixed', 'right'=>'mixed'], 'variant_eqv' => ['mixed', 'left'=>'mixed', 'right'=>'mixed'], 'variant_fix' => ['mixed', 'value'=>'mixed'], 'variant_get_type' => ['int', 'variant'=>'VARIANT'], 'variant_idiv' => ['mixed', 'left'=>'mixed', 'right'=>'mixed'], 'variant_imp' => ['mixed', 'left'=>'mixed', 'right'=>'mixed'], 'variant_int' => ['mixed', 'value'=>'mixed'], 'variant_mod' => ['mixed', 'left'=>'mixed', 'right'=>'mixed'], 'variant_mul' => ['mixed', 'left'=>'mixed', 'right'=>'mixed'], 'variant_neg' => ['mixed', 'value'=>'mixed'], 'variant_not' => ['mixed', 'value'=>'mixed'], 'variant_or' => ['mixed', 'left'=>'mixed', 'right'=>'mixed'], 'variant_pow' => ['mixed', 'left'=>'mixed', 'right'=>'mixed'], 'variant_round' => ['mixed', 'value'=>'mixed', 'decimals'=>'int'], 'variant_set' => ['void', 'variant'=>'object', 'value'=>'mixed'], 'variant_set_type' => ['void', 'variant'=>'object', 'type'=>'int'], 'variant_sub' => ['mixed', 'left'=>'mixed', 'right'=>'mixed'], 'variant_xor' => ['mixed', 'left'=>'mixed', 'right'=>'mixed'], 'VarnishAdmin::__construct' => ['void', 'args='=>'array'], 'VarnishAdmin::auth' => ['bool'], 'VarnishAdmin::ban' => ['int', 'vcl_regex'=>'string'], 'VarnishAdmin::banUrl' => ['int', 'vcl_regex'=>'string'], 'VarnishAdmin::clearPanic' => ['int'], 'VarnishAdmin::connect' => ['bool'], 'VarnishAdmin::disconnect' => ['bool'], 'VarnishAdmin::getPanic' => ['string'], 'VarnishAdmin::getParams' => ['array'], 'VarnishAdmin::isRunning' => ['bool'], 'VarnishAdmin::setCompat' => ['void', 'compat'=>'int'], 'VarnishAdmin::setHost' => ['void', 'host'=>'string'], 'VarnishAdmin::setIdent' => ['void', 'ident'=>'string'], 'VarnishAdmin::setParam' => ['int', 'name'=>'string', 'value'=>'string|int'], 'VarnishAdmin::setPort' => ['void', 'port'=>'int'], 'VarnishAdmin::setSecret' => ['void', 'secret'=>'string'], 'VarnishAdmin::setTimeout' => ['void', 'timeout'=>'int'], 'VarnishAdmin::start' => ['int'], 'VarnishAdmin::stop' => ['int'], 'VarnishLog::__construct' => ['void', 'args='=>'array'], 'VarnishLog::getLine' => ['array'], 'VarnishLog::getTagName' => ['string', 'index'=>'int'], 'VarnishStat::__construct' => ['void', 'args='=>'array'], 'VarnishStat::getSnapshot' => ['array'], 'version_compare' => ['bool', 'version1'=>'string', 'version2'=>'string', 'operator'=>'\'<\'|\'lt\'|\'<=\'|\'le\'|\'>\'|\'gt\'|\'>=\'|\'ge\'|\'==\'|\'=\'|\'eq\'|\'!=\'|\'<>\'|\'ne\''], 'version_compare\'1' => ['int', 'version1'=>'string', 'version2'=>'string'], 'vfprintf' => ['int<0, max>', 'stream'=>'resource', 'format'=>'string', 'values'=>'array'], 'virtual' => ['bool', 'uri'=>'string'], 'vpopmail_add_alias_domain' => ['bool', 'domain'=>'string', 'aliasdomain'=>'string'], 'vpopmail_add_alias_domain_ex' => ['bool', 'olddomain'=>'string', 'newdomain'=>'string'], 'vpopmail_add_domain' => ['bool', 'domain'=>'string', 'dir'=>'string', 'uid'=>'int', 'gid'=>'int'], 'vpopmail_add_domain_ex' => ['bool', 'domain'=>'string', 'passwd'=>'string', 'quota='=>'string', 'bounce='=>'string', 'apop='=>'bool'], 'vpopmail_add_user' => ['bool', 'user'=>'string', 'domain'=>'string', 'password'=>'string', 'gecos='=>'string', 'apop='=>'bool'], 'vpopmail_alias_add' => ['bool', 'user'=>'string', 'domain'=>'string', 'alias'=>'string'], 'vpopmail_alias_del' => ['bool', 'user'=>'string', 'domain'=>'string'], 'vpopmail_alias_del_domain' => ['bool', 'domain'=>'string'], 'vpopmail_alias_get' => ['array', 'alias'=>'string', 'domain'=>'string'], 'vpopmail_alias_get_all' => ['array', 'domain'=>'string'], 'vpopmail_auth_user' => ['bool', 'user'=>'string', 'domain'=>'string', 'password'=>'string', 'apop='=>'string'], 'vpopmail_del_domain' => ['bool', 'domain'=>'string'], 'vpopmail_del_domain_ex' => ['bool', 'domain'=>'string'], 'vpopmail_del_user' => ['bool', 'user'=>'string', 'domain'=>'string'], 'vpopmail_error' => ['string'], 'vpopmail_passwd' => ['bool', 'user'=>'string', 'domain'=>'string', 'password'=>'string', 'apop='=>'bool'], 'vpopmail_set_user_quota' => ['bool', 'user'=>'string', 'domain'=>'string', 'quota'=>'string'], 'vprintf' => ['int<0, max>', 'format'=>'string', 'values'=>'array'], 'vsprintf' => ['string', 'format'=>'string', 'values'=>'array'], 'Vtiful\Kernel\Chart::__construct' => ['void', 'handle'=>'resource', 'type'=>'int'], 'Vtiful\Kernel\Chart::axisNameX' => ['Vtiful\Kernel\Chart', 'name'=>'string'], 'Vtiful\Kernel\Chart::axisNameY' => ['Vtiful\Kernel\Chart', 'name'=>'string'], 'Vtiful\Kernel\Chart::legendSetPosition' => ['Vtiful\Kernel\Chart', 'type'=>'int'], 'Vtiful\Kernel\Chart::series' => ['Vtiful\Kernel\Chart', 'value'=>'string', 'categories='=>'string'], 'Vtiful\Kernel\Chart::seriesName' => ['Vtiful\Kernel\Chart', 'value'=>'string'], 'Vtiful\Kernel\Chart::style' => ['Vtiful\Kernel\Chart', 'style'=>'int'], 'Vtiful\Kernel\Chart::title' => ['Vtiful\Kernel\Chart', 'title'=>'string'], 'Vtiful\Kernel\Chart::toResource' => ['resource'], 'Vtiful\Kernel\Excel::__construct' => ['void', 'config'=>'array'], 'Vtiful\Kernel\Excel::activateSheet' => ['bool', 'sheet_name'=>'string'], 'Vtiful\Kernel\Excel::addSheet' => ['Vtiful\Kernel\Excel', 'sheet_name='=>'?string'], 'Vtiful\Kernel\Excel::autoFilter' => ['Vtiful\Kernel\Excel', 'range'=>'string'], 'Vtiful\Kernel\Excel::checkoutSheet' => ['Vtiful\Kernel\Excel', 'sheet_name'=>'string'], 'Vtiful\Kernel\Excel::close' => ['Vtiful\Kernel\Excel'], 'Vtiful\Kernel\Excel::columnIndexFromString' => ['int', 'index'=>'string'], 'Vtiful\Kernel\Excel::constMemory' => ['Vtiful\Kernel\Excel', 'file_name'=>'string', 'sheet_name='=>'?string'], 'Vtiful\Kernel\Excel::data' => ['Vtiful\Kernel\Excel', 'data'=>'array'], 'Vtiful\Kernel\Excel::defaultFormat' => ['Vtiful\Kernel\Excel', 'format_handle'=>'resource'], 'Vtiful\Kernel\Excel::existSheet' => ['bool', 'sheet_name'=>'string'], 'Vtiful\Kernel\Excel::fileName' => ['Vtiful\Kernel\Excel', 'file_name'=>'string', 'sheet_name='=>'?string'], 'Vtiful\Kernel\Excel::freezePanes' => ['Vtiful\Kernel\Excel', 'row'=>'int', 'column'=>'int'], 'Vtiful\Kernel\Excel::getHandle' => ['resource'], 'Vtiful\Kernel\Excel::getSheetData' => ['array|false'], 'Vtiful\Kernel\Excel::gridline' => ['Vtiful\Kernel\Excel', 'option='=>'int'], 'Vtiful\Kernel\Excel::header' => ['Vtiful\Kernel\Excel', 'header'=>'array', 'format_handle='=>'?resource'], 'Vtiful\Kernel\Excel::insertChart' => ['Vtiful\Kernel\Excel', 'row'=>'int', 'column'=>'int', 'chart_resource'=>'resource'], 'Vtiful\Kernel\Excel::insertComment' => ['Vtiful\Kernel\Excel', 'row'=>'int', 'column'=>'int', 'comment'=>'string'], 'Vtiful\Kernel\Excel::insertDate' => ['Vtiful\Kernel\Excel', 'row'=>'int', 'column'=>'int', 'timestamp'=>'int', 'format='=>'?string', 'format_handle='=>'?resource'], 'Vtiful\Kernel\Excel::insertFormula' => ['Vtiful\Kernel\Excel', 'row'=>'int', 'column'=>'int', 'formula'=>'string', 'format_handle='=>'?resource'], 'Vtiful\Kernel\Excel::insertImage' => ['Vtiful\Kernel\Excel', 'row'=>'int', 'column'=>'int', 'image'=>'string', 'width='=>'?float', 'height='=>'?float'], 'Vtiful\Kernel\Excel::insertText' => ['Vtiful\Kernel\Excel', 'row'=>'int', 'column'=>'int', 'data'=>'int|string|double', 'format='=>'?string', 'format_handle='=>'?resource'], 'Vtiful\Kernel\Excel::insertUrl' => ['Vtiful\Kernel\Excel', 'row'=>'int', 'column'=>'int', 'url'=>'string', 'text='=>'?string', 'tool_tip='=>'?string', 'format='=>'?resource'], 'Vtiful\Kernel\Excel::mergeCells' => ['Vtiful\Kernel\Excel', 'range'=>'string', 'data'=>'string', 'format_handle='=>'?resource'], 'Vtiful\Kernel\Excel::nextCellCallback' => ['void', 'fci'=>'callable(int,int,mixed)', 'sheet_name='=>'?string'], 'Vtiful\Kernel\Excel::nextRow' => ['array|false', 'zv_type_t='=>'?array'], 'Vtiful\Kernel\Excel::openFile' => ['Vtiful\Kernel\Excel', 'zs_file_name'=>'string'], 'Vtiful\Kernel\Excel::openSheet' => ['Vtiful\Kernel\Excel', 'zs_sheet_name='=>'?string', 'zl_flag='=>'?int'], 'Vtiful\Kernel\Excel::output' => ['string'], 'Vtiful\Kernel\Excel::protection' => ['Vtiful\Kernel\Excel', 'password='=>'?string'], 'Vtiful\Kernel\Excel::putCSV' => ['bool', 'fp'=>'resource', 'delimiter_str='=>'?string', 'enclosure_str='=>'?string', 'escape_str='=>'?string'], 'Vtiful\Kernel\Excel::putCSVCallback' => ['bool', 'callback'=>'callable(array):array', 'fp'=>'resource', 'delimiter_str='=>'?string', 'enclosure_str='=>'?string', 'escape_str='=>'?string'], 'Vtiful\Kernel\Excel::setColumn' => ['Vtiful\Kernel\Excel', 'range'=>'string', 'width'=>'float', 'format_handle='=>'?resource'], 'Vtiful\Kernel\Excel::setCurrentSheetHide' => ['Vtiful\Kernel\Excel'], 'Vtiful\Kernel\Excel::setCurrentSheetIsFirst' => ['Vtiful\Kernel\Excel'], 'Vtiful\Kernel\Excel::setGlobalType' => ['Vtiful\Kernel\Excel', 'zv_type_t'=>'int'], 'Vtiful\Kernel\Excel::setLandscape' => ['Vtiful\Kernel\Excel'], 'Vtiful\Kernel\Excel::setMargins' => ['Vtiful\Kernel\Excel', 'left='=>'?float', 'right='=>'?float', 'top='=>'?float', 'bottom='=>'?float'], 'Vtiful\Kernel\Excel::setPaper' => ['Vtiful\Kernel\Excel', 'paper'=>'int'], 'Vtiful\Kernel\Excel::setPortrait' => ['Vtiful\Kernel\Excel'], 'Vtiful\Kernel\Excel::setRow' => ['Vtiful\Kernel\Excel', 'range'=>'string', 'height'=>'float', 'format_handle='=>'?resource'], 'Vtiful\Kernel\Excel::setSkipRows' => ['Vtiful\Kernel\Excel', 'zv_skip_t'=>'int'], 'Vtiful\Kernel\Excel::setType' => ['Vtiful\Kernel\Excel', 'zv_type_t'=>'array'], 'Vtiful\Kernel\Excel::sheetList' => ['array'], 'Vtiful\Kernel\Excel::showComment' => ['Vtiful\Kernel\Excel'], 'Vtiful\Kernel\Excel::stringFromColumnIndex' => ['string', 'index'=>'int'], 'Vtiful\Kernel\Excel::timestampFromDateDouble' => ['int', 'index'=>'?float'], 'Vtiful\Kernel\Excel::validation' => ['Vtiful\Kernel\Excel', 'range'=>'string', 'validation_resource'=>'resource'], 'Vtiful\Kernel\Excel::zoom' => ['Vtiful\Kernel\Excel', 'scale'=>'int'], 'Vtiful\Kernel\Format::__construct' => ['void', 'handle'=>'resource'], 'Vtiful\Kernel\Format::align' => ['Vtiful\Kernel\Format', '...style'=>'int'], 'Vtiful\Kernel\Format::background' => ['Vtiful\Kernel\Format', 'color'=>'int', 'pattern='=>'int'], 'Vtiful\Kernel\Format::bold' => ['Vtiful\Kernel\Format'], 'Vtiful\Kernel\Format::border' => ['Vtiful\Kernel\Format', 'style'=>'int'], 'Vtiful\Kernel\Format::font' => ['Vtiful\Kernel\Format', 'font'=>'string'], 'Vtiful\Kernel\Format::fontColor' => ['Vtiful\Kernel\Format', 'color'=>'int'], 'Vtiful\Kernel\Format::fontSize' => ['Vtiful\Kernel\Format', 'size'=>'float'], 'Vtiful\Kernel\Format::italic' => ['Vtiful\Kernel\Format'], 'Vtiful\Kernel\Format::number' => ['Vtiful\Kernel\Format', 'format'=>'string'], 'Vtiful\Kernel\Format::strikeout' => ['Vtiful\Kernel\Format'], 'Vtiful\Kernel\Format::toResource' => ['resource'], 'Vtiful\Kernel\Format::underline' => ['Vtiful\Kernel\Format', 'style'=>'int'], 'Vtiful\Kernel\Format::unlocked' => ['Vtiful\Kernel\Format'], 'Vtiful\Kernel\Format::wrap' => ['Vtiful\Kernel\Format'], 'Vtiful\Kernel\Validation::__construct' => ['void'], 'Vtiful\Kernel\Validation::criteriaType' => ['?Vtiful\Kernel\Validation', 'type'=>'int'], 'Vtiful\Kernel\Validation::maximumFormula' => ['?Vtiful\Kernel\Validation', 'maximum_formula'=>'string'], 'Vtiful\Kernel\Validation::maximumNumber' => ['?Vtiful\Kernel\Validation', 'maximum_number'=>'float'], 'Vtiful\Kernel\Validation::minimumFormula' => ['?Vtiful\Kernel\Validation', 'minimum_formula'=>'string'], 'Vtiful\Kernel\Validation::minimumNumber' => ['?Vtiful\Kernel\Validation', 'minimum_number'=>'float'], 'Vtiful\Kernel\Validation::toResource' => ['resource'], 'Vtiful\Kernel\Validation::validationType' => ['?Vtiful\Kernel\Validation', 'type'=>'int'], 'Vtiful\Kernel\Validation::valueList' => ['?Vtiful\Kernel\Validation', 'value_list'=>'array'], 'Vtiful\Kernel\Validation::valueNumber' => ['?Vtiful\Kernel\Validation', 'value_number'=>'int'], 'w32api_deftype' => ['bool', 'typename'=>'string', 'member1_type'=>'string', 'member1_name'=>'string', '...args='=>'string'], 'w32api_init_dtype' => ['resource', 'typename'=>'string', 'value'=>'', '...args='=>''], 'w32api_invoke_function' => ['', 'funcname'=>'string', 'argument'=>'', '...args='=>''], 'w32api_register_function' => ['bool', 'library'=>'string', 'function_name'=>'string', 'return_type'=>'string'], 'w32api_set_call_method' => ['', 'method'=>'int'], 'wddx_add_vars' => ['bool', 'packet_id'=>'resource', 'var_names'=>'mixed', '...vars='=>'mixed'], 'wddx_deserialize' => ['mixed', 'packet'=>'string'], 'wddx_packet_end' => ['string', 'packet_id'=>'resource'], 'wddx_packet_start' => ['resource|false', 'comment='=>'string'], 'wddx_serialize_value' => ['string|false', 'value'=>'mixed', 'comment='=>'string'], 'wddx_serialize_vars' => ['string|false', 'var_name'=>'mixed', '...vars='=>'mixed'], 'WeakMap::count' => ['int'], 'WeakMap::getIterator' => ['Iterator'], 'WeakMap::offsetExists' => ['bool', 'object'=>'object'], 'WeakMap::offsetGet' => ['mixed', 'object'=>'object'], 'WeakMap::offsetSet' => ['void', 'object'=>'object', 'value'=>'mixed'], 'WeakMap::offsetUnset' => ['void', 'object'=>'object'], 'Weakref::acquire' => ['bool'], 'Weakref::get' => ['object'], 'Weakref::release' => ['bool'], 'Weakref::valid' => ['bool'], 'webObj::convertToString' => ['string'], 'webObj::free' => ['void'], 'webObj::set' => ['int', 'property_name'=>'string', 'new_value'=>''], 'webObj::updateFromString' => ['int', 'snippet'=>'string'], 'win32_continue_service' => ['int|false', 'servicename'=>'string', 'machine='=>'string'], 'win32_create_service' => ['int|false', 'details'=>'array', 'machine='=>'string'], 'win32_delete_service' => ['int|false', 'servicename'=>'string', 'machine='=>'string'], 'win32_get_last_control_message' => ['int'], 'win32_pause_service' => ['int|false', 'servicename'=>'string', 'machine='=>'string'], 'win32_ps_list_procs' => ['array'], 'win32_ps_stat_mem' => ['array'], 'win32_ps_stat_proc' => ['array', 'pid='=>'int'], 'win32_query_service_status' => ['array|false|int', 'servicename'=>'string', 'machine='=>'string'], 'win32_send_custom_control' => ['int', 'servicename'=>'string', 'control'=>'int', 'machine='=>'string'], 'win32_set_service_exit_code' => ['int', 'exitCode='=>'int'], 'win32_set_service_exit_mode' => ['bool', 'gracefulMode='=>'bool'], 'win32_set_service_status' => ['bool|int', 'status'=>'int', 'checkpoint='=>'int'], 'win32_start_service' => ['int|false', 'servicename'=>'string', 'machine='=>'string'], 'win32_start_service_ctrl_dispatcher' => ['bool|int', 'name'=>'string'], 'win32_stop_service' => ['int|false', 'servicename'=>'string', 'machine='=>'string'], 'wincache_fcache_fileinfo' => ['array|false', 'summaryonly='=>'bool'], 'wincache_fcache_meminfo' => ['array|false'], 'wincache_lock' => ['bool', 'key'=>'string', 'isglobal='=>'bool'], 'wincache_ocache_fileinfo' => ['array|false', 'summaryonly='=>'bool'], 'wincache_ocache_meminfo' => ['array|false'], 'wincache_refresh_if_changed' => ['bool', 'files='=>'array'], 'wincache_rplist_fileinfo' => ['array|false', 'summaryonly='=>'bool'], 'wincache_rplist_meminfo' => ['array|false'], 'wincache_scache_info' => ['array|false', 'summaryonly='=>'bool'], 'wincache_scache_meminfo' => ['array|false'], 'wincache_ucache_add' => ['bool', 'key'=>'string', 'value'=>'mixed', 'ttl='=>'int'], 'wincache_ucache_add\'1' => ['bool', 'values'=>'array', 'unused='=>'', 'ttl='=>'int'], 'wincache_ucache_cas' => ['bool', 'key'=>'string', 'old_value'=>'int', 'new_value'=>'int'], 'wincache_ucache_clear' => ['bool'], 'wincache_ucache_dec' => ['int|false', 'key'=>'string', 'dec_by='=>'int', 'success='=>'bool'], 'wincache_ucache_delete' => ['bool', 'key'=>'mixed'], 'wincache_ucache_exists' => ['bool', 'key'=>'string'], 'wincache_ucache_get' => ['mixed', 'key'=>'mixed', '&w_success='=>'bool'], 'wincache_ucache_inc' => ['int|false', 'key'=>'string', 'inc_by='=>'int', 'success='=>'bool'], 'wincache_ucache_info' => ['array|false', 'summaryonly='=>'bool', 'key='=>'string'], 'wincache_ucache_meminfo' => ['array|false'], 'wincache_ucache_set' => ['bool', 'key'=>'', 'value'=>'', 'ttl='=>'int'], 'wincache_ucache_set\'1' => ['bool', 'values'=>'array', 'unused='=>'', 'ttl='=>'int'], 'wincache_unlock' => ['bool', 'key'=>'string'], 'wkhtmltox\image\converter::convert' => ['?string'], 'wkhtmltox\image\converter::getVersion' => ['string'], 'wkhtmltox\pdf\converter::add' => ['void', 'object'=>'wkhtmltox\PDF\Object'], 'wkhtmltox\pdf\converter::convert' => ['?string'], 'wkhtmltox\pdf\converter::getVersion' => ['string'], 'wordwrap' => ['string', 'string'=>'string', 'width='=>'int', 'break='=>'string', 'cut_long_words='=>'bool'], 'Worker::__construct' => ['void'], 'Worker::addRef' => ['void'], 'Worker::chunk' => ['array', 'size'=>'int', 'preserve'=>'bool'], 'Worker::collect' => ['int', 'collector='=>'Callable'], 'Worker::count' => ['int'], 'Worker::delRef' => ['void'], 'Worker::detach' => ['void'], 'Worker::extend' => ['bool', 'class'=>'string'], 'Worker::getCreatorId' => ['int'], 'Worker::getCurrentThread' => ['Thread'], 'Worker::getCurrentThreadId' => ['int'], 'Worker::getRefCount' => ['int'], 'Worker::getStacked' => ['int'], 'Worker::getTerminationInfo' => ['array'], 'Worker::getThreadId' => ['int'], 'Worker::globally' => ['mixed'], 'Worker::isGarbage' => ['bool'], 'Worker::isJoined' => ['bool'], 'Worker::isRunning' => ['bool'], 'Worker::isShutdown' => ['bool'], 'Worker::isStarted' => ['bool'], 'Worker::isTerminated' => ['bool'], 'Worker::isWaiting' => ['bool'], 'Worker::isWorking' => ['bool'], 'Worker::join' => ['bool'], 'Worker::kill' => ['bool'], 'Worker::lock' => ['bool'], 'Worker::merge' => ['bool', 'from'=>'', 'overwrite='=>'mixed'], 'Worker::notify' => ['bool'], 'Worker::notifyOne' => ['bool'], 'Worker::offsetExists' => ['bool', 'offset'=>'int|string'], 'Worker::offsetGet' => ['mixed', 'offset'=>'int|string'], 'Worker::offsetSet' => ['void', 'offset'=>'int|string|null', 'value'=>'mixed'], 'Worker::offsetUnset' => ['void', 'offset'=>'int|string'], 'Worker::pop' => ['bool'], 'Worker::run' => ['void'], 'Worker::setGarbage' => ['void'], 'Worker::shift' => ['bool'], 'Worker::shutdown' => ['bool'], 'Worker::stack' => ['int', '&rw_work'=>'Threaded'], 'Worker::start' => ['bool', 'options='=>'int'], 'Worker::synchronized' => ['mixed', 'block'=>'Closure', '_='=>'mixed'], 'Worker::unlock' => ['bool'], 'Worker::unstack' => ['int', '&rw_work='=>'Threaded'], 'Worker::wait' => ['bool', 'timeout='=>'int'], 'xattr_get' => ['string', 'filename'=>'string', 'name'=>'string', 'flags='=>'int'], 'xattr_list' => ['array', 'filename'=>'string', 'flags='=>'int'], 'xattr_remove' => ['bool', 'filename'=>'string', 'name'=>'string', 'flags='=>'int'], 'xattr_set' => ['bool', 'filename'=>'string', 'name'=>'string', 'value'=>'string', 'flags='=>'int'], 'xattr_supported' => ['bool', 'filename'=>'string', 'flags='=>'int'], 'xcache_asm' => ['string', 'filename'=>'string'], 'xcache_clear_cache' => ['void', 'type'=>'int', 'id='=>'int'], 'xcache_coredump' => ['string', 'op_type'=>'int'], 'xcache_count' => ['int', 'type'=>'int'], 'xcache_coverager_decode' => ['array', 'data'=>'string'], 'xcache_coverager_get' => ['array', 'clean='=>'bool'], 'xcache_coverager_start' => ['void', 'clean='=>'bool'], 'xcache_coverager_stop' => ['void', 'clean='=>'bool'], 'xcache_dasm_file' => ['string', 'filename'=>'string'], 'xcache_dasm_string' => ['string', 'code'=>'string'], 'xcache_dec' => ['int', 'name'=>'string', 'value='=>'int|mixed', 'ttl='=>'int'], 'xcache_decode' => ['bool', 'filename'=>'string'], 'xcache_encode' => ['string', 'filename'=>'string'], 'xcache_get' => ['mixed', 'name'=>'string'], 'xcache_get_data_type' => ['string', 'type'=>'int'], 'xcache_get_op_spec' => ['string', 'op_type'=>'int'], 'xcache_get_op_type' => ['string', 'op_type'=>'int'], 'xcache_get_opcode' => ['string', 'opcode'=>'int'], 'xcache_get_opcode_spec' => ['string', 'opcode'=>'int'], 'xcache_inc' => ['int', 'name'=>'string', 'value='=>'int|mixed', 'ttl='=>'int'], 'xcache_info' => ['array', 'type'=>'int', 'id'=>'int'], 'xcache_is_autoglobal' => ['string', 'name'=>'string'], 'xcache_isset' => ['bool', 'name'=>'string'], 'xcache_list' => ['array', 'type'=>'int', 'id'=>'int'], 'xcache_set' => ['bool', 'name'=>'string', 'value'=>'mixed', 'ttl='=>'int'], 'xcache_unset' => ['bool', 'name'=>'string'], 'xcache_unset_by_prefix' => ['bool', 'prefix'=>'string'], 'Xcom::__construct' => ['void', 'fabric_url='=>'string', 'fabric_token='=>'string', 'capability_token='=>'string'], 'Xcom::decode' => ['object', 'avro_msg'=>'string', 'json_schema'=>'string'], 'Xcom::encode' => ['string', 'data'=>'stdClass', 'avro_schema'=>'string'], 'Xcom::getDebugOutput' => ['string'], 'Xcom::getLastResponse' => ['string'], 'Xcom::getLastResponseInfo' => ['array'], 'Xcom::getOnboardingURL' => ['string', 'capability_name'=>'string', 'agreement_url'=>'string'], 'Xcom::send' => ['int', 'topic'=>'string', 'data'=>'mixed', 'json_schema='=>'string', 'http_headers='=>'array'], 'Xcom::sendAsync' => ['int', 'topic'=>'string', 'data'=>'mixed', 'json_schema='=>'string', 'http_headers='=>'array'], 'xdebug_break' => ['bool'], 'xdebug_call_class' => ['string', 'depth='=>'int'], 'xdebug_call_file' => ['string', 'depth='=>'int'], 'xdebug_call_function' => ['string', 'depth='=>'int'], 'xdebug_call_line' => ['int', 'depth='=>'int'], 'xdebug_clear_aggr_profiling_data' => ['bool'], 'xdebug_code_coverage_started' => ['bool'], 'xdebug_debug_zval' => ['void', '...varName'=>'string'], 'xdebug_debug_zval_stdout' => ['void', '...varName'=>'string'], 'xdebug_disable' => ['void'], 'xdebug_dump_aggr_profiling_data' => ['bool'], 'xdebug_dump_superglobals' => ['void'], 'xdebug_enable' => ['void'], 'xdebug_get_code_coverage' => ['array'], 'xdebug_get_collected_errors' => ['string', 'clean='=>'bool'], 'xdebug_get_declared_vars' => ['array'], 'xdebug_get_formatted_function_stack' => [''], 'xdebug_get_function_count' => ['int'], 'xdebug_get_function_stack' => ['array', 'message='=>'string', 'options='=>'int'], 'xdebug_get_headers' => ['array'], 'xdebug_get_monitored_functions' => ['array'], 'xdebug_get_profiler_filename' => ['string|false'], 'xdebug_get_stack_depth' => ['int'], 'xdebug_get_tracefile_name' => ['string'], 'xdebug_info' => ['mixed', 'category='=>'string'], 'xdebug_is_debugger_active' => ['bool'], 'xdebug_is_enabled' => ['bool'], 'xdebug_memory_usage' => ['int'], 'xdebug_peak_memory_usage' => ['int'], 'xdebug_print_function_stack' => ['array', 'message='=>'string', 'options='=>'int'], 'xdebug_set_filter' => ['void', 'group'=>'int', 'list_type'=>'int', 'configuration'=>'array'], 'xdebug_start_code_coverage' => ['void', 'options='=>'int'], 'xdebug_start_error_collection' => ['void'], 'xdebug_start_function_monitor' => ['void', 'list_of_functions_to_monitor'=>'string[]'], 'xdebug_start_trace' => ['void', 'trace_file'=>'', 'options='=>'int|mixed'], 'xdebug_stop_code_coverage' => ['void', 'cleanup='=>'bool'], 'xdebug_stop_error_collection' => ['void'], 'xdebug_stop_function_monitor' => ['void'], 'xdebug_stop_trace' => ['void'], 'xdebug_time_index' => ['float'], 'xdebug_var_dump' => ['void', '...var'=>''], 'xdiff_file_bdiff' => ['bool', 'old_file'=>'string', 'new_file'=>'string', 'dest'=>'string'], 'xdiff_file_bdiff_size' => ['int', 'file'=>'string'], 'xdiff_file_bpatch' => ['bool', 'file'=>'string', 'patch'=>'string', 'dest'=>'string'], 'xdiff_file_diff' => ['bool', 'old_file'=>'string', 'new_file'=>'string', 'dest'=>'string', 'context='=>'int', 'minimal='=>'bool'], 'xdiff_file_diff_binary' => ['bool', 'old_file'=>'string', 'new_file'=>'string', 'dest'=>'string'], 'xdiff_file_merge3' => ['mixed', 'old_file'=>'string', 'new_file1'=>'string', 'new_file2'=>'string', 'dest'=>'string'], 'xdiff_file_patch' => ['mixed', 'file'=>'string', 'patch'=>'string', 'dest'=>'string', 'flags='=>'int'], 'xdiff_file_patch_binary' => ['bool', 'file'=>'string', 'patch'=>'string', 'dest'=>'string'], 'xdiff_file_rabdiff' => ['bool', 'old_file'=>'string', 'new_file'=>'string', 'dest'=>'string'], 'xdiff_string_bdiff' => ['string', 'old_data'=>'string', 'new_data'=>'string'], 'xdiff_string_bdiff_size' => ['int', 'patch'=>'string'], 'xdiff_string_bpatch' => ['string', 'string'=>'string', 'patch'=>'string'], 'xdiff_string_diff' => ['string', 'old_data'=>'string', 'new_data'=>'string', 'context='=>'int', 'minimal='=>'bool'], 'xdiff_string_diff_binary' => ['string', 'old_data'=>'string', 'new_data'=>'string'], 'xdiff_string_merge3' => ['mixed', 'old_data'=>'string', 'new_data1'=>'string', 'new_data2'=>'string', 'error='=>'string'], 'xdiff_string_patch' => ['string', 'string'=>'string', 'patch'=>'string', 'flags='=>'int', '&w_error='=>'string'], 'xdiff_string_patch_binary' => ['string', 'string'=>'string', 'patch'=>'string'], 'xdiff_string_rabdiff' => ['string', 'old_data'=>'string', 'new_data'=>'string'], 'xhprof_disable' => ['array'], 'xhprof_enable' => ['void', 'flags='=>'int', 'options='=>'array'], 'xhprof_sample_disable' => ['array'], 'xhprof_sample_enable' => ['void'], 'xlswriter_get_author' => ['string'], 'xlswriter_get_version' => ['string'], 'xml_error_string' => ['?string', 'error_code'=>'int'], 'xml_get_current_byte_index' => ['int', 'parser'=>'XMLParser'], 'xml_get_current_column_number' => ['int', 'parser'=>'XMLParser'], 'xml_get_current_line_number' => ['int', 'parser'=>'XMLParser'], 'xml_get_error_code' => ['int', 'parser'=>'XMLParser'], 'xml_parse' => ['int', 'parser'=>'XMLParser', 'data'=>'string', 'is_final='=>'bool'], 'xml_parse_into_struct' => ['int', 'parser'=>'XMLParser', 'data'=>'string', '&w_values'=>'array', '&w_index='=>'array'], 'xml_parser_create' => ['XMLParser', 'encoding='=>'?string'], 'xml_parser_create_ns' => ['XMLParser', 'encoding='=>'?string', 'separator='=>'string'], 'xml_parser_free' => ['bool', 'parser'=>'XMLParser'], 'xml_parser_get_option' => ['string|int', 'parser'=>'XMLParser', 'option'=>'int'], 'xml_parser_set_option' => ['bool', 'parser'=>'XMLParser', 'option'=>'int', 'value'=>'mixed'], 'xml_set_character_data_handler' => ['true', 'parser'=>'XMLParser', 'handler'=>'callable'], 'xml_set_default_handler' => ['true', 'parser'=>'XMLParser', 'handler'=>'callable'], 'xml_set_element_handler' => ['true', 'parser'=>'XMLParser', 'start_handler'=>'callable', 'end_handler'=>'callable'], 'xml_set_end_namespace_decl_handler' => ['true', 'parser'=>'XMLParser', 'handler'=>'callable'], 'xml_set_external_entity_ref_handler' => ['true', 'parser'=>'XMLParser', 'handler'=>'callable'], 'xml_set_notation_decl_handler' => ['true', 'parser'=>'XMLParser', 'handler'=>'callable'], 'xml_set_object' => ['true', 'parser'=>'XMLParser', 'object'=>'object'], 'xml_set_processing_instruction_handler' => ['true', 'parser'=>'XMLParser', 'handler'=>'callable'], 'xml_set_start_namespace_decl_handler' => ['true', 'parser'=>'XMLParser', 'handler'=>'callable'], 'xml_set_unparsed_entity_decl_handler' => ['true', 'parser'=>'XMLParser', 'handler'=>'callable'], 'XMLDiff\Base::__construct' => ['void', 'nsname'=>'string'], 'XMLDiff\Base::diff' => ['mixed', 'from'=>'mixed', 'to'=>'mixed'], 'XMLDiff\Base::merge' => ['mixed', 'src'=>'mixed', 'diff'=>'mixed'], 'XMLDiff\DOM::diff' => ['DOMDocument', 'from'=>'DOMDocument', 'to'=>'DOMDocument'], 'XMLDiff\DOM::merge' => ['DOMDocument', 'src'=>'DOMDocument', 'diff'=>'DOMDocument'], 'XMLDiff\File::diff' => ['string', 'from'=>'string', 'to'=>'string'], 'XMLDiff\File::merge' => ['string', 'src'=>'string', 'diff'=>'string'], 'XMLDiff\Memory::diff' => ['string', 'from'=>'string', 'to'=>'string'], 'XMLDiff\Memory::merge' => ['string', 'src'=>'string', 'diff'=>'string'], 'XMLReader::close' => ['bool'], 'XMLReader::expand' => ['DOMNode|false', 'baseNode='=>'?DOMNode'], 'XMLReader::getAttribute' => ['?string', 'name'=>'string'], 'XMLReader::getAttributeNo' => ['?string', 'index'=>'int'], 'XMLReader::getAttributeNs' => ['?string', 'name'=>'string', 'namespace'=>'string'], 'XMLReader::getParserProperty' => ['bool', 'property'=>'int'], 'XMLReader::isValid' => ['bool'], 'XMLReader::lookupNamespace' => ['?string', 'prefix'=>'string'], 'XMLReader::moveToAttribute' => ['bool', 'name'=>'string'], 'XMLReader::moveToAttributeNo' => ['bool', 'index'=>'int'], 'XMLReader::moveToAttributeNs' => ['bool', 'name'=>'string', 'namespace'=>'string'], 'XMLReader::moveToElement' => ['bool'], 'XMLReader::moveToFirstAttribute' => ['bool'], 'XMLReader::moveToNextAttribute' => ['bool'], 'XMLReader::next' => ['bool', 'name='=>'?string'], 'XMLReader::open' => ['bool|XmlReader', 'uri'=>'string', 'encoding='=>'?string', 'flags='=>'int'], 'XMLReader::read' => ['bool'], 'XMLReader::readInnerXML' => ['string'], 'XMLReader::readOuterXML' => ['string'], 'XMLReader::readString' => ['string'], 'XMLReader::setParserProperty' => ['bool', 'property'=>'int', 'value'=>'bool'], 'XMLReader::setRelaxNGSchema' => ['bool', 'filename'=>'?string'], 'XMLReader::setRelaxNGSchemaSource' => ['bool', 'source'=>'?string'], 'XMLReader::setSchema' => ['bool', 'filename'=>'?string'], 'XMLReader::XML' => ['bool|XMLReader', 'source'=>'string', 'encoding='=>'?string', 'flags='=>'int'], 'XMLWriter::endAttribute' => ['bool'], 'XMLWriter::endCdata' => ['bool'], 'XMLWriter::endComment' => ['bool'], 'XMLWriter::endDocument' => ['bool'], 'XMLWriter::endDtd' => ['bool'], 'XMLWriter::endDtdAttlist' => ['bool'], 'XMLWriter::endDtdElement' => ['bool'], 'XMLWriter::endDtdEntity' => ['bool'], 'XMLWriter::endElement' => ['bool'], 'XMLWriter::endPi' => ['bool'], 'XMLWriter::flush' => ['string|int', 'empty='=>'bool'], 'XMLWriter::fullEndElement' => ['bool'], 'XMLWriter::openMemory' => ['bool'], 'XMLWriter::openUri' => ['bool', 'uri'=>'string'], 'XMLWriter::outputMemory' => ['string', 'flush='=>'bool'], 'XMLWriter::setIndent' => ['bool', 'enable'=>'bool'], 'XMLWriter::setIndentString' => ['bool', 'indentation'=>'string'], 'XMLWriter::startAttribute' => ['bool', 'name'=>'string'], 'XMLWriter::startAttributeNs' => ['bool', 'prefix'=>'?string', 'name'=>'string', 'namespace'=>'?string'], 'XMLWriter::startCdata' => ['bool'], 'XMLWriter::startComment' => ['bool'], 'XMLWriter::startDocument' => ['bool', 'version='=>'?string', 'encoding='=>'?string', 'standalone='=>'?string'], 'XMLWriter::startDtd' => ['bool', 'qualifiedName'=>'string', 'publicId='=>'?string', 'systemId='=>'?string'], 'XMLWriter::startDtdAttlist' => ['bool', 'name'=>'string'], 'XMLWriter::startDtdElement' => ['bool', 'qualifiedName'=>'string'], 'XMLWriter::startDtdEntity' => ['bool', 'name'=>'string', 'isParam'=>'bool'], 'XMLWriter::startElement' => ['bool', 'name'=>'string'], 'XMLWriter::startElementNs' => ['bool', 'prefix'=>'?string', 'name'=>'string', 'namespace'=>'?string'], 'XMLWriter::startPi' => ['bool', 'target'=>'string'], 'XMLWriter::text' => ['bool', 'content'=>'string'], 'XMLWriter::writeAttribute' => ['bool', 'name'=>'string', 'value'=>'string'], 'XMLWriter::writeAttributeNs' => ['bool', 'prefix'=>'?string', 'name'=>'string', 'namespace'=>'?string', 'value'=>'string'], 'XMLWriter::writeCdata' => ['bool', 'content'=>'string'], 'XMLWriter::writeComment' => ['bool', 'content'=>'string'], 'XMLWriter::writeDtd' => ['bool', 'name'=>'string', 'publicId='=>'?string', 'systemId='=>'?string', 'content='=>'?string'], 'XMLWriter::writeDtdAttlist' => ['bool', 'name'=>'string', 'content'=>'string'], 'XMLWriter::writeDtdElement' => ['bool', 'name'=>'string', 'content'=>'string'], 'XMLWriter::writeDtdEntity' => ['bool', 'name'=>'string', 'content'=>'string', 'isParam='=>'bool', 'publicId='=>'?string', 'systemId='=>'?string', 'notationData='=>'?string'], 'XMLWriter::writeElement' => ['bool', 'name'=>'string', 'content='=>'?string'], 'XMLWriter::writeElementNs' => ['bool', 'prefix'=>'?string', 'name'=>'string', 'namespace'=>'?string', 'content='=>'?string'], 'XMLWriter::writePi' => ['bool', 'target'=>'string', 'content'=>'string'], 'XMLWriter::writeRaw' => ['bool', 'content'=>'string'], 'xmlwriter_end_attribute' => ['bool', 'writer'=>'XMLWriter'], 'xmlwriter_end_cdata' => ['bool', 'writer'=>'XMLWriter'], 'xmlwriter_end_comment' => ['bool', 'writer'=>'XMLWriter'], 'xmlwriter_end_document' => ['bool', 'writer'=>'XMLWriter'], 'xmlwriter_end_dtd' => ['bool', 'writer'=>'XMLWriter'], 'xmlwriter_end_dtd_attlist' => ['bool', 'writer'=>'XMLWriter'], 'xmlwriter_end_dtd_element' => ['bool', 'writer'=>'XMLWriter'], 'xmlwriter_end_dtd_entity' => ['bool', 'writer'=>'XMLWriter'], 'xmlwriter_end_element' => ['bool', 'writer'=>'XMLWriter'], 'xmlwriter_end_pi' => ['bool', 'writer'=>'XMLWriter'], 'xmlwriter_flush' => ['string|int', 'writer'=>'XMLWriter', 'empty='=>'bool'], 'xmlwriter_full_end_element' => ['bool', 'writer'=>'XMLWriter'], 'xmlwriter_open_memory' => ['XMLWriter|false'], 'xmlwriter_open_uri' => ['XMLWriter|false', 'uri'=>'string'], 'xmlwriter_output_memory' => ['string', 'writer'=>'XMLWriter', 'flush='=>'bool'], 'xmlwriter_set_indent' => ['bool', 'writer'=>'XMLWriter', 'enable'=>'bool'], 'xmlwriter_set_indent_string' => ['bool', 'writer'=>'XMLWriter', 'indentation'=>'string'], 'xmlwriter_start_attribute' => ['bool', 'writer'=>'XMLWriter', 'name'=>'string'], 'xmlwriter_start_attribute_ns' => ['bool', 'writer'=>'XMLWriter', 'prefix'=>'?string', 'name'=>'string', 'namespace'=>'?string'], 'xmlwriter_start_cdata' => ['bool', 'writer'=>'XMLWriter'], 'xmlwriter_start_comment' => ['bool', 'writer'=>'XMLWriter'], 'xmlwriter_start_document' => ['bool', 'writer'=>'XMLWriter', 'version='=>'?string', 'encoding='=>'?string', 'standalone='=>'?string'], 'xmlwriter_start_dtd' => ['bool', 'writer'=>'XMLWriter', 'qualifiedName'=>'string', 'publicId='=>'?string', 'systemId='=>'?string'], 'xmlwriter_start_dtd_attlist' => ['bool', 'writer'=>'XMLWriter', 'name'=>'string'], 'xmlwriter_start_dtd_element' => ['bool', 'writer'=>'XMLWriter', 'qualifiedName'=>'string'], 'xmlwriter_start_dtd_entity' => ['bool', 'writer'=>'XMLWriter', 'name'=>'string', 'isParam'=>'bool'], 'xmlwriter_start_element' => ['bool', 'writer'=>'XMLWriter', 'name'=>'string'], 'xmlwriter_start_element_ns' => ['bool', 'writer'=>'XMLWriter', 'prefix'=>'?string', 'name'=>'string', 'namespace'=>'?string'], 'xmlwriter_start_pi' => ['bool', 'writer'=>'XMLWriter', 'target'=>'string'], 'xmlwriter_text' => ['bool', 'writer'=>'XMLWriter', 'content'=>'string'], 'xmlwriter_write_attribute' => ['bool', 'writer'=>'XMLWriter', 'name'=>'string', 'value'=>'string'], 'xmlwriter_write_attribute_ns' => ['bool', 'writer'=>'XMLWriter', 'prefix'=>'?string', 'name'=>'string', 'namespace'=>'?string', 'value'=>'string'], 'xmlwriter_write_cdata' => ['bool', 'writer'=>'XMLWriter', 'content'=>'string'], 'xmlwriter_write_comment' => ['bool', 'writer'=>'XMLWriter', 'content'=>'string'], 'xmlwriter_write_dtd' => ['bool', 'writer'=>'XMLWriter', 'name'=>'string', 'publicId='=>'?string', 'systemId='=>'?string', 'content='=>'?string'], 'xmlwriter_write_dtd_attlist' => ['bool', 'writer'=>'XMLWriter', 'name'=>'string', 'content'=>'string'], 'xmlwriter_write_dtd_element' => ['bool', 'writer'=>'XMLWriter', 'name'=>'string', 'content'=>'string'], 'xmlwriter_write_dtd_entity' => ['bool', 'writer'=>'XMLWriter', 'name'=>'string', 'content'=>'string', 'isParam='=>'bool', 'publicId='=>'?string', 'systemId='=>'?string', 'notationData='=>'?string'], 'xmlwriter_write_element' => ['bool', 'writer'=>'XMLWriter', 'name'=>'string', 'content='=>'?string'], 'xmlwriter_write_element_ns' => ['bool', 'writer'=>'XMLWriter', 'prefix'=>'?string', 'name'=>'string', 'namespace'=>'?string', 'content='=>'?string'], 'xmlwriter_write_pi' => ['bool', 'writer'=>'XMLWriter', 'target'=>'string', 'content'=>'string'], 'xmlwriter_write_raw' => ['bool', 'writer'=>'XMLWriter', 'content'=>'string'], 'xpath_new_context' => ['XPathContext', 'dom_document'=>'DOMDocument'], 'xpath_register_ns' => ['bool', 'xpath_context'=>'xpathcontext', 'prefix'=>'string', 'uri'=>'string'], 'xpath_register_ns_auto' => ['bool', 'xpath_context'=>'xpathcontext', 'context_node='=>'object'], 'xptr_new_context' => ['XPathContext'], 'XSLTProcessor::getParameter' => ['string|false', 'namespace'=>'string', 'name'=>'string'], 'XsltProcessor::getSecurityPrefs' => ['int'], 'XSLTProcessor::hasExsltSupport' => ['bool'], 'XSLTProcessor::importStylesheet' => ['bool', 'stylesheet'=>'object'], 'XSLTProcessor::registerPHPFunctions' => ['void', 'functions='=>'array|string|null'], 'XSLTProcessor::removeParameter' => ['bool', 'namespace'=>'string', 'name'=>'string'], 'XSLTProcessor::setParameter' => ['bool', 'namespace'=>'string', 'name'=>'string', 'value'=>'string'], 'XSLTProcessor::setParameter\'1' => ['bool', 'namespace'=>'string', 'options'=>'array'], 'XSLTProcessor::setProfiling' => ['bool', 'filename'=>'?string'], 'XsltProcessor::setSecurityPrefs' => ['int', 'preferences'=>'int'], 'XSLTProcessor::transformToDoc' => ['DOMDocument|false', 'document'=>'DOMNode', 'returnClass='=>'?string'], 'XSLTProcessor::transformToURI' => ['int', 'document'=>'DOMDocument', 'uri'=>'string'], 'XSLTProcessor::transformToXML' => ['string|false', 'document'=>'DOMDocument'], 'yac::__construct' => ['void', 'prefix='=>'string'], 'yac::__get' => ['mixed', 'key'=>'string'], 'yac::__set' => ['mixed', 'key'=>'string', 'value'=>'mixed'], 'yac::delete' => ['bool', 'keys'=>'string|array', 'ttl='=>'int'], 'yac::dump' => ['mixed', 'num'=>'int'], 'yac::flush' => ['bool'], 'yac::get' => ['mixed', 'key'=>'string|array', 'cas='=>'int'], 'yac::info' => ['array'], 'Yaconf::get' => ['mixed', 'name'=>'string', 'default_value='=>'mixed'], 'Yaconf::has' => ['bool', 'name'=>'string'], 'Yaf\Action_Abstract::__clone' => ['void'], 'Yaf\Action_Abstract::__construct' => ['void', 'request'=>'Yaf\Request_Abstract', 'response'=>'Yaf\Response_Abstract', 'view'=>'Yaf\View_Interface', 'invokeArgs='=>'?array'], 'Yaf\Action_Abstract::display' => ['bool', 'tpl'=>'string', 'parameters='=>'?array'], 'Yaf\Action_Abstract::execute' => ['mixed'], 'Yaf\Action_Abstract::forward' => ['bool', 'module'=>'string', 'controller='=>'string', 'action='=>'string', 'parameters='=>'?array'], 'Yaf\Action_Abstract::getController' => ['Yaf\Controller_Abstract'], 'Yaf\Action_Abstract::getInvokeArg' => ['mixed|null', 'name'=>'string'], 'Yaf\Action_Abstract::getInvokeArgs' => ['array'], 'Yaf\Action_Abstract::getModuleName' => ['string'], 'Yaf\Action_Abstract::getRequest' => ['Yaf\Request_Abstract'], 'Yaf\Action_Abstract::getResponse' => ['Yaf\Response_Abstract'], 'Yaf\Action_Abstract::getView' => ['Yaf\View_Interface'], 'Yaf\Action_Abstract::getViewpath' => ['string'], 'Yaf\Action_Abstract::init' => [''], 'Yaf\Action_Abstract::initView' => ['Yaf\Response_Abstract', 'options='=>'?array'], 'Yaf\Action_Abstract::redirect' => ['bool', 'url'=>'string'], 'Yaf\Action_Abstract::render' => ['string', 'tpl'=>'string', 'parameters='=>'?array'], 'Yaf\Action_Abstract::setViewpath' => ['bool', 'view_directory'=>'string'], 'Yaf\Application::__clone' => ['void'], 'Yaf\Application::__construct' => ['void', 'config'=>'array|string', 'envrion='=>'string'], 'Yaf\Application::__destruct' => ['void'], 'Yaf\Application::__sleep' => ['string[]'], 'Yaf\Application::__wakeup' => ['void'], 'Yaf\Application::app' => ['?Yaf\Application'], 'Yaf\Application::bootstrap' => ['Yaf\Application', 'bootstrap='=>'?Yaf\Bootstrap_Abstract'], 'Yaf\Application::clearLastError' => ['void'], 'Yaf\Application::environ' => ['string'], 'Yaf\Application::execute' => ['void', 'entry'=>'callable', '_='=>'string'], 'Yaf\Application::getAppDirectory' => ['string'], 'Yaf\Application::getConfig' => ['Yaf\Config_Abstract'], 'Yaf\Application::getDispatcher' => ['Yaf\Dispatcher'], 'Yaf\Application::getLastErrorMsg' => ['string'], 'Yaf\Application::getLastErrorNo' => ['int'], 'Yaf\Application::getModules' => ['array'], 'Yaf\Application::run' => ['void'], 'Yaf\Application::setAppDirectory' => ['Yaf\Application', 'directory'=>'string'], 'Yaf\Config\Ini::__construct' => ['void', 'config_file'=>'string', 'section='=>'string'], 'Yaf\Config\Ini::__get' => ['', 'name='=>'mixed'], 'Yaf\Config\Ini::__isset' => ['', 'name'=>'string'], 'Yaf\Config\Ini::__set' => ['void', 'name'=>'', 'value'=>''], 'Yaf\Config\Ini::count' => ['int'], 'Yaf\Config\Ini::current' => ['mixed'], 'Yaf\Config\Ini::get' => ['mixed', 'name='=>'mixed'], 'Yaf\Config\Ini::key' => ['int|string'], 'Yaf\Config\Ini::next' => ['void'], 'Yaf\Config\Ini::offsetExists' => ['bool', 'name'=>'int|string'], 'Yaf\Config\Ini::offsetGet' => ['mixed', 'name'=>'int|string'], 'Yaf\Config\Ini::offsetSet' => ['void', 'name'=>'int|string|null', 'value'=>'mixed'], 'Yaf\Config\Ini::offsetUnset' => ['void', 'name'=>'int|string'], 'Yaf\Config\Ini::readonly' => ['bool'], 'Yaf\Config\Ini::rewind' => ['void'], 'Yaf\Config\Ini::set' => ['Yaf\Config_Abstract', 'name'=>'string', 'value'=>'mixed'], 'Yaf\Config\Ini::toArray' => ['array'], 'Yaf\Config\Ini::valid' => ['bool'], 'Yaf\Config\Simple::__construct' => ['void', 'array'=>'array', 'readonly='=>'string'], 'Yaf\Config\Simple::__get' => ['', 'name='=>'mixed'], 'Yaf\Config\Simple::__isset' => ['', 'name'=>'string'], 'Yaf\Config\Simple::__set' => ['void', 'name'=>'', 'value'=>''], 'Yaf\Config\Simple::count' => ['int'], 'Yaf\Config\Simple::current' => ['mixed'], 'Yaf\Config\Simple::get' => ['mixed', 'name='=>'mixed'], 'Yaf\Config\Simple::key' => ['int|string'], 'Yaf\Config\Simple::next' => ['void'], 'Yaf\Config\Simple::offsetExists' => ['bool', 'name'=>'int|string'], 'Yaf\Config\Simple::offsetGet' => ['mixed', 'name'=>'int|string'], 'Yaf\Config\Simple::offsetSet' => ['void', 'name'=>'int|string|null', 'value'=>'mixed'], 'Yaf\Config\Simple::offsetUnset' => ['void', 'name'=>'int|string'], 'Yaf\Config\Simple::readonly' => ['bool'], 'Yaf\Config\Simple::rewind' => ['void'], 'Yaf\Config\Simple::set' => ['Yaf\Config_Abstract', 'name'=>'string', 'value'=>'mixed'], 'Yaf\Config\Simple::toArray' => ['array'], 'Yaf\Config\Simple::valid' => ['bool'], 'Yaf\Config_Abstract::__construct' => ['void'], 'Yaf\Config_Abstract::get' => ['mixed', 'name='=>'string'], 'Yaf\Config_Abstract::readonly' => ['bool'], 'Yaf\Config_Abstract::set' => ['Yaf\Config_Abstract', 'name'=>'string', 'value'=>'mixed'], 'Yaf\Config_Abstract::toArray' => ['array'], 'Yaf\Controller_Abstract::__clone' => ['void'], 'Yaf\Controller_Abstract::__construct' => ['void', 'request'=>'Yaf\Request_Abstract', 'response'=>'Yaf\Response_Abstract', 'view'=>'Yaf\View_Interface', 'invokeArgs='=>'?array'], 'Yaf\Controller_Abstract::display' => ['bool', 'tpl'=>'string', 'parameters='=>'?array'], 'Yaf\Controller_Abstract::forward' => ['bool', 'module'=>'string', 'controller='=>'string', 'action='=>'string', 'parameters='=>'?array'], 'Yaf\Controller_Abstract::getInvokeArg' => ['mixed|null', 'name'=>'string'], 'Yaf\Controller_Abstract::getInvokeArgs' => ['array'], 'Yaf\Controller_Abstract::getModuleName' => ['string'], 'Yaf\Controller_Abstract::getRequest' => ['Yaf\Request_Abstract'], 'Yaf\Controller_Abstract::getResponse' => ['Yaf\Response_Abstract'], 'Yaf\Controller_Abstract::getView' => ['Yaf\View_Interface'], 'Yaf\Controller_Abstract::getViewpath' => ['string'], 'Yaf\Controller_Abstract::init' => [''], 'Yaf\Controller_Abstract::initView' => ['Yaf\Response_Abstract', 'options='=>'?array'], 'Yaf\Controller_Abstract::redirect' => ['bool', 'url'=>'string'], 'Yaf\Controller_Abstract::render' => ['string', 'tpl'=>'string', 'parameters='=>'?array'], 'Yaf\Controller_Abstract::setViewpath' => ['bool', 'view_directory'=>'string'], 'Yaf\Dispatcher::__clone' => ['void'], 'Yaf\Dispatcher::__construct' => ['void'], 'Yaf\Dispatcher::__sleep' => ['list'], 'Yaf\Dispatcher::__wakeup' => ['void'], 'Yaf\Dispatcher::autoRender' => ['Yaf\Dispatcher', 'flag='=>'bool'], 'Yaf\Dispatcher::catchException' => ['Yaf\Dispatcher', 'flag='=>'bool'], 'Yaf\Dispatcher::disableView' => ['bool'], 'Yaf\Dispatcher::dispatch' => ['Yaf\Response_Abstract', 'request'=>'Yaf\Request_Abstract'], 'Yaf\Dispatcher::enableView' => ['Yaf\Dispatcher'], 'Yaf\Dispatcher::flushInstantly' => ['Yaf\Dispatcher', 'flag='=>'bool'], 'Yaf\Dispatcher::getApplication' => ['Yaf\Application'], 'Yaf\Dispatcher::getInstance' => ['Yaf\Dispatcher'], 'Yaf\Dispatcher::getRequest' => ['Yaf\Request_Abstract'], 'Yaf\Dispatcher::getRouter' => ['Yaf\Router'], 'Yaf\Dispatcher::initView' => ['Yaf\View_Interface', 'templates_dir'=>'string', 'options='=>'?array'], 'Yaf\Dispatcher::registerPlugin' => ['Yaf\Dispatcher', 'plugin'=>'Yaf\Plugin_Abstract'], 'Yaf\Dispatcher::returnResponse' => ['Yaf\Dispatcher', 'flag'=>'bool'], 'Yaf\Dispatcher::setDefaultAction' => ['Yaf\Dispatcher', 'action'=>'string'], 'Yaf\Dispatcher::setDefaultController' => ['Yaf\Dispatcher', 'controller'=>'string'], 'Yaf\Dispatcher::setDefaultModule' => ['Yaf\Dispatcher', 'module'=>'string'], 'Yaf\Dispatcher::setErrorHandler' => ['Yaf\Dispatcher', 'callback'=>'callable', 'error_types'=>'int'], 'Yaf\Dispatcher::setRequest' => ['Yaf\Dispatcher', 'request'=>'Yaf\Request_Abstract'], 'Yaf\Dispatcher::setView' => ['Yaf\Dispatcher', 'view'=>'Yaf\View_Interface'], 'Yaf\Dispatcher::throwException' => ['Yaf\Dispatcher', 'flag='=>'bool'], 'Yaf\Loader::__clone' => ['void'], 'Yaf\Loader::__construct' => ['void'], 'Yaf\Loader::__sleep' => ['list'], 'Yaf\Loader::__wakeup' => ['void'], 'Yaf\Loader::autoload' => ['bool', 'class_name'=>'string'], 'Yaf\Loader::clearLocalNamespace' => [''], 'Yaf\Loader::getInstance' => ['Yaf\Loader', 'local_library_path='=>'string', 'global_library_path='=>'string'], 'Yaf\Loader::getLibraryPath' => ['string', 'is_global='=>'bool'], 'Yaf\Loader::getLocalNamespace' => ['string'], 'Yaf\Loader::import' => ['bool', 'file'=>'string'], 'Yaf\Loader::isLocalName' => ['bool', 'class_name'=>'string'], 'Yaf\Loader::registerLocalNamespace' => ['bool', 'name_prefix'=>'string|string[]'], 'Yaf\Loader::setLibraryPath' => ['Yaf\Loader', 'directory'=>'string', 'global='=>'bool'], 'Yaf\Plugin_Abstract::dispatchLoopShutdown' => ['bool', 'request'=>'Yaf\Request_Abstract', 'response'=>'Yaf\Response_Abstract'], 'Yaf\Plugin_Abstract::dispatchLoopStartup' => ['bool', 'request'=>'Yaf\Request_Abstract', 'response'=>'Yaf\Response_Abstract'], 'Yaf\Plugin_Abstract::postDispatch' => ['bool', 'request'=>'Yaf\Request_Abstract', 'response'=>'Yaf\Response_Abstract'], 'Yaf\Plugin_Abstract::preDispatch' => ['bool', 'request'=>'Yaf\Request_Abstract', 'response'=>'Yaf\Response_Abstract'], 'Yaf\Plugin_Abstract::preResponse' => ['bool', 'request'=>'Yaf\Request_Abstract', 'response'=>'Yaf\Response_Abstract'], 'Yaf\Plugin_Abstract::routerShutdown' => ['bool', 'request'=>'Yaf\Request_Abstract', 'response'=>'Yaf\Response_Abstract'], 'Yaf\Plugin_Abstract::routerStartup' => ['bool', 'request'=>'Yaf\Request_Abstract', 'response'=>'Yaf\Response_Abstract'], 'Yaf\Registry::__clone' => ['void'], 'Yaf\Registry::__construct' => ['void'], 'Yaf\Registry::del' => ['bool|void', 'name'=>'string'], 'Yaf\Registry::get' => ['mixed', 'name'=>'string'], 'Yaf\Registry::has' => ['bool', 'name'=>'string'], 'Yaf\Registry::set' => ['bool', 'name'=>'string', 'value'=>'mixed'], 'Yaf\Request\Http::__clone' => ['void'], 'Yaf\Request\Http::__construct' => ['void', 'request_uri'=>'string', 'base_uri'=>'string'], 'Yaf\Request\Http::get' => ['mixed', 'name'=>'string', 'default='=>'string'], 'Yaf\Request\Http::getActionName' => ['string'], 'Yaf\Request\Http::getBaseUri' => ['string'], 'Yaf\Request\Http::getControllerName' => ['string'], 'Yaf\Request\Http::getCookie' => ['mixed', 'name='=>'string', 'default='=>'mixed'], 'Yaf\Request\Http::getEnv' => ['mixed', 'name='=>'string', 'default='=>'mixed'], 'Yaf\Request\Http::getException' => ['Yaf\Exception'], 'Yaf\Request\Http::getFiles' => ['mixed', 'name='=>'string', 'default='=>'mixed'], 'Yaf\Request\Http::getLanguage' => ['string'], 'Yaf\Request\Http::getMethod' => ['string'], 'Yaf\Request\Http::getModuleName' => ['string'], 'Yaf\Request\Http::getParam' => ['mixed', 'name'=>'string', 'default='=>'mixed'], 'Yaf\Request\Http::getParams' => ['array'], 'Yaf\Request\Http::getPost' => ['mixed', 'name='=>'string', 'default='=>'mixed'], 'Yaf\Request\Http::getQuery' => ['mixed', 'name='=>'string', 'default='=>'mixed'], 'Yaf\Request\Http::getRequest' => ['mixed', 'name='=>'string', 'default='=>'mixed'], 'Yaf\Request\Http::getRequestUri' => ['string'], 'Yaf\Request\Http::getServer' => ['mixed', 'name='=>'string', 'default='=>'mixed'], 'Yaf\Request\Http::isCli' => ['bool'], 'Yaf\Request\Http::isDispatched' => ['bool'], 'Yaf\Request\Http::isGet' => ['bool'], 'Yaf\Request\Http::isHead' => ['bool'], 'Yaf\Request\Http::isOptions' => ['bool'], 'Yaf\Request\Http::isPost' => ['bool'], 'Yaf\Request\Http::isPut' => ['bool'], 'Yaf\Request\Http::isRouted' => ['bool'], 'Yaf\Request\Http::isXmlHttpRequest' => ['bool'], 'Yaf\Request\Http::setActionName' => ['Yaf\Request_Abstract|bool', 'action'=>'string'], 'Yaf\Request\Http::setBaseUri' => ['bool', 'uri'=>'string'], 'Yaf\Request\Http::setControllerName' => ['Yaf\Request_Abstract|bool', 'controller'=>'string'], 'Yaf\Request\Http::setDispatched' => ['bool'], 'Yaf\Request\Http::setModuleName' => ['Yaf\Request_Abstract|bool', 'module'=>'string'], 'Yaf\Request\Http::setParam' => ['Yaf\Request_Abstract|bool', 'name'=>'array|string', 'value='=>'string'], 'Yaf\Request\Http::setRequestUri' => ['', 'uri'=>'string'], 'Yaf\Request\Http::setRouted' => ['Yaf\Request_Abstract|bool'], 'Yaf\Request\Simple::__clone' => ['void'], 'Yaf\Request\Simple::__construct' => ['void', 'method'=>'string', 'controller'=>'string', 'action'=>'string', 'params='=>'string'], 'Yaf\Request\Simple::get' => ['mixed', 'name'=>'string', 'default='=>'string'], 'Yaf\Request\Simple::getActionName' => ['string'], 'Yaf\Request\Simple::getBaseUri' => ['string'], 'Yaf\Request\Simple::getControllerName' => ['string'], 'Yaf\Request\Simple::getCookie' => ['mixed', 'name='=>'string', 'default='=>'string'], 'Yaf\Request\Simple::getEnv' => ['mixed', 'name='=>'string', 'default='=>'mixed'], 'Yaf\Request\Simple::getException' => ['Yaf\Exception'], 'Yaf\Request\Simple::getFiles' => ['array', 'name='=>'mixed', 'default='=>'null'], 'Yaf\Request\Simple::getLanguage' => ['string'], 'Yaf\Request\Simple::getMethod' => ['string'], 'Yaf\Request\Simple::getModuleName' => ['string'], 'Yaf\Request\Simple::getParam' => ['mixed', 'name'=>'string', 'default='=>'mixed'], 'Yaf\Request\Simple::getParams' => ['array'], 'Yaf\Request\Simple::getPost' => ['mixed', 'name='=>'string', 'default='=>'string'], 'Yaf\Request\Simple::getQuery' => ['mixed', 'name='=>'string', 'default='=>'string'], 'Yaf\Request\Simple::getRequest' => ['mixed', 'name='=>'string', 'default='=>'string'], 'Yaf\Request\Simple::getRequestUri' => ['string'], 'Yaf\Request\Simple::getServer' => ['mixed', 'name='=>'string', 'default='=>'mixed'], 'Yaf\Request\Simple::isCli' => ['bool'], 'Yaf\Request\Simple::isDispatched' => ['bool'], 'Yaf\Request\Simple::isGet' => ['bool'], 'Yaf\Request\Simple::isHead' => ['bool'], 'Yaf\Request\Simple::isOptions' => ['bool'], 'Yaf\Request\Simple::isPost' => ['bool'], 'Yaf\Request\Simple::isPut' => ['bool'], 'Yaf\Request\Simple::isRouted' => ['bool'], 'Yaf\Request\Simple::isXmlHttpRequest' => ['bool'], 'Yaf\Request\Simple::setActionName' => ['Yaf\Request_Abstract|bool', 'action'=>'string'], 'Yaf\Request\Simple::setBaseUri' => ['bool', 'uri'=>'string'], 'Yaf\Request\Simple::setControllerName' => ['Yaf\Request_Abstract|bool', 'controller'=>'string'], 'Yaf\Request\Simple::setDispatched' => ['bool'], 'Yaf\Request\Simple::setModuleName' => ['Yaf\Request_Abstract|bool', 'module'=>'string'], 'Yaf\Request\Simple::setParam' => ['Yaf\Request_Abstract|bool', 'name'=>'array|string', 'value='=>'string'], 'Yaf\Request\Simple::setRequestUri' => ['', 'uri'=>'string'], 'Yaf\Request\Simple::setRouted' => ['Yaf\Request_Abstract|bool'], 'Yaf\Request_Abstract::getActionName' => ['string'], 'Yaf\Request_Abstract::getBaseUri' => ['string'], 'Yaf\Request_Abstract::getControllerName' => ['string'], 'Yaf\Request_Abstract::getEnv' => ['mixed', 'name='=>'string', 'default='=>'mixed'], 'Yaf\Request_Abstract::getException' => ['Yaf\Exception'], 'Yaf\Request_Abstract::getLanguage' => ['string'], 'Yaf\Request_Abstract::getMethod' => ['string'], 'Yaf\Request_Abstract::getModuleName' => ['string'], 'Yaf\Request_Abstract::getParam' => ['mixed', 'name'=>'string', 'default='=>'mixed'], 'Yaf\Request_Abstract::getParams' => ['array'], 'Yaf\Request_Abstract::getRequestUri' => ['string'], 'Yaf\Request_Abstract::getServer' => ['mixed', 'name='=>'string', 'default='=>'mixed'], 'Yaf\Request_Abstract::isCli' => ['bool'], 'Yaf\Request_Abstract::isDispatched' => ['bool'], 'Yaf\Request_Abstract::isGet' => ['bool'], 'Yaf\Request_Abstract::isHead' => ['bool'], 'Yaf\Request_Abstract::isOptions' => ['bool'], 'Yaf\Request_Abstract::isPost' => ['bool'], 'Yaf\Request_Abstract::isPut' => ['bool'], 'Yaf\Request_Abstract::isRouted' => ['bool'], 'Yaf\Request_Abstract::isXmlHttpRequest' => ['bool'], 'Yaf\Request_Abstract::setActionName' => ['Yaf\Request_Abstract|bool', 'action'=>'string'], 'Yaf\Request_Abstract::setBaseUri' => ['bool', 'uri'=>'string'], 'Yaf\Request_Abstract::setControllerName' => ['Yaf\Request_Abstract|bool', 'controller'=>'string'], 'Yaf\Request_Abstract::setDispatched' => ['bool'], 'Yaf\Request_Abstract::setModuleName' => ['Yaf\Request_Abstract|bool', 'module'=>'string'], 'Yaf\Request_Abstract::setParam' => ['Yaf\Request_Abstract|bool', 'name'=>'array|string', 'value='=>'string'], 'Yaf\Request_Abstract::setRequestUri' => ['', 'uri'=>'string'], 'Yaf\Request_Abstract::setRouted' => ['Yaf\Request_Abstract|bool'], 'Yaf\Response\Cli::__clone' => ['void'], 'Yaf\Response\Cli::__construct' => ['void'], 'Yaf\Response\Cli::__destruct' => ['void'], 'Yaf\Response\Cli::__toString' => ['string'], 'Yaf\Response\Cli::appendBody' => ['bool', 'content'=>'string', 'key='=>'string'], 'Yaf\Response\Cli::clearBody' => ['bool', 'key='=>'string'], 'Yaf\Response\Cli::getBody' => ['mixed', 'key='=>'?string'], 'Yaf\Response\Cli::prependBody' => ['bool', 'content'=>'string', 'key='=>'string'], 'Yaf\Response\Cli::setBody' => ['bool', 'content'=>'string', 'key='=>'string'], 'Yaf\Response\Http::__clone' => ['void'], 'Yaf\Response\Http::__construct' => ['void'], 'Yaf\Response\Http::__destruct' => ['void'], 'Yaf\Response\Http::__toString' => ['string'], 'Yaf\Response\Http::appendBody' => ['bool', 'content'=>'string', 'key='=>'string'], 'Yaf\Response\Http::clearBody' => ['bool', 'key='=>'string'], 'Yaf\Response\Http::clearHeaders' => ['Yaf\Response_Abstract|false', 'name='=>'string'], 'Yaf\Response\Http::getBody' => ['mixed', 'key='=>'?string'], 'Yaf\Response\Http::getHeader' => ['mixed', 'name='=>'string'], 'Yaf\Response\Http::prependBody' => ['bool', 'content'=>'string', 'key='=>'string'], 'Yaf\Response\Http::response' => ['bool'], 'Yaf\Response\Http::setAllHeaders' => ['bool', 'headers'=>'array'], 'Yaf\Response\Http::setBody' => ['bool', 'content'=>'string', 'key='=>'string'], 'Yaf\Response\Http::setHeader' => ['bool', 'name'=>'string', 'value'=>'string', 'replace='=>'bool', 'response_code='=>'int'], 'Yaf\Response\Http::setRedirect' => ['bool', 'url'=>'string'], 'Yaf\Response_Abstract::__clone' => ['void'], 'Yaf\Response_Abstract::__construct' => ['void'], 'Yaf\Response_Abstract::__destruct' => ['void'], 'Yaf\Response_Abstract::__toString' => ['void'], 'Yaf\Response_Abstract::appendBody' => ['bool', 'content'=>'string', 'key='=>'string'], 'Yaf\Response_Abstract::clearBody' => ['bool', 'key='=>'string'], 'Yaf\Response_Abstract::getBody' => ['mixed', 'key='=>'?string'], 'Yaf\Response_Abstract::prependBody' => ['bool', 'content'=>'string', 'key='=>'string'], 'Yaf\Response_Abstract::setBody' => ['bool', 'content'=>'string', 'key='=>'string'], 'Yaf\Route\Map::__construct' => ['void', 'controller_prefer='=>'bool', 'delimiter='=>'string'], 'Yaf\Route\Map::assemble' => ['bool', 'info'=>'array', 'query='=>'?array'], 'Yaf\Route\Map::route' => ['bool', 'request'=>'Yaf\Request_Abstract'], 'Yaf\Route\Regex::__construct' => ['void', 'match'=>'string', 'route'=>'array', 'map='=>'?array', 'verify='=>'?array', 'reverse='=>'string'], 'Yaf\Route\Regex::addConfig' => ['Yaf\Router|bool', 'config'=>'Yaf\Config_Abstract'], 'Yaf\Route\Regex::addRoute' => ['Yaf\Router|bool', 'name'=>'string', 'route'=>'Yaf\Route_Interface'], 'Yaf\Route\Regex::assemble' => ['bool', 'info'=>'array', 'query='=>'?array'], 'Yaf\Route\Regex::getCurrentRoute' => ['string'], 'Yaf\Route\Regex::getRoute' => ['Yaf\Route_Interface', 'name'=>'string'], 'Yaf\Route\Regex::getRoutes' => ['Yaf\Route_Interface[]'], 'Yaf\Route\Regex::route' => ['bool', 'request'=>'Yaf\Request_Abstract'], 'Yaf\Route\Rewrite::__construct' => ['void', 'match'=>'string', 'route'=>'array', 'verify='=>'?array', 'reverse='=>'string'], 'Yaf\Route\Rewrite::addConfig' => ['Yaf\Router|bool', 'config'=>'Yaf\Config_Abstract'], 'Yaf\Route\Rewrite::addRoute' => ['Yaf\Router|bool', 'name'=>'string', 'route'=>'Yaf\Route_Interface'], 'Yaf\Route\Rewrite::assemble' => ['bool', 'info'=>'array', 'query='=>'?array'], 'Yaf\Route\Rewrite::getCurrentRoute' => ['string'], 'Yaf\Route\Rewrite::getRoute' => ['Yaf\Route_Interface', 'name'=>'string'], 'Yaf\Route\Rewrite::getRoutes' => ['Yaf\Route_Interface[]'], 'Yaf\Route\Rewrite::route' => ['bool', 'request'=>'Yaf\Request_Abstract'], 'Yaf\Route\Simple::__construct' => ['void', 'module_name'=>'string', 'controller_name'=>'string', 'action_name'=>'string'], 'Yaf\Route\Simple::assemble' => ['bool', 'info'=>'array', 'query='=>'?array'], 'Yaf\Route\Simple::route' => ['bool', 'request'=>'Yaf\Request_Abstract'], 'Yaf\Route\Supervar::__construct' => ['void', 'supervar_name'=>'string'], 'Yaf\Route\Supervar::assemble' => ['bool', 'info'=>'array', 'query='=>'?array'], 'Yaf\Route\Supervar::route' => ['bool', 'request'=>'Yaf\Request_Abstract'], 'Yaf\Route_Interface::__construct' => ['Yaf\Route_Interface'], 'Yaf\Route_Interface::assemble' => ['bool', 'info'=>'array', 'query='=>'?array'], 'Yaf\Route_Interface::route' => ['bool', 'request'=>'Yaf\Request_Abstract'], 'Yaf\Route_Static::assemble' => ['bool', 'info'=>'array', 'query='=>'?array'], 'Yaf\Route_Static::match' => ['bool', 'uri'=>'string'], 'Yaf\Route_Static::route' => ['bool', 'request'=>'Yaf\Request_Abstract'], 'Yaf\Router::__construct' => ['void'], 'Yaf\Router::addConfig' => ['Yaf\Router|false', 'config'=>'Yaf\Config_Abstract'], 'Yaf\Router::addRoute' => ['Yaf\Router|false', 'name'=>'string', 'route'=>'Yaf\Route_Interface'], 'Yaf\Router::getCurrentRoute' => ['string'], 'Yaf\Router::getRoute' => ['Yaf\Route_Interface', 'name'=>'string'], 'Yaf\Router::getRoutes' => ['Yaf\Route_Interface[]'], 'Yaf\Router::route' => ['Yaf\Router|false', 'request'=>'Yaf\Request_Abstract'], 'Yaf\Session::__clone' => ['void'], 'Yaf\Session::__construct' => ['void'], 'Yaf\Session::__get' => ['void', 'name'=>''], 'Yaf\Session::__isset' => ['void', 'name'=>''], 'Yaf\Session::__set' => ['void', 'name'=>'', 'value'=>''], 'Yaf\Session::__sleep' => ['list'], 'Yaf\Session::__unset' => ['void', 'name'=>''], 'Yaf\Session::__wakeup' => ['void'], 'Yaf\Session::count' => ['int'], 'Yaf\Session::current' => ['mixed'], 'Yaf\Session::del' => ['Yaf\Session|false', 'name'=>'string'], 'Yaf\Session::get' => ['mixed', 'name'=>'string'], 'Yaf\Session::getInstance' => ['Yaf\Session'], 'Yaf\Session::has' => ['bool', 'name'=>'string'], 'Yaf\Session::key' => ['int|string'], 'Yaf\Session::next' => ['void'], 'Yaf\Session::offsetExists' => ['bool', 'name'=>'int|string'], 'Yaf\Session::offsetGet' => ['mixed', 'name'=>'int|string'], 'Yaf\Session::offsetSet' => ['void', 'name'=>'int|string|null', 'value'=>'mixed'], 'Yaf\Session::offsetUnset' => ['void', 'name'=>'int|string'], 'Yaf\Session::rewind' => ['void'], 'Yaf\Session::set' => ['Yaf\Session|false', 'name'=>'string', 'value'=>'mixed'], 'Yaf\Session::start' => ['Yaf\Session'], 'Yaf\Session::valid' => ['bool'], 'Yaf\View\Simple::__construct' => ['void', 'template_dir'=>'string', 'options='=>'?array'], 'Yaf\View\Simple::__get' => ['mixed', 'name='=>'null'], 'Yaf\View\Simple::__isset' => ['', 'name'=>'string'], 'Yaf\View\Simple::__set' => ['void', 'name'=>'string', 'value='=>'mixed'], 'Yaf\View\Simple::assign' => ['Yaf\View\Simple', 'name'=>'array|string', 'value='=>'mixed'], 'Yaf\View\Simple::assignRef' => ['Yaf\View\Simple', 'name'=>'string', '&value'=>'mixed'], 'Yaf\View\Simple::clear' => ['Yaf\View\Simple', 'name='=>'string'], 'Yaf\View\Simple::display' => ['bool', 'tpl'=>'string', 'tpl_vars='=>'?array'], 'Yaf\View\Simple::eval' => ['bool|void', 'tpl_str'=>'string', 'vars='=>'?array'], 'Yaf\View\Simple::getScriptPath' => ['string'], 'Yaf\View\Simple::render' => ['string|void', 'tpl'=>'string', 'tpl_vars='=>'?array'], 'Yaf\View\Simple::setScriptPath' => ['Yaf\View\Simple', 'template_dir'=>'string'], 'Yaf\View_Interface::assign' => ['bool', 'name'=>'array|string', 'value'=>'mixed'], 'Yaf\View_Interface::display' => ['bool', 'tpl'=>'string', 'tpl_vars='=>'?array'], 'Yaf\View_Interface::getScriptPath' => ['string'], 'Yaf\View_Interface::render' => ['string', 'tpl'=>'string', 'tpl_vars='=>'?array'], 'Yaf\View_Interface::setScriptPath' => ['void', 'template_dir'=>'string'], 'Yaf_Action_Abstract::__clone' => ['void'], 'Yaf_Action_Abstract::__construct' => ['void', 'request'=>'Yaf_Request_Abstract', 'response'=>'Yaf_Response_Abstract', 'view'=>'Yaf_View_Interface', 'invokeArgs='=>'?array'], 'Yaf_Action_Abstract::display' => ['bool', 'tpl'=>'string', 'parameters='=>'?array'], 'Yaf_Action_Abstract::execute' => ['mixed', 'arg='=>'mixed', '...args='=>'mixed'], 'Yaf_Action_Abstract::forward' => ['bool', 'module'=>'string', 'controller='=>'string', 'action='=>'string', 'parameters='=>'?array'], 'Yaf_Action_Abstract::getController' => ['Yaf_Controller_Abstract'], 'Yaf_Action_Abstract::getControllerName' => ['string'], 'Yaf_Action_Abstract::getInvokeArg' => ['mixed|null', 'name'=>'string'], 'Yaf_Action_Abstract::getInvokeArgs' => ['array'], 'Yaf_Action_Abstract::getModuleName' => ['string'], 'Yaf_Action_Abstract::getRequest' => ['Yaf_Request_Abstract'], 'Yaf_Action_Abstract::getResponse' => ['Yaf_Response_Abstract'], 'Yaf_Action_Abstract::getView' => ['Yaf_View_Interface'], 'Yaf_Action_Abstract::getViewpath' => ['string'], 'Yaf_Action_Abstract::init' => [''], 'Yaf_Action_Abstract::initView' => ['Yaf_Response_Abstract', 'options='=>'?array'], 'Yaf_Action_Abstract::redirect' => ['bool', 'url'=>'string'], 'Yaf_Action_Abstract::render' => ['string', 'tpl'=>'string', 'parameters='=>'?array'], 'Yaf_Action_Abstract::setViewpath' => ['bool', 'view_directory'=>'string'], 'Yaf_Application::__clone' => ['void'], 'Yaf_Application::__construct' => ['void', 'config'=>'mixed', 'envrion='=>'string'], 'Yaf_Application::__destruct' => ['void'], 'Yaf_Application::__sleep' => ['list'], 'Yaf_Application::__wakeup' => ['void'], 'Yaf_Application::app' => ['?Yaf_Application'], 'Yaf_Application::bootstrap' => ['Yaf_Application', 'bootstrap='=>'Yaf_Bootstrap_Abstract'], 'Yaf_Application::clearLastError' => ['Yaf_Application'], 'Yaf_Application::environ' => ['string'], 'Yaf_Application::execute' => ['void', 'entry'=>'callable', '...args'=>'string'], 'Yaf_Application::getAppDirectory' => ['Yaf_Application'], 'Yaf_Application::getConfig' => ['Yaf_Config_Abstract'], 'Yaf_Application::getDispatcher' => ['Yaf_Dispatcher'], 'Yaf_Application::getLastErrorMsg' => ['string'], 'Yaf_Application::getLastErrorNo' => ['int'], 'Yaf_Application::getModules' => ['array'], 'Yaf_Application::run' => ['void'], 'Yaf_Application::setAppDirectory' => ['Yaf_Application', 'directory'=>'string'], 'Yaf_Config_Abstract::__construct' => ['void'], 'Yaf_Config_Abstract::get' => ['mixed', 'name'=>'string', 'value'=>'mixed'], 'Yaf_Config_Abstract::readonly' => ['bool'], 'Yaf_Config_Abstract::set' => ['Yaf_Config_Abstract'], 'Yaf_Config_Abstract::toArray' => ['array'], 'Yaf_Config_Ini::__construct' => ['void', 'config_file'=>'string', 'section='=>'string'], 'Yaf_Config_Ini::__get' => ['void', 'name='=>'string'], 'Yaf_Config_Ini::__isset' => ['void', 'name'=>'string'], 'Yaf_Config_Ini::__set' => ['void', 'name'=>'string', 'value'=>'mixed'], 'Yaf_Config_Ini::count' => ['void'], 'Yaf_Config_Ini::current' => ['void'], 'Yaf_Config_Ini::get' => ['mixed', 'name='=>'mixed'], 'Yaf_Config_Ini::key' => ['void'], 'Yaf_Config_Ini::next' => ['void'], 'Yaf_Config_Ini::offsetExists' => ['void', 'name'=>'string'], 'Yaf_Config_Ini::offsetGet' => ['void', 'name'=>'string'], 'Yaf_Config_Ini::offsetSet' => ['void', 'name'=>'string', 'value'=>'string'], 'Yaf_Config_Ini::offsetUnset' => ['void', 'name'=>'string'], 'Yaf_Config_Ini::readonly' => ['void'], 'Yaf_Config_Ini::rewind' => ['void'], 'Yaf_Config_Ini::set' => ['Yaf_Config_Abstract', 'name'=>'string', 'value'=>'mixed'], 'Yaf_Config_Ini::toArray' => ['array'], 'Yaf_Config_Ini::valid' => ['void'], 'Yaf_Config_Simple::__construct' => ['void', 'config_file'=>'string', 'section='=>'string'], 'Yaf_Config_Simple::__get' => ['void', 'name='=>'string'], 'Yaf_Config_Simple::__isset' => ['void', 'name'=>'string'], 'Yaf_Config_Simple::__set' => ['void', 'name'=>'string', 'value'=>'string'], 'Yaf_Config_Simple::count' => ['void'], 'Yaf_Config_Simple::current' => ['void'], 'Yaf_Config_Simple::get' => ['mixed', 'name='=>'mixed'], 'Yaf_Config_Simple::key' => ['void'], 'Yaf_Config_Simple::next' => ['void'], 'Yaf_Config_Simple::offsetExists' => ['void', 'name'=>'string'], 'Yaf_Config_Simple::offsetGet' => ['void', 'name'=>'string'], 'Yaf_Config_Simple::offsetSet' => ['void', 'name'=>'string', 'value'=>'string'], 'Yaf_Config_Simple::offsetUnset' => ['void', 'name'=>'string'], 'Yaf_Config_Simple::readonly' => ['void'], 'Yaf_Config_Simple::rewind' => ['void'], 'Yaf_Config_Simple::set' => ['Yaf_Config_Abstract', 'name'=>'string', 'value'=>'mixed'], 'Yaf_Config_Simple::toArray' => ['array'], 'Yaf_Config_Simple::valid' => ['void'], 'Yaf_Controller_Abstract::__clone' => ['void'], 'Yaf_Controller_Abstract::__construct' => ['void'], 'Yaf_Controller_Abstract::display' => ['bool', 'tpl'=>'string', 'parameters='=>'array'], 'Yaf_Controller_Abstract::forward' => ['void', 'action'=>'string', 'parameters='=>'array'], 'Yaf_Controller_Abstract::forward\'1' => ['void', 'controller'=>'string', 'action'=>'string', 'parameters='=>'array'], 'Yaf_Controller_Abstract::forward\'2' => ['void', 'module'=>'string', 'controller'=>'string', 'action'=>'string', 'parameters='=>'array'], 'Yaf_Controller_Abstract::getInvokeArg' => ['void', 'name'=>'string'], 'Yaf_Controller_Abstract::getInvokeArgs' => ['void'], 'Yaf_Controller_Abstract::getModuleName' => ['string'], 'Yaf_Controller_Abstract::getName' => ['string'], 'Yaf_Controller_Abstract::getRequest' => ['Yaf_Request_Abstract'], 'Yaf_Controller_Abstract::getResponse' => ['Yaf_Response_Abstract'], 'Yaf_Controller_Abstract::getView' => ['Yaf_View_Interface'], 'Yaf_Controller_Abstract::getViewpath' => ['void'], 'Yaf_Controller_Abstract::init' => ['void'], 'Yaf_Controller_Abstract::initView' => ['void', 'options='=>'array'], 'Yaf_Controller_Abstract::redirect' => ['bool', 'url'=>'string'], 'Yaf_Controller_Abstract::render' => ['string', 'tpl'=>'string', 'parameters='=>'array'], 'Yaf_Controller_Abstract::setViewpath' => ['void', 'view_directory'=>'string'], 'Yaf_Dispatcher::__clone' => ['void'], 'Yaf_Dispatcher::__construct' => ['void'], 'Yaf_Dispatcher::__sleep' => ['list'], 'Yaf_Dispatcher::__wakeup' => ['void'], 'Yaf_Dispatcher::autoRender' => ['Yaf_Dispatcher', 'flag='=>'bool'], 'Yaf_Dispatcher::catchException' => ['Yaf_Dispatcher', 'flag='=>'bool'], 'Yaf_Dispatcher::disableView' => ['bool'], 'Yaf_Dispatcher::dispatch' => ['Yaf_Response_Abstract', 'request'=>'Yaf_Request_Abstract'], 'Yaf_Dispatcher::enableView' => ['Yaf_Dispatcher'], 'Yaf_Dispatcher::flushInstantly' => ['Yaf_Dispatcher', 'flag='=>'bool'], 'Yaf_Dispatcher::getApplication' => ['Yaf_Application'], 'Yaf_Dispatcher::getDefaultAction' => ['string'], 'Yaf_Dispatcher::getDefaultController' => ['string'], 'Yaf_Dispatcher::getDefaultModule' => ['string'], 'Yaf_Dispatcher::getInstance' => ['Yaf_Dispatcher'], 'Yaf_Dispatcher::getRequest' => ['Yaf_Request_Abstract'], 'Yaf_Dispatcher::getRouter' => ['Yaf_Router'], 'Yaf_Dispatcher::initView' => ['Yaf_View_Interface', 'templates_dir'=>'string', 'options='=>'array'], 'Yaf_Dispatcher::registerPlugin' => ['Yaf_Dispatcher', 'plugin'=>'Yaf_Plugin_Abstract'], 'Yaf_Dispatcher::returnResponse' => ['Yaf_Dispatcher', 'flag'=>'bool'], 'Yaf_Dispatcher::setDefaultAction' => ['Yaf_Dispatcher', 'action'=>'string'], 'Yaf_Dispatcher::setDefaultController' => ['Yaf_Dispatcher', 'controller'=>'string'], 'Yaf_Dispatcher::setDefaultModule' => ['Yaf_Dispatcher', 'module'=>'string'], 'Yaf_Dispatcher::setErrorHandler' => ['Yaf_Dispatcher', 'callback'=>'callable', 'error_types'=>'int'], 'Yaf_Dispatcher::setRequest' => ['Yaf_Dispatcher', 'request'=>'Yaf_Request_Abstract'], 'Yaf_Dispatcher::setView' => ['Yaf_Dispatcher', 'view'=>'Yaf_View_Interface'], 'Yaf_Dispatcher::throwException' => ['Yaf_Dispatcher', 'flag='=>'bool'], 'Yaf_Exception::__construct' => ['void'], 'Yaf_Exception::getPrevious' => ['void'], 'Yaf_Loader::__clone' => ['void'], 'Yaf_Loader::__construct' => ['void'], 'Yaf_Loader::__sleep' => ['list'], 'Yaf_Loader::__wakeup' => ['void'], 'Yaf_Loader::autoload' => ['void'], 'Yaf_Loader::clearLocalNamespace' => ['void'], 'Yaf_Loader::getInstance' => ['Yaf_Loader'], 'Yaf_Loader::getLibraryPath' => ['Yaf_Loader', 'is_global='=>'bool'], 'Yaf_Loader::getLocalNamespace' => ['void'], 'Yaf_Loader::getNamespacePath' => ['string', 'namespaces'=>'string'], 'Yaf_Loader::import' => ['bool'], 'Yaf_Loader::isLocalName' => ['bool'], 'Yaf_Loader::registerLocalNamespace' => ['void', 'prefix'=>'mixed'], 'Yaf_Loader::registerNamespace' => ['bool', 'namespaces'=>'string|array', 'path='=>'string'], 'Yaf_Loader::setLibraryPath' => ['Yaf_Loader', 'directory'=>'string', 'is_global='=>'bool'], 'Yaf_Plugin_Abstract::dispatchLoopShutdown' => ['void', 'request'=>'Yaf_Request_Abstract', 'response'=>'Yaf_Response_Abstract'], 'Yaf_Plugin_Abstract::dispatchLoopStartup' => ['void', 'request'=>'Yaf_Request_Abstract', 'response'=>'Yaf_Response_Abstract'], 'Yaf_Plugin_Abstract::postDispatch' => ['void', 'request'=>'Yaf_Request_Abstract', 'response'=>'Yaf_Response_Abstract'], 'Yaf_Plugin_Abstract::preDispatch' => ['void', 'request'=>'Yaf_Request_Abstract', 'response'=>'Yaf_Response_Abstract'], 'Yaf_Plugin_Abstract::preResponse' => ['void', 'request'=>'Yaf_Request_Abstract', 'response'=>'Yaf_Response_Abstract'], 'Yaf_Plugin_Abstract::routerShutdown' => ['void', 'request'=>'Yaf_Request_Abstract', 'response'=>'Yaf_Response_Abstract'], 'Yaf_Plugin_Abstract::routerStartup' => ['void', 'request'=>'Yaf_Request_Abstract', 'response'=>'Yaf_Response_Abstract'], 'Yaf_Registry::__clone' => ['void'], 'Yaf_Registry::__construct' => ['void'], 'Yaf_Registry::del' => ['void', 'name'=>'string'], 'Yaf_Registry::get' => ['mixed', 'name'=>'string'], 'Yaf_Registry::has' => ['bool', 'name'=>'string'], 'Yaf_Registry::set' => ['bool', 'name'=>'string', 'value'=>'string'], 'Yaf_Request_Abstract::clearParams' => ['bool'], 'Yaf_Request_Abstract::getActionName' => ['void'], 'Yaf_Request_Abstract::getBaseUri' => ['void'], 'Yaf_Request_Abstract::getControllerName' => ['void'], 'Yaf_Request_Abstract::getEnv' => ['void', 'name'=>'string', 'default='=>'string'], 'Yaf_Request_Abstract::getException' => ['void'], 'Yaf_Request_Abstract::getLanguage' => ['void'], 'Yaf_Request_Abstract::getMethod' => ['void'], 'Yaf_Request_Abstract::getModuleName' => ['void'], 'Yaf_Request_Abstract::getParam' => ['void', 'name'=>'string', 'default='=>'string'], 'Yaf_Request_Abstract::getParams' => ['void'], 'Yaf_Request_Abstract::getRequestUri' => ['void'], 'Yaf_Request_Abstract::getServer' => ['void', 'name'=>'string', 'default='=>'string'], 'Yaf_Request_Abstract::isCli' => ['void'], 'Yaf_Request_Abstract::isDispatched' => ['void'], 'Yaf_Request_Abstract::isGet' => ['void'], 'Yaf_Request_Abstract::isHead' => ['void'], 'Yaf_Request_Abstract::isOptions' => ['void'], 'Yaf_Request_Abstract::isPost' => ['void'], 'Yaf_Request_Abstract::isPut' => ['void'], 'Yaf_Request_Abstract::isRouted' => ['void'], 'Yaf_Request_Abstract::isXmlHttpRequest' => ['void'], 'Yaf_Request_Abstract::setActionName' => ['void', 'action'=>'string'], 'Yaf_Request_Abstract::setBaseUri' => ['bool', 'uir'=>'string'], 'Yaf_Request_Abstract::setControllerName' => ['void', 'controller'=>'string'], 'Yaf_Request_Abstract::setDispatched' => ['void'], 'Yaf_Request_Abstract::setModuleName' => ['void', 'module'=>'string'], 'Yaf_Request_Abstract::setParam' => ['void', 'name'=>'string', 'value='=>'string'], 'Yaf_Request_Abstract::setRequestUri' => ['void', 'uir'=>'string'], 'Yaf_Request_Abstract::setRouted' => ['void', 'flag='=>'string'], 'Yaf_Request_Http::__clone' => ['void'], 'Yaf_Request_Http::__construct' => ['void'], 'Yaf_Request_Http::get' => ['mixed', 'name'=>'string', 'default='=>'string'], 'Yaf_Request_Http::getActionName' => ['string'], 'Yaf_Request_Http::getBaseUri' => ['string'], 'Yaf_Request_Http::getControllerName' => ['string'], 'Yaf_Request_Http::getCookie' => ['mixed', 'name'=>'string', 'default='=>'string'], 'Yaf_Request_Http::getEnv' => ['mixed', 'name='=>'string', 'default='=>'mixed'], 'Yaf_Request_Http::getException' => ['Yaf_Exception'], 'Yaf_Request_Http::getFiles' => ['void'], 'Yaf_Request_Http::getLanguage' => ['string'], 'Yaf_Request_Http::getMethod' => ['string'], 'Yaf_Request_Http::getModuleName' => ['string'], 'Yaf_Request_Http::getParam' => ['mixed', 'name'=>'string', 'default='=>'mixed'], 'Yaf_Request_Http::getParams' => ['array'], 'Yaf_Request_Http::getPost' => ['mixed', 'name'=>'string', 'default='=>'string'], 'Yaf_Request_Http::getQuery' => ['mixed', 'name'=>'string', 'default='=>'string'], 'Yaf_Request_Http::getRaw' => ['mixed'], 'Yaf_Request_Http::getRequest' => ['void'], 'Yaf_Request_Http::getRequestUri' => ['string'], 'Yaf_Request_Http::getServer' => ['mixed', 'name='=>'string', 'default='=>'mixed'], 'Yaf_Request_Http::isCli' => ['bool'], 'Yaf_Request_Http::isDispatched' => ['bool'], 'Yaf_Request_Http::isGet' => ['bool'], 'Yaf_Request_Http::isHead' => ['bool'], 'Yaf_Request_Http::isOptions' => ['bool'], 'Yaf_Request_Http::isPost' => ['bool'], 'Yaf_Request_Http::isPut' => ['bool'], 'Yaf_Request_Http::isRouted' => ['bool'], 'Yaf_Request_Http::isXmlHttpRequest' => ['bool'], 'Yaf_Request_Http::setActionName' => ['Yaf_Request_Abstract|bool', 'action'=>'string'], 'Yaf_Request_Http::setBaseUri' => ['bool', 'uri'=>'string'], 'Yaf_Request_Http::setControllerName' => ['Yaf_Request_Abstract|bool', 'controller'=>'string'], 'Yaf_Request_Http::setDispatched' => ['bool'], 'Yaf_Request_Http::setModuleName' => ['Yaf_Request_Abstract|bool', 'module'=>'string'], 'Yaf_Request_Http::setParam' => ['Yaf_Request_Abstract|bool', 'name'=>'array|string', 'value='=>'string'], 'Yaf_Request_Http::setRequestUri' => ['', 'uri'=>'string'], 'Yaf_Request_Http::setRouted' => ['Yaf_Request_Abstract|bool'], 'Yaf_Request_Simple::__clone' => ['void'], 'Yaf_Request_Simple::__construct' => ['void'], 'Yaf_Request_Simple::get' => ['void'], 'Yaf_Request_Simple::getActionName' => ['string'], 'Yaf_Request_Simple::getBaseUri' => ['string'], 'Yaf_Request_Simple::getControllerName' => ['string'], 'Yaf_Request_Simple::getCookie' => ['void'], 'Yaf_Request_Simple::getEnv' => ['mixed', 'name='=>'string', 'default='=>'mixed'], 'Yaf_Request_Simple::getException' => ['Yaf_Exception'], 'Yaf_Request_Simple::getFiles' => ['void'], 'Yaf_Request_Simple::getLanguage' => ['string'], 'Yaf_Request_Simple::getMethod' => ['string'], 'Yaf_Request_Simple::getModuleName' => ['string'], 'Yaf_Request_Simple::getParam' => ['mixed', 'name'=>'string', 'default='=>'mixed'], 'Yaf_Request_Simple::getParams' => ['array'], 'Yaf_Request_Simple::getPost' => ['void'], 'Yaf_Request_Simple::getQuery' => ['void'], 'Yaf_Request_Simple::getRequest' => ['void'], 'Yaf_Request_Simple::getRequestUri' => ['string'], 'Yaf_Request_Simple::getServer' => ['mixed', 'name='=>'string', 'default='=>'mixed'], 'Yaf_Request_Simple::isCli' => ['bool'], 'Yaf_Request_Simple::isDispatched' => ['bool'], 'Yaf_Request_Simple::isGet' => ['bool'], 'Yaf_Request_Simple::isHead' => ['bool'], 'Yaf_Request_Simple::isOptions' => ['bool'], 'Yaf_Request_Simple::isPost' => ['bool'], 'Yaf_Request_Simple::isPut' => ['bool'], 'Yaf_Request_Simple::isRouted' => ['bool'], 'Yaf_Request_Simple::isXmlHttpRequest' => ['void'], 'Yaf_Request_Simple::setActionName' => ['Yaf_Request_Abstract|bool', 'action'=>'string'], 'Yaf_Request_Simple::setBaseUri' => ['bool', 'uri'=>'string'], 'Yaf_Request_Simple::setControllerName' => ['Yaf_Request_Abstract|bool', 'controller'=>'string'], 'Yaf_Request_Simple::setDispatched' => ['bool'], 'Yaf_Request_Simple::setModuleName' => ['Yaf_Request_Abstract|bool', 'module'=>'string'], 'Yaf_Request_Simple::setParam' => ['Yaf_Request_Abstract|bool', 'name'=>'array|string', 'value='=>'string'], 'Yaf_Request_Simple::setRequestUri' => ['', 'uri'=>'string'], 'Yaf_Request_Simple::setRouted' => ['Yaf_Request_Abstract|bool'], 'Yaf_Response_Abstract::__clone' => ['void'], 'Yaf_Response_Abstract::__construct' => ['void'], 'Yaf_Response_Abstract::__destruct' => ['void'], 'Yaf_Response_Abstract::__toString' => ['string'], 'Yaf_Response_Abstract::appendBody' => ['bool', 'content'=>'string', 'key='=>'string'], 'Yaf_Response_Abstract::clearBody' => ['bool', 'key='=>'string'], 'Yaf_Response_Abstract::clearHeaders' => ['void'], 'Yaf_Response_Abstract::getBody' => ['mixed', 'key='=>'string'], 'Yaf_Response_Abstract::getHeader' => ['void'], 'Yaf_Response_Abstract::prependBody' => ['bool', 'content'=>'string', 'key='=>'string'], 'Yaf_Response_Abstract::response' => ['void'], 'Yaf_Response_Abstract::setAllHeaders' => ['void'], 'Yaf_Response_Abstract::setBody' => ['bool', 'content'=>'string', 'key='=>'string'], 'Yaf_Response_Abstract::setHeader' => ['void'], 'Yaf_Response_Abstract::setRedirect' => ['void'], 'Yaf_Response_Cli::__clone' => ['void'], 'Yaf_Response_Cli::__construct' => ['void'], 'Yaf_Response_Cli::__destruct' => ['void'], 'Yaf_Response_Cli::__toString' => ['string'], 'Yaf_Response_Cli::appendBody' => ['bool', 'content'=>'string', 'key='=>'string'], 'Yaf_Response_Cli::clearBody' => ['bool', 'key='=>'string'], 'Yaf_Response_Cli::getBody' => ['mixed', 'key='=>'?string'], 'Yaf_Response_Cli::prependBody' => ['bool', 'content'=>'string', 'key='=>'string'], 'Yaf_Response_Cli::setBody' => ['bool', 'content'=>'string', 'key='=>'string'], 'Yaf_Response_Http::__clone' => ['void'], 'Yaf_Response_Http::__construct' => ['void'], 'Yaf_Response_Http::__destruct' => ['void'], 'Yaf_Response_Http::__toString' => ['string'], 'Yaf_Response_Http::appendBody' => ['bool', 'content'=>'string', 'key='=>'string'], 'Yaf_Response_Http::clearBody' => ['bool', 'key='=>'string'], 'Yaf_Response_Http::clearHeaders' => ['Yaf_Response_Abstract|false', 'name='=>'string'], 'Yaf_Response_Http::getBody' => ['mixed', 'key='=>'?string'], 'Yaf_Response_Http::getHeader' => ['mixed', 'name='=>'string'], 'Yaf_Response_Http::prependBody' => ['bool', 'content'=>'string', 'key='=>'string'], 'Yaf_Response_Http::response' => ['bool'], 'Yaf_Response_Http::setAllHeaders' => ['bool', 'headers'=>'array'], 'Yaf_Response_Http::setBody' => ['bool', 'content'=>'string', 'key='=>'string'], 'Yaf_Response_Http::setHeader' => ['bool', 'name'=>'string', 'value'=>'string', 'replace='=>'bool', 'response_code='=>'int'], 'Yaf_Response_Http::setRedirect' => ['bool', 'url'=>'string'], 'Yaf_Route_Interface::__construct' => ['void'], 'Yaf_Route_Interface::assemble' => ['string', 'info'=>'array', 'query='=>'array'], 'Yaf_Route_Interface::route' => ['bool', 'request'=>'Yaf_Request_Abstract'], 'Yaf_Route_Map::__construct' => ['void', 'controller_prefer='=>'string', 'delimiter='=>'string'], 'Yaf_Route_Map::assemble' => ['string', 'info'=>'array', 'query='=>'array'], 'Yaf_Route_Map::route' => ['bool', 'request'=>'Yaf_Request_Abstract'], 'Yaf_Route_Regex::__construct' => ['void', 'match'=>'string', 'route'=>'array', 'map='=>'array', 'verify='=>'array', 'reverse='=>'string'], 'Yaf_Route_Regex::addConfig' => ['Yaf_Router|bool', 'config'=>'Yaf_Config_Abstract'], 'Yaf_Route_Regex::addRoute' => ['Yaf_Router|bool', 'name'=>'string', 'route'=>'Yaf_Route_Interface'], 'Yaf_Route_Regex::assemble' => ['string', 'info'=>'array', 'query='=>'array'], 'Yaf_Route_Regex::getCurrentRoute' => ['string'], 'Yaf_Route_Regex::getRoute' => ['Yaf_Route_Interface', 'name'=>'string'], 'Yaf_Route_Regex::getRoutes' => ['Yaf_Route_Interface[]'], 'Yaf_Route_Regex::route' => ['bool', 'request'=>'Yaf_Request_Abstract'], 'Yaf_Route_Rewrite::__construct' => ['void', 'match'=>'string', 'route'=>'array', 'verify='=>'array'], 'Yaf_Route_Rewrite::addConfig' => ['Yaf_Router|bool', 'config'=>'Yaf_Config_Abstract'], 'Yaf_Route_Rewrite::addRoute' => ['Yaf_Router|bool', 'name'=>'string', 'route'=>'Yaf_Route_Interface'], 'Yaf_Route_Rewrite::assemble' => ['string', 'info'=>'array', 'query='=>'array'], 'Yaf_Route_Rewrite::getCurrentRoute' => ['string'], 'Yaf_Route_Rewrite::getRoute' => ['Yaf_Route_Interface', 'name'=>'string'], 'Yaf_Route_Rewrite::getRoutes' => ['Yaf_Route_Interface[]'], 'Yaf_Route_Rewrite::route' => ['bool', 'request'=>'Yaf_Request_Abstract'], 'Yaf_Route_Simple::__construct' => ['void', 'module_name'=>'string', 'controller_name'=>'string', 'action_name'=>'string'], 'Yaf_Route_Simple::assemble' => ['string', 'info'=>'array', 'query='=>'array'], 'Yaf_Route_Simple::route' => ['bool', 'request'=>'Yaf_Request_Abstract'], 'Yaf_Route_Static::assemble' => ['string', 'info'=>'array', 'query='=>'array'], 'Yaf_Route_Static::match' => ['void', 'uri'=>'string'], 'Yaf_Route_Static::route' => ['bool', 'request'=>'Yaf_Request_Abstract'], 'Yaf_Route_Supervar::__construct' => ['void', 'supervar_name'=>'string'], 'Yaf_Route_Supervar::assemble' => ['string', 'info'=>'array', 'query='=>'array'], 'Yaf_Route_Supervar::route' => ['bool', 'request'=>'Yaf_Request_Abstract'], 'Yaf_Router::__construct' => ['void'], 'Yaf_Router::addConfig' => ['bool', 'config'=>'Yaf_Config_Abstract'], 'Yaf_Router::addRoute' => ['bool', 'name'=>'string', 'route'=>'Yaf_Route_Interface'], 'Yaf_Router::getCurrentRoute' => ['string'], 'Yaf_Router::getRoute' => ['Yaf_Route_Interface', 'name'=>'string'], 'Yaf_Router::getRoutes' => ['mixed'], 'Yaf_Router::route' => ['bool', 'request'=>'Yaf_Request_Abstract'], 'Yaf_Session::__clone' => ['void'], 'Yaf_Session::__construct' => ['void'], 'Yaf_Session::__get' => ['void', 'name'=>'string'], 'Yaf_Session::__isset' => ['void', 'name'=>'string'], 'Yaf_Session::__set' => ['void', 'name'=>'string', 'value'=>'string'], 'Yaf_Session::__sleep' => ['list'], 'Yaf_Session::__unset' => ['void', 'name'=>'string'], 'Yaf_Session::__wakeup' => ['void'], 'Yaf_Session::count' => ['void'], 'Yaf_Session::current' => ['void'], 'Yaf_Session::del' => ['void', 'name'=>'string'], 'Yaf_Session::get' => ['mixed', 'name'=>'string'], 'Yaf_Session::getInstance' => ['void'], 'Yaf_Session::has' => ['void', 'name'=>'string'], 'Yaf_Session::key' => ['void'], 'Yaf_Session::next' => ['void'], 'Yaf_Session::offsetExists' => ['void', 'name'=>'string'], 'Yaf_Session::offsetGet' => ['void', 'name'=>'string'], 'Yaf_Session::offsetSet' => ['void', 'name'=>'string', 'value'=>'string'], 'Yaf_Session::offsetUnset' => ['void', 'name'=>'string'], 'Yaf_Session::rewind' => ['void'], 'Yaf_Session::set' => ['Yaf_Session|bool', 'name'=>'string', 'value'=>'mixed'], 'Yaf_Session::start' => ['void'], 'Yaf_Session::valid' => ['void'], 'Yaf_View_Interface::assign' => ['bool', 'name'=>'string', 'value='=>'string'], 'Yaf_View_Interface::display' => ['bool', 'tpl'=>'string', 'tpl_vars='=>'array'], 'Yaf_View_Interface::getScriptPath' => ['string'], 'Yaf_View_Interface::render' => ['string', 'tpl'=>'string', 'tpl_vars='=>'array'], 'Yaf_View_Interface::setScriptPath' => ['void', 'template_dir'=>'string'], 'Yaf_View_Simple::__construct' => ['void', 'tempalte_dir'=>'string', 'options='=>'array'], 'Yaf_View_Simple::__get' => ['void', 'name='=>'string'], 'Yaf_View_Simple::__isset' => ['void', 'name'=>'string'], 'Yaf_View_Simple::__set' => ['void', 'name'=>'string', 'value'=>'mixed'], 'Yaf_View_Simple::assign' => ['bool', 'name'=>'string', 'value='=>'mixed'], 'Yaf_View_Simple::assignRef' => ['bool', 'name'=>'string', '&rw_value'=>'mixed'], 'Yaf_View_Simple::clear' => ['bool', 'name='=>'string'], 'Yaf_View_Simple::display' => ['bool', 'tpl'=>'string', 'tpl_vars='=>'array'], 'Yaf_View_Simple::eval' => ['string', 'tpl_content'=>'string', 'tpl_vars='=>'array'], 'Yaf_View_Simple::getScriptPath' => ['string'], 'Yaf_View_Simple::render' => ['string', 'tpl'=>'string', 'tpl_vars='=>'array'], 'Yaf_View_Simple::setScriptPath' => ['bool', 'template_dir'=>'string'], 'yaml_emit' => ['string', 'data'=>'mixed', 'encoding='=>'int', 'linebreak='=>'int', 'callbacks='=>'array'], 'yaml_emit_file' => ['bool', 'filename'=>'string', 'data'=>'mixed', 'encoding='=>'int', 'linebreak='=>'int', 'callbacks='=>'array'], 'yaml_parse' => ['mixed|false', 'input'=>'string', 'pos='=>'int', '&w_ndocs='=>'int', 'callbacks='=>'array'], 'yaml_parse_file' => ['mixed|false', 'filename'=>'string', 'pos='=>'int', '&w_ndocs='=>'int', 'callbacks='=>'array'], 'yaml_parse_url' => ['mixed|false', 'url'=>'string', 'pos='=>'int', '&w_ndocs='=>'int', 'callbacks='=>'array'], 'Yar_Client::__call' => ['void', 'method'=>'string', 'parameters'=>'array'], 'Yar_Client::__construct' => ['void', 'url'=>'string'], 'Yar_Client::setOpt' => ['Yar_Client|false', 'name'=>'int', 'value'=>'mixed'], 'Yar_Client_Exception::__clone' => ['void'], 'Yar_Client_Exception::__construct' => ['void', 'message='=>'string', 'code='=>'int', 'previous='=>'?Exception|?Throwable'], 'Yar_Client_Exception::__toString' => ['string'], 'Yar_Client_Exception::__wakeup' => ['void'], 'Yar_Client_Exception::getCode' => ['int'], 'Yar_Client_Exception::getFile' => ['string'], 'Yar_Client_Exception::getLine' => ['int'], 'Yar_Client_Exception::getMessage' => ['string'], 'Yar_Client_Exception::getPrevious' => ['?Exception|?Throwable'], 'Yar_Client_Exception::getTrace' => ['list\',args?:array}>'], 'Yar_Client_Exception::getTraceAsString' => ['string'], 'Yar_Client_Exception::getType' => ['string'], 'Yar_Concurrent_Client::call' => ['int', 'uri'=>'string', 'method'=>'string', 'parameters'=>'array', 'callback='=>'callable'], 'Yar_Concurrent_Client::loop' => ['bool', 'callback='=>'callable', 'error_callback='=>'callable'], 'Yar_Concurrent_Client::reset' => ['bool'], 'Yar_Server::__construct' => ['void', 'object'=>'Object'], 'Yar_Server::handle' => ['bool'], 'Yar_Server_Exception::__clone' => ['void'], 'Yar_Server_Exception::__construct' => ['void', 'message='=>'string', 'code='=>'int', 'previous='=>'?Exception|?Throwable'], 'Yar_Server_Exception::__toString' => ['string'], 'Yar_Server_Exception::__wakeup' => ['void'], 'Yar_Server_Exception::getCode' => ['int'], 'Yar_Server_Exception::getFile' => ['string'], 'Yar_Server_Exception::getLine' => ['int'], 'Yar_Server_Exception::getMessage' => ['string'], 'Yar_Server_Exception::getPrevious' => ['?Exception|?Throwable'], 'Yar_Server_Exception::getTrace' => ['list\',args?:array}>'], 'Yar_Server_Exception::getTraceAsString' => ['string'], 'Yar_Server_Exception::getType' => ['string'], 'yaz_addinfo' => ['string', 'id'=>'resource'], 'yaz_ccl_conf' => ['void', 'id'=>'resource', 'config'=>'array'], 'yaz_ccl_parse' => ['bool', 'id'=>'resource', 'query'=>'string', '&w_result'=>'array'], 'yaz_close' => ['bool', 'id'=>'resource'], 'yaz_connect' => ['mixed', 'zurl'=>'string', 'options='=>'mixed'], 'yaz_database' => ['bool', 'id'=>'resource', 'databases'=>'string'], 'yaz_element' => ['bool', 'id'=>'resource', 'elementset'=>'string'], 'yaz_errno' => ['int', 'id'=>'resource'], 'yaz_error' => ['string', 'id'=>'resource'], 'yaz_es' => ['void', 'id'=>'resource', 'type'=>'string', 'args'=>'array'], 'yaz_es_result' => ['array', 'id'=>'resource'], 'yaz_get_option' => ['string', 'id'=>'resource', 'name'=>'string'], 'yaz_hits' => ['int', 'id'=>'resource', 'searchresult='=>'array'], 'yaz_itemorder' => ['void', 'id'=>'resource', 'args'=>'array'], 'yaz_present' => ['bool', 'id'=>'resource'], 'yaz_range' => ['void', 'id'=>'resource', 'start'=>'int', 'number'=>'int'], 'yaz_record' => ['string', 'id'=>'resource', 'pos'=>'int', 'type'=>'string'], 'yaz_scan' => ['void', 'id'=>'resource', 'type'=>'string', 'startterm'=>'string', 'flags='=>'array'], 'yaz_scan_result' => ['array', 'id'=>'resource', 'result='=>'array'], 'yaz_schema' => ['void', 'id'=>'resource', 'schema'=>'string'], 'yaz_search' => ['bool', 'id'=>'resource', 'type'=>'string', 'query'=>'string'], 'yaz_set_option' => ['', 'id'=>'', 'name'=>'string', 'value'=>'string', 'options'=>'array'], 'yaz_sort' => ['void', 'id'=>'resource', 'criteria'=>'string'], 'yaz_syntax' => ['void', 'id'=>'resource', 'syntax'=>'string'], 'yaz_wait' => ['mixed', '&rw_options='=>'array'], 'yp_all' => ['void', 'domain'=>'string', 'map'=>'string', 'callback'=>'string'], 'yp_cat' => ['array', 'domain'=>'string', 'map'=>'string'], 'yp_err_string' => ['string', 'errorcode'=>'int'], 'yp_errno' => ['int'], 'yp_first' => ['array', 'domain'=>'string', 'map'=>'string'], 'yp_get_default_domain' => ['string'], 'yp_master' => ['string', 'domain'=>'string', 'map'=>'string'], 'yp_match' => ['string', 'domain'=>'string', 'map'=>'string', 'key'=>'string'], 'yp_next' => ['array', 'domain'=>'string', 'map'=>'string', 'key'=>'string'], 'yp_order' => ['int', 'domain'=>'string', 'map'=>'string'], 'zem_get_extension_info_by_id' => [''], 'zem_get_extension_info_by_name' => [''], 'zem_get_extensions_info' => [''], 'zem_get_license_info' => [''], 'zend_current_obfuscation_level' => ['int'], 'zend_disk_cache_clear' => ['bool', 'namespace='=>'mixed|string'], 'zend_disk_cache_delete' => ['mixed|null', 'key'=>'string'], 'zend_disk_cache_fetch' => ['mixed|null', 'key'=>'string'], 'zend_disk_cache_store' => ['bool', 'key'=>'', 'value'=>'', 'ttl='=>'int|mixed'], 'zend_get_id' => ['array', 'all_ids='=>'all_ids|false'], 'zend_is_configuration_changed' => [''], 'zend_loader_current_file' => ['string'], 'zend_loader_enabled' => ['bool'], 'zend_loader_file_encoded' => ['bool'], 'zend_loader_file_licensed' => ['array'], 'zend_loader_install_license' => ['bool', 'license_file'=>'string', 'override'=>'bool'], 'zend_logo_guid' => ['string'], 'zend_obfuscate_class_name' => ['string', 'class_name'=>'string'], 'zend_obfuscate_function_name' => ['string', 'function_name'=>'string'], 'zend_optimizer_version' => ['string'], 'zend_runtime_obfuscate' => ['void'], 'zend_send_buffer' => ['null|false', 'buffer'=>'string', 'mime_type='=>'string', 'custom_headers='=>'string'], 'zend_send_file' => ['null|false', 'filename'=>'string', 'mime_type='=>'string', 'custom_headers='=>'string'], 'zend_set_configuration_changed' => [''], 'zend_shm_cache_clear' => ['bool', 'namespace='=>'mixed|string'], 'zend_shm_cache_delete' => ['mixed|null', 'key'=>'string'], 'zend_shm_cache_fetch' => ['mixed|null', 'key'=>'string'], 'zend_shm_cache_store' => ['bool', 'key'=>'', 'value'=>'', 'ttl='=>'int|mixed'], 'zend_thread_id' => ['int'], 'zend_version' => ['string'], 'ZendAPI_Job::addJobToQueue' => ['int', 'jobqueue_url'=>'string', 'password'=>'string'], 'ZendAPI_Job::getApplicationID' => [''], 'ZendAPI_Job::getEndTime' => [''], 'ZendAPI_Job::getGlobalVariables' => [''], 'ZendAPI_Job::getHost' => [''], 'ZendAPI_Job::getID' => [''], 'ZendAPI_Job::getInterval' => [''], 'ZendAPI_Job::getJobDependency' => [''], 'ZendAPI_Job::getJobName' => [''], 'ZendAPI_Job::getJobPriority' => [''], 'ZendAPI_Job::getJobStatus' => ['int'], 'ZendAPI_Job::getLastPerformedStatus' => ['int'], 'ZendAPI_Job::getOutput' => ['An'], 'ZendAPI_Job::getPreserved' => [''], 'ZendAPI_Job::getProperties' => ['array'], 'ZendAPI_Job::getScheduledTime' => [''], 'ZendAPI_Job::getScript' => [''], 'ZendAPI_Job::getTimeToNextRepeat' => ['int'], 'ZendAPI_Job::getUserVariables' => [''], 'ZendAPI_Job::setApplicationID' => ['', 'app_id'=>''], 'ZendAPI_Job::setGlobalVariables' => ['', 'vars'=>''], 'ZendAPI_Job::setJobDependency' => ['', 'job_id'=>''], 'ZendAPI_Job::setJobName' => ['', 'name'=>''], 'ZendAPI_Job::setJobPriority' => ['', 'priority'=>'int'], 'ZendAPI_Job::setPreserved' => ['', 'preserved'=>''], 'ZendAPI_Job::setRecurrenceData' => ['', 'interval'=>'', 'end_time='=>'mixed'], 'ZendAPI_Job::setScheduledTime' => ['', 'timestamp'=>''], 'ZendAPI_Job::setScript' => ['', 'script'=>''], 'ZendAPI_Job::setUserVariables' => ['', 'vars'=>''], 'ZendAPI_Job::ZendAPI_Job' => ['Job', 'script'=>'script'], 'ZendAPI_Queue::addJob' => ['int', '&job'=>'Job'], 'ZendAPI_Queue::getAllApplicationIDs' => ['array'], 'ZendAPI_Queue::getAllhosts' => ['array'], 'ZendAPI_Queue::getHistoricJobs' => ['array', 'status'=>'int', 'start_time'=>'', 'end_time'=>'', 'index'=>'int', 'count'=>'int', '&total'=>'int'], 'ZendAPI_Queue::getJob' => ['Job', 'job_id'=>'int'], 'ZendAPI_Queue::getJobsInQueue' => ['array', 'filter_options='=>'array', 'max_jobs='=>'int', 'with_globals_and_output='=>'bool'], 'ZendAPI_Queue::getLastError' => ['string'], 'ZendAPI_Queue::getNumOfJobsInQueue' => ['int', 'filter_options='=>'array'], 'ZendAPI_Queue::getStatistics' => ['array'], 'ZendAPI_Queue::isScriptExists' => ['bool', 'path'=>'string'], 'ZendAPI_Queue::isSuspend' => ['bool'], 'ZendAPI_Queue::login' => ['bool', 'password'=>'string', 'application_id='=>'int'], 'ZendAPI_Queue::removeJob' => ['bool', 'job_id'=>'array|int'], 'ZendAPI_Queue::requeueJob' => ['bool', 'job'=>'Job'], 'ZendAPI_Queue::resumeJob' => ['bool', 'job_id'=>'array|int'], 'ZendAPI_Queue::resumeQueue' => ['bool'], 'ZendAPI_Queue::setMaxHistoryTime' => ['bool'], 'ZendAPI_Queue::suspendJob' => ['bool', 'job_id'=>'array|int'], 'ZendAPI_Queue::suspendQueue' => ['bool'], 'ZendAPI_Queue::updateJob' => ['int', '&job'=>'Job'], 'ZendAPI_Queue::zendapi_queue' => ['ZendAPI_Queue', 'queue_url'=>'string'], 'zip_close' => ['void', 'zip'=>'resource'], 'zip_entry_close' => ['bool', 'zip_entry'=>'resource'], 'zip_entry_compressedsize' => ['int', 'zip_entry'=>'resource'], 'zip_entry_compressionmethod' => ['string', 'zip_entry'=>'resource'], 'zip_entry_filesize' => ['int', 'zip_entry'=>'resource'], 'zip_entry_name' => ['string|false', 'zip_entry'=>'resource'], 'zip_entry_open' => ['bool', 'zip_dp'=>'resource', 'zip_entry'=>'resource', 'mode='=>'string'], 'zip_entry_read' => ['string|false', 'zip_entry'=>'resource', 'len='=>'int'], 'zip_open' => ['resource|int|false', 'filename'=>'string'], 'zip_read' => ['resource', 'zip'=>'resource'], 'ZipArchive::addEmptyDir' => ['bool', 'dirname'=>'string', 'flags='=>'int'], 'ZipArchive::addFile' => ['bool', 'filepath'=>'string', 'entryname='=>'string', 'start='=>'int', 'length='=>'int', 'flags='=>'int'], 'ZipArchive::addFromString' => ['bool', 'name'=>'string', 'content'=>'string', 'flags='=>'int'], 'ZipArchive::addGlob' => ['array|false', 'pattern'=>'string', 'flags='=>'int', 'options='=>'array'], 'ZipArchive::addPattern' => ['array|false', 'pattern'=>'string', 'path='=>'string', 'options='=>'array'], 'ZipArchive::clearError' => ['void'], 'ZipArchive::close' => ['bool'], 'ZipArchive::count' => ['int'], 'ZipArchive::deleteIndex' => ['bool', 'index'=>'int'], 'ZipArchive::deleteName' => ['bool', 'name'=>'string'], 'ZipArchive::extractTo' => ['bool', 'pathto'=>'string', 'files='=>'string[]|string|null'], 'ZipArchive::getArchiveComment' => ['string|false', 'flags='=>'int'], 'ZipArchive::getCommentIndex' => ['string|false', 'index'=>'int', 'flags='=>'int'], 'ZipArchive::getCommentName' => ['string|false', 'name'=>'string', 'flags='=>'int'], 'ZipArchive::getExternalAttributesIndex' => ['bool', 'index'=>'int', '&w_opsys'=>'int', '&w_attr'=>'int', 'flags='=>'int'], 'ZipArchive::getExternalAttributesName' => ['bool', 'name'=>'string', '&w_opsys'=>'int', '&w_attr'=>'int', 'flags='=>'int'], 'ZipArchive::getFromIndex' => ['string|false', 'index'=>'int', 'len='=>'int', 'flags='=>'int'], 'ZipArchive::getFromName' => ['string|false', 'name'=>'string', 'len='=>'int', 'flags='=>'int'], 'ZipArchive::getNameIndex' => ['string|false', 'index'=>'int', 'flags='=>'int'], 'ZipArchive::getStatusString' => ['string'], 'ZipArchive::getStream' => ['resource|false', 'name'=>'string'], 'ZipArchive::getStreamIndex' => ['resource|false', 'index'=>'int', 'flags='=>'int'], 'ZipArchive::getStreamName' => ['resource|false', 'name'=>'string', 'flags='=>'int'], 'ZipArchive::isCompressionMethodSupported' => ['bool', 'method'=>'int', 'enc='=>'bool'], 'ZipArchive::isEncryptionMethodSupported' => ['bool', 'method'=>'int', 'enc='=>'bool'], 'ZipArchive::locateName' => ['int|false', 'name'=>'string', 'flags='=>'int'], 'ZipArchive::open' => ['int|bool', 'filename'=>'string', 'flags='=>'int'], 'ZipArchive::registerCancelCallback' => ['bool', 'callback'=>'callable'], 'ZipArchive::registerProgressCallback' => ['bool', 'rate'=>'float', 'callback'=>'callable'], 'ZipArchive::renameIndex' => ['bool', 'index'=>'int', 'new_name'=>'string'], 'ZipArchive::renameName' => ['bool', 'name'=>'string', 'new_name'=>'string'], 'ZipArchive::replaceFile' => ['bool', 'filepath'=>'string', 'index'=>'int', 'start='=>'int', 'length='=>'int', 'flags='=>'int'], 'ZipArchive::setArchiveComment' => ['bool', 'comment'=>'string'], 'ZipArchive::setCommentIndex' => ['bool', 'index'=>'int', 'comment'=>'string'], 'ZipArchive::setCommentName' => ['bool', 'name'=>'string', 'comment'=>'string'], 'ZipArchive::setCompressionIndex' => ['bool', 'index'=>'int', 'method'=>'int', 'compflags='=>'int'], 'ZipArchive::setCompressionName' => ['bool', 'name'=>'string', 'method'=>'int', 'compflags='=>'int'], 'ZipArchive::setEncryptionIndex' => ['bool', 'index'=>'int', 'method'=>'int', 'password='=>'?string'], 'ZipArchive::setEncryptionName' => ['bool', 'name'=>'string', 'method'=>'int', 'password='=>'?string'], 'ZipArchive::setExternalAttributesIndex' => ['bool', 'index'=>'int', 'opsys'=>'int', 'attr'=>'int', 'flags='=>'int'], 'ZipArchive::setExternalAttributesName' => ['bool', 'name'=>'string', 'opsys'=>'int', 'attr'=>'int', 'flags='=>'int'], 'ZipArchive::setMtimeIndex' => ['bool', 'index'=>'int', 'timestamp'=>'int', 'flags='=>'int'], 'ZipArchive::setMtimeName' => ['bool', 'name'=>'string', 'timestamp'=>'int', 'flags='=>'int'], 'ZipArchive::setPassword' => ['bool', 'password'=>'string'], 'ZipArchive::statIndex' => ['array|false', 'index'=>'int', 'flags='=>'int'], 'ZipArchive::statName' => ['array|false', 'name'=>'string', 'flags='=>'int'], 'ZipArchive::unchangeAll' => ['bool'], 'ZipArchive::unchangeArchive' => ['bool'], 'ZipArchive::unchangeIndex' => ['bool', 'index'=>'int'], 'ZipArchive::unchangeName' => ['bool', 'name'=>'string'], 'zlib_decode' => ['string|false', 'data'=>'string', 'max_length='=>'int'], 'zlib_encode' => ['string|false', 'data'=>'string', 'encoding'=>'int', 'level='=>'int'], 'zlib_get_coding_type' => ['string|false'], 'ZMQ::__construct' => ['void'], 'ZMQContext::__construct' => ['void', 'io_threads='=>'int', 'is_persistent='=>'bool'], 'ZMQContext::getOpt' => ['int|string', 'key'=>'string'], 'ZMQContext::getSocket' => ['ZMQSocket', 'type'=>'int', 'persistent_id='=>'string', 'on_new_socket='=>'callable'], 'ZMQContext::isPersistent' => ['bool'], 'ZMQContext::setOpt' => ['ZMQContext', 'key'=>'int', 'value'=>'mixed'], 'ZMQDevice::__construct' => ['void', 'frontend'=>'ZMQSocket', 'backend'=>'ZMQSocket', 'listener='=>'ZMQSocket'], 'ZMQDevice::getIdleTimeout' => ['ZMQDevice'], 'ZMQDevice::getTimerTimeout' => ['ZMQDevice'], 'ZMQDevice::run' => ['void'], 'ZMQDevice::setIdleCallback' => ['ZMQDevice', 'cb_func'=>'callable', 'timeout'=>'int', 'user_data='=>'mixed'], 'ZMQDevice::setIdleTimeout' => ['ZMQDevice', 'timeout'=>'int'], 'ZMQDevice::setTimerCallback' => ['ZMQDevice', 'cb_func'=>'callable', 'timeout'=>'int', 'user_data='=>'mixed'], 'ZMQDevice::setTimerTimeout' => ['ZMQDevice', 'timeout'=>'int'], 'ZMQPoll::add' => ['string', 'entry'=>'mixed', 'type'=>'int'], 'ZMQPoll::clear' => ['ZMQPoll'], 'ZMQPoll::count' => ['int'], 'ZMQPoll::getLastErrors' => ['array'], 'ZMQPoll::poll' => ['int', '&w_readable'=>'array', '&w_writable'=>'array', 'timeout='=>'int'], 'ZMQPoll::remove' => ['bool', 'item'=>'mixed'], 'ZMQSocket::__construct' => ['void', 'context'=>'ZMQContext', 'type'=>'int', 'persistent_id='=>'string', 'on_new_socket='=>'callable'], 'ZMQSocket::bind' => ['ZMQSocket', 'dsn'=>'string', 'force='=>'bool'], 'ZMQSocket::connect' => ['ZMQSocket', 'dsn'=>'string', 'force='=>'bool'], 'ZMQSocket::disconnect' => ['ZMQSocket', 'dsn'=>'string'], 'ZMQSocket::getEndpoints' => ['array'], 'ZMQSocket::getPersistentId' => ['?string'], 'ZMQSocket::getSocketType' => ['int'], 'ZMQSocket::getSockOpt' => ['int|string', 'key'=>'string'], 'ZMQSocket::isPersistent' => ['bool'], 'ZMQSocket::recv' => ['string', 'mode='=>'int'], 'ZMQSocket::recvMulti' => ['string[]', 'mode='=>'int'], 'ZMQSocket::send' => ['ZMQSocket', 'message'=>'array', 'mode='=>'int'], 'ZMQSocket::send\'1' => ['ZMQSocket', 'message'=>'string', 'mode='=>'int'], 'ZMQSocket::sendmulti' => ['ZMQSocket', 'message'=>'array', 'mode='=>'int'], 'ZMQSocket::setSockOpt' => ['ZMQSocket', 'key'=>'int', 'value'=>'mixed'], 'ZMQSocket::unbind' => ['ZMQSocket', 'dsn'=>'string'], 'Zookeeper::addAuth' => ['bool', 'scheme'=>'string', 'cert'=>'string', 'completion_cb='=>'callable'], 'Zookeeper::close' => ['void'], 'Zookeeper::connect' => ['void', 'host'=>'string', 'watcher_cb='=>'callable', 'recv_timeout='=>'int'], 'Zookeeper::create' => ['string', 'path'=>'string', 'value'=>'string', 'acls'=>'array', 'flags='=>'int'], 'Zookeeper::delete' => ['bool', 'path'=>'string', 'version='=>'int'], 'Zookeeper::exists' => ['bool', 'path'=>'string', 'watcher_cb='=>'callable'], 'Zookeeper::get' => ['string', 'path'=>'string', 'watcher_cb='=>'callable', 'stat='=>'array', 'max_size='=>'int'], 'Zookeeper::getAcl' => ['array', 'path'=>'string'], 'Zookeeper::getChildren' => ['array|false', 'path'=>'string', 'watcher_cb='=>'callable'], 'Zookeeper::getClientId' => ['int'], 'Zookeeper::getConfig' => ['ZookeeperConfig'], 'Zookeeper::getRecvTimeout' => ['int'], 'Zookeeper::getState' => ['int'], 'Zookeeper::isRecoverable' => ['bool'], 'Zookeeper::set' => ['bool', 'path'=>'string', 'value'=>'string', 'version='=>'int', 'stat='=>'array'], 'Zookeeper::setAcl' => ['bool', 'path'=>'string', 'version'=>'int', 'acl'=>'array'], 'Zookeeper::setDebugLevel' => ['bool', 'logLevel'=>'int'], 'Zookeeper::setDeterministicConnOrder' => ['bool', 'yesOrNo'=>'bool'], 'Zookeeper::setLogStream' => ['bool', 'stream'=>'resource'], 'Zookeeper::setWatcher' => ['bool', 'watcher_cb'=>'callable'], 'zookeeper_dispatch' => ['void'], 'ZookeeperConfig::add' => ['void', 'members'=>'string', 'version='=>'int', 'stat='=>'array'], 'ZookeeperConfig::get' => ['string', 'watcher_cb='=>'callable', 'stat='=>'array'], 'ZookeeperConfig::remove' => ['void', 'id_list'=>'string', 'version='=>'int', 'stat='=>'array'], 'ZookeeperConfig::set' => ['void', 'members'=>'string', 'version='=>'int', 'stat='=>'array'], ]; [ 'Closure::fromCallable' => ['Closure', 'callback'=>'callable'], 'curl_multi_errno' => ['int|false', 'mh'=>'resource'], 'curl_share_errno' => ['int|false', 'sh'=>'resource'], 'curl_share_strerror' => ['?string', 'error_code'=>'int'], 'getenv\'1' => ['array'], 'hash_hkdf' => ['non-empty-string|false', 'algo'=>'string', 'key'=>'string', 'length='=>'int', 'info='=>'string', 'salt='=>'string'], 'is_iterable' => ['bool', 'value'=>'mixed'], 'openssl_get_curve_names' => ['list'], 'pcntl_async_signals' => ['bool', 'enable='=>'bool'], 'pcntl_signal_get_handler' => ['int|string', 'signal'=>'int'], 'sapi_windows_cp_conv' => ['?string', 'in_codepage'=>'int|string', 'out_codepage'=>'int|string', 'subject'=>'string'], 'sapi_windows_cp_get' => ['int', 'kind='=>'string'], 'sapi_windows_cp_is_utf8' => ['bool'], 'sapi_windows_cp_set' => ['bool', 'codepage'=>'int'], 'session_create_id' => ['string|false', 'prefix='=>'string'], 'session_gc' => ['int|false'], ], 'changed' => [ 'DateTimeZone::listIdentifiers' => [ 'old' => ['list|false', 'timezoneGroup='=>'int', 'countryCode='=>'string'], 'new' => ['list|false', 'timezoneGroup='=>'int', 'countryCode='=>'string|null'], ], 'IntlDateFormatter::format' => [ 'old' => ['string|false', 'value'=>'IntlCalendar|DateTime|array{0: int, 1: int, 2: int, 3: int, 4: int, 5: int, 6: int, 7: int, 8: int}|array{tm_sec: int, tm_min: int, tm_hour: int, tm_mday: int, tm_mon: int, tm_year: int, tm_wday: int, tm_yday: int, tm_isdst: int}|string|int|float'], 'new' => ['string|false', 'value'=>'IntlCalendar|DateTimeInterface|array{0: int, 1: int, 2: int, 3: int, 4: int, 5: int, 6: int, 7: int, 8: int}|array{tm_sec: int, tm_min: int, tm_hour: int, tm_mday: int, tm_mon: int, tm_year: int, tm_wday: int, tm_yday: int, tm_isdst: int}|string|int|float'], ], 'SessionHandler::gc' => [ 'old' => ['bool', 'max_lifetime'=>'int'], 'new' => ['int|false', 'max_lifetime'=>'int'], ], 'SQLite3::createFunction' => [ 'old' => ['bool', 'name'=>'string', 'callback'=>'callable', 'argCount='=>'int'], 'new' => ['bool', 'name'=>'string', 'callback'=>'callable', 'argCount='=>'int', 'flags='=>'int'], ], 'get_headers' => [ 'old' => ['array|false', 'url'=>'string', 'associative='=>'int'], 'new' => ['array|false', 'url'=>'string', 'associative='=>'int', 'context='=>'?resource'], ], 'getopt' => [ 'old' => ['array>|false', 'short_options'=>'string', 'long_options='=>'array'], 'new' => ['array>|false', 'short_options'=>'string', 'long_options='=>'array', '&w_rest_index='=>'int'], ], 'pg_fetch_all' => [ 'old' => ['array', 'result'=>'resource'], 'new' => ['array', 'result'=>'resource', 'mode='=>'int'], ], 'pg_select' => [ 'old' => ['string|array|false', 'connection'=>'resource', 'table_name'=>'string', 'conditions'=>'array', 'flags='=>'int'], 'new' => ['string|array|false', 'connection'=>'resource', 'table_name'=>'string', 'conditions'=>'array', 'flags='=>'int', 'mode='=>'int'], ], 'timezone_identifiers_list' => [ 'old' => ['list|false', 'timezoneGroup='=>'int', 'countryCode='=>'string'], 'new' => ['list|false', 'timezoneGroup='=>'int', 'countryCode='=>'?string'], ], 'unpack' => [ 'old' => ['array', 'format'=>'string', 'string'=>'string'], 'new' => ['array|false', 'format'=>'string', 'string'=>'string', 'offset='=>'int'], ], ], 'removed' => [ ], ]; [ 'DOMNodeList::count' => ['int'], 'ReflectionClass::isIterable' => ['bool'], 'ZipArchive::count' => ['int'], 'ZipArchive::setEncryptionIndex' => ['bool', 'index'=>'int', 'method'=>'int', 'password='=>'string'], 'ZipArchive::setEncryptionName' => ['bool', 'name'=>'string', 'method'=>'int', 'password='=>'string'], 'ftp_append' => ['bool', 'ftp'=>'resource', 'remote_filename'=>'string', 'local_filename'=>'string', 'mode='=>'int'], 'hash_hmac_algos' => ['list'], 'imagebmp' => ['bool', 'image'=>'resource', 'file='=>'resource|string|null', 'compressed='=>'int'], 'imagecreatefrombmp' => ['resource|false', 'filename'=>'string'], 'imageopenpolygon' => ['bool', 'image'=>'resource', 'points'=>'array', 'num_points'=>'int', 'color'=>'int'], 'imageresolution' => ['array|bool', 'image'=>'resource', 'resolution_x='=>'int', 'resolution_y='=>'int'], 'imagesetclip' => ['bool', 'image'=>'resource', 'x1'=>'int', 'y1'=>'int', 'x2'=>'int', 'y2'=>'int'], 'ldap_exop' => ['resource|bool', 'ldap'=>'resource', 'request_oid'=>'string', 'request_data='=>'?string', 'controls='=>'array|null', '&w_response_data='=>'string', '&w_response_oid='=>'string'], 'ldap_exop_passwd' => ['bool|string', 'ldap'=>'resource', 'user='=>'string', 'old_password='=>'string', 'new_password='=>'string'], 'ldap_exop_refresh' => ['int|false', 'ldap'=>'resource', 'dn'=>'string', 'ttl'=>'int'], 'ldap_exop_whoami' => ['string|false', 'ldap'=>'resource'], 'ldap_parse_exop' => ['bool', 'ldap'=>'resource', 'result'=>'resource', '&w_response_data='=>'string', '&w_response_oid='=>'string'], 'mb_chr' => ['non-empty-string|false', 'codepoint'=>'int', 'encoding='=>'string'], 'mb_convert_encoding\'1' => ['array', 'string'=>'array', 'to_encoding'=>'string', 'from_encoding='=>'mixed'], 'mb_ord' => ['int|false', 'string'=>'string', 'encoding='=>'string'], 'mb_scrub' => ['string', 'string'=>'string', 'encoding='=>'string'], 'oci_register_taf_callback' => ['bool', 'connection'=>'resource', 'callback='=>'callable'], 'oci_unregister_taf_callback' => ['bool', 'connection'=>'resource'], 'sapi_windows_vt100_support' => ['bool', 'stream'=>'resource', 'enable='=>'bool'], 'socket_addrinfo_bind' => ['?resource', 'addrinfo'=>'resource'], 'socket_addrinfo_connect' => ['resource', 'addrinfo'=>'resource'], 'socket_addrinfo_explain' => ['array', 'addrinfo'=>'resource'], 'socket_addrinfo_lookup' => ['resource[]', 'host'=>'string', 'service='=>'string', 'hints='=>'array'], 'sodium_add' => ['void', '&rw_string1'=>'string', 'string2'=>'string'], 'sodium_base642bin' => ['string', 'string'=>'string', 'id'=>'int', 'ignore='=>'string'], 'sodium_bin2base64' => ['string', 'string'=>'string', 'id'=>'int'], 'sodium_bin2hex' => ['string', 'string'=>'string'], 'sodium_compare' => ['int', 'string1'=>'string', 'string2'=>'string'], 'sodium_crypto_aead_aes256gcm_decrypt' => ['string|false', 'ciphertext'=>'string', 'additional_data'=>'string', 'nonce'=>'string', 'key'=>'string'], 'sodium_crypto_aead_aes256gcm_encrypt' => ['string', 'message'=>'string', 'additional_data'=>'string', 'nonce'=>'string', 'key'=>'string'], 'sodium_crypto_aead_aes256gcm_is_available' => ['bool'], 'sodium_crypto_aead_aes256gcm_keygen' => ['non-empty-string'], 'sodium_crypto_aead_chacha20poly1305_decrypt' => ['string|false', 'ciphertext'=>'string', 'additional_data'=>'string', 'nonce'=>'string', 'key'=>'string'], 'sodium_crypto_aead_chacha20poly1305_encrypt' => ['string', 'message'=>'string', 'additional_data'=>'string', 'nonce'=>'string', 'key'=>'string'], 'sodium_crypto_aead_chacha20poly1305_ietf_decrypt' => ['string|false', 'ciphertext'=>'string', 'additional_data'=>'string', 'nonce'=>'string', 'key'=>'string'], 'sodium_crypto_aead_chacha20poly1305_ietf_encrypt' => ['string', 'message'=>'string', 'additional_data'=>'string', 'nonce'=>'string', 'key'=>'string'], 'sodium_crypto_aead_chacha20poly1305_ietf_keygen' => ['non-empty-string'], 'sodium_crypto_aead_chacha20poly1305_keygen' => ['non-empty-string'], 'sodium_crypto_aead_xchacha20poly1305_ietf_decrypt' => ['string|false', 'ciphertext'=>'string', 'additional_data'=>'string', 'nonce'=>'string', 'key'=>'string'], 'sodium_crypto_aead_xchacha20poly1305_ietf_encrypt' => ['string', 'message'=>'string', 'additional_data'=>'string', 'nonce'=>'string', 'key'=>'string'], 'sodium_crypto_aead_xchacha20poly1305_ietf_keygen' => ['non-empty-string'], 'sodium_crypto_auth' => ['string', 'message'=>'string', 'key'=>'string'], 'sodium_crypto_auth_keygen' => ['non-empty-string'], 'sodium_crypto_auth_verify' => ['bool', 'mac'=>'string', 'message'=>'string', 'key'=>'string'], 'sodium_crypto_box' => ['string', 'message'=>'string', 'nonce'=>'string', 'key_pair'=>'string'], 'sodium_crypto_box_keypair' => ['string'], 'sodium_crypto_box_keypair_from_secretkey_and_publickey' => ['string', 'secret_key'=>'string', 'public_key'=>'string'], 'sodium_crypto_box_open' => ['string|false', 'ciphertext'=>'string', 'nonce'=>'string', 'key_pair'=>'string'], 'sodium_crypto_box_publickey' => ['string', 'key_pair'=>'string'], 'sodium_crypto_box_publickey_from_secretkey' => ['string', 'secret_key'=>'string'], 'sodium_crypto_box_seal' => ['string', 'message'=>'string', 'public_key'=>'string'], 'sodium_crypto_box_seal_open' => ['string|false', 'ciphertext'=>'string', 'key_pair'=>'string'], 'sodium_crypto_box_secretkey' => ['string', 'key_pair'=>'string'], 'sodium_crypto_box_seed_keypair' => ['string', 'seed'=>'string'], 'sodium_crypto_generichash' => ['string', 'message'=>'string', 'key='=>'string', 'length='=>'int'], 'sodium_crypto_generichash_final' => ['string', '&state'=>'string', 'length='=>'int'], 'sodium_crypto_generichash_init' => ['string', 'key='=>'string', 'length='=>'int'], 'sodium_crypto_generichash_keygen' => ['non-empty-string'], 'sodium_crypto_generichash_update' => ['true', '&rw_state'=>'string', 'message'=>'string'], 'sodium_crypto_kdf_derive_from_key' => ['string', 'subkey_length'=>'int', 'subkey_id'=>'int', 'context'=>'string', 'key'=>'string'], 'sodium_crypto_kdf_keygen' => ['non-empty-string'], 'sodium_crypto_kx_client_session_keys' => ['array', 'client_key_pair'=>'string', 'server_key'=>'string'], 'sodium_crypto_kx_keypair' => ['string'], 'sodium_crypto_kx_publickey' => ['string', 'key_pair'=>'string'], 'sodium_crypto_kx_secretkey' => ['string', 'key_pair'=>'string'], 'sodium_crypto_kx_seed_keypair' => ['string', 'seed'=>'string'], 'sodium_crypto_kx_server_session_keys' => ['array', 'server_key_pair'=>'string', 'client_key'=>'string'], 'sodium_crypto_pwhash' => ['string', 'length'=>'int', 'password'=>'string', 'salt'=>'string', 'opslimit'=>'int', 'memlimit'=>'int', 'algo='=>'int'], 'sodium_crypto_pwhash_scryptsalsa208sha256' => ['string', 'length'=>'int', 'password'=>'string', 'salt'=>'string', 'opslimit'=>'int', 'memlimit'=>'int'], 'sodium_crypto_pwhash_scryptsalsa208sha256_str' => ['string', 'password'=>'string', 'opslimit'=>'int', 'memlimit'=>'int'], 'sodium_crypto_pwhash_scryptsalsa208sha256_str_verify' => ['bool', 'hash'=>'string', 'password'=>'string'], 'sodium_crypto_pwhash_str' => ['string', 'password'=>'string', 'opslimit'=>'int', 'memlimit'=>'int'], 'sodium_crypto_pwhash_str_needs_rehash' => ['bool', 'password'=>'string', 'opslimit'=>'int', 'memlimit'=>'int'], 'sodium_crypto_pwhash_str_verify' => ['bool', 'hash'=>'string', 'password'=>'string'], 'sodium_crypto_scalarmult' => ['string', 'n'=>'string', 'p'=>'string'], 'sodium_crypto_scalarmult_base' => ['string', 'secret_key'=>'string'], 'sodium_crypto_secretbox' => ['string', 'message'=>'string', 'nonce'=>'string', 'key'=>'string'], 'sodium_crypto_secretbox_keygen' => ['non-empty-string'], 'sodium_crypto_secretbox_open' => ['string|false', 'ciphertext'=>'string', 'nonce'=>'string', 'key'=>'string'], 'sodium_crypto_secretstream_xchacha20poly1305_init_pull' => ['string', 'header'=>'string', 'key'=>'string'], 'sodium_crypto_secretstream_xchacha20poly1305_init_push' => ['array', 'key'=>'string'], 'sodium_crypto_secretstream_xchacha20poly1305_keygen' => ['non-empty-string'], 'sodium_crypto_secretstream_xchacha20poly1305_pull' => ['array|false', '&r_state'=>'string', 'ciphertext'=>'string', 'additional_data='=>'string'], 'sodium_crypto_secretstream_xchacha20poly1305_push' => ['string', '&w_state'=>'string', 'message'=>'string', 'additional_data='=>'string', 'tag='=>'int'], 'sodium_crypto_secretstream_xchacha20poly1305_rekey' => ['void', '&w_state'=>'string'], 'sodium_crypto_shorthash' => ['string', 'message'=>'string', 'key'=>'string'], 'sodium_crypto_shorthash_keygen' => ['non-empty-string'], 'sodium_crypto_sign' => ['string', 'message'=>'string', 'secret_key'=>'string'], 'sodium_crypto_sign_detached' => ['string', 'message'=>'string', 'secret_key'=>'string'], 'sodium_crypto_sign_ed25519_pk_to_curve25519' => ['string', 'public_key'=>'string'], 'sodium_crypto_sign_ed25519_sk_to_curve25519' => ['string', 'secret_key'=>'string'], 'sodium_crypto_sign_keypair' => ['string'], 'sodium_crypto_sign_keypair_from_secretkey_and_publickey' => ['string', 'secret_key'=>'string', 'public_key'=>'string'], 'sodium_crypto_sign_open' => ['string|false', 'signed_message'=>'string', 'public_key'=>'string'], 'sodium_crypto_sign_publickey' => ['string', 'key_pair'=>'string'], 'sodium_crypto_sign_publickey_from_secretkey' => ['string', 'secret_key'=>'string'], 'sodium_crypto_sign_secretkey' => ['string', 'key_pair'=>'string'], 'sodium_crypto_sign_seed_keypair' => ['string', 'seed'=>'string'], 'sodium_crypto_sign_verify_detached' => ['bool', 'signature'=>'string', 'message'=>'string', 'public_key'=>'string'], 'sodium_crypto_stream' => ['string', 'length'=>'int', 'nonce'=>'string', 'key'=>'string'], 'sodium_crypto_stream_keygen' => ['non-empty-string'], 'sodium_crypto_stream_xor' => ['string', 'message'=>'string', 'nonce'=>'string', 'key'=>'string'], 'sodium_hex2bin' => ['string', 'string'=>'string', 'ignore='=>'string'], 'sodium_increment' => ['void', '&rw_string'=>'string'], 'sodium_memcmp' => ['int', 'string1'=>'string', 'string2'=>'string'], 'sodium_memzero' => ['void', '&w_string'=>'string'], 'sodium_pad' => ['string', 'string'=>'string', 'block_size'=>'int'], 'sodium_unpad' => ['string', 'string'=>'string', 'block_size'=>'int'], 'stream_isatty' => ['bool', 'stream'=>'resource'], 'xdebug_info' => ['mixed', 'category='=>'string'], ], 'changed' => [ 'ReflectionClass::getMethods' => [ 'old' => ['list', 'filter='=>'int'], 'new' => ['list', 'filter='=>'?int'], ], 'ReflectionClass::getProperties' => [ 'old' => ['list', 'filter='=>'int'], 'new' => ['list', 'filter='=>'?int'], ], 'ReflectionObject::getMethods' => [ 'old' => ['ReflectionMethod[]', 'filter='=>'int'], 'new' => ['ReflectionMethod[]', 'filter='=>'?int'], ], 'ReflectionObject::getProperties' => [ 'old' => ['ReflectionProperty[]', 'filter='=>'int'], 'new' => ['ReflectionProperty[]', 'filter='=>'?int'], ], 'SQLite3::openBlob' => [ 'old' => ['resource|false', 'table'=>'string', 'column'=>'string', 'rowid'=>'int', 'dbname='=>'string'], 'new' => ['resource|false', 'table'=>'string', 'column'=>'string', 'rowid'=>'int', 'database='=>'string', 'flags='=>'int'], ], 'hash_copy' => [ 'old' => ['resource', 'context'=>'resource'], 'new' => ['HashContext', 'context'=>'HashContext'], ], 'hash_final' => [ 'old' => ['non-empty-string', 'context'=>'resource', 'raw_output='=>'bool'], 'new' => ['non-empty-string', 'context'=>'HashContext', 'binary='=>'bool'], ], 'hash_init' => [ 'old' => ['resource', 'algo'=>'string', 'options='=>'int', 'key='=>'string'], 'new' => ['HashContext|false', 'algo'=>'string', 'flags='=>'int', 'key='=>'string'], ], 'hash_update' => [ 'old' => ['bool', 'context'=>'resource', 'data'=>'string'], 'new' => ['bool', 'context'=>'HashContext', 'data'=>'string'], ], 'hash_update_file' => [ 'old' => ['bool', 'hcontext'=>'resource', 'filename'=>'string', 'scontext='=>'resource'], 'new' => ['bool', 'context'=>'HashContext', 'filename'=>'string', 'stream_context='=>'resource'], ], 'hash_update_stream' => [ 'old' => ['int', 'context'=>'resource', 'handle'=>'resource', 'length='=>'int'], 'new' => ['int', 'context'=>'HashContext', 'stream'=>'resource', 'length='=>'int'], ], 'json_decode' => [ 'old' => ['mixed', 'json'=>'string', 'associative='=>'bool', 'depth='=>'int', 'flags='=>'int'], 'new' => ['mixed', 'json'=>'string', 'associative='=>'?bool', 'depth='=>'int', 'flags='=>'int'], ], 'mb_check_encoding' => [ 'old' => ['bool', 'value='=>'string', 'encoding='=>'string'], 'new' => ['bool', 'value='=>'array|string', 'encoding='=>'string'], ], 'preg_quote' => [ 'old' => ['string', 'str'=>'string', 'delimiter='=>'string'], 'new' => ['string', 'str'=>'string', 'delimiter='=>'?string'], ], ], 'removed' => [ 'Sodium\add' => ['void', '&left'=>'string', 'right'=>'string'], 'Sodium\bin2hex' => ['string', 'binary'=>'string'], 'Sodium\compare' => ['int', 'left'=>'string', 'right'=>'string'], 'Sodium\crypto_aead_aes256gcm_decrypt' => ['string|false', 'msg'=>'string', 'nonce'=>'string', 'key'=>'string', 'ad='=>'string'], 'Sodium\crypto_aead_aes256gcm_encrypt' => ['string', 'msg'=>'string', 'nonce'=>'string', 'key'=>'string', 'ad='=>'string'], 'Sodium\crypto_aead_aes256gcm_is_available' => ['bool'], 'Sodium\crypto_aead_chacha20poly1305_decrypt' => ['string', 'msg'=>'string', 'nonce'=>'string', 'key'=>'string', 'ad='=>'string'], 'Sodium\crypto_aead_chacha20poly1305_encrypt' => ['string', 'msg'=>'string', 'nonce'=>'string', 'key'=>'string', 'ad='=>'string'], 'Sodium\crypto_auth' => ['string', 'msg'=>'string', 'key'=>'string'], 'Sodium\crypto_auth_verify' => ['bool', 'mac'=>'string', 'msg'=>'string', 'key'=>'string'], 'Sodium\crypto_box' => ['string', 'msg'=>'string', 'nonce'=>'string', 'keypair'=>'string'], 'Sodium\crypto_box_keypair' => ['string'], 'Sodium\crypto_box_keypair_from_secretkey_and_publickey' => ['string', 'secretkey'=>'string', 'publickey'=>'string'], 'Sodium\crypto_box_open' => ['string', 'msg'=>'string', 'nonce'=>'string', 'keypair'=>'string'], 'Sodium\crypto_box_publickey' => ['string', 'keypair'=>'string'], 'Sodium\crypto_box_publickey_from_secretkey' => ['string', 'secretkey'=>'string'], 'Sodium\crypto_box_seal' => ['string', 'message'=>'string', 'publickey'=>'string'], 'Sodium\crypto_box_seal_open' => ['string', 'encrypted'=>'string', 'keypair'=>'string'], 'Sodium\crypto_box_secretkey' => ['string', 'keypair'=>'string'], 'Sodium\crypto_box_seed_keypair' => ['string', 'seed'=>'string'], 'Sodium\crypto_generichash' => ['string', 'input'=>'string', 'key='=>'string', 'length='=>'int'], 'Sodium\crypto_generichash_final' => ['string', 'state'=>'string', 'length='=>'int'], 'Sodium\crypto_generichash_init' => ['string', 'key='=>'string', 'length='=>'int'], 'Sodium\crypto_generichash_update' => ['bool', '&hashState'=>'string', 'append'=>'string'], 'Sodium\crypto_kx' => ['string', 'secretkey'=>'string', 'publickey'=>'string', 'client_publickey'=>'string', 'server_publickey'=>'string'], 'Sodium\crypto_pwhash' => ['string', 'out_len'=>'int', 'passwd'=>'string', 'salt'=>'string', 'opslimit'=>'int', 'memlimit'=>'int'], 'Sodium\crypto_pwhash_scryptsalsa208sha256' => ['string', 'out_len'=>'int', 'passwd'=>'string', 'salt'=>'string', 'opslimit'=>'int', 'memlimit'=>'int'], 'Sodium\crypto_pwhash_scryptsalsa208sha256_str' => ['string', 'passwd'=>'string', 'opslimit'=>'int', 'memlimit'=>'int'], 'Sodium\crypto_pwhash_scryptsalsa208sha256_str_verify' => ['bool', 'hash'=>'string', 'passwd'=>'string'], 'Sodium\crypto_pwhash_str' => ['string', 'passwd'=>'string', 'opslimit'=>'int', 'memlimit'=>'int'], 'Sodium\crypto_pwhash_str_verify' => ['bool', 'hash'=>'string', 'passwd'=>'string'], 'Sodium\crypto_scalarmult' => ['string', 'ecdhA'=>'string', 'ecdhB'=>'string'], 'Sodium\crypto_scalarmult_base' => ['string', 'sk'=>'string'], 'Sodium\crypto_secretbox' => ['string', 'plaintext'=>'string', 'nonce'=>'string', 'key'=>'string'], 'Sodium\crypto_secretbox_open' => ['string', 'ciphertext'=>'string', 'nonce'=>'string', 'key'=>'string'], 'Sodium\crypto_shorthash' => ['string', 'message'=>'string', 'key'=>'string'], 'Sodium\crypto_sign' => ['string', 'message'=>'string', 'secretkey'=>'string'], 'Sodium\crypto_sign_detached' => ['string', 'message'=>'string', 'secretkey'=>'string'], 'Sodium\crypto_sign_ed25519_pk_to_curve25519' => ['string', 'sign_pk'=>'string'], 'Sodium\crypto_sign_ed25519_sk_to_curve25519' => ['string', 'sign_sk'=>'string'], 'Sodium\crypto_sign_keypair' => ['string'], 'Sodium\crypto_sign_keypair_from_secretkey_and_publickey' => ['string', 'secretkey'=>'string', 'publickey'=>'string'], 'Sodium\crypto_sign_open' => ['string|false', 'signed_message'=>'string', 'publickey'=>'string'], 'Sodium\crypto_sign_publickey' => ['string', 'keypair'=>'string'], 'Sodium\crypto_sign_publickey_from_secretkey' => ['string', 'secretkey'=>'string'], 'Sodium\crypto_sign_secretkey' => ['string', 'keypair'=>'string'], 'Sodium\crypto_sign_seed_keypair' => ['string', 'seed'=>'string'], 'Sodium\crypto_sign_verify_detached' => ['bool', 'signature'=>'string', 'msg'=>'string', 'publickey'=>'string'], 'Sodium\crypto_stream' => ['string', 'length'=>'int', 'nonce'=>'string', 'key'=>'string'], 'Sodium\crypto_stream_xor' => ['string', 'plaintext'=>'string', 'nonce'=>'string', 'key'=>'string'], 'Sodium\hex2bin' => ['string', 'hex'=>'string'], 'Sodium\increment' => ['string', '&nonce'=>'string'], 'Sodium\library_version_major' => ['int'], 'Sodium\library_version_minor' => ['int'], 'Sodium\memcmp' => ['int', 'left'=>'string', 'right'=>'string'], 'Sodium\memzero' => ['void', '&target'=>'string'], 'Sodium\randombytes_buf' => ['string', 'length'=>'int'], 'Sodium\randombytes_random16' => ['int|string'], 'Sodium\randombytes_uniform' => ['int', 'upperBoundNonInclusive'=>'int'], 'Sodium\version_string' => ['string'], ], ]; [ // documented as 'mixed' in doc-en/reference/datetime/dateinterval.xml:90. 'days' => 'false|int', ], 'domnode' => [ // documented as 'DomNodeList' in doc-en/reference/dom/domnode.xml:57. 'childnodes' => 'DomNodeList' ], 'tidy' => [ // documented via in doc-en/reference/tidy/tidy.xml:33 'errorbuffer' => 'string', ], // // Undocumented classes from here on. // 'phpparser\\node\\expr\\array_' => [ 'items' => 'array', ], 'phpparser\\node\\expr\\arrowfunction' => [ 'params' => 'list', ], 'phpparser\\node\\expr\\closure' => [ 'params' => 'list', ], 'phpparser\\node\\expr\\list_' => [ 'items' => 'array', ], 'phpparser\\node\\expr\\shellexec' => [ 'parts' => 'list', ], 'phpparser\\node\\matcharm' => [ 'conds' => 'null|non-empty-list', ], 'phpparser\\node\\name' => [ 'parts' => 'non-empty-list', ], 'phpparser\\node\\stmt\\case_' => [ 'stmts' => 'list', ], 'phpparser\\node\\stmt\\catch_' => [ 'stmts' => 'list', ], 'phpparser\\node\\stmt\\class_' => [ 'stmts' => 'list', ], 'phpparser\\node\\stmt\\do_' => [ 'stmts' => 'list', ], 'phpparser\\node\\stmt\\else_' => [ 'stmts' => 'list', ], 'phpparser\\node\\stmt\\elseif_' => [ 'stmts' => 'list', ], 'phpparser\\node\\stmt\\finally_' => [ 'stmts' => 'list', ], 'phpparser\\node\\stmt\\for_' => [ 'stmts' => 'list', ], 'phpparser\\node\\stmt\\foreach_' => [ 'stmts' => 'list', ], 'phpparser\\node\\stmt\\if_' => [ 'stmts' => 'list', ], 'phpparser\\node\\stmt\\interface_' => [ 'stmts' => 'list', ], 'phpparser\\node\\stmt\\namespace_' => [ 'stmts' => 'list', ], 'phpparser\\node\\stmt\\trait_' => [ 'stmts' => 'list', ], 'phpparser\\node\\stmt\\trycatch' => [ 'stmts' => 'list', ], 'phpparser\\node\\stmt\\while_' => [ 'stmts' => 'list', ], 'rdkafka\\message' => [ 'err' => 'int', 'headers' => 'array|null', 'key' => 'string|null', 'offset' => 'int', 'partition' => 'int', 'payload' => 'string', 'timestamp' => 'int', 'topic_name' => 'string', ], // // Legacy extensions that got removed. // 'mongoclient' => [ 'connected' => 'boolean', 'status' => 'string', ], 'mongocollection' => [ 'db' => 'MongoDB', 'w' => 'integer', 'wtimeout' => 'integer', ], 'mongocursor' => [ 'slaveokay' => 'boolean', 'timeout' => 'integer', ], 'mongodb' => [ 'w' => 'integer', 'wtimeout' => 'integer', ], 'mongodb-driver-exception-writeexception' => [ 'writeresult' => 'MongoDBDriverWriteResult', ], 'mongoid' => [ 'id' => 'string', ], 'mongoint32' => [ 'value' => 'string', ], 'mongoint64' => [ 'value' => 'string', ], 'tokyotyrantexception' => [ 'code' => 'int', ], ]; [ 'DateTime::createFromInterface' => ['static', 'object'=>'DateTimeInterface'], 'DateTimeImmutable::createFromInterface' => ['static', 'object'=>'DateTimeInterface'], 'PhpToken::getTokenName' => ['?string'], 'PhpToken::is' => ['bool', 'kind'=>'string|int|string[]|int[]'], 'PhpToken::isIgnorable' => ['bool'], 'PhpToken::tokenize' => ['list', 'code'=>'string', 'flags='=>'int'], 'ReflectionClass::getAttributes' => ['list', 'name='=>'?string', 'flags='=>'int'], 'ReflectionClassConstant::getAttributes' => ['list', 'name='=>'?string', 'flags='=>'int'], 'ReflectionFunctionAbstract::getAttributes' => ['list', 'name='=>'?string', 'flags='=>'int'], 'ReflectionParameter::getAttributes' => ['list', 'name='=>'?string', 'flags='=>'int'], 'ReflectionProperty::getAttributes' => ['list', 'name='=>'?string', 'flags='=>'int'], 'ReflectionProperty::getDefaultValue' => ['mixed'], 'ReflectionProperty::hasDefaultValue' => ['bool'], 'ReflectionProperty::isPromoted' => ['bool'], 'ReflectionUnionType::getTypes' => ['list'], 'SplFixedArray::getIterator' => ['Iterator'], 'WeakMap::count' => ['int'], 'WeakMap::getIterator' => ['Iterator'], 'WeakMap::offsetExists' => ['bool', 'object'=>'object'], 'WeakMap::offsetGet' => ['mixed', 'object'=>'object'], 'WeakMap::offsetSet' => ['void', 'object'=>'object', 'value'=>'mixed'], 'WeakMap::offsetUnset' => ['void', 'object'=>'object'], 'fdiv' => ['float', 'num1'=>'float', 'num2'=>'float'], 'get_debug_type' => ['string', 'value'=>'mixed'], 'get_resource_id' => ['int', 'resource'=>'resource'], 'imagegetinterpolation' => ['int', 'image'=>'GdImage'], 'str_contains' => ['bool', 'haystack'=>'string', 'needle'=>'string'], 'str_ends_with' => ['bool', 'haystack'=>'string', 'needle'=>'string'], 'str_starts_with' => ['bool', 'haystack'=>'string', 'needle'=>'string'], ], 'changed' => [ 'Collator::getStrength' => [ 'old' => ['int|false'], 'new' => ['int'], ], 'CURLFile::__construct' => [ 'old' => ['void', 'filename'=>'string', 'mime_type='=>'string', 'posted_filename='=>'string'], 'new' => ['void', 'filename'=>'string', 'mime_type='=>'?string', 'posted_filename='=>'?string'], ], 'DateTime::format' => [ 'old' => ['string|false', 'format'=>'string'], 'new' => ['string', 'format'=>'string'], ], 'DateTime::getTimestamp' => [ 'old' => ['int|false'], 'new' => ['int'], ], 'DateTimeInterface::getTimestamp' => [ 'old' => ['int|false'], 'new' => ['int'], ], 'DateTimeZone::getOffset' => [ 'old' => ['int|false', 'datetime'=>'DateTimeInterface'], 'new' => ['int', 'datetime'=>'DateTimeInterface'], ], 'DateTimeZone::listIdentifiers' => [ 'old' => ['list|false', 'timezoneGroup='=>'int', 'countryCode='=>'string|null'], 'new' => ['list', 'timezoneGroup='=>'int', 'countryCode='=>'string|null'], ], 'Directory::close' => [ 'old' => ['void', 'dir_handle='=>'resource'], 'new' => ['void'], ], 'Directory::read' => [ 'old' => ['string|false', 'dir_handle='=>'resource'], 'new' => ['string|false'], ], 'Directory::rewind' => [ 'old' => ['void', 'dir_handle='=>'resource'], 'new' => ['void'], ], 'DirectoryIterator::getFileInfo' => [ 'old' => ['SplFileInfo', 'class='=>'class-string'], 'new' => ['SplFileInfo', 'class='=>'?class-string'], ], 'DirectoryIterator::getPathInfo' => [ 'old' => ['?SplFileInfo', 'class='=>'class-string'], 'new' => ['?SplFileInfo', 'class='=>'?class-string'], ], 'DirectoryIterator::openFile' => [ 'old' => ['SplFileObject', 'mode='=>'string', 'useIncludePath='=>'bool', 'context='=>'resource'], 'new' => ['SplFileObject', 'mode='=>'string', 'useIncludePath='=>'bool', 'context='=>'?resource'], ], 'DOMDocument::getElementsByTagNameNS' => [ 'old' => ['DOMNodeList', 'namespace'=>'string', 'localName'=>'string'], 'new' => ['DOMNodeList', 'namespace'=>'?string', 'localName'=>'string'], ], 'DOMDocument::load' => [ 'old' => ['DOMDocument|bool', 'filename'=>'string', 'options='=>'int'], 'new' => ['bool', 'filename'=>'string', 'options='=>'int'], ], 'DOMDocument::loadXML' => [ 'old' => ['DOMDocument|bool', 'source'=>'non-empty-string', 'options='=>'int'], 'new' => ['bool', 'source'=>'non-empty-string', 'options='=>'int'], ], 'DOMDocument::loadHTML' => [ 'old' => ['DOMDocument|bool', 'source'=>'non-empty-string', 'options='=>'int'], 'new' => ['bool', 'source'=>'non-empty-string', 'options='=>'int'], ], 'DOMDocument::loadHTMLFile' => [ 'old' => ['DOMDocument|bool', 'filename'=>'string', 'options='=>'int'], 'new' => ['bool', 'filename'=>'string', 'options='=>'int'], ], 'DOMImplementation::createDocument' => [ 'old' => ['DOMDocument|false', 'namespace='=>'string', 'qualifiedName='=>'string', 'doctype='=>'DOMDocumentType'], 'new' => ['DOMDocument|false', 'namespace='=>'?string', 'qualifiedName='=>'string', 'doctype='=>'?DOMDocumentType'], ], 'ErrorException::__construct' => [ 'old' => ['void', 'message='=>'string', 'code='=>'int', 'severity='=>'int', 'filename='=>'string', 'line='=>'int', 'previous='=>'?Throwable'], 'new' => ['void', 'message='=>'string', 'code='=>'int', 'severity='=>'int', 'filename='=>'?string', 'line='=>'?int', 'previous='=>'?Throwable'], ], 'FilesystemIterator::getFileInfo' => [ 'old' => ['SplFileInfo', 'class='=>'class-string'], 'new' => ['SplFileInfo', 'class='=>'?class-string'], ], 'FilesystemIterator::getPathInfo' => [ 'old' => ['?SplFileInfo', 'class='=>'class-string'], 'new' => ['?SplFileInfo', 'class='=>'?class-string'], ], 'FilesystemIterator::openFile' => [ 'old' => ['SplFileObject', 'mode='=>'string', 'useIncludePath='=>'bool', 'context='=>'resource'], 'new' => ['SplFileObject', 'mode='=>'string', 'useIncludePath='=>'bool', 'context='=>'?resource'], ], 'finfo::__construct' => [ 'old' => ['void', 'flags='=>'int', 'magic_database='=>'string'], 'new' => ['void', 'flags='=>'int', 'magic_database='=>'?string'], ], 'GlobIterator::getFileInfo' => [ 'old' => ['SplFileInfo', 'class='=>'class-string'], 'new' => ['SplFileInfo', 'class='=>'?class-string'], ], 'GlobIterator::getPathInfo' => [ 'old' => ['?SplFileInfo', 'class='=>'class-string'], 'new' => ['?SplFileInfo', 'class='=>'?class-string'], ], 'GlobIterator::openFile' => [ 'old' => ['SplFileObject', 'mode='=>'string', 'useIncludePath='=>'bool', 'context='=>'resource'], 'new' => ['SplFileObject', 'mode='=>'string', 'useIncludePath='=>'bool', 'context='=>'?resource'], ], 'IntlDateFormatter::__construct' => [ 'old' => ['void', 'locale'=>'?string', 'datetype'=>'null|int', 'timetype'=>'null|int', 'timezone='=>'IntlTimeZone|DateTimeZone|string|null', 'calendar='=>'IntlCalendar|int|null', 'pattern='=>'?string'], 'new' => ['void', 'locale'=>'?string', 'dateType'=>'int', 'timeType'=>'int', 'timezone='=>'IntlTimeZone|DateTimeZone|string|null', 'calendar='=>'IntlCalendar|int|null', 'pattern='=>'?string'], ], 'IntlDateFormatter::create' => [ 'old' => ['?IntlDateFormatter', 'locale'=>'?string', 'datetype'=>'null|int', 'timetype'=>'null|int', 'timezone='=>'IntlTimeZone|DateTimeZone|string|null', 'calendar='=>'IntlCalendar|int|null', 'pattern='=>'?string'], 'new' => ['?IntlDateFormatter', 'locale'=>'?string', 'dateType'=>'int', 'timeType'=>'int', 'timezone='=>'IntlTimeZone|DateTimeZone|string|null', 'calendar='=>'IntlCalendar|int|null', 'pattern='=>'?string'], ], 'IntlDateFormatter::format' => [ 'old' => ['string|false', 'value'=>'IntlCalendar|DateTimeInterface|array{0: int, 1: int, 2: int, 3: int, 4: int, 5: int, 6: int, 7: int, 8: int}|array{tm_sec: int, tm_min: int, tm_hour: int, tm_mday: int, tm_mon: int, tm_year: int, tm_wday: int, tm_yday: int, tm_isdst: int}|string|int|float'], 'new' => ['string|false', 'datetime'=>'IntlCalendar|DateTimeInterface|array{0: int, 1: int, 2: int, 3: int, 4: int, 5: int, 6: int, 7: int, 8: int}|array{tm_sec: int, tm_min: int, tm_hour: int, tm_mday: int, tm_mon: int, tm_year: int, tm_wday: int, tm_yday: int, tm_isdst: int}|string|int|float'], ], 'IntlDateFormatter::formatObject' => [ 'old' => ['string|false', 'object'=>'IntlCalendar|DateTime', 'format='=>'array{0: int, 1: int}|int|string|null', 'locale='=>'?string'], 'new' => ['string|false', 'datetime'=>'IntlCalendar|DateTimeInterface', 'format='=>'array{0: int, 1: int}|int|string|null', 'locale='=>'?string'], ], 'IntlDateFormatter::getCalendar' => [ 'old' => ['int'], 'new' => ['int|false'], ], 'IntlDateFormatter::getCalendarObject' => [ 'old' => ['IntlCalendar'], 'new' => ['IntlCalendar|false|null'], ], 'IntlDateFormatter::getDateType' => [ 'old' => ['int'], 'new' => ['int|false'], ], 'IntlDateFormatter::getLocale' => [ 'old' => ['string', 'which='=>'int'], 'new' => ['string|false', 'type='=>'int'], ], 'IntlDateFormatter::getPattern' => [ 'old' => ['string'], 'new' => ['string|false'], ], 'IntlDateFormatter::getTimeType' => [ 'old' => ['int'], 'new' => ['int|false'], ], 'IntlDateFormatter::getTimeZoneId' => [ 'old' => ['string'], 'new' => ['string|false'], ], 'IntlDateFormatter::localtime' => [ 'old' => ['array', 'value'=>'string', '&rw_position='=>'int'], 'new' => ['array|false', 'string'=>'string', '&rw_offset='=>'int'], ], 'IntlDateFormatter::parse' => [ 'old' => ['int|float', 'value'=>'string', '&rw_position='=>'int'], 'new' => ['int|float|false', 'string'=>'string', '&rw_offset='=>'int'], ], 'IntlDateFormatter::setCalendar' => [ 'old' => ['bool', 'which'=>'IntlCalendar|int|null'], 'new' => ['bool', 'calendar'=>'IntlCalendar|int|null'], ], 'IntlDateFormatter::setLenient' => [ 'old' => ['bool', 'lenient'=>'bool'], 'new' => ['void', 'lenient'=>'bool'], ], 'IntlDateFormatter::setTimeZone' => [ 'old' => ['null|false', 'zone'=>'IntlTimeZone|DateTimeZone|string|null'], 'new' => ['null|false', 'timezone'=>'IntlTimeZone|DateTimeZone|string|null'], ], 'IntlTimeZone::getIDForWindowsID' => [ 'old' => ['string|false', 'timezoneId'=>'string', 'region='=>'string'], 'new' => ['string|false', 'timezoneId'=>'string', 'region='=>'?string'], ], 'Locale::getDisplayLanguage' => [ 'old' => ['string', 'locale'=>'string', 'displayLocale='=>'string'], 'new' => ['string', 'locale'=>'string', 'displayLocale='=>'?string'], ], 'Locale::getDisplayName' => [ 'old' => ['string', 'locale'=>'string', 'displayLocale='=>'string'], 'new' => ['string', 'locale'=>'string', 'displayLocale='=>'?string'], ], 'Locale::getDisplayRegion' => [ 'old' => ['string', 'locale'=>'string', 'displayLocale='=>'string'], 'new' => ['string', 'locale'=>'string', 'displayLocale='=>'?string'], ], 'Locale::getDisplayScript' => [ 'old' => ['string', 'locale'=>'string', 'displayLocale='=>'string'], 'new' => ['string', 'locale'=>'string', 'displayLocale='=>'?string'], ], 'Locale::getDisplayVariant' => [ 'old' => ['string', 'locale'=>'string', 'displayLocale='=>'string'], 'new' => ['string', 'locale'=>'string', 'displayLocale='=>'?string'], ], 'mysqli_field_seek' => [ 'old' => ['bool', 'result'=>'mysqli_result', 'index'=>'int'], 'new' => ['true', 'result'=>'mysqli_result', 'index'=>'int'], ], 'mysqli_result::field_seek' => [ 'old' => ['bool', 'index'=>'int'], 'new' => ['true', 'index'=>'int'], ], 'mysqli_stmt::__construct' => [ 'old' => ['void', 'mysql'=>'mysqli', 'query='=>'string'], 'new' => ['void', 'mysql'=>'mysqli', 'query='=>'?string'], ], 'NumberFormatter::__construct' => [ 'old' => ['void', 'locale'=>'string', 'style'=>'int', 'pattern='=>'string'], 'new' => ['void', 'locale'=>'string', 'style'=>'int', 'pattern='=>'?string'], ], 'NumberFormatter::create' => [ 'old' => ['NumberFormatter|null', 'locale'=>'string', 'style'=>'int', 'pattern='=>'string'], 'new' => ['NumberFormatter|null', 'locale'=>'string', 'style'=>'int', 'pattern='=>'?string'], ], 'PDOStatement::debugDumpParams' => [ 'old' => ['void'], 'new' => ['bool|null'], ], 'PDOStatement::errorCode' => [ 'old' => ['string'], 'new' => ['string|null'], ], 'PDOStatement::execute' => [ 'old' => ['bool', 'bound_input_params='=>'?array'], 'new' => ['bool', 'params='=>'?array'], ], 'PDOStatement::fetch' => [ 'old' => ['mixed', 'how='=>'int', 'orientation='=>'int', 'offset='=>'int'], 'new' => ['mixed', 'mode='=>'int', 'cursorOrientation='=>'int', 'cursorOffset='=>'int'], ], 'PDOStatement::fetchAll' => [ 'old' => ['array|false', 'how='=>'int', 'fetch_argument='=>'int|string|callable', 'ctor_args='=>'?array'], 'new' => ['array', 'mode='=>'int', '...args='=>'mixed'], ], 'PDOStatement::fetchColumn' => [ 'old' => ['string|int|float|bool|null', 'column_number='=>'int'], 'new' => ['mixed', 'column='=>'int'], ], 'PDOStatement::setFetchMode' => [ 'old' => ['bool', 'mode'=>'int'], 'new' => ['bool', 'mode'=>'int', '...args='=>'mixed'], ], 'Phar::addFile' => [ 'old' => ['void', 'filename'=>'string', 'localName='=>'string'], 'new' => ['void', 'filename'=>'string', 'localName='=>'?string'], ], 'Phar::buildFromIterator' => [ 'old' => ['array|false', 'iterator'=>'Traversable', 'baseDirectory='=>'string'], 'new' => ['array|false', 'iterator'=>'Traversable', 'baseDirectory='=>'?string'], ], 'Phar::createDefaultStub' => [ 'old' => ['string', 'index='=>'string', 'webIndex='=>'string'], 'new' => ['string', 'index='=>'?string', 'webIndex='=>'?string'], ], 'Phar::compress' => [ 'old' => ['?Phar', 'compression'=>'int', 'extension='=>'string'], 'new' => ['?Phar', 'compression'=>'int', 'extension='=>'?string'], ], 'Phar::convertToData' => [ 'old' => ['?PharData', 'format='=>'int', 'compression='=>'int', 'extension='=>'string'], 'new' => ['?PharData', 'format='=>'?int', 'compression='=>'?int', 'extension='=>'?string'], ], 'Phar::convertToExecutable' => [ 'old' => ['?Phar', 'format='=>'int', 'compression='=>'int', 'extension='=>'string'], 'new' => ['?Phar', 'format='=>'?int', 'compression='=>'?int', 'extension='=>'?string'], ], 'Phar::decompress' => [ 'old' => ['?Phar', 'extension='=>'string'], 'new' => ['?Phar', 'extension='=>'?string'], ], 'Phar::getMetadata' => [ 'old' => ['mixed'], 'new' => ['mixed', 'unserializeOptions='=>'array'], ], 'Phar::setDefaultStub' => [ 'old' => ['bool', 'index='=>'?string', 'webIndex='=>'string'], 'new' => ['bool', 'index='=>'?string', 'webIndex='=>'?string'], ], 'Phar::setSignatureAlgorithm' => [ 'old' => ['void', 'algo'=>'int', 'privateKey='=>'string'], 'new' => ['void', 'algo'=>'int', 'privateKey='=>'?string'], ], 'Phar::webPhar' => [ 'old' => ['void', 'alias='=>'?string', 'index='=>'?string', 'fileNotFoundScript='=>'string', 'mimeTypes='=>'array', 'rewrite='=>'callable'], 'new' => ['void', 'alias='=>'?string', 'index='=>'?string', 'fileNotFoundScript='=>'?string', 'mimeTypes='=>'array', 'rewrite='=>'?callable'], ], 'PharData::addFile' => [ 'old' => ['void', 'filename'=>'string', 'localName='=>'string'], 'new' => ['void', 'filename'=>'string', 'localName='=>'?string'], ], 'PharData::buildFromIterator' => [ 'old' => ['array|false', 'iterator'=>'Traversable', 'baseDirectory='=>'string'], 'new' => ['array|false', 'iterator'=>'Traversable', 'baseDirectory='=>'?string'], ], 'PharData::compress' => [ 'old' => ['?PharData', 'compression'=>'int', 'extension='=>'string'], 'new' => ['?PharData', 'compression'=>'int', 'extension='=>'?string'], ], 'PharData::convertToData' => [ 'old' => ['?PharData', 'format='=>'int', 'compression='=>'int', 'extension='=>'string'], 'new' => ['?PharData', 'format='=>'?int', 'compression='=>'?int', 'extension='=>'?string'], ], 'PharData::convertToExecutable' => [ 'old' => ['?Phar', 'format='=>'int', 'compression='=>'int', 'extension='=>'string'], 'new' => ['?Phar', 'format='=>'?int', 'compression='=>'?int', 'extension='=>'?string'], ], 'PharData::decompress' => [ 'old' => ['?PharData', 'extension='=>'string'], 'new' => ['?PharData', 'extension='=>'?string'], ], 'PharData::setDefaultStub' => [ 'old' => ['bool', 'index='=>'?string', 'webIndex='=>'string'], 'new' => ['bool', 'index='=>'?string', 'webIndex='=>'?string'], ], 'PharData::setSignatureAlgorithm' => [ 'old' => ['void', 'algo'=>'int', 'privateKey='=>'string'], 'new' => ['void', 'algo'=>'int', 'privateKey='=>'?string'], ], 'PharFileInfo::getMetadata' => [ 'old' => ['mixed'], 'new' => ['mixed', 'unserializeOptions='=>'array'], ], 'PharFileInfo::isCompressed' => [ 'old' => ['bool', 'compression='=>'int'], 'new' => ['bool', 'compression='=>'?int'], ], 'RecursiveDirectoryIterator::getFileInfo' => [ 'old' => ['SplFileInfo', 'class='=>'class-string'], 'new' => ['SplFileInfo', 'class='=>'?class-string'], ], 'RecursiveDirectoryIterator::getPathInfo' => [ 'old' => ['?SplFileInfo', 'class='=>'class-string'], 'new' => ['?SplFileInfo', 'class='=>'?class-string'], ], 'RecursiveDirectoryIterator::openFile' => [ 'old' => ['SplFileObject', 'mode='=>'string', 'useIncludePath='=>'bool', 'context='=>'resource'], 'new' => ['SplFileObject', 'mode='=>'string', 'useIncludePath='=>'bool', 'context='=>'?resource'], ], 'RecursiveIteratorIterator::getSubIterator' => [ 'old' => ['?RecursiveIterator', 'level='=>'int'], 'new' => ['?RecursiveIterator', 'level='=>'?int'], ], 'RecursiveTreeIterator::getSubIterator' => [ 'old' => ['?RecursiveIterator', 'level='=>'int'], 'new' => ['?RecursiveIterator', 'level='=>'?int'], ], 'ReflectionClass::getConstants' => [ 'old' => ['array'], 'new' => ['array', 'filter='=>'?int'], ], 'ReflectionClass::getReflectionConstants' => [ 'old' => ['list'], 'new' => ['list', 'filter='=>'?int'], ], 'ReflectionClass::newInstanceArgs' => [ 'old' => ['object', 'args='=>'list'], 'new' => ['object', 'args='=>'list|array'], ], 'ReflectionMethod::getClosure' => [ 'old' => ['?Closure', 'object='=>'object'], 'new' => ['Closure', 'object='=>'?object'], ], 'ReflectionObject::getConstants' => [ 'old' => ['array'], 'new' => ['array', 'filter='=>'?int'], ], 'ReflectionObject::getReflectionConstants' => [ 'old' => ['list<\ReflectionClassConstant>'], 'new' => ['list<\ReflectionClassConstant>', 'filter='=>'?int'], ], 'ReflectionObject::newInstanceArgs' => [ 'old' => ['object', 'args='=>'list'], 'new' => ['object', 'args='=>'list|array'], ], 'ReflectionProperty::getValue' => [ 'old' => ['mixed', 'object='=>'object'], 'new' => ['mixed', 'object='=>'null|object'], ], 'ReflectionProperty::isInitialized' => [ 'old' => ['bool', 'object'=>'object'], 'new' => ['bool', 'object='=>'null|object'], ], 'SplFileInfo::getFileInfo' => [ 'old' => ['SplFileInfo', 'class='=>'class-string'], 'new' => ['SplFileInfo', 'class='=>'?class-string'], ], 'SplFileInfo::getPathInfo' => [ 'old' => ['SplFileInfo|null', 'class='=>'class-string'], 'new' => ['SplFileInfo|null', 'class='=>'?class-string'], ], 'SplFileInfo::openFile' => [ 'old' => ['SplFileObject', 'mode='=>'string', 'useIncludePath='=>'bool', 'context='=>'resource'], 'new' => ['SplFileObject', 'mode='=>'string', 'useIncludePath='=>'bool', 'context='=>'?resource'], ], 'SplFileObject::getFileInfo' => [ 'old' => ['SplFileInfo', 'class='=>'class-string'], 'new' => ['SplFileInfo', 'class='=>'?class-string'], ], 'SplFileObject::getPathInfo' => [ 'old' => ['SplFileInfo|null', 'class='=>'class-string'], 'new' => ['SplFileInfo|null', 'class='=>'?class-string'], ], 'SplFileObject::openFile' => [ 'old' => ['SplFileObject', 'mode='=>'string', 'useIncludePath='=>'bool', 'context='=>'resource'], 'new' => ['SplFileObject', 'mode='=>'string', 'useIncludePath='=>'bool', 'context='=>'?resource'], ], 'SplTempFileObject::getFileInfo' => [ 'old' => ['SplFileInfo', 'class='=>'class-string'], 'new' => ['SplFileInfo', 'class='=>'?class-string'], ], 'SplTempFileObject::getPathInfo' => [ 'old' => ['SplFileInfo|null', 'class='=>'class-string'], 'new' => ['SplFileInfo|null', 'class='=>'?class-string'], ], 'SplTempFileObject::openFile' => [ 'old' => ['SplTempFileObject', 'mode='=>'string', 'useIncludePath='=>'bool', 'context='=>'resource'], 'new' => ['SplTempFileObject', 'mode='=>'string', 'useIncludePath='=>'bool', 'context='=>'?resource'], ], 'tidy::__construct' => [ 'old' => ['void', 'filename='=>'string', 'config='=>'array|string', 'encoding='=>'string', 'useIncludePath='=>'bool'], 'new' => ['void', 'filename='=>'?string', 'config='=>'array|string|null', 'encoding='=>'?string', 'useIncludePath='=>'bool'], ], 'tidy::parseFile' => [ 'old' => ['bool', 'filename'=>'string', 'config='=>'array|string', 'encoding='=>'string', 'useIncludePath='=>'bool'], 'new' => ['bool', 'filename'=>'string', 'config='=>'array|string|null', 'encoding='=>'?string', 'useIncludePath='=>'bool'], ], 'tidy::parseString' => [ 'old' => ['bool', 'string'=>'string', 'config='=>'array|string', 'encoding='=>'string'], 'new' => ['bool', 'string'=>'string', 'config='=>'array|string|null', 'encoding='=>'?string'], ], 'tidy::repairFile' => [ 'old' => ['string', 'filename'=>'string', 'config='=>'array|string', 'encoding='=>'string', 'useIncludePath='=>'bool'], 'new' => ['string', 'filename'=>'string', 'config='=>'array|string|null', 'encoding='=>'?string', 'useIncludePath='=>'bool'], ], 'tidy::repairString' => [ 'old' => ['string', 'string'=>'string', 'config='=>'array|string', 'encoding='=>'string'], 'new' => ['string', 'string'=>'string', 'config='=>'array|string|null', 'encoding='=>'?string'], ], 'XMLWriter::flush' => [ 'old' => ['string|int|false', 'empty='=>'bool'], 'new' => ['string|int', 'empty='=>'bool'], ], 'SimpleXMLElement::asXML' => [ 'old' => ['string|bool', 'filename'=>'string'], 'new' => ['string|bool', 'filename='=>'?string'], ], 'SimpleXMLElement::saveXML' => [ 'old' => ['string|bool', 'filename='=>'string'], 'new' => ['string|bool', 'filename='=>'?string'], ], 'SoapClient::__doRequest' => [ 'old' => ['?string', 'request'=>'string', 'location'=>'string', 'action'=>'string', 'version'=>'int', 'one_way='=>'int'], 'new' => ['?string', 'request'=>'string', 'location'=>'string', 'action'=>'string', 'version'=>'int', 'one_way='=>'bool'], ], 'SplFileObject::fgets' => [ 'old' => ['string|false'], 'new' => ['string'], ], 'SplFileObject::getCurrentLine' => [ 'old' => ['string|false'], 'new' => ['string'], ], 'XMLReader::next' => [ 'old' => ['bool', 'name='=>'string'], 'new' => ['bool', 'name='=>'?string'], ], 'XMLWriter::startAttributeNs' => [ 'old' => ['bool', 'prefix'=>'string', 'name'=>'string', 'namespace'=>'?string'], 'new' => ['bool', 'prefix'=>'?string', 'name'=>'string', 'namespace'=>'?string'], ], 'XMLWriter::writeAttributeNs' => [ 'old' => ['bool', 'prefix'=>'string', 'name'=>'string', 'namespace'=>'?string', 'value'=>'string'], 'new' => ['bool', 'prefix'=>'?string', 'name'=>'string', 'namespace'=>'?string', 'value'=>'string'], ], 'XMLWriter::writeDtdEntity' => [ 'old' => ['bool', 'name'=>'string', 'content'=>'string', 'isParam'=>'bool', 'publicId'=>'string', 'systemId'=>'string', 'notationData'=>'string'], 'new' => ['bool', 'name'=>'string', 'content'=>'string', 'isParam='=>'bool', 'publicId='=>'?string', 'systemId='=>'?string', 'notationData='=>'?string'], ], 'ZipArchive::getStatusString' => [ 'old' => ['string|false'], 'new' => ['string'], ], 'ZipArchive::setEncryptionIndex' => [ 'old' => ['bool', 'index'=>'int', 'method'=>'int', 'password='=>'string'], 'new' => ['bool', 'index'=>'int', 'method'=>'int', 'password='=>'?string'], ], 'ZipArchive::setEncryptionName' => [ 'old' => ['bool', 'name'=>'string', 'method'=>'int', 'password='=>'string'], 'new' => ['bool', 'name'=>'string', 'method'=>'int', 'password='=>'?string'], ], 'array_column' => [ 'old' => ['array', 'array'=>'array', 'column_key'=>'mixed', 'index_key='=>'mixed'], 'new' => ['array', 'array'=>'array', 'column_key'=>'int|string|null', 'index_key='=>'int|string|null'], ], 'array_combine' => [ 'old' => ['array|false', 'keys'=>'string[]|int[]', 'values'=>'array'], 'new' => ['array', 'keys'=>'string[]|int[]', 'values'=>'array'], ], 'array_diff' => [ 'old' => ['array', 'array'=>'array', '...arrays'=>'array'], 'new' => ['array', 'array'=>'array', '...arrays='=>'array'], ], 'array_diff_assoc' => [ 'old' => ['array', 'array'=>'array', '...arrays'=>'array'], 'new' => ['array', 'array'=>'array', '...arrays='=>'array'], ], 'array_diff_key' => [ 'old' => ['array', 'array'=>'array', '...arrays'=>'array'], 'new' => ['array', 'array'=>'array', '...arrays='=>'array'], ], 'array_filter' => [ 'old' => ['array', 'array'=>'array', 'callback='=>'callable(mixed,array-key=):mixed', 'mode='=>'int'], 'new' => ['array', 'array'=>'array', 'callback='=>'callable(mixed,array-key=):mixed|null', 'mode='=>'int'], ], 'array_key_exists' => [ 'old' => ['bool', 'key'=>'string|int', 'array'=>'array|object'], 'new' => ['bool', 'key'=>'string|int', 'array'=>'array'], ], 'array_intersect' => [ 'old' => ['array', 'array'=>'array', '...arrays'=>'array'], 'new' => ['array', 'array'=>'array', '...arrays='=>'array'], ], 'array_intersect_assoc' => [ 'old' => ['array', 'array'=>'array', '...arrays'=>'array'], 'new' => ['array', 'array'=>'array', '...arrays='=>'array'], ], 'array_intersect_key' => [ 'old' => ['array', 'array'=>'array', '...arrays'=>'array'], 'new' => ['array', 'array'=>'array', '...arrays='=>'array'], ], 'array_splice' => [ 'old' => ['array', '&rw_array'=>'array', 'offset'=>'int', 'length='=>'int', 'replacement='=>'array|string'], 'new' => ['array', '&rw_array'=>'array', 'offset'=>'int', 'length='=>'?int', 'replacement='=>'array|string'], ], 'bcadd' => [ 'old' => ['numeric-string', 'num1'=>'numeric-string', 'num2'=>'numeric-string', 'scale='=>'int'], 'new' => ['numeric-string', 'num1'=>'numeric-string', 'num2'=>'numeric-string', 'scale='=>'int|null'], ], 'bccomp' => [ 'old' => ['int', 'num1'=>'numeric-string', 'num2'=>'numeric-string', 'scale='=>'int'], 'new' => ['int', 'num1'=>'numeric-string', 'num2'=>'numeric-string', 'scale='=>'int|null'], ], 'bcdiv' => [ 'old' => ['numeric-string', 'num1'=>'numeric-string', 'num2'=>'numeric-string', 'scale='=>'int'], 'new' => ['numeric-string', 'num1'=>'numeric-string', 'num2'=>'numeric-string', 'scale='=>'int|null'], ], 'bcmod' => [ 'old' => ['numeric-string', 'num1'=>'numeric-string', 'num2'=>'numeric-string', 'scale='=>'int'], 'new' => ['numeric-string', 'num1'=>'numeric-string', 'num2'=>'numeric-string', 'scale='=>'int|null'], ], 'bcmul' => [ 'old' => ['numeric-string', 'num1'=>'numeric-string', 'num2'=>'numeric-string', 'scale='=>'int'], 'new' => ['numeric-string', 'num1'=>'numeric-string', 'num2'=>'numeric-string', 'scale='=>'int|null'], ], 'bcpow' => [ 'old' => ['numeric-string', 'num'=>'numeric-string', 'exponent'=>'numeric-string', 'scale='=>'int'], 'new' => ['numeric-string', 'num'=>'numeric-string', 'exponent'=>'numeric-string', 'scale='=>'int|null'], ], 'bcpowmod' => [ 'old' => ['numeric-string|false', 'num'=>'numeric-string', 'exponent'=>'numeric-string', 'modulus'=>'numeric-string', 'scale='=>'int'], 'new' => ['numeric-string', 'num'=>'numeric-string', 'exponent'=>'numeric-string', 'modulus'=>'numeric-string', 'scale='=>'int|null'], ], 'bcscale' => [ 'old' => ['int', 'scale='=>'int'], 'new' => ['int', 'scale='=>'int|null'], ], 'bcsqrt' => [ 'old' => ['numeric-string', 'num'=>'numeric-string', 'scale='=>'int'], 'new' => ['numeric-string', 'num'=>'numeric-string', 'scale='=>'int|null'], ], 'bcsub' => [ 'old' => ['numeric-string', 'num1'=>'numeric-string', 'num2'=>'numeric-string', 'scale='=>'int'], 'new' => ['numeric-string', 'num1'=>'numeric-string', 'num2'=>'numeric-string', 'scale='=>'int|null'], ], 'bind_textdomain_codeset' => [ 'old' => ['string', 'domain'=>'string', 'codeset'=>'string'], 'new' => ['string', 'domain'=>'string', 'codeset'=>'?string'], ], 'bindtextdomain' => [ 'old' => ['string', 'domain'=>'string', 'directory'=>'string'], 'new' => ['string', 'domain'=>'string', 'directory'=>'?string'], ], 'bzdecompress' => [ 'old' => ['string|int|false', 'data'=>'string', 'use_less_memory='=>'int'], 'new' => ['string|int|false', 'data'=>'string', 'use_less_memory='=>'bool'], ], 'bzwrite' => [ 'old' => ['int|false', 'bz'=>'resource', 'data'=>'string', 'length='=>'int'], 'new' => ['int|false', 'bz'=>'resource', 'data'=>'string', 'length='=>'?int'], ], 'collator_get_strength' => [ 'old' => ['int|false', 'object'=>'collator'], 'new' => ['int', 'object'=>'collator'], ], 'com_load_typelib' => [ 'old' => ['bool', 'typelib_name'=>'string', 'case_insensitive='=>'bool'], 'new' => ['bool', 'typelib_name'=>'string', 'case_insensitive='=>'true'], ], 'count' => [ 'old' => ['int<0, max>', 'value'=>'Countable|array|SimpleXMLElement', 'mode='=>'int'], 'new' => ['int<0, max>', 'value'=>'Countable|array', 'mode='=>'int'], ], 'sizeof' => [ 'old' => ['int<0, max>', 'value'=>'Countable|array|SimpleXMLElement', 'mode='=>'int'], 'new' => ['int<0, max>', 'value'=>'Countable|array', 'mode='=>'int'], ], 'count_chars' => [ 'old' => ['array|false', 'input'=>'string', 'mode='=>'0|1|2'], 'new' => ['array', 'input'=>'string', 'mode='=>'0|1|2'], ], 'count_chars\'1' => [ 'old' => ['string|false', 'input'=>'string', 'mode='=>'3|4'], 'new' => ['string', 'input'=>'string', 'mode='=>'3|4'], ], 'crypt' => [ 'old' => ['string', 'string'=>'string', 'salt='=>'string'], 'new' => ['string', 'string'=>'string', 'salt'=>'string'], ], 'curl_close' => [ 'old' => ['void', 'ch'=>'resource'], 'new' => ['void', 'handle'=>'CurlHandle'], ], 'curl_copy_handle' => [ 'old' => ['resource|false', 'ch'=>'resource'], 'new' => ['CurlHandle|false', 'handle'=>'CurlHandle'], ], 'curl_errno' => [ 'old' => ['int', 'ch'=>'resource'], 'new' => ['int', 'handle'=>'CurlHandle'], ], 'curl_error' => [ 'old' => ['string', 'ch'=>'resource'], 'new' => ['string', 'handle'=>'CurlHandle'], ], 'curl_escape' => [ 'old' => ['string|false', 'ch'=>'resource', 'string'=>'string'], 'new' => ['string|false', 'handle'=>'CurlHandle', 'string'=>'string'], ], 'curl_exec' => [ 'old' => ['bool|string', 'ch'=>'resource'], 'new' => ['bool|string', 'handle'=>'CurlHandle'], ], 'curl_file_create' => [ 'old' => ['CURLFile', 'filename'=>'string', 'mimetype='=>'string', 'postfilename='=>'string'], 'new' => ['CURLFile', 'filename'=>'string', 'mime_type='=>'string|null', 'posted_filename='=>'string|null'], ], 'curl_getinfo' => [ 'old' => ['mixed', 'ch'=>'resource', 'option='=>'int'], 'new' => ['mixed', 'handle'=>'CurlHandle', 'option='=>'?int'], ], 'curl_init' => [ 'old' => ['resource|false', 'url='=>'string'], 'new' => ['CurlHandle|false', 'url='=>'?string'], ], 'curl_multi_add_handle' => [ 'old' => ['int', 'mh'=>'resource', 'ch'=>'resource'], 'new' => ['int', 'multi_handle'=>'CurlMultiHandle', 'handle'=>'CurlHandle'], ], 'curl_multi_close' => [ 'old' => ['void', 'mh'=>'resource'], 'new' => ['void', 'multi_handle'=>'CurlMultiHandle'], ], 'curl_multi_errno' => [ 'old' => ['int|false', 'mh'=>'resource'], 'new' => ['int', 'multi_handle'=>'CurlMultiHandle'], ], 'curl_multi_exec' => [ 'old' => ['int', 'mh'=>'resource', '&w_still_running'=>'int'], 'new' => ['int', 'multi_handle'=>'CurlMultiHandle', '&w_still_running'=>'int'], ], 'curl_multi_getcontent' => [ 'old' => ['string', 'ch'=>'resource'], 'new' => ['string', 'handle'=>'CurlHandle'], ], 'curl_multi_info_read' => [ 'old' => ['array|false', 'mh'=>'resource', '&w_msgs_in_queue='=>'int'], 'new' => ['array|false', 'multi_handle'=>'CurlMultiHandle', '&w_queued_messages='=>'int'], ], 'curl_multi_init' => [ 'old' => ['resource'], 'new' => ['CurlMultiHandle'], ], 'curl_multi_remove_handle' => [ 'old' => ['int', 'mh'=>'resource', 'ch'=>'resource'], 'new' => ['int', 'multi_handle'=>'CurlMultiHandle', 'handle'=>'CurlHandle'], ], 'curl_multi_select' => [ 'old' => ['int', 'mh'=>'resource', 'timeout='=>'float'], 'new' => ['int', 'multi_handle'=>'CurlMultiHandle', 'timeout='=>'float'], ], 'curl_multi_setopt' => [ 'old' => ['bool', 'mh'=>'resource', 'option'=>'int', 'value'=>'mixed'], 'new' => ['bool', 'multi_handle'=>'CurlMultiHandle', 'option'=>'int', 'value'=>'mixed'], ], 'curl_pause' => [ 'old' => ['int', 'ch'=>'resource', 'bitmask'=>'int'], 'new' => ['int', 'handle'=>'CurlHandle', 'flags'=>'int'], ], 'curl_reset' => [ 'old' => ['void', 'ch'=>'resource'], 'new' => ['void', 'handle'=>'CurlHandle'], ], 'curl_setopt' => [ 'old' => ['bool', 'ch'=>'resource', 'option'=>'int', 'value'=>'callable|mixed'], 'new' => ['bool', 'handle'=>'CurlHandle', 'option'=>'int', 'value'=>'callable|mixed'], ], 'curl_setopt_array' => [ 'old' => ['bool', 'ch'=>'resource', 'options'=>'array'], 'new' => ['bool', 'handle'=>'CurlHandle', 'options'=>'array'], ], 'curl_share_close' => [ 'old' => ['void', 'sh'=>'resource'], 'new' => ['void', 'share_handle'=>'CurlShareHandle'], ], 'curl_share_errno' => [ 'old' => ['int|false', 'sh'=>'resource'], 'new' => ['int', 'share_handle'=>'CurlShareHandle'], ], 'curl_share_init' => [ 'old' => ['resource'], 'new' => ['CurlShareHandle'], ], 'curl_share_setopt' => [ 'old' => ['bool', 'sh'=>'resource', 'option'=>'int', 'value'=>'mixed'], 'new' => ['bool', 'share_handle'=>'CurlShareHandle', 'option'=>'int', 'value'=>'mixed'], ], 'curl_unescape' => [ 'old' => ['string|false', 'ch'=>'resource', 'string'=>'string'], 'new' => ['string|false', 'handle'=>'CurlHandle', 'string'=>'string'], ], 'date' => [ 'old' => ['string', 'format'=>'string', 'timestamp='=>'int'], 'new' => ['string', 'format'=>'string', 'timestamp='=>'?int'], ], 'date_add' => [ 'old' => ['DateTime|false', 'object'=>'DateTime', 'interval'=>'DateInterval'], 'new' => ['DateTime', 'object'=>'DateTime', 'interval'=>'DateInterval'], ], 'date_date_set' => [ 'old' => ['DateTime|false', 'object'=>'DateTime', 'year'=>'int', 'month'=>'int', 'day'=>'int'], 'new' => ['DateTime', 'object'=>'DateTime', 'year'=>'int', 'month'=>'int', 'day'=>'int'], ], 'date_diff' => [ 'old' => ['DateInterval|false', 'baseObject'=>'DateTimeInterface', 'targetObject'=>'DateTimeInterface', 'absolute='=>'bool'], 'new' => ['DateInterval', 'baseObject'=>'DateTimeInterface', 'targetObject'=>'DateTimeInterface', 'absolute='=>'bool'], ], 'date_format' => [ 'old' => ['string|false', 'object'=>'DateTimeInterface', 'format'=>'string'], 'new' => ['string', 'object'=>'DateTimeInterface', 'format'=>'string'], ], 'date_offset_get' => [ 'old' => ['int|false', 'object'=>'DateTimeInterface'], 'new' => ['int', 'object'=>'DateTimeInterface'], ], 'date_parse' => [ 'old' => ['array|false', 'datetime'=>'string'], 'new' => ['array', 'datetime'=>'string'], ], 'date_sub' => [ 'old' => ['DateTime|false', 'object'=>'DateTime', 'interval'=>'DateInterval'], 'new' => ['DateTime', 'object'=>'DateTime', 'interval'=>'DateInterval'], ], 'date_sun_info' => [ 'old' => ['array|false', 'timestamp'=>'int', 'latitude'=>'float', 'longitude'=>'float'], 'new' => ['array', 'timestamp'=>'int', 'latitude'=>'float', 'longitude'=>'float'], ], 'date_sunrise' => [ 'old' => ['string|int|float|false', 'timestamp'=>'int', 'returnFormat='=>'int', 'latitude='=>'float', 'longitude='=>'float', 'zenith='=>'float', 'utcOffset='=>'float'], 'new' => ['string|int|float|false', 'timestamp'=>'int', 'returnFormat='=>'int', 'latitude='=>'?float', 'longitude='=>'?float', 'zenith='=>'?float', 'utcOffset='=>'?float'], ], 'date_sunset' => [ 'old' => ['string|int|float|false', 'timestamp'=>'int', 'returnFormat='=>'int', 'latitude='=>'float', 'longitude='=>'float', 'zenith='=>'float', 'utcOffset='=>'float'], 'new' => ['string|int|float|false', 'timestamp'=>'int', 'returnFormat='=>'int', 'latitude='=>'?float', 'longitude='=>'?float', 'zenith='=>'?float', 'utcOffset='=>'?float'], ], 'date_time_set' => [ 'old' => ['DateTime|false', 'object'=>'', 'hour'=>'', 'minute'=>'', 'second='=>'', 'microsecond='=>''], 'new' => ['DateTime', 'object'=>'', 'hour'=>'', 'minute'=>'', 'second='=>'', 'microsecond='=>''], ], 'date_timestamp_set' => [ 'old' => ['DateTime|false', 'object'=>'DateTime', 'timestamp'=>'int'], 'new' => ['DateTime', 'object'=>'DateTime', 'timestamp'=>'int'], ], 'date_timezone_set' => [ 'old' => ['DateTime|false', 'object'=>'DateTime', 'timezone'=>'DateTimeZone'], 'new' => ['DateTime', 'object'=>'DateTime', 'timezone'=>'DateTimeZone'], ], 'datefmt_create' => [ 'old' => ['?IntlDateFormatter', 'locale'=>'?string', 'dateType'=>'int', 'timeType'=>'int', 'timezone='=>'DateTimeZone|IntlTimeZone|string|null', 'calendar='=>'IntlCalendar|int|null', 'pattern='=>'string'], 'new' => ['?IntlDateFormatter', 'locale'=>'?string', 'dateType='=>'int', 'timeType='=>'int', 'timezone='=>'DateTimeZone|IntlTimeZone|string|null', 'calendar='=>'IntlCalendar|int|null', 'pattern='=>'?string'], ], 'deflate_add' => [ 'old' => ['string|false', 'context'=>'resource', 'data'=>'string', 'flush_mode='=>'int'], 'new' => ['string|false', 'context'=>'DeflateContext', 'data'=>'string', 'flush_mode='=>'int'], ], 'deflate_init' => [ 'old' => ['resource|false', 'encoding'=>'int', 'options='=>'array'], 'new' => ['DeflateContext|false', 'encoding'=>'int', 'options='=>'array'], ], 'dom_import_simplexml' => [ 'old' => ['DOMElement|null', 'node'=>'SimpleXMLElement'], 'new' => ['DOMElement', 'node'=>'SimpleXMLElement'], ], 'easter_date' => [ 'old' => ['int', 'year='=>'int', 'mode='=>'int'], 'new' => ['int', 'year='=>'?int', 'mode='=>'int'], ], 'easter_days' => [ 'old' => ['int', 'year='=>'int', 'mode='=>'int'], 'new' => ['int', 'year='=>'?int', 'mode='=>'int'], ], 'enchant_broker_describe' => [ 'old' => ['array|false', 'broker'=>'resource'], 'new' => ['array', 'broker'=>'EnchantBroker'], ], 'enchant_broker_dict_exists' => [ 'old' => ['bool', 'broker'=>'resource', 'tag'=>'string'], 'new' => ['bool', 'broker'=>'EnchantBroker', 'tag'=>'string'], ], 'enchant_broker_free' => [ 'old' => ['bool', 'broker'=>'resource'], 'new' => ['bool', 'broker'=>'EnchantBroker'], ], 'enchant_broker_free_dict' => [ 'old' => ['bool', 'dictionary'=>'resource'], 'new' => ['bool', 'dictionary'=>'EnchantBroker'], ], 'enchant_broker_get_dict_path' => [ 'old' => ['string', 'broker'=>'resource', 'type'=>'int'], 'new' => ['string', 'broker'=>'EnchantBroker', 'type'=>'int'], ], 'enchant_broker_get_error' => [ 'old' => ['string|false', 'broker'=>'resource'], 'new' => ['string|false', 'broker'=>'EnchantBroker'], ], 'enchant_broker_init' => [ 'old' => ['resource|false'], 'new' => ['EnchantBroker|false'], ], 'enchant_broker_list_dicts' => [ 'old' => ['array|false', 'broker'=>'resource'], 'new' => ['array', 'broker'=>'EnchantBroker'], ], 'enchant_broker_request_dict' => [ 'old' => ['resource|false', 'broker'=>'resource', 'tag'=>'string'], 'new' => ['EnchantDictionary|false', 'broker'=>'EnchantBroker', 'tag'=>'string'], ], 'enchant_broker_request_pwl_dict' => [ 'old' => ['resource|false', 'broker'=>'resource', 'filename'=>'string'], 'new' => ['EnchantDictionary|false', 'broker'=>'EnchantBroker', 'filename'=>'string'], ], 'enchant_broker_set_dict_path' => [ 'old' => ['bool', 'broker'=>'resource', 'type'=>'int', 'path'=>'string'], 'new' => ['bool', 'broker'=>'EnchantBroker', 'type'=>'int', 'path'=>'string'], ], 'enchant_broker_set_ordering' => [ 'old' => ['bool', 'broker'=>'resource', 'tag'=>'string', 'ordering'=>'string'], 'new' => ['bool', 'broker'=>'EnchantBroker', 'tag'=>'string', 'ordering'=>'string'], ], 'enchant_dict_add_to_personal' => [ 'old' => ['void', 'dictionary'=>'resource', 'word'=>'string'], 'new' => ['void', 'dictionary'=>'EnchantDictionary', 'word'=>'string'], ], 'enchant_dict_add_to_session' => [ 'old' => ['void', 'dictionary'=>'resource', 'word'=>'string'], 'new' => ['void', 'dictionary'=>'EnchantDictionary', 'word'=>'string'], ], 'enchant_dict_check' => [ 'old' => ['bool', 'dictionary'=>'resource', 'word'=>'string'], 'new' => ['bool', 'dictionary'=>'EnchantDictionary', 'word'=>'string'], ], 'enchant_dict_describe' => [ 'old' => ['array', 'dictionary'=>'resource'], 'new' => ['array', 'dictionary'=>'EnchantDictionary'], ], 'enchant_dict_get_error' => [ 'old' => ['string', 'dictionary'=>'resource'], 'new' => ['string', 'dictionary'=>'EnchantDictionary'], ], 'enchant_dict_is_in_session' => [ 'old' => ['bool', 'dictionary'=>'resource', 'word'=>'string'], 'new' => ['bool', 'dictionary'=>'EnchantDictionary', 'word'=>'string'], ], 'enchant_dict_quick_check' => [ 'old' => ['bool', 'dictionary'=>'resource', 'word'=>'string', '&w_suggestions='=>'array'], 'new' => ['bool', 'dictionary'=>'EnchantDictionary', 'word'=>'string', '&w_suggestions='=>'array'], ], 'enchant_dict_store_replacement' => [ 'old' => ['void', 'dictionary'=>'resource', 'misspelled'=>'string', 'correct'=>'string'], 'new' => ['void', 'dictionary'=>'EnchantDictionary', 'misspelled'=>'string', 'correct'=>'string'], ], 'enchant_dict_suggest' => [ 'old' => ['array', 'dictionary'=>'resource', 'word'=>'string'], 'new' => ['array', 'dictionary'=>'EnchantDictionary', 'word'=>'string'], ], 'error_log' => [ 'old' => ['bool', 'message'=>'string', 'message_type='=>'int', 'destination='=>'string', 'additional_headers='=>'string'], 'new' => ['bool', 'message'=>'string', 'message_type='=>'int', 'destination='=>'?string', 'additional_headers='=>'?string'], ], 'error_reporting' => [ 'old' => ['int', 'error_level='=>'int'], 'new' => ['int', 'error_level='=>'?int'], ], 'exif_read_data' => [ 'old' => ['array|false', 'file'=>'string|resource', 'required_sections='=>'string', 'as_arrays='=>'bool', 'read_thumbnail='=>'bool'], 'new' => ['array|false', 'file'=>'string|resource', 'required_sections='=>'?string', 'as_arrays='=>'bool', 'read_thumbnail='=>'bool'], ], 'explode' => [ 'old' => ['list|false', 'separator'=>'string', 'string'=>'string', 'limit='=>'int'], 'new' => ['list', 'separator'=>'string', 'string'=>'string', 'limit='=>'int'], ], 'fgetcsv' => [ 'old' => ['list|array{0: null}|false', 'stream'=>'resource', 'length='=>'int', 'separator='=>'string', 'enclosure='=>'string', 'escape='=>'string'], 'new' => ['list|array{0: null}|false', 'stream'=>'resource', 'length='=>'?int', 'separator='=>'string', 'enclosure='=>'string', 'escape='=>'string'], ], 'fgets' => [ 'old' => ['string|false', 'stream'=>'resource', 'length='=>'int'], 'new' => ['string|false', 'stream'=>'resource', 'length='=>'?int'], ], 'file_get_contents' => [ 'old' => ['string|false', 'filename'=>'string', 'use_include_path='=>'bool', 'context='=>'?resource', 'offset='=>'int', 'length='=>'int'], 'new' => ['string|false', 'filename'=>'string', 'use_include_path='=>'bool', 'context='=>'?resource', 'offset='=>'int', 'length='=>'?int'], ], 'finfo_open' => [ 'old' => ['resource|false', 'flags='=>'int', 'magic_database='=>'string'], 'new' => ['resource|false', 'flags='=>'int', 'magic_database='=>'?string'], ], 'fputs' => [ 'old' => ['int|false', 'stream'=>'resource', 'data'=>'string', 'length='=>'int'], 'new' => ['int|false', 'stream'=>'resource', 'data'=>'string', 'length='=>'?int'], ], 'fsockopen' => [ 'old' => ['resource|false', 'hostname'=>'string', 'port='=>'int', '&w_error_code='=>'int', '&w_error_message='=>'string', 'timeout='=>'float'], 'new' => ['resource|false', 'hostname'=>'string', 'port='=>'int', '&w_error_code='=>'int', '&w_error_message='=>'string', 'timeout='=>'?float'], ], 'fwrite' => [ 'old' => ['int|false', 'stream'=>'resource', 'data'=>'string', 'length='=>'int'], 'new' => ['int|false', 'stream'=>'resource', 'data'=>'string', 'length='=>'?int'], ], 'get_class_methods' => [ 'old' => ['list|null', 'object_or_class'=>'mixed'], 'new' => ['list', 'object_or_class'=>'object|class-string'], ], 'get_headers' => [ 'old' => ['array|false', 'url'=>'string', 'associative='=>'int', 'context='=>'?resource'], 'new' => ['array|false', 'url'=>'string', 'associative='=>'bool', 'context='=>'?resource'], ], 'get_parent_class' => [ 'old' => ['class-string|false', 'object_or_class='=>'mixed'], 'new' => ['class-string|false', 'object_or_class='=>'object|class-string'], ], 'get_resources' => [ 'old' => ['array', 'type='=>'string'], 'new' => ['array', 'type='=>'?string'], ], 'getdate' => [ 'old' => ['array{seconds: int<0, 59>, minutes: int<0, 59>, hours: int<0, 23>, mday: int<1, 31>, wday: int<0, 6>, mon: int<1, 12>, year: int, yday: int<0, 365>, weekday: "Monday"|"Tuesday"|"Wednesday"|"Thursday"|"Friday"|"Saturday"|"Sunday", month: "January"|"February"|"March"|"April"|"May"|"June"|"July"|"August"|"September"|"October"|"November"|"December", 0: int}', 'timestamp='=>'int'], 'new' => ['array{seconds: int<0, 59>, minutes: int<0, 59>, hours: int<0, 23>, mday: int<1, 31>, wday: int<0, 6>, mon: int<1, 12>, year: int, yday: int<0, 365>, weekday: "Monday"|"Tuesday"|"Wednesday"|"Thursday"|"Friday"|"Saturday"|"Sunday", month: "January"|"February"|"March"|"April"|"May"|"June"|"July"|"August"|"September"|"October"|"November"|"December", 0: int}', 'timestamp='=>'?int'], ], 'gmdate' => [ 'old' => ['string', 'format'=>'string', 'timestamp='=>'int'], 'new' => ['string', 'format'=>'string', 'timestamp='=>'int|null'], ], 'gmmktime' => [ 'old' => ['int|false', 'hour='=>'int', 'minute='=>'int', 'second='=>'int', 'month='=>'int', 'day='=>'int', 'year='=>'int'], 'new' => ['int|false', 'hour'=>'int', 'minute='=>'int|null', 'second='=>'int|null', 'month='=>'int|null', 'day='=>'int|null', 'year='=>'int|null'], ], 'gmp_binomial' => [ 'old' => ['GMP|false', 'n'=>'GMP|string|int', 'k'=>'int'], 'new' => ['GMP', 'n'=>'GMP|string|int', 'k'=>'int'], ], 'gmp_export' => [ 'old' => ['string|false', 'num'=>'GMP|string|int', 'word_size='=>'int', 'flags='=>'int'], 'new' => ['string', 'num'=>'GMP|string|int', 'word_size='=>'int', 'flags='=>'int'], ], 'gmp_import' => [ 'old' => ['GMP|false', 'data'=>'string', 'word_size='=>'int', 'flags='=>'int'], 'new' => ['GMP', 'data'=>'string', 'word_size='=>'int', 'flags='=>'int'], ], 'gmstrftime' => [ 'old' => ['string|false', 'format'=>'string', 'timestamp='=>'int'], 'new' => ['string|false', 'format'=>'string', 'timestamp='=>'?int'], ], 'gzgets' => [ 'old' => ['string|false', 'stream'=>'resource', 'length='=>'int'], 'new' => ['string|false', 'stream'=>'resource', 'length='=>'?int'], ], 'gzputs' => [ 'old' => ['int|false', 'stream'=>'resource', 'data'=>'string', 'length='=>'int'], 'new' => ['int|false', 'stream'=>'resource', 'data'=>'string', 'length='=>'?int'], ], 'gzwrite' => [ 'old' => ['int|false', 'stream'=>'resource', 'data'=>'string', 'length='=>'int'], 'new' => ['int|false', 'stream'=>'resource', 'data'=>'string', 'length='=>'?int'], ], 'hash' => [ 'old' => ['string|false', 'algo'=>'string', 'data'=>'string', 'binary='=>'bool'], 'new' => ['non-empty-string', 'algo'=>'string', 'data'=>'string', 'binary='=>'bool'], ], 'hash_hmac' => [ 'old' => ['non-empty-string|false', 'algo'=>'string', 'data'=>'string', 'key'=>'string', 'binary='=>'bool'], 'new' => ['non-empty-string', 'algo'=>'string', 'data'=>'string', 'key'=>'string', 'binary='=>'bool'], ], 'hash_hmac_file' => [ 'old' => ['non-empty-string|false', 'algo'=>'string', 'data'=>'string', 'key'=>'string', 'binary='=>'bool'], 'new' => ['non-empty-string', 'algo'=>'string', 'filename'=>'string', 'key'=>'string', 'binary='=>'bool'], ], 'hash_init' => [ 'old' => ['HashContext|false', 'algo'=>'string', 'flags='=>'int', 'key='=>'string'], 'new' => ['HashContext', 'algo'=>'string', 'flags='=>'int', 'key='=>'string'], ], 'hash_hkdf' => [ 'old' => ['non-empty-string|false', 'algo'=>'string', 'key'=>'string', 'length='=>'int', 'info='=>'string', 'salt='=>'string'], 'new' => ['non-empty-string', 'algo'=>'string', 'key'=>'string', 'length='=>'int', 'info='=>'string', 'salt='=>'string'], ], 'hash_update_file' => [ 'old' => ['bool', 'context'=>'HashContext', 'filename'=>'string', 'stream_context='=>'resource'], 'new' => ['bool', 'context'=>'HashContext', 'filename'=>'string', 'stream_context='=>'?resource'], ], 'header_remove' => [ 'old' => ['void', 'name='=>'string'], 'new' => ['void', 'name='=>'?string'], ], 'html_entity_decode' => [ 'old' => ['string', 'string'=>'string', 'flags='=>'int', 'encoding='=>'string'], 'new' => ['string', 'string'=>'string', 'flags='=>'int', 'encoding='=>'?string'], ], 'htmlentities' => [ 'old' => ['string', 'string'=>'string', 'flags='=>'int', 'encoding='=>'string', 'double_encode='=>'bool'], 'new' => ['string', 'string'=>'string', 'flags='=>'int', 'encoding='=>'?string', 'double_encode='=>'bool'], ], 'iconv_mime_decode' => [ 'old' => ['string|false', 'string'=>'string', 'mode='=>'int', 'encoding='=>'string'], 'new' => ['string|false', 'string'=>'string', 'mode='=>'int', 'encoding='=>'?string'], ], 'iconv_mime_decode_headers' => [ 'old' => ['array|false', 'headers'=>'string', 'mode='=>'int', 'encoding='=>'string'], 'new' => ['array|false', 'headers'=>'string', 'mode='=>'int', 'encoding='=>'?string'], ], 'iconv_strlen' => [ 'old' => ['0|positive-int|false', 'string'=>'string', 'encoding='=>'string'], 'new' => ['0|positive-int|false', 'string'=>'string', 'encoding='=>'?string'], ], 'iconv_strpos' => [ 'old' => ['int|false', 'haystack'=>'string', 'needle'=>'string', 'offset='=>'int', 'encoding='=>'string'], 'new' => ['int|false', 'haystack'=>'string', 'needle'=>'string', 'offset='=>'int', 'encoding='=>'?string'], ], 'iconv_strrpos' => [ 'old' => ['int|false', 'haystack'=>'string', 'needle'=>'string', 'encoding='=>'string'], 'new' => ['int|false', 'haystack'=>'string', 'needle'=>'string', 'encoding='=>'?string'], ], 'iconv_substr' => [ 'old' => ['string|false', 'string'=>'string', 'offset'=>'int', 'length='=>'int', 'encoding='=>'string'], 'new' => ['string|false', 'string'=>'string', 'offset'=>'int', 'length='=>'?int', 'encoding='=>'?string'], ], 'idate' => [ 'old' => ['int', 'format'=>'string', 'timestamp='=>'int'], 'new' => ['int', 'format'=>'string', 'timestamp='=>'?int'], ], 'ignore_user_abort' => [ 'old' => ['int', 'enable='=>'bool'], 'new' => ['int', 'enable='=>'?bool'], ], 'imageaffine' => [ 'old' => ['resource|false', 'src'=>'resource', 'affine'=>'array', 'clip='=>'array'], 'new' => ['false|GdImage', 'image'=>'GdImage', 'affine'=>'array', 'clip='=>'?array'], ], 'imagealphablending' => [ 'old' => ['bool', 'image'=>'resource', 'enable'=>'bool'], 'new' => ['bool', 'image'=>'GdImage', 'enable'=>'bool'], ], 'imageantialias' => [ 'old' => ['bool', 'image'=>'resource', 'enable'=>'bool'], 'new' => ['bool', 'image'=>'GdImage', 'enable'=>'bool'], ], 'imagearc' => [ 'old' => ['bool', 'image'=>'resource', 'center_x'=>'int', 'center_y'=>'int', 'width'=>'int', 'height'=>'int', 'start_angle'=>'int', 'end_angle'=>'int', 'color'=>'int'], 'new' => ['bool', 'image'=>'GdImage', 'center_x'=>'int', 'center_y'=>'int', 'width'=>'int', 'height'=>'int', 'start_angle'=>'int', 'end_angle'=>'int', 'color'=>'int'], ], 'imagebmp' => [ 'old' => ['bool', 'image'=>'resource', 'file='=>'resource|string|null', 'compressed='=>'int'], 'new' => ['bool', 'image'=>'GdImage', 'file='=>'resource|string|null', 'compressed='=>'bool'], ], 'imagechar' => [ 'old' => ['bool', 'image'=>'resource', 'font'=>'int', 'x'=>'int', 'y'=>'int', 'char'=>'string', 'color'=>'int'], 'new' => ['bool', 'image'=>'GdImage', 'font'=>'int', 'x'=>'int', 'y'=>'int', 'char'=>'string', 'color'=>'int'], ], 'imagecharup' => [ 'old' => ['bool', 'image'=>'resource', 'font'=>'int', 'x'=>'int', 'y'=>'int', 'char'=>'string', 'color'=>'int'], 'new' => ['bool', 'image'=>'GdImage', 'font'=>'int', 'x'=>'int', 'y'=>'int', 'char'=>'string', 'color'=>'int'], ], 'imagecolorallocate' => [ 'old' => ['int|false', 'image'=>'resource', 'red'=>'int', 'green'=>'int', 'blue'=>'int'], 'new' => ['int|false', 'image'=>'GdImage', 'red'=>'int', 'green'=>'int', 'blue'=>'int'], ], 'imagecolorallocatealpha' => [ 'old' => ['int|false', 'image'=>'resource', 'red'=>'int', 'green'=>'int', 'blue'=>'int', 'alpha'=>'int'], 'new' => ['int|false', 'image'=>'GdImage', 'red'=>'int', 'green'=>'int', 'blue'=>'int', 'alpha'=>'int'], ], 'imagecolorat' => [ 'old' => ['int|false', 'image'=>'resource', 'x'=>'int', 'y'=>'int'], 'new' => ['int|false', 'image'=>'GdImage', 'x'=>'int', 'y'=>'int'], ], 'imagecolorclosest' => [ 'old' => ['int', 'image'=>'resource', 'red'=>'int', 'green'=>'int', 'blue'=>'int'], 'new' => ['int', 'image'=>'GdImage', 'red'=>'int', 'green'=>'int', 'blue'=>'int'], ], 'imagecolorclosestalpha' => [ 'old' => ['int', 'image'=>'resource', 'red'=>'int', 'green'=>'int', 'blue'=>'int', 'alpha'=>'int'], 'new' => ['int', 'image'=>'GdImage', 'red'=>'int', 'green'=>'int', 'blue'=>'int', 'alpha'=>'int'], ], 'imagecolorclosesthwb' => [ 'old' => ['int', 'image'=>'resource', 'red'=>'int', 'green'=>'int', 'blue'=>'int'], 'new' => ['int', 'image'=>'GdImage', 'red'=>'int', 'green'=>'int', 'blue'=>'int'], ], 'imagecolordeallocate' => [ 'old' => ['bool', 'image'=>'resource', 'color'=>'int'], 'new' => ['bool', 'image'=>'GdImage', 'color'=>'int'], ], 'imagecolorexact' => [ 'old' => ['int', 'image'=>'resource', 'red'=>'int', 'green'=>'int', 'blue'=>'int'], 'new' => ['int', 'image'=>'GdImage', 'red'=>'int', 'green'=>'int', 'blue'=>'int'], ], 'imagecolorexactalpha' => [ 'old' => ['int', 'image'=>'resource', 'red'=>'int', 'green'=>'int', 'blue'=>'int', 'alpha'=>'int'], 'new' => ['int', 'image'=>'GdImage', 'red'=>'int', 'green'=>'int', 'blue'=>'int', 'alpha'=>'int'], ], 'imagecolormatch' => [ 'old' => ['bool', 'image1'=>'resource', 'image2'=>'resource'], 'new' => ['bool', 'image1'=>'GdImage', 'image2'=>'GdImage'], ], 'imagecolorresolve' => [ 'old' => ['int', 'image'=>'resource', 'red'=>'int', 'green'=>'int', 'blue'=>'int'], 'new' => ['int', 'image'=>'GdImage', 'red'=>'int', 'green'=>'int', 'blue'=>'int'], ], 'imagecolorresolvealpha' => [ 'old' => ['int', 'image'=>'resource', 'red'=>'int', 'green'=>'int', 'blue'=>'int', 'alpha'=>'int'], 'new' => ['int', 'image'=>'GdImage', 'red'=>'int', 'green'=>'int', 'blue'=>'int', 'alpha'=>'int'], ], 'imagecolorset' => [ 'old' => ['false|null', 'image'=>'resource', 'color'=>'int', 'red'=>'int', 'green'=>'int', 'blue'=>'int', 'alpha='=>'int'], 'new' => ['false|null', 'image'=>'GdImage', 'color'=>'int', 'red'=>'int', 'green'=>'int', 'blue'=>'int', 'alpha='=>'int'], ], 'imagecolorsforindex' => [ 'old' => ['array', 'image'=>'resource', 'color'=>'int'], 'new' => ['array', 'image'=>'GdImage', 'color'=>'int'], ], 'imagecolorstotal' => [ 'old' => ['int', 'image'=>'resource'], 'new' => ['int', 'image'=>'GdImage'], ], 'imagecolortransparent' => [ 'old' => ['int', 'image'=>'resource', 'color='=>'int'], 'new' => ['int', 'image'=>'GdImage', 'color='=>'?int'], ], 'imageconvolution' => [ 'old' => ['bool', 'image'=>'resource', 'matrix'=>'array', 'divisor'=>'float', 'offset'=>'float'], 'new' => ['bool', 'image'=>'GdImage', 'matrix'=>'array', 'divisor'=>'float', 'offset'=>'float'], ], 'imagecopy' => [ 'old' => ['bool', 'dst_image'=>'resource', 'src_image'=>'resource', 'dst_x'=>'int', 'dst_y'=>'int', 'src_x'=>'int', 'src_y'=>'int', 'src_width'=>'int', 'src_height'=>'int'], 'new' => ['bool', 'dst_image'=>'GdImage', 'src_image'=>'GdImage', 'dst_x'=>'int', 'dst_y'=>'int', 'src_x'=>'int', 'src_y'=>'int', 'src_width'=>'int', 'src_height'=>'int'], ], 'imagecopymerge' => [ 'old' => ['bool', 'dst_image'=>'resource', 'src_image'=>'resource', 'dst_x'=>'int', 'dst_y'=>'int', 'src_x'=>'int', 'src_y'=>'int', 'src_width'=>'int', 'src_height'=>'int', 'pct'=>'int'], 'new' => ['bool', 'dst_image'=>'GdImage', 'src_image'=>'GdImage', 'dst_x'=>'int', 'dst_y'=>'int', 'src_x'=>'int', 'src_y'=>'int', 'src_width'=>'int', 'src_height'=>'int', 'pct'=>'int'], ], 'imagecopymergegray' => [ 'old' => ['bool', 'dst_image'=>'resource', 'src_image'=>'resource', 'dst_x'=>'int', 'dst_y'=>'int', 'src_x'=>'int', 'src_y'=>'int', 'src_width'=>'int', 'src_height'=>'int', 'pct'=>'int'], 'new' => ['bool', 'dst_image'=>'GdImage', 'src_image'=>'GdImage', 'dst_x'=>'int', 'dst_y'=>'int', 'src_x'=>'int', 'src_y'=>'int', 'src_width'=>'int', 'src_height'=>'int', 'pct'=>'int'], ], 'imagecopyresampled' => [ 'old' => ['bool', 'dst_image'=>'resource', 'src_image'=>'resource', 'dst_x'=>'int', 'dst_y'=>'int', 'src_x'=>'int', 'src_y'=>'int', 'dst_width'=>'int', 'dst_height'=>'int', 'src_width'=>'int', 'src_height'=>'int'], 'new' => ['bool', 'dst_image'=>'GdImage', 'src_image'=>'GdImage', 'dst_x'=>'int', 'dst_y'=>'int', 'src_x'=>'int', 'src_y'=>'int', 'dst_width'=>'int', 'dst_height'=>'int', 'src_width'=>'int', 'src_height'=>'int'], ], 'imagecopyresized' => [ 'old' => ['bool', 'dst_image'=>'resource', 'src_image'=>'resource', 'dst_x'=>'int', 'dst_y'=>'int', 'src_x'=>'int', 'src_y'=>'int', 'dst_width'=>'int', 'dst_height'=>'int', 'src_width'=>'int', 'src_height'=>'int'], 'new' => ['bool', 'dst_image'=>'GdImage', 'src_image'=>'GdImage', 'dst_x'=>'int', 'dst_y'=>'int', 'src_x'=>'int', 'src_y'=>'int', 'dst_width'=>'int', 'dst_height'=>'int', 'src_width'=>'int', 'src_height'=>'int'], ], 'imagecreate' => [ 'old' => ['resource|false', 'x_size'=>'int', 'y_size'=>'int'], 'new' => ['false|GdImage', 'width'=>'int', 'height'=>'int'], ], 'imagecreatefrombmp' => [ 'old' => ['resource|false', 'filename'=>'string'], 'new' => ['false|GdImage', 'filename'=>'string'], ], 'imagecreatefromgd' => [ 'old' => ['resource|false', 'filename'=>'string'], 'new' => ['false|GdImage', 'filename'=>'string'], ], 'imagecreatefromgd2' => [ 'old' => ['resource|false', 'filename'=>'string'], 'new' => ['false|GdImage', 'filename'=>'string'], ], 'imagecreatefromgd2part' => [ 'old' => ['resource|false', 'filename'=>'string', 'srcx'=>'int', 'srcy'=>'int', 'width'=>'int', 'height'=>'int'], 'new' => ['false|GdImage', 'filename'=>'string', 'x'=>'int', 'y'=>'int', 'width'=>'int', 'height'=>'int'], ], 'imagecreatefromgif' => [ 'old' => ['resource|false', 'filename'=>'string'], 'new' => ['false|GdImage', 'filename'=>'string'], ], 'imagecreatefromjpeg' => [ 'old' => ['resource|false', 'filename'=>'string'], 'new' => ['false|GdImage', 'filename'=>'string'], ], 'imagecreatefrompng' => [ 'old' => ['resource|false', 'filename'=>'string'], 'new' => ['false|GdImage', 'filename'=>'string'], ], 'imagecreatefromstring' => [ 'old' => ['resource|false', 'image'=>'string'], 'new' => ['false|GdImage', 'data'=>'string'], ], 'imagecreatefromwbmp' => [ 'old' => ['resource|false', 'filename'=>'string'], 'new' => ['false|GdImage', 'filename'=>'string'], ], 'imagecreatefromwebp' => [ 'old' => ['resource|false', 'filename'=>'string'], 'new' => ['false|GdImage', 'filename'=>'string'], ], 'imagecreatefromxbm' => [ 'old' => ['resource|false', 'filename'=>'string'], 'new' => ['false|GdImage', 'filename'=>'string'], ], 'imagecreatefromxpm' => [ 'old' => ['resource|false', 'filename'=>'string'], 'new' => ['false|GdImage', 'filename'=>'string'], ], 'imagecreatetruecolor' => [ 'old' => ['resource|false', 'x_size'=>'int', 'y_size'=>'int'], 'new' => ['false|GdImage', 'width'=>'int', 'height'=>'int'], ], 'imagecrop' => [ 'old' => ['resource|false', 'im'=>'resource', 'rect'=>'array'], 'new' => ['false|GdImage', 'image'=>'GdImage', 'rectangle'=>'array'], ], 'imagecropauto' => [ 'old' => ['resource|false', 'im'=>'resource', 'mode='=>'int', 'threshold='=>'float', 'color='=>'int'], 'new' => ['false|GdImage', 'image'=>'GdImage', 'mode='=>'int', 'threshold='=>'float', 'color='=>'int'], ], 'imagedashedline' => [ 'old' => ['bool', 'image'=>'resource', 'x1'=>'int', 'y1'=>'int', 'x2'=>'int', 'y2'=>'int', 'color'=>'int'], 'new' => ['bool', 'image'=>'GdImage', 'x1'=>'int', 'y1'=>'int', 'x2'=>'int', 'y2'=>'int', 'color'=>'int'], ], 'imagedestroy' => [ 'old' => ['bool', 'image'=>'resource'], 'new' => ['bool', 'image'=>'GdImage'], ], 'imageellipse' => [ 'old' => ['bool', 'image'=>'resource', 'center_x'=>'int', 'center_y'=>'int', 'width'=>'int', 'height'=>'int', 'color'=>'int'], 'new' => ['bool', 'image'=>'GdImage', 'center_x'=>'int', 'center_y'=>'int', 'width'=>'int', 'height'=>'int', 'color'=>'int'], ], 'imagefill' => [ 'old' => ['bool', 'image'=>'resource', 'x'=>'int', 'y'=>'int', 'color'=>'int'], 'new' => ['bool', 'image'=>'GdImage', 'x'=>'int', 'y'=>'int', 'color'=>'int'], ], 'imagefilledarc' => [ 'old' => ['bool', 'image'=>'resource', 'center_x'=>'int', 'center_y'=>'int', 'width'=>'int', 'height'=>'int', 'start_angle'=>'int', 'end_angle'=>'int', 'color'=>'int', 'style'=>'int'], 'new' => ['bool', 'image'=>'GdImage', 'center_x'=>'int', 'center_y'=>'int', 'width'=>'int', 'height'=>'int', 'start_angle'=>'int', 'end_angle'=>'int', 'color'=>'int', 'style'=>'int'], ], 'imagefilledellipse' => [ 'old' => ['bool', 'image'=>'resource', 'center_x'=>'int', 'center_y'=>'int', 'width'=>'int', 'height'=>'int', 'color'=>'int'], 'new' => ['bool', 'image'=>'GdImage', 'center_x'=>'int', 'center_y'=>'int', 'width'=>'int', 'height'=>'int', 'color'=>'int'], ], 'imagefilledpolygon' => [ 'old' => ['bool', 'image'=>'resource', 'points'=>'array', 'num_points_or_color'=>'int', 'color'=>'int'], 'new' => ['bool', 'image'=>'GdImage', 'points'=>'array', 'num_points_or_color'=>'int', 'color'=>'int'], ], 'imagefilledrectangle' => [ 'old' => ['bool', 'image'=>'resource', 'x1'=>'int', 'y1'=>'int', 'x2'=>'int', 'y2'=>'int', 'color'=>'int'], 'new' => ['bool', 'image'=>'GdImage', 'x1'=>'int', 'y1'=>'int', 'x2'=>'int', 'y2'=>'int', 'color'=>'int'], ], 'imagefilltoborder' => [ 'old' => ['bool', 'image'=>'resource', 'x'=>'int', 'y'=>'int', 'border_color'=>'int', 'color'=>'int'], 'new' => ['bool', 'image'=>'GdImage', 'x'=>'int', 'y'=>'int', 'border_color'=>'int', 'color'=>'int'], ], 'imagefilter' => [ 'old' => ['bool', 'image'=>'resource', 'filter'=>'int', '...args='=>'array|int|float|bool'], 'new' => ['bool', 'image'=>'GdImage', 'filter'=>'int', '...args='=>'array|int|float|bool'], ], 'imageflip' => [ 'old' => ['bool', 'image'=>'resource', 'mode'=>'int'], 'new' => ['bool', 'image'=>'GdImage', 'mode'=>'int'], ], 'imagefttext' => [ 'old' => ['array|false', 'image'=>'resource', 'size'=>'float', 'angle'=>'float', 'x'=>'int', 'y'=>'int', 'color'=>'int', 'font_filename'=>'string', 'text'=>'string', 'options='=>'array'], 'new' => ['array|false', 'image'=>'GdImage', 'size'=>'float', 'angle'=>'float', 'x'=>'int', 'y'=>'int', 'color'=>'int', 'font_filename'=>'string', 'text'=>'string', 'options='=>'array'], ], 'imagegammacorrect' => [ 'old' => ['bool', 'image'=>'resource', 'input_gamma'=>'float', 'output_gamma'=>'float'], 'new' => ['bool', 'image'=>'GdImage', 'input_gamma'=>'float', 'output_gamma'=>'float'], ], 'imagegd' => [ 'old' => ['bool', 'image'=>'resource', 'file='=>'string|resource|null'], 'new' => ['bool', 'image'=>'GdImage', 'file='=>'string|resource|null'], ], 'imagegd2' => [ 'old' => ['bool', 'image'=>'resource', 'file='=>'string|resource|null', 'chunk_size='=>'int', 'mode='=>'int'], 'new' => ['bool', 'image'=>'GdImage', 'file='=>'string|resource|null', 'chunk_size='=>'int', 'mode='=>'int'], ], 'imagegetclip' => [ 'old' => ['array|false', 'im'=>'resource'], 'new' => ['array', 'image'=>'GdImage'], ], 'imagegif' => [ 'old' => ['bool', 'image'=>'resource', 'file='=>'string|resource|null'], 'new' => ['bool', 'image'=>'GdImage', 'file='=>'string|resource|null'], ], 'imagegrabscreen' => [ 'old' => ['false|resource'], 'new' => ['false|GdImage'], ], 'imagegrabwindow' => [ 'old' => ['false|resource', 'window_handle'=>'int', 'client_area='=>'int'], 'new' => ['false|GdImage', 'handle'=>'int', 'client_area='=>'int'], ], 'imageinterlace' => [ 'old' => ['int|false', 'image'=>'resource', 'enable='=>'int'], 'new' => ['bool', 'image'=>'GdImage', 'enable='=>'bool|null'], ], 'imageistruecolor' => [ 'old' => ['bool', 'image'=>'resource'], 'new' => ['bool', 'image'=>'GdImage'], ], 'imagejpeg' => [ 'old' => ['bool', 'image'=>'resource', 'file='=>'string|resource|null', 'quality='=>'int'], 'new' => ['bool', 'image'=>'GdImage', 'file='=>'string|resource|null', 'quality='=>'int'], ], 'imagelayereffect' => [ 'old' => ['bool', 'image'=>'resource', 'effect'=>'int'], 'new' => ['bool', 'image'=>'GdImage', 'effect'=>'int'], ], 'imageline' => [ 'old' => ['bool', 'image'=>'resource', 'x1'=>'int', 'y1'=>'int', 'x2'=>'int', 'y2'=>'int', 'color'=>'int'], 'new' => ['bool', 'image'=>'GdImage', 'x1'=>'int', 'y1'=>'int', 'x2'=>'int', 'y2'=>'int', 'color'=>'int'], ], 'imageopenpolygon' => [ 'old' => ['bool', 'image'=>'resource', 'points'=>'array', 'num_points'=>'int', 'color'=>'int'], 'new' => ['bool', 'image'=>'GdImage', 'points'=>'array', 'num_points'=>'int', 'color'=>'int'], ], 'imagepalettecopy' => [ 'old' => ['void', 'dst'=>'resource', 'src'=>'resource'], 'new' => ['void', 'dst'=>'GdImage', 'src'=>'GdImage'], ], 'imagepalettetotruecolor' => [ 'old' => ['bool', 'image'=>'resource'], 'new' => ['bool', 'image'=>'GdImage'], ], 'imagepng' => [ 'old' => ['bool', 'image'=>'resource', 'file='=>'string|resource|null', 'quality='=>'int', 'filters='=>'int'], 'new' => ['bool', 'image'=>'GdImage', 'file='=>'string|resource|null', 'quality='=>'int', 'filters='=>'int'], ], 'imagepolygon' => [ 'old' => ['bool', 'image'=>'resource', 'points'=>'array', 'num_points_or_color'=>'int', 'color'=>'int'], 'new' => ['bool', 'image'=>'GdImage', 'points'=>'array', 'num_points_or_color'=>'int', 'color'=>'int'], ], 'imagerectangle' => [ 'old' => ['bool', 'image'=>'resource', 'x1'=>'int', 'y1'=>'int', 'x2'=>'int', 'y2'=>'int', 'color'=>'int'], 'new' => ['bool', 'image'=>'GdImage', 'x1'=>'int', 'y1'=>'int', 'x2'=>'int', 'y2'=>'int', 'color'=>'int'], ], 'imageresolution' => [ 'old' => ['array|bool', 'image'=>'resource', 'resolution_x='=>'int', 'resolution_y='=>'int'], 'new' => ['array|bool', 'image'=>'GdImage', 'resolution_x='=>'?int', 'resolution_y='=>'?int'], ], 'imagerotate' => [ 'old' => ['resource|false', 'src_im'=>'resource', 'angle'=>'float', 'bgdcolor'=>'int', 'ignoretransparent='=>'int'], 'new' => ['false|GdImage', 'image'=>'GdImage', 'angle'=>'float', 'background_color'=>'int', 'ignore_transparent='=>'bool'], ], 'imagesavealpha' => [ 'old' => ['bool', 'image'=>'resource', 'enable'=>'bool'], 'new' => ['bool', 'image'=>'GdImage', 'enable'=>'bool'], ], 'imagescale' => [ 'old' => ['resource|false', 'im'=>'resource', 'new_width'=>'int', 'new_height='=>'int', 'method='=>'int'], 'new' => ['false|GdImage', 'image'=>'GdImage', 'width'=>'int', 'height='=>'int', 'mode='=>'int'], ], 'imagesetbrush' => [ 'old' => ['bool', 'image'=>'resource', 'brush'=>'resource'], 'new' => ['bool', 'image'=>'GdImage', 'brush'=>'GdImage'], ], 'imagesetclip' => [ 'old' => ['bool', 'image'=>'resource', 'x1'=>'int', 'x2'=>'int', 'y1'=>'int', 'y2'=>'int'], 'new' => ['bool', 'image'=>'GdImage', 'x1'=>'int', 'x2'=>'int', 'y1'=>'int', 'y2'=>'int'], ], 'imagesetinterpolation' => [ 'old' => ['bool', 'image'=>'resource', 'method='=>'int'], 'new' => ['bool', 'image'=>'GdImage', 'method='=>'int'], ], 'imagesetpixel' => [ 'old' => ['bool', 'image'=>'resource', 'x'=>'int', 'y'=>'int', 'color'=>'int'], 'new' => ['bool', 'image'=>'GdImage', 'x'=>'int', 'y'=>'int', 'color'=>'int'], ], 'imagesetstyle' => [ 'old' => ['bool', 'image'=>'resource', 'style'=>'non-empty-array'], 'new' => ['bool', 'image'=>'GdImage', 'style'=>'non-empty-array'], ], 'imagesetthickness' => [ 'old' => ['bool', 'image'=>'resource', 'thickness'=>'int'], 'new' => ['bool', 'image'=>'GdImage', 'thickness'=>'int'], ], 'imagesettile' => [ 'old' => ['bool', 'image'=>'resource', 'tile'=>'resource'], 'new' => ['bool', 'image'=>'GdImage', 'tile'=>'GdImage'], ], 'imagestring' => [ 'old' => ['bool', 'image'=>'resource', 'font'=>'int', 'x'=>'int', 'y'=>'int', 'string'=>'string', 'color'=>'int'], 'new' => ['bool', 'image'=>'GdImage', 'font'=>'int', 'x'=>'int', 'y'=>'int', 'string'=>'string', 'color'=>'int'], ], 'imagestringup' => [ 'old' => ['bool', 'image'=>'resource', 'font'=>'int', 'x'=>'int', 'y'=>'int', 'string'=>'string', 'color'=>'int'], 'new' => ['bool', 'image'=>'GdImage', 'font'=>'int', 'x'=>'int', 'y'=>'int', 'string'=>'string', 'color'=>'int'], ], 'imagesx' => [ 'old' => ['int', 'image'=>'resource'], 'new' => ['int', 'image'=>'GdImage'], ], 'imagesy' => [ 'old' => ['int', 'image'=>'resource'], 'new' => ['int', 'image'=>'GdImage'], ], 'imagetruecolortopalette' => [ 'old' => ['bool', 'image'=>'resource', 'dither'=>'bool', 'num_colors'=>'int'], 'new' => ['bool', 'image'=>'GdImage', 'dither'=>'bool', 'num_colors'=>'int'], ], 'imagettfbbox' => [ 'old' => ['false|array', 'size'=>'float', 'angle'=>'float', 'font_filename'=>'string', 'string'=>'string'], 'new' => ['false|array', 'size'=>'float', 'angle'=>'float', 'font_filename'=>'string', 'string'=>'string', 'options='=>'array'], ], 'imagettftext' => [ 'old' => ['false|array', 'image'=>'resource', 'size'=>'float', 'angle'=>'float', 'x'=>'int', 'y'=>'int', 'color'=>'int', 'font_filename'=>'string', 'text'=>'string'], 'new' => ['false|array', 'image'=>'GdImage', 'size'=>'float', 'angle'=>'float', 'x'=>'int', 'y'=>'int', 'color'=>'int', 'font_filename'=>'string', 'text'=>'string', 'options='=>'array'], ], 'imagewbmp' => [ 'old' => ['bool', 'image'=>'resource', 'file='=>'string|resource|null', 'foreground_color='=>'int'], 'new' => ['bool', 'image'=>'GdImage', 'file='=>'string|resource|null', 'foreground_color='=>'?int'], ], 'imagewebp' => [ 'old' => ['bool', 'image'=>'resource', 'file='=>'string|resource|null', 'quality='=>'int'], 'new' => ['bool', 'image'=>'GdImage', 'file='=>'string|resource|null', 'quality='=>'int'], ], 'imagexbm' => [ 'old' => ['bool', 'image'=>'resource', 'filename'=>'?string', 'foreground_color='=>'int'], 'new' => ['bool', 'image'=>'GdImage', 'filename'=>'?string', 'foreground_color='=>'?int'], ], 'imap_append' => [ 'old' => ['bool', 'imap'=>'resource', 'folder'=>'string', 'message'=>'string', 'options='=>'string', 'internal_date='=>'string'], 'new' => ['bool', 'imap'=>'resource', 'folder'=>'string', 'message'=>'string', 'options='=>'?string', 'internal_date='=>'?string'], ], 'imap_headerinfo' => [ 'old' => ['stdClass|false', 'imap'=>'resource', 'message_num'=>'int', 'from_length='=>'int', 'subject_length='=>'int', 'default_host='=>'string|null'], 'new' => ['stdClass|false', 'imap'=>'resource', 'message_num'=>'int', 'from_length='=>'int', 'subject_length='=>'int'], ], 'imap_mail' => [ 'old' => ['bool', 'to'=>'string', 'subject'=>'string', 'message'=>'string', 'additional_headers='=>'string', 'cc='=>'string', 'bcc='=>'string', 'return_path='=>'string'], 'new' => ['bool', 'to'=>'string', 'subject'=>'string', 'message'=>'string', 'additional_headers='=>'?string', 'cc='=>'?string', 'bcc='=>'?string', 'return_path='=>'?string'], ], 'imap_sort' => [ 'old' => ['array|false', 'imap'=>'resource', 'criteria'=>'int', 'reverse'=>'int', 'flags='=>'int', 'search_criteria='=>'string', 'charset='=>'string'], 'new' => ['array|false', 'imap'=>'resource', 'criteria'=>'int', 'reverse'=>'bool', 'flags='=>'int', 'search_criteria='=>'?string', 'charset='=>'?string'], ], 'inflate_add' => [ 'old' => ['string|false', 'context'=>'resource', 'data'=>'string', 'flush_mode='=>'int'], 'new' => ['string|false', 'context'=>'InflateContext', 'data'=>'string', 'flush_mode='=>'int'], ], 'inflate_get_read_len' => [ 'old' => ['int', 'context'=>'resource'], 'new' => ['int', 'context'=>'InflateContext'], ], 'inflate_get_status' => [ 'old' => ['int', 'context'=>'resource'], 'new' => ['int', 'context'=>'InflateContext'], ], 'inflate_init' => [ 'old' => ['resource|false', 'encoding'=>'int', 'options='=>'array'], 'new' => ['InflateContext|false', 'encoding'=>'int', 'options='=>'array'], ], 'jdtounix' => [ 'old' => ['int|false', 'julian_day'=>'int'], 'new' => ['int', 'julian_day'=>'int'], ], 'ldap_add' => [ 'old' => ['bool', 'ldap'=>'resource', 'dn'=>'string', 'entry'=>'array', 'controls='=>'array'], 'new' => ['bool', 'ldap'=>'resource', 'dn'=>'string', 'entry'=>'array', 'controls='=>'?array'], ], 'ldap_add_ext' => [ 'old' => ['resource|false', 'ldap'=>'resource', 'dn'=>'string', 'entry'=>'array', 'controls='=>'array'], 'new' => ['resource|false', 'ldap'=>'resource', 'dn'=>'string', 'entry'=>'array', 'controls='=>'?array'], ], 'ldap_bind_ext' => [ 'old' => ['resource|false', 'ldap'=>'resource', 'dn='=>'string|null', 'password='=>'string|null', 'controls='=>'array'], 'new' => ['resource|false', 'ldap'=>'resource', 'dn='=>'string|null', 'password='=>'string|null', 'controls='=>'?array'], ], 'ldap_compare' => [ 'old' => ['bool|int', 'ldap'=>'resource', 'dn'=>'string', 'attribute'=>'string', 'value'=>'string', 'controls='=>'array'], 'new' => ['bool|int', 'ldap'=>'resource', 'dn'=>'string', 'attribute'=>'string', 'value'=>'string', 'controls='=>'?array'], ], 'ldap_delete' => [ 'old' => ['bool', 'ldap'=>'resource', 'dn'=>'string', 'controls='=>'array'], 'new' => ['bool', 'ldap'=>'resource', 'dn'=>'string', 'controls='=>'?array'], ], 'ldap_delete_ext' => [ 'old' => ['resource|false', 'ldap'=>'resource', 'dn'=>'string', 'controls='=>'array'], 'new' => ['resource|false', 'ldap'=>'resource', 'dn'=>'string', 'controls='=>'?array'], ], 'ldap_exop_passwd' => [ 'old' => ['bool|string', 'ldap'=>'resource', 'user='=>'string', 'old_password='=>'string', 'new_password='=>'string', '&w_controls='=>'array'], 'new' => ['bool|string', 'ldap'=>'resource', 'user='=>'string', 'old_password='=>'string', 'new_password='=>'string', '&w_controls='=>'array|null'], ], 'ldap_list' => [ 'old' => ['resource|false', 'ldap'=>'resource|array', 'base'=>'array|string', 'filter'=>'array|string', 'attributes='=>'array', 'attributes_only='=>'int', 'sizelimit='=>'int', 'timelimit='=>'int', 'deref='=>'int', 'controls='=>'array'], 'new' => ['resource|false', 'ldap'=>'resource|array', 'base'=>'array|string', 'filter'=>'array|string', 'attributes='=>'array', 'attributes_only='=>'int', 'sizelimit='=>'int', 'timelimit='=>'int', 'deref='=>'int', 'controls='=>'?array'], ], 'ldap_rename_ext' => [ 'old' => ['resource|false', 'ldap'=>'resource', 'dn'=>'string', 'new_rdn'=>'string', 'new_parent'=>'string', 'delete_old_rdn'=>'bool', 'controls='=>'array'], 'new' => ['resource|false', 'ldap'=>'resource', 'dn'=>'string', 'new_rdn'=>'string', 'new_parent'=>'string', 'delete_old_rdn'=>'bool', 'controls='=>'?array'], ], 'ldap_mod_add' => [ 'old' => ['bool', 'ldap'=>'resource', 'dn'=>'string', 'entry'=>'array', 'controls='=>'array'], 'new' => ['bool', 'ldap'=>'resource', 'dn'=>'string', 'entry'=>'array', 'controls='=>'?array'], ], 'ldap_mod_add_ext' => [ 'old' => ['resource|false', 'ldap'=>'resource', 'dn'=>'string', 'entry'=>'array', 'controls='=>'array'], 'new' => ['resource|false', 'ldap'=>'resource', 'dn'=>'string', 'entry'=>'array', 'controls='=>'?array'], ], 'ldap_mod_del' => [ 'old' => ['bool', 'ldap'=>'resource', 'dn'=>'string', 'entry'=>'array', 'controls='=>'array'], 'new' => ['bool', 'ldap'=>'resource', 'dn'=>'string', 'entry'=>'array', 'controls='=>'?array'], ], 'ldap_mod_del_ext' => [ 'old' => ['resource|false', 'ldap'=>'resource', 'dn'=>'string', 'entry'=>'array', 'controls='=>'array'], 'new' => ['resource|false', 'ldap'=>'resource', 'dn'=>'string', 'entry'=>'array', 'controls='=>'?array'], ], 'ldap_mod_replace' => [ 'old' => ['bool', 'ldap'=>'resource', 'dn'=>'string', 'entry'=>'array', 'controls='=>'array'], 'new' => ['bool', 'ldap'=>'resource', 'dn'=>'string', 'entry'=>'array', 'controls='=>'?array'], ], 'ldap_mod_replace_ext' => [ 'old' => ['resource|false', 'ldap'=>'resource', 'dn'=>'string', 'entry'=>'array', 'controls='=>'array'], 'new' => ['resource|false', 'ldap'=>'resource', 'dn'=>'string', 'entry'=>'array', 'controls='=>'?array'], ], 'ldap_modify' => [ 'old' => ['bool', 'ldap'=>'resource', 'dn'=>'string', 'entry'=>'array', 'controls='=>'array'], 'new' => ['bool', 'ldap'=>'resource', 'dn'=>'string', 'entry'=>'array', 'controls='=>'?array'], ], 'ldap_modify_batch' => [ 'old' => ['bool', 'ldap'=>'resource', 'dn'=>'string', 'modifications_info'=>'array', 'controls='=>'array'], 'new' => ['bool', 'ldap'=>'resource', 'dn'=>'string', 'modifications_info'=>'array', 'controls='=>'?array'], ], 'ldap_read' => [ 'old' => ['resource|false', 'ldap'=>'resource|array', 'base'=>'array|string', 'filter'=>'array|string', 'attributes='=>'array', 'attributes_only='=>'int', 'sizelimit='=>'int', 'timelimit='=>'int', 'deref='=>'int', 'controls='=>'array'], 'new' => ['resource|false', 'ldap'=>'resource|array', 'base'=>'array|string', 'filter'=>'array|string', 'attributes='=>'array', 'attributes_only='=>'int', 'sizelimit='=>'int', 'timelimit='=>'int', 'deref='=>'int', 'controls='=>'?array'], ], 'ldap_rename' => [ 'old' => ['bool', 'ldap'=>'resource', 'dn'=>'string', 'new_rdn'=>'string', 'new_parent'=>'string', 'delete_old_rdn'=>'bool', 'controls='=>'array'], 'new' => ['bool', 'ldap'=>'resource', 'dn'=>'string', 'new_rdn'=>'string', 'new_parent'=>'string', 'delete_old_rdn'=>'bool', 'controls='=>'?array'], ], 'ldap_search' => [ 'old' => ['resource[]|resource|false', 'ldap'=>'resource|resource[]', 'base'=>'array|string', 'filter'=>'array|string', 'attributes='=>'array', 'attributes_only='=>'int', 'sizelimit='=>'int', 'timelimit='=>'int', 'deref='=>'int', 'controls='=>'array'], 'new' => ['resource[]|resource|false', 'ldap'=>'resource|resource[]', 'base'=>'array|string', 'filter'=>'array|string', 'attributes='=>'array', 'attributes_only='=>'int', 'sizelimit='=>'int', 'timelimit='=>'int', 'deref='=>'int', 'controls='=>'?array'], ], 'ldap_set_rebind_proc' => [ 'old' => ['bool', 'ldap'=>'resource', 'callback'=>'callable'], 'new' => ['bool', 'ldap'=>'resource', 'callback'=>'?callable'], ], 'ldap_sasl_bind' => [ 'old' => ['bool', 'ldap'=>'resource', 'dn='=>'string', 'password='=>'string', 'mech='=>'string', 'realm='=>'string', 'authc_id='=>'string', 'authz_id='=>'string', 'props='=>'string'], 'new' => ['bool', 'ldap'=>'resource', 'dn='=>'?string', 'password='=>'?string', 'mech='=>'?string', 'realm='=>'?string', 'authc_id='=>'?string', 'authz_id='=>'?string', 'props='=>'?string'], ], 'libxml_use_internal_errors' => [ 'old' => ['bool', 'use_errors='=>'bool'], 'new' => ['bool', 'use_errors='=>'?bool'], ], 'locale_get_display_language' => [ 'old' => ['string', 'locale'=>'string', 'displayLocale='=>'string'], 'new' => ['string', 'locale'=>'string', 'displayLocale='=>'?string'], ], 'locale_get_display_name' => [ 'old' => ['string', 'locale'=>'string', 'displayLocale='=>'string'], 'new' => ['string', 'locale'=>'string', 'displayLocale='=>'?string'], ], 'locale_get_display_region' => [ 'old' => ['string', 'locale'=>'string', 'displayLocale='=>'string'], 'new' => ['string', 'locale'=>'string', 'displayLocale='=>'?string'], ], 'locale_get_display_script' => [ 'old' => ['string', 'locale'=>'string', 'displayLocale='=>'string'], 'new' => ['string', 'locale'=>'string', 'displayLocale='=>'?string'], ], 'locale_get_display_variant' => [ 'old' => ['string', 'locale'=>'string', 'displayLocale='=>'string'], 'new' => ['string', 'locale'=>'string', 'displayLocale='=>'?string'], ], 'localtime' => [ 'old' => ['array', 'timestamp='=>'int', 'associative='=>'bool'], 'new' => ['array', 'timestamp='=>'?int', 'associative='=>'bool'], ], 'mb_check_encoding' => [ 'old' => ['bool', 'value='=>'array|string', 'encoding='=>'string'], 'new' => ['bool', 'value='=>'array|string|null', 'encoding='=>'string|null'], ], 'mb_chr' => [ 'old' => ['non-empty-string|false', 'codepoint'=>'int', 'encoding='=>'string'], 'new' => ['non-empty-string|false', 'codepoint'=>'int', 'encoding='=>'string|null'], ], 'mb_convert_case' => [ 'old' => ['string', 'string'=>'string', 'mode'=>'int', 'encoding='=>'string'], 'new' => ['string', 'string'=>'string', 'mode'=>'int', 'encoding='=>'string|null'], ], 'mb_convert_encoding' => [ 'old' => ['string|false', 'string'=>'string', 'to_encoding'=>'string', 'from_encoding='=>'mixed'], 'new' => ['string|false', 'string'=>'string', 'to_encoding'=>'string', 'from_encoding='=>'array|string|null'], ], 'mb_convert_encoding\'1' => [ 'old' => ['array', 'string'=>'array', 'to_encoding'=>'string', 'from_encoding='=>'mixed'], 'new' => ['array', 'string'=>'array', 'to_encoding'=>'string', 'from_encoding='=>'array|string|null'], ], 'mb_convert_kana' => [ 'old' => ['string', 'string'=>'string', 'mode='=>'string', 'encoding='=>'string'], 'new' => ['string', 'string'=>'string', 'mode='=>'string', 'encoding='=>'string|null'], ], 'mb_decode_numericentity' => [ 'old' => ['string', 'string'=>'string', 'map'=>'array', 'encoding='=>'string'], 'new' => ['string', 'string'=>'string', 'map'=>'array', 'encoding='=>'string|null'], ], 'mb_detect_encoding' => [ 'old' => ['string|false', 'string'=>'string', 'encodings='=>'mixed', 'strict='=>'bool'], 'new' => ['string|false', 'string'=>'string', 'encodings='=>'array|string|null', 'strict='=>'bool'], ], 'mb_detect_order' => [ 'old' => ['bool|list', 'encoding='=>'mixed'], 'new' => ['bool|list', 'encoding='=>'array|string|null'], ], 'mb_encode_mimeheader' => [ 'old' => ['string', 'string'=>'string', 'charset='=>'string', 'transfer_encoding='=>'string', 'newline='=>'string', 'indent='=>'int'], 'new' => ['string', 'string'=>'string', 'charset='=>'string|null', 'transfer_encoding='=>'string|null', 'newline='=>'string', 'indent='=>'int'], ], 'mb_encode_numericentity' => [ 'old' => ['string', 'string'=>'string', 'map'=>'array', 'encoding='=>'string', 'hex='=>'bool'], 'new' => ['string', 'string'=>'string', 'map'=>'array', 'encoding='=>'string|null', 'hex='=>'bool'], ], 'mb_encoding_aliases' => [ 'old' => ['list|false', 'encoding'=>'string'], 'new' => ['list', 'encoding'=>'string'], ], 'mb_ereg' => [ 'old' => ['int|false', 'pattern'=>'string', 'string'=>'string', '&w_matches='=>'array|null'], 'new' => ['bool', 'pattern'=>'string', 'string'=>'string', '&w_matches='=>'array|null'], ], 'mb_ereg_match' => [ 'old' => ['bool', 'pattern'=>'string', 'string'=>'string', 'options='=>'string'], 'new' => ['bool', 'pattern'=>'string', 'string'=>'string', 'options='=>'string|null'], ], 'mb_ereg_replace' => [ 'old' => ['string|false', 'pattern'=>'string', 'replacement'=>'string', 'string'=>'string', 'options='=>'string'], 'new' => ['string|false|null', 'pattern'=>'string', 'replacement'=>'string', 'string'=>'string', 'options='=>'string|null'], ], 'mb_ereg_replace_callback' => [ 'old' => ['string|false|null', 'pattern'=>'string', 'callback'=>'callable', 'string'=>'string', 'options='=>'string'], 'new' => ['string|false|null', 'pattern'=>'string', 'callback'=>'callable', 'string'=>'string', 'options='=>'string|null'], ], 'mb_ereg_search' => [ 'old' => ['bool', 'pattern='=>'string', 'options='=>'string'], 'new' => ['bool', 'pattern='=>'string|null', 'options='=>'string|null'], ], 'mb_ereg_search_init' => [ 'old' => ['bool', 'string'=>'string', 'pattern='=>'string', 'options='=>'string'], 'new' => ['bool', 'string'=>'string', 'pattern='=>'string|null', 'options='=>'string|null'], ], 'mb_ereg_search_pos' => [ 'old' => ['int[]|false', 'pattern='=>'string', 'options='=>'string'], 'new' => ['int[]|false', 'pattern='=>'string|null', 'options='=>'string|null'], ], 'mb_ereg_search_regs' => [ 'old' => ['string[]|false', 'pattern='=>'string', 'options='=>'string'], 'new' => ['string[]|false', 'pattern='=>'string|null', 'options='=>'string|null'], ], 'mb_eregi' => [ 'old' => ['int|false', 'pattern'=>'string', 'string'=>'string', '&w_matches='=>'array'], 'new' => ['bool', 'pattern'=>'string', 'string'=>'string', '&w_matches='=>'array|null'], ], 'mb_eregi_replace' => [ 'old' => ['string|false', 'pattern'=>'string', 'replacement'=>'string', 'string'=>'string', 'options='=>'string'], 'new' => ['string|false|null', 'pattern'=>'string', 'replacement'=>'string', 'string'=>'string', 'options='=>'string|null'], ], 'mb_http_input' => [ 'old' => ['string|false', 'type='=>'string'], 'new' => ['array|string|false', 'type='=>'string|null'], ], 'mb_http_output' => [ 'old' => ['string|bool', 'encoding='=>'string'], 'new' => ['string|bool', 'encoding='=>'string|null'], ], 'mb_internal_encoding' => [ 'old' => ['string|bool', 'encoding='=>'string'], 'new' => ['string|bool', 'encoding='=>'string|null'], ], 'mb_language' => [ 'old' => ['string|bool', 'language='=>'string'], 'new' => ['string|bool', 'language='=>'string|null'], ], 'mb_ord' => [ 'old' => ['int|false', 'string'=>'string', 'encoding='=>'string'], 'new' => ['int|false', 'string'=>'string', 'encoding='=>'string|null'], ], 'mb_parse_str' => [ 'old' => ['bool', 'string'=>'string', '&w_result='=>'array'], 'new' => ['bool', 'string'=>'string', '&w_result'=>'array'], ], 'mb_regex_encoding' => [ 'old' => ['string|bool', 'encoding='=>'string'], 'new' => ['string|bool', 'encoding='=>'string|null'], ], 'mb_regex_set_options' => [ 'old' => ['string', 'options='=>'string'], 'new' => ['string', 'options='=>'string|null'], ], 'mb_scrub' => [ 'old' => ['string', 'string'=>'string', 'encoding='=>'string'], 'new' => ['string', 'string'=>'string', 'encoding='=>'string|null'], ], 'mb_send_mail' => [ 'old' => ['bool', 'to'=>'string', 'subject'=>'string', 'message'=>'string', 'additional_headers='=>'string|array', 'additional_params='=>'string'], 'new' => ['bool', 'to'=>'string', 'subject'=>'string', 'message'=>'string', 'additional_headers='=>'string|array', 'additional_params='=>'string|null'], ], 'mb_str_split' => [ 'old' => ['list|false', 'string'=>'string', 'length='=>'positive-int', 'encoding='=>'string'], 'new' => ['list', 'string'=>'string', 'length='=>'positive-int', 'encoding='=>'string|null'], ], 'mb_strcut' => [ 'old' => ['string', 'string'=>'string', 'start'=>'int', 'length='=>'?int', 'encoding='=>'string'], 'new' => ['string', 'string'=>'string', 'start'=>'int', 'length='=>'?int', 'encoding='=>'string|null'], ], 'mb_strimwidth' => [ 'old' => ['string', 'string'=>'string', 'start'=>'int', 'width'=>'int', 'trim_marker='=>'string', 'encoding='=>'string'], 'new' => ['string', 'string'=>'string', 'start'=>'int', 'width'=>'int', 'trim_marker='=>'string', 'encoding='=>'string|null'], ], 'mb_stripos' => [ 'old' => ['int|false', 'haystack'=>'string', 'needle'=>'string', 'offset='=>'int', 'encoding='=>'string'], 'new' => ['int|false', 'haystack'=>'string', 'needle'=>'string', 'offset='=>'int', 'encoding='=>'string|null'], ], 'mb_stristr' => [ 'old' => ['string|false', 'haystack'=>'string', 'needle'=>'string', 'before_needle='=>'bool', 'encoding='=>'string'], 'new' => ['string|false', 'haystack'=>'string', 'needle'=>'string', 'before_needle='=>'bool', 'encoding='=>'string|null'], ], 'mb_strlen' => [ 'old' => ['0|positive-int', 'string'=>'string', 'encoding='=>'string'], 'new' => ['0|positive-int', 'string'=>'string', 'encoding='=>'string|null'], ], 'mb_strpos' => [ 'old' => ['int|false', 'haystack'=>'string', 'needle'=>'string', 'offset='=>'int', 'encoding='=>'string'], 'new' => ['int|false', 'haystack'=>'string', 'needle'=>'string', 'offset='=>'int', 'encoding='=>'string|null'], ], 'mb_strrchr' => [ 'old' => ['string|false', 'haystack'=>'string', 'needle'=>'string', 'before_needle='=>'bool', 'encoding='=>'string'], 'new' => ['string|false', 'haystack'=>'string', 'needle'=>'string', 'before_needle='=>'bool', 'encoding='=>'string|null'], ], 'mb_strrichr' => [ 'old' => ['string|false', 'haystack'=>'string', 'needle'=>'string', 'before_needle='=>'bool', 'encoding='=>'string'], 'new' => ['string|false', 'haystack'=>'string', 'needle'=>'string', 'before_needle='=>'bool', 'encoding='=>'string|null'], ], 'mb_strripos' => [ 'old' => ['int|false', 'haystack'=>'string', 'needle'=>'string', 'offset='=>'int', 'encoding='=>'string'], 'new' => ['int|false', 'haystack'=>'string', 'needle'=>'string', 'offset='=>'int', 'encoding='=>'string|null'], ], 'mb_strrpos' => [ 'old' => ['int|false', 'haystack'=>'string', 'needle'=>'string', 'offset='=>'int', 'encoding='=>'string'], 'new' => ['int|false', 'haystack'=>'string', 'needle'=>'string', 'offset='=>'int', 'encoding='=>'string|null'], ], 'mb_strstr' => [ 'old' => ['string|false', 'haystack'=>'string', 'needle'=>'string', 'before_needle='=>'bool', 'encoding='=>'string'], 'new' => ['string|false', 'haystack'=>'string', 'needle'=>'string', 'before_needle='=>'bool', 'encoding='=>'string|null'], ], 'mb_strtolower' => [ 'old' => ['lowercase-string', 'string'=>'string', 'encoding='=>'string'], 'new' => ['lowercase-string', 'string'=>'string', 'encoding='=>'string|null'], ], 'mb_strtoupper' => [ 'old' => ['string', 'string'=>'string', 'encoding='=>'string'], 'new' => ['string', 'string'=>'string', 'encoding='=>'string|null'], ], 'mb_strwidth' => [ 'old' => ['int', 'string'=>'string', 'encoding='=>'string'], 'new' => ['int', 'string'=>'string', 'encoding='=>'string|null'], ], 'mb_substitute_character' => [ 'old' => ['bool|int|string', 'substitute_character='=>'mixed'], 'new' => ['bool|int|string', 'substitute_character='=>'int|string|null'], ], 'mb_substr' => [ 'old' => ['string', 'string'=>'string', 'start'=>'int', 'length='=>'?int', 'encoding='=>'string'], 'new' => ['string', 'string'=>'string', 'start'=>'int', 'length='=>'?int', 'encoding='=>'string|null'], ], 'mb_substr_count' => [ 'old' => ['int', 'haystack'=>'string', 'needle'=>'string', 'encoding='=>'string'], 'new' => ['int', 'haystack'=>'string', 'needle'=>'string', 'encoding='=>'string|null'], ], 'metaphone' => [ 'old' => ['string|false', 'string'=>'string', 'max_phonemes='=>'int'], 'new' => ['string', 'string'=>'string', 'max_phonemes='=>'int'], ], 'mhash' => [ 'old' => ['string', 'algo'=>'int', 'data'=>'string', 'key='=>'string'], 'new' => ['string', 'algo'=>'int', 'data'=>'string', 'key='=>'?string'], ], 'mktime' => [ 'old' => ['int|false', 'hour='=>'int', 'minute='=>'int', 'second='=>'int', 'month='=>'int', 'day='=>'int', 'year='=>'int'], 'new' => ['int|false', 'hour'=>'int', 'minute='=>'int|null', 'second='=>'int|null', 'month='=>'int|null', 'day='=>'int|null', 'year='=>'int|null'], ], 'msg_get_queue' => [ 'old' => ['resource|false', 'key'=>'int', 'permissions='=>'int'], 'new' => ['SysvMessageQueue|false', 'key'=>'int', 'permissions='=>'int'], ], 'msg_receive' => [ 'old' => ['bool', 'queue'=>'resource', 'desired_message_type'=>'int', '&w_received_message_type'=>'int', 'max_message_size'=>'int', '&w_message'=>'mixed', 'unserialize='=>'bool', 'flags='=>'int', '&w_error_code='=>'int'], 'new' => ['bool', 'queue'=>'SysvMessageQueue', 'desired_message_type'=>'int', '&w_received_message_type'=>'int', 'max_message_size'=>'int', '&w_message'=>'mixed', 'unserialize='=>'bool', 'flags='=>'int', '&w_error_code='=>'int'], ], 'msg_remove_queue' => [ 'old' => ['bool', 'queue'=>'resource'], 'new' => ['bool', 'queue'=>'SysvMessageQueue'], ], 'msg_send' => [ 'old' => ['bool', 'queue'=>'resource', 'message_type'=>'int', 'message'=>'mixed', 'serialize='=>'bool', 'blocking='=>'bool', '&w_error_code='=>'int'], 'new' => ['bool', 'queue'=>'SysvMessageQueue', 'message_type'=>'int', 'message'=>'mixed', 'serialize='=>'bool', 'blocking='=>'bool', '&w_error_code='=>'int'], ], 'msg_set_queue' => [ 'old' => ['bool', 'queue'=>'resource', 'data'=>'array'], 'new' => ['bool', 'queue'=>'SysvMessageQueue', 'data'=>'array'], ], 'msg_stat_queue' => [ 'old' => ['array', 'queue'=>'resource'], 'new' => ['array', 'queue'=>'SysvMessageQueue'], ], 'mysqli::__construct' => [ 'old' => ['void', 'hostname='=>'string', 'username='=>'string', 'password='=>'string', 'database='=>'string', 'port='=>'int', 'socket='=>'string'], 'new' => ['void', 'hostname='=>'string|null', 'username='=>'string|null', 'password='=>'string|null', 'database='=>'string|null', 'port='=>'int|null', 'socket='=>'string|null'], ], 'mysqli::begin_transaction' => [ 'old' => ['bool', 'flags='=>'int', 'name='=>'string'], 'new' => ['bool', 'flags='=>'int', 'name='=>'?string'], ], 'mysqli::commit' => [ 'old' => ['bool', 'flags='=>'int', 'name='=>'string'], 'new' => ['bool', 'flags='=>'int', 'name='=>'?string'], ], 'mysqli::connect' => [ 'old' => ['null|false', 'hostname='=>'string', 'username='=>'string', 'password='=>'string', 'database='=>'string', 'port='=>'int', 'socket='=>'string'], 'new' => ['null|false', 'hostname='=>'string|null', 'username='=>'string|null', 'password='=>'string|null', 'database='=>'string|null', 'port='=>'int|null', 'socket='=>'string|null'], ], 'mysqli::rollback' => [ 'old' => ['bool', 'flags='=>'int', 'name='=>'string'], 'new' => ['bool', 'flags='=>'int', 'name='=>'?string'], ], 'mysqli_begin_transaction' => [ 'old' => ['bool', 'mysql'=>'mysqli', 'flags='=>'int', 'name='=>'string'], 'new' => ['bool', 'mysql'=>'mysqli', 'flags='=>'int', 'name='=>'?string'], ], 'mysqli_commit' => [ 'old' => ['bool', 'mysql'=>'mysqli', 'flags='=>'int', 'name='=>'string'], 'new' => ['bool', 'mysql'=>'mysqli', 'flags='=>'int', 'name='=>'?string'], ], 'mysqli_connect' => [ 'old' => ['mysqli|false', 'hostname='=>'string', 'username='=>'string', 'password='=>'string', 'database='=>'string', 'port='=>'int', 'socket='=>'string'], 'new' => ['mysqli|false', 'hostname='=>'string|null', 'username='=>'string|null', 'password='=>'string|null', 'database='=>'string|null', 'port='=>'int|null', 'socket='=>'string|null'], ], 'mysqli_rollback' => [ 'old' => ['bool', 'mysql'=>'mysqli', 'flags='=>'int', 'name='=>'string'], 'new' => ['bool', 'mysql'=>'mysqli', 'flags='=>'int', 'name='=>'?string'], ], 'number_format' => [ 'old' => ['string', 'num'=>'float', 'decimals='=>'int'], 'new' => ['string', 'num'=>'float', 'decimals='=>'int', 'decimal_separator='=>'?string', 'thousands_separator='=>'?string'], ], 'numfmt_create' => [ 'old' => ['NumberFormatter|null', 'locale'=>'string', 'style'=>'int', 'pattern='=>'string'], 'new' => ['NumberFormatter|null', 'locale'=>'string', 'style'=>'int', 'pattern='=>'?string'], ], 'ob_implicit_flush' => [ 'old' => ['void', 'enable='=>'int'], 'new' => ['void', 'enable='=>'bool'], ], 'odbc_exec' => [ 'old' => ['resource', 'odbc'=>'resource', 'query'=>'string', 'flags='=>'int'], 'new' => ['resource', 'odbc'=>'resource', 'query'=>'string'], ], 'odbc_fetch_row' => [ 'old' => ['bool', 'statement'=>'resource', 'row='=>'int'], 'new' => ['bool', 'statement'=>'resource', 'row='=>'?int'], ], 'odbc_do' => [ 'old' => ['resource', 'odbc'=>'resource', 'query'=>'string', 'flags='=>'int'], 'new' => ['resource', 'odbc'=>'resource', 'query'=>'string'], ], 'odbc_tables' => [ 'old' => ['resource|false', 'odbc'=>'resource', 'catalog='=>'?string', 'schema='=>'string', 'table='=>'string', 'types='=>'string'], 'new' => ['resource|false', 'odbc'=>'resource', 'catalog='=>'?string', 'schema='=>'?string', 'table='=>'?string', 'types='=>'?string'], ], 'openssl_csr_export' => [ 'old' => ['bool', 'csr'=>'string|resource', '&w_output'=>'string', 'no_text='=>'bool'], 'new' => ['bool', 'csr'=>'OpenSSLCertificateSigningRequest|string', '&w_output'=>'string', 'no_text='=>'bool'], ], 'openssl_csr_export_to_file' => [ 'old' => ['bool', 'csr'=>'string|resource', 'output_filename'=>'string', 'no_text='=>'bool'], 'new' => ['bool', 'csr'=>'OpenSSLCertificateSigningRequest|string', 'output_filename'=>'string', 'no_text='=>'bool'], ], 'openssl_csr_get_public_key' => [ 'old' => ['resource|false', 'csr'=>'string|resource', 'short_names='=>'bool'], 'new' => ['OpenSSLAsymmetricKey|false', 'csr'=>'OpenSSLCertificateSigningRequest|string', 'short_names='=>'bool'], ], 'openssl_csr_get_subject' => [ 'old' => ['array|false', 'csr'=>'string|resource', 'short_names='=>'bool'], 'new' => ['array|false', 'csr'=>'OpenSSLCertificateSigningRequest|string', 'short_names='=>'bool'], ], 'openssl_csr_new' => [ 'old' => ['resource|false', 'distinguished_names'=>'array', '&w_private_key'=>'resource', 'options='=>'array', 'extra_attributes='=>'array'], 'new' => ['OpenSSLCertificateSigningRequest|false', 'distinguished_names'=>'array', '&w_private_key'=>'OpenSSLAsymmetricKey', 'options='=>'array|null', 'extra_attributes='=>'array|null'], ], 'openssl_csr_sign' => [ 'old' => ['resource|false', 'csr'=>'string|resource', 'ca_certificate'=>'string|resource|null', 'private_key'=>'string|resource|array', 'days'=>'int', 'options='=>'array', 'serial='=>'int'], 'new' => ['OpenSSLCertificate|false', 'csr'=>'OpenSSLCertificateSigningRequest|string', 'ca_certificate'=>'OpenSSLCertificate|string|null', 'private_key'=>'OpenSSLAsymmetricKey|OpenSSLCertificate|array{OpenSSLAsymmetricKey|OpenSSLCertificate|string, string}|string', 'days'=>'int', 'options='=>'array|null', 'serial='=>'int'], ], 'openssl_dh_compute_key' => [ 'old' => ['string|false', 'public_key'=>'string', 'private_key'=>'resource'], 'new' => ['string|false', 'public_key'=>'string', 'private_key'=>'OpenSSLAsymmetricKey'], ], 'openssl_free_key' => [ 'old' => ['void', 'key'=>'resource'], 'new' => ['void', 'key'=>'OpenSSLAsymmetricKey'], ], 'openssl_get_privatekey' => [ 'old' => ['resource|false', 'private_key'=>'string', 'passphrase='=>'string'], 'new' => ['OpenSSLAsymmetricKey|false', 'private_key'=>'OpenSSLAsymmetricKey|OpenSSLCertificate|array{OpenSSLAsymmetricKey|OpenSSLCertificate|string, string}|string', 'passphrase='=>'?string'], ], 'openssl_get_publickey' => [ 'old' => ['resource|false', 'public_key'=>'resource|string'], 'new' => ['OpenSSLAsymmetricKey|false', 'public_key'=>'OpenSSLAsymmetricKey|OpenSSLCertificate|array{OpenSSLAsymmetricKey|OpenSSLCertificate|string, string}|string'], ], 'openssl_open' => [ 'old' => ['bool', 'data'=>'string', '&w_output'=>'string', 'encrypted_key'=>'string', 'private_key'=>'string|array|resource', 'cipher_algo='=>'string', 'iv='=>'string'], 'new' => ['bool', 'data'=>'string', '&w_output'=>'string', 'encrypted_key'=>'string', 'private_key'=>'OpenSSLAsymmetricKey|OpenSSLCertificate|array{OpenSSLAsymmetricKey|OpenSSLCertificate|string, string}|string', 'cipher_algo'=>'string', 'iv='=>'string|null'], ], 'openssl_pkcs12_export' => [ 'old' => ['bool', 'certificate'=>'string|resource', '&w_output'=>'string', 'private_key'=>'string|array|resource', 'passphrase'=>'string', 'options='=>'array'], 'new' => ['bool', 'certificate'=>'OpenSSLCertificate|string', '&w_output'=>'string', 'private_key'=>'OpenSSLAsymmetricKey|OpenSSLCertificate|array{OpenSSLAsymmetricKey|OpenSSLCertificate|string, string}|string', 'passphrase'=>'string', 'options='=>'array'], ], 'openssl_pkcs12_export_to_file' => [ 'old' => ['bool', 'certificate'=>'string|resource', 'output_filename'=>'string', 'private_key'=>'string|array|resource', 'passphrase'=>'string', 'options='=>'array'], 'new' => ['bool', 'certificate'=>'OpenSSLCertificate|string', 'output_filename'=>'string', 'private_key'=>'OpenSSLAsymmetricKey|OpenSSLCertificate|array{OpenSSLAsymmetricKey|OpenSSLCertificate|string, string}|string', 'passphrase'=>'string', 'options='=>'array'], ], 'openssl_pkcs7_decrypt' => [ 'old' => ['bool', 'input_filename'=>'string', 'output_filename'=>'string', 'certificate'=>'string|resource', 'private_key='=>'string|resource|array'], 'new' => ['bool', 'input_filename'=>'string', 'output_filename'=>'string', 'certificate'=>'OpenSSLCertificate|string', 'private_key='=>'OpenSSLAsymmetricKey|OpenSSLCertificate|array{OpenSSLAsymmetricKey|OpenSSLCertificate|string, string}|string|null'], ], 'openssl_pkcs7_encrypt' => [ 'old' => ['bool', 'input_filename'=>'string', 'output_filename'=>'string', 'certificate'=>'string|resource|array', 'headers'=>'array', 'flags='=>'int', 'cipher_algo='=>'int'], 'new' => ['bool', 'input_filename'=>'string', 'output_filename'=>'string', 'certificate'=>'OpenSSLCertificate|list|string', 'headers'=>'array|null', 'flags='=>'int', 'cipher_algo='=>'int'], ], 'openssl_pkcs7_sign' => [ 'old' => ['bool', 'input_filename'=>'string', 'output_filename'=>'string', 'certificate'=>'string|resource', 'private_key'=>'string|resource|array', 'headers'=>'array', 'flags='=>'int', 'untrusted_certificates_filename='=>'string'], 'new' => ['bool', 'input_filename'=>'string', 'output_filename'=>'string', 'certificate'=>'OpenSSLCertificate|string', 'private_key'=>'OpenSSLAsymmetricKey|OpenSSLCertificate|array{OpenSSLAsymmetricKey|OpenSSLCertificate|string, string}|string', 'headers'=>'array|null', 'flags='=>'int', 'untrusted_certificates_filename='=>'string|null'], ], 'openssl_pkcs7_verify' => [ 'old' => ['bool|int', 'input_filename'=>'string', 'flags'=>'int', 'signers_certificates_filename='=>'string', 'ca_info='=>'array', 'untrusted_certificates_filename='=>'string', 'content='=>'string', 'output_filename='=>'string'], 'new' => ['bool|int', 'input_filename'=>'string', 'flags'=>'int', 'signers_certificates_filename='=>'?string', 'ca_info='=>'array', 'untrusted_certificates_filename='=>'?string', 'content='=>'?string', 'output_filename='=>'?string'], ], 'openssl_pkey_derive' => [ 'old' => ['string|false', 'public_key'=>'mixed', 'private_key'=>'mixed', 'key_length='=>'?int'], 'new' => ['string|false', 'public_key'=>'OpenSSLAsymmetricKey|OpenSSLCertificate|array{OpenSSLAsymmetricKey|OpenSSLCertificate|string, string}|string', 'private_key'=>'OpenSSLAsymmetricKey|OpenSSLCertificate|array{OpenSSLAsymmetricKey|OpenSSLCertificate|string, string}|string', 'key_length='=>'int'], ], 'openssl_pkey_export' => [ 'old' => ['bool', 'key'=>'resource', '&w_output'=>'string', 'passphrase='=>'string|null', 'options='=>'array'], 'new' => ['bool', 'key'=>'OpenSSLAsymmetricKey|OpenSSLCertificate|array{OpenSSLAsymmetricKey|OpenSSLCertificate|string, string}|string', '&w_output'=>'string', 'passphrase='=>'string|null', 'options='=>'array|null'], ], 'openssl_pkey_export_to_file' => [ 'old' => ['bool', 'key'=>'resource|string|array', 'output_filename'=>'string', 'passphrase='=>'string|null', 'options='=>'array'], 'new' => ['bool', 'key'=>'OpenSSLAsymmetricKey|OpenSSLCertificate|array{OpenSSLAsymmetricKey|OpenSSLCertificate|string, string}|string', 'output_filename'=>'string', 'passphrase='=>'string|null', 'options='=>'array|null'], ], 'openssl_pkey_free' => [ 'old' => ['void', 'key'=>'resource'], 'new' => ['void', 'key'=>'OpenSSLAsymmetricKey'], ], 'openssl_pkey_get_details' => [ 'old' => ['array|false', 'key'=>'resource'], 'new' => ['array|false', 'key'=>'OpenSSLAsymmetricKey'], ], 'openssl_pkey_get_private' => [ 'old' => ['resource|false', 'private_key'=>'string', 'passphrase='=>'string'], 'new' => ['OpenSSLAsymmetricKey|false', 'private_key'=>'OpenSSLAsymmetricKey|OpenSSLCertificate|array|string', 'passphrase='=>'?string'], ], 'openssl_pkey_get_public' => [ 'old' => ['resource|false', 'public_key'=>'resource|string'], 'new' => ['OpenSSLAsymmetricKey|false', 'public_key'=>'OpenSSLAsymmetricKey|OpenSSLCertificate|array{OpenSSLAsymmetricKey|OpenSSLCertificate|string, string}|string'], ], 'openssl_pkey_new' => [ 'old' => ['resource|false', 'options='=>'array'], 'new' => ['OpenSSLAsymmetricKey|false', 'options='=>'array|null'], ], 'openssl_private_decrypt' => [ 'old' => ['bool', 'data'=>'string', '&w_decrypted_data'=>'string', 'private_key'=>'string|resource|array', 'padding='=>'int'], 'new' => ['bool', 'data'=>'string', '&w_decrypted_data'=>'string', 'private_key'=>'OpenSSLAsymmetricKey|OpenSSLCertificate|array{OpenSSLAsymmetricKey|OpenSSLCertificate|string, string}|string', 'padding='=>'int'], ], 'openssl_private_encrypt' => [ 'old' => ['bool', 'data'=>'string', '&w_encrypted_data'=>'string', 'private_key'=>'string|resource|array', 'padding='=>'int'], 'new' => ['bool', 'data'=>'string', '&w_encrypted_data'=>'string', 'private_key'=>'OpenSSLAsymmetricKey|OpenSSLCertificate|array{OpenSSLAsymmetricKey|OpenSSLCertificate|string, string}|string', 'padding='=>'int'], ], 'openssl_public_decrypt' => [ 'old' => ['bool', 'data'=>'string', '&w_decrypted_data'=>'string', 'public_key'=>'string|resource', 'padding='=>'int'], 'new' => ['bool', 'data'=>'string', '&w_decrypted_data'=>'string', 'public_key'=>'OpenSSLAsymmetricKey|OpenSSLCertificate|array{OpenSSLAsymmetricKey|OpenSSLCertificate|string, string}|string', 'padding='=>'int'], ], 'openssl_public_encrypt' => [ 'old' => ['bool', 'data'=>'string', '&w_encrypted_data'=>'string', 'public_key'=>'string|resource', 'padding='=>'int'], 'new' => ['bool', 'data'=>'string', '&w_encrypted_data'=>'string', 'public_key'=>'OpenSSLAsymmetricKey|OpenSSLCertificate|array{OpenSSLAsymmetricKey|OpenSSLCertificate|string, string}|string', 'padding='=>'int'], ], 'openssl_seal' => [ 'old' => ['int|false', 'data'=>'string', '&w_sealed_data'=>'string', '&w_encrypted_keys'=>'array', 'public_key'=>'array', 'cipher_algo='=>'string', '&rw_iv='=>'string'], 'new' => ['int|false', 'data'=>'string', '&w_sealed_data'=>'string', '&w_encrypted_keys'=>'array', 'public_key'=>'list', 'cipher_algo'=>'string', '&rw_iv='=>'string'], ], 'openssl_sign' => [ 'old' => ['bool', 'data'=>'string', '&w_signature'=>'string', 'private_key'=>'resource|string', 'algorithm='=>'int|string'], 'new' => ['bool', 'data'=>'string', '&w_signature'=>'string', 'private_key'=>'OpenSSLAsymmetricKey|OpenSSLCertificate|array{OpenSSLAsymmetricKey|OpenSSLCertificate|string, string}|string', 'algorithm='=>'int|string'], ], 'openssl_spki_new' => [ 'old' => ['?string', 'private_key'=>'resource', 'challenge'=>'string', 'digest_algo='=>'int'], 'new' => ['string|false', 'private_key'=>'OpenSSLAsymmetricKey', 'challenge'=>'string', 'digest_algo='=>'int'], ], 'openssl_verify' => [ 'old' => ['-1|0|1', 'data'=>'string', 'signature'=>'string', 'public_key'=>'resource|string', 'algorithm='=>'int|string'], 'new' => ['-1|0|1|false', 'data'=>'string', 'signature'=>'string', 'public_key'=>'OpenSSLAsymmetricKey|OpenSSLCertificate|array{OpenSSLAsymmetricKey|OpenSSLCertificate|string, string}|string', 'algorithm='=>'int|string'], ], 'openssl_x509_check_private_key' => [ 'old' => ['bool', 'certificate'=>'string|resource', 'private_key'=>'string|resource|array'], 'new' => ['bool', 'certificate'=>'OpenSSLCertificate|string', 'private_key'=>'OpenSSLAsymmetricKey|OpenSSLCertificate|array{OpenSSLAsymmetricKey|OpenSSLCertificate|string, string}|string'], ], 'openssl_x509_checkpurpose' => [ 'old' => ['bool|int', 'certificate'=>'string|resource', 'purpose'=>'int', 'ca_info='=>'array', 'untrusted_certificates_file='=>'string'], 'new' => ['bool|int', 'certificate'=>'OpenSSLCertificate|string', 'purpose'=>'int', 'ca_info='=>'array', 'untrusted_certificates_file='=>'string|null'], ], 'openssl_x509_export' => [ 'old' => ['bool', 'certificate'=>'string|resource', '&w_output'=>'string', 'no_text='=>'bool'], 'new' => ['bool', 'certificate'=>'OpenSSLCertificate|string', '&w_output'=>'string', 'no_text='=>'bool'], ], 'openssl_x509_export_to_file' => [ 'old' => ['bool', 'certificate'=>'string|resource', 'output_filename'=>'string', 'no_text='=>'bool'], 'new' => ['bool', 'certificate'=>'OpenSSLCertificate|string', 'output_filename'=>'string', 'no_text='=>'bool'], ], 'openssl_x509_fingerprint' => [ 'old' => ['string|false', 'certificate'=>'string|resource', 'digest_algo='=>'string', 'binary='=>'bool'], 'new' => ['string|false', 'certificate'=>'OpenSSLCertificate|string', 'digest_algo='=>'string', 'binary='=>'bool'], ], 'openssl_x509_free' => [ 'old' => ['void', 'certificate'=>'resource'], 'new' => ['void', 'certificate'=>'OpenSSLCertificate'], ], 'openssl_x509_parse' => [ 'old' => ['array|false', 'certificate'=>'string|resource', 'short_names='=>'bool'], 'new' => ['array|false', 'certificate'=>'OpenSSLCertificate|string', 'short_names='=>'bool'], ], 'openssl_x509_read' => [ 'old' => ['resource|false', 'certificate'=>'string|resource'], 'new' => ['OpenSSLCertificate|false', 'certificate'=>'OpenSSLCertificate|string'], ], 'openssl_x509_verify' => [ 'old' => ['int', 'certificate'=>'string|resource', 'public_key'=>'string|array|resource'], 'new' => ['int', 'certificate'=>'string|OpenSSLCertificate', 'public_key'=>'string|OpenSSLCertificate|OpenSSLAsymmetricKey|array'], ], 'pack' => [ 'old' => ['string|false', 'format'=>'string', '...values='=>'mixed'], 'new' => ['string', 'format'=>'string', '...values='=>'mixed'], ], 'parse_str' => [ 'old' => ['void', 'string'=>'string', '&w_result='=>'array'], 'new' => ['void', 'string'=>'string', '&w_result'=>'array'], ], 'password_hash' => [ 'old' => ['string|false', 'password'=>'string', 'algo'=>'int|string|null', 'options='=>'array'], 'new' => ['string', 'password'=>'string', 'algo'=>'int|string|null', 'options='=>'array'], ], 'pcntl_async_signals' => [ 'old' => ['bool', 'enable='=>'bool'], 'new' => ['bool', 'enable='=>'?bool'], ], 'pcntl_exec' => [ 'old' => ['null|false', 'path'=>'string', 'args='=>'array', 'env_vars='=>'array'], 'new' => ['false', 'path'=>'string', 'args='=>'array', 'env_vars='=>'array'], ], 'pcntl_getpriority' => [ 'old' => ['int', 'process_id='=>'int', 'mode='=>'int'], 'new' => ['int', 'process_id='=>'?int', 'mode='=>'int'], ], 'pcntl_setpriority' => [ 'old' => ['bool', 'priority'=>'int', 'process_id='=>'int', 'mode='=>'int'], 'new' => ['bool', 'priority'=>'int', 'process_id='=>'?int', 'mode='=>'int'], ], 'pfsockopen' => [ 'old' => ['resource|false', 'hostname'=>'string', 'port='=>'int', '&w_error_code='=>'int', '&w_error_message='=>'string', 'timeout='=>'float'], 'new' => ['resource|false', 'hostname'=>'string', 'port='=>'int', '&w_error_code='=>'int', '&w_error_message='=>'string', 'timeout='=>'?float'], ], 'pg_client_encoding' => [ 'old' => ['string', 'connection='=>'resource'], 'new' => ['string', 'connection='=>'?resource'], ], 'pg_close' => [ 'old' => ['bool', 'connection='=>'resource'], 'new' => ['bool', 'connection='=>'?resource'], ], 'pg_dbname' => [ 'old' => ['string', 'connection='=>'resource'], 'new' => ['string', 'connection='=>'?resource'], ], 'pg_end_copy' => [ 'old' => ['bool', 'connection='=>'resource'], 'new' => ['bool', 'connection='=>'?resource'], ], 'pg_last_error' => [ 'old' => ['string', 'connection='=>'resource'], 'new' => ['string', 'connection='=>'?resource'], ], 'pg_lo_write' => [ 'old' => ['int|false', 'lob'=>'resource', 'data'=>'string', 'length='=>'int'], 'new' => ['int|false', 'lob'=>'resource', 'data'=>'string', 'length='=>'?int'], ], 'pg_options' => [ 'old' => ['string', 'connection='=>'resource'], 'new' => ['string', 'connection='=>'?resource'], ], 'pg_ping' => [ 'old' => ['bool', 'connection='=>'resource'], 'new' => ['bool', 'connection='=>'?resource'], ], 'pg_port' => [ 'old' => ['string', 'connection='=>'resource'], 'new' => ['string', 'connection='=>'?resource'], ], 'pg_trace' => [ 'old' => ['bool', 'filename'=>'string', 'mode='=>'string', 'connection='=>'resource'], 'new' => ['bool', 'filename'=>'string', 'mode='=>'string', 'connection='=>'?resource'], ], 'pg_tty' => [ 'old' => ['string', 'connection='=>'resource'], 'new' => ['string', 'connection='=>'?resource'], ], 'pg_untrace' => [ 'old' => ['bool', 'connection='=>'resource'], 'new' => ['bool', 'connection='=>'?resource'], ], 'pg_version' => [ 'old' => ['array', 'connection='=>'resource'], 'new' => ['array', 'connection='=>'?resource'], ], 'phpversion' => [ 'old' => ['string|false', 'extension='=>'string'], 'new' => ['string|false', 'extension='=>'?string'], ], 'proc_get_status' => [ 'old' => ['array{command: string, pid: int, running: bool, signaled: bool, stopped: bool, exitcode: int, termsig: int, stopsig: int}|false', 'process'=>'resource'], 'new' => ['array{command: string, pid: int, running: bool, signaled: bool, stopped: bool, exitcode: int, termsig: int, stopsig: int}', 'process'=>'resource'], ], 'readline_info' => [ 'old' => ['mixed', 'var_name='=>'string', 'value='=>'string|int|bool'], 'new' => ['mixed', 'var_name='=>'?string', 'value='=>'string|int|bool|null'], ], 'readline_read_history' => [ 'old'=> ['bool', 'filename='=>'string'], 'new'=> ['bool', 'filename='=>'?string'], ], 'readline_write_history' => [ 'old' => ['bool', 'filename='=>'string'], 'new' => ['bool', 'filename='=>'?string'], ], 'sapi_windows_vt100_support' => [ 'old' => ['bool', 'stream'=>'resource', 'enable='=>'bool'], 'new' => ['bool', 'stream'=>'resource', 'enable='=>'?bool'], ], 'sem_acquire' => [ 'old' => ['bool', 'semaphore'=>'resource', 'non_blocking='=>'bool'], 'new' => ['bool', 'semaphore'=>'SysvSemaphore', 'non_blocking='=>'bool'], ], 'sem_get' => [ 'old' => ['resource|false', 'key'=>'int', 'max_acquire='=>'int', 'permissions='=>'int', 'auto_release='=>'bool'], 'new' => ['SysvSemaphore|false', 'key'=>'int', 'max_acquire='=>'int', 'permissions='=>'int', 'auto_release='=>'bool'], ], 'sem_release' => [ 'old' => ['bool', 'semaphore'=>'resource'], 'new' => ['bool', 'semaphore'=>'SysvSemaphore'], ], 'sem_remove' => [ 'old' => ['bool', 'semaphore'=>'resource'], 'new' => ['bool', 'semaphore'=>'SysvSemaphore'], ], 'session_cache_expire' => [ 'old' => ['int|false', 'value='=>'int'], 'new' => ['int|false', 'value='=>'?int'], ], 'session_cache_limiter' => [ 'old' => ['string|false', 'value='=>'string'], 'new' => ['string|false', 'value='=>'?string'], ], 'session_id' => [ 'old' => ['string|false', 'id='=>'string'], 'new' => ['string|false', 'id='=>'?string'], ], 'session_module_name' => [ 'old' => ['string|false', 'module='=>'string'], 'new' => ['string|false', 'module='=>'?string'], ], 'session_name' => [ 'old' => ['string|false', 'name='=>'string'], 'new' => ['string|false', 'name='=>'?string'], ], 'session_save_path' => [ 'old' => ['string|false', 'path='=>'string'], 'new' => ['string|false', 'path='=>'?string'], ], 'session_set_cookie_params' => [ 'old' => ['bool', 'lifetime'=>'int', 'path='=>'string', 'domain='=>'string', 'secure='=>'bool', 'httponly='=>'bool'], 'new' => ['bool', 'lifetime'=>'int', 'path='=>'?string', 'domain='=>'?string', 'secure='=>'?bool', 'httponly='=>'?bool'], ], 'shm_attach' => [ 'old' => ['resource|false', 'key'=>'int', 'size='=>'int', 'permissions='=>'int'], 'new' => ['SysvSharedMemory|false', 'key'=>'int', 'size='=>'?int', 'permissions='=>'int'], ], 'shm_detach' => [ 'old' => ['bool', 'shm'=>'resource'], 'new' => ['bool', 'shm'=>'SysvSharedMemory'], ], 'shm_get_var' => [ 'old' => ['mixed', 'shm'=>'resource', 'key'=>'int'], 'new' => ['mixed', 'shm'=>'SysvSharedMemory', 'key'=>'int'], ], 'shm_has_var' => [ 'old' => ['bool', 'shm'=>'resource', 'key'=>'int'], 'new' => ['bool', 'shm'=>'SysvSharedMemory', 'key'=>'int'], ], 'shm_put_var' => [ 'old' => ['bool', 'shm'=>'resource', 'key'=>'int', 'value'=>'mixed'], 'new' => ['bool', 'shm'=>'SysvSharedMemory', 'key'=>'int', 'value'=>'mixed'], ], 'shm_remove' => [ 'old' => ['bool', 'shm'=>'resource'], 'new' => ['bool', 'shm'=>'SysvSharedMemory'], ], 'shm_remove_var' => [ 'old' => ['bool', 'shm'=>'resource', 'key'=>'int'], 'new' => ['bool', 'shm'=>'SysvSharedMemory', 'key'=>'int'], ], 'shmop_close' => [ 'old' => ['void', 'shmop'=>'resource'], 'new' => ['void', 'shmop'=>'Shmop'], ], 'shmop_delete' => [ 'old' => ['bool', 'shmop'=>'resource'], 'new' => ['bool', 'shmop'=>'Shmop'], ], 'shmop_open' => [ 'old' => ['resource|false', 'key'=>'int', 'mode'=>'string', 'permissions'=>'int', 'size'=>'int'], 'new' => ['Shmop|false', 'key'=>'int', 'mode'=>'string', 'permissions'=>'int', 'size'=>'int'], ], 'shmop_read' => [ 'old' => ['string|false', 'shmop'=>'resource', 'offset'=>'int', 'size'=>'int'], 'new' => ['string', 'shmop'=>'Shmop', 'offset'=>'int', 'size'=>'int'], ], 'shmop_size' => [ 'old' => ['int', 'shmop'=>'resource'], 'new' => ['int', 'shmop'=>'Shmop'], ], 'shmop_write' => [ 'old' => ['int|false', 'shmop'=>'resource', 'data'=>'string', 'offset'=>'int'], 'new' => ['int', 'shmop'=>'Shmop', 'data'=>'string', 'offset'=>'int'], ], 'sleep' => [ 'old' => ['int|false', 'seconds'=>'0|positive-int'], 'new' => ['int', 'seconds'=>'0|positive-int'], ], 'socket_accept' => [ 'old' => ['resource|false', 'socket'=>'resource'], 'new' => ['Socket|false', 'socket'=>'Socket'], ], 'socket_addrinfo_bind' => [ 'old' => ['?resource', 'addrinfo'=>'resource'], 'new' => ['Socket|false', 'address'=>'AddressInfo'], ], 'socket_addrinfo_connect' => [ 'old' => ['resource', 'addrinfo'=>'resource'], 'new' => ['Socket|false', 'address'=>'AddressInfo'], ], 'socket_addrinfo_explain' => [ 'old' => ['array', 'addrinfo'=>'resource'], 'new' => ['array', 'address'=>'AddressInfo'], ], 'socket_addrinfo_lookup' => [ 'old' => ['resource[]', 'host'=>'string', 'service='=>'string', 'hints='=>'array'], 'new' => ['false|AddressInfo[]', 'host'=>'string', 'service='=>'?string', 'hints='=>'array'], ], 'socket_bind' => [ 'old' => ['bool', 'socket'=>'resource', 'address'=>'string', 'port='=>'int'], 'new' => ['bool', 'socket'=>'Socket', 'address'=>'string', 'port='=>'int'], ], 'socket_clear_error' => [ 'old' => ['void', 'socket='=>'resource'], 'new' => ['void', 'socket='=>'?Socket'], ], 'socket_close' => [ 'old' => ['void', 'socket'=>'resource'], 'new' => ['void', 'socket'=>'Socket'], ], 'socket_connect' => [ 'old' => ['bool', 'socket'=>'resource', 'address'=>'string', 'port='=>'int'], 'new' => ['bool', 'socket'=>'Socket', 'address'=>'string', 'port='=>'?int'], ], 'socket_create' => [ 'old' => ['resource|false', 'domain'=>'int', 'type'=>'int', 'protocol'=>'int'], 'new' => ['Socket|false', 'domain'=>'int', 'type'=>'int', 'protocol'=>'int'], ], 'socket_create_listen' => [ 'old' => ['resource|false', 'port'=>'int', 'backlog='=>'int'], 'new' => ['Socket|false', 'port'=>'int', 'backlog='=>'int'], ], 'socket_create_pair' => [ 'old' => ['bool', 'domain'=>'int', 'type'=>'int', 'protocol'=>'int', '&w_pair'=>'resource[]'], 'new' => ['bool', 'domain'=>'int', 'type'=>'int', 'protocol'=>'int', '&w_pair'=>'Socket[]'], ], 'socket_export_stream' => [ 'old' => ['resource|false', 'socket'=>'resource'], 'new' => ['resource|false', 'socket'=>'Socket'], ], 'socket_get_option' => [ 'old' => ['array|int|false', 'socket'=>'resource', 'level'=>'int', 'option'=>'int'], 'new' => ['array|int|false', 'socket'=>'Socket', 'level'=>'int', 'option'=>'int'], ], 'socket_get_status' => [ 'old' => ['array', 'stream'=>'resource'], 'new' => ['array', 'stream'=>'Socket'], ], 'socket_getopt' => [ 'old' => ['array|int|false', 'socket'=>'resource', 'level'=>'int', 'option'=>'int'], 'new' => ['array|int|false', 'socket'=>'Socket', 'level'=>'int', 'option'=>'int'], ], 'socket_getpeername' => [ 'old' => ['bool', 'socket'=>'resource', '&w_address'=>'string', '&w_port='=>'int'], 'new' => ['bool', 'socket'=>'Socket', '&w_address'=>'string', '&w_port='=>'int'], ], 'socket_getsockname' => [ 'old' => ['bool', 'socket'=>'resource', '&w_address'=>'string', '&w_port='=>'int'], 'new' => ['bool', 'socket'=>'Socket', '&w_address'=>'string', '&w_port='=>'int'], ], 'socket_import_stream' => [ 'old' => ['resource|false', 'stream'=>'resource'], 'new' => ['Socket|false', 'stream'=>'resource'], ], 'socket_last_error' => [ 'old' => ['int', 'socket='=>'resource'], 'new' => ['int', 'socket='=>'?Socket'], ], 'socket_listen' => [ 'old' => ['bool', 'socket'=>'resource', 'backlog='=>'int'], 'new' => ['bool', 'socket'=>'Socket', 'backlog='=>'int'], ], 'socket_read' => [ 'old' => ['string|false', 'socket'=>'resource', 'length'=>'int', 'mode='=>'int'], 'new' => ['string|false', 'socket'=>'Socket', 'length'=>'int', 'mode='=>'int'], ], 'socket_recv' => [ 'old' => ['int|false', 'socket'=>'resource', '&w_data'=>'string', 'length'=>'int', 'flags'=>'int'], 'new' => ['int|false', 'socket'=>'Socket', '&w_data'=>'string', 'length'=>'int', 'flags'=>'int'], ], 'socket_recvfrom' => [ 'old' => ['int|false', 'socket'=>'resource', '&w_data'=>'string', 'length'=>'int', 'flags'=>'int', '&w_address'=>'string', '&w_port='=>'int'], 'new' => ['int|false', 'socket'=>'Socket', '&w_data'=>'string', 'length'=>'int', 'flags'=>'int', '&w_address'=>'string', '&w_port='=>'int'], ], 'socket_recvmsg' => [ 'old' => ['int|false', 'socket'=>'resource', '&w_message'=>'array', 'flags='=>'int'], 'new' => ['int|false', 'socket'=>'Socket', '&w_message'=>'array', 'flags='=>'int'], ], 'socket_select' => [ 'old' => ['int|false', '&rw_read'=>'resource[]|null', '&rw_write'=>'resource[]|null', '&rw_except'=>'resource[]|null', 'seconds'=>'int|null', 'microseconds='=>'int'], 'new' => ['int|false', '&rw_read'=>'Socket[]|null', '&rw_write'=>'Socket[]|null', '&rw_except'=>'Socket[]|null', 'seconds'=>'int|null', 'microseconds='=>'int'], ], 'socket_send' => [ 'old' => ['int|false', 'socket'=>'resource', 'data'=>'string', 'length'=>'int', 'flags'=>'int'], 'new' => ['int|false', 'socket'=>'Socket', 'data'=>'string', 'length'=>'int', 'flags'=>'int'], ], 'socket_sendmsg' => [ 'old' => ['int|false', 'socket'=>'resource', 'message'=>'array', 'flags='=>'int'], 'new' => ['int|false', 'socket'=>'Socket', 'message'=>'array', 'flags='=>'int'], ], 'socket_sendto' => [ 'old' => ['int|false', 'socket'=>'resource', 'data'=>'string', 'length'=>'int', 'flags'=>'int', 'address'=>'string', 'port='=>'int'], 'new' => ['int|false', 'socket'=>'Socket', 'data'=>'string', 'length'=>'int', 'flags'=>'int', 'address'=>'string', 'port='=>'?int'], ], 'socket_set_block' => [ 'old' => ['bool', 'socket'=>'resource'], 'new' => ['bool', 'socket'=>'Socket'], ], 'socket_set_blocking' => [ 'old' => ['bool', 'stream'=>'resource', 'enable'=>'bool'], 'new' => ['bool', 'stream'=>'Socket', 'enable'=>'bool'], ], 'socket_set_nonblock' => [ 'old' => ['bool', 'socket'=>'resource'], 'new' => ['bool', 'socket'=>'Socket'], ], 'socket_set_option' => [ 'old' => ['bool', 'socket'=>'resource', 'level'=>'int', 'option'=>'int', 'value'=>'int|string|array'], 'new' => ['bool', 'socket'=>'Socket', 'level'=>'int', 'option'=>'int', 'value'=>'int|string|array'], ], 'socket_set_timeout' => [ 'old' => ['bool', 'stream'=>'resource', 'seconds'=>'int', 'microseconds='=>'int'], 'new' => ['bool', 'stream'=>'resource', 'seconds'=>'int', 'microseconds='=>'int'], ], 'socket_setopt' => [ 'old' => ['bool', 'socket'=>'resource', 'level'=>'int', 'option'=>'int', 'value'=>'int|string|array'], 'new' => ['bool', 'socket'=>'Socket', 'level'=>'int', 'option'=>'int', 'value'=>'int|string|array'], ], 'socket_shutdown' => [ 'old' => ['bool', 'socket'=>'resource', 'mode='=>'int'], 'new' => ['bool', 'socket'=>'Socket', 'mode='=>'int'], ], 'socket_write' => [ 'old' => ['int|false', 'socket'=>'resource', 'data'=>'string', 'length='=>'int'], 'new' => ['int|false', 'socket'=>'Socket', 'data'=>'string', 'length='=>'int|null'], ], 'socket_wsaprotocol_info_export' => [ 'old' => ['string|false', 'socket'=>'resource', 'process_id'=>'int'], 'new' => ['string|false', 'socket'=>'Socket', 'process_id'=>'int'], ], 'socket_wsaprotocol_info_import' => [ 'old' => ['resource|false', 'info_id'=>'string'], 'new' => ['Socket|false', 'info_id'=>'string'], ], 'spl_autoload' => [ 'old' => ['void', 'class'=>'string', 'file_extensions='=>'string'], 'new' => ['void', 'class'=>'string', 'file_extensions='=>'?string'], ], 'spl_autoload_extensions' => [ 'old' => ['string', 'file_extensions='=>'string'], 'new' => ['string', 'file_extensions='=>'?string'], ], 'spl_autoload_functions' => [ 'old' => ['false|list'], 'new' => ['list'], ], 'spl_autoload_register' => [ 'old' => ['bool', 'callback='=>'callable(string):void', 'throw='=>'bool', 'prepend='=>'bool'], 'new' => ['bool', 'callback='=>'callable(string):void|null', 'throw='=>'bool', 'prepend='=>'bool'], ], 'str_word_count' => [ 'old' => ['array|int', 'string'=>'string', 'format='=>'int', 'characters='=>'string'], 'new' => ['array|int', 'string'=>'string', 'format='=>'int', 'characters='=>'?string'], ], 'strchr' => [ 'old' => ['string|false', 'haystack'=>'string', 'needle'=>'string|int', 'before_needle='=>'bool'], 'new' => ['string|false', 'haystack'=>'string', 'needle'=>'string', 'before_needle='=>'bool'], ], 'strcspn' => [ 'old' => ['int', 'string'=>'string', 'characters'=>'string', 'offset='=>'int', 'length='=>'int'], 'new' => ['int', 'string'=>'string', 'characters'=>'string', 'offset='=>'int', 'length='=>'?int'], ], 'stream_context_create' => [ 'old' => ['resource', 'options='=>'array', 'params='=>'array'], 'new' => ['resource', 'options='=>'?array', 'params='=>'?array'], ], 'stream_context_get_default' => [ 'old' => ['resource', 'options='=>'array'], 'new' => ['resource', 'options='=>'?array'], ], 'stream_copy_to_stream' => [ 'old' => ['int|false', 'from'=>'resource', 'to'=>'resource', 'length='=>'int', 'offset='=>'int'], 'new' => ['int|false', 'from'=>'resource', 'to'=>'resource', 'length='=>'?int', 'offset='=>'int'], ], 'stream_get_contents' => [ 'old' => ['string|false', 'stream'=>'resource', 'length='=>'int', 'offset='=>'int'], 'new' => ['string|false', 'stream'=>'resource', 'length='=>'?int', 'offset='=>'int'], ], 'stream_set_chunk_size' => [ 'old' => ['int|false', 'stream'=>'resource', 'size'=>'int'], 'new' => ['int', 'stream'=>'resource', 'size'=>'int'], ], 'stream_socket_accept' => [ 'old' => ['resource|false', 'socket'=>'resource', 'timeout='=>'float', '&w_peer_name='=>'string'], 'new' => ['resource|false', 'socket'=>'resource', 'timeout='=>'?float', '&w_peer_name='=>'string'], ], 'stream_socket_client' => [ 'old' => ['resource|false', 'address'=>'string', '&w_error_code='=>'int', '&w_error_message='=>'string', 'timeout='=>'float', 'flags='=>'int', 'context='=>'resource'], 'new' => ['resource|false', 'address'=>'string', '&w_error_code='=>'int', '&w_error_message='=>'string', 'timeout='=>'?float', 'flags='=>'int', 'context='=>'?resource'], ], 'stream_socket_enable_crypto' => [ 'old' => ['int|bool', 'stream'=>'resource', 'enable'=>'bool', 'crypto_method='=>'?int', 'session_stream='=>'resource'], 'new' => ['int|bool', 'stream'=>'resource', 'enable'=>'bool', 'crypto_method='=>'?int', 'session_stream='=>'?resource'], ], 'strftime' => [ 'old' => ['string|false', 'format'=>'string', 'timestamp='=>'int'], 'new' => ['string|false', 'format'=>'string', 'timestamp='=>'?int'], ], 'strip_tags' => [ 'old' => ['string', 'string'=>'string', 'allowed_tags='=>'string|list'], 'new' => ['string', 'string'=>'string', 'allowed_tags='=>'string|list|null'], ], 'stripos' => [ 'old' => ['int|false', 'haystack'=>'string', 'needle'=>'string|int', 'offset='=>'int'], 'new' => ['int|false', 'haystack'=>'string', 'needle'=>'string', 'offset='=>'int'], ], 'stristr' => [ 'old' => ['string|false', 'haystack'=>'string', 'needle'=>'string|int', 'before_needle='=>'bool'], 'new' => ['string|false', 'haystack'=>'string', 'needle'=>'string', 'before_needle='=>'bool'], ], 'strpos' => [ 'old' => ['int|false', 'haystack'=>'string', 'needle'=>'string|int', 'offset='=>'int'], 'new' => ['int|false', 'haystack'=>'string', 'needle'=>'string', 'offset='=>'int'], ], 'strrchr' => [ 'old' => ['string|false', 'haystack'=>'string', 'needle'=>'string|int'], 'new' => ['string|false', 'haystack'=>'string', 'needle'=>'string'], ], 'strripos' => [ 'old' => ['int|false', 'haystack'=>'string', 'needle'=>'string|int', 'offset='=>'int'], 'new' => ['int|false', 'haystack'=>'string', 'needle'=>'string', 'offset='=>'int'], ], 'strrpos' => [ 'old' => ['int|false', 'haystack'=>'string', 'needle'=>'string|int', 'offset='=>'int'], 'new' => ['int|false', 'haystack'=>'string', 'needle'=>'string', 'offset='=>'int'], ], 'strspn' => [ 'old' => ['int', 'string'=>'string', 'characters'=>'string', 'offset='=>'int', 'length='=>'int'], 'new' => ['int', 'string'=>'string', 'characters'=>'string', 'offset='=>'int', 'length='=>'?int'], ], 'strstr' => [ 'old' => ['string|false', 'haystack'=>'string', 'needle'=>'string|int', 'before_needle='=>'bool'], 'new' => ['string|false', 'haystack'=>'string', 'needle'=>'string', 'before_needle='=>'bool'], ], 'strtotime' => [ 'old' => ['int|false', 'datetime'=>'string', 'baseTimestamp='=>'int'], 'new' => ['int|false', 'datetime'=>'string', 'baseTimestamp='=>'?int'], ], 'substr_compare' => [ 'old' => ['int|false', 'haystack'=>'string', 'needle'=>'string', 'offset'=>'int', 'length='=>'int', 'case_insensitive='=>'bool'], 'new' => ['int', 'haystack'=>'string', 'needle'=>'string', 'offset'=>'int', 'length='=>'?int', 'case_insensitive='=>'bool'], ], 'substr_count' => [ 'old' => ['int', 'haystack'=>'string', 'needle'=>'string', 'offset='=>'int', 'length='=>'int'], 'new' => ['int', 'haystack'=>'string', 'needle'=>'string', 'offset='=>'int', 'length='=>'?int'], ], 'substr' => [ 'old' => ['string|false', 'string'=>'string', 'offset'=>'int', 'length='=>'int'], 'new' => ['string', 'string'=>'string', 'offset'=>'int', 'length='=>'?int'], ], 'substr_replace' => [ 'old' => ['string', 'string'=>'string', 'replace'=>'string|string[]', 'offset'=>'int|int[]', 'length='=>'int|int[]'], 'new' => ['string', 'string'=>'string', 'replace'=>'string|string[]', 'offset'=>'int|int[]', 'length='=>'int|int[]|null'], ], 'substr_replace\'1' => [ 'old' => ['string[]', 'string'=>'string[]', 'replace'=>'string|string[]', 'offset'=>'int|int[]', 'length='=>'int|int[]'], 'new' => ['string[]', 'string'=>'string[]', 'replace'=>'string|string[]', 'offset'=>'int|int[]', 'length='=>'int|int[]|null'], ], 'tidy_parse_file' => [ 'old' => ['tidy', 'filename'=>'string', 'config='=>'array|string', 'encoding='=>'string', 'useIncludePath='=>'bool'], 'new' => ['tidy', 'filename'=>'string', 'config='=>'array|string|null', 'encoding='=>'?string', 'useIncludePath='=>'bool'], ], 'tidy_parse_string' => [ 'old' => ['tidy', 'string'=>'string', 'config='=>'array|string', 'encoding='=>'string'], 'new' => ['tidy', 'string'=>'string', 'config='=>'array|string|null', 'encoding='=>'?string'], ], 'tidy_repair_file' => [ 'old' => ['string', 'filename'=>'string', 'config='=>'array|string', 'encoding='=>'string', 'useIncludePath='=>'bool'], 'new' => ['string', 'filename'=>'string', 'config='=>'array|string|null', 'encoding='=>'?string', 'useIncludePath='=>'bool'], ], 'tidy_repair_string' => [ 'old' => ['string', 'string'=>'string', 'config='=>'array|string', 'encoding='=>'string'], 'new' => ['string', 'string'=>'string', 'config='=>'array|string|null', 'encoding='=>'?string'], ], 'timezone_identifiers_list' => [ 'old' => ['list|false', 'timezoneGroup='=>'int', 'countryCode='=>'?string'], 'new' => ['list', 'timezoneGroup='=>'int', 'countryCode='=>'?string'], ], 'timezone_offset_get' => [ 'old' => ['int|false', 'object'=>'DateTimeZone', 'datetime'=>'DateTimeInterface'], 'new' => ['int', 'object'=>'DateTimeZone', 'datetime'=>'DateTimeInterface'], ], 'touch' => [ 'old' => ['bool', 'filename'=>'string', 'mtime='=>'int', 'atime='=>'int'], 'new' => ['bool', 'filename'=>'string', 'mtime='=>'?int', 'atime='=>'?int'], ], 'umask' => [ 'old' => ['int', 'mask='=>'int'], 'new' => ['int', 'mask='=>'?int'], ], 'unixtojd' => [ 'old' => ['int|false', 'timestamp='=>'int'], 'new' => ['int|false', 'timestamp='=>'?int'], ], 'xml_get_current_byte_index' => [ 'old' => ['int|false', 'parser'=>'resource'], 'new' => ['int', 'parser'=>'XMLParser'], ], 'xml_get_current_column_number' => [ 'old' => ['int|false', 'parser'=>'resource'], 'new' => ['int', 'parser'=>'XMLParser'], ], 'xml_get_current_line_number' => [ 'old' => ['int|false', 'parser'=>'resource'], 'new' => ['int', 'parser'=>'XMLParser'], ], 'xml_get_error_code' => [ 'old' => ['int|false', 'parser'=>'resource'], 'new' => ['int', 'parser'=>'XMLParser'], ], 'xml_parse' => [ 'old' => ['int', 'parser'=>'resource', 'data'=>'string', 'is_final='=>'bool'], 'new' => ['int', 'parser'=>'XMLParser', 'data'=>'string', 'is_final='=>'bool'], ], 'xml_parse_into_struct' => [ 'old' => ['int', 'parser'=>'resource', 'data'=>'string', '&w_values'=>'array', '&w_index='=>'array'], 'new' => ['int', 'parser'=>'XMLParser', 'data'=>'string', '&w_values'=>'array', '&w_index='=>'array'], ], 'xml_parser_create' => [ 'old' => ['resource', 'encoding='=>'string'], 'new' => ['XMLParser', 'encoding='=>'?string'], ], 'xml_parser_create_ns' => [ 'old' => ['resource', 'encoding='=>'string', 'separator='=>'string'], 'new' => ['XMLParser', 'encoding='=>'?string', 'separator='=>'string'], ], 'xml_parser_free' => [ 'old' => ['bool', 'parser'=>'resource'], 'new' => ['bool', 'parser'=>'XMLParser'], ], 'xml_parser_get_option' => [ 'old' => ['string|int', 'parser'=>'resource', 'option'=>'int'], 'new' => ['string|int', 'parser'=>'XMLParser', 'option'=>'int'], ], 'xml_parser_set_option' => [ 'old' => ['bool', 'parser'=>'resource', 'option'=>'int', 'value'=>'mixed'], 'new' => ['bool', 'parser'=>'XMLParser', 'option'=>'int', 'value'=>'mixed'], ], 'xml_set_character_data_handler' => [ 'old' => ['true', 'parser'=>'resource', 'handler'=>'callable'], 'new' => ['true', 'parser'=>'XMLParser', 'handler'=>'callable'], ], 'xml_set_default_handler' => [ 'old' => ['true', 'parser'=>'resource', 'handler'=>'callable'], 'new' => ['true', 'parser'=>'XMLParser', 'handler'=>'callable'], ], 'xml_set_element_handler' => [ 'old' => ['true', 'parser'=>'resource', 'start_handler'=>'callable', 'end_handler'=>'callable'], 'new' => ['true', 'parser'=>'XMLParser', 'start_handler'=>'callable', 'end_handler'=>'callable'], ], 'xml_set_end_namespace_decl_handler' => [ 'old' => ['true', 'parser'=>'resource', 'handler'=>'callable'], 'new' => ['true', 'parser'=>'XMLParser', 'handler'=>'callable'], ], 'xml_set_external_entity_ref_handler' => [ 'old' => ['true', 'parser'=>'resource', 'handler'=>'callable'], 'new' => ['true', 'parser'=>'XMLParser', 'handler'=>'callable'], ], 'xml_set_notation_decl_handler' => [ 'old' => ['true', 'parser'=>'resource', 'handler'=>'callable'], 'new' => ['true', 'parser'=>'XMLParser', 'handler'=>'callable'], ], 'xml_set_object' => [ 'old' => ['true', 'parser'=>'resource', 'object'=>'object'], 'new' => ['true', 'parser'=>'XMLParser', 'object'=>'object'], ], 'xml_set_processing_instruction_handler' => [ 'old' => ['true', 'parser'=>'resource', 'handler'=>'callable'], 'new' => ['true', 'parser'=>'XMLParser', 'handler'=>'callable'], ], 'xml_set_start_namespace_decl_handler' => [ 'old' => ['true', 'parser'=>'resource', 'handler'=>'callable'], 'new' => ['true', 'parser'=>'XMLParser', 'handler'=>'callable'], ], 'xml_set_unparsed_entity_decl_handler' => [ 'old' => ['true', 'parser'=>'resource', 'handler'=>'callable'], 'new' => ['true', 'parser'=>'XMLParser', 'handler'=>'callable'], ], 'xmlwriter_end_attribute' => [ 'old' => ['bool', 'writer'=>'resource'], 'new' => ['bool', 'writer'=>'XMLWriter'], ], 'xmlwriter_end_cdata' => [ 'old' => ['bool', 'writer'=>'resource'], 'new' => ['bool', 'writer'=>'XMLWriter'], ], 'xmlwriter_end_comment' => [ 'old' => ['bool', 'writer'=>'resource'], 'new' => ['bool', 'writer'=>'XMLWriter'], ], 'xmlwriter_end_document' => [ 'old' => ['bool', 'writer'=>'resource'], 'new' => ['bool', 'writer'=>'XMLWriter'], ], 'xmlwriter_end_dtd' => [ 'old' => ['bool', 'writer'=>'resource'], 'new' => ['bool', 'writer'=>'XMLWriter'], ], 'xmlwriter_end_dtd_attlist' => [ 'old' => ['bool', 'writer'=>'resource'], 'new' => ['bool', 'writer'=>'XMLWriter'], ], 'xmlwriter_end_dtd_element' => [ 'old' => ['bool', 'writer'=>'resource'], 'new' => ['bool', 'writer'=>'XMLWriter'], ], 'xmlwriter_end_dtd_entity' => [ 'old' => ['bool', 'writer'=>'resource'], 'new' => ['bool', 'writer'=>'XMLWriter'], ], 'xmlwriter_end_element' => [ 'old' => ['bool', 'writer'=>'resource'], 'new' => ['bool', 'writer'=>'XMLWriter'], ], 'xmlwriter_end_pi' => [ 'old' => ['bool', 'writer'=>'resource'], 'new' => ['bool', 'writer'=>'XMLWriter'], ], 'xmlwriter_flush' => [ 'old' => ['string|int|false', 'writer'=>'resource', 'empty='=>'bool'], 'new' => ['string|int', 'writer'=>'XMLWriter', 'empty='=>'bool'], ], 'xmlwriter_full_end_element' => [ 'old' => ['bool', 'writer'=>'resource'], 'new' => ['bool', 'writer'=>'XMLWriter'], ], 'xmlwriter_open_memory' => [ 'old' => ['resource|false'], 'new' => ['XMLWriter|false'], ], 'xmlwriter_open_uri' => [ 'old' => ['resource|false', 'uri'=>'string'], 'new' => ['XMLWriter|false', 'uri'=>'string'], ], 'xmlwriter_output_memory' => [ 'old' => ['string', 'writer'=>'resource', 'flush='=>'bool'], 'new' => ['string', 'writer'=>'XMLWriter', 'flush='=>'bool'], ], 'xmlwriter_set_indent' => [ 'old' => ['bool', 'writer'=>'resource', 'enable'=>'bool'], 'new' => ['bool', 'writer'=>'XMLWriter', 'enable'=>'bool'], ], 'xmlwriter_set_indent_string' => [ 'old' => ['bool', 'writer'=>'resource', 'indentation'=>'string'], 'new' => ['bool', 'writer'=>'XMLWriter', 'indentation'=>'string'], ], 'xmlwriter_start_attribute' => [ 'old' => ['bool', 'writer'=>'resource', 'name'=>'string'], 'new' => ['bool', 'writer'=>'XMLWriter', 'name'=>'string'], ], 'xmlwriter_start_attribute_ns' => [ 'old' => ['bool', 'writer'=>'resource', 'prefix'=>'string', 'name'=>'string', 'namespace'=>'?string'], 'new' => ['bool', 'writer'=>'XMLWriter', 'prefix'=>'?string', 'name'=>'string', 'namespace'=>'?string'], ], 'xmlwriter_start_cdata' => [ 'old' => ['bool', 'writer'=>'resource'], 'new' => ['bool', 'writer'=>'XMLWriter'], ], 'xmlwriter_start_comment' => [ 'old' => ['bool', 'writer'=>'resource'], 'new' => ['bool', 'writer'=>'XMLWriter'], ], 'xmlwriter_start_document' => [ 'old' => ['bool', 'writer'=>'resource', 'version='=>'?string', 'encoding='=>'?string', 'standalone='=>'?string'], 'new' => ['bool', 'writer'=>'XMLWriter', 'version='=>'?string', 'encoding='=>'?string', 'standalone='=>'?string'], ], 'xmlwriter_start_dtd' => [ 'old' => ['bool', 'writer'=>'resource', 'qualifiedName'=>'string', 'publicId='=>'?string', 'systemId='=>'?string'], 'new' => ['bool', 'writer'=>'XMLWriter', 'qualifiedName'=>'string', 'publicId='=>'?string', 'systemId='=>'?string'], ], 'xmlwriter_start_dtd_attlist' => [ 'old' => ['bool', 'writer'=>'resource', 'name'=>'string'], 'new' => ['bool', 'writer'=>'XMLWriter', 'name'=>'string'], ], 'xmlwriter_start_dtd_element' => [ 'old' => ['bool', 'writer'=>'resource', 'qualifiedName'=>'string'], 'new' => ['bool', 'writer'=>'XMLWriter', 'qualifiedName'=>'string'], ], 'xmlwriter_start_dtd_entity' => [ 'old' => ['bool', 'writer'=>'resource', 'name'=>'string', 'isParam'=>'bool'], 'new' => ['bool', 'writer'=>'XMLWriter', 'name'=>'string', 'isParam'=>'bool'], ], 'xmlwriter_start_element' => [ 'old' => ['bool', 'writer'=>'resource', 'name'=>'string'], 'new' => ['bool', 'writer'=>'XMLWriter', 'name'=>'string'], ], 'xmlwriter_start_element_ns' => [ 'old' => ['bool', 'writer'=>'resource', 'prefix'=>'?string', 'name'=>'string', 'namespace'=>'?string'], 'new' => ['bool', 'writer'=>'XMLWriter', 'prefix'=>'?string', 'name'=>'string', 'namespace'=>'?string'], ], 'xmlwriter_start_pi' => [ 'old' => ['bool', 'writer'=>'resource', 'target'=>'string'], 'new' => ['bool', 'writer'=>'XMLWriter', 'target'=>'string'], ], 'xmlwriter_text' => [ 'old' => ['bool', 'writer'=>'resource', 'content'=>'string'], 'new' => ['bool', 'writer'=>'XMLWriter', 'content'=>'string'], ], 'xmlwriter_write_attribute' => [ 'old' => ['bool', 'writer'=>'resource', 'name'=>'string', 'value'=>'string'], 'new' => ['bool', 'writer'=>'XMLWriter', 'name'=>'string', 'value'=>'string'], ], 'xmlwriter_write_attribute_ns' => [ 'old' => ['bool', 'writer'=>'resource', 'prefix'=>'string', 'name'=>'string', 'namespace'=>'?string', 'value'=>'string'], 'new' => ['bool', 'writer'=>'XMLWriter', 'prefix'=>'?string', 'name'=>'string', 'namespace'=>'?string', 'value'=>'string'], ], 'xmlwriter_write_cdata' => [ 'old' => ['bool', 'writer'=>'resource', 'content'=>'string'], 'new' => ['bool', 'writer'=>'XMLWriter', 'content'=>'string'], ], 'xmlwriter_write_comment' => [ 'old' => ['bool', 'writer'=>'resource', 'content'=>'string'], 'new' => ['bool', 'writer'=>'XMLWriter', 'content'=>'string'], ], 'xmlwriter_write_dtd' => [ 'old' => ['bool', 'writer'=>'resource', 'name'=>'string', 'publicId='=>'?string', 'systemId='=>'?string', 'content='=>'?string'], 'new' => ['bool', 'writer'=>'XMLWriter', 'name'=>'string', 'publicId='=>'?string', 'systemId='=>'?string', 'content='=>'?string'], ], 'xmlwriter_write_dtd_attlist' => [ 'old' => ['bool', 'writer'=>'resource', 'name'=>'string', 'content'=>'string'], 'new' => ['bool', 'writer'=>'XMLWriter', 'name'=>'string', 'content'=>'string'], ], 'xmlwriter_write_dtd_element' => [ 'old' => ['bool', 'writer'=>'resource', 'name'=>'string', 'content'=>'string'], 'new' => ['bool', 'writer'=>'XMLWriter', 'name'=>'string', 'content'=>'string'], ], 'xmlwriter_write_dtd_entity' => [ 'old' => ['bool', 'writer'=>'resource', 'name'=>'string', 'content'=>'string', 'isParam'=>'bool', 'publicId'=>'string', 'systemId'=>'string', 'notationData'=>'string'], 'new' => ['bool', 'writer'=>'XMLWriter', 'name'=>'string', 'content'=>'string', 'isParam='=>'bool', 'publicId='=>'?string', 'systemId='=>'?string', 'notationData='=>'?string'], ], 'xmlwriter_write_element' => [ 'old' => ['bool', 'writer'=>'resource', 'name'=>'string', 'content'=>'?string'], 'new' => ['bool', 'writer'=>'XMLWriter', 'name'=>'string', 'content='=>'?string'], ], 'xmlwriter_write_element_ns' => [ 'old' => ['bool', 'writer'=>'resource', 'prefix'=>'?string', 'name'=>'string', 'namespace'=>'string', 'content'=>'?string'], 'new' => ['bool', 'writer'=>'XMLWriter', 'prefix'=>'?string', 'name'=>'string', 'namespace'=>'?string', 'content='=>'?string'], ], 'xmlwriter_write_pi' => [ 'old' => ['bool', 'writer'=>'resource', 'target'=>'string', 'content'=>'string'], 'new' => ['bool', 'writer'=>'XMLWriter', 'target'=>'string', 'content'=>'string'], ], 'xmlwriter_write_raw' => [ 'old' => ['bool', 'writer'=>'resource', 'content'=>'string'], 'new' => ['bool', 'writer'=>'XMLWriter', 'content'=>'string'], ], 'ZipArchive::addEmptyDir' => [ 'old' => ['bool', 'dirname'=>'string'], 'new' => ['bool', 'dirname'=>'string', 'flags='=>'int'], ], 'ZipArchive::addFile' => [ 'old' => ['bool', 'filepath'=>'string', 'entryname='=>'string', 'start='=>'int', 'length='=>'int'], 'new' => ['bool', 'filepath'=>'string', 'entryname='=>'string', 'start='=>'int', 'length='=>'int', 'flags='=>'int'], ], 'ZipArchive::addFromString' => [ 'old' => ['bool', 'name'=>'string', 'content'=>'string'], 'new' => ['bool', 'name'=>'string', 'content'=>'string', 'flags='=>'int'], ], ], 'removed' => [ 'PDOStatement::setFetchMode\'1' => ['bool', 'fetch_column'=>'int', 'colno'=>'int'], 'PDOStatement::setFetchMode\'2' => ['bool', 'fetch_class'=>'int', 'classname'=>'string', 'ctorargs'=>'array'], 'PDOStatement::setFetchMode\'3' => ['bool', 'fetch_into'=>'int', 'object'=>'object'], 'ReflectionType::isBuiltin' => ['bool'], 'SplFileObject::fgetss' => ['string|false', 'allowable_tags='=>'string'], 'create_function' => ['string', 'args'=>'string', 'code'=>'string'], 'each' => ['array{0:int|string,key:int|string,1:mixed,value:mixed}', '&r_arr'=>'array'], 'fgetss' => ['string|false', 'fp'=>'resource', 'length='=>'int', 'allowable_tags='=>'string'], 'gmp_random' => ['GMP', 'limiter='=>'int'], 'gzgetss' => ['string|false', 'zp'=>'resource', 'length'=>'int', 'allowable_tags='=>'string'], 'image2wbmp' => ['bool', 'im'=>'resource', 'filename='=>'?string', 'threshold='=>'int'], 'jpeg2wbmp' => ['bool', 'jpegname'=>'string', 'wbmpname'=>'string', 'dest_height'=>'int', 'dest_width'=>'int', 'threshold'=>'int'], 'ldap_control_paged_result' => ['bool', 'link_identifier'=>'resource', 'pagesize'=>'int', 'iscritical='=>'bool', 'cookie='=>'string'], 'ldap_control_paged_result_response' => ['bool', 'link_identifier'=>'resource', 'result_identifier'=>'resource', '&w_cookie'=>'string', '&w_estimated'=>'int'], 'ldap_sort' => ['bool', 'link_identifier'=>'resource', 'result_identifier'=>'resource', 'sortfilter'=>'string'], 'number_format\'1' => ['string', 'num'=>'float', 'decimals'=>'int', 'decimal_separator'=>'?string', 'thousands_separator'=>'?string'], 'png2wbmp' => ['bool', 'pngname'=>'string', 'wbmpname'=>'string', 'dest_height'=>'int', 'dest_width'=>'int', 'threshold'=>'int'], 'read_exif_data' => ['array', 'filename'=>'string', 'sections_needed='=>'string', 'sub_arrays='=>'bool', 'read_thumbnail='=>'bool'], 'Reflection::export' => ['?string', 'r'=>'reflector', 'return='=>'bool'], 'ReflectionClass::export' => ['?string', 'argument'=>'string|object', 'return='=>'bool'], 'ReflectionClassConstant::export' => ['string', 'class'=>'mixed', 'name'=>'string', 'return='=>'bool'], 'ReflectionExtension::export' => ['?string', 'name'=>'string', 'return='=>'bool'], 'ReflectionFunction::export' => ['?string', 'name'=>'string', 'return='=>'bool'], 'ReflectionFunctionAbstract::export' => ['?string'], 'ReflectionMethod::export' => ['?string', 'class'=>'string', 'name'=>'string', 'return='=>'bool'], 'ReflectionObject::export' => ['?string', 'argument'=>'object', 'return='=>'bool'], 'ReflectionParameter::export' => ['?string', 'function'=>'string', 'parameter'=>'string', 'return='=>'bool'], 'ReflectionProperty::export' => ['?string', 'class'=>'mixed', 'name'=>'string', 'return='=>'bool'], 'ReflectionZendExtension::export' => ['?string', 'name'=>'string', 'return='=>'bool'], 'SimpleXMLIterator::rewind' => ['void'], 'SimpleXMLIterator::valid' => ['bool'], 'SimpleXMLIterator::current' => ['?SimpleXMLIterator'], 'SimpleXMLIterator::key' => ['string|false'], 'SimpleXMLIterator::next' => ['void'], 'SimpleXMLIterator::hasChildren' => ['bool'], 'SimpleXMLIterator::getChildren' => ['?SimpleXMLIterator'], 'SplFixedArray::current' => ['mixed'], 'SplFixedArray::key' => ['int'], 'SplFixedArray::next' => ['void'], 'SplFixedArray::rewind' => ['void'], 'SplFixedArray::valid' => ['bool'], 'SplTempFileObject::fgetss' => ['string', 'allowable_tags='=>'string'], 'xmlrpc_decode' => ['mixed', 'xml'=>'string', 'encoding='=>'string'], 'xmlrpc_decode_request' => ['?array', 'xml'=>'string', '&w_method'=>'string', 'encoding='=>'string'], 'xmlrpc_encode' => ['string', 'value'=>'mixed'], 'xmlrpc_encode_request' => ['string', 'method'=>'string', 'params'=>'mixed', 'output_options='=>'array'], 'xmlrpc_get_type' => ['string', 'value'=>'mixed'], 'xmlrpc_is_fault' => ['bool', 'arg'=>'array'], 'xmlrpc_parse_method_descriptions' => ['array', 'xml'=>'string'], 'xmlrpc_server_add_introspection_data' => ['int', 'server'=>'resource', 'desc'=>'array'], 'xmlrpc_server_call_method' => ['string', 'server'=>'resource', 'xml'=>'string', 'user_data'=>'mixed', 'output_options='=>'array'], 'xmlrpc_server_create' => ['resource'], 'xmlrpc_server_destroy' => ['int', 'server'=>'resource'], 'xmlrpc_server_register_introspection_callback' => ['bool', 'server'=>'resource', 'function'=>'string'], 'xmlrpc_server_register_method' => ['bool', 'server'=>'resource', 'method_name'=>'string', 'function'=>'string'], 'xmlrpc_set_type' => ['bool', '&rw_value'=>'string|DateTime', 'type'=>'string'], ], ]; strtolower($a) <=> strtolower($b)); foreach ($new_local as $name => $data) { if (!is_array($data)) { throw new UnexpectedValueException('bad data for ' . $name); } $return_type = array_shift($data); echo '\'' . str_replace("'", "\'", $name) . '\' => [\'' . str_replace("'", "\'", $return_type) . '\''; if ($data) { $signature = []; foreach ($data as $param_name => $type) { $signature[] = '\'' . str_replace("'", "\'", $param_name) . '\'=>\'' . str_replace("'", "\'", $type) . '\''; } echo ', ' . implode(', ', $signature); } echo '],' . "\n"; } function get_changed_functions(array $a, array $b) { $changed_functions = []; foreach (array_intersect_key($a, $b) as $function_name => $a_data) { if (json_encode($b[$function_name]) !== json_encode($a_data)) { $changed_functions[$function_name] = $b[$function_name]; } } return $changed_functions; } [ 'DateTime::createFromImmutable' => ['static', 'object'=>'DateTimeImmutable'], 'JsonException::__clone' => ['void'], 'JsonException::__construct' => ['void', "message="=>"string", 'code='=>'int', 'previous='=>'?Throwable'], 'JsonException::__toString' => ['string'], 'JsonException::__wakeup' => ['void'], 'JsonException::getCode' => ['int'], 'JsonException::getFile' => ['string'], 'JsonException::getLine' => ['int'], 'JsonException::getMessage' => ['string'], 'JsonException::getPrevious' => ['?Throwable'], 'JsonException::getTrace' => ['list\',args?:array}>'], 'JsonException::getTraceAsString' => ['string'], 'Normalizer::getRawDecomposition' => ['?string', 'string'=>'string', 'form='=>'int'], 'SplPriorityQueue::isCorrupted' => ['bool'], 'array_key_first' => ['int|string|null', 'array'=>'array'], 'array_key_last' => ['int|string|null', 'array'=>'array'], 'fpm_get_status' => ['array|false'], 'gc_status' => ['array{runs:int,collected:int,threshold:int,roots:int}'], 'gmp_binomial' => ['GMP|false', 'n'=>'GMP|string|int', 'k'=>'int'], 'gmp_kronecker' => ['int', 'num1'=>'GMP|string|int', 'num2'=>'GMP|string|int'], 'gmp_lcm' => ['GMP', 'num1'=>'GMP|string|int', 'num2'=>'GMP|string|int'], 'gmp_perfect_power' => ['bool', 'num'=>'GMP|string|int'], 'hrtime' => ['array{0:int,1:int}|false', 'as_number='=>'false'], 'hrtime\'1' => ['int|float|false', 'as_number='=>'true'], 'is_countable' => ['bool', 'value'=>'mixed'], 'normalizer_get_raw_decomposition' => ['string|null', 'string'=>'string', 'form='=>'int'], 'net_get_interfaces' => ['array>|false'], 'openssl_pkey_derive' => ['string|false', 'public_key'=>'mixed', 'private_key'=>'mixed', 'key_length='=>'?int'], 'session_set_cookie_params\'1' => ['bool', 'options'=>'array{lifetime?:?int,path?:?string,domain?:?string,secure?:?bool,httponly?:?bool,samesite?:?string}'], 'setcookie\'1' => ['bool', 'name'=>'string', 'value='=>'string', 'options='=>'array'], 'setrawcookie\'1' => ['bool', 'name'=>'string', 'value='=>'string', 'options='=>'array'], 'socket_wsaprotocol_info_export' => ['string|false', 'socket'=>'resource', 'process_id'=>'int'], 'socket_wsaprotocol_info_import' => ['resource|false', 'info_id'=>'string'], 'socket_wsaprotocol_info_release' => ['bool', 'info_id'=>'string'], ], 'changed' => [ 'array_push' => [ 'old' => ['int', '&rw_array'=>'array', '...values'=>'mixed'], 'new' => ['int', '&rw_array'=>'array', '...values='=>'mixed'], ], 'array_unshift' => [ 'old' => ['int', '&rw_array'=>'array', '...values'=>'mixed'], 'new' => ['int', '&rw_array'=>'array', '...values='=>'mixed'], ], 'bcscale' => [ 'old' => ['int', 'scale'=>'int'], 'new' => ['int', 'scale='=>'int'], ], 'define' => [ 'old' => ['bool', 'constant_name'=>'string', 'value'=>'array|scalar|null', 'case_insensitive='=>'bool'], 'new' => ['bool', 'constant_name'=>'string', 'value'=>'array|scalar|null', 'case_insensitive='=>'false'], ], 'ldap_compare' => [ 'old' => ['bool|int', 'ldap'=>'resource', 'dn'=>'string', 'attribute'=>'string', 'value'=>'string'], 'new' => ['bool|int', 'ldap'=>'resource', 'dn'=>'string', 'attribute'=>'string', 'value'=>'string', 'controls='=>'array'], ], 'ldap_delete' => [ 'old' => ['bool', 'ldap'=>'resource', 'dn'=>'string'], 'new' => ['bool', 'ldap'=>'resource', 'dn'=>'string', 'controls='=>'array'], ], 'ldap_exop_passwd' => [ 'old' => ['bool|string', 'ldap'=>'resource', 'user='=>'string', 'old_password='=>'string', 'new_password='=>'string'], 'new' => ['bool|string', 'ldap'=>'resource', 'user='=>'string', 'old_password='=>'string', 'new_password='=>'string', '&w_controls='=>'array'], ], 'ldap_list' => [ 'old' => ['resource|false', 'ldap'=>'resource|array', 'base'=>'array|string', 'filter'=>'array|string', 'attributes='=>'array', 'attributes_only='=>'int', 'sizelimit='=>'int', 'timelimit='=>'int', 'deref='=>'int'], 'new' => ['resource|false', 'ldap'=>'resource|array', 'base'=>'array|string', 'filter'=>'array|string', 'attributes='=>'array', 'attributes_only='=>'int', 'sizelimit='=>'int', 'timelimit='=>'int', 'deref='=>'int', 'controls='=>'array'], ], 'ldap_mod_add' => [ 'old' => ['bool', 'ldap'=>'resource', 'dn'=>'string', 'entry'=>'array'], 'new' => ['bool', 'ldap'=>'resource', 'dn'=>'string', 'entry'=>'array', 'controls='=>'array'], ], 'ldap_mod_del' => [ 'old' => ['bool', 'ldap'=>'resource', 'dn'=>'string', 'entry'=>'array'], 'new' => ['bool', 'ldap'=>'resource', 'dn'=>'string', 'entry'=>'array', 'controls='=>'array'], ], 'ldap_mod_replace' => [ 'old' => ['bool', 'ldap'=>'resource', 'dn'=>'string', 'entry'=>'array'], 'new' => ['bool', 'ldap'=>'resource', 'dn'=>'string', 'entry'=>'array', 'controls='=>'array'], ], 'ldap_modify' => [ 'old' => ['bool', 'ldap'=>'resource', 'dn'=>'string', 'entry'=>'array'], 'new' => ['bool', 'ldap'=>'resource', 'dn'=>'string', 'entry'=>'array', 'controls='=>'array'], ], 'ldap_modify_batch' => [ 'old' => ['bool', 'ldap'=>'resource', 'dn'=>'string', 'modifications_info'=>'array'], 'new' => ['bool', 'ldap'=>'resource', 'dn'=>'string', 'modifications_info'=>'array', 'controls='=>'array'], ], 'ldap_read' => [ 'old' => ['resource|false', 'ldap'=>'resource|array', 'base'=>'array|string', 'filter'=>'array|string', 'attributes='=>'array', 'attributes_only='=>'int', 'sizelimit='=>'int', 'timelimit='=>'int', 'deref='=>'int'], 'new' => ['resource|false', 'ldap'=>'resource|array', 'base'=>'array|string', 'filter'=>'array|string', 'attributes='=>'array', 'attributes_only='=>'int', 'sizelimit='=>'int', 'timelimit='=>'int', 'deref='=>'int', 'controls='=>'array'], ], 'ldap_rename' => [ 'old' => ['bool', 'ldap'=>'resource', 'dn'=>'string', 'new_rdn'=>'string', 'new_parent'=>'string', 'delete_old_rdn'=>'bool'], 'new' => ['bool', 'ldap'=>'resource', 'dn'=>'string', 'new_rdn'=>'string', 'new_parent'=>'string', 'delete_old_rdn'=>'bool', 'controls='=>'array'], ], 'ldap_search' => [ 'old' => ['resource[]|resource|false', 'ldap'=>'resource|resource[]', 'base'=>'array|string', 'filter'=>'array|string', 'attributes='=>'array', 'attributes_only='=>'int', 'sizelimit='=>'int', 'timelimit='=>'int', 'deref='=>'int'], 'new' => ['resource[]|resource|false', 'ldap'=>'resource|resource[]', 'base'=>'array|string', 'filter'=>'array|string', 'attributes='=>'array', 'attributes_only='=>'int', 'sizelimit='=>'int', 'timelimit='=>'int', 'deref='=>'int', 'controls='=>'array'], ], 'mkdir' => [ 'old' => ['bool', 'directory'=>'string', 'permissions='=>'int', 'recursive='=>'bool', 'context='=>'resource'], 'new' => ['bool', 'directory'=>'string', 'permissions='=>'int', 'recursive='=>'bool', 'context='=>'null|resource'], ], 'session_get_cookie_params' => [ 'old' => ['array{lifetime:?int,path:?string,domain:?string,secure:?bool,httponly:?bool}'], 'new' => ['array{lifetime:?int,path:?string,domain:?string,secure:?bool,httponly:?bool,samesite:?string}'], ] ], 'removed' => [ ], ]; ['void', 'content_type='=>'string', 'content_encoding='=>'string', 'headers='=>'array', 'delivery_mode='=>'int', 'priority='=>'int', 'correlation_id='=>'string', 'reply_to='=>'string', 'expiration='=>'string', 'message_id='=>'string', 'timestamp='=>'int', 'type='=>'string', 'user_id='=>'string', 'app_id='=>'string', 'cluster_id='=>'string'], 'AMQPBasicProperties::getAppId' => ['string'], 'AMQPBasicProperties::getClusterId' => ['string'], 'AMQPBasicProperties::getContentEncoding' => ['string'], 'AMQPBasicProperties::getContentType' => ['string'], 'AMQPBasicProperties::getCorrelationId' => ['string'], 'AMQPBasicProperties::getDeliveryMode' => ['int'], 'AMQPBasicProperties::getExpiration' => ['string'], 'AMQPBasicProperties::getHeaders' => ['array'], 'AMQPBasicProperties::getMessageId' => ['string'], 'AMQPBasicProperties::getPriority' => ['int'], 'AMQPBasicProperties::getReplyTo' => ['string'], 'AMQPBasicProperties::getTimestamp' => ['string'], 'AMQPBasicProperties::getType' => ['string'], 'AMQPBasicProperties::getUserId' => ['string'], 'AMQPChannel::__construct' => ['void', 'amqp_connection'=>'AMQPConnection'], 'AMQPChannel::basicRecover' => ['', 'requeue='=>'bool'], 'AMQPChannel::close' => [''], 'AMQPChannel::commitTransaction' => ['bool'], 'AMQPChannel::confirmSelect' => [''], 'AMQPChannel::getChannelId' => ['int'], 'AMQPChannel::getConnection' => ['AMQPConnection'], 'AMQPChannel::getConsumers' => ['AMQPQueue[]'], 'AMQPChannel::getPrefetchCount' => ['int'], 'AMQPChannel::getPrefetchSize' => ['int'], 'AMQPChannel::isConnected' => ['bool'], 'AMQPChannel::qos' => ['bool', 'size'=>'int', 'count'=>'int'], 'AMQPChannel::rollbackTransaction' => ['bool'], 'AMQPChannel::setConfirmCallback' => ['', 'ack_callback='=>'?callable', 'nack_callback='=>'?callable'], 'AMQPChannel::setPrefetchCount' => ['bool', 'count'=>'int'], 'AMQPChannel::setPrefetchSize' => ['bool', 'size'=>'int'], 'AMQPChannel::setReturnCallback' => ['', 'return_callback='=>'?callable'], 'AMQPChannel::startTransaction' => ['bool'], 'AMQPChannel::waitForBasicReturn' => ['', 'timeout='=>'float'], 'AMQPChannel::waitForConfirm' => ['', 'timeout='=>'float'], 'AMQPConnection::__construct' => ['void', 'credentials='=>'array'], 'AMQPConnection::connect' => ['bool'], 'AMQPConnection::disconnect' => ['bool'], 'AMQPConnection::getCACert' => ['string'], 'AMQPConnection::getCert' => ['string'], 'AMQPConnection::getHeartbeatInterval' => ['int'], 'AMQPConnection::getHost' => ['string'], 'AMQPConnection::getKey' => ['string'], 'AMQPConnection::getLogin' => ['string'], 'AMQPConnection::getMaxChannels' => ['?int'], 'AMQPConnection::getMaxFrameSize' => ['int'], 'AMQPConnection::getPassword' => ['string'], 'AMQPConnection::getPort' => ['int'], 'AMQPConnection::getReadTimeout' => ['float'], 'AMQPConnection::getTimeout' => ['float'], 'AMQPConnection::getUsedChannels' => ['int'], 'AMQPConnection::getVerify' => ['bool'], 'AMQPConnection::getVhost' => ['string'], 'AMQPConnection::getWriteTimeout' => ['float'], 'AMQPConnection::isConnected' => ['bool'], 'AMQPConnection::isPersistent' => ['?bool'], 'AMQPConnection::pconnect' => ['bool'], 'AMQPConnection::pdisconnect' => ['bool'], 'AMQPConnection::preconnect' => ['bool'], 'AMQPConnection::reconnect' => ['bool'], 'AMQPConnection::setCACert' => ['', 'cacert'=>'string'], 'AMQPConnection::setCert' => ['', 'cert'=>'string'], 'AMQPConnection::setHost' => ['bool', 'host'=>'string'], 'AMQPConnection::setKey' => ['', 'key'=>'string'], 'AMQPConnection::setLogin' => ['bool', 'login'=>'string'], 'AMQPConnection::setPassword' => ['bool', 'password'=>'string'], 'AMQPConnection::setPort' => ['bool', 'port'=>'int'], 'AMQPConnection::setReadTimeout' => ['bool', 'timeout'=>'int'], 'AMQPConnection::setTimeout' => ['bool', 'timeout'=>'int'], 'AMQPConnection::setVerify' => ['', 'verify'=>'bool'], 'AMQPConnection::setVhost' => ['bool', 'vhost'=>'string'], 'AMQPConnection::setWriteTimeout' => ['bool', 'timeout'=>'int'], 'AMQPDecimal::__construct' => ['void', 'exponent'=>'', 'significand'=>''], 'AMQPDecimal::getExponent' => ['int'], 'AMQPDecimal::getSignificand' => ['int'], 'AMQPEnvelope::__construct' => ['void'], 'AMQPEnvelope::getAppId' => ['string'], 'AMQPEnvelope::getBody' => ['string'], 'AMQPEnvelope::getClusterId' => ['string'], 'AMQPEnvelope::getConsumerTag' => ['string'], 'AMQPEnvelope::getContentEncoding' => ['string'], 'AMQPEnvelope::getContentType' => ['string'], 'AMQPEnvelope::getCorrelationId' => ['string'], 'AMQPEnvelope::getDeliveryMode' => ['int'], 'AMQPEnvelope::getDeliveryTag' => ['string'], 'AMQPEnvelope::getExchangeName' => ['string'], 'AMQPEnvelope::getExpiration' => ['string'], 'AMQPEnvelope::getHeader' => ['string|false', 'header_key'=>'string'], 'AMQPEnvelope::getHeaders' => ['array'], 'AMQPEnvelope::getMessageId' => ['string'], 'AMQPEnvelope::getPriority' => ['int'], 'AMQPEnvelope::getReplyTo' => ['string'], 'AMQPEnvelope::getRoutingKey' => ['string'], 'AMQPEnvelope::getTimeStamp' => ['string'], 'AMQPEnvelope::getType' => ['string'], 'AMQPEnvelope::getUserId' => ['string'], 'AMQPEnvelope::hasHeader' => ['bool', 'header_key'=>'string'], 'AMQPEnvelope::isRedelivery' => ['bool'], 'AMQPExchange::__construct' => ['void', 'amqp_channel'=>'AMQPChannel'], 'AMQPExchange::bind' => ['bool', 'exchange_name'=>'string', 'routing_key='=>'string', 'arguments='=>'array'], 'AMQPExchange::declareExchange' => ['bool'], 'AMQPExchange::delete' => ['bool', 'exchangeName='=>'string', 'flags='=>'int'], 'AMQPExchange::getArgument' => ['int|string|false', 'key'=>'string'], 'AMQPExchange::getArguments' => ['array'], 'AMQPExchange::getChannel' => ['AMQPChannel'], 'AMQPExchange::getConnection' => ['AMQPConnection'], 'AMQPExchange::getFlags' => ['int'], 'AMQPExchange::getName' => ['string'], 'AMQPExchange::getType' => ['string'], 'AMQPExchange::hasArgument' => ['bool', 'key'=>'string'], 'AMQPExchange::publish' => ['bool', 'message'=>'string', 'routing_key='=>'string', 'flags='=>'int', 'attributes='=>'array'], 'AMQPExchange::setArgument' => ['bool', 'key'=>'string', 'value'=>'int|string'], 'AMQPExchange::setArguments' => ['bool', 'arguments'=>'array'], 'AMQPExchange::setFlags' => ['bool', 'flags'=>'int'], 'AMQPExchange::setName' => ['bool', 'exchange_name'=>'string'], 'AMQPExchange::setType' => ['bool', 'exchange_type'=>'string'], 'AMQPExchange::unbind' => ['bool', 'exchange_name'=>'string', 'routing_key='=>'string', 'arguments='=>'array'], 'AMQPQueue::__construct' => ['void', 'amqp_channel'=>'AMQPChannel'], 'AMQPQueue::ack' => ['bool', 'delivery_tag'=>'string', 'flags='=>'int'], 'AMQPQueue::bind' => ['bool', 'exchange_name'=>'string', 'routing_key='=>'string', 'arguments='=>'array'], 'AMQPQueue::cancel' => ['bool', 'consumer_tag='=>'string'], 'AMQPQueue::consume' => ['void', 'callback='=>'?callable', 'flags='=>'int', 'consumerTag='=>'string'], 'AMQPQueue::declareQueue' => ['int'], 'AMQPQueue::delete' => ['int', 'flags='=>'int'], 'AMQPQueue::get' => ['AMQPEnvelope|false', 'flags='=>'int'], 'AMQPQueue::getArgument' => ['int|string|false', 'key'=>'string'], 'AMQPQueue::getArguments' => ['array'], 'AMQPQueue::getChannel' => ['AMQPChannel'], 'AMQPQueue::getConnection' => ['AMQPConnection'], 'AMQPQueue::getConsumerTag' => ['?string'], 'AMQPQueue::getFlags' => ['int'], 'AMQPQueue::getName' => ['string'], 'AMQPQueue::hasArgument' => ['bool', 'key'=>'string'], 'AMQPQueue::nack' => ['bool', 'delivery_tag'=>'string', 'flags='=>'int'], 'AMQPQueue::purge' => ['bool'], 'AMQPQueue::reject' => ['bool', 'delivery_tag'=>'string', 'flags='=>'int'], 'AMQPQueue::setArgument' => ['bool', 'key'=>'string', 'value'=>'mixed'], 'AMQPQueue::setArguments' => ['bool', 'arguments'=>'array'], 'AMQPQueue::setFlags' => ['bool', 'flags'=>'int'], 'AMQPQueue::setName' => ['bool', 'queue_name'=>'string'], 'AMQPQueue::unbind' => ['bool', 'exchange_name'=>'string', 'routing_key='=>'string', 'arguments='=>'array'], 'AMQPTimestamp::__construct' => ['void', 'timestamp'=>'string'], 'AMQPTimestamp::__toString' => ['string'], 'AMQPTimestamp::getTimestamp' => ['string'], 'APCIterator::__construct' => ['void', 'cache'=>'string', 'search='=>'null|string|string[]', 'format='=>'int', 'chunk_size='=>'int', 'list='=>'int'], 'APCIterator::current' => ['mixed|false'], 'APCIterator::getTotalCount' => ['int|false'], 'APCIterator::getTotalHits' => ['int|false'], 'APCIterator::getTotalSize' => ['int|false'], 'APCIterator::key' => ['string'], 'APCIterator::next' => ['void'], 'APCIterator::rewind' => ['void'], 'APCIterator::valid' => ['bool'], 'APCuIterator::__construct' => ['void', 'search='=>'string|string[]|null', 'format='=>'int', 'chunk_size='=>'int', 'list='=>'int'], 'APCuIterator::current' => ['mixed'], 'APCuIterator::getTotalCount' => ['int'], 'APCuIterator::getTotalHits' => ['int'], 'APCuIterator::getTotalSize' => ['int'], 'APCuIterator::key' => ['string'], 'APCuIterator::next' => ['void'], 'APCuIterator::rewind' => ['void'], 'APCuIterator::valid' => ['bool'], 'AppendIterator::__construct' => ['void'], 'AppendIterator::append' => ['void', 'iterator'=>'Iterator'], 'AppendIterator::current' => ['mixed'], 'AppendIterator::getArrayIterator' => ['ArrayIterator'], 'AppendIterator::getInnerIterator' => ['Iterator'], 'AppendIterator::getIteratorIndex' => ['int'], 'AppendIterator::key' => ['int|string|float|bool'], 'AppendIterator::next' => ['void'], 'AppendIterator::rewind' => ['void'], 'AppendIterator::valid' => ['bool'], 'ArgumentCountError::__clone' => ['void'], 'ArgumentCountError::__construct' => ['void', 'message='=>'string', 'code='=>'int', 'previous='=>'?Throwable'], 'ArgumentCountError::__toString' => ['string'], 'ArgumentCountError::__wakeup' => ['void'], 'ArgumentCountError::getCode' => ['int'], 'ArgumentCountError::getFile' => ['string'], 'ArgumentCountError::getLine' => ['int'], 'ArgumentCountError::getMessage' => ['string'], 'ArgumentCountError::getPrevious' => ['?Throwable'], 'ArgumentCountError::getTrace' => ['list\',args?:array}>'], 'ArgumentCountError::getTraceAsString' => ['string'], 'ArithmeticError::__clone' => ['void'], 'ArithmeticError::__construct' => ['void', 'message='=>'string', 'code='=>'int', 'previous='=>'?Throwable'], 'ArithmeticError::__toString' => ['string'], 'ArithmeticError::__wakeup' => ['void'], 'ArithmeticError::getCode' => ['int'], 'ArithmeticError::getFile' => ['string'], 'ArithmeticError::getLine' => ['int'], 'ArithmeticError::getMessage' => ['string'], 'ArithmeticError::getPrevious' => ['?Throwable'], 'ArithmeticError::getTrace' => ['list\',args?:array}>'], 'ArithmeticError::getTraceAsString' => ['string'], 'ArrayAccess::offsetExists' => ['bool', 'offset'=>'int|string'], 'ArrayAccess::offsetGet' => ['mixed', 'offset'=>'int|string'], 'ArrayAccess::offsetSet' => ['void', 'offset'=>'int|string|null', 'value'=>'mixed'], 'ArrayAccess::offsetUnset' => ['void', 'offset'=>'int|string'], 'ArrayIterator::__construct' => ['void', 'array='=>'array|object', 'flags='=>'int'], 'ArrayIterator::append' => ['void', 'value'=>'mixed'], 'ArrayIterator::asort' => ['true', 'flags='=>'int'], 'ArrayIterator::count' => ['int'], 'ArrayIterator::current' => ['mixed'], 'ArrayIterator::getArrayCopy' => ['array'], 'ArrayIterator::getFlags' => ['int'], 'ArrayIterator::key' => ['int|string|null'], 'ArrayIterator::ksort' => ['true', 'flags='=>'int'], 'ArrayIterator::natcasesort' => ['true'], 'ArrayIterator::natsort' => ['true'], 'ArrayIterator::next' => ['void'], 'ArrayIterator::offsetExists' => ['bool', 'key'=>'string|int'], 'ArrayIterator::offsetGet' => ['mixed', 'key'=>'string|int'], 'ArrayIterator::offsetSet' => ['void', 'key'=>'string|int|null', 'value'=>'mixed'], 'ArrayIterator::offsetUnset' => ['void', 'key'=>'string|int'], 'ArrayIterator::rewind' => ['void'], 'ArrayIterator::seek' => ['void', 'offset'=>'int'], 'ArrayIterator::serialize' => ['string'], 'ArrayIterator::setFlags' => ['void', 'flags'=>'int'], 'ArrayIterator::uasort' => ['true', 'callback'=>'callable(mixed,mixed):int'], 'ArrayIterator::uksort' => ['true', 'callback'=>'callable(mixed,mixed):int'], 'ArrayIterator::unserialize' => ['void', 'data'=>'string'], 'ArrayIterator::valid' => ['bool'], 'ArrayObject::__construct' => ['void', 'array='=>'array|object', 'flags='=>'int', 'iteratorClass='=>'class-string'], 'ArrayObject::append' => ['void', 'value'=>'mixed'], 'ArrayObject::asort' => ['true', 'flags='=>'int'], 'ArrayObject::count' => ['int'], 'ArrayObject::exchangeArray' => ['array', 'array'=>'array|object'], 'ArrayObject::getArrayCopy' => ['array'], 'ArrayObject::getFlags' => ['int'], 'ArrayObject::getIterator' => ['ArrayIterator'], 'ArrayObject::getIteratorClass' => ['string'], 'ArrayObject::ksort' => ['true', 'flags='=>'int'], 'ArrayObject::natcasesort' => ['true'], 'ArrayObject::natsort' => ['true'], 'ArrayObject::offsetExists' => ['bool', 'key'=>'int|string'], 'ArrayObject::offsetGet' => ['mixed|null', 'key'=>'int|string'], 'ArrayObject::offsetSet' => ['void', 'key'=>'int|string|null', 'value'=>'mixed'], 'ArrayObject::offsetUnset' => ['void', 'key'=>'int|string'], 'ArrayObject::serialize' => ['string'], 'ArrayObject::setFlags' => ['void', 'flags'=>'int'], 'ArrayObject::setIteratorClass' => ['void', 'iteratorClass'=>'class-string'], 'ArrayObject::uasort' => ['true', 'callback'=>'callable(mixed,mixed):int'], 'ArrayObject::uksort' => ['true', 'callback'=>'callable(mixed,mixed):int'], 'ArrayObject::unserialize' => ['void', 'data'=>'string'], 'BadFunctionCallException::__clone' => ['void'], 'BadFunctionCallException::__construct' => ['void', 'message='=>'string', 'code='=>'int', 'previous='=>'?Throwable'], 'BadFunctionCallException::__toString' => ['string'], 'BadFunctionCallException::getCode' => ['int'], 'BadFunctionCallException::getFile' => ['string'], 'BadFunctionCallException::getLine' => ['int'], 'BadFunctionCallException::getMessage' => ['string'], 'BadFunctionCallException::getPrevious' => ['?Throwable'], 'BadFunctionCallException::getTrace' => ['list\',args?:array}>'], 'BadFunctionCallException::getTraceAsString' => ['string'], 'BadMethodCallException::__clone' => ['void'], 'BadMethodCallException::__construct' => ['void', 'message='=>'string', 'code='=>'int', 'previous='=>'?Throwable'], 'BadMethodCallException::__toString' => ['string'], 'BadMethodCallException::getCode' => ['int'], 'BadMethodCallException::getFile' => ['string'], 'BadMethodCallException::getLine' => ['int'], 'BadMethodCallException::getMessage' => ['string'], 'BadMethodCallException::getPrevious' => ['?Throwable'], 'BadMethodCallException::getTrace' => ['list\',args?:array}>'], 'BadMethodCallException::getTraceAsString' => ['string'], 'COM::__call' => ['', 'name'=>'', 'args'=>''], 'COM::__construct' => ['void', 'module_name'=>'string', 'server_name='=>'mixed', 'codepage='=>'int', 'typelib='=>'string'], 'COM::__get' => ['', 'name'=>''], 'COM::__set' => ['void', 'name'=>'', 'value'=>''], 'COMPersistHelper::GetCurFile' => ['string'], 'COMPersistHelper::GetCurFileName' => ['string'], 'COMPersistHelper::GetMaxStreamSize' => ['int'], 'COMPersistHelper::InitNew' => ['int'], 'COMPersistHelper::LoadFromFile' => ['bool', 'filename'=>'string', 'flags'=>'int'], 'COMPersistHelper::LoadFromStream' => ['', 'stream'=>''], 'COMPersistHelper::SaveToFile' => ['bool', 'filename'=>'string', 'remember'=>'bool'], 'COMPersistHelper::SaveToStream' => ['int', 'stream'=>''], 'COMPersistHelper::__construct' => ['void', 'variant'=>'object'], 'CURLFile::__construct' => ['void', 'filename'=>'string', 'mime_type='=>'string', 'posted_filename='=>'string'], 'CURLFile::getFilename' => ['string'], 'CURLFile::getMimeType' => ['string'], 'CURLFile::getPostFilename' => ['string'], 'CURLFile::setMimeType' => ['void', 'mime_type'=>'string'], 'CURLFile::setPostFilename' => ['void', 'posted_filename'=>'string'], 'CachingIterator::__construct' => ['void', 'iterator'=>'Iterator', 'flags='=>''], 'CachingIterator::__toString' => ['string'], 'CachingIterator::count' => ['int'], 'CachingIterator::current' => ['mixed'], 'CachingIterator::getCache' => ['array'], 'CachingIterator::getFlags' => ['int'], 'CachingIterator::getInnerIterator' => ['Iterator'], 'CachingIterator::hasNext' => ['bool'], 'CachingIterator::key' => ['int|string|float|bool'], 'CachingIterator::next' => ['void'], 'CachingIterator::offsetExists' => ['bool', 'key'=>'string'], 'CachingIterator::offsetGet' => ['mixed', 'key'=>'string'], 'CachingIterator::offsetSet' => ['void', 'key'=>'string', 'value'=>'mixed'], 'CachingIterator::offsetUnset' => ['void', 'key'=>'string'], 'CachingIterator::rewind' => ['void'], 'CachingIterator::setFlags' => ['void', 'flags'=>'int'], 'CachingIterator::valid' => ['bool'], 'CallbackFilterIterator::__construct' => ['void', 'iterator'=>'Iterator', 'callback'=>'callable(mixed,mixed=,mixed=):bool'], 'CallbackFilterIterator::accept' => ['bool'], 'CallbackFilterIterator::current' => ['mixed'], 'CallbackFilterIterator::getInnerIterator' => ['Iterator'], 'CallbackFilterIterator::key' => ['mixed'], 'CallbackFilterIterator::next' => ['void'], 'CallbackFilterIterator::rewind' => ['void'], 'CallbackFilterIterator::valid' => ['bool'], 'ClosedGeneratorException::__clone' => ['void'], 'ClosedGeneratorException::__toString' => ['string'], 'ClosedGeneratorException::getCode' => ['int'], 'ClosedGeneratorException::getFile' => ['string'], 'ClosedGeneratorException::getLine' => ['int'], 'ClosedGeneratorException::getMessage' => ['string'], 'ClosedGeneratorException::getPrevious' => ['?Throwable'], 'ClosedGeneratorException::getTrace' => ['list\',args?:array}>'], 'ClosedGeneratorException::getTraceAsString' => ['string'], 'Closure::__construct' => ['void'], 'Closure::__invoke' => ['', '...args='=>''], 'Closure::bind' => ['?Closure', 'closure'=>'Closure', 'newThis'=>'?object', 'newScope='=>'object|string|null'], 'Closure::bindTo' => ['?Closure', 'newThis'=>'?object', 'newScope='=>'object|string|null'], 'Closure::call' => ['mixed', 'newThis'=>'object', '...args='=>'mixed'], 'Collator::__construct' => ['void', 'locale'=>'string'], 'Collator::asort' => ['bool', '&rw_array'=>'array', 'flags='=>'int'], 'Collator::compare' => ['int|false', 'string1'=>'string', 'string2'=>'string'], 'Collator::create' => ['?Collator', 'locale'=>'string'], 'Collator::getAttribute' => ['int|false', 'attribute'=>'int'], 'Collator::getErrorCode' => ['int'], 'Collator::getErrorMessage' => ['string'], 'Collator::getLocale' => ['string', 'type'=>'int'], 'Collator::getSortKey' => ['string|false', 'string'=>'string'], 'Collator::getStrength' => ['int|false'], 'Collator::setAttribute' => ['bool', 'attribute'=>'int', 'value'=>'int'], 'Collator::setStrength' => ['bool', 'strength'=>'int'], 'Collator::sort' => ['bool', '&rw_array'=>'array', 'flags='=>'int'], 'Collator::sortWithSortKeys' => ['bool', '&rw_array'=>'array'], 'Collectable::isGarbage' => ['bool'], 'Collectable::setGarbage' => ['void'], 'Cond::broadcast' => ['bool', 'condition'=>'long'], 'Cond::create' => ['long'], 'Cond::destroy' => ['bool', 'condition'=>'long'], 'Cond::signal' => ['bool', 'condition'=>'long'], 'Cond::wait' => ['bool', 'condition'=>'long', 'mutex'=>'long', 'timeout='=>'long'], 'Couchbase\AnalyticsQuery::__construct' => ['void'], 'Couchbase\AnalyticsQuery::fromString' => ['Couchbase\AnalyticsQuery', 'statement'=>'string'], 'Couchbase\BooleanFieldSearchQuery::__construct' => ['void'], 'Couchbase\BooleanFieldSearchQuery::boost' => ['Couchbase\BooleanFieldSearchQuery', 'boost'=>'float'], 'Couchbase\BooleanFieldSearchQuery::field' => ['Couchbase\BooleanFieldSearchQuery', 'field'=>'string'], 'Couchbase\BooleanFieldSearchQuery::jsonSerialize' => ['array'], 'Couchbase\BooleanSearchQuery::__construct' => ['void'], 'Couchbase\BooleanSearchQuery::boost' => ['Couchbase\BooleanSearchQuery', 'boost'=>'float'], 'Couchbase\BooleanSearchQuery::jsonSerialize' => ['array'], 'Couchbase\BooleanSearchQuery::must' => ['Couchbase\BooleanSearchQuery', '...queries='=>'array'], 'Couchbase\BooleanSearchQuery::mustNot' => ['Couchbase\BooleanSearchQuery', '...queries='=>'array'], 'Couchbase\BooleanSearchQuery::should' => ['Couchbase\BooleanSearchQuery', '...queries='=>'array'], 'Couchbase\Bucket::__construct' => ['void'], 'Couchbase\Bucket::__get' => ['int', 'name'=>'string'], 'Couchbase\Bucket::__set' => ['int', 'name'=>'string', 'value'=>'int'], 'Couchbase\Bucket::append' => ['Couchbase\Document|array', 'ids'=>'array|string', 'value'=>'mixed', 'options='=>'array'], 'Couchbase\Bucket::counter' => ['Couchbase\Document|array', 'ids'=>'array|string', 'delta='=>'int', 'options='=>'array'], 'Couchbase\Bucket::decryptFields' => ['array', 'document'=>'array', 'fieldOptions'=>'', 'prefix='=>'string'], 'Couchbase\Bucket::diag' => ['array', 'reportId='=>'string'], 'Couchbase\Bucket::encryptFields' => ['array', 'document'=>'array', 'fieldOptions'=>'', 'prefix='=>'string'], 'Couchbase\Bucket::get' => ['Couchbase\Document|array', 'ids'=>'array|string', 'options='=>'array'], 'Couchbase\Bucket::getAndLock' => ['Couchbase\Document|array', 'ids'=>'array|string', 'lockTime'=>'int', 'options='=>'array'], 'Couchbase\Bucket::getAndTouch' => ['Couchbase\Document|array', 'ids'=>'array|string', 'expiry'=>'int', 'options='=>'array'], 'Couchbase\Bucket::getFromReplica' => ['Couchbase\Document|array', 'ids'=>'array|string', 'options='=>'array'], 'Couchbase\Bucket::getName' => ['string'], 'Couchbase\Bucket::insert' => ['Couchbase\Document|array', 'ids'=>'array|string', 'value'=>'mixed', 'options='=>'array'], 'Couchbase\Bucket::listExists' => ['bool', 'id'=>'string', 'value'=>'mixed'], 'Couchbase\Bucket::listGet' => ['mixed', 'id'=>'string', 'index'=>'int'], 'Couchbase\Bucket::listPush' => ['', 'id'=>'string', 'value'=>'mixed'], 'Couchbase\Bucket::listRemove' => ['', 'id'=>'string', 'index'=>'int'], 'Couchbase\Bucket::listSet' => ['', 'id'=>'string', 'index'=>'int', 'value'=>'mixed'], 'Couchbase\Bucket::listShift' => ['', 'id'=>'string', 'value'=>'mixed'], 'Couchbase\Bucket::listSize' => ['int', 'id'=>'string'], 'Couchbase\Bucket::lookupIn' => ['Couchbase\LookupInBuilder', 'id'=>'string'], 'Couchbase\Bucket::manager' => ['Couchbase\BucketManager'], 'Couchbase\Bucket::mapAdd' => ['', 'id'=>'string', 'key'=>'string', 'value'=>'mixed'], 'Couchbase\Bucket::mapGet' => ['mixed', 'id'=>'string', 'key'=>'string'], 'Couchbase\Bucket::mapRemove' => ['', 'id'=>'string', 'key'=>'string'], 'Couchbase\Bucket::mapSize' => ['int', 'id'=>'string'], 'Couchbase\Bucket::mutateIn' => ['Couchbase\MutateInBuilder', 'id'=>'string', 'cas'=>'string'], 'Couchbase\Bucket::ping' => ['array', 'services='=>'int', 'reportId='=>'string'], 'Couchbase\Bucket::prepend' => ['Couchbase\Document|array', 'ids'=>'array|string', 'value'=>'mixed', 'options='=>'array'], 'Couchbase\Bucket::query' => ['object', 'query'=>'Couchbase\AnalyticsQuery|Couchbase\N1qlQuery|Couchbase\SearchQuery|Couchbase\SpatialViewQuery|Couchbase\ViewQuery', 'jsonAsArray='=>'bool'], 'Couchbase\Bucket::queueAdd' => ['', 'id'=>'string', 'value'=>'mixed'], 'Couchbase\Bucket::queueExists' => ['bool', 'id'=>'string', 'value'=>'mixed'], 'Couchbase\Bucket::queueRemove' => ['mixed', 'id'=>'string'], 'Couchbase\Bucket::queueSize' => ['int', 'id'=>'string'], 'Couchbase\Bucket::remove' => ['Couchbase\Document|array', 'ids'=>'array|string', 'options='=>'array'], 'Couchbase\Bucket::replace' => ['Couchbase\Document|array', 'ids'=>'array|string', 'value'=>'mixed', 'options='=>'array'], 'Couchbase\Bucket::retrieveIn' => ['Couchbase\DocumentFragment', 'id'=>'string', '...paths='=>'array'], 'Couchbase\Bucket::setAdd' => ['', 'id'=>'string', 'value'=>'bool|float|int|string'], 'Couchbase\Bucket::setExists' => ['bool', 'id'=>'string', 'value'=>'bool|float|int|string'], 'Couchbase\Bucket::setRemove' => ['', 'id'=>'string', 'value'=>'bool|float|int|string'], 'Couchbase\Bucket::setSize' => ['int', 'id'=>'string'], 'Couchbase\Bucket::setTranscoder' => ['', 'encoder'=>'callable', 'decoder'=>'callable'], 'Couchbase\Bucket::touch' => ['Couchbase\Document|array', 'ids'=>'array|string', 'expiry'=>'int', 'options='=>'array'], 'Couchbase\Bucket::unlock' => ['Couchbase\Document|array', 'ids'=>'array|string', 'options='=>'array'], 'Couchbase\Bucket::upsert' => ['Couchbase\Document|array', 'ids'=>'array|string', 'value'=>'mixed', 'options='=>'array'], 'Couchbase\BucketManager::__construct' => ['void'], 'Couchbase\BucketManager::createN1qlIndex' => ['', 'name'=>'string', 'fields'=>'array', 'whereClause='=>'string', 'ignoreIfExist='=>'bool', 'defer='=>'bool'], 'Couchbase\BucketManager::createN1qlPrimaryIndex' => ['', 'customName='=>'string', 'ignoreIfExist='=>'bool', 'defer='=>'bool'], 'Couchbase\BucketManager::dropN1qlIndex' => ['', 'name'=>'string', 'ignoreIfNotExist='=>'bool'], 'Couchbase\BucketManager::dropN1qlPrimaryIndex' => ['', 'customName='=>'string', 'ignoreIfNotExist='=>'bool'], 'Couchbase\BucketManager::flush' => [''], 'Couchbase\BucketManager::getDesignDocument' => ['array', 'name'=>'string'], 'Couchbase\BucketManager::info' => ['array'], 'Couchbase\BucketManager::insertDesignDocument' => ['', 'name'=>'string', 'document'=>'array'], 'Couchbase\BucketManager::listDesignDocuments' => ['array'], 'Couchbase\BucketManager::listN1qlIndexes' => ['array'], 'Couchbase\BucketManager::removeDesignDocument' => ['', 'name'=>'string'], 'Couchbase\BucketManager::upsertDesignDocument' => ['', 'name'=>'string', 'document'=>'array'], 'Couchbase\ClassicAuthenticator::bucket' => ['', 'name'=>'string', 'password'=>'string'], 'Couchbase\ClassicAuthenticator::cluster' => ['', 'username'=>'string', 'password'=>'string'], 'Couchbase\Cluster::__construct' => ['void', 'connstr'=>'string'], 'Couchbase\Cluster::authenticate' => ['null', 'authenticator'=>'Couchbase\Authenticator'], 'Couchbase\Cluster::authenticateAs' => ['null', 'username'=>'string', 'password'=>'string'], 'Couchbase\Cluster::manager' => ['Couchbase\ClusterManager', 'username='=>'string', 'password='=>'string'], 'Couchbase\Cluster::openBucket' => ['Couchbase\Bucket', 'name='=>'string', 'password='=>'string'], 'Couchbase\ClusterManager::__construct' => ['void'], 'Couchbase\ClusterManager::createBucket' => ['', 'name'=>'string', 'options='=>'array'], 'Couchbase\ClusterManager::getUser' => ['array', 'username'=>'string', 'domain='=>'int'], 'Couchbase\ClusterManager::info' => ['array'], 'Couchbase\ClusterManager::listBuckets' => ['array'], 'Couchbase\ClusterManager::listUsers' => ['array', 'domain='=>'int'], 'Couchbase\ClusterManager::removeBucket' => ['', 'name'=>'string'], 'Couchbase\ClusterManager::removeUser' => ['', 'name'=>'string', 'domain='=>'int'], 'Couchbase\ClusterManager::upsertUser' => ['', 'name'=>'string', 'settings'=>'Couchbase\UserSettings', 'domain='=>'int'], 'Couchbase\ConjunctionSearchQuery::__construct' => ['void'], 'Couchbase\ConjunctionSearchQuery::boost' => ['Couchbase\ConjunctionSearchQuery', 'boost'=>'float'], 'Couchbase\ConjunctionSearchQuery::every' => ['Couchbase\ConjunctionSearchQuery', '...queries='=>'array'], 'Couchbase\ConjunctionSearchQuery::jsonSerialize' => ['array'], 'Couchbase\DateRangeSearchFacet::__construct' => ['void'], 'Couchbase\DateRangeSearchFacet::addRange' => ['Couchbase\DateRangeSearchFacet', 'name'=>'string', 'start'=>'int|string', 'end'=>'int|string'], 'Couchbase\DateRangeSearchFacet::jsonSerialize' => ['array'], 'Couchbase\DateRangeSearchQuery::__construct' => ['void'], 'Couchbase\DateRangeSearchQuery::boost' => ['Couchbase\DateRangeSearchQuery', 'boost'=>'float'], 'Couchbase\DateRangeSearchQuery::dateTimeParser' => ['Couchbase\DateRangeSearchQuery', 'dateTimeParser'=>'string'], 'Couchbase\DateRangeSearchQuery::end' => ['Couchbase\DateRangeSearchQuery', 'end'=>'int|string', 'inclusive='=>'bool'], 'Couchbase\DateRangeSearchQuery::field' => ['Couchbase\DateRangeSearchQuery', 'field'=>'string'], 'Couchbase\DateRangeSearchQuery::jsonSerialize' => ['array'], 'Couchbase\DateRangeSearchQuery::start' => ['Couchbase\DateRangeSearchQuery', 'start'=>'int|string', 'inclusive='=>'bool'], 'Couchbase\DisjunctionSearchQuery::__construct' => ['void'], 'Couchbase\DisjunctionSearchQuery::boost' => ['Couchbase\DisjunctionSearchQuery', 'boost'=>'float'], 'Couchbase\DisjunctionSearchQuery::either' => ['Couchbase\DisjunctionSearchQuery', '...queries='=>'array'], 'Couchbase\DisjunctionSearchQuery::jsonSerialize' => ['array'], 'Couchbase\DisjunctionSearchQuery::min' => ['Couchbase\DisjunctionSearchQuery', 'min'=>'int'], 'Couchbase\DocIdSearchQuery::__construct' => ['void'], 'Couchbase\DocIdSearchQuery::boost' => ['Couchbase\DocIdSearchQuery', 'boost'=>'float'], 'Couchbase\DocIdSearchQuery::docIds' => ['Couchbase\DocIdSearchQuery', '...documentIds='=>'array'], 'Couchbase\DocIdSearchQuery::field' => ['Couchbase\DocIdSearchQuery', 'field'=>'string'], 'Couchbase\DocIdSearchQuery::jsonSerialize' => ['array'], 'Couchbase\GeoBoundingBoxSearchQuery::__construct' => ['void'], 'Couchbase\GeoBoundingBoxSearchQuery::boost' => ['Couchbase\GeoBoundingBoxSearchQuery', 'boost'=>'float'], 'Couchbase\GeoBoundingBoxSearchQuery::field' => ['Couchbase\GeoBoundingBoxSearchQuery', 'field'=>'string'], 'Couchbase\GeoBoundingBoxSearchQuery::jsonSerialize' => ['array'], 'Couchbase\GeoDistanceSearchQuery::__construct' => ['void'], 'Couchbase\GeoDistanceSearchQuery::boost' => ['Couchbase\GeoDistanceSearchQuery', 'boost'=>'float'], 'Couchbase\GeoDistanceSearchQuery::field' => ['Couchbase\GeoDistanceSearchQuery', 'field'=>'string'], 'Couchbase\GeoDistanceSearchQuery::jsonSerialize' => ['array'], 'Couchbase\LookupInBuilder::__construct' => ['void'], 'Couchbase\LookupInBuilder::execute' => ['Couchbase\DocumentFragment'], 'Couchbase\LookupInBuilder::exists' => ['Couchbase\LookupInBuilder', 'path'=>'string', 'options='=>'array'], 'Couchbase\LookupInBuilder::get' => ['Couchbase\LookupInBuilder', 'path'=>'string', 'options='=>'array'], 'Couchbase\LookupInBuilder::getCount' => ['Couchbase\LookupInBuilder', 'path'=>'string', 'options='=>'array'], 'Couchbase\MatchAllSearchQuery::__construct' => ['void'], 'Couchbase\MatchAllSearchQuery::boost' => ['Couchbase\MatchAllSearchQuery', 'boost'=>'float'], 'Couchbase\MatchAllSearchQuery::jsonSerialize' => ['array'], 'Couchbase\MatchNoneSearchQuery::__construct' => ['void'], 'Couchbase\MatchNoneSearchQuery::boost' => ['Couchbase\MatchNoneSearchQuery', 'boost'=>'float'], 'Couchbase\MatchNoneSearchQuery::jsonSerialize' => ['array'], 'Couchbase\MatchPhraseSearchQuery::__construct' => ['void'], 'Couchbase\MatchPhraseSearchQuery::analyzer' => ['Couchbase\MatchPhraseSearchQuery', 'analyzer'=>'string'], 'Couchbase\MatchPhraseSearchQuery::boost' => ['Couchbase\MatchPhraseSearchQuery', 'boost'=>'float'], 'Couchbase\MatchPhraseSearchQuery::field' => ['Couchbase\MatchPhraseSearchQuery', 'field'=>'string'], 'Couchbase\MatchPhraseSearchQuery::jsonSerialize' => ['array'], 'Couchbase\MatchSearchQuery::__construct' => ['void'], 'Couchbase\MatchSearchQuery::analyzer' => ['Couchbase\MatchSearchQuery', 'analyzer'=>'string'], 'Couchbase\MatchSearchQuery::boost' => ['Couchbase\MatchSearchQuery', 'boost'=>'float'], 'Couchbase\MatchSearchQuery::field' => ['Couchbase\MatchSearchQuery', 'field'=>'string'], 'Couchbase\MatchSearchQuery::fuzziness' => ['Couchbase\MatchSearchQuery', 'fuzziness'=>'int'], 'Couchbase\MatchSearchQuery::jsonSerialize' => ['array'], 'Couchbase\MatchSearchQuery::prefixLength' => ['Couchbase\MatchSearchQuery', 'prefixLength'=>'int'], 'Couchbase\MutateInBuilder::__construct' => ['void'], 'Couchbase\MutateInBuilder::arrayAddUnique' => ['Couchbase\MutateInBuilder', 'path'=>'string', 'value'=>'mixed', 'options='=>'array|bool'], 'Couchbase\MutateInBuilder::arrayAppend' => ['Couchbase\MutateInBuilder', 'path'=>'string', 'value'=>'mixed', 'options='=>'array|bool'], 'Couchbase\MutateInBuilder::arrayAppendAll' => ['Couchbase\MutateInBuilder', 'path'=>'string', 'values'=>'array', 'options='=>'array|bool'], 'Couchbase\MutateInBuilder::arrayInsert' => ['Couchbase\MutateInBuilder', 'path'=>'string', 'value'=>'mixed', 'options='=>'array'], 'Couchbase\MutateInBuilder::arrayInsertAll' => ['Couchbase\MutateInBuilder', 'path'=>'string', 'values'=>'array', 'options='=>'array'], 'Couchbase\MutateInBuilder::arrayPrepend' => ['Couchbase\MutateInBuilder', 'path'=>'string', 'value'=>'mixed', 'options='=>'array|bool'], 'Couchbase\MutateInBuilder::arrayPrependAll' => ['Couchbase\MutateInBuilder', 'path'=>'string', 'values'=>'array', 'options='=>'array|bool'], 'Couchbase\MutateInBuilder::counter' => ['Couchbase\MutateInBuilder', 'path'=>'string', 'delta'=>'int', 'options='=>'array|bool'], 'Couchbase\MutateInBuilder::execute' => ['Couchbase\DocumentFragment'], 'Couchbase\MutateInBuilder::insert' => ['Couchbase\MutateInBuilder', 'path'=>'string', 'value'=>'mixed', 'options='=>'array|bool'], 'Couchbase\MutateInBuilder::modeDocument' => ['', 'mode'=>'int'], 'Couchbase\MutateInBuilder::remove' => ['Couchbase\MutateInBuilder', 'path'=>'string', 'options='=>'array'], 'Couchbase\MutateInBuilder::replace' => ['Couchbase\MutateInBuilder', 'path'=>'string', 'value'=>'mixed', 'options='=>'array'], 'Couchbase\MutateInBuilder::upsert' => ['Couchbase\MutateInBuilder', 'path'=>'string', 'value'=>'mixed', 'options='=>'array|bool'], 'Couchbase\MutateInBuilder::withExpiry' => ['Couchbase\MutateInBuilder', 'expiry'=>'Couchbase\expiry'], 'Couchbase\MutationState::__construct' => ['void'], 'Couchbase\MutationState::add' => ['', 'source'=>'Couchbase\Document|Couchbase\DocumentFragment|array'], 'Couchbase\MutationState::from' => ['Couchbase\MutationState', 'source'=>'Couchbase\Document|Couchbase\DocumentFragment|array'], 'Couchbase\MutationToken::__construct' => ['void'], 'Couchbase\MutationToken::bucketName' => ['string'], 'Couchbase\MutationToken::from' => ['', 'bucketName'=>'string', 'vbucketId'=>'int', 'vbucketUuid'=>'string', 'sequenceNumber'=>'string'], 'Couchbase\MutationToken::sequenceNumber' => ['string'], 'Couchbase\MutationToken::vbucketId' => ['int'], 'Couchbase\MutationToken::vbucketUuid' => ['string'], 'Couchbase\N1qlIndex::__construct' => ['void'], 'Couchbase\N1qlQuery::__construct' => ['void'], 'Couchbase\N1qlQuery::adhoc' => ['Couchbase\N1qlQuery', 'adhoc'=>'bool'], 'Couchbase\N1qlQuery::consistency' => ['Couchbase\N1qlQuery', 'consistency'=>'int'], 'Couchbase\N1qlQuery::consistentWith' => ['Couchbase\N1qlQuery', 'state'=>'Couchbase\MutationState'], 'Couchbase\N1qlQuery::crossBucket' => ['Couchbase\N1qlQuery', 'crossBucket'=>'bool'], 'Couchbase\N1qlQuery::fromString' => ['Couchbase\N1qlQuery', 'statement'=>'string'], 'Couchbase\N1qlQuery::maxParallelism' => ['Couchbase\N1qlQuery', 'maxParallelism'=>'int'], 'Couchbase\N1qlQuery::namedParams' => ['Couchbase\N1qlQuery', 'params'=>'array'], 'Couchbase\N1qlQuery::pipelineBatch' => ['Couchbase\N1qlQuery', 'pipelineBatch'=>'int'], 'Couchbase\N1qlQuery::pipelineCap' => ['Couchbase\N1qlQuery', 'pipelineCap'=>'int'], 'Couchbase\N1qlQuery::positionalParams' => ['Couchbase\N1qlQuery', 'params'=>'array'], 'Couchbase\N1qlQuery::profile' => ['', 'profileType'=>'string'], 'Couchbase\N1qlQuery::readonly' => ['Couchbase\N1qlQuery', 'readonly'=>'bool'], 'Couchbase\N1qlQuery::scanCap' => ['Couchbase\N1qlQuery', 'scanCap'=>'int'], 'Couchbase\NumericRangeSearchFacet::__construct' => ['void'], 'Couchbase\NumericRangeSearchFacet::addRange' => ['Couchbase\NumericRangeSearchFacet', 'name'=>'string', 'min'=>'float', 'max'=>'float'], 'Couchbase\NumericRangeSearchFacet::jsonSerialize' => ['array'], 'Couchbase\NumericRangeSearchQuery::__construct' => ['void'], 'Couchbase\NumericRangeSearchQuery::boost' => ['Couchbase\NumericRangeSearchQuery', 'boost'=>'float'], 'Couchbase\NumericRangeSearchQuery::field' => ['Couchbase\NumericRangeSearchQuery', 'field'=>'string'], 'Couchbase\NumericRangeSearchQuery::jsonSerialize' => ['array'], 'Couchbase\NumericRangeSearchQuery::max' => ['Couchbase\NumericRangeSearchQuery', 'max'=>'float', 'inclusive='=>'bool'], 'Couchbase\NumericRangeSearchQuery::min' => ['Couchbase\NumericRangeSearchQuery', 'min'=>'float', 'inclusive='=>'bool'], 'Couchbase\PasswordAuthenticator::password' => ['Couchbase\PasswordAuthenticator', 'password'=>'string'], 'Couchbase\PasswordAuthenticator::username' => ['Couchbase\PasswordAuthenticator', 'username'=>'string'], 'Couchbase\PhraseSearchQuery::__construct' => ['void'], 'Couchbase\PhraseSearchQuery::boost' => ['Couchbase\PhraseSearchQuery', 'boost'=>'float'], 'Couchbase\PhraseSearchQuery::field' => ['Couchbase\PhraseSearchQuery', 'field'=>'string'], 'Couchbase\PhraseSearchQuery::jsonSerialize' => ['array'], 'Couchbase\PrefixSearchQuery::__construct' => ['void'], 'Couchbase\PrefixSearchQuery::boost' => ['Couchbase\PrefixSearchQuery', 'boost'=>'float'], 'Couchbase\PrefixSearchQuery::field' => ['Couchbase\PrefixSearchQuery', 'field'=>'string'], 'Couchbase\PrefixSearchQuery::jsonSerialize' => ['array'], 'Couchbase\QueryStringSearchQuery::__construct' => ['void'], 'Couchbase\QueryStringSearchQuery::boost' => ['Couchbase\QueryStringSearchQuery', 'boost'=>'float'], 'Couchbase\QueryStringSearchQuery::jsonSerialize' => ['array'], 'Couchbase\RegexpSearchQuery::__construct' => ['void'], 'Couchbase\RegexpSearchQuery::boost' => ['Couchbase\RegexpSearchQuery', 'boost'=>'float'], 'Couchbase\RegexpSearchQuery::field' => ['Couchbase\RegexpSearchQuery', 'field'=>'string'], 'Couchbase\RegexpSearchQuery::jsonSerialize' => ['array'], 'Couchbase\SearchQuery::__construct' => ['void', 'indexName'=>'string', 'queryPart'=>'Couchbase\SearchQueryPart'], 'Couchbase\SearchQuery::addFacet' => ['Couchbase\SearchQuery', 'name'=>'string', 'facet'=>'Couchbase\SearchFacet'], 'Couchbase\SearchQuery::boolean' => ['Couchbase\BooleanSearchQuery'], 'Couchbase\SearchQuery::booleanField' => ['Couchbase\BooleanFieldSearchQuery', 'value'=>'bool'], 'Couchbase\SearchQuery::conjuncts' => ['Couchbase\ConjunctionSearchQuery', '...queries='=>'array'], 'Couchbase\SearchQuery::consistentWith' => ['Couchbase\SearchQuery', 'state'=>'Couchbase\MutationState'], 'Couchbase\SearchQuery::dateRange' => ['Couchbase\DateRangeSearchQuery'], 'Couchbase\SearchQuery::dateRangeFacet' => ['Couchbase\DateRangeSearchFacet', 'field'=>'string', 'limit'=>'int'], 'Couchbase\SearchQuery::disjuncts' => ['Couchbase\DisjunctionSearchQuery', '...queries='=>'array'], 'Couchbase\SearchQuery::docId' => ['Couchbase\DocIdSearchQuery', '...documentIds='=>'array'], 'Couchbase\SearchQuery::explain' => ['Couchbase\SearchQuery', 'explain'=>'bool'], 'Couchbase\SearchQuery::fields' => ['Couchbase\SearchQuery', '...fields='=>'array'], 'Couchbase\SearchQuery::geoBoundingBox' => ['Couchbase\GeoBoundingBoxSearchQuery', 'topLeftLongitude'=>'float', 'topLeftLatitude'=>'float', 'bottomRightLongitude'=>'float', 'bottomRightLatitude'=>'float'], 'Couchbase\SearchQuery::geoDistance' => ['Couchbase\GeoDistanceSearchQuery', 'longitude'=>'float', 'latitude'=>'float', 'distance'=>'string'], 'Couchbase\SearchQuery::highlight' => ['Couchbase\SearchQuery', 'style'=>'string', '...fields='=>'array'], 'Couchbase\SearchQuery::jsonSerialize' => ['array'], 'Couchbase\SearchQuery::limit' => ['Couchbase\SearchQuery', 'limit'=>'int'], 'Couchbase\SearchQuery::match' => ['Couchbase\MatchSearchQuery', 'match'=>'string'], 'Couchbase\SearchQuery::matchAll' => ['Couchbase\MatchAllSearchQuery'], 'Couchbase\SearchQuery::matchNone' => ['Couchbase\MatchNoneSearchQuery'], 'Couchbase\SearchQuery::matchPhrase' => ['Couchbase\MatchPhraseSearchQuery', '...terms='=>'array'], 'Couchbase\SearchQuery::numericRange' => ['Couchbase\NumericRangeSearchQuery'], 'Couchbase\SearchQuery::numericRangeFacet' => ['Couchbase\NumericRangeSearchFacet', 'field'=>'string', 'limit'=>'int'], 'Couchbase\SearchQuery::prefix' => ['Couchbase\PrefixSearchQuery', 'prefix'=>'string'], 'Couchbase\SearchQuery::queryString' => ['Couchbase\QueryStringSearchQuery', 'queryString'=>'string'], 'Couchbase\SearchQuery::regexp' => ['Couchbase\RegexpSearchQuery', 'regexp'=>'string'], 'Couchbase\SearchQuery::serverSideTimeout' => ['Couchbase\SearchQuery', 'serverSideTimeout'=>'int'], 'Couchbase\SearchQuery::skip' => ['Couchbase\SearchQuery', 'skip'=>'int'], 'Couchbase\SearchQuery::sort' => ['Couchbase\SearchQuery', '...sort='=>'array'], 'Couchbase\SearchQuery::term' => ['Couchbase\TermSearchQuery', 'term'=>'string'], 'Couchbase\SearchQuery::termFacet' => ['Couchbase\TermSearchFacet', 'field'=>'string', 'limit'=>'int'], 'Couchbase\SearchQuery::termRange' => ['Couchbase\TermRangeSearchQuery'], 'Couchbase\SearchQuery::wildcard' => ['Couchbase\WildcardSearchQuery', 'wildcard'=>'string'], 'Couchbase\SearchSort::__construct' => ['void'], 'Couchbase\SearchSort::field' => ['Couchbase\SearchSortField', 'field'=>'string'], 'Couchbase\SearchSort::geoDistance' => ['Couchbase\SearchSortGeoDistance', 'field'=>'string', 'longitude'=>'float', 'latitude'=>'float'], 'Couchbase\SearchSort::id' => ['Couchbase\SearchSortId'], 'Couchbase\SearchSort::score' => ['Couchbase\SearchSortScore'], 'Couchbase\SearchSortField::__construct' => ['void'], 'Couchbase\SearchSortField::descending' => ['Couchbase\SearchSortField', 'descending'=>'bool'], 'Couchbase\SearchSortField::field' => ['Couchbase\SearchSortField', 'field'=>'string'], 'Couchbase\SearchSortField::geoDistance' => ['Couchbase\SearchSortGeoDistance', 'field'=>'string', 'longitude'=>'float', 'latitude'=>'float'], 'Couchbase\SearchSortField::id' => ['Couchbase\SearchSortId'], 'Couchbase\SearchSortField::jsonSerialize' => ['mixed'], 'Couchbase\SearchSortField::missing' => ['', 'missing'=>'string'], 'Couchbase\SearchSortField::mode' => ['', 'mode'=>'string'], 'Couchbase\SearchSortField::score' => ['Couchbase\SearchSortScore'], 'Couchbase\SearchSortField::type' => ['', 'type'=>'string'], 'Couchbase\SearchSortGeoDistance::__construct' => ['void'], 'Couchbase\SearchSortGeoDistance::descending' => ['Couchbase\SearchSortGeoDistance', 'descending'=>'bool'], 'Couchbase\SearchSortGeoDistance::field' => ['Couchbase\SearchSortField', 'field'=>'string'], 'Couchbase\SearchSortGeoDistance::geoDistance' => ['Couchbase\SearchSortGeoDistance', 'field'=>'string', 'longitude'=>'float', 'latitude'=>'float'], 'Couchbase\SearchSortGeoDistance::id' => ['Couchbase\SearchSortId'], 'Couchbase\SearchSortGeoDistance::jsonSerialize' => ['mixed'], 'Couchbase\SearchSortGeoDistance::score' => ['Couchbase\SearchSortScore'], 'Couchbase\SearchSortGeoDistance::unit' => ['Couchbase\SearchSortGeoDistance', 'unit'=>'string'], 'Couchbase\SearchSortId::__construct' => ['void'], 'Couchbase\SearchSortId::descending' => ['Couchbase\SearchSortId', 'descending'=>'bool'], 'Couchbase\SearchSortId::field' => ['Couchbase\SearchSortField', 'field'=>'string'], 'Couchbase\SearchSortId::geoDistance' => ['Couchbase\SearchSortGeoDistance', 'field'=>'string', 'longitude'=>'float', 'latitude'=>'float'], 'Couchbase\SearchSortId::id' => ['Couchbase\SearchSortId'], 'Couchbase\SearchSortId::jsonSerialize' => ['mixed'], 'Couchbase\SearchSortId::score' => ['Couchbase\SearchSortScore'], 'Couchbase\SearchSortScore::__construct' => ['void'], 'Couchbase\SearchSortScore::descending' => ['Couchbase\SearchSortScore', 'descending'=>'bool'], 'Couchbase\SearchSortScore::field' => ['Couchbase\SearchSortField', 'field'=>'string'], 'Couchbase\SearchSortScore::geoDistance' => ['Couchbase\SearchSortGeoDistance', 'field'=>'string', 'longitude'=>'float', 'latitude'=>'float'], 'Couchbase\SearchSortScore::id' => ['Couchbase\SearchSortId'], 'Couchbase\SearchSortScore::jsonSerialize' => ['mixed'], 'Couchbase\SearchSortScore::score' => ['Couchbase\SearchSortScore'], 'Couchbase\SpatialViewQuery::__construct' => ['void'], 'Couchbase\SpatialViewQuery::bbox' => ['Couchbase\SpatialViewQuery', 'bbox'=>'array'], 'Couchbase\SpatialViewQuery::consistency' => ['Couchbase\SpatialViewQuery', 'consistency'=>'int'], 'Couchbase\SpatialViewQuery::custom' => ['', 'customParameters'=>'array'], 'Couchbase\SpatialViewQuery::encode' => ['array'], 'Couchbase\SpatialViewQuery::endRange' => ['Couchbase\SpatialViewQuery', 'range'=>'array'], 'Couchbase\SpatialViewQuery::limit' => ['Couchbase\SpatialViewQuery', 'limit'=>'int'], 'Couchbase\SpatialViewQuery::order' => ['Couchbase\SpatialViewQuery', 'order'=>'int'], 'Couchbase\SpatialViewQuery::skip' => ['Couchbase\SpatialViewQuery', 'skip'=>'int'], 'Couchbase\SpatialViewQuery::startRange' => ['Couchbase\SpatialViewQuery', 'range'=>'array'], 'Couchbase\TermRangeSearchQuery::__construct' => ['void'], 'Couchbase\TermRangeSearchQuery::boost' => ['Couchbase\TermRangeSearchQuery', 'boost'=>'float'], 'Couchbase\TermRangeSearchQuery::field' => ['Couchbase\TermRangeSearchQuery', 'field'=>'string'], 'Couchbase\TermRangeSearchQuery::jsonSerialize' => ['array'], 'Couchbase\TermRangeSearchQuery::max' => ['Couchbase\TermRangeSearchQuery', 'max'=>'string', 'inclusive='=>'bool'], 'Couchbase\TermRangeSearchQuery::min' => ['Couchbase\TermRangeSearchQuery', 'min'=>'string', 'inclusive='=>'bool'], 'Couchbase\TermSearchFacet::__construct' => ['void'], 'Couchbase\TermSearchFacet::jsonSerialize' => ['array'], 'Couchbase\TermSearchQuery::__construct' => ['void'], 'Couchbase\TermSearchQuery::boost' => ['Couchbase\TermSearchQuery', 'boost'=>'float'], 'Couchbase\TermSearchQuery::field' => ['Couchbase\TermSearchQuery', 'field'=>'string'], 'Couchbase\TermSearchQuery::fuzziness' => ['Couchbase\TermSearchQuery', 'fuzziness'=>'int'], 'Couchbase\TermSearchQuery::jsonSerialize' => ['array'], 'Couchbase\TermSearchQuery::prefixLength' => ['Couchbase\TermSearchQuery', 'prefixLength'=>'int'], 'Couchbase\UserSettings::fullName' => ['Couchbase\UserSettings', 'fullName'=>'string'], 'Couchbase\UserSettings::password' => ['Couchbase\UserSettings', 'password'=>'string'], 'Couchbase\UserSettings::role' => ['Couchbase\UserSettings', 'role'=>'string', 'bucket='=>'string'], 'Couchbase\ViewQuery::__construct' => ['void'], 'Couchbase\ViewQuery::consistency' => ['Couchbase\ViewQuery', 'consistency'=>'int'], 'Couchbase\ViewQuery::custom' => ['Couchbase\ViewQuery', 'customParameters'=>'array'], 'Couchbase\ViewQuery::encode' => ['array'], 'Couchbase\ViewQuery::from' => ['Couchbase\ViewQuery', 'designDocumentName'=>'string', 'viewName'=>'string'], 'Couchbase\ViewQuery::fromSpatial' => ['Couchbase\SpatialViewQuery', 'designDocumentName'=>'string', 'viewName'=>'string'], 'Couchbase\ViewQuery::group' => ['Couchbase\ViewQuery', 'group'=>'bool'], 'Couchbase\ViewQuery::groupLevel' => ['Couchbase\ViewQuery', 'groupLevel'=>'int'], 'Couchbase\ViewQuery::idRange' => ['Couchbase\ViewQuery', 'startKeyDocumentId'=>'string', 'endKeyDocumentId'=>'string'], 'Couchbase\ViewQuery::key' => ['Couchbase\ViewQuery', 'key'=>'mixed'], 'Couchbase\ViewQuery::keys' => ['Couchbase\ViewQuery', 'keys'=>'array'], 'Couchbase\ViewQuery::limit' => ['Couchbase\ViewQuery', 'limit'=>'int'], 'Couchbase\ViewQuery::order' => ['Couchbase\ViewQuery', 'order'=>'int'], 'Couchbase\ViewQuery::range' => ['Couchbase\ViewQuery', 'startKey'=>'mixed', 'endKey'=>'mixed', 'inclusiveEnd='=>'bool'], 'Couchbase\ViewQuery::reduce' => ['Couchbase\ViewQuery', 'reduce'=>'bool'], 'Couchbase\ViewQuery::skip' => ['Couchbase\ViewQuery', 'skip'=>'int'], 'Couchbase\ViewQueryEncodable::encode' => ['array'], 'Couchbase\WildcardSearchQuery::__construct' => ['void'], 'Couchbase\WildcardSearchQuery::boost' => ['Couchbase\WildcardSearchQuery', 'boost'=>'float'], 'Couchbase\WildcardSearchQuery::field' => ['Couchbase\WildcardSearchQuery', 'field'=>'string'], 'Couchbase\WildcardSearchQuery::jsonSerialize' => ['array'], 'Couchbase\basicDecoderV1' => ['mixed', 'bytes'=>'string', 'flags'=>'int', 'datatype'=>'int', 'options'=>'array'], 'Couchbase\basicEncoderV1' => ['array', 'value'=>'mixed', 'options'=>'array'], 'Couchbase\defaultDecoder' => ['mixed', 'bytes'=>'string', 'flags'=>'int', 'datatype'=>'int'], 'Couchbase\defaultEncoder' => ['array', 'value'=>'mixed'], 'Couchbase\fastlzCompress' => ['string', 'data'=>'string'], 'Couchbase\fastlzDecompress' => ['string', 'data'=>'string'], 'Couchbase\passthruDecoder' => ['string', 'bytes'=>'string', 'flags'=>'int', 'datatype'=>'int'], 'Couchbase\passthruEncoder' => ['array', 'value'=>'string'], 'Couchbase\zlibCompress' => ['string', 'data'=>'string'], 'Couchbase\zlibDecompress' => ['string', 'data'=>'string'], 'Countable::count' => ['int'], 'DOMAttr::__construct' => ['void', 'name'=>'string', 'value='=>'string'], 'DOMAttr::getLineNo' => ['int'], 'DOMAttr::getNodePath' => ['?string'], 'DOMAttr::hasAttributes' => ['bool'], 'DOMAttr::hasChildNodes' => ['bool'], 'DOMAttr::insertBefore' => ['DOMNode|false', 'node'=>'DOMNode', 'child='=>'?DOMNode'], 'DOMAttr::isDefaultNamespace' => ['bool', 'namespace'=>'string'], 'DOMAttr::isId' => ['bool'], 'DOMAttr::isSameNode' => ['bool', 'otherNode'=>'DOMNode'], 'DOMAttr::isSupported' => ['bool', 'feature'=>'string', 'version'=>'string'], 'DOMAttr::lookupNamespaceUri' => ['string|null', 'prefix'=>'string|null'], 'DOMAttr::lookupPrefix' => ['string|null', 'namespace'=>'string'], 'DOMAttr::normalize' => ['void'], 'DOMAttr::removeChild' => ['DOMNode|false', 'child'=>'DOMNode'], 'DOMAttr::replaceChild' => ['DOMNode|false', 'node'=>'DOMNode', 'child'=>'DOMNode'], 'DOMCdataSection::__construct' => ['void', 'data'=>'string'], 'DOMCharacterData::appendData' => ['true', 'data'=>'string'], 'DOMCharacterData::deleteData' => ['bool', 'offset'=>'int', 'count'=>'int'], 'DOMCharacterData::insertData' => ['bool', 'offset'=>'int', 'data'=>'string'], 'DOMCharacterData::replaceData' => ['bool', 'offset'=>'int', 'count'=>'int', 'data'=>'string'], 'DOMCharacterData::substringData' => ['string', 'offset'=>'int', 'count'=>'int'], 'DOMComment::__construct' => ['void', 'data='=>'string'], 'DOMDocument::__construct' => ['void', 'version='=>'string', 'encoding='=>'string'], 'DOMDocument::createAttribute' => ['DOMAttr|false', 'localName'=>'string'], 'DOMDocument::createAttributeNS' => ['DOMAttr|false', 'namespace'=>'string|null', 'qualifiedName'=>'string'], 'DOMDocument::createCDATASection' => ['DOMCDATASection|false', 'data'=>'string'], 'DOMDocument::createComment' => ['DOMComment|false', 'data'=>'string'], 'DOMDocument::createDocumentFragment' => ['DOMDocumentFragment|false'], 'DOMDocument::createElement' => ['DOMElement|false', 'localName'=>'string', 'value='=>'string'], 'DOMDocument::createElementNS' => ['DOMElement|false', 'namespace'=>'string|null', 'qualifiedName'=>'string', 'value='=>'string'], 'DOMDocument::createEntityReference' => ['DOMEntityReference|false', 'name'=>'string'], 'DOMDocument::createProcessingInstruction' => ['DOMProcessingInstruction|false', 'target'=>'string', 'data='=>'string'], 'DOMDocument::createTextNode' => ['DOMText|false', 'data'=>'string'], 'DOMDocument::getElementById' => ['?DOMElement', 'elementId'=>'string'], 'DOMDocument::getElementsByTagName' => ['DOMNodeList', 'qualifiedName'=>'string'], 'DOMDocument::getElementsByTagNameNS' => ['DOMNodeList', 'namespace'=>'string', 'localName'=>'string'], 'DOMDocument::importNode' => ['DOMNode|false', 'node'=>'DOMNode', 'deep='=>'bool'], 'DOMDocument::load' => ['DOMDocument|bool', 'filename'=>'string', 'options='=>'int'], 'DOMDocument::loadHTML' => ['DOMDocument|bool', 'source'=>'non-empty-string', 'options='=>'int'], 'DOMDocument::loadHTMLFile' => ['DOMDocument|bool', 'filename'=>'string', 'options='=>'int'], 'DOMDocument::loadXML' => ['DOMDocument|bool', 'source'=>'non-empty-string', 'options='=>'int'], 'DOMDocument::normalizeDocument' => ['void'], 'DOMDocument::registerNodeClass' => ['bool', 'baseClass'=>'string', 'extendedClass'=>'?string'], 'DOMDocument::relaxNGValidate' => ['bool', 'filename'=>'string'], 'DOMDocument::relaxNGValidateSource' => ['bool', 'source'=>'string'], 'DOMDocument::save' => ['int|false', 'filename'=>'string', 'options='=>'int'], 'DOMDocument::saveHTML' => ['string|false', 'node='=>'?DOMNode'], 'DOMDocument::saveHTMLFile' => ['int|false', 'filename'=>'string'], 'DOMDocument::saveXML' => ['string|false', 'node='=>'?DOMNode', 'options='=>'int'], 'DOMDocument::schemaValidate' => ['bool', 'filename'=>'string', 'flags='=>'int'], 'DOMDocument::schemaValidateSource' => ['bool', 'source'=>'string', 'flags='=>'int'], 'DOMDocument::validate' => ['bool'], 'DOMDocument::xinclude' => ['int', 'options='=>'int'], 'DOMDocumentFragment::__construct' => ['void'], 'DOMDocumentFragment::appendXML' => ['bool', 'data'=>'string'], 'DOMElement::__construct' => ['void', 'qualifiedName'=>'string', 'value='=>'?string', 'namespace='=>'string'], 'DOMElement::getAttribute' => ['string', 'qualifiedName'=>'string'], 'DOMElement::getAttributeNS' => ['string', 'namespace'=>'string|null', 'localName'=>'string'], 'DOMElement::getAttributeNode' => ['DOMAttr', 'qualifiedName'=>'string'], 'DOMElement::getAttributeNodeNS' => ['DOMAttr', 'namespace'=>'string|null', 'localName'=>'string'], 'DOMElement::getElementsByTagName' => ['DOMNodeList', 'qualifiedName'=>'string'], 'DOMElement::getElementsByTagNameNS' => ['DOMNodeList', 'namespace'=>'string|null', 'localName'=>'string'], 'DOMElement::hasAttribute' => ['bool', 'qualifiedName'=>'string'], 'DOMElement::hasAttributeNS' => ['bool', 'namespace'=>'string|null', 'localName'=>'string'], 'DOMElement::removeAttribute' => ['bool', 'qualifiedName'=>'string'], 'DOMElement::removeAttributeNS' => ['void', 'namespace'=>'string|null', 'localName'=>'string'], 'DOMElement::removeAttributeNode' => ['DOMAttr|false', 'attr'=>'DOMAttr'], 'DOMElement::setAttribute' => ['DOMAttr|false', 'qualifiedName'=>'string', 'value'=>'string'], 'DOMElement::setAttributeNS' => ['void', 'namespace'=>'string|null', 'qualifiedName'=>'string', 'value'=>'string'], 'DOMElement::setAttributeNode' => ['?DOMAttr', 'attr'=>'DOMAttr'], 'DOMElement::setAttributeNodeNS' => ['DOMAttr', 'attr'=>'DOMAttr'], 'DOMElement::setIdAttribute' => ['void', 'qualifiedName'=>'string', 'isId'=>'bool'], 'DOMElement::setIdAttributeNS' => ['void', 'namespace'=>'string', 'qualifiedName'=>'string', 'isId'=>'bool'], 'DOMElement::setIdAttributeNode' => ['void', 'attr'=>'DOMAttr', 'isId'=>'bool'], 'DOMEntityReference::__construct' => ['void', 'name'=>'string'], 'DOMImplementation::__construct' => ['void'], 'DOMImplementation::createDocument' => ['DOMDocument|false', 'namespace='=>'string', 'qualifiedName='=>'string', 'doctype='=>'DOMDocumentType'], 'DOMImplementation::createDocumentType' => ['DOMDocumentType|false', 'qualifiedName'=>'string', 'publicId='=>'string', 'systemId='=>'string'], 'DOMImplementation::hasFeature' => ['bool', 'feature'=>'string', 'version'=>'string'], 'DOMNamedNodeMap::count' => ['int'], 'DOMNamedNodeMap::getNamedItem' => ['?DOMNode', 'qualifiedName'=>'string'], 'DOMNamedNodeMap::getNamedItemNS' => ['?DOMNode', 'namespace'=>'?string', 'localName'=>'string'], 'DOMNamedNodeMap::item' => ['?DOMNode', 'index'=>'int'], 'DOMNode::C14N' => ['string|false', 'exclusive='=>'bool', 'withComments='=>'bool', 'xpath='=>'?array', 'nsPrefixes='=>'?array'], 'DOMNode::C14NFile' => ['int|false', 'uri'=>'string', 'exclusive='=>'bool', 'withComments='=>'bool', 'xpath='=>'?array', 'nsPrefixes='=>'?array'], 'DOMNode::appendChild' => ['DOMNode|false', 'node'=>'DOMNode'], 'DOMNode::cloneNode' => ['DOMNode', 'deep='=>'bool'], 'DOMNode::getLineNo' => ['int'], 'DOMNode::getNodePath' => ['?string'], 'DOMNode::hasAttributes' => ['bool'], 'DOMNode::hasChildNodes' => ['bool'], 'DOMNode::insertBefore' => ['DOMNode|false', 'node'=>'DOMNode', 'child='=>'?DOMNode'], 'DOMNode::isDefaultNamespace' => ['bool', 'namespace'=>'string'], 'DOMNode::isSameNode' => ['bool', 'otherNode'=>'DOMNode'], 'DOMNode::isSupported' => ['bool', 'feature'=>'string', 'version'=>'string'], 'DOMNode::lookupNamespaceURI' => ['string|null', 'prefix'=>'string|null'], 'DOMNode::lookupPrefix' => ['string|null', 'namespace'=>'string'], 'DOMNode::normalize' => ['void'], 'DOMNode::removeChild' => ['DOMNode|false', 'child'=>'DOMNode'], 'DOMNode::replaceChild' => ['DOMNode|false', 'node'=>'DOMNode', 'child'=>'DOMNode'], 'DOMNodeList::item' => ['?DOMNode', 'index'=>'int'], 'DOMProcessingInstruction::__construct' => ['void', 'name'=>'string', 'value='=>'string'], 'DOMText::__construct' => ['void', 'data='=>'string'], 'DOMText::isElementContentWhitespace' => ['bool'], 'DOMText::isWhitespaceInElementContent' => ['bool'], 'DOMText::splitText' => ['DOMText', 'offset'=>'int'], 'DOMXPath::__construct' => ['void', 'document'=>'DOMDocument', 'registerNodeNS='=>'bool'], 'DOMXPath::evaluate' => ['mixed', 'expression'=>'string', 'contextNode='=>'?DOMNode', 'registerNodeNS='=>'bool'], 'DOMXPath::query' => ['DOMNodeList|false', 'expression'=>'string', 'contextNode='=>'?DOMNode', 'registerNodeNS='=>'bool'], 'DOMXPath::registerNamespace' => ['bool', 'prefix'=>'string', 'namespace'=>'string'], 'DOMXPath::registerPhpFunctions' => ['void', 'restrict='=>'array|string|null'], 'DOTNET::__call' => ['mixed', 'name'=>'string', 'args'=>''], 'DOTNET::__construct' => ['void', 'assembly_name'=>'string', 'datatype_name'=>'string', 'codepage='=>'int'], 'DOTNET::__get' => ['mixed', 'name'=>'string'], 'DOTNET::__set' => ['void', 'name'=>'string', 'value'=>''], 'DateInterval::__construct' => ['void', 'duration'=>'string'], 'DateInterval::__set_state' => ['DateInterval', 'array'=>'array'], 'DateInterval::__wakeup' => ['void'], 'DateInterval::createFromDateString' => ['DateInterval|false', 'datetime'=>'string'], 'DateInterval::format' => ['string', 'format'=>'string'], 'DatePeriod::__construct' => ['void', 'start'=>'DateTimeInterface', 'interval'=>'DateInterval', 'recur'=>'int', 'options='=>'int'], 'DatePeriod::__construct\'1' => ['void', 'start'=>'DateTimeInterface', 'interval'=>'DateInterval', 'end'=>'DateTimeInterface', 'options='=>'int'], 'DatePeriod::__construct\'2' => ['void', 'iso'=>'string', 'options='=>'int'], 'DatePeriod::__wakeup' => ['void'], 'DatePeriod::getDateInterval' => ['DateInterval'], 'DatePeriod::getEndDate' => ['?DateTimeInterface'], 'DatePeriod::getStartDate' => ['DateTimeInterface'], 'DateTime::__construct' => ['void', 'time='=>'string'], 'DateTime::__construct\'1' => ['void', 'time'=>'?string', 'timezone'=>'?DateTimeZone'], 'DateTime::__wakeup' => ['void'], 'DateTime::add' => ['static', 'interval'=>'DateInterval'], 'DateTime::createFromFormat' => ['static|false', 'format'=>'string', 'datetime'=>'string', 'timezone='=>'?DateTimeZone'], 'DateTime::diff' => ['DateInterval', 'targetObject'=>'DateTimeInterface', 'absolute='=>'bool'], 'DateTime::format' => ['string|false', 'format'=>'string'], 'DateTime::getLastErrors' => ['array{warning_count:int,warnings:array,error_count:int,errors:array}|false'], 'DateTime::getOffset' => ['int'], 'DateTime::getTimestamp' => ['int|false'], 'DateTime::getTimezone' => ['DateTimeZone|false'], 'DateTime::modify' => ['static|false', 'modifier'=>'string'], 'DateTime::setDate' => ['static', 'year'=>'int', 'month'=>'int', 'day'=>'int'], 'DateTime::setISODate' => ['static', 'year'=>'int', 'week'=>'int', 'dayOfWeek='=>'int'], 'DateTime::setTime' => ['static', 'hour'=>'int', 'minute'=>'int', 'second='=>'int', 'microsecond='=>'int'], 'DateTime::setTimestamp' => ['static', 'timestamp'=>'int'], 'DateTime::setTimezone' => ['static', 'timezone'=>'DateTimeZone'], 'DateTime::sub' => ['static', 'interval'=>'DateInterval'], 'DateTimeImmutable::__wakeup' => ['void'], 'DateTimeImmutable::getLastErrors' => ['array{warning_count:int,warnings:array,error_count:int,errors:array}|false'], 'DateTimeInterface::diff' => ['DateInterval', 'datetime2'=>'DateTimeInterface', 'absolute='=>'bool'], 'DateTimeInterface::format' => ['string', 'format'=>'string'], 'DateTimeInterface::getOffset' => ['int'], 'DateTimeInterface::getTimestamp' => ['int|false'], 'DateTimeInterface::getTimezone' => ['DateTimeZone|false'], 'DateTimeZone::__construct' => ['void', 'timezone'=>'non-empty-string'], 'DateTimeZone::__set_state' => ['DateTimeZone', 'array'=>'array'], 'DateTimeZone::__wakeup' => ['void'], 'DateTimeZone::getLocation' => ['array|false'], 'DateTimeZone::getName' => ['non-empty-string'], 'DateTimeZone::getOffset' => ['int|false', 'datetime'=>'DateTimeInterface'], 'DateTimeZone::getTransitions' => ['list|false', 'timestampBegin='=>'int', 'timestampEnd='=>'int'], 'DateTimeZone::listAbbreviations' => ['array>'], 'DateTimeZone::listIdentifiers' => ['list|false', 'timezoneGroup='=>'int', 'countryCode='=>'string'], 'Directory::close' => ['void', 'dir_handle='=>'resource'], 'Directory::read' => ['string|false', 'dir_handle='=>'resource'], 'Directory::rewind' => ['void', 'dir_handle='=>'resource'], 'DirectoryIterator::__construct' => ['void', 'directory'=>'string'], 'DirectoryIterator::__toString' => ['string'], 'DirectoryIterator::current' => ['DirectoryIterator'], 'DirectoryIterator::getATime' => ['int'], 'DirectoryIterator::getBasename' => ['string', 'suffix='=>'string'], 'DirectoryIterator::getCTime' => ['int'], 'DirectoryIterator::getExtension' => ['string'], 'DirectoryIterator::getFileInfo' => ['SplFileInfo', 'class='=>'class-string'], 'DirectoryIterator::getFilename' => ['string'], 'DirectoryIterator::getGroup' => ['int'], 'DirectoryIterator::getInode' => ['int'], 'DirectoryIterator::getLinkTarget' => ['string'], 'DirectoryIterator::getMTime' => ['int'], 'DirectoryIterator::getOwner' => ['int'], 'DirectoryIterator::getPath' => ['string'], 'DirectoryIterator::getPathInfo' => ['?SplFileInfo', 'class='=>'class-string'], 'DirectoryIterator::getPathname' => ['string'], 'DirectoryIterator::getPerms' => ['int'], 'DirectoryIterator::getRealPath' => ['non-falsy-string'], 'DirectoryIterator::getSize' => ['int'], 'DirectoryIterator::getType' => ['string'], 'DirectoryIterator::isDir' => ['bool'], 'DirectoryIterator::isDot' => ['bool'], 'DirectoryIterator::isExecutable' => ['bool'], 'DirectoryIterator::isFile' => ['bool'], 'DirectoryIterator::isLink' => ['bool'], 'DirectoryIterator::isReadable' => ['bool'], 'DirectoryIterator::isWritable' => ['bool'], 'DirectoryIterator::key' => ['string'], 'DirectoryIterator::next' => ['void'], 'DirectoryIterator::openFile' => ['SplFileObject', 'mode='=>'string', 'useIncludePath='=>'bool', 'context='=>'resource'], 'DirectoryIterator::rewind' => ['void'], 'DirectoryIterator::seek' => ['void', 'offset'=>'int'], 'DirectoryIterator::setFileClass' => ['void', 'class='=>'class-string'], 'DirectoryIterator::setInfoClass' => ['void', 'class='=>'class-string'], 'DirectoryIterator::valid' => ['bool'], 'DomAttribute::name' => ['string'], 'DomAttribute::set_value' => ['bool', 'content'=>'string'], 'DomAttribute::specified' => ['bool'], 'DomAttribute::value' => ['string'], 'DomXsltStylesheet::process' => ['DomDocument', 'xml_doc'=>'DOMDocument', 'xslt_params='=>'array', 'is_xpath_param='=>'bool', 'profile_filename='=>'string'], 'DomXsltStylesheet::result_dump_file' => ['string', 'xmldoc'=>'DOMDocument', 'filename'=>'string'], 'DomXsltStylesheet::result_dump_mem' => ['string', 'xmldoc'=>'DOMDocument'], 'DomainException::__clone' => ['void'], 'DomainException::__construct' => ['void', 'message='=>'string', 'code='=>'int', 'previous='=>'?Throwable'], 'DomainException::__toString' => ['string'], 'DomainException::__wakeup' => ['void'], 'DomainException::getCode' => ['int'], 'DomainException::getFile' => ['string'], 'DomainException::getLine' => ['int'], 'DomainException::getMessage' => ['string'], 'DomainException::getPrevious' => ['?Throwable'], 'DomainException::getTrace' => ['list\',args?:array}>'], 'DomainException::getTraceAsString' => ['string'], 'Ds\Collection::clear' => ['void'], 'Ds\Collection::copy' => ['Ds\Collection'], 'Ds\Collection::isEmpty' => ['bool'], 'Ds\Collection::toArray' => ['array'], 'Ds\Deque::__construct' => ['void', 'values='=>'mixed'], 'Ds\Deque::allocate' => ['void', 'capacity'=>'int'], 'Ds\Deque::apply' => ['void', 'callback'=>'callable'], 'Ds\Deque::capacity' => ['int'], 'Ds\Deque::clear' => ['void'], 'Ds\Deque::contains' => ['bool', '...values='=>'mixed'], 'Ds\Deque::copy' => ['Ds\Deque'], 'Ds\Deque::count' => ['int'], 'Ds\Deque::filter' => ['Ds\Deque', 'callback='=>'callable'], 'Ds\Deque::find' => ['mixed', 'value'=>'mixed'], 'Ds\Deque::first' => ['mixed'], 'Ds\Deque::get' => ['void', 'index'=>'int'], 'Ds\Deque::insert' => ['void', 'index'=>'int', '...values='=>'mixed'], 'Ds\Deque::isEmpty' => ['bool'], 'Ds\Deque::join' => ['string', 'glue='=>'string'], 'Ds\Deque::jsonSerialize' => ['array'], 'Ds\Deque::last' => ['mixed'], 'Ds\Deque::map' => ['Ds\Deque', 'callback'=>'callable'], 'Ds\Deque::merge' => ['Ds\Deque', 'values'=>'mixed'], 'Ds\Deque::pop' => ['mixed'], 'Ds\Deque::push' => ['void', '...values='=>'mixed'], 'Ds\Deque::reduce' => ['mixed', 'callback'=>'callable', 'initial='=>'mixed'], 'Ds\Deque::remove' => ['mixed', 'index'=>'int'], 'Ds\Deque::reverse' => ['void'], 'Ds\Deque::reversed' => ['Ds\Deque'], 'Ds\Deque::rotate' => ['void', 'rotations'=>'int'], 'Ds\Deque::set' => ['void', 'index'=>'int', 'value'=>'mixed'], 'Ds\Deque::shift' => ['mixed'], 'Ds\Deque::slice' => ['Ds\Deque', 'index'=>'int', 'length='=>'?int'], 'Ds\Deque::sort' => ['void', 'comparator='=>'callable'], 'Ds\Deque::sorted' => ['Ds\Deque', 'comparator='=>'callable'], 'Ds\Deque::sum' => ['int|float'], 'Ds\Deque::toArray' => ['array'], 'Ds\Deque::unshift' => ['void', '...values='=>'mixed'], 'Ds\Hashable::equals' => ['bool', 'object'=>'mixed'], 'Ds\Hashable::hash' => ['mixed'], 'Ds\Map::__construct' => ['void', 'values='=>'mixed'], 'Ds\Map::allocate' => ['void', 'capacity'=>'int'], 'Ds\Map::apply' => ['void', 'callback'=>'callable'], 'Ds\Map::capacity' => ['int'], 'Ds\Map::clear' => ['void'], 'Ds\Map::copy' => ['Ds\Map'], 'Ds\Map::count' => ['int'], 'Ds\Map::diff' => ['Ds\Map', 'map'=>'Ds\Map'], 'Ds\Map::filter' => ['Ds\Map', 'callback='=>'callable'], 'Ds\Map::first' => ['Ds\Pair'], 'Ds\Map::get' => ['mixed', 'key'=>'mixed', 'default='=>'mixed'], 'Ds\Map::hasKey' => ['bool', 'key'=>'mixed'], 'Ds\Map::hasValue' => ['bool', 'value'=>'mixed'], 'Ds\Map::intersect' => ['Ds\Map', 'map'=>'Ds\Map'], 'Ds\Map::isEmpty' => ['bool'], 'Ds\Map::jsonSerialize' => ['array'], 'Ds\Map::keys' => ['Ds\Set'], 'Ds\Map::ksort' => ['void', 'comparator='=>'callable'], 'Ds\Map::ksorted' => ['Ds\Map', 'comparator='=>'callable'], 'Ds\Map::last' => ['Ds\Pair'], 'Ds\Map::map' => ['Ds\Map', 'callback'=>'callable'], 'Ds\Map::merge' => ['Ds\Map', 'values'=>'mixed'], 'Ds\Map::pairs' => ['Ds\Sequence'], 'Ds\Map::put' => ['void', 'key'=>'mixed', 'value'=>'mixed'], 'Ds\Map::putAll' => ['void', 'values'=>'mixed'], 'Ds\Map::reduce' => ['mixed', 'callback'=>'callable', 'initial='=>'mixed'], 'Ds\Map::remove' => ['mixed', 'key'=>'mixed', 'default='=>'mixed'], 'Ds\Map::reverse' => ['void'], 'Ds\Map::reversed' => ['Ds\Map'], 'Ds\Map::skip' => ['Ds\Pair', 'position'=>'int'], 'Ds\Map::slice' => ['Ds\Map', 'index'=>'int', 'length='=>'?int'], 'Ds\Map::sort' => ['void', 'comparator='=>'callable'], 'Ds\Map::sorted' => ['Ds\Map', 'comparator='=>'callable'], 'Ds\Map::sum' => ['int|float'], 'Ds\Map::toArray' => ['array'], 'Ds\Map::union' => ['Ds\Map', 'map'=>'Ds\Map'], 'Ds\Map::values' => ['Ds\Sequence'], 'Ds\Map::xor' => ['Ds\Map', 'map'=>'Ds\Map'], 'Ds\Pair::__construct' => ['void', 'key='=>'mixed', 'value='=>'mixed'], 'Ds\Pair::clear' => ['void'], 'Ds\Pair::copy' => ['Ds\Pair'], 'Ds\Pair::isEmpty' => ['bool'], 'Ds\Pair::jsonSerialize' => ['array'], 'Ds\Pair::toArray' => ['array'], 'Ds\PriorityQueue::__construct' => ['void'], 'Ds\PriorityQueue::allocate' => ['void', 'capacity'=>'int'], 'Ds\PriorityQueue::capacity' => ['int'], 'Ds\PriorityQueue::clear' => ['void'], 'Ds\PriorityQueue::copy' => ['Ds\PriorityQueue'], 'Ds\PriorityQueue::count' => ['int'], 'Ds\PriorityQueue::isEmpty' => ['bool'], 'Ds\PriorityQueue::jsonSerialize' => ['array'], 'Ds\PriorityQueue::peek' => ['mixed'], 'Ds\PriorityQueue::pop' => ['mixed'], 'Ds\PriorityQueue::push' => ['void', 'value'=>'mixed', 'priority'=>'int'], 'Ds\PriorityQueue::toArray' => ['array'], 'Ds\Queue::__construct' => ['void', 'values='=>'mixed'], 'Ds\Queue::allocate' => ['void', 'capacity'=>'int'], 'Ds\Queue::capacity' => ['int'], 'Ds\Queue::clear' => ['void'], 'Ds\Queue::copy' => ['Ds\Queue'], 'Ds\Queue::count' => ['int'], 'Ds\Queue::isEmpty' => ['bool'], 'Ds\Queue::jsonSerialize' => ['array'], 'Ds\Queue::peek' => ['mixed'], 'Ds\Queue::pop' => ['mixed'], 'Ds\Queue::push' => ['void', '...values='=>'mixed'], 'Ds\Queue::toArray' => ['array'], 'Ds\Sequence::allocate' => ['void', 'capacity'=>'int'], 'Ds\Sequence::apply' => ['void', 'callback'=>'callable'], 'Ds\Sequence::capacity' => ['int'], 'Ds\Sequence::contains' => ['bool', '...values='=>'mixed'], 'Ds\Sequence::filter' => ['Ds\Sequence', 'callback='=>'callable'], 'Ds\Sequence::find' => ['mixed', 'value'=>'mixed'], 'Ds\Sequence::first' => ['mixed'], 'Ds\Sequence::get' => ['mixed', 'index'=>'int'], 'Ds\Sequence::insert' => ['void', 'index'=>'int', '...values='=>'mixed'], 'Ds\Sequence::join' => ['string', 'glue='=>'string'], 'Ds\Sequence::last' => ['void'], 'Ds\Sequence::map' => ['Ds\Sequence', 'callback'=>'callable'], 'Ds\Sequence::merge' => ['Ds\Sequence', 'values'=>'mixed'], 'Ds\Sequence::pop' => ['mixed'], 'Ds\Sequence::push' => ['void', '...values='=>'mixed'], 'Ds\Sequence::reduce' => ['mixed', 'callback'=>'callable', 'initial='=>'mixed'], 'Ds\Sequence::remove' => ['mixed', 'index'=>'int'], 'Ds\Sequence::reverse' => ['void'], 'Ds\Sequence::reversed' => ['Ds\Sequence'], 'Ds\Sequence::rotate' => ['void', 'rotations'=>'int'], 'Ds\Sequence::set' => ['void', 'index'=>'int', 'value'=>'mixed'], 'Ds\Sequence::shift' => ['mixed'], 'Ds\Sequence::slice' => ['Ds\Sequence', 'index'=>'int', 'length='=>'?int'], 'Ds\Sequence::sort' => ['void', 'comparator='=>'callable'], 'Ds\Sequence::sorted' => ['Ds\Sequence', 'comparator='=>'callable'], 'Ds\Sequence::sum' => ['int|float'], 'Ds\Sequence::unshift' => ['void', '...values='=>'mixed'], 'Ds\Set::__construct' => ['void', 'values='=>'mixed'], 'Ds\Set::add' => ['void', '...values='=>'mixed'], 'Ds\Set::allocate' => ['void', 'capacity'=>'int'], 'Ds\Set::capacity' => ['int'], 'Ds\Set::clear' => ['void'], 'Ds\Set::contains' => ['bool', '...values='=>'mixed'], 'Ds\Set::copy' => ['Ds\Set'], 'Ds\Set::count' => ['int'], 'Ds\Set::diff' => ['Ds\Set', 'set'=>'Ds\Set'], 'Ds\Set::filter' => ['Ds\Set', 'callback='=>'callable'], 'Ds\Set::first' => ['mixed'], 'Ds\Set::get' => ['mixed', 'index'=>'int'], 'Ds\Set::intersect' => ['Ds\Set', 'set'=>'Ds\Set'], 'Ds\Set::isEmpty' => ['bool'], 'Ds\Set::join' => ['string', 'glue='=>'string'], 'Ds\Set::jsonSerialize' => ['array'], 'Ds\Set::last' => ['mixed'], 'Ds\Set::merge' => ['Ds\Set', 'values'=>'mixed'], 'Ds\Set::reduce' => ['mixed', 'callback'=>'callable', 'initial='=>'mixed'], 'Ds\Set::remove' => ['void', '...values='=>'mixed'], 'Ds\Set::reverse' => ['void'], 'Ds\Set::reversed' => ['Ds\Set'], 'Ds\Set::slice' => ['Ds\Set', 'index'=>'int', 'length='=>'?int'], 'Ds\Set::sort' => ['void', 'comparator='=>'callable'], 'Ds\Set::sorted' => ['Ds\Set', 'comparator='=>'callable'], 'Ds\Set::sum' => ['int|float'], 'Ds\Set::toArray' => ['array'], 'Ds\Set::union' => ['Ds\Set', 'set'=>'Ds\Set'], 'Ds\Set::xor' => ['Ds\Set', 'set'=>'Ds\Set'], 'Ds\Stack::__construct' => ['void', 'values='=>'mixed'], 'Ds\Stack::allocate' => ['void', 'capacity'=>'int'], 'Ds\Stack::capacity' => ['int'], 'Ds\Stack::clear' => ['void'], 'Ds\Stack::copy' => ['Ds\Stack'], 'Ds\Stack::count' => ['int'], 'Ds\Stack::isEmpty' => ['bool'], 'Ds\Stack::jsonSerialize' => ['array'], 'Ds\Stack::peek' => ['mixed'], 'Ds\Stack::pop' => ['mixed'], 'Ds\Stack::push' => ['void', '...values='=>'mixed'], 'Ds\Stack::toArray' => ['array'], 'Ds\Vector::__construct' => ['void', 'values='=>'mixed'], 'Ds\Vector::allocate' => ['void', 'capacity'=>'int'], 'Ds\Vector::apply' => ['void', 'callback'=>'callable'], 'Ds\Vector::capacity' => ['int'], 'Ds\Vector::clear' => ['void'], 'Ds\Vector::contains' => ['bool', '...values='=>'mixed'], 'Ds\Vector::copy' => ['Ds\Vector'], 'Ds\Vector::count' => ['int'], 'Ds\Vector::filter' => ['Ds\Vector', 'callback='=>'callable'], 'Ds\Vector::find' => ['mixed', 'value'=>'mixed'], 'Ds\Vector::first' => ['mixed'], 'Ds\Vector::get' => ['mixed', 'index'=>'int'], 'Ds\Vector::insert' => ['void', 'index'=>'int', '...values='=>'mixed'], 'Ds\Vector::isEmpty' => ['bool'], 'Ds\Vector::join' => ['string', 'glue='=>'string'], 'Ds\Vector::jsonSerialize' => ['array'], 'Ds\Vector::last' => ['mixed'], 'Ds\Vector::map' => ['Ds\Vector', 'callback'=>'callable'], 'Ds\Vector::merge' => ['Ds\Vector', 'values'=>'mixed'], 'Ds\Vector::pop' => ['mixed'], 'Ds\Vector::push' => ['void', '...values='=>'mixed'], 'Ds\Vector::reduce' => ['mixed', 'callback'=>'callable', 'initial='=>'mixed'], 'Ds\Vector::remove' => ['mixed', 'index'=>'int'], 'Ds\Vector::reverse' => ['void'], 'Ds\Vector::reversed' => ['Ds\Vector'], 'Ds\Vector::rotate' => ['void', 'rotations'=>'int'], 'Ds\Vector::set' => ['void', 'index'=>'int', 'value'=>'mixed'], 'Ds\Vector::shift' => ['mixed'], 'Ds\Vector::slice' => ['Ds\Vector', 'index'=>'int', 'length='=>'?int'], 'Ds\Vector::sort' => ['void', 'comparator='=>'callable'], 'Ds\Vector::sorted' => ['Ds\Vector', 'comparator='=>'callable'], 'Ds\Vector::sum' => ['int|float'], 'Ds\Vector::toArray' => ['array'], 'Ds\Vector::unshift' => ['void', '...values='=>'mixed'], 'EmptyIterator::current' => ['never'], 'EmptyIterator::key' => ['never'], 'EmptyIterator::next' => ['void'], 'EmptyIterator::rewind' => ['void'], 'EmptyIterator::valid' => ['false'], 'Error::__clone' => ['void'], 'Error::__construct' => ['void', 'message='=>'string', 'code='=>'int', 'previous='=>'?Throwable'], 'Error::__toString' => ['string'], 'Error::getCode' => ['int'], 'Error::getFile' => ['string'], 'Error::getLine' => ['int'], 'Error::getMessage' => ['string'], 'Error::getPrevious' => ['?Throwable'], 'Error::getTrace' => ['list\',args?:array}>'], 'Error::getTraceAsString' => ['string'], 'ErrorException::__clone' => ['void'], 'ErrorException::__construct' => ['void', 'message='=>'string', 'code='=>'int', 'severity='=>'int', 'filename='=>'string', 'line='=>'int', 'previous='=>'?Throwable'], 'ErrorException::__toString' => ['string'], 'ErrorException::getCode' => ['int'], 'ErrorException::getFile' => ['string'], 'ErrorException::getLine' => ['int'], 'ErrorException::getMessage' => ['string'], 'ErrorException::getPrevious' => ['?Throwable'], 'ErrorException::getSeverity' => ['int'], 'ErrorException::getTrace' => ['list\',args?:array}>'], 'ErrorException::getTraceAsString' => ['string'], 'Ev::backend' => ['int'], 'Ev::depth' => ['int'], 'Ev::embeddableBackends' => ['int'], 'Ev::feedSignal' => ['void', 'signum'=>'int'], 'Ev::feedSignalEvent' => ['void', 'signum'=>'int'], 'Ev::iteration' => ['int'], 'Ev::now' => ['float'], 'Ev::nowUpdate' => ['void'], 'Ev::recommendedBackends' => ['int'], 'Ev::resume' => ['void'], 'Ev::run' => ['void', 'flags='=>'int'], 'Ev::sleep' => ['void', 'seconds'=>'float'], 'Ev::stop' => ['void', 'how='=>'int'], 'Ev::supportedBackends' => ['int'], 'Ev::suspend' => ['void'], 'Ev::time' => ['float'], 'Ev::verify' => ['void'], 'EvCheck::__construct' => ['void', 'callback'=>'callable', 'data='=>'mixed', 'priority='=>'int'], 'EvCheck::clear' => ['int'], 'EvCheck::createStopped' => ['EvCheck', 'callback'=>'callable', 'data='=>'mixed', 'priority='=>'int'], 'EvCheck::feed' => ['void', 'events'=>'int'], 'EvCheck::getLoop' => ['EvLoop'], 'EvCheck::invoke' => ['void', 'events'=>'int'], 'EvCheck::keepAlive' => ['void', 'value'=>'bool'], 'EvCheck::setCallback' => ['void', 'callback'=>'callable'], 'EvCheck::start' => ['void'], 'EvCheck::stop' => ['void'], 'EvChild::__construct' => ['void', 'pid'=>'int', 'trace'=>'bool', 'callback'=>'callable', 'data='=>'mixed', 'priority='=>'int'], 'EvChild::clear' => ['int'], 'EvChild::createStopped' => ['EvChild', 'pid'=>'int', 'trace'=>'bool', 'callback'=>'callable', 'data='=>'mixed', 'priority='=>'int'], 'EvChild::feed' => ['void', 'events'=>'int'], 'EvChild::getLoop' => ['EvLoop'], 'EvChild::invoke' => ['void', 'events'=>'int'], 'EvChild::keepAlive' => ['void', 'value'=>'bool'], 'EvChild::set' => ['void', 'pid'=>'int', 'trace'=>'bool'], 'EvChild::setCallback' => ['void', 'callback'=>'callable'], 'EvChild::start' => ['void'], 'EvChild::stop' => ['void'], 'EvEmbed::__construct' => ['void', 'other'=>'object', 'callback='=>'callable', 'data='=>'mixed', 'priority='=>'int'], 'EvEmbed::clear' => ['int'], 'EvEmbed::createStopped' => ['EvEmbed', 'other'=>'object', 'callback='=>'callable', 'data='=>'mixed', 'priority='=>'int'], 'EvEmbed::feed' => ['void', 'events'=>'int'], 'EvEmbed::getLoop' => ['EvLoop'], 'EvEmbed::invoke' => ['void', 'events'=>'int'], 'EvEmbed::keepAlive' => ['void', 'value'=>'bool'], 'EvEmbed::set' => ['void', 'other'=>'object'], 'EvEmbed::setCallback' => ['void', 'callback'=>'callable'], 'EvEmbed::start' => ['void'], 'EvEmbed::stop' => ['void'], 'EvEmbed::sweep' => ['void'], 'EvFork::__construct' => ['void', 'callback'=>'callable', 'data='=>'mixed', 'priority='=>'int'], 'EvFork::clear' => ['int'], 'EvFork::createStopped' => ['EvFork', 'callback'=>'callable', 'data='=>'string', 'priority='=>'string'], 'EvFork::feed' => ['void', 'events'=>'int'], 'EvFork::getLoop' => ['EvLoop'], 'EvFork::invoke' => ['void', 'events'=>'int'], 'EvFork::keepAlive' => ['void', 'value'=>'bool'], 'EvFork::setCallback' => ['void', 'callback'=>'callable'], 'EvFork::start' => ['void'], 'EvFork::stop' => ['void'], 'EvIdle::__construct' => ['void', 'callback'=>'callable', 'data='=>'mixed', 'priority='=>'int'], 'EvIdle::clear' => ['int'], 'EvIdle::createStopped' => ['EvIdle', 'callback'=>'callable', 'data='=>'mixed', 'priority='=>'int'], 'EvIdle::feed' => ['void', 'events'=>'int'], 'EvIdle::getLoop' => ['EvLoop'], 'EvIdle::invoke' => ['void', 'events'=>'int'], 'EvIdle::keepAlive' => ['void', 'value'=>'bool'], 'EvIdle::setCallback' => ['void', 'callback'=>'callable'], 'EvIdle::start' => ['void'], 'EvIdle::stop' => ['void'], 'EvIo::__construct' => ['void', 'fd'=>'mixed', 'events'=>'int', 'callback'=>'callable', 'data='=>'mixed', 'priority='=>'int'], 'EvIo::clear' => ['int'], 'EvIo::createStopped' => ['EvIo', 'fd'=>'resource', 'events'=>'int', 'callback'=>'callable', 'data='=>'mixed', 'priority='=>'int'], 'EvIo::feed' => ['void', 'events'=>'int'], 'EvIo::getLoop' => ['EvLoop'], 'EvIo::invoke' => ['void', 'events'=>'int'], 'EvIo::keepAlive' => ['void', 'value'=>'bool'], 'EvIo::set' => ['void', 'fd'=>'resource', 'events'=>'int'], 'EvIo::setCallback' => ['void', 'callback'=>'callable'], 'EvIo::start' => ['void'], 'EvIo::stop' => ['void'], 'EvLoop::__construct' => ['void', 'flags='=>'int', 'data='=>'mixed', 'io_interval='=>'float', 'timeout_interval='=>'float'], 'EvLoop::backend' => ['int'], 'EvLoop::check' => ['EvCheck', 'callback'=>'callable', 'data='=>'mixed', 'priority='=>'int'], 'EvLoop::child' => ['EvChild', 'pid'=>'int', 'trace'=>'bool', 'callback'=>'callable', 'data='=>'mixed', 'priority='=>'int'], 'EvLoop::defaultLoop' => ['EvLoop', 'flags='=>'int', 'data='=>'mixed', 'io_interval='=>'float', 'timeout_interval='=>'float'], 'EvLoop::embed' => ['EvEmbed', 'other'=>'EvLoop', 'callback='=>'callable', 'data='=>'mixed', 'priority='=>'int'], 'EvLoop::fork' => ['EvFork', 'callback'=>'callable', 'data='=>'mixed', 'priority='=>'int'], 'EvLoop::idle' => ['EvIdle', 'callback'=>'callable', 'data='=>'mixed', 'priority='=>'int'], 'EvLoop::invokePending' => ['void'], 'EvLoop::io' => ['EvIo', 'fd'=>'resource', 'events'=>'int', 'callback'=>'callable', 'data='=>'mixed', 'priority='=>'int'], 'EvLoop::loopFork' => ['void'], 'EvLoop::now' => ['float'], 'EvLoop::nowUpdate' => ['void'], 'EvLoop::periodic' => ['EvPeriodic', 'offset'=>'float', 'interval'=>'float', 'callback'=>'callable', 'data='=>'mixed', 'priority='=>'int'], 'EvLoop::prepare' => ['EvPrepare', 'callback'=>'callable', 'data='=>'mixed', 'priority='=>'int'], 'EvLoop::resume' => ['void'], 'EvLoop::run' => ['void', 'flags='=>'int'], 'EvLoop::signal' => ['EvSignal', 'signum'=>'int', 'callback'=>'callable', 'data='=>'mixed', 'priority='=>'int'], 'EvLoop::stat' => ['EvStat', 'path'=>'string', 'interval'=>'float', 'callback'=>'callable', 'data='=>'mixed', 'priority='=>'int'], 'EvLoop::stop' => ['void', 'how='=>'int'], 'EvLoop::suspend' => ['void'], 'EvLoop::timer' => ['EvTimer', 'after'=>'float', 'repeat'=>'float', 'callback'=>'callable', 'data='=>'mixed', 'priority='=>'int'], 'EvLoop::verify' => ['void'], 'EvPeriodic::__construct' => ['void', 'offset'=>'float', 'interval'=>'string', 'reschedule_cb'=>'callable', 'callback'=>'callable', 'data='=>'mixed', 'priority='=>'int'], 'EvPeriodic::again' => ['void'], 'EvPeriodic::at' => ['float'], 'EvPeriodic::clear' => ['int'], 'EvPeriodic::createStopped' => ['EvPeriodic', 'offset'=>'float', 'interval'=>'float', 'reschedule_cb'=>'callable', 'callback'=>'callable', 'data='=>'mixed', 'priority='=>'int'], 'EvPeriodic::feed' => ['void', 'events'=>'int'], 'EvPeriodic::getLoop' => ['EvLoop'], 'EvPeriodic::invoke' => ['void', 'events'=>'int'], 'EvPeriodic::keepAlive' => ['void', 'value'=>'bool'], 'EvPeriodic::set' => ['void', 'offset'=>'float', 'interval'=>'float'], 'EvPeriodic::setCallback' => ['void', 'callback'=>'callable'], 'EvPeriodic::start' => ['void'], 'EvPeriodic::stop' => ['void'], 'EvPrepare::__construct' => ['void', 'callback'=>'string', 'data='=>'string', 'priority='=>'string'], 'EvPrepare::clear' => ['int'], 'EvPrepare::createStopped' => ['EvPrepare', 'callback'=>'callable', 'data='=>'mixed', 'priority='=>'int'], 'EvPrepare::feed' => ['void', 'events'=>'int'], 'EvPrepare::getLoop' => ['EvLoop'], 'EvPrepare::invoke' => ['void', 'events'=>'int'], 'EvPrepare::keepAlive' => ['void', 'value'=>'bool'], 'EvPrepare::setCallback' => ['void', 'callback'=>'callable'], 'EvPrepare::start' => ['void'], 'EvPrepare::stop' => ['void'], 'EvSignal::__construct' => ['void', 'signum'=>'int', 'callback'=>'callable', 'data='=>'mixed', 'priority='=>'int'], 'EvSignal::clear' => ['int'], 'EvSignal::createStopped' => ['EvSignal', 'signum'=>'int', 'callback'=>'callable', 'data='=>'mixed', 'priority='=>'int'], 'EvSignal::feed' => ['void', 'events'=>'int'], 'EvSignal::getLoop' => ['EvLoop'], 'EvSignal::invoke' => ['void', 'events'=>'int'], 'EvSignal::keepAlive' => ['void', 'value'=>'bool'], 'EvSignal::set' => ['void', 'signum'=>'int'], 'EvSignal::setCallback' => ['void', 'callback'=>'callable'], 'EvSignal::start' => ['void'], 'EvSignal::stop' => ['void'], 'EvStat::__construct' => ['void', 'path'=>'string', 'interval'=>'float', 'callback'=>'callable', 'data='=>'mixed', 'priority='=>'int'], 'EvStat::attr' => ['array'], 'EvStat::clear' => ['int'], 'EvStat::createStopped' => ['EvStat', 'path'=>'string', 'interval'=>'float', 'callback'=>'callable', 'data='=>'mixed', 'priority='=>'int'], 'EvStat::feed' => ['void', 'events'=>'int'], 'EvStat::getLoop' => ['EvLoop'], 'EvStat::invoke' => ['void', 'events'=>'int'], 'EvStat::keepAlive' => ['void', 'value'=>'bool'], 'EvStat::prev' => ['array'], 'EvStat::set' => ['void', 'path'=>'string', 'interval'=>'float'], 'EvStat::setCallback' => ['void', 'callback'=>'callable'], 'EvStat::start' => ['void'], 'EvStat::stat' => ['bool'], 'EvStat::stop' => ['void'], 'EvTimer::__construct' => ['void', 'after'=>'float', 'repeat'=>'float', 'callback'=>'callable', 'data='=>'mixed', 'priority='=>'int'], 'EvTimer::again' => ['void'], 'EvTimer::clear' => ['int'], 'EvTimer::createStopped' => ['EvTimer', 'after'=>'float', 'repeat'=>'float', 'callback'=>'callable', 'data='=>'mixed', 'priority='=>'int'], 'EvTimer::feed' => ['void', 'events'=>'int'], 'EvTimer::getLoop' => ['EvLoop'], 'EvTimer::invoke' => ['void', 'events'=>'int'], 'EvTimer::keepAlive' => ['void', 'value'=>'bool'], 'EvTimer::set' => ['void', 'after'=>'float', 'repeat'=>'float'], 'EvTimer::setCallback' => ['void', 'callback'=>'callable'], 'EvTimer::start' => ['void'], 'EvTimer::stop' => ['void'], 'EvWatcher::__construct' => ['void'], 'EvWatcher::clear' => ['int'], 'EvWatcher::feed' => ['void', 'revents'=>'int'], 'EvWatcher::getLoop' => ['EvLoop'], 'EvWatcher::invoke' => ['void', 'revents'=>'int'], 'EvWatcher::keepalive' => ['bool', 'value='=>'bool'], 'EvWatcher::setCallback' => ['void', 'callback'=>'callable'], 'EvWatcher::start' => ['void'], 'EvWatcher::stop' => ['void'], 'Event::__construct' => ['void', 'base'=>'EventBase', 'fd'=>'mixed', 'what'=>'int', 'cb'=>'callable', 'arg='=>'mixed'], 'Event::add' => ['bool', 'timeout='=>'float'], 'Event::addSignal' => ['bool', 'timeout='=>'float'], 'Event::addTimer' => ['bool', 'timeout='=>'float'], 'Event::del' => ['bool'], 'Event::delSignal' => ['bool'], 'Event::delTimer' => ['bool'], 'Event::free' => ['void'], 'Event::getSupportedMethods' => ['array'], 'Event::pending' => ['bool', 'flags'=>'int'], 'Event::set' => ['bool', 'base'=>'EventBase', 'fd'=>'mixed', 'what='=>'int', 'cb='=>'callable', 'arg='=>'mixed'], 'Event::setPriority' => ['bool', 'priority'=>'int'], 'Event::setTimer' => ['bool', 'base'=>'EventBase', 'cb'=>'callable', 'arg='=>'mixed'], 'Event::signal' => ['Event', 'base'=>'EventBase', 'signum'=>'int', 'cb'=>'callable', 'arg='=>'mixed'], 'Event::timer' => ['Event', 'base'=>'EventBase', 'cb'=>'callable', 'arg='=>'mixed'], 'EventBase::__construct' => ['void', 'cfg='=>'EventConfig'], 'EventBase::dispatch' => ['void'], 'EventBase::exit' => ['bool', 'timeout='=>'float'], 'EventBase::free' => ['void'], 'EventBase::getFeatures' => ['int'], 'EventBase::getMethod' => ['string', 'cfg='=>'EventConfig'], 'EventBase::getTimeOfDayCached' => ['float'], 'EventBase::gotExit' => ['bool'], 'EventBase::gotStop' => ['bool'], 'EventBase::loop' => ['bool', 'flags='=>'int'], 'EventBase::priorityInit' => ['bool', 'n_priorities'=>'int'], 'EventBase::reInit' => ['bool'], 'EventBase::stop' => ['bool'], 'EventBuffer::__construct' => ['void'], 'EventBuffer::add' => ['bool', 'data'=>'string'], 'EventBuffer::addBuffer' => ['bool', 'buf'=>'EventBuffer'], 'EventBuffer::appendFrom' => ['int', 'buf'=>'EventBuffer', 'length'=>'int'], 'EventBuffer::copyout' => ['int', '&w_data'=>'string', 'max_bytes'=>'int'], 'EventBuffer::drain' => ['bool', 'length'=>'int'], 'EventBuffer::enableLocking' => ['void'], 'EventBuffer::expand' => ['bool', 'length'=>'int'], 'EventBuffer::freeze' => ['bool', 'at_front'=>'bool'], 'EventBuffer::lock' => ['void'], 'EventBuffer::prepend' => ['bool', 'data'=>'string'], 'EventBuffer::prependBuffer' => ['bool', 'buf'=>'EventBuffer'], 'EventBuffer::pullup' => ['string', 'size'=>'int'], 'EventBuffer::read' => ['string', 'max_bytes'=>'int'], 'EventBuffer::readFrom' => ['int', 'fd'=>'mixed', 'howmuch'=>'int'], 'EventBuffer::readLine' => ['string', 'eol_style'=>'int'], 'EventBuffer::search' => ['mixed', 'what'=>'string', 'start='=>'int', 'end='=>'int'], 'EventBuffer::searchEol' => ['mixed', 'start='=>'int', 'eol_style='=>'int'], 'EventBuffer::substr' => ['string', 'start'=>'int', 'length='=>'int'], 'EventBuffer::unfreeze' => ['bool', 'at_front'=>'bool'], 'EventBuffer::unlock' => ['bool'], 'EventBuffer::write' => ['int', 'fd'=>'mixed', 'howmuch='=>'int'], 'EventBufferEvent::__construct' => ['void', 'base'=>'EventBase', 'socket='=>'mixed', 'options='=>'int', 'readcb='=>'callable', 'writecb='=>'callable', 'eventcb='=>'callable'], 'EventBufferEvent::close' => ['void'], 'EventBufferEvent::connect' => ['bool', 'addr'=>'string'], 'EventBufferEvent::connectHost' => ['bool', 'dns_base'=>'EventDnsBase', 'hostname'=>'string', 'port'=>'int', 'family='=>'int'], 'EventBufferEvent::createPair' => ['array', 'base'=>'EventBase', 'options='=>'int'], 'EventBufferEvent::disable' => ['bool', 'events'=>'int'], 'EventBufferEvent::enable' => ['bool', 'events'=>'int'], 'EventBufferEvent::free' => ['void'], 'EventBufferEvent::getDnsErrorString' => ['string'], 'EventBufferEvent::getEnabled' => ['int'], 'EventBufferEvent::getInput' => ['EventBuffer'], 'EventBufferEvent::getOutput' => ['EventBuffer'], 'EventBufferEvent::read' => ['string', 'size'=>'int'], 'EventBufferEvent::readBuffer' => ['bool', 'buf'=>'EventBuffer'], 'EventBufferEvent::setCallbacks' => ['void', 'readcb'=>'callable', 'writecb'=>'callable', 'eventcb'=>'callable', 'arg='=>'string'], 'EventBufferEvent::setPriority' => ['bool', 'priority'=>'int'], 'EventBufferEvent::setTimeouts' => ['bool', 'timeout_read'=>'float', 'timeout_write'=>'float'], 'EventBufferEvent::setWatermark' => ['void', 'events'=>'int', 'lowmark'=>'int', 'highmark'=>'int'], 'EventBufferEvent::sslError' => ['string'], 'EventBufferEvent::sslFilter' => ['EventBufferEvent', 'base'=>'EventBase', 'underlying'=>'EventBufferEvent', 'ctx'=>'EventSslContext', 'state'=>'int', 'options='=>'int'], 'EventBufferEvent::sslGetCipherInfo' => ['string'], 'EventBufferEvent::sslGetCipherName' => ['string'], 'EventBufferEvent::sslGetCipherVersion' => ['string'], 'EventBufferEvent::sslGetProtocol' => ['string'], 'EventBufferEvent::sslRenegotiate' => ['void'], 'EventBufferEvent::sslSocket' => ['EventBufferEvent', 'base'=>'EventBase', 'socket'=>'mixed', 'ctx'=>'EventSslContext', 'state'=>'int', 'options='=>'int'], 'EventBufferEvent::write' => ['bool', 'data'=>'string'], 'EventBufferEvent::writeBuffer' => ['bool', 'buf'=>'EventBuffer'], 'EventConfig::__construct' => ['void'], 'EventConfig::avoidMethod' => ['bool', 'method'=>'string'], 'EventConfig::requireFeatures' => ['bool', 'feature'=>'int'], 'EventConfig::setMaxDispatchInterval' => ['void', 'max_interval'=>'int', 'max_callbacks'=>'int', 'min_priority'=>'int'], 'EventDnsBase::__construct' => ['void', 'base'=>'EventBase', 'initialize'=>'bool'], 'EventDnsBase::addNameserverIp' => ['bool', 'ip'=>'string'], 'EventDnsBase::addSearch' => ['void', 'domain'=>'string'], 'EventDnsBase::clearSearch' => ['void'], 'EventDnsBase::countNameservers' => ['int'], 'EventDnsBase::loadHosts' => ['bool', 'hosts'=>'string'], 'EventDnsBase::parseResolvConf' => ['bool', 'flags'=>'int', 'filename'=>'string'], 'EventDnsBase::setOption' => ['bool', 'option'=>'string', 'value'=>'string'], 'EventDnsBase::setSearchNdots' => ['bool', 'ndots'=>'int'], 'EventHttp::__construct' => ['void', 'base'=>'EventBase', 'ctx='=>'EventSslContext'], 'EventHttp::accept' => ['bool', 'socket'=>'mixed'], 'EventHttp::addServerAlias' => ['bool', 'alias'=>'string'], 'EventHttp::bind' => ['void', 'address'=>'string', 'port'=>'int'], 'EventHttp::removeServerAlias' => ['bool', 'alias'=>'string'], 'EventHttp::setAllowedMethods' => ['void', 'methods'=>'int'], 'EventHttp::setCallback' => ['void', 'path'=>'string', 'cb'=>'string', 'arg='=>'string'], 'EventHttp::setDefaultCallback' => ['void', 'cb'=>'string', 'arg='=>'string'], 'EventHttp::setMaxBodySize' => ['void', 'value'=>'int'], 'EventHttp::setMaxHeadersSize' => ['void', 'value'=>'int'], 'EventHttp::setTimeout' => ['void', 'value'=>'int'], 'EventHttpConnection::__construct' => ['void', 'base'=>'EventBase', 'dns_base'=>'EventDnsBase', 'address'=>'string', 'port'=>'int', 'ctx='=>'EventSslContext'], 'EventHttpConnection::getBase' => ['EventBase'], 'EventHttpConnection::getPeer' => ['void', '&w_address'=>'string', '&w_port'=>'int'], 'EventHttpConnection::makeRequest' => ['bool', 'req'=>'EventHttpRequest', 'type'=>'int', 'uri'=>'string'], 'EventHttpConnection::setCloseCallback' => ['void', 'callback'=>'callable', 'data='=>'mixed'], 'EventHttpConnection::setLocalAddress' => ['void', 'address'=>'string'], 'EventHttpConnection::setLocalPort' => ['void', 'port'=>'int'], 'EventHttpConnection::setMaxBodySize' => ['void', 'max_size'=>'string'], 'EventHttpConnection::setMaxHeadersSize' => ['void', 'max_size'=>'string'], 'EventHttpConnection::setRetries' => ['void', 'retries'=>'int'], 'EventHttpConnection::setTimeout' => ['void', 'timeout'=>'int'], 'EventHttpRequest::__construct' => ['void', 'callback'=>'callable', 'data='=>'mixed'], 'EventHttpRequest::addHeader' => ['bool', 'key'=>'string', 'value'=>'string', 'type'=>'int'], 'EventHttpRequest::cancel' => ['void'], 'EventHttpRequest::clearHeaders' => ['void'], 'EventHttpRequest::closeConnection' => ['void'], 'EventHttpRequest::findHeader' => ['void', 'key'=>'string', 'type'=>'string'], 'EventHttpRequest::free' => ['void'], 'EventHttpRequest::getBufferEvent' => ['EventBufferEvent'], 'EventHttpRequest::getCommand' => ['void'], 'EventHttpRequest::getConnection' => ['EventHttpConnection'], 'EventHttpRequest::getHost' => ['string'], 'EventHttpRequest::getInputBuffer' => ['EventBuffer'], 'EventHttpRequest::getInputHeaders' => ['array'], 'EventHttpRequest::getOutputBuffer' => ['EventBuffer'], 'EventHttpRequest::getOutputHeaders' => ['void'], 'EventHttpRequest::getResponseCode' => ['int'], 'EventHttpRequest::getUri' => ['string'], 'EventHttpRequest::removeHeader' => ['void', 'key'=>'string', 'type'=>'string'], 'EventHttpRequest::sendError' => ['void', 'error'=>'int', 'reason='=>'string'], 'EventHttpRequest::sendReply' => ['void', 'code'=>'int', 'reason'=>'string', 'buf='=>'EventBuffer'], 'EventHttpRequest::sendReplyChunk' => ['void', 'buf'=>'EventBuffer'], 'EventHttpRequest::sendReplyEnd' => ['void'], 'EventHttpRequest::sendReplyStart' => ['void', 'code'=>'int', 'reason'=>'string'], 'EventListener::__construct' => ['void', 'base'=>'EventBase', 'cb'=>'callable', 'data'=>'mixed', 'flags'=>'int', 'backlog'=>'int', 'target'=>'mixed'], 'EventListener::disable' => ['bool'], 'EventListener::enable' => ['bool'], 'EventListener::getBase' => ['void'], 'EventListener::getSocketName' => ['bool', '&w_address'=>'string', '&w_port='=>'mixed'], 'EventListener::setCallback' => ['void', 'cb'=>'callable', 'arg='=>'mixed'], 'EventListener::setErrorCallback' => ['void', 'cb'=>'string'], 'EventSslContext::__construct' => ['void', 'method'=>'string', 'options'=>'string'], 'EventUtil::__construct' => ['void'], 'EventUtil::getLastSocketErrno' => ['int', 'socket='=>'mixed'], 'EventUtil::getLastSocketError' => ['string', 'socket='=>'mixed'], 'EventUtil::getSocketFd' => ['int', 'socket'=>'mixed'], 'EventUtil::getSocketName' => ['bool', 'socket'=>'mixed', '&w_address'=>'string', '&w_port='=>'mixed'], 'EventUtil::setSocketOption' => ['bool', 'socket'=>'mixed', 'level'=>'int', 'optname'=>'int', 'optval'=>'mixed'], 'EventUtil::sslRandPoll' => ['void'], 'Exception::__clone' => ['void'], 'Exception::__construct' => ['void', 'message='=>'string', 'code='=>'int', 'previous='=>'?Throwable'], 'Exception::__toString' => ['string'], 'Exception::getCode' => ['int|string'], 'Exception::getFile' => ['string'], 'Exception::getLine' => ['int'], 'Exception::getMessage' => ['string'], 'Exception::getPrevious' => ['?Throwable'], 'Exception::getTrace' => ['list\',args?:array}>'], 'Exception::getTraceAsString' => ['string'], 'FANNConnection::__construct' => ['void', 'from_neuron'=>'int', 'to_neuron'=>'int', 'weight'=>'float'], 'FANNConnection::getFromNeuron' => ['int'], 'FANNConnection::getToNeuron' => ['int'], 'FANNConnection::getWeight' => ['void'], 'FANNConnection::setWeight' => ['bool', 'weight'=>'float'], 'FilesystemIterator::__construct' => ['void', 'directory'=>'string', 'flags='=>'int'], 'FilesystemIterator::__toString' => ['string'], 'FilesystemIterator::current' => ['SplFileInfo|FilesystemIterator|string'], 'FilesystemIterator::getATime' => ['int'], 'FilesystemIterator::getBasename' => ['string', 'suffix='=>'string'], 'FilesystemIterator::getCTime' => ['int'], 'FilesystemIterator::getExtension' => ['string'], 'FilesystemIterator::getFileInfo' => ['SplFileInfo', 'class='=>'class-string'], 'FilesystemIterator::getFilename' => ['string'], 'FilesystemIterator::getFlags' => ['int'], 'FilesystemIterator::getGroup' => ['int'], 'FilesystemIterator::getInode' => ['int'], 'FilesystemIterator::getLinkTarget' => ['string'], 'FilesystemIterator::getMTime' => ['int'], 'FilesystemIterator::getOwner' => ['int'], 'FilesystemIterator::getPath' => ['string'], 'FilesystemIterator::getPathInfo' => ['?SplFileInfo', 'class='=>'class-string'], 'FilesystemIterator::getPathname' => ['string'], 'FilesystemIterator::getPerms' => ['int'], 'FilesystemIterator::getRealPath' => ['non-falsy-string'], 'FilesystemIterator::getSize' => ['int'], 'FilesystemIterator::getType' => ['string'], 'FilesystemIterator::isDir' => ['bool'], 'FilesystemIterator::isDot' => ['bool'], 'FilesystemIterator::isExecutable' => ['bool'], 'FilesystemIterator::isFile' => ['bool'], 'FilesystemIterator::isLink' => ['bool'], 'FilesystemIterator::isReadable' => ['bool'], 'FilesystemIterator::isWritable' => ['bool'], 'FilesystemIterator::key' => ['string'], 'FilesystemIterator::next' => ['void'], 'FilesystemIterator::openFile' => ['SplFileObject', 'mode='=>'string', 'useIncludePath='=>'bool', 'context='=>'resource'], 'FilesystemIterator::rewind' => ['void'], 'FilesystemIterator::seek' => ['void', 'offset'=>'int'], 'FilesystemIterator::setFileClass' => ['void', 'class='=>'class-string'], 'FilesystemIterator::setFlags' => ['void', 'flags'=>'int'], 'FilesystemIterator::setInfoClass' => ['void', 'class='=>'class-string'], 'FilesystemIterator::valid' => ['bool'], 'FilterIterator::__construct' => ['void', 'iterator'=>'Iterator'], 'FilterIterator::accept' => ['bool'], 'FilterIterator::current' => ['mixed'], 'FilterIterator::getInnerIterator' => ['Iterator'], 'FilterIterator::key' => ['mixed'], 'FilterIterator::next' => ['void'], 'FilterIterator::rewind' => ['void'], 'FilterIterator::valid' => ['bool'], 'GEOSGeometry::__toString' => ['string'], 'GEOSGeometry::area' => ['float'], 'GEOSGeometry::boundary' => ['GEOSGeometry'], 'GEOSGeometry::buffer' => ['GEOSGeometry', 'dist'=>'float', 'styleArray='=>'array'], 'GEOSGeometry::centroid' => ['GEOSGeometry'], 'GEOSGeometry::checkValidity' => ['array{valid: bool, reason?: string, location?: GEOSGeometry}'], 'GEOSGeometry::contains' => ['bool', 'geom'=>'GEOSGeometry'], 'GEOSGeometry::convexHull' => ['GEOSGeometry'], 'GEOSGeometry::coordinateDimension' => ['int'], 'GEOSGeometry::coveredBy' => ['bool', 'geom'=>'GEOSGeometry'], 'GEOSGeometry::covers' => ['bool', 'geom'=>'GEOSGeometry'], 'GEOSGeometry::crosses' => ['bool', 'geom'=>'GEOSGeometry'], 'GEOSGeometry::delaunayTriangulation' => ['GEOSGeometry', 'tolerance'=>'float', 'onlyEdges'=>'bool'], 'GEOSGeometry::difference' => ['GEOSGeometry', 'geom'=>'GEOSGeometry'], 'GEOSGeometry::dimension' => ['int'], 'GEOSGeometry::disjoint' => ['bool', 'geom'=>'GEOSGeometry'], 'GEOSGeometry::distance' => ['float', 'geom'=>'GEOSGeometry'], 'GEOSGeometry::endPoint' => ['GEOSGeometry'], 'GEOSGeometry::envelope' => ['GEOSGeometry'], 'GEOSGeometry::equals' => ['bool', 'geom'=>'GEOSGeometry'], 'GEOSGeometry::equalsExact' => ['bool', 'geom'=>'GEOSGeometry', 'tolerance'=>'float'], 'GEOSGeometry::exteriorRing' => ['GEOSGeometry'], 'GEOSGeometry::extractUniquePoints' => ['GEOSGeometry'], 'GEOSGeometry::geometryN' => ['GEOSGeometry', 'num'=>'int'], 'GEOSGeometry::getSRID' => ['int'], 'GEOSGeometry::getX' => ['float'], 'GEOSGeometry::getY' => ['float'], 'GEOSGeometry::hasZ' => ['bool'], 'GEOSGeometry::hausdorffDistance' => ['float', 'geom'=>'GEOSGeometry'], 'GEOSGeometry::interiorRingN' => ['GEOSGeometry', 'num'=>'int'], 'GEOSGeometry::interpolate' => ['GEOSGeometry', 'dist'=>'float', 'normalized'=>'bool'], 'GEOSGeometry::intersection' => ['GEOSGeometry', 'geom'=>'GEOSGeometry'], 'GEOSGeometry::intersects' => ['bool', 'geom'=>'GEOSGeometry'], 'GEOSGeometry::isClosed' => ['bool'], 'GEOSGeometry::isEmpty' => ['bool'], 'GEOSGeometry::isRing' => ['bool'], 'GEOSGeometry::isSimple' => ['bool'], 'GEOSGeometry::length' => ['float'], 'GEOSGeometry::node' => ['GEOSGeometry'], 'GEOSGeometry::normalize' => ['GEOSGeometry'], 'GEOSGeometry::numCoordinates' => ['int'], 'GEOSGeometry::numGeometries' => ['int'], 'GEOSGeometry::numInteriorRings' => ['int'], 'GEOSGeometry::numPoints' => ['int'], 'GEOSGeometry::offsetCurve' => ['GEOSGeometry', 'dist'=>'float', 'styleArray'=>'array'], 'GEOSGeometry::overlaps' => ['bool', 'geom'=>'GEOSGeometry'], 'GEOSGeometry::pointN' => ['GEOSGeometry', 'num'=>'int'], 'GEOSGeometry::pointOnSurface' => ['GEOSGeometry'], 'GEOSGeometry::project' => ['float', 'other'=>'GEOSGeometry', 'normalized'=>'bool'], 'GEOSGeometry::relate' => ['string|bool', 'otherGeom'=>'GEOSGeometry', 'pattern'=>'string'], 'GEOSGeometry::relateBoundaryNodeRule' => ['string', 'otherGeom'=>'GEOSGeometry', 'rule'=>'int'], 'GEOSGeometry::setSRID' => ['void', 'srid'=>'int'], 'GEOSGeometry::simplify' => ['GEOSGeometry', 'tolerance'=>'float', 'preserveTopology='=>'bool'], 'GEOSGeometry::snapTo' => ['GEOSGeometry', 'geom'=>'GEOSGeometry', 'tolerance'=>'float'], 'GEOSGeometry::startPoint' => ['GEOSGeometry'], 'GEOSGeometry::symDifference' => ['GEOSGeometry', 'geom'=>'GEOSGeometry'], 'GEOSGeometry::touches' => ['bool', 'geom'=>'GEOSGeometry'], 'GEOSGeometry::typeId' => ['int'], 'GEOSGeometry::typeName' => ['string'], 'GEOSGeometry::union' => ['GEOSGeometry', 'otherGeom='=>'GEOSGeometry'], 'GEOSGeometry::voronoiDiagram' => ['GEOSGeometry', 'tolerance'=>'float', 'onlyEdges'=>'bool', 'extent'=>'GEOSGeometry|null'], 'GEOSGeometry::within' => ['bool', 'geom'=>'GEOSGeometry'], 'GEOSLineMerge' => ['array', 'geom'=>'GEOSGeometry'], 'GEOSPolygonize' => ['array{rings: GEOSGeometry[], cut_edges?: GEOSGeometry[], dangles: GEOSGeometry[], invalid_rings: GEOSGeometry[]}', 'geom'=>'GEOSGeometry'], 'GEOSRelateMatch' => ['bool', 'matrix'=>'string', 'pattern'=>'string'], 'GEOSSharedPaths' => ['GEOSGeometry', 'geom1'=>'GEOSGeometry', 'geom2'=>'GEOSGeometry'], 'GEOSVersion' => ['string'], 'GEOSWKBReader::__construct' => ['void'], 'GEOSWKBReader::read' => ['GEOSGeometry', 'wkb'=>'string'], 'GEOSWKBReader::readHEX' => ['GEOSGeometry', 'wkb'=>'string'], 'GEOSWKBWriter::__construct' => ['void'], 'GEOSWKBWriter::getByteOrder' => ['int'], 'GEOSWKBWriter::getIncludeSRID' => ['bool'], 'GEOSWKBWriter::getOutputDimension' => ['int'], 'GEOSWKBWriter::setByteOrder' => ['void', 'byteOrder'=>'int'], 'GEOSWKBWriter::setIncludeSRID' => ['void', 'inc'=>'bool'], 'GEOSWKBWriter::setOutputDimension' => ['void', 'dim'=>'int'], 'GEOSWKBWriter::write' => ['string', 'geom'=>'GEOSGeometry'], 'GEOSWKBWriter::writeHEX' => ['string', 'geom'=>'GEOSGeometry'], 'GEOSWKTReader::__construct' => ['void'], 'GEOSWKTReader::read' => ['GEOSGeometry', 'wkt'=>'string'], 'GEOSWKTWriter::__construct' => ['void'], 'GEOSWKTWriter::getOutputDimension' => ['int'], 'GEOSWKTWriter::setOld3D' => ['void', 'val'=>'bool'], 'GEOSWKTWriter::setOutputDimension' => ['void', 'dim'=>'int'], 'GEOSWKTWriter::setRoundingPrecision' => ['void', 'prec'=>'int'], 'GEOSWKTWriter::setTrim' => ['void', 'trim'=>'bool'], 'GEOSWKTWriter::write' => ['string', 'geom'=>'GEOSGeometry'], 'GearmanClient::__construct' => ['void'], 'GearmanClient::addOptions' => ['bool', 'options'=>'int'], 'GearmanClient::addServer' => ['bool', 'host='=>'string', 'port='=>'int'], 'GearmanClient::addServers' => ['bool', 'servers='=>'string'], 'GearmanClient::addTask' => ['GearmanTask|false', 'function_name'=>'string', 'workload'=>'string', 'context='=>'mixed', 'unique='=>'string'], 'GearmanClient::addTaskBackground' => ['GearmanTask|false', 'function_name'=>'string', 'workload'=>'string', 'context='=>'mixed', 'unique='=>'string'], 'GearmanClient::addTaskHigh' => ['GearmanTask|false', 'function_name'=>'string', 'workload'=>'string', 'context='=>'mixed', 'unique='=>'string'], 'GearmanClient::addTaskHighBackground' => ['GearmanTask|false', 'function_name'=>'string', 'workload'=>'string', 'context='=>'mixed', 'unique='=>'string'], 'GearmanClient::addTaskLow' => ['GearmanTask|false', 'function_name'=>'string', 'workload'=>'string', 'context='=>'mixed', 'unique='=>'string'], 'GearmanClient::addTaskLowBackground' => ['GearmanTask|false', 'function_name'=>'string', 'workload'=>'string', 'context='=>'mixed', 'unique='=>'string'], 'GearmanClient::addTaskStatus' => ['GearmanTask', 'job_handle'=>'string', 'context='=>'string'], 'GearmanClient::clearCallbacks' => ['bool'], 'GearmanClient::clone' => ['GearmanClient'], 'GearmanClient::context' => ['string'], 'GearmanClient::data' => ['string'], 'GearmanClient::do' => ['string', 'function_name'=>'string', 'workload'=>'string', 'unique='=>'string'], 'GearmanClient::doBackground' => ['string', 'function_name'=>'string', 'workload'=>'string', 'unique='=>'string'], 'GearmanClient::doHigh' => ['string', 'function_name'=>'string', 'workload'=>'string', 'unique='=>'string'], 'GearmanClient::doHighBackground' => ['string', 'function_name'=>'string', 'workload'=>'string', 'unique='=>'string'], 'GearmanClient::doJobHandle' => ['string'], 'GearmanClient::doLow' => ['string', 'function_name'=>'string', 'workload'=>'string', 'unique='=>'string'], 'GearmanClient::doLowBackground' => ['string', 'function_name'=>'string', 'workload'=>'string', 'unique='=>'string'], 'GearmanClient::doNormal' => ['string', 'function_name'=>'string', 'workload'=>'string', 'unique='=>'string'], 'GearmanClient::doStatus' => ['array'], 'GearmanClient::echo' => ['bool', 'workload'=>'string'], 'GearmanClient::error' => ['string'], 'GearmanClient::getErrno' => ['int'], 'GearmanClient::jobStatus' => ['array', 'job_handle'=>'string'], 'GearmanClient::options' => [''], 'GearmanClient::ping' => ['bool', 'workload'=>'string'], 'GearmanClient::removeOptions' => ['bool', 'options'=>'int'], 'GearmanClient::returnCode' => ['int'], 'GearmanClient::runTasks' => ['bool'], 'GearmanClient::setClientCallback' => ['void', 'callback'=>'callable'], 'GearmanClient::setCompleteCallback' => ['bool', 'callback'=>'callable'], 'GearmanClient::setContext' => ['bool', 'context'=>'string'], 'GearmanClient::setCreatedCallback' => ['bool', 'callback'=>'string'], 'GearmanClient::setData' => ['bool', 'data'=>'string'], 'GearmanClient::setDataCallback' => ['bool', 'callback'=>'callable'], 'GearmanClient::setExceptionCallback' => ['bool', 'callback'=>'callable'], 'GearmanClient::setFailCallback' => ['bool', 'callback'=>'callable'], 'GearmanClient::setOptions' => ['bool', 'options'=>'int'], 'GearmanClient::setStatusCallback' => ['bool', 'callback'=>'callable'], 'GearmanClient::setTimeout' => ['bool', 'timeout'=>'int'], 'GearmanClient::setWarningCallback' => ['bool', 'callback'=>'callable'], 'GearmanClient::setWorkloadCallback' => ['bool', 'callback'=>'callable'], 'GearmanClient::timeout' => ['int'], 'GearmanClient::wait' => [''], 'GearmanJob::__construct' => ['void'], 'GearmanJob::complete' => ['bool', 'result'=>'string'], 'GearmanJob::data' => ['bool', 'data'=>'string'], 'GearmanJob::exception' => ['bool', 'exception'=>'string'], 'GearmanJob::fail' => ['bool'], 'GearmanJob::functionName' => ['string'], 'GearmanJob::handle' => ['string'], 'GearmanJob::returnCode' => ['int'], 'GearmanJob::sendComplete' => ['bool', 'result'=>'string'], 'GearmanJob::sendData' => ['bool', 'data'=>'string'], 'GearmanJob::sendException' => ['bool', 'exception'=>'string'], 'GearmanJob::sendFail' => ['bool'], 'GearmanJob::sendStatus' => ['bool', 'numerator'=>'int', 'denominator'=>'int'], 'GearmanJob::sendWarning' => ['bool', 'warning'=>'string'], 'GearmanJob::setReturn' => ['bool', 'gearman_return_t'=>'string'], 'GearmanJob::status' => ['bool', 'numerator'=>'int', 'denominator'=>'int'], 'GearmanJob::unique' => ['string'], 'GearmanJob::warning' => ['bool', 'warning'=>'string'], 'GearmanJob::workload' => ['string'], 'GearmanJob::workloadSize' => ['int'], 'GearmanTask::__construct' => ['void'], 'GearmanTask::create' => ['GearmanTask'], 'GearmanTask::data' => ['string|false'], 'GearmanTask::dataSize' => ['int|false'], 'GearmanTask::function' => ['string'], 'GearmanTask::functionName' => ['string'], 'GearmanTask::isKnown' => ['bool'], 'GearmanTask::isRunning' => ['bool'], 'GearmanTask::jobHandle' => ['string'], 'GearmanTask::recvData' => ['array|false', 'data_len'=>'int'], 'GearmanTask::returnCode' => ['int'], 'GearmanTask::sendData' => ['int', 'data'=>'string'], 'GearmanTask::sendWorkload' => ['int|false', 'data'=>'string'], 'GearmanTask::taskDenominator' => ['int|false'], 'GearmanTask::taskNumerator' => ['int|false'], 'GearmanTask::unique' => ['string|false'], 'GearmanTask::uuid' => ['string'], 'GearmanWorker::__construct' => ['void'], 'GearmanWorker::addFunction' => ['bool', 'function_name'=>'string', 'function'=>'callable', 'context='=>'mixed', 'timeout='=>'int'], 'GearmanWorker::addOptions' => ['bool', 'option'=>'int'], 'GearmanWorker::addServer' => ['bool', 'host='=>'string', 'port='=>'int'], 'GearmanWorker::addServers' => ['bool', 'servers'=>'string'], 'GearmanWorker::clone' => ['void'], 'GearmanWorker::echo' => ['bool', 'workload'=>'string'], 'GearmanWorker::error' => ['string'], 'GearmanWorker::getErrno' => ['int'], 'GearmanWorker::grabJob' => [''], 'GearmanWorker::options' => ['int'], 'GearmanWorker::register' => ['bool', 'function_name'=>'string', 'timeout='=>'int'], 'GearmanWorker::removeOptions' => ['bool', 'option'=>'int'], 'GearmanWorker::returnCode' => ['int'], 'GearmanWorker::setId' => ['bool', 'id'=>'string'], 'GearmanWorker::setOptions' => ['bool', 'option'=>'int'], 'GearmanWorker::setTimeout' => ['bool', 'timeout'=>'int'], 'GearmanWorker::timeout' => ['int'], 'GearmanWorker::unregister' => ['bool', 'function_name'=>'string'], 'GearmanWorker::unregisterAll' => ['bool'], 'GearmanWorker::wait' => ['bool'], 'GearmanWorker::work' => ['bool'], 'Gender\Gender::__construct' => ['void', 'dsn='=>'string'], 'Gender\Gender::connect' => ['bool', 'dsn'=>'string'], 'Gender\Gender::country' => ['array', 'country'=>'int'], 'Gender\Gender::get' => ['int', 'name'=>'string', 'country='=>'int'], 'Gender\Gender::isNick' => ['array', 'name0'=>'string', 'name1'=>'string', 'country='=>'int'], 'Gender\Gender::similarNames' => ['array', 'name'=>'string', 'country='=>'int'], 'Generator::current' => ['mixed'], 'Generator::getReturn' => ['mixed'], 'Generator::key' => ['mixed'], 'Generator::next' => ['void'], 'Generator::rewind' => ['void'], 'Generator::send' => ['mixed', 'value'=>'mixed'], 'Generator::throw' => ['mixed', 'exception'=>'Throwable'], 'Generator::valid' => ['bool'], 'GlobIterator::__construct' => ['void', 'pattern'=>'string', 'flags='=>'int'], 'GlobIterator::count' => ['int'], 'GlobIterator::current' => ['FilesystemIterator|SplFileInfo|string'], 'GlobIterator::getATime' => ['int'], 'GlobIterator::getBasename' => ['string', 'suffix='=>'string'], 'GlobIterator::getCTime' => ['int'], 'GlobIterator::getExtension' => ['string'], 'GlobIterator::getFileInfo' => ['SplFileInfo', 'class='=>'class-string'], 'GlobIterator::getFilename' => ['string'], 'GlobIterator::getFlags' => ['int'], 'GlobIterator::getGroup' => ['int'], 'GlobIterator::getInode' => ['int'], 'GlobIterator::getLinkTarget' => ['string|false'], 'GlobIterator::getMTime' => ['int'], 'GlobIterator::getOwner' => ['int'], 'GlobIterator::getPath' => ['string'], 'GlobIterator::getPathInfo' => ['?SplFileInfo', 'class='=>'class-string'], 'GlobIterator::getPathname' => ['string'], 'GlobIterator::getPerms' => ['int'], 'GlobIterator::getRealPath' => ['non-falsy-string|false'], 'GlobIterator::getSize' => ['int'], 'GlobIterator::getType' => ['string|false'], 'GlobIterator::isDir' => ['bool'], 'GlobIterator::isDot' => ['bool'], 'GlobIterator::isExecutable' => ['bool'], 'GlobIterator::isFile' => ['bool'], 'GlobIterator::isLink' => ['bool'], 'GlobIterator::isReadable' => ['bool'], 'GlobIterator::isWritable' => ['bool'], 'GlobIterator::key' => ['string'], 'GlobIterator::next' => ['void'], 'GlobIterator::openFile' => ['SplFileObject', 'mode='=>'string', 'useIncludePath='=>'bool', 'context='=>'resource'], 'GlobIterator::rewind' => ['void'], 'GlobIterator::seek' => ['void', 'offset'=>'int'], 'GlobIterator::setFileClass' => ['void', 'class='=>'class-string'], 'GlobIterator::setFlags' => ['void', 'flags'=>'int'], 'GlobIterator::setInfoClass' => ['void', 'class='=>'class-string'], 'GlobIterator::valid' => ['bool'], 'Gmagick::__construct' => ['void', 'filename='=>'string'], 'Gmagick::addimage' => ['Gmagick', 'gmagick'=>'gmagick'], 'Gmagick::addnoiseimage' => ['Gmagick', 'noise'=>'int'], 'Gmagick::annotateimage' => ['Gmagick', 'gmagickdraw'=>'gmagickdraw', 'x'=>'float', 'y'=>'float', 'angle'=>'float', 'text'=>'string'], 'Gmagick::blurimage' => ['Gmagick', 'radius'=>'float', 'sigma'=>'float', 'channel='=>'int'], 'Gmagick::borderimage' => ['Gmagick', 'color'=>'gmagickpixel', 'width'=>'int', 'height'=>'int'], 'Gmagick::charcoalimage' => ['Gmagick', 'radius'=>'float', 'sigma'=>'float'], 'Gmagick::chopimage' => ['Gmagick', 'width'=>'int', 'height'=>'int', 'x'=>'int', 'y'=>'int'], 'Gmagick::clear' => ['Gmagick'], 'Gmagick::commentimage' => ['Gmagick', 'comment'=>'string'], 'Gmagick::compositeimage' => ['Gmagick', 'source'=>'gmagick', 'compose'=>'int', 'x'=>'int', 'y'=>'int'], 'Gmagick::cropimage' => ['Gmagick', 'width'=>'int', 'height'=>'int', 'x'=>'int', 'y'=>'int'], 'Gmagick::cropthumbnailimage' => ['Gmagick', 'width'=>'int', 'height'=>'int'], 'Gmagick::current' => ['Gmagick'], 'Gmagick::cyclecolormapimage' => ['Gmagick', 'displace'=>'int'], 'Gmagick::deconstructimages' => ['Gmagick'], 'Gmagick::despeckleimage' => ['Gmagick'], 'Gmagick::destroy' => ['bool'], 'Gmagick::drawimage' => ['Gmagick', 'gmagickdraw'=>'gmagickdraw'], 'Gmagick::edgeimage' => ['Gmagick', 'radius'=>'float'], 'Gmagick::embossimage' => ['Gmagick', 'radius'=>'float', 'sigma'=>'float'], 'Gmagick::enhanceimage' => ['Gmagick'], 'Gmagick::equalizeimage' => ['Gmagick'], 'Gmagick::flipimage' => ['Gmagick'], 'Gmagick::flopimage' => ['Gmagick'], 'Gmagick::frameimage' => ['Gmagick', 'color'=>'gmagickpixel', 'width'=>'int', 'height'=>'int', 'inner_bevel'=>'int', 'outer_bevel'=>'int'], 'Gmagick::gammaimage' => ['Gmagick', 'gamma'=>'float'], 'Gmagick::getcopyright' => ['string'], 'Gmagick::getfilename' => ['string'], 'Gmagick::getimagebackgroundcolor' => ['GmagickPixel'], 'Gmagick::getimageblueprimary' => ['array'], 'Gmagick::getimagebordercolor' => ['GmagickPixel'], 'Gmagick::getimagechanneldepth' => ['int', 'channel_type'=>'int'], 'Gmagick::getimagecolors' => ['int'], 'Gmagick::getimagecolorspace' => ['int'], 'Gmagick::getimagecompose' => ['int'], 'Gmagick::getimagedelay' => ['int'], 'Gmagick::getimagedepth' => ['int'], 'Gmagick::getimagedispose' => ['int'], 'Gmagick::getimageextrema' => ['array'], 'Gmagick::getimagefilename' => ['string'], 'Gmagick::getimageformat' => ['string'], 'Gmagick::getimagegamma' => ['float'], 'Gmagick::getimagegreenprimary' => ['array'], 'Gmagick::getimageheight' => ['int'], 'Gmagick::getimagehistogram' => ['array'], 'Gmagick::getimageindex' => ['int'], 'Gmagick::getimageinterlacescheme' => ['int'], 'Gmagick::getimageiterations' => ['int'], 'Gmagick::getimagematte' => ['int'], 'Gmagick::getimagemattecolor' => ['GmagickPixel'], 'Gmagick::getimageprofile' => ['string', 'name'=>'string'], 'Gmagick::getimageredprimary' => ['array'], 'Gmagick::getimagerenderingintent' => ['int'], 'Gmagick::getimageresolution' => ['array'], 'Gmagick::getimagescene' => ['int'], 'Gmagick::getimagesignature' => ['string'], 'Gmagick::getimagetype' => ['int'], 'Gmagick::getimageunits' => ['int'], 'Gmagick::getimagewhitepoint' => ['array'], 'Gmagick::getimagewidth' => ['int'], 'Gmagick::getpackagename' => ['string'], 'Gmagick::getquantumdepth' => ['array'], 'Gmagick::getreleasedate' => ['string'], 'Gmagick::getsamplingfactors' => ['array'], 'Gmagick::getsize' => ['array'], 'Gmagick::getversion' => ['array'], 'Gmagick::hasnextimage' => ['bool'], 'Gmagick::haspreviousimage' => ['bool'], 'Gmagick::implodeimage' => ['mixed', 'radius'=>'float'], 'Gmagick::labelimage' => ['mixed', 'label'=>'string'], 'Gmagick::levelimage' => ['mixed', 'blackpoint'=>'float', 'gamma'=>'float', 'whitepoint'=>'float', 'channel='=>'int'], 'Gmagick::magnifyimage' => ['mixed'], 'Gmagick::mapimage' => ['Gmagick', 'gmagick'=>'gmagick', 'dither'=>'bool'], 'Gmagick::medianfilterimage' => ['void', 'radius'=>'float'], 'Gmagick::minifyimage' => ['Gmagick'], 'Gmagick::modulateimage' => ['Gmagick', 'brightness'=>'float', 'saturation'=>'float', 'hue'=>'float'], 'Gmagick::motionblurimage' => ['Gmagick', 'radius'=>'float', 'sigma'=>'float', 'angle'=>'float'], 'Gmagick::newimage' => ['Gmagick', 'width'=>'int', 'height'=>'int', 'background'=>'string', 'format='=>'string'], 'Gmagick::nextimage' => ['bool'], 'Gmagick::normalizeimage' => ['Gmagick', 'channel='=>'int'], 'Gmagick::oilpaintimage' => ['Gmagick', 'radius'=>'float'], 'Gmagick::previousimage' => ['bool'], 'Gmagick::profileimage' => ['Gmagick', 'name'=>'string', 'profile'=>'string'], 'Gmagick::quantizeimage' => ['Gmagick', 'numcolors'=>'int', 'colorspace'=>'int', 'treedepth'=>'int', 'dither'=>'bool', 'measureerror'=>'bool'], 'Gmagick::quantizeimages' => ['Gmagick', 'numcolors'=>'int', 'colorspace'=>'int', 'treedepth'=>'int', 'dither'=>'bool', 'measureerror'=>'bool'], 'Gmagick::queryfontmetrics' => ['array', 'draw'=>'gmagickdraw', 'text'=>'string'], 'Gmagick::queryfonts' => ['array', 'pattern='=>'string'], 'Gmagick::queryformats' => ['array', 'pattern='=>'string'], 'Gmagick::radialblurimage' => ['Gmagick', 'angle'=>'float', 'channel='=>'int'], 'Gmagick::raiseimage' => ['Gmagick', 'width'=>'int', 'height'=>'int', 'x'=>'int', 'y'=>'int', 'raise'=>'bool'], 'Gmagick::read' => ['Gmagick', 'filename'=>'string'], 'Gmagick::readimage' => ['Gmagick', 'filename'=>'string'], 'Gmagick::readimageblob' => ['Gmagick', 'imagecontents'=>'string', 'filename='=>'string'], 'Gmagick::readimagefile' => ['Gmagick', 'fp'=>'resource', 'filename='=>'string'], 'Gmagick::reducenoiseimage' => ['Gmagick', 'radius'=>'float'], 'Gmagick::removeimage' => ['Gmagick'], 'Gmagick::removeimageprofile' => ['string', 'name'=>'string'], 'Gmagick::resampleimage' => ['Gmagick', 'xresolution'=>'float', 'yresolution'=>'float', 'filter'=>'int', 'blur'=>'float'], 'Gmagick::resizeimage' => ['Gmagick', 'width'=>'int', 'height'=>'int', 'filter'=>'int', 'blur'=>'float', 'fit='=>'bool'], 'Gmagick::rollimage' => ['Gmagick', 'x'=>'int', 'y'=>'int'], 'Gmagick::rotateimage' => ['Gmagick', 'color'=>'mixed', 'degrees'=>'float'], 'Gmagick::scaleimage' => ['Gmagick', 'width'=>'int', 'height'=>'int', 'fit='=>'bool'], 'Gmagick::separateimagechannel' => ['Gmagick', 'channel'=>'int'], 'Gmagick::setCompressionQuality' => ['Gmagick', 'quality'=>'int'], 'Gmagick::setfilename' => ['Gmagick', 'filename'=>'string'], 'Gmagick::setimagebackgroundcolor' => ['Gmagick', 'color'=>'gmagickpixel'], 'Gmagick::setimageblueprimary' => ['Gmagick', 'x'=>'float', 'y'=>'float'], 'Gmagick::setimagebordercolor' => ['Gmagick', 'color'=>'gmagickpixel'], 'Gmagick::setimagechanneldepth' => ['Gmagick', 'channel'=>'int', 'depth'=>'int'], 'Gmagick::setimagecolorspace' => ['Gmagick', 'colorspace'=>'int'], 'Gmagick::setimagecompose' => ['Gmagick', 'composite'=>'int'], 'Gmagick::setimagedelay' => ['Gmagick', 'delay'=>'int'], 'Gmagick::setimagedepth' => ['Gmagick', 'depth'=>'int'], 'Gmagick::setimagedispose' => ['Gmagick', 'disposetype'=>'int'], 'Gmagick::setimagefilename' => ['Gmagick', 'filename'=>'string'], 'Gmagick::setimageformat' => ['Gmagick', 'imageformat'=>'string'], 'Gmagick::setimagegamma' => ['Gmagick', 'gamma'=>'float'], 'Gmagick::setimagegreenprimary' => ['Gmagick', 'x'=>'float', 'y'=>'float'], 'Gmagick::setimageindex' => ['Gmagick', 'index'=>'int'], 'Gmagick::setimageinterlacescheme' => ['Gmagick', 'interlace'=>'int'], 'Gmagick::setimageiterations' => ['Gmagick', 'iterations'=>'int'], 'Gmagick::setimageprofile' => ['Gmagick', 'name'=>'string', 'profile'=>'string'], 'Gmagick::setimageredprimary' => ['Gmagick', 'x'=>'float', 'y'=>'float'], 'Gmagick::setimagerenderingintent' => ['Gmagick', 'rendering_intent'=>'int'], 'Gmagick::setimageresolution' => ['Gmagick', 'xresolution'=>'float', 'yresolution'=>'float'], 'Gmagick::setimagescene' => ['Gmagick', 'scene'=>'int'], 'Gmagick::setimagetype' => ['Gmagick', 'imgtype'=>'int'], 'Gmagick::setimageunits' => ['Gmagick', 'resolution'=>'int'], 'Gmagick::setimagewhitepoint' => ['Gmagick', 'x'=>'float', 'y'=>'float'], 'Gmagick::setsamplingfactors' => ['Gmagick', 'factors'=>'array'], 'Gmagick::setsize' => ['Gmagick', 'columns'=>'int', 'rows'=>'int'], 'Gmagick::shearimage' => ['Gmagick', 'color'=>'mixed', 'xshear'=>'float', 'yshear'=>'float'], 'Gmagick::solarizeimage' => ['Gmagick', 'threshold'=>'int'], 'Gmagick::spreadimage' => ['Gmagick', 'radius'=>'float'], 'Gmagick::stripimage' => ['Gmagick'], 'Gmagick::swirlimage' => ['Gmagick', 'degrees'=>'float'], 'Gmagick::thumbnailimage' => ['Gmagick', 'width'=>'int', 'height'=>'int', 'fit='=>'bool'], 'Gmagick::trimimage' => ['Gmagick', 'fuzz'=>'float'], 'Gmagick::write' => ['Gmagick', 'filename'=>'string'], 'Gmagick::writeimage' => ['Gmagick', 'filename'=>'string', 'all_frames='=>'bool'], 'GmagickDraw::annotate' => ['GmagickDraw', 'x'=>'float', 'y'=>'float', 'text'=>'string'], 'GmagickDraw::arc' => ['GmagickDraw', 'sx'=>'float', 'sy'=>'float', 'ex'=>'float', 'ey'=>'float', 'sd'=>'float', 'ed'=>'float'], 'GmagickDraw::bezier' => ['GmagickDraw', 'coordinate_array'=>'array'], 'GmagickDraw::ellipse' => ['GmagickDraw', 'ox'=>'float', 'oy'=>'float', 'rx'=>'float', 'ry'=>'float', 'start'=>'float', 'end'=>'float'], 'GmagickDraw::getfillcolor' => ['GmagickPixel'], 'GmagickDraw::getfillopacity' => ['float'], 'GmagickDraw::getfont' => ['string|false'], 'GmagickDraw::getfontsize' => ['float'], 'GmagickDraw::getfontstyle' => ['int'], 'GmagickDraw::getfontweight' => ['int'], 'GmagickDraw::getstrokecolor' => ['GmagickPixel'], 'GmagickDraw::getstrokeopacity' => ['float'], 'GmagickDraw::getstrokewidth' => ['float'], 'GmagickDraw::gettextdecoration' => ['int'], 'GmagickDraw::gettextencoding' => ['string|false'], 'GmagickDraw::line' => ['GmagickDraw', 'sx'=>'float', 'sy'=>'float', 'ex'=>'float', 'ey'=>'float'], 'GmagickDraw::point' => ['GmagickDraw', 'x'=>'float', 'y'=>'float'], 'GmagickDraw::polygon' => ['GmagickDraw', 'coordinates'=>'array'], 'GmagickDraw::polyline' => ['GmagickDraw', 'coordinate_array'=>'array'], 'GmagickDraw::rectangle' => ['GmagickDraw', 'x1'=>'float', 'y1'=>'float', 'x2'=>'float', 'y2'=>'float'], 'GmagickDraw::rotate' => ['GmagickDraw', 'degrees'=>'float'], 'GmagickDraw::roundrectangle' => ['GmagickDraw', 'x1'=>'float', 'y1'=>'float', 'x2'=>'float', 'y2'=>'float', 'rx'=>'float', 'ry'=>'float'], 'GmagickDraw::scale' => ['GmagickDraw', 'x'=>'float', 'y'=>'float'], 'GmagickDraw::setfillcolor' => ['GmagickDraw', 'color'=>'string'], 'GmagickDraw::setfillopacity' => ['GmagickDraw', 'fill_opacity'=>'float'], 'GmagickDraw::setfont' => ['GmagickDraw', 'font'=>'string'], 'GmagickDraw::setfontsize' => ['GmagickDraw', 'pointsize'=>'float'], 'GmagickDraw::setfontstyle' => ['GmagickDraw', 'style'=>'int'], 'GmagickDraw::setfontweight' => ['GmagickDraw', 'weight'=>'int'], 'GmagickDraw::setstrokecolor' => ['GmagickDraw', 'color'=>'gmagickpixel'], 'GmagickDraw::setstrokeopacity' => ['GmagickDraw', 'stroke_opacity'=>'float'], 'GmagickDraw::setstrokewidth' => ['GmagickDraw', 'width'=>'float'], 'GmagickDraw::settextdecoration' => ['GmagickDraw', 'decoration'=>'int'], 'GmagickDraw::settextencoding' => ['GmagickDraw', 'encoding'=>'string'], 'GmagickPixel::__construct' => ['void', 'color='=>'string'], 'GmagickPixel::getcolor' => ['mixed', 'as_array='=>'bool', 'normalize_array='=>'bool'], 'GmagickPixel::getcolorcount' => ['int'], 'GmagickPixel::getcolorvalue' => ['float', 'color'=>'int'], 'GmagickPixel::setcolor' => ['GmagickPixel', 'color'=>'string'], 'GmagickPixel::setcolorvalue' => ['GmagickPixel', 'color'=>'int', 'value'=>'float'], 'Grpc\Call::__construct' => ['void', 'channel'=>'Grpc\Channel', 'method'=>'string', 'absolute_deadline'=>'Grpc\Timeval', 'host_override='=>'mixed'], 'Grpc\Call::cancel' => [''], 'Grpc\Call::getPeer' => ['string'], 'Grpc\Call::setCredentials' => ['int', 'creds_obj'=>'Grpc\CallCredentials'], 'Grpc\Call::startBatch' => ['object', 'batch'=>'array'], 'Grpc\CallCredentials::createComposite' => ['Grpc\CallCredentials', 'cred1'=>'Grpc\CallCredentials', 'cred2'=>'Grpc\CallCredentials'], 'Grpc\CallCredentials::createFromPlugin' => ['Grpc\CallCredentials', 'callback'=>'Closure'], 'Grpc\Channel::__construct' => ['void', 'target'=>'string', 'args='=>'array'], 'Grpc\Channel::close' => [''], 'Grpc\Channel::getConnectivityState' => ['int', 'try_to_connect='=>'bool'], 'Grpc\Channel::getTarget' => ['string'], 'Grpc\Channel::watchConnectivityState' => ['bool', 'last_state'=>'int', 'deadline_obj'=>'Grpc\Timeval'], 'Grpc\ChannelCredentials::createComposite' => ['Grpc\ChannelCredentials', 'cred1'=>'Grpc\ChannelCredentials', 'cred2'=>'Grpc\CallCredentials'], 'Grpc\ChannelCredentials::createDefault' => ['Grpc\ChannelCredentials'], 'Grpc\ChannelCredentials::createInsecure' => ['null'], 'Grpc\ChannelCredentials::createSsl' => ['Grpc\ChannelCredentials', 'pem_root_certs'=>'string', 'pem_private_key='=>'string', 'pem_cert_chain='=>'string'], 'Grpc\ChannelCredentials::setDefaultRootsPem' => ['', 'pem_roots'=>'string'], 'Grpc\Server::__construct' => ['void', 'args'=>'array'], 'Grpc\Server::addHttp2Port' => ['bool', 'addr'=>'string'], 'Grpc\Server::addSecureHttp2Port' => ['bool', 'addr'=>'string', 'creds_obj'=>'Grpc\ServerCredentials'], 'Grpc\Server::requestCall' => ['', 'tag_new'=>'int', 'tag_cancel'=>'int'], 'Grpc\Server::start' => [''], 'Grpc\ServerCredentials::createSsl' => ['object', 'pem_root_certs'=>'string', 'pem_private_key'=>'string', 'pem_cert_chain'=>'string'], 'Grpc\Timeval::__construct' => ['void', 'usec'=>'int'], 'Grpc\Timeval::add' => ['Grpc\Timeval', 'other'=>'Grpc\Timeval'], 'Grpc\Timeval::compare' => ['int', 'a'=>'Grpc\Timeval', 'b'=>'Grpc\Timeval'], 'Grpc\Timeval::infFuture' => ['Grpc\Timeval'], 'Grpc\Timeval::infPast' => ['Grpc\Timeval'], 'Grpc\Timeval::now' => ['Grpc\Timeval'], 'Grpc\Timeval::similar' => ['bool', 'a'=>'Grpc\Timeval', 'b'=>'Grpc\Timeval', 'threshold'=>'Grpc\Timeval'], 'Grpc\Timeval::sleepUntil' => [''], 'Grpc\Timeval::subtract' => ['Grpc\Timeval', 'other'=>'Grpc\Timeval'], 'Grpc\Timeval::zero' => ['Grpc\Timeval'], 'HRTime\PerformanceCounter::getElapsedTicks' => ['int'], 'HRTime\PerformanceCounter::getFrequency' => ['int'], 'HRTime\PerformanceCounter::getLastElapsedTicks' => ['int'], 'HRTime\PerformanceCounter::getTicks' => ['int'], 'HRTime\PerformanceCounter::getTicksSince' => ['int', 'start'=>'int'], 'HRTime\PerformanceCounter::isRunning' => ['bool'], 'HRTime\PerformanceCounter::start' => ['void'], 'HRTime\PerformanceCounter::stop' => ['void'], 'HRTime\StopWatch::getElapsedTicks' => ['int'], 'HRTime\StopWatch::getElapsedTime' => ['float', 'unit='=>'int'], 'HRTime\StopWatch::getLastElapsedTicks' => ['int'], 'HRTime\StopWatch::getLastElapsedTime' => ['float', 'unit='=>'int'], 'HRTime\StopWatch::isRunning' => ['bool'], 'HRTime\StopWatch::start' => ['void'], 'HRTime\StopWatch::stop' => ['void'], 'HaruAnnotation::setBorderStyle' => ['bool', 'width'=>'float', 'dash_on'=>'int', 'dash_off'=>'int'], 'HaruAnnotation::setHighlightMode' => ['bool', 'mode'=>'int'], 'HaruAnnotation::setIcon' => ['bool', 'icon'=>'int'], 'HaruAnnotation::setOpened' => ['bool', 'opened'=>'bool'], 'HaruDestination::setFit' => ['bool'], 'HaruDestination::setFitB' => ['bool'], 'HaruDestination::setFitBH' => ['bool', 'top'=>'float'], 'HaruDestination::setFitBV' => ['bool', 'left'=>'float'], 'HaruDestination::setFitH' => ['bool', 'top'=>'float'], 'HaruDestination::setFitR' => ['bool', 'left'=>'float', 'bottom'=>'float', 'right'=>'float', 'top'=>'float'], 'HaruDestination::setFitV' => ['bool', 'left'=>'float'], 'HaruDestination::setXYZ' => ['bool', 'left'=>'float', 'top'=>'float', 'zoom'=>'float'], 'HaruDoc::__construct' => ['void'], 'HaruDoc::addPage' => ['object'], 'HaruDoc::addPageLabel' => ['bool', 'first_page'=>'int', 'style'=>'int', 'first_num'=>'int', 'prefix='=>'string'], 'HaruDoc::createOutline' => ['object', 'title'=>'string', 'parent_outline='=>'object', 'encoder='=>'object'], 'HaruDoc::getCurrentEncoder' => ['object'], 'HaruDoc::getCurrentPage' => ['object'], 'HaruDoc::getEncoder' => ['object', 'encoding'=>'string'], 'HaruDoc::getFont' => ['object', 'fontname'=>'string', 'encoding='=>'string'], 'HaruDoc::getInfoAttr' => ['string', 'type'=>'int'], 'HaruDoc::getPageLayout' => ['int'], 'HaruDoc::getPageMode' => ['int'], 'HaruDoc::getStreamSize' => ['int'], 'HaruDoc::insertPage' => ['object', 'page'=>'object'], 'HaruDoc::loadJPEG' => ['object', 'filename'=>'string'], 'HaruDoc::loadPNG' => ['object', 'filename'=>'string', 'deferred='=>'bool'], 'HaruDoc::loadRaw' => ['object', 'filename'=>'string', 'width'=>'int', 'height'=>'int', 'color_space'=>'int'], 'HaruDoc::loadTTC' => ['string', 'fontfile'=>'string', 'index'=>'int', 'embed='=>'bool'], 'HaruDoc::loadTTF' => ['string', 'fontfile'=>'string', 'embed='=>'bool'], 'HaruDoc::loadType1' => ['string', 'afmfile'=>'string', 'pfmfile='=>'string'], 'HaruDoc::output' => ['bool'], 'HaruDoc::readFromStream' => ['string', 'bytes'=>'int'], 'HaruDoc::resetError' => ['bool'], 'HaruDoc::resetStream' => ['bool'], 'HaruDoc::save' => ['bool', 'file'=>'string'], 'HaruDoc::saveToStream' => ['bool'], 'HaruDoc::setCompressionMode' => ['bool', 'mode'=>'int'], 'HaruDoc::setCurrentEncoder' => ['bool', 'encoding'=>'string'], 'HaruDoc::setEncryptionMode' => ['bool', 'mode'=>'int', 'key_len='=>'int'], 'HaruDoc::setInfoAttr' => ['bool', 'type'=>'int', 'info'=>'string'], 'HaruDoc::setInfoDateAttr' => ['bool', 'type'=>'int', 'year'=>'int', 'month'=>'int', 'day'=>'int', 'hour'=>'int', 'min'=>'int', 'sec'=>'int', 'ind'=>'string', 'off_hour'=>'int', 'off_min'=>'int'], 'HaruDoc::setOpenAction' => ['bool', 'destination'=>'object'], 'HaruDoc::setPageLayout' => ['bool', 'layout'=>'int'], 'HaruDoc::setPageMode' => ['bool', 'mode'=>'int'], 'HaruDoc::setPagesConfiguration' => ['bool', 'page_per_pages'=>'int'], 'HaruDoc::setPassword' => ['bool', 'owner_password'=>'string', 'user_password'=>'string'], 'HaruDoc::setPermission' => ['bool', 'permission'=>'int'], 'HaruDoc::useCNSEncodings' => ['bool'], 'HaruDoc::useCNSFonts' => ['bool'], 'HaruDoc::useCNTEncodings' => ['bool'], 'HaruDoc::useCNTFonts' => ['bool'], 'HaruDoc::useJPEncodings' => ['bool'], 'HaruDoc::useJPFonts' => ['bool'], 'HaruDoc::useKREncodings' => ['bool'], 'HaruDoc::useKRFonts' => ['bool'], 'HaruEncoder::getByteType' => ['int', 'text'=>'string', 'index'=>'int'], 'HaruEncoder::getType' => ['int'], 'HaruEncoder::getUnicode' => ['int', 'character'=>'int'], 'HaruEncoder::getWritingMode' => ['int'], 'HaruFont::getAscent' => ['int'], 'HaruFont::getCapHeight' => ['int'], 'HaruFont::getDescent' => ['int'], 'HaruFont::getEncodingName' => ['string'], 'HaruFont::getFontName' => ['string'], 'HaruFont::getTextWidth' => ['array', 'text'=>'string'], 'HaruFont::getUnicodeWidth' => ['int', 'character'=>'int'], 'HaruFont::getXHeight' => ['int'], 'HaruFont::measureText' => ['int', 'text'=>'string', 'width'=>'float', 'font_size'=>'float', 'char_space'=>'float', 'word_space'=>'float', 'word_wrap='=>'bool'], 'HaruImage::getBitsPerComponent' => ['int'], 'HaruImage::getColorSpace' => ['string'], 'HaruImage::getHeight' => ['int'], 'HaruImage::getSize' => ['array'], 'HaruImage::getWidth' => ['int'], 'HaruImage::setColorMask' => ['bool', 'rmin'=>'int', 'rmax'=>'int', 'gmin'=>'int', 'gmax'=>'int', 'bmin'=>'int', 'bmax'=>'int'], 'HaruImage::setMaskImage' => ['bool', 'mask_image'=>'object'], 'HaruOutline::setDestination' => ['bool', 'destination'=>'object'], 'HaruOutline::setOpened' => ['bool', 'opened'=>'bool'], 'HaruPage::arc' => ['bool', 'x'=>'float', 'y'=>'float', 'ray'=>'float', 'ang1'=>'float', 'ang2'=>'float'], 'HaruPage::beginText' => ['bool'], 'HaruPage::circle' => ['bool', 'x'=>'float', 'y'=>'float', 'ray'=>'float'], 'HaruPage::closePath' => ['bool'], 'HaruPage::concat' => ['bool', 'a'=>'float', 'b'=>'float', 'c'=>'float', 'd'=>'float', 'x'=>'float', 'y'=>'float'], 'HaruPage::createDestination' => ['object'], 'HaruPage::createLinkAnnotation' => ['object', 'rectangle'=>'array', 'destination'=>'object'], 'HaruPage::createTextAnnotation' => ['object', 'rectangle'=>'array', 'text'=>'string', 'encoder='=>'object'], 'HaruPage::createURLAnnotation' => ['object', 'rectangle'=>'array', 'url'=>'string'], 'HaruPage::curveTo' => ['bool', 'x1'=>'float', 'y1'=>'float', 'x2'=>'float', 'y2'=>'float', 'x3'=>'float', 'y3'=>'float'], 'HaruPage::curveTo2' => ['bool', 'x2'=>'float', 'y2'=>'float', 'x3'=>'float', 'y3'=>'float'], 'HaruPage::curveTo3' => ['bool', 'x1'=>'float', 'y1'=>'float', 'x3'=>'float', 'y3'=>'float'], 'HaruPage::drawImage' => ['bool', 'image'=>'object', 'x'=>'float', 'y'=>'float', 'width'=>'float', 'height'=>'float'], 'HaruPage::ellipse' => ['bool', 'x'=>'float', 'y'=>'float', 'xray'=>'float', 'yray'=>'float'], 'HaruPage::endPath' => ['bool'], 'HaruPage::endText' => ['bool'], 'HaruPage::eoFillStroke' => ['bool', 'close_path='=>'bool'], 'HaruPage::eofill' => ['bool'], 'HaruPage::fill' => ['bool'], 'HaruPage::fillStroke' => ['bool', 'close_path='=>'bool'], 'HaruPage::getCMYKFill' => ['array'], 'HaruPage::getCMYKStroke' => ['array'], 'HaruPage::getCharSpace' => ['float'], 'HaruPage::getCurrentFont' => ['object'], 'HaruPage::getCurrentFontSize' => ['float'], 'HaruPage::getCurrentPos' => ['array'], 'HaruPage::getCurrentTextPos' => ['array'], 'HaruPage::getDash' => ['array'], 'HaruPage::getFillingColorSpace' => ['int'], 'HaruPage::getFlatness' => ['float'], 'HaruPage::getGMode' => ['int'], 'HaruPage::getGrayFill' => ['float'], 'HaruPage::getGrayStroke' => ['float'], 'HaruPage::getHeight' => ['float'], 'HaruPage::getHorizontalScaling' => ['float'], 'HaruPage::getLineCap' => ['int'], 'HaruPage::getLineJoin' => ['int'], 'HaruPage::getLineWidth' => ['float'], 'HaruPage::getMiterLimit' => ['float'], 'HaruPage::getRGBFill' => ['array'], 'HaruPage::getRGBStroke' => ['array'], 'HaruPage::getStrokingColorSpace' => ['int'], 'HaruPage::getTextLeading' => ['float'], 'HaruPage::getTextMatrix' => ['array'], 'HaruPage::getTextRenderingMode' => ['int'], 'HaruPage::getTextRise' => ['float'], 'HaruPage::getTextWidth' => ['float', 'text'=>'string'], 'HaruPage::getTransMatrix' => ['array'], 'HaruPage::getWidth' => ['float'], 'HaruPage::getWordSpace' => ['float'], 'HaruPage::lineTo' => ['bool', 'x'=>'float', 'y'=>'float'], 'HaruPage::measureText' => ['int', 'text'=>'string', 'width'=>'float', 'wordwrap='=>'bool'], 'HaruPage::moveTextPos' => ['bool', 'x'=>'float', 'y'=>'float', 'set_leading='=>'bool'], 'HaruPage::moveTo' => ['bool', 'x'=>'float', 'y'=>'float'], 'HaruPage::moveToNextLine' => ['bool'], 'HaruPage::rectangle' => ['bool', 'x'=>'float', 'y'=>'float', 'width'=>'float', 'height'=>'float'], 'HaruPage::setCMYKFill' => ['bool', 'c'=>'float', 'm'=>'float', 'y'=>'float', 'k'=>'float'], 'HaruPage::setCMYKStroke' => ['bool', 'c'=>'float', 'm'=>'float', 'y'=>'float', 'k'=>'float'], 'HaruPage::setCharSpace' => ['bool', 'char_space'=>'float'], 'HaruPage::setDash' => ['bool', 'pattern'=>'array', 'phase'=>'int'], 'HaruPage::setFlatness' => ['bool', 'flatness'=>'float'], 'HaruPage::setFontAndSize' => ['bool', 'font'=>'object', 'size'=>'float'], 'HaruPage::setGrayFill' => ['bool', 'value'=>'float'], 'HaruPage::setGrayStroke' => ['bool', 'value'=>'float'], 'HaruPage::setHeight' => ['bool', 'height'=>'float'], 'HaruPage::setHorizontalScaling' => ['bool', 'scaling'=>'float'], 'HaruPage::setLineCap' => ['bool', 'cap'=>'int'], 'HaruPage::setLineJoin' => ['bool', 'join'=>'int'], 'HaruPage::setLineWidth' => ['bool', 'width'=>'float'], 'HaruPage::setMiterLimit' => ['bool', 'limit'=>'float'], 'HaruPage::setRGBFill' => ['bool', 'r'=>'float', 'g'=>'float', 'b'=>'float'], 'HaruPage::setRGBStroke' => ['bool', 'r'=>'float', 'g'=>'float', 'b'=>'float'], 'HaruPage::setRotate' => ['bool', 'angle'=>'int'], 'HaruPage::setSize' => ['bool', 'size'=>'int', 'direction'=>'int'], 'HaruPage::setSlideShow' => ['bool', 'type'=>'int', 'disp_time'=>'float', 'trans_time'=>'float'], 'HaruPage::setTextLeading' => ['bool', 'text_leading'=>'float'], 'HaruPage::setTextMatrix' => ['bool', 'a'=>'float', 'b'=>'float', 'c'=>'float', 'd'=>'float', 'x'=>'float', 'y'=>'float'], 'HaruPage::setTextRenderingMode' => ['bool', 'mode'=>'int'], 'HaruPage::setTextRise' => ['bool', 'rise'=>'float'], 'HaruPage::setWidth' => ['bool', 'width'=>'float'], 'HaruPage::setWordSpace' => ['bool', 'word_space'=>'float'], 'HaruPage::showText' => ['bool', 'text'=>'string'], 'HaruPage::showTextNextLine' => ['bool', 'text'=>'string', 'word_space='=>'float', 'char_space='=>'float'], 'HaruPage::stroke' => ['bool', 'close_path='=>'bool'], 'HaruPage::textOut' => ['bool', 'x'=>'float', 'y'=>'float', 'text'=>'string'], 'HaruPage::textRect' => ['bool', 'left'=>'float', 'top'=>'float', 'right'=>'float', 'bottom'=>'float', 'text'=>'string', 'align='=>'int'], 'HttpDeflateStream::__construct' => ['void', 'flags='=>'int'], 'HttpDeflateStream::factory' => ['HttpDeflateStream', 'flags='=>'int', 'class_name='=>'string'], 'HttpDeflateStream::finish' => ['string', 'data='=>'string'], 'HttpDeflateStream::flush' => ['string|false', 'data='=>'string'], 'HttpDeflateStream::update' => ['string|false', 'data'=>'string'], 'HttpInflateStream::__construct' => ['void', 'flags='=>'int'], 'HttpInflateStream::factory' => ['HttpInflateStream', 'flags='=>'int', 'class_name='=>'string'], 'HttpInflateStream::finish' => ['string', 'data='=>'string'], 'HttpInflateStream::flush' => ['string|false', 'data='=>'string'], 'HttpInflateStream::update' => ['string|false', 'data'=>'string'], 'HttpMessage::__construct' => ['void', 'message='=>'string'], 'HttpMessage::__toString' => ['string'], 'HttpMessage::addHeaders' => ['void', 'headers'=>'array', 'append='=>'bool'], 'HttpMessage::count' => ['int'], 'HttpMessage::current' => ['mixed'], 'HttpMessage::detach' => ['HttpMessage'], 'HttpMessage::factory' => ['?HttpMessage', 'raw_message='=>'string', 'class_name='=>'string'], 'HttpMessage::fromEnv' => ['?HttpMessage', 'message_type'=>'int', 'class_name='=>'string'], 'HttpMessage::fromString' => ['?HttpMessage', 'raw_message='=>'string', 'class_name='=>'string'], 'HttpMessage::getBody' => ['string'], 'HttpMessage::getHeader' => ['?string', 'header'=>'string'], 'HttpMessage::getHeaders' => ['array'], 'HttpMessage::getHttpVersion' => ['string'], 'HttpMessage::getInfo' => [''], 'HttpMessage::getParentMessage' => ['HttpMessage'], 'HttpMessage::getRequestMethod' => ['string|false'], 'HttpMessage::getRequestUrl' => ['string|false'], 'HttpMessage::getResponseCode' => ['int'], 'HttpMessage::getResponseStatus' => ['string'], 'HttpMessage::getType' => ['int'], 'HttpMessage::guessContentType' => ['string|false', 'magic_file'=>'string', 'magic_mode='=>'int'], 'HttpMessage::key' => ['int|string'], 'HttpMessage::next' => ['void'], 'HttpMessage::prepend' => ['void', 'message'=>'HttpMessage', 'top='=>'bool'], 'HttpMessage::reverse' => ['HttpMessage'], 'HttpMessage::rewind' => ['void'], 'HttpMessage::send' => ['bool'], 'HttpMessage::serialize' => ['string'], 'HttpMessage::setBody' => ['void', 'body'=>'string'], 'HttpMessage::setHeaders' => ['void', 'headers'=>'array'], 'HttpMessage::setHttpVersion' => ['bool', 'version'=>'string'], 'HttpMessage::setInfo' => ['', 'http_info'=>''], 'HttpMessage::setRequestMethod' => ['bool', 'method'=>'string'], 'HttpMessage::setRequestUrl' => ['bool', 'url'=>'string'], 'HttpMessage::setResponseCode' => ['bool', 'code'=>'int'], 'HttpMessage::setResponseStatus' => ['bool', 'status'=>'string'], 'HttpMessage::setType' => ['void', 'type'=>'int'], 'HttpMessage::toMessageTypeObject' => ['HttpRequest|HttpResponse|null'], 'HttpMessage::toString' => ['string', 'include_parent='=>'bool'], 'HttpMessage::unserialize' => ['void', 'serialized'=>'string'], 'HttpMessage::valid' => ['bool'], 'HttpQueryString::__construct' => ['void', 'global='=>'bool', 'add='=>'mixed'], 'HttpQueryString::__toString' => ['string'], 'HttpQueryString::factory' => ['', 'global'=>'', 'params'=>'', 'class_name'=>''], 'HttpQueryString::get' => ['mixed', 'key='=>'string', 'type='=>'mixed', 'defval='=>'mixed', 'delete='=>'bool'], 'HttpQueryString::getArray' => ['', 'name'=>'', 'defval'=>'', 'delete'=>''], 'HttpQueryString::getBool' => ['', 'name'=>'', 'defval'=>'', 'delete'=>''], 'HttpQueryString::getFloat' => ['', 'name'=>'', 'defval'=>'', 'delete'=>''], 'HttpQueryString::getInt' => ['', 'name'=>'', 'defval'=>'', 'delete'=>''], 'HttpQueryString::getObject' => ['', 'name'=>'', 'defval'=>'', 'delete'=>''], 'HttpQueryString::getString' => ['', 'name'=>'', 'defval'=>'', 'delete'=>''], 'HttpQueryString::mod' => ['HttpQueryString', 'params'=>'mixed'], 'HttpQueryString::offsetExists' => ['bool', 'offset'=>'int|string'], 'HttpQueryString::offsetGet' => ['mixed', 'offset'=>'int|string'], 'HttpQueryString::offsetSet' => ['void', 'offset'=>'int|string|null', 'value'=>'mixed'], 'HttpQueryString::offsetUnset' => ['void', 'offset'=>'int|string'], 'HttpQueryString::serialize' => ['string'], 'HttpQueryString::set' => ['string', 'params'=>'mixed'], 'HttpQueryString::singleton' => ['HttpQueryString', 'global='=>'bool'], 'HttpQueryString::toArray' => ['array'], 'HttpQueryString::toString' => ['string'], 'HttpQueryString::unserialize' => ['void', 'serialized'=>'string'], 'HttpQueryString::xlate' => ['bool', 'ie'=>'string', 'oe'=>'string'], 'HttpRequest::__construct' => ['void', 'url='=>'string', 'request_method='=>'int', 'options='=>'array'], 'HttpRequest::addBody' => ['', 'request_body_data'=>''], 'HttpRequest::addCookies' => ['bool', 'cookies'=>'array'], 'HttpRequest::addHeaders' => ['bool', 'headers'=>'array'], 'HttpRequest::addPostFields' => ['bool', 'post_data'=>'array'], 'HttpRequest::addPostFile' => ['bool', 'name'=>'string', 'file'=>'string', 'content_type='=>'string'], 'HttpRequest::addPutData' => ['bool', 'put_data'=>'string'], 'HttpRequest::addQueryData' => ['bool', 'query_params'=>'array'], 'HttpRequest::addRawPostData' => ['bool', 'raw_post_data'=>'string'], 'HttpRequest::addSslOptions' => ['bool', 'options'=>'array'], 'HttpRequest::clearHistory' => ['void'], 'HttpRequest::enableCookies' => ['bool'], 'HttpRequest::encodeBody' => ['', 'fields'=>'', 'files'=>''], 'HttpRequest::factory' => ['', 'url'=>'', 'method'=>'', 'options'=>'', 'class_name'=>''], 'HttpRequest::flushCookies' => [''], 'HttpRequest::get' => ['', 'url'=>'', 'options'=>'', '&info'=>''], 'HttpRequest::getBody' => [''], 'HttpRequest::getContentType' => ['string'], 'HttpRequest::getCookies' => ['array'], 'HttpRequest::getHeaders' => ['array'], 'HttpRequest::getHistory' => ['HttpMessage'], 'HttpRequest::getMethod' => ['int'], 'HttpRequest::getOptions' => ['array'], 'HttpRequest::getPostFields' => ['array'], 'HttpRequest::getPostFiles' => ['array'], 'HttpRequest::getPutData' => ['string'], 'HttpRequest::getPutFile' => ['string'], 'HttpRequest::getQueryData' => ['string'], 'HttpRequest::getRawPostData' => ['string'], 'HttpRequest::getRawRequestMessage' => ['string'], 'HttpRequest::getRawResponseMessage' => ['string'], 'HttpRequest::getRequestMessage' => ['HttpMessage'], 'HttpRequest::getResponseBody' => ['string'], 'HttpRequest::getResponseCode' => ['int'], 'HttpRequest::getResponseCookies' => ['stdClass[]', 'flags='=>'int', 'allowed_extras='=>'array'], 'HttpRequest::getResponseData' => ['array'], 'HttpRequest::getResponseHeader' => ['mixed', 'name='=>'string'], 'HttpRequest::getResponseInfo' => ['mixed', 'name='=>'string'], 'HttpRequest::getResponseMessage' => ['HttpMessage'], 'HttpRequest::getResponseStatus' => ['string'], 'HttpRequest::getSslOptions' => ['array'], 'HttpRequest::getUrl' => ['string'], 'HttpRequest::head' => ['', 'url'=>'', 'options'=>'', '&info'=>''], 'HttpRequest::methodExists' => ['', 'method'=>''], 'HttpRequest::methodName' => ['', 'method_id'=>''], 'HttpRequest::methodRegister' => ['', 'method_name'=>''], 'HttpRequest::methodUnregister' => ['', 'method'=>''], 'HttpRequest::postData' => ['', 'url'=>'', 'data'=>'', 'options'=>'', '&info'=>''], 'HttpRequest::postFields' => ['', 'url'=>'', 'data'=>'', 'options'=>'', '&info'=>''], 'HttpRequest::putData' => ['', 'url'=>'', 'data'=>'', 'options'=>'', '&info'=>''], 'HttpRequest::putFile' => ['', 'url'=>'', 'file'=>'', 'options'=>'', '&info'=>''], 'HttpRequest::putStream' => ['', 'url'=>'', 'stream'=>'', 'options'=>'', '&info'=>''], 'HttpRequest::resetCookies' => ['bool', 'session_only='=>'bool'], 'HttpRequest::send' => ['HttpMessage'], 'HttpRequest::setBody' => ['bool', 'request_body_data='=>'string'], 'HttpRequest::setContentType' => ['bool', 'content_type'=>'string'], 'HttpRequest::setCookies' => ['bool', 'cookies='=>'array'], 'HttpRequest::setHeaders' => ['bool', 'headers='=>'array'], 'HttpRequest::setMethod' => ['bool', 'request_method'=>'int'], 'HttpRequest::setOptions' => ['bool', 'options='=>'array'], 'HttpRequest::setPostFields' => ['bool', 'post_data'=>'array'], 'HttpRequest::setPostFiles' => ['bool', 'post_files'=>'array'], 'HttpRequest::setPutData' => ['bool', 'put_data='=>'string'], 'HttpRequest::setPutFile' => ['bool', 'file='=>'string'], 'HttpRequest::setQueryData' => ['bool', 'query_data'=>'mixed'], 'HttpRequest::setRawPostData' => ['bool', 'raw_post_data='=>'string'], 'HttpRequest::setSslOptions' => ['bool', 'options='=>'array'], 'HttpRequest::setUrl' => ['bool', 'url'=>'string'], 'HttpRequestDataShare::__construct' => ['void'], 'HttpRequestDataShare::__destruct' => ['void'], 'HttpRequestDataShare::attach' => ['', 'request'=>'HttpRequest'], 'HttpRequestDataShare::count' => ['int'], 'HttpRequestDataShare::detach' => ['', 'request'=>'HttpRequest'], 'HttpRequestDataShare::factory' => ['', 'global'=>'', 'class_name'=>''], 'HttpRequestDataShare::reset' => [''], 'HttpRequestDataShare::singleton' => ['', 'global'=>''], 'HttpRequestPool::__construct' => ['void', 'request='=>'HttpRequest'], 'HttpRequestPool::__destruct' => ['void'], 'HttpRequestPool::attach' => ['bool', 'request'=>'HttpRequest'], 'HttpRequestPool::count' => ['int'], 'HttpRequestPool::current' => ['mixed'], 'HttpRequestPool::detach' => ['bool', 'request'=>'HttpRequest'], 'HttpRequestPool::enableEvents' => ['', 'enable'=>''], 'HttpRequestPool::enablePipelining' => ['', 'enable'=>''], 'HttpRequestPool::getAttachedRequests' => ['array'], 'HttpRequestPool::getFinishedRequests' => ['array'], 'HttpRequestPool::key' => ['int|string'], 'HttpRequestPool::next' => ['void'], 'HttpRequestPool::reset' => ['void'], 'HttpRequestPool::rewind' => ['void'], 'HttpRequestPool::send' => ['bool'], 'HttpRequestPool::socketPerform' => ['bool'], 'HttpRequestPool::socketSelect' => ['bool', 'timeout='=>'float'], 'HttpRequestPool::valid' => ['bool'], 'HttpResponse::capture' => ['void'], 'HttpResponse::getBufferSize' => ['int'], 'HttpResponse::getCache' => ['bool'], 'HttpResponse::getCacheControl' => ['string'], 'HttpResponse::getContentDisposition' => ['string'], 'HttpResponse::getContentType' => ['string'], 'HttpResponse::getData' => ['string'], 'HttpResponse::getETag' => ['string'], 'HttpResponse::getFile' => ['string'], 'HttpResponse::getGzip' => ['bool'], 'HttpResponse::getHeader' => ['mixed', 'name='=>'string'], 'HttpResponse::getLastModified' => ['int'], 'HttpResponse::getRequestBody' => ['string'], 'HttpResponse::getRequestBodyStream' => ['resource'], 'HttpResponse::getRequestHeaders' => ['array'], 'HttpResponse::getStream' => ['resource'], 'HttpResponse::getThrottleDelay' => ['float'], 'HttpResponse::guessContentType' => ['string|false', 'magic_file'=>'string', 'magic_mode='=>'int'], 'HttpResponse::redirect' => ['void', 'url='=>'string', 'params='=>'array', 'session='=>'bool', 'status='=>'int'], 'HttpResponse::send' => ['bool', 'clean_ob='=>'bool'], 'HttpResponse::setBufferSize' => ['bool', 'bytes'=>'int'], 'HttpResponse::setCache' => ['bool', 'cache'=>'bool'], 'HttpResponse::setCacheControl' => ['bool', 'control'=>'string', 'max_age='=>'int', 'must_revalidate='=>'bool'], 'HttpResponse::setContentDisposition' => ['bool', 'filename'=>'string', 'inline='=>'bool'], 'HttpResponse::setContentType' => ['bool', 'content_type'=>'string'], 'HttpResponse::setData' => ['bool', 'data'=>'mixed'], 'HttpResponse::setETag' => ['bool', 'etag'=>'string'], 'HttpResponse::setFile' => ['bool', 'file'=>'string'], 'HttpResponse::setGzip' => ['bool', 'gzip'=>'bool'], 'HttpResponse::setHeader' => ['bool', 'name'=>'string', 'value='=>'mixed', 'replace='=>'bool'], 'HttpResponse::setLastModified' => ['bool', 'timestamp'=>'int'], 'HttpResponse::setStream' => ['bool', 'stream'=>'resource'], 'HttpResponse::setThrottleDelay' => ['bool', 'seconds'=>'float'], 'HttpResponse::status' => ['bool', 'status'=>'int'], 'HttpUtil::buildCookie' => ['', 'cookie_array'=>''], 'HttpUtil::buildStr' => ['', 'query'=>'', 'prefix'=>'', 'arg_sep'=>''], 'HttpUtil::buildUrl' => ['', 'url'=>'', 'parts'=>'', 'flags'=>'', '&composed'=>''], 'HttpUtil::chunkedDecode' => ['', 'encoded_string'=>''], 'HttpUtil::date' => ['', 'timestamp'=>''], 'HttpUtil::deflate' => ['', 'plain'=>'', 'flags'=>''], 'HttpUtil::inflate' => ['', 'encoded'=>''], 'HttpUtil::matchEtag' => ['', 'plain_etag'=>'', 'for_range'=>''], 'HttpUtil::matchModified' => ['', 'last_modified'=>'', 'for_range'=>''], 'HttpUtil::matchRequestHeader' => ['', 'header_name'=>'', 'header_value'=>'', 'case_sensitive'=>''], 'HttpUtil::negotiateCharset' => ['', 'supported'=>'', '&result'=>''], 'HttpUtil::negotiateContentType' => ['', 'supported'=>'', '&result'=>''], 'HttpUtil::negotiateLanguage' => ['', 'supported'=>'', '&result'=>''], 'HttpUtil::parseCookie' => ['', 'cookie_string'=>''], 'HttpUtil::parseHeaders' => ['', 'headers_string'=>''], 'HttpUtil::parseMessage' => ['', 'message_string'=>''], 'HttpUtil::parseParams' => ['', 'param_string'=>'', 'flags'=>''], 'HttpUtil::support' => ['', 'feature'=>''], 'Imagick::__construct' => ['void', 'files='=>'string|string[]'], 'Imagick::__toString' => ['string'], 'Imagick::adaptiveBlurImage' => ['bool', 'radius'=>'float', 'sigma'=>'float', 'channel='=>'int'], 'Imagick::adaptiveResizeImage' => ['bool', 'columns'=>'int', 'rows'=>'int', 'bestfit='=>'bool'], 'Imagick::adaptiveSharpenImage' => ['bool', 'radius'=>'float', 'sigma'=>'float', 'channel='=>'int'], 'Imagick::adaptiveThresholdImage' => ['bool', 'width'=>'int', 'height'=>'int', 'offset'=>'int'], 'Imagick::addImage' => ['bool', 'source'=>'Imagick'], 'Imagick::addNoiseImage' => ['bool', 'noise_type'=>'int', 'channel='=>'int'], 'Imagick::affineTransformImage' => ['bool', 'matrix'=>'ImagickDraw'], 'Imagick::animateImages' => ['bool', 'x_server'=>'string'], 'Imagick::annotateImage' => ['bool', 'draw_settings'=>'ImagickDraw', 'x'=>'float', 'y'=>'float', 'angle'=>'float', 'text'=>'string'], 'Imagick::appendImages' => ['Imagick', 'stack'=>'bool'], 'Imagick::autoGammaImage' => ['bool', 'channel='=>'int'], 'Imagick::autoLevelImage' => ['void', 'CHANNEL='=>'string'], 'Imagick::autoOrient' => ['bool'], 'Imagick::averageImages' => ['Imagick'], 'Imagick::blackThresholdImage' => ['bool', 'threshold'=>'mixed'], 'Imagick::blueShiftImage' => ['void', 'factor='=>'float'], 'Imagick::blurImage' => ['bool', 'radius'=>'float', 'sigma'=>'float', 'channel='=>'int'], 'Imagick::borderImage' => ['bool', 'bordercolor'=>'mixed', 'width'=>'int', 'height'=>'int'], 'Imagick::brightnessContrastImage' => ['void', 'brightness'=>'string', 'contrast'=>'string', 'CHANNEL='=>'string'], 'Imagick::charcoalImage' => ['bool', 'radius'=>'float', 'sigma'=>'float'], 'Imagick::chopImage' => ['bool', 'width'=>'int', 'height'=>'int', 'x'=>'int', 'y'=>'int'], 'Imagick::clampImage' => ['void', 'CHANNEL='=>'string'], 'Imagick::clear' => ['bool'], 'Imagick::clipImage' => ['bool'], 'Imagick::clipImagePath' => ['void', 'pathname'=>'string', 'inside'=>'string'], 'Imagick::clipPathImage' => ['bool', 'pathname'=>'string', 'inside'=>'bool'], 'Imagick::clone' => ['Imagick'], 'Imagick::clutImage' => ['bool', 'lookup_table'=>'Imagick', 'channel='=>'float'], 'Imagick::coalesceImages' => ['Imagick'], 'Imagick::colorFloodfillImage' => ['bool', 'fill'=>'mixed', 'fuzz'=>'float', 'bordercolor'=>'mixed', 'x'=>'int', 'y'=>'int'], 'Imagick::colorMatrixImage' => ['void', 'color_matrix'=>'string'], 'Imagick::colorizeImage' => ['bool', 'colorize'=>'mixed', 'opacity'=>'mixed'], 'Imagick::combineImages' => ['Imagick', 'channeltype'=>'int'], 'Imagick::commentImage' => ['bool', 'comment'=>'string'], 'Imagick::compareImageChannels' => ['array{Imagick, float}', 'image'=>'Imagick', 'channeltype'=>'int', 'metrictype'=>'int'], 'Imagick::compareImageLayers' => ['Imagick', 'method'=>'int'], 'Imagick::compareImages' => ['array{Imagick, float}', 'compare'=>'Imagick', 'metric'=>'int'], 'Imagick::compositeImage' => ['bool', 'composite_object'=>'Imagick', 'composite'=>'int', 'x'=>'int', 'y'=>'int', 'channel='=>'int'], 'Imagick::compositeImageGravity' => ['bool', 'Imagick'=>'Imagick', 'COMPOSITE_CONSTANT'=>'int', 'GRAVITY_CONSTANT'=>'int'], 'Imagick::contrastImage' => ['bool', 'sharpen'=>'bool'], 'Imagick::contrastStretchImage' => ['bool', 'black_point'=>'float', 'white_point'=>'float', 'channel='=>'int'], 'Imagick::convolveImage' => ['bool', 'kernel'=>'array', 'channel='=>'int'], 'Imagick::count' => ['void', 'mode='=>'string'], 'Imagick::cropImage' => ['bool', 'width'=>'int', 'height'=>'int', 'x'=>'int', 'y'=>'int'], 'Imagick::cropThumbnailImage' => ['bool', 'width'=>'int', 'height'=>'int', 'legacy='=>'bool'], 'Imagick::current' => ['Imagick'], 'Imagick::cycleColormapImage' => ['bool', 'displace'=>'int'], 'Imagick::decipherImage' => ['bool', 'passphrase'=>'string'], 'Imagick::deconstructImages' => ['Imagick'], 'Imagick::deleteImageArtifact' => ['bool', 'artifact'=>'string'], 'Imagick::deleteImageProperty' => ['void', 'name'=>'string'], 'Imagick::deskewImage' => ['bool', 'threshold'=>'float'], 'Imagick::despeckleImage' => ['bool'], 'Imagick::destroy' => ['bool'], 'Imagick::displayImage' => ['bool', 'servername'=>'string'], 'Imagick::displayImages' => ['bool', 'servername'=>'string'], 'Imagick::distortImage' => ['bool', 'method'=>'int', 'arguments'=>'array', 'bestfit'=>'bool'], 'Imagick::drawImage' => ['bool', 'draw'=>'ImagickDraw'], 'Imagick::edgeImage' => ['bool', 'radius'=>'float'], 'Imagick::embossImage' => ['bool', 'radius'=>'float', 'sigma'=>'float'], 'Imagick::encipherImage' => ['bool', 'passphrase'=>'string'], 'Imagick::enhanceImage' => ['bool'], 'Imagick::equalizeImage' => ['bool'], 'Imagick::evaluateImage' => ['bool', 'op'=>'int', 'constant'=>'float', 'channel='=>'int'], 'Imagick::evaluateImages' => ['bool', 'EVALUATE_CONSTANT'=>'int'], 'Imagick::exportImagePixels' => ['list', 'x'=>'int', 'y'=>'int', 'width'=>'int', 'height'=>'int', 'map'=>'string', 'storage'=>'int'], 'Imagick::extentImage' => ['bool', 'width'=>'int', 'height'=>'int', 'x'=>'int', 'y'=>'int'], 'Imagick::filter' => ['void', 'ImagickKernel'=>'ImagickKernel', 'CHANNEL='=>'int'], 'Imagick::flattenImages' => ['Imagick'], 'Imagick::flipImage' => ['bool'], 'Imagick::floodFillPaintImage' => ['bool', 'fill'=>'mixed', 'fuzz'=>'float', 'target'=>'mixed', 'x'=>'int', 'y'=>'int', 'invert'=>'bool', 'channel='=>'int'], 'Imagick::flopImage' => ['bool'], 'Imagick::forwardFourierTransformimage' => ['void', 'magnitude'=>'bool'], 'Imagick::frameImage' => ['bool', 'matte_color'=>'mixed', 'width'=>'int', 'height'=>'int', 'inner_bevel'=>'int', 'outer_bevel'=>'int'], 'Imagick::functionImage' => ['bool', 'function'=>'int', 'arguments'=>'array', 'channel='=>'int'], 'Imagick::fxImage' => ['Imagick', 'expression'=>'string', 'channel='=>'int'], 'Imagick::gammaImage' => ['bool', 'gamma'=>'float', 'channel='=>'int'], 'Imagick::gaussianBlurImage' => ['bool', 'radius'=>'float', 'sigma'=>'float', 'channel='=>'int'], 'Imagick::getColorspace' => ['int'], 'Imagick::getCompression' => ['int'], 'Imagick::getCompressionQuality' => ['int'], 'Imagick::getConfigureOptions' => ['string'], 'Imagick::getCopyright' => ['string'], 'Imagick::getFeatures' => ['string'], 'Imagick::getFilename' => ['string'], 'Imagick::getFont' => ['string|false'], 'Imagick::getFormat' => ['string'], 'Imagick::getGravity' => ['int'], 'Imagick::getHDRIEnabled' => ['int'], 'Imagick::getHomeURL' => ['string'], 'Imagick::getImage' => ['Imagick'], 'Imagick::getImageAlphaChannel' => ['int'], 'Imagick::getImageArtifact' => ['string', 'artifact'=>'string'], 'Imagick::getImageAttribute' => ['string', 'key'=>'string'], 'Imagick::getImageBackgroundColor' => ['ImagickPixel'], 'Imagick::getImageBlob' => ['string'], 'Imagick::getImageBluePrimary' => ['array{x:float, y:float}'], 'Imagick::getImageBorderColor' => ['ImagickPixel'], 'Imagick::getImageChannelDepth' => ['int', 'channel'=>'int'], 'Imagick::getImageChannelDistortion' => ['float', 'reference'=>'Imagick', 'channel'=>'int', 'metric'=>'int'], 'Imagick::getImageChannelDistortions' => ['float', 'reference'=>'Imagick', 'metric'=>'int', 'channel='=>'int'], 'Imagick::getImageChannelExtrema' => ['array{minima:int, maxima:int}', 'channel'=>'int'], 'Imagick::getImageChannelKurtosis' => ['array{kurtosis:float, skewness:float}', 'channel='=>'int'], 'Imagick::getImageChannelMean' => ['array{mean:float, standardDeviation:float}', 'channel'=>'int'], 'Imagick::getImageChannelRange' => ['array{minima:float, maxima:float}', 'channel'=>'int'], 'Imagick::getImageChannelStatistics' => ['array'], 'Imagick::getImageClipMask' => ['Imagick'], 'Imagick::getImageColormapColor' => ['ImagickPixel', 'index'=>'int'], 'Imagick::getImageColors' => ['int'], 'Imagick::getImageColorspace' => ['int'], 'Imagick::getImageCompose' => ['int'], 'Imagick::getImageCompression' => ['int'], 'Imagick::getImageCompressionQuality' => ['int'], 'Imagick::getImageDelay' => ['int'], 'Imagick::getImageDepth' => ['int'], 'Imagick::getImageDispose' => ['int'], 'Imagick::getImageDistortion' => ['float', 'reference'=>'magickwand', 'metric'=>'int'], 'Imagick::getImageExtrema' => ['array{min:int, max:int}'], 'Imagick::getImageFilename' => ['string'], 'Imagick::getImageFormat' => ['string'], 'Imagick::getImageGamma' => ['float'], 'Imagick::getImageGeometry' => ['array{width:int, height:int}'], 'Imagick::getImageGravity' => ['int'], 'Imagick::getImageGreenPrimary' => ['array{x:float, y:float}'], 'Imagick::getImageHeight' => ['int'], 'Imagick::getImageHistogram' => ['list'], 'Imagick::getImageIndex' => ['int'], 'Imagick::getImageInterlaceScheme' => ['int'], 'Imagick::getImageInterpolateMethod' => ['int'], 'Imagick::getImageIterations' => ['int'], 'Imagick::getImageLength' => ['int'], 'Imagick::getImageMagickLicense' => ['string'], 'Imagick::getImageMatte' => ['bool'], 'Imagick::getImageMatteColor' => ['ImagickPixel'], 'Imagick::getImageMimeType' => ['string'], 'Imagick::getImageOrientation' => ['int'], 'Imagick::getImagePage' => ['array{width:int, height:int, x:int, y:int}'], 'Imagick::getImagePixelColor' => ['ImagickPixel', 'x'=>'int', 'y'=>'int'], 'Imagick::getImageProfile' => ['string', 'name'=>'string'], 'Imagick::getImageProfiles' => ['array', 'pattern='=>'string', 'only_names='=>'bool'], 'Imagick::getImageProperties' => ['array', 'pattern='=>'string', 'only_names='=>'bool'], 'Imagick::getImageProperty' => ['string|false', 'name'=>'string'], 'Imagick::getImageRedPrimary' => ['array{x:float, y:float}'], 'Imagick::getImageRegion' => ['Imagick', 'width'=>'int', 'height'=>'int', 'x'=>'int', 'y'=>'int'], 'Imagick::getImageRenderingIntent' => ['int'], 'Imagick::getImageResolution' => ['array{x:float, y:float}'], 'Imagick::getImageScene' => ['int'], 'Imagick::getImageSignature' => ['string'], 'Imagick::getImageSize' => ['int'], 'Imagick::getImageTicksPerSecond' => ['int'], 'Imagick::getImageTotalInkDensity' => ['float'], 'Imagick::getImageType' => ['int'], 'Imagick::getImageUnits' => ['int'], 'Imagick::getImageVirtualPixelMethod' => ['int'], 'Imagick::getImageWhitePoint' => ['array{x:float, y:float}'], 'Imagick::getImageWidth' => ['int'], 'Imagick::getImagesBlob' => ['string'], 'Imagick::getInterlaceScheme' => ['int'], 'Imagick::getIteratorIndex' => ['int'], 'Imagick::getNumberImages' => ['int'], 'Imagick::getOption' => ['string', 'key'=>'string'], 'Imagick::getPackageName' => ['string'], 'Imagick::getPage' => ['array{width:int, height:int, x:int, y:int}'], 'Imagick::getPixelIterator' => ['ImagickPixelIterator'], 'Imagick::getPixelRegionIterator' => ['ImagickPixelIterator', 'x'=>'int', 'y'=>'int', 'columns'=>'int', 'rows'=>'int'], 'Imagick::getPointSize' => ['float'], 'Imagick::getQuantum' => ['int'], 'Imagick::getQuantumDepth' => ['array{quantumDepthLong:int, quantumDepthString:string}'], 'Imagick::getQuantumRange' => ['array{quantumRangeLong:int, quantumRangeString:string}'], 'Imagick::getRegistry' => ['string|false', 'key'=>'string'], 'Imagick::getReleaseDate' => ['string'], 'Imagick::getResource' => ['int', 'type'=>'int'], 'Imagick::getResourceLimit' => ['int', 'type'=>'int'], 'Imagick::getSamplingFactors' => ['array'], 'Imagick::getSize' => ['array{columns:int, rows: int}'], 'Imagick::getSizeOffset' => ['int'], 'Imagick::getVersion' => ['array{versionNumber: int, versionString:string}'], 'Imagick::haldClutImage' => ['bool', 'clut'=>'Imagick', 'channel='=>'int'], 'Imagick::hasNextImage' => ['bool'], 'Imagick::hasPreviousImage' => ['bool'], 'Imagick::identifyFormat' => ['string|false', 'embedText'=>'string'], 'Imagick::identifyImage' => ['array', 'appendrawoutput='=>'bool'], 'Imagick::identifyImageType' => ['int'], 'Imagick::implodeImage' => ['bool', 'radius'=>'float'], 'Imagick::importImagePixels' => ['bool', 'x'=>'int', 'y'=>'int', 'width'=>'int', 'height'=>'int', 'map'=>'string', 'storage'=>'int', 'pixels'=>'list'], 'Imagick::inverseFourierTransformImage' => ['void', 'complement'=>'string', 'magnitude'=>'string'], 'Imagick::key' => ['int|string'], 'Imagick::labelImage' => ['bool', 'label'=>'string'], 'Imagick::levelImage' => ['bool', 'blackpoint'=>'float', 'gamma'=>'float', 'whitepoint'=>'float', 'channel='=>'int'], 'Imagick::linearStretchImage' => ['bool', 'blackpoint'=>'float', 'whitepoint'=>'float'], 'Imagick::liquidRescaleImage' => ['bool', 'width'=>'int', 'height'=>'int', 'delta_x'=>'float', 'rigidity'=>'float'], 'Imagick::listRegistry' => ['array'], 'Imagick::localContrastImage' => ['bool', 'radius'=>'float', 'strength'=>'float'], 'Imagick::magnifyImage' => ['bool'], 'Imagick::mapImage' => ['bool', 'map'=>'Imagick', 'dither'=>'bool'], 'Imagick::matteFloodfillImage' => ['bool', 'alpha'=>'float', 'fuzz'=>'float', 'bordercolor'=>'mixed', 'x'=>'int', 'y'=>'int'], 'Imagick::medianFilterImage' => ['bool', 'radius'=>'float'], 'Imagick::mergeImageLayers' => ['Imagick', 'layer_method'=>'int'], 'Imagick::minifyImage' => ['bool'], 'Imagick::modulateImage' => ['bool', 'brightness'=>'float', 'saturation'=>'float', 'hue'=>'float'], 'Imagick::montageImage' => ['Imagick', 'draw'=>'ImagickDraw', 'tile_geometry'=>'string', 'thumbnail_geometry'=>'string', 'mode'=>'int', 'frame'=>'string'], 'Imagick::morphImages' => ['Imagick', 'number_frames'=>'int'], 'Imagick::morphology' => ['void', 'morphologyMethod'=>'int', 'iterations'=>'int', 'ImagickKernel'=>'ImagickKernel', 'CHANNEL='=>'string'], 'Imagick::mosaicImages' => ['Imagick'], 'Imagick::motionBlurImage' => ['bool', 'radius'=>'float', 'sigma'=>'float', 'angle'=>'float', 'channel='=>'int'], 'Imagick::negateImage' => ['bool', 'gray'=>'bool', 'channel='=>'int'], 'Imagick::newImage' => ['bool', 'cols'=>'int', 'rows'=>'int', 'background'=>'mixed', 'format='=>'string'], 'Imagick::newPseudoImage' => ['bool', 'columns'=>'int', 'rows'=>'int', 'pseudostring'=>'string'], 'Imagick::next' => ['void'], 'Imagick::nextImage' => ['bool'], 'Imagick::normalizeImage' => ['bool', 'channel='=>'int'], 'Imagick::oilPaintImage' => ['bool', 'radius'=>'float'], 'Imagick::opaquePaintImage' => ['bool', 'target'=>'mixed', 'fill'=>'mixed', 'fuzz'=>'float', 'invert'=>'bool', 'channel='=>'int'], 'Imagick::optimizeImageLayers' => ['bool'], 'Imagick::orderedPosterizeImage' => ['bool', 'threshold_map'=>'string', 'channel='=>'int'], 'Imagick::paintFloodfillImage' => ['bool', 'fill'=>'mixed', 'fuzz'=>'float', 'bordercolor'=>'mixed', 'x'=>'int', 'y'=>'int', 'channel='=>'int'], 'Imagick::paintOpaqueImage' => ['bool', 'target'=>'mixed', 'fill'=>'mixed', 'fuzz'=>'float', 'channel='=>'int'], 'Imagick::paintTransparentImage' => ['bool', 'target'=>'mixed', 'alpha'=>'float', 'fuzz'=>'float'], 'Imagick::pingImage' => ['bool', 'filename'=>'string'], 'Imagick::pingImageBlob' => ['bool', 'image'=>'string'], 'Imagick::pingImageFile' => ['bool', 'filehandle'=>'resource', 'filename='=>'string'], 'Imagick::polaroidImage' => ['bool', 'properties'=>'ImagickDraw', 'angle'=>'float'], 'Imagick::posterizeImage' => ['bool', 'levels'=>'int', 'dither'=>'bool'], 'Imagick::previewImages' => ['bool', 'preview'=>'int'], 'Imagick::previousImage' => ['bool'], 'Imagick::profileImage' => ['bool', 'name'=>'string', 'profile'=>'string'], 'Imagick::quantizeImage' => ['bool', 'numbercolors'=>'int', 'colorspace'=>'int', 'treedepth'=>'int', 'dither'=>'bool', 'measureerror'=>'bool'], 'Imagick::quantizeImages' => ['bool', 'numbercolors'=>'int', 'colorspace'=>'int', 'treedepth'=>'int', 'dither'=>'bool', 'measureerror'=>'bool'], 'Imagick::queryFontMetrics' => ['array', 'properties'=>'ImagickDraw', 'text'=>'string', 'multiline='=>'bool'], 'Imagick::queryFonts' => ['array', 'pattern='=>'string'], 'Imagick::queryFormats' => ['list', 'pattern='=>'string'], 'Imagick::radialBlurImage' => ['bool', 'angle'=>'float', 'channel='=>'int'], 'Imagick::raiseImage' => ['bool', 'width'=>'int', 'height'=>'int', 'x'=>'int', 'y'=>'int', 'raise'=>'bool'], 'Imagick::randomThresholdImage' => ['bool', 'low'=>'float', 'high'=>'float', 'channel='=>'int'], 'Imagick::readImage' => ['bool', 'filename'=>'string'], 'Imagick::readImageBlob' => ['bool', 'image'=>'string', 'filename='=>'string'], 'Imagick::readImageFile' => ['bool', 'filehandle'=>'resource', 'filename='=>'string'], 'Imagick::readImages' => ['Imagick', 'filenames'=>'string'], 'Imagick::recolorImage' => ['bool', 'matrix'=>'list'], 'Imagick::reduceNoiseImage' => ['bool', 'radius'=>'float'], 'Imagick::remapImage' => ['bool', 'replacement'=>'Imagick', 'dither'=>'int'], 'Imagick::removeImage' => ['bool'], 'Imagick::removeImageProfile' => ['string', 'name'=>'string'], 'Imagick::render' => ['bool'], 'Imagick::resampleImage' => ['bool', 'x_resolution'=>'float', 'y_resolution'=>'float', 'filter'=>'int', 'blur'=>'float'], 'Imagick::resetImagePage' => ['bool', 'page'=>'string'], 'Imagick::resetIterator' => [''], 'Imagick::resizeImage' => ['bool', 'columns'=>'int', 'rows'=>'int', 'filter'=>'int', 'blur'=>'float', 'bestfit='=>'bool'], 'Imagick::rewind' => ['void'], 'Imagick::rollImage' => ['bool', 'x'=>'int', 'y'=>'int'], 'Imagick::rotateImage' => ['bool', 'background'=>'mixed', 'degrees'=>'float'], 'Imagick::rotationalBlurImage' => ['void', 'angle'=>'string', 'CHANNEL='=>'string'], 'Imagick::roundCorners' => ['bool', 'x_rounding'=>'float', 'y_rounding'=>'float', 'stroke_width='=>'float', 'displace='=>'float', 'size_correction='=>'float'], 'Imagick::roundCornersImage' => ['', 'xRounding'=>'', 'yRounding'=>'', 'strokeWidth'=>'', 'displace'=>'', 'sizeCorrection'=>''], 'Imagick::sampleImage' => ['bool', 'columns'=>'int', 'rows'=>'int'], 'Imagick::scaleImage' => ['bool', 'cols'=>'int', 'rows'=>'int', 'bestfit='=>'bool'], 'Imagick::segmentImage' => ['bool', 'colorspace'=>'int', 'cluster_threshold'=>'float', 'smooth_threshold'=>'float', 'verbose='=>'bool'], 'Imagick::selectiveBlurImage' => ['void', 'radius'=>'float', 'sigma'=>'float', 'threshold'=>'float', 'CHANNEL'=>'int'], 'Imagick::separateImageChannel' => ['bool', 'channel'=>'int'], 'Imagick::sepiaToneImage' => ['bool', 'threshold'=>'float'], 'Imagick::setAntiAlias' => ['int', 'antialias'=>'bool'], 'Imagick::setBackgroundColor' => ['bool', 'background'=>'mixed'], 'Imagick::setColorspace' => ['bool', 'colorspace'=>'int'], 'Imagick::setCompression' => ['bool', 'compression'=>'int'], 'Imagick::setCompressionQuality' => ['bool', 'quality'=>'int'], 'Imagick::setFilename' => ['bool', 'filename'=>'string'], 'Imagick::setFirstIterator' => ['bool'], 'Imagick::setFont' => ['bool', 'font'=>'string'], 'Imagick::setFormat' => ['bool', 'format'=>'string'], 'Imagick::setGravity' => ['bool', 'gravity'=>'int'], 'Imagick::setImage' => ['bool', 'replace'=>'Imagick'], 'Imagick::setImageAlpha' => ['bool', 'alpha'=>'float'], 'Imagick::setImageAlphaChannel' => ['bool', 'mode'=>'int'], 'Imagick::setImageArtifact' => ['bool', 'artifact'=>'string', 'value'=>'string'], 'Imagick::setImageAttribute' => ['void', 'key'=>'string', 'value'=>'string'], 'Imagick::setImageBackgroundColor' => ['bool', 'background'=>'mixed'], 'Imagick::setImageBias' => ['bool', 'bias'=>'float'], 'Imagick::setImageBiasQuantum' => ['void', 'bias'=>'string'], 'Imagick::setImageBluePrimary' => ['bool', 'x'=>'float', 'y'=>'float'], 'Imagick::setImageBorderColor' => ['bool', 'border'=>'mixed'], 'Imagick::setImageChannelDepth' => ['bool', 'channel'=>'int', 'depth'=>'int'], 'Imagick::setImageChannelMask' => ['', 'channel'=>'int'], 'Imagick::setImageClipMask' => ['bool', 'clip_mask'=>'Imagick'], 'Imagick::setImageColormapColor' => ['bool', 'index'=>'int', 'color'=>'ImagickPixel'], 'Imagick::setImageColorspace' => ['bool', 'colorspace'=>'int'], 'Imagick::setImageCompose' => ['bool', 'compose'=>'int'], 'Imagick::setImageCompression' => ['bool', 'compression'=>'int'], 'Imagick::setImageCompressionQuality' => ['bool', 'quality'=>'int'], 'Imagick::setImageDelay' => ['bool', 'delay'=>'int'], 'Imagick::setImageDepth' => ['bool', 'depth'=>'int'], 'Imagick::setImageDispose' => ['bool', 'dispose'=>'int'], 'Imagick::setImageExtent' => ['bool', 'columns'=>'int', 'rows'=>'int'], 'Imagick::setImageFilename' => ['bool', 'filename'=>'string'], 'Imagick::setImageFormat' => ['bool', 'format'=>'string'], 'Imagick::setImageGamma' => ['bool', 'gamma'=>'float'], 'Imagick::setImageGravity' => ['bool', 'gravity'=>'int'], 'Imagick::setImageGreenPrimary' => ['bool', 'x'=>'float', 'y'=>'float'], 'Imagick::setImageIndex' => ['bool', 'index'=>'int'], 'Imagick::setImageInterlaceScheme' => ['bool', 'interlace_scheme'=>'int'], 'Imagick::setImageInterpolateMethod' => ['bool', 'method'=>'int'], 'Imagick::setImageIterations' => ['bool', 'iterations'=>'int'], 'Imagick::setImageMatte' => ['bool', 'matte'=>'bool'], 'Imagick::setImageMatteColor' => ['bool', 'matte'=>'mixed'], 'Imagick::setImageOpacity' => ['bool', 'opacity'=>'float'], 'Imagick::setImageOrientation' => ['bool', 'orientation'=>'int'], 'Imagick::setImagePage' => ['bool', 'width'=>'int', 'height'=>'int', 'x'=>'int', 'y'=>'int'], 'Imagick::setImageProfile' => ['bool', 'name'=>'string', 'profile'=>'string'], 'Imagick::setImageProgressMonitor' => ['', 'filename'=>''], 'Imagick::setImageProperty' => ['bool', 'name'=>'string', 'value'=>'string'], 'Imagick::setImageRedPrimary' => ['bool', 'x'=>'float', 'y'=>'float'], 'Imagick::setImageRenderingIntent' => ['bool', 'rendering_intent'=>'int'], 'Imagick::setImageResolution' => ['bool', 'x_resolution'=>'float', 'y_resolution'=>'float'], 'Imagick::setImageScene' => ['bool', 'scene'=>'int'], 'Imagick::setImageTicksPerSecond' => ['bool', 'ticks_per_second'=>'int'], 'Imagick::setImageType' => ['bool', 'image_type'=>'int'], 'Imagick::setImageUnits' => ['bool', 'units'=>'int'], 'Imagick::setImageVirtualPixelMethod' => ['bool', 'method'=>'int'], 'Imagick::setImageWhitePoint' => ['bool', 'x'=>'float', 'y'=>'float'], 'Imagick::setInterlaceScheme' => ['bool', 'interlace_scheme'=>'int'], 'Imagick::setIteratorIndex' => ['bool', 'index'=>'int'], 'Imagick::setLastIterator' => ['bool'], 'Imagick::setOption' => ['bool', 'key'=>'string', 'value'=>'string'], 'Imagick::setPage' => ['bool', 'width'=>'int', 'height'=>'int', 'x'=>'int', 'y'=>'int'], 'Imagick::setPointSize' => ['bool', 'point_size'=>'float'], 'Imagick::setProgressMonitor' => ['void', 'callback'=>'callable'], 'Imagick::setRegistry' => ['void', 'key'=>'string', 'value'=>'string'], 'Imagick::setResolution' => ['bool', 'x_resolution'=>'float', 'y_resolution'=>'float'], 'Imagick::setResourceLimit' => ['bool', 'type'=>'int', 'limit'=>'int'], 'Imagick::setSamplingFactors' => ['bool', 'factors'=>'list'], 'Imagick::setSize' => ['bool', 'columns'=>'int', 'rows'=>'int'], 'Imagick::setSizeOffset' => ['bool', 'columns'=>'int', 'rows'=>'int', 'offset'=>'int'], 'Imagick::setType' => ['bool', 'image_type'=>'int'], 'Imagick::shadeImage' => ['bool', 'gray'=>'bool', 'azimuth'=>'float', 'elevation'=>'float'], 'Imagick::shadowImage' => ['bool', 'opacity'=>'float', 'sigma'=>'float', 'x'=>'int', 'y'=>'int'], 'Imagick::sharpenImage' => ['bool', 'radius'=>'float', 'sigma'=>'float', 'channel='=>'int'], 'Imagick::shaveImage' => ['bool', 'columns'=>'int', 'rows'=>'int'], 'Imagick::shearImage' => ['bool', 'background'=>'mixed', 'x_shear'=>'float', 'y_shear'=>'float'], 'Imagick::sigmoidalContrastImage' => ['bool', 'sharpen'=>'bool', 'alpha'=>'float', 'beta'=>'float', 'channel='=>'int'], 'Imagick::similarityImage' => ['Imagick', 'Imagick'=>'Imagick', '&bestMatch'=>'array', '&similarity'=>'float', 'similarity_threshold'=>'float', 'metric'=>'int'], 'Imagick::sketchImage' => ['bool', 'radius'=>'float', 'sigma'=>'float', 'angle'=>'float'], 'Imagick::smushImages' => ['Imagick', 'stack'=>'string', 'offset'=>'string'], 'Imagick::solarizeImage' => ['bool', 'threshold'=>'int'], 'Imagick::sparseColorImage' => ['bool', 'sparse_method'=>'int', 'arguments'=>'array', 'channel='=>'int'], 'Imagick::spliceImage' => ['bool', 'width'=>'int', 'height'=>'int', 'x'=>'int', 'y'=>'int'], 'Imagick::spreadImage' => ['bool', 'radius'=>'float'], 'Imagick::statisticImage' => ['void', 'type'=>'int', 'width'=>'int', 'height'=>'int', 'CHANNEL='=>'string'], 'Imagick::steganoImage' => ['Imagick', 'watermark_wand'=>'Imagick', 'offset'=>'int'], 'Imagick::stereoImage' => ['bool', 'offset_wand'=>'Imagick'], 'Imagick::stripImage' => ['bool'], 'Imagick::subImageMatch' => ['Imagick', 'Imagick'=>'Imagick', '&w_offset='=>'array', '&w_similarity='=>'float'], 'Imagick::swirlImage' => ['bool', 'degrees'=>'float'], 'Imagick::textureImage' => ['bool', 'texture_wand'=>'Imagick'], 'Imagick::thresholdImage' => ['bool', 'threshold'=>'float', 'channel='=>'int'], 'Imagick::thumbnailImage' => ['bool', 'columns'=>'int', 'rows'=>'int', 'bestfit='=>'bool', 'fill='=>'bool', 'legacy='=>'bool'], 'Imagick::tintImage' => ['bool', 'tint'=>'mixed', 'opacity'=>'mixed'], 'Imagick::transformImage' => ['Imagick', 'crop'=>'string', 'geometry'=>'string'], 'Imagick::transformImageColorspace' => ['bool', 'colorspace'=>'int'], 'Imagick::transparentPaintImage' => ['bool', 'target'=>'mixed', 'alpha'=>'float', 'fuzz'=>'float', 'invert'=>'bool'], 'Imagick::transposeImage' => ['bool'], 'Imagick::transverseImage' => ['bool'], 'Imagick::trimImage' => ['bool', 'fuzz'=>'float'], 'Imagick::uniqueImageColors' => ['bool'], 'Imagick::unsharpMaskImage' => ['bool', 'radius'=>'float', 'sigma'=>'float', 'amount'=>'float', 'threshold'=>'float', 'channel='=>'int'], 'Imagick::valid' => ['bool'], 'Imagick::vignetteImage' => ['bool', 'blackpoint'=>'float', 'whitepoint'=>'float', 'x'=>'int', 'y'=>'int'], 'Imagick::waveImage' => ['bool', 'amplitude'=>'float', 'length'=>'float'], 'Imagick::whiteThresholdImage' => ['bool', 'threshold'=>'mixed'], 'Imagick::writeImage' => ['bool', 'filename='=>'string'], 'Imagick::writeImageFile' => ['bool', 'filehandle'=>'resource'], 'Imagick::writeImages' => ['bool', 'filename'=>'string', 'adjoin'=>'bool'], 'Imagick::writeImagesFile' => ['bool', 'filehandle'=>'resource'], 'ImagickDraw::__construct' => ['void'], 'ImagickDraw::affine' => ['bool', 'affine'=>'array'], 'ImagickDraw::annotation' => ['bool', 'x'=>'float', 'y'=>'float', 'text'=>'string'], 'ImagickDraw::arc' => ['bool', 'sx'=>'float', 'sy'=>'float', 'ex'=>'float', 'ey'=>'float', 'sd'=>'float', 'ed'=>'float'], 'ImagickDraw::bezier' => ['bool', 'coordinates'=>'list'], 'ImagickDraw::circle' => ['bool', 'ox'=>'float', 'oy'=>'float', 'px'=>'float', 'py'=>'float'], 'ImagickDraw::clear' => ['bool'], 'ImagickDraw::clone' => ['ImagickDraw'], 'ImagickDraw::color' => ['bool', 'x'=>'float', 'y'=>'float', 'paintmethod'=>'int'], 'ImagickDraw::comment' => ['bool', 'comment'=>'string'], 'ImagickDraw::composite' => ['bool', 'compose'=>'int', 'x'=>'float', 'y'=>'float', 'width'=>'float', 'height'=>'float', 'compositewand'=>'Imagick'], 'ImagickDraw::destroy' => ['bool'], 'ImagickDraw::ellipse' => ['bool', 'ox'=>'float', 'oy'=>'float', 'rx'=>'float', 'ry'=>'float', 'start'=>'float', 'end'=>'float'], 'ImagickDraw::getBorderColor' => ['ImagickPixel'], 'ImagickDraw::getClipPath' => ['string|false'], 'ImagickDraw::getClipRule' => ['int'], 'ImagickDraw::getClipUnits' => ['int'], 'ImagickDraw::getDensity' => ['?string'], 'ImagickDraw::getFillColor' => ['ImagickPixel'], 'ImagickDraw::getFillOpacity' => ['float'], 'ImagickDraw::getFillRule' => ['int'], 'ImagickDraw::getFont' => ['string|false'], 'ImagickDraw::getFontFamily' => ['string|false'], 'ImagickDraw::getFontResolution' => ['array'], 'ImagickDraw::getFontSize' => ['float'], 'ImagickDraw::getFontStretch' => ['int'], 'ImagickDraw::getFontStyle' => ['int'], 'ImagickDraw::getFontWeight' => ['int'], 'ImagickDraw::getGravity' => ['int'], 'ImagickDraw::getOpacity' => ['float'], 'ImagickDraw::getStrokeAntialias' => ['bool'], 'ImagickDraw::getStrokeColor' => ['ImagickPixel'], 'ImagickDraw::getStrokeDashArray' => ['array'], 'ImagickDraw::getStrokeDashOffset' => ['float'], 'ImagickDraw::getStrokeLineCap' => ['int'], 'ImagickDraw::getStrokeLineJoin' => ['int'], 'ImagickDraw::getStrokeMiterLimit' => ['int'], 'ImagickDraw::getStrokeOpacity' => ['float'], 'ImagickDraw::getStrokeWidth' => ['float'], 'ImagickDraw::getTextAlignment' => ['int'], 'ImagickDraw::getTextAntialias' => ['bool'], 'ImagickDraw::getTextDecoration' => ['int'], 'ImagickDraw::getTextDirection' => ['bool'], 'ImagickDraw::getTextEncoding' => ['string'], 'ImagickDraw::getTextInterlineSpacing' => ['float'], 'ImagickDraw::getTextInterwordSpacing' => ['float'], 'ImagickDraw::getTextKerning' => ['float'], 'ImagickDraw::getTextUnderColor' => ['ImagickPixel'], 'ImagickDraw::getVectorGraphics' => ['string'], 'ImagickDraw::line' => ['bool', 'sx'=>'float', 'sy'=>'float', 'ex'=>'float', 'ey'=>'float'], 'ImagickDraw::matte' => ['bool', 'x'=>'float', 'y'=>'float', 'paintmethod'=>'int'], 'ImagickDraw::pathClose' => ['bool'], 'ImagickDraw::pathCurveToAbsolute' => ['bool', 'x1'=>'float', 'y1'=>'float', 'x2'=>'float', 'y2'=>'float', 'x'=>'float', 'y'=>'float'], 'ImagickDraw::pathCurveToQuadraticBezierAbsolute' => ['bool', 'x1'=>'float', 'y1'=>'float', 'x'=>'float', 'y'=>'float'], 'ImagickDraw::pathCurveToQuadraticBezierRelative' => ['bool', 'x1'=>'float', 'y1'=>'float', 'x'=>'float', 'y'=>'float'], 'ImagickDraw::pathCurveToQuadraticBezierSmoothAbsolute' => ['bool', 'x'=>'float', 'y'=>'float'], 'ImagickDraw::pathCurveToQuadraticBezierSmoothRelative' => ['bool', 'x'=>'float', 'y'=>'float'], 'ImagickDraw::pathCurveToRelative' => ['bool', 'x1'=>'float', 'y1'=>'float', 'x2'=>'float', 'y2'=>'float', 'x'=>'float', 'y'=>'float'], 'ImagickDraw::pathCurveToSmoothAbsolute' => ['bool', 'x2'=>'float', 'y2'=>'float', 'x'=>'float', 'y'=>'float'], 'ImagickDraw::pathCurveToSmoothRelative' => ['bool', 'x2'=>'float', 'y2'=>'float', 'x'=>'float', 'y'=>'float'], 'ImagickDraw::pathEllipticArcAbsolute' => ['bool', 'rx'=>'float', 'ry'=>'float', 'x_axis_rotation'=>'float', 'large_arc_flag'=>'bool', 'sweep_flag'=>'bool', 'x'=>'float', 'y'=>'float'], 'ImagickDraw::pathEllipticArcRelative' => ['bool', 'rx'=>'float', 'ry'=>'float', 'x_axis_rotation'=>'float', 'large_arc_flag'=>'bool', 'sweep_flag'=>'bool', 'x'=>'float', 'y'=>'float'], 'ImagickDraw::pathFinish' => ['bool'], 'ImagickDraw::pathLineToAbsolute' => ['bool', 'x'=>'float', 'y'=>'float'], 'ImagickDraw::pathLineToHorizontalAbsolute' => ['bool', 'x'=>'float'], 'ImagickDraw::pathLineToHorizontalRelative' => ['bool', 'x'=>'float'], 'ImagickDraw::pathLineToRelative' => ['bool', 'x'=>'float', 'y'=>'float'], 'ImagickDraw::pathLineToVerticalAbsolute' => ['bool', 'y'=>'float'], 'ImagickDraw::pathLineToVerticalRelative' => ['bool', 'y'=>'float'], 'ImagickDraw::pathMoveToAbsolute' => ['bool', 'x'=>'float', 'y'=>'float'], 'ImagickDraw::pathMoveToRelative' => ['bool', 'x'=>'float', 'y'=>'float'], 'ImagickDraw::pathStart' => ['bool'], 'ImagickDraw::point' => ['bool', 'x'=>'float', 'y'=>'float'], 'ImagickDraw::polygon' => ['bool', 'coordinates'=>'list'], 'ImagickDraw::polyline' => ['bool', 'coordinates'=>'list'], 'ImagickDraw::pop' => ['bool'], 'ImagickDraw::popClipPath' => ['bool'], 'ImagickDraw::popDefs' => ['bool'], 'ImagickDraw::popPattern' => ['bool'], 'ImagickDraw::push' => ['bool'], 'ImagickDraw::pushClipPath' => ['bool', 'clip_mask_id'=>'string'], 'ImagickDraw::pushDefs' => ['bool'], 'ImagickDraw::pushPattern' => ['bool', 'pattern_id'=>'string', 'x'=>'float', 'y'=>'float', 'width'=>'float', 'height'=>'float'], 'ImagickDraw::rectangle' => ['bool', 'x1'=>'float', 'y1'=>'float', 'x2'=>'float', 'y2'=>'float'], 'ImagickDraw::render' => ['bool'], 'ImagickDraw::resetVectorGraphics' => ['void'], 'ImagickDraw::rotate' => ['bool', 'degrees'=>'float'], 'ImagickDraw::roundRectangle' => ['bool', 'x1'=>'float', 'y1'=>'float', 'x2'=>'float', 'y2'=>'float', 'rx'=>'float', 'ry'=>'float'], 'ImagickDraw::scale' => ['bool', 'x'=>'float', 'y'=>'float'], 'ImagickDraw::setBorderColor' => ['bool', 'color'=>'ImagickPixel|string'], 'ImagickDraw::setClipPath' => ['bool', 'clip_mask'=>'string'], 'ImagickDraw::setClipRule' => ['bool', 'fill_rule'=>'int'], 'ImagickDraw::setClipUnits' => ['bool', 'clip_units'=>'int'], 'ImagickDraw::setDensity' => ['bool', 'density_string'=>'string'], 'ImagickDraw::setFillAlpha' => ['bool', 'opacity'=>'float'], 'ImagickDraw::setFillColor' => ['bool', 'fill_pixel'=>'ImagickPixel|string'], 'ImagickDraw::setFillOpacity' => ['bool', 'fillopacity'=>'float'], 'ImagickDraw::setFillPatternURL' => ['bool', 'fill_url'=>'string'], 'ImagickDraw::setFillRule' => ['bool', 'fill_rule'=>'int'], 'ImagickDraw::setFont' => ['bool', 'font_name'=>'string'], 'ImagickDraw::setFontFamily' => ['bool', 'font_family'=>'string'], 'ImagickDraw::setFontResolution' => ['bool', 'x'=>'float', 'y'=>'float'], 'ImagickDraw::setFontSize' => ['bool', 'pointsize'=>'float'], 'ImagickDraw::setFontStretch' => ['bool', 'fontstretch'=>'int'], 'ImagickDraw::setFontStyle' => ['bool', 'style'=>'int'], 'ImagickDraw::setFontWeight' => ['bool', 'font_weight'=>'int'], 'ImagickDraw::setGravity' => ['bool', 'gravity'=>'int'], 'ImagickDraw::setOpacity' => ['void', 'opacity'=>'float'], 'ImagickDraw::setResolution' => ['void', 'x_resolution'=>'float', 'y_resolution'=>'float'], 'ImagickDraw::setStrokeAlpha' => ['bool', 'opacity'=>'float'], 'ImagickDraw::setStrokeAntialias' => ['bool', 'stroke_antialias'=>'bool'], 'ImagickDraw::setStrokeColor' => ['bool', 'stroke_pixel'=>'ImagickPixel|string'], 'ImagickDraw::setStrokeDashArray' => ['bool', 'dasharray'=>'list'], 'ImagickDraw::setStrokeDashOffset' => ['bool', 'dash_offset'=>'float'], 'ImagickDraw::setStrokeLineCap' => ['bool', 'linecap'=>'int'], 'ImagickDraw::setStrokeLineJoin' => ['bool', 'linejoin'=>'int'], 'ImagickDraw::setStrokeMiterLimit' => ['bool', 'miterlimit'=>'int'], 'ImagickDraw::setStrokeOpacity' => ['bool', 'stroke_opacity'=>'float'], 'ImagickDraw::setStrokePatternURL' => ['bool', 'stroke_url'=>'string'], 'ImagickDraw::setStrokeWidth' => ['bool', 'stroke_width'=>'float'], 'ImagickDraw::setTextAlignment' => ['bool', 'alignment'=>'int'], 'ImagickDraw::setTextAntialias' => ['bool', 'antialias'=>'bool'], 'ImagickDraw::setTextDecoration' => ['bool', 'decoration'=>'int'], 'ImagickDraw::setTextDirection' => ['bool', 'direction'=>'int'], 'ImagickDraw::setTextEncoding' => ['bool', 'encoding'=>'string'], 'ImagickDraw::setTextInterlineSpacing' => ['void', 'spacing'=>'float'], 'ImagickDraw::setTextInterwordSpacing' => ['void', 'spacing'=>'float'], 'ImagickDraw::setTextKerning' => ['void', 'kerning'=>'float'], 'ImagickDraw::setTextUnderColor' => ['bool', 'under_color'=>'ImagickPixel|string'], 'ImagickDraw::setVectorGraphics' => ['bool', 'xml'=>'string'], 'ImagickDraw::setViewbox' => ['bool', 'x1'=>'int', 'y1'=>'int', 'x2'=>'int', 'y2'=>'int'], 'ImagickDraw::skewX' => ['bool', 'degrees'=>'float'], 'ImagickDraw::skewY' => ['bool', 'degrees'=>'float'], 'ImagickDraw::translate' => ['bool', 'x'=>'float', 'y'=>'float'], 'ImagickKernel::addKernel' => ['void', 'ImagickKernel'=>'ImagickKernel'], 'ImagickKernel::addUnityKernel' => ['void'], 'ImagickKernel::fromBuiltin' => ['ImagickKernel', 'kernelType'=>'string', 'kernelString'=>'string'], 'ImagickKernel::fromMatrix' => ['ImagickKernel', 'matrix'=>'list>', 'origin='=>'array'], 'ImagickKernel::getMatrix' => ['list>'], 'ImagickKernel::scale' => ['void'], 'ImagickKernel::separate' => ['ImagickKernel[]'], 'ImagickKernel::seperate' => ['void'], 'ImagickPixel::__construct' => ['void', 'color='=>'string'], 'ImagickPixel::clear' => ['bool'], 'ImagickPixel::clone' => ['void'], 'ImagickPixel::destroy' => ['bool'], 'ImagickPixel::getColor' => ['array{r: int|float, g: int|float, b: int|float, a: int|float}', 'normalized='=>'0|1|2'], 'ImagickPixel::getColorAsString' => ['string'], 'ImagickPixel::getColorCount' => ['int'], 'ImagickPixel::getColorQuantum' => ['mixed'], 'ImagickPixel::getColorValue' => ['float', 'color'=>'int'], 'ImagickPixel::getColorValueQuantum' => ['mixed'], 'ImagickPixel::getHSL' => ['array{hue: float, saturation: float, luminosity: float}'], 'ImagickPixel::getIndex' => ['int'], 'ImagickPixel::isPixelSimilar' => ['bool', 'color'=>'ImagickPixel', 'fuzz'=>'float'], 'ImagickPixel::isPixelSimilarQuantum' => ['bool', 'color'=>'string', 'fuzz='=>'string'], 'ImagickPixel::isSimilar' => ['bool', 'color'=>'ImagickPixel', 'fuzz'=>'float'], 'ImagickPixel::setColor' => ['bool', 'color'=>'string'], 'ImagickPixel::setColorFromPixel' => ['bool', 'srcPixel'=>'ImagickPixel'], 'ImagickPixel::setColorValue' => ['bool', 'color'=>'int', 'value'=>'float'], 'ImagickPixel::setColorValueQuantum' => ['void', 'color'=>'int', 'value'=>'mixed'], 'ImagickPixel::setHSL' => ['bool', 'hue'=>'float', 'saturation'=>'float', 'luminosity'=>'float'], 'ImagickPixel::setIndex' => ['void', 'index'=>'int'], 'ImagickPixel::setcolorcount' => ['void', 'colorCount'=>'string'], 'ImagickPixelIterator::__construct' => ['void', 'wand'=>'Imagick'], 'ImagickPixelIterator::clear' => ['bool'], 'ImagickPixelIterator::current' => ['mixed'], 'ImagickPixelIterator::destroy' => ['bool'], 'ImagickPixelIterator::getCurrentIteratorRow' => ['array'], 'ImagickPixelIterator::getIteratorRow' => ['int'], 'ImagickPixelIterator::getNextIteratorRow' => ['array'], 'ImagickPixelIterator::getPreviousIteratorRow' => ['array'], 'ImagickPixelIterator::getpixeliterator' => ['', 'Imagick'=>'Imagick'], 'ImagickPixelIterator::getpixelregioniterator' => ['', 'Imagick'=>'Imagick', 'x'=>'', 'y'=>'', 'columns'=>'', 'rows'=>''], 'ImagickPixelIterator::key' => ['int|string'], 'ImagickPixelIterator::newPixelIterator' => ['bool', 'wand'=>'Imagick'], 'ImagickPixelIterator::newPixelRegionIterator' => ['bool', 'wand'=>'Imagick', 'x'=>'int', 'y'=>'int', 'columns'=>'int', 'rows'=>'int'], 'ImagickPixelIterator::next' => ['void'], 'ImagickPixelIterator::resetIterator' => ['bool'], 'ImagickPixelIterator::rewind' => ['void'], 'ImagickPixelIterator::setIteratorFirstRow' => ['bool'], 'ImagickPixelIterator::setIteratorLastRow' => ['bool'], 'ImagickPixelIterator::setIteratorRow' => ['bool', 'row'=>'int'], 'ImagickPixelIterator::syncIterator' => ['bool'], 'ImagickPixelIterator::valid' => ['bool'], 'InfiniteIterator::__construct' => ['void', 'iterator'=>'Iterator'], 'InfiniteIterator::current' => ['mixed'], 'InfiniteIterator::getInnerIterator' => ['Iterator'], 'InfiniteIterator::key' => ['bool|float|int|string'], 'InfiniteIterator::next' => ['void'], 'InfiniteIterator::rewind' => ['void'], 'InfiniteIterator::valid' => ['bool'], 'IntlBreakIterator::__construct' => ['void'], 'IntlBreakIterator::createCharacterInstance' => ['?IntlRuleBasedBreakIterator', 'locale='=>'?string'], 'IntlBreakIterator::createCodePointInstance' => ['IntlCodePointBreakIterator'], 'IntlBreakIterator::createLineInstance' => ['?IntlRuleBasedBreakIterator', 'locale='=>'?string'], 'IntlBreakIterator::createSentenceInstance' => ['?IntlRuleBasedBreakIterator', 'locale='=>'?string'], 'IntlBreakIterator::createTitleInstance' => ['?IntlRuleBasedBreakIterator', 'locale='=>'?string'], 'IntlBreakIterator::createWordInstance' => ['?IntlRuleBasedBreakIterator', 'locale='=>'?string'], 'IntlBreakIterator::current' => ['int'], 'IntlBreakIterator::first' => ['int'], 'IntlBreakIterator::following' => ['int', 'offset'=>'int'], 'IntlBreakIterator::getErrorCode' => ['int'], 'IntlBreakIterator::getErrorMessage' => ['string'], 'IntlBreakIterator::getLocale' => ['string|false', 'type'=>'int'], 'IntlBreakIterator::getPartsIterator' => ['IntlPartsIterator', 'type='=>'string'], 'IntlBreakIterator::getText' => ['?string'], 'IntlBreakIterator::isBoundary' => ['bool', 'offset'=>'int'], 'IntlBreakIterator::last' => ['int'], 'IntlBreakIterator::next' => ['int', 'offset='=>'?int'], 'IntlBreakIterator::preceding' => ['int', 'offset'=>'int'], 'IntlBreakIterator::previous' => ['int'], 'IntlBreakIterator::setText' => ['?bool', 'text'=>'string'], 'IntlCalendar::__construct' => ['void'], 'IntlCalendar::add' => ['bool', 'field'=>'int', 'value'=>'int'], 'IntlCalendar::after' => ['bool', 'other'=>'IntlCalendar'], 'IntlCalendar::before' => ['bool', 'other'=>'IntlCalendar'], 'IntlCalendar::clear' => ['bool', 'field='=>'?int'], 'IntlCalendar::createInstance' => ['?IntlCalendar', 'timezone='=>'IntlTimeZone|DateTimeZone|string|null', 'locale='=>'?string'], 'IntlCalendar::equals' => ['bool', 'other'=>'IntlCalendar'], 'IntlCalendar::fieldDifference' => ['int|false', 'timestamp'=>'float', 'field'=>'int'], 'IntlCalendar::fromDateTime' => ['?IntlCalendar', 'datetime'=>'DateTime|string', 'locale='=>'?string'], 'IntlCalendar::get' => ['int', 'field'=>'int'], 'IntlCalendar::getActualMaximum' => ['int', 'field'=>'int'], 'IntlCalendar::getActualMinimum' => ['int', 'field'=>'int'], 'IntlCalendar::getAvailableLocales' => ['array'], 'IntlCalendar::getDayOfWeekType' => ['int', 'dayOfWeek'=>'int'], 'IntlCalendar::getErrorCode' => ['int'], 'IntlCalendar::getErrorMessage' => ['string'], 'IntlCalendar::getFirstDayOfWeek' => ['int'], 'IntlCalendar::getGreatestMinimum' => ['int', 'field'=>'int'], 'IntlCalendar::getKeywordValuesForLocale' => ['IntlIterator|false', 'keyword'=>'string', 'locale'=>'string', 'onlyCommon'=>'bool'], 'IntlCalendar::getLeastMaximum' => ['int', 'field'=>'int'], 'IntlCalendar::getLocale' => ['string|false', 'type'=>'int'], 'IntlCalendar::getMaximum' => ['int|false', 'field'=>'int'], 'IntlCalendar::getMinimalDaysInFirstWeek' => ['int'], 'IntlCalendar::getMinimum' => ['int', 'field'=>'int'], 'IntlCalendar::getNow' => ['float'], 'IntlCalendar::getRepeatedWallTimeOption' => ['int'], 'IntlCalendar::getSkippedWallTimeOption' => ['int'], 'IntlCalendar::getTime' => ['float'], 'IntlCalendar::getTimeZone' => ['IntlTimeZone'], 'IntlCalendar::getType' => ['string'], 'IntlCalendar::getWeekendTransition' => ['int|false', 'dayOfWeek'=>'int'], 'IntlCalendar::inDaylightTime' => ['bool'], 'IntlCalendar::isEquivalentTo' => ['bool', 'other'=>'IntlCalendar'], 'IntlCalendar::isLenient' => ['bool'], 'IntlCalendar::isSet' => ['bool', 'field'=>'int'], 'IntlCalendar::isWeekend' => ['bool', 'timestamp='=>'?float'], 'IntlCalendar::roll' => ['bool', 'field'=>'int', 'value'=>'int|bool'], 'IntlCalendar::set' => ['bool', 'field'=>'int', 'value'=>'int'], 'IntlCalendar::set\'1' => ['bool', 'year'=>'int', 'month'=>'int', 'dayOfMonth='=>'int', 'hour='=>'int', 'minute='=>'int', 'second='=>'int'], 'IntlCalendar::setFirstDayOfWeek' => ['bool', 'dayOfWeek'=>'int'], 'IntlCalendar::setLenient' => ['true', 'lenient'=>'bool'], 'IntlCalendar::setMinimalDaysInFirstWeek' => ['bool', 'days'=>'int'], 'IntlCalendar::setRepeatedWallTimeOption' => ['true', 'option'=>'int'], 'IntlCalendar::setSkippedWallTimeOption' => ['true', 'option'=>'int'], 'IntlCalendar::setTime' => ['bool', 'timestamp'=>'float'], 'IntlCalendar::setTimeZone' => ['bool', 'timezone'=>'IntlTimeZone|DateTimeZone|string|null'], 'IntlCalendar::toDateTime' => ['DateTime|false'], 'IntlChar::charAge' => ['?array', 'codepoint'=>'int|string'], 'IntlChar::charDigitValue' => ['?int', 'codepoint'=>'int|string'], 'IntlChar::charDirection' => ['?int', 'codepoint'=>'int|string'], 'IntlChar::charFromName' => ['?int', 'name'=>'string', 'type='=>'int'], 'IntlChar::charMirror' => ['int|string|null', 'codepoint'=>'int|string'], 'IntlChar::charName' => ['?string', 'codepoint'=>'int|string', 'type='=>'int'], 'IntlChar::charType' => ['?int', 'codepoint'=>'int|string'], 'IntlChar::chr' => ['?string', 'codepoint'=>'int|string'], 'IntlChar::digit' => ['int|false|null', 'codepoint'=>'int|string', 'base='=>'int'], 'IntlChar::enumCharNames' => ['?bool', 'start'=>'string|int', 'end'=>'string|int', 'callback'=>'callable(int,int,int):void', 'type='=>'int'], 'IntlChar::enumCharTypes' => ['void', 'callback'=>'callable(int,int,int):void'], 'IntlChar::foldCase' => ['int|string|null', 'codepoint'=>'int|string', 'options='=>'int'], 'IntlChar::forDigit' => ['int', 'digit'=>'int', 'base='=>'int'], 'IntlChar::getBidiPairedBracket' => ['int|string|null', 'codepoint'=>'int|string'], 'IntlChar::getBlockCode' => ['?int', 'codepoint'=>'int|string'], 'IntlChar::getCombiningClass' => ['?int', 'codepoint'=>'int|string'], 'IntlChar::getFC_NFKC_Closure' => ['?string', 'codepoint'=>'int|string'], 'IntlChar::getIntPropertyMaxValue' => ['int', 'property'=>'int'], 'IntlChar::getIntPropertyMinValue' => ['int', 'property'=>'int'], 'IntlChar::getIntPropertyValue' => ['?int', 'codepoint'=>'int|string', 'property'=>'int'], 'IntlChar::getNumericValue' => ['?float', 'codepoint'=>'int|string'], 'IntlChar::getPropertyEnum' => ['int', 'alias'=>'string'], 'IntlChar::getPropertyName' => ['string|false', 'property'=>'int', 'type='=>'int'], 'IntlChar::getPropertyValueEnum' => ['int', 'property'=>'int', 'name'=>'string'], 'IntlChar::getPropertyValueName' => ['string|false', 'property'=>'int', 'value'=>'int', 'type='=>'int'], 'IntlChar::getUnicodeVersion' => ['array'], 'IntlChar::hasBinaryProperty' => ['?bool', 'codepoint'=>'int|string', 'property'=>'int'], 'IntlChar::isIDIgnorable' => ['?bool', 'codepoint'=>'int|string'], 'IntlChar::isIDPart' => ['?bool', 'codepoint'=>'int|string'], 'IntlChar::isIDStart' => ['?bool', 'codepoint'=>'int|string'], 'IntlChar::isISOControl' => ['?bool', 'codepoint'=>'int|string'], 'IntlChar::isJavaIDPart' => ['?bool', 'codepoint'=>'int|string'], 'IntlChar::isJavaIDStart' => ['?bool', 'codepoint'=>'int|string'], 'IntlChar::isJavaSpaceChar' => ['?bool', 'codepoint'=>'int|string'], 'IntlChar::isMirrored' => ['?bool', 'codepoint'=>'int|string'], 'IntlChar::isUAlphabetic' => ['?bool', 'codepoint'=>'int|string'], 'IntlChar::isULowercase' => ['?bool', 'codepoint'=>'int|string'], 'IntlChar::isUUppercase' => ['?bool', 'codepoint'=>'int|string'], 'IntlChar::isUWhiteSpace' => ['?bool', 'codepoint'=>'int|string'], 'IntlChar::isWhitespace' => ['?bool', 'codepoint'=>'int|string'], 'IntlChar::isalnum' => ['?bool', 'codepoint'=>'int|string'], 'IntlChar::isalpha' => ['?bool', 'codepoint'=>'int|string'], 'IntlChar::isbase' => ['?bool', 'codepoint'=>'int|string'], 'IntlChar::isblank' => ['?bool', 'codepoint'=>'int|string'], 'IntlChar::iscntrl' => ['?bool', 'codepoint'=>'int|string'], 'IntlChar::isdefined' => ['?bool', 'codepoint'=>'int|string'], 'IntlChar::isdigit' => ['?bool', 'codepoint'=>'int|string'], 'IntlChar::isgraph' => ['?bool', 'codepoint'=>'int|string'], 'IntlChar::islower' => ['?bool', 'codepoint'=>'int|string'], 'IntlChar::isprint' => ['?bool', 'codepoint'=>'int|string'], 'IntlChar::ispunct' => ['?bool', 'codepoint'=>'int|string'], 'IntlChar::isspace' => ['?bool', 'codepoint'=>'int|string'], 'IntlChar::istitle' => ['?bool', 'codepoint'=>'int|string'], 'IntlChar::isupper' => ['?bool', 'codepoint'=>'int|string'], 'IntlChar::isxdigit' => ['?bool', 'codepoint'=>'int|string'], 'IntlChar::ord' => ['?int', 'character'=>'int|string'], 'IntlChar::tolower' => ['int|string|null', 'codepoint'=>'int|string'], 'IntlChar::totitle' => ['int|string|null', 'codepoint'=>'int|string'], 'IntlChar::toupper' => ['int|string|null', 'codepoint'=>'int|string'], 'IntlCodePointBreakIterator::__construct' => ['void'], 'IntlCodePointBreakIterator::createCharacterInstance' => ['?IntlRuleBasedBreakIterator', 'locale='=>'?string'], 'IntlCodePointBreakIterator::createCodePointInstance' => ['IntlCodePointBreakIterator'], 'IntlCodePointBreakIterator::createLineInstance' => ['?IntlRuleBasedBreakIterator', 'locale='=>'?string'], 'IntlCodePointBreakIterator::createSentenceInstance' => ['?IntlRuleBasedBreakIterator', 'locale='=>'?string'], 'IntlCodePointBreakIterator::createTitleInstance' => ['?IntlRuleBasedBreakIterator', 'locale='=>'?string'], 'IntlCodePointBreakIterator::createWordInstance' => ['?IntlRuleBasedBreakIterator', 'locale='=>'?string'], 'IntlCodePointBreakIterator::current' => ['int'], 'IntlCodePointBreakIterator::first' => ['int'], 'IntlCodePointBreakIterator::following' => ['int', 'offset'=>'int'], 'IntlCodePointBreakIterator::getErrorCode' => ['int'], 'IntlCodePointBreakIterator::getErrorMessage' => ['string'], 'IntlCodePointBreakIterator::getLastCodePoint' => ['int'], 'IntlCodePointBreakIterator::getLocale' => ['string|false', 'type'=>'int'], 'IntlCodePointBreakIterator::getPartsIterator' => ['IntlPartsIterator', 'type='=>'string'], 'IntlCodePointBreakIterator::getText' => ['?string'], 'IntlCodePointBreakIterator::isBoundary' => ['bool', 'offset'=>'int'], 'IntlCodePointBreakIterator::last' => ['int'], 'IntlCodePointBreakIterator::next' => ['int', 'offset='=>'?int'], 'IntlCodePointBreakIterator::preceding' => ['int', 'offset'=>'int'], 'IntlCodePointBreakIterator::previous' => ['int'], 'IntlCodePointBreakIterator::setText' => ['?bool', 'text'=>'string'], 'IntlDateFormatter::__construct' => ['void', 'locale'=>'?string', 'datetype'=>'null|int', 'timetype'=>'null|int', 'timezone='=>'IntlTimeZone|DateTimeZone|string|null', 'calendar='=>'IntlCalendar|int|null', 'pattern='=>'?string'], 'IntlDateFormatter::create' => ['?IntlDateFormatter', 'locale'=>'?string', 'datetype'=>'null|int', 'timetype'=>'null|int', 'timezone='=>'IntlTimeZone|DateTimeZone|string|null', 'calendar='=>'IntlCalendar|int|null', 'pattern='=>'?string'], 'IntlDateFormatter::format' => ['string|false', 'value'=>'IntlCalendar|DateTime|array{0: int, 1: int, 2: int, 3: int, 4: int, 5: int, 6: int, 7: int, 8: int}|array{tm_sec: int, tm_min: int, tm_hour: int, tm_mday: int, tm_mon: int, tm_year: int, tm_wday: int, tm_yday: int, tm_isdst: int}|string|int|float'], 'IntlDateFormatter::formatObject' => ['string|false', 'object'=>'IntlCalendar|DateTime', 'format='=>'array{0: int, 1: int}|int|string|null', 'locale='=>'?string'], 'IntlDateFormatter::getCalendar' => ['int'], 'IntlDateFormatter::getCalendarObject' => ['IntlCalendar'], 'IntlDateFormatter::getDateType' => ['int'], 'IntlDateFormatter::getErrorCode' => ['int'], 'IntlDateFormatter::getErrorMessage' => ['string'], 'IntlDateFormatter::getLocale' => ['string', 'which='=>'int'], 'IntlDateFormatter::getPattern' => ['string'], 'IntlDateFormatter::getTimeType' => ['int'], 'IntlDateFormatter::getTimeZone' => ['IntlTimeZone|false'], 'IntlDateFormatter::getTimeZoneId' => ['string'], 'IntlDateFormatter::isLenient' => ['bool'], 'IntlDateFormatter::localtime' => ['array', 'value'=>'string', '&rw_position='=>'int'], 'IntlDateFormatter::parse' => ['int|float', 'value'=>'string', '&rw_position='=>'int'], 'IntlDateFormatter::setCalendar' => ['bool', 'which'=>'IntlCalendar|int|null'], 'IntlDateFormatter::setLenient' => ['bool', 'lenient'=>'bool'], 'IntlDateFormatter::setPattern' => ['bool', 'pattern'=>'string'], 'IntlDateFormatter::setTimeZone' => ['null|false', 'zone'=>'IntlTimeZone|DateTimeZone|string|null'], 'IntlException::__clone' => ['void'], 'IntlException::__construct' => ['void', 'message='=>'string', 'code='=>'int', 'previous='=>'?Throwable'], 'IntlException::__toString' => ['string'], 'IntlException::__wakeup' => ['void'], 'IntlException::getCode' => ['int'], 'IntlException::getFile' => ['string'], 'IntlException::getLine' => ['int'], 'IntlException::getMessage' => ['string'], 'IntlException::getPrevious' => ['?Throwable'], 'IntlException::getTrace' => ['list\',args?:array}>'], 'IntlException::getTraceAsString' => ['string'], 'IntlGregorianCalendar::__construct' => ['void'], 'IntlGregorianCalendar::add' => ['bool', 'field'=>'int', 'value'=>'int'], 'IntlGregorianCalendar::after' => ['bool', 'other'=>'IntlCalendar'], 'IntlGregorianCalendar::before' => ['bool', 'other'=>'IntlCalendar'], 'IntlGregorianCalendar::clear' => ['bool', 'field='=>'?int'], 'IntlGregorianCalendar::createInstance' => ['?IntlGregorianCalendar', 'timezone='=>'IntlTimeZone|DateTimeZone|string|null', 'locale='=>'?string'], 'IntlGregorianCalendar::equals' => ['bool', 'other'=>'IntlCalendar'], 'IntlGregorianCalendar::fieldDifference' => ['int|false', 'timestamp'=>'float', 'field'=>'int'], 'IntlGregorianCalendar::fromDateTime' => ['?IntlCalendar', 'datetime'=>'DateTime|string', 'locale='=>'?string'], 'IntlGregorianCalendar::get' => ['int', 'field'=>'int'], 'IntlGregorianCalendar::getActualMaximum' => ['int', 'field'=>'int'], 'IntlGregorianCalendar::getActualMinimum' => ['int', 'field'=>'int'], 'IntlGregorianCalendar::getAvailableLocales' => ['array'], 'IntlGregorianCalendar::getDayOfWeekType' => ['int', 'dayOfWeek'=>'int'], 'IntlGregorianCalendar::getErrorCode' => ['int'], 'IntlGregorianCalendar::getErrorMessage' => ['string'], 'IntlGregorianCalendar::getFirstDayOfWeek' => ['int'], 'IntlGregorianCalendar::getGreatestMinimum' => ['int', 'field'=>'int'], 'IntlGregorianCalendar::getGregorianChange' => ['float'], 'IntlGregorianCalendar::getKeywordValuesForLocale' => ['IntlIterator|false', 'keyword'=>'string', 'locale'=>'string', 'onlyCommon'=>'bool'], 'IntlGregorianCalendar::getLeastMaximum' => ['int', 'field'=>'int'], 'IntlGregorianCalendar::getLocale' => ['string|false', 'type'=>'int'], 'IntlGregorianCalendar::getMaximum' => ['int', 'field'=>'int'], 'IntlGregorianCalendar::getMinimalDaysInFirstWeek' => ['int'], 'IntlGregorianCalendar::getMinimum' => ['int', 'field'=>'int'], 'IntlGregorianCalendar::getNow' => ['float'], 'IntlGregorianCalendar::getRepeatedWallTimeOption' => ['int'], 'IntlGregorianCalendar::getSkippedWallTimeOption' => ['int'], 'IntlGregorianCalendar::getTime' => ['float'], 'IntlGregorianCalendar::getTimeZone' => ['IntlTimeZone'], 'IntlGregorianCalendar::getType' => ['string'], 'IntlGregorianCalendar::getWeekendTransition' => ['int|false', 'dayOfWeek'=>'int'], 'IntlGregorianCalendar::inDaylightTime' => ['bool'], 'IntlGregorianCalendar::isEquivalentTo' => ['bool', 'other'=>'IntlCalendar'], 'IntlGregorianCalendar::isLeapYear' => ['bool', 'year'=>'int'], 'IntlGregorianCalendar::isLenient' => ['bool'], 'IntlGregorianCalendar::isSet' => ['bool', 'field'=>'int'], 'IntlGregorianCalendar::isWeekend' => ['bool', 'timestamp='=>'?float'], 'IntlGregorianCalendar::roll' => ['bool', 'field'=>'int', 'value'=>'int|bool'], 'IntlGregorianCalendar::set' => ['bool', 'field'=>'int', 'value'=>'int'], 'IntlGregorianCalendar::set\'1' => ['bool', 'year'=>'int', 'month'=>'int', 'dayOfMonth='=>'int', 'hour='=>'int', 'minute='=>'int', 'second='=>'int'], 'IntlGregorianCalendar::setFirstDayOfWeek' => ['bool', 'dayOfWeek'=>'int'], 'IntlGregorianCalendar::setGregorianChange' => ['bool', 'timestamp'=>'float'], 'IntlGregorianCalendar::setLenient' => ['true', 'lenient'=>'bool'], 'IntlGregorianCalendar::setMinimalDaysInFirstWeek' => ['bool', 'days'=>'int'], 'IntlGregorianCalendar::setRepeatedWallTimeOption' => ['true', 'option'=>'int'], 'IntlGregorianCalendar::setSkippedWallTimeOption' => ['true', 'option'=>'int'], 'IntlGregorianCalendar::setTime' => ['bool', 'timestamp'=>'float'], 'IntlGregorianCalendar::setTimeZone' => ['bool', 'timezone'=>'IntlTimeZone|DateTimeZone|string|null'], 'IntlGregorianCalendar::toDateTime' => ['DateTime'], 'IntlIterator::__construct' => ['void'], 'IntlIterator::current' => ['mixed'], 'IntlIterator::key' => ['string'], 'IntlIterator::next' => ['void'], 'IntlIterator::rewind' => ['void'], 'IntlIterator::valid' => ['bool'], 'IntlPartsIterator::getBreakIterator' => ['IntlBreakIterator'], 'IntlRuleBasedBreakIterator::__construct' => ['void', 'rules'=>'string', 'compiled='=>'bool'], 'IntlRuleBasedBreakIterator::createCharacterInstance' => ['?IntlRuleBasedBreakIterator', 'locale='=>'?string'], 'IntlRuleBasedBreakIterator::createCodePointInstance' => ['IntlCodePointBreakIterator'], 'IntlRuleBasedBreakIterator::createLineInstance' => ['?IntlRuleBasedBreakIterator', 'locale='=>'?string'], 'IntlRuleBasedBreakIterator::createSentenceInstance' => ['?IntlRuleBasedBreakIterator', 'locale='=>'?string'], 'IntlRuleBasedBreakIterator::createTitleInstance' => ['?IntlRuleBasedBreakIterator', 'locale='=>'?string'], 'IntlRuleBasedBreakIterator::createWordInstance' => ['?IntlRuleBasedBreakIterator', 'locale='=>'?string'], 'IntlRuleBasedBreakIterator::current' => ['int'], 'IntlRuleBasedBreakIterator::first' => ['int'], 'IntlRuleBasedBreakIterator::following' => ['int', 'offset'=>'int'], 'IntlRuleBasedBreakIterator::getBinaryRules' => ['string'], 'IntlRuleBasedBreakIterator::getErrorCode' => ['int'], 'IntlRuleBasedBreakIterator::getErrorMessage' => ['string'], 'IntlRuleBasedBreakIterator::getLocale' => ['string|false', 'type'=>'int'], 'IntlRuleBasedBreakIterator::getPartsIterator' => ['IntlPartsIterator', 'type='=>'string'], 'IntlRuleBasedBreakIterator::getRuleStatus' => ['int'], 'IntlRuleBasedBreakIterator::getRuleStatusVec' => ['array'], 'IntlRuleBasedBreakIterator::getRules' => ['string'], 'IntlRuleBasedBreakIterator::getText' => ['?string'], 'IntlRuleBasedBreakIterator::isBoundary' => ['bool', 'offset'=>'int'], 'IntlRuleBasedBreakIterator::last' => ['int'], 'IntlRuleBasedBreakIterator::next' => ['int', 'offset='=>'?int'], 'IntlRuleBasedBreakIterator::preceding' => ['int', 'offset'=>'int'], 'IntlRuleBasedBreakIterator::previous' => ['int'], 'IntlRuleBasedBreakIterator::setText' => ['?bool', 'text'=>'string'], 'IntlTimeZone::countEquivalentIDs' => ['int|false', 'timezoneId'=>'string'], 'IntlTimeZone::createDefault' => ['IntlTimeZone'], 'IntlTimeZone::createEnumeration' => ['IntlIterator|false', 'countryOrRawOffset='=>'IntlTimeZone|string|int|float|null'], 'IntlTimeZone::createTimeZone' => ['?IntlTimeZone', 'timezoneId'=>'string'], 'IntlTimeZone::createTimeZoneIDEnumeration' => ['IntlIterator|false', 'type'=>'int', 'region='=>'?string', 'rawOffset='=>'?int'], 'IntlTimeZone::fromDateTimeZone' => ['?IntlTimeZone', 'timezone'=>'DateTimeZone'], 'IntlTimeZone::getCanonicalID' => ['string|false', 'timezoneId'=>'string', '&w_isSystemId='=>'bool'], 'IntlTimeZone::getDSTSavings' => ['int'], 'IntlTimeZone::getDisplayName' => ['string|false', 'dst='=>'bool', 'style='=>'int', 'locale='=>'?string'], 'IntlTimeZone::getEquivalentID' => ['string|false', 'timezoneId'=>'string', 'offset'=>'int'], 'IntlTimeZone::getErrorCode' => ['int'], 'IntlTimeZone::getErrorMessage' => ['string'], 'IntlTimeZone::getGMT' => ['IntlTimeZone'], 'IntlTimeZone::getID' => ['string'], 'IntlTimeZone::getIDForWindowsID' => ['string|false', 'timezoneId'=>'string', 'region='=>'string'], 'IntlTimeZone::getOffset' => ['bool', 'timestamp'=>'float', 'local'=>'bool', '&w_rawOffset'=>'int', '&w_dstOffset'=>'int'], 'IntlTimeZone::getRawOffset' => ['int'], 'IntlTimeZone::getRegion' => ['string|false', 'timezoneId'=>'string'], 'IntlTimeZone::getTZDataVersion' => ['string'], 'IntlTimeZone::getUnknown' => ['IntlTimeZone'], 'IntlTimeZone::getWindowsID' => ['string|false', 'timezoneId'=>'string'], 'IntlTimeZone::hasSameRules' => ['bool', 'other'=>'IntlTimeZone'], 'IntlTimeZone::toDateTimeZone' => ['DateTimeZone|false'], 'IntlTimeZone::useDaylightTime' => ['bool'], 'InvalidArgumentException::__clone' => ['void'], 'InvalidArgumentException::__construct' => ['void', 'message='=>'string', 'code='=>'int', 'previous='=>'?Throwable'], 'InvalidArgumentException::__toString' => ['string'], 'InvalidArgumentException::getCode' => ['int'], 'InvalidArgumentException::getFile' => ['string'], 'InvalidArgumentException::getLine' => ['int'], 'InvalidArgumentException::getMessage' => ['string'], 'InvalidArgumentException::getPrevious' => ['?Throwable'], 'InvalidArgumentException::getTrace' => ['list\',args?:array}>'], 'InvalidArgumentException::getTraceAsString' => ['string'], 'Iterator::current' => ['mixed'], 'Iterator::key' => ['mixed'], 'Iterator::next' => ['void'], 'Iterator::rewind' => ['void'], 'Iterator::valid' => ['bool'], 'IteratorAggregate::getIterator' => ['Traversable'], 'IteratorIterator::__construct' => ['void', 'iterator'=>'Traversable', 'class='=>'?string'], 'IteratorIterator::current' => ['mixed'], 'IteratorIterator::getInnerIterator' => ['Iterator'], 'IteratorIterator::key' => ['mixed'], 'IteratorIterator::next' => ['void'], 'IteratorIterator::rewind' => ['void'], 'IteratorIterator::valid' => ['bool'], 'JavaException::getCause' => ['object'], 'JsonIncrementalParser::__construct' => ['void', 'depth'=>'', 'options'=>''], 'JsonIncrementalParser::get' => ['', 'options'=>''], 'JsonIncrementalParser::getError' => [''], 'JsonIncrementalParser::parse' => ['', 'json'=>''], 'JsonIncrementalParser::parseFile' => ['', 'filename'=>''], 'JsonIncrementalParser::reset' => [''], 'JsonSerializable::jsonSerialize' => ['mixed'], 'Judy::__construct' => ['void', 'judy_type'=>'int'], 'Judy::__destruct' => ['void'], 'Judy::byCount' => ['int', 'nth_index'=>'int'], 'Judy::count' => ['int', 'index_start='=>'int', 'index_end='=>'int'], 'Judy::first' => ['mixed', 'index='=>'mixed'], 'Judy::firstEmpty' => ['mixed', 'index='=>'mixed'], 'Judy::free' => ['int'], 'Judy::getType' => ['int'], 'Judy::last' => ['mixed', 'index='=>'string'], 'Judy::lastEmpty' => ['mixed', 'index='=>'int'], 'Judy::memoryUsage' => ['int'], 'Judy::next' => ['mixed', 'index'=>'mixed'], 'Judy::nextEmpty' => ['mixed', 'index'=>'mixed'], 'Judy::offsetExists' => ['bool', 'offset'=>'int|string'], 'Judy::offsetGet' => ['mixed', 'offset'=>'int|string'], 'Judy::offsetSet' => ['bool', 'offset'=>'int|string|null', 'value'=>'mixed'], 'Judy::offsetUnset' => ['bool', 'offset'=>'int|string'], 'Judy::prev' => ['mixed', 'index'=>'mixed'], 'Judy::prevEmpty' => ['mixed', 'index'=>'mixed'], 'Judy::size' => ['int'], 'KTaglib_ID3v2_AttachedPictureFrame::getDescription' => ['string'], 'KTaglib_ID3v2_AttachedPictureFrame::getMimeType' => ['string'], 'KTaglib_ID3v2_AttachedPictureFrame::getType' => ['int'], 'KTaglib_ID3v2_AttachedPictureFrame::savePicture' => ['bool', 'filename'=>'string'], 'KTaglib_ID3v2_AttachedPictureFrame::setMimeType' => ['string', 'type'=>'string'], 'KTaglib_ID3v2_AttachedPictureFrame::setPicture' => ['', 'filename'=>'string'], 'KTaglib_ID3v2_AttachedPictureFrame::setType' => ['', 'type'=>'int'], 'KTaglib_ID3v2_Frame::__toString' => ['string'], 'KTaglib_ID3v2_Frame::getDescription' => ['string'], 'KTaglib_ID3v2_Frame::getMimeType' => ['string'], 'KTaglib_ID3v2_Frame::getSize' => ['int'], 'KTaglib_ID3v2_Frame::getType' => ['int'], 'KTaglib_ID3v2_Frame::savePicture' => ['bool', 'filename'=>'string'], 'KTaglib_ID3v2_Frame::setMimeType' => ['string', 'type'=>'string'], 'KTaglib_ID3v2_Frame::setPicture' => ['void', 'filename'=>'string'], 'KTaglib_ID3v2_Frame::setType' => ['void', 'type'=>'int'], 'KTaglib_ID3v2_Tag::addFrame' => ['bool', 'frame'=>'KTaglib_ID3v2_Frame'], 'KTaglib_ID3v2_Tag::getFrameList' => ['array'], 'KTaglib_MPEG_AudioProperties::getBitrate' => ['int'], 'KTaglib_MPEG_AudioProperties::getChannels' => ['int'], 'KTaglib_MPEG_AudioProperties::getLayer' => ['int'], 'KTaglib_MPEG_AudioProperties::getLength' => ['int'], 'KTaglib_MPEG_AudioProperties::getSampleBitrate' => ['int'], 'KTaglib_MPEG_AudioProperties::getVersion' => ['int'], 'KTaglib_MPEG_AudioProperties::isCopyrighted' => ['bool'], 'KTaglib_MPEG_AudioProperties::isOriginal' => ['bool'], 'KTaglib_MPEG_AudioProperties::isProtectionEnabled' => ['bool'], 'KTaglib_MPEG_File::getAudioProperties' => ['KTaglib_MPEG_File'], 'KTaglib_MPEG_File::getID3v1Tag' => ['KTaglib_ID3v1_Tag', 'create='=>'bool'], 'KTaglib_MPEG_File::getID3v2Tag' => ['KTaglib_ID3v2_Tag', 'create='=>'bool'], 'KTaglib_Tag::getAlbum' => ['string'], 'KTaglib_Tag::getArtist' => ['string'], 'KTaglib_Tag::getComment' => ['string'], 'KTaglib_Tag::getGenre' => ['string'], 'KTaglib_Tag::getTitle' => ['string'], 'KTaglib_Tag::getTrack' => ['int'], 'KTaglib_Tag::getYear' => ['int'], 'KTaglib_Tag::isEmpty' => ['bool'], 'Lapack::eigenValues' => ['array', 'a'=>'array', 'left='=>'array', 'right='=>'array'], 'Lapack::identity' => ['array', 'n'=>'int'], 'Lapack::leastSquaresByFactorisation' => ['array', 'a'=>'array', 'b'=>'array'], 'Lapack::leastSquaresBySVD' => ['array', 'a'=>'array', 'b'=>'array'], 'Lapack::pseudoInverse' => ['array', 'a'=>'array'], 'Lapack::singularValues' => ['array', 'a'=>'array'], 'Lapack::solveLinearEquation' => ['array', 'a'=>'array', 'b'=>'array'], 'LengthException::__clone' => ['void'], 'LengthException::__construct' => ['void', 'message='=>'string', 'code='=>'int', 'previous='=>'?Throwable'], 'LengthException::__toString' => ['string'], 'LengthException::getCode' => ['int'], 'LengthException::getFile' => ['string'], 'LengthException::getLine' => ['int'], 'LengthException::getMessage' => ['string'], 'LengthException::getPrevious' => ['?Throwable'], 'LengthException::getTrace' => ['list\',args?:array}>'], 'LengthException::getTraceAsString' => ['string'], 'LevelDB::__construct' => ['void', 'name'=>'string', 'options='=>'array', 'read_options='=>'array', 'write_options='=>'array'], 'LevelDB::close' => [''], 'LevelDB::compactRange' => ['', 'start'=>'', 'limit'=>''], 'LevelDB::delete' => ['bool', 'key'=>'string', 'write_options='=>'array'], 'LevelDB::destroy' => ['', 'name'=>'', 'options='=>'array'], 'LevelDB::get' => ['bool|string', 'key'=>'string', 'read_options='=>'array'], 'LevelDB::getApproximateSizes' => ['', 'start'=>'', 'limit'=>''], 'LevelDB::getIterator' => ['LevelDBIterator', 'options='=>'array'], 'LevelDB::getProperty' => ['mixed', 'name'=>'string'], 'LevelDB::getSnapshot' => ['LevelDBSnapshot'], 'LevelDB::put' => ['', 'key'=>'string', 'value'=>'string', 'write_options='=>'array'], 'LevelDB::repair' => ['', 'name'=>'', 'options='=>'array'], 'LevelDB::set' => ['', 'key'=>'string', 'value'=>'string', 'write_options='=>'array'], 'LevelDB::write' => ['', 'batch'=>'LevelDBWriteBatch', 'write_options='=>'array'], 'LevelDBIterator::__construct' => ['void', 'db'=>'LevelDB', 'read_options='=>'array'], 'LevelDBIterator::current' => ['mixed'], 'LevelDBIterator::destroy' => [''], 'LevelDBIterator::getError' => [''], 'LevelDBIterator::key' => ['int|string'], 'LevelDBIterator::last' => [''], 'LevelDBIterator::next' => ['void'], 'LevelDBIterator::prev' => [''], 'LevelDBIterator::rewind' => ['void'], 'LevelDBIterator::seek' => ['', 'key'=>''], 'LevelDBIterator::valid' => ['bool'], 'LevelDBSnapshot::__construct' => ['void', 'db'=>'LevelDB'], 'LevelDBSnapshot::release' => [''], 'LevelDBWriteBatch::__construct' => ['void', 'name'=>'', 'options='=>'array', 'read_options='=>'array', 'write_options='=>'array'], 'LevelDBWriteBatch::clear' => [''], 'LevelDBWriteBatch::delete' => ['', 'key'=>'', 'write_options='=>'array'], 'LevelDBWriteBatch::put' => ['', 'key'=>'', 'value'=>'', 'write_options='=>'array'], 'LevelDBWriteBatch::set' => ['', 'key'=>'', 'value'=>'', 'write_options='=>'array'], 'LimitIterator::__construct' => ['void', 'iterator'=>'Iterator', 'offset='=>'int', 'limit='=>'int'], 'LimitIterator::current' => ['mixed'], 'LimitIterator::getInnerIterator' => ['Iterator'], 'LimitIterator::getPosition' => ['int'], 'LimitIterator::key' => ['mixed'], 'LimitIterator::next' => ['void'], 'LimitIterator::rewind' => ['void'], 'LimitIterator::seek' => ['int', 'offset'=>'int'], 'LimitIterator::valid' => ['bool'], 'Locale::acceptFromHttp' => ['string|false', 'header'=>'string'], 'Locale::canonicalize' => ['?string', 'locale'=>'string'], 'Locale::composeLocale' => ['string', 'subtags'=>'array'], 'Locale::filterMatches' => ['?bool', 'languageTag'=>'string', 'locale'=>'string', 'canonicalize='=>'bool'], 'Locale::getAllVariants' => ['array', 'locale'=>'string'], 'Locale::getDefault' => ['string'], 'Locale::getDisplayLanguage' => ['string', 'locale'=>'string', 'displayLocale='=>'string'], 'Locale::getDisplayName' => ['string', 'locale'=>'string', 'displayLocale='=>'string'], 'Locale::getDisplayRegion' => ['string', 'locale'=>'string', 'displayLocale='=>'string'], 'Locale::getDisplayScript' => ['string', 'locale'=>'string', 'displayLocale='=>'string'], 'Locale::getDisplayVariant' => ['string', 'locale'=>'string', 'displayLocale='=>'string'], 'Locale::getKeywords' => ['array|false', 'locale'=>'string'], 'Locale::getPrimaryLanguage' => ['string', 'locale'=>'string'], 'Locale::getRegion' => ['string', 'locale'=>'string'], 'Locale::getScript' => ['string', 'locale'=>'string'], 'Locale::lookup' => ['?string', 'languageTag'=>'array', 'locale'=>'string', 'canonicalize='=>'bool', 'defaultLocale='=>'string'], 'Locale::parseLocale' => ['array', 'locale'=>'string'], 'Locale::setDefault' => ['bool', 'locale'=>'string'], 'LogicException::__clone' => ['void'], 'LogicException::__construct' => ['void', 'message='=>'string', 'code='=>'int', 'previous='=>'?Throwable'], 'LogicException::__toString' => ['string'], 'LogicException::getCode' => ['int'], 'LogicException::getFile' => ['string'], 'LogicException::getLine' => ['int'], 'LogicException::getMessage' => ['string'], 'LogicException::getPrevious' => ['?Throwable'], 'LogicException::getTrace' => ['list\',args?:array}>'], 'LogicException::getTraceAsString' => ['string'], 'Lua::__call' => ['mixed', 'lua_func'=>'callable', 'args='=>'array', 'use_self='=>'int'], 'Lua::__construct' => ['void', 'lua_script_file'=>'string'], 'Lua::assign' => ['?Lua', 'name'=>'string', 'value'=>'mixed'], 'Lua::call' => ['mixed', 'lua_func'=>'callable', 'args='=>'array', 'use_self='=>'int'], 'Lua::eval' => ['mixed', 'statements'=>'string'], 'Lua::getVersion' => ['string'], 'Lua::include' => ['mixed', 'file'=>'string'], 'Lua::registerCallback' => ['Lua|null|false', 'name'=>'string', 'function'=>'callable'], 'LuaClosure::__invoke' => ['void', 'arg'=>'mixed', '...args='=>'mixed'], 'Memcache::add' => ['bool', 'key'=>'string', 'var'=>'mixed', 'flag='=>'int', 'expire='=>'int'], 'Memcache::addServer' => ['bool', 'host'=>'string', 'port='=>'int', 'persistent='=>'bool', 'weight='=>'int', 'timeout='=>'int', 'retry_interval='=>'int', 'status='=>'bool', 'failure_callback='=>'callable', 'timeoutms='=>'int'], 'Memcache::append' => [''], 'Memcache::cas' => [''], 'Memcache::close' => ['bool'], 'Memcache::connect' => ['bool', 'host'=>'string', 'port='=>'int', 'timeout='=>'int'], 'Memcache::decrement' => ['int', 'key'=>'string', 'value='=>'int'], 'Memcache::delete' => ['bool', 'key'=>'string', 'timeout='=>'int'], 'Memcache::findServer' => [''], 'Memcache::flush' => ['bool'], 'Memcache::get' => ['string|array|false', 'key'=>'string', 'flags='=>'array', 'keys='=>'array'], 'Memcache::get\'1' => ['array', 'key'=>'string[]', 'flags='=>'int[]'], 'Memcache::getExtendedStats' => ['false|array>', 'type='=>'string', 'slabid='=>'int', 'limit='=>'int'], 'Memcache::getServerStatus' => ['int', 'host'=>'string', 'port='=>'int'], 'Memcache::getStats' => ['array', 'type='=>'string', 'slabid='=>'int', 'limit='=>'int'], 'Memcache::getVersion' => ['string'], 'Memcache::increment' => ['int', 'key'=>'string', 'value='=>'int'], 'Memcache::pconnect' => ['bool', 'host'=>'string', 'port='=>'int', 'timeout='=>'int'], 'Memcache::prepend' => ['string'], 'Memcache::replace' => ['bool', 'key'=>'string', 'var'=>'mixed', 'flag='=>'int', 'expire='=>'int'], 'Memcache::set' => ['bool', 'key'=>'string', 'var'=>'mixed', 'flag='=>'int', 'expire='=>'int'], 'Memcache::setCompressThreshold' => ['bool', 'threshold'=>'int', 'min_savings='=>'float'], 'Memcache::setFailureCallback' => [''], 'Memcache::setServerParams' => ['bool', 'host'=>'string', 'port='=>'int', 'timeout='=>'int', 'retry_interval='=>'int', 'status='=>'bool', 'failure_callback='=>'callable'], 'MemcachePool::add' => ['bool', 'key'=>'string', 'var'=>'mixed', 'flag='=>'int', 'expire='=>'int'], 'MemcachePool::addServer' => ['bool', 'host'=>'string', 'port='=>'int', 'persistent='=>'bool', 'weight='=>'int', 'timeout='=>'int', 'retry_interval='=>'int', 'status='=>'bool', 'failure_callback='=>'?callable', 'timeoutms='=>'int'], 'MemcachePool::append' => [''], 'MemcachePool::cas' => [''], 'MemcachePool::close' => ['bool'], 'MemcachePool::connect' => ['bool', 'host'=>'string', 'port'=>'int', 'timeout='=>'int'], 'MemcachePool::decrement' => ['int|false', 'key'=>'', 'value='=>'int|mixed'], 'MemcachePool::delete' => ['bool', 'key'=>'', 'timeout='=>'int|mixed'], 'MemcachePool::findServer' => [''], 'MemcachePool::flush' => ['bool'], 'MemcachePool::get' => ['array|string|false', 'key'=>'array|string', '&flags='=>'array|int'], 'MemcachePool::getExtendedStats' => ['false|array>', 'type='=>'string', 'slabid='=>'int', 'limit='=>'int'], 'MemcachePool::getServerStatus' => ['int', 'host'=>'string', 'port='=>'int'], 'MemcachePool::getStats' => ['array|false', 'type='=>'string', 'slabid='=>'int', 'limit='=>'int'], 'MemcachePool::getVersion' => ['string|false'], 'MemcachePool::increment' => ['int|false', 'key'=>'', 'value='=>'int|mixed'], 'MemcachePool::prepend' => ['string'], 'MemcachePool::replace' => ['bool', 'key'=>'string', 'var'=>'mixed', 'flag='=>'int', 'expire='=>'int'], 'MemcachePool::set' => ['bool', 'key'=>'string', 'var'=>'mixed', 'flag='=>'int', 'expire='=>'int'], 'MemcachePool::setCompressThreshold' => ['bool', 'thresold'=>'int', 'min_saving='=>'float'], 'MemcachePool::setFailureCallback' => [''], 'MemcachePool::setServerParams' => ['bool', 'host'=>'string', 'port='=>'int', 'timeout='=>'int', 'retry_interval='=>'int', 'status='=>'bool', 'failure_callback='=>'?callable'], 'Memcached::__construct' => ['void', 'persistent_id='=>'?string', 'callback='=>'?callable', 'connection_str='=>'?string'], 'Memcached::add' => ['bool', 'key'=>'string', 'value'=>'mixed', 'expiration='=>'int'], 'Memcached::addByKey' => ['bool', 'server_key'=>'string', 'key'=>'string', 'value'=>'mixed', 'expiration='=>'int'], 'Memcached::addServer' => ['bool', 'host'=>'string', 'port'=>'int', 'weight='=>'int'], 'Memcached::addServers' => ['bool', 'servers'=>'array'], 'Memcached::append' => ['?bool', 'key'=>'string', 'value'=>'string'], 'Memcached::appendByKey' => ['?bool', 'server_key'=>'string', 'key'=>'string', 'value'=>'string'], 'Memcached::cas' => ['bool', 'cas_token'=>'string|int|float', 'key'=>'string', 'value'=>'mixed', 'expiration='=>'int'], 'Memcached::casByKey' => ['bool', 'cas_token'=>'string|int|float', 'server_key'=>'string', 'key'=>'string', 'value'=>'mixed', 'expiration='=>'int'], 'Memcached::decrement' => ['int|false', 'key'=>'string', 'offset='=>'int', 'initial_value='=>'int', 'expiry='=>'int'], 'Memcached::decrementByKey' => ['int|false', 'server_key'=>'string', 'key'=>'string', 'offset='=>'int', 'initial_value='=>'int', 'expiry='=>'int'], 'Memcached::delete' => ['bool', 'key'=>'string', 'time='=>'int'], 'Memcached::deleteByKey' => ['bool', 'server_key'=>'string', 'key'=>'string', 'time='=>'int'], 'Memcached::deleteMulti' => ['array', 'keys'=>'array', 'time='=>'int'], 'Memcached::deleteMultiByKey' => ['array', 'server_key'=>'string', 'keys'=>'array', 'time='=>'int'], 'Memcached::fetch' => ['array|false'], 'Memcached::fetchAll' => ['array|false'], 'Memcached::flush' => ['bool', 'delay='=>'int'], 'Memcached::flushBuffers' => ['bool'], 'Memcached::get' => ['mixed|false', 'key'=>'string', 'cache_cb='=>'?callable', 'get_flags='=>'int'], 'Memcached::getAllKeys' => ['array|false'], 'Memcached::getByKey' => ['mixed|false', 'server_key'=>'string', 'key'=>'string', 'cache_cb='=>'?callable', 'get_flags='=>'int'], 'Memcached::getDelayed' => ['bool', 'keys'=>'array', 'with_cas='=>'bool', 'value_cb='=>'?callable'], 'Memcached::getDelayedByKey' => ['bool', 'server_key'=>'string', 'keys'=>'array', 'with_cas='=>'bool', 'value_cb='=>'?callable'], 'Memcached::getLastDisconnectedServer' => ['array|false'], 'Memcached::getLastErrorCode' => ['int'], 'Memcached::getLastErrorErrno' => ['int'], 'Memcached::getLastErrorMessage' => ['string'], 'Memcached::getMulti' => ['array|false', 'keys'=>'array', 'get_flags='=>'int'], 'Memcached::getMultiByKey' => ['array|false', 'server_key'=>'string', 'keys'=>'array', 'get_flags='=>'int'], 'Memcached::getOption' => ['mixed|false', 'option'=>'int'], 'Memcached::getResultCode' => ['int'], 'Memcached::getResultMessage' => ['string'], 'Memcached::getServerByKey' => ['array', 'server_key'=>'string'], 'Memcached::getServerList' => ['array'], 'Memcached::getStats' => ['false|array>', 'type='=>'?string'], 'Memcached::getVersion' => ['array'], 'Memcached::increment' => ['int|false', 'key'=>'string', 'offset='=>'int', 'initial_value='=>'int', 'expiry='=>'int'], 'Memcached::incrementByKey' => ['int|false', 'server_key'=>'string', 'key'=>'string', 'offset='=>'int', 'initial_value='=>'int', 'expiry='=>'int'], 'Memcached::isPersistent' => ['bool'], 'Memcached::isPristine' => ['bool'], 'Memcached::prepend' => ['?bool', 'key'=>'string', 'value'=>'string'], 'Memcached::prependByKey' => ['?bool', 'server_key'=>'string', 'key'=>'string', 'value'=>'string'], 'Memcached::quit' => ['bool'], 'Memcached::replace' => ['bool', 'key'=>'string', 'value'=>'mixed', 'expiration='=>'int'], 'Memcached::replaceByKey' => ['bool', 'server_key'=>'string', 'key'=>'string', 'value'=>'mixed', 'expiration='=>'int'], 'Memcached::resetServerList' => ['bool'], 'Memcached::set' => ['bool', 'key'=>'string', 'value'=>'mixed', 'expiration='=>'int'], 'Memcached::setBucket' => ['bool', 'host_map'=>'array', 'forward_map'=>'?array', 'replicas'=>'int'], 'Memcached::setByKey' => ['bool', 'server_key'=>'string', 'key'=>'string', 'value'=>'mixed', 'expiration='=>'int'], 'Memcached::setEncodingKey' => ['bool', 'key'=>'string'], 'Memcached::setMulti' => ['bool', 'items'=>'array', 'expiration='=>'int'], 'Memcached::setMultiByKey' => ['bool', 'server_key'=>'string', 'items'=>'array', 'expiration='=>'int'], 'Memcached::setOption' => ['bool', 'option'=>'int', 'value'=>'mixed'], 'Memcached::setOptions' => ['bool', 'options'=>'array'], 'Memcached::setSaslAuthData' => ['bool', 'username'=>'string', 'password'=>'string'], 'Memcached::touch' => ['bool', 'key'=>'string', 'expiration='=>'int'], 'Memcached::touchByKey' => ['bool', 'server_key'=>'string', 'key'=>'string', 'expiration='=>'int'], 'MessageFormatter::__construct' => ['void', 'locale'=>'string', 'pattern'=>'string'], 'MessageFormatter::create' => ['MessageFormatter', 'locale'=>'string', 'pattern'=>'string'], 'MessageFormatter::format' => ['false|string', 'values'=>'array'], 'MessageFormatter::formatMessage' => ['false|string', 'locale'=>'string', 'pattern'=>'string', 'values'=>'array'], 'MessageFormatter::getErrorCode' => ['int'], 'MessageFormatter::getErrorMessage' => ['string'], 'MessageFormatter::getLocale' => ['string'], 'MessageFormatter::getPattern' => ['string'], 'MessageFormatter::parse' => ['array|false', 'string'=>'string'], 'MessageFormatter::parseMessage' => ['array|false', 'locale'=>'string', 'pattern'=>'string', 'message'=>'string'], 'MessageFormatter::setPattern' => ['bool', 'pattern'=>'string'], 'Mongo::__construct' => ['void', 'server='=>'string', 'options='=>'array', 'driver_options='=>'array'], 'Mongo::__get' => ['MongoDB', 'dbname'=>'string'], 'Mongo::__toString' => ['string'], 'Mongo::close' => ['bool'], 'Mongo::connect' => ['bool'], 'Mongo::connectUtil' => ['bool'], 'Mongo::dropDB' => ['array', 'db'=>'mixed'], 'Mongo::forceError' => ['bool'], 'Mongo::getConnections' => ['array'], 'Mongo::getHosts' => ['array'], 'Mongo::getPoolSize' => ['int'], 'Mongo::getReadPreference' => ['array'], 'Mongo::getSlave' => ['?string'], 'Mongo::getSlaveOkay' => ['bool'], 'Mongo::getWriteConcern' => ['array'], 'Mongo::killCursor' => ['', 'server_hash'=>'string', 'id'=>'MongoInt64|int'], 'Mongo::lastError' => ['?array'], 'Mongo::listDBs' => ['array'], 'Mongo::pairConnect' => ['bool'], 'Mongo::pairPersistConnect' => ['bool', 'username='=>'string', 'password='=>'string'], 'Mongo::persistConnect' => ['bool', 'username='=>'string', 'password='=>'string'], 'Mongo::poolDebug' => ['array'], 'Mongo::prevError' => ['array'], 'Mongo::resetError' => ['array'], 'Mongo::selectCollection' => ['MongoCollection', 'db'=>'string', 'collection'=>'string'], 'Mongo::selectDB' => ['MongoDB', 'name'=>'string'], 'Mongo::setPoolSize' => ['bool', 'size'=>'int'], 'Mongo::setReadPreference' => ['bool', 'readPreference'=>'string', 'tags='=>'array'], 'Mongo::setSlaveOkay' => ['bool', 'ok='=>'bool'], 'Mongo::switchSlave' => ['string'], 'MongoBinData::__construct' => ['void', 'data'=>'string', 'type='=>'int'], 'MongoBinData::__toString' => ['string'], 'MongoClient::__construct' => ['void', 'server='=>'string', 'options='=>'array', 'driver_options='=>'array'], 'MongoClient::__get' => ['MongoDB', 'dbname'=>'string'], 'MongoClient::__toString' => ['string'], 'MongoClient::close' => ['bool', 'connection='=>'bool|string'], 'MongoClient::connect' => ['bool'], 'MongoClient::dropDB' => ['array', 'db'=>'mixed'], 'MongoClient::getConnections' => ['array'], 'MongoClient::getHosts' => ['array'], 'MongoClient::getReadPreference' => ['array'], 'MongoClient::getWriteConcern' => ['array'], 'MongoClient::killCursor' => ['bool', 'server_hash'=>'string', 'id'=>'int|MongoInt64'], 'MongoClient::listDBs' => ['array'], 'MongoClient::selectCollection' => ['MongoCollection', 'db'=>'string', 'collection'=>'string'], 'MongoClient::selectDB' => ['MongoDB', 'name'=>'string'], 'MongoClient::setReadPreference' => ['bool', 'read_preference'=>'string', 'tags='=>'array'], 'MongoClient::setWriteConcern' => ['bool', 'w'=>'mixed', 'wtimeout='=>'int'], 'MongoClient::switchSlave' => ['string'], 'MongoCode::__construct' => ['void', 'code'=>'string', 'scope='=>'array'], 'MongoCode::__toString' => ['string'], 'MongoCollection::__construct' => ['void', 'db'=>'MongoDB', 'name'=>'string'], 'MongoCollection::__get' => ['MongoCollection', 'name'=>'string'], 'MongoCollection::__toString' => ['string'], 'MongoCollection::aggregate' => ['array', 'op'=>'array', 'op='=>'array', '...args='=>'array'], 'MongoCollection::aggregate\'1' => ['array', 'pipeline'=>'array', 'options='=>'array'], 'MongoCollection::aggregateCursor' => ['MongoCommandCursor', 'command'=>'array', 'options='=>'array'], 'MongoCollection::batchInsert' => ['array|bool', 'a'=>'array', 'options='=>'array'], 'MongoCollection::count' => ['int', 'query='=>'array', 'limit='=>'int', 'skip='=>'int'], 'MongoCollection::createDBRef' => ['array', 'a'=>'array'], 'MongoCollection::createIndex' => ['array', 'keys'=>'array', 'options='=>'array'], 'MongoCollection::deleteIndex' => ['array', 'keys'=>'string|array'], 'MongoCollection::deleteIndexes' => ['array'], 'MongoCollection::distinct' => ['array|false', 'key'=>'string', 'query='=>'array'], 'MongoCollection::drop' => ['array'], 'MongoCollection::ensureIndex' => ['bool', 'keys'=>'array', 'options='=>'array'], 'MongoCollection::find' => ['MongoCursor', 'query='=>'array', 'fields='=>'array'], 'MongoCollection::findAndModify' => ['array', 'query'=>'array', 'update='=>'array', 'fields='=>'array', 'options='=>'array'], 'MongoCollection::findOne' => ['?array', 'query='=>'array', 'fields='=>'array'], 'MongoCollection::getDBRef' => ['array', 'ref'=>'array'], 'MongoCollection::getIndexInfo' => ['array'], 'MongoCollection::getName' => ['string'], 'MongoCollection::getReadPreference' => ['array'], 'MongoCollection::getSlaveOkay' => ['bool'], 'MongoCollection::getWriteConcern' => ['array'], 'MongoCollection::group' => ['array', 'keys'=>'mixed', 'initial'=>'array', 'reduce'=>'MongoCode', 'options='=>'array'], 'MongoCollection::insert' => ['bool|array', 'a'=>'array|object', 'options='=>'array'], 'MongoCollection::parallelCollectionScan' => ['MongoCommandCursor[]', 'num_cursors'=>'int'], 'MongoCollection::remove' => ['bool|array', 'criteria='=>'array', 'options='=>'array'], 'MongoCollection::save' => ['bool|array', 'a'=>'array|object', 'options='=>'array'], 'MongoCollection::setReadPreference' => ['bool', 'read_preference'=>'string', 'tags='=>'array'], 'MongoCollection::setSlaveOkay' => ['bool', 'ok='=>'bool'], 'MongoCollection::setWriteConcern' => ['bool', 'w'=>'mixed', 'wtimeout='=>'int'], 'MongoCollection::toIndexString' => ['string', 'keys'=>'mixed'], 'MongoCollection::update' => ['bool', 'criteria'=>'array', 'newobj'=>'array', 'options='=>'array'], 'MongoCollection::validate' => ['array', 'scan_data='=>'bool'], 'MongoCommandCursor::__construct' => ['void', 'connection'=>'MongoClient', 'ns'=>'string', 'command'=>'array'], 'MongoCommandCursor::batchSize' => ['MongoCommandCursor', 'batchSize'=>'int'], 'MongoCommandCursor::createFromDocument' => ['MongoCommandCursor', 'connection'=>'MongoClient', 'hash'=>'string', 'document'=>'array'], 'MongoCommandCursor::current' => ['array'], 'MongoCommandCursor::dead' => ['bool'], 'MongoCommandCursor::getReadPreference' => ['array'], 'MongoCommandCursor::info' => ['array'], 'MongoCommandCursor::key' => ['int'], 'MongoCommandCursor::next' => ['void'], 'MongoCommandCursor::rewind' => ['array'], 'MongoCommandCursor::setReadPreference' => ['MongoCommandCursor', 'read_preference'=>'string', 'tags='=>'array'], 'MongoCommandCursor::timeout' => ['MongoCommandCursor', 'ms'=>'int'], 'MongoCommandCursor::valid' => ['bool'], 'MongoCursor::__construct' => ['void', 'connection'=>'MongoClient', 'ns'=>'string', 'query='=>'array', 'fields='=>'array'], 'MongoCursor::addOption' => ['MongoCursor', 'key'=>'string', 'value'=>'mixed'], 'MongoCursor::awaitData' => ['MongoCursor', 'wait='=>'bool'], 'MongoCursor::batchSize' => ['MongoCursor', 'num'=>'int'], 'MongoCursor::count' => ['int', 'foundonly='=>'bool'], 'MongoCursor::current' => ['array'], 'MongoCursor::dead' => ['bool'], 'MongoCursor::doQuery' => ['void'], 'MongoCursor::explain' => ['array'], 'MongoCursor::fields' => ['MongoCursor', 'f'=>'array'], 'MongoCursor::getNext' => ['array'], 'MongoCursor::getReadPreference' => ['array'], 'MongoCursor::hasNext' => ['bool'], 'MongoCursor::hint' => ['MongoCursor', 'key_pattern'=>'string|array|object'], 'MongoCursor::immortal' => ['MongoCursor', 'liveforever='=>'bool'], 'MongoCursor::info' => ['array'], 'MongoCursor::key' => ['string'], 'MongoCursor::limit' => ['MongoCursor', 'num'=>'int'], 'MongoCursor::maxTimeMS' => ['MongoCursor', 'ms'=>'int'], 'MongoCursor::next' => ['array'], 'MongoCursor::partial' => ['MongoCursor', 'okay='=>'bool'], 'MongoCursor::reset' => ['void'], 'MongoCursor::rewind' => ['void'], 'MongoCursor::setFlag' => ['MongoCursor', 'flag'=>'int', 'set='=>'bool'], 'MongoCursor::setReadPreference' => ['MongoCursor', 'read_preference'=>'string', 'tags='=>'array'], 'MongoCursor::skip' => ['MongoCursor', 'num'=>'int'], 'MongoCursor::slaveOkay' => ['MongoCursor', 'okay='=>'bool'], 'MongoCursor::snapshot' => ['MongoCursor'], 'MongoCursor::sort' => ['MongoCursor', 'fields'=>'array'], 'MongoCursor::tailable' => ['MongoCursor', 'tail='=>'bool'], 'MongoCursor::timeout' => ['MongoCursor', 'ms'=>'int'], 'MongoCursor::valid' => ['bool'], 'MongoCursorException::__clone' => ['void'], 'MongoCursorException::__construct' => ['void', 'message='=>'string', 'code='=>'int', 'previous='=>'?Exception|?Throwable'], 'MongoCursorException::__toString' => ['string'], 'MongoCursorException::__wakeup' => ['void'], 'MongoCursorException::getCode' => ['int'], 'MongoCursorException::getFile' => ['string'], 'MongoCursorException::getHost' => ['string'], 'MongoCursorException::getLine' => ['int'], 'MongoCursorException::getMessage' => ['string'], 'MongoCursorException::getPrevious' => ['Exception|Throwable'], 'MongoCursorException::getTrace' => ['list\',args?:array}>'], 'MongoCursorException::getTraceAsString' => ['string'], 'MongoCursorInterface::__construct' => ['void'], 'MongoCursorInterface::batchSize' => ['MongoCursorInterface', 'batchSize'=>'int'], 'MongoCursorInterface::current' => ['mixed'], 'MongoCursorInterface::dead' => ['bool'], 'MongoCursorInterface::getReadPreference' => ['array'], 'MongoCursorInterface::info' => ['array'], 'MongoCursorInterface::key' => ['int|string'], 'MongoCursorInterface::next' => ['void'], 'MongoCursorInterface::rewind' => ['void'], 'MongoCursorInterface::setReadPreference' => ['MongoCursorInterface', 'read_preference'=>'string', 'tags='=>'array'], 'MongoCursorInterface::timeout' => ['MongoCursorInterface', 'ms'=>'int'], 'MongoCursorInterface::valid' => ['bool'], 'MongoDB::__construct' => ['void', 'conn'=>'MongoClient', 'name'=>'string'], 'MongoDB::__get' => ['MongoCollection', 'name'=>'string'], 'MongoDB::__toString' => ['string'], 'MongoDB::authenticate' => ['array', 'username'=>'string', 'password'=>'string'], 'MongoDB::command' => ['array', 'command'=>'array'], 'MongoDB::createCollection' => ['MongoCollection', 'name'=>'string', 'capped='=>'bool', 'size='=>'int', 'max='=>'int'], 'MongoDB::createDBRef' => ['array', 'collection'=>'string', 'a'=>'mixed'], 'MongoDB::drop' => ['array'], 'MongoDB::dropCollection' => ['array', 'coll'=>'MongoCollection|string'], 'MongoDB::execute' => ['array', 'code'=>'MongoCode|string', 'args='=>'array'], 'MongoDB::forceError' => ['bool'], 'MongoDB::getCollectionInfo' => ['array', 'options='=>'array'], 'MongoDB::getCollectionNames' => ['array', 'options='=>'array'], 'MongoDB::getDBRef' => ['array', 'ref'=>'array'], 'MongoDB::getGridFS' => ['MongoGridFS', 'prefix='=>'string'], 'MongoDB::getProfilingLevel' => ['int'], 'MongoDB::getReadPreference' => ['array'], 'MongoDB::getSlaveOkay' => ['bool'], 'MongoDB::getWriteConcern' => ['array'], 'MongoDB::lastError' => ['array'], 'MongoDB::listCollections' => ['array'], 'MongoDB::prevError' => ['array'], 'MongoDB::repair' => ['array', 'preserve_cloned_files='=>'bool', 'backup_original_files='=>'bool'], 'MongoDB::resetError' => ['array'], 'MongoDB::selectCollection' => ['MongoCollection', 'name'=>'string'], 'MongoDB::setProfilingLevel' => ['int', 'level'=>'int'], 'MongoDB::setReadPreference' => ['bool', 'read_preference'=>'string', 'tags='=>'array'], 'MongoDB::setSlaveOkay' => ['bool', 'ok='=>'bool'], 'MongoDB::setWriteConcern' => ['bool', 'w'=>'mixed', 'wtimeout='=>'int'], 'MongoDBRef::create' => ['array', 'collection'=>'string', 'id'=>'mixed', 'database='=>'string'], 'MongoDBRef::get' => ['?array', 'db'=>'MongoDB', 'ref'=>'array'], 'MongoDBRef::isRef' => ['bool', 'ref'=>'mixed'], 'MongoDB\BSON\fromJSON' => ['string', 'json' => 'string'], 'MongoDB\BSON\fromPHP' => ['string', 'value' => 'object|array'], 'MongoDB\BSON\toCanonicalExtendedJSON' => ['string', 'bson' => 'string'], 'MongoDB\BSON\toJSON' => ['string', 'bson' => 'string'], 'MongoDB\BSON\toPHP' => ['object|array', 'bson' => 'string', 'typemap=' => '?array'], 'MongoDB\BSON\toRelaxedExtendedJSON' => ['string', 'bson' => 'string'], 'MongoDB\Driver\Monitoring\addSubscriber' => ['void', 'subscriber' => 'MongoDB\Driver\Monitoring\Subscriber'], 'MongoDB\Driver\Monitoring\removeSubscriber' => ['void', 'subscriber' => 'MongoDB\Driver\Monitoring\Subscriber'], 'MongoDB\BSON\Binary::__construct' => ['void', 'data' => 'string', 'type=' => 'int'], 'MongoDB\BSON\Binary::getData' => ['string'], 'MongoDB\BSON\Binary::getType' => ['int'], 'MongoDB\BSON\Binary::__toString' => ['string'], 'MongoDB\BSON\Binary::serialize' => ['string'], 'MongoDB\BSON\Binary::unserialize' => ['void', 'data' => 'string'], 'MongoDB\BSON\Binary::jsonSerialize' => ['mixed'], 'MongoDB\BSON\BinaryInterface::getData' => ['string'], 'MongoDB\BSON\BinaryInterface::getType' => ['int'], 'MongoDB\BSON\BinaryInterface::__toString' => ['string'], 'MongoDB\BSON\DBPointer::__toString' => ['string'], 'MongoDB\BSON\DBPointer::serialize' => ['string'], 'MongoDB\BSON\DBPointer::unserialize' => ['void', 'data' => 'string'], 'MongoDB\BSON\DBPointer::jsonSerialize' => ['mixed'], 'MongoDB\BSON\Decimal128::__construct' => ['void', 'value' => 'string'], 'MongoDB\BSON\Decimal128::__toString' => ['string'], 'MongoDB\BSON\Decimal128::serialize' => ['string'], 'MongoDB\BSON\Decimal128::unserialize' => ['void', 'data' => 'string'], 'MongoDB\BSON\Decimal128::jsonSerialize' => ['mixed'], 'MongoDB\BSON\Decimal128Interface::__toString' => ['string'], 'MongoDB\BSON\Document::fromBSON' => ['MongoDB\BSON\Document', 'bson' => 'string'], 'MongoDB\BSON\Document::fromJSON' => ['MongoDB\BSON\Document', 'json' => 'string'], 'MongoDB\BSON\Document::fromPHP' => ['MongoDB\BSON\Document', 'value' => 'object|array'], 'MongoDB\BSON\Document::get' => ['mixed', 'key' => 'string'], 'MongoDB\BSON\Document::getIterator' => ['MongoDB\BSON\Iterator'], 'MongoDB\BSON\Document::has' => ['bool', 'key' => 'string'], 'MongoDB\BSON\Document::toPHP' => ['object|array', 'typeMap=' => '?array'], 'MongoDB\BSON\Document::toCanonicalExtendedJSON' => ['string'], 'MongoDB\BSON\Document::toRelaxedExtendedJSON' => ['string'], 'MongoDB\BSON\Document::offsetExists' => ['bool', 'offset' => 'mixed'], 'MongoDB\BSON\Document::offsetGet' => ['mixed', 'offset' => 'mixed'], 'MongoDB\BSON\Document::offsetSet' => ['void', 'offset' => 'mixed', 'value' => 'mixed'], 'MongoDB\BSON\Document::offsetUnset' => ['void', 'offset' => 'mixed'], 'MongoDB\BSON\Document::__toString' => ['string'], 'MongoDB\BSON\Document::serialize' => ['string'], 'MongoDB\BSON\Document::unserialize' => ['void', 'data' => 'string'], 'MongoDB\BSON\Int64::__construct' => ['void', 'value' => 'string|int'], 'MongoDB\BSON\Int64::__toString' => ['string'], 'MongoDB\BSON\Int64::serialize' => ['string'], 'MongoDB\BSON\Int64::unserialize' => ['void', 'data' => 'string'], 'MongoDB\BSON\Int64::jsonSerialize' => ['mixed'], 'MongoDB\BSON\Iterator::current' => ['mixed'], 'MongoDB\BSON\Iterator::key' => ['string|int'], 'MongoDB\BSON\Iterator::next' => ['void'], 'MongoDB\BSON\Iterator::rewind' => ['void'], 'MongoDB\BSON\Iterator::valid' => ['bool'], 'MongoDB\BSON\Javascript::__construct' => ['void', 'code' => 'string', 'scope=' => 'object|array|null'], 'MongoDB\BSON\Javascript::getCode' => ['string'], 'MongoDB\BSON\Javascript::getScope' => ['?object'], 'MongoDB\BSON\Javascript::__toString' => ['string'], 'MongoDB\BSON\Javascript::serialize' => ['string'], 'MongoDB\BSON\Javascript::unserialize' => ['void', 'data' => 'string'], 'MongoDB\BSON\Javascript::jsonSerialize' => ['mixed'], 'MongoDB\BSON\JavascriptInterface::getCode' => ['string'], 'MongoDB\BSON\JavascriptInterface::getScope' => ['?object'], 'MongoDB\BSON\JavascriptInterface::__toString' => ['string'], 'MongoDB\BSON\MaxKey::serialize' => ['string'], 'MongoDB\BSON\MaxKey::unserialize' => ['void', 'data' => 'string'], 'MongoDB\BSON\MaxKey::jsonSerialize' => ['mixed'], 'MongoDB\BSON\MinKey::serialize' => ['string'], 'MongoDB\BSON\MinKey::unserialize' => ['void', 'data' => 'string'], 'MongoDB\BSON\MinKey::jsonSerialize' => ['mixed'], 'MongoDB\BSON\ObjectId::__construct' => ['void', 'id=' => '?string'], 'MongoDB\BSON\ObjectId::getTimestamp' => ['int'], 'MongoDB\BSON\ObjectId::__toString' => ['string'], 'MongoDB\BSON\ObjectId::serialize' => ['string'], 'MongoDB\BSON\ObjectId::unserialize' => ['void', 'data' => 'string'], 'MongoDB\BSON\ObjectId::jsonSerialize' => ['mixed'], 'MongoDB\BSON\ObjectIdInterface::getTimestamp' => ['int'], 'MongoDB\BSON\ObjectIdInterface::__toString' => ['string'], 'MongoDB\BSON\PackedArray::fromPHP' => ['MongoDB\BSON\PackedArray', 'value' => 'array'], 'MongoDB\BSON\PackedArray::get' => ['mixed', 'index' => 'int'], 'MongoDB\BSON\PackedArray::getIterator' => ['MongoDB\BSON\Iterator'], 'MongoDB\BSON\PackedArray::has' => ['bool', 'index' => 'int'], 'MongoDB\BSON\PackedArray::toPHP' => ['object|array', 'typeMap=' => '?array'], 'MongoDB\BSON\PackedArray::offsetExists' => ['bool', 'offset' => 'mixed'], 'MongoDB\BSON\PackedArray::offsetGet' => ['mixed', 'offset' => 'mixed'], 'MongoDB\BSON\PackedArray::offsetSet' => ['void', 'offset' => 'mixed', 'value' => 'mixed'], 'MongoDB\BSON\PackedArray::offsetUnset' => ['void', 'offset' => 'mixed'], 'MongoDB\BSON\PackedArray::__toString' => ['string'], 'MongoDB\BSON\PackedArray::serialize' => ['string'], 'MongoDB\BSON\PackedArray::unserialize' => ['void', 'data' => 'string'], 'MongoDB\BSON\Persistable::bsonSerialize' => ['stdClass|MongoDB\BSON\Document|array'], 'MongoDB\BSON\Regex::__construct' => ['void', 'pattern' => 'string', 'flags=' => 'string'], 'MongoDB\BSON\Regex::getPattern' => ['string'], 'MongoDB\BSON\Regex::getFlags' => ['string'], 'MongoDB\BSON\Regex::__toString' => ['string'], 'MongoDB\BSON\Regex::serialize' => ['string'], 'MongoDB\BSON\Regex::unserialize' => ['void', 'data' => 'string'], 'MongoDB\BSON\Regex::jsonSerialize' => ['mixed'], 'MongoDB\BSON\RegexInterface::getPattern' => ['string'], 'MongoDB\BSON\RegexInterface::getFlags' => ['string'], 'MongoDB\BSON\RegexInterface::__toString' => ['string'], 'MongoDB\BSON\Serializable::bsonSerialize' => ['stdClass|MongoDB\BSON\Document|MongoDB\BSON\PackedArray|array'], 'MongoDB\BSON\Symbol::__toString' => ['string'], 'MongoDB\BSON\Symbol::serialize' => ['string'], 'MongoDB\BSON\Symbol::unserialize' => ['void', 'data' => 'string'], 'MongoDB\BSON\Symbol::jsonSerialize' => ['mixed'], 'MongoDB\BSON\Timestamp::__construct' => ['void', 'increment' => 'string|int', 'timestamp' => 'string|int'], 'MongoDB\BSON\Timestamp::getTimestamp' => ['int'], 'MongoDB\BSON\Timestamp::getIncrement' => ['int'], 'MongoDB\BSON\Timestamp::__toString' => ['string'], 'MongoDB\BSON\Timestamp::serialize' => ['string'], 'MongoDB\BSON\Timestamp::unserialize' => ['void', 'data' => 'string'], 'MongoDB\BSON\Timestamp::jsonSerialize' => ['mixed'], 'MongoDB\BSON\TimestampInterface::getTimestamp' => ['int'], 'MongoDB\BSON\TimestampInterface::getIncrement' => ['int'], 'MongoDB\BSON\TimestampInterface::__toString' => ['string'], 'MongoDB\BSON\UTCDateTime::__construct' => ['void', 'milliseconds=' => 'DateTimeInterface|string|int|float|null'], 'MongoDB\BSON\UTCDateTime::toDateTime' => ['DateTime'], 'MongoDB\BSON\UTCDateTime::__toString' => ['string'], 'MongoDB\BSON\UTCDateTime::serialize' => ['string'], 'MongoDB\BSON\UTCDateTime::unserialize' => ['void', 'data' => 'string'], 'MongoDB\BSON\UTCDateTime::jsonSerialize' => ['mixed'], 'MongoDB\BSON\UTCDateTimeInterface::toDateTime' => ['DateTime'], 'MongoDB\BSON\UTCDateTimeInterface::__toString' => ['string'], 'MongoDB\BSON\Undefined::__toString' => ['string'], 'MongoDB\BSON\Undefined::serialize' => ['string'], 'MongoDB\BSON\Undefined::unserialize' => ['void', 'data' => 'string'], 'MongoDB\BSON\Undefined::jsonSerialize' => ['mixed'], 'MongoDB\BSON\Unserializable::bsonUnserialize' => ['void', 'data' => 'array'], 'MongoDB\Driver\BulkWrite::__construct' => ['void', 'options=' => '?array'], 'MongoDB\Driver\BulkWrite::count' => ['int'], 'MongoDB\Driver\BulkWrite::delete' => ['void', 'filter' => 'object|array', 'deleteOptions=' => '?array'], 'MongoDB\Driver\BulkWrite::insert' => ['mixed', 'document' => 'object|array'], 'MongoDB\Driver\BulkWrite::update' => ['void', 'filter' => 'object|array', 'newObj' => 'object|array', 'updateOptions=' => '?array'], 'MongoDB\Driver\ClientEncryption::__construct' => ['void', 'options' => 'array'], 'MongoDB\Driver\ClientEncryption::addKeyAltName' => ['?object', 'keyId' => 'MongoDB\BSON\Binary', 'keyAltName' => 'string'], 'MongoDB\Driver\ClientEncryption::createDataKey' => ['MongoDB\BSON\Binary', 'kmsProvider' => 'string', 'options=' => '?array'], 'MongoDB\Driver\ClientEncryption::decrypt' => ['mixed', 'value' => 'MongoDB\BSON\Binary'], 'MongoDB\Driver\ClientEncryption::deleteKey' => ['object', 'keyId' => 'MongoDB\BSON\Binary'], 'MongoDB\Driver\ClientEncryption::encrypt' => ['MongoDB\BSON\Binary', 'value' => 'mixed', 'options=' => '?array'], 'MongoDB\Driver\ClientEncryption::encryptExpression' => ['object', 'expr' => 'object|array', 'options=' => '?array'], 'MongoDB\Driver\ClientEncryption::getKey' => ['?object', 'keyId' => 'MongoDB\BSON\Binary'], 'MongoDB\Driver\ClientEncryption::getKeyByAltName' => ['?object', 'keyAltName' => 'string'], 'MongoDB\Driver\ClientEncryption::getKeys' => ['MongoDB\Driver\Cursor'], 'MongoDB\Driver\ClientEncryption::removeKeyAltName' => ['?object', 'keyId' => 'MongoDB\BSON\Binary', 'keyAltName' => 'string'], 'MongoDB\Driver\ClientEncryption::rewrapManyDataKey' => ['object', 'filter' => 'object|array', 'options=' => '?array'], 'MongoDB\Driver\Command::__construct' => ['void', 'document' => 'object|array', 'commandOptions=' => '?array'], 'MongoDB\Driver\Cursor::current' => ['object|array|null'], 'MongoDB\Driver\Cursor::getId' => ['MongoDB\Driver\CursorId'], 'MongoDB\Driver\Cursor::getServer' => ['MongoDB\Driver\Server'], 'MongoDB\Driver\Cursor::isDead' => ['bool'], 'MongoDB\Driver\Cursor::key' => ['?int'], 'MongoDB\Driver\Cursor::next' => ['void'], 'MongoDB\Driver\Cursor::rewind' => ['void'], 'MongoDB\Driver\Cursor::setTypeMap' => ['void', 'typemap' => 'array'], 'MongoDB\Driver\Cursor::toArray' => ['array'], 'MongoDB\Driver\Cursor::valid' => ['bool'], 'MongoDB\Driver\CursorId::__toString' => ['string'], 'MongoDB\Driver\CursorId::serialize' => ['string'], 'MongoDB\Driver\CursorId::unserialize' => ['void', 'data' => 'string'], 'MongoDB\Driver\CursorInterface::getId' => ['MongoDB\Driver\CursorId'], 'MongoDB\Driver\CursorInterface::getServer' => ['MongoDB\Driver\Server'], 'MongoDB\Driver\CursorInterface::isDead' => ['bool'], 'MongoDB\Driver\CursorInterface::setTypeMap' => ['void', 'typemap' => 'array'], 'MongoDB\Driver\CursorInterface::toArray' => ['array'], 'MongoDB\Driver\Exception\AuthenticationException::__toString' => ['string'], 'MongoDB\Driver\Exception\BulkWriteException::__toString' => ['string'], 'MongoDB\Driver\Exception\CommandException::getResultDocument' => ['object'], 'MongoDB\Driver\Exception\CommandException::__toString' => ['string'], 'MongoDB\Driver\Exception\ConnectionException::__toString' => ['string'], 'MongoDB\Driver\Exception\ConnectionTimeoutException::__toString' => ['string'], 'MongoDB\Driver\Exception\EncryptionException::__toString' => ['string'], 'MongoDB\Driver\Exception\Exception::__toString' => ['string'], 'MongoDB\Driver\Exception\ExecutionTimeoutException::__toString' => ['string'], 'MongoDB\Driver\Exception\InvalidArgumentException::__toString' => ['string'], 'MongoDB\Driver\Exception\LogicException::__toString' => ['string'], 'MongoDB\Driver\Exception\RuntimeException::hasErrorLabel' => ['bool', 'errorLabel' => 'string'], 'MongoDB\Driver\Exception\RuntimeException::__toString' => ['string'], 'MongoDB\Driver\Exception\SSLConnectionException::__toString' => ['string'], 'MongoDB\Driver\Exception\ServerException::__toString' => ['string'], 'MongoDB\Driver\Exception\UnexpectedValueException::__toString' => ['string'], 'MongoDB\Driver\Exception\WriteException::getWriteResult' => ['MongoDB\Driver\WriteResult'], 'MongoDB\Driver\Exception\WriteException::__toString' => ['string'], 'MongoDB\Driver\Manager::__construct' => ['void', 'uri=' => '?string', 'uriOptions=' => '?array', 'driverOptions=' => '?array'], 'MongoDB\Driver\Manager::addSubscriber' => ['void', 'subscriber' => 'MongoDB\Driver\Monitoring\Subscriber'], 'MongoDB\Driver\Manager::createClientEncryption' => ['MongoDB\Driver\ClientEncryption', 'options' => 'array'], 'MongoDB\Driver\Manager::executeBulkWrite' => ['MongoDB\Driver\WriteResult', 'namespace' => 'string', 'bulk' => 'MongoDB\Driver\BulkWrite', 'options=' => 'MongoDB\Driver\WriteConcern|array|null'], 'MongoDB\Driver\Manager::executeCommand' => ['MongoDB\Driver\Cursor', 'db' => 'string', 'command' => 'MongoDB\Driver\Command', 'options=' => 'MongoDB\Driver\ReadPreference|array|null'], 'MongoDB\Driver\Manager::executeQuery' => ['MongoDB\Driver\Cursor', 'namespace' => 'string', 'query' => 'MongoDB\Driver\Query', 'options=' => 'MongoDB\Driver\ReadPreference|array|null'], 'MongoDB\Driver\Manager::executeReadCommand' => ['MongoDB\Driver\Cursor', 'db' => 'string', 'command' => 'MongoDB\Driver\Command', 'options=' => '?array'], 'MongoDB\Driver\Manager::executeReadWriteCommand' => ['MongoDB\Driver\Cursor', 'db' => 'string', 'command' => 'MongoDB\Driver\Command', 'options=' => '?array'], 'MongoDB\Driver\Manager::executeWriteCommand' => ['MongoDB\Driver\Cursor', 'db' => 'string', 'command' => 'MongoDB\Driver\Command', 'options=' => '?array'], 'MongoDB\Driver\Manager::getEncryptedFieldsMap' => ['object|array|null'], 'MongoDB\Driver\Manager::getReadConcern' => ['MongoDB\Driver\ReadConcern'], 'MongoDB\Driver\Manager::getReadPreference' => ['MongoDB\Driver\ReadPreference'], 'MongoDB\Driver\Manager::getServers' => ['array'], 'MongoDB\Driver\Manager::getWriteConcern' => ['MongoDB\Driver\WriteConcern'], 'MongoDB\Driver\Manager::removeSubscriber' => ['void', 'subscriber' => 'MongoDB\Driver\Monitoring\Subscriber'], 'MongoDB\Driver\Manager::selectServer' => ['MongoDB\Driver\Server', 'readPreference=' => '?MongoDB\Driver\ReadPreference'], 'MongoDB\Driver\Manager::startSession' => ['MongoDB\Driver\Session', 'options=' => '?array'], 'MongoDB\Driver\Monitoring\CommandFailedEvent::getCommandName' => ['string'], 'MongoDB\Driver\Monitoring\CommandFailedEvent::getDurationMicros' => ['int'], 'MongoDB\Driver\Monitoring\CommandFailedEvent::getError' => ['Exception'], 'MongoDB\Driver\Monitoring\CommandFailedEvent::getOperationId' => ['string'], 'MongoDB\Driver\Monitoring\CommandFailedEvent::getReply' => ['object'], 'MongoDB\Driver\Monitoring\CommandFailedEvent::getRequestId' => ['string'], 'MongoDB\Driver\Monitoring\CommandFailedEvent::getServer' => ['MongoDB\Driver\Server'], 'MongoDB\Driver\Monitoring\CommandFailedEvent::getServiceId' => ['?MongoDB\BSON\ObjectId'], 'MongoDB\Driver\Monitoring\CommandFailedEvent::getServerConnectionId' => ['?int'], 'MongoDB\Driver\Monitoring\CommandStartedEvent::getCommand' => ['object'], 'MongoDB\Driver\Monitoring\CommandStartedEvent::getCommandName' => ['string'], 'MongoDB\Driver\Monitoring\CommandStartedEvent::getDatabaseName' => ['string'], 'MongoDB\Driver\Monitoring\CommandStartedEvent::getOperationId' => ['string'], 'MongoDB\Driver\Monitoring\CommandStartedEvent::getRequestId' => ['string'], 'MongoDB\Driver\Monitoring\CommandStartedEvent::getServer' => ['MongoDB\Driver\Server'], 'MongoDB\Driver\Monitoring\CommandStartedEvent::getServiceId' => ['?MongoDB\BSON\ObjectId'], 'MongoDB\Driver\Monitoring\CommandStartedEvent::getServerConnectionId' => ['?int'], 'MongoDB\Driver\Monitoring\CommandSubscriber::commandStarted' => ['void', 'event' => 'MongoDB\Driver\Monitoring\CommandStartedEvent'], 'MongoDB\Driver\Monitoring\CommandSubscriber::commandSucceeded' => ['void', 'event' => 'MongoDB\Driver\Monitoring\CommandSucceededEvent'], 'MongoDB\Driver\Monitoring\CommandSubscriber::commandFailed' => ['void', 'event' => 'MongoDB\Driver\Monitoring\CommandFailedEvent'], 'MongoDB\Driver\Monitoring\CommandSucceededEvent::getCommandName' => ['string'], 'MongoDB\Driver\Monitoring\CommandSucceededEvent::getDurationMicros' => ['int'], 'MongoDB\Driver\Monitoring\CommandSucceededEvent::getOperationId' => ['string'], 'MongoDB\Driver\Monitoring\CommandSucceededEvent::getReply' => ['object'], 'MongoDB\Driver\Monitoring\CommandSucceededEvent::getRequestId' => ['string'], 'MongoDB\Driver\Monitoring\CommandSucceededEvent::getServer' => ['MongoDB\Driver\Server'], 'MongoDB\Driver\Monitoring\CommandSucceededEvent::getServiceId' => ['?MongoDB\BSON\ObjectId'], 'MongoDB\Driver\Monitoring\CommandSucceededEvent::getServerConnectionId' => ['?int'], 'MongoDB\Driver\Monitoring\LogSubscriber::log' => ['void', 'level' => 'int', 'domain' => 'string', 'message' => 'string'], 'MongoDB\Driver\Monitoring\SDAMSubscriber::serverChanged' => ['void', 'event' => 'MongoDB\Driver\Monitoring\ServerChangedEvent'], 'MongoDB\Driver\Monitoring\SDAMSubscriber::serverClosed' => ['void', 'event' => 'MongoDB\Driver\Monitoring\ServerClosedEvent'], 'MongoDB\Driver\Monitoring\SDAMSubscriber::serverOpening' => ['void', 'event' => 'MongoDB\Driver\Monitoring\ServerOpeningEvent'], 'MongoDB\Driver\Monitoring\SDAMSubscriber::serverHeartbeatFailed' => ['void', 'event' => 'MongoDB\Driver\Monitoring\ServerHeartbeatFailedEvent'], 'MongoDB\Driver\Monitoring\SDAMSubscriber::serverHeartbeatStarted' => ['void', 'event' => 'MongoDB\Driver\Monitoring\ServerHeartbeatStartedEvent'], 'MongoDB\Driver\Monitoring\SDAMSubscriber::serverHeartbeatSucceeded' => ['void', 'event' => 'MongoDB\Driver\Monitoring\ServerHeartbeatSucceededEvent'], 'MongoDB\Driver\Monitoring\SDAMSubscriber::topologyChanged' => ['void', 'event' => 'MongoDB\Driver\Monitoring\TopologyChangedEvent'], 'MongoDB\Driver\Monitoring\SDAMSubscriber::topologyClosed' => ['void', 'event' => 'MongoDB\Driver\Monitoring\TopologyClosedEvent'], 'MongoDB\Driver\Monitoring\SDAMSubscriber::topologyOpening' => ['void', 'event' => 'MongoDB\Driver\Monitoring\TopologyOpeningEvent'], 'MongoDB\Driver\Monitoring\ServerChangedEvent::getPort' => ['int'], 'MongoDB\Driver\Monitoring\ServerChangedEvent::getHost' => ['string'], 'MongoDB\Driver\Monitoring\ServerChangedEvent::getNewDescription' => ['MongoDB\Driver\ServerDescription'], 'MongoDB\Driver\Monitoring\ServerChangedEvent::getPreviousDescription' => ['MongoDB\Driver\ServerDescription'], 'MongoDB\Driver\Monitoring\ServerChangedEvent::getTopologyId' => ['MongoDB\BSON\ObjectId'], 'MongoDB\Driver\Monitoring\ServerClosedEvent::getPort' => ['int'], 'MongoDB\Driver\Monitoring\ServerClosedEvent::getHost' => ['string'], 'MongoDB\Driver\Monitoring\ServerClosedEvent::getTopologyId' => ['MongoDB\BSON\ObjectId'], 'MongoDB\Driver\Monitoring\ServerHeartbeatFailedEvent::getDurationMicros' => ['int'], 'MongoDB\Driver\Monitoring\ServerHeartbeatFailedEvent::getError' => ['Exception'], 'MongoDB\Driver\Monitoring\ServerHeartbeatFailedEvent::getPort' => ['int'], 'MongoDB\Driver\Monitoring\ServerHeartbeatFailedEvent::getHost' => ['string'], 'MongoDB\Driver\Monitoring\ServerHeartbeatFailedEvent::isAwaited' => ['bool'], 'MongoDB\Driver\Monitoring\ServerHeartbeatStartedEvent::getPort' => ['int'], 'MongoDB\Driver\Monitoring\ServerHeartbeatStartedEvent::getHost' => ['string'], 'MongoDB\Driver\Monitoring\ServerHeartbeatStartedEvent::isAwaited' => ['bool'], 'MongoDB\Driver\Monitoring\ServerHeartbeatSucceededEvent::getDurationMicros' => ['int'], 'MongoDB\Driver\Monitoring\ServerHeartbeatSucceededEvent::getReply' => ['object'], 'MongoDB\Driver\Monitoring\ServerHeartbeatSucceededEvent::getPort' => ['int'], 'MongoDB\Driver\Monitoring\ServerHeartbeatSucceededEvent::getHost' => ['string'], 'MongoDB\Driver\Monitoring\ServerHeartbeatSucceededEvent::isAwaited' => ['bool'], 'MongoDB\Driver\Monitoring\ServerOpeningEvent::getPort' => ['int'], 'MongoDB\Driver\Monitoring\ServerOpeningEvent::getHost' => ['string'], 'MongoDB\Driver\Monitoring\ServerOpeningEvent::getTopologyId' => ['MongoDB\BSON\ObjectId'], 'MongoDB\Driver\Monitoring\TopologyChangedEvent::getNewDescription' => ['MongoDB\Driver\TopologyDescription'], 'MongoDB\Driver\Monitoring\TopologyChangedEvent::getPreviousDescription' => ['MongoDB\Driver\TopologyDescription'], 'MongoDB\Driver\Monitoring\TopologyChangedEvent::getTopologyId' => ['MongoDB\BSON\ObjectId'], 'MongoDB\Driver\Monitoring\TopologyClosedEvent::getTopologyId' => ['MongoDB\BSON\ObjectId'], 'MongoDB\Driver\Monitoring\TopologyOpeningEvent::getTopologyId' => ['MongoDB\BSON\ObjectId'], 'MongoDB\Driver\Query::__construct' => ['void', 'filter' => 'object|array', 'queryOptions=' => '?array'], 'MongoDB\Driver\ReadConcern::__construct' => ['void', 'level=' => '?string'], 'MongoDB\Driver\ReadConcern::getLevel' => ['?string'], 'MongoDB\Driver\ReadConcern::isDefault' => ['bool'], 'MongoDB\Driver\ReadConcern::bsonSerialize' => ['stdClass'], 'MongoDB\Driver\ReadConcern::serialize' => ['string'], 'MongoDB\Driver\ReadConcern::unserialize' => ['void', 'data' => 'string'], 'MongoDB\Driver\ReadPreference::__construct' => ['void', 'mode' => 'string|int', 'tagSets=' => '?array', 'options=' => '?array'], 'MongoDB\Driver\ReadPreference::getHedge' => ['?object'], 'MongoDB\Driver\ReadPreference::getMaxStalenessSeconds' => ['int'], 'MongoDB\Driver\ReadPreference::getMode' => ['int'], 'MongoDB\Driver\ReadPreference::getModeString' => ['string'], 'MongoDB\Driver\ReadPreference::getTagSets' => ['array'], 'MongoDB\Driver\ReadPreference::bsonSerialize' => ['stdClass'], 'MongoDB\Driver\ReadPreference::serialize' => ['string'], 'MongoDB\Driver\ReadPreference::unserialize' => ['void', 'data' => 'string'], 'MongoDB\Driver\Server::executeBulkWrite' => ['MongoDB\Driver\WriteResult', 'namespace' => 'string', 'bulkWrite' => 'MongoDB\Driver\BulkWrite', 'options=' => 'MongoDB\Driver\WriteConcern|array|null'], 'MongoDB\Driver\Server::executeCommand' => ['MongoDB\Driver\Cursor', 'db' => 'string', 'command' => 'MongoDB\Driver\Command', 'options=' => 'MongoDB\Driver\ReadPreference|array|null'], 'MongoDB\Driver\Server::executeQuery' => ['MongoDB\Driver\Cursor', 'namespace' => 'string', 'query' => 'MongoDB\Driver\Query', 'options=' => 'MongoDB\Driver\ReadPreference|array|null'], 'MongoDB\Driver\Server::executeReadCommand' => ['MongoDB\Driver\Cursor', 'db' => 'string', 'command' => 'MongoDB\Driver\Command', 'options=' => '?array'], 'MongoDB\Driver\Server::executeReadWriteCommand' => ['MongoDB\Driver\Cursor', 'db' => 'string', 'command' => 'MongoDB\Driver\Command', 'options=' => '?array'], 'MongoDB\Driver\Server::executeWriteCommand' => ['MongoDB\Driver\Cursor', 'db' => 'string', 'command' => 'MongoDB\Driver\Command', 'options=' => '?array'], 'MongoDB\Driver\Server::getHost' => ['string'], 'MongoDB\Driver\Server::getInfo' => ['array'], 'MongoDB\Driver\Server::getLatency' => ['?int'], 'MongoDB\Driver\Server::getPort' => ['int'], 'MongoDB\Driver\Server::getServerDescription' => ['MongoDB\Driver\ServerDescription'], 'MongoDB\Driver\Server::getTags' => ['array'], 'MongoDB\Driver\Server::getType' => ['int'], 'MongoDB\Driver\Server::isArbiter' => ['bool'], 'MongoDB\Driver\Server::isHidden' => ['bool'], 'MongoDB\Driver\Server::isPassive' => ['bool'], 'MongoDB\Driver\Server::isPrimary' => ['bool'], 'MongoDB\Driver\Server::isSecondary' => ['bool'], 'MongoDB\Driver\ServerApi::__construct' => ['void', 'version' => 'string', 'strict=' => '?bool', 'deprecationErrors=' => '?bool'], 'MongoDB\Driver\ServerApi::bsonSerialize' => ['stdClass'], 'MongoDB\Driver\ServerApi::serialize' => ['string'], 'MongoDB\Driver\ServerApi::unserialize' => ['void', 'data' => 'string'], 'MongoDB\Driver\ServerDescription::getHelloResponse' => ['array'], 'MongoDB\Driver\ServerDescription::getHost' => ['string'], 'MongoDB\Driver\ServerDescription::getLastUpdateTime' => ['int'], 'MongoDB\Driver\ServerDescription::getPort' => ['int'], 'MongoDB\Driver\ServerDescription::getRoundTripTime' => ['?int'], 'MongoDB\Driver\ServerDescription::getType' => ['string'], 'MongoDB\Driver\Session::abortTransaction' => ['void'], 'MongoDB\Driver\Session::advanceClusterTime' => ['void', 'clusterTime' => 'object|array'], 'MongoDB\Driver\Session::advanceOperationTime' => ['void', 'operationTime' => 'MongoDB\BSON\TimestampInterface'], 'MongoDB\Driver\Session::commitTransaction' => ['void'], 'MongoDB\Driver\Session::endSession' => ['void'], 'MongoDB\Driver\Session::getClusterTime' => ['?object'], 'MongoDB\Driver\Session::getLogicalSessionId' => ['object'], 'MongoDB\Driver\Session::getOperationTime' => ['?MongoDB\BSON\Timestamp'], 'MongoDB\Driver\Session::getServer' => ['?MongoDB\Driver\Server'], 'MongoDB\Driver\Session::getTransactionOptions' => ['?array'], 'MongoDB\Driver\Session::getTransactionState' => ['string'], 'MongoDB\Driver\Session::isDirty' => ['bool'], 'MongoDB\Driver\Session::isInTransaction' => ['bool'], 'MongoDB\Driver\Session::startTransaction' => ['void', 'options=' => '?array'], 'MongoDB\Driver\TopologyDescription::getServers' => ['array'], 'MongoDB\Driver\TopologyDescription::getType' => ['string'], 'MongoDB\Driver\TopologyDescription::hasReadableServer' => ['bool', 'readPreference=' => '?MongoDB\Driver\ReadPreference'], 'MongoDB\Driver\TopologyDescription::hasWritableServer' => ['bool'], 'MongoDB\Driver\WriteConcern::__construct' => ['void', 'w' => 'string|int', 'wtimeout=' => '?int', 'journal=' => '?bool'], 'MongoDB\Driver\WriteConcern::getJournal' => ['?bool'], 'MongoDB\Driver\WriteConcern::getW' => ['string|int|null'], 'MongoDB\Driver\WriteConcern::getWtimeout' => ['int'], 'MongoDB\Driver\WriteConcern::isDefault' => ['bool'], 'MongoDB\Driver\WriteConcern::bsonSerialize' => ['stdClass'], 'MongoDB\Driver\WriteConcern::serialize' => ['string'], 'MongoDB\Driver\WriteConcern::unserialize' => ['void', 'data' => 'string'], 'MongoDB\Driver\WriteConcernError::getCode' => ['int'], 'MongoDB\Driver\WriteConcernError::getInfo' => ['?object'], 'MongoDB\Driver\WriteConcernError::getMessage' => ['string'], 'MongoDB\Driver\WriteError::getCode' => ['int'], 'MongoDB\Driver\WriteError::getIndex' => ['int'], 'MongoDB\Driver\WriteError::getInfo' => ['?object'], 'MongoDB\Driver\WriteError::getMessage' => ['string'], 'MongoDB\Driver\WriteResult::getInsertedCount' => ['?int'], 'MongoDB\Driver\WriteResult::getMatchedCount' => ['?int'], 'MongoDB\Driver\WriteResult::getModifiedCount' => ['?int'], 'MongoDB\Driver\WriteResult::getDeletedCount' => ['?int'], 'MongoDB\Driver\WriteResult::getUpsertedCount' => ['?int'], 'MongoDB\Driver\WriteResult::getServer' => ['MongoDB\Driver\Server'], 'MongoDB\Driver\WriteResult::getUpsertedIds' => ['array'], 'MongoDB\Driver\WriteResult::getWriteConcernError' => ['?MongoDB\Driver\WriteConcernError'], 'MongoDB\Driver\WriteResult::getWriteErrors' => ['array'], 'MongoDB\Driver\WriteResult::getErrorReplies' => ['array'], 'MongoDB\Driver\WriteResult::isAcknowledged' => ['bool'], 'MongoDate::__construct' => ['void', 'second='=>'int', 'usecond='=>'int'], 'MongoDate::__toString' => ['string'], 'MongoDate::toDateTime' => ['DateTime'], 'MongoDeleteBatch::__construct' => ['void', 'collection'=>'MongoCollection', 'write_options='=>'array'], 'MongoException::__clone' => ['void'], 'MongoException::__construct' => ['void', 'message='=>'string', 'code='=>'int', 'previous='=>'?Exception|?Throwable'], 'MongoException::__toString' => ['string'], 'MongoException::__wakeup' => ['void'], 'MongoException::getCode' => ['int'], 'MongoException::getFile' => ['string'], 'MongoException::getLine' => ['int'], 'MongoException::getMessage' => ['string'], 'MongoException::getPrevious' => ['Exception|Throwable'], 'MongoException::getTrace' => ['list\',args?:array}>'], 'MongoException::getTraceAsString' => ['string'], 'MongoGridFS::__construct' => ['void', 'db'=>'MongoDB', 'prefix='=>'string', 'chunks='=>'mixed'], 'MongoGridFS::__get' => ['MongoCollection', 'name'=>'string'], 'MongoGridFS::__toString' => ['string'], 'MongoGridFS::aggregate' => ['array', 'pipeline'=>'array', 'op'=>'array', 'pipelineOperators'=>'array'], 'MongoGridFS::aggregateCursor' => ['MongoCommandCursor', 'pipeline'=>'array', 'options'=>'array'], 'MongoGridFS::batchInsert' => ['mixed', 'a'=>'array', 'options='=>'array'], 'MongoGridFS::count' => ['int', 'query='=>'stdClass|array'], 'MongoGridFS::createDBRef' => ['array', 'a'=>'array'], 'MongoGridFS::createIndex' => ['array', 'keys'=>'array', 'options='=>'array'], 'MongoGridFS::delete' => ['bool', 'id'=>'mixed'], 'MongoGridFS::deleteIndex' => ['array', 'keys'=>'array|string'], 'MongoGridFS::deleteIndexes' => ['array'], 'MongoGridFS::distinct' => ['array|bool', 'key'=>'string', 'query='=>'?array'], 'MongoGridFS::drop' => ['array'], 'MongoGridFS::ensureIndex' => ['bool', 'keys'=>'array', 'options='=>'array'], 'MongoGridFS::find' => ['MongoGridFSCursor', 'query='=>'array', 'fields='=>'array'], 'MongoGridFS::findAndModify' => ['array', 'query'=>'array', 'update='=>'?array', 'fields='=>'?array', 'options='=>'?array'], 'MongoGridFS::findOne' => ['?MongoGridFSFile', 'query='=>'mixed', 'fields='=>'mixed'], 'MongoGridFS::get' => ['?MongoGridFSFile', 'id'=>'mixed'], 'MongoGridFS::getDBRef' => ['array', 'ref'=>'array'], 'MongoGridFS::getIndexInfo' => ['array'], 'MongoGridFS::getName' => ['string'], 'MongoGridFS::getReadPreference' => ['array'], 'MongoGridFS::getSlaveOkay' => ['bool'], 'MongoGridFS::group' => ['array', 'keys'=>'mixed', 'initial'=>'array', 'reduce'=>'MongoCode', 'condition='=>'array'], 'MongoGridFS::insert' => ['array|bool', 'a'=>'array|object', 'options='=>'array'], 'MongoGridFS::put' => ['mixed', 'filename'=>'string', 'extra='=>'array'], 'MongoGridFS::remove' => ['bool', 'criteria='=>'array', 'options='=>'array'], 'MongoGridFS::save' => ['array|bool', 'a'=>'array|object', 'options='=>'array'], 'MongoGridFS::setReadPreference' => ['bool', 'read_preference'=>'string', 'tags'=>'array'], 'MongoGridFS::setSlaveOkay' => ['bool', 'ok='=>'bool'], 'MongoGridFS::storeBytes' => ['mixed', 'bytes'=>'string', 'extra='=>'array', 'options='=>'array'], 'MongoGridFS::storeFile' => ['mixed', 'filename'=>'string', 'extra='=>'array', 'options='=>'array'], 'MongoGridFS::storeUpload' => ['mixed', 'name'=>'string', 'filename='=>'string'], 'MongoGridFS::toIndexString' => ['string', 'keys'=>'mixed'], 'MongoGridFS::update' => ['bool', 'criteria'=>'array', 'newobj'=>'array', 'options='=>'array'], 'MongoGridFS::validate' => ['array', 'scan_data='=>'bool'], 'MongoGridFSCursor::__construct' => ['void', 'gridfs'=>'MongoGridFS', 'connection'=>'resource', 'ns'=>'string', 'query'=>'array', 'fields'=>'array'], 'MongoGridFSCursor::addOption' => ['MongoCursor', 'key'=>'string', 'value'=>'mixed'], 'MongoGridFSCursor::awaitData' => ['MongoCursor', 'wait='=>'bool'], 'MongoGridFSCursor::batchSize' => ['MongoCursor', 'batchSize'=>'int'], 'MongoGridFSCursor::count' => ['int', 'all='=>'bool'], 'MongoGridFSCursor::current' => ['MongoGridFSFile'], 'MongoGridFSCursor::dead' => ['bool'], 'MongoGridFSCursor::doQuery' => ['void'], 'MongoGridFSCursor::explain' => ['array'], 'MongoGridFSCursor::fields' => ['MongoCursor', 'f'=>'array'], 'MongoGridFSCursor::getNext' => ['MongoGridFSFile'], 'MongoGridFSCursor::getReadPreference' => ['array'], 'MongoGridFSCursor::hasNext' => ['bool'], 'MongoGridFSCursor::hint' => ['MongoCursor', 'key_pattern'=>'mixed'], 'MongoGridFSCursor::immortal' => ['MongoCursor', 'liveForever='=>'bool'], 'MongoGridFSCursor::info' => ['array'], 'MongoGridFSCursor::key' => ['string'], 'MongoGridFSCursor::limit' => ['MongoCursor', 'num'=>'int'], 'MongoGridFSCursor::maxTimeMS' => ['MongoCursor', 'ms'=>'int'], 'MongoGridFSCursor::next' => ['void'], 'MongoGridFSCursor::partial' => ['MongoCursor', 'okay='=>'bool'], 'MongoGridFSCursor::reset' => ['void'], 'MongoGridFSCursor::rewind' => ['void'], 'MongoGridFSCursor::setFlag' => ['MongoCursor', 'flag'=>'int', 'set='=>'bool'], 'MongoGridFSCursor::setReadPreference' => ['MongoCursor', 'read_preference'=>'string', 'tags'=>'array'], 'MongoGridFSCursor::skip' => ['MongoCursor', 'num'=>'int'], 'MongoGridFSCursor::slaveOkay' => ['MongoCursor', 'okay='=>'bool'], 'MongoGridFSCursor::snapshot' => ['MongoCursor'], 'MongoGridFSCursor::sort' => ['MongoCursor', 'fields'=>'array'], 'MongoGridFSCursor::tailable' => ['MongoCursor', 'tail='=>'bool'], 'MongoGridFSCursor::timeout' => ['MongoCursor', 'ms'=>'int'], 'MongoGridFSCursor::valid' => ['bool'], 'MongoGridFSFile::getBytes' => ['string'], 'MongoGridFSFile::getFilename' => ['string'], 'MongoGridFSFile::getResource' => ['resource'], 'MongoGridFSFile::getSize' => ['int'], 'MongoGridFSFile::write' => ['int', 'filename='=>'string'], 'MongoGridfsFile::__construct' => ['void', 'gridfs'=>'MongoGridFS', 'file'=>'array'], 'MongoId::__construct' => ['void', 'id='=>'string|MongoId'], 'MongoId::__set_state' => ['MongoId', 'props'=>'array'], 'MongoId::__toString' => ['string'], 'MongoId::getHostname' => ['string'], 'MongoId::getInc' => ['int'], 'MongoId::getPID' => ['int'], 'MongoId::getTimestamp' => ['int'], 'MongoId::isValid' => ['bool', 'value'=>'mixed'], 'MongoInsertBatch::__construct' => ['void', 'collection'=>'MongoCollection', 'write_options='=>'array'], 'MongoInt32::__construct' => ['void', 'value'=>'string'], 'MongoInt32::__toString' => ['string'], 'MongoInt64::__construct' => ['void', 'value'=>'string'], 'MongoInt64::__toString' => ['string'], 'MongoLog::getCallback' => ['callable'], 'MongoLog::getLevel' => ['int'], 'MongoLog::getModule' => ['int'], 'MongoLog::setCallback' => ['void', 'log_function'=>'callable'], 'MongoLog::setLevel' => ['void', 'level'=>'int'], 'MongoLog::setModule' => ['void', 'module'=>'int'], 'MongoPool::getSize' => ['int'], 'MongoPool::info' => ['array'], 'MongoPool::setSize' => ['bool', 'size'=>'int'], 'MongoRegex::__construct' => ['void', 'regex'=>'string'], 'MongoRegex::__toString' => ['string'], 'MongoResultException::__clone' => ['void'], 'MongoResultException::__construct' => ['void', 'message='=>'string', 'code='=>'int', 'previous='=>'?Exception|?Throwable'], 'MongoResultException::__toString' => ['string'], 'MongoResultException::__wakeup' => ['void'], 'MongoResultException::getCode' => ['int'], 'MongoResultException::getDocument' => ['array'], 'MongoResultException::getFile' => ['string'], 'MongoResultException::getLine' => ['int'], 'MongoResultException::getMessage' => ['string'], 'MongoResultException::getPrevious' => ['Exception|Throwable'], 'MongoResultException::getTrace' => ['list\',args?:array}>'], 'MongoResultException::getTraceAsString' => ['string'], 'MongoTimestamp::__construct' => ['void', 'second='=>'int', 'inc='=>'int'], 'MongoTimestamp::__toString' => ['string'], 'MongoUpdateBatch::__construct' => ['void', 'collection'=>'MongoCollection', 'write_options='=>'array'], 'MongoUpdateBatch::add' => ['bool', 'item'=>'array'], 'MongoUpdateBatch::execute' => ['array', 'write_options'=>'array'], 'MongoWriteBatch::__construct' => ['void', 'collection'=>'MongoCollection', 'batch_type'=>'string', 'write_options'=>'array'], 'MongoWriteBatch::add' => ['bool', 'item'=>'array'], 'MongoWriteBatch::execute' => ['array', 'write_options'=>'array'], 'MongoWriteConcernException::__clone' => ['void'], 'MongoWriteConcernException::__construct' => ['void', 'message='=>'string', 'code='=>'int', 'previous='=>'?Exception|?Throwable'], 'MongoWriteConcernException::__toString' => ['string'], 'MongoWriteConcernException::__wakeup' => ['void'], 'MongoWriteConcernException::getCode' => ['int'], 'MongoWriteConcernException::getDocument' => ['array'], 'MongoWriteConcernException::getFile' => ['string'], 'MongoWriteConcernException::getLine' => ['int'], 'MongoWriteConcernException::getMessage' => ['string'], 'MongoWriteConcernException::getPrevious' => ['Exception|Throwable'], 'MongoWriteConcernException::getTrace' => ['list\',args?:array}>'], 'MongoWriteConcernException::getTraceAsString' => ['string'], 'MultipleIterator::__construct' => ['void', 'flags='=>'int'], 'MultipleIterator::attachIterator' => ['void', 'iterator'=>'Iterator', 'info='=>'string|int|null'], 'MultipleIterator::containsIterator' => ['bool', 'iterator'=>'Iterator'], 'MultipleIterator::countIterators' => ['int'], 'MultipleIterator::current' => ['array|false'], 'MultipleIterator::detachIterator' => ['void', 'iterator'=>'Iterator'], 'MultipleIterator::getFlags' => ['int'], 'MultipleIterator::key' => ['array'], 'MultipleIterator::next' => ['void'], 'MultipleIterator::rewind' => ['void'], 'MultipleIterator::setFlags' => ['void', 'flags'=>'int'], 'MultipleIterator::valid' => ['bool'], 'Mutex::create' => ['long', 'lock='=>'bool'], 'Mutex::destroy' => ['bool', 'mutex'=>'long'], 'Mutex::lock' => ['bool', 'mutex'=>'long'], 'Mutex::trylock' => ['bool', 'mutex'=>'long'], 'Mutex::unlock' => ['bool', 'mutex'=>'long', 'destroy='=>'bool'], 'MysqlndUhConnection::__construct' => ['void'], 'MysqlndUhConnection::changeUser' => ['bool', 'connection'=>'mysqlnd_connection', 'user'=>'string', 'password'=>'string', 'database'=>'string', 'silent'=>'bool', 'passwd_len'=>'int'], 'MysqlndUhConnection::charsetName' => ['string', 'connection'=>'mysqlnd_connection'], 'MysqlndUhConnection::close' => ['bool', 'connection'=>'mysqlnd_connection', 'close_type'=>'int'], 'MysqlndUhConnection::connect' => ['bool', 'connection'=>'mysqlnd_connection', 'host'=>'string', 'use'=>'string', 'password'=>'string', 'database'=>'string', 'port'=>'int', 'socket'=>'string', 'mysql_flags'=>'int'], 'MysqlndUhConnection::endPSession' => ['bool', 'connection'=>'mysqlnd_connection'], 'MysqlndUhConnection::escapeString' => ['string', 'connection'=>'mysqlnd_connection', 'escape_string'=>'string'], 'MysqlndUhConnection::getAffectedRows' => ['int', 'connection'=>'mysqlnd_connection'], 'MysqlndUhConnection::getErrorNumber' => ['int', 'connection'=>'mysqlnd_connection'], 'MysqlndUhConnection::getErrorString' => ['string', 'connection'=>'mysqlnd_connection'], 'MysqlndUhConnection::getFieldCount' => ['int', 'connection'=>'mysqlnd_connection'], 'MysqlndUhConnection::getHostInformation' => ['string', 'connection'=>'mysqlnd_connection'], 'MysqlndUhConnection::getLastInsertId' => ['int', 'connection'=>'mysqlnd_connection'], 'MysqlndUhConnection::getLastMessage' => ['void', 'connection'=>'mysqlnd_connection'], 'MysqlndUhConnection::getProtocolInformation' => ['string', 'connection'=>'mysqlnd_connection'], 'MysqlndUhConnection::getServerInformation' => ['string', 'connection'=>'mysqlnd_connection'], 'MysqlndUhConnection::getServerStatistics' => ['string', 'connection'=>'mysqlnd_connection'], 'MysqlndUhConnection::getServerVersion' => ['int', 'connection'=>'mysqlnd_connection'], 'MysqlndUhConnection::getSqlstate' => ['string', 'connection'=>'mysqlnd_connection'], 'MysqlndUhConnection::getStatistics' => ['array', 'connection'=>'mysqlnd_connection'], 'MysqlndUhConnection::getThreadId' => ['int', 'connection'=>'mysqlnd_connection'], 'MysqlndUhConnection::getWarningCount' => ['int', 'connection'=>'mysqlnd_connection'], 'MysqlndUhConnection::init' => ['bool', 'connection'=>'mysqlnd_connection'], 'MysqlndUhConnection::killConnection' => ['bool', 'connection'=>'mysqlnd_connection', 'pid'=>'int'], 'MysqlndUhConnection::listFields' => ['array', 'connection'=>'mysqlnd_connection', 'table'=>'string', 'achtung_wild'=>'string'], 'MysqlndUhConnection::listMethod' => ['void', 'connection'=>'mysqlnd_connection', 'query'=>'string', 'achtung_wild'=>'string', 'par1'=>'string'], 'MysqlndUhConnection::moreResults' => ['bool', 'connection'=>'mysqlnd_connection'], 'MysqlndUhConnection::nextResult' => ['bool', 'connection'=>'mysqlnd_connection'], 'MysqlndUhConnection::ping' => ['bool', 'connection'=>'mysqlnd_connection'], 'MysqlndUhConnection::query' => ['bool', 'connection'=>'mysqlnd_connection', 'query'=>'string'], 'MysqlndUhConnection::queryReadResultsetHeader' => ['bool', 'connection'=>'mysqlnd_connection', 'mysqlnd_stmt'=>'mysqlnd_statement'], 'MysqlndUhConnection::reapQuery' => ['bool', 'connection'=>'mysqlnd_connection'], 'MysqlndUhConnection::refreshServer' => ['bool', 'connection'=>'mysqlnd_connection', 'options'=>'int'], 'MysqlndUhConnection::restartPSession' => ['bool', 'connection'=>'mysqlnd_connection'], 'MysqlndUhConnection::selectDb' => ['bool', 'connection'=>'mysqlnd_connection', 'database'=>'string'], 'MysqlndUhConnection::sendClose' => ['bool', 'connection'=>'mysqlnd_connection'], 'MysqlndUhConnection::sendQuery' => ['bool', 'connection'=>'mysqlnd_connection', 'query'=>'string'], 'MysqlndUhConnection::serverDumpDebugInformation' => ['bool', 'connection'=>'mysqlnd_connection'], 'MysqlndUhConnection::setAutocommit' => ['bool', 'connection'=>'mysqlnd_connection', 'mode'=>'int'], 'MysqlndUhConnection::setCharset' => ['bool', 'connection'=>'mysqlnd_connection', 'charset'=>'string'], 'MysqlndUhConnection::setClientOption' => ['bool', 'connection'=>'mysqlnd_connection', 'option'=>'int', 'value'=>'int'], 'MysqlndUhConnection::setServerOption' => ['void', 'connection'=>'mysqlnd_connection', 'option'=>'int'], 'MysqlndUhConnection::shutdownServer' => ['void', 'MYSQLND_UH_RES_MYSQLND_NAME'=>'string', 'level'=>'string'], 'MysqlndUhConnection::simpleCommand' => ['bool', 'connection'=>'mysqlnd_connection', 'command'=>'int', 'arg'=>'string', 'ok_packet'=>'int', 'silent'=>'bool', 'ignore_upsert_status'=>'bool'], 'MysqlndUhConnection::simpleCommandHandleResponse' => ['bool', 'connection'=>'mysqlnd_connection', 'ok_packet'=>'int', 'silent'=>'bool', 'command'=>'int', 'ignore_upsert_status'=>'bool'], 'MysqlndUhConnection::sslSet' => ['bool', 'connection'=>'mysqlnd_connection', 'key'=>'string', 'cert'=>'string', 'ca'=>'string', 'capath'=>'string', 'cipher'=>'string'], 'MysqlndUhConnection::stmtInit' => ['resource', 'connection'=>'mysqlnd_connection'], 'MysqlndUhConnection::storeResult' => ['resource', 'connection'=>'mysqlnd_connection'], 'MysqlndUhConnection::txCommit' => ['bool', 'connection'=>'mysqlnd_connection'], 'MysqlndUhConnection::txRollback' => ['bool', 'connection'=>'mysqlnd_connection'], 'MysqlndUhConnection::useResult' => ['resource', 'connection'=>'mysqlnd_connection'], 'MysqlndUhPreparedStatement::__construct' => ['void'], 'MysqlndUhPreparedStatement::execute' => ['bool', 'statement'=>'mysqlnd_prepared_statement'], 'MysqlndUhPreparedStatement::prepare' => ['bool', 'statement'=>'mysqlnd_prepared_statement', 'query'=>'string'], 'NoRewindIterator::__construct' => ['void', 'iterator'=>'Iterator'], 'NoRewindIterator::current' => ['mixed'], 'NoRewindIterator::getInnerIterator' => ['Iterator'], 'NoRewindIterator::key' => ['mixed'], 'NoRewindIterator::next' => ['void'], 'NoRewindIterator::rewind' => ['void'], 'NoRewindIterator::valid' => ['bool'], 'Normalizer::isNormalized' => ['bool', 'string'=>'string', 'form='=>'int'], 'Normalizer::normalize' => ['string|false', 'string'=>'string', 'form='=>'int'], 'NumberFormatter::__construct' => ['void', 'locale'=>'string', 'style'=>'int', 'pattern='=>'string'], 'NumberFormatter::create' => ['NumberFormatter|null', 'locale'=>'string', 'style'=>'int', 'pattern='=>'string'], 'NumberFormatter::format' => ['string|false', 'num'=>'', 'type='=>'int'], 'NumberFormatter::formatCurrency' => ['string|false', 'amount'=>'float', 'currency'=>'string'], 'NumberFormatter::getAttribute' => ['int|float|false', 'attribute'=>'int'], 'NumberFormatter::getErrorCode' => ['int'], 'NumberFormatter::getErrorMessage' => ['string'], 'NumberFormatter::getLocale' => ['string', 'type='=>'int'], 'NumberFormatter::getPattern' => ['string|false'], 'NumberFormatter::getSymbol' => ['string|false', 'symbol'=>'int'], 'NumberFormatter::getTextAttribute' => ['string|false', 'attribute'=>'int'], 'NumberFormatter::parse' => ['int|float|false', 'string'=>'string', 'type='=>'int', '&rw_offset='=>'int'], 'NumberFormatter::parseCurrency' => ['float|false', 'string'=>'string', '&w_currency'=>'string', '&rw_offset='=>'int'], 'NumberFormatter::setAttribute' => ['bool', 'attribute'=>'int', 'value'=>'int|float'], 'NumberFormatter::setPattern' => ['bool', 'pattern'=>'string'], 'NumberFormatter::setSymbol' => ['bool', 'symbol'=>'int', 'value'=>'string'], 'NumberFormatter::setTextAttribute' => ['bool', 'attribute'=>'int', 'value'=>'string'], 'OAuth::__construct' => ['void', 'consumer_key'=>'string', 'consumer_secret'=>'string', 'signature_method='=>'string', 'auth_type='=>'int'], 'OAuth::disableDebug' => ['bool'], 'OAuth::disableRedirects' => ['bool'], 'OAuth::disableSSLChecks' => ['bool'], 'OAuth::enableDebug' => ['bool'], 'OAuth::enableRedirects' => ['bool'], 'OAuth::enableSSLChecks' => ['bool'], 'OAuth::fetch' => ['mixed', 'protected_resource_url'=>'string', 'extra_parameters='=>'array', 'http_method='=>'string', 'http_headers='=>'array'], 'OAuth::generateSignature' => ['string', 'http_method'=>'string', 'url'=>'string', 'extra_parameters='=>'mixed'], 'OAuth::getAccessToken' => ['array|false', 'access_token_url'=>'string', 'auth_session_handle='=>'string', 'verifier_token='=>'string', 'http_method='=>'string'], 'OAuth::getCAPath' => ['array'], 'OAuth::getLastResponse' => ['string'], 'OAuth::getLastResponseHeaders' => ['string|false'], 'OAuth::getLastResponseInfo' => ['array'], 'OAuth::getRequestHeader' => ['string|false', 'http_method'=>'string', 'url'=>'string', 'extra_parameters='=>'mixed'], 'OAuth::getRequestToken' => ['array|false', 'request_token_url'=>'string', 'callback_url='=>'string', 'http_method='=>'string'], 'OAuth::setAuthType' => ['bool', 'auth_type'=>'int'], 'OAuth::setCAPath' => ['mixed', 'ca_path='=>'string', 'ca_info='=>'string'], 'OAuth::setNonce' => ['mixed', 'nonce'=>'string'], 'OAuth::setRSACertificate' => ['mixed', 'cert'=>'string'], 'OAuth::setRequestEngine' => ['void', 'reqengine'=>'int'], 'OAuth::setSSLChecks' => ['bool', 'sslcheck'=>'int'], 'OAuth::setTimeout' => ['void', 'timeout'=>'int'], 'OAuth::setTimestamp' => ['mixed', 'timestamp'=>'string'], 'OAuth::setToken' => ['bool', 'token'=>'string', 'token_secret'=>'string'], 'OAuth::setVersion' => ['bool', 'version'=>'string'], 'OAuthProvider::__construct' => ['void', 'params_array='=>'array'], 'OAuthProvider::addRequiredParameter' => ['bool', 'req_params'=>'string'], 'OAuthProvider::callTimestampNonceHandler' => ['void'], 'OAuthProvider::callconsumerHandler' => ['void'], 'OAuthProvider::calltokenHandler' => ['void'], 'OAuthProvider::checkOAuthRequest' => ['void', 'uri='=>'string', 'method='=>'string'], 'OAuthProvider::consumerHandler' => ['void', 'callback_function'=>'callable'], 'OAuthProvider::generateToken' => ['string', 'size'=>'int', 'strong='=>'bool'], 'OAuthProvider::is2LeggedEndpoint' => ['void', 'params_array'=>'mixed'], 'OAuthProvider::isRequestTokenEndpoint' => ['void', 'will_issue_request_token'=>'bool'], 'OAuthProvider::removeRequiredParameter' => ['bool', 'req_params'=>'string'], 'OAuthProvider::reportProblem' => ['string', 'oauthexception'=>'string', 'send_headers='=>'bool'], 'OAuthProvider::setParam' => ['bool', 'param_key'=>'string', 'param_val='=>'mixed'], 'OAuthProvider::setRequestTokenPath' => ['bool', 'path'=>'string'], 'OAuthProvider::timestampNonceHandler' => ['void', 'callback_function'=>'callable'], 'OAuthProvider::tokenHandler' => ['void', 'callback_function'=>'callable'], 'OCICollection::append' => ['bool', 'value'=>'mixed'], 'OCICollection::assign' => ['bool', 'from'=>'OCI_Collection'], 'OCICollection::assignElem' => ['bool', 'index'=>'int', 'value'=>'mixed'], 'OCICollection::free' => ['bool'], 'OCICollection::getElem' => ['mixed', 'index'=>'int'], 'OCICollection::max' => ['int|false'], 'OCICollection::size' => ['int|false'], 'OCICollection::trim' => ['bool', 'num'=>'int'], 'OCILob::append' => ['bool', 'lob_from'=>'OCILob'], 'OCILob::close' => ['bool'], 'OCILob::eof' => ['bool'], 'OCILob::erase' => ['int|false', 'offset='=>'int', 'length='=>'int'], 'OCILob::export' => ['bool', 'filename'=>'string', 'start='=>'int', 'length='=>'int'], 'OCILob::flush' => ['bool', 'flag='=>'int'], 'OCILob::free' => ['bool'], 'OCILob::getbuffering' => ['bool'], 'OCILob::import' => ['bool', 'filename'=>'string'], 'OCILob::load' => ['string|false'], 'OCILob::read' => ['string|false', 'length'=>'int'], 'OCILob::rewind' => ['bool'], 'OCILob::save' => ['bool', 'data'=>'string', 'offset='=>'int'], 'OCILob::savefile' => ['bool', 'filename'=>''], 'OCILob::seek' => ['bool', 'offset'=>'int', 'whence='=>'int'], 'OCILob::setbuffering' => ['bool', 'on_off'=>'bool'], 'OCILob::size' => ['int|false'], 'OCILob::tell' => ['int|false'], 'OCILob::truncate' => ['bool', 'length='=>'int'], 'OCILob::write' => ['int|false', 'data'=>'string', 'length='=>'int'], 'OCILob::writeTemporary' => ['bool', 'data'=>'string', 'lob_type='=>'int'], 'OCILob::writetofile' => ['bool', 'filename'=>'', 'start'=>'', 'length'=>''], 'OutOfBoundsException::__clone' => ['void'], 'OutOfBoundsException::__construct' => ['void', 'message='=>'string', 'code='=>'int', 'previous='=>'?Throwable'], 'OutOfBoundsException::__toString' => ['string'], 'OutOfBoundsException::getCode' => ['int'], 'OutOfBoundsException::getFile' => ['string'], 'OutOfBoundsException::getLine' => ['int'], 'OutOfBoundsException::getMessage' => ['string'], 'OutOfBoundsException::getPrevious' => ['?Throwable'], 'OutOfBoundsException::getTrace' => ['list\',args?:array}>'], 'OutOfBoundsException::getTraceAsString' => ['string'], 'OutOfRangeException::__clone' => ['void'], 'OutOfRangeException::__construct' => ['void', 'message='=>'string', 'code='=>'int', 'previous='=>'?Throwable'], 'OutOfRangeException::__toString' => ['string'], 'OutOfRangeException::getCode' => ['int'], 'OutOfRangeException::getFile' => ['string'], 'OutOfRangeException::getLine' => ['int'], 'OutOfRangeException::getMessage' => ['string'], 'OutOfRangeException::getPrevious' => ['?Throwable'], 'OutOfRangeException::getTrace' => ['list\',args?:array}>'], 'OutOfRangeException::getTraceAsString' => ['string'], 'OuterIterator::current' => ['mixed'], 'OuterIterator::getInnerIterator' => ['Iterator'], 'OuterIterator::key' => ['int|string'], 'OuterIterator::next' => ['void'], 'OuterIterator::rewind' => ['void'], 'OuterIterator::valid' => ['bool'], 'OverflowException::__clone' => ['void'], 'OverflowException::__construct' => ['void', 'message='=>'string', 'code='=>'int', 'previous='=>'?Throwable'], 'OverflowException::__toString' => ['string'], 'OverflowException::getCode' => ['int'], 'OverflowException::getFile' => ['string'], 'OverflowException::getLine' => ['int'], 'OverflowException::getMessage' => ['string'], 'OverflowException::getPrevious' => ['?Throwable'], 'OverflowException::getTrace' => ['list\',args?:array}>'], 'OverflowException::getTraceAsString' => ['string'], 'OwsrequestObj::__construct' => ['void'], 'OwsrequestObj::addParameter' => ['int', 'name'=>'string', 'value'=>'string'], 'OwsrequestObj::getName' => ['string', 'index'=>'int'], 'OwsrequestObj::getValue' => ['string', 'index'=>'int'], 'OwsrequestObj::getValueByName' => ['string', 'name'=>'string'], 'OwsrequestObj::loadParams' => ['int'], 'OwsrequestObj::setParameter' => ['int', 'name'=>'string', 'value'=>'string'], 'PDF_activate_item' => ['bool', 'pdfdoc'=>'resource', 'id'=>'int'], 'PDF_add_launchlink' => ['bool', 'pdfdoc'=>'resource', 'llx'=>'float', 'lly'=>'float', 'urx'=>'float', 'ury'=>'float', 'filename'=>'string'], 'PDF_add_locallink' => ['bool', 'pdfdoc'=>'resource', 'lowerleftx'=>'float', 'lowerlefty'=>'float', 'upperrightx'=>'float', 'upperrighty'=>'float', 'page'=>'int', 'dest'=>'string'], 'PDF_add_nameddest' => ['bool', 'pdfdoc'=>'resource', 'name'=>'string', 'optlist'=>'string'], 'PDF_add_note' => ['bool', 'pdfdoc'=>'resource', 'llx'=>'float', 'lly'=>'float', 'urx'=>'float', 'ury'=>'float', 'contents'=>'string', 'title'=>'string', 'icon'=>'string', 'open'=>'int'], 'PDF_add_pdflink' => ['bool', 'pdfdoc'=>'resource', 'bottom_left_x'=>'float', 'bottom_left_y'=>'float', 'up_right_x'=>'float', 'up_right_y'=>'float', 'filename'=>'string', 'page'=>'int', 'dest'=>'string'], 'PDF_add_table_cell' => ['int', 'pdfdoc'=>'resource', 'table'=>'int', 'column'=>'int', 'row'=>'int', 'text'=>'string', 'optlist'=>'string'], 'PDF_add_textflow' => ['int', 'pdfdoc'=>'resource', 'textflow'=>'int', 'text'=>'string', 'optlist'=>'string'], 'PDF_add_thumbnail' => ['bool', 'pdfdoc'=>'resource', 'image'=>'int'], 'PDF_add_weblink' => ['bool', 'pdfdoc'=>'resource', 'lowerleftx'=>'float', 'lowerlefty'=>'float', 'upperrightx'=>'float', 'upperrighty'=>'float', 'url'=>'string'], 'PDF_arc' => ['bool', 'p'=>'resource', 'x'=>'float', 'y'=>'float', 'r'=>'float', 'alpha'=>'float', 'beta'=>'float'], 'PDF_arcn' => ['bool', 'p'=>'resource', 'x'=>'float', 'y'=>'float', 'r'=>'float', 'alpha'=>'float', 'beta'=>'float'], 'PDF_attach_file' => ['bool', 'pdfdoc'=>'resource', 'llx'=>'float', 'lly'=>'float', 'urx'=>'float', 'ury'=>'float', 'filename'=>'string', 'description'=>'string', 'author'=>'string', 'mimetype'=>'string', 'icon'=>'string'], 'PDF_begin_document' => ['int', 'pdfdoc'=>'resource', 'filename'=>'string', 'optlist'=>'string'], 'PDF_begin_font' => ['bool', 'pdfdoc'=>'resource', 'filename'=>'string', 'a'=>'float', 'b'=>'float', 'c'=>'float', 'd'=>'float', 'e'=>'float', 'f'=>'float', 'optlist'=>'string'], 'PDF_begin_glyph' => ['bool', 'pdfdoc'=>'resource', 'glyphname'=>'string', 'wx'=>'float', 'llx'=>'float', 'lly'=>'float', 'urx'=>'float', 'ury'=>'float'], 'PDF_begin_item' => ['int', 'pdfdoc'=>'resource', 'tag'=>'string', 'optlist'=>'string'], 'PDF_begin_layer' => ['bool', 'pdfdoc'=>'resource', 'layer'=>'int'], 'PDF_begin_page' => ['bool', 'pdfdoc'=>'resource', 'width'=>'float', 'height'=>'float'], 'PDF_begin_page_ext' => ['bool', 'pdfdoc'=>'resource', 'width'=>'float', 'height'=>'float', 'optlist'=>'string'], 'PDF_begin_pattern' => ['int', 'pdfdoc'=>'resource', 'width'=>'float', 'height'=>'float', 'xstep'=>'float', 'ystep'=>'float', 'painttype'=>'int'], 'PDF_begin_template' => ['int', 'pdfdoc'=>'resource', 'width'=>'float', 'height'=>'float'], 'PDF_begin_template_ext' => ['int', 'pdfdoc'=>'resource', 'width'=>'float', 'height'=>'float', 'optlist'=>'string'], 'PDF_circle' => ['bool', 'pdfdoc'=>'resource', 'x'=>'float', 'y'=>'float', 'r'=>'float'], 'PDF_clip' => ['bool', 'p'=>'resource'], 'PDF_close' => ['bool', 'p'=>'resource'], 'PDF_close_image' => ['bool', 'p'=>'resource', 'image'=>'int'], 'PDF_close_pdi' => ['bool', 'p'=>'resource', 'doc'=>'int'], 'PDF_close_pdi_page' => ['bool', 'p'=>'resource', 'page'=>'int'], 'PDF_closepath' => ['bool', 'p'=>'resource'], 'PDF_closepath_fill_stroke' => ['bool', 'p'=>'resource'], 'PDF_closepath_stroke' => ['bool', 'p'=>'resource'], 'PDF_concat' => ['bool', 'p'=>'resource', 'a'=>'float', 'b'=>'float', 'c'=>'float', 'd'=>'float', 'e'=>'float', 'f'=>'float'], 'PDF_continue_text' => ['bool', 'p'=>'resource', 'text'=>'string'], 'PDF_create_3dview' => ['int', 'pdfdoc'=>'resource', 'username'=>'string', 'optlist'=>'string'], 'PDF_create_action' => ['int', 'pdfdoc'=>'resource', 'type'=>'string', 'optlist'=>'string'], 'PDF_create_annotation' => ['bool', 'pdfdoc'=>'resource', 'llx'=>'float', 'lly'=>'float', 'urx'=>'float', 'ury'=>'float', 'type'=>'string', 'optlist'=>'string'], 'PDF_create_bookmark' => ['int', 'pdfdoc'=>'resource', 'text'=>'string', 'optlist'=>'string'], 'PDF_create_field' => ['bool', 'pdfdoc'=>'resource', 'llx'=>'float', 'lly'=>'float', 'urx'=>'float', 'ury'=>'float', 'name'=>'string', 'type'=>'string', 'optlist'=>'string'], 'PDF_create_fieldgroup' => ['bool', 'pdfdoc'=>'resource', 'name'=>'string', 'optlist'=>'string'], 'PDF_create_gstate' => ['int', 'pdfdoc'=>'resource', 'optlist'=>'string'], 'PDF_create_pvf' => ['bool', 'pdfdoc'=>'resource', 'filename'=>'string', 'data'=>'string', 'optlist'=>'string'], 'PDF_create_textflow' => ['int', 'pdfdoc'=>'resource', 'text'=>'string', 'optlist'=>'string'], 'PDF_curveto' => ['bool', 'p'=>'resource', 'x1'=>'float', 'y1'=>'float', 'x2'=>'float', 'y2'=>'float', 'x3'=>'float', 'y3'=>'float'], 'PDF_define_layer' => ['int', 'pdfdoc'=>'resource', 'name'=>'string', 'optlist'=>'string'], 'PDF_delete' => ['bool', 'pdfdoc'=>'resource'], 'PDF_delete_pvf' => ['int', 'pdfdoc'=>'resource', 'filename'=>'string'], 'PDF_delete_table' => ['bool', 'pdfdoc'=>'resource', 'table'=>'int', 'optlist'=>'string'], 'PDF_delete_textflow' => ['bool', 'pdfdoc'=>'resource', 'textflow'=>'int'], 'PDF_encoding_set_char' => ['bool', 'pdfdoc'=>'resource', 'encoding'=>'string', 'slot'=>'int', 'glyphname'=>'string', 'uv'=>'int'], 'PDF_end_document' => ['bool', 'pdfdoc'=>'resource', 'optlist'=>'string'], 'PDF_end_font' => ['bool', 'pdfdoc'=>'resource'], 'PDF_end_glyph' => ['bool', 'pdfdoc'=>'resource'], 'PDF_end_item' => ['bool', 'pdfdoc'=>'resource', 'id'=>'int'], 'PDF_end_layer' => ['bool', 'pdfdoc'=>'resource'], 'PDF_end_page' => ['bool', 'p'=>'resource'], 'PDF_end_page_ext' => ['bool', 'pdfdoc'=>'resource', 'optlist'=>'string'], 'PDF_end_pattern' => ['bool', 'p'=>'resource'], 'PDF_end_template' => ['bool', 'p'=>'resource'], 'PDF_endpath' => ['bool', 'p'=>'resource'], 'PDF_fill' => ['bool', 'p'=>'resource'], 'PDF_fill_imageblock' => ['int', 'pdfdoc'=>'resource', 'page'=>'int', 'blockname'=>'string', 'image'=>'int', 'optlist'=>'string'], 'PDF_fill_pdfblock' => ['int', 'pdfdoc'=>'resource', 'page'=>'int', 'blockname'=>'string', 'contents'=>'int', 'optlist'=>'string'], 'PDF_fill_stroke' => ['bool', 'p'=>'resource'], 'PDF_fill_textblock' => ['int', 'pdfdoc'=>'resource', 'page'=>'int', 'blockname'=>'string', 'text'=>'string', 'optlist'=>'string'], 'PDF_findfont' => ['int', 'p'=>'resource', 'fontname'=>'string', 'encoding'=>'string', 'embed'=>'int'], 'PDF_fit_image' => ['bool', 'pdfdoc'=>'resource', 'image'=>'int', 'x'=>'float', 'y'=>'float', 'optlist'=>'string'], 'PDF_fit_pdi_page' => ['bool', 'pdfdoc'=>'resource', 'page'=>'int', 'x'=>'float', 'y'=>'float', 'optlist'=>'string'], 'PDF_fit_table' => ['string', 'pdfdoc'=>'resource', 'table'=>'int', 'llx'=>'float', 'lly'=>'float', 'urx'=>'float', 'ury'=>'float', 'optlist'=>'string'], 'PDF_fit_textflow' => ['string', 'pdfdoc'=>'resource', 'textflow'=>'int', 'llx'=>'float', 'lly'=>'float', 'urx'=>'float', 'ury'=>'float', 'optlist'=>'string'], 'PDF_fit_textline' => ['bool', 'pdfdoc'=>'resource', 'text'=>'string', 'x'=>'float', 'y'=>'float', 'optlist'=>'string'], 'PDF_get_apiname' => ['string', 'pdfdoc'=>'resource'], 'PDF_get_buffer' => ['string', 'p'=>'resource'], 'PDF_get_errmsg' => ['string', 'pdfdoc'=>'resource'], 'PDF_get_errnum' => ['int', 'pdfdoc'=>'resource'], 'PDF_get_majorversion' => ['int'], 'PDF_get_minorversion' => ['int'], 'PDF_get_parameter' => ['string', 'p'=>'resource', 'key'=>'string', 'modifier'=>'float'], 'PDF_get_pdi_parameter' => ['string', 'p'=>'resource', 'key'=>'string', 'doc'=>'int', 'page'=>'int', 'reserved'=>'int'], 'PDF_get_pdi_value' => ['float', 'p'=>'resource', 'key'=>'string', 'doc'=>'int', 'page'=>'int', 'reserved'=>'int'], 'PDF_get_value' => ['float', 'p'=>'resource', 'key'=>'string', 'modifier'=>'float'], 'PDF_info_font' => ['float', 'pdfdoc'=>'resource', 'font'=>'int', 'keyword'=>'string', 'optlist'=>'string'], 'PDF_info_matchbox' => ['float', 'pdfdoc'=>'resource', 'boxname'=>'string', 'num'=>'int', 'keyword'=>'string'], 'PDF_info_table' => ['float', 'pdfdoc'=>'resource', 'table'=>'int', 'keyword'=>'string'], 'PDF_info_textflow' => ['float', 'pdfdoc'=>'resource', 'textflow'=>'int', 'keyword'=>'string'], 'PDF_info_textline' => ['float', 'pdfdoc'=>'resource', 'text'=>'string', 'keyword'=>'string', 'optlist'=>'string'], 'PDF_initgraphics' => ['bool', 'p'=>'resource'], 'PDF_lineto' => ['bool', 'p'=>'resource', 'x'=>'float', 'y'=>'float'], 'PDF_load_3ddata' => ['int', 'pdfdoc'=>'resource', 'filename'=>'string', 'optlist'=>'string'], 'PDF_load_font' => ['int', 'pdfdoc'=>'resource', 'fontname'=>'string', 'encoding'=>'string', 'optlist'=>'string'], 'PDF_load_iccprofile' => ['int', 'pdfdoc'=>'resource', 'profilename'=>'string', 'optlist'=>'string'], 'PDF_load_image' => ['int', 'pdfdoc'=>'resource', 'imagetype'=>'string', 'filename'=>'string', 'optlist'=>'string'], 'PDF_makespotcolor' => ['int', 'p'=>'resource', 'spotname'=>'string'], 'PDF_moveto' => ['bool', 'p'=>'resource', 'x'=>'float', 'y'=>'float'], 'PDF_new' => ['resource'], 'PDF_open_ccitt' => ['int', 'pdfdoc'=>'resource', 'filename'=>'string', 'width'=>'int', 'height'=>'int', 'bitreverse'=>'int', 'k'=>'int', 'blackls1'=>'int'], 'PDF_open_file' => ['bool', 'p'=>'resource', 'filename'=>'string'], 'PDF_open_image' => ['int', 'p'=>'resource', 'imagetype'=>'string', 'source'=>'string', 'data'=>'string', 'length'=>'int', 'width'=>'int', 'height'=>'int', 'components'=>'int', 'bpc'=>'int', 'params'=>'string'], 'PDF_open_image_file' => ['int', 'p'=>'resource', 'imagetype'=>'string', 'filename'=>'string', 'stringparam'=>'string', 'intparam'=>'int'], 'PDF_open_memory_image' => ['int', 'p'=>'resource', 'image'=>'resource'], 'PDF_open_pdi' => ['int', 'pdfdoc'=>'resource', 'filename'=>'string', 'optlist'=>'string', 'length'=>'int'], 'PDF_open_pdi_document' => ['int', 'p'=>'resource', 'filename'=>'string', 'optlist'=>'string'], 'PDF_open_pdi_page' => ['int', 'p'=>'resource', 'doc'=>'int', 'pagenumber'=>'int', 'optlist'=>'string'], 'PDF_pcos_get_number' => ['float', 'p'=>'resource', 'doc'=>'int', 'path'=>'string'], 'PDF_pcos_get_stream' => ['string', 'p'=>'resource', 'doc'=>'int', 'optlist'=>'string', 'path'=>'string'], 'PDF_pcos_get_string' => ['string', 'p'=>'resource', 'doc'=>'int', 'path'=>'string'], 'PDF_place_image' => ['bool', 'pdfdoc'=>'resource', 'image'=>'int', 'x'=>'float', 'y'=>'float', 'scale'=>'float'], 'PDF_place_pdi_page' => ['bool', 'pdfdoc'=>'resource', 'page'=>'int', 'x'=>'float', 'y'=>'float', 'sx'=>'float', 'sy'=>'float'], 'PDF_process_pdi' => ['int', 'pdfdoc'=>'resource', 'doc'=>'int', 'page'=>'int', 'optlist'=>'string'], 'PDF_rect' => ['bool', 'p'=>'resource', 'x'=>'float', 'y'=>'float', 'width'=>'float', 'height'=>'float'], 'PDF_restore' => ['bool', 'p'=>'resource'], 'PDF_resume_page' => ['bool', 'pdfdoc'=>'resource', 'optlist'=>'string'], 'PDF_rotate' => ['bool', 'p'=>'resource', 'phi'=>'float'], 'PDF_save' => ['bool', 'p'=>'resource'], 'PDF_scale' => ['bool', 'p'=>'resource', 'sx'=>'float', 'sy'=>'float'], 'PDF_set_border_color' => ['bool', 'p'=>'resource', 'red'=>'float', 'green'=>'float', 'blue'=>'float'], 'PDF_set_border_dash' => ['bool', 'pdfdoc'=>'resource', 'black'=>'float', 'white'=>'float'], 'PDF_set_border_style' => ['bool', 'pdfdoc'=>'resource', 'style'=>'string', 'width'=>'float'], 'PDF_set_gstate' => ['bool', 'pdfdoc'=>'resource', 'gstate'=>'int'], 'PDF_set_info' => ['bool', 'p'=>'resource', 'key'=>'string', 'value'=>'string'], 'PDF_set_layer_dependency' => ['bool', 'pdfdoc'=>'resource', 'type'=>'string', 'optlist'=>'string'], 'PDF_set_parameter' => ['bool', 'p'=>'resource', 'key'=>'string', 'value'=>'string'], 'PDF_set_text_pos' => ['bool', 'p'=>'resource', 'x'=>'float', 'y'=>'float'], 'PDF_set_value' => ['bool', 'p'=>'resource', 'key'=>'string', 'value'=>'float'], 'PDF_setcolor' => ['bool', 'p'=>'resource', 'fstype'=>'string', 'colorspace'=>'string', 'c1'=>'float', 'c2'=>'float', 'c3'=>'float', 'c4'=>'float'], 'PDF_setdash' => ['bool', 'pdfdoc'=>'resource', 'b'=>'float', 'w'=>'float'], 'PDF_setdashpattern' => ['bool', 'pdfdoc'=>'resource', 'optlist'=>'string'], 'PDF_setflat' => ['bool', 'pdfdoc'=>'resource', 'flatness'=>'float'], 'PDF_setfont' => ['bool', 'pdfdoc'=>'resource', 'font'=>'int', 'fontsize'=>'float'], 'PDF_setgray' => ['bool', 'p'=>'resource', 'g'=>'float'], 'PDF_setgray_fill' => ['bool', 'p'=>'resource', 'g'=>'float'], 'PDF_setgray_stroke' => ['bool', 'p'=>'resource', 'g'=>'float'], 'PDF_setlinecap' => ['bool', 'p'=>'resource', 'linecap'=>'int'], 'PDF_setlinejoin' => ['bool', 'p'=>'resource', 'value'=>'int'], 'PDF_setlinewidth' => ['bool', 'p'=>'resource', 'width'=>'float'], 'PDF_setmatrix' => ['bool', 'p'=>'resource', 'a'=>'float', 'b'=>'float', 'c'=>'float', 'd'=>'float', 'e'=>'float', 'f'=>'float'], 'PDF_setmiterlimit' => ['bool', 'pdfdoc'=>'resource', 'miter'=>'float'], 'PDF_setrgbcolor' => ['bool', 'p'=>'resource', 'red'=>'float', 'green'=>'float', 'blue'=>'float'], 'PDF_setrgbcolor_fill' => ['bool', 'p'=>'resource', 'red'=>'float', 'green'=>'float', 'blue'=>'float'], 'PDF_setrgbcolor_stroke' => ['bool', 'p'=>'resource', 'red'=>'float', 'green'=>'float', 'blue'=>'float'], 'PDF_shading' => ['int', 'pdfdoc'=>'resource', 'shtype'=>'string', 'x0'=>'float', 'y0'=>'float', 'x1'=>'float', 'y1'=>'float', 'c1'=>'float', 'c2'=>'float', 'c3'=>'float', 'c4'=>'float', 'optlist'=>'string'], 'PDF_shading_pattern' => ['int', 'pdfdoc'=>'resource', 'shading'=>'int', 'optlist'=>'string'], 'PDF_shfill' => ['bool', 'pdfdoc'=>'resource', 'shading'=>'int'], 'PDF_show' => ['bool', 'pdfdoc'=>'resource', 'text'=>'string'], 'PDF_show_boxed' => ['int', 'p'=>'resource', 'text'=>'string', 'left'=>'float', 'top'=>'float', 'width'=>'float', 'height'=>'float', 'mode'=>'string', 'feature'=>'string'], 'PDF_show_xy' => ['bool', 'p'=>'resource', 'text'=>'string', 'x'=>'float', 'y'=>'float'], 'PDF_skew' => ['bool', 'p'=>'resource', 'alpha'=>'float', 'beta'=>'float'], 'PDF_stringwidth' => ['float', 'p'=>'resource', 'text'=>'string', 'font'=>'int', 'fontsize'=>'float'], 'PDF_stroke' => ['bool', 'p'=>'resource'], 'PDF_suspend_page' => ['bool', 'pdfdoc'=>'resource', 'optlist'=>'string'], 'PDF_translate' => ['bool', 'p'=>'resource', 'tx'=>'float', 'ty'=>'float'], 'PDF_utf16_to_utf8' => ['string', 'pdfdoc'=>'resource', 'utf16string'=>'string'], 'PDF_utf32_to_utf16' => ['string', 'pdfdoc'=>'resource', 'utf32string'=>'string', 'ordering'=>'string'], 'PDF_utf8_to_utf16' => ['string', 'pdfdoc'=>'resource', 'utf8string'=>'string', 'ordering'=>'string'], 'PDFlib::activate_item' => ['bool', 'id'=>''], 'PDFlib::add_launchlink' => ['bool', 'llx'=>'float', 'lly'=>'float', 'urx'=>'float', 'ury'=>'float', 'filename'=>'string'], 'PDFlib::add_locallink' => ['bool', 'lowerleftx'=>'float', 'lowerlefty'=>'float', 'upperrightx'=>'float', 'upperrighty'=>'float', 'page'=>'int', 'dest'=>'string'], 'PDFlib::add_nameddest' => ['bool', 'name'=>'string', 'optlist'=>'string'], 'PDFlib::add_note' => ['bool', 'llx'=>'float', 'lly'=>'float', 'urx'=>'float', 'ury'=>'float', 'contents'=>'string', 'title'=>'string', 'icon'=>'string', 'open'=>'int'], 'PDFlib::add_pdflink' => ['bool', 'bottom_left_x'=>'float', 'bottom_left_y'=>'float', 'up_right_x'=>'float', 'up_right_y'=>'float', 'filename'=>'string', 'page'=>'int', 'dest'=>'string'], 'PDFlib::add_table_cell' => ['int', 'table'=>'int', 'column'=>'int', 'row'=>'int', 'text'=>'string', 'optlist'=>'string'], 'PDFlib::add_textflow' => ['int', 'textflow'=>'int', 'text'=>'string', 'optlist'=>'string'], 'PDFlib::add_thumbnail' => ['bool', 'image'=>'int'], 'PDFlib::add_weblink' => ['bool', 'lowerleftx'=>'float', 'lowerlefty'=>'float', 'upperrightx'=>'float', 'upperrighty'=>'float', 'url'=>'string'], 'PDFlib::arc' => ['bool', 'x'=>'float', 'y'=>'float', 'r'=>'float', 'alpha'=>'float', 'beta'=>'float'], 'PDFlib::arcn' => ['bool', 'x'=>'float', 'y'=>'float', 'r'=>'float', 'alpha'=>'float', 'beta'=>'float'], 'PDFlib::attach_file' => ['bool', 'llx'=>'float', 'lly'=>'float', 'urx'=>'float', 'ury'=>'float', 'filename'=>'string', 'description'=>'string', 'author'=>'string', 'mimetype'=>'string', 'icon'=>'string'], 'PDFlib::begin_document' => ['int', 'filename'=>'string', 'optlist'=>'string'], 'PDFlib::begin_font' => ['bool', 'filename'=>'string', 'a'=>'float', 'b'=>'float', 'c'=>'float', 'd'=>'float', 'e'=>'float', 'f'=>'float', 'optlist'=>'string'], 'PDFlib::begin_glyph' => ['bool', 'glyphname'=>'string', 'wx'=>'float', 'llx'=>'float', 'lly'=>'float', 'urx'=>'float', 'ury'=>'float'], 'PDFlib::begin_item' => ['int', 'tag'=>'string', 'optlist'=>'string'], 'PDFlib::begin_layer' => ['bool', 'layer'=>'int'], 'PDFlib::begin_page' => ['bool', 'width'=>'float', 'height'=>'float'], 'PDFlib::begin_page_ext' => ['bool', 'width'=>'float', 'height'=>'float', 'optlist'=>'string'], 'PDFlib::begin_pattern' => ['int', 'width'=>'float', 'height'=>'float', 'xstep'=>'float', 'ystep'=>'float', 'painttype'=>'int'], 'PDFlib::begin_template' => ['int', 'width'=>'float', 'height'=>'float'], 'PDFlib::begin_template_ext' => ['int', 'width'=>'float', 'height'=>'float', 'optlist'=>'string'], 'PDFlib::circle' => ['bool', 'x'=>'float', 'y'=>'float', 'r'=>'float'], 'PDFlib::clip' => ['bool'], 'PDFlib::close' => ['bool'], 'PDFlib::close_image' => ['bool', 'image'=>'int'], 'PDFlib::close_pdi' => ['bool', 'doc'=>'int'], 'PDFlib::close_pdi_page' => ['bool', 'page'=>'int'], 'PDFlib::closepath' => ['bool'], 'PDFlib::closepath_fill_stroke' => ['bool'], 'PDFlib::closepath_stroke' => ['bool'], 'PDFlib::concat' => ['bool', 'a'=>'float', 'b'=>'float', 'c'=>'float', 'd'=>'float', 'e'=>'float', 'f'=>'float'], 'PDFlib::continue_text' => ['bool', 'text'=>'string'], 'PDFlib::create_3dview' => ['int', 'username'=>'string', 'optlist'=>'string'], 'PDFlib::create_action' => ['int', 'type'=>'string', 'optlist'=>'string'], 'PDFlib::create_annotation' => ['bool', 'llx'=>'float', 'lly'=>'float', 'urx'=>'float', 'ury'=>'float', 'type'=>'string', 'optlist'=>'string'], 'PDFlib::create_bookmark' => ['int', 'text'=>'string', 'optlist'=>'string'], 'PDFlib::create_field' => ['bool', 'llx'=>'float', 'lly'=>'float', 'urx'=>'float', 'ury'=>'float', 'name'=>'string', 'type'=>'string', 'optlist'=>'string'], 'PDFlib::create_fieldgroup' => ['bool', 'name'=>'string', 'optlist'=>'string'], 'PDFlib::create_gstate' => ['int', 'optlist'=>'string'], 'PDFlib::create_pvf' => ['bool', 'filename'=>'string', 'data'=>'string', 'optlist'=>'string'], 'PDFlib::create_textflow' => ['int', 'text'=>'string', 'optlist'=>'string'], 'PDFlib::curveto' => ['bool', 'x1'=>'float', 'y1'=>'float', 'x2'=>'float', 'y2'=>'float', 'x3'=>'float', 'y3'=>'float'], 'PDFlib::define_layer' => ['int', 'name'=>'string', 'optlist'=>'string'], 'PDFlib::delete' => ['bool'], 'PDFlib::delete_pvf' => ['int', 'filename'=>'string'], 'PDFlib::delete_table' => ['bool', 'table'=>'int', 'optlist'=>'string'], 'PDFlib::delete_textflow' => ['bool', 'textflow'=>'int'], 'PDFlib::encoding_set_char' => ['bool', 'encoding'=>'string', 'slot'=>'int', 'glyphname'=>'string', 'uv'=>'int'], 'PDFlib::end_document' => ['bool', 'optlist'=>'string'], 'PDFlib::end_font' => ['bool'], 'PDFlib::end_glyph' => ['bool'], 'PDFlib::end_item' => ['bool', 'id'=>'int'], 'PDFlib::end_layer' => ['bool'], 'PDFlib::end_page' => ['bool', 'p'=>''], 'PDFlib::end_page_ext' => ['bool', 'optlist'=>'string'], 'PDFlib::end_pattern' => ['bool', 'p'=>''], 'PDFlib::end_template' => ['bool', 'p'=>''], 'PDFlib::endpath' => ['bool', 'p'=>''], 'PDFlib::fill' => ['bool'], 'PDFlib::fill_imageblock' => ['int', 'page'=>'int', 'blockname'=>'string', 'image'=>'int', 'optlist'=>'string'], 'PDFlib::fill_pdfblock' => ['int', 'page'=>'int', 'blockname'=>'string', 'contents'=>'int', 'optlist'=>'string'], 'PDFlib::fill_stroke' => ['bool'], 'PDFlib::fill_textblock' => ['int', 'page'=>'int', 'blockname'=>'string', 'text'=>'string', 'optlist'=>'string'], 'PDFlib::findfont' => ['int', 'fontname'=>'string', 'encoding'=>'string', 'embed'=>'int'], 'PDFlib::fit_image' => ['bool', 'image'=>'int', 'x'=>'float', 'y'=>'float', 'optlist'=>'string'], 'PDFlib::fit_pdi_page' => ['bool', 'page'=>'int', 'x'=>'float', 'y'=>'float', 'optlist'=>'string'], 'PDFlib::fit_table' => ['string', 'table'=>'int', 'llx'=>'float', 'lly'=>'float', 'urx'=>'float', 'ury'=>'float', 'optlist'=>'string'], 'PDFlib::fit_textflow' => ['string', 'textflow'=>'int', 'llx'=>'float', 'lly'=>'float', 'urx'=>'float', 'ury'=>'float', 'optlist'=>'string'], 'PDFlib::fit_textline' => ['bool', 'text'=>'string', 'x'=>'float', 'y'=>'float', 'optlist'=>'string'], 'PDFlib::get_apiname' => ['string'], 'PDFlib::get_buffer' => ['string'], 'PDFlib::get_errmsg' => ['string'], 'PDFlib::get_errnum' => ['int'], 'PDFlib::get_majorversion' => ['int'], 'PDFlib::get_minorversion' => ['int'], 'PDFlib::get_parameter' => ['string', 'key'=>'string', 'modifier'=>'float'], 'PDFlib::get_pdi_parameter' => ['string', 'key'=>'string', 'doc'=>'int', 'page'=>'int', 'reserved'=>'int'], 'PDFlib::get_pdi_value' => ['float', 'key'=>'string', 'doc'=>'int', 'page'=>'int', 'reserved'=>'int'], 'PDFlib::get_value' => ['float', 'key'=>'string', 'modifier'=>'float'], 'PDFlib::info_font' => ['float', 'font'=>'int', 'keyword'=>'string', 'optlist'=>'string'], 'PDFlib::info_matchbox' => ['float', 'boxname'=>'string', 'num'=>'int', 'keyword'=>'string'], 'PDFlib::info_table' => ['float', 'table'=>'int', 'keyword'=>'string'], 'PDFlib::info_textflow' => ['float', 'textflow'=>'int', 'keyword'=>'string'], 'PDFlib::info_textline' => ['float', 'text'=>'string', 'keyword'=>'string', 'optlist'=>'string'], 'PDFlib::initgraphics' => ['bool'], 'PDFlib::lineto' => ['bool', 'x'=>'float', 'y'=>'float'], 'PDFlib::load_3ddata' => ['int', 'filename'=>'string', 'optlist'=>'string'], 'PDFlib::load_font' => ['int', 'fontname'=>'string', 'encoding'=>'string', 'optlist'=>'string'], 'PDFlib::load_iccprofile' => ['int', 'profilename'=>'string', 'optlist'=>'string'], 'PDFlib::load_image' => ['int', 'imagetype'=>'string', 'filename'=>'string', 'optlist'=>'string'], 'PDFlib::makespotcolor' => ['int', 'spotname'=>'string'], 'PDFlib::moveto' => ['bool', 'x'=>'float', 'y'=>'float'], 'PDFlib::open_ccitt' => ['int', 'filename'=>'string', 'width'=>'int', 'height'=>'int', 'BitReverse'=>'int', 'k'=>'int', 'Blackls1'=>'int'], 'PDFlib::open_file' => ['bool', 'filename'=>'string'], 'PDFlib::open_image' => ['int', 'imagetype'=>'string', 'source'=>'string', 'data'=>'string', 'length'=>'int', 'width'=>'int', 'height'=>'int', 'components'=>'int', 'bpc'=>'int', 'params'=>'string'], 'PDFlib::open_image_file' => ['int', 'imagetype'=>'string', 'filename'=>'string', 'stringparam'=>'string', 'intparam'=>'int'], 'PDFlib::open_memory_image' => ['int', 'image'=>'resource'], 'PDFlib::open_pdi' => ['int', 'filename'=>'string', 'optlist'=>'string', 'length'=>'int'], 'PDFlib::open_pdi_document' => ['int', 'filename'=>'string', 'optlist'=>'string'], 'PDFlib::open_pdi_page' => ['int', 'doc'=>'int', 'pagenumber'=>'int', 'optlist'=>'string'], 'PDFlib::pcos_get_number' => ['float', 'doc'=>'int', 'path'=>'string'], 'PDFlib::pcos_get_stream' => ['string', 'doc'=>'int', 'optlist'=>'string', 'path'=>'string'], 'PDFlib::pcos_get_string' => ['string', 'doc'=>'int', 'path'=>'string'], 'PDFlib::place_image' => ['bool', 'image'=>'int', 'x'=>'float', 'y'=>'float', 'scale'=>'float'], 'PDFlib::place_pdi_page' => ['bool', 'page'=>'int', 'x'=>'float', 'y'=>'float', 'sx'=>'float', 'sy'=>'float'], 'PDFlib::process_pdi' => ['int', 'doc'=>'int', 'page'=>'int', 'optlist'=>'string'], 'PDFlib::rect' => ['bool', 'x'=>'float', 'y'=>'float', 'width'=>'float', 'height'=>'float'], 'PDFlib::restore' => ['bool', 'p'=>''], 'PDFlib::resume_page' => ['bool', 'optlist'=>'string'], 'PDFlib::rotate' => ['bool', 'phi'=>'float'], 'PDFlib::save' => ['bool', 'p'=>''], 'PDFlib::scale' => ['bool', 'sx'=>'float', 'sy'=>'float'], 'PDFlib::set_border_color' => ['bool', 'red'=>'float', 'green'=>'float', 'blue'=>'float'], 'PDFlib::set_border_dash' => ['bool', 'black'=>'float', 'white'=>'float'], 'PDFlib::set_border_style' => ['bool', 'style'=>'string', 'width'=>'float'], 'PDFlib::set_gstate' => ['bool', 'gstate'=>'int'], 'PDFlib::set_info' => ['bool', 'key'=>'string', 'value'=>'string'], 'PDFlib::set_layer_dependency' => ['bool', 'type'=>'string', 'optlist'=>'string'], 'PDFlib::set_parameter' => ['bool', 'key'=>'string', 'value'=>'string'], 'PDFlib::set_text_pos' => ['bool', 'x'=>'float', 'y'=>'float'], 'PDFlib::set_value' => ['bool', 'key'=>'string', 'value'=>'float'], 'PDFlib::setcolor' => ['bool', 'fstype'=>'string', 'colorspace'=>'string', 'c1'=>'float', 'c2'=>'float', 'c3'=>'float', 'c4'=>'float'], 'PDFlib::setdash' => ['bool', 'b'=>'float', 'w'=>'float'], 'PDFlib::setdashpattern' => ['bool', 'optlist'=>'string'], 'PDFlib::setflat' => ['bool', 'flatness'=>'float'], 'PDFlib::setfont' => ['bool', 'font'=>'int', 'fontsize'=>'float'], 'PDFlib::setgray' => ['bool', 'g'=>'float'], 'PDFlib::setgray_fill' => ['bool', 'g'=>'float'], 'PDFlib::setgray_stroke' => ['bool', 'g'=>'float'], 'PDFlib::setlinecap' => ['bool', 'linecap'=>'int'], 'PDFlib::setlinejoin' => ['bool', 'value'=>'int'], 'PDFlib::setlinewidth' => ['bool', 'width'=>'float'], 'PDFlib::setmatrix' => ['bool', 'a'=>'float', 'b'=>'float', 'c'=>'float', 'd'=>'float', 'e'=>'float', 'f'=>'float'], 'PDFlib::setmiterlimit' => ['bool', 'miter'=>'float'], 'PDFlib::setrgbcolor' => ['bool', 'red'=>'float', 'green'=>'float', 'blue'=>'float'], 'PDFlib::setrgbcolor_fill' => ['bool', 'red'=>'float', 'green'=>'float', 'blue'=>'float'], 'PDFlib::setrgbcolor_stroke' => ['bool', 'red'=>'float', 'green'=>'float', 'blue'=>'float'], 'PDFlib::shading' => ['int', 'shtype'=>'string', 'x0'=>'float', 'y0'=>'float', 'x1'=>'float', 'y1'=>'float', 'c1'=>'float', 'c2'=>'float', 'c3'=>'float', 'c4'=>'float', 'optlist'=>'string'], 'PDFlib::shading_pattern' => ['int', 'shading'=>'int', 'optlist'=>'string'], 'PDFlib::shfill' => ['bool', 'shading'=>'int'], 'PDFlib::show' => ['bool', 'text'=>'string'], 'PDFlib::show_boxed' => ['int', 'text'=>'string', 'left'=>'float', 'top'=>'float', 'width'=>'float', 'height'=>'float', 'mode'=>'string', 'feature'=>'string'], 'PDFlib::show_xy' => ['bool', 'text'=>'string', 'x'=>'float', 'y'=>'float'], 'PDFlib::skew' => ['bool', 'alpha'=>'float', 'beta'=>'float'], 'PDFlib::stringwidth' => ['float', 'text'=>'string', 'font'=>'int', 'fontsize'=>'float'], 'PDFlib::stroke' => ['bool', 'p'=>''], 'PDFlib::suspend_page' => ['bool', 'optlist'=>'string'], 'PDFlib::translate' => ['bool', 'tx'=>'float', 'ty'=>'float'], 'PDFlib::utf16_to_utf8' => ['string', 'utf16string'=>'string'], 'PDFlib::utf32_to_utf16' => ['string', 'utf32string'=>'string', 'ordering'=>'string'], 'PDFlib::utf8_to_utf16' => ['string', 'utf8string'=>'string', 'ordering'=>'string'], 'PDO::__construct' => ['void', 'dsn'=>'string', 'username='=>'?string', 'password='=>'?string', 'options='=>'?array'], 'PDO::beginTransaction' => ['bool'], 'PDO::commit' => ['bool'], 'PDO::cubrid_schema' => ['array', 'schema_type'=>'int', 'table_name='=>'string', 'col_name='=>'string'], 'PDO::errorCode' => ['?string'], 'PDO::errorInfo' => ['array{0: ?string, 1: ?int, 2: ?string, 3?: mixed, 4?: mixed}'], 'PDO::exec' => ['int|false', 'statement'=>'string'], 'PDO::getAttribute' => ['mixed', 'attribute'=>'int'], 'PDO::getAvailableDrivers' => ['array'], 'PDO::inTransaction' => ['bool'], 'PDO::lastInsertId' => ['string', 'name='=>'string|null'], 'PDO::pgsqlCopyFromArray' => ['bool', 'table_name'=>'string', 'rows'=>'array', 'delimiter'=>'string', 'null_as'=>'string', 'fields'=>'string'], 'PDO::pgsqlCopyFromFile' => ['bool', 'table_name'=>'string', 'filename'=>'string', 'delimiter'=>'string', 'null_as'=>'string', 'fields'=>'string'], 'PDO::pgsqlCopyToArray' => ['array', 'table_name'=>'string', 'delimiter'=>'string', 'null_as'=>'string', 'fields'=>'string'], 'PDO::pgsqlCopyToFile' => ['bool', 'table_name'=>'string', 'filename'=>'string', 'delimiter'=>'string', 'null_as'=>'string', 'fields'=>'string'], 'PDO::pgsqlGetNotify' => ['array{message:string,pid:int,payload?:string}|false', 'result_type='=>'PDO::FETCH_*', 'ms_timeout='=>'int'], 'PDO::pgsqlGetPid' => ['int'], 'PDO::pgsqlLOBCreate' => ['string'], 'PDO::pgsqlLOBOpen' => ['resource', 'oid'=>'string', 'mode='=>'string'], 'PDO::pgsqlLOBUnlink' => ['bool', 'oid'=>'string'], 'PDO::prepare' => ['PDOStatement|false', 'query'=>'string', 'options='=>'array'], 'PDO::query' => ['PDOStatement|false', 'query'=>'string'], 'PDO::query\'1' => ['PDOStatement|false', 'query'=>'string', 'fetch_column'=>'int', 'colno='=>'int'], 'PDO::query\'2' => ['PDOStatement|false', 'query'=>'string', 'fetch_class'=>'int', 'classname'=>'string', 'constructorArgs'=>'array'], 'PDO::query\'3' => ['PDOStatement|false', 'query'=>'string', 'fetch_into'=>'int', 'object'=>'object'], 'PDO::quote' => ['string|false', 'string'=>'string', 'type='=>'int'], 'PDO::rollBack' => ['bool'], 'PDO::setAttribute' => ['bool', 'attribute'=>'int', 'value'=>''], 'PDO::sqliteCreateAggregate' => ['bool', 'function_name'=>'string', 'step_func'=>'callable', 'finalize_func'=>'callable', 'num_args='=>'int'], 'PDO::sqliteCreateCollation' => ['bool', 'name'=>'string', 'callback'=>'callable'], 'PDO::sqliteCreateFunction' => ['bool', 'function_name'=>'string', 'callback'=>'callable', 'num_args='=>'int'], 'PDOException::getCode' => ['int|string'], 'PDOException::getFile' => ['string'], 'PDOException::getLine' => ['int'], 'PDOException::getMessage' => ['string'], 'PDOException::getPrevious' => ['?Throwable'], 'PDOException::getTrace' => ['list\',args?:array}>'], 'PDOException::getTraceAsString' => ['string'], 'PDOStatement::bindColumn' => ['bool', 'column'=>'string|int', '&rw_var'=>'mixed', 'type='=>'int', 'maxLength='=>'int', 'driverOptions='=>'mixed'], 'PDOStatement::bindParam' => ['bool', 'param'=>'string|int', '&rw_var'=>'mixed', 'type='=>'int', 'maxLength='=>'int', 'driverOptions='=>'mixed'], 'PDOStatement::bindValue' => ['bool', 'param'=>'string|int', 'value'=>'mixed', 'type='=>'int'], 'PDOStatement::closeCursor' => ['bool'], 'PDOStatement::columnCount' => ['int'], 'PDOStatement::debugDumpParams' => ['void'], 'PDOStatement::errorCode' => ['string'], 'PDOStatement::errorInfo' => ['array{0: ?string, 1: ?int, 2: ?string, 3?: mixed, 4?: mixed}'], 'PDOStatement::execute' => ['bool', 'bound_input_params='=>'?array'], 'PDOStatement::fetch' => ['mixed', 'how='=>'int', 'orientation='=>'int', 'offset='=>'int'], 'PDOStatement::fetchAll' => ['array|false', 'how='=>'int', 'fetch_argument='=>'int|string|callable', 'ctor_args='=>'?array'], 'PDOStatement::fetchColumn' => ['string|int|float|bool|null', 'column_number='=>'int'], 'PDOStatement::fetchObject' => ['object|false', 'class='=>'?class-string', 'constructorArgs='=>'array'], 'PDOStatement::getAttribute' => ['mixed', 'name'=>'int'], 'PDOStatement::getColumnMeta' => ['array|false', 'column'=>'int'], 'PDOStatement::nextRowset' => ['bool'], 'PDOStatement::rowCount' => ['int'], 'PDOStatement::setAttribute' => ['bool', 'attribute'=>'int', 'value'=>'mixed'], 'PDOStatement::setFetchMode' => ['bool', 'mode'=>'int'], 'PDOStatement::setFetchMode\'1' => ['bool', 'fetch_column'=>'int', 'colno'=>'int'], 'PDOStatement::setFetchMode\'2' => ['bool', 'fetch_class'=>'int', 'classname'=>'string', 'ctorargs'=>'array'], 'PDOStatement::setFetchMode\'3' => ['bool', 'fetch_into'=>'int', 'object'=>'object'], 'ParentIterator::__construct' => ['void', 'iterator'=>'RecursiveIterator'], 'ParentIterator::accept' => ['bool'], 'ParentIterator::getChildren' => ['?ParentIterator'], 'ParentIterator::hasChildren' => ['bool'], 'ParentIterator::next' => ['void'], 'ParentIterator::rewind' => ['void'], 'ParentIterator::valid' => ['bool'], 'Parle\Lexer::advance' => ['void'], 'Parle\Lexer::build' => ['void'], 'Parle\Lexer::callout' => ['void', 'id'=>'int', 'callback'=>'callable'], 'Parle\Lexer::consume' => ['void', 'data'=>'string'], 'Parle\Lexer::dump' => ['void'], 'Parle\Lexer::getToken' => ['Parle\Token'], 'Parle\Lexer::insertMacro' => ['void', 'name'=>'string', 'regex'=>'string'], 'Parle\Lexer::push' => ['void', 'regex'=>'string', 'id'=>'int'], 'Parle\Lexer::reset' => ['void', 'pos'=>'int'], 'Parle\Parser::advance' => ['void'], 'Parle\Parser::build' => ['void'], 'Parle\Parser::consume' => ['void', 'data'=>'string', 'lexer'=>'Parle\Lexer'], 'Parle\Parser::dump' => ['void'], 'Parle\Parser::errorInfo' => ['Parle\ErrorInfo'], 'Parle\Parser::left' => ['void', 'token'=>'string'], 'Parle\Parser::nonassoc' => ['void', 'token'=>'string'], 'Parle\Parser::precedence' => ['void', 'token'=>'string'], 'Parle\Parser::push' => ['int', 'name'=>'string', 'rule'=>'string'], 'Parle\Parser::reset' => ['void', 'tokenId'=>'int'], 'Parle\Parser::right' => ['void', 'token'=>'string'], 'Parle\Parser::sigil' => ['string', 'idx'=>'array'], 'Parle\Parser::token' => ['void', 'token'=>'string'], 'Parle\Parser::tokenId' => ['int', 'token'=>'string'], 'Parle\Parser::trace' => ['string'], 'Parle\Parser::validate' => ['bool', 'data'=>'string', 'lexer'=>'Parle\Lexer'], 'Parle\RLexer::advance' => ['void'], 'Parle\RLexer::build' => ['void'], 'Parle\RLexer::callout' => ['void', 'id'=>'int', 'callback'=>'callable'], 'Parle\RLexer::consume' => ['void', 'data'=>'string'], 'Parle\RLexer::dump' => ['void'], 'Parle\RLexer::getToken' => ['Parle\Token'], 'Parle\RLexer::push' => ['void', 'state'=>'string', 'regex'=>'string', 'newState'=>'string'], 'Parle\RLexer::pushState' => ['int', 'state'=>'string'], 'Parle\RLexer::reset' => ['void', 'pos'=>'int'], 'Parle\RParser::advance' => ['void'], 'Parle\RParser::build' => ['void'], 'Parle\RParser::consume' => ['void', 'data'=>'string', 'lexer'=>'Parle\Lexer'], 'Parle\RParser::dump' => ['void'], 'Parle\RParser::errorInfo' => ['Parle\ErrorInfo'], 'Parle\RParser::left' => ['void', 'token'=>'string'], 'Parle\RParser::nonassoc' => ['void', 'token'=>'string'], 'Parle\RParser::precedence' => ['void', 'token'=>'string'], 'Parle\RParser::push' => ['int', 'name'=>'string', 'rule'=>'string'], 'Parle\RParser::reset' => ['void', 'tokenId'=>'int'], 'Parle\RParser::right' => ['void', 'token'=>'string'], 'Parle\RParser::sigil' => ['string', 'idx'=>'array'], 'Parle\RParser::token' => ['void', 'token'=>'string'], 'Parle\RParser::tokenId' => ['int', 'token'=>'string'], 'Parle\RParser::trace' => ['string'], 'Parle\RParser::validate' => ['bool', 'data'=>'string', 'lexer'=>'Parle\Lexer'], 'Parle\Stack::pop' => ['void'], 'Parle\Stack::push' => ['void', 'item'=>'mixed'], 'ParseError::__clone' => ['void'], 'ParseError::__construct' => ['void', 'message='=>'string', 'code='=>'int', 'previous='=>'?Throwable'], 'ParseError::__toString' => ['string'], 'ParseError::getCode' => ['int'], 'ParseError::getFile' => ['string'], 'ParseError::getLine' => ['int'], 'ParseError::getMessage' => ['string'], 'ParseError::getPrevious' => ['?Throwable'], 'ParseError::getTrace' => ['list\',args?:array}>'], 'ParseError::getTraceAsString' => ['string'], 'Phar::__construct' => ['void', 'filename'=>'string', 'flags='=>'int', 'alias='=>'?string'], 'Phar::addEmptyDir' => ['void', 'directory'=>'string'], 'Phar::addFile' => ['void', 'filename'=>'string', 'localName='=>'string'], 'Phar::addFromString' => ['void', 'localName'=>'string', 'contents'=>'string'], 'Phar::apiVersion' => ['string'], 'Phar::buildFromDirectory' => ['array|false', 'directory'=>'string', 'pattern='=>'string'], 'Phar::buildFromIterator' => ['array|false', 'iterator'=>'Traversable', 'baseDirectory='=>'string'], 'Phar::canCompress' => ['bool', 'compression='=>'int'], 'Phar::canWrite' => ['bool'], 'Phar::compress' => ['?Phar', 'compression'=>'int', 'extension='=>'string'], 'Phar::compressFiles' => ['void', 'compression'=>'int'], 'Phar::convertToData' => ['?PharData', 'format='=>'int', 'compression='=>'int', 'extension='=>'string'], 'Phar::convertToExecutable' => ['?Phar', 'format='=>'int', 'compression='=>'int', 'extension='=>'string'], 'Phar::copy' => ['bool', 'from'=>'string', 'to'=>'string'], 'Phar::count' => ['int', 'mode='=>'int'], 'Phar::createDefaultStub' => ['string', 'index='=>'string', 'webIndex='=>'string'], 'Phar::decompress' => ['?Phar', 'extension='=>'string'], 'Phar::decompressFiles' => ['bool'], 'Phar::delMetadata' => ['bool'], 'Phar::delete' => ['bool', 'localName'=>'string'], 'Phar::extractTo' => ['bool', 'directory'=>'string', 'files='=>'string|array|null', 'overwrite='=>'bool'], 'Phar::getAlias' => ['?string'], 'Phar::getMetadata' => ['mixed'], 'Phar::getModified' => ['bool'], 'Phar::getPath' => ['string'], 'Phar::getSignature' => ['array{hash:string, hash_type:string}'], 'Phar::getStub' => ['string'], 'Phar::getSupportedCompression' => ['array'], 'Phar::getSupportedSignatures' => ['array'], 'Phar::getVersion' => ['string'], 'Phar::hasMetadata' => ['bool'], 'Phar::interceptFileFuncs' => ['void'], 'Phar::isBuffering' => ['bool'], 'Phar::isCompressed' => ['int|false'], 'Phar::isFileFormat' => ['bool', 'format'=>'int'], 'Phar::isValidPharFilename' => ['bool', 'filename'=>'string', 'executable='=>'bool'], 'Phar::isWritable' => ['bool'], 'Phar::loadPhar' => ['bool', 'filename'=>'string', 'alias='=>'?string'], 'Phar::mapPhar' => ['bool', 'alias='=>'?string', 'offset='=>'int'], 'Phar::mount' => ['void', 'pharPath'=>'string', 'externalPath'=>'string'], 'Phar::mungServer' => ['void', 'variables'=>'list'], 'Phar::offsetExists' => ['bool', 'localName'=>'string'], 'Phar::offsetGet' => ['PharFileInfo', 'localName'=>'string'], 'Phar::offsetSet' => ['void', 'localName'=>'string', 'value'=>'resource|string'], 'Phar::offsetUnset' => ['void', 'localName'=>'string'], 'Phar::running' => ['string', 'returnPhar='=>'bool'], 'Phar::setAlias' => ['bool', 'alias'=>'string'], 'Phar::setDefaultStub' => ['bool', 'index='=>'?string', 'webIndex='=>'string'], 'Phar::setMetadata' => ['void', 'metadata'=>''], 'Phar::setSignatureAlgorithm' => ['void', 'algo'=>'int', 'privateKey='=>'string'], 'Phar::setStub' => ['bool', 'stub'=>'string', 'length='=>'int'], 'Phar::startBuffering' => ['void'], 'Phar::stopBuffering' => ['void'], 'Phar::unlinkArchive' => ['bool', 'filename'=>'string'], 'Phar::webPhar' => ['void', 'alias='=>'?string', 'index='=>'?string', 'fileNotFoundScript='=>'string', 'mimeTypes='=>'array', 'rewrite='=>'callable'], 'PharData::__construct' => ['void', 'filename'=>'string', 'flags='=>'int', 'alias='=>'?string', 'format='=>'int'], 'PharData::addEmptyDir' => ['void', 'directory'=>'string'], 'PharData::addFile' => ['void', 'filename'=>'string', 'localName='=>'string'], 'PharData::addFromString' => ['void', 'localName'=>'string', 'contents'=>'string'], 'PharData::buildFromDirectory' => ['array|false', 'directory'=>'string', 'pattern='=>'string'], 'PharData::buildFromIterator' => ['array|false', 'iterator'=>'Traversable', 'baseDirectory='=>'string'], 'PharData::compress' => ['?PharData', 'compression'=>'int', 'extension='=>'string'], 'PharData::compressFiles' => ['void', 'compression'=>'int'], 'PharData::convertToData' => ['?PharData', 'format='=>'int', 'compression='=>'int', 'extension='=>'string'], 'PharData::convertToExecutable' => ['?Phar', 'format='=>'int', 'compression='=>'int', 'extension='=>'string'], 'PharData::copy' => ['bool', 'from'=>'string', 'to'=>'string'], 'PharData::decompress' => ['?PharData', 'extension='=>'string'], 'PharData::decompressFiles' => ['bool'], 'PharData::delMetadata' => ['bool'], 'PharData::delete' => ['bool', 'localName'=>'string'], 'PharData::extractTo' => ['bool', 'directory'=>'string', 'files='=>'string|array|null', 'overwrite='=>'bool'], 'PharData::isWritable' => ['bool'], 'PharData::offsetExists' => ['bool', 'localName'=>'string'], 'PharData::offsetGet' => ['PharFileInfo', 'localName'=>'string'], 'PharData::offsetSet' => ['void', 'localName'=>'string', 'value'=>'string'], 'PharData::offsetUnset' => ['void', 'localName'=>'string'], 'PharData::setAlias' => ['bool', 'alias'=>'string'], 'PharData::setDefaultStub' => ['bool', 'index='=>'?string', 'webIndex='=>'string'], 'PharData::setMetadata' => ['void', 'metadata'=>'mixed'], 'PharData::setSignatureAlgorithm' => ['void', 'algo'=>'int', 'privateKey='=>'string'], 'PharData::setStub' => ['bool', 'stub'=>'string', 'length='=>'int'], 'PharFileInfo::__construct' => ['void', 'filename'=>'string'], 'PharFileInfo::chmod' => ['void', 'perms'=>'int'], 'PharFileInfo::compress' => ['bool', 'compression'=>'int'], 'PharFileInfo::decompress' => ['bool'], 'PharFileInfo::delMetadata' => ['bool'], 'PharFileInfo::getCRC32' => ['int'], 'PharFileInfo::getCompressedSize' => ['int'], 'PharFileInfo::getContent' => ['string'], 'PharFileInfo::getMetadata' => ['mixed'], 'PharFileInfo::getPharFlags' => ['int'], 'PharFileInfo::hasMetadata' => ['bool'], 'PharFileInfo::isCRCChecked' => ['bool'], 'PharFileInfo::isCompressed' => ['bool', 'compression='=>'int'], 'PharFileInfo::setMetadata' => ['void', 'metadata'=>'mixed'], 'Pool::__construct' => ['void', 'size'=>'int', 'class'=>'string', 'ctor='=>'array'], 'Pool::collect' => ['int', 'collector='=>'Callable'], 'Pool::resize' => ['void', 'size'=>'int'], 'Pool::shutdown' => ['void'], 'Pool::submit' => ['int', 'task'=>'Threaded'], 'Pool::submitTo' => ['int', 'worker'=>'int', 'task'=>'Threaded'], 'Postal\Expand::expand_address' => ['string[]', 'address'=>'string', 'options='=>'array'], 'Postal\Parser::parse_address' => ['array', 'address'=>'string', 'options='=>'array'], 'QuickHashIntHash::__construct' => ['void', 'size'=>'int', 'options='=>'int'], 'QuickHashIntHash::add' => ['bool', 'key'=>'int', 'value='=>'int'], 'QuickHashIntHash::delete' => ['bool', 'key'=>'int'], 'QuickHashIntHash::exists' => ['bool', 'key'=>'int'], 'QuickHashIntHash::get' => ['int', 'key'=>'int'], 'QuickHashIntHash::getSize' => ['int'], 'QuickHashIntHash::loadFromFile' => ['QuickHashIntHash', 'filename'=>'string', 'options='=>'int'], 'QuickHashIntHash::loadFromString' => ['QuickHashIntHash', 'contents'=>'string', 'options='=>'int'], 'QuickHashIntHash::saveToFile' => ['void', 'filename'=>'string'], 'QuickHashIntHash::saveToString' => ['string'], 'QuickHashIntHash::set' => ['bool', 'key'=>'int', 'value'=>'int'], 'QuickHashIntHash::update' => ['bool', 'key'=>'int', 'value'=>'int'], 'QuickHashIntSet::__construct' => ['void', 'size'=>'int', 'options='=>'int'], 'QuickHashIntSet::add' => ['bool', 'key'=>'int'], 'QuickHashIntSet::delete' => ['bool', 'key'=>'int'], 'QuickHashIntSet::exists' => ['bool', 'key'=>'int'], 'QuickHashIntSet::getSize' => ['int'], 'QuickHashIntSet::loadFromFile' => ['QuickHashIntSet', 'filename'=>'string', 'size='=>'int', 'options='=>'int'], 'QuickHashIntSet::loadFromString' => ['QuickHashIntSet', 'contents'=>'string', 'size='=>'int', 'options='=>'int'], 'QuickHashIntSet::saveToFile' => ['void', 'filename'=>'string'], 'QuickHashIntSet::saveToString' => ['string'], 'QuickHashIntStringHash::__construct' => ['void', 'size'=>'int', 'options='=>'int'], 'QuickHashIntStringHash::add' => ['bool', 'key'=>'int', 'value'=>'string'], 'QuickHashIntStringHash::delete' => ['bool', 'key'=>'int'], 'QuickHashIntStringHash::exists' => ['bool', 'key'=>'int'], 'QuickHashIntStringHash::get' => ['mixed', 'key'=>'int'], 'QuickHashIntStringHash::getSize' => ['int'], 'QuickHashIntStringHash::loadFromFile' => ['QuickHashIntStringHash', 'filename'=>'string', 'size='=>'int', 'options='=>'int'], 'QuickHashIntStringHash::loadFromString' => ['QuickHashIntStringHash', 'contents'=>'string', 'size='=>'int', 'options='=>'int'], 'QuickHashIntStringHash::saveToFile' => ['void', 'filename'=>'string'], 'QuickHashIntStringHash::saveToString' => ['string'], 'QuickHashIntStringHash::set' => ['int', 'key'=>'int', 'value'=>'string'], 'QuickHashIntStringHash::update' => ['bool', 'key'=>'int', 'value'=>'string'], 'QuickHashStringIntHash::__construct' => ['void', 'size'=>'int', 'options='=>'int'], 'QuickHashStringIntHash::add' => ['bool', 'key'=>'string', 'value'=>'int'], 'QuickHashStringIntHash::delete' => ['bool', 'key'=>'string'], 'QuickHashStringIntHash::exists' => ['bool', 'key'=>'string'], 'QuickHashStringIntHash::get' => ['mixed', 'key'=>'string'], 'QuickHashStringIntHash::getSize' => ['int'], 'QuickHashStringIntHash::loadFromFile' => ['QuickHashStringIntHash', 'filename'=>'string', 'size='=>'int', 'options='=>'int'], 'QuickHashStringIntHash::loadFromString' => ['QuickHashStringIntHash', 'contents'=>'string', 'size='=>'int', 'options='=>'int'], 'QuickHashStringIntHash::saveToFile' => ['void', 'filename'=>'string'], 'QuickHashStringIntHash::saveToString' => ['string'], 'QuickHashStringIntHash::set' => ['int', 'key'=>'string', 'value'=>'int'], 'QuickHashStringIntHash::update' => ['bool', 'key'=>'string', 'value'=>'int'], 'RRDCreator::__construct' => ['void', 'path'=>'string', 'starttime='=>'string', 'step='=>'int'], 'RRDCreator::addArchive' => ['void', 'description'=>'string'], 'RRDCreator::addDataSource' => ['void', 'description'=>'string'], 'RRDCreator::save' => ['bool'], 'RRDGraph::__construct' => ['void', 'path'=>'string'], 'RRDGraph::save' => ['array|false'], 'RRDGraph::saveVerbose' => ['array|false'], 'RRDGraph::setOptions' => ['void', 'options'=>'array'], 'RRDUpdater::__construct' => ['void', 'path'=>'string'], 'RRDUpdater::update' => ['bool', 'values'=>'array', 'time='=>'string'], 'RangeException::__clone' => ['void'], 'RangeException::__construct' => ['void', 'message='=>'string', 'code='=>'int', 'previous='=>'?Throwable'], 'RangeException::__toString' => ['string'], 'RangeException::getCode' => ['int'], 'RangeException::getFile' => ['string'], 'RangeException::getLine' => ['int'], 'RangeException::getMessage' => ['string'], 'RangeException::getPrevious' => ['?Throwable'], 'RangeException::getTrace' => ['list\',args?:array}>'], 'RangeException::getTraceAsString' => ['string'], 'RarArchive::__toString' => ['string'], 'RarArchive::close' => ['bool'], 'RarArchive::getComment' => ['string|null'], 'RarArchive::getEntries' => ['RarEntry[]|false'], 'RarArchive::getEntry' => ['RarEntry|false', 'entryname'=>'string'], 'RarArchive::isBroken' => ['bool'], 'RarArchive::isSolid' => ['bool'], 'RarArchive::open' => ['RarArchive|false', 'filename'=>'string', 'password='=>'string', 'volume_callback='=>'callable'], 'RarArchive::setAllowBroken' => ['bool', 'allow_broken'=>'bool'], 'RarEntry::__toString' => ['string'], 'RarEntry::extract' => ['bool', 'dir'=>'string', 'filepath='=>'string', 'password='=>'string', 'extended_data='=>'bool'], 'RarEntry::getAttr' => ['int|false'], 'RarEntry::getCrc' => ['string|false'], 'RarEntry::getFileTime' => ['string|false'], 'RarEntry::getHostOs' => ['int|false'], 'RarEntry::getMethod' => ['int|false'], 'RarEntry::getName' => ['string|false'], 'RarEntry::getPackedSize' => ['int|false'], 'RarEntry::getStream' => ['resource|false', 'password='=>'string'], 'RarEntry::getUnpackedSize' => ['int|false'], 'RarEntry::getVersion' => ['int|false'], 'RarEntry::isDirectory' => ['bool'], 'RarEntry::isEncrypted' => ['bool'], 'RarException::getCode' => ['int'], 'RarException::getFile' => ['string'], 'RarException::getLine' => ['int'], 'RarException::getMessage' => ['string'], 'RarException::getPrevious' => ['Exception|Throwable'], 'RarException::getTrace' => ['list\',args?:array}>'], 'RarException::getTraceAsString' => ['string'], 'RarException::isUsingExceptions' => ['bool'], 'RarException::setUsingExceptions' => ['RarEntry', 'using_exceptions'=>'bool'], 'RecursiveArrayIterator::__construct' => ['void', 'array='=>'array|object', 'flags='=>'int'], 'RecursiveArrayIterator::append' => ['void', 'value'=>'mixed'], 'RecursiveArrayIterator::asort' => ['true', 'flags='=>'int'], 'RecursiveArrayIterator::count' => ['int'], 'RecursiveArrayIterator::current' => ['mixed'], 'RecursiveArrayIterator::getArrayCopy' => ['array'], 'RecursiveArrayIterator::getChildren' => ['?RecursiveArrayIterator'], 'RecursiveArrayIterator::getFlags' => ['int'], 'RecursiveArrayIterator::hasChildren' => ['bool'], 'RecursiveArrayIterator::key' => ['string|int|null'], 'RecursiveArrayIterator::ksort' => ['true', 'flags='=>'int'], 'RecursiveArrayIterator::natcasesort' => ['true'], 'RecursiveArrayIterator::natsort' => ['true'], 'RecursiveArrayIterator::next' => ['void'], 'RecursiveArrayIterator::offsetExists' => ['bool', 'key'=>'string|int'], 'RecursiveArrayIterator::offsetGet' => ['mixed', 'key'=>'string|int'], 'RecursiveArrayIterator::offsetSet' => ['void', 'key'=>'string|int|null', 'value'=>'string'], 'RecursiveArrayIterator::offsetUnset' => ['void', 'key'=>'string|int'], 'RecursiveArrayIterator::rewind' => ['void'], 'RecursiveArrayIterator::seek' => ['void', 'offset'=>'int'], 'RecursiveArrayIterator::serialize' => ['string'], 'RecursiveArrayIterator::setFlags' => ['void', 'flags'=>'int'], 'RecursiveArrayIterator::uasort' => ['true', 'callback'=>'callable(mixed,mixed):int'], 'RecursiveArrayIterator::uksort' => ['true', 'callback'=>'callable(mixed,mixed):int'], 'RecursiveArrayIterator::unserialize' => ['void', 'data'=>'string'], 'RecursiveArrayIterator::valid' => ['bool'], 'RecursiveCachingIterator::__construct' => ['void', 'iterator'=>'Iterator', 'flags='=>'int'], 'RecursiveCachingIterator::__toString' => ['string'], 'RecursiveCachingIterator::count' => ['int'], 'RecursiveCachingIterator::current' => ['void'], 'RecursiveCachingIterator::getCache' => ['array'], 'RecursiveCachingIterator::getChildren' => ['?RecursiveCachingIterator'], 'RecursiveCachingIterator::getFlags' => ['int'], 'RecursiveCachingIterator::getInnerIterator' => ['Iterator'], 'RecursiveCachingIterator::hasChildren' => ['bool'], 'RecursiveCachingIterator::hasNext' => ['bool'], 'RecursiveCachingIterator::key' => ['bool|float|int|string'], 'RecursiveCachingIterator::next' => ['void'], 'RecursiveCachingIterator::offsetExists' => ['bool', 'key'=>'string'], 'RecursiveCachingIterator::offsetGet' => ['string', 'key'=>'string'], 'RecursiveCachingIterator::offsetSet' => ['void', 'key'=>'string', 'value'=>'string'], 'RecursiveCachingIterator::offsetUnset' => ['void', 'key'=>'string'], 'RecursiveCachingIterator::rewind' => ['void'], 'RecursiveCachingIterator::setFlags' => ['void', 'flags'=>'int'], 'RecursiveCachingIterator::valid' => ['bool'], 'RecursiveCallbackFilterIterator::__construct' => ['void', 'iterator'=>'RecursiveIterator', 'callback'=>'callable(mixed,mixed=,mixed=):bool'], 'RecursiveCallbackFilterIterator::accept' => ['bool'], 'RecursiveCallbackFilterIterator::current' => ['mixed'], 'RecursiveCallbackFilterIterator::getChildren' => ['RecursiveCallbackFilterIterator'], 'RecursiveCallbackFilterIterator::getInnerIterator' => ['Iterator'], 'RecursiveCallbackFilterIterator::hasChildren' => ['bool'], 'RecursiveCallbackFilterIterator::key' => ['bool|float|int|string'], 'RecursiveCallbackFilterIterator::next' => ['void'], 'RecursiveCallbackFilterIterator::rewind' => ['void'], 'RecursiveCallbackFilterIterator::valid' => ['bool'], 'RecursiveDirectoryIterator::__construct' => ['void', 'directory'=>'string', 'flags='=>'int'], 'RecursiveDirectoryIterator::__toString' => ['string'], 'RecursiveDirectoryIterator::current' => ['string|SplFileInfo|FilesystemIterator'], 'RecursiveDirectoryIterator::getATime' => ['int'], 'RecursiveDirectoryIterator::getBasename' => ['string', 'suffix='=>'string'], 'RecursiveDirectoryIterator::getCTime' => ['int'], 'RecursiveDirectoryIterator::getChildren' => ['RecursiveDirectoryIterator'], 'RecursiveDirectoryIterator::getExtension' => ['string'], 'RecursiveDirectoryIterator::getFileInfo' => ['SplFileInfo', 'class='=>'class-string'], 'RecursiveDirectoryIterator::getFilename' => ['string'], 'RecursiveDirectoryIterator::getFlags' => ['int'], 'RecursiveDirectoryIterator::getGroup' => ['int'], 'RecursiveDirectoryIterator::getInode' => ['int'], 'RecursiveDirectoryIterator::getLinkTarget' => ['string'], 'RecursiveDirectoryIterator::getMTime' => ['int'], 'RecursiveDirectoryIterator::getOwner' => ['int'], 'RecursiveDirectoryIterator::getPath' => ['string'], 'RecursiveDirectoryIterator::getPathInfo' => ['?SplFileInfo', 'class='=>'class-string'], 'RecursiveDirectoryIterator::getPathname' => ['string'], 'RecursiveDirectoryIterator::getPerms' => ['int'], 'RecursiveDirectoryIterator::getRealPath' => ['non-falsy-string'], 'RecursiveDirectoryIterator::getSize' => ['int'], 'RecursiveDirectoryIterator::getSubPath' => ['string'], 'RecursiveDirectoryIterator::getSubPathname' => ['string'], 'RecursiveDirectoryIterator::getType' => ['string'], 'RecursiveDirectoryIterator::hasChildren' => ['bool', 'allowLinks='=>'bool'], 'RecursiveDirectoryIterator::isDir' => ['bool'], 'RecursiveDirectoryIterator::isDot' => ['bool'], 'RecursiveDirectoryIterator::isExecutable' => ['bool'], 'RecursiveDirectoryIterator::isFile' => ['bool'], 'RecursiveDirectoryIterator::isLink' => ['bool'], 'RecursiveDirectoryIterator::isReadable' => ['bool'], 'RecursiveDirectoryIterator::isWritable' => ['bool'], 'RecursiveDirectoryIterator::key' => ['string'], 'RecursiveDirectoryIterator::next' => ['void'], 'RecursiveDirectoryIterator::openFile' => ['SplFileObject', 'mode='=>'string', 'useIncludePath='=>'bool', 'context='=>'resource'], 'RecursiveDirectoryIterator::rewind' => ['void'], 'RecursiveDirectoryIterator::seek' => ['void', 'offset'=>'int'], 'RecursiveDirectoryIterator::setFileClass' => ['void', 'class='=>'class-string'], 'RecursiveDirectoryIterator::setFlags' => ['void', 'flags'=>'int'], 'RecursiveDirectoryIterator::setInfoClass' => ['void', 'class='=>'class-string'], 'RecursiveDirectoryIterator::valid' => ['bool'], 'RecursiveFilterIterator::__construct' => ['void', 'iterator'=>'RecursiveIterator'], 'RecursiveFilterIterator::accept' => ['bool'], 'RecursiveFilterIterator::current' => ['mixed'], 'RecursiveFilterIterator::getChildren' => ['?RecursiveFilterIterator'], 'RecursiveFilterIterator::getInnerIterator' => ['Iterator'], 'RecursiveFilterIterator::hasChildren' => ['bool'], 'RecursiveFilterIterator::key' => ['mixed'], 'RecursiveFilterIterator::next' => ['void'], 'RecursiveFilterIterator::rewind' => ['void'], 'RecursiveFilterIterator::valid' => ['bool'], 'RecursiveIterator::__construct' => ['void'], 'RecursiveIterator::current' => ['mixed'], 'RecursiveIterator::getChildren' => ['?RecursiveIterator'], 'RecursiveIterator::hasChildren' => ['bool'], 'RecursiveIterator::key' => ['int|string'], 'RecursiveIterator::next' => ['void'], 'RecursiveIterator::rewind' => ['void'], 'RecursiveIterator::valid' => ['bool'], 'RecursiveIteratorIterator::__construct' => ['void', 'iterator'=>'RecursiveIterator|IteratorAggregate', 'mode='=>'int', 'flags='=>'int'], 'RecursiveIteratorIterator::beginChildren' => ['void'], 'RecursiveIteratorIterator::beginIteration' => ['void'], 'RecursiveIteratorIterator::callGetChildren' => ['?RecursiveIterator'], 'RecursiveIteratorIterator::callHasChildren' => ['bool'], 'RecursiveIteratorIterator::current' => ['mixed'], 'RecursiveIteratorIterator::endChildren' => ['void'], 'RecursiveIteratorIterator::endIteration' => ['void'], 'RecursiveIteratorIterator::getDepth' => ['int'], 'RecursiveIteratorIterator::getInnerIterator' => ['RecursiveIterator'], 'RecursiveIteratorIterator::getMaxDepth' => ['int|false'], 'RecursiveIteratorIterator::getSubIterator' => ['?RecursiveIterator', 'level='=>'int'], 'RecursiveIteratorIterator::key' => ['mixed'], 'RecursiveIteratorIterator::next' => ['void'], 'RecursiveIteratorIterator::nextElement' => ['void'], 'RecursiveIteratorIterator::rewind' => ['void'], 'RecursiveIteratorIterator::setMaxDepth' => ['void', 'maxDepth='=>'int'], 'RecursiveIteratorIterator::valid' => ['bool'], 'RecursiveRegexIterator::__construct' => ['void', 'iterator'=>'RecursiveIterator', 'pattern'=>'string', 'mode='=>'int', 'flags='=>'int', 'pregFlags='=>'int'], 'RecursiveRegexIterator::accept' => ['bool'], 'RecursiveRegexIterator::current' => ['mixed'], 'RecursiveRegexIterator::getChildren' => ['RecursiveRegexIterator'], 'RecursiveRegexIterator::getFlags' => ['int'], 'RecursiveRegexIterator::getInnerIterator' => ['Iterator'], 'RecursiveRegexIterator::getMode' => ['int'], 'RecursiveRegexIterator::getPregFlags' => ['int'], 'RecursiveRegexIterator::getRegex' => ['string'], 'RecursiveRegexIterator::hasChildren' => ['bool'], 'RecursiveRegexIterator::key' => ['mixed'], 'RecursiveRegexIterator::next' => ['void'], 'RecursiveRegexIterator::rewind' => ['void'], 'RecursiveRegexIterator::setFlags' => ['void', 'flags'=>'int'], 'RecursiveRegexIterator::setMode' => ['void', 'mode'=>'int'], 'RecursiveRegexIterator::setPregFlags' => ['void', 'pregFlags'=>'int'], 'RecursiveRegexIterator::valid' => ['bool'], 'RecursiveTreeIterator::__construct' => ['void', 'iterator'=>'RecursiveIterator|IteratorAggregate', 'flags='=>'int', 'cachingIteratorFlags='=>'int', 'mode='=>'int'], 'RecursiveTreeIterator::beginChildren' => ['void'], 'RecursiveTreeIterator::beginIteration' => ['void'], 'RecursiveTreeIterator::callGetChildren' => ['?RecursiveIterator'], 'RecursiveTreeIterator::callHasChildren' => ['bool'], 'RecursiveTreeIterator::current' => ['string'], 'RecursiveTreeIterator::endChildren' => ['void'], 'RecursiveTreeIterator::endIteration' => ['void'], 'RecursiveTreeIterator::getDepth' => ['int'], 'RecursiveTreeIterator::getEntry' => ['string'], 'RecursiveTreeIterator::getInnerIterator' => ['RecursiveIterator'], 'RecursiveTreeIterator::getMaxDepth' => ['false|int'], 'RecursiveTreeIterator::getPostfix' => ['string'], 'RecursiveTreeIterator::getPrefix' => ['string'], 'RecursiveTreeIterator::getSubIterator' => ['?RecursiveIterator', 'level='=>'int'], 'RecursiveTreeIterator::key' => ['string'], 'RecursiveTreeIterator::next' => ['void'], 'RecursiveTreeIterator::nextElement' => ['void'], 'RecursiveTreeIterator::rewind' => ['void'], 'RecursiveTreeIterator::setMaxDepth' => ['void', 'maxDepth='=>'int'], 'RecursiveTreeIterator::setPostfix' => ['void', 'postfix'=>'string'], 'RecursiveTreeIterator::setPrefixPart' => ['void', 'part'=>'int', 'value'=>'string'], 'RecursiveTreeIterator::valid' => ['bool'], 'Redis::__construct' => ['void'], 'Redis::__destruct' => ['void'], 'Redis::_prefix' => ['string', 'value'=>'mixed'], 'Redis::_serialize' => ['mixed', 'value'=>'mixed'], 'Redis::_unserialize' => ['mixed', 'value'=>'string'], 'Redis::append' => ['int', 'key'=>'string', 'value'=>'string'], 'Redis::auth' => ['bool', 'password'=>'string'], 'Redis::bgRewriteAOF' => ['bool'], 'Redis::bgSave' => ['bool'], 'Redis::bitCount' => ['int', 'key'=>'string'], 'Redis::bitOp' => ['int', 'operation'=>'string', 'ret_key'=>'string', 'key'=>'string', '...other_keys='=>'string'], 'Redis::bitpos' => ['int', 'key'=>'string', 'bit'=>'int', 'start='=>'int', 'end='=>'int'], 'Redis::blPop' => ['array', 'keys'=>'string[]', 'timeout'=>'int'], 'Redis::blPop\'1' => ['array', 'key'=>'string', 'timeout_or_key'=>'int|string', '...extra_args'=>'int|string'], 'Redis::brPop' => ['array', 'keys'=>'string[]', 'timeout'=>'int'], 'Redis::brPop\'1' => ['array', 'key'=>'string', 'timeout_or_key'=>'int|string', '...extra_args'=>'int|string'], 'Redis::brpoplpush' => ['string|false', 'srcKey'=>'string', 'dstKey'=>'string', 'timeout'=>'int'], 'Redis::clearLastError' => ['bool'], 'Redis::client' => ['mixed', 'command'=>'string', 'arg='=>'string'], 'Redis::close' => ['bool'], 'Redis::command' => ['', '...args'=>''], 'Redis::config' => ['string', 'operation'=>'string', 'key'=>'string', 'value='=>'string'], 'Redis::connect' => ['bool', 'host'=>'string', 'port='=>'int', 'timeout='=>'float', 'reserved='=>'null', 'retry_interval='=>'?int', 'read_timeout='=>'float'], 'Redis::dbSize' => ['int'], 'Redis::debug' => ['', 'key'=>''], 'Redis::decr' => ['int', 'key'=>'string'], 'Redis::decrBy' => ['int', 'key'=>'string', 'value'=>'int'], 'Redis::decrByFloat' => ['float', 'key'=>'string', 'value'=>'float'], 'Redis::del' => ['int', 'key'=>'string', '...args'=>'string'], 'Redis::del\'1' => ['int', 'key'=>'string[]'], 'Redis::delete' => ['int', 'key'=>'string', '...args'=>'string'], 'Redis::delete\'1' => ['int', 'key'=>'string[]'], 'Redis::discard' => [''], 'Redis::dump' => ['string|false', 'key'=>'string'], 'Redis::echo' => ['string', 'message'=>'string'], 'Redis::eval' => ['mixed', 'script'=>'', 'args='=>'', 'numKeys='=>''], 'Redis::evalSha' => ['mixed', 'scriptSha'=>'string', 'args='=>'array', 'numKeys='=>'int'], 'Redis::evaluate' => ['mixed', 'script'=>'string', 'args='=>'array', 'numKeys='=>'int'], 'Redis::evaluateSha' => ['', 'scriptSha'=>'string', 'args='=>'array', 'numKeys='=>'int'], 'Redis::exec' => ['array'], 'Redis::exists' => ['int', 'keys'=>'string|string[]'], 'Redis::exists\'1' => ['int', '...keys'=>'string'], 'Redis::expire' => ['bool', 'key'=>'string', 'ttl'=>'int'], 'Redis::expireAt' => ['bool', 'key'=>'string', 'expiry'=>'int'], 'Redis::flushAll' => ['bool', 'async='=>'bool'], 'Redis::flushDb' => ['bool', 'async='=>'bool'], 'Redis::geoAdd' => ['int', 'key'=>'string', 'longitude'=>'float', 'latitude'=>'float', 'member'=>'string', '...other_triples='=>'string|int|float'], 'Redis::geoDist' => ['float', 'key'=>'string', 'member1'=>'string', 'member2'=>'string', 'unit='=>'string'], 'Redis::geoHash' => ['array', 'key'=>'string', 'member'=>'string', '...other_members='=>'string'], 'Redis::geoPos' => ['array', 'key'=>'string', 'member'=>'string', '...members='=>'string'], 'Redis::geoRadius' => ['array|int', 'key'=>'string', 'longitude'=>'float', 'latitude'=>'float', 'radius'=>'float', 'unit'=>'float', 'options='=>'array'], 'Redis::geoRadiusByMember' => ['array|int', 'key'=>'string', 'member'=>'string', 'radius'=>'float', 'units'=>'string', 'options='=>'array'], 'Redis::get' => ['string|false', 'key'=>'string'], 'Redis::getAuth' => ['string|false|null'], 'Redis::getBit' => ['int', 'key'=>'string', 'offset'=>'int'], 'Redis::getDBNum' => ['int|false'], 'Redis::getHost' => ['string|false'], 'Redis::getKeys' => ['array', 'pattern'=>'string'], 'Redis::getLastError' => ['?string'], 'Redis::getMode' => ['int'], 'Redis::getMultiple' => ['array', 'keys'=>'string[]'], 'Redis::getOption' => ['int', 'name'=>'int'], 'Redis::getPersistentID' => ['string|false|null'], 'Redis::getPort' => ['int|false'], 'Redis::getRange' => ['int', 'key'=>'string', 'start'=>'int', 'end'=>'int'], 'Redis::getReadTimeout' => ['float|false'], 'Redis::getSet' => ['string', 'key'=>'string', 'string'=>'string'], 'Redis::getTimeout' => ['float|false'], 'Redis::hDel' => ['int|false', 'key'=>'string', 'hashKey1'=>'string', '...otherHashKeys='=>'string'], 'Redis::hExists' => ['bool', 'key'=>'string', 'hashKey'=>'string'], 'Redis::hGet' => ['string|false', 'key'=>'string', 'hashKey'=>'string'], 'Redis::hGetAll' => ['array', 'key'=>'string'], 'Redis::hIncrBy' => ['int', 'key'=>'string', 'hashKey'=>'string', 'value'=>'int'], 'Redis::hIncrByFloat' => ['float', 'key'=>'string', 'field'=>'string', 'increment'=>'float'], 'Redis::hKeys' => ['array', 'key'=>'string'], 'Redis::hLen' => ['int|false', 'key'=>'string'], 'Redis::hMGet' => ['array', 'key'=>'string', 'hashKeys'=>'array'], 'Redis::hMSet' => ['bool', 'key'=>'string', 'hashKeys'=>'array'], 'Redis::hScan' => ['array', 'key'=>'string', '&iterator'=>'int', 'pattern='=>'string', 'count='=>'int'], 'Redis::hSet' => ['int|false', 'key'=>'string', 'hashKey'=>'string', 'value'=>'string'], 'Redis::hSetNx' => ['bool', 'key'=>'string', 'hashKey'=>'string', 'value'=>'string'], 'Redis::hStrLen' => ['', 'key'=>'', 'member'=>''], 'Redis::hVals' => ['array', 'key'=>'string'], 'Redis::incr' => ['int', 'key'=>'string'], 'Redis::incrBy' => ['int', 'key'=>'string', 'value'=>'int'], 'Redis::incrByFloat' => ['float', 'key'=>'string', 'value'=>'float'], 'Redis::info' => ['array', 'option='=>'string'], 'Redis::isConnected' => ['bool'], 'Redis::keys' => ['array', 'pattern'=>'string'], 'Redis::lGet' => ['string', 'key'=>'string', 'index'=>'int'], 'Redis::lGetRange' => ['array', 'key'=>'string', 'start'=>'int', 'end'=>'int'], 'Redis::lIndex' => ['string|false', 'key'=>'string', 'index'=>'int'], 'Redis::lInsert' => ['int', 'key'=>'string', 'position'=>'int', 'pivot'=>'string', 'value'=>'string'], 'Redis::lLen' => ['int|false', 'key'=>'string'], 'Redis::lPop' => ['string|false', 'key'=>'string'], 'Redis::lPush' => ['int|false', 'key'=>'string', 'value1'=>'string', 'value2='=>'string', 'valueN='=>'string'], 'Redis::lPushx' => ['int|false', 'key'=>'string', 'value'=>'string'], 'Redis::lRange' => ['array', 'key'=>'string', 'start'=>'int', 'end'=>'int'], 'Redis::lRem' => ['int|false', 'key'=>'string', 'value'=>'string', 'count'=>'int'], 'Redis::lRemove' => ['int', 'key'=>'string', 'value'=>'string', 'count'=>'int'], 'Redis::lSet' => ['bool', 'key'=>'string', 'index'=>'int', 'value'=>'string'], 'Redis::lSize' => ['int', 'key'=>'string'], 'Redis::lTrim' => ['array|false', 'key'=>'string', 'start'=>'int', 'stop'=>'int'], 'Redis::lastSave' => ['int'], 'Redis::listTrim' => ['', 'key'=>'string', 'start'=>'int', 'stop'=>'int'], 'Redis::mGet' => ['array', 'keys'=>'string[]'], 'Redis::mSet' => ['bool', 'pairs'=>'array'], 'Redis::mSetNx' => ['bool', 'pairs'=>'array'], 'Redis::migrate' => ['bool', 'host'=>'string', 'port'=>'int', 'key'=>'string|string[]', 'db'=>'int', 'timeout'=>'int', 'copy='=>'bool', 'replace='=>'bool'], 'Redis::move' => ['bool', 'key'=>'string', 'dbindex'=>'int'], 'Redis::multi' => ['Redis', 'mode='=>'int'], 'Redis::object' => ['string|long|false', 'info'=>'string', 'key'=>'string'], 'Redis::open' => ['bool', 'host'=>'string', 'port='=>'int', 'timeout='=>'float', 'reserved='=>'null', 'retry_interval='=>'?int', 'read_timeout='=>'float'], 'Redis::pExpire' => ['bool', 'key'=>'string', 'ttl'=>'int'], 'Redis::pconnect' => ['bool', 'host'=>'string', 'port='=>'int', 'timeout='=>'float', 'persistent_id='=>'string', 'retry_interval='=>'?int'], 'Redis::persist' => ['bool', 'key'=>'string'], 'Redis::pexpireAt' => ['bool', 'key'=>'string', 'expiry'=>'int'], 'Redis::pfAdd' => ['bool', 'key'=>'string', 'elements'=>'array'], 'Redis::pfCount' => ['int', 'key'=>'array|string'], 'Redis::pfMerge' => ['bool', 'destkey'=>'string', 'sourcekeys'=>'array'], 'Redis::ping' => ['string'], 'Redis::pipeline' => ['Redis'], 'Redis::popen' => ['bool', 'host'=>'string', 'port='=>'int', 'timeout='=>'float', 'persistent_id='=>'string', 'retry_interval='=>'?int'], 'Redis::psetex' => ['bool', 'key'=>'string', 'ttl'=>'int', 'value'=>'string'], 'Redis::psubscribe' => ['', 'patterns'=>'array', 'callback'=>'array|string'], 'Redis::pttl' => ['int|false', 'key'=>'string'], 'Redis::publish' => ['int', 'channel'=>'string', 'message'=>'string'], 'Redis::pubsub' => ['array|int', 'keyword'=>'string', 'argument='=>'array|string'], 'Redis::punsubscribe' => ['', 'pattern'=>'string', '...other_patterns='=>'string'], 'Redis::rPop' => ['string|false', 'key'=>'string'], 'Redis::rPush' => ['int|false', 'key'=>'string', 'value1'=>'string', 'value2='=>'string', 'valueN='=>'string'], 'Redis::rPushx' => ['int|false', 'key'=>'string', 'value'=>'string'], 'Redis::randomKey' => ['string'], 'Redis::rawCommand' => ['mixed', 'command'=>'string', '...arguments='=>'mixed'], 'Redis::rename' => ['bool', 'srckey'=>'string', 'dstkey'=>'string'], 'Redis::renameKey' => ['bool', 'srckey'=>'string', 'dstkey'=>'string'], 'Redis::renameNx' => ['bool', 'srckey'=>'string', 'dstkey'=>'string'], 'Redis::resetStat' => ['bool'], 'Redis::restore' => ['bool', 'key'=>'string', 'ttl'=>'int', 'value'=>'string'], 'Redis::role' => ['array', 'nodeParams'=>'string|array{0:string,1:int}'], 'Redis::rpoplpush' => ['string', 'srcKey'=>'string', 'dstKey'=>'string'], 'Redis::sAdd' => ['int|false', 'key'=>'string', 'value1'=>'string', 'value2='=>'string', 'valueN='=>'string'], 'Redis::sAddArray' => ['bool', 'key'=>'string', 'values'=>'array'], 'Redis::sCard' => ['int', 'key'=>'string'], 'Redis::sContains' => ['', 'key'=>'string', 'value'=>'string'], 'Redis::sDiff' => ['array', 'key1'=>'string', '...other_keys='=>'string'], 'Redis::sDiffStore' => ['int|false', 'dstKey'=>'string', 'key'=>'string', '...other_keys='=>'string'], 'Redis::sGetMembers' => ['', 'key'=>'string'], 'Redis::sInter' => ['array|false', 'key'=>'string', '...other_keys='=>'string'], 'Redis::sInterStore' => ['int|false', 'dstKey'=>'string', 'key'=>'string', '...other_keys='=>'string'], 'Redis::sIsMember' => ['bool', 'key'=>'string', 'value'=>'string'], 'Redis::sMembers' => ['array', 'key'=>'string'], 'Redis::sMove' => ['bool', 'srcKey'=>'string', 'dstKey'=>'string', 'member'=>'string'], 'Redis::sPop' => ['string|false', 'key'=>'string'], 'Redis::sRandMember' => ['array|string|false', 'key'=>'string', 'count='=>'int'], 'Redis::sRem' => ['int', 'key'=>'string', 'member1'=>'string', '...other_members='=>'string'], 'Redis::sRemove' => ['int', 'key'=>'string', 'member1'=>'string', '...other_members='=>'string'], 'Redis::sScan' => ['array|bool', 'key'=>'string', '&iterator'=>'int', 'pattern='=>'string', 'count='=>'int'], 'Redis::sSize' => ['int', 'key'=>'string'], 'Redis::sUnion' => ['array', 'key'=>'string', '...other_keys='=>'string'], 'Redis::sUnionStore' => ['int', 'dstKey'=>'string', 'key'=>'string', '...other_keys='=>'string'], 'Redis::save' => ['bool'], 'Redis::scan' => ['array|false', '&rw_iterator'=>'?int', 'pattern='=>'?string', 'count='=>'?int'], 'Redis::script' => ['mixed', 'command'=>'string', '...args='=>'mixed'], 'Redis::select' => ['bool', 'dbindex'=>'int'], 'Redis::sendEcho' => ['string', 'msg'=>'string'], 'Redis::set' => ['bool', 'key'=>'string', 'value'=>'mixed', 'options='=>'array'], 'Redis::set\'1' => ['bool', 'key'=>'string', 'value'=>'mixed', 'timeout='=>'int'], 'Redis::setBit' => ['int', 'key'=>'string', 'offset'=>'int', 'value'=>'int'], 'Redis::setEx' => ['bool', 'key'=>'string', 'ttl'=>'int', 'value'=>'string'], 'Redis::setNx' => ['bool', 'key'=>'string', 'value'=>'string'], 'Redis::setOption' => ['bool', 'name'=>'int', 'value'=>'mixed'], 'Redis::setRange' => ['int', 'key'=>'string', 'offset'=>'int', 'end'=>'int'], 'Redis::setTimeout' => ['', 'key'=>'string', 'ttl'=>'int'], 'Redis::slave' => ['bool', 'host'=>'string', 'port'=>'int'], 'Redis::slave\'1' => ['bool', 'host'=>'string', 'port'=>'int'], 'Redis::slaveof' => ['bool', 'host='=>'string', 'port='=>'int'], 'Redis::slowLog' => ['mixed', 'operation'=>'string', 'length='=>'int'], 'Redis::sort' => ['array|int', 'key'=>'string', 'options='=>'array'], 'Redis::sortAsc' => ['array', 'key'=>'string', 'pattern='=>'string', 'get='=>'string', 'start='=>'int', 'end='=>'int', 'getList='=>'bool'], 'Redis::sortAscAlpha' => ['array', 'key'=>'string', 'pattern='=>'', 'get='=>'string', 'start='=>'int', 'end='=>'int', 'getList='=>'bool'], 'Redis::sortDesc' => ['array', 'key'=>'string', 'pattern='=>'', 'get='=>'string', 'start='=>'int', 'end='=>'int', 'getList='=>'bool'], 'Redis::sortDescAlpha' => ['array', 'key'=>'string', 'pattern='=>'', 'get='=>'string', 'start='=>'int', 'end='=>'int', 'getList='=>'bool'], 'Redis::strLen' => ['int', 'key'=>'string'], 'Redis::subscribe' => ['mixed|null', 'channels'=>'array', 'callback'=>'string|array'], 'Redis::substr' => ['', 'key'=>'string', 'start'=>'int', 'end'=>'int'], 'Redis::swapdb' => ['bool', 'srcdb'=>'int', 'dstdb'=>'int'], 'Redis::time' => ['array'], 'Redis::ttl' => ['int|false', 'key'=>'string'], 'Redis::type' => ['int', 'key'=>'string'], 'Redis::unlink' => ['int', 'key'=>'string', '...args'=>'string'], 'Redis::unlink\'1' => ['int', 'key'=>'string[]'], 'Redis::unsubscribe' => ['', 'channel'=>'string', '...other_channels='=>'string'], 'Redis::unwatch' => [''], 'Redis::wait' => ['int', 'numSlaves'=>'int', 'timeout'=>'int'], 'Redis::watch' => ['void', 'key'=>'string', '...other_keys='=>'string'], 'Redis::xack' => ['', 'str_key'=>'string', 'str_group'=>'string', 'arr_ids'=>'array'], 'Redis::xadd' => ['', 'str_key'=>'string', 'str_id'=>'string', 'arr_fields'=>'array', 'i_maxlen='=>'', 'boo_approximate='=>''], 'Redis::xclaim' => ['', 'str_key'=>'string', 'str_group'=>'string', 'str_consumer'=>'string', 'i_min_idle'=>'', 'arr_ids'=>'array', 'arr_opts='=>'array'], 'Redis::xdel' => ['', 'str_key'=>'string', 'arr_ids'=>'array'], 'Redis::xgroup' => ['', 'str_operation'=>'string', 'str_key='=>'string', 'str_arg1='=>'', 'str_arg2='=>'', 'str_arg3='=>''], 'Redis::xinfo' => ['', 'str_cmd'=>'string', 'str_key='=>'string', 'str_group='=>'string'], 'Redis::xlen' => ['', 'key'=>''], 'Redis::xpending' => ['', 'str_key'=>'string', 'str_group'=>'string', 'str_start='=>'', 'str_end='=>'', 'i_count='=>'', 'str_consumer='=>'string'], 'Redis::xrange' => ['', 'str_key'=>'string', 'str_start'=>'', 'str_end'=>'', 'i_count='=>''], 'Redis::xread' => ['', 'arr_streams'=>'array', 'i_count='=>'', 'i_block='=>''], 'Redis::xreadgroup' => ['', 'str_group'=>'string', 'str_consumer'=>'string', 'arr_streams'=>'array', 'i_count='=>'', 'i_block='=>''], 'Redis::xrevrange' => ['', 'str_key'=>'string', 'str_start'=>'', 'str_end'=>'', 'i_count='=>''], 'Redis::xtrim' => ['', 'str_key'=>'string', 'i_maxlen'=>'', 'boo_approximate='=>''], 'Redis::zAdd' => ['int', 'key'=>'string', 'score1'=>'float', 'value1'=>'string', 'score2='=>'float', 'value2='=>'string', 'scoreN='=>'float', 'valueN='=>'string'], 'Redis::zAdd\'1' => ['int', 'options'=>'array', 'key'=>'string', 'score1'=>'float', 'value1'=>'string', 'score2='=>'float', 'value2='=>'string', 'scoreN='=>'float', 'valueN='=>'string'], 'Redis::zCard' => ['int', 'key'=>'string'], 'Redis::zCount' => ['int', 'key'=>'string', 'start'=>'string', 'end'=>'string'], 'Redis::zDelete' => ['int', 'key'=>'string', 'member'=>'string', '...other_members='=>'string'], 'Redis::zDeleteRangeByRank' => ['', 'key'=>'string', 'start'=>'int', 'end'=>'int'], 'Redis::zDeleteRangeByScore' => ['', 'key'=>'string', 'start'=>'float', 'end'=>'float'], 'Redis::zIncrBy' => ['float', 'key'=>'string', 'value'=>'float', 'member'=>'string'], 'Redis::zInter' => ['int', 'Output'=>'string', 'ZSetKeys'=>'array', 'Weights='=>'?array', 'aggregateFunction='=>'string'], 'Redis::zInterStore' => ['int', 'Output'=>'string', 'ZSetKeys'=>'array', 'Weights='=>'?array', 'aggregateFunction='=>'string'], 'Redis::zLexCount' => ['int', 'key'=>'string', 'min'=>'string', 'max'=>'string'], 'Redis::zRange' => ['array', 'key'=>'string', 'start'=>'int', 'end'=>'int', 'withscores='=>'bool'], 'Redis::zRangeByLex' => ['array|false', 'key'=>'string', 'min'=>'int', 'max'=>'int', 'offset='=>'int', 'limit='=>'int'], 'Redis::zRangeByScore' => ['array', 'key'=>'string', 'start'=>'int|string', 'end'=>'int|string', 'options='=>'array'], 'Redis::zRank' => ['int', 'key'=>'string', 'member'=>'string'], 'Redis::zRem' => ['int', 'key'=>'string', 'member'=>'string', '...other_members='=>'string'], 'Redis::zRemRangeByLex' => ['int', 'key'=>'string', 'min'=>'string', 'max'=>'string'], 'Redis::zRemRangeByRank' => ['int', 'key'=>'string', 'start'=>'int', 'end'=>'int'], 'Redis::zRemRangeByScore' => ['int', 'key'=>'string', 'start'=>'float|string', 'end'=>'float|string'], 'Redis::zRemove' => ['int', 'key'=>'string', 'member'=>'string', '...other_members='=>'string'], 'Redis::zRemoveRangeByRank' => ['int', 'key'=>'string', 'start'=>'int', 'end'=>'int'], 'Redis::zRemoveRangeByScore' => ['int', 'key'=>'string', 'start'=>'float|string', 'end'=>'float|string'], 'Redis::zRevRange' => ['array', 'key'=>'string', 'start'=>'int', 'end'=>'int', 'withscore='=>'bool'], 'Redis::zRevRangeByLex' => ['array', 'key'=>'string', 'min'=>'string', 'max'=>'string', 'offset='=>'int', 'limit='=>'int'], 'Redis::zRevRangeByScore' => ['array', 'key'=>'string', 'start'=>'string', 'end'=>'string', 'options='=>'array'], 'Redis::zRevRank' => ['int', 'key'=>'string', 'member'=>'string'], 'Redis::zReverseRange' => ['array', 'key'=>'string', 'start'=>'int', 'end'=>'int', 'withscore='=>'bool'], 'Redis::zScan' => ['array|bool', 'key'=>'string', '&iterator'=>'int', 'pattern='=>'string', 'count='=>'int'], 'Redis::zScore' => ['float|false', 'key'=>'string', 'member'=>'string'], 'Redis::zSize' => ['', 'key'=>'string'], 'Redis::zUnion' => ['int', 'Output'=>'string', 'ZSetKeys'=>'array', 'Weights='=>'?array', 'aggregateFunction='=>'string'], 'Redis::zUnionStore' => ['int', 'Output'=>'string', 'ZSetKeys'=>'array', 'Weights='=>'?array', 'aggregateFunction='=>'string'], 'RedisArray::__call' => ['mixed', 'function_name'=>'string', 'arguments'=>'array'], 'RedisArray::__construct' => ['void', 'name='=>'string', 'hosts='=>'?array', 'opts='=>'?array'], 'RedisArray::_continuum' => [''], 'RedisArray::_distributor' => [''], 'RedisArray::_function' => ['string'], 'RedisArray::_hosts' => ['array'], 'RedisArray::_instance' => ['', 'host'=>''], 'RedisArray::_rehash' => ['', 'callable='=>'callable'], 'RedisArray::_target' => ['string', 'key'=>'string'], 'RedisArray::bgsave' => [''], 'RedisArray::del' => ['bool', 'key'=>'string', '...args'=>'string'], 'RedisArray::delete' => ['bool', 'key'=>'string', '...args'=>'string'], 'RedisArray::delete\'1' => ['bool', 'key'=>'string[]'], 'RedisArray::discard' => [''], 'RedisArray::exec' => ['array'], 'RedisArray::flushAll' => ['bool', 'async='=>'bool'], 'RedisArray::flushDb' => ['bool', 'async='=>'bool'], 'RedisArray::getMultiple' => ['', 'keys'=>''], 'RedisArray::getOption' => ['', 'opt'=>''], 'RedisArray::info' => ['array'], 'RedisArray::keys' => ['array', 'pattern'=>''], 'RedisArray::mGet' => ['array', 'keys'=>'string[]'], 'RedisArray::mSet' => ['bool', 'pairs'=>'array'], 'RedisArray::multi' => ['RedisArray', 'host'=>'string', 'mode='=>'int'], 'RedisArray::ping' => ['string'], 'RedisArray::save' => ['bool'], 'RedisArray::select' => ['', 'index'=>''], 'RedisArray::setOption' => ['', 'opt'=>'', 'value'=>''], 'RedisArray::unlink' => ['int', 'key'=>'string', '...other_keys='=>'string'], 'RedisArray::unlink\'1' => ['int', 'key'=>'string[]'], 'RedisArray::unwatch' => [''], 'RedisCluster::__construct' => ['void', 'name'=>'?string', 'seeds='=>'string[]', 'timeout='=>'float', 'readTimeout='=>'float', 'persistent='=>'bool', 'auth='=>'?string'], 'RedisCluster::_masters' => ['array'], 'RedisCluster::_prefix' => ['string', 'value'=>'mixed'], 'RedisCluster::_redir' => [''], 'RedisCluster::_serialize' => ['mixed', 'value'=>'mixed'], 'RedisCluster::_unserialize' => ['mixed', 'value'=>'string'], 'RedisCluster::append' => ['int', 'key'=>'string', 'value'=>'string'], 'RedisCluster::bgrewriteaof' => ['bool', 'nodeParams'=>'string|array{0:string,1:int}'], 'RedisCluster::bgsave' => ['bool', 'nodeParams'=>'string|array{0:string,1:int}'], 'RedisCluster::bitCount' => ['int', 'key'=>'string'], 'RedisCluster::bitOp' => ['int', 'operation'=>'string', 'retKey'=>'string', 'key1'=>'string', '...other_keys='=>'string'], 'RedisCluster::bitpos' => ['int', 'key'=>'string', 'bit'=>'int', 'start='=>'int', 'end='=>'int'], 'RedisCluster::blPop' => ['array', 'keys'=>'array', 'timeout'=>'int'], 'RedisCluster::brPop' => ['array', 'keys'=>'array', 'timeout'=>'int'], 'RedisCluster::brpoplpush' => ['string|false', 'srcKey'=>'string', 'dstKey'=>'string', 'timeout'=>'int'], 'RedisCluster::clearLastError' => ['bool'], 'RedisCluster::client' => ['', 'nodeParams'=>'string|array{0:string,1:int}', 'subCmd='=>'string', '...args='=>''], 'RedisCluster::close' => [''], 'RedisCluster::cluster' => ['mixed', 'nodeParams'=>'string|array{0:string,1:int}', 'command'=>'string', 'arguments='=>'mixed'], 'RedisCluster::command' => ['array|bool'], 'RedisCluster::config' => ['array|bool', 'nodeParams'=>'string|array{0:string,1:int}', 'operation'=>'string', 'key'=>'string', 'value='=>'string'], 'RedisCluster::dbSize' => ['int', 'nodeParams'=>'string|array{0:string,1:int}'], 'RedisCluster::decr' => ['int', 'key'=>'string'], 'RedisCluster::decrBy' => ['int', 'key'=>'string', 'value'=>'int'], 'RedisCluster::del' => ['int', 'key'=>'string', '...other_keys='=>'string'], 'RedisCluster::del\'1' => ['int', 'key'=>'string[]'], 'RedisCluster::discard' => [''], 'RedisCluster::dump' => ['string|false', 'key'=>'string'], 'RedisCluster::echo' => ['string', 'nodeParams'=>'string|array{0:string,1:int}', 'msg'=>'string'], 'RedisCluster::eval' => ['mixed', 'script'=>'', 'args='=>'', 'numKeys='=>''], 'RedisCluster::evalSha' => ['mixed', 'scriptSha'=>'string', 'args='=>'array', 'numKeys='=>'int'], 'RedisCluster::exec' => ['array|void'], 'RedisCluster::exists' => ['bool', 'key'=>'string'], 'RedisCluster::expire' => ['bool', 'key'=>'string', 'ttl'=>'int'], 'RedisCluster::expireAt' => ['bool', 'key'=>'string', 'timestamp'=>'int'], 'RedisCluster::flushAll' => ['bool', 'nodeParams'=>'string|array{0:string,1:int}', 'async='=>'bool'], 'RedisCluster::flushDB' => ['bool', 'nodeParams'=>'string|array{0:string,1:int}', 'async='=>'bool'], 'RedisCluster::geoAdd' => ['int', 'key'=>'string', 'longitude'=>'float', 'latitude'=>'float', 'member'=>'string', '...other_members='=>'float|string'], 'RedisCluster::geoDist' => ['', 'key'=>'string', 'member1'=>'string', 'member2'=>'string', 'unit='=>'string'], 'RedisCluster::geoRadius' => ['', 'key'=>'string', 'longitude'=>'float', 'latitude'=>'float', 'radius'=>'float', 'radiusUnit'=>'string', 'options='=>'array'], 'RedisCluster::geoRadiusByMember' => ['string[]', 'key'=>'string', 'member'=>'string', 'radius'=>'float', 'radiusUnit'=>'string', 'options='=>'array'], 'RedisCluster::geohash' => ['array', 'key'=>'string', 'member'=>'string', '...other_members='=>'string'], 'RedisCluster::geopos' => ['array', 'key'=>'string', 'member'=>'string', '...other_members='=>'string'], 'RedisCluster::get' => ['string|false', 'key'=>'string'], 'RedisCluster::getBit' => ['int', 'key'=>'string', 'offset'=>'int'], 'RedisCluster::getLastError' => ['?string'], 'RedisCluster::getMode' => ['int'], 'RedisCluster::getOption' => ['int', 'option'=>'int'], 'RedisCluster::getRange' => ['string', 'key'=>'string', 'start'=>'int', 'end'=>'int'], 'RedisCluster::getSet' => ['string', 'key'=>'string', 'value'=>'string'], 'RedisCluster::hDel' => ['int|false', 'key'=>'string', 'hashKey'=>'string', '...other_hashKeys='=>'string[]'], 'RedisCluster::hExists' => ['bool', 'key'=>'string', 'hashKey'=>'string'], 'RedisCluster::hGet' => ['string|false', 'key'=>'string', 'hashKey'=>'string'], 'RedisCluster::hGetAll' => ['array', 'key'=>'string'], 'RedisCluster::hIncrBy' => ['int', 'key'=>'string', 'hashKey'=>'string', 'value'=>'int'], 'RedisCluster::hIncrByFloat' => ['float', 'key'=>'string', 'field'=>'string', 'increment'=>'float'], 'RedisCluster::hKeys' => ['array', 'key'=>'string'], 'RedisCluster::hLen' => ['int|false', 'key'=>'string'], 'RedisCluster::hMGet' => ['array', 'key'=>'string', 'hashKeys'=>'array'], 'RedisCluster::hMSet' => ['bool', 'key'=>'string', 'hashKeys'=>'array'], 'RedisCluster::hScan' => ['array', 'key'=>'string', '&iterator'=>'int', 'pattern='=>'string', 'count='=>'int'], 'RedisCluster::hSet' => ['int', 'key'=>'string', 'hashKey'=>'string', 'value'=>'string'], 'RedisCluster::hSetNx' => ['bool', 'key'=>'string', 'hashKey'=>'string', 'value'=>'string'], 'RedisCluster::hStrlen' => ['int', 'key'=>'string', 'member'=>'string'], 'RedisCluster::hVals' => ['array', 'key'=>'string'], 'RedisCluster::incr' => ['int', 'key'=>'string'], 'RedisCluster::incrBy' => ['int', 'key'=>'string', 'value'=>'int'], 'RedisCluster::incrByFloat' => ['float', 'key'=>'string', 'increment'=>'float'], 'RedisCluster::info' => ['array', 'nodeParams'=>'string|array{0:string,1:int}', 'option='=>'string'], 'RedisCluster::keys' => ['array', 'pattern'=>'string'], 'RedisCluster::lGet' => ['', 'key'=>'string', 'index'=>'int'], 'RedisCluster::lIndex' => ['string|false', 'key'=>'string', 'index'=>'int'], 'RedisCluster::lInsert' => ['int', 'key'=>'string', 'position'=>'int', 'pivot'=>'string', 'value'=>'string'], 'RedisCluster::lLen' => ['int', 'key'=>'string'], 'RedisCluster::lPop' => ['string|false', 'key'=>'string'], 'RedisCluster::lPush' => ['int|false', 'key'=>'string', 'value1'=>'string', 'value2='=>'string', 'valueN='=>'string'], 'RedisCluster::lPushx' => ['int|false', 'key'=>'string', 'value'=>'string'], 'RedisCluster::lRange' => ['array', 'key'=>'string', 'start'=>'int', 'end'=>'int'], 'RedisCluster::lRem' => ['int|false', 'key'=>'string', 'value'=>'string', 'count'=>'int'], 'RedisCluster::lSet' => ['bool', 'key'=>'string', 'index'=>'int', 'value'=>'string'], 'RedisCluster::lTrim' => ['array|false', 'key'=>'string', 'start'=>'int', 'stop'=>'int'], 'RedisCluster::lastSave' => ['int', 'nodeParams'=>'string|array{0:string,1:int}'], 'RedisCluster::mget' => ['array', 'array'=>'array'], 'RedisCluster::mset' => ['bool', 'array'=>'array'], 'RedisCluster::msetnx' => ['int', 'array'=>'array'], 'RedisCluster::multi' => ['Redis', 'mode='=>'int'], 'RedisCluster::object' => ['string|int|false', 'string'=>'string', 'key'=>'string'], 'RedisCluster::pExpire' => ['bool', 'key'=>'string', 'ttl'=>'int'], 'RedisCluster::pExpireAt' => ['bool', 'key'=>'string', 'timestamp'=>'int'], 'RedisCluster::persist' => ['bool', 'key'=>'string'], 'RedisCluster::pfAdd' => ['bool', 'key'=>'string', 'elements'=>'array'], 'RedisCluster::pfCount' => ['int', 'key'=>'string'], 'RedisCluster::pfMerge' => ['bool', 'destKey'=>'string', 'sourceKeys'=>'array'], 'RedisCluster::ping' => ['string', 'nodeParams'=>'string|array{0:string,1:int}'], 'RedisCluster::psetex' => ['bool', 'key'=>'string', 'ttl'=>'int', 'value'=>'string'], 'RedisCluster::psubscribe' => ['mixed', 'patterns'=>'array', 'callback'=>'string'], 'RedisCluster::pttl' => ['int', 'key'=>'string'], 'RedisCluster::publish' => ['int', 'channel'=>'string', 'message'=>'string'], 'RedisCluster::pubsub' => ['array', 'nodeParams'=>'string', 'keyword'=>'string', '...argument='=>'string'], 'RedisCluster::punSubscribe' => ['', 'channels'=>'', 'callback'=>''], 'RedisCluster::rPop' => ['string|false', 'key'=>'string'], 'RedisCluster::rPush' => ['int|false', 'key'=>'string', 'value1'=>'string', 'value2='=>'string', 'valueN='=>'string'], 'RedisCluster::rPushx' => ['int|false', 'key'=>'string', 'value'=>'string'], 'RedisCluster::randomKey' => ['string', 'nodeParams'=>'string|array{0:string,1:int}'], 'RedisCluster::rawCommand' => ['mixed', 'nodeParams'=>'string|array{0:string,1:int}', 'command'=>'string', 'arguments='=>'mixed'], 'RedisCluster::rename' => ['bool', 'srcKey'=>'string', 'dstKey'=>'string'], 'RedisCluster::renameNx' => ['bool', 'srcKey'=>'string', 'dstKey'=>'string'], 'RedisCluster::restore' => ['bool', 'key'=>'string', 'ttl'=>'int', 'value'=>'string'], 'RedisCluster::role' => ['array'], 'RedisCluster::rpoplpush' => ['string|false', 'srcKey'=>'string', 'dstKey'=>'string'], 'RedisCluster::sAdd' => ['int|false', 'key'=>'string', 'value1'=>'string', 'value2='=>'string', 'valueN='=>'string'], 'RedisCluster::sAddArray' => ['int|false', 'key'=>'string', 'valueArray'=>'array'], 'RedisCluster::sCard' => ['int', 'key'=>'string'], 'RedisCluster::sDiff' => ['list', 'key1'=>'string', 'key2'=>'string', '...other_keys='=>'string'], 'RedisCluster::sDiffStore' => ['int', 'dstKey'=>'string', 'key1'=>'string', '...other_keys='=>'string'], 'RedisCluster::sInter' => ['list', 'key'=>'string', '...other_keys='=>'string'], 'RedisCluster::sInterStore' => ['int', 'dstKey'=>'string', 'key'=>'string', '...other_keys='=>'string'], 'RedisCluster::sIsMember' => ['bool', 'key'=>'string', 'value'=>'string'], 'RedisCluster::sMembers' => ['list', 'key'=>'string'], 'RedisCluster::sMove' => ['bool', 'srcKey'=>'string', 'dstKey'=>'string', 'member'=>'string'], 'RedisCluster::sPop' => ['string', 'key'=>'string'], 'RedisCluster::sRandMember' => ['array|string', 'key'=>'string', 'count='=>'int'], 'RedisCluster::sRem' => ['int', 'key'=>'string', 'member1'=>'string', '...other_members='=>'string'], 'RedisCluster::sScan' => ['array|false', 'key'=>'string', '&iterator'=>'int', 'pattern='=>'null', 'count='=>'int'], 'RedisCluster::sUnion' => ['list', 'key1'=>'string', '...other_keys='=>'string'], 'RedisCluster::sUnion\'1' => ['list', 'keys'=>'string[]'], 'RedisCluster::sUnionStore' => ['int', 'dstKey'=>'string', 'key1'=>'string', '...other_keys='=>'string'], 'RedisCluster::save' => ['bool', 'nodeParams'=>'string|array{0:string,1:int}'], 'RedisCluster::scan' => ['array|false', '&iterator'=>'int', 'nodeParams'=>'string|array{0:string,1:int}', 'pattern='=>'string', 'count='=>'int'], 'RedisCluster::script' => ['string|bool|array', 'nodeParams'=>'string|array{0:string,1:int}', 'command'=>'string', 'script='=>'string', '...other_scripts='=>'string[]'], 'RedisCluster::set' => ['bool', 'key'=>'string', 'value'=>'string', 'timeout='=>'array|int'], 'RedisCluster::setBit' => ['int', 'key'=>'string', 'offset'=>'int', 'value'=>'bool|int'], 'RedisCluster::setOption' => ['bool', 'option'=>'int', 'value'=>'string|int'], 'RedisCluster::setRange' => ['string', 'key'=>'string', 'offset'=>'int', 'value'=>'string'], 'RedisCluster::setex' => ['bool', 'key'=>'string', 'ttl'=>'int', 'value'=>'string'], 'RedisCluster::setnx' => ['bool', 'key'=>'string', 'value'=>'string'], 'RedisCluster::slowLog' => ['array|int|bool', 'nodeParams'=>'string|array{0:string,1:int}', 'command'=>'string', 'length='=>'int'], 'RedisCluster::sort' => ['array', 'key'=>'string', 'option='=>'array'], 'RedisCluster::strlen' => ['int', 'key'=>'string'], 'RedisCluster::subscribe' => ['mixed', 'channels'=>'array', 'callback'=>'string'], 'RedisCluster::time' => ['array'], 'RedisCluster::ttl' => ['int', 'key'=>'string'], 'RedisCluster::type' => ['int', 'key'=>'string'], 'RedisCluster::unSubscribe' => ['', 'channels'=>'', '...other_channels='=>''], 'RedisCluster::unlink' => ['int', 'key'=>'string', '...other_keys='=>'string'], 'RedisCluster::unwatch' => [''], 'RedisCluster::watch' => ['void', 'key'=>'string', '...other_keys='=>'string'], 'RedisCluster::xack' => ['', 'str_key'=>'string', 'str_group'=>'string', 'arr_ids'=>'array'], 'RedisCluster::xadd' => ['', 'str_key'=>'string', 'str_id'=>'string', 'arr_fields'=>'array', 'i_maxlen='=>'', 'boo_approximate='=>''], 'RedisCluster::xclaim' => ['', 'str_key'=>'string', 'str_group'=>'string', 'str_consumer'=>'string', 'i_min_idle'=>'', 'arr_ids'=>'array', 'arr_opts='=>'array'], 'RedisCluster::xdel' => ['', 'str_key'=>'string', 'arr_ids'=>'array'], 'RedisCluster::xgroup' => ['', 'str_operation'=>'string', 'str_key='=>'string', 'str_arg1='=>'', 'str_arg2='=>'', 'str_arg3='=>''], 'RedisCluster::xinfo' => ['', 'str_cmd'=>'string', 'str_key='=>'string', 'str_group='=>'string'], 'RedisCluster::xlen' => ['', 'key'=>''], 'RedisCluster::xpending' => ['', 'str_key'=>'string', 'str_group'=>'string', 'str_start='=>'', 'str_end='=>'', 'i_count='=>'', 'str_consumer='=>'string'], 'RedisCluster::xrange' => ['', 'str_key'=>'string', 'str_start'=>'', 'str_end'=>'', 'i_count='=>''], 'RedisCluster::xread' => ['', 'arr_streams'=>'array', 'i_count='=>'', 'i_block='=>''], 'RedisCluster::xreadgroup' => ['', 'str_group'=>'string', 'str_consumer'=>'string', 'arr_streams'=>'array', 'i_count='=>'', 'i_block='=>''], 'RedisCluster::xrevrange' => ['', 'str_key'=>'string', 'str_start'=>'', 'str_end'=>'', 'i_count='=>''], 'RedisCluster::xtrim' => ['', 'str_key'=>'string', 'i_maxlen'=>'', 'boo_approximate='=>''], 'RedisCluster::zAdd' => ['int', 'key'=>'string', 'score1'=>'float', 'value1'=>'string', 'score2='=>'float', 'value2='=>'string', 'scoreN='=>'float', 'valueN='=>'string'], 'RedisCluster::zCard' => ['int', 'key'=>'string'], 'RedisCluster::zCount' => ['int', 'key'=>'string', 'start'=>'string', 'end'=>'string'], 'RedisCluster::zIncrBy' => ['float', 'key'=>'string', 'value'=>'float', 'member'=>'string'], 'RedisCluster::zInterStore' => ['int', 'Output'=>'string', 'ZSetKeys'=>'array', 'Weights='=>'?array', 'aggregateFunction='=>'string'], 'RedisCluster::zLexCount' => ['int', 'key'=>'string', 'min'=>'int', 'max'=>'int'], 'RedisCluster::zRange' => ['array', 'key'=>'string', 'start'=>'int', 'end'=>'int', 'withscores='=>'bool'], 'RedisCluster::zRangeByLex' => ['array', 'key'=>'string', 'min'=>'int', 'max'=>'int', 'offset='=>'int', 'limit='=>'int'], 'RedisCluster::zRangeByScore' => ['array', 'key'=>'string', 'start'=>'int', 'end'=>'int', 'options='=>'array'], 'RedisCluster::zRank' => ['int', 'key'=>'string', 'member'=>'string'], 'RedisCluster::zRem' => ['int', 'key'=>'string', 'member1'=>'string', '...other_members='=>'string'], 'RedisCluster::zRemRangeByLex' => ['array', 'key'=>'string', 'min'=>'int', 'max'=>'int'], 'RedisCluster::zRemRangeByRank' => ['int', 'key'=>'string', 'start'=>'int', 'end'=>'int'], 'RedisCluster::zRemRangeByScore' => ['int', 'key'=>'string', 'start'=>'float|string', 'end'=>'float|string'], 'RedisCluster::zRevRange' => ['array', 'key'=>'string', 'start'=>'int', 'end'=>'int', 'withscore='=>'bool'], 'RedisCluster::zRevRangeByLex' => ['array', 'key'=>'string', 'min'=>'int', 'max'=>'int', 'offset='=>'int', 'limit='=>'int'], 'RedisCluster::zRevRangeByScore' => ['array', 'key'=>'string', 'start'=>'int', 'end'=>'int', 'options='=>'array'], 'RedisCluster::zRevRank' => ['int', 'key'=>'string', 'member'=>'string'], 'RedisCluster::zScan' => ['array|false', 'key'=>'string', '&iterator'=>'int', 'pattern='=>'string', 'count='=>'int'], 'RedisCluster::zScore' => ['float', 'key'=>'string', 'member'=>'string'], 'RedisCluster::zUnionStore' => ['int', 'Output'=>'string', 'ZSetKeys'=>'array', 'Weights='=>'?array', 'aggregateFunction='=>'string'], 'Reflection::export' => ['?string', 'r'=>'reflector', 'return='=>'bool'], 'Reflection::getModifierNames' => ['list', 'modifiers'=>'int'], 'ReflectionClass::__clone' => ['void'], 'ReflectionClass::__construct' => ['void', 'objectOrClass'=>'object|class-string'], 'ReflectionClass::__toString' => ['string'], 'ReflectionClass::export' => ['?string', 'argument'=>'string|object', 'return='=>'bool'], 'ReflectionClass::getConstant' => ['mixed', 'name'=>'string'], 'ReflectionClass::getConstants' => ['array'], 'ReflectionClass::getConstructor' => ['?ReflectionMethod'], 'ReflectionClass::getDefaultProperties' => ['array'], 'ReflectionClass::getDocComment' => ['string|false'], 'ReflectionClass::getEndLine' => ['int|false'], 'ReflectionClass::getExtension' => ['?ReflectionExtension'], 'ReflectionClass::getExtensionName' => ['string|false'], 'ReflectionClass::getFileName' => ['string|false'], 'ReflectionClass::getInterfaceNames' => ['list'], 'ReflectionClass::getInterfaces' => ['array'], 'ReflectionClass::getMethod' => ['ReflectionMethod', 'name'=>'string'], 'ReflectionClass::getMethods' => ['list', 'filter='=>'int'], 'ReflectionClass::getModifiers' => ['int'], 'ReflectionClass::getName' => ['class-string'], 'ReflectionClass::getNamespaceName' => ['string'], 'ReflectionClass::getParentClass' => ['ReflectionClass|false'], 'ReflectionClass::getProperties' => ['list', 'filter='=>'int'], 'ReflectionClass::getProperty' => ['ReflectionProperty', 'name'=>'string'], 'ReflectionClass::getReflectionConstant' => ['ReflectionClassConstant|false', 'name'=>'string'], 'ReflectionClass::getReflectionConstants' => ['list'], 'ReflectionClass::getShortName' => ['string'], 'ReflectionClass::getStartLine' => ['int|false'], 'ReflectionClass::getStaticProperties' => ['array'], 'ReflectionClass::getStaticPropertyValue' => ['mixed', 'name'=>'string', 'default='=>'mixed'], 'ReflectionClass::getTraitAliases' => ['array'], 'ReflectionClass::getTraitNames' => ['list'], 'ReflectionClass::getTraits' => ['array'], 'ReflectionClass::hasConstant' => ['bool', 'name'=>'string'], 'ReflectionClass::hasMethod' => ['bool', 'name'=>'string'], 'ReflectionClass::hasProperty' => ['bool', 'name'=>'string'], 'ReflectionClass::implementsInterface' => ['bool', 'interface'=>'interface-string|ReflectionClass'], 'ReflectionClass::inNamespace' => ['bool'], 'ReflectionClass::isAbstract' => ['bool'], 'ReflectionClass::isAnonymous' => ['bool'], 'ReflectionClass::isCloneable' => ['bool'], 'ReflectionClass::isFinal' => ['bool'], 'ReflectionClass::isInstance' => ['bool', 'object'=>'object'], 'ReflectionClass::isInstantiable' => ['bool'], 'ReflectionClass::isInterface' => ['bool'], 'ReflectionClass::isInternal' => ['bool'], 'ReflectionClass::isIterateable' => ['bool'], 'ReflectionClass::isSubclassOf' => ['bool', 'class'=>'class-string|ReflectionClass'], 'ReflectionClass::isTrait' => ['bool'], 'ReflectionClass::isUserDefined' => ['bool'], 'ReflectionClass::newInstance' => ['object', '...args='=>'mixed'], 'ReflectionClass::newInstanceArgs' => ['object', 'args='=>'list'], 'ReflectionClass::newInstanceWithoutConstructor' => ['object'], 'ReflectionClass::setStaticPropertyValue' => ['void', 'name'=>'string', 'value'=>'mixed'], 'ReflectionClassConstant::__construct' => ['void', 'class'=>'object|class-string', 'constant'=>'string'], 'ReflectionClassConstant::__toString' => ['string'], 'ReflectionClassConstant::export' => ['string', 'class'=>'mixed', 'name'=>'string', 'return='=>'bool'], 'ReflectionClassConstant::getDeclaringClass' => ['ReflectionClass'], 'ReflectionClassConstant::getDocComment' => ['string|false'], 'ReflectionClassConstant::getModifiers' => ['int'], 'ReflectionClassConstant::getName' => ['string'], 'ReflectionClassConstant::getValue' => ['scalar|array|null'], 'ReflectionClassConstant::isPrivate' => ['bool'], 'ReflectionClassConstant::isProtected' => ['bool'], 'ReflectionClassConstant::isPublic' => ['bool'], 'ReflectionExtension::__clone' => ['void'], 'ReflectionExtension::__construct' => ['void', 'name'=>'string'], 'ReflectionExtension::__toString' => ['string'], 'ReflectionExtension::export' => ['?string', 'name'=>'string', 'return='=>'bool'], 'ReflectionExtension::getClassNames' => ['list'], 'ReflectionExtension::getClasses' => ['array'], 'ReflectionExtension::getConstants' => ['array'], 'ReflectionExtension::getDependencies' => ['array'], 'ReflectionExtension::getFunctions' => ['array'], 'ReflectionExtension::getINIEntries' => ['array'], 'ReflectionExtension::getName' => ['string'], 'ReflectionExtension::getVersion' => ['?string'], 'ReflectionExtension::info' => ['void'], 'ReflectionExtension::isPersistent' => ['bool'], 'ReflectionExtension::isTemporary' => ['bool'], 'ReflectionFunction::__construct' => ['void', 'function'=>'callable-string|Closure'], 'ReflectionFunction::__toString' => ['string'], 'ReflectionFunction::export' => ['?string', 'name'=>'string', 'return='=>'bool'], 'ReflectionFunction::getClosure' => ['Closure'], 'ReflectionFunction::getClosureScopeClass' => ['ReflectionClass'], 'ReflectionFunction::getClosureThis' => ['object'], 'ReflectionFunction::getDocComment' => ['string|false'], 'ReflectionFunction::getEndLine' => ['int|false'], 'ReflectionFunction::getExtension' => ['?ReflectionExtension'], 'ReflectionFunction::getExtensionName' => ['string|false'], 'ReflectionFunction::getFileName' => ['string|false'], 'ReflectionFunction::getName' => ['callable-string'], 'ReflectionFunction::getNamespaceName' => ['string'], 'ReflectionFunction::getNumberOfParameters' => ['int'], 'ReflectionFunction::getNumberOfRequiredParameters' => ['int'], 'ReflectionFunction::getParameters' => ['list'], 'ReflectionFunction::getReturnType' => ['?ReflectionType'], 'ReflectionFunction::getShortName' => ['string'], 'ReflectionFunction::getStartLine' => ['int|false'], 'ReflectionFunction::getStaticVariables' => ['array'], 'ReflectionFunction::hasReturnType' => ['bool'], 'ReflectionFunction::inNamespace' => ['bool'], 'ReflectionFunction::invoke' => ['mixed', '...args='=>'mixed'], 'ReflectionFunction::invokeArgs' => ['mixed', 'args'=>'array'], 'ReflectionFunction::isClosure' => ['bool'], 'ReflectionFunction::isDeprecated' => ['bool'], 'ReflectionFunction::isDisabled' => ['bool'], 'ReflectionFunction::isGenerator' => ['bool'], 'ReflectionFunction::isInternal' => ['bool'], 'ReflectionFunction::isUserDefined' => ['bool'], 'ReflectionFunction::isVariadic' => ['bool'], 'ReflectionFunction::returnsReference' => ['bool'], 'ReflectionFunctionAbstract::__clone' => ['void'], 'ReflectionFunctionAbstract::__toString' => ['string'], 'ReflectionFunctionAbstract::export' => ['?string'], 'ReflectionFunctionAbstract::getClosureScopeClass' => ['ReflectionClass|null'], 'ReflectionFunctionAbstract::getClosureThis' => ['object|null'], 'ReflectionFunctionAbstract::getDocComment' => ['string|false'], 'ReflectionFunctionAbstract::getEndLine' => ['int|false'], 'ReflectionFunctionAbstract::getExtension' => ['?ReflectionExtension'], 'ReflectionFunctionAbstract::getExtensionName' => ['string|false'], 'ReflectionFunctionAbstract::getFileName' => ['string|false'], 'ReflectionFunctionAbstract::getName' => ['string'], 'ReflectionFunctionAbstract::getNamespaceName' => ['string'], 'ReflectionFunctionAbstract::getNumberOfParameters' => ['int'], 'ReflectionFunctionAbstract::getNumberOfRequiredParameters' => ['int'], 'ReflectionFunctionAbstract::getParameters' => ['list'], 'ReflectionFunctionAbstract::getReturnType' => ['?ReflectionType'], 'ReflectionFunctionAbstract::getShortName' => ['string'], 'ReflectionFunctionAbstract::getStartLine' => ['int|false'], 'ReflectionFunctionAbstract::getStaticVariables' => ['array'], 'ReflectionFunctionAbstract::hasReturnType' => ['bool'], 'ReflectionFunctionAbstract::inNamespace' => ['bool'], 'ReflectionFunctionAbstract::isClosure' => ['bool'], 'ReflectionFunctionAbstract::isDeprecated' => ['bool'], 'ReflectionFunctionAbstract::isGenerator' => ['bool'], 'ReflectionFunctionAbstract::isInternal' => ['bool'], 'ReflectionFunctionAbstract::isUserDefined' => ['bool'], 'ReflectionFunctionAbstract::isVariadic' => ['bool'], 'ReflectionFunctionAbstract::returnsReference' => ['bool'], 'ReflectionGenerator::__construct' => ['void', 'generator'=>'Generator'], 'ReflectionGenerator::getExecutingFile' => ['string'], 'ReflectionGenerator::getExecutingGenerator' => ['Generator'], 'ReflectionGenerator::getExecutingLine' => ['int'], 'ReflectionGenerator::getFunction' => ['ReflectionFunctionAbstract'], 'ReflectionGenerator::getThis' => ['?object'], 'ReflectionGenerator::getTrace' => ['array', 'options='=>'int'], 'ReflectionMethod::__construct' => ['void', 'class'=>'class-string|object', 'name'=>'string'], 'ReflectionMethod::__construct\'1' => ['void', 'class_method'=>'string'], 'ReflectionMethod::__toString' => ['string'], 'ReflectionMethod::export' => ['?string', 'class'=>'string', 'name'=>'string', 'return='=>'bool'], 'ReflectionMethod::getClosure' => ['?Closure', 'object='=>'object'], 'ReflectionMethod::getClosureScopeClass' => ['ReflectionClass'], 'ReflectionMethod::getClosureThis' => ['object'], 'ReflectionMethod::getDeclaringClass' => ['ReflectionClass'], 'ReflectionMethod::getDocComment' => ['false|string'], 'ReflectionMethod::getEndLine' => ['false|int'], 'ReflectionMethod::getExtension' => ['?ReflectionExtension'], 'ReflectionMethod::getExtensionName' => ['string|false'], 'ReflectionMethod::getFileName' => ['false|string'], 'ReflectionMethod::getModifiers' => ['int'], 'ReflectionMethod::getName' => ['string'], 'ReflectionMethod::getNamespaceName' => ['string'], 'ReflectionMethod::getNumberOfParameters' => ['int'], 'ReflectionMethod::getNumberOfRequiredParameters' => ['int'], 'ReflectionMethod::getParameters' => ['list<\ReflectionParameter>'], 'ReflectionMethod::getPrototype' => ['ReflectionMethod'], 'ReflectionMethod::getReturnType' => ['?ReflectionType'], 'ReflectionMethod::getShortName' => ['string'], 'ReflectionMethod::getStartLine' => ['false|int'], 'ReflectionMethod::getStaticVariables' => ['array'], 'ReflectionMethod::hasReturnType' => ['bool'], 'ReflectionMethod::inNamespace' => ['bool'], 'ReflectionMethod::invoke' => ['mixed', 'object'=>'?object', '...args='=>'mixed'], 'ReflectionMethod::invokeArgs' => ['mixed', 'object'=>'?object', 'args'=>'array'], 'ReflectionMethod::isAbstract' => ['bool'], 'ReflectionMethod::isClosure' => ['bool'], 'ReflectionMethod::isConstructor' => ['bool'], 'ReflectionMethod::isDeprecated' => ['bool'], 'ReflectionMethod::isDestructor' => ['bool'], 'ReflectionMethod::isFinal' => ['bool'], 'ReflectionMethod::isGenerator' => ['bool'], 'ReflectionMethod::isInternal' => ['bool'], 'ReflectionMethod::isPrivate' => ['bool'], 'ReflectionMethod::isProtected' => ['bool'], 'ReflectionMethod::isPublic' => ['bool'], 'ReflectionMethod::isStatic' => ['bool'], 'ReflectionMethod::isUserDefined' => ['bool'], 'ReflectionMethod::isVariadic' => ['bool'], 'ReflectionMethod::returnsReference' => ['bool'], 'ReflectionMethod::setAccessible' => ['void', 'accessible'=>'bool'], 'ReflectionNamedType::__clone' => ['void'], 'ReflectionNamedType::__toString' => ['string'], 'ReflectionNamedType::allowsNull' => ['bool'], 'ReflectionNamedType::getName' => ['string'], 'ReflectionNamedType::isBuiltin' => ['bool'], 'ReflectionObject::__clone' => ['void'], 'ReflectionObject::__construct' => ['void', 'object'=>'object'], 'ReflectionObject::__toString' => ['string'], 'ReflectionObject::export' => ['?string', 'argument'=>'object', 'return='=>'bool'], 'ReflectionObject::getConstant' => ['mixed', 'name'=>'string'], 'ReflectionObject::getConstants' => ['array'], 'ReflectionObject::getConstructor' => ['?ReflectionMethod'], 'ReflectionObject::getDefaultProperties' => ['array'], 'ReflectionObject::getDocComment' => ['false|string'], 'ReflectionObject::getEndLine' => ['false|int'], 'ReflectionObject::getExtension' => ['?ReflectionExtension'], 'ReflectionObject::getExtensionName' => ['false|string'], 'ReflectionObject::getFileName' => ['false|string'], 'ReflectionObject::getInterfaceNames' => ['class-string[]'], 'ReflectionObject::getInterfaces' => ['array'], 'ReflectionObject::getMethod' => ['ReflectionMethod', 'name'=>'string'], 'ReflectionObject::getMethods' => ['ReflectionMethod[]', 'filter='=>'int'], 'ReflectionObject::getModifiers' => ['int'], 'ReflectionObject::getName' => ['string'], 'ReflectionObject::getNamespaceName' => ['string'], 'ReflectionObject::getParentClass' => ['ReflectionClass|false'], 'ReflectionObject::getProperties' => ['ReflectionProperty[]', 'filter='=>'int'], 'ReflectionObject::getProperty' => ['ReflectionProperty', 'name'=>'string'], 'ReflectionObject::getReflectionConstant' => ['ReflectionClassConstant', 'name'=>'string'], 'ReflectionObject::getReflectionConstants' => ['list<\ReflectionClassConstant>'], 'ReflectionObject::getShortName' => ['string'], 'ReflectionObject::getStartLine' => ['false|int'], 'ReflectionObject::getStaticProperties' => ['ReflectionProperty[]'], 'ReflectionObject::getStaticPropertyValue' => ['mixed', 'name'=>'string', 'default='=>'mixed'], 'ReflectionObject::getTraitAliases' => ['array'], 'ReflectionObject::getTraitNames' => ['list'], 'ReflectionObject::getTraits' => ['array'], 'ReflectionObject::hasConstant' => ['bool', 'name'=>'string'], 'ReflectionObject::hasMethod' => ['bool', 'name'=>'string'], 'ReflectionObject::hasProperty' => ['bool', 'name'=>'string'], 'ReflectionObject::implementsInterface' => ['bool', 'interface'=>'ReflectionClass|interface-string'], 'ReflectionObject::inNamespace' => ['bool'], 'ReflectionObject::isAbstract' => ['bool'], 'ReflectionObject::isAnonymous' => ['bool'], 'ReflectionObject::isCloneable' => ['bool'], 'ReflectionObject::isFinal' => ['bool'], 'ReflectionObject::isInstance' => ['bool', 'object'=>'object'], 'ReflectionObject::isInstantiable' => ['bool'], 'ReflectionObject::isInterface' => ['bool'], 'ReflectionObject::isInternal' => ['bool'], 'ReflectionObject::isIterable' => ['bool'], 'ReflectionObject::isIterateable' => ['bool'], 'ReflectionObject::isSubclassOf' => ['bool', 'class'=>'ReflectionClass|string'], 'ReflectionObject::isTrait' => ['bool'], 'ReflectionObject::isUserDefined' => ['bool'], 'ReflectionObject::newInstance' => ['object', 'args='=>'mixed', '...args='=>'array'], 'ReflectionObject::newInstanceArgs' => ['object', 'args='=>'list'], 'ReflectionObject::newInstanceWithoutConstructor' => ['object'], 'ReflectionObject::setStaticPropertyValue' => ['void', 'name'=>'string', 'value'=>'string'], 'ReflectionParameter::__clone' => ['void'], 'ReflectionParameter::__construct' => ['void', 'function'=>'string|array|object', 'param'=>'int|string'], 'ReflectionParameter::__toString' => ['string'], 'ReflectionParameter::allowsNull' => ['bool'], 'ReflectionParameter::canBePassedByValue' => ['bool'], 'ReflectionParameter::export' => ['?string', 'function'=>'string', 'parameter'=>'string', 'return='=>'bool'], 'ReflectionParameter::getClass' => ['?ReflectionClass'], 'ReflectionParameter::getDeclaringClass' => ['?ReflectionClass'], 'ReflectionParameter::getDeclaringFunction' => ['ReflectionFunctionAbstract'], 'ReflectionParameter::getDefaultValue' => ['mixed'], 'ReflectionParameter::getDefaultValueConstantName' => ['?string'], 'ReflectionParameter::getName' => ['non-empty-string'], 'ReflectionParameter::getPosition' => ['int<0, max>'], 'ReflectionParameter::getType' => ['?ReflectionType'], 'ReflectionParameter::hasType' => ['bool'], 'ReflectionParameter::isArray' => ['bool'], 'ReflectionParameter::isCallable' => ['bool'], 'ReflectionParameter::isDefaultValueAvailable' => ['bool'], 'ReflectionParameter::isDefaultValueConstant' => ['bool'], 'ReflectionParameter::isOptional' => ['bool'], 'ReflectionParameter::isPassedByReference' => ['bool'], 'ReflectionParameter::isVariadic' => ['bool'], 'ReflectionProperty::__clone' => ['void'], 'ReflectionProperty::__construct' => ['void', 'class'=>'object|class-string', 'property'=>'string'], 'ReflectionProperty::__toString' => ['string'], 'ReflectionProperty::export' => ['?string', 'class'=>'mixed', 'name'=>'string', 'return='=>'bool'], 'ReflectionProperty::getDeclaringClass' => ['ReflectionClass'], 'ReflectionProperty::getDocComment' => ['string|false'], 'ReflectionProperty::getModifiers' => ['int'], 'ReflectionProperty::getName' => ['string'], 'ReflectionProperty::getValue' => ['mixed', 'object='=>'object'], 'ReflectionProperty::hasType' => ['bool'], 'ReflectionProperty::isDefault' => ['bool'], 'ReflectionProperty::isPrivate' => ['bool'], 'ReflectionProperty::isProtected' => ['bool'], 'ReflectionProperty::isPublic' => ['bool'], 'ReflectionProperty::isStatic' => ['bool'], 'ReflectionProperty::setAccessible' => ['void', 'accessible'=>'bool'], 'ReflectionProperty::setValue' => ['void', 'object'=>'null|object', 'value'=>''], 'ReflectionProperty::setValue\'1' => ['void', 'value'=>''], 'ReflectionType::__clone' => ['void'], 'ReflectionType::__toString' => ['string'], 'ReflectionType::allowsNull' => ['bool'], 'ReflectionType::isBuiltin' => ['bool'], 'ReflectionZendExtension::__clone' => ['void'], 'ReflectionZendExtension::__construct' => ['void', 'name'=>'string'], 'ReflectionZendExtension::__toString' => ['string'], 'ReflectionZendExtension::export' => ['?string', 'name'=>'string', 'return='=>'bool'], 'ReflectionZendExtension::getAuthor' => ['string'], 'ReflectionZendExtension::getCopyright' => ['string'], 'ReflectionZendExtension::getName' => ['string'], 'ReflectionZendExtension::getURL' => ['string'], 'ReflectionZendExtension::getVersion' => ['string'], 'Reflector::__toString' => ['string'], 'Reflector::export' => ['?string'], 'RegexIterator::__construct' => ['void', 'iterator'=>'Iterator', 'pattern'=>'string', 'mode='=>'int', 'flags='=>'int', 'pregFlags='=>'int'], 'RegexIterator::accept' => ['bool'], 'RegexIterator::current' => ['mixed'], 'RegexIterator::getFlags' => ['int'], 'RegexIterator::getInnerIterator' => ['Iterator'], 'RegexIterator::getMode' => ['int'], 'RegexIterator::getPregFlags' => ['int'], 'RegexIterator::getRegex' => ['string'], 'RegexIterator::key' => ['mixed'], 'RegexIterator::next' => ['void'], 'RegexIterator::rewind' => ['void'], 'RegexIterator::setFlags' => ['void', 'flags'=>'int'], 'RegexIterator::setMode' => ['void', 'mode'=>'int'], 'RegexIterator::setPregFlags' => ['void', 'pregFlags'=>'int'], 'RegexIterator::valid' => ['bool'], 'ResourceBundle::__construct' => ['void', 'locale'=>'?string', 'bundle'=>'?string', 'fallback='=>'bool'], 'ResourceBundle::count' => ['int'], 'ResourceBundle::create' => ['?ResourceBundle', 'locale'=>'?string', 'bundle'=>'?string', 'fallback='=>'bool'], 'ResourceBundle::get' => ['mixed', 'index'=>'string|int', 'fallback='=>'bool'], 'ResourceBundle::getErrorCode' => ['int'], 'ResourceBundle::getErrorMessage' => ['string'], 'ResourceBundle::getLocales' => ['array|false', 'bundle'=>'string'], 'Runkit_Sandbox::__construct' => ['void', 'options='=>'array'], 'Runkit_Sandbox_Parent' => [''], 'Runkit_Sandbox_Parent::__construct' => ['void'], 'RuntimeException::__clone' => ['void'], 'RuntimeException::__construct' => ['void', 'message='=>'string', 'code='=>'int', 'previous='=>'?Throwable'], 'RuntimeException::__toString' => ['string'], 'RuntimeException::getCode' => ['int'], 'RuntimeException::getFile' => ['string'], 'RuntimeException::getLine' => ['int'], 'RuntimeException::getMessage' => ['string'], 'RuntimeException::getPrevious' => ['?Throwable'], 'RuntimeException::getTrace' => ['list\',args?:array}>'], 'RuntimeException::getTraceAsString' => ['string'], 'SAMConnection::commit' => ['bool'], 'SAMConnection::connect' => ['bool', 'protocol'=>'string', 'properties='=>'array'], 'SAMConnection::disconnect' => ['bool'], 'SAMConnection::errno' => ['int'], 'SAMConnection::error' => ['string'], 'SAMConnection::isConnected' => ['bool'], 'SAMConnection::peek' => ['SAMMessage', 'target'=>'string', 'properties='=>'array'], 'SAMConnection::peekAll' => ['array', 'target'=>'string', 'properties='=>'array'], 'SAMConnection::receive' => ['SAMMessage', 'target'=>'string', 'properties='=>'array'], 'SAMConnection::remove' => ['SAMMessage', 'target'=>'string', 'properties='=>'array'], 'SAMConnection::rollback' => ['bool'], 'SAMConnection::send' => ['string', 'target'=>'string', 'msg'=>'sammessage', 'properties='=>'array'], 'SAMConnection::setDebug' => ['', 'switch'=>'bool'], 'SAMConnection::subscribe' => ['string', 'targettopic'=>'string'], 'SAMConnection::unsubscribe' => ['bool', 'subscriptionid'=>'string', 'targettopic='=>'string'], 'SAMMessage::body' => ['string'], 'SAMMessage::header' => ['object'], 'SCA::createDataObject' => ['SDO_DataObject', 'type_namespace_uri'=>'string', 'type_name'=>'string'], 'SCA::getService' => ['', 'target'=>'string', 'binding='=>'string', 'config='=>'array'], 'SCA_LocalProxy::createDataObject' => ['SDO_DataObject', 'type_namespace_uri'=>'string', 'type_name'=>'string'], 'SCA_SoapProxy::createDataObject' => ['SDO_DataObject', 'type_namespace_uri'=>'string', 'type_name'=>'string'], 'SDO_DAS_ChangeSummary::beginLogging' => [''], 'SDO_DAS_ChangeSummary::endLogging' => [''], 'SDO_DAS_ChangeSummary::getChangeType' => ['int', 'dataobject'=>'sdo_dataobject'], 'SDO_DAS_ChangeSummary::getChangedDataObjects' => ['SDO_List'], 'SDO_DAS_ChangeSummary::getOldContainer' => ['SDO_DataObject', 'data_object'=>'sdo_dataobject'], 'SDO_DAS_ChangeSummary::getOldValues' => ['SDO_List', 'data_object'=>'sdo_dataobject'], 'SDO_DAS_ChangeSummary::isLogging' => ['bool'], 'SDO_DAS_DataFactory::addPropertyToType' => ['', 'parent_type_namespace_uri'=>'string', 'parent_type_name'=>'string', 'property_name'=>'string', 'type_namespace_uri'=>'string', 'type_name'=>'string', 'options='=>'array'], 'SDO_DAS_DataFactory::addType' => ['', 'type_namespace_uri'=>'string', 'type_name'=>'string', 'options='=>'array'], 'SDO_DAS_DataFactory::getDataFactory' => ['SDO_DAS_DataFactory'], 'SDO_DAS_DataObject::getChangeSummary' => ['SDO_DAS_ChangeSummary'], 'SDO_DAS_Relational::__construct' => ['void', 'database_metadata'=>'array', 'application_root_type='=>'string', 'sdo_containment_references_metadata='=>'array'], 'SDO_DAS_Relational::applyChanges' => ['', 'database_handle'=>'pdo', 'root_data_object'=>'sdodataobject'], 'SDO_DAS_Relational::createRootDataObject' => ['SDODataObject'], 'SDO_DAS_Relational::executePreparedQuery' => ['SDODataObject', 'database_handle'=>'pdo', 'prepared_statement'=>'pdostatement', 'value_list'=>'array', 'column_specifier='=>'array'], 'SDO_DAS_Relational::executeQuery' => ['SDODataObject', 'database_handle'=>'pdo', 'sql_statement'=>'string', 'column_specifier='=>'array'], 'SDO_DAS_Setting::getListIndex' => ['int'], 'SDO_DAS_Setting::getPropertyIndex' => ['int'], 'SDO_DAS_Setting::getPropertyName' => ['string'], 'SDO_DAS_Setting::getValue' => [''], 'SDO_DAS_Setting::isSet' => ['bool'], 'SDO_DAS_XML::addTypes' => ['', 'xsd_file'=>'string'], 'SDO_DAS_XML::create' => ['SDO_DAS_XML', 'xsd_file='=>'mixed', 'key='=>'string'], 'SDO_DAS_XML::createDataObject' => ['SDO_DataObject', 'namespace_uri'=>'string', 'type_name'=>'string'], 'SDO_DAS_XML::createDocument' => ['SDO_DAS_XML_Document', 'document_element_name'=>'string', 'document_element_namespace_uri'=>'string', 'dataobject='=>'sdo_dataobject'], 'SDO_DAS_XML::loadFile' => ['SDO_XMLDocument', 'xml_file'=>'string'], 'SDO_DAS_XML::loadString' => ['SDO_DAS_XML_Document', 'xml_string'=>'string'], 'SDO_DAS_XML::saveFile' => ['', 'xdoc'=>'sdo_xmldocument', 'xml_file'=>'string', 'indent='=>'int'], 'SDO_DAS_XML::saveString' => ['string', 'xdoc'=>'sdo_xmldocument', 'indent='=>'int'], 'SDO_DAS_XML_Document::getRootDataObject' => ['SDO_DataObject'], 'SDO_DAS_XML_Document::getRootElementName' => ['string'], 'SDO_DAS_XML_Document::getRootElementURI' => ['string'], 'SDO_DAS_XML_Document::setEncoding' => ['', 'encoding'=>'string'], 'SDO_DAS_XML_Document::setXMLDeclaration' => ['', 'xmldeclatation'=>'bool'], 'SDO_DAS_XML_Document::setXMLVersion' => ['', 'xmlversion'=>'string'], 'SDO_DataFactory::create' => ['void', 'type_namespace_uri'=>'string', 'type_name'=>'string'], 'SDO_DataObject::clear' => ['void'], 'SDO_DataObject::createDataObject' => ['SDO_DataObject', 'identifier'=>''], 'SDO_DataObject::getContainer' => ['SDO_DataObject'], 'SDO_DataObject::getSequence' => ['SDO_Sequence'], 'SDO_DataObject::getTypeName' => ['string'], 'SDO_DataObject::getTypeNamespaceURI' => ['string'], 'SDO_Exception::getCause' => [''], 'SDO_List::insert' => ['void', 'value'=>'mixed', 'index='=>'int'], 'SDO_Model_Property::getContainingType' => ['SDO_Model_Type'], 'SDO_Model_Property::getDefault' => [''], 'SDO_Model_Property::getName' => ['string'], 'SDO_Model_Property::getType' => ['SDO_Model_Type'], 'SDO_Model_Property::isContainment' => ['bool'], 'SDO_Model_Property::isMany' => ['bool'], 'SDO_Model_ReflectionDataObject::__construct' => ['void', 'data_object'=>'sdo_dataobject'], 'SDO_Model_ReflectionDataObject::export' => ['mixed', 'rdo'=>'sdo_model_reflectiondataobject', 'return='=>'bool'], 'SDO_Model_ReflectionDataObject::getContainmentProperty' => ['SDO_Model_Property'], 'SDO_Model_ReflectionDataObject::getInstanceProperties' => ['array'], 'SDO_Model_ReflectionDataObject::getType' => ['SDO_Model_Type'], 'SDO_Model_Type::getBaseType' => ['SDO_Model_Type'], 'SDO_Model_Type::getName' => ['string'], 'SDO_Model_Type::getNamespaceURI' => ['string'], 'SDO_Model_Type::getProperties' => ['array'], 'SDO_Model_Type::getProperty' => ['SDO_Model_Property', 'identifier'=>''], 'SDO_Model_Type::isAbstractType' => ['bool'], 'SDO_Model_Type::isDataType' => ['bool'], 'SDO_Model_Type::isInstance' => ['bool', 'data_object'=>'sdo_dataobject'], 'SDO_Model_Type::isOpenType' => ['bool'], 'SDO_Model_Type::isSequencedType' => ['bool'], 'SDO_Sequence::getProperty' => ['SDO_Model_Property', 'sequence_index'=>'int'], 'SDO_Sequence::insert' => ['void', 'value'=>'mixed', 'sequenceindex='=>'int', 'propertyidentifier='=>'mixed'], 'SDO_Sequence::move' => ['void', 'toindex'=>'int', 'fromindex'=>'int'], 'SNMP::__construct' => ['void', 'version'=>'int', 'hostname'=>'string', 'community'=>'string', 'timeout='=>'int', 'retries='=>'int'], 'SNMP::close' => ['bool'], 'SNMP::get' => ['array|string|false', 'objectId'=>'string|array', 'preserveKeys='=>'bool'], 'SNMP::getErrno' => ['int'], 'SNMP::getError' => ['string'], 'SNMP::getnext' => ['string|array|false', 'objectId'=>'string|array'], 'SNMP::set' => ['bool', 'objectId'=>'string|array', 'type'=>'string|array', 'value'=>'string|array'], 'SNMP::setSecurity' => ['bool', 'securityLevel'=>'string', 'authProtocol='=>'string', 'authPassphrase='=>'string', 'privacyProtocol='=>'string', 'privacyPassphrase='=>'string', 'contextName='=>'string', 'contextEngineId='=>'string'], 'SNMP::walk' => ['array|false', 'objectId'=>'array|string', 'suffixAsKey='=>'bool', 'maxRepetitions='=>'int', 'nonRepeaters='=>'int'], 'SQLite3::__construct' => ['void', 'filename'=>'string', 'flags='=>'int', 'encryptionKey='=>'string'], 'SQLite3::busyTimeout' => ['bool', 'milliseconds'=>'int'], 'SQLite3::changes' => ['int'], 'SQLite3::close' => ['bool'], 'SQLite3::createAggregate' => ['bool', 'name'=>'string', 'stepCallback'=>'callable', 'finalCallback'=>'callable', 'argCount='=>'int'], 'SQLite3::createCollation' => ['bool', 'name'=>'string', 'callback'=>'callable'], 'SQLite3::createFunction' => ['bool', 'name'=>'string', 'callback'=>'callable', 'argCount='=>'int'], 'SQLite3::enableExceptions' => ['bool', 'enable='=>'bool'], 'SQLite3::escapeString' => ['string', 'string'=>'string'], 'SQLite3::exec' => ['bool', 'query'=>'string'], 'SQLite3::lastErrorCode' => ['int'], 'SQLite3::lastErrorMsg' => ['string'], 'SQLite3::lastInsertRowID' => ['int'], 'SQLite3::loadExtension' => ['bool', 'name'=>'string'], 'SQLite3::open' => ['void', 'filename'=>'string', 'flags='=>'int', 'encryptionKey='=>'string'], 'SQLite3::openBlob' => ['resource|false', 'table'=>'string', 'column'=>'string', 'rowid'=>'int', 'dbname='=>'string'], 'SQLite3::prepare' => ['SQLite3Stmt|false', 'query'=>'string'], 'SQLite3::query' => ['SQLite3Result|false', 'query'=>'string'], 'SQLite3::querySingle' => ['array|int|string|bool|float|null|false', 'query'=>'string', 'entireRow='=>'bool'], 'SQLite3::version' => ['array'], 'SQLite3Result::__construct' => ['void'], 'SQLite3Result::columnName' => ['string', 'column'=>'int'], 'SQLite3Result::columnType' => ['int', 'column'=>'int'], 'SQLite3Result::fetchArray' => ['array|false', 'mode='=>'int'], 'SQLite3Result::finalize' => ['bool'], 'SQLite3Result::numColumns' => ['int'], 'SQLite3Result::reset' => ['bool'], 'SQLite3Stmt::__construct' => ['void', 'sqlite3'=>'sqlite3', 'query'=>'string'], 'SQLite3Stmt::bindParam' => ['bool', 'param'=>'string|int', '&rw_var'=>'mixed', 'type='=>'int'], 'SQLite3Stmt::bindValue' => ['bool', 'param'=>'string|int', 'value'=>'mixed', 'type='=>'int'], 'SQLite3Stmt::clear' => ['bool'], 'SQLite3Stmt::close' => ['bool'], 'SQLite3Stmt::execute' => ['false|SQLite3Result'], 'SQLite3Stmt::getSQL' => ['string', 'expand='=>'bool'], 'SQLite3Stmt::paramCount' => ['int'], 'SQLite3Stmt::readOnly' => ['bool'], 'SQLite3Stmt::reset' => ['bool'], 'SQLiteDatabase::__construct' => ['void', 'filename'=>'', 'mode='=>'int|mixed', '&error_message'=>''], 'SQLiteDatabase::arrayQuery' => ['array', 'query'=>'string', 'result_type='=>'int', 'decode_binary='=>'bool'], 'SQLiteDatabase::busyTimeout' => ['int', 'milliseconds'=>'int'], 'SQLiteDatabase::changes' => ['int'], 'SQLiteDatabase::createAggregate' => ['', 'function_name'=>'string', 'step_func'=>'callable', 'finalize_func'=>'callable', 'num_args='=>'int'], 'SQLiteDatabase::createFunction' => ['', 'function_name'=>'string', 'callback'=>'callable', 'num_args='=>'int'], 'SQLiteDatabase::exec' => ['bool', 'query'=>'string', 'error_msg='=>'string'], 'SQLiteDatabase::fetchColumnTypes' => ['array', 'table_name'=>'string', 'result_type='=>'int'], 'SQLiteDatabase::lastError' => ['int'], 'SQLiteDatabase::lastInsertRowid' => ['int'], 'SQLiteDatabase::query' => ['SQLiteResult|false', 'query'=>'string', 'result_type='=>'int', 'error_msg='=>'string'], 'SQLiteDatabase::queryExec' => ['bool', 'query'=>'string', '&w_error_msg='=>'string'], 'SQLiteDatabase::singleQuery' => ['array', 'query'=>'string', 'first_row_only='=>'bool', 'decode_binary='=>'bool'], 'SQLiteDatabase::unbufferedQuery' => ['SQLiteUnbuffered|false', 'query'=>'string', 'result_type='=>'int', 'error_msg='=>'string'], 'SQLiteException::__clone' => ['void'], 'SQLiteException::__construct' => ['void', 'message'=>'', 'code'=>'', 'previous'=>''], 'SQLiteException::__toString' => ['string'], 'SQLiteException::__wakeup' => ['void'], 'SQLiteException::getCode' => ['int'], 'SQLiteException::getFile' => ['string'], 'SQLiteException::getLine' => ['int'], 'SQLiteException::getMessage' => ['string'], 'SQLiteException::getPrevious' => ['RuntimeException|Throwable|null'], 'SQLiteException::getTrace' => ['list\',args?:array}>'], 'SQLiteException::getTraceAsString' => ['string'], 'SQLiteResult::__construct' => ['void'], 'SQLiteResult::column' => ['mixed', 'index_or_name'=>'', 'decode_binary='=>'bool'], 'SQLiteResult::count' => ['int'], 'SQLiteResult::current' => ['array', 'result_type='=>'int', 'decode_binary='=>'bool'], 'SQLiteResult::fetch' => ['array', 'result_type='=>'int', 'decode_binary='=>'bool'], 'SQLiteResult::fetchAll' => ['array', 'result_type='=>'int', 'decode_binary='=>'bool'], 'SQLiteResult::fetchObject' => ['object', 'class_name='=>'string', 'ctor_params='=>'array', 'decode_binary='=>'bool'], 'SQLiteResult::fetchSingle' => ['string', 'decode_binary='=>'bool'], 'SQLiteResult::fieldName' => ['string', 'field_index'=>'int'], 'SQLiteResult::hasPrev' => ['bool'], 'SQLiteResult::key' => ['mixed|null'], 'SQLiteResult::next' => ['bool'], 'SQLiteResult::numFields' => ['int'], 'SQLiteResult::numRows' => ['int'], 'SQLiteResult::prev' => ['bool'], 'SQLiteResult::rewind' => ['bool'], 'SQLiteResult::seek' => ['bool', 'rownum'=>'int'], 'SQLiteResult::valid' => ['bool'], 'SQLiteUnbuffered::column' => ['void', 'index_or_name'=>'', 'decode_binary='=>'bool'], 'SQLiteUnbuffered::current' => ['array', 'result_type='=>'int', 'decode_binary='=>'bool'], 'SQLiteUnbuffered::fetch' => ['array', 'result_type='=>'int', 'decode_binary='=>'bool'], 'SQLiteUnbuffered::fetchAll' => ['array', 'result_type='=>'int', 'decode_binary='=>'bool'], 'SQLiteUnbuffered::fetchObject' => ['object', 'class_name='=>'string', 'ctor_params='=>'array', 'decode_binary='=>'bool'], 'SQLiteUnbuffered::fetchSingle' => ['string', 'decode_binary='=>'bool'], 'SQLiteUnbuffered::fieldName' => ['string', 'field_index'=>'int'], 'SQLiteUnbuffered::next' => ['bool'], 'SQLiteUnbuffered::numFields' => ['int'], 'SQLiteUnbuffered::valid' => ['bool'], 'SVM::__construct' => ['void'], 'SVM::getOptions' => ['array'], 'SVM::setOptions' => ['bool', 'params'=>'array'], 'SVMModel::__construct' => ['void', 'filename='=>'string'], 'SVMModel::checkProbabilityModel' => ['bool'], 'SVMModel::getLabels' => ['array'], 'SVMModel::getNrClass' => ['int'], 'SVMModel::getSvmType' => ['int'], 'SVMModel::getSvrProbability' => ['float'], 'SVMModel::load' => ['bool', 'filename'=>'string'], 'SVMModel::predict' => ['float', 'data'=>'array'], 'SVMModel::predict_probability' => ['float', 'data'=>'array'], 'SVMModel::save' => ['bool', 'filename'=>'string'], 'SWFAction::__construct' => ['void', 'script'=>'string'], 'SWFBitmap::__construct' => ['void', 'file'=>'', 'alphafile='=>''], 'SWFBitmap::getHeight' => ['float'], 'SWFBitmap::getWidth' => ['float'], 'SWFButton::__construct' => ['void'], 'SWFButton::addASound' => ['SWFSoundInstance', 'sound'=>'swfsound', 'flags'=>'int'], 'SWFButton::addAction' => ['void', 'action'=>'swfaction', 'flags'=>'int'], 'SWFButton::addShape' => ['void', 'shape'=>'swfshape', 'flags'=>'int'], 'SWFButton::setAction' => ['void', 'action'=>'swfaction'], 'SWFButton::setDown' => ['void', 'shape'=>'swfshape'], 'SWFButton::setHit' => ['void', 'shape'=>'swfshape'], 'SWFButton::setMenu' => ['void', 'flag'=>'int'], 'SWFButton::setOver' => ['void', 'shape'=>'swfshape'], 'SWFButton::setUp' => ['void', 'shape'=>'swfshape'], 'SWFDisplayItem::addAction' => ['void', 'action'=>'swfaction', 'flags'=>'int'], 'SWFDisplayItem::addColor' => ['void', 'red'=>'int', 'green'=>'int', 'blue'=>'int', 'a='=>'int'], 'SWFDisplayItem::endMask' => ['void'], 'SWFDisplayItem::getRot' => ['float'], 'SWFDisplayItem::getX' => ['float'], 'SWFDisplayItem::getXScale' => ['float'], 'SWFDisplayItem::getXSkew' => ['float'], 'SWFDisplayItem::getY' => ['float'], 'SWFDisplayItem::getYScale' => ['float'], 'SWFDisplayItem::getYSkew' => ['float'], 'SWFDisplayItem::move' => ['void', 'dx'=>'float', 'dy'=>'float'], 'SWFDisplayItem::moveTo' => ['void', 'x'=>'float', 'y'=>'float'], 'SWFDisplayItem::multColor' => ['void', 'red'=>'float', 'green'=>'float', 'blue'=>'float', 'a='=>'float'], 'SWFDisplayItem::remove' => ['void'], 'SWFDisplayItem::rotate' => ['void', 'angle'=>'float'], 'SWFDisplayItem::rotateTo' => ['void', 'angle'=>'float'], 'SWFDisplayItem::scale' => ['void', 'dx'=>'float', 'dy'=>'float'], 'SWFDisplayItem::scaleTo' => ['void', 'x'=>'float', 'y='=>'float'], 'SWFDisplayItem::setDepth' => ['void', 'depth'=>'int'], 'SWFDisplayItem::setMaskLevel' => ['void', 'level'=>'int'], 'SWFDisplayItem::setMatrix' => ['void', 'a'=>'float', 'b'=>'float', 'c'=>'float', 'd'=>'float', 'x'=>'float', 'y'=>'float'], 'SWFDisplayItem::setName' => ['void', 'name'=>'string'], 'SWFDisplayItem::setRatio' => ['void', 'ratio'=>'float'], 'SWFDisplayItem::skewX' => ['void', 'ddegrees'=>'float'], 'SWFDisplayItem::skewXTo' => ['void', 'degrees'=>'float'], 'SWFDisplayItem::skewY' => ['void', 'ddegrees'=>'float'], 'SWFDisplayItem::skewYTo' => ['void', 'degrees'=>'float'], 'SWFFill::moveTo' => ['void', 'x'=>'float', 'y'=>'float'], 'SWFFill::rotateTo' => ['void', 'angle'=>'float'], 'SWFFill::scaleTo' => ['void', 'x'=>'float', 'y='=>'float'], 'SWFFill::skewXTo' => ['void', 'x'=>'float'], 'SWFFill::skewYTo' => ['void', 'y'=>'float'], 'SWFFont::__construct' => ['void', 'filename'=>'string'], 'SWFFont::getAscent' => ['float'], 'SWFFont::getDescent' => ['float'], 'SWFFont::getLeading' => ['float'], 'SWFFont::getShape' => ['string', 'code'=>'int'], 'SWFFont::getUTF8Width' => ['float', 'string'=>'string'], 'SWFFont::getWidth' => ['float', 'string'=>'string'], 'SWFFontChar::addChars' => ['void', 'char'=>'string'], 'SWFFontChar::addUTF8Chars' => ['void', 'char'=>'string'], 'SWFGradient::__construct' => ['void'], 'SWFGradient::addEntry' => ['void', 'ratio'=>'float', 'red'=>'int', 'green'=>'int', 'blue'=>'int', 'alpha='=>'int'], 'SWFMorph::__construct' => ['void'], 'SWFMorph::getShape1' => ['SWFShape'], 'SWFMorph::getShape2' => ['SWFShape'], 'SWFMovie::__construct' => ['void', 'version='=>'int'], 'SWFMovie::add' => ['mixed', 'instance'=>'object'], 'SWFMovie::addExport' => ['void', 'char'=>'swfcharacter', 'name'=>'string'], 'SWFMovie::addFont' => ['mixed', 'font'=>'swffont'], 'SWFMovie::importChar' => ['SWFSprite', 'libswf'=>'string', 'name'=>'string'], 'SWFMovie::importFont' => ['SWFFontChar', 'libswf'=>'string', 'name'=>'string'], 'SWFMovie::labelFrame' => ['void', 'label'=>'string'], 'SWFMovie::namedAnchor' => [''], 'SWFMovie::nextFrame' => ['void'], 'SWFMovie::output' => ['int', 'compression='=>'int'], 'SWFMovie::protect' => [''], 'SWFMovie::remove' => ['void', 'instance'=>'object'], 'SWFMovie::save' => ['int', 'filename'=>'string', 'compression='=>'int'], 'SWFMovie::saveToFile' => ['int', 'x'=>'resource', 'compression='=>'int'], 'SWFMovie::setDimension' => ['void', 'width'=>'float', 'height'=>'float'], 'SWFMovie::setFrames' => ['void', 'number'=>'int'], 'SWFMovie::setRate' => ['void', 'rate'=>'float'], 'SWFMovie::setbackground' => ['void', 'red'=>'int', 'green'=>'int', 'blue'=>'int'], 'SWFMovie::startSound' => ['SWFSoundInstance', 'sound'=>'swfsound'], 'SWFMovie::stopSound' => ['void', 'sound'=>'swfsound'], 'SWFMovie::streamMP3' => ['int', 'mp3file'=>'mixed', 'skip='=>'float'], 'SWFMovie::writeExports' => ['void'], 'SWFPrebuiltClip::__construct' => ['void', 'file'=>''], 'SWFShape::__construct' => ['void'], 'SWFShape::addFill' => ['SWFFill', 'red'=>'int', 'green'=>'int', 'blue'=>'int', 'alpha='=>'int', 'bitmap='=>'swfbitmap', 'flags='=>'int', 'gradient='=>'swfgradient'], 'SWFShape::addFill\'1' => ['SWFFill', 'bitmap'=>'SWFBitmap', 'flags='=>'int'], 'SWFShape::addFill\'2' => ['SWFFill', 'gradient'=>'SWFGradient', 'flags='=>'int'], 'SWFShape::drawArc' => ['void', 'r'=>'float', 'startangle'=>'float', 'endangle'=>'float'], 'SWFShape::drawCircle' => ['void', 'r'=>'float'], 'SWFShape::drawCubic' => ['int', 'bx'=>'float', 'by'=>'float', 'cx'=>'float', 'cy'=>'float', 'dx'=>'float', 'dy'=>'float'], 'SWFShape::drawCubicTo' => ['int', 'bx'=>'float', 'by'=>'float', 'cx'=>'float', 'cy'=>'float', 'dx'=>'float', 'dy'=>'float'], 'SWFShape::drawCurve' => ['int', 'controldx'=>'float', 'controldy'=>'float', 'anchordx'=>'float', 'anchordy'=>'float', 'targetdx='=>'float', 'targetdy='=>'float'], 'SWFShape::drawCurveTo' => ['int', 'controlx'=>'float', 'controly'=>'float', 'anchorx'=>'float', 'anchory'=>'float', 'targetx='=>'float', 'targety='=>'float'], 'SWFShape::drawGlyph' => ['void', 'font'=>'swffont', 'character'=>'string', 'size='=>'int'], 'SWFShape::drawLine' => ['void', 'dx'=>'float', 'dy'=>'float'], 'SWFShape::drawLineTo' => ['void', 'x'=>'float', 'y'=>'float'], 'SWFShape::movePen' => ['void', 'dx'=>'float', 'dy'=>'float'], 'SWFShape::movePenTo' => ['void', 'x'=>'float', 'y'=>'float'], 'SWFShape::setLeftFill' => ['', 'fill'=>'swfgradient', 'red'=>'int', 'green'=>'int', 'blue'=>'int', 'a='=>'int'], 'SWFShape::setLine' => ['', 'shape'=>'swfshape', 'width'=>'int', 'red'=>'int', 'green'=>'int', 'blue'=>'int', 'a='=>'int'], 'SWFShape::setRightFill' => ['', 'fill'=>'swfgradient', 'red'=>'int', 'green'=>'int', 'blue'=>'int', 'a='=>'int'], 'SWFSound' => ['SWFSound', 'filename'=>'string', 'flags='=>'int'], 'SWFSound::__construct' => ['void', 'filename'=>'string', 'flags='=>'int'], 'SWFSoundInstance::loopCount' => ['void', 'point'=>'int'], 'SWFSoundInstance::loopInPoint' => ['void', 'point'=>'int'], 'SWFSoundInstance::loopOutPoint' => ['void', 'point'=>'int'], 'SWFSoundInstance::noMultiple' => ['void'], 'SWFSprite::__construct' => ['void'], 'SWFSprite::add' => ['void', 'object'=>'object'], 'SWFSprite::labelFrame' => ['void', 'label'=>'string'], 'SWFSprite::nextFrame' => ['void'], 'SWFSprite::remove' => ['void', 'object'=>'object'], 'SWFSprite::setFrames' => ['void', 'number'=>'int'], 'SWFSprite::startSound' => ['SWFSoundInstance', 'sount'=>'swfsound'], 'SWFSprite::stopSound' => ['void', 'sount'=>'swfsound'], 'SWFText::__construct' => ['void'], 'SWFText::addString' => ['void', 'string'=>'string'], 'SWFText::addUTF8String' => ['void', 'text'=>'string'], 'SWFText::getAscent' => ['float'], 'SWFText::getDescent' => ['float'], 'SWFText::getLeading' => ['float'], 'SWFText::getUTF8Width' => ['float', 'string'=>'string'], 'SWFText::getWidth' => ['float', 'string'=>'string'], 'SWFText::moveTo' => ['void', 'x'=>'float', 'y'=>'float'], 'SWFText::setColor' => ['void', 'red'=>'int', 'green'=>'int', 'blue'=>'int', 'a='=>'int'], 'SWFText::setFont' => ['void', 'font'=>'swffont'], 'SWFText::setHeight' => ['void', 'height'=>'float'], 'SWFText::setSpacing' => ['void', 'spacing'=>'float'], 'SWFTextField::__construct' => ['void', 'flags='=>'int'], 'SWFTextField::addChars' => ['void', 'chars'=>'string'], 'SWFTextField::addString' => ['void', 'string'=>'string'], 'SWFTextField::align' => ['void', 'alignement'=>'int'], 'SWFTextField::setBounds' => ['void', 'width'=>'float', 'height'=>'float'], 'SWFTextField::setColor' => ['void', 'red'=>'int', 'green'=>'int', 'blue'=>'int', 'a='=>'int'], 'SWFTextField::setFont' => ['void', 'font'=>'swffont'], 'SWFTextField::setHeight' => ['void', 'height'=>'float'], 'SWFTextField::setIndentation' => ['void', 'width'=>'float'], 'SWFTextField::setLeftMargin' => ['void', 'width'=>'float'], 'SWFTextField::setLineSpacing' => ['void', 'height'=>'float'], 'SWFTextField::setMargins' => ['void', 'left'=>'float', 'right'=>'float'], 'SWFTextField::setName' => ['void', 'name'=>'string'], 'SWFTextField::setPadding' => ['void', 'padding'=>'float'], 'SWFTextField::setRightMargin' => ['void', 'width'=>'float'], 'SWFVideoStream::__construct' => ['void', 'file='=>'string'], 'SWFVideoStream::getNumFrames' => ['int'], 'SWFVideoStream::setDimension' => ['void', 'x'=>'int', 'y'=>'int'], 'Saxon\SaxonProcessor::__construct' => ['void', 'license='=>'bool', 'cwd='=>'string'], 'Saxon\SaxonProcessor::createAtomicValue' => ['Saxon\XdmValue', 'primitive_type_val'=>'bool|float|int|string'], 'Saxon\SaxonProcessor::newSchemaValidator' => ['Saxon\SchemaValidator'], 'Saxon\SaxonProcessor::newXPathProcessor' => ['Saxon\XPathProcessor'], 'Saxon\SaxonProcessor::newXQueryProcessor' => ['Saxon\XQueryProcessor'], 'Saxon\SaxonProcessor::newXsltProcessor' => ['Saxon\XsltProcessor'], 'Saxon\SaxonProcessor::parseXmlFromFile' => ['Saxon\XdmNode', 'fileName'=>'string'], 'Saxon\SaxonProcessor::parseXmlFromString' => ['Saxon\XdmNode', 'value'=>'string'], 'Saxon\SaxonProcessor::registerPHPFunctions' => ['void', 'library'=>'string'], 'Saxon\SaxonProcessor::setConfigurationProperty' => ['void', 'name'=>'string', 'value'=>'string'], 'Saxon\SaxonProcessor::setResourceDirectory' => ['void', 'dir'=>'string'], 'Saxon\SaxonProcessor::setcwd' => ['void', 'cwd'=>'string'], 'Saxon\SaxonProcessor::version' => ['string'], 'Saxon\SchemaValidator::clearParameters' => ['void'], 'Saxon\SchemaValidator::clearProperties' => ['void'], 'Saxon\SchemaValidator::exceptionClear' => ['void'], 'Saxon\SchemaValidator::getErrorCode' => ['string', 'i'=>'int'], 'Saxon\SchemaValidator::getErrorMessage' => ['string', 'i'=>'int'], 'Saxon\SchemaValidator::getExceptionCount' => ['int'], 'Saxon\SchemaValidator::getValidationReport' => ['Saxon\XdmNode'], 'Saxon\SchemaValidator::registerSchemaFromFile' => ['void', 'fileName'=>'string'], 'Saxon\SchemaValidator::registerSchemaFromString' => ['void', 'schemaStr'=>'string'], 'Saxon\SchemaValidator::setOutputFile' => ['void', 'fileName'=>'string'], 'Saxon\SchemaValidator::setParameter' => ['void', 'name'=>'string', 'value'=>'Saxon\XdmValue'], 'Saxon\SchemaValidator::setProperty' => ['void', 'name'=>'string', 'value'=>'string'], 'Saxon\SchemaValidator::setSourceNode' => ['void', 'node'=>'Saxon\XdmNode'], 'Saxon\SchemaValidator::validate' => ['void', 'filename='=>'?string'], 'Saxon\SchemaValidator::validateToNode' => ['Saxon\XdmNode', 'filename='=>'?string'], 'Saxon\XPathProcessor::clearParameters' => ['void'], 'Saxon\XPathProcessor::clearProperties' => ['void'], 'Saxon\XPathProcessor::declareNamespace' => ['void', 'prefix'=>'', 'namespace'=>''], 'Saxon\XPathProcessor::effectiveBooleanValue' => ['bool', 'xpathStr'=>'string'], 'Saxon\XPathProcessor::evaluate' => ['Saxon\XdmValue', 'xpathStr'=>'string'], 'Saxon\XPathProcessor::evaluateSingle' => ['Saxon\XdmItem', 'xpathStr'=>'string'], 'Saxon\XPathProcessor::exceptionClear' => ['void'], 'Saxon\XPathProcessor::getErrorCode' => ['string', 'i'=>'int'], 'Saxon\XPathProcessor::getErrorMessage' => ['string', 'i'=>'int'], 'Saxon\XPathProcessor::getExceptionCount' => ['int'], 'Saxon\XPathProcessor::setBaseURI' => ['void', 'uri'=>'string'], 'Saxon\XPathProcessor::setContextFile' => ['void', 'fileName'=>'string'], 'Saxon\XPathProcessor::setContextItem' => ['void', 'item'=>'Saxon\XdmItem'], 'Saxon\XPathProcessor::setParameter' => ['void', 'name'=>'string', 'value'=>'Saxon\XdmValue'], 'Saxon\XPathProcessor::setProperty' => ['void', 'name'=>'string', 'value'=>'string'], 'Saxon\XQueryProcessor::clearParameters' => ['void'], 'Saxon\XQueryProcessor::clearProperties' => ['void'], 'Saxon\XQueryProcessor::declareNamespace' => ['void', 'prefix'=>'string', 'namespace'=>'string'], 'Saxon\XQueryProcessor::exceptionClear' => ['void'], 'Saxon\XQueryProcessor::getErrorCode' => ['string', 'i'=>'int'], 'Saxon\XQueryProcessor::getErrorMessage' => ['string', 'i'=>'int'], 'Saxon\XQueryProcessor::getExceptionCount' => ['int'], 'Saxon\XQueryProcessor::runQueryToFile' => ['void', 'outfilename'=>'string'], 'Saxon\XQueryProcessor::runQueryToString' => ['?string'], 'Saxon\XQueryProcessor::runQueryToValue' => ['?Saxon\XdmValue'], 'Saxon\XQueryProcessor::setContextItem' => ['void', 'object'=>'Saxon\XdmAtomicValue|Saxon\XdmItem|Saxon\XdmNode|Saxon\XdmValue'], 'Saxon\XQueryProcessor::setContextItemFromFile' => ['void', 'fileName'=>'string'], 'Saxon\XQueryProcessor::setParameter' => ['void', 'name'=>'string', 'value'=>'Saxon\XdmValue'], 'Saxon\XQueryProcessor::setProperty' => ['void', 'name'=>'string', 'value'=>'string'], 'Saxon\XQueryProcessor::setQueryBaseURI' => ['void', 'uri'=>'string'], 'Saxon\XQueryProcessor::setQueryContent' => ['void', 'string'=>'string'], 'Saxon\XQueryProcessor::setQueryFile' => ['void', 'filename'=>'string'], 'Saxon\XQueryProcessor::setQueryItem' => ['void', 'item'=>'Saxon\XdmItem'], 'Saxon\XdmAtomicValue::addXdmItem' => ['', 'item'=>'Saxon\XdmItem'], 'Saxon\XdmAtomicValue::getAtomicValue' => ['?Saxon\XdmAtomicValue'], 'Saxon\XdmAtomicValue::getBooleanValue' => ['bool'], 'Saxon\XdmAtomicValue::getDoubleValue' => ['float'], 'Saxon\XdmAtomicValue::getHead' => ['Saxon\XdmItem'], 'Saxon\XdmAtomicValue::getLongValue' => ['int'], 'Saxon\XdmAtomicValue::getNodeValue' => ['?Saxon\XdmNode'], 'Saxon\XdmAtomicValue::getStringValue' => ['string'], 'Saxon\XdmAtomicValue::isAtomic' => ['true'], 'Saxon\XdmAtomicValue::isNode' => ['bool'], 'Saxon\XdmAtomicValue::itemAt' => ['Saxon\XdmItem', 'index'=>'int'], 'Saxon\XdmAtomicValue::size' => ['int'], 'Saxon\XdmItem::addXdmItem' => ['', 'item'=>'Saxon\XdmItem'], 'Saxon\XdmItem::getAtomicValue' => ['?Saxon\XdmAtomicValue'], 'Saxon\XdmItem::getHead' => ['Saxon\XdmItem'], 'Saxon\XdmItem::getNodeValue' => ['?Saxon\XdmNode'], 'Saxon\XdmItem::getStringValue' => ['string'], 'Saxon\XdmItem::isAtomic' => ['bool'], 'Saxon\XdmItem::isNode' => ['bool'], 'Saxon\XdmItem::itemAt' => ['Saxon\XdmItem', 'index'=>'int'], 'Saxon\XdmItem::size' => ['int'], 'Saxon\XdmNode::addXdmItem' => ['', 'item'=>'Saxon\XdmItem'], 'Saxon\XdmNode::getAtomicValue' => ['?Saxon\XdmAtomicValue'], 'Saxon\XdmNode::getAttributeCount' => ['int'], 'Saxon\XdmNode::getAttributeNode' => ['?Saxon\XdmNode', 'index'=>'int'], 'Saxon\XdmNode::getAttributeValue' => ['?string', 'index'=>'int'], 'Saxon\XdmNode::getChildCount' => ['int'], 'Saxon\XdmNode::getChildNode' => ['?Saxon\XdmNode', 'index'=>'int'], 'Saxon\XdmNode::getHead' => ['Saxon\XdmItem'], 'Saxon\XdmNode::getNodeKind' => ['int'], 'Saxon\XdmNode::getNodeName' => ['string'], 'Saxon\XdmNode::getNodeValue' => ['?Saxon\XdmNode'], 'Saxon\XdmNode::getParent' => ['?Saxon\XdmNode'], 'Saxon\XdmNode::getStringValue' => ['string'], 'Saxon\XdmNode::isAtomic' => ['false'], 'Saxon\XdmNode::isNode' => ['bool'], 'Saxon\XdmNode::itemAt' => ['Saxon\XdmItem', 'index'=>'int'], 'Saxon\XdmNode::size' => ['int'], 'Saxon\XdmValue::addXdmItem' => ['', 'item'=>'Saxon\XdmItem'], 'Saxon\XdmValue::getHead' => ['Saxon\XdmItem'], 'Saxon\XdmValue::itemAt' => ['Saxon\XdmItem', 'index'=>'int'], 'Saxon\XdmValue::size' => ['int'], 'Saxon\XsltProcessor::clearParameters' => ['void'], 'Saxon\XsltProcessor::clearProperties' => ['void'], 'Saxon\XsltProcessor::compileFromFile' => ['void', 'fileName'=>'string'], 'Saxon\XsltProcessor::compileFromString' => ['void', 'string'=>'string'], 'Saxon\XsltProcessor::compileFromValue' => ['void', 'node'=>'Saxon\XdmNode'], 'Saxon\XsltProcessor::exceptionClear' => ['void'], 'Saxon\XsltProcessor::getErrorCode' => ['string', 'i'=>'int'], 'Saxon\XsltProcessor::getErrorMessage' => ['string', 'i'=>'int'], 'Saxon\XsltProcessor::getExceptionCount' => ['int'], 'Saxon\XsltProcessor::setOutputFile' => ['void', 'fileName'=>'string'], 'Saxon\XsltProcessor::setParameter' => ['void', 'name'=>'string', 'value'=>'Saxon\XdmValue'], 'Saxon\XsltProcessor::setProperty' => ['void', 'name'=>'string', 'value'=>'string'], 'Saxon\XsltProcessor::setSourceFromFile' => ['void', 'filename'=>'string'], 'Saxon\XsltProcessor::setSourceFromXdmValue' => ['void', 'value'=>'Saxon\XdmValue'], 'Saxon\XsltProcessor::transformFileToFile' => ['void', 'sourceFileName'=>'string', 'stylesheetFileName'=>'string', 'outputfileName'=>'string'], 'Saxon\XsltProcessor::transformFileToString' => ['?string', 'sourceFileName'=>'string', 'stylesheetFileName'=>'string'], 'Saxon\XsltProcessor::transformFileToValue' => ['Saxon\XdmValue', 'fileName'=>'string'], 'Saxon\XsltProcessor::transformToFile' => ['void'], 'Saxon\XsltProcessor::transformToString' => ['string'], 'Saxon\XsltProcessor::transformToValue' => ['?Saxon\XdmValue'], 'SeasLog::__destruct' => ['void'], 'SeasLog::alert' => ['bool', 'message'=>'string', 'content='=>'array', 'logger='=>'string'], 'SeasLog::analyzerCount' => ['mixed', 'level'=>'string', 'log_path='=>'string', 'key_word='=>'string'], 'SeasLog::analyzerDetail' => ['mixed', 'level'=>'string', 'log_path='=>'string', 'key_word='=>'string', 'start='=>'int', 'limit='=>'int', 'order='=>'int'], 'SeasLog::closeLoggerStream' => ['bool', 'model'=>'int', 'logger'=>'string'], 'SeasLog::critical' => ['bool', 'message'=>'string', 'content='=>'array', 'logger='=>'string'], 'SeasLog::debug' => ['bool', 'message'=>'string', 'content='=>'array', 'logger='=>'string'], 'SeasLog::emergency' => ['bool', 'message'=>'string', 'content='=>'array', 'logger='=>'string'], 'SeasLog::error' => ['bool', 'message'=>'string', 'content='=>'array', 'logger='=>'string'], 'SeasLog::flushBuffer' => ['bool'], 'SeasLog::getBasePath' => ['string'], 'SeasLog::getBuffer' => ['array'], 'SeasLog::getBufferEnabled' => ['bool'], 'SeasLog::getDatetimeFormat' => ['string'], 'SeasLog::getLastLogger' => ['string'], 'SeasLog::getRequestID' => ['string'], 'SeasLog::getRequestVariable' => ['bool', 'key'=>'int'], 'SeasLog::info' => ['bool', 'message'=>'string', 'content='=>'array', 'logger='=>'string'], 'SeasLog::log' => ['bool', 'level'=>'string', 'message='=>'string', 'content='=>'array', 'logger='=>'string'], 'SeasLog::notice' => ['bool', 'message'=>'string', 'content='=>'array', 'logger='=>'string'], 'SeasLog::setBasePath' => ['bool', 'base_path'=>'string'], 'SeasLog::setDatetimeFormat' => ['bool', 'format'=>'string'], 'SeasLog::setLogger' => ['bool', 'logger'=>'string'], 'SeasLog::setRequestID' => ['bool', 'request_id'=>'string'], 'SeasLog::setRequestVariable' => ['bool', 'key'=>'int', 'value'=>'string'], 'SeasLog::warning' => ['bool', 'message'=>'string', 'content='=>'array', 'logger='=>'string'], 'SeekableIterator::__construct' => ['void'], 'SeekableIterator::current' => ['mixed'], 'SeekableIterator::key' => ['int|string'], 'SeekableIterator::next' => ['void'], 'SeekableIterator::rewind' => ['void'], 'SeekableIterator::seek' => ['void', 'position'=>'int'], 'SeekableIterator::valid' => ['bool'], 'Serializable::__construct' => ['void'], 'Serializable::serialize' => ['?string'], 'Serializable::unserialize' => ['void', 'serialized'=>'string'], 'ServerRequest::withInput' => ['ServerRequest', 'input'=>'mixed'], 'ServerRequest::withParam' => ['ServerRequest', 'key'=>'int|string', 'value'=>'mixed'], 'ServerRequest::withParams' => ['ServerRequest', 'params'=>'mixed'], 'ServerRequest::withUrl' => ['ServerRequest', 'url'=>'array'], 'ServerRequest::withoutParams' => ['ServerRequest', 'params'=>'int|string'], 'ServerResponse::addHeader' => ['void', 'label'=>'string', 'value'=>'string'], 'ServerResponse::date' => ['string', 'date'=>'string|DateTimeInterface'], 'ServerResponse::getHeader' => ['string', 'label'=>'string'], 'ServerResponse::getHeaders' => ['string[]'], 'ServerResponse::getStatus' => ['int'], 'ServerResponse::getVersion' => ['string'], 'ServerResponse::setHeader' => ['void', 'label'=>'string', 'value'=>'string'], 'ServerResponse::setStatus' => ['void', 'status'=>'int'], 'ServerResponse::setVersion' => ['void', 'version'=>'string'], 'SessionHandler::close' => ['bool'], 'SessionHandler::create_sid' => ['string'], 'SessionHandler::destroy' => ['bool', 'id'=>'string'], 'SessionHandler::gc' => ['bool', 'max_lifetime'=>'int'], 'SessionHandler::open' => ['bool', 'path'=>'string', 'name'=>'string'], 'SessionHandler::read' => ['string|false', 'id'=>'string'], 'SessionHandler::write' => ['bool', 'id'=>'string', 'data'=>'string'], 'SessionHandlerInterface::close' => ['bool'], 'SessionHandlerInterface::destroy' => ['bool', 'id'=>'string'], 'SessionHandlerInterface::gc' => ['int|false', 'max_lifetime'=>'int'], 'SessionHandlerInterface::open' => ['bool', 'path'=>'string', 'name'=>'string'], 'SessionHandlerInterface::read' => ['string|false', 'id'=>'string'], 'SessionHandlerInterface::write' => ['bool', 'id'=>'string', 'data'=>'string'], 'SessionIdInterface::create_sid' => ['string'], 'SessionUpdateTimestampHandler::updateTimestamp' => ['bool', 'id'=>'string', 'data'=>'string'], 'SessionUpdateTimestampHandler::validateId' => ['char', 'id'=>'string'], 'SessionUpdateTimestampHandlerInterface::updateTimestamp' => ['bool', 'id'=>'string', 'data'=>'string'], 'SessionUpdateTimestampHandlerInterface::validateId' => ['bool', 'id'=>'string'], 'SimpleXMLElement::__construct' => ['void', 'data'=>'string', 'options='=>'int', 'dataIsURL='=>'bool', 'namespaceOrPrefix='=>'string', 'isPrefix='=>'bool'], 'SimpleXMLElement::__get' => ['SimpleXMLElement', 'name'=>'string'], 'SimpleXMLElement::__toString' => ['string'], 'SimpleXMLElement::addAttribute' => ['void', 'qualifiedName'=>'string', 'value'=>'string', 'namespace='=>'?string'], 'SimpleXMLElement::addChild' => ['?SimpleXMLElement', 'qualifiedName'=>'string', 'value='=>'?string', 'namespace='=>'?string'], 'SimpleXMLElement::asXML' => ['string|bool', 'filename'=>'string'], 'SimpleXMLElement::asXML\'1' => ['string|false'], 'SimpleXMLElement::attributes' => ['?SimpleXMLElement', 'namespaceOrPrefix='=>'?string', 'isPrefix='=>'bool'], 'SimpleXMLElement::children' => ['?SimpleXMLElement', 'namespaceOrPrefix='=>'?string', 'isPrefix='=>'bool'], 'SimpleXMLElement::count' => ['int'], 'SimpleXMLElement::getDocNamespaces' => ['array', 'recursive='=>'bool', 'fromRoot='=>'bool'], 'SimpleXMLElement::getName' => ['string'], 'SimpleXMLElement::getNamespaces' => ['array', 'recursive='=>'bool'], 'SimpleXMLElement::offsetExists' => ['bool', 'offset'=>'int|string'], 'SimpleXMLElement::offsetGet' => ['SimpleXMLElement', 'offset'=>'int|string'], 'SimpleXMLElement::offsetSet' => ['void', 'offset'=>'int|string|null', 'value'=>'mixed'], 'SimpleXMLElement::offsetUnset' => ['void', 'offset'=>'int|string'], 'SimpleXMLElement::registerXPathNamespace' => ['bool', 'prefix'=>'string', 'namespace'=>'string'], 'SimpleXMLElement::saveXML' => ['string|bool', 'filename='=>'string'], 'SimpleXMLElement::xpath' => ['SimpleXMLElement[]|false|null', 'expression'=>'string'], 'SimpleXMLIterator::current' => ['?SimpleXMLIterator'], 'SimpleXMLIterator::getChildren' => ['?SimpleXMLIterator'], 'SimpleXMLIterator::hasChildren' => ['bool'], 'SimpleXMLIterator::key' => ['string|false'], 'SimpleXMLIterator::next' => ['void'], 'SimpleXMLIterator::rewind' => ['void'], 'SimpleXMLIterator::valid' => ['bool'], 'SoapClient::SoapClient' => ['object', 'wsdl'=>'mixed', 'options='=>'array|null'], 'SoapClient::__call' => ['', 'function_name'=>'string', 'arguments'=>'array'], 'SoapClient::__construct' => ['void', 'wsdl'=>'mixed', 'options='=>'array|null'], 'SoapClient::__doRequest' => ['?string', 'request'=>'string', 'location'=>'string', 'action'=>'string', 'version'=>'int', 'one_way='=>'int'], 'SoapClient::__getCookies' => ['array'], 'SoapClient::__getFunctions' => ['?array'], 'SoapClient::__getLastRequest' => ['?string'], 'SoapClient::__getLastRequestHeaders' => ['?string'], 'SoapClient::__getLastResponse' => ['?string'], 'SoapClient::__getLastResponseHeaders' => ['?string'], 'SoapClient::__getTypes' => ['?array'], 'SoapClient::__setCookie' => ['', 'name'=>'string', 'value='=>'string'], 'SoapClient::__setLocation' => ['string', 'new_location='=>'string'], 'SoapClient::__setSoapHeaders' => ['bool', 'soapheaders='=>''], 'SoapClient::__soapCall' => ['', 'function_name'=>'string', 'arguments'=>'array', 'options='=>'array', 'input_headers='=>'SoapHeader|array', '&w_output_headers='=>'array'], 'SoapFault::SoapFault' => ['object', 'faultcode'=>'string', 'faultstring'=>'string', 'faultactor='=>'?string', 'detail='=>'?mixed', 'faultname='=>'?string', 'headerfault='=>'?mixed'], 'SoapFault::__clone' => ['void'], 'SoapFault::__construct' => ['void', 'code'=>'array|string|null', 'string'=>'string', 'actor='=>'?string', 'details='=>'?mixed', 'name='=>'?string', 'headerFault='=>'?mixed'], 'SoapFault::__toString' => ['string'], 'SoapFault::__wakeup' => ['void'], 'SoapFault::getCode' => ['int'], 'SoapFault::getFile' => ['string'], 'SoapFault::getLine' => ['int'], 'SoapFault::getMessage' => ['string'], 'SoapFault::getPrevious' => ['?Exception|?Throwable'], 'SoapFault::getTrace' => ['list\',args?:array}>'], 'SoapFault::getTraceAsString' => ['string'], 'SoapHeader::SoapHeader' => ['object', 'namespace'=>'string', 'name'=>'string', 'data='=>'mixed', 'mustunderstand='=>'bool', 'actor='=>'string'], 'SoapHeader::__construct' => ['void', 'namespace'=>'string', 'name'=>'string', 'data='=>'mixed', 'mustunderstand='=>'bool', 'actor='=>'string'], 'SoapParam::SoapParam' => ['object', 'data'=>'mixed', 'name'=>'string'], 'SoapParam::__construct' => ['void', 'data'=>'mixed', 'name'=>'string'], 'SoapServer::SoapServer' => ['object', 'wsdl'=>'?string', 'options='=>'array'], 'SoapServer::__construct' => ['void', 'wsdl'=>'?string', 'options='=>'array'], 'SoapServer::addFunction' => ['void', 'functions'=>'mixed'], 'SoapServer::addSoapHeader' => ['void', 'object'=>'SoapHeader'], 'SoapServer::fault' => ['void', 'code'=>'string', 'string'=>'string', 'actor='=>'string', 'details='=>'string', 'name='=>'string'], 'SoapServer::getFunctions' => ['array'], 'SoapServer::handle' => ['void', 'soap_request='=>'string'], 'SoapServer::setClass' => ['void', 'class_name'=>'string', '...args='=>'mixed'], 'SoapServer::setObject' => ['void', 'object'=>'object'], 'SoapServer::setPersistence' => ['void', 'mode'=>'int'], 'SoapVar::SoapVar' => ['object', 'data'=>'mixed', 'encoding'=>'int', 'type_name='=>'string|null', 'type_namespace='=>'string|null', 'node_name='=>'string|null', 'node_namespace='=>'string|null'], 'SoapVar::__construct' => ['void', 'data'=>'mixed', 'encoding'=>'int', 'type_name='=>'string|null', 'type_namespace='=>'string|null', 'node_name='=>'string|null', 'node_namespace='=>'string|null'], 'Sodium\add' => ['void', '&left'=>'string', 'right'=>'string'], 'Sodium\bin2hex' => ['string', 'binary'=>'string'], 'Sodium\compare' => ['int', 'left'=>'string', 'right'=>'string'], 'Sodium\crypto_aead_aes256gcm_decrypt' => ['string|false', 'msg'=>'string', 'nonce'=>'string', 'key'=>'string', 'ad='=>'string'], 'Sodium\crypto_aead_aes256gcm_encrypt' => ['string', 'msg'=>'string', 'nonce'=>'string', 'key'=>'string', 'ad='=>'string'], 'Sodium\crypto_aead_aes256gcm_is_available' => ['bool'], 'Sodium\crypto_aead_chacha20poly1305_decrypt' => ['string', 'msg'=>'string', 'nonce'=>'string', 'key'=>'string', 'ad='=>'string'], 'Sodium\crypto_aead_chacha20poly1305_encrypt' => ['string', 'msg'=>'string', 'nonce'=>'string', 'key'=>'string', 'ad='=>'string'], 'Sodium\crypto_auth' => ['string', 'msg'=>'string', 'key'=>'string'], 'Sodium\crypto_auth_verify' => ['bool', 'mac'=>'string', 'msg'=>'string', 'key'=>'string'], 'Sodium\crypto_box' => ['string', 'msg'=>'string', 'nonce'=>'string', 'keypair'=>'string'], 'Sodium\crypto_box_keypair' => ['string'], 'Sodium\crypto_box_keypair_from_secretkey_and_publickey' => ['string', 'secretkey'=>'string', 'publickey'=>'string'], 'Sodium\crypto_box_open' => ['string', 'msg'=>'string', 'nonce'=>'string', 'keypair'=>'string'], 'Sodium\crypto_box_publickey' => ['string', 'keypair'=>'string'], 'Sodium\crypto_box_publickey_from_secretkey' => ['string', 'secretkey'=>'string'], 'Sodium\crypto_box_seal' => ['string', 'message'=>'string', 'publickey'=>'string'], 'Sodium\crypto_box_seal_open' => ['string', 'encrypted'=>'string', 'keypair'=>'string'], 'Sodium\crypto_box_secretkey' => ['string', 'keypair'=>'string'], 'Sodium\crypto_box_seed_keypair' => ['string', 'seed'=>'string'], 'Sodium\crypto_generichash' => ['string', 'input'=>'string', 'key='=>'string', 'length='=>'int'], 'Sodium\crypto_generichash_final' => ['string', 'state'=>'string', 'length='=>'int'], 'Sodium\crypto_generichash_init' => ['string', 'key='=>'string', 'length='=>'int'], 'Sodium\crypto_generichash_update' => ['bool', '&hashState'=>'string', 'append'=>'string'], 'Sodium\crypto_kx' => ['string', 'secretkey'=>'string', 'publickey'=>'string', 'client_publickey'=>'string', 'server_publickey'=>'string'], 'Sodium\crypto_pwhash' => ['string', 'out_len'=>'int', 'passwd'=>'string', 'salt'=>'string', 'opslimit'=>'int', 'memlimit'=>'int'], 'Sodium\crypto_pwhash_scryptsalsa208sha256' => ['string', 'out_len'=>'int', 'passwd'=>'string', 'salt'=>'string', 'opslimit'=>'int', 'memlimit'=>'int'], 'Sodium\crypto_pwhash_scryptsalsa208sha256_str' => ['string', 'passwd'=>'string', 'opslimit'=>'int', 'memlimit'=>'int'], 'Sodium\crypto_pwhash_scryptsalsa208sha256_str_verify' => ['bool', 'hash'=>'string', 'passwd'=>'string'], 'Sodium\crypto_pwhash_str' => ['string', 'passwd'=>'string', 'opslimit'=>'int', 'memlimit'=>'int'], 'Sodium\crypto_pwhash_str_verify' => ['bool', 'hash'=>'string', 'passwd'=>'string'], 'Sodium\crypto_scalarmult' => ['string', 'ecdhA'=>'string', 'ecdhB'=>'string'], 'Sodium\crypto_scalarmult_base' => ['string', 'sk'=>'string'], 'Sodium\crypto_secretbox' => ['string', 'plaintext'=>'string', 'nonce'=>'string', 'key'=>'string'], 'Sodium\crypto_secretbox_open' => ['string', 'ciphertext'=>'string', 'nonce'=>'string', 'key'=>'string'], 'Sodium\crypto_shorthash' => ['string', 'message'=>'string', 'key'=>'string'], 'Sodium\crypto_sign' => ['string', 'message'=>'string', 'secretkey'=>'string'], 'Sodium\crypto_sign_detached' => ['string', 'message'=>'string', 'secretkey'=>'string'], 'Sodium\crypto_sign_ed25519_pk_to_curve25519' => ['string', 'sign_pk'=>'string'], 'Sodium\crypto_sign_ed25519_sk_to_curve25519' => ['string', 'sign_sk'=>'string'], 'Sodium\crypto_sign_keypair' => ['string'], 'Sodium\crypto_sign_keypair_from_secretkey_and_publickey' => ['string', 'secretkey'=>'string', 'publickey'=>'string'], 'Sodium\crypto_sign_open' => ['string|false', 'signed_message'=>'string', 'publickey'=>'string'], 'Sodium\crypto_sign_publickey' => ['string', 'keypair'=>'string'], 'Sodium\crypto_sign_publickey_from_secretkey' => ['string', 'secretkey'=>'string'], 'Sodium\crypto_sign_secretkey' => ['string', 'keypair'=>'string'], 'Sodium\crypto_sign_seed_keypair' => ['string', 'seed'=>'string'], 'Sodium\crypto_sign_verify_detached' => ['bool', 'signature'=>'string', 'msg'=>'string', 'publickey'=>'string'], 'Sodium\crypto_stream' => ['string', 'length'=>'int', 'nonce'=>'string', 'key'=>'string'], 'Sodium\crypto_stream_xor' => ['string', 'plaintext'=>'string', 'nonce'=>'string', 'key'=>'string'], 'Sodium\hex2bin' => ['string', 'hex'=>'string'], 'Sodium\increment' => ['string', '&nonce'=>'string'], 'Sodium\library_version_major' => ['int'], 'Sodium\library_version_minor' => ['int'], 'Sodium\memcmp' => ['int', 'left'=>'string', 'right'=>'string'], 'Sodium\memzero' => ['void', '&target'=>'string'], 'Sodium\randombytes_buf' => ['string', 'length'=>'int'], 'Sodium\randombytes_random16' => ['int|string'], 'Sodium\randombytes_uniform' => ['int', 'upperBoundNonInclusive'=>'int'], 'Sodium\version_string' => ['string'], 'SolrClient::__construct' => ['void', 'clientOptions'=>'array'], 'SolrClient::__destruct' => ['void'], 'SolrClient::addDocument' => ['SolrUpdateResponse', 'doc'=>'SolrInputDocument', 'allowdups='=>'bool', 'commitwithin='=>'int'], 'SolrClient::addDocuments' => ['SolrUpdateResponse', 'docs'=>'array', 'allowdups='=>'bool', 'commitwithin='=>'int'], 'SolrClient::commit' => ['SolrUpdateResponse', 'maxsegments='=>'int', 'waitflush='=>'bool', 'waitsearcher='=>'bool'], 'SolrClient::deleteById' => ['SolrUpdateResponse', 'id'=>'string'], 'SolrClient::deleteByIds' => ['SolrUpdateResponse', 'ids'=>'array'], 'SolrClient::deleteByQueries' => ['SolrUpdateResponse', 'queries'=>'array'], 'SolrClient::deleteByQuery' => ['SolrUpdateResponse', 'query'=>'string'], 'SolrClient::getById' => ['SolrQueryResponse', 'id'=>'string'], 'SolrClient::getByIds' => ['SolrQueryResponse', 'ids'=>'array'], 'SolrClient::getDebug' => ['string'], 'SolrClient::getOptions' => ['array'], 'SolrClient::optimize' => ['SolrUpdateResponse', 'maxsegments='=>'int', 'waitflush='=>'bool', 'waitsearcher='=>'bool'], 'SolrClient::ping' => ['SolrPingResponse'], 'SolrClient::query' => ['SolrQueryResponse', 'query'=>'SolrParams'], 'SolrClient::request' => ['SolrUpdateResponse', 'raw_request'=>'string'], 'SolrClient::rollback' => ['SolrUpdateResponse'], 'SolrClient::setResponseWriter' => ['void', 'responsewriter'=>'string'], 'SolrClient::setServlet' => ['bool', 'type'=>'int', 'value'=>'string'], 'SolrClient::system' => ['SolrGenericResponse'], 'SolrClient::threads' => ['SolrGenericResponse'], 'SolrClientException::__clone' => ['void'], 'SolrClientException::__construct' => ['void', 'message='=>'string', 'code='=>'int', 'previous='=>'?Exception|?Throwable'], 'SolrClientException::__toString' => ['string'], 'SolrClientException::__wakeup' => ['void'], 'SolrClientException::getCode' => ['int'], 'SolrClientException::getFile' => ['string'], 'SolrClientException::getInternalInfo' => ['array'], 'SolrClientException::getLine' => ['int'], 'SolrClientException::getMessage' => ['string'], 'SolrClientException::getPrevious' => ['?Exception|?Throwable'], 'SolrClientException::getTrace' => ['list\',args?:array}>'], 'SolrClientException::getTraceAsString' => ['string'], 'SolrCollapseFunction::__construct' => ['void', 'field'=>'string'], 'SolrCollapseFunction::__toString' => ['string'], 'SolrCollapseFunction::getField' => ['string'], 'SolrCollapseFunction::getHint' => ['string'], 'SolrCollapseFunction::getMax' => ['string'], 'SolrCollapseFunction::getMin' => ['string'], 'SolrCollapseFunction::getNullPolicy' => ['string'], 'SolrCollapseFunction::getSize' => ['int'], 'SolrCollapseFunction::setField' => ['SolrCollapseFunction', 'fieldName'=>'string'], 'SolrCollapseFunction::setHint' => ['SolrCollapseFunction', 'hint'=>'string'], 'SolrCollapseFunction::setMax' => ['SolrCollapseFunction', 'max'=>'string'], 'SolrCollapseFunction::setMin' => ['SolrCollapseFunction', 'min'=>'string'], 'SolrCollapseFunction::setNullPolicy' => ['SolrCollapseFunction', 'nullPolicy'=>'string'], 'SolrCollapseFunction::setSize' => ['SolrCollapseFunction', 'size'=>'int'], 'SolrDisMaxQuery::__construct' => ['void', 'q='=>'string'], 'SolrDisMaxQuery::__destruct' => ['void'], 'SolrDisMaxQuery::add' => ['SolrParams', 'name'=>'string', 'value'=>'string'], 'SolrDisMaxQuery::addBigramPhraseField' => ['SolrDisMaxQuery', 'field'=>'string', 'boost'=>'string', 'slop='=>'string'], 'SolrDisMaxQuery::addBoostQuery' => ['SolrDisMaxQuery', 'field'=>'string', 'value'=>'string', 'boost='=>'string'], 'SolrDisMaxQuery::addExpandFilterQuery' => ['SolrQuery', 'fq'=>'string'], 'SolrDisMaxQuery::addExpandSortField' => ['SolrQuery', 'field'=>'string', 'order'=>'string'], 'SolrDisMaxQuery::addFacetDateField' => ['SolrQuery', 'dateField'=>'string'], 'SolrDisMaxQuery::addFacetDateOther' => ['SolrQuery', 'value'=>'string', 'field_override'=>'string'], 'SolrDisMaxQuery::addFacetField' => ['SolrQuery', 'field'=>'string'], 'SolrDisMaxQuery::addFacetQuery' => ['SolrQuery', 'facetQuery'=>'string'], 'SolrDisMaxQuery::addField' => ['SolrQuery', 'field'=>'string'], 'SolrDisMaxQuery::addFilterQuery' => ['SolrQuery', 'fq'=>'string'], 'SolrDisMaxQuery::addGroupField' => ['SolrQuery', 'value'=>'string'], 'SolrDisMaxQuery::addGroupFunction' => ['SolrQuery', 'value'=>'string'], 'SolrDisMaxQuery::addGroupQuery' => ['SolrQuery', 'value'=>'string'], 'SolrDisMaxQuery::addGroupSortField' => ['SolrQuery', 'field'=>'string', 'order'=>'int'], 'SolrDisMaxQuery::addHighlightField' => ['SolrQuery', 'field'=>'string'], 'SolrDisMaxQuery::addMltField' => ['SolrQuery', 'field'=>'string'], 'SolrDisMaxQuery::addMltQueryField' => ['SolrQuery', 'field'=>'string', 'boost'=>'float'], 'SolrDisMaxQuery::addParam' => ['SolrParams', 'name'=>'string', 'value'=>'string'], 'SolrDisMaxQuery::addPhraseField' => ['SolrDisMaxQuery', 'field'=>'string', 'boost'=>'string', 'slop='=>'string'], 'SolrDisMaxQuery::addQueryField' => ['SolrDisMaxQuery', 'field'=>'string', 'boost='=>'string'], 'SolrDisMaxQuery::addSortField' => ['SolrQuery', 'field'=>'string', 'order='=>'int'], 'SolrDisMaxQuery::addStatsFacet' => ['SolrQuery', 'field'=>'string'], 'SolrDisMaxQuery::addStatsField' => ['SolrQuery', 'field'=>'string'], 'SolrDisMaxQuery::addTrigramPhraseField' => ['SolrDisMaxQuery', 'field'=>'string', 'boost'=>'string', 'slop='=>'string'], 'SolrDisMaxQuery::addUserField' => ['SolrDisMaxQuery', 'field'=>'string'], 'SolrDisMaxQuery::collapse' => ['SolrQuery', 'collapseFunction'=>'SolrCollapseFunction'], 'SolrDisMaxQuery::get' => ['mixed', 'param_name'=>'string'], 'SolrDisMaxQuery::getExpand' => ['bool'], 'SolrDisMaxQuery::getExpandFilterQueries' => ['array'], 'SolrDisMaxQuery::getExpandQuery' => ['array'], 'SolrDisMaxQuery::getExpandRows' => ['int'], 'SolrDisMaxQuery::getExpandSortFields' => ['array'], 'SolrDisMaxQuery::getFacet' => ['bool'], 'SolrDisMaxQuery::getFacetDateEnd' => ['string', 'field_override'=>'string'], 'SolrDisMaxQuery::getFacetDateFields' => ['array'], 'SolrDisMaxQuery::getFacetDateGap' => ['string', 'field_override'=>'string'], 'SolrDisMaxQuery::getFacetDateHardEnd' => ['string', 'field_override'=>'string'], 'SolrDisMaxQuery::getFacetDateOther' => ['string', 'field_override'=>'string'], 'SolrDisMaxQuery::getFacetDateStart' => ['string', 'field_override'=>'string'], 'SolrDisMaxQuery::getFacetFields' => ['array'], 'SolrDisMaxQuery::getFacetLimit' => ['int', 'field_override'=>'string'], 'SolrDisMaxQuery::getFacetMethod' => ['string', 'field_override'=>'string'], 'SolrDisMaxQuery::getFacetMinCount' => ['int', 'field_override'=>'string'], 'SolrDisMaxQuery::getFacetMissing' => ['string', 'field_override'=>'string'], 'SolrDisMaxQuery::getFacetOffset' => ['int', 'field_override'=>'string'], 'SolrDisMaxQuery::getFacetPrefix' => ['string', 'field_override'=>'string'], 'SolrDisMaxQuery::getFacetQueries' => ['string'], 'SolrDisMaxQuery::getFacetSort' => ['int', 'field_override'=>'string'], 'SolrDisMaxQuery::getFields' => ['string'], 'SolrDisMaxQuery::getFilterQueries' => ['string'], 'SolrDisMaxQuery::getGroup' => ['bool'], 'SolrDisMaxQuery::getGroupCachePercent' => ['int'], 'SolrDisMaxQuery::getGroupFacet' => ['bool'], 'SolrDisMaxQuery::getGroupFields' => ['array'], 'SolrDisMaxQuery::getGroupFormat' => ['string'], 'SolrDisMaxQuery::getGroupFunctions' => ['array'], 'SolrDisMaxQuery::getGroupLimit' => ['int'], 'SolrDisMaxQuery::getGroupMain' => ['bool'], 'SolrDisMaxQuery::getGroupNGroups' => ['bool'], 'SolrDisMaxQuery::getGroupOffset' => ['bool'], 'SolrDisMaxQuery::getGroupQueries' => ['array'], 'SolrDisMaxQuery::getGroupSortFields' => ['array'], 'SolrDisMaxQuery::getGroupTruncate' => ['bool'], 'SolrDisMaxQuery::getHighlight' => ['bool'], 'SolrDisMaxQuery::getHighlightAlternateField' => ['string', 'field_override'=>'string'], 'SolrDisMaxQuery::getHighlightFields' => ['array'], 'SolrDisMaxQuery::getHighlightFormatter' => ['string', 'field_override'=>'string'], 'SolrDisMaxQuery::getHighlightFragmenter' => ['string', 'field_override'=>'string'], 'SolrDisMaxQuery::getHighlightFragsize' => ['int', 'field_override'=>'string'], 'SolrDisMaxQuery::getHighlightHighlightMultiTerm' => ['bool'], 'SolrDisMaxQuery::getHighlightMaxAlternateFieldLength' => ['int', 'field_override'=>'string'], 'SolrDisMaxQuery::getHighlightMaxAnalyzedChars' => ['int'], 'SolrDisMaxQuery::getHighlightMergeContiguous' => ['bool', 'field_override'=>'string'], 'SolrDisMaxQuery::getHighlightRegexMaxAnalyzedChars' => ['int'], 'SolrDisMaxQuery::getHighlightRegexPattern' => ['string'], 'SolrDisMaxQuery::getHighlightRegexSlop' => ['float'], 'SolrDisMaxQuery::getHighlightRequireFieldMatch' => ['bool'], 'SolrDisMaxQuery::getHighlightSimplePost' => ['string', 'field_override'=>'string'], 'SolrDisMaxQuery::getHighlightSimplePre' => ['string', 'field_override'=>'string'], 'SolrDisMaxQuery::getHighlightSnippets' => ['int', 'field_override'=>'string'], 'SolrDisMaxQuery::getHighlightUsePhraseHighlighter' => ['bool'], 'SolrDisMaxQuery::getMlt' => ['bool'], 'SolrDisMaxQuery::getMltBoost' => ['bool'], 'SolrDisMaxQuery::getMltCount' => ['int'], 'SolrDisMaxQuery::getMltFields' => ['array'], 'SolrDisMaxQuery::getMltMaxNumQueryTerms' => ['int'], 'SolrDisMaxQuery::getMltMaxNumTokens' => ['int'], 'SolrDisMaxQuery::getMltMaxWordLength' => ['int'], 'SolrDisMaxQuery::getMltMinDocFrequency' => ['int'], 'SolrDisMaxQuery::getMltMinTermFrequency' => ['int'], 'SolrDisMaxQuery::getMltMinWordLength' => ['int'], 'SolrDisMaxQuery::getMltQueryFields' => ['array'], 'SolrDisMaxQuery::getParam' => ['mixed', 'param_name'=>'string'], 'SolrDisMaxQuery::getParams' => ['array'], 'SolrDisMaxQuery::getPreparedParams' => ['array'], 'SolrDisMaxQuery::getQuery' => ['string'], 'SolrDisMaxQuery::getRows' => ['int'], 'SolrDisMaxQuery::getSortFields' => ['array'], 'SolrDisMaxQuery::getStart' => ['int'], 'SolrDisMaxQuery::getStats' => ['bool'], 'SolrDisMaxQuery::getStatsFacets' => ['array'], 'SolrDisMaxQuery::getStatsFields' => ['array'], 'SolrDisMaxQuery::getTerms' => ['bool'], 'SolrDisMaxQuery::getTermsField' => ['string'], 'SolrDisMaxQuery::getTermsIncludeLowerBound' => ['bool'], 'SolrDisMaxQuery::getTermsIncludeUpperBound' => ['bool'], 'SolrDisMaxQuery::getTermsLimit' => ['int'], 'SolrDisMaxQuery::getTermsLowerBound' => ['string'], 'SolrDisMaxQuery::getTermsMaxCount' => ['int'], 'SolrDisMaxQuery::getTermsMinCount' => ['int'], 'SolrDisMaxQuery::getTermsPrefix' => ['string'], 'SolrDisMaxQuery::getTermsReturnRaw' => ['bool'], 'SolrDisMaxQuery::getTermsSort' => ['int'], 'SolrDisMaxQuery::getTermsUpperBound' => ['string'], 'SolrDisMaxQuery::getTimeAllowed' => ['int'], 'SolrDisMaxQuery::removeBigramPhraseField' => ['SolrDisMaxQuery', 'field'=>'string'], 'SolrDisMaxQuery::removeBoostQuery' => ['SolrDisMaxQuery', 'field'=>'string'], 'SolrDisMaxQuery::removeExpandFilterQuery' => ['SolrQuery', 'fq'=>'string'], 'SolrDisMaxQuery::removeExpandSortField' => ['SolrQuery', 'field'=>'string'], 'SolrDisMaxQuery::removeFacetDateField' => ['SolrQuery', 'field'=>'string'], 'SolrDisMaxQuery::removeFacetDateOther' => ['SolrQuery', 'value'=>'string', 'field_override'=>'string'], 'SolrDisMaxQuery::removeFacetField' => ['SolrQuery', 'field'=>'string'], 'SolrDisMaxQuery::removeFacetQuery' => ['SolrQuery', 'value'=>'string'], 'SolrDisMaxQuery::removeField' => ['SolrQuery', 'field'=>'string'], 'SolrDisMaxQuery::removeFilterQuery' => ['SolrQuery', 'fq'=>'string'], 'SolrDisMaxQuery::removeHighlightField' => ['SolrQuery', 'field'=>'string'], 'SolrDisMaxQuery::removeMltField' => ['SolrQuery', 'field'=>'string'], 'SolrDisMaxQuery::removeMltQueryField' => ['SolrQuery', 'queryField'=>'string'], 'SolrDisMaxQuery::removePhraseField' => ['SolrDisMaxQuery', 'field'=>'string'], 'SolrDisMaxQuery::removeQueryField' => ['SolrDisMaxQuery', 'field'=>'string'], 'SolrDisMaxQuery::removeSortField' => ['SolrQuery', 'field'=>'string'], 'SolrDisMaxQuery::removeStatsFacet' => ['SolrQuery', 'value'=>'string'], 'SolrDisMaxQuery::removeStatsField' => ['SolrQuery', 'field'=>'string'], 'SolrDisMaxQuery::removeTrigramPhraseField' => ['SolrDisMaxQuery', 'field'=>'string'], 'SolrDisMaxQuery::removeUserField' => ['SolrDisMaxQuery', 'field'=>'string'], 'SolrDisMaxQuery::serialize' => ['string'], 'SolrDisMaxQuery::set' => ['SolrParams', 'name'=>'string', 'value'=>''], 'SolrDisMaxQuery::setBigramPhraseFields' => ['SolrDisMaxQuery', 'fields'=>'string'], 'SolrDisMaxQuery::setBigramPhraseSlop' => ['SolrDisMaxQuery', 'slop'=>'string'], 'SolrDisMaxQuery::setBoostFunction' => ['SolrDisMaxQuery', 'function'=>'string'], 'SolrDisMaxQuery::setBoostQuery' => ['SolrDisMaxQuery', 'q'=>'string'], 'SolrDisMaxQuery::setEchoHandler' => ['SolrQuery', 'flag'=>'bool'], 'SolrDisMaxQuery::setEchoParams' => ['SolrQuery', 'type'=>'string'], 'SolrDisMaxQuery::setExpand' => ['SolrQuery', 'value'=>'bool'], 'SolrDisMaxQuery::setExpandQuery' => ['SolrQuery', 'q'=>'string'], 'SolrDisMaxQuery::setExpandRows' => ['SolrQuery', 'value'=>'int'], 'SolrDisMaxQuery::setExplainOther' => ['SolrQuery', 'query'=>'string'], 'SolrDisMaxQuery::setFacet' => ['SolrQuery', 'flag'=>'bool'], 'SolrDisMaxQuery::setFacetDateEnd' => ['SolrQuery', 'value'=>'string', 'field_override'=>'string'], 'SolrDisMaxQuery::setFacetDateGap' => ['SolrQuery', 'value'=>'string', 'field_override'=>'string'], 'SolrDisMaxQuery::setFacetDateHardEnd' => ['SolrQuery', 'value'=>'string', 'field_override'=>'string'], 'SolrDisMaxQuery::setFacetDateStart' => ['SolrQuery', 'value'=>'string', 'field_override'=>'string'], 'SolrDisMaxQuery::setFacetEnumCacheMinDefaultFrequency' => ['SolrQuery', 'frequency'=>'int', 'field_override'=>'string'], 'SolrDisMaxQuery::setFacetLimit' => ['SolrQuery', 'limit'=>'int', 'field_override'=>'string'], 'SolrDisMaxQuery::setFacetMethod' => ['SolrQuery', 'method'=>'string', 'field_override'=>'string'], 'SolrDisMaxQuery::setFacetMinCount' => ['SolrQuery', 'mincount'=>'int', 'field_override'=>'string'], 'SolrDisMaxQuery::setFacetMissing' => ['SolrQuery', 'flag'=>'bool', 'field_override'=>'string'], 'SolrDisMaxQuery::setFacetOffset' => ['SolrQuery', 'offset'=>'int', 'field_override'=>'string'], 'SolrDisMaxQuery::setFacetPrefix' => ['SolrQuery', 'prefix'=>'string', 'field_override'=>'string'], 'SolrDisMaxQuery::setFacetSort' => ['SolrQuery', 'facetSort'=>'int', 'field_override'=>'string'], 'SolrDisMaxQuery::setGroup' => ['SolrQuery', 'value'=>'bool'], 'SolrDisMaxQuery::setGroupCachePercent' => ['SolrQuery', 'percent'=>'int'], 'SolrDisMaxQuery::setGroupFacet' => ['SolrQuery', 'value'=>'bool'], 'SolrDisMaxQuery::setGroupFormat' => ['SolrQuery', 'value'=>'string'], 'SolrDisMaxQuery::setGroupLimit' => ['SolrQuery', 'value'=>'int'], 'SolrDisMaxQuery::setGroupMain' => ['SolrQuery', 'value'=>'string'], 'SolrDisMaxQuery::setGroupNGroups' => ['SolrQuery', 'value'=>'bool'], 'SolrDisMaxQuery::setGroupOffset' => ['SolrQuery', 'value'=>'int'], 'SolrDisMaxQuery::setGroupTruncate' => ['SolrQuery', 'value'=>'bool'], 'SolrDisMaxQuery::setHighlight' => ['SolrQuery', 'flag'=>'bool'], 'SolrDisMaxQuery::setHighlightAlternateField' => ['SolrQuery', 'field'=>'string', 'field_override'=>'string'], 'SolrDisMaxQuery::setHighlightFormatter' => ['SolrQuery', 'formatter'=>'string', 'field_override'=>'string'], 'SolrDisMaxQuery::setHighlightFragmenter' => ['SolrQuery', 'fragmenter'=>'string', 'field_override'=>'string'], 'SolrDisMaxQuery::setHighlightFragsize' => ['SolrQuery', 'size'=>'int', 'field_override'=>'string'], 'SolrDisMaxQuery::setHighlightHighlightMultiTerm' => ['SolrQuery', 'flag'=>'bool'], 'SolrDisMaxQuery::setHighlightMaxAlternateFieldLength' => ['SolrQuery', 'fieldLength'=>'string', 'field_override'=>'string'], 'SolrDisMaxQuery::setHighlightMaxAnalyzedChars' => ['SolrQuery', 'value'=>'int'], 'SolrDisMaxQuery::setHighlightMergeContiguous' => ['SolrQuery', 'flag'=>'bool', 'field_override'=>'string'], 'SolrDisMaxQuery::setHighlightRegexMaxAnalyzedChars' => ['SolrQuery', 'maxAnalyzedChars'=>'int'], 'SolrDisMaxQuery::setHighlightRegexPattern' => ['SolrQuery', 'value'=>'string'], 'SolrDisMaxQuery::setHighlightRegexSlop' => ['SolrQuery', 'factor'=>'float'], 'SolrDisMaxQuery::setHighlightRequireFieldMatch' => ['SolrQuery', 'flag'=>'bool'], 'SolrDisMaxQuery::setHighlightSimplePost' => ['SolrQuery', 'simplePost'=>'string', 'field_override'=>'string'], 'SolrDisMaxQuery::setHighlightSimplePre' => ['SolrQuery', 'simplePre'=>'string', 'field_override'=>'string'], 'SolrDisMaxQuery::setHighlightSnippets' => ['SolrQuery', 'value'=>'int', 'field_override'=>'string'], 'SolrDisMaxQuery::setHighlightUsePhraseHighlighter' => ['SolrQuery', 'flag'=>'bool'], 'SolrDisMaxQuery::setMinimumMatch' => ['SolrDisMaxQuery', 'value'=>'string'], 'SolrDisMaxQuery::setMlt' => ['SolrQuery', 'flag'=>'bool'], 'SolrDisMaxQuery::setMltBoost' => ['SolrQuery', 'flag'=>'bool'], 'SolrDisMaxQuery::setMltCount' => ['SolrQuery', 'count'=>'int'], 'SolrDisMaxQuery::setMltMaxNumQueryTerms' => ['SolrQuery', 'value'=>'int'], 'SolrDisMaxQuery::setMltMaxNumTokens' => ['SolrQuery', 'value'=>'int'], 'SolrDisMaxQuery::setMltMaxWordLength' => ['SolrQuery', 'maxWordLength'=>'int'], 'SolrDisMaxQuery::setMltMinDocFrequency' => ['SolrQuery', 'minDocFrequency'=>'int'], 'SolrDisMaxQuery::setMltMinTermFrequency' => ['SolrQuery', 'minTermFrequency'=>'int'], 'SolrDisMaxQuery::setMltMinWordLength' => ['SolrQuery', 'minWordLength'=>'int'], 'SolrDisMaxQuery::setOmitHeader' => ['SolrQuery', 'flag'=>'bool'], 'SolrDisMaxQuery::setParam' => ['SolrParams', 'name'=>'string', 'value'=>''], 'SolrDisMaxQuery::setPhraseFields' => ['SolrDisMaxQuery', 'fields'=>'string'], 'SolrDisMaxQuery::setPhraseSlop' => ['SolrDisMaxQuery', 'slop'=>'string'], 'SolrDisMaxQuery::setQuery' => ['SolrQuery', 'query'=>'string'], 'SolrDisMaxQuery::setQueryAlt' => ['SolrDisMaxQuery', 'q'=>'string'], 'SolrDisMaxQuery::setQueryPhraseSlop' => ['SolrDisMaxQuery', 'slop'=>'string'], 'SolrDisMaxQuery::setRows' => ['SolrQuery', 'rows'=>'int'], 'SolrDisMaxQuery::setShowDebugInfo' => ['SolrQuery', 'flag'=>'bool'], 'SolrDisMaxQuery::setStart' => ['SolrQuery', 'start'=>'int'], 'SolrDisMaxQuery::setStats' => ['SolrQuery', 'flag'=>'bool'], 'SolrDisMaxQuery::setTerms' => ['SolrQuery', 'flag'=>'bool'], 'SolrDisMaxQuery::setTermsField' => ['SolrQuery', 'fieldname'=>'string'], 'SolrDisMaxQuery::setTermsIncludeLowerBound' => ['SolrQuery', 'flag'=>'bool'], 'SolrDisMaxQuery::setTermsIncludeUpperBound' => ['SolrQuery', 'flag'=>'bool'], 'SolrDisMaxQuery::setTermsLimit' => ['SolrQuery', 'limit'=>'int'], 'SolrDisMaxQuery::setTermsLowerBound' => ['SolrQuery', 'lowerBound'=>'string'], 'SolrDisMaxQuery::setTermsMaxCount' => ['SolrQuery', 'frequency'=>'int'], 'SolrDisMaxQuery::setTermsMinCount' => ['SolrQuery', 'frequency'=>'int'], 'SolrDisMaxQuery::setTermsPrefix' => ['SolrQuery', 'prefix'=>'string'], 'SolrDisMaxQuery::setTermsReturnRaw' => ['SolrQuery', 'flag'=>'bool'], 'SolrDisMaxQuery::setTermsSort' => ['SolrQuery', 'sortType'=>'int'], 'SolrDisMaxQuery::setTermsUpperBound' => ['SolrQuery', 'upperBound'=>'string'], 'SolrDisMaxQuery::setTieBreaker' => ['SolrDisMaxQuery', 'tieBreaker'=>'string'], 'SolrDisMaxQuery::setTimeAllowed' => ['SolrQuery', 'timeAllowed'=>'int'], 'SolrDisMaxQuery::setTrigramPhraseFields' => ['SolrDisMaxQuery', 'fields'=>'string'], 'SolrDisMaxQuery::setTrigramPhraseSlop' => ['SolrDisMaxQuery', 'slop'=>'string'], 'SolrDisMaxQuery::setUserFields' => ['SolrDisMaxQuery', 'fields'=>'string'], 'SolrDisMaxQuery::toString' => ['string', 'url_encode='=>'bool'], 'SolrDisMaxQuery::unserialize' => ['void', 'serialized'=>'string'], 'SolrDisMaxQuery::useDisMaxQueryParser' => ['SolrDisMaxQuery'], 'SolrDisMaxQuery::useEDisMaxQueryParser' => ['SolrDisMaxQuery'], 'SolrDocument::__clone' => ['void'], 'SolrDocument::__construct' => ['void'], 'SolrDocument::__destruct' => ['void'], 'SolrDocument::__get' => ['SolrDocumentField', 'fieldname'=>'string'], 'SolrDocument::__isset' => ['bool', 'fieldname'=>'string'], 'SolrDocument::__set' => ['bool', 'fieldname'=>'string', 'fieldvalue'=>'string'], 'SolrDocument::__unset' => ['bool', 'fieldname'=>'string'], 'SolrDocument::addField' => ['bool', 'fieldname'=>'string', 'fieldvalue'=>'string'], 'SolrDocument::clear' => ['bool'], 'SolrDocument::current' => ['SolrDocumentField'], 'SolrDocument::deleteField' => ['bool', 'fieldname'=>'string'], 'SolrDocument::fieldExists' => ['bool', 'fieldname'=>'string'], 'SolrDocument::getChildDocuments' => ['SolrInputDocument[]'], 'SolrDocument::getChildDocumentsCount' => ['int'], 'SolrDocument::getField' => ['SolrDocumentField|false', 'fieldname'=>'string'], 'SolrDocument::getFieldCount' => ['int|false'], 'SolrDocument::getFieldNames' => ['array|false'], 'SolrDocument::getInputDocument' => ['SolrInputDocument'], 'SolrDocument::hasChildDocuments' => ['bool'], 'SolrDocument::key' => ['string'], 'SolrDocument::merge' => ['bool', 'sourcedoc'=>'solrdocument', 'overwrite='=>'bool'], 'SolrDocument::next' => ['void'], 'SolrDocument::offsetExists' => ['bool', 'fieldname'=>'string'], 'SolrDocument::offsetGet' => ['SolrDocumentField', 'fieldname'=>'string'], 'SolrDocument::offsetSet' => ['void', 'fieldname'=>'string', 'fieldvalue'=>'string'], 'SolrDocument::offsetUnset' => ['void', 'fieldname'=>'string'], 'SolrDocument::reset' => ['bool'], 'SolrDocument::rewind' => ['void'], 'SolrDocument::serialize' => ['string'], 'SolrDocument::sort' => ['bool', 'sortorderby'=>'int', 'sortdirection='=>'int'], 'SolrDocument::toArray' => ['array'], 'SolrDocument::unserialize' => ['void', 'serialized'=>'string'], 'SolrDocument::valid' => ['bool'], 'SolrDocumentField::__construct' => ['void'], 'SolrDocumentField::__destruct' => ['void'], 'SolrException::__clone' => ['void'], 'SolrException::__construct' => ['void', 'message='=>'string', 'code='=>'int', 'previous='=>'?Exception|?Throwable'], 'SolrException::__toString' => ['string'], 'SolrException::__wakeup' => ['void'], 'SolrException::getCode' => ['int'], 'SolrException::getFile' => ['string'], 'SolrException::getInternalInfo' => ['array'], 'SolrException::getLine' => ['int'], 'SolrException::getMessage' => ['string'], 'SolrException::getPrevious' => ['Exception|Throwable'], 'SolrException::getTrace' => ['list\',args?:array}>'], 'SolrException::getTraceAsString' => ['string'], 'SolrGenericResponse::__construct' => ['void'], 'SolrGenericResponse::__destruct' => ['void'], 'SolrGenericResponse::getDigestedResponse' => ['string'], 'SolrGenericResponse::getHttpStatus' => ['int'], 'SolrGenericResponse::getHttpStatusMessage' => ['string'], 'SolrGenericResponse::getRawRequest' => ['string'], 'SolrGenericResponse::getRawRequestHeaders' => ['string'], 'SolrGenericResponse::getRawResponse' => ['string'], 'SolrGenericResponse::getRawResponseHeaders' => ['string'], 'SolrGenericResponse::getRequestUrl' => ['string'], 'SolrGenericResponse::getResponse' => ['SolrObject'], 'SolrGenericResponse::setParseMode' => ['bool', 'parser_mode='=>'int'], 'SolrGenericResponse::success' => ['bool'], 'SolrIllegalArgumentException::__clone' => ['void'], 'SolrIllegalArgumentException::__construct' => ['void', 'message='=>'string', 'code='=>'int', 'previous='=>'?Exception|?Throwable'], 'SolrIllegalArgumentException::__toString' => ['string'], 'SolrIllegalArgumentException::__wakeup' => ['void'], 'SolrIllegalArgumentException::getCode' => ['int'], 'SolrIllegalArgumentException::getFile' => ['string'], 'SolrIllegalArgumentException::getInternalInfo' => ['array'], 'SolrIllegalArgumentException::getLine' => ['int'], 'SolrIllegalArgumentException::getMessage' => ['string'], 'SolrIllegalArgumentException::getPrevious' => ['Exception|Throwable'], 'SolrIllegalArgumentException::getTrace' => ['list\',args?:array}>'], 'SolrIllegalArgumentException::getTraceAsString' => ['string'], 'SolrIllegalOperationException::__clone' => ['void'], 'SolrIllegalOperationException::__construct' => ['void', 'message='=>'string', 'code='=>'int', 'previous='=>'?Exception|?Throwable'], 'SolrIllegalOperationException::__toString' => ['string'], 'SolrIllegalOperationException::__wakeup' => ['void'], 'SolrIllegalOperationException::getCode' => ['int'], 'SolrIllegalOperationException::getFile' => ['string'], 'SolrIllegalOperationException::getInternalInfo' => ['array'], 'SolrIllegalOperationException::getLine' => ['int'], 'SolrIllegalOperationException::getMessage' => ['string'], 'SolrIllegalOperationException::getPrevious' => ['Exception|Throwable'], 'SolrIllegalOperationException::getTrace' => ['list\',args?:array}>'], 'SolrIllegalOperationException::getTraceAsString' => ['string'], 'SolrInputDocument::__clone' => ['void'], 'SolrInputDocument::__construct' => ['void'], 'SolrInputDocument::__destruct' => ['void'], 'SolrInputDocument::addChildDocument' => ['void', 'child'=>'SolrInputDocument'], 'SolrInputDocument::addChildDocuments' => ['void', 'docs'=>'array'], 'SolrInputDocument::addField' => ['bool', 'fieldname'=>'string', 'fieldvalue'=>'string', 'fieldboostvalue='=>'float'], 'SolrInputDocument::clear' => ['bool'], 'SolrInputDocument::deleteField' => ['bool', 'fieldname'=>'string'], 'SolrInputDocument::fieldExists' => ['bool', 'fieldname'=>'string'], 'SolrInputDocument::getBoost' => ['float|false'], 'SolrInputDocument::getChildDocuments' => ['SolrInputDocument[]'], 'SolrInputDocument::getChildDocumentsCount' => ['int'], 'SolrInputDocument::getField' => ['SolrDocumentField|false', 'fieldname'=>'string'], 'SolrInputDocument::getFieldBoost' => ['float|false', 'fieldname'=>'string'], 'SolrInputDocument::getFieldCount' => ['int|false'], 'SolrInputDocument::getFieldNames' => ['array|false'], 'SolrInputDocument::hasChildDocuments' => ['bool'], 'SolrInputDocument::merge' => ['bool', 'sourcedoc'=>'SolrInputDocument', 'overwrite='=>'bool'], 'SolrInputDocument::reset' => ['bool'], 'SolrInputDocument::setBoost' => ['bool', 'documentboostvalue'=>'float'], 'SolrInputDocument::setFieldBoost' => ['bool', 'fieldname'=>'string', 'fieldboostvalue'=>'float'], 'SolrInputDocument::sort' => ['bool', 'sortorderby'=>'int', 'sortdirection='=>'int'], 'SolrInputDocument::toArray' => ['array|false'], 'SolrModifiableParams::__construct' => ['void'], 'SolrModifiableParams::__destruct' => ['void'], 'SolrModifiableParams::add' => ['SolrParams', 'name'=>'string', 'value'=>'string'], 'SolrModifiableParams::addParam' => ['SolrParams', 'name'=>'string', 'value'=>'string'], 'SolrModifiableParams::get' => ['mixed', 'param_name'=>'string'], 'SolrModifiableParams::getParam' => ['mixed', 'param_name'=>'string'], 'SolrModifiableParams::getParams' => ['array'], 'SolrModifiableParams::getPreparedParams' => ['array'], 'SolrModifiableParams::serialize' => ['string'], 'SolrModifiableParams::set' => ['SolrParams', 'name'=>'string', 'value'=>''], 'SolrModifiableParams::setParam' => ['SolrParams', 'name'=>'string', 'value'=>''], 'SolrModifiableParams::toString' => ['string', 'url_encode='=>'bool'], 'SolrModifiableParams::unserialize' => ['void', 'serialized'=>'string'], 'SolrObject::__construct' => ['void'], 'SolrObject::__destruct' => ['void'], 'SolrObject::getPropertyNames' => ['array'], 'SolrObject::offsetExists' => ['bool', 'property_name'=>'string'], 'SolrObject::offsetGet' => ['SolrDocumentField', 'property_name'=>'string'], 'SolrObject::offsetSet' => ['void', 'property_name'=>'string', 'property_value'=>'string'], 'SolrObject::offsetUnset' => ['void', 'property_name'=>'string'], 'SolrParams::__construct' => ['void'], 'SolrParams::add' => ['SolrParams|false', 'name'=>'string', 'value'=>'string'], 'SolrParams::addParam' => ['SolrParams|false', 'name'=>'string', 'value'=>'string'], 'SolrParams::get' => ['mixed', 'param_name'=>'string'], 'SolrParams::getParam' => ['mixed', 'param_name='=>'string'], 'SolrParams::getParams' => ['array'], 'SolrParams::getPreparedParams' => ['array'], 'SolrParams::serialize' => ['string'], 'SolrParams::set' => ['SolrParams|false', 'name'=>'string', 'value'=>'string'], 'SolrParams::setParam' => ['SolrParams|false', 'name'=>'string', 'value'=>'string'], 'SolrParams::toString' => ['string|false', 'url_encode='=>'bool'], 'SolrParams::unserialize' => ['void', 'serialized'=>'string'], 'SolrPingResponse::__construct' => ['void'], 'SolrPingResponse::__destruct' => ['void'], 'SolrPingResponse::getDigestedResponse' => ['string'], 'SolrPingResponse::getHttpStatus' => ['int'], 'SolrPingResponse::getHttpStatusMessage' => ['string'], 'SolrPingResponse::getRawRequest' => ['string'], 'SolrPingResponse::getRawRequestHeaders' => ['string'], 'SolrPingResponse::getRawResponse' => ['string'], 'SolrPingResponse::getRawResponseHeaders' => ['string'], 'SolrPingResponse::getRequestUrl' => ['string'], 'SolrPingResponse::getResponse' => ['string'], 'SolrPingResponse::setParseMode' => ['bool', 'parser_mode='=>'int'], 'SolrPingResponse::success' => ['bool'], 'SolrQuery::__construct' => ['void', 'q='=>'string'], 'SolrQuery::__destruct' => ['void'], 'SolrQuery::add' => ['SolrParams', 'name'=>'string', 'value'=>'string'], 'SolrQuery::addExpandFilterQuery' => ['SolrQuery', 'fq'=>'string'], 'SolrQuery::addExpandSortField' => ['SolrQuery', 'field'=>'string', 'order='=>'string'], 'SolrQuery::addFacetDateField' => ['SolrQuery', 'datefield'=>'string'], 'SolrQuery::addFacetDateOther' => ['SolrQuery', 'value'=>'string', 'field_override='=>'string'], 'SolrQuery::addFacetField' => ['SolrQuery', 'field'=>'string'], 'SolrQuery::addFacetQuery' => ['SolrQuery', 'facetquery'=>'string'], 'SolrQuery::addField' => ['SolrQuery', 'field'=>'string'], 'SolrQuery::addFilterQuery' => ['SolrQuery', 'fq'=>'string'], 'SolrQuery::addGroupField' => ['SolrQuery', 'value'=>'string'], 'SolrQuery::addGroupFunction' => ['SolrQuery', 'value'=>'string'], 'SolrQuery::addGroupQuery' => ['SolrQuery', 'value'=>'string'], 'SolrQuery::addGroupSortField' => ['SolrQuery', 'field'=>'string', 'order='=>'int'], 'SolrQuery::addHighlightField' => ['SolrQuery', 'field'=>'string'], 'SolrQuery::addMltField' => ['SolrQuery', 'field'=>'string'], 'SolrQuery::addMltQueryField' => ['SolrQuery', 'field'=>'string', 'boost'=>'float'], 'SolrQuery::addParam' => ['SolrParams', 'name'=>'string', 'value'=>'string'], 'SolrQuery::addSortField' => ['SolrQuery', 'field'=>'string', 'order='=>'int'], 'SolrQuery::addStatsFacet' => ['SolrQuery', 'field'=>'string'], 'SolrQuery::addStatsField' => ['SolrQuery', 'field'=>'string'], 'SolrQuery::collapse' => ['SolrQuery', 'collapseFunction'=>'SolrCollapseFunction'], 'SolrQuery::get' => ['mixed', 'param_name'=>'string'], 'SolrQuery::getExpand' => ['bool'], 'SolrQuery::getExpandFilterQueries' => ['array'], 'SolrQuery::getExpandQuery' => ['array'], 'SolrQuery::getExpandRows' => ['int'], 'SolrQuery::getExpandSortFields' => ['array'], 'SolrQuery::getFacet' => ['?bool'], 'SolrQuery::getFacetDateEnd' => ['?string', 'field_override='=>'string'], 'SolrQuery::getFacetDateFields' => ['array'], 'SolrQuery::getFacetDateGap' => ['?string', 'field_override='=>'string'], 'SolrQuery::getFacetDateHardEnd' => ['?string', 'field_override='=>'string'], 'SolrQuery::getFacetDateOther' => ['?string', 'field_override='=>'string'], 'SolrQuery::getFacetDateStart' => ['?string', 'field_override='=>'string'], 'SolrQuery::getFacetFields' => ['array'], 'SolrQuery::getFacetLimit' => ['?int', 'field_override='=>'string'], 'SolrQuery::getFacetMethod' => ['?string', 'field_override='=>'string'], 'SolrQuery::getFacetMinCount' => ['?int', 'field_override='=>'string'], 'SolrQuery::getFacetMissing' => ['?bool', 'field_override='=>'string'], 'SolrQuery::getFacetOffset' => ['?int', 'field_override='=>'string'], 'SolrQuery::getFacetPrefix' => ['?string', 'field_override='=>'string'], 'SolrQuery::getFacetQueries' => ['?array'], 'SolrQuery::getFacetSort' => ['int', 'field_override='=>'string'], 'SolrQuery::getFields' => ['?array'], 'SolrQuery::getFilterQueries' => ['?array'], 'SolrQuery::getGroup' => ['bool'], 'SolrQuery::getGroupCachePercent' => ['int'], 'SolrQuery::getGroupFacet' => ['bool'], 'SolrQuery::getGroupFields' => ['array'], 'SolrQuery::getGroupFormat' => ['string'], 'SolrQuery::getGroupFunctions' => ['array'], 'SolrQuery::getGroupLimit' => ['int'], 'SolrQuery::getGroupMain' => ['bool'], 'SolrQuery::getGroupNGroups' => ['bool'], 'SolrQuery::getGroupOffset' => ['int'], 'SolrQuery::getGroupQueries' => ['array'], 'SolrQuery::getGroupSortFields' => ['array'], 'SolrQuery::getGroupTruncate' => ['bool'], 'SolrQuery::getHighlight' => ['bool'], 'SolrQuery::getHighlightAlternateField' => ['?string', 'field_override='=>'string'], 'SolrQuery::getHighlightFields' => ['?array'], 'SolrQuery::getHighlightFormatter' => ['?string', 'field_override='=>'string'], 'SolrQuery::getHighlightFragmenter' => ['?string', 'field_override='=>'string'], 'SolrQuery::getHighlightFragsize' => ['?int', 'field_override='=>'string'], 'SolrQuery::getHighlightHighlightMultiTerm' => ['?bool'], 'SolrQuery::getHighlightMaxAlternateFieldLength' => ['?int', 'field_override='=>'string'], 'SolrQuery::getHighlightMaxAnalyzedChars' => ['?int'], 'SolrQuery::getHighlightMergeContiguous' => ['?bool', 'field_override='=>'string'], 'SolrQuery::getHighlightRegexMaxAnalyzedChars' => ['?int'], 'SolrQuery::getHighlightRegexPattern' => ['?string'], 'SolrQuery::getHighlightRegexSlop' => ['?float'], 'SolrQuery::getHighlightRequireFieldMatch' => ['?bool'], 'SolrQuery::getHighlightSimplePost' => ['?string', 'field_override='=>'string'], 'SolrQuery::getHighlightSimplePre' => ['?string', 'field_override='=>'string'], 'SolrQuery::getHighlightSnippets' => ['?int', 'field_override='=>'string'], 'SolrQuery::getHighlightUsePhraseHighlighter' => ['?bool'], 'SolrQuery::getMlt' => ['?bool'], 'SolrQuery::getMltBoost' => ['?bool'], 'SolrQuery::getMltCount' => ['?int'], 'SolrQuery::getMltFields' => ['?array'], 'SolrQuery::getMltMaxNumQueryTerms' => ['?int'], 'SolrQuery::getMltMaxNumTokens' => ['?int'], 'SolrQuery::getMltMaxWordLength' => ['?int'], 'SolrQuery::getMltMinDocFrequency' => ['?int'], 'SolrQuery::getMltMinTermFrequency' => ['?int'], 'SolrQuery::getMltMinWordLength' => ['?int'], 'SolrQuery::getMltQueryFields' => ['?array'], 'SolrQuery::getParam' => ['?mixed', 'param_name'=>'string'], 'SolrQuery::getParams' => ['?array'], 'SolrQuery::getPreparedParams' => ['?array'], 'SolrQuery::getQuery' => ['?string'], 'SolrQuery::getRows' => ['?int'], 'SolrQuery::getSortFields' => ['?array'], 'SolrQuery::getStart' => ['?int'], 'SolrQuery::getStats' => ['?bool'], 'SolrQuery::getStatsFacets' => ['?array'], 'SolrQuery::getStatsFields' => ['?array'], 'SolrQuery::getTerms' => ['?bool'], 'SolrQuery::getTermsField' => ['?string'], 'SolrQuery::getTermsIncludeLowerBound' => ['?bool'], 'SolrQuery::getTermsIncludeUpperBound' => ['?bool'], 'SolrQuery::getTermsLimit' => ['?int'], 'SolrQuery::getTermsLowerBound' => ['?string'], 'SolrQuery::getTermsMaxCount' => ['?int'], 'SolrQuery::getTermsMinCount' => ['?int'], 'SolrQuery::getTermsPrefix' => ['?string'], 'SolrQuery::getTermsReturnRaw' => ['?bool'], 'SolrQuery::getTermsSort' => ['?int'], 'SolrQuery::getTermsUpperBound' => ['?string'], 'SolrQuery::getTimeAllowed' => ['?int'], 'SolrQuery::removeExpandFilterQuery' => ['SolrQuery', 'fq'=>'string'], 'SolrQuery::removeExpandSortField' => ['SolrQuery', 'field'=>'string'], 'SolrQuery::removeFacetDateField' => ['SolrQuery', 'field'=>'string'], 'SolrQuery::removeFacetDateOther' => ['SolrQuery', 'value'=>'string', 'field_override='=>'string'], 'SolrQuery::removeFacetField' => ['SolrQuery', 'field'=>'string'], 'SolrQuery::removeFacetQuery' => ['SolrQuery', 'value'=>'string'], 'SolrQuery::removeField' => ['SolrQuery', 'field'=>'string'], 'SolrQuery::removeFilterQuery' => ['SolrQuery', 'fq'=>'string'], 'SolrQuery::removeHighlightField' => ['SolrQuery', 'field'=>'string'], 'SolrQuery::removeMltField' => ['SolrQuery', 'field'=>'string'], 'SolrQuery::removeMltQueryField' => ['SolrQuery', 'queryfield'=>'string'], 'SolrQuery::removeSortField' => ['SolrQuery', 'field'=>'string'], 'SolrQuery::removeStatsFacet' => ['SolrQuery', 'value'=>'string'], 'SolrQuery::removeStatsField' => ['SolrQuery', 'field'=>'string'], 'SolrQuery::serialize' => ['string'], 'SolrQuery::set' => ['SolrParams', 'name'=>'string', 'value'=>''], 'SolrQuery::setEchoHandler' => ['SolrQuery', 'flag'=>'bool'], 'SolrQuery::setEchoParams' => ['SolrQuery', 'type'=>'string'], 'SolrQuery::setExpand' => ['SolrQuery', 'value'=>'bool'], 'SolrQuery::setExpandQuery' => ['SolrQuery', 'q'=>'string'], 'SolrQuery::setExpandRows' => ['SolrQuery', 'value'=>'int'], 'SolrQuery::setExplainOther' => ['SolrQuery', 'query'=>'string'], 'SolrQuery::setFacet' => ['SolrQuery', 'flag'=>'bool'], 'SolrQuery::setFacetDateEnd' => ['SolrQuery', 'value'=>'string', 'field_override='=>'string'], 'SolrQuery::setFacetDateGap' => ['SolrQuery', 'value'=>'string', 'field_override='=>'string'], 'SolrQuery::setFacetDateHardEnd' => ['SolrQuery', 'value'=>'bool', 'field_override='=>'string'], 'SolrQuery::setFacetDateStart' => ['SolrQuery', 'value'=>'string', 'field_override='=>'string'], 'SolrQuery::setFacetEnumCacheMinDefaultFrequency' => ['SolrQuery', 'frequency'=>'int', 'field_override='=>'string'], 'SolrQuery::setFacetLimit' => ['SolrQuery', 'limit'=>'int', 'field_override='=>'string'], 'SolrQuery::setFacetMethod' => ['SolrQuery', 'method'=>'string', 'field_override='=>'string'], 'SolrQuery::setFacetMinCount' => ['SolrQuery', 'mincount'=>'int', 'field_override='=>'string'], 'SolrQuery::setFacetMissing' => ['SolrQuery', 'flag'=>'bool', 'field_override='=>'string'], 'SolrQuery::setFacetOffset' => ['SolrQuery', 'offset'=>'int', 'field_override='=>'string'], 'SolrQuery::setFacetPrefix' => ['SolrQuery', 'prefix'=>'string', 'field_override='=>'string'], 'SolrQuery::setFacetSort' => ['SolrQuery', 'facetsort'=>'int', 'field_override='=>'string'], 'SolrQuery::setGroup' => ['SolrQuery', 'value'=>'bool'], 'SolrQuery::setGroupCachePercent' => ['SolrQuery', 'percent'=>'int'], 'SolrQuery::setGroupFacet' => ['SolrQuery', 'value'=>'bool'], 'SolrQuery::setGroupFormat' => ['SolrQuery', 'value'=>'string'], 'SolrQuery::setGroupLimit' => ['SolrQuery', 'value'=>'int'], 'SolrQuery::setGroupMain' => ['SolrQuery', 'value'=>'string'], 'SolrQuery::setGroupNGroups' => ['SolrQuery', 'value'=>'bool'], 'SolrQuery::setGroupOffset' => ['SolrQuery', 'value'=>'int'], 'SolrQuery::setGroupTruncate' => ['SolrQuery', 'value'=>'bool'], 'SolrQuery::setHighlight' => ['SolrQuery', 'flag'=>'bool'], 'SolrQuery::setHighlightAlternateField' => ['SolrQuery', 'field'=>'string', 'field_override='=>'string'], 'SolrQuery::setHighlightFormatter' => ['SolrQuery', 'formatter'=>'string', 'field_override='=>'string'], 'SolrQuery::setHighlightFragmenter' => ['SolrQuery', 'fragmenter'=>'string', 'field_override='=>'string'], 'SolrQuery::setHighlightFragsize' => ['SolrQuery', 'size'=>'int', 'field_override='=>'string'], 'SolrQuery::setHighlightHighlightMultiTerm' => ['SolrQuery', 'flag'=>'bool'], 'SolrQuery::setHighlightMaxAlternateFieldLength' => ['SolrQuery', 'fieldlength'=>'int', 'field_override='=>'string'], 'SolrQuery::setHighlightMaxAnalyzedChars' => ['SolrQuery', 'value'=>'int'], 'SolrQuery::setHighlightMergeContiguous' => ['SolrQuery', 'flag'=>'bool', 'field_override='=>'string'], 'SolrQuery::setHighlightRegexMaxAnalyzedChars' => ['SolrQuery', 'maxanalyzedchars'=>'int'], 'SolrQuery::setHighlightRegexPattern' => ['SolrQuery', 'value'=>'string'], 'SolrQuery::setHighlightRegexSlop' => ['SolrQuery', 'factor'=>'float'], 'SolrQuery::setHighlightRequireFieldMatch' => ['SolrQuery', 'flag'=>'bool'], 'SolrQuery::setHighlightSimplePost' => ['SolrQuery', 'simplepost'=>'string', 'field_override='=>'string'], 'SolrQuery::setHighlightSimplePre' => ['SolrQuery', 'simplepre'=>'string', 'field_override='=>'string'], 'SolrQuery::setHighlightSnippets' => ['SolrQuery', 'value'=>'int', 'field_override='=>'string'], 'SolrQuery::setHighlightUsePhraseHighlighter' => ['SolrQuery', 'flag'=>'bool'], 'SolrQuery::setMlt' => ['SolrQuery', 'flag'=>'bool'], 'SolrQuery::setMltBoost' => ['SolrQuery', 'flag'=>'bool'], 'SolrQuery::setMltCount' => ['SolrQuery', 'count'=>'int'], 'SolrQuery::setMltMaxNumQueryTerms' => ['SolrQuery', 'value'=>'int'], 'SolrQuery::setMltMaxNumTokens' => ['SolrQuery', 'value'=>'int'], 'SolrQuery::setMltMaxWordLength' => ['SolrQuery', 'maxwordlength'=>'int'], 'SolrQuery::setMltMinDocFrequency' => ['SolrQuery', 'mindocfrequency'=>'int'], 'SolrQuery::setMltMinTermFrequency' => ['SolrQuery', 'mintermfrequency'=>'int'], 'SolrQuery::setMltMinWordLength' => ['SolrQuery', 'minwordlength'=>'int'], 'SolrQuery::setOmitHeader' => ['SolrQuery', 'flag'=>'bool'], 'SolrQuery::setParam' => ['SolrParams', 'name'=>'string', 'value'=>''], 'SolrQuery::setQuery' => ['SolrQuery', 'query'=>'string'], 'SolrQuery::setRows' => ['SolrQuery', 'rows'=>'int'], 'SolrQuery::setShowDebugInfo' => ['SolrQuery', 'flag'=>'bool'], 'SolrQuery::setStart' => ['SolrQuery', 'start'=>'int'], 'SolrQuery::setStats' => ['SolrQuery', 'flag'=>'bool'], 'SolrQuery::setTerms' => ['SolrQuery', 'flag'=>'bool'], 'SolrQuery::setTermsField' => ['SolrQuery', 'fieldname'=>'string'], 'SolrQuery::setTermsIncludeLowerBound' => ['SolrQuery', 'flag'=>'bool'], 'SolrQuery::setTermsIncludeUpperBound' => ['SolrQuery', 'flag'=>'bool'], 'SolrQuery::setTermsLimit' => ['SolrQuery', 'limit'=>'int'], 'SolrQuery::setTermsLowerBound' => ['SolrQuery', 'lowerbound'=>'string'], 'SolrQuery::setTermsMaxCount' => ['SolrQuery', 'frequency'=>'int'], 'SolrQuery::setTermsMinCount' => ['SolrQuery', 'frequency'=>'int'], 'SolrQuery::setTermsPrefix' => ['SolrQuery', 'prefix'=>'string'], 'SolrQuery::setTermsReturnRaw' => ['SolrQuery', 'flag'=>'bool'], 'SolrQuery::setTermsSort' => ['SolrQuery', 'sorttype'=>'int'], 'SolrQuery::setTermsUpperBound' => ['SolrQuery', 'upperbound'=>'string'], 'SolrQuery::setTimeAllowed' => ['SolrQuery', 'timeallowed'=>'int'], 'SolrQuery::toString' => ['string', 'url_encode='=>'bool'], 'SolrQuery::unserialize' => ['void', 'serialized'=>'string'], 'SolrQueryResponse::__construct' => ['void'], 'SolrQueryResponse::__destruct' => ['void'], 'SolrQueryResponse::getDigestedResponse' => ['string'], 'SolrQueryResponse::getHttpStatus' => ['int'], 'SolrQueryResponse::getHttpStatusMessage' => ['string'], 'SolrQueryResponse::getRawRequest' => ['string'], 'SolrQueryResponse::getRawRequestHeaders' => ['string'], 'SolrQueryResponse::getRawResponse' => ['string'], 'SolrQueryResponse::getRawResponseHeaders' => ['string'], 'SolrQueryResponse::getRequestUrl' => ['string'], 'SolrQueryResponse::getResponse' => ['SolrObject'], 'SolrQueryResponse::setParseMode' => ['bool', 'parser_mode='=>'int'], 'SolrQueryResponse::success' => ['bool'], 'SolrResponse::getDigestedResponse' => ['string'], 'SolrResponse::getHttpStatus' => ['int'], 'SolrResponse::getHttpStatusMessage' => ['string'], 'SolrResponse::getRawRequest' => ['string'], 'SolrResponse::getRawRequestHeaders' => ['string'], 'SolrResponse::getRawResponse' => ['string'], 'SolrResponse::getRawResponseHeaders' => ['string'], 'SolrResponse::getRequestUrl' => ['string'], 'SolrResponse::getResponse' => ['SolrObject'], 'SolrResponse::setParseMode' => ['bool', 'parser_mode='=>'int'], 'SolrResponse::success' => ['bool'], 'SolrServerException::__clone' => ['void'], 'SolrServerException::__construct' => ['void', 'message='=>'string', 'code='=>'int', 'previous='=>'?Exception|?Throwable'], 'SolrServerException::__toString' => ['string'], 'SolrServerException::__wakeup' => ['void'], 'SolrServerException::getCode' => ['int'], 'SolrServerException::getFile' => ['string'], 'SolrServerException::getInternalInfo' => ['array'], 'SolrServerException::getLine' => ['int'], 'SolrServerException::getMessage' => ['string'], 'SolrServerException::getPrevious' => ['Exception|Throwable'], 'SolrServerException::getTrace' => ['list\',args?:array}>'], 'SolrServerException::getTraceAsString' => ['string'], 'SolrUpdateResponse::__construct' => ['void'], 'SolrUpdateResponse::__destruct' => ['void'], 'SolrUpdateResponse::getDigestedResponse' => ['string'], 'SolrUpdateResponse::getHttpStatus' => ['int'], 'SolrUpdateResponse::getHttpStatusMessage' => ['string'], 'SolrUpdateResponse::getRawRequest' => ['string'], 'SolrUpdateResponse::getRawRequestHeaders' => ['string'], 'SolrUpdateResponse::getRawResponse' => ['string'], 'SolrUpdateResponse::getRawResponseHeaders' => ['string'], 'SolrUpdateResponse::getRequestUrl' => ['string'], 'SolrUpdateResponse::getResponse' => ['SolrObject'], 'SolrUpdateResponse::setParseMode' => ['bool', 'parser_mode='=>'int'], 'SolrUpdateResponse::success' => ['bool'], 'SolrUtils::digestXmlResponse' => ['SolrObject', 'xmlresponse'=>'string', 'parse_mode='=>'int'], 'SolrUtils::escapeQueryChars' => ['string|false', 'string'=>'string'], 'SolrUtils::getSolrVersion' => ['string'], 'SolrUtils::queryPhrase' => ['string', 'string'=>'string'], 'SphinxClient::__construct' => ['void'], 'SphinxClient::addQuery' => ['int', 'query'=>'string', 'index='=>'string', 'comment='=>'string'], 'SphinxClient::buildExcerpts' => ['array', 'docs'=>'array', 'index'=>'string', 'words'=>'string', 'opts='=>'array'], 'SphinxClient::buildKeywords' => ['array', 'query'=>'string', 'index'=>'string', 'hits'=>'bool'], 'SphinxClient::close' => ['bool'], 'SphinxClient::escapeString' => ['string', 'string'=>'string'], 'SphinxClient::getLastError' => ['string'], 'SphinxClient::getLastWarning' => ['string'], 'SphinxClient::open' => ['bool'], 'SphinxClient::query' => ['array', 'query'=>'string', 'index='=>'string', 'comment='=>'string'], 'SphinxClient::resetFilters' => ['void'], 'SphinxClient::resetGroupBy' => ['void'], 'SphinxClient::runQueries' => ['array'], 'SphinxClient::setArrayResult' => ['bool', 'array_result'=>'bool'], 'SphinxClient::setConnectTimeout' => ['bool', 'timeout'=>'float'], 'SphinxClient::setFieldWeights' => ['bool', 'weights'=>'array'], 'SphinxClient::setFilter' => ['bool', 'attribute'=>'string', 'values'=>'array', 'exclude='=>'bool'], 'SphinxClient::setFilterFloatRange' => ['bool', 'attribute'=>'string', 'min'=>'float', 'max'=>'float', 'exclude='=>'bool'], 'SphinxClient::setFilterRange' => ['bool', 'attribute'=>'string', 'min'=>'int', 'max'=>'int', 'exclude='=>'bool'], 'SphinxClient::setGeoAnchor' => ['bool', 'attrlat'=>'string', 'attrlong'=>'string', 'latitude'=>'float', 'longitude'=>'float'], 'SphinxClient::setGroupBy' => ['bool', 'attribute'=>'string', 'func'=>'int', 'groupsort='=>'string'], 'SphinxClient::setGroupDistinct' => ['bool', 'attribute'=>'string'], 'SphinxClient::setIDRange' => ['bool', 'min'=>'int', 'max'=>'int'], 'SphinxClient::setIndexWeights' => ['bool', 'weights'=>'array'], 'SphinxClient::setLimits' => ['bool', 'offset'=>'int', 'limit'=>'int', 'max_matches='=>'int', 'cutoff='=>'int'], 'SphinxClient::setMatchMode' => ['bool', 'mode'=>'int'], 'SphinxClient::setMaxQueryTime' => ['bool', 'qtime'=>'int'], 'SphinxClient::setOverride' => ['bool', 'attribute'=>'string', 'type'=>'int', 'values'=>'array'], 'SphinxClient::setRankingMode' => ['bool', 'ranker'=>'int'], 'SphinxClient::setRetries' => ['bool', 'count'=>'int', 'delay='=>'int'], 'SphinxClient::setSelect' => ['bool', 'clause'=>'string'], 'SphinxClient::setServer' => ['bool', 'server'=>'string', 'port'=>'int'], 'SphinxClient::setSortMode' => ['bool', 'mode'=>'int', 'sortby='=>'string'], 'SphinxClient::status' => ['array'], 'SphinxClient::updateAttributes' => ['int', 'index'=>'string', 'attributes'=>'array', 'values'=>'array', 'mva='=>'bool'], 'SplDoublyLinkedList::__construct' => ['void'], 'SplDoublyLinkedList::add' => ['void', 'index'=>'int', 'value'=>'mixed'], 'SplDoublyLinkedList::bottom' => ['mixed'], 'SplDoublyLinkedList::count' => ['int'], 'SplDoublyLinkedList::current' => ['mixed'], 'SplDoublyLinkedList::getIteratorMode' => ['int'], 'SplDoublyLinkedList::isEmpty' => ['bool'], 'SplDoublyLinkedList::key' => ['int'], 'SplDoublyLinkedList::next' => ['void'], 'SplDoublyLinkedList::offsetExists' => ['bool', 'index'=>'int'], 'SplDoublyLinkedList::offsetGet' => ['mixed', 'index'=>'int'], 'SplDoublyLinkedList::offsetSet' => ['void', 'index'=>'?int', 'value'=>'mixed'], 'SplDoublyLinkedList::offsetUnset' => ['void', 'index'=>'int'], 'SplDoublyLinkedList::pop' => ['mixed'], 'SplDoublyLinkedList::prev' => ['void'], 'SplDoublyLinkedList::push' => ['void', 'value'=>'mixed'], 'SplDoublyLinkedList::rewind' => ['void'], 'SplDoublyLinkedList::serialize' => ['string'], 'SplDoublyLinkedList::setIteratorMode' => ['int', 'mode'=>'int'], 'SplDoublyLinkedList::shift' => ['mixed'], 'SplDoublyLinkedList::top' => ['mixed'], 'SplDoublyLinkedList::unserialize' => ['void', 'data'=>'string'], 'SplDoublyLinkedList::unshift' => ['void', 'value'=>'mixed'], 'SplDoublyLinkedList::valid' => ['bool'], 'SplEnum::__construct' => ['void', 'initial_value='=>'mixed', 'strict='=>'bool'], 'SplEnum::getConstList' => ['array', 'include_default='=>'bool'], 'SplFileInfo::__construct' => ['void', 'filename'=>'string'], 'SplFileInfo::__toString' => ['string'], 'SplFileInfo::getATime' => ['int|false'], 'SplFileInfo::getBasename' => ['string', 'suffix='=>'string'], 'SplFileInfo::getCTime' => ['int|false'], 'SplFileInfo::getExtension' => ['string'], 'SplFileInfo::getFileInfo' => ['SplFileInfo', 'class='=>'class-string'], 'SplFileInfo::getFilename' => ['string'], 'SplFileInfo::getGroup' => ['int|false'], 'SplFileInfo::getInode' => ['int|false'], 'SplFileInfo::getLinkTarget' => ['string|false'], 'SplFileInfo::getMTime' => ['int|false'], 'SplFileInfo::getOwner' => ['int|false'], 'SplFileInfo::getPath' => ['string'], 'SplFileInfo::getPathInfo' => ['SplFileInfo|null', 'class='=>'class-string'], 'SplFileInfo::getPathname' => ['string'], 'SplFileInfo::getPerms' => ['int|false'], 'SplFileInfo::getRealPath' => ['non-falsy-string|false'], 'SplFileInfo::getSize' => ['int|false'], 'SplFileInfo::getType' => ['string|false'], 'SplFileInfo::isDir' => ['bool'], 'SplFileInfo::isExecutable' => ['bool'], 'SplFileInfo::isFile' => ['bool'], 'SplFileInfo::isLink' => ['bool'], 'SplFileInfo::isReadable' => ['bool'], 'SplFileInfo::isWritable' => ['bool'], 'SplFileInfo::openFile' => ['SplFileObject', 'mode='=>'string', 'useIncludePath='=>'bool', 'context='=>'resource'], 'SplFileInfo::setFileClass' => ['void', 'class='=>'class-string'], 'SplFileInfo::setInfoClass' => ['void', 'class='=>'class-string'], 'SplFileObject::__construct' => ['void', 'filename'=>'string', 'mode='=>'string', 'useIncludePath='=>'bool', 'context='=>'?resource'], 'SplFileObject::__toString' => ['string'], 'SplFileObject::current' => ['string|array|false'], 'SplFileObject::eof' => ['bool'], 'SplFileObject::fflush' => ['bool'], 'SplFileObject::fgetc' => ['string|false'], 'SplFileObject::fgetcsv' => ['list|array{0: null}|false', 'separator='=>'string', 'enclosure='=>'string', 'escape='=>'string'], 'SplFileObject::fgets' => ['string|false'], 'SplFileObject::fgetss' => ['string|false', 'allowable_tags='=>'string'], 'SplFileObject::flock' => ['bool', 'operation'=>'int', '&w_wouldBlock='=>'int'], 'SplFileObject::fpassthru' => ['int'], 'SplFileObject::fputcsv' => ['int|false', 'fields'=>'array', 'separator='=>'string', 'enclosure='=>'string', 'escape='=>'string'], 'SplFileObject::fread' => ['string|false', 'length'=>'int'], 'SplFileObject::fscanf' => ['array|int', 'format'=>'string', '&...w_vars='=>'string|int|float'], 'SplFileObject::fseek' => ['int', 'offset'=>'int', 'whence='=>'int'], 'SplFileObject::fstat' => ['array{0: int, 1: int, 2: int, 3: int, 4: int, 5: int, 6: int, 7: int, 8: int, 9: int, 10: int, 11: int, 12: int, dev: int, ino: int, mode: int, nlink: int, uid: int, gid: int, rdev: int, size: int, atime: int, mtime: int, ctime: int, blksize: int, blocks: int}'], 'SplFileObject::ftell' => ['int|false'], 'SplFileObject::ftruncate' => ['bool', 'size'=>'int'], 'SplFileObject::fwrite' => ['int', 'data'=>'string', 'length='=>'int'], 'SplFileObject::getATime' => ['int|false'], 'SplFileObject::getBasename' => ['string', 'suffix='=>'string'], 'SplFileObject::getCTime' => ['int|false'], 'SplFileObject::getChildren' => ['null'], 'SplFileObject::getCsvControl' => ['array'], 'SplFileObject::getCurrentLine' => ['string|false'], 'SplFileObject::getExtension' => ['string'], 'SplFileObject::getFileInfo' => ['SplFileInfo', 'class='=>'class-string'], 'SplFileObject::getFilename' => ['string'], 'SplFileObject::getFlags' => ['int'], 'SplFileObject::getGroup' => ['int|false'], 'SplFileObject::getInode' => ['int|false'], 'SplFileObject::getLinkTarget' => ['string|false'], 'SplFileObject::getMaxLineLen' => ['int'], 'SplFileObject::getMTime' => ['int|false'], 'SplFileObject::getOwner' => ['int|false'], 'SplFileObject::getPath' => ['string'], 'SplFileObject::getPathInfo' => ['SplFileInfo|null', 'class='=>'class-string'], 'SplFileObject::getPathname' => ['string'], 'SplFileObject::getPerms' => ['int|false'], 'SplFileObject::getRealPath' => ['false|non-falsy-string'], 'SplFileObject::getSize' => ['int|false'], 'SplFileObject::getType' => ['string|false'], 'SplFileObject::hasChildren' => ['false'], 'SplFileObject::isDir' => ['bool'], 'SplFileObject::isExecutable' => ['bool'], 'SplFileObject::isFile' => ['bool'], 'SplFileObject::isLink' => ['bool'], 'SplFileObject::isReadable' => ['bool'], 'SplFileObject::isWritable' => ['bool'], 'SplFileObject::key' => ['int'], 'SplFileObject::next' => ['void'], 'SplFileObject::openFile' => ['SplFileObject', 'mode='=>'string', 'useIncludePath='=>'bool', 'context='=>'resource'], 'SplFileObject::rewind' => ['void'], 'SplFileObject::seek' => ['void', 'line'=>'int'], 'SplFileObject::setCsvControl' => ['void', 'separator='=>'string', 'enclosure='=>'string', 'escape='=>'string'], 'SplFileObject::setFileClass' => ['void', 'class='=>'class-string'], 'SplFileObject::setFlags' => ['void', 'flags'=>'int'], 'SplFileObject::setInfoClass' => ['void', 'class='=>'class-string'], 'SplFileObject::setMaxLineLen' => ['void', 'maxLength'=>'int'], 'SplFileObject::valid' => ['bool'], 'SplFixedArray::__construct' => ['void', 'size='=>'int'], 'SplFixedArray::__wakeup' => ['void'], 'SplFixedArray::count' => ['int'], 'SplFixedArray::current' => ['mixed'], 'SplFixedArray::fromArray' => ['SplFixedArray', 'array'=>'array', 'preserveKeys='=>'bool'], 'SplFixedArray::getSize' => ['int'], 'SplFixedArray::key' => ['int'], 'SplFixedArray::next' => ['void'], 'SplFixedArray::offsetExists' => ['bool', 'index'=>'int'], 'SplFixedArray::offsetGet' => ['mixed', 'index'=>'int'], 'SplFixedArray::offsetSet' => ['void', 'index'=>'int', 'value'=>'mixed'], 'SplFixedArray::offsetUnset' => ['void', 'index'=>'int'], 'SplFixedArray::rewind' => ['void'], 'SplFixedArray::setSize' => ['bool', 'size'=>'int'], 'SplFixedArray::toArray' => ['array'], 'SplFixedArray::valid' => ['bool'], 'SplHeap::__construct' => ['void'], 'SplHeap::compare' => ['int', 'value1'=>'mixed', 'value2'=>'mixed'], 'SplHeap::count' => ['int'], 'SplHeap::current' => ['mixed'], 'SplHeap::extract' => ['mixed'], 'SplHeap::insert' => ['bool', 'value'=>'mixed'], 'SplHeap::isCorrupted' => ['bool'], 'SplHeap::isEmpty' => ['bool'], 'SplHeap::key' => ['int'], 'SplHeap::next' => ['void'], 'SplHeap::recoverFromCorruption' => ['true'], 'SplHeap::rewind' => ['void'], 'SplHeap::top' => ['mixed'], 'SplHeap::valid' => ['bool'], 'SplMaxHeap::__construct' => ['void'], 'SplMaxHeap::compare' => ['int', 'value1'=>'mixed', 'value2'=>'mixed'], 'SplMinHeap::compare' => ['int', 'value1'=>'mixed', 'value2'=>'mixed'], 'SplMinHeap::count' => ['int'], 'SplMinHeap::current' => ['mixed'], 'SplMinHeap::extract' => ['mixed'], 'SplMinHeap::insert' => ['true', 'value'=>'mixed'], 'SplMinHeap::isCorrupted' => ['bool'], 'SplMinHeap::isEmpty' => ['bool'], 'SplMinHeap::key' => ['int'], 'SplMinHeap::next' => ['void'], 'SplMinHeap::recoverFromCorruption' => ['true'], 'SplMinHeap::rewind' => ['void'], 'SplMinHeap::top' => ['mixed'], 'SplMinHeap::valid' => ['bool'], 'SplObjectStorage::__construct' => ['void'], 'SplObjectStorage::addAll' => ['int', 'storage'=>'SplObjectStorage'], 'SplObjectStorage::attach' => ['void', 'object'=>'object', 'info='=>'mixed'], 'SplObjectStorage::contains' => ['bool', 'object'=>'object'], 'SplObjectStorage::count' => ['int', 'mode='=>'int'], 'SplObjectStorage::current' => ['object'], 'SplObjectStorage::detach' => ['void', 'object'=>'object'], 'SplObjectStorage::getHash' => ['string', 'object'=>'object'], 'SplObjectStorage::getInfo' => ['mixed'], 'SplObjectStorage::key' => ['int'], 'SplObjectStorage::next' => ['void'], 'SplObjectStorage::offsetExists' => ['bool', 'object'=>'object'], 'SplObjectStorage::offsetGet' => ['mixed', 'object'=>'object'], 'SplObjectStorage::offsetSet' => ['void', 'object'=>'object', 'info='=>'mixed'], 'SplObjectStorage::offsetUnset' => ['void', 'object'=>'object'], 'SplObjectStorage::removeAll' => ['int', 'storage'=>'SplObjectStorage'], 'SplObjectStorage::removeAllExcept' => ['int', 'storage'=>'SplObjectStorage'], 'SplObjectStorage::rewind' => ['void'], 'SplObjectStorage::serialize' => ['string'], 'SplObjectStorage::setInfo' => ['void', 'info'=>'mixed'], 'SplObjectStorage::unserialize' => ['void', 'data'=>'string'], 'SplObjectStorage::valid' => ['bool'], 'SplObserver::update' => ['void', 'subject'=>'SplSubject'], 'SplPriorityQueue::__construct' => ['void'], 'SplPriorityQueue::compare' => ['int', 'priority1'=>'mixed', 'priority2'=>'mixed'], 'SplPriorityQueue::count' => ['int'], 'SplPriorityQueue::current' => ['mixed'], 'SplPriorityQueue::extract' => ['mixed'], 'SplPriorityQueue::getExtractFlags' => ['int'], 'SplPriorityQueue::insert' => ['bool', 'value'=>'mixed', 'priority'=>'mixed'], 'SplPriorityQueue::isEmpty' => ['bool'], 'SplPriorityQueue::key' => ['int'], 'SplPriorityQueue::next' => ['void'], 'SplPriorityQueue::recoverFromCorruption' => ['void'], 'SplPriorityQueue::rewind' => ['void'], 'SplPriorityQueue::setExtractFlags' => ['int', 'flags'=>'int'], 'SplPriorityQueue::top' => ['mixed'], 'SplPriorityQueue::valid' => ['bool'], 'SplQueue::dequeue' => ['mixed'], 'SplQueue::enqueue' => ['void', 'value'=>'mixed'], 'SplQueue::getIteratorMode' => ['int'], 'SplQueue::isEmpty' => ['bool'], 'SplQueue::key' => ['int'], 'SplQueue::next' => ['void'], 'SplQueue::offsetExists' => ['bool', 'index'=>'mixed'], 'SplQueue::offsetGet' => ['mixed', 'index'=>'mixed'], 'SplQueue::offsetSet' => ['void', 'index'=>'?int', 'value'=>'mixed'], 'SplQueue::offsetUnset' => ['void', 'index'=>'mixed'], 'SplQueue::pop' => ['mixed'], 'SplQueue::prev' => ['void'], 'SplQueue::push' => ['void', 'value'=>'mixed'], 'SplQueue::rewind' => ['void'], 'SplQueue::serialize' => ['string'], 'SplQueue::setIteratorMode' => ['int', 'mode'=>'int'], 'SplQueue::shift' => ['mixed'], 'SplQueue::top' => ['mixed'], 'SplQueue::unserialize' => ['void', 'data'=>'string'], 'SplQueue::unshift' => ['void', 'value'=>'mixed'], 'SplQueue::valid' => ['bool'], 'SplStack::__construct' => ['void'], 'SplStack::add' => ['void', 'index'=>'int', 'value'=>'mixed'], 'SplStack::bottom' => ['mixed'], 'SplStack::count' => ['int'], 'SplStack::current' => ['mixed'], 'SplStack::getIteratorMode' => ['int'], 'SplStack::isEmpty' => ['bool'], 'SplStack::key' => ['int'], 'SplStack::next' => ['void'], 'SplStack::offsetExists' => ['bool', 'index'=>'mixed'], 'SplStack::offsetGet' => ['mixed', 'index'=>'mixed'], 'SplStack::offsetSet' => ['void', 'index'=>'?int', 'value'=>'mixed'], 'SplStack::offsetUnset' => ['void', 'index'=>'mixed'], 'SplStack::pop' => ['mixed'], 'SplStack::prev' => ['void'], 'SplStack::push' => ['void', 'value'=>'mixed'], 'SplStack::rewind' => ['void'], 'SplStack::serialize' => ['string'], 'SplStack::setIteratorMode' => ['int', 'mode'=>'int'], 'SplStack::shift' => ['mixed'], 'SplStack::top' => ['mixed'], 'SplStack::unserialize' => ['void', 'data'=>'string'], 'SplStack::unshift' => ['void', 'value'=>'mixed'], 'SplStack::valid' => ['bool'], 'SplSubject::attach' => ['void', 'observer'=>'SplObserver'], 'SplSubject::detach' => ['void', 'observer'=>'SplObserver'], 'SplSubject::notify' => ['void'], 'SplTempFileObject::__construct' => ['void', 'maxMemory='=>'int'], 'SplTempFileObject::__toString' => ['string'], 'SplTempFileObject::current' => ['string|array|false'], 'SplTempFileObject::eof' => ['bool'], 'SplTempFileObject::fflush' => ['bool'], 'SplTempFileObject::fgetc' => ['string|false'], 'SplTempFileObject::fgetcsv' => ['list|array{0: null}|false', 'separator='=>'string', 'enclosure='=>'string', 'escape='=>'string'], 'SplTempFileObject::fgets' => ['string'], 'SplTempFileObject::fgetss' => ['string', 'allowable_tags='=>'string'], 'SplTempFileObject::flock' => ['bool', 'operation'=>'int', '&w_wouldBlock='=>'int'], 'SplTempFileObject::fpassthru' => ['int'], 'SplTempFileObject::fputcsv' => ['int|false', 'fields'=>'array', 'separator='=>'string', 'enclosure='=>'string', 'escape='=>'string'], 'SplTempFileObject::fread' => ['string|false', 'length'=>'int'], 'SplTempFileObject::fscanf' => ['array|int', 'format'=>'string', '&...w_vars='=>'string|int|float'], 'SplTempFileObject::fseek' => ['int', 'offset'=>'int', 'whence='=>'int'], 'SplTempFileObject::fstat' => ['array{0: int, 1: int, 2: int, 3: int, 4: int, 5: int, 6: int, 7: int, 8: int, 9: int, 10: int, 11: int, 12: int, dev: int, ino: int, mode: int, nlink: int, uid: int, gid: int, rdev: int, size: int, atime: int, mtime: int, ctime: int, blksize: int, blocks: int}'], 'SplTempFileObject::ftell' => ['int|false'], 'SplTempFileObject::ftruncate' => ['bool', 'size'=>'int'], 'SplTempFileObject::fwrite' => ['int', 'data'=>'string', 'length='=>'int'], 'SplTempFileObject::getATime' => ['int|false'], 'SplTempFileObject::getBasename' => ['string', 'suffix='=>'string'], 'SplTempFileObject::getCTime' => ['int|false'], 'SplTempFileObject::getChildren' => ['null'], 'SplTempFileObject::getCsvControl' => ['array'], 'SplTempFileObject::getCurrentLine' => ['string'], 'SplTempFileObject::getExtension' => ['string'], 'SplTempFileObject::getFileInfo' => ['SplFileInfo', 'class='=>'class-string'], 'SplTempFileObject::getFilename' => ['string'], 'SplTempFileObject::getFlags' => ['int'], 'SplTempFileObject::getGroup' => ['int|false'], 'SplTempFileObject::getInode' => ['int|false'], 'SplTempFileObject::getLinkTarget' => ['string|false'], 'SplTempFileObject::getMaxLineLen' => ['int'], 'SplTempFileObject::getMTime' => ['int|false'], 'SplTempFileObject::getOwner' => ['int|false'], 'SplTempFileObject::getPath' => ['string'], 'SplTempFileObject::getPathInfo' => ['SplFileInfo|null', 'class='=>'class-string'], 'SplTempFileObject::getPathname' => ['string'], 'SplTempFileObject::getPerms' => ['int|false'], 'SplTempFileObject::getRealPath' => ['false|non-falsy-string'], 'SplTempFileObject::getSize' => ['int|false'], 'SplTempFileObject::getType' => ['string|false'], 'SplTempFileObject::hasChildren' => ['false'], 'SplTempFileObject::isDir' => ['bool'], 'SplTempFileObject::isExecutable' => ['bool'], 'SplTempFileObject::isFile' => ['bool'], 'SplTempFileObject::isLink' => ['bool'], 'SplTempFileObject::isReadable' => ['bool'], 'SplTempFileObject::isWritable' => ['bool'], 'SplTempFileObject::key' => ['int'], 'SplTempFileObject::next' => ['void'], 'SplTempFileObject::openFile' => ['SplTempFileObject', 'mode='=>'string', 'useIncludePath='=>'bool', 'context='=>'resource'], 'SplTempFileObject::rewind' => ['void'], 'SplTempFileObject::seek' => ['void', 'line'=>'int'], 'SplTempFileObject::setCsvControl' => ['void', 'separator='=>'string', 'enclosure='=>'string', 'escape='=>'string'], 'SplTempFileObject::setFileClass' => ['void', 'class='=>'class-string'], 'SplTempFileObject::setFlags' => ['void', 'flags'=>'int'], 'SplTempFileObject::setInfoClass' => ['void', 'class='=>'class-string'], 'SplTempFileObject::setMaxLineLen' => ['void', 'maxLength'=>'int'], 'SplTempFileObject::valid' => ['bool'], 'SplType::__construct' => ['void', 'initial_value='=>'mixed', 'strict='=>'bool'], 'Spoofchecker::__construct' => ['void'], 'Spoofchecker::areConfusable' => ['bool', 'string1'=>'string', 'string2'=>'string', '&w_errorCode='=>'int'], 'Spoofchecker::isSuspicious' => ['bool', 'string'=>'string', '&w_errorCode='=>'int'], 'Spoofchecker::setAllowedLocales' => ['void', 'locales'=>'string'], 'Spoofchecker::setChecks' => ['void', 'checks'=>'int'], 'Spoofchecker::setRestrictionLevel' => ['void', 'level'=>'int'], 'Stomp::__construct' => ['void', 'broker='=>'string', 'username='=>'string', 'password='=>'string', 'headers='=>'?array'], 'Stomp::abort' => ['bool', 'transaction_id'=>'string', 'headers='=>'?array'], 'Stomp::ack' => ['bool', 'msg'=>'', 'headers='=>'?array'], 'Stomp::begin' => ['bool', 'transaction_id'=>'string', 'headers='=>'?array'], 'Stomp::commit' => ['bool', 'transaction_id'=>'string', 'headers='=>'?array'], 'Stomp::error' => ['string'], 'Stomp::getReadTimeout' => ['array'], 'Stomp::getSessionId' => ['string'], 'Stomp::hasFrame' => ['bool'], 'Stomp::readFrame' => ['array', 'class_name='=>'string'], 'Stomp::send' => ['bool', 'destination'=>'string', 'msg'=>'', 'headers='=>'?array'], 'Stomp::setReadTimeout' => ['void', 'seconds'=>'int', 'microseconds='=>'?int'], 'Stomp::subscribe' => ['bool', 'destination'=>'string', 'headers='=>'?array'], 'Stomp::unsubscribe' => ['bool', 'destination'=>'string', 'headers='=>'?array'], 'StompException::getDetails' => ['string'], 'StompFrame::__construct' => ['void', 'command='=>'string', 'headers='=>'?array', 'body='=>'string'], 'Swish::__construct' => ['void', 'index_names'=>'string'], 'Swish::getMetaList' => ['array', 'index_name'=>'string'], 'Swish::getPropertyList' => ['array', 'index_name'=>'string'], 'Swish::prepare' => ['object', 'query='=>'string'], 'Swish::query' => ['object', 'query'=>'string'], 'SwishResult::getMetaList' => ['array'], 'SwishResult::stem' => ['array', 'word'=>'string'], 'SwishResults::getParsedWords' => ['array', 'index_name'=>'string'], 'SwishResults::getRemovedStopwords' => ['array', 'index_name'=>'string'], 'SwishResults::nextResult' => ['object'], 'SwishResults::seekResult' => ['int', 'position'=>'int'], 'SwishSearch::execute' => ['object', 'query='=>'string'], 'SwishSearch::resetLimit' => [''], 'SwishSearch::setLimit' => ['', 'property'=>'string', 'low'=>'string', 'high'=>'string'], 'SwishSearch::setPhraseDelimiter' => ['', 'delimiter'=>'string'], 'SwishSearch::setSort' => ['', 'sort'=>'string'], 'SwishSearch::setStructure' => ['', 'structure'=>'int'], 'SyncEvent::__construct' => ['void', 'name='=>'string', 'manual='=>'bool'], 'SyncEvent::fire' => ['bool'], 'SyncEvent::reset' => ['bool'], 'SyncEvent::wait' => ['bool', 'wait='=>'int'], 'SyncMutex::__construct' => ['void', 'name='=>'string'], 'SyncMutex::lock' => ['bool', 'wait='=>'int'], 'SyncMutex::unlock' => ['bool', 'all='=>'bool'], 'SyncReaderWriter::__construct' => ['void', 'name='=>'string', 'autounlock='=>'bool'], 'SyncReaderWriter::readlock' => ['bool', 'wait='=>'int'], 'SyncReaderWriter::readunlock' => ['bool'], 'SyncReaderWriter::writelock' => ['bool', 'wait='=>'int'], 'SyncReaderWriter::writeunlock' => ['bool'], 'SyncSemaphore::__construct' => ['void', 'name='=>'string', 'initialval='=>'int', 'autounlock='=>'bool'], 'SyncSemaphore::lock' => ['bool', 'wait='=>'int'], 'SyncSemaphore::unlock' => ['bool', '&w_prevcount='=>'int'], 'SyncSharedMemory::__construct' => ['void', 'name'=>'string', 'size'=>'int'], 'SyncSharedMemory::first' => ['bool'], 'SyncSharedMemory::read' => ['string', 'start='=>'int', 'length='=>'int'], 'SyncSharedMemory::size' => ['int'], 'SyncSharedMemory::write' => ['int', 'string='=>'string', 'start='=>'int'], 'Thread::__construct' => ['void'], 'Thread::addRef' => ['void'], 'Thread::chunk' => ['array', 'size'=>'int', 'preserve'=>'bool'], 'Thread::count' => ['int'], 'Thread::delRef' => ['void'], 'Thread::detach' => ['void'], 'Thread::extend' => ['bool', 'class'=>'string'], 'Thread::getCreatorId' => ['int'], 'Thread::getCurrentThread' => ['Thread'], 'Thread::getCurrentThreadId' => ['int'], 'Thread::getRefCount' => ['int'], 'Thread::getTerminationInfo' => ['array'], 'Thread::getThreadId' => ['int'], 'Thread::globally' => ['mixed'], 'Thread::isGarbage' => ['bool'], 'Thread::isJoined' => ['bool'], 'Thread::isRunning' => ['bool'], 'Thread::isStarted' => ['bool'], 'Thread::isTerminated' => ['bool'], 'Thread::isWaiting' => ['bool'], 'Thread::join' => ['bool'], 'Thread::kill' => ['void'], 'Thread::lock' => ['bool'], 'Thread::merge' => ['bool', 'from'=>'', 'overwrite='=>'mixed'], 'Thread::notify' => ['bool'], 'Thread::notifyOne' => ['bool'], 'Thread::offsetExists' => ['bool', 'offset'=>'int|string'], 'Thread::offsetGet' => ['mixed', 'offset'=>'int|string'], 'Thread::offsetSet' => ['void', 'offset'=>'int|string|null', 'value'=>'mixed'], 'Thread::offsetUnset' => ['void', 'offset'=>'int|string'], 'Thread::pop' => ['bool'], 'Thread::run' => ['void'], 'Thread::setGarbage' => ['void'], 'Thread::shift' => ['bool'], 'Thread::start' => ['bool', 'options='=>'int'], 'Thread::synchronized' => ['mixed', 'block'=>'Closure', '_='=>'mixed'], 'Thread::unlock' => ['bool'], 'Thread::wait' => ['bool', 'timeout='=>'int'], 'Threaded::__construct' => ['void'], 'Threaded::addRef' => ['void'], 'Threaded::chunk' => ['array', 'size'=>'int', 'preserve'=>'bool'], 'Threaded::count' => ['int'], 'Threaded::delRef' => ['void'], 'Threaded::extend' => ['bool', 'class'=>'string'], 'Threaded::from' => ['Threaded', 'run'=>'Closure', 'construct='=>'Closure', 'args='=>'array'], 'Threaded::getRefCount' => ['int'], 'Threaded::getTerminationInfo' => ['array'], 'Threaded::isGarbage' => ['bool'], 'Threaded::isRunning' => ['bool'], 'Threaded::isTerminated' => ['bool'], 'Threaded::isWaiting' => ['bool'], 'Threaded::lock' => ['bool'], 'Threaded::merge' => ['bool', 'from'=>'mixed', 'overwrite='=>'bool'], 'Threaded::notify' => ['bool'], 'Threaded::notifyOne' => ['bool'], 'Threaded::offsetExists' => ['bool', 'offset'=>'int|string'], 'Threaded::offsetGet' => ['mixed', 'offset'=>'int|string'], 'Threaded::offsetSet' => ['void', 'offset'=>'int|string|null', 'value'=>'mixed'], 'Threaded::offsetUnset' => ['void', 'offset'=>'int|string'], 'Threaded::pop' => ['bool'], 'Threaded::run' => ['void'], 'Threaded::setGarbage' => ['void'], 'Threaded::shift' => ['mixed'], 'Threaded::synchronized' => ['mixed', 'block'=>'Closure', '...args='=>'mixed'], 'Threaded::unlock' => ['bool'], 'Threaded::wait' => ['bool', 'timeout='=>'int'], 'Throwable::__toString' => ['string'], 'Throwable::getCode' => ['int|string'], 'Throwable::getFile' => ['string'], 'Throwable::getLine' => ['int'], 'Throwable::getMessage' => ['string'], 'Throwable::getPrevious' => ['?Throwable'], 'Throwable::getTrace' => ['list\',args?:array}>'], 'Throwable::getTraceAsString' => ['string'], 'TokyoTyrant::__construct' => ['void', 'host='=>'string', 'port='=>'int', 'options='=>'array'], 'TokyoTyrant::add' => ['int|float', 'key'=>'string', 'increment'=>'float', 'type='=>'int'], 'TokyoTyrant::connect' => ['TokyoTyrant', 'host'=>'string', 'port='=>'int', 'options='=>'array'], 'TokyoTyrant::connectUri' => ['TokyoTyrant', 'uri'=>'string'], 'TokyoTyrant::copy' => ['TokyoTyrant', 'path'=>'string'], 'TokyoTyrant::ext' => ['string', 'name'=>'string', 'options'=>'int', 'key'=>'string', 'value'=>'string'], 'TokyoTyrant::fwmKeys' => ['array', 'prefix'=>'string', 'max_recs'=>'int'], 'TokyoTyrant::get' => ['array', 'keys'=>'mixed'], 'TokyoTyrant::getIterator' => ['TokyoTyrantIterator'], 'TokyoTyrant::num' => ['int'], 'TokyoTyrant::out' => ['string', 'keys'=>'mixed'], 'TokyoTyrant::put' => ['TokyoTyrant', 'keys'=>'mixed', 'value='=>'string'], 'TokyoTyrant::putCat' => ['TokyoTyrant', 'keys'=>'mixed', 'value='=>'string'], 'TokyoTyrant::putKeep' => ['TokyoTyrant', 'keys'=>'mixed', 'value='=>'string'], 'TokyoTyrant::putNr' => ['TokyoTyrant', 'keys'=>'mixed', 'value='=>'string'], 'TokyoTyrant::putShl' => ['mixed', 'key'=>'string', 'value'=>'string', 'width'=>'int'], 'TokyoTyrant::restore' => ['mixed', 'log_dir'=>'string', 'timestamp'=>'int', 'check_consistency='=>'bool'], 'TokyoTyrant::setMaster' => ['mixed', 'host'=>'string', 'port'=>'int', 'timestamp'=>'int', 'check_consistency='=>'bool'], 'TokyoTyrant::size' => ['int', 'key'=>'string'], 'TokyoTyrant::stat' => ['array'], 'TokyoTyrant::sync' => ['mixed'], 'TokyoTyrant::tune' => ['TokyoTyrant', 'timeout'=>'float', 'options='=>'int'], 'TokyoTyrant::vanish' => ['mixed'], 'TokyoTyrantIterator::__construct' => ['void', 'object'=>'mixed'], 'TokyoTyrantIterator::current' => ['mixed'], 'TokyoTyrantIterator::key' => ['mixed'], 'TokyoTyrantIterator::next' => ['mixed'], 'TokyoTyrantIterator::rewind' => ['void'], 'TokyoTyrantIterator::valid' => ['bool'], 'TokyoTyrantQuery::__construct' => ['void', 'table'=>'TokyoTyrantTable'], 'TokyoTyrantQuery::addCond' => ['mixed', 'name'=>'string', 'op'=>'int', 'expr'=>'string'], 'TokyoTyrantQuery::count' => ['int'], 'TokyoTyrantQuery::current' => ['array'], 'TokyoTyrantQuery::hint' => ['string'], 'TokyoTyrantQuery::key' => ['string'], 'TokyoTyrantQuery::metaSearch' => ['array', 'queries'=>'array', 'type'=>'int'], 'TokyoTyrantQuery::next' => ['array'], 'TokyoTyrantQuery::out' => ['TokyoTyrantQuery'], 'TokyoTyrantQuery::rewind' => ['bool'], 'TokyoTyrantQuery::search' => ['array'], 'TokyoTyrantQuery::setLimit' => ['mixed', 'max='=>'int', 'skip='=>'int'], 'TokyoTyrantQuery::setOrder' => ['mixed', 'name'=>'string', 'type'=>'int'], 'TokyoTyrantQuery::valid' => ['bool'], 'TokyoTyrantTable::add' => ['void', 'key'=>'string', 'increment'=>'mixed', 'type='=>'string'], 'TokyoTyrantTable::genUid' => ['int'], 'TokyoTyrantTable::get' => ['array', 'keys'=>'mixed'], 'TokyoTyrantTable::getIterator' => ['TokyoTyrantIterator'], 'TokyoTyrantTable::getQuery' => ['TokyoTyrantQuery'], 'TokyoTyrantTable::out' => ['void', 'keys'=>'mixed'], 'TokyoTyrantTable::put' => ['int', 'key'=>'string', 'columns'=>'array'], 'TokyoTyrantTable::putCat' => ['void', 'key'=>'string', 'columns'=>'array'], 'TokyoTyrantTable::putKeep' => ['void', 'key'=>'string', 'columns'=>'array'], 'TokyoTyrantTable::putNr' => ['void', 'keys'=>'mixed', 'value='=>'string'], 'TokyoTyrantTable::putShl' => ['void', 'key'=>'string', 'value'=>'string', 'width'=>'int'], 'TokyoTyrantTable::setIndex' => ['mixed', 'column'=>'string', 'type'=>'int'], 'Transliterator::create' => ['?Transliterator', 'id'=>'string', 'direction='=>'int'], 'Transliterator::createFromRules' => ['?Transliterator', 'rules'=>'string', 'direction='=>'int'], 'Transliterator::createInverse' => ['?Transliterator'], 'Transliterator::getErrorCode' => ['int'], 'Transliterator::getErrorMessage' => ['string'], 'Transliterator::listIDs' => ['array'], 'Transliterator::transliterate' => ['string|false', 'string'=>'string', 'start='=>'int', 'end='=>'int'], 'TypeError::__clone' => ['void'], 'TypeError::__construct' => ['void', 'message='=>'string', 'code='=>'int', 'previous='=>'?Throwable'], 'TypeError::__toString' => ['string'], 'TypeError::getCode' => ['int'], 'TypeError::getFile' => ['string'], 'TypeError::getLine' => ['int'], 'TypeError::getMessage' => ['string'], 'TypeError::getPrevious' => ['?Throwable'], 'TypeError::getTrace' => ['list\',args?:array}>'], 'TypeError::getTraceAsString' => ['string'], 'UConverter::__construct' => ['void', 'destination_encoding='=>'?string', 'source_encoding='=>'?string'], 'UConverter::convert' => ['string', 'str'=>'string', 'reverse='=>'bool'], 'UConverter::fromUCallback' => ['string|int|array|null', 'reason'=>'int', 'source'=>'array', 'codePoint'=>'int', '&w_error'=>'int'], 'UConverter::getAliases' => ['array|false|null', 'name'=>'string'], 'UConverter::getAvailable' => ['array'], 'UConverter::getDestinationEncoding' => ['string|false|null'], 'UConverter::getDestinationType' => ['int|false|null'], 'UConverter::getErrorCode' => ['int'], 'UConverter::getErrorMessage' => ['?string'], 'UConverter::getSourceEncoding' => ['string|false|null'], 'UConverter::getSourceType' => ['int|false|null'], 'UConverter::getStandards' => ['?array'], 'UConverter::getSubstChars' => ['string|false|null'], 'UConverter::reasonText' => ['string', 'reason'=>'int'], 'UConverter::setDestinationEncoding' => ['bool', 'encoding'=>'string'], 'UConverter::setSourceEncoding' => ['bool', 'encoding'=>'string'], 'UConverter::setSubstChars' => ['bool', 'chars'=>'string'], 'UConverter::toUCallback' => ['string|int|array|null', 'reason'=>'int', 'source'=>'string', 'codeUnits'=>'string', '&w_error'=>'int'], 'UConverter::transcode' => ['string', 'str'=>'string', 'toEncoding'=>'string', 'fromEncoding'=>'string', 'options='=>'?array'], 'UnderflowException::__clone' => ['void'], 'UnderflowException::__construct' => ['void', 'message='=>'string', 'code='=>'int', 'previous='=>'?Throwable'], 'UnderflowException::__toString' => ['string'], 'UnderflowException::getCode' => ['int'], 'UnderflowException::getFile' => ['string'], 'UnderflowException::getLine' => ['int'], 'UnderflowException::getMessage' => ['string'], 'UnderflowException::getPrevious' => ['?Throwable'], 'UnderflowException::getTrace' => ['list\',args?:array}>'], 'UnderflowException::getTraceAsString' => ['string'], 'UnexpectedValueException::__clone' => ['void'], 'UnexpectedValueException::__construct' => ['void', 'message='=>'string', 'code='=>'int', 'previous='=>'?Throwable'], 'UnexpectedValueException::__toString' => ['string'], 'UnexpectedValueException::getCode' => ['int'], 'UnexpectedValueException::getFile' => ['string'], 'UnexpectedValueException::getLine' => ['int'], 'UnexpectedValueException::getMessage' => ['string'], 'UnexpectedValueException::getPrevious' => ['?Throwable'], 'UnexpectedValueException::getTrace' => ['list\',args?:array}>'], 'UnexpectedValueException::getTraceAsString' => ['string'], 'V8Js::__construct' => ['void', 'object_name='=>'string', 'variables='=>'array', 'extensions='=>'array', 'report_uncaught_exceptions='=>'bool', 'snapshot_blob='=>'string'], 'V8Js::clearPendingException' => [''], 'V8Js::compileString' => ['resource', 'script'=>'', 'identifier='=>'string'], 'V8Js::createSnapshot' => ['false|string', 'embed_source'=>'string'], 'V8Js::executeScript' => ['', 'script'=>'resource', 'flags='=>'int', 'time_limit='=>'int', 'memory_limit='=>'int'], 'V8Js::executeString' => ['mixed', 'script'=>'string', 'identifier='=>'string', 'flags='=>'int'], 'V8Js::getExtensions' => ['string[]'], 'V8Js::getPendingException' => ['?V8JsException'], 'V8Js::registerExtension' => ['bool', 'extension_name'=>'string', 'script'=>'string', 'dependencies='=>'array', 'auto_enable='=>'bool'], 'V8Js::setAverageObjectSize' => ['', 'average_object_size'=>'int'], 'V8Js::setMemoryLimit' => ['', 'limit'=>'int'], 'V8Js::setModuleLoader' => ['', 'loader'=>'callable'], 'V8Js::setModuleNormaliser' => ['', 'normaliser'=>'callable'], 'V8Js::setTimeLimit' => ['', 'limit'=>'int'], 'V8JsException::getJsFileName' => ['string'], 'V8JsException::getJsLineNumber' => ['int'], 'V8JsException::getJsSourceLine' => ['int'], 'V8JsException::getJsTrace' => ['string'], 'V8JsScriptException::__clone' => ['void'], 'V8JsScriptException::__construct' => ['void', 'message='=>'string', 'code='=>'int', 'previous='=>'?Exception|?Throwable'], 'V8JsScriptException::__toString' => ['string'], 'V8JsScriptException::__wakeup' => ['void'], 'V8JsScriptException::getCode' => ['int'], 'V8JsScriptException::getFile' => ['string'], 'V8JsScriptException::getJsEndColumn' => ['int'], 'V8JsScriptException::getJsFileName' => ['string'], 'V8JsScriptException::getJsLineNumber' => ['int'], 'V8JsScriptException::getJsSourceLine' => ['string'], 'V8JsScriptException::getJsStartColumn' => ['int'], 'V8JsScriptException::getJsTrace' => ['string'], 'V8JsScriptException::getLine' => ['int'], 'V8JsScriptException::getMessage' => ['string'], 'V8JsScriptException::getPrevious' => ['Exception|Throwable'], 'V8JsScriptException::getTrace' => ['list\',args?:array}>'], 'V8JsScriptException::getTraceAsString' => ['string'], 'VARIANT::__construct' => ['void', 'value='=>'mixed', 'type='=>'int', 'codepage='=>'int'], 'VarnishAdmin::__construct' => ['void', 'args='=>'array'], 'VarnishAdmin::auth' => ['bool'], 'VarnishAdmin::ban' => ['int', 'vcl_regex'=>'string'], 'VarnishAdmin::banUrl' => ['int', 'vcl_regex'=>'string'], 'VarnishAdmin::clearPanic' => ['int'], 'VarnishAdmin::connect' => ['bool'], 'VarnishAdmin::disconnect' => ['bool'], 'VarnishAdmin::getPanic' => ['string'], 'VarnishAdmin::getParams' => ['array'], 'VarnishAdmin::isRunning' => ['bool'], 'VarnishAdmin::setCompat' => ['void', 'compat'=>'int'], 'VarnishAdmin::setHost' => ['void', 'host'=>'string'], 'VarnishAdmin::setIdent' => ['void', 'ident'=>'string'], 'VarnishAdmin::setParam' => ['int', 'name'=>'string', 'value'=>'string|int'], 'VarnishAdmin::setPort' => ['void', 'port'=>'int'], 'VarnishAdmin::setSecret' => ['void', 'secret'=>'string'], 'VarnishAdmin::setTimeout' => ['void', 'timeout'=>'int'], 'VarnishAdmin::start' => ['int'], 'VarnishAdmin::stop' => ['int'], 'VarnishLog::__construct' => ['void', 'args='=>'array'], 'VarnishLog::getLine' => ['array'], 'VarnishLog::getTagName' => ['string', 'index'=>'int'], 'VarnishStat::__construct' => ['void', 'args='=>'array'], 'VarnishStat::getSnapshot' => ['array'], 'Vtiful\Kernel\Chart::__construct' => ['void', 'handle'=>'resource', 'type'=>'int'], 'Vtiful\Kernel\Chart::axisNameX' => ['Vtiful\Kernel\Chart', 'name'=>'string'], 'Vtiful\Kernel\Chart::axisNameY' => ['Vtiful\Kernel\Chart', 'name'=>'string'], 'Vtiful\Kernel\Chart::legendSetPosition' => ['Vtiful\Kernel\Chart', 'type'=>'int'], 'Vtiful\Kernel\Chart::series' => ['Vtiful\Kernel\Chart', 'value'=>'string', 'categories='=>'string'], 'Vtiful\Kernel\Chart::seriesName' => ['Vtiful\Kernel\Chart', 'value'=>'string'], 'Vtiful\Kernel\Chart::style' => ['Vtiful\Kernel\Chart', 'style'=>'int'], 'Vtiful\Kernel\Chart::title' => ['Vtiful\Kernel\Chart', 'title'=>'string'], 'Vtiful\Kernel\Chart::toResource' => ['resource'], 'Vtiful\Kernel\Excel::__construct' => ['void', 'config'=>'array'], 'Vtiful\Kernel\Excel::activateSheet' => ['bool', 'sheet_name'=>'string'], 'Vtiful\Kernel\Excel::addSheet' => ['Vtiful\Kernel\Excel', 'sheet_name='=>'?string'], 'Vtiful\Kernel\Excel::autoFilter' => ['Vtiful\Kernel\Excel', 'range'=>'string'], 'Vtiful\Kernel\Excel::checkoutSheet' => ['Vtiful\Kernel\Excel', 'sheet_name'=>'string'], 'Vtiful\Kernel\Excel::close' => ['Vtiful\Kernel\Excel'], 'Vtiful\Kernel\Excel::columnIndexFromString' => ['int', 'index'=>'string'], 'Vtiful\Kernel\Excel::constMemory' => ['Vtiful\Kernel\Excel', 'file_name'=>'string', 'sheet_name='=>'?string'], 'Vtiful\Kernel\Excel::data' => ['Vtiful\Kernel\Excel', 'data'=>'array'], 'Vtiful\Kernel\Excel::defaultFormat' => ['Vtiful\Kernel\Excel', 'format_handle'=>'resource'], 'Vtiful\Kernel\Excel::existSheet' => ['bool', 'sheet_name'=>'string'], 'Vtiful\Kernel\Excel::fileName' => ['Vtiful\Kernel\Excel', 'file_name'=>'string', 'sheet_name='=>'?string'], 'Vtiful\Kernel\Excel::freezePanes' => ['Vtiful\Kernel\Excel', 'row'=>'int', 'column'=>'int'], 'Vtiful\Kernel\Excel::getHandle' => ['resource'], 'Vtiful\Kernel\Excel::getSheetData' => ['array|false'], 'Vtiful\Kernel\Excel::gridline' => ['Vtiful\Kernel\Excel', 'option='=>'int'], 'Vtiful\Kernel\Excel::header' => ['Vtiful\Kernel\Excel', 'header'=>'array', 'format_handle='=>'?resource'], 'Vtiful\Kernel\Excel::insertChart' => ['Vtiful\Kernel\Excel', 'row'=>'int', 'column'=>'int', 'chart_resource'=>'resource'], 'Vtiful\Kernel\Excel::insertComment' => ['Vtiful\Kernel\Excel', 'row'=>'int', 'column'=>'int', 'comment'=>'string'], 'Vtiful\Kernel\Excel::insertDate' => ['Vtiful\Kernel\Excel', 'row'=>'int', 'column'=>'int', 'timestamp'=>'int', 'format='=>'?string', 'format_handle='=>'?resource'], 'Vtiful\Kernel\Excel::insertFormula' => ['Vtiful\Kernel\Excel', 'row'=>'int', 'column'=>'int', 'formula'=>'string', 'format_handle='=>'?resource'], 'Vtiful\Kernel\Excel::insertImage' => ['Vtiful\Kernel\Excel', 'row'=>'int', 'column'=>'int', 'image'=>'string', 'width='=>'?float', 'height='=>'?float'], 'Vtiful\Kernel\Excel::insertText' => ['Vtiful\Kernel\Excel', 'row'=>'int', 'column'=>'int', 'data'=>'int|string|double', 'format='=>'?string', 'format_handle='=>'?resource'], 'Vtiful\Kernel\Excel::insertUrl' => ['Vtiful\Kernel\Excel', 'row'=>'int', 'column'=>'int', 'url'=>'string', 'text='=>'?string', 'tool_tip='=>'?string', 'format='=>'?resource'], 'Vtiful\Kernel\Excel::mergeCells' => ['Vtiful\Kernel\Excel', 'range'=>'string', 'data'=>'string', 'format_handle='=>'?resource'], 'Vtiful\Kernel\Excel::nextCellCallback' => ['void', 'fci'=>'callable(int,int,mixed)', 'sheet_name='=>'?string'], 'Vtiful\Kernel\Excel::nextRow' => ['array|false', 'zv_type_t='=>'?array'], 'Vtiful\Kernel\Excel::openFile' => ['Vtiful\Kernel\Excel', 'zs_file_name'=>'string'], 'Vtiful\Kernel\Excel::openSheet' => ['Vtiful\Kernel\Excel', 'zs_sheet_name='=>'?string', 'zl_flag='=>'?int'], 'Vtiful\Kernel\Excel::output' => ['string'], 'Vtiful\Kernel\Excel::protection' => ['Vtiful\Kernel\Excel', 'password='=>'?string'], 'Vtiful\Kernel\Excel::putCSV' => ['bool', 'fp'=>'resource', 'delimiter_str='=>'?string', 'enclosure_str='=>'?string', 'escape_str='=>'?string'], 'Vtiful\Kernel\Excel::putCSVCallback' => ['bool', 'callback'=>'callable(array):array', 'fp'=>'resource', 'delimiter_str='=>'?string', 'enclosure_str='=>'?string', 'escape_str='=>'?string'], 'Vtiful\Kernel\Excel::setColumn' => ['Vtiful\Kernel\Excel', 'range'=>'string', 'width'=>'float', 'format_handle='=>'?resource'], 'Vtiful\Kernel\Excel::setCurrentSheetHide' => ['Vtiful\Kernel\Excel'], 'Vtiful\Kernel\Excel::setCurrentSheetIsFirst' => ['Vtiful\Kernel\Excel'], 'Vtiful\Kernel\Excel::setGlobalType' => ['Vtiful\Kernel\Excel', 'zv_type_t'=>'int'], 'Vtiful\Kernel\Excel::setLandscape' => ['Vtiful\Kernel\Excel'], 'Vtiful\Kernel\Excel::setMargins' => ['Vtiful\Kernel\Excel', 'left='=>'?float', 'right='=>'?float', 'top='=>'?float', 'bottom='=>'?float'], 'Vtiful\Kernel\Excel::setPaper' => ['Vtiful\Kernel\Excel', 'paper'=>'int'], 'Vtiful\Kernel\Excel::setPortrait' => ['Vtiful\Kernel\Excel'], 'Vtiful\Kernel\Excel::setRow' => ['Vtiful\Kernel\Excel', 'range'=>'string', 'height'=>'float', 'format_handle='=>'?resource'], 'Vtiful\Kernel\Excel::setSkipRows' => ['Vtiful\Kernel\Excel', 'zv_skip_t'=>'int'], 'Vtiful\Kernel\Excel::setType' => ['Vtiful\Kernel\Excel', 'zv_type_t'=>'array'], 'Vtiful\Kernel\Excel::sheetList' => ['array'], 'Vtiful\Kernel\Excel::showComment' => ['Vtiful\Kernel\Excel'], 'Vtiful\Kernel\Excel::stringFromColumnIndex' => ['string', 'index'=>'int'], 'Vtiful\Kernel\Excel::timestampFromDateDouble' => ['int', 'index'=>'?float'], 'Vtiful\Kernel\Excel::validation' => ['Vtiful\Kernel\Excel', 'range'=>'string', 'validation_resource'=>'resource'], 'Vtiful\Kernel\Excel::zoom' => ['Vtiful\Kernel\Excel', 'scale'=>'int'], 'Vtiful\Kernel\Format::__construct' => ['void', 'handle'=>'resource'], 'Vtiful\Kernel\Format::align' => ['Vtiful\Kernel\Format', '...style'=>'int'], 'Vtiful\Kernel\Format::background' => ['Vtiful\Kernel\Format', 'color'=>'int', 'pattern='=>'int'], 'Vtiful\Kernel\Format::bold' => ['Vtiful\Kernel\Format'], 'Vtiful\Kernel\Format::border' => ['Vtiful\Kernel\Format', 'style'=>'int'], 'Vtiful\Kernel\Format::font' => ['Vtiful\Kernel\Format', 'font'=>'string'], 'Vtiful\Kernel\Format::fontColor' => ['Vtiful\Kernel\Format', 'color'=>'int'], 'Vtiful\Kernel\Format::fontSize' => ['Vtiful\Kernel\Format', 'size'=>'float'], 'Vtiful\Kernel\Format::italic' => ['Vtiful\Kernel\Format'], 'Vtiful\Kernel\Format::number' => ['Vtiful\Kernel\Format', 'format'=>'string'], 'Vtiful\Kernel\Format::strikeout' => ['Vtiful\Kernel\Format'], 'Vtiful\Kernel\Format::toResource' => ['resource'], 'Vtiful\Kernel\Format::underline' => ['Vtiful\Kernel\Format', 'style'=>'int'], 'Vtiful\Kernel\Format::unlocked' => ['Vtiful\Kernel\Format'], 'Vtiful\Kernel\Format::wrap' => ['Vtiful\Kernel\Format'], 'Vtiful\Kernel\Validation::__construct' => ['void'], 'Vtiful\Kernel\Validation::criteriaType' => ['?Vtiful\Kernel\Validation', 'type'=>'int'], 'Vtiful\Kernel\Validation::maximumFormula' => ['?Vtiful\Kernel\Validation', 'maximum_formula'=>'string'], 'Vtiful\Kernel\Validation::maximumNumber' => ['?Vtiful\Kernel\Validation', 'maximum_number'=>'float'], 'Vtiful\Kernel\Validation::minimumFormula' => ['?Vtiful\Kernel\Validation', 'minimum_formula'=>'string'], 'Vtiful\Kernel\Validation::minimumNumber' => ['?Vtiful\Kernel\Validation', 'minimum_number'=>'float'], 'Vtiful\Kernel\Validation::toResource' => ['resource'], 'Vtiful\Kernel\Validation::validationType' => ['?Vtiful\Kernel\Validation', 'type'=>'int'], 'Vtiful\Kernel\Validation::valueList' => ['?Vtiful\Kernel\Validation', 'value_list'=>'array'], 'Vtiful\Kernel\Validation::valueNumber' => ['?Vtiful\Kernel\Validation', 'value_number'=>'int'], 'Weakref::acquire' => ['bool'], 'Weakref::get' => ['object'], 'Weakref::release' => ['bool'], 'Weakref::valid' => ['bool'], 'Worker::__construct' => ['void'], 'Worker::addRef' => ['void'], 'Worker::chunk' => ['array', 'size'=>'int', 'preserve'=>'bool'], 'Worker::collect' => ['int', 'collector='=>'Callable'], 'Worker::count' => ['int'], 'Worker::delRef' => ['void'], 'Worker::detach' => ['void'], 'Worker::extend' => ['bool', 'class'=>'string'], 'Worker::getCreatorId' => ['int'], 'Worker::getCurrentThread' => ['Thread'], 'Worker::getCurrentThreadId' => ['int'], 'Worker::getRefCount' => ['int'], 'Worker::getStacked' => ['int'], 'Worker::getTerminationInfo' => ['array'], 'Worker::getThreadId' => ['int'], 'Worker::globally' => ['mixed'], 'Worker::isGarbage' => ['bool'], 'Worker::isJoined' => ['bool'], 'Worker::isRunning' => ['bool'], 'Worker::isShutdown' => ['bool'], 'Worker::isStarted' => ['bool'], 'Worker::isTerminated' => ['bool'], 'Worker::isWaiting' => ['bool'], 'Worker::isWorking' => ['bool'], 'Worker::join' => ['bool'], 'Worker::kill' => ['bool'], 'Worker::lock' => ['bool'], 'Worker::merge' => ['bool', 'from'=>'', 'overwrite='=>'mixed'], 'Worker::notify' => ['bool'], 'Worker::notifyOne' => ['bool'], 'Worker::offsetExists' => ['bool', 'offset'=>'int|string'], 'Worker::offsetGet' => ['mixed', 'offset'=>'int|string'], 'Worker::offsetSet' => ['void', 'offset'=>'int|string|null', 'value'=>'mixed'], 'Worker::offsetUnset' => ['void', 'offset'=>'int|string'], 'Worker::pop' => ['bool'], 'Worker::run' => ['void'], 'Worker::setGarbage' => ['void'], 'Worker::shift' => ['bool'], 'Worker::shutdown' => ['bool'], 'Worker::stack' => ['int', '&rw_work'=>'Threaded'], 'Worker::start' => ['bool', 'options='=>'int'], 'Worker::synchronized' => ['mixed', 'block'=>'Closure', '_='=>'mixed'], 'Worker::unlock' => ['bool'], 'Worker::unstack' => ['int', '&rw_work='=>'Threaded'], 'Worker::wait' => ['bool', 'timeout='=>'int'], 'XMLDiff\Base::__construct' => ['void', 'nsname'=>'string'], 'XMLDiff\Base::diff' => ['mixed', 'from'=>'mixed', 'to'=>'mixed'], 'XMLDiff\Base::merge' => ['mixed', 'src'=>'mixed', 'diff'=>'mixed'], 'XMLDiff\DOM::diff' => ['DOMDocument', 'from'=>'DOMDocument', 'to'=>'DOMDocument'], 'XMLDiff\DOM::merge' => ['DOMDocument', 'src'=>'DOMDocument', 'diff'=>'DOMDocument'], 'XMLDiff\File::diff' => ['string', 'from'=>'string', 'to'=>'string'], 'XMLDiff\File::merge' => ['string', 'src'=>'string', 'diff'=>'string'], 'XMLDiff\Memory::diff' => ['string', 'from'=>'string', 'to'=>'string'], 'XMLDiff\Memory::merge' => ['string', 'src'=>'string', 'diff'=>'string'], 'XMLReader::XML' => ['bool|XMLReader', 'source'=>'string', 'encoding='=>'?string', 'flags='=>'int'], 'XMLReader::close' => ['bool'], 'XMLReader::expand' => ['DOMNode|false', 'baseNode='=>'?DOMNode'], 'XMLReader::getAttribute' => ['?string', 'name'=>'string'], 'XMLReader::getAttributeNo' => ['?string', 'index'=>'int'], 'XMLReader::getAttributeNs' => ['?string', 'name'=>'string', 'namespace'=>'string'], 'XMLReader::getParserProperty' => ['bool', 'property'=>'int'], 'XMLReader::isValid' => ['bool'], 'XMLReader::lookupNamespace' => ['?string', 'prefix'=>'string'], 'XMLReader::moveToAttribute' => ['bool', 'name'=>'string'], 'XMLReader::moveToAttributeNo' => ['bool', 'index'=>'int'], 'XMLReader::moveToAttributeNs' => ['bool', 'name'=>'string', 'namespace'=>'string'], 'XMLReader::moveToElement' => ['bool'], 'XMLReader::moveToFirstAttribute' => ['bool'], 'XMLReader::moveToNextAttribute' => ['bool'], 'XMLReader::next' => ['bool', 'name='=>'string'], 'XMLReader::open' => ['bool|XmlReader', 'uri'=>'string', 'encoding='=>'?string', 'flags='=>'int'], 'XMLReader::read' => ['bool'], 'XMLReader::readInnerXML' => ['string'], 'XMLReader::readOuterXML' => ['string'], 'XMLReader::readString' => ['string'], 'XMLReader::setParserProperty' => ['bool', 'property'=>'int', 'value'=>'bool'], 'XMLReader::setRelaxNGSchema' => ['bool', 'filename'=>'?string'], 'XMLReader::setRelaxNGSchemaSource' => ['bool', 'source'=>'?string'], 'XMLReader::setSchema' => ['bool', 'filename'=>'?string'], 'XMLWriter::endAttribute' => ['bool'], 'XMLWriter::endCdata' => ['bool'], 'XMLWriter::endComment' => ['bool'], 'XMLWriter::endDocument' => ['bool'], 'XMLWriter::endDtd' => ['bool'], 'XMLWriter::endDtdAttlist' => ['bool'], 'XMLWriter::endDtdElement' => ['bool'], 'XMLWriter::endDtdEntity' => ['bool'], 'XMLWriter::endElement' => ['bool'], 'XMLWriter::endPi' => ['bool'], 'XMLWriter::flush' => ['string|int|false', 'empty='=>'bool'], 'XMLWriter::fullEndElement' => ['bool'], 'XMLWriter::openMemory' => ['bool'], 'XMLWriter::openUri' => ['bool', 'uri'=>'string'], 'XMLWriter::outputMemory' => ['string', 'flush='=>'bool'], 'XMLWriter::setIndent' => ['bool', 'enable'=>'bool'], 'XMLWriter::setIndentString' => ['bool', 'indentation'=>'string'], 'XMLWriter::startAttribute' => ['bool', 'name'=>'string'], 'XMLWriter::startAttributeNs' => ['bool', 'prefix'=>'string', 'name'=>'string', 'namespace'=>'?string'], 'XMLWriter::startCdata' => ['bool'], 'XMLWriter::startComment' => ['bool'], 'XMLWriter::startDocument' => ['bool', 'version='=>'?string', 'encoding='=>'?string', 'standalone='=>'?string'], 'XMLWriter::startDtd' => ['bool', 'qualifiedName'=>'string', 'publicId='=>'?string', 'systemId='=>'?string'], 'XMLWriter::startDtdAttlist' => ['bool', 'name'=>'string'], 'XMLWriter::startDtdElement' => ['bool', 'qualifiedName'=>'string'], 'XMLWriter::startDtdEntity' => ['bool', 'name'=>'string', 'isParam'=>'bool'], 'XMLWriter::startElement' => ['bool', 'name'=>'string'], 'XMLWriter::startElementNs' => ['bool', 'prefix'=>'?string', 'name'=>'string', 'namespace'=>'?string'], 'XMLWriter::startPi' => ['bool', 'target'=>'string'], 'XMLWriter::text' => ['bool', 'content'=>'string'], 'XMLWriter::writeAttribute' => ['bool', 'name'=>'string', 'value'=>'string'], 'XMLWriter::writeAttributeNs' => ['bool', 'prefix'=>'string', 'name'=>'string', 'namespace'=>'?string', 'value'=>'string'], 'XMLWriter::writeCdata' => ['bool', 'content'=>'string'], 'XMLWriter::writeComment' => ['bool', 'content'=>'string'], 'XMLWriter::writeDtd' => ['bool', 'name'=>'string', 'publicId='=>'?string', 'systemId='=>'?string', 'content='=>'?string'], 'XMLWriter::writeDtdAttlist' => ['bool', 'name'=>'string', 'content'=>'string'], 'XMLWriter::writeDtdElement' => ['bool', 'name'=>'string', 'content'=>'string'], 'XMLWriter::writeDtdEntity' => ['bool', 'name'=>'string', 'content'=>'string', 'isParam'=>'bool', 'publicId'=>'string', 'systemId'=>'string', 'notationData'=>'string'], 'XMLWriter::writeElement' => ['bool', 'name'=>'string', 'content='=>'?string'], 'XMLWriter::writeElementNs' => ['bool', 'prefix'=>'?string', 'name'=>'string', 'namespace'=>'?string', 'content='=>'?string'], 'XMLWriter::writePi' => ['bool', 'target'=>'string', 'content'=>'string'], 'XMLWriter::writeRaw' => ['bool', 'content'=>'string'], 'XSLTProcessor::getParameter' => ['string|false', 'namespace'=>'string', 'name'=>'string'], 'XSLTProcessor::hasExsltSupport' => ['bool'], 'XSLTProcessor::importStylesheet' => ['bool', 'stylesheet'=>'object'], 'XSLTProcessor::registerPHPFunctions' => ['void', 'functions='=>'array|string|null'], 'XSLTProcessor::removeParameter' => ['bool', 'namespace'=>'string', 'name'=>'string'], 'XSLTProcessor::setParameter' => ['bool', 'namespace'=>'string', 'name'=>'string', 'value'=>'string'], 'XSLTProcessor::setParameter\'1' => ['bool', 'namespace'=>'string', 'options'=>'array'], 'XSLTProcessor::setProfiling' => ['bool', 'filename'=>'?string'], 'XSLTProcessor::transformToDoc' => ['DOMDocument|false', 'document'=>'DOMNode', 'returnClass='=>'?string'], 'XSLTProcessor::transformToURI' => ['int', 'document'=>'DOMDocument', 'uri'=>'string'], 'XSLTProcessor::transformToXML' => ['string|false', 'document'=>'DOMDocument'], 'Xcom::__construct' => ['void', 'fabric_url='=>'string', 'fabric_token='=>'string', 'capability_token='=>'string'], 'Xcom::decode' => ['object', 'avro_msg'=>'string', 'json_schema'=>'string'], 'Xcom::encode' => ['string', 'data'=>'stdClass', 'avro_schema'=>'string'], 'Xcom::getDebugOutput' => ['string'], 'Xcom::getLastResponse' => ['string'], 'Xcom::getLastResponseInfo' => ['array'], 'Xcom::getOnboardingURL' => ['string', 'capability_name'=>'string', 'agreement_url'=>'string'], 'Xcom::send' => ['int', 'topic'=>'string', 'data'=>'mixed', 'json_schema='=>'string', 'http_headers='=>'array'], 'Xcom::sendAsync' => ['int', 'topic'=>'string', 'data'=>'mixed', 'json_schema='=>'string', 'http_headers='=>'array'], 'XsltProcessor::getSecurityPrefs' => ['int'], 'XsltProcessor::setSecurityPrefs' => ['int', 'preferences'=>'int'], 'Yaconf::get' => ['mixed', 'name'=>'string', 'default_value='=>'mixed'], 'Yaconf::has' => ['bool', 'name'=>'string'], 'Yaf\Action_Abstract::__clone' => ['void'], 'Yaf\Action_Abstract::__construct' => ['void', 'request'=>'Yaf\Request_Abstract', 'response'=>'Yaf\Response_Abstract', 'view'=>'Yaf\View_Interface', 'invokeArgs='=>'?array'], 'Yaf\Action_Abstract::display' => ['bool', 'tpl'=>'string', 'parameters='=>'?array'], 'Yaf\Action_Abstract::execute' => ['mixed'], 'Yaf\Action_Abstract::forward' => ['bool', 'module'=>'string', 'controller='=>'string', 'action='=>'string', 'parameters='=>'?array'], 'Yaf\Action_Abstract::getController' => ['Yaf\Controller_Abstract'], 'Yaf\Action_Abstract::getInvokeArg' => ['mixed|null', 'name'=>'string'], 'Yaf\Action_Abstract::getInvokeArgs' => ['array'], 'Yaf\Action_Abstract::getModuleName' => ['string'], 'Yaf\Action_Abstract::getRequest' => ['Yaf\Request_Abstract'], 'Yaf\Action_Abstract::getResponse' => ['Yaf\Response_Abstract'], 'Yaf\Action_Abstract::getView' => ['Yaf\View_Interface'], 'Yaf\Action_Abstract::getViewpath' => ['string'], 'Yaf\Action_Abstract::init' => [''], 'Yaf\Action_Abstract::initView' => ['Yaf\Response_Abstract', 'options='=>'?array'], 'Yaf\Action_Abstract::redirect' => ['bool', 'url'=>'string'], 'Yaf\Action_Abstract::render' => ['string', 'tpl'=>'string', 'parameters='=>'?array'], 'Yaf\Action_Abstract::setViewpath' => ['bool', 'view_directory'=>'string'], 'Yaf\Application::__clone' => ['void'], 'Yaf\Application::__construct' => ['void', 'config'=>'array|string', 'envrion='=>'string'], 'Yaf\Application::__destruct' => ['void'], 'Yaf\Application::__sleep' => ['string[]'], 'Yaf\Application::__wakeup' => ['void'], 'Yaf\Application::app' => ['?Yaf\Application'], 'Yaf\Application::bootstrap' => ['Yaf\Application', 'bootstrap='=>'?Yaf\Bootstrap_Abstract'], 'Yaf\Application::clearLastError' => ['void'], 'Yaf\Application::environ' => ['string'], 'Yaf\Application::execute' => ['void', 'entry'=>'callable', '_='=>'string'], 'Yaf\Application::getAppDirectory' => ['string'], 'Yaf\Application::getConfig' => ['Yaf\Config_Abstract'], 'Yaf\Application::getDispatcher' => ['Yaf\Dispatcher'], 'Yaf\Application::getLastErrorMsg' => ['string'], 'Yaf\Application::getLastErrorNo' => ['int'], 'Yaf\Application::getModules' => ['array'], 'Yaf\Application::run' => ['void'], 'Yaf\Application::setAppDirectory' => ['Yaf\Application', 'directory'=>'string'], 'Yaf\Config\Ini::__construct' => ['void', 'config_file'=>'string', 'section='=>'string'], 'Yaf\Config\Ini::__get' => ['', 'name='=>'mixed'], 'Yaf\Config\Ini::__isset' => ['', 'name'=>'string'], 'Yaf\Config\Ini::__set' => ['void', 'name'=>'', 'value'=>''], 'Yaf\Config\Ini::count' => ['int'], 'Yaf\Config\Ini::current' => ['mixed'], 'Yaf\Config\Ini::get' => ['mixed', 'name='=>'mixed'], 'Yaf\Config\Ini::key' => ['int|string'], 'Yaf\Config\Ini::next' => ['void'], 'Yaf\Config\Ini::offsetExists' => ['bool', 'name'=>'int|string'], 'Yaf\Config\Ini::offsetGet' => ['mixed', 'name'=>'int|string'], 'Yaf\Config\Ini::offsetSet' => ['void', 'name'=>'int|string|null', 'value'=>'mixed'], 'Yaf\Config\Ini::offsetUnset' => ['void', 'name'=>'int|string'], 'Yaf\Config\Ini::readonly' => ['bool'], 'Yaf\Config\Ini::rewind' => ['void'], 'Yaf\Config\Ini::set' => ['Yaf\Config_Abstract', 'name'=>'string', 'value'=>'mixed'], 'Yaf\Config\Ini::toArray' => ['array'], 'Yaf\Config\Ini::valid' => ['bool'], 'Yaf\Config\Simple::__construct' => ['void', 'array'=>'array', 'readonly='=>'string'], 'Yaf\Config\Simple::__get' => ['', 'name='=>'mixed'], 'Yaf\Config\Simple::__isset' => ['', 'name'=>'string'], 'Yaf\Config\Simple::__set' => ['void', 'name'=>'', 'value'=>''], 'Yaf\Config\Simple::count' => ['int'], 'Yaf\Config\Simple::current' => ['mixed'], 'Yaf\Config\Simple::get' => ['mixed', 'name='=>'mixed'], 'Yaf\Config\Simple::key' => ['int|string'], 'Yaf\Config\Simple::next' => ['void'], 'Yaf\Config\Simple::offsetExists' => ['bool', 'name'=>'int|string'], 'Yaf\Config\Simple::offsetGet' => ['mixed', 'name'=>'int|string'], 'Yaf\Config\Simple::offsetSet' => ['void', 'name'=>'int|string|null', 'value'=>'mixed'], 'Yaf\Config\Simple::offsetUnset' => ['void', 'name'=>'int|string'], 'Yaf\Config\Simple::readonly' => ['bool'], 'Yaf\Config\Simple::rewind' => ['void'], 'Yaf\Config\Simple::set' => ['Yaf\Config_Abstract', 'name'=>'string', 'value'=>'mixed'], 'Yaf\Config\Simple::toArray' => ['array'], 'Yaf\Config\Simple::valid' => ['bool'], 'Yaf\Config_Abstract::__construct' => ['void'], 'Yaf\Config_Abstract::get' => ['mixed', 'name='=>'string'], 'Yaf\Config_Abstract::readonly' => ['bool'], 'Yaf\Config_Abstract::set' => ['Yaf\Config_Abstract', 'name'=>'string', 'value'=>'mixed'], 'Yaf\Config_Abstract::toArray' => ['array'], 'Yaf\Controller_Abstract::__clone' => ['void'], 'Yaf\Controller_Abstract::__construct' => ['void', 'request'=>'Yaf\Request_Abstract', 'response'=>'Yaf\Response_Abstract', 'view'=>'Yaf\View_Interface', 'invokeArgs='=>'?array'], 'Yaf\Controller_Abstract::display' => ['bool', 'tpl'=>'string', 'parameters='=>'?array'], 'Yaf\Controller_Abstract::forward' => ['bool', 'module'=>'string', 'controller='=>'string', 'action='=>'string', 'parameters='=>'?array'], 'Yaf\Controller_Abstract::getInvokeArg' => ['mixed|null', 'name'=>'string'], 'Yaf\Controller_Abstract::getInvokeArgs' => ['array'], 'Yaf\Controller_Abstract::getModuleName' => ['string'], 'Yaf\Controller_Abstract::getRequest' => ['Yaf\Request_Abstract'], 'Yaf\Controller_Abstract::getResponse' => ['Yaf\Response_Abstract'], 'Yaf\Controller_Abstract::getView' => ['Yaf\View_Interface'], 'Yaf\Controller_Abstract::getViewpath' => ['string'], 'Yaf\Controller_Abstract::init' => [''], 'Yaf\Controller_Abstract::initView' => ['Yaf\Response_Abstract', 'options='=>'?array'], 'Yaf\Controller_Abstract::redirect' => ['bool', 'url'=>'string'], 'Yaf\Controller_Abstract::render' => ['string', 'tpl'=>'string', 'parameters='=>'?array'], 'Yaf\Controller_Abstract::setViewpath' => ['bool', 'view_directory'=>'string'], 'Yaf\Dispatcher::__clone' => ['void'], 'Yaf\Dispatcher::__construct' => ['void'], 'Yaf\Dispatcher::__sleep' => ['list'], 'Yaf\Dispatcher::__wakeup' => ['void'], 'Yaf\Dispatcher::autoRender' => ['Yaf\Dispatcher', 'flag='=>'bool'], 'Yaf\Dispatcher::catchException' => ['Yaf\Dispatcher', 'flag='=>'bool'], 'Yaf\Dispatcher::disableView' => ['bool'], 'Yaf\Dispatcher::dispatch' => ['Yaf\Response_Abstract', 'request'=>'Yaf\Request_Abstract'], 'Yaf\Dispatcher::enableView' => ['Yaf\Dispatcher'], 'Yaf\Dispatcher::flushInstantly' => ['Yaf\Dispatcher', 'flag='=>'bool'], 'Yaf\Dispatcher::getApplication' => ['Yaf\Application'], 'Yaf\Dispatcher::getInstance' => ['Yaf\Dispatcher'], 'Yaf\Dispatcher::getRequest' => ['Yaf\Request_Abstract'], 'Yaf\Dispatcher::getRouter' => ['Yaf\Router'], 'Yaf\Dispatcher::initView' => ['Yaf\View_Interface', 'templates_dir'=>'string', 'options='=>'?array'], 'Yaf\Dispatcher::registerPlugin' => ['Yaf\Dispatcher', 'plugin'=>'Yaf\Plugin_Abstract'], 'Yaf\Dispatcher::returnResponse' => ['Yaf\Dispatcher', 'flag'=>'bool'], 'Yaf\Dispatcher::setDefaultAction' => ['Yaf\Dispatcher', 'action'=>'string'], 'Yaf\Dispatcher::setDefaultController' => ['Yaf\Dispatcher', 'controller'=>'string'], 'Yaf\Dispatcher::setDefaultModule' => ['Yaf\Dispatcher', 'module'=>'string'], 'Yaf\Dispatcher::setErrorHandler' => ['Yaf\Dispatcher', 'callback'=>'callable', 'error_types'=>'int'], 'Yaf\Dispatcher::setRequest' => ['Yaf\Dispatcher', 'request'=>'Yaf\Request_Abstract'], 'Yaf\Dispatcher::setView' => ['Yaf\Dispatcher', 'view'=>'Yaf\View_Interface'], 'Yaf\Dispatcher::throwException' => ['Yaf\Dispatcher', 'flag='=>'bool'], 'Yaf\Loader::__clone' => ['void'], 'Yaf\Loader::__construct' => ['void'], 'Yaf\Loader::__sleep' => ['list'], 'Yaf\Loader::__wakeup' => ['void'], 'Yaf\Loader::autoload' => ['bool', 'class_name'=>'string'], 'Yaf\Loader::clearLocalNamespace' => [''], 'Yaf\Loader::getInstance' => ['Yaf\Loader', 'local_library_path='=>'string', 'global_library_path='=>'string'], 'Yaf\Loader::getLibraryPath' => ['string', 'is_global='=>'bool'], 'Yaf\Loader::getLocalNamespace' => ['string'], 'Yaf\Loader::import' => ['bool', 'file'=>'string'], 'Yaf\Loader::isLocalName' => ['bool', 'class_name'=>'string'], 'Yaf\Loader::registerLocalNamespace' => ['bool', 'name_prefix'=>'string|string[]'], 'Yaf\Loader::setLibraryPath' => ['Yaf\Loader', 'directory'=>'string', 'global='=>'bool'], 'Yaf\Plugin_Abstract::dispatchLoopShutdown' => ['bool', 'request'=>'Yaf\Request_Abstract', 'response'=>'Yaf\Response_Abstract'], 'Yaf\Plugin_Abstract::dispatchLoopStartup' => ['bool', 'request'=>'Yaf\Request_Abstract', 'response'=>'Yaf\Response_Abstract'], 'Yaf\Plugin_Abstract::postDispatch' => ['bool', 'request'=>'Yaf\Request_Abstract', 'response'=>'Yaf\Response_Abstract'], 'Yaf\Plugin_Abstract::preDispatch' => ['bool', 'request'=>'Yaf\Request_Abstract', 'response'=>'Yaf\Response_Abstract'], 'Yaf\Plugin_Abstract::preResponse' => ['bool', 'request'=>'Yaf\Request_Abstract', 'response'=>'Yaf\Response_Abstract'], 'Yaf\Plugin_Abstract::routerShutdown' => ['bool', 'request'=>'Yaf\Request_Abstract', 'response'=>'Yaf\Response_Abstract'], 'Yaf\Plugin_Abstract::routerStartup' => ['bool', 'request'=>'Yaf\Request_Abstract', 'response'=>'Yaf\Response_Abstract'], 'Yaf\Registry::__clone' => ['void'], 'Yaf\Registry::__construct' => ['void'], 'Yaf\Registry::del' => ['bool|void', 'name'=>'string'], 'Yaf\Registry::get' => ['mixed', 'name'=>'string'], 'Yaf\Registry::has' => ['bool', 'name'=>'string'], 'Yaf\Registry::set' => ['bool', 'name'=>'string', 'value'=>'mixed'], 'Yaf\Request\Http::__clone' => ['void'], 'Yaf\Request\Http::__construct' => ['void', 'request_uri'=>'string', 'base_uri'=>'string'], 'Yaf\Request\Http::get' => ['mixed', 'name'=>'string', 'default='=>'string'], 'Yaf\Request\Http::getActionName' => ['string'], 'Yaf\Request\Http::getBaseUri' => ['string'], 'Yaf\Request\Http::getControllerName' => ['string'], 'Yaf\Request\Http::getCookie' => ['mixed', 'name='=>'string', 'default='=>'mixed'], 'Yaf\Request\Http::getEnv' => ['mixed', 'name='=>'string', 'default='=>'mixed'], 'Yaf\Request\Http::getException' => ['Yaf\Exception'], 'Yaf\Request\Http::getFiles' => ['mixed', 'name='=>'string', 'default='=>'mixed'], 'Yaf\Request\Http::getLanguage' => ['string'], 'Yaf\Request\Http::getMethod' => ['string'], 'Yaf\Request\Http::getModuleName' => ['string'], 'Yaf\Request\Http::getParam' => ['mixed', 'name'=>'string', 'default='=>'mixed'], 'Yaf\Request\Http::getParams' => ['array'], 'Yaf\Request\Http::getPost' => ['mixed', 'name='=>'string', 'default='=>'mixed'], 'Yaf\Request\Http::getQuery' => ['mixed', 'name='=>'string', 'default='=>'mixed'], 'Yaf\Request\Http::getRequest' => ['mixed', 'name='=>'string', 'default='=>'mixed'], 'Yaf\Request\Http::getRequestUri' => ['string'], 'Yaf\Request\Http::getServer' => ['mixed', 'name='=>'string', 'default='=>'mixed'], 'Yaf\Request\Http::isCli' => ['bool'], 'Yaf\Request\Http::isDispatched' => ['bool'], 'Yaf\Request\Http::isGet' => ['bool'], 'Yaf\Request\Http::isHead' => ['bool'], 'Yaf\Request\Http::isOptions' => ['bool'], 'Yaf\Request\Http::isPost' => ['bool'], 'Yaf\Request\Http::isPut' => ['bool'], 'Yaf\Request\Http::isRouted' => ['bool'], 'Yaf\Request\Http::isXmlHttpRequest' => ['bool'], 'Yaf\Request\Http::setActionName' => ['Yaf\Request_Abstract|bool', 'action'=>'string'], 'Yaf\Request\Http::setBaseUri' => ['bool', 'uri'=>'string'], 'Yaf\Request\Http::setControllerName' => ['Yaf\Request_Abstract|bool', 'controller'=>'string'], 'Yaf\Request\Http::setDispatched' => ['bool'], 'Yaf\Request\Http::setModuleName' => ['Yaf\Request_Abstract|bool', 'module'=>'string'], 'Yaf\Request\Http::setParam' => ['Yaf\Request_Abstract|bool', 'name'=>'array|string', 'value='=>'string'], 'Yaf\Request\Http::setRequestUri' => ['', 'uri'=>'string'], 'Yaf\Request\Http::setRouted' => ['Yaf\Request_Abstract|bool'], 'Yaf\Request\Simple::__clone' => ['void'], 'Yaf\Request\Simple::__construct' => ['void', 'method'=>'string', 'controller'=>'string', 'action'=>'string', 'params='=>'string'], 'Yaf\Request\Simple::get' => ['mixed', 'name'=>'string', 'default='=>'string'], 'Yaf\Request\Simple::getActionName' => ['string'], 'Yaf\Request\Simple::getBaseUri' => ['string'], 'Yaf\Request\Simple::getControllerName' => ['string'], 'Yaf\Request\Simple::getCookie' => ['mixed', 'name='=>'string', 'default='=>'string'], 'Yaf\Request\Simple::getEnv' => ['mixed', 'name='=>'string', 'default='=>'mixed'], 'Yaf\Request\Simple::getException' => ['Yaf\Exception'], 'Yaf\Request\Simple::getFiles' => ['array', 'name='=>'mixed', 'default='=>'null'], 'Yaf\Request\Simple::getLanguage' => ['string'], 'Yaf\Request\Simple::getMethod' => ['string'], 'Yaf\Request\Simple::getModuleName' => ['string'], 'Yaf\Request\Simple::getParam' => ['mixed', 'name'=>'string', 'default='=>'mixed'], 'Yaf\Request\Simple::getParams' => ['array'], 'Yaf\Request\Simple::getPost' => ['mixed', 'name='=>'string', 'default='=>'string'], 'Yaf\Request\Simple::getQuery' => ['mixed', 'name='=>'string', 'default='=>'string'], 'Yaf\Request\Simple::getRequest' => ['mixed', 'name='=>'string', 'default='=>'string'], 'Yaf\Request\Simple::getRequestUri' => ['string'], 'Yaf\Request\Simple::getServer' => ['mixed', 'name='=>'string', 'default='=>'mixed'], 'Yaf\Request\Simple::isCli' => ['bool'], 'Yaf\Request\Simple::isDispatched' => ['bool'], 'Yaf\Request\Simple::isGet' => ['bool'], 'Yaf\Request\Simple::isHead' => ['bool'], 'Yaf\Request\Simple::isOptions' => ['bool'], 'Yaf\Request\Simple::isPost' => ['bool'], 'Yaf\Request\Simple::isPut' => ['bool'], 'Yaf\Request\Simple::isRouted' => ['bool'], 'Yaf\Request\Simple::isXmlHttpRequest' => ['bool'], 'Yaf\Request\Simple::setActionName' => ['Yaf\Request_Abstract|bool', 'action'=>'string'], 'Yaf\Request\Simple::setBaseUri' => ['bool', 'uri'=>'string'], 'Yaf\Request\Simple::setControllerName' => ['Yaf\Request_Abstract|bool', 'controller'=>'string'], 'Yaf\Request\Simple::setDispatched' => ['bool'], 'Yaf\Request\Simple::setModuleName' => ['Yaf\Request_Abstract|bool', 'module'=>'string'], 'Yaf\Request\Simple::setParam' => ['Yaf\Request_Abstract|bool', 'name'=>'array|string', 'value='=>'string'], 'Yaf\Request\Simple::setRequestUri' => ['', 'uri'=>'string'], 'Yaf\Request\Simple::setRouted' => ['Yaf\Request_Abstract|bool'], 'Yaf\Request_Abstract::getActionName' => ['string'], 'Yaf\Request_Abstract::getBaseUri' => ['string'], 'Yaf\Request_Abstract::getControllerName' => ['string'], 'Yaf\Request_Abstract::getEnv' => ['mixed', 'name='=>'string', 'default='=>'mixed'], 'Yaf\Request_Abstract::getException' => ['Yaf\Exception'], 'Yaf\Request_Abstract::getLanguage' => ['string'], 'Yaf\Request_Abstract::getMethod' => ['string'], 'Yaf\Request_Abstract::getModuleName' => ['string'], 'Yaf\Request_Abstract::getParam' => ['mixed', 'name'=>'string', 'default='=>'mixed'], 'Yaf\Request_Abstract::getParams' => ['array'], 'Yaf\Request_Abstract::getRequestUri' => ['string'], 'Yaf\Request_Abstract::getServer' => ['mixed', 'name='=>'string', 'default='=>'mixed'], 'Yaf\Request_Abstract::isCli' => ['bool'], 'Yaf\Request_Abstract::isDispatched' => ['bool'], 'Yaf\Request_Abstract::isGet' => ['bool'], 'Yaf\Request_Abstract::isHead' => ['bool'], 'Yaf\Request_Abstract::isOptions' => ['bool'], 'Yaf\Request_Abstract::isPost' => ['bool'], 'Yaf\Request_Abstract::isPut' => ['bool'], 'Yaf\Request_Abstract::isRouted' => ['bool'], 'Yaf\Request_Abstract::isXmlHttpRequest' => ['bool'], 'Yaf\Request_Abstract::setActionName' => ['Yaf\Request_Abstract|bool', 'action'=>'string'], 'Yaf\Request_Abstract::setBaseUri' => ['bool', 'uri'=>'string'], 'Yaf\Request_Abstract::setControllerName' => ['Yaf\Request_Abstract|bool', 'controller'=>'string'], 'Yaf\Request_Abstract::setDispatched' => ['bool'], 'Yaf\Request_Abstract::setModuleName' => ['Yaf\Request_Abstract|bool', 'module'=>'string'], 'Yaf\Request_Abstract::setParam' => ['Yaf\Request_Abstract|bool', 'name'=>'array|string', 'value='=>'string'], 'Yaf\Request_Abstract::setRequestUri' => ['', 'uri'=>'string'], 'Yaf\Request_Abstract::setRouted' => ['Yaf\Request_Abstract|bool'], 'Yaf\Response\Cli::__clone' => ['void'], 'Yaf\Response\Cli::__construct' => ['void'], 'Yaf\Response\Cli::__destruct' => ['void'], 'Yaf\Response\Cli::__toString' => ['string'], 'Yaf\Response\Cli::appendBody' => ['bool', 'content'=>'string', 'key='=>'string'], 'Yaf\Response\Cli::clearBody' => ['bool', 'key='=>'string'], 'Yaf\Response\Cli::getBody' => ['mixed', 'key='=>'?string'], 'Yaf\Response\Cli::prependBody' => ['bool', 'content'=>'string', 'key='=>'string'], 'Yaf\Response\Cli::setBody' => ['bool', 'content'=>'string', 'key='=>'string'], 'Yaf\Response\Http::__clone' => ['void'], 'Yaf\Response\Http::__construct' => ['void'], 'Yaf\Response\Http::__destruct' => ['void'], 'Yaf\Response\Http::__toString' => ['string'], 'Yaf\Response\Http::appendBody' => ['bool', 'content'=>'string', 'key='=>'string'], 'Yaf\Response\Http::clearBody' => ['bool', 'key='=>'string'], 'Yaf\Response\Http::clearHeaders' => ['Yaf\Response_Abstract|false', 'name='=>'string'], 'Yaf\Response\Http::getBody' => ['mixed', 'key='=>'?string'], 'Yaf\Response\Http::getHeader' => ['mixed', 'name='=>'string'], 'Yaf\Response\Http::prependBody' => ['bool', 'content'=>'string', 'key='=>'string'], 'Yaf\Response\Http::response' => ['bool'], 'Yaf\Response\Http::setAllHeaders' => ['bool', 'headers'=>'array'], 'Yaf\Response\Http::setBody' => ['bool', 'content'=>'string', 'key='=>'string'], 'Yaf\Response\Http::setHeader' => ['bool', 'name'=>'string', 'value'=>'string', 'replace='=>'bool', 'response_code='=>'int'], 'Yaf\Response\Http::setRedirect' => ['bool', 'url'=>'string'], 'Yaf\Response_Abstract::__clone' => ['void'], 'Yaf\Response_Abstract::__construct' => ['void'], 'Yaf\Response_Abstract::__destruct' => ['void'], 'Yaf\Response_Abstract::__toString' => ['void'], 'Yaf\Response_Abstract::appendBody' => ['bool', 'content'=>'string', 'key='=>'string'], 'Yaf\Response_Abstract::clearBody' => ['bool', 'key='=>'string'], 'Yaf\Response_Abstract::getBody' => ['mixed', 'key='=>'?string'], 'Yaf\Response_Abstract::prependBody' => ['bool', 'content'=>'string', 'key='=>'string'], 'Yaf\Response_Abstract::setBody' => ['bool', 'content'=>'string', 'key='=>'string'], 'Yaf\Route\Map::__construct' => ['void', 'controller_prefer='=>'bool', 'delimiter='=>'string'], 'Yaf\Route\Map::assemble' => ['bool', 'info'=>'array', 'query='=>'?array'], 'Yaf\Route\Map::route' => ['bool', 'request'=>'Yaf\Request_Abstract'], 'Yaf\Route\Regex::__construct' => ['void', 'match'=>'string', 'route'=>'array', 'map='=>'?array', 'verify='=>'?array', 'reverse='=>'string'], 'Yaf\Route\Regex::addConfig' => ['Yaf\Router|bool', 'config'=>'Yaf\Config_Abstract'], 'Yaf\Route\Regex::addRoute' => ['Yaf\Router|bool', 'name'=>'string', 'route'=>'Yaf\Route_Interface'], 'Yaf\Route\Regex::assemble' => ['bool', 'info'=>'array', 'query='=>'?array'], 'Yaf\Route\Regex::getCurrentRoute' => ['string'], 'Yaf\Route\Regex::getRoute' => ['Yaf\Route_Interface', 'name'=>'string'], 'Yaf\Route\Regex::getRoutes' => ['Yaf\Route_Interface[]'], 'Yaf\Route\Regex::route' => ['bool', 'request'=>'Yaf\Request_Abstract'], 'Yaf\Route\Rewrite::__construct' => ['void', 'match'=>'string', 'route'=>'array', 'verify='=>'?array', 'reverse='=>'string'], 'Yaf\Route\Rewrite::addConfig' => ['Yaf\Router|bool', 'config'=>'Yaf\Config_Abstract'], 'Yaf\Route\Rewrite::addRoute' => ['Yaf\Router|bool', 'name'=>'string', 'route'=>'Yaf\Route_Interface'], 'Yaf\Route\Rewrite::assemble' => ['bool', 'info'=>'array', 'query='=>'?array'], 'Yaf\Route\Rewrite::getCurrentRoute' => ['string'], 'Yaf\Route\Rewrite::getRoute' => ['Yaf\Route_Interface', 'name'=>'string'], 'Yaf\Route\Rewrite::getRoutes' => ['Yaf\Route_Interface[]'], 'Yaf\Route\Rewrite::route' => ['bool', 'request'=>'Yaf\Request_Abstract'], 'Yaf\Route\Simple::__construct' => ['void', 'module_name'=>'string', 'controller_name'=>'string', 'action_name'=>'string'], 'Yaf\Route\Simple::assemble' => ['bool', 'info'=>'array', 'query='=>'?array'], 'Yaf\Route\Simple::route' => ['bool', 'request'=>'Yaf\Request_Abstract'], 'Yaf\Route\Supervar::__construct' => ['void', 'supervar_name'=>'string'], 'Yaf\Route\Supervar::assemble' => ['bool', 'info'=>'array', 'query='=>'?array'], 'Yaf\Route\Supervar::route' => ['bool', 'request'=>'Yaf\Request_Abstract'], 'Yaf\Route_Interface::__construct' => ['Yaf\Route_Interface'], 'Yaf\Route_Interface::assemble' => ['bool', 'info'=>'array', 'query='=>'?array'], 'Yaf\Route_Interface::route' => ['bool', 'request'=>'Yaf\Request_Abstract'], 'Yaf\Route_Static::assemble' => ['bool', 'info'=>'array', 'query='=>'?array'], 'Yaf\Route_Static::match' => ['bool', 'uri'=>'string'], 'Yaf\Route_Static::route' => ['bool', 'request'=>'Yaf\Request_Abstract'], 'Yaf\Router::__construct' => ['void'], 'Yaf\Router::addConfig' => ['Yaf\Router|false', 'config'=>'Yaf\Config_Abstract'], 'Yaf\Router::addRoute' => ['Yaf\Router|false', 'name'=>'string', 'route'=>'Yaf\Route_Interface'], 'Yaf\Router::getCurrentRoute' => ['string'], 'Yaf\Router::getRoute' => ['Yaf\Route_Interface', 'name'=>'string'], 'Yaf\Router::getRoutes' => ['Yaf\Route_Interface[]'], 'Yaf\Router::route' => ['Yaf\Router|false', 'request'=>'Yaf\Request_Abstract'], 'Yaf\Session::__clone' => ['void'], 'Yaf\Session::__construct' => ['void'], 'Yaf\Session::__get' => ['void', 'name'=>''], 'Yaf\Session::__isset' => ['void', 'name'=>''], 'Yaf\Session::__set' => ['void', 'name'=>'', 'value'=>''], 'Yaf\Session::__sleep' => ['list'], 'Yaf\Session::__unset' => ['void', 'name'=>''], 'Yaf\Session::__wakeup' => ['void'], 'Yaf\Session::count' => ['int'], 'Yaf\Session::current' => ['mixed'], 'Yaf\Session::del' => ['Yaf\Session|false', 'name'=>'string'], 'Yaf\Session::get' => ['mixed', 'name'=>'string'], 'Yaf\Session::getInstance' => ['Yaf\Session'], 'Yaf\Session::has' => ['bool', 'name'=>'string'], 'Yaf\Session::key' => ['int|string'], 'Yaf\Session::next' => ['void'], 'Yaf\Session::offsetExists' => ['bool', 'name'=>'int|string'], 'Yaf\Session::offsetGet' => ['mixed', 'name'=>'int|string'], 'Yaf\Session::offsetSet' => ['void', 'name'=>'int|string|null', 'value'=>'mixed'], 'Yaf\Session::offsetUnset' => ['void', 'name'=>'int|string'], 'Yaf\Session::rewind' => ['void'], 'Yaf\Session::set' => ['Yaf\Session|false', 'name'=>'string', 'value'=>'mixed'], 'Yaf\Session::start' => ['Yaf\Session'], 'Yaf\Session::valid' => ['bool'], 'Yaf\View\Simple::__construct' => ['void', 'template_dir'=>'string', 'options='=>'?array'], 'Yaf\View\Simple::__get' => ['mixed', 'name='=>'null'], 'Yaf\View\Simple::__isset' => ['', 'name'=>'string'], 'Yaf\View\Simple::__set' => ['void', 'name'=>'string', 'value='=>'mixed'], 'Yaf\View\Simple::assign' => ['Yaf\View\Simple', 'name'=>'array|string', 'value='=>'mixed'], 'Yaf\View\Simple::assignRef' => ['Yaf\View\Simple', 'name'=>'string', '&value'=>'mixed'], 'Yaf\View\Simple::clear' => ['Yaf\View\Simple', 'name='=>'string'], 'Yaf\View\Simple::display' => ['bool', 'tpl'=>'string', 'tpl_vars='=>'?array'], 'Yaf\View\Simple::eval' => ['bool|void', 'tpl_str'=>'string', 'vars='=>'?array'], 'Yaf\View\Simple::getScriptPath' => ['string'], 'Yaf\View\Simple::render' => ['string|void', 'tpl'=>'string', 'tpl_vars='=>'?array'], 'Yaf\View\Simple::setScriptPath' => ['Yaf\View\Simple', 'template_dir'=>'string'], 'Yaf\View_Interface::assign' => ['bool', 'name'=>'array|string', 'value'=>'mixed'], 'Yaf\View_Interface::display' => ['bool', 'tpl'=>'string', 'tpl_vars='=>'?array'], 'Yaf\View_Interface::getScriptPath' => ['string'], 'Yaf\View_Interface::render' => ['string', 'tpl'=>'string', 'tpl_vars='=>'?array'], 'Yaf\View_Interface::setScriptPath' => ['void', 'template_dir'=>'string'], 'Yaf_Action_Abstract::__clone' => ['void'], 'Yaf_Action_Abstract::__construct' => ['void', 'request'=>'Yaf_Request_Abstract', 'response'=>'Yaf_Response_Abstract', 'view'=>'Yaf_View_Interface', 'invokeArgs='=>'?array'], 'Yaf_Action_Abstract::display' => ['bool', 'tpl'=>'string', 'parameters='=>'?array'], 'Yaf_Action_Abstract::execute' => ['mixed', 'arg='=>'mixed', '...args='=>'mixed'], 'Yaf_Action_Abstract::forward' => ['bool', 'module'=>'string', 'controller='=>'string', 'action='=>'string', 'parameters='=>'?array'], 'Yaf_Action_Abstract::getController' => ['Yaf_Controller_Abstract'], 'Yaf_Action_Abstract::getControllerName' => ['string'], 'Yaf_Action_Abstract::getInvokeArg' => ['mixed|null', 'name'=>'string'], 'Yaf_Action_Abstract::getInvokeArgs' => ['array'], 'Yaf_Action_Abstract::getModuleName' => ['string'], 'Yaf_Action_Abstract::getRequest' => ['Yaf_Request_Abstract'], 'Yaf_Action_Abstract::getResponse' => ['Yaf_Response_Abstract'], 'Yaf_Action_Abstract::getView' => ['Yaf_View_Interface'], 'Yaf_Action_Abstract::getViewpath' => ['string'], 'Yaf_Action_Abstract::init' => [''], 'Yaf_Action_Abstract::initView' => ['Yaf_Response_Abstract', 'options='=>'?array'], 'Yaf_Action_Abstract::redirect' => ['bool', 'url'=>'string'], 'Yaf_Action_Abstract::render' => ['string', 'tpl'=>'string', 'parameters='=>'?array'], 'Yaf_Action_Abstract::setViewpath' => ['bool', 'view_directory'=>'string'], 'Yaf_Application::__clone' => ['void'], 'Yaf_Application::__construct' => ['void', 'config'=>'mixed', 'envrion='=>'string'], 'Yaf_Application::__destruct' => ['void'], 'Yaf_Application::__sleep' => ['list'], 'Yaf_Application::__wakeup' => ['void'], 'Yaf_Application::app' => ['?Yaf_Application'], 'Yaf_Application::bootstrap' => ['Yaf_Application', 'bootstrap='=>'Yaf_Bootstrap_Abstract'], 'Yaf_Application::clearLastError' => ['Yaf_Application'], 'Yaf_Application::environ' => ['string'], 'Yaf_Application::execute' => ['void', 'entry'=>'callable', '...args'=>'string'], 'Yaf_Application::getAppDirectory' => ['Yaf_Application'], 'Yaf_Application::getConfig' => ['Yaf_Config_Abstract'], 'Yaf_Application::getDispatcher' => ['Yaf_Dispatcher'], 'Yaf_Application::getLastErrorMsg' => ['string'], 'Yaf_Application::getLastErrorNo' => ['int'], 'Yaf_Application::getModules' => ['array'], 'Yaf_Application::run' => ['void'], 'Yaf_Application::setAppDirectory' => ['Yaf_Application', 'directory'=>'string'], 'Yaf_Config_Abstract::__construct' => ['void'], 'Yaf_Config_Abstract::get' => ['mixed', 'name'=>'string', 'value'=>'mixed'], 'Yaf_Config_Abstract::readonly' => ['bool'], 'Yaf_Config_Abstract::set' => ['Yaf_Config_Abstract'], 'Yaf_Config_Abstract::toArray' => ['array'], 'Yaf_Config_Ini::__construct' => ['void', 'config_file'=>'string', 'section='=>'string'], 'Yaf_Config_Ini::__get' => ['void', 'name='=>'string'], 'Yaf_Config_Ini::__isset' => ['void', 'name'=>'string'], 'Yaf_Config_Ini::__set' => ['void', 'name'=>'string', 'value'=>'mixed'], 'Yaf_Config_Ini::count' => ['void'], 'Yaf_Config_Ini::current' => ['void'], 'Yaf_Config_Ini::get' => ['mixed', 'name='=>'mixed'], 'Yaf_Config_Ini::key' => ['void'], 'Yaf_Config_Ini::next' => ['void'], 'Yaf_Config_Ini::offsetExists' => ['void', 'name'=>'string'], 'Yaf_Config_Ini::offsetGet' => ['void', 'name'=>'string'], 'Yaf_Config_Ini::offsetSet' => ['void', 'name'=>'string', 'value'=>'string'], 'Yaf_Config_Ini::offsetUnset' => ['void', 'name'=>'string'], 'Yaf_Config_Ini::readonly' => ['void'], 'Yaf_Config_Ini::rewind' => ['void'], 'Yaf_Config_Ini::set' => ['Yaf_Config_Abstract', 'name'=>'string', 'value'=>'mixed'], 'Yaf_Config_Ini::toArray' => ['array'], 'Yaf_Config_Ini::valid' => ['void'], 'Yaf_Config_Simple::__construct' => ['void', 'config_file'=>'string', 'section='=>'string'], 'Yaf_Config_Simple::__get' => ['void', 'name='=>'string'], 'Yaf_Config_Simple::__isset' => ['void', 'name'=>'string'], 'Yaf_Config_Simple::__set' => ['void', 'name'=>'string', 'value'=>'string'], 'Yaf_Config_Simple::count' => ['void'], 'Yaf_Config_Simple::current' => ['void'], 'Yaf_Config_Simple::get' => ['mixed', 'name='=>'mixed'], 'Yaf_Config_Simple::key' => ['void'], 'Yaf_Config_Simple::next' => ['void'], 'Yaf_Config_Simple::offsetExists' => ['void', 'name'=>'string'], 'Yaf_Config_Simple::offsetGet' => ['void', 'name'=>'string'], 'Yaf_Config_Simple::offsetSet' => ['void', 'name'=>'string', 'value'=>'string'], 'Yaf_Config_Simple::offsetUnset' => ['void', 'name'=>'string'], 'Yaf_Config_Simple::readonly' => ['void'], 'Yaf_Config_Simple::rewind' => ['void'], 'Yaf_Config_Simple::set' => ['Yaf_Config_Abstract', 'name'=>'string', 'value'=>'mixed'], 'Yaf_Config_Simple::toArray' => ['array'], 'Yaf_Config_Simple::valid' => ['void'], 'Yaf_Controller_Abstract::__clone' => ['void'], 'Yaf_Controller_Abstract::__construct' => ['void'], 'Yaf_Controller_Abstract::display' => ['bool', 'tpl'=>'string', 'parameters='=>'array'], 'Yaf_Controller_Abstract::forward' => ['void', 'action'=>'string', 'parameters='=>'array'], 'Yaf_Controller_Abstract::forward\'1' => ['void', 'controller'=>'string', 'action'=>'string', 'parameters='=>'array'], 'Yaf_Controller_Abstract::forward\'2' => ['void', 'module'=>'string', 'controller'=>'string', 'action'=>'string', 'parameters='=>'array'], 'Yaf_Controller_Abstract::getInvokeArg' => ['void', 'name'=>'string'], 'Yaf_Controller_Abstract::getInvokeArgs' => ['void'], 'Yaf_Controller_Abstract::getModuleName' => ['string'], 'Yaf_Controller_Abstract::getName' => ['string'], 'Yaf_Controller_Abstract::getRequest' => ['Yaf_Request_Abstract'], 'Yaf_Controller_Abstract::getResponse' => ['Yaf_Response_Abstract'], 'Yaf_Controller_Abstract::getView' => ['Yaf_View_Interface'], 'Yaf_Controller_Abstract::getViewpath' => ['void'], 'Yaf_Controller_Abstract::init' => ['void'], 'Yaf_Controller_Abstract::initView' => ['void', 'options='=>'array'], 'Yaf_Controller_Abstract::redirect' => ['bool', 'url'=>'string'], 'Yaf_Controller_Abstract::render' => ['string', 'tpl'=>'string', 'parameters='=>'array'], 'Yaf_Controller_Abstract::setViewpath' => ['void', 'view_directory'=>'string'], 'Yaf_Dispatcher::__clone' => ['void'], 'Yaf_Dispatcher::__construct' => ['void'], 'Yaf_Dispatcher::__sleep' => ['list'], 'Yaf_Dispatcher::__wakeup' => ['void'], 'Yaf_Dispatcher::autoRender' => ['Yaf_Dispatcher', 'flag='=>'bool'], 'Yaf_Dispatcher::catchException' => ['Yaf_Dispatcher', 'flag='=>'bool'], 'Yaf_Dispatcher::disableView' => ['bool'], 'Yaf_Dispatcher::dispatch' => ['Yaf_Response_Abstract', 'request'=>'Yaf_Request_Abstract'], 'Yaf_Dispatcher::enableView' => ['Yaf_Dispatcher'], 'Yaf_Dispatcher::flushInstantly' => ['Yaf_Dispatcher', 'flag='=>'bool'], 'Yaf_Dispatcher::getApplication' => ['Yaf_Application'], 'Yaf_Dispatcher::getDefaultAction' => ['string'], 'Yaf_Dispatcher::getDefaultController' => ['string'], 'Yaf_Dispatcher::getDefaultModule' => ['string'], 'Yaf_Dispatcher::getInstance' => ['Yaf_Dispatcher'], 'Yaf_Dispatcher::getRequest' => ['Yaf_Request_Abstract'], 'Yaf_Dispatcher::getRouter' => ['Yaf_Router'], 'Yaf_Dispatcher::initView' => ['Yaf_View_Interface', 'templates_dir'=>'string', 'options='=>'array'], 'Yaf_Dispatcher::registerPlugin' => ['Yaf_Dispatcher', 'plugin'=>'Yaf_Plugin_Abstract'], 'Yaf_Dispatcher::returnResponse' => ['Yaf_Dispatcher', 'flag'=>'bool'], 'Yaf_Dispatcher::setDefaultAction' => ['Yaf_Dispatcher', 'action'=>'string'], 'Yaf_Dispatcher::setDefaultController' => ['Yaf_Dispatcher', 'controller'=>'string'], 'Yaf_Dispatcher::setDefaultModule' => ['Yaf_Dispatcher', 'module'=>'string'], 'Yaf_Dispatcher::setErrorHandler' => ['Yaf_Dispatcher', 'callback'=>'callable', 'error_types'=>'int'], 'Yaf_Dispatcher::setRequest' => ['Yaf_Dispatcher', 'request'=>'Yaf_Request_Abstract'], 'Yaf_Dispatcher::setView' => ['Yaf_Dispatcher', 'view'=>'Yaf_View_Interface'], 'Yaf_Dispatcher::throwException' => ['Yaf_Dispatcher', 'flag='=>'bool'], 'Yaf_Exception::__construct' => ['void'], 'Yaf_Exception::getPrevious' => ['void'], 'Yaf_Loader::__clone' => ['void'], 'Yaf_Loader::__construct' => ['void'], 'Yaf_Loader::__sleep' => ['list'], 'Yaf_Loader::__wakeup' => ['void'], 'Yaf_Loader::autoload' => ['void'], 'Yaf_Loader::clearLocalNamespace' => ['void'], 'Yaf_Loader::getInstance' => ['Yaf_Loader'], 'Yaf_Loader::getLibraryPath' => ['Yaf_Loader', 'is_global='=>'bool'], 'Yaf_Loader::getLocalNamespace' => ['void'], 'Yaf_Loader::getNamespacePath' => ['string', 'namespaces'=>'string'], 'Yaf_Loader::import' => ['bool'], 'Yaf_Loader::isLocalName' => ['bool'], 'Yaf_Loader::registerLocalNamespace' => ['void', 'prefix'=>'mixed'], 'Yaf_Loader::registerNamespace' => ['bool', 'namespaces'=>'string|array', 'path='=>'string'], 'Yaf_Loader::setLibraryPath' => ['Yaf_Loader', 'directory'=>'string', 'is_global='=>'bool'], 'Yaf_Plugin_Abstract::dispatchLoopShutdown' => ['void', 'request'=>'Yaf_Request_Abstract', 'response'=>'Yaf_Response_Abstract'], 'Yaf_Plugin_Abstract::dispatchLoopStartup' => ['void', 'request'=>'Yaf_Request_Abstract', 'response'=>'Yaf_Response_Abstract'], 'Yaf_Plugin_Abstract::postDispatch' => ['void', 'request'=>'Yaf_Request_Abstract', 'response'=>'Yaf_Response_Abstract'], 'Yaf_Plugin_Abstract::preDispatch' => ['void', 'request'=>'Yaf_Request_Abstract', 'response'=>'Yaf_Response_Abstract'], 'Yaf_Plugin_Abstract::preResponse' => ['void', 'request'=>'Yaf_Request_Abstract', 'response'=>'Yaf_Response_Abstract'], 'Yaf_Plugin_Abstract::routerShutdown' => ['void', 'request'=>'Yaf_Request_Abstract', 'response'=>'Yaf_Response_Abstract'], 'Yaf_Plugin_Abstract::routerStartup' => ['void', 'request'=>'Yaf_Request_Abstract', 'response'=>'Yaf_Response_Abstract'], 'Yaf_Registry::__clone' => ['void'], 'Yaf_Registry::__construct' => ['void'], 'Yaf_Registry::del' => ['void', 'name'=>'string'], 'Yaf_Registry::get' => ['mixed', 'name'=>'string'], 'Yaf_Registry::has' => ['bool', 'name'=>'string'], 'Yaf_Registry::set' => ['bool', 'name'=>'string', 'value'=>'string'], 'Yaf_Request_Abstract::clearParams' => ['bool'], 'Yaf_Request_Abstract::getActionName' => ['void'], 'Yaf_Request_Abstract::getBaseUri' => ['void'], 'Yaf_Request_Abstract::getControllerName' => ['void'], 'Yaf_Request_Abstract::getEnv' => ['void', 'name'=>'string', 'default='=>'string'], 'Yaf_Request_Abstract::getException' => ['void'], 'Yaf_Request_Abstract::getLanguage' => ['void'], 'Yaf_Request_Abstract::getMethod' => ['void'], 'Yaf_Request_Abstract::getModuleName' => ['void'], 'Yaf_Request_Abstract::getParam' => ['void', 'name'=>'string', 'default='=>'string'], 'Yaf_Request_Abstract::getParams' => ['void'], 'Yaf_Request_Abstract::getRequestUri' => ['void'], 'Yaf_Request_Abstract::getServer' => ['void', 'name'=>'string', 'default='=>'string'], 'Yaf_Request_Abstract::isCli' => ['void'], 'Yaf_Request_Abstract::isDispatched' => ['void'], 'Yaf_Request_Abstract::isGet' => ['void'], 'Yaf_Request_Abstract::isHead' => ['void'], 'Yaf_Request_Abstract::isOptions' => ['void'], 'Yaf_Request_Abstract::isPost' => ['void'], 'Yaf_Request_Abstract::isPut' => ['void'], 'Yaf_Request_Abstract::isRouted' => ['void'], 'Yaf_Request_Abstract::isXmlHttpRequest' => ['void'], 'Yaf_Request_Abstract::setActionName' => ['void', 'action'=>'string'], 'Yaf_Request_Abstract::setBaseUri' => ['bool', 'uir'=>'string'], 'Yaf_Request_Abstract::setControllerName' => ['void', 'controller'=>'string'], 'Yaf_Request_Abstract::setDispatched' => ['void'], 'Yaf_Request_Abstract::setModuleName' => ['void', 'module'=>'string'], 'Yaf_Request_Abstract::setParam' => ['void', 'name'=>'string', 'value='=>'string'], 'Yaf_Request_Abstract::setRequestUri' => ['void', 'uir'=>'string'], 'Yaf_Request_Abstract::setRouted' => ['void', 'flag='=>'string'], 'Yaf_Request_Http::__clone' => ['void'], 'Yaf_Request_Http::__construct' => ['void'], 'Yaf_Request_Http::get' => ['mixed', 'name'=>'string', 'default='=>'string'], 'Yaf_Request_Http::getActionName' => ['string'], 'Yaf_Request_Http::getBaseUri' => ['string'], 'Yaf_Request_Http::getControllerName' => ['string'], 'Yaf_Request_Http::getCookie' => ['mixed', 'name'=>'string', 'default='=>'string'], 'Yaf_Request_Http::getEnv' => ['mixed', 'name='=>'string', 'default='=>'mixed'], 'Yaf_Request_Http::getException' => ['Yaf_Exception'], 'Yaf_Request_Http::getFiles' => ['void'], 'Yaf_Request_Http::getLanguage' => ['string'], 'Yaf_Request_Http::getMethod' => ['string'], 'Yaf_Request_Http::getModuleName' => ['string'], 'Yaf_Request_Http::getParam' => ['mixed', 'name'=>'string', 'default='=>'mixed'], 'Yaf_Request_Http::getParams' => ['array'], 'Yaf_Request_Http::getPost' => ['mixed', 'name'=>'string', 'default='=>'string'], 'Yaf_Request_Http::getQuery' => ['mixed', 'name'=>'string', 'default='=>'string'], 'Yaf_Request_Http::getRaw' => ['mixed'], 'Yaf_Request_Http::getRequest' => ['void'], 'Yaf_Request_Http::getRequestUri' => ['string'], 'Yaf_Request_Http::getServer' => ['mixed', 'name='=>'string', 'default='=>'mixed'], 'Yaf_Request_Http::isCli' => ['bool'], 'Yaf_Request_Http::isDispatched' => ['bool'], 'Yaf_Request_Http::isGet' => ['bool'], 'Yaf_Request_Http::isHead' => ['bool'], 'Yaf_Request_Http::isOptions' => ['bool'], 'Yaf_Request_Http::isPost' => ['bool'], 'Yaf_Request_Http::isPut' => ['bool'], 'Yaf_Request_Http::isRouted' => ['bool'], 'Yaf_Request_Http::isXmlHttpRequest' => ['bool'], 'Yaf_Request_Http::setActionName' => ['Yaf_Request_Abstract|bool', 'action'=>'string'], 'Yaf_Request_Http::setBaseUri' => ['bool', 'uri'=>'string'], 'Yaf_Request_Http::setControllerName' => ['Yaf_Request_Abstract|bool', 'controller'=>'string'], 'Yaf_Request_Http::setDispatched' => ['bool'], 'Yaf_Request_Http::setModuleName' => ['Yaf_Request_Abstract|bool', 'module'=>'string'], 'Yaf_Request_Http::setParam' => ['Yaf_Request_Abstract|bool', 'name'=>'array|string', 'value='=>'string'], 'Yaf_Request_Http::setRequestUri' => ['', 'uri'=>'string'], 'Yaf_Request_Http::setRouted' => ['Yaf_Request_Abstract|bool'], 'Yaf_Request_Simple::__clone' => ['void'], 'Yaf_Request_Simple::__construct' => ['void'], 'Yaf_Request_Simple::get' => ['void'], 'Yaf_Request_Simple::getActionName' => ['string'], 'Yaf_Request_Simple::getBaseUri' => ['string'], 'Yaf_Request_Simple::getControllerName' => ['string'], 'Yaf_Request_Simple::getCookie' => ['void'], 'Yaf_Request_Simple::getEnv' => ['mixed', 'name='=>'string', 'default='=>'mixed'], 'Yaf_Request_Simple::getException' => ['Yaf_Exception'], 'Yaf_Request_Simple::getFiles' => ['void'], 'Yaf_Request_Simple::getLanguage' => ['string'], 'Yaf_Request_Simple::getMethod' => ['string'], 'Yaf_Request_Simple::getModuleName' => ['string'], 'Yaf_Request_Simple::getParam' => ['mixed', 'name'=>'string', 'default='=>'mixed'], 'Yaf_Request_Simple::getParams' => ['array'], 'Yaf_Request_Simple::getPost' => ['void'], 'Yaf_Request_Simple::getQuery' => ['void'], 'Yaf_Request_Simple::getRequest' => ['void'], 'Yaf_Request_Simple::getRequestUri' => ['string'], 'Yaf_Request_Simple::getServer' => ['mixed', 'name='=>'string', 'default='=>'mixed'], 'Yaf_Request_Simple::isCli' => ['bool'], 'Yaf_Request_Simple::isDispatched' => ['bool'], 'Yaf_Request_Simple::isGet' => ['bool'], 'Yaf_Request_Simple::isHead' => ['bool'], 'Yaf_Request_Simple::isOptions' => ['bool'], 'Yaf_Request_Simple::isPost' => ['bool'], 'Yaf_Request_Simple::isPut' => ['bool'], 'Yaf_Request_Simple::isRouted' => ['bool'], 'Yaf_Request_Simple::isXmlHttpRequest' => ['void'], 'Yaf_Request_Simple::setActionName' => ['Yaf_Request_Abstract|bool', 'action'=>'string'], 'Yaf_Request_Simple::setBaseUri' => ['bool', 'uri'=>'string'], 'Yaf_Request_Simple::setControllerName' => ['Yaf_Request_Abstract|bool', 'controller'=>'string'], 'Yaf_Request_Simple::setDispatched' => ['bool'], 'Yaf_Request_Simple::setModuleName' => ['Yaf_Request_Abstract|bool', 'module'=>'string'], 'Yaf_Request_Simple::setParam' => ['Yaf_Request_Abstract|bool', 'name'=>'array|string', 'value='=>'string'], 'Yaf_Request_Simple::setRequestUri' => ['', 'uri'=>'string'], 'Yaf_Request_Simple::setRouted' => ['Yaf_Request_Abstract|bool'], 'Yaf_Response_Abstract::__clone' => ['void'], 'Yaf_Response_Abstract::__construct' => ['void'], 'Yaf_Response_Abstract::__destruct' => ['void'], 'Yaf_Response_Abstract::__toString' => ['string'], 'Yaf_Response_Abstract::appendBody' => ['bool', 'content'=>'string', 'key='=>'string'], 'Yaf_Response_Abstract::clearBody' => ['bool', 'key='=>'string'], 'Yaf_Response_Abstract::clearHeaders' => ['void'], 'Yaf_Response_Abstract::getBody' => ['mixed', 'key='=>'string'], 'Yaf_Response_Abstract::getHeader' => ['void'], 'Yaf_Response_Abstract::prependBody' => ['bool', 'content'=>'string', 'key='=>'string'], 'Yaf_Response_Abstract::response' => ['void'], 'Yaf_Response_Abstract::setAllHeaders' => ['void'], 'Yaf_Response_Abstract::setBody' => ['bool', 'content'=>'string', 'key='=>'string'], 'Yaf_Response_Abstract::setHeader' => ['void'], 'Yaf_Response_Abstract::setRedirect' => ['void'], 'Yaf_Response_Cli::__clone' => ['void'], 'Yaf_Response_Cli::__construct' => ['void'], 'Yaf_Response_Cli::__destruct' => ['void'], 'Yaf_Response_Cli::__toString' => ['string'], 'Yaf_Response_Cli::appendBody' => ['bool', 'content'=>'string', 'key='=>'string'], 'Yaf_Response_Cli::clearBody' => ['bool', 'key='=>'string'], 'Yaf_Response_Cli::getBody' => ['mixed', 'key='=>'?string'], 'Yaf_Response_Cli::prependBody' => ['bool', 'content'=>'string', 'key='=>'string'], 'Yaf_Response_Cli::setBody' => ['bool', 'content'=>'string', 'key='=>'string'], 'Yaf_Response_Http::__clone' => ['void'], 'Yaf_Response_Http::__construct' => ['void'], 'Yaf_Response_Http::__destruct' => ['void'], 'Yaf_Response_Http::__toString' => ['string'], 'Yaf_Response_Http::appendBody' => ['bool', 'content'=>'string', 'key='=>'string'], 'Yaf_Response_Http::clearBody' => ['bool', 'key='=>'string'], 'Yaf_Response_Http::clearHeaders' => ['Yaf_Response_Abstract|false', 'name='=>'string'], 'Yaf_Response_Http::getBody' => ['mixed', 'key='=>'?string'], 'Yaf_Response_Http::getHeader' => ['mixed', 'name='=>'string'], 'Yaf_Response_Http::prependBody' => ['bool', 'content'=>'string', 'key='=>'string'], 'Yaf_Response_Http::response' => ['bool'], 'Yaf_Response_Http::setAllHeaders' => ['bool', 'headers'=>'array'], 'Yaf_Response_Http::setBody' => ['bool', 'content'=>'string', 'key='=>'string'], 'Yaf_Response_Http::setHeader' => ['bool', 'name'=>'string', 'value'=>'string', 'replace='=>'bool', 'response_code='=>'int'], 'Yaf_Response_Http::setRedirect' => ['bool', 'url'=>'string'], 'Yaf_Route_Interface::__construct' => ['void'], 'Yaf_Route_Interface::assemble' => ['string', 'info'=>'array', 'query='=>'array'], 'Yaf_Route_Interface::route' => ['bool', 'request'=>'Yaf_Request_Abstract'], 'Yaf_Route_Map::__construct' => ['void', 'controller_prefer='=>'string', 'delimiter='=>'string'], 'Yaf_Route_Map::assemble' => ['string', 'info'=>'array', 'query='=>'array'], 'Yaf_Route_Map::route' => ['bool', 'request'=>'Yaf_Request_Abstract'], 'Yaf_Route_Regex::__construct' => ['void', 'match'=>'string', 'route'=>'array', 'map='=>'array', 'verify='=>'array', 'reverse='=>'string'], 'Yaf_Route_Regex::addConfig' => ['Yaf_Router|bool', 'config'=>'Yaf_Config_Abstract'], 'Yaf_Route_Regex::addRoute' => ['Yaf_Router|bool', 'name'=>'string', 'route'=>'Yaf_Route_Interface'], 'Yaf_Route_Regex::assemble' => ['string', 'info'=>'array', 'query='=>'array'], 'Yaf_Route_Regex::getCurrentRoute' => ['string'], 'Yaf_Route_Regex::getRoute' => ['Yaf_Route_Interface', 'name'=>'string'], 'Yaf_Route_Regex::getRoutes' => ['Yaf_Route_Interface[]'], 'Yaf_Route_Regex::route' => ['bool', 'request'=>'Yaf_Request_Abstract'], 'Yaf_Route_Rewrite::__construct' => ['void', 'match'=>'string', 'route'=>'array', 'verify='=>'array'], 'Yaf_Route_Rewrite::addConfig' => ['Yaf_Router|bool', 'config'=>'Yaf_Config_Abstract'], 'Yaf_Route_Rewrite::addRoute' => ['Yaf_Router|bool', 'name'=>'string', 'route'=>'Yaf_Route_Interface'], 'Yaf_Route_Rewrite::assemble' => ['string', 'info'=>'array', 'query='=>'array'], 'Yaf_Route_Rewrite::getCurrentRoute' => ['string'], 'Yaf_Route_Rewrite::getRoute' => ['Yaf_Route_Interface', 'name'=>'string'], 'Yaf_Route_Rewrite::getRoutes' => ['Yaf_Route_Interface[]'], 'Yaf_Route_Rewrite::route' => ['bool', 'request'=>'Yaf_Request_Abstract'], 'Yaf_Route_Simple::__construct' => ['void', 'module_name'=>'string', 'controller_name'=>'string', 'action_name'=>'string'], 'Yaf_Route_Simple::assemble' => ['string', 'info'=>'array', 'query='=>'array'], 'Yaf_Route_Simple::route' => ['bool', 'request'=>'Yaf_Request_Abstract'], 'Yaf_Route_Static::assemble' => ['string', 'info'=>'array', 'query='=>'array'], 'Yaf_Route_Static::match' => ['void', 'uri'=>'string'], 'Yaf_Route_Static::route' => ['bool', 'request'=>'Yaf_Request_Abstract'], 'Yaf_Route_Supervar::__construct' => ['void', 'supervar_name'=>'string'], 'Yaf_Route_Supervar::assemble' => ['string', 'info'=>'array', 'query='=>'array'], 'Yaf_Route_Supervar::route' => ['bool', 'request'=>'Yaf_Request_Abstract'], 'Yaf_Router::__construct' => ['void'], 'Yaf_Router::addConfig' => ['bool', 'config'=>'Yaf_Config_Abstract'], 'Yaf_Router::addRoute' => ['bool', 'name'=>'string', 'route'=>'Yaf_Route_Interface'], 'Yaf_Router::getCurrentRoute' => ['string'], 'Yaf_Router::getRoute' => ['Yaf_Route_Interface', 'name'=>'string'], 'Yaf_Router::getRoutes' => ['mixed'], 'Yaf_Router::route' => ['bool', 'request'=>'Yaf_Request_Abstract'], 'Yaf_Session::__clone' => ['void'], 'Yaf_Session::__construct' => ['void'], 'Yaf_Session::__get' => ['void', 'name'=>'string'], 'Yaf_Session::__isset' => ['void', 'name'=>'string'], 'Yaf_Session::__set' => ['void', 'name'=>'string', 'value'=>'string'], 'Yaf_Session::__sleep' => ['list'], 'Yaf_Session::__unset' => ['void', 'name'=>'string'], 'Yaf_Session::__wakeup' => ['void'], 'Yaf_Session::count' => ['void'], 'Yaf_Session::current' => ['void'], 'Yaf_Session::del' => ['void', 'name'=>'string'], 'Yaf_Session::get' => ['mixed', 'name'=>'string'], 'Yaf_Session::getInstance' => ['void'], 'Yaf_Session::has' => ['void', 'name'=>'string'], 'Yaf_Session::key' => ['void'], 'Yaf_Session::next' => ['void'], 'Yaf_Session::offsetExists' => ['void', 'name'=>'string'], 'Yaf_Session::offsetGet' => ['void', 'name'=>'string'], 'Yaf_Session::offsetSet' => ['void', 'name'=>'string', 'value'=>'string'], 'Yaf_Session::offsetUnset' => ['void', 'name'=>'string'], 'Yaf_Session::rewind' => ['void'], 'Yaf_Session::set' => ['Yaf_Session|bool', 'name'=>'string', 'value'=>'mixed'], 'Yaf_Session::start' => ['void'], 'Yaf_Session::valid' => ['void'], 'Yaf_View_Interface::assign' => ['bool', 'name'=>'string', 'value='=>'string'], 'Yaf_View_Interface::display' => ['bool', 'tpl'=>'string', 'tpl_vars='=>'array'], 'Yaf_View_Interface::getScriptPath' => ['string'], 'Yaf_View_Interface::render' => ['string', 'tpl'=>'string', 'tpl_vars='=>'array'], 'Yaf_View_Interface::setScriptPath' => ['void', 'template_dir'=>'string'], 'Yaf_View_Simple::__construct' => ['void', 'tempalte_dir'=>'string', 'options='=>'array'], 'Yaf_View_Simple::__get' => ['void', 'name='=>'string'], 'Yaf_View_Simple::__isset' => ['void', 'name'=>'string'], 'Yaf_View_Simple::__set' => ['void', 'name'=>'string', 'value'=>'mixed'], 'Yaf_View_Simple::assign' => ['bool', 'name'=>'string', 'value='=>'mixed'], 'Yaf_View_Simple::assignRef' => ['bool', 'name'=>'string', '&rw_value'=>'mixed'], 'Yaf_View_Simple::clear' => ['bool', 'name='=>'string'], 'Yaf_View_Simple::display' => ['bool', 'tpl'=>'string', 'tpl_vars='=>'array'], 'Yaf_View_Simple::eval' => ['string', 'tpl_content'=>'string', 'tpl_vars='=>'array'], 'Yaf_View_Simple::getScriptPath' => ['string'], 'Yaf_View_Simple::render' => ['string', 'tpl'=>'string', 'tpl_vars='=>'array'], 'Yaf_View_Simple::setScriptPath' => ['bool', 'template_dir'=>'string'], 'Yar_Client::__call' => ['void', 'method'=>'string', 'parameters'=>'array'], 'Yar_Client::__construct' => ['void', 'url'=>'string'], 'Yar_Client::setOpt' => ['Yar_Client|false', 'name'=>'int', 'value'=>'mixed'], 'Yar_Client_Exception::__clone' => ['void'], 'Yar_Client_Exception::__construct' => ['void', 'message='=>'string', 'code='=>'int', 'previous='=>'?Exception|?Throwable'], 'Yar_Client_Exception::__toString' => ['string'], 'Yar_Client_Exception::__wakeup' => ['void'], 'Yar_Client_Exception::getCode' => ['int'], 'Yar_Client_Exception::getFile' => ['string'], 'Yar_Client_Exception::getLine' => ['int'], 'Yar_Client_Exception::getMessage' => ['string'], 'Yar_Client_Exception::getPrevious' => ['?Exception|?Throwable'], 'Yar_Client_Exception::getTrace' => ['list\',args?:array}>'], 'Yar_Client_Exception::getTraceAsString' => ['string'], 'Yar_Client_Exception::getType' => ['string'], 'Yar_Concurrent_Client::call' => ['int', 'uri'=>'string', 'method'=>'string', 'parameters'=>'array', 'callback='=>'callable'], 'Yar_Concurrent_Client::loop' => ['bool', 'callback='=>'callable', 'error_callback='=>'callable'], 'Yar_Concurrent_Client::reset' => ['bool'], 'Yar_Server::__construct' => ['void', 'object'=>'Object'], 'Yar_Server::handle' => ['bool'], 'Yar_Server_Exception::__clone' => ['void'], 'Yar_Server_Exception::__construct' => ['void', 'message='=>'string', 'code='=>'int', 'previous='=>'?Exception|?Throwable'], 'Yar_Server_Exception::__toString' => ['string'], 'Yar_Server_Exception::__wakeup' => ['void'], 'Yar_Server_Exception::getCode' => ['int'], 'Yar_Server_Exception::getFile' => ['string'], 'Yar_Server_Exception::getLine' => ['int'], 'Yar_Server_Exception::getMessage' => ['string'], 'Yar_Server_Exception::getPrevious' => ['?Exception|?Throwable'], 'Yar_Server_Exception::getTrace' => ['list\',args?:array}>'], 'Yar_Server_Exception::getTraceAsString' => ['string'], 'Yar_Server_Exception::getType' => ['string'], 'ZMQ::__construct' => ['void'], 'ZMQContext::__construct' => ['void', 'io_threads='=>'int', 'is_persistent='=>'bool'], 'ZMQContext::getOpt' => ['int|string', 'key'=>'string'], 'ZMQContext::getSocket' => ['ZMQSocket', 'type'=>'int', 'persistent_id='=>'string', 'on_new_socket='=>'callable'], 'ZMQContext::isPersistent' => ['bool'], 'ZMQContext::setOpt' => ['ZMQContext', 'key'=>'int', 'value'=>'mixed'], 'ZMQDevice::__construct' => ['void', 'frontend'=>'ZMQSocket', 'backend'=>'ZMQSocket', 'listener='=>'ZMQSocket'], 'ZMQDevice::getIdleTimeout' => ['ZMQDevice'], 'ZMQDevice::getTimerTimeout' => ['ZMQDevice'], 'ZMQDevice::run' => ['void'], 'ZMQDevice::setIdleCallback' => ['ZMQDevice', 'cb_func'=>'callable', 'timeout'=>'int', 'user_data='=>'mixed'], 'ZMQDevice::setIdleTimeout' => ['ZMQDevice', 'timeout'=>'int'], 'ZMQDevice::setTimerCallback' => ['ZMQDevice', 'cb_func'=>'callable', 'timeout'=>'int', 'user_data='=>'mixed'], 'ZMQDevice::setTimerTimeout' => ['ZMQDevice', 'timeout'=>'int'], 'ZMQPoll::add' => ['string', 'entry'=>'mixed', 'type'=>'int'], 'ZMQPoll::clear' => ['ZMQPoll'], 'ZMQPoll::count' => ['int'], 'ZMQPoll::getLastErrors' => ['array'], 'ZMQPoll::poll' => ['int', '&w_readable'=>'array', '&w_writable'=>'array', 'timeout='=>'int'], 'ZMQPoll::remove' => ['bool', 'item'=>'mixed'], 'ZMQSocket::__construct' => ['void', 'context'=>'ZMQContext', 'type'=>'int', 'persistent_id='=>'string', 'on_new_socket='=>'callable'], 'ZMQSocket::bind' => ['ZMQSocket', 'dsn'=>'string', 'force='=>'bool'], 'ZMQSocket::connect' => ['ZMQSocket', 'dsn'=>'string', 'force='=>'bool'], 'ZMQSocket::disconnect' => ['ZMQSocket', 'dsn'=>'string'], 'ZMQSocket::getEndpoints' => ['array'], 'ZMQSocket::getPersistentId' => ['?string'], 'ZMQSocket::getSockOpt' => ['int|string', 'key'=>'string'], 'ZMQSocket::getSocketType' => ['int'], 'ZMQSocket::isPersistent' => ['bool'], 'ZMQSocket::recv' => ['string', 'mode='=>'int'], 'ZMQSocket::recvMulti' => ['string[]', 'mode='=>'int'], 'ZMQSocket::send' => ['ZMQSocket', 'message'=>'array', 'mode='=>'int'], 'ZMQSocket::send\'1' => ['ZMQSocket', 'message'=>'string', 'mode='=>'int'], 'ZMQSocket::sendmulti' => ['ZMQSocket', 'message'=>'array', 'mode='=>'int'], 'ZMQSocket::setSockOpt' => ['ZMQSocket', 'key'=>'int', 'value'=>'mixed'], 'ZMQSocket::unbind' => ['ZMQSocket', 'dsn'=>'string'], 'ZendAPI_Job::ZendAPI_Job' => ['Job', 'script'=>'script'], 'ZendAPI_Job::addJobToQueue' => ['int', 'jobqueue_url'=>'string', 'password'=>'string'], 'ZendAPI_Job::getApplicationID' => [''], 'ZendAPI_Job::getEndTime' => [''], 'ZendAPI_Job::getGlobalVariables' => [''], 'ZendAPI_Job::getHost' => [''], 'ZendAPI_Job::getID' => [''], 'ZendAPI_Job::getInterval' => [''], 'ZendAPI_Job::getJobDependency' => [''], 'ZendAPI_Job::getJobName' => [''], 'ZendAPI_Job::getJobPriority' => [''], 'ZendAPI_Job::getJobStatus' => ['int'], 'ZendAPI_Job::getLastPerformedStatus' => ['int'], 'ZendAPI_Job::getOutput' => ['An'], 'ZendAPI_Job::getPreserved' => [''], 'ZendAPI_Job::getProperties' => ['array'], 'ZendAPI_Job::getScheduledTime' => [''], 'ZendAPI_Job::getScript' => [''], 'ZendAPI_Job::getTimeToNextRepeat' => ['int'], 'ZendAPI_Job::getUserVariables' => [''], 'ZendAPI_Job::setApplicationID' => ['', 'app_id'=>''], 'ZendAPI_Job::setGlobalVariables' => ['', 'vars'=>''], 'ZendAPI_Job::setJobDependency' => ['', 'job_id'=>''], 'ZendAPI_Job::setJobName' => ['', 'name'=>''], 'ZendAPI_Job::setJobPriority' => ['', 'priority'=>'int'], 'ZendAPI_Job::setPreserved' => ['', 'preserved'=>''], 'ZendAPI_Job::setRecurrenceData' => ['', 'interval'=>'', 'end_time='=>'mixed'], 'ZendAPI_Job::setScheduledTime' => ['', 'timestamp'=>''], 'ZendAPI_Job::setScript' => ['', 'script'=>''], 'ZendAPI_Job::setUserVariables' => ['', 'vars'=>''], 'ZendAPI_Queue::addJob' => ['int', '&job'=>'Job'], 'ZendAPI_Queue::getAllApplicationIDs' => ['array'], 'ZendAPI_Queue::getAllhosts' => ['array'], 'ZendAPI_Queue::getHistoricJobs' => ['array', 'status'=>'int', 'start_time'=>'', 'end_time'=>'', 'index'=>'int', 'count'=>'int', '&total'=>'int'], 'ZendAPI_Queue::getJob' => ['Job', 'job_id'=>'int'], 'ZendAPI_Queue::getJobsInQueue' => ['array', 'filter_options='=>'array', 'max_jobs='=>'int', 'with_globals_and_output='=>'bool'], 'ZendAPI_Queue::getLastError' => ['string'], 'ZendAPI_Queue::getNumOfJobsInQueue' => ['int', 'filter_options='=>'array'], 'ZendAPI_Queue::getStatistics' => ['array'], 'ZendAPI_Queue::isScriptExists' => ['bool', 'path'=>'string'], 'ZendAPI_Queue::isSuspend' => ['bool'], 'ZendAPI_Queue::login' => ['bool', 'password'=>'string', 'application_id='=>'int'], 'ZendAPI_Queue::removeJob' => ['bool', 'job_id'=>'array|int'], 'ZendAPI_Queue::requeueJob' => ['bool', 'job'=>'Job'], 'ZendAPI_Queue::resumeJob' => ['bool', 'job_id'=>'array|int'], 'ZendAPI_Queue::resumeQueue' => ['bool'], 'ZendAPI_Queue::setMaxHistoryTime' => ['bool'], 'ZendAPI_Queue::suspendJob' => ['bool', 'job_id'=>'array|int'], 'ZendAPI_Queue::suspendQueue' => ['bool'], 'ZendAPI_Queue::updateJob' => ['int', '&job'=>'Job'], 'ZendAPI_Queue::zendapi_queue' => ['ZendAPI_Queue', 'queue_url'=>'string'], 'ZipArchive::addEmptyDir' => ['bool', 'dirname'=>'string'], 'ZipArchive::addFile' => ['bool', 'filepath'=>'string', 'entryname='=>'string', 'start='=>'int', 'length='=>'int'], 'ZipArchive::addFromString' => ['bool', 'name'=>'string', 'content'=>'string'], 'ZipArchive::addGlob' => ['array|false', 'pattern'=>'string', 'flags='=>'int', 'options='=>'array'], 'ZipArchive::addPattern' => ['array|false', 'pattern'=>'string', 'path='=>'string', 'options='=>'array'], 'ZipArchive::close' => ['bool'], 'ZipArchive::deleteIndex' => ['bool', 'index'=>'int'], 'ZipArchive::deleteName' => ['bool', 'name'=>'string'], 'ZipArchive::extractTo' => ['bool', 'pathto'=>'string', 'files='=>'string[]|string|null'], 'ZipArchive::getArchiveComment' => ['string|false', 'flags='=>'int'], 'ZipArchive::getCommentIndex' => ['string|false', 'index'=>'int', 'flags='=>'int'], 'ZipArchive::getCommentName' => ['string|false', 'name'=>'string', 'flags='=>'int'], 'ZipArchive::getExternalAttributesIndex' => ['bool', 'index'=>'int', '&w_opsys'=>'int', '&w_attr'=>'int', 'flags='=>'int'], 'ZipArchive::getExternalAttributesName' => ['bool', 'name'=>'string', '&w_opsys'=>'int', '&w_attr'=>'int', 'flags='=>'int'], 'ZipArchive::getFromIndex' => ['string|false', 'index'=>'int', 'len='=>'int', 'flags='=>'int'], 'ZipArchive::getFromName' => ['string|false', 'name'=>'string', 'len='=>'int', 'flags='=>'int'], 'ZipArchive::getNameIndex' => ['string|false', 'index'=>'int', 'flags='=>'int'], 'ZipArchive::getStatusString' => ['string|false'], 'ZipArchive::getStream' => ['resource|false', 'name'=>'string'], 'ZipArchive::isCompressionMethodSupported' => ['bool', 'method'=>'int', 'enc='=>'bool'], 'ZipArchive::isEncryptionMethodSupported' => ['bool', 'method'=>'int', 'enc='=>'bool'], 'ZipArchive::locateName' => ['int|false', 'name'=>'string', 'flags='=>'int'], 'ZipArchive::open' => ['int|bool', 'filename'=>'string', 'flags='=>'int'], 'ZipArchive::registerCancelCallback' => ['bool', 'callback'=>'callable'], 'ZipArchive::registerProgressCallback' => ['bool', 'rate'=>'float', 'callback'=>'callable'], 'ZipArchive::renameIndex' => ['bool', 'index'=>'int', 'new_name'=>'string'], 'ZipArchive::renameName' => ['bool', 'name'=>'string', 'new_name'=>'string'], 'ZipArchive::replaceFile' => ['bool', 'filepath'=>'string', 'index'=>'int', 'start='=>'int', 'length='=>'int', 'flags='=>'int'], 'ZipArchive::setArchiveComment' => ['bool', 'comment'=>'string'], 'ZipArchive::setCommentIndex' => ['bool', 'index'=>'int', 'comment'=>'string'], 'ZipArchive::setCommentName' => ['bool', 'name'=>'string', 'comment'=>'string'], 'ZipArchive::setCompressionIndex' => ['bool', 'index'=>'int', 'method'=>'int', 'compflags='=>'int'], 'ZipArchive::setCompressionName' => ['bool', 'name'=>'string', 'method'=>'int', 'compflags='=>'int'], 'ZipArchive::setExternalAttributesIndex' => ['bool', 'index'=>'int', 'opsys'=>'int', 'attr'=>'int', 'flags='=>'int'], 'ZipArchive::setExternalAttributesName' => ['bool', 'name'=>'string', 'opsys'=>'int', 'attr'=>'int', 'flags='=>'int'], 'ZipArchive::setMtimeIndex' => ['bool', 'index'=>'int', 'timestamp'=>'int', 'flags='=>'int'], 'ZipArchive::setMtimeName' => ['bool', 'name'=>'string', 'timestamp'=>'int', 'flags='=>'int'], 'ZipArchive::setPassword' => ['bool', 'password'=>'string'], 'ZipArchive::statIndex' => ['array|false', 'index'=>'int', 'flags='=>'int'], 'ZipArchive::statName' => ['array|false', 'name'=>'string', 'flags='=>'int'], 'ZipArchive::unchangeAll' => ['bool'], 'ZipArchive::unchangeArchive' => ['bool'], 'ZipArchive::unchangeIndex' => ['bool', 'index'=>'int'], 'ZipArchive::unchangeName' => ['bool', 'name'=>'string'], 'Zookeeper::addAuth' => ['bool', 'scheme'=>'string', 'cert'=>'string', 'completion_cb='=>'callable'], 'Zookeeper::close' => ['void'], 'Zookeeper::connect' => ['void', 'host'=>'string', 'watcher_cb='=>'callable', 'recv_timeout='=>'int'], 'Zookeeper::create' => ['string', 'path'=>'string', 'value'=>'string', 'acls'=>'array', 'flags='=>'int'], 'Zookeeper::delete' => ['bool', 'path'=>'string', 'version='=>'int'], 'Zookeeper::exists' => ['bool', 'path'=>'string', 'watcher_cb='=>'callable'], 'Zookeeper::get' => ['string', 'path'=>'string', 'watcher_cb='=>'callable', 'stat='=>'array', 'max_size='=>'int'], 'Zookeeper::getAcl' => ['array', 'path'=>'string'], 'Zookeeper::getChildren' => ['array|false', 'path'=>'string', 'watcher_cb='=>'callable'], 'Zookeeper::getClientId' => ['int'], 'Zookeeper::getConfig' => ['ZookeeperConfig'], 'Zookeeper::getRecvTimeout' => ['int'], 'Zookeeper::getState' => ['int'], 'Zookeeper::isRecoverable' => ['bool'], 'Zookeeper::set' => ['bool', 'path'=>'string', 'value'=>'string', 'version='=>'int', 'stat='=>'array'], 'Zookeeper::setAcl' => ['bool', 'path'=>'string', 'version'=>'int', 'acl'=>'array'], 'Zookeeper::setDebugLevel' => ['bool', 'logLevel'=>'int'], 'Zookeeper::setDeterministicConnOrder' => ['bool', 'yesOrNo'=>'bool'], 'Zookeeper::setLogStream' => ['bool', 'stream'=>'resource'], 'Zookeeper::setWatcher' => ['bool', 'watcher_cb'=>'callable'], 'ZookeeperConfig::add' => ['void', 'members'=>'string', 'version='=>'int', 'stat='=>'array'], 'ZookeeperConfig::get' => ['string', 'watcher_cb='=>'callable', 'stat='=>'array'], 'ZookeeperConfig::remove' => ['void', 'id_list'=>'string', 'version='=>'int', 'stat='=>'array'], 'ZookeeperConfig::set' => ['void', 'members'=>'string', 'version='=>'int', 'stat='=>'array'], '_' => ['string', 'message'=>'string'], '__halt_compiler' => ['void'], 'abs' => ['0|positive-int', 'num'=>'int'], 'abs\'1' => ['float', 'num'=>'float'], 'abs\'2' => ['numeric', 'num'=>'numeric'], 'accelerator_get_configuration' => ['array'], 'accelerator_get_scripts' => ['array'], 'accelerator_get_status' => ['array', 'fetch_scripts'=>'bool'], 'accelerator_reset' => [''], 'accelerator_set_status' => ['void', 'status'=>'bool'], 'acos' => ['float', 'num'=>'float'], 'acosh' => ['float', 'num'=>'float'], 'addcslashes' => ['string', 'string'=>'string', 'characters'=>'string'], 'addslashes' => ['string', 'string'=>'string'], 'apache_child_terminate' => ['bool'], 'apache_get_modules' => ['array'], 'apache_get_version' => ['string|false'], 'apache_getenv' => ['string|false', 'variable'=>'string', 'walk_to_top='=>'bool'], 'apache_lookup_uri' => ['object', 'filename'=>'string'], 'apache_note' => ['string|false', 'note_name'=>'string', 'note_value='=>'string'], 'apache_request_headers' => ['array|false'], 'apache_reset_timeout' => ['bool'], 'apache_response_headers' => ['array|false'], 'apache_setenv' => ['bool', 'variable'=>'string', 'value'=>'string', 'walk_to_top='=>'bool'], 'apc_add' => ['bool', 'key'=>'string', 'var'=>'mixed', 'ttl='=>'int'], 'apc_add\'1' => ['array', 'values'=>'array', 'unused='=>'', 'ttl='=>'int'], 'apc_bin_dump' => ['string|false|null', 'files='=>'array', 'user_vars='=>'array'], 'apc_bin_dumpfile' => ['int|false', 'files'=>'array', 'user_vars'=>'array', 'filename'=>'string', 'flags='=>'int', 'context='=>'resource'], 'apc_bin_load' => ['bool', 'data'=>'string', 'flags='=>'int'], 'apc_bin_loadfile' => ['bool', 'filename'=>'string', 'context='=>'resource', 'flags='=>'int'], 'apc_cache_info' => ['array|false', 'cache_type='=>'string', 'limited='=>'bool'], 'apc_cas' => ['bool', 'key'=>'string', 'old'=>'int', 'new'=>'int'], 'apc_clear_cache' => ['bool', 'cache_type='=>'string'], 'apc_compile_file' => ['bool', 'filename'=>'string', 'atomic='=>'bool'], 'apc_dec' => ['int|false', 'key'=>'string', 'step='=>'int', '&w_success='=>'bool'], 'apc_define_constants' => ['bool', 'key'=>'string', 'constants'=>'array', 'case_sensitive='=>'bool'], 'apc_delete' => ['bool', 'key'=>'string|string[]|APCIterator'], 'apc_delete_file' => ['bool|string[]', 'keys'=>'mixed'], 'apc_exists' => ['bool', 'keys'=>'string'], 'apc_exists\'1' => ['array', 'keys'=>'string[]'], 'apc_fetch' => ['mixed|false', 'key'=>'string', '&w_success='=>'bool'], 'apc_fetch\'1' => ['array|false', 'key'=>'string[]', '&w_success='=>'bool'], 'apc_inc' => ['int|false', 'key'=>'string', 'step='=>'int', '&w_success='=>'bool'], 'apc_load_constants' => ['bool', 'key'=>'string', 'case_sensitive='=>'bool'], 'apc_sma_info' => ['array|false', 'limited='=>'bool'], 'apc_store' => ['bool', 'key'=>'string', 'var'=>'', 'ttl='=>'int'], 'apc_store\'1' => ['array', 'values'=>'array', 'unused='=>'', 'ttl='=>'int'], 'apcu_add' => ['bool', 'key'=>'string', 'var'=>'', 'ttl='=>'int'], 'apcu_add\'1' => ['array', 'values'=>'array', 'unused='=>'', 'ttl='=>'int'], 'apcu_cache_info' => ['array|false', 'limited='=>'bool'], 'apcu_cas' => ['bool', 'key'=>'string', 'old'=>'int', 'new'=>'int'], 'apcu_clear_cache' => ['bool'], 'apcu_dec' => ['int|false', 'key'=>'string', 'step='=>'int', '&w_success='=>'bool', 'ttl='=>'int'], 'apcu_delete' => ['bool', 'key'=>'string|APCuIterator'], 'apcu_delete\'1' => ['list', 'key'=>'string[]'], 'apcu_enabled' => ['bool'], 'apcu_entry' => ['mixed', 'key'=>'string', 'generator'=>'callable(string):mixed', 'ttl='=>'int'], 'apcu_exists' => ['bool', 'keys'=>'string'], 'apcu_exists\'1' => ['array', 'keys'=>'string[]'], 'apcu_fetch' => ['mixed|false', 'key'=>'string', '&w_success='=>'bool'], 'apcu_fetch\'1' => ['array|false', 'key'=>'string[]', '&w_success='=>'bool'], 'apcu_inc' => ['int|false', 'key'=>'string', 'step='=>'int', '&w_success='=>'bool', 'ttl='=>'int'], 'apcu_key_info' => ['?array', 'key'=>'string'], 'apcu_sma_info' => ['array|false', 'limited='=>'bool'], 'apcu_store' => ['bool', 'key'=>'string', 'var='=>'', 'ttl='=>'int'], 'apcu_store\'1' => ['array', 'values'=>'array', 'unused='=>'', 'ttl='=>'int'], 'apd_breakpoint' => ['bool', 'debug_level'=>'int'], 'apd_callstack' => ['array'], 'apd_clunk' => ['void', 'warning'=>'string', 'delimiter='=>'string'], 'apd_continue' => ['bool', 'debug_level'=>'int'], 'apd_croak' => ['void', 'warning'=>'string', 'delimiter='=>'string'], 'apd_dump_function_table' => ['void'], 'apd_dump_persistent_resources' => ['array'], 'apd_dump_regular_resources' => ['array'], 'apd_echo' => ['bool', 'output'=>'string'], 'apd_get_active_symbols' => ['array'], 'apd_set_pprof_trace' => ['string', 'dump_directory='=>'string', 'fragment='=>'string'], 'apd_set_session' => ['void', 'debug_level'=>'int'], 'apd_set_session_trace' => ['void', 'debug_level'=>'int', 'dump_directory='=>'string'], 'apd_set_session_trace_socket' => ['bool', 'tcp_server'=>'string', 'socket_type'=>'int', 'port'=>'int', 'debug_level'=>'int'], 'array_change_key_case' => ['array', 'array'=>'array', 'case='=>'int'], 'array_chunk' => ['list', 'array'=>'array', 'length'=>'int', 'preserve_keys='=>'bool'], 'array_column' => ['array', 'array'=>'array', 'column_key'=>'mixed', 'index_key='=>'mixed'], 'array_combine' => ['array|false', 'keys'=>'string[]|int[]', 'values'=>'array'], 'array_count_values' => ['array', 'array'=>'array'], 'array_diff' => ['array', 'array'=>'array', '...arrays'=>'array'], 'array_diff_assoc' => ['array', 'array'=>'array', '...arrays'=>'array'], 'array_diff_key' => ['array', 'array'=>'array', '...arrays'=>'array'], 'array_diff_uassoc' => ['array', 'array'=>'array', 'rest'=>'array', 'data_comp_func'=>'callable(mixed,mixed):int'], 'array_diff_uassoc\'1' => ['array', 'array'=>'array', 'rest'=>'array', 'arr3'=>'array', 'arg4'=>'array|callable(mixed,mixed):int', '...rest='=>'array|callable(mixed,mixed):int'], 'array_diff_ukey' => ['array', 'array'=>'array', 'rest'=>'array', 'key_comp_func'=>'callable(mixed,mixed):int'], 'array_diff_ukey\'1' => ['array', 'array'=>'array', 'rest'=>'array', 'arr3'=>'array', 'arg4'=>'array|callable(mixed,mixed):int', '...rest='=>'array|callable(mixed,mixed):int'], 'array_fill' => ['array', 'start_index'=>'int', 'count'=>'int', 'value'=>'mixed'], 'array_fill_keys' => ['array', 'keys'=>'array', 'value'=>'mixed'], 'array_filter' => ['array', 'array'=>'array', 'callback='=>'callable(mixed,array-key=):mixed', 'mode='=>'int'], 'array_flip' => ['array', 'array'=>'array'], 'array_intersect' => ['array', 'array'=>'array', '...arrays'=>'array'], 'array_intersect_assoc' => ['array', 'array'=>'array', '...arrays'=>'array'], 'array_intersect_key' => ['array', 'array'=>'array', '...arrays'=>'array'], 'array_intersect_uassoc' => ['array', 'array'=>'array', 'rest'=>'array', 'key_compare_func'=>'callable(mixed,mixed):int'], 'array_intersect_uassoc\'1' => ['array', 'array'=>'array', 'rest'=>'array', 'arr3'=>'array', 'arg4'=>'array|callable(mixed,mixed):int', '...rest'=>'array|callable(mixed,mixed):int'], 'array_intersect_ukey' => ['array', 'array'=>'array', 'rest'=>'array', 'key_compare_func'=>'callable(mixed,mixed):int'], 'array_intersect_ukey\'1' => ['array', 'array'=>'array', 'rest'=>'array', 'arr3'=>'array', 'arg4'=>'array|callable(mixed,mixed):int', '...rest'=>'array|callable(mixed,mixed):int'], 'array_key_exists' => ['bool', 'key'=>'string|int', 'array'=>'array|object'], 'array_keys' => ['list', 'array'=>'array', 'filter_value='=>'mixed', 'strict='=>'bool'], 'array_map' => ['array', 'callback'=>'?callable', 'array'=>'array', '...arrays='=>'array'], 'array_merge' => ['array', '...arrays'=>'array'], 'array_merge_recursive' => ['array', '...arrays'=>'array'], 'array_multisort' => ['bool', '&rw_array'=>'array', 'rest='=>'array|int', 'array1_sort_flags='=>'array|int', '...args='=>'array|int'], 'array_pad' => ['array', 'array'=>'array', 'length'=>'int', 'value'=>'mixed'], 'array_pop' => ['mixed', '&rw_array'=>'array'], 'array_product' => ['int|float', 'array'=>'array'], 'array_push' => ['int', '&rw_array'=>'array', '...values'=>'mixed'], 'array_rand' => ['int|string|array|array', 'array'=>'non-empty-array', 'num'=>'int'], 'array_rand\'1' => ['int|string', 'array'=>'array'], 'array_reduce' => ['mixed', 'array'=>'array', 'callback'=>'callable(mixed,mixed):mixed', 'initial='=>'mixed'], 'array_replace' => ['array', 'array'=>'array', '...replacements='=>'array'], 'array_replace_recursive' => ['array', 'array'=>'array', '...replacements='=>'array'], 'array_reverse' => ['array', 'array'=>'array', 'preserve_keys='=>'bool'], 'array_search' => ['int|string|false', 'needle'=>'mixed', 'haystack'=>'array', 'strict='=>'bool'], 'array_shift' => ['mixed|null', '&rw_array'=>'array'], 'array_slice' => ['array', 'array'=>'array', 'offset'=>'int', 'length='=>'?int', 'preserve_keys='=>'bool'], 'array_splice' => ['array', '&rw_array'=>'array', 'offset'=>'int', 'length='=>'int', 'replacement='=>'array|string'], 'array_sum' => ['int|float', 'array'=>'array'], 'array_udiff' => ['array', 'array'=>'array', 'rest'=>'array', 'data_comp_func'=>'callable(mixed,mixed):int'], 'array_udiff\'1' => ['array', 'array'=>'array', 'rest'=>'array', 'arr3'=>'array', 'arg4'=>'array|callable(mixed,mixed):int', '...rest='=>'array|callable(mixed,mixed):int'], 'array_udiff_assoc' => ['array', 'array'=>'array', 'rest'=>'array', 'key_comp_func'=>'callable(mixed,mixed):int'], 'array_udiff_assoc\'1' => ['array', 'array'=>'array', 'rest'=>'array', 'arr3'=>'array', 'arg4'=>'array|callable(mixed,mixed):int', '...rest='=>'array|callable(mixed,mixed):int'], 'array_udiff_uassoc' => ['array', 'array'=>'array', 'rest'=>'array', 'data_comp_func'=>'callable(mixed,mixed):int', 'key_comp_func'=>'callable(mixed,mixed):int'], 'array_udiff_uassoc\'1' => ['array', 'array'=>'array', 'rest'=>'array', 'arr3'=>'array', 'arg4'=>'array|callable(mixed,mixed):int', 'arg5'=>'array|callable(mixed,mixed):int', '...rest='=>'array|callable(mixed,mixed):int'], 'array_uintersect' => ['array', 'array'=>'array', 'rest'=>'array', 'data_compare_func'=>'callable(mixed,mixed):int'], 'array_uintersect\'1' => ['array', 'array'=>'array', 'rest'=>'array', 'arr3'=>'array', 'arg4'=>'array|callable(mixed,mixed):int', '...rest='=>'array|callable(mixed,mixed):int'], 'array_uintersect_assoc' => ['array', 'array'=>'array', 'rest'=>'array', 'data_compare_func'=>'callable(mixed,mixed):int'], 'array_uintersect_assoc\'1' => ['array', 'array'=>'array', 'rest'=>'array', 'arr3'=>'array', 'arg4'=>'array|callable', '...rest='=>'array|callable(mixed,mixed):int'], 'array_uintersect_uassoc' => ['array', 'array'=>'array', 'rest'=>'array', 'data_compare_func'=>'callable(mixed,mixed):int', 'key_compare_func'=>'callable(mixed,mixed):int'], 'array_uintersect_uassoc\'1' => ['array', 'array'=>'array', 'rest'=>'array', 'arr3'=>'array', 'arg4'=>'array|callable(mixed,mixed):int', 'arg5'=>'array|callable(mixed,mixed):int', '...rest='=>'array|callable(mixed,mixed):int'], 'array_unique' => ['array', 'array'=>'array', 'flags='=>'int'], 'array_unshift' => ['int', '&rw_array'=>'array', '...values'=>'mixed'], 'array_values' => ['list', 'array'=>'array'], 'array_walk' => ['bool', '&rw_array'=>'array', 'callback'=>'callable', 'arg='=>'mixed'], 'array_walk\'1' => ['bool', '&rw_array'=>'object', 'callback'=>'callable', 'arg='=>'mixed'], 'array_walk_recursive' => ['bool', '&rw_array'=>'array', 'callback'=>'callable', 'arg='=>'mixed'], 'array_walk_recursive\'1' => ['bool', '&rw_array'=>'object', 'callback'=>'callable', 'arg='=>'mixed'], 'arsort' => ['true', '&rw_array'=>'array', 'flags='=>'int'], 'asin' => ['float', 'num'=>'float'], 'asinh' => ['float', 'num'=>'float'], 'asort' => ['true', '&rw_array'=>'array', 'flags='=>'int'], 'assert' => ['bool', 'assertion'=>'string|bool|int', 'description='=>'string|Throwable|null'], 'assert_options' => ['mixed|false', 'option'=>'int', 'value='=>'mixed'], 'ast\Node::__construct' => ['void', 'kind='=>'int', 'flags='=>'int', 'children='=>'ast\Node\Decl[]|ast\Node[]|int[]|string[]|float[]|bool[]|null[]', 'start_line='=>'int'], 'ast\get_kind_name' => ['string', 'kind'=>'int'], 'ast\get_metadata' => ['array'], 'ast\get_supported_versions' => ['array', 'exclude_deprecated='=>'bool'], 'ast\kind_uses_flags' => ['bool', 'kind'=>'int'], 'ast\parse_code' => ['ast\Node', 'code'=>'string', 'version'=>'int', 'filename='=>'string'], 'ast\parse_file' => ['ast\Node', 'filename'=>'string', 'version'=>'int'], 'atan' => ['float', 'num'=>'float'], 'atan2' => ['float', 'y'=>'float', 'x'=>'float'], 'atanh' => ['float', 'num'=>'float'], 'base64_decode' => ['string', 'string'=>'string', 'strict='=>'false'], 'base64_decode\'1' => ['string|false', 'string'=>'string', 'strict='=>'true'], 'base64_encode' => ['string', 'string'=>'string'], 'base_convert' => ['string', 'num'=>'string', 'from_base'=>'int', 'to_base'=>'int'], 'basename' => ['string', 'path'=>'string', 'suffix='=>'string'], 'bbcode_add_element' => ['bool', 'bbcode_container'=>'resource', 'tag_name'=>'string', 'tag_rules'=>'array'], 'bbcode_add_smiley' => ['bool', 'bbcode_container'=>'resource', 'smiley'=>'string', 'replace_by'=>'string'], 'bbcode_create' => ['resource', 'bbcode_initial_tags='=>'array'], 'bbcode_destroy' => ['bool', 'bbcode_container'=>'resource'], 'bbcode_parse' => ['string', 'bbcode_container'=>'resource', 'to_parse'=>'string'], 'bbcode_set_arg_parser' => ['bool', 'bbcode_container'=>'resource', 'bbcode_arg_parser'=>'resource'], 'bbcode_set_flags' => ['bool', 'bbcode_container'=>'resource', 'flags'=>'int', 'mode='=>'int'], 'bcadd' => ['numeric-string', 'num1'=>'numeric-string', 'num2'=>'numeric-string', 'scale='=>'int'], 'bccomp' => ['int', 'num1'=>'numeric-string', 'num2'=>'numeric-string', 'scale='=>'int'], 'bcdiv' => ['numeric-string', 'num1'=>'numeric-string', 'num2'=>'numeric-string', 'scale='=>'int'], 'bcmod' => ['numeric-string', 'num1'=>'numeric-string', 'num2'=>'numeric-string', 'scale='=>'int'], 'bcmul' => ['numeric-string', 'num1'=>'numeric-string', 'num2'=>'numeric-string', 'scale='=>'int'], 'bcompiler_load' => ['bool', 'filename'=>'string'], 'bcompiler_load_exe' => ['bool', 'filename'=>'string'], 'bcompiler_parse_class' => ['bool', 'class'=>'string', 'callback'=>'string'], 'bcompiler_read' => ['bool', 'filehandle'=>'resource'], 'bcompiler_write_class' => ['bool', 'filehandle'=>'resource', 'classname'=>'string', 'extends='=>'string'], 'bcompiler_write_constant' => ['bool', 'filehandle'=>'resource', 'constantname'=>'string'], 'bcompiler_write_exe_footer' => ['bool', 'filehandle'=>'resource', 'startpos'=>'int'], 'bcompiler_write_file' => ['bool', 'filehandle'=>'resource', 'filename'=>'string'], 'bcompiler_write_footer' => ['bool', 'filehandle'=>'resource'], 'bcompiler_write_function' => ['bool', 'filehandle'=>'resource', 'functionname'=>'string'], 'bcompiler_write_functions_from_file' => ['bool', 'filehandle'=>'resource', 'filename'=>'string'], 'bcompiler_write_header' => ['bool', 'filehandle'=>'resource', 'write_ver='=>'string'], 'bcompiler_write_included_filename' => ['bool', 'filehandle'=>'resource', 'filename'=>'string'], 'bcpow' => ['numeric-string', 'num'=>'numeric-string', 'exponent'=>'numeric-string', 'scale='=>'int'], 'bcpowmod' => ['numeric-string|false', 'num'=>'numeric-string', 'exponent'=>'numeric-string', 'modulus'=>'numeric-string', 'scale='=>'int'], 'bcscale' => ['int', 'scale'=>'int'], 'bcsqrt' => ['numeric-string', 'num'=>'numeric-string', 'scale='=>'int'], 'bcsub' => ['numeric-string', 'num1'=>'numeric-string', 'num2'=>'numeric-string', 'scale='=>'int'], 'bin2hex' => ['string', 'string'=>'string'], 'bind_textdomain_codeset' => ['string', 'domain'=>'string', 'codeset'=>'string'], 'bindec' => ['float|int', 'binary_string'=>'string'], 'bindtextdomain' => ['string', 'domain'=>'string', 'directory'=>'string'], 'birdstep_autocommit' => ['bool', 'index'=>'int'], 'birdstep_close' => ['bool', 'id'=>'int'], 'birdstep_commit' => ['bool', 'index'=>'int'], 'birdstep_connect' => ['int', 'server'=>'string', 'user'=>'string', 'pass'=>'string'], 'birdstep_exec' => ['int', 'index'=>'int', 'exec_str'=>'string'], 'birdstep_fetch' => ['bool', 'index'=>'int'], 'birdstep_fieldname' => ['string', 'index'=>'int', 'col'=>'int'], 'birdstep_fieldnum' => ['int', 'index'=>'int'], 'birdstep_freeresult' => ['bool', 'index'=>'int'], 'birdstep_off_autocommit' => ['bool', 'index'=>'int'], 'birdstep_result' => ['', 'index'=>'int', 'col'=>''], 'birdstep_rollback' => ['bool', 'index'=>'int'], 'blenc_encrypt' => ['string', 'plaintext'=>'string', 'encodedfile'=>'string', 'encryption_key='=>'string'], 'boolval' => ['bool', 'value'=>'mixed'], 'bson_decode' => ['array', 'bson'=>'string'], 'bson_encode' => ['string', 'anything'=>'mixed'], 'bzclose' => ['bool', 'bz'=>'resource'], 'bzcompress' => ['string|int', 'data'=>'string', 'block_size='=>'int', 'work_factor='=>'int'], 'bzdecompress' => ['string|int|false', 'data'=>'string', 'use_less_memory='=>'int'], 'bzerrno' => ['int', 'bz'=>'resource'], 'bzerror' => ['array', 'bz'=>'resource'], 'bzerrstr' => ['string', 'bz'=>'resource'], 'bzflush' => ['bool', 'bz'=>'resource'], 'bzopen' => ['resource|false', 'file'=>'string|resource', 'mode'=>'string'], 'bzread' => ['string|false', 'bz'=>'resource', 'length='=>'int'], 'bzwrite' => ['int|false', 'bz'=>'resource', 'data'=>'string', 'length='=>'int'], 'cal_days_in_month' => ['int', 'calendar'=>'int', 'month'=>'int', 'year'=>'int'], 'cal_from_jd' => ['array{date:string,month:int,day:int,year:int,dow:int,abbrevdayname:string,dayname:string,abbrevmonth:string,monthname:string}', 'julian_day'=>'int', 'calendar'=>'int'], 'cal_info' => ['array', 'calendar='=>'int'], 'cal_to_jd' => ['int', 'calendar'=>'int', 'month'=>'int', 'day'=>'int', 'year'=>'int'], 'calcul_hmac' => ['string', 'clent'=>'string', 'siretcode'=>'string', 'price'=>'string', 'reference'=>'string', 'validity'=>'string', 'taxation'=>'string', 'devise'=>'string', 'language'=>'string'], 'calculhmac' => ['string', 'clent'=>'string', 'data'=>'string'], 'call_user_func' => ['mixed|false', 'callback'=>'callable', '...args='=>'mixed'], 'call_user_func_array' => ['mixed|false', 'callback'=>'callable', 'args'=>'list'], 'call_user_method' => ['mixed', 'method_name'=>'string', 'object'=>'object', 'parameter='=>'mixed', '...args='=>'mixed'], 'call_user_method_array' => ['mixed', 'method_name'=>'string', 'object'=>'object', 'params'=>'list'], 'ceil' => ['float', 'num'=>'float|int'], 'chdb::__construct' => ['void', 'pathname'=>'string'], 'chdb::get' => ['string', 'key'=>'string'], 'chdb_create' => ['bool', 'pathname'=>'string', 'data'=>'array'], 'chdir' => ['bool', 'directory'=>'string'], 'checkdate' => ['bool', 'month'=>'int', 'day'=>'int', 'year'=>'int'], 'checkdnsrr' => ['bool', 'hostname'=>'string', 'type='=>'string'], 'chgrp' => ['bool', 'filename'=>'string', 'group'=>'string|int'], 'chmod' => ['bool', 'filename'=>'string', 'permissions'=>'int'], 'chop' => ['string', 'string'=>'string', 'characters='=>'string'], 'chown' => ['bool', 'filename'=>'string', 'user'=>'string|int'], 'chr' => ['non-empty-string', 'codepoint'=>'int'], 'chroot' => ['bool', 'directory'=>'string'], 'chunk_split' => ['string', 'string'=>'string', 'length='=>'int', 'separator='=>'string'], 'classObj::__construct' => ['void', 'layer'=>'layerObj', 'class'=>'classObj'], 'classObj::addLabel' => ['int', 'label'=>'labelObj'], 'classObj::convertToString' => ['string'], 'classObj::createLegendIcon' => ['imageObj', 'width'=>'int', 'height'=>'int'], 'classObj::deletestyle' => ['int', 'index'=>'int'], 'classObj::drawLegendIcon' => ['int', 'width'=>'int', 'height'=>'int', 'im'=>'imageObj', 'dstX'=>'int', 'dstY'=>'int'], 'classObj::free' => ['void'], 'classObj::getExpressionString' => ['string'], 'classObj::getLabel' => ['labelObj', 'index'=>'int'], 'classObj::getMetaData' => ['int', 'name'=>'string'], 'classObj::getStyle' => ['styleObj', 'index'=>'int'], 'classObj::getTextString' => ['string'], 'classObj::movestyledown' => ['int', 'index'=>'int'], 'classObj::movestyleup' => ['int', 'index'=>'int'], 'classObj::ms_newClassObj' => ['classObj', 'layer'=>'layerObj', 'class'=>'classObj'], 'classObj::removeLabel' => ['labelObj', 'index'=>'int'], 'classObj::removeMetaData' => ['int', 'name'=>'string'], 'classObj::set' => ['int', 'property_name'=>'string', 'new_value'=>''], 'classObj::setExpression' => ['int', 'expression'=>'string'], 'classObj::setMetaData' => ['int', 'name'=>'string', 'value'=>'string'], 'classObj::settext' => ['int', 'text'=>'string'], 'classObj::updateFromString' => ['int', 'snippet'=>'string'], 'class_alias' => ['bool', 'class'=>'string', 'alias'=>'string', 'autoload='=>'bool'], 'class_exists' => ['bool', 'class'=>'string', 'autoload='=>'bool'], 'class_implements' => ['array|false', 'object_or_class'=>'object|string', 'autoload='=>'bool'], 'class_parents' => ['array|false', 'object_or_class'=>'object|string', 'autoload='=>'bool'], 'class_uses' => ['array|false', 'object_or_class'=>'object|string', 'autoload='=>'bool'], 'classkit_import' => ['array', 'filename'=>'string'], 'classkit_method_add' => ['bool', 'classname'=>'string', 'methodname'=>'string', 'args'=>'string', 'code'=>'string', 'flags='=>'int'], 'classkit_method_copy' => ['bool', 'dclass'=>'string', 'dmethod'=>'string', 'sclass'=>'string', 'smethod='=>'string'], 'classkit_method_redefine' => ['bool', 'classname'=>'string', 'methodname'=>'string', 'args'=>'string', 'code'=>'string', 'flags='=>'int'], 'classkit_method_remove' => ['bool', 'classname'=>'string', 'methodname'=>'string'], 'classkit_method_rename' => ['bool', 'classname'=>'string', 'methodname'=>'string', 'newname'=>'string'], 'clearstatcache' => ['void', 'clear_realpath_cache='=>'bool', 'filename='=>'string'], 'cli_get_process_title' => ['?string'], 'cli_set_process_title' => ['bool', 'title'=>'string'], 'closedir' => ['void', 'dir_handle='=>'resource'], 'closelog' => ['true'], 'clusterObj::convertToString' => ['string'], 'clusterObj::getFilterString' => ['string'], 'clusterObj::getGroupString' => ['string'], 'clusterObj::setFilter' => ['int', 'expression'=>'string'], 'clusterObj::setGroup' => ['int', 'expression'=>'string'], 'collator_asort' => ['bool', 'object'=>'collator', '&rw_array'=>'array', 'flags='=>'int'], 'collator_compare' => ['int', 'object'=>'collator', 'string1'=>'string', 'string2'=>'string'], 'collator_create' => ['?Collator', 'locale'=>'string'], 'collator_get_attribute' => ['int|false', 'object'=>'collator', 'attribute'=>'int'], 'collator_get_error_code' => ['int', 'object'=>'collator'], 'collator_get_error_message' => ['string', 'object'=>'collator'], 'collator_get_locale' => ['string', 'object'=>'collator', 'type'=>'int'], 'collator_get_sort_key' => ['string', 'object'=>'collator', 'string'=>'string'], 'collator_get_strength' => ['int|false', 'object'=>'collator'], 'collator_set_attribute' => ['bool', 'object'=>'collator', 'attribute'=>'int', 'value'=>'int'], 'collator_set_strength' => ['bool', 'object'=>'collator', 'strength'=>'int'], 'collator_sort' => ['bool', 'object'=>'collator', '&rw_array'=>'array', 'flags='=>'int'], 'collator_sort_with_sort_keys' => ['bool', 'object'=>'collator', '&rw_array'=>'array'], 'colorObj::setHex' => ['int', 'hex'=>'string'], 'colorObj::toHex' => ['string'], 'com_addref' => [''], 'com_create_guid' => ['string'], 'com_event_sink' => ['bool', 'variant'=>'VARIANT', 'sink_object'=>'object', 'sink_interface='=>'mixed'], 'com_get_active_object' => ['VARIANT', 'prog_id'=>'string', 'codepage='=>'int'], 'com_isenum' => ['bool', 'com_module'=>'variant'], 'com_load_typelib' => ['bool', 'typelib_name'=>'string', 'case_insensitive='=>'bool'], 'com_message_pump' => ['bool', 'timeout_milliseconds='=>'int'], 'com_print_typeinfo' => ['bool', 'variant'=>'object', 'dispatch_interface='=>'string', 'display_sink='=>'bool'], 'commonmark\cql::__invoke' => ['', 'root'=>'CommonMark\Node', 'handler'=>'callable'], 'commonmark\interfaces\ivisitable::accept' => ['void', 'visitor'=>'CommonMark\Interfaces\IVisitor'], 'commonmark\interfaces\ivisitor::enter' => ['?int|IVisitable', 'visitable'=>'IVisitable'], 'commonmark\interfaces\ivisitor::leave' => ['?int|IVisitable', 'visitable'=>'IVisitable'], 'commonmark\node::accept' => ['void', 'visitor'=>'CommonMark\Interfaces\IVisitor'], 'commonmark\node::appendChild' => ['CommonMark\Node', 'child'=>'CommonMark\Node'], 'commonmark\node::insertAfter' => ['CommonMark\Node', 'sibling'=>'CommonMark\Node'], 'commonmark\node::insertBefore' => ['CommonMark\Node', 'sibling'=>'CommonMark\Node'], 'commonmark\node::prependChild' => ['CommonMark\Node', 'child'=>'CommonMark\Node'], 'commonmark\node::replace' => ['CommonMark\Node', 'target'=>'CommonMark\Node'], 'commonmark\node::unlink' => ['void'], 'commonmark\parse' => ['CommonMark\Node', 'content'=>'string', 'options='=>'int'], 'commonmark\parser::finish' => ['CommonMark\Node'], 'commonmark\parser::parse' => ['void', 'buffer'=>'string'], 'commonmark\render' => ['string', 'node'=>'CommonMark\Node', 'options='=>'int', 'width='=>'int'], 'commonmark\render\html' => ['string', 'node'=>'CommonMark\Node', 'options='=>'int'], 'commonmark\render\latex' => ['string', 'node'=>'CommonMark\Node', 'options='=>'int', 'width='=>'int'], 'commonmark\render\man' => ['string', 'node'=>'CommonMark\Node', 'options='=>'int', 'width='=>'int'], 'commonmark\render\xml' => ['string', 'node'=>'CommonMark\Node', 'options='=>'int'], 'compact' => ['array', 'var_name'=>'string|array', '...var_names='=>'string|array'], 'componere\abstract\definition::addInterface' => ['Componere\Abstract\Definition', 'interface'=>'string'], 'componere\abstract\definition::addMethod' => ['Componere\Abstract\Definition', 'name'=>'string', 'method'=>'Componere\Method'], 'componere\abstract\definition::addTrait' => ['Componere\Abstract\Definition', 'trait'=>'string'], 'componere\abstract\definition::getReflector' => ['ReflectionClass'], 'componere\cast' => ['object', 'arg1'=>'string', 'object'=>'object'], 'componere\cast_by_ref' => ['object', 'arg1'=>'string', 'object'=>'object'], 'componere\definition::addConstant' => ['Componere\Definition', 'name'=>'string', 'value'=>'Componere\Value'], 'componere\definition::addProperty' => ['Componere\Definition', 'name'=>'string', 'value'=>'Componere\Value'], 'componere\definition::getClosure' => ['Closure', 'name'=>'string'], 'componere\definition::getClosures' => ['Closure[]'], 'componere\definition::isRegistered' => ['bool'], 'componere\definition::register' => ['void'], 'componere\method::getReflector' => ['ReflectionMethod'], 'componere\method::setPrivate' => ['Method'], 'componere\method::setProtected' => ['Method'], 'componere\method::setStatic' => ['Method'], 'componere\patch::apply' => ['void'], 'componere\patch::derive' => ['Componere\Patch', 'instance'=>'object'], 'componere\patch::getClosure' => ['Closure', 'name'=>'string'], 'componere\patch::getClosures' => ['Closure[]'], 'componere\patch::isApplied' => ['bool'], 'componere\patch::revert' => ['void'], 'componere\value::hasDefault' => ['bool'], 'componere\value::isPrivate' => ['bool'], 'componere\value::isProtected' => ['bool'], 'componere\value::isStatic' => ['bool'], 'componere\value::setPrivate' => ['Value'], 'componere\value::setProtected' => ['Value'], 'componere\value::setStatic' => ['Value'], 'confirm_pdo_ibm_compiled' => [''], 'connection_aborted' => ['int'], 'connection_status' => ['int'], 'connection_timeout' => ['int'], 'constant' => ['mixed', 'name'=>'string'], 'convert_cyr_string' => ['string', 'string'=>'string', 'from'=>'string', 'to'=>'string'], 'convert_uudecode' => ['string', 'string'=>'string'], 'convert_uuencode' => ['string', 'string'=>'string'], 'copy' => ['bool', 'from'=>'string', 'to'=>'string', 'context='=>'resource'], 'cos' => ['float', 'num'=>'float'], 'cosh' => ['float', 'num'=>'float'], 'count' => ['int<0, max>', 'value'=>'Countable|array|SimpleXMLElement', 'mode='=>'int'], 'count_chars' => ['array|false', 'input'=>'string', 'mode='=>'0|1|2'], 'count_chars\'1' => ['string|false', 'input'=>'string', 'mode='=>'3|4'], 'crack_check' => ['bool', 'dictionary'=>'', 'password'=>'string'], 'crack_closedict' => ['bool', 'dictionary='=>'resource'], 'crack_getlastmessage' => ['string'], 'crack_opendict' => ['resource|false', 'dictionary'=>'string'], 'crash' => [''], 'crc32' => ['int', 'string'=>'string'], 'create_function' => ['string', 'args'=>'string', 'code'=>'string'], 'crypt' => ['string', 'string'=>'string', 'salt='=>'string'], 'ctype_alnum' => ['bool', 'text'=>'string|int'], 'ctype_alpha' => ['bool', 'text'=>'string|int'], 'ctype_cntrl' => ['bool', 'text'=>'string|int'], 'ctype_digit' => ['bool', 'text'=>'string|int'], 'ctype_graph' => ['bool', 'text'=>'string|int'], 'ctype_lower' => ['bool', 'text'=>'string|int'], 'ctype_print' => ['bool', 'text'=>'string|int'], 'ctype_punct' => ['bool', 'text'=>'string|int'], 'ctype_space' => ['bool', 'text'=>'string|int'], 'ctype_upper' => ['bool', 'text'=>'string|int'], 'ctype_xdigit' => ['bool', 'text'=>'string|int'], 'cubrid_affected_rows' => ['int', 'req_identifier='=>''], 'cubrid_bind' => ['bool', 'req_identifier'=>'resource', 'bind_param'=>'int', 'bind_value'=>'mixed', 'bind_value_type='=>'string'], 'cubrid_client_encoding' => ['string', 'conn_identifier='=>''], 'cubrid_close' => ['bool', 'conn_identifier='=>''], 'cubrid_close_prepare' => ['bool', 'req_identifier'=>'resource'], 'cubrid_close_request' => ['bool', 'req_identifier'=>'resource'], 'cubrid_col_get' => ['array', 'conn_identifier'=>'resource', 'oid'=>'string', 'attr_name'=>'string'], 'cubrid_col_size' => ['int', 'conn_identifier'=>'resource', 'oid'=>'string', 'attr_name'=>'string'], 'cubrid_column_names' => ['array', 'req_identifier'=>'resource'], 'cubrid_column_types' => ['array', 'req_identifier'=>'resource'], 'cubrid_commit' => ['bool', 'conn_identifier'=>'resource'], 'cubrid_connect' => ['resource', 'host'=>'string', 'port'=>'int', 'dbname'=>'string', 'userid='=>'string', 'passwd='=>'string'], 'cubrid_connect_with_url' => ['resource', 'conn_url'=>'string', 'userid='=>'string', 'passwd='=>'string'], 'cubrid_current_oid' => ['string', 'req_identifier'=>'resource'], 'cubrid_data_seek' => ['bool', 'req_identifier'=>'', 'row_number'=>'int'], 'cubrid_db_name' => ['string', 'result'=>'array', 'index'=>'int'], 'cubrid_db_parameter' => ['array', 'conn_identifier'=>'resource'], 'cubrid_disconnect' => ['bool', 'conn_identifier'=>'resource'], 'cubrid_drop' => ['bool', 'conn_identifier'=>'resource', 'oid'=>'string'], 'cubrid_errno' => ['int', 'conn_identifier='=>''], 'cubrid_error' => ['string', 'connection='=>''], 'cubrid_error_code' => ['int'], 'cubrid_error_code_facility' => ['int'], 'cubrid_error_msg' => ['string'], 'cubrid_execute' => ['bool', 'conn_identifier'=>'', 'sql'=>'string', 'option='=>'int', 'request_identifier='=>''], 'cubrid_fetch' => ['mixed', 'result'=>'resource', 'type='=>'int'], 'cubrid_fetch_array' => ['array', 'result'=>'resource', 'type='=>'int'], 'cubrid_fetch_assoc' => ['array', 'result'=>'resource'], 'cubrid_fetch_field' => ['object', 'result'=>'resource', 'field_offset='=>'int'], 'cubrid_fetch_lengths' => ['array', 'result'=>'resource'], 'cubrid_fetch_object' => ['object', 'result'=>'resource', 'class_name='=>'string', 'params='=>'array'], 'cubrid_fetch_row' => ['array', 'result'=>'resource'], 'cubrid_field_flags' => ['string', 'result'=>'resource', 'field_offset'=>'int'], 'cubrid_field_len' => ['int', 'result'=>'resource', 'field_offset'=>'int'], 'cubrid_field_name' => ['string', 'result'=>'resource', 'field_offset'=>'int'], 'cubrid_field_seek' => ['bool', 'result'=>'resource', 'field_offset='=>'int'], 'cubrid_field_table' => ['string', 'result'=>'resource', 'field_offset'=>'int'], 'cubrid_field_type' => ['string', 'result'=>'resource', 'field_offset'=>'int'], 'cubrid_free_result' => ['bool', 'req_identifier'=>'resource'], 'cubrid_get' => ['mixed', 'conn_identifier'=>'resource', 'oid'=>'string', 'attr='=>'mixed'], 'cubrid_get_autocommit' => ['bool', 'conn_identifier'=>'resource'], 'cubrid_get_charset' => ['string', 'conn_identifier'=>'resource'], 'cubrid_get_class_name' => ['string', 'conn_identifier'=>'resource', 'oid'=>'string'], 'cubrid_get_client_info' => ['string'], 'cubrid_get_db_parameter' => ['array', 'conn_identifier'=>'resource'], 'cubrid_get_query_timeout' => ['int', 'req_identifier'=>'resource'], 'cubrid_get_server_info' => ['string', 'conn_identifier'=>'resource'], 'cubrid_insert_id' => ['string', 'conn_identifier='=>'resource'], 'cubrid_is_instance' => ['int', 'conn_identifier'=>'resource', 'oid'=>'string'], 'cubrid_list_dbs' => ['array', 'conn_identifier'=>'resource'], 'cubrid_load_from_glo' => ['int', 'conn_identifier'=>'', 'oid'=>'string', 'file_name'=>'string'], 'cubrid_lob2_bind' => ['bool', 'req_identifier'=>'resource', 'bind_index'=>'int', 'bind_value'=>'mixed', 'bind_value_type='=>'string'], 'cubrid_lob2_close' => ['bool', 'lob_identifier'=>'resource'], 'cubrid_lob2_export' => ['bool', 'lob_identifier'=>'resource', 'file_name'=>'string'], 'cubrid_lob2_import' => ['bool', 'lob_identifier'=>'resource', 'file_name'=>'string'], 'cubrid_lob2_new' => ['resource', 'conn_identifier='=>'resource', 'type='=>'string'], 'cubrid_lob2_read' => ['string', 'lob_identifier'=>'resource', 'length'=>'int'], 'cubrid_lob2_seek' => ['bool', 'lob_identifier'=>'resource', 'offset'=>'int', 'origin='=>'int'], 'cubrid_lob2_seek64' => ['bool', 'lob_identifier'=>'resource', 'offset'=>'string', 'origin='=>'int'], 'cubrid_lob2_size' => ['int', 'lob_identifier'=>'resource'], 'cubrid_lob2_size64' => ['string', 'lob_identifier'=>'resource'], 'cubrid_lob2_tell' => ['int', 'lob_identifier'=>'resource'], 'cubrid_lob2_tell64' => ['string', 'lob_identifier'=>'resource'], 'cubrid_lob2_write' => ['bool', 'lob_identifier'=>'resource', 'buf'=>'string'], 'cubrid_lob_close' => ['bool', 'lob_identifier_array'=>'array'], 'cubrid_lob_export' => ['bool', 'conn_identifier'=>'resource', 'lob_identifier'=>'resource', 'path_name'=>'string'], 'cubrid_lob_get' => ['array', 'conn_identifier'=>'resource', 'sql'=>'string'], 'cubrid_lob_send' => ['bool', 'conn_identifier'=>'resource', 'lob_identifier'=>'resource'], 'cubrid_lob_size' => ['string', 'lob_identifier'=>'resource'], 'cubrid_lock_read' => ['bool', 'conn_identifier'=>'resource', 'oid'=>'string'], 'cubrid_lock_write' => ['bool', 'conn_identifier'=>'resource', 'oid'=>'string'], 'cubrid_move_cursor' => ['int', 'req_identifier'=>'resource', 'offset'=>'int', 'origin='=>'int'], 'cubrid_new_glo' => ['string', 'conn_identifier'=>'', 'class_name'=>'string', 'file_name'=>'string'], 'cubrid_next_result' => ['bool', 'result'=>'resource'], 'cubrid_num_cols' => ['int', 'req_identifier'=>'resource'], 'cubrid_num_fields' => ['int', 'result'=>'resource'], 'cubrid_num_rows' => ['int', 'req_identifier'=>'resource'], 'cubrid_pconnect' => ['resource', 'host'=>'string', 'port'=>'int', 'dbname'=>'string', 'userid='=>'string', 'passwd='=>'string'], 'cubrid_pconnect_with_url' => ['resource', 'conn_url'=>'string', 'userid='=>'string', 'passwd='=>'string'], 'cubrid_ping' => ['bool', 'conn_identifier='=>''], 'cubrid_prepare' => ['resource', 'conn_identifier'=>'resource', 'prepare_stmt'=>'string', 'option='=>'int'], 'cubrid_put' => ['bool', 'conn_identifier'=>'resource', 'oid'=>'string', 'attr='=>'string', 'value='=>'mixed'], 'cubrid_query' => ['resource', 'query'=>'string', 'conn_identifier='=>''], 'cubrid_real_escape_string' => ['string', 'unescaped_string'=>'string', 'conn_identifier='=>''], 'cubrid_result' => ['string', 'result'=>'resource', 'row'=>'int', 'field='=>''], 'cubrid_rollback' => ['bool', 'conn_identifier'=>'resource'], 'cubrid_save_to_glo' => ['int', 'conn_identifier'=>'', 'oid'=>'string', 'file_name'=>'string'], 'cubrid_schema' => ['array', 'conn_identifier'=>'resource', 'schema_type'=>'int', 'class_name='=>'string', 'attr_name='=>'string'], 'cubrid_send_glo' => ['int', 'conn_identifier'=>'', 'oid'=>'string'], 'cubrid_seq_add' => ['bool', 'conn_identifier'=>'resource', 'oid'=>'string', 'attr_name'=>'string', 'seq_element'=>'string'], 'cubrid_seq_drop' => ['bool', 'conn_identifier'=>'resource', 'oid'=>'string', 'attr_name'=>'string', 'index'=>'int'], 'cubrid_seq_insert' => ['bool', 'conn_identifier'=>'resource', 'oid'=>'string', 'attr_name'=>'string', 'index'=>'int', 'seq_element'=>'string'], 'cubrid_seq_put' => ['bool', 'conn_identifier'=>'resource', 'oid'=>'string', 'attr_name'=>'string', 'index'=>'int', 'seq_element'=>'string'], 'cubrid_set_add' => ['bool', 'conn_identifier'=>'resource', 'oid'=>'string', 'attr_name'=>'string', 'set_element'=>'string'], 'cubrid_set_autocommit' => ['bool', 'conn_identifier'=>'resource', 'mode'=>'bool'], 'cubrid_set_db_parameter' => ['bool', 'conn_identifier'=>'resource', 'param_type'=>'int', 'param_value'=>'int'], 'cubrid_set_drop' => ['bool', 'conn_identifier'=>'resource', 'oid'=>'string', 'attr_name'=>'string', 'set_element'=>'string'], 'cubrid_set_query_timeout' => ['bool', 'req_identifier'=>'resource', 'timeout'=>'int'], 'cubrid_unbuffered_query' => ['resource', 'query'=>'string', 'conn_identifier='=>''], 'cubrid_version' => ['string'], 'curl_close' => ['void', 'ch'=>'resource'], 'curl_copy_handle' => ['resource|false', 'ch'=>'resource'], 'curl_errno' => ['int', 'ch'=>'resource'], 'curl_error' => ['string', 'ch'=>'resource'], 'curl_escape' => ['string|false', 'ch'=>'resource', 'string'=>'string'], 'curl_exec' => ['bool|string', 'ch'=>'resource'], 'curl_file_create' => ['CURLFile', 'filename'=>'string', 'mimetype='=>'string', 'postfilename='=>'string'], 'curl_getinfo' => ['mixed', 'ch'=>'resource', 'option='=>'int'], 'curl_init' => ['resource|false', 'url='=>'string'], 'curl_multi_add_handle' => ['int', 'mh'=>'resource', 'ch'=>'resource'], 'curl_multi_close' => ['void', 'mh'=>'resource'], 'curl_multi_exec' => ['int', 'mh'=>'resource', '&w_still_running'=>'int'], 'curl_multi_getcontent' => ['string', 'ch'=>'resource'], 'curl_multi_info_read' => ['array|false', 'mh'=>'resource', '&w_msgs_in_queue='=>'int'], 'curl_multi_init' => ['resource'], 'curl_multi_remove_handle' => ['int', 'mh'=>'resource', 'ch'=>'resource'], 'curl_multi_select' => ['int', 'mh'=>'resource', 'timeout='=>'float'], 'curl_multi_setopt' => ['bool', 'mh'=>'resource', 'option'=>'int', 'value'=>'mixed'], 'curl_multi_strerror' => ['?string', 'error_code'=>'int'], 'curl_pause' => ['int', 'ch'=>'resource', 'bitmask'=>'int'], 'curl_reset' => ['void', 'ch'=>'resource'], 'curl_setopt' => ['bool', 'ch'=>'resource', 'option'=>'int', 'value'=>'callable|mixed'], 'curl_setopt_array' => ['bool', 'ch'=>'resource', 'options'=>'array'], 'curl_share_close' => ['void', 'sh'=>'resource'], 'curl_share_init' => ['resource'], 'curl_share_setopt' => ['bool', 'sh'=>'resource', 'option'=>'int', 'value'=>'mixed'], 'curl_strerror' => ['?string', 'error_code'=>'int'], 'curl_unescape' => ['string|false', 'ch'=>'resource', 'string'=>'string'], 'curl_version' => ['array', 'version='=>'int'], 'current' => ['mixed|false', 'array'=>'array|object'], 'cyrus_authenticate' => ['void', 'connection'=>'resource', 'mechlist='=>'string', 'service='=>'string', 'user='=>'string', 'minssf='=>'int', 'maxssf='=>'int', 'authname='=>'string', 'password='=>'string'], 'cyrus_bind' => ['bool', 'connection'=>'resource', 'callbacks'=>'array'], 'cyrus_close' => ['bool', 'connection'=>'resource'], 'cyrus_connect' => ['resource', 'host='=>'string', 'port='=>'string', 'flags='=>'int'], 'cyrus_query' => ['array', 'connection'=>'resource', 'query'=>'string'], 'cyrus_unbind' => ['bool', 'connection'=>'resource', 'trigger_name'=>'string'], 'date' => ['string', 'format'=>'string', 'timestamp='=>'int'], 'date_add' => ['DateTime|false', 'object'=>'DateTime', 'interval'=>'DateInterval'], 'date_create' => ['DateTime|false', 'datetime='=>'string', 'timezone='=>'?DateTimeZone'], 'date_create_from_format' => ['DateTime|false', 'format'=>'string', 'datetime'=>'string', 'timezone='=>'?\DateTimeZone'], 'date_create_immutable' => ['DateTimeImmutable|false', 'datetime='=>'string', 'timezone='=>'?DateTimeZone'], 'date_create_immutable_from_format' => ['DateTimeImmutable|false', 'format'=>'string', 'datetime'=>'string', 'timezone='=>'?DateTimeZone'], 'date_date_set' => ['DateTime|false', 'object'=>'DateTime', 'year'=>'int', 'month'=>'int', 'day'=>'int'], 'date_default_timezone_get' => ['non-empty-string'], 'date_default_timezone_set' => ['bool', 'timezoneId'=>'non-empty-string'], 'date_diff' => ['DateInterval|false', 'baseObject'=>'DateTimeInterface', 'targetObject'=>'DateTimeInterface', 'absolute='=>'bool'], 'date_format' => ['string|false', 'object'=>'DateTimeInterface', 'format'=>'string'], 'date_get_last_errors' => ['array{warning_count:int,warnings:array,error_count:int,errors:array}|false'], 'date_interval_create_from_date_string' => ['DateInterval', 'datetime'=>'string'], 'date_interval_format' => ['string', 'object'=>'DateInterval', 'format'=>'string'], 'date_isodate_set' => ['DateTime', 'object'=>'DateTime', 'year'=>'int', 'week'=>'int', 'dayOfWeek='=>'int'], 'date_modify' => ['DateTime|false', 'object'=>'DateTime', 'modifier'=>'string'], 'date_offset_get' => ['int|false', 'object'=>'DateTimeInterface'], 'date_parse' => ['array|false', 'datetime'=>'string'], 'date_parse_from_format' => ['array', 'format'=>'string', 'datetime'=>'string'], 'date_sub' => ['DateTime|false', 'object'=>'DateTime', 'interval'=>'DateInterval'], 'date_sun_info' => ['array|false', 'timestamp'=>'int', 'latitude'=>'float', 'longitude'=>'float'], 'date_sunrise' => ['string|int|float|false', 'timestamp'=>'int', 'returnFormat='=>'int', 'latitude='=>'float', 'longitude='=>'float', 'zenith='=>'float', 'utcOffset='=>'float'], 'date_sunset' => ['string|int|float|false', 'timestamp'=>'int', 'returnFormat='=>'int', 'latitude='=>'float', 'longitude='=>'float', 'zenith='=>'float', 'utcOffset='=>'float'], 'date_time_set' => ['DateTime|false', 'object'=>'', 'hour'=>'', 'minute'=>'', 'second='=>'', 'microsecond='=>''], 'date_timestamp_get' => ['int', 'object'=>'DateTimeInterface'], 'date_timestamp_set' => ['DateTime|false', 'object'=>'DateTime', 'timestamp'=>'int'], 'date_timezone_get' => ['DateTimeZone|false', 'object'=>'DateTimeInterface'], 'date_timezone_set' => ['DateTime|false', 'object'=>'DateTime', 'timezone'=>'DateTimeZone'], 'datefmt_create' => ['?IntlDateFormatter', 'locale'=>'?string', 'dateType'=>'int', 'timeType'=>'int', 'timezone='=>'DateTimeZone|IntlTimeZone|string|null', 'calendar='=>'IntlCalendar|int|null', 'pattern='=>'string'], 'datefmt_format' => ['string|false', 'formatter'=>'IntlDateFormatter', 'datetime'=>'DateTime|IntlCalendar|array|int'], 'datefmt_format_object' => ['string|false', 'datetime'=>'object', 'format='=>'mixed', 'locale='=>'?string'], 'datefmt_get_calendar' => ['int', 'formatter'=>'IntlDateFormatter'], 'datefmt_get_calendar_object' => ['IntlCalendar|false|null', 'formatter'=>'IntlDateFormatter'], 'datefmt_get_datetype' => ['int', 'formatter'=>'IntlDateFormatter'], 'datefmt_get_error_code' => ['int', 'formatter'=>'IntlDateFormatter'], 'datefmt_get_error_message' => ['string', 'formatter'=>'IntlDateFormatter'], 'datefmt_get_locale' => ['string|false', 'formatter'=>'IntlDateFormatter', 'type='=>'int'], 'datefmt_get_pattern' => ['string', 'formatter'=>'IntlDateFormatter'], 'datefmt_get_timetype' => ['int', 'formatter'=>'IntlDateFormatter'], 'datefmt_get_timezone' => ['IntlTimeZone|false', 'formatter'=>'IntlDateFormatter'], 'datefmt_get_timezone_id' => ['string|false', 'formatter'=>'IntlDateFormatter'], 'datefmt_is_lenient' => ['bool', 'formatter'=>'IntlDateFormatter'], 'datefmt_localtime' => ['array|false', 'formatter'=>'IntlDateFormatter', 'string'=>'string', '&rw_offset='=>'int'], 'datefmt_parse' => ['float|int|false', 'formatter'=>'IntlDateFormatter', 'string'=>'string', '&rw_offset='=>'int'], 'datefmt_set_calendar' => ['bool', 'formatter'=>'IntlDateFormatter', 'calendar'=>'IntlCalendar|int|null'], 'datefmt_set_lenient' => ['void', 'formatter'=>'IntlDateFormatter', 'lenient'=>'bool'], 'datefmt_set_pattern' => ['bool', 'formatter'=>'IntlDateFormatter', 'pattern'=>'string'], 'datefmt_set_timezone' => ['false|null', 'formatter'=>'IntlDateFormatter', 'timezone'=>'IntlTimeZone|DateTimeZone|string|null'], 'db2_autocommit' => ['0|1|bool', 'connection'=>'resource', 'value='=>'0|1'], 'db2_bind_param' => ['bool', 'stmt'=>'resource', 'parameter_number'=>'int', 'variable_name'=>'string', 'parameter_type='=>'int', 'data_type='=>'int', 'precision='=>'int', 'scale='=>'int'], 'db2_client_info' => ['stdClass|false', 'connection'=>'resource'], 'db2_close' => ['bool', 'connection'=>'resource'], 'db2_column_privileges' => ['resource|false', 'connection'=>'resource', 'qualifier='=>'?string', 'schema='=>'?string', 'table_name='=>'?string', 'column_name='=>'?string'], 'db2_columns' => ['resource|false', 'connection'=>'resource', 'qualifier='=>'?string', 'schema='=>'?string', 'table_name='=>'?string', 'column_name='=>'?string'], 'db2_commit' => ['bool', 'connection'=>'resource'], 'db2_conn_error' => ['string', 'connection='=>'resource'], 'db2_conn_errormsg' => ['string', 'connection='=>'resource'], 'db2_connect' => ['resource|false', 'database'=>'string', 'username'=>'?string', 'password'=>'?string', 'options='=>'array'], 'db2_cursor_type' => ['int', 'stmt'=>'resource'], 'db2_escape_string' => ['string', 'string_literal'=>'string'], 'db2_exec' => ['resource|false', 'connection'=>'resource', 'statement'=>'string', 'options='=>'array'], 'db2_execute' => ['bool', 'stmt'=>'resource', 'parameters='=>'array'], 'db2_fetch_array' => ['array|false', 'stmt'=>'resource', 'row_number='=>'?int'], 'db2_fetch_assoc' => ['array|false', 'stmt'=>'resource', 'row_number='=>'?int'], 'db2_fetch_both' => ['array|false', 'stmt'=>'resource', 'row_number='=>'?int'], 'db2_fetch_object' => ['stdClass|false', 'stmt'=>'resource', 'row_number='=>'?int'], 'db2_fetch_row' => ['bool', 'stmt'=>'resource', 'row_number='=>'?int'], 'db2_field_display_size' => ['int|false', 'stmt'=>'resource', 'column'=>'string|int'], 'db2_field_name' => ['string|false', 'stmt'=>'resource', 'column'=>'string|int'], 'db2_field_num' => ['int|false', 'stmt'=>'resource', 'column'=>'string|int'], 'db2_field_precision' => ['int|false', 'stmt'=>'resource', 'column'=>'string|int'], 'db2_field_scale' => ['int|false', 'stmt'=>'resource', 'column'=>'string|int'], 'db2_field_type' => ['string|false', 'stmt'=>'resource', 'column'=>'string|int'], 'db2_field_width' => ['int|false', 'stmt'=>'resource', 'column'=>'string|int'], 'db2_foreign_keys' => ['resource|false', 'connection'=>'resource', 'qualifier'=>'?string', 'schema'=>'?string', 'table_name'=>'string'], 'db2_free_result' => ['bool', 'stmt'=>'resource'], 'db2_free_stmt' => ['bool', 'stmt'=>'resource'], 'db2_get_option' => ['string|false', 'resource'=>'resource', 'option'=>'string'], 'db2_last_insert_id' => ['string|null', 'resource'=>'resource'], 'db2_lob_read' => ['string|false', 'stmt'=>'resource', 'colnum'=>'int', 'length'=>'int'], 'db2_next_result' => ['resource|false', 'stmt'=>'resource'], 'db2_num_fields' => ['int|false', 'stmt'=>'resource'], 'db2_num_rows' => ['int|false', 'stmt'=>'resource'], 'db2_pclose' => ['bool', 'resource'=>'resource'], 'db2_pconnect' => ['resource|false', 'database'=>'string', 'username'=>'?string', 'password'=>'?string', 'options='=>'array'], 'db2_prepare' => ['resource|false', 'connection'=>'resource', 'statement'=>'string', 'options='=>'array'], 'db2_primary_keys' => ['resource|false', 'connection'=>'resource', 'qualifier'=>'?string', 'schema'=>'?string', 'table_name'=>'string'], 'db2_primarykeys' => [''], 'db2_procedure_columns' => ['resource|false', 'connection'=>'resource', 'qualifier'=>'?string', 'schema'=>'string', 'procedure'=>'string', 'parameter'=>'?string'], 'db2_procedurecolumns' => [''], 'db2_procedures' => ['resource|false', 'connection'=>'resource', 'qualifier'=>'?string', 'schema'=>'string', 'procedure'=>'string'], 'db2_result' => ['mixed', 'stmt'=>'resource', 'column'=>'string|int'], 'db2_rollback' => ['bool', 'connection'=>'resource'], 'db2_server_info' => ['stdClass|false', 'connection'=>'resource'], 'db2_set_option' => ['bool', 'resource'=>'resource', 'options'=>'array', 'type'=>'int'], 'db2_setoption' => [''], 'db2_special_columns' => ['resource|false', 'connection'=>'resource', 'qualifier'=>'?string', 'schema'=>'string', 'table_name'=>'string', 'scope'=>'int'], 'db2_specialcolumns' => [''], 'db2_statistics' => ['resource|false', 'connection'=>'resource', 'qualifier'=>'?string', 'schema'=>'?string', 'table_name'=>'string', 'unique'=>'bool'], 'db2_stmt_error' => ['string', 'stmt='=>'resource'], 'db2_stmt_errormsg' => ['string', 'stmt='=>'resource'], 'db2_table_privileges' => ['resource|false', 'connection'=>'resource', 'qualifier='=>'?string', 'schema='=>'?string', 'table_name='=>'?string'], 'db2_tableprivileges' => [''], 'db2_tables' => ['resource|false', 'connection'=>'resource', 'qualifier='=>'?string', 'schema='=>'?string', 'table_name='=>'?string', 'table_type='=>'?string'], 'dba_close' => ['void', 'dba'=>'resource'], 'dba_delete' => ['bool', 'key'=>'array|string', 'dba'=>'resource'], 'dba_exists' => ['bool', 'key'=>'array|string', 'dba'=>'resource'], 'dba_fetch' => ['string|false', 'key'=>'array|string', 'skip'=>'int', 'dba'=>'resource'], 'dba_fetch\'1' => ['string|false', 'key'=>'array|string', 'skip'=>'resource'], 'dba_firstkey' => ['string', 'dba'=>'resource'], 'dba_handlers' => ['array', 'full_info='=>'bool'], 'dba_insert' => ['bool', 'key'=>'array|string', 'value'=>'string', 'dba'=>'resource'], 'dba_key_split' => ['array|false', 'key'=>'string|false|null'], 'dba_list' => ['array'], 'dba_nextkey' => ['string', 'dba'=>'resource'], 'dba_open' => ['resource', 'path'=>'string', 'mode'=>'string', 'handler='=>'string', '...handler_params='=>'string'], 'dba_optimize' => ['bool', 'dba'=>'resource'], 'dba_popen' => ['resource', 'path'=>'string', 'mode'=>'string', 'handler='=>'string', '...handler_params='=>'string'], 'dba_replace' => ['bool', 'key'=>'array|string', 'value'=>'string', 'dba'=>'resource'], 'dba_sync' => ['bool', 'dba'=>'resource'], 'dbase_add_record' => ['bool', 'dbase_identifier'=>'resource', 'record'=>'array'], 'dbase_close' => ['bool', 'dbase_identifier'=>'resource'], 'dbase_create' => ['resource|false', 'filename'=>'string', 'fields'=>'array'], 'dbase_delete_record' => ['bool', 'dbase_identifier'=>'resource', 'record_number'=>'int'], 'dbase_get_header_info' => ['array', 'dbase_identifier'=>'resource'], 'dbase_get_record' => ['array', 'dbase_identifier'=>'resource', 'record_number'=>'int'], 'dbase_get_record_with_names' => ['array', 'dbase_identifier'=>'resource', 'record_number'=>'int'], 'dbase_numfields' => ['int', 'dbase_identifier'=>'resource'], 'dbase_numrecords' => ['int', 'dbase_identifier'=>'resource'], 'dbase_open' => ['resource|false', 'filename'=>'string', 'mode'=>'int'], 'dbase_pack' => ['bool', 'dbase_identifier'=>'resource'], 'dbase_replace_record' => ['bool', 'dbase_identifier'=>'resource', 'record'=>'array', 'record_number'=>'int'], 'dbplus_add' => ['int', 'relation'=>'resource', 'tuple'=>'array'], 'dbplus_aql' => ['resource', 'query'=>'string', 'server='=>'string', 'dbpath='=>'string'], 'dbplus_chdir' => ['string', 'newdir='=>'string'], 'dbplus_close' => ['mixed', 'relation'=>'resource'], 'dbplus_curr' => ['int', 'relation'=>'resource', 'tuple'=>'array'], 'dbplus_errcode' => ['string', 'errno='=>'int'], 'dbplus_errno' => ['int'], 'dbplus_find' => ['int', 'relation'=>'resource', 'constraints'=>'array', 'tuple'=>'mixed'], 'dbplus_first' => ['int', 'relation'=>'resource', 'tuple'=>'array'], 'dbplus_flush' => ['int', 'relation'=>'resource'], 'dbplus_freealllocks' => ['int'], 'dbplus_freelock' => ['int', 'relation'=>'resource', 'tuple'=>'string'], 'dbplus_freerlocks' => ['int', 'relation'=>'resource'], 'dbplus_getlock' => ['int', 'relation'=>'resource', 'tuple'=>'string'], 'dbplus_getunique' => ['int', 'relation'=>'resource', 'uniqueid'=>'int'], 'dbplus_info' => ['int', 'relation'=>'resource', 'key'=>'string', 'result'=>'array'], 'dbplus_last' => ['int', 'relation'=>'resource', 'tuple'=>'array'], 'dbplus_lockrel' => ['int', 'relation'=>'resource'], 'dbplus_next' => ['int', 'relation'=>'resource', 'tuple'=>'array'], 'dbplus_open' => ['resource', 'name'=>'string'], 'dbplus_prev' => ['int', 'relation'=>'resource', 'tuple'=>'array'], 'dbplus_rchperm' => ['int', 'relation'=>'resource', 'mask'=>'int', 'user'=>'string', 'group'=>'string'], 'dbplus_rcreate' => ['resource', 'name'=>'string', 'domlist'=>'mixed', 'overwrite='=>'bool'], 'dbplus_rcrtexact' => ['mixed', 'name'=>'string', 'relation'=>'resource', 'overwrite='=>'bool'], 'dbplus_rcrtlike' => ['mixed', 'name'=>'string', 'relation'=>'resource', 'overwrite='=>'int'], 'dbplus_resolve' => ['array', 'relation_name'=>'string'], 'dbplus_restorepos' => ['int', 'relation'=>'resource', 'tuple'=>'array'], 'dbplus_rkeys' => ['mixed', 'relation'=>'resource', 'domlist'=>'mixed'], 'dbplus_ropen' => ['resource', 'name'=>'string'], 'dbplus_rquery' => ['resource', 'query'=>'string', 'dbpath='=>'string'], 'dbplus_rrename' => ['int', 'relation'=>'resource', 'name'=>'string'], 'dbplus_rsecindex' => ['mixed', 'relation'=>'resource', 'domlist'=>'mixed', 'type'=>'int'], 'dbplus_runlink' => ['int', 'relation'=>'resource'], 'dbplus_rzap' => ['int', 'relation'=>'resource'], 'dbplus_savepos' => ['int', 'relation'=>'resource'], 'dbplus_setindex' => ['int', 'relation'=>'resource', 'idx_name'=>'string'], 'dbplus_setindexbynumber' => ['int', 'relation'=>'resource', 'idx_number'=>'int'], 'dbplus_sql' => ['resource', 'query'=>'string', 'server='=>'string', 'dbpath='=>'string'], 'dbplus_tcl' => ['string', 'sid'=>'int', 'script'=>'string'], 'dbplus_tremove' => ['int', 'relation'=>'resource', 'tuple'=>'array', 'current='=>'array'], 'dbplus_undo' => ['int', 'relation'=>'resource'], 'dbplus_undoprepare' => ['int', 'relation'=>'resource'], 'dbplus_unlockrel' => ['int', 'relation'=>'resource'], 'dbplus_unselect' => ['int', 'relation'=>'resource'], 'dbplus_update' => ['int', 'relation'=>'resource', 'old'=>'array', 'new'=>'array'], 'dbplus_xlockrel' => ['int', 'relation'=>'resource'], 'dbplus_xunlockrel' => ['int', 'relation'=>'resource'], 'dbx_close' => ['int', 'link_identifier'=>'object'], 'dbx_compare' => ['int', 'row_a'=>'array', 'row_b'=>'array', 'column_key'=>'string', 'flags='=>'int'], 'dbx_connect' => ['object', 'module'=>'mixed', 'host'=>'string', 'database'=>'string', 'username'=>'string', 'password'=>'string', 'persistent='=>'int'], 'dbx_error' => ['string', 'link_identifier'=>'object'], 'dbx_escape_string' => ['string', 'link_identifier'=>'object', 'text'=>'string'], 'dbx_fetch_row' => ['mixed', 'result_identifier'=>'object'], 'dbx_query' => ['mixed', 'link_identifier'=>'object', 'sql_statement'=>'string', 'flags='=>'int'], 'dbx_sort' => ['bool', 'result'=>'object', 'user_compare_function'=>'string'], 'dcgettext' => ['string', 'domain'=>'string', 'message'=>'string', 'category'=>'int'], 'dcngettext' => ['string', 'domain'=>'string', 'singular'=>'string', 'plural'=>'string', 'count'=>'int', 'category'=>'int'], 'deaggregate' => ['', 'object'=>'object', 'class_name='=>'string'], 'debug_backtrace' => ['list', 'options='=>'int', 'limit='=>'int'], 'debug_print_backtrace' => ['void', 'options='=>'int', 'limit='=>'int'], 'debug_zval_dump' => ['void', 'value'=>'mixed', '...values='=>'mixed'], 'debugger_connect' => [''], 'debugger_connector_pid' => [''], 'debugger_get_server_start_time' => [''], 'debugger_print' => [''], 'debugger_start_debug' => [''], 'decbin' => ['string', 'num'=>'int'], 'dechex' => ['string', 'num'=>'int'], 'decoct' => ['string', 'num'=>'int'], 'define' => ['bool', 'constant_name'=>'string', 'value'=>'array|scalar|null', 'case_insensitive='=>'bool'], 'define_syslog_variables' => ['void'], 'defined' => ['bool', 'constant_name'=>'string'], 'deflate_add' => ['string|false', 'context'=>'resource', 'data'=>'string', 'flush_mode='=>'int'], 'deflate_init' => ['resource|false', 'encoding'=>'int', 'options='=>'array'], 'deg2rad' => ['float', 'num'=>'float'], 'dgettext' => ['string', 'domain'=>'string', 'message'=>'string'], 'dio_close' => ['void', 'fd'=>'resource'], 'dio_fcntl' => ['mixed', 'fd'=>'resource', 'cmd'=>'int', 'args='=>'mixed'], 'dio_open' => ['resource|false', 'filename'=>'string', 'flags'=>'int', 'mode='=>'int'], 'dio_read' => ['string', 'fd'=>'resource', 'length='=>'int'], 'dio_seek' => ['int', 'fd'=>'resource', 'pos'=>'int', 'whence='=>'int'], 'dio_stat' => ['?array', 'fd'=>'resource'], 'dio_tcsetattr' => ['bool', 'fd'=>'resource', 'options'=>'array'], 'dio_truncate' => ['bool', 'fd'=>'resource', 'offset'=>'int'], 'dio_write' => ['int', 'fd'=>'resource', 'data'=>'string', 'length='=>'int'], 'dir' => ['Directory|false', 'directory'=>'string', 'context='=>'resource'], 'dirname' => ['string', 'path'=>'string', 'levels='=>'int<1, max>'], 'disk_free_space' => ['float|false', 'directory'=>'string'], 'disk_total_space' => ['float|false', 'directory'=>'string'], 'diskfreespace' => ['float|false', 'directory'=>'string'], 'display_disabled_function' => [''], 'dl' => ['bool', 'extension_filename'=>'string'], 'dngettext' => ['string', 'domain'=>'string', 'singular'=>'string', 'plural'=>'string', 'count'=>'int'], 'dns_check_record' => ['bool', 'hostname'=>'string', 'type='=>'string'], 'dns_get_mx' => ['bool', 'hostname'=>'string', '&w_hosts'=>'array', '&w_weights='=>'array'], 'dns_get_record' => ['list|false', 'hostname'=>'string', 'type='=>'int', '&w_authoritative_name_servers='=>'array', '&w_additional_records='=>'array', 'raw='=>'bool'], 'dom_document_relaxNG_validate_file' => ['bool', 'filename'=>'string'], 'dom_document_relaxNG_validate_xml' => ['bool', 'source'=>'string'], 'dom_document_schema_validate' => ['bool', 'source'=>'string', 'flags'=>'int'], 'dom_document_schema_validate_file' => ['bool', 'filename'=>'string', 'flags'=>'int'], 'dom_document_xinclude' => ['int', 'options'=>'int'], 'dom_import_simplexml' => ['DOMElement|null', 'node'=>'SimpleXMLElement'], 'dom_xpath_evaluate' => ['', 'expr'=>'string', 'context'=>'DOMNode', 'registernodens'=>'bool'], 'dom_xpath_query' => ['DOMNodeList', 'expr'=>'string', 'context'=>'DOMNode', 'registernodens'=>'bool'], 'dom_xpath_register_ns' => ['bool', 'prefix'=>'string', 'uri'=>'string'], 'dom_xpath_register_php_functions' => [''], 'domxml_new_doc' => ['DomDocument', 'version'=>'string'], 'domxml_open_file' => ['DomDocument', 'filename'=>'string', 'mode='=>'int', 'error='=>'array'], 'domxml_open_mem' => ['DomDocument', 'string'=>'string', 'mode='=>'int', 'error='=>'array'], 'domxml_version' => ['string'], 'domxml_xmltree' => ['DomDocument', 'string'=>'string'], 'domxml_xslt_stylesheet' => ['DomXsltStylesheet', 'xsl_buf'=>'string'], 'domxml_xslt_stylesheet_doc' => ['DomXsltStylesheet', 'xsl_doc'=>'DOMDocument'], 'domxml_xslt_stylesheet_file' => ['DomXsltStylesheet', 'xsl_file'=>'string'], 'domxml_xslt_version' => ['int'], 'dotnet_load' => ['int', 'assembly_name'=>'string', 'datatype_name='=>'string', 'codepage='=>'int'], 'doubleval' => ['float', 'value'=>'mixed'], 'each' => ['array{0:int|string,key:int|string,1:mixed,value:mixed}', '&r_arr'=>'array'], 'easter_date' => ['int', 'year='=>'int', 'mode='=>'int'], 'easter_days' => ['int', 'year='=>'int', 'mode='=>'int'], 'echo' => ['void', 'arg1'=>'string', '...args='=>'string'], 'eio_busy' => ['resource', 'delay'=>'int', 'pri='=>'int', 'callback='=>'callable', 'data='=>'mixed'], 'eio_cancel' => ['void', 'req'=>'resource'], 'eio_chmod' => ['resource', 'path'=>'string', 'mode'=>'int', 'pri='=>'int', 'callback='=>'callable', 'data='=>'mixed'], 'eio_chown' => ['resource', 'path'=>'string', 'uid'=>'int', 'gid='=>'int', 'pri='=>'int', 'callback='=>'callable', 'data='=>'mixed'], 'eio_close' => ['resource', 'fd'=>'mixed', 'pri='=>'int', 'callback='=>'callable', 'data='=>'mixed'], 'eio_custom' => ['resource', 'execute'=>'callable', 'pri'=>'int', 'callback'=>'callable', 'data='=>'mixed'], 'eio_dup2' => ['resource', 'fd'=>'mixed', 'fd2'=>'mixed', 'pri='=>'int', 'callback='=>'callable', 'data='=>'mixed'], 'eio_event_loop' => ['bool'], 'eio_fallocate' => ['resource', 'fd'=>'mixed', 'mode'=>'int', 'offset'=>'int', 'length'=>'int', 'pri='=>'int', 'callback='=>'callable', 'data='=>'mixed'], 'eio_fchmod' => ['resource', 'fd'=>'mixed', 'mode'=>'int', 'pri='=>'int', 'callback='=>'callable', 'data='=>'mixed'], 'eio_fchown' => ['resource', 'fd'=>'mixed', 'uid'=>'int', 'gid='=>'int', 'pri='=>'int', 'callback='=>'callable', 'data='=>'mixed'], 'eio_fdatasync' => ['resource', 'fd'=>'mixed', 'pri='=>'int', 'callback='=>'callable', 'data='=>'mixed'], 'eio_fstat' => ['resource', 'fd'=>'mixed', 'pri'=>'int', 'callback'=>'callable', 'data='=>'mixed'], 'eio_fstatvfs' => ['resource', 'fd'=>'mixed', 'pri'=>'int', 'callback'=>'callable', 'data='=>'mixed'], 'eio_fsync' => ['resource', 'fd'=>'mixed', 'pri='=>'int', 'callback='=>'callable', 'data='=>'mixed'], 'eio_ftruncate' => ['resource', 'fd'=>'mixed', 'offset='=>'int', 'pri='=>'int', 'callback='=>'callable', 'data='=>'mixed'], 'eio_futime' => ['resource', 'fd'=>'mixed', 'atime'=>'float', 'mtime'=>'float', 'pri='=>'int', 'callback='=>'callable', 'data='=>'mixed'], 'eio_get_event_stream' => ['mixed'], 'eio_get_last_error' => ['string', 'req'=>'resource'], 'eio_grp' => ['resource', 'callback'=>'callable', 'data='=>'string'], 'eio_grp_add' => ['void', 'grp'=>'resource', 'req'=>'resource'], 'eio_grp_cancel' => ['void', 'grp'=>'resource'], 'eio_grp_limit' => ['void', 'grp'=>'resource', 'limit'=>'int'], 'eio_init' => ['void'], 'eio_link' => ['resource', 'path'=>'string', 'new_path'=>'string', 'pri='=>'int', 'callback='=>'callable', 'data='=>'mixed'], 'eio_lstat' => ['resource', 'path'=>'string', 'pri'=>'int', 'callback'=>'callable', 'data='=>'mixed'], 'eio_mkdir' => ['resource', 'path'=>'string', 'mode'=>'int', 'pri='=>'int', 'callback='=>'callable', 'data='=>'mixed'], 'eio_mknod' => ['resource', 'path'=>'string', 'mode'=>'int', 'dev'=>'int', 'pri='=>'int', 'callback='=>'callable', 'data='=>'mixed'], 'eio_nop' => ['resource', 'pri='=>'int', 'callback='=>'callable', 'data='=>'mixed'], 'eio_npending' => ['int'], 'eio_nready' => ['int'], 'eio_nreqs' => ['int'], 'eio_nthreads' => ['int'], 'eio_open' => ['resource', 'path'=>'string', 'flags'=>'int', 'mode'=>'int', 'pri'=>'int', 'callback'=>'callable', 'data='=>'mixed'], 'eio_poll' => ['int'], 'eio_read' => ['resource', 'fd'=>'mixed', 'length'=>'int', 'offset'=>'int', 'pri'=>'int', 'callback'=>'callable', 'data='=>'mixed'], 'eio_readahead' => ['resource', 'fd'=>'mixed', 'offset'=>'int', 'length'=>'int', 'pri='=>'int', 'callback='=>'callable', 'data='=>'mixed'], 'eio_readdir' => ['resource', 'path'=>'string', 'flags'=>'int', 'pri'=>'int', 'callback'=>'callable', 'data='=>'string'], 'eio_readlink' => ['resource', 'path'=>'string', 'pri'=>'int', 'callback'=>'callable', 'data='=>'string'], 'eio_realpath' => ['resource', 'path'=>'string', 'pri'=>'int', 'callback'=>'callable', 'data='=>'string'], 'eio_rename' => ['resource', 'path'=>'string', 'new_path'=>'string', 'pri='=>'int', 'callback='=>'callable', 'data='=>'mixed'], 'eio_rmdir' => ['resource', 'path'=>'string', 'pri='=>'int', 'callback='=>'callable', 'data='=>'mixed'], 'eio_seek' => ['resource', 'fd'=>'mixed', 'offset'=>'int', 'whence'=>'int', 'pri='=>'int', 'callback='=>'callable', 'data='=>'mixed'], 'eio_sendfile' => ['resource', 'out_fd'=>'mixed', 'in_fd'=>'mixed', 'offset'=>'int', 'length'=>'int', 'pri='=>'int', 'callback='=>'callable', 'data='=>'string'], 'eio_set_max_idle' => ['void', 'nthreads'=>'int'], 'eio_set_max_parallel' => ['void', 'nthreads'=>'int'], 'eio_set_max_poll_reqs' => ['void', 'nreqs'=>'int'], 'eio_set_max_poll_time' => ['void', 'nseconds'=>'float'], 'eio_set_min_parallel' => ['void', 'nthreads'=>'string'], 'eio_stat' => ['resource', 'path'=>'string', 'pri'=>'int', 'callback'=>'callable', 'data='=>'mixed'], 'eio_statvfs' => ['resource', 'path'=>'string', 'pri'=>'int', 'callback'=>'callable', 'data='=>'mixed'], 'eio_symlink' => ['resource', 'path'=>'string', 'new_path'=>'string', 'pri='=>'int', 'callback='=>'callable', 'data='=>'mixed'], 'eio_sync' => ['resource', 'pri='=>'int', 'callback='=>'callable', 'data='=>'mixed'], 'eio_sync_file_range' => ['resource', 'fd'=>'mixed', 'offset'=>'int', 'nbytes'=>'int', 'flags'=>'int', 'pri='=>'int', 'callback='=>'callable', 'data='=>'mixed'], 'eio_syncfs' => ['resource', 'fd'=>'mixed', 'pri='=>'int', 'callback='=>'callable', 'data='=>'mixed'], 'eio_truncate' => ['resource', 'path'=>'string', 'offset='=>'int', 'pri='=>'int', 'callback='=>'callable', 'data='=>'mixed'], 'eio_unlink' => ['resource', 'path'=>'string', 'pri='=>'int', 'callback='=>'callable', 'data='=>'mixed'], 'eio_utime' => ['resource', 'path'=>'string', 'atime'=>'float', 'mtime'=>'float', 'pri='=>'int', 'callback='=>'callable', 'data='=>'mixed'], 'eio_write' => ['resource', 'fd'=>'mixed', 'string'=>'string', 'length='=>'int', 'offset='=>'int', 'pri='=>'int', 'callback='=>'callable', 'data='=>'mixed'], 'empty' => ['bool', 'value'=>'mixed'], 'enchant_broker_describe' => ['array|false', 'broker'=>'resource'], 'enchant_broker_dict_exists' => ['bool', 'broker'=>'resource', 'tag'=>'string'], 'enchant_broker_free' => ['bool', 'broker'=>'resource'], 'enchant_broker_free_dict' => ['bool', 'dictionary'=>'resource'], 'enchant_broker_get_dict_path' => ['string', 'broker'=>'resource', 'type'=>'int'], 'enchant_broker_get_error' => ['string|false', 'broker'=>'resource'], 'enchant_broker_init' => ['resource|false'], 'enchant_broker_list_dicts' => ['array|false', 'broker'=>'resource'], 'enchant_broker_request_dict' => ['resource|false', 'broker'=>'resource', 'tag'=>'string'], 'enchant_broker_request_pwl_dict' => ['resource|false', 'broker'=>'resource', 'filename'=>'string'], 'enchant_broker_set_dict_path' => ['bool', 'broker'=>'resource', 'type'=>'int', 'path'=>'string'], 'enchant_broker_set_ordering' => ['bool', 'broker'=>'resource', 'tag'=>'string', 'ordering'=>'string'], 'enchant_dict_add_to_personal' => ['void', 'dictionary'=>'resource', 'word'=>'string'], 'enchant_dict_add_to_session' => ['void', 'dictionary'=>'resource', 'word'=>'string'], 'enchant_dict_check' => ['bool', 'dictionary'=>'resource', 'word'=>'string'], 'enchant_dict_describe' => ['array', 'dictionary'=>'resource'], 'enchant_dict_get_error' => ['string', 'dictionary'=>'resource'], 'enchant_dict_is_in_session' => ['bool', 'dictionary'=>'resource', 'word'=>'string'], 'enchant_dict_quick_check' => ['bool', 'dictionary'=>'resource', 'word'=>'string', '&w_suggestions='=>'array'], 'enchant_dict_store_replacement' => ['void', 'dictionary'=>'resource', 'misspelled'=>'string', 'correct'=>'string'], 'enchant_dict_suggest' => ['array', 'dictionary'=>'resource', 'word'=>'string'], 'end' => ['mixed|false', '&r_array'=>'array|object'], 'error_clear_last' => ['void'], 'error_get_last' => ['?array{type:int,message:string,file:string,line:int}'], 'error_log' => ['bool', 'message'=>'string', 'message_type='=>'int', 'destination='=>'string', 'additional_headers='=>'string'], 'error_reporting' => ['int', 'error_level='=>'int'], 'escapeshellarg' => ['string', 'arg'=>'string'], 'escapeshellcmd' => ['string', 'command'=>'string'], 'eval' => ['mixed', 'code_str'=>'string'], 'event_add' => ['bool', 'event'=>'resource', 'timeout='=>'int'], 'event_base_free' => ['void', 'event_base'=>'resource'], 'event_base_loop' => ['int', 'event_base'=>'resource', 'flags='=>'int'], 'event_base_loopbreak' => ['bool', 'event_base'=>'resource'], 'event_base_loopexit' => ['bool', 'event_base'=>'resource', 'timeout='=>'int'], 'event_base_new' => ['resource|false'], 'event_base_priority_init' => ['bool', 'event_base'=>'resource', 'npriorities'=>'int'], 'event_base_reinit' => ['bool', 'event_base'=>'resource'], 'event_base_set' => ['bool', 'event'=>'resource', 'event_base'=>'resource'], 'event_buffer_base_set' => ['bool', 'bevent'=>'resource', 'event_base'=>'resource'], 'event_buffer_disable' => ['bool', 'bevent'=>'resource', 'events'=>'int'], 'event_buffer_enable' => ['bool', 'bevent'=>'resource', 'events'=>'int'], 'event_buffer_fd_set' => ['void', 'bevent'=>'resource', 'fd'=>'resource'], 'event_buffer_free' => ['void', 'bevent'=>'resource'], 'event_buffer_new' => ['resource|false', 'stream'=>'resource', 'readcb'=>'callable|null', 'writecb'=>'callable|null', 'errorcb'=>'callable', 'arg='=>'mixed'], 'event_buffer_priority_set' => ['bool', 'bevent'=>'resource', 'priority'=>'int'], 'event_buffer_read' => ['string', 'bevent'=>'resource', 'data_size'=>'int'], 'event_buffer_set_callback' => ['bool', 'event'=>'resource', 'readcb'=>'mixed', 'writecb'=>'mixed', 'errorcb'=>'mixed', 'arg='=>'mixed'], 'event_buffer_timeout_set' => ['void', 'bevent'=>'resource', 'read_timeout'=>'int', 'write_timeout'=>'int'], 'event_buffer_watermark_set' => ['void', 'bevent'=>'resource', 'events'=>'int', 'lowmark'=>'int', 'highmark'=>'int'], 'event_buffer_write' => ['bool', 'bevent'=>'resource', 'data'=>'string', 'data_size='=>'int'], 'event_del' => ['bool', 'event'=>'resource'], 'event_free' => ['void', 'event'=>'resource'], 'event_new' => ['resource|false'], 'event_priority_set' => ['bool', 'event'=>'resource', 'priority'=>'int'], 'event_set' => ['bool', 'event'=>'resource', 'fd'=>'int|resource', 'events'=>'int', 'callback'=>'callable', 'arg='=>'mixed'], 'event_timer_add' => ['bool', 'event'=>'resource', 'timeout='=>'int'], 'event_timer_del' => ['bool', 'event'=>'resource'], 'event_timer_new' => ['resource|false'], 'event_timer_pending' => ['bool', 'event'=>'resource', 'timeout='=>'int'], 'event_timer_set' => ['bool', 'event'=>'resource', 'callback'=>'callable', 'arg='=>'mixed'], 'exec' => ['string|false', 'command'=>'string', '&w_output='=>'array', '&w_result_code='=>'int'], 'exif_imagetype' => ['int|false', 'filename'=>'string'], 'exif_read_data' => ['array|false', 'file'=>'string|resource', 'required_sections='=>'string', 'as_arrays='=>'bool', 'read_thumbnail='=>'bool'], 'exif_tagname' => ['string|false', 'index'=>'int'], 'exif_thumbnail' => ['string|false', 'file'=>'string', '&w_width='=>'int', '&w_height='=>'int', '&w_image_type='=>'int'], 'exit' => ['', 'status'=>'string|int'], 'exp' => ['float', 'num'=>'float'], 'expect_expectl' => ['int', 'expect'=>'resource', 'cases'=>'array', 'match='=>'array'], 'expect_popen' => ['resource|false', 'command'=>'string'], 'explode' => ['list|false', 'separator'=>'string', 'string'=>'string', 'limit='=>'int'], 'expm1' => ['float', 'num'=>'float'], 'extension_loaded' => ['bool', 'extension'=>'string'], 'extract' => ['int', '&rw_array'=>'array', 'flags='=>'int', 'prefix='=>'string'], 'ezmlm_hash' => ['int', 'addr'=>'string'], 'fam_cancel_monitor' => ['bool', 'fam'=>'resource', 'fam_monitor'=>'resource'], 'fam_close' => ['void', 'fam'=>'resource'], 'fam_monitor_collection' => ['resource', 'fam'=>'resource', 'dirname'=>'string', 'depth'=>'int', 'mask'=>'string'], 'fam_monitor_directory' => ['resource', 'fam'=>'resource', 'dirname'=>'string'], 'fam_monitor_file' => ['resource', 'fam'=>'resource', 'filename'=>'string'], 'fam_next_event' => ['array', 'fam'=>'resource'], 'fam_open' => ['resource|false', 'appname='=>'string'], 'fam_pending' => ['int', 'fam'=>'resource'], 'fam_resume_monitor' => ['bool', 'fam'=>'resource', 'fam_monitor'=>'resource'], 'fam_suspend_monitor' => ['bool', 'fam'=>'resource', 'fam_monitor'=>'resource'], 'fann_cascadetrain_on_data' => ['bool', 'ann'=>'resource', 'data'=>'resource', 'max_neurons'=>'int', 'neurons_between_reports'=>'int', 'desired_error'=>'float'], 'fann_cascadetrain_on_file' => ['bool', 'ann'=>'resource', 'filename'=>'string', 'max_neurons'=>'int', 'neurons_between_reports'=>'int', 'desired_error'=>'float'], 'fann_clear_scaling_params' => ['bool', 'ann'=>'resource'], 'fann_copy' => ['resource|false', 'ann'=>'resource'], 'fann_create_from_file' => ['resource', 'configuration_file'=>'string'], 'fann_create_shortcut' => ['resource|false', 'num_layers'=>'int', 'num_neurons1'=>'int', 'num_neurons2'=>'int', '...args='=>'int'], 'fann_create_shortcut_array' => ['resource|false', 'num_layers'=>'int', 'layers'=>'array'], 'fann_create_sparse' => ['resource|false', 'connection_rate'=>'float', 'num_layers'=>'int', 'num_neurons1'=>'int', 'num_neurons2'=>'int', '...args='=>'int'], 'fann_create_sparse_array' => ['resource|false', 'connection_rate'=>'float', 'num_layers'=>'int', 'layers'=>'array'], 'fann_create_standard' => ['resource|false', 'num_layers'=>'int', 'num_neurons1'=>'int', 'num_neurons2'=>'int', '...args='=>'int'], 'fann_create_standard_array' => ['resource|false', 'num_layers'=>'int', 'layers'=>'array'], 'fann_create_train' => ['resource', 'num_data'=>'int', 'num_input'=>'int', 'num_output'=>'int'], 'fann_create_train_from_callback' => ['resource', 'num_data'=>'int', 'num_input'=>'int', 'num_output'=>'int', 'user_function'=>'callable'], 'fann_descale_input' => ['bool', 'ann'=>'resource', 'input_vector'=>'array'], 'fann_descale_output' => ['bool', 'ann'=>'resource', 'output_vector'=>'array'], 'fann_descale_train' => ['bool', 'ann'=>'resource', 'train_data'=>'resource'], 'fann_destroy' => ['bool', 'ann'=>'resource'], 'fann_destroy_train' => ['bool', 'train_data'=>'resource'], 'fann_duplicate_train_data' => ['resource', 'data'=>'resource'], 'fann_get_MSE' => ['float|false', 'ann'=>'resource'], 'fann_get_activation_function' => ['int|false', 'ann'=>'resource', 'layer'=>'int', 'neuron'=>'int'], 'fann_get_activation_steepness' => ['float|false', 'ann'=>'resource', 'layer'=>'int', 'neuron'=>'int'], 'fann_get_bias_array' => ['array', 'ann'=>'resource'], 'fann_get_bit_fail' => ['int|false', 'ann'=>'resource'], 'fann_get_bit_fail_limit' => ['float|false', 'ann'=>'resource'], 'fann_get_cascade_activation_functions' => ['array|false', 'ann'=>'resource'], 'fann_get_cascade_activation_functions_count' => ['int|false', 'ann'=>'resource'], 'fann_get_cascade_activation_steepnesses' => ['array|false', 'ann'=>'resource'], 'fann_get_cascade_activation_steepnesses_count' => ['int|false', 'ann'=>'resource'], 'fann_get_cascade_candidate_change_fraction' => ['float|false', 'ann'=>'resource'], 'fann_get_cascade_candidate_limit' => ['float|false', 'ann'=>'resource'], 'fann_get_cascade_candidate_stagnation_epochs' => ['float|false', 'ann'=>'resource'], 'fann_get_cascade_max_cand_epochs' => ['int|false', 'ann'=>'resource'], 'fann_get_cascade_max_out_epochs' => ['int|false', 'ann'=>'resource'], 'fann_get_cascade_min_cand_epochs' => ['int|false', 'ann'=>'resource'], 'fann_get_cascade_min_out_epochs' => ['int|false', 'ann'=>'resource'], 'fann_get_cascade_num_candidate_groups' => ['int|false', 'ann'=>'resource'], 'fann_get_cascade_num_candidates' => ['int|false', 'ann'=>'resource'], 'fann_get_cascade_output_change_fraction' => ['float|false', 'ann'=>'resource'], 'fann_get_cascade_output_stagnation_epochs' => ['int|false', 'ann'=>'resource'], 'fann_get_cascade_weight_multiplier' => ['float|false', 'ann'=>'resource'], 'fann_get_connection_array' => ['array', 'ann'=>'resource'], 'fann_get_connection_rate' => ['float|false', 'ann'=>'resource'], 'fann_get_errno' => ['int|false', 'errdat'=>'resource'], 'fann_get_errstr' => ['string|false', 'errdat'=>'resource'], 'fann_get_layer_array' => ['array', 'ann'=>'resource'], 'fann_get_learning_momentum' => ['float|false', 'ann'=>'resource'], 'fann_get_learning_rate' => ['float|false', 'ann'=>'resource'], 'fann_get_network_type' => ['int|false', 'ann'=>'resource'], 'fann_get_num_input' => ['int|false', 'ann'=>'resource'], 'fann_get_num_layers' => ['int|false', 'ann'=>'resource'], 'fann_get_num_output' => ['int|false', 'ann'=>'resource'], 'fann_get_quickprop_decay' => ['float|false', 'ann'=>'resource'], 'fann_get_quickprop_mu' => ['float|false', 'ann'=>'resource'], 'fann_get_rprop_decrease_factor' => ['float|false', 'ann'=>'resource'], 'fann_get_rprop_delta_max' => ['float|false', 'ann'=>'resource'], 'fann_get_rprop_delta_min' => ['float|false', 'ann'=>'resource'], 'fann_get_rprop_delta_zero' => ['float|false', 'ann'=>'resource'], 'fann_get_rprop_increase_factor' => ['float|false', 'ann'=>'resource'], 'fann_get_sarprop_step_error_shift' => ['float|false', 'ann'=>'resource'], 'fann_get_sarprop_step_error_threshold_factor' => ['float|false', 'ann'=>'resource'], 'fann_get_sarprop_temperature' => ['float|false', 'ann'=>'resource'], 'fann_get_sarprop_weight_decay_shift' => ['float|false', 'ann'=>'resource'], 'fann_get_total_connections' => ['int|false', 'ann'=>'resource'], 'fann_get_total_neurons' => ['int|false', 'ann'=>'resource'], 'fann_get_train_error_function' => ['int|false', 'ann'=>'resource'], 'fann_get_train_stop_function' => ['int|false', 'ann'=>'resource'], 'fann_get_training_algorithm' => ['int|false', 'ann'=>'resource'], 'fann_init_weights' => ['bool', 'ann'=>'resource', 'train_data'=>'resource'], 'fann_length_train_data' => ['int|false', 'data'=>'resource'], 'fann_merge_train_data' => ['resource|false', 'data1'=>'resource', 'data2'=>'resource'], 'fann_num_input_train_data' => ['int|false', 'data'=>'resource'], 'fann_num_output_train_data' => ['int|false', 'data'=>'resource'], 'fann_print_error' => ['void', 'errdat'=>'string'], 'fann_randomize_weights' => ['bool', 'ann'=>'resource', 'min_weight'=>'float', 'max_weight'=>'float'], 'fann_read_train_from_file' => ['resource', 'filename'=>'string'], 'fann_reset_MSE' => ['bool', 'ann'=>'string'], 'fann_reset_errno' => ['void', 'errdat'=>'resource'], 'fann_reset_errstr' => ['void', 'errdat'=>'resource'], 'fann_run' => ['array|false', 'ann'=>'resource', 'input'=>'array'], 'fann_save' => ['bool', 'ann'=>'resource', 'configuration_file'=>'string'], 'fann_save_train' => ['bool', 'data'=>'resource', 'file_name'=>'string'], 'fann_scale_input' => ['bool', 'ann'=>'resource', 'input_vector'=>'array'], 'fann_scale_input_train_data' => ['bool', 'train_data'=>'resource', 'new_min'=>'float', 'new_max'=>'float'], 'fann_scale_output' => ['bool', 'ann'=>'resource', 'output_vector'=>'array'], 'fann_scale_output_train_data' => ['bool', 'train_data'=>'resource', 'new_min'=>'float', 'new_max'=>'float'], 'fann_scale_train' => ['bool', 'ann'=>'resource', 'train_data'=>'resource'], 'fann_scale_train_data' => ['bool', 'train_data'=>'resource', 'new_min'=>'float', 'new_max'=>'float'], 'fann_set_activation_function' => ['bool', 'ann'=>'resource', 'activation_function'=>'int', 'layer'=>'int', 'neuron'=>'int'], 'fann_set_activation_function_hidden' => ['bool', 'ann'=>'resource', 'activation_function'=>'int'], 'fann_set_activation_function_layer' => ['bool', 'ann'=>'resource', 'activation_function'=>'int', 'layer'=>'int'], 'fann_set_activation_function_output' => ['bool', 'ann'=>'resource', 'activation_function'=>'int'], 'fann_set_activation_steepness' => ['bool', 'ann'=>'resource', 'activation_steepness'=>'float', 'layer'=>'int', 'neuron'=>'int'], 'fann_set_activation_steepness_hidden' => ['bool', 'ann'=>'resource', 'activation_steepness'=>'float'], 'fann_set_activation_steepness_layer' => ['bool', 'ann'=>'resource', 'activation_steepness'=>'float', 'layer'=>'int'], 'fann_set_activation_steepness_output' => ['bool', 'ann'=>'resource', 'activation_steepness'=>'float'], 'fann_set_bit_fail_limit' => ['bool', 'ann'=>'resource', 'bit_fail_limit'=>'float'], 'fann_set_callback' => ['bool', 'ann'=>'resource', 'callback'=>'callable'], 'fann_set_cascade_activation_functions' => ['bool', 'ann'=>'resource', 'cascade_activation_functions'=>'array'], 'fann_set_cascade_activation_steepnesses' => ['bool', 'ann'=>'resource', 'cascade_activation_steepnesses_count'=>'array'], 'fann_set_cascade_candidate_change_fraction' => ['bool', 'ann'=>'resource', 'cascade_candidate_change_fraction'=>'float'], 'fann_set_cascade_candidate_limit' => ['bool', 'ann'=>'resource', 'cascade_candidate_limit'=>'float'], 'fann_set_cascade_candidate_stagnation_epochs' => ['bool', 'ann'=>'resource', 'cascade_candidate_stagnation_epochs'=>'int'], 'fann_set_cascade_max_cand_epochs' => ['bool', 'ann'=>'resource', 'cascade_max_cand_epochs'=>'int'], 'fann_set_cascade_max_out_epochs' => ['bool', 'ann'=>'resource', 'cascade_max_out_epochs'=>'int'], 'fann_set_cascade_min_cand_epochs' => ['bool', 'ann'=>'resource', 'cascade_min_cand_epochs'=>'int'], 'fann_set_cascade_min_out_epochs' => ['bool', 'ann'=>'resource', 'cascade_min_out_epochs'=>'int'], 'fann_set_cascade_num_candidate_groups' => ['bool', 'ann'=>'resource', 'cascade_num_candidate_groups'=>'int'], 'fann_set_cascade_output_change_fraction' => ['bool', 'ann'=>'resource', 'cascade_output_change_fraction'=>'float'], 'fann_set_cascade_output_stagnation_epochs' => ['bool', 'ann'=>'resource', 'cascade_output_stagnation_epochs'=>'int'], 'fann_set_cascade_weight_multiplier' => ['bool', 'ann'=>'resource', 'cascade_weight_multiplier'=>'float'], 'fann_set_error_log' => ['void', 'errdat'=>'resource', 'log_file'=>'string'], 'fann_set_input_scaling_params' => ['bool', 'ann'=>'resource', 'train_data'=>'resource', 'new_input_min'=>'float', 'new_input_max'=>'float'], 'fann_set_learning_momentum' => ['bool', 'ann'=>'resource', 'learning_momentum'=>'float'], 'fann_set_learning_rate' => ['bool', 'ann'=>'resource', 'learning_rate'=>'float'], 'fann_set_output_scaling_params' => ['bool', 'ann'=>'resource', 'train_data'=>'resource', 'new_output_min'=>'float', 'new_output_max'=>'float'], 'fann_set_quickprop_decay' => ['bool', 'ann'=>'resource', 'quickprop_decay'=>'float'], 'fann_set_quickprop_mu' => ['bool', 'ann'=>'resource', 'quickprop_mu'=>'float'], 'fann_set_rprop_decrease_factor' => ['bool', 'ann'=>'resource', 'rprop_decrease_factor'=>'float'], 'fann_set_rprop_delta_max' => ['bool', 'ann'=>'resource', 'rprop_delta_max'=>'float'], 'fann_set_rprop_delta_min' => ['bool', 'ann'=>'resource', 'rprop_delta_min'=>'float'], 'fann_set_rprop_delta_zero' => ['bool', 'ann'=>'resource', 'rprop_delta_zero'=>'float'], 'fann_set_rprop_increase_factor' => ['bool', 'ann'=>'resource', 'rprop_increase_factor'=>'float'], 'fann_set_sarprop_step_error_shift' => ['bool', 'ann'=>'resource', 'sarprop_step_error_shift'=>'float'], 'fann_set_sarprop_step_error_threshold_factor' => ['bool', 'ann'=>'resource', 'sarprop_step_error_threshold_factor'=>'float'], 'fann_set_sarprop_temperature' => ['bool', 'ann'=>'resource', 'sarprop_temperature'=>'float'], 'fann_set_sarprop_weight_decay_shift' => ['bool', 'ann'=>'resource', 'sarprop_weight_decay_shift'=>'float'], 'fann_set_scaling_params' => ['bool', 'ann'=>'resource', 'train_data'=>'resource', 'new_input_min'=>'float', 'new_input_max'=>'float', 'new_output_min'=>'float', 'new_output_max'=>'float'], 'fann_set_train_error_function' => ['bool', 'ann'=>'resource', 'error_function'=>'int'], 'fann_set_train_stop_function' => ['bool', 'ann'=>'resource', 'stop_function'=>'int'], 'fann_set_training_algorithm' => ['bool', 'ann'=>'resource', 'training_algorithm'=>'int'], 'fann_set_weight' => ['bool', 'ann'=>'resource', 'from_neuron'=>'int', 'to_neuron'=>'int', 'weight'=>'float'], 'fann_set_weight_array' => ['bool', 'ann'=>'resource', 'connections'=>'array'], 'fann_shuffle_train_data' => ['bool', 'train_data'=>'resource'], 'fann_subset_train_data' => ['resource', 'data'=>'resource', 'pos'=>'int', 'length'=>'int'], 'fann_test' => ['bool', 'ann'=>'resource', 'input'=>'array', 'desired_output'=>'array'], 'fann_test_data' => ['float|false', 'ann'=>'resource', 'data'=>'resource'], 'fann_train' => ['bool', 'ann'=>'resource', 'input'=>'array', 'desired_output'=>'array'], 'fann_train_epoch' => ['float|false', 'ann'=>'resource', 'data'=>'resource'], 'fann_train_on_data' => ['bool', 'ann'=>'resource', 'data'=>'resource', 'max_epochs'=>'int', 'epochs_between_reports'=>'int', 'desired_error'=>'float'], 'fann_train_on_file' => ['bool', 'ann'=>'resource', 'filename'=>'string', 'max_epochs'=>'int', 'epochs_between_reports'=>'int', 'desired_error'=>'float'], 'fastcgi_finish_request' => ['bool'], 'fbsql_affected_rows' => ['int', 'link_identifier='=>'?resource'], 'fbsql_autocommit' => ['bool', 'link_identifier'=>'resource', 'onoff='=>'bool'], 'fbsql_blob_size' => ['int', 'blob_handle'=>'string', 'link_identifier='=>'?resource'], 'fbsql_change_user' => ['bool', 'user'=>'string', 'password'=>'string', 'database='=>'string', 'link_identifier='=>'?resource'], 'fbsql_clob_size' => ['int', 'clob_handle'=>'string', 'link_identifier='=>'?resource'], 'fbsql_close' => ['bool', 'link_identifier='=>'?resource'], 'fbsql_commit' => ['bool', 'link_identifier='=>'?resource'], 'fbsql_connect' => ['resource', 'hostname='=>'string', 'username='=>'string', 'password='=>'string'], 'fbsql_create_blob' => ['string', 'blob_data'=>'string', 'link_identifier='=>'?resource'], 'fbsql_create_clob' => ['string', 'clob_data'=>'string', 'link_identifier='=>'?resource'], 'fbsql_create_db' => ['bool', 'database_name'=>'string', 'link_identifier='=>'?resource', 'database_options='=>'string'], 'fbsql_data_seek' => ['bool', 'result'=>'resource', 'row_number'=>'int'], 'fbsql_database' => ['string', 'link_identifier'=>'resource', 'database='=>'string'], 'fbsql_database_password' => ['string', 'link_identifier'=>'resource', 'database_password='=>'string'], 'fbsql_db_query' => ['resource', 'database'=>'string', 'query'=>'string', 'link_identifier='=>'?resource'], 'fbsql_db_status' => ['int', 'database_name'=>'string', 'link_identifier='=>'?resource'], 'fbsql_drop_db' => ['bool', 'database_name'=>'string', 'link_identifier='=>'?resource'], 'fbsql_errno' => ['int', 'link_identifier='=>'?resource'], 'fbsql_error' => ['string', 'link_identifier='=>'?resource'], 'fbsql_fetch_array' => ['array', 'result'=>'resource', 'result_type='=>'int'], 'fbsql_fetch_assoc' => ['array', 'result'=>'resource'], 'fbsql_fetch_field' => ['object', 'result'=>'resource', 'field_offset='=>'int'], 'fbsql_fetch_lengths' => ['array', 'result'=>'resource'], 'fbsql_fetch_object' => ['object', 'result'=>'resource'], 'fbsql_fetch_row' => ['array', 'result'=>'resource'], 'fbsql_field_flags' => ['string', 'result'=>'resource', 'field_offset='=>'int'], 'fbsql_field_len' => ['int', 'result'=>'resource', 'field_offset='=>'int'], 'fbsql_field_name' => ['string', 'result'=>'resource', 'field_index='=>'int'], 'fbsql_field_seek' => ['bool', 'result'=>'resource', 'field_offset='=>'int'], 'fbsql_field_table' => ['string', 'result'=>'resource', 'field_offset='=>'int'], 'fbsql_field_type' => ['string', 'result'=>'resource', 'field_offset='=>'int'], 'fbsql_free_result' => ['bool', 'result'=>'resource'], 'fbsql_get_autostart_info' => ['array', 'link_identifier='=>'?resource'], 'fbsql_hostname' => ['string', 'link_identifier'=>'resource', 'host_name='=>'string'], 'fbsql_insert_id' => ['int', 'link_identifier='=>'?resource'], 'fbsql_list_dbs' => ['resource', 'link_identifier='=>'?resource'], 'fbsql_list_fields' => ['resource', 'database_name'=>'string', 'table_name'=>'string', 'link_identifier='=>'?resource'], 'fbsql_list_tables' => ['resource', 'database'=>'string', 'link_identifier='=>'?resource'], 'fbsql_next_result' => ['bool', 'result'=>'resource'], 'fbsql_num_fields' => ['int', 'result'=>'resource'], 'fbsql_num_rows' => ['int', 'result'=>'resource'], 'fbsql_password' => ['string', 'link_identifier'=>'resource', 'password='=>'string'], 'fbsql_pconnect' => ['resource', 'hostname='=>'string', 'username='=>'string', 'password='=>'string'], 'fbsql_query' => ['resource', 'query'=>'string', 'link_identifier='=>'?resource', 'batch_size='=>'int'], 'fbsql_read_blob' => ['string', 'blob_handle'=>'string', 'link_identifier='=>'?resource'], 'fbsql_read_clob' => ['string', 'clob_handle'=>'string', 'link_identifier='=>'?resource'], 'fbsql_result' => ['mixed', 'result'=>'resource', 'row='=>'int', 'field='=>'mixed'], 'fbsql_rollback' => ['bool', 'link_identifier='=>'?resource'], 'fbsql_rows_fetched' => ['int', 'result'=>'resource'], 'fbsql_select_db' => ['bool', 'database_name='=>'string', 'link_identifier='=>'?resource'], 'fbsql_set_characterset' => ['void', 'link_identifier'=>'resource', 'characterset'=>'int', 'in_out_both='=>'int'], 'fbsql_set_lob_mode' => ['bool', 'result'=>'resource', 'lob_mode'=>'int'], 'fbsql_set_password' => ['bool', 'link_identifier'=>'resource', 'user'=>'string', 'password'=>'string', 'old_password'=>'string'], 'fbsql_set_transaction' => ['void', 'link_identifier'=>'resource', 'locking'=>'int', 'isolation'=>'int'], 'fbsql_start_db' => ['bool', 'database_name'=>'string', 'link_identifier='=>'?resource', 'database_options='=>'string'], 'fbsql_stop_db' => ['bool', 'database_name'=>'string', 'link_identifier='=>'?resource'], 'fbsql_table_name' => ['string', 'result'=>'resource', 'index'=>'int'], 'fbsql_username' => ['string', 'link_identifier'=>'resource', 'username='=>'string'], 'fbsql_warnings' => ['bool', 'onoff='=>'bool'], 'fclose' => ['bool', 'stream'=>'resource'], 'fdf_add_doc_javascript' => ['bool', 'fdf_document'=>'resource', 'script_name'=>'string', 'script_code'=>'string'], 'fdf_add_template' => ['bool', 'fdf_document'=>'resource', 'newpage'=>'int', 'filename'=>'string', 'template'=>'string', 'rename'=>'int'], 'fdf_close' => ['void', 'fdf_document'=>'resource'], 'fdf_create' => ['resource'], 'fdf_enum_values' => ['bool', 'fdf_document'=>'resource', 'function'=>'callable', 'userdata='=>'mixed'], 'fdf_errno' => ['int'], 'fdf_error' => ['string', 'error_code='=>'int'], 'fdf_get_ap' => ['bool', 'fdf_document'=>'resource', 'field'=>'string', 'face'=>'int', 'filename'=>'string'], 'fdf_get_attachment' => ['array', 'fdf_document'=>'resource', 'fieldname'=>'string', 'savepath'=>'string'], 'fdf_get_encoding' => ['string', 'fdf_document'=>'resource'], 'fdf_get_file' => ['string', 'fdf_document'=>'resource'], 'fdf_get_flags' => ['int', 'fdf_document'=>'resource', 'fieldname'=>'string', 'whichflags'=>'int'], 'fdf_get_opt' => ['mixed', 'fdf_document'=>'resource', 'fieldname'=>'string', 'element='=>'int'], 'fdf_get_status' => ['string', 'fdf_document'=>'resource'], 'fdf_get_value' => ['mixed', 'fdf_document'=>'resource', 'fieldname'=>'string', 'which='=>'int'], 'fdf_get_version' => ['string', 'fdf_document='=>'resource'], 'fdf_header' => ['void'], 'fdf_next_field_name' => ['string', 'fdf_document'=>'resource', 'fieldname='=>'string'], 'fdf_open' => ['resource|false', 'filename'=>'string'], 'fdf_open_string' => ['resource', 'fdf_data'=>'string'], 'fdf_remove_item' => ['bool', 'fdf_document'=>'resource', 'fieldname'=>'string', 'item'=>'int'], 'fdf_save' => ['bool', 'fdf_document'=>'resource', 'filename='=>'string'], 'fdf_save_string' => ['string', 'fdf_document'=>'resource'], 'fdf_set_ap' => ['bool', 'fdf_document'=>'resource', 'field_name'=>'string', 'face'=>'int', 'filename'=>'string', 'page_number'=>'int'], 'fdf_set_encoding' => ['bool', 'fdf_document'=>'resource', 'encoding'=>'string'], 'fdf_set_file' => ['bool', 'fdf_document'=>'resource', 'url'=>'string', 'target_frame='=>'string'], 'fdf_set_flags' => ['bool', 'fdf_document'=>'resource', 'fieldname'=>'string', 'whichflags'=>'int', 'newflags'=>'int'], 'fdf_set_javascript_action' => ['bool', 'fdf_document'=>'resource', 'fieldname'=>'string', 'trigger'=>'int', 'script'=>'string'], 'fdf_set_on_import_javascript' => ['bool', 'fdf_document'=>'resource', 'script'=>'string', 'before_data_import'=>'bool'], 'fdf_set_opt' => ['bool', 'fdf_document'=>'resource', 'fieldname'=>'string', 'element'=>'int', 'string1'=>'string', 'string2'=>'string'], 'fdf_set_status' => ['bool', 'fdf_document'=>'resource', 'status'=>'string'], 'fdf_set_submit_form_action' => ['bool', 'fdf_document'=>'resource', 'fieldname'=>'string', 'trigger'=>'int', 'script'=>'string', 'flags'=>'int'], 'fdf_set_target_frame' => ['bool', 'fdf_document'=>'resource', 'frame_name'=>'string'], 'fdf_set_value' => ['bool', 'fdf_document'=>'resource', 'fieldname'=>'string', 'value'=>'mixed', 'isname='=>'int'], 'fdf_set_version' => ['bool', 'fdf_document'=>'resource', 'version'=>'string'], 'feof' => ['bool', 'stream'=>'resource'], 'fflush' => ['bool', 'stream'=>'resource'], 'ffmpeg_animated_gif::__construct' => ['void', 'output_file_path'=>'string', 'width'=>'int', 'height'=>'int', 'frame_rate'=>'int', 'loop_count='=>'int'], 'ffmpeg_animated_gif::addFrame' => ['', 'frame_to_add'=>'ffmpeg_frame'], 'ffmpeg_frame::__construct' => ['void', 'gd_image'=>'resource'], 'ffmpeg_frame::crop' => ['', 'crop_top'=>'int', 'crop_bottom='=>'int', 'crop_left='=>'int', 'crop_right='=>'int'], 'ffmpeg_frame::getHeight' => ['int'], 'ffmpeg_frame::getPTS' => ['int'], 'ffmpeg_frame::getPresentationTimestamp' => ['int'], 'ffmpeg_frame::getWidth' => ['int'], 'ffmpeg_frame::resize' => ['', 'width'=>'int', 'height'=>'int', 'crop_top='=>'int', 'crop_bottom='=>'int', 'crop_left='=>'int', 'crop_right='=>'int'], 'ffmpeg_frame::toGDImage' => ['resource'], 'ffmpeg_movie::__construct' => ['void', 'path_to_media'=>'string', 'persistent'=>'bool'], 'ffmpeg_movie::getArtist' => ['string'], 'ffmpeg_movie::getAudioBitRate' => ['int'], 'ffmpeg_movie::getAudioChannels' => ['int'], 'ffmpeg_movie::getAudioCodec' => ['string'], 'ffmpeg_movie::getAudioSampleRate' => ['int'], 'ffmpeg_movie::getAuthor' => ['string'], 'ffmpeg_movie::getBitRate' => ['int'], 'ffmpeg_movie::getComment' => ['string'], 'ffmpeg_movie::getCopyright' => ['string'], 'ffmpeg_movie::getDuration' => ['int'], 'ffmpeg_movie::getFilename' => ['string'], 'ffmpeg_movie::getFrame' => ['ffmpeg_frame|false', 'framenumber'=>'int'], 'ffmpeg_movie::getFrameCount' => ['int'], 'ffmpeg_movie::getFrameHeight' => ['int'], 'ffmpeg_movie::getFrameNumber' => ['int'], 'ffmpeg_movie::getFrameRate' => ['int'], 'ffmpeg_movie::getFrameWidth' => ['int'], 'ffmpeg_movie::getGenre' => ['string'], 'ffmpeg_movie::getNextKeyFrame' => ['ffmpeg_frame|false'], 'ffmpeg_movie::getPixelFormat' => [''], 'ffmpeg_movie::getTitle' => ['string'], 'ffmpeg_movie::getTrackNumber' => ['int|string'], 'ffmpeg_movie::getVideoBitRate' => ['int'], 'ffmpeg_movie::getVideoCodec' => ['string'], 'ffmpeg_movie::getYear' => ['int|string'], 'ffmpeg_movie::hasAudio' => ['bool'], 'ffmpeg_movie::hasVideo' => ['bool'], 'fgetc' => ['string|false', 'stream'=>'resource'], 'fgetcsv' => ['list|array{0: null}|false', 'stream'=>'resource', 'length='=>'int', 'separator='=>'string', 'enclosure='=>'string', 'escape='=>'string'], 'fgets' => ['string|false', 'stream'=>'resource', 'length='=>'int'], 'fgetss' => ['string|false', 'fp'=>'resource', 'length='=>'int', 'allowable_tags='=>'string'], 'file' => ['list|false', 'filename'=>'string', 'flags='=>'int', 'context='=>'resource'], 'file_exists' => ['bool', 'filename'=>'string'], 'file_get_contents' => ['string|false', 'filename'=>'string', 'use_include_path='=>'bool', 'context='=>'?resource', 'offset='=>'int', 'length='=>'int'], 'file_put_contents' => ['int<0, max>|false', 'filename'=>'string', 'data'=>'string|resource|array', 'flags='=>'int', 'context='=>'resource'], 'fileatime' => ['int|false', 'filename'=>'string'], 'filectime' => ['int|false', 'filename'=>'string'], 'filegroup' => ['int|false', 'filename'=>'string'], 'fileinode' => ['int|false', 'filename'=>'string'], 'filemtime' => ['int|false', 'filename'=>'string'], 'fileowner' => ['int|false', 'filename'=>'string'], 'fileperms' => ['int|false', 'filename'=>'string'], 'filepro' => ['bool', 'directory'=>'string'], 'filepro_fieldcount' => ['int'], 'filepro_fieldname' => ['string', 'field_number'=>'int'], 'filepro_fieldtype' => ['string', 'field_number'=>'int'], 'filepro_fieldwidth' => ['int', 'field_number'=>'int'], 'filepro_retrieve' => ['string', 'row_number'=>'int', 'field_number'=>'int'], 'filepro_rowcount' => ['int'], 'filesize' => ['int|false', 'filename'=>'string'], 'filetype' => ['string|false', 'filename'=>'string'], 'filter_has_var' => ['bool', 'input_type'=>'0|1|2|4|5', 'var_name'=>'string'], 'filter_id' => ['int|false', 'name'=>'string'], 'filter_input' => ['mixed|false|null', 'type'=>'0|1|2|4|5', 'var_name'=>'string', 'filter='=>'int', 'options='=>'array|int'], 'filter_input_array' => ['array|false|null', 'type'=>'0|1|2|4|5', 'options='=>'int|array', 'add_empty='=>'bool'], 'filter_list' => ['non-empty-list'], 'filter_var' => ['mixed|false', 'value'=>'mixed', 'filter='=>'int', 'options='=>'array|int'], 'filter_var_array' => ['array|false|null', 'array'=>'array', 'options='=>'array|int', 'add_empty='=>'bool'], 'finfo::__construct' => ['void', 'flags='=>'int', 'magic_database='=>'string'], 'finfo::buffer' => ['string|false', 'string'=>'string', 'flags='=>'int', 'context='=>'?resource'], 'finfo::file' => ['string|false', 'filename'=>'string', 'flags='=>'int', 'context='=>'?resource'], 'finfo::set_flags' => ['bool', 'flags'=>'int'], 'finfo_buffer' => ['string|false', 'finfo'=>'resource', 'string'=>'string', 'flags='=>'int', 'context='=>'resource'], 'finfo_close' => ['bool', 'finfo'=>'resource'], 'finfo_file' => ['string|false', 'finfo'=>'resource', 'filename'=>'string', 'flags='=>'int', 'context='=>'resource'], 'finfo_open' => ['resource|false', 'flags='=>'int', 'magic_database='=>'string'], 'finfo_set_flags' => ['bool', 'finfo'=>'resource', 'flags'=>'int'], 'floatval' => ['float', 'value'=>'mixed'], 'flock' => ['bool', 'stream'=>'resource', 'operation'=>'int', '&w_would_block='=>'int'], 'floor' => ['float', 'num'=>'float|int'], 'flush' => ['void'], 'fmod' => ['float', 'num1'=>'float', 'num2'=>'float'], 'fnmatch' => ['bool', 'pattern'=>'string', 'filename'=>'string', 'flags='=>'int'], 'fopen' => ['resource|false', 'filename'=>'string', 'mode'=>'string', 'use_include_path='=>'bool', 'context='=>'resource|null'], 'forward_static_call' => ['mixed|false', 'callback'=>'callable', '...args='=>'mixed'], 'forward_static_call_array' => ['mixed|false', 'callback'=>'callable', 'args'=>'list'], 'fpassthru' => ['int', 'stream'=>'resource'], 'fprintf' => ['int', 'stream'=>'resource', 'format'=>'string', '...values='=>'string|int|float'], 'fputcsv' => ['int|false', 'stream'=>'resource', 'fields'=>'array', 'separator='=>'string', 'enclosure='=>'string', 'escape='=>'string'], 'fputs' => ['int|false', 'stream'=>'resource', 'data'=>'string', 'length='=>'int'], 'fread' => ['string|false', 'stream'=>'resource', 'length'=>'int'], 'frenchtojd' => ['int', 'month'=>'int', 'day'=>'int', 'year'=>'int'], 'fribidi_log2vis' => ['string', 'string'=>'string', 'direction'=>'string', 'charset'=>'int'], 'fscanf' => ['list', 'stream'=>'resource', 'format'=>'string'], 'fscanf\'1' => ['int', 'stream'=>'resource', 'format'=>'string', '&...w_vars='=>'string|int|float'], 'fseek' => ['int', 'stream'=>'resource', 'offset'=>'int', 'whence='=>'int'], 'fsockopen' => ['resource|false', 'hostname'=>'string', 'port='=>'int', '&w_error_code='=>'int', '&w_error_message='=>'string', 'timeout='=>'float'], 'fstat' => ['array{0: int, 1: int, 2: int, 3: int, 4: int, 5: int, 6: int, 7: int, 8: int, 9: int, 10: int, 11: int, 12: int, dev: int, ino: int, mode: int, nlink: int, uid: int, gid: int, rdev: int, size: int, atime: int, mtime: int, ctime: int, blksize: int, blocks: int}|false', 'stream'=>'resource'], 'ftell' => ['int|false', 'stream'=>'resource'], 'ftok' => ['int', 'filename'=>'string', 'project_id'=>'string'], 'ftp_alloc' => ['bool', 'ftp'=>'resource', 'size'=>'int', '&w_response='=>'string'], 'ftp_cdup' => ['bool', 'ftp'=>'resource'], 'ftp_chdir' => ['bool', 'ftp'=>'resource', 'directory'=>'string'], 'ftp_chmod' => ['int|false', 'ftp'=>'resource', 'permissions'=>'int', 'filename'=>'string'], 'ftp_close' => ['bool', 'ftp'=>'resource'], 'ftp_connect' => ['resource|false', 'hostname'=>'string', 'port='=>'int', 'timeout='=>'int'], 'ftp_delete' => ['bool', 'ftp'=>'resource', 'filename'=>'string'], 'ftp_exec' => ['bool', 'ftp'=>'resource', 'command'=>'string'], 'ftp_fget' => ['bool', 'ftp'=>'resource', 'stream'=>'resource', 'remote_filename'=>'string', 'mode='=>'int', 'offset='=>'int'], 'ftp_fput' => ['bool', 'ftp'=>'resource', 'remote_filename'=>'string', 'stream'=>'resource', 'mode='=>'int', 'offset='=>'int'], 'ftp_get' => ['bool', 'ftp'=>'resource', 'local_filename'=>'string', 'remote_filename'=>'string', 'mode='=>'int', 'offset='=>'int'], 'ftp_get_option' => ['int|false', 'ftp'=>'resource', 'option'=>'int'], 'ftp_login' => ['bool', 'ftp'=>'resource', 'username'=>'string', 'password'=>'string'], 'ftp_mdtm' => ['int', 'ftp'=>'resource', 'filename'=>'string'], 'ftp_mkdir' => ['string|false', 'ftp'=>'resource', 'directory'=>'string'], 'ftp_mlsd' => ['array|false', 'ftp'=>'resource', 'directory'=>'string'], 'ftp_nb_continue' => ['int', 'ftp'=>'resource'], 'ftp_nb_fget' => ['int', 'ftp'=>'resource', 'stream'=>'resource', 'remote_filename'=>'string', 'mode='=>'int', 'offset='=>'int'], 'ftp_nb_fput' => ['int', 'ftp'=>'resource', 'remote_filename'=>'string', 'stream'=>'resource', 'mode='=>'int', 'offset='=>'int'], 'ftp_nb_get' => ['int', 'ftp'=>'resource', 'local_filename'=>'string', 'remote_filename'=>'string', 'mode='=>'int', 'offset='=>'int'], 'ftp_nb_put' => ['int', 'ftp'=>'resource', 'remote_filename'=>'string', 'local_filename'=>'string', 'mode='=>'int', 'offset='=>'int'], 'ftp_nlist' => ['array|false', 'ftp'=>'resource', 'directory'=>'string'], 'ftp_pasv' => ['bool', 'ftp'=>'resource', 'enable'=>'bool'], 'ftp_put' => ['bool', 'ftp'=>'resource', 'remote_filename'=>'string', 'local_filename'=>'string', 'mode='=>'int', 'offset='=>'int'], 'ftp_pwd' => ['string|false', 'ftp'=>'resource'], 'ftp_quit' => ['bool', 'ftp'=>'resource'], 'ftp_raw' => ['?array', 'ftp'=>'resource', 'command'=>'string'], 'ftp_rawlist' => ['array|false', 'ftp'=>'resource', 'directory'=>'string', 'recursive='=>'bool'], 'ftp_rename' => ['bool', 'ftp'=>'resource', 'from'=>'string', 'to'=>'string'], 'ftp_rmdir' => ['bool', 'ftp'=>'resource', 'directory'=>'string'], 'ftp_set_option' => ['bool', 'ftp'=>'resource', 'option'=>'int', 'value'=>'mixed'], 'ftp_site' => ['bool', 'ftp'=>'resource', 'command'=>'string'], 'ftp_size' => ['int', 'ftp'=>'resource', 'filename'=>'string'], 'ftp_ssl_connect' => ['resource|false', 'hostname'=>'string', 'port='=>'int', 'timeout='=>'int'], 'ftp_systype' => ['string|false', 'ftp'=>'resource'], 'ftruncate' => ['bool', 'stream'=>'resource', 'size'=>'int'], 'func_get_arg' => ['mixed|false', 'position'=>'int'], 'func_get_args' => ['list'], 'func_num_args' => ['int'], 'function_exists' => ['bool', 'function'=>'string'], 'fwrite' => ['int|false', 'stream'=>'resource', 'data'=>'string', 'length='=>'int'], 'gc_collect_cycles' => ['int'], 'gc_disable' => ['void'], 'gc_enable' => ['void'], 'gc_enabled' => ['bool'], 'gc_mem_caches' => ['int'], 'gd_info' => ['array'], 'gearman_bugreport' => [''], 'gearman_client_add_options' => ['', 'client_object'=>'', 'option'=>''], 'gearman_client_add_server' => ['', 'client_object'=>'', 'host'=>'', 'port'=>''], 'gearman_client_add_servers' => ['', 'client_object'=>'', 'servers'=>''], 'gearman_client_add_task' => ['', 'client_object'=>'', 'function_name'=>'', 'workload'=>'', 'context'=>'', 'unique'=>''], 'gearman_client_add_task_background' => ['', 'client_object'=>'', 'function_name'=>'', 'workload'=>'', 'context'=>'', 'unique'=>''], 'gearman_client_add_task_high' => ['', 'client_object'=>'', 'function_name'=>'', 'workload'=>'', 'context'=>'', 'unique'=>''], 'gearman_client_add_task_high_background' => ['', 'client_object'=>'', 'function_name'=>'', 'workload'=>'', 'context'=>'', 'unique'=>''], 'gearman_client_add_task_low' => ['', 'client_object'=>'', 'function_name'=>'', 'workload'=>'', 'context'=>'', 'unique'=>''], 'gearman_client_add_task_low_background' => ['', 'client_object'=>'', 'function_name'=>'', 'workload'=>'', 'context'=>'', 'unique'=>''], 'gearman_client_add_task_status' => ['', 'client_object'=>'', 'job_handle'=>'', 'context'=>''], 'gearman_client_clear_fn' => ['', 'client_object'=>''], 'gearman_client_clone' => ['', 'client_object'=>''], 'gearman_client_context' => ['', 'client_object'=>''], 'gearman_client_create' => ['', 'client_object'=>''], 'gearman_client_do' => ['', 'client_object'=>'', 'function_name'=>'', 'workload'=>'', 'unique'=>''], 'gearman_client_do_background' => ['', 'client_object'=>'', 'function_name'=>'', 'workload'=>'', 'unique'=>''], 'gearman_client_do_high' => ['', 'client_object'=>'', 'function_name'=>'', 'workload'=>'', 'unique'=>''], 'gearman_client_do_high_background' => ['', 'client_object'=>'', 'function_name'=>'', 'workload'=>'', 'unique'=>''], 'gearman_client_do_job_handle' => ['', 'client_object'=>''], 'gearman_client_do_low' => ['', 'client_object'=>'', 'function_name'=>'', 'workload'=>'', 'unique'=>''], 'gearman_client_do_low_background' => ['', 'client_object'=>'', 'function_name'=>'', 'workload'=>'', 'unique'=>''], 'gearman_client_do_normal' => ['', 'client_object'=>'', 'function_name'=>'string', 'workload'=>'string', 'unique'=>'string'], 'gearman_client_do_status' => ['', 'client_object'=>''], 'gearman_client_echo' => ['', 'client_object'=>'', 'workload'=>''], 'gearman_client_errno' => ['', 'client_object'=>''], 'gearman_client_error' => ['', 'client_object'=>''], 'gearman_client_job_status' => ['', 'client_object'=>'', 'job_handle'=>''], 'gearman_client_options' => ['', 'client_object'=>''], 'gearman_client_remove_options' => ['', 'client_object'=>'', 'option'=>''], 'gearman_client_return_code' => ['', 'client_object'=>''], 'gearman_client_run_tasks' => ['', 'data'=>''], 'gearman_client_set_complete_fn' => ['', 'client_object'=>'', 'callback'=>''], 'gearman_client_set_context' => ['', 'client_object'=>'', 'context'=>''], 'gearman_client_set_created_fn' => ['', 'client_object'=>'', 'callback'=>''], 'gearman_client_set_data_fn' => ['', 'client_object'=>'', 'callback'=>''], 'gearman_client_set_exception_fn' => ['', 'client_object'=>'', 'callback'=>''], 'gearman_client_set_fail_fn' => ['', 'client_object'=>'', 'callback'=>''], 'gearman_client_set_options' => ['', 'client_object'=>'', 'option'=>''], 'gearman_client_set_status_fn' => ['', 'client_object'=>'', 'callback'=>''], 'gearman_client_set_timeout' => ['', 'client_object'=>'', 'timeout'=>''], 'gearman_client_set_warning_fn' => ['', 'client_object'=>'', 'callback'=>''], 'gearman_client_set_workload_fn' => ['', 'client_object'=>'', 'callback'=>''], 'gearman_client_timeout' => ['', 'client_object'=>''], 'gearman_client_wait' => ['', 'client_object'=>''], 'gearman_job_function_name' => ['', 'job_object'=>''], 'gearman_job_handle' => ['string'], 'gearman_job_return_code' => ['', 'job_object'=>''], 'gearman_job_send_complete' => ['', 'job_object'=>'', 'result'=>''], 'gearman_job_send_data' => ['', 'job_object'=>'', 'data'=>''], 'gearman_job_send_exception' => ['', 'job_object'=>'', 'exception'=>''], 'gearman_job_send_fail' => ['', 'job_object'=>''], 'gearman_job_send_status' => ['', 'job_object'=>'', 'numerator'=>'', 'denominator'=>''], 'gearman_job_send_warning' => ['', 'job_object'=>'', 'warning'=>''], 'gearman_job_status' => ['array', 'job_handle'=>'string'], 'gearman_job_unique' => ['', 'job_object'=>''], 'gearman_job_workload' => ['', 'job_object'=>''], 'gearman_job_workload_size' => ['', 'job_object'=>''], 'gearman_task_data' => ['', 'task_object'=>''], 'gearman_task_data_size' => ['', 'task_object'=>''], 'gearman_task_denominator' => ['', 'task_object'=>''], 'gearman_task_function_name' => ['', 'task_object'=>''], 'gearman_task_is_known' => ['', 'task_object'=>''], 'gearman_task_is_running' => ['', 'task_object'=>''], 'gearman_task_job_handle' => ['', 'task_object'=>''], 'gearman_task_numerator' => ['', 'task_object'=>''], 'gearman_task_recv_data' => ['', 'task_object'=>'', 'data_len'=>''], 'gearman_task_return_code' => ['', 'task_object'=>''], 'gearman_task_send_workload' => ['', 'task_object'=>'', 'data'=>''], 'gearman_task_unique' => ['', 'task_object'=>''], 'gearman_verbose_name' => ['', 'verbose'=>''], 'gearman_version' => [''], 'gearman_worker_add_function' => ['', 'worker_object'=>'', 'function_name'=>'', 'function'=>'', 'data'=>'', 'timeout'=>''], 'gearman_worker_add_options' => ['', 'worker_object'=>'', 'option'=>''], 'gearman_worker_add_server' => ['', 'worker_object'=>'', 'host'=>'', 'port'=>''], 'gearman_worker_add_servers' => ['', 'worker_object'=>'', 'servers'=>''], 'gearman_worker_clone' => ['', 'worker_object'=>''], 'gearman_worker_create' => [''], 'gearman_worker_echo' => ['', 'worker_object'=>'', 'workload'=>''], 'gearman_worker_errno' => ['', 'worker_object'=>''], 'gearman_worker_error' => ['', 'worker_object'=>''], 'gearman_worker_grab_job' => ['', 'worker_object'=>''], 'gearman_worker_options' => ['', 'worker_object'=>''], 'gearman_worker_register' => ['', 'worker_object'=>'', 'function_name'=>'', 'timeout'=>''], 'gearman_worker_remove_options' => ['', 'worker_object'=>'', 'option'=>''], 'gearman_worker_return_code' => ['', 'worker_object'=>''], 'gearman_worker_set_options' => ['', 'worker_object'=>'', 'option'=>''], 'gearman_worker_set_timeout' => ['', 'worker_object'=>'', 'timeout'=>''], 'gearman_worker_timeout' => ['', 'worker_object'=>''], 'gearman_worker_unregister' => ['', 'worker_object'=>'', 'function_name'=>''], 'gearman_worker_unregister_all' => ['', 'worker_object'=>''], 'gearman_worker_wait' => ['', 'worker_object'=>''], 'gearman_worker_work' => ['', 'worker_object'=>''], 'geoip_asnum_by_name' => ['string|false', 'hostname'=>'string'], 'geoip_continent_code_by_name' => ['string|false', 'hostname'=>'string'], 'geoip_country_code3_by_name' => ['string|false', 'hostname'=>'string'], 'geoip_country_code_by_name' => ['string|false', 'hostname'=>'string'], 'geoip_country_name_by_name' => ['string|false', 'hostname'=>'string'], 'geoip_database_info' => ['string', 'database='=>'int'], 'geoip_db_avail' => ['bool', 'database'=>'int'], 'geoip_db_filename' => ['string', 'database'=>'int'], 'geoip_db_get_all_info' => ['array'], 'geoip_domain_by_name' => ['string', 'hostname'=>'string'], 'geoip_id_by_name' => ['int', 'hostname'=>'string'], 'geoip_isp_by_name' => ['string|false', 'hostname'=>'string'], 'geoip_netspeedcell_by_name' => ['string|false', 'hostname'=>'string'], 'geoip_org_by_name' => ['string|false', 'hostname'=>'string'], 'geoip_record_by_name' => ['array|false', 'hostname'=>'string'], 'geoip_region_by_name' => ['array|false', 'hostname'=>'string'], 'geoip_region_name_by_code' => ['string|false', 'country_code'=>'string', 'region_code'=>'string'], 'geoip_setup_custom_directory' => ['void', 'path'=>'string'], 'geoip_time_zone_by_country_and_region' => ['string|false', 'country_code'=>'string', 'region_code='=>'string'], 'get_browser' => ['array|object|false', 'user_agent='=>'?string', 'return_array='=>'bool'], 'get_call_stack' => [''], 'get_called_class' => ['class-string'], 'get_cfg_var' => ['string|false', 'option'=>'string'], 'get_class' => ['class-string', 'object='=>'object'], 'get_class_methods' => ['list|null', 'object_or_class'=>'mixed'], 'get_class_vars' => ['array', 'class'=>'string'], 'get_current_user' => ['string'], 'get_declared_classes' => ['list'], 'get_declared_interfaces' => ['list'], 'get_declared_traits' => ['list'], 'get_defined_constants' => ['array', 'categorize='=>'bool'], 'get_defined_functions' => ['array{internal: list, user: list}', 'exclude_disabled='=>'bool'], 'get_defined_vars' => ['array'], 'get_extension_funcs' => ['list|false', 'extension'=>'string'], 'get_headers' => ['array|false', 'url'=>'string', 'associative='=>'int'], 'get_html_translation_table' => ['array', 'table='=>'int', 'flags='=>'int', 'encoding='=>'string'], 'get_include_path' => ['string'], 'get_included_files' => ['list'], 'get_loaded_extensions' => ['list', 'zend_extensions='=>'bool'], 'get_magic_quotes_gpc' => ['int|false'], 'get_magic_quotes_runtime' => ['int|false'], 'get_meta_tags' => ['array', 'filename'=>'string', 'use_include_path='=>'bool'], 'get_object_vars' => ['array', 'object'=>'object'], 'get_parent_class' => ['class-string|false', 'object_or_class='=>'mixed'], 'get_required_files' => ['list'], 'get_resource_type' => ['string', 'resource'=>'resource'], 'get_resources' => ['array', 'type='=>'string'], 'getallheaders' => ['array|false'], 'getcwd' => ['non-falsy-string|false'], 'getdate' => ['array{seconds: int<0, 59>, minutes: int<0, 59>, hours: int<0, 23>, mday: int<1, 31>, wday: int<0, 6>, mon: int<1, 12>, year: int, yday: int<0, 365>, weekday: "Monday"|"Tuesday"|"Wednesday"|"Thursday"|"Friday"|"Saturday"|"Sunday", month: "January"|"February"|"March"|"April"|"May"|"June"|"July"|"August"|"September"|"October"|"November"|"December", 0: int}', 'timestamp='=>'int'], 'getenv' => ['string|false', 'name'=>'string', 'local_only='=>'bool'], 'gethostbyaddr' => ['string|false', 'ip'=>'string'], 'gethostbyname' => ['string', 'hostname'=>'string'], 'gethostbynamel' => ['list|false', 'hostname'=>'string'], 'gethostname' => ['string|false'], 'getimagesize' => ['array{0:int, 1: int, 2: int, 3: string, mime: string, channels?: 3|4, bits?: int}|false', 'filename'=>'string', '&w_image_info='=>'array'], 'getimagesizefromstring' => ['array{0:int, 1: int, 2: int, 3: string, mime: string, channels?: 3|4, bits?: int}|false', 'string'=>'string', '&w_image_info='=>'array'], 'getlastmod' => ['int|false'], 'getmxrr' => ['bool', 'hostname'=>'string', '&w_hosts'=>'array', '&w_weights='=>'array'], 'getmygid' => ['int|false'], 'getmyinode' => ['int|false'], 'getmypid' => ['int|false'], 'getmyuid' => ['int|false'], 'getopt' => ['array>|false', 'short_options'=>'string', 'long_options='=>'array'], 'getprotobyname' => ['int|false', 'protocol'=>'string'], 'getprotobynumber' => ['string', 'protocol'=>'int'], 'getrandmax' => ['int<1, max>'], 'getrusage' => ['array', 'mode='=>'int'], 'getservbyname' => ['int|false', 'service'=>'string', 'protocol'=>'string'], 'getservbyport' => ['string|false', 'port'=>'int', 'protocol'=>'string'], 'gettext' => ['string', 'message'=>'string'], 'gettimeofday' => ['array'], 'gettimeofday\'1' => ['float', 'as_float='=>'true'], 'gettype' => ['string', 'value'=>'mixed'], 'glob' => ['false|list{0?:string, ...}', 'pattern'=>'string', 'flags='=>'int<0, max>'], 'gmdate' => ['string', 'format'=>'string', 'timestamp='=>'int'], 'gmmktime' => ['int|false', 'hour='=>'int', 'minute='=>'int', 'second='=>'int', 'month='=>'int', 'day='=>'int', 'year='=>'int'], 'gmp_abs' => ['GMP', 'num'=>'GMP|string|int'], 'gmp_add' => ['GMP', 'num1'=>'GMP|string|int', 'num2'=>'GMP|string|int'], 'gmp_and' => ['GMP', 'num1'=>'GMP|string|int', 'num2'=>'GMP|string|int'], 'gmp_clrbit' => ['void', 'num'=>'GMP', 'index'=>'int'], 'gmp_cmp' => ['int', 'num1'=>'GMP|string|int', 'num2'=>'GMP|string|int'], 'gmp_com' => ['GMP', 'num'=>'GMP|string|int'], 'gmp_div' => ['GMP', 'num1'=>'GMP|string|int', 'num2'=>'GMP|string|int', 'rounding_mode='=>'int'], 'gmp_div_q' => ['GMP', 'num1'=>'GMP|string|int', 'num2'=>'GMP|string|int', 'rounding_mode='=>'int'], 'gmp_div_qr' => ['array{0: GMP, 1: GMP}', 'num1'=>'GMP|string|int', 'num2'=>'GMP|string|int', 'rounding_mode='=>'int'], 'gmp_div_r' => ['GMP', 'num1'=>'GMP|string|int', 'num2'=>'GMP|string|int', 'rounding_mode='=>'int'], 'gmp_divexact' => ['GMP', 'num1'=>'GMP|string|int', 'num2'=>'GMP|string|int'], 'gmp_export' => ['string|false', 'num'=>'GMP|string|int', 'word_size='=>'int', 'flags='=>'int'], 'gmp_fact' => ['GMP', 'num'=>'int'], 'gmp_gcd' => ['GMP', 'num1'=>'GMP|string|int', 'num2'=>'GMP|string|int'], 'gmp_gcdext' => ['array', 'num1'=>'GMP|string|int', 'num2'=>'GMP|string|int'], 'gmp_hamdist' => ['int', 'num1'=>'GMP|string|int', 'num2'=>'GMP|string|int'], 'gmp_import' => ['GMP|false', 'data'=>'string', 'word_size='=>'int', 'flags='=>'int'], 'gmp_init' => ['GMP', 'num'=>'int|string', 'base='=>'int'], 'gmp_intval' => ['int', 'num'=>'GMP|string|int'], 'gmp_invert' => ['GMP|false', 'num1'=>'GMP|string|int', 'num2'=>'GMP|string|int'], 'gmp_jacobi' => ['int', 'num1'=>'GMP|string|int', 'num2'=>'GMP|string|int'], 'gmp_legendre' => ['int', 'num1'=>'GMP|string|int', 'num2'=>'GMP|string|int'], 'gmp_mod' => ['GMP', 'num1'=>'GMP|string|int', 'num2'=>'GMP|string|int'], 'gmp_mul' => ['GMP', 'num1'=>'GMP|string|int', 'num2'=>'GMP|string|int'], 'gmp_neg' => ['GMP', 'num'=>'GMP|string|int'], 'gmp_nextprime' => ['GMP', 'num'=>'GMP|string|int'], 'gmp_or' => ['GMP', 'num1'=>'GMP|string|int', 'num2'=>'GMP|string|int'], 'gmp_perfect_square' => ['bool', 'num'=>'GMP|string|int'], 'gmp_popcount' => ['int', 'num'=>'GMP|string|int'], 'gmp_pow' => ['GMP', 'num'=>'GMP|string|int', 'exponent'=>'int'], 'gmp_powm' => ['GMP', 'num'=>'GMP|string|int', 'exponent'=>'GMP|string|int', 'modulus'=>'GMP|string|int'], 'gmp_prob_prime' => ['int', 'num'=>'GMP|string|int', 'repetitions='=>'int'], 'gmp_random' => ['GMP', 'limiter='=>'int'], 'gmp_random_bits' => ['GMP', 'bits'=>'int'], 'gmp_random_range' => ['GMP', 'min'=>'GMP|string|int', 'max'=>'GMP|string|int'], 'gmp_random_seed' => ['void', 'seed'=>'GMP|string|int'], 'gmp_root' => ['GMP', 'num'=>'GMP|string|int', 'nth'=>'int'], 'gmp_rootrem' => ['array{0: GMP, 1: GMP}', 'num'=>'GMP|string|int', 'nth'=>'int'], 'gmp_scan0' => ['int', 'num1'=>'GMP|string|int', 'start'=>'int'], 'gmp_scan1' => ['int', 'num1'=>'GMP|string|int', 'start'=>'int'], 'gmp_setbit' => ['void', 'num'=>'GMP', 'index'=>'int', 'value='=>'bool'], 'gmp_sign' => ['int', 'num'=>'GMP|string|int'], 'gmp_sqrt' => ['GMP', 'num'=>'GMP|string|int'], 'gmp_sqrtrem' => ['array{0: GMP, 1: GMP}', 'num'=>'GMP|string|int'], 'gmp_strval' => ['numeric-string', 'num'=>'GMP|string|int', 'base='=>'int'], 'gmp_sub' => ['GMP', 'num1'=>'GMP|string|int', 'num2'=>'GMP|string|int'], 'gmp_testbit' => ['bool', 'num'=>'GMP|string|int', 'index'=>'int'], 'gmp_xor' => ['GMP', 'num1'=>'GMP|string|int', 'num2'=>'GMP|string|int'], 'gmstrftime' => ['string|false', 'format'=>'string', 'timestamp='=>'int'], 'gnupg::adddecryptkey' => ['bool', 'fingerprint'=>'string', 'passphrase'=>'string'], 'gnupg::addencryptkey' => ['bool', 'fingerprint'=>'string'], 'gnupg::addsignkey' => ['bool', 'fingerprint'=>'string', 'passphrase='=>'string'], 'gnupg::cleardecryptkeys' => ['bool'], 'gnupg::clearencryptkeys' => ['bool'], 'gnupg::clearsignkeys' => ['bool'], 'gnupg::decrypt' => ['string|false', 'text'=>'string'], 'gnupg::decryptverify' => ['array|false', 'text'=>'string', '&plaintext'=>'string'], 'gnupg::encrypt' => ['string|false', 'plaintext'=>'string'], 'gnupg::encryptsign' => ['string|false', 'plaintext'=>'string'], 'gnupg::export' => ['string|false', 'fingerprint'=>'string'], 'gnupg::geterror' => ['string|false'], 'gnupg::getprotocol' => ['int'], 'gnupg::import' => ['array|false', 'keydata'=>'string'], 'gnupg::keyinfo' => ['array', 'pattern'=>'string'], 'gnupg::setarmor' => ['bool', 'armor'=>'int'], 'gnupg::seterrormode' => ['void', 'errormode'=>'int'], 'gnupg::setsignmode' => ['bool', 'signmode'=>'int'], 'gnupg::sign' => ['string|false', 'plaintext'=>'string'], 'gnupg::verify' => ['array|false', 'signed_text'=>'string', 'signature'=>'string', '&plaintext='=>'string'], 'gnupg_adddecryptkey' => ['bool', 'identifier'=>'resource', 'fingerprint'=>'string', 'passphrase'=>'string'], 'gnupg_addencryptkey' => ['bool', 'identifier'=>'resource', 'fingerprint'=>'string'], 'gnupg_addsignkey' => ['bool', 'identifier'=>'resource', 'fingerprint'=>'string', 'passphrase='=>'string'], 'gnupg_cleardecryptkeys' => ['bool', 'identifier'=>'resource'], 'gnupg_clearencryptkeys' => ['bool', 'identifier'=>'resource'], 'gnupg_clearsignkeys' => ['bool', 'identifier'=>'resource'], 'gnupg_decrypt' => ['string', 'identifier'=>'resource', 'text'=>'string'], 'gnupg_decryptverify' => ['array', 'identifier'=>'resource', 'text'=>'string', 'plaintext'=>'string'], 'gnupg_encrypt' => ['string', 'identifier'=>'resource', 'plaintext'=>'string'], 'gnupg_encryptsign' => ['string', 'identifier'=>'resource', 'plaintext'=>'string'], 'gnupg_export' => ['string', 'identifier'=>'resource', 'fingerprint'=>'string'], 'gnupg_geterror' => ['string', 'identifier'=>'resource'], 'gnupg_getprotocol' => ['int', 'identifier'=>'resource'], 'gnupg_import' => ['array', 'identifier'=>'resource', 'keydata'=>'string'], 'gnupg_init' => ['resource'], 'gnupg_keyinfo' => ['array', 'identifier'=>'resource', 'pattern'=>'string'], 'gnupg_setarmor' => ['bool', 'identifier'=>'resource', 'armor'=>'int'], 'gnupg_seterrormode' => ['void', 'identifier'=>'resource', 'errormode'=>'int'], 'gnupg_setsignmode' => ['bool', 'identifier'=>'resource', 'signmode'=>'int'], 'gnupg_sign' => ['string', 'identifier'=>'resource', 'plaintext'=>'string'], 'gnupg_verify' => ['array', 'identifier'=>'resource', 'signed_text'=>'string', 'signature'=>'string', 'plaintext='=>'string'], 'gopher_parsedir' => ['array', 'dirent'=>'string'], 'grapheme_extract' => ['string|false', 'haystack'=>'string', 'size'=>'int', 'type='=>'int', 'offset='=>'int', '&w_next='=>'int'], 'grapheme_stripos' => ['int|false', 'haystack'=>'string', 'needle'=>'string', 'offset='=>'int'], 'grapheme_stristr' => ['string|false', 'haystack'=>'string', 'needle'=>'string', 'beforeNeedle='=>'bool'], 'grapheme_strlen' => ['0|positive-int|false|null', 'string'=>'string'], 'grapheme_strpos' => ['int|false', 'haystack'=>'string', 'needle'=>'string', 'offset='=>'int'], 'grapheme_strripos' => ['int|false', 'haystack'=>'string', 'needle'=>'string', 'offset='=>'int'], 'grapheme_strrpos' => ['int|false', 'haystack'=>'string', 'needle'=>'string', 'offset='=>'int'], 'grapheme_strstr' => ['string|false', 'haystack'=>'string', 'needle'=>'string', 'beforeNeedle='=>'bool'], 'grapheme_substr' => ['string|false', 'string'=>'string', 'offset'=>'int', 'length='=>'?int'], 'gregoriantojd' => ['int', 'month'=>'int', 'day'=>'int', 'year'=>'int'], 'gridObj::set' => ['int', 'property_name'=>'string', 'new_value'=>''], 'gupnp_context_get_host_ip' => ['string', 'context'=>'resource'], 'gupnp_context_get_port' => ['int', 'context'=>'resource'], 'gupnp_context_get_subscription_timeout' => ['int', 'context'=>'resource'], 'gupnp_context_host_path' => ['bool', 'context'=>'resource', 'local_path'=>'string', 'server_path'=>'string'], 'gupnp_context_new' => ['resource', 'host_ip='=>'string', 'port='=>'int'], 'gupnp_context_set_subscription_timeout' => ['void', 'context'=>'resource', 'timeout'=>'int'], 'gupnp_context_timeout_add' => ['bool', 'context'=>'resource', 'timeout'=>'int', 'callback'=>'mixed', 'arg='=>'mixed'], 'gupnp_context_unhost_path' => ['bool', 'context'=>'resource', 'server_path'=>'string'], 'gupnp_control_point_browse_start' => ['bool', 'cpoint'=>'resource'], 'gupnp_control_point_browse_stop' => ['bool', 'cpoint'=>'resource'], 'gupnp_control_point_callback_set' => ['bool', 'cpoint'=>'resource', 'signal'=>'int', 'callback'=>'mixed', 'arg='=>'mixed'], 'gupnp_control_point_new' => ['resource', 'context'=>'resource', 'target'=>'string'], 'gupnp_device_action_callback_set' => ['bool', 'root_device'=>'resource', 'signal'=>'int', 'action_name'=>'string', 'callback'=>'mixed', 'arg='=>'mixed'], 'gupnp_device_info_get' => ['array', 'root_device'=>'resource'], 'gupnp_device_info_get_service' => ['resource', 'root_device'=>'resource', 'type'=>'string'], 'gupnp_root_device_get_available' => ['bool', 'root_device'=>'resource'], 'gupnp_root_device_get_relative_location' => ['string', 'root_device'=>'resource'], 'gupnp_root_device_new' => ['resource', 'context'=>'resource', 'location'=>'string', 'description_dir'=>'string'], 'gupnp_root_device_set_available' => ['bool', 'root_device'=>'resource', 'available'=>'bool'], 'gupnp_root_device_start' => ['bool', 'root_device'=>'resource'], 'gupnp_root_device_stop' => ['bool', 'root_device'=>'resource'], 'gupnp_service_action_get' => ['mixed', 'action'=>'resource', 'name'=>'string', 'type'=>'int'], 'gupnp_service_action_return' => ['bool', 'action'=>'resource'], 'gupnp_service_action_return_error' => ['bool', 'action'=>'resource', 'error_code'=>'int', 'error_description='=>'string'], 'gupnp_service_action_set' => ['bool', 'action'=>'resource', 'name'=>'string', 'type'=>'int', 'value'=>'mixed'], 'gupnp_service_freeze_notify' => ['bool', 'service'=>'resource'], 'gupnp_service_info_get' => ['array', 'proxy'=>'resource'], 'gupnp_service_info_get_introspection' => ['mixed', 'proxy'=>'resource', 'callback='=>'mixed', 'arg='=>'mixed'], 'gupnp_service_introspection_get_state_variable' => ['array', 'introspection'=>'resource', 'variable_name'=>'string'], 'gupnp_service_notify' => ['bool', 'service'=>'resource', 'name'=>'string', 'type'=>'int', 'value'=>'mixed'], 'gupnp_service_proxy_action_get' => ['mixed', 'proxy'=>'resource', 'action'=>'string', 'name'=>'string', 'type'=>'int'], 'gupnp_service_proxy_action_set' => ['bool', 'proxy'=>'resource', 'action'=>'string', 'name'=>'string', 'value'=>'mixed', 'type'=>'int'], 'gupnp_service_proxy_add_notify' => ['bool', 'proxy'=>'resource', 'value'=>'string', 'type'=>'int', 'callback'=>'mixed', 'arg='=>'mixed'], 'gupnp_service_proxy_callback_set' => ['bool', 'proxy'=>'resource', 'signal'=>'int', 'callback'=>'mixed', 'arg='=>'mixed'], 'gupnp_service_proxy_get_subscribed' => ['bool', 'proxy'=>'resource'], 'gupnp_service_proxy_remove_notify' => ['bool', 'proxy'=>'resource', 'value'=>'string'], 'gupnp_service_proxy_send_action' => ['array', 'proxy'=>'resource', 'action'=>'string', 'in_params'=>'array', 'out_params'=>'array'], 'gupnp_service_proxy_set_subscribed' => ['bool', 'proxy'=>'resource', 'subscribed'=>'bool'], 'gupnp_service_thaw_notify' => ['bool', 'service'=>'resource'], 'gzclose' => ['bool', 'stream'=>'resource'], 'gzcompress' => ['string|false', 'data'=>'string', 'level='=>'int', 'encoding='=>'int'], 'gzdecode' => ['string|false', 'data'=>'string', 'max_length='=>'int'], 'gzdeflate' => ['string|false', 'data'=>'string', 'level='=>'int', 'encoding='=>'int'], 'gzencode' => ['string|false', 'data'=>'string', 'level='=>'int', 'encoding='=>'int'], 'gzeof' => ['bool', 'stream'=>'resource'], 'gzfile' => ['list|false', 'filename'=>'string', 'use_include_path='=>'int'], 'gzgetc' => ['string|false', 'stream'=>'resource'], 'gzgets' => ['string|false', 'stream'=>'resource', 'length='=>'int'], 'gzgetss' => ['string|false', 'zp'=>'resource', 'length'=>'int', 'allowable_tags='=>'string'], 'gzinflate' => ['string|false', 'data'=>'string', 'max_length='=>'int'], 'gzopen' => ['resource|false', 'filename'=>'string', 'mode'=>'string', 'use_include_path='=>'int'], 'gzpassthru' => ['int', 'stream'=>'resource'], 'gzputs' => ['int|false', 'stream'=>'resource', 'data'=>'string', 'length='=>'int'], 'gzread' => ['string|0', 'stream'=>'resource', 'length'=>'int'], 'gzrewind' => ['bool', 'stream'=>'resource'], 'gzseek' => ['int', 'stream'=>'resource', 'offset'=>'int', 'whence='=>'int'], 'gztell' => ['int|false', 'stream'=>'resource'], 'gzuncompress' => ['string|false', 'data'=>'string', 'max_length='=>'int'], 'gzwrite' => ['int|false', 'stream'=>'resource', 'data'=>'string', 'length='=>'int'], 'hash' => ['string|false', 'algo'=>'string', 'data'=>'string', 'binary='=>'bool'], 'hashTableObj::clear' => ['void'], 'hashTableObj::get' => ['string', 'key'=>'string'], 'hashTableObj::nextkey' => ['string', 'previousKey'=>'string'], 'hashTableObj::remove' => ['int', 'key'=>'string'], 'hashTableObj::set' => ['int', 'key'=>'string', 'value'=>'string'], 'hash_algos' => ['list'], 'hash_copy' => ['resource', 'context'=>'resource'], 'hash_equals' => ['bool', 'known_string'=>'string', 'user_string'=>'string'], 'hash_file' => ['non-empty-string|false', 'algo'=>'string', 'filename'=>'string', 'binary='=>'bool'], 'hash_final' => ['non-empty-string', 'context'=>'resource', 'raw_output='=>'bool'], 'hash_hmac' => ['non-empty-string|false', 'algo'=>'string', 'data'=>'string', 'key'=>'string', 'binary='=>'bool'], 'hash_hmac_file' => ['non-empty-string|false', 'algo'=>'string', 'data'=>'string', 'key'=>'string', 'binary='=>'bool'], 'hash_init' => ['resource', 'algo'=>'string', 'options='=>'int', 'key='=>'string'], 'hash_pbkdf2' => ['non-empty-string', 'algo'=>'string', 'password'=>'string', 'salt'=>'string', 'iterations'=>'int', 'length='=>'int', 'binary='=>'bool'], 'hash_update' => ['bool', 'context'=>'resource', 'data'=>'string'], 'hash_update_file' => ['bool', 'hcontext'=>'resource', 'filename'=>'string', 'scontext='=>'resource'], 'hash_update_stream' => ['int', 'context'=>'resource', 'handle'=>'resource', 'length='=>'int'], 'header' => ['void', 'header'=>'string', 'replace='=>'bool', 'response_code='=>'int'], 'header_register_callback' => ['bool', 'callback'=>'callable():void'], 'header_remove' => ['void', 'name='=>'string'], 'headers_list' => ['list'], 'headers_sent' => ['bool', '&w_filename='=>'string', '&w_line='=>'int'], 'hebrev' => ['string', 'string'=>'string', 'max_chars_per_line='=>'int'], 'hebrevc' => ['string', 'string'=>'string', 'max_chars_per_line='=>'int'], 'hex2bin' => ['string|false', 'string'=>'string'], 'hexdec' => ['int|float', 'hex_string'=>'string'], 'highlight_file' => ['string|bool', 'filename'=>'string', 'return='=>'bool'], 'highlight_string' => ['string|bool', 'string'=>'string', 'return='=>'bool'], 'html_entity_decode' => ['string', 'string'=>'string', 'flags='=>'int', 'encoding='=>'string'], 'htmlentities' => ['string', 'string'=>'string', 'flags='=>'int', 'encoding='=>'string', 'double_encode='=>'bool'], 'htmlspecialchars' => ['string', 'string'=>'string', 'flags='=>'int', 'encoding='=>'string|null', 'double_encode='=>'bool'], 'htmlspecialchars_decode' => ['string', 'string'=>'string', 'flags='=>'int'], 'http\Client::__construct' => ['void', 'driver='=>'string', 'persistent_handle_id='=>'string'], 'http\Client::addCookies' => ['http\Client', 'cookies='=>'?array'], 'http\Client::addSslOptions' => ['http\Client', 'ssl_options='=>'?array'], 'http\Client::attach' => ['void', 'observer'=>'SplObserver'], 'http\Client::configure' => ['http\Client', 'settings'=>'array'], 'http\Client::count' => ['int'], 'http\Client::dequeue' => ['http\Client', 'request'=>'http\Client\Request'], 'http\Client::detach' => ['void', 'observer'=>'SplObserver'], 'http\Client::enableEvents' => ['http\Client', 'enable='=>'mixed'], 'http\Client::enablePipelining' => ['http\Client', 'enable='=>'mixed'], 'http\Client::enqueue' => ['http\Client', 'request'=>'http\Client\Request', 'callable='=>'mixed'], 'http\Client::getAvailableConfiguration' => ['array'], 'http\Client::getAvailableDrivers' => ['array'], 'http\Client::getAvailableOptions' => ['array'], 'http\Client::getCookies' => ['array'], 'http\Client::getHistory' => ['http\Message'], 'http\Client::getObservers' => ['SplObjectStorage'], 'http\Client::getOptions' => ['array'], 'http\Client::getProgressInfo' => ['null|object', 'request'=>'http\Client\Request'], 'http\Client::getResponse' => ['http\Client\Response|null', 'request='=>'?http\Client\Request'], 'http\Client::getSslOptions' => ['array'], 'http\Client::getTransferInfo' => ['object', 'request'=>'http\Client\Request'], 'http\Client::notify' => ['void', 'request='=>'?http\Client\Request'], 'http\Client::once' => ['bool'], 'http\Client::requeue' => ['http\Client', 'request'=>'http\Client\Request', 'callable='=>'mixed'], 'http\Client::reset' => ['http\Client'], 'http\Client::send' => ['http\Client'], 'http\Client::setCookies' => ['http\Client', 'cookies='=>'?array'], 'http\Client::setDebug' => ['http\Client', 'callback'=>'callable'], 'http\Client::setOptions' => ['http\Client', 'options='=>'?array'], 'http\Client::setSslOptions' => ['http\Client', 'ssl_option='=>'?array'], 'http\Client::wait' => ['bool', 'timeout='=>'mixed'], 'http\Client\Curl\User::init' => ['', 'run'=>'callable'], 'http\Client\Curl\User::once' => [''], 'http\Client\Curl\User::send' => [''], 'http\Client\Curl\User::socket' => ['', 'socket'=>'resource', 'action'=>'int'], 'http\Client\Curl\User::timer' => ['', 'timeout_ms'=>'int'], 'http\Client\Curl\User::wait' => ['', 'timeout_ms='=>'mixed'], 'http\Client\Request::__construct' => ['void', 'method='=>'mixed', 'url='=>'mixed', 'headers='=>'?array', 'body='=>'?http\Message\Body'], 'http\Client\Request::__toString' => ['string'], 'http\Client\Request::addBody' => ['http\Message', 'body'=>'http\Message\Body'], 'http\Client\Request::addHeader' => ['http\Message', 'header'=>'string', 'value'=>'mixed'], 'http\Client\Request::addHeaders' => ['http\Message', 'headers'=>'array', 'append='=>'mixed'], 'http\Client\Request::addQuery' => ['http\Client\Request', 'query_data'=>'mixed'], 'http\Client\Request::addSslOptions' => ['http\Client\Request', 'ssl_options='=>'?array'], 'http\Client\Request::count' => ['int'], 'http\Client\Request::current' => ['mixed'], 'http\Client\Request::detach' => ['http\Message'], 'http\Client\Request::getBody' => ['http\Message\Body'], 'http\Client\Request::getContentType' => ['null|string'], 'http\Client\Request::getHeader' => ['http\Header|mixed', 'header'=>'string', 'into_class='=>'mixed'], 'http\Client\Request::getHeaders' => ['array'], 'http\Client\Request::getHttpVersion' => ['string'], 'http\Client\Request::getInfo' => ['null|string'], 'http\Client\Request::getOptions' => ['array'], 'http\Client\Request::getParentMessage' => ['http\Message'], 'http\Client\Request::getQuery' => ['null|string'], 'http\Client\Request::getRequestMethod' => ['false|string'], 'http\Client\Request::getRequestUrl' => ['false|string'], 'http\Client\Request::getResponseCode' => ['false|int'], 'http\Client\Request::getResponseStatus' => ['false|string'], 'http\Client\Request::getSslOptions' => ['array'], 'http\Client\Request::getType' => ['int'], 'http\Client\Request::isMultipart' => ['bool', '&boundary='=>'mixed'], 'http\Client\Request::key' => ['int|string'], 'http\Client\Request::next' => ['void'], 'http\Client\Request::prepend' => ['http\Message', 'message'=>'http\Message', 'top='=>'mixed'], 'http\Client\Request::reverse' => ['http\Message'], 'http\Client\Request::rewind' => ['void'], 'http\Client\Request::serialize' => ['string'], 'http\Client\Request::setBody' => ['http\Message', 'body'=>'http\Message\Body'], 'http\Client\Request::setContentType' => ['http\Client\Request', 'content_type'=>'string'], 'http\Client\Request::setHeader' => ['http\Message', 'header'=>'string', 'value='=>'mixed'], 'http\Client\Request::setHeaders' => ['http\Message', 'headers'=>'array'], 'http\Client\Request::setHttpVersion' => ['http\Message', 'http_version'=>'string'], 'http\Client\Request::setInfo' => ['http\Message', 'http_info'=>'string'], 'http\Client\Request::setOptions' => ['http\Client\Request', 'options='=>'?array'], 'http\Client\Request::setQuery' => ['http\Client\Request', 'query_data='=>'mixed'], 'http\Client\Request::setRequestMethod' => ['http\Message', 'request_method'=>'string'], 'http\Client\Request::setRequestUrl' => ['http\Message', 'url'=>'string'], 'http\Client\Request::setResponseCode' => ['http\Message', 'response_code'=>'int', 'strict='=>'mixed'], 'http\Client\Request::setResponseStatus' => ['http\Message', 'response_status'=>'string'], 'http\Client\Request::setSslOptions' => ['http\Client\Request', 'ssl_options='=>'?array'], 'http\Client\Request::setType' => ['http\Message', 'type'=>'int'], 'http\Client\Request::splitMultipartBody' => ['http\Message'], 'http\Client\Request::toCallback' => ['http\Message', 'callback'=>'callable'], 'http\Client\Request::toStream' => ['http\Message', 'stream'=>'resource'], 'http\Client\Request::toString' => ['string', 'include_parent='=>'mixed'], 'http\Client\Request::unserialize' => ['void', 'serialized'=>'string'], 'http\Client\Request::valid' => ['bool'], 'http\Client\Response::__construct' => ['Iterator'], 'http\Client\Response::__toString' => ['string'], 'http\Client\Response::addBody' => ['http\Message', 'body'=>'http\Message\Body'], 'http\Client\Response::addHeader' => ['http\Message', 'header'=>'string', 'value'=>'mixed'], 'http\Client\Response::addHeaders' => ['http\Message', 'headers'=>'array', 'append='=>'mixed'], 'http\Client\Response::count' => ['int'], 'http\Client\Response::current' => ['mixed'], 'http\Client\Response::detach' => ['http\Message'], 'http\Client\Response::getBody' => ['http\Message\Body'], 'http\Client\Response::getCookies' => ['array', 'flags='=>'mixed', 'allowed_extras='=>'mixed'], 'http\Client\Response::getHeader' => ['http\Header|mixed', 'header'=>'string', 'into_class='=>'mixed'], 'http\Client\Response::getHeaders' => ['array'], 'http\Client\Response::getHttpVersion' => ['string'], 'http\Client\Response::getInfo' => ['null|string'], 'http\Client\Response::getParentMessage' => ['http\Message'], 'http\Client\Response::getRequestMethod' => ['false|string'], 'http\Client\Response::getRequestUrl' => ['false|string'], 'http\Client\Response::getResponseCode' => ['false|int'], 'http\Client\Response::getResponseStatus' => ['false|string'], 'http\Client\Response::getTransferInfo' => ['mixed|object', 'element='=>'mixed'], 'http\Client\Response::getType' => ['int'], 'http\Client\Response::isMultipart' => ['bool', '&boundary='=>'mixed'], 'http\Client\Response::key' => ['int|string'], 'http\Client\Response::next' => ['void'], 'http\Client\Response::prepend' => ['http\Message', 'message'=>'http\Message', 'top='=>'mixed'], 'http\Client\Response::reverse' => ['http\Message'], 'http\Client\Response::rewind' => ['void'], 'http\Client\Response::serialize' => ['string'], 'http\Client\Response::setBody' => ['http\Message', 'body'=>'http\Message\Body'], 'http\Client\Response::setHeader' => ['http\Message', 'header'=>'string', 'value='=>'mixed'], 'http\Client\Response::setHeaders' => ['http\Message', 'headers'=>'array'], 'http\Client\Response::setHttpVersion' => ['http\Message', 'http_version'=>'string'], 'http\Client\Response::setInfo' => ['http\Message', 'http_info'=>'string'], 'http\Client\Response::setRequestMethod' => ['http\Message', 'request_method'=>'string'], 'http\Client\Response::setRequestUrl' => ['http\Message', 'url'=>'string'], 'http\Client\Response::setResponseCode' => ['http\Message', 'response_code'=>'int', 'strict='=>'mixed'], 'http\Client\Response::setResponseStatus' => ['http\Message', 'response_status'=>'string'], 'http\Client\Response::setType' => ['http\Message', 'type'=>'int'], 'http\Client\Response::splitMultipartBody' => ['http\Message'], 'http\Client\Response::toCallback' => ['http\Message', 'callback'=>'callable'], 'http\Client\Response::toStream' => ['http\Message', 'stream'=>'resource'], 'http\Client\Response::toString' => ['string', 'include_parent='=>'mixed'], 'http\Client\Response::unserialize' => ['void', 'serialized'=>'string'], 'http\Client\Response::valid' => ['bool'], 'http\Cookie::__construct' => ['void', 'cookie_string='=>'mixed', 'parser_flags='=>'int', 'allowed_extras='=>'array'], 'http\Cookie::__toString' => ['string'], 'http\Cookie::addCookie' => ['http\Cookie', 'cookie_name'=>'string', 'cookie_value'=>'string'], 'http\Cookie::addCookies' => ['http\Cookie', 'cookies'=>'array'], 'http\Cookie::addExtra' => ['http\Cookie', 'extra_name'=>'string', 'extra_value'=>'string'], 'http\Cookie::addExtras' => ['http\Cookie', 'extras'=>'array'], 'http\Cookie::getCookie' => ['null|string', 'name'=>'string'], 'http\Cookie::getCookies' => ['array'], 'http\Cookie::getDomain' => ['string'], 'http\Cookie::getExpires' => ['int'], 'http\Cookie::getExtra' => ['string', 'name'=>'string'], 'http\Cookie::getExtras' => ['array'], 'http\Cookie::getFlags' => ['int'], 'http\Cookie::getMaxAge' => ['int'], 'http\Cookie::getPath' => ['string'], 'http\Cookie::setCookie' => ['http\Cookie', 'cookie_name'=>'string', 'cookie_value='=>'mixed'], 'http\Cookie::setCookies' => ['http\Cookie', 'cookies='=>'mixed'], 'http\Cookie::setDomain' => ['http\Cookie', 'value='=>'mixed'], 'http\Cookie::setExpires' => ['http\Cookie', 'value='=>'mixed'], 'http\Cookie::setExtra' => ['http\Cookie', 'extra_name'=>'string', 'extra_value='=>'mixed'], 'http\Cookie::setExtras' => ['http\Cookie', 'extras='=>'mixed'], 'http\Cookie::setFlags' => ['http\Cookie', 'value='=>'mixed'], 'http\Cookie::setMaxAge' => ['http\Cookie', 'value='=>'mixed'], 'http\Cookie::setPath' => ['http\Cookie', 'value='=>'mixed'], 'http\Cookie::toArray' => ['array'], 'http\Cookie::toString' => ['string'], 'http\Encoding\Stream::__construct' => ['void', 'flags='=>'mixed'], 'http\Encoding\Stream::done' => ['bool'], 'http\Encoding\Stream::finish' => ['string'], 'http\Encoding\Stream::flush' => ['string'], 'http\Encoding\Stream::update' => ['string', 'data'=>'string'], 'http\Encoding\Stream\Debrotli::__construct' => ['void', 'flags='=>'int'], 'http\Encoding\Stream\Debrotli::decode' => ['string', 'data'=>'string'], 'http\Encoding\Stream\Debrotli::done' => ['bool'], 'http\Encoding\Stream\Debrotli::finish' => ['string'], 'http\Encoding\Stream\Debrotli::flush' => ['string'], 'http\Encoding\Stream\Debrotli::update' => ['string', 'data'=>'string'], 'http\Encoding\Stream\Dechunk::__construct' => ['void', 'flags='=>'mixed'], 'http\Encoding\Stream\Dechunk::decode' => ['false|string', 'data'=>'string', '&decoded_len='=>'mixed'], 'http\Encoding\Stream\Dechunk::done' => ['bool'], 'http\Encoding\Stream\Dechunk::finish' => ['string'], 'http\Encoding\Stream\Dechunk::flush' => ['string'], 'http\Encoding\Stream\Dechunk::update' => ['string', 'data'=>'string'], 'http\Encoding\Stream\Deflate::__construct' => ['void', 'flags='=>'mixed'], 'http\Encoding\Stream\Deflate::done' => ['bool'], 'http\Encoding\Stream\Deflate::encode' => ['string', 'data'=>'string', 'flags='=>'mixed'], 'http\Encoding\Stream\Deflate::finish' => ['string'], 'http\Encoding\Stream\Deflate::flush' => ['string'], 'http\Encoding\Stream\Deflate::update' => ['string', 'data'=>'string'], 'http\Encoding\Stream\Enbrotli::__construct' => ['void', 'flags='=>'int'], 'http\Encoding\Stream\Enbrotli::done' => ['bool'], 'http\Encoding\Stream\Enbrotli::encode' => ['string', 'data'=>'string', 'flags='=>'int'], 'http\Encoding\Stream\Enbrotli::finish' => ['string'], 'http\Encoding\Stream\Enbrotli::flush' => ['string'], 'http\Encoding\Stream\Enbrotli::update' => ['string', 'data'=>'string'], 'http\Encoding\Stream\Inflate::__construct' => ['void', 'flags='=>'mixed'], 'http\Encoding\Stream\Inflate::decode' => ['string', 'data'=>'string'], 'http\Encoding\Stream\Inflate::done' => ['bool'], 'http\Encoding\Stream\Inflate::finish' => ['string'], 'http\Encoding\Stream\Inflate::flush' => ['string'], 'http\Encoding\Stream\Inflate::update' => ['string', 'data'=>'string'], 'http\Env::getRequestBody' => ['http\Message\Body', 'body_class_name='=>'mixed'], 'http\Env::getRequestHeader' => ['array|null|string', 'header_name='=>'mixed'], 'http\Env::getResponseCode' => ['int'], 'http\Env::getResponseHeader' => ['array|null|string', 'header_name='=>'mixed'], 'http\Env::getResponseStatusForAllCodes' => ['array'], 'http\Env::getResponseStatusForCode' => ['string', 'code'=>'int'], 'http\Env::negotiate' => ['null|string', 'params'=>'string', 'supported'=>'array', 'primary_type_separator='=>'mixed', '&result_array='=>'mixed'], 'http\Env::negotiateCharset' => ['null|string', 'supported'=>'array', '&result_array='=>'mixed'], 'http\Env::negotiateContentType' => ['null|string', 'supported'=>'array', '&result_array='=>'mixed'], 'http\Env::negotiateEncoding' => ['null|string', 'supported'=>'array', '&result_array='=>'mixed'], 'http\Env::negotiateLanguage' => ['null|string', 'supported'=>'array', '&result_array='=>'mixed'], 'http\Env::setResponseCode' => ['bool', 'code'=>'int'], 'http\Env::setResponseHeader' => ['bool', 'header_name'=>'string', 'header_value='=>'mixed', 'response_code='=>'mixed', 'replace_header='=>'mixed'], 'http\Env\Request::__construct' => ['void'], 'http\Env\Request::__toString' => ['string'], 'http\Env\Request::addBody' => ['http\Message', 'body'=>'http\Message\Body'], 'http\Env\Request::addHeader' => ['http\Message', 'header'=>'string', 'value'=>'mixed'], 'http\Env\Request::addHeaders' => ['http\Message', 'headers'=>'array', 'append='=>'mixed'], 'http\Env\Request::count' => ['int'], 'http\Env\Request::current' => ['mixed'], 'http\Env\Request::detach' => ['http\Message'], 'http\Env\Request::getBody' => ['http\Message\Body'], 'http\Env\Request::getCookie' => ['mixed', 'name='=>'string', 'type='=>'mixed', 'defval='=>'mixed', 'delete='=>'bool'], 'http\Env\Request::getFiles' => ['array'], 'http\Env\Request::getForm' => ['mixed', 'name='=>'string', 'type='=>'mixed', 'defval='=>'mixed', 'delete='=>'bool'], 'http\Env\Request::getHeader' => ['http\Header|mixed', 'header'=>'string', 'into_class='=>'mixed'], 'http\Env\Request::getHeaders' => ['array'], 'http\Env\Request::getHttpVersion' => ['string'], 'http\Env\Request::getInfo' => ['null|string'], 'http\Env\Request::getParentMessage' => ['http\Message'], 'http\Env\Request::getQuery' => ['mixed', 'name='=>'string', 'type='=>'mixed', 'defval='=>'mixed', 'delete='=>'bool'], 'http\Env\Request::getRequestMethod' => ['false|string'], 'http\Env\Request::getRequestUrl' => ['false|string'], 'http\Env\Request::getResponseCode' => ['false|int'], 'http\Env\Request::getResponseStatus' => ['false|string'], 'http\Env\Request::getType' => ['int'], 'http\Env\Request::isMultipart' => ['bool', '&boundary='=>'mixed'], 'http\Env\Request::key' => ['int|string'], 'http\Env\Request::next' => ['void'], 'http\Env\Request::prepend' => ['http\Message', 'message'=>'http\Message', 'top='=>'mixed'], 'http\Env\Request::reverse' => ['http\Message'], 'http\Env\Request::rewind' => ['void'], 'http\Env\Request::serialize' => ['string'], 'http\Env\Request::setBody' => ['http\Message', 'body'=>'http\Message\Body'], 'http\Env\Request::setHeader' => ['http\Message', 'header'=>'string', 'value='=>'mixed'], 'http\Env\Request::setHeaders' => ['http\Message', 'headers'=>'array'], 'http\Env\Request::setHttpVersion' => ['http\Message', 'http_version'=>'string'], 'http\Env\Request::setInfo' => ['http\Message', 'http_info'=>'string'], 'http\Env\Request::setRequestMethod' => ['http\Message', 'request_method'=>'string'], 'http\Env\Request::setRequestUrl' => ['http\Message', 'url'=>'string'], 'http\Env\Request::setResponseCode' => ['http\Message', 'response_code'=>'int', 'strict='=>'mixed'], 'http\Env\Request::setResponseStatus' => ['http\Message', 'response_status'=>'string'], 'http\Env\Request::setType' => ['http\Message', 'type'=>'int'], 'http\Env\Request::splitMultipartBody' => ['http\Message'], 'http\Env\Request::toCallback' => ['http\Message', 'callback'=>'callable'], 'http\Env\Request::toStream' => ['http\Message', 'stream'=>'resource'], 'http\Env\Request::toString' => ['string', 'include_parent='=>'mixed'], 'http\Env\Request::unserialize' => ['void', 'serialized'=>'string'], 'http\Env\Request::valid' => ['bool'], 'http\Env\Response::__construct' => ['void'], 'http\Env\Response::__invoke' => ['bool', 'data'=>'string', 'ob_flags='=>'int'], 'http\Env\Response::__toString' => ['string'], 'http\Env\Response::addBody' => ['http\Message', 'body'=>'http\Message\Body'], 'http\Env\Response::addHeader' => ['http\Message', 'header'=>'string', 'value'=>'mixed'], 'http\Env\Response::addHeaders' => ['http\Message', 'headers'=>'array', 'append='=>'mixed'], 'http\Env\Response::count' => ['int'], 'http\Env\Response::current' => ['mixed'], 'http\Env\Response::detach' => ['http\Message'], 'http\Env\Response::getBody' => ['http\Message\Body'], 'http\Env\Response::getHeader' => ['http\Header|mixed', 'header'=>'string', 'into_class='=>'mixed'], 'http\Env\Response::getHeaders' => ['array'], 'http\Env\Response::getHttpVersion' => ['string'], 'http\Env\Response::getInfo' => ['?string'], 'http\Env\Response::getParentMessage' => ['http\Message'], 'http\Env\Response::getRequestMethod' => ['false|string'], 'http\Env\Response::getRequestUrl' => ['false|string'], 'http\Env\Response::getResponseCode' => ['false|int'], 'http\Env\Response::getResponseStatus' => ['false|string'], 'http\Env\Response::getType' => ['int'], 'http\Env\Response::isCachedByETag' => ['int', 'header_name='=>'string'], 'http\Env\Response::isCachedByLastModified' => ['int', 'header_name='=>'string'], 'http\Env\Response::isMultipart' => ['bool', '&boundary='=>'mixed'], 'http\Env\Response::key' => ['int|string'], 'http\Env\Response::next' => ['void'], 'http\Env\Response::prepend' => ['http\Message', 'message'=>'http\Message', 'top='=>'mixed'], 'http\Env\Response::reverse' => ['http\Message'], 'http\Env\Response::rewind' => ['void'], 'http\Env\Response::send' => ['bool', 'stream='=>'resource'], 'http\Env\Response::serialize' => ['string'], 'http\Env\Response::setBody' => ['http\Message', 'body'=>'http\Message\Body'], 'http\Env\Response::setCacheControl' => ['http\Env\Response', 'cache_control'=>'string'], 'http\Env\Response::setContentDisposition' => ['http\Env\Response', 'disposition_params'=>'array'], 'http\Env\Response::setContentEncoding' => ['http\Env\Response', 'content_encoding'=>'int'], 'http\Env\Response::setContentType' => ['http\Env\Response', 'content_type'=>'string'], 'http\Env\Response::setCookie' => ['http\Env\Response', 'cookie'=>'mixed'], 'http\Env\Response::setEnvRequest' => ['http\Env\Response', 'env_request'=>'http\Message'], 'http\Env\Response::setEtag' => ['http\Env\Response', 'etag'=>'string'], 'http\Env\Response::setHeader' => ['http\Message', 'header'=>'string', 'value='=>'mixed'], 'http\Env\Response::setHeaders' => ['http\Message', 'headers'=>'array'], 'http\Env\Response::setHttpVersion' => ['http\Message', 'http_version'=>'string'], 'http\Env\Response::setInfo' => ['http\Message', 'http_info'=>'string'], 'http\Env\Response::setLastModified' => ['http\Env\Response', 'last_modified'=>'int'], 'http\Env\Response::setRequestMethod' => ['http\Message', 'request_method'=>'string'], 'http\Env\Response::setRequestUrl' => ['http\Message', 'url'=>'string'], 'http\Env\Response::setResponseCode' => ['http\Message', 'response_code'=>'int', 'strict='=>'mixed'], 'http\Env\Response::setResponseStatus' => ['http\Message', 'response_status'=>'string'], 'http\Env\Response::setThrottleRate' => ['http\Env\Response', 'chunk_size'=>'int', 'delay='=>'float|int'], 'http\Env\Response::setType' => ['http\Message', 'type'=>'int'], 'http\Env\Response::splitMultipartBody' => ['http\Message'], 'http\Env\Response::toCallback' => ['http\Message', 'callback'=>'callable'], 'http\Env\Response::toStream' => ['http\Message', 'stream'=>'resource'], 'http\Env\Response::toString' => ['string', 'include_parent='=>'mixed'], 'http\Env\Response::unserialize' => ['void', 'serialized'=>'string'], 'http\Env\Response::valid' => ['bool'], 'http\Header::__construct' => ['void', 'name='=>'mixed', 'value='=>'mixed'], 'http\Header::__toString' => ['string'], 'http\Header::getParams' => ['http\Params', 'param_sep='=>'mixed', 'arg_sep='=>'mixed', 'val_sep='=>'mixed', 'flags='=>'mixed'], 'http\Header::match' => ['bool', 'value'=>'string', 'flags='=>'mixed'], 'http\Header::negotiate' => ['null|string', 'supported'=>'array', '&result='=>'mixed'], 'http\Header::parse' => ['array|false', 'string'=>'string', 'header_class='=>'mixed'], 'http\Header::serialize' => ['string'], 'http\Header::toString' => ['string'], 'http\Header::unserialize' => ['void', 'serialized'=>'string'], 'http\Header\Parser::getState' => ['int'], 'http\Header\Parser::parse' => ['int', 'data'=>'string', 'flags'=>'int', '&headers'=>'array'], 'http\Header\Parser::stream' => ['int', 'stream'=>'resource', 'flags'=>'int', '&headers'=>'array'], 'http\Message::__construct' => ['void', 'message='=>'mixed', 'greedy='=>'bool'], 'http\Message::__toString' => ['string'], 'http\Message::addBody' => ['http\Message', 'body'=>'http\Message\Body'], 'http\Message::addHeader' => ['http\Message', 'header'=>'string', 'value'=>'mixed'], 'http\Message::addHeaders' => ['http\Message', 'headers'=>'array', 'append='=>'mixed'], 'http\Message::count' => ['int'], 'http\Message::current' => ['mixed'], 'http\Message::detach' => ['http\Message'], 'http\Message::getBody' => ['http\Message\Body'], 'http\Message::getHeader' => ['http\Header|mixed', 'header'=>'string', 'into_class='=>'mixed'], 'http\Message::getHeaders' => ['array'], 'http\Message::getHttpVersion' => ['string'], 'http\Message::getInfo' => ['null|string'], 'http\Message::getParentMessage' => ['http\Message'], 'http\Message::getRequestMethod' => ['false|string'], 'http\Message::getRequestUrl' => ['false|string'], 'http\Message::getResponseCode' => ['false|int'], 'http\Message::getResponseStatus' => ['false|string'], 'http\Message::getType' => ['int'], 'http\Message::isMultipart' => ['bool', '&boundary='=>'mixed'], 'http\Message::key' => ['int|string'], 'http\Message::next' => ['void'], 'http\Message::prepend' => ['http\Message', 'message'=>'http\Message', 'top='=>'mixed'], 'http\Message::reverse' => ['http\Message'], 'http\Message::rewind' => ['void'], 'http\Message::serialize' => ['string'], 'http\Message::setBody' => ['http\Message', 'body'=>'http\Message\Body'], 'http\Message::setHeader' => ['http\Message', 'header'=>'string', 'value='=>'mixed'], 'http\Message::setHeaders' => ['http\Message', 'headers'=>'array'], 'http\Message::setHttpVersion' => ['http\Message', 'http_version'=>'string'], 'http\Message::setInfo' => ['http\Message', 'http_info'=>'string'], 'http\Message::setRequestMethod' => ['http\Message', 'request_method'=>'string'], 'http\Message::setRequestUrl' => ['http\Message', 'url'=>'string'], 'http\Message::setResponseCode' => ['http\Message', 'response_code'=>'int', 'strict='=>'mixed'], 'http\Message::setResponseStatus' => ['http\Message', 'response_status'=>'string'], 'http\Message::setType' => ['http\Message', 'type'=>'int'], 'http\Message::splitMultipartBody' => ['http\Message'], 'http\Message::toCallback' => ['http\Message', 'callback'=>'callable'], 'http\Message::toStream' => ['http\Message', 'stream'=>'resource'], 'http\Message::toString' => ['string', 'include_parent='=>'mixed'], 'http\Message::unserialize' => ['void', 'serialized'=>'string'], 'http\Message::valid' => ['bool'], 'http\Message\Body::__construct' => ['void', 'stream='=>'resource'], 'http\Message\Body::__toString' => ['string'], 'http\Message\Body::addForm' => ['http\Message\Body', 'fields='=>'?array', 'files='=>'?array'], 'http\Message\Body::addPart' => ['http\Message\Body', 'message'=>'http\Message'], 'http\Message\Body::append' => ['http\Message\Body', 'string'=>'string'], 'http\Message\Body::etag' => ['false|string'], 'http\Message\Body::getBoundary' => ['null|string'], 'http\Message\Body::getResource' => ['resource'], 'http\Message\Body::serialize' => ['string'], 'http\Message\Body::stat' => ['int|object', 'field='=>'mixed'], 'http\Message\Body::toCallback' => ['http\Message\Body', 'callback'=>'callable', 'offset='=>'mixed', 'maxlen='=>'mixed'], 'http\Message\Body::toStream' => ['http\Message\Body', 'stream'=>'resource', 'offset='=>'mixed', 'maxlen='=>'mixed'], 'http\Message\Body::toString' => ['string'], 'http\Message\Body::unserialize' => ['void', 'serialized'=>'string'], 'http\Message\Parser::getState' => ['int'], 'http\Message\Parser::parse' => ['int', 'data'=>'string', 'flags'=>'int', '&message'=>'http\Message'], 'http\Message\Parser::stream' => ['int', 'stream'=>'resource', 'flags'=>'int', '&message'=>'http\Message'], 'http\Params::__construct' => ['void', 'params='=>'mixed', 'param_sep='=>'mixed', 'arg_sep='=>'mixed', 'val_sep='=>'mixed', 'flags='=>'mixed'], 'http\Params::__toString' => ['string'], 'http\Params::offsetExists' => ['bool', 'name'=>'int|string'], 'http\Params::offsetGet' => ['mixed', 'name'=>'int|string'], 'http\Params::offsetSet' => ['void', 'name'=>'int|string|null', 'value'=>'mixed'], 'http\Params::offsetUnset' => ['void', 'name'=>'int|string'], 'http\Params::toArray' => ['array'], 'http\Params::toString' => ['string'], 'http\QueryString::__construct' => ['void', 'querystring'=>'string'], 'http\QueryString::__toString' => ['string'], 'http\QueryString::get' => ['http\QueryString|string|mixed', 'name='=>'string', 'type='=>'mixed', 'defval='=>'mixed', 'delete='=>'bool|false'], 'http\QueryString::getArray' => ['array|mixed', 'name'=>'string', 'defval='=>'mixed', 'delete='=>'bool|false'], 'http\QueryString::getBool' => ['bool|mixed', 'name'=>'string', 'defval='=>'mixed', 'delete='=>'bool|false'], 'http\QueryString::getFloat' => ['float|mixed', 'name'=>'string', 'defval='=>'mixed', 'delete='=>'bool|false'], 'http\QueryString::getGlobalInstance' => ['http\QueryString'], 'http\QueryString::getInt' => ['int|mixed', 'name'=>'string', 'defval='=>'mixed', 'delete='=>'bool|false'], 'http\QueryString::getIterator' => ['IteratorAggregate'], 'http\QueryString::getObject' => ['object|mixed', 'name'=>'string', 'defval='=>'mixed', 'delete='=>'bool|false'], 'http\QueryString::getString' => ['string|mixed', 'name'=>'string', 'defval='=>'mixed', 'delete='=>'bool|false'], 'http\QueryString::mod' => ['http\QueryString', 'params='=>'mixed'], 'http\QueryString::offsetExists' => ['bool', 'offset'=>'int|string'], 'http\QueryString::offsetGet' => ['mixed|null', 'offset'=>'int|string'], 'http\QueryString::offsetSet' => ['void', 'offset'=>'int|string|null', 'value'=>'mixed'], 'http\QueryString::offsetUnset' => ['void', 'offset'=>'int|string'], 'http\QueryString::serialize' => ['string'], 'http\QueryString::set' => ['http\QueryString', 'params'=>'mixed'], 'http\QueryString::toArray' => ['array'], 'http\QueryString::toString' => ['string'], 'http\QueryString::unserialize' => ['void', 'serialized'=>'string'], 'http\QueryString::xlate' => ['http\QueryString'], 'http\Url::__construct' => ['void', 'old_url='=>'mixed', 'new_url='=>'mixed', 'flags='=>'int'], 'http\Url::__toString' => ['string'], 'http\Url::mod' => ['http\Url', 'parts'=>'mixed', 'flags='=>'float|int|mixed'], 'http\Url::toArray' => ['string[]'], 'http\Url::toString' => ['string'], 'http_build_cookie' => ['string', 'cookie'=>'array'], 'http_build_query' => ['string', 'data'=>'array|object', 'numeric_prefix='=>'string', 'arg_separator='=>'?string', 'encoding_type='=>'int'], 'http_build_str' => ['string', 'query'=>'array', 'prefix='=>'?string', 'arg_separator='=>'string'], 'http_build_url' => ['string', 'url='=>'string|array', 'parts='=>'string|array', 'flags='=>'int', 'new_url='=>'array'], 'http_cache_etag' => ['bool', 'etag='=>'string'], 'http_cache_last_modified' => ['bool', 'timestamp_or_expires='=>'int'], 'http_chunked_decode' => ['string|false', 'encoded'=>'string'], 'http_date' => ['string', 'timestamp='=>'int'], 'http_deflate' => ['?string', 'data'=>'string', 'flags='=>'int'], 'http_get' => ['string', 'url'=>'string', 'options='=>'array', 'info='=>'array'], 'http_get_request_body' => ['?string'], 'http_get_request_body_stream' => ['?resource'], 'http_get_request_headers' => ['array'], 'http_head' => ['string', 'url'=>'string', 'options='=>'array', 'info='=>'array'], 'http_inflate' => ['?string', 'data'=>'string'], 'http_match_etag' => ['bool', 'etag'=>'string', 'for_range='=>'bool'], 'http_match_modified' => ['bool', 'timestamp='=>'int', 'for_range='=>'bool'], 'http_match_request_header' => ['bool', 'header'=>'string', 'value'=>'string', 'match_case='=>'bool'], 'http_negotiate_charset' => ['string', 'supported'=>'array', 'result='=>'array'], 'http_negotiate_content_type' => ['string', 'supported'=>'array', 'result='=>'array'], 'http_negotiate_language' => ['string', 'supported'=>'array', 'result='=>'array'], 'http_parse_cookie' => ['stdClass|false', 'cookie'=>'string', 'flags='=>'int', 'allowed_extras='=>'array'], 'http_parse_headers' => ['array|false', 'header'=>'string'], 'http_parse_message' => ['object', 'message'=>'string'], 'http_parse_params' => ['stdClass', 'param'=>'string', 'flags='=>'int'], 'http_persistent_handles_clean' => ['string', 'ident='=>'string'], 'http_persistent_handles_count' => ['stdClass|false'], 'http_persistent_handles_ident' => ['string|false', 'ident='=>'string'], 'http_post_data' => ['string', 'url'=>'string', 'data'=>'string', 'options='=>'array', 'info='=>'array'], 'http_post_fields' => ['string', 'url'=>'string', 'data'=>'array', 'files='=>'array', 'options='=>'array', 'info='=>'array'], 'http_put_data' => ['string', 'url'=>'string', 'data'=>'string', 'options='=>'array', 'info='=>'array'], 'http_put_file' => ['string', 'url'=>'string', 'file'=>'string', 'options='=>'array', 'info='=>'array'], 'http_put_stream' => ['string', 'url'=>'string', 'stream'=>'resource', 'options='=>'array', 'info='=>'array'], 'http_redirect' => ['int|false', 'url='=>'string', 'params='=>'array', 'session='=>'bool', 'status='=>'int'], 'http_request' => ['string', 'method'=>'int', 'url'=>'string', 'body='=>'string', 'options='=>'array', 'info='=>'array'], 'http_request_body_encode' => ['string|false', 'fields'=>'array', 'files'=>'array'], 'http_request_method_exists' => ['bool', 'method'=>'mixed'], 'http_request_method_name' => ['string|false', 'method'=>'int'], 'http_request_method_register' => ['int|false', 'method'=>'string'], 'http_request_method_unregister' => ['bool', 'method'=>'mixed'], 'http_response_code' => ['int|bool', 'response_code='=>'int'], 'http_send_content_disposition' => ['bool', 'filename'=>'string', 'inline='=>'bool'], 'http_send_content_type' => ['bool', 'content_type='=>'string'], 'http_send_data' => ['bool', 'data'=>'string'], 'http_send_file' => ['bool', 'file'=>'string'], 'http_send_last_modified' => ['bool', 'timestamp='=>'int'], 'http_send_status' => ['bool', 'status'=>'int'], 'http_send_stream' => ['bool', 'stream'=>'resource'], 'http_support' => ['int', 'feature='=>'int'], 'http_throttle' => ['void', 'sec'=>'float', 'bytes='=>'int'], 'hw_Array2Objrec' => ['string', 'object_array'=>'array'], 'hw_Children' => ['array', 'connection'=>'int', 'objectid'=>'int'], 'hw_ChildrenObj' => ['array', 'connection'=>'int', 'objectid'=>'int'], 'hw_Close' => ['bool', 'connection'=>'int'], 'hw_Connect' => ['int', 'host'=>'string', 'port'=>'int', 'username='=>'string', 'password='=>'string'], 'hw_Deleteobject' => ['bool', 'connection'=>'int', 'object_to_delete'=>'int'], 'hw_DocByAnchor' => ['int', 'connection'=>'int', 'anchorid'=>'int'], 'hw_DocByAnchorObj' => ['string', 'connection'=>'int', 'anchorid'=>'int'], 'hw_Document_Attributes' => ['string', 'hw_document'=>'int'], 'hw_Document_BodyTag' => ['string', 'hw_document'=>'int', 'prefix='=>'string'], 'hw_Document_Content' => ['string', 'hw_document'=>'int'], 'hw_Document_SetContent' => ['bool', 'hw_document'=>'int', 'content'=>'string'], 'hw_Document_Size' => ['int', 'hw_document'=>'int'], 'hw_EditText' => ['bool', 'connection'=>'int', 'hw_document'=>'int'], 'hw_Error' => ['int', 'connection'=>'int'], 'hw_ErrorMsg' => ['string', 'connection'=>'int'], 'hw_Free_Document' => ['bool', 'hw_document'=>'int'], 'hw_GetAnchors' => ['array', 'connection'=>'int', 'objectid'=>'int'], 'hw_GetAnchorsObj' => ['array', 'connection'=>'int', 'objectid'=>'int'], 'hw_GetAndLock' => ['string', 'connection'=>'int', 'objectid'=>'int'], 'hw_GetChildColl' => ['array', 'connection'=>'int', 'objectid'=>'int'], 'hw_GetChildCollObj' => ['array', 'connection'=>'int', 'objectid'=>'int'], 'hw_GetChildDocColl' => ['array', 'connection'=>'int', 'objectid'=>'int'], 'hw_GetChildDocCollObj' => ['array', 'connection'=>'int', 'objectid'=>'int'], 'hw_GetObject' => ['', 'connection'=>'int', 'objectid'=>'', 'query='=>'string'], 'hw_GetObjectByQuery' => ['array', 'connection'=>'int', 'query'=>'string', 'max_hits'=>'int'], 'hw_GetObjectByQueryColl' => ['array', 'connection'=>'int', 'objectid'=>'int', 'query'=>'string', 'max_hits'=>'int'], 'hw_GetObjectByQueryCollObj' => ['array', 'connection'=>'int', 'objectid'=>'int', 'query'=>'string', 'max_hits'=>'int'], 'hw_GetObjectByQueryObj' => ['array', 'connection'=>'int', 'query'=>'string', 'max_hits'=>'int'], 'hw_GetParents' => ['array', 'connection'=>'int', 'objectid'=>'int'], 'hw_GetParentsObj' => ['array', 'connection'=>'int', 'objectid'=>'int'], 'hw_GetRemote' => ['int', 'connection'=>'int', 'objectid'=>'int'], 'hw_GetSrcByDestObj' => ['array', 'connection'=>'int', 'objectid'=>'int'], 'hw_GetText' => ['int', 'connection'=>'int', 'objectid'=>'int', 'prefix='=>''], 'hw_Identify' => ['string', 'link'=>'int', 'username'=>'string', 'password'=>'string'], 'hw_InCollections' => ['array', 'connection'=>'int', 'object_id_array'=>'array', 'collection_id_array'=>'array', 'return_collections'=>'int'], 'hw_Info' => ['string', 'connection'=>'int'], 'hw_InsColl' => ['int', 'connection'=>'int', 'objectid'=>'int', 'object_array'=>'array'], 'hw_InsDoc' => ['int', 'connection'=>'', 'parentid'=>'int', 'object_record'=>'string', 'text='=>'string'], 'hw_InsertDocument' => ['int', 'connection'=>'int', 'parent_id'=>'int', 'hw_document'=>'int'], 'hw_InsertObject' => ['int', 'connection'=>'int', 'object_rec'=>'string', 'parameter'=>'string'], 'hw_Modifyobject' => ['bool', 'connection'=>'int', 'object_to_change'=>'int', 'remove'=>'array', 'add'=>'array', 'mode='=>'int'], 'hw_New_Document' => ['int', 'object_record'=>'string', 'document_data'=>'string', 'document_size'=>'int'], 'hw_Output_Document' => ['bool', 'hw_document'=>'int'], 'hw_PipeDocument' => ['int', 'connection'=>'int', 'objectid'=>'int', 'url_prefixes='=>'array'], 'hw_Root' => ['int'], 'hw_Unlock' => ['bool', 'connection'=>'int', 'objectid'=>'int'], 'hw_Who' => ['array', 'connection'=>'int'], 'hw_api::checkin' => ['bool', 'parameter'=>'array'], 'hw_api::checkout' => ['bool', 'parameter'=>'array'], 'hw_api::children' => ['array', 'parameter'=>'array'], 'hw_api::content' => ['HW_API_Content', 'parameter'=>'array'], 'hw_api::copy' => ['hw_api_content', 'parameter'=>'array'], 'hw_api::dbstat' => ['hw_api_object', 'parameter'=>'array'], 'hw_api::dcstat' => ['hw_api_object', 'parameter'=>'array'], 'hw_api::dstanchors' => ['array', 'parameter'=>'array'], 'hw_api::dstofsrcanchor' => ['hw_api_object', 'parameter'=>'array'], 'hw_api::find' => ['array', 'parameter'=>'array'], 'hw_api::ftstat' => ['hw_api_object', 'parameter'=>'array'], 'hw_api::hwstat' => ['hw_api_object', 'parameter'=>'array'], 'hw_api::identify' => ['bool', 'parameter'=>'array'], 'hw_api::info' => ['array', 'parameter'=>'array'], 'hw_api::insert' => ['hw_api_object', 'parameter'=>'array'], 'hw_api::insertanchor' => ['hw_api_object', 'parameter'=>'array'], 'hw_api::insertcollection' => ['hw_api_object', 'parameter'=>'array'], 'hw_api::insertdocument' => ['hw_api_object', 'parameter'=>'array'], 'hw_api::link' => ['bool', 'parameter'=>'array'], 'hw_api::lock' => ['bool', 'parameter'=>'array'], 'hw_api::move' => ['bool', 'parameter'=>'array'], 'hw_api::object' => ['hw_api_object', 'parameter'=>'array'], 'hw_api::objectbyanchor' => ['hw_api_object', 'parameter'=>'array'], 'hw_api::parents' => ['array', 'parameter'=>'array'], 'hw_api::remove' => ['bool', 'parameter'=>'array'], 'hw_api::replace' => ['hw_api_object', 'parameter'=>'array'], 'hw_api::setcommittedversion' => ['hw_api_object', 'parameter'=>'array'], 'hw_api::srcanchors' => ['array', 'parameter'=>'array'], 'hw_api::srcsofdst' => ['array', 'parameter'=>'array'], 'hw_api::unlock' => ['bool', 'parameter'=>'array'], 'hw_api::user' => ['hw_api_object', 'parameter'=>'array'], 'hw_api::userlist' => ['array', 'parameter'=>'array'], 'hw_api_attribute' => ['HW_API_Attribute', 'name='=>'string', 'value='=>'string'], 'hw_api_attribute::key' => ['string'], 'hw_api_attribute::langdepvalue' => ['string', 'language'=>'string'], 'hw_api_attribute::value' => ['string'], 'hw_api_attribute::values' => ['array'], 'hw_api_content' => ['HW_API_Content', 'content'=>'string', 'mimetype'=>'string'], 'hw_api_content::mimetype' => ['string'], 'hw_api_content::read' => ['string', 'buffer'=>'string', 'length'=>'int'], 'hw_api_error::count' => ['int'], 'hw_api_error::reason' => ['HW_API_Reason'], 'hw_api_object' => ['hw_api_object', 'parameter'=>'array'], 'hw_api_object::assign' => ['bool', 'parameter'=>'array'], 'hw_api_object::attreditable' => ['bool', 'parameter'=>'array'], 'hw_api_object::count' => ['int', 'parameter'=>'array'], 'hw_api_object::insert' => ['bool', 'attribute'=>'hw_api_attribute'], 'hw_api_object::remove' => ['bool', 'name'=>'string'], 'hw_api_object::title' => ['string', 'parameter'=>'array'], 'hw_api_object::value' => ['string', 'name'=>'string'], 'hw_api_reason::description' => ['string'], 'hw_api_reason::type' => ['HW_API_Reason'], 'hw_changeobject' => ['bool', 'link'=>'int', 'objid'=>'int', 'attributes'=>'array'], 'hw_connection_info' => ['', 'link'=>'int'], 'hw_cp' => ['int', 'connection'=>'int', 'object_id_array'=>'array', 'destination_id'=>'int'], 'hw_dummy' => ['string', 'link'=>'int', 'id'=>'int', 'msgid'=>'int'], 'hw_getrellink' => ['string', 'link'=>'int', 'rootid'=>'int', 'sourceid'=>'int', 'destid'=>'int'], 'hw_getremotechildren' => ['', 'connection'=>'int', 'object_record'=>'string'], 'hw_getusername' => ['string', 'connection'=>'int'], 'hw_insertanchors' => ['bool', 'hwdoc'=>'int', 'anchorecs'=>'array', 'dest'=>'array', 'urlprefixes='=>'array'], 'hw_mapid' => ['int', 'connection'=>'int', 'server_id'=>'int', 'object_id'=>'int'], 'hw_mv' => ['int', 'connection'=>'int', 'object_id_array'=>'array', 'source_id'=>'int', 'destination_id'=>'int'], 'hw_objrec2array' => ['array', 'object_record'=>'string', 'format='=>'array'], 'hw_pConnect' => ['int', 'host'=>'string', 'port'=>'int', 'username='=>'string', 'password='=>'string'], 'hw_setlinkroot' => ['int', 'link'=>'int', 'rootid'=>'int'], 'hw_stat' => ['string', 'link'=>'int'], 'hwapi_attribute_new' => ['HW_API_Attribute', 'name='=>'string', 'value='=>'string'], 'hwapi_content_new' => ['HW_API_Content', 'content'=>'string', 'mimetype'=>'string'], 'hwapi_hgcsp' => ['HW_API', 'hostname'=>'string', 'port='=>'int'], 'hwapi_object_new' => ['hw_api_object', 'parameter'=>'array'], 'hypot' => ['float', 'x'=>'float', 'y'=>'float'], 'ibase_add_user' => ['bool', 'service_handle'=>'resource', 'user_name'=>'string', 'password'=>'string', 'first_name='=>'string', 'middle_name='=>'string', 'last_name='=>'string'], 'ibase_affected_rows' => ['int', 'link_identifier='=>'resource'], 'ibase_backup' => ['mixed', 'service_handle'=>'resource', 'source_db'=>'string', 'dest_file'=>'string', 'options='=>'int', 'verbose='=>'bool'], 'ibase_blob_add' => ['void', 'blob_handle'=>'resource', 'data'=>'string'], 'ibase_blob_cancel' => ['bool', 'blob_handle'=>'resource'], 'ibase_blob_close' => ['string|bool', 'blob_handle'=>'resource'], 'ibase_blob_create' => ['resource', 'link_identifier='=>'resource'], 'ibase_blob_echo' => ['bool', 'link_identifier'=>'', 'blob_id'=>'string'], 'ibase_blob_echo\'1' => ['bool', 'blob_id'=>'string'], 'ibase_blob_get' => ['string|false', 'blob_handle'=>'resource', 'length'=>'int'], 'ibase_blob_import' => ['string|false', 'link_identifier'=>'resource', 'file_handle'=>'resource'], 'ibase_blob_info' => ['array', 'link_identifier'=>'resource', 'blob_id'=>'string'], 'ibase_blob_info\'1' => ['array', 'blob_id'=>'string'], 'ibase_blob_open' => ['resource|false', 'link_identifier'=>'', 'blob_id'=>'string'], 'ibase_blob_open\'1' => ['resource', 'blob_id'=>'string'], 'ibase_close' => ['bool', 'link_identifier='=>'resource'], 'ibase_commit' => ['bool', 'link_identifier='=>'resource'], 'ibase_commit_ret' => ['bool', 'link_identifier='=>'resource'], 'ibase_connect' => ['resource|false', 'database='=>'string', 'username='=>'string', 'password='=>'string', 'charset='=>'string', 'buffers='=>'int', 'dialect='=>'int', 'role='=>'string'], 'ibase_db_info' => ['string', 'service_handle'=>'resource', 'db'=>'string', 'action'=>'int', 'argument='=>'int'], 'ibase_delete_user' => ['bool', 'service_handle'=>'resource', 'user_name'=>'string', 'password='=>'string', 'first_name='=>'string', 'middle_name='=>'string', 'last_name='=>'string'], 'ibase_drop_db' => ['bool', 'link_identifier='=>'resource'], 'ibase_errcode' => ['int|false'], 'ibase_errmsg' => ['string|false'], 'ibase_execute' => ['resource|false', 'query'=>'resource', 'bind_arg='=>'mixed', '...args='=>'mixed'], 'ibase_fetch_assoc' => ['array|false', 'result'=>'resource', 'fetch_flags='=>'int'], 'ibase_fetch_object' => ['object|false', 'result'=>'resource', 'fetch_flags='=>'int'], 'ibase_fetch_row' => ['array|false', 'result'=>'resource', 'fetch_flags='=>'int'], 'ibase_field_info' => ['array', 'query_result'=>'resource', 'field_number'=>'int'], 'ibase_free_event_handler' => ['bool', 'event'=>'resource'], 'ibase_free_query' => ['bool', 'query'=>'resource'], 'ibase_free_result' => ['bool', 'result'=>'resource'], 'ibase_gen_id' => ['int|string', 'generator'=>'string', 'increment='=>'int', 'link_identifier='=>'resource'], 'ibase_maintain_db' => ['bool', 'service_handle'=>'resource', 'db'=>'string', 'action'=>'int', 'argument='=>'int'], 'ibase_modify_user' => ['bool', 'service_handle'=>'resource', 'user_name'=>'string', 'password'=>'string', 'first_name='=>'string', 'middle_name='=>'string', 'last_name='=>'string'], 'ibase_name_result' => ['bool', 'result'=>'resource', 'name'=>'string'], 'ibase_num_fields' => ['int', 'query_result'=>'resource'], 'ibase_num_params' => ['int', 'query'=>'resource'], 'ibase_num_rows' => ['int', 'result_identifier'=>''], 'ibase_param_info' => ['array', 'query'=>'resource', 'field_number'=>'int'], 'ibase_pconnect' => ['resource|false', 'database='=>'string', 'username='=>'string', 'password='=>'string', 'charset='=>'string', 'buffers='=>'int', 'dialect='=>'int', 'role='=>'string'], 'ibase_prepare' => ['resource|false', 'link_identifier'=>'', 'query'=>'string', 'trans_identifier'=>''], 'ibase_query' => ['resource|false', 'link_identifier='=>'resource', 'string='=>'string', 'bind_arg='=>'int', '...args='=>''], 'ibase_restore' => ['mixed', 'service_handle'=>'resource', 'source_file'=>'string', 'dest_db'=>'string', 'options='=>'int', 'verbose='=>'bool'], 'ibase_rollback' => ['bool', 'link_identifier='=>'resource'], 'ibase_rollback_ret' => ['bool', 'link_identifier='=>'resource'], 'ibase_server_info' => ['string', 'service_handle'=>'resource', 'action'=>'int'], 'ibase_service_attach' => ['resource', 'host'=>'string', 'dba_username'=>'string', 'dba_password'=>'string'], 'ibase_service_detach' => ['bool', 'service_handle'=>'resource'], 'ibase_set_event_handler' => ['resource', 'link_identifier'=>'', 'callback'=>'callable', 'event='=>'string', '...args='=>''], 'ibase_set_event_handler\'1' => ['resource', 'callback'=>'callable', 'event'=>'string', '...args'=>''], 'ibase_timefmt' => ['bool', 'format'=>'string', 'columntype='=>'int'], 'ibase_trans' => ['resource|false', 'trans_args='=>'int', 'link_identifier='=>'', '...args='=>''], 'ibase_wait_event' => ['string', 'link_identifier'=>'', 'event='=>'string', '...args='=>''], 'ibase_wait_event\'1' => ['string', 'event'=>'string', '...args'=>''], 'iconv' => ['string|false', 'from_encoding'=>'string', 'to_encoding'=>'string', 'string'=>'string'], 'iconv_get_encoding' => ['array|string|false', 'type='=>'string'], 'iconv_mime_decode' => ['string|false', 'string'=>'string', 'mode='=>'int', 'encoding='=>'string'], 'iconv_mime_decode_headers' => ['array|false', 'headers'=>'string', 'mode='=>'int', 'encoding='=>'string'], 'iconv_mime_encode' => ['string|false', 'field_name'=>'string', 'field_value'=>'string', 'options='=>'array'], 'iconv_set_encoding' => ['bool', 'type'=>'string', 'encoding'=>'string'], 'iconv_strlen' => ['0|positive-int|false', 'string'=>'string', 'encoding='=>'string'], 'iconv_strpos' => ['int|false', 'haystack'=>'string', 'needle'=>'string', 'offset='=>'int', 'encoding='=>'string'], 'iconv_strrpos' => ['int|false', 'haystack'=>'string', 'needle'=>'string', 'encoding='=>'string'], 'iconv_substr' => ['string|false', 'string'=>'string', 'offset'=>'int', 'length='=>'int', 'encoding='=>'string'], 'id3_get_frame_long_name' => ['string', 'frameid'=>'string'], 'id3_get_frame_short_name' => ['string', 'frameid'=>'string'], 'id3_get_genre_id' => ['int', 'genre'=>'string'], 'id3_get_genre_list' => ['array'], 'id3_get_genre_name' => ['string', 'genre_id'=>'int'], 'id3_get_tag' => ['array', 'filename'=>'string', 'version='=>'int'], 'id3_get_version' => ['int', 'filename'=>'string'], 'id3_remove_tag' => ['bool', 'filename'=>'string', 'version='=>'int'], 'id3_set_tag' => ['bool', 'filename'=>'string', 'tag'=>'array', 'version='=>'int'], 'idate' => ['int', 'format'=>'string', 'timestamp='=>'int'], 'idn_strerror' => ['string', 'errorcode'=>'int'], 'idn_to_ascii' => ['string|false', 'domain'=>'string', 'flags='=>'int', 'variant='=>'int', '&w_idna_info='=>'array'], 'idn_to_utf8' => ['string|false', 'domain'=>'string', 'flags='=>'int', 'variant='=>'int', '&w_idna_info='=>'array'], 'ifx_affected_rows' => ['int', 'result_id'=>'resource'], 'ifx_blobinfile_mode' => ['bool', 'mode'=>'int'], 'ifx_byteasvarchar' => ['bool', 'mode'=>'int'], 'ifx_close' => ['bool', 'link_identifier='=>'resource'], 'ifx_connect' => ['resource', 'database='=>'string', 'userid='=>'string', 'password='=>'string'], 'ifx_copy_blob' => ['int', 'bid'=>'int'], 'ifx_create_blob' => ['int', 'type'=>'int', 'mode'=>'int', 'param'=>'string'], 'ifx_create_char' => ['int', 'param'=>'string'], 'ifx_do' => ['bool', 'result_id'=>'resource'], 'ifx_error' => ['string', 'link_identifier='=>'resource'], 'ifx_errormsg' => ['string', 'errorcode='=>'int'], 'ifx_fetch_row' => ['array', 'result_id'=>'resource', 'position='=>'mixed'], 'ifx_fieldproperties' => ['array', 'result_id'=>'resource'], 'ifx_fieldtypes' => ['array', 'result_id'=>'resource'], 'ifx_free_blob' => ['bool', 'bid'=>'int'], 'ifx_free_char' => ['bool', 'bid'=>'int'], 'ifx_free_result' => ['bool', 'result_id'=>'resource'], 'ifx_get_blob' => ['string', 'bid'=>'int'], 'ifx_get_char' => ['string', 'bid'=>'int'], 'ifx_getsqlca' => ['array', 'result_id'=>'resource'], 'ifx_htmltbl_result' => ['int', 'result_id'=>'resource', 'html_table_options='=>'string'], 'ifx_nullformat' => ['bool', 'mode'=>'int'], 'ifx_num_fields' => ['int', 'result_id'=>'resource'], 'ifx_num_rows' => ['int', 'result_id'=>'resource'], 'ifx_pconnect' => ['resource', 'database='=>'string', 'userid='=>'string', 'password='=>'string'], 'ifx_prepare' => ['resource', 'query'=>'string', 'link_identifier'=>'resource', 'cursor_def='=>'int', 'blobidarray='=>'mixed'], 'ifx_query' => ['resource', 'query'=>'string', 'link_identifier'=>'resource', 'cursor_type='=>'int', 'blobidarray='=>'mixed'], 'ifx_textasvarchar' => ['bool', 'mode'=>'int'], 'ifx_update_blob' => ['bool', 'bid'=>'int', 'content'=>'string'], 'ifx_update_char' => ['bool', 'bid'=>'int', 'content'=>'string'], 'ifxus_close_slob' => ['bool', 'bid'=>'int'], 'ifxus_create_slob' => ['int', 'mode'=>'int'], 'ifxus_free_slob' => ['bool', 'bid'=>'int'], 'ifxus_open_slob' => ['int', 'bid'=>'int', 'mode'=>'int'], 'ifxus_read_slob' => ['string', 'bid'=>'int', 'nbytes'=>'int'], 'ifxus_seek_slob' => ['int', 'bid'=>'int', 'mode'=>'int', 'offset'=>'int'], 'ifxus_tell_slob' => ['int', 'bid'=>'int'], 'ifxus_write_slob' => ['int', 'bid'=>'int', 'content'=>'string'], 'igbinary_serialize' => ['string|false', 'value'=>'mixed'], 'igbinary_unserialize' => ['mixed', 'str'=>'string'], 'ignore_user_abort' => ['int', 'enable='=>'bool'], 'iis_add_server' => ['int', 'path'=>'string', 'comment'=>'string', 'server_ip'=>'string', 'port'=>'int', 'host_name'=>'string', 'rights'=>'int', 'start_server'=>'int'], 'iis_get_dir_security' => ['int', 'server_instance'=>'int', 'virtual_path'=>'string'], 'iis_get_script_map' => ['string', 'server_instance'=>'int', 'virtual_path'=>'string', 'script_extension'=>'string'], 'iis_get_server_by_comment' => ['int', 'comment'=>'string'], 'iis_get_server_by_path' => ['int', 'path'=>'string'], 'iis_get_server_rights' => ['int', 'server_instance'=>'int', 'virtual_path'=>'string'], 'iis_get_service_state' => ['int', 'service_id'=>'string'], 'iis_remove_server' => ['int', 'server_instance'=>'int'], 'iis_set_app_settings' => ['int', 'server_instance'=>'int', 'virtual_path'=>'string', 'application_scope'=>'string'], 'iis_set_dir_security' => ['int', 'server_instance'=>'int', 'virtual_path'=>'string', 'directory_flags'=>'int'], 'iis_set_script_map' => ['int', 'server_instance'=>'int', 'virtual_path'=>'string', 'script_extension'=>'string', 'engine_path'=>'string', 'allow_scripting'=>'int'], 'iis_set_server_rights' => ['int', 'server_instance'=>'int', 'virtual_path'=>'string', 'directory_flags'=>'int'], 'iis_start_server' => ['int', 'server_instance'=>'int'], 'iis_start_service' => ['int', 'service_id'=>'string'], 'iis_stop_server' => ['int', 'server_instance'=>'int'], 'iis_stop_service' => ['int', 'service_id'=>'string'], 'image2wbmp' => ['bool', 'im'=>'resource', 'filename='=>'?string', 'threshold='=>'int'], 'imageObj::pasteImage' => ['void', 'srcImg'=>'imageObj', 'transparentColorHex'=>'int', 'dstX'=>'int', 'dstY'=>'int', 'angle'=>'int'], 'imageObj::saveImage' => ['int', 'filename'=>'string', 'oMap'=>'mapObj'], 'imageObj::saveWebImage' => ['string'], 'image_type_to_extension' => ['string', 'image_type'=>'int', 'include_dot='=>'bool'], 'image_type_to_mime_type' => ['string', 'image_type'=>'int'], 'imageaffine' => ['resource|false', 'src'=>'resource', 'affine'=>'array', 'clip='=>'array'], 'imageaffinematrixconcat' => ['array{0:float,1:float,2:float,3:float,4:float,5:float}|false', 'matrix1'=>'array', 'matrix2'=>'array'], 'imageaffinematrixget' => ['array{0:float,1:float,2:float,3:float,4:float,5:float}|false', 'type'=>'int', 'options'=>'array|float'], 'imagealphablending' => ['bool', 'image'=>'resource', 'enable'=>'bool'], 'imageantialias' => ['bool', 'image'=>'resource', 'enable'=>'bool'], 'imagearc' => ['bool', 'image'=>'resource', 'center_x'=>'int', 'center_y'=>'int', 'width'=>'int', 'height'=>'int', 'start_angle'=>'int', 'end_angle'=>'int', 'color'=>'int'], 'imagechar' => ['bool', 'image'=>'resource', 'font'=>'int', 'x'=>'int', 'y'=>'int', 'char'=>'string', 'color'=>'int'], 'imagecharup' => ['bool', 'image'=>'resource', 'font'=>'int', 'x'=>'int', 'y'=>'int', 'char'=>'string', 'color'=>'int'], 'imagecolorallocate' => ['int|false', 'image'=>'resource', 'red'=>'int', 'green'=>'int', 'blue'=>'int'], 'imagecolorallocatealpha' => ['int|false', 'image'=>'resource', 'red'=>'int', 'green'=>'int', 'blue'=>'int', 'alpha'=>'int'], 'imagecolorat' => ['int|false', 'image'=>'resource', 'x'=>'int', 'y'=>'int'], 'imagecolorclosest' => ['int', 'image'=>'resource', 'red'=>'int', 'green'=>'int', 'blue'=>'int'], 'imagecolorclosestalpha' => ['int', 'image'=>'resource', 'red'=>'int', 'green'=>'int', 'blue'=>'int', 'alpha'=>'int'], 'imagecolorclosesthwb' => ['int', 'image'=>'resource', 'red'=>'int', 'green'=>'int', 'blue'=>'int'], 'imagecolordeallocate' => ['bool', 'image'=>'resource', 'color'=>'int'], 'imagecolorexact' => ['int', 'image'=>'resource', 'red'=>'int', 'green'=>'int', 'blue'=>'int'], 'imagecolorexactalpha' => ['int', 'image'=>'resource', 'red'=>'int', 'green'=>'int', 'blue'=>'int', 'alpha'=>'int'], 'imagecolormatch' => ['bool', 'image1'=>'resource', 'image2'=>'resource'], 'imagecolorresolve' => ['int', 'image'=>'resource', 'red'=>'int', 'green'=>'int', 'blue'=>'int'], 'imagecolorresolvealpha' => ['int', 'image'=>'resource', 'red'=>'int', 'green'=>'int', 'blue'=>'int', 'alpha'=>'int'], 'imagecolorset' => ['false|null', 'image'=>'resource', 'color'=>'int', 'red'=>'int', 'green'=>'int', 'blue'=>'int', 'alpha='=>'int'], 'imagecolorsforindex' => ['array', 'image'=>'resource', 'color'=>'int'], 'imagecolorstotal' => ['int', 'image'=>'resource'], 'imagecolortransparent' => ['int', 'image'=>'resource', 'color='=>'int'], 'imageconvolution' => ['bool', 'image'=>'resource', 'matrix'=>'array', 'divisor'=>'float', 'offset'=>'float'], 'imagecopy' => ['bool', 'dst_image'=>'resource', 'src_image'=>'resource', 'dst_x'=>'int', 'dst_y'=>'int', 'src_x'=>'int', 'src_y'=>'int', 'src_width'=>'int', 'src_height'=>'int'], 'imagecopymerge' => ['bool', 'dst_image'=>'resource', 'src_image'=>'resource', 'dst_x'=>'int', 'dst_y'=>'int', 'src_x'=>'int', 'src_y'=>'int', 'src_width'=>'int', 'src_height'=>'int', 'pct'=>'int'], 'imagecopymergegray' => ['bool', 'dst_image'=>'resource', 'src_image'=>'resource', 'dst_x'=>'int', 'dst_y'=>'int', 'src_x'=>'int', 'src_y'=>'int', 'src_width'=>'int', 'src_height'=>'int', 'pct'=>'int'], 'imagecopyresampled' => ['bool', 'dst_image'=>'resource', 'src_image'=>'resource', 'dst_x'=>'int', 'dst_y'=>'int', 'src_x'=>'int', 'src_y'=>'int', 'dst_width'=>'int', 'dst_height'=>'int', 'src_width'=>'int', 'src_height'=>'int'], 'imagecopyresized' => ['bool', 'dst_image'=>'resource', 'src_image'=>'resource', 'dst_x'=>'int', 'dst_y'=>'int', 'src_x'=>'int', 'src_y'=>'int', 'dst_width'=>'int', 'dst_height'=>'int', 'src_width'=>'int', 'src_height'=>'int'], 'imagecreate' => ['resource|false', 'x_size'=>'int', 'y_size'=>'int'], 'imagecreatefromgd' => ['resource|false', 'filename'=>'string'], 'imagecreatefromgd2' => ['resource|false', 'filename'=>'string'], 'imagecreatefromgd2part' => ['resource|false', 'filename'=>'string', 'srcx'=>'int', 'srcy'=>'int', 'width'=>'int', 'height'=>'int'], 'imagecreatefromgif' => ['resource|false', 'filename'=>'string'], 'imagecreatefromjpeg' => ['resource|false', 'filename'=>'string'], 'imagecreatefrompng' => ['resource|false', 'filename'=>'string'], 'imagecreatefromstring' => ['resource|false', 'image'=>'string'], 'imagecreatefromwbmp' => ['resource|false', 'filename'=>'string'], 'imagecreatefromwebp' => ['resource|false', 'filename'=>'string'], 'imagecreatefromxbm' => ['resource|false', 'filename'=>'string'], 'imagecreatefromxpm' => ['resource|false', 'filename'=>'string'], 'imagecreatetruecolor' => ['resource|false', 'x_size'=>'int', 'y_size'=>'int'], 'imagecrop' => ['resource|false', 'im'=>'resource', 'rect'=>'array'], 'imagecropauto' => ['resource|false', 'im'=>'resource', 'mode='=>'int', 'threshold='=>'float', 'color='=>'int'], 'imagedashedline' => ['bool', 'image'=>'resource', 'x1'=>'int', 'y1'=>'int', 'x2'=>'int', 'y2'=>'int', 'color'=>'int'], 'imagedestroy' => ['bool', 'image'=>'resource'], 'imageellipse' => ['bool', 'image'=>'resource', 'center_x'=>'int', 'center_y'=>'int', 'width'=>'int', 'height'=>'int', 'color'=>'int'], 'imagefill' => ['bool', 'image'=>'resource', 'x'=>'int', 'y'=>'int', 'color'=>'int'], 'imagefilledarc' => ['bool', 'image'=>'resource', 'center_x'=>'int', 'center_y'=>'int', 'width'=>'int', 'height'=>'int', 'start_angle'=>'int', 'end_angle'=>'int', 'color'=>'int', 'style'=>'int'], 'imagefilledellipse' => ['bool', 'image'=>'resource', 'center_x'=>'int', 'center_y'=>'int', 'width'=>'int', 'height'=>'int', 'color'=>'int'], 'imagefilledpolygon' => ['bool', 'image'=>'resource', 'points'=>'array', 'num_points_or_color'=>'int', 'color'=>'int'], 'imagefilledrectangle' => ['bool', 'image'=>'resource', 'x1'=>'int', 'y1'=>'int', 'x2'=>'int', 'y2'=>'int', 'color'=>'int'], 'imagefilltoborder' => ['bool', 'image'=>'resource', 'x'=>'int', 'y'=>'int', 'border_color'=>'int', 'color'=>'int'], 'imagefilter' => ['bool', 'image'=>'resource', 'filter'=>'int', '...args='=>'array|int|float|bool'], 'imageflip' => ['bool', 'image'=>'resource', 'mode'=>'int'], 'imagefontheight' => ['int', 'font'=>'int'], 'imagefontwidth' => ['int', 'font'=>'int'], 'imageftbbox' => ['array|false', 'size'=>'float', 'angle'=>'float', 'font_filename'=>'string', 'string'=>'string', 'options='=>'array'], 'imagefttext' => ['array|false', 'image'=>'resource', 'size'=>'float', 'angle'=>'float', 'x'=>'int', 'y'=>'int', 'color'=>'int', 'font_filename'=>'string', 'text'=>'string', 'options='=>'array'], 'imagegammacorrect' => ['bool', 'image'=>'resource', 'input_gamma'=>'float', 'output_gamma'=>'float'], 'imagegd' => ['bool', 'image'=>'resource', 'file='=>'string|resource|null'], 'imagegd2' => ['bool', 'image'=>'resource', 'file='=>'string|resource|null', 'chunk_size='=>'int', 'mode='=>'int'], 'imagegetclip' => ['array|false', 'im'=>'resource'], 'imagegif' => ['bool', 'image'=>'resource', 'file='=>'string|resource|null'], 'imagegrabscreen' => ['false|resource'], 'imagegrabwindow' => ['false|resource', 'window_handle'=>'int', 'client_area='=>'int'], 'imageinterlace' => ['int|false', 'image'=>'resource', 'enable='=>'int'], 'imageistruecolor' => ['bool', 'image'=>'resource'], 'imagejpeg' => ['bool', 'image'=>'resource', 'file='=>'string|resource|null', 'quality='=>'int'], 'imagelayereffect' => ['bool', 'image'=>'resource', 'effect'=>'int'], 'imageline' => ['bool', 'image'=>'resource', 'x1'=>'int', 'y1'=>'int', 'x2'=>'int', 'y2'=>'int', 'color'=>'int'], 'imageloadfont' => ['int|false', 'filename'=>'string'], 'imagepalettecopy' => ['void', 'dst'=>'resource', 'src'=>'resource'], 'imagepalettetotruecolor' => ['bool', 'image'=>'resource'], 'imagepng' => ['bool', 'image'=>'resource', 'file='=>'string|resource|null', 'quality='=>'int', 'filters='=>'int'], 'imagepolygon' => ['bool', 'image'=>'resource', 'points'=>'array', 'num_points_or_color'=>'int', 'color'=>'int'], 'imagerectangle' => ['bool', 'image'=>'resource', 'x1'=>'int', 'y1'=>'int', 'x2'=>'int', 'y2'=>'int', 'color'=>'int'], 'imagerotate' => ['resource|false', 'src_im'=>'resource', 'angle'=>'float', 'bgdcolor'=>'int', 'ignoretransparent='=>'int'], 'imagesavealpha' => ['bool', 'image'=>'resource', 'enable'=>'bool'], 'imagescale' => ['resource|false', 'im'=>'resource', 'new_width'=>'int', 'new_height='=>'int', 'method='=>'int'], 'imagesetbrush' => ['bool', 'image'=>'resource', 'brush'=>'resource'], 'imagesetinterpolation' => ['bool', 'image'=>'resource', 'method='=>'int'], 'imagesetpixel' => ['bool', 'image'=>'resource', 'x'=>'int', 'y'=>'int', 'color'=>'int'], 'imagesetstyle' => ['bool', 'image'=>'resource', 'style'=>'non-empty-array'], 'imagesetthickness' => ['bool', 'image'=>'resource', 'thickness'=>'int'], 'imagesettile' => ['bool', 'image'=>'resource', 'tile'=>'resource'], 'imagestring' => ['bool', 'image'=>'resource', 'font'=>'int', 'x'=>'int', 'y'=>'int', 'string'=>'string', 'color'=>'int'], 'imagestringup' => ['bool', 'image'=>'resource', 'font'=>'int', 'x'=>'int', 'y'=>'int', 'string'=>'string', 'color'=>'int'], 'imagesx' => ['int', 'image'=>'resource'], 'imagesy' => ['int', 'image'=>'resource'], 'imagetruecolortopalette' => ['bool', 'image'=>'resource', 'dither'=>'bool', 'num_colors'=>'int'], 'imagettfbbox' => ['false|array', 'size'=>'float', 'angle'=>'float', 'font_filename'=>'string', 'string'=>'string'], 'imagettftext' => ['false|array', 'image'=>'resource', 'size'=>'float', 'angle'=>'float', 'x'=>'int', 'y'=>'int', 'color'=>'int', 'font_filename'=>'string', 'text'=>'string'], 'imagetypes' => ['int'], 'imagewbmp' => ['bool', 'image'=>'resource', 'file='=>'string|resource|null', 'foreground_color='=>'int'], 'imagewebp' => ['bool', 'image'=>'resource', 'file='=>'string|resource|null', 'quality='=>'int'], 'imagexbm' => ['bool', 'image'=>'resource', 'filename'=>'?string', 'foreground_color='=>'int'], 'imap_8bit' => ['string|false', 'string'=>'string'], 'imap_alerts' => ['array|false'], 'imap_append' => ['bool', 'imap'=>'resource', 'folder'=>'string', 'message'=>'string', 'options='=>'string', 'internal_date='=>'string'], 'imap_base64' => ['string|false', 'string'=>'string'], 'imap_binary' => ['string|false', 'string'=>'string'], 'imap_body' => ['string|false', 'imap'=>'resource', 'message_num'=>'int', 'flags='=>'int'], 'imap_bodystruct' => ['stdClass|false', 'imap'=>'resource', 'message_num'=>'int', 'section'=>'string'], 'imap_check' => ['stdClass|false', 'imap'=>'resource'], 'imap_clearflag_full' => ['bool', 'imap'=>'resource', 'sequence'=>'string', 'flag'=>'string', 'options='=>'int'], 'imap_close' => ['bool', 'imap'=>'resource', 'flags='=>'int'], 'imap_create' => ['bool', 'imap'=>'resource', 'mailbox'=>'string'], 'imap_createmailbox' => ['bool', 'imap'=>'resource', 'mailbox'=>'string'], 'imap_delete' => ['bool', 'imap'=>'resource', 'message_nums'=>'string', 'flags='=>'int'], 'imap_deletemailbox' => ['bool', 'imap'=>'resource', 'mailbox'=>'string'], 'imap_errors' => ['array|false'], 'imap_expunge' => ['bool', 'imap'=>'resource'], 'imap_fetch_overview' => ['array|false', 'imap'=>'resource', 'sequence'=>'string', 'flags='=>'int'], 'imap_fetchbody' => ['string|false', 'imap'=>'resource', 'message_num'=>'int', 'section'=>'string', 'flags='=>'int'], 'imap_fetchheader' => ['string|false', 'imap'=>'resource', 'message_num'=>'int', 'flags='=>'int'], 'imap_fetchmime' => ['string|false', 'imap'=>'resource', 'message_num'=>'int', 'section'=>'string', 'flags='=>'int'], 'imap_fetchstructure' => ['stdClass|false', 'imap'=>'resource', 'message_num'=>'int', 'flags='=>'int'], 'imap_fetchtext' => ['string|false', 'imap'=>'resource', 'message_num'=>'int', 'flags='=>'int'], 'imap_gc' => ['bool', 'imap'=>'resource', 'flags'=>'int'], 'imap_get_quota' => ['array|false', 'imap'=>'resource', 'quota_root'=>'string'], 'imap_get_quotaroot' => ['array|false', 'imap'=>'resource', 'mailbox'=>'string'], 'imap_getacl' => ['array|false', 'imap'=>'resource', 'mailbox'=>'string'], 'imap_getmailboxes' => ['array|false', 'imap'=>'resource', 'reference'=>'string', 'pattern'=>'string'], 'imap_getsubscribed' => ['array|false', 'imap'=>'resource', 'reference'=>'string', 'pattern'=>'string'], 'imap_header' => ['stdClass|false', 'stream_id'=>'resource', 'msg_no'=>'int', 'from_length='=>'int', 'subject_length='=>'int', 'default_host='=>'string'], 'imap_headerinfo' => ['stdClass|false', 'imap'=>'resource', 'message_num'=>'int', 'from_length='=>'int', 'subject_length='=>'int', 'default_host='=>'string|null'], 'imap_headers' => ['array|false', 'imap'=>'resource'], 'imap_last_error' => ['string|false'], 'imap_list' => ['array|false', 'imap'=>'resource', 'reference'=>'string', 'pattern'=>'string'], 'imap_listmailbox' => ['array|false', 'imap'=>'resource', 'reference'=>'string', 'pattern'=>'string'], 'imap_listscan' => ['array|false', 'imap'=>'resource', 'reference'=>'string', 'pattern'=>'string', 'content'=>'string'], 'imap_listsubscribed' => ['array|false', 'imap'=>'resource', 'reference'=>'string', 'pattern'=>'string'], 'imap_lsub' => ['array|false', 'imap'=>'resource', 'reference'=>'string', 'pattern'=>'string'], 'imap_mail' => ['bool', 'to'=>'string', 'subject'=>'string', 'message'=>'string', 'additional_headers='=>'string', 'cc='=>'string', 'bcc='=>'string', 'return_path='=>'string'], 'imap_mail_compose' => ['string|false', 'envelope'=>'array', 'bodies'=>'array'], 'imap_mail_copy' => ['bool', 'imap'=>'resource', 'message_nums'=>'string', 'mailbox'=>'string', 'flags='=>'int'], 'imap_mail_move' => ['bool', 'imap'=>'resource', 'message_nums'=>'string', 'mailbox'=>'string', 'flags='=>'int'], 'imap_mailboxmsginfo' => ['stdClass', 'imap'=>'resource'], 'imap_mime_header_decode' => ['array|false', 'string'=>'string'], 'imap_msgno' => ['int', 'imap'=>'resource', 'message_uid'=>'int'], 'imap_mutf7_to_utf8' => ['string|false', 'string'=>'string'], 'imap_num_msg' => ['int|false', 'imap'=>'resource'], 'imap_num_recent' => ['int', 'imap'=>'resource'], 'imap_open' => ['resource|false', 'mailbox'=>'string', 'user'=>'string', 'password'=>'string', 'flags='=>'int', 'retries='=>'int', 'options='=>'array'], 'imap_ping' => ['bool', 'imap'=>'resource'], 'imap_qprint' => ['string|false', 'string'=>'string'], 'imap_rename' => ['bool', 'imap'=>'resource', 'from'=>'string', 'to'=>'string'], 'imap_renamemailbox' => ['bool', 'imap'=>'resource', 'from'=>'string', 'to'=>'string'], 'imap_reopen' => ['bool', 'imap'=>'resource', 'mailbox'=>'string', 'flags='=>'int', 'retries='=>'int'], 'imap_rfc822_parse_adrlist' => ['array', 'string'=>'string', 'default_hostname'=>'string'], 'imap_rfc822_parse_headers' => ['stdClass', 'headers'=>'string', 'default_hostname='=>'string'], 'imap_rfc822_write_address' => ['string|false', 'mailbox'=>'string', 'hostname'=>'string', 'personal'=>'string'], 'imap_savebody' => ['bool', 'imap'=>'resource', 'file'=>'string|resource', 'message_num'=>'int', 'section='=>'string', 'flags='=>'int'], 'imap_scan' => ['array|false', 'imap'=>'resource', 'reference'=>'string', 'pattern'=>'string', 'content'=>'string'], 'imap_scanmailbox' => ['array|false', 'imap'=>'resource', 'reference'=>'string', 'pattern'=>'string', 'content'=>'string'], 'imap_search' => ['array|false', 'imap'=>'resource', 'criteria'=>'string', 'flags='=>'int', 'charset='=>'string'], 'imap_set_quota' => ['bool', 'imap'=>'resource', 'quota_root'=>'string', 'mailbox_size'=>'int'], 'imap_setacl' => ['bool', 'imap'=>'resource', 'mailbox'=>'string', 'user_id'=>'string', 'rights'=>'string'], 'imap_setflag_full' => ['bool', 'imap'=>'resource', 'sequence'=>'string', 'flag'=>'string', 'options='=>'int'], 'imap_sort' => ['array|false', 'imap'=>'resource', 'criteria'=>'int', 'reverse'=>'int', 'flags='=>'int', 'search_criteria='=>'string', 'charset='=>'string'], 'imap_status' => ['stdClass|false', 'imap'=>'resource', 'mailbox'=>'string', 'flags'=>'int'], 'imap_subscribe' => ['bool', 'imap'=>'resource', 'mailbox'=>'string'], 'imap_thread' => ['array|false', 'imap'=>'resource', 'flags='=>'int'], 'imap_timeout' => ['int|bool', 'timeout_type'=>'int', 'timeout='=>'int'], 'imap_uid' => ['int|false', 'imap'=>'resource', 'message_num'=>'int'], 'imap_undelete' => ['bool', 'imap'=>'resource', 'message_nums'=>'string', 'flags='=>'int'], 'imap_unsubscribe' => ['bool', 'imap'=>'resource', 'mailbox'=>'string'], 'imap_utf7_decode' => ['string|false', 'string'=>'string'], 'imap_utf7_encode' => ['string', 'string'=>'string'], 'imap_utf8' => ['string', 'mime_encoded_text'=>'string'], 'imap_utf8_to_mutf7' => ['string|false', 'string'=>'string'], 'implode' => ['string', 'separator'=>'string', 'array'=>'array'], 'implode\'1' => ['string', 'separator'=>'array'], 'import_request_variables' => ['bool', 'types'=>'string', 'prefix='=>'string'], 'in_array' => ['bool', 'needle'=>'mixed', 'haystack'=>'array', 'strict='=>'bool'], 'inclued_get_data' => ['array'], 'inet_ntop' => ['string|false', 'ip'=>'string'], 'inet_pton' => ['string|false', 'ip'=>'string'], 'inflate_add' => ['string|false', 'context'=>'resource', 'data'=>'string', 'flush_mode='=>'int'], 'inflate_get_read_len' => ['int', 'context'=>'resource'], 'inflate_get_status' => ['int', 'context'=>'resource'], 'inflate_init' => ['resource|false', 'encoding'=>'int', 'options='=>'array'], 'ingres_autocommit' => ['bool', 'link'=>'resource'], 'ingres_autocommit_state' => ['bool', 'link'=>'resource'], 'ingres_charset' => ['string', 'link'=>'resource'], 'ingres_close' => ['bool', 'link'=>'resource'], 'ingres_commit' => ['bool', 'link'=>'resource'], 'ingres_connect' => ['resource', 'database='=>'string', 'username='=>'string', 'password='=>'string', 'options='=>'array'], 'ingres_cursor' => ['string', 'result'=>'resource'], 'ingres_errno' => ['int', 'link='=>'resource'], 'ingres_error' => ['string', 'link='=>'resource'], 'ingres_errsqlstate' => ['string', 'link='=>'resource'], 'ingres_escape_string' => ['string', 'link'=>'resource', 'source_string'=>'string'], 'ingres_execute' => ['bool', 'result'=>'resource', 'params='=>'array', 'types='=>'string'], 'ingres_fetch_array' => ['array', 'result'=>'resource', 'result_type='=>'int'], 'ingres_fetch_assoc' => ['array', 'result'=>'resource'], 'ingres_fetch_object' => ['object', 'result'=>'resource', 'result_type='=>'int'], 'ingres_fetch_proc_return' => ['int', 'result'=>'resource'], 'ingres_fetch_row' => ['array', 'result'=>'resource'], 'ingres_field_length' => ['int', 'result'=>'resource', 'index'=>'int'], 'ingres_field_name' => ['string', 'result'=>'resource', 'index'=>'int'], 'ingres_field_nullable' => ['bool', 'result'=>'resource', 'index'=>'int'], 'ingres_field_precision' => ['int', 'result'=>'resource', 'index'=>'int'], 'ingres_field_scale' => ['int', 'result'=>'resource', 'index'=>'int'], 'ingres_field_type' => ['string', 'result'=>'resource', 'index'=>'int'], 'ingres_free_result' => ['bool', 'result'=>'resource'], 'ingres_next_error' => ['bool', 'link='=>'resource'], 'ingres_num_fields' => ['int', 'result'=>'resource'], 'ingres_num_rows' => ['int', 'result'=>'resource'], 'ingres_pconnect' => ['resource', 'database='=>'string', 'username='=>'string', 'password='=>'string', 'options='=>'array'], 'ingres_prepare' => ['mixed', 'link'=>'resource', 'query'=>'string'], 'ingres_query' => ['mixed', 'link'=>'resource', 'query'=>'string', 'params='=>'array', 'types='=>'string'], 'ingres_result_seek' => ['bool', 'result'=>'resource', 'position'=>'int'], 'ingres_rollback' => ['bool', 'link'=>'resource'], 'ingres_set_environment' => ['bool', 'link'=>'resource', 'options'=>'array'], 'ingres_unbuffered_query' => ['mixed', 'link'=>'resource', 'query'=>'string', 'params='=>'array', 'types='=>'string'], 'ini_alter' => ['string|false', 'option'=>'string', 'value'=>'string'], 'ini_get' => ['string|false', 'option'=>'string'], 'ini_get_all' => ['array|false', 'extension='=>'?string', 'details='=>'bool'], 'ini_restore' => ['void', 'option'=>'string'], 'ini_set' => ['string|false', 'option'=>'string', 'value'=>'string'], 'inotify_add_watch' => ['int|false', 'inotify_instance'=>'resource', 'pathname'=>'string', 'mask'=>'int'], 'inotify_init' => ['resource|false'], 'inotify_queue_len' => ['int', 'inotify_instance'=>'resource'], 'inotify_read' => ['array{wd: int, mask: int, cookie: int, name: string}[]|false', 'inotify_instance'=>'resource'], 'inotify_rm_watch' => ['bool', 'inotify_instance'=>'resource', 'watch_descriptor'=>'int'], 'intdiv' => ['int', 'num1'=>'int', 'num2'=>'int'], 'interface_exists' => ['bool', 'interface'=>'string', 'autoload='=>'bool'], 'intl_error_name' => ['string', 'errorCode'=>'int'], 'intl_get_error_code' => ['int'], 'intl_get_error_message' => ['string'], 'intl_is_failure' => ['bool', 'errorCode'=>'int'], 'intlcal_add' => ['bool', 'calendar'=>'IntlCalendar', 'field'=>'int', 'value'=>'int'], 'intlcal_after' => ['bool', 'calendar'=>'IntlCalendar', 'other'=>'IntlCalendar'], 'intlcal_before' => ['bool', 'calendar'=>'IntlCalendar', 'other'=>'IntlCalendar'], 'intlcal_clear' => ['bool', 'calendar'=>'IntlCalendar', 'field='=>'?int'], 'intlcal_create_instance' => ['?IntlCalendar', 'timezone='=>'mixed', 'locale='=>'?string'], 'intlcal_equals' => ['bool', 'calendar'=>'IntlCalendar', 'other'=>'IntlCalendar'], 'intlcal_field_difference' => ['int|false', 'calendar'=>'IntlCalendar', 'timestamp'=>'float', 'field'=>'int'], 'intlcal_from_date_time' => ['?IntlCalendar', 'datetime'=>'DateTime|string', 'locale='=>'?string'], 'intlcal_get' => ['int|false', 'calendar'=>'IntlCalendar', 'field'=>'int'], 'intlcal_get_actual_maximum' => ['int', 'calendar'=>'IntlCalendar', 'field'=>'int'], 'intlcal_get_actual_minimum' => ['int', 'calendar'=>'IntlCalendar', 'field'=>'int'], 'intlcal_get_available_locales' => ['array'], 'intlcal_get_day_of_week_type' => ['int', 'calendar'=>'IntlCalendar', 'dayOfWeek'=>'int'], 'intlcal_get_first_day_of_week' => ['int', 'calendar'=>'IntlCalendar'], 'intlcal_get_greatest_minimum' => ['int', 'calendar'=>'IntlCalendar', 'field'=>'int'], 'intlcal_get_keyword_values_for_locale' => ['IntlIterator|false', 'keyword'=>'string', 'locale'=>'string', 'onlyCommon'=>'bool'], 'intlcal_get_least_maximum' => ['int', 'calendar'=>'IntlCalendar', 'field'=>'int'], 'intlcal_get_locale' => ['string', 'calendar'=>'IntlCalendar', 'type'=>'int'], 'intlcal_get_maximum' => ['int|false', 'calendar'=>'IntlCalendar', 'field'=>'int'], 'intlcal_get_minimal_days_in_first_week' => ['int', 'calendar'=>'IntlCalendar'], 'intlcal_get_minimum' => ['int', 'calendar'=>'IntlCalendar', 'field'=>'int'], 'intlcal_get_now' => ['float'], 'intlcal_get_repeated_wall_time_option' => ['int', 'calendar'=>'IntlCalendar'], 'intlcal_get_skipped_wall_time_option' => ['int', 'calendar'=>'IntlCalendar'], 'intlcal_get_time' => ['float', 'calendar'=>'IntlCalendar'], 'intlcal_get_time_zone' => ['IntlTimeZone', 'calendar'=>'IntlCalendar'], 'intlcal_get_type' => ['string', 'calendar'=>'IntlCalendar'], 'intlcal_get_weekend_transition' => ['int|false', 'calendar'=>'IntlCalendar', 'dayOfWeek'=>'int'], 'intlcal_in_daylight_time' => ['bool', 'calendar'=>'IntlCalendar'], 'intlcal_is_equivalent_to' => ['bool', 'calendar'=>'IntlCalendar', 'other'=>'IntlCalendar'], 'intlcal_is_lenient' => ['bool', 'calendar'=>'IntlCalendar'], 'intlcal_is_set' => ['bool', 'calendar'=>'IntlCalendar', 'field'=>'int'], 'intlcal_is_weekend' => ['bool', 'calendar'=>'IntlCalendar', 'timestamp='=>'?float'], 'intlcal_roll' => ['bool', 'calendar'=>'IntlCalendar', 'field'=>'int', 'value'=>'mixed'], 'intlcal_set' => ['bool', 'calendar'=>'IntlCalendar', 'year'=>'int', 'month'=>'int'], 'intlcal_set\'1' => ['bool', 'calendar'=>'IntlCalendar', 'year'=>'int', 'month'=>'int', 'dayOfMonth='=>'int', 'hour='=>'int', 'minute='=>'int', 'second='=>'int'], 'intlcal_set_first_day_of_week' => ['bool', 'calendar'=>'IntlCalendar', 'dayOfWeek'=>'int'], 'intlcal_set_lenient' => ['bool', 'calendar'=>'IntlCalendar', 'lenient'=>'bool'], 'intlcal_set_repeated_wall_time_option' => ['true', 'calendar'=>'IntlCalendar', 'option'=>'int'], 'intlcal_set_skipped_wall_time_option' => ['true', 'calendar'=>'IntlCalendar', 'option'=>'int'], 'intlcal_set_time' => ['bool', 'calendar'=>'IntlCalendar', 'timestamp'=>'float'], 'intlcal_set_time_zone' => ['bool', 'calendar'=>'IntlCalendar', 'timezone'=>'mixed'], 'intlcal_to_date_time' => ['DateTime|false', 'calendar'=>'IntlCalendar'], 'intlgregcal_create_instance' => ['?IntlGregorianCalendar', 'timezoneOrYear='=>'IntlTimeZone|DateTimeZone|string|null', 'localeOrMonth='=>'string|int|null', 'day='=>'int', 'hour='=>'int', 'minute='=>'int', 'second='=>'int'], 'intlgregcal_get_gregorian_change' => ['float', 'calendar'=>'IntlGregorianCalendar'], 'intlgregcal_is_leap_year' => ['bool', 'calendar'=>'IntlGregorianCalendar', 'year'=>'int'], 'intlgregcal_set_gregorian_change' => ['bool', 'calendar'=>'IntlGregorianCalendar', 'timestamp'=>'float'], 'intltz_count_equivalent_ids' => ['int', 'timezoneId'=>'string'], 'intltz_create_enumeration' => ['IntlIterator|false', 'countryOrRawOffset='=>'IntlTimeZone|string|int|float|null'], 'intltz_create_time_zone' => ['?IntlTimeZone', 'timezoneId'=>'string'], 'intltz_from_date_time_zone' => ['?IntlTimeZone', 'timezone'=>'DateTimeZone'], 'intltz_getGMT' => ['IntlTimeZone'], 'intltz_get_canonical_id' => ['string|false', 'timezoneId'=>'string', '&isSystemId='=>'bool'], 'intltz_get_display_name' => ['string|false', 'timezone'=>'IntlTimeZone', 'dst='=>'bool', 'style='=>'int', 'locale='=>'?string'], 'intltz_get_dst_savings' => ['int', 'timezone'=>'IntlTimeZone'], 'intltz_get_equivalent_id' => ['string', 'timezoneId'=>'string', 'offset'=>'int'], 'intltz_get_error_code' => ['int', 'timezone'=>'IntlTimeZone'], 'intltz_get_error_message' => ['string', 'timezone'=>'IntlTimeZone'], 'intltz_get_id' => ['string', 'timezone'=>'IntlTimeZone'], 'intltz_get_offset' => ['bool', 'timezone'=>'IntlTimeZone', 'timestamp'=>'float', 'local'=>'bool', '&rawOffset'=>'int', '&dstOffset'=>'int'], 'intltz_get_raw_offset' => ['int', 'timezone'=>'IntlTimeZone'], 'intltz_get_tz_data_version' => ['string', 'object'=>'IntlTimeZone'], 'intltz_has_same_rules' => ['bool', 'timezone'=>'IntlTimeZone', 'other'=>'IntlTimeZone'], 'intltz_to_date_time_zone' => ['DateTimeZone', 'timezone'=>'IntlTimeZone'], 'intltz_use_daylight_time' => ['bool', 'timezone'=>'IntlTimeZone'], 'intlz_create_default' => ['IntlTimeZone'], 'intval' => ['int', 'value'=>'mixed', 'base='=>'int'], 'ip2long' => ['int|false', 'ip'=>'string'], 'iptcembed' => ['string|bool', 'iptc_data'=>'string', 'filename'=>'string', 'spool='=>'int'], 'iptcparse' => ['array|false', 'iptc_block'=>'string'], 'is_a' => ['bool', 'object_or_class'=>'mixed', 'class'=>'string', 'allow_string='=>'bool'], 'is_array' => ['bool', 'value'=>'mixed'], 'is_bool' => ['bool', 'value'=>'mixed'], 'is_callable' => ['bool', 'value'=>'callable|mixed', 'syntax_only='=>'bool', '&w_callable_name='=>'string'], 'is_dir' => ['bool', 'filename'=>'string'], 'is_double' => ['bool', 'value'=>'mixed'], 'is_executable' => ['bool', 'filename'=>'string'], 'is_file' => ['bool', 'filename'=>'string'], 'is_finite' => ['bool', 'num'=>'float'], 'is_float' => ['bool', 'value'=>'mixed'], 'is_infinite' => ['bool', 'num'=>'float'], 'is_int' => ['bool', 'value'=>'mixed'], 'is_integer' => ['bool', 'value'=>'mixed'], 'is_link' => ['bool', 'filename'=>'string'], 'is_long' => ['bool', 'value'=>'mixed'], 'is_nan' => ['bool', 'num'=>'float'], 'is_null' => ['bool', 'value'=>'mixed'], 'is_numeric' => ['bool', 'value'=>'mixed'], 'is_object' => ['bool', 'value'=>'mixed'], 'is_readable' => ['bool', 'filename'=>'string'], 'is_real' => ['bool', 'value'=>'mixed'], 'is_resource' => ['bool', 'value'=>'mixed'], 'is_scalar' => ['bool', 'value'=>'mixed'], 'is_soap_fault' => ['bool', 'object'=>'mixed'], 'is_string' => ['bool', 'value'=>'mixed'], 'is_subclass_of' => ['bool', 'object_or_class'=>'object|string', 'class'=>'class-string', 'allow_string='=>'bool'], 'is_tainted' => ['bool', 'string'=>'string'], 'is_uploaded_file' => ['bool', 'filename'=>'string'], 'is_writable' => ['bool', 'filename'=>'string'], 'is_writeable' => ['bool', 'filename'=>'string'], 'isset' => ['bool', 'value'=>'mixed', '...rest='=>'mixed'], 'iterator_apply' => ['0|positive-int', 'iterator'=>'Traversable', 'callback'=>'callable(mixed):bool', 'args='=>'?array'], 'iterator_count' => ['0|positive-int', 'iterator'=>'Traversable'], 'iterator_to_array' => ['array', 'iterator'=>'Traversable', 'preserve_keys='=>'bool'], 'java_last_exception_clear' => ['void'], 'java_last_exception_get' => ['object'], 'java_reload' => ['array', 'new_jarpath'=>'string'], 'java_require' => ['array', 'new_classpath'=>'string'], 'java_set_encoding' => ['array', 'encoding'=>'string'], 'java_set_ignore_case' => ['void', 'ignore'=>'bool'], 'java_throw_exceptions' => ['void', 'throw'=>'bool'], 'jddayofweek' => ['string|int', 'julian_day'=>'int', 'mode='=>'int'], 'jdmonthname' => ['string', 'julian_day'=>'int', 'mode'=>'int'], 'jdtofrench' => ['string', 'julian_day'=>'int'], 'jdtogregorian' => ['string', 'julian_day'=>'int'], 'jdtojewish' => ['string', 'julian_day'=>'int', 'hebrew='=>'bool', 'flags='=>'int'], 'jdtojulian' => ['string', 'julian_day'=>'int'], 'jdtounix' => ['int|false', 'julian_day'=>'int'], 'jewishtojd' => ['int', 'month'=>'int', 'day'=>'int', 'year'=>'int'], 'jobqueue_license_info' => ['array'], 'join' => ['string', 'separator'=>'string', 'array'=>'array'], 'join\'1' => ['string', 'separator'=>'array'], 'jpeg2wbmp' => ['bool', 'jpegname'=>'string', 'wbmpname'=>'string', 'dest_height'=>'int', 'dest_width'=>'int', 'threshold'=>'int'], 'json_decode' => ['mixed', 'json'=>'string', 'associative='=>'bool', 'depth='=>'int', 'flags='=>'int'], 'json_encode' => ['non-empty-string|false', 'value'=>'mixed', 'flags='=>'int', 'depth='=>'int'], 'json_last_error' => ['int'], 'json_last_error_msg' => ['string'], 'judy_type' => ['int', 'array'=>'judy'], 'judy_version' => ['string'], 'juliantojd' => ['int', 'month'=>'int', 'day'=>'int', 'year'=>'int'], 'kadm5_chpass_principal' => ['bool', 'handle'=>'resource', 'principal'=>'string', 'password'=>'string'], 'kadm5_create_principal' => ['bool', 'handle'=>'resource', 'principal'=>'string', 'password='=>'string', 'options='=>'array'], 'kadm5_delete_principal' => ['bool', 'handle'=>'resource', 'principal'=>'string'], 'kadm5_destroy' => ['bool', 'handle'=>'resource'], 'kadm5_flush' => ['bool', 'handle'=>'resource'], 'kadm5_get_policies' => ['array', 'handle'=>'resource'], 'kadm5_get_principal' => ['array', 'handle'=>'resource', 'principal'=>'string'], 'kadm5_get_principals' => ['array', 'handle'=>'resource'], 'kadm5_init_with_password' => ['resource', 'admin_server'=>'string', 'realm'=>'string', 'principal'=>'string', 'password'=>'string'], 'kadm5_modify_principal' => ['bool', 'handle'=>'resource', 'principal'=>'string', 'options'=>'array'], 'key' => ['int|string|null', 'array'=>'array|object'], 'key_exists' => ['bool', 'key'=>'string|int', 'array'=>'array'], 'krsort' => ['true', '&rw_array'=>'array', 'flags='=>'int'], 'ksort' => ['true', '&rw_array'=>'array', 'flags='=>'int'], 'labelObj::__construct' => ['void'], 'labelObj::convertToString' => ['string'], 'labelObj::deleteStyle' => ['int', 'index'=>'int'], 'labelObj::free' => ['void'], 'labelObj::getBinding' => ['string', 'labelbinding'=>'mixed'], 'labelObj::getExpressionString' => ['string'], 'labelObj::getStyle' => ['styleObj', 'index'=>'int'], 'labelObj::getTextString' => ['string'], 'labelObj::moveStyleDown' => ['int', 'index'=>'int'], 'labelObj::moveStyleUp' => ['int', 'index'=>'int'], 'labelObj::removeBinding' => ['int', 'labelbinding'=>'mixed'], 'labelObj::set' => ['int', 'property_name'=>'string', 'new_value'=>''], 'labelObj::setBinding' => ['int', 'labelbinding'=>'mixed', 'value'=>'string'], 'labelObj::setExpression' => ['int', 'expression'=>'string'], 'labelObj::setText' => ['int', 'text'=>'string'], 'labelObj::updateFromString' => ['int', 'snippet'=>'string'], 'labelcacheObj::freeCache' => ['bool'], 'layerObj::addFeature' => ['int', 'shape'=>'shapeObj'], 'layerObj::applySLD' => ['int', 'sldxml'=>'string', 'namedlayer'=>'string'], 'layerObj::applySLDURL' => ['int', 'sldurl'=>'string', 'namedlayer'=>'string'], 'layerObj::clearProcessing' => ['void'], 'layerObj::close' => ['void'], 'layerObj::convertToString' => ['string'], 'layerObj::draw' => ['int', 'image'=>'imageObj'], 'layerObj::drawQuery' => ['int', 'image'=>'imageObj'], 'layerObj::free' => ['void'], 'layerObj::generateSLD' => ['string'], 'layerObj::getClass' => ['classObj', 'classIndex'=>'int'], 'layerObj::getClassIndex' => ['int', 'shape'=>'', 'classgroup'=>'', 'numclasses'=>''], 'layerObj::getExtent' => ['rectObj'], 'layerObj::getFilterString' => ['?string'], 'layerObj::getGridIntersectionCoordinates' => ['array'], 'layerObj::getItems' => ['array'], 'layerObj::getMetaData' => ['int', 'name'=>'string'], 'layerObj::getNumResults' => ['int'], 'layerObj::getProcessing' => ['array'], 'layerObj::getProjection' => ['string'], 'layerObj::getResult' => ['resultObj', 'index'=>'int'], 'layerObj::getResultsBounds' => ['rectObj'], 'layerObj::getShape' => ['shapeObj', 'result'=>'resultObj'], 'layerObj::getWMSFeatureInfoURL' => ['string', 'clickX'=>'int', 'clickY'=>'int', 'featureCount'=>'int', 'infoFormat'=>'string'], 'layerObj::isVisible' => ['bool'], 'layerObj::moveclassdown' => ['int', 'index'=>'int'], 'layerObj::moveclassup' => ['int', 'index'=>'int'], 'layerObj::ms_newLayerObj' => ['layerObj', 'map'=>'mapObj', 'layer'=>'layerObj'], 'layerObj::nextShape' => ['shapeObj'], 'layerObj::open' => ['int'], 'layerObj::queryByAttributes' => ['int', 'qitem'=>'string', 'qstring'=>'string', 'mode'=>'int'], 'layerObj::queryByFeatures' => ['int', 'slayer'=>'int'], 'layerObj::queryByPoint' => ['int', 'point'=>'pointObj', 'mode'=>'int', 'buffer'=>'float'], 'layerObj::queryByRect' => ['int', 'rect'=>'rectObj'], 'layerObj::queryByShape' => ['int', 'shape'=>'shapeObj'], 'layerObj::removeClass' => ['?classObj', 'index'=>'int'], 'layerObj::removeMetaData' => ['int', 'name'=>'string'], 'layerObj::set' => ['int', 'property_name'=>'string', 'new_value'=>''], 'layerObj::setConnectionType' => ['int', 'connectiontype'=>'int', 'plugin_library'=>'string'], 'layerObj::setFilter' => ['int', 'expression'=>'string'], 'layerObj::setMetaData' => ['int', 'name'=>'string', 'value'=>'string'], 'layerObj::setProjection' => ['int', 'proj_params'=>'string'], 'layerObj::setWKTProjection' => ['int', 'proj_params'=>'string'], 'layerObj::updateFromString' => ['int', 'snippet'=>'string'], 'lcfirst' => ['string', 'string'=>'string'], 'lcg_value' => ['float'], 'lchgrp' => ['bool', 'filename'=>'string', 'group'=>'string|int'], 'lchown' => ['bool', 'filename'=>'string', 'user'=>'string|int'], 'ldap_8859_to_t61' => ['string', 'value'=>'string'], 'ldap_add' => ['bool', 'ldap'=>'resource', 'dn'=>'string', 'entry'=>'array', 'controls='=>'array'], 'ldap_add_ext' => ['resource|false', 'ldap'=>'resource', 'dn'=>'string', 'entry'=>'array', 'controls='=>'array'], 'ldap_bind' => ['bool', 'ldap'=>'resource', 'dn='=>'string|null', 'password='=>'string|null'], 'ldap_bind_ext' => ['resource|false', 'ldap'=>'resource', 'dn='=>'string|null', 'password='=>'string|null', 'controls='=>'array'], 'ldap_close' => ['bool', 'ldap'=>'resource'], 'ldap_compare' => ['bool|int', 'ldap'=>'resource', 'dn'=>'string', 'attribute'=>'string', 'value'=>'string'], 'ldap_connect' => ['resource|false', 'uri='=>'?string', 'port='=>'int', 'wallet='=>'string', 'password='=>'string', 'auth_mode='=>'int'], 'ldap_control_paged_result' => ['bool', 'link_identifier'=>'resource', 'pagesize'=>'int', 'iscritical='=>'bool', 'cookie='=>'string'], 'ldap_control_paged_result_response' => ['bool', 'link_identifier'=>'resource', 'result_identifier'=>'resource', '&w_cookie'=>'string', '&w_estimated'=>'int'], 'ldap_count_entries' => ['int', 'ldap'=>'resource', 'result'=>'resource'], 'ldap_delete' => ['bool', 'ldap'=>'resource', 'dn'=>'string'], 'ldap_delete_ext' => ['resource|false', 'ldap'=>'resource', 'dn'=>'string', 'controls='=>'array'], 'ldap_dn2ufn' => ['string|false', 'dn'=>'string'], 'ldap_err2str' => ['string', 'errno'=>'int'], 'ldap_errno' => ['int', 'ldap'=>'resource'], 'ldap_error' => ['string', 'ldap'=>'resource'], 'ldap_escape' => ['string', 'value'=>'string', 'ignore='=>'string', 'flags='=>'int'], 'ldap_explode_dn' => ['array|false', 'dn'=>'string', 'with_attrib'=>'int'], 'ldap_first_attribute' => ['string|false', 'ldap'=>'resource', 'entry'=>'resource'], 'ldap_first_entry' => ['resource|false', 'ldap'=>'resource', 'result'=>'resource'], 'ldap_first_reference' => ['resource|false', 'ldap'=>'resource', 'result'=>'resource'], 'ldap_free_result' => ['bool', 'ldap'=>'resource'], 'ldap_get_attributes' => ['array', 'ldap'=>'resource', 'entry'=>'resource'], 'ldap_get_dn' => ['string|false', 'ldap'=>'resource', 'entry'=>'resource'], 'ldap_get_entries' => ['array|false', 'ldap'=>'resource', 'result'=>'resource'], 'ldap_get_option' => ['bool', 'ldap'=>'resource', 'option'=>'int', '&w_value='=>'array|string|int'], 'ldap_get_values' => ['array|false', 'ldap'=>'resource', 'entry'=>'resource', 'attribute'=>'string'], 'ldap_get_values_len' => ['array|false', 'ldap'=>'resource', 'entry'=>'resource', 'attribute'=>'string'], 'ldap_list' => ['resource|false', 'ldap'=>'resource|array', 'base'=>'array|string', 'filter'=>'array|string', 'attributes='=>'array', 'attributes_only='=>'int', 'sizelimit='=>'int', 'timelimit='=>'int', 'deref='=>'int'], 'ldap_mod_add' => ['bool', 'ldap'=>'resource', 'dn'=>'string', 'entry'=>'array'], 'ldap_mod_add_ext' => ['resource|false', 'ldap'=>'resource', 'dn'=>'string', 'entry'=>'array', 'controls='=>'array'], 'ldap_mod_del' => ['bool', 'ldap'=>'resource', 'dn'=>'string', 'entry'=>'array'], 'ldap_mod_del_ext' => ['resource|false', 'ldap'=>'resource', 'dn'=>'string', 'entry'=>'array', 'controls='=>'array'], 'ldap_mod_replace' => ['bool', 'ldap'=>'resource', 'dn'=>'string', 'entry'=>'array'], 'ldap_mod_replace_ext' => ['resource|false', 'ldap'=>'resource', 'dn'=>'string', 'entry'=>'array', 'controls='=>'array'], 'ldap_modify' => ['bool', 'ldap'=>'resource', 'dn'=>'string', 'entry'=>'array'], 'ldap_modify_batch' => ['bool', 'ldap'=>'resource', 'dn'=>'string', 'modifications_info'=>'array'], 'ldap_next_attribute' => ['string|false', 'ldap'=>'resource', 'entry'=>'resource'], 'ldap_next_entry' => ['resource|false', 'ldap'=>'resource', 'entry'=>'resource'], 'ldap_next_reference' => ['resource|false', 'ldap'=>'resource', 'entry'=>'resource'], 'ldap_parse_reference' => ['bool', 'ldap'=>'resource', 'entry'=>'resource', '&w_referrals'=>'array'], 'ldap_parse_result' => ['bool', 'ldap'=>'resource', 'result'=>'resource', '&w_error_code'=>'int', '&w_matched_dn='=>'string', '&w_error_message='=>'string', '&w_referrals='=>'array', '&w_controls='=>'array'], 'ldap_read' => ['resource|false', 'ldap'=>'resource|array', 'base'=>'array|string', 'filter'=>'array|string', 'attributes='=>'array', 'attributes_only='=>'int', 'sizelimit='=>'int', 'timelimit='=>'int', 'deref='=>'int'], 'ldap_rename' => ['bool', 'ldap'=>'resource', 'dn'=>'string', 'new_rdn'=>'string', 'new_parent'=>'string', 'delete_old_rdn'=>'bool'], 'ldap_rename_ext' => ['resource|false', 'ldap'=>'resource', 'dn'=>'string', 'new_rdn'=>'string', 'new_parent'=>'string', 'delete_old_rdn'=>'bool', 'controls='=>'array'], 'ldap_sasl_bind' => ['bool', 'ldap'=>'resource', 'dn='=>'string', 'password='=>'string', 'mech='=>'string', 'realm='=>'string', 'authc_id='=>'string', 'authz_id='=>'string', 'props='=>'string'], 'ldap_search' => ['resource[]|resource|false', 'ldap'=>'resource|resource[]', 'base'=>'array|string', 'filter'=>'array|string', 'attributes='=>'array', 'attributes_only='=>'int', 'sizelimit='=>'int', 'timelimit='=>'int', 'deref='=>'int'], 'ldap_set_option' => ['bool', 'ldap'=>'resource|null', 'option'=>'int', 'value'=>'mixed'], 'ldap_set_rebind_proc' => ['bool', 'ldap'=>'resource', 'callback'=>'callable'], 'ldap_sort' => ['bool', 'link_identifier'=>'resource', 'result_identifier'=>'resource', 'sortfilter'=>'string'], 'ldap_start_tls' => ['bool', 'ldap'=>'resource'], 'ldap_t61_to_8859' => ['string', 'value'=>'string'], 'ldap_unbind' => ['bool', 'ldap'=>'resource'], 'leak' => ['', 'num_bytes'=>'int'], 'leak_variable' => ['', 'variable'=>'', 'leak_data'=>'bool'], 'legendObj::convertToString' => ['string'], 'legendObj::free' => ['void'], 'legendObj::set' => ['int', 'property_name'=>'string', 'new_value'=>''], 'legendObj::updateFromString' => ['int', 'snippet'=>'string'], 'levenshtein' => ['int', 'string1'=>'string', 'string2'=>'string'], 'levenshtein\'1' => ['int', 'string1'=>'string', 'string2'=>'string', 'insertion_cost'=>'int', 'repetition_cost'=>'int', 'deletion_cost'=>'int'], 'libxml_clear_errors' => ['void'], 'libxml_disable_entity_loader' => ['bool', 'disable='=>'bool'], 'libxml_get_errors' => ['list'], 'libxml_get_last_error' => ['LibXMLError|false'], 'libxml_set_external_entity_loader' => ['bool', 'resolver_function'=>'(callable(string,string,array{directory:?string,intSubName:?string,extSubURI:?string,extSubSystem:?string}):(resource|string|null))|null'], 'libxml_set_streams_context' => ['void', 'context'=>'resource'], 'libxml_use_internal_errors' => ['bool', 'use_errors='=>'bool'], 'lineObj::__construct' => ['void'], 'lineObj::add' => ['int', 'point'=>'pointObj'], 'lineObj::addXY' => ['int', 'x'=>'float', 'y'=>'float', 'm'=>'float'], 'lineObj::addXYZ' => ['int', 'x'=>'float', 'y'=>'float', 'z'=>'float', 'm'=>'float'], 'lineObj::ms_newLineObj' => ['lineObj'], 'lineObj::point' => ['pointObj', 'i'=>'int'], 'lineObj::project' => ['int', 'in'=>'projectionObj', 'out'=>'projectionObj'], 'link' => ['bool', 'target'=>'string', 'link'=>'string'], 'linkinfo' => ['int|false', 'path'=>'string'], 'litespeed_request_headers' => ['array'], 'litespeed_response_headers' => ['array'], 'locale_accept_from_http' => ['string|false', 'header'=>'string'], 'locale_canonicalize' => ['?string', 'locale'=>'string'], 'locale_compose' => ['string|false', 'subtags'=>'array'], 'locale_filter_matches' => ['?bool', 'languageTag'=>'string', 'locale'=>'string', 'canonicalize='=>'bool'], 'locale_get_all_variants' => ['?array', 'locale'=>'string'], 'locale_get_default' => ['string'], 'locale_get_display_language' => ['string', 'locale'=>'string', 'displayLocale='=>'string'], 'locale_get_display_name' => ['string', 'locale'=>'string', 'displayLocale='=>'string'], 'locale_get_display_region' => ['string', 'locale'=>'string', 'displayLocale='=>'string'], 'locale_get_display_script' => ['string', 'locale'=>'string', 'displayLocale='=>'string'], 'locale_get_display_variant' => ['string', 'locale'=>'string', 'displayLocale='=>'string'], 'locale_get_keywords' => ['array|false|null', 'locale'=>'string'], 'locale_get_primary_language' => ['?string', 'locale'=>'string'], 'locale_get_region' => ['?string', 'locale'=>'string'], 'locale_get_script' => ['?string', 'locale'=>'string'], 'locale_lookup' => ['?string', 'languageTag'=>'array', 'locale'=>'string', 'canonicalize='=>'bool', 'defaultLocale='=>'string'], 'locale_parse' => ['?array', 'locale'=>'string'], 'locale_set_default' => ['bool', 'locale'=>'string'], 'localeconv' => ['array'], 'localtime' => ['array', 'timestamp='=>'int', 'associative='=>'bool'], 'log' => ['float', 'num'=>'float', 'base='=>'float'], 'log10' => ['float', 'num'=>'float'], 'log1p' => ['float', 'num'=>'float'], 'long2ip' => ['string', 'ip'=>'int'], 'lstat' => ['array{0: int, 1: int, 2: int, 3: int, 4: int, 5: int, 6: int, 7: int, 8: int, 9: int, 10: int, 11: int, 12: int, dev: int, ino: int, mode: int, nlink: int, uid: int, gid: int, rdev: int, size: int, atime: int, mtime: int, ctime: int, blksize: int, blocks: int}|false', 'filename'=>'string'], 'ltrim' => ['string', 'string'=>'string', 'characters='=>'string'], 'lzf_compress' => ['string', 'data'=>'string'], 'lzf_decompress' => ['string', 'data'=>'string'], 'lzf_optimized_for' => ['int'], 'magic_quotes_runtime' => ['bool', 'new_setting'=>'bool'], 'mail' => ['bool', 'to'=>'string', 'subject'=>'string', 'message'=>'string', 'additional_headers='=>'string|array', 'additional_params='=>'string'], 'mailparse_determine_best_xfer_encoding' => ['string', 'fp'=>'resource'], 'mailparse_msg_create' => ['resource'], 'mailparse_msg_extract_part' => ['void', 'mimemail'=>'resource', 'msgbody'=>'string', 'callbackfunc='=>'callable'], 'mailparse_msg_extract_part_file' => ['string', 'mimemail'=>'resource', 'filename'=>'mixed', 'callbackfunc='=>'callable'], 'mailparse_msg_extract_whole_part_file' => ['string', 'mimemail'=>'resource', 'filename'=>'string', 'callbackfunc='=>'callable'], 'mailparse_msg_free' => ['bool', 'mimemail'=>'resource'], 'mailparse_msg_get_part' => ['resource', 'mimemail'=>'resource', 'mimesection'=>'string'], 'mailparse_msg_get_part_data' => ['array', 'mimemail'=>'resource'], 'mailparse_msg_get_structure' => ['array', 'mimemail'=>'resource'], 'mailparse_msg_parse' => ['bool', 'mimemail'=>'resource', 'data'=>'string'], 'mailparse_msg_parse_file' => ['resource|false', 'filename'=>'string'], 'mailparse_rfc822_parse_addresses' => ['array', 'addresses'=>'string'], 'mailparse_stream_encode' => ['bool', 'sourcefp'=>'resource', 'destfp'=>'resource', 'encoding'=>'string'], 'mailparse_uudecode_all' => ['array', 'fp'=>'resource'], 'mapObj::__construct' => ['void', 'map_file_name'=>'string', 'new_map_path'=>'string'], 'mapObj::appendOutputFormat' => ['int', 'outputFormat'=>'outputformatObj'], 'mapObj::applySLD' => ['int', 'sldxml'=>'string'], 'mapObj::applySLDURL' => ['int', 'sldurl'=>'string'], 'mapObj::applyconfigoptions' => ['int'], 'mapObj::convertToString' => ['string'], 'mapObj::draw' => ['?imageObj'], 'mapObj::drawLabelCache' => ['int', 'image'=>'imageObj'], 'mapObj::drawLegend' => ['imageObj'], 'mapObj::drawQuery' => ['?imageObj'], 'mapObj::drawReferenceMap' => ['imageObj'], 'mapObj::drawScaleBar' => ['imageObj'], 'mapObj::embedLegend' => ['int', 'image'=>'imageObj'], 'mapObj::embedScalebar' => ['int', 'image'=>'imageObj'], 'mapObj::free' => ['void'], 'mapObj::generateSLD' => ['string'], 'mapObj::getAllGroupNames' => ['array'], 'mapObj::getAllLayerNames' => ['array'], 'mapObj::getColorbyIndex' => ['colorObj', 'iCloIndex'=>'int'], 'mapObj::getConfigOption' => ['string', 'key'=>'string'], 'mapObj::getLabel' => ['labelcacheMemberObj', 'index'=>'int'], 'mapObj::getLayer' => ['layerObj', 'index'=>'int'], 'mapObj::getLayerByName' => ['layerObj', 'layer_name'=>'string'], 'mapObj::getLayersDrawingOrder' => ['array'], 'mapObj::getLayersIndexByGroup' => ['array', 'groupname'=>'string'], 'mapObj::getMetaData' => ['int', 'name'=>'string'], 'mapObj::getNumSymbols' => ['int'], 'mapObj::getOutputFormat' => ['?outputformatObj', 'index'=>'int'], 'mapObj::getProjection' => ['string'], 'mapObj::getSymbolByName' => ['int', 'symbol_name'=>'string'], 'mapObj::getSymbolObjectById' => ['symbolObj', 'symbolid'=>'int'], 'mapObj::loadMapContext' => ['int', 'filename'=>'string', 'unique_layer_name'=>'bool'], 'mapObj::loadOWSParameters' => ['int', 'request'=>'OwsrequestObj', 'version'=>'string'], 'mapObj::moveLayerDown' => ['int', 'layerindex'=>'int'], 'mapObj::moveLayerUp' => ['int', 'layerindex'=>'int'], 'mapObj::ms_newMapObjFromString' => ['mapObj', 'map_file_string'=>'string', 'new_map_path'=>'string'], 'mapObj::offsetExtent' => ['int', 'x'=>'float', 'y'=>'float'], 'mapObj::owsDispatch' => ['int', 'request'=>'OwsrequestObj'], 'mapObj::prepareImage' => ['imageObj'], 'mapObj::prepareQuery' => ['void'], 'mapObj::processLegendTemplate' => ['string', 'params'=>'array'], 'mapObj::processQueryTemplate' => ['string', 'params'=>'array', 'generateimages'=>'bool'], 'mapObj::processTemplate' => ['string', 'params'=>'array', 'generateimages'=>'bool'], 'mapObj::queryByFeatures' => ['int', 'slayer'=>'int'], 'mapObj::queryByIndex' => ['int', 'layerindex'=>'', 'tileindex'=>'', 'shapeindex'=>'', 'addtoquery'=>''], 'mapObj::queryByPoint' => ['int', 'point'=>'pointObj', 'mode'=>'int', 'buffer'=>'float'], 'mapObj::queryByRect' => ['int', 'rect'=>'rectObj'], 'mapObj::queryByShape' => ['int', 'shape'=>'shapeObj'], 'mapObj::removeLayer' => ['layerObj', 'nIndex'=>'int'], 'mapObj::removeMetaData' => ['int', 'name'=>'string'], 'mapObj::removeOutputFormat' => ['int', 'name'=>'string'], 'mapObj::save' => ['int', 'filename'=>'string'], 'mapObj::saveMapContext' => ['int', 'filename'=>'string'], 'mapObj::saveQuery' => ['int', 'filename'=>'string', 'results'=>'int'], 'mapObj::scaleExtent' => ['int', 'zoomfactor'=>'float', 'minscaledenom'=>'float', 'maxscaledenom'=>'float'], 'mapObj::selectOutputFormat' => ['int', 'type'=>'string'], 'mapObj::set' => ['int', 'property_name'=>'string', 'new_value'=>''], 'mapObj::setCenter' => ['int', 'center'=>'pointObj'], 'mapObj::setConfigOption' => ['int', 'key'=>'string', 'value'=>'string'], 'mapObj::setExtent' => ['void', 'minx'=>'float', 'miny'=>'float', 'maxx'=>'float', 'maxy'=>'float'], 'mapObj::setFontSet' => ['int', 'fileName'=>'string'], 'mapObj::setMetaData' => ['int', 'name'=>'string', 'value'=>'string'], 'mapObj::setProjection' => ['int', 'proj_params'=>'string', 'bSetUnitsAndExtents'=>'bool'], 'mapObj::setRotation' => ['int', 'rotation_angle'=>'float'], 'mapObj::setSize' => ['int', 'width'=>'int', 'height'=>'int'], 'mapObj::setSymbolSet' => ['int', 'fileName'=>'string'], 'mapObj::setWKTProjection' => ['int', 'proj_params'=>'string', 'bSetUnitsAndExtents'=>'bool'], 'mapObj::zoomPoint' => ['int', 'nZoomFactor'=>'int', 'oPixelPos'=>'pointObj', 'nImageWidth'=>'int', 'nImageHeight'=>'int', 'oGeorefExt'=>'rectObj'], 'mapObj::zoomRectangle' => ['int', 'oPixelExt'=>'rectObj', 'nImageWidth'=>'int', 'nImageHeight'=>'int', 'oGeorefExt'=>'rectObj'], 'mapObj::zoomScale' => ['int', 'nScaleDenom'=>'float', 'oPixelPos'=>'pointObj', 'nImageWidth'=>'int', 'nImageHeight'=>'int', 'oGeorefExt'=>'rectObj', 'oMaxGeorefExt'=>'rectObj'], 'max' => ['mixed', 'value'=>'non-empty-array'], 'max\'1' => ['mixed', 'value'=>'', 'values'=>'', '...args='=>''], 'mb_check_encoding' => ['bool', 'value='=>'string', 'encoding='=>'string'], 'mb_convert_case' => ['string', 'string'=>'string', 'mode'=>'int', 'encoding='=>'string'], 'mb_convert_encoding' => ['string|false', 'string'=>'string', 'to_encoding'=>'string', 'from_encoding='=>'mixed'], 'mb_convert_kana' => ['string', 'string'=>'string', 'mode='=>'string', 'encoding='=>'string'], 'mb_convert_variables' => ['string|false', 'to_encoding'=>'string', 'from_encoding'=>'array|string', '&rw_var'=>'string|array|object', '&...rw_vars='=>'string|array|object'], 'mb_decode_mimeheader' => ['string', 'string'=>'string'], 'mb_decode_numericentity' => ['string', 'string'=>'string', 'map'=>'array', 'encoding='=>'string'], 'mb_detect_encoding' => ['string|false', 'string'=>'string', 'encodings='=>'mixed', 'strict='=>'bool'], 'mb_detect_order' => ['bool|list', 'encoding='=>'mixed'], 'mb_encode_mimeheader' => ['string', 'string'=>'string', 'charset='=>'string', 'transfer_encoding='=>'string', 'newline='=>'string', 'indent='=>'int'], 'mb_encode_numericentity' => ['string', 'string'=>'string', 'map'=>'array', 'encoding='=>'string', 'hex='=>'bool'], 'mb_encoding_aliases' => ['list|false', 'encoding'=>'string'], 'mb_ereg' => ['int|false', 'pattern'=>'string', 'string'=>'string', '&w_matches='=>'array|null'], 'mb_ereg_match' => ['bool', 'pattern'=>'string', 'string'=>'string', 'options='=>'string'], 'mb_ereg_replace' => ['string|false', 'pattern'=>'string', 'replacement'=>'string', 'string'=>'string', 'options='=>'string'], 'mb_ereg_replace_callback' => ['string|false|null', 'pattern'=>'string', 'callback'=>'callable', 'string'=>'string', 'options='=>'string'], 'mb_ereg_search' => ['bool', 'pattern='=>'string', 'options='=>'string'], 'mb_ereg_search_getpos' => ['int'], 'mb_ereg_search_getregs' => ['string[]|false'], 'mb_ereg_search_init' => ['bool', 'string'=>'string', 'pattern='=>'string', 'options='=>'string'], 'mb_ereg_search_pos' => ['int[]|false', 'pattern='=>'string', 'options='=>'string'], 'mb_ereg_search_regs' => ['string[]|false', 'pattern='=>'string', 'options='=>'string'], 'mb_ereg_search_setpos' => ['bool', 'offset'=>'int'], 'mb_eregi' => ['int|false', 'pattern'=>'string', 'string'=>'string', '&w_matches='=>'array'], 'mb_eregi_replace' => ['string|false', 'pattern'=>'string', 'replacement'=>'string', 'string'=>'string', 'options='=>'string'], 'mb_get_info' => ['array|string|int|false', 'type='=>'string'], 'mb_http_input' => ['string|false', 'type='=>'string'], 'mb_http_output' => ['string|bool', 'encoding='=>'string'], 'mb_internal_encoding' => ['string|bool', 'encoding='=>'string'], 'mb_language' => ['string|bool', 'language='=>'string'], 'mb_list_encodings' => ['list'], 'mb_output_handler' => ['string', 'string'=>'string', 'status'=>'int'], 'mb_parse_str' => ['bool', 'string'=>'string', '&w_result='=>'array'], 'mb_preferred_mime_name' => ['string|false', 'encoding'=>'string'], 'mb_regex_encoding' => ['string|bool', 'encoding='=>'string'], 'mb_regex_set_options' => ['string', 'options='=>'string'], 'mb_send_mail' => ['bool', 'to'=>'string', 'subject'=>'string', 'message'=>'string', 'additional_headers='=>'string|array', 'additional_params='=>'string'], 'mb_split' => ['list|false', 'pattern'=>'string', 'string'=>'string', 'limit='=>'int'], 'mb_strcut' => ['string', 'string'=>'string', 'start'=>'int', 'length='=>'?int', 'encoding='=>'string'], 'mb_strimwidth' => ['string', 'string'=>'string', 'start'=>'int', 'width'=>'int', 'trim_marker='=>'string', 'encoding='=>'string'], 'mb_stripos' => ['int|false', 'haystack'=>'string', 'needle'=>'string', 'offset='=>'int', 'encoding='=>'string'], 'mb_stristr' => ['string|false', 'haystack'=>'string', 'needle'=>'string', 'before_needle='=>'bool', 'encoding='=>'string'], 'mb_strlen' => ['0|positive-int', 'string'=>'string', 'encoding='=>'string'], 'mb_strpos' => ['int|false', 'haystack'=>'string', 'needle'=>'string', 'offset='=>'int', 'encoding='=>'string'], 'mb_strrchr' => ['string|false', 'haystack'=>'string', 'needle'=>'string', 'before_needle='=>'bool', 'encoding='=>'string'], 'mb_strrichr' => ['string|false', 'haystack'=>'string', 'needle'=>'string', 'before_needle='=>'bool', 'encoding='=>'string'], 'mb_strripos' => ['int|false', 'haystack'=>'string', 'needle'=>'string', 'offset='=>'int', 'encoding='=>'string'], 'mb_strrpos' => ['int|false', 'haystack'=>'string', 'needle'=>'string', 'offset='=>'int', 'encoding='=>'string'], 'mb_strstr' => ['string|false', 'haystack'=>'string', 'needle'=>'string', 'before_needle='=>'bool', 'encoding='=>'string'], 'mb_strtolower' => ['lowercase-string', 'string'=>'string', 'encoding='=>'string'], 'mb_strtoupper' => ['string', 'string'=>'string', 'encoding='=>'string'], 'mb_strwidth' => ['int', 'string'=>'string', 'encoding='=>'string'], 'mb_substitute_character' => ['bool|int|string', 'substitute_character='=>'mixed'], 'mb_substr' => ['string', 'string'=>'string', 'start'=>'int', 'length='=>'?int', 'encoding='=>'string'], 'mb_substr_count' => ['int', 'haystack'=>'string', 'needle'=>'string', 'encoding='=>'string'], 'mcrypt_cbc' => ['string', 'cipher'=>'string|int', 'key'=>'string', 'data'=>'string', 'mode'=>'int', 'iv='=>'string'], 'mcrypt_cfb' => ['string', 'cipher'=>'string|int', 'key'=>'string', 'data'=>'string', 'mode'=>'int', 'iv='=>'string'], 'mcrypt_create_iv' => ['string|false', 'size'=>'int', 'source='=>'int'], 'mcrypt_decrypt' => ['string', 'cipher'=>'string', 'key'=>'string', 'data'=>'string', 'mode'=>'string', 'iv='=>'string'], 'mcrypt_ecb' => ['string', 'cipher'=>'string|int', 'key'=>'string', 'data'=>'string', 'mode'=>'int', 'iv='=>'string'], 'mcrypt_enc_get_algorithms_name' => ['string', 'td'=>'resource'], 'mcrypt_enc_get_block_size' => ['int', 'td'=>'resource'], 'mcrypt_enc_get_iv_size' => ['int', 'td'=>'resource'], 'mcrypt_enc_get_key_size' => ['int', 'td'=>'resource'], 'mcrypt_enc_get_modes_name' => ['string', 'td'=>'resource'], 'mcrypt_enc_get_supported_key_sizes' => ['array', 'td'=>'resource'], 'mcrypt_enc_is_block_algorithm' => ['bool', 'td'=>'resource'], 'mcrypt_enc_is_block_algorithm_mode' => ['bool', 'td'=>'resource'], 'mcrypt_enc_is_block_mode' => ['bool', 'td'=>'resource'], 'mcrypt_enc_self_test' => ['int|false', 'td'=>'resource'], 'mcrypt_encrypt' => ['string', 'cipher'=>'string', 'key'=>'string', 'data'=>'string', 'mode'=>'string', 'iv='=>'string'], 'mcrypt_generic' => ['string', 'td'=>'resource', 'data'=>'string'], 'mcrypt_generic_deinit' => ['bool', 'td'=>'resource'], 'mcrypt_generic_end' => ['bool', 'td'=>'resource'], 'mcrypt_generic_init' => ['int|false', 'td'=>'resource', 'key'=>'string', 'iv'=>'string'], 'mcrypt_get_block_size' => ['int', 'cipher'=>'int|string', 'module'=>'string'], 'mcrypt_get_cipher_name' => ['string|false', 'cipher'=>'int|string'], 'mcrypt_get_iv_size' => ['int|false', 'cipher'=>'int|string', 'module'=>'string'], 'mcrypt_get_key_size' => ['int', 'cipher'=>'int|string', 'module'=>'string'], 'mcrypt_list_algorithms' => ['array', 'lib_dir='=>'string'], 'mcrypt_list_modes' => ['array', 'lib_dir='=>'string'], 'mcrypt_module_close' => ['bool', 'td'=>'resource'], 'mcrypt_module_get_algo_block_size' => ['int', 'algorithm'=>'string', 'lib_dir='=>'string'], 'mcrypt_module_get_algo_key_size' => ['int', 'algorithm'=>'string', 'lib_dir='=>'string'], 'mcrypt_module_get_supported_key_sizes' => ['array', 'algorithm'=>'string', 'lib_dir='=>'string'], 'mcrypt_module_is_block_algorithm' => ['bool', 'algorithm'=>'string', 'lib_dir='=>'string'], 'mcrypt_module_is_block_algorithm_mode' => ['bool', 'mode'=>'string', 'lib_dir='=>'string'], 'mcrypt_module_is_block_mode' => ['bool', 'mode'=>'string', 'lib_dir='=>'string'], 'mcrypt_module_open' => ['resource|false', 'cipher'=>'string', 'cipher_directory'=>'string', 'mode'=>'string', 'mode_directory'=>'string'], 'mcrypt_module_self_test' => ['bool', 'algorithm'=>'string', 'lib_dir='=>'string'], 'mcrypt_ofb' => ['string', 'cipher'=>'int|string', 'key'=>'string', 'data'=>'string', 'mode'=>'int', 'iv='=>'string'], 'md5' => ['non-falsy-string', 'string'=>'string', 'binary='=>'bool'], 'md5_file' => ['non-falsy-string|false', 'filename'=>'string', 'binary='=>'bool'], 'mdecrypt_generic' => ['string', 'td'=>'resource', 'data'=>'string'], 'memcache_add' => ['bool', 'memcache_obj'=>'Memcache', 'key'=>'string', 'var'=>'mixed', 'flag='=>'int', 'expire='=>'int'], 'memcache_add_server' => ['bool', 'memcache_obj'=>'Memcache', 'host'=>'string', 'port='=>'int', 'persistent='=>'bool', 'weight='=>'int', 'timeout='=>'int', 'retry_interval='=>'int', 'status='=>'bool', 'failure_callback='=>'callable', 'timeoutms='=>'int'], 'memcache_append' => ['', 'memcache_obj'=>'Memcache'], 'memcache_cas' => ['', 'memcache_obj'=>'Memcache'], 'memcache_close' => ['bool', 'memcache_obj'=>'Memcache'], 'memcache_connect' => ['Memcache|false', 'host'=>'string', 'port='=>'int', 'timeout='=>'int'], 'memcache_debug' => ['bool', 'on_off'=>'bool'], 'memcache_decrement' => ['int', 'memcache_obj'=>'Memcache', 'key'=>'string', 'value='=>'int'], 'memcache_delete' => ['bool', 'memcache_obj'=>'Memcache', 'key'=>'string', 'timeout='=>'int'], 'memcache_flush' => ['bool', 'memcache_obj'=>'Memcache'], 'memcache_get' => ['string', 'memcache_obj'=>'Memcache', 'key'=>'string', 'flags='=>'int'], 'memcache_get\'1' => ['array', 'memcache_obj'=>'Memcache', 'key'=>'string[]', 'flags='=>'int[]'], 'memcache_get_extended_stats' => ['array', 'memcache_obj'=>'Memcache', 'type='=>'string', 'slabid='=>'int', 'limit='=>'int'], 'memcache_get_server_status' => ['int', 'memcache_obj'=>'Memcache', 'host'=>'string', 'port='=>'int'], 'memcache_get_stats' => ['array', 'memcache_obj'=>'Memcache', 'type='=>'string', 'slabid='=>'int', 'limit='=>'int'], 'memcache_get_version' => ['string', 'memcache_obj'=>'Memcache'], 'memcache_increment' => ['int', 'memcache_obj'=>'Memcache', 'key'=>'string', 'value='=>'int'], 'memcache_pconnect' => ['Memcache|false', 'host'=>'string', 'port='=>'int', 'timeout='=>'int'], 'memcache_prepend' => ['string', 'memcache_obj'=>'Memcache'], 'memcache_replace' => ['bool', 'memcache_obj'=>'Memcache', 'key'=>'string', 'var'=>'mixed', 'flag='=>'int', 'expire='=>'int'], 'memcache_set' => ['bool', 'memcache_obj'=>'Memcache', 'key'=>'string', 'var'=>'mixed', 'flag='=>'int', 'expire='=>'int'], 'memcache_set_compress_threshold' => ['bool', 'memcache_obj'=>'Memcache', 'threshold'=>'int', 'min_savings='=>'float'], 'memcache_set_failure_callback' => ['', 'memcache_obj'=>'Memcache'], 'memcache_set_server_params' => ['bool', 'memcache_obj'=>'Memcache', 'host'=>'string', 'port='=>'int', 'timeout='=>'int', 'retry_interval='=>'int', 'status='=>'bool', 'failure_callback='=>'callable'], 'memory_get_peak_usage' => ['int', 'real_usage='=>'bool'], 'memory_get_usage' => ['int', 'real_usage='=>'bool'], 'metaphone' => ['string|false', 'string'=>'string', 'max_phonemes='=>'int'], 'method_exists' => ['bool', 'object_or_class'=>'object|class-string|interface-string|enum-string', 'method'=>'string'], 'mhash' => ['string', 'algo'=>'int', 'data'=>'string', 'key='=>'string'], 'mhash_count' => ['int'], 'mhash_get_block_size' => ['int|false', 'algo'=>'int'], 'mhash_get_hash_name' => ['string|false', 'algo'=>'int'], 'mhash_keygen_s2k' => ['string|false', 'algo'=>'int', 'password'=>'string', 'salt'=>'string', 'length'=>'int'], 'microtime' => ['string', 'as_float='=>'false'], 'microtime\'1' => ['float', 'as_float='=>'true'], 'mime_content_type' => ['string|false', 'filename'=>'string|resource'], 'min' => ['mixed', 'value'=>'non-empty-array'], 'min\'1' => ['mixed', 'value'=>'', 'values'=>'', '...args='=>''], 'ming_keypress' => ['int', 'char'=>'string'], 'ming_setcubicthreshold' => ['void', 'threshold'=>'int'], 'ming_setscale' => ['void', 'scale'=>'float'], 'ming_setswfcompression' => ['void', 'level'=>'int'], 'ming_useconstants' => ['void', 'use'=>'int'], 'ming_useswfversion' => ['void', 'version'=>'int'], 'mkdir' => ['bool', 'directory'=>'string', 'permissions='=>'int', 'recursive='=>'bool', 'context='=>'resource'], 'mktime' => ['int|false', 'hour='=>'int', 'minute='=>'int', 'second='=>'int', 'month='=>'int', 'day='=>'int', 'year='=>'int'], 'money_format' => ['string', 'format'=>'string', 'value'=>'float'], 'monitor_custom_event' => ['void', 'class'=>'string', 'text'=>'string', 'severe='=>'int', 'user_data='=>'mixed'], 'monitor_httperror_event' => ['void', 'error_code'=>'int', 'url'=>'string', 'severe='=>'int'], 'monitor_license_info' => ['array'], 'monitor_pass_error' => ['void', 'errno'=>'int', 'errstr'=>'string', 'errfile'=>'string', 'errline'=>'int'], 'monitor_set_aggregation_hint' => ['void', 'hint'=>'string'], 'move_uploaded_file' => ['bool', 'from'=>'string', 'to'=>'string'], 'mqseries_back' => ['void', 'hconn'=>'resource', 'compcode'=>'resource', 'reason'=>'resource'], 'mqseries_begin' => ['void', 'hconn'=>'resource', 'beginoptions'=>'array', 'compcode'=>'resource', 'reason'=>'resource'], 'mqseries_close' => ['void', 'hconn'=>'resource', 'hobj'=>'resource', 'options'=>'int', 'compcode'=>'resource', 'reason'=>'resource'], 'mqseries_cmit' => ['void', 'hconn'=>'resource', 'compcode'=>'resource', 'reason'=>'resource'], 'mqseries_conn' => ['void', 'qmanagername'=>'string', 'hconn'=>'resource', 'compcode'=>'resource', 'reason'=>'resource'], 'mqseries_connx' => ['void', 'qmanagername'=>'string', 'connoptions'=>'array', 'hconn'=>'resource', 'compcode'=>'resource', 'reason'=>'resource'], 'mqseries_disc' => ['void', 'hconn'=>'resource', 'compcode'=>'resource', 'reason'=>'resource'], 'mqseries_get' => ['void', 'hconn'=>'resource', 'hobj'=>'resource', 'md'=>'array', 'gmo'=>'array', 'bufferlength'=>'int', 'msg'=>'string', 'data_length'=>'int', 'compcode'=>'resource', 'reason'=>'resource'], 'mqseries_inq' => ['void', 'hconn'=>'resource', 'hobj'=>'resource', 'selectorcount'=>'int', 'selectors'=>'array', 'intattrcount'=>'int', 'intattr'=>'resource', 'charattrlength'=>'int', 'charattr'=>'resource', 'compcode'=>'resource', 'reason'=>'resource'], 'mqseries_open' => ['void', 'hconn'=>'resource', 'objdesc'=>'array', 'option'=>'int', 'hobj'=>'resource', 'compcode'=>'resource', 'reason'=>'resource'], 'mqseries_put' => ['void', 'hconn'=>'resource', 'hobj'=>'resource', 'md'=>'array', 'pmo'=>'array', 'message'=>'string', 'compcode'=>'resource', 'reason'=>'resource'], 'mqseries_put1' => ['void', 'hconn'=>'resource', 'objdesc'=>'resource', 'msgdesc'=>'resource', 'pmo'=>'resource', 'buffer'=>'string', 'compcode'=>'resource', 'reason'=>'resource'], 'mqseries_set' => ['void', 'hconn'=>'resource', 'hobj'=>'resource', 'selectorcount'=>'int', 'selectors'=>'array', 'intattrcount'=>'int', 'intattrs'=>'array', 'charattrlength'=>'int', 'charattrs'=>'array', 'compcode'=>'resource', 'reason'=>'resource'], 'mqseries_strerror' => ['string', 'reason'=>'int'], 'ms_GetErrorObj' => ['errorObj'], 'ms_GetVersion' => ['string'], 'ms_GetVersionInt' => ['int'], 'ms_ResetErrorList' => ['void'], 'ms_TokenizeMap' => ['array', 'map_file_name'=>'string'], 'ms_iogetStdoutBufferBytes' => ['int'], 'ms_iogetstdoutbufferstring' => ['void'], 'ms_ioinstallstdinfrombuffer' => ['void'], 'ms_ioinstallstdouttobuffer' => ['void'], 'ms_ioresethandlers' => ['void'], 'ms_iostripstdoutbuffercontentheaders' => ['void'], 'ms_iostripstdoutbuffercontenttype' => ['string'], 'msession_connect' => ['bool', 'host'=>'string', 'port'=>'string'], 'msession_count' => ['int'], 'msession_create' => ['bool', 'session'=>'string', 'classname='=>'string', 'data='=>'string'], 'msession_destroy' => ['bool', 'name'=>'string'], 'msession_disconnect' => ['void'], 'msession_find' => ['array', 'name'=>'string', 'value'=>'string'], 'msession_get' => ['string', 'session'=>'string', 'name'=>'string', 'value'=>'string'], 'msession_get_array' => ['array', 'session'=>'string'], 'msession_get_data' => ['string', 'session'=>'string'], 'msession_inc' => ['string', 'session'=>'string', 'name'=>'string'], 'msession_list' => ['array'], 'msession_listvar' => ['array', 'name'=>'string'], 'msession_lock' => ['int', 'name'=>'string'], 'msession_plugin' => ['string', 'session'=>'string', 'value'=>'string', 'param='=>'string'], 'msession_randstr' => ['string', 'param'=>'int'], 'msession_set' => ['bool', 'session'=>'string', 'name'=>'string', 'value'=>'string'], 'msession_set_array' => ['void', 'session'=>'string', 'tuples'=>'array'], 'msession_set_data' => ['bool', 'session'=>'string', 'value'=>'string'], 'msession_timeout' => ['int', 'session'=>'string', 'param='=>'int'], 'msession_uniq' => ['string', 'param'=>'int', 'classname='=>'string', 'data='=>'string'], 'msession_unlock' => ['int', 'session'=>'string', 'key'=>'int'], 'msg_get_queue' => ['resource|false', 'key'=>'int', 'permissions='=>'int'], 'msg_queue_exists' => ['bool', 'key'=>'int'], 'msg_receive' => ['bool', 'queue'=>'resource', 'desired_message_type'=>'int', '&w_received_message_type'=>'int', 'max_message_size'=>'int', '&w_message'=>'mixed', 'unserialize='=>'bool', 'flags='=>'int', '&w_error_code='=>'int'], 'msg_remove_queue' => ['bool', 'queue'=>'resource'], 'msg_send' => ['bool', 'queue'=>'resource', 'message_type'=>'int', 'message'=>'mixed', 'serialize='=>'bool', 'blocking='=>'bool', '&w_error_code='=>'int'], 'msg_set_queue' => ['bool', 'queue'=>'resource', 'data'=>'array'], 'msg_stat_queue' => ['array', 'queue'=>'resource'], 'msgfmt_create' => ['?MessageFormatter', 'locale'=>'string', 'pattern'=>'string'], 'msgfmt_format' => ['string|false', 'formatter'=>'MessageFormatter', 'values'=>'array'], 'msgfmt_format_message' => ['string|false', 'locale'=>'string', 'pattern'=>'string', 'values'=>'array'], 'msgfmt_get_error_code' => ['int', 'formatter'=>'MessageFormatter'], 'msgfmt_get_error_message' => ['string', 'formatter'=>'MessageFormatter'], 'msgfmt_get_locale' => ['string', 'formatter'=>'MessageFormatter'], 'msgfmt_get_pattern' => ['string', 'formatter'=>'MessageFormatter'], 'msgfmt_parse' => ['array|false', 'formatter'=>'MessageFormatter', 'string'=>'string'], 'msgfmt_parse_message' => ['array|false', 'locale'=>'string', 'pattern'=>'string', 'message'=>'string'], 'msgfmt_set_pattern' => ['bool', 'formatter'=>'MessageFormatter', 'pattern'=>'string'], 'msql_affected_rows' => ['int', 'result'=>'resource'], 'msql_close' => ['bool', 'link_identifier='=>'?resource'], 'msql_connect' => ['resource', 'hostname='=>'string'], 'msql_create_db' => ['bool', 'database_name'=>'string', 'link_identifier='=>'?resource'], 'msql_data_seek' => ['bool', 'result'=>'resource', 'row_number'=>'int'], 'msql_db_query' => ['resource', 'database'=>'string', 'query'=>'string', 'link_identifier='=>'?resource'], 'msql_drop_db' => ['bool', 'database_name'=>'string', 'link_identifier='=>'?resource'], 'msql_error' => ['string'], 'msql_fetch_array' => ['array', 'result'=>'resource', 'result_type='=>'int'], 'msql_fetch_field' => ['object', 'result'=>'resource', 'field_offset='=>'int'], 'msql_fetch_object' => ['object', 'result'=>'resource'], 'msql_fetch_row' => ['array', 'result'=>'resource'], 'msql_field_flags' => ['string', 'result'=>'resource', 'field_offset'=>'int'], 'msql_field_len' => ['int', 'result'=>'resource', 'field_offset'=>'int'], 'msql_field_name' => ['string', 'result'=>'resource', 'field_offset'=>'int'], 'msql_field_seek' => ['bool', 'result'=>'resource', 'field_offset'=>'int'], 'msql_field_table' => ['int', 'result'=>'resource', 'field_offset'=>'int'], 'msql_field_type' => ['string', 'result'=>'resource', 'field_offset'=>'int'], 'msql_free_result' => ['bool', 'result'=>'resource'], 'msql_list_dbs' => ['resource', 'link_identifier='=>'?resource'], 'msql_list_fields' => ['resource', 'database'=>'string', 'tablename'=>'string', 'link_identifier='=>'?resource'], 'msql_list_tables' => ['resource', 'database'=>'string', 'link_identifier='=>'?resource'], 'msql_num_fields' => ['int', 'result'=>'resource'], 'msql_num_rows' => ['int', 'query_identifier'=>'resource'], 'msql_pconnect' => ['resource', 'hostname='=>'string'], 'msql_query' => ['resource', 'query'=>'string', 'link_identifier='=>'?resource'], 'msql_result' => ['string', 'result'=>'resource', 'row'=>'int', 'field='=>'mixed'], 'msql_select_db' => ['bool', 'database_name'=>'string', 'link_identifier='=>'?resource'], 'mt_getrandmax' => ['int<1, max>'], 'mt_rand' => ['int', 'min'=>'int', 'max'=>'int'], 'mt_rand\'1' => ['int'], 'mt_srand' => ['void', 'seed='=>'int', 'mode='=>'int'], 'mysql_xdevapi\baseresult::getWarnings' => ['array'], 'mysql_xdevapi\baseresult::getWarningsCount' => ['integer'], 'mysql_xdevapi\collection::add' => ['mysql_xdevapi\CollectionAdd', 'document'=>'mixed'], 'mysql_xdevapi\collection::addOrReplaceOne' => ['mysql_xdevapi\Result', 'id'=>'string', 'doc'=>'string'], 'mysql_xdevapi\collection::count' => ['integer'], 'mysql_xdevapi\collection::createIndex' => ['void', 'index_name'=>'string', 'index_desc_json'=>'string'], 'mysql_xdevapi\collection::dropIndex' => ['bool', 'index_name'=>'string'], 'mysql_xdevapi\collection::existsInDatabase' => ['bool'], 'mysql_xdevapi\collection::find' => ['mysql_xdevapi\CollectionFind', 'search_condition='=>'string'], 'mysql_xdevapi\collection::getName' => ['string'], 'mysql_xdevapi\collection::getOne' => ['Document', 'id'=>'string'], 'mysql_xdevapi\collection::getSchema' => ['mysql_xdevapi\schema'], 'mysql_xdevapi\collection::getSession' => ['Session'], 'mysql_xdevapi\collection::modify' => ['mysql_xdevapi\CollectionModify', 'search_condition'=>'string'], 'mysql_xdevapi\collection::remove' => ['mysql_xdevapi\CollectionRemove', 'search_condition'=>'string'], 'mysql_xdevapi\collection::removeOne' => ['mysql_xdevapi\Result', 'id'=>'string'], 'mysql_xdevapi\collection::replaceOne' => ['mysql_xdevapi\Result', 'id'=>'string', 'doc'=>'string'], 'mysql_xdevapi\collectionadd::execute' => ['mysql_xdevapi\Result'], 'mysql_xdevapi\collectionfind::bind' => ['mysql_xdevapi\CollectionFind', 'placeholder_values'=>'array'], 'mysql_xdevapi\collectionfind::execute' => ['mysql_xdevapi\DocResult'], 'mysql_xdevapi\collectionfind::fields' => ['mysql_xdevapi\CollectionFind', 'projection'=>'string'], 'mysql_xdevapi\collectionfind::groupBy' => ['mysql_xdevapi\CollectionFind', 'sort_expr'=>'string'], 'mysql_xdevapi\collectionfind::having' => ['mysql_xdevapi\CollectionFind', 'sort_expr'=>'string'], 'mysql_xdevapi\collectionfind::limit' => ['mysql_xdevapi\CollectionFind', 'rows'=>'integer'], 'mysql_xdevapi\collectionfind::lockExclusive' => ['mysql_xdevapi\CollectionFind', 'lock_waiting_option='=>'integer'], 'mysql_xdevapi\collectionfind::lockShared' => ['mysql_xdevapi\CollectionFind', 'lock_waiting_option='=>'integer'], 'mysql_xdevapi\collectionfind::offset' => ['mysql_xdevapi\CollectionFind', 'position'=>'integer'], 'mysql_xdevapi\collectionfind::sort' => ['mysql_xdevapi\CollectionFind', 'sort_expr'=>'string'], 'mysql_xdevapi\collectionmodify::arrayAppend' => ['mysql_xdevapi\CollectionModify', 'collection_field'=>'string', 'expression_or_literal'=>'string'], 'mysql_xdevapi\collectionmodify::arrayInsert' => ['mysql_xdevapi\CollectionModify', 'collection_field'=>'string', 'expression_or_literal'=>'string'], 'mysql_xdevapi\collectionmodify::bind' => ['mysql_xdevapi\CollectionModify', 'placeholder_values'=>'array'], 'mysql_xdevapi\collectionmodify::execute' => ['mysql_xdevapi\Result'], 'mysql_xdevapi\collectionmodify::limit' => ['mysql_xdevapi\CollectionModify', 'rows'=>'integer'], 'mysql_xdevapi\collectionmodify::patch' => ['mysql_xdevapi\CollectionModify', 'document'=>'string'], 'mysql_xdevapi\collectionmodify::replace' => ['mysql_xdevapi\CollectionModify', 'collection_field'=>'string', 'expression_or_literal'=>'string'], 'mysql_xdevapi\collectionmodify::set' => ['mysql_xdevapi\CollectionModify', 'collection_field'=>'string', 'expression_or_literal'=>'string'], 'mysql_xdevapi\collectionmodify::skip' => ['mysql_xdevapi\CollectionModify', 'position'=>'integer'], 'mysql_xdevapi\collectionmodify::sort' => ['mysql_xdevapi\CollectionModify', 'sort_expr'=>'string'], 'mysql_xdevapi\collectionmodify::unset' => ['mysql_xdevapi\CollectionModify', 'fields'=>'array'], 'mysql_xdevapi\collectionremove::bind' => ['mysql_xdevapi\CollectionRemove', 'placeholder_values'=>'array'], 'mysql_xdevapi\collectionremove::execute' => ['mysql_xdevapi\Result'], 'mysql_xdevapi\collectionremove::limit' => ['mysql_xdevapi\CollectionRemove', 'rows'=>'integer'], 'mysql_xdevapi\collectionremove::sort' => ['mysql_xdevapi\CollectionRemove', 'sort_expr'=>'string'], 'mysql_xdevapi\columnresult::getCharacterSetName' => ['string'], 'mysql_xdevapi\columnresult::getCollationName' => ['string'], 'mysql_xdevapi\columnresult::getColumnLabel' => ['string'], 'mysql_xdevapi\columnresult::getColumnName' => ['string'], 'mysql_xdevapi\columnresult::getFractionalDigits' => ['integer'], 'mysql_xdevapi\columnresult::getLength' => ['integer'], 'mysql_xdevapi\columnresult::getSchemaName' => ['string'], 'mysql_xdevapi\columnresult::getTableLabel' => ['string'], 'mysql_xdevapi\columnresult::getTableName' => ['string'], 'mysql_xdevapi\columnresult::getType' => ['integer'], 'mysql_xdevapi\columnresult::isNumberSigned' => ['integer'], 'mysql_xdevapi\columnresult::isPadded' => ['integer'], 'mysql_xdevapi\crudoperationbindable::bind' => ['mysql_xdevapi\CrudOperationBindable', 'placeholder_values'=>'array'], 'mysql_xdevapi\crudoperationlimitable::limit' => ['mysql_xdevapi\CrudOperationLimitable', 'rows'=>'integer'], 'mysql_xdevapi\crudoperationskippable::skip' => ['mysql_xdevapi\CrudOperationSkippable', 'skip'=>'integer'], 'mysql_xdevapi\crudoperationsortable::sort' => ['mysql_xdevapi\CrudOperationSortable', 'sort_expr'=>'string'], 'mysql_xdevapi\databaseobject::existsInDatabase' => ['bool'], 'mysql_xdevapi\databaseobject::getName' => ['string'], 'mysql_xdevapi\databaseobject::getSession' => ['mysql_xdevapi\Session'], 'mysql_xdevapi\docresult::fetchAll' => ['Array'], 'mysql_xdevapi\docresult::fetchOne' => ['Object'], 'mysql_xdevapi\docresult::getWarnings' => ['Array'], 'mysql_xdevapi\docresult::getWarningsCount' => ['integer'], 'mysql_xdevapi\executable::execute' => ['mysql_xdevapi\Result'], 'mysql_xdevapi\getsession' => ['mysql_xdevapi\Session', 'uri'=>'string'], 'mysql_xdevapi\result::getAutoIncrementValue' => ['int'], 'mysql_xdevapi\result::getGeneratedIds' => ['ArrayOfInt'], 'mysql_xdevapi\result::getWarnings' => ['array'], 'mysql_xdevapi\result::getWarningsCount' => ['integer'], 'mysql_xdevapi\rowresult::fetchAll' => ['array'], 'mysql_xdevapi\rowresult::fetchOne' => ['object'], 'mysql_xdevapi\rowresult::getColumnCount' => ['integer'], 'mysql_xdevapi\rowresult::getColumnNames' => ['array'], 'mysql_xdevapi\rowresult::getColumns' => ['array'], 'mysql_xdevapi\rowresult::getWarnings' => ['array'], 'mysql_xdevapi\rowresult::getWarningsCount' => ['integer'], 'mysql_xdevapi\schema::createCollection' => ['mysql_xdevapi\Collection', 'name'=>'string'], 'mysql_xdevapi\schema::dropCollection' => ['bool', 'collection_name'=>'string'], 'mysql_xdevapi\schema::existsInDatabase' => ['bool'], 'mysql_xdevapi\schema::getCollection' => ['mysql_xdevapi\Collection', 'name'=>'string'], 'mysql_xdevapi\schema::getCollectionAsTable' => ['mysql_xdevapi\Table', 'name'=>'string'], 'mysql_xdevapi\schema::getCollections' => ['array'], 'mysql_xdevapi\schema::getName' => ['string'], 'mysql_xdevapi\schema::getSession' => ['mysql_xdevapi\Session'], 'mysql_xdevapi\schema::getTable' => ['mysql_xdevapi\Table', 'name'=>'string'], 'mysql_xdevapi\schema::getTables' => ['array'], 'mysql_xdevapi\schemaobject::getSchema' => ['mysql_xdevapi\Schema'], 'mysql_xdevapi\session::close' => ['bool'], 'mysql_xdevapi\session::commit' => ['Object'], 'mysql_xdevapi\session::createSchema' => ['mysql_xdevapi\Schema', 'schema_name'=>'string'], 'mysql_xdevapi\session::dropSchema' => ['bool', 'schema_name'=>'string'], 'mysql_xdevapi\session::executeSql' => ['Object', 'statement'=>'string'], 'mysql_xdevapi\session::generateUUID' => ['string'], 'mysql_xdevapi\session::getClientId' => ['integer'], 'mysql_xdevapi\session::getSchema' => ['mysql_xdevapi\Schema', 'schema_name'=>'string'], 'mysql_xdevapi\session::getSchemas' => ['array'], 'mysql_xdevapi\session::getServerVersion' => ['integer'], 'mysql_xdevapi\session::killClient' => ['object', 'client_id'=>'integer'], 'mysql_xdevapi\session::listClients' => ['array'], 'mysql_xdevapi\session::quoteName' => ['string', 'name'=>'string'], 'mysql_xdevapi\session::releaseSavepoint' => ['void', 'name'=>'string'], 'mysql_xdevapi\session::rollback' => ['void'], 'mysql_xdevapi\session::rollbackTo' => ['void', 'name'=>'string'], 'mysql_xdevapi\session::setSavepoint' => ['string', 'name='=>'string'], 'mysql_xdevapi\session::sql' => ['mysql_xdevapi\SqlStatement', 'query'=>'string'], 'mysql_xdevapi\session::startTransaction' => ['void'], 'mysql_xdevapi\sqlstatement::bind' => ['mysql_xdevapi\SqlStatement', 'param'=>'string'], 'mysql_xdevapi\sqlstatement::execute' => ['mysql_xdevapi\Result'], 'mysql_xdevapi\sqlstatement::getNextResult' => ['mysql_xdevapi\Result'], 'mysql_xdevapi\sqlstatement::getResult' => ['mysql_xdevapi\Result'], 'mysql_xdevapi\sqlstatement::hasMoreResults' => ['bool'], 'mysql_xdevapi\sqlstatementresult::fetchAll' => ['array'], 'mysql_xdevapi\sqlstatementresult::fetchOne' => ['object'], 'mysql_xdevapi\sqlstatementresult::getAffectedItemsCount' => ['integer'], 'mysql_xdevapi\sqlstatementresult::getColumnCount' => ['integer'], 'mysql_xdevapi\sqlstatementresult::getColumnNames' => ['array'], 'mysql_xdevapi\sqlstatementresult::getColumns' => ['Array'], 'mysql_xdevapi\sqlstatementresult::getGeneratedIds' => ['array'], 'mysql_xdevapi\sqlstatementresult::getLastInsertId' => ['String'], 'mysql_xdevapi\sqlstatementresult::getWarnings' => ['array'], 'mysql_xdevapi\sqlstatementresult::getWarningsCount' => ['integer'], 'mysql_xdevapi\sqlstatementresult::hasData' => ['bool'], 'mysql_xdevapi\sqlstatementresult::nextResult' => ['mysql_xdevapi\Result'], 'mysql_xdevapi\statement::getNextResult' => ['mysql_xdevapi\Result'], 'mysql_xdevapi\statement::getResult' => ['mysql_xdevapi\Result'], 'mysql_xdevapi\statement::hasMoreResults' => ['bool'], 'mysql_xdevapi\table::count' => ['integer'], 'mysql_xdevapi\table::delete' => ['mysql_xdevapi\TableDelete'], 'mysql_xdevapi\table::existsInDatabase' => ['bool'], 'mysql_xdevapi\table::getName' => ['string'], 'mysql_xdevapi\table::getSchema' => ['mysql_xdevapi\Schema'], 'mysql_xdevapi\table::getSession' => ['mysql_xdevapi\Session'], 'mysql_xdevapi\table::insert' => ['mysql_xdevapi\TableInsert', 'columns'=>'mixed', '...args='=>'mixed'], 'mysql_xdevapi\table::isView' => ['bool'], 'mysql_xdevapi\table::select' => ['mysql_xdevapi\TableSelect', 'columns'=>'mixed', '...args='=>'mixed'], 'mysql_xdevapi\table::update' => ['mysql_xdevapi\TableUpdate'], 'mysql_xdevapi\tabledelete::bind' => ['mysql_xdevapi\TableDelete', 'placeholder_values'=>'array'], 'mysql_xdevapi\tabledelete::execute' => ['mysql_xdevapi\Result'], 'mysql_xdevapi\tabledelete::limit' => ['mysql_xdevapi\TableDelete', 'rows'=>'integer'], 'mysql_xdevapi\tabledelete::offset' => ['mysql_xdevapi\TableDelete', 'position'=>'integer'], 'mysql_xdevapi\tabledelete::orderby' => ['mysql_xdevapi\TableDelete', 'orderby_expr'=>'string'], 'mysql_xdevapi\tabledelete::where' => ['mysql_xdevapi\TableDelete', 'where_expr'=>'string'], 'mysql_xdevapi\tableinsert::execute' => ['mysql_xdevapi\Result'], 'mysql_xdevapi\tableinsert::values' => ['mysql_xdevapi\TableInsert', 'row_values'=>'array'], 'mysql_xdevapi\tableselect::bind' => ['mysql_xdevapi\TableSelect', 'placeholder_values'=>'array'], 'mysql_xdevapi\tableselect::execute' => ['mysql_xdevapi\RowResult'], 'mysql_xdevapi\tableselect::groupBy' => ['mysql_xdevapi\TableSelect', 'sort_expr'=>'mixed'], 'mysql_xdevapi\tableselect::having' => ['mysql_xdevapi\TableSelect', 'sort_expr'=>'string'], 'mysql_xdevapi\tableselect::limit' => ['mysql_xdevapi\TableSelect', 'rows'=>'integer'], 'mysql_xdevapi\tableselect::lockExclusive' => ['mysql_xdevapi\TableSelect', 'lock_waiting_option='=>'integer'], 'mysql_xdevapi\tableselect::lockShared' => ['mysql_xdevapi\TableSelect', 'lock_waiting_option='=>'integer'], 'mysql_xdevapi\tableselect::offset' => ['mysql_xdevapi\TableSelect', 'position'=>'integer'], 'mysql_xdevapi\tableselect::orderby' => ['mysql_xdevapi\TableSelect', 'sort_expr'=>'mixed', '...args='=>'mixed'], 'mysql_xdevapi\tableselect::where' => ['mysql_xdevapi\TableSelect', 'where_expr'=>'string'], 'mysql_xdevapi\tableupdate::bind' => ['mysql_xdevapi\TableUpdate', 'placeholder_values'=>'array'], 'mysql_xdevapi\tableupdate::execute' => ['mysql_xdevapi\TableUpdate'], 'mysql_xdevapi\tableupdate::limit' => ['mysql_xdevapi\TableUpdate', 'rows'=>'integer'], 'mysql_xdevapi\tableupdate::orderby' => ['mysql_xdevapi\TableUpdate', 'orderby_expr'=>'mixed', '...args='=>'mixed'], 'mysql_xdevapi\tableupdate::set' => ['mysql_xdevapi\TableUpdate', 'table_field'=>'string', 'expression_or_literal'=>'string'], 'mysql_xdevapi\tableupdate::where' => ['mysql_xdevapi\TableUpdate', 'where_expr'=>'string'], 'mysqli::__construct' => ['void', 'hostname='=>'string', 'username='=>'string', 'password='=>'string', 'database='=>'string', 'port='=>'int', 'socket='=>'string'], 'mysqli::autocommit' => ['bool', 'enable'=>'bool'], 'mysqli::begin_transaction' => ['bool', 'flags='=>'int', 'name='=>'string'], 'mysqli::change_user' => ['bool', 'username'=>'string', 'password'=>'string', 'database'=>'?string'], 'mysqli::character_set_name' => ['string'], 'mysqli::close' => ['true'], 'mysqli::commit' => ['bool', 'flags='=>'int', 'name='=>'string'], 'mysqli::connect' => ['null|false', 'hostname='=>'string', 'username='=>'string', 'password='=>'string', 'database='=>'string', 'port='=>'int', 'socket='=>'string'], 'mysqli::debug' => ['true', 'options'=>'string'], 'mysqli::dump_debug_info' => ['bool'], 'mysqli::escape_string' => ['string', 'string'=>'string'], 'mysqli::get_charset' => ['object'], 'mysqli::get_client_info' => ['string'], 'mysqli::get_connection_stats' => ['array'], 'mysqli::get_warnings' => ['mysqli_warning'], 'mysqli::init' => ['false|null'], 'mysqli::kill' => ['bool', 'process_id'=>'int'], 'mysqli::more_results' => ['bool'], 'mysqli::multi_query' => ['bool', 'query'=>'string'], 'mysqli::next_result' => ['bool'], 'mysqli::options' => ['bool', 'option'=>'int', 'value'=>'string|int'], 'mysqli::ping' => ['bool'], 'mysqli::poll' => ['int|false', '&w_read'=>'?array', '&w_error'=>'?array', '&w_reject'=>'array', 'seconds'=>'int', 'microseconds='=>'int'], 'mysqli::prepare' => ['mysqli_stmt|false', 'query'=>'string'], 'mysqli::query' => ['bool|mysqli_result', 'query'=>'string', 'result_mode='=>'int'], 'mysqli::real_connect' => ['bool', 'hostname='=>'?string', 'username='=>'?string', 'password='=>'?string', 'database='=>'?string', 'port='=>'?int', 'socket='=>'?string', 'flags='=>'int'], 'mysqli::real_escape_string' => ['string', 'string'=>'string'], 'mysqli::real_query' => ['bool', 'query'=>'string'], 'mysqli::reap_async_query' => ['mysqli_result|false'], 'mysqli::refresh' => ['bool', 'flags'=>'int'], 'mysqli::release_savepoint' => ['bool', 'name'=>'string'], 'mysqli::rollback' => ['bool', 'flags='=>'int', 'name='=>'string'], 'mysqli::savepoint' => ['bool', 'name'=>'string'], 'mysqli::select_db' => ['bool', 'database'=>'string'], 'mysqli::set_charset' => ['bool', 'charset'=>'string'], 'mysqli::set_opt' => ['bool', 'option'=>'int', 'value'=>'string|int'], 'mysqli::ssl_set' => ['true', 'key'=>'?string', 'certificate'=>'?string', 'ca_certificate'=>'?string', 'ca_path'=>'?string', 'cipher_algos'=>'?string'], 'mysqli::stat' => ['string|false'], 'mysqli::stmt_init' => ['mysqli_stmt'], 'mysqli::store_result' => ['mysqli_result|false', 'mode='=>'int'], 'mysqli::thread_safe' => ['bool'], 'mysqli::use_result' => ['mysqli_result|false'], 'mysqli_affected_rows' => ['int<-1, max>|numeric-string', 'mysql'=>'mysqli'], 'mysqli_autocommit' => ['bool', 'mysql'=>'mysqli', 'enable'=>'bool'], 'mysqli_begin_transaction' => ['bool', 'mysql'=>'mysqli', 'flags='=>'int', 'name='=>'string'], 'mysqli_change_user' => ['bool', 'mysql'=>'mysqli', 'username'=>'string', 'password'=>'string', 'database'=>'?string'], 'mysqli_character_set_name' => ['string', 'mysql'=>'mysqli'], 'mysqli_close' => ['true', 'mysql'=>'mysqli'], 'mysqli_commit' => ['bool', 'mysql'=>'mysqli', 'flags='=>'int', 'name='=>'string'], 'mysqli_connect' => ['mysqli|false', 'hostname='=>'string', 'username='=>'string', 'password='=>'string', 'database='=>'string', 'port='=>'int', 'socket='=>'string'], 'mysqli_connect_errno' => ['int'], 'mysqli_connect_error' => ['?string'], 'mysqli_data_seek' => ['bool', 'result'=>'mysqli_result', 'offset'=>'int'], 'mysqli_debug' => ['true', 'options'=>'string'], 'mysqli_disable_reads_from_master' => ['bool', 'link'=>'mysqli'], 'mysqli_disable_rpl_parse' => ['bool', 'link'=>'mysqli'], 'mysqli_dump_debug_info' => ['bool', 'mysql'=>'mysqli'], 'mysqli_embedded_server_end' => ['void'], 'mysqli_embedded_server_start' => ['bool', 'start'=>'int', 'arguments'=>'array', 'groups'=>'array'], 'mysqli_enable_reads_from_master' => ['bool', 'link'=>'mysqli'], 'mysqli_enable_rpl_parse' => ['bool', 'link'=>'mysqli'], 'mysqli_errno' => ['int', 'mysql'=>'mysqli'], 'mysqli_error' => ['string', 'mysql'=>'mysqli'], 'mysqli_error_list' => ['array', 'mysql'=>'mysqli'], 'mysqli_escape_string' => ['string', 'mysql'=>'mysqli', 'string'=>'string'], 'mysqli_execute' => ['bool', 'statement'=>'mysqli_stmt'], 'mysqli_fetch_all' => ['list>', 'result'=>'mysqli_result', 'mode='=>'3'], 'mysqli_fetch_all\'1' => ['list>', 'result'=>'mysqli_result', 'mode='=>'1'], 'mysqli_fetch_all\'2' => ['list>', 'result'=>'mysqli_result', 'mode='=>'2'], 'mysqli_fetch_array' => ['array|false|null', 'result'=>'mysqli_result', 'mode='=>'3'], 'mysqli_fetch_array\'1' => ['array|false|null', 'result'=>'mysqli_result', 'mode='=>'1'], 'mysqli_fetch_array\'2' => ['list|false|null', 'result'=>'mysqli_result', 'mode='=>'2'], 'mysqli_fetch_assoc' => ['array|false|null', 'result'=>'mysqli_result'], 'mysqli_fetch_field' => ['object{name:string,orgname:string,table:string,orgtable:string,max_length:int,length:int,charsetnr:int,flags:int,type:int,decimals:int,db:string,def:\'\',catalog:\'def\'}|false', 'result'=>'mysqli_result'], 'mysqli_fetch_field_direct' => ['object{name:string,orgname:string,table:string,orgtable:string,max_length:int,length:int,charsetnr:int,flags:int,type:int,decimals:int,db:string,def:\'\',catalog:\'def\'}|false', 'result'=>'mysqli_result', 'index'=>'int'], 'mysqli_fetch_fields' => ['list', 'result'=>'mysqli_result'], 'mysqli_fetch_lengths' => ['array|false', 'result'=>'mysqli_result'], 'mysqli_fetch_object' => ['object|false|null', 'result'=>'mysqli_result', 'class='=>'string', 'constructor_args='=>'array'], 'mysqli_fetch_row' => ['list|false|null', 'result'=>'mysqli_result'], 'mysqli_field_count' => ['int', 'mysql'=>'mysqli'], 'mysqli_field_seek' => ['bool', 'result'=>'mysqli_result', 'index'=>'int'], 'mysqli_field_tell' => ['int', 'result'=>'mysqli_result'], 'mysqli_free_result' => ['void', 'result'=>'mysqli_result'], 'mysqli_get_cache_stats' => ['array|false'], 'mysqli_get_charset' => ['?object', 'mysql'=>'mysqli'], 'mysqli_get_client_info' => ['string', 'mysql='=>'?mysqli'], 'mysqli_get_client_stats' => ['array'], 'mysqli_get_client_version' => ['int'], 'mysqli_get_connection_stats' => ['array', 'mysql'=>'mysqli'], 'mysqli_get_host_info' => ['string', 'mysql'=>'mysqli'], 'mysqli_get_links_stats' => ['array'], 'mysqli_get_proto_info' => ['int', 'mysql'=>'mysqli'], 'mysqli_get_server_info' => ['string', 'mysql'=>'mysqli'], 'mysqli_get_server_version' => ['int', 'mysql'=>'mysqli'], 'mysqli_get_warnings' => ['mysqli_warning', 'mysql'=>'mysqli'], 'mysqli_info' => ['?string', 'mysql'=>'mysqli'], 'mysqli_init' => ['mysqli|false'], 'mysqli_insert_id' => ['int|string', 'mysql'=>'mysqli'], 'mysqli_kill' => ['bool', 'mysql'=>'mysqli', 'process_id'=>'int'], 'mysqli_link_construct' => ['object'], 'mysqli_master_query' => ['bool', 'link'=>'mysqli', 'query'=>'string'], 'mysqli_more_results' => ['bool', 'mysql'=>'mysqli'], 'mysqli_multi_query' => ['bool', 'mysql'=>'mysqli', 'query'=>'string'], 'mysqli_next_result' => ['bool', 'mysql'=>'mysqli'], 'mysqli_num_fields' => ['int', 'result'=>'mysqli_result'], 'mysqli_num_rows' => ['int<0, max>|numeric-string', 'result'=>'mysqli_result'], 'mysqli_options' => ['bool', 'mysql'=>'mysqli', 'option'=>'int', 'value'=>'string|int'], 'mysqli_ping' => ['bool', 'mysql'=>'mysqli'], 'mysqli_poll' => ['int|false', '&w_read'=>'?array', '&w_error'=>'?array', '&w_reject'=>'array', 'seconds'=>'int', 'microseconds='=>'int'], 'mysqli_prepare' => ['mysqli_stmt|false', 'mysql'=>'mysqli', 'query'=>'string'], 'mysqli_query' => ['mysqli_result|bool', 'mysql'=>'mysqli', 'query'=>'string', 'result_mode='=>'int'], 'mysqli_real_connect' => ['bool', 'mysql'=>'mysqli', 'hostname='=>'?string', 'username='=>'?string', 'password='=>'?string', 'database='=>'?string', 'port='=>'?int', 'socket='=>'?string', 'flags='=>'int'], 'mysqli_real_escape_string' => ['string', 'mysql'=>'mysqli', 'string'=>'string'], 'mysqli_real_query' => ['bool', 'mysql'=>'mysqli', 'query'=>'string'], 'mysqli_reap_async_query' => ['mysqli_result|false', 'mysql'=>'mysqli'], 'mysqli_refresh' => ['bool', 'mysql'=>'mysqli', 'flags'=>'int'], 'mysqli_release_savepoint' => ['bool', 'mysql'=>'mysqli', 'name'=>'string'], 'mysqli_report' => ['bool', 'flags'=>'int'], 'mysqli_result::__construct' => ['void', 'mysql'=>'mysqli', 'result_mode='=>'int'], 'mysqli_result::close' => ['void'], 'mysqli_result::data_seek' => ['bool', 'offset'=>'int'], 'mysqli_result::fetch_all' => ['list>', 'mode='=>'3'], 'mysqli_result::fetch_all\'1' => ['list>', 'mode='=>'1'], 'mysqli_result::fetch_all\'2' => ['list>', 'mode='=>'2'], 'mysqli_result::fetch_array' => ['array|false|null', 'mode='=>'3'], 'mysqli_result::fetch_array\'1' => ['array|false|null', 'mode='=>'1'], 'mysqli_result::fetch_array\'2' => ['list|false|null', 'mode='=>'2'], 'mysqli_result::fetch_assoc' => ['array|false|null'], 'mysqli_result::fetch_field' => ['object{name:string,orgname:string,table:string,orgtable:string,max_length:int,length:int,charsetnr:int,flags:int,type:int,decimals:int,db:string,def:\'\',catalog:\'def\'}|false'], 'mysqli_result::fetch_field_direct' => ['object{name:string,orgname:string,table:string,orgtable:string,max_length:int,length:int,charsetnr:int,flags:int,type:int,decimals:int,db:string,def:\'\',catalog:\'def\'}|false', 'index'=>'int'], 'mysqli_result::fetch_fields' => ['list'], 'mysqli_result::fetch_object' => ['object|false|null', 'class='=>'string', 'constructor_args='=>'array'], 'mysqli_result::fetch_row' => ['list|false|null'], 'mysqli_result::field_seek' => ['bool', 'index'=>'int'], 'mysqli_result::free' => ['void'], 'mysqli_result::free_result' => ['void'], 'mysqli_rollback' => ['bool', 'mysql'=>'mysqli', 'flags='=>'int', 'name='=>'string'], 'mysqli_rpl_parse_enabled' => ['int', 'link'=>'mysqli'], 'mysqli_rpl_probe' => ['bool', 'link'=>'mysqli'], 'mysqli_rpl_query_type' => ['int', 'link'=>'mysqli', 'query'=>'string'], 'mysqli_savepoint' => ['bool', 'mysql'=>'mysqli', 'name'=>'string'], 'mysqli_savepoint_libmysql' => ['bool'], 'mysqli_select_db' => ['bool', 'mysql'=>'mysqli', 'database'=>'string'], 'mysqli_send_query' => ['bool', 'link'=>'mysqli', 'query'=>'string'], 'mysqli_set_charset' => ['bool', 'mysql'=>'mysqli', 'charset'=>'string'], 'mysqli_set_local_infile_default' => ['void', 'link'=>'mysqli'], 'mysqli_set_local_infile_handler' => ['bool', 'link'=>'mysqli', 'read_func'=>'callable'], 'mysqli_set_opt' => ['bool', 'mysql'=>'mysqli', 'option'=>'int', 'value'=>'string|int'], 'mysqli_slave_query' => ['bool', 'link'=>'mysqli', 'query'=>'string'], 'mysqli_sqlstate' => ['string', 'mysql'=>'mysqli'], 'mysqli_ssl_set' => ['true', 'mysql'=>'mysqli', 'key'=>'?string', 'certificate'=>'?string', 'ca_certificate'=>'?string', 'ca_path'=>'?string', 'cipher_algos'=>'?string'], 'mysqli_stat' => ['string|false', 'mysql'=>'mysqli'], 'mysqli_stmt::__construct' => ['void', 'mysql'=>'mysqli', 'query='=>'string'], 'mysqli_stmt::attr_get' => ['int', 'attribute'=>'int'], 'mysqli_stmt::attr_set' => ['bool', 'attribute'=>'int', 'value'=>'int'], 'mysqli_stmt::bind_param' => ['bool', 'types'=>'string', '&var'=>'mixed', '&...vars='=>'mixed'], 'mysqli_stmt::bind_result' => ['bool', '&w_var1'=>'', '&...w_vars='=>''], 'mysqli_stmt::close' => ['true'], 'mysqli_stmt::data_seek' => ['void', 'offset'=>'int'], 'mysqli_stmt::execute' => ['bool'], 'mysqli_stmt::fetch' => ['bool|null'], 'mysqli_stmt::free_result' => ['void'], 'mysqli_stmt::get_result' => ['mysqli_result|false'], 'mysqli_stmt::get_warnings' => ['object'], 'mysqli_stmt::more_results' => ['bool'], 'mysqli_stmt::next_result' => ['bool'], 'mysqli_stmt::num_rows' => ['int<0, max>|numeric-string'], 'mysqli_stmt::prepare' => ['bool', 'query'=>'string'], 'mysqli_stmt::reset' => ['bool'], 'mysqli_stmt::result_metadata' => ['mysqli_result|false'], 'mysqli_stmt::send_long_data' => ['bool', 'param_num'=>'int', 'data'=>'string'], 'mysqli_stmt::store_result' => ['bool'], 'mysqli_stmt_affected_rows' => ['int<-1, max>|numeric-string', 'statement'=>'mysqli_stmt'], 'mysqli_stmt_attr_get' => ['int', 'statement'=>'mysqli_stmt', 'attribute'=>'int'], 'mysqli_stmt_attr_set' => ['bool', 'statement'=>'mysqli_stmt', 'attribute'=>'int', 'value'=>'int'], 'mysqli_stmt_bind_param' => ['bool', 'statement'=>'mysqli_stmt', 'types'=>'string', '&var'=>'mixed', '&...vars='=>'mixed'], 'mysqli_stmt_bind_result' => ['bool', 'statement'=>'mysqli_stmt', '&w_var1'=>'', '&...w_vars='=>''], 'mysqli_stmt_close' => ['true', 'statement'=>'mysqli_stmt'], 'mysqli_stmt_data_seek' => ['void', 'statement'=>'mysqli_stmt', 'offset'=>'int'], 'mysqli_stmt_errno' => ['int', 'statement'=>'mysqli_stmt'], 'mysqli_stmt_error' => ['string', 'statement'=>'mysqli_stmt'], 'mysqli_stmt_error_list' => ['array', 'statement'=>'mysqli_stmt'], 'mysqli_stmt_execute' => ['bool', 'statement'=>'mysqli_stmt'], 'mysqli_stmt_fetch' => ['bool|null', 'statement'=>'mysqli_stmt'], 'mysqli_stmt_field_count' => ['int', 'statement'=>'mysqli_stmt'], 'mysqli_stmt_free_result' => ['void', 'statement'=>'mysqli_stmt'], 'mysqli_stmt_get_result' => ['mysqli_result|false', 'statement'=>'mysqli_stmt'], 'mysqli_stmt_get_warnings' => ['object', 'statement'=>'mysqli_stmt'], 'mysqli_stmt_init' => ['mysqli_stmt', 'mysql'=>'mysqli'], 'mysqli_stmt_insert_id' => ['mixed', 'statement'=>'mysqli_stmt'], 'mysqli_stmt_more_results' => ['bool', 'statement'=>'mysqli_stmt'], 'mysqli_stmt_next_result' => ['bool', 'statement'=>'mysqli_stmt'], 'mysqli_stmt_num_rows' => ['int', 'statement'=>'mysqli_stmt'], 'mysqli_stmt_param_count' => ['int', 'statement'=>'mysqli_stmt'], 'mysqli_stmt_prepare' => ['bool', 'statement'=>'mysqli_stmt', 'query'=>'string'], 'mysqli_stmt_reset' => ['bool', 'statement'=>'mysqli_stmt'], 'mysqli_stmt_result_metadata' => ['mysqli_result|false', 'statement'=>'mysqli_stmt'], 'mysqli_stmt_send_long_data' => ['bool', 'statement'=>'mysqli_stmt', 'param_num'=>'int', 'data'=>'string'], 'mysqli_stmt_sqlstate' => ['string', 'statement'=>'mysqli_stmt'], 'mysqli_stmt_store_result' => ['bool', 'statement'=>'mysqli_stmt'], 'mysqli_store_result' => ['mysqli_result|false', 'mysql'=>'mysqli', 'mode='=>'int'], 'mysqli_thread_id' => ['int', 'mysql'=>'mysqli'], 'mysqli_thread_safe' => ['bool'], 'mysqli_use_result' => ['mysqli_result|false', 'mysql'=>'mysqli'], 'mysqli_warning::__construct' => ['void'], 'mysqli_warning::next' => ['bool'], 'mysqli_warning_count' => ['int', 'mysql'=>'mysqli'], 'mysqlnd_memcache_get_config' => ['array', 'connection'=>'mixed'], 'mysqlnd_memcache_set' => ['bool', 'mysql_connection'=>'mixed', 'memcache_connection='=>'Memcached', 'pattern='=>'string', 'callback='=>'callable'], 'mysqlnd_ms_dump_servers' => ['array', 'connection'=>'mixed'], 'mysqlnd_ms_fabric_select_global' => ['array', 'connection'=>'mixed', 'table_name'=>'mixed'], 'mysqlnd_ms_fabric_select_shard' => ['array', 'connection'=>'mixed', 'table_name'=>'mixed', 'shard_key'=>'mixed'], 'mysqlnd_ms_get_last_gtid' => ['string', 'connection'=>'mixed'], 'mysqlnd_ms_get_last_used_connection' => ['array', 'connection'=>'mixed'], 'mysqlnd_ms_get_stats' => ['array'], 'mysqlnd_ms_match_wild' => ['bool', 'table_name'=>'string', 'wildcard'=>'string'], 'mysqlnd_ms_query_is_select' => ['int', 'query'=>'string'], 'mysqlnd_ms_set_qos' => ['bool', 'connection'=>'mixed', 'service_level'=>'int', 'service_level_option='=>'int', 'option_value='=>'mixed'], 'mysqlnd_ms_set_user_pick_server' => ['bool', 'function'=>'string'], 'mysqlnd_ms_xa_begin' => ['int', 'connection'=>'mixed', 'gtrid'=>'string', 'timeout='=>'int'], 'mysqlnd_ms_xa_commit' => ['int', 'connection'=>'mixed', 'gtrid'=>'string'], 'mysqlnd_ms_xa_gc' => ['int', 'connection'=>'mixed', 'gtrid='=>'string', 'ignore_max_retries='=>'bool'], 'mysqlnd_ms_xa_rollback' => ['int', 'connection'=>'mixed', 'gtrid'=>'string'], 'mysqlnd_qc_change_handler' => ['bool', 'handler'=>''], 'mysqlnd_qc_clear_cache' => ['bool'], 'mysqlnd_qc_get_available_handlers' => ['array'], 'mysqlnd_qc_get_cache_info' => ['array'], 'mysqlnd_qc_get_core_stats' => ['array'], 'mysqlnd_qc_get_handler' => ['array'], 'mysqlnd_qc_get_normalized_query_trace_log' => ['array'], 'mysqlnd_qc_get_query_trace_log' => ['array'], 'mysqlnd_qc_set_cache_condition' => ['bool', 'condition_type'=>'int', 'condition'=>'mixed', 'condition_option'=>'mixed'], 'mysqlnd_qc_set_is_select' => ['mixed', 'callback'=>'string'], 'mysqlnd_qc_set_storage_handler' => ['bool', 'handler'=>'string'], 'mysqlnd_qc_set_user_handlers' => ['bool', 'get_hash'=>'string', 'find_query_in_cache'=>'string', 'return_to_cache'=>'string', 'add_query_to_cache_if_not_exists'=>'string', 'query_is_select'=>'string', 'update_query_run_time_stats'=>'string', 'get_stats'=>'string', 'clear_cache'=>'string'], 'mysqlnd_uh_convert_to_mysqlnd' => ['resource', '&rw_mysql_connection'=>'mysqli'], 'mysqlnd_uh_set_connection_proxy' => ['bool', '&rw_connection_proxy'=>'MysqlndUhConnection', '&rw_mysqli_connection='=>'mysqli'], 'mysqlnd_uh_set_statement_proxy' => ['bool', '&rw_statement_proxy'=>'MysqlndUhStatement'], 'natcasesort' => ['bool', '&rw_array'=>'array'], 'natsort' => ['bool', '&rw_array'=>'array'], 'newrelic_add_custom_parameter' => ['bool', 'key'=>'string', 'value'=>'bool|float|int|string'], 'newrelic_add_custom_tracer' => ['bool', 'function_name'=>'string'], 'newrelic_background_job' => ['void', 'flag='=>'bool'], 'newrelic_capture_params' => ['void', 'enable='=>'bool'], 'newrelic_custom_metric' => ['bool', 'metric_name'=>'string', 'value'=>'float'], 'newrelic_disable_autorum' => ['true'], 'newrelic_end_of_transaction' => ['void'], 'newrelic_end_transaction' => ['bool', 'ignore='=>'bool'], 'newrelic_get_browser_timing_footer' => ['string', 'include_tags='=>'bool'], 'newrelic_get_browser_timing_header' => ['string', 'include_tags='=>'bool'], 'newrelic_ignore_apdex' => ['void'], 'newrelic_ignore_transaction' => ['void'], 'newrelic_name_transaction' => ['bool', 'name'=>'string'], 'newrelic_notice_error' => ['void', 'message'=>'string', 'exception='=>'Exception|Throwable'], 'newrelic_notice_error\'1' => ['void', 'unused_1'=>'string', 'message'=>'string', 'unused_2'=>'string', 'unused_3'=>'int', 'unused_4='=>''], 'newrelic_record_custom_event' => ['void', 'name'=>'string', 'attributes'=>'array'], 'newrelic_record_datastore_segment' => ['mixed', 'func'=>'callable', 'parameters'=>'array'], 'newrelic_set_appname' => ['bool', 'name'=>'string', 'license='=>'string', 'xmit='=>'bool'], 'newrelic_set_user_attributes' => ['bool', 'user'=>'string', 'account'=>'string', 'product'=>'string'], 'newrelic_start_transaction' => ['bool', 'appname'=>'string', 'license='=>'string'], 'next' => ['mixed', '&r_array'=>'array|object'], 'ngettext' => ['string', 'singular'=>'string', 'plural'=>'string', 'count'=>'int'], 'nl2br' => ['string', 'string'=>'string', 'use_xhtml='=>'bool'], 'nl_langinfo' => ['string|false', 'item'=>'int'], 'normalizer_is_normalized' => ['bool', 'string'=>'string', 'form='=>'int'], 'normalizer_normalize' => ['string|false', 'string'=>'string', 'form='=>'int'], 'notes_body' => ['array', 'server'=>'string', 'mailbox'=>'string', 'msg_number'=>'int'], 'notes_copy_db' => ['bool', 'from_database_name'=>'string', 'to_database_name'=>'string'], 'notes_create_db' => ['bool', 'database_name'=>'string'], 'notes_create_note' => ['bool', 'database_name'=>'string', 'form_name'=>'string'], 'notes_drop_db' => ['bool', 'database_name'=>'string'], 'notes_find_note' => ['int', 'database_name'=>'string', 'name'=>'string', 'type='=>'string'], 'notes_header_info' => ['object', 'server'=>'string', 'mailbox'=>'string', 'msg_number'=>'int'], 'notes_list_msgs' => ['bool', 'db'=>'string'], 'notes_mark_read' => ['bool', 'database_name'=>'string', 'user_name'=>'string', 'note_id'=>'string'], 'notes_mark_unread' => ['bool', 'database_name'=>'string', 'user_name'=>'string', 'note_id'=>'string'], 'notes_nav_create' => ['bool', 'database_name'=>'string', 'name'=>'string'], 'notes_search' => ['array', 'database_name'=>'string', 'keywords'=>'string'], 'notes_unread' => ['array', 'database_name'=>'string', 'user_name'=>'string'], 'notes_version' => ['float', 'database_name'=>'string'], 'nsapi_request_headers' => ['array'], 'nsapi_response_headers' => ['array'], 'nsapi_virtual' => ['bool', 'uri'=>'string'], 'nthmac' => ['string', 'clent'=>'string', 'data'=>'string'], 'number_format' => ['string', 'num'=>'float', 'decimals='=>'int'], 'number_format\'1' => ['string', 'num'=>'float', 'decimals'=>'int', 'decimal_separator'=>'?string', 'thousands_separator'=>'?string'], 'numfmt_create' => ['NumberFormatter|null', 'locale'=>'string', 'style'=>'int', 'pattern='=>'string'], 'numfmt_format' => ['string|false', 'formatter'=>'NumberFormatter', 'num'=>'int|float', 'type='=>'int'], 'numfmt_format_currency' => ['string|false', 'formatter'=>'NumberFormatter', 'amount'=>'float', 'currency'=>'string'], 'numfmt_get_attribute' => ['float|int|false', 'formatter'=>'NumberFormatter', 'attribute'=>'int'], 'numfmt_get_error_code' => ['int', 'formatter'=>'NumberFormatter'], 'numfmt_get_error_message' => ['string', 'formatter'=>'NumberFormatter'], 'numfmt_get_locale' => ['string', 'formatter'=>'NumberFormatter', 'type='=>'int'], 'numfmt_get_pattern' => ['string|false', 'formatter'=>'NumberFormatter'], 'numfmt_get_symbol' => ['string|false', 'formatter'=>'NumberFormatter', 'symbol'=>'int'], 'numfmt_get_text_attribute' => ['string|false', 'formatter'=>'NumberFormatter', 'attribute'=>'int'], 'numfmt_parse' => ['float|int|false', 'formatter'=>'NumberFormatter', 'string'=>'string', 'type='=>'int', '&rw_offset='=>'int'], 'numfmt_parse_currency' => ['float|false', 'formatter'=>'NumberFormatter', 'string'=>'string', '&w_currency'=>'string', '&rw_offset='=>'int'], 'numfmt_set_attribute' => ['bool', 'formatter'=>'NumberFormatter', 'attribute'=>'int', 'value'=>'float|int'], 'numfmt_set_pattern' => ['bool', 'formatter'=>'NumberFormatter', 'pattern'=>'string'], 'numfmt_set_symbol' => ['bool', 'formatter'=>'NumberFormatter', 'symbol'=>'int', 'value'=>'string'], 'numfmt_set_text_attribute' => ['bool', 'formatter'=>'NumberFormatter', 'attribute'=>'int', 'value'=>'string'], 'oauth_get_sbs' => ['string', 'http_method'=>'string', 'uri'=>'string', 'parameters'=>'array'], 'oauth_urlencode' => ['string', 'uri'=>'string'], 'ob_clean' => ['bool'], 'ob_deflatehandler' => ['string', 'data'=>'string', 'mode'=>'int'], 'ob_end_clean' => ['bool'], 'ob_end_flush' => ['bool'], 'ob_etaghandler' => ['string', 'data'=>'string', 'mode'=>'int'], 'ob_flush' => ['bool'], 'ob_get_clean' => ['string|false'], 'ob_get_contents' => ['string|false'], 'ob_get_flush' => ['string|false'], 'ob_get_length' => ['int|false'], 'ob_get_level' => ['int'], 'ob_get_status' => ['array', 'full_status='=>'bool'], 'ob_gzhandler' => ['string|false', 'data'=>'string', 'flags'=>'int'], 'ob_iconv_handler' => ['string', 'contents'=>'string', 'status'=>'int'], 'ob_implicit_flush' => ['void', 'enable='=>'int'], 'ob_inflatehandler' => ['string', 'data'=>'string', 'mode'=>'int'], 'ob_list_handlers' => ['list'], 'ob_start' => ['bool', 'callback='=>'string|array|?callable', 'chunk_size='=>'int', 'flags='=>'int'], 'ob_tidyhandler' => ['string', 'input'=>'string', 'mode='=>'int'], 'oci_bind_array_by_name' => ['bool', 'statement'=>'resource', 'param'=>'string', '&rw_var'=>'array', 'max_array_length'=>'int', 'max_item_length='=>'int', 'type='=>'int'], 'oci_bind_by_name' => ['bool', 'statement'=>'resource', 'param'=>'string', '&rw_var'=>'mixed', 'max_length='=>'int', 'type='=>'int'], 'oci_cancel' => ['bool', 'statement'=>'resource'], 'oci_client_version' => ['string'], 'oci_close' => ['bool', 'connection'=>'resource'], 'oci_collection_append' => ['bool', 'collection'=>'string'], 'oci_collection_assign' => ['bool', 'to'=>'object'], 'oci_collection_element_assign' => ['bool', 'collection'=>'int', 'index'=>'string'], 'oci_collection_element_get' => ['string', 'collection'=>'int'], 'oci_collection_max' => ['int'], 'oci_collection_size' => ['int'], 'oci_collection_trim' => ['bool', 'collection'=>'int'], 'oci_commit' => ['bool', 'connection'=>'resource'], 'oci_connect' => ['resource|false', 'username'=>'string', 'password'=>'string', 'connection_string='=>'string', 'encoding='=>'string', 'session_mode='=>'int'], 'oci_define_by_name' => ['bool', 'statement'=>'resource', 'column'=>'string', '&w_var'=>'mixed', 'type='=>'int'], 'oci_error' => ['array|false', 'connection_or_statement='=>'resource'], 'oci_execute' => ['bool', 'statement'=>'resource', 'mode='=>'int'], 'oci_fetch' => ['bool', 'statement'=>'resource'], 'oci_fetch_all' => ['int|false', 'statement'=>'resource', '&w_output'=>'array', 'offset='=>'int', 'limit='=>'int', 'flags='=>'int'], 'oci_fetch_array' => ['array|false', 'statement'=>'resource', 'mode='=>'int'], 'oci_fetch_assoc' => ['array|false', 'statement'=>'resource'], 'oci_fetch_object' => ['object|false', 'statement'=>'resource'], 'oci_fetch_row' => ['array|false', 'statement'=>'resource'], 'oci_field_is_null' => ['bool', 'statement'=>'resource', 'column'=>'mixed'], 'oci_field_name' => ['string|false', 'statement'=>'resource', 'column'=>'mixed'], 'oci_field_precision' => ['int|false', 'statement'=>'resource', 'column'=>'mixed'], 'oci_field_scale' => ['int|false', 'statement'=>'resource', 'column'=>'mixed'], 'oci_field_size' => ['int|false', 'statement'=>'resource', 'column'=>'mixed'], 'oci_field_type' => ['mixed|false', 'statement'=>'resource', 'column'=>'mixed'], 'oci_field_type_raw' => ['int|false', 'statement'=>'resource', 'column'=>'mixed'], 'oci_free_collection' => ['bool'], 'oci_free_cursor' => ['bool', 'statement'=>'resource'], 'oci_free_descriptor' => ['bool'], 'oci_free_statement' => ['bool', 'statement'=>'resource'], 'oci_get_implicit' => ['bool', 'stmt'=>''], 'oci_get_implicit_resultset' => ['resource|false', 'statement'=>'resource'], 'oci_internal_debug' => ['void', 'onoff'=>'bool'], 'oci_lob_append' => ['bool', 'to'=>'object'], 'oci_lob_close' => ['bool'], 'oci_lob_copy' => ['bool', 'to'=>'OCILob', 'from'=>'OCILob', 'length='=>'int'], 'oci_lob_eof' => ['bool'], 'oci_lob_erase' => ['int', 'lob'=>'int', 'offset'=>'int'], 'oci_lob_export' => ['bool', 'lob'=>'string', 'filename'=>'int', 'offset'=>'int'], 'oci_lob_flush' => ['bool', 'lob'=>'int'], 'oci_lob_import' => ['bool', 'lob'=>'string'], 'oci_lob_is_equal' => ['bool', 'lob1'=>'OCILob', 'lob2'=>'OCILob'], 'oci_lob_load' => ['string'], 'oci_lob_read' => ['string', 'lob'=>'int'], 'oci_lob_rewind' => ['bool'], 'oci_lob_save' => ['bool', 'lob'=>'string', 'data'=>'int'], 'oci_lob_seek' => ['bool', 'lob'=>'int', 'offset'=>'int'], 'oci_lob_size' => ['int'], 'oci_lob_tell' => ['int'], 'oci_lob_truncate' => ['bool', 'lob'=>'int'], 'oci_lob_write' => ['int', 'lob'=>'string', 'data'=>'int'], 'oci_lob_write_temporary' => ['bool', 'value'=>'string', 'lob_type'=>'int'], 'oci_new_collection' => ['OCICollection|false', 'connection'=>'resource', 'type_name'=>'string', 'schema='=>'string'], 'oci_new_connect' => ['resource|false', 'username'=>'string', 'password'=>'string', 'connection_string='=>'string', 'encoding='=>'string', 'session_mode='=>'int'], 'oci_new_cursor' => ['resource|false', 'connection'=>'resource'], 'oci_new_descriptor' => ['OCILob|false', 'connection'=>'resource', 'type='=>'int'], 'oci_num_fields' => ['int|false', 'statement'=>'resource'], 'oci_num_rows' => ['int|false', 'statement'=>'resource'], 'oci_parse' => ['resource|false', 'connection'=>'resource', 'sql'=>'string'], 'oci_password_change' => ['bool', 'connection'=>'resource', 'username'=>'string', 'old_password'=>'string', 'new_password'=>'string'], 'oci_pconnect' => ['resource|false', 'username'=>'string', 'password'=>'string', 'connection_string='=>'string', 'encoding='=>'string', 'session_mode='=>'int'], 'oci_result' => ['mixed|false', 'statement'=>'resource', 'column'=>'mixed'], 'oci_rollback' => ['bool', 'connection'=>'resource'], 'oci_server_version' => ['string|false', 'connection'=>'resource'], 'oci_set_action' => ['bool', 'connection'=>'resource', 'action'=>'string'], 'oci_set_call_timeout' => ['bool', 'connection'=>'resource', 'timeout'=>'int'], 'oci_set_client_identifier' => ['bool', 'connection'=>'resource', 'client_id'=>'string'], 'oci_set_client_info' => ['bool', 'connection'=>'resource', 'client_info'=>'string'], 'oci_set_db_operation' => ['bool', 'connection'=>'resource', 'action'=>'string'], 'oci_set_edition' => ['bool', 'edition'=>'string'], 'oci_set_module_name' => ['bool', 'connection'=>'resource', 'name'=>'string'], 'oci_set_prefetch' => ['bool', 'statement'=>'resource', 'rows'=>'int'], 'oci_statement_type' => ['string|false', 'statement'=>'resource'], 'ocifetchinto' => ['int|bool', 'statement'=>'resource', '&w_result'=>'array', 'mode='=>'int'], 'ocigetbufferinglob' => ['bool'], 'ocisetbufferinglob' => ['bool', 'lob'=>'bool'], 'octdec' => ['int|float', 'octal_string'=>'string'], 'odbc_autocommit' => ['int|bool', 'odbc'=>'resource', 'enable='=>'bool'], 'odbc_binmode' => ['bool', 'statement'=>'resource', 'mode'=>'int'], 'odbc_close' => ['void', 'odbc'=>'resource'], 'odbc_close_all' => ['void'], 'odbc_columnprivileges' => ['resource|false', 'odbc'=>'resource', 'catalog'=>'?string', 'schema'=>'string', 'table'=>'string', 'column'=>'string'], 'odbc_columns' => ['resource|false', 'odbc'=>'resource', 'catalog='=>'?string', 'schema='=>'?string', 'table='=>'?string', 'column='=>'?string'], 'odbc_commit' => ['bool', 'odbc'=>'resource'], 'odbc_connect' => ['resource|false', 'dsn'=>'string', 'user'=>'string', 'password'=>'string', 'cursor_option='=>'int'], 'odbc_cursor' => ['string', 'statement'=>'resource'], 'odbc_data_source' => ['array|false', 'odbc'=>'resource', 'fetch_type'=>'int'], 'odbc_do' => ['resource', 'odbc'=>'resource', 'query'=>'string', 'flags='=>'int'], 'odbc_error' => ['string', 'odbc='=>'resource'], 'odbc_errormsg' => ['string', 'odbc='=>'resource'], 'odbc_exec' => ['resource', 'odbc'=>'resource', 'query'=>'string', 'flags='=>'int'], 'odbc_execute' => ['bool', 'statement'=>'resource', 'params='=>'array'], 'odbc_fetch_array' => ['array|false', 'statement'=>'resource', 'row='=>'int'], 'odbc_fetch_into' => ['int', 'statement'=>'resource', '&w_array'=>'array', 'row='=>'int'], 'odbc_fetch_object' => ['stdClass|false', 'statement'=>'resource', 'row='=>'int'], 'odbc_fetch_row' => ['bool', 'statement'=>'resource', 'row='=>'int'], 'odbc_field_len' => ['int|false', 'statement'=>'resource', 'field'=>'int'], 'odbc_field_name' => ['string|false', 'statement'=>'resource', 'field'=>'int'], 'odbc_field_num' => ['int|false', 'statement'=>'resource', 'field'=>'string'], 'odbc_field_precision' => ['int', 'statement'=>'resource', 'field'=>'int'], 'odbc_field_scale' => ['int|false', 'statement'=>'resource', 'field'=>'int'], 'odbc_field_type' => ['string|false', 'statement'=>'resource', 'field'=>'int'], 'odbc_foreignkeys' => ['resource|false', 'odbc'=>'resource', 'pk_catalog'=>'?string', 'pk_schema'=>'string', 'pk_table'=>'string', 'fk_catalog'=>'string', 'fk_schema'=>'string', 'fk_table'=>'string'], 'odbc_free_result' => ['bool', 'statement'=>'resource'], 'odbc_gettypeinfo' => ['resource', 'odbc'=>'resource', 'data_type='=>'int'], 'odbc_longreadlen' => ['bool', 'statement'=>'resource', 'length'=>'int'], 'odbc_next_result' => ['bool', 'statement'=>'resource'], 'odbc_num_fields' => ['int', 'statement'=>'resource'], 'odbc_num_rows' => ['int', 'statement'=>'resource'], 'odbc_pconnect' => ['resource|false', 'dsn'=>'string', 'user'=>'string', 'password'=>'string', 'cursor_option='=>'int'], 'odbc_prepare' => ['resource|false', 'odbc'=>'resource', 'query'=>'string'], 'odbc_primarykeys' => ['resource|false', 'odbc'=>'resource', 'catalog'=>'?string', 'schema'=>'string', 'table'=>'string'], 'odbc_procedurecolumns' => ['resource|false', 'odbc'=>'resource', 'catalog='=>'?string', 'schema='=>'?string', 'procedure='=>'?string', 'column='=>'?string'], 'odbc_procedures' => ['resource|false', 'odbc'=>'resource', 'catalog='=>'?string', 'schema='=>'?string', 'procedure='=>'?string'], 'odbc_result' => ['string|bool|null', 'statement'=>'resource', 'field'=>'string|int'], 'odbc_result_all' => ['int|false', 'statement'=>'resource', 'format='=>'string'], 'odbc_rollback' => ['bool', 'odbc'=>'resource'], 'odbc_setoption' => ['bool', 'odbc'=>'resource', 'which'=>'int', 'option'=>'int', 'value'=>'int'], 'odbc_specialcolumns' => ['resource|false', 'odbc'=>'resource', 'type'=>'int', 'catalog'=>'?string', 'schema'=>'string', 'table'=>'string', 'scope'=>'int', 'nullable'=>'int'], 'odbc_statistics' => ['resource|false', 'odbc'=>'resource', 'catalog'=>'?string', 'schema'=>'string', 'table'=>'string', 'unique'=>'int', 'accuracy'=>'int'], 'odbc_tableprivileges' => ['resource|false', 'odbc'=>'resource', 'catalog'=>'?string', 'schema'=>'string', 'table'=>'string'], 'odbc_tables' => ['resource|false', 'odbc'=>'resource', 'catalog='=>'?string', 'schema='=>'string', 'table='=>'string', 'types='=>'string'], 'opcache_compile_file' => ['bool', 'filename'=>'string'], 'opcache_get_configuration' => ['array'], 'opcache_get_status' => ['array|false', 'include_scripts='=>'bool'], 'opcache_invalidate' => ['bool', 'filename'=>'string', 'force='=>'bool'], 'opcache_is_script_cached' => ['bool', 'filename'=>'string'], 'opcache_reset' => ['bool'], 'openal_buffer_create' => ['resource'], 'openal_buffer_data' => ['bool', 'buffer'=>'resource', 'format'=>'int', 'data'=>'string', 'freq'=>'int'], 'openal_buffer_destroy' => ['bool', 'buffer'=>'resource'], 'openal_buffer_get' => ['int', 'buffer'=>'resource', 'property'=>'int'], 'openal_buffer_loadwav' => ['bool', 'buffer'=>'resource', 'wavfile'=>'string'], 'openal_context_create' => ['resource', 'device'=>'resource'], 'openal_context_current' => ['bool', 'context'=>'resource'], 'openal_context_destroy' => ['bool', 'context'=>'resource'], 'openal_context_process' => ['bool', 'context'=>'resource'], 'openal_context_suspend' => ['bool', 'context'=>'resource'], 'openal_device_close' => ['bool', 'device'=>'resource'], 'openal_device_open' => ['resource|false', 'device_desc='=>'string'], 'openal_listener_get' => ['mixed', 'property'=>'int'], 'openal_listener_set' => ['bool', 'property'=>'int', 'setting'=>'mixed'], 'openal_source_create' => ['resource'], 'openal_source_destroy' => ['bool', 'source'=>'resource'], 'openal_source_get' => ['mixed', 'source'=>'resource', 'property'=>'int'], 'openal_source_pause' => ['bool', 'source'=>'resource'], 'openal_source_play' => ['bool', 'source'=>'resource'], 'openal_source_rewind' => ['bool', 'source'=>'resource'], 'openal_source_set' => ['bool', 'source'=>'resource', 'property'=>'int', 'setting'=>'mixed'], 'openal_source_stop' => ['bool', 'source'=>'resource'], 'openal_stream' => ['resource', 'source'=>'resource', 'format'=>'int', 'rate'=>'int'], 'opendir' => ['resource|false', 'directory'=>'string', 'context='=>'resource'], 'openlog' => ['true', 'prefix'=>'string', 'flags'=>'int', 'facility'=>'int'], 'openssl_cipher_iv_length' => ['int|false', 'cipher_algo'=>'string'], 'openssl_csr_export' => ['bool', 'csr'=>'string|resource', '&w_output'=>'string', 'no_text='=>'bool'], 'openssl_csr_export_to_file' => ['bool', 'csr'=>'string|resource', 'output_filename'=>'string', 'no_text='=>'bool'], 'openssl_csr_get_public_key' => ['resource|false', 'csr'=>'string|resource', 'short_names='=>'bool'], 'openssl_csr_get_subject' => ['array|false', 'csr'=>'string|resource', 'short_names='=>'bool'], 'openssl_csr_new' => ['resource|false', 'distinguished_names'=>'array', '&w_private_key'=>'resource', 'options='=>'array', 'extra_attributes='=>'array'], 'openssl_csr_sign' => ['resource|false', 'csr'=>'string|resource', 'ca_certificate'=>'string|resource|null', 'private_key'=>'string|resource|array', 'days'=>'int', 'options='=>'array', 'serial='=>'int'], 'openssl_decrypt' => ['string|false', 'data'=>'string', 'cipher_algo'=>'string', 'passphrase'=>'string', 'options='=>'int', 'iv='=>'string', 'tag='=>'string', 'aad='=>'string'], 'openssl_dh_compute_key' => ['string|false', 'public_key'=>'string', 'private_key'=>'resource'], 'openssl_digest' => ['string|false', 'data'=>'string', 'digest_algo'=>'string', 'binary='=>'bool'], 'openssl_encrypt' => ['string|false', 'data'=>'string', 'cipher_algo'=>'string', 'passphrase'=>'string', 'options='=>'int', 'iv='=>'string', '&w_tag='=>'string', 'aad='=>'string', 'tag_length='=>'int'], 'openssl_error_string' => ['string|false'], 'openssl_free_key' => ['void', 'key'=>'resource'], 'openssl_get_cert_locations' => ['array'], 'openssl_get_cipher_methods' => ['array', 'aliases='=>'bool'], 'openssl_get_md_methods' => ['array', 'aliases='=>'bool'], 'openssl_get_privatekey' => ['resource|false', 'private_key'=>'string', 'passphrase='=>'string'], 'openssl_get_publickey' => ['resource|false', 'public_key'=>'resource|string'], 'openssl_open' => ['bool', 'data'=>'string', '&w_output'=>'string', 'encrypted_key'=>'string', 'private_key'=>'string|array|resource', 'cipher_algo='=>'string', 'iv='=>'string'], 'openssl_pbkdf2' => ['string|false', 'password'=>'string', 'salt'=>'string', 'key_length'=>'int', 'iterations'=>'int', 'digest_algo='=>'string'], 'openssl_pkcs12_export' => ['bool', 'certificate'=>'string|resource', '&w_output'=>'string', 'private_key'=>'string|array|resource', 'passphrase'=>'string', 'options='=>'array'], 'openssl_pkcs12_export_to_file' => ['bool', 'certificate'=>'string|resource', 'output_filename'=>'string', 'private_key'=>'string|array|resource', 'passphrase'=>'string', 'options='=>'array'], 'openssl_pkcs12_read' => ['bool', 'pkcs12'=>'string', '&w_certificates'=>'array', 'passphrase'=>'string'], 'openssl_pkcs7_decrypt' => ['bool', 'input_filename'=>'string', 'output_filename'=>'string', 'certificate'=>'string|resource', 'private_key='=>'string|resource|array'], 'openssl_pkcs7_encrypt' => ['bool', 'input_filename'=>'string', 'output_filename'=>'string', 'certificate'=>'string|resource|array', 'headers'=>'array', 'flags='=>'int', 'cipher_algo='=>'int'], 'openssl_pkcs7_read' => ['bool', 'data'=>'string', '&w_certificates'=>'array'], 'openssl_pkcs7_sign' => ['bool', 'input_filename'=>'string', 'output_filename'=>'string', 'certificate'=>'string|resource', 'private_key'=>'string|resource|array', 'headers'=>'array', 'flags='=>'int', 'untrusted_certificates_filename='=>'string'], 'openssl_pkcs7_verify' => ['bool|int', 'input_filename'=>'string', 'flags'=>'int', 'signers_certificates_filename='=>'string', 'ca_info='=>'array', 'untrusted_certificates_filename='=>'string', 'content='=>'string', 'output_filename='=>'string'], 'openssl_pkey_export' => ['bool', 'key'=>'resource', '&w_output'=>'string', 'passphrase='=>'string|null', 'options='=>'array'], 'openssl_pkey_export_to_file' => ['bool', 'key'=>'resource|string|array', 'output_filename'=>'string', 'passphrase='=>'string|null', 'options='=>'array'], 'openssl_pkey_free' => ['void', 'key'=>'resource'], 'openssl_pkey_get_details' => ['array|false', 'key'=>'resource'], 'openssl_pkey_get_private' => ['resource|false', 'private_key'=>'string', 'passphrase='=>'string'], 'openssl_pkey_get_public' => ['resource|false', 'public_key'=>'resource|string'], 'openssl_pkey_new' => ['resource|false', 'options='=>'array'], 'openssl_private_decrypt' => ['bool', 'data'=>'string', '&w_decrypted_data'=>'string', 'private_key'=>'string|resource|array', 'padding='=>'int'], 'openssl_private_encrypt' => ['bool', 'data'=>'string', '&w_encrypted_data'=>'string', 'private_key'=>'string|resource|array', 'padding='=>'int'], 'openssl_public_decrypt' => ['bool', 'data'=>'string', '&w_decrypted_data'=>'string', 'public_key'=>'string|resource', 'padding='=>'int'], 'openssl_public_encrypt' => ['bool', 'data'=>'string', '&w_encrypted_data'=>'string', 'public_key'=>'string|resource', 'padding='=>'int'], 'openssl_random_pseudo_bytes' => ['string|false', 'length'=>'int', '&w_strong_result='=>'bool'], 'openssl_seal' => ['int|false', 'data'=>'string', '&w_sealed_data'=>'string', '&w_encrypted_keys'=>'array', 'public_key'=>'array', 'cipher_algo='=>'string', '&rw_iv='=>'string'], 'openssl_sign' => ['bool', 'data'=>'string', '&w_signature'=>'string', 'private_key'=>'resource|string', 'algorithm='=>'int|string'], 'openssl_spki_export' => ['string|false', 'spki'=>'string'], 'openssl_spki_export_challenge' => ['string|false', 'spki'=>'string'], 'openssl_spki_new' => ['?string', 'private_key'=>'resource', 'challenge'=>'string', 'digest_algo='=>'int'], 'openssl_spki_verify' => ['bool', 'spki'=>'string'], 'openssl_verify' => ['-1|0|1', 'data'=>'string', 'signature'=>'string', 'public_key'=>'resource|string', 'algorithm='=>'int|string'], 'openssl_x509_check_private_key' => ['bool', 'certificate'=>'string|resource', 'private_key'=>'string|resource|array'], 'openssl_x509_checkpurpose' => ['bool|int', 'certificate'=>'string|resource', 'purpose'=>'int', 'ca_info='=>'array', 'untrusted_certificates_file='=>'string'], 'openssl_x509_export' => ['bool', 'certificate'=>'string|resource', '&w_output'=>'string', 'no_text='=>'bool'], 'openssl_x509_export_to_file' => ['bool', 'certificate'=>'string|resource', 'output_filename'=>'string', 'no_text='=>'bool'], 'openssl_x509_fingerprint' => ['string|false', 'certificate'=>'string|resource', 'digest_algo='=>'string', 'binary='=>'bool'], 'openssl_x509_free' => ['void', 'certificate'=>'resource'], 'openssl_x509_parse' => ['array|false', 'certificate'=>'string|resource', 'short_names='=>'bool'], 'openssl_x509_read' => ['resource|false', 'certificate'=>'string|resource'], 'ord' => ['int<0,255>', 'character'=>'string'], 'output_add_rewrite_var' => ['bool', 'name'=>'string', 'value'=>'string'], 'output_cache_disable' => ['void'], 'output_cache_disable_compression' => ['void'], 'output_cache_exists' => ['bool', 'key'=>'string', 'lifetime'=>'int'], 'output_cache_fetch' => ['string', 'key'=>'string', 'function'=>'', 'lifetime'=>'int'], 'output_cache_get' => ['mixed|false', 'key'=>'string', 'lifetime'=>'int'], 'output_cache_output' => ['string', 'key'=>'string', 'function'=>'', 'lifetime'=>'int'], 'output_cache_put' => ['bool', 'key'=>'string', 'data'=>'mixed'], 'output_cache_remove' => ['bool', 'filename'=>''], 'output_cache_remove_key' => ['bool', 'key'=>'string'], 'output_cache_remove_url' => ['bool', 'url'=>'string'], 'output_cache_stop' => ['void'], 'output_reset_rewrite_vars' => ['bool'], 'outputformatObj::getOption' => ['string', 'property_name'=>'string'], 'outputformatObj::set' => ['int', 'property_name'=>'string', 'new_value'=>''], 'outputformatObj::setOption' => ['void', 'property_name'=>'string', 'new_value'=>'string'], 'outputformatObj::validate' => ['int'], 'overload' => ['', 'class_name'=>'string'], 'override_function' => ['bool', 'function_name'=>'string', 'function_args'=>'string', 'function_code'=>'string'], 'pack' => ['string|false', 'format'=>'string', '...values='=>'mixed'], 'parallel\Future::done' => ['bool'], 'parallel\Future::select' => ['mixed', '&resolving'=>'parallel\Future[]', '&w_resolved'=>'parallel\Future[]', '&w_errored'=>'parallel\Future[]', '&w_timedout='=>'parallel\Future[]', 'timeout='=>'int'], 'parallel\Future::value' => ['mixed', 'timeout='=>'int'], 'parallel\Runtime::__construct' => ['void', 'arg'=>'string|array'], 'parallel\Runtime::__construct\'1' => ['void', 'bootstrap'=>'string', 'configuration'=>'array'], 'parallel\Runtime::close' => ['void'], 'parallel\Runtime::kill' => ['void'], 'parallel\Runtime::run' => ['?parallel\Future', 'closure'=>'Closure', 'args='=>'array'], 'parle\rlexer::insertMacro' => ['void', 'name'=>'string', 'regex'=>'string'], 'parse_ini_file' => ['array|false', 'filename'=>'string', 'process_sections='=>'bool', 'scanner_mode='=>'int'], 'parse_ini_string' => ['array|false', 'ini_string'=>'string', 'process_sections='=>'bool', 'scanner_mode='=>'int'], 'parse_str' => ['void', 'string'=>'string', '&w_result='=>'array'], 'parse_url' => ['int|string|array|null|false', 'url'=>'string', 'component='=>'int'], 'parsekit_compile_file' => ['array', 'filename'=>'string', 'errors='=>'array', 'options='=>'int'], 'parsekit_compile_string' => ['array', 'phpcode'=>'string', 'errors='=>'array', 'options='=>'int'], 'parsekit_func_arginfo' => ['array', 'function'=>'mixed'], 'passthru' => ['void', 'command'=>'string', '&w_result_code='=>'int'], 'password_get_info' => ['array', 'hash'=>'string'], 'password_hash' => ['string|false', 'password'=>'string', 'algo'=>'int', 'options='=>'array'], 'password_make_salt' => ['bool', 'password'=>'string', 'hash'=>'string'], 'password_needs_rehash' => ['bool', 'hash'=>'string', 'algo'=>'int', 'options='=>'array'], 'password_verify' => ['bool', 'password'=>'string', 'hash'=>'string'], 'pathinfo' => ['array|string', 'path'=>'string', 'flags='=>'int'], 'pclose' => ['int', 'handle'=>'resource'], 'pcnlt_sigwaitinfo' => ['int', 'set'=>'array', '&w_siginfo'=>'array'], 'pcntl_alarm' => ['int', 'seconds'=>'int'], 'pcntl_errno' => ['int'], 'pcntl_exec' => ['null|false', 'path'=>'string', 'args='=>'array', 'env_vars='=>'array'], 'pcntl_fork' => ['int'], 'pcntl_get_last_error' => ['int'], 'pcntl_getpriority' => ['int', 'process_id='=>'int', 'mode='=>'int'], 'pcntl_setpriority' => ['bool', 'priority'=>'int', 'process_id='=>'int', 'mode='=>'int'], 'pcntl_signal' => ['bool', 'signal'=>'int', 'handler'=>'callable():void|callable(int):void|callable(int,array):void|int', 'restart_syscalls='=>'bool'], 'pcntl_signal_dispatch' => ['bool'], 'pcntl_sigprocmask' => ['bool', 'mode'=>'int', 'signals'=>'array', '&w_old_signals='=>'array'], 'pcntl_sigtimedwait' => ['int', 'signals'=>'array', '&w_info='=>'array', 'seconds='=>'int', 'nanoseconds='=>'int'], 'pcntl_sigwaitinfo' => ['int', 'signals'=>'array', '&w_info='=>'array'], 'pcntl_strerror' => ['string', 'error_code'=>'int'], 'pcntl_wait' => ['int', '&w_status'=>'int', 'flags='=>'int', '&w_resource_usage='=>'array'], 'pcntl_waitpid' => ['int', 'process_id'=>'int', '&w_status'=>'int', 'flags='=>'int', '&w_resource_usage='=>'array'], 'pcntl_wexitstatus' => ['int', 'status'=>'int'], 'pcntl_wifcontinued' => ['bool', 'status'=>'int'], 'pcntl_wifexited' => ['bool', 'status'=>'int'], 'pcntl_wifsignaled' => ['bool', 'status'=>'int'], 'pcntl_wifstopped' => ['bool', 'status'=>'int'], 'pcntl_wstopsig' => ['int', 'status'=>'int'], 'pcntl_wtermsig' => ['int', 'status'=>'int'], 'pdo_drivers' => ['array'], 'pfsockopen' => ['resource|false', 'hostname'=>'string', 'port='=>'int', '&w_error_code='=>'int', '&w_error_message='=>'string', 'timeout='=>'float'], 'pg_affected_rows' => ['int', 'result'=>'resource'], 'pg_cancel_query' => ['bool', 'connection'=>'resource'], 'pg_client_encoding' => ['string', 'connection='=>'resource'], 'pg_close' => ['bool', 'connection='=>'resource'], 'pg_connect' => ['resource|false', 'connection_string'=>'string', 'flags='=>'int'], 'pg_connect_poll' => ['int', 'connection'=>'resource'], 'pg_connection_busy' => ['bool', 'connection'=>'resource'], 'pg_connection_reset' => ['bool', 'connection'=>'resource'], 'pg_connection_status' => ['int', 'connection'=>'resource'], 'pg_consume_input' => ['bool', 'connection'=>'resource'], 'pg_convert' => ['array|false', 'connection'=>'resource', 'table_name'=>'string', 'values'=>'array', 'flags='=>'int'], 'pg_copy_from' => ['bool', 'connection'=>'resource', 'table_name'=>'string', 'rows'=>'array', 'separator='=>'string', 'null_as='=>'string'], 'pg_copy_to' => ['array|false', 'connection'=>'resource', 'table_name'=>'string', 'separator='=>'string', 'null_as='=>'string'], 'pg_dbname' => ['string', 'connection='=>'resource'], 'pg_delete' => ['string|bool', 'connection'=>'resource', 'table_name'=>'string', 'conditions'=>'array', 'flags='=>'int'], 'pg_end_copy' => ['bool', 'connection='=>'resource'], 'pg_escape_bytea' => ['string', 'connection'=>'resource', 'string'=>'string'], 'pg_escape_bytea\'1' => ['string', 'connection'=>'string'], 'pg_escape_identifier' => ['string|false', 'connection'=>'resource', 'string'=>'string'], 'pg_escape_identifier\'1' => ['string|false', 'connection'=>'string'], 'pg_escape_literal' => ['string|false', 'connection'=>'resource', 'string'=>'string'], 'pg_escape_literal\'1' => ['string|false', 'connection'=>'string'], 'pg_escape_string' => ['string', 'connection'=>'resource', 'string'=>'string'], 'pg_escape_string\'1' => ['string', 'connection'=>'string'], 'pg_exec' => ['resource|false', 'connection'=>'resource', 'query'=>'string'], 'pg_exec\'1' => ['resource|false', 'connection'=>'string'], 'pg_execute' => ['resource|false', 'connection'=>'resource', 'statement_name'=>'string', 'params'=>'array'], 'pg_execute\'1' => ['resource|false', 'connection'=>'string', 'statement_name'=>'array'], 'pg_fetch_all' => ['array', 'result'=>'resource'], 'pg_fetch_all_columns' => ['array', 'result'=>'resource', 'field='=>'int'], 'pg_fetch_array' => ['array|false', 'result'=>'resource', 'row='=>'?int', 'mode='=>'int'], 'pg_fetch_assoc' => ['array|false', 'result'=>'resource', 'row='=>'?int'], 'pg_fetch_object' => ['object|false', 'result'=>'resource', 'row='=>'?int', 'class='=>'string', 'constructor_args='=>'array'], 'pg_fetch_result' => ['string|false|null', 'result'=>'resource', 'row'=>'string|int'], 'pg_fetch_result\'1' => ['string|false|null', 'result'=>'resource', 'row'=>'?int', 'field'=>'string|int'], 'pg_fetch_row' => ['array|false', 'result'=>'resource', 'row='=>'?int', 'mode='=>'int'], 'pg_field_is_null' => ['int|false', 'result'=>'resource', 'row'=>'string|int'], 'pg_field_is_null\'1' => ['int|false', 'result'=>'resource', 'row'=>'int', 'field'=>'string|int'], 'pg_field_name' => ['string', 'result'=>'resource', 'field'=>'int'], 'pg_field_num' => ['int', 'result'=>'resource', 'field'=>'string'], 'pg_field_prtlen' => ['int|false', 'result'=>'resource', 'row'=>'string|int'], 'pg_field_prtlen\'1' => ['int|false', 'result'=>'resource', 'row'=>'int', 'field'=>'string|int'], 'pg_field_size' => ['int', 'result'=>'resource', 'field'=>'int'], 'pg_field_table' => ['string|int|false', 'result'=>'resource', 'field'=>'int', 'oid_only='=>'bool'], 'pg_field_type' => ['string', 'result'=>'resource', 'field'=>'int'], 'pg_field_type_oid' => ['int|string', 'result'=>'resource', 'field'=>'int'], 'pg_flush' => ['int|bool', 'connection'=>'resource'], 'pg_free_result' => ['bool', 'result'=>'resource'], 'pg_get_notify' => ['array|false', 'connection'=>'resource', 'mode='=>'int'], 'pg_get_pid' => ['int', 'connection'=>'resource'], 'pg_get_result' => ['resource|false', 'connection'=>'resource'], 'pg_host' => ['string', 'connection='=>'resource'], 'pg_insert' => ['resource|string|false', 'connection'=>'resource', 'table_name'=>'string', 'values'=>'array', 'flags='=>'int'], 'pg_last_error' => ['string', 'connection='=>'resource'], 'pg_last_notice' => ['string|array|bool', 'connection'=>'resource', 'mode='=>'int'], 'pg_last_oid' => ['string|int|false', 'result'=>'resource'], 'pg_lo_close' => ['bool', 'lob'=>'resource'], 'pg_lo_create' => ['int|string|false', 'connection='=>'resource', 'oid='=>'int|string'], 'pg_lo_export' => ['bool', 'connection'=>'resource', 'oid'=>'int|string', 'filename'=>'string'], 'pg_lo_export\'1' => ['bool', 'connection'=>'int|string', 'oid'=>'string'], 'pg_lo_import' => ['int|string|false', 'connection'=>'resource', 'filename'=>'string', 'oid'=>'string|int'], 'pg_lo_import\'1' => ['int|string|false', 'connection'=>'string', 'filename'=>'string|int'], 'pg_lo_open' => ['resource|false', 'connection'=>'resource', 'oid'=>'int|string', 'mode'=>'string'], 'pg_lo_open\'1' => ['resource|false', 'connection'=>'int|string', 'oid'=>'string'], 'pg_lo_read' => ['string|false', 'lob'=>'resource', 'length='=>'int'], 'pg_lo_read_all' => ['int', 'lob'=>'resource'], 'pg_lo_seek' => ['bool', 'lob'=>'resource', 'offset'=>'int', 'whence='=>'int'], 'pg_lo_tell' => ['int', 'lob'=>'resource'], 'pg_lo_truncate' => ['bool', 'lob'=>'resource', 'size'=>'int'], 'pg_lo_unlink' => ['bool', 'connection'=>'resource', 'oid'=>'int|string'], 'pg_lo_unlink\'1' => ['bool', 'connection'=>'int|string'], 'pg_lo_write' => ['int|false', 'lob'=>'resource', 'data'=>'string', 'length='=>'int'], 'pg_meta_data' => ['array|false', 'connection'=>'resource', 'table_name'=>'string', 'extended='=>'bool'], 'pg_num_fields' => ['int', 'result'=>'resource'], 'pg_num_rows' => ['int', 'result'=>'resource'], 'pg_options' => ['string', 'connection='=>'resource'], 'pg_parameter_status' => ['string|false', 'connection'=>'resource', 'name'=>'string'], 'pg_parameter_status\'1' => ['string|false', 'connection'=>'string'], 'pg_pconnect' => ['resource|false', 'connection_string'=>'string', 'flags='=>'int'], 'pg_ping' => ['bool', 'connection='=>'resource'], 'pg_port' => ['string', 'connection='=>'resource'], 'pg_prepare' => ['resource|false', 'connection'=>'resource', 'statement_name'=>'string', 'query'=>'string'], 'pg_prepare\'1' => ['resource|false', 'connection'=>'string', 'statement_name'=>'string'], 'pg_put_line' => ['bool', 'connection'=>'resource', 'data'=>'string'], 'pg_put_line\'1' => ['bool', 'connection'=>'string'], 'pg_query' => ['resource|false', 'connection'=>'resource', 'query'=>'string'], 'pg_query\'1' => ['resource|false', 'connection'=>'string'], 'pg_query_params' => ['resource|false', 'connection'=>'resource', 'query'=>'string', 'params'=>'array'], 'pg_query_params\'1' => ['resource|false', 'connection'=>'string', 'query'=>'array'], 'pg_result_error' => ['string|false', 'result'=>'resource'], 'pg_result_error_field' => ['string|false|null', 'result'=>'resource', 'field_code'=>'int'], 'pg_result_seek' => ['bool', 'result'=>'resource', 'row'=>'int'], 'pg_result_status' => ['string|int', 'result'=>'resource', 'mode='=>'int'], 'pg_select' => ['string|array|false', 'connection'=>'resource', 'table_name'=>'string', 'conditions'=>'array', 'flags='=>'int'], 'pg_send_execute' => ['bool|int', 'connection'=>'resource', 'statement_name'=>'string', 'params'=>'array'], 'pg_send_prepare' => ['bool|int', 'connection'=>'resource', 'statement_name'=>'string', 'query'=>'string'], 'pg_send_query' => ['bool|int', 'connection'=>'resource', 'query'=>'string'], 'pg_send_query_params' => ['bool|int', 'connection'=>'resource', 'query'=>'string', 'params'=>'array'], 'pg_set_client_encoding' => ['int', 'connection'=>'resource', 'encoding'=>'string'], 'pg_set_client_encoding\'1' => ['int', 'connection'=>'string'], 'pg_set_error_verbosity' => ['int|false', 'connection'=>'resource', 'verbosity'=>'int'], 'pg_set_error_verbosity\'1' => ['int|false', 'connection'=>'int'], 'pg_socket' => ['resource|false', 'connection'=>'resource'], 'pg_trace' => ['bool', 'filename'=>'string', 'mode='=>'string', 'connection='=>'resource'], 'pg_transaction_status' => ['int', 'connection'=>'resource'], 'pg_tty' => ['string', 'connection='=>'resource'], 'pg_unescape_bytea' => ['string', 'string'=>'string'], 'pg_untrace' => ['bool', 'connection='=>'resource'], 'pg_update' => ['string|bool', 'connection'=>'resource', 'table_name'=>'string', 'values'=>'array', 'conditions'=>'array', 'flags='=>'int'], 'pg_version' => ['array', 'connection='=>'resource'], 'phdfs::__construct' => ['void', 'ip'=>'string', 'port'=>'string'], 'phdfs::__destruct' => ['void'], 'phdfs::connect' => ['bool'], 'phdfs::copy' => ['bool', 'source_file'=>'string', 'destination_file'=>'string'], 'phdfs::create_directory' => ['bool', 'path'=>'string'], 'phdfs::delete' => ['bool', 'path'=>'string'], 'phdfs::disconnect' => ['bool'], 'phdfs::exists' => ['bool', 'path'=>'string'], 'phdfs::file_info' => ['array', 'path'=>'string'], 'phdfs::list_directory' => ['array', 'path'=>'string'], 'phdfs::read' => ['string', 'path'=>'string', 'length='=>'string'], 'phdfs::rename' => ['bool', 'old_path'=>'string', 'new_path'=>'string'], 'phdfs::tell' => ['int', 'path'=>'string'], 'phdfs::write' => ['bool', 'path'=>'string', 'buffer'=>'string', 'mode='=>'string'], 'php_check_syntax' => ['bool', 'filename'=>'string', 'error_message='=>'string'], 'php_ini_loaded_file' => ['string|false'], 'php_ini_scanned_files' => ['string|false'], 'php_logo_guid' => ['string'], 'php_sapi_name' => ['string'], 'php_strip_whitespace' => ['string', 'filename'=>'string'], 'php_uname' => ['string', 'mode='=>'string'], 'php_user_filter::filter' => ['int', 'in'=>'resource', 'out'=>'resource', '&rw_consumed'=>'int', 'closing'=>'bool'], 'php_user_filter::onClose' => ['void'], 'php_user_filter::onCreate' => ['bool'], 'phpcredits' => ['true', 'flags='=>'int'], 'phpdbg_break_file' => ['void', 'file'=>'string', 'line'=>'int'], 'phpdbg_break_function' => ['void', 'function'=>'string'], 'phpdbg_break_method' => ['void', 'class'=>'string', 'method'=>'string'], 'phpdbg_break_next' => ['void'], 'phpdbg_clear' => ['void'], 'phpdbg_color' => ['void', 'element'=>'int', 'color'=>'string'], 'phpdbg_end_oplog' => ['array', 'options='=>'array'], 'phpdbg_exec' => ['mixed', 'context='=>'string'], 'phpdbg_get_executable' => ['array', 'options='=>'array'], 'phpdbg_prompt' => ['void', 'string'=>'string'], 'phpdbg_start_oplog' => ['void'], 'phpinfo' => ['true', 'flags='=>'int'], 'phpversion' => ['string|false', 'extension='=>'string'], 'pht\AtomicInteger::__construct' => ['void', 'value='=>'int'], 'pht\AtomicInteger::dec' => ['void'], 'pht\AtomicInteger::get' => ['int'], 'pht\AtomicInteger::inc' => ['void'], 'pht\AtomicInteger::lock' => ['void'], 'pht\AtomicInteger::set' => ['void', 'value'=>'int'], 'pht\AtomicInteger::unlock' => ['void'], 'pht\HashTable::lock' => ['void'], 'pht\HashTable::size' => ['int'], 'pht\HashTable::unlock' => ['void'], 'pht\Queue::front' => ['mixed'], 'pht\Queue::lock' => ['void'], 'pht\Queue::pop' => ['mixed'], 'pht\Queue::push' => ['void', 'value'=>'mixed'], 'pht\Queue::size' => ['int'], 'pht\Queue::unlock' => ['void'], 'pht\Runnable::run' => ['void'], 'pht\Vector::__construct' => ['void', 'size='=>'int', 'value='=>'mixed'], 'pht\Vector::deleteAt' => ['void', 'offset'=>'int'], 'pht\Vector::insertAt' => ['void', 'value'=>'mixed', 'offset'=>'int'], 'pht\Vector::lock' => ['void'], 'pht\Vector::pop' => ['mixed'], 'pht\Vector::push' => ['void', 'value'=>'mixed'], 'pht\Vector::resize' => ['void', 'size'=>'int', 'value='=>'mixed'], 'pht\Vector::shift' => ['mixed'], 'pht\Vector::size' => ['int'], 'pht\Vector::unlock' => ['void'], 'pht\Vector::unshift' => ['void', 'value'=>'mixed'], 'pht\Vector::updateAt' => ['void', 'value'=>'mixed', 'offset'=>'int'], 'pht\thread::addClassTask' => ['void', 'className'=>'string', '...ctorArgs='=>'mixed'], 'pht\thread::addFileTask' => ['void', 'fileName'=>'string', '...globals='=>'mixed'], 'pht\thread::addFunctionTask' => ['void', 'func'=>'callable', '...funcArgs='=>'mixed'], 'pht\thread::join' => ['void'], 'pht\thread::start' => ['void'], 'pht\thread::taskCount' => ['int'], 'pht\threaded::lock' => ['void'], 'pht\threaded::unlock' => ['void'], 'pi' => ['float'], 'png2wbmp' => ['bool', 'pngname'=>'string', 'wbmpname'=>'string', 'dest_height'=>'int', 'dest_width'=>'int', 'threshold'=>'int'], 'pointObj::__construct' => ['void'], 'pointObj::distanceToLine' => ['float', 'p1'=>'pointObj', 'p2'=>'pointObj'], 'pointObj::distanceToPoint' => ['float', 'poPoint'=>'pointObj'], 'pointObj::distanceToShape' => ['float', 'shape'=>'shapeObj'], 'pointObj::draw' => ['int', 'map'=>'mapObj', 'layer'=>'layerObj', 'img'=>'imageObj', 'class_index'=>'int', 'text'=>'string'], 'pointObj::ms_newPointObj' => ['pointObj'], 'pointObj::project' => ['int', 'in'=>'projectionObj', 'out'=>'projectionObj'], 'pointObj::setXY' => ['int', 'x'=>'float', 'y'=>'float', 'm'=>'float'], 'pointObj::setXYZ' => ['int', 'x'=>'float', 'y'=>'float', 'z'=>'float', 'm'=>'float'], 'popen' => ['resource|false', 'command'=>'string', 'mode'=>'string'], 'pos' => ['mixed', 'array'=>'array'], 'posix_access' => ['bool', 'filename'=>'string', 'flags='=>'int'], 'posix_ctermid' => ['string|false'], 'posix_errno' => ['int'], 'posix_get_last_error' => ['int'], 'posix_getcwd' => ['string|false'], 'posix_getegid' => ['int'], 'posix_geteuid' => ['int'], 'posix_getgid' => ['int'], 'posix_getgrgid' => ['array{name: string, passwd: string, gid: int, members: list}|false', 'group_id'=>'int'], 'posix_getgrnam' => ['array{name: string, passwd: string, gid: int, members: list}|false', 'name'=>'string'], 'posix_getgroups' => ['list|false'], 'posix_getlogin' => ['string|false'], 'posix_getpgid' => ['int|false', 'process_id'=>'int'], 'posix_getpgrp' => ['int'], 'posix_getpid' => ['int'], 'posix_getppid' => ['int'], 'posix_getpwnam' => ['array{name: string, passwd: string, uid: int, gid: int, gecos: string, dir: string, shell: string}|false', 'username'=>'string'], 'posix_getpwuid' => ['array{name: string, passwd: string, uid: int, gid: int, gecos: string, dir: string, shell: string}|false', 'user_id'=>'int'], 'posix_getrlimit' => ['array{"soft core": string, "hard core": string, "soft data": string, "hard data": string, "soft stack": integer, "hard stack": string, "soft totalmem": string, "hard totalmem": string, "soft rss": string, "hard rss": string, "soft maxproc": integer, "hard maxproc": integer, "soft memlock": integer, "hard memlock": integer, "soft cpu": string, "hard cpu": string, "soft filesize": string, "hard filesize": string, "soft openfiles": integer, "hard openfiles": integer}|false'], 'posix_getsid' => ['int|false', 'process_id'=>'int'], 'posix_getuid' => ['int'], 'posix_initgroups' => ['bool', 'username'=>'string', 'group_id'=>'int'], 'posix_isatty' => ['bool', 'file_descriptor'=>'resource|int'], 'posix_kill' => ['bool', 'process_id'=>'int', 'signal'=>'int'], 'posix_mkfifo' => ['bool', 'filename'=>'string', 'permissions'=>'int'], 'posix_mknod' => ['bool', 'filename'=>'string', 'flags'=>'int', 'major='=>'int', 'minor='=>'int'], 'posix_setegid' => ['bool', 'group_id'=>'int'], 'posix_seteuid' => ['bool', 'user_id'=>'int'], 'posix_setgid' => ['bool', 'group_id'=>'int'], 'posix_setpgid' => ['bool', 'process_id'=>'int', 'process_group_id'=>'int'], 'posix_setrlimit' => ['bool', 'resource'=>'int', 'soft_limit'=>'int', 'hard_limit'=>'int'], 'posix_setsid' => ['int'], 'posix_setuid' => ['bool', 'user_id'=>'int'], 'posix_strerror' => ['string', 'error_code'=>'int'], 'posix_times' => ['array{ticks: int, utime: int, stime: int, cutime: int, cstime: int}|false'], 'posix_ttyname' => ['string|false', 'file_descriptor'=>'resource|int'], 'posix_uname' => ['array{sysname: string, nodename: string, release: string, version: string, machine: string, domainname: string}|false'], 'pow' => ['float|int', 'num'=>'int|float', 'exponent'=>'int|float'], 'preg_filter' => ['string|string[]|null', 'pattern'=>'string|string[]', 'replacement'=>'string|string[]', 'subject'=>'string|string[]', 'limit='=>'int', '&w_count='=>'int'], 'preg_grep' => ['array|false', 'pattern'=>'string', 'array'=>'array', 'flags='=>'int'], 'preg_last_error' => ['int'], 'preg_match' => ['0|1|false', 'pattern'=>'string', 'subject'=>'string', '&w_matches='=>'string[]', 'flags='=>'0', 'offset='=>'int'], 'preg_match\'1' => ['0|1|false', 'pattern'=>'string', 'subject'=>'string', '&w_matches='=>'array', 'flags='=>'int', 'offset='=>'int'], 'preg_match_all' => ['int<0,max>|false', 'pattern'=>'string', 'subject'=>'string', '&w_matches='=>'array', 'flags='=>'int', 'offset='=>'int'], 'preg_quote' => ['string', 'str'=>'string', 'delimiter='=>'string'], 'preg_replace' => ['string|string[]|null', 'pattern'=>'string|array', 'replacement'=>'string|array', 'subject'=>'string|array', 'limit='=>'int', '&w_count='=>'int'], 'preg_replace_callback' => ['string|null', 'pattern'=>'string|array', 'callback'=>'callable(string[]):string', 'subject'=>'string', 'limit='=>'int', '&w_count='=>'int'], 'preg_replace_callback\'1' => ['string[]|null', 'pattern'=>'string|array', 'callback'=>'callable(string[]):string', 'subject'=>'string[]', 'limit='=>'int', '&w_count='=>'int'], 'preg_replace_callback_array' => ['string|null', 'pattern'=>'array', 'subject'=>'string', 'limit='=>'int', '&w_count='=>'int'], 'preg_replace_callback_array\'1' => ['string[]|null', 'pattern'=>'array', 'subject'=>'string[]', 'limit='=>'int', '&w_count='=>'int'], 'preg_split' => ['list|false', 'pattern'=>'string', 'subject'=>'string', 'limit'=>'int', 'flags='=>'null'], 'preg_split\'1' => ['list|list>|false', 'pattern'=>'string', 'subject'=>'string', 'limit='=>'int', 'flags='=>'int'], 'prev' => ['mixed', '&r_array'=>'array|object'], 'print' => ['int', 'arg'=>'string'], 'print_r' => ['string', 'value'=>'mixed'], 'print_r\'1' => ['true', 'value'=>'mixed', 'return='=>'bool'], 'printf' => ['int<0, max>', 'format'=>'string', '...values='=>'string|int|float'], 'proc_close' => ['int', 'process'=>'resource'], 'proc_get_status' => ['array{command: string, pid: int, running: bool, signaled: bool, stopped: bool, exitcode: int, termsig: int, stopsig: int}|false', 'process'=>'resource'], 'proc_nice' => ['bool', 'priority'=>'int'], 'proc_open' => ['resource|false', 'command'=>'string', 'descriptor_spec'=>'array', '&pipes'=>'resource[]', 'cwd='=>'?string', 'env_vars='=>'?array', 'options='=>'?array'], 'proc_terminate' => ['bool', 'process'=>'resource', 'signal='=>'int'], 'projectionObj::__construct' => ['void', 'projectionString'=>'string'], 'projectionObj::getUnits' => ['int'], 'projectionObj::ms_newProjectionObj' => ['projectionObj', 'projectionString'=>'string'], 'property_exists' => ['bool', 'object_or_class'=>'object|string', 'property'=>'string'], 'ps_add_bookmark' => ['int', 'psdoc'=>'resource', 'text'=>'string', 'parent='=>'int', 'open='=>'int'], 'ps_add_launchlink' => ['bool', 'psdoc'=>'resource', 'llx'=>'float', 'lly'=>'float', 'urx'=>'float', 'ury'=>'float', 'filename'=>'string'], 'ps_add_locallink' => ['bool', 'psdoc'=>'resource', 'llx'=>'float', 'lly'=>'float', 'urx'=>'float', 'ury'=>'float', 'page'=>'int', 'dest'=>'string'], 'ps_add_note' => ['bool', 'psdoc'=>'resource', 'llx'=>'float', 'lly'=>'float', 'urx'=>'float', 'ury'=>'float', 'contents'=>'string', 'title'=>'string', 'icon'=>'string', 'open'=>'int'], 'ps_add_pdflink' => ['bool', 'psdoc'=>'resource', 'llx'=>'float', 'lly'=>'float', 'urx'=>'float', 'ury'=>'float', 'filename'=>'string', 'page'=>'int', 'dest'=>'string'], 'ps_add_weblink' => ['bool', 'psdoc'=>'resource', 'llx'=>'float', 'lly'=>'float', 'urx'=>'float', 'ury'=>'float', 'url'=>'string'], 'ps_arc' => ['bool', 'psdoc'=>'resource', 'x'=>'float', 'y'=>'float', 'radius'=>'float', 'alpha'=>'float', 'beta'=>'float'], 'ps_arcn' => ['bool', 'psdoc'=>'resource', 'x'=>'float', 'y'=>'float', 'radius'=>'float', 'alpha'=>'float', 'beta'=>'float'], 'ps_begin_page' => ['bool', 'psdoc'=>'resource', 'width'=>'float', 'height'=>'float'], 'ps_begin_pattern' => ['int', 'psdoc'=>'resource', 'width'=>'float', 'height'=>'float', 'xstep'=>'float', 'ystep'=>'float', 'painttype'=>'int'], 'ps_begin_template' => ['int', 'psdoc'=>'resource', 'width'=>'float', 'height'=>'float'], 'ps_circle' => ['bool', 'psdoc'=>'resource', 'x'=>'float', 'y'=>'float', 'radius'=>'float'], 'ps_clip' => ['bool', 'psdoc'=>'resource'], 'ps_close' => ['bool', 'psdoc'=>'resource'], 'ps_close_image' => ['void', 'psdoc'=>'resource', 'imageid'=>'int'], 'ps_closepath' => ['bool', 'psdoc'=>'resource'], 'ps_closepath_stroke' => ['bool', 'psdoc'=>'resource'], 'ps_continue_text' => ['bool', 'psdoc'=>'resource', 'text'=>'string'], 'ps_curveto' => ['bool', 'psdoc'=>'resource', 'x1'=>'float', 'y1'=>'float', 'x2'=>'float', 'y2'=>'float', 'x3'=>'float', 'y3'=>'float'], 'ps_delete' => ['bool', 'psdoc'=>'resource'], 'ps_end_page' => ['bool', 'psdoc'=>'resource'], 'ps_end_pattern' => ['bool', 'psdoc'=>'resource'], 'ps_end_template' => ['bool', 'psdoc'=>'resource'], 'ps_fill' => ['bool', 'psdoc'=>'resource'], 'ps_fill_stroke' => ['bool', 'psdoc'=>'resource'], 'ps_findfont' => ['int', 'psdoc'=>'resource', 'fontname'=>'string', 'encoding'=>'string', 'embed='=>'bool'], 'ps_get_buffer' => ['string', 'psdoc'=>'resource'], 'ps_get_parameter' => ['string', 'psdoc'=>'resource', 'name'=>'string', 'modifier='=>'float'], 'ps_get_value' => ['float', 'psdoc'=>'resource', 'name'=>'string', 'modifier='=>'float'], 'ps_hyphenate' => ['array', 'psdoc'=>'resource', 'text'=>'string'], 'ps_include_file' => ['bool', 'psdoc'=>'resource', 'file'=>'string'], 'ps_lineto' => ['bool', 'psdoc'=>'resource', 'x'=>'float', 'y'=>'float'], 'ps_makespotcolor' => ['int', 'psdoc'=>'resource', 'name'=>'string', 'reserved='=>'int'], 'ps_moveto' => ['bool', 'psdoc'=>'resource', 'x'=>'float', 'y'=>'float'], 'ps_new' => ['resource'], 'ps_open_file' => ['bool', 'psdoc'=>'resource', 'filename='=>'string'], 'ps_open_image' => ['int', 'psdoc'=>'resource', 'type'=>'string', 'source'=>'string', 'data'=>'string', 'length'=>'int', 'width'=>'int', 'height'=>'int', 'components'=>'int', 'bpc'=>'int', 'params'=>'string'], 'ps_open_image_file' => ['int', 'psdoc'=>'resource', 'type'=>'string', 'filename'=>'string', 'stringparam='=>'string', 'intparam='=>'int'], 'ps_open_memory_image' => ['int', 'psdoc'=>'resource', 'gd'=>'int'], 'ps_place_image' => ['bool', 'psdoc'=>'resource', 'imageid'=>'int', 'x'=>'float', 'y'=>'float', 'scale'=>'float'], 'ps_rect' => ['bool', 'psdoc'=>'resource', 'x'=>'float', 'y'=>'float', 'width'=>'float', 'height'=>'float'], 'ps_restore' => ['bool', 'psdoc'=>'resource'], 'ps_rotate' => ['bool', 'psdoc'=>'resource', 'rot'=>'float'], 'ps_save' => ['bool', 'psdoc'=>'resource'], 'ps_scale' => ['bool', 'psdoc'=>'resource', 'x'=>'float', 'y'=>'float'], 'ps_set_border_color' => ['bool', 'psdoc'=>'resource', 'red'=>'float', 'green'=>'float', 'blue'=>'float'], 'ps_set_border_dash' => ['bool', 'psdoc'=>'resource', 'black'=>'float', 'white'=>'float'], 'ps_set_border_style' => ['bool', 'psdoc'=>'resource', 'style'=>'string', 'width'=>'float'], 'ps_set_info' => ['bool', 'p'=>'resource', 'key'=>'string', 'value'=>'string'], 'ps_set_parameter' => ['bool', 'psdoc'=>'resource', 'name'=>'string', 'value'=>'string'], 'ps_set_text_pos' => ['bool', 'psdoc'=>'resource', 'x'=>'float', 'y'=>'float'], 'ps_set_value' => ['bool', 'psdoc'=>'resource', 'name'=>'string', 'value'=>'float'], 'ps_setcolor' => ['bool', 'psdoc'=>'resource', 'type'=>'string', 'colorspace'=>'string', 'c1'=>'float', 'c2'=>'float', 'c3'=>'float', 'c4'=>'float'], 'ps_setdash' => ['bool', 'psdoc'=>'resource', 'on'=>'float', 'off'=>'float'], 'ps_setflat' => ['bool', 'psdoc'=>'resource', 'value'=>'float'], 'ps_setfont' => ['bool', 'psdoc'=>'resource', 'fontid'=>'int', 'size'=>'float'], 'ps_setgray' => ['bool', 'psdoc'=>'resource', 'gray'=>'float'], 'ps_setlinecap' => ['bool', 'psdoc'=>'resource', 'type'=>'int'], 'ps_setlinejoin' => ['bool', 'psdoc'=>'resource', 'type'=>'int'], 'ps_setlinewidth' => ['bool', 'psdoc'=>'resource', 'width'=>'float'], 'ps_setmiterlimit' => ['bool', 'psdoc'=>'resource', 'value'=>'float'], 'ps_setoverprintmode' => ['bool', 'psdoc'=>'resource', 'mode'=>'int'], 'ps_setpolydash' => ['bool', 'psdoc'=>'resource', 'arr'=>'float'], 'ps_shading' => ['int', 'psdoc'=>'resource', 'type'=>'string', 'x0'=>'float', 'y0'=>'float', 'x1'=>'float', 'y1'=>'float', 'c1'=>'float', 'c2'=>'float', 'c3'=>'float', 'c4'=>'float', 'optlist'=>'string'], 'ps_shading_pattern' => ['int', 'psdoc'=>'resource', 'shadingid'=>'int', 'optlist'=>'string'], 'ps_shfill' => ['bool', 'psdoc'=>'resource', 'shadingid'=>'int'], 'ps_show' => ['bool', 'psdoc'=>'resource', 'text'=>'string'], 'ps_show2' => ['bool', 'psdoc'=>'resource', 'text'=>'string', 'length'=>'int'], 'ps_show_boxed' => ['int', 'psdoc'=>'resource', 'text'=>'string', 'left'=>'float', 'bottom'=>'float', 'width'=>'float', 'height'=>'float', 'hmode'=>'string', 'feature='=>'string'], 'ps_show_xy' => ['bool', 'psdoc'=>'resource', 'text'=>'string', 'x'=>'float', 'y'=>'float'], 'ps_show_xy2' => ['bool', 'psdoc'=>'resource', 'text'=>'string', 'length'=>'int', 'xcoor'=>'float', 'ycoor'=>'float'], 'ps_string_geometry' => ['array', 'psdoc'=>'resource', 'text'=>'string', 'fontid='=>'int', 'size='=>'float'], 'ps_stringwidth' => ['float', 'psdoc'=>'resource', 'text'=>'string', 'fontid='=>'int', 'size='=>'float'], 'ps_stroke' => ['bool', 'psdoc'=>'resource'], 'ps_symbol' => ['bool', 'psdoc'=>'resource', 'ord'=>'int'], 'ps_symbol_name' => ['string', 'psdoc'=>'resource', 'ord'=>'int', 'fontid='=>'int'], 'ps_symbol_width' => ['float', 'psdoc'=>'resource', 'ord'=>'int', 'fontid='=>'int', 'size='=>'float'], 'ps_translate' => ['bool', 'psdoc'=>'resource', 'x'=>'float', 'y'=>'float'], 'pspell_add_to_personal' => ['bool', 'dictionary'=>'int', 'word'=>'string'], 'pspell_add_to_session' => ['bool', 'dictionary'=>'int', 'word'=>'string'], 'pspell_check' => ['bool', 'dictionary'=>'int', 'word'=>'string'], 'pspell_clear_session' => ['bool', 'dictionary'=>'int'], 'pspell_config_create' => ['int', 'language'=>'string', 'spelling='=>'string', 'jargon='=>'string', 'encoding='=>'string'], 'pspell_config_data_dir' => ['bool', 'config'=>'int', 'directory'=>'string'], 'pspell_config_dict_dir' => ['bool', 'config'=>'int', 'directory'=>'string'], 'pspell_config_ignore' => ['bool', 'config'=>'int', 'min_length'=>'int'], 'pspell_config_mode' => ['bool', 'config'=>'int', 'mode'=>'int'], 'pspell_config_personal' => ['bool', 'config'=>'int', 'filename'=>'string'], 'pspell_config_repl' => ['bool', 'config'=>'int', 'filename'=>'string'], 'pspell_config_runtogether' => ['bool', 'config'=>'int', 'allow'=>'bool'], 'pspell_config_save_repl' => ['bool', 'config'=>'int', 'save'=>'bool'], 'pspell_new' => ['int|false', 'language'=>'string', 'spelling='=>'string', 'jargon='=>'string', 'encoding='=>'string', 'mode='=>'int'], 'pspell_new_config' => ['int|false', 'config'=>'int'], 'pspell_new_personal' => ['int|false', 'filename'=>'string', 'language'=>'string', 'spelling='=>'string', 'jargon='=>'string', 'encoding='=>'string', 'mode='=>'int'], 'pspell_save_wordlist' => ['bool', 'dictionary'=>'int'], 'pspell_store_replacement' => ['bool', 'dictionary'=>'int', 'misspelled'=>'string', 'correct'=>'string'], 'pspell_suggest' => ['array', 'dictionary'=>'int', 'word'=>'string'], 'putenv' => ['bool', 'assignment'=>'string'], 'px_close' => ['bool', 'pxdoc'=>'resource'], 'px_create_fp' => ['bool', 'pxdoc'=>'resource', 'file'=>'resource', 'fielddesc'=>'array'], 'px_date2string' => ['string', 'pxdoc'=>'resource', 'value'=>'int', 'format'=>'string'], 'px_delete' => ['bool', 'pxdoc'=>'resource'], 'px_delete_record' => ['bool', 'pxdoc'=>'resource', 'num'=>'int'], 'px_get_field' => ['array', 'pxdoc'=>'resource', 'fieldno'=>'int'], 'px_get_info' => ['array', 'pxdoc'=>'resource'], 'px_get_parameter' => ['string', 'pxdoc'=>'resource', 'name'=>'string'], 'px_get_record' => ['array', 'pxdoc'=>'resource', 'num'=>'int', 'mode='=>'int'], 'px_get_schema' => ['array', 'pxdoc'=>'resource', 'mode='=>'int'], 'px_get_value' => ['float', 'pxdoc'=>'resource', 'name'=>'string'], 'px_insert_record' => ['int', 'pxdoc'=>'resource', 'data'=>'array'], 'px_new' => ['resource'], 'px_numfields' => ['int', 'pxdoc'=>'resource'], 'px_numrecords' => ['int', 'pxdoc'=>'resource'], 'px_open_fp' => ['bool', 'pxdoc'=>'resource', 'file'=>'resource'], 'px_put_record' => ['bool', 'pxdoc'=>'resource', 'record'=>'array', 'recpos='=>'int'], 'px_retrieve_record' => ['array', 'pxdoc'=>'resource', 'num'=>'int', 'mode='=>'int'], 'px_set_blob_file' => ['bool', 'pxdoc'=>'resource', 'filename'=>'string'], 'px_set_parameter' => ['bool', 'pxdoc'=>'resource', 'name'=>'string', 'value'=>'string'], 'px_set_tablename' => ['void', 'pxdoc'=>'resource', 'name'=>'string'], 'px_set_targetencoding' => ['bool', 'pxdoc'=>'resource', 'encoding'=>'string'], 'px_set_value' => ['bool', 'pxdoc'=>'resource', 'name'=>'string', 'value'=>'float'], 'px_timestamp2string' => ['string', 'pxdoc'=>'resource', 'value'=>'float', 'format'=>'string'], 'px_update_record' => ['bool', 'pxdoc'=>'resource', 'data'=>'array', 'num'=>'int'], 'qdom_error' => ['string'], 'qdom_tree' => ['QDomDocument', 'doc'=>'string'], 'querymapObj::convertToString' => ['string'], 'querymapObj::free' => ['void'], 'querymapObj::set' => ['int', 'property_name'=>'string', 'new_value'=>''], 'querymapObj::updateFromString' => ['int', 'snippet'=>'string'], 'quoted_printable_decode' => ['string', 'string'=>'string'], 'quoted_printable_encode' => ['string', 'string'=>'string'], 'quotemeta' => ['string', 'string'=>'string'], 'rad2deg' => ['float', 'num'=>'float'], 'radius_acct_open' => ['resource|false'], 'radius_add_server' => ['bool', 'radius_handle'=>'resource', 'hostname'=>'string', 'port'=>'int', 'secret'=>'string', 'timeout'=>'int', 'max_tries'=>'int'], 'radius_auth_open' => ['resource|false'], 'radius_close' => ['bool', 'radius_handle'=>'resource'], 'radius_config' => ['bool', 'radius_handle'=>'resource', 'file'=>'string'], 'radius_create_request' => ['bool', 'radius_handle'=>'resource', 'type'=>'int'], 'radius_cvt_addr' => ['string', 'data'=>'string'], 'radius_cvt_int' => ['int', 'data'=>'string'], 'radius_cvt_string' => ['string', 'data'=>'string'], 'radius_demangle' => ['string', 'radius_handle'=>'resource', 'mangled'=>'string'], 'radius_demangle_mppe_key' => ['string', 'radius_handle'=>'resource', 'mangled'=>'string'], 'radius_get_attr' => ['mixed', 'radius_handle'=>'resource'], 'radius_get_tagged_attr_data' => ['string', 'data'=>'string'], 'radius_get_tagged_attr_tag' => ['int', 'data'=>'string'], 'radius_get_vendor_attr' => ['array', 'data'=>'string'], 'radius_put_addr' => ['bool', 'radius_handle'=>'resource', 'type'=>'int', 'addr'=>'string'], 'radius_put_attr' => ['bool', 'radius_handle'=>'resource', 'type'=>'int', 'value'=>'string'], 'radius_put_int' => ['bool', 'radius_handle'=>'resource', 'type'=>'int', 'value'=>'int'], 'radius_put_string' => ['bool', 'radius_handle'=>'resource', 'type'=>'int', 'value'=>'string'], 'radius_put_vendor_addr' => ['bool', 'radius_handle'=>'resource', 'vendor'=>'int', 'type'=>'int', 'addr'=>'string'], 'radius_put_vendor_attr' => ['bool', 'radius_handle'=>'resource', 'vendor'=>'int', 'type'=>'int', 'value'=>'string'], 'radius_put_vendor_int' => ['bool', 'radius_handle'=>'resource', 'vendor'=>'int', 'type'=>'int', 'value'=>'int'], 'radius_put_vendor_string' => ['bool', 'radius_handle'=>'resource', 'vendor'=>'int', 'type'=>'int', 'value'=>'string'], 'radius_request_authenticator' => ['string', 'radius_handle'=>'resource'], 'radius_salt_encrypt_attr' => ['string', 'radius_handle'=>'resource', 'data'=>'string'], 'radius_send_request' => ['int|false', 'radius_handle'=>'resource'], 'radius_server_secret' => ['string', 'radius_handle'=>'resource'], 'radius_strerror' => ['string', 'radius_handle'=>'resource'], 'rand' => ['int', 'min'=>'int', 'max'=>'int'], 'rand\'1' => ['int'], 'random_bytes' => ['non-empty-string', 'length'=>'positive-int'], 'random_int' => ['int', 'min'=>'int', 'max'=>'int'], 'range' => ['non-empty-array', 'start'=>'string|int|float', 'end'=>'string|int|float', 'step='=>'int<1, max>|float'], 'rar_allow_broken_set' => ['bool', 'rarfile'=>'RarArchive', 'allow_broken'=>'bool'], 'rar_broken_is' => ['bool', 'rarfile'=>'rararchive'], 'rar_close' => ['bool', 'rarfile'=>'rararchive'], 'rar_comment_get' => ['string', 'rarfile'=>'rararchive'], 'rar_entry_get' => ['RarEntry', 'rarfile'=>'RarArchive', 'entryname'=>'string'], 'rar_list' => ['RarArchive', 'rarfile'=>'rararchive'], 'rar_open' => ['RarArchive', 'filename'=>'string', 'password='=>'string', 'volume_callback='=>'callable'], 'rar_solid_is' => ['bool', 'rarfile'=>'rararchive'], 'rar_wrapper_cache_stats' => ['string'], 'rawurldecode' => ['string', 'string'=>'string'], 'rawurlencode' => ['string', 'string'=>'string'], 'read_exif_data' => ['array', 'filename'=>'string', 'sections_needed='=>'string', 'sub_arrays='=>'bool', 'read_thumbnail='=>'bool'], 'readdir' => ['string|false', 'dir_handle='=>'resource'], 'readfile' => ['int|false', 'filename'=>'string', 'use_include_path='=>'bool', 'context='=>'resource'], 'readgzfile' => ['int|false', 'filename'=>'string', 'use_include_path='=>'int'], 'readline' => ['string|false', 'prompt='=>'?string'], 'readline_add_history' => ['bool', 'prompt'=>'string'], 'readline_callback_handler_install' => ['bool', 'prompt'=>'string', 'callback'=>'callable'], 'readline_callback_handler_remove' => ['bool'], 'readline_callback_read_char' => ['void'], 'readline_clear_history' => ['bool'], 'readline_completion_function' => ['bool', 'callback'=>'callable'], 'readline_info' => ['mixed', 'var_name='=>'string', 'value='=>'string|int|bool'], 'readline_list_history' => ['array'], 'readline_on_new_line' => ['void'], 'readline_read_history' => ['bool', 'filename='=>'string'], 'readline_redisplay' => ['void'], 'readline_write_history' => ['bool', 'filename='=>'string'], 'readlink' => ['non-falsy-string|false', 'path'=>'string'], 'realpath' => ['non-falsy-string|false', 'path'=>'string'], 'realpath_cache_get' => ['array'], 'realpath_cache_size' => ['int'], 'recode' => ['string', 'request'=>'string', 'string'=>'string'], 'recode_file' => ['bool', 'request'=>'string', 'input'=>'resource', 'output'=>'resource'], 'recode_string' => ['string|false', 'request'=>'string', 'string'=>'string'], 'rectObj::__construct' => ['void'], 'rectObj::draw' => ['int', 'map'=>'mapObj', 'layer'=>'layerObj', 'img'=>'imageObj', 'class_index'=>'int', 'text'=>'string'], 'rectObj::fit' => ['float', 'width'=>'int', 'height'=>'int'], 'rectObj::ms_newRectObj' => ['rectObj'], 'rectObj::project' => ['int', 'in'=>'projectionObj', 'out'=>'projectionObj'], 'rectObj::set' => ['int', 'property_name'=>'string', 'new_value'=>''], 'rectObj::setextent' => ['void', 'minx'=>'float', 'miny'=>'float', 'maxx'=>'float', 'maxy'=>'float'], 'register_event_handler' => ['bool', 'event_handler_func'=>'string', 'handler_register_name'=>'string', 'event_type_mask'=>'int'], 'register_shutdown_function' => ['void', 'callback'=>'callable', '...args='=>'mixed'], 'register_tick_function' => ['bool', 'callback'=>'callable():void', '...args='=>'mixed'], 'rename' => ['bool', 'from'=>'string', 'to'=>'string', 'context='=>'resource'], 'rename_function' => ['bool', 'original_name'=>'string', 'new_name'=>'string'], 'reset' => ['mixed|false', '&r_array'=>'array|object'], 'resourcebundle_count' => ['int', 'bundle'=>'ResourceBundle'], 'resourcebundle_create' => ['?ResourceBundle', 'locale'=>'?string', 'bundle'=>'?string', 'fallback='=>'bool'], 'resourcebundle_get' => ['mixed|null', 'bundle'=>'ResourceBundle', 'index'=>'string|int', 'fallback='=>'bool'], 'resourcebundle_get_error_code' => ['int', 'bundle'=>'ResourceBundle'], 'resourcebundle_get_error_message' => ['string', 'bundle'=>'ResourceBundle'], 'resourcebundle_locales' => ['array', 'bundle'=>'string'], 'restore_error_handler' => ['true'], 'restore_exception_handler' => ['true'], 'restore_include_path' => ['void'], 'rewind' => ['bool', 'stream'=>'resource'], 'rewinddir' => ['void', 'dir_handle='=>'resource'], 'rmdir' => ['bool', 'directory'=>'string', 'context='=>'resource'], 'round' => ['float', 'num'=>'float|int', 'precision='=>'int', 'mode='=>'0|positive-int'], 'rpm_close' => ['bool', 'rpmr'=>'resource'], 'rpm_get_tag' => ['mixed', 'rpmr'=>'resource', 'tagnum'=>'int'], 'rpm_is_valid' => ['bool', 'filename'=>'string'], 'rpm_open' => ['resource|false', 'filename'=>'string'], 'rpm_version' => ['string'], 'rpmaddtag' => ['bool', 'tag'=>'int'], 'rpmdbinfo' => ['array', 'nevr'=>'string', 'full='=>'bool'], 'rpmdbsearch' => ['array', 'pattern'=>'string', 'rpmtag='=>'int', 'rpmmire='=>'int', 'full='=>'bool'], 'rpminfo' => ['array', 'path'=>'string', 'full='=>'bool', 'error='=>'string'], 'rpmvercmp' => ['int', 'evr1'=>'string', 'evr2'=>'string'], 'rrd_create' => ['bool', 'filename'=>'string', 'options'=>'array'], 'rrd_disconnect' => ['void'], 'rrd_error' => ['string'], 'rrd_fetch' => ['array', 'filename'=>'string', 'options'=>'array'], 'rrd_first' => ['int|false', 'file'=>'string', 'raaindex='=>'int'], 'rrd_graph' => ['array|false', 'filename'=>'string', 'options'=>'array'], 'rrd_info' => ['array|false', 'filename'=>'string'], 'rrd_last' => ['int', 'filename'=>'string'], 'rrd_lastupdate' => ['array|false', 'filename'=>'string'], 'rrd_restore' => ['bool', 'xml_file'=>'string', 'rrd_file'=>'string', 'options='=>'array'], 'rrd_tune' => ['bool', 'filename'=>'string', 'options'=>'array'], 'rrd_update' => ['bool', 'filename'=>'string', 'options'=>'array'], 'rrd_version' => ['string'], 'rrd_xport' => ['array|false', 'options'=>'array'], 'rrdc_disconnect' => ['void'], 'rsort' => ['bool', '&rw_array'=>'array', 'flags='=>'int'], 'rtrim' => ['string', 'string'=>'string', 'characters='=>'string'], 'runkit7_constant_add' => ['bool', 'constant_name'=>'string', 'value'=>'mixed', 'new_visibility='=>'int'], 'runkit7_constant_redefine' => ['bool', 'constant_name'=>'string', 'value'=>'mixed', 'new_visibility='=>'?int'], 'runkit7_constant_remove' => ['bool', 'constant_name'=>'string'], 'runkit7_function_add' => ['bool', 'function_name'=>'string', 'argument_list_or_closure'=>'Closure|string', 'code_or_doc_comment='=>'?string', 'return_by_reference='=>'?bool', 'doc_comment='=>'?string', 'return_type='=>'?string', 'is_strict='=>'?bool'], 'runkit7_function_copy' => ['bool', 'source_name'=>'string', 'target_name'=>'string'], 'runkit7_function_redefine' => ['bool', 'function_name'=>'string', 'argument_list_or_closure'=>'Closure|string', 'code_or_doc_comment='=>'?string', 'return_by_reference='=>'?bool', 'doc_comment='=>'?string', 'return_type='=>'?string', 'is_strict='=>'?bool'], 'runkit7_function_remove' => ['bool', 'function_name'=>'string'], 'runkit7_function_rename' => ['bool', 'source_name'=>'string', 'target_name'=>'string'], 'runkit7_import' => ['bool', 'filename'=>'string', 'flags='=>'?int'], 'runkit7_method_add' => ['bool', 'class_name'=>'string', 'method_name'=>'string', 'argument_list_or_closure'=>'Closure|string', 'code_or_flags='=>'int|null|string', 'flags_or_doc_comment='=>'int|null|string', 'doc_comment='=>'?string', 'return_type='=>'?string', 'is_strict='=>'?bool'], 'runkit7_method_copy' => ['bool', 'destination_class'=>'string', 'destination_method'=>'string', 'source_class'=>'string', 'source_method='=>'?string'], 'runkit7_method_redefine' => ['bool', 'class_name'=>'string', 'method_name'=>'string', 'argument_list_or_closure'=>'Closure|string', 'code_or_flags='=>'int|null|string', 'flags_or_doc_comment='=>'int|null|string', 'doc_comment='=>'?string', 'return_type='=>'?string', 'is_strict='=>'?bool'], 'runkit7_method_remove' => ['bool', 'class_name'=>'string', 'method_name'=>'string'], 'runkit7_method_rename' => ['bool', 'class_name'=>'string', 'source_method_name'=>'string', 'source_target_name'=>'string'], 'runkit7_superglobals' => ['array'], 'runkit7_zval_inspect' => ['array', 'value'=>'mixed'], 'runkit_class_adopt' => ['bool', 'classname'=>'string', 'parentname'=>'string'], 'runkit_class_emancipate' => ['bool', 'classname'=>'string'], 'runkit_constant_add' => ['bool', 'constname'=>'string', 'value'=>'mixed'], 'runkit_constant_redefine' => ['bool', 'constname'=>'string', 'newvalue'=>'mixed'], 'runkit_constant_remove' => ['bool', 'constname'=>'string'], 'runkit_function_add' => ['bool', 'funcname'=>'string', 'arglist'=>'string', 'code'=>'string', 'doccomment='=>'?string'], 'runkit_function_add\'1' => ['bool', 'funcname'=>'string', 'closure'=>'Closure', 'doccomment='=>'?string'], 'runkit_function_copy' => ['bool', 'funcname'=>'string', 'targetname'=>'string'], 'runkit_function_redefine' => ['bool', 'funcname'=>'string', 'arglist'=>'string', 'code'=>'string', 'doccomment='=>'?string'], 'runkit_function_redefine\'1' => ['bool', 'funcname'=>'string', 'closure'=>'Closure', 'doccomment='=>'?string'], 'runkit_function_remove' => ['bool', 'funcname'=>'string'], 'runkit_function_rename' => ['bool', 'funcname'=>'string', 'newname'=>'string'], 'runkit_import' => ['bool', 'filename'=>'string', 'flags='=>'int'], 'runkit_lint' => ['bool', 'code'=>'string'], 'runkit_lint_file' => ['bool', 'filename'=>'string'], 'runkit_method_add' => ['bool', 'classname'=>'string', 'methodname'=>'string', 'args'=>'string', 'code'=>'string', 'flags='=>'int', 'doccomment='=>'?string'], 'runkit_method_add\'1' => ['bool', 'classname'=>'string', 'methodname'=>'string', 'closure'=>'Closure', 'flags='=>'int', 'doccomment='=>'?string'], 'runkit_method_copy' => ['bool', 'dclass'=>'string', 'dmethod'=>'string', 'sclass'=>'string', 'smethod='=>'string'], 'runkit_method_redefine' => ['bool', 'classname'=>'string', 'methodname'=>'string', 'args'=>'string', 'code'=>'string', 'flags='=>'int', 'doccomment='=>'?string'], 'runkit_method_redefine\'1' => ['bool', 'classname'=>'string', 'methodname'=>'string', 'closure'=>'Closure', 'flags='=>'int', 'doccomment='=>'?string'], 'runkit_method_remove' => ['bool', 'classname'=>'string', 'methodname'=>'string'], 'runkit_method_rename' => ['bool', 'classname'=>'string', 'methodname'=>'string', 'newname'=>'string'], 'runkit_return_value_used' => ['bool'], 'runkit_sandbox_output_handler' => ['mixed', 'sandbox'=>'object', 'callback='=>'mixed'], 'runkit_superglobals' => ['array'], 'runkit_zval_inspect' => ['array', 'value'=>'mixed'], 'scalebarObj::convertToString' => ['string'], 'scalebarObj::free' => ['void'], 'scalebarObj::set' => ['int', 'property_name'=>'string', 'new_value'=>''], 'scalebarObj::setImageColor' => ['int', 'red'=>'int', 'green'=>'int', 'blue'=>'int'], 'scalebarObj::updateFromString' => ['int', 'snippet'=>'string'], 'scandir' => ['list|false', 'directory'=>'string', 'sorting_order='=>'int', 'context='=>'resource'], 'seaslog_get_author' => ['string'], 'seaslog_get_version' => ['string'], 'sem_acquire' => ['bool', 'semaphore'=>'resource', 'non_blocking='=>'bool'], 'sem_get' => ['resource|false', 'key'=>'int', 'max_acquire='=>'int', 'permissions='=>'int', 'auto_release='=>'bool'], 'sem_release' => ['bool', 'semaphore'=>'resource'], 'sem_remove' => ['bool', 'semaphore'=>'resource'], 'serialize' => ['string', 'value'=>'mixed'], 'session_abort' => ['bool'], 'session_cache_expire' => ['int|false', 'value='=>'int'], 'session_cache_limiter' => ['string|false', 'value='=>'string'], 'session_commit' => ['bool'], 'session_decode' => ['bool', 'data'=>'string'], 'session_destroy' => ['bool'], 'session_encode' => ['string|false'], 'session_get_cookie_params' => ['array{lifetime:?int,path:?string,domain:?string,secure:?bool,httponly:?bool}'], 'session_id' => ['string|false', 'id='=>'string'], 'session_is_registered' => ['bool', 'name'=>'string'], 'session_module_name' => ['string|false', 'module='=>'string'], 'session_name' => ['string|false', 'name='=>'string'], 'session_pgsql_add_error' => ['bool', 'error_level'=>'int', 'error_message='=>'string'], 'session_pgsql_get_error' => ['array', 'with_error_message='=>'bool'], 'session_pgsql_get_field' => ['string'], 'session_pgsql_reset' => ['bool'], 'session_pgsql_set_field' => ['bool', 'value'=>'string'], 'session_pgsql_status' => ['array'], 'session_regenerate_id' => ['bool', 'delete_old_session='=>'bool'], 'session_register' => ['bool', 'name'=>'mixed', '...args='=>'mixed'], 'session_register_shutdown' => ['void'], 'session_reset' => ['bool'], 'session_save_path' => ['string|false', 'path='=>'string'], 'session_set_cookie_params' => ['bool', 'lifetime'=>'int', 'path='=>'string', 'domain='=>'string', 'secure='=>'bool', 'httponly='=>'bool'], 'session_set_save_handler' => ['bool', 'open'=>'callable(string,string):bool', 'close'=>'callable():bool', 'read'=>'callable(string):string', 'write'=>'callable(string,string):bool', 'destroy'=>'callable(string):bool', 'gc'=>'callable(string):bool', 'create_sid='=>'callable():string', 'validate_sid='=>'callable(string):bool', 'update_timestamp='=>'callable(string):bool'], 'session_set_save_handler\'1' => ['bool', 'open'=>'SessionHandlerInterface', 'close='=>'bool'], 'session_start' => ['bool', 'options='=>'array'], 'session_status' => ['int'], 'session_unregister' => ['bool', 'name'=>'string'], 'session_unset' => ['bool'], 'session_write_close' => ['bool'], 'setLeftFill' => ['void', 'red'=>'int', 'green'=>'int', 'blue'=>'int', 'a='=>'int'], 'setLine' => ['void', 'width'=>'int', 'red'=>'int', 'green'=>'int', 'blue'=>'int', 'a='=>'int'], 'setRightFill' => ['void', 'red'=>'int', 'green'=>'int', 'blue'=>'int', 'a='=>'int'], 'set_error_handler' => ['null|callable(int,string,string=,int=,array=):bool', 'callback'=>'null|callable(int,string,string=,int=,array=):bool', 'error_levels='=>'int'], 'set_exception_handler' => ['null|callable(Throwable):void', 'callback'=>'null|callable(Throwable):void'], 'set_file_buffer' => ['int', 'stream'=>'resource', 'size'=>'int'], 'set_include_path' => ['string|false', 'include_path'=>'string'], 'set_magic_quotes_runtime' => ['bool', 'new_setting'=>'bool'], 'set_time_limit' => ['bool', 'seconds'=>'int'], 'setcookie' => ['bool', 'name'=>'string', 'value='=>'string', 'expires='=>'int', 'path='=>'string', 'domain='=>'string', 'secure='=>'bool', 'httponly='=>'bool', 'samesite='=>'string', 'url_encode='=>'int'], 'setlocale' => ['string|false', 'category'=>'int', 'locales'=>'string|0|null', '...rest='=>'string'], 'setlocale\'1' => ['string|false', 'category'=>'int', 'locales'=>'?array'], 'setproctitle' => ['void', 'title'=>'string'], 'setrawcookie' => ['bool', 'name'=>'string', 'value='=>'string', 'expires='=>'int', 'path='=>'string', 'domain='=>'string', 'secure='=>'bool', 'httponly='=>'bool'], 'setthreadtitle' => ['bool', 'title'=>'string'], 'settype' => ['bool', '&rw_var'=>'mixed', 'type'=>'string'], 'sha1' => ['string', 'string'=>'string', 'binary='=>'bool'], 'sha1_file' => ['string|false', 'filename'=>'string', 'binary='=>'bool'], 'sha256' => ['string', 'string'=>'string', 'raw_output='=>'bool'], 'sha256_file' => ['string', 'filename'=>'string', 'raw_output='=>'bool'], 'shapeObj::__construct' => ['void', 'type'=>'int'], 'shapeObj::add' => ['int', 'line'=>'lineObj'], 'shapeObj::boundary' => ['shapeObj'], 'shapeObj::contains' => ['bool', 'point'=>'pointObj'], 'shapeObj::containsShape' => ['int', 'shape2'=>'shapeObj'], 'shapeObj::convexhull' => ['shapeObj'], 'shapeObj::crosses' => ['int', 'shape'=>'shapeObj'], 'shapeObj::difference' => ['shapeObj', 'shape'=>'shapeObj'], 'shapeObj::disjoint' => ['int', 'shape'=>'shapeObj'], 'shapeObj::draw' => ['int', 'map'=>'mapObj', 'layer'=>'layerObj', 'img'=>'imageObj'], 'shapeObj::equals' => ['int', 'shape'=>'shapeObj'], 'shapeObj::free' => ['void'], 'shapeObj::getArea' => ['float'], 'shapeObj::getCentroid' => ['pointObj'], 'shapeObj::getLabelPoint' => ['pointObj'], 'shapeObj::getLength' => ['float'], 'shapeObj::getPointUsingMeasure' => ['pointObj', 'm'=>'float'], 'shapeObj::getValue' => ['string', 'layer'=>'layerObj', 'filedname'=>'string'], 'shapeObj::intersection' => ['shapeObj', 'shape'=>'shapeObj'], 'shapeObj::intersects' => ['bool', 'shape'=>'shapeObj'], 'shapeObj::line' => ['lineObj', 'i'=>'int'], 'shapeObj::ms_shapeObjFromWkt' => ['shapeObj', 'wkt'=>'string'], 'shapeObj::overlaps' => ['int', 'shape'=>'shapeObj'], 'shapeObj::project' => ['int', 'in'=>'projectionObj', 'out'=>'projectionObj'], 'shapeObj::set' => ['int', 'property_name'=>'string', 'new_value'=>''], 'shapeObj::setBounds' => ['int'], 'shapeObj::simplify' => ['shapeObj|null', 'tolerance'=>'float'], 'shapeObj::symdifference' => ['shapeObj', 'shape'=>'shapeObj'], 'shapeObj::toWkt' => ['string'], 'shapeObj::topologyPreservingSimplify' => ['shapeObj|null', 'tolerance'=>'float'], 'shapeObj::touches' => ['int', 'shape'=>'shapeObj'], 'shapeObj::union' => ['shapeObj', 'shape'=>'shapeObj'], 'shapeObj::within' => ['int', 'shape2'=>'shapeObj'], 'shapefileObj::__construct' => ['void', 'filename'=>'string', 'type'=>'int'], 'shapefileObj::addPoint' => ['int', 'point'=>'pointObj'], 'shapefileObj::addShape' => ['int', 'shape'=>'shapeObj'], 'shapefileObj::free' => ['void'], 'shapefileObj::getExtent' => ['rectObj', 'i'=>'int'], 'shapefileObj::getPoint' => ['shapeObj', 'i'=>'int'], 'shapefileObj::getShape' => ['shapeObj', 'i'=>'int'], 'shapefileObj::getTransformed' => ['shapeObj', 'map'=>'mapObj', 'i'=>'int'], 'shapefileObj::ms_newShapefileObj' => ['shapefileObj', 'filename'=>'string', 'type'=>'int'], 'shell_exec' => ['string|false|null', 'command'=>'string'], 'shm_attach' => ['resource|false', 'key'=>'int', 'size='=>'int', 'permissions='=>'int'], 'shm_detach' => ['bool', 'shm'=>'resource'], 'shm_get_var' => ['mixed', 'shm'=>'resource', 'key'=>'int'], 'shm_has_var' => ['bool', 'shm'=>'resource', 'key'=>'int'], 'shm_put_var' => ['bool', 'shm'=>'resource', 'key'=>'int', 'value'=>'mixed'], 'shm_remove' => ['bool', 'shm'=>'resource'], 'shm_remove_var' => ['bool', 'shm'=>'resource', 'key'=>'int'], 'shmop_close' => ['void', 'shmop'=>'resource'], 'shmop_delete' => ['bool', 'shmop'=>'resource'], 'shmop_open' => ['resource|false', 'key'=>'int', 'mode'=>'string', 'permissions'=>'int', 'size'=>'int'], 'shmop_read' => ['string|false', 'shmop'=>'resource', 'offset'=>'int', 'size'=>'int'], 'shmop_size' => ['int', 'shmop'=>'resource'], 'shmop_write' => ['int|false', 'shmop'=>'resource', 'data'=>'string', 'offset'=>'int'], 'show_source' => ['string|bool', 'filename'=>'string', 'return='=>'bool'], 'shuffle' => ['true', '&rw_array'=>'array'], 'signeurlpaiement' => ['string', 'clent'=>'string', 'data'=>'string'], 'similar_text' => ['int', 'string1'=>'string', 'string2'=>'string', '&w_percent='=>'float'], 'simplexml_import_dom' => ['?SimpleXMLElement', 'node'=>'DOMNode', 'class_name='=>'?string'], 'simplexml_load_file' => ['SimpleXMLElement|false', 'filename'=>'string', 'class_name='=>'?string', 'options='=>'int', 'namespace_or_prefix='=>'string', 'is_prefix='=>'bool'], 'simplexml_load_string' => ['SimpleXMLElement|false', 'data'=>'string', 'class_name='=>'?string', 'options='=>'int', 'namespace_or_prefix='=>'string', 'is_prefix='=>'bool'], 'sin' => ['float', 'num'=>'float'], 'sinh' => ['float', 'num'=>'float'], 'sizeof' => ['int<0, max>', 'value'=>'Countable|array|SimpleXMLElement', 'mode='=>'int'], 'sleep' => ['int|false', 'seconds'=>'0|positive-int'], 'snmp2_get' => ['string|false', 'hostname'=>'string', 'community'=>'string', 'object_id'=>'array|string', 'timeout='=>'int', 'retries='=>'int'], 'snmp2_getnext' => ['string|false', 'hostname'=>'string', 'community'=>'string', 'object_id'=>'array|string', 'timeout='=>'int', 'retries='=>'int'], 'snmp2_real_walk' => ['array|false', 'hostname'=>'string', 'community'=>'string', 'object_id'=>'array|string', 'timeout='=>'int', 'retries='=>'int'], 'snmp2_set' => ['bool', 'hostname'=>'string', 'community'=>'string', 'object_id'=>'array|string', 'type'=>'array|string', 'value'=>'array|string', 'timeout='=>'int', 'retries='=>'int'], 'snmp2_walk' => ['array|false', 'hostname'=>'string', 'community'=>'string', 'object_id'=>'array|string', 'timeout='=>'int', 'retries='=>'int'], 'snmp3_get' => ['string|false', 'hostname'=>'string', 'security_name'=>'string', 'security_level'=>'string', 'auth_protocol'=>'string', 'auth_passphrase'=>'string', 'privacy_protocol'=>'string', 'privacy_passphrase'=>'string', 'object_id'=>'array|string', 'timeout='=>'int', 'retries='=>'int'], 'snmp3_getnext' => ['string|false', 'hostname'=>'string', 'security_name'=>'string', 'security_level'=>'string', 'auth_protocol'=>'string', 'auth_passphrase'=>'string', 'privacy_protocol'=>'string', 'privacy_passphrase'=>'string', 'object_id'=>'array|string', 'timeout='=>'int', 'retries='=>'int'], 'snmp3_real_walk' => ['array|false', 'hostname'=>'string', 'security_name'=>'string', 'security_level'=>'string', 'auth_protocol'=>'string', 'auth_passphrase'=>'string', 'privacy_protocol'=>'string', 'privacy_passphrase'=>'string', 'object_id'=>'array|string', 'timeout='=>'int', 'retries='=>'int'], 'snmp3_set' => ['bool', 'hostname'=>'string', 'security_name'=>'string', 'security_level'=>'string', 'auth_protocol'=>'string', 'auth_passphrase'=>'string', 'privacy_protocol'=>'string', 'privacy_passphrase'=>'string', 'object_id'=>'array|string', 'type'=>'array|string', 'value'=>'array|string', 'timeout='=>'int', 'retries='=>'int'], 'snmp3_walk' => ['array|false', 'hostname'=>'string', 'security_name'=>'string', 'security_level'=>'string', 'auth_protocol'=>'string', 'auth_passphrase'=>'string', 'privacy_protocol'=>'string', 'privacy_passphrase'=>'string', 'object_id'=>'array|string', 'timeout='=>'int', 'retries='=>'int'], 'snmp_get_quick_print' => ['bool'], 'snmp_get_valueretrieval' => ['int'], 'snmp_read_mib' => ['bool', 'filename'=>'string'], 'snmp_set_enum_print' => ['true', 'enable'=>'bool'], 'snmp_set_oid_numeric_print' => ['true', 'format'=>'int'], 'snmp_set_oid_output_format' => ['true', 'format'=>'int'], 'snmp_set_quick_print' => ['bool', 'enable'=>'bool'], 'snmp_set_valueretrieval' => ['true', 'method'=>'int'], 'snmpget' => ['string|false', 'hostname'=>'string', 'community'=>'string', 'object_id'=>'array|string', 'timeout='=>'int', 'retries='=>'int'], 'snmpgetnext' => ['string|false', 'hostname'=>'string', 'community'=>'string', 'object_id'=>'array|string', 'timeout='=>'int', 'retries='=>'int'], 'snmprealwalk' => ['array|false', 'hostname'=>'string', 'community'=>'string', 'object_id'=>'array|string', 'timeout='=>'int', 'retries='=>'int'], 'snmpset' => ['bool', 'hostname'=>'string', 'community'=>'string', 'object_id'=>'array|string', 'type'=>'string|string[]', 'value'=>'string|string[]', 'timeout='=>'int', 'retries='=>'int'], 'snmpwalk' => ['array|false', 'hostname'=>'string', 'community'=>'string', 'object_id'=>'array|string', 'timeout='=>'int', 'retries='=>'int'], 'snmpwalkoid' => ['array|false', 'hostname'=>'string', 'community'=>'string', 'object_id'=>'array|string', 'timeout='=>'int', 'retries='=>'int'], 'socket_accept' => ['resource|false', 'socket'=>'resource'], 'socket_bind' => ['bool', 'socket'=>'resource', 'address'=>'string', 'port='=>'int'], 'socket_clear_error' => ['void', 'socket='=>'resource'], 'socket_close' => ['void', 'socket'=>'resource'], 'socket_cmsg_space' => ['?int', 'level'=>'int', 'type'=>'int', 'num='=>'int'], 'socket_connect' => ['bool', 'socket'=>'resource', 'address'=>'string', 'port='=>'int'], 'socket_create' => ['resource|false', 'domain'=>'int', 'type'=>'int', 'protocol'=>'int'], 'socket_create_listen' => ['resource|false', 'port'=>'int', 'backlog='=>'int'], 'socket_create_pair' => ['bool', 'domain'=>'int', 'type'=>'int', 'protocol'=>'int', '&w_pair'=>'resource[]'], 'socket_export_stream' => ['resource|false', 'socket'=>'resource'], 'socket_get_option' => ['array|int|false', 'socket'=>'resource', 'level'=>'int', 'option'=>'int'], 'socket_get_status' => ['array', 'stream'=>'resource'], 'socket_getopt' => ['array|int|false', 'socket'=>'resource', 'level'=>'int', 'option'=>'int'], 'socket_getpeername' => ['bool', 'socket'=>'resource', '&w_address'=>'string', '&w_port='=>'int'], 'socket_getsockname' => ['bool', 'socket'=>'resource', '&w_address'=>'string', '&w_port='=>'int'], 'socket_import_stream' => ['resource|false', 'stream'=>'resource'], 'socket_last_error' => ['int', 'socket='=>'resource'], 'socket_listen' => ['bool', 'socket'=>'resource', 'backlog='=>'int'], 'socket_read' => ['string|false', 'socket'=>'resource', 'length'=>'int', 'mode='=>'int'], 'socket_recv' => ['int|false', 'socket'=>'resource', '&w_data'=>'string', 'length'=>'int', 'flags'=>'int'], 'socket_recvfrom' => ['int|false', 'socket'=>'resource', '&w_data'=>'string', 'length'=>'int', 'flags'=>'int', '&w_address'=>'string', '&w_port='=>'int'], 'socket_recvmsg' => ['int|false', 'socket'=>'resource', '&w_message'=>'array', 'flags='=>'int'], 'socket_select' => ['int|false', '&rw_read'=>'resource[]|null', '&rw_write'=>'resource[]|null', '&rw_except'=>'resource[]|null', 'seconds'=>'int|null', 'microseconds='=>'int'], 'socket_send' => ['int|false', 'socket'=>'resource', 'data'=>'string', 'length'=>'int', 'flags'=>'int'], 'socket_sendmsg' => ['int|false', 'socket'=>'resource', 'message'=>'array', 'flags='=>'int'], 'socket_sendto' => ['int|false', 'socket'=>'resource', 'data'=>'string', 'length'=>'int', 'flags'=>'int', 'address'=>'string', 'port='=>'int'], 'socket_set_block' => ['bool', 'socket'=>'resource'], 'socket_set_blocking' => ['bool', 'stream'=>'resource', 'enable'=>'bool'], 'socket_set_nonblock' => ['bool', 'socket'=>'resource'], 'socket_set_option' => ['bool', 'socket'=>'resource', 'level'=>'int', 'option'=>'int', 'value'=>'int|string|array'], 'socket_set_timeout' => ['bool', 'stream'=>'resource', 'seconds'=>'int', 'microseconds='=>'int'], 'socket_setopt' => ['bool', 'socket'=>'resource', 'level'=>'int', 'option'=>'int', 'value'=>'int|string|array'], 'socket_shutdown' => ['bool', 'socket'=>'resource', 'mode='=>'int'], 'socket_strerror' => ['string', 'error_code'=>'int'], 'socket_write' => ['int|false', 'socket'=>'resource', 'data'=>'string', 'length='=>'int'], 'solid_fetch_prev' => ['bool', 'result_id'=>''], 'solr_get_version' => ['string|false'], 'sort' => ['true', '&rw_array'=>'array', 'flags='=>'int'], 'soundex' => ['string', 'string'=>'string'], 'spl_autoload' => ['void', 'class'=>'string', 'file_extensions='=>'string'], 'spl_autoload_call' => ['void', 'class'=>'string'], 'spl_autoload_extensions' => ['string', 'file_extensions='=>'string'], 'spl_autoload_functions' => ['false|list'], 'spl_autoload_register' => ['bool', 'callback='=>'callable(string):void', 'throw='=>'bool', 'prepend='=>'bool'], 'spl_autoload_unregister' => ['bool', 'callback'=>'callable(string):void'], 'spl_classes' => ['array'], 'spl_object_hash' => ['string', 'object'=>'object'], 'spl_object_id' => ['int', 'object'=>'object'], 'sprintf' => ['string', 'format'=>'string', '...values='=>'string|int|float'], 'sqlite_array_query' => ['array|false', 'dbhandle'=>'resource', 'query'=>'string', 'result_type='=>'int', 'decode_binary='=>'bool'], 'sqlite_busy_timeout' => ['void', 'dbhandle'=>'resource', 'milliseconds'=>'int'], 'sqlite_changes' => ['int', 'dbhandle'=>'resource'], 'sqlite_close' => ['void', 'dbhandle'=>'resource'], 'sqlite_column' => ['mixed', 'result'=>'resource', 'index_or_name'=>'mixed', 'decode_binary='=>'bool'], 'sqlite_create_aggregate' => ['void', 'dbhandle'=>'resource', 'function_name'=>'string', 'step_func'=>'callable', 'finalize_func'=>'callable', 'num_args='=>'int'], 'sqlite_create_function' => ['void', 'dbhandle'=>'resource', 'function_name'=>'string', 'callback'=>'callable', 'num_args='=>'int'], 'sqlite_current' => ['array|false', 'result'=>'resource', 'result_type='=>'int', 'decode_binary='=>'bool'], 'sqlite_error_string' => ['string', 'error_code'=>'int'], 'sqlite_escape_string' => ['string', 'item'=>'string'], 'sqlite_exec' => ['bool', 'dbhandle'=>'resource', 'query'=>'string', 'error_msg='=>'string'], 'sqlite_factory' => ['SQLiteDatabase', 'filename'=>'string', 'mode='=>'int', 'error_message='=>'string'], 'sqlite_fetch_all' => ['array', 'result'=>'resource', 'result_type='=>'int', 'decode_binary='=>'bool'], 'sqlite_fetch_array' => ['array|false', 'result'=>'resource', 'result_type='=>'int', 'decode_binary='=>'bool'], 'sqlite_fetch_column_types' => ['array|false', 'table_name'=>'string', 'dbhandle'=>'resource', 'result_type='=>'int'], 'sqlite_fetch_object' => ['object', 'result'=>'resource', 'class_name='=>'string', 'ctor_params='=>'array', 'decode_binary='=>'bool'], 'sqlite_fetch_single' => ['string', 'result'=>'resource', 'decode_binary='=>'bool'], 'sqlite_fetch_string' => ['string', 'result'=>'resource', 'decode_binary'=>'bool'], 'sqlite_field_name' => ['string', 'result'=>'resource', 'field_index'=>'int'], 'sqlite_has_more' => ['bool', 'result'=>'resource'], 'sqlite_has_prev' => ['bool', 'result'=>'resource'], 'sqlite_key' => ['int', 'result'=>'resource'], 'sqlite_last_error' => ['int', 'dbhandle'=>'resource'], 'sqlite_last_insert_rowid' => ['int', 'dbhandle'=>'resource'], 'sqlite_libencoding' => ['string'], 'sqlite_libversion' => ['string'], 'sqlite_next' => ['bool', 'result'=>'resource'], 'sqlite_num_fields' => ['int', 'result'=>'resource'], 'sqlite_num_rows' => ['int', 'result'=>'resource'], 'sqlite_open' => ['resource|false', 'filename'=>'string', 'mode='=>'int', 'error_message='=>'string'], 'sqlite_popen' => ['resource|false', 'filename'=>'string', 'mode='=>'int', 'error_message='=>'string'], 'sqlite_prev' => ['bool', 'result'=>'resource'], 'sqlite_query' => ['resource|false', 'dbhandle'=>'resource', 'query'=>'resource|string', 'result_type='=>'int', 'error_msg='=>'string'], 'sqlite_rewind' => ['bool', 'result'=>'resource'], 'sqlite_seek' => ['bool', 'result'=>'resource', 'rownum'=>'int'], 'sqlite_single_query' => ['array', 'db'=>'resource', 'query'=>'string', 'first_row_only='=>'bool', 'decode_binary='=>'bool'], 'sqlite_udf_decode_binary' => ['string', 'data'=>'string'], 'sqlite_udf_encode_binary' => ['string', 'data'=>'string'], 'sqlite_unbuffered_query' => ['SQLiteUnbuffered|false', 'dbhandle'=>'resource', 'query'=>'string', 'result_type='=>'int', 'error_msg='=>'string'], 'sqlite_valid' => ['bool', 'result'=>'resource'], 'sqlsrv_begin_transaction' => ['bool', 'conn'=>'resource'], 'sqlsrv_cancel' => ['bool', 'stmt'=>'resource'], 'sqlsrv_client_info' => ['array|false', 'conn'=>'resource'], 'sqlsrv_close' => ['bool', 'conn'=>'?resource'], 'sqlsrv_commit' => ['bool', 'conn'=>'resource'], 'sqlsrv_configure' => ['bool', 'setting'=>'string', 'value'=>'mixed'], 'sqlsrv_connect' => ['resource|false', 'server_name'=>'string', 'connection_info='=>'array'], 'sqlsrv_errors' => ['?array', 'errors_and_or_warnings='=>'int'], 'sqlsrv_execute' => ['bool', 'stmt'=>'resource'], 'sqlsrv_fetch' => ['?bool', 'stmt'=>'resource', 'row='=>'int', 'offset='=>'int'], 'sqlsrv_fetch_array' => ['array|null|false', 'stmt'=>'resource', 'fetchType='=>'int', 'row='=>'int', 'offset='=>'int'], 'sqlsrv_fetch_object' => ['object|null|false', 'stmt'=>'resource', 'className='=>'string', 'ctorParams='=>'array', 'row='=>'int', 'offset='=>'int'], 'sqlsrv_field_metadata' => ['array|false', 'stmt'=>'resource'], 'sqlsrv_free_stmt' => ['bool', 'stmt'=>'resource'], 'sqlsrv_get_config' => ['mixed', 'setting'=>'string'], 'sqlsrv_get_field' => ['mixed', 'stmt'=>'resource', 'fieldIndex'=>'int', 'getAsType='=>'int'], 'sqlsrv_has_rows' => ['bool', 'stmt'=>'resource'], 'sqlsrv_next_result' => ['?bool', 'stmt'=>'resource'], 'sqlsrv_num_fields' => ['int|false', 'stmt'=>'resource'], 'sqlsrv_num_rows' => ['int|false', 'stmt'=>'resource'], 'sqlsrv_prepare' => ['resource|false', 'conn'=>'resource', 'sql'=>'string', 'params='=>'array', 'options='=>'array'], 'sqlsrv_query' => ['resource|false', 'conn'=>'resource', 'sql'=>'string', 'params='=>'array', 'options='=>'array'], 'sqlsrv_rollback' => ['bool', 'conn'=>'resource'], 'sqlsrv_rows_affected' => ['int|false', 'stmt'=>'resource'], 'sqlsrv_send_stream_data' => ['bool', 'stmt'=>'resource'], 'sqlsrv_server_info' => ['array', 'conn'=>'resource'], 'sqrt' => ['float', 'num'=>'float'], 'srand' => ['void', 'seed='=>'int', 'mode='=>'int'], 'sscanf' => ['list|int|null', 'string'=>'string', 'format'=>'string', '&...w_vars='=>'string|int|float|null'], 'ssdeep_fuzzy_compare' => ['int', 'signature1'=>'string', 'signature2'=>'string'], 'ssdeep_fuzzy_hash' => ['string', 'to_hash'=>'string'], 'ssdeep_fuzzy_hash_filename' => ['string', 'file_name'=>'string'], 'ssh2_auth_agent' => ['bool', 'session'=>'resource', 'username'=>'string'], 'ssh2_auth_hostbased_file' => ['bool', 'session'=>'resource', 'username'=>'string', 'hostname'=>'string', 'pubkeyfile'=>'string', 'privkeyfile'=>'string', 'passphrase='=>'string', 'local_username='=>'string'], 'ssh2_auth_none' => ['bool|string[]', 'session'=>'resource', 'username'=>'string'], 'ssh2_auth_password' => ['bool', 'session'=>'resource', 'username'=>'string', 'password'=>'string'], 'ssh2_auth_pubkey_file' => ['bool', 'session'=>'resource', 'username'=>'string', 'pubkeyfile'=>'string', 'privkeyfile'=>'string', 'passphrase='=>'string'], 'ssh2_connect' => ['resource|false', 'host'=>'string', 'port='=>'int', 'methods='=>'array', 'callbacks='=>'array'], 'ssh2_disconnect' => ['bool', 'session'=>'resource'], 'ssh2_exec' => ['resource|false', 'session'=>'resource', 'command'=>'string', 'pty='=>'string', 'env='=>'array', 'width='=>'int', 'height='=>'int', 'width_height_type='=>'int'], 'ssh2_fetch_stream' => ['resource|false', 'channel'=>'resource', 'streamid'=>'int'], 'ssh2_fingerprint' => ['string|false', 'session'=>'resource', 'flags='=>'int'], 'ssh2_forward_accept' => ['resource|false', 'listener'=>'resource'], 'ssh2_forward_listen' => ['resource|false', 'session'=>'resource', 'port'=>'int', 'host='=>'string', 'max_connections='=>'string'], 'ssh2_methods_negotiated' => ['array|false', 'session'=>'resource'], 'ssh2_poll' => ['int', '&polldes'=>'array', 'timeout='=>'int'], 'ssh2_publickey_add' => ['bool', 'pkey'=>'resource', 'algoname'=>'string', 'blob'=>'string', 'overwrite='=>'bool', 'attributes='=>'array'], 'ssh2_publickey_init' => ['resource|false', 'session'=>'resource'], 'ssh2_publickey_list' => ['array|false', 'pkey'=>'resource'], 'ssh2_publickey_remove' => ['bool', 'pkey'=>'resource', 'algoname'=>'string', 'blob'=>'string'], 'ssh2_scp_recv' => ['bool', 'session'=>'resource', 'remote_file'=>'string', 'local_file'=>'string'], 'ssh2_scp_send' => ['bool', 'session'=>'resource', 'local_file'=>'string', 'remote_file'=>'string', 'create_mode='=>'int'], 'ssh2_sftp' => ['resource|false', 'session'=>'resource'], 'ssh2_sftp_chmod' => ['bool', 'sftp'=>'resource', 'filename'=>'string', 'mode'=>'int'], 'ssh2_sftp_lstat' => ['array{0: int, 1: int, 2: int, 3: int, 4: int, 5: int, 6: int, 7: int, 8: int, 9: int, 10: int, 11: int, 12: int, dev: int, ino: int, mode: int, nlink: int, uid: int, gid: int, rdev: int, size: int, atime: int, mtime: int, ctime: int, blksize: int, blocks: int}|false', 'sftp'=>'resource', 'path'=>'string'], 'ssh2_sftp_mkdir' => ['bool', 'sftp'=>'resource', 'dirname'=>'string', 'mode='=>'int', 'recursive='=>'bool'], 'ssh2_sftp_readlink' => ['non-falsy-string|false', 'sftp'=>'resource', 'link'=>'string'], 'ssh2_sftp_realpath' => ['non-falsy-string|false', 'sftp'=>'resource', 'filename'=>'string'], 'ssh2_sftp_rename' => ['bool', 'sftp'=>'resource', 'from'=>'string', 'to'=>'string'], 'ssh2_sftp_rmdir' => ['bool', 'sftp'=>'resource', 'dirname'=>'string'], 'ssh2_sftp_stat' => ['array{0: int, 1: int, 2: int, 3: int, 4: int, 5: int, 6: int, 7: int, 8: int, 9: int, 10: int, 11: int, 12: int, dev: int, ino: int, mode: int, nlink: int, uid: int, gid: int, rdev: int, size: int, atime: int, mtime: int, ctime: int, blksize: int, blocks: int}|false', 'sftp'=>'resource', 'path'=>'string'], 'ssh2_sftp_symlink' => ['bool', 'sftp'=>'resource', 'target'=>'string', 'link'=>'string'], 'ssh2_sftp_unlink' => ['bool', 'sftp'=>'resource', 'filename'=>'string'], 'ssh2_shell' => ['resource|false', 'session'=>'resource', 'termtype='=>'string', 'env='=>'array', 'width='=>'int', 'height='=>'int', 'width_height_type='=>'int'], 'ssh2_tunnel' => ['resource|false', 'session'=>'resource', 'host'=>'string', 'port'=>'int'], 'stat' => ['array{0: int, 1: int, 2: int, 3: int, 4: int, 5: int, 6: int, 7: int, 8: int, 9: int, 10: int, 11: int, 12: int, dev: int, ino: int, mode: int, nlink: int, uid: int, gid: int, rdev: int, size: int, atime: int, mtime: int, ctime: int, blksize: int, blocks: int}|false', 'filename'=>'string'], 'stats_absolute_deviation' => ['float', 'a'=>'array'], 'stats_cdf_beta' => ['float', 'par1'=>'float', 'par2'=>'float', 'par3'=>'float', 'which'=>'int'], 'stats_cdf_binomial' => ['float', 'par1'=>'float', 'par2'=>'float', 'par3'=>'float', 'which'=>'int'], 'stats_cdf_cauchy' => ['float', 'par1'=>'float', 'par2'=>'float', 'par3'=>'float', 'which'=>'int'], 'stats_cdf_chisquare' => ['float', 'par1'=>'float', 'par2'=>'float', 'which'=>'int'], 'stats_cdf_exponential' => ['float', 'par1'=>'float', 'par2'=>'float', 'which'=>'int'], 'stats_cdf_f' => ['float', 'par1'=>'float', 'par2'=>'float', 'par3'=>'float', 'which'=>'int'], 'stats_cdf_gamma' => ['float', 'par1'=>'float', 'par2'=>'float', 'par3'=>'float', 'which'=>'int'], 'stats_cdf_laplace' => ['float', 'par1'=>'float', 'par2'=>'float', 'par3'=>'float', 'which'=>'int'], 'stats_cdf_logistic' => ['float', 'par1'=>'float', 'par2'=>'float', 'par3'=>'float', 'which'=>'int'], 'stats_cdf_negative_binomial' => ['float', 'par1'=>'float', 'par2'=>'float', 'par3'=>'float', 'which'=>'int'], 'stats_cdf_noncentral_chisquare' => ['float', 'par1'=>'float', 'par2'=>'float', 'par3'=>'float', 'which'=>'int'], 'stats_cdf_noncentral_f' => ['float', 'par1'=>'float', 'par2'=>'float', 'par3'=>'float', 'par4'=>'float', 'which'=>'int'], 'stats_cdf_noncentral_t' => ['float', 'par1'=>'float', 'par2'=>'float', 'par3'=>'float', 'which'=>'int'], 'stats_cdf_normal' => ['float', 'par1'=>'float', 'par2'=>'float', 'par3'=>'float', 'which'=>'int'], 'stats_cdf_poisson' => ['float', 'par1'=>'float', 'par2'=>'float', 'which'=>'int'], 'stats_cdf_t' => ['float', 'par1'=>'float', 'par2'=>'float', 'which'=>'int'], 'stats_cdf_uniform' => ['float', 'par1'=>'float', 'par2'=>'float', 'par3'=>'float', 'which'=>'int'], 'stats_cdf_weibull' => ['float', 'par1'=>'float', 'par2'=>'float', 'par3'=>'float', 'which'=>'int'], 'stats_covariance' => ['float', 'a'=>'array', 'b'=>'array'], 'stats_den_uniform' => ['float', 'x'=>'float', 'a'=>'float', 'b'=>'float'], 'stats_dens_beta' => ['float', 'x'=>'float', 'a'=>'float', 'b'=>'float'], 'stats_dens_cauchy' => ['float', 'x'=>'float', 'ave'=>'float', 'stdev'=>'float'], 'stats_dens_chisquare' => ['float', 'x'=>'float', 'dfr'=>'float'], 'stats_dens_exponential' => ['float', 'x'=>'float', 'scale'=>'float'], 'stats_dens_f' => ['float', 'x'=>'float', 'dfr1'=>'float', 'dfr2'=>'float'], 'stats_dens_gamma' => ['float', 'x'=>'float', 'shape'=>'float', 'scale'=>'float'], 'stats_dens_laplace' => ['float', 'x'=>'float', 'ave'=>'float', 'stdev'=>'float'], 'stats_dens_logistic' => ['float', 'x'=>'float', 'ave'=>'float', 'stdev'=>'float'], 'stats_dens_negative_binomial' => ['float', 'x'=>'float', 'n'=>'float', 'pi'=>'float'], 'stats_dens_normal' => ['float', 'x'=>'float', 'ave'=>'float', 'stdev'=>'float'], 'stats_dens_pmf_binomial' => ['float', 'x'=>'float', 'n'=>'float', 'pi'=>'float'], 'stats_dens_pmf_hypergeometric' => ['float', 'n1'=>'float', 'n2'=>'float', 'N1'=>'float', 'N2'=>'float'], 'stats_dens_pmf_negative_binomial' => ['float', 'x'=>'float', 'n'=>'float', 'pi'=>'float'], 'stats_dens_pmf_poisson' => ['float', 'x'=>'float', 'lb'=>'float'], 'stats_dens_t' => ['float', 'x'=>'float', 'dfr'=>'float'], 'stats_dens_uniform' => ['float', 'x'=>'float', 'a'=>'float', 'b'=>'float'], 'stats_dens_weibull' => ['float', 'x'=>'float', 'a'=>'float', 'b'=>'float'], 'stats_harmonic_mean' => ['float', 'a'=>'array'], 'stats_kurtosis' => ['float', 'a'=>'array'], 'stats_rand_gen_beta' => ['float', 'a'=>'float', 'b'=>'float'], 'stats_rand_gen_chisquare' => ['float', 'df'=>'float'], 'stats_rand_gen_exponential' => ['float', 'av'=>'float'], 'stats_rand_gen_f' => ['float', 'dfn'=>'float', 'dfd'=>'float'], 'stats_rand_gen_funiform' => ['float', 'low'=>'float', 'high'=>'float'], 'stats_rand_gen_gamma' => ['float', 'a'=>'float', 'r'=>'float'], 'stats_rand_gen_ibinomial' => ['int', 'n'=>'int', 'pp'=>'float'], 'stats_rand_gen_ibinomial_negative' => ['int', 'n'=>'int', 'p'=>'float'], 'stats_rand_gen_int' => ['int'], 'stats_rand_gen_ipoisson' => ['int', 'mu'=>'float'], 'stats_rand_gen_iuniform' => ['int', 'low'=>'int', 'high'=>'int'], 'stats_rand_gen_noncenral_chisquare' => ['float', 'df'=>'float', 'xnonc'=>'float'], 'stats_rand_gen_noncentral_chisquare' => ['float', 'df'=>'float', 'xnonc'=>'float'], 'stats_rand_gen_noncentral_f' => ['float', 'dfn'=>'float', 'dfd'=>'float', 'xnonc'=>'float'], 'stats_rand_gen_noncentral_t' => ['float', 'df'=>'float', 'xnonc'=>'float'], 'stats_rand_gen_normal' => ['float', 'av'=>'float', 'sd'=>'float'], 'stats_rand_gen_t' => ['float', 'df'=>'float'], 'stats_rand_get_seeds' => ['array'], 'stats_rand_phrase_to_seeds' => ['array', 'phrase'=>'string'], 'stats_rand_ranf' => ['float'], 'stats_rand_setall' => ['void', 'iseed1'=>'int', 'iseed2'=>'int'], 'stats_skew' => ['float', 'a'=>'array'], 'stats_standard_deviation' => ['float', 'a'=>'array', 'sample='=>'bool'], 'stats_stat_binomial_coef' => ['float', 'x'=>'int', 'n'=>'int'], 'stats_stat_correlation' => ['float', 'array1'=>'array', 'array2'=>'array'], 'stats_stat_factorial' => ['float', 'n'=>'int'], 'stats_stat_gennch' => ['float', 'n'=>'int'], 'stats_stat_independent_t' => ['float', 'array1'=>'array', 'array2'=>'array'], 'stats_stat_innerproduct' => ['float', 'array1'=>'array', 'array2'=>'array'], 'stats_stat_noncentral_t' => ['float', 'par1'=>'float', 'par2'=>'float', 'par3'=>'float', 'which'=>'int'], 'stats_stat_paired_t' => ['float', 'array1'=>'array', 'array2'=>'array'], 'stats_stat_percentile' => ['float', 'arr'=>'array', 'perc'=>'float'], 'stats_stat_powersum' => ['float', 'arr'=>'array', 'power'=>'float'], 'stats_variance' => ['float', 'a'=>'array', 'sample='=>'bool'], 'stomp_abort' => ['bool', 'link'=>'resource', 'transaction_id'=>'string', 'headers='=>'?array'], 'stomp_ack' => ['bool', 'link'=>'resource', 'msg'=>'', 'headers='=>'?array'], 'stomp_begin' => ['bool', 'link'=>'resource', 'transaction_id'=>'string', 'headers='=>'?array'], 'stomp_close' => ['bool', 'link'=>'resource'], 'stomp_commit' => ['bool', 'link'=>'resource', 'transaction_id'=>'string', 'headers='=>'?array'], 'stomp_connect' => ['resource', 'link'=>'resource', 'broker='=>'string', 'username='=>'string', 'password='=>'string', 'headers='=>'?array'], 'stomp_connect_error' => ['string'], 'stomp_error' => ['string', 'link'=>'resource'], 'stomp_get_read_timeout' => ['array', 'link'=>'resource'], 'stomp_get_session_id' => ['string', 'link'=>'resource'], 'stomp_has_frame' => ['bool', 'link'=>'resource'], 'stomp_read_frame' => ['array', 'link'=>'resource', 'class_name='=>'string'], 'stomp_send' => ['bool', 'link'=>'resource', 'destination'=>'string', 'msg'=>'', 'headers='=>'?array'], 'stomp_set_read_timeout' => ['void', 'link'=>'resource', 'seconds'=>'int', 'microseconds='=>'?int'], 'stomp_subscribe' => ['bool', 'link'=>'resource', 'destination'=>'string', 'headers='=>'?array'], 'stomp_unsubscribe' => ['bool', 'link'=>'resource', 'destination'=>'string', 'headers='=>'?array'], 'stomp_version' => ['string'], 'str_getcsv' => ['non-empty-list', 'string'=>'string', 'separator='=>'string', 'enclosure='=>'string', 'escape='=>'string'], 'str_ireplace' => ['string', 'search'=>'string', 'replace'=>'string', 'subject'=>'string', '&w_count='=>'int'], 'str_ireplace\'1' => ['string[]', 'search'=>'string', 'replace'=>'string', 'subject'=>'array', '&w_count='=>'int'], 'str_ireplace\'2' => ['string', 'search'=>'array', 'replace'=>'string|string[]', 'subject'=>'string', '&w_count='=>'int'], 'str_ireplace\'3' => ['string[]', 'search'=>'array', 'replace'=>'string|string[]', 'subject'=>'array', '&w_count='=>'int'], 'str_pad' => ['string', 'string'=>'string', 'length'=>'int', 'pad_string='=>'string', 'pad_type='=>'int'], 'str_repeat' => ['string', 'string'=>'string', 'times'=>'int'], 'str_replace' => ['string', 'search'=>'string', 'replace'=>'string', 'subject'=>'string', '&w_count='=>'int'], 'str_replace\'1' => ['string[]', 'search'=>'string', 'replace'=>'string', 'subject'=>'array', '&w_count='=>'int'], 'str_replace\'2' => ['string', 'search'=>'array', 'replace'=>'string|string[]', 'subject'=>'string', '&w_count='=>'int'], 'str_replace\'3' => ['string[]', 'search'=>'array', 'replace'=>'string|string[]', 'subject'=>'array', '&w_count='=>'int'], 'str_rot13' => ['string', 'string'=>'string'], 'str_shuffle' => ['string', 'string'=>'string'], 'str_split' => ['non-empty-list', 'string'=>'string', 'length='=>'positive-int'], 'str_word_count' => ['array|int', 'string'=>'string', 'format='=>'int', 'characters='=>'string'], 'strcasecmp' => ['int', 'string1'=>'string', 'string2'=>'string'], 'strchr' => ['string|false', 'haystack'=>'string', 'needle'=>'string|int', 'before_needle='=>'bool'], 'strcmp' => ['int', 'string1'=>'string', 'string2'=>'string'], 'strcoll' => ['int', 'string1'=>'string', 'string2'=>'string'], 'strcspn' => ['int', 'string'=>'string', 'characters'=>'string', 'offset='=>'int', 'length='=>'int'], 'streamWrapper::__construct' => ['void'], 'streamWrapper::__destruct' => ['void'], 'streamWrapper::dir_closedir' => ['bool'], 'streamWrapper::dir_opendir' => ['bool', 'path'=>'string', 'options'=>'int'], 'streamWrapper::dir_readdir' => ['string'], 'streamWrapper::dir_rewinddir' => ['bool'], 'streamWrapper::mkdir' => ['bool', 'path'=>'string', 'mode'=>'int', 'options'=>'int'], 'streamWrapper::rename' => ['bool', 'path_from'=>'string', 'path_to'=>'string'], 'streamWrapper::rmdir' => ['bool', 'path'=>'string', 'options'=>'int'], 'streamWrapper::stream_cast' => ['resource', 'cast_as'=>'int'], 'streamWrapper::stream_close' => ['void'], 'streamWrapper::stream_eof' => ['bool'], 'streamWrapper::stream_flush' => ['bool'], 'streamWrapper::stream_lock' => ['bool', 'operation'=>'mode'], 'streamWrapper::stream_metadata' => ['bool', 'path'=>'string', 'option'=>'int', 'value'=>'mixed'], 'streamWrapper::stream_open' => ['bool', 'path'=>'string', 'mode'=>'string', 'options'=>'int', 'opened_path'=>'string'], 'streamWrapper::stream_read' => ['string', 'count'=>'int'], 'streamWrapper::stream_seek' => ['bool', 'offset'=>'int', 'whence'=>'int'], 'streamWrapper::stream_set_option' => ['bool', 'option'=>'int', 'arg1'=>'int', 'arg2'=>'int'], 'streamWrapper::stream_stat' => ['array'], 'streamWrapper::stream_tell' => ['int'], 'streamWrapper::stream_truncate' => ['bool', 'new_size'=>'int'], 'streamWrapper::stream_write' => ['int', 'data'=>'string'], 'streamWrapper::unlink' => ['bool', 'path'=>'string'], 'streamWrapper::url_stat' => ['array', 'path'=>'string', 'flags'=>'int'], 'stream_bucket_append' => ['void', 'brigade'=>'resource', 'bucket'=>'object'], 'stream_bucket_make_writeable' => ['?object', 'brigade'=>'resource'], 'stream_bucket_new' => ['object', 'stream'=>'resource', 'buffer'=>'string'], 'stream_bucket_prepend' => ['void', 'brigade'=>'resource', 'bucket'=>'object'], 'stream_context_create' => ['resource', 'options='=>'array', 'params='=>'array'], 'stream_context_get_default' => ['resource', 'options='=>'array'], 'stream_context_get_options' => ['array', 'stream_or_context'=>'resource'], 'stream_context_get_params' => ['array{notification:string,options:array}', 'context'=>'resource'], 'stream_context_set_default' => ['resource', 'options'=>'array'], 'stream_context_set_option' => ['bool', 'context'=>'', 'wrapper_or_options'=>'string', 'option_name'=>'string', 'value'=>''], 'stream_context_set_option\'1' => ['bool', 'context'=>'', 'wrapper_or_options'=>'array'], 'stream_context_set_params' => ['bool', 'context'=>'resource', 'params'=>'array'], 'stream_copy_to_stream' => ['int|false', 'from'=>'resource', 'to'=>'resource', 'length='=>'int', 'offset='=>'int'], 'stream_encoding' => ['bool', 'stream'=>'resource', 'encoding='=>'string'], 'stream_filter_append' => ['resource|false', 'stream'=>'resource', 'filter_name'=>'string', 'mode='=>'int', 'params='=>'mixed'], 'stream_filter_prepend' => ['resource|false', 'stream'=>'resource', 'filter_name'=>'string', 'mode='=>'int', 'params='=>'mixed'], 'stream_filter_register' => ['bool', 'filter_name'=>'string', 'class'=>'string'], 'stream_filter_remove' => ['bool', 'stream_filter'=>'resource'], 'stream_get_contents' => ['string|false', 'stream'=>'resource', 'length='=>'int', 'offset='=>'int'], 'stream_get_filters' => ['array'], 'stream_get_line' => ['string|false', 'stream'=>'resource', 'length'=>'int', 'ending='=>'string'], 'stream_get_meta_data' => ['array{timed_out:bool,blocked:bool,eof:bool,unread_bytes:int,stream_type:string,wrapper_type:string,wrapper_data:mixed,mode:string,seekable:bool,uri:string,mediatype:string,crypto?:array{protocol:string,cipher_name:string,cipher_bits:int,cipher_version:string}}', 'stream'=>'resource'], 'stream_get_transports' => ['list'], 'stream_get_wrappers' => ['list'], 'stream_is_local' => ['bool', 'stream'=>'resource|string'], 'stream_notification_callback' => ['callback', 'notification_code'=>'int', 'severity'=>'int', 'message'=>'string', 'message_code'=>'int', 'bytes_transferred'=>'int', 'bytes_max'=>'int'], 'stream_register_wrapper' => ['bool', 'protocol'=>'string', 'class'=>'string', 'flags='=>'int'], 'stream_resolve_include_path' => ['string|false', 'filename'=>'string'], 'stream_select' => ['int|false', '&rw_read'=>'?resource[]', '&rw_write'=>'?resource[]', '&rw_except'=>'?resource[]', 'seconds'=>'?int', 'microseconds='=>'int'], 'stream_set_blocking' => ['bool', 'stream'=>'resource', 'enable'=>'bool'], 'stream_set_chunk_size' => ['int|false', 'stream'=>'resource', 'size'=>'int'], 'stream_set_read_buffer' => ['int', 'stream'=>'resource', 'size'=>'int'], 'stream_set_timeout' => ['bool', 'stream'=>'resource', 'seconds'=>'int', 'microseconds='=>'int'], 'stream_set_write_buffer' => ['int', 'stream'=>'resource', 'size'=>'int'], 'stream_socket_accept' => ['resource|false', 'socket'=>'resource', 'timeout='=>'float', '&w_peer_name='=>'string'], 'stream_socket_client' => ['resource|false', 'address'=>'string', '&w_error_code='=>'int', '&w_error_message='=>'string', 'timeout='=>'float', 'flags='=>'int', 'context='=>'resource'], 'stream_socket_enable_crypto' => ['int|bool', 'stream'=>'resource', 'enable'=>'bool', 'crypto_method='=>'?int', 'session_stream='=>'resource'], 'stream_socket_get_name' => ['string|false', 'socket'=>'resource', 'remote'=>'bool'], 'stream_socket_pair' => ['resource[]|false', 'domain'=>'int', 'type'=>'int', 'protocol'=>'int'], 'stream_socket_recvfrom' => ['string|false', 'socket'=>'resource', 'length'=>'int', 'flags='=>'int', '&w_address='=>'string'], 'stream_socket_sendto' => ['int|false', 'socket'=>'resource', 'data'=>'string', 'flags='=>'int', 'address='=>'string'], 'stream_socket_server' => ['resource|false', 'address'=>'string', '&w_error_code='=>'int', '&w_error_message='=>'string', 'flags='=>'int', 'context='=>'resource'], 'stream_socket_shutdown' => ['bool', 'stream'=>'resource', 'mode'=>'int'], 'stream_supports_lock' => ['bool', 'stream'=>'resource'], 'stream_wrapper_register' => ['bool', 'protocol'=>'string', 'class'=>'string', 'flags='=>'int'], 'stream_wrapper_restore' => ['bool', 'protocol'=>'string'], 'stream_wrapper_unregister' => ['bool', 'protocol'=>'string'], 'strftime' => ['string|false', 'format'=>'string', 'timestamp='=>'int'], 'strip_tags' => ['string', 'string'=>'string', 'allowed_tags='=>'string'], 'stripcslashes' => ['string', 'string'=>'string'], 'stripos' => ['int|false', 'haystack'=>'string', 'needle'=>'string|int', 'offset='=>'int'], 'stripslashes' => ['string', 'string'=>'string'], 'stristr' => ['string|false', 'haystack'=>'string', 'needle'=>'string|int', 'before_needle='=>'bool'], 'strlen' => ['0|positive-int', 'string'=>'string'], 'strnatcasecmp' => ['int', 'string1'=>'string', 'string2'=>'string'], 'strnatcmp' => ['int', 'string1'=>'string', 'string2'=>'string'], 'strncasecmp' => ['int', 'string1'=>'string', 'string2'=>'string', 'length'=>'int'], 'strncmp' => ['int', 'string1'=>'string', 'string2'=>'string', 'length'=>'int'], 'strpbrk' => ['string|false', 'string'=>'string', 'characters'=>'string'], 'strpos' => ['int|false', 'haystack'=>'string', 'needle'=>'string|int', 'offset='=>'int'], 'strptime' => ['array|false', 'timestamp'=>'string', 'format'=>'string'], 'strrchr' => ['string|false', 'haystack'=>'string', 'needle'=>'string|int'], 'strrev' => ['string', 'string'=>'string'], 'strripos' => ['int|false', 'haystack'=>'string', 'needle'=>'string|int', 'offset='=>'int'], 'strrpos' => ['int|false', 'haystack'=>'string', 'needle'=>'string|int', 'offset='=>'int'], 'strspn' => ['int', 'string'=>'string', 'characters'=>'string', 'offset='=>'int', 'length='=>'int'], 'strstr' => ['string|false', 'haystack'=>'string', 'needle'=>'string|int', 'before_needle='=>'bool'], 'strtok' => ['non-empty-string|false', 'string'=>'string', 'token'=>'string'], 'strtok\'1' => ['non-empty-string|false', 'string'=>'string'], 'strtolower' => ['lowercase-string', 'string'=>'string'], 'strtotime' => ['int|false', 'datetime'=>'string', 'baseTimestamp='=>'int'], 'strtoupper' => ['string', 'string'=>'string'], 'strtr' => ['string', 'string'=>'string', 'from'=>'string', 'to'=>'string'], 'strtr\'1' => ['string', 'string'=>'string', 'from'=>'array'], 'strval' => ['string', 'value'=>'mixed'], 'styleObj::__construct' => ['void', 'label'=>'labelObj', 'style'=>'styleObj'], 'styleObj::convertToString' => ['string'], 'styleObj::free' => ['void'], 'styleObj::getBinding' => ['string', 'stylebinding'=>'mixed'], 'styleObj::getGeomTransform' => ['string'], 'styleObj::ms_newStyleObj' => ['styleObj', 'class'=>'classObj', 'style'=>'styleObj'], 'styleObj::removeBinding' => ['int', 'stylebinding'=>'mixed'], 'styleObj::set' => ['int', 'property_name'=>'string', 'new_value'=>''], 'styleObj::setBinding' => ['int', 'stylebinding'=>'mixed', 'value'=>'string'], 'styleObj::setGeomTransform' => ['int', 'value'=>'string'], 'styleObj::updateFromString' => ['int', 'snippet'=>'string'], 'substr' => ['string|false', 'string'=>'string', 'offset'=>'int', 'length='=>'int'], 'substr_compare' => ['int|false', 'haystack'=>'string', 'needle'=>'string', 'offset'=>'int', 'length='=>'int', 'case_insensitive='=>'bool'], 'substr_count' => ['int', 'haystack'=>'string', 'needle'=>'string', 'offset='=>'int', 'length='=>'int'], 'substr_replace' => ['string', 'string'=>'string', 'replace'=>'string|string[]', 'offset'=>'int|int[]', 'length='=>'int|int[]'], 'substr_replace\'1' => ['string[]', 'string'=>'string[]', 'replace'=>'string|string[]', 'offset'=>'int|int[]', 'length='=>'int|int[]'], 'suhosin_encrypt_cookie' => ['string|false', 'name'=>'string', 'value'=>'string'], 'suhosin_get_raw_cookies' => ['array'], 'svm::crossvalidate' => ['float', 'problem'=>'array', 'number_of_folds'=>'int'], 'svm::train' => ['SVMModel', 'problem'=>'array', 'weights='=>'array'], 'svn_add' => ['bool', 'path'=>'string', 'recursive='=>'bool', 'force='=>'bool'], 'svn_auth_get_parameter' => ['?string', 'key'=>'string'], 'svn_auth_set_parameter' => ['void', 'key'=>'string', 'value'=>'string'], 'svn_blame' => ['array', 'repository_url'=>'string', 'revision_no='=>'int'], 'svn_cat' => ['string', 'repos_url'=>'string', 'revision_no='=>'int'], 'svn_checkout' => ['bool', 'repos'=>'string', 'targetpath'=>'string', 'revision='=>'int', 'flags='=>'int'], 'svn_cleanup' => ['bool', 'workingdir'=>'string'], 'svn_client_version' => ['string'], 'svn_commit' => ['array', 'log'=>'string', 'targets'=>'array', 'dontrecurse='=>'bool'], 'svn_delete' => ['bool', 'path'=>'string', 'force='=>'bool'], 'svn_diff' => ['array', 'path1'=>'string', 'rev1'=>'int', 'path2'=>'string', 'rev2'=>'int'], 'svn_export' => ['bool', 'frompath'=>'string', 'topath'=>'string', 'working_copy='=>'bool', 'revision_no='=>'int'], 'svn_fs_abort_txn' => ['bool', 'txn'=>'resource'], 'svn_fs_apply_text' => ['resource', 'root'=>'resource', 'path'=>'string'], 'svn_fs_begin_txn2' => ['resource', 'repos'=>'resource', 'rev'=>'int'], 'svn_fs_change_node_prop' => ['bool', 'root'=>'resource', 'path'=>'string', 'name'=>'string', 'value'=>'string'], 'svn_fs_check_path' => ['int', 'fsroot'=>'resource', 'path'=>'string'], 'svn_fs_contents_changed' => ['bool', 'root1'=>'resource', 'path1'=>'string', 'root2'=>'resource', 'path2'=>'string'], 'svn_fs_copy' => ['bool', 'from_root'=>'resource', 'from_path'=>'string', 'to_root'=>'resource', 'to_path'=>'string'], 'svn_fs_delete' => ['bool', 'root'=>'resource', 'path'=>'string'], 'svn_fs_dir_entries' => ['array', 'fsroot'=>'resource', 'path'=>'string'], 'svn_fs_file_contents' => ['resource', 'fsroot'=>'resource', 'path'=>'string'], 'svn_fs_file_length' => ['int', 'fsroot'=>'resource', 'path'=>'string'], 'svn_fs_is_dir' => ['bool', 'root'=>'resource', 'path'=>'string'], 'svn_fs_is_file' => ['bool', 'root'=>'resource', 'path'=>'string'], 'svn_fs_make_dir' => ['bool', 'root'=>'resource', 'path'=>'string'], 'svn_fs_make_file' => ['bool', 'root'=>'resource', 'path'=>'string'], 'svn_fs_node_created_rev' => ['int', 'fsroot'=>'resource', 'path'=>'string'], 'svn_fs_node_prop' => ['string', 'fsroot'=>'resource', 'path'=>'string', 'propname'=>'string'], 'svn_fs_props_changed' => ['bool', 'root1'=>'resource', 'path1'=>'string', 'root2'=>'resource', 'path2'=>'string'], 'svn_fs_revision_prop' => ['string', 'fs'=>'resource', 'revnum'=>'int', 'propname'=>'string'], 'svn_fs_revision_root' => ['resource', 'fs'=>'resource', 'revnum'=>'int'], 'svn_fs_txn_root' => ['resource', 'txn'=>'resource'], 'svn_fs_youngest_rev' => ['int', 'fs'=>'resource'], 'svn_import' => ['bool', 'path'=>'string', 'url'=>'string', 'nonrecursive'=>'bool'], 'svn_log' => ['array', 'repos_url'=>'string', 'start_revision='=>'int', 'end_revision='=>'int', 'limit='=>'int', 'flags='=>'int'], 'svn_ls' => ['array', 'repos_url'=>'string', 'revision_no='=>'int', 'recurse='=>'bool', 'peg='=>'bool'], 'svn_mkdir' => ['bool', 'path'=>'string', 'log_message='=>'string'], 'svn_move' => ['mixed', 'src_path'=>'string', 'dst_path'=>'string', 'force='=>'bool'], 'svn_propget' => ['mixed', 'path'=>'string', 'property_name'=>'string', 'recurse='=>'bool', 'revision'=>'int'], 'svn_proplist' => ['mixed', 'path'=>'string', 'recurse='=>'bool', 'revision'=>'int'], 'svn_repos_create' => ['resource', 'path'=>'string', 'config='=>'array', 'fsconfig='=>'array'], 'svn_repos_fs' => ['resource', 'repos'=>'resource'], 'svn_repos_fs_begin_txn_for_commit' => ['resource', 'repos'=>'resource', 'rev'=>'int', 'author'=>'string', 'log_msg'=>'string'], 'svn_repos_fs_commit_txn' => ['int', 'txn'=>'resource'], 'svn_repos_hotcopy' => ['bool', 'repospath'=>'string', 'destpath'=>'string', 'cleanlogs'=>'bool'], 'svn_repos_open' => ['resource', 'path'=>'string'], 'svn_repos_recover' => ['bool', 'path'=>'string'], 'svn_revert' => ['bool', 'path'=>'string', 'recursive='=>'bool'], 'svn_status' => ['array', 'path'=>'string', 'flags='=>'int'], 'svn_update' => ['int|false', 'path'=>'string', 'revno='=>'int', 'recurse='=>'bool'], 'swf_actiongeturl' => ['', 'url'=>'string', 'target'=>'string'], 'swf_actiongotoframe' => ['', 'framenumber'=>'int'], 'swf_actiongotolabel' => ['', 'label'=>'string'], 'swf_actionnextframe' => [''], 'swf_actionplay' => [''], 'swf_actionprevframe' => [''], 'swf_actionsettarget' => ['', 'target'=>'string'], 'swf_actionstop' => [''], 'swf_actiontogglequality' => [''], 'swf_actionwaitforframe' => ['', 'framenumber'=>'int', 'skipcount'=>'int'], 'swf_addbuttonrecord' => ['', 'states'=>'int', 'shapeid'=>'int', 'depth'=>'int'], 'swf_addcolor' => ['', 'r'=>'float', 'g'=>'float', 'b'=>'float', 'a'=>'float'], 'swf_closefile' => ['', 'return_file='=>'int'], 'swf_definebitmap' => ['', 'objid'=>'int', 'image_name'=>'string'], 'swf_definefont' => ['', 'fontid'=>'int', 'fontname'=>'string'], 'swf_defineline' => ['', 'objid'=>'int', 'x1'=>'float', 'y1'=>'float', 'x2'=>'float', 'y2'=>'float', 'width'=>'float'], 'swf_definepoly' => ['', 'objid'=>'int', 'coords'=>'array', 'npoints'=>'int', 'width'=>'float'], 'swf_definerect' => ['', 'objid'=>'int', 'x1'=>'float', 'y1'=>'float', 'x2'=>'float', 'y2'=>'float', 'width'=>'float'], 'swf_definetext' => ['', 'objid'=>'int', 'string'=>'string', 'docenter'=>'int'], 'swf_endbutton' => [''], 'swf_enddoaction' => [''], 'swf_endshape' => [''], 'swf_endsymbol' => [''], 'swf_fontsize' => ['', 'size'=>'float'], 'swf_fontslant' => ['', 'slant'=>'float'], 'swf_fonttracking' => ['', 'tracking'=>'float'], 'swf_getbitmapinfo' => ['array', 'bitmapid'=>'int'], 'swf_getfontinfo' => ['array'], 'swf_getframe' => ['int'], 'swf_labelframe' => ['', 'name'=>'string'], 'swf_lookat' => ['', 'view_x'=>'float', 'view_y'=>'float', 'view_z'=>'float', 'reference_x'=>'float', 'reference_y'=>'float', 'reference_z'=>'float', 'twist'=>'float'], 'swf_modifyobject' => ['', 'depth'=>'int', 'how'=>'int'], 'swf_mulcolor' => ['', 'r'=>'float', 'g'=>'float', 'b'=>'float', 'a'=>'float'], 'swf_nextid' => ['int'], 'swf_oncondition' => ['', 'transition'=>'int'], 'swf_openfile' => ['', 'filename'=>'string', 'width'=>'float', 'height'=>'float', 'framerate'=>'float', 'r'=>'float', 'g'=>'float', 'b'=>'float'], 'swf_ortho' => ['', 'xmin'=>'float', 'xmax'=>'float', 'ymin'=>'float', 'ymax'=>'float', 'zmin'=>'float', 'zmax'=>'float'], 'swf_ortho2' => ['', 'xmin'=>'float', 'xmax'=>'float', 'ymin'=>'float', 'ymax'=>'float'], 'swf_perspective' => ['', 'fovy'=>'float', 'aspect'=>'float', 'near'=>'float', 'far'=>'float'], 'swf_placeobject' => ['', 'objid'=>'int', 'depth'=>'int'], 'swf_polarview' => ['', 'dist'=>'float', 'azimuth'=>'float', 'incidence'=>'float', 'twist'=>'float'], 'swf_popmatrix' => [''], 'swf_posround' => ['', 'round'=>'int'], 'swf_pushmatrix' => [''], 'swf_removeobject' => ['', 'depth'=>'int'], 'swf_rotate' => ['', 'angle'=>'float', 'axis'=>'string'], 'swf_scale' => ['', 'x'=>'float', 'y'=>'float', 'z'=>'float'], 'swf_setfont' => ['', 'fontid'=>'int'], 'swf_setframe' => ['', 'framenumber'=>'int'], 'swf_shapearc' => ['', 'x'=>'float', 'y'=>'float', 'r'=>'float', 'ang1'=>'float', 'ang2'=>'float'], 'swf_shapecurveto' => ['', 'x1'=>'float', 'y1'=>'float', 'x2'=>'float', 'y2'=>'float'], 'swf_shapecurveto3' => ['', 'x1'=>'float', 'y1'=>'float', 'x2'=>'float', 'y2'=>'float', 'x3'=>'float', 'y3'=>'float'], 'swf_shapefillbitmapclip' => ['', 'bitmapid'=>'int'], 'swf_shapefillbitmaptile' => ['', 'bitmapid'=>'int'], 'swf_shapefilloff' => [''], 'swf_shapefillsolid' => ['', 'r'=>'float', 'g'=>'float', 'b'=>'float', 'a'=>'float'], 'swf_shapelinesolid' => ['', 'r'=>'float', 'g'=>'float', 'b'=>'float', 'a'=>'float', 'width'=>'float'], 'swf_shapelineto' => ['', 'x'=>'float', 'y'=>'float'], 'swf_shapemoveto' => ['', 'x'=>'float', 'y'=>'float'], 'swf_showframe' => [''], 'swf_startbutton' => ['', 'objid'=>'int', 'type'=>'int'], 'swf_startdoaction' => [''], 'swf_startshape' => ['', 'objid'=>'int'], 'swf_startsymbol' => ['', 'objid'=>'int'], 'swf_textwidth' => ['float', 'string'=>'string'], 'swf_translate' => ['', 'x'=>'float', 'y'=>'float', 'z'=>'float'], 'swf_viewport' => ['', 'xmin'=>'float', 'xmax'=>'float', 'ymin'=>'float', 'ymax'=>'float'], 'swoole\async::dnsLookup' => ['void', 'hostname'=>'string', 'callback'=>'callable'], 'swoole\async::read' => ['bool', 'filename'=>'string', 'callback'=>'callable', 'chunk_size='=>'integer', 'offset='=>'integer'], 'swoole\async::readFile' => ['void', 'filename'=>'string', 'callback'=>'callable'], 'swoole\async::set' => ['void', 'settings'=>'array'], 'swoole\async::write' => ['void', 'filename'=>'string', 'content'=>'string', 'offset='=>'integer', 'callback='=>'callable'], 'swoole\async::writeFile' => ['void', 'filename'=>'string', 'content'=>'string', 'callback='=>'callable', 'flags='=>'string'], 'swoole\atomic::add' => ['integer', 'add_value='=>'integer'], 'swoole\atomic::cmpset' => ['integer', 'cmp_value'=>'integer', 'new_value'=>'integer'], 'swoole\atomic::get' => ['integer'], 'swoole\atomic::set' => ['integer', 'value'=>'integer'], 'swoole\atomic::sub' => ['integer', 'sub_value='=>'integer'], 'swoole\buffer::__destruct' => ['void'], 'swoole\buffer::__toString' => ['string'], 'swoole\buffer::append' => ['integer', 'data'=>'string'], 'swoole\buffer::clear' => ['void'], 'swoole\buffer::expand' => ['integer', 'size'=>'integer'], 'swoole\buffer::read' => ['string', 'offset'=>'integer', 'length'=>'integer'], 'swoole\buffer::recycle' => ['void'], 'swoole\buffer::substr' => ['string', 'offset'=>'integer', 'length='=>'integer', 'remove='=>'bool'], 'swoole\buffer::write' => ['void', 'offset'=>'integer', 'data'=>'string'], 'swoole\channel::__destruct' => ['void'], 'swoole\channel::pop' => ['mixed'], 'swoole\channel::push' => ['bool', 'data'=>'string'], 'swoole\channel::stats' => ['array'], 'swoole\client::__destruct' => ['void'], 'swoole\client::close' => ['bool', 'force='=>'bool'], 'swoole\client::connect' => ['bool', 'host'=>'string', 'port='=>'integer', 'timeout='=>'integer', 'flag='=>'integer'], 'swoole\client::getpeername' => ['array'], 'swoole\client::getsockname' => ['array'], 'swoole\client::isConnected' => ['bool'], 'swoole\client::on' => ['void', 'event'=>'string', 'callback'=>'callable'], 'swoole\client::pause' => ['void'], 'swoole\client::pipe' => ['void', 'socket'=>'string'], 'swoole\client::recv' => ['void', 'size='=>'string', 'flag='=>'string'], 'swoole\client::resume' => ['void'], 'swoole\client::send' => ['integer', 'data'=>'string', 'flag='=>'string'], 'swoole\client::sendfile' => ['bool', 'filename'=>'string', 'offset='=>'int'], 'swoole\client::sendto' => ['bool', 'ip'=>'string', 'port'=>'integer', 'data'=>'string'], 'swoole\client::set' => ['void', 'settings'=>'array'], 'swoole\client::sleep' => ['void'], 'swoole\client::wakeup' => ['void'], 'swoole\connection\iterator::count' => ['int'], 'swoole\connection\iterator::current' => ['Connection'], 'swoole\connection\iterator::key' => ['int'], 'swoole\connection\iterator::next' => ['Connection'], 'swoole\connection\iterator::offsetExists' => ['bool', 'index'=>'int'], 'swoole\connection\iterator::offsetGet' => ['Connection', 'index'=>'string'], 'swoole\connection\iterator::offsetSet' => ['void', 'offset'=>'int', 'connection'=>'mixed'], 'swoole\connection\iterator::offsetUnset' => ['void', 'offset'=>'int'], 'swoole\connection\iterator::rewind' => ['void'], 'swoole\connection\iterator::valid' => ['bool'], 'swoole\coroutine::call_user_func' => ['mixed', 'callback'=>'callable', 'parameter='=>'mixed', '...args='=>'mixed'], 'swoole\coroutine::call_user_func_array' => ['mixed', 'callback'=>'callable', 'param_array'=>'array'], 'swoole\coroutine::cli_wait' => ['ReturnType'], 'swoole\coroutine::create' => ['ReturnType'], 'swoole\coroutine::getuid' => ['ReturnType'], 'swoole\coroutine::resume' => ['ReturnType'], 'swoole\coroutine::suspend' => ['ReturnType'], 'swoole\coroutine\client::__destruct' => ['ReturnType'], 'swoole\coroutine\client::close' => ['ReturnType'], 'swoole\coroutine\client::connect' => ['ReturnType'], 'swoole\coroutine\client::getpeername' => ['ReturnType'], 'swoole\coroutine\client::getsockname' => ['ReturnType'], 'swoole\coroutine\client::isConnected' => ['ReturnType'], 'swoole\coroutine\client::recv' => ['ReturnType'], 'swoole\coroutine\client::send' => ['ReturnType'], 'swoole\coroutine\client::sendfile' => ['ReturnType'], 'swoole\coroutine\client::sendto' => ['ReturnType'], 'swoole\coroutine\client::set' => ['ReturnType'], 'swoole\coroutine\http\client::__destruct' => ['ReturnType'], 'swoole\coroutine\http\client::addFile' => ['ReturnType'], 'swoole\coroutine\http\client::close' => ['ReturnType'], 'swoole\coroutine\http\client::execute' => ['ReturnType'], 'swoole\coroutine\http\client::get' => ['ReturnType'], 'swoole\coroutine\http\client::getDefer' => ['ReturnType'], 'swoole\coroutine\http\client::isConnected' => ['ReturnType'], 'swoole\coroutine\http\client::post' => ['ReturnType'], 'swoole\coroutine\http\client::recv' => ['ReturnType'], 'swoole\coroutine\http\client::set' => ['ReturnType'], 'swoole\coroutine\http\client::setCookies' => ['ReturnType'], 'swoole\coroutine\http\client::setData' => ['ReturnType'], 'swoole\coroutine\http\client::setDefer' => ['ReturnType'], 'swoole\coroutine\http\client::setHeaders' => ['ReturnType'], 'swoole\coroutine\http\client::setMethod' => ['ReturnType'], 'swoole\coroutine\mysql::__destruct' => ['ReturnType'], 'swoole\coroutine\mysql::close' => ['ReturnType'], 'swoole\coroutine\mysql::connect' => ['ReturnType'], 'swoole\coroutine\mysql::getDefer' => ['ReturnType'], 'swoole\coroutine\mysql::query' => ['ReturnType'], 'swoole\coroutine\mysql::recv' => ['ReturnType'], 'swoole\coroutine\mysql::setDefer' => ['ReturnType'], 'swoole\event::add' => ['bool', 'fd'=>'int', 'read_callback'=>'callable', 'write_callback='=>'callable', 'events='=>'string'], 'swoole\event::defer' => ['void', 'callback'=>'mixed'], 'swoole\event::del' => ['bool', 'fd'=>'string'], 'swoole\event::exit' => ['void'], 'swoole\event::set' => ['bool', 'fd'=>'int', 'read_callback='=>'string', 'write_callback='=>'string', 'events='=>'string'], 'swoole\event::wait' => ['void'], 'swoole\event::write' => ['void', 'fd'=>'string', 'data'=>'string'], 'swoole\http\client::__destruct' => ['void'], 'swoole\http\client::addFile' => ['void', 'path'=>'string', 'name'=>'string', 'type='=>'string', 'filename='=>'string', 'offset='=>'string'], 'swoole\http\client::close' => ['void'], 'swoole\http\client::download' => ['void', 'path'=>'string', 'file'=>'string', 'callback'=>'callable', 'offset='=>'integer'], 'swoole\http\client::execute' => ['void', 'path'=>'string', 'callback'=>'string'], 'swoole\http\client::get' => ['void', 'path'=>'string', 'callback'=>'callable'], 'swoole\http\client::isConnected' => ['bool'], 'swoole\http\client::on' => ['void', 'event_name'=>'string', 'callback'=>'callable'], 'swoole\http\client::post' => ['void', 'path'=>'string', 'data'=>'string', 'callback'=>'callable'], 'swoole\http\client::push' => ['void', 'data'=>'string', 'opcode='=>'string', 'finish='=>'string'], 'swoole\http\client::set' => ['void', 'settings'=>'array'], 'swoole\http\client::setCookies' => ['void', 'cookies'=>'array'], 'swoole\http\client::setData' => ['ReturnType', 'data'=>'string'], 'swoole\http\client::setHeaders' => ['void', 'headers'=>'array'], 'swoole\http\client::setMethod' => ['void', 'method'=>'string'], 'swoole\http\client::upgrade' => ['void', 'path'=>'string', 'callback'=>'string'], 'swoole\http\request::__destruct' => ['void'], 'swoole\http\request::rawcontent' => ['string'], 'swoole\http\response::__destruct' => ['void'], 'swoole\http\response::cookie' => ['string', 'name'=>'string', 'value='=>'string', 'expires='=>'string', 'path='=>'string', 'domain='=>'string', 'secure='=>'string', 'httponly='=>'string'], 'swoole\http\response::end' => ['void', 'content='=>'string'], 'swoole\http\response::gzip' => ['ReturnType', 'compress_level='=>'string'], 'swoole\http\response::header' => ['void', 'key'=>'string', 'value'=>'string', 'ucwords='=>'string'], 'swoole\http\response::initHeader' => ['ReturnType'], 'swoole\http\response::rawcookie' => ['ReturnType', 'name'=>'string', 'value='=>'string', 'expires='=>'string', 'path='=>'string', 'domain='=>'string', 'secure='=>'string', 'httponly='=>'string'], 'swoole\http\response::sendfile' => ['ReturnType', 'filename'=>'string', 'offset='=>'int'], 'swoole\http\response::status' => ['ReturnType', 'http_code'=>'string'], 'swoole\http\response::write' => ['void', 'content'=>'string'], 'swoole\http\server::on' => ['void', 'event_name'=>'string', 'callback'=>'callable'], 'swoole\http\server::start' => ['void'], 'swoole\lock::__destruct' => ['void'], 'swoole\lock::lock' => ['void'], 'swoole\lock::lock_read' => ['void'], 'swoole\lock::trylock' => ['void'], 'swoole\lock::trylock_read' => ['void'], 'swoole\lock::unlock' => ['void'], 'swoole\mmap::open' => ['ReturnType', 'filename'=>'string', 'size='=>'string', 'offset='=>'string'], 'swoole\mysql::__destruct' => ['void'], 'swoole\mysql::close' => ['void'], 'swoole\mysql::connect' => ['void', 'server_config'=>'array', 'callback'=>'callable'], 'swoole\mysql::getBuffer' => ['ReturnType'], 'swoole\mysql::on' => ['void', 'event_name'=>'string', 'callback'=>'callable'], 'swoole\mysql::query' => ['ReturnType', 'sql'=>'string', 'callback'=>'callable'], 'swoole\process::__destruct' => ['void'], 'swoole\process::alarm' => ['void', 'interval_usec'=>'integer'], 'swoole\process::close' => ['void'], 'swoole\process::daemon' => ['void', 'nochdir='=>'bool', 'noclose='=>'bool'], 'swoole\process::exec' => ['ReturnType', 'exec_file'=>'string', 'args'=>'string'], 'swoole\process::exit' => ['void', 'exit_code='=>'string'], 'swoole\process::freeQueue' => ['void'], 'swoole\process::kill' => ['void', 'pid'=>'integer', 'signal_no='=>'string'], 'swoole\process::name' => ['void', 'process_name'=>'string'], 'swoole\process::pop' => ['mixed', 'maxsize='=>'integer'], 'swoole\process::push' => ['bool', 'data'=>'string'], 'swoole\process::read' => ['string', 'maxsize='=>'integer'], 'swoole\process::signal' => ['void', 'signal_no'=>'string', 'callback'=>'callable'], 'swoole\process::start' => ['void'], 'swoole\process::statQueue' => ['array'], 'swoole\process::useQueue' => ['bool', 'key'=>'integer', 'mode='=>'integer'], 'swoole\process::wait' => ['array', 'blocking='=>'bool'], 'swoole\process::write' => ['integer', 'data'=>'string'], 'swoole\redis\server::format' => ['ReturnType', 'type'=>'string', 'value='=>'string'], 'swoole\redis\server::setHandler' => ['ReturnType', 'command'=>'string', 'callback'=>'string', 'number_of_string_param='=>'string', 'type_of_array_param='=>'string'], 'swoole\redis\server::start' => ['ReturnType'], 'swoole\serialize::pack' => ['ReturnType', 'data'=>'string', 'is_fast='=>'int'], 'swoole\serialize::unpack' => ['ReturnType', 'data'=>'string', 'args='=>'string'], 'swoole\server::addProcess' => ['bool', 'process'=>'swoole_process'], 'swoole\server::addlistener' => ['void', 'host'=>'string', 'port'=>'integer', 'socket_type'=>'string'], 'swoole\server::after' => ['ReturnType', 'after_time_ms'=>'integer', 'callback'=>'callable', 'param='=>'string'], 'swoole\server::bind' => ['bool', 'fd'=>'integer', 'uid'=>'integer'], 'swoole\server::close' => ['bool', 'fd'=>'integer', 'reset='=>'bool'], 'swoole\server::confirm' => ['bool', 'fd'=>'integer'], 'swoole\server::connection_info' => ['array', 'fd'=>'integer', 'reactor_id='=>'integer'], 'swoole\server::connection_list' => ['array', 'start_fd'=>'integer', 'pagesize='=>'integer'], 'swoole\server::defer' => ['void', 'callback'=>'callable'], 'swoole\server::exist' => ['bool', 'fd'=>'integer'], 'swoole\server::finish' => ['void', 'data'=>'string'], 'swoole\server::getClientInfo' => ['ReturnType', 'fd'=>'integer', 'reactor_id='=>'integer'], 'swoole\server::getClientList' => ['array', 'start_fd'=>'integer', 'pagesize='=>'integer'], 'swoole\server::getLastError' => ['integer'], 'swoole\server::heartbeat' => ['mixed', 'if_close_connection'=>'bool'], 'swoole\server::listen' => ['bool', 'host'=>'string', 'port'=>'integer', 'socket_type'=>'string'], 'swoole\server::on' => ['void', 'event_name'=>'string', 'callback'=>'callable'], 'swoole\server::pause' => ['void', 'fd'=>'integer'], 'swoole\server::protect' => ['void', 'fd'=>'integer', 'is_protected='=>'bool'], 'swoole\server::reload' => ['bool'], 'swoole\server::resume' => ['void', 'fd'=>'integer'], 'swoole\server::send' => ['bool', 'fd'=>'integer', 'data'=>'string', 'reactor_id='=>'integer'], 'swoole\server::sendMessage' => ['bool', 'worker_id'=>'integer', 'data'=>'string'], 'swoole\server::sendfile' => ['bool', 'fd'=>'integer', 'filename'=>'string', 'offset='=>'integer'], 'swoole\server::sendto' => ['bool', 'ip'=>'string', 'port'=>'integer', 'data'=>'string', 'server_socket='=>'string'], 'swoole\server::sendwait' => ['bool', 'fd'=>'integer', 'data'=>'string'], 'swoole\server::set' => ['ReturnType', 'settings'=>'array'], 'swoole\server::shutdown' => ['void'], 'swoole\server::start' => ['void'], 'swoole\server::stats' => ['array'], 'swoole\server::stop' => ['bool', 'worker_id='=>'integer'], 'swoole\server::task' => ['mixed', 'data'=>'string', 'dst_worker_id='=>'integer', 'callback='=>'callable'], 'swoole\server::taskWaitMulti' => ['void', 'tasks'=>'array', 'timeout_ms='=>'double'], 'swoole\server::taskwait' => ['void', 'data'=>'string', 'timeout='=>'float', 'worker_id='=>'integer'], 'swoole\server::tick' => ['void', 'interval_ms'=>'integer', 'callback'=>'callable'], 'swoole\server\port::__destruct' => ['void'], 'swoole\server\port::on' => ['ReturnType', 'event_name'=>'string', 'callback'=>'callable'], 'swoole\server\port::set' => ['void', 'settings'=>'array'], 'swoole\table::column' => ['ReturnType', 'name'=>'string', 'type'=>'string', 'size='=>'integer'], 'swoole\table::count' => ['integer'], 'swoole\table::create' => ['void'], 'swoole\table::current' => ['array'], 'swoole\table::decr' => ['ReturnType', 'key'=>'string', 'column'=>'string', 'decrby='=>'integer'], 'swoole\table::del' => ['void', 'key'=>'string'], 'swoole\table::destroy' => ['void'], 'swoole\table::exist' => ['bool', 'key'=>'string'], 'swoole\table::get' => ['integer', 'row_key'=>'string', 'column_key'=>'string'], 'swoole\table::incr' => ['void', 'key'=>'string', 'column'=>'string', 'incrby='=>'integer'], 'swoole\table::key' => ['string'], 'swoole\table::next' => ['ReturnType'], 'swoole\table::rewind' => ['void'], 'swoole\table::set' => ['VOID', 'key'=>'string', 'value'=>'array'], 'swoole\table::valid' => ['bool'], 'swoole\timer::after' => ['void', 'after_time_ms'=>'int', 'callback'=>'callable'], 'swoole\timer::clear' => ['void', 'timer_id'=>'integer'], 'swoole\timer::exists' => ['bool', 'timer_id'=>'integer'], 'swoole\timer::tick' => ['void', 'interval_ms'=>'integer', 'callback'=>'callable', 'param='=>'string'], 'swoole\websocket\server::exist' => ['bool', 'fd'=>'integer'], 'swoole\websocket\server::on' => ['ReturnType', 'event_name'=>'string', 'callback'=>'callable'], 'swoole\websocket\server::pack' => ['binary', 'data'=>'string', 'opcode='=>'string', 'finish='=>'string', 'mask='=>'string'], 'swoole\websocket\server::push' => ['void', 'fd'=>'string', 'data'=>'string', 'opcode='=>'string', 'finish='=>'string'], 'swoole\websocket\server::unpack' => ['string', 'data'=>'binary'], 'swoole_async_dns_lookup' => ['bool', 'hostname'=>'string', 'callback'=>'callable'], 'swoole_async_read' => ['bool', 'filename'=>'string', 'callback'=>'callable', 'chunk_size='=>'int', 'offset='=>'int'], 'swoole_async_readfile' => ['bool', 'filename'=>'string', 'callback'=>'string'], 'swoole_async_set' => ['void', 'settings'=>'array'], 'swoole_async_write' => ['bool', 'filename'=>'string', 'content'=>'string', 'offset='=>'int', 'callback='=>'callable'], 'swoole_async_writefile' => ['bool', 'filename'=>'string', 'content'=>'string', 'callback='=>'callable', 'flags='=>'int'], 'swoole_client_select' => ['int', 'read_array'=>'array', 'write_array'=>'array', 'error_array'=>'array', 'timeout='=>'float'], 'swoole_cpu_num' => ['int'], 'swoole_errno' => ['int'], 'swoole_event_add' => ['int', 'fd'=>'int', 'read_callback='=>'callable', 'write_callback='=>'callable', 'events='=>'int'], 'swoole_event_defer' => ['bool', 'callback'=>'callable'], 'swoole_event_del' => ['bool', 'fd'=>'int'], 'swoole_event_exit' => ['void'], 'swoole_event_set' => ['bool', 'fd'=>'int', 'read_callback='=>'callable', 'write_callback='=>'callable', 'events='=>'int'], 'swoole_event_wait' => ['void'], 'swoole_event_write' => ['bool', 'fd'=>'int', 'data'=>'string'], 'swoole_get_local_ip' => ['array'], 'swoole_last_error' => ['int'], 'swoole_load_module' => ['mixed', 'filename'=>'string'], 'swoole_select' => ['int', 'read_array'=>'array', 'write_array'=>'array', 'error_array'=>'array', 'timeout='=>'float'], 'swoole_set_process_name' => ['void', 'process_name'=>'string', 'size='=>'int'], 'swoole_strerror' => ['string', 'errno'=>'int', 'error_type='=>'int'], 'swoole_timer_after' => ['int', 'ms'=>'int', 'callback'=>'callable', 'param='=>'mixed'], 'swoole_timer_exists' => ['bool', 'timer_id'=>'int'], 'swoole_timer_tick' => ['int', 'ms'=>'int', 'callback'=>'callable', 'param='=>'mixed'], 'swoole_version' => ['string'], 'symbolObj::__construct' => ['void', 'map'=>'mapObj', 'symbolname'=>'string'], 'symbolObj::free' => ['void'], 'symbolObj::getPatternArray' => ['array'], 'symbolObj::getPointsArray' => ['array'], 'symbolObj::ms_newSymbolObj' => ['int', 'map'=>'mapObj', 'symbolname'=>'string'], 'symbolObj::set' => ['int', 'property_name'=>'string', 'new_value'=>''], 'symbolObj::setImagePath' => ['int', 'filename'=>'string'], 'symbolObj::setPattern' => ['int', 'int'=>'array'], 'symbolObj::setPoints' => ['int', 'double'=>'array'], 'symlink' => ['bool', 'target'=>'string', 'link'=>'string'], 'sys_get_temp_dir' => ['string'], 'sys_getloadavg' => ['array|false'], 'syslog' => ['true', 'priority'=>'int', 'message'=>'string'], 'system' => ['string|false', 'command'=>'string', '&w_result_code='=>'int'], 'taint' => ['bool', '&rw_string'=>'string', '&...w_other_strings='=>'string'], 'tan' => ['float', 'num'=>'float'], 'tanh' => ['float', 'num'=>'float'], 'tcpwrap_check' => ['bool', 'daemon'=>'string', 'address'=>'string', 'user='=>'string', 'nodns='=>'bool'], 'tempnam' => ['string|false', 'directory'=>'string', 'prefix'=>'string'], 'textdomain' => ['string', 'domain'=>'?string'], 'tidy::__construct' => ['void', 'filename='=>'string', 'config='=>'array|string', 'encoding='=>'string', 'useIncludePath='=>'bool'], 'tidy::body' => ['?tidyNode'], 'tidy::cleanRepair' => ['bool'], 'tidy::diagnose' => ['bool'], 'tidy::getConfig' => ['array'], 'tidy::getHtmlVer' => ['int'], 'tidy::getOpt' => ['string|int|bool', 'option'=>'string'], 'tidy::getOptDoc' => ['string', 'option'=>'string'], 'tidy::getRelease' => ['string'], 'tidy::getStatus' => ['int'], 'tidy::head' => ['?tidyNode'], 'tidy::html' => ['?tidyNode'], 'tidy::isXhtml' => ['bool'], 'tidy::isXml' => ['bool'], 'tidy::parseFile' => ['bool', 'filename'=>'string', 'config='=>'array|string', 'encoding='=>'string', 'useIncludePath='=>'bool'], 'tidy::parseString' => ['bool', 'string'=>'string', 'config='=>'array|string', 'encoding='=>'string'], 'tidy::repairFile' => ['string', 'filename'=>'string', 'config='=>'array|string', 'encoding='=>'string', 'useIncludePath='=>'bool'], 'tidy::repairString' => ['string', 'string'=>'string', 'config='=>'array|string', 'encoding='=>'string'], 'tidy::root' => ['?tidyNode'], 'tidyNode::__construct' => ['void'], 'tidyNode::getParent' => ['?tidyNode'], 'tidyNode::hasChildren' => ['bool'], 'tidyNode::hasSiblings' => ['bool'], 'tidyNode::isAsp' => ['bool'], 'tidyNode::isComment' => ['bool'], 'tidyNode::isHtml' => ['bool'], 'tidyNode::isJste' => ['bool'], 'tidyNode::isPhp' => ['bool'], 'tidyNode::isText' => ['bool'], 'tidy_access_count' => ['int', 'tidy'=>'tidy'], 'tidy_clean_repair' => ['bool', 'tidy'=>'tidy'], 'tidy_config_count' => ['int', 'tidy'=>'tidy'], 'tidy_diagnose' => ['bool', 'tidy'=>'tidy'], 'tidy_error_count' => ['int', 'tidy'=>'tidy'], 'tidy_get_body' => ['?tidyNode', 'tidy'=>'tidy'], 'tidy_get_config' => ['array', 'tidy'=>'tidy'], 'tidy_get_error_buffer' => ['string', 'tidy'=>'tidy'], 'tidy_get_head' => ['?tidyNode', 'tidy'=>'tidy'], 'tidy_get_html' => ['?tidyNode', 'tidy'=>'tidy'], 'tidy_get_html_ver' => ['int', 'tidy'=>'tidy'], 'tidy_get_opt_doc' => ['string', 'tidy'=>'tidy', 'option'=>'string'], 'tidy_get_output' => ['string', 'tidy'=>'tidy'], 'tidy_get_release' => ['string'], 'tidy_get_root' => ['?tidyNode', 'tidy'=>'tidy'], 'tidy_get_status' => ['int', 'tidy'=>'tidy'], 'tidy_getopt' => ['string|int|bool', 'tidy'=>'tidy', 'option'=>'string'], 'tidy_is_xhtml' => ['bool', 'tidy'=>'tidy'], 'tidy_is_xml' => ['bool', 'tidy'=>'tidy'], 'tidy_load_config' => ['void', 'filename'=>'string', 'encoding'=>'string'], 'tidy_parse_file' => ['tidy', 'filename'=>'string', 'config='=>'array|string', 'encoding='=>'string', 'useIncludePath='=>'bool'], 'tidy_parse_string' => ['tidy', 'string'=>'string', 'config='=>'array|string', 'encoding='=>'string'], 'tidy_repair_file' => ['string', 'filename'=>'string', 'config='=>'array|string', 'encoding='=>'string', 'useIncludePath='=>'bool'], 'tidy_repair_string' => ['string', 'string'=>'string', 'config='=>'array|string', 'encoding='=>'string'], 'tidy_reset_config' => ['bool'], 'tidy_save_config' => ['bool', 'filename'=>'string'], 'tidy_set_encoding' => ['bool', 'encoding'=>'string'], 'tidy_setopt' => ['bool', 'option'=>'string', 'value'=>'mixed'], 'tidy_warning_count' => ['int', 'tidy'=>'tidy'], 'time' => ['positive-int'], 'time_nanosleep' => ['array{0:0|positive-int,1:0|positive-int}|bool', 'seconds'=>'positive-int', 'nanoseconds'=>'positive-int'], 'time_sleep_until' => ['bool', 'timestamp'=>'float'], 'timezone_abbreviations_list' => ['array>'], 'timezone_identifiers_list' => ['list|false', 'timezoneGroup='=>'int', 'countryCode='=>'string'], 'timezone_location_get' => ['array|false', 'object'=>'DateTimeZone'], 'timezone_name_from_abbr' => ['string|false', 'abbr'=>'string', 'utcOffset='=>'int', 'isDST='=>'int'], 'timezone_name_get' => ['string', 'object'=>'DateTimeZone'], 'timezone_offset_get' => ['int|false', 'object'=>'DateTimeZone', 'datetime'=>'DateTimeInterface'], 'timezone_open' => ['DateTimeZone|false', 'timezone'=>'string'], 'timezone_transitions_get' => ['list|false', 'object'=>'DateTimeZone', 'timestampBegin='=>'int', 'timestampEnd='=>'int'], 'timezone_version_get' => ['string'], 'tmpfile' => ['resource|false'], 'token_get_all' => ['list', 'code'=>'string', 'flags='=>'int'], 'token_name' => ['string', 'id'=>'int'], 'touch' => ['bool', 'filename'=>'string', 'mtime='=>'int', 'atime='=>'int'], 'trader_acos' => ['array', 'real'=>'array'], 'trader_ad' => ['array', 'high'=>'array', 'low'=>'array', 'close'=>'array', 'volume'=>'array'], 'trader_add' => ['array', 'real0'=>'array', 'real1'=>'array'], 'trader_adosc' => ['array', 'high'=>'array', 'low'=>'array', 'close'=>'array', 'volume'=>'array', 'fastPeriod='=>'int', 'slowPeriod='=>'int'], 'trader_adx' => ['array', 'high'=>'array', 'low'=>'array', 'close'=>'array', 'timePeriod='=>'int'], 'trader_adxr' => ['array', 'high'=>'array', 'low'=>'array', 'close'=>'array', 'timePeriod='=>'int'], 'trader_apo' => ['array', 'real'=>'array', 'fastPeriod='=>'int', 'slowPeriod='=>'int', 'mAType='=>'int'], 'trader_aroon' => ['array', 'high'=>'array', 'low'=>'array', 'timePeriod='=>'int'], 'trader_aroonosc' => ['array', 'high'=>'array', 'low'=>'array', 'timePeriod='=>'int'], 'trader_asin' => ['array', 'real'=>'array'], 'trader_atan' => ['array', 'real'=>'array'], 'trader_atr' => ['array', 'high'=>'array', 'low'=>'array', 'close'=>'array', 'timePeriod='=>'int'], 'trader_avgprice' => ['array', 'open'=>'array', 'high'=>'array', 'low'=>'array', 'close'=>'array'], 'trader_bbands' => ['array', 'real'=>'array', 'timePeriod='=>'int', 'nbDevUp='=>'float', 'nbDevDn='=>'float', 'mAType='=>'int'], 'trader_beta' => ['array', 'real0'=>'array', 'real1'=>'array', 'timePeriod='=>'int'], 'trader_bop' => ['array', 'open'=>'array', 'high'=>'array', 'low'=>'array', 'close'=>'array'], 'trader_cci' => ['array', 'high'=>'array', 'low'=>'array', 'close'=>'array', 'timePeriod='=>'int'], 'trader_cdl2crows' => ['array', 'open'=>'array', 'high'=>'array', 'low'=>'array', 'close'=>'array'], 'trader_cdl3blackcrows' => ['array', 'open'=>'array', 'high'=>'array', 'low'=>'array', 'close'=>'array'], 'trader_cdl3inside' => ['array', 'open'=>'array', 'high'=>'array', 'low'=>'array', 'close'=>'array'], 'trader_cdl3linestrike' => ['array', 'open'=>'array', 'high'=>'array', 'low'=>'array', 'close'=>'array'], 'trader_cdl3outside' => ['array', 'open'=>'array', 'high'=>'array', 'low'=>'array', 'close'=>'array'], 'trader_cdl3starsinsouth' => ['array', 'open'=>'array', 'high'=>'array', 'low'=>'array', 'close'=>'array'], 'trader_cdl3whitesoldiers' => ['array', 'open'=>'array', 'high'=>'array', 'low'=>'array', 'close'=>'array'], 'trader_cdlabandonedbaby' => ['array', 'open'=>'array', 'high'=>'array', 'low'=>'array', 'close'=>'array', 'penetration='=>'float'], 'trader_cdladvanceblock' => ['array', 'open'=>'array', 'high'=>'array', 'low'=>'array', 'close'=>'array'], 'trader_cdlbelthold' => ['array', 'open'=>'array', 'high'=>'array', 'low'=>'array', 'close'=>'array'], 'trader_cdlbreakaway' => ['array', 'open'=>'array', 'high'=>'array', 'low'=>'array', 'close'=>'array'], 'trader_cdlclosingmarubozu' => ['array', 'open'=>'array', 'high'=>'array', 'low'=>'array', 'close'=>'array'], 'trader_cdlconcealbabyswall' => ['array', 'open'=>'array', 'high'=>'array', 'low'=>'array', 'close'=>'array'], 'trader_cdlcounterattack' => ['array', 'open'=>'array', 'high'=>'array', 'low'=>'array', 'close'=>'array'], 'trader_cdldarkcloudcover' => ['array', 'open'=>'array', 'high'=>'array', 'low'=>'array', 'close'=>'array', 'penetration='=>'float'], 'trader_cdldoji' => ['array', 'open'=>'array', 'high'=>'array', 'low'=>'array', 'close'=>'array'], 'trader_cdldojistar' => ['array', 'open'=>'array', 'high'=>'array', 'low'=>'array', 'close'=>'array'], 'trader_cdldragonflydoji' => ['array', 'open'=>'array', 'high'=>'array', 'low'=>'array', 'close'=>'array'], 'trader_cdlengulfing' => ['array', 'open'=>'array', 'high'=>'array', 'low'=>'array', 'close'=>'array'], 'trader_cdleveningdojistar' => ['array', 'open'=>'array', 'high'=>'array', 'low'=>'array', 'close'=>'array', 'penetration='=>'float'], 'trader_cdleveningstar' => ['array', 'open'=>'array', 'high'=>'array', 'low'=>'array', 'close'=>'array', 'penetration='=>'float'], 'trader_cdlgapsidesidewhite' => ['array', 'open'=>'array', 'high'=>'array', 'low'=>'array', 'close'=>'array'], 'trader_cdlgravestonedoji' => ['array', 'open'=>'array', 'high'=>'array', 'low'=>'array', 'close'=>'array'], 'trader_cdlhammer' => ['array', 'open'=>'array', 'high'=>'array', 'low'=>'array', 'close'=>'array'], 'trader_cdlhangingman' => ['array', 'open'=>'array', 'high'=>'array', 'low'=>'array', 'close'=>'array'], 'trader_cdlharami' => ['array', 'open'=>'array', 'high'=>'array', 'low'=>'array', 'close'=>'array'], 'trader_cdlharamicross' => ['array', 'open'=>'array', 'high'=>'array', 'low'=>'array', 'close'=>'array'], 'trader_cdlhighwave' => ['array', 'open'=>'array', 'high'=>'array', 'low'=>'array', 'close'=>'array'], 'trader_cdlhikkake' => ['array', 'open'=>'array', 'high'=>'array', 'low'=>'array', 'close'=>'array'], 'trader_cdlhikkakemod' => ['array', 'open'=>'array', 'high'=>'array', 'low'=>'array', 'close'=>'array'], 'trader_cdlhomingpigeon' => ['array', 'open'=>'array', 'high'=>'array', 'low'=>'array', 'close'=>'array'], 'trader_cdlidentical3crows' => ['array', 'open'=>'array', 'high'=>'array', 'low'=>'array', 'close'=>'array'], 'trader_cdlinneck' => ['array', 'open'=>'array', 'high'=>'array', 'low'=>'array', 'close'=>'array'], 'trader_cdlinvertedhammer' => ['array', 'open'=>'array', 'high'=>'array', 'low'=>'array', 'close'=>'array'], 'trader_cdlkicking' => ['array', 'open'=>'array', 'high'=>'array', 'low'=>'array', 'close'=>'array'], 'trader_cdlkickingbylength' => ['array', 'open'=>'array', 'high'=>'array', 'low'=>'array', 'close'=>'array'], 'trader_cdlladderbottom' => ['array', 'open'=>'array', 'high'=>'array', 'low'=>'array', 'close'=>'array'], 'trader_cdllongleggeddoji' => ['array', 'open'=>'array', 'high'=>'array', 'low'=>'array', 'close'=>'array'], 'trader_cdllongline' => ['array', 'open'=>'array', 'high'=>'array', 'low'=>'array', 'close'=>'array'], 'trader_cdlmarubozu' => ['array', 'open'=>'array', 'high'=>'array', 'low'=>'array', 'close'=>'array'], 'trader_cdlmatchinglow' => ['array', 'open'=>'array', 'high'=>'array', 'low'=>'array', 'close'=>'array'], 'trader_cdlmathold' => ['array', 'open'=>'array', 'high'=>'array', 'low'=>'array', 'close'=>'array', 'penetration='=>'float'], 'trader_cdlmorningdojistar' => ['array', 'open'=>'array', 'high'=>'array', 'low'=>'array', 'close'=>'array', 'penetration='=>'float'], 'trader_cdlmorningstar' => ['array', 'open'=>'array', 'high'=>'array', 'low'=>'array', 'close'=>'array', 'penetration='=>'float'], 'trader_cdlonneck' => ['array', 'open'=>'array', 'high'=>'array', 'low'=>'array', 'close'=>'array'], 'trader_cdlpiercing' => ['array', 'open'=>'array', 'high'=>'array', 'low'=>'array', 'close'=>'array'], 'trader_cdlrickshawman' => ['array', 'open'=>'array', 'high'=>'array', 'low'=>'array', 'close'=>'array'], 'trader_cdlrisefall3methods' => ['array', 'open'=>'array', 'high'=>'array', 'low'=>'array', 'close'=>'array'], 'trader_cdlseparatinglines' => ['array', 'open'=>'array', 'high'=>'array', 'low'=>'array', 'close'=>'array'], 'trader_cdlshootingstar' => ['array', 'open'=>'array', 'high'=>'array', 'low'=>'array', 'close'=>'array'], 'trader_cdlshortline' => ['array', 'open'=>'array', 'high'=>'array', 'low'=>'array', 'close'=>'array'], 'trader_cdlspinningtop' => ['array', 'open'=>'array', 'high'=>'array', 'low'=>'array', 'close'=>'array'], 'trader_cdlstalledpattern' => ['array', 'open'=>'array', 'high'=>'array', 'low'=>'array', 'close'=>'array'], 'trader_cdlsticksandwich' => ['array', 'open'=>'array', 'high'=>'array', 'low'=>'array', 'close'=>'array'], 'trader_cdltakuri' => ['array', 'open'=>'array', 'high'=>'array', 'low'=>'array', 'close'=>'array'], 'trader_cdltasukigap' => ['array', 'open'=>'array', 'high'=>'array', 'low'=>'array', 'close'=>'array'], 'trader_cdlthrusting' => ['array', 'open'=>'array', 'high'=>'array', 'low'=>'array', 'close'=>'array'], 'trader_cdltristar' => ['array', 'open'=>'array', 'high'=>'array', 'low'=>'array', 'close'=>'array'], 'trader_cdlunique3river' => ['array', 'open'=>'array', 'high'=>'array', 'low'=>'array', 'close'=>'array'], 'trader_cdlupsidegap2crows' => ['array', 'open'=>'array', 'high'=>'array', 'low'=>'array', 'close'=>'array'], 'trader_cdlxsidegap3methods' => ['array', 'open'=>'array', 'high'=>'array', 'low'=>'array', 'close'=>'array'], 'trader_ceil' => ['array', 'real'=>'array'], 'trader_cmo' => ['array', 'real'=>'array', 'timePeriod='=>'int'], 'trader_correl' => ['array', 'real0'=>'array', 'real1'=>'array', 'timePeriod='=>'int'], 'trader_cos' => ['array', 'real'=>'array'], 'trader_cosh' => ['array', 'real'=>'array'], 'trader_dema' => ['array', 'real'=>'array', 'timePeriod='=>'int'], 'trader_div' => ['array', 'real0'=>'array', 'real1'=>'array'], 'trader_dx' => ['array', 'high'=>'array', 'low'=>'array', 'close'=>'array', 'timePeriod='=>'int'], 'trader_ema' => ['array', 'real'=>'array', 'timePeriod='=>'int'], 'trader_errno' => ['int'], 'trader_exp' => ['array', 'real'=>'array'], 'trader_floor' => ['array', 'real'=>'array'], 'trader_get_compat' => ['int'], 'trader_get_unstable_period' => ['int', 'functionId'=>'int'], 'trader_ht_dcperiod' => ['array', 'real'=>'array'], 'trader_ht_dcphase' => ['array', 'real'=>'array'], 'trader_ht_phasor' => ['array', 'real'=>'array'], 'trader_ht_sine' => ['array', 'real'=>'array'], 'trader_ht_trendline' => ['array', 'real'=>'array'], 'trader_ht_trendmode' => ['array', 'real'=>'array'], 'trader_kama' => ['array', 'real'=>'array', 'timePeriod='=>'int'], 'trader_linearreg' => ['array', 'real'=>'array', 'timePeriod='=>'int'], 'trader_linearreg_angle' => ['array', 'real'=>'array', 'timePeriod='=>'int'], 'trader_linearreg_intercept' => ['array', 'real'=>'array', 'timePeriod='=>'int'], 'trader_linearreg_slope' => ['array', 'real'=>'array', 'timePeriod='=>'int'], 'trader_ln' => ['array', 'real'=>'array'], 'trader_log10' => ['array', 'real'=>'array'], 'trader_ma' => ['array', 'real'=>'array', 'timePeriod='=>'int', 'mAType='=>'int'], 'trader_macd' => ['array', 'real'=>'array', 'fastPeriod='=>'int', 'slowPeriod='=>'int', 'signalPeriod='=>'int'], 'trader_macdext' => ['array', 'real'=>'array', 'fastPeriod='=>'int', 'fastMAType='=>'int', 'slowPeriod='=>'int', 'slowMAType='=>'int', 'signalPeriod='=>'int', 'signalMAType='=>'int'], 'trader_macdfix' => ['array', 'real'=>'array', 'signalPeriod='=>'int'], 'trader_mama' => ['array', 'real'=>'array', 'fastLimit='=>'float', 'slowLimit='=>'float'], 'trader_mavp' => ['array', 'real'=>'array', 'periods'=>'array', 'minPeriod='=>'int', 'maxPeriod='=>'int', 'mAType='=>'int'], 'trader_max' => ['array', 'real'=>'array', 'timePeriod='=>'int'], 'trader_maxindex' => ['array', 'real'=>'array', 'timePeriod='=>'int'], 'trader_medprice' => ['array', 'high'=>'array', 'low'=>'array'], 'trader_mfi' => ['array', 'high'=>'array', 'low'=>'array', 'close'=>'array', 'volume'=>'array', 'timePeriod='=>'int'], 'trader_midpoint' => ['array', 'real'=>'array', 'timePeriod='=>'int'], 'trader_midprice' => ['array', 'high'=>'array', 'low'=>'array', 'timePeriod='=>'int'], 'trader_min' => ['array', 'real'=>'array', 'timePeriod='=>'int'], 'trader_minindex' => ['array', 'real'=>'array', 'timePeriod='=>'int'], 'trader_minmax' => ['array', 'real'=>'array', 'timePeriod='=>'int'], 'trader_minmaxindex' => ['array', 'real'=>'array', 'timePeriod='=>'int'], 'trader_minus_di' => ['array', 'high'=>'array', 'low'=>'array', 'close'=>'array', 'timePeriod='=>'int'], 'trader_minus_dm' => ['array', 'high'=>'array', 'low'=>'array', 'timePeriod='=>'int'], 'trader_mom' => ['array', 'real'=>'array', 'timePeriod='=>'int'], 'trader_mult' => ['array', 'real0'=>'array', 'real1'=>'array'], 'trader_natr' => ['array', 'high'=>'array', 'low'=>'array', 'close'=>'array', 'timePeriod='=>'int'], 'trader_obv' => ['array', 'real'=>'array', 'volume'=>'array'], 'trader_plus_di' => ['array', 'high'=>'array', 'low'=>'array', 'close'=>'array', 'timePeriod='=>'int'], 'trader_plus_dm' => ['array', 'high'=>'array', 'low'=>'array', 'timePeriod='=>'int'], 'trader_ppo' => ['array', 'real'=>'array', 'fastPeriod='=>'int', 'slowPeriod='=>'int', 'mAType='=>'int'], 'trader_roc' => ['array', 'real'=>'array', 'timePeriod='=>'int'], 'trader_rocp' => ['array', 'real'=>'array', 'timePeriod='=>'int'], 'trader_rocr' => ['array', 'real'=>'array', 'timePeriod='=>'int'], 'trader_rocr100' => ['array', 'real'=>'array', 'timePeriod='=>'int'], 'trader_rsi' => ['array', 'real'=>'array', 'timePeriod='=>'int'], 'trader_sar' => ['array', 'high'=>'array', 'low'=>'array', 'acceleration='=>'float', 'maximum='=>'float'], 'trader_sarext' => ['array', 'high'=>'array', 'low'=>'array', 'startValue='=>'float', 'offsetOnReverse='=>'float', 'accelerationInitLong='=>'float', 'accelerationLong='=>'float', 'accelerationMaxLong='=>'float', 'accelerationInitShort='=>'float', 'accelerationShort='=>'float', 'accelerationMaxShort='=>'float'], 'trader_set_compat' => ['void', 'compatId'=>'int'], 'trader_set_unstable_period' => ['void', 'functionId'=>'int', 'timePeriod'=>'int'], 'trader_sin' => ['array', 'real'=>'array'], 'trader_sinh' => ['array', 'real'=>'array'], 'trader_sma' => ['array', 'real'=>'array', 'timePeriod='=>'int'], 'trader_sqrt' => ['array', 'real'=>'array'], 'trader_stddev' => ['array', 'real'=>'array', 'timePeriod='=>'int', 'nbDev='=>'float'], 'trader_stoch' => ['array', 'high'=>'array', 'low'=>'array', 'close'=>'array', 'fastK_Period='=>'int', 'slowK_Period='=>'int', 'slowK_MAType='=>'int', 'slowD_Period='=>'int', 'slowD_MAType='=>'int'], 'trader_stochf' => ['array', 'high'=>'array', 'low'=>'array', 'close'=>'array', 'fastK_Period='=>'int', 'fastD_Period='=>'int', 'fastD_MAType='=>'int'], 'trader_stochrsi' => ['array', 'real'=>'array', 'timePeriod='=>'int', 'fastK_Period='=>'int', 'fastD_Period='=>'int', 'fastD_MAType='=>'int'], 'trader_sub' => ['array', 'real0'=>'array', 'real1'=>'array'], 'trader_sum' => ['array', 'real'=>'array', 'timePeriod='=>'int'], 'trader_t3' => ['array', 'real'=>'array', 'timePeriod='=>'int', 'vFactor='=>'float'], 'trader_tan' => ['array', 'real'=>'array'], 'trader_tanh' => ['array', 'real'=>'array'], 'trader_tema' => ['array', 'real'=>'array', 'timePeriod='=>'int'], 'trader_trange' => ['array', 'high'=>'array', 'low'=>'array', 'close'=>'array'], 'trader_trima' => ['array', 'real'=>'array', 'timePeriod='=>'int'], 'trader_trix' => ['array', 'real'=>'array', 'timePeriod='=>'int'], 'trader_tsf' => ['array', 'real'=>'array', 'timePeriod='=>'int'], 'trader_typprice' => ['array', 'high'=>'array', 'low'=>'array', 'close'=>'array'], 'trader_ultosc' => ['array', 'high'=>'array', 'low'=>'array', 'close'=>'array', 'timePeriod1='=>'int', 'timePeriod2='=>'int', 'timePeriod3='=>'int'], 'trader_var' => ['array', 'real'=>'array', 'timePeriod='=>'int', 'nbDev='=>'float'], 'trader_wclprice' => ['array', 'high'=>'array', 'low'=>'array', 'close'=>'array'], 'trader_willr' => ['array', 'high'=>'array', 'low'=>'array', 'close'=>'array', 'timePeriod='=>'int'], 'trader_wma' => ['array', 'real'=>'array', 'timePeriod='=>'int'], 'trait_exists' => ['bool', 'trait'=>'string', 'autoload='=>'bool'], 'transliterator_create' => ['?Transliterator', 'id'=>'string', 'direction='=>'int'], 'transliterator_create_from_rules' => ['?Transliterator', 'rules'=>'string', 'direction='=>'int'], 'transliterator_create_inverse' => ['?Transliterator', 'transliterator'=>'Transliterator'], 'transliterator_get_error_code' => ['int', 'transliterator'=>'Transliterator'], 'transliterator_get_error_message' => ['string', 'transliterator'=>'Transliterator'], 'transliterator_list_ids' => ['array'], 'transliterator_transliterate' => ['string|false', 'transliterator'=>'Transliterator|string', 'string'=>'string', 'start='=>'int', 'end='=>'int'], 'trigger_error' => ['bool', 'message'=>'string', 'error_level='=>'256|512|1024|16384'], 'trim' => ['string', 'string'=>'string', 'characters='=>'string'], 'uasort' => ['true', '&rw_array'=>'array', 'callback'=>'callable(mixed,mixed):int'], 'ucfirst' => ['string', 'string'=>'string'], 'ucwords' => ['string', 'string'=>'string', 'separators='=>'string'], 'udm_add_search_limit' => ['bool', 'agent'=>'resource', 'var'=>'int', 'value'=>'string'], 'udm_alloc_agent' => ['resource', 'dbaddr'=>'string', 'dbmode='=>'string'], 'udm_alloc_agent_array' => ['resource', 'databases'=>'array'], 'udm_api_version' => ['int'], 'udm_cat_list' => ['array', 'agent'=>'resource', 'category'=>'string'], 'udm_cat_path' => ['array', 'agent'=>'resource', 'category'=>'string'], 'udm_check_charset' => ['bool', 'agent'=>'resource', 'charset'=>'string'], 'udm_check_stored' => ['int', 'agent'=>'', 'link'=>'int', 'doc_id'=>'string'], 'udm_clear_search_limits' => ['bool', 'agent'=>'resource'], 'udm_close_stored' => ['int', 'agent'=>'', 'link'=>'int'], 'udm_crc32' => ['int', 'agent'=>'resource', 'string'=>'string'], 'udm_errno' => ['int', 'agent'=>'resource'], 'udm_error' => ['string', 'agent'=>'resource'], 'udm_find' => ['resource', 'agent'=>'resource', 'query'=>'string'], 'udm_free_agent' => ['int', 'agent'=>'resource'], 'udm_free_ispell_data' => ['bool', 'agent'=>'int'], 'udm_free_res' => ['bool', 'res'=>'resource'], 'udm_get_doc_count' => ['int', 'agent'=>'resource'], 'udm_get_res_field' => ['string', 'res'=>'resource', 'row'=>'int', 'field'=>'int'], 'udm_get_res_param' => ['string', 'res'=>'resource', 'param'=>'int'], 'udm_hash32' => ['int', 'agent'=>'resource', 'string'=>'string'], 'udm_load_ispell_data' => ['bool', 'agent'=>'resource', 'var'=>'int', 'val1'=>'string', 'val2'=>'string', 'flag'=>'int'], 'udm_open_stored' => ['int', 'agent'=>'', 'storedaddr'=>'string'], 'udm_set_agent_param' => ['bool', 'agent'=>'resource', 'var'=>'int', 'val'=>'string'], 'ui\area::onDraw' => ['', 'pen'=>'UI\Draw\Pen', 'areaSize'=>'UI\Size', 'clipPoint'=>'UI\Point', 'clipSize'=>'UI\Size'], 'ui\area::onKey' => ['', 'key'=>'string', 'ext'=>'int', 'flags'=>'int'], 'ui\area::onMouse' => ['', 'areaPoint'=>'UI\Point', 'areaSize'=>'UI\Size', 'flags'=>'int'], 'ui\area::redraw' => [''], 'ui\area::scrollTo' => ['', 'point'=>'UI\Point', 'size'=>'UI\Size'], 'ui\area::setSize' => ['', 'size'=>'UI\Size'], 'ui\control::destroy' => [''], 'ui\control::disable' => [''], 'ui\control::enable' => [''], 'ui\control::getParent' => ['UI\Control'], 'ui\control::getTopLevel' => ['int'], 'ui\control::hide' => [''], 'ui\control::isEnabled' => ['bool'], 'ui\control::isVisible' => ['bool'], 'ui\control::setParent' => ['', 'parent'=>'UI\Control'], 'ui\control::show' => [''], 'ui\controls\box::append' => ['int', 'control'=>'Control', 'stretchy='=>'bool'], 'ui\controls\box::delete' => ['bool', 'index'=>'int'], 'ui\controls\box::getOrientation' => ['int'], 'ui\controls\box::isPadded' => ['bool'], 'ui\controls\box::setPadded' => ['', 'padded'=>'bool'], 'ui\controls\button::getText' => ['string'], 'ui\controls\button::onClick' => [''], 'ui\controls\button::setText' => ['', 'text'=>'string'], 'ui\controls\check::getText' => ['string'], 'ui\controls\check::isChecked' => ['bool'], 'ui\controls\check::onToggle' => [''], 'ui\controls\check::setChecked' => ['', 'checked'=>'bool'], 'ui\controls\check::setText' => ['', 'text'=>'string'], 'ui\controls\colorbutton::getColor' => ['UI\Color'], 'ui\controls\colorbutton::onChange' => [''], 'ui\controls\combo::append' => ['', 'text'=>'string'], 'ui\controls\combo::getSelected' => ['int'], 'ui\controls\combo::onSelected' => [''], 'ui\controls\combo::setSelected' => ['', 'index'=>'int'], 'ui\controls\editablecombo::append' => ['', 'text'=>'string'], 'ui\controls\editablecombo::getText' => ['string'], 'ui\controls\editablecombo::onChange' => [''], 'ui\controls\editablecombo::setText' => ['', 'text'=>'string'], 'ui\controls\entry::getText' => ['string'], 'ui\controls\entry::isReadOnly' => ['bool'], 'ui\controls\entry::onChange' => [''], 'ui\controls\entry::setReadOnly' => ['', 'readOnly'=>'bool'], 'ui\controls\entry::setText' => ['', 'text'=>'string'], 'ui\controls\form::append' => ['int', 'label'=>'string', 'control'=>'UI\Control', 'stretchy='=>'bool'], 'ui\controls\form::delete' => ['bool', 'index'=>'int'], 'ui\controls\form::isPadded' => ['bool'], 'ui\controls\form::setPadded' => ['', 'padded'=>'bool'], 'ui\controls\grid::append' => ['', 'control'=>'UI\Control', 'left'=>'int', 'top'=>'int', 'xspan'=>'int', 'yspan'=>'int', 'hexpand'=>'bool', 'halign'=>'int', 'vexpand'=>'bool', 'valign'=>'int'], 'ui\controls\grid::isPadded' => ['bool'], 'ui\controls\grid::setPadded' => ['', 'padding'=>'bool'], 'ui\controls\group::append' => ['', 'control'=>'UI\Control'], 'ui\controls\group::getTitle' => ['string'], 'ui\controls\group::hasMargin' => ['bool'], 'ui\controls\group::setMargin' => ['', 'margin'=>'bool'], 'ui\controls\group::setTitle' => ['', 'title'=>'string'], 'ui\controls\label::getText' => ['string'], 'ui\controls\label::setText' => ['', 'text'=>'string'], 'ui\controls\multilineentry::append' => ['', 'text'=>'string'], 'ui\controls\multilineentry::getText' => ['string'], 'ui\controls\multilineentry::isReadOnly' => ['bool'], 'ui\controls\multilineentry::onChange' => [''], 'ui\controls\multilineentry::setReadOnly' => ['', 'readOnly'=>'bool'], 'ui\controls\multilineentry::setText' => ['', 'text'=>'string'], 'ui\controls\progress::getValue' => ['int'], 'ui\controls\progress::setValue' => ['', 'value'=>'int'], 'ui\controls\radio::append' => ['', 'text'=>'string'], 'ui\controls\radio::getSelected' => ['int'], 'ui\controls\radio::onSelected' => [''], 'ui\controls\radio::setSelected' => ['', 'index'=>'int'], 'ui\controls\slider::getValue' => ['int'], 'ui\controls\slider::onChange' => [''], 'ui\controls\slider::setValue' => ['', 'value'=>'int'], 'ui\controls\spin::getValue' => ['int'], 'ui\controls\spin::onChange' => [''], 'ui\controls\spin::setValue' => ['', 'value'=>'int'], 'ui\controls\tab::append' => ['int', 'name'=>'string', 'control'=>'UI\Control'], 'ui\controls\tab::delete' => ['bool', 'index'=>'int'], 'ui\controls\tab::hasMargin' => ['bool', 'page'=>'int'], 'ui\controls\tab::insertAt' => ['', 'name'=>'string', 'page'=>'int', 'control'=>'UI\Control'], 'ui\controls\tab::pages' => ['int'], 'ui\controls\tab::setMargin' => ['', 'page'=>'int', 'margin'=>'bool'], 'ui\draw\brush::getColor' => ['UI\Draw\Color'], 'ui\draw\brush\gradient::delStop' => ['int', 'index'=>'int'], 'ui\draw\color::getChannel' => ['float', 'channel'=>'int'], 'ui\draw\color::setChannel' => ['void', 'channel'=>'int', 'value'=>'float'], 'ui\draw\matrix::invert' => [''], 'ui\draw\matrix::isInvertible' => ['bool'], 'ui\draw\matrix::multiply' => ['UI\Draw\Matrix', 'matrix'=>'UI\Draw\Matrix'], 'ui\draw\matrix::rotate' => ['', 'point'=>'UI\Point', 'amount'=>'float'], 'ui\draw\matrix::scale' => ['', 'center'=>'UI\Point', 'point'=>'UI\Point'], 'ui\draw\matrix::skew' => ['', 'point'=>'UI\Point', 'amount'=>'UI\Point'], 'ui\draw\matrix::translate' => ['', 'point'=>'UI\Point'], 'ui\draw\path::addRectangle' => ['', 'point'=>'UI\Point', 'size'=>'UI\Size'], 'ui\draw\path::arcTo' => ['', 'point'=>'UI\Point', 'radius'=>'float', 'angle'=>'float', 'sweep'=>'float', 'negative'=>'float'], 'ui\draw\path::bezierTo' => ['', 'point'=>'UI\Point', 'radius'=>'float', 'angle'=>'float', 'sweep'=>'float', 'negative'=>'float'], 'ui\draw\path::closeFigure' => [''], 'ui\draw\path::end' => [''], 'ui\draw\path::lineTo' => ['', 'point'=>'UI\Point', 'radius'=>'float', 'angle'=>'float', 'sweep'=>'float', 'negative'=>'float'], 'ui\draw\path::newFigure' => ['', 'point'=>'UI\Point'], 'ui\draw\path::newFigureWithArc' => ['', 'point'=>'UI\Point', 'radius'=>'float', 'angle'=>'float', 'sweep'=>'float', 'negative'=>'float'], 'ui\draw\pen::clip' => ['', 'path'=>'UI\Draw\Path'], 'ui\draw\pen::restore' => [''], 'ui\draw\pen::save' => [''], 'ui\draw\pen::transform' => ['', 'matrix'=>'UI\Draw\Matrix'], 'ui\draw\pen::write' => ['', 'point'=>'UI\Point', 'layout'=>'UI\Draw\Text\Layout'], 'ui\draw\stroke::getCap' => ['int'], 'ui\draw\stroke::getJoin' => ['int'], 'ui\draw\stroke::getMiterLimit' => ['float'], 'ui\draw\stroke::getThickness' => ['float'], 'ui\draw\stroke::setCap' => ['', 'cap'=>'int'], 'ui\draw\stroke::setJoin' => ['', 'join'=>'int'], 'ui\draw\stroke::setMiterLimit' => ['', 'limit'=>'float'], 'ui\draw\stroke::setThickness' => ['', 'thickness'=>'float'], 'ui\draw\text\font::getAscent' => ['float'], 'ui\draw\text\font::getDescent' => ['float'], 'ui\draw\text\font::getLeading' => ['float'], 'ui\draw\text\font::getUnderlinePosition' => ['float'], 'ui\draw\text\font::getUnderlineThickness' => ['float'], 'ui\draw\text\font\descriptor::getFamily' => ['string'], 'ui\draw\text\font\descriptor::getItalic' => ['int'], 'ui\draw\text\font\descriptor::getSize' => ['float'], 'ui\draw\text\font\descriptor::getStretch' => ['int'], 'ui\draw\text\font\descriptor::getWeight' => ['int'], 'ui\draw\text\font\fontfamilies' => ['array'], 'ui\draw\text\layout::setWidth' => ['', 'width'=>'float'], 'ui\executor::kill' => ['void'], 'ui\executor::onExecute' => ['void'], 'ui\menu::append' => ['UI\MenuItem', 'name'=>'string', 'type='=>'string'], 'ui\menu::appendAbout' => ['UI\MenuItem', 'type='=>'string'], 'ui\menu::appendCheck' => ['UI\MenuItem', 'name'=>'string', 'type='=>'string'], 'ui\menu::appendPreferences' => ['UI\MenuItem', 'type='=>'string'], 'ui\menu::appendQuit' => ['UI\MenuItem', 'type='=>'string'], 'ui\menu::appendSeparator' => [''], 'ui\menuitem::disable' => [''], 'ui\menuitem::enable' => [''], 'ui\menuitem::isChecked' => ['bool'], 'ui\menuitem::onClick' => [''], 'ui\menuitem::setChecked' => ['', 'checked'=>'bool'], 'ui\point::getX' => ['float'], 'ui\point::getY' => ['float'], 'ui\point::setX' => ['', 'point'=>'float'], 'ui\point::setY' => ['', 'point'=>'float'], 'ui\quit' => ['void'], 'ui\run' => ['void', 'flags='=>'int'], 'ui\size::getHeight' => ['float'], 'ui\size::getWidth' => ['float'], 'ui\size::setHeight' => ['', 'size'=>'float'], 'ui\size::setWidth' => ['', 'size'=>'float'], 'ui\window::add' => ['', 'control'=>'UI\Control'], 'ui\window::error' => ['', 'title'=>'string', 'msg'=>'string'], 'ui\window::getSize' => ['UI\Size'], 'ui\window::getTitle' => ['string'], 'ui\window::hasBorders' => ['bool'], 'ui\window::hasMargin' => ['bool'], 'ui\window::isFullScreen' => ['bool'], 'ui\window::msg' => ['', 'title'=>'string', 'msg'=>'string'], 'ui\window::onClosing' => ['int'], 'ui\window::open' => ['string'], 'ui\window::save' => ['string'], 'ui\window::setBorders' => ['', 'borders'=>'bool'], 'ui\window::setFullScreen' => ['', 'full'=>'bool'], 'ui\window::setMargin' => ['', 'margin'=>'bool'], 'ui\window::setSize' => ['', 'size'=>'UI\Size'], 'ui\window::setTitle' => ['', 'title'=>'string'], 'uksort' => ['true', '&rw_array'=>'array', 'callback'=>'callable(mixed,mixed):int'], 'umask' => ['int', 'mask='=>'int'], 'uniqid' => ['non-empty-string', 'prefix='=>'string', 'more_entropy='=>'bool'], 'unixtojd' => ['int|false', 'timestamp='=>'int'], 'unlink' => ['bool', 'filename'=>'string', 'context='=>'resource'], 'unpack' => ['array', 'format'=>'string', 'string'=>'string'], 'unregister_tick_function' => ['void', 'callback'=>'callable'], 'unserialize' => ['mixed', 'data'=>'string', 'options='=>'array{allowed_classes?:class-string[]|bool}'], 'unset' => ['void', 'var='=>'mixed', '...args='=>'mixed'], 'untaint' => ['bool', '&rw_string'=>'string', '&...rw_strings='=>'string'], 'uopz_allow_exit' => ['void', 'allow'=>'bool'], 'uopz_backup' => ['void', 'class'=>'string', 'function'=>'string'], 'uopz_backup\'1' => ['void', 'function'=>'string'], 'uopz_compose' => ['void', 'name'=>'string', 'classes'=>'array', 'methods='=>'array', 'properties='=>'array', 'flags='=>'int'], 'uopz_copy' => ['Closure', 'class'=>'string', 'function'=>'string'], 'uopz_copy\'1' => ['Closure', 'function'=>'string'], 'uopz_delete' => ['void', 'class'=>'string', 'function'=>'string'], 'uopz_delete\'1' => ['void', 'function'=>'string'], 'uopz_extend' => ['bool', 'class'=>'string', 'parent'=>'string'], 'uopz_flags' => ['int', 'class'=>'string', 'function'=>'string', 'flags'=>'int'], 'uopz_flags\'1' => ['int', 'function'=>'string', 'flags'=>'int'], 'uopz_function' => ['void', 'class'=>'string', 'function'=>'string', 'handler'=>'Closure', 'modifiers='=>'int'], 'uopz_function\'1' => ['void', 'function'=>'string', 'handler'=>'Closure', 'modifiers='=>'int'], 'uopz_get_exit_status' => ['?int'], 'uopz_get_hook' => ['?Closure', 'class'=>'string', 'function'=>'string'], 'uopz_get_hook\'1' => ['?Closure', 'function'=>'string'], 'uopz_get_mock' => ['string|object|null', 'class'=>'string'], 'uopz_get_property' => ['mixed', 'class'=>'object|string', 'property'=>'string'], 'uopz_get_return' => ['mixed', 'class='=>'class-string', 'function='=>'string'], 'uopz_get_static' => ['?array', 'class'=>'string', 'function'=>'string'], 'uopz_implement' => ['bool', 'class'=>'string', 'interface'=>'string'], 'uopz_overload' => ['void', 'opcode'=>'int', 'callable'=>'Callable'], 'uopz_redefine' => ['bool', 'class'=>'string', 'constant'=>'string', 'value'=>'mixed'], 'uopz_redefine\'1' => ['bool', 'constant'=>'string', 'value'=>'mixed'], 'uopz_rename' => ['void', 'class'=>'string', 'function'=>'string', 'rename'=>'string'], 'uopz_rename\'1' => ['void', 'function'=>'string', 'rename'=>'string'], 'uopz_restore' => ['void', 'class'=>'string', 'function'=>'string'], 'uopz_restore\'1' => ['void', 'function'=>'string'], 'uopz_set_hook' => ['bool', 'class'=>'string', 'function'=>'string', 'hook'=>'Closure'], 'uopz_set_hook\'1' => ['bool', 'function'=>'string', 'hook'=>'Closure'], 'uopz_set_mock' => ['void', 'class'=>'string', 'mock'=>'object|string'], 'uopz_set_property' => ['void', 'class'=>'object|string', 'property'=>'string', 'value'=>'mixed'], 'uopz_set_return' => ['bool', 'class'=>'string', 'function'=>'string', 'value'=>'mixed', 'execute='=>'bool'], 'uopz_set_return\'1' => ['bool', 'function'=>'string', 'value'=>'mixed', 'execute='=>'bool'], 'uopz_set_static' => ['void', 'class'=>'string', 'function'=>'string', 'static'=>'array'], 'uopz_undefine' => ['bool', 'class'=>'string', 'constant'=>'string'], 'uopz_undefine\'1' => ['bool', 'constant'=>'string'], 'uopz_unset_hook' => ['bool', 'class'=>'string', 'function'=>'string'], 'uopz_unset_hook\'1' => ['bool', 'function'=>'string'], 'uopz_unset_mock' => ['void', 'class'=>'string'], 'uopz_unset_return' => ['bool', 'class='=>'class-string', 'function='=>'string'], 'uopz_unset_return\'1' => ['bool', 'function'=>'string'], 'urldecode' => ['string', 'string'=>'string'], 'urlencode' => ['string', 'string'=>'string'], 'use_soap_error_handler' => ['bool', 'enable='=>'bool'], 'user_error' => ['bool', 'message'=>'string', 'error_level='=>'int'], 'usleep' => ['void', 'microseconds'=>'positive-int|0'], 'usort' => ['true', '&rw_array'=>'array', 'callback'=>'callable(mixed,mixed):int'], 'utf8_decode' => ['string', 'string'=>'string'], 'utf8_encode' => ['string', 'string'=>'string'], 'var_dump' => ['void', 'value'=>'mixed', '...values='=>'mixed'], 'var_export' => ['?string', 'value'=>'mixed', 'return='=>'bool'], 'variant_abs' => ['mixed', 'value'=>'mixed'], 'variant_add' => ['mixed', 'left'=>'mixed', 'right'=>'mixed'], 'variant_and' => ['mixed', 'left'=>'mixed', 'right'=>'mixed'], 'variant_cast' => ['VARIANT', 'variant'=>'VARIANT', 'type'=>'int'], 'variant_cat' => ['mixed', 'left'=>'mixed', 'right'=>'mixed'], 'variant_cmp' => ['int', 'left'=>'mixed', 'right'=>'mixed', 'locale_id='=>'int', 'flags='=>'int'], 'variant_date_from_timestamp' => ['VARIANT', 'timestamp'=>'int'], 'variant_date_to_timestamp' => ['int', 'variant'=>'VARIANT'], 'variant_div' => ['mixed', 'left'=>'mixed', 'right'=>'mixed'], 'variant_eqv' => ['mixed', 'left'=>'mixed', 'right'=>'mixed'], 'variant_fix' => ['mixed', 'value'=>'mixed'], 'variant_get_type' => ['int', 'variant'=>'VARIANT'], 'variant_idiv' => ['mixed', 'left'=>'mixed', 'right'=>'mixed'], 'variant_imp' => ['mixed', 'left'=>'mixed', 'right'=>'mixed'], 'variant_int' => ['mixed', 'value'=>'mixed'], 'variant_mod' => ['mixed', 'left'=>'mixed', 'right'=>'mixed'], 'variant_mul' => ['mixed', 'left'=>'mixed', 'right'=>'mixed'], 'variant_neg' => ['mixed', 'value'=>'mixed'], 'variant_not' => ['mixed', 'value'=>'mixed'], 'variant_or' => ['mixed', 'left'=>'mixed', 'right'=>'mixed'], 'variant_pow' => ['mixed', 'left'=>'mixed', 'right'=>'mixed'], 'variant_round' => ['mixed', 'value'=>'mixed', 'decimals'=>'int'], 'variant_set' => ['void', 'variant'=>'object', 'value'=>'mixed'], 'variant_set_type' => ['void', 'variant'=>'object', 'type'=>'int'], 'variant_sub' => ['mixed', 'left'=>'mixed', 'right'=>'mixed'], 'variant_xor' => ['mixed', 'left'=>'mixed', 'right'=>'mixed'], 'version_compare' => ['bool', 'version1'=>'string', 'version2'=>'string', 'operator'=>'\'<\'|\'lt\'|\'<=\'|\'le\'|\'>\'|\'gt\'|\'>=\'|\'ge\'|\'==\'|\'=\'|\'eq\'|\'!=\'|\'<>\'|\'ne\''], 'version_compare\'1' => ['int', 'version1'=>'string', 'version2'=>'string'], 'vfprintf' => ['int<0, max>', 'stream'=>'resource', 'format'=>'string', 'values'=>'array'], 'virtual' => ['bool', 'uri'=>'string'], 'vpopmail_add_alias_domain' => ['bool', 'domain'=>'string', 'aliasdomain'=>'string'], 'vpopmail_add_alias_domain_ex' => ['bool', 'olddomain'=>'string', 'newdomain'=>'string'], 'vpopmail_add_domain' => ['bool', 'domain'=>'string', 'dir'=>'string', 'uid'=>'int', 'gid'=>'int'], 'vpopmail_add_domain_ex' => ['bool', 'domain'=>'string', 'passwd'=>'string', 'quota='=>'string', 'bounce='=>'string', 'apop='=>'bool'], 'vpopmail_add_user' => ['bool', 'user'=>'string', 'domain'=>'string', 'password'=>'string', 'gecos='=>'string', 'apop='=>'bool'], 'vpopmail_alias_add' => ['bool', 'user'=>'string', 'domain'=>'string', 'alias'=>'string'], 'vpopmail_alias_del' => ['bool', 'user'=>'string', 'domain'=>'string'], 'vpopmail_alias_del_domain' => ['bool', 'domain'=>'string'], 'vpopmail_alias_get' => ['array', 'alias'=>'string', 'domain'=>'string'], 'vpopmail_alias_get_all' => ['array', 'domain'=>'string'], 'vpopmail_auth_user' => ['bool', 'user'=>'string', 'domain'=>'string', 'password'=>'string', 'apop='=>'string'], 'vpopmail_del_domain' => ['bool', 'domain'=>'string'], 'vpopmail_del_domain_ex' => ['bool', 'domain'=>'string'], 'vpopmail_del_user' => ['bool', 'user'=>'string', 'domain'=>'string'], 'vpopmail_error' => ['string'], 'vpopmail_passwd' => ['bool', 'user'=>'string', 'domain'=>'string', 'password'=>'string', 'apop='=>'bool'], 'vpopmail_set_user_quota' => ['bool', 'user'=>'string', 'domain'=>'string', 'quota'=>'string'], 'vprintf' => ['int<0, max>', 'format'=>'string', 'values'=>'array'], 'vsprintf' => ['string', 'format'=>'string', 'values'=>'array'], 'w32api_deftype' => ['bool', 'typename'=>'string', 'member1_type'=>'string', 'member1_name'=>'string', '...args='=>'string'], 'w32api_init_dtype' => ['resource', 'typename'=>'string', 'value'=>'', '...args='=>''], 'w32api_invoke_function' => ['', 'funcname'=>'string', 'argument'=>'', '...args='=>''], 'w32api_register_function' => ['bool', 'library'=>'string', 'function_name'=>'string', 'return_type'=>'string'], 'w32api_set_call_method' => ['', 'method'=>'int'], 'wddx_add_vars' => ['bool', 'packet_id'=>'resource', 'var_names'=>'mixed', '...vars='=>'mixed'], 'wddx_deserialize' => ['mixed', 'packet'=>'string'], 'wddx_packet_end' => ['string', 'packet_id'=>'resource'], 'wddx_packet_start' => ['resource|false', 'comment='=>'string'], 'wddx_serialize_value' => ['string|false', 'value'=>'mixed', 'comment='=>'string'], 'wddx_serialize_vars' => ['string|false', 'var_name'=>'mixed', '...vars='=>'mixed'], 'webObj::convertToString' => ['string'], 'webObj::free' => ['void'], 'webObj::set' => ['int', 'property_name'=>'string', 'new_value'=>''], 'webObj::updateFromString' => ['int', 'snippet'=>'string'], 'win32_continue_service' => ['int|false', 'servicename'=>'string', 'machine='=>'string'], 'win32_create_service' => ['int|false', 'details'=>'array', 'machine='=>'string'], 'win32_delete_service' => ['int|false', 'servicename'=>'string', 'machine='=>'string'], 'win32_get_last_control_message' => ['int'], 'win32_pause_service' => ['int|false', 'servicename'=>'string', 'machine='=>'string'], 'win32_ps_list_procs' => ['array'], 'win32_ps_stat_mem' => ['array'], 'win32_ps_stat_proc' => ['array', 'pid='=>'int'], 'win32_query_service_status' => ['array|false|int', 'servicename'=>'string', 'machine='=>'string'], 'win32_send_custom_control' => ['int', 'servicename'=>'string', 'control'=>'int', 'machine='=>'string'], 'win32_set_service_exit_code' => ['int', 'exitCode='=>'int'], 'win32_set_service_exit_mode' => ['bool', 'gracefulMode='=>'bool'], 'win32_set_service_status' => ['bool|int', 'status'=>'int', 'checkpoint='=>'int'], 'win32_start_service' => ['int|false', 'servicename'=>'string', 'machine='=>'string'], 'win32_start_service_ctrl_dispatcher' => ['bool|int', 'name'=>'string'], 'win32_stop_service' => ['int|false', 'servicename'=>'string', 'machine='=>'string'], 'wincache_fcache_fileinfo' => ['array|false', 'summaryonly='=>'bool'], 'wincache_fcache_meminfo' => ['array|false'], 'wincache_lock' => ['bool', 'key'=>'string', 'isglobal='=>'bool'], 'wincache_ocache_fileinfo' => ['array|false', 'summaryonly='=>'bool'], 'wincache_ocache_meminfo' => ['array|false'], 'wincache_refresh_if_changed' => ['bool', 'files='=>'array'], 'wincache_rplist_fileinfo' => ['array|false', 'summaryonly='=>'bool'], 'wincache_rplist_meminfo' => ['array|false'], 'wincache_scache_info' => ['array|false', 'summaryonly='=>'bool'], 'wincache_scache_meminfo' => ['array|false'], 'wincache_ucache_add' => ['bool', 'key'=>'string', 'value'=>'mixed', 'ttl='=>'int'], 'wincache_ucache_add\'1' => ['bool', 'values'=>'array', 'unused='=>'', 'ttl='=>'int'], 'wincache_ucache_cas' => ['bool', 'key'=>'string', 'old_value'=>'int', 'new_value'=>'int'], 'wincache_ucache_clear' => ['bool'], 'wincache_ucache_dec' => ['int|false', 'key'=>'string', 'dec_by='=>'int', 'success='=>'bool'], 'wincache_ucache_delete' => ['bool', 'key'=>'mixed'], 'wincache_ucache_exists' => ['bool', 'key'=>'string'], 'wincache_ucache_get' => ['mixed', 'key'=>'mixed', '&w_success='=>'bool'], 'wincache_ucache_inc' => ['int|false', 'key'=>'string', 'inc_by='=>'int', 'success='=>'bool'], 'wincache_ucache_info' => ['array|false', 'summaryonly='=>'bool', 'key='=>'string'], 'wincache_ucache_meminfo' => ['array|false'], 'wincache_ucache_set' => ['bool', 'key'=>'', 'value'=>'', 'ttl='=>'int'], 'wincache_ucache_set\'1' => ['bool', 'values'=>'array', 'unused='=>'', 'ttl='=>'int'], 'wincache_unlock' => ['bool', 'key'=>'string'], 'wkhtmltox\image\converter::convert' => ['?string'], 'wkhtmltox\image\converter::getVersion' => ['string'], 'wkhtmltox\pdf\converter::add' => ['void', 'object'=>'wkhtmltox\PDF\Object'], 'wkhtmltox\pdf\converter::convert' => ['?string'], 'wkhtmltox\pdf\converter::getVersion' => ['string'], 'wordwrap' => ['string', 'string'=>'string', 'width='=>'int', 'break='=>'string', 'cut_long_words='=>'bool'], 'xattr_get' => ['string', 'filename'=>'string', 'name'=>'string', 'flags='=>'int'], 'xattr_list' => ['array', 'filename'=>'string', 'flags='=>'int'], 'xattr_remove' => ['bool', 'filename'=>'string', 'name'=>'string', 'flags='=>'int'], 'xattr_set' => ['bool', 'filename'=>'string', 'name'=>'string', 'value'=>'string', 'flags='=>'int'], 'xattr_supported' => ['bool', 'filename'=>'string', 'flags='=>'int'], 'xcache_asm' => ['string', 'filename'=>'string'], 'xcache_clear_cache' => ['void', 'type'=>'int', 'id='=>'int'], 'xcache_coredump' => ['string', 'op_type'=>'int'], 'xcache_count' => ['int', 'type'=>'int'], 'xcache_coverager_decode' => ['array', 'data'=>'string'], 'xcache_coverager_get' => ['array', 'clean='=>'bool'], 'xcache_coverager_start' => ['void', 'clean='=>'bool'], 'xcache_coverager_stop' => ['void', 'clean='=>'bool'], 'xcache_dasm_file' => ['string', 'filename'=>'string'], 'xcache_dasm_string' => ['string', 'code'=>'string'], 'xcache_dec' => ['int', 'name'=>'string', 'value='=>'int|mixed', 'ttl='=>'int'], 'xcache_decode' => ['bool', 'filename'=>'string'], 'xcache_encode' => ['string', 'filename'=>'string'], 'xcache_get' => ['mixed', 'name'=>'string'], 'xcache_get_data_type' => ['string', 'type'=>'int'], 'xcache_get_op_spec' => ['string', 'op_type'=>'int'], 'xcache_get_op_type' => ['string', 'op_type'=>'int'], 'xcache_get_opcode' => ['string', 'opcode'=>'int'], 'xcache_get_opcode_spec' => ['string', 'opcode'=>'int'], 'xcache_inc' => ['int', 'name'=>'string', 'value='=>'int|mixed', 'ttl='=>'int'], 'xcache_info' => ['array', 'type'=>'int', 'id'=>'int'], 'xcache_is_autoglobal' => ['string', 'name'=>'string'], 'xcache_isset' => ['bool', 'name'=>'string'], 'xcache_list' => ['array', 'type'=>'int', 'id'=>'int'], 'xcache_set' => ['bool', 'name'=>'string', 'value'=>'mixed', 'ttl='=>'int'], 'xcache_unset' => ['bool', 'name'=>'string'], 'xcache_unset_by_prefix' => ['bool', 'prefix'=>'string'], 'xdebug_break' => ['bool'], 'xdebug_call_class' => ['string', 'depth='=>'int'], 'xdebug_call_file' => ['string', 'depth='=>'int'], 'xdebug_call_function' => ['string', 'depth='=>'int'], 'xdebug_call_line' => ['int', 'depth='=>'int'], 'xdebug_clear_aggr_profiling_data' => ['bool'], 'xdebug_code_coverage_started' => ['bool'], 'xdebug_debug_zval' => ['void', '...varName'=>'string'], 'xdebug_debug_zval_stdout' => ['void', '...varName'=>'string'], 'xdebug_disable' => ['void'], 'xdebug_dump_aggr_profiling_data' => ['bool'], 'xdebug_dump_superglobals' => ['void'], 'xdebug_enable' => ['void'], 'xdebug_get_code_coverage' => ['array'], 'xdebug_get_collected_errors' => ['string', 'clean='=>'bool'], 'xdebug_get_declared_vars' => ['array'], 'xdebug_get_formatted_function_stack' => [''], 'xdebug_get_function_count' => ['int'], 'xdebug_get_function_stack' => ['array', 'message='=>'string', 'options='=>'int'], 'xdebug_get_headers' => ['array'], 'xdebug_get_monitored_functions' => ['array'], 'xdebug_get_profiler_filename' => ['string|false'], 'xdebug_get_stack_depth' => ['int'], 'xdebug_get_tracefile_name' => ['string'], 'xdebug_is_debugger_active' => ['bool'], 'xdebug_is_enabled' => ['bool'], 'xdebug_memory_usage' => ['int'], 'xdebug_peak_memory_usage' => ['int'], 'xdebug_print_function_stack' => ['array', 'message='=>'string', 'options='=>'int'], 'xdebug_set_filter' => ['void', 'group'=>'int', 'list_type'=>'int', 'configuration'=>'array'], 'xdebug_start_code_coverage' => ['void', 'options='=>'int'], 'xdebug_start_error_collection' => ['void'], 'xdebug_start_function_monitor' => ['void', 'list_of_functions_to_monitor'=>'string[]'], 'xdebug_start_trace' => ['void', 'trace_file'=>'', 'options='=>'int|mixed'], 'xdebug_stop_code_coverage' => ['void', 'cleanup='=>'bool'], 'xdebug_stop_error_collection' => ['void'], 'xdebug_stop_function_monitor' => ['void'], 'xdebug_stop_trace' => ['void'], 'xdebug_time_index' => ['float'], 'xdebug_var_dump' => ['void', '...var'=>''], 'xdiff_file_bdiff' => ['bool', 'old_file'=>'string', 'new_file'=>'string', 'dest'=>'string'], 'xdiff_file_bdiff_size' => ['int', 'file'=>'string'], 'xdiff_file_bpatch' => ['bool', 'file'=>'string', 'patch'=>'string', 'dest'=>'string'], 'xdiff_file_diff' => ['bool', 'old_file'=>'string', 'new_file'=>'string', 'dest'=>'string', 'context='=>'int', 'minimal='=>'bool'], 'xdiff_file_diff_binary' => ['bool', 'old_file'=>'string', 'new_file'=>'string', 'dest'=>'string'], 'xdiff_file_merge3' => ['mixed', 'old_file'=>'string', 'new_file1'=>'string', 'new_file2'=>'string', 'dest'=>'string'], 'xdiff_file_patch' => ['mixed', 'file'=>'string', 'patch'=>'string', 'dest'=>'string', 'flags='=>'int'], 'xdiff_file_patch_binary' => ['bool', 'file'=>'string', 'patch'=>'string', 'dest'=>'string'], 'xdiff_file_rabdiff' => ['bool', 'old_file'=>'string', 'new_file'=>'string', 'dest'=>'string'], 'xdiff_string_bdiff' => ['string', 'old_data'=>'string', 'new_data'=>'string'], 'xdiff_string_bdiff_size' => ['int', 'patch'=>'string'], 'xdiff_string_bpatch' => ['string', 'string'=>'string', 'patch'=>'string'], 'xdiff_string_diff' => ['string', 'old_data'=>'string', 'new_data'=>'string', 'context='=>'int', 'minimal='=>'bool'], 'xdiff_string_diff_binary' => ['string', 'old_data'=>'string', 'new_data'=>'string'], 'xdiff_string_merge3' => ['mixed', 'old_data'=>'string', 'new_data1'=>'string', 'new_data2'=>'string', 'error='=>'string'], 'xdiff_string_patch' => ['string', 'string'=>'string', 'patch'=>'string', 'flags='=>'int', '&w_error='=>'string'], 'xdiff_string_patch_binary' => ['string', 'string'=>'string', 'patch'=>'string'], 'xdiff_string_rabdiff' => ['string', 'old_data'=>'string', 'new_data'=>'string'], 'xhprof_disable' => ['array'], 'xhprof_enable' => ['void', 'flags='=>'int', 'options='=>'array'], 'xhprof_sample_disable' => ['array'], 'xhprof_sample_enable' => ['void'], 'xlswriter_get_author' => ['string'], 'xlswriter_get_version' => ['string'], 'xml_error_string' => ['?string', 'error_code'=>'int'], 'xml_get_current_byte_index' => ['int|false', 'parser'=>'resource'], 'xml_get_current_column_number' => ['int|false', 'parser'=>'resource'], 'xml_get_current_line_number' => ['int|false', 'parser'=>'resource'], 'xml_get_error_code' => ['int|false', 'parser'=>'resource'], 'xml_parse' => ['int', 'parser'=>'resource', 'data'=>'string', 'is_final='=>'bool'], 'xml_parse_into_struct' => ['int', 'parser'=>'resource', 'data'=>'string', '&w_values'=>'array', '&w_index='=>'array'], 'xml_parser_create' => ['resource', 'encoding='=>'string'], 'xml_parser_create_ns' => ['resource', 'encoding='=>'string', 'separator='=>'string'], 'xml_parser_free' => ['bool', 'parser'=>'resource'], 'xml_parser_get_option' => ['string|int', 'parser'=>'resource', 'option'=>'int'], 'xml_parser_set_option' => ['bool', 'parser'=>'resource', 'option'=>'int', 'value'=>'mixed'], 'xml_set_character_data_handler' => ['true', 'parser'=>'resource', 'handler'=>'callable'], 'xml_set_default_handler' => ['true', 'parser'=>'resource', 'handler'=>'callable'], 'xml_set_element_handler' => ['true', 'parser'=>'resource', 'start_handler'=>'callable', 'end_handler'=>'callable'], 'xml_set_end_namespace_decl_handler' => ['true', 'parser'=>'resource', 'handler'=>'callable'], 'xml_set_external_entity_ref_handler' => ['true', 'parser'=>'resource', 'handler'=>'callable'], 'xml_set_notation_decl_handler' => ['true', 'parser'=>'resource', 'handler'=>'callable'], 'xml_set_object' => ['true', 'parser'=>'resource', 'object'=>'object'], 'xml_set_processing_instruction_handler' => ['true', 'parser'=>'resource', 'handler'=>'callable'], 'xml_set_start_namespace_decl_handler' => ['true', 'parser'=>'resource', 'handler'=>'callable'], 'xml_set_unparsed_entity_decl_handler' => ['true', 'parser'=>'resource', 'handler'=>'callable'], 'xmlrpc_decode' => ['mixed', 'xml'=>'string', 'encoding='=>'string'], 'xmlrpc_decode_request' => ['?array', 'xml'=>'string', '&w_method'=>'string', 'encoding='=>'string'], 'xmlrpc_encode' => ['string', 'value'=>'mixed'], 'xmlrpc_encode_request' => ['string', 'method'=>'string', 'params'=>'mixed', 'output_options='=>'array'], 'xmlrpc_get_type' => ['string', 'value'=>'mixed'], 'xmlrpc_is_fault' => ['bool', 'arg'=>'array'], 'xmlrpc_parse_method_descriptions' => ['array', 'xml'=>'string'], 'xmlrpc_server_add_introspection_data' => ['int', 'server'=>'resource', 'desc'=>'array'], 'xmlrpc_server_call_method' => ['string', 'server'=>'resource', 'xml'=>'string', 'user_data'=>'mixed', 'output_options='=>'array'], 'xmlrpc_server_create' => ['resource'], 'xmlrpc_server_destroy' => ['int', 'server'=>'resource'], 'xmlrpc_server_register_introspection_callback' => ['bool', 'server'=>'resource', 'function'=>'string'], 'xmlrpc_server_register_method' => ['bool', 'server'=>'resource', 'method_name'=>'string', 'function'=>'string'], 'xmlrpc_set_type' => ['bool', '&rw_value'=>'string|DateTime', 'type'=>'string'], 'xmlwriter_end_attribute' => ['bool', 'writer'=>'resource'], 'xmlwriter_end_cdata' => ['bool', 'writer'=>'resource'], 'xmlwriter_end_comment' => ['bool', 'writer'=>'resource'], 'xmlwriter_end_document' => ['bool', 'writer'=>'resource'], 'xmlwriter_end_dtd' => ['bool', 'writer'=>'resource'], 'xmlwriter_end_dtd_attlist' => ['bool', 'writer'=>'resource'], 'xmlwriter_end_dtd_element' => ['bool', 'writer'=>'resource'], 'xmlwriter_end_dtd_entity' => ['bool', 'writer'=>'resource'], 'xmlwriter_end_element' => ['bool', 'writer'=>'resource'], 'xmlwriter_end_pi' => ['bool', 'writer'=>'resource'], 'xmlwriter_flush' => ['string|int|false', 'writer'=>'resource', 'empty='=>'bool'], 'xmlwriter_full_end_element' => ['bool', 'writer'=>'resource'], 'xmlwriter_open_memory' => ['resource|false'], 'xmlwriter_open_uri' => ['resource|false', 'uri'=>'string'], 'xmlwriter_output_memory' => ['string', 'writer'=>'resource', 'flush='=>'bool'], 'xmlwriter_set_indent' => ['bool', 'writer'=>'resource', 'enable'=>'bool'], 'xmlwriter_set_indent_string' => ['bool', 'writer'=>'resource', 'indentation'=>'string'], 'xmlwriter_start_attribute' => ['bool', 'writer'=>'resource', 'name'=>'string'], 'xmlwriter_start_attribute_ns' => ['bool', 'writer'=>'resource', 'prefix'=>'string', 'name'=>'string', 'namespace'=>'?string'], 'xmlwriter_start_cdata' => ['bool', 'writer'=>'resource'], 'xmlwriter_start_comment' => ['bool', 'writer'=>'resource'], 'xmlwriter_start_document' => ['bool', 'writer'=>'resource', 'version='=>'?string', 'encoding='=>'?string', 'standalone='=>'?string'], 'xmlwriter_start_dtd' => ['bool', 'writer'=>'resource', 'qualifiedName'=>'string', 'publicId='=>'?string', 'systemId='=>'?string'], 'xmlwriter_start_dtd_attlist' => ['bool', 'writer'=>'resource', 'name'=>'string'], 'xmlwriter_start_dtd_element' => ['bool', 'writer'=>'resource', 'qualifiedName'=>'string'], 'xmlwriter_start_dtd_entity' => ['bool', 'writer'=>'resource', 'name'=>'string', 'isParam'=>'bool'], 'xmlwriter_start_element' => ['bool', 'writer'=>'resource', 'name'=>'string'], 'xmlwriter_start_element_ns' => ['bool', 'writer'=>'resource', 'prefix'=>'?string', 'name'=>'string', 'namespace'=>'?string'], 'xmlwriter_start_pi' => ['bool', 'writer'=>'resource', 'target'=>'string'], 'xmlwriter_text' => ['bool', 'writer'=>'resource', 'content'=>'string'], 'xmlwriter_write_attribute' => ['bool', 'writer'=>'resource', 'name'=>'string', 'value'=>'string'], 'xmlwriter_write_attribute_ns' => ['bool', 'writer'=>'resource', 'prefix'=>'string', 'name'=>'string', 'namespace'=>'?string', 'value'=>'string'], 'xmlwriter_write_cdata' => ['bool', 'writer'=>'resource', 'content'=>'string'], 'xmlwriter_write_comment' => ['bool', 'writer'=>'resource', 'content'=>'string'], 'xmlwriter_write_dtd' => ['bool', 'writer'=>'resource', 'name'=>'string', 'publicId='=>'?string', 'systemId='=>'?string', 'content='=>'?string'], 'xmlwriter_write_dtd_attlist' => ['bool', 'writer'=>'resource', 'name'=>'string', 'content'=>'string'], 'xmlwriter_write_dtd_element' => ['bool', 'writer'=>'resource', 'name'=>'string', 'content'=>'string'], 'xmlwriter_write_dtd_entity' => ['bool', 'writer'=>'resource', 'name'=>'string', 'content'=>'string', 'isParam'=>'bool', 'publicId'=>'string', 'systemId'=>'string', 'notationData'=>'string'], 'xmlwriter_write_element' => ['bool', 'writer'=>'resource', 'name'=>'string', 'content'=>'?string'], 'xmlwriter_write_element_ns' => ['bool', 'writer'=>'resource', 'prefix'=>'?string', 'name'=>'string', 'namespace'=>'string', 'content'=>'?string'], 'xmlwriter_write_pi' => ['bool', 'writer'=>'resource', 'target'=>'string', 'content'=>'string'], 'xmlwriter_write_raw' => ['bool', 'writer'=>'resource', 'content'=>'string'], 'xpath_new_context' => ['XPathContext', 'dom_document'=>'DOMDocument'], 'xpath_register_ns' => ['bool', 'xpath_context'=>'xpathcontext', 'prefix'=>'string', 'uri'=>'string'], 'xpath_register_ns_auto' => ['bool', 'xpath_context'=>'xpathcontext', 'context_node='=>'object'], 'xptr_new_context' => ['XPathContext'], 'yac::__construct' => ['void', 'prefix='=>'string'], 'yac::__get' => ['mixed', 'key'=>'string'], 'yac::__set' => ['mixed', 'key'=>'string', 'value'=>'mixed'], 'yac::delete' => ['bool', 'keys'=>'string|array', 'ttl='=>'int'], 'yac::dump' => ['mixed', 'num'=>'int'], 'yac::flush' => ['bool'], 'yac::get' => ['mixed', 'key'=>'string|array', 'cas='=>'int'], 'yac::info' => ['array'], 'yaml_emit' => ['string', 'data'=>'mixed', 'encoding='=>'int', 'linebreak='=>'int', 'callbacks='=>'array'], 'yaml_emit_file' => ['bool', 'filename'=>'string', 'data'=>'mixed', 'encoding='=>'int', 'linebreak='=>'int', 'callbacks='=>'array'], 'yaml_parse' => ['mixed|false', 'input'=>'string', 'pos='=>'int', '&w_ndocs='=>'int', 'callbacks='=>'array'], 'yaml_parse_file' => ['mixed|false', 'filename'=>'string', 'pos='=>'int', '&w_ndocs='=>'int', 'callbacks='=>'array'], 'yaml_parse_url' => ['mixed|false', 'url'=>'string', 'pos='=>'int', '&w_ndocs='=>'int', 'callbacks='=>'array'], 'yaz_addinfo' => ['string', 'id'=>'resource'], 'yaz_ccl_conf' => ['void', 'id'=>'resource', 'config'=>'array'], 'yaz_ccl_parse' => ['bool', 'id'=>'resource', 'query'=>'string', '&w_result'=>'array'], 'yaz_close' => ['bool', 'id'=>'resource'], 'yaz_connect' => ['mixed', 'zurl'=>'string', 'options='=>'mixed'], 'yaz_database' => ['bool', 'id'=>'resource', 'databases'=>'string'], 'yaz_element' => ['bool', 'id'=>'resource', 'elementset'=>'string'], 'yaz_errno' => ['int', 'id'=>'resource'], 'yaz_error' => ['string', 'id'=>'resource'], 'yaz_es' => ['void', 'id'=>'resource', 'type'=>'string', 'args'=>'array'], 'yaz_es_result' => ['array', 'id'=>'resource'], 'yaz_get_option' => ['string', 'id'=>'resource', 'name'=>'string'], 'yaz_hits' => ['int', 'id'=>'resource', 'searchresult='=>'array'], 'yaz_itemorder' => ['void', 'id'=>'resource', 'args'=>'array'], 'yaz_present' => ['bool', 'id'=>'resource'], 'yaz_range' => ['void', 'id'=>'resource', 'start'=>'int', 'number'=>'int'], 'yaz_record' => ['string', 'id'=>'resource', 'pos'=>'int', 'type'=>'string'], 'yaz_scan' => ['void', 'id'=>'resource', 'type'=>'string', 'startterm'=>'string', 'flags='=>'array'], 'yaz_scan_result' => ['array', 'id'=>'resource', 'result='=>'array'], 'yaz_schema' => ['void', 'id'=>'resource', 'schema'=>'string'], 'yaz_search' => ['bool', 'id'=>'resource', 'type'=>'string', 'query'=>'string'], 'yaz_set_option' => ['', 'id'=>'', 'name'=>'string', 'value'=>'string', 'options'=>'array'], 'yaz_sort' => ['void', 'id'=>'resource', 'criteria'=>'string'], 'yaz_syntax' => ['void', 'id'=>'resource', 'syntax'=>'string'], 'yaz_wait' => ['mixed', '&rw_options='=>'array'], 'yp_all' => ['void', 'domain'=>'string', 'map'=>'string', 'callback'=>'string'], 'yp_cat' => ['array', 'domain'=>'string', 'map'=>'string'], 'yp_err_string' => ['string', 'errorcode'=>'int'], 'yp_errno' => ['int'], 'yp_first' => ['array', 'domain'=>'string', 'map'=>'string'], 'yp_get_default_domain' => ['string'], 'yp_master' => ['string', 'domain'=>'string', 'map'=>'string'], 'yp_match' => ['string', 'domain'=>'string', 'map'=>'string', 'key'=>'string'], 'yp_next' => ['array', 'domain'=>'string', 'map'=>'string', 'key'=>'string'], 'yp_order' => ['int', 'domain'=>'string', 'map'=>'string'], 'zem_get_extension_info_by_id' => [''], 'zem_get_extension_info_by_name' => [''], 'zem_get_extensions_info' => [''], 'zem_get_license_info' => [''], 'zend_current_obfuscation_level' => ['int'], 'zend_disk_cache_clear' => ['bool', 'namespace='=>'mixed|string'], 'zend_disk_cache_delete' => ['mixed|null', 'key'=>'string'], 'zend_disk_cache_fetch' => ['mixed|null', 'key'=>'string'], 'zend_disk_cache_store' => ['bool', 'key'=>'', 'value'=>'', 'ttl='=>'int|mixed'], 'zend_get_id' => ['array', 'all_ids='=>'all_ids|false'], 'zend_is_configuration_changed' => [''], 'zend_loader_current_file' => ['string'], 'zend_loader_enabled' => ['bool'], 'zend_loader_file_encoded' => ['bool'], 'zend_loader_file_licensed' => ['array'], 'zend_loader_install_license' => ['bool', 'license_file'=>'string', 'override'=>'bool'], 'zend_logo_guid' => ['string'], 'zend_obfuscate_class_name' => ['string', 'class_name'=>'string'], 'zend_obfuscate_function_name' => ['string', 'function_name'=>'string'], 'zend_optimizer_version' => ['string'], 'zend_runtime_obfuscate' => ['void'], 'zend_send_buffer' => ['null|false', 'buffer'=>'string', 'mime_type='=>'string', 'custom_headers='=>'string'], 'zend_send_file' => ['null|false', 'filename'=>'string', 'mime_type='=>'string', 'custom_headers='=>'string'], 'zend_set_configuration_changed' => [''], 'zend_shm_cache_clear' => ['bool', 'namespace='=>'mixed|string'], 'zend_shm_cache_delete' => ['mixed|null', 'key'=>'string'], 'zend_shm_cache_fetch' => ['mixed|null', 'key'=>'string'], 'zend_shm_cache_store' => ['bool', 'key'=>'', 'value'=>'', 'ttl='=>'int|mixed'], 'zend_thread_id' => ['int'], 'zend_version' => ['string'], 'zip_close' => ['void', 'zip'=>'resource'], 'zip_entry_close' => ['bool', 'zip_entry'=>'resource'], 'zip_entry_compressedsize' => ['int', 'zip_entry'=>'resource'], 'zip_entry_compressionmethod' => ['string', 'zip_entry'=>'resource'], 'zip_entry_filesize' => ['int', 'zip_entry'=>'resource'], 'zip_entry_name' => ['string|false', 'zip_entry'=>'resource'], 'zip_entry_open' => ['bool', 'zip_dp'=>'resource', 'zip_entry'=>'resource', 'mode='=>'string'], 'zip_entry_read' => ['string|false', 'zip_entry'=>'resource', 'len='=>'int'], 'zip_open' => ['resource|int|false', 'filename'=>'string'], 'zip_read' => ['resource', 'zip'=>'resource'], 'zlib_decode' => ['string|false', 'data'=>'string', 'max_length='=>'int'], 'zlib_encode' => ['string|false', 'data'=>'string', 'encoding'=>'int', 'level='=>'int'], 'zlib_get_coding_type' => ['string|false'], 'zookeeper_dispatch' => ['void'], ]; [ 'mysqli_execute_query' => ['mysqli_result|bool', 'mysql'=>'mysqli', 'query'=>'non-empty-string', 'params='=>'list|null'], 'mysqli::execute_query' => ['mysqli_result|bool', 'query'=>'non-empty-string', 'params='=>'list|null'], 'openssl_cipher_key_length' => ['positive-int|false', 'cipher_algo'=>'non-empty-string'], 'curl_upkeep' => ['bool', 'handle'=>'CurlHandle'], 'imap_is_open' => ['bool', 'imap'=>'IMAP\Connection'], 'ini_parse_quantity' => ['int', 'shorthand'=>'non-empty-string'], 'libxml_get_external_entity_loader' => ['(callable(string,string,array{directory:?string,intSubName:?string,extSubURI:?string,extSubSystem:?string}):(resource|string|null))|null'], 'memory_reset_peak_usage' => ['void'], 'sodium_crypto_stream_xchacha20_xor_ic' => ['string', 'message'=>'string', 'nonce'=>'non-empty-string', 'counter'=>'int', 'key'=>'non-empty-string'], 'ZipArchive::clearError' => ['void'], 'ZipArchive::getStreamIndex' => ['resource|false', 'index'=>'int', 'flags='=>'int'], 'ZipArchive::getStreamName' => ['resource|false', 'name'=>'string', 'flags='=>'int'], 'DateTimeInterface::__serialize' => ['array'], 'DateTimeInterface::__unserialize' => ['void', 'data'=>'array'], ], 'changed' => [ 'dba_open' => [ 'old' => ['resource', 'path'=>'string', 'mode'=>'string', 'handler='=>'string', '...handler_params='=>'string'], 'new' => ['resource', 'path'=>'string', 'mode'=>'string', 'handler='=>'?string', 'permission='=>'int', 'map_size='=>'int', 'flags='=>'?int'], ], 'dba_popen' => [ 'old' => ['resource', 'path'=>'string', 'mode'=>'string', 'handler='=>'string', '...handler_params='=>'string'], 'new' => ['resource', 'path'=>'string', 'mode'=>'string', 'handler='=>'?string', 'permission='=>'int', 'map_size='=>'int', 'flags='=>'?int'], ], 'iterator_count' => [ 'old' => ['0|positive-int', 'iterator'=>'Traversable'], 'new' => ['0|positive-int', 'iterator'=>'Traversable|array'], ], 'iterator_to_array' => [ 'old' => ['array', 'iterator'=>'Traversable', 'preserve_keys='=>'bool'], 'new' => ['array', 'iterator'=>'Traversable|array', 'preserve_keys='=>'bool'], ], 'str_split' => [ 'old' => ['non-empty-list', 'string'=>'string', 'length='=>'positive-int'], 'new' => ['list', 'string'=>'string', 'length='=>'positive-int'], ], 'mb_get_info' => [ 'old' => ['array|string|int|false', 'type='=>'string'], 'new' => ['array|string|int|false|null', 'type='=>'string'], ], 'strcmp' => [ 'old' => ['int', 'string1' => 'string', 'string2' => 'string'], 'new' => ['int<-1,1>', 'string1' => 'string', 'string2' => 'string'], ], 'strcasecmp' => [ 'old' => ['int', 'string1' => 'string', 'string2' => 'string'], 'new' => ['int<-1,1>', 'string1' => 'string', 'string2' => 'string'], ], 'strnatcasecmp' => [ 'old' => ['int', 'string1' => 'string', 'string2' => 'string'], 'new' => ['int<-1,1>', 'string1' => 'string', 'string2' => 'string'], ], 'strnatcmp' => [ 'old' => ['int', 'string1' => 'string', 'string2' => 'string'], 'new' => ['int<-1,1>', 'string1' => 'string', 'string2' => 'string'], ], 'strncmp' => [ 'old' => ['int', 'string1'=>'string', 'string2'=>'string', 'length'=>'int'], 'new' => ['int<-1,1>', 'string1' => 'string', 'string2' => 'string', 'length'=>'positive-int|0'], ], 'strncasecmp' => [ 'old' => ['int', 'string1'=>'string', 'string2'=>'string', 'length'=>'int'], 'new' => ['int<-1,1>', 'string1' => 'string', 'string2' => 'string', 'length'=>'positive-int|0'], ], ], 'removed' => [ ], ]; >> */ return [ 'exec' => [['shell']], 'create_function' => [[], ['eval']], 'file_get_contents' => [['file']], 'file_put_contents' => [['file']], 'fopen' => [['file']], 'unlink' => [['file']], 'copy' => [['file'], ['file']], 'file' => [['file']], 'link' => [['file'], ['file']], 'mkdir' => [['file']], 'move_uploaded_file' => [['file'], ['file']], 'parse_ini_file' => [['file']], 'chown' => [['file']], 'lchown' => [['file']], 'readfile' => [['file']], 'rename' => [['file'], ['file']], 'rmdir' => [['file']], 'header' => [['header']], 'symlink' => [['file']], 'tempnam' => [['file']], 'igbinary_unserialize' => [['unserialize']], 'ldap_search' => [[], ['ldap'], ['ldap']], 'mysqli_query' => [[], ['sql']], 'mysqli::query' => [['sql']], 'mysqli_real_query' => [[], ['sql']], 'mysqli::real_query' => [['sql']], 'mysqli_multi_query' => [[], ['sql']], 'mysqli::multi_query' => [['sql']], 'mysqli_prepare' => [[], ['sql']], 'mysqli::prepare' => [['sql']], 'mysqli_stmt::__construct' => [[], ['sql']], 'mysqli_stmt_prepare' => [[], ['sql']], 'mysqli_stmt::prepare' => [['sql']], 'passthru' => [['shell']], 'pcntl_exec' => [['shell']], 'pg_exec' => [[], ['sql']], 'pg_prepare' => [[], [], ['sql']], 'pg_put_line' => [[], ['sql']], 'pg_query' => [[], ['sql']], 'pg_query_params' => [[], ['sql']], 'pg_send_prepare' => [[], [], ['sql']], 'pg_send_query' => [[], ['sql']], 'pg_send_query_params' => [[], ['sql'], []], 'setcookie' => [['cookie'], ['cookie']], 'shell_exec' => [['shell']], 'system' => [['shell']], 'unserialize' => [['unserialize']], 'popen' => [['shell']], 'proc_open' => [['shell']], 'curl_init' => [['ssrf']], 'curl_setopt' => [[], [], ['ssrf']], 'getimagesize' => [['ssrf']], ]; [ 'ReflectionProperty::getType' => ['?ReflectionType'], 'ReflectionProperty::isInitialized' => ['bool', 'object'=>'object'], 'mb_str_split' => ['list|false', 'string'=>'string', 'length='=>'positive-int', 'encoding='=>'string'], 'openssl_x509_verify' => ['int', 'certificate'=>'string|resource', 'public_key'=>'string|array|resource'], ], 'changed' => [ 'Locale::lookup' => [ 'old' => ['?string', 'languageTag'=>'array', 'locale'=>'string', 'canonicalize='=>'bool', 'defaultLocale='=>'string'], 'new' => ['?string', 'languageTag'=>'array', 'locale'=>'string', 'canonicalize='=>'bool', 'defaultLocale='=>'?string'], ], 'SplFileObject::fwrite' => [ 'old' => ['int', 'data'=>'string', 'length='=>'int'], 'new' => ['int|false', 'data'=>'string', 'length='=>'int'], ], 'SplTempFileObject::fwrite' => [ 'old' => ['int', 'data'=>'string', 'length='=>'int'], 'new' => ['int|false', 'data'=>'string', 'length='=>'int'], ], 'array_merge' => [ 'old' => ['array', '...arrays'=>'array'], 'new' => ['array', '...arrays='=>'array'], ], 'array_merge_recursive' => [ 'old' => ['array', '...arrays'=>'array'], 'new' => ['array', '...arrays='=>'array'], ], 'gzread' => [ 'old' => ['string|0', 'stream'=>'resource', 'length'=>'int'], 'new' => ['string|false', 'stream'=>'resource', 'length'=>'int'], ], 'locale_lookup' => [ 'old' => ['?string', 'languageTag'=>'array', 'locale'=>'string', 'canonicalize='=>'bool', 'defaultLocale='=>'string'], 'new' => ['?string', 'languageTag'=>'array', 'locale'=>'string', 'canonicalize='=>'bool', 'defaultLocale='=>'?string'], ], 'openssl_random_pseudo_bytes' => [ 'old' => ['string|false', 'length'=>'int', '&w_strong_result='=>'bool'], 'new' => ['string', 'length'=>'int', '&w_strong_result='=>'bool'], ], 'password_hash' => [ 'old' => ['string|false', 'password'=>'string', 'algo'=>'int', 'options='=>'array'], 'new' => ['string|false', 'password'=>'string', 'algo'=>'int|string|null', 'options='=>'array'], ], 'password_needs_rehash' => [ 'old' => ['bool', 'hash'=>'string', 'algo'=>'int', 'options='=>'array'], 'new' => ['bool', 'hash'=>'string', 'algo'=>'int|string|null', 'options='=>'array'], ], 'preg_replace_callback' => [ 'old' => ['string|null', 'pattern'=>'string|array', 'callback'=>'callable(string[]):string', 'subject'=>'string', 'limit='=>'int', '&w_count='=>'int'], 'new' => ['string|null', 'pattern'=>'string|array', 'callback'=>'callable(string[]):string', 'subject'=>'string', 'limit='=>'int', '&w_count='=>'int', 'flags='=>'int'], ], 'preg_replace_callback\'1' => [ 'old' => ['string[]|null', 'pattern'=>'string|array', 'callback'=>'callable(string[]):string', 'subject'=>'string[]', 'limit='=>'int', '&w_count='=>'int'], 'new' => ['string[]|null', 'pattern'=>'string|array', 'callback'=>'callable(string[]):string', 'subject'=>'string[]', 'limit='=>'int', '&w_count='=>'int', 'flags='=>'int'], ], 'preg_replace_callback_array' => [ 'old' => ['string|null', 'pattern'=>'array', 'subject'=>'string', 'limit='=>'int', '&w_count='=>'int'], 'new' => ['string|null', 'pattern'=>'array', 'subject'=>'string', 'limit='=>'int', '&w_count='=>'int', 'flags='=>'int'], ], 'preg_replace_callback_array\'1' => [ 'old' => ['string[]|null', 'pattern'=>'array', 'subject'=>'string[]', 'limit='=>'int', '&w_count='=>'int'], 'new' => ['string[]|null', 'pattern'=>'array', 'subject'=>'string[]', 'limit='=>'int', '&w_count='=>'int', 'flags='=>'int'], ], 'proc_open' => [ 'old' => ['resource|false', 'command'=>'string', 'descriptor_spec'=>'array', '&pipes'=>'resource[]', 'cwd='=>'?string', 'env_vars='=>'?array', 'options='=>'?array'], 'new' => ['resource|false', 'command'=>'string|array', 'descriptor_spec'=>'array', '&pipes'=>'resource[]', 'cwd='=>'?string', 'env_vars='=>'?array', 'options='=>'?array'], ], 'strip_tags' => [ 'old' => ['string', 'string'=>'string', 'allowed_tags='=>'string'], 'new' => ['string', 'string'=>'string', 'allowed_tags='=>'string|list'], ], ], 'removed' => [ ], ]; [ 'endColumn' => 'int', 'endLine' => 'int', 'firstChild' => 'Node|null', 'lastChild' => 'Node|null', 'next' => 'Node|null', 'parent' => 'Node|null', 'previous' => 'Node|null', 'startColumn' => 'int', 'startLine' => 'int', ], 'commonmark\\node\\bulletlist' => [ 'delimiter' => 'int', 'tight' => 'bool', ], 'commonmark\\node\\codeblock' => [ 'fence' => 'string|null', ], 'commonmark\\node\\customblock' => [ 'onEnter' => 'string|null', 'onLeave' => 'string|null', ], 'commonmark\\node\\custominline' => [ 'onEnter' => 'string|null', 'onLeave' => 'string|null', ], 'commonmark\\node\\heading' => [ 'level' => 'int', ], 'commonmark\\node\\image' => [ 'title' => 'string|null', 'url' => 'string|null', ], 'commonmark\\node\\link' => [ 'title' => 'string|null', 'url' => 'string|null', ], 'commonmark\\node\\orderedlist' => [ 'delimiter' => 'int', 'start' => 'int', 'tight' => 'bool', ], 'commonmark\\node\\text' => [ 'literal' => 'string|null', ], 'curlfile' => [ 'mime' => 'string', 'name' => 'string', 'postname' => 'string', ], 'curlstringfile' => [ 'data' => 'string', 'mime' => 'string', 'postname' => 'string', ], 'dateinterval' => [ 'd' => 'int', 'date_string' => 'string', 'days' => 'false|int', 'f' => 'float', 'from_string' => 'bool', 'h' => 'int', 'i' => 'int', 'invert' => 'int', 'm' => 'int', 's' => 'int', 'y' => 'int', ], 'dateperiod' => [ 'current' => 'DateTimeInterface', 'end' => 'DateTimeInterface', 'include_start_date' => 'bool', 'interval' => 'DateInterval', 'recurrences' => 'int', 'start' => 'DateTimeInterface', ], 'directory' => [ 'handle' => 'resource', 'path' => 'string', ], 'domattr' => [ 'name' => 'string', 'ownerElement' => 'DOMElement|null', 'schemaTypeInfo' => 'mixed', 'specified' => 'bool', 'value' => 'string', ], 'domcharacterdata' => [ 'data' => 'string', 'length' => 'int', 'nextElementSibling' => 'DOMElement|null', 'previousElementSibling' => 'DOMElement|null', ], 'domdocument' => [ 'actualEncoding' => 'string|null', 'childElementCount' => 'int', 'config' => 'mixed', 'doctype' => 'DOMDocumentType|null', 'documentElement' => 'DOMElement|null', 'documentURI' => 'string|null', 'encoding' => 'string|null', 'firstElementChild' => 'DOMElement|null', 'formatOutput' => 'bool', 'implementation' => 'DOMImplementation', 'lastElementChild' => 'DOMElement|null', 'ownerDocument' => 'null', 'preserveWhiteSpace' => 'bool', 'recover' => 'bool', 'resolveExternals' => 'bool', 'standalone' => 'bool', 'strictErrorChecking' => 'bool', 'substituteEntities' => 'bool', 'validateOnParse' => 'bool', 'version' => 'string|null', 'xmlEncoding' => 'string|null', 'xmlStandalone' => 'bool', 'xmlVersion' => 'string|null', ], 'domdocumentfragment' => [ 'childElementCount' => 'int', 'firstelementChild' => 'DOMElement|null', 'lastelementChild' => 'DOMElement|null', ], 'domdocumenttype' => [ 'entities' => 'DOMNamedNodeMap', 'internalsubset' => 'string|null', 'name' => 'string', 'notations' => 'DOMNamedNodeMap', 'publicid' => 'string', 'systemid' => 'string', ], 'domelement' => [ 'childElementCount' => 'int', 'firstElementChild' => 'DOMElement|null', 'lastElementChild' => 'DOMElement|null', 'nextElementSibling' => 'DOMElement|null', 'previousElementSibling' => 'DOMElement|null', 'schemaTypeInfo' => 'mixed', 'tagName' => 'string', ], 'domentity' => [ 'actualEncoding' => 'string|null', 'encoding' => 'string|null', 'notationName' => 'string|null', 'publicid' => 'string|null', 'systemid' => 'string|null', 'version' => 'string|null', ], 'domexception' => [ 'code' => 'int', ], 'domnamednodemap' => [ 'length' => 'int', ], 'domnode' => [ 'attributes' => 'DOMNamedNodeMap|null', 'baseURI' => 'string|null', 'childNodes' => 'DOMNodeList', 'firstChild' => 'DOMNode|null', 'lastChild' => 'DOMNode|null', 'localName' => 'string|null', 'namespaceURI' => 'string|null', 'nextSibling' => 'DOMNode|null', 'nodeName' => 'string', 'nodeType' => 'int', 'nodeValue' => 'string|null', 'ownerDocument' => 'DOMDocument', 'parentNode' => 'DOMNode|null', 'prefix' => 'string', 'previousSibling' => 'DOMNode|null', 'textContent' => 'string', ], 'domnodelist' => [ 'length' => 'int', ], 'domnotation' => [ 'publicId' => 'string', 'systemId' => 'string', ], 'domprocessinginstruction' => [ 'data' => 'string', 'target' => 'string', ], 'domtext' => [ 'wholeText' => 'string', ], 'domxpath' => [ 'document' => 'DOMDocument', 'registerNodeNamespaces' => 'bool', ], 'errorexception' => [ 'severity' => 'int', ], 'event' => [ 'pending' => 'bool', ], 'eventbuffer' => [ 'contiguous_space' => 'int', 'length' => 'int', ], 'eventbufferevent' => [ 'fd' => 'int', 'input' => 'EventBuffer', 'output' => 'EventBuffer', 'priority' => 'int', ], 'eventlistener' => [ 'fd' => 'int', ], 'eventsslcontext' => [ 'local_cert' => 'string', 'local_pk' => 'string', ], 'libxmlerror' => [ 'code' => 'int', 'column' => 'int', 'file' => 'string', 'level' => 'int', 'line' => 'int', 'message' => 'string', ], 'mongoclient' => [ 'connected' => 'boolean', 'status' => 'string', ], 'mongocollection' => [ 'db' => 'MongoDB', 'w' => 'integer', 'wtimeout' => 'integer', ], 'mongocursor' => [ 'slaveokay' => 'boolean', 'timeout' => 'integer', ], 'mongodb' => [ 'w' => 'integer', 'wtimeout' => 'integer', ], 'mongodb\\driver\\exception\\commandexception' => [ 'resultdocument' => 'object', ], 'mongodb\\driver\\exception\\runtimeexception' => [ 'errorlabels' => 'array|null', ], 'mongodb\\driver\\exception\\writeexception' => [ 'writeresult' => 'MongoDB\\Driver\\WriteResult', ], 'mongoid' => [ 'id' => 'string', ], 'mongoint32' => [ 'value' => 'string', ], 'mongoint64' => [ 'value' => 'string', ], 'mysqli' => [ 'affected_rows' => 'int<-1, max>|numeric-string', 'client_info' => 'string', 'client_version' => 'int', 'connect_errno' => 'int', 'connect_error' => 'string|null', 'errno' => 'int', 'error' => 'string', 'error_list' => 'array', 'field_count' => 'int', 'host_info' => 'string', 'info' => 'string|null', 'insert_id' => 'int|string', 'protocol_version' => 'int', 'server_info' => 'string', 'server_version' => 'int', 'sqlstate' => 'string', 'thread_id' => 'int', 'warning_count' => 'int', ], 'mysqli_driver' => [ 'client_info' => 'string', 'client_version' => 'int', 'driver_version' => 'int', 'embedded' => 'bool', 'reconnect' => 'bool', 'report_mode' => 'int', ], 'mysqli_result' => [ 'current_field' => 'int', 'field_count' => 'int', 'lengths' => 'array|null', 'num_rows' => 'int<0, max>|numeric-string', 'type' => 'int', ], 'mysqli_sql_exception' => [ 'sqlstate' => 'string', ], 'mysqli_stmt' => [ 'affected_rows' => 'int<-1, max>|numeric-string', 'errno' => 'int', 'error' => 'string', 'error_list' => 'array', 'field_count' => 'int', 'id' => 'int', 'insert_id' => 'int|string', 'num_rows' => 'int<0, max>|numeric-string', 'param_count' => 'int', 'sqlstate' => 'string', ], 'mysqli_warning' => [ 'errno' => 'int', 'message' => 'string', 'sqlstate' => 'string', ], 'parallel\\events\\event' => [ 'object' => 'object', 'source' => 'string', 'type' => 'int', ], 'parle\\errorinfo' => [ 'id' => 'int', 'position' => 'int', 'token' => 'mixed', ], 'parle\\lexer' => [ 'bol' => 'bool', 'cursor' => 'int', 'flags' => 'int', 'marker' => 'int', 'state' => 'int', ], 'parle\\parser' => [ 'action' => 'int', 'reduceid' => 'int', ], 'parle\\rlexer' => [ 'bol' => 'bool', 'cursor' => 'int', 'flags' => 'int', 'marker' => 'int', 'state' => 'int', ], 'parle\\rparser' => [ 'action' => 'int', 'reduceid' => 'int', ], 'parle\\stack' => [ 'empty' => 'bool', 'size' => 'int', 'top' => 'mixed', ], 'parle\\token' => [ 'id' => 'int', 'value' => 'string', ], 'pdoexception' => [ 'code' => 'int|string', 'errorInfo' => 'array|null', ], 'pdostatement' => [ 'queryString' => 'string', ], 'php_user_filter' => [ 'filtername' => 'string', 'params' => 'mixed', 'stream' => 'resource|null', ], 'phpparser\\node\\expr\\array_' => [ 'items' => 'array', ], 'phpparser\\node\\expr\\arrowfunction' => [ 'params' => 'list', ], 'phpparser\\node\\expr\\closure' => [ 'params' => 'list', ], 'phpparser\\node\\expr\\list_' => [ 'items' => 'array', ], 'phpparser\\node\\expr\\shellexec' => [ 'parts' => 'list', ], 'phpparser\\node\\matcharm' => [ 'conds' => 'null|non-empty-list', ], 'phpparser\\node\\name' => [ 'parts' => 'non-empty-list', ], 'phpparser\\node\\stmt\\case_' => [ 'stmts' => 'list', ], 'phpparser\\node\\stmt\\catch_' => [ 'stmts' => 'list', ], 'phpparser\\node\\stmt\\class_' => [ 'stmts' => 'list', ], 'phpparser\\node\\stmt\\do_' => [ 'stmts' => 'list', ], 'phpparser\\node\\stmt\\else_' => [ 'stmts' => 'list', ], 'phpparser\\node\\stmt\\elseif_' => [ 'stmts' => 'list', ], 'phpparser\\node\\stmt\\finally_' => [ 'stmts' => 'list', ], 'phpparser\\node\\stmt\\for_' => [ 'stmts' => 'list', ], 'phpparser\\node\\stmt\\foreach_' => [ 'stmts' => 'list', ], 'phpparser\\node\\stmt\\if_' => [ 'stmts' => 'list', ], 'phpparser\\node\\stmt\\interface_' => [ 'stmts' => 'list', ], 'phpparser\\node\\stmt\\namespace_' => [ 'stmts' => 'list', ], 'phpparser\\node\\stmt\\trait_' => [ 'stmts' => 'list', ], 'phpparser\\node\\stmt\\trycatch' => [ 'stmts' => 'list', ], 'phpparser\\node\\stmt\\while_' => [ 'stmts' => 'list', ], 'phptoken' => [ 'id' => 'int', 'line' => 'int', 'pos' => 'int', 'text' => 'string', ], 'rdkafka\\message' => [ 'err' => 'int', 'headers' => 'array|null', 'key' => 'string|null', 'offset' => 'int', 'partition' => 'int', 'payload' => 'string', 'timestamp' => 'int', 'topic_name' => 'string', ], 'reflectionextension' => [ 'name' => 'string', ], 'reflectionfunctionabstract' => [ 'name' => 'string', ], 'reflectionzendextension' => [ 'name' => 'string', ], 'snmp' => [ 'enum_print' => 'bool', 'exceptions_enabled' => 'int', 'info' => 'array', 'max_oids' => 'int|null', 'oid_increasing_check' => 'bool', 'oid_output_format' => 'int', 'quick_print' => 'bool', 'valueretrieval' => 'int', ], 'snmpexception' => [ 'code' => 'string', ], 'soapclient' => [ '__default_headers' => 'array|null', '__last_request' => 'string|null', '__last_request_headers' => 'string|null', '__last_response' => 'string|null', '__last_response_headers' => 'string|null', '__soap_fault' => 'SoapFault|null', '_classmap' => 'array|null', '_connection_timeout' => 'int', '_cookies' => 'array', '_digest' => 'string|null', '_encoding' => 'string|null', '_exceptions' => 'bool', '_features' => 'int|null', '_keep_alive' => 'bool', '_login' => 'string|null', '_password' => 'string|null', '_proxy_host' => 'string|null', '_proxy_login' => 'string|null', '_proxy_password' => 'string|null', '_proxy_port' => 'int|null', '_soap_version' => 'int', '_ssl_method' => 'int|null', '_stream_context' => 'resource|null', '_use_digest' => 'bool', '_use_proxy' => 'int|null', '_user_agent' => 'string|null', 'compression' => 'int|null', 'httpsocket' => 'resource|null', 'httpurl' => 'resource|null', 'location' => 'string|null', 'sdl' => 'resource|null', 'style' => 'int|null', 'trace' => 'bool', 'typemap' => 'resource|null', 'uri' => 'string|null', 'use' => 'int|null', ], 'soapfault' => [ '_name' => 'string|null', 'detail' => 'mixed', 'faultactor' => 'string|null', 'faultcode' => 'string|null', 'faultcodens' => 'string|null', 'faultstring' => 'string', 'headerfault' => 'mixed', ], 'soapheader' => [ 'actor' => 'string|int|null', 'data' => 'mixed', 'mustUnderstand' => 'bool', 'name' => 'string', 'namespace' => 'string', ], 'soapparam' => [ 'param_data' => 'mixed', 'param_name' => 'string', ], 'soapserver' => [ '__soap_fault' => 'SoapFault|null', 'service' => 'resource', ], 'soapvar' => [ 'enc_name' => 'string|null', 'enc_namens' => 'string|null', 'enc_ns' => 'string|null', 'enc_stype' => 'string|null', 'enc_type' => 'int', 'enc_value' => 'mixed', ], 'solrdocumentfield' => [ 'boost' => 'float', 'name' => 'string', 'values' => 'array', ], 'solrexception' => [ 'sourcefile' => 'string', 'sourceline' => 'int', 'zif_name' => 'string', ], 'solrresponse' => [ 'http_digested_response' => 'string', 'http_raw_request' => 'string', 'http_raw_request_headers' => 'string', 'http_raw_response' => 'string', 'http_raw_response_headers' => 'string', 'http_request_url' => 'string', 'http_status' => 'int', 'http_status_message' => 'string', 'parser_mode' => 'int', 'success' => 'bool', ], 'streamwrapper' => [ 'context' => 'resource', ], 'tidy' => [ 'errorBuffer' => 'string', 'value' => 'string|null', ], 'tidynode' => [ 'attribute' => 'array|null', 'child' => 'array|null', 'column' => 'int', 'id' => 'int|null', 'line' => 'int', 'name' => 'string', 'proprietary' => 'bool', 'type' => 'int', 'value' => 'string', ], 'tokyotyrantexception' => [ 'code' => 'int', ], 'transliterator' => [ 'id' => 'string', ], 'xmlreader' => [ 'attributeCount' => 'int', 'baseURI' => 'string', 'depth' => 'int', 'hasAttributes' => 'bool', 'hasValue' => 'bool', 'isDefault' => 'bool', 'isEmptyElement' => 'bool', 'localName' => 'string', 'name' => 'string', 'namespaceURI' => 'string', 'nodeType' => 'int', 'prefix' => 'string', 'value' => 'string', 'xmlLang' => 'string', ], 'ziparchive' => [ 'comment' => 'string', 'filename' => 'string', 'lastId' => 'int', 'numFiles' => 'int', 'status' => 'int', 'statusSys' => 'int', ], ]; true, 'chgrp' => true, 'chmod' => true, 'chown' => true, 'chroot' => true, 'copy' => true, 'file_get_contents' => true, 'file_put_contents' => true, 'opendir' => true, 'readdir' => true, 'closedir' => true, 'rewinddir' => true, 'scandir' => true, 'fopen' => true, 'fread' => true, 'fwrite' => true, 'fclose' => true, 'touch' => true, 'fpassthru' => true, 'fputs' => true, 'fscanf' => true, 'fseek' => true, 'flock' => true, 'ftruncate' => true, 'fprintf' => true, 'symlink' => true, 'mkdir' => true, 'unlink' => true, 'rename' => true, 'rmdir' => true, 'popen' => true, 'pclose' => true, 'fgetcsv' => true, 'fputcsv' => true, 'umask' => true, 'finfo_open' => true, 'finfo_close' => true, 'finfo_file' => true, 'stream_set_timeout' => true, 'fgets' => true, 'fflush' => true, 'move_uploaded_file' => true, 'file_exists' => true, 'realpath' => true, 'glob' => true, 'is_readable' => true, 'is_dir' => true, 'is_file' => true, // stream/socket io 'stream_context_set_option' => true, 'socket_write' => true, 'stream_set_blocking' => true, 'socket_close' => true, 'socket_set_option' => true, 'stream_set_write_buffer' => true, 'stream_socket_enable_crypto' => true, 'stream_copy_to_stream' => true, 'stream_wrapper_register' => true, 'socket_connect' => true, 'socket_bind' => true, 'socket_set_block' => true, 'socket_set_nonblock' => true, 'socket_listen' => true, 'stream_socket_shutdown' => true, 'socket_shutdown' => true, // meta calls 'call_user_func' => true, 'call_user_func_array' => true, 'define' => true, 'create_function' => true, // http 'header' => true, 'header_remove' => true, 'http_response_code' => true, 'setcookie' => true, 'setrawcookie' => true, // output buffer 'ob_start' => true, 'ob_end_clean' => true, 'ob_get_clean' => true, 'readfile' => true, 'readgzfile' => true, 'printf' => true, 'var_dump' => true, 'phpinfo' => true, 'ob_implicit_flush' => true, 'vprintf' => true, // mcrypt 'mcrypt_generic_init' => true, 'mcrypt_generic_deinit' => true, 'mcrypt_module_close' => true, // internal optimisation 'clearstatcache' => true, // process-related 'pcntl_signal' => true, 'pcntl_alarm' => true, 'posix_kill' => true, 'cli_set_process_title' => true, 'pcntl_async_signals' => true, 'proc_close' => true, 'proc_nice' => true, 'proc_open' => true, 'proc_terminate' => true, // curl 'curl_setopt' => true, 'curl_close' => true, 'curl_multi_add_handle' => true, 'curl_multi_remove_handle' => true, 'curl_multi_select' => true, 'curl_multi_close' => true, 'curl_setopt_array' => true, // apc, apcu 'apc_store' => true, 'apc_delete' => true, 'apc_clear_cache' => true, 'apc_add' => true, 'apc_inc' => true, 'apc_dec' => true, 'apc_cas' => true, 'apcu_store' => true, 'apcu_delete' => true, 'apcu_clear_cache' => true, 'apcu_add' => true, 'apcu_inc' => true, 'apcu_dec' => true, 'apcu_cas' => true, // gz 'gzwrite' => true, 'gzrewind' => true, 'gzseek' => true, 'gzclose' => true, // newrelic 'newrelic_start_transaction' => true, 'newrelic_name_transaction' => true, 'newrelic_add_custom_parameter' => true, 'newrelic_add_custom_tracer' => true, 'newrelic_background_job' => true, 'newrelic_end_transaction' => true, 'newrelic_set_appname' => true, // execution 'shell_exec' => true, 'exec' => true, 'system' => true, 'passthru' => true, 'pcntl_exec' => true, // well-known functions 'libxml_use_internal_errors' => true, 'libxml_disable_entity_loader' => true, 'curl_exec' => true, 'mt_srand' => true, 'openssl_pkcs7_sign' => true, 'openssl_sign' => true, 'mt_rand' => true, 'rand' => true, 'random_int' => true, 'random_bytes' => true, 'wincache_ucache_delete' => true, 'wincache_ucache_set' => true, 'wincache_ucache_inc' => true, 'class_alias' => true, 'class_exists' => true, // impure by virtue of triggering autoloader 'enum_exists' => true, // impure by virtue of triggering autoloader // php environment 'ini_set' => true, 'sleep' => true, 'usleep' => true, 'register_shutdown_function' => true, 'error_reporting' => true, 'register_tick_function' => true, 'unregister_tick_function' => true, 'set_error_handler' => true, 'user_error' => true, 'trigger_error' => true, 'restore_error_handler' => true, 'date_default_timezone_set' => true, 'assert_options' => true, 'setlocale' => true, 'set_exception_handler' => true, 'set_time_limit' => true, 'putenv' => true, 'spl_autoload_register' => true, 'spl_autoload_unregister' => true, 'microtime' => true, 'array_rand' => true, 'set_include_path' => true, // logging 'openlog' => true, 'syslog' => true, 'error_log' => true, 'define_syslog_variables' => true, // session 'session_id' => true, 'session_decode' => true, 'session_name' => true, 'session_set_cookie_params' => true, 'session_set_save_handler' => true, 'session_regenerate_id' => true, 'mb_internal_encoding' => true, 'session_start' => true, 'session_cache_limiter' => true, // ldap 'ldap_set_option' => true, // iterators 'rewind' => true, 'iterator_apply' => true, 'iterator_to_array' => true, // mysqli 'mysqli_select_db' => true, 'mysqli_dump_debug_info' => true, 'mysqli_kill' => true, 'mysqli_multi_query' => true, 'mysqli_next_result' => true, 'mysqli_options' => true, 'mysqli_ping' => true, 'mysqli_query' => true, 'mysqli_report' => true, 'mysqli_rollback' => true, 'mysqli_savepoint' => true, 'mysqli_set_charset' => true, 'mysqli_ssl_set' => true, 'mysqli_close' => true, // script execution 'ignore_user_abort' => true, // ftp 'ftp_close' => true, 'ftp_pasv' => true, // bcmath 'bcscale' => true, // json 'json_last_error' => true, // opcache 'opcache_compile_file' => true, 'opcache_get_configuration' => true, 'opcache_get_status' => true, 'opcache_invalidate' => true, 'opcache_is_script_cached' => true, 'opcache_reset' => true, //gettext 'bindtextdomain' => true, // hash 'hash_update' => true, 'hash_update_file' => true, 'hash_update_stream' => true, // unserialize 'unserialize' => true, // openssl 'openssl_csr_export_to_file' => true, 'openssl_pkcs12_export_to_file' => true, 'openssl_pkey_export_to_file' => true, 'openssl_x509_export_to_file' => true, // xml 'xml_parser_set_option' => true, 'xml_parser_free' => true, // mail 'mail' => true, ]; [ 'array_is_list' => ['bool', 'array' => 'array'], 'enum_exists' => ['bool', 'enum' => 'string', 'autoload=' => 'bool'], 'fsync' => ['bool', 'stream' => 'resource'], 'fdatasync' => ['bool', 'stream' => 'resource'], 'imageavif' => ['bool', 'image'=>'GdImage', 'file='=>'resource|string|null', 'quality='=>'int', 'speed='=>'int'], 'imagecreatefromavif' => ['false|GdImage', 'filename'=>'string'], 'mysqli_fetch_column' => ['null|int|float|string|false', 'result'=>'mysqli_result', 'column='=>'int'], 'mysqli_result::fetch_column' => ['null|int|float|string|false', 'column='=>'int'], 'CURLStringFile::__construct' => ['void', 'data'=>'string', 'postname'=>'string', 'mime='=>'string'], 'Fiber::__construct' => ['void', 'callback'=>'callable'], 'Fiber::start' => ['mixed', '...args'=>'mixed'], 'Fiber::resume' => ['mixed', 'value='=>'null|mixed'], 'Fiber::throw' => ['mixed', 'exception'=>'Throwable'], 'Fiber::isStarted' => ['bool'], 'Fiber::isSuspended' => ['bool'], 'Fiber::isRunning' => ['bool'], 'Fiber::isTerminated' => ['bool'], 'Fiber::getReturn' => ['mixed'], 'Fiber::getCurrent' => ['?self'], 'Fiber::suspend' => ['mixed', 'value='=>'null|mixed'], 'FiberError::__construct' => ['void'], 'GMP::__serialize' => ['array'], 'GMP::__unserialize' => ['void', 'data'=>'array'], 'ReflectionClass::isEnum' => ['bool'], 'ReflectionEnum::getBackingType' => ['?ReflectionType'], 'ReflectionEnum::getCase' => ['ReflectionEnumUnitCase', 'name' => 'string'], 'ReflectionEnum::getCases' => ['list'], 'ReflectionEnum::hasCase' => ['bool', 'name' => 'string'], 'ReflectionEnum::isBacked' => ['bool'], 'ReflectionEnumUnitCase::getEnum' => ['ReflectionEnum'], 'ReflectionEnumUnitCase::getValue' => ['UnitEnum'], 'ReflectionEnumBackedCase::getBackingValue' => ['string|int'], 'ReflectionFunctionAbstract::getTentativeReturnType' => ['?ReflectionType'], 'ReflectionFunctionAbstract::hasTentativeReturnType' => ['bool'], 'ReflectionFunctionAbstract::isStatic' => ['bool'], 'ReflectionObject::isEnum' => ['bool'], 'ReflectionProperty::isReadonly' => ['bool'], 'sodium_crypto_stream_xchacha20' => ['non-empty-string', 'length'=>'positive-int', 'nonce'=>'non-empty-string', 'key'=>'non-empty-string'], 'sodium_crypto_stream_xchacha20_keygen' => ['non-empty-string'], 'sodium_crypto_stream_xchacha20_xor' => ['string', 'message'=>'string', 'nonce'=>'non-empty-string', 'key'=>'non-empty-string'], ], 'changed' => [ 'DOMDocument::createComment' => [ 'old' => ['DOMComment|false', 'data'=>'string'], 'new' => ['DOMComment', 'data'=>'string'], ], 'DOMDocument::createDocumentFragment' => [ 'old' => ['DOMDocumentFragment|false'], 'new' => ['DOMDocumentFragment'], ], 'DOMDocument::createTextNode' => [ 'old' => ['DOMText|false', 'data'=>'string'], 'new' => ['DOMText', 'data'=>'string'], ], 'Phar::buildFromDirectory' => [ 'old' => ['array|false', 'directory'=>'string', 'pattern='=>'string'], 'new' => ['array', 'directory'=>'string', 'pattern='=>'string'], ], 'Phar::buildFromIterator' => [ 'old' => ['array|false', 'iterator'=>'Traversable', 'baseDirectory='=>'?string'], 'new' => ['array', 'iterator'=>'Traversable', 'baseDirectory='=>'?string'], ], 'PharData::buildFromDirectory' => [ 'old' => ['array|false', 'directory'=>'string', 'pattern='=>'string'], 'new' => ['array', 'directory'=>'string', 'pattern='=>'string'], ], 'PharData::buildFromIterator' => [ 'old' => ['array|false', 'iterator'=>'Traversable', 'baseDirectory='=>'?string'], 'new' => ['array', 'iterator'=>'Traversable', 'baseDirectory='=>'?string'], ], 'SplFileObject::fputcsv' => [ 'old' => ['int|false', 'fields'=>'array', 'separator='=>'string', 'enclosure='=>'string', 'escape='=>'string'], 'new' => ['int|false', 'fields'=>'array', 'separator='=>'string', 'enclosure='=>'string', 'escape='=>'string', 'eol='=>'string'], ], 'SplTempFileObject::fputcsv' => [ 'old' => ['int|false', 'fields'=>'array', 'separator='=>'string', 'enclosure='=>'string', 'escape='=>'string'], 'new' => ['int|false', 'fields'=>'array', 'separator='=>'string', 'enclosure='=>'string', 'escape='=>'string', 'eol='=>'string'], ], 'hash_pbkdf2' => [ 'old' => ['non-empty-string', 'algo'=>'string', 'password'=>'string', 'salt'=>'string', 'iterations'=>'int', 'length='=>'int', 'binary='=>'bool'], 'new' => ['non-empty-string', 'algo'=>'string', 'password'=>'string', 'salt'=>'string', 'iterations'=>'int', 'length='=>'int', 'binary='=>'bool', 'options=' => 'array'], ], 'finfo_buffer' => [ 'old' => ['string|false', 'finfo'=>'resource', 'string'=>'string', 'flags='=>'int', 'context='=>'resource'], 'new' => ['string|false', 'finfo'=>'finfo', 'string'=>'string', 'flags='=>'int', 'context='=>'resource'], ], 'finfo_close' => [ 'old' => ['bool', 'finfo'=>'resource'], 'new' => ['bool', 'finfo'=>'finfo'], ], 'finfo_file' => [ 'old' => ['string|false', 'finfo'=>'resource', 'filename'=>'string', 'flags='=>'int', 'context='=>'resource'], 'new' => ['string|false', 'finfo'=>'finfo', 'filename'=>'string', 'flags='=>'int', 'context='=>'resource'], ], 'finfo_open' => [ 'old' => ['resource|false', 'flags='=>'int', 'magic_database='=>'?string'], 'new' => ['finfo|false', 'flags='=>'int', 'magic_database='=>'?string'], ], 'finfo_set_flags' => [ 'old' => ['bool', 'finfo'=>'resource', 'flags'=>'int'], 'new' => ['bool', 'finfo'=>'finfo', 'flags'=>'int'], ], 'fputcsv' => [ 'old' => ['int|false', 'stream'=>'resource', 'fields'=>'array', 'separator='=>'string', 'enclosure='=>'string', 'escape='=>'string'], 'new' => ['int|false', 'stream'=>'resource', 'fields'=>'array', 'separator='=>'string', 'enclosure='=>'string', 'escape='=>'string', 'eol='=>'string'], ], 'ftp_connect' => [ 'old' => ['resource|false', 'hostname' => 'string', 'port=' => 'int', 'timeout=' => 'int'], 'new' => ['FTP\Connection|false', 'hostname' => 'string', 'port=' => 'int', 'timeout=' => 'int'], ], 'ftp_ssl_connect' => [ 'old' => ['resource|false', 'hostname' => 'string', 'port=' => 'int', 'timeout=' => 'int'], 'new' => ['FTP\Connection|false', 'hostname' => 'string', 'port=' => 'int', 'timeout=' => 'int'], ], 'ftp_login' => [ 'old' => ['bool', 'ftp' => 'resource', 'username' => 'string', 'password' => 'string'], 'new' => ['bool', 'ftp' => 'FTP\Connection', 'username' => 'string', 'password' => 'string'], ], 'ftp_pwd' => [ 'old' => ['string|false', 'ftp' => 'resource'], 'new' => ['string|false', 'ftp' => 'FTP\Connection'], ], 'ftp_cdup' => [ 'old' => ['bool', 'ftp' => 'resource'], 'new' => ['bool', 'ftp' => 'FTP\Connection'], ], 'ftp_chdir' => [ 'old' => ['bool', 'ftp' => 'resource', 'directory' => 'string'], 'new' => ['bool', 'ftp' => 'FTP\Connection', 'directory' => 'string'], ], 'ftp_exec' => [ 'old' => ['bool', 'ftp' => 'resource', 'command' => 'string'], 'new' => ['bool', 'ftp' => 'FTP\Connection', 'command' => 'string'], ], 'ftp_raw' => [ 'old' => ['?array', 'ftp' => 'resource', 'command' => 'string'], 'new' => ['?array', 'ftp' => 'FTP\Connection', 'command' => 'string'], ], 'ftp_mkdir' => [ 'old' => ['string|false', 'ftp' => 'resource', 'directory' => 'string'], 'new' => ['string|false', 'ftp' => 'FTP\Connection', 'directory' => 'string'], ], 'ftp_rmdir' => [ 'old' => ['bool', 'ftp' => 'resource', 'directory' => 'string'], 'new' => ['bool', 'ftp' => 'FTP\Connection', 'directory' => 'string'], ], 'ftp_chmod' => [ 'old' => ['int|false', 'ftp' => 'resource', 'permissions' => 'int', 'filename' => 'string'], 'new' => ['int|false', 'ftp' => 'FTP\Connection', 'permissions' => 'int', 'filename' => 'string'], ], 'ftp_alloc' => [ 'old' => ['bool', 'ftp' => 'resource', 'size' => 'int', '&w_response=' => 'string'], 'new' => ['bool', 'ftp' => 'FTP\Connection', 'size' => 'int', '&w_response=' => 'string'], ], 'ftp_nlist' => [ 'old' => ['array|false', 'ftp' => 'resource', 'directory' => 'string'], 'new' => ['array|false', 'ftp' => 'FTP\Connection', 'directory' => 'string'], ], 'ftp_rawlist' => [ 'old' => ['array|false', 'ftp' => 'resource', 'directory' => 'string', 'recursive=' => 'bool'], 'new' => ['array|false', 'ftp' => 'FTP\Connection', 'directory' => 'string', 'recursive=' => 'bool'], ], 'ftp_mlsd' => [ 'old' => ['array|false', 'ftp' => 'resource', 'directory' => 'string'], 'new' => ['array|false', 'ftp' => 'FTP\Connection', 'directory' => 'string'], ], 'ftp_systype' => [ 'old' => ['string|false', 'ftp' => 'resource'], 'new' => ['string|false', 'ftp' => 'FTP\Connection'], ], 'ftp_fget' => [ 'old' => ['bool', 'ftp' => 'resource', 'stream' => 'resource', 'remote_filename' => 'string', 'mode=' => 'int', 'offset=' => 'int'], 'new' => ['bool', 'ftp' => 'FTP\Connection', 'stream' => 'resource', 'remote_filename' => 'string', 'mode=' => 'int', 'offset=' => 'int'], ], 'ftp_nb_fget' => [ 'old' => ['int', 'ftp' => 'resource', 'stream' => 'resource', 'remote_filename' => 'string', 'mode=' => 'int', 'offset=' => 'int'], 'new' => ['int', 'ftp' => 'FTP\Connection', 'stream' => 'resource', 'remote_filename' => 'string', 'mode=' => 'int', 'offset=' => 'int'], ], 'ftp_pasv' => [ 'old' => ['bool', 'ftp' => 'resource', 'enable' => 'bool'], 'new' => ['bool', 'ftp' => 'FTP\Connection', 'enable' => 'bool'], ], 'ftp_get' => [ 'old' => ['bool', 'ftp' => 'resource', 'local_filename' => 'string', 'remote_filename' => 'string', 'mode=' => 'int', 'offset=' => 'int'], 'new' => ['bool', 'ftp' => 'FTP\Connection', 'local_filename' => 'string', 'remote_filename' => 'string', 'mode=' => 'int', 'offset=' => 'int'], ], 'ftp_nb_get' => [ 'old' => ['int', 'ftp' => 'resource', 'local_filename' => 'string', 'remote_filename' => 'string', 'mode=' => 'int', 'offset=' => 'int'], 'new' => ['int', 'ftp' => 'FTP\Connection', 'local_filename' => 'string', 'remote_filename' => 'string', 'mode=' => 'int', 'offset=' => 'int'], ], 'ftp_nb_continue' => [ 'old' => ['int', 'ftp' => 'resource'], 'new' => ['int', 'ftp' => 'FTP\Connection'], ], 'ftp_fput' => [ 'old' => ['bool', 'ftp' => 'resource', 'remote_filename' => 'string', 'stream' => 'resource', 'mode=' => 'int', 'offset=' => 'int'], 'new' => ['bool', 'ftp' => 'FTP\Connection', 'remote_filename' => 'string', 'stream' => 'resource', 'mode=' => 'int', 'offset=' => 'int'], ], 'ftp_nb_fput' => [ 'old' => ['int', 'ftp' => 'resource', 'remote_filename' => 'string', 'stream' => 'resource', 'mode=' => 'int', 'offset=' => 'int'], 'new' => ['int', 'ftp' => 'FTP\Connection', 'remote_filename' => 'string', 'stream' => 'resource', 'mode=' => 'int', 'offset=' => 'int'], ], 'ftp_put' => [ 'old' => ['bool', 'ftp' => 'resource', 'remote_filename' => 'string', 'local_filename' => 'string', 'mode=' => 'int', 'offset=' => 'int'], 'new' => ['bool', 'ftp' => 'FTP\Connection', 'remote_filename' => 'string', 'local_filename' => 'string', 'mode=' => 'int', 'offset=' => 'int'], ], 'ftp_append' => [ 'old' => ['bool', 'ftp' => 'resource', 'remote_filename' => 'string', 'local_filename' => 'string', 'mode=' => 'int'], 'new' => ['bool', 'ftp' => 'FTP\Connection', 'remote_filename' => 'string', 'local_filename' => 'string', 'mode=' => 'int'], ], 'ftp_nb_put' => [ 'old' => ['int', 'ftp' => 'resource', 'remote_filename' => 'string', 'local_filename' => 'string', 'mode=' => 'int', 'offset=' => 'int'], 'new' => ['int', 'ftp' => 'FTP\Connection', 'remote_filename' => 'string', 'local_filename' => 'string', 'mode=' => 'int', 'offset=' => 'int'], ], 'ftp_size' => [ 'old' => ['int', 'ftp' => 'resource', 'filename' => 'string'], 'new' => ['int', 'ftp' => 'FTP\Connection', 'filename' => 'string'], ], 'ftp_mdtm' => [ 'old' => ['int', 'ftp' => 'resource', 'filename' => 'string'], 'new' => ['int', 'ftp' => 'FTP\Connection', 'filename' => 'string'], ], 'ftp_rename' => [ 'old' => ['bool', 'ftp' => 'resource', 'from' => 'string', 'to' => 'string'], 'new' => ['bool', 'ftp' => 'FTP\Connection', 'from' => 'string', 'to' => 'string'], ], 'ftp_delete' => [ 'old' => ['bool', 'ftp' => 'resource', 'filename' => 'string'], 'new' => ['bool', 'ftp' => 'FTP\Connection', 'filename' => 'string'], ], 'ftp_site' => [ 'old' => ['bool', 'ftp' => 'resource', 'command' => 'string'], 'new' => ['bool', 'ftp' => 'FTP\Connection', 'command' => 'string'], ], 'ftp_close' => [ 'old' => ['bool', 'ftp' => 'resource'], 'new' => ['bool', 'ftp' => 'FTP\Connection'], ], 'ftp_quit' => [ 'old' => ['bool', 'ftp' => 'resource'], 'new' => ['bool', 'ftp' => 'FTP\Connection'], ], 'ftp_set_option' => [ 'old' => ['bool', 'ftp' => 'resource', 'option' => 'int', 'value' => 'mixed'], 'new' => ['bool', 'ftp' => 'FTP\Connection', 'option' => 'int', 'value' => 'mixed'], ], 'ftp_get_option' => [ 'old' => ['int|false', 'ftp' => 'resource', 'option' => 'int'], 'new' => ['int|false', 'ftp' => 'FTP\Connection', 'option' => 'int'], ], 'hash' => [ 'old' => ['non-empty-string', 'algo'=>'string', 'data'=>'string', 'binary='=>'bool'], 'new' => ['non-empty-string', 'algo'=>'string', 'data'=>'string', 'binary='=>'bool', 'options='=>'array{seed:scalar}'], ], 'hash_file' => [ 'old' => ['non-empty-string|false', 'algo'=>'string', 'filename'=>'string', 'binary='=>'bool'], 'new' => ['non-empty-string|false', 'algo'=>'string', 'filename'=>'string', 'binary='=>'bool', 'options='=>'array{seed:scalar}'], ], 'hash_init' => [ 'old' => ['HashContext', 'algo'=>'string', 'flags='=>'int', 'key='=>'string'], 'new' => ['HashContext', 'algo'=>'string', 'flags='=>'int', 'key='=>'string', 'options='=>'array{seed:scalar}'], ], 'imageloadfont' => [ 'old' => ['int|false', 'filename'=>'string'], 'new' => ['GdFont|false', 'filename'=>'string'], ], 'imap_append' => [ 'old' => ['bool', 'imap'=>'resource', 'folder'=>'string', 'message'=>'string', 'options='=>'?string', 'internal_date='=>'?string'], 'new' => ['bool', 'imap'=>'IMAP\Connection', 'folder'=>'string', 'message'=>'string', 'options='=>'?string', 'internal_date='=>'?string'], ], 'imap_body' => [ 'old' => ['string|false', 'imap'=>'resource', 'message_num'=>'int', 'flags='=>'int'], 'new' => ['string|false', 'imap'=>'IMAP\Connection', 'message_num'=>'int', 'flags='=>'int'], ], 'imap_bodystruct' => [ 'old' => ['stdClass|false', 'imap'=>'resource', 'message_num'=>'int', 'section'=>'string'], 'new' => ['stdClass|false', 'imap'=>'IMAP\Connection', 'message_num'=>'int', 'section'=>'string'], ], 'imap_check' => [ 'old' => ['stdClass|false', 'imap'=>'resource'], 'new' => ['stdClass|false', 'imap'=>'IMAP\Connection'], ], 'imap_clearflag_full' => [ 'old' => ['bool', 'imap'=>'resource', 'sequence'=>'string', 'flag'=>'string', 'options='=>'int'], 'new' => ['bool', 'imap'=>'IMAP\Connection', 'sequence'=>'string', 'flag'=>'string', 'options='=>'int'], ], 'imap_close' => [ 'old' => ['bool', 'imap'=>'resource', 'flags='=>'int'], 'new' => ['bool', 'imap'=>'IMAP\Connection', 'flags='=>'int'], ], 'imap_create' => [ 'old' => ['bool', 'imap'=>'resource', 'mailbox'=>'string'], 'new' => ['bool', 'imap'=>'IMAP\Connection', 'mailbox'=>'string'], ], 'imap_createmailbox' => [ 'old' => ['bool', 'imap'=>'resource', 'mailbox'=>'string'], 'new' => ['bool', 'imap'=>'IMAP\Connection', 'mailbox'=>'string'], ], 'imap_delete' => [ 'old' => ['bool', 'imap'=>'resource', 'message_nums'=>'string', 'flags='=>'int'], 'new' => ['bool', 'imap'=>'IMAP\Connection', 'message_nums'=>'string', 'flags='=>'int'], ], 'imap_deletemailbox' => [ 'old' => ['bool', 'imap'=>'resource', 'mailbox'=>'string'], 'new' => ['bool', 'imap'=>'IMAP\Connection', 'mailbox'=>'string'], ], 'imap_expunge' => [ 'old' => ['bool', 'imap'=>'resource'], 'new' => ['bool', 'imap'=>'IMAP\Connection'], ], 'imap_fetch_overview' => [ 'old' => ['array|false', 'imap'=>'resource', 'sequence'=>'string', 'flags='=>'int'], 'new' => ['array|false', 'imap'=>'IMAP\Connection', 'sequence'=>'string', 'flags='=>'int'], ], 'imap_fetchbody' => [ 'old' => ['string|false', 'imap'=>'resource', 'message_num'=>'int', 'section'=>'string', 'flags='=>'int'], 'new' => ['string|false', 'imap'=>'IMAP\Connection', 'message_num'=>'int', 'section'=>'string', 'flags='=>'int'], ], 'imap_fetchheader' => [ 'old' => ['string|false', 'imap'=>'resource', 'message_num'=>'int', 'flags='=>'int'], 'new' => ['string|false', 'imap'=>'IMAP\Connection', 'message_num'=>'int', 'flags='=>'int'], ], 'imap_fetchmime' => [ 'old' => ['string|false', 'imap'=>'resource', 'message_num'=>'int', 'section'=>'string', 'flags='=>'int'], 'new' => ['string|false', 'imap'=>'IMAP\Connection', 'message_num'=>'int', 'section'=>'string', 'flags='=>'int'], ], 'imap_fetchstructure' => [ 'old' => ['stdClass|false', 'imap'=>'resource', 'message_num'=>'int', 'flags='=>'int'], 'new' => ['stdClass|false', 'imap'=>'IMAP\Connection', 'message_num'=>'int', 'flags='=>'int'], ], 'imap_fetchtext' => [ 'old' => ['string|false', 'imap'=>'resource', 'message_num'=>'int', 'flags='=>'int'], 'new' => ['string|false', 'imap'=>'IMAP\Connection', 'message_num'=>'int', 'flags='=>'int'], ], 'imap_gc' => [ 'old' => ['bool', 'imap'=>'resource', 'flags'=>'int'], 'new' => ['bool', 'imap'=>'IMAP\Connection', 'flags'=>'int'], ], 'imap_get_quota' => [ 'old' => ['array|false', 'imap'=>'resource', 'quota_root'=>'string'], 'new' => ['array|false', 'imap'=>'IMAP\Connection', 'quota_root'=>'string'], ], 'imap_get_quotaroot' => [ 'old' => ['array|false', 'imap'=>'resource', 'mailbox'=>'string'], 'new' => ['array|false', 'imap'=>'IMAP\Connection', 'mailbox'=>'string'], ], 'imap_getacl' => [ 'old' => ['array|false', 'imap'=>'resource', 'mailbox'=>'string'], 'new' => ['array|false', 'imap'=>'IMAP\Connection', 'mailbox'=>'string'], ], 'imap_getmailboxes' => [ 'old' => ['array|false', 'imap'=>'resource', 'reference'=>'string', 'pattern'=>'string'], 'new' => ['array|false', 'imap'=>'IMAP\Connection', 'reference'=>'string', 'pattern'=>'string'], ], 'imap_getsubscribed' => [ 'old' => ['array|false', 'imap'=>'resource', 'reference'=>'string', 'pattern'=>'string'], 'new' => ['array|false', 'imap'=>'IMAP\Connection', 'reference'=>'string', 'pattern'=>'string'], ], 'imap_headerinfo' => [ 'old' => ['stdClass|false', 'imap'=>'resource', 'message_num'=>'int', 'from_length='=>'int', 'subject_length='=>'int'], 'new' => ['stdClass|false', 'imap'=>'IMAP\Connection', 'message_num'=>'int', 'from_length='=>'int', 'subject_length='=>'int'], ], 'imap_headers' => [ 'old' => ['array|false', 'imap'=>'resource'], 'new' => ['array|false', 'imap'=>'IMAP\Connection'], ], 'imap_list' => [ 'old' => ['array|false', 'imap'=>'resource', 'reference'=>'string', 'pattern'=>'string'], 'new' => ['array|false', 'imap'=>'IMAP\Connection', 'reference'=>'string', 'pattern'=>'string'], ], 'imap_listmailbox' => [ 'old' => ['array|false', 'imap'=>'resource', 'reference'=>'string', 'pattern'=>'string'], 'new' => ['array|false', 'imap'=>'IMAP\Connection', 'reference'=>'string', 'pattern'=>'string'], ], 'imap_listscan' => [ 'old' => ['array|false', 'imap'=>'resource', 'reference'=>'string', 'pattern'=>'string', 'content'=>'string'], 'new' => ['array|false', 'imap'=>'IMAP\Connection', 'reference'=>'string', 'pattern'=>'string', 'content'=>'string'], ], 'imap_listsubscribed' => [ 'old' => ['array|false', 'imap'=>'resource', 'reference'=>'string', 'pattern'=>'string'], 'new' => ['array|false', 'imap'=>'IMAP\Connection', 'reference'=>'string', 'pattern'=>'string'], ], 'imap_lsub' => [ 'old' => ['array|false', 'imap'=>'resource', 'reference'=>'string', 'pattern'=>'string'], 'new' => ['array|false', 'imap'=>'IMAP\Connection', 'reference'=>'string', 'pattern'=>'string'], ], 'imap_mail_copy' => [ 'old' => ['bool', 'imap'=>'resource', 'message_nums'=>'string', 'mailbox'=>'string', 'flags='=>'int'], 'new' => ['bool', 'imap'=>'IMAP\Connection', 'message_nums'=>'string', 'mailbox'=>'string', 'flags='=>'int'], ], 'imap_mail_move' => [ 'old' => ['bool', 'imap'=>'resource', 'message_nums'=>'string', 'mailbox'=>'string', 'flags='=>'int'], 'new' => ['bool', 'imap'=>'IMAP\Connection', 'message_nums'=>'string', 'mailbox'=>'string', 'flags='=>'int'], ], 'imap_mailboxmsginfo' => [ 'old' => ['stdClass', 'imap'=>'resource'], 'new' => ['stdClass', 'imap'=>'IMAP\Connection'], ], 'imap_msgno' => [ 'old' => ['int', 'imap'=>'resource', 'message_uid'=>'int'], 'new' => ['int', 'imap'=>'IMAP\Connection', 'message_uid'=>'int'], ], 'imap_num_msg' => [ 'old' => ['int|false', 'imap'=>'resource'], 'new' => ['int|false', 'imap'=>'IMAP\Connection'], ], 'imap_num_recent' => [ 'old' => ['int', 'imap'=>'resource'], 'new' => ['int', 'imap'=>'IMAP\Connection'], ], 'imap_open' => [ 'old' => ['resource|false', 'mailbox'=>'string', 'user'=>'string', 'password'=>'string', 'flags='=>'int', 'retries='=>'int', 'options='=>'array'], 'new' => ['IMAP\Connection|false', 'mailbox'=>'string', 'user'=>'string', 'password'=>'string', 'flags='=>'int', 'retries='=>'int', 'options='=>'array'], ], 'imap_ping' => [ 'old' => ['bool', 'imap'=>'resource'], 'new' => ['bool', 'imap'=>'IMAP\Connection'], ], 'imap_rename' => [ 'old' => ['bool', 'imap'=>'resource', 'from'=>'string', 'to'=>'string'], 'new' => ['bool', 'imap'=>'IMAP\Connection', 'from'=>'string', 'to'=>'string'], ], 'imap_renamemailbox' => [ 'old' => ['bool', 'imap'=>'resource', 'from'=>'string', 'to'=>'string'], 'new' => ['bool', 'imap'=>'IMAP\Connection', 'from'=>'string', 'to'=>'string'], ], 'imap_reopen' => [ 'old' => ['bool', 'imap'=>'resource', 'mailbox'=>'string', 'flags='=>'int', 'retries='=>'int'], 'new' => ['bool', 'imap'=>'IMAP\Connection', 'mailbox'=>'string', 'flags='=>'int', 'retries='=>'int'], ], 'imap_savebody' => [ 'old' => ['bool', 'imap'=>'resource', 'file'=>'string|resource', 'message_num'=>'int', 'section='=>'string', 'flags='=>'int'], 'new' => ['bool', 'imap'=>'IMAP\Connection', 'file'=>'string|resource', 'message_num'=>'int', 'section='=>'string', 'flags='=>'int'], ], 'imap_scan' => [ 'old' => ['array|false', 'imap'=>'resource', 'reference'=>'string', 'pattern'=>'string', 'content'=>'string'], 'new' => ['array|false', 'imap'=>'IMAP\Connection', 'reference'=>'string', 'pattern'=>'string', 'content'=>'string'], ], 'imap_scanmailbox' => [ 'old' => ['array|false', 'imap'=>'resource', 'reference'=>'string', 'pattern'=>'string', 'content'=>'string'], 'new' => ['array|false', 'imap'=>'IMAP\Connection', 'reference'=>'string', 'pattern'=>'string', 'content'=>'string'], ], 'imap_search' => [ 'old' => ['array|false', 'imap'=>'resource', 'criteria'=>'string', 'flags='=>'int', 'charset='=>'string'], 'new' => ['array|false', 'imap'=>'IMAP\Connection', 'criteria'=>'string', 'flags='=>'int', 'charset='=>'string'], ], 'imap_set_quota' => [ 'old' => ['bool', 'imap'=>'resource', 'quota_root'=>'string', 'mailbox_size'=>'int'], 'new' => ['bool', 'imap'=>'IMAP\Connection', 'quota_root'=>'string', 'mailbox_size'=>'int'], ], 'imap_setacl' => [ 'old' => ['bool', 'imap'=>'resource', 'mailbox'=>'string', 'user_id'=>'string', 'rights'=>'string'], 'new' => ['bool', 'imap'=>'IMAP\Connection', 'mailbox'=>'string', 'user_id'=>'string', 'rights'=>'string'], ], 'imap_setflag_full' => [ 'old' => ['bool', 'imap'=>'resource', 'sequence'=>'string', 'flag'=>'string', 'options='=>'int'], 'new' => ['bool', 'imap'=>'IMAP\Connection', 'sequence'=>'string', 'flag'=>'string', 'options='=>'int'], ], 'imap_sort' => [ 'old' => ['array|false', 'imap'=>'resource', 'criteria'=>'int', 'reverse'=>'bool', 'flags='=>'int', 'search_criteria='=>'?string', 'charset='=>'?string'], 'new' => ['array|false', 'imap'=>'IMAP\Connection', 'criteria'=>'int', 'reverse'=>'bool', 'flags='=>'int', 'search_criteria='=>'?string', 'charset='=>'?string'], ], 'imap_status' => [ 'old' => ['stdClass|false', 'imap'=>'resource', 'mailbox'=>'string', 'flags'=>'int'], 'new' => ['stdClass|false', 'imap'=>'IMAP\Connection', 'mailbox'=>'string', 'flags'=>'int'], ], 'imap_subscribe' => [ 'old' => ['bool', 'imap'=>'resource', 'mailbox'=>'string'], 'new' => ['bool', 'imap'=>'IMAP\Connection', 'mailbox'=>'string'], ], 'imap_thread' => [ 'old' => ['array|false', 'imap'=>'resource', 'flags='=>'int'], 'new' => ['array|false', 'imap'=>'IMAP\Connection', 'flags='=>'int'], ], 'imap_uid' => [ 'old' => ['int|false', 'imap'=>'resource', 'message_num'=>'int'], 'new' => ['int|false', 'imap'=>'IMAP\Connection', 'message_num'=>'int'], ], 'imap_undelete' => [ 'old' => ['bool', 'imap'=>'resource', 'message_nums'=>'string', 'flags='=>'int'], 'new' => ['bool', 'imap'=>'IMAP\Connection', 'message_nums'=>'string', 'flags='=>'int'], ], 'imap_unsubscribe' => [ 'old' => ['bool', 'imap'=>'resource', 'mailbox'=>'string'], 'new' => ['bool', 'imap'=>'IMAP\Connection', 'mailbox'=>'string'], ], 'ini_alter' => [ 'old' => ['string|false', 'option'=>'string', 'value'=>'string'], 'new' => ['string|false', 'option'=>'string', 'value'=>'string|int|float|bool|null'], ], 'ini_set' => [ 'old' => ['string|false', 'option'=>'string', 'value'=>'string'], 'new' => ['string|false', 'option'=>'string', 'value'=>'string|int|float|bool|null'], ], 'IntlDateFormatter::__construct' => [ 'old' => ['void', 'locale'=>'?string', 'dateType'=>'int', 'timeType'=>'int', 'timezone='=>'IntlTimeZone|DateTimeZone|string|null', 'calendar='=>'IntlCalendar|int|null', 'pattern='=>'?string'], 'new' => ['void', 'locale'=>'?string', 'dateType='=>'int', 'timeType='=>'int', 'timezone='=>'IntlTimeZone|DateTimeZone|string|null', 'calendar='=>'IntlCalendar|int|null', 'pattern='=>'?string'], ], 'IntlDateFormatter::create' => [ 'old' => ['?IntlDateFormatter', 'locale'=>'?string', 'dateType'=>'int', 'timeType'=>'int', 'timezone='=>'IntlTimeZone|DateTimeZone|string|null', 'calendar='=>'IntlCalendar|int|null', 'pattern='=>'?string'], 'new' => ['?IntlDateFormatter', 'locale'=>'?string', 'dateType='=>'int', 'timeType='=>'int', 'timezone='=>'IntlTimeZone|DateTimeZone|string|null', 'calendar='=>'IntlCalendar|int|null', 'pattern='=>'?string'], ], 'ldap_add' => [ 'old' => ['bool', 'ldap'=>'resource', 'dn'=>'string', 'entry'=>'array', 'controls='=>'?array'], 'new' => ['bool', 'ldap'=>'LDAP\Connection', 'dn'=>'string', 'entry'=>'array', 'controls='=>'?array'], ], 'ldap_add_ext' => [ 'old' => ['resource|false', 'ldap'=>'resource', 'dn'=>'string', 'entry'=>'array', 'controls='=>'?array'], 'new' => ['LDAP\Result|false', 'ldap'=>'LDAP\Connection', 'dn'=>'string', 'entry'=>'array', 'controls='=>'?array'], ], 'ldap_bind' => [ 'old' => ['bool', 'ldap'=>'resource', 'dn='=>'string|null', 'password='=>'string|null'], 'new' => ['bool', 'ldap'=>'LDAP\Connection', 'dn='=>'string|null', 'password='=>'string|null'], ], 'ldap_bind_ext' => [ 'old' => ['resource|false', 'ldap'=>'resource', 'dn='=>'string|null', 'password='=>'string|null', 'controls='=>'?array'], 'new' => ['LDAP\Result|false', 'ldap'=>'LDAP\Connection', 'dn='=>'string|null', 'password='=>'string|null', 'controls='=>'?array'], ], 'ldap_close' => [ 'old' => ['bool', 'ldap'=>'resource'], 'new' => ['bool', 'ldap'=>'LDAP\Connection'], ], 'ldap_compare' => [ 'old' => ['bool|int', 'ldap'=>'resource', 'dn'=>'string', 'attribute'=>'string', 'value'=>'string', 'controls='=>'?array'], 'new' => ['bool|int', 'ldap'=>'LDAP\Connection', 'dn'=>'string', 'attribute'=>'string', 'value'=>'string', 'controls='=>'?array'], ], 'ldap_connect' => [ 'old' => ['resource|false', 'uri='=>'?string', 'port='=>'int', 'wallet='=>'string', 'password='=>'string', 'auth_mode='=>'int'], 'new' => ['LDAP\Connection|false', 'uri='=>'?string', 'port='=>'int', 'wallet='=>'string', 'password='=>'string', 'auth_mode='=>'int'], ], 'ldap_count_entries' => [ 'old' => ['int', 'ldap'=>'resource', 'result'=>'resource'], 'new' => ['int', 'ldap'=>'LDAP\Connection', 'result'=>'LDAP\Result'], ], 'ldap_delete' => [ 'old' => ['bool', 'ldap'=>'resource', 'dn'=>'string', 'controls='=>'?array'], 'new' => ['bool', 'ldap'=>'LDAP\Connection', 'dn'=>'string', 'controls='=>'?array'], ], 'ldap_delete_ext' => [ 'old' => ['resource|false', 'ldap'=>'resource', 'dn'=>'string', 'controls='=>'?array'], 'new' => ['LDAP\Result|false', 'ldap'=>'LDAP\Connection', 'dn'=>'string', 'controls='=>'?array'], ], 'ldap_errno' => [ 'old' => ['int', 'ldap'=>'resource'], 'new' => ['int', 'ldap'=>'LDAP\Connection'], ], 'ldap_error' => [ 'old' => ['string', 'ldap'=>'resource'], 'new' => ['string', 'ldap'=>'LDAP\Connection'], ], 'ldap_exop' => [ 'old' => ['resource|bool', 'ldap'=>'resource', 'request_oid'=>'string', 'request_data='=>'?string', 'controls='=>'array|null', '&w_response_data='=>'string', '&w_response_oid='=>'string'], 'new' => ['LDAP\Result|bool', 'ldap'=>'LDAP\Connection', 'request_oid'=>'string', 'request_data='=>'?string', 'controls='=>'?array', '&w_response_data='=>'string', '&w_response_oid='=>'string'], ], 'ldap_exop_passwd' => [ 'old' => ['bool|string', 'ldap'=>'resource', 'user='=>'string', 'old_password='=>'string', 'new_password='=>'string', '&w_controls='=>'array|null'], 'new' => ['bool|string', 'ldap'=>'LDAP\Connection', 'user='=>'string', 'old_password='=>'string', 'new_password='=>'string', '&w_controls='=>'array|null'], ], 'ldap_exop_refresh' => [ 'old' => ['int|false', 'ldap'=>'resource', 'dn'=>'string', 'ttl'=>'int'], 'new' => ['int|false', 'ldap'=>'LDAP\Connection', 'dn'=>'string', 'ttl'=>'int'], ], 'ldap_exop_whoami' => [ 'old' => ['string|false', 'ldap'=>'resource'], 'new' => ['string|false', 'ldap'=>'LDAP\Connection'], ], 'ldap_first_attribute' => [ 'old' => ['string|false', 'ldap'=>'resource', 'entry'=>'resource'], 'new' => ['string|false', 'ldap'=>'LDAP\Connection', 'entry'=>'LDAP\ResultEntry'], ], 'ldap_first_entry' => [ 'old' => ['resource|false', 'ldap'=>'resource', 'result'=>'resource'], 'new' => ['LDAP\ResultEntry|false', 'ldap'=>'LDAP\Connection', 'result'=>'LDAP\Result'], ], 'ldap_first_reference' => [ 'old' => ['resource|false', 'ldap'=>'resource', 'result'=>'resource'], 'new' => ['LDAP\ResultEntry|false', 'ldap'=>'LDAP\Connection', 'result'=>'LDAP\Result'], ], 'ldap_free_result' => [ 'old' => ['bool', 'ldap'=>'resource'], 'new' => ['bool', 'result'=>'LDAP\Result'], ], 'ldap_get_attributes' => [ 'old' => ['array', 'ldap'=>'resource', 'entry'=>'resource'], 'new' => ['array', 'ldap'=>'LDAP\Connection', 'entry'=>'LDAP\ResultEntry'], ], 'ldap_get_dn' => [ 'old' => ['string|false', 'ldap'=>'resource', 'entry'=>'resource'], 'new' => ['string|false', 'ldap'=>'LDAP\Connection', 'entry'=>'LDAP\ResultEntry'], ], 'ldap_get_entries' => [ 'old' => ['array|false', 'ldap'=>'resource', 'result'=>'resource'], 'new' => ['array|false', 'ldap'=>'LDAP\Connection', 'result'=>'LDAP\Result'], ], 'ldap_get_option' => [ 'old' => ['bool', 'ldap'=>'resource', 'option'=>'int', '&w_value='=>'array|string|int'], 'new' => ['bool', 'ldap'=>'LDAP\Connection', 'option'=>'int', '&w_value='=>'array|string|int'], ], 'ldap_get_values' => [ 'old' => ['array|false', 'ldap'=>'resource', 'entry'=>'resource', 'attribute'=>'string'], 'new' => ['array|false', 'ldap'=>'LDAP\Connection', 'entry'=>'LDAP\ResultEntry', 'attribute'=>'string'], ], 'ldap_get_values_len' => [ 'old' => ['array|false', 'ldap'=>'resource', 'entry'=>'resource', 'attribute'=>'string'], 'new' => ['array|false', 'ldap'=>'LDAP\Connection', 'entry'=>'LDAP\ResultEntry', 'attribute'=>'string'], ], 'ldap_list' => [ 'old' => ['resource|false', 'ldap'=>'resource|array', 'base'=>'array|string', 'filter'=>'array|string', 'attributes='=>'array', 'attributes_only='=>'int', 'sizelimit='=>'int', 'timelimit='=>'int', 'deref='=>'int', 'controls='=>'?array'], 'new' => ['LDAP\Result|LDAP\Result[]|false', 'ldap'=>'LDAP\Connection|LDAP\Connection[]', 'base'=>'array|string', 'filter'=>'array|string', 'attributes='=>'array', 'attributes_only='=>'int', 'sizelimit='=>'int', 'timelimit='=>'int', 'deref='=>'int', 'controls='=>'?array'], ], 'ldap_mod_add' => [ 'old' => ['bool', 'ldap'=>'resource', 'dn'=>'string', 'entry'=>'array', 'controls='=>'?array'], 'new' => ['bool', 'ldap'=>'LDAP\Connection', 'dn'=>'string', 'entry'=>'array', 'controls='=>'?array'], ], 'ldap_mod_add_ext' => [ 'old' => ['resource|false', 'ldap'=>'resource', 'dn'=>'string', 'entry'=>'array', 'controls='=>'?array'], 'new' => ['LDAP\Result|false', 'ldap'=>'LDAP\Connection', 'dn'=>'string', 'entry'=>'array', 'controls='=>'?array'], ], 'ldap_mod_del' => [ 'old' => ['bool', 'ldap'=>'resource', 'dn'=>'string', 'entry'=>'array', 'controls='=>'?array'], 'new' => ['bool', 'ldap'=>'LDAP\Connection', 'dn'=>'string', 'entry'=>'array', 'controls='=>'?array'], ], 'ldap_mod_del_ext' => [ 'old' => ['resource|false', 'ldap'=>'resource', 'dn'=>'string', 'entry'=>'array', 'controls='=>'?array'], 'new' => ['LDAP\Result|false', 'ldap'=>'LDAP\Connection', 'dn'=>'string', 'entry'=>'array', 'controls='=>'?array'], ], 'ldap_mod_replace' => [ 'old' => ['bool', 'ldap'=>'resource', 'dn'=>'string', 'entry'=>'array', 'controls='=>'?array'], 'new' => ['bool', 'ldap'=>'LDAP\Connection', 'dn'=>'string', 'entry'=>'array', 'controls='=>'?array'], ], 'ldap_mod_replace_ext' => [ 'old' => ['resource|false', 'ldap'=>'resource', 'dn'=>'string', 'entry'=>'array', 'controls='=>'?array'], 'new' => ['LDAP\Result|false', 'ldap'=>'LDAP\Connection', 'dn'=>'string', 'entry'=>'array', 'controls='=>'?array'], ], 'ldap_modify' => [ 'old' => ['bool', 'ldap'=>'resource', 'dn'=>'string', 'entry'=>'array', 'controls='=>'?array'], 'new' => ['bool', 'ldap'=>'LDAP\Connection', 'dn'=>'string', 'entry'=>'array', 'controls='=>'?array'], ], 'ldap_modify_batch' => [ 'old' => ['bool', 'ldap'=>'resource', 'dn'=>'string', 'modifications_info'=>'array', 'controls='=>'?array'], 'new' => ['bool', 'ldap'=>'LDAP\Connection', 'dn'=>'string', 'modifications_info'=>'array', 'controls='=>'?array'], ], 'ldap_next_attribute' => [ 'old' => ['string|false', 'ldap'=>'resource', 'entry'=>'resource'], 'new' => ['string|false', 'ldap'=>'LDAP\Connection', 'entry'=>'LDAP\ResultEntry'], ], 'ldap_next_entry' => [ 'old' => ['resource|false', 'ldap'=>'resource', 'entry'=>'resource'], 'new' => ['LDAP\ResultEntry|false', 'ldap'=>'LDAP\Connection', 'entry'=>'LDAP\ResultEntry'], ], 'ldap_next_reference' => [ 'old' => ['resource|false', 'ldap'=>'resource', 'entry'=>'resource'], 'new' => ['LDAP\ResultEntry|false', 'ldap'=>'LDAP\Connection', 'entry'=>'LDAP\ResultEntry'], ], 'ldap_parse_exop' => [ 'old' => ['bool', 'ldap'=>'resource', 'result'=>'resource', '&w_response_data='=>'string', '&w_response_oid='=>'string'], 'new' => ['bool', 'ldap'=>'LDAP\Connection', 'result'=>'LDAP\Result', '&w_response_data='=>'string', '&w_response_oid='=>'string'], ], 'ldap_parse_reference' => [ 'old' => ['bool', 'ldap'=>'resource', 'entry'=>'resource', '&w_referrals'=>'array'], 'new' => ['bool', 'ldap'=>'LDAP\Connection', 'entry'=>'LDAP\ResultEntry', '&w_referrals'=>'array'], ], 'ldap_parse_result' => [ 'old' => ['bool', 'ldap'=>'resource', 'result'=>'resource', '&w_error_code'=>'int', '&w_matched_dn='=>'string', '&w_error_message='=>'string', '&w_referrals='=>'array', '&w_controls='=>'array'], 'new' => ['bool', 'ldap'=>'LDAP\Connection', 'result'=>'LDAP\Result', '&w_error_code'=>'int', '&w_matched_dn='=>'string', '&w_error_message='=>'string', '&w_referrals='=>'array', '&w_controls='=>'array'], ], 'ldap_read' => [ 'old' => ['resource|false', 'ldap'=>'resource|array', 'base'=>'array|string', 'filter'=>'array|string', 'attributes='=>'array', 'attributes_only='=>'int', 'sizelimit='=>'int', 'timelimit='=>'int', 'deref='=>'int', 'controls='=>'?array'], 'new' => ['LDAP\Result|LDAP\Result[]|false', 'ldap'=>'LDAP\Connection|LDAP\Connection[]', 'base'=>'array|string', 'filter'=>'array|string', 'attributes='=>'array', 'attributes_only='=>'int', 'sizelimit='=>'int', 'timelimit='=>'int', 'deref='=>'int', 'controls='=>'?array'], ], 'ldap_rename' => [ 'old' => ['bool', 'ldap'=>'resource', 'dn'=>'string', 'new_rdn'=>'string', 'new_parent'=>'string', 'delete_old_rdn'=>'bool', 'controls='=>'?array'], 'new' => ['bool', 'ldap'=>'LDAP\Connection', 'dn'=>'string', 'new_rdn'=>'string', 'new_parent'=>'string', 'delete_old_rdn'=>'bool', 'controls='=>'?array'], ], 'ldap_rename_ext' => [ 'old' => ['resource|false', 'ldap'=>'resource', 'dn'=>'string', 'new_rdn'=>'string', 'new_parent'=>'string', 'delete_old_rdn'=>'bool', 'controls='=>'?array'], 'new' => ['LDAP\Result|false', 'ldap'=>'LDAP\Connection', 'dn'=>'string', 'new_rdn'=>'string', 'new_parent'=>'string', 'delete_old_rdn'=>'bool', 'controls='=>'?array'], ], 'ldap_sasl_bind' => [ 'old' => ['bool', 'ldap'=>'resource', 'dn='=>'?string', 'password='=>'?string', 'mech='=>'?string', 'realm='=>'?string', 'authc_id='=>'?string', 'authz_id='=>'?string', 'props='=>'?string'], 'new' => ['bool', 'ldap'=>'LDAP\Connection', 'dn='=>'?string', 'password='=>'?string', 'mech='=>'?string', 'realm='=>'?string', 'authc_id='=>'?string', 'authz_id='=>'?string', 'props='=>'?string'], ], 'ldap_search' => [ 'old' => ['resource[]|resource|false', 'ldap'=>'resource|resource[]', 'base'=>'array|string', 'filter'=>'array|string', 'attributes='=>'array', 'attributes_only='=>'int', 'sizelimit='=>'int', 'timelimit='=>'int', 'deref='=>'int', 'controls='=>'?array'], 'new' => ['LDAP\Result|LDAP\Result[]|false', 'ldap'=>'LDAP\Connection|LDAP\Connection[]', 'base'=>'array|string', 'filter'=>'array|string', 'attributes='=>'array', 'attributes_only='=>'int', 'sizelimit='=>'int', 'timelimit='=>'int', 'deref='=>'int', 'controls='=>'?array'], ], 'ldap_set_option' => [ 'old' => ['bool', 'ldap'=>'resource|null', 'option'=>'int', 'value'=>'mixed'], 'new' => ['bool', 'ldap'=>'LDAP\Connection|null', 'option'=>'int', 'value'=>'mixed'], ], 'ldap_set_rebind_proc' => [ 'old' => ['bool', 'ldap'=>'resource', 'callback'=>'?callable'], 'new' => ['bool', 'ldap'=>'LDAP\Connection', 'callback'=>'?callable'], ], 'ldap_start_tls' => [ 'old' => ['bool', 'ldap'=>'resource'], 'new' => ['bool', 'ldap'=>'LDAP\Connection'], ], 'ldap_unbind' => [ 'old' => ['bool', 'ldap'=>'resource'], 'new' => ['bool', 'ldap'=>'LDAP\Connection'], ], 'mysqli::connect' => [ 'old' => ['null|false', 'hostname='=>'string|null', 'username='=>'string|null', 'password='=>'string|null', 'database='=>'string|null', 'port='=>'int|null', 'socket='=>'string|null'], 'new' => ['bool', 'hostname='=>'string|null', 'username='=>'string|null', 'password='=>'string|null', 'database='=>'string|null', 'port='=>'int|null', 'socket='=>'string|null'], ], 'mysqli_execute' => [ 'old' => ['bool', 'statement' => 'mysqli_stmt'], 'new' => ['bool', 'statement' => 'mysqli_stmt', 'params=' => 'list|null'], ], 'mysqli_fetch_field' => [ 'old' => ['object{name:string,orgname:string,table:string,orgtable:string,max_length:int,length:int,charsetnr:int,flags:int,type:int,decimals:int,db:string,def:\'\',catalog:\'def\'}|false', 'result'=>'mysqli_result'], 'new' => ['object{name:string,orgname:string,table:string,orgtable:string,max_length:0,length:int,charsetnr:int,flags:int,type:int,decimals:int,db:string,def:\'\',catalog:\'def\'}|false', 'result'=>'mysqli_result'], ], 'mysqli_fetch_field_direct' => [ 'old' => ['object{name:string,orgname:string,table:string,orgtable:string,max_length:int,length:int,charsetnr:int,flags:int,type:int,decimals:int,db:string,def:\'\',catalog:\'def\'}|false', 'result'=>'mysqli_result', 'index'=>'int'], 'new' => ['object{name:string,orgname:string,table:string,orgtable:string,max_length:0,length:int,charsetnr:int,flags:int,type:int,decimals:int,db:string,def:\'\',catalog:\'def\'}|false', 'result'=>'mysqli_result', 'index'=>'int'], ], 'mysqli_fetch_fields' => [ 'old' => ['list', 'result'=>'mysqli_result'], 'new' => ['list', 'result'=>'mysqli_result'], ], 'mysqli_result::fetch_field' => [ 'old' => ['object{name:string,orgname:string,table:string,orgtable:string,max_length:int,length:int,charsetnr:int,flags:int,type:int,decimals:int,db:string,def:\'\',catalog:\'def\'}|false'], 'new' => ['object{name:string,orgname:string,table:string,orgtable:string,max_length:0,length:int,charsetnr:int,flags:int,type:int,decimals:int,db:string,def:\'\',catalog:\'def\'}|false'], ], 'mysqli_result::fetch_field_direct' => [ 'old' => ['object{name:string,orgname:string,table:string,orgtable:string,max_length:int,length:int,charsetnr:int,flags:int,type:int,decimals:int,db:string,def:\'\',catalog:\'def\'}|false', 'index'=>'int'], 'new' => ['object{name:string,orgname:string,table:string,orgtable:string,max_length:0,length:int,charsetnr:int,flags:int,type:int,decimals:int,db:string,def:\'\',catalog:\'def\'}|false', 'index'=>'int'], ], 'mysqli_result::fetch_fields' => [ 'old' => ['list'], 'new' => ['list'], ], 'mysqli_stmt_execute' => [ 'old' => ['bool', 'statement' => 'mysqli_stmt'], 'new' => ['bool', 'statement' => 'mysqli_stmt', 'params=' => 'list|null'], ], 'mysqli_stmt::execute' => [ 'old' => ['bool'], 'new' => ['bool', 'params=' => 'list|null'], ], 'openssl_decrypt' => [ 'old' => ['string|false', 'data'=>'string', 'cipher_algo'=>'string', 'passphrase'=>'string', 'options='=>'int', 'iv='=>'string', 'tag='=>'string', 'aad='=>'string'], 'new' => ['string|false', 'data'=>'string', 'cipher_algo'=>'string', 'passphrase'=>'string', 'options='=>'int', 'iv='=>'string', 'tag='=>'?string', 'aad='=>'string'], ], 'pg_affected_rows' => [ 'old' => ['int', 'result' => 'resource'], 'new' => ['int', 'result' => '\PgSql\Result'], ], 'pg_cancel_query' => [ 'old' => ['bool', 'connection' => 'resource'], 'new' => ['bool', 'connection' => '\PgSql\Connection'], ], 'pg_client_encoding' => [ 'old' => ['string', 'connection=' => '?resource'], 'new' => ['string', 'connection=' => '?\PgSql\Connection'], ], 'pg_close' => [ 'old' => ['bool', 'connection=' => '?resource'], 'new' => ['bool', 'connection=' => '?\PgSql\Connection'], ], 'pg_connect' => [ 'old' => ['resource|false', 'connection_string' => 'string', 'flags=' => 'int'], 'new' => ['\PgSql\Connection|false', 'connection_string' => 'string', 'flags=' => 'int'], ], 'pg_connect_poll' => [ 'old' => ['int', 'connection' => 'resource'], 'new' => ['int', 'connection' => '\PgSql\Connection'], ], 'pg_connection_busy' => [ 'old' => ['bool', 'connection' => 'resource'], 'new' => ['bool', 'connection' => '\PgSql\Connection'], ], 'pg_connection_reset' => [ 'old' => ['bool', 'connection' => 'resource'], 'new' => ['bool', 'connection' => '\PgSql\Connection'], ], 'pg_connection_status' => [ 'old' => ['int', 'connection' => 'resource'], 'new' => ['int', 'connection' => '\PgSql\Connection'], ], 'pg_consume_input' => [ 'old' => ['bool', 'connection' => 'resource'], 'new' => ['bool', 'connection' => '\PgSql\Connection'], ], 'pg_convert' => [ 'old' => ['array|false', 'connection' => 'resource', 'table_name' => 'string', 'values' => 'array', 'flags=' => 'int'], 'new' => ['array|false', 'connection' => '\PgSql\Connection', 'table_name' => 'string', 'values' => 'array', 'flags=' => 'int'], ], 'pg_copy_from' => [ 'old' => ['bool', 'connection' => 'resource', 'table_name' => 'string', 'rows' => 'array', 'separator=' => 'string', 'null_as=' => 'string'], 'new' => ['bool', 'connection' => '\PgSql\Connection', 'table_name' => 'string', 'rows' => 'array', 'separator=' => 'string', 'null_as=' => 'string'], ], 'pg_copy_to' => [ 'old' => ['array|false', 'connection' => 'resource', 'table_name' => 'string', 'separator=' => 'string', 'null_as=' => 'string'], 'new' => ['array|false', 'connection' => '\PgSql\Connection', 'table_name' => 'string', 'separator=' => 'string', 'null_as=' => 'string'], ], 'pg_dbname' => [ 'old' => ['string', 'connection=' => '?resource'], 'new' => ['string', 'connection=' => '?\PgSql\Connection'], ], 'pg_delete' => [ 'old' => ['string|bool', 'connection' => 'resource', 'table_name' => 'string', 'conditions' => 'array', 'flags=' => 'int'], 'new' => ['string|bool', 'connection' => '\PgSql\Connection', 'table_name' => 'string', 'conditions' => 'array', 'flags=' => 'int'], ], 'pg_end_copy' => [ 'old' => ['bool', 'connection=' => '?resource'], 'new' => ['bool', 'connection=' => '?\PgSql\Connection'], ], 'pg_escape_bytea' => [ 'old' => ['string', 'connection' => 'resource', 'string' => 'string'], 'new' => ['string', 'connection' => '\PgSql\Connection', 'string' => 'string'], ], 'pg_escape_identifier' => [ 'old' => ['string|false', 'connection' => 'resource', 'string' => 'string'], 'new' => ['string|false', 'connection' => '\PgSql\Connection', 'string' => 'string'], ], 'pg_escape_literal' => [ 'old' => ['string|false', 'connection' => 'resource', 'string' => 'string'], 'new' => ['string|false', 'connection' => '\PgSql\Connection', 'string' => 'string'], ], 'pg_escape_string' => [ 'old' => ['string', 'connection' => 'resource', 'string' => 'string'], 'new' => ['string', 'connection' => '\PgSql\Connection', 'string' => 'string'], ], 'pg_exec' => [ 'old' => ['resource|false', 'connection' => 'resource', 'query' => 'string'], 'new' => ['\PgSql\Result|false', 'connection' => '\PgSql\Connection', 'query' => 'string'], ], 'pg_exec\'1' => [ 'old' => ['resource|false', 'connection' => 'string'], 'new' => ['\PgSql\Result|false', 'connection' => 'string'], ], 'pg_execute' => [ 'old' => ['resource|false', 'connection' => 'resource', 'statement_name' => 'string', 'params' => 'array'], 'new' => ['\PgSql\Result|false', 'connection' => '\PgSql\Connection', 'statement_name' => 'string', 'params' => 'array'], ], 'pg_execute\'1' => [ 'old' => ['resource|false', 'connection' => 'string', 'statement_name' => 'array'], 'new' => ['\PgSql\Result|false', 'connection' => 'string', 'statement_name' => 'array'], ], 'pg_fetch_all' => [ 'old' => ['array', 'result' => 'resource', 'mode=' => 'int'], 'new' => ['array', 'result' => '\PgSql\Result', 'mode=' => 'int'], ], 'pg_fetch_all_columns' => [ 'old' => ['array', 'result' => 'resource', 'field=' => 'int'], 'new' => ['array', 'result' => '\PgSql\Result', 'field=' => 'int'], ], 'pg_fetch_array' => [ 'old' => ['array|false', 'result' => 'resource', 'row=' => '?int', 'mode=' => 'int'], 'new' => ['array|false', 'result' => '\PgSql\Result', 'row=' => '?int', 'mode=' => 'int'], ], 'pg_fetch_assoc' => [ 'old' => ['array|false', 'result' => 'resource', 'row=' => '?int'], 'new' => ['array|false', 'result' => '\PgSql\Result', 'row=' => '?int'], ], 'pg_fetch_object' => [ 'old' => ['object|false', 'result' => 'resource', 'row=' => '?int', 'class=' => 'string', 'constructor_args=' => 'array'], 'new' => ['object|false', 'result' => '\PgSql\Result', 'row=' => '?int', 'class=' => 'string', 'constructor_args=' => 'array'], ], 'pg_fetch_result' => [ 'old' => ['string|false|null', 'result' => 'resource', 'row' => 'string|int'], 'new' => ['string|false|null', 'result' => '\PgSql\Result', 'row' => 'string|int'], ], 'pg_fetch_result\'1' => [ 'old' => ['string|false|null', 'result' => 'resource', 'row' => '?int', 'field' => 'string|int'], 'new' => ['string|false|null', 'result' => '\PgSql\Result', 'row' => '?int', 'field' => 'string|int'], ], 'pg_fetch_row' => [ 'old' => ['array|false', 'result' => 'resource', 'row=' => '?int', 'mode=' => 'int'], 'new' => ['array|false', 'result' => '\PgSql\Result', 'row=' => '?int', 'mode=' => 'int'], ], 'pg_field_is_null' => [ 'old' => ['int|false', 'result' => 'resource', 'row'=>'string|int'], 'new' => ['int|false', 'result' => '\PgSql\Result', 'row'=>'string|int'], ], 'pg_field_is_null\'1' => [ 'old' => ['int|false', 'result' => 'resource', 'row' => 'int', 'field' => 'string|int'], 'new' => ['int|false', 'result' => '\PgSql\Result', 'row' => 'int', 'field' => 'string|int'], ], 'pg_field_name' => [ 'old' => ['string', 'result' => 'resource', 'field' => 'int'], 'new' => ['string', 'result' => '\PgSql\Result', 'field' => 'int'], ], 'pg_field_num' => [ 'old' => ['int', 'result' => 'resource', 'field' => 'string'], 'new' => ['int', 'result' => '\PgSql\Result', 'field' => 'string'], ], 'pg_field_prtlen' => [ 'old' => ['int|false', 'result' => 'resource', 'row' => 'string|int'], 'new' => ['int|false', 'result' => '\PgSql\Result', 'row' => 'string|int'], ], 'pg_field_prtlen\'1' => [ 'old' => ['int|false', 'result' => 'resource', 'row' => 'int', 'field' => 'string|int'], 'new' => ['int|false', 'result' => '\PgSql\Result', 'row' => 'int', 'field' => 'string|int'], ], 'pg_field_size' => [ 'old' => ['int', 'result' => 'resource', 'field' => 'int'], 'new' => ['int', 'result' => '\PgSql\Result', 'field' => 'int'], ], 'pg_field_table' => [ 'old' => ['string|int|false', 'result' => 'resource', 'field' => 'int', 'oid_only=' => 'bool'], 'new' => ['string|int|false', 'result' => '\PgSql\Result', 'field' => 'int', 'oid_only=' => 'bool'], ], 'pg_field_type' => [ 'old' => ['string', 'result' => 'resource', 'field' => 'int'], 'new' => ['string', 'result' => '\PgSql\Result', 'field' => 'int'], ], 'pg_field_type_oid' => [ 'old' => ['int|string', 'result' => 'resource', 'field' => 'int'], 'new' => ['int|string', 'result' => '\PgSql\Result', 'field' => 'int'], ], 'pg_flush' => [ 'old' => ['int|bool', 'connection' => 'resource'], 'new' => ['int|bool', 'connection' => '\PgSql\Connection'], ], 'pg_free_result' => [ 'old' => ['bool', 'result' => 'resource'], 'new' => ['bool', 'result' => '\PgSql\Result'], ], 'pg_get_notify' => [ 'old' => ['array|false', 'connection' => 'resource', 'mode=' => 'int'], 'new' => ['array|false', 'connection' => '\PgSql\Connection', 'mode=' => 'int'], ], 'pg_get_pid' => [ 'old' => ['int', 'connection' => 'resource'], 'new' => ['int', 'connection' => '\PgSql\Connection'], ], 'pg_get_result' => [ 'old' => ['resource|false', 'connection' => 'resource'], 'new' => ['\PgSql\Result|false', 'connection' => '\PgSql\Connection'], ], 'pg_host' => [ 'old' => ['string', 'connection=' => 'resource'], 'new' => ['string', 'connection=' => '?\PgSql\Connection'], ], 'pg_insert' => [ 'old' => ['resource|string|false', 'connection' => 'resource', 'table_name' => 'string', 'values' => 'array', 'flags=' => 'int'], 'new' => ['\PgSql\Result|string|false', 'connection' => '\PgSql\Connection', 'table_name' => 'string', 'values' => 'array', 'flags=' => 'int'], ], 'pg_last_error' => [ 'old' => ['string', 'connection=' => '?resource'], 'new' => ['string', 'connection=' => '?\PgSql\Connection'], ], 'pg_last_notice' => [ 'old' => ['string|array|bool', 'connection' => 'resource', 'mode=' => 'int'], 'new' => ['string|array|bool', 'connection' => '\PgSql\Connection', 'mode=' => 'int'], ], 'pg_last_oid' => [ 'old' => ['string|int|false', 'result' => 'resource'], 'new' => ['string|int|false', 'result' => '\PgSql\Result'], ], 'pg_lo_close' => [ 'old' => ['bool', 'lob' => 'resource'], 'new' => ['bool', 'lob' => '\PgSql\Lob'], ], 'pg_lo_create' => [ 'old' => ['int|string|false', 'connection=' => 'resource', 'oid=' => 'int|string'], 'new' => ['int|string|false', 'connection=' => '\PgSql\Connection', 'oid=' => 'int|string'], ], 'pg_lo_export' => [ 'old' => ['bool', 'connection' => 'resource', 'oid' => 'int|string', 'filename' => 'string'], 'new' => ['bool', 'connection' => '\PgSql\Connection', 'oid' => 'int|string', 'filename' => 'string'], ], 'pg_lo_import' => [ 'old' => ['int|string|false', 'connection' => 'resource', 'filename' => 'string', 'oid' => 'string|int'], 'new' => ['int|string|false', 'connection' => '\PgSql\Connection', 'filename' => 'string', 'oid' => 'string|int'], ], 'pg_lo_open' => [ 'old' => ['resource|false', 'connection' => 'resource', 'oid' => 'int|string', 'mode' => 'string'], 'new' => ['\PgSql\Lob|false', 'connection' => '\PgSql\Connection', 'oid' => 'int|string', 'mode' => 'string'], ], 'pg_lo_open\'1' => [ 'old' => ['resource|false', 'connection' => 'int|string', 'oid' => 'string'], 'new' => ['\PgSql\Lob|false', 'connection' => 'int|string', 'oid' => 'string'], ], 'pg_lo_read' => [ 'old' => ['string|false', 'lob' => 'resource', 'length=' => 'int'], 'new' => ['string|false', 'lob' => '\PgSql\Lob', 'length=' => 'int'], ], 'pg_lo_read_all' => [ 'old' => ['int', 'lob' => 'resource'], 'new' => ['int', 'lob' => '\PgSql\Lob'], ], 'pg_lo_seek' => [ 'old' => ['bool', 'lob' => 'resource', 'offset' => 'int', 'whence=' => 'int'], 'new' => ['bool', 'lob' => '\PgSql\Lob', 'offset' => 'int', 'whence=' => 'int'], ], 'pg_lo_tell' => [ 'old' => ['int', 'lob' => 'resource'], 'new' => ['int', 'lob' => '\PgSql\Lob'], ], 'pg_lo_truncate' => [ 'old' => ['bool', 'lob' => 'resource', 'size' => 'int'], 'new' => ['bool', 'lob' => '\PgSql\Lob', 'size' => 'int'], ], 'pg_lo_unlink' => [ 'old' => ['bool', 'connection' => 'resource', 'oid' => 'int|string'], 'new' => ['bool', 'connection' => '\PgSql\Connection', 'oid' => 'int|string'], ], 'pg_lo_write' => [ 'old' => ['int|false', 'lob' => 'resource', 'data' => 'string', 'length=' => '?int'], 'new' => ['int|false', 'lob' => '\PgSql\Lob', 'data' => 'string', 'length=' => '?int'], ], 'pg_meta_data' => [ 'old' => ['array|false', 'connection' => 'resource', 'table_name' => 'string', 'extended=' => 'bool'], 'new' => ['array|false', 'connection' => '\PgSql\Connection', 'table_name' => 'string', 'extended=' => 'bool'], ], 'pg_num_fields' => [ 'old' => ['int', 'result' => 'resource'], 'new' => ['int', 'result' => '\PgSql\Result'], ], 'pg_num_rows' => [ 'old' => ['int', 'result' => 'resource'], 'new' => ['int', 'result' => '\PgSql\Result'], ], 'pg_options' => [ 'old' => ['string', 'connection=' => '?resource'], 'new' => ['string', 'connection=' => '?\PgSql\Connection'], ], 'pg_parameter_status' => [ 'old' => ['string|false', 'connection' => 'resource', 'name' => 'string'], 'new' => ['string|false', 'connection' => '\PgSql\Connection', 'name' => 'string'], ], 'pg_pconnect' => [ 'old' => ['resource|false', 'connection_string' => 'string', 'flags=' => 'int'], 'new' => ['\PgSql\Connection|false', 'connection_string' => 'string', 'flags=' => 'int'], ], 'pg_ping' => [ 'old' => ['bool', 'connection=' => '?resource'], 'new' => ['bool', 'connection=' => '?\PgSql\Connection'], ], 'pg_port' => [ 'old' => ['string', 'connection=' => '?resource'], 'new' => ['string', 'connection=' => '?\PgSql\Connection'], ], 'pg_prepare' => [ 'old' => ['resource|false', 'connection' => 'resource', 'statement_name' => 'string', 'query' => 'string'], 'new' => ['\PgSql\Result|false', 'connection' => '\PgSql\Connection', 'statement_name' => 'string', 'query' => 'string'], ], 'pg_prepare\'1' => [ 'old' => ['resource|false', 'connection' => 'string', 'statement_name' => 'string'], 'new' => ['\PgSql\Result|false', 'connection' => 'string', 'statement_name' => 'string'], ], 'pg_put_line' => [ 'old' => ['bool', 'connection' => 'resource', 'data' => 'string'], 'new' => ['bool', 'connection' => '\PgSql\Connection', 'data' => 'string'], ], 'pg_query' => [ 'old' => ['resource|false', 'connection' => 'resource', 'query' => 'string'], 'new' => ['\PgSql\Result|false', 'connection' => '\PgSql\Connection', 'query' => 'string'], ], 'pg_query\'1' => [ 'old' => ['resource|false', 'connection' => 'string'], 'new' => ['\PgSql\Result|false', 'connection' => 'string'], ], 'pg_query_params' => [ 'old' => ['resource|false', 'connection' => 'resource', 'query' => 'string', 'params' => 'array'], 'new' => ['\PgSql\Result|false', 'connection' => '\PgSql\Connection', 'query' => 'string', 'params' => 'array'], ], 'pg_query_params\'1' => [ 'old' => ['resource|false', 'connection' => 'string', 'query' => 'array'], 'new' => ['\PgSql\Result|false', 'connection' => 'string', 'query' => 'array'], ], 'pg_result_error' => [ 'old' => ['string|false', 'result' => 'resource'], 'new' => ['string|false', 'result' => '\PgSql\Result'], ], 'pg_result_error_field' => [ 'old' => ['string|false|null', 'result' => 'resource', 'field_code' => 'int'], 'new' => ['string|false|null', 'result' => '\PgSql\Result', 'field_code' => 'int'], ], 'pg_result_seek' => [ 'old' => ['bool', 'result' => 'resource', 'row' => 'int'], 'new' => ['bool', 'result' => '\PgSql\Result', 'row' => 'int'], ], 'pg_result_status' => [ 'old' => ['string|int', 'result' => 'resource', 'mode=' => 'int'], 'new' => ['string|int', 'result' => '\PgSql\Result', 'mode=' => 'int'], ], 'pg_select' => [ 'old' => ['string|array|false', 'connection' => 'resource', 'table_name' => 'string', 'conditions' => 'array', 'flags=' => 'int', 'mode='=>'int'], 'new' => ['string|array|false', 'connection' => '\PgSql\Connection', 'table_name' => 'string', 'conditions' => 'array', 'flags=' => 'int', 'mode='=>'int'], ], 'pg_send_execute' => [ 'old' => ['bool|int', 'connection' => 'resource', 'statement_name' => 'string', 'params' => 'array'], 'new' => ['bool|int', 'connection' => '\PgSql\Connection', 'statement_name' => 'string', 'params' => 'array'], ], 'pg_send_prepare' => [ 'old' => ['bool|int', 'connection' => 'resource', 'statement_name' => 'string', 'query' => 'string'], 'new' => ['bool|int', 'connection' => '\PgSql\Connection', 'statement_name' => 'string', 'query' => 'string'], ], 'pg_send_query' => [ 'old' => ['bool|int', 'connection' => 'resource', 'query' => 'string'], 'new' => ['bool|int', 'connection' => '\PgSql\Connection', 'query' => 'string'], ], 'pg_send_query_params' => [ 'old' => ['bool|int', 'connection' => 'resource', 'query' => 'string', 'params' => 'array'], 'new' => ['bool|int', 'connection' => '\PgSql\Connection', 'query' => 'string', 'params' => 'array'], ], 'pg_set_client_encoding' => [ 'old' => ['int', 'connection' => 'resource', 'encoding' => 'string'], 'new' => ['int', 'connection' => '\PgSql\Connection', 'encoding' => 'string'], ], 'pg_set_error_verbosity' => [ 'old' => ['int|false', 'connection' => 'resource', 'verbosity' => 'int'], 'new' => ['int|false', 'connection' => '\PgSql\Connection', 'verbosity' => 'int'], ], 'pg_socket' => [ 'old' => ['resource|false', 'connection' => 'resource'], 'new' => ['resource|false', 'connection' => '\PgSql\Connection'], ], 'pg_trace' => [ 'old' => ['bool', 'filename' => 'string', 'mode=' => 'string', 'connection=' => '?resource'], 'new' => ['bool', 'filename' => 'string', 'mode=' => 'string', 'connection=' => '?\PgSql\Connection'], ], 'pg_transaction_status' => [ 'old' => ['int', 'connection' => 'resource'], 'new' => ['int', 'connection' => '\PgSql\Connection'], ], 'pg_tty' => [ 'old' => ['string', 'connection=' => '?resource'], 'new' => ['string', 'connection=' => '?\PgSql\Connection'], ], 'pg_untrace' => [ 'old' => ['bool', 'connection=' => '?resource'], 'new' => ['bool', 'connection=' => '?\PgSql\Connection'], ], 'pg_update' => [ 'old' => ['string|bool', 'connection' => 'resource', 'table_name' => 'string', 'values' => 'array', 'conditions' => 'array', 'flags=' => 'int'], 'new' => ['string|bool', 'connection' => '\PgSql\Connection', 'table_name' => 'string', 'values' => 'array', 'conditions' => 'array', 'flags=' => 'int'], ], 'pg_version' => [ 'old' => ['array', 'connection=' => '?resource'], 'new' => ['array', 'connection=' => '?\PgSql\Connection'], ], 'pspell_add_to_personal' => [ 'old' => ['bool', 'dictionary'=>'int', 'word'=>'string'], 'new' => ['bool', 'dictionary'=>'PSpell\Dictionary', 'word'=>'string'], ], 'pspell_add_to_session' => [ 'old' => ['bool', 'dictionary'=>'int', 'word'=>'string'], 'new' => ['bool', 'dictionary'=>'PSpell\Dictionary', 'word'=>'string'], ], 'pspell_check' => [ 'old' => ['bool', 'dictionary'=>'int', 'word'=>'string'], 'new' => ['bool', 'dictionary'=>'PSpell\Dictionary', 'word'=>'string'], ], 'pspell_clear_session' => [ 'old' => ['bool', 'dictionary'=>'int'], 'new' => ['bool', 'dictionary'=>'PSpell\Dictionary'], ], 'pspell_config_create' => [ 'old' => ['int', 'language'=>'string', 'spelling='=>'string', 'jargon='=>'string', 'encoding='=>'string'], 'new' => ['PSpell\Config', 'language'=>'string', 'spelling='=>'string', 'jargon='=>'string', 'encoding='=>'string'], ], 'pspell_config_data_dir' => [ 'old' => ['bool', 'config'=>'int', 'directory'=>'string'], 'new' => ['bool', 'config'=>'PSpell\Config', 'directory'=>'string'], ], 'pspell_config_dict_dir' => [ 'old' => ['bool', 'config'=>'int', 'directory'=>'string'], 'new' => ['bool', 'config'=>'PSpell\Config', 'directory'=>'string'], ], 'pspell_config_ignore' => [ 'old' => ['bool', 'config'=>'int', 'min_length'=>'int'], 'new' => ['bool', 'config'=>'PSpell\Config', 'min_length'=>'int'], ], 'pspell_config_mode' => [ 'old' => ['bool', 'config'=>'int', 'mode'=>'int'], 'new' => ['bool', 'config'=>'PSpell\Config', 'mode'=>'int'], ], 'pspell_config_personal' => [ 'old' => ['bool', 'config'=>'int', 'filename'=>'string'], 'new' => ['bool', 'config'=>'PSpell\Config', 'filename'=>'string'], ], 'pspell_config_repl' => [ 'old' => ['bool', 'config'=>'int', 'filename'=>'string'], 'new' => ['bool', 'config'=>'PSpell\Config', 'filename'=>'string'], ], 'pspell_config_runtogether' => [ 'old' => ['bool', 'config'=>'int', 'allow'=>'bool'], 'new' => ['bool', 'config'=>'PSpell\Config', 'allow'=>'bool'], ], 'pspell_config_save_repl' => [ 'old' => ['bool', 'config'=>'int', 'save'=>'bool'], 'new' => ['bool', 'config'=>'PSpell\Config', 'save'=>'bool'], ], 'pspell_new' => [ 'old' => ['int|false', 'language'=>'string', 'spelling='=>'string', 'jargon='=>'string', 'encoding='=>'string', 'mode='=>'int'], 'new' => ['PSpell\Dictionary|false', 'language'=>'string', 'spelling='=>'string', 'jargon='=>'string', 'encoding='=>'string', 'mode='=>'int'], ], 'pspell_new_config' => [ 'old' => ['int|false', 'config'=>'int'], 'new' => ['PSpell\Dictionary|false', 'config'=>'PSpell\Config'], ], 'pspell_new_personal' => [ 'old' => ['int|false', 'filename'=>'string', 'language'=>'string', 'spelling='=>'string', 'jargon='=>'string', 'encoding='=>'string', 'mode='=>'int'], 'new' => ['PSpell\Dictionary|false', 'filename'=>'string', 'language'=>'string', 'spelling='=>'string', 'jargon='=>'string', 'encoding='=>'string', 'mode='=>'int'], ], 'pspell_save_wordlist' => [ 'old' => ['bool', 'dictionary'=>'int'], 'new' => ['bool', 'dictionary'=>'PSpell\Dictionary'], ], 'pspell_store_replacement' => [ 'old' => ['bool', 'dictionary'=>'int', 'misspelled'=>'string', 'correct'=>'string'], 'new' => ['bool', 'dictionary'=>'PSpell\Dictionary', 'misspelled'=>'string', 'correct'=>'string'], ], 'pspell_suggest' => [ 'old' => ['array', 'dictionary'=>'int', 'word'=>'string'], 'new' => ['array', 'dictionary'=>'PSpell\Dictionary', 'word'=>'string'], ], 'stream_select' => [ 'old' => ['int|false', '&rw_read'=>'?resource[]', '&rw_write'=>'?resource[]', '&rw_except'=>'?resource[]', 'seconds'=>'?int', 'microseconds='=>'int'], 'new' => ['int|false', '&rw_read'=>'?resource[]', '&rw_write'=>'?resource[]', '&rw_except'=>'?resource[]', 'seconds'=>'?int', 'microseconds='=>'?int'], ], 'mb_check_encoding' => [ 'old' => ['bool', 'value='=>'array|string|null', 'encoding='=>'string|null'], 'new' => ['bool', 'value'=>'array|string', 'encoding='=>'string|null'], ], 'ctype_alnum' => [ 'old' => ['bool', 'text'=>'string|int'], 'new' => ['bool', 'text'=>'string'], ], 'ctype_alpha' => [ 'old' => ['bool', 'text'=>'string|int'], 'new' => ['bool', 'text'=>'string'], ], 'ctype_cntrl' => [ 'old' => ['bool', 'text'=>'string|int'], 'new' => ['bool', 'text'=>'string'], ], 'ctype_digit' => [ 'old' => ['bool', 'text'=>'string|int'], 'new' => ['bool', 'text'=>'string'], ], 'ctype_graph' => [ 'old' => ['bool', 'text'=>'string|int'], 'new' => ['bool', 'text'=>'string'], ], 'ctype_lower' => [ 'old' => ['bool', 'text'=>'string|int'], 'new' => ['bool', 'text'=>'string'], ], 'ctype_print' => [ 'old' => ['bool', 'text'=>'string|int'], 'new' => ['bool', 'text'=>'string'], ], 'ctype_punct' => [ 'old' => ['bool', 'text'=>'string|int'], 'new' => ['bool', 'text'=>'string'], ], 'ctype_space' => [ 'old' => ['bool', 'text'=>'string|int'], 'new' => ['bool', 'text'=>'string'], ], 'ctype_upper' => [ 'old' => ['bool', 'text'=>'string|int'], 'new' => ['bool', 'text'=>'string'], ], 'ctype_xdigit' => [ 'old' => ['bool', 'text'=>'string|int'], 'new' => ['bool', 'text'=>'string'], ], 'key' => [ 'old' => ['int|string|null', 'array'=>'array|object'], 'new' => ['int|string|null', 'array'=>'array'], ], 'current' => [ 'old' => ['mixed|false', 'array'=>'array|object'], 'new' => ['mixed|false', 'array'=>'array'], ], 'next' => [ 'old' => ['mixed', '&r_array'=>'array|object'], 'new' => ['mixed', '&r_array'=>'array'], ], 'prev' => [ 'old' => ['mixed', '&r_array'=>'array|object'], 'new' => ['mixed', '&r_array'=>'array'], ], 'reset' => [ 'old' => ['mixed|false', '&r_array'=>'array|object'], 'new' => ['mixed|false', '&r_array'=>'array'], ], ], 'removed' => [ 'ReflectionMethod::isStatic' => ['bool'], ], ]; [ 'json_validate' => ['bool', 'json'=>'string', 'depth='=>'positive-int', 'flags='=>'int'], ], 'changed' => [ 'gc_status' => [ 'old' => ['array{runs:int,collected:int,threshold:int,roots:int}'], 'new' => ['array{runs:int,collected:int,threshold:int,roots:int,running:bool,protected:bool,full:bool,buffer_size:int,application_time:float,collector_time:float,destructor_time:float,free_time:float}'], ], 'srand' => [ 'old' => ['void', 'seed='=>'int', 'mode='=>'int'], 'new' => ['void', 'seed='=>'?int', 'mode='=>'int'], ], 'mt_srand' => [ 'old' => ['void', 'seed='=>'int', 'mode='=>'int'], 'new' =>['void', 'seed='=>'?int', 'mode='=>'int'], ], 'posix_getrlimit' => [ 'old' => ['array{"soft core": string, "hard core": string, "soft data": string, "hard data": string, "soft stack": integer, "hard stack": string, "soft totalmem": string, "hard totalmem": string, "soft rss": string, "hard rss": string, "soft maxproc": integer, "hard maxproc": integer, "soft memlock": integer, "hard memlock": integer, "soft cpu": string, "hard cpu": string, "soft filesize": string, "hard filesize": string, "soft openfiles": integer, "hard openfiles": integer}|false'], 'new' => ['array{"soft core": string, "hard core": string, "soft data": string, "hard data": string, "soft stack": integer, "hard stack": string, "soft totalmem": string, "hard totalmem": string, "soft rss": string, "hard rss": string, "soft maxproc": integer, "hard maxproc": integer, "soft memlock": integer, "hard memlock": integer, "soft cpu": string, "hard cpu": string, "soft filesize": string, "hard filesize": string, "soft openfiles": integer, "hard openfiles": integer}|false', 'resource=' => '?int'], ], 'natcasesort' => [ 'old' => ['bool', '&rw_array'=>'array'], 'new' => ['true', '&rw_array'=>'array'], ], 'natsort' => [ 'old' => ['bool', '&rw_array'=>'array'], 'new' => ['true', '&rw_array'=>'array'], ], 'rsort' => [ 'old' => ['bool', '&rw_array'=>'array', 'flags='=>'int'], 'new' => ['true', '&rw_array'=>'array', 'flags='=>'int'], ], 'imap_setflag_full' => [ 'old' => ['bool', 'imap'=>'IMAP\Connection', 'sequence'=>'string', 'flag'=>'string', 'options='=>'int'], 'new' => ['true', 'imap'=>'IMAP\Connection', 'sequence'=>'string', 'flag'=>'string', 'options='=>'int'], ], 'imap_expunge' => [ 'old' => ['bool', 'imap'=>'IMAP\Connection'], 'new' => ['true', 'imap'=>'IMAP\Connection'], ], 'imap_gc' => [ 'old' => ['bool', 'imap'=>'IMAP\Connection', 'flags'=>'int'], 'new' => ['true', 'imap'=>'IMAP\Connection', 'flags'=>'int'], ], 'imap_undelete' => [ 'old' => ['bool', 'imap'=>'IMAP\Connection', 'message_nums'=>'string', 'flags='=>'int'], 'new' => ['true', 'imap'=>'IMAP\Connection', 'message_nums'=>'string', 'flags='=>'int'], ], 'imap_delete' => [ 'old' => ['bool', 'imap'=>'IMAP\Connection', 'message_nums'=>'string', 'flags='=>'int'], 'new' => ['true', 'imap'=>'IMAP\Connection', 'message_nums'=>'string', 'flags='=>'int'], ], 'imap_clearflag_full' => [ 'old' => ['bool', 'imap'=>'IMAP\Connection', 'sequence'=>'string', 'flag'=>'string', 'options='=>'int'], 'new' => ['true', 'imap'=>'IMAP\Connection', 'sequence'=>'string', 'flag'=>'string', 'options='=>'int'], ], 'imap_close' => [ 'old' => ['bool', 'imap'=>'IMAP\Connection', 'flags='=>'int'], 'new' => ['true', 'imap'=>'IMAP\Connection', 'flags='=>'int'], ], 'intlcal_clear' => [ 'old' => ['bool', 'calendar'=>'IntlCalendar', 'field='=>'?int'], 'new' => ['true', 'calendar'=>'IntlCalendar', 'field='=>'?int'], ], 'intlcal_set_lenient' => [ 'old' => ['bool', 'calendar'=>'IntlCalendar', 'lenient'=>'bool'], 'new' => ['true', 'calendar'=>'IntlCalendar', 'lenient'=>'bool'], ], 'intlcal_set_first_day_of_week' => [ 'old' => ['bool', 'calendar'=>'IntlCalendar', 'dayOfWeek'=>'int'], 'new' => ['true', 'calendar'=>'IntlCalendar', 'dayOfWeek'=>'int'], ], 'datefmt_set_timezone' => [ 'old' => ['false|null', 'formatter'=>'IntlDateFormatter', 'timezone'=>'IntlTimeZone|DateTimeZone|string|null'], 'new' => ['bool', 'formatter'=>'IntlDateFormatter', 'timezone'=>'IntlTimeZone|DateTimeZone|string|null'], ], 'IntlRuleBasedBreakIterator::setText' => [ 'old' => ['?bool', 'text'=>'string'], 'new' => ['bool', 'text'=>'string'], ], 'IntlCodePointBreakIterator::setText' => [ 'old' => ['?bool', 'text'=>'string'], 'new' => ['bool', 'text'=>'string'], ], 'IntlDateFormatter::setTimeZone' => [ 'old' => ['null|false', 'timezone'=>'IntlTimeZone|DateTimeZone|string|null'], 'new' => ['bool', 'timezone'=>'IntlTimeZone|DateTimeZone|string|null'], ], 'IntlChar::enumCharNames' => [ 'old' => ['?bool', 'start'=>'string|int', 'end'=>'string|int', 'callback'=>'callable(int,int,int):void', 'type='=>'int'], 'new' => ['bool', 'start'=>'string|int', 'end'=>'string|int', 'callback'=>'callable(int,int,int):void', 'type='=>'int'], ], 'IntlBreakIterator::setText' => [ 'old' => ['?bool', 'text'=>'string'], 'new' => ['bool', 'text'=>'string'], ], 'strrchr' => [ 'old' => ['string|false', 'haystack'=>'string', 'needle'=>'string'], 'new' => ['string|false', 'haystack'=>'string', 'needle'=>'string', 'before_needle='=>'bool'], ], 'get_class' => [ 'old' => ['class-string', 'object='=>'object'], 'new' => ['class-string', 'object'=>'object'], ], 'get_parent_class' => [ 'old' => ['class-string|false', 'object_or_class='=>'object|class-string'], 'new' => ['class-string|false', 'object_or_class'=>'object|class-string'], ], ], 'removed' => [ 'OutOfBoundsException::__clone' => ['void'], 'ArgumentCountError::__clone' => ['void'], 'ArithmeticError::__clone' => ['void'], 'BadFunctionCallException::__clone' => ['void'], 'BadMethodCallException::__clone' => ['void'], 'ClosedGeneratorException::__clone' => ['void'], 'DomainException::__clone' => ['void'], 'ErrorException::__clone' => ['void'], 'IntlException::__clone' => ['void'], 'InvalidArgumentException::__clone' => ['void'], 'JsonException::__clone' => ['void'], 'LengthException::__clone' => ['void'], 'LogicException::__clone' => ['void'], 'OutOfRangeException::__clone' => ['void'], 'OverflowException::__clone' => ['void'], 'ParseError::__clone' => ['void'], 'RangeException::__clone' => ['void'], 'ReflectionNamedType::__clone' => ['void'], 'ReflectionObject::__clone' => ['void'], 'RuntimeException::__clone' => ['void'], 'TypeError::__clone' => ['void'], 'UnderflowException::__clone' => ['void'], 'UnexpectedValueException::__clone' => ['void'], 'IntlCodePointBreakIterator::__construct' => ['void'], ], ]; * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ declare (strict_types=1); namespace _HumbugBox7ff99e199a36\Fidry\CpuCoreCounter; use RuntimeException; final class NumberOfCpuCoreNotFound extends RuntimeException { public static function create() : self { return new self('Could not find the number of CPU cores available.'); } } * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ declare (strict_types=1); namespace _HumbugBox7ff99e199a36\Fidry\CpuCoreCounter; /** * @readonly */ final class ParallelisationResult { /** * @var positive-int|0 */ public $passedReservedCpus; /** * @var non-zero-int|null */ public $passedCountLimit; /** * @var float|null */ public $passedLoadLimit; /** * @var float|null */ public $passedSystemLoadAverage; /** * @var non-zero-int|null */ public $correctedCountLimit; /** * @var float|null */ public $correctedSystemLoadAverage; /** * @var positive-int */ public $totalCoresCount; /** * @var positive-int */ public $availableCpus; /** * @param positive-int|0 $passedReservedCpus * @param non-zero-int|null $passedCountLimit * @param non-zero-int|null $correctedCountLimit * @param positive-int $totalCoresCount * @param positive-int $availableCpus */ public function __construct(int $passedReservedCpus, ?int $passedCountLimit, ?float $passedLoadLimit, ?float $passedSystemLoadAverage, ?int $correctedCountLimit, ?float $correctedSystemLoadAverage, int $totalCoresCount, int $availableCpus) { $this->passedReservedCpus = $passedReservedCpus; $this->passedCountLimit = $passedCountLimit; $this->passedLoadLimit = $passedLoadLimit; $this->passedSystemLoadAverage = $passedSystemLoadAverage; $this->correctedCountLimit = $correctedCountLimit; $this->correctedSystemLoadAverage = $correctedSystemLoadAverage; $this->totalCoresCount = $totalCoresCount; $this->availableCpus = $availableCpus; } } * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ declare (strict_types=1); namespace _HumbugBox7ff99e199a36\Fidry\CpuCoreCounter; use _HumbugBox7ff99e199a36\Fidry\CpuCoreCounter\Finder\CpuCoreFinder; use _HumbugBox7ff99e199a36\Fidry\CpuCoreCounter\Finder\EnvVariableFinder; use _HumbugBox7ff99e199a36\Fidry\CpuCoreCounter\Finder\FinderRegistry; use InvalidArgumentException; use function implode; use function max; use function sprintf; use function sys_getloadavg; use const PHP_EOL; final class CpuCoreCounter { /** * @var list */ private $finders; /** * @var positive-int|null */ private $count; /** * @param list|null $finders */ public function __construct(?array $finders = null) { $this->finders = $finders ?? FinderRegistry::getDefaultLogicalFinders(); } /** * @param positive-int|0 $reservedCpus Number of CPUs to reserve. This is useful when you want * to reserve some CPUs for other processes. If the main * process is going to be busy still, you may want to set * this value to 1. * @param non-zero-int|null $countLimit The maximum number of CPUs to return. If not provided, it * may look for a limit in the environment variables, e.g. * KUBERNETES_CPU_LIMIT. If negative, the limit will be * the total number of cores found minus the absolute value. * For instance if the system has 10 cores and countLimit=-2, * then the effective limit considered will be 8. * @param float|null $loadLimit Element of [0., 1.]. Percentage representing the * amount of cores that should be used among the available * resources. For instance, if set to 0.7, it will use 70% * of the available cores, i.e. if 1 core is reserved, 11 * cores are available and 5 are busy, it will use 70% * of (11-1-5)=5 cores, so 3 cores. Set this parameter to null * to skip this check. Beware that 1 does not mean "no limit", * but 100% of the _available_ resources, i.e. with the * previous example, it will return 5 cores. How busy is * the system is determined by the system load average * (see $systemLoadAverage). * @param float|null $systemLoadAverage The system load average. If passed, it will use * this information to limit the available cores based * on the _available_ resources. For instance, if there * is 10 cores but 3 are busy, then only 7 cores will * be considered for further calculation. If set to * `null`, it will use `sys_getloadavg()` to check the * load of the system in the past minute. You can * otherwise pass an arbitrary value. Should be a * positive float. * * @see https://php.net/manual/en/function.sys-getloadavg.php */ public function getAvailableForParallelisation(int $reservedCpus = 0, ?int $countLimit = null, ?float $loadLimit = null, ?float $systemLoadAverage = 0.0) : ParallelisationResult { self::checkCountLimit($countLimit); self::checkLoadLimit($loadLimit); self::checkSystemLoadAverage($systemLoadAverage); $totalCoreCount = $this->getCountWithFallback(1); $availableCores = max(1, $totalCoreCount - $reservedCpus); // Adjust available CPUs based on current load if (null !== $loadLimit) { $correctedSystemLoadAverage = null === $systemLoadAverage ? sys_getloadavg()[0] ?? 0.0 : $systemLoadAverage; $availableCores = max(1, $loadLimit * ($availableCores - $correctedSystemLoadAverage)); } if (null === $countLimit) { $correctedCountLimit = self::getKubernetesLimit(); } else { $correctedCountLimit = $countLimit > 0 ? $countLimit : max(1, $totalCoreCount + $countLimit); } if (null !== $correctedCountLimit && $availableCores > $correctedCountLimit) { $availableCores = $correctedCountLimit; } return new ParallelisationResult($reservedCpus, $countLimit, $loadLimit, $systemLoadAverage, $correctedCountLimit, $correctedSystemLoadAverage ?? $systemLoadAverage, $totalCoreCount, (int) $availableCores); } /** * @throws NumberOfCpuCoreNotFound * * @return positive-int */ public function getCount() : int { // Memoize result if (null === $this->count) { $this->count = $this->findCount(); } return $this->count; } /** * @param positive-int $fallback * * @return positive-int */ public function getCountWithFallback(int $fallback) : int { try { return $this->getCount(); } catch (NumberOfCpuCoreNotFound $exception) { return $fallback; } } /** * This method is mostly for debugging purposes. */ public function trace() : string { $output = []; foreach ($this->finders as $finder) { $output[] = sprintf('Executing the finder "%s":', $finder->toString()); $output[] = $finder->diagnose(); $cores = $finder->find(); if (null !== $cores) { $output[] = 'Result found: ' . $cores; break; } $output[] = '–––'; } return implode(PHP_EOL, $output); } /** * @throws NumberOfCpuCoreNotFound * * @return positive-int */ private function findCount() : int { foreach ($this->finders as $finder) { $cores = $finder->find(); if (null !== $cores) { return $cores; } } throw NumberOfCpuCoreNotFound::create(); } /** * @throws NumberOfCpuCoreNotFound * * @return array{CpuCoreFinder, positive-int} */ public function getFinderAndCores() : array { foreach ($this->finders as $finder) { $cores = $finder->find(); if (null !== $cores) { return [$finder, $cores]; } } throw NumberOfCpuCoreNotFound::create(); } /** * @return positive-int|null */ public static function getKubernetesLimit() : ?int { $finder = new EnvVariableFinder('KUBERNETES_CPU_LIMIT'); return $finder->find(); } private static function checkCountLimit(?int $countLimit) : void { if (0 === $countLimit) { throw new InvalidArgumentException('The count limit must be a non zero integer. Got "0".'); } } private static function checkLoadLimit(?float $loadLimit) : void { if (null === $loadLimit) { return; } if ($loadLimit < 0.0 || $loadLimit > 1.0) { throw new InvalidArgumentException(sprintf('The load limit must be in the range [0., 1.], got "%s".', $loadLimit)); } } private static function checkSystemLoadAverage(?float $systemLoadAverage) : void { if (null !== $systemLoadAverage && $systemLoadAverage < 0.0) { throw new InvalidArgumentException(sprintf('The system load average must be a positive float, got "%s".', $systemLoadAverage)); } } } * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ declare (strict_types=1); namespace _HumbugBox7ff99e199a36\Fidry\CpuCoreCounter\Executor; use function fclose; use function function_exists; use function is_resource; use function proc_close; use function proc_open; use function stream_get_contents; final class ProcOpenExecutor implements ProcessExecutor { public function execute(string $command) : ?array { if (!function_exists('proc_open')) { return null; } $pipes = []; $process = @proc_open($command, [ ['pipe', 'rb'], ['pipe', 'wb'], // stdout ['pipe', 'wb'], ], $pipes); if (!is_resource($process)) { return null; } fclose($pipes[0]); $stdout = (string) stream_get_contents($pipes[1]); $stderr = (string) stream_get_contents($pipes[2]); proc_close($process); return [$stdout, $stderr]; } } * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ declare (strict_types=1); namespace _HumbugBox7ff99e199a36\Fidry\CpuCoreCounter\Executor; interface ProcessExecutor { /** * @return array{string, string}|null STDOUT & STDERR tuple */ public function execute(string $command) : ?array; } * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ declare (strict_types=1); namespace _HumbugBox7ff99e199a36\Fidry\CpuCoreCounter\Finder; final class FinderRegistry { /** * @return list List of all the known finders with all their variants. */ public static function getAllVariants() : array { return [new CpuInfoFinder(), new DummyCpuCoreFinder(1), new HwLogicalFinder(), new HwPhysicalFinder(), new LscpuLogicalFinder(), new LscpuPhysicalFinder(), new _NProcessorFinder(), new NProcessorFinder(), new NProcFinder(\true), new NProcFinder(\false), new NullCpuCoreFinder(), SkipOnOSFamilyFinder::forWindows(new DummyCpuCoreFinder(1)), OnlyOnOSFamilyFinder::forWindows(new DummyCpuCoreFinder(1)), new OnlyInPowerShellFinder(new CmiCmdletLogicalFinder()), new OnlyInPowerShellFinder(new CmiCmdletPhysicalFinder()), new WindowsRegistryLogicalFinder(), new WmicPhysicalFinder(), new WmicLogicalFinder()]; } /** * @return list */ public static function getDefaultLogicalFinders() : array { return [OnlyOnOSFamilyFinder::forWindows(new OnlyInPowerShellFinder(new CmiCmdletLogicalFinder())), OnlyOnOSFamilyFinder::forWindows(new WindowsRegistryLogicalFinder()), OnlyOnOSFamilyFinder::forWindows(new WmicLogicalFinder()), new NProcFinder(), new HwLogicalFinder(), new _NProcessorFinder(), new NProcessorFinder(), new LscpuLogicalFinder(), new CpuInfoFinder()]; } /** * @return list */ public static function getDefaultPhysicalFinders() : array { return [OnlyOnOSFamilyFinder::forWindows(new OnlyInPowerShellFinder(new CmiCmdletPhysicalFinder())), OnlyOnOSFamilyFinder::forWindows(new WmicPhysicalFinder()), new HwPhysicalFinder(), new LscpuPhysicalFinder()]; } private function __construct() { } } * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ declare (strict_types=1); namespace _HumbugBox7ff99e199a36\Fidry\CpuCoreCounter\Finder; use function getenv; use function sprintf; final class OnlyInPowerShellFinder implements CpuCoreFinder { /** * @var CpuCoreFinder */ private $decoratedFinder; public function __construct(CpuCoreFinder $decoratedFinder) { $this->decoratedFinder = $decoratedFinder; } public function diagnose() : string { $powerShellModulePath = getenv('PSModulePath'); return $this->skip() ? sprintf('Skipped; no power shell module path detected ("%s").', $powerShellModulePath) : $this->decoratedFinder->diagnose(); } public function find() : ?int { return $this->skip() ? null : $this->decoratedFinder->find(); } public function toString() : string { return sprintf('OnlyInPowerShellFinder(%s)', $this->decoratedFinder->toString()); } private function skip() : bool { return \false === getenv('PSModulePath'); } } * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ declare (strict_types=1); namespace _HumbugBox7ff99e199a36\Fidry\CpuCoreCounter\Finder; use function implode; use function sprintf; use const PHP_OS_FAMILY; final class OnlyOnOSFamilyFinder implements CpuCoreFinder { /** * @var list */ private $skippedOSFamilies; /** * @var CpuCoreFinder */ private $decoratedFinder; /** * @param string|list $skippedOSFamilyOrFamilies */ public function __construct($skippedOSFamilyOrFamilies, CpuCoreFinder $decoratedFinder) { $this->skippedOSFamilies = (array) $skippedOSFamilyOrFamilies; $this->decoratedFinder = $decoratedFinder; } public static function forWindows(CpuCoreFinder $decoratedFinder) : self { return new self('Windows', $decoratedFinder); } public static function forBSD(CpuCoreFinder $decoratedFinder) : self { return new self('BSD', $decoratedFinder); } public static function forDarwin(CpuCoreFinder $decoratedFinder) : self { return new self('Darwin', $decoratedFinder); } public static function forSolaris(CpuCoreFinder $decoratedFinder) : self { return new self('Solaris', $decoratedFinder); } public static function forLinux(CpuCoreFinder $decoratedFinder) : self { return new self('Linux', $decoratedFinder); } public function diagnose() : string { return $this->skip() ? sprintf('Skipped platform detected ("%s").', PHP_OS_FAMILY) : $this->decoratedFinder->diagnose(); } public function find() : ?int { return $this->skip() ? null : $this->decoratedFinder->find(); } public function toString() : string { return sprintf('OnlyOnOSFamilyFinder(only=(%s),%s)', implode(',', $this->skippedOSFamilies), $this->decoratedFinder->toString()); } private function skip() : bool { return !\in_array(PHP_OS_FAMILY, $this->skippedOSFamilies, \true); } } * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ declare (strict_types=1); namespace _HumbugBox7ff99e199a36\Fidry\CpuCoreCounter\Finder; interface CpuCoreFinder { /** * Provides an explanation which may offer some insight as to what the finder * will be able to find. * * This is practical to have an idea of what each finder will find collect * information for the unit tests, since integration tests are quite complicated * as dependent on complex infrastructures. */ public function diagnose() : string; /** * Find the number of CPU cores. If it could not find it, returns null. The * means used to find the cores are at the implementation discretion. * * @return positive-int|null */ public function find() : ?int; public function toString() : string; } * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ declare (strict_types=1); namespace _HumbugBox7ff99e199a36\Fidry\CpuCoreCounter\Finder; use function count; use function explode; use function is_array; use function preg_grep; use const PHP_EOL; /** * The number of logical cores. * * @see https://stackoverflow.com/a/23378780/5846754 */ final class LscpuLogicalFinder extends ProcOpenBasedFinder { public function getCommand() : string { return 'lscpu -p'; } protected function countCpuCores(string $process) : ?int { $lines = explode(PHP_EOL, $process); $actualLines = preg_grep('/^\\d+,/', $lines); if (!is_array($actualLines)) { return null; } $count = count($actualLines); return 0 === $count ? null : $count; } public function toString() : string { return 'LscpuLogicalFinder'; } } * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ declare (strict_types=1); namespace _HumbugBox7ff99e199a36\Fidry\CpuCoreCounter\Finder; use function preg_match; /** * Find the number of physical CPU cores for Windows. * * @see https://github.com/paratestphp/paratest/blob/c163539818fd96308ca8dc60f46088461e366ed4/src/Runners/PHPUnit/Options.php#L912-L916 */ final class CmiCmdletPhysicalFinder extends ProcOpenBasedFinder { private const CPU_CORE_COUNT_REGEX = '/NumberOfCores[\\s\\n]-+[\\s\\n]+(?\\d+)/'; protected function getCommand() : string { return 'Get-CimInstance -ClassName Win32_Processor | Select-Object -Property NumberOfCores'; } public function toString() : string { return 'CmiCmdletPhysicalFinder'; } protected function countCpuCores(string $process) : ?int { if (0 === preg_match(self::CPU_CORE_COUNT_REGEX, $process, $matches)) { return parent::countCpuCores($process); } $count = $matches['count']; return parent::countCpuCores($count); } } * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ declare (strict_types=1); namespace _HumbugBox7ff99e199a36\Fidry\CpuCoreCounter\Finder; use function preg_match; /** * Find the number of logical CPU cores for Windows leveraging the Get-CimInstance * cmdlet, which is a newer version that is recommended over Get-WmiObject. */ final class CmiCmdletLogicalFinder extends ProcOpenBasedFinder { private const CPU_CORE_COUNT_REGEX = '/NumberOfLogicalProcessors[\\s\\n]-+[\\s\\n]+(?\\d+)/'; protected function getCommand() : string { return 'Get-CimInstance -ClassName Win32_ComputerSystem | Select-Object -Property NumberOfLogicalProcessors'; } public function toString() : string { return 'CmiCmdletLogicalFinder'; } protected function countCpuCores(string $process) : ?int { if (0 === preg_match(self::CPU_CORE_COUNT_REGEX, $process, $matches)) { return parent::countCpuCores($process); } $count = $matches['count']; return parent::countCpuCores($count); } } * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ declare (strict_types=1); namespace _HumbugBox7ff99e199a36\Fidry\CpuCoreCounter\Finder; use function count; use function explode; use function is_array; use function preg_grep; use function strtok; use const PHP_EOL; /** * The number of physical processors. * * @see https://stackoverflow.com/a/23378780/5846754 */ final class LscpuPhysicalFinder extends ProcOpenBasedFinder { public function toString() : string { return 'LscpuPhysicalFinder'; } public function getCommand() : string { return 'lscpu -p'; } protected function countCpuCores(string $process) : ?int { $lines = explode(PHP_EOL, $process); $actualLines = preg_grep('/^\\d+/', $lines); if (!is_array($actualLines)) { return null; } $cores = []; foreach ($actualLines as $line) { strtok($line, ','); $core = strtok(','); if (\false === $core) { continue; } $cores[$core] = \true; } unset($cores['-']); $count = count($cores); return 0 === $count ? null : $count; } } * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ declare (strict_types=1); namespace _HumbugBox7ff99e199a36\Fidry\CpuCoreCounter\Finder; use function preg_match; /** * Find the number of logical CPU cores for Windows. * * @see https://github.com/paratestphp/paratest/blob/c163539818fd96308ca8dc60f46088461e366ed4/src/Runners/PHPUnit/Options.php#L912-L916 */ final class WmicLogicalFinder extends ProcOpenBasedFinder { private const CPU_CORE_COUNT_REGEX = '/NumberOfLogicalProcessors[\\s\\n]+(?\\d+)/'; protected function getCommand() : string { return 'wmic cpu get NumberOfLogicalProcessors'; } public function toString() : string { return 'WmicLogicalFinder'; } protected function countCpuCores(string $process) : ?int { if (0 === preg_match(self::CPU_CORE_COUNT_REGEX, $process, $matches)) { return parent::countCpuCores($process); } $count = $matches['count']; return parent::countCpuCores($count); } } * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ declare (strict_types=1); namespace _HumbugBox7ff99e199a36\Fidry\CpuCoreCounter\Finder; use function getenv; use function preg_match; use function sprintf; use function var_export; final class EnvVariableFinder implements CpuCoreFinder { /** @var string */ private $environmentVariableName; public function __construct(string $environmentVariableName) { $this->environmentVariableName = $environmentVariableName; } public function diagnose() : string { $value = getenv($this->environmentVariableName); return sprintf('parse(getenv(%s)=%s)=%s', $this->environmentVariableName, var_export($value, \true), self::isPositiveInteger($value) ? $value : 'null'); } public function find() : ?int { $value = getenv($this->environmentVariableName); return self::isPositiveInteger($value) ? (int) $value : null; } public function toString() : string { return sprintf('getenv(%s)', $this->environmentVariableName); } /** * @param string|false $value */ private static function isPositiveInteger($value) : bool { return \false !== $value && 1 === preg_match('/^\\d+$/', $value) && (int) $value > 0; } } * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ declare (strict_types=1); namespace _HumbugBox7ff99e199a36\Fidry\CpuCoreCounter\Finder; /** * Find the number of physical CPU cores for Linux, BSD and OSX. * * @see https://github.com/paratestphp/paratest/blob/c163539818fd96308ca8dc60f46088461e366ed4/src/Runners/PHPUnit/Options.php#L903-L909 * @see https://opensource.apple.com/source/xnu/xnu-792.2.4/libkern/libkern/sysctl.h.auto.html */ final class HwPhysicalFinder extends ProcOpenBasedFinder { protected function getCommand() : string { return 'sysctl -n hw.physicalcpu'; } public function toString() : string { return 'HwPhysicalFinder'; } } * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ declare (strict_types=1); namespace _HumbugBox7ff99e199a36\Fidry\CpuCoreCounter\Finder; /** * Find the number of logical CPU cores for FreeSBD, Solaris and the likes. * * @see https://twitter.com/freebsdfrau/status/1052016199452700678?s=20&t=M2pHkRqmmna-UF68lfL2hw */ final class NProcessorFinder extends ProcOpenBasedFinder { protected function getCommand() : string { return 'getconf NPROCESSORS_ONLN'; } public function toString() : string { return 'NProcessorFinder'; } } * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ declare (strict_types=1); namespace _HumbugBox7ff99e199a36\Fidry\CpuCoreCounter\Finder; use function sprintf; /** * This finder returns whatever value you gave to it. This is useful for testing * or as a fallback to avoid to catch the NumberOfCpuCoreNotFound exception. */ final class DummyCpuCoreFinder implements CpuCoreFinder { /** * @var positive-int */ private $count; public function diagnose() : string { return sprintf('Will return "%d".', $this->count); } /** * @param positive-int $count */ public function __construct(int $count) { $this->count = $count; } public function find() : ?int { return $this->count; } public function toString() : string { return sprintf('DummyCpuCoreFinder(value=%d)', $this->count); } } * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ declare (strict_types=1); namespace _HumbugBox7ff99e199a36\Fidry\CpuCoreCounter\Finder; /** * Find the number of logical CPU cores for Linux, BSD and OSX. * * @see https://github.com/paratestphp/paratest/blob/c163539818fd96308ca8dc60f46088461e366ed4/src/Runners/PHPUnit/Options.php#L903-L909 * @see https://opensource.apple.com/source/xnu/xnu-792.2.4/libkern/libkern/sysctl.h.auto.html */ final class HwLogicalFinder extends ProcOpenBasedFinder { protected function getCommand() : string { return 'sysctl -n hw.logicalcpu'; } public function toString() : string { return 'HwLogicalFinder'; } } * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ declare (strict_types=1); namespace _HumbugBox7ff99e199a36\Fidry\CpuCoreCounter\Finder; /** * Find the number of logical CPU cores for Linux and the likes. * * @see https://twitter.com/freebsdfrau/status/1052016199452700678?s=20&t=M2pHkRqmmna-UF68lfL2hw */ final class _NProcessorFinder extends ProcOpenBasedFinder { protected function getCommand() : string { return 'getconf _NPROCESSORS_ONLN'; } public function toString() : string { return '_NProcessorFinder'; } } * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ declare (strict_types=1); namespace _HumbugBox7ff99e199a36\Fidry\CpuCoreCounter\Finder; /** * This finder returns whatever value you gave to it. This is useful for testing. */ final class NullCpuCoreFinder implements CpuCoreFinder { public function diagnose() : string { return 'Will return "null".'; } public function find() : ?int { return null; } public function toString() : string { return 'NullCpuCoreFinder'; } } * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ declare (strict_types=1); namespace _HumbugBox7ff99e199a36\Fidry\CpuCoreCounter\Finder; use function preg_match; /** * Find the number of physical CPU cores for Windows. * * @see https://github.com/paratestphp/paratest/blob/c163539818fd96308ca8dc60f46088461e366ed4/src/Runners/PHPUnit/Options.php#L912-L916 */ final class WmicPhysicalFinder extends ProcOpenBasedFinder { private const CPU_CORE_COUNT_REGEX = '/NumberOfCores[\\s\\n]+(?\\d+)/'; protected function getCommand() : string { return 'wmic cpu get NumberOfCores'; } public function toString() : string { return 'WmicPhysicalFinder'; } protected function countCpuCores(string $process) : ?int { if (0 === preg_match(self::CPU_CORE_COUNT_REGEX, $process, $matches)) { return parent::countCpuCores($process); } $count = $matches['count']; return parent::countCpuCores($count); } } * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ declare (strict_types=1); namespace _HumbugBox7ff99e199a36\Fidry\CpuCoreCounter\Finder; use function array_filter; use function count; use function explode; use const PHP_EOL; /** * Find the number of logical CPU cores for Windows. * * @see https://knowledge.informatica.com/s/article/151521 */ final class WindowsRegistryLogicalFinder extends ProcOpenBasedFinder { protected function getCommand() : string { return '_HumbugBox7ff99e199a36\\reg query HKEY_LOCAL_MACHINE\\HARDWARE\\DESCRIPTION\\System\\CentralProcessor'; } public function toString() : string { return 'WindowsRegistryLogicalFinder'; } protected function countCpuCores(string $process) : ?int { $count = count(array_filter(explode(PHP_EOL, $process), static function (string $line) : bool { return '' !== \trim($line); })); return $count > 0 ? $count : null; } } * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ declare (strict_types=1); namespace _HumbugBox7ff99e199a36\Fidry\CpuCoreCounter\Finder; use function implode; use function in_array; use function sprintf; final class SkipOnOSFamilyFinder implements CpuCoreFinder { /** * @var list */ private $skippedOSFamilies; /** * @var CpuCoreFinder */ private $decoratedFinder; /** * @param string|list $skippedOSFamilyOrFamilies */ public function __construct($skippedOSFamilyOrFamilies, CpuCoreFinder $decoratedFinder) { $this->skippedOSFamilies = (array) $skippedOSFamilyOrFamilies; $this->decoratedFinder = $decoratedFinder; } public static function forWindows(CpuCoreFinder $decoratedFinder) : self { return new self('Windows', $decoratedFinder); } public static function forBSD(CpuCoreFinder $decoratedFinder) : self { return new self('BSD', $decoratedFinder); } public static function forDarwin(CpuCoreFinder $decoratedFinder) : self { return new self('Darwin', $decoratedFinder); } public static function forSolaris(CpuCoreFinder $decoratedFinder) : self { return new self('Solaris', $decoratedFinder); } public static function forLinux(CpuCoreFinder $decoratedFinder) : self { return new self('Linux', $decoratedFinder); } public function diagnose() : string { return $this->skip() ? sprintf('Skipped platform detected ("%s").', \PHP_OS_FAMILY) : $this->decoratedFinder->diagnose(); } public function find() : ?int { return $this->skip() ? null : $this->decoratedFinder->find(); } public function toString() : string { return sprintf('SkipOnOSFamilyFinder(skip=(%s),%s)', implode(',', $this->skippedOSFamilies), $this->decoratedFinder->toString()); } private function skip() : bool { return in_array(\PHP_OS_FAMILY, $this->skippedOSFamilies, \true); } } * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ declare (strict_types=1); namespace _HumbugBox7ff99e199a36\Fidry\CpuCoreCounter\Finder; use function file_get_contents; use function is_file; use function sprintf; use function substr_count; use const PHP_EOL; /** * Find the number of CPU cores looking up at the cpuinfo file which is available * on Linux systems and Windows systems with a Linux sub-system. * * @see https://github.com/paratestphp/paratest/blob/c163539818fd96308ca8dc60f46088461e366ed4/src/Runners/PHPUnit/Options.php#L903-L909 * @see https://unix.stackexchange.com/questions/146051/number-of-processors-in-proc-cpuinfo */ final class CpuInfoFinder implements CpuCoreFinder { private const CPU_INFO_PATH = '/proc/cpuinfo'; public function diagnose() : string { if (!is_file(self::CPU_INFO_PATH)) { return sprintf('The file "%s" could not be found.', self::CPU_INFO_PATH); } $cpuInfo = file_get_contents(self::CPU_INFO_PATH); if (\false === $cpuInfo) { return sprintf('Could not get the content of the file "%s".', self::CPU_INFO_PATH); } return sprintf('Found the file "%s" with the content:%s%s%sWill return "%s".', self::CPU_INFO_PATH, PHP_EOL, $cpuInfo, PHP_EOL, self::countCpuCores($cpuInfo)); } /** * @return positive-int|null */ public function find() : ?int { $cpuInfo = self::getCpuInfo(); return null === $cpuInfo ? null : self::countCpuCores($cpuInfo); } public function toString() : string { return 'CpuInfoFinder'; } private static function getCpuInfo() : ?string { if (!@is_file(self::CPU_INFO_PATH)) { return null; } $cpuInfo = @file_get_contents(self::CPU_INFO_PATH); return \false === $cpuInfo ? null : $cpuInfo; } /** * @internal * * @return positive-int|null */ public static function countCpuCores(string $cpuInfo) : ?int { $processorCount = substr_count($cpuInfo, 'processor'); return $processorCount > 0 ? $processorCount : null; } } * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ declare (strict_types=1); namespace _HumbugBox7ff99e199a36\Fidry\CpuCoreCounter\Finder; use _HumbugBox7ff99e199a36\Fidry\CpuCoreCounter\Executor\ProcessExecutor; use _HumbugBox7ff99e199a36\Fidry\CpuCoreCounter\Executor\ProcOpenExecutor; use function filter_var; use function function_exists; use function is_int; use function sprintf; use function trim; use const FILTER_VALIDATE_INT; use const PHP_EOL; abstract class ProcOpenBasedFinder implements CpuCoreFinder { /** * @var ProcessExecutor */ private $executor; public function __construct(?ProcessExecutor $executor = null) { $this->executor = $executor ?? new ProcOpenExecutor(); } public function diagnose() : string { if (!function_exists('proc_open')) { return 'The function "proc_open" is not available.'; } $command = $this->getCommand(); $output = $this->executor->execute($command); if (null === $output) { return sprintf('Failed to execute the command "%s".', $command); } [$stdout, $stderr] = $output; $failed = '' !== trim($stderr); return $failed ? sprintf('Executed the command "%s" which wrote the following output to the STDERR:%s%s%sWill return "null".', $command, PHP_EOL, $stderr, PHP_EOL) : sprintf('Executed the command "%s" and got the following (STDOUT) output:%s%s%sWill return "%s".', $command, PHP_EOL, $stdout, PHP_EOL, $this->countCpuCores($stdout) ?? 'null'); } /** * @return positive-int|null */ public function find() : ?int { $output = $this->executor->execute($this->getCommand()); if (null === $output) { return null; } [$stdout, $stderr] = $output; $failed = '' !== trim($stderr); return $failed ? null : $this->countCpuCores($stdout); } /** * @internal * * @return positive-int|null */ protected function countCpuCores(string $process) : ?int { $cpuCount = filter_var($process, FILTER_VALIDATE_INT); return is_int($cpuCount) && $cpuCount > 0 ? $cpuCount : null; } protected abstract function getCommand() : string; } * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ declare (strict_types=1); namespace _HumbugBox7ff99e199a36\Fidry\CpuCoreCounter\Finder; use _HumbugBox7ff99e199a36\Fidry\CpuCoreCounter\Executor\ProcessExecutor; use function sprintf; /** * The number of (logical) cores. * * @see https://github.com/infection/infection/blob/fbd8c44/src/Resource/Processor/CpuCoresCountProvider.php#L69-L82 * @see https://unix.stackexchange.com/questions/146051/number-of-processors-in-proc-cpuinfo */ final class NProcFinder extends ProcOpenBasedFinder { /** * @var bool */ private $all; /** * @param bool $all If disabled will give the number of cores available for the current process * only. This is disabled by default as it is known to be "buggy" on virtual * environments as the virtualization tool, e.g. VMWare, might over-commit * resources by default. */ public function __construct(bool $all = \false, ?ProcessExecutor $executor = null) { parent::__construct($executor); $this->all = $all; } public function toString() : string { return sprintf('NProcFinder(all=%s)', $this->all ? 'true' : 'false'); } protected function getCommand() : string { return 'nproc' . ($this->all ? ' --all' : ''); } } * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ declare (strict_types=1); namespace _HumbugBox7ff99e199a36\Fidry\CpuCoreCounter; use _HumbugBox7ff99e199a36\Fidry\CpuCoreCounter\Finder\CpuCoreFinder; use function array_map; use function explode; use function implode; use function max; use function str_repeat; use const PHP_EOL; /** * Utility to debug. * * @private */ final class Diagnoser { /** * Provides an aggregated diagnosis based on each finders diagnosis. * * @param list $finders */ public static function diagnose(array $finders) : string { $diagnoses = array_map(static function (CpuCoreFinder $finder) : string { return self::diagnoseFinder($finder); }, $finders); return implode(PHP_EOL, $diagnoses); } /** * Executes each finders. * * @param list $finders */ public static function execute(array $finders) : string { $diagnoses = array_map(static function (CpuCoreFinder $finder) : string { $coresCount = $finder->find(); return implode('', [$finder->toString(), ': ', null === $coresCount ? 'NULL' : $coresCount]); }, $finders); return implode(PHP_EOL, $diagnoses); } private static function diagnoseFinder(CpuCoreFinder $finder) : string { $diagnosis = $finder->diagnose(); $maxLineLength = max(array_map('strlen', explode(PHP_EOL, $diagnosis))); $separator = str_repeat('-', $maxLineLength); return implode('', [$finder->toString() . ':' . PHP_EOL, $separator . PHP_EOL, $diagnosis . PHP_EOL, $separator . PHP_EOL]); } private function __construct() { } } #!/usr/bin/env php * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ declare (strict_types=1); namespace _HumbugBox7ff99e199a36; use _HumbugBox7ff99e199a36\Fidry\CpuCoreCounter\Diagnoser; use _HumbugBox7ff99e199a36\Fidry\CpuCoreCounter\Finder\FinderRegistry; require_once __DIR__ . '/../vendor/autoload.php'; echo 'Running diagnosis...' . \PHP_EOL . \PHP_EOL; echo Diagnoser::diagnose(FinderRegistry::getAllVariants()) . \PHP_EOL; echo 'Logical CPU cores finders...' . \PHP_EOL . \PHP_EOL; echo Diagnoser::diagnose(FinderRegistry::getDefaultLogicalFinders()) . \PHP_EOL; echo 'Physical CPU cores finders...' . \PHP_EOL . \PHP_EOL; echo Diagnoser::diagnose(FinderRegistry::getDefaultPhysicalFinders()) . \PHP_EOL; #!/usr/bin/env php * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ declare (strict_types=1); namespace _HumbugBox7ff99e199a36; use _HumbugBox7ff99e199a36\Fidry\CpuCoreCounter\CpuCoreCounter; use _HumbugBox7ff99e199a36\Fidry\CpuCoreCounter\Finder\FinderRegistry; require_once __DIR__ . '/../vendor/autoload.php'; $separator = \str_repeat('–', 80); echo 'With all finders...' . \PHP_EOL . \PHP_EOL; echo (new CpuCoreCounter(FinderRegistry::getAllVariants()))->trace() . \PHP_EOL; echo $separator . \PHP_EOL . \PHP_EOL; echo 'Logical CPU cores finders...' . \PHP_EOL . \PHP_EOL; echo (new CpuCoreCounter(FinderRegistry::getDefaultLogicalFinders()))->trace() . \PHP_EOL; echo $separator . \PHP_EOL . \PHP_EOL; echo 'Physical CPU cores finders...' . \PHP_EOL . \PHP_EOL; echo (new CpuCoreCounter(FinderRegistry::getDefaultPhysicalFinders()))->trace() . \PHP_EOL; echo $separator . \PHP_EOL . \PHP_EOL; #!/usr/bin/env php * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ declare (strict_types=1); namespace _HumbugBox7ff99e199a36; use _HumbugBox7ff99e199a36\Fidry\CpuCoreCounter\Diagnoser; use _HumbugBox7ff99e199a36\Fidry\CpuCoreCounter\Finder\FinderRegistry; require_once __DIR__ . '/../vendor/autoload.php'; echo 'Executing finders...' . \PHP_EOL . \PHP_EOL; echo Diagnoser::execute(FinderRegistry::getAllVariants()) . \PHP_EOL; Open Software License v. 3.0 (OSL-3.0) This Open Software License (the "License") applies to any original work of authorship (the "Original Work") whose owner (the "Licensor") has placed the following licensing notice adjacent to the copyright notice for the Original Work: Licensed under the Open Software License version 3.0 1) Grant of Copyright License. Licensor grants You a worldwide, royalty-free, non-exclusive, sublicensable license, for the duration of the copyright, to do the following: a) to reproduce the Original Work in copies, either alone or as part of a collective work; b) to translate, adapt, alter, transform, modify, or arrange the Original Work, thereby creating derivative works ("Derivative Works") based upon the Original Work; c) to distribute or communicate copies of the Original Work and Derivative Works to the public, with the proviso that copies of Original Work or Derivative Works that You distribute or communicate shall be licensed under this Open Software License; d) to perform the Original Work publicly; and e) to display the Original Work publicly. 2) Grant of Patent License. Licensor grants You a worldwide, royalty-free, non-exclusive, sublicensable license, under patent claims owned or controlled by the Licensor that are embodied in the Original Work as furnished by the Licensor, for the duration of the patents, to make, use, sell, offer for sale, have made, and import the Original Work and Derivative Works. 3) Grant of Source Code License. The term "Source Code" means the preferred form of the Original Work for making modifications to it and all available documentation describing how to modify the Original Work. Licensor agrees to provide a machine-readable copy of the Source Code of the Original Work along with each copy of the Original Work that Licensor distributes. Licensor reserves the right to satisfy this obligation by placing a machine-readable copy of the Source Code in an information repository reasonably calculated to permit inexpensive and convenient access by You for as long as Licensor continues to distribute the Original Work. 4) Exclusions From License Grant. Neither the names of Licensor, nor the names of any contributors to the Original Work, nor any of their trademarks or service marks, may be used to endorse or promote products derived from this Original Work without express prior permission of the Licensor. Except as expressly stated herein, nothing in this License grants any license to Licensor’s trademarks, copyrights, patents, trade secrets or any other intellectual property. No patent license is granted to make, use, sell, offer for sale, have made, or import embodiments of any patent claims other than the licensed claims defined in Section 2. No license is granted to the trademarks of Licensor even if such marks are included in the Original Work. Nothing in this License shall be interpreted to prohibit Licensor from licensing under terms different from this License any Original Work that Licensor otherwise would have a right to license. 5) External Deployment. The term "External Deployment" means the use, distribution, or communication of the Original Work or Derivative Works in any way such that the Original Work or Derivative Works may be used by anyone other than You, whether those works are distributed or communicated to those persons or made available as an application intended for use over a network. As an express condition for the grants of license hereunder, You must treat any External Deployment by You of the Original Work or a Derivative Work as a distribution under section 1(c). 6) Attribution Rights. You must retain, in the Source Code of any Derivative Works that You create, all copyright, patent, or trademark notices from the Source Code of the Original Work, as well as any notices of licensing and any descriptive text identified therein as an "Attribution Notice." You must cause the Source Code for any Derivative Works that You create to carry a prominent Attribution Notice reasonably calculated to inform recipients that You have modified the Original Work. 7) Warranty of Provenance and Disclaimer of Warranty. Licensor warrants that the copyright in and to the Original Work and the patent rights granted herein by Licensor are owned by the Licensor or are sublicensed to You under the terms of this License with the permission of the contributor(s) of those copyrights and patent rights. Except as expressly stated in the immediately preceding sentence, the Original Work is provided under this License on an "AS IS" BASIS and WITHOUT WARRANTY, either express or implied, including, without limitation, the warranties of non-infringement, merchantability or fitness for a particular purpose. THE ENTIRE RISK AS TO THE QUALITY OF THE ORIGINAL WORK IS WITH YOU. This DISCLAIMER OF WARRANTY constitutes an essential part of this License. No license to the Original Work is granted by this License except under this disclaimer. 8) Limitation of Liability. Under no circumstances and under no legal theory, whether in tort (including negligence), contract, or otherwise, shall the Licensor be liable to anyone for any indirect, special, incidental, or consequential damages of any character arising as a result of this License or the use of the Original Work including, without limitation, damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses. This limitation of liability shall not apply to the extent applicable law prohibits such limitation. 9) Acceptance and Termination. If, at any time, You expressly assented to this License, that assent indicates your clear and irrevocable acceptance of this License and all of its terms and conditions. If You distribute or communicate copies of the Original Work or a Derivative Work, You must make a reasonable effort under the circumstances to obtain the express assent of recipients to the terms of this License. This License conditions your rights to undertake the activities listed in Section 1, including your right to create Derivative Works based upon the Original Work, and doing so without honoring these terms and conditions is prohibited by copyright law and international treaty. Nothing in this License is intended to affect copyright exceptions and limitations (including “fair use” or “fair dealing”). This License shall terminate immediately and You may no longer exercise any of the rights granted to You by this License upon your failure to honor the conditions in Section 1(c). 10) Termination for Patent Action. This License shall terminate automatically and You may no longer exercise any of the rights granted to You by this License as of the date You commence an action, including a cross-claim or counterclaim, against Licensor or any licensee alleging that the Original Work infringes a patent. This termination provision shall not apply for an action alleging patent infringement by combinations of the Original Work with other software or hardware. 11) Jurisdiction, Venue and Governing Law. Any action or suit relating to this License may be brought only in the courts of a jurisdiction wherein the Licensor resides or in which Licensor conducts its primary business, and under the laws of that jurisdiction excluding its conflict-of-law provisions. The application of the United Nations Convention on Contracts for the International Sale of Goods is expressly excluded. Any use of the Original Work outside the scope of this License or after its termination shall be subject to the requirements and penalties of copyright or patent law in the appropriate jurisdiction. This section shall survive the termination of this License. 12) Attorneys' Fees. In any action to enforce the terms of this License or seeking damages relating thereto, the prevailing party shall be entitled to recover its costs and expenses, including, without limitation, reasonable attorneys' fees and costs incurred in connection with such action, including any appeal of such action. This section shall survive the termination of this License. 13) Miscellaneous. If any provision of this License is held to be unenforceable, such provision shall be reformed only to the extent necessary to make it enforceable. 14) Definition of "You" in This License. "You" throughout this License, whether in upper or lower case, means an individual or a legal entity exercising rights under, and complying with all of the terms of, this License. For legal entities, "You" includes any entity that controls, is controlled by, or is under common control with you. For purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. 15) Right to Use. You may use the Original Work in all ways not otherwise restricted or conditioned by this License or by law, and Licensor promises not to interfere with or be responsible for such uses by You. 16) Modification of This License. This License is Copyright (c) 2005 Lawrence Rosen. Permission is granted to copy, distribute, or communicate this License without modification. Nothing in this License permits You to modify this License as applied to the Original Work or to Derivative Works. However, You may modify the text of this License and copy, distribute or communicate your modified version (the "Modified License") and apply it to other original works of authorship subject to the following conditions: (i) You may not indicate in any way that your Modified License is the "Open Software License" or "OSL" and you may not use those names in the name of your Modified License; (ii) You must replace the notice specified in the first paragraph above with the notice "Licensed under " or with a notice of your own that is not confusingly similar to the notice in this License; and (iii) You may not claim that your original works are open source software unless your Modified License has been approved by Open Source Initiative (OSI) and You comply with its license review and certification process. * @license OSL-3.0 http://opensource.org/licenses/osl-3.0 * @link http://cweiske.de/ */ /** * Automatically map JSON structures into objects. * * @category Netresearch * @package JsonMapper * @author Christian Weiske * @license OSL-3.0 http://opensource.org/licenses/osl-3.0 * @link http://cweiske.de/ */ class JsonMapper { /** * PSR-3 compatible logger object * * @link http://www.php-fig.org/psr/psr-3/ * @var \Psr\Log\LoggerInterface|null * @see setLogger() */ protected $logger; /** * Throw an exception when JSON data contain a property * that is not defined in the PHP class * * @var boolean */ public $bExceptionOnUndefinedProperty = \false; /** * Throw an exception if the JSON data miss a property * that is marked with @required in the PHP class * * @var boolean */ public $bExceptionOnMissingData = \false; /** * If the types of map() parameters shall be checked. * * You have to disable it if you're using the json_decode "assoc" parameter. * * json_decode($str, false) * * @var boolean */ public $bEnforceMapType = \true; /** * Throw an exception when an object is expected but the JSON contains * a non-object type. * * @var boolean */ public $bStrictObjectTypeChecking = \false; /** * Throw an exception, if null value is found * but the type of attribute does not allow nulls. * * @var bool */ public $bStrictNullTypes = \true; /** * Allow mapping of private and protected properties. * * @var boolean */ public $bIgnoreVisibility = \false; /** * Remove attributes that were not passed in JSON, * to avoid confusion between them and NULL values. * * @var boolean */ public $bRemoveUndefinedAttributes = \false; /** * Override class names that JsonMapper uses to create objects. * Useful when your setter methods accept abstract classes or interfaces. * * @var array */ public $classMap = array(); /** * Callback used when an undefined property is found. * * Works only when $bExceptionOnUndefinedProperty is disabled. * * Parameters to this function are: * 1. Object that is being filled * 2. Name of the unknown JSON property * 3. JSON value of the property * * @var callable */ public $undefinedPropertyHandler = null; /** * Runtime cache for inspected classes. This is particularly effective if * mapArray() is called with a large number of objects * * @var array property inspection result cache */ protected $arInspectedClasses = array(); /** * Method to call on each object after deserialization is done. * * Is only called if it exists on the object. * * @var string|null */ public $postMappingMethod = null; /** * Optional arguments that are passed to the post mapping method * * @var array */ public $postMappingMethodArguments = array(); /** * Map data all data in $json into the given $object instance. * * @param object|array $json JSON object structure from json_decode() * @param object|class-string $object Object to map $json data into * * @return mixed Mapped object is returned. * * @template T * @phpstan-param class-string|T $object * @phpstan-return T * * @see mapArray() */ public function map($json, $object) { if ($this->bEnforceMapType && !\is_object($json)) { throw new \InvalidArgumentException('JsonMapper::map() requires first argument to be an object' . ', ' . \gettype($json) . ' given.'); } if (!\is_object($object) && (!\is_string($object) || !\class_exists($object))) { throw new \InvalidArgumentException('JsonMapper::map() requires second argument to ' . 'be an object or existing class name' . ', ' . \gettype($object) . ' given.'); } if (\is_string($object)) { $object = $this->createInstance($object); } $strClassName = \get_class($object); $rc = new \ReflectionClass($object); $strNs = $rc->getNamespaceName(); $providedProperties = array(); foreach ($json as $key => $jvalue) { $key = $this->getSafeName($key); $providedProperties[$key] = \true; // Store the property inspection results so we don't have to do it // again for subsequent objects of the same type if (!isset($this->arInspectedClasses[$strClassName][$key])) { $this->arInspectedClasses[$strClassName][$key] = $this->inspectProperty($rc, $key); } list($hasProperty, $accessor, $type, $isNullable) = $this->arInspectedClasses[$strClassName][$key]; if (!$hasProperty) { if ($this->bExceptionOnUndefinedProperty) { throw new JsonMapper_Exception('JSON property "' . $key . '" does not exist' . ' in object of type ' . $strClassName); } else { if ($this->undefinedPropertyHandler !== null) { $undefinedPropertyKey = \call_user_func($this->undefinedPropertyHandler, $object, $key, $jvalue); if (\is_string($undefinedPropertyKey)) { list($hasProperty, $accessor, $type, $isNullable) = $this->inspectProperty($rc, $undefinedPropertyKey); } } else { $this->log('info', 'Property {property} does not exist in {class}', array('property' => $key, 'class' => $strClassName)); } } if (!$hasProperty) { continue; } } if ($accessor === null) { if ($this->bExceptionOnUndefinedProperty) { throw new JsonMapper_Exception('JSON property "' . $key . '" has no public setter method' . ' in object of type ' . $strClassName); } $this->log('info', 'Property {property} has no public setter method in {class}', array('property' => $key, 'class' => $strClassName)); continue; } if ($isNullable || !$this->bStrictNullTypes) { if ($jvalue === null) { $this->setProperty($object, $accessor, null); continue; } $type = $this->removeNullable($type); } else { if ($jvalue === null) { throw new JsonMapper_Exception('JSON property "' . $key . '" in class "' . $strClassName . '" must not be NULL'); } } $type = $this->getFullNamespace($type, $strNs); $type = $this->getMappedType($type, $jvalue); if ($type === null || $type === 'mixed') { //no given type - simply set the json data $this->setProperty($object, $accessor, $jvalue); continue; } else { if ($this->isObjectOfSameType($type, $jvalue)) { $this->setProperty($object, $accessor, $jvalue); continue; } else { if ($this->isSimpleType($type) && !(\is_array($jvalue) && $this->hasVariadicArrayType($accessor))) { if ($this->isFlatType($type) && !$this->isFlatType(\gettype($jvalue))) { throw new JsonMapper_Exception('JSON property "' . $key . '" in class "' . $strClassName . '" is of type ' . \gettype($jvalue) . ' and' . ' cannot be converted to ' . $type); } \settype($jvalue, $type); $this->setProperty($object, $accessor, $jvalue); continue; } } } //FIXME: check if type exists, give detailed error message if not if ($type === '') { throw new JsonMapper_Exception('Empty type at property "' . $strClassName . '::$' . $key . '"'); } else { if (\strpos($type, '|')) { throw new JsonMapper_Exception('Cannot decide which of the union types shall be used: ' . $type); } } $array = null; $subtype = null; if ($this->isArrayOfType($type)) { //array $array = array(); $subtype = \substr($type, 0, -2); } else { if (\substr($type, -1) == ']') { list($proptype, $subtype) = \explode('[', \substr($type, 0, -1)); if ($proptype == 'array') { $array = array(); } else { $array = $this->createInstance($proptype, \false, $jvalue); } } else { if (\is_array($jvalue) && $this->hasVariadicArrayType($accessor)) { $array = array(); $subtype = $type; } else { if (\is_a($type, 'ArrayAccess', \true)) { $array = $this->createInstance($type, \false, $jvalue); } } } } if ($array !== null) { if (!\is_array($jvalue) && $this->isFlatType(\gettype($jvalue))) { throw new JsonMapper_Exception('JSON property "' . $key . '" must be an array, ' . \gettype($jvalue) . ' given'); } $cleanSubtype = $this->removeNullable($subtype); $subtype = $this->getFullNamespace($cleanSubtype, $strNs); $child = $this->mapArray($jvalue, $array, $subtype, $key); } else { if ($this->isFlatType(\gettype($jvalue))) { //use constructor parameter if we have a class // but only a flat type (i.e. string, int) if ($this->bStrictObjectTypeChecking) { throw new JsonMapper_Exception('JSON property "' . $key . '" must be an object, ' . \gettype($jvalue) . ' given'); } $child = $this->createInstance($type, \true, $jvalue); } else { $child = $this->createInstance($type, \false, $jvalue); $this->map($jvalue, $child); } } $this->setProperty($object, $accessor, $child); } if ($this->bExceptionOnMissingData) { $this->checkMissingData($providedProperties, $rc); } if ($this->bRemoveUndefinedAttributes) { $this->removeUndefinedAttributes($object, $providedProperties); } if ($this->postMappingMethod !== null && $rc->hasMethod($this->postMappingMethod)) { $refDeserializePostMethod = $rc->getMethod($this->postMappingMethod); $refDeserializePostMethod->setAccessible(\true); $refDeserializePostMethod->invoke($object, ...$this->postMappingMethodArguments); } return $object; } /** * Convert a type name to a fully namespaced type name. * * @param string|null $type Type name (simple type or class name) * @param string $strNs Base namespace that gets prepended to the type name * * @return string|null Fully-qualified type name with namespace */ protected function getFullNamespace($type, $strNs) { if ($type === null || $type === '' || $type[0] === '\\' || $strNs === '') { return $type; } list($first) = \explode('[', $type, 2); if ($this->isSimpleType($first)) { return $type; } //create a full qualified namespace return '\\' . $strNs . '\\' . $type; } /** * Check required properties exist in json * * @param array $providedProperties array with json properties * @param ReflectionClass $rc Reflection class to check * * @throws JsonMapper_Exception * * @return void */ protected function checkMissingData($providedProperties, \ReflectionClass $rc) { foreach ($rc->getProperties() as $property) { $rprop = $rc->getProperty($property->name); $docblock = $rprop->getDocComment(); $annotations = static::parseAnnotations($docblock); if (isset($annotations['required']) && !isset($providedProperties[$property->name])) { throw new JsonMapper_Exception('Required property "' . $property->name . '" of class ' . $rc->getName() . ' is missing in JSON data'); } } } /** * Remove attributes from object that were not passed in JSON data. * * This is to avoid confusion between those that were actually passed * as NULL, and those that weren't provided at all. * * @param object $object Object to remove properties from * @param array $providedProperties Array with JSON properties * * @return void */ protected function removeUndefinedAttributes($object, $providedProperties) { foreach (\get_object_vars($object) as $propertyName => $dummy) { if (!isset($providedProperties[$propertyName])) { unset($object->{$propertyName}); } } } /** * Map an array * * @param array $json JSON array structure from json_decode() * @param mixed $array Array or ArrayObject that gets filled with * data from $json * @param string $class Class name for children objects. * All children will get mapped onto this type. * Supports class names and simple types * like "string" and nullability "string|null". * Pass "null" to not convert any values * @param string $parent_key Defines the key this array belongs to * in order to aid debugging. * * @return mixed Mapped $array is returned */ public function mapArray($json, $array, $class = null, $parent_key = '') { $originalClass = $class; foreach ($json as $key => $jvalue) { $class = $this->getMappedType($originalClass, $jvalue); if ($class === null) { $array[$key] = $jvalue; } else { if ($this->isArrayOfType($class)) { $array[$key] = $this->mapArray($jvalue, array(), \substr($class, 0, -2)); } else { if ($this->isFlatType(\gettype($jvalue))) { //use constructor parameter if we have a class // but only a flat type (i.e. string, int) if ($jvalue === null) { $array[$key] = null; } else { if ($this->isSimpleType($class)) { \settype($jvalue, $class); $array[$key] = $jvalue; } else { $array[$key] = $this->createInstance($class, \true, $jvalue); } } } else { if ($this->isFlatType($class)) { throw new JsonMapper_Exception('JSON property "' . ($parent_key ? $parent_key : '?') . '"' . ' is an array of type "' . $class . '"' . ' but contained a value of type' . ' "' . \gettype($jvalue) . '"'); } else { if (\is_a($class, 'ArrayObject', \true)) { $array[$key] = $this->mapArray($jvalue, $this->createInstance($class)); } else { $array[$key] = $this->map($jvalue, $this->createInstance($class, \false, $jvalue)); } } } } } } return $array; } /** * Try to find out if a property exists in a given class. * Checks property first, falls back to setter method. * * @param ReflectionClass $rc Reflection class to check * @param string $name Property name * * @return array First value: if the property exists * Second value: the accessor to use ( * ReflectionMethod or ReflectionProperty, or null) * Third value: type of the property * Fourth value: if the property is nullable */ protected function inspectProperty(\ReflectionClass $rc, $name) { //try setter method first $setter = 'set' . $this->getCamelCaseName($name); if ($rc->hasMethod($setter)) { $rmeth = $rc->getMethod($setter); if ($rmeth->isPublic() || $this->bIgnoreVisibility) { $isNullable = \false; $rparams = $rmeth->getParameters(); if (\count($rparams) > 0) { $isNullable = $rparams[0]->allowsNull(); $ptype = $rparams[0]->getType(); if ($ptype !== null) { $typeName = $this->stringifyReflectionType($ptype); //allow overriding an "array" type hint // with a more specific class in the docblock if ($typeName !== 'array') { return array(\true, $rmeth, $typeName, $isNullable); } } } $docblock = $rmeth->getDocComment(); $annotations = static::parseAnnotations($docblock); if (!isset($annotations['param'][0])) { return array(\true, $rmeth, null, $isNullable); } list($type) = \explode(' ', \trim($annotations['param'][0])); return array(\true, $rmeth, $type, $this->isNullable($type)); } } //now try to set the property directly //we have to look it up in the class hierarchy $class = $rc; $rprop = null; do { if ($class->hasProperty($name)) { $rprop = $class->getProperty($name); } } while ($rprop === null && ($class = $class->getParentClass())); if ($rprop === null) { //case-insensitive property matching foreach ($rc->getProperties() as $p) { if (\strcasecmp($p->name, $name) === 0) { $rprop = $p; $class = $rc; break; } } } if ($rprop !== null) { if ($rprop->isPublic() || $this->bIgnoreVisibility) { $docblock = $rprop->getDocComment(); if (\PHP_VERSION_ID >= 80000 && $docblock === \false && $class->hasMethod('__construct')) { $docblock = $class->getMethod('__construct')->getDocComment(); } $annotations = static::parseAnnotations($docblock); if (!isset($annotations['var'][0])) { if (\PHP_VERSION_ID >= 80000 && $rprop->hasType() && isset($annotations['param'])) { foreach ($annotations['param'] as $param) { if (\strpos($param, '$' . $rprop->getName()) !== \false) { list($type) = \explode(' ', $param); return array(\true, $rprop, $type, $this->isNullable($type)); } } } // If there is no annotations (higher priority) inspect // if there's a scalar type being defined if (\PHP_VERSION_ID >= 70400 && $rprop->hasType()) { $rPropType = $rprop->getType(); $propTypeName = $this->stringifyReflectionType($rPropType); if ($this->isSimpleType($propTypeName)) { return array(\true, $rprop, $propTypeName, $rPropType->allowsNull()); } return array(\true, $rprop, '\\' . \ltrim($propTypeName, '\\'), $rPropType->allowsNull()); } return array(\true, $rprop, null, \false); } //support "@var type description" list($type) = \explode(' ', $annotations['var'][0]); return array(\true, $rprop, $type, $this->isNullable($type)); } else { //no setter, private property return array(\true, null, null, \false); } } //no setter, no property return array(\false, null, null, \false); } /** * Removes - and _ and makes the next letter uppercase * * @param string $name Property name * * @return string CamelCasedVariableName */ protected function getCamelCaseName($name) { return \str_replace(' ', '', \ucwords(\str_replace(array('_', '-'), ' ', $name))); } /** * Since hyphens cannot be used in variables we have to uppercase them. * * Technically you may use them, but they are awkward to access. * * @param string $name Property name * * @return string Name without hyphen */ protected function getSafeName($name) { if (\strpos($name, '-') !== \false) { $name = $this->getCamelCaseName($name); } return $name; } /** * Set a property on a given object to a given value. * * Checks if the setter or the property are public are made before * calling this method. * * @param object $object Object to set property on * @param object $accessor ReflectionMethod or ReflectionProperty * @param mixed $value Value of property * * @return void */ protected function setProperty($object, $accessor, $value) { if (!$accessor->isPublic() && $this->bIgnoreVisibility) { $accessor->setAccessible(\true); } if ($accessor instanceof \ReflectionProperty) { $accessor->setValue($object, $value); } else { if (\is_array($value) && $this->hasVariadicArrayType($accessor)) { $accessor->invoke($object, ...$value); } else { //setter method $accessor->invoke($object, $value); } } } /** * Create a new object of the given type. * * This method exists to be overwritten in child classes, * so you can do dependency injection or so. * * @param string $class Class name to instantiate * @param boolean $useParameter Pass $parameter to the constructor or not * @param mixed $jvalue Constructor parameter (the json value) * * @return object Freshly created object */ protected function createInstance($class, $useParameter = \false, $jvalue = null) { if ($useParameter) { if (\PHP_VERSION_ID >= 80100 && \is_subclass_of($class, \BackedEnum::class)) { return $class::from($jvalue); } return new $class($jvalue); } else { $reflectClass = new \ReflectionClass($class); $constructor = $reflectClass->getConstructor(); if (null === $constructor || $constructor->getNumberOfRequiredParameters() > 0) { return $reflectClass->newInstanceWithoutConstructor(); } return $reflectClass->newInstance(); } } /** * Get the mapped class/type name for this class. * Returns the incoming classname if not mapped. * * Lets you override class names via the $classMap property. * * @param string|null $type Type name to map * @param mixed $jvalue Constructor parameter (the json value) * * @return string|null The mapped type/class name */ protected function getMappedType($type, $jvalue = null) { if (isset($this->classMap[$type])) { $target = $this->classMap[$type]; } else { if (\is_string($type) && $type !== '' && $type[0] == '\\' && isset($this->classMap[\substr($type, 1)])) { $target = $this->classMap[\substr($type, 1)]; } else { $target = null; } } if ($target) { if (\is_callable($target)) { $type = $target($type, $jvalue); } else { $type = $target; } } return $type; } /** * Checks if the given type is a "simple type" * * @param string $type type name from gettype() * * @return boolean True if it is a simple PHP type * * @see isFlatType() */ protected function isSimpleType($type) { return $type == 'string' || $type == 'boolean' || $type == 'bool' || $type == 'integer' || $type == 'int' || $type == 'double' || $type == 'float' || $type == 'array' || $type == 'object' || $type === 'mixed'; } /** * Checks if the object is of this type or has this type as one of its parents * * @param string $type class name of type being required * @param mixed $value Some PHP value to be tested * * @return boolean True if $object has type of $type */ protected function isObjectOfSameType($type, $value) { if (\false === \is_object($value)) { return \false; } return \is_a($value, $type); } /** * Checks if the given type is a type that is not nested * (simple type except array, object and mixed) * * @param string $type type name from gettype() * * @return boolean True if it is a non-nested PHP type * * @see isSimpleType() */ protected function isFlatType($type) { return $type == 'NULL' || $type == 'string' || $type == 'boolean' || $type == 'bool' || $type == 'integer' || $type == 'int' || $type == 'double' || $type == 'float'; } /** * Returns true if type is an array of elements * (bracket notation) * * @param string $strType type to be matched * * @return bool */ protected function isArrayOfType($strType) { return \substr($strType, -2) === '[]'; } /** * Returns true if accessor is a method and has only one parameter * which is variadic ("...$args"). * * @param ReflectionMethod|ReflectionProperty|null $accessor accessor * to set value * * @return bool */ protected function hasVariadicArrayType($accessor) { if (!$accessor instanceof \ReflectionMethod) { return \false; } $parameters = $accessor->getParameters(); if (\count($parameters) !== 1) { return \false; } $parameter = $parameters[0]; return $parameter->isVariadic(); } /** * Checks if the given type is nullable * * @param string $type type name from the phpdoc param * * @return boolean True if it is nullable */ protected function isNullable($type) { return \stripos('|' . $type . '|', '|null|') !== \false || \strpos('|' . $type, '|?') !== \false; } /** * Remove the 'null' section of a type * * @param string|null $type type name from the phpdoc param * * @return string|null The new type value */ protected function removeNullable($type) { if ($type === null) { return null; } return \substr(\str_ireplace(['|null|', '|?'], '|', '|' . $type . '|'), 1, -1); } /** * Get a string representation of the reflection type. * Required because named, union and intersection types need to be handled. * * @param ReflectionType $type Native PHP type * * @return string "foo|bar" */ protected function stringifyReflectionType(\ReflectionType $type) { if ($type instanceof \ReflectionNamedType) { return ($type->isBuiltin() ? '' : '\\') . $type->getName(); } return \implode('|', \array_map(function (\ReflectionNamedType $type) { return ($type->isBuiltin() ? '' : '\\') . $type->getName(); }, $type->getTypes())); } /** * Copied from PHPUnit 3.7.29, Util/Test.php * * @param string $docblock Full method docblock * * @return array Array of arrays. * Key is the "@"-name like "param", * each value is an array of the rest of the @-lines */ protected static function parseAnnotations($docblock) { $annotations = array(); // Strip away the docblock header and footer // to ease parsing of one line annotations $docblock = \substr($docblock, 3, -2); $re = '/@(?P[A-Za-z_-]+)(?:[ \\t]+(?P.*?))?[ \\t]*\\r?$/m'; if (\preg_match_all($re, $docblock, $matches)) { $numMatches = \count($matches[0]); for ($i = 0; $i < $numMatches; ++$i) { $annotations[$matches['name'][$i]][] = $matches['value'][$i]; } } return $annotations; } /** * Log a message to the $logger object * * @param string $level Logging level * @param string $message Text to log * @param array $context Additional information * * @return void */ protected function log($level, $message, array $context = array()) { if ($this->logger) { $this->logger->log($level, $message, $context); } } /** * Sets a logger instance on the object * * @param \Psr\Log\LoggerInterface $logger PSR-3 compatible logger object * * @return void */ public function setLogger($logger) { $this->logger = $logger; } } * @license OSL-3.0 http://opensource.org/licenses/osl-3.0 * @link http://cweiske.de/ */ /** * Simple exception * * @category Netresearch * @package JsonMapper * @author Christian Weiske * @license OSL-3.0 http://opensource.org/licenses/osl-3.0 * @link http://cweiske.de/ */ class JsonMapper_Exception extends \Exception { } Copyright (c) 2014 Daniel Nögel Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. getHomeDir(); $path = \DIRECTORY_SEPARATOR === $homeDir ? $homeDir . '.config' : $homeDir . \DIRECTORY_SEPARATOR . '.config'; return $path; } /** * @return string */ public function getHomeDataDir() { $path = \getenv('XDG_DATA_HOME') ?: $this->getHomeDir() . \DIRECTORY_SEPARATOR . '.local' . \DIRECTORY_SEPARATOR . 'share'; return $path; } /** * @return array */ public function getConfigDirs() { $configDirs = \getenv('XDG_CONFIG_DIRS') ? \explode(':', \getenv('XDG_CONFIG_DIRS')) : array('/etc/xdg'); $paths = \array_merge(array($this->getHomeConfigDir()), $configDirs); return $paths; } /** * @return array */ public function getDataDirs() { $dataDirs = \getenv('XDG_DATA_DIRS') ? \explode(':', \getenv('XDG_DATA_DIRS')) : array('/usr/local/share', '/usr/share'); $paths = \array_merge(array($this->getHomeDataDir()), $dataDirs); return $paths; } /** * @return string */ public function getHomeCacheDir() { $path = \getenv('XDG_CACHE_HOME') ?: $this->getHomeDir() . \DIRECTORY_SEPARATOR . '.cache'; return $path; } public function getRuntimeDir($strict = \true) { if ($runtimeDir = \getenv('XDG_RUNTIME_DIR')) { return $runtimeDir; } if ($strict) { throw new \RuntimeException('XDG_RUNTIME_DIR was not set'); } $fallback = \sys_get_temp_dir() . \DIRECTORY_SEPARATOR . self::RUNTIME_DIR_FALLBACK . \getenv('USER'); $create = \false; if (!\is_dir($fallback)) { \mkdir($fallback, 0700, \true); } $st = \lstat($fallback); # The fallback must be a directory if (!$st['mode'] & self::S_IFDIR) { \rmdir($fallback); $create = \true; } elseif ($st['uid'] != $this->getUid() || $st['mode'] & (self::S_IRWXG | self::S_IRWXO)) { \rmdir($fallback); $create = \true; } if ($create) { \mkdir($fallback, 0700, \true); } return $fallback; } private function getUid() { if (\function_exists('posix_getuid')) { return \posix_getuid(); } return \getmyuid(); } } Copyright (c) 2012 PHP Framework Interoperability Group Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. logger) { }` * blocks. */ class NullLogger extends AbstractLogger { /** * Logs with an arbitrary level. * * @param mixed $level * @param string $message * @param array $context * * @return void * * @throws \Psr\Log\InvalidArgumentException */ public function log($level, $message, array $context = array()) { // noop } } log(LogLevel::EMERGENCY, $message, $context); } /** * Action must be taken immediately. * * Example: Entire website down, database unavailable, etc. This should * trigger the SMS alerts and wake you up. * * @param string $message * @param mixed[] $context * * @return void */ public function alert($message, array $context = array()) { $this->log(LogLevel::ALERT, $message, $context); } /** * Critical conditions. * * Example: Application component unavailable, unexpected exception. * * @param string $message * @param mixed[] $context * * @return void */ public function critical($message, array $context = array()) { $this->log(LogLevel::CRITICAL, $message, $context); } /** * Runtime errors that do not require immediate action but should typically * be logged and monitored. * * @param string $message * @param mixed[] $context * * @return void */ public function error($message, array $context = array()) { $this->log(LogLevel::ERROR, $message, $context); } /** * Exceptional occurrences that are not errors. * * Example: Use of deprecated APIs, poor use of an API, undesirable things * that are not necessarily wrong. * * @param string $message * @param mixed[] $context * * @return void */ public function warning($message, array $context = array()) { $this->log(LogLevel::WARNING, $message, $context); } /** * Normal but significant events. * * @param string $message * @param mixed[] $context * * @return void */ public function notice($message, array $context = array()) { $this->log(LogLevel::NOTICE, $message, $context); } /** * Interesting events. * * Example: User logs in, SQL logs. * * @param string $message * @param mixed[] $context * * @return void */ public function info($message, array $context = array()) { $this->log(LogLevel::INFO, $message, $context); } /** * Detailed debug information. * * @param string $message * @param mixed[] $context * * @return void */ public function debug($message, array $context = array()) { $this->log(LogLevel::DEBUG, $message, $context); } } logger = $logger; } } log(LogLevel::EMERGENCY, $message, $context); } /** * Action must be taken immediately. * * Example: Entire website down, database unavailable, etc. This should * trigger the SMS alerts and wake you up. * * @param string $message * @param array $context * * @return void */ public function alert($message, array $context = array()) { $this->log(LogLevel::ALERT, $message, $context); } /** * Critical conditions. * * Example: Application component unavailable, unexpected exception. * * @param string $message * @param array $context * * @return void */ public function critical($message, array $context = array()) { $this->log(LogLevel::CRITICAL, $message, $context); } /** * Runtime errors that do not require immediate action but should typically * be logged and monitored. * * @param string $message * @param array $context * * @return void */ public function error($message, array $context = array()) { $this->log(LogLevel::ERROR, $message, $context); } /** * Exceptional occurrences that are not errors. * * Example: Use of deprecated APIs, poor use of an API, undesirable things * that are not necessarily wrong. * * @param string $message * @param array $context * * @return void */ public function warning($message, array $context = array()) { $this->log(LogLevel::WARNING, $message, $context); } /** * Normal but significant events. * * @param string $message * @param array $context * * @return void */ public function notice($message, array $context = array()) { $this->log(LogLevel::NOTICE, $message, $context); } /** * Interesting events. * * Example: User logs in, SQL logs. * * @param string $message * @param array $context * * @return void */ public function info($message, array $context = array()) { $this->log(LogLevel::INFO, $message, $context); } /** * Detailed debug information. * * @param string $message * @param array $context * * @return void */ public function debug($message, array $context = array()) { $this->log(LogLevel::DEBUG, $message, $context); } /** * Logs with an arbitrary level. * * @param mixed $level * @param string $message * @param array $context * * @return void * * @throws \Psr\Log\InvalidArgumentException */ public abstract function log($level, $message, array $context = array()); } uri = $uri; /** @psalm-suppress PossiblyNullPropertyAssignmentValue */ $this->range = $range; } } name = $name; } } additionalPropertiesSupport = $additionalPropertiesSupport; } } dynamicRegistration = $dynamicRegistration; $this->willSave = $willSave; $this->willSaveWaitUntil = $willSaveWaitUntil; $this->didSave = $didSave; } } reference = $reference; /** @psalm-suppress PossiblyNullPropertyAssignmentValue */ $this->symbol = $symbol; } } uri = $uri; /** @psalm-suppress PossiblyNullPropertyAssignmentValue */ $this->languageId = $languageId; /** @psalm-suppress PossiblyNullPropertyAssignmentValue */ $this->version = $version; /** @psalm-suppress PossiblyNullPropertyAssignmentValue */ $this->text = $text; } } valueSet = $valueSet; } } parser = $parser; $this->version = $version; $this->allowedTags = $allowedTags; } } dynamicRegistration = $dynamicRegistration; } } properties = $properties; } } ` and a completion item with an `insertText` of * `console` is provided it will only insert `sole`. Therefore it is * recommended to use `textEdit` instead since it avoids additional client * side interpretation. * * @var string|null */ public $insertText; /** * The format of the insert text. The format applies to both the * `insertText` property and the `newText` property of a provided * `textEdit`. If omitted defaults to `InsertTextFormat.PlainText`. * * Please note that the insertTextFormat doesn't apply to * `additionalTextEdits`. * * @var int|null * @see InsertTextFormat */ public $insertTextFormat; /** * How whitespace and indentation is handled during completion * item insertion. If not provided the client's default value depends on * the `textDocument.completion.insertTextMode` client capability. * * @since 3.16.0 * @since 3.17.0 - support for `textDocument.completion.insertTextMode` * * @var int|null * @see InsertTextMode */ public $insertTextMode; /** * An edit which is applied to a document when selecting this completion. * When an edit is provided the value of `insertText` is ignored. * * *Note:* The range of the edit must be a single line range and it must * contain the position at which completion has been requested. * * Most editors support two different operations when accepting a completion * item. One is to insert a completion text and the other is to replace an * existing text with a completion text. Since this can usually not be * predetermined by a server it can report both ranges. Clients need to * signal support for `InsertReplaceEdit`s via the * `textDocument.completion.completionItem.insertReplaceSupport` client * capability property. * * *Note 1:* The text edit's range as well as both ranges from an insert * replace edit must be a [single line] and they must contain the position * at which completion has been requested. * *Note 2:* If an `InsertReplaceEdit` is returned the edit's insert range * must be a prefix of the edit's replace range, that means it must be * contained and starting at the same position. * * @since 3.16.0 additional type `InsertReplaceEdit` * * @var TextEdit|null */ public $textEdit; /** * An optional array of additional text edits that are applied when * selecting this completion. Edits must not overlap (including the same * insert position) with the main edit nor with themselves. * * Additional text edits should be used to change text unrelated to the * current cursor position (for example adding an import statement at the * top of the file if the completion item will insert an unqualified type). * * @var TextEdit[]|null */ public $additionalTextEdits; /** * An optional set of characters that when pressed while this completion is * active will accept it first and then type that character. *Note* that all * commit characters should have `length=1` and that superfluous characters * will be ignored. * * @var string[]|null */ public $commitCharacters; /** * An optional command that is executed *after* inserting this completion. *Note* that * additional modifications to the current document should be described with the * additionalTextEdits-property. * * @var Command|null */ public $command; /** * An data entry field that is preserved on a completion item between * a completion and a completion resolve request. * * @var mixed */ public $data; /** * @param string $label * @param int|null $kind * @param string|null $detail * @param string|null $documentation * @param string|null $sortText * @param string|null $filterText * @param string|null $insertText * @param TextEdit|null $textEdit * @param TextEdit[]|null $additionalTextEdits * @param Command|null $command * @param mixed|null $data * @param int|null $insertTextFormat */ public function __construct(string $label = null, int $kind = null, string $detail = null, string $documentation = null, string $sortText = null, string $filterText = null, string $insertText = null, TextEdit $textEdit = null, array $additionalTextEdits = null, Command $command = null, $data = null, int $insertTextFormat = null) { /** @psalm-suppress PossiblyNullPropertyAssignmentValue */ $this->label = $label; $this->kind = $kind; $this->detail = $detail; $this->documentation = $documentation; $this->sortText = $sortText; $this->filterText = $filterText; $this->insertText = $insertText; $this->textEdit = $textEdit; $this->additionalTextEdits = $additionalTextEdits; $this->command = $command; $this->data = $data; $this->insertTextFormat = $insertTextFormat; } } dynamicRegistration = $dynamicRegistration; } } line = $line; /** @psalm-suppress PossiblyNullPropertyAssignmentValue */ $this->character = $character; } /** * Compares this position to another position * Returns * - 0 if the positions match * - a negative number if $this is before $position * - a positive number otherwise * * @param Position $position * @return int */ public function compare(Position $position) : int { if ($this->line === $position->line && $this->character === $position->character) { return 0; } if ($this->line !== $position->line) { return $this->line - $position->line; } return $this->character - $position->character; } /** * Returns the offset of the position in a string * * @param string $content * @return int */ public function toOffset(string $content) : int { $lines = \explode("\n", $content); $slice = \array_slice($lines, 0, $this->line); return \array_sum(\array_map('strlen', $slice)) + \count($slice) + $this->character; } } snippetSupport = $snippetSupport; $this->commitCharactersSupport = $commitCharactersSupport; $this->documentationFormat = $documentationFormat; $this->deprecatedSupport = $deprecatedSupport; $this->preselectSupport = $preselectSupport; $this->tagSupport = $tagSupport; $this->insertReplaceSupport = $insertReplaceSupport; $this->resolveSupport = $resolveSupport; $this->insertTextModeSupport = $insertTextModeSupport; $this->labelDetailsSupport = $labelDetailsSupport; } } dynamicRegistration = $dynamicRegistration; $this->symbolKind = $symbolKind; $this->hierarchicalDocumentSymbolSupport = $hierarchicalDocumentSymbolSupport; $this->tagSupport = $tagSupport; $this->labelSupport = $labelSupport; } } message = $message; /** @psalm-suppress PossiblyNullPropertyAssignmentValue */ $this->range = $range; $this->code = $code; $this->severity = $severity; $this->source = $source; $this->codeDescription = $codeDescription; $this->tags = $tags; $this->relatedInformation = $relatedInformation; $this->data = $data; } } dynamicRegistration = $dynamicRegistration; $this->linkSupport = $linkSupport; } } triggerKind = $triggerKind; $this->triggerCharacter = $triggerCharacter; } } */ public $changes; /** * Depending on the client capability * `workspace.workspaceEdit.resourceOperations` document changes are either * an array of `TextDocumentEdit`s to express changes to n different text * documents where each text document edit addresses a specific version of * a text document. Or it can contain above `TextDocumentEdit`s mixed with * create, rename and delete file / folder operations. * * Whether a client supports versioned document edits is expressed via * `workspace.workspaceEdit.documentChanges` client capability. * * If a client neither supports `documentChanges` nor * `workspace.workspaceEdit.resourceOperations` then only plain `TextEdit`s * using the `changes` property are supported. * * @var mixed */ public $documentChanges; /** * A map of change annotations that can be referenced in * `AnnotatedTextEdit`s or create, rename and delete file / folder * operations. * * Whether clients honor this property depends on the client capability * `workspace.changeAnnotationSupport`. * * @since 3.16.0 * * @var array|null */ public $changeAnnotations; /** * @param array $changes * @param mixed $documentChanges * @param array|null $changeAnnotations */ public function __construct(array $changes = [], $documentChanges = null, array $changeAnnotations = null) { $this->changes = $changes; $this->documentChanges = $documentChanges; $this->changeAnnotations = $changeAnnotations; } /** * This is needed because VSCode Does not like nulls * meaning if a null is sent then this will not compute * * @return mixed */ #[\ReturnTypeWillChange] public function jsonSerialize() { return \array_filter(\get_object_vars($this)); } } range = $range; $this->kind = $kind; } } contents = $contents; $this->range = $range; } } label = $label; $this->documentation = $documentation; } } name = $name; $this->version = $version; } } type = $type; $this->message = $message; } } title = $title; $this->kind = $kind; $this->diagnostics = $diagnostics; $this->isPreferred = $isPreferred; $this->disabled = $disabled; $this->edit = $edit; $this->command = $command; $this->data = $data; } /** * This is needed because VSCode Does not like nulls * meaning if a null is sent then this will not compute * * @return mixed */ #[\ReturnTypeWillChange] public function jsonSerialize() { return \array_filter(\get_object_vars($this)); } } symbol = $symbol; $this->location = $location; } } capabilities = $capabilities; $this->serverInfo = $serverInfo; } } refreshSupport = $refreshSupport; } } refreshSupport = $refreshSupport; } } dynamicRegistration = $dynamicRegistration; } } labelOffsetSupport = $labelOffsetSupport; } } attributes = $attributes ?? new \stdClass(); $this->hints = $hints; } } dynamicRegistration = $dynamicRegistration; $this->contentFormat = $contentFormat; } } uri = $uri; $this->type = $type; } } href = $href; } } valueSet = $valueSet; } } valueSet = $valueSet; } } uri = $uri; } } commands = $commands; } } support = $support; } } includeDeclaration = $includeDeclaration; } } fqsen = $fqsen; $this->package = $package; } } start = $start; /** @psalm-suppress PossiblyNullPropertyAssignmentValue */ $this->end = $end; } /** * Checks if a position is within the range * * @param Position $position * @return bool */ public function includes(Position $position) : bool { return $this->start->compare($position) <= 0 && $this->end->compare($position) >= 0; } } workspace = $workspace; $this->textDocument = $textDocument; $this->window = $window; $this->general = $general; $this->experimental = $experimental; $this->xfilesProvider = $xfilesProvider; $this->xcontentProvider = $xcontentProvider; $this->xcacheProvider = $xcacheProvider; } } diagnostics = $diagnostics; } } dynamicRegistration = $dynamicRegistration; $this->codeActionLiteralSupport = $codeActionLiteralSupport; $this->isPreferredSupport = $isPreferredSupport; $this->disabledSupport = $disabledSupport; $this->dataSupport = $dataSupport; $this->resolveSupport = $resolveSupport; $this->honorsChangeAnnotations = $honorsChangeAnnotations; } } title = $title; $this->command = $command; $this->arguments = $arguments; } } regularExpressions = $regularExpressions; $this->markdown = $markdown; } } properties = $properties; } } dynamicRegistration = $dynamicRegistration; } } signatures = $signatures; $this->activeSignature = $activeSignature; $this->activeParameter = $activeParameter; } } dynamicRegistration = $dynamicRegistration; $this->didCreate = $didCreate; $this->willCreate = $willCreate; $this->didRename = $didRename; $this->willRename = $willRename; $this->didDelete = $didDelete; $this->willDelete = $willDelete; } } range = $range; $this->command = $command; $this->data = $data; } } detail = $detail; $this->description = $description; } } name = $name; $this->version = $version; } } kind = $kind; /** @psalm-suppress PossiblyNullPropertyAssignmentValue */ $this->value = $value; } } dynamicRegistration = $dynamicRegistration; } } codeActionKind = $codeActionKind; } } documentChanges = $documentChanges; $this->resourceOperations = $resourceOperations; $this->failureHandling = $failureHandling; $this->normalizesLineEndings = $normalizesLineEndings; $this->changeAnnotationSupport = $changeAnnotationSupport; } } dynamicRegistration = $dynamicRegistration; $this->prepareSupport = $prepareSupport; $this->prepareSupportDefaultBehavior = $prepareSupportDefaultBehavior; $this->honorsChangeAnnotations = $honorsChangeAnnotations; } } messageActionItem = $messageActionItem; } } dynamicRegistration = $dynamicRegistration; $this->signatureInformation = $signatureInformation; $this->contextSupport = $contextSupport; } } range = $range; $this->full = $full; } } resolveProvider = $resolveProvider; } } valueSet = $valueSet; } } range = $range; $this->rangeLength = $rangeLength; /** @psalm-suppress PossiblyNullPropertyAssignmentValue */ $this->text = $text; } } dynamicRegistration = $dynamicRegistration; } } dynamicRegistration = $dynamicRegistration; $this->symbolKind = $symbolKind; $this->tagSupport = $tagSupport; $this->resolveSupport = $resolveSupport; } } documentationFormat = $documentationFormat; $this->parameterInformation = $parameterInformation; $this->activeParameterSupport = $activeParameterSupport; } } name = $name; /** @psalm-suppress PossiblyNullPropertyAssignmentValue */ $this->kind = $kind; /** @psalm-suppress PossiblyNullPropertyAssignmentValue */ $this->location = $location; $this->containerName = $containerName; } } firstTriggerCharacter = $firstTriggerCharacter; $this->moreTriggerCharacter = $moreTriggerCharacter; } } workDoneProgress = $workDoneProgress; $this->showMessage = $showMessage; $this->showDocument = $showDocument; } } itemDefaults = $itemDefaults; } } valueSet = $valueSet; } } dynamicRegistration = $dynamicRegistration; } } dynamicRegistration = $dynamicRegistration; $this->linkSupport = $linkSupport; } } requests = $requests; /** @psalm-suppress PossiblyNullPropertyAssignmentValue */ $this->tokenTypes = $tokenTypes; /** @psalm-suppress PossiblyNullPropertyAssignmentValue */ $this->tokenModifiers = $tokenModifiers; /** @psalm-suppress PossiblyNullPropertyAssignmentValue */ $this->formats = $formats; $this->dynamicRegistration = $dynamicRegistration; $this->overlappingTokenSupport = $overlappingTokenSupport; $this->multilineTokenSupport = $multilineTokenSupport; $this->serverCancelSupport = $serverCancelSupport; $this->augmentsSyntaxTokens = $augmentsSyntaxTokens; } } dynamicRegistration = $dynamicRegistration; } } engine = $engine; $this->version = $version; } } dynamicRegistration = $dynamicRegistration; $this->rangeLimit = $rangeLimit; $this->lineFoldingOnly = $lineFoldingOnly; } } triggerCharacters = $triggerCharacters; } } dynamicRegistration = $dynamicRegistration; } } range = $range; $this->rangeLength = $rangeLength; /** @psalm-suppress PossiblyNullPropertyAssignmentValue */ $this->text = $text; } } dynamicRegistration = $dynamicRegistration; $this->tooltipSupport = $tooltipSupport; } } dynamicRegistration = $dynamicRegistration; $this->linkSupport = $linkSupport; } } dynamicRegistration = $dynamicRegistration; } } dynamicRegistration = $dynamicRegistration; } } synchronization = $synchronization; $this->completion = $completion; $this->hover = $hover; $this->signatureHelp = $signatureHelp; $this->declaration = $declaration; $this->definition = $definition; $this->typeDefinition = $typeDefinition; $this->implementation = $implementation; $this->references = $references; $this->documentHighlight = $documentHighlight; $this->documentSymbol = $documentSymbol; $this->codeAction = $codeAction; $this->codeLens = $codeLens; $this->documentLink = $documentLink; $this->colorProvider = $colorProvider; $this->formatting = $formatting; $this->rangeFormatting = $rangeFormatting; $this->onTypeFormatting = $onTypeFormatting; $this->rename = $rename; $this->publishDiagnostics = $publishDiagnostics; $this->foldingRange = $foldingRange; $this->selectionRange = $selectionRange; $this->linkedEditingRange = $linkedEditingRange; $this->callHierarchy = $callHierarchy; $this->semanticTokens = $semanticTokens; $this->moniker = $moniker; } } tabSize = $tabSize; /** @psalm-suppress PossiblyNullPropertyAssignmentValue */ $this->insertSpaces = $insertSpaces; } } language = $language; /** @psalm-suppress PossiblyNullPropertyAssignmentValue */ $this->value = $value; } } uri = $uri; /** @psalm-suppress PossiblyNullPropertyAssignmentValue */ $this->name = $name; } } relatedInformation = $relatedInformation; $this->tagSupport = $tagSupport; $this->versionSupport = $versionSupport; $this->codeDescriptionSupport = $codeDescriptionSupport; $this->dataSupport = $dataSupport; } } label = $label; $this->needsConfirmation = $needsConfirmation; $this->description = $description; } } <3tabs>foo. Accepting a * multi line completion item is indented using 2 tabs and all * following lines inserted will be indented using 2 tabs as well. */ const ADJUST_INDENTATION = 2; } message = $message; $this->verbose = $verbose; } } dynamicRegistration = $dynamicRegistration; } } valueSet = $valueSet; } } location = $location; $this->message = $message; } } resolveProvider = $resolveProvider; $this->triggerCharacters = $triggerCharacters; } } groupsOnLabel = $groupsOnLabel; } } dynamicRegistration = $dynamicRegistration; $this->completionItem = $completionItem; $this->contextSupport = $contextSupport; $this->insertTextMode = $insertTextMode; $this->completionList = $completionList; } } properties = $properties; } } dynamicRegistration = $dynamicRegistration; $this->linkSupport = $linkSupport; } } dynamicRegistration = $dynamicRegistration; } } title = $title; } } items = $items; $this->isIncomplete = $isIncomplete; } } version = $version; } } dynamicRegistration = $dynamicRegistration; } } range = $range; $this->newText = $newText; } } valueSet = $valueSet; } } valueSet = $valueSet; } } label = $label; $this->parameters = $parameters; $this->documentation = $documentation; $this->activeParameter = $activeParameter; } } reason = $reason; } } { "name": "php-language-server-protocol", "version": "1.0.0", "lockfileVersion": 1, "requires": true, "dependencies": { "@mrmlnc/readdir-enhanced": { "version": "2.2.1", "resolved": "https://registry.npmjs.org/@mrmlnc/readdir-enhanced/-/readdir-enhanced-2.2.1.tgz", "integrity": "sha512-bPHp6Ji8b41szTOcaP63VlnbbO5Ny6dwAATtY6JTjh5N2OLrb5Qk/Th5cRkRQhkWCt+EJsYrNB0MiL+Gpn6e3g==", "dev": true, "requires": { "call-me-maybe": "^1.0.1", "glob-to-regexp": "^0.3.0" } }, "@nodelib/fs.stat": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-1.1.2.tgz", "integrity": "sha512-yprFYuno9FtNsSHVlSWd+nRlmGoAbqbeCwOryP6sC/zoCjhpArcRMYp19EvpSUSizJAlsXEwJv+wcWS9XaXdMw==", "dev": true }, "@octokit/rest": { "version": "15.12.0", "resolved": "https://registry.npmjs.org/@octokit/rest/-/rest-15.12.0.tgz", "integrity": "sha512-5wRag4kHRkp0JDo++L9x9FkDlHEALbLnbSede16D8u+a2/t+gX32uhDs8cukVLyyrZR79nmh1lNpxZmffwoNoQ==", "dev": true, "requires": { "before-after-hook": "^1.1.0", "btoa-lite": "^1.0.0", "debug": "^3.1.0", "http-proxy-agent": "^2.1.0", "https-proxy-agent": "^2.2.0", "lodash": "^4.17.4", "node-fetch": "^2.1.1", "universal-user-agent": "^2.0.0", "url-template": "^2.0.8" }, "dependencies": { "debug": { "version": "3.2.5", "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.5.tgz", "integrity": "sha512-D61LaDQPQkxJ5AUM2mbSJRbPkNs/TmdmOeLAi1hgDkpDfIfetSrjmWhccwtuResSwMbACjx/xXQofvM9CE/aeg==", "dev": true, "requires": { "ms": "^2.1.1" } } } }, "@semantic-release/commit-analyzer": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/@semantic-release/commit-analyzer/-/commit-analyzer-6.0.1.tgz", "integrity": "sha512-ENCRn1tm1D08CCBnIPsID8GjboWT6E97s0Lk3XrpAh+IMx615uAU1X2FoXyOGGc6zmqp9Ff4s8KECd/GjMcodQ==", "dev": true, "requires": { "conventional-changelog-angular": "^5.0.0", "conventional-commits-filter": "^2.0.0", "conventional-commits-parser": "^3.0.0", "debug": "^4.0.0", "import-from": "^2.1.0", "lodash": "^4.17.4" } }, "@semantic-release/error": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/@semantic-release/error/-/error-2.2.0.tgz", "integrity": "sha512-9Tj/qn+y2j+sjCI3Jd+qseGtHjOAeg7dU2/lVcqIQ9TV3QDaDXDYXcoOHU+7o2Hwh8L8ymL4gfuO7KxDs3q2zg==", "dev": true }, "@semantic-release/github": { "version": "5.0.5", "resolved": "https://registry.npmjs.org/@semantic-release/github/-/github-5.0.5.tgz", "integrity": "sha512-Hdt6b8ST2pg6pl151PlcsnTcdsC2UJhA5FdbmunbZG/TVmlnKCZ4WUzpji7YqJtDLjbQTuFm/vhM6atW3XjMWg==", "dev": true, "requires": { "@octokit/rest": "^15.2.0", "@semantic-release/error": "^2.2.0", "aggregate-error": "^1.0.0", "bottleneck": "^2.0.1", "debug": "^4.0.0", "dir-glob": "^2.0.0", "fs-extra": "^7.0.0", "globby": "^8.0.0", "http-proxy-agent": "^2.1.0", "https-proxy-agent": "^2.2.1", "issue-parser": "^3.0.0", "lodash": "^4.17.4", "mime": "^2.0.3", "p-filter": "^1.0.0", "p-retry": "^2.0.0", "parse-github-url": "^1.0.1", "url-join": "^4.0.0" } }, "@semantic-release/npm": { "version": "5.0.4", "resolved": "https://registry.npmjs.org/@semantic-release/npm/-/npm-5.0.4.tgz", "integrity": "sha512-ExGXP9GnM2hqUIgTnp6sXKB1G0Yh+fuLftmIopq5KHBWj34Wd2YbM/3iLkXXnAP1YZ9YCp7hsAdsR014ctbwHg==", "dev": true, "requires": { "@semantic-release/error": "^2.2.0", "aggregate-error": "^1.0.0", "detect-indent": "^5.0.0", "detect-newline": "^2.1.0", "execa": "^1.0.0", "fs-extra": "^7.0.0", "lodash": "^4.17.4", "nerf-dart": "^1.0.0", "normalize-url": "^3.0.0", "npm": "^6.3.0", "parse-json": "^4.0.0", "rc": "^1.2.8", "read-pkg": "^4.0.0", "registry-auth-token": "^3.3.1" }, "dependencies": { "read-pkg": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-4.0.1.tgz", "integrity": "sha1-ljYlN48+HE1IyFhytabsfV0JMjc=", "dev": true, "requires": { "normalize-package-data": "^2.3.2", "parse-json": "^4.0.0", "pify": "^3.0.0" } } } }, "@semantic-release/release-notes-generator": { "version": "7.0.2", "resolved": "https://registry.npmjs.org/@semantic-release/release-notes-generator/-/release-notes-generator-7.0.2.tgz", "integrity": "sha512-fomHrGq/gfZIAQYZk0MLRwfQ8d+DbTcI3kuO1hU2L0fDJYKHZHuPmKnsfVa5KoNdVVPHx878D/ojgyStRqhc9g==", "dev": true, "requires": { "conventional-changelog-angular": "^5.0.0", "conventional-changelog-writer": "^4.0.0", "conventional-commits-filter": "^2.0.0", "conventional-commits-parser": "^3.0.0", "debug": "^4.0.0", "get-stream": "^4.0.0", "git-url-parse": "^10.0.1", "import-from": "^2.1.0", "into-stream": "^3.1.0", "lodash": "^4.17.4" } }, "JSONStream": { "version": "1.3.4", "resolved": "https://registry.npmjs.org/JSONStream/-/JSONStream-1.3.4.tgz", "integrity": "sha512-Y7vfi3I5oMOYIr+WxV8NZxDSwcbNgzdKYsTNInmycOq9bUYwGg9ryu57Wg5NLmCjqdFPNUmpMBo3kSJN9tCbXg==", "dev": true, "requires": { "jsonparse": "^1.2.0", "through": ">=2.2.7 <3" } }, "agent-base": { "version": "4.2.1", "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-4.2.1.tgz", "integrity": "sha512-JVwXMr9nHYTUXsBFKUqhJwvlcYU/blreOEUkhNR2eXZIvwd+c+o5V4MgDPKWnMS/56awN3TRzIP+KoPn+roQtg==", "dev": true, "requires": { "es6-promisify": "^5.0.0" } }, "aggregate-error": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-1.0.0.tgz", "integrity": "sha1-iINE2tAiCnLjr1CQYRf0h3GSX6w=", "dev": true, "requires": { "clean-stack": "^1.0.0", "indent-string": "^3.0.0" } }, "ansi-regex": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", "dev": true }, "ansi-styles": { "version": "3.2.1", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", "dev": true, "requires": { "color-convert": "^1.9.0" } }, "ansicolors": { "version": "0.3.2", "resolved": "https://registry.npmjs.org/ansicolors/-/ansicolors-0.3.2.tgz", "integrity": "sha1-ZlWX3oap/+Oqm/vmyuXG6kJrSXk=", "dev": true }, "argparse": { "version": "1.0.10", "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", "dev": true, "requires": { "sprintf-js": "~1.0.2" } }, "argv-formatter": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/argv-formatter/-/argv-formatter-1.0.0.tgz", "integrity": "sha1-oMoMvCmltz6Dbuvhy/bF4OTrgvk=", "dev": true }, "arr-diff": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-4.0.0.tgz", "integrity": "sha1-1kYQdP6/7HHn4VI1dhoyml3HxSA=", "dev": true }, "arr-flatten": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/arr-flatten/-/arr-flatten-1.1.0.tgz", "integrity": "sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg==", "dev": true }, "arr-union": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/arr-union/-/arr-union-3.1.0.tgz", "integrity": "sha1-45sJrqne+Gao8gbiiK9jkZuuOcQ=", "dev": true }, "array-find-index": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/array-find-index/-/array-find-index-1.0.2.tgz", "integrity": "sha1-3wEKoSh+Fku9pvlyOwqWoexBh6E=", "dev": true }, "array-ify": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/array-ify/-/array-ify-1.0.0.tgz", "integrity": "sha1-nlKHYrSpBmrRY6aWKjZEGOlibs4=", "dev": true }, "array-union": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/array-union/-/array-union-1.0.2.tgz", "integrity": "sha1-mjRBDk9OPaI96jdb5b5w8kd47Dk=", "dev": true, "requires": { "array-uniq": "^1.0.1" } }, "array-uniq": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/array-uniq/-/array-uniq-1.0.3.tgz", "integrity": "sha1-r2rId6Jcx/dOBYiUdThY39sk/bY=", "dev": true }, "array-unique": { "version": "0.3.2", "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.3.2.tgz", "integrity": "sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg=", "dev": true }, "arrify": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/arrify/-/arrify-1.0.1.tgz", "integrity": "sha1-iYUI2iIm84DfkEcoRWhJwVAaSw0=", "dev": true }, "assign-symbols": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/assign-symbols/-/assign-symbols-1.0.0.tgz", "integrity": "sha1-WWZ/QfrdTyDMvCu5a41Pf3jsA2c=", "dev": true }, "async": { "version": "2.6.1", "resolved": "https://registry.npmjs.org/async/-/async-2.6.1.tgz", "integrity": "sha512-fNEiL2+AZt6AlAw/29Cr0UDe4sRAHCpEHh54WMz+Bb7QfNcFw4h3loofyJpLeQs4Yx7yuqu/2dLgM5hKOs6HlQ==", "dev": true, "requires": { "lodash": "^4.17.10" } }, "atob": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/atob/-/atob-2.1.2.tgz", "integrity": "sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg==", "dev": true }, "balanced-match": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", "dev": true }, "base": { "version": "0.11.2", "resolved": "https://registry.npmjs.org/base/-/base-0.11.2.tgz", "integrity": "sha512-5T6P4xPgpp0YDFvSWwEZ4NoE3aM4QBQXDzmVbraCkFj8zHM+mba8SyqB5DbZWyR7mYHo6Y7BdQo3MoA4m0TeQg==", "dev": true, "requires": { "cache-base": "^1.0.1", "class-utils": "^0.3.5", "component-emitter": "^1.2.1", "define-property": "^1.0.0", "isobject": "^3.0.1", "mixin-deep": "^1.2.0", "pascalcase": "^0.1.1" }, "dependencies": { "define-property": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", "dev": true, "requires": { "is-descriptor": "^1.0.0" } }, "is-accessor-descriptor": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", "dev": true, "requires": { "kind-of": "^6.0.0" } }, "is-data-descriptor": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", "dev": true, "requires": { "kind-of": "^6.0.0" } }, "is-descriptor": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", "dev": true, "requires": { "is-accessor-descriptor": "^1.0.0", "is-data-descriptor": "^1.0.0", "kind-of": "^6.0.2" } } } }, "before-after-hook": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/before-after-hook/-/before-after-hook-1.1.0.tgz", "integrity": "sha512-VOMDtYPwLbIncTxNoSzRyvaMxtXmLWLUqr8k5AfC1BzLk34HvBXaQX8snOwQZ4c0aX8aSERqtJSiI9/m2u5kuA==", "dev": true }, "bottleneck": { "version": "2.11.0", "resolved": "https://registry.npmjs.org/bottleneck/-/bottleneck-2.11.0.tgz", "integrity": "sha512-DvKiYR1kG1qRVoLBUtPlmJffktoBZIz3qtdUbINlwzQXDhlhZdF8gWesPjwp05xqr5QZ7wXA2k1w78/COCweTg==", "dev": true }, "brace-expansion": { "version": "1.1.11", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", "dev": true, "requires": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" } }, "braces": { "version": "2.3.2", "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz", "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==", "dev": true, "requires": { "arr-flatten": "^1.1.0", "array-unique": "^0.3.2", "extend-shallow": "^2.0.1", "fill-range": "^4.0.0", "isobject": "^3.0.1", "repeat-element": "^1.1.2", "snapdragon": "^0.8.1", "snapdragon-node": "^2.0.1", "split-string": "^3.0.2", "to-regex": "^3.0.1" }, "dependencies": { "extend-shallow": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", "dev": true, "requires": { "is-extendable": "^0.1.0" } } } }, "btoa-lite": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/btoa-lite/-/btoa-lite-1.0.0.tgz", "integrity": "sha1-M3dm2hWAEhD92VbCLpxokaudAzc=", "dev": true }, "builtin-modules": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-1.1.1.tgz", "integrity": "sha1-Jw8HbFpywC9bZaR9+Uxf46J4iS8=", "dev": true }, "cache-base": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/cache-base/-/cache-base-1.0.1.tgz", "integrity": "sha512-AKcdTnFSWATd5/GCPRxr2ChwIJ85CeyrEyjRHlKxQ56d4XJMGym0uAiKn0xbLOGOl3+yRpOTi484dVCEc5AUzQ==", "dev": true, "requires": { "collection-visit": "^1.0.0", "component-emitter": "^1.2.1", "get-value": "^2.0.6", "has-value": "^1.0.0", "isobject": "^3.0.1", "set-value": "^2.0.0", "to-object-path": "^0.3.0", "union-value": "^1.0.0", "unset-value": "^1.0.0" } }, "call-me-maybe": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/call-me-maybe/-/call-me-maybe-1.0.1.tgz", "integrity": "sha1-JtII6onje1y95gJQoV8DHBak1ms=", "dev": true }, "camelcase": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-4.1.0.tgz", "integrity": "sha1-1UVjW+HjPFQmScaRc+Xeas+uNN0=", "dev": true }, "camelcase-keys": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/camelcase-keys/-/camelcase-keys-4.2.0.tgz", "integrity": "sha1-oqpfsa9oh1glnDLBQUJteJI7m3c=", "dev": true, "requires": { "camelcase": "^4.1.0", "map-obj": "^2.0.0", "quick-lru": "^1.0.0" } }, "cardinal": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/cardinal/-/cardinal-2.1.1.tgz", "integrity": "sha1-fMEFXYItISlU0HsIXeolHMe8VQU=", "dev": true, "requires": { "ansicolors": "~0.3.2", "redeyed": "~2.1.0" } }, "chalk": { "version": "2.4.1", "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.1.tgz", "integrity": "sha512-ObN6h1v2fTJSmUXoS3nMQ92LbDK9be4TV+6G+omQlGJFdcUX5heKi1LZ1YnRMIgwTLEj3E24bT6tYni50rlCfQ==", "dev": true, "requires": { "ansi-styles": "^3.2.1", "escape-string-regexp": "^1.0.5", "supports-color": "^5.3.0" } }, "class-utils": { "version": "0.3.6", "resolved": "https://registry.npmjs.org/class-utils/-/class-utils-0.3.6.tgz", "integrity": "sha512-qOhPa/Fj7s6TY8H8esGu5QNpMMQxz79h+urzrNYN6mn+9BnxlDGf5QZ+XeCDsxSjPqsSR56XOZOJmpeurnLMeg==", "dev": true, "requires": { "arr-union": "^3.1.0", "define-property": "^0.2.5", "isobject": "^3.0.0", "static-extend": "^0.1.1" }, "dependencies": { "define-property": { "version": "0.2.5", "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", "dev": true, "requires": { "is-descriptor": "^0.1.0" } } } }, "clean-stack": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-1.3.0.tgz", "integrity": "sha1-noIVAa6XmYbEax1m0tQy2y/UrjE=", "dev": true }, "cli-table": { "version": "0.3.1", "resolved": "https://registry.npmjs.org/cli-table/-/cli-table-0.3.1.tgz", "integrity": "sha1-9TsFJmqLGguTSz0IIebi3FkUriM=", "dev": true, "requires": { "colors": "1.0.3" } }, "cliui": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/cliui/-/cliui-4.1.0.tgz", "integrity": "sha512-4FG+RSG9DL7uEwRUZXZn3SS34DiDPfzP0VOiEwtUWlE+AR2EIg+hSyvrIgUUfhdgR/UkAeW2QHgeP+hWrXs7jQ==", "dev": true, "requires": { "string-width": "^2.1.1", "strip-ansi": "^4.0.0", "wrap-ansi": "^2.0.0" } }, "code-point-at": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz", "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=", "dev": true }, "collection-visit": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/collection-visit/-/collection-visit-1.0.0.tgz", "integrity": "sha1-S8A3PBZLwykbTTaMgpzxqApZ3KA=", "dev": true, "requires": { "map-visit": "^1.0.0", "object-visit": "^1.0.0" } }, "color-convert": { "version": "1.9.3", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", "dev": true, "requires": { "color-name": "1.1.3" } }, "color-name": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", "dev": true }, "colors": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/colors/-/colors-1.0.3.tgz", "integrity": "sha1-BDP0TYCWgP3rYO0mDxsMJi6CpAs=", "dev": true }, "commander": { "version": "2.17.1", "resolved": "https://registry.npmjs.org/commander/-/commander-2.17.1.tgz", "integrity": "sha512-wPMUt6FnH2yzG95SA6mzjQOEKUU3aLaDEmzs1ti+1E9h+CsrZghRlqEM/EJ4KscsQVG8uNN4uVreUeT8+drlgg==", "dev": true, "optional": true }, "compare-func": { "version": "1.3.2", "resolved": "https://registry.npmjs.org/compare-func/-/compare-func-1.3.2.tgz", "integrity": "sha1-md0LpFfh+bxyKxLAjsM+6rMfpkg=", "dev": true, "requires": { "array-ify": "^1.0.0", "dot-prop": "^3.0.0" } }, "component-emitter": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.2.1.tgz", "integrity": "sha1-E3kY1teCg/ffemt8WmPhQOaUJeY=", "dev": true }, "concat-map": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", "dev": true }, "conventional-changelog-angular": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/conventional-changelog-angular/-/conventional-changelog-angular-5.0.1.tgz", "integrity": "sha512-q4ylJ68fWZDdrFC9z4zKcf97HW6hp7Mo2YlqD4owfXhecFKy/PJCU/1oVFF4TqochchChqmZ0Vb0e0g8/MKNlA==", "dev": true, "requires": { "compare-func": "^1.3.1", "q": "^1.5.1" } }, "conventional-changelog-writer": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/conventional-changelog-writer/-/conventional-changelog-writer-4.0.0.tgz", "integrity": "sha512-hMZPe0AQ6Bi05epeK/7hz80xxk59nPA5z/b63TOHq2wigM0/akreOc8N4Jam5b9nFgKWX1e9PdPv2ewgW6bcfg==", "dev": true, "requires": { "compare-func": "^1.3.1", "conventional-commits-filter": "^2.0.0", "dateformat": "^3.0.0", "handlebars": "^4.0.2", "json-stringify-safe": "^5.0.1", "lodash": "^4.2.1", "meow": "^4.0.0", "semver": "^5.5.0", "split": "^1.0.0", "through2": "^2.0.0" } }, "conventional-commits-filter": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/conventional-commits-filter/-/conventional-commits-filter-2.0.0.tgz", "integrity": "sha512-Cfl0j1/NquB/TMVx7Wrmyq7uRM+/rPQbtVVGwzfkhZ6/yH6fcMmP0Q/9044TBZPTNdGzm46vXFXL14wbET0/Mg==", "dev": true, "requires": { "is-subset": "^0.1.1", "modify-values": "^1.0.0" } }, "conventional-commits-parser": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/conventional-commits-parser/-/conventional-commits-parser-3.0.0.tgz", "integrity": "sha512-GWh71U26BLWgMykCp+VghZ4s64wVbtseECcKQ/PvcPZR2cUnz+FUc2J9KjxNl7/ZbCxST8R03c9fc+Vi0umS9Q==", "dev": true, "requires": { "JSONStream": "^1.0.4", "is-text-path": "^1.0.0", "lodash": "^4.2.1", "meow": "^4.0.0", "split2": "^2.0.0", "through2": "^2.0.0", "trim-off-newlines": "^1.0.0" } }, "copy-descriptor": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/copy-descriptor/-/copy-descriptor-0.1.1.tgz", "integrity": "sha1-Z29us8OZl8LuGsOpJP1hJHSPV40=", "dev": true }, "core-util-is": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=", "dev": true }, "cosmiconfig": { "version": "5.0.6", "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-5.0.6.tgz", "integrity": "sha512-6DWfizHriCrFWURP1/qyhsiFvYdlJzbCzmtFWh744+KyWsJo5+kPzUZZaMRSSItoYc0pxFX7gEO7ZC1/gN/7AQ==", "dev": true, "requires": { "is-directory": "^0.3.1", "js-yaml": "^3.9.0", "parse-json": "^4.0.0" } }, "cross-spawn": { "version": "6.0.5", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz", "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==", "dev": true, "requires": { "nice-try": "^1.0.4", "path-key": "^2.0.1", "semver": "^5.5.0", "shebang-command": "^1.2.0", "which": "^1.2.9" } }, "currently-unhandled": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/currently-unhandled/-/currently-unhandled-0.4.1.tgz", "integrity": "sha1-mI3zP+qxke95mmE2nddsF635V+o=", "dev": true, "requires": { "array-find-index": "^1.0.1" } }, "dateformat": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/dateformat/-/dateformat-3.0.3.tgz", "integrity": "sha512-jyCETtSl3VMZMWeRo7iY1FL19ges1t55hMo5yaam4Jrsm5EPL89UQkoQRyiI+Yf4k8r2ZpdngkV8hr1lIdjb3Q==", "dev": true }, "debug": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/debug/-/debug-4.0.1.tgz", "integrity": "sha512-K23FHJ/Mt404FSlp6gSZCevIbTMLX0j3fmHhUEhQ3Wq0FMODW3+cUSoLdy1Gx4polAf4t/lphhmHH35BB8cLYw==", "dev": true, "requires": { "ms": "^2.1.1" } }, "decamelize": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=", "dev": true }, "decamelize-keys": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/decamelize-keys/-/decamelize-keys-1.1.0.tgz", "integrity": "sha1-0XGoeTMlKAfrPLYdwcFEXQeN8tk=", "dev": true, "requires": { "decamelize": "^1.1.0", "map-obj": "^1.0.0" }, "dependencies": { "map-obj": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/map-obj/-/map-obj-1.0.1.tgz", "integrity": "sha1-2TPOuSBdgr3PSIb2dCvcK03qFG0=", "dev": true } } }, "decode-uri-component": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.0.tgz", "integrity": "sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU=", "dev": true }, "deep-extend": { "version": "0.6.0", "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==", "dev": true }, "define-property": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/define-property/-/define-property-2.0.2.tgz", "integrity": "sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ==", "dev": true, "requires": { "is-descriptor": "^1.0.2", "isobject": "^3.0.1" }, "dependencies": { "is-accessor-descriptor": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", "dev": true, "requires": { "kind-of": "^6.0.0" } }, "is-data-descriptor": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", "dev": true, "requires": { "kind-of": "^6.0.0" } }, "is-descriptor": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", "dev": true, "requires": { "is-accessor-descriptor": "^1.0.0", "is-data-descriptor": "^1.0.0", "kind-of": "^6.0.2" } } } }, "detect-indent": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/detect-indent/-/detect-indent-5.0.0.tgz", "integrity": "sha1-OHHMCmoALow+Wzz38zYmRnXwa50=", "dev": true }, "detect-newline": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/detect-newline/-/detect-newline-2.1.0.tgz", "integrity": "sha1-9B8cEL5LAOh7XxPaaAdZ8sW/0+I=", "dev": true }, "dir-glob": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-2.0.0.tgz", "integrity": "sha512-37qirFDz8cA5fimp9feo43fSuRo2gHwaIn6dXL8Ber1dGwUosDrGZeCCXq57WnIqE4aQ+u3eQZzsk1yOzhdwag==", "dev": true, "requires": { "arrify": "^1.0.1", "path-type": "^3.0.0" } }, "dot-prop": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-3.0.0.tgz", "integrity": "sha1-G3CK8JSknJoOfbyteQq6U52sEXc=", "dev": true, "requires": { "is-obj": "^1.0.0" } }, "duplexer2": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/duplexer2/-/duplexer2-0.1.4.tgz", "integrity": "sha1-ixLauHjA1p4+eJEFFmKjL8a93ME=", "dev": true, "requires": { "readable-stream": "^2.0.2" } }, "end-of-stream": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.1.tgz", "integrity": "sha512-1MkrZNvWTKCaigbn+W15elq2BB/L22nqrSY5DKlo3X6+vclJm8Bb5djXJBmEX6fS3+zCh/F4VBK5Z2KxJt4s2Q==", "dev": true, "requires": { "once": "^1.4.0" } }, "env-ci": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/env-ci/-/env-ci-3.0.0.tgz", "integrity": "sha512-3Xt4Cfjdy9MTTrg/eWTnJNQIrtU1DDV0KyuWOGlrR2oa9dOdzoOMbQBFbfrTiv+GypdiWWIw5HdmtakZO+rzWA==", "dev": true, "requires": { "execa": "^1.0.0", "java-properties": "^0.2.9" } }, "error-ex": { "version": "1.3.2", "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", "dev": true, "requires": { "is-arrayish": "^0.2.1" } }, "es6-promise": { "version": "4.2.5", "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-4.2.5.tgz", "integrity": "sha512-n6wvpdE43VFtJq+lUDYDBFUwV8TZbuGXLV4D6wKafg13ldznKsyEvatubnmUe31zcvelSzOHF+XbaT+Bl9ObDg==", "dev": true }, "es6-promisify": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/es6-promisify/-/es6-promisify-5.0.0.tgz", "integrity": "sha1-UQnWLz5W6pZ8S2NQWu8IKRyKUgM=", "dev": true, "requires": { "es6-promise": "^4.0.3" } }, "escape-string-regexp": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", "dev": true }, "esprima": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", "dev": true }, "execa": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/execa/-/execa-1.0.0.tgz", "integrity": "sha512-adbxcyWV46qiHyvSp50TKt05tB4tK3HcmF7/nxfAdhnox83seTDbwnaqKO4sXRy7roHAIFqJP/Rw/AuEbX61LA==", "dev": true, "requires": { "cross-spawn": "^6.0.0", "get-stream": "^4.0.0", "is-stream": "^1.1.0", "npm-run-path": "^2.0.0", "p-finally": "^1.0.0", "signal-exit": "^3.0.0", "strip-eof": "^1.0.0" } }, "expand-brackets": { "version": "2.1.4", "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-2.1.4.tgz", "integrity": "sha1-t3c14xXOMPa27/D4OwQVGiJEliI=", "dev": true, "requires": { "debug": "^2.3.3", "define-property": "^0.2.5", "extend-shallow": "^2.0.1", "posix-character-classes": "^0.1.0", "regex-not": "^1.0.0", "snapdragon": "^0.8.1", "to-regex": "^3.0.1" }, "dependencies": { "debug": { "version": "2.6.9", "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", "dev": true, "requires": { "ms": "2.0.0" } }, "define-property": { "version": "0.2.5", "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", "dev": true, "requires": { "is-descriptor": "^0.1.0" } }, "extend-shallow": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", "dev": true, "requires": { "is-extendable": "^0.1.0" } }, "ms": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", "dev": true } } }, "extend-shallow": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", "integrity": "sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg=", "dev": true, "requires": { "assign-symbols": "^1.0.0", "is-extendable": "^1.0.1" }, "dependencies": { "is-extendable": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", "dev": true, "requires": { "is-plain-object": "^2.0.4" } } } }, "extglob": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/extglob/-/extglob-2.0.4.tgz", "integrity": "sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw==", "dev": true, "requires": { "array-unique": "^0.3.2", "define-property": "^1.0.0", "expand-brackets": "^2.1.4", "extend-shallow": "^2.0.1", "fragment-cache": "^0.2.1", "regex-not": "^1.0.0", "snapdragon": "^0.8.1", "to-regex": "^3.0.1" }, "dependencies": { "define-property": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", "dev": true, "requires": { "is-descriptor": "^1.0.0" } }, "extend-shallow": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", "dev": true, "requires": { "is-extendable": "^0.1.0" } }, "is-accessor-descriptor": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", "dev": true, "requires": { "kind-of": "^6.0.0" } }, "is-data-descriptor": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", "dev": true, "requires": { "kind-of": "^6.0.0" } }, "is-descriptor": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", "dev": true, "requires": { "is-accessor-descriptor": "^1.0.0", "is-data-descriptor": "^1.0.0", "kind-of": "^6.0.2" } } } }, "fast-glob": { "version": "2.2.2", "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-2.2.2.tgz", "integrity": "sha512-TR6zxCKftDQnUAPvkrCWdBgDq/gbqx8A3ApnBrR5rMvpp6+KMJI0Igw7fkWPgeVK0uhRXTXdvO3O+YP0CaUX2g==", "dev": true, "requires": { "@mrmlnc/readdir-enhanced": "^2.2.1", "@nodelib/fs.stat": "^1.0.1", "glob-parent": "^3.1.0", "is-glob": "^4.0.0", "merge2": "^1.2.1", "micromatch": "^3.1.10" } }, "figures": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/figures/-/figures-2.0.0.tgz", "integrity": "sha1-OrGi0qYsi/tDGgyUy3l6L84nyWI=", "dev": true, "requires": { "escape-string-regexp": "^1.0.5" } }, "fill-range": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz", "integrity": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=", "dev": true, "requires": { "extend-shallow": "^2.0.1", "is-number": "^3.0.0", "repeat-string": "^1.6.1", "to-regex-range": "^2.1.0" }, "dependencies": { "extend-shallow": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", "dev": true, "requires": { "is-extendable": "^0.1.0" } } } }, "find-up": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", "integrity": "sha1-RdG35QbHF93UgndaK3eSCjwMV6c=", "dev": true, "requires": { "locate-path": "^2.0.0" } }, "find-versions": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/find-versions/-/find-versions-2.0.0.tgz", "integrity": "sha1-KtkNSQ9oKMGqQCks9wmsMxghDDw=", "dev": true, "requires": { "array-uniq": "^1.0.0", "semver-regex": "^1.0.0" } }, "for-in": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz", "integrity": "sha1-gQaNKVqBQuwKxybG4iAMMPttXoA=", "dev": true }, "fragment-cache": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/fragment-cache/-/fragment-cache-0.2.1.tgz", "integrity": "sha1-QpD60n8T6Jvn8zeZxrxaCr//DRk=", "dev": true, "requires": { "map-cache": "^0.2.2" } }, "from2": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/from2/-/from2-2.3.0.tgz", "integrity": "sha1-i/tVAr3kpNNs/e6gB/zKIdfjgq8=", "dev": true, "requires": { "inherits": "^2.0.1", "readable-stream": "^2.0.0" } }, "fs-extra": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-7.0.0.tgz", "integrity": "sha512-EglNDLRpmaTWiD/qraZn6HREAEAHJcJOmxNEYwq6xeMKnVMAy3GUcFB+wXt2C6k4CNvB/mP1y/U3dzvKKj5OtQ==", "dev": true, "requires": { "graceful-fs": "^4.1.2", "jsonfile": "^4.0.0", "universalify": "^0.1.0" } }, "fs.realpath": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", "dev": true }, "get-caller-file": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-1.0.3.tgz", "integrity": "sha512-3t6rVToeoZfYSGd8YoLFR2DJkiQrIiUrGcjvFX2mDw3bn6k2OtwHN0TNCLbBO+w8qTvimhDkv+LSscbJY1vE6w==", "dev": true }, "get-stream": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-4.0.0.tgz", "integrity": "sha512-FneLKMENeOR7wOK0/ZXCh+lwqtnPwkeunJjRN28LPqzGvNAhYvrTAhXv6xDm4vsJ0M7lcRbIYHQudKsSy2RtSQ==", "dev": true, "requires": { "pump": "^3.0.0" } }, "get-value": { "version": "2.0.6", "resolved": "https://registry.npmjs.org/get-value/-/get-value-2.0.6.tgz", "integrity": "sha1-3BXKHGcjh8p2vTesCjlbogQqLCg=", "dev": true }, "git-log-parser": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/git-log-parser/-/git-log-parser-1.2.0.tgz", "integrity": "sha1-LmpMGxP8AAKCB7p5WnrDFme5/Uo=", "dev": true, "requires": { "argv-formatter": "~1.0.0", "spawn-error-forwarder": "~1.0.0", "split2": "~1.0.0", "stream-combiner2": "~1.1.1", "through2": "~2.0.0", "traverse": "~0.6.6" }, "dependencies": { "split2": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/split2/-/split2-1.0.0.tgz", "integrity": "sha1-UuLiIdiMdfmnP5BVbiY/+WdysxQ=", "dev": true, "requires": { "through2": "~2.0.0" } } } }, "git-up": { "version": "2.0.10", "resolved": "https://registry.npmjs.org/git-up/-/git-up-2.0.10.tgz", "integrity": "sha512-2v4UN3qV2RGypD9QpmUjpk+4+RlYpW8GFuiZqQnKmvei08HsFPd0RfbDvEhnE4wBvnYs8ORVtYpOFuuCEmBVBw==", "dev": true, "requires": { "is-ssh": "^1.3.0", "parse-url": "^1.3.0" } }, "git-url-parse": { "version": "10.0.1", "resolved": "https://registry.npmjs.org/git-url-parse/-/git-url-parse-10.0.1.tgz", "integrity": "sha512-Tq2u8UPXc/FawC/dO8bvh8jcck0Lkor5OhuZvmVSeyJGRucDBfw9y2zy/GNCx28lMYh1N12IzPwDexjUNFyAeg==", "dev": true, "requires": { "git-up": "^2.0.0" } }, "glob": { "version": "7.1.3", "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.3.tgz", "integrity": "sha512-vcfuiIxogLV4DlGBHIUOwI0IbrJ8HWPc4MU7HzviGeNho/UJDfi6B5p3sHeWIQ0KGIU0Jpxi5ZHxemQfLkkAwQ==", "dev": true, "requires": { "fs.realpath": "^1.0.0", "inflight": "^1.0.4", "inherits": "2", "minimatch": "^3.0.4", "once": "^1.3.0", "path-is-absolute": "^1.0.0" } }, "glob-parent": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-3.1.0.tgz", "integrity": "sha1-nmr2KZ2NO9K9QEMIMr0RPfkGxa4=", "dev": true, "requires": { "is-glob": "^3.1.0", "path-dirname": "^1.0.0" }, "dependencies": { "is-glob": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-3.1.0.tgz", "integrity": "sha1-e6WuJCF4BKxwcHuWkiVnSGzD6Eo=", "dev": true, "requires": { "is-extglob": "^2.1.0" } } } }, "glob-to-regexp": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/glob-to-regexp/-/glob-to-regexp-0.3.0.tgz", "integrity": "sha1-jFoUlNIGbFcMw7/kSWF1rMTVAqs=", "dev": true }, "globby": { "version": "8.0.1", "resolved": "https://registry.npmjs.org/globby/-/globby-8.0.1.tgz", "integrity": "sha512-oMrYrJERnKBLXNLVTqhm3vPEdJ/b2ZE28xN4YARiix1NOIOBPEpOUnm844K1iu/BkphCaf2WNFwMszv8Soi1pw==", "dev": true, "requires": { "array-union": "^1.0.1", "dir-glob": "^2.0.0", "fast-glob": "^2.0.2", "glob": "^7.1.2", "ignore": "^3.3.5", "pify": "^3.0.0", "slash": "^1.0.0" } }, "graceful-fs": { "version": "4.1.11", "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.11.tgz", "integrity": "sha1-Dovf5NHduIVNZOBOp8AOKgJuVlg=", "dev": true }, "handlebars": { "version": "4.0.12", "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.0.12.tgz", "integrity": "sha512-RhmTekP+FZL+XNhwS1Wf+bTTZpdLougwt5pcgA1tuz6Jcx0fpH/7z0qd71RKnZHBCxIRBHfBOnio4gViPemNzA==", "dev": true, "requires": { "async": "^2.5.0", "optimist": "^0.6.1", "source-map": "^0.6.1", "uglify-js": "^3.1.4" }, "dependencies": { "source-map": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", "dev": true } } }, "has-flag": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", "dev": true }, "has-value": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/has-value/-/has-value-1.0.0.tgz", "integrity": "sha1-GLKB2lhbHFxR3vJMkw7SmgvmsXc=", "dev": true, "requires": { "get-value": "^2.0.6", "has-values": "^1.0.0", "isobject": "^3.0.0" } }, "has-values": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/has-values/-/has-values-1.0.0.tgz", "integrity": "sha1-lbC2P+whRmGab+V/51Yo1aOe/k8=", "dev": true, "requires": { "is-number": "^3.0.0", "kind-of": "^4.0.0" }, "dependencies": { "kind-of": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-4.0.0.tgz", "integrity": "sha1-IIE989cSkosgc3hpGkUGb65y3Vc=", "dev": true, "requires": { "is-buffer": "^1.1.5" } } } }, "hook-std": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/hook-std/-/hook-std-1.1.0.tgz", "integrity": "sha512-aIyBZbZl3NS8XoSwIDQ+ZaiBuPOhhPWoBFA3QX0Q8hOMO8Tx4xGRTDnn/nl/LAtZWdieXzFC9ohAtTSnWrlHCQ==", "dev": true }, "hosted-git-info": { "version": "2.7.1", "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.7.1.tgz", "integrity": "sha512-7T/BxH19zbcCTa8XkMlbK5lTo1WtgkFi3GvdWEyNuc4Vex7/9Dqbnpsf4JMydcfj9HCg4zUWFTL3Za6lapg5/w==", "dev": true }, "http-proxy-agent": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-2.1.0.tgz", "integrity": "sha512-qwHbBLV7WviBl0rQsOzH6o5lwyOIvwp/BdFnvVxXORldu5TmjFfjzBcWUWS5kWAZhmv+JtiDhSuQCp4sBfbIgg==", "dev": true, "requires": { "agent-base": "4", "debug": "3.1.0" }, "dependencies": { "debug": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", "dev": true, "requires": { "ms": "2.0.0" } }, "ms": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", "dev": true } } }, "https-proxy-agent": { "version": "2.2.1", "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-2.2.1.tgz", "integrity": "sha512-HPCTS1LW51bcyMYbxUIOO4HEOlQ1/1qRaFWcyxvwaqUS9TY88aoEuHUY33kuAh1YhVVaDQhLZsnPd+XNARWZlQ==", "dev": true, "requires": { "agent-base": "^4.1.0", "debug": "^3.1.0" }, "dependencies": { "debug": { "version": "3.2.5", "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.5.tgz", "integrity": "sha512-D61LaDQPQkxJ5AUM2mbSJRbPkNs/TmdmOeLAi1hgDkpDfIfetSrjmWhccwtuResSwMbACjx/xXQofvM9CE/aeg==", "dev": true, "requires": { "ms": "^2.1.1" } } } }, "ignore": { "version": "3.3.10", "resolved": "https://registry.npmjs.org/ignore/-/ignore-3.3.10.tgz", "integrity": "sha512-Pgs951kaMm5GXP7MOvxERINe3gsaVjUWFm+UZPSq9xYriQAksyhg0csnS0KXSNRD5NmNdapXEpjxG49+AKh/ug==", "dev": true }, "import-from": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/import-from/-/import-from-2.1.0.tgz", "integrity": "sha1-M1238qev/VOqpHHUuAId7ja387E=", "dev": true, "requires": { "resolve-from": "^3.0.0" }, "dependencies": { "resolve-from": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-3.0.0.tgz", "integrity": "sha1-six699nWiBvItuZTM17rywoYh0g=", "dev": true } } }, "indent-string": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-3.2.0.tgz", "integrity": "sha1-Sl/W0nzDMvN+VBmlBNu4NxBckok=", "dev": true }, "inflight": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", "dev": true, "requires": { "once": "^1.3.0", "wrappy": "1" } }, "inherits": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=", "dev": true }, "ini": { "version": "1.3.5", "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.5.tgz", "integrity": "sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw==", "dev": true }, "into-stream": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/into-stream/-/into-stream-3.1.0.tgz", "integrity": "sha1-lvsKk2wSur1v8XUqF9BWFqvQlMY=", "dev": true, "requires": { "from2": "^2.1.1", "p-is-promise": "^1.1.0" } }, "invert-kv": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/invert-kv/-/invert-kv-2.0.0.tgz", "integrity": "sha512-wPVv/y/QQ/Uiirj/vh3oP+1Ww+AWehmi1g5fFWGPF6IpCBCDVrhgHRMvrLfdYcwDh3QJbGXDW4JAuzxElLSqKA==", "dev": true }, "is-accessor-descriptor": { "version": "0.1.6", "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", "dev": true, "requires": { "kind-of": "^3.0.2" }, "dependencies": { "kind-of": { "version": "3.2.2", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", "dev": true, "requires": { "is-buffer": "^1.1.5" } } } }, "is-arrayish": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=", "dev": true }, "is-buffer": { "version": "1.1.6", "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==", "dev": true }, "is-builtin-module": { "version": "1.0.0", "resolved": "http://registry.npmjs.org/is-builtin-module/-/is-builtin-module-1.0.0.tgz", "integrity": "sha1-VAVy0096wxGfj3bDDLwbHgN6/74=", "dev": true, "requires": { "builtin-modules": "^1.0.0" } }, "is-data-descriptor": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", "dev": true, "requires": { "kind-of": "^3.0.2" }, "dependencies": { "kind-of": { "version": "3.2.2", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", "dev": true, "requires": { "is-buffer": "^1.1.5" } } } }, "is-descriptor": { "version": "0.1.6", "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", "dev": true, "requires": { "is-accessor-descriptor": "^0.1.6", "is-data-descriptor": "^0.1.4", "kind-of": "^5.0.0" }, "dependencies": { "kind-of": { "version": "5.1.0", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==", "dev": true } } }, "is-directory": { "version": "0.3.1", "resolved": "https://registry.npmjs.org/is-directory/-/is-directory-0.3.1.tgz", "integrity": "sha1-YTObbyR1/Hcv2cnYP1yFddwVSuE=", "dev": true }, "is-extendable": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", "integrity": "sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik=", "dev": true }, "is-extglob": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=", "dev": true }, "is-fullwidth-code-point": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", "dev": true }, "is-glob": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.0.tgz", "integrity": "sha1-lSHHaEXMJhCoUgPd8ICpWML/q8A=", "dev": true, "requires": { "is-extglob": "^2.1.1" } }, "is-number": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", "dev": true, "requires": { "kind-of": "^3.0.2" }, "dependencies": { "kind-of": { "version": "3.2.2", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", "dev": true, "requires": { "is-buffer": "^1.1.5" } } } }, "is-obj": { "version": "1.0.1", "resolved": "http://registry.npmjs.org/is-obj/-/is-obj-1.0.1.tgz", "integrity": "sha1-PkcprB9f3gJc19g6iW2rn09n2w8=", "dev": true }, "is-plain-obj": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-1.1.0.tgz", "integrity": "sha1-caUMhCnfync8kqOQpKA7OfzVHT4=", "dev": true }, "is-plain-object": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", "dev": true, "requires": { "isobject": "^3.0.1" } }, "is-ssh": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/is-ssh/-/is-ssh-1.3.0.tgz", "integrity": "sha1-6+oRaaJhTaOSpjdANmw84EnY3/Y=", "dev": true, "requires": { "protocols": "^1.1.0" } }, "is-stream": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz", "integrity": "sha1-EtSj3U5o4Lec6428hBc66A2RykQ=", "dev": true }, "is-subset": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/is-subset/-/is-subset-0.1.1.tgz", "integrity": "sha1-ilkRfZMt4d4A8kX83TnOQ/HpOaY=", "dev": true }, "is-text-path": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/is-text-path/-/is-text-path-1.0.1.tgz", "integrity": "sha1-Thqg+1G/vLPpJogAE5cgLBd1tm4=", "dev": true, "requires": { "text-extensions": "^1.0.0" } }, "is-windows": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz", "integrity": "sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==", "dev": true }, "isarray": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", "dev": true }, "isexe": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", "dev": true }, "isobject": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", "dev": true }, "issue-parser": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/issue-parser/-/issue-parser-3.0.0.tgz", "integrity": "sha512-VWIhBdy0eOhlvpxOOMecBCHMpjx7lWVZcYpSzjD4dSdxptzI9TBR/cQEh057HL8+7jQKTLs+uCtezY/9VoveCA==", "dev": true, "requires": { "lodash.capitalize": "^4.2.1", "lodash.escaperegexp": "^4.1.2", "lodash.isplainobject": "^4.0.6", "lodash.isstring": "^4.0.1", "lodash.uniqby": "^4.7.0" } }, "java-properties": { "version": "0.2.10", "resolved": "https://registry.npmjs.org/java-properties/-/java-properties-0.2.10.tgz", "integrity": "sha512-CpKJh9VRNhS+XqZtg1UMejETGEiqwCGDC/uwPEEQwc2nfdbSm73SIE29TplG2gLYuBOOTNDqxzG6A9NtEPLt0w==", "dev": true }, "js-yaml": { "version": "3.12.0", "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.12.0.tgz", "integrity": "sha512-PIt2cnwmPfL4hKNwqeiuz4bKfnzHTBv6HyVgjahA6mPLwPDzjDWrplJBMjHUFxku/N3FlmrbyPclad+I+4mJ3A==", "dev": true, "requires": { "argparse": "^1.0.7", "esprima": "^4.0.0" } }, "json-parse-better-errors": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz", "integrity": "sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==", "dev": true }, "json-stringify-safe": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", "integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=", "dev": true }, "jsonfile": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", "integrity": "sha1-h3Gq4HmbZAdrdmQPygWPnBDjPss=", "dev": true, "requires": { "graceful-fs": "^4.1.6" } }, "jsonparse": { "version": "1.3.1", "resolved": "https://registry.npmjs.org/jsonparse/-/jsonparse-1.3.1.tgz", "integrity": "sha1-P02uSpH6wxX3EGL4UhzCOfE2YoA=", "dev": true }, "kind-of": { "version": "6.0.2", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz", "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==", "dev": true }, "lcid": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/lcid/-/lcid-2.0.0.tgz", "integrity": "sha512-avPEb8P8EGnwXKClwsNUgryVjllcRqtMYa49NTsbQagYuT1DcXnl1915oxWjoyGrXR6zH/Y0Zc96xWsPcoDKeA==", "dev": true, "requires": { "invert-kv": "^2.0.0" } }, "load-json-file": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-4.0.0.tgz", "integrity": "sha1-L19Fq5HjMhYjT9U62rZo607AmTs=", "dev": true, "requires": { "graceful-fs": "^4.1.2", "parse-json": "^4.0.0", "pify": "^3.0.0", "strip-bom": "^3.0.0" } }, "locate-path": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz", "integrity": "sha1-K1aLJl7slExtnA3pw9u7ygNUzY4=", "dev": true, "requires": { "p-locate": "^2.0.0", "path-exists": "^3.0.0" }, "dependencies": { "p-locate": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz", "integrity": "sha1-IKAQOyIqcMj9OcwuWAaA893l7EM=", "dev": true, "requires": { "p-limit": "^1.1.0" } } } }, "lodash": { "version": "4.17.11", "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.11.tgz", "integrity": "sha512-cQKh8igo5QUhZ7lg38DYWAxMvjSAKG0A8wGSVimP07SIUEK2UO+arSRKbRZWtelMtN5V0Hkwh5ryOto/SshYIg==", "dev": true }, "lodash.assign": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/lodash.assign/-/lodash.assign-4.2.0.tgz", "integrity": "sha1-DZnzzNem0mHRm9rrkkUAXShYCOc=", "dev": true }, "lodash.capitalize": { "version": "4.2.1", "resolved": "https://registry.npmjs.org/lodash.capitalize/-/lodash.capitalize-4.2.1.tgz", "integrity": "sha1-+CbJtOKoUR2E46yinbBeGk87cqk=", "dev": true }, "lodash.escaperegexp": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/lodash.escaperegexp/-/lodash.escaperegexp-4.1.2.tgz", "integrity": "sha1-ZHYsSGGAglGKw99Mz11YhtriA0c=", "dev": true }, "lodash.isplainobject": { "version": "4.0.6", "resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz", "integrity": "sha1-fFJqUtibRcRcxpC4gWO+BJf1UMs=", "dev": true }, "lodash.isstring": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/lodash.isstring/-/lodash.isstring-4.0.1.tgz", "integrity": "sha1-1SfftUVuynzJu5XV2ur4i6VKVFE=", "dev": true }, "lodash.toarray": { "version": "4.4.0", "resolved": "https://registry.npmjs.org/lodash.toarray/-/lodash.toarray-4.4.0.tgz", "integrity": "sha1-JMS/zWsvuji/0FlNsRedjptlZWE=", "dev": true }, "lodash.uniqby": { "version": "4.7.0", "resolved": "https://registry.npmjs.org/lodash.uniqby/-/lodash.uniqby-4.7.0.tgz", "integrity": "sha1-2ZwHpmnp5tJOE2Lf4mbGdhavEwI=", "dev": true }, "loud-rejection": { "version": "1.6.0", "resolved": "https://registry.npmjs.org/loud-rejection/-/loud-rejection-1.6.0.tgz", "integrity": "sha1-W0b4AUft7leIcPCG0Eghz5mOVR8=", "dev": true, "requires": { "currently-unhandled": "^0.4.1", "signal-exit": "^3.0.0" } }, "macos-release": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/macos-release/-/macos-release-1.1.0.tgz", "integrity": "sha512-mmLbumEYMi5nXReB9js3WGsB8UE6cDBWyIO62Z4DNx6GbRhDxHNjA1MlzSpJ2S2KM1wyiPRA0d19uHWYYvMHjA==", "dev": true }, "map-age-cleaner": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/map-age-cleaner/-/map-age-cleaner-0.1.2.tgz", "integrity": "sha512-UN1dNocxQq44IhJyMI4TU8phc2m9BddacHRPRjKGLYaF0jqd3xLz0jS0skpAU9WgYyoR4gHtUpzytNBS385FWQ==", "dev": true, "requires": { "p-defer": "^1.0.0" } }, "map-cache": { "version": "0.2.2", "resolved": "https://registry.npmjs.org/map-cache/-/map-cache-0.2.2.tgz", "integrity": "sha1-wyq9C9ZSXZsFFkW7TyasXcmKDb8=", "dev": true }, "map-obj": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/map-obj/-/map-obj-2.0.0.tgz", "integrity": "sha1-plzSkIepJZi4eRJXpSPgISIqwfk=", "dev": true }, "map-visit": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/map-visit/-/map-visit-1.0.0.tgz", "integrity": "sha1-7Nyo8TFE5mDxtb1B8S80edmN+48=", "dev": true, "requires": { "object-visit": "^1.0.0" } }, "marked": { "version": "0.5.0", "resolved": "https://registry.npmjs.org/marked/-/marked-0.5.0.tgz", "integrity": "sha512-UhjmkCWKu1SS/BIePL2a59BMJ7V42EYtTfksodPRXzPEGEph3Inp5dylseqt+KbU9Jglsx8xcMKmlumfJMBXAA==", "dev": true }, "marked-terminal": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/marked-terminal/-/marked-terminal-3.1.1.tgz", "integrity": "sha512-7UBFww1rdx0w9HehLMCVYa8/AxXaiDigDfMsJcj82/wgLQG9cj+oiMAVlJpeWD57VFJY2OYY+bKeEVIjIlxi+w==", "dev": true, "requires": { "cardinal": "^2.1.1", "chalk": "^2.4.1", "cli-table": "^0.3.1", "lodash.assign": "^4.2.0", "node-emoji": "^1.4.1" } }, "mem": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/mem/-/mem-4.0.0.tgz", "integrity": "sha512-WQxG/5xYc3tMbYLXoXPm81ET2WDULiU5FxbuIoNbJqLOOI8zehXFdZuiUEgfdrU2mVB1pxBZUGlYORSrpuJreA==", "dev": true, "requires": { "map-age-cleaner": "^0.1.1", "mimic-fn": "^1.0.0", "p-is-promise": "^1.1.0" } }, "meow": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/meow/-/meow-4.0.1.tgz", "integrity": "sha512-xcSBHD5Z86zaOc+781KrupuHAzeGXSLtiAOmBsiLDiPSaYSB6hdew2ng9EBAnZ62jagG9MHAOdxpDi/lWBFJ/A==", "dev": true, "requires": { "camelcase-keys": "^4.0.0", "decamelize-keys": "^1.0.0", "loud-rejection": "^1.0.0", "minimist": "^1.1.3", "minimist-options": "^3.0.1", "normalize-package-data": "^2.3.4", "read-pkg-up": "^3.0.0", "redent": "^2.0.0", "trim-newlines": "^2.0.0" }, "dependencies": { "read-pkg-up": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-3.0.0.tgz", "integrity": "sha1-PtSWaF26D4/hGNBpHcUfSh/5bwc=", "dev": true, "requires": { "find-up": "^2.0.0", "read-pkg": "^3.0.0" } } } }, "merge2": { "version": "1.2.2", "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.2.2.tgz", "integrity": "sha512-bgM8twH86rWni21thii6WCMQMRMmwqqdW3sGWi9IipnVAszdLXRjwDwAnyrVXo6DuP3AjRMMttZKUB48QWIFGg==", "dev": true }, "micromatch": { "version": "3.1.10", "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==", "dev": true, "requires": { "arr-diff": "^4.0.0", "array-unique": "^0.3.2", "braces": "^2.3.1", "define-property": "^2.0.2", "extend-shallow": "^3.0.2", "extglob": "^2.0.4", "fragment-cache": "^0.2.1", "kind-of": "^6.0.2", "nanomatch": "^1.2.9", "object.pick": "^1.3.0", "regex-not": "^1.0.0", "snapdragon": "^0.8.1", "to-regex": "^3.0.2" } }, "mime": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/mime/-/mime-2.3.1.tgz", "integrity": "sha512-OEUllcVoydBHGN1z84yfQDimn58pZNNNXgZlHXSboxMlFvgI6MXSWpWKpFRra7H1HxpVhHTkrghfRW49k6yjeg==", "dev": true }, "mimic-fn": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-1.2.0.tgz", "integrity": "sha512-jf84uxzwiuiIVKiOLpfYk7N46TSy8ubTonmneY9vrpHNAnp0QBt2BxWV9dO3/j+BoVAb+a5G6YDPW3M5HOdMWQ==", "dev": true }, "minimatch": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", "dev": true, "requires": { "brace-expansion": "^1.1.7" } }, "minimist": { "version": "1.2.0", "resolved": "http://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", "dev": true }, "minimist-options": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/minimist-options/-/minimist-options-3.0.2.tgz", "integrity": "sha512-FyBrT/d0d4+uiZRbqznPXqw3IpZZG3gl3wKWiX784FycUKVwBt0uLBFkQrtE4tZOrgo78nZp2jnKz3L65T5LdQ==", "dev": true, "requires": { "arrify": "^1.0.1", "is-plain-obj": "^1.1.0" } }, "mixin-deep": { "version": "1.3.1", "resolved": "https://registry.npmjs.org/mixin-deep/-/mixin-deep-1.3.1.tgz", "integrity": "sha512-8ZItLHeEgaqEvd5lYBXfm4EZSFCX29Jb9K+lAHhDKzReKBQKj3R+7NOF6tjqYi9t4oI8VUfaWITJQm86wnXGNQ==", "dev": true, "requires": { "for-in": "^1.0.2", "is-extendable": "^1.0.1" }, "dependencies": { "is-extendable": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", "dev": true, "requires": { "is-plain-object": "^2.0.4" } } } }, "modify-values": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/modify-values/-/modify-values-1.0.1.tgz", "integrity": "sha512-xV2bxeN6F7oYjZWTe/YPAy6MN2M+sL4u/Rlm2AHCIVGfo2p1yGmBHQ6vHehl4bRTZBdHu3TSkWdYgkwpYzAGSw==", "dev": true }, "ms": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==", "dev": true }, "nanomatch": { "version": "1.2.13", "resolved": "https://registry.npmjs.org/nanomatch/-/nanomatch-1.2.13.tgz", "integrity": "sha512-fpoe2T0RbHwBTBUOftAfBPaDEi06ufaUai0mE6Yn1kacc3SnTErfb/h+X94VXzI64rKFHYImXSvdwGGCmwOqCA==", "dev": true, "requires": { "arr-diff": "^4.0.0", "array-unique": "^0.3.2", "define-property": "^2.0.2", "extend-shallow": "^3.0.2", "fragment-cache": "^0.2.1", "is-windows": "^1.0.2", "kind-of": "^6.0.2", "object.pick": "^1.3.0", "regex-not": "^1.0.0", "snapdragon": "^0.8.1", "to-regex": "^3.0.1" } }, "nerf-dart": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/nerf-dart/-/nerf-dart-1.0.0.tgz", "integrity": "sha1-5tq3/r9a2Bbqgc9cYpxaDr3nLBo=", "dev": true }, "nice-try": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz", "integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==", "dev": true }, "node-emoji": { "version": "1.8.1", "resolved": "https://registry.npmjs.org/node-emoji/-/node-emoji-1.8.1.tgz", "integrity": "sha512-+ktMAh1Jwas+TnGodfCfjUbJKoANqPaJFN0z0iqh41eqD8dvguNzcitVSBSVK1pidz0AqGbLKcoVuVLRVZ/aVg==", "dev": true, "requires": { "lodash.toarray": "^4.4.0" } }, "node-fetch": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.2.0.tgz", "integrity": "sha512-OayFWziIxiHY8bCUyLX6sTpDH8Jsbp4FfYd1j1f7vZyfgkcOnAyM4oQR16f8a0s7Gl/viMGRey8eScYk4V4EZA==", "dev": true }, "normalize-package-data": { "version": "2.4.0", "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.4.0.tgz", "integrity": "sha512-9jjUFbTPfEy3R/ad/2oNbKtW9Hgovl5O1FvFWKkKblNXoN/Oou6+9+KKohPK13Yc3/TyunyWhJp6gvRNR/PPAw==", "dev": true, "requires": { "hosted-git-info": "^2.1.4", "is-builtin-module": "^1.0.0", "semver": "2 || 3 || 4 || 5", "validate-npm-package-license": "^3.0.1" } }, "normalize-url": { "version": "3.3.0", "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-3.3.0.tgz", "integrity": "sha512-U+JJi7duF1o+u2pynbp2zXDW2/PADgC30f0GsHZtRh+HOcXHnw137TrNlyxxRvWW5fjKd3bcLHPxofWuCjaeZg==", "dev": true }, "npm": { "version": "6.4.1", "resolved": "https://registry.npmjs.org/npm/-/npm-6.4.1.tgz", "integrity": "sha512-mXJL1NTVU136PtuopXCUQaNWuHlXCTp4McwlSW8S9/Aj8OEPAlSBgo8og7kJ01MjCDrkmqFQTvN5tTEhBMhXQg==", "dev": true, "requires": { "JSONStream": "^1.3.4", "abbrev": "~1.1.1", "ansicolors": "~0.3.2", "ansistyles": "~0.1.3", "aproba": "~1.2.0", "archy": "~1.0.0", "bin-links": "^1.1.2", "bluebird": "~3.5.1", "byte-size": "^4.0.3", "cacache": "^11.2.0", "call-limit": "~1.1.0", "chownr": "~1.0.1", "ci-info": "^1.4.0", "cli-columns": "^3.1.2", "cli-table3": "^0.5.0", "cmd-shim": "~2.0.2", "columnify": "~1.5.4", "config-chain": "~1.1.11", "debuglog": "*", "detect-indent": "~5.0.0", "detect-newline": "^2.1.0", "dezalgo": "~1.0.3", "editor": "~1.0.0", "figgy-pudding": "^3.4.1", "find-npm-prefix": "^1.0.2", "fs-vacuum": "~1.2.10", "fs-write-stream-atomic": "~1.0.10", "gentle-fs": "^2.0.1", "glob": "~7.1.2", "graceful-fs": "~4.1.11", "has-unicode": "~2.0.1", "hosted-git-info": "^2.7.1", "iferr": "^1.0.2", "imurmurhash": "*", "inflight": "~1.0.6", "inherits": "~2.0.3", "ini": "^1.3.5", "init-package-json": "^1.10.3", "is-cidr": "^2.0.6", "json-parse-better-errors": "^1.0.2", "lazy-property": "~1.0.0", "libcipm": "^2.0.2", "libnpmhook": "^4.0.1", "libnpx": "^10.2.0", "lock-verify": "^2.0.2", "lockfile": "^1.0.4", "lodash._baseindexof": "*", "lodash._baseuniq": "~4.6.0", "lodash._bindcallback": "*", "lodash._cacheindexof": "*", "lodash._createcache": "*", "lodash._getnative": "*", "lodash.clonedeep": "~4.5.0", "lodash.restparam": "*", "lodash.union": "~4.6.0", "lodash.uniq": "~4.5.0", "lodash.without": "~4.4.0", "lru-cache": "^4.1.3", "meant": "~1.0.1", "mississippi": "^3.0.0", "mkdirp": "~0.5.1", "move-concurrently": "^1.0.1", "node-gyp": "^3.8.0", "nopt": "~4.0.1", "normalize-package-data": "~2.4.0", "npm-audit-report": "^1.3.1", "npm-cache-filename": "~1.0.2", "npm-install-checks": "~3.0.0", "npm-lifecycle": "^2.1.0", "npm-package-arg": "^6.1.0", "npm-packlist": "^1.1.11", "npm-pick-manifest": "^2.1.0", "npm-profile": "^3.0.2", "npm-registry-client": "^8.6.0", "npm-registry-fetch": "^1.1.0", "npm-user-validate": "~1.0.0", "npmlog": "~4.1.2", "once": "~1.4.0", "opener": "^1.5.0", "osenv": "^0.1.5", "pacote": "^8.1.6", "path-is-inside": "~1.0.2", "promise-inflight": "~1.0.1", "qrcode-terminal": "^0.12.0", "query-string": "^6.1.0", "qw": "~1.0.1", "read": "~1.0.7", "read-cmd-shim": "~1.0.1", "read-installed": "~4.0.3", "read-package-json": "^2.0.13", "read-package-tree": "^5.2.1", "readable-stream": "^2.3.6", "readdir-scoped-modules": "*", "request": "^2.88.0", "retry": "^0.12.0", "rimraf": "~2.6.2", "safe-buffer": "^5.1.2", "semver": "^5.5.0", "sha": "~2.0.1", "slide": "~1.1.6", "sorted-object": "~2.0.1", "sorted-union-stream": "~2.1.3", "ssri": "^6.0.0", "stringify-package": "^1.0.0", "tar": "^4.4.6", "text-table": "~0.2.0", "tiny-relative-date": "^1.3.0", "uid-number": "0.0.6", "umask": "~1.1.0", "unique-filename": "~1.1.0", "unpipe": "~1.0.0", "update-notifier": "^2.5.0", "uuid": "^3.3.2", "validate-npm-package-license": "^3.0.4", "validate-npm-package-name": "~3.0.0", "which": "^1.3.1", "worker-farm": "^1.6.0", "write-file-atomic": "^2.3.0" }, "dependencies": { "JSONStream": { "version": "1.3.4", "bundled": true, "dev": true, "requires": { "jsonparse": "^1.2.0", "through": ">=2.2.7 <3" } }, "abbrev": { "version": "1.1.1", "bundled": true, "dev": true }, "agent-base": { "version": "4.2.0", "bundled": true, "dev": true, "requires": { "es6-promisify": "^5.0.0" } }, "agentkeepalive": { "version": "3.4.1", "bundled": true, "dev": true, "requires": { "humanize-ms": "^1.2.1" } }, "ajv": { "version": "5.5.2", "bundled": true, "dev": true, "requires": { "co": "^4.6.0", "fast-deep-equal": "^1.0.0", "fast-json-stable-stringify": "^2.0.0", "json-schema-traverse": "^0.3.0" } }, "ansi-align": { "version": "2.0.0", "bundled": true, "dev": true, "requires": { "string-width": "^2.0.0" } }, "ansi-regex": { "version": "2.1.1", "bundled": true, "dev": true }, "ansi-styles": { "version": "3.2.1", "bundled": true, "dev": true, "requires": { "color-convert": "^1.9.0" } }, "ansicolors": { "version": "0.3.2", "bundled": true, "dev": true }, "ansistyles": { "version": "0.1.3", "bundled": true, "dev": true }, "aproba": { "version": "1.2.0", "bundled": true, "dev": true }, "archy": { "version": "1.0.0", "bundled": true, "dev": true }, "are-we-there-yet": { "version": "1.1.4", "bundled": true, "dev": true, "requires": { "delegates": "^1.0.0", "readable-stream": "^2.0.6" } }, "asap": { "version": "2.0.6", "bundled": true, "dev": true }, "asn1": { "version": "0.2.4", "bundled": true, "dev": true, "requires": { "safer-buffer": "~2.1.0" } }, "assert-plus": { "version": "1.0.0", "bundled": true, "dev": true }, "asynckit": { "version": "0.4.0", "bundled": true, "dev": true }, "aws-sign2": { "version": "0.7.0", "bundled": true, "dev": true }, "aws4": { "version": "1.8.0", "bundled": true, "dev": true }, "balanced-match": { "version": "1.0.0", "bundled": true, "dev": true }, "bcrypt-pbkdf": { "version": "1.0.2", "bundled": true, "dev": true, "optional": true, "requires": { "tweetnacl": "^0.14.3" } }, "bin-links": { "version": "1.1.2", "bundled": true, "dev": true, "requires": { "bluebird": "^3.5.0", "cmd-shim": "^2.0.2", "gentle-fs": "^2.0.0", "graceful-fs": "^4.1.11", "write-file-atomic": "^2.3.0" } }, "block-stream": { "version": "0.0.9", "bundled": true, "dev": true, "requires": { "inherits": "~2.0.0" } }, "bluebird": { "version": "3.5.1", "bundled": true, "dev": true }, "boxen": { "version": "1.3.0", "bundled": true, "dev": true, "requires": { "ansi-align": "^2.0.0", "camelcase": "^4.0.0", "chalk": "^2.0.1", "cli-boxes": "^1.0.0", "string-width": "^2.0.0", "term-size": "^1.2.0", "widest-line": "^2.0.0" } }, "brace-expansion": { "version": "1.1.11", "bundled": true, "dev": true, "requires": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" } }, "buffer-from": { "version": "1.0.0", "bundled": true, "dev": true }, "builtin-modules": { "version": "1.1.1", "bundled": true, "dev": true }, "builtins": { "version": "1.0.3", "bundled": true, "dev": true }, "byline": { "version": "5.0.0", "bundled": true, "dev": true }, "byte-size": { "version": "4.0.3", "bundled": true, "dev": true }, "cacache": { "version": "11.2.0", "bundled": true, "dev": true, "requires": { "bluebird": "^3.5.1", "chownr": "^1.0.1", "figgy-pudding": "^3.1.0", "glob": "^7.1.2", "graceful-fs": "^4.1.11", "lru-cache": "^4.1.3", "mississippi": "^3.0.0", "mkdirp": "^0.5.1", "move-concurrently": "^1.0.1", "promise-inflight": "^1.0.1", "rimraf": "^2.6.2", "ssri": "^6.0.0", "unique-filename": "^1.1.0", "y18n": "^4.0.0" } }, "call-limit": { "version": "1.1.0", "bundled": true, "dev": true }, "camelcase": { "version": "4.1.0", "bundled": true, "dev": true }, "capture-stack-trace": { "version": "1.0.0", "bundled": true, "dev": true }, "caseless": { "version": "0.12.0", "bundled": true, "dev": true }, "chalk": { "version": "2.4.1", "bundled": true, "dev": true, "requires": { "ansi-styles": "^3.2.1", "escape-string-regexp": "^1.0.5", "supports-color": "^5.3.0" } }, "chownr": { "version": "1.0.1", "bundled": true, "dev": true }, "ci-info": { "version": "1.4.0", "bundled": true, "dev": true }, "cidr-regex": { "version": "2.0.9", "bundled": true, "dev": true, "requires": { "ip-regex": "^2.1.0" } }, "cli-boxes": { "version": "1.0.0", "bundled": true, "dev": true }, "cli-columns": { "version": "3.1.2", "bundled": true, "dev": true, "requires": { "string-width": "^2.0.0", "strip-ansi": "^3.0.1" } }, "cli-table3": { "version": "0.5.0", "bundled": true, "dev": true, "requires": { "colors": "^1.1.2", "object-assign": "^4.1.0", "string-width": "^2.1.1" } }, "cliui": { "version": "4.1.0", "bundled": true, "dev": true, "requires": { "string-width": "^2.1.1", "strip-ansi": "^4.0.0", "wrap-ansi": "^2.0.0" }, "dependencies": { "ansi-regex": { "version": "3.0.0", "bundled": true, "dev": true }, "strip-ansi": { "version": "4.0.0", "bundled": true, "dev": true, "requires": { "ansi-regex": "^3.0.0" } } } }, "clone": { "version": "1.0.4", "bundled": true, "dev": true }, "cmd-shim": { "version": "2.0.2", "bundled": true, "dev": true, "requires": { "graceful-fs": "^4.1.2", "mkdirp": "~0.5.0" } }, "co": { "version": "4.6.0", "bundled": true, "dev": true }, "code-point-at": { "version": "1.1.0", "bundled": true, "dev": true }, "color-convert": { "version": "1.9.1", "bundled": true, "dev": true, "requires": { "color-name": "^1.1.1" } }, "color-name": { "version": "1.1.3", "bundled": true, "dev": true }, "colors": { "version": "1.1.2", "bundled": true, "dev": true, "optional": true }, "columnify": { "version": "1.5.4", "bundled": true, "dev": true, "requires": { "strip-ansi": "^3.0.0", "wcwidth": "^1.0.0" } }, "combined-stream": { "version": "1.0.6", "bundled": true, "dev": true, "requires": { "delayed-stream": "~1.0.0" } }, "concat-map": { "version": "0.0.1", "bundled": true, "dev": true }, "concat-stream": { "version": "1.6.2", "bundled": true, "dev": true, "requires": { "buffer-from": "^1.0.0", "inherits": "^2.0.3", "readable-stream": "^2.2.2", "typedarray": "^0.0.6" } }, "config-chain": { "version": "1.1.11", "bundled": true, "dev": true, "requires": { "ini": "^1.3.4", "proto-list": "~1.2.1" } }, "configstore": { "version": "3.1.2", "bundled": true, "dev": true, "requires": { "dot-prop": "^4.1.0", "graceful-fs": "^4.1.2", "make-dir": "^1.0.0", "unique-string": "^1.0.0", "write-file-atomic": "^2.0.0", "xdg-basedir": "^3.0.0" } }, "console-control-strings": { "version": "1.1.0", "bundled": true, "dev": true }, "copy-concurrently": { "version": "1.0.5", "bundled": true, "dev": true, "requires": { "aproba": "^1.1.1", "fs-write-stream-atomic": "^1.0.8", "iferr": "^0.1.5", "mkdirp": "^0.5.1", "rimraf": "^2.5.4", "run-queue": "^1.0.0" }, "dependencies": { "iferr": { "version": "0.1.5", "bundled": true, "dev": true } } }, "core-util-is": { "version": "1.0.2", "bundled": true, "dev": true }, "create-error-class": { "version": "3.0.2", "bundled": true, "dev": true, "requires": { "capture-stack-trace": "^1.0.0" } }, "cross-spawn": { "version": "5.1.0", "bundled": true, "dev": true, "requires": { "lru-cache": "^4.0.1", "shebang-command": "^1.2.0", "which": "^1.2.9" } }, "crypto-random-string": { "version": "1.0.0", "bundled": true, "dev": true }, "cyclist": { "version": "0.2.2", "bundled": true, "dev": true }, "dashdash": { "version": "1.14.1", "bundled": true, "dev": true, "requires": { "assert-plus": "^1.0.0" } }, "debug": { "version": "3.1.0", "bundled": true, "dev": true, "requires": { "ms": "2.0.0" }, "dependencies": { "ms": { "version": "2.0.0", "bundled": true, "dev": true } } }, "debuglog": { "version": "1.0.1", "bundled": true, "dev": true }, "decamelize": { "version": "1.2.0", "bundled": true, "dev": true }, "decode-uri-component": { "version": "0.2.0", "bundled": true, "dev": true }, "deep-extend": { "version": "0.5.1", "bundled": true, "dev": true }, "defaults": { "version": "1.0.3", "bundled": true, "dev": true, "requires": { "clone": "^1.0.2" } }, "delayed-stream": { "version": "1.0.0", "bundled": true, "dev": true }, "delegates": { "version": "1.0.0", "bundled": true, "dev": true }, "detect-indent": { "version": "5.0.0", "bundled": true, "dev": true }, "detect-newline": { "version": "2.1.0", "bundled": true, "dev": true }, "dezalgo": { "version": "1.0.3", "bundled": true, "dev": true, "requires": { "asap": "^2.0.0", "wrappy": "1" } }, "dot-prop": { "version": "4.2.0", "bundled": true, "dev": true, "requires": { "is-obj": "^1.0.0" } }, "dotenv": { "version": "5.0.1", "bundled": true, "dev": true }, "duplexer3": { "version": "0.1.4", "bundled": true, "dev": true }, "duplexify": { "version": "3.6.0", "bundled": true, "dev": true, "requires": { "end-of-stream": "^1.0.0", "inherits": "^2.0.1", "readable-stream": "^2.0.0", "stream-shift": "^1.0.0" } }, "ecc-jsbn": { "version": "0.1.2", "bundled": true, "dev": true, "optional": true, "requires": { "jsbn": "~0.1.0", "safer-buffer": "^2.1.0" } }, "editor": { "version": "1.0.0", "bundled": true, "dev": true }, "encoding": { "version": "0.1.12", "bundled": true, "dev": true, "requires": { "iconv-lite": "~0.4.13" } }, "end-of-stream": { "version": "1.4.1", "bundled": true, "dev": true, "requires": { "once": "^1.4.0" } }, "err-code": { "version": "1.1.2", "bundled": true, "dev": true }, "errno": { "version": "0.1.7", "bundled": true, "dev": true, "requires": { "prr": "~1.0.1" } }, "es6-promise": { "version": "4.2.4", "bundled": true, "dev": true }, "es6-promisify": { "version": "5.0.0", "bundled": true, "dev": true, "requires": { "es6-promise": "^4.0.3" } }, "escape-string-regexp": { "version": "1.0.5", "bundled": true, "dev": true }, "execa": { "version": "0.7.0", "bundled": true, "dev": true, "requires": { "cross-spawn": "^5.0.1", "get-stream": "^3.0.0", "is-stream": "^1.1.0", "npm-run-path": "^2.0.0", "p-finally": "^1.0.0", "signal-exit": "^3.0.0", "strip-eof": "^1.0.0" } }, "extend": { "version": "3.0.2", "bundled": true, "dev": true }, "extsprintf": { "version": "1.3.0", "bundled": true, "dev": true }, "fast-deep-equal": { "version": "1.1.0", "bundled": true, "dev": true }, "fast-json-stable-stringify": { "version": "2.0.0", "bundled": true, "dev": true }, "figgy-pudding": { "version": "3.4.1", "bundled": true, "dev": true }, "find-npm-prefix": { "version": "1.0.2", "bundled": true, "dev": true }, "find-up": { "version": "2.1.0", "bundled": true, "dev": true, "requires": { "locate-path": "^2.0.0" } }, "flush-write-stream": { "version": "1.0.3", "bundled": true, "dev": true, "requires": { "inherits": "^2.0.1", "readable-stream": "^2.0.4" } }, "forever-agent": { "version": "0.6.1", "bundled": true, "dev": true }, "form-data": { "version": "2.3.2", "bundled": true, "dev": true, "requires": { "asynckit": "^0.4.0", "combined-stream": "1.0.6", "mime-types": "^2.1.12" } }, "from2": { "version": "2.3.0", "bundled": true, "dev": true, "requires": { "inherits": "^2.0.1", "readable-stream": "^2.0.0" } }, "fs-minipass": { "version": "1.2.5", "bundled": true, "dev": true, "requires": { "minipass": "^2.2.1" } }, "fs-vacuum": { "version": "1.2.10", "bundled": true, "dev": true, "requires": { "graceful-fs": "^4.1.2", "path-is-inside": "^1.0.1", "rimraf": "^2.5.2" } }, "fs-write-stream-atomic": { "version": "1.0.10", "bundled": true, "dev": true, "requires": { "graceful-fs": "^4.1.2", "iferr": "^0.1.5", "imurmurhash": "^0.1.4", "readable-stream": "1 || 2" }, "dependencies": { "iferr": { "version": "0.1.5", "bundled": true, "dev": true } } }, "fs.realpath": { "version": "1.0.0", "bundled": true, "dev": true }, "fstream": { "version": "1.0.11", "bundled": true, "dev": true, "requires": { "graceful-fs": "^4.1.2", "inherits": "~2.0.0", "mkdirp": ">=0.5 0", "rimraf": "2" } }, "gauge": { "version": "2.7.4", "bundled": true, "dev": true, "requires": { "aproba": "^1.0.3", "console-control-strings": "^1.0.0", "has-unicode": "^2.0.0", "object-assign": "^4.1.0", "signal-exit": "^3.0.0", "string-width": "^1.0.1", "strip-ansi": "^3.0.1", "wide-align": "^1.1.0" }, "dependencies": { "string-width": { "version": "1.0.2", "bundled": true, "dev": true, "requires": { "code-point-at": "^1.0.0", "is-fullwidth-code-point": "^1.0.0", "strip-ansi": "^3.0.0" } } } }, "genfun": { "version": "4.0.1", "bundled": true, "dev": true }, "gentle-fs": { "version": "2.0.1", "bundled": true, "dev": true, "requires": { "aproba": "^1.1.2", "fs-vacuum": "^1.2.10", "graceful-fs": "^4.1.11", "iferr": "^0.1.5", "mkdirp": "^0.5.1", "path-is-inside": "^1.0.2", "read-cmd-shim": "^1.0.1", "slide": "^1.1.6" }, "dependencies": { "iferr": { "version": "0.1.5", "bundled": true, "dev": true } } }, "get-caller-file": { "version": "1.0.2", "bundled": true, "dev": true }, "get-stream": { "version": "3.0.0", "bundled": true, "dev": true }, "getpass": { "version": "0.1.7", "bundled": true, "dev": true, "requires": { "assert-plus": "^1.0.0" } }, "glob": { "version": "7.1.2", "bundled": true, "dev": true, "requires": { "fs.realpath": "^1.0.0", "inflight": "^1.0.4", "inherits": "2", "minimatch": "^3.0.4", "once": "^1.3.0", "path-is-absolute": "^1.0.0" } }, "global-dirs": { "version": "0.1.1", "bundled": true, "dev": true, "requires": { "ini": "^1.3.4" } }, "got": { "version": "6.7.1", "bundled": true, "dev": true, "requires": { "create-error-class": "^3.0.0", "duplexer3": "^0.1.4", "get-stream": "^3.0.0", "is-redirect": "^1.0.0", "is-retry-allowed": "^1.0.0", "is-stream": "^1.0.0", "lowercase-keys": "^1.0.0", "safe-buffer": "^5.0.1", "timed-out": "^4.0.0", "unzip-response": "^2.0.1", "url-parse-lax": "^1.0.0" } }, "graceful-fs": { "version": "4.1.11", "bundled": true, "dev": true }, "har-schema": { "version": "2.0.0", "bundled": true, "dev": true }, "har-validator": { "version": "5.1.0", "bundled": true, "dev": true, "requires": { "ajv": "^5.3.0", "har-schema": "^2.0.0" } }, "has-flag": { "version": "3.0.0", "bundled": true, "dev": true }, "has-unicode": { "version": "2.0.1", "bundled": true, "dev": true }, "hosted-git-info": { "version": "2.7.1", "bundled": true, "dev": true }, "http-cache-semantics": { "version": "3.8.1", "bundled": true, "dev": true }, "http-proxy-agent": { "version": "2.1.0", "bundled": true, "dev": true, "requires": { "agent-base": "4", "debug": "3.1.0" } }, "http-signature": { "version": "1.2.0", "bundled": true, "dev": true, "requires": { "assert-plus": "^1.0.0", "jsprim": "^1.2.2", "sshpk": "^1.7.0" } }, "https-proxy-agent": { "version": "2.2.1", "bundled": true, "dev": true, "requires": { "agent-base": "^4.1.0", "debug": "^3.1.0" } }, "humanize-ms": { "version": "1.2.1", "bundled": true, "dev": true, "requires": { "ms": "^2.0.0" } }, "iconv-lite": { "version": "0.4.23", "bundled": true, "dev": true, "requires": { "safer-buffer": ">= 2.1.2 < 3" } }, "iferr": { "version": "1.0.2", "bundled": true, "dev": true }, "ignore-walk": { "version": "3.0.1", "bundled": true, "dev": true, "requires": { "minimatch": "^3.0.4" } }, "import-lazy": { "version": "2.1.0", "bundled": true, "dev": true }, "imurmurhash": { "version": "0.1.4", "bundled": true, "dev": true }, "inflight": { "version": "1.0.6", "bundled": true, "dev": true, "requires": { "once": "^1.3.0", "wrappy": "1" } }, "inherits": { "version": "2.0.3", "bundled": true, "dev": true }, "ini": { "version": "1.3.5", "bundled": true, "dev": true }, "init-package-json": { "version": "1.10.3", "bundled": true, "dev": true, "requires": { "glob": "^7.1.1", "npm-package-arg": "^4.0.0 || ^5.0.0 || ^6.0.0", "promzard": "^0.3.0", "read": "~1.0.1", "read-package-json": "1 || 2", "semver": "2.x || 3.x || 4 || 5", "validate-npm-package-license": "^3.0.1", "validate-npm-package-name": "^3.0.0" } }, "invert-kv": { "version": "1.0.0", "bundled": true, "dev": true }, "ip": { "version": "1.1.5", "bundled": true, "dev": true }, "ip-regex": { "version": "2.1.0", "bundled": true, "dev": true }, "is-builtin-module": { "version": "1.0.0", "bundled": true, "dev": true, "requires": { "builtin-modules": "^1.0.0" } }, "is-ci": { "version": "1.1.0", "bundled": true, "dev": true, "requires": { "ci-info": "^1.0.0" } }, "is-cidr": { "version": "2.0.6", "bundled": true, "dev": true, "requires": { "cidr-regex": "^2.0.8" } }, "is-fullwidth-code-point": { "version": "1.0.0", "bundled": true, "dev": true, "requires": { "number-is-nan": "^1.0.0" } }, "is-installed-globally": { "version": "0.1.0", "bundled": true, "dev": true, "requires": { "global-dirs": "^0.1.0", "is-path-inside": "^1.0.0" } }, "is-npm": { "version": "1.0.0", "bundled": true, "dev": true }, "is-obj": { "version": "1.0.1", "bundled": true, "dev": true }, "is-path-inside": { "version": "1.0.1", "bundled": true, "dev": true, "requires": { "path-is-inside": "^1.0.1" } }, "is-redirect": { "version": "1.0.0", "bundled": true, "dev": true }, "is-retry-allowed": { "version": "1.1.0", "bundled": true, "dev": true }, "is-stream": { "version": "1.1.0", "bundled": true, "dev": true }, "is-typedarray": { "version": "1.0.0", "bundled": true, "dev": true }, "isarray": { "version": "1.0.0", "bundled": true, "dev": true }, "isexe": { "version": "2.0.0", "bundled": true, "dev": true }, "isstream": { "version": "0.1.2", "bundled": true, "dev": true }, "jsbn": { "version": "0.1.1", "bundled": true, "dev": true, "optional": true }, "json-parse-better-errors": { "version": "1.0.2", "bundled": true, "dev": true }, "json-schema": { "version": "0.2.3", "bundled": true, "dev": true }, "json-schema-traverse": { "version": "0.3.1", "bundled": true, "dev": true }, "json-stringify-safe": { "version": "5.0.1", "bundled": true, "dev": true }, "jsonparse": { "version": "1.3.1", "bundled": true, "dev": true }, "jsprim": { "version": "1.4.1", "bundled": true, "dev": true, "requires": { "assert-plus": "1.0.0", "extsprintf": "1.3.0", "json-schema": "0.2.3", "verror": "1.10.0" } }, "latest-version": { "version": "3.1.0", "bundled": true, "dev": true, "requires": { "package-json": "^4.0.0" } }, "lazy-property": { "version": "1.0.0", "bundled": true, "dev": true }, "lcid": { "version": "1.0.0", "bundled": true, "dev": true, "requires": { "invert-kv": "^1.0.0" } }, "libcipm": { "version": "2.0.2", "bundled": true, "dev": true, "requires": { "bin-links": "^1.1.2", "bluebird": "^3.5.1", "find-npm-prefix": "^1.0.2", "graceful-fs": "^4.1.11", "lock-verify": "^2.0.2", "mkdirp": "^0.5.1", "npm-lifecycle": "^2.0.3", "npm-logical-tree": "^1.2.1", "npm-package-arg": "^6.1.0", "pacote": "^8.1.6", "protoduck": "^5.0.0", "read-package-json": "^2.0.13", "rimraf": "^2.6.2", "worker-farm": "^1.6.0" } }, "libnpmhook": { "version": "4.0.1", "bundled": true, "dev": true, "requires": { "figgy-pudding": "^3.1.0", "npm-registry-fetch": "^3.0.0" }, "dependencies": { "npm-registry-fetch": { "version": "3.1.1", "bundled": true, "dev": true, "requires": { "bluebird": "^3.5.1", "figgy-pudding": "^3.1.0", "lru-cache": "^4.1.2", "make-fetch-happen": "^4.0.0", "npm-package-arg": "^6.0.0" } } } }, "libnpx": { "version": "10.2.0", "bundled": true, "dev": true, "requires": { "dotenv": "^5.0.1", "npm-package-arg": "^6.0.0", "rimraf": "^2.6.2", "safe-buffer": "^5.1.0", "update-notifier": "^2.3.0", "which": "^1.3.0", "y18n": "^4.0.0", "yargs": "^11.0.0" } }, "locate-path": { "version": "2.0.0", "bundled": true, "dev": true, "requires": { "p-locate": "^2.0.0", "path-exists": "^3.0.0" } }, "lock-verify": { "version": "2.0.2", "bundled": true, "dev": true, "requires": { "npm-package-arg": "^5.1.2 || 6", "semver": "^5.4.1" } }, "lockfile": { "version": "1.0.4", "bundled": true, "dev": true, "requires": { "signal-exit": "^3.0.2" } }, "lodash._baseindexof": { "version": "3.1.0", "bundled": true, "dev": true }, "lodash._baseuniq": { "version": "4.6.0", "bundled": true, "dev": true, "requires": { "lodash._createset": "~4.0.0", "lodash._root": "~3.0.0" } }, "lodash._bindcallback": { "version": "3.0.1", "bundled": true, "dev": true }, "lodash._cacheindexof": { "version": "3.0.2", "bundled": true, "dev": true }, "lodash._createcache": { "version": "3.1.2", "bundled": true, "dev": true, "requires": { "lodash._getnative": "^3.0.0" } }, "lodash._createset": { "version": "4.0.3", "bundled": true, "dev": true }, "lodash._getnative": { "version": "3.9.1", "bundled": true, "dev": true }, "lodash._root": { "version": "3.0.1", "bundled": true, "dev": true }, "lodash.clonedeep": { "version": "4.5.0", "bundled": true, "dev": true }, "lodash.restparam": { "version": "3.6.1", "bundled": true, "dev": true }, "lodash.union": { "version": "4.6.0", "bundled": true, "dev": true }, "lodash.uniq": { "version": "4.5.0", "bundled": true, "dev": true }, "lodash.without": { "version": "4.4.0", "bundled": true, "dev": true }, "lowercase-keys": { "version": "1.0.1", "bundled": true, "dev": true }, "lru-cache": { "version": "4.1.3", "bundled": true, "dev": true, "requires": { "pseudomap": "^1.0.2", "yallist": "^2.1.2" } }, "make-dir": { "version": "1.3.0", "bundled": true, "dev": true, "requires": { "pify": "^3.0.0" } }, "make-fetch-happen": { "version": "4.0.1", "bundled": true, "dev": true, "requires": { "agentkeepalive": "^3.4.1", "cacache": "^11.0.1", "http-cache-semantics": "^3.8.1", "http-proxy-agent": "^2.1.0", "https-proxy-agent": "^2.2.1", "lru-cache": "^4.1.2", "mississippi": "^3.0.0", "node-fetch-npm": "^2.0.2", "promise-retry": "^1.1.1", "socks-proxy-agent": "^4.0.0", "ssri": "^6.0.0" } }, "meant": { "version": "1.0.1", "bundled": true, "dev": true }, "mem": { "version": "1.1.0", "bundled": true, "dev": true, "requires": { "mimic-fn": "^1.0.0" } }, "mime-db": { "version": "1.35.0", "bundled": true, "dev": true }, "mime-types": { "version": "2.1.19", "bundled": true, "dev": true, "requires": { "mime-db": "~1.35.0" } }, "mimic-fn": { "version": "1.2.0", "bundled": true, "dev": true }, "minimatch": { "version": "3.0.4", "bundled": true, "dev": true, "requires": { "brace-expansion": "^1.1.7" } }, "minimist": { "version": "0.0.8", "bundled": true, "dev": true }, "minipass": { "version": "2.3.3", "bundled": true, "dev": true, "requires": { "safe-buffer": "^5.1.2", "yallist": "^3.0.0" }, "dependencies": { "yallist": { "version": "3.0.2", "bundled": true, "dev": true } } }, "minizlib": { "version": "1.1.0", "bundled": true, "dev": true, "requires": { "minipass": "^2.2.1" } }, "mississippi": { "version": "3.0.0", "bundled": true, "dev": true, "requires": { "concat-stream": "^1.5.0", "duplexify": "^3.4.2", "end-of-stream": "^1.1.0", "flush-write-stream": "^1.0.0", "from2": "^2.1.0", "parallel-transform": "^1.1.0", "pump": "^3.0.0", "pumpify": "^1.3.3", "stream-each": "^1.1.0", "through2": "^2.0.0" } }, "mkdirp": { "version": "0.5.1", "bundled": true, "dev": true, "requires": { "minimist": "0.0.8" } }, "move-concurrently": { "version": "1.0.1", "bundled": true, "dev": true, "requires": { "aproba": "^1.1.1", "copy-concurrently": "^1.0.0", "fs-write-stream-atomic": "^1.0.8", "mkdirp": "^0.5.1", "rimraf": "^2.5.4", "run-queue": "^1.0.3" } }, "ms": { "version": "2.1.1", "bundled": true, "dev": true }, "mute-stream": { "version": "0.0.7", "bundled": true, "dev": true }, "node-fetch-npm": { "version": "2.0.2", "bundled": true, "dev": true, "requires": { "encoding": "^0.1.11", "json-parse-better-errors": "^1.0.0", "safe-buffer": "^5.1.1" } }, "node-gyp": { "version": "3.8.0", "bundled": true, "dev": true, "requires": { "fstream": "^1.0.0", "glob": "^7.0.3", "graceful-fs": "^4.1.2", "mkdirp": "^0.5.0", "nopt": "2 || 3", "npmlog": "0 || 1 || 2 || 3 || 4", "osenv": "0", "request": "^2.87.0", "rimraf": "2", "semver": "~5.3.0", "tar": "^2.0.0", "which": "1" }, "dependencies": { "nopt": { "version": "3.0.6", "bundled": true, "dev": true, "requires": { "abbrev": "1" } }, "semver": { "version": "5.3.0", "bundled": true, "dev": true }, "tar": { "version": "2.2.1", "bundled": true, "dev": true, "requires": { "block-stream": "*", "fstream": "^1.0.2", "inherits": "2" } } } }, "nopt": { "version": "4.0.1", "bundled": true, "dev": true, "requires": { "abbrev": "1", "osenv": "^0.1.4" } }, "normalize-package-data": { "version": "2.4.0", "bundled": true, "dev": true, "requires": { "hosted-git-info": "^2.1.4", "is-builtin-module": "^1.0.0", "semver": "2 || 3 || 4 || 5", "validate-npm-package-license": "^3.0.1" } }, "npm-audit-report": { "version": "1.3.1", "bundled": true, "dev": true, "requires": { "cli-table3": "^0.5.0", "console-control-strings": "^1.1.0" } }, "npm-bundled": { "version": "1.0.5", "bundled": true, "dev": true }, "npm-cache-filename": { "version": "1.0.2", "bundled": true, "dev": true }, "npm-install-checks": { "version": "3.0.0", "bundled": true, "dev": true, "requires": { "semver": "^2.3.0 || 3.x || 4 || 5" } }, "npm-lifecycle": { "version": "2.1.0", "bundled": true, "dev": true, "requires": { "byline": "^5.0.0", "graceful-fs": "^4.1.11", "node-gyp": "^3.8.0", "resolve-from": "^4.0.0", "slide": "^1.1.6", "uid-number": "0.0.6", "umask": "^1.1.0", "which": "^1.3.1" } }, "npm-logical-tree": { "version": "1.2.1", "bundled": true, "dev": true }, "npm-package-arg": { "version": "6.1.0", "bundled": true, "dev": true, "requires": { "hosted-git-info": "^2.6.0", "osenv": "^0.1.5", "semver": "^5.5.0", "validate-npm-package-name": "^3.0.0" } }, "npm-packlist": { "version": "1.1.11", "bundled": true, "dev": true, "requires": { "ignore-walk": "^3.0.1", "npm-bundled": "^1.0.1" } }, "npm-pick-manifest": { "version": "2.1.0", "bundled": true, "dev": true, "requires": { "npm-package-arg": "^6.0.0", "semver": "^5.4.1" } }, "npm-profile": { "version": "3.0.2", "bundled": true, "dev": true, "requires": { "aproba": "^1.1.2 || 2", "make-fetch-happen": "^2.5.0 || 3 || 4" } }, "npm-registry-client": { "version": "8.6.0", "bundled": true, "dev": true, "requires": { "concat-stream": "^1.5.2", "graceful-fs": "^4.1.6", "normalize-package-data": "~1.0.1 || ^2.0.0", "npm-package-arg": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0", "npmlog": "2 || ^3.1.0 || ^4.0.0", "once": "^1.3.3", "request": "^2.74.0", "retry": "^0.10.0", "safe-buffer": "^5.1.1", "semver": "2 >=2.2.1 || 3.x || 4 || 5", "slide": "^1.1.3", "ssri": "^5.2.4" }, "dependencies": { "retry": { "version": "0.10.1", "bundled": true, "dev": true }, "ssri": { "version": "5.3.0", "bundled": true, "dev": true, "requires": { "safe-buffer": "^5.1.1" } } } }, "npm-registry-fetch": { "version": "1.1.0", "bundled": true, "dev": true, "requires": { "bluebird": "^3.5.1", "figgy-pudding": "^2.0.1", "lru-cache": "^4.1.2", "make-fetch-happen": "^3.0.0", "npm-package-arg": "^6.0.0", "safe-buffer": "^5.1.1" }, "dependencies": { "cacache": { "version": "10.0.4", "bundled": true, "dev": true, "requires": { "bluebird": "^3.5.1", "chownr": "^1.0.1", "glob": "^7.1.2", "graceful-fs": "^4.1.11", "lru-cache": "^4.1.1", "mississippi": "^2.0.0", "mkdirp": "^0.5.1", "move-concurrently": "^1.0.1", "promise-inflight": "^1.0.1", "rimraf": "^2.6.2", "ssri": "^5.2.4", "unique-filename": "^1.1.0", "y18n": "^4.0.0" }, "dependencies": { "mississippi": { "version": "2.0.0", "bundled": true, "dev": true, "requires": { "concat-stream": "^1.5.0", "duplexify": "^3.4.2", "end-of-stream": "^1.1.0", "flush-write-stream": "^1.0.0", "from2": "^2.1.0", "parallel-transform": "^1.1.0", "pump": "^2.0.1", "pumpify": "^1.3.3", "stream-each": "^1.1.0", "through2": "^2.0.0" } } } }, "figgy-pudding": { "version": "2.0.1", "bundled": true, "dev": true }, "make-fetch-happen": { "version": "3.0.0", "bundled": true, "dev": true, "requires": { "agentkeepalive": "^3.4.1", "cacache": "^10.0.4", "http-cache-semantics": "^3.8.1", "http-proxy-agent": "^2.1.0", "https-proxy-agent": "^2.2.0", "lru-cache": "^4.1.2", "mississippi": "^3.0.0", "node-fetch-npm": "^2.0.2", "promise-retry": "^1.1.1", "socks-proxy-agent": "^3.0.1", "ssri": "^5.2.4" } }, "pump": { "version": "2.0.1", "bundled": true, "dev": true, "requires": { "end-of-stream": "^1.1.0", "once": "^1.3.1" } }, "smart-buffer": { "version": "1.1.15", "bundled": true, "dev": true }, "socks": { "version": "1.1.10", "bundled": true, "dev": true, "requires": { "ip": "^1.1.4", "smart-buffer": "^1.0.13" } }, "socks-proxy-agent": { "version": "3.0.1", "bundled": true, "dev": true, "requires": { "agent-base": "^4.1.0", "socks": "^1.1.10" } }, "ssri": { "version": "5.3.0", "bundled": true, "dev": true, "requires": { "safe-buffer": "^5.1.1" } } } }, "npm-run-path": { "version": "2.0.2", "bundled": true, "dev": true, "requires": { "path-key": "^2.0.0" } }, "npm-user-validate": { "version": "1.0.0", "bundled": true, "dev": true }, "npmlog": { "version": "4.1.2", "bundled": true, "dev": true, "requires": { "are-we-there-yet": "~1.1.2", "console-control-strings": "~1.1.0", "gauge": "~2.7.3", "set-blocking": "~2.0.0" } }, "number-is-nan": { "version": "1.0.1", "bundled": true, "dev": true }, "oauth-sign": { "version": "0.9.0", "bundled": true, "dev": true }, "object-assign": { "version": "4.1.1", "bundled": true, "dev": true }, "once": { "version": "1.4.0", "bundled": true, "dev": true, "requires": { "wrappy": "1" } }, "opener": { "version": "1.5.0", "bundled": true, "dev": true }, "os-homedir": { "version": "1.0.2", "bundled": true, "dev": true }, "os-locale": { "version": "2.1.0", "bundled": true, "dev": true, "requires": { "execa": "^0.7.0", "lcid": "^1.0.0", "mem": "^1.1.0" } }, "os-tmpdir": { "version": "1.0.2", "bundled": true, "dev": true }, "osenv": { "version": "0.1.5", "bundled": true, "dev": true, "requires": { "os-homedir": "^1.0.0", "os-tmpdir": "^1.0.0" } }, "p-finally": { "version": "1.0.0", "bundled": true, "dev": true }, "p-limit": { "version": "1.2.0", "bundled": true, "dev": true, "requires": { "p-try": "^1.0.0" } }, "p-locate": { "version": "2.0.0", "bundled": true, "dev": true, "requires": { "p-limit": "^1.1.0" } }, "p-try": { "version": "1.0.0", "bundled": true, "dev": true }, "package-json": { "version": "4.0.1", "bundled": true, "dev": true, "requires": { "got": "^6.7.1", "registry-auth-token": "^3.0.1", "registry-url": "^3.0.3", "semver": "^5.1.0" } }, "pacote": { "version": "8.1.6", "bundled": true, "dev": true, "requires": { "bluebird": "^3.5.1", "cacache": "^11.0.2", "get-stream": "^3.0.0", "glob": "^7.1.2", "lru-cache": "^4.1.3", "make-fetch-happen": "^4.0.1", "minimatch": "^3.0.4", "minipass": "^2.3.3", "mississippi": "^3.0.0", "mkdirp": "^0.5.1", "normalize-package-data": "^2.4.0", "npm-package-arg": "^6.1.0", "npm-packlist": "^1.1.10", "npm-pick-manifest": "^2.1.0", "osenv": "^0.1.5", "promise-inflight": "^1.0.1", "promise-retry": "^1.1.1", "protoduck": "^5.0.0", "rimraf": "^2.6.2", "safe-buffer": "^5.1.2", "semver": "^5.5.0", "ssri": "^6.0.0", "tar": "^4.4.3", "unique-filename": "^1.1.0", "which": "^1.3.0" } }, "parallel-transform": { "version": "1.1.0", "bundled": true, "dev": true, "requires": { "cyclist": "~0.2.2", "inherits": "^2.0.3", "readable-stream": "^2.1.5" } }, "path-exists": { "version": "3.0.0", "bundled": true, "dev": true }, "path-is-absolute": { "version": "1.0.1", "bundled": true, "dev": true }, "path-is-inside": { "version": "1.0.2", "bundled": true, "dev": true }, "path-key": { "version": "2.0.1", "bundled": true, "dev": true }, "performance-now": { "version": "2.1.0", "bundled": true, "dev": true }, "pify": { "version": "3.0.0", "bundled": true, "dev": true }, "prepend-http": { "version": "1.0.4", "bundled": true, "dev": true }, "process-nextick-args": { "version": "2.0.0", "bundled": true, "dev": true }, "promise-inflight": { "version": "1.0.1", "bundled": true, "dev": true }, "promise-retry": { "version": "1.1.1", "bundled": true, "dev": true, "requires": { "err-code": "^1.0.0", "retry": "^0.10.0" }, "dependencies": { "retry": { "version": "0.10.1", "bundled": true, "dev": true } } }, "promzard": { "version": "0.3.0", "bundled": true, "dev": true, "requires": { "read": "1" } }, "proto-list": { "version": "1.2.4", "bundled": true, "dev": true }, "protoduck": { "version": "5.0.0", "bundled": true, "dev": true, "requires": { "genfun": "^4.0.1" } }, "prr": { "version": "1.0.1", "bundled": true, "dev": true }, "pseudomap": { "version": "1.0.2", "bundled": true, "dev": true }, "psl": { "version": "1.1.29", "bundled": true, "dev": true }, "pump": { "version": "3.0.0", "bundled": true, "dev": true, "requires": { "end-of-stream": "^1.1.0", "once": "^1.3.1" } }, "pumpify": { "version": "1.5.1", "bundled": true, "dev": true, "requires": { "duplexify": "^3.6.0", "inherits": "^2.0.3", "pump": "^2.0.0" }, "dependencies": { "pump": { "version": "2.0.1", "bundled": true, "dev": true, "requires": { "end-of-stream": "^1.1.0", "once": "^1.3.1" } } } }, "punycode": { "version": "1.4.1", "bundled": true, "dev": true }, "qrcode-terminal": { "version": "0.12.0", "bundled": true, "dev": true }, "qs": { "version": "6.5.2", "bundled": true, "dev": true }, "query-string": { "version": "6.1.0", "bundled": true, "dev": true, "requires": { "decode-uri-component": "^0.2.0", "strict-uri-encode": "^2.0.0" } }, "qw": { "version": "1.0.1", "bundled": true, "dev": true }, "rc": { "version": "1.2.7", "bundled": true, "dev": true, "requires": { "deep-extend": "^0.5.1", "ini": "~1.3.0", "minimist": "^1.2.0", "strip-json-comments": "~2.0.1" }, "dependencies": { "minimist": { "version": "1.2.0", "bundled": true, "dev": true } } }, "read": { "version": "1.0.7", "bundled": true, "dev": true, "requires": { "mute-stream": "~0.0.4" } }, "read-cmd-shim": { "version": "1.0.1", "bundled": true, "dev": true, "requires": { "graceful-fs": "^4.1.2" } }, "read-installed": { "version": "4.0.3", "bundled": true, "dev": true, "requires": { "debuglog": "^1.0.1", "graceful-fs": "^4.1.2", "read-package-json": "^2.0.0", "readdir-scoped-modules": "^1.0.0", "semver": "2 || 3 || 4 || 5", "slide": "~1.1.3", "util-extend": "^1.0.1" } }, "read-package-json": { "version": "2.0.13", "bundled": true, "dev": true, "requires": { "glob": "^7.1.1", "graceful-fs": "^4.1.2", "json-parse-better-errors": "^1.0.1", "normalize-package-data": "^2.0.0", "slash": "^1.0.0" } }, "read-package-tree": { "version": "5.2.1", "bundled": true, "dev": true, "requires": { "debuglog": "^1.0.1", "dezalgo": "^1.0.0", "once": "^1.3.0", "read-package-json": "^2.0.0", "readdir-scoped-modules": "^1.0.0" } }, "readable-stream": { "version": "2.3.6", "bundled": true, "dev": true, "requires": { "core-util-is": "~1.0.0", "inherits": "~2.0.3", "isarray": "~1.0.0", "process-nextick-args": "~2.0.0", "safe-buffer": "~5.1.1", "string_decoder": "~1.1.1", "util-deprecate": "~1.0.1" } }, "readdir-scoped-modules": { "version": "1.0.2", "bundled": true, "dev": true, "requires": { "debuglog": "^1.0.1", "dezalgo": "^1.0.0", "graceful-fs": "^4.1.2", "once": "^1.3.0" } }, "registry-auth-token": { "version": "3.3.2", "bundled": true, "dev": true, "requires": { "rc": "^1.1.6", "safe-buffer": "^5.0.1" } }, "registry-url": { "version": "3.1.0", "bundled": true, "dev": true, "requires": { "rc": "^1.0.1" } }, "request": { "version": "2.88.0", "bundled": true, "dev": true, "requires": { "aws-sign2": "~0.7.0", "aws4": "^1.8.0", "caseless": "~0.12.0", "combined-stream": "~1.0.6", "extend": "~3.0.2", "forever-agent": "~0.6.1", "form-data": "~2.3.2", "har-validator": "~5.1.0", "http-signature": "~1.2.0", "is-typedarray": "~1.0.0", "isstream": "~0.1.2", "json-stringify-safe": "~5.0.1", "mime-types": "~2.1.19", "oauth-sign": "~0.9.0", "performance-now": "^2.1.0", "qs": "~6.5.2", "safe-buffer": "^5.1.2", "tough-cookie": "~2.4.3", "tunnel-agent": "^0.6.0", "uuid": "^3.3.2" } }, "require-directory": { "version": "2.1.1", "bundled": true, "dev": true }, "require-main-filename": { "version": "1.0.1", "bundled": true, "dev": true }, "resolve-from": { "version": "4.0.0", "bundled": true, "dev": true }, "retry": { "version": "0.12.0", "bundled": true, "dev": true }, "rimraf": { "version": "2.6.2", "bundled": true, "dev": true, "requires": { "glob": "^7.0.5" } }, "run-queue": { "version": "1.0.3", "bundled": true, "dev": true, "requires": { "aproba": "^1.1.1" } }, "safe-buffer": { "version": "5.1.2", "bundled": true, "dev": true }, "safer-buffer": { "version": "2.1.2", "bundled": true, "dev": true }, "semver": { "version": "5.5.0", "bundled": true, "dev": true }, "semver-diff": { "version": "2.1.0", "bundled": true, "dev": true, "requires": { "semver": "^5.0.3" } }, "set-blocking": { "version": "2.0.0", "bundled": true, "dev": true }, "sha": { "version": "2.0.1", "bundled": true, "dev": true, "requires": { "graceful-fs": "^4.1.2", "readable-stream": "^2.0.2" } }, "shebang-command": { "version": "1.2.0", "bundled": true, "dev": true, "requires": { "shebang-regex": "^1.0.0" } }, "shebang-regex": { "version": "1.0.0", "bundled": true, "dev": true }, "signal-exit": { "version": "3.0.2", "bundled": true, "dev": true }, "slash": { "version": "1.0.0", "bundled": true, "dev": true }, "slide": { "version": "1.1.6", "bundled": true, "dev": true }, "smart-buffer": { "version": "4.0.1", "bundled": true, "dev": true }, "socks": { "version": "2.2.0", "bundled": true, "dev": true, "requires": { "ip": "^1.1.5", "smart-buffer": "^4.0.1" } }, "socks-proxy-agent": { "version": "4.0.1", "bundled": true, "dev": true, "requires": { "agent-base": "~4.2.0", "socks": "~2.2.0" } }, "sorted-object": { "version": "2.0.1", "bundled": true, "dev": true }, "sorted-union-stream": { "version": "2.1.3", "bundled": true, "dev": true, "requires": { "from2": "^1.3.0", "stream-iterate": "^1.1.0" }, "dependencies": { "from2": { "version": "1.3.0", "bundled": true, "dev": true, "requires": { "inherits": "~2.0.1", "readable-stream": "~1.1.10" } }, "isarray": { "version": "0.0.1", "bundled": true, "dev": true }, "readable-stream": { "version": "1.1.14", "bundled": true, "dev": true, "requires": { "core-util-is": "~1.0.0", "inherits": "~2.0.1", "isarray": "0.0.1", "string_decoder": "~0.10.x" } }, "string_decoder": { "version": "0.10.31", "bundled": true, "dev": true } } }, "spdx-correct": { "version": "3.0.0", "bundled": true, "dev": true, "requires": { "spdx-expression-parse": "^3.0.0", "spdx-license-ids": "^3.0.0" } }, "spdx-exceptions": { "version": "2.1.0", "bundled": true, "dev": true }, "spdx-expression-parse": { "version": "3.0.0", "bundled": true, "dev": true, "requires": { "spdx-exceptions": "^2.1.0", "spdx-license-ids": "^3.0.0" } }, "spdx-license-ids": { "version": "3.0.0", "bundled": true, "dev": true }, "sshpk": { "version": "1.14.2", "bundled": true, "dev": true, "requires": { "asn1": "~0.2.3", "assert-plus": "^1.0.0", "bcrypt-pbkdf": "^1.0.0", "dashdash": "^1.12.0", "ecc-jsbn": "~0.1.1", "getpass": "^0.1.1", "jsbn": "~0.1.0", "safer-buffer": "^2.0.2", "tweetnacl": "~0.14.0" } }, "ssri": { "version": "6.0.0", "bundled": true, "dev": true }, "stream-each": { "version": "1.2.2", "bundled": true, "dev": true, "requires": { "end-of-stream": "^1.1.0", "stream-shift": "^1.0.0" } }, "stream-iterate": { "version": "1.2.0", "bundled": true, "dev": true, "requires": { "readable-stream": "^2.1.5", "stream-shift": "^1.0.0" } }, "stream-shift": { "version": "1.0.0", "bundled": true, "dev": true }, "strict-uri-encode": { "version": "2.0.0", "bundled": true, "dev": true }, "string-width": { "version": "2.1.1", "bundled": true, "dev": true, "requires": { "is-fullwidth-code-point": "^2.0.0", "strip-ansi": "^4.0.0" }, "dependencies": { "ansi-regex": { "version": "3.0.0", "bundled": true, "dev": true }, "is-fullwidth-code-point": { "version": "2.0.0", "bundled": true, "dev": true }, "strip-ansi": { "version": "4.0.0", "bundled": true, "dev": true, "requires": { "ansi-regex": "^3.0.0" } } } }, "string_decoder": { "version": "1.1.1", "bundled": true, "dev": true, "requires": { "safe-buffer": "~5.1.0" } }, "stringify-package": { "version": "1.0.0", "bundled": true, "dev": true }, "strip-ansi": { "version": "3.0.1", "bundled": true, "dev": true, "requires": { "ansi-regex": "^2.0.0" } }, "strip-eof": { "version": "1.0.0", "bundled": true, "dev": true }, "strip-json-comments": { "version": "2.0.1", "bundled": true, "dev": true }, "supports-color": { "version": "5.4.0", "bundled": true, "dev": true, "requires": { "has-flag": "^3.0.0" } }, "tar": { "version": "4.4.6", "bundled": true, "dev": true, "requires": { "chownr": "^1.0.1", "fs-minipass": "^1.2.5", "minipass": "^2.3.3", "minizlib": "^1.1.0", "mkdirp": "^0.5.0", "safe-buffer": "^5.1.2", "yallist": "^3.0.2" }, "dependencies": { "yallist": { "version": "3.0.2", "bundled": true, "dev": true } } }, "term-size": { "version": "1.2.0", "bundled": true, "dev": true, "requires": { "execa": "^0.7.0" } }, "text-table": { "version": "0.2.0", "bundled": true, "dev": true }, "through": { "version": "2.3.8", "bundled": true, "dev": true }, "through2": { "version": "2.0.3", "bundled": true, "dev": true, "requires": { "readable-stream": "^2.1.5", "xtend": "~4.0.1" } }, "timed-out": { "version": "4.0.1", "bundled": true, "dev": true }, "tiny-relative-date": { "version": "1.3.0", "bundled": true, "dev": true }, "tough-cookie": { "version": "2.4.3", "bundled": true, "dev": true, "requires": { "psl": "^1.1.24", "punycode": "^1.4.1" } }, "tunnel-agent": { "version": "0.6.0", "bundled": true, "dev": true, "requires": { "safe-buffer": "^5.0.1" } }, "tweetnacl": { "version": "0.14.5", "bundled": true, "dev": true, "optional": true }, "typedarray": { "version": "0.0.6", "bundled": true, "dev": true }, "uid-number": { "version": "0.0.6", "bundled": true, "dev": true }, "umask": { "version": "1.1.0", "bundled": true, "dev": true }, "unique-filename": { "version": "1.1.0", "bundled": true, "dev": true, "requires": { "unique-slug": "^2.0.0" } }, "unique-slug": { "version": "2.0.0", "bundled": true, "dev": true, "requires": { "imurmurhash": "^0.1.4" } }, "unique-string": { "version": "1.0.0", "bundled": true, "dev": true, "requires": { "crypto-random-string": "^1.0.0" } }, "unpipe": { "version": "1.0.0", "bundled": true, "dev": true }, "unzip-response": { "version": "2.0.1", "bundled": true, "dev": true }, "update-notifier": { "version": "2.5.0", "bundled": true, "dev": true, "requires": { "boxen": "^1.2.1", "chalk": "^2.0.1", "configstore": "^3.0.0", "import-lazy": "^2.1.0", "is-ci": "^1.0.10", "is-installed-globally": "^0.1.0", "is-npm": "^1.0.0", "latest-version": "^3.0.0", "semver-diff": "^2.0.0", "xdg-basedir": "^3.0.0" } }, "url-parse-lax": { "version": "1.0.0", "bundled": true, "dev": true, "requires": { "prepend-http": "^1.0.1" } }, "util-deprecate": { "version": "1.0.2", "bundled": true, "dev": true }, "util-extend": { "version": "1.0.3", "bundled": true, "dev": true }, "uuid": { "version": "3.3.2", "bundled": true, "dev": true }, "validate-npm-package-license": { "version": "3.0.4", "bundled": true, "dev": true, "requires": { "spdx-correct": "^3.0.0", "spdx-expression-parse": "^3.0.0" } }, "validate-npm-package-name": { "version": "3.0.0", "bundled": true, "dev": true, "requires": { "builtins": "^1.0.3" } }, "verror": { "version": "1.10.0", "bundled": true, "dev": true, "requires": { "assert-plus": "^1.0.0", "core-util-is": "1.0.2", "extsprintf": "^1.2.0" } }, "wcwidth": { "version": "1.0.1", "bundled": true, "dev": true, "requires": { "defaults": "^1.0.3" } }, "which": { "version": "1.3.1", "bundled": true, "dev": true, "requires": { "isexe": "^2.0.0" } }, "which-module": { "version": "2.0.0", "bundled": true, "dev": true }, "wide-align": { "version": "1.1.2", "bundled": true, "dev": true, "requires": { "string-width": "^1.0.2" }, "dependencies": { "string-width": { "version": "1.0.2", "bundled": true, "dev": true, "requires": { "code-point-at": "^1.0.0", "is-fullwidth-code-point": "^1.0.0", "strip-ansi": "^3.0.0" } } } }, "widest-line": { "version": "2.0.0", "bundled": true, "dev": true, "requires": { "string-width": "^2.1.1" } }, "worker-farm": { "version": "1.6.0", "bundled": true, "dev": true, "requires": { "errno": "~0.1.7" } }, "wrap-ansi": { "version": "2.1.0", "bundled": true, "dev": true, "requires": { "string-width": "^1.0.1", "strip-ansi": "^3.0.1" }, "dependencies": { "string-width": { "version": "1.0.2", "bundled": true, "dev": true, "requires": { "code-point-at": "^1.0.0", "is-fullwidth-code-point": "^1.0.0", "strip-ansi": "^3.0.0" } } } }, "wrappy": { "version": "1.0.2", "bundled": true, "dev": true }, "write-file-atomic": { "version": "2.3.0", "bundled": true, "dev": true, "requires": { "graceful-fs": "^4.1.11", "imurmurhash": "^0.1.4", "signal-exit": "^3.0.2" } }, "xdg-basedir": { "version": "3.0.0", "bundled": true, "dev": true }, "xtend": { "version": "4.0.1", "bundled": true, "dev": true }, "y18n": { "version": "4.0.0", "bundled": true, "dev": true }, "yallist": { "version": "2.1.2", "bundled": true, "dev": true }, "yargs": { "version": "11.0.0", "bundled": true, "dev": true, "requires": { "cliui": "^4.0.0", "decamelize": "^1.1.1", "find-up": "^2.1.0", "get-caller-file": "^1.0.1", "os-locale": "^2.0.0", "require-directory": "^2.1.1", "require-main-filename": "^1.0.1", "set-blocking": "^2.0.0", "string-width": "^2.0.0", "which-module": "^2.0.0", "y18n": "^3.2.1", "yargs-parser": "^9.0.2" }, "dependencies": { "y18n": { "version": "3.2.1", "bundled": true, "dev": true } } }, "yargs-parser": { "version": "9.0.2", "bundled": true, "dev": true, "requires": { "camelcase": "^4.1.0" } } } }, "npm-run-path": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-2.0.2.tgz", "integrity": "sha1-NakjLfo11wZ7TLLd8jV7GHFTbF8=", "dev": true, "requires": { "path-key": "^2.0.0" } }, "number-is-nan": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz", "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=", "dev": true }, "object-copy": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/object-copy/-/object-copy-0.1.0.tgz", "integrity": "sha1-fn2Fi3gb18mRpBupde04EnVOmYw=", "dev": true, "requires": { "copy-descriptor": "^0.1.0", "define-property": "^0.2.5", "kind-of": "^3.0.3" }, "dependencies": { "define-property": { "version": "0.2.5", "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", "dev": true, "requires": { "is-descriptor": "^0.1.0" } }, "kind-of": { "version": "3.2.2", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", "dev": true, "requires": { "is-buffer": "^1.1.5" } } } }, "object-visit": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/object-visit/-/object-visit-1.0.1.tgz", "integrity": "sha1-95xEk68MU3e1n+OdOV5BBC3QRbs=", "dev": true, "requires": { "isobject": "^3.0.0" } }, "object.pick": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/object.pick/-/object.pick-1.3.0.tgz", "integrity": "sha1-h6EKxMFpS9Lhy/U1kaZhQftd10c=", "dev": true, "requires": { "isobject": "^3.0.1" } }, "once": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", "dev": true, "requires": { "wrappy": "1" } }, "optimist": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/optimist/-/optimist-0.6.1.tgz", "integrity": "sha1-2j6nRob6IaGaERwybpDrFaAZZoY=", "dev": true, "requires": { "minimist": "~0.0.1", "wordwrap": "~0.0.2" }, "dependencies": { "minimist": { "version": "0.0.10", "resolved": "http://registry.npmjs.org/minimist/-/minimist-0.0.10.tgz", "integrity": "sha1-3j+YVD2/lggr5IrRoMfNqDYwHc8=", "dev": true } } }, "os-locale": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/os-locale/-/os-locale-3.0.1.tgz", "integrity": "sha512-7g5e7dmXPtzcP4bgsZ8ixDVqA7oWYuEz4lOSujeWyliPai4gfVDiFIcwBg3aGCPnmSGfzOKTK3ccPn0CKv3DBw==", "dev": true, "requires": { "execa": "^0.10.0", "lcid": "^2.0.0", "mem": "^4.0.0" }, "dependencies": { "execa": { "version": "0.10.0", "resolved": "https://registry.npmjs.org/execa/-/execa-0.10.0.tgz", "integrity": "sha512-7XOMnz8Ynx1gGo/3hyV9loYNPWM94jG3+3T3Y8tsfSstFmETmENCMU/A/zj8Lyaj1lkgEepKepvd6240tBRvlw==", "dev": true, "requires": { "cross-spawn": "^6.0.0", "get-stream": "^3.0.0", "is-stream": "^1.1.0", "npm-run-path": "^2.0.0", "p-finally": "^1.0.0", "signal-exit": "^3.0.0", "strip-eof": "^1.0.0" } }, "get-stream": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-3.0.0.tgz", "integrity": "sha1-jpQ9E1jcN1VQVOy+LtsFqhdO3hQ=", "dev": true } } }, "os-name": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/os-name/-/os-name-2.0.1.tgz", "integrity": "sha1-uaOGNhwXrjohc27wWZQFyajF3F4=", "dev": true, "requires": { "macos-release": "^1.0.0", "win-release": "^1.0.0" } }, "p-defer": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/p-defer/-/p-defer-1.0.0.tgz", "integrity": "sha1-n26xgvbJqozXQwBKfU+WsZaw+ww=", "dev": true }, "p-filter": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/p-filter/-/p-filter-1.0.0.tgz", "integrity": "sha1-Yp0xcVAgnI/VCLoTdxPvS7kg6ds=", "dev": true, "requires": { "p-map": "^1.0.0" } }, "p-finally": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz", "integrity": "sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4=", "dev": true }, "p-is-promise": { "version": "1.1.0", "resolved": "http://registry.npmjs.org/p-is-promise/-/p-is-promise-1.1.0.tgz", "integrity": "sha1-nJRWmJ6fZYgBewQ01WCXZ1w9oF4=", "dev": true }, "p-limit": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz", "integrity": "sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==", "dev": true, "requires": { "p-try": "^1.0.0" } }, "p-locate": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", "dev": true, "requires": { "p-limit": "^2.0.0" }, "dependencies": { "p-limit": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.0.0.tgz", "integrity": "sha512-fl5s52lI5ahKCernzzIyAP0QAZbGIovtVHGwpcu1Jr/EpzLVDI2myISHwGqK7m8uQFugVWSrbxH7XnhGtvEc+A==", "dev": true, "requires": { "p-try": "^2.0.0" } }, "p-try": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.0.0.tgz", "integrity": "sha512-hMp0onDKIajHfIkdRk3P4CdCmErkYAxxDtP3Wx/4nZ3aGlau2VKh3mZpcuFkH27WQkL/3WBCPOktzA9ZOAnMQQ==", "dev": true } } }, "p-map": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/p-map/-/p-map-1.2.0.tgz", "integrity": "sha512-r6zKACMNhjPJMTl8KcFH4li//gkrXWfbD6feV8l6doRHlzljFWGJ2AP6iKaCJXyZmAUMOPtvbW7EXkbWO/pLEA==", "dev": true }, "p-reduce": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/p-reduce/-/p-reduce-1.0.0.tgz", "integrity": "sha1-GMKw3ZNqRpClKfgjH1ig/bakffo=", "dev": true }, "p-retry": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/p-retry/-/p-retry-2.0.0.tgz", "integrity": "sha512-ZbCuzAmiwJ45q4evp/IG9D+5MUllGSUeCWwPt3j/tdYSi1KPkSD+46uqmAA1LhccDhOXv8kYZKNb8x78VflzfA==", "dev": true, "requires": { "retry": "^0.12.0" } }, "p-try": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz", "integrity": "sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M=", "dev": true }, "parse-github-url": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/parse-github-url/-/parse-github-url-1.0.2.tgz", "integrity": "sha512-kgBf6avCbO3Cn6+RnzRGLkUsv4ZVqv/VfAYkRsyBcgkshNvVBkRn1FEZcW0Jb+npXQWm2vHPnnOqFteZxRRGNw==", "dev": true }, "parse-json": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz", "integrity": "sha1-vjX1Qlvh9/bHRxhPmKeIy5lHfuA=", "dev": true, "requires": { "error-ex": "^1.3.1", "json-parse-better-errors": "^1.0.1" } }, "parse-url": { "version": "1.3.11", "resolved": "https://registry.npmjs.org/parse-url/-/parse-url-1.3.11.tgz", "integrity": "sha1-V8FUKKuKiSsfQ4aWRccR0OFEtVQ=", "dev": true, "requires": { "is-ssh": "^1.3.0", "protocols": "^1.4.0" } }, "pascalcase": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/pascalcase/-/pascalcase-0.1.1.tgz", "integrity": "sha1-s2PlXoAGym/iF4TS2yK9FdeRfxQ=", "dev": true }, "path-dirname": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/path-dirname/-/path-dirname-1.0.2.tgz", "integrity": "sha1-zDPSTVJeCZpTiMAzbG4yuRYGCeA=", "dev": true }, "path-exists": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=", "dev": true }, "path-is-absolute": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", "dev": true }, "path-key": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", "integrity": "sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A=", "dev": true }, "path-type": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/path-type/-/path-type-3.0.0.tgz", "integrity": "sha512-T2ZUsdZFHgA3u4e5PfPbjd7HDDpxPnQb5jN0SrDsjNSuVXHJqtwTnWqG0B1jZrgmJ/7lj1EmVIByWt1gxGkWvg==", "dev": true, "requires": { "pify": "^3.0.0" } }, "pify": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=", "dev": true }, "pkg-conf": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/pkg-conf/-/pkg-conf-2.1.0.tgz", "integrity": "sha1-ISZRTKbyq/69FoWW3xi6V4Z/AFg=", "dev": true, "requires": { "find-up": "^2.0.0", "load-json-file": "^4.0.0" } }, "posix-character-classes": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/posix-character-classes/-/posix-character-classes-0.1.1.tgz", "integrity": "sha1-AerA/jta9xoqbAL+q7jB/vfgDqs=", "dev": true }, "process-nextick-args": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.0.tgz", "integrity": "sha512-MtEC1TqN0EU5nephaJ4rAtThHtC86dNN9qCuEhtshvpVBkAW5ZO7BASN9REnF9eoXGcRub+pFuKEpOHE+HbEMw==", "dev": true }, "protocols": { "version": "1.4.6", "resolved": "https://registry.npmjs.org/protocols/-/protocols-1.4.6.tgz", "integrity": "sha1-+LsmPqG1/Xp2BNJri+Ob13Z4v4o=", "dev": true }, "pump": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", "dev": true, "requires": { "end-of-stream": "^1.1.0", "once": "^1.3.1" } }, "q": { "version": "1.5.1", "resolved": "https://registry.npmjs.org/q/-/q-1.5.1.tgz", "integrity": "sha1-fjL3W0E4EpHQRhHxvxQQmsAGUdc=", "dev": true }, "quick-lru": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/quick-lru/-/quick-lru-1.1.0.tgz", "integrity": "sha1-Q2CxfGETatOAeDl/8RQW4Ybc+7g=", "dev": true }, "rc": { "version": "1.2.8", "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz", "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==", "dev": true, "requires": { "deep-extend": "^0.6.0", "ini": "~1.3.0", "minimist": "^1.2.0", "strip-json-comments": "~2.0.1" } }, "read-pkg": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-3.0.0.tgz", "integrity": "sha1-nLxoaXj+5l0WwA4rGcI3/Pbjg4k=", "dev": true, "requires": { "load-json-file": "^4.0.0", "normalize-package-data": "^2.3.2", "path-type": "^3.0.0" } }, "read-pkg-up": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-4.0.0.tgz", "integrity": "sha512-6etQSH7nJGsK0RbG/2TeDzZFa8shjQ1um+SwQQ5cwKy0dhSXdOncEhb1CPpvQG4h7FyOV6EB6YlV0yJvZQNAkA==", "dev": true, "requires": { "find-up": "^3.0.0", "read-pkg": "^3.0.0" }, "dependencies": { "find-up": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", "dev": true, "requires": { "locate-path": "^3.0.0" } }, "locate-path": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", "dev": true, "requires": { "p-locate": "^3.0.0", "path-exists": "^3.0.0" } } } }, "readable-stream": { "version": "2.3.6", "resolved": "http://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", "dev": true, "requires": { "core-util-is": "~1.0.0", "inherits": "~2.0.3", "isarray": "~1.0.0", "process-nextick-args": "~2.0.0", "safe-buffer": "~5.1.1", "string_decoder": "~1.1.1", "util-deprecate": "~1.0.1" } }, "redent": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/redent/-/redent-2.0.0.tgz", "integrity": "sha1-wbIAe0LVfrE4kHmzyDM2OdXhzKo=", "dev": true, "requires": { "indent-string": "^3.0.0", "strip-indent": "^2.0.0" } }, "redeyed": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/redeyed/-/redeyed-2.1.1.tgz", "integrity": "sha1-iYS1gV2ZyyIEacme7v/jiRPmzAs=", "dev": true, "requires": { "esprima": "~4.0.0" } }, "regex-not": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/regex-not/-/regex-not-1.0.2.tgz", "integrity": "sha512-J6SDjUgDxQj5NusnOtdFxDwN/+HWykR8GELwctJ7mdqhcyy1xEc4SRFHUXvxTp661YaVKAjfRLZ9cCqS6tn32A==", "dev": true, "requires": { "extend-shallow": "^3.0.2", "safe-regex": "^1.1.0" } }, "registry-auth-token": { "version": "3.3.2", "resolved": "https://registry.npmjs.org/registry-auth-token/-/registry-auth-token-3.3.2.tgz", "integrity": "sha512-JL39c60XlzCVgNrO+qq68FoNb56w/m7JYvGR2jT5iR1xBrUA3Mfx5Twk5rqTThPmQKMWydGmq8oFtDlxfrmxnQ==", "dev": true, "requires": { "rc": "^1.1.6", "safe-buffer": "^5.0.1" } }, "repeat-element": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/repeat-element/-/repeat-element-1.1.3.tgz", "integrity": "sha512-ahGq0ZnV5m5XtZLMb+vP76kcAM5nkLqk0lpqAuojSKGgQtn4eRi4ZZGm2olo2zKFH+sMsWaqOCW1dqAnOru72g==", "dev": true }, "repeat-string": { "version": "1.6.1", "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz", "integrity": "sha1-jcrkcOHIirwtYA//Sndihtp15jc=", "dev": true }, "require-directory": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=", "dev": true }, "require-main-filename": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-1.0.1.tgz", "integrity": "sha1-l/cXtp1IeE9fUmpsWqj/3aBVpNE=", "dev": true }, "resolve-from": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", "dev": true }, "resolve-url": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/resolve-url/-/resolve-url-0.2.1.tgz", "integrity": "sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo=", "dev": true }, "ret": { "version": "0.1.15", "resolved": "https://registry.npmjs.org/ret/-/ret-0.1.15.tgz", "integrity": "sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg==", "dev": true }, "retry": { "version": "0.12.0", "resolved": "https://registry.npmjs.org/retry/-/retry-0.12.0.tgz", "integrity": "sha1-G0KmJmoh8HQh0bC1S33BZ7AcATs=", "dev": true }, "safe-buffer": { "version": "5.1.2", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", "dev": true }, "safe-regex": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/safe-regex/-/safe-regex-1.1.0.tgz", "integrity": "sha1-QKNmnzsHfR6UPURinhV91IAjvy4=", "dev": true, "requires": { "ret": "~0.1.10" } }, "semantic-release": { "version": "15.9.16", "resolved": "https://registry.npmjs.org/semantic-release/-/semantic-release-15.9.16.tgz", "integrity": "sha512-5RWqMFwDBXzIaNGUdnJxI4aCd4DtKtdc+5ZNjNWXABEmkimZVuuzZhMaTVNhHYfSuVUqWG9GuATEKhjlVoTzfQ==", "dev": true, "requires": { "@semantic-release/commit-analyzer": "^6.0.0", "@semantic-release/error": "^2.2.0", "@semantic-release/github": "^5.0.0", "@semantic-release/npm": "^5.0.1", "@semantic-release/release-notes-generator": "^7.0.0", "aggregate-error": "^1.0.0", "cosmiconfig": "^5.0.1", "debug": "^4.0.0", "env-ci": "^3.0.0", "execa": "^1.0.0", "figures": "^2.0.0", "find-versions": "^2.0.0", "get-stream": "^4.0.0", "git-log-parser": "^1.2.0", "git-url-parse": "^10.0.1", "hook-std": "^1.1.0", "hosted-git-info": "^2.7.1", "lodash": "^4.17.4", "marked": "^0.5.0", "marked-terminal": "^3.0.0", "p-locate": "^3.0.0", "p-reduce": "^1.0.0", "read-pkg-up": "^4.0.0", "resolve-from": "^4.0.0", "semver": "^5.4.1", "signale": "^1.2.1", "yargs": "^12.0.0" } }, "semver": { "version": "5.5.1", "resolved": "https://registry.npmjs.org/semver/-/semver-5.5.1.tgz", "integrity": "sha512-PqpAxfrEhlSUWge8dwIp4tZnQ25DIOthpiaHNIthsjEFQD6EvqUKUDM7L8O2rShkFccYo1VjJR0coWfNkCubRw==", "dev": true }, "semver-regex": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/semver-regex/-/semver-regex-1.0.0.tgz", "integrity": "sha1-kqSWkGX5xwxpR1PVUkj8aPj2Usk=", "dev": true }, "set-blocking": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=", "dev": true }, "set-value": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/set-value/-/set-value-2.0.0.tgz", "integrity": "sha512-hw0yxk9GT/Hr5yJEYnHNKYXkIA8mVJgd9ditYZCe16ZczcaELYYcfvaXesNACk2O8O0nTiPQcQhGUQj8JLzeeg==", "dev": true, "requires": { "extend-shallow": "^2.0.1", "is-extendable": "^0.1.1", "is-plain-object": "^2.0.3", "split-string": "^3.0.1" }, "dependencies": { "extend-shallow": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", "dev": true, "requires": { "is-extendable": "^0.1.0" } } } }, "shebang-command": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", "integrity": "sha1-RKrGW2lbAzmJaMOfNj/uXer98eo=", "dev": true, "requires": { "shebang-regex": "^1.0.0" } }, "shebang-regex": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz", "integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=", "dev": true }, "signal-exit": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.2.tgz", "integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=", "dev": true }, "signale": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/signale/-/signale-1.3.0.tgz", "integrity": "sha512-TyFhsQ9wZDYDfsPqWMyjCxsDoMwfpsT0130Mce7wDiVCSDdtWSg83dOqoj8aGpGCs3n1YPcam6sT1OFPuGT/OQ==", "dev": true, "requires": { "chalk": "^2.3.2", "figures": "^2.0.0", "pkg-conf": "^2.1.0" } }, "slash": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/slash/-/slash-1.0.0.tgz", "integrity": "sha1-xB8vbDn8FtHNF61LXYlhFK5HDVU=", "dev": true }, "snapdragon": { "version": "0.8.2", "resolved": "https://registry.npmjs.org/snapdragon/-/snapdragon-0.8.2.tgz", "integrity": "sha512-FtyOnWN/wCHTVXOMwvSv26d+ko5vWlIDD6zoUJ7LW8vh+ZBC8QdljveRP+crNrtBwioEUWy/4dMtbBjA4ioNlg==", "dev": true, "requires": { "base": "^0.11.1", "debug": "^2.2.0", "define-property": "^0.2.5", "extend-shallow": "^2.0.1", "map-cache": "^0.2.2", "source-map": "^0.5.6", "source-map-resolve": "^0.5.0", "use": "^3.1.0" }, "dependencies": { "debug": { "version": "2.6.9", "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", "dev": true, "requires": { "ms": "2.0.0" } }, "define-property": { "version": "0.2.5", "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", "dev": true, "requires": { "is-descriptor": "^0.1.0" } }, "extend-shallow": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", "dev": true, "requires": { "is-extendable": "^0.1.0" } }, "ms": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", "dev": true } } }, "snapdragon-node": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/snapdragon-node/-/snapdragon-node-2.1.1.tgz", "integrity": "sha512-O27l4xaMYt/RSQ5TR3vpWCAB5Kb/czIcqUFOM/C4fYcLnbZUc1PkjTAMjof2pBWaSTwOUd6qUHcFGVGj7aIwnw==", "dev": true, "requires": { "define-property": "^1.0.0", "isobject": "^3.0.0", "snapdragon-util": "^3.0.1" }, "dependencies": { "define-property": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", "dev": true, "requires": { "is-descriptor": "^1.0.0" } }, "is-accessor-descriptor": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", "dev": true, "requires": { "kind-of": "^6.0.0" } }, "is-data-descriptor": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", "dev": true, "requires": { "kind-of": "^6.0.0" } }, "is-descriptor": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", "dev": true, "requires": { "is-accessor-descriptor": "^1.0.0", "is-data-descriptor": "^1.0.0", "kind-of": "^6.0.2" } } } }, "snapdragon-util": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/snapdragon-util/-/snapdragon-util-3.0.1.tgz", "integrity": "sha512-mbKkMdQKsjX4BAL4bRYTj21edOf8cN7XHdYUJEe+Zn99hVEYcMvKPct1IqNe7+AZPirn8BCDOQBHQZknqmKlZQ==", "dev": true, "requires": { "kind-of": "^3.2.0" }, "dependencies": { "kind-of": { "version": "3.2.2", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", "dev": true, "requires": { "is-buffer": "^1.1.5" } } } }, "source-map": { "version": "0.5.7", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", "dev": true }, "source-map-resolve": { "version": "0.5.2", "resolved": "https://registry.npmjs.org/source-map-resolve/-/source-map-resolve-0.5.2.tgz", "integrity": "sha512-MjqsvNwyz1s0k81Goz/9vRBe9SZdB09Bdw+/zYyO+3CuPk6fouTaxscHkgtE8jKvf01kVfl8riHzERQ/kefaSA==", "dev": true, "requires": { "atob": "^2.1.1", "decode-uri-component": "^0.2.0", "resolve-url": "^0.2.1", "source-map-url": "^0.4.0", "urix": "^0.1.0" } }, "source-map-url": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/source-map-url/-/source-map-url-0.4.0.tgz", "integrity": "sha1-PpNdfd1zYxuXZZlW1VEo6HtQhKM=", "dev": true }, "spawn-error-forwarder": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/spawn-error-forwarder/-/spawn-error-forwarder-1.0.0.tgz", "integrity": "sha1-Gv2Uc46ZmwNG17n8NzvlXgdXcCk=", "dev": true }, "spdx-correct": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.0.0.tgz", "integrity": "sha512-N19o9z5cEyc8yQQPukRCZ9EUmb4HUpnrmaL/fxS2pBo2jbfcFRVuFZ/oFC+vZz0MNNk0h80iMn5/S6qGZOL5+g==", "dev": true, "requires": { "spdx-expression-parse": "^3.0.0", "spdx-license-ids": "^3.0.0" } }, "spdx-exceptions": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.1.0.tgz", "integrity": "sha512-4K1NsmrlCU1JJgUrtgEeTVyfx8VaYea9J9LvARxhbHtVtohPs/gFGG5yy49beySjlIMhhXZ4QqujIZEfS4l6Cg==", "dev": true }, "spdx-expression-parse": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.0.tgz", "integrity": "sha512-Yg6D3XpRD4kkOmTpdgbUiEJFKghJH03fiC1OPll5h/0sO6neh2jqRDVHOQ4o/LMea0tgCkbMgea5ip/e+MkWyg==", "dev": true, "requires": { "spdx-exceptions": "^2.1.0", "spdx-license-ids": "^3.0.0" } }, "spdx-license-ids": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.1.tgz", "integrity": "sha512-TfOfPcYGBB5sDuPn3deByxPhmfegAhpDYKSOXZQN81Oyrrif8ZCodOLzK3AesELnCx03kikhyDwh0pfvvQvF8w==", "dev": true }, "split": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/split/-/split-1.0.1.tgz", "integrity": "sha512-mTyOoPbrivtXnwnIxZRFYRrPNtEFKlpB2fvjSnCQUiAA6qAZzqwna5envK4uk6OIeP17CsdF3rSBGYVBsU0Tkg==", "dev": true, "requires": { "through": "2" } }, "split-string": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/split-string/-/split-string-3.1.0.tgz", "integrity": "sha512-NzNVhJDYpwceVVii8/Hu6DKfD2G+NrQHlS/V/qgv763EYudVwEcMQNxd2lh+0VrUByXN/oJkl5grOhYWvQUYiw==", "dev": true, "requires": { "extend-shallow": "^3.0.0" } }, "split2": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/split2/-/split2-2.2.0.tgz", "integrity": "sha512-RAb22TG39LhI31MbreBgIuKiIKhVsawfTgEGqKHTK87aG+ul/PB8Sqoi3I7kVdRWiCfrKxK3uo4/YUkpNvhPbw==", "dev": true, "requires": { "through2": "^2.0.2" } }, "sprintf-js": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", "dev": true }, "static-extend": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/static-extend/-/static-extend-0.1.2.tgz", "integrity": "sha1-YICcOcv/VTNyJv1eC1IPNB8ftcY=", "dev": true, "requires": { "define-property": "^0.2.5", "object-copy": "^0.1.0" }, "dependencies": { "define-property": { "version": "0.2.5", "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", "dev": true, "requires": { "is-descriptor": "^0.1.0" } } } }, "stream-combiner2": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/stream-combiner2/-/stream-combiner2-1.1.1.tgz", "integrity": "sha1-+02KFCDqNidk4hrUeAOXvry0HL4=", "dev": true, "requires": { "duplexer2": "~0.1.0", "readable-stream": "^2.0.2" } }, "string-width": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", "dev": true, "requires": { "is-fullwidth-code-point": "^2.0.0", "strip-ansi": "^4.0.0" } }, "string_decoder": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", "dev": true, "requires": { "safe-buffer": "~5.1.0" } }, "strip-ansi": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", "dev": true, "requires": { "ansi-regex": "^3.0.0" } }, "strip-bom": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=", "dev": true }, "strip-eof": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/strip-eof/-/strip-eof-1.0.0.tgz", "integrity": "sha1-u0P/VZim6wXYm1n80SnJgzE2Br8=", "dev": true }, "strip-indent": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-2.0.0.tgz", "integrity": "sha1-XvjbKV0B5u1sv3qrlpmNeCJSe2g=", "dev": true }, "strip-json-comments": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=", "dev": true }, "supports-color": { "version": "5.5.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", "dev": true, "requires": { "has-flag": "^3.0.0" } }, "text-extensions": { "version": "1.8.0", "resolved": "https://registry.npmjs.org/text-extensions/-/text-extensions-1.8.0.tgz", "integrity": "sha512-mVzjRxuWnDKs/qH1rbOJEVHLlSX9kty9lpi7lMvLgU9S74mQ8/Ozg9UPcKxShh0qG2NZ+NyPOPpcZU4C1Eld9A==", "dev": true }, "through": { "version": "2.3.8", "resolved": "http://registry.npmjs.org/through/-/through-2.3.8.tgz", "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=", "dev": true }, "through2": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.3.tgz", "integrity": "sha1-AARWmzfHx0ujnEPzzteNGtlBQL4=", "dev": true, "requires": { "readable-stream": "^2.1.5", "xtend": "~4.0.1" } }, "to-object-path": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/to-object-path/-/to-object-path-0.3.0.tgz", "integrity": "sha1-KXWIt7Dn4KwI4E5nL4XB9JmeF68=", "dev": true, "requires": { "kind-of": "^3.0.2" }, "dependencies": { "kind-of": { "version": "3.2.2", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", "dev": true, "requires": { "is-buffer": "^1.1.5" } } } }, "to-regex": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/to-regex/-/to-regex-3.0.2.tgz", "integrity": "sha512-FWtleNAtZ/Ki2qtqej2CXTOayOH9bHDQF+Q48VpWyDXjbYxA4Yz8iDB31zXOBUlOHHKidDbqGVrTUvQMPmBGBw==", "dev": true, "requires": { "define-property": "^2.0.2", "extend-shallow": "^3.0.2", "regex-not": "^1.0.2", "safe-regex": "^1.1.0" } }, "to-regex-range": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-2.1.1.tgz", "integrity": "sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg=", "dev": true, "requires": { "is-number": "^3.0.0", "repeat-string": "^1.6.1" } }, "traverse": { "version": "0.6.6", "resolved": "https://registry.npmjs.org/traverse/-/traverse-0.6.6.tgz", "integrity": "sha1-y99WD9e5r2MlAv7UD5GMFX6pcTc=", "dev": true }, "trim-newlines": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/trim-newlines/-/trim-newlines-2.0.0.tgz", "integrity": "sha1-tAPQuRvlDDMd/EuC7s6yLD3hbSA=", "dev": true }, "trim-off-newlines": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/trim-off-newlines/-/trim-off-newlines-1.0.1.tgz", "integrity": "sha1-n5up2e+odkw4dpi8v+sshI8RrbM=", "dev": true }, "uglify-js": { "version": "3.4.9", "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.4.9.tgz", "integrity": "sha512-8CJsbKOtEbnJsTyv6LE6m6ZKniqMiFWmm9sRbopbkGs3gMPPfd3Fh8iIA4Ykv5MgaTbqHr4BaoGLJLZNhsrW1Q==", "dev": true, "optional": true, "requires": { "commander": "~2.17.1", "source-map": "~0.6.1" }, "dependencies": { "source-map": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", "dev": true, "optional": true } } }, "union-value": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/union-value/-/union-value-1.0.0.tgz", "integrity": "sha1-XHHDTLW61dzr4+oM0IIHulqhrqQ=", "dev": true, "requires": { "arr-union": "^3.1.0", "get-value": "^2.0.6", "is-extendable": "^0.1.1", "set-value": "^0.4.3" }, "dependencies": { "extend-shallow": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", "dev": true, "requires": { "is-extendable": "^0.1.0" } }, "set-value": { "version": "0.4.3", "resolved": "https://registry.npmjs.org/set-value/-/set-value-0.4.3.tgz", "integrity": "sha1-fbCPnT0i3H945Trzw79GZuzfzPE=", "dev": true, "requires": { "extend-shallow": "^2.0.1", "is-extendable": "^0.1.1", "is-plain-object": "^2.0.1", "to-object-path": "^0.3.0" } } } }, "universal-user-agent": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/universal-user-agent/-/universal-user-agent-2.0.1.tgz", "integrity": "sha512-vz+heWVydO0iyYAa65VHD7WZkYzhl7BeNVy4i54p4TF8OMiLSXdbuQe4hm+fmWAsL+rVibaQHXfhvkw3c1Ws2w==", "dev": true, "requires": { "os-name": "^2.0.1" } }, "universalify": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==", "dev": true }, "unset-value": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/unset-value/-/unset-value-1.0.0.tgz", "integrity": "sha1-g3aHP30jNRef+x5vw6jtDfyKtVk=", "dev": true, "requires": { "has-value": "^0.3.1", "isobject": "^3.0.0" }, "dependencies": { "has-value": { "version": "0.3.1", "resolved": "https://registry.npmjs.org/has-value/-/has-value-0.3.1.tgz", "integrity": "sha1-ex9YutpiyoJ+wKIHgCVlSEWZXh8=", "dev": true, "requires": { "get-value": "^2.0.3", "has-values": "^0.1.4", "isobject": "^2.0.0" }, "dependencies": { "isobject": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/isobject/-/isobject-2.1.0.tgz", "integrity": "sha1-8GVWEJaj8dou9GJy+BXIQNh+DIk=", "dev": true, "requires": { "isarray": "1.0.0" } } } }, "has-values": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/has-values/-/has-values-0.1.4.tgz", "integrity": "sha1-bWHeldkd/Km5oCCJrThL/49it3E=", "dev": true } } }, "urix": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/urix/-/urix-0.1.0.tgz", "integrity": "sha1-2pN/emLiH+wf0Y1Js1wpNQZ6bHI=", "dev": true }, "url-join": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/url-join/-/url-join-4.0.0.tgz", "integrity": "sha1-TTNA6AfTdzvamZH4MFrNzCpmXSo=", "dev": true }, "url-template": { "version": "2.0.8", "resolved": "https://registry.npmjs.org/url-template/-/url-template-2.0.8.tgz", "integrity": "sha1-/FZaPMy/93MMd19WQflVV5FDnyE=", "dev": true }, "use": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/use/-/use-3.1.1.tgz", "integrity": "sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ==", "dev": true }, "util-deprecate": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=", "dev": true }, "validate-npm-package-license": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==", "dev": true, "requires": { "spdx-correct": "^3.0.0", "spdx-expression-parse": "^3.0.0" } }, "which": { "version": "1.3.1", "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", "dev": true, "requires": { "isexe": "^2.0.0" } }, "which-module": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.0.tgz", "integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=", "dev": true }, "win-release": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/win-release/-/win-release-1.1.1.tgz", "integrity": "sha1-X6VeAr58qTTt/BJmVjLoSbcuUgk=", "dev": true, "requires": { "semver": "^5.0.1" } }, "wordwrap": { "version": "0.0.3", "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.3.tgz", "integrity": "sha1-o9XabNXAvAAI03I0u68b7WMFkQc=", "dev": true }, "wrap-ansi": { "version": "2.1.0", "resolved": "http://registry.npmjs.org/wrap-ansi/-/wrap-ansi-2.1.0.tgz", "integrity": "sha1-2Pw9KE3QV5T+hJc8rs3Rz4JP3YU=", "dev": true, "requires": { "string-width": "^1.0.1", "strip-ansi": "^3.0.1" }, "dependencies": { "ansi-regex": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", "dev": true }, "is-fullwidth-code-point": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", "dev": true, "requires": { "number-is-nan": "^1.0.0" } }, "string-width": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", "dev": true, "requires": { "code-point-at": "^1.0.0", "is-fullwidth-code-point": "^1.0.0", "strip-ansi": "^3.0.0" } }, "strip-ansi": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", "dev": true, "requires": { "ansi-regex": "^2.0.0" } } } }, "wrappy": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", "dev": true }, "xregexp": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/xregexp/-/xregexp-4.0.0.tgz", "integrity": "sha512-PHyM+sQouu7xspQQwELlGwwd05mXUFqwFYfqPO0cC7x4fxyHnnuetmQr6CjJiafIDoH4MogHb9dOoJzR/Y4rFg==", "dev": true }, "xtend": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.1.tgz", "integrity": "sha1-pcbVMr5lbiPbgg77lDofBJmNY68=", "dev": true }, "y18n": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.0.tgz", "integrity": "sha512-r9S/ZyXu/Xu9q1tYlpsLIsa3EeLXXk0VwlxqTcFRfg9EhMW+17kbt9G0NrgCmhGb5vT2hyhJZLfDGx+7+5Uj/w==", "dev": true }, "yargs": { "version": "12.0.2", "resolved": "https://registry.npmjs.org/yargs/-/yargs-12.0.2.tgz", "integrity": "sha512-e7SkEx6N6SIZ5c5H22RTZae61qtn3PYUE8JYbBFlK9sYmh3DMQ6E5ygtaG/2BW0JZi4WGgTR2IV5ChqlqrDGVQ==", "dev": true, "requires": { "cliui": "^4.0.0", "decamelize": "^2.0.0", "find-up": "^3.0.0", "get-caller-file": "^1.0.1", "os-locale": "^3.0.0", "require-directory": "^2.1.1", "require-main-filename": "^1.0.1", "set-blocking": "^2.0.0", "string-width": "^2.0.0", "which-module": "^2.0.0", "y18n": "^3.2.1 || ^4.0.0", "yargs-parser": "^10.1.0" }, "dependencies": { "decamelize": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-2.0.0.tgz", "integrity": "sha512-Ikpp5scV3MSYxY39ymh45ZLEecsTdv/Xj2CaQfI8RLMuwi7XvjX9H/fhraiSuU+C5w5NTDu4ZU72xNiZnurBPg==", "dev": true, "requires": { "xregexp": "4.0.0" } }, "find-up": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", "dev": true, "requires": { "locate-path": "^3.0.0" } }, "locate-path": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", "dev": true, "requires": { "p-locate": "^3.0.0", "path-exists": "^3.0.0" } } } }, "yargs-parser": { "version": "10.1.0", "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-10.1.0.tgz", "integrity": "sha512-VCIyR1wJoEBZUqk5PA+oOBF6ypbwh5aNB3I50guxAL/quggdfs4TtNHQrSazFA3fYZ+tEqfs0zIGlv0c/rgjbQ==", "dev": true, "requires": { "camelcase": "^4.1.0" } } } } { "private": true, "repository": { "type": "git", "url": "https://github.com/felixfbecker/php-language-server-protocol" }, "release": { "verifyConditions": "@semantic-release/github", "prepare": [], "publish": "@semantic-release/github" }, "devDependencies": { "semantic-release": "^15.9.16" } } ISC License Copyright (c) 2016, Felix Frederick Becker Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. result = $result; } } ReflectionMethod[] * * @var ReflectionMethod */ private $methods; /** * @var \phpDocumentor\Reflection\DocBlockFactory */ private $docBlockFactory; /** * @var \phpDocumentor\Reflection\Types\ContextFactory */ private $contextFactory; /** * @param object $target The target object that should receive the method calls * @param string $delimiter A delimiter for method calls on properties, for example someProperty->someMethod */ public function __construct($target, $delimiter = '->') { $this->target = $target; $this->delimiter = $delimiter; $this->docBlockFactory = DocBlockFactory::createInstance(); $this->contextFactory = new Types\ContextFactory(); $this->mapper = new JsonMapper(); } /** * Calls the appropriate method handler for an incoming Message * * @param string|object $msg The incoming message * @return mixed */ public function dispatch($msg) { if (\is_string($msg)) { $msg = \json_decode($msg); if (\json_last_error() !== \JSON_ERROR_NONE) { throw new Error(\json_last_error_msg(), ErrorCode::PARSE_ERROR); } } // Find out the object and function that should be called $obj = $this->target; $parts = \explode($this->delimiter, $msg->method); // The function to call is always the last part of the method $fn = \array_pop($parts); // For namespaced methods like textDocument/didOpen, call the didOpen method on the $textDocument property // For simple methods like initialize, shutdown, exit, this loop will simply not be entered and $obj will be // the target foreach ($parts as $part) { if (!isset($obj->{$part})) { throw new Error("Method {$msg->method} is not implemented", ErrorCode::METHOD_NOT_FOUND); } $obj = $obj->{$part}; } if (!isset($this->methods[$msg->method])) { try { $method = new ReflectionMethod($obj, $fn); $this->methods[$msg->method] = $method; } catch (ReflectionException $e) { throw new Error($e->getMessage(), ErrorCode::METHOD_NOT_FOUND, null, $e); } } $method = $this->methods[$msg->method]; $parameters = $method->getParameters(); if ($method->getDocComment()) { $docBlock = $this->docBlockFactory->create($method->getDocComment(), $this->contextFactory->createFromReflector($method->getDeclaringClass())); $paramTags = $docBlock->getTagsByName('param'); } $args = []; if (isset($msg->params)) { // Find out the position if (\is_array($msg->params)) { $args = $msg->params; } else { if (\is_object($msg->params)) { foreach ($parameters as $pos => $parameter) { $value = null; foreach (\get_object_vars($msg->params) as $key => $val) { if ($parameter->name === $key) { $value = $val; break; } } $args[$pos] = $value; } } else { throw new Error('Params must be structured or omitted', ErrorCode::INVALID_REQUEST); } } foreach ($args as $position => $value) { try { // If the type is structured (array or object), map it with JsonMapper if (\is_object($value)) { // Does the parameter have a type hint? $param = $parameters[$position]; if ($param->hasType()) { $paramType = $param->getType(); if ($paramType instanceof ReflectionNamedType) { // We have object data to map and want the class name. // This should not include the `?` if the type was nullable. $class = $paramType->getName(); } else { // Fallback for php 7.0, which is still supported (and doesn't have nullable). $class = (string) $paramType; } $value = $this->mapper->map($value, new $class()); } } else { if (\is_array($value) && isset($docBlock)) { // Get the array type from the DocBlock $type = $paramTags[$position]->getType(); // For union types, use the first one that is a class array (often it is SomeClass[]|null) if ($type instanceof Types\Compound) { for ($i = 0; $t = $type->get($i); $i++) { if ($t instanceof Types\Array_ && $t->getValueType() instanceof Types\Object_ && (string) $t->getValueType() !== 'object') { $class = (string) $t->getValueType()->getFqsen(); $value = $this->mapper->mapArray($value, [], $class); break; } } } else { if ($type instanceof Types\Array_) { $class = (string) $type->getValueType()->getFqsen(); $value = $this->mapper->mapArray($value, [], $class); } else { throw new Error('Type is not matching @param tag', ErrorCode::INVALID_PARAMS); } } } } } catch (JsonMapper_Exception $e) { throw new Error($e->getMessage(), ErrorCode::INVALID_PARAMS, null, $e); } $args[$position] = $value; } } \ksort($args); $result = $obj->{$fn}(...$args); return $result; } } error)); } /** * @param int|string $id * @param mixed $result * @param ResponseError $error */ public function __construct($id) { $this->id = $id; } } method); } /** * @param string|int $id * @param string $method * @param object|array $params */ public function __construct($id, string $method, $params = null) { $this->id = $id; $this->method = $method; $this->params = $params; } } id) && isset($msg->error); } /** * @param int|string $id * @param \AdvancedJsonRpc\Error $error */ public function __construct($id, Error $error) { parent::__construct($id); $this->error = $error; } } method); } /** * @param string $method * @param mixed $params */ public function __construct(string $method, $params = null) { $this->method = $method; $this->params = $params; } } data = $data; } } method, $decoded->params ?? null); } else { if (Request::isRequest($decoded)) { $obj = new Request($decoded->id, $decoded->method, $decoded->params ?? null); } else { if (SuccessResponse::isSuccessResponse($decoded)) { $obj = new SuccessResponse($decoded->id, $decoded->result); } else { if (ErrorResponse::isErrorResponse($decoded)) { $obj = new ErrorResponse($decoded->id, new Error($decoded->error->message, $decoded->error->code, $decoded->error->data ?? null)); } else { throw new Error('Invalid message', ErrorCode::INVALID_REQUEST); } } } } return $obj; } public function __toString() : string { $encoded = \json_encode($this); if ($encoded === \false) { throw new Error(\json_last_error_msg(), ErrorCode::INTERNAL_ERROR); } return $encoded; } } sebastian/diff Copyright (c) 2002-2020, Sebastian Bergmann . All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the name of Sebastian Bergmann nor the names of his contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace _HumbugBox7ff99e199a36\SebastianBergmann\Diff; use const PHP_INT_SIZE; use const PREG_SPLIT_DELIM_CAPTURE; use const PREG_SPLIT_NO_EMPTY; use function array_shift; use function array_unshift; use function array_values; use function count; use function current; use function end; use function get_class; use function gettype; use function is_array; use function is_object; use function is_string; use function key; use function min; use function preg_split; use function prev; use function reset; use function sprintf; use function substr; use _HumbugBox7ff99e199a36\SebastianBergmann\Diff\Output\DiffOutputBuilderInterface; use _HumbugBox7ff99e199a36\SebastianBergmann\Diff\Output\UnifiedDiffOutputBuilder; final class Differ { public const OLD = 0; public const ADDED = 1; public const REMOVED = 2; public const DIFF_LINE_END_WARNING = 3; public const NO_LINE_END_EOF_WARNING = 4; /** * @var DiffOutputBuilderInterface */ private $outputBuilder; /** * @param DiffOutputBuilderInterface $outputBuilder * * @throws InvalidArgumentException */ public function __construct($outputBuilder = null) { if ($outputBuilder instanceof DiffOutputBuilderInterface) { $this->outputBuilder = $outputBuilder; } elseif (null === $outputBuilder) { $this->outputBuilder = new UnifiedDiffOutputBuilder(); } elseif (is_string($outputBuilder)) { // PHPUnit 6.1.4, 6.2.0, 6.2.1, 6.2.2, and 6.2.3 support // @see https://github.com/sebastianbergmann/phpunit/issues/2734#issuecomment-314514056 // @deprecated $this->outputBuilder = new UnifiedDiffOutputBuilder($outputBuilder); } else { throw new InvalidArgumentException(sprintf('Expected builder to be an instance of DiffOutputBuilderInterface, or a string, got %s.', is_object($outputBuilder) ? 'instance of "' . get_class($outputBuilder) . '"' : gettype($outputBuilder) . ' "' . $outputBuilder . '"')); } } /** * Returns the diff between two arrays or strings as string. * * @param array|string $from * @param array|string $to */ public function diff($from, $to, ?LongestCommonSubsequenceCalculator $lcs = null) : string { $diff = $this->diffToArray($this->normalizeDiffInput($from), $this->normalizeDiffInput($to), $lcs); return $this->outputBuilder->getDiff($diff); } /** * Returns the diff between two arrays or strings as array. * * Each array element contains two elements: * - [0] => mixed $token * - [1] => 2|1|0 * * - 2: REMOVED: $token was removed from $from * - 1: ADDED: $token was added to $from * - 0: OLD: $token is not changed in $to * * @param array|string $from * @param array|string $to * @param LongestCommonSubsequenceCalculator $lcs */ public function diffToArray($from, $to, ?LongestCommonSubsequenceCalculator $lcs = null) : array { if (is_string($from)) { $from = $this->splitStringByLines($from); } elseif (!is_array($from)) { throw new InvalidArgumentException('"from" must be an array or string.'); } if (is_string($to)) { $to = $this->splitStringByLines($to); } elseif (!is_array($to)) { throw new InvalidArgumentException('"to" must be an array or string.'); } [$from, $to, $start, $end] = self::getArrayDiffParted($from, $to); if ($lcs === null) { $lcs = $this->selectLcsImplementation($from, $to); } $common = $lcs->calculate(array_values($from), array_values($to)); $diff = []; foreach ($start as $token) { $diff[] = [$token, self::OLD]; } reset($from); reset($to); foreach ($common as $token) { while (($fromToken = reset($from)) !== $token) { $diff[] = [array_shift($from), self::REMOVED]; } while (($toToken = reset($to)) !== $token) { $diff[] = [array_shift($to), self::ADDED]; } $diff[] = [$token, self::OLD]; array_shift($from); array_shift($to); } while (($token = array_shift($from)) !== null) { $diff[] = [$token, self::REMOVED]; } while (($token = array_shift($to)) !== null) { $diff[] = [$token, self::ADDED]; } foreach ($end as $token) { $diff[] = [$token, self::OLD]; } if ($this->detectUnmatchedLineEndings($diff)) { array_unshift($diff, ["#Warning: Strings contain different line endings!\n", self::DIFF_LINE_END_WARNING]); } return $diff; } /** * Casts variable to string if it is not a string or array. * * @return array|string */ private function normalizeDiffInput($input) { if (!is_array($input) && !is_string($input)) { return (string) $input; } return $input; } /** * Checks if input is string, if so it will split it line-by-line. */ private function splitStringByLines(string $input) : array { return preg_split('/(.*\\R)/', $input, -1, PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_NO_EMPTY); } private function selectLcsImplementation(array $from, array $to) : LongestCommonSubsequenceCalculator { // We do not want to use the time-efficient implementation if its memory // footprint will probably exceed this value. Note that the footprint // calculation is only an estimation for the matrix and the LCS method // will typically allocate a bit more memory than this. $memoryLimit = 100 * 1024 * 1024; if ($this->calculateEstimatedFootprint($from, $to) > $memoryLimit) { return new MemoryEfficientLongestCommonSubsequenceCalculator(); } return new TimeEfficientLongestCommonSubsequenceCalculator(); } /** * Calculates the estimated memory footprint for the DP-based method. * * @return float|int */ private function calculateEstimatedFootprint(array $from, array $to) { $itemSize = PHP_INT_SIZE === 4 ? 76 : 144; return $itemSize * min(count($from), count($to)) ** 2; } /** * Returns true if line ends don't match in a diff. */ private function detectUnmatchedLineEndings(array $diff) : bool { $newLineBreaks = ['' => \true]; $oldLineBreaks = ['' => \true]; foreach ($diff as $entry) { if (self::OLD === $entry[1]) { $ln = $this->getLinebreak($entry[0]); $oldLineBreaks[$ln] = \true; $newLineBreaks[$ln] = \true; } elseif (self::ADDED === $entry[1]) { $newLineBreaks[$this->getLinebreak($entry[0])] = \true; } elseif (self::REMOVED === $entry[1]) { $oldLineBreaks[$this->getLinebreak($entry[0])] = \true; } } // if either input or output is a single line without breaks than no warning should be raised if (['' => \true] === $newLineBreaks || ['' => \true] === $oldLineBreaks) { return \false; } // two way compare foreach ($newLineBreaks as $break => $set) { if (!isset($oldLineBreaks[$break])) { return \true; } } foreach ($oldLineBreaks as $break => $set) { if (!isset($newLineBreaks[$break])) { return \true; } } return \false; } private function getLinebreak($line) : string { if (!is_string($line)) { return ''; } $lc = substr($line, -1); if ("\r" === $lc) { return "\r"; } if ("\n" !== $lc) { return ''; } if ("\r\n" === substr($line, -2)) { return "\r\n"; } return "\n"; } private static function getArrayDiffParted(array &$from, array &$to) : array { $start = []; $end = []; reset($to); foreach ($from as $k => $v) { $toK = key($to); if ($toK === $k && $v === $to[$k]) { $start[$k] = $v; unset($from[$k], $to[$k]); } else { break; } } end($from); end($to); do { $fromK = key($from); $toK = key($to); if (null === $fromK || null === $toK || current($from) !== current($to)) { break; } prev($from); prev($to); $end = [$fromK => $from[$fromK]] + $end; unset($from[$fromK], $to[$toK]); } while (\true); return [$from, $to, $start, $end]; } } * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace _HumbugBox7ff99e199a36\SebastianBergmann\Diff; final class Chunk { /** * @var int */ private $start; /** * @var int */ private $startRange; /** * @var int */ private $end; /** * @var int */ private $endRange; /** * @var Line[] */ private $lines; public function __construct(int $start = 0, int $startRange = 1, int $end = 0, int $endRange = 1, array $lines = []) { $this->start = $start; $this->startRange = $startRange; $this->end = $end; $this->endRange = $endRange; $this->lines = $lines; } public function getStart() : int { return $this->start; } public function getStartRange() : int { return $this->startRange; } public function getEnd() : int { return $this->end; } public function getEndRange() : int { return $this->endRange; } /** * @return Line[] */ public function getLines() : array { return $this->lines; } /** * @param Line[] $lines */ public function setLines(array $lines) : void { foreach ($lines as $line) { if (!$line instanceof Line) { throw new InvalidArgumentException(); } } $this->lines = $lines; } } * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace _HumbugBox7ff99e199a36\SebastianBergmann\Diff; use function array_reverse; use function count; use function max; use SplFixedArray; final class TimeEfficientLongestCommonSubsequenceCalculator implements LongestCommonSubsequenceCalculator { /** * {@inheritdoc} */ public function calculate(array $from, array $to) : array { $common = []; $fromLength = count($from); $toLength = count($to); $width = $fromLength + 1; $matrix = new SplFixedArray($width * ($toLength + 1)); for ($i = 0; $i <= $fromLength; ++$i) { $matrix[$i] = 0; } for ($j = 0; $j <= $toLength; ++$j) { $matrix[$j * $width] = 0; } for ($i = 1; $i <= $fromLength; ++$i) { for ($j = 1; $j <= $toLength; ++$j) { $o = $j * $width + $i; // don't use max() to avoid function call overhead $firstOrLast = $from[$i - 1] === $to[$j - 1] ? $matrix[$o - $width - 1] + 1 : 0; if ($matrix[$o - 1] > $matrix[$o - $width]) { if ($firstOrLast > $matrix[$o - 1]) { $matrix[$o] = $firstOrLast; } else { $matrix[$o] = $matrix[$o - 1]; } } else { if ($firstOrLast > $matrix[$o - $width]) { $matrix[$o] = $firstOrLast; } else { $matrix[$o] = $matrix[$o - $width]; } } } } $i = $fromLength; $j = $toLength; while ($i > 0 && $j > 0) { if ($from[$i - 1] === $to[$j - 1]) { $common[] = $from[$i - 1]; --$i; --$j; } else { $o = $j * $width + $i; if ($matrix[$o - $width] > $matrix[$o - 1]) { --$j; } else { --$i; } } } return array_reverse($common); } } * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace _HumbugBox7ff99e199a36\SebastianBergmann\Diff; interface LongestCommonSubsequenceCalculator { /** * Calculates the longest common subsequence of two arrays. */ public function calculate(array $from, array $to) : array; } * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace _HumbugBox7ff99e199a36\SebastianBergmann\Diff\Output; /** * Defines how an output builder should take a generated * diff array and return a string representation of that diff. */ interface DiffOutputBuilderInterface { public function getDiff(array $diff) : string; } * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace _HumbugBox7ff99e199a36\SebastianBergmann\Diff\Output; use function array_merge; use function array_splice; use function count; use function fclose; use function fopen; use function fwrite; use function is_bool; use function is_int; use function is_string; use function max; use function min; use function sprintf; use function stream_get_contents; use function substr; use _HumbugBox7ff99e199a36\SebastianBergmann\Diff\ConfigurationException; use _HumbugBox7ff99e199a36\SebastianBergmann\Diff\Differ; /** * Strict Unified diff output builder. * * Generates (strict) Unified diff's (unidiffs) with hunks. */ final class StrictUnifiedDiffOutputBuilder implements DiffOutputBuilderInterface { private static $default = [ 'collapseRanges' => \true, // ranges of length one are rendered with the trailing `,1` 'commonLineThreshold' => 6, // number of same lines before ending a new hunk and creating a new one (if needed) 'contextLines' => 3, // like `diff: -u, -U NUM, --unified[=NUM]`, for patch/git apply compatibility best to keep at least @ 3 'fromFile' => null, 'fromFileDate' => null, 'toFile' => null, 'toFileDate' => null, ]; /** * @var bool */ private $changed; /** * @var bool */ private $collapseRanges; /** * @var int >= 0 */ private $commonLineThreshold; /** * @var string */ private $header; /** * @var int >= 0 */ private $contextLines; public function __construct(array $options = []) { $options = array_merge(self::$default, $options); if (!is_bool($options['collapseRanges'])) { throw new ConfigurationException('collapseRanges', 'a bool', $options['collapseRanges']); } if (!is_int($options['contextLines']) || $options['contextLines'] < 0) { throw new ConfigurationException('contextLines', 'an int >= 0', $options['contextLines']); } if (!is_int($options['commonLineThreshold']) || $options['commonLineThreshold'] <= 0) { throw new ConfigurationException('commonLineThreshold', 'an int > 0', $options['commonLineThreshold']); } $this->assertString($options, 'fromFile'); $this->assertString($options, 'toFile'); $this->assertStringOrNull($options, 'fromFileDate'); $this->assertStringOrNull($options, 'toFileDate'); $this->header = sprintf("--- %s%s\n+++ %s%s\n", $options['fromFile'], null === $options['fromFileDate'] ? '' : "\t" . $options['fromFileDate'], $options['toFile'], null === $options['toFileDate'] ? '' : "\t" . $options['toFileDate']); $this->collapseRanges = $options['collapseRanges']; $this->commonLineThreshold = $options['commonLineThreshold']; $this->contextLines = $options['contextLines']; } public function getDiff(array $diff) : string { if (0 === count($diff)) { return ''; } $this->changed = \false; $buffer = fopen('php://memory', 'r+b'); fwrite($buffer, $this->header); $this->writeDiffHunks($buffer, $diff); if (!$this->changed) { fclose($buffer); return ''; } $diff = stream_get_contents($buffer, -1, 0); fclose($buffer); // If the last char is not a linebreak: add it. // This might happen when both the `from` and `to` do not have a trailing linebreak $last = substr($diff, -1); return "\n" !== $last && "\r" !== $last ? $diff . "\n" : $diff; } private function writeDiffHunks($output, array $diff) : void { // detect "No newline at end of file" and insert into `$diff` if needed $upperLimit = count($diff); if (0 === $diff[$upperLimit - 1][1]) { $lc = substr($diff[$upperLimit - 1][0], -1); if ("\n" !== $lc) { array_splice($diff, $upperLimit, 0, [["\n\\ No newline at end of file\n", Differ::NO_LINE_END_EOF_WARNING]]); } } else { // search back for the last `+` and `-` line, // check if has trailing linebreak, else add under it warning under it $toFind = [1 => \true, 2 => \true]; for ($i = $upperLimit - 1; $i >= 0; --$i) { if (isset($toFind[$diff[$i][1]])) { unset($toFind[$diff[$i][1]]); $lc = substr($diff[$i][0], -1); if ("\n" !== $lc) { array_splice($diff, $i + 1, 0, [["\n\\ No newline at end of file\n", Differ::NO_LINE_END_EOF_WARNING]]); } if (!count($toFind)) { break; } } } } // write hunks to output buffer $cutOff = max($this->commonLineThreshold, $this->contextLines); $hunkCapture = \false; $sameCount = $toRange = $fromRange = 0; $toStart = $fromStart = 1; $i = 0; /** @var int $i */ foreach ($diff as $i => $entry) { if (0 === $entry[1]) { // same if (\false === $hunkCapture) { ++$fromStart; ++$toStart; continue; } ++$sameCount; ++$toRange; ++$fromRange; if ($sameCount === $cutOff) { $contextStartOffset = $hunkCapture - $this->contextLines < 0 ? $hunkCapture : $this->contextLines; // note: $contextEndOffset = $this->contextLines; // // because we never go beyond the end of the diff. // with the cutoff/contextlines here the follow is never true; // // if ($i - $cutOff + $this->contextLines + 1 > \count($diff)) { // $contextEndOffset = count($diff) - 1; // } // // ; that would be true for a trailing incomplete hunk case which is dealt with after this loop $this->writeHunk($diff, $hunkCapture - $contextStartOffset, $i - $cutOff + $this->contextLines + 1, $fromStart - $contextStartOffset, $fromRange - $cutOff + $contextStartOffset + $this->contextLines, $toStart - $contextStartOffset, $toRange - $cutOff + $contextStartOffset + $this->contextLines, $output); $fromStart += $fromRange; $toStart += $toRange; $hunkCapture = \false; $sameCount = $toRange = $fromRange = 0; } continue; } $sameCount = 0; if ($entry[1] === Differ::NO_LINE_END_EOF_WARNING) { continue; } $this->changed = \true; if (\false === $hunkCapture) { $hunkCapture = $i; } if (Differ::ADDED === $entry[1]) { // added ++$toRange; } if (Differ::REMOVED === $entry[1]) { // removed ++$fromRange; } } if (\false === $hunkCapture) { return; } // we end here when cutoff (commonLineThreshold) was not reached, but we where capturing a hunk, // do not render hunk till end automatically because the number of context lines might be less than the commonLineThreshold $contextStartOffset = $hunkCapture - $this->contextLines < 0 ? $hunkCapture : $this->contextLines; // prevent trying to write out more common lines than there are in the diff _and_ // do not write more than configured through the context lines $contextEndOffset = min($sameCount, $this->contextLines); $fromRange -= $sameCount; $toRange -= $sameCount; $this->writeHunk($diff, $hunkCapture - $contextStartOffset, $i - $sameCount + $contextEndOffset + 1, $fromStart - $contextStartOffset, $fromRange + $contextStartOffset + $contextEndOffset, $toStart - $contextStartOffset, $toRange + $contextStartOffset + $contextEndOffset, $output); } private function writeHunk(array $diff, int $diffStartIndex, int $diffEndIndex, int $fromStart, int $fromRange, int $toStart, int $toRange, $output) : void { fwrite($output, '@@ -' . $fromStart); if (!$this->collapseRanges || 1 !== $fromRange) { fwrite($output, ',' . $fromRange); } fwrite($output, ' +' . $toStart); if (!$this->collapseRanges || 1 !== $toRange) { fwrite($output, ',' . $toRange); } fwrite($output, " @@\n"); for ($i = $diffStartIndex; $i < $diffEndIndex; ++$i) { if ($diff[$i][1] === Differ::ADDED) { $this->changed = \true; fwrite($output, '+' . $diff[$i][0]); } elseif ($diff[$i][1] === Differ::REMOVED) { $this->changed = \true; fwrite($output, '-' . $diff[$i][0]); } elseif ($diff[$i][1] === Differ::OLD) { fwrite($output, ' ' . $diff[$i][0]); } elseif ($diff[$i][1] === Differ::NO_LINE_END_EOF_WARNING) { $this->changed = \true; fwrite($output, $diff[$i][0]); } //} elseif ($diff[$i][1] === Differ::DIFF_LINE_END_WARNING) { // custom comment inserted by PHPUnit/diff package // skip //} else { // unknown/invalid //} } } private function assertString(array $options, string $option) : void { if (!is_string($options[$option])) { throw new ConfigurationException($option, 'a string', $options[$option]); } } private function assertStringOrNull(array $options, string $option) : void { if (null !== $options[$option] && !is_string($options[$option])) { throw new ConfigurationException($option, 'a string or ', $options[$option]); } } } * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace _HumbugBox7ff99e199a36\SebastianBergmann\Diff\Output; use function array_splice; use function count; use function fclose; use function fopen; use function fwrite; use function max; use function min; use function stream_get_contents; use function strlen; use function substr; use _HumbugBox7ff99e199a36\SebastianBergmann\Diff\Differ; /** * Builds a diff string representation in unified diff format in chunks. */ final class UnifiedDiffOutputBuilder extends AbstractChunkOutputBuilder { /** * @var bool */ private $collapseRanges = \true; /** * @var int >= 0 */ private $commonLineThreshold = 6; /** * @var int >= 0 */ private $contextLines = 3; /** * @var string */ private $header; /** * @var bool */ private $addLineNumbers; public function __construct(string $header = "--- Original\n+++ New\n", bool $addLineNumbers = \false) { $this->header = $header; $this->addLineNumbers = $addLineNumbers; } public function getDiff(array $diff) : string { $buffer = fopen('php://memory', 'r+b'); if ('' !== $this->header) { fwrite($buffer, $this->header); if ("\n" !== substr($this->header, -1, 1)) { fwrite($buffer, "\n"); } } if (0 !== count($diff)) { $this->writeDiffHunks($buffer, $diff); } $diff = stream_get_contents($buffer, -1, 0); fclose($buffer); // If the diff is non-empty and last char is not a linebreak: add it. // This might happen when both the `from` and `to` do not have a trailing linebreak $last = substr($diff, -1); return 0 !== strlen($diff) && "\n" !== $last && "\r" !== $last ? $diff . "\n" : $diff; } private function writeDiffHunks($output, array $diff) : void { // detect "No newline at end of file" and insert into `$diff` if needed $upperLimit = count($diff); if (0 === $diff[$upperLimit - 1][1]) { $lc = substr($diff[$upperLimit - 1][0], -1); if ("\n" !== $lc) { array_splice($diff, $upperLimit, 0, [["\n\\ No newline at end of file\n", Differ::NO_LINE_END_EOF_WARNING]]); } } else { // search back for the last `+` and `-` line, // check if has trailing linebreak, else add under it warning under it $toFind = [1 => \true, 2 => \true]; for ($i = $upperLimit - 1; $i >= 0; --$i) { if (isset($toFind[$diff[$i][1]])) { unset($toFind[$diff[$i][1]]); $lc = substr($diff[$i][0], -1); if ("\n" !== $lc) { array_splice($diff, $i + 1, 0, [["\n\\ No newline at end of file\n", Differ::NO_LINE_END_EOF_WARNING]]); } if (!count($toFind)) { break; } } } } // write hunks to output buffer $cutOff = max($this->commonLineThreshold, $this->contextLines); $hunkCapture = \false; $sameCount = $toRange = $fromRange = 0; $toStart = $fromStart = 1; $i = 0; /** @var int $i */ foreach ($diff as $i => $entry) { if (0 === $entry[1]) { // same if (\false === $hunkCapture) { ++$fromStart; ++$toStart; continue; } ++$sameCount; ++$toRange; ++$fromRange; if ($sameCount === $cutOff) { $contextStartOffset = $hunkCapture - $this->contextLines < 0 ? $hunkCapture : $this->contextLines; // note: $contextEndOffset = $this->contextLines; // // because we never go beyond the end of the diff. // with the cutoff/contextlines here the follow is never true; // // if ($i - $cutOff + $this->contextLines + 1 > \count($diff)) { // $contextEndOffset = count($diff) - 1; // } // // ; that would be true for a trailing incomplete hunk case which is dealt with after this loop $this->writeHunk($diff, $hunkCapture - $contextStartOffset, $i - $cutOff + $this->contextLines + 1, $fromStart - $contextStartOffset, $fromRange - $cutOff + $contextStartOffset + $this->contextLines, $toStart - $contextStartOffset, $toRange - $cutOff + $contextStartOffset + $this->contextLines, $output); $fromStart += $fromRange; $toStart += $toRange; $hunkCapture = \false; $sameCount = $toRange = $fromRange = 0; } continue; } $sameCount = 0; if ($entry[1] === Differ::NO_LINE_END_EOF_WARNING) { continue; } if (\false === $hunkCapture) { $hunkCapture = $i; } if (Differ::ADDED === $entry[1]) { ++$toRange; } if (Differ::REMOVED === $entry[1]) { ++$fromRange; } } if (\false === $hunkCapture) { return; } // we end here when cutoff (commonLineThreshold) was not reached, but we where capturing a hunk, // do not render hunk till end automatically because the number of context lines might be less than the commonLineThreshold $contextStartOffset = $hunkCapture - $this->contextLines < 0 ? $hunkCapture : $this->contextLines; // prevent trying to write out more common lines than there are in the diff _and_ // do not write more than configured through the context lines $contextEndOffset = min($sameCount, $this->contextLines); $fromRange -= $sameCount; $toRange -= $sameCount; $this->writeHunk($diff, $hunkCapture - $contextStartOffset, $i - $sameCount + $contextEndOffset + 1, $fromStart - $contextStartOffset, $fromRange + $contextStartOffset + $contextEndOffset, $toStart - $contextStartOffset, $toRange + $contextStartOffset + $contextEndOffset, $output); } private function writeHunk(array $diff, int $diffStartIndex, int $diffEndIndex, int $fromStart, int $fromRange, int $toStart, int $toRange, $output) : void { if ($this->addLineNumbers) { fwrite($output, '@@ -' . $fromStart); if (!$this->collapseRanges || 1 !== $fromRange) { fwrite($output, ',' . $fromRange); } fwrite($output, ' +' . $toStart); if (!$this->collapseRanges || 1 !== $toRange) { fwrite($output, ',' . $toRange); } fwrite($output, " @@\n"); } else { fwrite($output, "@@ @@\n"); } for ($i = $diffStartIndex; $i < $diffEndIndex; ++$i) { if ($diff[$i][1] === Differ::ADDED) { fwrite($output, '+' . $diff[$i][0]); } elseif ($diff[$i][1] === Differ::REMOVED) { fwrite($output, '-' . $diff[$i][0]); } elseif ($diff[$i][1] === Differ::OLD) { fwrite($output, ' ' . $diff[$i][0]); } elseif ($diff[$i][1] === Differ::NO_LINE_END_EOF_WARNING) { fwrite($output, "\n"); // $diff[$i][0] } else { /* Not changed (old) Differ::OLD or Warning Differ::DIFF_LINE_END_WARNING */ fwrite($output, ' ' . $diff[$i][0]); } } } } * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace _HumbugBox7ff99e199a36\SebastianBergmann\Diff\Output; use function fclose; use function fopen; use function fwrite; use function stream_get_contents; use function substr; use _HumbugBox7ff99e199a36\SebastianBergmann\Diff\Differ; /** * Builds a diff string representation in a loose unified diff format * listing only changes lines. Does not include line numbers. */ final class DiffOnlyOutputBuilder implements DiffOutputBuilderInterface { /** * @var string */ private $header; public function __construct(string $header = "--- Original\n+++ New\n") { $this->header = $header; } public function getDiff(array $diff) : string { $buffer = fopen('php://memory', 'r+b'); if ('' !== $this->header) { fwrite($buffer, $this->header); if ("\n" !== substr($this->header, -1, 1)) { fwrite($buffer, "\n"); } } foreach ($diff as $diffEntry) { if ($diffEntry[1] === Differ::ADDED) { fwrite($buffer, '+' . $diffEntry[0]); } elseif ($diffEntry[1] === Differ::REMOVED) { fwrite($buffer, '-' . $diffEntry[0]); } elseif ($diffEntry[1] === Differ::DIFF_LINE_END_WARNING) { fwrite($buffer, ' ' . $diffEntry[0]); continue; // Warnings should not be tested for line break, it will always be there } else { /* Not changed (old) 0 */ continue; // we didn't write the non changs line, so do not add a line break either } $lc = substr($diffEntry[0], -1); if ($lc !== "\n" && $lc !== "\r") { fwrite($buffer, "\n"); // \No newline at end of file } } $diff = stream_get_contents($buffer, -1, 0); fclose($buffer); return $diff; } } * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace _HumbugBox7ff99e199a36\SebastianBergmann\Diff\Output; use function count; abstract class AbstractChunkOutputBuilder implements DiffOutputBuilderInterface { /** * Takes input of the diff array and returns the common parts. * Iterates through diff line by line. */ protected function getCommonChunks(array $diff, int $lineThreshold = 5) : array { $diffSize = count($diff); $capturing = \false; $chunkStart = 0; $chunkSize = 0; $commonChunks = []; for ($i = 0; $i < $diffSize; ++$i) { if ($diff[$i][1] === 0) { if ($capturing === \false) { $capturing = \true; $chunkStart = $i; $chunkSize = 0; } else { ++$chunkSize; } } elseif ($capturing !== \false) { if ($chunkSize >= $lineThreshold) { $commonChunks[$chunkStart] = $chunkStart + $chunkSize; } $capturing = \false; } } if ($capturing !== \false && $chunkSize >= $lineThreshold) { $commonChunks[$chunkStart] = $chunkStart + $chunkSize; } return $commonChunks; } } * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace _HumbugBox7ff99e199a36\SebastianBergmann\Diff; use function array_pop; use function count; use function max; use function preg_match; use function preg_split; /** * Unified diff parser. */ final class Parser { /** * @return Diff[] */ public function parse(string $string) : array { $lines = preg_split('(\\r\\n|\\r|\\n)', $string); if (!empty($lines) && $lines[count($lines) - 1] === '') { array_pop($lines); } $lineCount = count($lines); $diffs = []; $diff = null; $collected = []; for ($i = 0; $i < $lineCount; ++$i) { if (preg_match('#^---\\h+"?(?P[^\\v\\t"]+)#', $lines[$i], $fromMatch) && preg_match('#^\\+\\+\\+\\h+"?(?P[^\\v\\t"]+)#', $lines[$i + 1], $toMatch)) { if ($diff !== null) { $this->parseFileDiff($diff, $collected); $diffs[] = $diff; $collected = []; } $diff = new Diff($fromMatch['file'], $toMatch['file']); ++$i; } else { if (preg_match('/^(?:diff --git |index [\\da-f\\.]+|[+-]{3} [ab])/', $lines[$i])) { continue; } $collected[] = $lines[$i]; } } if ($diff !== null && count($collected)) { $this->parseFileDiff($diff, $collected); $diffs[] = $diff; } return $diffs; } private function parseFileDiff(Diff $diff, array $lines) : void { $chunks = []; $chunk = null; $diffLines = []; foreach ($lines as $line) { if (preg_match('/^@@\\s+-(?P\\d+)(?:,\\s*(?P\\d+))?\\s+\\+(?P\\d+)(?:,\\s*(?P\\d+))?\\s+@@/', $line, $match)) { $chunk = new Chunk((int) $match['start'], isset($match['startrange']) ? max(1, (int) $match['startrange']) : 1, (int) $match['end'], isset($match['endrange']) ? max(1, (int) $match['endrange']) : 1); $chunks[] = $chunk; $diffLines = []; continue; } if (preg_match('/^(?P[+ -])?(?P.*)/', $line, $match)) { $type = Line::UNCHANGED; if ($match['type'] === '+') { $type = Line::ADDED; } elseif ($match['type'] === '-') { $type = Line::REMOVED; } $diffLines[] = new Line($type, $match['line']); if (null !== $chunk) { $chunk->setLines($diffLines); } } } $diff->setChunks($chunks); } } * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace _HumbugBox7ff99e199a36\SebastianBergmann\Diff; final class Diff { /** * @var string */ private $from; /** * @var string */ private $to; /** * @var Chunk[] */ private $chunks; /** * @param Chunk[] $chunks */ public function __construct(string $from, string $to, array $chunks = []) { $this->from = $from; $this->to = $to; $this->chunks = $chunks; } public function getFrom() : string { return $this->from; } public function getTo() : string { return $this->to; } /** * @return Chunk[] */ public function getChunks() : array { return $this->chunks; } /** * @param Chunk[] $chunks */ public function setChunks(array $chunks) : void { $this->chunks = $chunks; } } * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace _HumbugBox7ff99e199a36\SebastianBergmann\Diff; use Throwable; interface Exception extends Throwable { } * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace _HumbugBox7ff99e199a36\SebastianBergmann\Diff; use function get_class; use function gettype; use function is_object; use function sprintf; use Exception; final class ConfigurationException extends InvalidArgumentException { public function __construct(string $option, string $expected, $value, int $code = 0, ?Exception $previous = null) { parent::__construct(sprintf('Option "%s" must be %s, got "%s".', $option, $expected, is_object($value) ? get_class($value) : (null === $value ? '' : gettype($value) . '#' . $value)), $code, $previous); } } * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace _HumbugBox7ff99e199a36\SebastianBergmann\Diff; class InvalidArgumentException extends \InvalidArgumentException implements Exception { } * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace _HumbugBox7ff99e199a36\SebastianBergmann\Diff; use function array_fill; use function array_merge; use function array_reverse; use function array_slice; use function count; use function in_array; use function max; final class MemoryEfficientLongestCommonSubsequenceCalculator implements LongestCommonSubsequenceCalculator { /** * {@inheritdoc} */ public function calculate(array $from, array $to) : array { $cFrom = count($from); $cTo = count($to); if ($cFrom === 0) { return []; } if ($cFrom === 1) { if (in_array($from[0], $to, \true)) { return [$from[0]]; } return []; } $i = (int) ($cFrom / 2); $fromStart = array_slice($from, 0, $i); $fromEnd = array_slice($from, $i); $llB = $this->length($fromStart, $to); $llE = $this->length(array_reverse($fromEnd), array_reverse($to)); $jMax = 0; $max = 0; for ($j = 0; $j <= $cTo; $j++) { $m = $llB[$j] + $llE[$cTo - $j]; if ($m >= $max) { $max = $m; $jMax = $j; } } $toStart = array_slice($to, 0, $jMax); $toEnd = array_slice($to, $jMax); return array_merge($this->calculate($fromStart, $toStart), $this->calculate($fromEnd, $toEnd)); } private function length(array $from, array $to) : array { $current = array_fill(0, count($to) + 1, 0); $cFrom = count($from); $cTo = count($to); for ($i = 0; $i < $cFrom; $i++) { $prev = $current; for ($j = 0; $j < $cTo; $j++) { if ($from[$i] === $to[$j]) { $current[$j + 1] = $prev[$j] + 1; } else { // don't use max() to avoid function call overhead if ($current[$j] > $prev[$j + 1]) { $current[$j + 1] = $current[$j]; } else { $current[$j + 1] = $prev[$j + 1]; } } } } return $current; } } * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace _HumbugBox7ff99e199a36\SebastianBergmann\Diff; final class Line { public const ADDED = 1; public const REMOVED = 2; public const UNCHANGED = 3; /** * @var int */ private $type; /** * @var string */ private $content; public function __construct(int $type = self::UNCHANGED, string $content = '') { $this->type = $type; $this->content = $content; } public function getContent() : string { return $this->content; } public function getType() : int { return $this->type; } } * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace _HumbugBox7ff99e199a36\Symfony\Component\Console\Formatter; use _HumbugBox7ff99e199a36\Symfony\Component\Console\Color; /** * Formatter style class for defining styles. * * @author Konstantin Kudryashov */ class OutputFormatterStyle implements OutputFormatterStyleInterface { private $color; private $foreground; private $background; private $options; private $href; private $handlesHrefGracefully; /** * Initializes output formatter style. * * @param string|null $foreground The style foreground color name * @param string|null $background The style background color name */ public function __construct(?string $foreground = null, ?string $background = null, array $options = []) { $this->color = new Color($this->foreground = $foreground ?: '', $this->background = $background ?: '', $this->options = $options); } /** * {@inheritdoc} */ public function setForeground(?string $color = null) { $this->color = new Color($this->foreground = $color ?: '', $this->background, $this->options); } /** * {@inheritdoc} */ public function setBackground(?string $color = null) { $this->color = new Color($this->foreground, $this->background = $color ?: '', $this->options); } public function setHref(string $url) : void { $this->href = $url; } /** * {@inheritdoc} */ public function setOption(string $option) { $this->options[] = $option; $this->color = new Color($this->foreground, $this->background, $this->options); } /** * {@inheritdoc} */ public function unsetOption(string $option) { $pos = \array_search($option, $this->options); if (\false !== $pos) { unset($this->options[$pos]); } $this->color = new Color($this->foreground, $this->background, $this->options); } /** * {@inheritdoc} */ public function setOptions(array $options) { $this->color = new Color($this->foreground, $this->background, $this->options = $options); } /** * {@inheritdoc} */ public function apply(string $text) { if (null === $this->handlesHrefGracefully) { $this->handlesHrefGracefully = 'JetBrains-JediTerm' !== \getenv('TERMINAL_EMULATOR') && (!\getenv('KONSOLE_VERSION') || (int) \getenv('KONSOLE_VERSION') > 201100) && !isset($_SERVER['IDEA_INITIAL_DIRECTORY']); } if (null !== $this->href && $this->handlesHrefGracefully) { $text = "\x1b]8;;{$this->href}\x1b\\{$text}\x1b]8;;\x1b\\"; } return $this->color->apply($text); } } * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace _HumbugBox7ff99e199a36\Symfony\Component\Console\Formatter; use _HumbugBox7ff99e199a36\Symfony\Component\Console\Exception\InvalidArgumentException; use _HumbugBox7ff99e199a36\Symfony\Contracts\Service\ResetInterface; /** * @author Jean-François Simon */ class OutputFormatterStyleStack implements ResetInterface { /** * @var OutputFormatterStyleInterface[] */ private $styles; private $emptyStyle; public function __construct(?OutputFormatterStyleInterface $emptyStyle = null) { $this->emptyStyle = $emptyStyle ?? new OutputFormatterStyle(); $this->reset(); } /** * Resets stack (ie. empty internal arrays). */ public function reset() { $this->styles = []; } /** * Pushes a style in the stack. */ public function push(OutputFormatterStyleInterface $style) { $this->styles[] = $style; } /** * Pops a style from the stack. * * @return OutputFormatterStyleInterface * * @throws InvalidArgumentException When style tags incorrectly nested */ public function pop(?OutputFormatterStyleInterface $style = null) { if (empty($this->styles)) { return $this->emptyStyle; } if (null === $style) { return \array_pop($this->styles); } foreach (\array_reverse($this->styles, \true) as $index => $stackedStyle) { if ($style->apply('') === $stackedStyle->apply('')) { $this->styles = \array_slice($this->styles, 0, $index); return $stackedStyle; } } throw new InvalidArgumentException('Incorrectly nested style tag found.'); } /** * Computes current style with stacks top codes. * * @return OutputFormatterStyle */ public function getCurrent() { if (empty($this->styles)) { return $this->emptyStyle; } return $this->styles[\count($this->styles) - 1]; } /** * @return $this */ public function setEmptyStyle(OutputFormatterStyleInterface $emptyStyle) { $this->emptyStyle = $emptyStyle; return $this; } /** * @return OutputFormatterStyleInterface */ public function getEmptyStyle() { return $this->emptyStyle; } } * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace _HumbugBox7ff99e199a36\Symfony\Component\Console\Formatter; use _HumbugBox7ff99e199a36\Symfony\Component\Console\Exception\InvalidArgumentException; use function _HumbugBox7ff99e199a36\Symfony\Component\String\b; /** * Formatter class for console output. * * @author Konstantin Kudryashov * @author Roland Franssen */ class OutputFormatter implements WrappableOutputFormatterInterface { private $decorated; private $styles = []; private $styleStack; public function __clone() { $this->styleStack = clone $this->styleStack; foreach ($this->styles as $key => $value) { $this->styles[$key] = clone $value; } } /** * Escapes "<" and ">" special chars in given text. * * @return string */ public static function escape(string $text) { $text = \preg_replace('/([^\\\\]|^)([<>])/', '$1\\\\$2', $text); return self::escapeTrailingBackslash($text); } /** * Escapes trailing "\" in given text. * * @internal */ public static function escapeTrailingBackslash(string $text) : string { if (\str_ends_with($text, '\\')) { $len = \strlen($text); $text = \rtrim($text, '\\'); $text = \str_replace("\x00", '', $text); $text .= \str_repeat("\x00", $len - \strlen($text)); } return $text; } /** * Initializes console output formatter. * * @param OutputFormatterStyleInterface[] $styles Array of "name => FormatterStyle" instances */ public function __construct(bool $decorated = \false, array $styles = []) { $this->decorated = $decorated; $this->setStyle('error', new OutputFormatterStyle('white', 'red')); $this->setStyle('info', new OutputFormatterStyle('green')); $this->setStyle('comment', new OutputFormatterStyle('yellow')); $this->setStyle('question', new OutputFormatterStyle('black', 'cyan')); foreach ($styles as $name => $style) { $this->setStyle($name, $style); } $this->styleStack = new OutputFormatterStyleStack(); } /** * {@inheritdoc} */ public function setDecorated(bool $decorated) { $this->decorated = $decorated; } /** * {@inheritdoc} */ public function isDecorated() { return $this->decorated; } /** * {@inheritdoc} */ public function setStyle(string $name, OutputFormatterStyleInterface $style) { $this->styles[\strtolower($name)] = $style; } /** * {@inheritdoc} */ public function hasStyle(string $name) { return isset($this->styles[\strtolower($name)]); } /** * {@inheritdoc} */ public function getStyle(string $name) { if (!$this->hasStyle($name)) { throw new InvalidArgumentException(\sprintf('Undefined style: "%s".', $name)); } return $this->styles[\strtolower($name)]; } /** * {@inheritdoc} */ public function format(?string $message) { return $this->formatAndWrap($message, 0); } /** * {@inheritdoc} */ public function formatAndWrap(?string $message, int $width) { if (null === $message) { return ''; } $offset = 0; $output = ''; $openTagRegex = '[a-z](?:[^\\\\<>]*+ | \\\\.)*'; $closeTagRegex = '[a-z][^<>]*+'; $currentLineLength = 0; \preg_match_all("#<(({$openTagRegex}) | /({$closeTagRegex})?)>#ix", $message, $matches, \PREG_OFFSET_CAPTURE); foreach ($matches[0] as $i => $match) { $pos = $match[1]; $text = $match[0]; if (0 != $pos && '\\' == $message[$pos - 1]) { continue; } // add the text up to the next tag $output .= $this->applyCurrentStyle(\substr($message, $offset, $pos - $offset), $output, $width, $currentLineLength); $offset = $pos + \strlen($text); // opening tag? if ($open = '/' != $text[1]) { $tag = $matches[1][$i][0]; } else { $tag = $matches[3][$i][0] ?? ''; } if (!$open && !$tag) { // $this->styleStack->pop(); } elseif (null === ($style = $this->createStyleFromString($tag))) { $output .= $this->applyCurrentStyle($text, $output, $width, $currentLineLength); } elseif ($open) { $this->styleStack->push($style); } else { $this->styleStack->pop($style); } } $output .= $this->applyCurrentStyle(\substr($message, $offset), $output, $width, $currentLineLength); return \strtr($output, ["\x00" => '\\', '\\<' => '<', '\\>' => '>']); } /** * @return OutputFormatterStyleStack */ public function getStyleStack() { return $this->styleStack; } /** * Tries to create new style instance from string. */ private function createStyleFromString(string $string) : ?OutputFormatterStyleInterface { if (isset($this->styles[$string])) { return $this->styles[$string]; } if (!\preg_match_all('/([^=]+)=([^;]+)(;|$)/', $string, $matches, \PREG_SET_ORDER)) { return null; } $style = new OutputFormatterStyle(); foreach ($matches as $match) { \array_shift($match); $match[0] = \strtolower($match[0]); if ('fg' == $match[0]) { $style->setForeground(\strtolower($match[1])); } elseif ('bg' == $match[0]) { $style->setBackground(\strtolower($match[1])); } elseif ('href' === $match[0]) { $url = \preg_replace('{\\\\([<>])}', '$1', $match[1]); $style->setHref($url); } elseif ('options' === $match[0]) { \preg_match_all('([^,;]+)', \strtolower($match[1]), $options); $options = \array_shift($options); foreach ($options as $option) { $style->setOption($option); } } else { return null; } } return $style; } /** * Applies current style from stack to text, if must be applied. */ private function applyCurrentStyle(string $text, string $current, int $width, int &$currentLineLength) : string { if ('' === $text) { return ''; } if (!$width) { return $this->isDecorated() ? $this->styleStack->getCurrent()->apply($text) : $text; } if (!$currentLineLength && '' !== $current) { $text = \ltrim($text); } if ($currentLineLength) { $prefix = \substr($text, 0, $i = $width - $currentLineLength) . "\n"; $text = \substr($text, $i); } else { $prefix = ''; } \preg_match('~(\\n)$~', $text, $matches); $text = $prefix . $this->addLineBreaks($text, $width); $text = \rtrim($text, "\n") . ($matches[1] ?? ''); if (!$currentLineLength && '' !== $current && "\n" !== \substr($current, -1)) { $text = "\n" . $text; } $lines = \explode("\n", $text); foreach ($lines as $line) { $currentLineLength += \strlen($line); if ($width <= $currentLineLength) { $currentLineLength = 0; } } if ($this->isDecorated()) { foreach ($lines as $i => $line) { $lines[$i] = $this->styleStack->getCurrent()->apply($line); } } return \implode("\n", $lines); } private function addLineBreaks(string $text, int $width) : string { $encoding = \mb_detect_encoding($text, null, \true) ?: 'UTF-8'; return b($text)->toCodePointString($encoding)->wordwrap($width, "\n", \true)->toByteString($encoding); } } * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace _HumbugBox7ff99e199a36\Symfony\Component\Console\Formatter; /** * @author Tien Xuan Vo */ final class NullOutputFormatter implements OutputFormatterInterface { private $style; /** * {@inheritdoc} */ public function format(?string $message) : ?string { return null; } /** * {@inheritdoc} */ public function getStyle(string $name) : OutputFormatterStyleInterface { // to comply with the interface we must return a OutputFormatterStyleInterface return $this->style ?? ($this->style = new NullOutputFormatterStyle()); } /** * {@inheritdoc} */ public function hasStyle(string $name) : bool { return \false; } /** * {@inheritdoc} */ public function isDecorated() : bool { return \false; } /** * {@inheritdoc} */ public function setDecorated(bool $decorated) : void { // do nothing } /** * {@inheritdoc} */ public function setStyle(string $name, OutputFormatterStyleInterface $style) : void { // do nothing } } * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace _HumbugBox7ff99e199a36\Symfony\Component\Console\Formatter; /** * Formatter interface for console output that supports word wrapping. * * @author Roland Franssen */ interface WrappableOutputFormatterInterface extends OutputFormatterInterface { /** * Formats a message according to the given styles, wrapping at `$width` (0 means no wrapping). */ public function formatAndWrap(?string $message, int $width); } * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace _HumbugBox7ff99e199a36\Symfony\Component\Console\Formatter; /** * @author Tien Xuan Vo */ final class NullOutputFormatterStyle implements OutputFormatterStyleInterface { /** * {@inheritdoc} */ public function apply(string $text) : string { return $text; } /** * {@inheritdoc} */ public function setBackground(?string $color = null) : void { // do nothing } /** * {@inheritdoc} */ public function setForeground(?string $color = null) : void { // do nothing } /** * {@inheritdoc} */ public function setOption(string $option) : void { // do nothing } /** * {@inheritdoc} */ public function setOptions(array $options) : void { // do nothing } /** * {@inheritdoc} */ public function unsetOption(string $option) : void { // do nothing } } * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace _HumbugBox7ff99e199a36\Symfony\Component\Console\Formatter; /** * Formatter style interface for defining styles. * * @author Konstantin Kudryashov */ interface OutputFormatterStyleInterface { /** * Sets style foreground color. */ public function setForeground(?string $color = null); /** * Sets style background color. */ public function setBackground(?string $color = null); /** * Sets some specific style option. */ public function setOption(string $option); /** * Unsets some specific style option. */ public function unsetOption(string $option); /** * Sets multiple style options at once. */ public function setOptions(array $options); /** * Applies the style to a given text. * * @return string */ public function apply(string $text); } * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace _HumbugBox7ff99e199a36\Symfony\Component\Console\Formatter; /** * Formatter interface for console output. * * @author Konstantin Kudryashov */ interface OutputFormatterInterface { /** * Sets the decorated flag. */ public function setDecorated(bool $decorated); /** * Whether the output will decorate messages. * * @return bool */ public function isDecorated(); /** * Sets a new style. */ public function setStyle(string $name, OutputFormatterStyleInterface $style); /** * Checks if output formatter has style with specified name. * * @return bool */ public function hasStyle(string $name); /** * Gets style options from style with specified name. * * @return OutputFormatterStyleInterface * * @throws \InvalidArgumentException When style isn't defined */ public function getStyle(string $name); /** * Formats a message according to the given styles. * * @return string|null */ public function format(?string $message); } * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace _HumbugBox7ff99e199a36\Symfony\Component\Console\Helper; use _HumbugBox7ff99e199a36\Symfony\Component\Console\Formatter\OutputFormatter; /** * The Formatter class provides helpers to format messages. * * @author Fabien Potencier */ class FormatterHelper extends Helper { /** * Formats a message within a section. * * @return string */ public function formatSection(string $section, string $message, string $style = 'info') { return \sprintf('<%s>[%s] %s', $style, $section, $style, $message); } /** * Formats a message as a block of text. * * @param string|array $messages The message to write in the block * * @return string */ public function formatBlock($messages, string $style, bool $large = \false) { if (!\is_array($messages)) { $messages = [$messages]; } $len = 0; $lines = []; foreach ($messages as $message) { $message = OutputFormatter::escape($message); $lines[] = \sprintf($large ? ' %s ' : ' %s ', $message); $len = \max(self::width($message) + ($large ? 4 : 2), $len); } $messages = $large ? [\str_repeat(' ', $len)] : []; for ($i = 0; isset($lines[$i]); ++$i) { $messages[] = $lines[$i] . \str_repeat(' ', $len - self::width($lines[$i])); } if ($large) { $messages[] = \str_repeat(' ', $len); } for ($i = 0; isset($messages[$i]); ++$i) { $messages[$i] = \sprintf('<%s>%s', $style, $messages[$i], $style); } return \implode("\n", $messages); } /** * Truncates a message to the given length. * * @return string */ public function truncate(string $message, int $length, string $suffix = '...') { $computedLength = $length - self::width($suffix); if ($computedLength > self::width($message)) { return $message; } return self::substr($message, 0, $length) . $suffix; } /** * {@inheritdoc} */ public function getName() { return 'formatter'; } } * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace _HumbugBox7ff99e199a36\Symfony\Component\Console\Helper; use _HumbugBox7ff99e199a36\Symfony\Component\Console\Output\OutputInterface; use _HumbugBox7ff99e199a36\Symfony\Component\VarDumper\Cloner\ClonerInterface; use _HumbugBox7ff99e199a36\Symfony\Component\VarDumper\Cloner\VarCloner; use _HumbugBox7ff99e199a36\Symfony\Component\VarDumper\Dumper\CliDumper; /** * @author Roland Franssen */ final class Dumper { private $output; private $dumper; private $cloner; private $handler; public function __construct(OutputInterface $output, ?CliDumper $dumper = null, ?ClonerInterface $cloner = null) { $this->output = $output; $this->dumper = $dumper; $this->cloner = $cloner; if (\class_exists(CliDumper::class)) { $this->handler = function ($var) : string { $dumper = $this->dumper ?? ($this->dumper = new CliDumper(null, null, CliDumper::DUMP_LIGHT_ARRAY | CliDumper::DUMP_COMMA_SEPARATOR)); $dumper->setColors($this->output->isDecorated()); return \rtrim($dumper->dump(($this->cloner ?? ($this->cloner = new VarCloner()))->cloneVar($var)->withRefHandles(\false), \true)); }; } else { $this->handler = function ($var) : string { switch (\true) { case null === $var: return 'null'; case \true === $var: return 'true'; case \false === $var: return 'false'; case \is_string($var): return '"' . $var . '"'; default: return \rtrim(\print_r($var, \true)); } }; } } public function __invoke($var) : string { return ($this->handler)($var); } } * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace _HumbugBox7ff99e199a36\Symfony\Component\Console\Helper; use _HumbugBox7ff99e199a36\Symfony\Component\Console\Descriptor\DescriptorInterface; use _HumbugBox7ff99e199a36\Symfony\Component\Console\Descriptor\JsonDescriptor; use _HumbugBox7ff99e199a36\Symfony\Component\Console\Descriptor\MarkdownDescriptor; use _HumbugBox7ff99e199a36\Symfony\Component\Console\Descriptor\TextDescriptor; use _HumbugBox7ff99e199a36\Symfony\Component\Console\Descriptor\XmlDescriptor; use _HumbugBox7ff99e199a36\Symfony\Component\Console\Exception\InvalidArgumentException; use _HumbugBox7ff99e199a36\Symfony\Component\Console\Output\OutputInterface; /** * This class adds helper method to describe objects in various formats. * * @author Jean-François Simon */ class DescriptorHelper extends Helper { /** * @var DescriptorInterface[] */ private $descriptors = []; public function __construct() { $this->register('txt', new TextDescriptor())->register('xml', new XmlDescriptor())->register('json', new JsonDescriptor())->register('md', new MarkdownDescriptor()); } /** * Describes an object if supported. * * Available options are: * * format: string, the output format name * * raw_text: boolean, sets output type as raw * * @throws InvalidArgumentException when the given format is not supported */ public function describe(OutputInterface $output, ?object $object, array $options = []) { $options = \array_merge(['raw_text' => \false, 'format' => 'txt'], $options); if (!isset($this->descriptors[$options['format']])) { throw new InvalidArgumentException(\sprintf('Unsupported format "%s".', $options['format'])); } $descriptor = $this->descriptors[$options['format']]; $descriptor->describe($output, $object, $options); } /** * Registers a descriptor. * * @return $this */ public function register(string $format, DescriptorInterface $descriptor) { $this->descriptors[$format] = $descriptor; return $this; } /** * {@inheritdoc} */ public function getName() { return 'descriptor'; } public function getFormats() : array { return \array_keys($this->descriptors); } } * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace _HumbugBox7ff99e199a36\Symfony\Component\Console\Helper; use _HumbugBox7ff99e199a36\Symfony\Component\Console\Command\Command; use _HumbugBox7ff99e199a36\Symfony\Component\Console\Exception\InvalidArgumentException; /** * HelperSet represents a set of helpers to be used with a command. * * @author Fabien Potencier * * @implements \IteratorAggregate */ class HelperSet implements \IteratorAggregate { /** @var array */ private $helpers = []; private $command; /** * @param Helper[] $helpers An array of helper */ public function __construct(array $helpers = []) { foreach ($helpers as $alias => $helper) { $this->set($helper, \is_int($alias) ? null : $alias); } } public function set(HelperInterface $helper, ?string $alias = null) { $this->helpers[$helper->getName()] = $helper; if (null !== $alias) { $this->helpers[$alias] = $helper; } $helper->setHelperSet($this); } /** * Returns true if the helper if defined. * * @return bool */ public function has(string $name) { return isset($this->helpers[$name]); } /** * Gets a helper value. * * @return HelperInterface * * @throws InvalidArgumentException if the helper is not defined */ public function get(string $name) { if (!$this->has($name)) { throw new InvalidArgumentException(\sprintf('The helper "%s" is not defined.', $name)); } return $this->helpers[$name]; } /** * @deprecated since Symfony 5.4 */ public function setCommand(?Command $command = null) { trigger_deprecation('symfony/console', '5.4', 'Method "%s()" is deprecated.', __METHOD__); $this->command = $command; } /** * Gets the command associated with this helper set. * * @return Command * * @deprecated since Symfony 5.4 */ public function getCommand() { trigger_deprecation('symfony/console', '5.4', 'Method "%s()" is deprecated.', __METHOD__); return $this->command; } /** * @return \Traversable */ #[\ReturnTypeWillChange] public function getIterator() { return new \ArrayIterator($this->helpers); } } * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace _HumbugBox7ff99e199a36\Symfony\Component\Console\Helper; use _HumbugBox7ff99e199a36\Symfony\Component\Console\Cursor; use _HumbugBox7ff99e199a36\Symfony\Component\Console\Exception\LogicException; use _HumbugBox7ff99e199a36\Symfony\Component\Console\Output\ConsoleOutputInterface; use _HumbugBox7ff99e199a36\Symfony\Component\Console\Output\ConsoleSectionOutput; use _HumbugBox7ff99e199a36\Symfony\Component\Console\Output\OutputInterface; use _HumbugBox7ff99e199a36\Symfony\Component\Console\Terminal; /** * The ProgressBar provides helpers to display progress output. * * @author Fabien Potencier * @author Chris Jones */ final class ProgressBar { public const FORMAT_VERBOSE = 'verbose'; public const FORMAT_VERY_VERBOSE = 'very_verbose'; public const FORMAT_DEBUG = 'debug'; public const FORMAT_NORMAL = 'normal'; private const FORMAT_VERBOSE_NOMAX = 'verbose_nomax'; private const FORMAT_VERY_VERBOSE_NOMAX = 'very_verbose_nomax'; private const FORMAT_DEBUG_NOMAX = 'debug_nomax'; private const FORMAT_NORMAL_NOMAX = 'normal_nomax'; private $barWidth = 28; private $barChar; private $emptyBarChar = '-'; private $progressChar = '>'; private $format; private $internalFormat; private $redrawFreq = 1; private $writeCount; private $lastWriteTime; private $minSecondsBetweenRedraws = 0; private $maxSecondsBetweenRedraws = 1; private $output; private $step = 0; private $max; private $startTime; private $stepWidth; private $percent = 0.0; private $messages = []; private $overwrite = \true; private $terminal; private $previousMessage; private $cursor; private static $formatters; private static $formats; /** * @param int $max Maximum steps (0 if unknown) */ public function __construct(OutputInterface $output, int $max = 0, float $minSecondsBetweenRedraws = 1 / 25) { if ($output instanceof ConsoleOutputInterface) { $output = $output->getErrorOutput(); } $this->output = $output; $this->setMaxSteps($max); $this->terminal = new Terminal(); if (0 < $minSecondsBetweenRedraws) { $this->redrawFreq = null; $this->minSecondsBetweenRedraws = $minSecondsBetweenRedraws; } if (!$this->output->isDecorated()) { // disable overwrite when output does not support ANSI codes. $this->overwrite = \false; // set a reasonable redraw frequency so output isn't flooded $this->redrawFreq = null; } $this->startTime = \time(); $this->cursor = new Cursor($output); } /** * Sets a placeholder formatter for a given name. * * This method also allow you to override an existing placeholder. * * @param string $name The placeholder name (including the delimiter char like %) * @param callable $callable A PHP callable */ public static function setPlaceholderFormatterDefinition(string $name, callable $callable) : void { if (!self::$formatters) { self::$formatters = self::initPlaceholderFormatters(); } self::$formatters[$name] = $callable; } /** * Gets the placeholder formatter for a given name. * * @param string $name The placeholder name (including the delimiter char like %) */ public static function getPlaceholderFormatterDefinition(string $name) : ?callable { if (!self::$formatters) { self::$formatters = self::initPlaceholderFormatters(); } return self::$formatters[$name] ?? null; } /** * Sets a format for a given name. * * This method also allow you to override an existing format. * * @param string $name The format name * @param string $format A format string */ public static function setFormatDefinition(string $name, string $format) : void { if (!self::$formats) { self::$formats = self::initFormats(); } self::$formats[$name] = $format; } /** * Gets the format for a given name. * * @param string $name The format name */ public static function getFormatDefinition(string $name) : ?string { if (!self::$formats) { self::$formats = self::initFormats(); } return self::$formats[$name] ?? null; } /** * Associates a text with a named placeholder. * * The text is displayed when the progress bar is rendered but only * when the corresponding placeholder is part of the custom format line * (by wrapping the name with %). * * @param string $message The text to associate with the placeholder * @param string $name The name of the placeholder */ public function setMessage(string $message, string $name = 'message') { $this->messages[$name] = $message; } /** * @return string|null */ public function getMessage(string $name = 'message') { return $this->messages[$name] ?? null; } public function getStartTime() : int { return $this->startTime; } public function getMaxSteps() : int { return $this->max; } public function getProgress() : int { return $this->step; } private function getStepWidth() : int { return $this->stepWidth; } public function getProgressPercent() : float { return $this->percent; } public function getBarOffset() : float { return \floor($this->max ? $this->percent * $this->barWidth : (null === $this->redrawFreq ? (int) (\min(5, $this->barWidth / 15) * $this->writeCount) : $this->step) % $this->barWidth); } public function getEstimated() : float { if (!$this->step) { return 0; } return \round((\time() - $this->startTime) / $this->step * $this->max); } public function getRemaining() : float { if (!$this->step) { return 0; } return \round((\time() - $this->startTime) / $this->step * ($this->max - $this->step)); } public function setBarWidth(int $size) { $this->barWidth = \max(1, $size); } public function getBarWidth() : int { return $this->barWidth; } public function setBarCharacter(string $char) { $this->barChar = $char; } public function getBarCharacter() : string { return $this->barChar ?? ($this->max ? '=' : $this->emptyBarChar); } public function setEmptyBarCharacter(string $char) { $this->emptyBarChar = $char; } public function getEmptyBarCharacter() : string { return $this->emptyBarChar; } public function setProgressCharacter(string $char) { $this->progressChar = $char; } public function getProgressCharacter() : string { return $this->progressChar; } public function setFormat(string $format) { $this->format = null; $this->internalFormat = $format; } /** * Sets the redraw frequency. * * @param int|null $freq The frequency in steps */ public function setRedrawFrequency(?int $freq) { $this->redrawFreq = null !== $freq ? \max(1, $freq) : null; } public function minSecondsBetweenRedraws(float $seconds) : void { $this->minSecondsBetweenRedraws = $seconds; } public function maxSecondsBetweenRedraws(float $seconds) : void { $this->maxSecondsBetweenRedraws = $seconds; } /** * Returns an iterator that will automatically update the progress bar when iterated. * * @param int|null $max Number of steps to complete the bar (0 if indeterminate), if null it will be inferred from $iterable */ public function iterate(iterable $iterable, ?int $max = null) : iterable { $this->start($max ?? (\is_countable($iterable) ? \count($iterable) : 0)); foreach ($iterable as $key => $value) { (yield $key => $value); $this->advance(); } $this->finish(); } /** * Starts the progress output. * * @param int|null $max Number of steps to complete the bar (0 if indeterminate), null to leave unchanged */ public function start(?int $max = null) { $this->startTime = \time(); $this->step = 0; $this->percent = 0.0; if (null !== $max) { $this->setMaxSteps($max); } $this->display(); } /** * Advances the progress output X steps. * * @param int $step Number of steps to advance */ public function advance(int $step = 1) { $this->setProgress($this->step + $step); } /** * Sets whether to overwrite the progressbar, false for new line. */ public function setOverwrite(bool $overwrite) { $this->overwrite = $overwrite; } public function setProgress(int $step) { if ($this->max && $step > $this->max) { $this->max = $step; } elseif ($step < 0) { $step = 0; } $redrawFreq = $this->redrawFreq ?? ($this->max ?: 10) / 10; $prevPeriod = (int) ($this->step / $redrawFreq); $currPeriod = (int) ($step / $redrawFreq); $this->step = $step; $this->percent = $this->max ? (float) $this->step / $this->max : 0; $timeInterval = \microtime(\true) - $this->lastWriteTime; // Draw regardless of other limits if ($this->max === $step) { $this->display(); return; } // Throttling if ($timeInterval < $this->minSecondsBetweenRedraws) { return; } // Draw each step period, but not too late if ($prevPeriod !== $currPeriod || $timeInterval >= $this->maxSecondsBetweenRedraws) { $this->display(); } } public function setMaxSteps(int $max) { $this->format = null; $this->max = \max(0, $max); $this->stepWidth = $this->max ? Helper::width((string) $this->max) : 4; } /** * Finishes the progress output. */ public function finish() : void { if (!$this->max) { $this->max = $this->step; } if ($this->step === $this->max && !$this->overwrite) { // prevent double 100% output return; } $this->setProgress($this->max); } /** * Outputs the current progress string. */ public function display() : void { if (OutputInterface::VERBOSITY_QUIET === $this->output->getVerbosity()) { return; } if (null === $this->format) { $this->setRealFormat($this->internalFormat ?: $this->determineBestFormat()); } $this->overwrite($this->buildLine()); } /** * Removes the progress bar from the current line. * * This is useful if you wish to write some output * while a progress bar is running. * Call display() to show the progress bar again. */ public function clear() : void { if (!$this->overwrite) { return; } if (null === $this->format) { $this->setRealFormat($this->internalFormat ?: $this->determineBestFormat()); } $this->overwrite(''); } private function setRealFormat(string $format) { // try to use the _nomax variant if available if (!$this->max && null !== self::getFormatDefinition($format . '_nomax')) { $this->format = self::getFormatDefinition($format . '_nomax'); } elseif (null !== self::getFormatDefinition($format)) { $this->format = self::getFormatDefinition($format); } else { $this->format = $format; } } /** * Overwrites a previous message to the output. */ private function overwrite(string $message) : void { if ($this->previousMessage === $message) { return; } $originalMessage = $message; if ($this->overwrite) { if (null !== $this->previousMessage) { if ($this->output instanceof ConsoleSectionOutput) { $messageLines = \explode("\n", $this->previousMessage); $lineCount = \count($messageLines); foreach ($messageLines as $messageLine) { $messageLineLength = Helper::width(Helper::removeDecoration($this->output->getFormatter(), $messageLine)); if ($messageLineLength > $this->terminal->getWidth()) { $lineCount += \floor($messageLineLength / $this->terminal->getWidth()); } } $this->output->clear($lineCount); } else { $lineCount = \substr_count($this->previousMessage, "\n"); for ($i = 0; $i < $lineCount; ++$i) { $this->cursor->moveToColumn(1); $this->cursor->clearLine(); $this->cursor->moveUp(); } $this->cursor->moveToColumn(1); $this->cursor->clearLine(); } } } elseif ($this->step > 0) { $message = \PHP_EOL . $message; } $this->previousMessage = $originalMessage; $this->lastWriteTime = \microtime(\true); $this->output->write($message); ++$this->writeCount; } private function determineBestFormat() : string { switch ($this->output->getVerbosity()) { // OutputInterface::VERBOSITY_QUIET: display is disabled anyway case OutputInterface::VERBOSITY_VERBOSE: return $this->max ? self::FORMAT_VERBOSE : self::FORMAT_VERBOSE_NOMAX; case OutputInterface::VERBOSITY_VERY_VERBOSE: return $this->max ? self::FORMAT_VERY_VERBOSE : self::FORMAT_VERY_VERBOSE_NOMAX; case OutputInterface::VERBOSITY_DEBUG: return $this->max ? self::FORMAT_DEBUG : self::FORMAT_DEBUG_NOMAX; default: return $this->max ? self::FORMAT_NORMAL : self::FORMAT_NORMAL_NOMAX; } } private static function initPlaceholderFormatters() : array { return ['bar' => function (self $bar, OutputInterface $output) { $completeBars = $bar->getBarOffset(); $display = \str_repeat($bar->getBarCharacter(), $completeBars); if ($completeBars < $bar->getBarWidth()) { $emptyBars = $bar->getBarWidth() - $completeBars - Helper::length(Helper::removeDecoration($output->getFormatter(), $bar->getProgressCharacter())); $display .= $bar->getProgressCharacter() . \str_repeat($bar->getEmptyBarCharacter(), $emptyBars); } return $display; }, 'elapsed' => function (self $bar) { return Helper::formatTime(\time() - $bar->getStartTime()); }, 'remaining' => function (self $bar) { if (!$bar->getMaxSteps()) { throw new LogicException('Unable to display the remaining time if the maximum number of steps is not set.'); } return Helper::formatTime($bar->getRemaining()); }, 'estimated' => function (self $bar) { if (!$bar->getMaxSteps()) { throw new LogicException('Unable to display the estimated time if the maximum number of steps is not set.'); } return Helper::formatTime($bar->getEstimated()); }, 'memory' => function (self $bar) { return Helper::formatMemory(\memory_get_usage(\true)); }, 'current' => function (self $bar) { return \str_pad($bar->getProgress(), $bar->getStepWidth(), ' ', \STR_PAD_LEFT); }, 'max' => function (self $bar) { return $bar->getMaxSteps(); }, 'percent' => function (self $bar) { return \floor($bar->getProgressPercent() * 100); }]; } private static function initFormats() : array { return [self::FORMAT_NORMAL => ' %current%/%max% [%bar%] %percent:3s%%', self::FORMAT_NORMAL_NOMAX => ' %current% [%bar%]', self::FORMAT_VERBOSE => ' %current%/%max% [%bar%] %percent:3s%% %elapsed:6s%', self::FORMAT_VERBOSE_NOMAX => ' %current% [%bar%] %elapsed:6s%', self::FORMAT_VERY_VERBOSE => ' %current%/%max% [%bar%] %percent:3s%% %elapsed:6s%/%estimated:-6s%', self::FORMAT_VERY_VERBOSE_NOMAX => ' %current% [%bar%] %elapsed:6s%', self::FORMAT_DEBUG => ' %current%/%max% [%bar%] %percent:3s%% %elapsed:6s%/%estimated:-6s% %memory:6s%', self::FORMAT_DEBUG_NOMAX => ' %current% [%bar%] %elapsed:6s% %memory:6s%']; } private function buildLine() : string { $regex = "{%([a-z\\-_]+)(?:\\:([^%]+))?%}i"; $callback = function ($matches) { if ($formatter = $this::getPlaceholderFormatterDefinition($matches[1])) { $text = $formatter($this, $this->output); } elseif (isset($this->messages[$matches[1]])) { $text = $this->messages[$matches[1]]; } else { return $matches[0]; } if (isset($matches[2])) { $text = \sprintf('%' . $matches[2], $text); } return $text; }; $line = \preg_replace_callback($regex, $callback, $this->format); // gets string length for each sub line with multiline format $linesLength = \array_map(function ($subLine) { return Helper::width(Helper::removeDecoration($this->output->getFormatter(), \rtrim($subLine, "\r"))); }, \explode("\n", $line)); $linesWidth = \max($linesLength); $terminalWidth = $this->terminal->getWidth(); if ($linesWidth <= $terminalWidth) { return $line; } $this->setBarWidth($this->barWidth - $linesWidth + $terminalWidth); return \preg_replace_callback($regex, $callback, $this->format); } } * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace _HumbugBox7ff99e199a36\Symfony\Component\Console\Helper; use _HumbugBox7ff99e199a36\Symfony\Component\Console\Exception\InvalidArgumentException; use _HumbugBox7ff99e199a36\Symfony\Component\Console\Exception\RuntimeException; use _HumbugBox7ff99e199a36\Symfony\Component\Console\Formatter\OutputFormatter; use _HumbugBox7ff99e199a36\Symfony\Component\Console\Formatter\WrappableOutputFormatterInterface; use _HumbugBox7ff99e199a36\Symfony\Component\Console\Output\ConsoleSectionOutput; use _HumbugBox7ff99e199a36\Symfony\Component\Console\Output\OutputInterface; /** * Provides helpers to display a table. * * @author Fabien Potencier * @author Саша Стаменковић * @author Abdellatif Ait boudad * @author Max Grigorian * @author Dany Maillard */ class Table { private const SEPARATOR_TOP = 0; private const SEPARATOR_TOP_BOTTOM = 1; private const SEPARATOR_MID = 2; private const SEPARATOR_BOTTOM = 3; private const BORDER_OUTSIDE = 0; private const BORDER_INSIDE = 1; private $headerTitle; private $footerTitle; /** * Table headers. */ private $headers = []; /** * Table rows. */ private $rows = []; private $horizontal = \false; /** * Column widths cache. */ private $effectiveColumnWidths = []; /** * Number of columns cache. * * @var int */ private $numberOfColumns; /** * @var OutputInterface */ private $output; /** * @var TableStyle */ private $style; /** * @var array */ private $columnStyles = []; /** * User set column widths. * * @var array */ private $columnWidths = []; private $columnMaxWidths = []; /** * @var array|null */ private static $styles; private $rendered = \false; public function __construct(OutputInterface $output) { $this->output = $output; if (!self::$styles) { self::$styles = self::initStyles(); } $this->setStyle('default'); } /** * Sets a style definition. */ public static function setStyleDefinition(string $name, TableStyle $style) { if (!self::$styles) { self::$styles = self::initStyles(); } self::$styles[$name] = $style; } /** * Gets a style definition by name. * * @return TableStyle */ public static function getStyleDefinition(string $name) { if (!self::$styles) { self::$styles = self::initStyles(); } if (isset(self::$styles[$name])) { return self::$styles[$name]; } throw new InvalidArgumentException(\sprintf('Style "%s" is not defined.', $name)); } /** * Sets table style. * * @param TableStyle|string $name The style name or a TableStyle instance * * @return $this */ public function setStyle($name) { $this->style = $this->resolveStyle($name); return $this; } /** * Gets the current table style. * * @return TableStyle */ public function getStyle() { return $this->style; } /** * Sets table column style. * * @param TableStyle|string $name The style name or a TableStyle instance * * @return $this */ public function setColumnStyle(int $columnIndex, $name) { $this->columnStyles[$columnIndex] = $this->resolveStyle($name); return $this; } /** * Gets the current style for a column. * * If style was not set, it returns the global table style. * * @return TableStyle */ public function getColumnStyle(int $columnIndex) { return $this->columnStyles[$columnIndex] ?? $this->getStyle(); } /** * Sets the minimum width of a column. * * @return $this */ public function setColumnWidth(int $columnIndex, int $width) { $this->columnWidths[$columnIndex] = $width; return $this; } /** * Sets the minimum width of all columns. * * @return $this */ public function setColumnWidths(array $widths) { $this->columnWidths = []; foreach ($widths as $index => $width) { $this->setColumnWidth($index, $width); } return $this; } /** * Sets the maximum width of a column. * * Any cell within this column which contents exceeds the specified width will be wrapped into multiple lines, while * formatted strings are preserved. * * @return $this */ public function setColumnMaxWidth(int $columnIndex, int $width) : self { if (!$this->output->getFormatter() instanceof WrappableOutputFormatterInterface) { throw new \LogicException(\sprintf('Setting a maximum column width is only supported when using a "%s" formatter, got "%s".', WrappableOutputFormatterInterface::class, \get_debug_type($this->output->getFormatter()))); } $this->columnMaxWidths[$columnIndex] = $width; return $this; } /** * @return $this */ public function setHeaders(array $headers) { $headers = \array_values($headers); if (!empty($headers) && !\is_array($headers[0])) { $headers = [$headers]; } $this->headers = $headers; return $this; } public function setRows(array $rows) { $this->rows = []; return $this->addRows($rows); } /** * @return $this */ public function addRows(array $rows) { foreach ($rows as $row) { $this->addRow($row); } return $this; } /** * @return $this */ public function addRow($row) { if ($row instanceof TableSeparator) { $this->rows[] = $row; return $this; } if (!\is_array($row)) { throw new InvalidArgumentException('A row must be an array or a TableSeparator instance.'); } $this->rows[] = \array_values($row); return $this; } /** * Adds a row to the table, and re-renders the table. * * @return $this */ public function appendRow($row) : self { if (!$this->output instanceof ConsoleSectionOutput) { throw new RuntimeException(\sprintf('Output should be an instance of "%s" when calling "%s".', ConsoleSectionOutput::class, __METHOD__)); } if ($this->rendered) { $this->output->clear($this->calculateRowCount()); } $this->addRow($row); $this->render(); return $this; } /** * @return $this */ public function setRow($column, array $row) { $this->rows[$column] = $row; return $this; } /** * @return $this */ public function setHeaderTitle(?string $title) : self { $this->headerTitle = $title; return $this; } /** * @return $this */ public function setFooterTitle(?string $title) : self { $this->footerTitle = $title; return $this; } /** * @return $this */ public function setHorizontal(bool $horizontal = \true) : self { $this->horizontal = $horizontal; return $this; } /** * Renders table to output. * * Example: * * +---------------+-----------------------+------------------+ * | ISBN | Title | Author | * +---------------+-----------------------+------------------+ * | 99921-58-10-7 | Divine Comedy | Dante Alighieri | * | 9971-5-0210-0 | A Tale of Two Cities | Charles Dickens | * | 960-425-059-0 | The Lord of the Rings | J. R. R. Tolkien | * +---------------+-----------------------+------------------+ */ public function render() { $divider = new TableSeparator(); if ($this->horizontal) { $rows = []; foreach ($this->headers[0] ?? [] as $i => $header) { $rows[$i] = [$header]; foreach ($this->rows as $row) { if ($row instanceof TableSeparator) { continue; } if (isset($row[$i])) { $rows[$i][] = $row[$i]; } elseif ($rows[$i][0] instanceof TableCell && $rows[$i][0]->getColspan() >= 2) { // Noop, there is a "title" } else { $rows[$i][] = null; } } } } else { $rows = \array_merge($this->headers, [$divider], $this->rows); } $this->calculateNumberOfColumns($rows); $rowGroups = $this->buildTableRows($rows); $this->calculateColumnsWidth($rowGroups); $isHeader = !$this->horizontal; $isFirstRow = $this->horizontal; $hasTitle = (bool) $this->headerTitle; foreach ($rowGroups as $rowGroup) { $isHeaderSeparatorRendered = \false; foreach ($rowGroup as $row) { if ($divider === $row) { $isHeader = \false; $isFirstRow = \true; continue; } if ($row instanceof TableSeparator) { $this->renderRowSeparator(); continue; } if (!$row) { continue; } if ($isHeader && !$isHeaderSeparatorRendered) { $this->renderRowSeparator($isHeader ? self::SEPARATOR_TOP : self::SEPARATOR_TOP_BOTTOM, $hasTitle ? $this->headerTitle : null, $hasTitle ? $this->style->getHeaderTitleFormat() : null); $hasTitle = \false; $isHeaderSeparatorRendered = \true; } if ($isFirstRow) { $this->renderRowSeparator($isHeader ? self::SEPARATOR_TOP : self::SEPARATOR_TOP_BOTTOM, $hasTitle ? $this->headerTitle : null, $hasTitle ? $this->style->getHeaderTitleFormat() : null); $isFirstRow = \false; $hasTitle = \false; } if ($this->horizontal) { $this->renderRow($row, $this->style->getCellRowFormat(), $this->style->getCellHeaderFormat()); } else { $this->renderRow($row, $isHeader ? $this->style->getCellHeaderFormat() : $this->style->getCellRowFormat()); } } } $this->renderRowSeparator(self::SEPARATOR_BOTTOM, $this->footerTitle, $this->style->getFooterTitleFormat()); $this->cleanup(); $this->rendered = \true; } /** * Renders horizontal header separator. * * Example: * * +-----+-----------+-------+ */ private function renderRowSeparator(int $type = self::SEPARATOR_MID, ?string $title = null, ?string $titleFormat = null) { if (0 === ($count = $this->numberOfColumns)) { return; } $borders = $this->style->getBorderChars(); if (!$borders[0] && !$borders[2] && !$this->style->getCrossingChar()) { return; } $crossings = $this->style->getCrossingChars(); if (self::SEPARATOR_MID === $type) { [$horizontal, $leftChar, $midChar, $rightChar] = [$borders[2], $crossings[8], $crossings[0], $crossings[4]]; } elseif (self::SEPARATOR_TOP === $type) { [$horizontal, $leftChar, $midChar, $rightChar] = [$borders[0], $crossings[1], $crossings[2], $crossings[3]]; } elseif (self::SEPARATOR_TOP_BOTTOM === $type) { [$horizontal, $leftChar, $midChar, $rightChar] = [$borders[0], $crossings[9], $crossings[10], $crossings[11]]; } else { [$horizontal, $leftChar, $midChar, $rightChar] = [$borders[0], $crossings[7], $crossings[6], $crossings[5]]; } $markup = $leftChar; for ($column = 0; $column < $count; ++$column) { $markup .= \str_repeat($horizontal, $this->effectiveColumnWidths[$column]); $markup .= $column === $count - 1 ? $rightChar : $midChar; } if (null !== $title) { $titleLength = Helper::width(Helper::removeDecoration($formatter = $this->output->getFormatter(), $formattedTitle = \sprintf($titleFormat, $title))); $markupLength = Helper::width($markup); if ($titleLength > ($limit = $markupLength - 4)) { $titleLength = $limit; $formatLength = Helper::width(Helper::removeDecoration($formatter, \sprintf($titleFormat, ''))); $formattedTitle = \sprintf($titleFormat, Helper::substr($title, 0, $limit - $formatLength - 3) . '...'); } $titleStart = \intdiv($markupLength - $titleLength, 2); if (\false === \mb_detect_encoding($markup, null, \true)) { $markup = \substr_replace($markup, $formattedTitle, $titleStart, $titleLength); } else { $markup = \mb_substr($markup, 0, $titleStart) . $formattedTitle . \mb_substr($markup, $titleStart + $titleLength); } } $this->output->writeln(\sprintf($this->style->getBorderFormat(), $markup)); } /** * Renders vertical column separator. */ private function renderColumnSeparator(int $type = self::BORDER_OUTSIDE) : string { $borders = $this->style->getBorderChars(); return \sprintf($this->style->getBorderFormat(), self::BORDER_OUTSIDE === $type ? $borders[1] : $borders[3]); } /** * Renders table row. * * Example: * * | 9971-5-0210-0 | A Tale of Two Cities | Charles Dickens | */ private function renderRow(array $row, string $cellFormat, ?string $firstCellFormat = null) { $rowContent = $this->renderColumnSeparator(self::BORDER_OUTSIDE); $columns = $this->getRowColumns($row); $last = \count($columns) - 1; foreach ($columns as $i => $column) { if ($firstCellFormat && 0 === $i) { $rowContent .= $this->renderCell($row, $column, $firstCellFormat); } else { $rowContent .= $this->renderCell($row, $column, $cellFormat); } $rowContent .= $this->renderColumnSeparator($last === $i ? self::BORDER_OUTSIDE : self::BORDER_INSIDE); } $this->output->writeln($rowContent); } /** * Renders table cell with padding. */ private function renderCell(array $row, int $column, string $cellFormat) : string { $cell = $row[$column] ?? ''; $width = $this->effectiveColumnWidths[$column]; if ($cell instanceof TableCell && $cell->getColspan() > 1) { // add the width of the following columns(numbers of colspan). foreach (\range($column + 1, $column + $cell->getColspan() - 1) as $nextColumn) { $width += $this->getColumnSeparatorWidth() + $this->effectiveColumnWidths[$nextColumn]; } } // str_pad won't work properly with multi-byte strings, we need to fix the padding if (\false !== ($encoding = \mb_detect_encoding($cell, null, \true))) { $width += \strlen($cell) - \mb_strwidth($cell, $encoding); } $style = $this->getColumnStyle($column); if ($cell instanceof TableSeparator) { return \sprintf($style->getBorderFormat(), \str_repeat($style->getBorderChars()[2], $width)); } $width += Helper::length($cell) - Helper::length(Helper::removeDecoration($this->output->getFormatter(), $cell)); $content = \sprintf($style->getCellRowContentFormat(), $cell); $padType = $style->getPadType(); if ($cell instanceof TableCell && $cell->getStyle() instanceof TableCellStyle) { $isNotStyledByTag = !\preg_match('/^<(\\w+|(\\w+=[\\w,]+;?)*)>.+<\\/(\\w+|(\\w+=\\w+;?)*)?>$/', $cell); if ($isNotStyledByTag) { $cellFormat = $cell->getStyle()->getCellFormat(); if (!\is_string($cellFormat)) { $tag = \http_build_query($cell->getStyle()->getTagOptions(), '', ';'); $cellFormat = '<' . $tag . '>%s'; } if (\strstr($content, '')) { $content = \str_replace('', '', $content); $width -= 3; } if (\strstr($content, '')) { $content = \str_replace('', '', $content); $width -= \strlen(''); } } $padType = $cell->getStyle()->getPadByAlign(); } return \sprintf($cellFormat, \str_pad($content, $width, $style->getPaddingChar(), $padType)); } /** * Calculate number of columns for this table. */ private function calculateNumberOfColumns(array $rows) { $columns = [0]; foreach ($rows as $row) { if ($row instanceof TableSeparator) { continue; } $columns[] = $this->getNumberOfColumns($row); } $this->numberOfColumns = \max($columns); } private function buildTableRows(array $rows) : TableRows { /** @var WrappableOutputFormatterInterface $formatter */ $formatter = $this->output->getFormatter(); $unmergedRows = []; for ($rowKey = 0; $rowKey < \count($rows); ++$rowKey) { $rows = $this->fillNextRows($rows, $rowKey); // Remove any new line breaks and replace it with a new line foreach ($rows[$rowKey] as $column => $cell) { $colspan = $cell instanceof TableCell ? $cell->getColspan() : 1; if (isset($this->columnMaxWidths[$column]) && Helper::width(Helper::removeDecoration($formatter, $cell)) > $this->columnMaxWidths[$column]) { $cell = $formatter->formatAndWrap($cell, $this->columnMaxWidths[$column] * $colspan); } if (!\strstr($cell ?? '', "\n")) { continue; } $eol = \str_contains($cell ?? '', "\r\n") ? "\r\n" : "\n"; $escaped = \implode($eol, \array_map([OutputFormatter::class, 'escapeTrailingBackslash'], \explode($eol, $cell))); $cell = $cell instanceof TableCell ? new TableCell($escaped, ['colspan' => $cell->getColspan()]) : $escaped; $lines = \explode($eol, \str_replace($eol, '' . $eol, $cell)); foreach ($lines as $lineKey => $line) { if ($colspan > 1) { $line = new TableCell($line, ['colspan' => $colspan]); } if (0 === $lineKey) { $rows[$rowKey][$column] = $line; } else { if (!\array_key_exists($rowKey, $unmergedRows) || !\array_key_exists($lineKey, $unmergedRows[$rowKey])) { $unmergedRows[$rowKey][$lineKey] = $this->copyRow($rows, $rowKey); } $unmergedRows[$rowKey][$lineKey][$column] = $line; } } } } return new TableRows(function () use($rows, $unmergedRows) : \Traversable { foreach ($rows as $rowKey => $row) { $rowGroup = [$row instanceof TableSeparator ? $row : $this->fillCells($row)]; if (isset($unmergedRows[$rowKey])) { foreach ($unmergedRows[$rowKey] as $row) { $rowGroup[] = $row instanceof TableSeparator ? $row : $this->fillCells($row); } } (yield $rowGroup); } }); } private function calculateRowCount() : int { $numberOfRows = \count(\iterator_to_array($this->buildTableRows(\array_merge($this->headers, [new TableSeparator()], $this->rows)))); if ($this->headers) { ++$numberOfRows; // Add row for header separator } if (\count($this->rows) > 0) { ++$numberOfRows; // Add row for footer separator } return $numberOfRows; } /** * fill rows that contains rowspan > 1. * * @throws InvalidArgumentException */ private function fillNextRows(array $rows, int $line) : array { $unmergedRows = []; foreach ($rows[$line] as $column => $cell) { if (null !== $cell && !$cell instanceof TableCell && !\is_scalar($cell) && !(\is_object($cell) && \method_exists($cell, '__toString'))) { throw new InvalidArgumentException(\sprintf('A cell must be a TableCell, a scalar or an object implementing "__toString()", "%s" given.', \get_debug_type($cell))); } if ($cell instanceof TableCell && $cell->getRowspan() > 1) { $nbLines = $cell->getRowspan() - 1; $lines = [$cell]; if (\strstr($cell, "\n")) { $eol = \str_contains($cell, "\r\n") ? "\r\n" : "\n"; $lines = \explode($eol, \str_replace($eol, '' . $eol . '', $cell)); $nbLines = \count($lines) > $nbLines ? \substr_count($cell, $eol) : $nbLines; $rows[$line][$column] = new TableCell($lines[0], ['colspan' => $cell->getColspan(), 'style' => $cell->getStyle()]); unset($lines[0]); } // create a two dimensional array (rowspan x colspan) $unmergedRows = \array_replace_recursive(\array_fill($line + 1, $nbLines, []), $unmergedRows); foreach ($unmergedRows as $unmergedRowKey => $unmergedRow) { $value = $lines[$unmergedRowKey - $line] ?? ''; $unmergedRows[$unmergedRowKey][$column] = new TableCell($value, ['colspan' => $cell->getColspan(), 'style' => $cell->getStyle()]); if ($nbLines === $unmergedRowKey - $line) { break; } } } } foreach ($unmergedRows as $unmergedRowKey => $unmergedRow) { // we need to know if $unmergedRow will be merged or inserted into $rows if (isset($rows[$unmergedRowKey]) && \is_array($rows[$unmergedRowKey]) && $this->getNumberOfColumns($rows[$unmergedRowKey]) + $this->getNumberOfColumns($unmergedRows[$unmergedRowKey]) <= $this->numberOfColumns) { foreach ($unmergedRow as $cellKey => $cell) { // insert cell into row at cellKey position \array_splice($rows[$unmergedRowKey], $cellKey, 0, [$cell]); } } else { $row = $this->copyRow($rows, $unmergedRowKey - 1); foreach ($unmergedRow as $column => $cell) { if (!empty($cell)) { $row[$column] = $unmergedRow[$column]; } } \array_splice($rows, $unmergedRowKey, 0, [$row]); } } return $rows; } /** * fill cells for a row that contains colspan > 1. */ private function fillCells(iterable $row) { $newRow = []; foreach ($row as $column => $cell) { $newRow[] = $cell; if ($cell instanceof TableCell && $cell->getColspan() > 1) { foreach (\range($column + 1, $column + $cell->getColspan() - 1) as $position) { // insert empty value at column position $newRow[] = ''; } } } return $newRow ?: $row; } private function copyRow(array $rows, int $line) : array { $row = $rows[$line]; foreach ($row as $cellKey => $cellValue) { $row[$cellKey] = ''; if ($cellValue instanceof TableCell) { $row[$cellKey] = new TableCell('', ['colspan' => $cellValue->getColspan()]); } } return $row; } /** * Gets number of columns by row. */ private function getNumberOfColumns(array $row) : int { $columns = \count($row); foreach ($row as $column) { $columns += $column instanceof TableCell ? $column->getColspan() - 1 : 0; } return $columns; } /** * Gets list of columns for the given row. */ private function getRowColumns(array $row) : array { $columns = \range(0, $this->numberOfColumns - 1); foreach ($row as $cellKey => $cell) { if ($cell instanceof TableCell && $cell->getColspan() > 1) { // exclude grouped columns. $columns = \array_diff($columns, \range($cellKey + 1, $cellKey + $cell->getColspan() - 1)); } } return $columns; } /** * Calculates columns widths. */ private function calculateColumnsWidth(iterable $groups) { for ($column = 0; $column < $this->numberOfColumns; ++$column) { $lengths = []; foreach ($groups as $group) { foreach ($group as $row) { if ($row instanceof TableSeparator) { continue; } foreach ($row as $i => $cell) { if ($cell instanceof TableCell) { $textContent = Helper::removeDecoration($this->output->getFormatter(), $cell); $textLength = Helper::width($textContent); if ($textLength > 0) { $contentColumns = \mb_str_split($textContent, \ceil($textLength / $cell->getColspan())); foreach ($contentColumns as $position => $content) { $row[$i + $position] = $content; } } } } $lengths[] = $this->getCellWidth($row, $column); } } $this->effectiveColumnWidths[$column] = \max($lengths) + Helper::width($this->style->getCellRowContentFormat()) - 2; } } private function getColumnSeparatorWidth() : int { return Helper::width(\sprintf($this->style->getBorderFormat(), $this->style->getBorderChars()[3])); } private function getCellWidth(array $row, int $column) : int { $cellWidth = 0; if (isset($row[$column])) { $cell = $row[$column]; $cellWidth = Helper::width(Helper::removeDecoration($this->output->getFormatter(), $cell)); } $columnWidth = $this->columnWidths[$column] ?? 0; $cellWidth = \max($cellWidth, $columnWidth); return isset($this->columnMaxWidths[$column]) ? \min($this->columnMaxWidths[$column], $cellWidth) : $cellWidth; } /** * Called after rendering to cleanup cache data. */ private function cleanup() { $this->effectiveColumnWidths = []; $this->numberOfColumns = null; } /** * @return array */ private static function initStyles() : array { $borderless = new TableStyle(); $borderless->setHorizontalBorderChars('=')->setVerticalBorderChars(' ')->setDefaultCrossingChar(' '); $compact = new TableStyle(); $compact->setHorizontalBorderChars('')->setVerticalBorderChars('')->setDefaultCrossingChar('')->setCellRowContentFormat('%s '); $styleGuide = new TableStyle(); $styleGuide->setHorizontalBorderChars('-')->setVerticalBorderChars(' ')->setDefaultCrossingChar(' ')->setCellHeaderFormat('%s'); $box = (new TableStyle())->setHorizontalBorderChars('─')->setVerticalBorderChars('│')->setCrossingChars('┼', '┌', '┬', '┐', '┤', '┘', '┴', '└', '├'); $boxDouble = (new TableStyle())->setHorizontalBorderChars('═', '─')->setVerticalBorderChars('║', '│')->setCrossingChars('┼', '╔', '╤', '╗', '╢', '╝', '╧', '╚', '╟', '╠', '╪', '╣'); return ['default' => new TableStyle(), 'borderless' => $borderless, 'compact' => $compact, 'symfony-style-guide' => $styleGuide, 'box' => $box, 'box-double' => $boxDouble]; } private function resolveStyle($name) : TableStyle { if ($name instanceof TableStyle) { return $name; } if (isset(self::$styles[$name])) { return self::$styles[$name]; } throw new InvalidArgumentException(\sprintf('Style "%s" is not defined.', $name)); } } * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace _HumbugBox7ff99e199a36\Symfony\Component\Console\Helper; use _HumbugBox7ff99e199a36\Symfony\Component\Console\Exception\InvalidArgumentException; use _HumbugBox7ff99e199a36\Symfony\Component\Console\Exception\LogicException; /** * Defines the styles for a Table. * * @author Fabien Potencier * @author Саша Стаменковић * @author Dany Maillard */ class TableStyle { private $paddingChar = ' '; private $horizontalOutsideBorderChar = '-'; private $horizontalInsideBorderChar = '-'; private $verticalOutsideBorderChar = '|'; private $verticalInsideBorderChar = '|'; private $crossingChar = '+'; private $crossingTopRightChar = '+'; private $crossingTopMidChar = '+'; private $crossingTopLeftChar = '+'; private $crossingMidRightChar = '+'; private $crossingBottomRightChar = '+'; private $crossingBottomMidChar = '+'; private $crossingBottomLeftChar = '+'; private $crossingMidLeftChar = '+'; private $crossingTopLeftBottomChar = '+'; private $crossingTopMidBottomChar = '+'; private $crossingTopRightBottomChar = '+'; private $headerTitleFormat = ' %s '; private $footerTitleFormat = ' %s '; private $cellHeaderFormat = '%s'; private $cellRowFormat = '%s'; private $cellRowContentFormat = ' %s '; private $borderFormat = '%s'; private $padType = \STR_PAD_RIGHT; /** * Sets padding character, used for cell padding. * * @return $this */ public function setPaddingChar(string $paddingChar) { if (!$paddingChar) { throw new LogicException('The padding char must not be empty.'); } $this->paddingChar = $paddingChar; return $this; } /** * Gets padding character, used for cell padding. * * @return string */ public function getPaddingChar() { return $this->paddingChar; } /** * Sets horizontal border characters. * * * ╔═══════════════╤══════════════════════════╤══════════════════╗ * 1 ISBN 2 Title │ Author ║ * ╠═══════════════╪══════════════════════════╪══════════════════╣ * ║ 99921-58-10-7 │ Divine Comedy │ Dante Alighieri ║ * ║ 9971-5-0210-0 │ A Tale of Two Cities │ Charles Dickens ║ * ║ 960-425-059-0 │ The Lord of the Rings │ J. R. R. Tolkien ║ * ║ 80-902734-1-6 │ And Then There Were None │ Agatha Christie ║ * ╚═══════════════╧══════════════════════════╧══════════════════╝ * * * @return $this */ public function setHorizontalBorderChars(string $outside, ?string $inside = null) : self { $this->horizontalOutsideBorderChar = $outside; $this->horizontalInsideBorderChar = $inside ?? $outside; return $this; } /** * Sets vertical border characters. * * * ╔═══════════════╤══════════════════════════╤══════════════════╗ * ║ ISBN │ Title │ Author ║ * ╠═══════1═══════╪══════════════════════════╪══════════════════╣ * ║ 99921-58-10-7 │ Divine Comedy │ Dante Alighieri ║ * ║ 9971-5-0210-0 │ A Tale of Two Cities │ Charles Dickens ║ * ╟───────2───────┼──────────────────────────┼──────────────────╢ * ║ 960-425-059-0 │ The Lord of the Rings │ J. R. R. Tolkien ║ * ║ 80-902734-1-6 │ And Then There Were None │ Agatha Christie ║ * ╚═══════════════╧══════════════════════════╧══════════════════╝ * * * @return $this */ public function setVerticalBorderChars(string $outside, ?string $inside = null) : self { $this->verticalOutsideBorderChar = $outside; $this->verticalInsideBorderChar = $inside ?? $outside; return $this; } /** * Gets border characters. * * @internal */ public function getBorderChars() : array { return [$this->horizontalOutsideBorderChar, $this->verticalOutsideBorderChar, $this->horizontalInsideBorderChar, $this->verticalInsideBorderChar]; } /** * Sets crossing characters. * * Example: * * 1═══════════════2══════════════════════════2══════════════════3 * ║ ISBN │ Title │ Author ║ * 8'══════════════0'═════════════════════════0'═════════════════4' * ║ 99921-58-10-7 │ Divine Comedy │ Dante Alighieri ║ * ║ 9971-5-0210-0 │ A Tale of Two Cities │ Charles Dickens ║ * 8───────────────0──────────────────────────0──────────────────4 * ║ 960-425-059-0 │ The Lord of the Rings │ J. R. R. Tolkien ║ * ║ 80-902734-1-6 │ And Then There Were None │ Agatha Christie ║ * 7═══════════════6══════════════════════════6══════════════════5 * * * @param string $cross Crossing char (see #0 of example) * @param string $topLeft Top left char (see #1 of example) * @param string $topMid Top mid char (see #2 of example) * @param string $topRight Top right char (see #3 of example) * @param string $midRight Mid right char (see #4 of example) * @param string $bottomRight Bottom right char (see #5 of example) * @param string $bottomMid Bottom mid char (see #6 of example) * @param string $bottomLeft Bottom left char (see #7 of example) * @param string $midLeft Mid left char (see #8 of example) * @param string|null $topLeftBottom Top left bottom char (see #8' of example), equals to $midLeft if null * @param string|null $topMidBottom Top mid bottom char (see #0' of example), equals to $cross if null * @param string|null $topRightBottom Top right bottom char (see #4' of example), equals to $midRight if null * * @return $this */ public function setCrossingChars(string $cross, string $topLeft, string $topMid, string $topRight, string $midRight, string $bottomRight, string $bottomMid, string $bottomLeft, string $midLeft, ?string $topLeftBottom = null, ?string $topMidBottom = null, ?string $topRightBottom = null) : self { $this->crossingChar = $cross; $this->crossingTopLeftChar = $topLeft; $this->crossingTopMidChar = $topMid; $this->crossingTopRightChar = $topRight; $this->crossingMidRightChar = $midRight; $this->crossingBottomRightChar = $bottomRight; $this->crossingBottomMidChar = $bottomMid; $this->crossingBottomLeftChar = $bottomLeft; $this->crossingMidLeftChar = $midLeft; $this->crossingTopLeftBottomChar = $topLeftBottom ?? $midLeft; $this->crossingTopMidBottomChar = $topMidBottom ?? $cross; $this->crossingTopRightBottomChar = $topRightBottom ?? $midRight; return $this; } /** * Sets default crossing character used for each cross. * * @see {@link setCrossingChars()} for setting each crossing individually. */ public function setDefaultCrossingChar(string $char) : self { return $this->setCrossingChars($char, $char, $char, $char, $char, $char, $char, $char, $char); } /** * Gets crossing character. * * @return string */ public function getCrossingChar() { return $this->crossingChar; } /** * Gets crossing characters. * * @internal */ public function getCrossingChars() : array { return [$this->crossingChar, $this->crossingTopLeftChar, $this->crossingTopMidChar, $this->crossingTopRightChar, $this->crossingMidRightChar, $this->crossingBottomRightChar, $this->crossingBottomMidChar, $this->crossingBottomLeftChar, $this->crossingMidLeftChar, $this->crossingTopLeftBottomChar, $this->crossingTopMidBottomChar, $this->crossingTopRightBottomChar]; } /** * Sets header cell format. * * @return $this */ public function setCellHeaderFormat(string $cellHeaderFormat) { $this->cellHeaderFormat = $cellHeaderFormat; return $this; } /** * Gets header cell format. * * @return string */ public function getCellHeaderFormat() { return $this->cellHeaderFormat; } /** * Sets row cell format. * * @return $this */ public function setCellRowFormat(string $cellRowFormat) { $this->cellRowFormat = $cellRowFormat; return $this; } /** * Gets row cell format. * * @return string */ public function getCellRowFormat() { return $this->cellRowFormat; } /** * Sets row cell content format. * * @return $this */ public function setCellRowContentFormat(string $cellRowContentFormat) { $this->cellRowContentFormat = $cellRowContentFormat; return $this; } /** * Gets row cell content format. * * @return string */ public function getCellRowContentFormat() { return $this->cellRowContentFormat; } /** * Sets table border format. * * @return $this */ public function setBorderFormat(string $borderFormat) { $this->borderFormat = $borderFormat; return $this; } /** * Gets table border format. * * @return string */ public function getBorderFormat() { return $this->borderFormat; } /** * Sets cell padding type. * * @return $this */ public function setPadType(int $padType) { if (!\in_array($padType, [\STR_PAD_LEFT, \STR_PAD_RIGHT, \STR_PAD_BOTH], \true)) { throw new InvalidArgumentException('Invalid padding type. Expected one of (STR_PAD_LEFT, STR_PAD_RIGHT, STR_PAD_BOTH).'); } $this->padType = $padType; return $this; } /** * Gets cell padding type. * * @return int */ public function getPadType() { return $this->padType; } public function getHeaderTitleFormat() : string { return $this->headerTitleFormat; } /** * @return $this */ public function setHeaderTitleFormat(string $format) : self { $this->headerTitleFormat = $format; return $this; } public function getFooterTitleFormat() : string { return $this->footerTitleFormat; } /** * @return $this */ public function setFooterTitleFormat(string $format) : self { $this->footerTitleFormat = $format; return $this; } } * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace _HumbugBox7ff99e199a36\Symfony\Component\Console\Helper; use _HumbugBox7ff99e199a36\Symfony\Component\Console\Exception\InvalidArgumentException; use _HumbugBox7ff99e199a36\Symfony\Component\Console\Exception\LogicException; use _HumbugBox7ff99e199a36\Symfony\Component\Console\Output\OutputInterface; /** * @author Kevin Bond */ class ProgressIndicator { private const FORMATS = ['normal' => ' %indicator% %message%', 'normal_no_ansi' => ' %message%', 'verbose' => ' %indicator% %message% (%elapsed:6s%)', 'verbose_no_ansi' => ' %message% (%elapsed:6s%)', 'very_verbose' => ' %indicator% %message% (%elapsed:6s%, %memory:6s%)', 'very_verbose_no_ansi' => ' %message% (%elapsed:6s%, %memory:6s%)']; private $output; private $startTime; private $format; private $message; private $indicatorValues; private $indicatorCurrent; private $indicatorChangeInterval; private $indicatorUpdateTime; private $started = \false; /** * @var array */ private static $formatters; /** * @param int $indicatorChangeInterval Change interval in milliseconds * @param array|null $indicatorValues Animated indicator characters */ public function __construct(OutputInterface $output, ?string $format = null, int $indicatorChangeInterval = 100, ?array $indicatorValues = null) { $this->output = $output; if (null === $format) { $format = $this->determineBestFormat(); } if (null === $indicatorValues) { $indicatorValues = ['-', '\\', '|', '/']; } $indicatorValues = \array_values($indicatorValues); if (2 > \count($indicatorValues)) { throw new InvalidArgumentException('Must have at least 2 indicator value characters.'); } $this->format = self::getFormatDefinition($format); $this->indicatorChangeInterval = $indicatorChangeInterval; $this->indicatorValues = $indicatorValues; $this->startTime = \time(); } /** * Sets the current indicator message. */ public function setMessage(?string $message) { $this->message = $message; $this->display(); } /** * Starts the indicator output. */ public function start(string $message) { if ($this->started) { throw new LogicException('Progress indicator already started.'); } $this->message = $message; $this->started = \true; $this->startTime = \time(); $this->indicatorUpdateTime = $this->getCurrentTimeInMilliseconds() + $this->indicatorChangeInterval; $this->indicatorCurrent = 0; $this->display(); } /** * Advances the indicator. */ public function advance() { if (!$this->started) { throw new LogicException('Progress indicator has not yet been started.'); } if (!$this->output->isDecorated()) { return; } $currentTime = $this->getCurrentTimeInMilliseconds(); if ($currentTime < $this->indicatorUpdateTime) { return; } $this->indicatorUpdateTime = $currentTime + $this->indicatorChangeInterval; ++$this->indicatorCurrent; $this->display(); } /** * Finish the indicator with message. */ public function finish(string $message) { if (!$this->started) { throw new LogicException('Progress indicator has not yet been started.'); } $this->message = $message; $this->display(); $this->output->writeln(''); $this->started = \false; } /** * Gets the format for a given name. * * @return string|null */ public static function getFormatDefinition(string $name) { return self::FORMATS[$name] ?? null; } /** * Sets a placeholder formatter for a given name. * * This method also allow you to override an existing placeholder. */ public static function setPlaceholderFormatterDefinition(string $name, callable $callable) { if (!self::$formatters) { self::$formatters = self::initPlaceholderFormatters(); } self::$formatters[$name] = $callable; } /** * Gets the placeholder formatter for a given name (including the delimiter char like %). * * @return callable|null */ public static function getPlaceholderFormatterDefinition(string $name) { if (!self::$formatters) { self::$formatters = self::initPlaceholderFormatters(); } return self::$formatters[$name] ?? null; } private function display() { if (OutputInterface::VERBOSITY_QUIET === $this->output->getVerbosity()) { return; } $this->overwrite(\preg_replace_callback("{%([a-z\\-_]+)(?:\\:([^%]+))?%}i", function ($matches) { if ($formatter = self::getPlaceholderFormatterDefinition($matches[1])) { return $formatter($this); } return $matches[0]; }, $this->format ?? '')); } private function determineBestFormat() : string { switch ($this->output->getVerbosity()) { // OutputInterface::VERBOSITY_QUIET: display is disabled anyway case OutputInterface::VERBOSITY_VERBOSE: return $this->output->isDecorated() ? 'verbose' : 'verbose_no_ansi'; case OutputInterface::VERBOSITY_VERY_VERBOSE: case OutputInterface::VERBOSITY_DEBUG: return $this->output->isDecorated() ? 'very_verbose' : 'very_verbose_no_ansi'; default: return $this->output->isDecorated() ? 'normal' : 'normal_no_ansi'; } } /** * Overwrites a previous message to the output. */ private function overwrite(string $message) { if ($this->output->isDecorated()) { $this->output->write("\r\x1b[2K"); $this->output->write($message); } else { $this->output->writeln($message); } } private function getCurrentTimeInMilliseconds() : float { return \round(\microtime(\true) * 1000); } private static function initPlaceholderFormatters() : array { return ['indicator' => function (self $indicator) { return $indicator->indicatorValues[$indicator->indicatorCurrent % \count($indicator->indicatorValues)]; }, 'message' => function (self $indicator) { return $indicator->message; }, 'elapsed' => function (self $indicator) { return Helper::formatTime(\time() - $indicator->startTime); }, 'memory' => function () { return Helper::formatMemory(\memory_get_usage(\true)); }]; } } * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace _HumbugBox7ff99e199a36\Symfony\Component\Console\Helper; use _HumbugBox7ff99e199a36\Symfony\Component\Console\Output\ConsoleOutputInterface; use _HumbugBox7ff99e199a36\Symfony\Component\Console\Output\OutputInterface; use _HumbugBox7ff99e199a36\Symfony\Component\Process\Exception\ProcessFailedException; use _HumbugBox7ff99e199a36\Symfony\Component\Process\Process; /** * The ProcessHelper class provides helpers to run external processes. * * @author Fabien Potencier * * @final */ class ProcessHelper extends Helper { /** * Runs an external process. * * @param array|Process $cmd An instance of Process or an array of the command and arguments * @param callable|null $callback A PHP callback to run whenever there is some * output available on STDOUT or STDERR */ public function run(OutputInterface $output, $cmd, ?string $error = null, ?callable $callback = null, int $verbosity = OutputInterface::VERBOSITY_VERY_VERBOSE) : Process { if (!\class_exists(Process::class)) { throw new \LogicException('The ProcessHelper cannot be run as the Process component is not installed. Try running "compose require symfony/process".'); } if ($output instanceof ConsoleOutputInterface) { $output = $output->getErrorOutput(); } $formatter = $this->getHelperSet()->get('debug_formatter'); if ($cmd instanceof Process) { $cmd = [$cmd]; } if (!\is_array($cmd)) { throw new \TypeError(\sprintf('The "command" argument of "%s()" must be an array or a "%s" instance, "%s" given.', __METHOD__, Process::class, \get_debug_type($cmd))); } if (\is_string($cmd[0] ?? null)) { $process = new Process($cmd); $cmd = []; } elseif (($cmd[0] ?? null) instanceof Process) { $process = $cmd[0]; unset($cmd[0]); } else { throw new \InvalidArgumentException(\sprintf('Invalid command provided to "%s()": the command should be an array whose first element is either the path to the binary to run or a "Process" object.', __METHOD__)); } if ($verbosity <= $output->getVerbosity()) { $output->write($formatter->start(\spl_object_hash($process), $this->escapeString($process->getCommandLine()))); } if ($output->isDebug()) { $callback = $this->wrapCallback($output, $process, $callback); } $process->run($callback, $cmd); if ($verbosity <= $output->getVerbosity()) { $message = $process->isSuccessful() ? 'Command ran successfully' : \sprintf('%s Command did not run successfully', $process->getExitCode()); $output->write($formatter->stop(\spl_object_hash($process), $message, $process->isSuccessful())); } if (!$process->isSuccessful() && null !== $error) { $output->writeln(\sprintf('%s', $this->escapeString($error))); } return $process; } /** * Runs the process. * * This is identical to run() except that an exception is thrown if the process * exits with a non-zero exit code. * * @param array|Process $cmd An instance of Process or a command to run * @param callable|null $callback A PHP callback to run whenever there is some * output available on STDOUT or STDERR * * @throws ProcessFailedException * * @see run() */ public function mustRun(OutputInterface $output, $cmd, ?string $error = null, ?callable $callback = null) : Process { $process = $this->run($output, $cmd, $error, $callback); if (!$process->isSuccessful()) { throw new ProcessFailedException($process); } return $process; } /** * Wraps a Process callback to add debugging output. */ public function wrapCallback(OutputInterface $output, Process $process, ?callable $callback = null) : callable { if ($output instanceof ConsoleOutputInterface) { $output = $output->getErrorOutput(); } $formatter = $this->getHelperSet()->get('debug_formatter'); return function ($type, $buffer) use($output, $process, $callback, $formatter) { $output->write($formatter->progress(\spl_object_hash($process), $this->escapeString($buffer), Process::ERR === $type)); if (null !== $callback) { $callback($type, $buffer); } }; } private function escapeString(string $str) : string { return \str_replace('<', '\\<', $str); } /** * {@inheritdoc} */ public function getName() : string { return 'process'; } } * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace _HumbugBox7ff99e199a36\Symfony\Component\Console\Helper; /** * Helps outputting debug information when running an external program from a command. * * An external program can be a Process, an HTTP request, or anything else. * * @author Fabien Potencier */ class DebugFormatterHelper extends Helper { private const COLORS = ['black', 'red', 'green', 'yellow', 'blue', 'magenta', 'cyan', 'white', 'default']; private $started = []; private $count = -1; /** * Starts a debug formatting session. * * @return string */ public function start(string $id, string $message, string $prefix = 'RUN') { $this->started[$id] = ['border' => ++$this->count % \count(self::COLORS)]; return \sprintf("%s %s %s\n", $this->getBorder($id), $prefix, $message); } /** * Adds progress to a formatting session. * * @return string */ public function progress(string $id, string $buffer, bool $error = \false, string $prefix = 'OUT', string $errorPrefix = 'ERR') { $message = ''; if ($error) { if (isset($this->started[$id]['out'])) { $message .= "\n"; unset($this->started[$id]['out']); } if (!isset($this->started[$id]['err'])) { $message .= \sprintf('%s %s ', $this->getBorder($id), $errorPrefix); $this->started[$id]['err'] = \true; } $message .= \str_replace("\n", \sprintf("\n%s %s ", $this->getBorder($id), $errorPrefix), $buffer); } else { if (isset($this->started[$id]['err'])) { $message .= "\n"; unset($this->started[$id]['err']); } if (!isset($this->started[$id]['out'])) { $message .= \sprintf('%s %s ', $this->getBorder($id), $prefix); $this->started[$id]['out'] = \true; } $message .= \str_replace("\n", \sprintf("\n%s %s ", $this->getBorder($id), $prefix), $buffer); } return $message; } /** * Stops a formatting session. * * @return string */ public function stop(string $id, string $message, bool $successful, string $prefix = 'RES') { $trailingEOL = isset($this->started[$id]['out']) || isset($this->started[$id]['err']) ? "\n" : ''; if ($successful) { return \sprintf("%s%s %s %s\n", $trailingEOL, $this->getBorder($id), $prefix, $message); } $message = \sprintf("%s%s %s %s\n", $trailingEOL, $this->getBorder($id), $prefix, $message); unset($this->started[$id]['out'], $this->started[$id]['err']); return $message; } private function getBorder(string $id) : string { return \sprintf(' ', self::COLORS[$this->started[$id]['border']]); } /** * {@inheritdoc} */ public function getName() { return 'debug_formatter'; } } * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace _HumbugBox7ff99e199a36\Symfony\Component\Console\Helper; use _HumbugBox7ff99e199a36\Symfony\Component\Console\Input\InputAwareInterface; use _HumbugBox7ff99e199a36\Symfony\Component\Console\Input\InputInterface; /** * An implementation of InputAwareInterface for Helpers. * * @author Wouter J */ abstract class InputAwareHelper extends Helper implements InputAwareInterface { protected $input; /** * {@inheritdoc} */ public function setInput(InputInterface $input) { $this->input = $input; } } * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace _HumbugBox7ff99e199a36\Symfony\Component\Console\Helper; use _HumbugBox7ff99e199a36\Symfony\Component\Console\Formatter\OutputFormatter; use _HumbugBox7ff99e199a36\Symfony\Component\Console\Output\OutputInterface; use _HumbugBox7ff99e199a36\Symfony\Component\Console\Question\ChoiceQuestion; use _HumbugBox7ff99e199a36\Symfony\Component\Console\Question\ConfirmationQuestion; use _HumbugBox7ff99e199a36\Symfony\Component\Console\Question\Question; use _HumbugBox7ff99e199a36\Symfony\Component\Console\Style\SymfonyStyle; /** * Symfony Style Guide compliant question helper. * * @author Kevin Bond */ class SymfonyQuestionHelper extends QuestionHelper { /** * {@inheritdoc} */ protected function writePrompt(OutputInterface $output, Question $question) { $text = OutputFormatter::escapeTrailingBackslash($question->getQuestion()); $default = $question->getDefault(); if ($question->isMultiline()) { $text .= \sprintf(' (press %s to continue)', $this->getEofShortcut()); } switch (\true) { case null === $default: $text = \sprintf(' %s:', $text); break; case $question instanceof ConfirmationQuestion: $text = \sprintf(' %s (yes/no) [%s]:', $text, $default ? 'yes' : 'no'); break; case $question instanceof ChoiceQuestion && $question->isMultiselect(): $choices = $question->getChoices(); $default = \explode(',', $default); foreach ($default as $key => $value) { $default[$key] = $choices[\trim($value)]; } $text = \sprintf(' %s [%s]:', $text, OutputFormatter::escape(\implode(', ', $default))); break; case $question instanceof ChoiceQuestion: $choices = $question->getChoices(); $text = \sprintf(' %s [%s]:', $text, OutputFormatter::escape($choices[$default] ?? $default)); break; default: $text = \sprintf(' %s [%s]:', $text, OutputFormatter::escape($default)); } $output->writeln($text); $prompt = ' > '; if ($question instanceof ChoiceQuestion) { $output->writeln($this->formatChoiceQuestionChoices($question, 'comment')); $prompt = $question->getPrompt(); } $output->write($prompt); } /** * {@inheritdoc} */ protected function writeError(OutputInterface $output, \Exception $error) { if ($output instanceof SymfonyStyle) { $output->newLine(); $output->error($error->getMessage()); return; } parent::writeError($output, $error); } private function getEofShortcut() : string { if ('Windows' === \PHP_OS_FAMILY) { return 'Ctrl+Z then Enter'; } return 'Ctrl+D'; } } * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace _HumbugBox7ff99e199a36\Symfony\Component\Console\Helper; use _HumbugBox7ff99e199a36\Symfony\Component\Console\Formatter\OutputFormatterInterface; use _HumbugBox7ff99e199a36\Symfony\Component\String\UnicodeString; /** * Helper is the base class for all helper classes. * * @author Fabien Potencier */ abstract class Helper implements HelperInterface { protected $helperSet = null; /** * {@inheritdoc} */ public function setHelperSet(?HelperSet $helperSet = null) { $this->helperSet = $helperSet; } /** * {@inheritdoc} */ public function getHelperSet() { return $this->helperSet; } /** * Returns the length of a string, using mb_strwidth if it is available. * * @deprecated since Symfony 5.3 * * @return int */ public static function strlen(?string $string) { trigger_deprecation('symfony/console', '5.3', 'Method "%s()" is deprecated and will be removed in Symfony 6.0. Use Helper::width() or Helper::length() instead.', __METHOD__); return self::width($string); } /** * Returns the width of a string, using mb_strwidth if it is available. * The width is how many characters positions the string will use. */ public static function width(?string $string) : int { $string ?? ($string = ''); if (\preg_match('//u', $string)) { return (new UnicodeString($string))->width(\false); } if (\false === ($encoding = \mb_detect_encoding($string, null, \true))) { return \strlen($string); } return \mb_strwidth($string, $encoding); } /** * Returns the length of a string, using mb_strlen if it is available. * The length is related to how many bytes the string will use. */ public static function length(?string $string) : int { $string ?? ($string = ''); if (\preg_match('//u', $string)) { return (new UnicodeString($string))->length(); } if (\false === ($encoding = \mb_detect_encoding($string, null, \true))) { return \strlen($string); } return \mb_strlen($string, $encoding); } /** * Returns the subset of a string, using mb_substr if it is available. * * @return string */ public static function substr(?string $string, int $from, ?int $length = null) { $string ?? ($string = ''); if (\false === ($encoding = \mb_detect_encoding($string, null, \true))) { return \substr($string, $from, $length); } return \mb_substr($string, $from, $length, $encoding); } public static function formatTime($secs) { static $timeFormats = [[0, '< 1 sec'], [1, '1 sec'], [2, 'secs', 1], [60, '1 min'], [120, 'mins', 60], [3600, '1 hr'], [7200, 'hrs', 3600], [86400, '1 day'], [172800, 'days', 86400]]; foreach ($timeFormats as $index => $format) { if ($secs >= $format[0]) { if (isset($timeFormats[$index + 1]) && $secs < $timeFormats[$index + 1][0] || $index == \count($timeFormats) - 1) { if (2 == \count($format)) { return $format[1]; } return \floor($secs / $format[2]) . ' ' . $format[1]; } } } } public static function formatMemory(int $memory) { if ($memory >= 1024 * 1024 * 1024) { return \sprintf('%.1f GiB', $memory / 1024 / 1024 / 1024); } if ($memory >= 1024 * 1024) { return \sprintf('%.1f MiB', $memory / 1024 / 1024); } if ($memory >= 1024) { return \sprintf('%d KiB', $memory / 1024); } return \sprintf('%d B', $memory); } /** * @deprecated since Symfony 5.3 */ public static function strlenWithoutDecoration(OutputFormatterInterface $formatter, ?string $string) { trigger_deprecation('symfony/console', '5.3', 'Method "%s()" is deprecated and will be removed in Symfony 6.0. Use Helper::removeDecoration() instead.', __METHOD__); return self::width(self::removeDecoration($formatter, $string)); } public static function removeDecoration(OutputFormatterInterface $formatter, ?string $string) { $isDecorated = $formatter->isDecorated(); $formatter->setDecorated(\false); // remove <...> formatting $string = $formatter->format($string ?? ''); // remove already formatted characters $string = \preg_replace("/\x1b\\[[^m]*m/", '', $string ?? ''); // remove terminal hyperlinks $string = \preg_replace('/\\033]8;[^;]*;[^\\033]*\\033\\\\/', '', $string ?? ''); $formatter->setDecorated($isDecorated); return $string; } } * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace _HumbugBox7ff99e199a36\Symfony\Component\Console\Helper; /** * Marks a row as being a separator. * * @author Fabien Potencier */ class TableSeparator extends TableCell { public function __construct(array $options = []) { parent::__construct('', $options); } } * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace _HumbugBox7ff99e199a36\Symfony\Component\Console\Helper; use _HumbugBox7ff99e199a36\Symfony\Component\Console\Cursor; use _HumbugBox7ff99e199a36\Symfony\Component\Console\Exception\MissingInputException; use _HumbugBox7ff99e199a36\Symfony\Component\Console\Exception\RuntimeException; use _HumbugBox7ff99e199a36\Symfony\Component\Console\Formatter\OutputFormatter; use _HumbugBox7ff99e199a36\Symfony\Component\Console\Formatter\OutputFormatterStyle; use _HumbugBox7ff99e199a36\Symfony\Component\Console\Input\InputInterface; use _HumbugBox7ff99e199a36\Symfony\Component\Console\Input\StreamableInputInterface; use _HumbugBox7ff99e199a36\Symfony\Component\Console\Output\ConsoleOutputInterface; use _HumbugBox7ff99e199a36\Symfony\Component\Console\Output\ConsoleSectionOutput; use _HumbugBox7ff99e199a36\Symfony\Component\Console\Output\OutputInterface; use _HumbugBox7ff99e199a36\Symfony\Component\Console\Question\ChoiceQuestion; use _HumbugBox7ff99e199a36\Symfony\Component\Console\Question\Question; use _HumbugBox7ff99e199a36\Symfony\Component\Console\Terminal; use function _HumbugBox7ff99e199a36\Symfony\Component\String\s; /** * The QuestionHelper class provides helpers to interact with the user. * * @author Fabien Potencier */ class QuestionHelper extends Helper { /** * @var resource|null */ private $inputStream; private static $stty = \true; private static $stdinIsInteractive; /** * Asks a question to the user. * * @return mixed The user answer * * @throws RuntimeException If there is no data to read in the input stream */ public function ask(InputInterface $input, OutputInterface $output, Question $question) { if ($output instanceof ConsoleOutputInterface) { $output = $output->getErrorOutput(); } if (!$input->isInteractive()) { return $this->getDefaultAnswer($question); } if ($input instanceof StreamableInputInterface && ($stream = $input->getStream())) { $this->inputStream = $stream; } try { if (!$question->getValidator()) { return $this->doAsk($output, $question); } $interviewer = function () use($output, $question) { return $this->doAsk($output, $question); }; return $this->validateAttempts($interviewer, $output, $question); } catch (MissingInputException $exception) { $input->setInteractive(\false); if (null === ($fallbackOutput = $this->getDefaultAnswer($question))) { throw $exception; } return $fallbackOutput; } } /** * {@inheritdoc} */ public function getName() { return 'question'; } /** * Prevents usage of stty. */ public static function disableStty() { self::$stty = \false; } /** * Asks the question to the user. * * @return mixed * * @throws RuntimeException In case the fallback is deactivated and the response cannot be hidden */ private function doAsk(OutputInterface $output, Question $question) { $this->writePrompt($output, $question); $inputStream = $this->inputStream ?: \STDIN; $autocomplete = $question->getAutocompleterCallback(); if (null === $autocomplete || !self::$stty || !Terminal::hasSttyAvailable()) { $ret = \false; if ($question->isHidden()) { try { $hiddenResponse = $this->getHiddenResponse($output, $inputStream, $question->isTrimmable()); $ret = $question->isTrimmable() ? \trim($hiddenResponse) : $hiddenResponse; } catch (RuntimeException $e) { if (!$question->isHiddenFallback()) { throw $e; } } } if (\false === $ret) { $isBlocked = \stream_get_meta_data($inputStream)['blocked'] ?? \true; if (!$isBlocked) { \stream_set_blocking($inputStream, \true); } $ret = $this->readInput($inputStream, $question); if (!$isBlocked) { \stream_set_blocking($inputStream, \false); } if (\false === $ret) { throw new MissingInputException('Aborted.'); } if ($question->isTrimmable()) { $ret = \trim($ret); } } } else { $autocomplete = $this->autocomplete($output, $question, $inputStream, $autocomplete); $ret = $question->isTrimmable() ? \trim($autocomplete) : $autocomplete; } if ($output instanceof ConsoleSectionOutput) { $output->addContent($ret); } $ret = \strlen($ret) > 0 ? $ret : $question->getDefault(); if ($normalizer = $question->getNormalizer()) { return $normalizer($ret); } return $ret; } /** * @return mixed */ private function getDefaultAnswer(Question $question) { $default = $question->getDefault(); if (null === $default) { return $default; } if ($validator = $question->getValidator()) { return \call_user_func($question->getValidator(), $default); } elseif ($question instanceof ChoiceQuestion) { $choices = $question->getChoices(); if (!$question->isMultiselect()) { return $choices[$default] ?? $default; } $default = \explode(',', $default); foreach ($default as $k => $v) { $v = $question->isTrimmable() ? \trim($v) : $v; $default[$k] = $choices[$v] ?? $v; } } return $default; } /** * Outputs the question prompt. */ protected function writePrompt(OutputInterface $output, Question $question) { $message = $question->getQuestion(); if ($question instanceof ChoiceQuestion) { $output->writeln(\array_merge([$question->getQuestion()], $this->formatChoiceQuestionChoices($question, 'info'))); $message = $question->getPrompt(); } $output->write($message); } /** * @return string[] */ protected function formatChoiceQuestionChoices(ChoiceQuestion $question, string $tag) { $messages = []; $maxWidth = \max(\array_map([__CLASS__, 'width'], \array_keys($choices = $question->getChoices()))); foreach ($choices as $key => $value) { $padding = \str_repeat(' ', $maxWidth - self::width($key)); $messages[] = \sprintf(" [<{$tag}>%s{$padding}] %s", $key, $value); } return $messages; } /** * Outputs an error message. */ protected function writeError(OutputInterface $output, \Exception $error) { if (null !== $this->getHelperSet() && $this->getHelperSet()->has('formatter')) { $message = $this->getHelperSet()->get('formatter')->formatBlock($error->getMessage(), 'error'); } else { $message = '' . $error->getMessage() . ''; } $output->writeln($message); } /** * Autocompletes a question. * * @param resource $inputStream */ private function autocomplete(OutputInterface $output, Question $question, $inputStream, callable $autocomplete) : string { $cursor = new Cursor($output, $inputStream); $fullChoice = ''; $ret = ''; $i = 0; $ofs = -1; $matches = $autocomplete($ret); $numMatches = \count($matches); $sttyMode = \shell_exec('stty -g'); $isStdin = 'php://stdin' === (\stream_get_meta_data($inputStream)['uri'] ?? null); $r = [$inputStream]; $w = []; // Disable icanon (so we can fread each keypress) and echo (we'll do echoing here instead) \shell_exec('stty -icanon -echo'); // Add highlighted text style $output->getFormatter()->setStyle('hl', new OutputFormatterStyle('black', 'white')); // Read a keypress while (!\feof($inputStream)) { while ($isStdin && 0 === @\stream_select($r, $w, $w, 0, 100)) { // Give signal handlers a chance to run $r = [$inputStream]; } $c = \fread($inputStream, 1); // as opposed to fgets(), fread() returns an empty string when the stream content is empty, not false. if (\false === $c || '' === $ret && '' === $c && null === $question->getDefault()) { \shell_exec('stty ' . $sttyMode); throw new MissingInputException('Aborted.'); } elseif ("" === $c) { // Backspace Character if (0 === $numMatches && 0 !== $i) { --$i; $cursor->moveLeft(s($fullChoice)->slice(-1)->width(\false)); $fullChoice = self::substr($fullChoice, 0, $i); } if (0 === $i) { $ofs = -1; $matches = $autocomplete($ret); $numMatches = \count($matches); } else { $numMatches = 0; } // Pop the last character off the end of our string $ret = self::substr($ret, 0, $i); } elseif ("\x1b" === $c) { // Did we read an escape sequence? $c .= \fread($inputStream, 2); // A = Up Arrow. B = Down Arrow if (isset($c[2]) && ('A' === $c[2] || 'B' === $c[2])) { if ('A' === $c[2] && -1 === $ofs) { $ofs = 0; } if (0 === $numMatches) { continue; } $ofs += 'A' === $c[2] ? -1 : 1; $ofs = ($numMatches + $ofs) % $numMatches; } } elseif (\ord($c) < 32) { if ("\t" === $c || "\n" === $c) { if ($numMatches > 0 && -1 !== $ofs) { $ret = (string) $matches[$ofs]; // Echo out remaining chars for current match $remainingCharacters = \substr($ret, \strlen(\trim($this->mostRecentlyEnteredValue($fullChoice)))); $output->write($remainingCharacters); $fullChoice .= $remainingCharacters; $i = \false === ($encoding = \mb_detect_encoding($fullChoice, null, \true)) ? \strlen($fullChoice) : \mb_strlen($fullChoice, $encoding); $matches = \array_filter($autocomplete($ret), function ($match) use($ret) { return '' === $ret || \str_starts_with($match, $ret); }); $numMatches = \count($matches); $ofs = -1; } if ("\n" === $c) { $output->write($c); break; } $numMatches = 0; } continue; } else { if ("\x80" <= $c) { $c .= \fread($inputStream, ["\xc0" => 1, "\xd0" => 1, "\xe0" => 2, "\xf0" => 3][$c & "\xf0"]); } $output->write($c); $ret .= $c; $fullChoice .= $c; ++$i; $tempRet = $ret; if ($question instanceof ChoiceQuestion && $question->isMultiselect()) { $tempRet = $this->mostRecentlyEnteredValue($fullChoice); } $numMatches = 0; $ofs = 0; foreach ($autocomplete($ret) as $value) { // If typed characters match the beginning chunk of value (e.g. [AcmeDe]moBundle) if (\str_starts_with($value, $tempRet)) { $matches[$numMatches++] = $value; } } } $cursor->clearLineAfter(); if ($numMatches > 0 && -1 !== $ofs) { $cursor->savePosition(); // Write highlighted text, complete the partially entered response $charactersEntered = \strlen(\trim($this->mostRecentlyEnteredValue($fullChoice))); $output->write('' . OutputFormatter::escapeTrailingBackslash(\substr($matches[$ofs], $charactersEntered)) . ''); $cursor->restorePosition(); } } // Reset stty so it behaves normally again \shell_exec('stty ' . $sttyMode); return $fullChoice; } private function mostRecentlyEnteredValue(string $entered) : string { // Determine the most recent value that the user entered if (!\str_contains($entered, ',')) { return $entered; } $choices = \explode(',', $entered); if ('' !== ($lastChoice = \trim($choices[\count($choices) - 1]))) { return $lastChoice; } return $entered; } /** * Gets a hidden response from user. * * @param resource $inputStream The handler resource * @param bool $trimmable Is the answer trimmable * * @throws RuntimeException In case the fallback is deactivated and the response cannot be hidden */ private function getHiddenResponse(OutputInterface $output, $inputStream, bool $trimmable = \true) : string { if ('\\' === \DIRECTORY_SEPARATOR) { $exe = __DIR__ . '/../Resources/bin/hiddeninput.exe'; // handle code running from a phar if ('phar:' === \substr(__FILE__, 0, 5)) { $tmpExe = \sys_get_temp_dir() . '/hiddeninput.exe'; \copy($exe, $tmpExe); $exe = $tmpExe; } $sExec = \shell_exec('"' . $exe . '"'); $value = $trimmable ? \rtrim($sExec) : $sExec; $output->writeln(''); if (isset($tmpExe)) { \unlink($tmpExe); } return $value; } if (self::$stty && Terminal::hasSttyAvailable()) { $sttyMode = \shell_exec('stty -g'); \shell_exec('stty -echo'); } elseif ($this->isInteractiveInput($inputStream)) { throw new RuntimeException('Unable to hide the response.'); } $value = \fgets($inputStream, 4096); if (self::$stty && Terminal::hasSttyAvailable()) { \shell_exec('stty ' . $sttyMode); } if (\false === $value) { throw new MissingInputException('Aborted.'); } if ($trimmable) { $value = \trim($value); } $output->writeln(''); return $value; } /** * Validates an attempt. * * @param callable $interviewer A callable that will ask for a question and return the result * * @return mixed The validated response * * @throws \Exception In case the max number of attempts has been reached and no valid response has been given */ private function validateAttempts(callable $interviewer, OutputInterface $output, Question $question) { $error = null; $attempts = $question->getMaxAttempts(); while (null === $attempts || $attempts--) { if (null !== $error) { $this->writeError($output, $error); } try { return $question->getValidator()($interviewer()); } catch (RuntimeException $e) { throw $e; } catch (\Exception $error) { } } throw $error; } private function isInteractiveInput($inputStream) : bool { if ('php://stdin' !== (\stream_get_meta_data($inputStream)['uri'] ?? null)) { return \false; } if (null !== self::$stdinIsInteractive) { return self::$stdinIsInteractive; } return self::$stdinIsInteractive = @\stream_isatty(\fopen('php://stdin', 'r')); } /** * Reads one or more lines of input and returns what is read. * * @param resource $inputStream The handler resource * @param Question $question The question being asked * * @return string|false The input received, false in case input could not be read */ private function readInput($inputStream, Question $question) { if (!$question->isMultiline()) { $cp = $this->setIOCodepage(); $ret = \fgets($inputStream, 4096); return $this->resetIOCodepage($cp, $ret); } $multiLineStreamReader = $this->cloneInputStream($inputStream); if (null === $multiLineStreamReader) { return \false; } $ret = ''; $cp = $this->setIOCodepage(); while (\false !== ($char = \fgetc($multiLineStreamReader))) { if (\PHP_EOL === "{$ret}{$char}") { break; } $ret .= $char; } return $this->resetIOCodepage($cp, $ret); } /** * Sets console I/O to the host code page. * * @return int Previous code page in IBM/EBCDIC format */ private function setIOCodepage() : int { if (\function_exists('sapi_windows_cp_set')) { $cp = \sapi_windows_cp_get(); \sapi_windows_cp_set(\sapi_windows_cp_get('oem')); return $cp; } return 0; } /** * Sets console I/O to the specified code page and converts the user input. * * @param string|false $input * * @return string|false */ private function resetIOCodepage(int $cp, $input) { if (0 !== $cp) { \sapi_windows_cp_set($cp); if (\false !== $input && '' !== $input) { $input = \sapi_windows_cp_conv(\sapi_windows_cp_get('oem'), $cp, $input); } } return $input; } /** * Clones an input stream in order to act on one instance of the same * stream without affecting the other instance. * * @param resource $inputStream The handler resource * * @return resource|null The cloned resource, null in case it could not be cloned */ private function cloneInputStream($inputStream) { $streamMetaData = \stream_get_meta_data($inputStream); $seekable = $streamMetaData['seekable'] ?? \false; $mode = $streamMetaData['mode'] ?? 'rb'; $uri = $streamMetaData['uri'] ?? null; if (null === $uri) { return null; } $cloneStream = \fopen($uri, $mode); // For seekable and writable streams, add all the same data to the // cloned stream and then seek to the same offset. if (\true === $seekable && !\in_array($mode, ['r', 'rb', 'rt'])) { $offset = \ftell($inputStream); \rewind($inputStream); \stream_copy_to_stream($inputStream, $cloneStream); \fseek($inputStream, $offset); \fseek($cloneStream, $offset); } return $cloneStream; } } * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace _HumbugBox7ff99e199a36\Symfony\Component\Console\Helper; /** * HelperInterface is the interface all helpers must implement. * * @author Fabien Potencier */ interface HelperInterface { /** * Sets the helper set associated with this helper. */ public function setHelperSet(?HelperSet $helperSet = null); /** * Gets the helper set associated with this helper. * * @return HelperSet|null */ public function getHelperSet(); /** * Returns the canonical name of this helper. * * @return string */ public function getName(); } * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace _HumbugBox7ff99e199a36\Symfony\Component\Console\Helper; /** * @internal */ class TableRows implements \IteratorAggregate { private $generator; public function __construct(\Closure $generator) { $this->generator = $generator; } public function getIterator() : \Traversable { return ($this->generator)(); } } * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace _HumbugBox7ff99e199a36\Symfony\Component\Console\Helper; use _HumbugBox7ff99e199a36\Symfony\Component\Console\Exception\InvalidArgumentException; /** * @author Abdellatif Ait boudad */ class TableCell { private $value; private $options = ['rowspan' => 1, 'colspan' => 1, 'style' => null]; public function __construct(string $value = '', array $options = []) { $this->value = $value; // check option names if ($diff = \array_diff(\array_keys($options), \array_keys($this->options))) { throw new InvalidArgumentException(\sprintf('The TableCell does not support the following options: \'%s\'.', \implode('\', \'', $diff))); } if (isset($options['style']) && !$options['style'] instanceof TableCellStyle) { throw new InvalidArgumentException('The style option must be an instance of "TableCellStyle".'); } $this->options = \array_merge($this->options, $options); } /** * Returns the cell value. * * @return string */ public function __toString() { return $this->value; } /** * Gets number of colspan. * * @return int */ public function getColspan() { return (int) $this->options['colspan']; } /** * Gets number of rowspan. * * @return int */ public function getRowspan() { return (int) $this->options['rowspan']; } public function getStyle() : ?TableCellStyle { return $this->options['style']; } } * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace _HumbugBox7ff99e199a36\Symfony\Component\Console\Helper; use _HumbugBox7ff99e199a36\Symfony\Component\Console\Exception\InvalidArgumentException; /** * @author Yewhen Khoptynskyi */ class TableCellStyle { public const DEFAULT_ALIGN = 'left'; private const TAG_OPTIONS = ['fg', 'bg', 'options']; private const ALIGN_MAP = ['left' => \STR_PAD_RIGHT, 'center' => \STR_PAD_BOTH, 'right' => \STR_PAD_LEFT]; private $options = ['fg' => 'default', 'bg' => 'default', 'options' => null, 'align' => self::DEFAULT_ALIGN, 'cellFormat' => null]; public function __construct(array $options = []) { if ($diff = \array_diff(\array_keys($options), \array_keys($this->options))) { throw new InvalidArgumentException(\sprintf('The TableCellStyle does not support the following options: \'%s\'.', \implode('\', \'', $diff))); } if (isset($options['align']) && !\array_key_exists($options['align'], self::ALIGN_MAP)) { throw new InvalidArgumentException(\sprintf('Wrong align value. Value must be following: \'%s\'.', \implode('\', \'', \array_keys(self::ALIGN_MAP)))); } $this->options = \array_merge($this->options, $options); } public function getOptions() : array { return $this->options; } /** * Gets options we need for tag for example fg, bg. * * @return string[] */ public function getTagOptions() { return \array_filter($this->getOptions(), function ($key) { return \in_array($key, self::TAG_OPTIONS) && isset($this->options[$key]); }, \ARRAY_FILTER_USE_KEY); } /** * @return int */ public function getPadByAlign() { return self::ALIGN_MAP[$this->getOptions()['align']]; } public function getCellFormat() : ?string { return $this->getOptions()['cellFormat']; } } Copyright (c) 2004-present Fabien Potencier Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace _HumbugBox7ff99e199a36\Symfony\Component\Console; use _HumbugBox7ff99e199a36\Symfony\Component\Console\Command\Command; use _HumbugBox7ff99e199a36\Symfony\Component\Console\Input\InputInterface; use _HumbugBox7ff99e199a36\Symfony\Component\Console\Output\OutputInterface; /** * @author Grégoire Pineau */ class SingleCommandApplication extends Command { private $version = 'UNKNOWN'; private $autoExit = \true; private $running = \false; /** * @return $this */ public function setVersion(string $version) : self { $this->version = $version; return $this; } /** * @final * * @return $this */ public function setAutoExit(bool $autoExit) : self { $this->autoExit = $autoExit; return $this; } public function run(?InputInterface $input = null, ?OutputInterface $output = null) : int { if ($this->running) { return parent::run($input, $output); } // We use the command name as the application name $application = new Application($this->getName() ?: 'UNKNOWN', $this->version); $application->setAutoExit($this->autoExit); // Fix the usage of the command displayed with "--help" $this->setName($_SERVER['argv'][0]); $application->add($this); $application->setDefaultCommand($this->getName(), \true); $this->running = \true; try { $ret = $application->run($input, $output); } finally { $this->running = \false; } return $ret ?? 1; } } * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace _HumbugBox7ff99e199a36\Symfony\Component\Console\Completion; /** * Represents a single suggested value. * * @author Wouter de Jong */ class Suggestion { private $value; public function __construct(string $value) { $this->value = $value; } public function getValue() : string { return $this->value; } public function __toString() : string { return $this->getValue(); } } * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace _HumbugBox7ff99e199a36\Symfony\Component\Console\Completion; use _HumbugBox7ff99e199a36\Symfony\Component\Console\Input\InputOption; /** * Stores all completion suggestions for the current input. * * @author Wouter de Jong */ final class CompletionSuggestions { private $valueSuggestions = []; private $optionSuggestions = []; /** * Add a suggested value for an input option or argument. * * @param string|Suggestion $value * * @return $this */ public function suggestValue($value) : self { $this->valueSuggestions[] = !$value instanceof Suggestion ? new Suggestion($value) : $value; return $this; } /** * Add multiple suggested values at once for an input option or argument. * * @param list $values * * @return $this */ public function suggestValues(array $values) : self { foreach ($values as $value) { $this->suggestValue($value); } return $this; } /** * Add a suggestion for an input option name. * * @return $this */ public function suggestOption(InputOption $option) : self { $this->optionSuggestions[] = $option; return $this; } /** * Add multiple suggestions for input option names at once. * * @param InputOption[] $options * * @return $this */ public function suggestOptions(array $options) : self { foreach ($options as $option) { $this->suggestOption($option); } return $this; } /** * @return InputOption[] */ public function getOptionSuggestions() : array { return $this->optionSuggestions; } /** * @return Suggestion[] */ public function getValueSuggestions() : array { return $this->valueSuggestions; } } * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace _HumbugBox7ff99e199a36\Symfony\Component\Console\Completion\Output; use _HumbugBox7ff99e199a36\Symfony\Component\Console\Completion\CompletionSuggestions; use _HumbugBox7ff99e199a36\Symfony\Component\Console\Output\OutputInterface; /** * Transforms the {@see CompletionSuggestions} object into output readable by the shell completion. * * @author Wouter de Jong */ interface CompletionOutputInterface { public function write(CompletionSuggestions $suggestions, OutputInterface $output) : void; } * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace _HumbugBox7ff99e199a36\Symfony\Component\Console\Completion\Output; use _HumbugBox7ff99e199a36\Symfony\Component\Console\Completion\CompletionSuggestions; use _HumbugBox7ff99e199a36\Symfony\Component\Console\Output\OutputInterface; /** * @author Wouter de Jong */ class BashCompletionOutput implements CompletionOutputInterface { public function write(CompletionSuggestions $suggestions, OutputInterface $output) : void { $values = $suggestions->getValueSuggestions(); foreach ($suggestions->getOptionSuggestions() as $option) { $values[] = '--' . $option->getName(); if ($option->isNegatable()) { $values[] = '--no-' . $option->getName(); } } $output->writeln(\implode("\n", $values)); } } * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace _HumbugBox7ff99e199a36\Symfony\Component\Console\Completion; use _HumbugBox7ff99e199a36\Symfony\Component\Console\Exception\RuntimeException; use _HumbugBox7ff99e199a36\Symfony\Component\Console\Input\ArgvInput; use _HumbugBox7ff99e199a36\Symfony\Component\Console\Input\InputDefinition; use _HumbugBox7ff99e199a36\Symfony\Component\Console\Input\InputOption; /** * An input specialized for shell completion. * * This input allows unfinished option names or values and exposes what kind of * completion is expected. * * @author Wouter de Jong */ final class CompletionInput extends ArgvInput { public const TYPE_ARGUMENT_VALUE = 'argument_value'; public const TYPE_OPTION_VALUE = 'option_value'; public const TYPE_OPTION_NAME = 'option_name'; public const TYPE_NONE = 'none'; private $tokens; private $currentIndex; private $completionType; private $completionName = null; private $completionValue = ''; /** * Converts a terminal string into tokens. * * This is required for shell completions without COMP_WORDS support. */ public static function fromString(string $inputStr, int $currentIndex) : self { \preg_match_all('/(?<=^|\\s)([\'"]?)(.+?)(?tokens = $tokens; $input->currentIndex = $currentIndex; return $input; } /** * {@inheritdoc} */ public function bind(InputDefinition $definition) : void { parent::bind($definition); $relevantToken = $this->getRelevantToken(); if ('-' === $relevantToken[0]) { // the current token is an input option: complete either option name or option value [$optionToken, $optionValue] = \explode('=', $relevantToken, 2) + ['', '']; $option = $this->getOptionFromToken($optionToken); if (null === $option && !$this->isCursorFree()) { $this->completionType = self::TYPE_OPTION_NAME; $this->completionValue = $relevantToken; return; } if (null !== $option && $option->acceptValue()) { $this->completionType = self::TYPE_OPTION_VALUE; $this->completionName = $option->getName(); $this->completionValue = $optionValue ?: (!\str_starts_with($optionToken, '--') ? \substr($optionToken, 2) : ''); return; } } $previousToken = $this->tokens[$this->currentIndex - 1]; if ('-' === $previousToken[0] && '' !== \trim($previousToken, '-')) { // check if previous option accepted a value $previousOption = $this->getOptionFromToken($previousToken); if (null !== $previousOption && $previousOption->acceptValue()) { $this->completionType = self::TYPE_OPTION_VALUE; $this->completionName = $previousOption->getName(); $this->completionValue = $relevantToken; return; } } // complete argument value $this->completionType = self::TYPE_ARGUMENT_VALUE; foreach ($this->definition->getArguments() as $argumentName => $argument) { if (!isset($this->arguments[$argumentName])) { break; } $argumentValue = $this->arguments[$argumentName]; $this->completionName = $argumentName; if (\is_array($argumentValue)) { $this->completionValue = $argumentValue ? $argumentValue[\array_key_last($argumentValue)] : null; } else { $this->completionValue = $argumentValue; } } if ($this->currentIndex >= \count($this->tokens)) { if (!isset($this->arguments[$argumentName]) || $this->definition->getArgument($argumentName)->isArray()) { $this->completionName = $argumentName; $this->completionValue = ''; } else { // we've reached the end $this->completionType = self::TYPE_NONE; $this->completionName = null; $this->completionValue = ''; } } } /** * Returns the type of completion required. * * TYPE_ARGUMENT_VALUE when completing the value of an input argument * TYPE_OPTION_VALUE when completing the value of an input option * TYPE_OPTION_NAME when completing the name of an input option * TYPE_NONE when nothing should be completed * * @return string One of self::TYPE_* constants. TYPE_OPTION_NAME and TYPE_NONE are already implemented by the Console component */ public function getCompletionType() : string { return $this->completionType; } /** * The name of the input option or argument when completing a value. * * @return string|null returns null when completing an option name */ public function getCompletionName() : ?string { return $this->completionName; } /** * The value already typed by the user (or empty string). */ public function getCompletionValue() : string { return $this->completionValue; } public function mustSuggestOptionValuesFor(string $optionName) : bool { return self::TYPE_OPTION_VALUE === $this->getCompletionType() && $optionName === $this->getCompletionName(); } public function mustSuggestArgumentValuesFor(string $argumentName) : bool { return self::TYPE_ARGUMENT_VALUE === $this->getCompletionType() && $argumentName === $this->getCompletionName(); } protected function parseToken(string $token, bool $parseOptions) : bool { try { return parent::parseToken($token, $parseOptions); } catch (RuntimeException $e) { // suppress errors, completed input is almost never valid } return $parseOptions; } private function getOptionFromToken(string $optionToken) : ?InputOption { $optionName = \ltrim($optionToken, '-'); if (!$optionName) { return null; } if ('-' === ($optionToken[1] ?? ' ')) { // long option name return $this->definition->hasOption($optionName) ? $this->definition->getOption($optionName) : null; } // short option name return $this->definition->hasShortcut($optionName[0]) ? $this->definition->getOptionForShortcut($optionName[0]) : null; } /** * The token of the cursor, or the last token if the cursor is at the end of the input. */ private function getRelevantToken() : string { return $this->tokens[$this->isCursorFree() ? $this->currentIndex - 1 : $this->currentIndex]; } /** * Whether the cursor is "free" (i.e. at the end of the input preceded by a space). */ private function isCursorFree() : bool { $nrOfTokens = \count($this->tokens); if ($this->currentIndex > $nrOfTokens) { throw new \LogicException('Current index is invalid, it must be the number of input tokens or one more.'); } return $this->currentIndex >= $nrOfTokens; } public function __toString() { $str = ''; foreach ($this->tokens as $i => $token) { $str .= $token; if ($this->currentIndex === $i) { $str .= '|'; } $str .= ' '; } if ($this->currentIndex > $i) { $str .= '|'; } return \rtrim($str); } } * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace _HumbugBox7ff99e199a36\Symfony\Component\Console\Attribute; /** * Service tag to autoconfigure commands. */ #[\Attribute(\Attribute::TARGET_CLASS)] class AsCommand { public function __construct(public string $name, public ?string $description = null, array $aliases = [], bool $hidden = \false) { if (!$hidden && !$aliases) { return; } $name = \explode('|', $name); $name = \array_merge($name, $aliases); if ($hidden && '' !== $name[0]) { \array_unshift($name, ''); } $this->name = \implode('|', $name); } } * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace _HumbugBox7ff99e199a36\Symfony\Component\Console\Tester; use _HumbugBox7ff99e199a36\Symfony\Component\Console\Application; use _HumbugBox7ff99e199a36\Symfony\Component\Console\Input\ArrayInput; /** * Eases the testing of console applications. * * When testing an application, don't forget to disable the auto exit flag: * * $application = new Application(); * $application->setAutoExit(false); * * @author Fabien Potencier */ class ApplicationTester { use TesterTrait; private $application; public function __construct(Application $application) { $this->application = $application; } /** * Executes the application. * * Available options: * * * interactive: Sets the input interactive flag * * decorated: Sets the output decorated flag * * verbosity: Sets the output verbosity flag * * capture_stderr_separately: Make output of stdOut and stdErr separately available * * @return int The command exit code */ public function run(array $input, array $options = []) { $prevShellVerbosity = \getenv('SHELL_VERBOSITY'); try { $this->input = new ArrayInput($input); if (isset($options['interactive'])) { $this->input->setInteractive($options['interactive']); } if ($this->inputs) { $this->input->setStream(self::createStream($this->inputs)); } $this->initOutput($options); return $this->statusCode = $this->application->run($this->input, $this->output); } finally { // SHELL_VERBOSITY is set by Application::configureIO so we need to unset/reset it // to its previous value to avoid one test's verbosity to spread to the following tests if (\false === $prevShellVerbosity) { if (\function_exists('putenv')) { @\putenv('SHELL_VERBOSITY'); } unset($_ENV['SHELL_VERBOSITY']); unset($_SERVER['SHELL_VERBOSITY']); } else { if (\function_exists('putenv')) { @\putenv('SHELL_VERBOSITY=' . $prevShellVerbosity); } $_ENV['SHELL_VERBOSITY'] = $prevShellVerbosity; $_SERVER['SHELL_VERBOSITY'] = $prevShellVerbosity; } } } } * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace _HumbugBox7ff99e199a36\Symfony\Component\Console\Tester; use _HumbugBox7ff99e199a36\Symfony\Component\Console\Command\Command; use _HumbugBox7ff99e199a36\Symfony\Component\Console\Input\ArrayInput; /** * Eases the testing of console commands. * * @author Fabien Potencier * @author Robin Chalas */ class CommandTester { use TesterTrait; private $command; public function __construct(Command $command) { $this->command = $command; } /** * Executes the command. * * Available execution options: * * * interactive: Sets the input interactive flag * * decorated: Sets the output decorated flag * * verbosity: Sets the output verbosity flag * * capture_stderr_separately: Make output of stdOut and stdErr separately available * * @param array $input An array of command arguments and options * @param array $options An array of execution options * * @return int The command exit code */ public function execute(array $input, array $options = []) { // set the command name automatically if the application requires // this argument and no command name was passed if (!isset($input['command']) && null !== ($application = $this->command->getApplication()) && $application->getDefinition()->hasArgument('command')) { $input = \array_merge(['command' => $this->command->getName()], $input); } $this->input = new ArrayInput($input); // Use an in-memory input stream even if no inputs are set so that QuestionHelper::ask() does not rely on the blocking STDIN. $this->input->setStream(self::createStream($this->inputs)); if (isset($options['interactive'])) { $this->input->setInteractive($options['interactive']); } if (!isset($options['decorated'])) { $options['decorated'] = \false; } $this->initOutput($options); return $this->statusCode = $this->command->run($this->input, $this->output); } } * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace _HumbugBox7ff99e199a36\Symfony\Component\Console\Tester\Constraint; use _HumbugBox7ff99e199a36\PHPUnit\Framework\Constraint\Constraint; use _HumbugBox7ff99e199a36\Symfony\Component\Console\Command\Command; final class CommandIsSuccessful extends Constraint { /** * {@inheritdoc} */ public function toString() : string { return 'is successful'; } /** * {@inheritdoc} */ protected function matches($other) : bool { return Command::SUCCESS === $other; } /** * {@inheritdoc} */ protected function failureDescription($other) : string { return 'the command ' . $this->toString(); } /** * {@inheritdoc} */ protected function additionalFailureDescription($other) : string { $mapping = [Command::FAILURE => 'Command failed.', Command::INVALID => 'Command was invalid.']; return $mapping[$other] ?? \sprintf('Command returned exit status %d.', $other); } } * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace _HumbugBox7ff99e199a36\Symfony\Component\Console\Tester; use _HumbugBox7ff99e199a36\Symfony\Component\Console\Command\Command; use _HumbugBox7ff99e199a36\Symfony\Component\Console\Completion\CompletionInput; use _HumbugBox7ff99e199a36\Symfony\Component\Console\Completion\CompletionSuggestions; /** * Eases the testing of command completion. * * @author Jérôme Tamarelle */ class CommandCompletionTester { private $command; public function __construct(Command $command) { $this->command = $command; } /** * Create completion suggestions from input tokens. */ public function complete(array $input) : array { $currentIndex = \count($input); if ('' === \end($input)) { \array_pop($input); } \array_unshift($input, $this->command->getName()); $completionInput = CompletionInput::fromTokens($input, $currentIndex); $completionInput->bind($this->command->getDefinition()); $suggestions = new CompletionSuggestions(); $this->command->complete($completionInput, $suggestions); $options = []; foreach ($suggestions->getOptionSuggestions() as $option) { $options[] = '--' . $option->getName(); } return \array_map('strval', \array_merge($options, $suggestions->getValueSuggestions())); } } * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace _HumbugBox7ff99e199a36\Symfony\Component\Console\Tester; use _HumbugBox7ff99e199a36\PHPUnit\Framework\Assert; use _HumbugBox7ff99e199a36\Symfony\Component\Console\Input\InputInterface; use _HumbugBox7ff99e199a36\Symfony\Component\Console\Output\ConsoleOutput; use _HumbugBox7ff99e199a36\Symfony\Component\Console\Output\OutputInterface; use _HumbugBox7ff99e199a36\Symfony\Component\Console\Output\StreamOutput; use _HumbugBox7ff99e199a36\Symfony\Component\Console\Tester\Constraint\CommandIsSuccessful; /** * @author Amrouche Hamza */ trait TesterTrait { /** @var StreamOutput */ private $output; private $inputs = []; private $captureStreamsIndependently = \false; /** @var InputInterface */ private $input; /** @var int */ private $statusCode; /** * Gets the display returned by the last execution of the command or application. * * @return string * * @throws \RuntimeException If it's called before the execute method */ public function getDisplay(bool $normalize = \false) { if (null === $this->output) { throw new \RuntimeException('Output not initialized, did you execute the command before requesting the display?'); } \rewind($this->output->getStream()); $display = \stream_get_contents($this->output->getStream()); if ($normalize) { $display = \str_replace(\PHP_EOL, "\n", $display); } return $display; } /** * Gets the output written to STDERR by the application. * * @param bool $normalize Whether to normalize end of lines to \n or not * * @return string */ public function getErrorOutput(bool $normalize = \false) { if (!$this->captureStreamsIndependently) { throw new \LogicException('The error output is not available when the tester is run without "capture_stderr_separately" option set.'); } \rewind($this->output->getErrorOutput()->getStream()); $display = \stream_get_contents($this->output->getErrorOutput()->getStream()); if ($normalize) { $display = \str_replace(\PHP_EOL, "\n", $display); } return $display; } /** * Gets the input instance used by the last execution of the command or application. * * @return InputInterface */ public function getInput() { return $this->input; } /** * Gets the output instance used by the last execution of the command or application. * * @return OutputInterface */ public function getOutput() { return $this->output; } /** * Gets the status code returned by the last execution of the command or application. * * @return int * * @throws \RuntimeException If it's called before the execute method */ public function getStatusCode() { if (null === $this->statusCode) { throw new \RuntimeException('Status code not initialized, did you execute the command before requesting the status code?'); } return $this->statusCode; } public function assertCommandIsSuccessful(string $message = '') : void { Assert::assertThat($this->statusCode, new CommandIsSuccessful(), $message); } /** * Sets the user inputs. * * @param array $inputs An array of strings representing each input * passed to the command input stream * * @return $this */ public function setInputs(array $inputs) { $this->inputs = $inputs; return $this; } /** * Initializes the output property. * * Available options: * * * decorated: Sets the output decorated flag * * verbosity: Sets the output verbosity flag * * capture_stderr_separately: Make output of stdOut and stdErr separately available */ private function initOutput(array $options) { $this->captureStreamsIndependently = \array_key_exists('capture_stderr_separately', $options) && $options['capture_stderr_separately']; if (!$this->captureStreamsIndependently) { $this->output = new StreamOutput(\fopen('php://memory', 'w', \false)); if (isset($options['decorated'])) { $this->output->setDecorated($options['decorated']); } if (isset($options['verbosity'])) { $this->output->setVerbosity($options['verbosity']); } } else { $this->output = new ConsoleOutput($options['verbosity'] ?? ConsoleOutput::VERBOSITY_NORMAL, $options['decorated'] ?? null); $errorOutput = new StreamOutput(\fopen('php://memory', 'w', \false)); $errorOutput->setFormatter($this->output->getFormatter()); $errorOutput->setVerbosity($this->output->getVerbosity()); $errorOutput->setDecorated($this->output->isDecorated()); $reflectedOutput = new \ReflectionObject($this->output); $strErrProperty = $reflectedOutput->getProperty('stderr'); $strErrProperty->setAccessible(\true); $strErrProperty->setValue($this->output, $errorOutput); $reflectedParent = $reflectedOutput->getParentClass(); $streamProperty = $reflectedParent->getProperty('stream'); $streamProperty->setAccessible(\true); $streamProperty->setValue($this->output, \fopen('php://memory', 'w', \false)); } } /** * @return resource */ private static function createStream(array $inputs) { $stream = \fopen('php://memory', 'r+', \false); foreach ($inputs as $input) { \fwrite($stream, $input . \PHP_EOL); } \rewind($stream); return $stream; } } * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace _HumbugBox7ff99e199a36\Symfony\Component\Console\Style; use _HumbugBox7ff99e199a36\Symfony\Component\Console\Formatter\OutputFormatterInterface; use _HumbugBox7ff99e199a36\Symfony\Component\Console\Helper\ProgressBar; use _HumbugBox7ff99e199a36\Symfony\Component\Console\Output\ConsoleOutputInterface; use _HumbugBox7ff99e199a36\Symfony\Component\Console\Output\OutputInterface; /** * Decorates output to add console style guide helpers. * * @author Kevin Bond */ abstract class OutputStyle implements OutputInterface, StyleInterface { private $output; public function __construct(OutputInterface $output) { $this->output = $output; } /** * {@inheritdoc} */ public function newLine(int $count = 1) { $this->output->write(\str_repeat(\PHP_EOL, $count)); } /** * @return ProgressBar */ public function createProgressBar(int $max = 0) { return new ProgressBar($this->output, $max); } /** * {@inheritdoc} */ public function write($messages, bool $newline = \false, int $type = self::OUTPUT_NORMAL) { $this->output->write($messages, $newline, $type); } /** * {@inheritdoc} */ public function writeln($messages, int $type = self::OUTPUT_NORMAL) { $this->output->writeln($messages, $type); } /** * {@inheritdoc} */ public function setVerbosity(int $level) { $this->output->setVerbosity($level); } /** * {@inheritdoc} */ public function getVerbosity() { return $this->output->getVerbosity(); } /** * {@inheritdoc} */ public function setDecorated(bool $decorated) { $this->output->setDecorated($decorated); } /** * {@inheritdoc} */ public function isDecorated() { return $this->output->isDecorated(); } /** * {@inheritdoc} */ public function setFormatter(OutputFormatterInterface $formatter) { $this->output->setFormatter($formatter); } /** * {@inheritdoc} */ public function getFormatter() { return $this->output->getFormatter(); } /** * {@inheritdoc} */ public function isQuiet() { return $this->output->isQuiet(); } /** * {@inheritdoc} */ public function isVerbose() { return $this->output->isVerbose(); } /** * {@inheritdoc} */ public function isVeryVerbose() { return $this->output->isVeryVerbose(); } /** * {@inheritdoc} */ public function isDebug() { return $this->output->isDebug(); } protected function getErrorOutput() { if (!$this->output instanceof ConsoleOutputInterface) { return $this->output; } return $this->output->getErrorOutput(); } } * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace _HumbugBox7ff99e199a36\Symfony\Component\Console\Style; use _HumbugBox7ff99e199a36\Symfony\Component\Console\Exception\InvalidArgumentException; use _HumbugBox7ff99e199a36\Symfony\Component\Console\Exception\RuntimeException; use _HumbugBox7ff99e199a36\Symfony\Component\Console\Formatter\OutputFormatter; use _HumbugBox7ff99e199a36\Symfony\Component\Console\Helper\Helper; use _HumbugBox7ff99e199a36\Symfony\Component\Console\Helper\ProgressBar; use _HumbugBox7ff99e199a36\Symfony\Component\Console\Helper\SymfonyQuestionHelper; use _HumbugBox7ff99e199a36\Symfony\Component\Console\Helper\Table; use _HumbugBox7ff99e199a36\Symfony\Component\Console\Helper\TableCell; use _HumbugBox7ff99e199a36\Symfony\Component\Console\Helper\TableSeparator; use _HumbugBox7ff99e199a36\Symfony\Component\Console\Input\InputInterface; use _HumbugBox7ff99e199a36\Symfony\Component\Console\Output\ConsoleOutputInterface; use _HumbugBox7ff99e199a36\Symfony\Component\Console\Output\OutputInterface; use _HumbugBox7ff99e199a36\Symfony\Component\Console\Output\TrimmedBufferOutput; use _HumbugBox7ff99e199a36\Symfony\Component\Console\Question\ChoiceQuestion; use _HumbugBox7ff99e199a36\Symfony\Component\Console\Question\ConfirmationQuestion; use _HumbugBox7ff99e199a36\Symfony\Component\Console\Question\Question; use _HumbugBox7ff99e199a36\Symfony\Component\Console\Terminal; /** * Output decorator helpers for the Symfony Style Guide. * * @author Kevin Bond */ class SymfonyStyle extends OutputStyle { public const MAX_LINE_LENGTH = 120; private $input; private $output; private $questionHelper; private $progressBar; private $lineLength; private $bufferedOutput; public function __construct(InputInterface $input, OutputInterface $output) { $this->input = $input; $this->bufferedOutput = new TrimmedBufferOutput(\DIRECTORY_SEPARATOR === '\\' ? 4 : 2, $output->getVerbosity(), \false, clone $output->getFormatter()); // Windows cmd wraps lines as soon as the terminal width is reached, whether there are following chars or not. $width = (new Terminal())->getWidth() ?: self::MAX_LINE_LENGTH; $this->lineLength = \min($width - (int) (\DIRECTORY_SEPARATOR === '\\'), self::MAX_LINE_LENGTH); parent::__construct($this->output = $output); } /** * Formats a message as a block of text. * * @param string|array $messages The message to write in the block */ public function block($messages, ?string $type = null, ?string $style = null, string $prefix = ' ', bool $padding = \false, bool $escape = \true) { $messages = \is_array($messages) ? \array_values($messages) : [$messages]; $this->autoPrependBlock(); $this->writeln($this->createBlock($messages, $type, $style, $prefix, $padding, $escape)); $this->newLine(); } /** * {@inheritdoc} */ public function title(string $message) { $this->autoPrependBlock(); $this->writeln([\sprintf('%s', OutputFormatter::escapeTrailingBackslash($message)), \sprintf('%s', \str_repeat('=', Helper::width(Helper::removeDecoration($this->getFormatter(), $message))))]); $this->newLine(); } /** * {@inheritdoc} */ public function section(string $message) { $this->autoPrependBlock(); $this->writeln([\sprintf('%s', OutputFormatter::escapeTrailingBackslash($message)), \sprintf('%s', \str_repeat('-', Helper::width(Helper::removeDecoration($this->getFormatter(), $message))))]); $this->newLine(); } /** * {@inheritdoc} */ public function listing(array $elements) { $this->autoPrependText(); $elements = \array_map(function ($element) { return \sprintf(' * %s', $element); }, $elements); $this->writeln($elements); $this->newLine(); } /** * {@inheritdoc} */ public function text($message) { $this->autoPrependText(); $messages = \is_array($message) ? \array_values($message) : [$message]; foreach ($messages as $message) { $this->writeln(\sprintf(' %s', $message)); } } /** * Formats a command comment. * * @param string|array $message */ public function comment($message) { $this->block($message, null, null, ' // ', \false, \false); } /** * {@inheritdoc} */ public function success($message) { $this->block($message, 'OK', 'fg=black;bg=green', ' ', \true); } /** * {@inheritdoc} */ public function error($message) { $this->block($message, 'ERROR', 'fg=white;bg=red', ' ', \true); } /** * {@inheritdoc} */ public function warning($message) { $this->block($message, 'WARNING', 'fg=black;bg=yellow', ' ', \true); } /** * {@inheritdoc} */ public function note($message) { $this->block($message, 'NOTE', 'fg=yellow', ' ! '); } /** * Formats an info message. * * @param string|array $message */ public function info($message) { $this->block($message, 'INFO', 'fg=green', ' ', \true); } /** * {@inheritdoc} */ public function caution($message) { $this->block($message, 'CAUTION', 'fg=white;bg=red', ' ! ', \true); } /** * {@inheritdoc} */ public function table(array $headers, array $rows) { $this->createTable()->setHeaders($headers)->setRows($rows)->render(); $this->newLine(); } /** * Formats a horizontal table. */ public function horizontalTable(array $headers, array $rows) { $this->createTable()->setHorizontal(\true)->setHeaders($headers)->setRows($rows)->render(); $this->newLine(); } /** * Formats a list of key/value horizontally. * * Each row can be one of: * * 'A title' * * ['key' => 'value'] * * new TableSeparator() * * @param string|array|TableSeparator ...$list */ public function definitionList(...$list) { $headers = []; $row = []; foreach ($list as $value) { if ($value instanceof TableSeparator) { $headers[] = $value; $row[] = $value; continue; } if (\is_string($value)) { $headers[] = new TableCell($value, ['colspan' => 2]); $row[] = null; continue; } if (!\is_array($value)) { throw new InvalidArgumentException('Value should be an array, string, or an instance of TableSeparator.'); } $headers[] = \key($value); $row[] = \current($value); } $this->horizontalTable($headers, [$row]); } /** * {@inheritdoc} */ public function ask(string $question, ?string $default = null, ?callable $validator = null) { $question = new Question($question, $default); $question->setValidator($validator); return $this->askQuestion($question); } /** * {@inheritdoc} */ public function askHidden(string $question, ?callable $validator = null) { $question = new Question($question); $question->setHidden(\true); $question->setValidator($validator); return $this->askQuestion($question); } /** * {@inheritdoc} */ public function confirm(string $question, bool $default = \true) { return $this->askQuestion(new ConfirmationQuestion($question, $default)); } /** * {@inheritdoc} */ public function choice(string $question, array $choices, $default = null) { if (null !== $default) { $values = \array_flip($choices); $default = $values[$default] ?? $default; } return $this->askQuestion(new ChoiceQuestion($question, $choices, $default)); } /** * {@inheritdoc} */ public function progressStart(int $max = 0) { $this->progressBar = $this->createProgressBar($max); $this->progressBar->start(); } /** * {@inheritdoc} */ public function progressAdvance(int $step = 1) { $this->getProgressBar()->advance($step); } /** * {@inheritdoc} */ public function progressFinish() { $this->getProgressBar()->finish(); $this->newLine(2); $this->progressBar = null; } /** * {@inheritdoc} */ public function createProgressBar(int $max = 0) { $progressBar = parent::createProgressBar($max); if ('\\' !== \DIRECTORY_SEPARATOR || 'Hyper' === \getenv('TERM_PROGRAM')) { $progressBar->setEmptyBarCharacter('░'); // light shade character \u2591 $progressBar->setProgressCharacter(''); $progressBar->setBarCharacter('▓'); // dark shade character \u2593 } return $progressBar; } /** * @see ProgressBar::iterate() */ public function progressIterate(iterable $iterable, ?int $max = null) : iterable { yield from $this->createProgressBar()->iterate($iterable, $max); $this->newLine(2); } /** * @return mixed */ public function askQuestion(Question $question) { if ($this->input->isInteractive()) { $this->autoPrependBlock(); } if (!$this->questionHelper) { $this->questionHelper = new SymfonyQuestionHelper(); } $answer = $this->questionHelper->ask($this->input, $this, $question); if ($this->input->isInteractive()) { $this->newLine(); $this->bufferedOutput->write("\n"); } return $answer; } /** * {@inheritdoc} */ public function writeln($messages, int $type = self::OUTPUT_NORMAL) { if (!\is_iterable($messages)) { $messages = [$messages]; } foreach ($messages as $message) { parent::writeln($message, $type); $this->writeBuffer($message, \true, $type); } } /** * {@inheritdoc} */ public function write($messages, bool $newline = \false, int $type = self::OUTPUT_NORMAL) { if (!\is_iterable($messages)) { $messages = [$messages]; } foreach ($messages as $message) { parent::write($message, $newline, $type); $this->writeBuffer($message, $newline, $type); } } /** * {@inheritdoc} */ public function newLine(int $count = 1) { parent::newLine($count); $this->bufferedOutput->write(\str_repeat("\n", $count)); } /** * Returns a new instance which makes use of stderr if available. * * @return self */ public function getErrorStyle() { return new self($this->input, $this->getErrorOutput()); } public function createTable() : Table { $output = $this->output instanceof ConsoleOutputInterface ? $this->output->section() : $this->output; $style = clone Table::getStyleDefinition('symfony-style-guide'); $style->setCellHeaderFormat('%s'); return (new Table($output))->setStyle($style); } private function getProgressBar() : ProgressBar { if (!$this->progressBar) { throw new RuntimeException('The ProgressBar is not started.'); } return $this->progressBar; } private function autoPrependBlock() : void { $chars = \substr(\str_replace(\PHP_EOL, "\n", $this->bufferedOutput->fetch()), -2); if (!isset($chars[0])) { $this->newLine(); // empty history, so we should start with a new line. return; } // Prepend new line for each non LF chars (This means no blank line was output before) $this->newLine(2 - \substr_count($chars, "\n")); } private function autoPrependText() : void { $fetched = $this->bufferedOutput->fetch(); // Prepend new line if last char isn't EOL: if (!\str_ends_with($fetched, "\n")) { $this->newLine(); } } private function writeBuffer(string $message, bool $newLine, int $type) : void { // We need to know if the last chars are PHP_EOL $this->bufferedOutput->write($message, $newLine, $type); } private function createBlock(iterable $messages, ?string $type = null, ?string $style = null, string $prefix = ' ', bool $padding = \false, bool $escape = \false) : array { $indentLength = 0; $prefixLength = Helper::width(Helper::removeDecoration($this->getFormatter(), $prefix)); $lines = []; if (null !== $type) { $type = \sprintf('[%s] ', $type); $indentLength = \strlen($type); $lineIndentation = \str_repeat(' ', $indentLength); } // wrap and add newlines for each element foreach ($messages as $key => $message) { if ($escape) { $message = OutputFormatter::escape($message); } $decorationLength = Helper::width($message) - Helper::width(Helper::removeDecoration($this->getFormatter(), $message)); $messageLineLength = \min($this->lineLength - $prefixLength - $indentLength + $decorationLength, $this->lineLength); $messageLines = \explode(\PHP_EOL, \wordwrap($message, $messageLineLength, \PHP_EOL, \true)); foreach ($messageLines as $messageLine) { $lines[] = $messageLine; } if (\count($messages) > 1 && $key < \count($messages) - 1) { $lines[] = ''; } } $firstLineIndex = 0; if ($padding && $this->isDecorated()) { $firstLineIndex = 1; \array_unshift($lines, ''); $lines[] = ''; } foreach ($lines as $i => &$line) { if (null !== $type) { $line = $firstLineIndex === $i ? $type . $line : $lineIndentation . $line; } $line = $prefix . $line; $line .= \str_repeat(' ', \max($this->lineLength - Helper::width(Helper::removeDecoration($this->getFormatter(), $line)), 0)); if ($style) { $line = \sprintf('<%s>%s', $style, $line); } } return $lines; } } * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace _HumbugBox7ff99e199a36\Symfony\Component\Console\Style; /** * Output style helpers. * * @author Kevin Bond */ interface StyleInterface { /** * Formats a command title. */ public function title(string $message); /** * Formats a section title. */ public function section(string $message); /** * Formats a list. */ public function listing(array $elements); /** * Formats informational text. * * @param string|array $message */ public function text($message); /** * Formats a success result bar. * * @param string|array $message */ public function success($message); /** * Formats an error result bar. * * @param string|array $message */ public function error($message); /** * Formats an warning result bar. * * @param string|array $message */ public function warning($message); /** * Formats a note admonition. * * @param string|array $message */ public function note($message); /** * Formats a caution admonition. * * @param string|array $message */ public function caution($message); /** * Formats a table. */ public function table(array $headers, array $rows); /** * Asks a question. * * @return mixed */ public function ask(string $question, ?string $default = null, ?callable $validator = null); /** * Asks a question with the user input hidden. * * @return mixed */ public function askHidden(string $question, ?callable $validator = null); /** * Asks for confirmation. * * @return bool */ public function confirm(string $question, bool $default = \true); /** * Asks a choice question. * * @param string|int|null $default * * @return mixed */ public function choice(string $question, array $choices, $default = null); /** * Add newline(s). */ public function newLine(int $count = 1); /** * Starts the progress output. */ public function progressStart(int $max = 0); /** * Advances the progress output X steps. */ public function progressAdvance(int $step = 1); /** * Finishes the progress output. */ public function progressFinish(); } MZ@ !L!This program cannot be run in DOS mode. $,;B;B;B2מ:B2-B2ƞ9B2ў?Ba98B;CB2Ȟ:B2֞:B2Ӟ:BRich;BPELMoO  8 @`?@"P@ Pp!8!@ .text   `.rdata @@.data0@.rsrc @@@.relocP"@Bj$@xj @eEPV @EЃPV @MX @eEP5H @L @YY5\ @EP5` @D @YYP @MMT @3H; 0@uh@l3@$40@5h3@40@h$0@h(0@h 0@ @00@}jYjh"@3ۉ]dp]俀3@SVW0 @;t;u3Fuh4 @3F|3@;u j\Y;|3@u,5|3@h @h @YYtE5<0@|3@;uh @h @lYY|3@9]uSW8 @93@th3@Yt SjS3@$0@ @5$0@5(0@5 0@ 80@9,0@u7P @E MPQYYËeE80@39,0@uPh @9<0@u @E80@øMZf9@t3M<@@8PEuH t uՃv39xtv39j,0@p @jl @YY3@3@ @ t3@ @ p3@ @x3@V=0@u h@ @Yg=0@u j @Y3{U(H1@ D1@@1@<1@581@=41@f`1@f T1@f01@f,1@f%(1@f-$1@X1@EL1@EP1@E\1@0@P1@L0@@0@ D0@0@0@ @0@j?Yj @h!@$ @=0@ujYh ( @P, @ËUE8csmu*xu$@= t=!t="t=@u3]hH@ @3% @jh("@b53@5 @YEu u @YgjYe53@։E53@YYEEPEPu5l @YPUEu֣3@uփ3@E EjYËUuNYH]ËV!@!@W;stЃ;r_^ËV"@"@W;stЃ;r_^% @̋UMMZf9t3]ËA<8PEu3ҹ f9H‹]̋UEH<ASVq3WDv} H ;r X;r B(;r3_^[]̋UjhH"@he@dPSVW0@1E3PEdeEh@*tUE-@Ph@Pt;@$ЃEMd Y_^[]ËE3=‹ËeE3Md Y_^[]% @% @he@d5D$l$l$+SVW0@1E3PeuEEEEdËMd Y__^[]QËUuuu uh@h0@]ËVhh3V t VVVVV^3ËU0@eeSWN@;t t У0@`VEP< @u3u @3 @3 @3EP @E3E3;uO@ u 50@։50@^_[%t @%x @%| @% @% @% @% @% @% @Pd5D$ +d$ SVW(0@3PEuEEdËMd Y__^[]QËM3M%T @T$B J3J3l"@s###)r)b)H)4))(((((()#$%%&d&&$('''''(((6('H(Z(t(('''''l'^'R'F'>'>(0'')@W@@MoOl!@0@0@bad allocationH0@!@RSDSьJ!LZc:\users\seld\documents\visual studio 2010\Projects\hiddeninp\Release\hiddeninp.pdbe@@:@@@@"d"@"# $#&D H#(h ###)r)b)H)4))(((((()#$%%&d&&$('''''(((6('H(Z(t(('''''l'^'R'F'>'>(0'')GetConsoleModeSetConsoleMode;GetStdHandleKERNEL32.dll??$?6DU?$char_traits@D@std@@V?$allocator@D@1@@std@@YAAAV?$basic_ostream@DU?$char_traits@D@std@@@0@AAV10@ABV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@0@@Z?cout@std@@3V?$basic_ostream@DU?$char_traits@D@std@@@1@AJ?cin@std@@3V?$basic_istream@DU?$char_traits@D@std@@@1@A??$getline@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@YAAAV?$basic_istream@DU?$char_traits@D@std@@@0@AAV10@AAV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@0@@Z??6?$basic_ostream@DU?$char_traits@D@std@@@std@@QAEAAV01@P6AAAV01@AAV01@@Z@Z_??1?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@QAE@XZ{??0?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@QAE@XZ?endl@std@@YAAAV?$basic_ostream@DU?$char_traits@D@std@@@1@AAV21@@ZMSVCP90.dll_amsg_exit__getmainargs,_cexit|_exitf_XcptFilterexit__initenv_initterm_initterm_e<_configthreadlocale__setusermatherr _adjust_fdiv__p__commode__p__fmodej_encode_pointer__set_app_typeK_crt_debugger_hookC?terminate@@YAXXZMSVCR90.dll_unlock__dllonexitv_lock_onexit`_decode_pointers_except_handler4_common _invoke_watson?_controlfp_sInterlockedExchange!SleepInterlockedCompareExchange-TerminateProcessGetCurrentProcess>UnhandledExceptionFilterSetUnhandledExceptionFilterIsDebuggerPresentTQueryPerformanceCounterfGetTickCountGetCurrentThreadIdGetCurrentProcessIdOGetSystemTimeAsFileTimes__CxxFrameHandler3N@D$!@ 8Ph  @(CV(4VS_VERSION_INFOStringFileInfob040904b0QFileDescriptionReads from stdin without leaking info to the terminal and outputs back to stdout6 FileVersion1, 0, 0, 08 InternalNamehiddeninputPLegalCopyrightJordi Boggiano - 2012HOriginalFilenamehiddeninput.exe: ProductNameHidden Input: ProductVersion1, 0, 0, 0DVarFileInfo$Translation  PAPADDINGXXPADDINGPADDINGXXPADDINGPADDINGXXPADDINGPADDINGXXPADDINGPADDINGXXPADDINGPADDINGXXPADDINGPADDINGXXPADDINGPADDINGXXPADDINGPADDINGXXPADDINGPADDINGXXPADDINGPADDINGXXPADDINGPADDINGXXPADDINGPADDINGXXPADDINGPADDINGXXPADDINGPADDINGXXPADDINGPADDINGXXPADDINGPADDINGXXPADDINGPADDINGXXPADDINGPADDINGXXPADDINGPADDINGXXPADDINGPADDINGXXPADDINGPADDINGXXPADDINGPADDINGXXPADDINGPADDINGXXPADDINGPADDINGXXPADDINGPADDINGXXPADDINGPADDINGXXPADDINGPADDINGXXPADDINGPADDINGXXPADDINGPADDINGXXPADDING@00!0/080F0L0T0^0d0n0{000000000000001#1-1@1J1O1T1v1{1111111111111112"2*23292A2M2_2j2p222222222222 333%303N3T3Z3`3f3l3s3z333333333333333334444%4;4B444444444445!5^5c5555H6M6_6}66677 7*7w7|777778 88=8E8P8V8\8b8h8n8t8z88889 $0001 1t1x12 2@2\2`2h2t20 0# This file is part of the Symfony package. # # (c) Fabien Potencier # # For the full copyright and license information, please view # https://symfony.com/doc/current/contributing/code/license.html _sf_{{ COMMAND_NAME }}() { # Use newline as only separator to allow space in completion values local IFS=$'\n' local sf_cmd="${COMP_WORDS[0]}" # for an alias, get the real script behind it sf_cmd_type=$(type -t $sf_cmd) if [[ $sf_cmd_type == "alias" ]]; then sf_cmd=$(alias $sf_cmd | sed -E "s/alias $sf_cmd='(.*)'/\1/") elif [[ $sf_cmd_type == "file" ]]; then sf_cmd=$(type -p $sf_cmd) fi if [[ $sf_cmd_type != "function" && ! -x $sf_cmd ]]; then return 1 fi local cur prev words cword _get_comp_words_by_ref -n := cur prev words cword local completecmd=("$sf_cmd" "_complete" "--no-interaction" "-sbash" "-c$cword" "-S{{ VERSION }}") for w in ${words[@]}; do w=$(printf -- '%b' "$w") # remove quotes from typed values quote="${w:0:1}" if [ "$quote" == \' ]; then w="${w%\'}" w="${w#\'}" elif [ "$quote" == \" ]; then w="${w%\"}" w="${w#\"}" fi # empty values are ignored if [ ! -z "$w" ]; then completecmd+=("-i$w") fi done local sfcomplete if sfcomplete=$(${completecmd[@]} 2>&1); then local quote suggestions quote=${cur:0:1} # Use single quotes by default if suggestions contains backslash (FQCN) if [ "$quote" == '' ] && [[ "$sfcomplete" =~ \\ ]]; then quote=\' fi if [ "$quote" == \' ]; then # single quotes: no additional escaping (does not accept ' in values) suggestions=$(for s in $sfcomplete; do printf $'%q%q%q\n' "$quote" "$s" "$quote"; done) elif [ "$quote" == \" ]; then # double quotes: double escaping for \ $ ` " suggestions=$(for s in $sfcomplete; do s=${s//\\/\\\\} s=${s//\$/\\\$} s=${s//\`/\\\`} s=${s//\"/\\\"} printf $'%q%q%q\n' "$quote" "$s" "$quote"; done) else # no quotes: double escaping suggestions=$(for s in $sfcomplete; do printf $'%q\n' $(printf '%q' "$s"); done) fi COMPREPLY=($(IFS=$'\n' compgen -W "$suggestions" -- $(printf -- "%q" "$cur"))) __ltrim_colon_completions "$cur" else if [[ "$sfcomplete" != *"Command \"_complete\" is not defined."* ]]; then >&2 echo >&2 echo $sfcomplete fi return 1 fi } complete -F _sf_{{ COMMAND_NAME }} {{ COMMAND_NAME }} * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace _HumbugBox7ff99e199a36\Symfony\Component\Console\Descriptor; use _HumbugBox7ff99e199a36\Symfony\Component\Console\Application; use _HumbugBox7ff99e199a36\Symfony\Component\Console\Command\Command; use _HumbugBox7ff99e199a36\Symfony\Component\Console\Helper\Helper; use _HumbugBox7ff99e199a36\Symfony\Component\Console\Input\InputArgument; use _HumbugBox7ff99e199a36\Symfony\Component\Console\Input\InputDefinition; use _HumbugBox7ff99e199a36\Symfony\Component\Console\Input\InputOption; use _HumbugBox7ff99e199a36\Symfony\Component\Console\Output\OutputInterface; /** * Markdown descriptor. * * @author Jean-François Simon * * @internal */ class MarkdownDescriptor extends Descriptor { /** * {@inheritdoc} */ public function describe(OutputInterface $output, object $object, array $options = []) { $decorated = $output->isDecorated(); $output->setDecorated(\false); parent::describe($output, $object, $options); $output->setDecorated($decorated); } /** * {@inheritdoc} */ protected function write(string $content, bool $decorated = \true) { parent::write($content, $decorated); } /** * {@inheritdoc} */ protected function describeInputArgument(InputArgument $argument, array $options = []) { $this->write('#### `' . ($argument->getName() ?: '') . "`\n\n" . ($argument->getDescription() ? \preg_replace('/\\s*[\\r\\n]\\s*/', "\n", $argument->getDescription()) . "\n\n" : '') . '* Is required: ' . ($argument->isRequired() ? 'yes' : 'no') . "\n" . '* Is array: ' . ($argument->isArray() ? 'yes' : 'no') . "\n" . '* Default: `' . \str_replace("\n", '', \var_export($argument->getDefault(), \true)) . '`'); } /** * {@inheritdoc} */ protected function describeInputOption(InputOption $option, array $options = []) { $name = '--' . $option->getName(); if ($option->isNegatable()) { $name .= '|--no-' . $option->getName(); } if ($option->getShortcut()) { $name .= '|-' . \str_replace('|', '|-', $option->getShortcut()) . ''; } $this->write('#### `' . $name . '`' . "\n\n" . ($option->getDescription() ? \preg_replace('/\\s*[\\r\\n]\\s*/', "\n", $option->getDescription()) . "\n\n" : '') . '* Accept value: ' . ($option->acceptValue() ? 'yes' : 'no') . "\n" . '* Is value required: ' . ($option->isValueRequired() ? 'yes' : 'no') . "\n" . '* Is multiple: ' . ($option->isArray() ? 'yes' : 'no') . "\n" . '* Is negatable: ' . ($option->isNegatable() ? 'yes' : 'no') . "\n" . '* Default: `' . \str_replace("\n", '', \var_export($option->getDefault(), \true)) . '`'); } /** * {@inheritdoc} */ protected function describeInputDefinition(InputDefinition $definition, array $options = []) { if ($showArguments = \count($definition->getArguments()) > 0) { $this->write('### Arguments'); foreach ($definition->getArguments() as $argument) { $this->write("\n\n"); if (null !== ($describeInputArgument = $this->describeInputArgument($argument))) { $this->write($describeInputArgument); } } } if (\count($definition->getOptions()) > 0) { if ($showArguments) { $this->write("\n\n"); } $this->write('### Options'); foreach ($definition->getOptions() as $option) { $this->write("\n\n"); if (null !== ($describeInputOption = $this->describeInputOption($option))) { $this->write($describeInputOption); } } } } /** * {@inheritdoc} */ protected function describeCommand(Command $command, array $options = []) { if ($options['short'] ?? \false) { $this->write('`' . $command->getName() . "`\n" . \str_repeat('-', Helper::width($command->getName()) + 2) . "\n\n" . ($command->getDescription() ? $command->getDescription() . "\n\n" : '') . '### Usage' . "\n\n" . \array_reduce($command->getAliases(), function ($carry, $usage) { return $carry . '* `' . $usage . '`' . "\n"; })); return; } $command->mergeApplicationDefinition(\false); $this->write('`' . $command->getName() . "`\n" . \str_repeat('-', Helper::width($command->getName()) + 2) . "\n\n" . ($command->getDescription() ? $command->getDescription() . "\n\n" : '') . '### Usage' . "\n\n" . \array_reduce(\array_merge([$command->getSynopsis()], $command->getAliases(), $command->getUsages()), function ($carry, $usage) { return $carry . '* `' . $usage . '`' . "\n"; })); if ($help = $command->getProcessedHelp()) { $this->write("\n"); $this->write($help); } $definition = $command->getDefinition(); if ($definition->getOptions() || $definition->getArguments()) { $this->write("\n\n"); $this->describeInputDefinition($definition); } } /** * {@inheritdoc} */ protected function describeApplication(Application $application, array $options = []) { $describedNamespace = $options['namespace'] ?? null; $description = new ApplicationDescription($application, $describedNamespace); $title = $this->getApplicationTitle($application); $this->write($title . "\n" . \str_repeat('=', Helper::width($title))); foreach ($description->getNamespaces() as $namespace) { if (ApplicationDescription::GLOBAL_NAMESPACE !== $namespace['id']) { $this->write("\n\n"); $this->write('**' . $namespace['id'] . ':**'); } $this->write("\n\n"); $this->write(\implode("\n", \array_map(function ($commandName) use($description) { return \sprintf('* [`%s`](#%s)', $commandName, \str_replace(':', '', $description->getCommand($commandName)->getName())); }, $namespace['commands']))); } foreach ($description->getCommands() as $command) { $this->write("\n\n"); if (null !== ($describeCommand = $this->describeCommand($command, $options))) { $this->write($describeCommand); } } } private function getApplicationTitle(Application $application) : string { if ('UNKNOWN' !== $application->getName()) { if ('UNKNOWN' !== $application->getVersion()) { return \sprintf('%s %s', $application->getName(), $application->getVersion()); } return $application->getName(); } return 'Console Tool'; } } * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace _HumbugBox7ff99e199a36\Symfony\Component\Console\Descriptor; use _HumbugBox7ff99e199a36\Symfony\Component\Console\Output\OutputInterface; /** * Descriptor interface. * * @author Jean-François Simon */ interface DescriptorInterface { public function describe(OutputInterface $output, object $object, array $options = []); } * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace _HumbugBox7ff99e199a36\Symfony\Component\Console\Descriptor; use _HumbugBox7ff99e199a36\Symfony\Component\Console\Application; use _HumbugBox7ff99e199a36\Symfony\Component\Console\Command\Command; use _HumbugBox7ff99e199a36\Symfony\Component\Console\Input\InputArgument; use _HumbugBox7ff99e199a36\Symfony\Component\Console\Input\InputDefinition; use _HumbugBox7ff99e199a36\Symfony\Component\Console\Input\InputOption; /** * JSON descriptor. * * @author Jean-François Simon * * @internal */ class JsonDescriptor extends Descriptor { /** * {@inheritdoc} */ protected function describeInputArgument(InputArgument $argument, array $options = []) { $this->writeData($this->getInputArgumentData($argument), $options); } /** * {@inheritdoc} */ protected function describeInputOption(InputOption $option, array $options = []) { $this->writeData($this->getInputOptionData($option), $options); if ($option->isNegatable()) { $this->writeData($this->getInputOptionData($option, \true), $options); } } /** * {@inheritdoc} */ protected function describeInputDefinition(InputDefinition $definition, array $options = []) { $this->writeData($this->getInputDefinitionData($definition), $options); } /** * {@inheritdoc} */ protected function describeCommand(Command $command, array $options = []) { $this->writeData($this->getCommandData($command, $options['short'] ?? \false), $options); } /** * {@inheritdoc} */ protected function describeApplication(Application $application, array $options = []) { $describedNamespace = $options['namespace'] ?? null; $description = new ApplicationDescription($application, $describedNamespace, \true); $commands = []; foreach ($description->getCommands() as $command) { $commands[] = $this->getCommandData($command, $options['short'] ?? \false); } $data = []; if ('UNKNOWN' !== $application->getName()) { $data['application']['name'] = $application->getName(); if ('UNKNOWN' !== $application->getVersion()) { $data['application']['version'] = $application->getVersion(); } } $data['commands'] = $commands; if ($describedNamespace) { $data['namespace'] = $describedNamespace; } else { $data['namespaces'] = \array_values($description->getNamespaces()); } $this->writeData($data, $options); } /** * Writes data as json. */ private function writeData(array $data, array $options) { $flags = $options['json_encoding'] ?? 0; $this->write(\json_encode($data, $flags)); } private function getInputArgumentData(InputArgument $argument) : array { return ['name' => $argument->getName(), 'is_required' => $argument->isRequired(), 'is_array' => $argument->isArray(), 'description' => \preg_replace('/\\s*[\\r\\n]\\s*/', ' ', $argument->getDescription()), 'default' => \INF === $argument->getDefault() ? 'INF' : $argument->getDefault()]; } private function getInputOptionData(InputOption $option, bool $negated = \false) : array { return $negated ? ['name' => '--no-' . $option->getName(), 'shortcut' => '', 'accept_value' => \false, 'is_value_required' => \false, 'is_multiple' => \false, 'description' => 'Negate the "--' . $option->getName() . '" option', 'default' => \false] : ['name' => '--' . $option->getName(), 'shortcut' => $option->getShortcut() ? '-' . \str_replace('|', '|-', $option->getShortcut()) : '', 'accept_value' => $option->acceptValue(), 'is_value_required' => $option->isValueRequired(), 'is_multiple' => $option->isArray(), 'description' => \preg_replace('/\\s*[\\r\\n]\\s*/', ' ', $option->getDescription()), 'default' => \INF === $option->getDefault() ? 'INF' : $option->getDefault()]; } private function getInputDefinitionData(InputDefinition $definition) : array { $inputArguments = []; foreach ($definition->getArguments() as $name => $argument) { $inputArguments[$name] = $this->getInputArgumentData($argument); } $inputOptions = []; foreach ($definition->getOptions() as $name => $option) { $inputOptions[$name] = $this->getInputOptionData($option); if ($option->isNegatable()) { $inputOptions['no-' . $name] = $this->getInputOptionData($option, \true); } } return ['arguments' => $inputArguments, 'options' => $inputOptions]; } private function getCommandData(Command $command, bool $short = \false) : array { $data = ['name' => $command->getName(), 'description' => $command->getDescription()]; if ($short) { $data += ['usage' => $command->getAliases()]; } else { $command->mergeApplicationDefinition(\false); $data += ['usage' => \array_merge([$command->getSynopsis()], $command->getUsages(), $command->getAliases()), 'help' => $command->getProcessedHelp(), 'definition' => $this->getInputDefinitionData($command->getDefinition())]; } $data['hidden'] = $command->isHidden(); return $data; } } * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace _HumbugBox7ff99e199a36\Symfony\Component\Console\Descriptor; use _HumbugBox7ff99e199a36\Symfony\Component\Console\Application; use _HumbugBox7ff99e199a36\Symfony\Component\Console\Command\Command; use _HumbugBox7ff99e199a36\Symfony\Component\Console\Input\InputArgument; use _HumbugBox7ff99e199a36\Symfony\Component\Console\Input\InputDefinition; use _HumbugBox7ff99e199a36\Symfony\Component\Console\Input\InputOption; /** * XML descriptor. * * @author Jean-François Simon * * @internal */ class XmlDescriptor extends Descriptor { public function getInputDefinitionDocument(InputDefinition $definition) : \DOMDocument { $dom = new \DOMDocument('1.0', 'UTF-8'); $dom->appendChild($definitionXML = $dom->createElement('definition')); $definitionXML->appendChild($argumentsXML = $dom->createElement('arguments')); foreach ($definition->getArguments() as $argument) { $this->appendDocument($argumentsXML, $this->getInputArgumentDocument($argument)); } $definitionXML->appendChild($optionsXML = $dom->createElement('options')); foreach ($definition->getOptions() as $option) { $this->appendDocument($optionsXML, $this->getInputOptionDocument($option)); } return $dom; } public function getCommandDocument(Command $command, bool $short = \false) : \DOMDocument { $dom = new \DOMDocument('1.0', 'UTF-8'); $dom->appendChild($commandXML = $dom->createElement('command')); $commandXML->setAttribute('id', $command->getName()); $commandXML->setAttribute('name', $command->getName()); $commandXML->setAttribute('hidden', $command->isHidden() ? 1 : 0); $commandXML->appendChild($usagesXML = $dom->createElement('usages')); $commandXML->appendChild($descriptionXML = $dom->createElement('description')); $descriptionXML->appendChild($dom->createTextNode(\str_replace("\n", "\n ", $command->getDescription()))); if ($short) { foreach ($command->getAliases() as $usage) { $usagesXML->appendChild($dom->createElement('usage', $usage)); } } else { $command->mergeApplicationDefinition(\false); foreach (\array_merge([$command->getSynopsis()], $command->getAliases(), $command->getUsages()) as $usage) { $usagesXML->appendChild($dom->createElement('usage', $usage)); } $commandXML->appendChild($helpXML = $dom->createElement('help')); $helpXML->appendChild($dom->createTextNode(\str_replace("\n", "\n ", $command->getProcessedHelp()))); $definitionXML = $this->getInputDefinitionDocument($command->getDefinition()); $this->appendDocument($commandXML, $definitionXML->getElementsByTagName('definition')->item(0)); } return $dom; } public function getApplicationDocument(Application $application, ?string $namespace = null, bool $short = \false) : \DOMDocument { $dom = new \DOMDocument('1.0', 'UTF-8'); $dom->appendChild($rootXml = $dom->createElement('symfony')); if ('UNKNOWN' !== $application->getName()) { $rootXml->setAttribute('name', $application->getName()); if ('UNKNOWN' !== $application->getVersion()) { $rootXml->setAttribute('version', $application->getVersion()); } } $rootXml->appendChild($commandsXML = $dom->createElement('commands')); $description = new ApplicationDescription($application, $namespace, \true); if ($namespace) { $commandsXML->setAttribute('namespace', $namespace); } foreach ($description->getCommands() as $command) { $this->appendDocument($commandsXML, $this->getCommandDocument($command, $short)); } if (!$namespace) { $rootXml->appendChild($namespacesXML = $dom->createElement('namespaces')); foreach ($description->getNamespaces() as $namespaceDescription) { $namespacesXML->appendChild($namespaceArrayXML = $dom->createElement('namespace')); $namespaceArrayXML->setAttribute('id', $namespaceDescription['id']); foreach ($namespaceDescription['commands'] as $name) { $namespaceArrayXML->appendChild($commandXML = $dom->createElement('command')); $commandXML->appendChild($dom->createTextNode($name)); } } } return $dom; } /** * {@inheritdoc} */ protected function describeInputArgument(InputArgument $argument, array $options = []) { $this->writeDocument($this->getInputArgumentDocument($argument)); } /** * {@inheritdoc} */ protected function describeInputOption(InputOption $option, array $options = []) { $this->writeDocument($this->getInputOptionDocument($option)); } /** * {@inheritdoc} */ protected function describeInputDefinition(InputDefinition $definition, array $options = []) { $this->writeDocument($this->getInputDefinitionDocument($definition)); } /** * {@inheritdoc} */ protected function describeCommand(Command $command, array $options = []) { $this->writeDocument($this->getCommandDocument($command, $options['short'] ?? \false)); } /** * {@inheritdoc} */ protected function describeApplication(Application $application, array $options = []) { $this->writeDocument($this->getApplicationDocument($application, $options['namespace'] ?? null, $options['short'] ?? \false)); } /** * Appends document children to parent node. */ private function appendDocument(\DOMNode $parentNode, \DOMNode $importedParent) { foreach ($importedParent->childNodes as $childNode) { $parentNode->appendChild($parentNode->ownerDocument->importNode($childNode, \true)); } } /** * Writes DOM document. */ private function writeDocument(\DOMDocument $dom) { $dom->formatOutput = \true; $this->write($dom->saveXML()); } private function getInputArgumentDocument(InputArgument $argument) : \DOMDocument { $dom = new \DOMDocument('1.0', 'UTF-8'); $dom->appendChild($objectXML = $dom->createElement('argument')); $objectXML->setAttribute('name', $argument->getName()); $objectXML->setAttribute('is_required', $argument->isRequired() ? 1 : 0); $objectXML->setAttribute('is_array', $argument->isArray() ? 1 : 0); $objectXML->appendChild($descriptionXML = $dom->createElement('description')); $descriptionXML->appendChild($dom->createTextNode($argument->getDescription())); $objectXML->appendChild($defaultsXML = $dom->createElement('defaults')); $defaults = \is_array($argument->getDefault()) ? $argument->getDefault() : (\is_bool($argument->getDefault()) ? [\var_export($argument->getDefault(), \true)] : ($argument->getDefault() ? [$argument->getDefault()] : [])); foreach ($defaults as $default) { $defaultsXML->appendChild($defaultXML = $dom->createElement('default')); $defaultXML->appendChild($dom->createTextNode($default)); } return $dom; } private function getInputOptionDocument(InputOption $option) : \DOMDocument { $dom = new \DOMDocument('1.0', 'UTF-8'); $dom->appendChild($objectXML = $dom->createElement('option')); $objectXML->setAttribute('name', '--' . $option->getName()); $pos = \strpos($option->getShortcut() ?? '', '|'); if (\false !== $pos) { $objectXML->setAttribute('shortcut', '-' . \substr($option->getShortcut(), 0, $pos)); $objectXML->setAttribute('shortcuts', '-' . \str_replace('|', '|-', $option->getShortcut())); } else { $objectXML->setAttribute('shortcut', $option->getShortcut() ? '-' . $option->getShortcut() : ''); } $objectXML->setAttribute('accept_value', $option->acceptValue() ? 1 : 0); $objectXML->setAttribute('is_value_required', $option->isValueRequired() ? 1 : 0); $objectXML->setAttribute('is_multiple', $option->isArray() ? 1 : 0); $objectXML->appendChild($descriptionXML = $dom->createElement('description')); $descriptionXML->appendChild($dom->createTextNode($option->getDescription())); if ($option->acceptValue()) { $defaults = \is_array($option->getDefault()) ? $option->getDefault() : (\is_bool($option->getDefault()) ? [\var_export($option->getDefault(), \true)] : ($option->getDefault() ? [$option->getDefault()] : [])); $objectXML->appendChild($defaultsXML = $dom->createElement('defaults')); if (!empty($defaults)) { foreach ($defaults as $default) { $defaultsXML->appendChild($defaultXML = $dom->createElement('default')); $defaultXML->appendChild($dom->createTextNode($default)); } } } if ($option->isNegatable()) { $dom->appendChild($objectXML = $dom->createElement('option')); $objectXML->setAttribute('name', '--no-' . $option->getName()); $objectXML->setAttribute('shortcut', ''); $objectXML->setAttribute('accept_value', 0); $objectXML->setAttribute('is_value_required', 0); $objectXML->setAttribute('is_multiple', 0); $objectXML->appendChild($descriptionXML = $dom->createElement('description')); $descriptionXML->appendChild($dom->createTextNode('Negate the "--' . $option->getName() . '" option')); } return $dom; } } * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace _HumbugBox7ff99e199a36\Symfony\Component\Console\Descriptor; use _HumbugBox7ff99e199a36\Symfony\Component\Console\Application; use _HumbugBox7ff99e199a36\Symfony\Component\Console\Command\Command; use _HumbugBox7ff99e199a36\Symfony\Component\Console\Exception\CommandNotFoundException; /** * @author Jean-François Simon * * @internal */ class ApplicationDescription { public const GLOBAL_NAMESPACE = '_global'; private $application; private $namespace; private $showHidden; /** * @var array */ private $namespaces; /** * @var array */ private $commands; /** * @var array */ private $aliases; public function __construct(Application $application, ?string $namespace = null, bool $showHidden = \false) { $this->application = $application; $this->namespace = $namespace; $this->showHidden = $showHidden; } public function getNamespaces() : array { if (null === $this->namespaces) { $this->inspectApplication(); } return $this->namespaces; } /** * @return Command[] */ public function getCommands() : array { if (null === $this->commands) { $this->inspectApplication(); } return $this->commands; } /** * @throws CommandNotFoundException */ public function getCommand(string $name) : Command { if (!isset($this->commands[$name]) && !isset($this->aliases[$name])) { throw new CommandNotFoundException(\sprintf('Command "%s" does not exist.', $name)); } return $this->commands[$name] ?? $this->aliases[$name]; } private function inspectApplication() { $this->commands = []; $this->namespaces = []; $all = $this->application->all($this->namespace ? $this->application->findNamespace($this->namespace) : null); foreach ($this->sortCommands($all) as $namespace => $commands) { $names = []; /** @var Command $command */ foreach ($commands as $name => $command) { if (!$command->getName() || !$this->showHidden && $command->isHidden()) { continue; } if ($command->getName() === $name) { $this->commands[$name] = $command; } else { $this->aliases[$name] = $command; } $names[] = $name; } $this->namespaces[$namespace] = ['id' => $namespace, 'commands' => $names]; } } private function sortCommands(array $commands) : array { $namespacedCommands = []; $globalCommands = []; $sortedCommands = []; foreach ($commands as $name => $command) { $key = $this->application->extractNamespace($name, 1); if (\in_array($key, ['', self::GLOBAL_NAMESPACE], \true)) { $globalCommands[$name] = $command; } else { $namespacedCommands[$key][$name] = $command; } } if ($globalCommands) { \ksort($globalCommands); $sortedCommands[self::GLOBAL_NAMESPACE] = $globalCommands; } if ($namespacedCommands) { \ksort($namespacedCommands, \SORT_STRING); foreach ($namespacedCommands as $key => $commandsSet) { \ksort($commandsSet); $sortedCommands[$key] = $commandsSet; } } return $sortedCommands; } } * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace _HumbugBox7ff99e199a36\Symfony\Component\Console\Descriptor; use _HumbugBox7ff99e199a36\Symfony\Component\Console\Application; use _HumbugBox7ff99e199a36\Symfony\Component\Console\Command\Command; use _HumbugBox7ff99e199a36\Symfony\Component\Console\Exception\InvalidArgumentException; use _HumbugBox7ff99e199a36\Symfony\Component\Console\Input\InputArgument; use _HumbugBox7ff99e199a36\Symfony\Component\Console\Input\InputDefinition; use _HumbugBox7ff99e199a36\Symfony\Component\Console\Input\InputOption; use _HumbugBox7ff99e199a36\Symfony\Component\Console\Output\OutputInterface; /** * @author Jean-François Simon * * @internal */ abstract class Descriptor implements DescriptorInterface { /** * @var OutputInterface */ protected $output; /** * {@inheritdoc} */ public function describe(OutputInterface $output, object $object, array $options = []) { $this->output = $output; switch (\true) { case $object instanceof InputArgument: $this->describeInputArgument($object, $options); break; case $object instanceof InputOption: $this->describeInputOption($object, $options); break; case $object instanceof InputDefinition: $this->describeInputDefinition($object, $options); break; case $object instanceof Command: $this->describeCommand($object, $options); break; case $object instanceof Application: $this->describeApplication($object, $options); break; default: throw new InvalidArgumentException(\sprintf('Object of type "%s" is not describable.', \get_debug_type($object))); } } /** * Writes content to output. */ protected function write(string $content, bool $decorated = \false) { $this->output->write($content, \false, $decorated ? OutputInterface::OUTPUT_NORMAL : OutputInterface::OUTPUT_RAW); } /** * Describes an InputArgument instance. */ protected abstract function describeInputArgument(InputArgument $argument, array $options = []); /** * Describes an InputOption instance. */ protected abstract function describeInputOption(InputOption $option, array $options = []); /** * Describes an InputDefinition instance. */ protected abstract function describeInputDefinition(InputDefinition $definition, array $options = []); /** * Describes a Command instance. */ protected abstract function describeCommand(Command $command, array $options = []); /** * Describes an Application instance. */ protected abstract function describeApplication(Application $application, array $options = []); } * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace _HumbugBox7ff99e199a36\Symfony\Component\Console\Descriptor; use _HumbugBox7ff99e199a36\Symfony\Component\Console\Application; use _HumbugBox7ff99e199a36\Symfony\Component\Console\Command\Command; use _HumbugBox7ff99e199a36\Symfony\Component\Console\Formatter\OutputFormatter; use _HumbugBox7ff99e199a36\Symfony\Component\Console\Helper\Helper; use _HumbugBox7ff99e199a36\Symfony\Component\Console\Input\InputArgument; use _HumbugBox7ff99e199a36\Symfony\Component\Console\Input\InputDefinition; use _HumbugBox7ff99e199a36\Symfony\Component\Console\Input\InputOption; /** * Text descriptor. * * @author Jean-François Simon * * @internal */ class TextDescriptor extends Descriptor { /** * {@inheritdoc} */ protected function describeInputArgument(InputArgument $argument, array $options = []) { if (null !== $argument->getDefault() && (!\is_array($argument->getDefault()) || \count($argument->getDefault()))) { $default = \sprintf(' [default: %s]', $this->formatDefaultValue($argument->getDefault())); } else { $default = ''; } $totalWidth = $options['total_width'] ?? Helper::width($argument->getName()); $spacingWidth = $totalWidth - \strlen($argument->getName()); $this->writeText(\sprintf( ' %s %s%s%s', $argument->getName(), \str_repeat(' ', $spacingWidth), // + 4 = 2 spaces before , 2 spaces after \preg_replace('/\\s*[\\r\\n]\\s*/', "\n" . \str_repeat(' ', $totalWidth + 4), $argument->getDescription()), $default ), $options); } /** * {@inheritdoc} */ protected function describeInputOption(InputOption $option, array $options = []) { if ($option->acceptValue() && null !== $option->getDefault() && (!\is_array($option->getDefault()) || \count($option->getDefault()))) { $default = \sprintf(' [default: %s]', $this->formatDefaultValue($option->getDefault())); } else { $default = ''; } $value = ''; if ($option->acceptValue()) { $value = '=' . \strtoupper($option->getName()); if ($option->isValueOptional()) { $value = '[' . $value . ']'; } } $totalWidth = $options['total_width'] ?? $this->calculateTotalWidthForOptions([$option]); $synopsis = \sprintf('%s%s', $option->getShortcut() ? \sprintf('-%s, ', $option->getShortcut()) : ' ', \sprintf($option->isNegatable() ? '--%1$s|--no-%1$s' : '--%1$s%2$s', $option->getName(), $value)); $spacingWidth = $totalWidth - Helper::width($synopsis); $this->writeText(\sprintf( ' %s %s%s%s%s', $synopsis, \str_repeat(' ', $spacingWidth), // + 4 = 2 spaces before , 2 spaces after \preg_replace('/\\s*[\\r\\n]\\s*/', "\n" . \str_repeat(' ', $totalWidth + 4), $option->getDescription()), $default, $option->isArray() ? ' (multiple values allowed)' : '' ), $options); } /** * {@inheritdoc} */ protected function describeInputDefinition(InputDefinition $definition, array $options = []) { $totalWidth = $this->calculateTotalWidthForOptions($definition->getOptions()); foreach ($definition->getArguments() as $argument) { $totalWidth = \max($totalWidth, Helper::width($argument->getName())); } if ($definition->getArguments()) { $this->writeText('Arguments:', $options); $this->writeText("\n"); foreach ($definition->getArguments() as $argument) { $this->describeInputArgument($argument, \array_merge($options, ['total_width' => $totalWidth])); $this->writeText("\n"); } } if ($definition->getArguments() && $definition->getOptions()) { $this->writeText("\n"); } if ($definition->getOptions()) { $laterOptions = []; $this->writeText('Options:', $options); foreach ($definition->getOptions() as $option) { if (\strlen($option->getShortcut() ?? '') > 1) { $laterOptions[] = $option; continue; } $this->writeText("\n"); $this->describeInputOption($option, \array_merge($options, ['total_width' => $totalWidth])); } foreach ($laterOptions as $option) { $this->writeText("\n"); $this->describeInputOption($option, \array_merge($options, ['total_width' => $totalWidth])); } } } /** * {@inheritdoc} */ protected function describeCommand(Command $command, array $options = []) { $command->mergeApplicationDefinition(\false); if ($description = $command->getDescription()) { $this->writeText('Description:', $options); $this->writeText("\n"); $this->writeText(' ' . $description); $this->writeText("\n\n"); } $this->writeText('Usage:', $options); foreach (\array_merge([$command->getSynopsis(\true)], $command->getAliases(), $command->getUsages()) as $usage) { $this->writeText("\n"); $this->writeText(' ' . OutputFormatter::escape($usage), $options); } $this->writeText("\n"); $definition = $command->getDefinition(); if ($definition->getOptions() || $definition->getArguments()) { $this->writeText("\n"); $this->describeInputDefinition($definition, $options); $this->writeText("\n"); } $help = $command->getProcessedHelp(); if ($help && $help !== $description) { $this->writeText("\n"); $this->writeText('Help:', $options); $this->writeText("\n"); $this->writeText(' ' . \str_replace("\n", "\n ", $help), $options); $this->writeText("\n"); } } /** * {@inheritdoc} */ protected function describeApplication(Application $application, array $options = []) { $describedNamespace = $options['namespace'] ?? null; $description = new ApplicationDescription($application, $describedNamespace); if (isset($options['raw_text']) && $options['raw_text']) { $width = $this->getColumnWidth($description->getCommands()); foreach ($description->getCommands() as $command) { $this->writeText(\sprintf("%-{$width}s %s", $command->getName(), $command->getDescription()), $options); $this->writeText("\n"); } } else { if ('' != ($help = $application->getHelp())) { $this->writeText("{$help}\n\n", $options); } $this->writeText("Usage:\n", $options); $this->writeText(" command [options] [arguments]\n\n", $options); $this->describeInputDefinition(new InputDefinition($application->getDefinition()->getOptions()), $options); $this->writeText("\n"); $this->writeText("\n"); $commands = $description->getCommands(); $namespaces = $description->getNamespaces(); if ($describedNamespace && $namespaces) { // make sure all alias commands are included when describing a specific namespace $describedNamespaceInfo = \reset($namespaces); foreach ($describedNamespaceInfo['commands'] as $name) { $commands[$name] = $description->getCommand($name); } } // calculate max. width based on available commands per namespace $width = $this->getColumnWidth(\array_merge(...\array_values(\array_map(function ($namespace) use($commands) { return \array_intersect($namespace['commands'], \array_keys($commands)); }, \array_values($namespaces))))); if ($describedNamespace) { $this->writeText(\sprintf('Available commands for the "%s" namespace:', $describedNamespace), $options); } else { $this->writeText('Available commands:', $options); } foreach ($namespaces as $namespace) { $namespace['commands'] = \array_filter($namespace['commands'], function ($name) use($commands) { return isset($commands[$name]); }); if (!$namespace['commands']) { continue; } if (!$describedNamespace && ApplicationDescription::GLOBAL_NAMESPACE !== $namespace['id']) { $this->writeText("\n"); $this->writeText(' ' . $namespace['id'] . '', $options); } foreach ($namespace['commands'] as $name) { $this->writeText("\n"); $spacingWidth = $width - Helper::width($name); $command = $commands[$name]; $commandAliases = $name === $command->getName() ? $this->getCommandAliasesText($command) : ''; $this->writeText(\sprintf(' %s%s%s', $name, \str_repeat(' ', $spacingWidth), $commandAliases . $command->getDescription()), $options); } } $this->writeText("\n"); } } /** * {@inheritdoc} */ private function writeText(string $content, array $options = []) { $this->write(isset($options['raw_text']) && $options['raw_text'] ? \strip_tags($content) : $content, isset($options['raw_output']) ? !$options['raw_output'] : \true); } /** * Formats command aliases to show them in the command description. */ private function getCommandAliasesText(Command $command) : string { $text = ''; $aliases = $command->getAliases(); if ($aliases) { $text = '[' . \implode('|', $aliases) . '] '; } return $text; } /** * Formats input option/argument default value. * * @param mixed $default */ private function formatDefaultValue($default) : string { if (\INF === $default) { return 'INF'; } if (\is_string($default)) { $default = OutputFormatter::escape($default); } elseif (\is_array($default)) { foreach ($default as $key => $value) { if (\is_string($value)) { $default[$key] = OutputFormatter::escape($value); } } } return \str_replace('\\\\', '\\', \json_encode($default, \JSON_UNESCAPED_SLASHES | \JSON_UNESCAPED_UNICODE)); } /** * @param array $commands */ private function getColumnWidth(array $commands) : int { $widths = []; foreach ($commands as $command) { if ($command instanceof Command) { $widths[] = Helper::width($command->getName()); foreach ($command->getAliases() as $alias) { $widths[] = Helper::width($alias); } } else { $widths[] = Helper::width($command); } } return $widths ? \max($widths) + 2 : 0; } /** * @param InputOption[] $options */ private function calculateTotalWidthForOptions(array $options) : int { $totalWidth = 0; foreach ($options as $option) { // "-" + shortcut + ", --" + name $nameLength = 1 + \max(Helper::width($option->getShortcut()), 1) + 4 + Helper::width($option->getName()); if ($option->isNegatable()) { $nameLength += 6 + Helper::width($option->getName()); // |--no- + name } elseif ($option->acceptValue()) { $valueLength = 1 + Helper::width($option->getName()); // = + value $valueLength += $option->isValueOptional() ? 2 : 0; // [ + ] $nameLength += $valueLength; } $totalWidth = \max($totalWidth, $nameLength); } return $totalWidth; } } * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace _HumbugBox7ff99e199a36\Symfony\Component\Console; use _HumbugBox7ff99e199a36\Symfony\Component\Console\Exception\InvalidArgumentException; /** * @author Fabien Potencier */ final class Color { private const COLORS = ['black' => 0, 'red' => 1, 'green' => 2, 'yellow' => 3, 'blue' => 4, 'magenta' => 5, 'cyan' => 6, 'white' => 7, 'default' => 9]; private const BRIGHT_COLORS = ['gray' => 0, 'bright-red' => 1, 'bright-green' => 2, 'bright-yellow' => 3, 'bright-blue' => 4, 'bright-magenta' => 5, 'bright-cyan' => 6, 'bright-white' => 7]; private const AVAILABLE_OPTIONS = ['bold' => ['set' => 1, 'unset' => 22], 'underscore' => ['set' => 4, 'unset' => 24], 'blink' => ['set' => 5, 'unset' => 25], 'reverse' => ['set' => 7, 'unset' => 27], 'conceal' => ['set' => 8, 'unset' => 28]]; private $foreground; private $background; private $options = []; public function __construct(string $foreground = '', string $background = '', array $options = []) { $this->foreground = $this->parseColor($foreground); $this->background = $this->parseColor($background, \true); foreach ($options as $option) { if (!isset(self::AVAILABLE_OPTIONS[$option])) { throw new InvalidArgumentException(\sprintf('Invalid option specified: "%s". Expected one of (%s).', $option, \implode(', ', \array_keys(self::AVAILABLE_OPTIONS)))); } $this->options[$option] = self::AVAILABLE_OPTIONS[$option]; } } public function apply(string $text) : string { return $this->set() . $text . $this->unset(); } public function set() : string { $setCodes = []; if ('' !== $this->foreground) { $setCodes[] = $this->foreground; } if ('' !== $this->background) { $setCodes[] = $this->background; } foreach ($this->options as $option) { $setCodes[] = $option['set']; } if (0 === \count($setCodes)) { return ''; } return \sprintf("\x1b[%sm", \implode(';', $setCodes)); } public function unset() : string { $unsetCodes = []; if ('' !== $this->foreground) { $unsetCodes[] = 39; } if ('' !== $this->background) { $unsetCodes[] = 49; } foreach ($this->options as $option) { $unsetCodes[] = $option['unset']; } if (0 === \count($unsetCodes)) { return ''; } return \sprintf("\x1b[%sm", \implode(';', $unsetCodes)); } private function parseColor(string $color, bool $background = \false) : string { if ('' === $color) { return ''; } if ('#' === $color[0]) { $color = \substr($color, 1); if (3 === \strlen($color)) { $color = $color[0] . $color[0] . $color[1] . $color[1] . $color[2] . $color[2]; } if (6 !== \strlen($color)) { throw new InvalidArgumentException(\sprintf('Invalid "%s" color.', $color)); } return ($background ? '4' : '3') . $this->convertHexColorToAnsi(\hexdec($color)); } if (isset(self::COLORS[$color])) { return ($background ? '4' : '3') . self::COLORS[$color]; } if (isset(self::BRIGHT_COLORS[$color])) { return ($background ? '10' : '9') . self::BRIGHT_COLORS[$color]; } throw new InvalidArgumentException(\sprintf('Invalid "%s" color; expected one of (%s).', $color, \implode(', ', \array_merge(\array_keys(self::COLORS), \array_keys(self::BRIGHT_COLORS))))); } private function convertHexColorToAnsi(int $color) : string { $r = $color >> 16 & 255; $g = $color >> 8 & 255; $b = $color & 255; // see https://github.com/termstandard/colors/ for more information about true color support if ('truecolor' !== \getenv('COLORTERM')) { return (string) $this->degradeHexColorToAnsi($r, $g, $b); } return \sprintf('8;2;%d;%d;%d', $r, $g, $b); } private function degradeHexColorToAnsi(int $r, int $g, int $b) : int { if (0 === \round($this->getSaturation($r, $g, $b) / 50)) { return 0; } return \round($b / 255) << 2 | \round($g / 255) << 1 | \round($r / 255); } private function getSaturation(int $r, int $g, int $b) : int { $r = $r / 255; $g = $g / 255; $b = $b / 255; $v = \max($r, $g, $b); if (0 === ($diff = $v - \min($r, $g, $b))) { return 0; } return (int) $diff * 100 / $v; } } * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace _HumbugBox7ff99e199a36\Symfony\Component\Console\EventListener; use _HumbugBox7ff99e199a36\Psr\Log\LoggerInterface; use _HumbugBox7ff99e199a36\Symfony\Component\Console\ConsoleEvents; use _HumbugBox7ff99e199a36\Symfony\Component\Console\Event\ConsoleErrorEvent; use _HumbugBox7ff99e199a36\Symfony\Component\Console\Event\ConsoleEvent; use _HumbugBox7ff99e199a36\Symfony\Component\Console\Event\ConsoleTerminateEvent; use _HumbugBox7ff99e199a36\Symfony\Component\EventDispatcher\EventSubscriberInterface; /** * @author James Halsall * @author Robin Chalas */ class ErrorListener implements EventSubscriberInterface { private $logger; public function __construct(?LoggerInterface $logger = null) { $this->logger = $logger; } public function onConsoleError(ConsoleErrorEvent $event) { if (null === $this->logger) { return; } $error = $event->getError(); if (!($inputString = $this->getInputString($event))) { $this->logger->critical('An error occurred while using the console. Message: "{message}"', ['exception' => $error, 'message' => $error->getMessage()]); return; } $this->logger->critical('Error thrown while running command "{command}". Message: "{message}"', ['exception' => $error, 'command' => $inputString, 'message' => $error->getMessage()]); } public function onConsoleTerminate(ConsoleTerminateEvent $event) { if (null === $this->logger) { return; } $exitCode = $event->getExitCode(); if (0 === $exitCode) { return; } if (!($inputString = $this->getInputString($event))) { $this->logger->debug('The console exited with code "{code}"', ['code' => $exitCode]); return; } $this->logger->debug('Command "{command}" exited with code "{code}"', ['command' => $inputString, 'code' => $exitCode]); } public static function getSubscribedEvents() { return [ConsoleEvents::ERROR => ['onConsoleError', -128], ConsoleEvents::TERMINATE => ['onConsoleTerminate', -128]]; } private static function getInputString(ConsoleEvent $event) : ?string { $commandName = $event->getCommand() ? $event->getCommand()->getName() : null; $input = $event->getInput(); if (\method_exists($input, '__toString')) { if ($commandName) { return \str_replace(["'{$commandName}'", "\"{$commandName}\""], $commandName, (string) $input); } return (string) $input; } return $commandName; } } * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace _HumbugBox7ff99e199a36\Symfony\Component\Console\SignalRegistry; final class SignalRegistry { private $signalHandlers = []; public function __construct() { if (\function_exists('pcntl_async_signals')) { \pcntl_async_signals(\true); } } public function register(int $signal, callable $signalHandler) : void { if (!isset($this->signalHandlers[$signal])) { $previousCallback = \pcntl_signal_get_handler($signal); if (\is_callable($previousCallback)) { $this->signalHandlers[$signal][] = $previousCallback; } } $this->signalHandlers[$signal][] = $signalHandler; \pcntl_signal($signal, [$this, 'handle']); } public static function isSupported() : bool { if (!\function_exists('pcntl_signal')) { return \false; } if (\in_array('pcntl_signal', \explode(',', \ini_get('disable_functions')))) { return \false; } return \true; } /** * @internal */ public function handle(int $signal) : void { $count = \count($this->signalHandlers[$signal]); foreach ($this->signalHandlers[$signal] as $i => $signalHandler) { $hasNext = $i !== $count - 1; $signalHandler($signal, $hasNext); } } } * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace _HumbugBox7ff99e199a36\Symfony\Component\Console; class Terminal { private static $width; private static $height; private static $stty; /** * Gets the terminal width. * * @return int */ public function getWidth() { $width = \getenv('COLUMNS'); if (\false !== $width) { return (int) \trim($width); } if (null === self::$width) { self::initDimensions(); } return self::$width ?: 80; } /** * Gets the terminal height. * * @return int */ public function getHeight() { $height = \getenv('LINES'); if (\false !== $height) { return (int) \trim($height); } if (null === self::$height) { self::initDimensions(); } return self::$height ?: 50; } /** * @internal */ public static function hasSttyAvailable() : bool { if (null !== self::$stty) { return self::$stty; } // skip check if shell_exec function is disabled if (!\function_exists('shell_exec')) { return \false; } return self::$stty = (bool) \shell_exec('stty 2> ' . ('\\' === \DIRECTORY_SEPARATOR ? 'NUL' : '/dev/null')); } private static function initDimensions() { if ('\\' === \DIRECTORY_SEPARATOR) { $ansicon = \getenv('ANSICON'); if (\false !== $ansicon && \preg_match('/^(\\d+)x(\\d+)(?: \\((\\d+)x(\\d+)\\))?$/', \trim($ansicon), $matches)) { // extract [w, H] from "wxh (WxH)" // or [w, h] from "wxh" self::$width = (int) $matches[1]; self::$height = isset($matches[4]) ? (int) $matches[4] : (int) $matches[2]; } elseif (!self::hasVt100Support() && self::hasSttyAvailable()) { // only use stty on Windows if the terminal does not support vt100 (e.g. Windows 7 + git-bash) // testing for stty in a Windows 10 vt100-enabled console will implicitly disable vt100 support on STDOUT self::initDimensionsUsingStty(); } elseif (null !== ($dimensions = self::getConsoleMode())) { // extract [w, h] from "wxh" self::$width = (int) $dimensions[0]; self::$height = (int) $dimensions[1]; } } else { self::initDimensionsUsingStty(); } } /** * Returns whether STDOUT has vt100 support (some Windows 10+ configurations). */ private static function hasVt100Support() : bool { return \function_exists('sapi_windows_vt100_support') && \sapi_windows_vt100_support(\fopen('php://stdout', 'w')); } /** * Initializes dimensions using the output of an stty columns line. */ private static function initDimensionsUsingStty() { if ($sttyString = self::getSttyColumns()) { if (\preg_match('/rows.(\\d+);.columns.(\\d+);/i', $sttyString, $matches)) { // extract [w, h] from "rows h; columns w;" self::$width = (int) $matches[2]; self::$height = (int) $matches[1]; } elseif (\preg_match('/;.(\\d+).rows;.(\\d+).columns/i', $sttyString, $matches)) { // extract [w, h] from "; h rows; w columns" self::$width = (int) $matches[2]; self::$height = (int) $matches[1]; } } } /** * Runs and parses mode CON if it's available, suppressing any error output. * * @return int[]|null An array composed of the width and the height or null if it could not be parsed */ private static function getConsoleMode() : ?array { $info = self::readFromProcess('mode CON'); if (null === $info || !\preg_match('/--------+\\r?\\n.+?(\\d+)\\r?\\n.+?(\\d+)\\r?\\n/', $info, $matches)) { return null; } return [(int) $matches[2], (int) $matches[1]]; } /** * Runs and parses stty -a if it's available, suppressing any error output. */ private static function getSttyColumns() : ?string { return self::readFromProcess('stty -a | grep columns'); } private static function readFromProcess(string $command) : ?string { if (!\function_exists('proc_open')) { return null; } $descriptorspec = [1 => ['pipe', 'w'], 2 => ['pipe', 'w']]; $cp = \function_exists('sapi_windows_cp_set') ? \sapi_windows_cp_get() : 0; $process = \proc_open($command, $descriptorspec, $pipes, null, null, ['suppress_errors' => \true]); if (!\is_resource($process)) { return null; } $info = \stream_get_contents($pipes[1]); \fclose($pipes[1]); \fclose($pipes[2]); \proc_close($process); if ($cp) { \sapi_windows_cp_set($cp); } return $info; } } * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace _HumbugBox7ff99e199a36\Symfony\Component\Console; use _HumbugBox7ff99e199a36\Symfony\Component\Console\Command\Command; use _HumbugBox7ff99e199a36\Symfony\Component\Console\Command\CompleteCommand; use _HumbugBox7ff99e199a36\Symfony\Component\Console\Command\DumpCompletionCommand; use _HumbugBox7ff99e199a36\Symfony\Component\Console\Command\HelpCommand; use _HumbugBox7ff99e199a36\Symfony\Component\Console\Command\LazyCommand; use _HumbugBox7ff99e199a36\Symfony\Component\Console\Command\ListCommand; use _HumbugBox7ff99e199a36\Symfony\Component\Console\Command\SignalableCommandInterface; use _HumbugBox7ff99e199a36\Symfony\Component\Console\CommandLoader\CommandLoaderInterface; use _HumbugBox7ff99e199a36\Symfony\Component\Console\Completion\CompletionInput; use _HumbugBox7ff99e199a36\Symfony\Component\Console\Completion\CompletionSuggestions; use _HumbugBox7ff99e199a36\Symfony\Component\Console\Event\ConsoleCommandEvent; use _HumbugBox7ff99e199a36\Symfony\Component\Console\Event\ConsoleErrorEvent; use _HumbugBox7ff99e199a36\Symfony\Component\Console\Event\ConsoleSignalEvent; use _HumbugBox7ff99e199a36\Symfony\Component\Console\Event\ConsoleTerminateEvent; use _HumbugBox7ff99e199a36\Symfony\Component\Console\Exception\CommandNotFoundException; use _HumbugBox7ff99e199a36\Symfony\Component\Console\Exception\ExceptionInterface; use _HumbugBox7ff99e199a36\Symfony\Component\Console\Exception\LogicException; use _HumbugBox7ff99e199a36\Symfony\Component\Console\Exception\NamespaceNotFoundException; use _HumbugBox7ff99e199a36\Symfony\Component\Console\Exception\RuntimeException; use _HumbugBox7ff99e199a36\Symfony\Component\Console\Formatter\OutputFormatter; use _HumbugBox7ff99e199a36\Symfony\Component\Console\Helper\DebugFormatterHelper; use _HumbugBox7ff99e199a36\Symfony\Component\Console\Helper\FormatterHelper; use _HumbugBox7ff99e199a36\Symfony\Component\Console\Helper\Helper; use _HumbugBox7ff99e199a36\Symfony\Component\Console\Helper\HelperSet; use _HumbugBox7ff99e199a36\Symfony\Component\Console\Helper\ProcessHelper; use _HumbugBox7ff99e199a36\Symfony\Component\Console\Helper\QuestionHelper; use _HumbugBox7ff99e199a36\Symfony\Component\Console\Input\ArgvInput; use _HumbugBox7ff99e199a36\Symfony\Component\Console\Input\ArrayInput; use _HumbugBox7ff99e199a36\Symfony\Component\Console\Input\InputArgument; use _HumbugBox7ff99e199a36\Symfony\Component\Console\Input\InputAwareInterface; use _HumbugBox7ff99e199a36\Symfony\Component\Console\Input\InputDefinition; use _HumbugBox7ff99e199a36\Symfony\Component\Console\Input\InputInterface; use _HumbugBox7ff99e199a36\Symfony\Component\Console\Input\InputOption; use _HumbugBox7ff99e199a36\Symfony\Component\Console\Output\ConsoleOutput; use _HumbugBox7ff99e199a36\Symfony\Component\Console\Output\ConsoleOutputInterface; use _HumbugBox7ff99e199a36\Symfony\Component\Console\Output\OutputInterface; use _HumbugBox7ff99e199a36\Symfony\Component\Console\SignalRegistry\SignalRegistry; use _HumbugBox7ff99e199a36\Symfony\Component\Console\Style\SymfonyStyle; use _HumbugBox7ff99e199a36\Symfony\Component\ErrorHandler\ErrorHandler; use _HumbugBox7ff99e199a36\Symfony\Contracts\EventDispatcher\EventDispatcherInterface; use _HumbugBox7ff99e199a36\Symfony\Contracts\Service\ResetInterface; /** * An Application is the container for a collection of commands. * * It is the main entry point of a Console application. * * This class is optimized for a standard CLI environment. * * Usage: * * $app = new Application('myapp', '1.0 (stable)'); * $app->add(new SimpleCommand()); * $app->run(); * * @author Fabien Potencier */ class Application implements ResetInterface { private $commands = []; private $wantHelps = \false; private $runningCommand; private $name; private $version; private $commandLoader; private $catchExceptions = \true; private $autoExit = \true; private $definition; private $helperSet; private $dispatcher; private $terminal; private $defaultCommand; private $singleCommand = \false; private $initialized; private $signalRegistry; private $signalsToDispatchEvent = []; public function __construct(string $name = 'UNKNOWN', string $version = 'UNKNOWN') { $this->name = $name; $this->version = $version; $this->terminal = new Terminal(); $this->defaultCommand = 'list'; if (\defined('SIGINT') && SignalRegistry::isSupported()) { $this->signalRegistry = new SignalRegistry(); $this->signalsToDispatchEvent = [\SIGINT, \SIGTERM, \SIGUSR1, \SIGUSR2]; } } /** * @final */ public function setDispatcher(EventDispatcherInterface $dispatcher) { $this->dispatcher = $dispatcher; } public function setCommandLoader(CommandLoaderInterface $commandLoader) { $this->commandLoader = $commandLoader; } public function getSignalRegistry() : SignalRegistry { if (!$this->signalRegistry) { throw new RuntimeException('Signals are not supported. Make sure that the `pcntl` extension is installed and that "pcntl_*" functions are not disabled by your php.ini\'s "disable_functions" directive.'); } return $this->signalRegistry; } public function setSignalsToDispatchEvent(int ...$signalsToDispatchEvent) { $this->signalsToDispatchEvent = $signalsToDispatchEvent; } /** * Runs the current application. * * @return int 0 if everything went fine, or an error code * * @throws \Exception When running fails. Bypass this when {@link setCatchExceptions()}. */ public function run(?InputInterface $input = null, ?OutputInterface $output = null) { if (\function_exists('putenv')) { @\putenv('LINES=' . $this->terminal->getHeight()); @\putenv('COLUMNS=' . $this->terminal->getWidth()); } if (null === $input) { $input = new ArgvInput(); } if (null === $output) { $output = new ConsoleOutput(); } $renderException = function (\Throwable $e) use($output) { if ($output instanceof ConsoleOutputInterface) { $this->renderThrowable($e, $output->getErrorOutput()); } else { $this->renderThrowable($e, $output); } }; if ($phpHandler = \set_exception_handler($renderException)) { \restore_exception_handler(); if (!\is_array($phpHandler) || !$phpHandler[0] instanceof ErrorHandler) { $errorHandler = \true; } elseif ($errorHandler = $phpHandler[0]->setExceptionHandler($renderException)) { $phpHandler[0]->setExceptionHandler($errorHandler); } } $this->configureIO($input, $output); try { $exitCode = $this->doRun($input, $output); } catch (\Exception $e) { if (!$this->catchExceptions) { throw $e; } $renderException($e); $exitCode = $e->getCode(); if (\is_numeric($exitCode)) { $exitCode = (int) $exitCode; if ($exitCode <= 0) { $exitCode = 1; } } else { $exitCode = 1; } } finally { // if the exception handler changed, keep it // otherwise, unregister $renderException if (!$phpHandler) { if (\set_exception_handler($renderException) === $renderException) { \restore_exception_handler(); } \restore_exception_handler(); } elseif (!$errorHandler) { $finalHandler = $phpHandler[0]->setExceptionHandler(null); if ($finalHandler !== $renderException) { $phpHandler[0]->setExceptionHandler($finalHandler); } } } if ($this->autoExit) { if ($exitCode > 255) { $exitCode = 255; } exit($exitCode); } return $exitCode; } /** * Runs the current application. * * @return int 0 if everything went fine, or an error code */ public function doRun(InputInterface $input, OutputInterface $output) { if (\true === $input->hasParameterOption(['--version', '-V'], \true)) { $output->writeln($this->getLongVersion()); return 0; } try { // Makes ArgvInput::getFirstArgument() able to distinguish an option from an argument. $input->bind($this->getDefinition()); } catch (ExceptionInterface $e) { // Errors must be ignored, full binding/validation happens later when the command is known. } $name = $this->getCommandName($input); if (\true === $input->hasParameterOption(['--help', '-h'], \true)) { if (!$name) { $name = 'help'; $input = new ArrayInput(['command_name' => $this->defaultCommand]); } else { $this->wantHelps = \true; } } if (!$name) { $name = $this->defaultCommand; $definition = $this->getDefinition(); $definition->setArguments(\array_merge($definition->getArguments(), ['command' => new InputArgument('command', InputArgument::OPTIONAL, $definition->getArgument('command')->getDescription(), $name)])); } try { $this->runningCommand = null; // the command name MUST be the first element of the input $command = $this->find($name); } catch (\Throwable $e) { if (!($e instanceof CommandNotFoundException && !$e instanceof NamespaceNotFoundException) || 1 !== \count($alternatives = $e->getAlternatives()) || !$input->isInteractive()) { if (null !== $this->dispatcher) { $event = new ConsoleErrorEvent($input, $output, $e); $this->dispatcher->dispatch($event, ConsoleEvents::ERROR); if (0 === $event->getExitCode()) { return 0; } $e = $event->getError(); } throw $e; } $alternative = $alternatives[0]; $style = new SymfonyStyle($input, $output); $output->writeln(''); $formattedBlock = (new FormatterHelper())->formatBlock(\sprintf('Command "%s" is not defined.', $name), 'error', \true); $output->writeln($formattedBlock); if (!$style->confirm(\sprintf('Do you want to run "%s" instead? ', $alternative), \false)) { if (null !== $this->dispatcher) { $event = new ConsoleErrorEvent($input, $output, $e); $this->dispatcher->dispatch($event, ConsoleEvents::ERROR); return $event->getExitCode(); } return 1; } $command = $this->find($alternative); } if ($command instanceof LazyCommand) { $command = $command->getCommand(); } $this->runningCommand = $command; $exitCode = $this->doRunCommand($command, $input, $output); $this->runningCommand = null; return $exitCode; } /** * {@inheritdoc} */ public function reset() { } public function setHelperSet(HelperSet $helperSet) { $this->helperSet = $helperSet; } /** * Get the helper set associated with the command. * * @return HelperSet */ public function getHelperSet() { if (!$this->helperSet) { $this->helperSet = $this->getDefaultHelperSet(); } return $this->helperSet; } public function setDefinition(InputDefinition $definition) { $this->definition = $definition; } /** * Gets the InputDefinition related to this Application. * * @return InputDefinition */ public function getDefinition() { if (!$this->definition) { $this->definition = $this->getDefaultInputDefinition(); } if ($this->singleCommand) { $inputDefinition = $this->definition; $inputDefinition->setArguments(); return $inputDefinition; } return $this->definition; } /** * Adds suggestions to $suggestions for the current completion input (e.g. option or argument). */ public function complete(CompletionInput $input, CompletionSuggestions $suggestions) : void { if (CompletionInput::TYPE_ARGUMENT_VALUE === $input->getCompletionType() && 'command' === $input->getCompletionName()) { $commandNames = []; foreach ($this->all() as $name => $command) { // skip hidden commands and aliased commands as they already get added below if ($command->isHidden() || $command->getName() !== $name) { continue; } $commandNames[] = $command->getName(); foreach ($command->getAliases() as $name) { $commandNames[] = $name; } } $suggestions->suggestValues(\array_filter($commandNames)); return; } if (CompletionInput::TYPE_OPTION_NAME === $input->getCompletionType()) { $suggestions->suggestOptions($this->getDefinition()->getOptions()); return; } } /** * Gets the help message. * * @return string */ public function getHelp() { return $this->getLongVersion(); } /** * Gets whether to catch exceptions or not during commands execution. * * @return bool */ public function areExceptionsCaught() { return $this->catchExceptions; } /** * Sets whether to catch exceptions or not during commands execution. */ public function setCatchExceptions(bool $boolean) { $this->catchExceptions = $boolean; } /** * Gets whether to automatically exit after a command execution or not. * * @return bool */ public function isAutoExitEnabled() { return $this->autoExit; } /** * Sets whether to automatically exit after a command execution or not. */ public function setAutoExit(bool $boolean) { $this->autoExit = $boolean; } /** * Gets the name of the application. * * @return string */ public function getName() { return $this->name; } /** * Sets the application name. **/ public function setName(string $name) { $this->name = $name; } /** * Gets the application version. * * @return string */ public function getVersion() { return $this->version; } /** * Sets the application version. */ public function setVersion(string $version) { $this->version = $version; } /** * Returns the long version of the application. * * @return string */ public function getLongVersion() { if ('UNKNOWN' !== $this->getName()) { if ('UNKNOWN' !== $this->getVersion()) { return \sprintf('%s %s', $this->getName(), $this->getVersion()); } return $this->getName(); } return 'Console Tool'; } /** * Registers a new command. * * @return Command */ public function register(string $name) { return $this->add(new Command($name)); } /** * Adds an array of command objects. * * If a Command is not enabled it will not be added. * * @param Command[] $commands An array of commands */ public function addCommands(array $commands) { foreach ($commands as $command) { $this->add($command); } } /** * Adds a command object. * * If a command with the same name already exists, it will be overridden. * If the command is not enabled it will not be added. * * @return Command|null */ public function add(Command $command) { $this->init(); $command->setApplication($this); if (!$command->isEnabled()) { $command->setApplication(null); return null; } if (!$command instanceof LazyCommand) { // Will throw if the command is not correctly initialized. $command->getDefinition(); } if (!$command->getName()) { throw new LogicException(\sprintf('The command defined in "%s" cannot have an empty name.', \get_debug_type($command))); } $this->commands[$command->getName()] = $command; foreach ($command->getAliases() as $alias) { $this->commands[$alias] = $command; } return $command; } /** * Returns a registered command by name or alias. * * @return Command * * @throws CommandNotFoundException When given command name does not exist */ public function get(string $name) { $this->init(); if (!$this->has($name)) { throw new CommandNotFoundException(\sprintf('The command "%s" does not exist.', $name)); } // When the command has a different name than the one used at the command loader level if (!isset($this->commands[$name])) { throw new CommandNotFoundException(\sprintf('The "%s" command cannot be found because it is registered under multiple names. Make sure you don\'t set a different name via constructor or "setName()".', $name)); } $command = $this->commands[$name]; if ($this->wantHelps) { $this->wantHelps = \false; $helpCommand = $this->get('help'); $helpCommand->setCommand($command); return $helpCommand; } return $command; } /** * Returns true if the command exists, false otherwise. * * @return bool */ public function has(string $name) { $this->init(); return isset($this->commands[$name]) || $this->commandLoader && $this->commandLoader->has($name) && $this->add($this->commandLoader->get($name)); } /** * Returns an array of all unique namespaces used by currently registered commands. * * It does not return the global namespace which always exists. * * @return string[] */ public function getNamespaces() { $namespaces = []; foreach ($this->all() as $command) { if ($command->isHidden()) { continue; } $namespaces[] = $this->extractAllNamespaces($command->getName()); foreach ($command->getAliases() as $alias) { $namespaces[] = $this->extractAllNamespaces($alias); } } return \array_values(\array_unique(\array_filter(\array_merge([], ...$namespaces)))); } /** * Finds a registered namespace by a name or an abbreviation. * * @return string * * @throws NamespaceNotFoundException When namespace is incorrect or ambiguous */ public function findNamespace(string $namespace) { $allNamespaces = $this->getNamespaces(); $expr = \implode('[^:]*:', \array_map('preg_quote', \explode(':', $namespace))) . '[^:]*'; $namespaces = \preg_grep('{^' . $expr . '}', $allNamespaces); if (empty($namespaces)) { $message = \sprintf('There are no commands defined in the "%s" namespace.', $namespace); if ($alternatives = $this->findAlternatives($namespace, $allNamespaces)) { if (1 == \count($alternatives)) { $message .= "\n\nDid you mean this?\n "; } else { $message .= "\n\nDid you mean one of these?\n "; } $message .= \implode("\n ", $alternatives); } throw new NamespaceNotFoundException($message, $alternatives); } $exact = \in_array($namespace, $namespaces, \true); if (\count($namespaces) > 1 && !$exact) { throw new NamespaceNotFoundException(\sprintf("The namespace \"%s\" is ambiguous.\nDid you mean one of these?\n%s.", $namespace, $this->getAbbreviationSuggestions(\array_values($namespaces))), \array_values($namespaces)); } return $exact ? $namespace : \reset($namespaces); } /** * Finds a command by name or alias. * * Contrary to get, this command tries to find the best * match if you give it an abbreviation of a name or alias. * * @return Command * * @throws CommandNotFoundException When command name is incorrect or ambiguous */ public function find(string $name) { $this->init(); $aliases = []; foreach ($this->commands as $command) { foreach ($command->getAliases() as $alias) { if (!$this->has($alias)) { $this->commands[$alias] = $command; } } } if ($this->has($name)) { return $this->get($name); } $allCommands = $this->commandLoader ? \array_merge($this->commandLoader->getNames(), \array_keys($this->commands)) : \array_keys($this->commands); $expr = \implode('[^:]*:', \array_map('preg_quote', \explode(':', $name))) . '[^:]*'; $commands = \preg_grep('{^' . $expr . '}', $allCommands); if (empty($commands)) { $commands = \preg_grep('{^' . $expr . '}i', $allCommands); } // if no commands matched or we just matched namespaces if (empty($commands) || \count(\preg_grep('{^' . $expr . '$}i', $commands)) < 1) { if (\false !== ($pos = \strrpos($name, ':'))) { // check if a namespace exists and contains commands $this->findNamespace(\substr($name, 0, $pos)); } $message = \sprintf('Command "%s" is not defined.', $name); if ($alternatives = $this->findAlternatives($name, $allCommands)) { // remove hidden commands $alternatives = \array_filter($alternatives, function ($name) { return !$this->get($name)->isHidden(); }); if (1 == \count($alternatives)) { $message .= "\n\nDid you mean this?\n "; } else { $message .= "\n\nDid you mean one of these?\n "; } $message .= \implode("\n ", $alternatives); } throw new CommandNotFoundException($message, \array_values($alternatives)); } // filter out aliases for commands which are already on the list if (\count($commands) > 1) { $commandList = $this->commandLoader ? \array_merge(\array_flip($this->commandLoader->getNames()), $this->commands) : $this->commands; $commands = \array_unique(\array_filter($commands, function ($nameOrAlias) use(&$commandList, $commands, &$aliases) { if (!$commandList[$nameOrAlias] instanceof Command) { $commandList[$nameOrAlias] = $this->commandLoader->get($nameOrAlias); } $commandName = $commandList[$nameOrAlias]->getName(); $aliases[$nameOrAlias] = $commandName; return $commandName === $nameOrAlias || !\in_array($commandName, $commands); })); } if (\count($commands) > 1) { $usableWidth = $this->terminal->getWidth() - 10; $abbrevs = \array_values($commands); $maxLen = 0; foreach ($abbrevs as $abbrev) { $maxLen = \max(Helper::width($abbrev), $maxLen); } $abbrevs = \array_map(function ($cmd) use($commandList, $usableWidth, $maxLen, &$commands) { if ($commandList[$cmd]->isHidden()) { unset($commands[\array_search($cmd, $commands)]); return \false; } $abbrev = \str_pad($cmd, $maxLen, ' ') . ' ' . $commandList[$cmd]->getDescription(); return Helper::width($abbrev) > $usableWidth ? Helper::substr($abbrev, 0, $usableWidth - 3) . '...' : $abbrev; }, \array_values($commands)); if (\count($commands) > 1) { $suggestions = $this->getAbbreviationSuggestions(\array_filter($abbrevs)); throw new CommandNotFoundException(\sprintf("Command \"%s\" is ambiguous.\nDid you mean one of these?\n%s.", $name, $suggestions), \array_values($commands)); } } $command = $this->get(\reset($commands)); if ($command->isHidden()) { throw new CommandNotFoundException(\sprintf('The command "%s" does not exist.', $name)); } return $command; } /** * Gets the commands (registered in the given namespace if provided). * * The array keys are the full names and the values the command instances. * * @return Command[] */ public function all(?string $namespace = null) { $this->init(); if (null === $namespace) { if (!$this->commandLoader) { return $this->commands; } $commands = $this->commands; foreach ($this->commandLoader->getNames() as $name) { if (!isset($commands[$name]) && $this->has($name)) { $commands[$name] = $this->get($name); } } return $commands; } $commands = []; foreach ($this->commands as $name => $command) { if ($namespace === $this->extractNamespace($name, \substr_count($namespace, ':') + 1)) { $commands[$name] = $command; } } if ($this->commandLoader) { foreach ($this->commandLoader->getNames() as $name) { if (!isset($commands[$name]) && $namespace === $this->extractNamespace($name, \substr_count($namespace, ':') + 1) && $this->has($name)) { $commands[$name] = $this->get($name); } } } return $commands; } /** * Returns an array of possible abbreviations given a set of names. * * @return string[][] */ public static function getAbbreviations(array $names) { $abbrevs = []; foreach ($names as $name) { for ($len = \strlen($name); $len > 0; --$len) { $abbrev = \substr($name, 0, $len); $abbrevs[$abbrev][] = $name; } } return $abbrevs; } public function renderThrowable(\Throwable $e, OutputInterface $output) : void { $output->writeln('', OutputInterface::VERBOSITY_QUIET); $this->doRenderThrowable($e, $output); if (null !== $this->runningCommand) { $output->writeln(\sprintf('%s', OutputFormatter::escape(\sprintf($this->runningCommand->getSynopsis(), $this->getName()))), OutputInterface::VERBOSITY_QUIET); $output->writeln('', OutputInterface::VERBOSITY_QUIET); } } protected function doRenderThrowable(\Throwable $e, OutputInterface $output) : void { do { $message = \trim($e->getMessage()); if ('' === $message || OutputInterface::VERBOSITY_VERBOSE <= $output->getVerbosity()) { $class = \get_debug_type($e); $title = \sprintf(' [%s%s] ', $class, 0 !== ($code = $e->getCode()) ? ' (' . $code . ')' : ''); $len = Helper::width($title); } else { $len = 0; } if (\str_contains($message, "@anonymous\x00")) { $message = \preg_replace_callback('/[a-zA-Z_\\x7f-\\xff][\\\\a-zA-Z0-9_\\x7f-\\xff]*+@anonymous\\x00.*?\\.php(?:0x?|:[0-9]++\\$)[0-9a-fA-F]++/', function ($m) { return \class_exists($m[0], \false) ? ((\get_parent_class($m[0]) ?: \key(\class_implements($m[0]))) ?: 'class') . '@anonymous' : $m[0]; }, $message); } $width = $this->terminal->getWidth() ? $this->terminal->getWidth() - 1 : \PHP_INT_MAX; $lines = []; foreach ('' !== $message ? \preg_split('/\\r?\\n/', $message) : [] as $line) { foreach ($this->splitStringByWidth($line, $width - 4) as $line) { // pre-format lines to get the right string length $lineLength = Helper::width($line) + 4; $lines[] = [$line, $lineLength]; $len = \max($lineLength, $len); } } $messages = []; if (!$e instanceof ExceptionInterface || OutputInterface::VERBOSITY_VERBOSE <= $output->getVerbosity()) { $messages[] = \sprintf('%s', OutputFormatter::escape(\sprintf('In %s line %s:', \basename($e->getFile()) ?: 'n/a', $e->getLine() ?: 'n/a'))); } $messages[] = $emptyLine = \sprintf('%s', \str_repeat(' ', $len)); if ('' === $message || OutputInterface::VERBOSITY_VERBOSE <= $output->getVerbosity()) { $messages[] = \sprintf('%s%s', $title, \str_repeat(' ', \max(0, $len - Helper::width($title)))); } foreach ($lines as $line) { $messages[] = \sprintf(' %s %s', OutputFormatter::escape($line[0]), \str_repeat(' ', $len - $line[1])); } $messages[] = $emptyLine; $messages[] = ''; $output->writeln($messages, OutputInterface::VERBOSITY_QUIET); if (OutputInterface::VERBOSITY_VERBOSE <= $output->getVerbosity()) { $output->writeln('Exception trace:', OutputInterface::VERBOSITY_QUIET); // exception related properties $trace = $e->getTrace(); \array_unshift($trace, ['function' => '', 'file' => $e->getFile() ?: 'n/a', 'line' => $e->getLine() ?: 'n/a', 'args' => []]); for ($i = 0, $count = \count($trace); $i < $count; ++$i) { $class = $trace[$i]['class'] ?? ''; $type = $trace[$i]['type'] ?? ''; $function = $trace[$i]['function'] ?? ''; $file = $trace[$i]['file'] ?? 'n/a'; $line = $trace[$i]['line'] ?? 'n/a'; $output->writeln(\sprintf(' %s%s at %s:%s', $class, $function ? $type . $function . '()' : '', $file, $line), OutputInterface::VERBOSITY_QUIET); } $output->writeln('', OutputInterface::VERBOSITY_QUIET); } } while ($e = $e->getPrevious()); } /** * Configures the input and output instances based on the user arguments and options. */ protected function configureIO(InputInterface $input, OutputInterface $output) { if (\true === $input->hasParameterOption(['--ansi'], \true)) { $output->setDecorated(\true); } elseif (\true === $input->hasParameterOption(['--no-ansi'], \true)) { $output->setDecorated(\false); } if (\true === $input->hasParameterOption(['--no-interaction', '-n'], \true)) { $input->setInteractive(\false); } switch ($shellVerbosity = (int) \getenv('SHELL_VERBOSITY')) { case -1: $output->setVerbosity(OutputInterface::VERBOSITY_QUIET); break; case 1: $output->setVerbosity(OutputInterface::VERBOSITY_VERBOSE); break; case 2: $output->setVerbosity(OutputInterface::VERBOSITY_VERY_VERBOSE); break; case 3: $output->setVerbosity(OutputInterface::VERBOSITY_DEBUG); break; default: $shellVerbosity = 0; break; } if (\true === $input->hasParameterOption(['--quiet', '-q'], \true)) { $output->setVerbosity(OutputInterface::VERBOSITY_QUIET); $shellVerbosity = -1; } else { if ($input->hasParameterOption('-vvv', \true) || $input->hasParameterOption('--verbose=3', \true) || 3 === $input->getParameterOption('--verbose', \false, \true)) { $output->setVerbosity(OutputInterface::VERBOSITY_DEBUG); $shellVerbosity = 3; } elseif ($input->hasParameterOption('-vv', \true) || $input->hasParameterOption('--verbose=2', \true) || 2 === $input->getParameterOption('--verbose', \false, \true)) { $output->setVerbosity(OutputInterface::VERBOSITY_VERY_VERBOSE); $shellVerbosity = 2; } elseif ($input->hasParameterOption('-v', \true) || $input->hasParameterOption('--verbose=1', \true) || $input->hasParameterOption('--verbose', \true) || $input->getParameterOption('--verbose', \false, \true)) { $output->setVerbosity(OutputInterface::VERBOSITY_VERBOSE); $shellVerbosity = 1; } } if (-1 === $shellVerbosity) { $input->setInteractive(\false); } if (\function_exists('putenv')) { @\putenv('SHELL_VERBOSITY=' . $shellVerbosity); } $_ENV['SHELL_VERBOSITY'] = $shellVerbosity; $_SERVER['SHELL_VERBOSITY'] = $shellVerbosity; } /** * Runs the current command. * * If an event dispatcher has been attached to the application, * events are also dispatched during the life-cycle of the command. * * @return int 0 if everything went fine, or an error code */ protected function doRunCommand(Command $command, InputInterface $input, OutputInterface $output) { foreach ($command->getHelperSet() as $helper) { if ($helper instanceof InputAwareInterface) { $helper->setInput($input); } } if ($this->signalsToDispatchEvent) { $commandSignals = $command instanceof SignalableCommandInterface ? $command->getSubscribedSignals() : []; if ($commandSignals || null !== $this->dispatcher) { if (!$this->signalRegistry) { throw new RuntimeException('Unable to subscribe to signal events. Make sure that the `pcntl` extension is installed and that "pcntl_*" functions are not disabled by your php.ini\'s "disable_functions" directive.'); } if (Terminal::hasSttyAvailable()) { $sttyMode = \shell_exec('stty -g'); foreach ([\SIGINT, \SIGTERM] as $signal) { $this->signalRegistry->register($signal, static function () use($sttyMode) { \shell_exec('stty ' . $sttyMode); }); } } } if (null !== $this->dispatcher) { foreach ($this->signalsToDispatchEvent as $signal) { $event = new ConsoleSignalEvent($command, $input, $output, $signal); $this->signalRegistry->register($signal, function ($signal, $hasNext) use($event) { $this->dispatcher->dispatch($event, ConsoleEvents::SIGNAL); // No more handlers, we try to simulate PHP default behavior if (!$hasNext) { if (!\in_array($signal, [\SIGUSR1, \SIGUSR2], \true)) { exit(0); } } }); } } foreach ($commandSignals as $signal) { $this->signalRegistry->register($signal, [$command, 'handleSignal']); } } if (null === $this->dispatcher) { return $command->run($input, $output); } // bind before the console.command event, so the listeners have access to input options/arguments try { $command->mergeApplicationDefinition(); $input->bind($command->getDefinition()); } catch (ExceptionInterface $e) { // ignore invalid options/arguments for now, to allow the event listeners to customize the InputDefinition } $event = new ConsoleCommandEvent($command, $input, $output); $e = null; try { $this->dispatcher->dispatch($event, ConsoleEvents::COMMAND); if ($event->commandShouldRun()) { $exitCode = $command->run($input, $output); } else { $exitCode = ConsoleCommandEvent::RETURN_CODE_DISABLED; } } catch (\Throwable $e) { $event = new ConsoleErrorEvent($input, $output, $e, $command); $this->dispatcher->dispatch($event, ConsoleEvents::ERROR); $e = $event->getError(); if (0 === ($exitCode = $event->getExitCode())) { $e = null; } } $event = new ConsoleTerminateEvent($command, $input, $output, $exitCode); $this->dispatcher->dispatch($event, ConsoleEvents::TERMINATE); if (null !== $e) { throw $e; } return $event->getExitCode(); } /** * Gets the name of the command based on input. * * @return string|null */ protected function getCommandName(InputInterface $input) { return $this->singleCommand ? $this->defaultCommand : $input->getFirstArgument(); } /** * Gets the default input definition. * * @return InputDefinition */ protected function getDefaultInputDefinition() { return new InputDefinition([new InputArgument('command', InputArgument::REQUIRED, 'The command to execute'), new InputOption('--help', '-h', InputOption::VALUE_NONE, 'Display help for the given command. When no command is given display help for the ' . $this->defaultCommand . ' command'), new InputOption('--quiet', '-q', InputOption::VALUE_NONE, 'Do not output any message'), new InputOption('--verbose', '-v|vv|vvv', InputOption::VALUE_NONE, 'Increase the verbosity of messages: 1 for normal output, 2 for more verbose output and 3 for debug'), new InputOption('--version', '-V', InputOption::VALUE_NONE, 'Display this application version'), new InputOption('--ansi', '', InputOption::VALUE_NEGATABLE, 'Force (or disable --no-ansi) ANSI output', null), new InputOption('--no-interaction', '-n', InputOption::VALUE_NONE, 'Do not ask any interactive question')]); } /** * Gets the default commands that should always be available. * * @return Command[] */ protected function getDefaultCommands() { return [new HelpCommand(), new ListCommand(), new CompleteCommand(), new DumpCompletionCommand()]; } /** * Gets the default helper set with the helpers that should always be available. * * @return HelperSet */ protected function getDefaultHelperSet() { return new HelperSet([new FormatterHelper(), new DebugFormatterHelper(), new ProcessHelper(), new QuestionHelper()]); } /** * Returns abbreviated suggestions in string format. */ private function getAbbreviationSuggestions(array $abbrevs) : string { return ' ' . \implode("\n ", $abbrevs); } /** * Returns the namespace part of the command name. * * This method is not part of public API and should not be used directly. * * @return string */ public function extractNamespace(string $name, ?int $limit = null) { $parts = \explode(':', $name, -1); return \implode(':', null === $limit ? $parts : \array_slice($parts, 0, $limit)); } /** * Finds alternative of $name among $collection, * if nothing is found in $collection, try in $abbrevs. * * @return string[] */ private function findAlternatives(string $name, iterable $collection) : array { $threshold = 1000.0; $alternatives = []; $collectionParts = []; foreach ($collection as $item) { $collectionParts[$item] = \explode(':', $item); } foreach (\explode(':', $name) as $i => $subname) { foreach ($collectionParts as $collectionName => $parts) { $exists = isset($alternatives[$collectionName]); if (!isset($parts[$i]) && $exists) { $alternatives[$collectionName] += $threshold; continue; } elseif (!isset($parts[$i])) { continue; } $lev = \levenshtein($subname, $parts[$i]); if ($lev <= \strlen($subname) / 3 || '' !== $subname && \str_contains($parts[$i], $subname)) { $alternatives[$collectionName] = $exists ? $alternatives[$collectionName] + $lev : $lev; } elseif ($exists) { $alternatives[$collectionName] += $threshold; } } } foreach ($collection as $item) { $lev = \levenshtein($name, $item); if ($lev <= \strlen($name) / 3 || \str_contains($item, $name)) { $alternatives[$item] = isset($alternatives[$item]) ? $alternatives[$item] - $lev : $lev; } } $alternatives = \array_filter($alternatives, function ($lev) use($threshold) { return $lev < 2 * $threshold; }); \ksort($alternatives, \SORT_NATURAL | \SORT_FLAG_CASE); return \array_keys($alternatives); } /** * Sets the default Command name. * * @return $this */ public function setDefaultCommand(string $commandName, bool $isSingleCommand = \false) { $this->defaultCommand = \explode('|', \ltrim($commandName, '|'))[0]; if ($isSingleCommand) { // Ensure the command exist $this->find($commandName); $this->singleCommand = \true; } return $this; } /** * @internal */ public function isSingleCommand() : bool { return $this->singleCommand; } private function splitStringByWidth(string $string, int $width) : array { // str_split is not suitable for multi-byte characters, we should use preg_split to get char array properly. // additionally, array_slice() is not enough as some character has doubled width. // we need a function to split string not by character count but by string width if (\false === ($encoding = \mb_detect_encoding($string, null, \true))) { return \str_split($string, $width); } $utf8String = \mb_convert_encoding($string, 'utf8', $encoding); $lines = []; $line = ''; $offset = 0; while (\preg_match('/.{1,10000}/u', $utf8String, $m, 0, $offset)) { $offset += \strlen($m[0]); foreach (\preg_split('//u', $m[0]) as $char) { // test if $char could be appended to current line if (\mb_strwidth($line . $char, 'utf8') <= $width) { $line .= $char; continue; } // if not, push current line to array and make new line $lines[] = \str_pad($line, $width); $line = $char; } } $lines[] = \count($lines) ? \str_pad($line, $width) : $line; \mb_convert_variables($encoding, 'utf8', $lines); return $lines; } /** * Returns all namespaces of the command name. * * @return string[] */ private function extractAllNamespaces(string $name) : array { // -1 as third argument is needed to skip the command short name when exploding $parts = \explode(':', $name, -1); $namespaces = []; foreach ($parts as $part) { if (\count($namespaces)) { $namespaces[] = \end($namespaces) . ':' . $part; } else { $namespaces[] = $part; } } return $namespaces; } private function init() { if ($this->initialized) { return; } $this->initialized = \true; foreach ($this->getDefaultCommands() as $command) { $this->add($command); } } } * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace _HumbugBox7ff99e199a36\Symfony\Component\Console\Command; /** * Interface for command reacting to signal. * * @author Grégoire Pineau */ interface SignalableCommandInterface { /** * Returns the list of signals to subscribe. */ public function getSubscribedSignals() : array; /** * The method will be called when the application is signaled. */ public function handleSignal(int $signal) : void; } * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace _HumbugBox7ff99e199a36\Symfony\Component\Console\Command; use _HumbugBox7ff99e199a36\Symfony\Component\Console\Completion\CompletionInput; use _HumbugBox7ff99e199a36\Symfony\Component\Console\Completion\CompletionSuggestions; use _HumbugBox7ff99e199a36\Symfony\Component\Console\Descriptor\ApplicationDescription; use _HumbugBox7ff99e199a36\Symfony\Component\Console\Helper\DescriptorHelper; use _HumbugBox7ff99e199a36\Symfony\Component\Console\Input\InputArgument; use _HumbugBox7ff99e199a36\Symfony\Component\Console\Input\InputInterface; use _HumbugBox7ff99e199a36\Symfony\Component\Console\Input\InputOption; use _HumbugBox7ff99e199a36\Symfony\Component\Console\Output\OutputInterface; /** * ListCommand displays the list of all available commands for the application. * * @author Fabien Potencier */ class ListCommand extends Command { /** * {@inheritdoc} */ protected function configure() { $this->setName('list')->setDefinition([new InputArgument('namespace', InputArgument::OPTIONAL, 'The namespace name'), new InputOption('raw', null, InputOption::VALUE_NONE, 'To output raw command list'), new InputOption('format', null, InputOption::VALUE_REQUIRED, 'The output format (txt, xml, json, or md)', 'txt'), new InputOption('short', null, InputOption::VALUE_NONE, 'To skip describing commands\' arguments')])->setDescription('List commands')->setHelp(<<<'EOF' The %command.name% command lists all commands: %command.full_name% You can also display the commands for a specific namespace: %command.full_name% test You can also output the information in other formats by using the --format option: %command.full_name% --format=xml It's also possible to get raw list of commands (useful for embedding command runner): %command.full_name% --raw EOF ); } /** * {@inheritdoc} */ protected function execute(InputInterface $input, OutputInterface $output) { $helper = new DescriptorHelper(); $helper->describe($output, $this->getApplication(), ['format' => $input->getOption('format'), 'raw_text' => $input->getOption('raw'), 'namespace' => $input->getArgument('namespace'), 'short' => $input->getOption('short')]); return 0; } public function complete(CompletionInput $input, CompletionSuggestions $suggestions) : void { if ($input->mustSuggestArgumentValuesFor('namespace')) { $descriptor = new ApplicationDescription($this->getApplication()); $suggestions->suggestValues(\array_keys($descriptor->getNamespaces())); return; } if ($input->mustSuggestOptionValuesFor('format')) { $helper = new DescriptorHelper(); $suggestions->suggestValues($helper->getFormats()); } } } * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace _HumbugBox7ff99e199a36\Symfony\Component\Console\Command; use _HumbugBox7ff99e199a36\Symfony\Component\Console\Application; use _HumbugBox7ff99e199a36\Symfony\Component\Console\Completion\CompletionInput; use _HumbugBox7ff99e199a36\Symfony\Component\Console\Completion\CompletionSuggestions; use _HumbugBox7ff99e199a36\Symfony\Component\Console\Helper\HelperSet; use _HumbugBox7ff99e199a36\Symfony\Component\Console\Input\InputDefinition; use _HumbugBox7ff99e199a36\Symfony\Component\Console\Input\InputInterface; use _HumbugBox7ff99e199a36\Symfony\Component\Console\Output\OutputInterface; /** * @author Nicolas Grekas */ final class LazyCommand extends Command { private $command; private $isEnabled; public function __construct(string $name, array $aliases, string $description, bool $isHidden, \Closure $commandFactory, ?bool $isEnabled = \true) { $this->setName($name)->setAliases($aliases)->setHidden($isHidden)->setDescription($description); $this->command = $commandFactory; $this->isEnabled = $isEnabled; } public function ignoreValidationErrors() : void { $this->getCommand()->ignoreValidationErrors(); } public function setApplication(?Application $application = null) : void { if ($this->command instanceof parent) { $this->command->setApplication($application); } parent::setApplication($application); } public function setHelperSet(HelperSet $helperSet) : void { if ($this->command instanceof parent) { $this->command->setHelperSet($helperSet); } parent::setHelperSet($helperSet); } public function isEnabled() : bool { return $this->isEnabled ?? $this->getCommand()->isEnabled(); } public function run(InputInterface $input, OutputInterface $output) : int { return $this->getCommand()->run($input, $output); } public function complete(CompletionInput $input, CompletionSuggestions $suggestions) : void { $this->getCommand()->complete($input, $suggestions); } /** * @return $this */ public function setCode(callable $code) : self { $this->getCommand()->setCode($code); return $this; } /** * @internal */ public function mergeApplicationDefinition(bool $mergeArgs = \true) : void { $this->getCommand()->mergeApplicationDefinition($mergeArgs); } /** * @return $this */ public function setDefinition($definition) : self { $this->getCommand()->setDefinition($definition); return $this; } public function getDefinition() : InputDefinition { return $this->getCommand()->getDefinition(); } public function getNativeDefinition() : InputDefinition { return $this->getCommand()->getNativeDefinition(); } /** * @return $this */ public function addArgument(string $name, ?int $mode = null, string $description = '', $default = null) : self { $this->getCommand()->addArgument($name, $mode, $description, $default); return $this; } /** * @return $this */ public function addOption(string $name, $shortcut = null, ?int $mode = null, string $description = '', $default = null) : self { $this->getCommand()->addOption($name, $shortcut, $mode, $description, $default); return $this; } /** * @return $this */ public function setProcessTitle(string $title) : self { $this->getCommand()->setProcessTitle($title); return $this; } /** * @return $this */ public function setHelp(string $help) : self { $this->getCommand()->setHelp($help); return $this; } public function getHelp() : string { return $this->getCommand()->getHelp(); } public function getProcessedHelp() : string { return $this->getCommand()->getProcessedHelp(); } public function getSynopsis(bool $short = \false) : string { return $this->getCommand()->getSynopsis($short); } /** * @return $this */ public function addUsage(string $usage) : self { $this->getCommand()->addUsage($usage); return $this; } public function getUsages() : array { return $this->getCommand()->getUsages(); } /** * @return mixed */ public function getHelper(string $name) { return $this->getCommand()->getHelper($name); } public function getCommand() : parent { if (!$this->command instanceof \Closure) { return $this->command; } $command = $this->command = ($this->command)(); $command->setApplication($this->getApplication()); if (null !== $this->getHelperSet()) { $command->setHelperSet($this->getHelperSet()); } $command->setName($this->getName())->setAliases($this->getAliases())->setHidden($this->isHidden())->setDescription($this->getDescription()); // Will throw if the command is not correctly initialized. $command->getDefinition(); return $command; } } * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace _HumbugBox7ff99e199a36\Symfony\Component\Console\Command; use _HumbugBox7ff99e199a36\Symfony\Component\Console\Exception\LogicException; use _HumbugBox7ff99e199a36\Symfony\Component\Lock\LockFactory; use _HumbugBox7ff99e199a36\Symfony\Component\Lock\LockInterface; use _HumbugBox7ff99e199a36\Symfony\Component\Lock\Store\FlockStore; use _HumbugBox7ff99e199a36\Symfony\Component\Lock\Store\SemaphoreStore; /** * Basic lock feature for commands. * * @author Geoffrey Brier */ trait LockableTrait { /** @var LockInterface|null */ private $lock; /** * Locks a command. */ private function lock(?string $name = null, bool $blocking = \false) : bool { if (!\class_exists(SemaphoreStore::class)) { throw new LogicException('To enable the locking feature you must install the symfony/lock component.'); } if (null !== $this->lock) { throw new LogicException('A lock is already in place.'); } if (SemaphoreStore::isSupported()) { $store = new SemaphoreStore(); } else { $store = new FlockStore(); } $this->lock = (new LockFactory($store))->createLock($name ?: $this->getName()); if (!$this->lock->acquire($blocking)) { $this->lock = null; return \false; } return \true; } /** * Releases the command lock if there is one. */ private function release() { if ($this->lock) { $this->lock->release(); $this->lock = null; } } } * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace _HumbugBox7ff99e199a36\Symfony\Component\Console\Command; use _HumbugBox7ff99e199a36\Symfony\Component\Console\Application; use _HumbugBox7ff99e199a36\Symfony\Component\Console\Attribute\AsCommand; use _HumbugBox7ff99e199a36\Symfony\Component\Console\Completion\CompletionInput; use _HumbugBox7ff99e199a36\Symfony\Component\Console\Completion\CompletionSuggestions; use _HumbugBox7ff99e199a36\Symfony\Component\Console\Exception\ExceptionInterface; use _HumbugBox7ff99e199a36\Symfony\Component\Console\Exception\InvalidArgumentException; use _HumbugBox7ff99e199a36\Symfony\Component\Console\Exception\LogicException; use _HumbugBox7ff99e199a36\Symfony\Component\Console\Helper\HelperSet; use _HumbugBox7ff99e199a36\Symfony\Component\Console\Input\InputArgument; use _HumbugBox7ff99e199a36\Symfony\Component\Console\Input\InputDefinition; use _HumbugBox7ff99e199a36\Symfony\Component\Console\Input\InputInterface; use _HumbugBox7ff99e199a36\Symfony\Component\Console\Input\InputOption; use _HumbugBox7ff99e199a36\Symfony\Component\Console\Output\OutputInterface; /** * Base class for all commands. * * @author Fabien Potencier */ class Command { // see https://tldp.org/LDP/abs/html/exitcodes.html public const SUCCESS = 0; public const FAILURE = 1; public const INVALID = 2; /** * @var string|null The default command name */ protected static $defaultName; /** * @var string|null The default command description */ protected static $defaultDescription; private $application; private $name; private $processTitle; private $aliases = []; private $definition; private $hidden = \false; private $help = ''; private $description = ''; private $fullDefinition; private $ignoreValidationErrors = \false; private $code; private $synopsis = []; private $usages = []; private $helperSet; /** * @return string|null */ public static function getDefaultName() { $class = static::class; if (\PHP_VERSION_ID >= 80000 && ($attribute = (new \ReflectionClass($class))->getAttributes(AsCommand::class))) { return $attribute[0]->newInstance()->name; } $r = new \ReflectionProperty($class, 'defaultName'); return $class === $r->class ? static::$defaultName : null; } public static function getDefaultDescription() : ?string { $class = static::class; if (\PHP_VERSION_ID >= 80000 && ($attribute = (new \ReflectionClass($class))->getAttributes(AsCommand::class))) { return $attribute[0]->newInstance()->description; } $r = new \ReflectionProperty($class, 'defaultDescription'); return $class === $r->class ? static::$defaultDescription : null; } /** * @param string|null $name The name of the command; passing null means it must be set in configure() * * @throws LogicException When the command name is empty */ public function __construct(?string $name = null) { $this->definition = new InputDefinition(); if (null === $name && null !== ($name = static::getDefaultName())) { $aliases = \explode('|', $name); if ('' === ($name = \array_shift($aliases))) { $this->setHidden(\true); $name = \array_shift($aliases); } $this->setAliases($aliases); } if (null !== $name) { $this->setName($name); } if ('' === $this->description) { $this->setDescription(static::getDefaultDescription() ?? ''); } $this->configure(); } /** * Ignores validation errors. * * This is mainly useful for the help command. */ public function ignoreValidationErrors() { $this->ignoreValidationErrors = \true; } public function setApplication(?Application $application = null) { $this->application = $application; if ($application) { $this->setHelperSet($application->getHelperSet()); } else { $this->helperSet = null; } $this->fullDefinition = null; } public function setHelperSet(HelperSet $helperSet) { $this->helperSet = $helperSet; } /** * Gets the helper set. * * @return HelperSet|null */ public function getHelperSet() { return $this->helperSet; } /** * Gets the application instance for this command. * * @return Application|null */ public function getApplication() { return $this->application; } /** * Checks whether the command is enabled or not in the current environment. * * Override this to check for x or y and return false if the command cannot * run properly under the current conditions. * * @return bool */ public function isEnabled() { return \true; } /** * Configures the current command. */ protected function configure() { } /** * Executes the current command. * * This method is not abstract because you can use this class * as a concrete class. In this case, instead of defining the * execute() method, you set the code to execute by passing * a Closure to the setCode() method. * * @return int 0 if everything went fine, or an exit code * * @throws LogicException When this abstract method is not implemented * * @see setCode() */ protected function execute(InputInterface $input, OutputInterface $output) { throw new LogicException('You must override the execute() method in the concrete command class.'); } /** * Interacts with the user. * * This method is executed before the InputDefinition is validated. * This means that this is the only place where the command can * interactively ask for values of missing required arguments. */ protected function interact(InputInterface $input, OutputInterface $output) { } /** * Initializes the command after the input has been bound and before the input * is validated. * * This is mainly useful when a lot of commands extends one main command * where some things need to be initialized based on the input arguments and options. * * @see InputInterface::bind() * @see InputInterface::validate() */ protected function initialize(InputInterface $input, OutputInterface $output) { } /** * Runs the command. * * The code to execute is either defined directly with the * setCode() method or by overriding the execute() method * in a sub-class. * * @return int The command exit code * * @throws ExceptionInterface When input binding fails. Bypass this by calling {@link ignoreValidationErrors()}. * * @see setCode() * @see execute() */ public function run(InputInterface $input, OutputInterface $output) { // add the application arguments and options $this->mergeApplicationDefinition(); // bind the input against the command specific arguments/options try { $input->bind($this->getDefinition()); } catch (ExceptionInterface $e) { if (!$this->ignoreValidationErrors) { throw $e; } } $this->initialize($input, $output); if (null !== $this->processTitle) { if (\function_exists('cli_set_process_title')) { if (!@\cli_set_process_title($this->processTitle)) { if ('Darwin' === \PHP_OS) { $output->writeln('Running "cli_set_process_title" as an unprivileged user is not supported on MacOS.', OutputInterface::VERBOSITY_VERY_VERBOSE); } else { \cli_set_process_title($this->processTitle); } } } elseif (\function_exists('_HumbugBox7ff99e199a36\\setproctitle')) { setproctitle($this->processTitle); } elseif (OutputInterface::VERBOSITY_VERY_VERBOSE === $output->getVerbosity()) { $output->writeln('Install the proctitle PECL to be able to change the process title.'); } } if ($input->isInteractive()) { $this->interact($input, $output); } // The command name argument is often omitted when a command is executed directly with its run() method. // It would fail the validation if we didn't make sure the command argument is present, // since it's required by the application. if ($input->hasArgument('command') && null === $input->getArgument('command')) { $input->setArgument('command', $this->getName()); } $input->validate(); if ($this->code) { $statusCode = ($this->code)($input, $output); } else { $statusCode = $this->execute($input, $output); if (!\is_int($statusCode)) { throw new \TypeError(\sprintf('Return value of "%s::execute()" must be of the type int, "%s" returned.', static::class, \get_debug_type($statusCode))); } } return \is_numeric($statusCode) ? (int) $statusCode : 0; } /** * Adds suggestions to $suggestions for the current completion input (e.g. option or argument). */ public function complete(CompletionInput $input, CompletionSuggestions $suggestions) : void { } /** * Sets the code to execute when running this command. * * If this method is used, it overrides the code defined * in the execute() method. * * @param callable $code A callable(InputInterface $input, OutputInterface $output) * * @return $this * * @throws InvalidArgumentException * * @see execute() */ public function setCode(callable $code) { if ($code instanceof \Closure) { $r = new \ReflectionFunction($code); if (null === $r->getClosureThis()) { \set_error_handler(static function () { }); try { if ($c = \Closure::bind($code, $this)) { $code = $c; } } finally { \restore_error_handler(); } } } $this->code = $code; return $this; } /** * Merges the application definition with the command definition. * * This method is not part of public API and should not be used directly. * * @param bool $mergeArgs Whether to merge or not the Application definition arguments to Command definition arguments * * @internal */ public function mergeApplicationDefinition(bool $mergeArgs = \true) { if (null === $this->application) { return; } $this->fullDefinition = new InputDefinition(); $this->fullDefinition->setOptions($this->definition->getOptions()); $this->fullDefinition->addOptions($this->application->getDefinition()->getOptions()); if ($mergeArgs) { $this->fullDefinition->setArguments($this->application->getDefinition()->getArguments()); $this->fullDefinition->addArguments($this->definition->getArguments()); } else { $this->fullDefinition->setArguments($this->definition->getArguments()); } } /** * Sets an array of argument and option instances. * * @param array|InputDefinition $definition An array of argument and option instances or a definition instance * * @return $this */ public function setDefinition($definition) { if ($definition instanceof InputDefinition) { $this->definition = $definition; } else { $this->definition->setDefinition($definition); } $this->fullDefinition = null; return $this; } /** * Gets the InputDefinition attached to this Command. * * @return InputDefinition */ public function getDefinition() { return $this->fullDefinition ?? $this->getNativeDefinition(); } /** * Gets the InputDefinition to be used to create representations of this Command. * * Can be overridden to provide the original command representation when it would otherwise * be changed by merging with the application InputDefinition. * * This method is not part of public API and should not be used directly. * * @return InputDefinition */ public function getNativeDefinition() { if (null === $this->definition) { throw new LogicException(\sprintf('Command class "%s" is not correctly initialized. You probably forgot to call the parent constructor.', static::class)); } return $this->definition; } /** * Adds an argument. * * @param int|null $mode The argument mode: InputArgument::REQUIRED or InputArgument::OPTIONAL * @param mixed $default The default value (for InputArgument::OPTIONAL mode only) * * @return $this * * @throws InvalidArgumentException When argument mode is not valid */ public function addArgument(string $name, ?int $mode = null, string $description = '', $default = null) { $this->definition->addArgument(new InputArgument($name, $mode, $description, $default)); if (null !== $this->fullDefinition) { $this->fullDefinition->addArgument(new InputArgument($name, $mode, $description, $default)); } return $this; } /** * Adds an option. * * @param string|array|null $shortcut The shortcuts, can be null, a string of shortcuts delimited by | or an array of shortcuts * @param int|null $mode The option mode: One of the InputOption::VALUE_* constants * @param mixed $default The default value (must be null for InputOption::VALUE_NONE) * * @return $this * * @throws InvalidArgumentException If option mode is invalid or incompatible */ public function addOption(string $name, $shortcut = null, ?int $mode = null, string $description = '', $default = null) { $this->definition->addOption(new InputOption($name, $shortcut, $mode, $description, $default)); if (null !== $this->fullDefinition) { $this->fullDefinition->addOption(new InputOption($name, $shortcut, $mode, $description, $default)); } return $this; } /** * Sets the name of the command. * * This method can set both the namespace and the name if * you separate them by a colon (:) * * $command->setName('foo:bar'); * * @return $this * * @throws InvalidArgumentException When the name is invalid */ public function setName(string $name) { $this->validateName($name); $this->name = $name; return $this; } /** * Sets the process title of the command. * * This feature should be used only when creating a long process command, * like a daemon. * * @return $this */ public function setProcessTitle(string $title) { $this->processTitle = $title; return $this; } /** * Returns the command name. * * @return string|null */ public function getName() { return $this->name; } /** * @param bool $hidden Whether or not the command should be hidden from the list of commands * The default value will be true in Symfony 6.0 * * @return $this * * @final since Symfony 5.1 */ public function setHidden(bool $hidden) { $this->hidden = $hidden; return $this; } /** * @return bool whether the command should be publicly shown or not */ public function isHidden() { return $this->hidden; } /** * Sets the description for the command. * * @return $this */ public function setDescription(string $description) { $this->description = $description; return $this; } /** * Returns the description for the command. * * @return string */ public function getDescription() { return $this->description; } /** * Sets the help for the command. * * @return $this */ public function setHelp(string $help) { $this->help = $help; return $this; } /** * Returns the help for the command. * * @return string */ public function getHelp() { return $this->help; } /** * Returns the processed help for the command replacing the %command.name% and * %command.full_name% patterns with the real values dynamically. * * @return string */ public function getProcessedHelp() { $name = $this->name; $isSingleCommand = $this->application && $this->application->isSingleCommand(); $placeholders = ['%command.name%', '%command.full_name%']; $replacements = [$name, $isSingleCommand ? $_SERVER['PHP_SELF'] : $_SERVER['PHP_SELF'] . ' ' . $name]; return \str_replace($placeholders, $replacements, $this->getHelp() ?: $this->getDescription()); } /** * Sets the aliases for the command. * * @param string[] $aliases An array of aliases for the command * * @return $this * * @throws InvalidArgumentException When an alias is invalid */ public function setAliases(iterable $aliases) { $list = []; foreach ($aliases as $alias) { $this->validateName($alias); $list[] = $alias; } $this->aliases = \is_array($aliases) ? $aliases : $list; return $this; } /** * Returns the aliases for the command. * * @return array */ public function getAliases() { return $this->aliases; } /** * Returns the synopsis for the command. * * @param bool $short Whether to show the short version of the synopsis (with options folded) or not * * @return string */ public function getSynopsis(bool $short = \false) { $key = $short ? 'short' : 'long'; if (!isset($this->synopsis[$key])) { $this->synopsis[$key] = \trim(\sprintf('%s %s', $this->name, $this->definition->getSynopsis($short))); } return $this->synopsis[$key]; } /** * Add a command usage example, it'll be prefixed with the command name. * * @return $this */ public function addUsage(string $usage) { if (!\str_starts_with($usage, $this->name)) { $usage = \sprintf('%s %s', $this->name, $usage); } $this->usages[] = $usage; return $this; } /** * Returns alternative usages of the command. * * @return array */ public function getUsages() { return $this->usages; } /** * Gets a helper instance by name. * * @return mixed * * @throws LogicException if no HelperSet is defined * @throws InvalidArgumentException if the helper is not defined */ public function getHelper(string $name) { if (null === $this->helperSet) { throw new LogicException(\sprintf('Cannot retrieve helper "%s" because there is no HelperSet defined. Did you forget to add your command to the application or to set the application on the command using the setApplication() method? You can also set the HelperSet directly using the setHelperSet() method.', $name)); } return $this->helperSet->get($name); } /** * Validates a command name. * * It must be non-empty and parts can optionally be separated by ":". * * @throws InvalidArgumentException When the name is invalid */ private function validateName(string $name) { if (!\preg_match('/^[^\\:]++(\\:[^\\:]++)*$/', $name)) { throw new InvalidArgumentException(\sprintf('Command name "%s" is invalid.', $name)); } } } * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace _HumbugBox7ff99e199a36\Symfony\Component\Console\Command; use _HumbugBox7ff99e199a36\Symfony\Component\Console\Completion\CompletionInput; use _HumbugBox7ff99e199a36\Symfony\Component\Console\Completion\CompletionSuggestions; use _HumbugBox7ff99e199a36\Symfony\Component\Console\Completion\Output\BashCompletionOutput; use _HumbugBox7ff99e199a36\Symfony\Component\Console\Completion\Output\CompletionOutputInterface; use _HumbugBox7ff99e199a36\Symfony\Component\Console\Exception\CommandNotFoundException; use _HumbugBox7ff99e199a36\Symfony\Component\Console\Exception\ExceptionInterface; use _HumbugBox7ff99e199a36\Symfony\Component\Console\Input\InputInterface; use _HumbugBox7ff99e199a36\Symfony\Component\Console\Input\InputOption; use _HumbugBox7ff99e199a36\Symfony\Component\Console\Output\OutputInterface; /** * Responsible for providing the values to the shell completion. * * @author Wouter de Jong */ final class CompleteCommand extends Command { protected static $defaultName = '|_complete'; protected static $defaultDescription = 'Internal command to provide shell completion suggestions'; private $completionOutputs; private $isDebug = \false; /** * @param array> $completionOutputs A list of additional completion outputs, with shell name as key and FQCN as value */ public function __construct(array $completionOutputs = []) { // must be set before the parent constructor, as the property value is used in configure() $this->completionOutputs = $completionOutputs + ['bash' => BashCompletionOutput::class]; parent::__construct(); } protected function configure() : void { $this->addOption('shell', 's', InputOption::VALUE_REQUIRED, 'The shell type ("' . \implode('", "', \array_keys($this->completionOutputs)) . '")')->addOption('input', 'i', InputOption::VALUE_REQUIRED | InputOption::VALUE_IS_ARRAY, 'An array of input tokens (e.g. COMP_WORDS or argv)')->addOption('current', 'c', InputOption::VALUE_REQUIRED, 'The index of the "input" array that the cursor is in (e.g. COMP_CWORD)')->addOption('symfony', 'S', InputOption::VALUE_REQUIRED, 'The version of the completion script'); } protected function initialize(InputInterface $input, OutputInterface $output) { $this->isDebug = \filter_var(\getenv('SYMFONY_COMPLETION_DEBUG'), \FILTER_VALIDATE_BOOLEAN); } protected function execute(InputInterface $input, OutputInterface $output) : int { try { // uncomment when a bugfix or BC break has been introduced in the shell completion scripts // $version = $input->getOption('symfony'); // if ($version && version_compare($version, 'x.y', '>=')) { // $message = sprintf('Completion script version is not supported ("%s" given, ">=x.y" required).', $version); // $this->log($message); // $output->writeln($message.' Install the Symfony completion script again by using the "completion" command.'); // return 126; // } $shell = $input->getOption('shell'); if (!$shell) { throw new \RuntimeException('The "--shell" option must be set.'); } if (!($completionOutput = $this->completionOutputs[$shell] ?? \false)) { throw new \RuntimeException(\sprintf('Shell completion is not supported for your shell: "%s" (supported: "%s").', $shell, \implode('", "', \array_keys($this->completionOutputs)))); } $completionInput = $this->createCompletionInput($input); $suggestions = new CompletionSuggestions(); $this->log(['', '' . \date('Y-m-d H:i:s') . '', 'Input: ("|" indicates the cursor position)', ' ' . (string) $completionInput, 'Command:', ' ' . (string) \implode(' ', $_SERVER['argv']), 'Messages:']); $command = $this->findCommand($completionInput, $output); if (null === $command) { $this->log(' No command found, completing using the Application class.'); $this->getApplication()->complete($completionInput, $suggestions); } elseif ($completionInput->mustSuggestArgumentValuesFor('command') && $command->getName() !== $completionInput->getCompletionValue() && !\in_array($completionInput->getCompletionValue(), $command->getAliases(), \true)) { $this->log(' No command found, completing using the Application class.'); // expand shortcut names ("cache:cl") into their full name ("cache:clear") $suggestions->suggestValues(\array_filter(\array_merge([$command->getName()], $command->getAliases()))); } else { $command->mergeApplicationDefinition(); $completionInput->bind($command->getDefinition()); if (CompletionInput::TYPE_OPTION_NAME === $completionInput->getCompletionType()) { $this->log(' Completing option names for the ' . \get_class($command instanceof LazyCommand ? $command->getCommand() : $command) . ' command.'); $suggestions->suggestOptions($command->getDefinition()->getOptions()); } else { $this->log([' Completing using the ' . \get_class($command instanceof LazyCommand ? $command->getCommand() : $command) . ' class.', ' Completing ' . $completionInput->getCompletionType() . ' for ' . $completionInput->getCompletionName() . '']); if (null !== ($compval = $completionInput->getCompletionValue())) { $this->log(' Current value: ' . $compval . ''); } $command->complete($completionInput, $suggestions); } } /** @var CompletionOutputInterface $completionOutput */ $completionOutput = new $completionOutput(); $this->log('Suggestions:'); if ($options = $suggestions->getOptionSuggestions()) { $this->log(' --' . \implode(' --', \array_map(function ($o) { return $o->getName(); }, $options))); } elseif ($values = $suggestions->getValueSuggestions()) { $this->log(' ' . \implode(' ', $values)); } else { $this->log(' No suggestions were provided'); } $completionOutput->write($suggestions, $output); } catch (\Throwable $e) { $this->log(['Error!', (string) $e]); if ($output->isDebug()) { throw $e; } return 2; } return 0; } private function createCompletionInput(InputInterface $input) : CompletionInput { $currentIndex = $input->getOption('current'); if (!$currentIndex || !\ctype_digit($currentIndex)) { throw new \RuntimeException('The "--current" option must be set and it must be an integer.'); } $completionInput = CompletionInput::fromTokens($input->getOption('input'), (int) $currentIndex); try { $completionInput->bind($this->getApplication()->getDefinition()); } catch (ExceptionInterface $e) { } return $completionInput; } private function findCommand(CompletionInput $completionInput, OutputInterface $output) : ?Command { try { $inputName = $completionInput->getFirstArgument(); if (null === $inputName) { return null; } return $this->getApplication()->find($inputName); } catch (CommandNotFoundException $e) { } return null; } private function log($messages) : void { if (!$this->isDebug) { return; } $commandName = \basename($_SERVER['argv'][0]); \file_put_contents(\sys_get_temp_dir() . '/sf_' . $commandName . '.log', \implode(\PHP_EOL, (array) $messages) . \PHP_EOL, \FILE_APPEND); } } * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace _HumbugBox7ff99e199a36\Symfony\Component\Console\Command; use _HumbugBox7ff99e199a36\Symfony\Component\Console\Completion\CompletionInput; use _HumbugBox7ff99e199a36\Symfony\Component\Console\Completion\CompletionSuggestions; use _HumbugBox7ff99e199a36\Symfony\Component\Console\Descriptor\ApplicationDescription; use _HumbugBox7ff99e199a36\Symfony\Component\Console\Helper\DescriptorHelper; use _HumbugBox7ff99e199a36\Symfony\Component\Console\Input\InputArgument; use _HumbugBox7ff99e199a36\Symfony\Component\Console\Input\InputInterface; use _HumbugBox7ff99e199a36\Symfony\Component\Console\Input\InputOption; use _HumbugBox7ff99e199a36\Symfony\Component\Console\Output\OutputInterface; /** * HelpCommand displays the help for a given command. * * @author Fabien Potencier */ class HelpCommand extends Command { private $command; /** * {@inheritdoc} */ protected function configure() { $this->ignoreValidationErrors(); $this->setName('help')->setDefinition([new InputArgument('command_name', InputArgument::OPTIONAL, 'The command name', 'help'), new InputOption('format', null, InputOption::VALUE_REQUIRED, 'The output format (txt, xml, json, or md)', 'txt'), new InputOption('raw', null, InputOption::VALUE_NONE, 'To output raw command help')])->setDescription('Display help for a command')->setHelp(<<<'EOF' The %command.name% command displays help for a given command: %command.full_name% list You can also output the help in other formats by using the --format option: %command.full_name% --format=xml list To display the list of available commands, please use the list command. EOF ); } public function setCommand(Command $command) { $this->command = $command; } /** * {@inheritdoc} */ protected function execute(InputInterface $input, OutputInterface $output) { if (null === $this->command) { $this->command = $this->getApplication()->find($input->getArgument('command_name')); } $helper = new DescriptorHelper(); $helper->describe($output, $this->command, ['format' => $input->getOption('format'), 'raw_text' => $input->getOption('raw')]); $this->command = null; return 0; } public function complete(CompletionInput $input, CompletionSuggestions $suggestions) : void { if ($input->mustSuggestArgumentValuesFor('command_name')) { $descriptor = new ApplicationDescription($this->getApplication()); $suggestions->suggestValues(\array_keys($descriptor->getCommands())); return; } if ($input->mustSuggestOptionValuesFor('format')) { $helper = new DescriptorHelper(); $suggestions->suggestValues($helper->getFormats()); } } } * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace _HumbugBox7ff99e199a36\Symfony\Component\Console\Command; use _HumbugBox7ff99e199a36\Symfony\Component\Console\Completion\CompletionInput; use _HumbugBox7ff99e199a36\Symfony\Component\Console\Completion\CompletionSuggestions; use _HumbugBox7ff99e199a36\Symfony\Component\Console\Input\InputArgument; use _HumbugBox7ff99e199a36\Symfony\Component\Console\Input\InputInterface; use _HumbugBox7ff99e199a36\Symfony\Component\Console\Input\InputOption; use _HumbugBox7ff99e199a36\Symfony\Component\Console\Output\ConsoleOutputInterface; use _HumbugBox7ff99e199a36\Symfony\Component\Console\Output\OutputInterface; use _HumbugBox7ff99e199a36\Symfony\Component\Process\Process; /** * Dumps the completion script for the current shell. * * @author Wouter de Jong */ final class DumpCompletionCommand extends Command { protected static $defaultName = 'completion'; protected static $defaultDescription = 'Dump the shell completion script'; public function complete(CompletionInput $input, CompletionSuggestions $suggestions) : void { if ($input->mustSuggestArgumentValuesFor('shell')) { $suggestions->suggestValues($this->getSupportedShells()); } } protected function configure() { $fullCommand = $_SERVER['PHP_SELF']; $commandName = \basename($fullCommand); $fullCommand = @\realpath($fullCommand) ?: $fullCommand; $this->setHelp(<<%command.name% command dumps the shell completion script required to use shell autocompletion (currently only bash completion is supported). Static installation ------------------- Dump the script to a global completion file and restart your shell: %command.full_name% bash | sudo tee /etc/bash_completion.d/{$commandName} Or dump the script to a local file and source it: %command.full_name% bash > completion.sh # source the file whenever you use the project source completion.sh # or add this line at the end of your "~/.bashrc" file: source /path/to/completion.sh Dynamic installation -------------------- Add this to the end of your shell configuration file (e.g. "~/.bashrc"): eval "\$({$fullCommand} completion bash)" EOH )->addArgument('shell', InputArgument::OPTIONAL, 'The shell type (e.g. "bash"), the value of the "$SHELL" env var will be used if this is not given')->addOption('debug', null, InputOption::VALUE_NONE, 'Tail the completion debug log'); } protected function execute(InputInterface $input, OutputInterface $output) : int { $commandName = \basename($_SERVER['argv'][0]); if ($input->getOption('debug')) { $this->tailDebugLog($commandName, $output); return 0; } $shell = $input->getArgument('shell') ?? self::guessShell(); $completionFile = __DIR__ . '/../Resources/completion.' . $shell; if (!\file_exists($completionFile)) { $supportedShells = $this->getSupportedShells(); if ($output instanceof ConsoleOutputInterface) { $output = $output->getErrorOutput(); } if ($shell) { $output->writeln(\sprintf('Detected shell "%s", which is not supported by Symfony shell completion (supported shells: "%s").', $shell, \implode('", "', $supportedShells))); } else { $output->writeln(\sprintf('Shell not detected, Symfony shell completion only supports "%s").', \implode('", "', $supportedShells))); } return 2; } $output->write(\str_replace(['{{ COMMAND_NAME }}', '{{ VERSION }}'], [$commandName, $this->getApplication()->getVersion()], \file_get_contents($completionFile))); return 0; } private static function guessShell() : string { return \basename($_SERVER['SHELL'] ?? ''); } private function tailDebugLog(string $commandName, OutputInterface $output) : void { $debugFile = \sys_get_temp_dir() . '/sf_' . $commandName . '.log'; if (!\file_exists($debugFile)) { \touch($debugFile); } $process = new Process(['tail', '-f', $debugFile], null, null, null, 0); $process->run(function (string $type, string $line) use($output) : void { $output->write($line); }); } /** * @return string[] */ private function getSupportedShells() : array { $shells = []; foreach (new \DirectoryIterator(__DIR__ . '/../Resources/') as $file) { if (\str_starts_with($file->getBasename(), 'completion.') && $file->isFile()) { $shells[] = $file->getExtension(); } } return $shells; } } * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace _HumbugBox7ff99e199a36\Symfony\Component\Console\CommandLoader; use _HumbugBox7ff99e199a36\Psr\Container\ContainerInterface; use _HumbugBox7ff99e199a36\Symfony\Component\Console\Exception\CommandNotFoundException; /** * Loads commands from a PSR-11 container. * * @author Robin Chalas */ class ContainerCommandLoader implements CommandLoaderInterface { private $container; private $commandMap; /** * @param array $commandMap An array with command names as keys and service ids as values */ public function __construct(ContainerInterface $container, array $commandMap) { $this->container = $container; $this->commandMap = $commandMap; } /** * {@inheritdoc} */ public function get(string $name) { if (!$this->has($name)) { throw new CommandNotFoundException(\sprintf('Command "%s" does not exist.', $name)); } return $this->container->get($this->commandMap[$name]); } /** * {@inheritdoc} */ public function has(string $name) { return isset($this->commandMap[$name]) && $this->container->has($this->commandMap[$name]); } /** * {@inheritdoc} */ public function getNames() { return \array_keys($this->commandMap); } } * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace _HumbugBox7ff99e199a36\Symfony\Component\Console\CommandLoader; use _HumbugBox7ff99e199a36\Symfony\Component\Console\Exception\CommandNotFoundException; /** * A simple command loader using factories to instantiate commands lazily. * * @author Maxime Steinhausser */ class FactoryCommandLoader implements CommandLoaderInterface { private $factories; /** * @param callable[] $factories Indexed by command names */ public function __construct(array $factories) { $this->factories = $factories; } /** * {@inheritdoc} */ public function has(string $name) { return isset($this->factories[$name]); } /** * {@inheritdoc} */ public function get(string $name) { if (!isset($this->factories[$name])) { throw new CommandNotFoundException(\sprintf('Command "%s" does not exist.', $name)); } $factory = $this->factories[$name]; return $factory(); } /** * {@inheritdoc} */ public function getNames() { return \array_keys($this->factories); } } * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace _HumbugBox7ff99e199a36\Symfony\Component\Console\CommandLoader; use _HumbugBox7ff99e199a36\Symfony\Component\Console\Command\Command; use _HumbugBox7ff99e199a36\Symfony\Component\Console\Exception\CommandNotFoundException; /** * @author Robin Chalas */ interface CommandLoaderInterface { /** * Loads a command. * * @return Command * * @throws CommandNotFoundException */ public function get(string $name); /** * Checks if a command exists. * * @return bool */ public function has(string $name); /** * @return string[] */ public function getNames(); } * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace _HumbugBox7ff99e199a36\Symfony\Component\Console\Output; use _HumbugBox7ff99e199a36\Symfony\Component\Console\Formatter\OutputFormatterInterface; use _HumbugBox7ff99e199a36\Symfony\Component\Console\Helper\Helper; use _HumbugBox7ff99e199a36\Symfony\Component\Console\Terminal; /** * @author Pierre du Plessis * @author Gabriel Ostrolucký */ class ConsoleSectionOutput extends StreamOutput { private $content = []; private $lines = 0; private $sections; private $terminal; /** * @param resource $stream * @param ConsoleSectionOutput[] $sections */ public function __construct($stream, array &$sections, int $verbosity, bool $decorated, OutputFormatterInterface $formatter) { parent::__construct($stream, $verbosity, $decorated, $formatter); \array_unshift($sections, $this); $this->sections =& $sections; $this->terminal = new Terminal(); } /** * Clears previous output for this section. * * @param int $lines Number of lines to clear. If null, then the entire output of this section is cleared */ public function clear(?int $lines = null) { if (empty($this->content) || !$this->isDecorated()) { return; } if ($lines) { \array_splice($this->content, -($lines * 2)); // Multiply lines by 2 to cater for each new line added between content } else { $lines = $this->lines; $this->content = []; } $this->lines -= $lines; parent::doWrite($this->popStreamContentUntilCurrentSection($lines), \false); } /** * Overwrites the previous output with a new message. * * @param array|string $message */ public function overwrite($message) { $this->clear(); $this->writeln($message); } public function getContent() : string { return \implode('', $this->content); } /** * @internal */ public function addContent(string $input) { foreach (\explode(\PHP_EOL, $input) as $lineContent) { $this->lines += \ceil($this->getDisplayLength($lineContent) / $this->terminal->getWidth()) ?: 1; $this->content[] = $lineContent; $this->content[] = \PHP_EOL; } } /** * {@inheritdoc} */ protected function doWrite(string $message, bool $newline) { if (!$this->isDecorated()) { parent::doWrite($message, $newline); return; } $erasedContent = $this->popStreamContentUntilCurrentSection(); $this->addContent($message); parent::doWrite($message, \true); parent::doWrite($erasedContent, \false); } /** * At initial stage, cursor is at the end of stream output. This method makes cursor crawl upwards until it hits * current section. Then it erases content it crawled through. Optionally, it erases part of current section too. */ private function popStreamContentUntilCurrentSection(int $numberOfLinesToClearFromCurrentSection = 0) : string { $numberOfLinesToClear = $numberOfLinesToClearFromCurrentSection; $erasedContent = []; foreach ($this->sections as $section) { if ($section === $this) { break; } $numberOfLinesToClear += $section->lines; $erasedContent[] = $section->getContent(); } if ($numberOfLinesToClear > 0) { // move cursor up n lines parent::doWrite(\sprintf("\x1b[%dA", $numberOfLinesToClear), \false); // erase to end of screen parent::doWrite("\x1b[0J", \false); } return \implode('', \array_reverse($erasedContent)); } private function getDisplayLength(string $text) : int { return Helper::width(Helper::removeDecoration($this->getFormatter(), \str_replace("\t", ' ', $text))); } } * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace _HumbugBox7ff99e199a36\Symfony\Component\Console\Output; /** * @author Jean-François Simon */ class BufferedOutput extends Output { private $buffer = ''; /** * Empties buffer and returns its content. * * @return string */ public function fetch() { $content = $this->buffer; $this->buffer = ''; return $content; } /** * {@inheritdoc} */ protected function doWrite(string $message, bool $newline) { $this->buffer .= $message; if ($newline) { $this->buffer .= \PHP_EOL; } } } * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace _HumbugBox7ff99e199a36\Symfony\Component\Console\Output; use _HumbugBox7ff99e199a36\Symfony\Component\Console\Exception\InvalidArgumentException; use _HumbugBox7ff99e199a36\Symfony\Component\Console\Formatter\OutputFormatterInterface; /** * StreamOutput writes the output to a given stream. * * Usage: * * $output = new StreamOutput(fopen('php://stdout', 'w')); * * As `StreamOutput` can use any stream, you can also use a file: * * $output = new StreamOutput(fopen('/path/to/output.log', 'a', false)); * * @author Fabien Potencier */ class StreamOutput extends Output { private $stream; /** * @param resource $stream A stream resource * @param int $verbosity The verbosity level (one of the VERBOSITY constants in OutputInterface) * @param bool|null $decorated Whether to decorate messages (null for auto-guessing) * @param OutputFormatterInterface|null $formatter Output formatter instance (null to use default OutputFormatter) * * @throws InvalidArgumentException When first argument is not a real stream */ public function __construct($stream, int $verbosity = self::VERBOSITY_NORMAL, ?bool $decorated = null, ?OutputFormatterInterface $formatter = null) { if (!\is_resource($stream) || 'stream' !== \get_resource_type($stream)) { throw new InvalidArgumentException('The StreamOutput class needs a stream as its first argument.'); } $this->stream = $stream; if (null === $decorated) { $decorated = $this->hasColorSupport(); } parent::__construct($verbosity, $decorated, $formatter); } /** * Gets the stream attached to this StreamOutput instance. * * @return resource */ public function getStream() { return $this->stream; } protected function doWrite(string $message, bool $newline) { if ($newline) { $message .= \PHP_EOL; } @\fwrite($this->stream, $message); \fflush($this->stream); } /** * Returns true if the stream supports colorization. * * Colorization is disabled if not supported by the stream: * * This is tricky on Windows, because Cygwin, Msys2 etc emulate pseudo * terminals via named pipes, so we can only check the environment. * * Reference: Composer\XdebugHandler\Process::supportsColor * https://github.com/composer/xdebug-handler * * @return bool true if the stream supports colorization, false otherwise */ protected function hasColorSupport() { // Follow https://no-color.org/ if ('' !== (($_SERVER['NO_COLOR'] ?? \getenv('NO_COLOR'))[0] ?? '')) { return \false; } // Detect msysgit/mingw and assume this is a tty because detection // does not work correctly, see https://github.com/composer/composer/issues/9690 if (!@\stream_isatty($this->stream) && !\in_array(\strtoupper((string) \getenv('MSYSTEM')), ['MINGW32', 'MINGW64'], \true)) { return \false; } if ('\\' === \DIRECTORY_SEPARATOR && @\sapi_windows_vt100_support($this->stream)) { return \true; } if ('Hyper' === \getenv('TERM_PROGRAM') || \false !== \getenv('COLORTERM') || \false !== \getenv('ANSICON') || 'ON' === \getenv('ConEmuANSI')) { return \true; } if ('dumb' === ($term = (string) \getenv('TERM'))) { return \false; } // See https://github.com/chalk/supports-color/blob/d4f413efaf8da045c5ab440ed418ef02dbb28bf1/index.js#L157 return \preg_match('/^((screen|xterm|vt100|vt220|putty|rxvt|ansi|cygwin|linux).*)|(.*-256(color)?(-bce)?)$/', $term); } } * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace _HumbugBox7ff99e199a36\Symfony\Component\Console\Output; /** * ConsoleOutputInterface is the interface implemented by ConsoleOutput class. * This adds information about stderr and section output stream. * * @author Dariusz Górecki */ interface ConsoleOutputInterface extends OutputInterface { /** * Gets the OutputInterface for errors. * * @return OutputInterface */ public function getErrorOutput(); public function setErrorOutput(OutputInterface $error); public function section() : ConsoleSectionOutput; } * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace _HumbugBox7ff99e199a36\Symfony\Component\Console\Output; use _HumbugBox7ff99e199a36\Symfony\Component\Console\Exception\InvalidArgumentException; use _HumbugBox7ff99e199a36\Symfony\Component\Console\Formatter\OutputFormatterInterface; /** * A BufferedOutput that keeps only the last N chars. * * @author Jérémy Derussé */ class TrimmedBufferOutput extends Output { private $maxLength; private $buffer = ''; public function __construct(int $maxLength, ?int $verbosity = self::VERBOSITY_NORMAL, bool $decorated = \false, ?OutputFormatterInterface $formatter = null) { if ($maxLength <= 0) { throw new InvalidArgumentException(\sprintf('"%s()" expects a strictly positive maxLength. Got %d.', __METHOD__, $maxLength)); } parent::__construct($verbosity, $decorated, $formatter); $this->maxLength = $maxLength; } /** * Empties buffer and returns its content. * * @return string */ public function fetch() { $content = $this->buffer; $this->buffer = ''; return $content; } /** * {@inheritdoc} */ protected function doWrite(string $message, bool $newline) { $this->buffer .= $message; if ($newline) { $this->buffer .= \PHP_EOL; } $this->buffer = \substr($this->buffer, 0 - $this->maxLength); } } * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace _HumbugBox7ff99e199a36\Symfony\Component\Console\Output; use _HumbugBox7ff99e199a36\Symfony\Component\Console\Formatter\OutputFormatterInterface; /** * OutputInterface is the interface implemented by all Output classes. * * @author Fabien Potencier */ interface OutputInterface { public const VERBOSITY_QUIET = 16; public const VERBOSITY_NORMAL = 32; public const VERBOSITY_VERBOSE = 64; public const VERBOSITY_VERY_VERBOSE = 128; public const VERBOSITY_DEBUG = 256; public const OUTPUT_NORMAL = 1; public const OUTPUT_RAW = 2; public const OUTPUT_PLAIN = 4; /** * Writes a message to the output. * * @param string|iterable $messages The message as an iterable of strings or a single string * @param bool $newline Whether to add a newline * @param int $options A bitmask of options (one of the OUTPUT or VERBOSITY constants), 0 is considered the same as self::OUTPUT_NORMAL | self::VERBOSITY_NORMAL */ public function write($messages, bool $newline = \false, int $options = 0); /** * Writes a message to the output and adds a newline at the end. * * @param string|iterable $messages The message as an iterable of strings or a single string * @param int $options A bitmask of options (one of the OUTPUT or VERBOSITY constants), 0 is considered the same as self::OUTPUT_NORMAL | self::VERBOSITY_NORMAL */ public function writeln($messages, int $options = 0); /** * Sets the verbosity of the output. */ public function setVerbosity(int $level); /** * Gets the current verbosity of the output. * * @return int */ public function getVerbosity(); /** * Returns whether verbosity is quiet (-q). * * @return bool */ public function isQuiet(); /** * Returns whether verbosity is verbose (-v). * * @return bool */ public function isVerbose(); /** * Returns whether verbosity is very verbose (-vv). * * @return bool */ public function isVeryVerbose(); /** * Returns whether verbosity is debug (-vvv). * * @return bool */ public function isDebug(); /** * Sets the decorated flag. */ public function setDecorated(bool $decorated); /** * Gets the decorated flag. * * @return bool */ public function isDecorated(); public function setFormatter(OutputFormatterInterface $formatter); /** * Returns current output formatter instance. * * @return OutputFormatterInterface */ public function getFormatter(); } * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace _HumbugBox7ff99e199a36\Symfony\Component\Console\Output; use _HumbugBox7ff99e199a36\Symfony\Component\Console\Formatter\OutputFormatterInterface; /** * ConsoleOutput is the default class for all CLI output. It uses STDOUT and STDERR. * * This class is a convenient wrapper around `StreamOutput` for both STDOUT and STDERR. * * $output = new ConsoleOutput(); * * This is equivalent to: * * $output = new StreamOutput(fopen('php://stdout', 'w')); * $stdErr = new StreamOutput(fopen('php://stderr', 'w')); * * @author Fabien Potencier */ class ConsoleOutput extends StreamOutput implements ConsoleOutputInterface { private $stderr; private $consoleSectionOutputs = []; /** * @param int $verbosity The verbosity level (one of the VERBOSITY constants in OutputInterface) * @param bool|null $decorated Whether to decorate messages (null for auto-guessing) * @param OutputFormatterInterface|null $formatter Output formatter instance (null to use default OutputFormatter) */ public function __construct(int $verbosity = self::VERBOSITY_NORMAL, ?bool $decorated = null, ?OutputFormatterInterface $formatter = null) { parent::__construct($this->openOutputStream(), $verbosity, $decorated, $formatter); if (null === $formatter) { // for BC reasons, stdErr has it own Formatter only when user don't inject a specific formatter. $this->stderr = new StreamOutput($this->openErrorStream(), $verbosity, $decorated); return; } $actualDecorated = $this->isDecorated(); $this->stderr = new StreamOutput($this->openErrorStream(), $verbosity, $decorated, $this->getFormatter()); if (null === $decorated) { $this->setDecorated($actualDecorated && $this->stderr->isDecorated()); } } /** * Creates a new output section. */ public function section() : ConsoleSectionOutput { return new ConsoleSectionOutput($this->getStream(), $this->consoleSectionOutputs, $this->getVerbosity(), $this->isDecorated(), $this->getFormatter()); } /** * {@inheritdoc} */ public function setDecorated(bool $decorated) { parent::setDecorated($decorated); $this->stderr->setDecorated($decorated); } /** * {@inheritdoc} */ public function setFormatter(OutputFormatterInterface $formatter) { parent::setFormatter($formatter); $this->stderr->setFormatter($formatter); } /** * {@inheritdoc} */ public function setVerbosity(int $level) { parent::setVerbosity($level); $this->stderr->setVerbosity($level); } /** * {@inheritdoc} */ public function getErrorOutput() { return $this->stderr; } /** * {@inheritdoc} */ public function setErrorOutput(OutputInterface $error) { $this->stderr = $error; } /** * Returns true if current environment supports writing console output to * STDOUT. * * @return bool */ protected function hasStdoutSupport() { return \false === $this->isRunningOS400(); } /** * Returns true if current environment supports writing console output to * STDERR. * * @return bool */ protected function hasStderrSupport() { return \false === $this->isRunningOS400(); } /** * Checks if current executing environment is IBM iSeries (OS400), which * doesn't properly convert character-encodings between ASCII to EBCDIC. */ private function isRunningOS400() : bool { $checks = [\function_exists('php_uname') ? \php_uname('s') : '', \getenv('OSTYPE'), \PHP_OS]; return \false !== \stripos(\implode(';', $checks), 'OS400'); } /** * @return resource */ private function openOutputStream() { if (!$this->hasStdoutSupport()) { return \fopen('php://output', 'w'); } // Use STDOUT when possible to prevent from opening too many file descriptors return \defined('STDOUT') ? \STDOUT : (@\fopen('php://stdout', 'w') ?: \fopen('php://output', 'w')); } /** * @return resource */ private function openErrorStream() { if (!$this->hasStderrSupport()) { return \fopen('php://output', 'w'); } // Use STDERR when possible to prevent from opening too many file descriptors return \defined('STDERR') ? \STDERR : (@\fopen('php://stderr', 'w') ?: \fopen('php://output', 'w')); } } * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace _HumbugBox7ff99e199a36\Symfony\Component\Console\Output; use _HumbugBox7ff99e199a36\Symfony\Component\Console\Formatter\OutputFormatter; use _HumbugBox7ff99e199a36\Symfony\Component\Console\Formatter\OutputFormatterInterface; /** * Base class for output classes. * * There are five levels of verbosity: * * * normal: no option passed (normal output) * * verbose: -v (more output) * * very verbose: -vv (highly extended output) * * debug: -vvv (all debug output) * * quiet: -q (no output) * * @author Fabien Potencier */ abstract class Output implements OutputInterface { private $verbosity; private $formatter; /** * @param int|null $verbosity The verbosity level (one of the VERBOSITY constants in OutputInterface) * @param bool $decorated Whether to decorate messages * @param OutputFormatterInterface|null $formatter Output formatter instance (null to use default OutputFormatter) */ public function __construct(?int $verbosity = self::VERBOSITY_NORMAL, bool $decorated = \false, ?OutputFormatterInterface $formatter = null) { $this->verbosity = $verbosity ?? self::VERBOSITY_NORMAL; $this->formatter = $formatter ?? new OutputFormatter(); $this->formatter->setDecorated($decorated); } /** * {@inheritdoc} */ public function setFormatter(OutputFormatterInterface $formatter) { $this->formatter = $formatter; } /** * {@inheritdoc} */ public function getFormatter() { return $this->formatter; } /** * {@inheritdoc} */ public function setDecorated(bool $decorated) { $this->formatter->setDecorated($decorated); } /** * {@inheritdoc} */ public function isDecorated() { return $this->formatter->isDecorated(); } /** * {@inheritdoc} */ public function setVerbosity(int $level) { $this->verbosity = $level; } /** * {@inheritdoc} */ public function getVerbosity() { return $this->verbosity; } /** * {@inheritdoc} */ public function isQuiet() { return self::VERBOSITY_QUIET === $this->verbosity; } /** * {@inheritdoc} */ public function isVerbose() { return self::VERBOSITY_VERBOSE <= $this->verbosity; } /** * {@inheritdoc} */ public function isVeryVerbose() { return self::VERBOSITY_VERY_VERBOSE <= $this->verbosity; } /** * {@inheritdoc} */ public function isDebug() { return self::VERBOSITY_DEBUG <= $this->verbosity; } /** * {@inheritdoc} */ public function writeln($messages, int $options = self::OUTPUT_NORMAL) { $this->write($messages, \true, $options); } /** * {@inheritdoc} */ public function write($messages, bool $newline = \false, int $options = self::OUTPUT_NORMAL) { if (!\is_iterable($messages)) { $messages = [$messages]; } $types = self::OUTPUT_NORMAL | self::OUTPUT_RAW | self::OUTPUT_PLAIN; $type = $types & $options ?: self::OUTPUT_NORMAL; $verbosities = self::VERBOSITY_QUIET | self::VERBOSITY_NORMAL | self::VERBOSITY_VERBOSE | self::VERBOSITY_VERY_VERBOSE | self::VERBOSITY_DEBUG; $verbosity = $verbosities & $options ?: self::VERBOSITY_NORMAL; if ($verbosity > $this->getVerbosity()) { return; } foreach ($messages as $message) { switch ($type) { case OutputInterface::OUTPUT_NORMAL: $message = $this->formatter->format($message); break; case OutputInterface::OUTPUT_RAW: break; case OutputInterface::OUTPUT_PLAIN: $message = \strip_tags($this->formatter->format($message)); break; } $this->doWrite($message ?? '', $newline); } } /** * Writes a message to the output. */ protected abstract function doWrite(string $message, bool $newline); } * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace _HumbugBox7ff99e199a36\Symfony\Component\Console\Output; use _HumbugBox7ff99e199a36\Symfony\Component\Console\Formatter\NullOutputFormatter; use _HumbugBox7ff99e199a36\Symfony\Component\Console\Formatter\OutputFormatterInterface; /** * NullOutput suppresses all output. * * $output = new NullOutput(); * * @author Fabien Potencier * @author Tobias Schultze */ class NullOutput implements OutputInterface { private $formatter; /** * {@inheritdoc} */ public function setFormatter(OutputFormatterInterface $formatter) { // do nothing } /** * {@inheritdoc} */ public function getFormatter() { if ($this->formatter) { return $this->formatter; } // to comply with the interface we must return a OutputFormatterInterface return $this->formatter = new NullOutputFormatter(); } /** * {@inheritdoc} */ public function setDecorated(bool $decorated) { // do nothing } /** * {@inheritdoc} */ public function isDecorated() { return \false; } /** * {@inheritdoc} */ public function setVerbosity(int $level) { // do nothing } /** * {@inheritdoc} */ public function getVerbosity() { return self::VERBOSITY_QUIET; } /** * {@inheritdoc} */ public function isQuiet() { return \true; } /** * {@inheritdoc} */ public function isVerbose() { return \false; } /** * {@inheritdoc} */ public function isVeryVerbose() { return \false; } /** * {@inheritdoc} */ public function isDebug() { return \false; } /** * {@inheritdoc} */ public function writeln($messages, int $options = self::OUTPUT_NORMAL) { // do nothing } /** * {@inheritdoc} */ public function write($messages, bool $newline = \false, int $options = self::OUTPUT_NORMAL) { // do nothing } } * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace _HumbugBox7ff99e199a36\Symfony\Component\Console\CI; use _HumbugBox7ff99e199a36\Symfony\Component\Console\Output\OutputInterface; /** * Utility class for Github actions. * * @author Maxime Steinhausser */ class GithubActionReporter { private $output; /** * @see https://github.com/actions/toolkit/blob/5e5e1b7aacba68a53836a34db4a288c3c1c1585b/packages/core/src/command.ts#L80-L85 */ private const ESCAPED_DATA = ['%' => '%25', "\r" => '%0D', "\n" => '%0A']; /** * @see https://github.com/actions/toolkit/blob/5e5e1b7aacba68a53836a34db4a288c3c1c1585b/packages/core/src/command.ts#L87-L94 */ private const ESCAPED_PROPERTIES = ['%' => '%25', "\r" => '%0D', "\n" => '%0A', ':' => '%3A', ',' => '%2C']; public function __construct(OutputInterface $output) { $this->output = $output; } public static function isGithubActionEnvironment() : bool { return \false !== \getenv('GITHUB_ACTIONS'); } /** * Output an error using the Github annotations format. * * @see https://docs.github.com/en/free-pro-team@latest/actions/reference/workflow-commands-for-github-actions#setting-an-error-message */ public function error(string $message, ?string $file = null, ?int $line = null, ?int $col = null) : void { $this->log('error', $message, $file, $line, $col); } /** * Output a warning using the Github annotations format. * * @see https://docs.github.com/en/free-pro-team@latest/actions/reference/workflow-commands-for-github-actions#setting-a-warning-message */ public function warning(string $message, ?string $file = null, ?int $line = null, ?int $col = null) : void { $this->log('warning', $message, $file, $line, $col); } /** * Output a debug log using the Github annotations format. * * @see https://docs.github.com/en/free-pro-team@latest/actions/reference/workflow-commands-for-github-actions#setting-a-debug-message */ public function debug(string $message, ?string $file = null, ?int $line = null, ?int $col = null) : void { $this->log('debug', $message, $file, $line, $col); } private function log(string $type, string $message, ?string $file = null, ?int $line = null, ?int $col = null) : void { // Some values must be encoded. $message = \strtr($message, self::ESCAPED_DATA); if (!$file) { // No file provided, output the message solely: $this->output->writeln(\sprintf('::%s::%s', $type, $message)); return; } $this->output->writeln(\sprintf('::%s file=%s,line=%s,col=%s::%s', $type, \strtr($file, self::ESCAPED_PROPERTIES), \strtr($line ?? 1, self::ESCAPED_PROPERTIES), \strtr($col ?? 0, self::ESCAPED_PROPERTIES), $message)); } } * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace _HumbugBox7ff99e199a36\Symfony\Component\Console\Input; use _HumbugBox7ff99e199a36\Symfony\Component\Console\Exception\InvalidArgumentException; use _HumbugBox7ff99e199a36\Symfony\Component\Console\Exception\LogicException; /** * A InputDefinition represents a set of valid command line arguments and options. * * Usage: * * $definition = new InputDefinition([ * new InputArgument('name', InputArgument::REQUIRED), * new InputOption('foo', 'f', InputOption::VALUE_REQUIRED), * ]); * * @author Fabien Potencier */ class InputDefinition { private $arguments; private $requiredCount; private $lastArrayArgument; private $lastOptionalArgument; private $options; private $negations; private $shortcuts; /** * @param array $definition An array of InputArgument and InputOption instance */ public function __construct(array $definition = []) { $this->setDefinition($definition); } /** * Sets the definition of the input. */ public function setDefinition(array $definition) { $arguments = []; $options = []; foreach ($definition as $item) { if ($item instanceof InputOption) { $options[] = $item; } else { $arguments[] = $item; } } $this->setArguments($arguments); $this->setOptions($options); } /** * Sets the InputArgument objects. * * @param InputArgument[] $arguments An array of InputArgument objects */ public function setArguments(array $arguments = []) { $this->arguments = []; $this->requiredCount = 0; $this->lastOptionalArgument = null; $this->lastArrayArgument = null; $this->addArguments($arguments); } /** * Adds an array of InputArgument objects. * * @param InputArgument[] $arguments An array of InputArgument objects */ public function addArguments(?array $arguments = []) { if (null !== $arguments) { foreach ($arguments as $argument) { $this->addArgument($argument); } } } /** * @throws LogicException When incorrect argument is given */ public function addArgument(InputArgument $argument) { if (isset($this->arguments[$argument->getName()])) { throw new LogicException(\sprintf('An argument with name "%s" already exists.', $argument->getName())); } if (null !== $this->lastArrayArgument) { throw new LogicException(\sprintf('Cannot add a required argument "%s" after an array argument "%s".', $argument->getName(), $this->lastArrayArgument->getName())); } if ($argument->isRequired() && null !== $this->lastOptionalArgument) { throw new LogicException(\sprintf('Cannot add a required argument "%s" after an optional one "%s".', $argument->getName(), $this->lastOptionalArgument->getName())); } if ($argument->isArray()) { $this->lastArrayArgument = $argument; } if ($argument->isRequired()) { ++$this->requiredCount; } else { $this->lastOptionalArgument = $argument; } $this->arguments[$argument->getName()] = $argument; } /** * Returns an InputArgument by name or by position. * * @param string|int $name The InputArgument name or position * * @return InputArgument * * @throws InvalidArgumentException When argument given doesn't exist */ public function getArgument($name) { if (!$this->hasArgument($name)) { throw new InvalidArgumentException(\sprintf('The "%s" argument does not exist.', $name)); } $arguments = \is_int($name) ? \array_values($this->arguments) : $this->arguments; return $arguments[$name]; } /** * Returns true if an InputArgument object exists by name or position. * * @param string|int $name The InputArgument name or position * * @return bool */ public function hasArgument($name) { $arguments = \is_int($name) ? \array_values($this->arguments) : $this->arguments; return isset($arguments[$name]); } /** * Gets the array of InputArgument objects. * * @return InputArgument[] */ public function getArguments() { return $this->arguments; } /** * Returns the number of InputArguments. * * @return int */ public function getArgumentCount() { return null !== $this->lastArrayArgument ? \PHP_INT_MAX : \count($this->arguments); } /** * Returns the number of required InputArguments. * * @return int */ public function getArgumentRequiredCount() { return $this->requiredCount; } /** * @return array */ public function getArgumentDefaults() { $values = []; foreach ($this->arguments as $argument) { $values[$argument->getName()] = $argument->getDefault(); } return $values; } /** * Sets the InputOption objects. * * @param InputOption[] $options An array of InputOption objects */ public function setOptions(array $options = []) { $this->options = []; $this->shortcuts = []; $this->negations = []; $this->addOptions($options); } /** * Adds an array of InputOption objects. * * @param InputOption[] $options An array of InputOption objects */ public function addOptions(array $options = []) { foreach ($options as $option) { $this->addOption($option); } } /** * @throws LogicException When option given already exist */ public function addOption(InputOption $option) { if (isset($this->options[$option->getName()]) && !$option->equals($this->options[$option->getName()])) { throw new LogicException(\sprintf('An option named "%s" already exists.', $option->getName())); } if (isset($this->negations[$option->getName()])) { throw new LogicException(\sprintf('An option named "%s" already exists.', $option->getName())); } if ($option->getShortcut()) { foreach (\explode('|', $option->getShortcut()) as $shortcut) { if (isset($this->shortcuts[$shortcut]) && !$option->equals($this->options[$this->shortcuts[$shortcut]])) { throw new LogicException(\sprintf('An option with shortcut "%s" already exists.', $shortcut)); } } } $this->options[$option->getName()] = $option; if ($option->getShortcut()) { foreach (\explode('|', $option->getShortcut()) as $shortcut) { $this->shortcuts[$shortcut] = $option->getName(); } } if ($option->isNegatable()) { $negatedName = 'no-' . $option->getName(); if (isset($this->options[$negatedName])) { throw new LogicException(\sprintf('An option named "%s" already exists.', $negatedName)); } $this->negations[$negatedName] = $option->getName(); } } /** * Returns an InputOption by name. * * @return InputOption * * @throws InvalidArgumentException When option given doesn't exist */ public function getOption(string $name) { if (!$this->hasOption($name)) { throw new InvalidArgumentException(\sprintf('The "--%s" option does not exist.', $name)); } return $this->options[$name]; } /** * Returns true if an InputOption object exists by name. * * This method can't be used to check if the user included the option when * executing the command (use getOption() instead). * * @return bool */ public function hasOption(string $name) { return isset($this->options[$name]); } /** * Gets the array of InputOption objects. * * @return InputOption[] */ public function getOptions() { return $this->options; } /** * Returns true if an InputOption object exists by shortcut. * * @return bool */ public function hasShortcut(string $name) { return isset($this->shortcuts[$name]); } /** * Returns true if an InputOption object exists by negated name. */ public function hasNegation(string $name) : bool { return isset($this->negations[$name]); } /** * Gets an InputOption by shortcut. * * @return InputOption */ public function getOptionForShortcut(string $shortcut) { return $this->getOption($this->shortcutToName($shortcut)); } /** * @return array */ public function getOptionDefaults() { $values = []; foreach ($this->options as $option) { $values[$option->getName()] = $option->getDefault(); } return $values; } /** * Returns the InputOption name given a shortcut. * * @throws InvalidArgumentException When option given does not exist * * @internal */ public function shortcutToName(string $shortcut) : string { if (!isset($this->shortcuts[$shortcut])) { throw new InvalidArgumentException(\sprintf('The "-%s" option does not exist.', $shortcut)); } return $this->shortcuts[$shortcut]; } /** * Returns the InputOption name given a negation. * * @throws InvalidArgumentException When option given does not exist * * @internal */ public function negationToName(string $negation) : string { if (!isset($this->negations[$negation])) { throw new InvalidArgumentException(\sprintf('The "--%s" option does not exist.', $negation)); } return $this->negations[$negation]; } /** * Gets the synopsis. * * @return string */ public function getSynopsis(bool $short = \false) { $elements = []; if ($short && $this->getOptions()) { $elements[] = '[options]'; } elseif (!$short) { foreach ($this->getOptions() as $option) { $value = ''; if ($option->acceptValue()) { $value = \sprintf(' %s%s%s', $option->isValueOptional() ? '[' : '', \strtoupper($option->getName()), $option->isValueOptional() ? ']' : ''); } $shortcut = $option->getShortcut() ? \sprintf('-%s|', $option->getShortcut()) : ''; $negation = $option->isNegatable() ? \sprintf('|--no-%s', $option->getName()) : ''; $elements[] = \sprintf('[%s--%s%s%s]', $shortcut, $option->getName(), $value, $negation); } } if (\count($elements) && $this->getArguments()) { $elements[] = '[--]'; } $tail = ''; foreach ($this->getArguments() as $argument) { $element = '<' . $argument->getName() . '>'; if ($argument->isArray()) { $element .= '...'; } if (!$argument->isRequired()) { $element = '[' . $element; $tail .= ']'; } $elements[] = $element; } return \implode(' ', $elements) . $tail; } } * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace _HumbugBox7ff99e199a36\Symfony\Component\Console\Input; use _HumbugBox7ff99e199a36\Symfony\Component\Console\Exception\InvalidArgumentException; use _HumbugBox7ff99e199a36\Symfony\Component\Console\Exception\InvalidOptionException; /** * ArrayInput represents an input provided as an array. * * Usage: * * $input = new ArrayInput(['command' => 'foo:bar', 'foo' => 'bar', '--bar' => 'foobar']); * * @author Fabien Potencier */ class ArrayInput extends Input { private $parameters; public function __construct(array $parameters, ?InputDefinition $definition = null) { $this->parameters = $parameters; parent::__construct($definition); } /** * {@inheritdoc} */ public function getFirstArgument() { foreach ($this->parameters as $param => $value) { if ($param && \is_string($param) && '-' === $param[0]) { continue; } return $value; } return null; } /** * {@inheritdoc} */ public function hasParameterOption($values, bool $onlyParams = \false) { $values = (array) $values; foreach ($this->parameters as $k => $v) { if (!\is_int($k)) { $v = $k; } if ($onlyParams && '--' === $v) { return \false; } if (\in_array($v, $values)) { return \true; } } return \false; } /** * {@inheritdoc} */ public function getParameterOption($values, $default = \false, bool $onlyParams = \false) { $values = (array) $values; foreach ($this->parameters as $k => $v) { if ($onlyParams && ('--' === $k || \is_int($k) && '--' === $v)) { return $default; } if (\is_int($k)) { if (\in_array($v, $values)) { return \true; } } elseif (\in_array($k, $values)) { return $v; } } return $default; } /** * Returns a stringified representation of the args passed to the command. * * @return string */ public function __toString() { $params = []; foreach ($this->parameters as $param => $val) { if ($param && \is_string($param) && '-' === $param[0]) { $glue = '-' === $param[1] ? '=' : ' '; if (\is_array($val)) { foreach ($val as $v) { $params[] = $param . ('' != $v ? $glue . $this->escapeToken($v) : ''); } } else { $params[] = $param . ('' != $val ? $glue . $this->escapeToken($val) : ''); } } else { $params[] = \is_array($val) ? \implode(' ', \array_map([$this, 'escapeToken'], $val)) : $this->escapeToken($val); } } return \implode(' ', $params); } /** * {@inheritdoc} */ protected function parse() { foreach ($this->parameters as $key => $value) { if ('--' === $key) { return; } if (\str_starts_with($key, '--')) { $this->addLongOption(\substr($key, 2), $value); } elseif (\str_starts_with($key, '-')) { $this->addShortOption(\substr($key, 1), $value); } else { $this->addArgument($key, $value); } } } /** * Adds a short option value. * * @throws InvalidOptionException When option given doesn't exist */ private function addShortOption(string $shortcut, $value) { if (!$this->definition->hasShortcut($shortcut)) { throw new InvalidOptionException(\sprintf('The "-%s" option does not exist.', $shortcut)); } $this->addLongOption($this->definition->getOptionForShortcut($shortcut)->getName(), $value); } /** * Adds a long option value. * * @throws InvalidOptionException When option given doesn't exist * @throws InvalidOptionException When a required value is missing */ private function addLongOption(string $name, $value) { if (!$this->definition->hasOption($name)) { if (!$this->definition->hasNegation($name)) { throw new InvalidOptionException(\sprintf('The "--%s" option does not exist.', $name)); } $optionName = $this->definition->negationToName($name); $this->options[$optionName] = \false; return; } $option = $this->definition->getOption($name); if (null === $value) { if ($option->isValueRequired()) { throw new InvalidOptionException(\sprintf('The "--%s" option requires a value.', $name)); } if (!$option->isValueOptional()) { $value = \true; } } $this->options[$name] = $value; } /** * Adds an argument value. * * @param string|int $name The argument name * @param mixed $value The value for the argument * * @throws InvalidArgumentException When argument given doesn't exist */ private function addArgument($name, $value) { if (!$this->definition->hasArgument($name)) { throw new InvalidArgumentException(\sprintf('The "%s" argument does not exist.', $name)); } $this->arguments[$name] = $value; } } * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace _HumbugBox7ff99e199a36\Symfony\Component\Console\Input; use _HumbugBox7ff99e199a36\Symfony\Component\Console\Exception\InvalidArgumentException; use _HumbugBox7ff99e199a36\Symfony\Component\Console\Exception\LogicException; /** * Represents a command line argument. * * @author Fabien Potencier */ class InputArgument { public const REQUIRED = 1; public const OPTIONAL = 2; public const IS_ARRAY = 4; private $name; private $mode; private $default; private $description; /** * @param string $name The argument name * @param int|null $mode The argument mode: a bit mask of self::REQUIRED, self::OPTIONAL and self::IS_ARRAY * @param string $description A description text * @param string|bool|int|float|array|null $default The default value (for self::OPTIONAL mode only) * * @throws InvalidArgumentException When argument mode is not valid */ public function __construct(string $name, ?int $mode = null, string $description = '', $default = null) { if (null === $mode) { $mode = self::OPTIONAL; } elseif ($mode > 7 || $mode < 1) { throw new InvalidArgumentException(\sprintf('Argument mode "%s" is not valid.', $mode)); } $this->name = $name; $this->mode = $mode; $this->description = $description; $this->setDefault($default); } /** * Returns the argument name. * * @return string */ public function getName() { return $this->name; } /** * Returns true if the argument is required. * * @return bool true if parameter mode is self::REQUIRED, false otherwise */ public function isRequired() { return self::REQUIRED === (self::REQUIRED & $this->mode); } /** * Returns true if the argument can take multiple values. * * @return bool true if mode is self::IS_ARRAY, false otherwise */ public function isArray() { return self::IS_ARRAY === (self::IS_ARRAY & $this->mode); } /** * Sets the default value. * * @param string|bool|int|float|array|null $default * * @throws LogicException When incorrect default value is given */ public function setDefault($default = null) { if ($this->isRequired() && null !== $default) { throw new LogicException('Cannot set a default value except for InputArgument::OPTIONAL mode.'); } if ($this->isArray()) { if (null === $default) { $default = []; } elseif (!\is_array($default)) { throw new LogicException('A default value for an array argument must be an array.'); } } $this->default = $default; } /** * Returns the default value. * * @return string|bool|int|float|array|null */ public function getDefault() { return $this->default; } /** * Returns the description text. * * @return string */ public function getDescription() { return $this->description; } } * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace _HumbugBox7ff99e199a36\Symfony\Component\Console\Input; use _HumbugBox7ff99e199a36\Symfony\Component\Console\Exception\InvalidArgumentException; use _HumbugBox7ff99e199a36\Symfony\Component\Console\Exception\LogicException; /** * Represents a command line option. * * @author Fabien Potencier */ class InputOption { /** * Do not accept input for the option (e.g. --yell). This is the default behavior of options. */ public const VALUE_NONE = 1; /** * A value must be passed when the option is used (e.g. --iterations=5 or -i5). */ public const VALUE_REQUIRED = 2; /** * The option may or may not have a value (e.g. --yell or --yell=loud). */ public const VALUE_OPTIONAL = 4; /** * The option accepts multiple values (e.g. --dir=/foo --dir=/bar). */ public const VALUE_IS_ARRAY = 8; /** * The option may have either positive or negative value (e.g. --ansi or --no-ansi). */ public const VALUE_NEGATABLE = 16; private $name; private $shortcut; private $mode; private $default; private $description; /** * @param string|array|null $shortcut The shortcuts, can be null, a string of shortcuts delimited by | or an array of shortcuts * @param int|null $mode The option mode: One of the VALUE_* constants * @param string|bool|int|float|array|null $default The default value (must be null for self::VALUE_NONE) * * @throws InvalidArgumentException If option mode is invalid or incompatible */ public function __construct(string $name, $shortcut = null, ?int $mode = null, string $description = '', $default = null) { if (\str_starts_with($name, '--')) { $name = \substr($name, 2); } if (empty($name)) { throw new InvalidArgumentException('An option name cannot be empty.'); } if ('' === $shortcut || [] === $shortcut || \false === $shortcut) { $shortcut = null; } if (null !== $shortcut) { if (\is_array($shortcut)) { $shortcut = \implode('|', $shortcut); } $shortcuts = \preg_split('{(\\|)-?}', \ltrim($shortcut, '-')); $shortcuts = \array_filter($shortcuts, 'strlen'); $shortcut = \implode('|', $shortcuts); if ('' === $shortcut) { throw new InvalidArgumentException('An option shortcut cannot be empty.'); } } if (null === $mode) { $mode = self::VALUE_NONE; } elseif ($mode >= self::VALUE_NEGATABLE << 1 || $mode < 1) { throw new InvalidArgumentException(\sprintf('Option mode "%s" is not valid.', $mode)); } $this->name = $name; $this->shortcut = $shortcut; $this->mode = $mode; $this->description = $description; if ($this->isArray() && !$this->acceptValue()) { throw new InvalidArgumentException('Impossible to have an option mode VALUE_IS_ARRAY if the option does not accept a value.'); } if ($this->isNegatable() && $this->acceptValue()) { throw new InvalidArgumentException('Impossible to have an option mode VALUE_NEGATABLE if the option also accepts a value.'); } $this->setDefault($default); } /** * Returns the option shortcut. * * @return string|null */ public function getShortcut() { return $this->shortcut; } /** * Returns the option name. * * @return string */ public function getName() { return $this->name; } /** * Returns true if the option accepts a value. * * @return bool true if value mode is not self::VALUE_NONE, false otherwise */ public function acceptValue() { return $this->isValueRequired() || $this->isValueOptional(); } /** * Returns true if the option requires a value. * * @return bool true if value mode is self::VALUE_REQUIRED, false otherwise */ public function isValueRequired() { return self::VALUE_REQUIRED === (self::VALUE_REQUIRED & $this->mode); } /** * Returns true if the option takes an optional value. * * @return bool true if value mode is self::VALUE_OPTIONAL, false otherwise */ public function isValueOptional() { return self::VALUE_OPTIONAL === (self::VALUE_OPTIONAL & $this->mode); } /** * Returns true if the option can take multiple values. * * @return bool true if mode is self::VALUE_IS_ARRAY, false otherwise */ public function isArray() { return self::VALUE_IS_ARRAY === (self::VALUE_IS_ARRAY & $this->mode); } public function isNegatable() : bool { return self::VALUE_NEGATABLE === (self::VALUE_NEGATABLE & $this->mode); } /** * @param string|bool|int|float|array|null $default */ public function setDefault($default = null) { if (self::VALUE_NONE === (self::VALUE_NONE & $this->mode) && null !== $default) { throw new LogicException('Cannot set a default value when using InputOption::VALUE_NONE mode.'); } if ($this->isArray()) { if (null === $default) { $default = []; } elseif (!\is_array($default)) { throw new LogicException('A default value for an array option must be an array.'); } } $this->default = $this->acceptValue() || $this->isNegatable() ? $default : \false; } /** * Returns the default value. * * @return string|bool|int|float|array|null */ public function getDefault() { return $this->default; } /** * Returns the description text. * * @return string */ public function getDescription() { return $this->description; } /** * Checks whether the given option equals this one. * * @return bool */ public function equals(self $option) { return $option->getName() === $this->getName() && $option->getShortcut() === $this->getShortcut() && $option->getDefault() === $this->getDefault() && $option->isNegatable() === $this->isNegatable() && $option->isArray() === $this->isArray() && $option->isValueRequired() === $this->isValueRequired() && $option->isValueOptional() === $this->isValueOptional(); } } * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace _HumbugBox7ff99e199a36\Symfony\Component\Console\Input; use _HumbugBox7ff99e199a36\Symfony\Component\Console\Exception\RuntimeException; /** * ArgvInput represents an input coming from the CLI arguments. * * Usage: * * $input = new ArgvInput(); * * By default, the `$_SERVER['argv']` array is used for the input values. * * This can be overridden by explicitly passing the input values in the constructor: * * $input = new ArgvInput($_SERVER['argv']); * * If you pass it yourself, don't forget that the first element of the array * is the name of the running application. * * When passing an argument to the constructor, be sure that it respects * the same rules as the argv one. It's almost always better to use the * `StringInput` when you want to provide your own input. * * @author Fabien Potencier * * @see http://www.gnu.org/software/libc/manual/html_node/Argument-Syntax.html * @see http://www.opengroup.org/onlinepubs/009695399/basedefs/xbd_chap12.html#tag_12_02 */ class ArgvInput extends Input { private $tokens; private $parsed; public function __construct(?array $argv = null, ?InputDefinition $definition = null) { $argv = $argv ?? $_SERVER['argv'] ?? []; // strip the application name \array_shift($argv); $this->tokens = $argv; parent::__construct($definition); } protected function setTokens(array $tokens) { $this->tokens = $tokens; } /** * {@inheritdoc} */ protected function parse() { $parseOptions = \true; $this->parsed = $this->tokens; while (null !== ($token = \array_shift($this->parsed))) { $parseOptions = $this->parseToken($token, $parseOptions); } } protected function parseToken(string $token, bool $parseOptions) : bool { if ($parseOptions && '' == $token) { $this->parseArgument($token); } elseif ($parseOptions && '--' == $token) { return \false; } elseif ($parseOptions && \str_starts_with($token, '--')) { $this->parseLongOption($token); } elseif ($parseOptions && '-' === $token[0] && '-' !== $token) { $this->parseShortOption($token); } else { $this->parseArgument($token); } return $parseOptions; } /** * Parses a short option. */ private function parseShortOption(string $token) { $name = \substr($token, 1); if (\strlen($name) > 1) { if ($this->definition->hasShortcut($name[0]) && $this->definition->getOptionForShortcut($name[0])->acceptValue()) { // an option with a value (with no space) $this->addShortOption($name[0], \substr($name, 1)); } else { $this->parseShortOptionSet($name); } } else { $this->addShortOption($name, null); } } /** * Parses a short option set. * * @throws RuntimeException When option given doesn't exist */ private function parseShortOptionSet(string $name) { $len = \strlen($name); for ($i = 0; $i < $len; ++$i) { if (!$this->definition->hasShortcut($name[$i])) { $encoding = \mb_detect_encoding($name, null, \true); throw new RuntimeException(\sprintf('The "-%s" option does not exist.', \false === $encoding ? $name[$i] : \mb_substr($name, $i, 1, $encoding))); } $option = $this->definition->getOptionForShortcut($name[$i]); if ($option->acceptValue()) { $this->addLongOption($option->getName(), $i === $len - 1 ? null : \substr($name, $i + 1)); break; } else { $this->addLongOption($option->getName(), null); } } } /** * Parses a long option. */ private function parseLongOption(string $token) { $name = \substr($token, 2); if (\false !== ($pos = \strpos($name, '='))) { if ('' === ($value = \substr($name, $pos + 1))) { \array_unshift($this->parsed, $value); } $this->addLongOption(\substr($name, 0, $pos), $value); } else { $this->addLongOption($name, null); } } /** * Parses an argument. * * @throws RuntimeException When too many arguments are given */ private function parseArgument(string $token) { $c = \count($this->arguments); // if input is expecting another argument, add it if ($this->definition->hasArgument($c)) { $arg = $this->definition->getArgument($c); $this->arguments[$arg->getName()] = $arg->isArray() ? [$token] : $token; // if last argument isArray(), append token to last argument } elseif ($this->definition->hasArgument($c - 1) && $this->definition->getArgument($c - 1)->isArray()) { $arg = $this->definition->getArgument($c - 1); $this->arguments[$arg->getName()][] = $token; // unexpected argument } else { $all = $this->definition->getArguments(); $symfonyCommandName = null; if (($inputArgument = $all[$key = \array_key_first($all)] ?? null) && 'command' === $inputArgument->getName()) { $symfonyCommandName = $this->arguments['command'] ?? null; unset($all[$key]); } if (\count($all)) { if ($symfonyCommandName) { $message = \sprintf('Too many arguments to "%s" command, expected arguments "%s".', $symfonyCommandName, \implode('" "', \array_keys($all))); } else { $message = \sprintf('Too many arguments, expected arguments "%s".', \implode('" "', \array_keys($all))); } } elseif ($symfonyCommandName) { $message = \sprintf('No arguments expected for "%s" command, got "%s".', $symfonyCommandName, $token); } else { $message = \sprintf('No arguments expected, got "%s".', $token); } throw new RuntimeException($message); } } /** * Adds a short option value. * * @throws RuntimeException When option given doesn't exist */ private function addShortOption(string $shortcut, $value) { if (!$this->definition->hasShortcut($shortcut)) { throw new RuntimeException(\sprintf('The "-%s" option does not exist.', $shortcut)); } $this->addLongOption($this->definition->getOptionForShortcut($shortcut)->getName(), $value); } /** * Adds a long option value. * * @throws RuntimeException When option given doesn't exist */ private function addLongOption(string $name, $value) { if (!$this->definition->hasOption($name)) { if (!$this->definition->hasNegation($name)) { throw new RuntimeException(\sprintf('The "--%s" option does not exist.', $name)); } $optionName = $this->definition->negationToName($name); if (null !== $value) { throw new RuntimeException(\sprintf('The "--%s" option does not accept a value.', $name)); } $this->options[$optionName] = \false; return; } $option = $this->definition->getOption($name); if (null !== $value && !$option->acceptValue()) { throw new RuntimeException(\sprintf('The "--%s" option does not accept a value.', $name)); } if (\in_array($value, ['', null], \true) && $option->acceptValue() && \count($this->parsed)) { // if option accepts an optional or mandatory argument // let's see if there is one provided $next = \array_shift($this->parsed); if (isset($next[0]) && '-' !== $next[0] || \in_array($next, ['', null], \true)) { $value = $next; } else { \array_unshift($this->parsed, $next); } } if (null === $value) { if ($option->isValueRequired()) { throw new RuntimeException(\sprintf('The "--%s" option requires a value.', $name)); } if (!$option->isArray() && !$option->isValueOptional()) { $value = \true; } } if ($option->isArray()) { $this->options[$name][] = $value; } else { $this->options[$name] = $value; } } /** * {@inheritdoc} */ public function getFirstArgument() { $isOption = \false; foreach ($this->tokens as $i => $token) { if ($token && '-' === $token[0]) { if (\str_contains($token, '=') || !isset($this->tokens[$i + 1])) { continue; } // If it's a long option, consider that everything after "--" is the option name. // Otherwise, use the last char (if it's a short option set, only the last one can take a value with space separator) $name = '-' === $token[1] ? \substr($token, 2) : \substr($token, -1); if (!isset($this->options[$name]) && !$this->definition->hasShortcut($name)) { // noop } elseif ((isset($this->options[$name]) || isset($this->options[$name = $this->definition->shortcutToName($name)])) && $this->tokens[$i + 1] === $this->options[$name]) { $isOption = \true; } continue; } if ($isOption) { $isOption = \false; continue; } return $token; } return null; } /** * {@inheritdoc} */ public function hasParameterOption($values, bool $onlyParams = \false) { $values = (array) $values; foreach ($this->tokens as $token) { if ($onlyParams && '--' === $token) { return \false; } foreach ($values as $value) { // Options with values: // For long options, test for '--option=' at beginning // For short options, test for '-o' at beginning $leading = \str_starts_with($value, '--') ? $value . '=' : $value; if ($token === $value || '' !== $leading && \str_starts_with($token, $leading)) { return \true; } } } return \false; } /** * {@inheritdoc} */ public function getParameterOption($values, $default = \false, bool $onlyParams = \false) { $values = (array) $values; $tokens = $this->tokens; while (0 < \count($tokens)) { $token = \array_shift($tokens); if ($onlyParams && '--' === $token) { return $default; } foreach ($values as $value) { if ($token === $value) { return \array_shift($tokens); } // Options with values: // For long options, test for '--option=' at beginning // For short options, test for '-o' at beginning $leading = \str_starts_with($value, '--') ? $value . '=' : $value; if ('' !== $leading && \str_starts_with($token, $leading)) { return \substr($token, \strlen($leading)); } } } return $default; } /** * Returns a stringified representation of the args passed to the command. * * @return string */ public function __toString() { $tokens = \array_map(function ($token) { if (\preg_match('{^(-[^=]+=)(.+)}', $token, $match)) { return $match[1] . $this->escapeToken($match[2]); } if ($token && '-' !== $token[0]) { return $this->escapeToken($token); } return $token; }, $this->tokens); return \implode(' ', $tokens); } } * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace _HumbugBox7ff99e199a36\Symfony\Component\Console\Input; /** * InputAwareInterface should be implemented by classes that depends on the * Console Input. * * @author Wouter J */ interface InputAwareInterface { /** * Sets the Console Input. */ public function setInput(InputInterface $input); } * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace _HumbugBox7ff99e199a36\Symfony\Component\Console\Input; use _HumbugBox7ff99e199a36\Symfony\Component\Console\Exception\InvalidArgumentException; /** * StringInput represents an input provided as a string. * * Usage: * * $input = new StringInput('foo --bar="foobar"'); * * @author Fabien Potencier */ class StringInput extends ArgvInput { public const REGEX_STRING = '([^\\s]+?)(?:\\s|(?setTokens($this->tokenize($input)); } /** * Tokenizes a string. * * @throws InvalidArgumentException When unable to parse input (should never happen) */ private function tokenize(string $input) : array { $tokens = []; $length = \strlen($input); $cursor = 0; $token = null; while ($cursor < $length) { if ('\\' === $input[$cursor]) { $token .= $input[++$cursor] ?? ''; ++$cursor; continue; } if (\preg_match('/\\s+/A', $input, $match, 0, $cursor)) { if (null !== $token) { $tokens[] = $token; $token = null; } } elseif (\preg_match('/([^="\'\\s]+?)(=?)(' . self::REGEX_QUOTED_STRING . '+)/A', $input, $match, 0, $cursor)) { $token .= $match[1] . $match[2] . \stripcslashes(\str_replace(['"\'', '\'"', '\'\'', '""'], '', \substr($match[3], 1, -1))); } elseif (\preg_match('/' . self::REGEX_QUOTED_STRING . '/A', $input, $match, 0, $cursor)) { $token .= \stripcslashes(\substr($match[0], 1, -1)); } elseif (\preg_match('/' . self::REGEX_UNQUOTED_STRING . '/A', $input, $match, 0, $cursor)) { $token .= $match[1]; } else { // should never happen throw new InvalidArgumentException(\sprintf('Unable to parse input near "... %s ...".', \substr($input, $cursor, 10))); } $cursor += \strlen($match[0]); } if (null !== $token) { $tokens[] = $token; } return $tokens; } } * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace _HumbugBox7ff99e199a36\Symfony\Component\Console\Input; use _HumbugBox7ff99e199a36\Symfony\Component\Console\Exception\InvalidArgumentException; use _HumbugBox7ff99e199a36\Symfony\Component\Console\Exception\RuntimeException; /** * Input is the base class for all concrete Input classes. * * Three concrete classes are provided by default: * * * `ArgvInput`: The input comes from the CLI arguments (argv) * * `StringInput`: The input is provided as a string * * `ArrayInput`: The input is provided as an array * * @author Fabien Potencier */ abstract class Input implements InputInterface, StreamableInputInterface { protected $definition; protected $stream; protected $options = []; protected $arguments = []; protected $interactive = \true; public function __construct(?InputDefinition $definition = null) { if (null === $definition) { $this->definition = new InputDefinition(); } else { $this->bind($definition); $this->validate(); } } /** * {@inheritdoc} */ public function bind(InputDefinition $definition) { $this->arguments = []; $this->options = []; $this->definition = $definition; $this->parse(); } /** * Processes command line arguments. */ protected abstract function parse(); /** * {@inheritdoc} */ public function validate() { $definition = $this->definition; $givenArguments = $this->arguments; $missingArguments = \array_filter(\array_keys($definition->getArguments()), function ($argument) use($definition, $givenArguments) { return !\array_key_exists($argument, $givenArguments) && $definition->getArgument($argument)->isRequired(); }); if (\count($missingArguments) > 0) { throw new RuntimeException(\sprintf('Not enough arguments (missing: "%s").', \implode(', ', $missingArguments))); } } /** * {@inheritdoc} */ public function isInteractive() { return $this->interactive; } /** * {@inheritdoc} */ public function setInteractive(bool $interactive) { $this->interactive = $interactive; } /** * {@inheritdoc} */ public function getArguments() { return \array_merge($this->definition->getArgumentDefaults(), $this->arguments); } /** * {@inheritdoc} */ public function getArgument(string $name) { if (!$this->definition->hasArgument($name)) { throw new InvalidArgumentException(\sprintf('The "%s" argument does not exist.', $name)); } return $this->arguments[$name] ?? $this->definition->getArgument($name)->getDefault(); } /** * {@inheritdoc} */ public function setArgument(string $name, $value) { if (!$this->definition->hasArgument($name)) { throw new InvalidArgumentException(\sprintf('The "%s" argument does not exist.', $name)); } $this->arguments[$name] = $value; } /** * {@inheritdoc} */ public function hasArgument(string $name) { return $this->definition->hasArgument($name); } /** * {@inheritdoc} */ public function getOptions() { return \array_merge($this->definition->getOptionDefaults(), $this->options); } /** * {@inheritdoc} */ public function getOption(string $name) { if ($this->definition->hasNegation($name)) { if (null === ($value = $this->getOption($this->definition->negationToName($name)))) { return $value; } return !$value; } if (!$this->definition->hasOption($name)) { throw new InvalidArgumentException(\sprintf('The "%s" option does not exist.', $name)); } return \array_key_exists($name, $this->options) ? $this->options[$name] : $this->definition->getOption($name)->getDefault(); } /** * {@inheritdoc} */ public function setOption(string $name, $value) { if ($this->definition->hasNegation($name)) { $this->options[$this->definition->negationToName($name)] = !$value; return; } elseif (!$this->definition->hasOption($name)) { throw new InvalidArgumentException(\sprintf('The "%s" option does not exist.', $name)); } $this->options[$name] = $value; } /** * {@inheritdoc} */ public function hasOption(string $name) { return $this->definition->hasOption($name) || $this->definition->hasNegation($name); } /** * Escapes a token through escapeshellarg if it contains unsafe chars. * * @return string */ public function escapeToken(string $token) { return \preg_match('{^[\\w-]+$}', $token) ? $token : \escapeshellarg($token); } /** * {@inheritdoc} */ public function setStream($stream) { $this->stream = $stream; } /** * {@inheritdoc} */ public function getStream() { return $this->stream; } } * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace _HumbugBox7ff99e199a36\Symfony\Component\Console\Input; /** * StreamableInputInterface is the interface implemented by all input classes * that have an input stream. * * @author Robin Chalas */ interface StreamableInputInterface extends InputInterface { /** * Sets the input stream to read from when interacting with the user. * * This is mainly useful for testing purpose. * * @param resource $stream The input stream */ public function setStream($stream); /** * Returns the input stream. * * @return resource|null */ public function getStream(); } * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace _HumbugBox7ff99e199a36\Symfony\Component\Console\Input; use _HumbugBox7ff99e199a36\Symfony\Component\Console\Exception\InvalidArgumentException; use _HumbugBox7ff99e199a36\Symfony\Component\Console\Exception\RuntimeException; /** * InputInterface is the interface implemented by all input classes. * * @author Fabien Potencier */ interface InputInterface { /** * Returns the first argument from the raw parameters (not parsed). * * @return string|null */ public function getFirstArgument(); /** * Returns true if the raw parameters (not parsed) contain a value. * * This method is to be used to introspect the input parameters * before they have been validated. It must be used carefully. * Does not necessarily return the correct result for short options * when multiple flags are combined in the same option. * * @param string|array $values The values to look for in the raw parameters (can be an array) * @param bool $onlyParams Only check real parameters, skip those following an end of options (--) signal * * @return bool */ public function hasParameterOption($values, bool $onlyParams = \false); /** * Returns the value of a raw option (not parsed). * * This method is to be used to introspect the input parameters * before they have been validated. It must be used carefully. * Does not necessarily return the correct result for short options * when multiple flags are combined in the same option. * * @param string|array $values The value(s) to look for in the raw parameters (can be an array) * @param string|bool|int|float|array|null $default The default value to return if no result is found * @param bool $onlyParams Only check real parameters, skip those following an end of options (--) signal * * @return mixed */ public function getParameterOption($values, $default = \false, bool $onlyParams = \false); /** * Binds the current Input instance with the given arguments and options. * * @throws RuntimeException */ public function bind(InputDefinition $definition); /** * Validates the input. * * @throws RuntimeException When not enough arguments are given */ public function validate(); /** * Returns all the given arguments merged with the default values. * * @return array */ public function getArguments(); /** * Returns the argument value for a given argument name. * * @return mixed * * @throws InvalidArgumentException When argument given doesn't exist */ public function getArgument(string $name); /** * Sets an argument value by name. * * @param mixed $value The argument value * * @throws InvalidArgumentException When argument given doesn't exist */ public function setArgument(string $name, $value); /** * Returns true if an InputArgument object exists by name or position. * * @return bool */ public function hasArgument(string $name); /** * Returns all the given options merged with the default values. * * @return array */ public function getOptions(); /** * Returns the option value for a given option name. * * @return mixed * * @throws InvalidArgumentException When option given doesn't exist */ public function getOption(string $name); /** * Sets an option value by name. * * @param mixed $value The option value * * @throws InvalidArgumentException When option given doesn't exist */ public function setOption(string $name, $value); /** * Returns true if an InputOption object exists by name. * * @return bool */ public function hasOption(string $name); /** * Is this input means interactive? * * @return bool */ public function isInteractive(); /** * Sets the input interactivity. */ public function setInteractive(bool $interactive); } * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace _HumbugBox7ff99e199a36\Symfony\Component\Console\Event; use _HumbugBox7ff99e199a36\Symfony\Component\Console\Command\Command; use _HumbugBox7ff99e199a36\Symfony\Component\Console\Input\InputInterface; use _HumbugBox7ff99e199a36\Symfony\Component\Console\Output\OutputInterface; /** * @author marie */ final class ConsoleSignalEvent extends ConsoleEvent { private $handlingSignal; public function __construct(Command $command, InputInterface $input, OutputInterface $output, int $handlingSignal) { parent::__construct($command, $input, $output); $this->handlingSignal = $handlingSignal; } public function getHandlingSignal() : int { return $this->handlingSignal; } } * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace _HumbugBox7ff99e199a36\Symfony\Component\Console\Event; use _HumbugBox7ff99e199a36\Symfony\Component\Console\Command\Command; use _HumbugBox7ff99e199a36\Symfony\Component\Console\Input\InputInterface; use _HumbugBox7ff99e199a36\Symfony\Component\Console\Output\OutputInterface; /** * Allows to manipulate the exit code of a command after its execution. * * @author Francesco Levorato */ final class ConsoleTerminateEvent extends ConsoleEvent { private $exitCode; public function __construct(Command $command, InputInterface $input, OutputInterface $output, int $exitCode) { parent::__construct($command, $input, $output); $this->setExitCode($exitCode); } public function setExitCode(int $exitCode) : void { $this->exitCode = $exitCode; } public function getExitCode() : int { return $this->exitCode; } } * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace _HumbugBox7ff99e199a36\Symfony\Component\Console\Event; /** * Allows to do things before the command is executed, like skipping the command or executing code before the command is * going to be executed. * * Changing the input arguments will have no effect. * * @author Fabien Potencier */ final class ConsoleCommandEvent extends ConsoleEvent { /** * The return code for skipped commands, this will also be passed into the terminate event. */ public const RETURN_CODE_DISABLED = 113; /** * Indicates if the command should be run or skipped. */ private $commandShouldRun = \true; /** * Disables the command, so it won't be run. */ public function disableCommand() : bool { return $this->commandShouldRun = \false; } public function enableCommand() : bool { return $this->commandShouldRun = \true; } /** * Returns true if the command is runnable, false otherwise. */ public function commandShouldRun() : bool { return $this->commandShouldRun; } } * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace _HumbugBox7ff99e199a36\Symfony\Component\Console\Event; use _HumbugBox7ff99e199a36\Symfony\Component\Console\Command\Command; use _HumbugBox7ff99e199a36\Symfony\Component\Console\Input\InputInterface; use _HumbugBox7ff99e199a36\Symfony\Component\Console\Output\OutputInterface; /** * Allows to handle throwables thrown while running a command. * * @author Wouter de Jong */ final class ConsoleErrorEvent extends ConsoleEvent { private $error; private $exitCode; public function __construct(InputInterface $input, OutputInterface $output, \Throwable $error, ?Command $command = null) { parent::__construct($command, $input, $output); $this->error = $error; } public function getError() : \Throwable { return $this->error; } public function setError(\Throwable $error) : void { $this->error = $error; } public function setExitCode(int $exitCode) : void { $this->exitCode = $exitCode; $r = new \ReflectionProperty($this->error, 'code'); $r->setAccessible(\true); $r->setValue($this->error, $this->exitCode); } public function getExitCode() : int { return $this->exitCode ?? (\is_int($this->error->getCode()) && 0 !== $this->error->getCode() ? $this->error->getCode() : 1); } } * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace _HumbugBox7ff99e199a36\Symfony\Component\Console\Event; use _HumbugBox7ff99e199a36\Symfony\Component\Console\Command\Command; use _HumbugBox7ff99e199a36\Symfony\Component\Console\Input\InputInterface; use _HumbugBox7ff99e199a36\Symfony\Component\Console\Output\OutputInterface; use _HumbugBox7ff99e199a36\Symfony\Contracts\EventDispatcher\Event; /** * Allows to inspect input and output of a command. * * @author Francesco Levorato */ class ConsoleEvent extends Event { protected $command; private $input; private $output; public function __construct(?Command $command, InputInterface $input, OutputInterface $output) { $this->command = $command; $this->input = $input; $this->output = $output; } /** * Gets the command that is executed. * * @return Command|null */ public function getCommand() { return $this->command; } /** * Gets the input instance. * * @return InputInterface */ public function getInput() { return $this->input; } /** * Gets the output instance. * * @return OutputInterface */ public function getOutput() { return $this->output; } } * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace _HumbugBox7ff99e199a36\Symfony\Component\Console\DependencyInjection; use _HumbugBox7ff99e199a36\Symfony\Component\Console\Command\Command; use _HumbugBox7ff99e199a36\Symfony\Component\Console\Command\LazyCommand; use _HumbugBox7ff99e199a36\Symfony\Component\Console\CommandLoader\ContainerCommandLoader; use _HumbugBox7ff99e199a36\Symfony\Component\DependencyInjection\Argument\ServiceClosureArgument; use _HumbugBox7ff99e199a36\Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface; use _HumbugBox7ff99e199a36\Symfony\Component\DependencyInjection\Compiler\ServiceLocatorTagPass; use _HumbugBox7ff99e199a36\Symfony\Component\DependencyInjection\ContainerBuilder; use _HumbugBox7ff99e199a36\Symfony\Component\DependencyInjection\Exception\InvalidArgumentException; use _HumbugBox7ff99e199a36\Symfony\Component\DependencyInjection\Reference; use _HumbugBox7ff99e199a36\Symfony\Component\DependencyInjection\TypedReference; /** * Registers console commands. * * @author Grégoire Pineau */ class AddConsoleCommandPass implements CompilerPassInterface { private $commandLoaderServiceId; private $commandTag; private $noPreloadTag; private $privateTagName; public function __construct(string $commandLoaderServiceId = 'console.command_loader', string $commandTag = 'console.command', string $noPreloadTag = 'container.no_preload', string $privateTagName = 'container.private') { if (0 < \func_num_args()) { trigger_deprecation('symfony/console', '5.3', 'Configuring "%s" is deprecated.', __CLASS__); } $this->commandLoaderServiceId = $commandLoaderServiceId; $this->commandTag = $commandTag; $this->noPreloadTag = $noPreloadTag; $this->privateTagName = $privateTagName; } public function process(ContainerBuilder $container) { $commandServices = $container->findTaggedServiceIds($this->commandTag, \true); $lazyCommandMap = []; $lazyCommandRefs = []; $serviceIds = []; foreach ($commandServices as $id => $tags) { $definition = $container->getDefinition($id); $definition->addTag($this->noPreloadTag); $class = $container->getParameterBag()->resolveValue($definition->getClass()); if (isset($tags[0]['command'])) { $aliases = $tags[0]['command']; } else { if (!($r = $container->getReflectionClass($class))) { throw new InvalidArgumentException(\sprintf('Class "%s" used for service "%s" cannot be found.', $class, $id)); } if (!$r->isSubclassOf(Command::class)) { throw new InvalidArgumentException(\sprintf('The service "%s" tagged "%s" must be a subclass of "%s".', $id, $this->commandTag, Command::class)); } $aliases = \str_replace('%', '%%', $class::getDefaultName() ?? ''); } $aliases = \explode('|', $aliases ?? ''); $commandName = \array_shift($aliases); if ($isHidden = '' === $commandName) { $commandName = \array_shift($aliases); } if (null === $commandName) { if (!$definition->isPublic() || $definition->isPrivate() || $definition->hasTag($this->privateTagName)) { $commandId = 'console.command.public_alias.' . $id; $container->setAlias($commandId, $id)->setPublic(\true); $id = $commandId; } $serviceIds[] = $id; continue; } $description = $tags[0]['description'] ?? null; unset($tags[0]); $lazyCommandMap[$commandName] = $id; $lazyCommandRefs[$id] = new TypedReference($id, $class); foreach ($aliases as $alias) { $lazyCommandMap[$alias] = $id; } foreach ($tags as $tag) { if (isset($tag['command'])) { $aliases[] = $tag['command']; $lazyCommandMap[$tag['command']] = $id; } $description = $description ?? $tag['description'] ?? null; } $definition->addMethodCall('setName', [$commandName]); if ($aliases) { $definition->addMethodCall('setAliases', [$aliases]); } if ($isHidden) { $definition->addMethodCall('setHidden', [\true]); } if (!$description) { if (!($r = $container->getReflectionClass($class))) { throw new InvalidArgumentException(\sprintf('Class "%s" used for service "%s" cannot be found.', $class, $id)); } if (!$r->isSubclassOf(Command::class)) { throw new InvalidArgumentException(\sprintf('The service "%s" tagged "%s" must be a subclass of "%s".', $id, $this->commandTag, Command::class)); } $description = \str_replace('%', '%%', $class::getDefaultDescription() ?? ''); } if ($description) { $definition->addMethodCall('setDescription', [$description]); $container->register('.' . $id . '.lazy', LazyCommand::class)->setArguments([$commandName, $aliases, $description, $isHidden, new ServiceClosureArgument($lazyCommandRefs[$id])]); $lazyCommandRefs[$id] = new Reference('.' . $id . '.lazy'); } } $container->register($this->commandLoaderServiceId, ContainerCommandLoader::class)->setPublic(\true)->addTag($this->noPreloadTag)->setArguments([ServiceLocatorTagPass::register($container, $lazyCommandRefs), $lazyCommandMap]); $container->setParameter('console.command.ids', $serviceIds); } } * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace _HumbugBox7ff99e199a36\Symfony\Component\Console\Question; /** * Represents a yes/no question. * * @author Fabien Potencier */ class ConfirmationQuestion extends Question { private $trueAnswerRegex; /** * @param string $question The question to ask to the user * @param bool $default The default answer to return, true or false * @param string $trueAnswerRegex A regex to match the "yes" answer */ public function __construct(string $question, bool $default = \true, string $trueAnswerRegex = '/^y/i') { parent::__construct($question, $default); $this->trueAnswerRegex = $trueAnswerRegex; $this->setNormalizer($this->getDefaultNormalizer()); } /** * Returns the default answer normalizer. */ private function getDefaultNormalizer() : callable { $default = $this->getDefault(); $regex = $this->trueAnswerRegex; return function ($answer) use($default, $regex) { if (\is_bool($answer)) { return $answer; } $answerIsTrue = (bool) \preg_match($regex, $answer); if (\false === $default) { return $answer && $answerIsTrue; } return '' === $answer || $answerIsTrue; }; } } * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace _HumbugBox7ff99e199a36\Symfony\Component\Console\Question; use _HumbugBox7ff99e199a36\Symfony\Component\Console\Exception\InvalidArgumentException; use _HumbugBox7ff99e199a36\Symfony\Component\Console\Exception\LogicException; /** * Represents a Question. * * @author Fabien Potencier */ class Question { private $question; private $attempts; private $hidden = \false; private $hiddenFallback = \true; private $autocompleterCallback; private $validator; private $default; private $normalizer; private $trimmable = \true; private $multiline = \false; /** * @param string $question The question to ask to the user * @param string|bool|int|float|null $default The default answer to return if the user enters nothing */ public function __construct(string $question, $default = null) { $this->question = $question; $this->default = $default; } /** * Returns the question. * * @return string */ public function getQuestion() { return $this->question; } /** * Returns the default answer. * * @return string|bool|int|float|null */ public function getDefault() { return $this->default; } /** * Returns whether the user response accepts newline characters. */ public function isMultiline() : bool { return $this->multiline; } /** * Sets whether the user response should accept newline characters. * * @return $this */ public function setMultiline(bool $multiline) : self { $this->multiline = $multiline; return $this; } /** * Returns whether the user response must be hidden. * * @return bool */ public function isHidden() { return $this->hidden; } /** * Sets whether the user response must be hidden or not. * * @return $this * * @throws LogicException In case the autocompleter is also used */ public function setHidden(bool $hidden) { if ($this->autocompleterCallback) { throw new LogicException('A hidden question cannot use the autocompleter.'); } $this->hidden = $hidden; return $this; } /** * In case the response cannot be hidden, whether to fallback on non-hidden question or not. * * @return bool */ public function isHiddenFallback() { return $this->hiddenFallback; } /** * Sets whether to fallback on non-hidden question if the response cannot be hidden. * * @return $this */ public function setHiddenFallback(bool $fallback) { $this->hiddenFallback = $fallback; return $this; } /** * Gets values for the autocompleter. * * @return iterable|null */ public function getAutocompleterValues() { $callback = $this->getAutocompleterCallback(); return $callback ? $callback('') : null; } /** * Sets values for the autocompleter. * * @return $this * * @throws LogicException */ public function setAutocompleterValues(?iterable $values) { if (\is_array($values)) { $values = $this->isAssoc($values) ? \array_merge(\array_keys($values), \array_values($values)) : \array_values($values); $callback = static function () use($values) { return $values; }; } elseif ($values instanceof \Traversable) { $valueCache = null; $callback = static function () use($values, &$valueCache) { return $valueCache ?? ($valueCache = \iterator_to_array($values, \false)); }; } else { $callback = null; } return $this->setAutocompleterCallback($callback); } /** * Gets the callback function used for the autocompleter. */ public function getAutocompleterCallback() : ?callable { return $this->autocompleterCallback; } /** * Sets the callback function used for the autocompleter. * * The callback is passed the user input as argument and should return an iterable of corresponding suggestions. * * @return $this */ public function setAutocompleterCallback(?callable $callback = null) : self { if ($this->hidden && null !== $callback) { throw new LogicException('A hidden question cannot use the autocompleter.'); } $this->autocompleterCallback = $callback; return $this; } /** * Sets a validator for the question. * * @return $this */ public function setValidator(?callable $validator = null) { $this->validator = $validator; return $this; } /** * Gets the validator for the question. * * @return callable|null */ public function getValidator() { return $this->validator; } /** * Sets the maximum number of attempts. * * Null means an unlimited number of attempts. * * @return $this * * @throws InvalidArgumentException in case the number of attempts is invalid */ public function setMaxAttempts(?int $attempts) { if (null !== $attempts && $attempts < 1) { throw new InvalidArgumentException('Maximum number of attempts must be a positive value.'); } $this->attempts = $attempts; return $this; } /** * Gets the maximum number of attempts. * * Null means an unlimited number of attempts. * * @return int|null */ public function getMaxAttempts() { return $this->attempts; } /** * Sets a normalizer for the response. * * The normalizer can be a callable (a string), a closure or a class implementing __invoke. * * @return $this */ public function setNormalizer(callable $normalizer) { $this->normalizer = $normalizer; return $this; } /** * Gets the normalizer for the response. * * The normalizer can ba a callable (a string), a closure or a class implementing __invoke. * * @return callable|null */ public function getNormalizer() { return $this->normalizer; } protected function isAssoc(array $array) { return (bool) \count(\array_filter(\array_keys($array), 'is_string')); } public function isTrimmable() : bool { return $this->trimmable; } /** * @return $this */ public function setTrimmable(bool $trimmable) : self { $this->trimmable = $trimmable; return $this; } } * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace _HumbugBox7ff99e199a36\Symfony\Component\Console\Question; use _HumbugBox7ff99e199a36\Symfony\Component\Console\Exception\InvalidArgumentException; /** * Represents a choice question. * * @author Fabien Potencier */ class ChoiceQuestion extends Question { private $choices; private $multiselect = \false; private $prompt = ' > '; private $errorMessage = 'Value "%s" is invalid'; /** * @param string $question The question to ask to the user * @param array $choices The list of available choices * @param mixed $default The default answer to return */ public function __construct(string $question, array $choices, $default = null) { if (!$choices) { throw new \LogicException('Choice question must have at least 1 choice available.'); } parent::__construct($question, $default); $this->choices = $choices; $this->setValidator($this->getDefaultValidator()); $this->setAutocompleterValues($choices); } /** * Returns available choices. * * @return array */ public function getChoices() { return $this->choices; } /** * Sets multiselect option. * * When multiselect is set to true, multiple choices can be answered. * * @return $this */ public function setMultiselect(bool $multiselect) { $this->multiselect = $multiselect; $this->setValidator($this->getDefaultValidator()); return $this; } /** * Returns whether the choices are multiselect. * * @return bool */ public function isMultiselect() { return $this->multiselect; } /** * Gets the prompt for choices. * * @return string */ public function getPrompt() { return $this->prompt; } /** * Sets the prompt for choices. * * @return $this */ public function setPrompt(string $prompt) { $this->prompt = $prompt; return $this; } /** * Sets the error message for invalid values. * * The error message has a string placeholder (%s) for the invalid value. * * @return $this */ public function setErrorMessage(string $errorMessage) { $this->errorMessage = $errorMessage; $this->setValidator($this->getDefaultValidator()); return $this; } private function getDefaultValidator() : callable { $choices = $this->choices; $errorMessage = $this->errorMessage; $multiselect = $this->multiselect; $isAssoc = $this->isAssoc($choices); return function ($selected) use($choices, $errorMessage, $multiselect, $isAssoc) { if ($multiselect) { // Check for a separated comma values if (!\preg_match('/^[^,]+(?:,[^,]+)*$/', (string) $selected, $matches)) { throw new InvalidArgumentException(\sprintf($errorMessage, $selected)); } $selectedChoices = \explode(',', (string) $selected); } else { $selectedChoices = [$selected]; } if ($this->isTrimmable()) { foreach ($selectedChoices as $k => $v) { $selectedChoices[$k] = \trim((string) $v); } } $multiselectChoices = []; foreach ($selectedChoices as $value) { $results = []; foreach ($choices as $key => $choice) { if ($choice === $value) { $results[] = $key; } } if (\count($results) > 1) { throw new InvalidArgumentException(\sprintf('The provided answer is ambiguous. Value should be one of "%s".', \implode('" or "', $results))); } $result = \array_search($value, $choices); if (!$isAssoc) { if (\false !== $result) { $result = $choices[$result]; } elseif (isset($choices[$value])) { $result = $choices[$value]; } } elseif (\false === $result && isset($choices[$value])) { $result = $value; } if (\false === $result) { throw new InvalidArgumentException(\sprintf($errorMessage, $value)); } // For associative choices, consistently return the key as string: $multiselectChoices[] = $isAssoc ? (string) $result : $result; } if ($multiselect) { return $multiselectChoices; } return \current($multiselectChoices); }; } } * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace _HumbugBox7ff99e199a36\Symfony\Component\Console\Exception; /** * Represents an incorrect option name or value typed in the console. * * @author Jérôme Tamarelle */ class InvalidOptionException extends \InvalidArgumentException implements ExceptionInterface { } * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace _HumbugBox7ff99e199a36\Symfony\Component\Console\Exception; /** * ExceptionInterface. * * @author Jérôme Tamarelle */ interface ExceptionInterface extends \Throwable { } * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace _HumbugBox7ff99e199a36\Symfony\Component\Console\Exception; /** * @author Jérôme Tamarelle */ class LogicException extends \LogicException implements ExceptionInterface { } * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace _HumbugBox7ff99e199a36\Symfony\Component\Console\Exception; /** * Represents an incorrect namespace typed in the console. * * @author Pierre du Plessis */ class NamespaceNotFoundException extends CommandNotFoundException { } * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace _HumbugBox7ff99e199a36\Symfony\Component\Console\Exception; /** * Represents failure to read input from stdin. * * @author Gabriel Ostrolucký */ class MissingInputException extends RuntimeException implements ExceptionInterface { } * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace _HumbugBox7ff99e199a36\Symfony\Component\Console\Exception; /** * Represents an incorrect command name typed in the console. * * @author Jérôme Tamarelle */ class CommandNotFoundException extends \InvalidArgumentException implements ExceptionInterface { private $alternatives; /** * @param string $message Exception message to throw * @param string[] $alternatives List of similar defined names * @param int $code Exception code * @param \Throwable|null $previous Previous exception used for the exception chaining */ public function __construct(string $message, array $alternatives = [], int $code = 0, ?\Throwable $previous = null) { parent::__construct($message, $code, $previous); $this->alternatives = $alternatives; } /** * @return string[] */ public function getAlternatives() { return $this->alternatives; } } * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace _HumbugBox7ff99e199a36\Symfony\Component\Console\Exception; /** * @author Jérôme Tamarelle */ class RuntimeException extends \RuntimeException implements ExceptionInterface { } * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace _HumbugBox7ff99e199a36\Symfony\Component\Console\Exception; /** * @author Jérôme Tamarelle */ class InvalidArgumentException extends \InvalidArgumentException implements ExceptionInterface { } * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace _HumbugBox7ff99e199a36\Symfony\Component\Console; use _HumbugBox7ff99e199a36\Symfony\Component\Console\Event\ConsoleCommandEvent; use _HumbugBox7ff99e199a36\Symfony\Component\Console\Event\ConsoleErrorEvent; use _HumbugBox7ff99e199a36\Symfony\Component\Console\Event\ConsoleSignalEvent; use _HumbugBox7ff99e199a36\Symfony\Component\Console\Event\ConsoleTerminateEvent; /** * Contains all events dispatched by an Application. * * @author Francesco Levorato */ final class ConsoleEvents { /** * The COMMAND event allows you to attach listeners before any command is * executed by the console. It also allows you to modify the command, input and output * before they are handed to the command. * * @Event("Symfony\Component\Console\Event\ConsoleCommandEvent") */ public const COMMAND = 'console.command'; /** * The SIGNAL event allows you to perform some actions * after the command execution was interrupted. * * @Event("Symfony\Component\Console\Event\ConsoleSignalEvent") */ public const SIGNAL = 'console.signal'; /** * The TERMINATE event allows you to attach listeners after a command is * executed by the console. * * @Event("Symfony\Component\Console\Event\ConsoleTerminateEvent") */ public const TERMINATE = 'console.terminate'; /** * The ERROR event occurs when an uncaught exception or error appears. * * This event allows you to deal with the exception/error or * to modify the thrown exception. * * @Event("Symfony\Component\Console\Event\ConsoleErrorEvent") */ public const ERROR = 'console.error'; /** * Event aliases. * * These aliases can be consumed by RegisterListenersPass. */ public const ALIASES = [ConsoleCommandEvent::class => self::COMMAND, ConsoleErrorEvent::class => self::ERROR, ConsoleSignalEvent::class => self::SIGNAL, ConsoleTerminateEvent::class => self::TERMINATE]; } * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace _HumbugBox7ff99e199a36\Symfony\Component\Console\Logger; use _HumbugBox7ff99e199a36\Psr\Log\AbstractLogger; use _HumbugBox7ff99e199a36\Psr\Log\InvalidArgumentException; use _HumbugBox7ff99e199a36\Psr\Log\LogLevel; use _HumbugBox7ff99e199a36\Symfony\Component\Console\Output\ConsoleOutputInterface; use _HumbugBox7ff99e199a36\Symfony\Component\Console\Output\OutputInterface; /** * PSR-3 compliant console logger. * * @author Kévin Dunglas * * @see https://www.php-fig.org/psr/psr-3/ */ class ConsoleLogger extends AbstractLogger { public const INFO = 'info'; public const ERROR = 'error'; private $output; private $verbosityLevelMap = [LogLevel::EMERGENCY => OutputInterface::VERBOSITY_NORMAL, LogLevel::ALERT => OutputInterface::VERBOSITY_NORMAL, LogLevel::CRITICAL => OutputInterface::VERBOSITY_NORMAL, LogLevel::ERROR => OutputInterface::VERBOSITY_NORMAL, LogLevel::WARNING => OutputInterface::VERBOSITY_NORMAL, LogLevel::NOTICE => OutputInterface::VERBOSITY_VERBOSE, LogLevel::INFO => OutputInterface::VERBOSITY_VERY_VERBOSE, LogLevel::DEBUG => OutputInterface::VERBOSITY_DEBUG]; private $formatLevelMap = [LogLevel::EMERGENCY => self::ERROR, LogLevel::ALERT => self::ERROR, LogLevel::CRITICAL => self::ERROR, LogLevel::ERROR => self::ERROR, LogLevel::WARNING => self::INFO, LogLevel::NOTICE => self::INFO, LogLevel::INFO => self::INFO, LogLevel::DEBUG => self::INFO]; private $errored = \false; public function __construct(OutputInterface $output, array $verbosityLevelMap = [], array $formatLevelMap = []) { $this->output = $output; $this->verbosityLevelMap = $verbosityLevelMap + $this->verbosityLevelMap; $this->formatLevelMap = $formatLevelMap + $this->formatLevelMap; } /** * {@inheritdoc} * * @return void */ public function log($level, $message, array $context = []) { if (!isset($this->verbosityLevelMap[$level])) { throw new InvalidArgumentException(\sprintf('The log level "%s" does not exist.', $level)); } $output = $this->output; // Write to the error output if necessary and available if (self::ERROR === $this->formatLevelMap[$level]) { if ($this->output instanceof ConsoleOutputInterface) { $output = $output->getErrorOutput(); } $this->errored = \true; } // the if condition check isn't necessary -- it's the same one that $output will do internally anyway. // We only do it for efficiency here as the message formatting is relatively expensive. if ($output->getVerbosity() >= $this->verbosityLevelMap[$level]) { $output->writeln(\sprintf('<%1$s>[%2$s] %3$s', $this->formatLevelMap[$level], $level, $this->interpolate($message, $context)), $this->verbosityLevelMap[$level]); } } /** * Returns true when any messages have been logged at error levels. * * @return bool */ public function hasErrored() { return $this->errored; } /** * Interpolates context values into the message placeholders. * * @author PHP Framework Interoperability Group */ private function interpolate(string $message, array $context) : string { if (!\str_contains($message, '{')) { return $message; } $replacements = []; foreach ($context as $key => $val) { if (null === $val || \is_scalar($val) || \is_object($val) && \method_exists($val, '__toString')) { $replacements["{{$key}}"] = $val; } elseif ($val instanceof \DateTimeInterface) { $replacements["{{$key}}"] = $val->format(\DateTime::RFC3339); } elseif (\is_object($val)) { $replacements["{{$key}}"] = '[object ' . \get_class($val) . ']'; } else { $replacements["{{$key}}"] = '[' . \gettype($val) . ']'; } } return \strtr($message, $replacements); } } * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace _HumbugBox7ff99e199a36\Symfony\Component\Console; use _HumbugBox7ff99e199a36\Symfony\Component\Console\Output\OutputInterface; /** * @author Pierre du Plessis */ final class Cursor { private $output; private $input; /** * @param resource|null $input */ public function __construct(OutputInterface $output, $input = null) { $this->output = $output; $this->input = $input ?? (\defined('STDIN') ? \STDIN : \fopen('php://input', 'r+')); } /** * @return $this */ public function moveUp(int $lines = 1) : self { $this->output->write(\sprintf("\x1b[%dA", $lines)); return $this; } /** * @return $this */ public function moveDown(int $lines = 1) : self { $this->output->write(\sprintf("\x1b[%dB", $lines)); return $this; } /** * @return $this */ public function moveRight(int $columns = 1) : self { $this->output->write(\sprintf("\x1b[%dC", $columns)); return $this; } /** * @return $this */ public function moveLeft(int $columns = 1) : self { $this->output->write(\sprintf("\x1b[%dD", $columns)); return $this; } /** * @return $this */ public function moveToColumn(int $column) : self { $this->output->write(\sprintf("\x1b[%dG", $column)); return $this; } /** * @return $this */ public function moveToPosition(int $column, int $row) : self { $this->output->write(\sprintf("\x1b[%d;%dH", $row + 1, $column)); return $this; } /** * @return $this */ public function savePosition() : self { $this->output->write("\x1b7"); return $this; } /** * @return $this */ public function restorePosition() : self { $this->output->write("\x1b8"); return $this; } /** * @return $this */ public function hide() : self { $this->output->write("\x1b[?25l"); return $this; } /** * @return $this */ public function show() : self { $this->output->write("\x1b[?25h\x1b[?0c"); return $this; } /** * Clears all the output from the current line. * * @return $this */ public function clearLine() : self { $this->output->write("\x1b[2K"); return $this; } /** * Clears all the output from the current line after the current position. */ public function clearLineAfter() : self { $this->output->write("\x1b[K"); return $this; } /** * Clears all the output from the cursors' current position to the end of the screen. * * @return $this */ public function clearOutput() : self { $this->output->write("\x1b[0J"); return $this; } /** * Clears the entire screen. * * @return $this */ public function clearScreen() : self { $this->output->write("\x1b[2J"); return $this; } /** * Returns the current cursor position as x,y coordinates. */ public function getCurrentPosition() : array { static $isTtySupported; if (null === $isTtySupported && \function_exists('proc_open')) { $isTtySupported = (bool) @\proc_open('echo 1 >/dev/null', [['file', '/dev/tty', 'r'], ['file', '/dev/tty', 'w'], ['file', '/dev/tty', 'w']], $pipes); } if (!$isTtySupported) { return [1, 1]; } $sttyMode = \shell_exec('stty -g'); \shell_exec('stty -icanon -echo'); @\fwrite($this->input, "\x1b[6n"); $code = \trim(\fread($this->input, 1024)); \shell_exec(\sprintf('stty %s', $sttyMode)); \sscanf($code, "\x1b[%d;%dR", $row, $col); return [$col, $row]; } } Copyright (c) 2018-present Fabien Potencier Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace _HumbugBox7ff99e199a36\Symfony\Contracts\Service\Attribute; /** * A required dependency. * * This attribute indicates that a property holds a required dependency. The annotated property or method should be * considered during the instantiation process of the containing class. * * @author Alexander M. Turek */ #[\Attribute(\Attribute::TARGET_METHOD | \Attribute::TARGET_PROPERTY)] final class Required { } * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace _HumbugBox7ff99e199a36\Symfony\Contracts\Service\Attribute; use _HumbugBox7ff99e199a36\Symfony\Contracts\Service\ServiceSubscriberTrait; /** * Use with {@see ServiceSubscriberTrait} to mark a method's return type * as a subscribed service. * * @author Kevin Bond */ #[\Attribute(\Attribute::TARGET_METHOD)] final class SubscribedService { /** * @param string|null $key The key to use for the service * If null, use "ClassName::methodName" */ public function __construct(public ?string $key = null) { } } * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace _HumbugBox7ff99e199a36\Symfony\Contracts\Service; use _HumbugBox7ff99e199a36\Psr\Container\ContainerInterface; use _HumbugBox7ff99e199a36\Symfony\Contracts\Service\Attribute\SubscribedService; /** * Implementation of ServiceSubscriberInterface that determines subscribed services from * method return types. Service ids are available as "ClassName::methodName". * * @author Kevin Bond */ trait ServiceSubscriberTrait { /** @var ContainerInterface */ protected $container; /** * {@inheritdoc} */ public static function getSubscribedServices() : array { $services = \method_exists(\get_parent_class(self::class) ?: '', __FUNCTION__) ? parent::getSubscribedServices() : []; $attributeOptIn = \false; if (\PHP_VERSION_ID >= 80000) { foreach ((new \ReflectionClass(self::class))->getMethods() as $method) { if (self::class !== $method->getDeclaringClass()->name) { continue; } if (!($attribute = $method->getAttributes(SubscribedService::class)[0] ?? null)) { continue; } if ($method->isStatic() || $method->isAbstract() || $method->isGenerator() || $method->isInternal() || $method->getNumberOfRequiredParameters()) { throw new \LogicException(\sprintf('Cannot use "%s" on method "%s::%s()" (can only be used on non-static, non-abstract methods with no parameters).', SubscribedService::class, self::class, $method->name)); } if (!($returnType = $method->getReturnType())) { throw new \LogicException(\sprintf('Cannot use "%s" on methods without a return type in "%s::%s()".', SubscribedService::class, $method->name, self::class)); } $serviceId = $returnType instanceof \ReflectionNamedType ? $returnType->getName() : (string) $returnType; if ($returnType->allowsNull()) { $serviceId = '?' . $serviceId; } $services[$attribute->newInstance()->key ?? self::class . '::' . $method->name] = $serviceId; $attributeOptIn = \true; } } if (!$attributeOptIn) { foreach ((new \ReflectionClass(self::class))->getMethods() as $method) { if ($method->isStatic() || $method->isAbstract() || $method->isGenerator() || $method->isInternal() || $method->getNumberOfRequiredParameters()) { continue; } if (self::class !== $method->getDeclaringClass()->name) { continue; } if (!($returnType = $method->getReturnType()) instanceof \ReflectionNamedType) { continue; } if ($returnType->isBuiltin()) { continue; } if (\PHP_VERSION_ID >= 80000) { trigger_deprecation('symfony/service-contracts', '2.5', 'Using "%s" in "%s" without using the "%s" attribute on any method is deprecated.', ServiceSubscriberTrait::class, self::class, SubscribedService::class); } $services[self::class . '::' . $method->name] = '?' . ($returnType instanceof \ReflectionNamedType ? $returnType->getName() : $returnType); } } return $services; } /** * @required * * @return ContainerInterface|null */ public function setContainer(ContainerInterface $container) { $ret = null; if (\method_exists(\get_parent_class(self::class) ?: '', __FUNCTION__)) { $ret = parent::setContainer($container); } $this->container = $container; return $ret; } } * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace _HumbugBox7ff99e199a36\Symfony\Contracts\Service; /** * Provides a way to reset an object to its initial state. * * When calling the "reset()" method on an object, it should be put back to its * initial state. This usually means clearing any internal buffers and forwarding * the call to internal dependencies. All properties of the object should be put * back to the same state it had when it was first ready to use. * * This method could be called, for example, to recycle objects that are used as * services, so that they can be used to handle several requests in the same * process loop (note that we advise making your services stateless instead of * implementing this interface when possible.) */ interface ResetInterface { public function reset(); } * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace _HumbugBox7ff99e199a36\Symfony\Contracts\Service; use _HumbugBox7ff99e199a36\Psr\Container\ContainerInterface; /** * A ServiceProviderInterface exposes the identifiers and the types of services provided by a container. * * @author Nicolas Grekas * @author Mateusz Sip */ interface ServiceProviderInterface extends ContainerInterface { /** * Returns an associative array of service types keyed by the identifiers provided by the current container. * * Examples: * * * ['logger' => 'Psr\Log\LoggerInterface'] means the object provides a service named "logger" that implements Psr\Log\LoggerInterface * * ['foo' => '?'] means the container provides service name "foo" of unspecified type * * ['bar' => '?Bar\Baz'] means the container provides a service "bar" of type Bar\Baz|null * * @return string[] The provided service types, keyed by service names */ public function getProvidedServices() : array; } * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace _HumbugBox7ff99e199a36\Symfony\Contracts\Service; use _HumbugBox7ff99e199a36\Psr\Container\ContainerExceptionInterface; use _HumbugBox7ff99e199a36\Psr\Container\NotFoundExceptionInterface; // Help opcache.preload discover always-needed symbols \class_exists(ContainerExceptionInterface::class); \class_exists(NotFoundExceptionInterface::class); /** * A trait to help implement ServiceProviderInterface. * * @author Robin Chalas * @author Nicolas Grekas */ trait ServiceLocatorTrait { private $factories; private $loading = []; private $providedTypes; /** * @param callable[] $factories */ public function __construct(array $factories) { $this->factories = $factories; } /** * {@inheritdoc} * * @return bool */ public function has(string $id) { return isset($this->factories[$id]); } /** * {@inheritdoc} * * @return mixed */ public function get(string $id) { if (!isset($this->factories[$id])) { throw $this->createNotFoundException($id); } if (isset($this->loading[$id])) { $ids = \array_values($this->loading); $ids = \array_slice($this->loading, \array_search($id, $ids)); $ids[] = $id; throw $this->createCircularReferenceException($id, $ids); } $this->loading[$id] = $id; try { return $this->factories[$id]($this); } finally { unset($this->loading[$id]); } } /** * {@inheritdoc} */ public function getProvidedServices() : array { if (null === $this->providedTypes) { $this->providedTypes = []; foreach ($this->factories as $name => $factory) { if (!\is_callable($factory)) { $this->providedTypes[$name] = '?'; } else { $type = (new \ReflectionFunction($factory))->getReturnType(); $this->providedTypes[$name] = $type ? ($type->allowsNull() ? '?' : '') . ($type instanceof \ReflectionNamedType ? $type->getName() : $type) : '?'; } } } return $this->providedTypes; } private function createNotFoundException(string $id) : NotFoundExceptionInterface { if (!($alternatives = \array_keys($this->factories))) { $message = 'is empty...'; } else { $last = \array_pop($alternatives); if ($alternatives) { $message = \sprintf('only knows about the "%s" and "%s" services.', \implode('", "', $alternatives), $last); } else { $message = \sprintf('only knows about the "%s" service.', $last); } } if ($this->loading) { $message = \sprintf('The service "%s" has a dependency on a non-existent service "%s". This locator %s', \end($this->loading), $id, $message); } else { $message = \sprintf('Service "%s" not found: the current service locator %s', $id, $message); } return new class($message) extends \InvalidArgumentException implements NotFoundExceptionInterface { }; } private function createCircularReferenceException(string $id, array $path) : ContainerExceptionInterface { return new class(\sprintf('Circular reference detected for service "%s", path: "%s".', $id, \implode(' -> ', $path))) extends \RuntimeException implements ContainerExceptionInterface { }; } } * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace _HumbugBox7ff99e199a36\Symfony\Contracts\Service; /** * A ServiceSubscriber exposes its dependencies via the static {@link getSubscribedServices} method. * * The getSubscribedServices method returns an array of service types required by such instances, * optionally keyed by the service names used internally. Service types that start with an interrogation * mark "?" are optional, while the other ones are mandatory service dependencies. * * The injected service locators SHOULD NOT allow access to any other services not specified by the method. * * It is expected that ServiceSubscriber instances consume PSR-11-based service locators internally. * This interface does not dictate any injection method for these service locators, although constructor * injection is recommended. * * @author Nicolas Grekas */ interface ServiceSubscriberInterface { /** * Returns an array of service types required by such instances, optionally keyed by the service names used internally. * * For mandatory dependencies: * * * ['logger' => 'Psr\Log\LoggerInterface'] means the objects use the "logger" name * internally to fetch a service which must implement Psr\Log\LoggerInterface. * * ['loggers' => 'Psr\Log\LoggerInterface[]'] means the objects use the "loggers" name * internally to fetch an iterable of Psr\Log\LoggerInterface instances. * * ['Psr\Log\LoggerInterface'] is a shortcut for * * ['Psr\Log\LoggerInterface' => 'Psr\Log\LoggerInterface'] * * otherwise: * * * ['logger' => '?Psr\Log\LoggerInterface'] denotes an optional dependency * * ['loggers' => '?Psr\Log\LoggerInterface[]'] denotes an optional iterable dependency * * ['?Psr\Log\LoggerInterface'] is a shortcut for * * ['Psr\Log\LoggerInterface' => '?Psr\Log\LoggerInterface'] * * @return string[] The required service types, optionally keyed by service names */ public static function getSubscribedServices(); } Copyright (c) 2015-present Fabien Potencier Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 'a', 'B' => 'b', 'C' => 'c', 'D' => 'd', 'E' => 'e', 'F' => 'f', 'G' => 'g', 'H' => 'h', 'I' => 'i', 'J' => 'j', 'K' => 'k', 'L' => 'l', 'M' => 'm', 'N' => 'n', 'O' => 'o', 'P' => 'p', 'Q' => 'q', 'R' => 'r', 'S' => 's', 'T' => 't', 'U' => 'u', 'V' => 'v', 'W' => 'w', 'X' => 'x', 'Y' => 'y', 'Z' => 'z', 'À' => 'à', 'Á' => 'á', 'Â' => 'â', 'Ã' => 'ã', 'Ä' => 'ä', 'Å' => 'å', 'Æ' => 'æ', 'Ç' => 'ç', 'È' => 'è', 'É' => 'é', 'Ê' => 'ê', 'Ë' => 'ë', 'Ì' => 'ì', 'Í' => 'í', 'Î' => 'î', 'Ï' => 'ï', 'Ð' => 'ð', 'Ñ' => 'ñ', 'Ò' => 'ò', 'Ó' => 'ó', 'Ô' => 'ô', 'Õ' => 'õ', 'Ö' => 'ö', 'Ø' => 'ø', 'Ù' => 'ù', 'Ú' => 'ú', 'Û' => 'û', 'Ü' => 'ü', 'Ý' => 'ý', 'Þ' => 'þ', 'Ā' => 'ā', 'Ă' => 'ă', 'Ą' => 'ą', 'Ć' => 'ć', 'Ĉ' => 'ĉ', 'Ċ' => 'ċ', 'Č' => 'č', 'Ď' => 'ď', 'Đ' => 'đ', 'Ē' => 'ē', 'Ĕ' => 'ĕ', 'Ė' => 'ė', 'Ę' => 'ę', 'Ě' => 'ě', 'Ĝ' => 'ĝ', 'Ğ' => 'ğ', 'Ġ' => 'ġ', 'Ģ' => 'ģ', 'Ĥ' => 'ĥ', 'Ħ' => 'ħ', 'Ĩ' => 'ĩ', 'Ī' => 'ī', 'Ĭ' => 'ĭ', 'Į' => 'į', 'İ' => 'i̇', 'IJ' => 'ij', 'Ĵ' => 'ĵ', 'Ķ' => 'ķ', 'Ĺ' => 'ĺ', 'Ļ' => 'ļ', 'Ľ' => 'ľ', 'Ŀ' => 'ŀ', 'Ł' => 'ł', 'Ń' => 'ń', 'Ņ' => 'ņ', 'Ň' => 'ň', 'Ŋ' => 'ŋ', 'Ō' => 'ō', 'Ŏ' => 'ŏ', 'Ő' => 'ő', 'Œ' => 'œ', 'Ŕ' => 'ŕ', 'Ŗ' => 'ŗ', 'Ř' => 'ř', 'Ś' => 'ś', 'Ŝ' => 'ŝ', 'Ş' => 'ş', 'Š' => 'š', 'Ţ' => 'ţ', 'Ť' => 'ť', 'Ŧ' => 'ŧ', 'Ũ' => 'ũ', 'Ū' => 'ū', 'Ŭ' => 'ŭ', 'Ů' => 'ů', 'Ű' => 'ű', 'Ų' => 'ų', 'Ŵ' => 'ŵ', 'Ŷ' => 'ŷ', 'Ÿ' => 'ÿ', 'Ź' => 'ź', 'Ż' => 'ż', 'Ž' => 'ž', 'Ɓ' => 'ɓ', 'Ƃ' => 'ƃ', 'Ƅ' => 'ƅ', 'Ɔ' => 'ɔ', 'Ƈ' => 'ƈ', 'Ɖ' => 'ɖ', 'Ɗ' => 'ɗ', 'Ƌ' => 'ƌ', 'Ǝ' => 'ǝ', 'Ə' => 'ə', 'Ɛ' => 'ɛ', 'Ƒ' => 'ƒ', 'Ɠ' => 'ɠ', 'Ɣ' => 'ɣ', 'Ɩ' => 'ɩ', 'Ɨ' => 'ɨ', 'Ƙ' => 'ƙ', 'Ɯ' => 'ɯ', 'Ɲ' => 'ɲ', 'Ɵ' => 'ɵ', 'Ơ' => 'ơ', 'Ƣ' => 'ƣ', 'Ƥ' => 'ƥ', 'Ʀ' => 'ʀ', 'Ƨ' => 'ƨ', 'Ʃ' => 'ʃ', 'Ƭ' => 'ƭ', 'Ʈ' => 'ʈ', 'Ư' => 'ư', 'Ʊ' => 'ʊ', 'Ʋ' => 'ʋ', 'Ƴ' => 'ƴ', 'Ƶ' => 'ƶ', 'Ʒ' => 'ʒ', 'Ƹ' => 'ƹ', 'Ƽ' => 'ƽ', 'DŽ' => 'dž', 'Dž' => 'dž', 'LJ' => 'lj', 'Lj' => 'lj', 'NJ' => 'nj', 'Nj' => 'nj', 'Ǎ' => 'ǎ', 'Ǐ' => 'ǐ', 'Ǒ' => 'ǒ', 'Ǔ' => 'ǔ', 'Ǖ' => 'ǖ', 'Ǘ' => 'ǘ', 'Ǚ' => 'ǚ', 'Ǜ' => 'ǜ', 'Ǟ' => 'ǟ', 'Ǡ' => 'ǡ', 'Ǣ' => 'ǣ', 'Ǥ' => 'ǥ', 'Ǧ' => 'ǧ', 'Ǩ' => 'ǩ', 'Ǫ' => 'ǫ', 'Ǭ' => 'ǭ', 'Ǯ' => 'ǯ', 'DZ' => 'dz', 'Dz' => 'dz', 'Ǵ' => 'ǵ', 'Ƕ' => 'ƕ', 'Ƿ' => 'ƿ', 'Ǹ' => 'ǹ', 'Ǻ' => 'ǻ', 'Ǽ' => 'ǽ', 'Ǿ' => 'ǿ', 'Ȁ' => 'ȁ', 'Ȃ' => 'ȃ', 'Ȅ' => 'ȅ', 'Ȇ' => 'ȇ', 'Ȉ' => 'ȉ', 'Ȋ' => 'ȋ', 'Ȍ' => 'ȍ', 'Ȏ' => 'ȏ', 'Ȑ' => 'ȑ', 'Ȓ' => 'ȓ', 'Ȕ' => 'ȕ', 'Ȗ' => 'ȗ', 'Ș' => 'ș', 'Ț' => 'ț', 'Ȝ' => 'ȝ', 'Ȟ' => 'ȟ', 'Ƞ' => 'ƞ', 'Ȣ' => 'ȣ', 'Ȥ' => 'ȥ', 'Ȧ' => 'ȧ', 'Ȩ' => 'ȩ', 'Ȫ' => 'ȫ', 'Ȭ' => 'ȭ', 'Ȯ' => 'ȯ', 'Ȱ' => 'ȱ', 'Ȳ' => 'ȳ', 'Ⱥ' => 'ⱥ', 'Ȼ' => 'ȼ', 'Ƚ' => 'ƚ', 'Ⱦ' => 'ⱦ', 'Ɂ' => 'ɂ', 'Ƀ' => 'ƀ', 'Ʉ' => 'ʉ', 'Ʌ' => 'ʌ', 'Ɇ' => 'ɇ', 'Ɉ' => 'ɉ', 'Ɋ' => 'ɋ', 'Ɍ' => 'ɍ', 'Ɏ' => 'ɏ', 'Ͱ' => 'ͱ', 'Ͳ' => 'ͳ', 'Ͷ' => 'ͷ', 'Ϳ' => 'ϳ', 'Ά' => 'ά', 'Έ' => 'έ', 'Ή' => 'ή', 'Ί' => 'ί', 'Ό' => 'ό', 'Ύ' => 'ύ', 'Ώ' => 'ώ', 'Α' => 'α', 'Β' => 'β', 'Γ' => 'γ', 'Δ' => 'δ', 'Ε' => 'ε', 'Ζ' => 'ζ', 'Η' => 'η', 'Θ' => 'θ', 'Ι' => 'ι', 'Κ' => 'κ', 'Λ' => 'λ', 'Μ' => 'μ', 'Ν' => 'ν', 'Ξ' => 'ξ', 'Ο' => 'ο', 'Π' => 'π', 'Ρ' => 'ρ', 'Σ' => 'σ', 'Τ' => 'τ', 'Υ' => 'υ', 'Φ' => 'φ', 'Χ' => 'χ', 'Ψ' => 'ψ', 'Ω' => 'ω', 'Ϊ' => 'ϊ', 'Ϋ' => 'ϋ', 'Ϗ' => 'ϗ', 'Ϙ' => 'ϙ', 'Ϛ' => 'ϛ', 'Ϝ' => 'ϝ', 'Ϟ' => 'ϟ', 'Ϡ' => 'ϡ', 'Ϣ' => 'ϣ', 'Ϥ' => 'ϥ', 'Ϧ' => 'ϧ', 'Ϩ' => 'ϩ', 'Ϫ' => 'ϫ', 'Ϭ' => 'ϭ', 'Ϯ' => 'ϯ', 'ϴ' => 'θ', 'Ϸ' => 'ϸ', 'Ϲ' => 'ϲ', 'Ϻ' => 'ϻ', 'Ͻ' => 'ͻ', 'Ͼ' => 'ͼ', 'Ͽ' => 'ͽ', 'Ѐ' => 'ѐ', 'Ё' => 'ё', 'Ђ' => 'ђ', 'Ѓ' => 'ѓ', 'Є' => 'є', 'Ѕ' => 'ѕ', 'І' => 'і', 'Ї' => 'ї', 'Ј' => 'ј', 'Љ' => 'љ', 'Њ' => 'њ', 'Ћ' => 'ћ', 'Ќ' => 'ќ', 'Ѝ' => 'ѝ', 'Ў' => 'ў', 'Џ' => 'џ', 'А' => 'а', 'Б' => 'б', 'В' => 'в', 'Г' => 'г', 'Д' => 'д', 'Е' => 'е', 'Ж' => 'ж', 'З' => 'з', 'И' => 'и', 'Й' => 'й', 'К' => 'к', 'Л' => 'л', 'М' => 'м', 'Н' => 'н', 'О' => 'о', 'П' => 'п', 'Р' => 'р', 'С' => 'с', 'Т' => 'т', 'У' => 'у', 'Ф' => 'ф', 'Х' => 'х', 'Ц' => 'ц', 'Ч' => 'ч', 'Ш' => 'ш', 'Щ' => 'щ', 'Ъ' => 'ъ', 'Ы' => 'ы', 'Ь' => 'ь', 'Э' => 'э', 'Ю' => 'ю', 'Я' => 'я', 'Ѡ' => 'ѡ', 'Ѣ' => 'ѣ', 'Ѥ' => 'ѥ', 'Ѧ' => 'ѧ', 'Ѩ' => 'ѩ', 'Ѫ' => 'ѫ', 'Ѭ' => 'ѭ', 'Ѯ' => 'ѯ', 'Ѱ' => 'ѱ', 'Ѳ' => 'ѳ', 'Ѵ' => 'ѵ', 'Ѷ' => 'ѷ', 'Ѹ' => 'ѹ', 'Ѻ' => 'ѻ', 'Ѽ' => 'ѽ', 'Ѿ' => 'ѿ', 'Ҁ' => 'ҁ', 'Ҋ' => 'ҋ', 'Ҍ' => 'ҍ', 'Ҏ' => 'ҏ', 'Ґ' => 'ґ', 'Ғ' => 'ғ', 'Ҕ' => 'ҕ', 'Җ' => 'җ', 'Ҙ' => 'ҙ', 'Қ' => 'қ', 'Ҝ' => 'ҝ', 'Ҟ' => 'ҟ', 'Ҡ' => 'ҡ', 'Ң' => 'ң', 'Ҥ' => 'ҥ', 'Ҧ' => 'ҧ', 'Ҩ' => 'ҩ', 'Ҫ' => 'ҫ', 'Ҭ' => 'ҭ', 'Ү' => 'ү', 'Ұ' => 'ұ', 'Ҳ' => 'ҳ', 'Ҵ' => 'ҵ', 'Ҷ' => 'ҷ', 'Ҹ' => 'ҹ', 'Һ' => 'һ', 'Ҽ' => 'ҽ', 'Ҿ' => 'ҿ', 'Ӏ' => 'ӏ', 'Ӂ' => 'ӂ', 'Ӄ' => 'ӄ', 'Ӆ' => 'ӆ', 'Ӈ' => 'ӈ', 'Ӊ' => 'ӊ', 'Ӌ' => 'ӌ', 'Ӎ' => 'ӎ', 'Ӑ' => 'ӑ', 'Ӓ' => 'ӓ', 'Ӕ' => 'ӕ', 'Ӗ' => 'ӗ', 'Ә' => 'ә', 'Ӛ' => 'ӛ', 'Ӝ' => 'ӝ', 'Ӟ' => 'ӟ', 'Ӡ' => 'ӡ', 'Ӣ' => 'ӣ', 'Ӥ' => 'ӥ', 'Ӧ' => 'ӧ', 'Ө' => 'ө', 'Ӫ' => 'ӫ', 'Ӭ' => 'ӭ', 'Ӯ' => 'ӯ', 'Ӱ' => 'ӱ', 'Ӳ' => 'ӳ', 'Ӵ' => 'ӵ', 'Ӷ' => 'ӷ', 'Ӹ' => 'ӹ', 'Ӻ' => 'ӻ', 'Ӽ' => 'ӽ', 'Ӿ' => 'ӿ', 'Ԁ' => 'ԁ', 'Ԃ' => 'ԃ', 'Ԅ' => 'ԅ', 'Ԇ' => 'ԇ', 'Ԉ' => 'ԉ', 'Ԋ' => 'ԋ', 'Ԍ' => 'ԍ', 'Ԏ' => 'ԏ', 'Ԑ' => 'ԑ', 'Ԓ' => 'ԓ', 'Ԕ' => 'ԕ', 'Ԗ' => 'ԗ', 'Ԙ' => 'ԙ', 'Ԛ' => 'ԛ', 'Ԝ' => 'ԝ', 'Ԟ' => 'ԟ', 'Ԡ' => 'ԡ', 'Ԣ' => 'ԣ', 'Ԥ' => 'ԥ', 'Ԧ' => 'ԧ', 'Ԩ' => 'ԩ', 'Ԫ' => 'ԫ', 'Ԭ' => 'ԭ', 'Ԯ' => 'ԯ', 'Ա' => 'ա', 'Բ' => 'բ', 'Գ' => 'գ', 'Դ' => 'դ', 'Ե' => 'ե', 'Զ' => 'զ', 'Է' => 'է', 'Ը' => 'ը', 'Թ' => 'թ', 'Ժ' => 'ժ', 'Ի' => 'ի', 'Լ' => 'լ', 'Խ' => 'խ', 'Ծ' => 'ծ', 'Կ' => 'կ', 'Հ' => 'հ', 'Ձ' => 'ձ', 'Ղ' => 'ղ', 'Ճ' => 'ճ', 'Մ' => 'մ', 'Յ' => 'յ', 'Ն' => 'ն', 'Շ' => 'շ', 'Ո' => 'ո', 'Չ' => 'չ', 'Պ' => 'պ', 'Ջ' => 'ջ', 'Ռ' => 'ռ', 'Ս' => 'ս', 'Վ' => 'վ', 'Տ' => 'տ', 'Ր' => 'ր', 'Ց' => 'ց', 'Ւ' => 'ւ', 'Փ' => 'փ', 'Ք' => 'ք', 'Օ' => 'օ', 'Ֆ' => 'ֆ', 'Ⴀ' => 'ⴀ', 'Ⴁ' => 'ⴁ', 'Ⴂ' => 'ⴂ', 'Ⴃ' => 'ⴃ', 'Ⴄ' => 'ⴄ', 'Ⴅ' => 'ⴅ', 'Ⴆ' => 'ⴆ', 'Ⴇ' => 'ⴇ', 'Ⴈ' => 'ⴈ', 'Ⴉ' => 'ⴉ', 'Ⴊ' => 'ⴊ', 'Ⴋ' => 'ⴋ', 'Ⴌ' => 'ⴌ', 'Ⴍ' => 'ⴍ', 'Ⴎ' => 'ⴎ', 'Ⴏ' => 'ⴏ', 'Ⴐ' => 'ⴐ', 'Ⴑ' => 'ⴑ', 'Ⴒ' => 'ⴒ', 'Ⴓ' => 'ⴓ', 'Ⴔ' => 'ⴔ', 'Ⴕ' => 'ⴕ', 'Ⴖ' => 'ⴖ', 'Ⴗ' => 'ⴗ', 'Ⴘ' => 'ⴘ', 'Ⴙ' => 'ⴙ', 'Ⴚ' => 'ⴚ', 'Ⴛ' => 'ⴛ', 'Ⴜ' => 'ⴜ', 'Ⴝ' => 'ⴝ', 'Ⴞ' => 'ⴞ', 'Ⴟ' => 'ⴟ', 'Ⴠ' => 'ⴠ', 'Ⴡ' => 'ⴡ', 'Ⴢ' => 'ⴢ', 'Ⴣ' => 'ⴣ', 'Ⴤ' => 'ⴤ', 'Ⴥ' => 'ⴥ', 'Ⴧ' => 'ⴧ', 'Ⴭ' => 'ⴭ', 'Ꭰ' => 'ꭰ', 'Ꭱ' => 'ꭱ', 'Ꭲ' => 'ꭲ', 'Ꭳ' => 'ꭳ', 'Ꭴ' => 'ꭴ', 'Ꭵ' => 'ꭵ', 'Ꭶ' => 'ꭶ', 'Ꭷ' => 'ꭷ', 'Ꭸ' => 'ꭸ', 'Ꭹ' => 'ꭹ', 'Ꭺ' => 'ꭺ', 'Ꭻ' => 'ꭻ', 'Ꭼ' => 'ꭼ', 'Ꭽ' => 'ꭽ', 'Ꭾ' => 'ꭾ', 'Ꭿ' => 'ꭿ', 'Ꮀ' => 'ꮀ', 'Ꮁ' => 'ꮁ', 'Ꮂ' => 'ꮂ', 'Ꮃ' => 'ꮃ', 'Ꮄ' => 'ꮄ', 'Ꮅ' => 'ꮅ', 'Ꮆ' => 'ꮆ', 'Ꮇ' => 'ꮇ', 'Ꮈ' => 'ꮈ', 'Ꮉ' => 'ꮉ', 'Ꮊ' => 'ꮊ', 'Ꮋ' => 'ꮋ', 'Ꮌ' => 'ꮌ', 'Ꮍ' => 'ꮍ', 'Ꮎ' => 'ꮎ', 'Ꮏ' => 'ꮏ', 'Ꮐ' => 'ꮐ', 'Ꮑ' => 'ꮑ', 'Ꮒ' => 'ꮒ', 'Ꮓ' => 'ꮓ', 'Ꮔ' => 'ꮔ', 'Ꮕ' => 'ꮕ', 'Ꮖ' => 'ꮖ', 'Ꮗ' => 'ꮗ', 'Ꮘ' => 'ꮘ', 'Ꮙ' => 'ꮙ', 'Ꮚ' => 'ꮚ', 'Ꮛ' => 'ꮛ', 'Ꮜ' => 'ꮜ', 'Ꮝ' => 'ꮝ', 'Ꮞ' => 'ꮞ', 'Ꮟ' => 'ꮟ', 'Ꮠ' => 'ꮠ', 'Ꮡ' => 'ꮡ', 'Ꮢ' => 'ꮢ', 'Ꮣ' => 'ꮣ', 'Ꮤ' => 'ꮤ', 'Ꮥ' => 'ꮥ', 'Ꮦ' => 'ꮦ', 'Ꮧ' => 'ꮧ', 'Ꮨ' => 'ꮨ', 'Ꮩ' => 'ꮩ', 'Ꮪ' => 'ꮪ', 'Ꮫ' => 'ꮫ', 'Ꮬ' => 'ꮬ', 'Ꮭ' => 'ꮭ', 'Ꮮ' => 'ꮮ', 'Ꮯ' => 'ꮯ', 'Ꮰ' => 'ꮰ', 'Ꮱ' => 'ꮱ', 'Ꮲ' => 'ꮲ', 'Ꮳ' => 'ꮳ', 'Ꮴ' => 'ꮴ', 'Ꮵ' => 'ꮵ', 'Ꮶ' => 'ꮶ', 'Ꮷ' => 'ꮷ', 'Ꮸ' => 'ꮸ', 'Ꮹ' => 'ꮹ', 'Ꮺ' => 'ꮺ', 'Ꮻ' => 'ꮻ', 'Ꮼ' => 'ꮼ', 'Ꮽ' => 'ꮽ', 'Ꮾ' => 'ꮾ', 'Ꮿ' => 'ꮿ', 'Ᏸ' => 'ᏸ', 'Ᏹ' => 'ᏹ', 'Ᏺ' => 'ᏺ', 'Ᏻ' => 'ᏻ', 'Ᏼ' => 'ᏼ', 'Ᏽ' => 'ᏽ', 'Ა' => 'ა', 'Ბ' => 'ბ', 'Გ' => 'გ', 'Დ' => 'დ', 'Ე' => 'ე', 'Ვ' => 'ვ', 'Ზ' => 'ზ', 'Თ' => 'თ', 'Ი' => 'ი', 'Კ' => 'კ', 'Ლ' => 'ლ', 'Მ' => 'მ', 'Ნ' => 'ნ', 'Ო' => 'ო', 'Პ' => 'პ', 'Ჟ' => 'ჟ', 'Რ' => 'რ', 'Ს' => 'ს', 'Ტ' => 'ტ', 'Უ' => 'უ', 'Ფ' => 'ფ', 'Ქ' => 'ქ', 'Ღ' => 'ღ', 'Ყ' => 'ყ', 'Შ' => 'შ', 'Ჩ' => 'ჩ', 'Ც' => 'ც', 'Ძ' => 'ძ', 'Წ' => 'წ', 'Ჭ' => 'ჭ', 'Ხ' => 'ხ', 'Ჯ' => 'ჯ', 'Ჰ' => 'ჰ', 'Ჱ' => 'ჱ', 'Ჲ' => 'ჲ', 'Ჳ' => 'ჳ', 'Ჴ' => 'ჴ', 'Ჵ' => 'ჵ', 'Ჶ' => 'ჶ', 'Ჷ' => 'ჷ', 'Ჸ' => 'ჸ', 'Ჹ' => 'ჹ', 'Ჺ' => 'ჺ', 'Ჽ' => 'ჽ', 'Ჾ' => 'ჾ', 'Ჿ' => 'ჿ', 'Ḁ' => 'ḁ', 'Ḃ' => 'ḃ', 'Ḅ' => 'ḅ', 'Ḇ' => 'ḇ', 'Ḉ' => 'ḉ', 'Ḋ' => 'ḋ', 'Ḍ' => 'ḍ', 'Ḏ' => 'ḏ', 'Ḑ' => 'ḑ', 'Ḓ' => 'ḓ', 'Ḕ' => 'ḕ', 'Ḗ' => 'ḗ', 'Ḙ' => 'ḙ', 'Ḛ' => 'ḛ', 'Ḝ' => 'ḝ', 'Ḟ' => 'ḟ', 'Ḡ' => 'ḡ', 'Ḣ' => 'ḣ', 'Ḥ' => 'ḥ', 'Ḧ' => 'ḧ', 'Ḩ' => 'ḩ', 'Ḫ' => 'ḫ', 'Ḭ' => 'ḭ', 'Ḯ' => 'ḯ', 'Ḱ' => 'ḱ', 'Ḳ' => 'ḳ', 'Ḵ' => 'ḵ', 'Ḷ' => 'ḷ', 'Ḹ' => 'ḹ', 'Ḻ' => 'ḻ', 'Ḽ' => 'ḽ', 'Ḿ' => 'ḿ', 'Ṁ' => 'ṁ', 'Ṃ' => 'ṃ', 'Ṅ' => 'ṅ', 'Ṇ' => 'ṇ', 'Ṉ' => 'ṉ', 'Ṋ' => 'ṋ', 'Ṍ' => 'ṍ', 'Ṏ' => 'ṏ', 'Ṑ' => 'ṑ', 'Ṓ' => 'ṓ', 'Ṕ' => 'ṕ', 'Ṗ' => 'ṗ', 'Ṙ' => 'ṙ', 'Ṛ' => 'ṛ', 'Ṝ' => 'ṝ', 'Ṟ' => 'ṟ', 'Ṡ' => 'ṡ', 'Ṣ' => 'ṣ', 'Ṥ' => 'ṥ', 'Ṧ' => 'ṧ', 'Ṩ' => 'ṩ', 'Ṫ' => 'ṫ', 'Ṭ' => 'ṭ', 'Ṯ' => 'ṯ', 'Ṱ' => 'ṱ', 'Ṳ' => 'ṳ', 'Ṵ' => 'ṵ', 'Ṷ' => 'ṷ', 'Ṹ' => 'ṹ', 'Ṻ' => 'ṻ', 'Ṽ' => 'ṽ', 'Ṿ' => 'ṿ', 'Ẁ' => 'ẁ', 'Ẃ' => 'ẃ', 'Ẅ' => 'ẅ', 'Ẇ' => 'ẇ', 'Ẉ' => 'ẉ', 'Ẋ' => 'ẋ', 'Ẍ' => 'ẍ', 'Ẏ' => 'ẏ', 'Ẑ' => 'ẑ', 'Ẓ' => 'ẓ', 'Ẕ' => 'ẕ', 'ẞ' => 'ß', 'Ạ' => 'ạ', 'Ả' => 'ả', 'Ấ' => 'ấ', 'Ầ' => 'ầ', 'Ẩ' => 'ẩ', 'Ẫ' => 'ẫ', 'Ậ' => 'ậ', 'Ắ' => 'ắ', 'Ằ' => 'ằ', 'Ẳ' => 'ẳ', 'Ẵ' => 'ẵ', 'Ặ' => 'ặ', 'Ẹ' => 'ẹ', 'Ẻ' => 'ẻ', 'Ẽ' => 'ẽ', 'Ế' => 'ế', 'Ề' => 'ề', 'Ể' => 'ể', 'Ễ' => 'ễ', 'Ệ' => 'ệ', 'Ỉ' => 'ỉ', 'Ị' => 'ị', 'Ọ' => 'ọ', 'Ỏ' => 'ỏ', 'Ố' => 'ố', 'Ồ' => 'ồ', 'Ổ' => 'ổ', 'Ỗ' => 'ỗ', 'Ộ' => 'ộ', 'Ớ' => 'ớ', 'Ờ' => 'ờ', 'Ở' => 'ở', 'Ỡ' => 'ỡ', 'Ợ' => 'ợ', 'Ụ' => 'ụ', 'Ủ' => 'ủ', 'Ứ' => 'ứ', 'Ừ' => 'ừ', 'Ử' => 'ử', 'Ữ' => 'ữ', 'Ự' => 'ự', 'Ỳ' => 'ỳ', 'Ỵ' => 'ỵ', 'Ỷ' => 'ỷ', 'Ỹ' => 'ỹ', 'Ỻ' => 'ỻ', 'Ỽ' => 'ỽ', 'Ỿ' => 'ỿ', 'Ἀ' => 'ἀ', 'Ἁ' => 'ἁ', 'Ἂ' => 'ἂ', 'Ἃ' => 'ἃ', 'Ἄ' => 'ἄ', 'Ἅ' => 'ἅ', 'Ἆ' => 'ἆ', 'Ἇ' => 'ἇ', 'Ἐ' => 'ἐ', 'Ἑ' => 'ἑ', 'Ἒ' => 'ἒ', 'Ἓ' => 'ἓ', 'Ἔ' => 'ἔ', 'Ἕ' => 'ἕ', 'Ἠ' => 'ἠ', 'Ἡ' => 'ἡ', 'Ἢ' => 'ἢ', 'Ἣ' => 'ἣ', 'Ἤ' => 'ἤ', 'Ἥ' => 'ἥ', 'Ἦ' => 'ἦ', 'Ἧ' => 'ἧ', 'Ἰ' => 'ἰ', 'Ἱ' => 'ἱ', 'Ἲ' => 'ἲ', 'Ἳ' => 'ἳ', 'Ἴ' => 'ἴ', 'Ἵ' => 'ἵ', 'Ἶ' => 'ἶ', 'Ἷ' => 'ἷ', 'Ὀ' => 'ὀ', 'Ὁ' => 'ὁ', 'Ὂ' => 'ὂ', 'Ὃ' => 'ὃ', 'Ὄ' => 'ὄ', 'Ὅ' => 'ὅ', 'Ὑ' => 'ὑ', 'Ὓ' => 'ὓ', 'Ὕ' => 'ὕ', 'Ὗ' => 'ὗ', 'Ὠ' => 'ὠ', 'Ὡ' => 'ὡ', 'Ὢ' => 'ὢ', 'Ὣ' => 'ὣ', 'Ὤ' => 'ὤ', 'Ὥ' => 'ὥ', 'Ὦ' => 'ὦ', 'Ὧ' => 'ὧ', 'ᾈ' => 'ᾀ', 'ᾉ' => 'ᾁ', 'ᾊ' => 'ᾂ', 'ᾋ' => 'ᾃ', 'ᾌ' => 'ᾄ', 'ᾍ' => 'ᾅ', 'ᾎ' => 'ᾆ', 'ᾏ' => 'ᾇ', 'ᾘ' => 'ᾐ', 'ᾙ' => 'ᾑ', 'ᾚ' => 'ᾒ', 'ᾛ' => 'ᾓ', 'ᾜ' => 'ᾔ', 'ᾝ' => 'ᾕ', 'ᾞ' => 'ᾖ', 'ᾟ' => 'ᾗ', 'ᾨ' => 'ᾠ', 'ᾩ' => 'ᾡ', 'ᾪ' => 'ᾢ', 'ᾫ' => 'ᾣ', 'ᾬ' => 'ᾤ', 'ᾭ' => 'ᾥ', 'ᾮ' => 'ᾦ', 'ᾯ' => 'ᾧ', 'Ᾰ' => 'ᾰ', 'Ᾱ' => 'ᾱ', 'Ὰ' => 'ὰ', 'Ά' => 'ά', 'ᾼ' => 'ᾳ', 'Ὲ' => 'ὲ', 'Έ' => 'έ', 'Ὴ' => 'ὴ', 'Ή' => 'ή', 'ῌ' => 'ῃ', 'Ῐ' => 'ῐ', 'Ῑ' => 'ῑ', 'Ὶ' => 'ὶ', 'Ί' => 'ί', 'Ῠ' => 'ῠ', 'Ῡ' => 'ῡ', 'Ὺ' => 'ὺ', 'Ύ' => 'ύ', 'Ῥ' => 'ῥ', 'Ὸ' => 'ὸ', 'Ό' => 'ό', 'Ὼ' => 'ὼ', 'Ώ' => 'ώ', 'ῼ' => 'ῳ', 'Ω' => 'ω', 'K' => 'k', 'Å' => 'å', 'Ⅎ' => 'ⅎ', 'Ⅰ' => 'ⅰ', 'Ⅱ' => 'ⅱ', 'Ⅲ' => 'ⅲ', 'Ⅳ' => 'ⅳ', 'Ⅴ' => 'ⅴ', 'Ⅵ' => 'ⅵ', 'Ⅶ' => 'ⅶ', 'Ⅷ' => 'ⅷ', 'Ⅸ' => 'ⅸ', 'Ⅹ' => 'ⅹ', 'Ⅺ' => 'ⅺ', 'Ⅻ' => 'ⅻ', 'Ⅼ' => 'ⅼ', 'Ⅽ' => 'ⅽ', 'Ⅾ' => 'ⅾ', 'Ⅿ' => 'ⅿ', 'Ↄ' => 'ↄ', 'Ⓐ' => 'ⓐ', 'Ⓑ' => 'ⓑ', 'Ⓒ' => 'ⓒ', 'Ⓓ' => 'ⓓ', 'Ⓔ' => 'ⓔ', 'Ⓕ' => 'ⓕ', 'Ⓖ' => 'ⓖ', 'Ⓗ' => 'ⓗ', 'Ⓘ' => 'ⓘ', 'Ⓙ' => 'ⓙ', 'Ⓚ' => 'ⓚ', 'Ⓛ' => 'ⓛ', 'Ⓜ' => 'ⓜ', 'Ⓝ' => 'ⓝ', 'Ⓞ' => 'ⓞ', 'Ⓟ' => 'ⓟ', 'Ⓠ' => 'ⓠ', 'Ⓡ' => 'ⓡ', 'Ⓢ' => 'ⓢ', 'Ⓣ' => 'ⓣ', 'Ⓤ' => 'ⓤ', 'Ⓥ' => 'ⓥ', 'Ⓦ' => 'ⓦ', 'Ⓧ' => 'ⓧ', 'Ⓨ' => 'ⓨ', 'Ⓩ' => 'ⓩ', 'Ⰰ' => 'ⰰ', 'Ⰱ' => 'ⰱ', 'Ⰲ' => 'ⰲ', 'Ⰳ' => 'ⰳ', 'Ⰴ' => 'ⰴ', 'Ⰵ' => 'ⰵ', 'Ⰶ' => 'ⰶ', 'Ⰷ' => 'ⰷ', 'Ⰸ' => 'ⰸ', 'Ⰹ' => 'ⰹ', 'Ⰺ' => 'ⰺ', 'Ⰻ' => 'ⰻ', 'Ⰼ' => 'ⰼ', 'Ⰽ' => 'ⰽ', 'Ⰾ' => 'ⰾ', 'Ⰿ' => 'ⰿ', 'Ⱀ' => 'ⱀ', 'Ⱁ' => 'ⱁ', 'Ⱂ' => 'ⱂ', 'Ⱃ' => 'ⱃ', 'Ⱄ' => 'ⱄ', 'Ⱅ' => 'ⱅ', 'Ⱆ' => 'ⱆ', 'Ⱇ' => 'ⱇ', 'Ⱈ' => 'ⱈ', 'Ⱉ' => 'ⱉ', 'Ⱊ' => 'ⱊ', 'Ⱋ' => 'ⱋ', 'Ⱌ' => 'ⱌ', 'Ⱍ' => 'ⱍ', 'Ⱎ' => 'ⱎ', 'Ⱏ' => 'ⱏ', 'Ⱐ' => 'ⱐ', 'Ⱑ' => 'ⱑ', 'Ⱒ' => 'ⱒ', 'Ⱓ' => 'ⱓ', 'Ⱔ' => 'ⱔ', 'Ⱕ' => 'ⱕ', 'Ⱖ' => 'ⱖ', 'Ⱗ' => 'ⱗ', 'Ⱘ' => 'ⱘ', 'Ⱙ' => 'ⱙ', 'Ⱚ' => 'ⱚ', 'Ⱛ' => 'ⱛ', 'Ⱜ' => 'ⱜ', 'Ⱝ' => 'ⱝ', 'Ⱞ' => 'ⱞ', 'Ⱡ' => 'ⱡ', 'Ɫ' => 'ɫ', 'Ᵽ' => 'ᵽ', 'Ɽ' => 'ɽ', 'Ⱨ' => 'ⱨ', 'Ⱪ' => 'ⱪ', 'Ⱬ' => 'ⱬ', 'Ɑ' => 'ɑ', 'Ɱ' => 'ɱ', 'Ɐ' => 'ɐ', 'Ɒ' => 'ɒ', 'Ⱳ' => 'ⱳ', 'Ⱶ' => 'ⱶ', 'Ȿ' => 'ȿ', 'Ɀ' => 'ɀ', 'Ⲁ' => 'ⲁ', 'Ⲃ' => 'ⲃ', 'Ⲅ' => 'ⲅ', 'Ⲇ' => 'ⲇ', 'Ⲉ' => 'ⲉ', 'Ⲋ' => 'ⲋ', 'Ⲍ' => 'ⲍ', 'Ⲏ' => 'ⲏ', 'Ⲑ' => 'ⲑ', 'Ⲓ' => 'ⲓ', 'Ⲕ' => 'ⲕ', 'Ⲗ' => 'ⲗ', 'Ⲙ' => 'ⲙ', 'Ⲛ' => 'ⲛ', 'Ⲝ' => 'ⲝ', 'Ⲟ' => 'ⲟ', 'Ⲡ' => 'ⲡ', 'Ⲣ' => 'ⲣ', 'Ⲥ' => 'ⲥ', 'Ⲧ' => 'ⲧ', 'Ⲩ' => 'ⲩ', 'Ⲫ' => 'ⲫ', 'Ⲭ' => 'ⲭ', 'Ⲯ' => 'ⲯ', 'Ⲱ' => 'ⲱ', 'Ⲳ' => 'ⲳ', 'Ⲵ' => 'ⲵ', 'Ⲷ' => 'ⲷ', 'Ⲹ' => 'ⲹ', 'Ⲻ' => 'ⲻ', 'Ⲽ' => 'ⲽ', 'Ⲿ' => 'ⲿ', 'Ⳁ' => 'ⳁ', 'Ⳃ' => 'ⳃ', 'Ⳅ' => 'ⳅ', 'Ⳇ' => 'ⳇ', 'Ⳉ' => 'ⳉ', 'Ⳋ' => 'ⳋ', 'Ⳍ' => 'ⳍ', 'Ⳏ' => 'ⳏ', 'Ⳑ' => 'ⳑ', 'Ⳓ' => 'ⳓ', 'Ⳕ' => 'ⳕ', 'Ⳗ' => 'ⳗ', 'Ⳙ' => 'ⳙ', 'Ⳛ' => 'ⳛ', 'Ⳝ' => 'ⳝ', 'Ⳟ' => 'ⳟ', 'Ⳡ' => 'ⳡ', 'Ⳣ' => 'ⳣ', 'Ⳬ' => 'ⳬ', 'Ⳮ' => 'ⳮ', 'Ⳳ' => 'ⳳ', 'Ꙁ' => 'ꙁ', 'Ꙃ' => 'ꙃ', 'Ꙅ' => 'ꙅ', 'Ꙇ' => 'ꙇ', 'Ꙉ' => 'ꙉ', 'Ꙋ' => 'ꙋ', 'Ꙍ' => 'ꙍ', 'Ꙏ' => 'ꙏ', 'Ꙑ' => 'ꙑ', 'Ꙓ' => 'ꙓ', 'Ꙕ' => 'ꙕ', 'Ꙗ' => 'ꙗ', 'Ꙙ' => 'ꙙ', 'Ꙛ' => 'ꙛ', 'Ꙝ' => 'ꙝ', 'Ꙟ' => 'ꙟ', 'Ꙡ' => 'ꙡ', 'Ꙣ' => 'ꙣ', 'Ꙥ' => 'ꙥ', 'Ꙧ' => 'ꙧ', 'Ꙩ' => 'ꙩ', 'Ꙫ' => 'ꙫ', 'Ꙭ' => 'ꙭ', 'Ꚁ' => 'ꚁ', 'Ꚃ' => 'ꚃ', 'Ꚅ' => 'ꚅ', 'Ꚇ' => 'ꚇ', 'Ꚉ' => 'ꚉ', 'Ꚋ' => 'ꚋ', 'Ꚍ' => 'ꚍ', 'Ꚏ' => 'ꚏ', 'Ꚑ' => 'ꚑ', 'Ꚓ' => 'ꚓ', 'Ꚕ' => 'ꚕ', 'Ꚗ' => 'ꚗ', 'Ꚙ' => 'ꚙ', 'Ꚛ' => 'ꚛ', 'Ꜣ' => 'ꜣ', 'Ꜥ' => 'ꜥ', 'Ꜧ' => 'ꜧ', 'Ꜩ' => 'ꜩ', 'Ꜫ' => 'ꜫ', 'Ꜭ' => 'ꜭ', 'Ꜯ' => 'ꜯ', 'Ꜳ' => 'ꜳ', 'Ꜵ' => 'ꜵ', 'Ꜷ' => 'ꜷ', 'Ꜹ' => 'ꜹ', 'Ꜻ' => 'ꜻ', 'Ꜽ' => 'ꜽ', 'Ꜿ' => 'ꜿ', 'Ꝁ' => 'ꝁ', 'Ꝃ' => 'ꝃ', 'Ꝅ' => 'ꝅ', 'Ꝇ' => 'ꝇ', 'Ꝉ' => 'ꝉ', 'Ꝋ' => 'ꝋ', 'Ꝍ' => 'ꝍ', 'Ꝏ' => 'ꝏ', 'Ꝑ' => 'ꝑ', 'Ꝓ' => 'ꝓ', 'Ꝕ' => 'ꝕ', 'Ꝗ' => 'ꝗ', 'Ꝙ' => 'ꝙ', 'Ꝛ' => 'ꝛ', 'Ꝝ' => 'ꝝ', 'Ꝟ' => 'ꝟ', 'Ꝡ' => 'ꝡ', 'Ꝣ' => 'ꝣ', 'Ꝥ' => 'ꝥ', 'Ꝧ' => 'ꝧ', 'Ꝩ' => 'ꝩ', 'Ꝫ' => 'ꝫ', 'Ꝭ' => 'ꝭ', 'Ꝯ' => 'ꝯ', 'Ꝺ' => 'ꝺ', 'Ꝼ' => 'ꝼ', 'Ᵹ' => 'ᵹ', 'Ꝿ' => 'ꝿ', 'Ꞁ' => 'ꞁ', 'Ꞃ' => 'ꞃ', 'Ꞅ' => 'ꞅ', 'Ꞇ' => 'ꞇ', 'Ꞌ' => 'ꞌ', 'Ɥ' => 'ɥ', 'Ꞑ' => 'ꞑ', 'Ꞓ' => 'ꞓ', 'Ꞗ' => 'ꞗ', 'Ꞙ' => 'ꞙ', 'Ꞛ' => 'ꞛ', 'Ꞝ' => 'ꞝ', 'Ꞟ' => 'ꞟ', 'Ꞡ' => 'ꞡ', 'Ꞣ' => 'ꞣ', 'Ꞥ' => 'ꞥ', 'Ꞧ' => 'ꞧ', 'Ꞩ' => 'ꞩ', 'Ɦ' => 'ɦ', 'Ɜ' => 'ɜ', 'Ɡ' => 'ɡ', 'Ɬ' => 'ɬ', 'Ɪ' => 'ɪ', 'Ʞ' => 'ʞ', 'Ʇ' => 'ʇ', 'Ʝ' => 'ʝ', 'Ꭓ' => 'ꭓ', 'Ꞵ' => 'ꞵ', 'Ꞷ' => 'ꞷ', 'Ꞹ' => 'ꞹ', 'Ꞻ' => 'ꞻ', 'Ꞽ' => 'ꞽ', 'Ꞿ' => 'ꞿ', 'Ꟃ' => 'ꟃ', 'Ꞔ' => 'ꞔ', 'Ʂ' => 'ʂ', 'Ᶎ' => 'ᶎ', 'Ꟈ' => 'ꟈ', 'Ꟊ' => 'ꟊ', 'Ꟶ' => 'ꟶ', 'A' => 'a', 'B' => 'b', 'C' => 'c', 'D' => 'd', 'E' => 'e', 'F' => 'f', 'G' => 'g', 'H' => 'h', 'I' => 'i', 'J' => 'j', 'K' => 'k', 'L' => 'l', 'M' => 'm', 'N' => 'n', 'O' => 'o', 'P' => 'p', 'Q' => 'q', 'R' => 'r', 'S' => 's', 'T' => 't', 'U' => 'u', 'V' => 'v', 'W' => 'w', 'X' => 'x', 'Y' => 'y', 'Z' => 'z', '𐐀' => '𐐨', '𐐁' => '𐐩', '𐐂' => '𐐪', '𐐃' => '𐐫', '𐐄' => '𐐬', '𐐅' => '𐐭', '𐐆' => '𐐮', '𐐇' => '𐐯', '𐐈' => '𐐰', '𐐉' => '𐐱', '𐐊' => '𐐲', '𐐋' => '𐐳', '𐐌' => '𐐴', '𐐍' => '𐐵', '𐐎' => '𐐶', '𐐏' => '𐐷', '𐐐' => '𐐸', '𐐑' => '𐐹', '𐐒' => '𐐺', '𐐓' => '𐐻', '𐐔' => '𐐼', '𐐕' => '𐐽', '𐐖' => '𐐾', '𐐗' => '𐐿', '𐐘' => '𐑀', '𐐙' => '𐑁', '𐐚' => '𐑂', '𐐛' => '𐑃', '𐐜' => '𐑄', '𐐝' => '𐑅', '𐐞' => '𐑆', '𐐟' => '𐑇', '𐐠' => '𐑈', '𐐡' => '𐑉', '𐐢' => '𐑊', '𐐣' => '𐑋', '𐐤' => '𐑌', '𐐥' => '𐑍', '𐐦' => '𐑎', '𐐧' => '𐑏', '𐒰' => '𐓘', '𐒱' => '𐓙', '𐒲' => '𐓚', '𐒳' => '𐓛', '𐒴' => '𐓜', '𐒵' => '𐓝', '𐒶' => '𐓞', '𐒷' => '𐓟', '𐒸' => '𐓠', '𐒹' => '𐓡', '𐒺' => '𐓢', '𐒻' => '𐓣', '𐒼' => '𐓤', '𐒽' => '𐓥', '𐒾' => '𐓦', '𐒿' => '𐓧', '𐓀' => '𐓨', '𐓁' => '𐓩', '𐓂' => '𐓪', '𐓃' => '𐓫', '𐓄' => '𐓬', '𐓅' => '𐓭', '𐓆' => '𐓮', '𐓇' => '𐓯', '𐓈' => '𐓰', '𐓉' => '𐓱', '𐓊' => '𐓲', '𐓋' => '𐓳', '𐓌' => '𐓴', '𐓍' => '𐓵', '𐓎' => '𐓶', '𐓏' => '𐓷', '𐓐' => '𐓸', '𐓑' => '𐓹', '𐓒' => '𐓺', '𐓓' => '𐓻', '𐲀' => '𐳀', '𐲁' => '𐳁', '𐲂' => '𐳂', '𐲃' => '𐳃', '𐲄' => '𐳄', '𐲅' => '𐳅', '𐲆' => '𐳆', '𐲇' => '𐳇', '𐲈' => '𐳈', '𐲉' => '𐳉', '𐲊' => '𐳊', '𐲋' => '𐳋', '𐲌' => '𐳌', '𐲍' => '𐳍', '𐲎' => '𐳎', '𐲏' => '𐳏', '𐲐' => '𐳐', '𐲑' => '𐳑', '𐲒' => '𐳒', '𐲓' => '𐳓', '𐲔' => '𐳔', '𐲕' => '𐳕', '𐲖' => '𐳖', '𐲗' => '𐳗', '𐲘' => '𐳘', '𐲙' => '𐳙', '𐲚' => '𐳚', '𐲛' => '𐳛', '𐲜' => '𐳜', '𐲝' => '𐳝', '𐲞' => '𐳞', '𐲟' => '𐳟', '𐲠' => '𐳠', '𐲡' => '𐳡', '𐲢' => '𐳢', '𐲣' => '𐳣', '𐲤' => '𐳤', '𐲥' => '𐳥', '𐲦' => '𐳦', '𐲧' => '𐳧', '𐲨' => '𐳨', '𐲩' => '𐳩', '𐲪' => '𐳪', '𐲫' => '𐳫', '𐲬' => '𐳬', '𐲭' => '𐳭', '𐲮' => '𐳮', '𐲯' => '𐳯', '𐲰' => '𐳰', '𐲱' => '𐳱', '𐲲' => '𐳲', '𑢠' => '𑣀', '𑢡' => '𑣁', '𑢢' => '𑣂', '𑢣' => '𑣃', '𑢤' => '𑣄', '𑢥' => '𑣅', '𑢦' => '𑣆', '𑢧' => '𑣇', '𑢨' => '𑣈', '𑢩' => '𑣉', '𑢪' => '𑣊', '𑢫' => '𑣋', '𑢬' => '𑣌', '𑢭' => '𑣍', '𑢮' => '𑣎', '𑢯' => '𑣏', '𑢰' => '𑣐', '𑢱' => '𑣑', '𑢲' => '𑣒', '𑢳' => '𑣓', '𑢴' => '𑣔', '𑢵' => '𑣕', '𑢶' => '𑣖', '𑢷' => '𑣗', '𑢸' => '𑣘', '𑢹' => '𑣙', '𑢺' => '𑣚', '𑢻' => '𑣛', '𑢼' => '𑣜', '𑢽' => '𑣝', '𑢾' => '𑣞', '𑢿' => '𑣟', '𖹀' => '𖹠', '𖹁' => '𖹡', '𖹂' => '𖹢', '𖹃' => '𖹣', '𖹄' => '𖹤', '𖹅' => '𖹥', '𖹆' => '𖹦', '𖹇' => '𖹧', '𖹈' => '𖹨', '𖹉' => '𖹩', '𖹊' => '𖹪', '𖹋' => '𖹫', '𖹌' => '𖹬', '𖹍' => '𖹭', '𖹎' => '𖹮', '𖹏' => '𖹯', '𖹐' => '𖹰', '𖹑' => '𖹱', '𖹒' => '𖹲', '𖹓' => '𖹳', '𖹔' => '𖹴', '𖹕' => '𖹵', '𖹖' => '𖹶', '𖹗' => '𖹷', '𖹘' => '𖹸', '𖹙' => '𖹹', '𖹚' => '𖹺', '𖹛' => '𖹻', '𖹜' => '𖹼', '𖹝' => '𖹽', '𖹞' => '𖹾', '𖹟' => '𖹿', '𞤀' => '𞤢', '𞤁' => '𞤣', '𞤂' => '𞤤', '𞤃' => '𞤥', '𞤄' => '𞤦', '𞤅' => '𞤧', '𞤆' => '𞤨', '𞤇' => '𞤩', '𞤈' => '𞤪', '𞤉' => '𞤫', '𞤊' => '𞤬', '𞤋' => '𞤭', '𞤌' => '𞤮', '𞤍' => '𞤯', '𞤎' => '𞤰', '𞤏' => '𞤱', '𞤐' => '𞤲', '𞤑' => '𞤳', '𞤒' => '𞤴', '𞤓' => '𞤵', '𞤔' => '𞤶', '𞤕' => '𞤷', '𞤖' => '𞤸', '𞤗' => '𞤹', '𞤘' => '𞤺', '𞤙' => '𞤻', '𞤚' => '𞤼', '𞤛' => '𞤽', '𞤜' => '𞤾', '𞤝' => '𞤿', '𞤞' => '𞥀', '𞤟' => '𞥁', '𞤠' => '𞥂', '𞤡' => '𞥃'); 'i̇', 'µ' => 'μ', 'ſ' => 's', 'ͅ' => 'ι', 'ς' => 'σ', 'ϐ' => 'β', 'ϑ' => 'θ', 'ϕ' => 'φ', 'ϖ' => 'π', 'ϰ' => 'κ', 'ϱ' => 'ρ', 'ϵ' => 'ε', 'ẛ' => 'ṡ', 'ι' => 'ι', 'ß' => 'ss', 'ʼn' => 'ʼn', 'ǰ' => 'ǰ', 'ΐ' => 'ΐ', 'ΰ' => 'ΰ', 'և' => 'եւ', 'ẖ' => 'ẖ', 'ẗ' => 'ẗ', 'ẘ' => 'ẘ', 'ẙ' => 'ẙ', 'ẚ' => 'aʾ', 'ẞ' => 'ss', 'ὐ' => 'ὐ', 'ὒ' => 'ὒ', 'ὔ' => 'ὔ', 'ὖ' => 'ὖ', 'ᾀ' => 'ἀι', 'ᾁ' => 'ἁι', 'ᾂ' => 'ἂι', 'ᾃ' => 'ἃι', 'ᾄ' => 'ἄι', 'ᾅ' => 'ἅι', 'ᾆ' => 'ἆι', 'ᾇ' => 'ἇι', 'ᾈ' => 'ἀι', 'ᾉ' => 'ἁι', 'ᾊ' => 'ἂι', 'ᾋ' => 'ἃι', 'ᾌ' => 'ἄι', 'ᾍ' => 'ἅι', 'ᾎ' => 'ἆι', 'ᾏ' => 'ἇι', 'ᾐ' => 'ἠι', 'ᾑ' => 'ἡι', 'ᾒ' => 'ἢι', 'ᾓ' => 'ἣι', 'ᾔ' => 'ἤι', 'ᾕ' => 'ἥι', 'ᾖ' => 'ἦι', 'ᾗ' => 'ἧι', 'ᾘ' => 'ἠι', 'ᾙ' => 'ἡι', 'ᾚ' => 'ἢι', 'ᾛ' => 'ἣι', 'ᾜ' => 'ἤι', 'ᾝ' => 'ἥι', 'ᾞ' => 'ἦι', 'ᾟ' => 'ἧι', 'ᾠ' => 'ὠι', 'ᾡ' => 'ὡι', 'ᾢ' => 'ὢι', 'ᾣ' => 'ὣι', 'ᾤ' => 'ὤι', 'ᾥ' => 'ὥι', 'ᾦ' => 'ὦι', 'ᾧ' => 'ὧι', 'ᾨ' => 'ὠι', 'ᾩ' => 'ὡι', 'ᾪ' => 'ὢι', 'ᾫ' => 'ὣι', 'ᾬ' => 'ὤι', 'ᾭ' => 'ὥι', 'ᾮ' => 'ὦι', 'ᾯ' => 'ὧι', 'ᾲ' => 'ὰι', 'ᾳ' => 'αι', 'ᾴ' => 'άι', 'ᾶ' => 'ᾶ', 'ᾷ' => 'ᾶι', 'ᾼ' => 'αι', 'ῂ' => 'ὴι', 'ῃ' => 'ηι', 'ῄ' => 'ήι', 'ῆ' => 'ῆ', 'ῇ' => 'ῆι', 'ῌ' => 'ηι', 'ῒ' => 'ῒ', 'ῖ' => 'ῖ', 'ῗ' => 'ῗ', 'ῢ' => 'ῢ', 'ῤ' => 'ῤ', 'ῦ' => 'ῦ', 'ῧ' => 'ῧ', 'ῲ' => 'ὼι', 'ῳ' => 'ωι', 'ῴ' => 'ώι', 'ῶ' => 'ῶ', 'ῷ' => 'ῶι', 'ῼ' => 'ωι', 'ff' => 'ff', 'fi' => 'fi', 'fl' => 'fl', 'ffi' => 'ffi', 'ffl' => 'ffl', 'ſt' => 'st', 'st' => 'st', 'ﬓ' => 'մն', 'ﬔ' => 'մե', 'ﬕ' => 'մի', 'ﬖ' => 'վն', 'ﬗ' => 'մխ']; 'A', 'b' => 'B', 'c' => 'C', 'd' => 'D', 'e' => 'E', 'f' => 'F', 'g' => 'G', 'h' => 'H', 'i' => 'I', 'j' => 'J', 'k' => 'K', 'l' => 'L', 'm' => 'M', 'n' => 'N', 'o' => 'O', 'p' => 'P', 'q' => 'Q', 'r' => 'R', 's' => 'S', 't' => 'T', 'u' => 'U', 'v' => 'V', 'w' => 'W', 'x' => 'X', 'y' => 'Y', 'z' => 'Z', 'µ' => 'Μ', 'à' => 'À', 'á' => 'Á', 'â' => 'Â', 'ã' => 'Ã', 'ä' => 'Ä', 'å' => 'Å', 'æ' => 'Æ', 'ç' => 'Ç', 'è' => 'È', 'é' => 'É', 'ê' => 'Ê', 'ë' => 'Ë', 'ì' => 'Ì', 'í' => 'Í', 'î' => 'Î', 'ï' => 'Ï', 'ð' => 'Ð', 'ñ' => 'Ñ', 'ò' => 'Ò', 'ó' => 'Ó', 'ô' => 'Ô', 'õ' => 'Õ', 'ö' => 'Ö', 'ø' => 'Ø', 'ù' => 'Ù', 'ú' => 'Ú', 'û' => 'Û', 'ü' => 'Ü', 'ý' => 'Ý', 'þ' => 'Þ', 'ÿ' => 'Ÿ', 'ā' => 'Ā', 'ă' => 'Ă', 'ą' => 'Ą', 'ć' => 'Ć', 'ĉ' => 'Ĉ', 'ċ' => 'Ċ', 'č' => 'Č', 'ď' => 'Ď', 'đ' => 'Đ', 'ē' => 'Ē', 'ĕ' => 'Ĕ', 'ė' => 'Ė', 'ę' => 'Ę', 'ě' => 'Ě', 'ĝ' => 'Ĝ', 'ğ' => 'Ğ', 'ġ' => 'Ġ', 'ģ' => 'Ģ', 'ĥ' => 'Ĥ', 'ħ' => 'Ħ', 'ĩ' => 'Ĩ', 'ī' => 'Ī', 'ĭ' => 'Ĭ', 'į' => 'Į', 'ı' => 'I', 'ij' => 'IJ', 'ĵ' => 'Ĵ', 'ķ' => 'Ķ', 'ĺ' => 'Ĺ', 'ļ' => 'Ļ', 'ľ' => 'Ľ', 'ŀ' => 'Ŀ', 'ł' => 'Ł', 'ń' => 'Ń', 'ņ' => 'Ņ', 'ň' => 'Ň', 'ŋ' => 'Ŋ', 'ō' => 'Ō', 'ŏ' => 'Ŏ', 'ő' => 'Ő', 'œ' => 'Œ', 'ŕ' => 'Ŕ', 'ŗ' => 'Ŗ', 'ř' => 'Ř', 'ś' => 'Ś', 'ŝ' => 'Ŝ', 'ş' => 'Ş', 'š' => 'Š', 'ţ' => 'Ţ', 'ť' => 'Ť', 'ŧ' => 'Ŧ', 'ũ' => 'Ũ', 'ū' => 'Ū', 'ŭ' => 'Ŭ', 'ů' => 'Ů', 'ű' => 'Ű', 'ų' => 'Ų', 'ŵ' => 'Ŵ', 'ŷ' => 'Ŷ', 'ź' => 'Ź', 'ż' => 'Ż', 'ž' => 'Ž', 'ſ' => 'S', 'ƀ' => 'Ƀ', 'ƃ' => 'Ƃ', 'ƅ' => 'Ƅ', 'ƈ' => 'Ƈ', 'ƌ' => 'Ƌ', 'ƒ' => 'Ƒ', 'ƕ' => 'Ƕ', 'ƙ' => 'Ƙ', 'ƚ' => 'Ƚ', 'ƞ' => 'Ƞ', 'ơ' => 'Ơ', 'ƣ' => 'Ƣ', 'ƥ' => 'Ƥ', 'ƨ' => 'Ƨ', 'ƭ' => 'Ƭ', 'ư' => 'Ư', 'ƴ' => 'Ƴ', 'ƶ' => 'Ƶ', 'ƹ' => 'Ƹ', 'ƽ' => 'Ƽ', 'ƿ' => 'Ƿ', 'Dž' => 'DŽ', 'dž' => 'DŽ', 'Lj' => 'LJ', 'lj' => 'LJ', 'Nj' => 'NJ', 'nj' => 'NJ', 'ǎ' => 'Ǎ', 'ǐ' => 'Ǐ', 'ǒ' => 'Ǒ', 'ǔ' => 'Ǔ', 'ǖ' => 'Ǖ', 'ǘ' => 'Ǘ', 'ǚ' => 'Ǚ', 'ǜ' => 'Ǜ', 'ǝ' => 'Ǝ', 'ǟ' => 'Ǟ', 'ǡ' => 'Ǡ', 'ǣ' => 'Ǣ', 'ǥ' => 'Ǥ', 'ǧ' => 'Ǧ', 'ǩ' => 'Ǩ', 'ǫ' => 'Ǫ', 'ǭ' => 'Ǭ', 'ǯ' => 'Ǯ', 'Dz' => 'DZ', 'dz' => 'DZ', 'ǵ' => 'Ǵ', 'ǹ' => 'Ǹ', 'ǻ' => 'Ǻ', 'ǽ' => 'Ǽ', 'ǿ' => 'Ǿ', 'ȁ' => 'Ȁ', 'ȃ' => 'Ȃ', 'ȅ' => 'Ȅ', 'ȇ' => 'Ȇ', 'ȉ' => 'Ȉ', 'ȋ' => 'Ȋ', 'ȍ' => 'Ȍ', 'ȏ' => 'Ȏ', 'ȑ' => 'Ȑ', 'ȓ' => 'Ȓ', 'ȕ' => 'Ȕ', 'ȗ' => 'Ȗ', 'ș' => 'Ș', 'ț' => 'Ț', 'ȝ' => 'Ȝ', 'ȟ' => 'Ȟ', 'ȣ' => 'Ȣ', 'ȥ' => 'Ȥ', 'ȧ' => 'Ȧ', 'ȩ' => 'Ȩ', 'ȫ' => 'Ȫ', 'ȭ' => 'Ȭ', 'ȯ' => 'Ȯ', 'ȱ' => 'Ȱ', 'ȳ' => 'Ȳ', 'ȼ' => 'Ȼ', 'ȿ' => 'Ȿ', 'ɀ' => 'Ɀ', 'ɂ' => 'Ɂ', 'ɇ' => 'Ɇ', 'ɉ' => 'Ɉ', 'ɋ' => 'Ɋ', 'ɍ' => 'Ɍ', 'ɏ' => 'Ɏ', 'ɐ' => 'Ɐ', 'ɑ' => 'Ɑ', 'ɒ' => 'Ɒ', 'ɓ' => 'Ɓ', 'ɔ' => 'Ɔ', 'ɖ' => 'Ɖ', 'ɗ' => 'Ɗ', 'ə' => 'Ə', 'ɛ' => 'Ɛ', 'ɜ' => 'Ɜ', 'ɠ' => 'Ɠ', 'ɡ' => 'Ɡ', 'ɣ' => 'Ɣ', 'ɥ' => 'Ɥ', 'ɦ' => 'Ɦ', 'ɨ' => 'Ɨ', 'ɩ' => 'Ɩ', 'ɪ' => 'Ɪ', 'ɫ' => 'Ɫ', 'ɬ' => 'Ɬ', 'ɯ' => 'Ɯ', 'ɱ' => 'Ɱ', 'ɲ' => 'Ɲ', 'ɵ' => 'Ɵ', 'ɽ' => 'Ɽ', 'ʀ' => 'Ʀ', 'ʂ' => 'Ʂ', 'ʃ' => 'Ʃ', 'ʇ' => 'Ʇ', 'ʈ' => 'Ʈ', 'ʉ' => 'Ʉ', 'ʊ' => 'Ʊ', 'ʋ' => 'Ʋ', 'ʌ' => 'Ʌ', 'ʒ' => 'Ʒ', 'ʝ' => 'Ʝ', 'ʞ' => 'Ʞ', 'ͅ' => 'Ι', 'ͱ' => 'Ͱ', 'ͳ' => 'Ͳ', 'ͷ' => 'Ͷ', 'ͻ' => 'Ͻ', 'ͼ' => 'Ͼ', 'ͽ' => 'Ͽ', 'ά' => 'Ά', 'έ' => 'Έ', 'ή' => 'Ή', 'ί' => 'Ί', 'α' => 'Α', 'β' => 'Β', 'γ' => 'Γ', 'δ' => 'Δ', 'ε' => 'Ε', 'ζ' => 'Ζ', 'η' => 'Η', 'θ' => 'Θ', 'ι' => 'Ι', 'κ' => 'Κ', 'λ' => 'Λ', 'μ' => 'Μ', 'ν' => 'Ν', 'ξ' => 'Ξ', 'ο' => 'Ο', 'π' => 'Π', 'ρ' => 'Ρ', 'ς' => 'Σ', 'σ' => 'Σ', 'τ' => 'Τ', 'υ' => 'Υ', 'φ' => 'Φ', 'χ' => 'Χ', 'ψ' => 'Ψ', 'ω' => 'Ω', 'ϊ' => 'Ϊ', 'ϋ' => 'Ϋ', 'ό' => 'Ό', 'ύ' => 'Ύ', 'ώ' => 'Ώ', 'ϐ' => 'Β', 'ϑ' => 'Θ', 'ϕ' => 'Φ', 'ϖ' => 'Π', 'ϗ' => 'Ϗ', 'ϙ' => 'Ϙ', 'ϛ' => 'Ϛ', 'ϝ' => 'Ϝ', 'ϟ' => 'Ϟ', 'ϡ' => 'Ϡ', 'ϣ' => 'Ϣ', 'ϥ' => 'Ϥ', 'ϧ' => 'Ϧ', 'ϩ' => 'Ϩ', 'ϫ' => 'Ϫ', 'ϭ' => 'Ϭ', 'ϯ' => 'Ϯ', 'ϰ' => 'Κ', 'ϱ' => 'Ρ', 'ϲ' => 'Ϲ', 'ϳ' => 'Ϳ', 'ϵ' => 'Ε', 'ϸ' => 'Ϸ', 'ϻ' => 'Ϻ', 'а' => 'А', 'б' => 'Б', 'в' => 'В', 'г' => 'Г', 'д' => 'Д', 'е' => 'Е', 'ж' => 'Ж', 'з' => 'З', 'и' => 'И', 'й' => 'Й', 'к' => 'К', 'л' => 'Л', 'м' => 'М', 'н' => 'Н', 'о' => 'О', 'п' => 'П', 'р' => 'Р', 'с' => 'С', 'т' => 'Т', 'у' => 'У', 'ф' => 'Ф', 'х' => 'Х', 'ц' => 'Ц', 'ч' => 'Ч', 'ш' => 'Ш', 'щ' => 'Щ', 'ъ' => 'Ъ', 'ы' => 'Ы', 'ь' => 'Ь', 'э' => 'Э', 'ю' => 'Ю', 'я' => 'Я', 'ѐ' => 'Ѐ', 'ё' => 'Ё', 'ђ' => 'Ђ', 'ѓ' => 'Ѓ', 'є' => 'Є', 'ѕ' => 'Ѕ', 'і' => 'І', 'ї' => 'Ї', 'ј' => 'Ј', 'љ' => 'Љ', 'њ' => 'Њ', 'ћ' => 'Ћ', 'ќ' => 'Ќ', 'ѝ' => 'Ѝ', 'ў' => 'Ў', 'џ' => 'Џ', 'ѡ' => 'Ѡ', 'ѣ' => 'Ѣ', 'ѥ' => 'Ѥ', 'ѧ' => 'Ѧ', 'ѩ' => 'Ѩ', 'ѫ' => 'Ѫ', 'ѭ' => 'Ѭ', 'ѯ' => 'Ѯ', 'ѱ' => 'Ѱ', 'ѳ' => 'Ѳ', 'ѵ' => 'Ѵ', 'ѷ' => 'Ѷ', 'ѹ' => 'Ѹ', 'ѻ' => 'Ѻ', 'ѽ' => 'Ѽ', 'ѿ' => 'Ѿ', 'ҁ' => 'Ҁ', 'ҋ' => 'Ҋ', 'ҍ' => 'Ҍ', 'ҏ' => 'Ҏ', 'ґ' => 'Ґ', 'ғ' => 'Ғ', 'ҕ' => 'Ҕ', 'җ' => 'Җ', 'ҙ' => 'Ҙ', 'қ' => 'Қ', 'ҝ' => 'Ҝ', 'ҟ' => 'Ҟ', 'ҡ' => 'Ҡ', 'ң' => 'Ң', 'ҥ' => 'Ҥ', 'ҧ' => 'Ҧ', 'ҩ' => 'Ҩ', 'ҫ' => 'Ҫ', 'ҭ' => 'Ҭ', 'ү' => 'Ү', 'ұ' => 'Ұ', 'ҳ' => 'Ҳ', 'ҵ' => 'Ҵ', 'ҷ' => 'Ҷ', 'ҹ' => 'Ҹ', 'һ' => 'Һ', 'ҽ' => 'Ҽ', 'ҿ' => 'Ҿ', 'ӂ' => 'Ӂ', 'ӄ' => 'Ӄ', 'ӆ' => 'Ӆ', 'ӈ' => 'Ӈ', 'ӊ' => 'Ӊ', 'ӌ' => 'Ӌ', 'ӎ' => 'Ӎ', 'ӏ' => 'Ӏ', 'ӑ' => 'Ӑ', 'ӓ' => 'Ӓ', 'ӕ' => 'Ӕ', 'ӗ' => 'Ӗ', 'ә' => 'Ә', 'ӛ' => 'Ӛ', 'ӝ' => 'Ӝ', 'ӟ' => 'Ӟ', 'ӡ' => 'Ӡ', 'ӣ' => 'Ӣ', 'ӥ' => 'Ӥ', 'ӧ' => 'Ӧ', 'ө' => 'Ө', 'ӫ' => 'Ӫ', 'ӭ' => 'Ӭ', 'ӯ' => 'Ӯ', 'ӱ' => 'Ӱ', 'ӳ' => 'Ӳ', 'ӵ' => 'Ӵ', 'ӷ' => 'Ӷ', 'ӹ' => 'Ӹ', 'ӻ' => 'Ӻ', 'ӽ' => 'Ӽ', 'ӿ' => 'Ӿ', 'ԁ' => 'Ԁ', 'ԃ' => 'Ԃ', 'ԅ' => 'Ԅ', 'ԇ' => 'Ԇ', 'ԉ' => 'Ԉ', 'ԋ' => 'Ԋ', 'ԍ' => 'Ԍ', 'ԏ' => 'Ԏ', 'ԑ' => 'Ԑ', 'ԓ' => 'Ԓ', 'ԕ' => 'Ԕ', 'ԗ' => 'Ԗ', 'ԙ' => 'Ԙ', 'ԛ' => 'Ԛ', 'ԝ' => 'Ԝ', 'ԟ' => 'Ԟ', 'ԡ' => 'Ԡ', 'ԣ' => 'Ԣ', 'ԥ' => 'Ԥ', 'ԧ' => 'Ԧ', 'ԩ' => 'Ԩ', 'ԫ' => 'Ԫ', 'ԭ' => 'Ԭ', 'ԯ' => 'Ԯ', 'ա' => 'Ա', 'բ' => 'Բ', 'գ' => 'Գ', 'դ' => 'Դ', 'ե' => 'Ե', 'զ' => 'Զ', 'է' => 'Է', 'ը' => 'Ը', 'թ' => 'Թ', 'ժ' => 'Ժ', 'ի' => 'Ի', 'լ' => 'Լ', 'խ' => 'Խ', 'ծ' => 'Ծ', 'կ' => 'Կ', 'հ' => 'Հ', 'ձ' => 'Ձ', 'ղ' => 'Ղ', 'ճ' => 'Ճ', 'մ' => 'Մ', 'յ' => 'Յ', 'ն' => 'Ն', 'շ' => 'Շ', 'ո' => 'Ո', 'չ' => 'Չ', 'պ' => 'Պ', 'ջ' => 'Ջ', 'ռ' => 'Ռ', 'ս' => 'Ս', 'վ' => 'Վ', 'տ' => 'Տ', 'ր' => 'Ր', 'ց' => 'Ց', 'ւ' => 'Ւ', 'փ' => 'Փ', 'ք' => 'Ք', 'օ' => 'Օ', 'ֆ' => 'Ֆ', 'ა' => 'Ა', 'ბ' => 'Ბ', 'გ' => 'Გ', 'დ' => 'Დ', 'ე' => 'Ე', 'ვ' => 'Ვ', 'ზ' => 'Ზ', 'თ' => 'Თ', 'ი' => 'Ი', 'კ' => 'Კ', 'ლ' => 'Ლ', 'მ' => 'Მ', 'ნ' => 'Ნ', 'ო' => 'Ო', 'პ' => 'Პ', 'ჟ' => 'Ჟ', 'რ' => 'Რ', 'ს' => 'Ს', 'ტ' => 'Ტ', 'უ' => 'Უ', 'ფ' => 'Ფ', 'ქ' => 'Ქ', 'ღ' => 'Ღ', 'ყ' => 'Ყ', 'შ' => 'Შ', 'ჩ' => 'Ჩ', 'ც' => 'Ც', 'ძ' => 'Ძ', 'წ' => 'Წ', 'ჭ' => 'Ჭ', 'ხ' => 'Ხ', 'ჯ' => 'Ჯ', 'ჰ' => 'Ჰ', 'ჱ' => 'Ჱ', 'ჲ' => 'Ჲ', 'ჳ' => 'Ჳ', 'ჴ' => 'Ჴ', 'ჵ' => 'Ჵ', 'ჶ' => 'Ჶ', 'ჷ' => 'Ჷ', 'ჸ' => 'Ჸ', 'ჹ' => 'Ჹ', 'ჺ' => 'Ჺ', 'ჽ' => 'Ჽ', 'ჾ' => 'Ჾ', 'ჿ' => 'Ჿ', 'ᏸ' => 'Ᏸ', 'ᏹ' => 'Ᏹ', 'ᏺ' => 'Ᏺ', 'ᏻ' => 'Ᏻ', 'ᏼ' => 'Ᏼ', 'ᏽ' => 'Ᏽ', 'ᲀ' => 'В', 'ᲁ' => 'Д', 'ᲂ' => 'О', 'ᲃ' => 'С', 'ᲄ' => 'Т', 'ᲅ' => 'Т', 'ᲆ' => 'Ъ', 'ᲇ' => 'Ѣ', 'ᲈ' => 'Ꙋ', 'ᵹ' => 'Ᵹ', 'ᵽ' => 'Ᵽ', 'ᶎ' => 'Ᶎ', 'ḁ' => 'Ḁ', 'ḃ' => 'Ḃ', 'ḅ' => 'Ḅ', 'ḇ' => 'Ḇ', 'ḉ' => 'Ḉ', 'ḋ' => 'Ḋ', 'ḍ' => 'Ḍ', 'ḏ' => 'Ḏ', 'ḑ' => 'Ḑ', 'ḓ' => 'Ḓ', 'ḕ' => 'Ḕ', 'ḗ' => 'Ḗ', 'ḙ' => 'Ḙ', 'ḛ' => 'Ḛ', 'ḝ' => 'Ḝ', 'ḟ' => 'Ḟ', 'ḡ' => 'Ḡ', 'ḣ' => 'Ḣ', 'ḥ' => 'Ḥ', 'ḧ' => 'Ḧ', 'ḩ' => 'Ḩ', 'ḫ' => 'Ḫ', 'ḭ' => 'Ḭ', 'ḯ' => 'Ḯ', 'ḱ' => 'Ḱ', 'ḳ' => 'Ḳ', 'ḵ' => 'Ḵ', 'ḷ' => 'Ḷ', 'ḹ' => 'Ḹ', 'ḻ' => 'Ḻ', 'ḽ' => 'Ḽ', 'ḿ' => 'Ḿ', 'ṁ' => 'Ṁ', 'ṃ' => 'Ṃ', 'ṅ' => 'Ṅ', 'ṇ' => 'Ṇ', 'ṉ' => 'Ṉ', 'ṋ' => 'Ṋ', 'ṍ' => 'Ṍ', 'ṏ' => 'Ṏ', 'ṑ' => 'Ṑ', 'ṓ' => 'Ṓ', 'ṕ' => 'Ṕ', 'ṗ' => 'Ṗ', 'ṙ' => 'Ṙ', 'ṛ' => 'Ṛ', 'ṝ' => 'Ṝ', 'ṟ' => 'Ṟ', 'ṡ' => 'Ṡ', 'ṣ' => 'Ṣ', 'ṥ' => 'Ṥ', 'ṧ' => 'Ṧ', 'ṩ' => 'Ṩ', 'ṫ' => 'Ṫ', 'ṭ' => 'Ṭ', 'ṯ' => 'Ṯ', 'ṱ' => 'Ṱ', 'ṳ' => 'Ṳ', 'ṵ' => 'Ṵ', 'ṷ' => 'Ṷ', 'ṹ' => 'Ṹ', 'ṻ' => 'Ṻ', 'ṽ' => 'Ṽ', 'ṿ' => 'Ṿ', 'ẁ' => 'Ẁ', 'ẃ' => 'Ẃ', 'ẅ' => 'Ẅ', 'ẇ' => 'Ẇ', 'ẉ' => 'Ẉ', 'ẋ' => 'Ẋ', 'ẍ' => 'Ẍ', 'ẏ' => 'Ẏ', 'ẑ' => 'Ẑ', 'ẓ' => 'Ẓ', 'ẕ' => 'Ẕ', 'ẛ' => 'Ṡ', 'ạ' => 'Ạ', 'ả' => 'Ả', 'ấ' => 'Ấ', 'ầ' => 'Ầ', 'ẩ' => 'Ẩ', 'ẫ' => 'Ẫ', 'ậ' => 'Ậ', 'ắ' => 'Ắ', 'ằ' => 'Ằ', 'ẳ' => 'Ẳ', 'ẵ' => 'Ẵ', 'ặ' => 'Ặ', 'ẹ' => 'Ẹ', 'ẻ' => 'Ẻ', 'ẽ' => 'Ẽ', 'ế' => 'Ế', 'ề' => 'Ề', 'ể' => 'Ể', 'ễ' => 'Ễ', 'ệ' => 'Ệ', 'ỉ' => 'Ỉ', 'ị' => 'Ị', 'ọ' => 'Ọ', 'ỏ' => 'Ỏ', 'ố' => 'Ố', 'ồ' => 'Ồ', 'ổ' => 'Ổ', 'ỗ' => 'Ỗ', 'ộ' => 'Ộ', 'ớ' => 'Ớ', 'ờ' => 'Ờ', 'ở' => 'Ở', 'ỡ' => 'Ỡ', 'ợ' => 'Ợ', 'ụ' => 'Ụ', 'ủ' => 'Ủ', 'ứ' => 'Ứ', 'ừ' => 'Ừ', 'ử' => 'Ử', 'ữ' => 'Ữ', 'ự' => 'Ự', 'ỳ' => 'Ỳ', 'ỵ' => 'Ỵ', 'ỷ' => 'Ỷ', 'ỹ' => 'Ỹ', 'ỻ' => 'Ỻ', 'ỽ' => 'Ỽ', 'ỿ' => 'Ỿ', 'ἀ' => 'Ἀ', 'ἁ' => 'Ἁ', 'ἂ' => 'Ἂ', 'ἃ' => 'Ἃ', 'ἄ' => 'Ἄ', 'ἅ' => 'Ἅ', 'ἆ' => 'Ἆ', 'ἇ' => 'Ἇ', 'ἐ' => 'Ἐ', 'ἑ' => 'Ἑ', 'ἒ' => 'Ἒ', 'ἓ' => 'Ἓ', 'ἔ' => 'Ἔ', 'ἕ' => 'Ἕ', 'ἠ' => 'Ἠ', 'ἡ' => 'Ἡ', 'ἢ' => 'Ἢ', 'ἣ' => 'Ἣ', 'ἤ' => 'Ἤ', 'ἥ' => 'Ἥ', 'ἦ' => 'Ἦ', 'ἧ' => 'Ἧ', 'ἰ' => 'Ἰ', 'ἱ' => 'Ἱ', 'ἲ' => 'Ἲ', 'ἳ' => 'Ἳ', 'ἴ' => 'Ἴ', 'ἵ' => 'Ἵ', 'ἶ' => 'Ἶ', 'ἷ' => 'Ἷ', 'ὀ' => 'Ὀ', 'ὁ' => 'Ὁ', 'ὂ' => 'Ὂ', 'ὃ' => 'Ὃ', 'ὄ' => 'Ὄ', 'ὅ' => 'Ὅ', 'ὑ' => 'Ὑ', 'ὓ' => 'Ὓ', 'ὕ' => 'Ὕ', 'ὗ' => 'Ὗ', 'ὠ' => 'Ὠ', 'ὡ' => 'Ὡ', 'ὢ' => 'Ὢ', 'ὣ' => 'Ὣ', 'ὤ' => 'Ὤ', 'ὥ' => 'Ὥ', 'ὦ' => 'Ὦ', 'ὧ' => 'Ὧ', 'ὰ' => 'Ὰ', 'ά' => 'Ά', 'ὲ' => 'Ὲ', 'έ' => 'Έ', 'ὴ' => 'Ὴ', 'ή' => 'Ή', 'ὶ' => 'Ὶ', 'ί' => 'Ί', 'ὸ' => 'Ὸ', 'ό' => 'Ό', 'ὺ' => 'Ὺ', 'ύ' => 'Ύ', 'ὼ' => 'Ὼ', 'ώ' => 'Ώ', 'ᾀ' => 'ἈΙ', 'ᾁ' => 'ἉΙ', 'ᾂ' => 'ἊΙ', 'ᾃ' => 'ἋΙ', 'ᾄ' => 'ἌΙ', 'ᾅ' => 'ἍΙ', 'ᾆ' => 'ἎΙ', 'ᾇ' => 'ἏΙ', 'ᾐ' => 'ἨΙ', 'ᾑ' => 'ἩΙ', 'ᾒ' => 'ἪΙ', 'ᾓ' => 'ἫΙ', 'ᾔ' => 'ἬΙ', 'ᾕ' => 'ἭΙ', 'ᾖ' => 'ἮΙ', 'ᾗ' => 'ἯΙ', 'ᾠ' => 'ὨΙ', 'ᾡ' => 'ὩΙ', 'ᾢ' => 'ὪΙ', 'ᾣ' => 'ὫΙ', 'ᾤ' => 'ὬΙ', 'ᾥ' => 'ὭΙ', 'ᾦ' => 'ὮΙ', 'ᾧ' => 'ὯΙ', 'ᾰ' => 'Ᾰ', 'ᾱ' => 'Ᾱ', 'ᾳ' => 'ΑΙ', 'ι' => 'Ι', 'ῃ' => 'ΗΙ', 'ῐ' => 'Ῐ', 'ῑ' => 'Ῑ', 'ῠ' => 'Ῠ', 'ῡ' => 'Ῡ', 'ῥ' => 'Ῥ', 'ῳ' => 'ΩΙ', 'ⅎ' => 'Ⅎ', 'ⅰ' => 'Ⅰ', 'ⅱ' => 'Ⅱ', 'ⅲ' => 'Ⅲ', 'ⅳ' => 'Ⅳ', 'ⅴ' => 'Ⅴ', 'ⅵ' => 'Ⅵ', 'ⅶ' => 'Ⅶ', 'ⅷ' => 'Ⅷ', 'ⅸ' => 'Ⅸ', 'ⅹ' => 'Ⅹ', 'ⅺ' => 'Ⅺ', 'ⅻ' => 'Ⅻ', 'ⅼ' => 'Ⅼ', 'ⅽ' => 'Ⅽ', 'ⅾ' => 'Ⅾ', 'ⅿ' => 'Ⅿ', 'ↄ' => 'Ↄ', 'ⓐ' => 'Ⓐ', 'ⓑ' => 'Ⓑ', 'ⓒ' => 'Ⓒ', 'ⓓ' => 'Ⓓ', 'ⓔ' => 'Ⓔ', 'ⓕ' => 'Ⓕ', 'ⓖ' => 'Ⓖ', 'ⓗ' => 'Ⓗ', 'ⓘ' => 'Ⓘ', 'ⓙ' => 'Ⓙ', 'ⓚ' => 'Ⓚ', 'ⓛ' => 'Ⓛ', 'ⓜ' => 'Ⓜ', 'ⓝ' => 'Ⓝ', 'ⓞ' => 'Ⓞ', 'ⓟ' => 'Ⓟ', 'ⓠ' => 'Ⓠ', 'ⓡ' => 'Ⓡ', 'ⓢ' => 'Ⓢ', 'ⓣ' => 'Ⓣ', 'ⓤ' => 'Ⓤ', 'ⓥ' => 'Ⓥ', 'ⓦ' => 'Ⓦ', 'ⓧ' => 'Ⓧ', 'ⓨ' => 'Ⓨ', 'ⓩ' => 'Ⓩ', 'ⰰ' => 'Ⰰ', 'ⰱ' => 'Ⰱ', 'ⰲ' => 'Ⰲ', 'ⰳ' => 'Ⰳ', 'ⰴ' => 'Ⰴ', 'ⰵ' => 'Ⰵ', 'ⰶ' => 'Ⰶ', 'ⰷ' => 'Ⰷ', 'ⰸ' => 'Ⰸ', 'ⰹ' => 'Ⰹ', 'ⰺ' => 'Ⰺ', 'ⰻ' => 'Ⰻ', 'ⰼ' => 'Ⰼ', 'ⰽ' => 'Ⰽ', 'ⰾ' => 'Ⰾ', 'ⰿ' => 'Ⰿ', 'ⱀ' => 'Ⱀ', 'ⱁ' => 'Ⱁ', 'ⱂ' => 'Ⱂ', 'ⱃ' => 'Ⱃ', 'ⱄ' => 'Ⱄ', 'ⱅ' => 'Ⱅ', 'ⱆ' => 'Ⱆ', 'ⱇ' => 'Ⱇ', 'ⱈ' => 'Ⱈ', 'ⱉ' => 'Ⱉ', 'ⱊ' => 'Ⱊ', 'ⱋ' => 'Ⱋ', 'ⱌ' => 'Ⱌ', 'ⱍ' => 'Ⱍ', 'ⱎ' => 'Ⱎ', 'ⱏ' => 'Ⱏ', 'ⱐ' => 'Ⱐ', 'ⱑ' => 'Ⱑ', 'ⱒ' => 'Ⱒ', 'ⱓ' => 'Ⱓ', 'ⱔ' => 'Ⱔ', 'ⱕ' => 'Ⱕ', 'ⱖ' => 'Ⱖ', 'ⱗ' => 'Ⱗ', 'ⱘ' => 'Ⱘ', 'ⱙ' => 'Ⱙ', 'ⱚ' => 'Ⱚ', 'ⱛ' => 'Ⱛ', 'ⱜ' => 'Ⱜ', 'ⱝ' => 'Ⱝ', 'ⱞ' => 'Ⱞ', 'ⱡ' => 'Ⱡ', 'ⱥ' => 'Ⱥ', 'ⱦ' => 'Ⱦ', 'ⱨ' => 'Ⱨ', 'ⱪ' => 'Ⱪ', 'ⱬ' => 'Ⱬ', 'ⱳ' => 'Ⱳ', 'ⱶ' => 'Ⱶ', 'ⲁ' => 'Ⲁ', 'ⲃ' => 'Ⲃ', 'ⲅ' => 'Ⲅ', 'ⲇ' => 'Ⲇ', 'ⲉ' => 'Ⲉ', 'ⲋ' => 'Ⲋ', 'ⲍ' => 'Ⲍ', 'ⲏ' => 'Ⲏ', 'ⲑ' => 'Ⲑ', 'ⲓ' => 'Ⲓ', 'ⲕ' => 'Ⲕ', 'ⲗ' => 'Ⲗ', 'ⲙ' => 'Ⲙ', 'ⲛ' => 'Ⲛ', 'ⲝ' => 'Ⲝ', 'ⲟ' => 'Ⲟ', 'ⲡ' => 'Ⲡ', 'ⲣ' => 'Ⲣ', 'ⲥ' => 'Ⲥ', 'ⲧ' => 'Ⲧ', 'ⲩ' => 'Ⲩ', 'ⲫ' => 'Ⲫ', 'ⲭ' => 'Ⲭ', 'ⲯ' => 'Ⲯ', 'ⲱ' => 'Ⲱ', 'ⲳ' => 'Ⲳ', 'ⲵ' => 'Ⲵ', 'ⲷ' => 'Ⲷ', 'ⲹ' => 'Ⲹ', 'ⲻ' => 'Ⲻ', 'ⲽ' => 'Ⲽ', 'ⲿ' => 'Ⲿ', 'ⳁ' => 'Ⳁ', 'ⳃ' => 'Ⳃ', 'ⳅ' => 'Ⳅ', 'ⳇ' => 'Ⳇ', 'ⳉ' => 'Ⳉ', 'ⳋ' => 'Ⳋ', 'ⳍ' => 'Ⳍ', 'ⳏ' => 'Ⳏ', 'ⳑ' => 'Ⳑ', 'ⳓ' => 'Ⳓ', 'ⳕ' => 'Ⳕ', 'ⳗ' => 'Ⳗ', 'ⳙ' => 'Ⳙ', 'ⳛ' => 'Ⳛ', 'ⳝ' => 'Ⳝ', 'ⳟ' => 'Ⳟ', 'ⳡ' => 'Ⳡ', 'ⳣ' => 'Ⳣ', 'ⳬ' => 'Ⳬ', 'ⳮ' => 'Ⳮ', 'ⳳ' => 'Ⳳ', 'ⴀ' => 'Ⴀ', 'ⴁ' => 'Ⴁ', 'ⴂ' => 'Ⴂ', 'ⴃ' => 'Ⴃ', 'ⴄ' => 'Ⴄ', 'ⴅ' => 'Ⴅ', 'ⴆ' => 'Ⴆ', 'ⴇ' => 'Ⴇ', 'ⴈ' => 'Ⴈ', 'ⴉ' => 'Ⴉ', 'ⴊ' => 'Ⴊ', 'ⴋ' => 'Ⴋ', 'ⴌ' => 'Ⴌ', 'ⴍ' => 'Ⴍ', 'ⴎ' => 'Ⴎ', 'ⴏ' => 'Ⴏ', 'ⴐ' => 'Ⴐ', 'ⴑ' => 'Ⴑ', 'ⴒ' => 'Ⴒ', 'ⴓ' => 'Ⴓ', 'ⴔ' => 'Ⴔ', 'ⴕ' => 'Ⴕ', 'ⴖ' => 'Ⴖ', 'ⴗ' => 'Ⴗ', 'ⴘ' => 'Ⴘ', 'ⴙ' => 'Ⴙ', 'ⴚ' => 'Ⴚ', 'ⴛ' => 'Ⴛ', 'ⴜ' => 'Ⴜ', 'ⴝ' => 'Ⴝ', 'ⴞ' => 'Ⴞ', 'ⴟ' => 'Ⴟ', 'ⴠ' => 'Ⴠ', 'ⴡ' => 'Ⴡ', 'ⴢ' => 'Ⴢ', 'ⴣ' => 'Ⴣ', 'ⴤ' => 'Ⴤ', 'ⴥ' => 'Ⴥ', 'ⴧ' => 'Ⴧ', 'ⴭ' => 'Ⴭ', 'ꙁ' => 'Ꙁ', 'ꙃ' => 'Ꙃ', 'ꙅ' => 'Ꙅ', 'ꙇ' => 'Ꙇ', 'ꙉ' => 'Ꙉ', 'ꙋ' => 'Ꙋ', 'ꙍ' => 'Ꙍ', 'ꙏ' => 'Ꙏ', 'ꙑ' => 'Ꙑ', 'ꙓ' => 'Ꙓ', 'ꙕ' => 'Ꙕ', 'ꙗ' => 'Ꙗ', 'ꙙ' => 'Ꙙ', 'ꙛ' => 'Ꙛ', 'ꙝ' => 'Ꙝ', 'ꙟ' => 'Ꙟ', 'ꙡ' => 'Ꙡ', 'ꙣ' => 'Ꙣ', 'ꙥ' => 'Ꙥ', 'ꙧ' => 'Ꙧ', 'ꙩ' => 'Ꙩ', 'ꙫ' => 'Ꙫ', 'ꙭ' => 'Ꙭ', 'ꚁ' => 'Ꚁ', 'ꚃ' => 'Ꚃ', 'ꚅ' => 'Ꚅ', 'ꚇ' => 'Ꚇ', 'ꚉ' => 'Ꚉ', 'ꚋ' => 'Ꚋ', 'ꚍ' => 'Ꚍ', 'ꚏ' => 'Ꚏ', 'ꚑ' => 'Ꚑ', 'ꚓ' => 'Ꚓ', 'ꚕ' => 'Ꚕ', 'ꚗ' => 'Ꚗ', 'ꚙ' => 'Ꚙ', 'ꚛ' => 'Ꚛ', 'ꜣ' => 'Ꜣ', 'ꜥ' => 'Ꜥ', 'ꜧ' => 'Ꜧ', 'ꜩ' => 'Ꜩ', 'ꜫ' => 'Ꜫ', 'ꜭ' => 'Ꜭ', 'ꜯ' => 'Ꜯ', 'ꜳ' => 'Ꜳ', 'ꜵ' => 'Ꜵ', 'ꜷ' => 'Ꜷ', 'ꜹ' => 'Ꜹ', 'ꜻ' => 'Ꜻ', 'ꜽ' => 'Ꜽ', 'ꜿ' => 'Ꜿ', 'ꝁ' => 'Ꝁ', 'ꝃ' => 'Ꝃ', 'ꝅ' => 'Ꝅ', 'ꝇ' => 'Ꝇ', 'ꝉ' => 'Ꝉ', 'ꝋ' => 'Ꝋ', 'ꝍ' => 'Ꝍ', 'ꝏ' => 'Ꝏ', 'ꝑ' => 'Ꝑ', 'ꝓ' => 'Ꝓ', 'ꝕ' => 'Ꝕ', 'ꝗ' => 'Ꝗ', 'ꝙ' => 'Ꝙ', 'ꝛ' => 'Ꝛ', 'ꝝ' => 'Ꝝ', 'ꝟ' => 'Ꝟ', 'ꝡ' => 'Ꝡ', 'ꝣ' => 'Ꝣ', 'ꝥ' => 'Ꝥ', 'ꝧ' => 'Ꝧ', 'ꝩ' => 'Ꝩ', 'ꝫ' => 'Ꝫ', 'ꝭ' => 'Ꝭ', 'ꝯ' => 'Ꝯ', 'ꝺ' => 'Ꝺ', 'ꝼ' => 'Ꝼ', 'ꝿ' => 'Ꝿ', 'ꞁ' => 'Ꞁ', 'ꞃ' => 'Ꞃ', 'ꞅ' => 'Ꞅ', 'ꞇ' => 'Ꞇ', 'ꞌ' => 'Ꞌ', 'ꞑ' => 'Ꞑ', 'ꞓ' => 'Ꞓ', 'ꞔ' => 'Ꞔ', 'ꞗ' => 'Ꞗ', 'ꞙ' => 'Ꞙ', 'ꞛ' => 'Ꞛ', 'ꞝ' => 'Ꞝ', 'ꞟ' => 'Ꞟ', 'ꞡ' => 'Ꞡ', 'ꞣ' => 'Ꞣ', 'ꞥ' => 'Ꞥ', 'ꞧ' => 'Ꞧ', 'ꞩ' => 'Ꞩ', 'ꞵ' => 'Ꞵ', 'ꞷ' => 'Ꞷ', 'ꞹ' => 'Ꞹ', 'ꞻ' => 'Ꞻ', 'ꞽ' => 'Ꞽ', 'ꞿ' => 'Ꞿ', 'ꟃ' => 'Ꟃ', 'ꟈ' => 'Ꟈ', 'ꟊ' => 'Ꟊ', 'ꟶ' => 'Ꟶ', 'ꭓ' => 'Ꭓ', 'ꭰ' => 'Ꭰ', 'ꭱ' => 'Ꭱ', 'ꭲ' => 'Ꭲ', 'ꭳ' => 'Ꭳ', 'ꭴ' => 'Ꭴ', 'ꭵ' => 'Ꭵ', 'ꭶ' => 'Ꭶ', 'ꭷ' => 'Ꭷ', 'ꭸ' => 'Ꭸ', 'ꭹ' => 'Ꭹ', 'ꭺ' => 'Ꭺ', 'ꭻ' => 'Ꭻ', 'ꭼ' => 'Ꭼ', 'ꭽ' => 'Ꭽ', 'ꭾ' => 'Ꭾ', 'ꭿ' => 'Ꭿ', 'ꮀ' => 'Ꮀ', 'ꮁ' => 'Ꮁ', 'ꮂ' => 'Ꮂ', 'ꮃ' => 'Ꮃ', 'ꮄ' => 'Ꮄ', 'ꮅ' => 'Ꮅ', 'ꮆ' => 'Ꮆ', 'ꮇ' => 'Ꮇ', 'ꮈ' => 'Ꮈ', 'ꮉ' => 'Ꮉ', 'ꮊ' => 'Ꮊ', 'ꮋ' => 'Ꮋ', 'ꮌ' => 'Ꮌ', 'ꮍ' => 'Ꮍ', 'ꮎ' => 'Ꮎ', 'ꮏ' => 'Ꮏ', 'ꮐ' => 'Ꮐ', 'ꮑ' => 'Ꮑ', 'ꮒ' => 'Ꮒ', 'ꮓ' => 'Ꮓ', 'ꮔ' => 'Ꮔ', 'ꮕ' => 'Ꮕ', 'ꮖ' => 'Ꮖ', 'ꮗ' => 'Ꮗ', 'ꮘ' => 'Ꮘ', 'ꮙ' => 'Ꮙ', 'ꮚ' => 'Ꮚ', 'ꮛ' => 'Ꮛ', 'ꮜ' => 'Ꮜ', 'ꮝ' => 'Ꮝ', 'ꮞ' => 'Ꮞ', 'ꮟ' => 'Ꮟ', 'ꮠ' => 'Ꮠ', 'ꮡ' => 'Ꮡ', 'ꮢ' => 'Ꮢ', 'ꮣ' => 'Ꮣ', 'ꮤ' => 'Ꮤ', 'ꮥ' => 'Ꮥ', 'ꮦ' => 'Ꮦ', 'ꮧ' => 'Ꮧ', 'ꮨ' => 'Ꮨ', 'ꮩ' => 'Ꮩ', 'ꮪ' => 'Ꮪ', 'ꮫ' => 'Ꮫ', 'ꮬ' => 'Ꮬ', 'ꮭ' => 'Ꮭ', 'ꮮ' => 'Ꮮ', 'ꮯ' => 'Ꮯ', 'ꮰ' => 'Ꮰ', 'ꮱ' => 'Ꮱ', 'ꮲ' => 'Ꮲ', 'ꮳ' => 'Ꮳ', 'ꮴ' => 'Ꮴ', 'ꮵ' => 'Ꮵ', 'ꮶ' => 'Ꮶ', 'ꮷ' => 'Ꮷ', 'ꮸ' => 'Ꮸ', 'ꮹ' => 'Ꮹ', 'ꮺ' => 'Ꮺ', 'ꮻ' => 'Ꮻ', 'ꮼ' => 'Ꮼ', 'ꮽ' => 'Ꮽ', 'ꮾ' => 'Ꮾ', 'ꮿ' => 'Ꮿ', 'a' => 'A', 'b' => 'B', 'c' => 'C', 'd' => 'D', 'e' => 'E', 'f' => 'F', 'g' => 'G', 'h' => 'H', 'i' => 'I', 'j' => 'J', 'k' => 'K', 'l' => 'L', 'm' => 'M', 'n' => 'N', 'o' => 'O', 'p' => 'P', 'q' => 'Q', 'r' => 'R', 's' => 'S', 't' => 'T', 'u' => 'U', 'v' => 'V', 'w' => 'W', 'x' => 'X', 'y' => 'Y', 'z' => 'Z', '𐐨' => '𐐀', '𐐩' => '𐐁', '𐐪' => '𐐂', '𐐫' => '𐐃', '𐐬' => '𐐄', '𐐭' => '𐐅', '𐐮' => '𐐆', '𐐯' => '𐐇', '𐐰' => '𐐈', '𐐱' => '𐐉', '𐐲' => '𐐊', '𐐳' => '𐐋', '𐐴' => '𐐌', '𐐵' => '𐐍', '𐐶' => '𐐎', '𐐷' => '𐐏', '𐐸' => '𐐐', '𐐹' => '𐐑', '𐐺' => '𐐒', '𐐻' => '𐐓', '𐐼' => '𐐔', '𐐽' => '𐐕', '𐐾' => '𐐖', '𐐿' => '𐐗', '𐑀' => '𐐘', '𐑁' => '𐐙', '𐑂' => '𐐚', '𐑃' => '𐐛', '𐑄' => '𐐜', '𐑅' => '𐐝', '𐑆' => '𐐞', '𐑇' => '𐐟', '𐑈' => '𐐠', '𐑉' => '𐐡', '𐑊' => '𐐢', '𐑋' => '𐐣', '𐑌' => '𐐤', '𐑍' => '𐐥', '𐑎' => '𐐦', '𐑏' => '𐐧', '𐓘' => '𐒰', '𐓙' => '𐒱', '𐓚' => '𐒲', '𐓛' => '𐒳', '𐓜' => '𐒴', '𐓝' => '𐒵', '𐓞' => '𐒶', '𐓟' => '𐒷', '𐓠' => '𐒸', '𐓡' => '𐒹', '𐓢' => '𐒺', '𐓣' => '𐒻', '𐓤' => '𐒼', '𐓥' => '𐒽', '𐓦' => '𐒾', '𐓧' => '𐒿', '𐓨' => '𐓀', '𐓩' => '𐓁', '𐓪' => '𐓂', '𐓫' => '𐓃', '𐓬' => '𐓄', '𐓭' => '𐓅', '𐓮' => '𐓆', '𐓯' => '𐓇', '𐓰' => '𐓈', '𐓱' => '𐓉', '𐓲' => '𐓊', '𐓳' => '𐓋', '𐓴' => '𐓌', '𐓵' => '𐓍', '𐓶' => '𐓎', '𐓷' => '𐓏', '𐓸' => '𐓐', '𐓹' => '𐓑', '𐓺' => '𐓒', '𐓻' => '𐓓', '𐳀' => '𐲀', '𐳁' => '𐲁', '𐳂' => '𐲂', '𐳃' => '𐲃', '𐳄' => '𐲄', '𐳅' => '𐲅', '𐳆' => '𐲆', '𐳇' => '𐲇', '𐳈' => '𐲈', '𐳉' => '𐲉', '𐳊' => '𐲊', '𐳋' => '𐲋', '𐳌' => '𐲌', '𐳍' => '𐲍', '𐳎' => '𐲎', '𐳏' => '𐲏', '𐳐' => '𐲐', '𐳑' => '𐲑', '𐳒' => '𐲒', '𐳓' => '𐲓', '𐳔' => '𐲔', '𐳕' => '𐲕', '𐳖' => '𐲖', '𐳗' => '𐲗', '𐳘' => '𐲘', '𐳙' => '𐲙', '𐳚' => '𐲚', '𐳛' => '𐲛', '𐳜' => '𐲜', '𐳝' => '𐲝', '𐳞' => '𐲞', '𐳟' => '𐲟', '𐳠' => '𐲠', '𐳡' => '𐲡', '𐳢' => '𐲢', '𐳣' => '𐲣', '𐳤' => '𐲤', '𐳥' => '𐲥', '𐳦' => '𐲦', '𐳧' => '𐲧', '𐳨' => '𐲨', '𐳩' => '𐲩', '𐳪' => '𐲪', '𐳫' => '𐲫', '𐳬' => '𐲬', '𐳭' => '𐲭', '𐳮' => '𐲮', '𐳯' => '𐲯', '𐳰' => '𐲰', '𐳱' => '𐲱', '𐳲' => '𐲲', '𑣀' => '𑢠', '𑣁' => '𑢡', '𑣂' => '𑢢', '𑣃' => '𑢣', '𑣄' => '𑢤', '𑣅' => '𑢥', '𑣆' => '𑢦', '𑣇' => '𑢧', '𑣈' => '𑢨', '𑣉' => '𑢩', '𑣊' => '𑢪', '𑣋' => '𑢫', '𑣌' => '𑢬', '𑣍' => '𑢭', '𑣎' => '𑢮', '𑣏' => '𑢯', '𑣐' => '𑢰', '𑣑' => '𑢱', '𑣒' => '𑢲', '𑣓' => '𑢳', '𑣔' => '𑢴', '𑣕' => '𑢵', '𑣖' => '𑢶', '𑣗' => '𑢷', '𑣘' => '𑢸', '𑣙' => '𑢹', '𑣚' => '𑢺', '𑣛' => '𑢻', '𑣜' => '𑢼', '𑣝' => '𑢽', '𑣞' => '𑢾', '𑣟' => '𑢿', '𖹠' => '𖹀', '𖹡' => '𖹁', '𖹢' => '𖹂', '𖹣' => '𖹃', '𖹤' => '𖹄', '𖹥' => '𖹅', '𖹦' => '𖹆', '𖹧' => '𖹇', '𖹨' => '𖹈', '𖹩' => '𖹉', '𖹪' => '𖹊', '𖹫' => '𖹋', '𖹬' => '𖹌', '𖹭' => '𖹍', '𖹮' => '𖹎', '𖹯' => '𖹏', '𖹰' => '𖹐', '𖹱' => '𖹑', '𖹲' => '𖹒', '𖹳' => '𖹓', '𖹴' => '𖹔', '𖹵' => '𖹕', '𖹶' => '𖹖', '𖹷' => '𖹗', '𖹸' => '𖹘', '𖹹' => '𖹙', '𖹺' => '𖹚', '𖹻' => '𖹛', '𖹼' => '𖹜', '𖹽' => '𖹝', '𖹾' => '𖹞', '𖹿' => '𖹟', '𞤢' => '𞤀', '𞤣' => '𞤁', '𞤤' => '𞤂', '𞤥' => '𞤃', '𞤦' => '𞤄', '𞤧' => '𞤅', '𞤨' => '𞤆', '𞤩' => '𞤇', '𞤪' => '𞤈', '𞤫' => '𞤉', '𞤬' => '𞤊', '𞤭' => '𞤋', '𞤮' => '𞤌', '𞤯' => '𞤍', '𞤰' => '𞤎', '𞤱' => '𞤏', '𞤲' => '𞤐', '𞤳' => '𞤑', '𞤴' => '𞤒', '𞤵' => '𞤓', '𞤶' => '𞤔', '𞤷' => '𞤕', '𞤸' => '𞤖', '𞤹' => '𞤗', '𞤺' => '𞤘', '𞤻' => '𞤙', '𞤼' => '𞤚', '𞤽' => '𞤛', '𞤾' => '𞤜', '𞤿' => '𞤝', '𞥀' => '𞤞', '𞥁' => '𞤟', '𞥂' => '𞤠', '𞥃' => '𞤡', 'ß' => 'SS', 'ff' => 'FF', 'fi' => 'FI', 'fl' => 'FL', 'ffi' => 'FFI', 'ffl' => 'FFL', 'ſt' => 'ST', 'st' => 'ST', 'և' => 'ԵՒ', 'ﬓ' => 'ՄՆ', 'ﬔ' => 'ՄԵ', 'ﬕ' => 'ՄԻ', 'ﬖ' => 'ՎՆ', 'ﬗ' => 'ՄԽ', 'ʼn' => 'ʼN', 'ΐ' => 'Ϊ́', 'ΰ' => 'Ϋ́', 'ǰ' => 'J̌', 'ẖ' => 'H̱', 'ẗ' => 'T̈', 'ẘ' => 'W̊', 'ẙ' => 'Y̊', 'ẚ' => 'Aʾ', 'ὐ' => 'Υ̓', 'ὒ' => 'Υ̓̀', 'ὔ' => 'Υ̓́', 'ὖ' => 'Υ̓͂', 'ᾶ' => 'Α͂', 'ῆ' => 'Η͂', 'ῒ' => 'Ϊ̀', 'ΐ' => 'Ϊ́', 'ῖ' => 'Ι͂', 'ῗ' => 'Ϊ͂', 'ῢ' => 'Ϋ̀', 'ΰ' => 'Ϋ́', 'ῤ' => 'Ρ̓', 'ῦ' => 'Υ͂', 'ῧ' => 'Ϋ͂', 'ῶ' => 'Ω͂', 'ᾈ' => 'ἈΙ', 'ᾉ' => 'ἉΙ', 'ᾊ' => 'ἊΙ', 'ᾋ' => 'ἋΙ', 'ᾌ' => 'ἌΙ', 'ᾍ' => 'ἍΙ', 'ᾎ' => 'ἎΙ', 'ᾏ' => 'ἏΙ', 'ᾘ' => 'ἨΙ', 'ᾙ' => 'ἩΙ', 'ᾚ' => 'ἪΙ', 'ᾛ' => 'ἫΙ', 'ᾜ' => 'ἬΙ', 'ᾝ' => 'ἭΙ', 'ᾞ' => 'ἮΙ', 'ᾟ' => 'ἯΙ', 'ᾨ' => 'ὨΙ', 'ᾩ' => 'ὩΙ', 'ᾪ' => 'ὪΙ', 'ᾫ' => 'ὫΙ', 'ᾬ' => 'ὬΙ', 'ᾭ' => 'ὭΙ', 'ᾮ' => 'ὮΙ', 'ᾯ' => 'ὯΙ', 'ᾼ' => 'ΑΙ', 'ῌ' => 'ΗΙ', 'ῼ' => 'ΩΙ', 'ᾲ' => 'ᾺΙ', 'ᾴ' => 'ΆΙ', 'ῂ' => 'ῊΙ', 'ῄ' => 'ΉΙ', 'ῲ' => 'ῺΙ', 'ῴ' => 'ΏΙ', 'ᾷ' => 'Α͂Ι', 'ῇ' => 'Η͂Ι', 'ῷ' => 'Ω͂Ι'); * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace _HumbugBox7ff99e199a36\Symfony\Polyfill\Mbstring; /** * Partial mbstring implementation in PHP, iconv based, UTF-8 centric. * * Implemented: * - mb_chr - Returns a specific character from its Unicode code point * - mb_convert_encoding - Convert character encoding * - mb_convert_variables - Convert character code in variable(s) * - mb_decode_mimeheader - Decode string in MIME header field * - mb_encode_mimeheader - Encode string for MIME header XXX NATIVE IMPLEMENTATION IS REALLY BUGGED * - mb_decode_numericentity - Decode HTML numeric string reference to character * - mb_encode_numericentity - Encode character to HTML numeric string reference * - mb_convert_case - Perform case folding on a string * - mb_detect_encoding - Detect character encoding * - mb_get_info - Get internal settings of mbstring * - mb_http_input - Detect HTTP input character encoding * - mb_http_output - Set/Get HTTP output character encoding * - mb_internal_encoding - Set/Get internal character encoding * - mb_list_encodings - Returns an array of all supported encodings * - mb_ord - Returns the Unicode code point of a character * - mb_output_handler - Callback function converts character encoding in output buffer * - mb_scrub - Replaces ill-formed byte sequences with substitute characters * - mb_strlen - Get string length * - mb_strpos - Find position of first occurrence of string in a string * - mb_strrpos - Find position of last occurrence of a string in a string * - mb_str_split - Convert a string to an array * - mb_strtolower - Make a string lowercase * - mb_strtoupper - Make a string uppercase * - mb_substitute_character - Set/Get substitution character * - mb_substr - Get part of string * - mb_stripos - Finds position of first occurrence of a string within another, case insensitive * - mb_stristr - Finds first occurrence of a string within another, case insensitive * - mb_strrchr - Finds the last occurrence of a character in a string within another * - mb_strrichr - Finds the last occurrence of a character in a string within another, case insensitive * - mb_strripos - Finds position of last occurrence of a string within another, case insensitive * - mb_strstr - Finds first occurrence of a string within another * - mb_strwidth - Return width of string * - mb_substr_count - Count the number of substring occurrences * - mb_ucfirst - Make a string's first character uppercase * - mb_lcfirst - Make a string's first character lowercase * - mb_trim - Strip whitespace (or other characters) from the beginning and end of a string * - mb_ltrim - Strip whitespace (or other characters) from the beginning of a string * - mb_rtrim - Strip whitespace (or other characters) from the end of a string * * Not implemented: * - mb_convert_kana - Convert "kana" one from another ("zen-kaku", "han-kaku" and more) * - mb_ereg_* - Regular expression with multibyte support * - mb_parse_str - Parse GET/POST/COOKIE data and set global variable * - mb_preferred_mime_name - Get MIME charset string * - mb_regex_encoding - Returns current encoding for multibyte regex as string * - mb_regex_set_options - Set/Get the default options for mbregex functions * - mb_send_mail - Send encoded mail * - mb_split - Split multibyte string using regular expression * - mb_strcut - Get part of string * - mb_strimwidth - Get truncated string with specified width * * @author Nicolas Grekas * * @internal */ final class Mbstring { public const MB_CASE_FOLD = \PHP_INT_MAX; private const SIMPLE_CASE_FOLD = [['µ', 'ſ', "ͅ", 'ς', "ϐ", "ϑ", "ϕ", "ϖ", "ϰ", "ϱ", "ϵ", "ẛ", "ι"], ['μ', 's', 'ι', 'σ', 'β', 'θ', 'φ', 'π', 'κ', 'ρ', 'ε', "ṡ", 'ι']]; private static $encodingList = ['ASCII', 'UTF-8']; private static $language = 'neutral'; private static $internalEncoding = 'UTF-8'; public static function mb_convert_encoding($s, $toEncoding, $fromEncoding = null) { if (\is_array($s)) { $r = []; foreach ($s as $str) { $r[] = self::mb_convert_encoding($str, $toEncoding, $fromEncoding); } return $r; } if (\is_array($fromEncoding) || null !== $fromEncoding && \false !== \strpos($fromEncoding, ',')) { $fromEncoding = self::mb_detect_encoding($s, $fromEncoding); } else { $fromEncoding = self::getEncoding($fromEncoding); } $toEncoding = self::getEncoding($toEncoding); if ('BASE64' === $fromEncoding) { $s = \base64_decode($s); $fromEncoding = $toEncoding; } if ('BASE64' === $toEncoding) { return \base64_encode($s); } if ('HTML-ENTITIES' === $toEncoding || 'HTML' === $toEncoding) { if ('HTML-ENTITIES' === $fromEncoding || 'HTML' === $fromEncoding) { $fromEncoding = 'Windows-1252'; } if ('UTF-8' !== $fromEncoding) { $s = \iconv($fromEncoding, 'UTF-8//IGNORE', $s); } return \preg_replace_callback('/[\\x80-\\xFF]+/', [__CLASS__, 'html_encoding_callback'], $s); } if ('HTML-ENTITIES' === $fromEncoding) { $s = \html_entity_decode($s, \ENT_COMPAT, 'UTF-8'); $fromEncoding = 'UTF-8'; } return \iconv($fromEncoding, $toEncoding . '//IGNORE', $s); } public static function mb_convert_variables($toEncoding, $fromEncoding, &...$vars) { $ok = \true; \array_walk_recursive($vars, function (&$v) use(&$ok, $toEncoding, $fromEncoding) { if (\false === ($v = self::mb_convert_encoding($v, $toEncoding, $fromEncoding))) { $ok = \false; } }); return $ok ? $fromEncoding : \false; } public static function mb_decode_mimeheader($s) { return \iconv_mime_decode($s, 2, self::$internalEncoding); } public static function mb_encode_mimeheader($s, $charset = null, $transferEncoding = null, $linefeed = null, $indent = null) { \trigger_error('mb_encode_mimeheader() is bugged. Please use iconv_mime_encode() instead', \E_USER_WARNING); } public static function mb_decode_numericentity($s, $convmap, $encoding = null) { if (null !== $s && !\is_scalar($s) && !(\is_object($s) && \method_exists($s, '__toString'))) { \trigger_error('mb_decode_numericentity() expects parameter 1 to be string, ' . \gettype($s) . ' given', \E_USER_WARNING); return null; } if (!\is_array($convmap) || 80000 > \PHP_VERSION_ID && !$convmap) { return \false; } if (null !== $encoding && !\is_scalar($encoding)) { \trigger_error('mb_decode_numericentity() expects parameter 3 to be string, ' . \gettype($s) . ' given', \E_USER_WARNING); return ''; // Instead of null (cf. mb_encode_numericentity). } $s = (string) $s; if ('' === $s) { return ''; } $encoding = self::getEncoding($encoding); if ('UTF-8' === $encoding) { $encoding = null; if (!\preg_match('//u', $s)) { $s = @\iconv('UTF-8', 'UTF-8//IGNORE', $s); } } else { $s = \iconv($encoding, 'UTF-8//IGNORE', $s); } $cnt = \floor(\count($convmap) / 4) * 4; for ($i = 0; $i < $cnt; $i += 4) { // collector_decode_htmlnumericentity ignores $convmap[$i + 3] $convmap[$i] += $convmap[$i + 2]; $convmap[$i + 1] += $convmap[$i + 2]; } $s = \preg_replace_callback('/&#(?:0*([0-9]+)|x0*([0-9a-fA-F]+))(?!&);?/', function (array $m) use($cnt, $convmap) { $c = isset($m[2]) ? (int) \hexdec($m[2]) : $m[1]; for ($i = 0; $i < $cnt; $i += 4) { if ($c >= $convmap[$i] && $c <= $convmap[$i + 1]) { return self::mb_chr($c - $convmap[$i + 2]); } } return $m[0]; }, $s); if (null === $encoding) { return $s; } return \iconv('UTF-8', $encoding . '//IGNORE', $s); } public static function mb_encode_numericentity($s, $convmap, $encoding = null, $is_hex = \false) { if (null !== $s && !\is_scalar($s) && !(\is_object($s) && \method_exists($s, '__toString'))) { \trigger_error('mb_encode_numericentity() expects parameter 1 to be string, ' . \gettype($s) . ' given', \E_USER_WARNING); return null; } if (!\is_array($convmap) || 80000 > \PHP_VERSION_ID && !$convmap) { return \false; } if (null !== $encoding && !\is_scalar($encoding)) { \trigger_error('mb_encode_numericentity() expects parameter 3 to be string, ' . \gettype($s) . ' given', \E_USER_WARNING); return null; // Instead of '' (cf. mb_decode_numericentity). } if (null !== $is_hex && !\is_scalar($is_hex)) { \trigger_error('mb_encode_numericentity() expects parameter 4 to be boolean, ' . \gettype($s) . ' given', \E_USER_WARNING); return null; } $s = (string) $s; if ('' === $s) { return ''; } $encoding = self::getEncoding($encoding); if ('UTF-8' === $encoding) { $encoding = null; if (!\preg_match('//u', $s)) { $s = @\iconv('UTF-8', 'UTF-8//IGNORE', $s); } } else { $s = \iconv($encoding, 'UTF-8//IGNORE', $s); } static $ulenMask = ["\xc0" => 2, "\xd0" => 2, "\xe0" => 3, "\xf0" => 4]; $cnt = \floor(\count($convmap) / 4) * 4; $i = 0; $len = \strlen($s); $result = ''; while ($i < $len) { $ulen = $s[$i] < "\x80" ? 1 : $ulenMask[$s[$i] & "\xf0"]; $uchr = \substr($s, $i, $ulen); $i += $ulen; $c = self::mb_ord($uchr); for ($j = 0; $j < $cnt; $j += 4) { if ($c >= $convmap[$j] && $c <= $convmap[$j + 1]) { $cOffset = $c + $convmap[$j + 2] & $convmap[$j + 3]; $result .= $is_hex ? \sprintf('&#x%X;', $cOffset) : '&#' . $cOffset . ';'; continue 2; } } $result .= $uchr; } if (null === $encoding) { return $result; } return \iconv('UTF-8', $encoding . '//IGNORE', $result); } public static function mb_convert_case($s, $mode, $encoding = null) { $s = (string) $s; if ('' === $s) { return ''; } $encoding = self::getEncoding($encoding); if ('UTF-8' === $encoding) { $encoding = null; if (!\preg_match('//u', $s)) { $s = @\iconv('UTF-8', 'UTF-8//IGNORE', $s); } } else { $s = \iconv($encoding, 'UTF-8//IGNORE', $s); } if (\MB_CASE_TITLE == $mode) { static $titleRegexp = null; if (null === $titleRegexp) { $titleRegexp = self::getData('titleCaseRegexp'); } $s = \preg_replace_callback($titleRegexp, [__CLASS__, 'title_case'], $s); } else { if (\MB_CASE_UPPER == $mode) { static $upper = null; if (null === $upper) { $upper = self::getData('upperCase'); } $map = $upper; } else { if (self::MB_CASE_FOLD === $mode) { static $caseFolding = null; if (null === $caseFolding) { $caseFolding = self::getData('caseFolding'); } $s = \strtr($s, $caseFolding); } static $lower = null; if (null === $lower) { $lower = self::getData('lowerCase'); } $map = $lower; } static $ulenMask = ["\xc0" => 2, "\xd0" => 2, "\xe0" => 3, "\xf0" => 4]; $i = 0; $len = \strlen($s); while ($i < $len) { $ulen = $s[$i] < "\x80" ? 1 : $ulenMask[$s[$i] & "\xf0"]; $uchr = \substr($s, $i, $ulen); $i += $ulen; if (isset($map[$uchr])) { $uchr = $map[$uchr]; $nlen = \strlen($uchr); if ($nlen == $ulen) { $nlen = $i; do { $s[--$nlen] = $uchr[--$ulen]; } while ($ulen); } else { $s = \substr_replace($s, $uchr, $i - $ulen, $ulen); $len += $nlen - $ulen; $i += $nlen - $ulen; } } } } if (null === $encoding) { return $s; } return \iconv('UTF-8', $encoding . '//IGNORE', $s); } public static function mb_internal_encoding($encoding = null) { if (null === $encoding) { return self::$internalEncoding; } $normalizedEncoding = self::getEncoding($encoding); if ('UTF-8' === $normalizedEncoding || \false !== @\iconv($normalizedEncoding, $normalizedEncoding, ' ')) { self::$internalEncoding = $normalizedEncoding; return \true; } if (80000 > \PHP_VERSION_ID) { return \false; } throw new \ValueError(\sprintf('Argument #1 ($encoding) must be a valid encoding, "%s" given', $encoding)); } public static function mb_language($lang = null) { if (null === $lang) { return self::$language; } switch ($normalizedLang = \strtolower($lang)) { case 'uni': case 'neutral': self::$language = $normalizedLang; return \true; } if (80000 > \PHP_VERSION_ID) { return \false; } throw new \ValueError(\sprintf('Argument #1 ($language) must be a valid language, "%s" given', $lang)); } public static function mb_list_encodings() { return ['UTF-8']; } public static function mb_encoding_aliases($encoding) { switch (\strtoupper($encoding)) { case 'UTF8': case 'UTF-8': return ['utf8']; } return \false; } public static function mb_check_encoding($var = null, $encoding = null) { if (null === $encoding) { if (null === $var) { return \false; } $encoding = self::$internalEncoding; } if (!\is_array($var)) { return self::mb_detect_encoding($var, [$encoding]) || \false !== @\iconv($encoding, $encoding, $var); } foreach ($var as $key => $value) { if (!self::mb_check_encoding($key, $encoding)) { return \false; } if (!self::mb_check_encoding($value, $encoding)) { return \false; } } return \true; } public static function mb_detect_encoding($str, $encodingList = null, $strict = \false) { if (null === $encodingList) { $encodingList = self::$encodingList; } else { if (!\is_array($encodingList)) { $encodingList = \array_map('trim', \explode(',', $encodingList)); } $encodingList = \array_map('strtoupper', $encodingList); } foreach ($encodingList as $enc) { switch ($enc) { case 'ASCII': if (!\preg_match('/[\\x80-\\xFF]/', $str)) { return $enc; } break; case 'UTF8': case 'UTF-8': if (\preg_match('//u', $str)) { return 'UTF-8'; } break; default: if (0 === \strncmp($enc, 'ISO-8859-', 9)) { return $enc; } } } return \false; } public static function mb_detect_order($encodingList = null) { if (null === $encodingList) { return self::$encodingList; } if (!\is_array($encodingList)) { $encodingList = \array_map('trim', \explode(',', $encodingList)); } $encodingList = \array_map('strtoupper', $encodingList); foreach ($encodingList as $enc) { switch ($enc) { default: if (\strncmp($enc, 'ISO-8859-', 9)) { return \false; } // no break case 'ASCII': case 'UTF8': case 'UTF-8': } } self::$encodingList = $encodingList; return \true; } public static function mb_strlen($s, $encoding = null) { $encoding = self::getEncoding($encoding); if ('CP850' === $encoding || 'ASCII' === $encoding) { return \strlen($s); } return @\iconv_strlen($s, $encoding); } public static function mb_strpos($haystack, $needle, $offset = 0, $encoding = null) { $encoding = self::getEncoding($encoding); if ('CP850' === $encoding || 'ASCII' === $encoding) { return \strpos($haystack, $needle, $offset); } $needle = (string) $needle; if ('' === $needle) { if (80000 > \PHP_VERSION_ID) { \trigger_error(__METHOD__ . ': Empty delimiter', \E_USER_WARNING); return \false; } return 0; } return \iconv_strpos($haystack, $needle, $offset, $encoding); } public static function mb_strrpos($haystack, $needle, $offset = 0, $encoding = null) { $encoding = self::getEncoding($encoding); if ('CP850' === $encoding || 'ASCII' === $encoding) { return \strrpos($haystack, $needle, $offset); } if ($offset != (int) $offset) { $offset = 0; } elseif ($offset = (int) $offset) { if ($offset < 0) { if (0 > ($offset += self::mb_strlen($needle))) { $haystack = self::mb_substr($haystack, 0, $offset, $encoding); } $offset = 0; } else { $haystack = self::mb_substr($haystack, $offset, 2147483647, $encoding); } } $pos = '' !== $needle || 80000 > \PHP_VERSION_ID ? \iconv_strrpos($haystack, $needle, $encoding) : self::mb_strlen($haystack, $encoding); return \false !== $pos ? $offset + $pos : \false; } public static function mb_str_split($string, $split_length = 1, $encoding = null) { if (null !== $string && !\is_scalar($string) && !(\is_object($string) && \method_exists($string, '__toString'))) { \trigger_error('mb_str_split() expects parameter 1 to be string, ' . \gettype($string) . ' given', \E_USER_WARNING); return null; } if (1 > ($split_length = (int) $split_length)) { if (80000 > \PHP_VERSION_ID) { \trigger_error('The length of each segment must be greater than zero', \E_USER_WARNING); return \false; } throw new \ValueError('Argument #2 ($length) must be greater than 0'); } if (null === $encoding) { $encoding = \mb_internal_encoding(); } if ('UTF-8' === ($encoding = self::getEncoding($encoding))) { $rx = '/('; while (65535 < $split_length) { $rx .= '.{65535}'; $split_length -= 65535; } $rx .= '.{' . $split_length . '})/us'; return \preg_split($rx, $string, -1, \PREG_SPLIT_DELIM_CAPTURE | \PREG_SPLIT_NO_EMPTY); } $result = []; $length = \mb_strlen($string, $encoding); for ($i = 0; $i < $length; $i += $split_length) { $result[] = \mb_substr($string, $i, $split_length, $encoding); } return $result; } public static function mb_strtolower($s, $encoding = null) { return self::mb_convert_case($s, \MB_CASE_LOWER, $encoding); } public static function mb_strtoupper($s, $encoding = null) { return self::mb_convert_case($s, \MB_CASE_UPPER, $encoding); } public static function mb_substitute_character($c = null) { if (null === $c) { return 'none'; } if (0 === \strcasecmp($c, 'none')) { return \true; } if (80000 > \PHP_VERSION_ID) { return \false; } if (\is_int($c) || 'long' === $c || 'entity' === $c) { return \false; } throw new \ValueError('Argument #1 ($substitute_character) must be "none", "long", "entity" or a valid codepoint'); } public static function mb_substr($s, $start, $length = null, $encoding = null) { $encoding = self::getEncoding($encoding); if ('CP850' === $encoding || 'ASCII' === $encoding) { return (string) \substr($s, $start, null === $length ? 2147483647 : $length); } if ($start < 0) { $start = \iconv_strlen($s, $encoding) + $start; if ($start < 0) { $start = 0; } } if (null === $length) { $length = 2147483647; } elseif ($length < 0) { $length = \iconv_strlen($s, $encoding) + $length - $start; if ($length < 0) { return ''; } } return (string) \iconv_substr($s, $start, $length, $encoding); } public static function mb_stripos($haystack, $needle, $offset = 0, $encoding = null) { [$haystack, $needle] = \str_replace(self::SIMPLE_CASE_FOLD[0], self::SIMPLE_CASE_FOLD[1], [self::mb_convert_case($haystack, \MB_CASE_LOWER, $encoding), self::mb_convert_case($needle, \MB_CASE_LOWER, $encoding)]); return self::mb_strpos($haystack, $needle, $offset, $encoding); } public static function mb_stristr($haystack, $needle, $part = \false, $encoding = null) { $pos = self::mb_stripos($haystack, $needle, 0, $encoding); return self::getSubpart($pos, $part, $haystack, $encoding); } public static function mb_strrchr($haystack, $needle, $part = \false, $encoding = null) { $encoding = self::getEncoding($encoding); if ('CP850' === $encoding || 'ASCII' === $encoding) { $pos = \strrpos($haystack, $needle); } else { $needle = self::mb_substr($needle, 0, 1, $encoding); $pos = \iconv_strrpos($haystack, $needle, $encoding); } return self::getSubpart($pos, $part, $haystack, $encoding); } public static function mb_strrichr($haystack, $needle, $part = \false, $encoding = null) { $needle = self::mb_substr($needle, 0, 1, $encoding); $pos = self::mb_strripos($haystack, $needle, $encoding); return self::getSubpart($pos, $part, $haystack, $encoding); } public static function mb_strripos($haystack, $needle, $offset = 0, $encoding = null) { $haystack = self::mb_convert_case($haystack, \MB_CASE_LOWER, $encoding); $needle = self::mb_convert_case($needle, \MB_CASE_LOWER, $encoding); $haystack = \str_replace(self::SIMPLE_CASE_FOLD[0], self::SIMPLE_CASE_FOLD[1], $haystack); $needle = \str_replace(self::SIMPLE_CASE_FOLD[0], self::SIMPLE_CASE_FOLD[1], $needle); return self::mb_strrpos($haystack, $needle, $offset, $encoding); } public static function mb_strstr($haystack, $needle, $part = \false, $encoding = null) { $pos = \strpos($haystack, $needle); if (\false === $pos) { return \false; } if ($part) { return \substr($haystack, 0, $pos); } return \substr($haystack, $pos); } public static function mb_get_info($type = 'all') { $info = ['internal_encoding' => self::$internalEncoding, 'http_output' => 'pass', 'http_output_conv_mimetypes' => '^(text/|application/xhtml\\+xml)', 'func_overload' => 0, 'func_overload_list' => 'no overload', 'mail_charset' => 'UTF-8', 'mail_header_encoding' => 'BASE64', 'mail_body_encoding' => 'BASE64', 'illegal_chars' => 0, 'encoding_translation' => 'Off', 'language' => self::$language, 'detect_order' => self::$encodingList, 'substitute_character' => 'none', 'strict_detection' => 'Off']; if ('all' === $type) { return $info; } if (isset($info[$type])) { return $info[$type]; } return \false; } public static function mb_http_input($type = '') { return \false; } public static function mb_http_output($encoding = null) { return null !== $encoding ? 'pass' === $encoding : 'pass'; } public static function mb_strwidth($s, $encoding = null) { $encoding = self::getEncoding($encoding); if ('UTF-8' !== $encoding) { $s = \iconv($encoding, 'UTF-8//IGNORE', $s); } $s = \preg_replace('/[\\x{1100}-\\x{115F}\\x{2329}\\x{232A}\\x{2E80}-\\x{303E}\\x{3040}-\\x{A4CF}\\x{AC00}-\\x{D7A3}\\x{F900}-\\x{FAFF}\\x{FE10}-\\x{FE19}\\x{FE30}-\\x{FE6F}\\x{FF00}-\\x{FF60}\\x{FFE0}-\\x{FFE6}\\x{20000}-\\x{2FFFD}\\x{30000}-\\x{3FFFD}]/u', '', $s, -1, $wide); return ($wide << 1) + \iconv_strlen($s, 'UTF-8'); } public static function mb_substr_count($haystack, $needle, $encoding = null) { return \substr_count($haystack, $needle); } public static function mb_output_handler($contents, $status) { return $contents; } public static function mb_chr($code, $encoding = null) { if (0x80 > ($code %= 0x200000)) { $s = \chr($code); } elseif (0x800 > $code) { $s = \chr(0xc0 | $code >> 6) . \chr(0x80 | $code & 0x3f); } elseif (0x10000 > $code) { $s = \chr(0xe0 | $code >> 12) . \chr(0x80 | $code >> 6 & 0x3f) . \chr(0x80 | $code & 0x3f); } else { $s = \chr(0xf0 | $code >> 18) . \chr(0x80 | $code >> 12 & 0x3f) . \chr(0x80 | $code >> 6 & 0x3f) . \chr(0x80 | $code & 0x3f); } if ('UTF-8' !== ($encoding = self::getEncoding($encoding))) { $s = \mb_convert_encoding($s, $encoding, 'UTF-8'); } return $s; } public static function mb_ord($s, $encoding = null) { if ('UTF-8' !== ($encoding = self::getEncoding($encoding))) { $s = \mb_convert_encoding($s, 'UTF-8', $encoding); } if (1 === \strlen($s)) { return \ord($s); } $code = ($s = \unpack('C*', \substr($s, 0, 4))) ? $s[1] : 0; if (0xf0 <= $code) { return ($code - 0xf0 << 18) + ($s[2] - 0x80 << 12) + ($s[3] - 0x80 << 6) + $s[4] - 0x80; } if (0xe0 <= $code) { return ($code - 0xe0 << 12) + ($s[2] - 0x80 << 6) + $s[3] - 0x80; } if (0xc0 <= $code) { return ($code - 0xc0 << 6) + $s[2] - 0x80; } return $code; } public static function mb_str_pad(string $string, int $length, string $pad_string = ' ', int $pad_type = \STR_PAD_RIGHT, ?string $encoding = null) : string { if (!\in_array($pad_type, [\STR_PAD_RIGHT, \STR_PAD_LEFT, \STR_PAD_BOTH], \true)) { throw new \ValueError('mb_str_pad(): Argument #4 ($pad_type) must be STR_PAD_LEFT, STR_PAD_RIGHT, or STR_PAD_BOTH'); } if (null === $encoding) { $encoding = self::mb_internal_encoding(); } else { self::assertEncoding($encoding, 'mb_str_pad(): Argument #5 ($encoding) must be a valid encoding, "%s" given'); } if (self::mb_strlen($pad_string, $encoding) <= 0) { throw new \ValueError('mb_str_pad(): Argument #3 ($pad_string) must be a non-empty string'); } $paddingRequired = $length - self::mb_strlen($string, $encoding); if ($paddingRequired < 1) { return $string; } switch ($pad_type) { case \STR_PAD_LEFT: return self::mb_substr(\str_repeat($pad_string, $paddingRequired), 0, $paddingRequired, $encoding) . $string; case \STR_PAD_RIGHT: return $string . self::mb_substr(\str_repeat($pad_string, $paddingRequired), 0, $paddingRequired, $encoding); default: $leftPaddingLength = \floor($paddingRequired / 2); $rightPaddingLength = $paddingRequired - $leftPaddingLength; return self::mb_substr(\str_repeat($pad_string, $leftPaddingLength), 0, $leftPaddingLength, $encoding) . $string . self::mb_substr(\str_repeat($pad_string, $rightPaddingLength), 0, $rightPaddingLength, $encoding); } } public static function mb_ucfirst(string $string, ?string $encoding = null) : string { if (null === $encoding) { $encoding = self::mb_internal_encoding(); } else { self::assertEncoding($encoding, 'mb_ucfirst(): Argument #2 ($encoding) must be a valid encoding, "%s" given'); } $firstChar = \mb_substr($string, 0, 1, $encoding); $firstChar = \mb_convert_case($firstChar, \MB_CASE_TITLE, $encoding); return $firstChar . \mb_substr($string, 1, null, $encoding); } public static function mb_lcfirst(string $string, ?string $encoding = null) : string { if (null === $encoding) { $encoding = self::mb_internal_encoding(); } else { self::assertEncoding($encoding, 'mb_lcfirst(): Argument #2 ($encoding) must be a valid encoding, "%s" given'); } $firstChar = \mb_substr($string, 0, 1, $encoding); $firstChar = \mb_convert_case($firstChar, \MB_CASE_LOWER, $encoding); return $firstChar . \mb_substr($string, 1, null, $encoding); } private static function getSubpart($pos, $part, $haystack, $encoding) { if (\false === $pos) { return \false; } if ($part) { return self::mb_substr($haystack, 0, $pos, $encoding); } return self::mb_substr($haystack, $pos, null, $encoding); } private static function html_encoding_callback(array $m) { $i = 1; $entities = ''; $m = \unpack('C*', \htmlentities($m[0], \ENT_COMPAT, 'UTF-8')); while (isset($m[$i])) { if (0x80 > $m[$i]) { $entities .= \chr($m[$i++]); continue; } if (0xf0 <= $m[$i]) { $c = ($m[$i++] - 0xf0 << 18) + ($m[$i++] - 0x80 << 12) + ($m[$i++] - 0x80 << 6) + $m[$i++] - 0x80; } elseif (0xe0 <= $m[$i]) { $c = ($m[$i++] - 0xe0 << 12) + ($m[$i++] - 0x80 << 6) + $m[$i++] - 0x80; } else { $c = ($m[$i++] - 0xc0 << 6) + $m[$i++] - 0x80; } $entities .= '&#' . $c . ';'; } return $entities; } private static function title_case(array $s) { return self::mb_convert_case($s[1], \MB_CASE_UPPER, 'UTF-8') . self::mb_convert_case($s[2], \MB_CASE_LOWER, 'UTF-8'); } private static function getData($file) { if (\file_exists($file = __DIR__ . '/Resources/unidata/' . $file . '.php')) { return require $file; } return \false; } private static function getEncoding($encoding) { if (null === $encoding) { return self::$internalEncoding; } if ('UTF-8' === $encoding) { return 'UTF-8'; } $encoding = \strtoupper($encoding); if ('8BIT' === $encoding || 'BINARY' === $encoding) { return 'CP850'; } if ('UTF8' === $encoding) { return 'UTF-8'; } return $encoding; } public static function mb_trim(string $string, ?string $characters = null, ?string $encoding = null) : string { return self::mb_internal_trim('{^[%s]+|[%1$s]+$}Du', $string, $characters, $encoding, __FUNCTION__); } public static function mb_ltrim(string $string, ?string $characters = null, ?string $encoding = null) : string { return self::mb_internal_trim('{^[%s]+}Du', $string, $characters, $encoding, __FUNCTION__); } public static function mb_rtrim(string $string, ?string $characters = null, ?string $encoding = null) : string { return self::mb_internal_trim('{[%s]+$}D', $string, $characters, $encoding, __FUNCTION__); } private static function mb_internal_trim(string $regex, string $string, ?string $characters, ?string $encoding, string $function) : string { if (null === $encoding) { $encoding = self::mb_internal_encoding(); } else { self::assertEncoding($encoding, $function . '(): Argument #3 ($encoding) must be a valid encoding, "%s" given'); } if ('' === $characters) { return null === $encoding ? $string : self::mb_convert_encoding($string, $encoding); } if ('UTF-8' === $encoding) { $encoding = null; if (!\preg_match('//u', $string)) { $string = @\iconv('UTF-8', 'UTF-8//IGNORE', $string); } if (null !== $characters && !\preg_match('//u', $characters)) { $characters = @\iconv('UTF-8', 'UTF-8//IGNORE', $characters); } } else { $string = \iconv($encoding, 'UTF-8//IGNORE', $string); if (null !== $characters) { $characters = \iconv($encoding, 'UTF-8//IGNORE', $characters); } } if (null === $characters) { $characters = "\\0 \f\n\r\t\v             

   …᠎"; } else { $characters = \preg_quote($characters); } $string = \preg_replace(\sprintf($regex, $characters), '', $string); if (null === $encoding) { return $string; } return \iconv('UTF-8', $encoding . '//IGNORE', $string); } private static function assertEncoding(string $encoding, string $errorFormat) : void { try { $validEncoding = @self::mb_check_encoding('', $encoding); } catch (\ValueError $e) { throw new \ValueError(\sprintf($errorFormat, $encoding)); } // BC for PHP 7.3 and lower if (!$validEncoding) { throw new \ValueError(\sprintf($errorFormat, $encoding)); } } } * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ use _HumbugBox7ff99e199a36\Symfony\Polyfill\Mbstring as p; if (!\function_exists('mb_convert_encoding')) { function mb_convert_encoding(array|string|null $string, ?string $to_encoding, array|string|null $from_encoding = null) : array|string|false { return p\Mbstring::mb_convert_encoding($string ?? '', (string) $to_encoding, $from_encoding); } } if (!\function_exists('mb_decode_mimeheader')) { function mb_decode_mimeheader(?string $string) : string { return p\Mbstring::mb_decode_mimeheader((string) $string); } } if (!\function_exists('mb_encode_mimeheader')) { function mb_encode_mimeheader(?string $string, ?string $charset = null, ?string $transfer_encoding = null, ?string $newline = "\r\n", ?int $indent = 0) : string { return p\Mbstring::mb_encode_mimeheader((string) $string, $charset, $transfer_encoding, (string) $newline, (int) $indent); } } if (!\function_exists('mb_decode_numericentity')) { function mb_decode_numericentity(?string $string, array $map, ?string $encoding = null) : string { return p\Mbstring::mb_decode_numericentity((string) $string, $map, $encoding); } } if (!\function_exists('mb_encode_numericentity')) { function mb_encode_numericentity(?string $string, array $map, ?string $encoding = null, ?bool $hex = \false) : string { return p\Mbstring::mb_encode_numericentity((string) $string, $map, $encoding, (bool) $hex); } } if (!\function_exists('mb_convert_case')) { function mb_convert_case(?string $string, ?int $mode, ?string $encoding = null) : string { return p\Mbstring::mb_convert_case((string) $string, (int) $mode, $encoding); } } if (!\function_exists('mb_internal_encoding')) { function mb_internal_encoding(?string $encoding = null) : string|bool { return p\Mbstring::mb_internal_encoding($encoding); } } if (!\function_exists('mb_language')) { function mb_language(?string $language = null) : string|bool { return p\Mbstring::mb_language($language); } } if (!\function_exists('mb_list_encodings')) { function mb_list_encodings() : array { return p\Mbstring::mb_list_encodings(); } } if (!\function_exists('mb_encoding_aliases')) { function mb_encoding_aliases(?string $encoding) : array { return p\Mbstring::mb_encoding_aliases((string) $encoding); } } if (!\function_exists('mb_check_encoding')) { function mb_check_encoding(array|string|null $value = null, ?string $encoding = null) : bool { return p\Mbstring::mb_check_encoding($value, $encoding); } } if (!\function_exists('mb_detect_encoding')) { function mb_detect_encoding(?string $string, array|string|null $encodings = null, ?bool $strict = \false) : string|false { return p\Mbstring::mb_detect_encoding((string) $string, $encodings, (bool) $strict); } } if (!\function_exists('mb_detect_order')) { function mb_detect_order(array|string|null $encoding = null) : array|bool { return p\Mbstring::mb_detect_order($encoding); } } if (!\function_exists('mb_parse_str')) { function mb_parse_str(?string $string, &$result = []) : bool { \parse_str((string) $string, $result); return (bool) $result; } } if (!\function_exists('mb_strlen')) { function mb_strlen(?string $string, ?string $encoding = null) : int { return p\Mbstring::mb_strlen((string) $string, $encoding); } } if (!\function_exists('mb_strpos')) { function mb_strpos(?string $haystack, ?string $needle, ?int $offset = 0, ?string $encoding = null) : int|false { return p\Mbstring::mb_strpos((string) $haystack, (string) $needle, (int) $offset, $encoding); } } if (!\function_exists('mb_strtolower')) { function mb_strtolower(?string $string, ?string $encoding = null) : string { return p\Mbstring::mb_strtolower((string) $string, $encoding); } } if (!\function_exists('mb_strtoupper')) { function mb_strtoupper(?string $string, ?string $encoding = null) : string { return p\Mbstring::mb_strtoupper((string) $string, $encoding); } } if (!\function_exists('mb_substitute_character')) { function mb_substitute_character(string|int|null $substitute_character = null) : string|int|bool { return p\Mbstring::mb_substitute_character($substitute_character); } } if (!\function_exists('mb_substr')) { function mb_substr(?string $string, ?int $start, ?int $length = null, ?string $encoding = null) : string { return p\Mbstring::mb_substr((string) $string, (int) $start, $length, $encoding); } } if (!\function_exists('mb_stripos')) { function mb_stripos(?string $haystack, ?string $needle, ?int $offset = 0, ?string $encoding = null) : int|false { return p\Mbstring::mb_stripos((string) $haystack, (string) $needle, (int) $offset, $encoding); } } if (!\function_exists('mb_stristr')) { function mb_stristr(?string $haystack, ?string $needle, ?bool $before_needle = \false, ?string $encoding = null) : string|false { return p\Mbstring::mb_stristr((string) $haystack, (string) $needle, (bool) $before_needle, $encoding); } } if (!\function_exists('mb_strrchr')) { function mb_strrchr(?string $haystack, ?string $needle, ?bool $before_needle = \false, ?string $encoding = null) : string|false { return p\Mbstring::mb_strrchr((string) $haystack, (string) $needle, (bool) $before_needle, $encoding); } } if (!\function_exists('mb_strrichr')) { function mb_strrichr(?string $haystack, ?string $needle, ?bool $before_needle = \false, ?string $encoding = null) : string|false { return p\Mbstring::mb_strrichr((string) $haystack, (string) $needle, (bool) $before_needle, $encoding); } } if (!\function_exists('mb_strripos')) { function mb_strripos(?string $haystack, ?string $needle, ?int $offset = 0, ?string $encoding = null) : int|false { return p\Mbstring::mb_strripos((string) $haystack, (string) $needle, (int) $offset, $encoding); } } if (!\function_exists('mb_strrpos')) { function mb_strrpos(?string $haystack, ?string $needle, ?int $offset = 0, ?string $encoding = null) : int|false { return p\Mbstring::mb_strrpos((string) $haystack, (string) $needle, (int) $offset, $encoding); } } if (!\function_exists('mb_strstr')) { function mb_strstr(?string $haystack, ?string $needle, ?bool $before_needle = \false, ?string $encoding = null) : string|false { return p\Mbstring::mb_strstr((string) $haystack, (string) $needle, (bool) $before_needle, $encoding); } } if (!\function_exists('mb_get_info')) { function mb_get_info(?string $type = 'all') : array|string|int|false|null { return p\Mbstring::mb_get_info((string) $type); } } if (!\function_exists('mb_http_output')) { function mb_http_output(?string $encoding = null) : string|bool { return p\Mbstring::mb_http_output($encoding); } } if (!\function_exists('mb_strwidth')) { function mb_strwidth(?string $string, ?string $encoding = null) : int { return p\Mbstring::mb_strwidth((string) $string, $encoding); } } if (!\function_exists('mb_substr_count')) { function mb_substr_count(?string $haystack, ?string $needle, ?string $encoding = null) : int { return p\Mbstring::mb_substr_count((string) $haystack, (string) $needle, $encoding); } } if (!\function_exists('mb_output_handler')) { function mb_output_handler(?string $string, ?int $status) : string { return p\Mbstring::mb_output_handler((string) $string, (int) $status); } } if (!\function_exists('mb_http_input')) { function mb_http_input(?string $type = null) : array|string|false { return p\Mbstring::mb_http_input($type); } } if (!\function_exists('mb_convert_variables')) { function mb_convert_variables(?string $to_encoding, array|string|null $from_encoding, mixed &$var, mixed &...$vars) : string|false { return p\Mbstring::mb_convert_variables((string) $to_encoding, $from_encoding ?? '', $var, ...$vars); } } if (!\function_exists('mb_ord')) { function mb_ord(?string $string, ?string $encoding = null) : int|false { return p\Mbstring::mb_ord((string) $string, $encoding); } } if (!\function_exists('mb_chr')) { function mb_chr(?int $codepoint, ?string $encoding = null) : string|false { return p\Mbstring::mb_chr((int) $codepoint, $encoding); } } if (!\function_exists('mb_scrub')) { function mb_scrub(?string $string, ?string $encoding = null) : string { $encoding ??= \mb_internal_encoding(); return \mb_convert_encoding((string) $string, $encoding, $encoding); } } if (!\function_exists('mb_str_split')) { function mb_str_split(?string $string, ?int $length = 1, ?string $encoding = null) : array { return p\Mbstring::mb_str_split((string) $string, (int) $length, $encoding); } } if (!\function_exists('_HumbugBox7ff99e199a36\\mb_str_pad')) { function mb_str_pad(string $string, int $length, string $pad_string = ' ', int $pad_type = \STR_PAD_RIGHT, ?string $encoding = null) : string { return p\Mbstring::mb_str_pad($string, $length, $pad_string, $pad_type, $encoding); } } if (!\function_exists('_HumbugBox7ff99e199a36\\mb_ucfirst')) { function mb_ucfirst($string, ?string $encoding = null) : string { return p\Mbstring::mb_ucfirst($string, $encoding); } } if (!\function_exists('_HumbugBox7ff99e199a36\\mb_lcfirst')) { function mb_lcfirst($string, ?string $encoding = null) : string { return p\Mbstring::mb_lcfirst($string, $encoding); } } if (!\function_exists('_HumbugBox7ff99e199a36\\mb_trim')) { function mb_trim(string $string, ?string $characters = null, ?string $encoding = null) : string { return p\Mbstring::mb_trim($string, $characters, $encoding); } } if (!\function_exists('_HumbugBox7ff99e199a36\\mb_ltrim')) { function mb_ltrim(string $string, ?string $characters = null, ?string $encoding = null) : string { return p\Mbstring::mb_ltrim($string, $characters, $encoding); } } if (!\function_exists('_HumbugBox7ff99e199a36\\mb_rtrim')) { function mb_rtrim(string $string, ?string $characters = null, ?string $encoding = null) : string { return p\Mbstring::mb_rtrim($string, $characters, $encoding); } } if (\extension_loaded('mbstring')) { return; } if (!\defined('MB_CASE_UPPER')) { \define('MB_CASE_UPPER', 0); } if (!\defined('MB_CASE_LOWER')) { \define('MB_CASE_LOWER', 1); } if (!\defined('MB_CASE_TITLE')) { \define('MB_CASE_TITLE', 2); } * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ use _HumbugBox7ff99e199a36\Symfony\Polyfill\Mbstring as p; if (\PHP_VERSION_ID >= 80000) { return require __DIR__ . '/bootstrap80.php'; } if (!\function_exists('mb_convert_encoding')) { function mb_convert_encoding($string, $to_encoding, $from_encoding = null) { return p\Mbstring::mb_convert_encoding($string, $to_encoding, $from_encoding); } } if (!\function_exists('mb_decode_mimeheader')) { function mb_decode_mimeheader($string) { return p\Mbstring::mb_decode_mimeheader($string); } } if (!\function_exists('mb_encode_mimeheader')) { function mb_encode_mimeheader($string, $charset = null, $transfer_encoding = null, $newline = "\r\n", $indent = 0) { return p\Mbstring::mb_encode_mimeheader($string, $charset, $transfer_encoding, $newline, $indent); } } if (!\function_exists('mb_decode_numericentity')) { function mb_decode_numericentity($string, $map, $encoding = null) { return p\Mbstring::mb_decode_numericentity($string, $map, $encoding); } } if (!\function_exists('mb_encode_numericentity')) { function mb_encode_numericentity($string, $map, $encoding = null, $hex = \false) { return p\Mbstring::mb_encode_numericentity($string, $map, $encoding, $hex); } } if (!\function_exists('mb_convert_case')) { function mb_convert_case($string, $mode, $encoding = null) { return p\Mbstring::mb_convert_case($string, $mode, $encoding); } } if (!\function_exists('mb_internal_encoding')) { function mb_internal_encoding($encoding = null) { return p\Mbstring::mb_internal_encoding($encoding); } } if (!\function_exists('mb_language')) { function mb_language($language = null) { return p\Mbstring::mb_language($language); } } if (!\function_exists('mb_list_encodings')) { function mb_list_encodings() { return p\Mbstring::mb_list_encodings(); } } if (!\function_exists('mb_encoding_aliases')) { function mb_encoding_aliases($encoding) { return p\Mbstring::mb_encoding_aliases($encoding); } } if (!\function_exists('mb_check_encoding')) { function mb_check_encoding($value = null, $encoding = null) { return p\Mbstring::mb_check_encoding($value, $encoding); } } if (!\function_exists('mb_detect_encoding')) { function mb_detect_encoding($string, $encodings = null, $strict = \false) { return p\Mbstring::mb_detect_encoding($string, $encodings, $strict); } } if (!\function_exists('mb_detect_order')) { function mb_detect_order($encoding = null) { return p\Mbstring::mb_detect_order($encoding); } } if (!\function_exists('mb_parse_str')) { function mb_parse_str($string, &$result = []) { \parse_str($string, $result); return (bool) $result; } } if (!\function_exists('mb_strlen')) { function mb_strlen($string, $encoding = null) { return p\Mbstring::mb_strlen($string, $encoding); } } if (!\function_exists('mb_strpos')) { function mb_strpos($haystack, $needle, $offset = 0, $encoding = null) { return p\Mbstring::mb_strpos($haystack, $needle, $offset, $encoding); } } if (!\function_exists('mb_strtolower')) { function mb_strtolower($string, $encoding = null) { return p\Mbstring::mb_strtolower($string, $encoding); } } if (!\function_exists('mb_strtoupper')) { function mb_strtoupper($string, $encoding = null) { return p\Mbstring::mb_strtoupper($string, $encoding); } } if (!\function_exists('mb_substitute_character')) { function mb_substitute_character($substitute_character = null) { return p\Mbstring::mb_substitute_character($substitute_character); } } if (!\function_exists('mb_substr')) { function mb_substr($string, $start, $length = 2147483647, $encoding = null) { return p\Mbstring::mb_substr($string, $start, $length, $encoding); } } if (!\function_exists('mb_stripos')) { function mb_stripos($haystack, $needle, $offset = 0, $encoding = null) { return p\Mbstring::mb_stripos($haystack, $needle, $offset, $encoding); } } if (!\function_exists('mb_stristr')) { function mb_stristr($haystack, $needle, $before_needle = \false, $encoding = null) { return p\Mbstring::mb_stristr($haystack, $needle, $before_needle, $encoding); } } if (!\function_exists('mb_strrchr')) { function mb_strrchr($haystack, $needle, $before_needle = \false, $encoding = null) { return p\Mbstring::mb_strrchr($haystack, $needle, $before_needle, $encoding); } } if (!\function_exists('mb_strrichr')) { function mb_strrichr($haystack, $needle, $before_needle = \false, $encoding = null) { return p\Mbstring::mb_strrichr($haystack, $needle, $before_needle, $encoding); } } if (!\function_exists('mb_strripos')) { function mb_strripos($haystack, $needle, $offset = 0, $encoding = null) { return p\Mbstring::mb_strripos($haystack, $needle, $offset, $encoding); } } if (!\function_exists('mb_strrpos')) { function mb_strrpos($haystack, $needle, $offset = 0, $encoding = null) { return p\Mbstring::mb_strrpos($haystack, $needle, $offset, $encoding); } } if (!\function_exists('mb_strstr')) { function mb_strstr($haystack, $needle, $before_needle = \false, $encoding = null) { return p\Mbstring::mb_strstr($haystack, $needle, $before_needle, $encoding); } } if (!\function_exists('mb_get_info')) { function mb_get_info($type = 'all') { return p\Mbstring::mb_get_info($type); } } if (!\function_exists('mb_http_output')) { function mb_http_output($encoding = null) { return p\Mbstring::mb_http_output($encoding); } } if (!\function_exists('mb_strwidth')) { function mb_strwidth($string, $encoding = null) { return p\Mbstring::mb_strwidth($string, $encoding); } } if (!\function_exists('mb_substr_count')) { function mb_substr_count($haystack, $needle, $encoding = null) { return p\Mbstring::mb_substr_count($haystack, $needle, $encoding); } } if (!\function_exists('mb_output_handler')) { function mb_output_handler($string, $status) { return p\Mbstring::mb_output_handler($string, $status); } } if (!\function_exists('mb_http_input')) { function mb_http_input($type = null) { return p\Mbstring::mb_http_input($type); } } if (!\function_exists('mb_convert_variables')) { function mb_convert_variables($to_encoding, $from_encoding, &...$vars) { return p\Mbstring::mb_convert_variables($to_encoding, $from_encoding, ...$vars); } } if (!\function_exists('mb_ord')) { function mb_ord($string, $encoding = null) { return p\Mbstring::mb_ord($string, $encoding); } } if (!\function_exists('mb_chr')) { function mb_chr($codepoint, $encoding = null) { return p\Mbstring::mb_chr($codepoint, $encoding); } } if (!\function_exists('mb_scrub')) { function mb_scrub($string, $encoding = null) { $encoding = null === $encoding ? \mb_internal_encoding() : $encoding; return \mb_convert_encoding($string, $encoding, $encoding); } } if (!\function_exists('mb_str_split')) { function mb_str_split($string, $length = 1, $encoding = null) { return p\Mbstring::mb_str_split($string, $length, $encoding); } } if (!\function_exists('_HumbugBox7ff99e199a36\\mb_str_pad')) { function mb_str_pad(string $string, int $length, string $pad_string = ' ', int $pad_type = \STR_PAD_RIGHT, ?string $encoding = null) : string { return p\Mbstring::mb_str_pad($string, $length, $pad_string, $pad_type, $encoding); } } if (!\function_exists('_HumbugBox7ff99e199a36\\mb_ucfirst')) { function mb_ucfirst(string $string, ?string $encoding = null) : string { return p\Mbstring::mb_ucfirst($string, $encoding); } } if (!\function_exists('_HumbugBox7ff99e199a36\\mb_lcfirst')) { function mb_lcfirst(string $string, ?string $encoding = null) : string { return p\Mbstring::mb_lcfirst($string, $encoding); } } if (!\function_exists('_HumbugBox7ff99e199a36\\mb_trim')) { function mb_trim(string $string, ?string $characters = null, ?string $encoding = null) : string { return p\Mbstring::mb_trim($string, $characters, $encoding); } } if (!\function_exists('_HumbugBox7ff99e199a36\\mb_ltrim')) { function mb_ltrim(string $string, ?string $characters = null, ?string $encoding = null) : string { return p\Mbstring::mb_ltrim($string, $characters, $encoding); } } if (!\function_exists('_HumbugBox7ff99e199a36\\mb_rtrim')) { function mb_rtrim(string $string, ?string $characters = null, ?string $encoding = null) : string { return p\Mbstring::mb_rtrim($string, $characters, $encoding); } } if (\extension_loaded('mbstring')) { return; } if (!\defined('MB_CASE_UPPER')) { \define('MB_CASE_UPPER', 0); } if (!\defined('MB_CASE_LOWER')) { \define('MB_CASE_LOWER', 1); } if (!\defined('MB_CASE_TITLE')) { \define('MB_CASE_TITLE', 2); } Copyright (c) 2018-present Fabien Potencier Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ if (\PHP_VERSION_ID < 70300) { class JsonException extends \Exception { } } * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace _HumbugBox7ff99e199a36\Symfony\Polyfill\Php73; /** * @author Gabriel Caruso * @author Ion Bazan * * @internal */ final class Php73 { public static $startAt = 1533462603; /** * @param bool $asNum * * @return array|float|int */ public static function hrtime($asNum = \false) { $ns = \microtime(\false); $s = \substr($ns, 11) - self::$startAt; $ns = 1000000000.0 * (float) $ns; if ($asNum) { $ns += $s * 1000000000.0; return \PHP_INT_SIZE === 4 ? $ns : (int) $ns; } return [$s, (int) $ns]; } } * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ use _HumbugBox7ff99e199a36\Symfony\Polyfill\Php73 as p; if (\PHP_VERSION_ID >= 70300) { return; } if (!\function_exists('is_countable')) { function is_countable($value) { return \is_array($value) || $value instanceof \Countable || $value instanceof \ResourceBundle || $value instanceof \SimpleXmlElement; } } if (!\function_exists('hrtime')) { require_once __DIR__ . '/Php73.php'; p\Php73::$startAt = (int) \microtime(\true); function hrtime($as_number = \false) { return p\Php73::hrtime($as_number); } } if (!\function_exists('array_key_first')) { function array_key_first(array $array) { foreach ($array as $key => $value) { return $key; } } } if (!\function_exists('array_key_last')) { function array_key_last(array $array) { return \key(\array_slice($array, -1, 1, \true)); } } Copyright (c) 2020-present Fabien Potencier Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Polyfill\Php80; /** * @author Ion Bazan * @author Nico Oelgart * @author Nicolas Grekas * * @internal */ final class Php80 { public static function fdiv(float $dividend, float $divisor): float { return @($dividend / $divisor); } public static function get_debug_type($value): string { switch (true) { case null === $value: return 'null'; case \is_bool($value): return 'bool'; case \is_string($value): return 'string'; case \is_array($value): return 'array'; case \is_int($value): return 'int'; case \is_float($value): return 'float'; case \is_object($value): break; case $value instanceof \__PHP_Incomplete_Class: return '__PHP_Incomplete_Class'; default: if (null === $type = @get_resource_type($value)) { return 'unknown'; } if ('Unknown' === $type) { $type = 'closed'; } return "resource ($type)"; } $class = \get_class($value); if (false === strpos($class, '@')) { return $class; } return (get_parent_class($class) ?: key(class_implements($class)) ?: 'class').'@anonymous'; } public static function get_resource_id($res): int { if (!\is_resource($res) && null === @get_resource_type($res)) { throw new \TypeError(sprintf('Argument 1 passed to get_resource_id() must be of the type resource, %s given', get_debug_type($res))); } return (int) $res; } public static function preg_last_error_msg(): string { switch (preg_last_error()) { case \PREG_INTERNAL_ERROR: return 'Internal error'; case \PREG_BAD_UTF8_ERROR: return 'Malformed UTF-8 characters, possibly incorrectly encoded'; case \PREG_BAD_UTF8_OFFSET_ERROR: return 'The offset did not correspond to the beginning of a valid UTF-8 code point'; case \PREG_BACKTRACK_LIMIT_ERROR: return 'Backtrack limit exhausted'; case \PREG_RECURSION_LIMIT_ERROR: return 'Recursion limit exhausted'; case \PREG_JIT_STACKLIMIT_ERROR: return 'JIT stack limit exhausted'; case \PREG_NO_ERROR: return 'No error'; default: return 'Unknown error'; } } public static function str_contains(string $haystack, string $needle): bool { return '' === $needle || false !== strpos($haystack, $needle); } public static function str_starts_with(string $haystack, string $needle): bool { return 0 === strncmp($haystack, $needle, \strlen($needle)); } public static function str_ends_with(string $haystack, string $needle): bool { if ('' === $needle || $needle === $haystack) { return true; } if ('' === $haystack) { return false; } $needleLength = \strlen($needle); return $needleLength <= \strlen($haystack) && 0 === substr_compare($haystack, $needle, -$needleLength); } } * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ if (\PHP_VERSION_ID < 80000 && extension_loaded('tokenizer')) { class PhpToken extends Symfony\Polyfill\Php80\PhpToken { } } * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ #[Attribute(Attribute::TARGET_CLASS)] final class Attribute { public const TARGET_CLASS = 1; public const TARGET_FUNCTION = 2; public const TARGET_METHOD = 4; public const TARGET_PROPERTY = 8; public const TARGET_CLASS_CONSTANT = 16; public const TARGET_PARAMETER = 32; public const TARGET_ALL = 63; public const IS_REPEATABLE = 64; /** @var int */ public $flags; public function __construct(int $flags = self::TARGET_ALL) { $this->flags = $flags; } } * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ if (\PHP_VERSION_ID < 80000) { class ValueError extends \Error { } } * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ if (\PHP_VERSION_ID < 80000) { interface Stringable { /** * @return string */ public function __toString(); } } * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ if (\PHP_VERSION_ID < 80000) { class UnhandledMatchError extends \Error { } } * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Polyfill\Php80; /** * @author Fedonyuk Anton * * @internal */ class PhpToken implements \Stringable { /** * @var int */ public $id; /** * @var string */ public $text; /** * @var int */ public $line; /** * @var int */ public $pos; public function __construct(int $id, string $text, int $line = -1, int $position = -1) { $this->id = $id; $this->text = $text; $this->line = $line; $this->pos = $position; } public function getTokenName(): ?string { if ('UNKNOWN' === $name = token_name($this->id)) { $name = \strlen($this->text) > 1 || \ord($this->text) < 32 ? null : $this->text; } return $name; } /** * @param int|string|array $kind */ public function is($kind): bool { foreach ((array) $kind as $value) { if (\in_array($value, [$this->id, $this->text], true)) { return true; } } return false; } public function isIgnorable(): bool { return \in_array($this->id, [\T_WHITESPACE, \T_COMMENT, \T_DOC_COMMENT, \T_OPEN_TAG], true); } public function __toString(): string { return (string) $this->text; } /** * @return static[] */ public static function tokenize(string $code, int $flags = 0): array { $line = 1; $position = 0; $tokens = token_get_all($code, $flags); foreach ($tokens as $index => $token) { if (\is_string($token)) { $id = \ord($token); $text = $token; } else { [$id, $text, $line] = $token; } $tokens[$index] = new static($id, $text, $line, $position); $position += \strlen($text); } return $tokens; } } * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ use _HumbugBox7ff99e199a36\Symfony\Polyfill\Php80 as p; if (\PHP_VERSION_ID >= 80000) { return; } if (!\defined('FILTER_VALIDATE_BOOL') && \defined('FILTER_VALIDATE_BOOLEAN')) { \define('FILTER_VALIDATE_BOOL', \FILTER_VALIDATE_BOOLEAN); } if (!\function_exists('fdiv')) { function fdiv(float $num1, float $num2) : float { return p\Php80::fdiv($num1, $num2); } } if (!\function_exists('preg_last_error_msg')) { function preg_last_error_msg() : string { return p\Php80::preg_last_error_msg(); } } if (!\function_exists('str_contains')) { function str_contains(?string $haystack, ?string $needle) : bool { return p\Php80::str_contains($haystack ?? '', $needle ?? ''); } } if (!\function_exists('str_starts_with')) { function str_starts_with(?string $haystack, ?string $needle) : bool { return p\Php80::str_starts_with($haystack ?? '', $needle ?? ''); } } if (!\function_exists('str_ends_with')) { function str_ends_with(?string $haystack, ?string $needle) : bool { return p\Php80::str_ends_with($haystack ?? '', $needle ?? ''); } } if (!\function_exists('get_debug_type')) { function get_debug_type($value) : string { return p\Php80::get_debug_type($value); } } if (!\function_exists('get_resource_id')) { function get_resource_id($resource) : int { return p\Php80::get_resource_id($resource); } } Copyright (c) 2020-present Fabien Potencier Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ if (!\function_exists('_HumbugBox7ff99e199a36\\trigger_deprecation')) { /** * Triggers a silenced deprecation notice. * * @param string $package The name of the Composer package that is triggering the deprecation * @param string $version The version of the package that introduced the deprecation * @param string $message The message of the deprecation * @param mixed ...$args Values to insert in the message using printf() formatting * * @author Nicolas Grekas */ function trigger_deprecation(string $package, string $version, string $message, ...$args) : void { @\trigger_error(($package || $version ? "Since {$package} {$version}: " : '') . ($args ? \vsprintf($message, $args) : $message), \E_USER_DEPRECATED); } } * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace _HumbugBox7ff99e199a36\Symfony\Component\Filesystem; use _HumbugBox7ff99e199a36\Symfony\Component\Filesystem\Exception\InvalidArgumentException; use _HumbugBox7ff99e199a36\Symfony\Component\Filesystem\Exception\RuntimeException; /** * Contains utility methods for handling path strings. * * The methods in this class are able to deal with both UNIX and Windows paths * with both forward and backward slashes. All methods return normalized parts * containing only forward slashes and no excess "." and ".." segments. * * @author Bernhard Schussek * @author Thomas Schulz * @author Théo Fidry */ final class Path { /** * The number of buffer entries that triggers a cleanup operation. */ private const CLEANUP_THRESHOLD = 1250; /** * The buffer size after the cleanup operation. */ private const CLEANUP_SIZE = 1000; /** * Buffers input/output of {@link canonicalize()}. * * @var array */ private static $buffer = []; /** * @var int */ private static $bufferSize = 0; /** * Canonicalizes the given path. * * During normalization, all slashes are replaced by forward slashes ("/"). * Furthermore, all "." and ".." segments are removed as far as possible. * ".." segments at the beginning of relative paths are not removed. * * ```php * echo Path::canonicalize("\symfony\puli\..\css\style.css"); * // => /symfony/css/style.css * * echo Path::canonicalize("../css/./style.css"); * // => ../css/style.css * ``` * * This method is able to deal with both UNIX and Windows paths. */ public static function canonicalize(string $path) : string { if ('' === $path) { return ''; } // This method is called by many other methods in this class. Buffer // the canonicalized paths to make up for the severe performance // decrease. if (isset(self::$buffer[$path])) { return self::$buffer[$path]; } // Replace "~" with user's home directory. if ('~' === $path[0]) { $path = self::getHomeDirectory() . \substr($path, 1); } $path = self::normalize($path); [$root, $pathWithoutRoot] = self::split($path); $canonicalParts = self::findCanonicalParts($root, $pathWithoutRoot); // Add the root directory again self::$buffer[$path] = $canonicalPath = $root . \implode('/', $canonicalParts); ++self::$bufferSize; // Clean up regularly to prevent memory leaks if (self::$bufferSize > self::CLEANUP_THRESHOLD) { self::$buffer = \array_slice(self::$buffer, -self::CLEANUP_SIZE, null, \true); self::$bufferSize = self::CLEANUP_SIZE; } return $canonicalPath; } /** * Normalizes the given path. * * During normalization, all slashes are replaced by forward slashes ("/"). * Contrary to {@link canonicalize()}, this method does not remove invalid * or dot path segments. Consequently, it is much more efficient and should * be used whenever the given path is known to be a valid, absolute system * path. * * This method is able to deal with both UNIX and Windows paths. */ public static function normalize(string $path) : string { return \str_replace('\\', '/', $path); } /** * Returns the directory part of the path. * * This method is similar to PHP's dirname(), but handles various cases * where dirname() returns a weird result: * * - dirname() does not accept backslashes on UNIX * - dirname("C:/symfony") returns "C:", not "C:/" * - dirname("C:/") returns ".", not "C:/" * - dirname("C:") returns ".", not "C:/" * - dirname("symfony") returns ".", not "" * - dirname() does not canonicalize the result * * This method fixes these shortcomings and behaves like dirname() * otherwise. * * The result is a canonical path. * * @return string The canonical directory part. Returns the root directory * if the root directory is passed. Returns an empty string * if a relative path is passed that contains no slashes. * Returns an empty string if an empty string is passed. */ public static function getDirectory(string $path) : string { if ('' === $path) { return ''; } $path = self::canonicalize($path); // Maintain scheme if (\false !== ($schemeSeparatorPosition = \strpos($path, '://'))) { $scheme = \substr($path, 0, $schemeSeparatorPosition + 3); $path = \substr($path, $schemeSeparatorPosition + 3); } else { $scheme = ''; } if (\false === ($dirSeparatorPosition = \strrpos($path, '/'))) { return ''; } // Directory equals root directory "/" if (0 === $dirSeparatorPosition) { return $scheme . '/'; } // Directory equals Windows root "C:/" if (2 === $dirSeparatorPosition && \ctype_alpha($path[0]) && ':' === $path[1]) { return $scheme . \substr($path, 0, 3); } return $scheme . \substr($path, 0, $dirSeparatorPosition); } /** * Returns canonical path of the user's home directory. * * Supported operating systems: * * - UNIX * - Windows8 and upper * * If your operating system or environment isn't supported, an exception is thrown. * * The result is a canonical path. * * @throws RuntimeException If your operating system or environment isn't supported */ public static function getHomeDirectory() : string { // For UNIX support if (\getenv('HOME')) { return self::canonicalize(\getenv('HOME')); } // For >= Windows8 support if (\getenv('HOMEDRIVE') && \getenv('HOMEPATH')) { return self::canonicalize(\getenv('HOMEDRIVE') . \getenv('HOMEPATH')); } throw new RuntimeException("Cannot find the home directory path: Your environment or operating system isn't supported."); } /** * Returns the root directory of a path. * * The result is a canonical path. * * @return string The canonical root directory. Returns an empty string if * the given path is relative or empty. */ public static function getRoot(string $path) : string { if ('' === $path) { return ''; } // Maintain scheme if (\false !== ($schemeSeparatorPosition = \strpos($path, '://'))) { $scheme = \substr($path, 0, $schemeSeparatorPosition + 3); $path = \substr($path, $schemeSeparatorPosition + 3); } else { $scheme = ''; } $firstCharacter = $path[0]; // UNIX root "/" or "\" (Windows style) if ('/' === $firstCharacter || '\\' === $firstCharacter) { return $scheme . '/'; } $length = \strlen($path); // Windows root if ($length > 1 && ':' === $path[1] && \ctype_alpha($firstCharacter)) { // Special case: "C:" if (2 === $length) { return $scheme . $path . '/'; } // Normal case: "C:/ or "C:\" if ('/' === $path[2] || '\\' === $path[2]) { return $scheme . $firstCharacter . $path[1] . '/'; } } return ''; } /** * Returns the file name without the extension from a file path. * * @param string|null $extension if specified, only that extension is cut * off (may contain leading dot) */ public static function getFilenameWithoutExtension(string $path, ?string $extension = null) : string { if ('' === $path) { return ''; } if (null !== $extension) { // remove extension and trailing dot return \rtrim(\basename($path, $extension), '.'); } return \pathinfo($path, \PATHINFO_FILENAME); } /** * Returns the extension from a file path (without leading dot). * * @param bool $forceLowerCase forces the extension to be lower-case */ public static function getExtension(string $path, bool $forceLowerCase = \false) : string { if ('' === $path) { return ''; } $extension = \pathinfo($path, \PATHINFO_EXTENSION); if ($forceLowerCase) { $extension = self::toLower($extension); } return $extension; } /** * Returns whether the path has an (or the specified) extension. * * @param string $path the path string * @param string|string[]|null $extensions if null or not provided, checks if * an extension exists, otherwise * checks for the specified extension * or array of extensions (with or * without leading dot) * @param bool $ignoreCase whether to ignore case-sensitivity */ public static function hasExtension(string $path, $extensions = null, bool $ignoreCase = \false) : bool { if ('' === $path) { return \false; } $actualExtension = self::getExtension($path, $ignoreCase); // Only check if path has any extension if ([] === $extensions || null === $extensions) { return '' !== $actualExtension; } if (\is_string($extensions)) { $extensions = [$extensions]; } foreach ($extensions as $key => $extension) { if ($ignoreCase) { $extension = self::toLower($extension); } // remove leading '.' in extensions array $extensions[$key] = \ltrim($extension, '.'); } return \in_array($actualExtension, $extensions, \true); } /** * Changes the extension of a path string. * * @param string $path The path string with filename.ext to change. * @param string $extension new extension (with or without leading dot) * * @return string the path string with new file extension */ public static function changeExtension(string $path, string $extension) : string { if ('' === $path) { return ''; } $actualExtension = self::getExtension($path); $extension = \ltrim($extension, '.'); // No extension for paths if ('/' === \substr($path, -1)) { return $path; } // No actual extension in path if (empty($actualExtension)) { return $path . ('.' === \substr($path, -1) ? '' : '.') . $extension; } return \substr($path, 0, -\strlen($actualExtension)) . $extension; } public static function isAbsolute(string $path) : bool { if ('' === $path) { return \false; } // Strip scheme if (\false !== ($schemeSeparatorPosition = \strpos($path, '://')) && 1 !== $schemeSeparatorPosition) { $path = \substr($path, $schemeSeparatorPosition + 3); } $firstCharacter = $path[0]; // UNIX root "/" or "\" (Windows style) if ('/' === $firstCharacter || '\\' === $firstCharacter) { return \true; } // Windows root if (\strlen($path) > 1 && \ctype_alpha($firstCharacter) && ':' === $path[1]) { // Special case: "C:" if (2 === \strlen($path)) { return \true; } // Normal case: "C:/ or "C:\" if ('/' === $path[2] || '\\' === $path[2]) { return \true; } } return \false; } public static function isRelative(string $path) : bool { return !self::isAbsolute($path); } /** * Turns a relative path into an absolute path in canonical form. * * Usually, the relative path is appended to the given base path. Dot * segments ("." and "..") are removed/collapsed and all slashes turned * into forward slashes. * * ```php * echo Path::makeAbsolute("../style.css", "/symfony/puli/css"); * // => /symfony/puli/style.css * ``` * * If an absolute path is passed, that path is returned unless its root * directory is different than the one of the base path. In that case, an * exception is thrown. * * ```php * Path::makeAbsolute("/style.css", "/symfony/puli/css"); * // => /style.css * * Path::makeAbsolute("C:/style.css", "C:/symfony/puli/css"); * // => C:/style.css * * Path::makeAbsolute("C:/style.css", "/symfony/puli/css"); * // InvalidArgumentException * ``` * * If the base path is not an absolute path, an exception is thrown. * * The result is a canonical path. * * @param string $basePath an absolute base path * * @throws InvalidArgumentException if the base path is not absolute or if * the given path is an absolute path with * a different root than the base path */ public static function makeAbsolute(string $path, string $basePath) : string { if ('' === $basePath) { throw new InvalidArgumentException(\sprintf('The base path must be a non-empty string. Got: "%s".', $basePath)); } if (!self::isAbsolute($basePath)) { throw new InvalidArgumentException(\sprintf('The base path "%s" is not an absolute path.', $basePath)); } if (self::isAbsolute($path)) { return self::canonicalize($path); } if (\false !== ($schemeSeparatorPosition = \strpos($basePath, '://'))) { $scheme = \substr($basePath, 0, $schemeSeparatorPosition + 3); $basePath = \substr($basePath, $schemeSeparatorPosition + 3); } else { $scheme = ''; } return $scheme . self::canonicalize(\rtrim($basePath, '/\\') . '/' . $path); } /** * Turns a path into a relative path. * * The relative path is created relative to the given base path: * * ```php * echo Path::makeRelative("/symfony/style.css", "/symfony/puli"); * // => ../style.css * ``` * * If a relative path is passed and the base path is absolute, the relative * path is returned unchanged: * * ```php * Path::makeRelative("style.css", "/symfony/puli/css"); * // => style.css * ``` * * If both paths are relative, the relative path is created with the * assumption that both paths are relative to the same directory: * * ```php * Path::makeRelative("style.css", "symfony/puli/css"); * // => ../../../style.css * ``` * * If both paths are absolute, their root directory must be the same, * otherwise an exception is thrown: * * ```php * Path::makeRelative("C:/symfony/style.css", "/symfony/puli"); * // InvalidArgumentException * ``` * * If the passed path is absolute, but the base path is not, an exception * is thrown as well: * * ```php * Path::makeRelative("/symfony/style.css", "symfony/puli"); * // InvalidArgumentException * ``` * * If the base path is not an absolute path, an exception is thrown. * * The result is a canonical path. * * @throws InvalidArgumentException if the base path is not absolute or if * the given path has a different root * than the base path */ public static function makeRelative(string $path, string $basePath) : string { $path = self::canonicalize($path); $basePath = self::canonicalize($basePath); [$root, $relativePath] = self::split($path); [$baseRoot, $relativeBasePath] = self::split($basePath); // If the base path is given as absolute path and the path is already // relative, consider it to be relative to the given absolute path // already if ('' === $root && '' !== $baseRoot) { // If base path is already in its root if ('' === $relativeBasePath) { $relativePath = \ltrim($relativePath, './\\'); } return $relativePath; } // If the passed path is absolute, but the base path is not, we // cannot generate a relative path if ('' !== $root && '' === $baseRoot) { throw new InvalidArgumentException(\sprintf('The absolute path "%s" cannot be made relative to the relative path "%s". You should provide an absolute base path instead.', $path, $basePath)); } // Fail if the roots of the two paths are different if ($baseRoot && $root !== $baseRoot) { throw new InvalidArgumentException(\sprintf('The path "%s" cannot be made relative to "%s", because they have different roots ("%s" and "%s").', $path, $basePath, $root, $baseRoot)); } if ('' === $relativeBasePath) { return $relativePath; } // Build a "../../" prefix with as many "../" parts as necessary $parts = \explode('/', $relativePath); $baseParts = \explode('/', $relativeBasePath); $dotDotPrefix = ''; // Once we found a non-matching part in the prefix, we need to add // "../" parts for all remaining parts $match = \true; foreach ($baseParts as $index => $basePart) { if ($match && isset($parts[$index]) && $basePart === $parts[$index]) { unset($parts[$index]); continue; } $match = \false; $dotDotPrefix .= '../'; } return \rtrim($dotDotPrefix . \implode('/', $parts), '/'); } /** * Returns whether the given path is on the local filesystem. */ public static function isLocal(string $path) : bool { return '' !== $path && \false === \strpos($path, '://'); } /** * Returns the longest common base path in canonical form of a set of paths or * `null` if the paths are on different Windows partitions. * * Dot segments ("." and "..") are removed/collapsed and all slashes turned * into forward slashes. * * ```php * $basePath = Path::getLongestCommonBasePath( * '/symfony/css/style.css', * '/symfony/css/..' * ); * // => /symfony * ``` * * The root is returned if no common base path can be found: * * ```php * $basePath = Path::getLongestCommonBasePath( * '/symfony/css/style.css', * '/puli/css/..' * ); * // => / * ``` * * If the paths are located on different Windows partitions, `null` is * returned. * * ```php * $basePath = Path::getLongestCommonBasePath( * 'C:/symfony/css/style.css', * 'D:/symfony/css/..' * ); * // => null * ``` */ public static function getLongestCommonBasePath(string ...$paths) : ?string { [$bpRoot, $basePath] = self::split(self::canonicalize(\reset($paths))); for (\next($paths); null !== \key($paths) && '' !== $basePath; \next($paths)) { [$root, $path] = self::split(self::canonicalize(\current($paths))); // If we deal with different roots (e.g. C:/ vs. D:/), it's time // to quit if ($root !== $bpRoot) { return null; } // Make the base path shorter until it fits into path while (\true) { if ('.' === $basePath) { // No more base paths $basePath = ''; // next path continue 2; } // Prevent false positives for common prefixes // see isBasePath() if (0 === \strpos($path . '/', $basePath . '/')) { // next path continue 2; } $basePath = \dirname($basePath); } } return $bpRoot . $basePath; } /** * Joins two or more path strings into a canonical path. */ public static function join(string ...$paths) : string { $finalPath = null; $wasScheme = \false; foreach ($paths as $path) { if ('' === $path) { continue; } if (null === $finalPath) { // For first part we keep slashes, like '/top', 'C:\' or 'phar://' $finalPath = $path; $wasScheme = \false !== \strpos($path, '://'); continue; } // Only add slash if previous part didn't end with '/' or '\' if (!\in_array(\substr($finalPath, -1), ['/', '\\'])) { $finalPath .= '/'; } // If first part included a scheme like 'phar://' we allow \current part to start with '/', otherwise trim $finalPath .= $wasScheme ? $path : \ltrim($path, '/'); $wasScheme = \false; } if (null === $finalPath) { return ''; } return self::canonicalize($finalPath); } /** * Returns whether a path is a base path of another path. * * Dot segments ("." and "..") are removed/collapsed and all slashes turned * into forward slashes. * * ```php * Path::isBasePath('/symfony', '/symfony/css'); * // => true * * Path::isBasePath('/symfony', '/symfony'); * // => true * * Path::isBasePath('/symfony', '/symfony/..'); * // => false * * Path::isBasePath('/symfony', '/puli'); * // => false * ``` */ public static function isBasePath(string $basePath, string $ofPath) : bool { $basePath = self::canonicalize($basePath); $ofPath = self::canonicalize($ofPath); // Append slashes to prevent false positives when two paths have // a common prefix, for example /base/foo and /base/foobar. // Don't append a slash for the root "/", because then that root // won't be discovered as common prefix ("//" is not a prefix of // "/foobar/"). return 0 === \strpos($ofPath . '/', \rtrim($basePath, '/') . '/'); } /** * @return string[] */ private static function findCanonicalParts(string $root, string $pathWithoutRoot) : array { $parts = \explode('/', $pathWithoutRoot); $canonicalParts = []; // Collapse "." and "..", if possible foreach ($parts as $part) { if ('.' === $part || '' === $part) { continue; } // Collapse ".." with the previous part, if one exists // Don't collapse ".." if the previous part is also ".." if ('..' === $part && \count($canonicalParts) > 0 && '..' !== $canonicalParts[\count($canonicalParts) - 1]) { \array_pop($canonicalParts); continue; } // Only add ".." prefixes for relative paths if ('..' !== $part || '' === $root) { $canonicalParts[] = $part; } } return $canonicalParts; } /** * Splits a canonical path into its root directory and the remainder. * * If the path has no root directory, an empty root directory will be * returned. * * If the root directory is a Windows style partition, the resulting root * will always contain a trailing slash. * * list ($root, $path) = Path::split("C:/symfony") * // => ["C:/", "symfony"] * * list ($root, $path) = Path::split("C:") * // => ["C:/", ""] * * @return array{string, string} an array with the root directory and the remaining relative path */ private static function split(string $path) : array { if ('' === $path) { return ['', '']; } // Remember scheme as part of the root, if any if (\false !== ($schemeSeparatorPosition = \strpos($path, '://'))) { $root = \substr($path, 0, $schemeSeparatorPosition + 3); $path = \substr($path, $schemeSeparatorPosition + 3); } else { $root = ''; } $length = \strlen($path); // Remove and remember root directory if (0 === \strpos($path, '/')) { $root .= '/'; $path = $length > 1 ? \substr($path, 1) : ''; } elseif ($length > 1 && \ctype_alpha($path[0]) && ':' === $path[1]) { if (2 === $length) { // Windows special case: "C:" $root .= $path . '/'; $path = ''; } elseif ('/' === $path[2]) { // Windows normal case: "C:/".. $root .= \substr($path, 0, 3); $path = $length > 3 ? \substr($path, 3) : ''; } } return [$root, $path]; } private static function toLower(string $string) : string { if (\false !== ($encoding = \mb_detect_encoding($string, null, \true))) { return \mb_strtolower($string, $encoding); } return \strtolower($string); } private function __construct() { } } Copyright (c) 2004-present Fabien Potencier Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace _HumbugBox7ff99e199a36\Symfony\Component\Filesystem\Exception; /** * Exception interface for all exceptions thrown by the component. * * @author Romain Neutron */ interface ExceptionInterface extends \Throwable { } * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace _HumbugBox7ff99e199a36\Symfony\Component\Filesystem\Exception; /** * IOException interface for file and input/output stream related exceptions thrown by the component. * * @author Christian Gärtner */ interface IOExceptionInterface extends ExceptionInterface { /** * Returns the associated path for the exception. * * @return string|null */ public function getPath(); } * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace _HumbugBox7ff99e199a36\Symfony\Component\Filesystem\Exception; /** * Exception class thrown when a filesystem operation failure happens. * * @author Romain Neutron * @author Christian Gärtner * @author Fabien Potencier */ class IOException extends \RuntimeException implements IOExceptionInterface { private $path; public function __construct(string $message, int $code = 0, ?\Throwable $previous = null, ?string $path = null) { $this->path = $path; parent::__construct($message, $code, $previous); } /** * {@inheritdoc} */ public function getPath() { return $this->path; } } * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace _HumbugBox7ff99e199a36\Symfony\Component\Filesystem\Exception; /** * Exception class thrown when a file couldn't be found. * * @author Fabien Potencier * @author Christian Gärtner */ class FileNotFoundException extends IOException { public function __construct(?string $message = null, int $code = 0, ?\Throwable $previous = null, ?string $path = null) { if (null === $message) { if (null === $path) { $message = 'File could not be found.'; } else { $message = \sprintf('File "%s" could not be found.', $path); } } parent::__construct($message, $code, $previous, $path); } } * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace _HumbugBox7ff99e199a36\Symfony\Component\Filesystem\Exception; /** * @author Théo Fidry */ class RuntimeException extends \RuntimeException implements ExceptionInterface { } * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace _HumbugBox7ff99e199a36\Symfony\Component\Filesystem\Exception; /** * @author Christian Flothmann */ class InvalidArgumentException extends \InvalidArgumentException implements ExceptionInterface { } * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace _HumbugBox7ff99e199a36\Symfony\Component\Filesystem; use _HumbugBox7ff99e199a36\Symfony\Component\Filesystem\Exception\FileNotFoundException; use _HumbugBox7ff99e199a36\Symfony\Component\Filesystem\Exception\InvalidArgumentException; use _HumbugBox7ff99e199a36\Symfony\Component\Filesystem\Exception\IOException; /** * Provides basic utility to manipulate the file system. * * @author Fabien Potencier */ class Filesystem { private static $lastError; /** * Copies a file. * * If the target file is older than the origin file, it's always overwritten. * If the target file is newer, it is overwritten only when the * $overwriteNewerFiles option is set to true. * * @throws FileNotFoundException When originFile doesn't exist * @throws IOException When copy fails */ public function copy(string $originFile, string $targetFile, bool $overwriteNewerFiles = \false) { $originIsLocal = \stream_is_local($originFile) || 0 === \stripos($originFile, 'file://'); if ($originIsLocal && !\is_file($originFile)) { throw new FileNotFoundException(\sprintf('Failed to copy "%s" because file does not exist.', $originFile), 0, null, $originFile); } $this->mkdir(\dirname($targetFile)); $doCopy = \true; if (!$overwriteNewerFiles && null === \parse_url($originFile, \PHP_URL_HOST) && \is_file($targetFile)) { $doCopy = \filemtime($originFile) > \filemtime($targetFile); } if ($doCopy) { // https://bugs.php.net/64634 if (!($source = self::box('fopen', $originFile, 'r'))) { throw new IOException(\sprintf('Failed to copy "%s" to "%s" because source file could not be opened for reading: ', $originFile, $targetFile) . self::$lastError, 0, null, $originFile); } // Stream context created to allow files overwrite when using FTP stream wrapper - disabled by default if (!($target = self::box('fopen', $targetFile, 'w', \false, \stream_context_create(['ftp' => ['overwrite' => \true]])))) { throw new IOException(\sprintf('Failed to copy "%s" to "%s" because target file could not be opened for writing: ', $originFile, $targetFile) . self::$lastError, 0, null, $originFile); } $bytesCopied = \stream_copy_to_stream($source, $target); \fclose($source); \fclose($target); unset($source, $target); if (!\is_file($targetFile)) { throw new IOException(\sprintf('Failed to copy "%s" to "%s".', $originFile, $targetFile), 0, null, $originFile); } if ($originIsLocal) { // Like `cp`, preserve executable permission bits self::box('chmod', $targetFile, \fileperms($targetFile) | \fileperms($originFile) & 0111); // Like `cp`, preserve the file modification time self::box('touch', $targetFile, \filemtime($originFile)); if ($bytesCopied !== ($bytesOrigin = \filesize($originFile))) { throw new IOException(\sprintf('Failed to copy the whole content of "%s" to "%s" (%g of %g bytes copied).', $originFile, $targetFile, $bytesCopied, $bytesOrigin), 0, null, $originFile); } } } } /** * Creates a directory recursively. * * @param string|iterable $dirs The directory path * * @throws IOException On any directory creation failure */ public function mkdir($dirs, int $mode = 0777) { foreach ($this->toIterable($dirs) as $dir) { if (\is_dir($dir)) { continue; } if (!self::box('mkdir', $dir, $mode, \true) && !\is_dir($dir)) { throw new IOException(\sprintf('Failed to create "%s": ', $dir) . self::$lastError, 0, null, $dir); } } } /** * Checks the existence of files or directories. * * @param string|iterable $files A filename, an array of files, or a \Traversable instance to check * * @return bool */ public function exists($files) { $maxPathLength = \PHP_MAXPATHLEN - 2; foreach ($this->toIterable($files) as $file) { if (\strlen($file) > $maxPathLength) { throw new IOException(\sprintf('Could not check if file exist because path length exceeds %d characters.', $maxPathLength), 0, null, $file); } if (!\file_exists($file)) { return \false; } } return \true; } /** * Sets access and modification time of file. * * @param string|iterable $files A filename, an array of files, or a \Traversable instance to create * @param int|null $time The touch time as a Unix timestamp, if not supplied the current system time is used * @param int|null $atime The access time as a Unix timestamp, if not supplied the current system time is used * * @throws IOException When touch fails */ public function touch($files, ?int $time = null, ?int $atime = null) { foreach ($this->toIterable($files) as $file) { if (!($time ? self::box('touch', $file, $time, $atime) : self::box('touch', $file))) { throw new IOException(\sprintf('Failed to touch "%s": ', $file) . self::$lastError, 0, null, $file); } } } /** * Removes files or directories. * * @param string|iterable $files A filename, an array of files, or a \Traversable instance to remove * * @throws IOException When removal fails */ public function remove($files) { if ($files instanceof \Traversable) { $files = \iterator_to_array($files, \false); } elseif (!\is_array($files)) { $files = [$files]; } self::doRemove($files, \false); } private static function doRemove(array $files, bool $isRecursive) : void { $files = \array_reverse($files); foreach ($files as $file) { if (\is_link($file)) { // See https://bugs.php.net/52176 if (!(self::box('unlink', $file) || '\\' !== \DIRECTORY_SEPARATOR || self::box('rmdir', $file)) && \file_exists($file)) { throw new IOException(\sprintf('Failed to remove symlink "%s": ', $file) . self::$lastError); } } elseif (\is_dir($file)) { if (!$isRecursive) { $tmpName = \dirname(\realpath($file)) . '/.!' . \strrev(\strtr(\base64_encode(\random_bytes(2)), '/=', '-!')); if (\file_exists($tmpName)) { try { self::doRemove([$tmpName], \true); } catch (IOException $e) { } } if (!\file_exists($tmpName) && self::box('rename', $file, $tmpName)) { $origFile = $file; $file = $tmpName; } else { $origFile = null; } } $files = new \FilesystemIterator($file, \FilesystemIterator::CURRENT_AS_PATHNAME | \FilesystemIterator::SKIP_DOTS); self::doRemove(\iterator_to_array($files, \true), \true); if (!self::box('rmdir', $file) && \file_exists($file) && !$isRecursive) { $lastError = self::$lastError; if (null !== $origFile && self::box('rename', $file, $origFile)) { $file = $origFile; } throw new IOException(\sprintf('Failed to remove directory "%s": ', $file) . $lastError); } } elseif (!self::box('unlink', $file) && (self::$lastError && \str_contains(self::$lastError, 'Permission denied') || \file_exists($file))) { throw new IOException(\sprintf('Failed to remove file "%s": ', $file) . self::$lastError); } } } /** * Change mode for an array of files or directories. * * @param string|iterable $files A filename, an array of files, or a \Traversable instance to change mode * @param int $mode The new mode (octal) * @param int $umask The mode mask (octal) * @param bool $recursive Whether change the mod recursively or not * * @throws IOException When the change fails */ public function chmod($files, int $mode, int $umask = 00, bool $recursive = \false) { foreach ($this->toIterable($files) as $file) { if ((\PHP_VERSION_ID < 80000 || \is_int($mode)) && !self::box('chmod', $file, $mode & ~$umask)) { throw new IOException(\sprintf('Failed to chmod file "%s": ', $file) . self::$lastError, 0, null, $file); } if ($recursive && \is_dir($file) && !\is_link($file)) { $this->chmod(new \FilesystemIterator($file), $mode, $umask, \true); } } } /** * Change the owner of an array of files or directories. * * @param string|iterable $files A filename, an array of files, or a \Traversable instance to change owner * @param string|int $user A user name or number * @param bool $recursive Whether change the owner recursively or not * * @throws IOException When the change fails */ public function chown($files, $user, bool $recursive = \false) { foreach ($this->toIterable($files) as $file) { if ($recursive && \is_dir($file) && !\is_link($file)) { $this->chown(new \FilesystemIterator($file), $user, \true); } if (\is_link($file) && \function_exists('lchown')) { if (!self::box('lchown', $file, $user)) { throw new IOException(\sprintf('Failed to chown file "%s": ', $file) . self::$lastError, 0, null, $file); } } else { if (!self::box('chown', $file, $user)) { throw new IOException(\sprintf('Failed to chown file "%s": ', $file) . self::$lastError, 0, null, $file); } } } } /** * Change the group of an array of files or directories. * * @param string|iterable $files A filename, an array of files, or a \Traversable instance to change group * @param string|int $group A group name or number * @param bool $recursive Whether change the group recursively or not * * @throws IOException When the change fails */ public function chgrp($files, $group, bool $recursive = \false) { foreach ($this->toIterable($files) as $file) { if ($recursive && \is_dir($file) && !\is_link($file)) { $this->chgrp(new \FilesystemIterator($file), $group, \true); } if (\is_link($file) && \function_exists('lchgrp')) { if (!self::box('lchgrp', $file, $group)) { throw new IOException(\sprintf('Failed to chgrp file "%s": ', $file) . self::$lastError, 0, null, $file); } } else { if (!self::box('chgrp', $file, $group)) { throw new IOException(\sprintf('Failed to chgrp file "%s": ', $file) . self::$lastError, 0, null, $file); } } } } /** * Renames a file or a directory. * * @throws IOException When target file or directory already exists * @throws IOException When origin cannot be renamed */ public function rename(string $origin, string $target, bool $overwrite = \false) { // we check that target does not exist if (!$overwrite && $this->isReadable($target)) { throw new IOException(\sprintf('Cannot rename because the target "%s" already exists.', $target), 0, null, $target); } if (!self::box('rename', $origin, $target)) { if (\is_dir($origin)) { // See https://bugs.php.net/54097 & https://php.net/rename#113943 $this->mirror($origin, $target, null, ['override' => $overwrite, 'delete' => $overwrite]); $this->remove($origin); return; } throw new IOException(\sprintf('Cannot rename "%s" to "%s": ', $origin, $target) . self::$lastError, 0, null, $target); } } /** * Tells whether a file exists and is readable. * * @throws IOException When windows path is longer than 258 characters */ private function isReadable(string $filename) : bool { $maxPathLength = \PHP_MAXPATHLEN - 2; if (\strlen($filename) > $maxPathLength) { throw new IOException(\sprintf('Could not check if file is readable because path length exceeds %d characters.', $maxPathLength), 0, null, $filename); } return \is_readable($filename); } /** * Creates a symbolic link or copy a directory. * * @throws IOException When symlink fails */ public function symlink(string $originDir, string $targetDir, bool $copyOnWindows = \false) { self::assertFunctionExists('symlink'); if ('\\' === \DIRECTORY_SEPARATOR) { $originDir = \strtr($originDir, '/', '\\'); $targetDir = \strtr($targetDir, '/', '\\'); if ($copyOnWindows) { $this->mirror($originDir, $targetDir); return; } } $this->mkdir(\dirname($targetDir)); if (\is_link($targetDir)) { if (\readlink($targetDir) === $originDir) { return; } $this->remove($targetDir); } if (!self::box('symlink', $originDir, $targetDir)) { $this->linkException($originDir, $targetDir, 'symbolic'); } } /** * Creates a hard link, or several hard links to a file. * * @param string|string[] $targetFiles The target file(s) * * @throws FileNotFoundException When original file is missing or not a file * @throws IOException When link fails, including if link already exists */ public function hardlink(string $originFile, $targetFiles) { self::assertFunctionExists('link'); if (!$this->exists($originFile)) { throw new FileNotFoundException(null, 0, null, $originFile); } if (!\is_file($originFile)) { throw new FileNotFoundException(\sprintf('Origin file "%s" is not a file.', $originFile)); } foreach ($this->toIterable($targetFiles) as $targetFile) { if (\is_file($targetFile)) { if (\fileinode($originFile) === \fileinode($targetFile)) { continue; } $this->remove($targetFile); } if (!self::box('link', $originFile, $targetFile)) { $this->linkException($originFile, $targetFile, 'hard'); } } } /** * @param string $linkType Name of the link type, typically 'symbolic' or 'hard' */ private function linkException(string $origin, string $target, string $linkType) { if (self::$lastError) { if ('\\' === \DIRECTORY_SEPARATOR && \str_contains(self::$lastError, 'error code(1314)')) { throw new IOException(\sprintf('Unable to create "%s" link due to error code 1314: \'A required privilege is not held by the client\'. Do you have the required Administrator-rights?', $linkType), 0, null, $target); } } throw new IOException(\sprintf('Failed to create "%s" link from "%s" to "%s": ', $linkType, $origin, $target) . self::$lastError, 0, null, $target); } /** * Resolves links in paths. * * With $canonicalize = false (default) * - if $path does not exist or is not a link, returns null * - if $path is a link, returns the next direct target of the link without considering the existence of the target * * With $canonicalize = true * - if $path does not exist, returns null * - if $path exists, returns its absolute fully resolved final version * * @return string|null */ public function readlink(string $path, bool $canonicalize = \false) { if (!$canonicalize && !\is_link($path)) { return null; } if ($canonicalize) { if (!$this->exists($path)) { return null; } if ('\\' === \DIRECTORY_SEPARATOR && \PHP_VERSION_ID < 70410) { $path = \readlink($path); } return \realpath($path); } if ('\\' === \DIRECTORY_SEPARATOR && \PHP_VERSION_ID < 70400) { return \realpath($path); } return \readlink($path); } /** * Given an existing path, convert it to a path relative to a given starting path. * * @return string */ public function makePathRelative(string $endPath, string $startPath) { if (!$this->isAbsolutePath($startPath)) { throw new InvalidArgumentException(\sprintf('The start path "%s" is not absolute.', $startPath)); } if (!$this->isAbsolutePath($endPath)) { throw new InvalidArgumentException(\sprintf('The end path "%s" is not absolute.', $endPath)); } // Normalize separators on Windows if ('\\' === \DIRECTORY_SEPARATOR) { $endPath = \str_replace('\\', '/', $endPath); $startPath = \str_replace('\\', '/', $startPath); } $splitDriveLetter = function ($path) { return \strlen($path) > 2 && ':' === $path[1] && '/' === $path[2] && \ctype_alpha($path[0]) ? [\substr($path, 2), \strtoupper($path[0])] : [$path, null]; }; $splitPath = function ($path) { $result = []; foreach (\explode('/', \trim($path, '/')) as $segment) { if ('..' === $segment) { \array_pop($result); } elseif ('.' !== $segment && '' !== $segment) { $result[] = $segment; } } return $result; }; [$endPath, $endDriveLetter] = $splitDriveLetter($endPath); [$startPath, $startDriveLetter] = $splitDriveLetter($startPath); $startPathArr = $splitPath($startPath); $endPathArr = $splitPath($endPath); if ($endDriveLetter && $startDriveLetter && $endDriveLetter != $startDriveLetter) { // End path is on another drive, so no relative path exists return $endDriveLetter . ':/' . ($endPathArr ? \implode('/', $endPathArr) . '/' : ''); } // Find for which directory the common path stops $index = 0; while (isset($startPathArr[$index]) && isset($endPathArr[$index]) && $startPathArr[$index] === $endPathArr[$index]) { ++$index; } // Determine how deep the start path is relative to the common path (ie, "web/bundles" = 2 levels) if (1 === \count($startPathArr) && '' === $startPathArr[0]) { $depth = 0; } else { $depth = \count($startPathArr) - $index; } // Repeated "../" for each level need to reach the common path $traverser = \str_repeat('../', $depth); $endPathRemainder = \implode('/', \array_slice($endPathArr, $index)); // Construct $endPath from traversing to the common path, then to the remaining $endPath $relativePath = $traverser . ('' !== $endPathRemainder ? $endPathRemainder . '/' : ''); return '' === $relativePath ? './' : $relativePath; } /** * Mirrors a directory to another. * * Copies files and directories from the origin directory into the target directory. By default: * * - existing files in the target directory will be overwritten, except if they are newer (see the `override` option) * - files in the target directory that do not exist in the source directory will not be deleted (see the `delete` option) * * @param \Traversable|null $iterator Iterator that filters which files and directories to copy, if null a recursive iterator is created * @param array $options An array of boolean options * Valid options are: * - $options['override'] If true, target files newer than origin files are overwritten (see copy(), defaults to false) * - $options['copy_on_windows'] Whether to copy files instead of links on Windows (see symlink(), defaults to false) * - $options['delete'] Whether to delete files that are not in the source directory (defaults to false) * * @throws IOException When file type is unknown */ public function mirror(string $originDir, string $targetDir, ?\Traversable $iterator = null, array $options = []) { $targetDir = \rtrim($targetDir, '/\\'); $originDir = \rtrim($originDir, '/\\'); $originDirLen = \strlen($originDir); if (!$this->exists($originDir)) { throw new IOException(\sprintf('The origin directory specified "%s" was not found.', $originDir), 0, null, $originDir); } // Iterate in destination folder to remove obsolete entries if ($this->exists($targetDir) && isset($options['delete']) && $options['delete']) { $deleteIterator = $iterator; if (null === $deleteIterator) { $flags = \FilesystemIterator::SKIP_DOTS; $deleteIterator = new \RecursiveIteratorIterator(new \RecursiveDirectoryIterator($targetDir, $flags), \RecursiveIteratorIterator::CHILD_FIRST); } $targetDirLen = \strlen($targetDir); foreach ($deleteIterator as $file) { $origin = $originDir . \substr($file->getPathname(), $targetDirLen); if (!$this->exists($origin)) { $this->remove($file); } } } $copyOnWindows = $options['copy_on_windows'] ?? \false; if (null === $iterator) { $flags = $copyOnWindows ? \FilesystemIterator::SKIP_DOTS | \FilesystemIterator::FOLLOW_SYMLINKS : \FilesystemIterator::SKIP_DOTS; $iterator = new \RecursiveIteratorIterator(new \RecursiveDirectoryIterator($originDir, $flags), \RecursiveIteratorIterator::SELF_FIRST); } $this->mkdir($targetDir); $filesCreatedWhileMirroring = []; foreach ($iterator as $file) { if ($file->getPathname() === $targetDir || $file->getRealPath() === $targetDir || isset($filesCreatedWhileMirroring[$file->getRealPath()])) { continue; } $target = $targetDir . \substr($file->getPathname(), $originDirLen); $filesCreatedWhileMirroring[$target] = \true; if (!$copyOnWindows && \is_link($file)) { $this->symlink($file->getLinkTarget(), $target); } elseif (\is_dir($file)) { $this->mkdir($target); } elseif (\is_file($file)) { $this->copy($file, $target, $options['override'] ?? \false); } else { throw new IOException(\sprintf('Unable to guess "%s" file type.', $file), 0, null, $file); } } } /** * Returns whether the file path is an absolute path. * * @return bool */ public function isAbsolutePath(string $file) { return '' !== $file && (\strspn($file, '/\\', 0, 1) || \strlen($file) > 3 && \ctype_alpha($file[0]) && ':' === $file[1] && \strspn($file, '/\\', 2, 1) || null !== \parse_url($file, \PHP_URL_SCHEME)); } /** * Creates a temporary file with support for custom stream wrappers. * * @param string $prefix The prefix of the generated temporary filename * Note: Windows uses only the first three characters of prefix * @param string $suffix The suffix of the generated temporary filename * * @return string The new temporary filename (with path), or throw an exception on failure */ public function tempnam(string $dir, string $prefix) { $suffix = \func_num_args() > 2 ? \func_get_arg(2) : ''; [$scheme, $hierarchy] = $this->getSchemeAndHierarchy($dir); // If no scheme or scheme is "file" or "gs" (Google Cloud) create temp file in local filesystem if ((null === $scheme || 'file' === $scheme || 'gs' === $scheme) && '' === $suffix) { // If tempnam failed or no scheme return the filename otherwise prepend the scheme if ($tmpFile = self::box('tempnam', $hierarchy, $prefix)) { if (null !== $scheme && 'gs' !== $scheme) { return $scheme . '://' . $tmpFile; } return $tmpFile; } throw new IOException('A temporary file could not be created: ' . self::$lastError); } // Loop until we create a valid temp file or have reached 10 attempts for ($i = 0; $i < 10; ++$i) { // Create a unique filename $tmpFile = $dir . '/' . $prefix . \uniqid(\mt_rand(), \true) . $suffix; // Use fopen instead of file_exists as some streams do not support stat // Use mode 'x+' to atomically check existence and create to avoid a TOCTOU vulnerability if (!($handle = self::box('fopen', $tmpFile, 'x+'))) { continue; } // Close the file if it was successfully opened self::box('fclose', $handle); return $tmpFile; } throw new IOException('A temporary file could not be created: ' . self::$lastError); } /** * Atomically dumps content into a file. * * @param string|resource $content The data to write into the file * * @throws IOException if the file cannot be written to */ public function dumpFile(string $filename, $content) { if (\is_array($content)) { throw new \TypeError(\sprintf('Argument 2 passed to "%s()" must be string or resource, array given.', __METHOD__)); } $dir = \dirname($filename); if (\is_link($filename) && ($linkTarget = $this->readlink($filename))) { $this->dumpFile(Path::makeAbsolute($linkTarget, $dir), $content); return; } if (!\is_dir($dir)) { $this->mkdir($dir); } // Will create a temp file with 0600 access rights // when the filesystem supports chmod. $tmpFile = $this->tempnam($dir, \basename($filename)); try { if (\false === self::box('file_put_contents', $tmpFile, $content)) { throw new IOException(\sprintf('Failed to write file "%s": ', $filename) . self::$lastError, 0, null, $filename); } self::box('chmod', $tmpFile, self::box('fileperms', $filename) ?: 0666 & ~\umask()); $this->rename($tmpFile, $filename, \true); } finally { if (\file_exists($tmpFile)) { self::box('unlink', $tmpFile); } } } /** * Appends content to an existing file. * * @param string|resource $content The content to append * @param bool $lock Whether the file should be locked when writing to it * * @throws IOException If the file is not writable */ public function appendToFile(string $filename, $content) { if (\is_array($content)) { throw new \TypeError(\sprintf('Argument 2 passed to "%s()" must be string or resource, array given.', __METHOD__)); } $dir = \dirname($filename); if (!\is_dir($dir)) { $this->mkdir($dir); } $lock = \func_num_args() > 2 && \func_get_arg(2); if (\false === self::box('file_put_contents', $filename, $content, \FILE_APPEND | ($lock ? \LOCK_EX : 0))) { throw new IOException(\sprintf('Failed to write file "%s": ', $filename) . self::$lastError, 0, null, $filename); } } private function toIterable($files) : iterable { return \is_iterable($files) ? $files : [$files]; } /** * Gets a 2-tuple of scheme (may be null) and hierarchical part of a filename (e.g. file:///tmp -> [file, tmp]). */ private function getSchemeAndHierarchy(string $filename) : array { $components = \explode('://', $filename, 2); return 2 === \count($components) ? [$components[0], $components[1]] : [null, $components[0]]; } private static function assertFunctionExists(string $func) : void { if (!\function_exists($func)) { throw new IOException(\sprintf('Unable to perform filesystem operation because the "%s()" function has been disabled.', $func)); } } /** * @param mixed ...$args * * @return mixed */ private static function box(string $func, ...$args) { self::assertFunctionExists($func); self::$lastError = null; \set_error_handler(__CLASS__ . '::handleError'); try { return $func(...$args); } finally { \restore_error_handler(); } } /** * @internal */ public static function handleError(int $type, string $msg) { self::$lastError = $msg; } } Copyright (c) 2015-present Fabien Potencier Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ' ', '¨' => ' ̈', 'ª' => 'a', '¯' => ' ̄', '²' => '2', '³' => '3', '´' => ' ́', 'µ' => 'μ', '¸' => ' ̧', '¹' => '1', 'º' => 'o', '¼' => '1⁄4', '½' => '1⁄2', '¾' => '3⁄4', 'IJ' => 'IJ', 'ij' => 'ij', 'Ŀ' => 'L·', 'ŀ' => 'l·', 'ʼn' => 'ʼn', 'ſ' => 's', 'DŽ' => 'DŽ', 'Dž' => 'Dž', 'dž' => 'dž', 'LJ' => 'LJ', 'Lj' => 'Lj', 'lj' => 'lj', 'NJ' => 'NJ', 'Nj' => 'Nj', 'nj' => 'nj', 'DZ' => 'DZ', 'Dz' => 'Dz', 'dz' => 'dz', 'ʰ' => 'h', 'ʱ' => 'ɦ', 'ʲ' => 'j', 'ʳ' => 'r', 'ʴ' => 'ɹ', 'ʵ' => 'ɻ', 'ʶ' => 'ʁ', 'ʷ' => 'w', 'ʸ' => 'y', '˘' => ' ̆', '˙' => ' ̇', '˚' => ' ̊', '˛' => ' ̨', '˜' => ' ̃', '˝' => ' ̋', 'ˠ' => 'ɣ', 'ˡ' => 'l', 'ˢ' => 's', 'ˣ' => 'x', 'ˤ' => 'ʕ', 'ͺ' => ' ͅ', '΄' => ' ́', '΅' => ' ̈́', 'ϐ' => 'β', 'ϑ' => 'θ', 'ϒ' => 'Υ', 'ϓ' => 'Ύ', 'ϔ' => 'Ϋ', 'ϕ' => 'φ', 'ϖ' => 'π', 'ϰ' => 'κ', 'ϱ' => 'ρ', 'ϲ' => 'ς', 'ϴ' => 'Θ', 'ϵ' => 'ε', 'Ϲ' => 'Σ', 'և' => 'եւ', 'ٵ' => 'اٴ', 'ٶ' => 'وٴ', 'ٷ' => 'ۇٴ', 'ٸ' => 'يٴ', 'ำ' => 'ํา', 'ຳ' => 'ໍາ', 'ໜ' => 'ຫນ', 'ໝ' => 'ຫມ', '༌' => '་', 'ཷ' => 'ྲཱྀ', 'ཹ' => 'ླཱྀ', 'ჼ' => 'ნ', 'ᴬ' => 'A', 'ᴭ' => 'Æ', 'ᴮ' => 'B', 'ᴰ' => 'D', 'ᴱ' => 'E', 'ᴲ' => 'Ǝ', 'ᴳ' => 'G', 'ᴴ' => 'H', 'ᴵ' => 'I', 'ᴶ' => 'J', 'ᴷ' => 'K', 'ᴸ' => 'L', 'ᴹ' => 'M', 'ᴺ' => 'N', 'ᴼ' => 'O', 'ᴽ' => 'Ȣ', 'ᴾ' => 'P', 'ᴿ' => 'R', 'ᵀ' => 'T', 'ᵁ' => 'U', 'ᵂ' => 'W', 'ᵃ' => 'a', 'ᵄ' => 'ɐ', 'ᵅ' => 'ɑ', 'ᵆ' => 'ᴂ', 'ᵇ' => 'b', 'ᵈ' => 'd', 'ᵉ' => 'e', 'ᵊ' => 'ə', 'ᵋ' => 'ɛ', 'ᵌ' => 'ɜ', 'ᵍ' => 'g', 'ᵏ' => 'k', 'ᵐ' => 'm', 'ᵑ' => 'ŋ', 'ᵒ' => 'o', 'ᵓ' => 'ɔ', 'ᵔ' => 'ᴖ', 'ᵕ' => 'ᴗ', 'ᵖ' => 'p', 'ᵗ' => 't', 'ᵘ' => 'u', 'ᵙ' => 'ᴝ', 'ᵚ' => 'ɯ', 'ᵛ' => 'v', 'ᵜ' => 'ᴥ', 'ᵝ' => 'β', 'ᵞ' => 'γ', 'ᵟ' => 'δ', 'ᵠ' => 'φ', 'ᵡ' => 'χ', 'ᵢ' => 'i', 'ᵣ' => 'r', 'ᵤ' => 'u', 'ᵥ' => 'v', 'ᵦ' => 'β', 'ᵧ' => 'γ', 'ᵨ' => 'ρ', 'ᵩ' => 'φ', 'ᵪ' => 'χ', 'ᵸ' => 'н', 'ᶛ' => 'ɒ', 'ᶜ' => 'c', 'ᶝ' => 'ɕ', 'ᶞ' => 'ð', 'ᶟ' => 'ɜ', 'ᶠ' => 'f', 'ᶡ' => 'ɟ', 'ᶢ' => 'ɡ', 'ᶣ' => 'ɥ', 'ᶤ' => 'ɨ', 'ᶥ' => 'ɩ', 'ᶦ' => 'ɪ', 'ᶧ' => 'ᵻ', 'ᶨ' => 'ʝ', 'ᶩ' => 'ɭ', 'ᶪ' => 'ᶅ', 'ᶫ' => 'ʟ', 'ᶬ' => 'ɱ', 'ᶭ' => 'ɰ', 'ᶮ' => 'ɲ', 'ᶯ' => 'ɳ', 'ᶰ' => 'ɴ', 'ᶱ' => 'ɵ', 'ᶲ' => 'ɸ', 'ᶳ' => 'ʂ', 'ᶴ' => 'ʃ', 'ᶵ' => 'ƫ', 'ᶶ' => 'ʉ', 'ᶷ' => 'ʊ', 'ᶸ' => 'ᴜ', 'ᶹ' => 'ʋ', 'ᶺ' => 'ʌ', 'ᶻ' => 'z', 'ᶼ' => 'ʐ', 'ᶽ' => 'ʑ', 'ᶾ' => 'ʒ', 'ᶿ' => 'θ', 'ẚ' => 'aʾ', 'ẛ' => 'ṡ', '᾽' => ' ̓', '᾿' => ' ̓', '῀' => ' ͂', '῁' => ' ̈͂', '῍' => ' ̓̀', '῎' => ' ̓́', '῏' => ' ̓͂', '῝' => ' ̔̀', '῞' => ' ̔́', '῟' => ' ̔͂', '῭' => ' ̈̀', '΅' => ' ̈́', '´' => ' ́', '῾' => ' ̔', ' ' => ' ', ' ' => ' ', ' ' => ' ', ' ' => ' ', ' ' => ' ', ' ' => ' ', ' ' => ' ', ' ' => ' ', ' ' => ' ', ' ' => ' ', ' ' => ' ', '‑' => '‐', '‗' => ' ̳', '․' => '.', '‥' => '..', '…' => '...', ' ' => ' ', '″' => '′′', '‴' => '′′′', '‶' => '‵‵', '‷' => '‵‵‵', '‼' => '!!', '‾' => ' ̅', '⁇' => '??', '⁈' => '?!', '⁉' => '!?', '⁗' => '′′′′', ' ' => ' ', '⁰' => '0', 'ⁱ' => 'i', '⁴' => '4', '⁵' => '5', '⁶' => '6', '⁷' => '7', '⁸' => '8', '⁹' => '9', '⁺' => '+', '⁻' => '−', '⁼' => '=', '⁽' => '(', '⁾' => ')', 'ⁿ' => 'n', '₀' => '0', '₁' => '1', '₂' => '2', '₃' => '3', '₄' => '4', '₅' => '5', '₆' => '6', '₇' => '7', '₈' => '8', '₉' => '9', '₊' => '+', '₋' => '−', '₌' => '=', '₍' => '(', '₎' => ')', 'ₐ' => 'a', 'ₑ' => 'e', 'ₒ' => 'o', 'ₓ' => 'x', 'ₔ' => 'ə', 'ₕ' => 'h', 'ₖ' => 'k', 'ₗ' => 'l', 'ₘ' => 'm', 'ₙ' => 'n', 'ₚ' => 'p', 'ₛ' => 's', 'ₜ' => 't', '₨' => 'Rs', '℀' => 'a/c', '℁' => 'a/s', 'ℂ' => 'C', '℃' => '°C', '℅' => 'c/o', '℆' => 'c/u', 'ℇ' => 'Ɛ', '℉' => '°F', 'ℊ' => 'g', 'ℋ' => 'H', 'ℌ' => 'H', 'ℍ' => 'H', 'ℎ' => 'h', 'ℏ' => 'ħ', 'ℐ' => 'I', 'ℑ' => 'I', 'ℒ' => 'L', 'ℓ' => 'l', 'ℕ' => 'N', '№' => 'No', 'ℙ' => 'P', 'ℚ' => 'Q', 'ℛ' => 'R', 'ℜ' => 'R', 'ℝ' => 'R', '℠' => 'SM', '℡' => 'TEL', '™' => 'TM', 'ℤ' => 'Z', 'ℨ' => 'Z', 'ℬ' => 'B', 'ℭ' => 'C', 'ℯ' => 'e', 'ℰ' => 'E', 'ℱ' => 'F', 'ℳ' => 'M', 'ℴ' => 'o', 'ℵ' => 'א', 'ℶ' => 'ב', 'ℷ' => 'ג', 'ℸ' => 'ד', 'ℹ' => 'i', '℻' => 'FAX', 'ℼ' => 'π', 'ℽ' => 'γ', 'ℾ' => 'Γ', 'ℿ' => 'Π', '⅀' => '∑', 'ⅅ' => 'D', 'ⅆ' => 'd', 'ⅇ' => 'e', 'ⅈ' => 'i', 'ⅉ' => 'j', '⅐' => '1⁄7', '⅑' => '1⁄9', '⅒' => '1⁄10', '⅓' => '1⁄3', '⅔' => '2⁄3', '⅕' => '1⁄5', '⅖' => '2⁄5', '⅗' => '3⁄5', '⅘' => '4⁄5', '⅙' => '1⁄6', '⅚' => '5⁄6', '⅛' => '1⁄8', '⅜' => '3⁄8', '⅝' => '5⁄8', '⅞' => '7⁄8', '⅟' => '1⁄', 'Ⅰ' => 'I', 'Ⅱ' => 'II', 'Ⅲ' => 'III', 'Ⅳ' => 'IV', 'Ⅴ' => 'V', 'Ⅵ' => 'VI', 'Ⅶ' => 'VII', 'Ⅷ' => 'VIII', 'Ⅸ' => 'IX', 'Ⅹ' => 'X', 'Ⅺ' => 'XI', 'Ⅻ' => 'XII', 'Ⅼ' => 'L', 'Ⅽ' => 'C', 'Ⅾ' => 'D', 'Ⅿ' => 'M', 'ⅰ' => 'i', 'ⅱ' => 'ii', 'ⅲ' => 'iii', 'ⅳ' => 'iv', 'ⅴ' => 'v', 'ⅵ' => 'vi', 'ⅶ' => 'vii', 'ⅷ' => 'viii', 'ⅸ' => 'ix', 'ⅹ' => 'x', 'ⅺ' => 'xi', 'ⅻ' => 'xii', 'ⅼ' => 'l', 'ⅽ' => 'c', 'ⅾ' => 'd', 'ⅿ' => 'm', '↉' => '0⁄3', '∬' => '∫∫', '∭' => '∫∫∫', '∯' => '∮∮', '∰' => '∮∮∮', '①' => '1', '②' => '2', '③' => '3', '④' => '4', '⑤' => '5', '⑥' => '6', '⑦' => '7', '⑧' => '8', '⑨' => '9', '⑩' => '10', '⑪' => '11', '⑫' => '12', '⑬' => '13', '⑭' => '14', '⑮' => '15', '⑯' => '16', '⑰' => '17', '⑱' => '18', '⑲' => '19', '⑳' => '20', '⑴' => '(1)', '⑵' => '(2)', '⑶' => '(3)', '⑷' => '(4)', '⑸' => '(5)', '⑹' => '(6)', '⑺' => '(7)', '⑻' => '(8)', '⑼' => '(9)', '⑽' => '(10)', '⑾' => '(11)', '⑿' => '(12)', '⒀' => '(13)', '⒁' => '(14)', '⒂' => '(15)', '⒃' => '(16)', '⒄' => '(17)', '⒅' => '(18)', '⒆' => '(19)', '⒇' => '(20)', '⒈' => '1.', '⒉' => '2.', '⒊' => '3.', '⒋' => '4.', '⒌' => '5.', '⒍' => '6.', '⒎' => '7.', '⒏' => '8.', '⒐' => '9.', '⒑' => '10.', '⒒' => '11.', '⒓' => '12.', '⒔' => '13.', '⒕' => '14.', '⒖' => '15.', '⒗' => '16.', '⒘' => '17.', '⒙' => '18.', '⒚' => '19.', '⒛' => '20.', '⒜' => '(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', 'ⓐ' => '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', '⓪' => '0', '⨌' => '∫∫∫∫', '⩴' => '::=', '⩵' => '==', '⩶' => '===', 'ⱼ' => 'j', 'ⱽ' => 'V', 'ⵯ' => 'ⵡ', '⺟' => '母', '⻳' => '龟', '⼀' => '一', '⼁' => '丨', '⼂' => '丶', '⼃' => '丿', '⼄' => '乙', '⼅' => '亅', '⼆' => '二', '⼇' => '亠', '⼈' => '人', '⼉' => '儿', '⼊' => '入', '⼋' => '八', '⼌' => '冂', '⼍' => '冖', '⼎' => '冫', '⼏' => '几', '⼐' => '凵', '⼑' => '刀', '⼒' => '力', '⼓' => '勹', '⼔' => '匕', '⼕' => '匚', '⼖' => '匸', '⼗' => '十', '⼘' => '卜', '⼙' => '卩', '⼚' => '厂', '⼛' => '厶', '⼜' => '又', '⼝' => '口', '⼞' => '囗', '⼟' => '土', '⼠' => '士', '⼡' => '夂', '⼢' => '夊', '⼣' => '夕', '⼤' => '大', '⼥' => '女', '⼦' => '子', '⼧' => '宀', '⼨' => '寸', '⼩' => '小', '⼪' => '尢', '⼫' => '尸', '⼬' => '屮', '⼭' => '山', '⼮' => '巛', '⼯' => '工', '⼰' => '己', '⼱' => '巾', '⼲' => '干', '⼳' => '幺', '⼴' => '广', '⼵' => '廴', '⼶' => '廾', '⼷' => '弋', '⼸' => '弓', '⼹' => '彐', '⼺' => '彡', '⼻' => '彳', '⼼' => '心', '⼽' => '戈', '⼾' => '戶', '⼿' => '手', '⽀' => '支', '⽁' => '攴', '⽂' => '文', '⽃' => '斗', '⽄' => '斤', '⽅' => '方', '⽆' => '无', '⽇' => '日', '⽈' => '曰', '⽉' => '月', '⽊' => '木', '⽋' => '欠', '⽌' => '止', '⽍' => '歹', '⽎' => '殳', '⽏' => '毋', '⽐' => '比', '⽑' => '毛', '⽒' => '氏', '⽓' => '气', '⽔' => '水', '⽕' => '火', '⽖' => '爪', '⽗' => '父', '⽘' => '爻', '⽙' => '爿', '⽚' => '片', '⽛' => '牙', '⽜' => '牛', '⽝' => '犬', '⽞' => '玄', '⽟' => '玉', '⽠' => '瓜', '⽡' => '瓦', '⽢' => '甘', '⽣' => '生', '⽤' => '用', '⽥' => '田', '⽦' => '疋', '⽧' => '疒', '⽨' => '癶', '⽩' => '白', '⽪' => '皮', '⽫' => '皿', '⽬' => '目', '⽭' => '矛', '⽮' => '矢', '⽯' => '石', '⽰' => '示', '⽱' => '禸', '⽲' => '禾', '⽳' => '穴', '⽴' => '立', '⽵' => '竹', '⽶' => '米', '⽷' => '糸', '⽸' => '缶', '⽹' => '网', '⽺' => '羊', '⽻' => '羽', '⽼' => '老', '⽽' => '而', '⽾' => '耒', '⽿' => '耳', '⾀' => '聿', '⾁' => '肉', '⾂' => '臣', '⾃' => '自', '⾄' => '至', '⾅' => '臼', '⾆' => '舌', '⾇' => '舛', '⾈' => '舟', '⾉' => '艮', '⾊' => '色', '⾋' => '艸', '⾌' => '虍', '⾍' => '虫', '⾎' => '血', '⾏' => '行', '⾐' => '衣', '⾑' => '襾', '⾒' => '見', '⾓' => '角', '⾔' => '言', '⾕' => '谷', '⾖' => '豆', '⾗' => '豕', '⾘' => '豸', '⾙' => '貝', '⾚' => '赤', '⾛' => '走', '⾜' => '足', '⾝' => '身', '⾞' => '車', '⾟' => '辛', '⾠' => '辰', '⾡' => '辵', '⾢' => '邑', '⾣' => '酉', '⾤' => '釆', '⾥' => '里', '⾦' => '金', '⾧' => '長', '⾨' => '門', '⾩' => '阜', '⾪' => '隶', '⾫' => '隹', '⾬' => '雨', '⾭' => '靑', '⾮' => '非', '⾯' => '面', '⾰' => '革', '⾱' => '韋', '⾲' => '韭', '⾳' => '音', '⾴' => '頁', '⾵' => '風', '⾶' => '飛', '⾷' => '食', '⾸' => '首', '⾹' => '香', '⾺' => '馬', '⾻' => '骨', '⾼' => '高', '⾽' => '髟', '⾾' => '鬥', '⾿' => '鬯', '⿀' => '鬲', '⿁' => '鬼', '⿂' => '魚', '⿃' => '鳥', '⿄' => '鹵', '⿅' => '鹿', '⿆' => '麥', '⿇' => '麻', '⿈' => '黃', '⿉' => '黍', '⿊' => '黑', '⿋' => '黹', '⿌' => '黽', '⿍' => '鼎', '⿎' => '鼓', '⿏' => '鼠', '⿐' => '鼻', '⿑' => '齊', '⿒' => '齒', '⿓' => '龍', '⿔' => '龜', '⿕' => '龠', ' ' => ' ', '〶' => '〒', '〸' => '十', '〹' => '卄', '〺' => '卅', '゛' => ' ゙', '゜' => ' ゚', 'ゟ' => 'より', 'ヿ' => 'コト', 'ㄱ' => 'ᄀ', 'ㄲ' => 'ᄁ', 'ㄳ' => 'ᆪ', 'ㄴ' => 'ᄂ', 'ㄵ' => 'ᆬ', 'ㄶ' => 'ᆭ', 'ㄷ' => 'ᄃ', 'ㄸ' => 'ᄄ', 'ㄹ' => 'ᄅ', 'ㄺ' => 'ᆰ', 'ㄻ' => 'ᆱ', 'ㄼ' => 'ᆲ', 'ㄽ' => 'ᆳ', 'ㄾ' => 'ᆴ', 'ㄿ' => 'ᆵ', 'ㅀ' => 'ᄚ', 'ㅁ' => 'ᄆ', 'ㅂ' => 'ᄇ', 'ㅃ' => 'ᄈ', 'ㅄ' => 'ᄡ', 'ㅅ' => 'ᄉ', 'ㅆ' => 'ᄊ', 'ㅇ' => 'ᄋ', 'ㅈ' => 'ᄌ', 'ㅉ' => 'ᄍ', 'ㅊ' => 'ᄎ', 'ㅋ' => 'ᄏ', 'ㅌ' => 'ᄐ', 'ㅍ' => 'ᄑ', 'ㅎ' => 'ᄒ', 'ㅏ' => 'ᅡ', 'ㅐ' => 'ᅢ', 'ㅑ' => 'ᅣ', 'ㅒ' => 'ᅤ', 'ㅓ' => 'ᅥ', 'ㅔ' => 'ᅦ', 'ㅕ' => 'ᅧ', 'ㅖ' => 'ᅨ', 'ㅗ' => 'ᅩ', 'ㅘ' => 'ᅪ', 'ㅙ' => 'ᅫ', 'ㅚ' => 'ᅬ', 'ㅛ' => 'ᅭ', 'ㅜ' => 'ᅮ', 'ㅝ' => 'ᅯ', 'ㅞ' => 'ᅰ', 'ㅟ' => 'ᅱ', 'ㅠ' => 'ᅲ', 'ㅡ' => 'ᅳ', 'ㅢ' => 'ᅴ', 'ㅣ' => 'ᅵ', 'ㅤ' => 'ᅠ', 'ㅥ' => 'ᄔ', 'ㅦ' => 'ᄕ', 'ㅧ' => 'ᇇ', 'ㅨ' => 'ᇈ', 'ㅩ' => 'ᇌ', 'ㅪ' => 'ᇎ', 'ㅫ' => 'ᇓ', 'ㅬ' => 'ᇗ', 'ㅭ' => 'ᇙ', 'ㅮ' => 'ᄜ', 'ㅯ' => 'ᇝ', 'ㅰ' => 'ᇟ', 'ㅱ' => 'ᄝ', 'ㅲ' => 'ᄞ', 'ㅳ' => 'ᄠ', 'ㅴ' => 'ᄢ', 'ㅵ' => 'ᄣ', 'ㅶ' => 'ᄧ', 'ㅷ' => 'ᄩ', 'ㅸ' => 'ᄫ', 'ㅹ' => 'ᄬ', 'ㅺ' => 'ᄭ', 'ㅻ' => 'ᄮ', 'ㅼ' => 'ᄯ', 'ㅽ' => 'ᄲ', 'ㅾ' => 'ᄶ', 'ㅿ' => 'ᅀ', 'ㆀ' => 'ᅇ', 'ㆁ' => 'ᅌ', 'ㆂ' => 'ᇱ', 'ㆃ' => 'ᇲ', 'ㆄ' => 'ᅗ', 'ㆅ' => 'ᅘ', 'ㆆ' => 'ᅙ', 'ㆇ' => 'ᆄ', 'ㆈ' => 'ᆅ', 'ㆉ' => 'ᆈ', 'ㆊ' => 'ᆑ', 'ㆋ' => 'ᆒ', 'ㆌ' => 'ᆔ', 'ㆍ' => 'ᆞ', 'ㆎ' => 'ᆡ', '㆒' => '一', '㆓' => '二', '㆔' => '三', '㆕' => '四', '㆖' => '上', '㆗' => '中', '㆘' => '下', '㆙' => '甲', '㆚' => '乙', '㆛' => '丙', '㆜' => '丁', '㆝' => '天', '㆞' => '地', '㆟' => '人', '㈀' => '(ᄀ)', '㈁' => '(ᄂ)', '㈂' => '(ᄃ)', '㈃' => '(ᄅ)', '㈄' => '(ᄆ)', '㈅' => '(ᄇ)', '㈆' => '(ᄉ)', '㈇' => '(ᄋ)', '㈈' => '(ᄌ)', '㈉' => '(ᄎ)', '㈊' => '(ᄏ)', '㈋' => '(ᄐ)', '㈌' => '(ᄑ)', '㈍' => '(ᄒ)', '㈎' => '(가)', '㈏' => '(나)', '㈐' => '(다)', '㈑' => '(라)', '㈒' => '(마)', '㈓' => '(바)', '㈔' => '(사)', '㈕' => '(아)', '㈖' => '(자)', '㈗' => '(차)', '㈘' => '(카)', '㈙' => '(타)', '㈚' => '(파)', '㈛' => '(하)', '㈜' => '(주)', '㈝' => '(오전)', '㈞' => '(오후)', '㈠' => '(一)', '㈡' => '(二)', '㈢' => '(三)', '㈣' => '(四)', '㈤' => '(五)', '㈥' => '(六)', '㈦' => '(七)', '㈧' => '(八)', '㈨' => '(九)', '㈩' => '(十)', '㈪' => '(月)', '㈫' => '(火)', '㈬' => '(水)', '㈭' => '(木)', '㈮' => '(金)', '㈯' => '(土)', '㈰' => '(日)', '㈱' => '(株)', '㈲' => '(有)', '㈳' => '(社)', '㈴' => '(名)', '㈵' => '(特)', '㈶' => '(財)', '㈷' => '(祝)', '㈸' => '(労)', '㈹' => '(代)', '㈺' => '(呼)', '㈻' => '(学)', '㈼' => '(監)', '㈽' => '(企)', '㈾' => '(資)', '㈿' => '(協)', '㉀' => '(祭)', '㉁' => '(休)', '㉂' => '(自)', '㉃' => '(至)', '㉄' => '問', '㉅' => '幼', '㉆' => '文', '㉇' => '箏', '㉐' => 'PTE', '㉑' => '21', '㉒' => '22', '㉓' => '23', '㉔' => '24', '㉕' => '25', '㉖' => '26', '㉗' => '27', '㉘' => '28', '㉙' => '29', '㉚' => '30', '㉛' => '31', '㉜' => '32', '㉝' => '33', '㉞' => '34', '㉟' => '35', '㉠' => 'ᄀ', '㉡' => 'ᄂ', '㉢' => 'ᄃ', '㉣' => 'ᄅ', '㉤' => 'ᄆ', '㉥' => 'ᄇ', '㉦' => 'ᄉ', '㉧' => 'ᄋ', '㉨' => 'ᄌ', '㉩' => 'ᄎ', '㉪' => 'ᄏ', '㉫' => 'ᄐ', '㉬' => 'ᄑ', '㉭' => 'ᄒ', '㉮' => '가', '㉯' => '나', '㉰' => '다', '㉱' => '라', '㉲' => '마', '㉳' => '바', '㉴' => '사', '㉵' => '아', '㉶' => '자', '㉷' => '차', '㉸' => '카', '㉹' => '타', '㉺' => '파', '㉻' => '하', '㉼' => '참고', '㉽' => '주의', '㉾' => '우', '㊀' => '一', '㊁' => '二', '㊂' => '三', '㊃' => '四', '㊄' => '五', '㊅' => '六', '㊆' => '七', '㊇' => '八', '㊈' => '九', '㊉' => '十', '㊊' => '月', '㊋' => '火', '㊌' => '水', '㊍' => '木', '㊎' => '金', '㊏' => '土', '㊐' => '日', '㊑' => '株', '㊒' => '有', '㊓' => '社', '㊔' => '名', '㊕' => '特', '㊖' => '財', '㊗' => '祝', '㊘' => '労', '㊙' => '秘', '㊚' => '男', '㊛' => '女', '㊜' => '適', '㊝' => '優', '㊞' => '印', '㊟' => '注', '㊠' => '項', '㊡' => '休', '㊢' => '写', '㊣' => '正', '㊤' => '上', '㊥' => '中', '㊦' => '下', '㊧' => '左', '㊨' => '右', '㊩' => '医', '㊪' => '宗', '㊫' => '学', '㊬' => '監', '㊭' => '企', '㊮' => '資', '㊯' => '協', '㊰' => '夜', '㊱' => '36', '㊲' => '37', '㊳' => '38', '㊴' => '39', '㊵' => '40', '㊶' => '41', '㊷' => '42', '㊸' => '43', '㊹' => '44', '㊺' => '45', '㊻' => '46', '㊼' => '47', '㊽' => '48', '㊾' => '49', '㊿' => '50', '㋀' => '1月', '㋁' => '2月', '㋂' => '3月', '㋃' => '4月', '㋄' => '5月', '㋅' => '6月', '㋆' => '7月', '㋇' => '8月', '㋈' => '9月', '㋉' => '10月', '㋊' => '11月', '㋋' => '12月', '㋌' => 'Hg', '㋍' => 'erg', '㋎' => 'eV', '㋏' => 'LTD', '㋐' => 'ア', '㋑' => 'イ', '㋒' => 'ウ', '㋓' => 'エ', '㋔' => 'オ', '㋕' => 'カ', '㋖' => 'キ', '㋗' => 'ク', '㋘' => 'ケ', '㋙' => 'コ', '㋚' => 'サ', '㋛' => 'シ', '㋜' => 'ス', '㋝' => 'セ', '㋞' => 'ソ', '㋟' => 'タ', '㋠' => 'チ', '㋡' => 'ツ', '㋢' => 'テ', '㋣' => 'ト', '㋤' => 'ナ', '㋥' => 'ニ', '㋦' => 'ヌ', '㋧' => 'ネ', '㋨' => 'ノ', '㋩' => 'ハ', '㋪' => 'ヒ', '㋫' => 'フ', '㋬' => 'ヘ', '㋭' => 'ホ', '㋮' => 'マ', '㋯' => 'ミ', '㋰' => 'ム', '㋱' => 'メ', '㋲' => 'モ', '㋳' => 'ヤ', '㋴' => 'ユ', '㋵' => 'ヨ', '㋶' => 'ラ', '㋷' => 'リ', '㋸' => 'ル', '㋹' => 'レ', '㋺' => 'ロ', '㋻' => 'ワ', '㋼' => 'ヰ', '㋽' => 'ヱ', '㋾' => 'ヲ', '㋿' => '令和', '㌀' => 'アパート', '㌁' => 'アルファ', '㌂' => 'アンペア', '㌃' => 'アール', '㌄' => 'イニング', '㌅' => 'インチ', '㌆' => 'ウォン', '㌇' => 'エスクード', '㌈' => 'エーカー', '㌉' => 'オンス', '㌊' => 'オーム', '㌋' => 'カイリ', '㌌' => 'カラット', '㌍' => 'カロリー', '㌎' => 'ガロン', '㌏' => 'ガンマ', '㌐' => 'ギガ', '㌑' => 'ギニー', '㌒' => 'キュリー', '㌓' => 'ギルダー', '㌔' => 'キロ', '㌕' => 'キログラム', '㌖' => 'キロメートル', '㌗' => 'キロワット', '㌘' => 'グラム', '㌙' => 'グラムトン', '㌚' => 'クルゼイロ', '㌛' => 'クローネ', '㌜' => 'ケース', '㌝' => 'コルナ', '㌞' => 'コーポ', '㌟' => 'サイクル', '㌠' => 'サンチーム', '㌡' => 'シリング', '㌢' => 'センチ', '㌣' => 'セント', '㌤' => 'ダース', '㌥' => 'デシ', '㌦' => 'ドル', '㌧' => 'トン', '㌨' => 'ナノ', '㌩' => 'ノット', '㌪' => 'ハイツ', '㌫' => 'パーセント', '㌬' => 'パーツ', '㌭' => 'バーレル', '㌮' => 'ピアストル', '㌯' => 'ピクル', '㌰' => 'ピコ', '㌱' => 'ビル', '㌲' => 'ファラッド', '㌳' => 'フィート', '㌴' => 'ブッシェル', '㌵' => 'フラン', '㌶' => 'ヘクタール', '㌷' => 'ペソ', '㌸' => 'ペニヒ', '㌹' => 'ヘルツ', '㌺' => 'ペンス', '㌻' => 'ページ', '㌼' => 'ベータ', '㌽' => 'ポイント', '㌾' => 'ボルト', '㌿' => 'ホン', '㍀' => 'ポンド', '㍁' => 'ホール', '㍂' => 'ホーン', '㍃' => 'マイクロ', '㍄' => 'マイル', '㍅' => 'マッハ', '㍆' => 'マルク', '㍇' => 'マンション', '㍈' => 'ミクロン', '㍉' => 'ミリ', '㍊' => 'ミリバール', '㍋' => 'メガ', '㍌' => 'メガトン', '㍍' => 'メートル', '㍎' => 'ヤード', '㍏' => 'ヤール', '㍐' => 'ユアン', '㍑' => 'リットル', '㍒' => 'リラ', '㍓' => 'ルピー', '㍔' => 'ルーブル', '㍕' => 'レム', '㍖' => 'レントゲン', '㍗' => 'ワット', '㍘' => '0点', '㍙' => '1点', '㍚' => '2点', '㍛' => '3点', '㍜' => '4点', '㍝' => '5点', '㍞' => '6点', '㍟' => '7点', '㍠' => '8点', '㍡' => '9点', '㍢' => '10点', '㍣' => '11点', '㍤' => '12点', '㍥' => '13点', '㍦' => '14点', '㍧' => '15点', '㍨' => '16点', '㍩' => '17点', '㍪' => '18点', '㍫' => '19点', '㍬' => '20点', '㍭' => '21点', '㍮' => '22点', '㍯' => '23点', '㍰' => '24点', '㍱' => 'hPa', '㍲' => 'da', '㍳' => 'AU', '㍴' => 'bar', '㍵' => 'oV', '㍶' => 'pc', '㍷' => 'dm', '㍸' => 'dm2', '㍹' => 'dm3', '㍺' => 'IU', '㍻' => '平成', '㍼' => '昭和', '㍽' => '大正', '㍾' => '明治', '㍿' => '株式会社', '㎀' => 'pA', '㎁' => 'nA', '㎂' => 'μA', '㎃' => 'mA', '㎄' => 'kA', '㎅' => 'KB', '㎆' => 'MB', '㎇' => 'GB', '㎈' => 'cal', '㎉' => 'kcal', '㎊' => 'pF', '㎋' => 'nF', '㎌' => 'μF', '㎍' => 'μg', '㎎' => 'mg', '㎏' => 'kg', '㎐' => 'Hz', '㎑' => 'kHz', '㎒' => 'MHz', '㎓' => 'GHz', '㎔' => 'THz', '㎕' => 'μl', '㎖' => 'ml', '㎗' => 'dl', '㎘' => 'kl', '㎙' => 'fm', '㎚' => 'nm', '㎛' => 'μm', '㎜' => 'mm', '㎝' => 'cm', '㎞' => 'km', '㎟' => 'mm2', '㎠' => 'cm2', '㎡' => 'm2', '㎢' => 'km2', '㎣' => 'mm3', '㎤' => 'cm3', '㎥' => 'm3', '㎦' => 'km3', '㎧' => 'm∕s', '㎨' => 'm∕s2', '㎩' => 'Pa', '㎪' => 'kPa', '㎫' => 'MPa', '㎬' => 'GPa', '㎭' => 'rad', '㎮' => 'rad∕s', '㎯' => 'rad∕s2', '㎰' => 'ps', '㎱' => 'ns', '㎲' => 'μs', '㎳' => 'ms', '㎴' => 'pV', '㎵' => 'nV', '㎶' => 'μV', '㎷' => 'mV', '㎸' => 'kV', '㎹' => 'MV', '㎺' => 'pW', '㎻' => 'nW', '㎼' => 'μW', '㎽' => 'mW', '㎾' => 'kW', '㎿' => 'MW', '㏀' => 'kΩ', '㏁' => 'MΩ', '㏂' => 'a.m.', '㏃' => 'Bq', '㏄' => 'cc', '㏅' => 'cd', '㏆' => 'C∕kg', '㏇' => 'Co.', '㏈' => 'dB', '㏉' => 'Gy', '㏊' => 'ha', '㏋' => 'HP', '㏌' => 'in', '㏍' => 'KK', '㏎' => 'KM', '㏏' => 'kt', '㏐' => 'lm', '㏑' => 'ln', '㏒' => 'log', '㏓' => 'lx', '㏔' => 'mb', '㏕' => 'mil', '㏖' => 'mol', '㏗' => 'PH', '㏘' => 'p.m.', '㏙' => 'PPM', '㏚' => 'PR', '㏛' => 'sr', '㏜' => 'Sv', '㏝' => 'Wb', '㏞' => 'V∕m', '㏟' => 'A∕m', '㏠' => '1日', '㏡' => '2日', '㏢' => '3日', '㏣' => '4日', '㏤' => '5日', '㏥' => '6日', '㏦' => '7日', '㏧' => '8日', '㏨' => '9日', '㏩' => '10日', '㏪' => '11日', '㏫' => '12日', '㏬' => '13日', '㏭' => '14日', '㏮' => '15日', '㏯' => '16日', '㏰' => '17日', '㏱' => '18日', '㏲' => '19日', '㏳' => '20日', '㏴' => '21日', '㏵' => '22日', '㏶' => '23日', '㏷' => '24日', '㏸' => '25日', '㏹' => '26日', '㏺' => '27日', '㏻' => '28日', '㏼' => '29日', '㏽' => '30日', '㏾' => '31日', '㏿' => 'gal', 'ꚜ' => 'ъ', 'ꚝ' => 'ь', 'ꝰ' => 'ꝯ', 'ꟸ' => 'Ħ', 'ꟹ' => 'œ', 'ꭜ' => 'ꜧ', 'ꭝ' => 'ꬷ', 'ꭞ' => 'ɫ', 'ꭟ' => 'ꭒ', 'ꭩ' => 'ʍ', 'ff' => 'ff', 'fi' => 'fi', 'fl' => 'fl', 'ffi' => 'ffi', 'ffl' => 'ffl', 'ſt' => 'st', 'st' => 'st', 'ﬓ' => 'մն', 'ﬔ' => 'մե', 'ﬕ' => 'մի', 'ﬖ' => 'վն', 'ﬗ' => 'մխ', 'ﬠ' => 'ע', 'ﬡ' => 'א', 'ﬢ' => 'ד', 'ﬣ' => 'ה', 'ﬤ' => 'כ', 'ﬥ' => 'ל', 'ﬦ' => 'ם', 'ﬧ' => 'ר', 'ﬨ' => 'ת', '﬩' => '+', 'ﭏ' => 'אל', 'ﭐ' => 'ٱ', 'ﭑ' => 'ٱ', 'ﭒ' => 'ٻ', 'ﭓ' => 'ٻ', 'ﭔ' => 'ٻ', 'ﭕ' => 'ٻ', 'ﭖ' => 'پ', 'ﭗ' => 'پ', 'ﭘ' => 'پ', 'ﭙ' => 'پ', 'ﭚ' => 'ڀ', 'ﭛ' => 'ڀ', 'ﭜ' => 'ڀ', 'ﭝ' => 'ڀ', 'ﭞ' => 'ٺ', 'ﭟ' => 'ٺ', 'ﭠ' => 'ٺ', 'ﭡ' => 'ٺ', 'ﭢ' => 'ٿ', 'ﭣ' => 'ٿ', 'ﭤ' => 'ٿ', 'ﭥ' => 'ٿ', 'ﭦ' => 'ٹ', 'ﭧ' => 'ٹ', 'ﭨ' => 'ٹ', 'ﭩ' => 'ٹ', 'ﭪ' => 'ڤ', 'ﭫ' => 'ڤ', 'ﭬ' => 'ڤ', 'ﭭ' => 'ڤ', 'ﭮ' => 'ڦ', 'ﭯ' => 'ڦ', 'ﭰ' => 'ڦ', 'ﭱ' => 'ڦ', 'ﭲ' => 'ڄ', 'ﭳ' => 'ڄ', 'ﭴ' => 'ڄ', 'ﭵ' => 'ڄ', 'ﭶ' => 'ڃ', 'ﭷ' => 'ڃ', 'ﭸ' => 'ڃ', 'ﭹ' => 'ڃ', 'ﭺ' => 'چ', 'ﭻ' => 'چ', 'ﭼ' => 'چ', 'ﭽ' => 'چ', 'ﭾ' => 'ڇ', 'ﭿ' => 'ڇ', 'ﮀ' => 'ڇ', 'ﮁ' => 'ڇ', 'ﮂ' => 'ڍ', 'ﮃ' => 'ڍ', 'ﮄ' => 'ڌ', 'ﮅ' => 'ڌ', 'ﮆ' => 'ڎ', 'ﮇ' => 'ڎ', 'ﮈ' => 'ڈ', 'ﮉ' => 'ڈ', 'ﮊ' => 'ژ', 'ﮋ' => 'ژ', 'ﮌ' => 'ڑ', 'ﮍ' => 'ڑ', 'ﮎ' => 'ک', 'ﮏ' => 'ک', 'ﮐ' => 'ک', 'ﮑ' => 'ک', 'ﮒ' => 'گ', 'ﮓ' => 'گ', 'ﮔ' => 'گ', 'ﮕ' => 'گ', 'ﮖ' => 'ڳ', 'ﮗ' => 'ڳ', 'ﮘ' => 'ڳ', 'ﮙ' => 'ڳ', 'ﮚ' => 'ڱ', 'ﮛ' => 'ڱ', 'ﮜ' => 'ڱ', 'ﮝ' => 'ڱ', 'ﮞ' => 'ں', 'ﮟ' => 'ں', 'ﮠ' => 'ڻ', 'ﮡ' => 'ڻ', 'ﮢ' => 'ڻ', 'ﮣ' => 'ڻ', 'ﮤ' => 'ۀ', 'ﮥ' => 'ۀ', 'ﮦ' => 'ہ', 'ﮧ' => 'ہ', 'ﮨ' => 'ہ', 'ﮩ' => 'ہ', 'ﮪ' => 'ھ', 'ﮫ' => 'ھ', 'ﮬ' => 'ھ', 'ﮭ' => 'ھ', 'ﮮ' => 'ے', 'ﮯ' => 'ے', 'ﮰ' => 'ۓ', 'ﮱ' => 'ۓ', 'ﯓ' => 'ڭ', 'ﯔ' => 'ڭ', 'ﯕ' => 'ڭ', 'ﯖ' => 'ڭ', 'ﯗ' => 'ۇ', 'ﯘ' => 'ۇ', 'ﯙ' => 'ۆ', 'ﯚ' => 'ۆ', 'ﯛ' => 'ۈ', 'ﯜ' => 'ۈ', 'ﯝ' => 'ۇٴ', 'ﯞ' => 'ۋ', 'ﯟ' => 'ۋ', 'ﯠ' => 'ۅ', 'ﯡ' => 'ۅ', 'ﯢ' => 'ۉ', 'ﯣ' => 'ۉ', 'ﯤ' => 'ې', 'ﯥ' => 'ې', 'ﯦ' => 'ې', 'ﯧ' => 'ې', 'ﯨ' => 'ى', 'ﯩ' => 'ى', 'ﯪ' => 'ئا', 'ﯫ' => 'ئا', 'ﯬ' => 'ئە', 'ﯭ' => 'ئە', 'ﯮ' => 'ئو', 'ﯯ' => 'ئو', 'ﯰ' => 'ئۇ', 'ﯱ' => 'ئۇ', 'ﯲ' => 'ئۆ', 'ﯳ' => 'ئۆ', 'ﯴ' => 'ئۈ', 'ﯵ' => 'ئۈ', 'ﯶ' => 'ئې', 'ﯷ' => 'ئې', 'ﯸ' => 'ئې', 'ﯹ' => 'ئى', 'ﯺ' => 'ئى', 'ﯻ' => 'ئى', 'ﯼ' => 'ی', 'ﯽ' => 'ی', 'ﯾ' => 'ی', 'ﯿ' => 'ی', 'ﰀ' => 'ئج', 'ﰁ' => 'ئح', 'ﰂ' => 'ئم', 'ﰃ' => 'ئى', 'ﰄ' => 'ئي', 'ﰅ' => 'بج', 'ﰆ' => 'بح', 'ﰇ' => 'بخ', 'ﰈ' => 'بم', 'ﰉ' => 'بى', 'ﰊ' => 'بي', 'ﰋ' => 'تج', 'ﰌ' => 'تح', 'ﰍ' => 'تخ', 'ﰎ' => 'تم', 'ﰏ' => 'تى', 'ﰐ' => 'تي', 'ﰑ' => 'ثج', 'ﰒ' => 'ثم', 'ﰓ' => 'ثى', 'ﰔ' => 'ثي', 'ﰕ' => 'جح', 'ﰖ' => 'جم', 'ﰗ' => 'حج', 'ﰘ' => 'حم', 'ﰙ' => 'خج', 'ﰚ' => 'خح', 'ﰛ' => 'خم', 'ﰜ' => 'سج', 'ﰝ' => 'سح', 'ﰞ' => 'سخ', 'ﰟ' => 'سم', 'ﰠ' => 'صح', 'ﰡ' => 'صم', 'ﰢ' => 'ضج', 'ﰣ' => 'ضح', 'ﰤ' => 'ضخ', 'ﰥ' => 'ضم', 'ﰦ' => 'طح', 'ﰧ' => 'طم', 'ﰨ' => 'ظم', 'ﰩ' => 'عج', 'ﰪ' => 'عم', 'ﰫ' => 'غج', 'ﰬ' => 'غم', 'ﰭ' => 'فج', 'ﰮ' => 'فح', 'ﰯ' => 'فخ', 'ﰰ' => 'فم', 'ﰱ' => 'فى', 'ﰲ' => 'في', 'ﰳ' => 'قح', 'ﰴ' => 'قم', 'ﰵ' => 'قى', 'ﰶ' => 'قي', 'ﰷ' => 'كا', 'ﰸ' => 'كج', 'ﰹ' => 'كح', 'ﰺ' => 'كخ', 'ﰻ' => 'كل', 'ﰼ' => 'كم', 'ﰽ' => 'كى', 'ﰾ' => 'كي', 'ﰿ' => 'لج', 'ﱀ' => 'لح', 'ﱁ' => 'لخ', 'ﱂ' => 'لم', 'ﱃ' => 'لى', 'ﱄ' => 'لي', 'ﱅ' => 'مج', 'ﱆ' => 'مح', 'ﱇ' => 'مخ', 'ﱈ' => 'مم', 'ﱉ' => 'مى', 'ﱊ' => 'مي', 'ﱋ' => 'نج', 'ﱌ' => 'نح', 'ﱍ' => 'نخ', 'ﱎ' => 'نم', 'ﱏ' => 'نى', 'ﱐ' => 'ني', 'ﱑ' => 'هج', 'ﱒ' => 'هم', 'ﱓ' => 'هى', 'ﱔ' => 'هي', 'ﱕ' => 'يج', 'ﱖ' => 'يح', 'ﱗ' => 'يخ', 'ﱘ' => 'يم', 'ﱙ' => 'يى', 'ﱚ' => 'يي', 'ﱛ' => 'ذٰ', 'ﱜ' => 'رٰ', 'ﱝ' => 'ىٰ', 'ﱞ' => ' ٌّ', 'ﱟ' => ' ٍّ', 'ﱠ' => ' َّ', 'ﱡ' => ' ُّ', 'ﱢ' => ' ِّ', 'ﱣ' => ' ّٰ', 'ﱤ' => 'ئر', 'ﱥ' => 'ئز', 'ﱦ' => 'ئم', 'ﱧ' => 'ئن', 'ﱨ' => 'ئى', 'ﱩ' => 'ئي', 'ﱪ' => 'بر', 'ﱫ' => 'بز', 'ﱬ' => 'بم', 'ﱭ' => 'بن', 'ﱮ' => 'بى', 'ﱯ' => 'بي', 'ﱰ' => 'تر', 'ﱱ' => 'تز', 'ﱲ' => 'تم', 'ﱳ' => 'تن', 'ﱴ' => 'تى', 'ﱵ' => 'تي', 'ﱶ' => 'ثر', 'ﱷ' => 'ثز', 'ﱸ' => 'ثم', 'ﱹ' => 'ثن', 'ﱺ' => 'ثى', 'ﱻ' => 'ثي', 'ﱼ' => 'فى', 'ﱽ' => 'في', 'ﱾ' => 'قى', 'ﱿ' => 'قي', 'ﲀ' => 'كا', 'ﲁ' => 'كل', 'ﲂ' => 'كم', 'ﲃ' => 'كى', 'ﲄ' => 'كي', 'ﲅ' => 'لم', 'ﲆ' => 'لى', 'ﲇ' => 'لي', 'ﲈ' => 'ما', 'ﲉ' => 'مم', 'ﲊ' => 'نر', 'ﲋ' => 'نز', 'ﲌ' => 'نم', 'ﲍ' => 'نن', 'ﲎ' => 'نى', 'ﲏ' => 'ني', 'ﲐ' => 'ىٰ', 'ﲑ' => 'ير', 'ﲒ' => 'يز', 'ﲓ' => 'يم', 'ﲔ' => 'ين', 'ﲕ' => 'يى', 'ﲖ' => 'يي', 'ﲗ' => 'ئج', 'ﲘ' => 'ئح', 'ﲙ' => 'ئخ', 'ﲚ' => 'ئم', 'ﲛ' => 'ئه', 'ﲜ' => 'بج', 'ﲝ' => 'بح', 'ﲞ' => 'بخ', 'ﲟ' => 'بم', 'ﲠ' => 'به', 'ﲡ' => 'تج', 'ﲢ' => 'تح', 'ﲣ' => 'تخ', 'ﲤ' => 'تم', 'ﲥ' => 'ته', 'ﲦ' => 'ثم', 'ﲧ' => 'جح', 'ﲨ' => 'جم', 'ﲩ' => 'حج', 'ﲪ' => 'حم', 'ﲫ' => 'خج', 'ﲬ' => 'خم', 'ﲭ' => 'سج', 'ﲮ' => 'سح', 'ﲯ' => 'سخ', 'ﲰ' => 'سم', 'ﲱ' => 'صح', 'ﲲ' => 'صخ', 'ﲳ' => 'صم', 'ﲴ' => 'ضج', 'ﲵ' => 'ضح', 'ﲶ' => 'ضخ', 'ﲷ' => 'ضم', 'ﲸ' => 'طح', 'ﲹ' => 'ظم', 'ﲺ' => 'عج', 'ﲻ' => 'عم', 'ﲼ' => 'غج', 'ﲽ' => 'غم', 'ﲾ' => 'فج', 'ﲿ' => 'فح', 'ﳀ' => 'فخ', 'ﳁ' => 'فم', 'ﳂ' => 'قح', 'ﳃ' => 'قم', 'ﳄ' => 'كج', 'ﳅ' => 'كح', 'ﳆ' => 'كخ', 'ﳇ' => 'كل', 'ﳈ' => 'كم', 'ﳉ' => 'لج', 'ﳊ' => 'لح', 'ﳋ' => 'لخ', 'ﳌ' => 'لم', 'ﳍ' => 'له', 'ﳎ' => 'مج', 'ﳏ' => 'مح', 'ﳐ' => 'مخ', 'ﳑ' => 'مم', 'ﳒ' => 'نج', 'ﳓ' => 'نح', 'ﳔ' => 'نخ', 'ﳕ' => 'نم', 'ﳖ' => 'نه', 'ﳗ' => 'هج', 'ﳘ' => 'هم', 'ﳙ' => 'هٰ', 'ﳚ' => 'يج', 'ﳛ' => 'يح', 'ﳜ' => 'يخ', 'ﳝ' => 'يم', 'ﳞ' => 'يه', 'ﳟ' => 'ئم', 'ﳠ' => 'ئه', 'ﳡ' => 'بم', 'ﳢ' => 'به', 'ﳣ' => 'تم', 'ﳤ' => 'ته', 'ﳥ' => 'ثم', 'ﳦ' => 'ثه', 'ﳧ' => 'سم', 'ﳨ' => 'سه', 'ﳩ' => 'شم', 'ﳪ' => 'شه', 'ﳫ' => 'كل', 'ﳬ' => 'كم', 'ﳭ' => 'لم', 'ﳮ' => 'نم', 'ﳯ' => 'نه', 'ﳰ' => 'يم', 'ﳱ' => 'يه', 'ﳲ' => 'ـَّ', 'ﳳ' => 'ـُّ', 'ﳴ' => 'ـِّ', 'ﳵ' => 'طى', 'ﳶ' => 'طي', 'ﳷ' => 'عى', 'ﳸ' => 'عي', 'ﳹ' => 'غى', 'ﳺ' => 'غي', 'ﳻ' => 'سى', 'ﳼ' => 'سي', 'ﳽ' => 'شى', 'ﳾ' => 'شي', 'ﳿ' => 'حى', 'ﴀ' => 'حي', 'ﴁ' => 'جى', 'ﴂ' => 'جي', 'ﴃ' => 'خى', 'ﴄ' => 'خي', 'ﴅ' => 'صى', 'ﴆ' => 'صي', 'ﴇ' => 'ضى', 'ﴈ' => 'ضي', 'ﴉ' => 'شج', 'ﴊ' => 'شح', 'ﴋ' => 'شخ', 'ﴌ' => 'شم', 'ﴍ' => 'شر', 'ﴎ' => 'سر', 'ﴏ' => 'صر', 'ﴐ' => 'ضر', 'ﴑ' => 'طى', 'ﴒ' => 'طي', 'ﴓ' => 'عى', 'ﴔ' => 'عي', 'ﴕ' => 'غى', 'ﴖ' => 'غي', 'ﴗ' => 'سى', 'ﴘ' => 'سي', 'ﴙ' => 'شى', 'ﴚ' => 'شي', 'ﴛ' => 'حى', 'ﴜ' => 'حي', 'ﴝ' => 'جى', 'ﴞ' => 'جي', 'ﴟ' => 'خى', 'ﴠ' => 'خي', 'ﴡ' => 'صى', 'ﴢ' => 'صي', 'ﴣ' => 'ضى', 'ﴤ' => 'ضي', 'ﴥ' => 'شج', 'ﴦ' => 'شح', 'ﴧ' => 'شخ', 'ﴨ' => 'شم', 'ﴩ' => 'شر', 'ﴪ' => 'سر', 'ﴫ' => 'صر', 'ﴬ' => 'ضر', 'ﴭ' => 'شج', 'ﴮ' => 'شح', 'ﴯ' => 'شخ', 'ﴰ' => 'شم', 'ﴱ' => 'سه', 'ﴲ' => 'شه', 'ﴳ' => 'طم', 'ﴴ' => 'سج', 'ﴵ' => 'سح', 'ﴶ' => 'سخ', 'ﴷ' => 'شج', 'ﴸ' => 'شح', 'ﴹ' => 'شخ', 'ﴺ' => 'طم', 'ﴻ' => 'ظم', 'ﴼ' => 'اً', 'ﴽ' => 'اً', 'ﵐ' => 'تجم', 'ﵑ' => 'تحج', 'ﵒ' => 'تحج', 'ﵓ' => 'تحم', 'ﵔ' => 'تخم', 'ﵕ' => 'تمج', 'ﵖ' => 'تمح', 'ﵗ' => 'تمخ', 'ﵘ' => 'جمح', 'ﵙ' => 'جمح', 'ﵚ' => 'حمي', 'ﵛ' => 'حمى', 'ﵜ' => 'سحج', 'ﵝ' => 'سجح', 'ﵞ' => 'سجى', 'ﵟ' => 'سمح', 'ﵠ' => 'سمح', 'ﵡ' => 'سمج', 'ﵢ' => 'سمم', 'ﵣ' => 'سمم', 'ﵤ' => 'صحح', 'ﵥ' => 'صحح', 'ﵦ' => 'صمم', 'ﵧ' => 'شحم', 'ﵨ' => 'شحم', 'ﵩ' => 'شجي', 'ﵪ' => 'شمخ', 'ﵫ' => 'شمخ', 'ﵬ' => 'شمم', 'ﵭ' => 'شمم', 'ﵮ' => 'ضحى', 'ﵯ' => 'ضخم', 'ﵰ' => 'ضخم', 'ﵱ' => 'طمح', 'ﵲ' => 'طمح', 'ﵳ' => 'طمم', 'ﵴ' => 'طمي', 'ﵵ' => 'عجم', 'ﵶ' => 'عمم', 'ﵷ' => 'عمم', 'ﵸ' => 'عمى', 'ﵹ' => 'غمم', 'ﵺ' => 'غمي', 'ﵻ' => 'غمى', 'ﵼ' => 'فخم', 'ﵽ' => 'فخم', 'ﵾ' => 'قمح', 'ﵿ' => 'قمم', 'ﶀ' => 'لحم', 'ﶁ' => 'لحي', 'ﶂ' => 'لحى', 'ﶃ' => 'لجج', 'ﶄ' => 'لجج', 'ﶅ' => 'لخم', 'ﶆ' => 'لخم', 'ﶇ' => 'لمح', 'ﶈ' => 'لمح', 'ﶉ' => 'محج', 'ﶊ' => 'محم', 'ﶋ' => 'محي', 'ﶌ' => 'مجح', 'ﶍ' => 'مجم', 'ﶎ' => 'مخج', 'ﶏ' => 'مخم', 'ﶒ' => 'مجخ', 'ﶓ' => 'همج', 'ﶔ' => 'همم', 'ﶕ' => 'نحم', 'ﶖ' => 'نحى', 'ﶗ' => 'نجم', 'ﶘ' => 'نجم', 'ﶙ' => 'نجى', 'ﶚ' => 'نمي', 'ﶛ' => 'نمى', 'ﶜ' => 'يمم', 'ﶝ' => 'يمم', 'ﶞ' => 'بخي', 'ﶟ' => 'تجي', 'ﶠ' => 'تجى', 'ﶡ' => 'تخي', 'ﶢ' => 'تخى', 'ﶣ' => 'تمي', 'ﶤ' => 'تمى', 'ﶥ' => 'جمي', 'ﶦ' => 'جحى', 'ﶧ' => 'جمى', 'ﶨ' => 'سخى', 'ﶩ' => 'صحي', 'ﶪ' => 'شحي', 'ﶫ' => 'ضحي', 'ﶬ' => 'لجي', 'ﶭ' => 'لمي', 'ﶮ' => 'يحي', 'ﶯ' => 'يجي', 'ﶰ' => 'يمي', 'ﶱ' => 'ممي', 'ﶲ' => 'قمي', 'ﶳ' => 'نحي', 'ﶴ' => 'قمح', 'ﶵ' => 'لحم', 'ﶶ' => 'عمي', 'ﶷ' => 'كمي', 'ﶸ' => 'نجح', 'ﶹ' => 'مخي', 'ﶺ' => 'لجم', 'ﶻ' => 'كمم', 'ﶼ' => 'لجم', 'ﶽ' => 'نجح', 'ﶾ' => 'جحي', 'ﶿ' => 'حجي', 'ﷀ' => 'مجي', 'ﷁ' => 'فمي', 'ﷂ' => 'بحي', 'ﷃ' => 'كمم', 'ﷄ' => 'عجم', 'ﷅ' => 'صمم', 'ﷆ' => 'سخي', 'ﷇ' => 'نجي', 'ﷰ' => 'صلے', 'ﷱ' => 'قلے', 'ﷲ' => 'الله', 'ﷳ' => 'اكبر', 'ﷴ' => 'محمد', 'ﷵ' => 'صلعم', 'ﷶ' => 'رسول', 'ﷷ' => 'عليه', 'ﷸ' => 'وسلم', 'ﷹ' => 'صلى', 'ﷺ' => 'صلى الله عليه وسلم', 'ﷻ' => 'جل جلاله', '﷼' => 'ریال', '︐' => ',', '︑' => '、', '︒' => '。', '︓' => ':', '︔' => ';', '︕' => '!', '︖' => '?', '︗' => '〖', '︘' => '〗', '︙' => '...', '︰' => '..', '︱' => '—', '︲' => '–', '︳' => '_', '︴' => '_', '︵' => '(', '︶' => ')', '︷' => '{', '︸' => '}', '︹' => '〔', '︺' => '〕', '︻' => '【', '︼' => '】', '︽' => '《', '︾' => '》', '︿' => '〈', '﹀' => '〉', '﹁' => '「', '﹂' => '」', '﹃' => '『', '﹄' => '』', '﹇' => '[', '﹈' => ']', '﹉' => ' ̅', '﹊' => ' ̅', '﹋' => ' ̅', '﹌' => ' ̅', '﹍' => '_', '﹎' => '_', '﹏' => '_', '﹐' => ',', '﹑' => '、', '﹒' => '.', '﹔' => ';', '﹕' => ':', '﹖' => '?', '﹗' => '!', '﹘' => '—', '﹙' => '(', '﹚' => ')', '﹛' => '{', '﹜' => '}', '﹝' => '〔', '﹞' => '〕', '﹟' => '#', '﹠' => '&', '﹡' => '*', '﹢' => '+', '﹣' => '-', '﹤' => '<', '﹥' => '>', '﹦' => '=', '﹨' => '\\', '﹩' => '$', '﹪' => '%', '﹫' => '@', 'ﹰ' => ' ً', 'ﹱ' => 'ـً', 'ﹲ' => ' ٌ', 'ﹴ' => ' ٍ', 'ﹶ' => ' َ', 'ﹷ' => 'ـَ', 'ﹸ' => ' ُ', 'ﹹ' => 'ـُ', 'ﹺ' => ' ِ', 'ﹻ' => 'ـِ', 'ﹼ' => ' ّ', 'ﹽ' => 'ـّ', 'ﹾ' => ' ْ', 'ﹿ' => 'ـْ', 'ﺀ' => 'ء', 'ﺁ' => 'آ', 'ﺂ' => 'آ', 'ﺃ' => 'أ', 'ﺄ' => 'أ', 'ﺅ' => 'ؤ', 'ﺆ' => 'ؤ', 'ﺇ' => 'إ', 'ﺈ' => 'إ', 'ﺉ' => 'ئ', 'ﺊ' => 'ئ', 'ﺋ' => 'ئ', 'ﺌ' => 'ئ', 'ﺍ' => 'ا', 'ﺎ' => 'ا', 'ﺏ' => 'ب', 'ﺐ' => 'ب', 'ﺑ' => 'ب', 'ﺒ' => 'ب', 'ﺓ' => 'ة', 'ﺔ' => 'ة', 'ﺕ' => 'ت', 'ﺖ' => 'ت', 'ﺗ' => 'ت', 'ﺘ' => 'ت', 'ﺙ' => 'ث', 'ﺚ' => 'ث', 'ﺛ' => 'ث', 'ﺜ' => 'ث', 'ﺝ' => 'ج', 'ﺞ' => 'ج', 'ﺟ' => 'ج', 'ﺠ' => 'ج', 'ﺡ' => 'ح', 'ﺢ' => 'ح', 'ﺣ' => 'ح', 'ﺤ' => 'ح', 'ﺥ' => 'خ', 'ﺦ' => 'خ', 'ﺧ' => 'خ', 'ﺨ' => 'خ', 'ﺩ' => 'د', 'ﺪ' => 'د', 'ﺫ' => 'ذ', 'ﺬ' => 'ذ', 'ﺭ' => 'ر', 'ﺮ' => 'ر', 'ﺯ' => 'ز', 'ﺰ' => 'ز', 'ﺱ' => 'س', 'ﺲ' => 'س', 'ﺳ' => 'س', 'ﺴ' => 'س', 'ﺵ' => 'ش', 'ﺶ' => 'ش', 'ﺷ' => 'ش', 'ﺸ' => 'ش', 'ﺹ' => 'ص', 'ﺺ' => 'ص', 'ﺻ' => 'ص', 'ﺼ' => 'ص', 'ﺽ' => 'ض', 'ﺾ' => 'ض', 'ﺿ' => 'ض', 'ﻀ' => 'ض', 'ﻁ' => 'ط', 'ﻂ' => 'ط', 'ﻃ' => 'ط', 'ﻄ' => 'ط', 'ﻅ' => 'ظ', 'ﻆ' => 'ظ', 'ﻇ' => 'ظ', 'ﻈ' => 'ظ', 'ﻉ' => 'ع', 'ﻊ' => 'ع', 'ﻋ' => 'ع', 'ﻌ' => 'ع', 'ﻍ' => 'غ', 'ﻎ' => 'غ', 'ﻏ' => 'غ', 'ﻐ' => 'غ', 'ﻑ' => 'ف', 'ﻒ' => 'ف', 'ﻓ' => 'ف', 'ﻔ' => 'ف', 'ﻕ' => 'ق', 'ﻖ' => 'ق', 'ﻗ' => 'ق', 'ﻘ' => 'ق', 'ﻙ' => 'ك', 'ﻚ' => 'ك', 'ﻛ' => 'ك', 'ﻜ' => 'ك', 'ﻝ' => 'ل', 'ﻞ' => 'ل', 'ﻟ' => 'ل', 'ﻠ' => 'ل', 'ﻡ' => 'م', 'ﻢ' => 'م', 'ﻣ' => 'م', 'ﻤ' => 'م', 'ﻥ' => 'ن', 'ﻦ' => 'ن', 'ﻧ' => 'ن', 'ﻨ' => 'ن', 'ﻩ' => 'ه', 'ﻪ' => 'ه', 'ﻫ' => 'ه', 'ﻬ' => 'ه', 'ﻭ' => 'و', 'ﻮ' => 'و', 'ﻯ' => 'ى', 'ﻰ' => 'ى', 'ﻱ' => 'ي', 'ﻲ' => 'ي', 'ﻳ' => 'ي', 'ﻴ' => 'ي', 'ﻵ' => 'لآ', 'ﻶ' => 'لآ', 'ﻷ' => 'لأ', 'ﻸ' => 'لأ', 'ﻹ' => 'لإ', 'ﻺ' => 'لإ', 'ﻻ' => 'لا', 'ﻼ' => 'لا', '!' => '!', '"' => '"', '#' => '#', '$' => '$', '%' => '%', '&' => '&', ''' => '\'', '(' => '(', ')' => ')', '*' => '*', '+' => '+', ',' => ',', '-' => '-', '.' => '.', '/' => '/', '0' => '0', '1' => '1', '2' => '2', '3' => '3', '4' => '4', '5' => '5', '6' => '6', '7' => '7', '8' => '8', '9' => '9', ':' => ':', ';' => ';', '<' => '<', '=' => '=', '>' => '>', '?' => '?', '@' => '@', 'A' => 'A', 'B' => 'B', 'C' => 'C', 'D' => 'D', 'E' => 'E', 'F' => 'F', 'G' => 'G', 'H' => 'H', 'I' => 'I', 'J' => 'J', 'K' => 'K', 'L' => 'L', 'M' => 'M', 'N' => 'N', 'O' => 'O', 'P' => 'P', 'Q' => 'Q', 'R' => 'R', 'S' => 'S', 'T' => 'T', 'U' => 'U', 'V' => 'V', 'W' => 'W', 'X' => 'X', 'Y' => 'Y', 'Z' => 'Z', '[' => '[', '\' => '\\', ']' => ']', '^' => '^', '_' => '_', '`' => '`', 'a' => 'a', 'b' => 'b', 'c' => 'c', 'd' => 'd', 'e' => 'e', 'f' => 'f', 'g' => 'g', 'h' => 'h', 'i' => 'i', 'j' => 'j', 'k' => 'k', 'l' => 'l', 'm' => 'm', 'n' => 'n', 'o' => 'o', 'p' => 'p', 'q' => 'q', 'r' => 'r', 's' => 's', 't' => 't', 'u' => 'u', 'v' => 'v', 'w' => 'w', 'x' => 'x', 'y' => 'y', 'z' => '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', '𝐚' => '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', '𝑎' => 'a', '𝑏' => 'b', '𝑐' => 'c', '𝑑' => 'd', '𝑒' => 'e', '𝑓' => 'f', '𝑔' => 'g', '𝑖' => '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', '𝒂' => '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', '𝒞' => 'C', '𝒟' => 'D', '𝒢' => 'G', '𝒥' => 'J', '𝒦' => 'K', '𝒩' => 'N', '𝒪' => 'O', '𝒫' => 'P', '𝒬' => 'Q', '𝒮' => 'S', '𝒯' => 'T', '𝒰' => 'U', '𝒱' => 'V', '𝒲' => 'W', '𝒳' => 'X', '𝒴' => 'Y', '𝒵' => 'Z', '𝒶' => 'a', '𝒷' => 'b', '𝒸' => 'c', '𝒹' => 'd', '𝒻' => 'f', '𝒽' => 'h', '𝒾' => 'i', '𝒿' => 'j', '𝓀' => 'k', '𝓁' => 'l', '𝓂' => 'm', '𝓃' => 'n', '𝓅' => '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', '𝓪' => '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', '𝔇' => 'D', '𝔈' => 'E', '𝔉' => 'F', '𝔊' => 'G', '𝔍' => 'J', '𝔎' => 'K', '𝔏' => 'L', '𝔐' => 'M', '𝔑' => 'N', '𝔒' => 'O', '𝔓' => 'P', '𝔔' => 'Q', '𝔖' => 'S', '𝔗' => 'T', '𝔘' => 'U', '𝔙' => 'V', '𝔚' => 'W', '𝔛' => 'X', '𝔜' => 'Y', '𝔞' => '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', '𝔻' => 'D', '𝔼' => 'E', '𝔽' => 'F', '𝔾' => 'G', '𝕀' => 'I', '𝕁' => 'J', '𝕂' => 'K', '𝕃' => 'L', '𝕄' => 'M', '𝕆' => 'O', '𝕊' => 'S', '𝕋' => 'T', '𝕌' => 'U', '𝕍' => 'V', '𝕎' => 'W', '𝕏' => 'X', '𝕐' => 'Y', '𝕒' => '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', '𝖆' => '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', '𝖺' => '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', '𝗮' => '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', '𝘢' => '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', '𝙖' => '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', '𝚊' => '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', '𝚤' => 'ı', '𝚥' => 'ȷ', '𝚨' => 'Α', '𝚩' => 'Β', '𝚪' => 'Γ', '𝚫' => 'Δ', '𝚬' => 'Ε', '𝚭' => 'Ζ', '𝚮' => 'Η', '𝚯' => 'Θ', '𝚰' => 'Ι', '𝚱' => 'Κ', '𝚲' => 'Λ', '𝚳' => 'Μ', '𝚴' => 'Ν', '𝚵' => 'Ξ', '𝚶' => 'Ο', '𝚷' => 'Π', '𝚸' => 'Ρ', '𝚹' => 'Θ', '𝚺' => 'Σ', '𝚻' => 'Τ', '𝚼' => 'Υ', '𝚽' => 'Φ', '𝚾' => 'Χ', '𝚿' => 'Ψ', '𝛀' => 'Ω', '𝛁' => '∇', '𝛂' => 'α', '𝛃' => 'β', '𝛄' => 'γ', '𝛅' => 'δ', '𝛆' => 'ε', '𝛇' => 'ζ', '𝛈' => 'η', '𝛉' => 'θ', '𝛊' => 'ι', '𝛋' => 'κ', '𝛌' => 'λ', '𝛍' => 'μ', '𝛎' => 'ν', '𝛏' => 'ξ', '𝛐' => 'ο', '𝛑' => 'π', '𝛒' => 'ρ', '𝛓' => 'ς', '𝛔' => 'σ', '𝛕' => 'τ', '𝛖' => 'υ', '𝛗' => 'φ', '𝛘' => 'χ', '𝛙' => 'ψ', '𝛚' => 'ω', '𝛛' => '∂', '𝛜' => 'ε', '𝛝' => 'θ', '𝛞' => 'κ', '𝛟' => 'φ', '𝛠' => 'ρ', '𝛡' => 'π', '𝛢' => 'Α', '𝛣' => 'Β', '𝛤' => 'Γ', '𝛥' => 'Δ', '𝛦' => 'Ε', '𝛧' => 'Ζ', '𝛨' => 'Η', '𝛩' => 'Θ', '𝛪' => 'Ι', '𝛫' => 'Κ', '𝛬' => 'Λ', '𝛭' => 'Μ', '𝛮' => 'Ν', '𝛯' => 'Ξ', '𝛰' => 'Ο', '𝛱' => 'Π', '𝛲' => 'Ρ', '𝛳' => 'Θ', '𝛴' => 'Σ', '𝛵' => 'Τ', '𝛶' => 'Υ', '𝛷' => 'Φ', '𝛸' => 'Χ', '𝛹' => 'Ψ', '𝛺' => 'Ω', '𝛻' => '∇', '𝛼' => 'α', '𝛽' => 'β', '𝛾' => 'γ', '𝛿' => 'δ', '𝜀' => 'ε', '𝜁' => 'ζ', '𝜂' => 'η', '𝜃' => 'θ', '𝜄' => 'ι', '𝜅' => 'κ', '𝜆' => 'λ', '𝜇' => 'μ', '𝜈' => 'ν', '𝜉' => 'ξ', '𝜊' => 'ο', '𝜋' => 'π', '𝜌' => 'ρ', '𝜍' => 'ς', '𝜎' => 'σ', '𝜏' => 'τ', '𝜐' => 'υ', '𝜑' => 'φ', '𝜒' => 'χ', '𝜓' => 'ψ', '𝜔' => 'ω', '𝜕' => '∂', '𝜖' => 'ε', '𝜗' => 'θ', '𝜘' => 'κ', '𝜙' => 'φ', '𝜚' => 'ρ', '𝜛' => 'π', '𝜜' => 'Α', '𝜝' => 'Β', '𝜞' => 'Γ', '𝜟' => 'Δ', '𝜠' => 'Ε', '𝜡' => 'Ζ', '𝜢' => 'Η', '𝜣' => 'Θ', '𝜤' => 'Ι', '𝜥' => 'Κ', '𝜦' => 'Λ', '𝜧' => 'Μ', '𝜨' => 'Ν', '𝜩' => 'Ξ', '𝜪' => 'Ο', '𝜫' => 'Π', '𝜬' => 'Ρ', '𝜭' => 'Θ', '𝜮' => 'Σ', '𝜯' => 'Τ', '𝜰' => 'Υ', '𝜱' => 'Φ', '𝜲' => 'Χ', '𝜳' => 'Ψ', '𝜴' => 'Ω', '𝜵' => '∇', '𝜶' => 'α', '𝜷' => 'β', '𝜸' => 'γ', '𝜹' => 'δ', '𝜺' => 'ε', '𝜻' => 'ζ', '𝜼' => 'η', '𝜽' => 'θ', '𝜾' => 'ι', '𝜿' => 'κ', '𝝀' => 'λ', '𝝁' => 'μ', '𝝂' => 'ν', '𝝃' => 'ξ', '𝝄' => 'ο', '𝝅' => 'π', '𝝆' => 'ρ', '𝝇' => 'ς', '𝝈' => 'σ', '𝝉' => 'τ', '𝝊' => 'υ', '𝝋' => 'φ', '𝝌' => 'χ', '𝝍' => 'ψ', '𝝎' => 'ω', '𝝏' => '∂', '𝝐' => 'ε', '𝝑' => 'θ', '𝝒' => 'κ', '𝝓' => 'φ', '𝝔' => 'ρ', '𝝕' => 'π', '𝝖' => 'Α', '𝝗' => 'Β', '𝝘' => 'Γ', '𝝙' => 'Δ', '𝝚' => 'Ε', '𝝛' => 'Ζ', '𝝜' => 'Η', '𝝝' => 'Θ', '𝝞' => 'Ι', '𝝟' => 'Κ', '𝝠' => 'Λ', '𝝡' => 'Μ', '𝝢' => 'Ν', '𝝣' => 'Ξ', '𝝤' => 'Ο', '𝝥' => 'Π', '𝝦' => 'Ρ', '𝝧' => 'Θ', '𝝨' => 'Σ', '𝝩' => 'Τ', '𝝪' => 'Υ', '𝝫' => 'Φ', '𝝬' => 'Χ', '𝝭' => 'Ψ', '𝝮' => 'Ω', '𝝯' => '∇', '𝝰' => 'α', '𝝱' => 'β', '𝝲' => 'γ', '𝝳' => 'δ', '𝝴' => 'ε', '𝝵' => 'ζ', '𝝶' => 'η', '𝝷' => 'θ', '𝝸' => 'ι', '𝝹' => 'κ', '𝝺' => 'λ', '𝝻' => 'μ', '𝝼' => 'ν', '𝝽' => 'ξ', '𝝾' => 'ο', '𝝿' => 'π', '𝞀' => 'ρ', '𝞁' => 'ς', '𝞂' => 'σ', '𝞃' => 'τ', '𝞄' => 'υ', '𝞅' => 'φ', '𝞆' => 'χ', '𝞇' => 'ψ', '𝞈' => 'ω', '𝞉' => '∂', '𝞊' => 'ε', '𝞋' => 'θ', '𝞌' => 'κ', '𝞍' => 'φ', '𝞎' => 'ρ', '𝞏' => 'π', '𝞐' => 'Α', '𝞑' => 'Β', '𝞒' => 'Γ', '𝞓' => 'Δ', '𝞔' => 'Ε', '𝞕' => 'Ζ', '𝞖' => 'Η', '𝞗' => 'Θ', '𝞘' => 'Ι', '𝞙' => 'Κ', '𝞚' => 'Λ', '𝞛' => 'Μ', '𝞜' => 'Ν', '𝞝' => 'Ξ', '𝞞' => 'Ο', '𝞟' => 'Π', '𝞠' => 'Ρ', '𝞡' => 'Θ', '𝞢' => 'Σ', '𝞣' => 'Τ', '𝞤' => 'Υ', '𝞥' => 'Φ', '𝞦' => 'Χ', '𝞧' => 'Ψ', '𝞨' => 'Ω', '𝞩' => '∇', '𝞪' => 'α', '𝞫' => 'β', '𝞬' => 'γ', '𝞭' => 'δ', '𝞮' => 'ε', '𝞯' => 'ζ', '𝞰' => 'η', '𝞱' => 'θ', '𝞲' => 'ι', '𝞳' => 'κ', '𝞴' => 'λ', '𝞵' => 'μ', '𝞶' => 'ν', '𝞷' => 'ξ', '𝞸' => 'ο', '𝞹' => 'π', '𝞺' => 'ρ', '𝞻' => 'ς', '𝞼' => 'σ', '𝞽' => 'τ', '𝞾' => 'υ', '𝞿' => 'φ', '𝟀' => 'χ', '𝟁' => 'ψ', '𝟂' => 'ω', '𝟃' => '∂', '𝟄' => 'ε', '𝟅' => 'θ', '𝟆' => 'κ', '𝟇' => 'φ', '𝟈' => 'ρ', '𝟉' => 'π', '𝟊' => 'Ϝ', '𝟋' => 'ϝ', '𝟎' => '0', '𝟏' => '1', '𝟐' => '2', '𝟑' => '3', '𝟒' => '4', '𝟓' => '5', '𝟔' => '6', '𝟕' => '7', '𝟖' => '8', '𝟗' => '9', '𝟘' => '0', '𝟙' => '1', '𝟚' => '2', '𝟛' => '3', '𝟜' => '4', '𝟝' => '5', '𝟞' => '6', '𝟟' => '7', '𝟠' => '8', '𝟡' => '9', '𝟢' => '0', '𝟣' => '1', '𝟤' => '2', '𝟥' => '3', '𝟦' => '4', '𝟧' => '5', '𝟨' => '6', '𝟩' => '7', '𝟪' => '8', '𝟫' => '9', '𝟬' => '0', '𝟭' => '1', '𝟮' => '2', '𝟯' => '3', '𝟰' => '4', '𝟱' => '5', '𝟲' => '6', '𝟳' => '7', '𝟴' => '8', '𝟵' => '9', '𝟶' => '0', '𝟷' => '1', '𝟸' => '2', '𝟹' => '3', '𝟺' => '4', '𝟻' => '5', '𝟼' => '6', '𝟽' => '7', '𝟾' => '8', '𝟿' => '9', '𞸀' => 'ا', '𞸁' => 'ب', '𞸂' => 'ج', '𞸃' => 'د', '𞸅' => 'و', '𞸆' => 'ز', '𞸇' => 'ح', '𞸈' => 'ط', '𞸉' => 'ي', '𞸊' => 'ك', '𞸋' => 'ل', '𞸌' => 'م', '𞸍' => 'ن', '𞸎' => 'س', '𞸏' => 'ع', '𞸐' => 'ف', '𞸑' => 'ص', '𞸒' => 'ق', '𞸓' => 'ر', '𞸔' => 'ش', '𞸕' => 'ت', '𞸖' => 'ث', '𞸗' => 'خ', '𞸘' => 'ذ', '𞸙' => 'ض', '𞸚' => 'ظ', '𞸛' => 'غ', '𞸜' => 'ٮ', '𞸝' => 'ں', '𞸞' => 'ڡ', '𞸟' => 'ٯ', '𞸡' => 'ب', '𞸢' => 'ج', '𞸤' => 'ه', '𞸧' => 'ح', '𞸩' => 'ي', '𞸪' => 'ك', '𞸫' => 'ل', '𞸬' => 'م', '𞸭' => 'ن', '𞸮' => 'س', '𞸯' => 'ع', '𞸰' => 'ف', '𞸱' => 'ص', '𞸲' => 'ق', '𞸴' => 'ش', '𞸵' => 'ت', '𞸶' => 'ث', '𞸷' => 'خ', '𞸹' => 'ض', '𞸻' => 'غ', '𞹂' => 'ج', '𞹇' => 'ح', '𞹉' => 'ي', '𞹋' => 'ل', '𞹍' => 'ن', '𞹎' => 'س', '𞹏' => 'ع', '𞹑' => 'ص', '𞹒' => 'ق', '𞹔' => 'ش', '𞹗' => 'خ', '𞹙' => 'ض', '𞹛' => 'غ', '𞹝' => 'ں', '𞹟' => 'ٯ', '𞹡' => 'ب', '𞹢' => 'ج', '𞹤' => 'ه', '𞹧' => 'ح', '𞹨' => 'ط', '𞹩' => 'ي', '𞹪' => 'ك', '𞹬' => 'م', '𞹭' => 'ن', '𞹮' => 'س', '𞹯' => 'ع', '𞹰' => 'ف', '𞹱' => 'ص', '𞹲' => 'ق', '𞹴' => 'ش', '𞹵' => 'ت', '𞹶' => 'ث', '𞹷' => 'خ', '𞹹' => 'ض', '𞹺' => 'ظ', '𞹻' => 'غ', '𞹼' => 'ٮ', '𞹾' => 'ڡ', '𞺀' => 'ا', '𞺁' => 'ب', '𞺂' => 'ج', '𞺃' => 'د', '𞺄' => 'ه', '𞺅' => 'و', '𞺆' => 'ز', '𞺇' => 'ح', '𞺈' => 'ط', '𞺉' => 'ي', '𞺋' => 'ل', '𞺌' => 'م', '𞺍' => 'ن', '𞺎' => 'س', '𞺏' => 'ع', '𞺐' => 'ف', '𞺑' => 'ص', '𞺒' => 'ق', '𞺓' => 'ر', '𞺔' => 'ش', '𞺕' => 'ت', '𞺖' => 'ث', '𞺗' => 'خ', '𞺘' => 'ذ', '𞺙' => 'ض', '𞺚' => 'ظ', '𞺛' => 'غ', '𞺡' => 'ب', '𞺢' => 'ج', '𞺣' => 'د', '𞺥' => 'و', '𞺦' => 'ز', '𞺧' => 'ح', '𞺨' => 'ط', '𞺩' => 'ي', '𞺫' => 'ل', '𞺬' => 'م', '𞺭' => 'ن', '𞺮' => 'س', '𞺯' => 'ع', '𞺰' => 'ف', '𞺱' => 'ص', '𞺲' => 'ق', '𞺳' => 'ر', '𞺴' => 'ش', '𞺵' => 'ت', '𞺶' => 'ث', '𞺷' => 'خ', '𞺸' => 'ذ', '𞺹' => 'ض', '𞺺' => 'ظ', '𞺻' => 'غ', '🄀' => '0.', '🄁' => '0,', '🄂' => '1,', '🄃' => '2,', '🄄' => '3,', '🄅' => '4,', '🄆' => '5,', '🄇' => '6,', '🄈' => '7,', '🄉' => '8,', '🄊' => '9,', '🄐' => '(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)', '🄪' => '〔S〕', '🄫' => 'C', '🄬' => 'R', '🄭' => 'CD', '🄮' => 'WZ', '🄰' => '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', '🅊' => 'HV', '🅋' => 'MV', '🅌' => 'SD', '🅍' => 'SS', '🅎' => 'PPV', '🅏' => 'WC', '🅪' => 'MC', '🅫' => 'MD', '🅬' => 'MR', '🆐' => 'DJ', '🈀' => 'ほか', '🈁' => 'ココ', '🈂' => 'サ', '🈐' => '手', '🈑' => '字', '🈒' => '双', '🈓' => 'デ', '🈔' => '二', '🈕' => '多', '🈖' => '解', '🈗' => '天', '🈘' => '交', '🈙' => '映', '🈚' => '無', '🈛' => '料', '🈜' => '前', '🈝' => '後', '🈞' => '再', '🈟' => '新', '🈠' => '初', '🈡' => '終', '🈢' => '生', '🈣' => '販', '🈤' => '声', '🈥' => '吹', '🈦' => '演', '🈧' => '投', '🈨' => '捕', '🈩' => '一', '🈪' => '三', '🈫' => '遊', '🈬' => '左', '🈭' => '中', '🈮' => '右', '🈯' => '指', '🈰' => '走', '🈱' => '打', '🈲' => '禁', '🈳' => '空', '🈴' => '合', '🈵' => '満', '🈶' => '有', '🈷' => '月', '🈸' => '申', '🈹' => '割', '🈺' => '営', '🈻' => '配', '🉀' => '〔本〕', '🉁' => '〔三〕', '🉂' => '〔二〕', '🉃' => '〔安〕', '🉄' => '〔点〕', '🉅' => '〔打〕', '🉆' => '〔盗〕', '🉇' => '〔勝〕', '🉈' => '〔敗〕', '🉐' => '得', '🉑' => '可', '🯰' => '0', '🯱' => '1', '🯲' => '2', '🯳' => '3', '🯴' => '4', '🯵' => '5', '🯶' => '6', '🯷' => '7', '🯸' => '8', '🯹' => '9'); 'À', 'Á' => 'Á', 'Â' => 'Â', 'Ã' => 'Ã', 'Ä' => 'Ä', 'Å' => 'Å', 'Ç' => 'Ç', 'È' => 'È', 'É' => 'É', 'Ê' => 'Ê', 'Ë' => 'Ë', 'Ì' => 'Ì', 'Í' => 'Í', 'Î' => 'Î', 'Ï' => 'Ï', 'Ñ' => 'Ñ', 'Ò' => 'Ò', 'Ó' => 'Ó', 'Ô' => 'Ô', 'Õ' => 'Õ', 'Ö' => 'Ö', 'Ù' => 'Ù', 'Ú' => 'Ú', 'Û' => 'Û', 'Ü' => 'Ü', 'Ý' => 'Ý', 'à' => 'à', 'á' => 'á', 'â' => 'â', 'ã' => 'ã', 'ä' => 'ä', 'å' => 'å', 'ç' => 'ç', 'è' => 'è', 'é' => 'é', 'ê' => 'ê', 'ë' => 'ë', 'ì' => 'ì', 'í' => 'í', 'î' => 'î', 'ï' => 'ï', 'ñ' => 'ñ', 'ò' => 'ò', 'ó' => 'ó', 'ô' => 'ô', 'õ' => 'õ', 'ö' => 'ö', 'ù' => 'ù', 'ú' => 'ú', 'û' => 'û', 'ü' => 'ü', 'ý' => 'ý', 'ÿ' => 'ÿ', 'Ā' => 'Ā', 'ā' => 'ā', 'Ă' => 'Ă', 'ă' => 'ă', 'Ą' => 'Ą', 'ą' => 'ą', 'Ć' => 'Ć', 'ć' => 'ć', 'Ĉ' => 'Ĉ', 'ĉ' => 'ĉ', 'Ċ' => 'Ċ', 'ċ' => 'ċ', 'Č' => 'Č', 'č' => 'č', 'Ď' => 'Ď', 'ď' => 'ď', 'Ē' => 'Ē', 'ē' => 'ē', 'Ĕ' => 'Ĕ', 'ĕ' => 'ĕ', 'Ė' => 'Ė', 'ė' => 'ė', 'Ę' => 'Ę', 'ę' => 'ę', 'Ě' => 'Ě', 'ě' => 'ě', 'Ĝ' => 'Ĝ', 'ĝ' => 'ĝ', 'Ğ' => 'Ğ', 'ğ' => 'ğ', 'Ġ' => 'Ġ', 'ġ' => 'ġ', 'Ģ' => 'Ģ', 'ģ' => 'ģ', 'Ĥ' => 'Ĥ', 'ĥ' => 'ĥ', 'Ĩ' => 'Ĩ', 'ĩ' => 'ĩ', 'Ī' => 'Ī', 'ī' => 'ī', 'Ĭ' => 'Ĭ', 'ĭ' => 'ĭ', 'Į' => 'Į', 'į' => 'į', 'İ' => 'İ', 'Ĵ' => 'Ĵ', 'ĵ' => 'ĵ', 'Ķ' => 'Ķ', 'ķ' => 'ķ', 'Ĺ' => 'Ĺ', 'ĺ' => 'ĺ', 'Ļ' => 'Ļ', 'ļ' => 'ļ', 'Ľ' => 'Ľ', 'ľ' => 'ľ', 'Ń' => 'Ń', 'ń' => 'ń', 'Ņ' => 'Ņ', 'ņ' => 'ņ', 'Ň' => 'Ň', 'ň' => 'ň', 'Ō' => 'Ō', 'ō' => 'ō', 'Ŏ' => 'Ŏ', 'ŏ' => 'ŏ', 'Ő' => 'Ő', 'ő' => 'ő', 'Ŕ' => 'Ŕ', 'ŕ' => 'ŕ', 'Ŗ' => 'Ŗ', 'ŗ' => 'ŗ', 'Ř' => 'Ř', 'ř' => 'ř', 'Ś' => 'Ś', 'ś' => 'ś', 'Ŝ' => 'Ŝ', 'ŝ' => 'ŝ', 'Ş' => 'Ş', 'ş' => 'ş', 'Š' => 'Š', 'š' => 'š', 'Ţ' => 'Ţ', 'ţ' => 'ţ', 'Ť' => 'Ť', 'ť' => 'ť', 'Ũ' => 'Ũ', 'ũ' => 'ũ', 'Ū' => 'Ū', 'ū' => 'ū', 'Ŭ' => 'Ŭ', 'ŭ' => 'ŭ', 'Ů' => 'Ů', 'ů' => 'ů', 'Ű' => 'Ű', 'ű' => 'ű', 'Ų' => 'Ų', 'ų' => 'ų', 'Ŵ' => 'Ŵ', 'ŵ' => 'ŵ', 'Ŷ' => 'Ŷ', 'ŷ' => 'ŷ', 'Ÿ' => 'Ÿ', 'Ź' => 'Ź', 'ź' => 'ź', 'Ż' => 'Ż', 'ż' => 'ż', 'Ž' => 'Ž', 'ž' => 'ž', 'Ơ' => 'Ơ', 'ơ' => 'ơ', 'Ư' => 'Ư', 'ư' => 'ư', 'Ǎ' => 'Ǎ', 'ǎ' => 'ǎ', 'Ǐ' => 'Ǐ', 'ǐ' => 'ǐ', 'Ǒ' => 'Ǒ', 'ǒ' => 'ǒ', 'Ǔ' => 'Ǔ', 'ǔ' => 'ǔ', 'Ǖ' => 'Ǖ', 'ǖ' => 'ǖ', 'Ǘ' => 'Ǘ', 'ǘ' => 'ǘ', 'Ǚ' => 'Ǚ', 'ǚ' => 'ǚ', 'Ǜ' => 'Ǜ', 'ǜ' => 'ǜ', 'Ǟ' => 'Ǟ', 'ǟ' => 'ǟ', 'Ǡ' => 'Ǡ', 'ǡ' => 'ǡ', 'Ǣ' => 'Ǣ', 'ǣ' => 'ǣ', 'Ǧ' => 'Ǧ', 'ǧ' => 'ǧ', 'Ǩ' => 'Ǩ', 'ǩ' => 'ǩ', 'Ǫ' => 'Ǫ', 'ǫ' => 'ǫ', 'Ǭ' => 'Ǭ', 'ǭ' => 'ǭ', 'Ǯ' => 'Ǯ', 'ǯ' => 'ǯ', 'ǰ' => 'ǰ', 'Ǵ' => 'Ǵ', 'ǵ' => 'ǵ', 'Ǹ' => 'Ǹ', 'ǹ' => 'ǹ', 'Ǻ' => 'Ǻ', 'ǻ' => 'ǻ', 'Ǽ' => 'Ǽ', 'ǽ' => 'ǽ', 'Ǿ' => 'Ǿ', 'ǿ' => 'ǿ', 'Ȁ' => 'Ȁ', 'ȁ' => 'ȁ', 'Ȃ' => 'Ȃ', 'ȃ' => 'ȃ', 'Ȅ' => 'Ȅ', 'ȅ' => 'ȅ', 'Ȇ' => 'Ȇ', 'ȇ' => 'ȇ', 'Ȉ' => 'Ȉ', 'ȉ' => 'ȉ', 'Ȋ' => 'Ȋ', 'ȋ' => 'ȋ', 'Ȍ' => 'Ȍ', 'ȍ' => 'ȍ', 'Ȏ' => 'Ȏ', 'ȏ' => 'ȏ', 'Ȑ' => 'Ȑ', 'ȑ' => 'ȑ', 'Ȓ' => 'Ȓ', 'ȓ' => 'ȓ', 'Ȕ' => 'Ȕ', 'ȕ' => 'ȕ', 'Ȗ' => 'Ȗ', 'ȗ' => 'ȗ', 'Ș' => 'Ș', 'ș' => 'ș', 'Ț' => 'Ț', 'ț' => 'ț', 'Ȟ' => 'Ȟ', 'ȟ' => 'ȟ', 'Ȧ' => 'Ȧ', 'ȧ' => 'ȧ', 'Ȩ' => 'Ȩ', 'ȩ' => 'ȩ', 'Ȫ' => 'Ȫ', 'ȫ' => 'ȫ', 'Ȭ' => 'Ȭ', 'ȭ' => 'ȭ', 'Ȯ' => 'Ȯ', 'ȯ' => 'ȯ', 'Ȱ' => 'Ȱ', 'ȱ' => 'ȱ', 'Ȳ' => 'Ȳ', 'ȳ' => 'ȳ', '΅' => '΅', 'Ά' => 'Ά', 'Έ' => 'Έ', 'Ή' => 'Ή', 'Ί' => 'Ί', 'Ό' => 'Ό', 'Ύ' => 'Ύ', 'Ώ' => 'Ώ', 'ΐ' => 'ΐ', 'Ϊ' => 'Ϊ', 'Ϋ' => 'Ϋ', 'ά' => 'ά', 'έ' => 'έ', 'ή' => 'ή', 'ί' => 'ί', 'ΰ' => 'ΰ', 'ϊ' => 'ϊ', 'ϋ' => 'ϋ', 'ό' => 'ό', 'ύ' => 'ύ', 'ώ' => 'ώ', 'ϓ' => 'ϓ', 'ϔ' => 'ϔ', 'Ѐ' => 'Ѐ', 'Ё' => 'Ё', 'Ѓ' => 'Ѓ', 'Ї' => 'Ї', 'Ќ' => 'Ќ', 'Ѝ' => 'Ѝ', 'Ў' => 'Ў', 'Й' => 'Й', 'й' => 'й', 'ѐ' => 'ѐ', 'ё' => 'ё', 'ѓ' => 'ѓ', 'ї' => 'ї', 'ќ' => 'ќ', 'ѝ' => 'ѝ', 'ў' => 'ў', 'Ѷ' => 'Ѷ', 'ѷ' => 'ѷ', 'Ӂ' => 'Ӂ', 'ӂ' => 'ӂ', 'Ӑ' => 'Ӑ', 'ӑ' => 'ӑ', 'Ӓ' => 'Ӓ', 'ӓ' => 'ӓ', 'Ӗ' => 'Ӗ', 'ӗ' => 'ӗ', 'Ӛ' => 'Ӛ', 'ӛ' => 'ӛ', 'Ӝ' => 'Ӝ', 'ӝ' => 'ӝ', 'Ӟ' => 'Ӟ', 'ӟ' => 'ӟ', 'Ӣ' => 'Ӣ', 'ӣ' => 'ӣ', 'Ӥ' => 'Ӥ', 'ӥ' => 'ӥ', 'Ӧ' => 'Ӧ', 'ӧ' => 'ӧ', 'Ӫ' => 'Ӫ', 'ӫ' => 'ӫ', 'Ӭ' => 'Ӭ', 'ӭ' => 'ӭ', 'Ӯ' => 'Ӯ', 'ӯ' => 'ӯ', 'Ӱ' => 'Ӱ', 'ӱ' => 'ӱ', 'Ӳ' => 'Ӳ', 'ӳ' => 'ӳ', 'Ӵ' => 'Ӵ', 'ӵ' => 'ӵ', 'Ӹ' => 'Ӹ', 'ӹ' => 'ӹ', 'آ' => 'آ', 'أ' => 'أ', 'ؤ' => 'ؤ', 'إ' => 'إ', 'ئ' => 'ئ', 'ۀ' => 'ۀ', 'ۂ' => 'ۂ', 'ۓ' => 'ۓ', 'ऩ' => 'ऩ', 'ऱ' => 'ऱ', 'ऴ' => 'ऴ', 'ো' => 'ো', 'ৌ' => 'ৌ', 'ୈ' => 'ୈ', 'ୋ' => 'ୋ', 'ୌ' => 'ୌ', 'ஔ' => 'ஔ', 'ொ' => 'ொ', 'ோ' => 'ோ', 'ௌ' => 'ௌ', 'ై' => 'ై', 'ೀ' => 'ೀ', 'ೇ' => 'ೇ', 'ೈ' => 'ೈ', 'ೊ' => 'ೊ', 'ೋ' => 'ೋ', 'ൊ' => 'ൊ', 'ോ' => 'ോ', 'ൌ' => 'ൌ', 'ේ' => 'ේ', 'ො' => 'ො', 'ෝ' => 'ෝ', 'ෞ' => 'ෞ', 'ဦ' => 'ဦ', 'ᬆ' => 'ᬆ', 'ᬈ' => 'ᬈ', 'ᬊ' => 'ᬊ', 'ᬌ' => 'ᬌ', 'ᬎ' => 'ᬎ', 'ᬒ' => 'ᬒ', 'ᬻ' => 'ᬻ', 'ᬽ' => 'ᬽ', 'ᭀ' => 'ᭀ', 'ᭁ' => 'ᭁ', 'ᭃ' => 'ᭃ', 'Ḁ' => 'Ḁ', 'ḁ' => 'ḁ', 'Ḃ' => 'Ḃ', 'ḃ' => 'ḃ', 'Ḅ' => 'Ḅ', 'ḅ' => 'ḅ', 'Ḇ' => 'Ḇ', 'ḇ' => 'ḇ', 'Ḉ' => 'Ḉ', 'ḉ' => 'ḉ', 'Ḋ' => 'Ḋ', 'ḋ' => 'ḋ', 'Ḍ' => 'Ḍ', 'ḍ' => 'ḍ', 'Ḏ' => 'Ḏ', 'ḏ' => 'ḏ', 'Ḑ' => 'Ḑ', 'ḑ' => 'ḑ', 'Ḓ' => 'Ḓ', 'ḓ' => 'ḓ', 'Ḕ' => 'Ḕ', 'ḕ' => 'ḕ', 'Ḗ' => 'Ḗ', 'ḗ' => 'ḗ', 'Ḙ' => 'Ḙ', 'ḙ' => 'ḙ', 'Ḛ' => 'Ḛ', 'ḛ' => 'ḛ', 'Ḝ' => 'Ḝ', 'ḝ' => 'ḝ', 'Ḟ' => 'Ḟ', 'ḟ' => 'ḟ', 'Ḡ' => 'Ḡ', 'ḡ' => 'ḡ', 'Ḣ' => 'Ḣ', 'ḣ' => 'ḣ', 'Ḥ' => 'Ḥ', 'ḥ' => 'ḥ', 'Ḧ' => 'Ḧ', 'ḧ' => 'ḧ', 'Ḩ' => 'Ḩ', 'ḩ' => 'ḩ', 'Ḫ' => 'Ḫ', 'ḫ' => 'ḫ', 'Ḭ' => 'Ḭ', 'ḭ' => 'ḭ', 'Ḯ' => 'Ḯ', 'ḯ' => 'ḯ', 'Ḱ' => 'Ḱ', 'ḱ' => 'ḱ', 'Ḳ' => 'Ḳ', 'ḳ' => 'ḳ', 'Ḵ' => 'Ḵ', 'ḵ' => 'ḵ', 'Ḷ' => 'Ḷ', 'ḷ' => 'ḷ', 'Ḹ' => 'Ḹ', 'ḹ' => 'ḹ', 'Ḻ' => 'Ḻ', 'ḻ' => 'ḻ', 'Ḽ' => 'Ḽ', 'ḽ' => 'ḽ', 'Ḿ' => 'Ḿ', 'ḿ' => 'ḿ', 'Ṁ' => 'Ṁ', 'ṁ' => 'ṁ', 'Ṃ' => 'Ṃ', 'ṃ' => 'ṃ', 'Ṅ' => 'Ṅ', 'ṅ' => 'ṅ', 'Ṇ' => 'Ṇ', 'ṇ' => 'ṇ', 'Ṉ' => 'Ṉ', 'ṉ' => 'ṉ', 'Ṋ' => 'Ṋ', 'ṋ' => 'ṋ', 'Ṍ' => 'Ṍ', 'ṍ' => 'ṍ', 'Ṏ' => 'Ṏ', 'ṏ' => 'ṏ', 'Ṑ' => 'Ṑ', 'ṑ' => 'ṑ', 'Ṓ' => 'Ṓ', 'ṓ' => 'ṓ', 'Ṕ' => 'Ṕ', 'ṕ' => 'ṕ', 'Ṗ' => 'Ṗ', 'ṗ' => 'ṗ', 'Ṙ' => 'Ṙ', 'ṙ' => 'ṙ', 'Ṛ' => 'Ṛ', 'ṛ' => 'ṛ', 'Ṝ' => 'Ṝ', 'ṝ' => 'ṝ', 'Ṟ' => 'Ṟ', 'ṟ' => 'ṟ', 'Ṡ' => 'Ṡ', 'ṡ' => 'ṡ', 'Ṣ' => 'Ṣ', 'ṣ' => 'ṣ', 'Ṥ' => 'Ṥ', 'ṥ' => 'ṥ', 'Ṧ' => 'Ṧ', 'ṧ' => 'ṧ', 'Ṩ' => 'Ṩ', 'ṩ' => 'ṩ', 'Ṫ' => 'Ṫ', 'ṫ' => 'ṫ', 'Ṭ' => 'Ṭ', 'ṭ' => 'ṭ', 'Ṯ' => 'Ṯ', 'ṯ' => 'ṯ', 'Ṱ' => 'Ṱ', 'ṱ' => 'ṱ', 'Ṳ' => 'Ṳ', 'ṳ' => 'ṳ', 'Ṵ' => 'Ṵ', 'ṵ' => 'ṵ', 'Ṷ' => 'Ṷ', 'ṷ' => 'ṷ', 'Ṹ' => 'Ṹ', 'ṹ' => 'ṹ', 'Ṻ' => 'Ṻ', 'ṻ' => 'ṻ', 'Ṽ' => 'Ṽ', 'ṽ' => 'ṽ', 'Ṿ' => 'Ṿ', 'ṿ' => 'ṿ', 'Ẁ' => 'Ẁ', 'ẁ' => 'ẁ', 'Ẃ' => 'Ẃ', 'ẃ' => 'ẃ', 'Ẅ' => 'Ẅ', 'ẅ' => 'ẅ', 'Ẇ' => 'Ẇ', 'ẇ' => 'ẇ', 'Ẉ' => 'Ẉ', 'ẉ' => 'ẉ', 'Ẋ' => 'Ẋ', 'ẋ' => 'ẋ', 'Ẍ' => 'Ẍ', 'ẍ' => 'ẍ', 'Ẏ' => 'Ẏ', 'ẏ' => 'ẏ', 'Ẑ' => 'Ẑ', 'ẑ' => 'ẑ', 'Ẓ' => 'Ẓ', 'ẓ' => 'ẓ', 'Ẕ' => 'Ẕ', 'ẕ' => 'ẕ', 'ẖ' => 'ẖ', 'ẗ' => 'ẗ', 'ẘ' => 'ẘ', 'ẙ' => 'ẙ', 'ẛ' => 'ẛ', 'Ạ' => 'Ạ', 'ạ' => 'ạ', 'Ả' => 'Ả', 'ả' => 'ả', 'Ấ' => 'Ấ', 'ấ' => 'ấ', 'Ầ' => 'Ầ', 'ầ' => 'ầ', 'Ẩ' => 'Ẩ', 'ẩ' => 'ẩ', 'Ẫ' => 'Ẫ', 'ẫ' => 'ẫ', 'Ậ' => 'Ậ', 'ậ' => 'ậ', 'Ắ' => 'Ắ', 'ắ' => 'ắ', 'Ằ' => 'Ằ', 'ằ' => 'ằ', 'Ẳ' => 'Ẳ', 'ẳ' => 'ẳ', 'Ẵ' => 'Ẵ', 'ẵ' => 'ẵ', 'Ặ' => 'Ặ', 'ặ' => 'ặ', 'Ẹ' => 'Ẹ', 'ẹ' => 'ẹ', 'Ẻ' => 'Ẻ', 'ẻ' => 'ẻ', 'Ẽ' => 'Ẽ', 'ẽ' => 'ẽ', 'Ế' => 'Ế', 'ế' => 'ế', 'Ề' => 'Ề', 'ề' => 'ề', 'Ể' => 'Ể', 'ể' => 'ể', 'Ễ' => 'Ễ', 'ễ' => 'ễ', 'Ệ' => 'Ệ', 'ệ' => 'ệ', 'Ỉ' => 'Ỉ', 'ỉ' => 'ỉ', 'Ị' => 'Ị', 'ị' => 'ị', 'Ọ' => 'Ọ', 'ọ' => 'ọ', 'Ỏ' => 'Ỏ', 'ỏ' => 'ỏ', 'Ố' => 'Ố', 'ố' => 'ố', 'Ồ' => 'Ồ', 'ồ' => 'ồ', 'Ổ' => 'Ổ', 'ổ' => 'ổ', 'Ỗ' => 'Ỗ', 'ỗ' => 'ỗ', 'Ộ' => 'Ộ', 'ộ' => 'ộ', 'Ớ' => 'Ớ', 'ớ' => 'ớ', 'Ờ' => 'Ờ', 'ờ' => 'ờ', 'Ở' => 'Ở', 'ở' => 'ở', 'Ỡ' => 'Ỡ', 'ỡ' => 'ỡ', 'Ợ' => 'Ợ', 'ợ' => 'ợ', 'Ụ' => 'Ụ', 'ụ' => 'ụ', 'Ủ' => 'Ủ', 'ủ' => 'ủ', 'Ứ' => 'Ứ', 'ứ' => 'ứ', 'Ừ' => 'Ừ', 'ừ' => 'ừ', 'Ử' => 'Ử', 'ử' => 'ử', 'Ữ' => 'Ữ', 'ữ' => 'ữ', 'Ự' => 'Ự', 'ự' => 'ự', 'Ỳ' => 'Ỳ', 'ỳ' => 'ỳ', 'Ỵ' => 'Ỵ', 'ỵ' => 'ỵ', 'Ỷ' => 'Ỷ', 'ỷ' => 'ỷ', 'Ỹ' => 'Ỹ', 'ỹ' => 'ỹ', 'ἀ' => 'ἀ', 'ἁ' => 'ἁ', 'ἂ' => 'ἂ', 'ἃ' => 'ἃ', 'ἄ' => 'ἄ', 'ἅ' => 'ἅ', 'ἆ' => 'ἆ', 'ἇ' => 'ἇ', 'Ἀ' => 'Ἀ', 'Ἁ' => 'Ἁ', 'Ἂ' => 'Ἂ', 'Ἃ' => 'Ἃ', 'Ἄ' => 'Ἄ', 'Ἅ' => 'Ἅ', 'Ἆ' => 'Ἆ', 'Ἇ' => 'Ἇ', 'ἐ' => 'ἐ', 'ἑ' => 'ἑ', 'ἒ' => 'ἒ', 'ἓ' => 'ἓ', 'ἔ' => 'ἔ', 'ἕ' => 'ἕ', 'Ἐ' => 'Ἐ', 'Ἑ' => 'Ἑ', 'Ἒ' => 'Ἒ', 'Ἓ' => 'Ἓ', 'Ἔ' => 'Ἔ', 'Ἕ' => 'Ἕ', 'ἠ' => 'ἠ', 'ἡ' => 'ἡ', 'ἢ' => 'ἢ', 'ἣ' => 'ἣ', 'ἤ' => 'ἤ', 'ἥ' => 'ἥ', 'ἦ' => 'ἦ', 'ἧ' => 'ἧ', 'Ἠ' => 'Ἠ', 'Ἡ' => 'Ἡ', 'Ἢ' => 'Ἢ', 'Ἣ' => 'Ἣ', 'Ἤ' => 'Ἤ', 'Ἥ' => 'Ἥ', 'Ἦ' => 'Ἦ', 'Ἧ' => 'Ἧ', 'ἰ' => 'ἰ', 'ἱ' => 'ἱ', 'ἲ' => 'ἲ', 'ἳ' => 'ἳ', 'ἴ' => 'ἴ', 'ἵ' => 'ἵ', 'ἶ' => 'ἶ', 'ἷ' => 'ἷ', 'Ἰ' => 'Ἰ', 'Ἱ' => 'Ἱ', 'Ἲ' => 'Ἲ', 'Ἳ' => 'Ἳ', 'Ἴ' => 'Ἴ', 'Ἵ' => 'Ἵ', 'Ἶ' => 'Ἶ', 'Ἷ' => 'Ἷ', 'ὀ' => 'ὀ', 'ὁ' => 'ὁ', 'ὂ' => 'ὂ', 'ὃ' => 'ὃ', 'ὄ' => 'ὄ', 'ὅ' => 'ὅ', 'Ὀ' => 'Ὀ', 'Ὁ' => 'Ὁ', 'Ὂ' => 'Ὂ', 'Ὃ' => 'Ὃ', 'Ὄ' => 'Ὄ', 'Ὅ' => 'Ὅ', 'ὐ' => 'ὐ', 'ὑ' => 'ὑ', 'ὒ' => 'ὒ', 'ὓ' => 'ὓ', 'ὔ' => 'ὔ', 'ὕ' => 'ὕ', 'ὖ' => 'ὖ', 'ὗ' => 'ὗ', 'Ὑ' => 'Ὑ', 'Ὓ' => 'Ὓ', 'Ὕ' => 'Ὕ', 'Ὗ' => 'Ὗ', 'ὠ' => 'ὠ', 'ὡ' => 'ὡ', 'ὢ' => 'ὢ', 'ὣ' => 'ὣ', 'ὤ' => 'ὤ', 'ὥ' => 'ὥ', 'ὦ' => 'ὦ', 'ὧ' => 'ὧ', 'Ὠ' => 'Ὠ', 'Ὡ' => 'Ὡ', 'Ὢ' => 'Ὢ', 'Ὣ' => 'Ὣ', 'Ὤ' => 'Ὤ', 'Ὥ' => 'Ὥ', 'Ὦ' => 'Ὦ', 'Ὧ' => 'Ὧ', 'ὰ' => 'ὰ', 'ὲ' => 'ὲ', 'ὴ' => 'ὴ', 'ὶ' => 'ὶ', 'ὸ' => 'ὸ', 'ὺ' => 'ὺ', 'ὼ' => 'ὼ', 'ᾀ' => 'ᾀ', 'ᾁ' => 'ᾁ', 'ᾂ' => 'ᾂ', 'ᾃ' => 'ᾃ', 'ᾄ' => 'ᾄ', 'ᾅ' => 'ᾅ', 'ᾆ' => 'ᾆ', 'ᾇ' => 'ᾇ', 'ᾈ' => 'ᾈ', 'ᾉ' => 'ᾉ', 'ᾊ' => 'ᾊ', 'ᾋ' => 'ᾋ', 'ᾌ' => 'ᾌ', 'ᾍ' => 'ᾍ', 'ᾎ' => 'ᾎ', 'ᾏ' => 'ᾏ', 'ᾐ' => 'ᾐ', 'ᾑ' => 'ᾑ', 'ᾒ' => 'ᾒ', 'ᾓ' => 'ᾓ', 'ᾔ' => 'ᾔ', 'ᾕ' => 'ᾕ', 'ᾖ' => 'ᾖ', 'ᾗ' => 'ᾗ', 'ᾘ' => 'ᾘ', 'ᾙ' => 'ᾙ', 'ᾚ' => 'ᾚ', 'ᾛ' => 'ᾛ', 'ᾜ' => 'ᾜ', 'ᾝ' => 'ᾝ', 'ᾞ' => 'ᾞ', 'ᾟ' => 'ᾟ', 'ᾠ' => 'ᾠ', 'ᾡ' => 'ᾡ', 'ᾢ' => 'ᾢ', 'ᾣ' => 'ᾣ', 'ᾤ' => 'ᾤ', 'ᾥ' => 'ᾥ', 'ᾦ' => 'ᾦ', 'ᾧ' => 'ᾧ', 'ᾨ' => 'ᾨ', 'ᾩ' => 'ᾩ', 'ᾪ' => 'ᾪ', 'ᾫ' => 'ᾫ', 'ᾬ' => 'ᾬ', 'ᾭ' => 'ᾭ', 'ᾮ' => 'ᾮ', 'ᾯ' => 'ᾯ', 'ᾰ' => 'ᾰ', 'ᾱ' => 'ᾱ', 'ᾲ' => 'ᾲ', 'ᾳ' => 'ᾳ', 'ᾴ' => 'ᾴ', 'ᾶ' => 'ᾶ', 'ᾷ' => 'ᾷ', 'Ᾰ' => 'Ᾰ', 'Ᾱ' => 'Ᾱ', 'Ὰ' => 'Ὰ', 'ᾼ' => 'ᾼ', '῁' => '῁', 'ῂ' => 'ῂ', 'ῃ' => 'ῃ', 'ῄ' => 'ῄ', 'ῆ' => 'ῆ', 'ῇ' => 'ῇ', 'Ὲ' => 'Ὲ', 'Ὴ' => 'Ὴ', 'ῌ' => 'ῌ', '῍' => '῍', '῎' => '῎', '῏' => '῏', 'ῐ' => 'ῐ', 'ῑ' => 'ῑ', 'ῒ' => 'ῒ', 'ῖ' => 'ῖ', 'ῗ' => 'ῗ', 'Ῐ' => 'Ῐ', 'Ῑ' => 'Ῑ', 'Ὶ' => 'Ὶ', '῝' => '῝', '῞' => '῞', '῟' => '῟', 'ῠ' => 'ῠ', 'ῡ' => 'ῡ', 'ῢ' => 'ῢ', 'ῤ' => 'ῤ', 'ῥ' => 'ῥ', 'ῦ' => 'ῦ', 'ῧ' => 'ῧ', 'Ῠ' => 'Ῠ', 'Ῡ' => 'Ῡ', 'Ὺ' => 'Ὺ', 'Ῥ' => 'Ῥ', '῭' => '῭', 'ῲ' => 'ῲ', 'ῳ' => 'ῳ', 'ῴ' => 'ῴ', 'ῶ' => 'ῶ', 'ῷ' => 'ῷ', 'Ὸ' => 'Ὸ', 'Ὼ' => 'Ὼ', 'ῼ' => 'ῼ', '↚' => '↚', '↛' => '↛', '↮' => '↮', '⇍' => '⇍', '⇎' => '⇎', '⇏' => '⇏', '∄' => '∄', '∉' => '∉', '∌' => '∌', '∤' => '∤', '∦' => '∦', '≁' => '≁', '≄' => '≄', '≇' => '≇', '≉' => '≉', '≠' => '≠', '≢' => '≢', '≭' => '≭', '≮' => '≮', '≯' => '≯', '≰' => '≰', '≱' => '≱', '≴' => '≴', '≵' => '≵', '≸' => '≸', '≹' => '≹', '⊀' => '⊀', '⊁' => '⊁', '⊄' => '⊄', '⊅' => '⊅', '⊈' => '⊈', '⊉' => '⊉', '⊬' => '⊬', '⊭' => '⊭', '⊮' => '⊮', '⊯' => '⊯', '⋠' => '⋠', '⋡' => '⋡', '⋢' => '⋢', '⋣' => '⋣', '⋪' => '⋪', '⋫' => '⋫', '⋬' => '⋬', '⋭' => '⋭', 'が' => 'が', 'ぎ' => 'ぎ', 'ぐ' => 'ぐ', 'げ' => 'げ', 'ご' => 'ご', 'ざ' => 'ざ', 'じ' => 'じ', 'ず' => 'ず', 'ぜ' => 'ぜ', 'ぞ' => 'ぞ', 'だ' => 'だ', 'ぢ' => 'ぢ', 'づ' => 'づ', 'で' => 'で', 'ど' => 'ど', 'ば' => 'ば', 'ぱ' => 'ぱ', 'び' => 'び', 'ぴ' => 'ぴ', 'ぶ' => 'ぶ', 'ぷ' => 'ぷ', 'べ' => 'べ', 'ぺ' => 'ぺ', 'ぼ' => 'ぼ', 'ぽ' => 'ぽ', 'ゔ' => 'ゔ', 'ゞ' => 'ゞ', 'ガ' => 'ガ', 'ギ' => 'ギ', 'グ' => 'グ', 'ゲ' => 'ゲ', 'ゴ' => 'ゴ', 'ザ' => 'ザ', 'ジ' => 'ジ', 'ズ' => 'ズ', 'ゼ' => 'ゼ', 'ゾ' => 'ゾ', 'ダ' => 'ダ', 'ヂ' => 'ヂ', 'ヅ' => 'ヅ', 'デ' => 'デ', 'ド' => 'ド', 'バ' => 'バ', 'パ' => 'パ', 'ビ' => 'ビ', 'ピ' => 'ピ', 'ブ' => 'ブ', 'プ' => 'プ', 'ベ' => 'ベ', 'ペ' => 'ペ', 'ボ' => 'ボ', 'ポ' => 'ポ', 'ヴ' => 'ヴ', 'ヷ' => 'ヷ', 'ヸ' => 'ヸ', 'ヹ' => 'ヹ', 'ヺ' => 'ヺ', 'ヾ' => 'ヾ', '𑂚' => '𑂚', '𑂜' => '𑂜', '𑂫' => '𑂫', '𑄮' => '𑄮', '𑄯' => '𑄯', '𑍋' => '𑍋', '𑍌' => '𑍌', '𑒻' => '𑒻', '𑒼' => '𑒼', '𑒾' => '𑒾', '𑖺' => '𑖺', '𑖻' => '𑖻', '𑤸' => '𑤸'); 230, '́' => 230, '̂' => 230, '̃' => 230, '̄' => 230, '̅' => 230, '̆' => 230, '̇' => 230, '̈' => 230, '̉' => 230, '̊' => 230, '̋' => 230, '̌' => 230, '̍' => 230, '̎' => 230, '̏' => 230, '̐' => 230, '̑' => 230, '̒' => 230, '̓' => 230, '̔' => 230, '̕' => 232, '̖' => 220, '̗' => 220, '̘' => 220, '̙' => 220, '̚' => 232, '̛' => 216, '̜' => 220, '̝' => 220, '̞' => 220, '̟' => 220, '̠' => 220, '̡' => 202, '̢' => 202, '̣' => 220, '̤' => 220, '̥' => 220, '̦' => 220, '̧' => 202, '̨' => 202, '̩' => 220, '̪' => 220, '̫' => 220, '̬' => 220, '̭' => 220, '̮' => 220, '̯' => 220, '̰' => 220, '̱' => 220, '̲' => 220, '̳' => 220, '̴' => 1, '̵' => 1, '̶' => 1, '̷' => 1, '̸' => 1, '̹' => 220, '̺' => 220, '̻' => 220, '̼' => 220, '̽' => 230, '̾' => 230, '̿' => 230, '̀' => 230, '́' => 230, '͂' => 230, '̓' => 230, '̈́' => 230, 'ͅ' => 240, '͆' => 230, '͇' => 220, '͈' => 220, '͉' => 220, '͊' => 230, '͋' => 230, '͌' => 230, '͍' => 220, '͎' => 220, '͐' => 230, '͑' => 230, '͒' => 230, '͓' => 220, '͔' => 220, '͕' => 220, '͖' => 220, '͗' => 230, '͘' => 232, '͙' => 220, '͚' => 220, '͛' => 230, '͜' => 233, '͝' => 234, '͞' => 234, '͟' => 233, '͠' => 234, '͡' => 234, '͢' => 233, 'ͣ' => 230, 'ͤ' => 230, 'ͥ' => 230, 'ͦ' => 230, 'ͧ' => 230, 'ͨ' => 230, 'ͩ' => 230, 'ͪ' => 230, 'ͫ' => 230, 'ͬ' => 230, 'ͭ' => 230, 'ͮ' => 230, 'ͯ' => 230, '҃' => 230, '҄' => 230, '҅' => 230, '҆' => 230, '҇' => 230, '֑' => 220, '֒' => 230, '֓' => 230, '֔' => 230, '֕' => 230, '֖' => 220, '֗' => 230, '֘' => 230, '֙' => 230, '֚' => 222, '֛' => 220, '֜' => 230, '֝' => 230, '֞' => 230, '֟' => 230, '֠' => 230, '֡' => 230, '֢' => 220, '֣' => 220, '֤' => 220, '֥' => 220, '֦' => 220, '֧' => 220, '֨' => 230, '֩' => 230, '֪' => 220, '֫' => 230, '֬' => 230, '֭' => 222, '֮' => 228, '֯' => 230, 'ְ' => 10, 'ֱ' => 11, 'ֲ' => 12, 'ֳ' => 13, 'ִ' => 14, 'ֵ' => 15, 'ֶ' => 16, 'ַ' => 17, 'ָ' => 18, 'ֹ' => 19, 'ֺ' => 19, 'ֻ' => 20, 'ּ' => 21, 'ֽ' => 22, 'ֿ' => 23, 'ׁ' => 24, 'ׂ' => 25, 'ׄ' => 230, 'ׅ' => 220, 'ׇ' => 18, 'ؐ' => 230, 'ؑ' => 230, 'ؒ' => 230, 'ؓ' => 230, 'ؔ' => 230, 'ؕ' => 230, 'ؖ' => 230, 'ؗ' => 230, 'ؘ' => 30, 'ؙ' => 31, 'ؚ' => 32, 'ً' => 27, 'ٌ' => 28, 'ٍ' => 29, 'َ' => 30, 'ُ' => 31, 'ِ' => 32, 'ّ' => 33, 'ْ' => 34, 'ٓ' => 230, 'ٔ' => 230, 'ٕ' => 220, 'ٖ' => 220, 'ٗ' => 230, '٘' => 230, 'ٙ' => 230, 'ٚ' => 230, 'ٛ' => 230, 'ٜ' => 220, 'ٝ' => 230, 'ٞ' => 230, 'ٟ' => 220, 'ٰ' => 35, 'ۖ' => 230, 'ۗ' => 230, 'ۘ' => 230, 'ۙ' => 230, 'ۚ' => 230, 'ۛ' => 230, 'ۜ' => 230, '۟' => 230, '۠' => 230, 'ۡ' => 230, 'ۢ' => 230, 'ۣ' => 220, 'ۤ' => 230, 'ۧ' => 230, 'ۨ' => 230, '۪' => 220, '۫' => 230, '۬' => 230, 'ۭ' => 220, 'ܑ' => 36, 'ܰ' => 230, 'ܱ' => 220, 'ܲ' => 230, 'ܳ' => 230, 'ܴ' => 220, 'ܵ' => 230, 'ܶ' => 230, 'ܷ' => 220, 'ܸ' => 220, 'ܹ' => 220, 'ܺ' => 230, 'ܻ' => 220, 'ܼ' => 220, 'ܽ' => 230, 'ܾ' => 220, 'ܿ' => 230, '݀' => 230, '݁' => 230, '݂' => 220, '݃' => 230, '݄' => 220, '݅' => 230, '݆' => 220, '݇' => 230, '݈' => 220, '݉' => 230, '݊' => 230, '߫' => 230, '߬' => 230, '߭' => 230, '߮' => 230, '߯' => 230, '߰' => 230, '߱' => 230, '߲' => 220, '߳' => 230, '߽' => 220, 'ࠖ' => 230, 'ࠗ' => 230, '࠘' => 230, '࠙' => 230, 'ࠛ' => 230, 'ࠜ' => 230, 'ࠝ' => 230, 'ࠞ' => 230, 'ࠟ' => 230, 'ࠠ' => 230, 'ࠡ' => 230, 'ࠢ' => 230, 'ࠣ' => 230, 'ࠥ' => 230, 'ࠦ' => 230, 'ࠧ' => 230, 'ࠩ' => 230, 'ࠪ' => 230, 'ࠫ' => 230, 'ࠬ' => 230, '࠭' => 230, '࡙' => 220, '࡚' => 220, '࡛' => 220, '࣓' => 220, 'ࣔ' => 230, 'ࣕ' => 230, 'ࣖ' => 230, 'ࣗ' => 230, 'ࣘ' => 230, 'ࣙ' => 230, 'ࣚ' => 230, 'ࣛ' => 230, 'ࣜ' => 230, 'ࣝ' => 230, 'ࣞ' => 230, 'ࣟ' => 230, '࣠' => 230, '࣡' => 230, 'ࣣ' => 220, 'ࣤ' => 230, 'ࣥ' => 230, 'ࣦ' => 220, 'ࣧ' => 230, 'ࣨ' => 230, 'ࣩ' => 220, '࣪' => 230, '࣫' => 230, '࣬' => 230, '࣭' => 220, '࣮' => 220, '࣯' => 220, 'ࣰ' => 27, 'ࣱ' => 28, 'ࣲ' => 29, 'ࣳ' => 230, 'ࣴ' => 230, 'ࣵ' => 230, 'ࣶ' => 220, 'ࣷ' => 230, 'ࣸ' => 230, 'ࣹ' => 220, 'ࣺ' => 220, 'ࣻ' => 230, 'ࣼ' => 230, 'ࣽ' => 230, 'ࣾ' => 230, 'ࣿ' => 230, '़' => 7, '्' => 9, '॑' => 230, '॒' => 220, '॓' => 230, '॔' => 230, '়' => 7, '্' => 9, '৾' => 230, '਼' => 7, '੍' => 9, '઼' => 7, '્' => 9, '଼' => 7, '୍' => 9, '்' => 9, '్' => 9, 'ౕ' => 84, 'ౖ' => 91, '಼' => 7, '್' => 9, '഻' => 9, '഼' => 9, '്' => 9, '්' => 9, 'ุ' => 103, 'ู' => 103, 'ฺ' => 9, '่' => 107, '้' => 107, '๊' => 107, '๋' => 107, 'ຸ' => 118, 'ູ' => 118, '຺' => 9, '່' => 122, '້' => 122, '໊' => 122, '໋' => 122, '༘' => 220, '༙' => 220, '༵' => 220, '༷' => 220, '༹' => 216, 'ཱ' => 129, 'ི' => 130, 'ུ' => 132, 'ེ' => 130, 'ཻ' => 130, 'ོ' => 130, 'ཽ' => 130, 'ྀ' => 130, 'ྂ' => 230, 'ྃ' => 230, '྄' => 9, '྆' => 230, '྇' => 230, '࿆' => 220, '့' => 7, '္' => 9, '်' => 9, 'ႍ' => 220, '፝' => 230, '፞' => 230, '፟' => 230, '᜔' => 9, '᜴' => 9, '្' => 9, '៝' => 230, 'ᢩ' => 228, '᤹' => 222, '᤺' => 230, '᤻' => 220, 'ᨗ' => 230, 'ᨘ' => 220, '᩠' => 9, '᩵' => 230, '᩶' => 230, '᩷' => 230, '᩸' => 230, '᩹' => 230, '᩺' => 230, '᩻' => 230, '᩼' => 230, '᩿' => 220, '᪰' => 230, '᪱' => 230, '᪲' => 230, '᪳' => 230, '᪴' => 230, '᪵' => 220, '᪶' => 220, '᪷' => 220, '᪸' => 220, '᪹' => 220, '᪺' => 220, '᪻' => 230, '᪼' => 230, '᪽' => 220, 'ᪿ' => 220, 'ᫀ' => 220, '᬴' => 7, '᭄' => 9, '᭫' => 230, '᭬' => 220, '᭭' => 230, '᭮' => 230, '᭯' => 230, '᭰' => 230, '᭱' => 230, '᭲' => 230, '᭳' => 230, '᮪' => 9, '᮫' => 9, '᯦' => 7, '᯲' => 9, '᯳' => 9, '᰷' => 7, '᳐' => 230, '᳑' => 230, '᳒' => 230, '᳔' => 1, '᳕' => 220, '᳖' => 220, '᳗' => 220, '᳘' => 220, '᳙' => 220, '᳚' => 230, '᳛' => 230, '᳜' => 220, '᳝' => 220, '᳞' => 220, '᳟' => 220, '᳠' => 230, '᳢' => 1, '᳣' => 1, '᳤' => 1, '᳥' => 1, '᳦' => 1, '᳧' => 1, '᳨' => 1, '᳭' => 220, '᳴' => 230, '᳸' => 230, '᳹' => 230, '᷀' => 230, '᷁' => 230, '᷂' => 220, '᷃' => 230, '᷄' => 230, '᷅' => 230, '᷆' => 230, '᷇' => 230, '᷈' => 230, '᷉' => 230, '᷊' => 220, '᷋' => 230, '᷌' => 230, '᷍' => 234, '᷎' => 214, '᷏' => 220, '᷐' => 202, '᷑' => 230, '᷒' => 230, 'ᷓ' => 230, 'ᷔ' => 230, 'ᷕ' => 230, 'ᷖ' => 230, 'ᷗ' => 230, 'ᷘ' => 230, 'ᷙ' => 230, 'ᷚ' => 230, 'ᷛ' => 230, 'ᷜ' => 230, 'ᷝ' => 230, 'ᷞ' => 230, 'ᷟ' => 230, 'ᷠ' => 230, 'ᷡ' => 230, 'ᷢ' => 230, 'ᷣ' => 230, 'ᷤ' => 230, 'ᷥ' => 230, 'ᷦ' => 230, 'ᷧ' => 230, 'ᷨ' => 230, 'ᷩ' => 230, 'ᷪ' => 230, 'ᷫ' => 230, 'ᷬ' => 230, 'ᷭ' => 230, 'ᷮ' => 230, 'ᷯ' => 230, 'ᷰ' => 230, 'ᷱ' => 230, 'ᷲ' => 230, 'ᷳ' => 230, 'ᷴ' => 230, '᷵' => 230, '᷶' => 232, '᷷' => 228, '᷸' => 228, '᷹' => 220, '᷻' => 230, '᷼' => 233, '᷽' => 220, '᷾' => 230, '᷿' => 220, '⃐' => 230, '⃑' => 230, '⃒' => 1, '⃓' => 1, '⃔' => 230, '⃕' => 230, '⃖' => 230, '⃗' => 230, '⃘' => 1, '⃙' => 1, '⃚' => 1, '⃛' => 230, '⃜' => 230, '⃡' => 230, '⃥' => 1, '⃦' => 1, '⃧' => 230, '⃨' => 220, '⃩' => 230, '⃪' => 1, '⃫' => 1, '⃬' => 220, '⃭' => 220, '⃮' => 220, '⃯' => 220, '⃰' => 230, '⳯' => 230, '⳰' => 230, '⳱' => 230, '⵿' => 9, 'ⷠ' => 230, 'ⷡ' => 230, 'ⷢ' => 230, 'ⷣ' => 230, 'ⷤ' => 230, 'ⷥ' => 230, 'ⷦ' => 230, 'ⷧ' => 230, 'ⷨ' => 230, 'ⷩ' => 230, 'ⷪ' => 230, 'ⷫ' => 230, 'ⷬ' => 230, 'ⷭ' => 230, 'ⷮ' => 230, 'ⷯ' => 230, 'ⷰ' => 230, 'ⷱ' => 230, 'ⷲ' => 230, 'ⷳ' => 230, 'ⷴ' => 230, 'ⷵ' => 230, 'ⷶ' => 230, 'ⷷ' => 230, 'ⷸ' => 230, 'ⷹ' => 230, 'ⷺ' => 230, 'ⷻ' => 230, 'ⷼ' => 230, 'ⷽ' => 230, 'ⷾ' => 230, 'ⷿ' => 230, '〪' => 218, '〫' => 228, '〬' => 232, '〭' => 222, '〮' => 224, '〯' => 224, '゙' => 8, '゚' => 8, '꙯' => 230, 'ꙴ' => 230, 'ꙵ' => 230, 'ꙶ' => 230, 'ꙷ' => 230, 'ꙸ' => 230, 'ꙹ' => 230, 'ꙺ' => 230, 'ꙻ' => 230, '꙼' => 230, '꙽' => 230, 'ꚞ' => 230, 'ꚟ' => 230, '꛰' => 230, '꛱' => 230, '꠆' => 9, '꠬' => 9, '꣄' => 9, '꣠' => 230, '꣡' => 230, '꣢' => 230, '꣣' => 230, '꣤' => 230, '꣥' => 230, '꣦' => 230, '꣧' => 230, '꣨' => 230, '꣩' => 230, '꣪' => 230, '꣫' => 230, '꣬' => 230, '꣭' => 230, '꣮' => 230, '꣯' => 230, '꣰' => 230, '꣱' => 230, '꤫' => 220, '꤬' => 220, '꤭' => 220, '꥓' => 9, '꦳' => 7, '꧀' => 9, 'ꪰ' => 230, 'ꪲ' => 230, 'ꪳ' => 230, 'ꪴ' => 220, 'ꪷ' => 230, 'ꪸ' => 230, 'ꪾ' => 230, '꪿' => 230, '꫁' => 230, '꫶' => 9, '꯭' => 9, 'ﬞ' => 26, '︠' => 230, '︡' => 230, '︢' => 230, '︣' => 230, '︤' => 230, '︥' => 230, '︦' => 230, '︧' => 220, '︨' => 220, '︩' => 220, '︪' => 220, '︫' => 220, '︬' => 220, '︭' => 220, '︮' => 230, '︯' => 230, '𐇽' => 220, '𐋠' => 220, '𐍶' => 230, '𐍷' => 230, '𐍸' => 230, '𐍹' => 230, '𐍺' => 230, '𐨍' => 220, '𐨏' => 230, '𐨸' => 230, '𐨹' => 1, '𐨺' => 220, '𐨿' => 9, '𐫥' => 230, '𐫦' => 220, '𐴤' => 230, '𐴥' => 230, '𐴦' => 230, '𐴧' => 230, '𐺫' => 230, '𐺬' => 230, '𐽆' => 220, '𐽇' => 220, '𐽈' => 230, '𐽉' => 230, '𐽊' => 230, '𐽋' => 220, '𐽌' => 230, '𐽍' => 220, '𐽎' => 220, '𐽏' => 220, '𐽐' => 220, '𑁆' => 9, '𑁿' => 9, '𑂹' => 9, '𑂺' => 7, '𑄀' => 230, '𑄁' => 230, '𑄂' => 230, '𑄳' => 9, '𑄴' => 9, '𑅳' => 7, '𑇀' => 9, '𑇊' => 7, '𑈵' => 9, '𑈶' => 7, '𑋩' => 7, '𑋪' => 9, '𑌻' => 7, '𑌼' => 7, '𑍍' => 9, '𑍦' => 230, '𑍧' => 230, '𑍨' => 230, '𑍩' => 230, '𑍪' => 230, '𑍫' => 230, '𑍬' => 230, '𑍰' => 230, '𑍱' => 230, '𑍲' => 230, '𑍳' => 230, '𑍴' => 230, '𑑂' => 9, '𑑆' => 7, '𑑞' => 230, '𑓂' => 9, '𑓃' => 7, '𑖿' => 9, '𑗀' => 7, '𑘿' => 9, '𑚶' => 9, '𑚷' => 7, '𑜫' => 9, '𑠹' => 9, '𑠺' => 7, '𑤽' => 9, '𑤾' => 9, '𑥃' => 7, '𑧠' => 9, '𑨴' => 9, '𑩇' => 9, '𑪙' => 9, '𑰿' => 9, '𑵂' => 7, '𑵄' => 9, '𑵅' => 9, '𑶗' => 9, '𖫰' => 1, '𖫱' => 1, '𖫲' => 1, '𖫳' => 1, '𖫴' => 1, '𖬰' => 230, '𖬱' => 230, '𖬲' => 230, '𖬳' => 230, '𖬴' => 230, '𖬵' => 230, '𖬶' => 230, '𖿰' => 6, '𖿱' => 6, '𛲞' => 1, '𝅥' => 216, '𝅦' => 216, '𝅧' => 1, '𝅨' => 1, '𝅩' => 1, '𝅭' => 226, '𝅮' => 216, '𝅯' => 216, '𝅰' => 216, '𝅱' => 216, '𝅲' => 216, '𝅻' => 220, '𝅼' => 220, '𝅽' => 220, '𝅾' => 220, '𝅿' => 220, '𝆀' => 220, '𝆁' => 220, '𝆂' => 220, '𝆅' => 230, '𝆆' => 230, '𝆇' => 230, '𝆈' => 230, '𝆉' => 230, '𝆊' => 220, '𝆋' => 220, '𝆪' => 230, '𝆫' => 230, '𝆬' => 230, '𝆭' => 230, '𝉂' => 230, '𝉃' => 230, '𝉄' => 230, '𞀀' => 230, '𞀁' => 230, '𞀂' => 230, '𞀃' => 230, '𞀄' => 230, '𞀅' => 230, '𞀆' => 230, '𞀈' => 230, '𞀉' => 230, '𞀊' => 230, '𞀋' => 230, '𞀌' => 230, '𞀍' => 230, '𞀎' => 230, '𞀏' => 230, '𞀐' => 230, '𞀑' => 230, '𞀒' => 230, '𞀓' => 230, '𞀔' => 230, '𞀕' => 230, '𞀖' => 230, '𞀗' => 230, '𞀘' => 230, '𞀛' => 230, '𞀜' => 230, '𞀝' => 230, '𞀞' => 230, '𞀟' => 230, '𞀠' => 230, '𞀡' => 230, '𞀣' => 230, '𞀤' => 230, '𞀦' => 230, '𞀧' => 230, '𞀨' => 230, '𞀩' => 230, '𞀪' => 230, '𞄰' => 230, '𞄱' => 230, '𞄲' => 230, '𞄳' => 230, '𞄴' => 230, '𞄵' => 230, '𞄶' => 230, '𞋬' => 230, '𞋭' => 230, '𞋮' => 230, '𞋯' => 230, '𞣐' => 220, '𞣑' => 220, '𞣒' => 220, '𞣓' => 220, '𞣔' => 220, '𞣕' => 220, '𞣖' => 220, '𞥄' => 230, '𞥅' => 230, '𞥆' => 230, '𞥇' => 230, '𞥈' => 230, '𞥉' => 230, '𞥊' => 7); 'À', 'Á' => 'Á', 'Â' => 'Â', 'Ã' => 'Ã', 'Ä' => 'Ä', 'Å' => 'Å', 'Ç' => 'Ç', 'È' => 'È', 'É' => 'É', 'Ê' => 'Ê', 'Ë' => 'Ë', 'Ì' => 'Ì', 'Í' => 'Í', 'Î' => 'Î', 'Ï' => 'Ï', 'Ñ' => 'Ñ', 'Ò' => 'Ò', 'Ó' => 'Ó', 'Ô' => 'Ô', 'Õ' => 'Õ', 'Ö' => 'Ö', 'Ù' => 'Ù', 'Ú' => 'Ú', 'Û' => 'Û', 'Ü' => 'Ü', 'Ý' => 'Ý', 'à' => 'à', 'á' => 'á', 'â' => 'â', 'ã' => 'ã', 'ä' => 'ä', 'å' => 'å', 'ç' => 'ç', 'è' => 'è', 'é' => 'é', 'ê' => 'ê', 'ë' => 'ë', 'ì' => 'ì', 'í' => 'í', 'î' => 'î', 'ï' => 'ï', 'ñ' => 'ñ', 'ò' => 'ò', 'ó' => 'ó', 'ô' => 'ô', 'õ' => 'õ', 'ö' => 'ö', 'ù' => 'ù', 'ú' => 'ú', 'û' => 'û', 'ü' => 'ü', 'ý' => 'ý', 'ÿ' => 'ÿ', 'Ā' => 'Ā', 'ā' => 'ā', 'Ă' => 'Ă', 'ă' => 'ă', 'Ą' => 'Ą', 'ą' => 'ą', 'Ć' => 'Ć', 'ć' => 'ć', 'Ĉ' => 'Ĉ', 'ĉ' => 'ĉ', 'Ċ' => 'Ċ', 'ċ' => 'ċ', 'Č' => 'Č', 'č' => 'č', 'Ď' => 'Ď', 'ď' => 'ď', 'Ē' => 'Ē', 'ē' => 'ē', 'Ĕ' => 'Ĕ', 'ĕ' => 'ĕ', 'Ė' => 'Ė', 'ė' => 'ė', 'Ę' => 'Ę', 'ę' => 'ę', 'Ě' => 'Ě', 'ě' => 'ě', 'Ĝ' => 'Ĝ', 'ĝ' => 'ĝ', 'Ğ' => 'Ğ', 'ğ' => 'ğ', 'Ġ' => 'Ġ', 'ġ' => 'ġ', 'Ģ' => 'Ģ', 'ģ' => 'ģ', 'Ĥ' => 'Ĥ', 'ĥ' => 'ĥ', 'Ĩ' => 'Ĩ', 'ĩ' => 'ĩ', 'Ī' => 'Ī', 'ī' => 'ī', 'Ĭ' => 'Ĭ', 'ĭ' => 'ĭ', 'Į' => 'Į', 'į' => 'į', 'İ' => 'İ', 'Ĵ' => 'Ĵ', 'ĵ' => 'ĵ', 'Ķ' => 'Ķ', 'ķ' => 'ķ', 'Ĺ' => 'Ĺ', 'ĺ' => 'ĺ', 'Ļ' => 'Ļ', 'ļ' => 'ļ', 'Ľ' => 'Ľ', 'ľ' => 'ľ', 'Ń' => 'Ń', 'ń' => 'ń', 'Ņ' => 'Ņ', 'ņ' => 'ņ', 'Ň' => 'Ň', 'ň' => 'ň', 'Ō' => 'Ō', 'ō' => 'ō', 'Ŏ' => 'Ŏ', 'ŏ' => 'ŏ', 'Ő' => 'Ő', 'ő' => 'ő', 'Ŕ' => 'Ŕ', 'ŕ' => 'ŕ', 'Ŗ' => 'Ŗ', 'ŗ' => 'ŗ', 'Ř' => 'Ř', 'ř' => 'ř', 'Ś' => 'Ś', 'ś' => 'ś', 'Ŝ' => 'Ŝ', 'ŝ' => 'ŝ', 'Ş' => 'Ş', 'ş' => 'ş', 'Š' => 'Š', 'š' => 'š', 'Ţ' => 'Ţ', 'ţ' => 'ţ', 'Ť' => 'Ť', 'ť' => 'ť', 'Ũ' => 'Ũ', 'ũ' => 'ũ', 'Ū' => 'Ū', 'ū' => 'ū', 'Ŭ' => 'Ŭ', 'ŭ' => 'ŭ', 'Ů' => 'Ů', 'ů' => 'ů', 'Ű' => 'Ű', 'ű' => 'ű', 'Ų' => 'Ų', 'ų' => 'ų', 'Ŵ' => 'Ŵ', 'ŵ' => 'ŵ', 'Ŷ' => 'Ŷ', 'ŷ' => 'ŷ', 'Ÿ' => 'Ÿ', 'Ź' => 'Ź', 'ź' => 'ź', 'Ż' => 'Ż', 'ż' => 'ż', 'Ž' => 'Ž', 'ž' => 'ž', 'Ơ' => 'Ơ', 'ơ' => 'ơ', 'Ư' => 'Ư', 'ư' => 'ư', 'Ǎ' => 'Ǎ', 'ǎ' => 'ǎ', 'Ǐ' => 'Ǐ', 'ǐ' => 'ǐ', 'Ǒ' => 'Ǒ', 'ǒ' => 'ǒ', 'Ǔ' => 'Ǔ', 'ǔ' => 'ǔ', 'Ǖ' => 'Ǖ', 'ǖ' => 'ǖ', 'Ǘ' => 'Ǘ', 'ǘ' => 'ǘ', 'Ǚ' => 'Ǚ', 'ǚ' => 'ǚ', 'Ǜ' => 'Ǜ', 'ǜ' => 'ǜ', 'Ǟ' => 'Ǟ', 'ǟ' => 'ǟ', 'Ǡ' => 'Ǡ', 'ǡ' => 'ǡ', 'Ǣ' => 'Ǣ', 'ǣ' => 'ǣ', 'Ǧ' => 'Ǧ', 'ǧ' => 'ǧ', 'Ǩ' => 'Ǩ', 'ǩ' => 'ǩ', 'Ǫ' => 'Ǫ', 'ǫ' => 'ǫ', 'Ǭ' => 'Ǭ', 'ǭ' => 'ǭ', 'Ǯ' => 'Ǯ', 'ǯ' => 'ǯ', 'ǰ' => 'ǰ', 'Ǵ' => 'Ǵ', 'ǵ' => 'ǵ', 'Ǹ' => 'Ǹ', 'ǹ' => 'ǹ', 'Ǻ' => 'Ǻ', 'ǻ' => 'ǻ', 'Ǽ' => 'Ǽ', 'ǽ' => 'ǽ', 'Ǿ' => 'Ǿ', 'ǿ' => 'ǿ', 'Ȁ' => 'Ȁ', 'ȁ' => 'ȁ', 'Ȃ' => 'Ȃ', 'ȃ' => 'ȃ', 'Ȅ' => 'Ȅ', 'ȅ' => 'ȅ', 'Ȇ' => 'Ȇ', 'ȇ' => 'ȇ', 'Ȉ' => 'Ȉ', 'ȉ' => 'ȉ', 'Ȋ' => 'Ȋ', 'ȋ' => 'ȋ', 'Ȍ' => 'Ȍ', 'ȍ' => 'ȍ', 'Ȏ' => 'Ȏ', 'ȏ' => 'ȏ', 'Ȑ' => 'Ȑ', 'ȑ' => 'ȑ', 'Ȓ' => 'Ȓ', 'ȓ' => 'ȓ', 'Ȕ' => 'Ȕ', 'ȕ' => 'ȕ', 'Ȗ' => 'Ȗ', 'ȗ' => 'ȗ', 'Ș' => 'Ș', 'ș' => 'ș', 'Ț' => 'Ț', 'ț' => 'ț', 'Ȟ' => 'Ȟ', 'ȟ' => 'ȟ', 'Ȧ' => 'Ȧ', 'ȧ' => 'ȧ', 'Ȩ' => 'Ȩ', 'ȩ' => 'ȩ', 'Ȫ' => 'Ȫ', 'ȫ' => 'ȫ', 'Ȭ' => 'Ȭ', 'ȭ' => 'ȭ', 'Ȯ' => 'Ȯ', 'ȯ' => 'ȯ', 'Ȱ' => 'Ȱ', 'ȱ' => 'ȱ', 'Ȳ' => 'Ȳ', 'ȳ' => 'ȳ', '̀' => '̀', '́' => '́', '̓' => '̓', '̈́' => '̈́', 'ʹ' => 'ʹ', ';' => ';', '΅' => '΅', 'Ά' => 'Ά', '·' => '·', 'Έ' => 'Έ', 'Ή' => 'Ή', 'Ί' => 'Ί', 'Ό' => 'Ό', 'Ύ' => 'Ύ', 'Ώ' => 'Ώ', 'ΐ' => 'ΐ', 'Ϊ' => 'Ϊ', 'Ϋ' => 'Ϋ', 'ά' => 'ά', 'έ' => 'έ', 'ή' => 'ή', 'ί' => 'ί', 'ΰ' => 'ΰ', 'ϊ' => 'ϊ', 'ϋ' => 'ϋ', 'ό' => 'ό', 'ύ' => 'ύ', 'ώ' => 'ώ', 'ϓ' => 'ϓ', 'ϔ' => 'ϔ', 'Ѐ' => 'Ѐ', 'Ё' => 'Ё', 'Ѓ' => 'Ѓ', 'Ї' => 'Ї', 'Ќ' => 'Ќ', 'Ѝ' => 'Ѝ', 'Ў' => 'Ў', 'Й' => 'Й', 'й' => 'й', 'ѐ' => 'ѐ', 'ё' => 'ё', 'ѓ' => 'ѓ', 'ї' => 'ї', 'ќ' => 'ќ', 'ѝ' => 'ѝ', 'ў' => 'ў', 'Ѷ' => 'Ѷ', 'ѷ' => 'ѷ', 'Ӂ' => 'Ӂ', 'ӂ' => 'ӂ', 'Ӑ' => 'Ӑ', 'ӑ' => 'ӑ', 'Ӓ' => 'Ӓ', 'ӓ' => 'ӓ', 'Ӗ' => 'Ӗ', 'ӗ' => 'ӗ', 'Ӛ' => 'Ӛ', 'ӛ' => 'ӛ', 'Ӝ' => 'Ӝ', 'ӝ' => 'ӝ', 'Ӟ' => 'Ӟ', 'ӟ' => 'ӟ', 'Ӣ' => 'Ӣ', 'ӣ' => 'ӣ', 'Ӥ' => 'Ӥ', 'ӥ' => 'ӥ', 'Ӧ' => 'Ӧ', 'ӧ' => 'ӧ', 'Ӫ' => 'Ӫ', 'ӫ' => 'ӫ', 'Ӭ' => 'Ӭ', 'ӭ' => 'ӭ', 'Ӯ' => 'Ӯ', 'ӯ' => 'ӯ', 'Ӱ' => 'Ӱ', 'ӱ' => 'ӱ', 'Ӳ' => 'Ӳ', 'ӳ' => 'ӳ', 'Ӵ' => 'Ӵ', 'ӵ' => 'ӵ', 'Ӹ' => 'Ӹ', 'ӹ' => 'ӹ', 'آ' => 'آ', 'أ' => 'أ', 'ؤ' => 'ؤ', 'إ' => 'إ', 'ئ' => 'ئ', 'ۀ' => 'ۀ', 'ۂ' => 'ۂ', 'ۓ' => 'ۓ', 'ऩ' => 'ऩ', 'ऱ' => 'ऱ', 'ऴ' => 'ऴ', 'क़' => 'क़', 'ख़' => 'ख़', 'ग़' => 'ग़', 'ज़' => 'ज़', 'ड़' => 'ड़', 'ढ़' => 'ढ़', 'फ़' => 'फ़', 'य़' => 'य़', 'ো' => 'ো', 'ৌ' => 'ৌ', 'ড়' => 'ড়', 'ঢ়' => 'ঢ়', 'য়' => 'য়', 'ਲ਼' => 'ਲ਼', 'ਸ਼' => 'ਸ਼', 'ਖ਼' => 'ਖ਼', 'ਗ਼' => 'ਗ਼', 'ਜ਼' => 'ਜ਼', 'ਫ਼' => 'ਫ਼', 'ୈ' => 'ୈ', 'ୋ' => 'ୋ', 'ୌ' => 'ୌ', 'ଡ଼' => 'ଡ଼', 'ଢ଼' => 'ଢ଼', 'ஔ' => 'ஔ', 'ொ' => 'ொ', 'ோ' => 'ோ', 'ௌ' => 'ௌ', 'ై' => 'ై', 'ೀ' => 'ೀ', 'ೇ' => 'ೇ', 'ೈ' => 'ೈ', 'ೊ' => 'ೊ', 'ೋ' => 'ೋ', 'ൊ' => 'ൊ', 'ോ' => 'ോ', 'ൌ' => 'ൌ', 'ේ' => 'ේ', 'ො' => 'ො', 'ෝ' => 'ෝ', 'ෞ' => 'ෞ', 'གྷ' => 'གྷ', 'ཌྷ' => 'ཌྷ', 'དྷ' => 'དྷ', 'བྷ' => 'བྷ', 'ཛྷ' => 'ཛྷ', 'ཀྵ' => 'ཀྵ', 'ཱི' => 'ཱི', 'ཱུ' => 'ཱུ', 'ྲྀ' => 'ྲྀ', 'ླྀ' => 'ླྀ', 'ཱྀ' => 'ཱྀ', 'ྒྷ' => 'ྒྷ', 'ྜྷ' => 'ྜྷ', 'ྡྷ' => 'ྡྷ', 'ྦྷ' => 'ྦྷ', 'ྫྷ' => 'ྫྷ', 'ྐྵ' => 'ྐྵ', 'ဦ' => 'ဦ', 'ᬆ' => 'ᬆ', 'ᬈ' => 'ᬈ', 'ᬊ' => 'ᬊ', 'ᬌ' => 'ᬌ', 'ᬎ' => 'ᬎ', 'ᬒ' => 'ᬒ', 'ᬻ' => 'ᬻ', 'ᬽ' => 'ᬽ', 'ᭀ' => 'ᭀ', 'ᭁ' => 'ᭁ', 'ᭃ' => 'ᭃ', 'Ḁ' => 'Ḁ', 'ḁ' => 'ḁ', 'Ḃ' => 'Ḃ', 'ḃ' => 'ḃ', 'Ḅ' => 'Ḅ', 'ḅ' => 'ḅ', 'Ḇ' => 'Ḇ', 'ḇ' => 'ḇ', 'Ḉ' => 'Ḉ', 'ḉ' => 'ḉ', 'Ḋ' => 'Ḋ', 'ḋ' => 'ḋ', 'Ḍ' => 'Ḍ', 'ḍ' => 'ḍ', 'Ḏ' => 'Ḏ', 'ḏ' => 'ḏ', 'Ḑ' => 'Ḑ', 'ḑ' => 'ḑ', 'Ḓ' => 'Ḓ', 'ḓ' => 'ḓ', 'Ḕ' => 'Ḕ', 'ḕ' => 'ḕ', 'Ḗ' => 'Ḗ', 'ḗ' => 'ḗ', 'Ḙ' => 'Ḙ', 'ḙ' => 'ḙ', 'Ḛ' => 'Ḛ', 'ḛ' => 'ḛ', 'Ḝ' => 'Ḝ', 'ḝ' => 'ḝ', 'Ḟ' => 'Ḟ', 'ḟ' => 'ḟ', 'Ḡ' => 'Ḡ', 'ḡ' => 'ḡ', 'Ḣ' => 'Ḣ', 'ḣ' => 'ḣ', 'Ḥ' => 'Ḥ', 'ḥ' => 'ḥ', 'Ḧ' => 'Ḧ', 'ḧ' => 'ḧ', 'Ḩ' => 'Ḩ', 'ḩ' => 'ḩ', 'Ḫ' => 'Ḫ', 'ḫ' => 'ḫ', 'Ḭ' => 'Ḭ', 'ḭ' => 'ḭ', 'Ḯ' => 'Ḯ', 'ḯ' => 'ḯ', 'Ḱ' => 'Ḱ', 'ḱ' => 'ḱ', 'Ḳ' => 'Ḳ', 'ḳ' => 'ḳ', 'Ḵ' => 'Ḵ', 'ḵ' => 'ḵ', 'Ḷ' => 'Ḷ', 'ḷ' => 'ḷ', 'Ḹ' => 'Ḹ', 'ḹ' => 'ḹ', 'Ḻ' => 'Ḻ', 'ḻ' => 'ḻ', 'Ḽ' => 'Ḽ', 'ḽ' => 'ḽ', 'Ḿ' => 'Ḿ', 'ḿ' => 'ḿ', 'Ṁ' => 'Ṁ', 'ṁ' => 'ṁ', 'Ṃ' => 'Ṃ', 'ṃ' => 'ṃ', 'Ṅ' => 'Ṅ', 'ṅ' => 'ṅ', 'Ṇ' => 'Ṇ', 'ṇ' => 'ṇ', 'Ṉ' => 'Ṉ', 'ṉ' => 'ṉ', 'Ṋ' => 'Ṋ', 'ṋ' => 'ṋ', 'Ṍ' => 'Ṍ', 'ṍ' => 'ṍ', 'Ṏ' => 'Ṏ', 'ṏ' => 'ṏ', 'Ṑ' => 'Ṑ', 'ṑ' => 'ṑ', 'Ṓ' => 'Ṓ', 'ṓ' => 'ṓ', 'Ṕ' => 'Ṕ', 'ṕ' => 'ṕ', 'Ṗ' => 'Ṗ', 'ṗ' => 'ṗ', 'Ṙ' => 'Ṙ', 'ṙ' => 'ṙ', 'Ṛ' => 'Ṛ', 'ṛ' => 'ṛ', 'Ṝ' => 'Ṝ', 'ṝ' => 'ṝ', 'Ṟ' => 'Ṟ', 'ṟ' => 'ṟ', 'Ṡ' => 'Ṡ', 'ṡ' => 'ṡ', 'Ṣ' => 'Ṣ', 'ṣ' => 'ṣ', 'Ṥ' => 'Ṥ', 'ṥ' => 'ṥ', 'Ṧ' => 'Ṧ', 'ṧ' => 'ṧ', 'Ṩ' => 'Ṩ', 'ṩ' => 'ṩ', 'Ṫ' => 'Ṫ', 'ṫ' => 'ṫ', 'Ṭ' => 'Ṭ', 'ṭ' => 'ṭ', 'Ṯ' => 'Ṯ', 'ṯ' => 'ṯ', 'Ṱ' => 'Ṱ', 'ṱ' => 'ṱ', 'Ṳ' => 'Ṳ', 'ṳ' => 'ṳ', 'Ṵ' => 'Ṵ', 'ṵ' => 'ṵ', 'Ṷ' => 'Ṷ', 'ṷ' => 'ṷ', 'Ṹ' => 'Ṹ', 'ṹ' => 'ṹ', 'Ṻ' => 'Ṻ', 'ṻ' => 'ṻ', 'Ṽ' => 'Ṽ', 'ṽ' => 'ṽ', 'Ṿ' => 'Ṿ', 'ṿ' => 'ṿ', 'Ẁ' => 'Ẁ', 'ẁ' => 'ẁ', 'Ẃ' => 'Ẃ', 'ẃ' => 'ẃ', 'Ẅ' => 'Ẅ', 'ẅ' => 'ẅ', 'Ẇ' => 'Ẇ', 'ẇ' => 'ẇ', 'Ẉ' => 'Ẉ', 'ẉ' => 'ẉ', 'Ẋ' => 'Ẋ', 'ẋ' => 'ẋ', 'Ẍ' => 'Ẍ', 'ẍ' => 'ẍ', 'Ẏ' => 'Ẏ', 'ẏ' => 'ẏ', 'Ẑ' => 'Ẑ', 'ẑ' => 'ẑ', 'Ẓ' => 'Ẓ', 'ẓ' => 'ẓ', 'Ẕ' => 'Ẕ', 'ẕ' => 'ẕ', 'ẖ' => 'ẖ', 'ẗ' => 'ẗ', 'ẘ' => 'ẘ', 'ẙ' => 'ẙ', 'ẛ' => 'ẛ', 'Ạ' => 'Ạ', 'ạ' => 'ạ', 'Ả' => 'Ả', 'ả' => 'ả', 'Ấ' => 'Ấ', 'ấ' => 'ấ', 'Ầ' => 'Ầ', 'ầ' => 'ầ', 'Ẩ' => 'Ẩ', 'ẩ' => 'ẩ', 'Ẫ' => 'Ẫ', 'ẫ' => 'ẫ', 'Ậ' => 'Ậ', 'ậ' => 'ậ', 'Ắ' => 'Ắ', 'ắ' => 'ắ', 'Ằ' => 'Ằ', 'ằ' => 'ằ', 'Ẳ' => 'Ẳ', 'ẳ' => 'ẳ', 'Ẵ' => 'Ẵ', 'ẵ' => 'ẵ', 'Ặ' => 'Ặ', 'ặ' => 'ặ', 'Ẹ' => 'Ẹ', 'ẹ' => 'ẹ', 'Ẻ' => 'Ẻ', 'ẻ' => 'ẻ', 'Ẽ' => 'Ẽ', 'ẽ' => 'ẽ', 'Ế' => 'Ế', 'ế' => 'ế', 'Ề' => 'Ề', 'ề' => 'ề', 'Ể' => 'Ể', 'ể' => 'ể', 'Ễ' => 'Ễ', 'ễ' => 'ễ', 'Ệ' => 'Ệ', 'ệ' => 'ệ', 'Ỉ' => 'Ỉ', 'ỉ' => 'ỉ', 'Ị' => 'Ị', 'ị' => 'ị', 'Ọ' => 'Ọ', 'ọ' => 'ọ', 'Ỏ' => 'Ỏ', 'ỏ' => 'ỏ', 'Ố' => 'Ố', 'ố' => 'ố', 'Ồ' => 'Ồ', 'ồ' => 'ồ', 'Ổ' => 'Ổ', 'ổ' => 'ổ', 'Ỗ' => 'Ỗ', 'ỗ' => 'ỗ', 'Ộ' => 'Ộ', 'ộ' => 'ộ', 'Ớ' => 'Ớ', 'ớ' => 'ớ', 'Ờ' => 'Ờ', 'ờ' => 'ờ', 'Ở' => 'Ở', 'ở' => 'ở', 'Ỡ' => 'Ỡ', 'ỡ' => 'ỡ', 'Ợ' => 'Ợ', 'ợ' => 'ợ', 'Ụ' => 'Ụ', 'ụ' => 'ụ', 'Ủ' => 'Ủ', 'ủ' => 'ủ', 'Ứ' => 'Ứ', 'ứ' => 'ứ', 'Ừ' => 'Ừ', 'ừ' => 'ừ', 'Ử' => 'Ử', 'ử' => 'ử', 'Ữ' => 'Ữ', 'ữ' => 'ữ', 'Ự' => 'Ự', 'ự' => 'ự', 'Ỳ' => 'Ỳ', 'ỳ' => 'ỳ', 'Ỵ' => 'Ỵ', 'ỵ' => 'ỵ', 'Ỷ' => 'Ỷ', 'ỷ' => 'ỷ', 'Ỹ' => 'Ỹ', 'ỹ' => 'ỹ', 'ἀ' => 'ἀ', 'ἁ' => 'ἁ', 'ἂ' => 'ἂ', 'ἃ' => 'ἃ', 'ἄ' => 'ἄ', 'ἅ' => 'ἅ', 'ἆ' => 'ἆ', 'ἇ' => 'ἇ', 'Ἀ' => 'Ἀ', 'Ἁ' => 'Ἁ', 'Ἂ' => 'Ἂ', 'Ἃ' => 'Ἃ', 'Ἄ' => 'Ἄ', 'Ἅ' => 'Ἅ', 'Ἆ' => 'Ἆ', 'Ἇ' => 'Ἇ', 'ἐ' => 'ἐ', 'ἑ' => 'ἑ', 'ἒ' => 'ἒ', 'ἓ' => 'ἓ', 'ἔ' => 'ἔ', 'ἕ' => 'ἕ', 'Ἐ' => 'Ἐ', 'Ἑ' => 'Ἑ', 'Ἒ' => 'Ἒ', 'Ἓ' => 'Ἓ', 'Ἔ' => 'Ἔ', 'Ἕ' => 'Ἕ', 'ἠ' => 'ἠ', 'ἡ' => 'ἡ', 'ἢ' => 'ἢ', 'ἣ' => 'ἣ', 'ἤ' => 'ἤ', 'ἥ' => 'ἥ', 'ἦ' => 'ἦ', 'ἧ' => 'ἧ', 'Ἠ' => 'Ἠ', 'Ἡ' => 'Ἡ', 'Ἢ' => 'Ἢ', 'Ἣ' => 'Ἣ', 'Ἤ' => 'Ἤ', 'Ἥ' => 'Ἥ', 'Ἦ' => 'Ἦ', 'Ἧ' => 'Ἧ', 'ἰ' => 'ἰ', 'ἱ' => 'ἱ', 'ἲ' => 'ἲ', 'ἳ' => 'ἳ', 'ἴ' => 'ἴ', 'ἵ' => 'ἵ', 'ἶ' => 'ἶ', 'ἷ' => 'ἷ', 'Ἰ' => 'Ἰ', 'Ἱ' => 'Ἱ', 'Ἲ' => 'Ἲ', 'Ἳ' => 'Ἳ', 'Ἴ' => 'Ἴ', 'Ἵ' => 'Ἵ', 'Ἶ' => 'Ἶ', 'Ἷ' => 'Ἷ', 'ὀ' => 'ὀ', 'ὁ' => 'ὁ', 'ὂ' => 'ὂ', 'ὃ' => 'ὃ', 'ὄ' => 'ὄ', 'ὅ' => 'ὅ', 'Ὀ' => 'Ὀ', 'Ὁ' => 'Ὁ', 'Ὂ' => 'Ὂ', 'Ὃ' => 'Ὃ', 'Ὄ' => 'Ὄ', 'Ὅ' => 'Ὅ', 'ὐ' => 'ὐ', 'ὑ' => 'ὑ', 'ὒ' => 'ὒ', 'ὓ' => 'ὓ', 'ὔ' => 'ὔ', 'ὕ' => 'ὕ', 'ὖ' => 'ὖ', 'ὗ' => 'ὗ', 'Ὑ' => 'Ὑ', 'Ὓ' => 'Ὓ', 'Ὕ' => 'Ὕ', 'Ὗ' => 'Ὗ', 'ὠ' => 'ὠ', 'ὡ' => 'ὡ', 'ὢ' => 'ὢ', 'ὣ' => 'ὣ', 'ὤ' => 'ὤ', 'ὥ' => 'ὥ', 'ὦ' => 'ὦ', 'ὧ' => 'ὧ', 'Ὠ' => 'Ὠ', 'Ὡ' => 'Ὡ', 'Ὢ' => 'Ὢ', 'Ὣ' => 'Ὣ', 'Ὤ' => 'Ὤ', 'Ὥ' => 'Ὥ', 'Ὦ' => 'Ὦ', 'Ὧ' => 'Ὧ', 'ὰ' => 'ὰ', 'ά' => 'ά', 'ὲ' => 'ὲ', 'έ' => 'έ', 'ὴ' => 'ὴ', 'ή' => 'ή', 'ὶ' => 'ὶ', 'ί' => 'ί', 'ὸ' => 'ὸ', 'ό' => 'ό', 'ὺ' => 'ὺ', 'ύ' => 'ύ', 'ὼ' => 'ὼ', 'ώ' => 'ώ', 'ᾀ' => 'ᾀ', 'ᾁ' => 'ᾁ', 'ᾂ' => 'ᾂ', 'ᾃ' => 'ᾃ', 'ᾄ' => 'ᾄ', 'ᾅ' => 'ᾅ', 'ᾆ' => 'ᾆ', 'ᾇ' => 'ᾇ', 'ᾈ' => 'ᾈ', 'ᾉ' => 'ᾉ', 'ᾊ' => 'ᾊ', 'ᾋ' => 'ᾋ', 'ᾌ' => 'ᾌ', 'ᾍ' => 'ᾍ', 'ᾎ' => 'ᾎ', 'ᾏ' => 'ᾏ', 'ᾐ' => 'ᾐ', 'ᾑ' => 'ᾑ', 'ᾒ' => 'ᾒ', 'ᾓ' => 'ᾓ', 'ᾔ' => 'ᾔ', 'ᾕ' => 'ᾕ', 'ᾖ' => 'ᾖ', 'ᾗ' => 'ᾗ', 'ᾘ' => 'ᾘ', 'ᾙ' => 'ᾙ', 'ᾚ' => 'ᾚ', 'ᾛ' => 'ᾛ', 'ᾜ' => 'ᾜ', 'ᾝ' => 'ᾝ', 'ᾞ' => 'ᾞ', 'ᾟ' => 'ᾟ', 'ᾠ' => 'ᾠ', 'ᾡ' => 'ᾡ', 'ᾢ' => 'ᾢ', 'ᾣ' => 'ᾣ', 'ᾤ' => 'ᾤ', 'ᾥ' => 'ᾥ', 'ᾦ' => 'ᾦ', 'ᾧ' => 'ᾧ', 'ᾨ' => 'ᾨ', 'ᾩ' => 'ᾩ', 'ᾪ' => 'ᾪ', 'ᾫ' => 'ᾫ', 'ᾬ' => 'ᾬ', 'ᾭ' => 'ᾭ', 'ᾮ' => 'ᾮ', 'ᾯ' => 'ᾯ', 'ᾰ' => 'ᾰ', 'ᾱ' => 'ᾱ', 'ᾲ' => 'ᾲ', 'ᾳ' => 'ᾳ', 'ᾴ' => 'ᾴ', 'ᾶ' => 'ᾶ', 'ᾷ' => 'ᾷ', 'Ᾰ' => 'Ᾰ', 'Ᾱ' => 'Ᾱ', 'Ὰ' => 'Ὰ', 'Ά' => 'Ά', 'ᾼ' => 'ᾼ', 'ι' => 'ι', '῁' => '῁', 'ῂ' => 'ῂ', 'ῃ' => 'ῃ', 'ῄ' => 'ῄ', 'ῆ' => 'ῆ', 'ῇ' => 'ῇ', 'Ὲ' => 'Ὲ', 'Έ' => 'Έ', 'Ὴ' => 'Ὴ', 'Ή' => 'Ή', 'ῌ' => 'ῌ', '῍' => '῍', '῎' => '῎', '῏' => '῏', 'ῐ' => 'ῐ', 'ῑ' => 'ῑ', 'ῒ' => 'ῒ', 'ΐ' => 'ΐ', 'ῖ' => 'ῖ', 'ῗ' => 'ῗ', 'Ῐ' => 'Ῐ', 'Ῑ' => 'Ῑ', 'Ὶ' => 'Ὶ', 'Ί' => 'Ί', '῝' => '῝', '῞' => '῞', '῟' => '῟', 'ῠ' => 'ῠ', 'ῡ' => 'ῡ', 'ῢ' => 'ῢ', 'ΰ' => 'ΰ', 'ῤ' => 'ῤ', 'ῥ' => 'ῥ', 'ῦ' => 'ῦ', 'ῧ' => 'ῧ', 'Ῠ' => 'Ῠ', 'Ῡ' => 'Ῡ', 'Ὺ' => 'Ὺ', 'Ύ' => 'Ύ', 'Ῥ' => 'Ῥ', '῭' => '῭', '΅' => '΅', '`' => '`', 'ῲ' => 'ῲ', 'ῳ' => 'ῳ', 'ῴ' => 'ῴ', 'ῶ' => 'ῶ', 'ῷ' => 'ῷ', 'Ὸ' => 'Ὸ', 'Ό' => 'Ό', 'Ὼ' => 'Ὼ', 'Ώ' => 'Ώ', 'ῼ' => 'ῼ', '´' => '´', ' ' => ' ', ' ' => ' ', 'Ω' => 'Ω', 'K' => 'K', 'Å' => 'Å', '↚' => '↚', '↛' => '↛', '↮' => '↮', '⇍' => '⇍', '⇎' => '⇎', '⇏' => '⇏', '∄' => '∄', '∉' => '∉', '∌' => '∌', '∤' => '∤', '∦' => '∦', '≁' => '≁', '≄' => '≄', '≇' => '≇', '≉' => '≉', '≠' => '≠', '≢' => '≢', '≭' => '≭', '≮' => '≮', '≯' => '≯', '≰' => '≰', '≱' => '≱', '≴' => '≴', '≵' => '≵', '≸' => '≸', '≹' => '≹', '⊀' => '⊀', '⊁' => '⊁', '⊄' => '⊄', '⊅' => '⊅', '⊈' => '⊈', '⊉' => '⊉', '⊬' => '⊬', '⊭' => '⊭', '⊮' => '⊮', '⊯' => '⊯', '⋠' => '⋠', '⋡' => '⋡', '⋢' => '⋢', '⋣' => '⋣', '⋪' => '⋪', '⋫' => '⋫', '⋬' => '⋬', '⋭' => '⋭', '〈' => '〈', '〉' => '〉', '⫝̸' => '⫝̸', 'が' => 'が', 'ぎ' => 'ぎ', 'ぐ' => 'ぐ', 'げ' => 'げ', 'ご' => 'ご', 'ざ' => 'ざ', 'じ' => 'じ', 'ず' => 'ず', 'ぜ' => 'ぜ', 'ぞ' => 'ぞ', 'だ' => 'だ', 'ぢ' => 'ぢ', 'づ' => 'づ', 'で' => 'で', 'ど' => 'ど', 'ば' => 'ば', 'ぱ' => 'ぱ', 'び' => 'び', 'ぴ' => 'ぴ', 'ぶ' => 'ぶ', 'ぷ' => 'ぷ', 'べ' => 'べ', 'ぺ' => 'ぺ', 'ぼ' => 'ぼ', 'ぽ' => 'ぽ', 'ゔ' => 'ゔ', 'ゞ' => 'ゞ', 'ガ' => 'ガ', 'ギ' => 'ギ', 'グ' => 'グ', 'ゲ' => 'ゲ', 'ゴ' => 'ゴ', 'ザ' => 'ザ', 'ジ' => 'ジ', 'ズ' => 'ズ', 'ゼ' => 'ゼ', 'ゾ' => 'ゾ', 'ダ' => 'ダ', 'ヂ' => 'ヂ', 'ヅ' => 'ヅ', 'デ' => 'デ', 'ド' => 'ド', 'バ' => 'バ', 'パ' => 'パ', 'ビ' => 'ビ', 'ピ' => 'ピ', 'ブ' => 'ブ', 'プ' => 'プ', 'ベ' => 'ベ', 'ペ' => 'ペ', 'ボ' => 'ボ', 'ポ' => 'ポ', 'ヴ' => 'ヴ', 'ヷ' => 'ヷ', 'ヸ' => 'ヸ', 'ヹ' => 'ヹ', 'ヺ' => 'ヺ', 'ヾ' => 'ヾ', '豈' => '豈', '更' => '更', '車' => '車', '賈' => '賈', '滑' => '滑', '串' => '串', '句' => '句', '龜' => '龜', '龜' => '龜', '契' => '契', '金' => '金', '喇' => '喇', '奈' => '奈', '懶' => '懶', '癩' => '癩', '羅' => '羅', '蘿' => '蘿', '螺' => '螺', '裸' => '裸', '邏' => '邏', '樂' => '樂', '洛' => '洛', '烙' => '烙', '珞' => '珞', '落' => '落', '酪' => '酪', '駱' => '駱', '亂' => '亂', '卵' => '卵', '欄' => '欄', '爛' => '爛', '蘭' => '蘭', '鸞' => '鸞', '嵐' => '嵐', '濫' => '濫', '藍' => '藍', '襤' => '襤', '拉' => '拉', '臘' => '臘', '蠟' => '蠟', '廊' => '廊', '朗' => '朗', '浪' => '浪', '狼' => '狼', '郎' => '郎', '來' => '來', '冷' => '冷', '勞' => '勞', '擄' => '擄', '櫓' => '櫓', '爐' => '爐', '盧' => '盧', '老' => '老', '蘆' => '蘆', '虜' => '虜', '路' => '路', '露' => '露', '魯' => '魯', '鷺' => '鷺', '碌' => '碌', '祿' => '祿', '綠' => '綠', '菉' => '菉', '錄' => '錄', '鹿' => '鹿', '論' => '論', '壟' => '壟', '弄' => '弄', '籠' => '籠', '聾' => '聾', '牢' => '牢', '磊' => '磊', '賂' => '賂', '雷' => '雷', '壘' => '壘', '屢' => '屢', '樓' => '樓', '淚' => '淚', '漏' => '漏', '累' => '累', '縷' => '縷', '陋' => '陋', '勒' => '勒', '肋' => '肋', '凜' => '凜', '凌' => '凌', '稜' => '稜', '綾' => '綾', '菱' => '菱', '陵' => '陵', '讀' => '讀', '拏' => '拏', '樂' => '樂', '諾' => '諾', '丹' => '丹', '寧' => '寧', '怒' => '怒', '率' => '率', '異' => '異', '北' => '北', '磻' => '磻', '便' => '便', '復' => '復', '不' => '不', '泌' => '泌', '數' => '數', '索' => '索', '參' => '參', '塞' => '塞', '省' => '省', '葉' => '葉', '說' => '說', '殺' => '殺', '辰' => '辰', '沈' => '沈', '拾' => '拾', '若' => '若', '掠' => '掠', '略' => '略', '亮' => '亮', '兩' => '兩', '凉' => '凉', '梁' => '梁', '糧' => '糧', '良' => '良', '諒' => '諒', '量' => '量', '勵' => '勵', '呂' => '呂', '女' => '女', '廬' => '廬', '旅' => '旅', '濾' => '濾', '礪' => '礪', '閭' => '閭', '驪' => '驪', '麗' => '麗', '黎' => '黎', '力' => '力', '曆' => '曆', '歷' => '歷', '轢' => '轢', '年' => '年', '憐' => '憐', '戀' => '戀', '撚' => '撚', '漣' => '漣', '煉' => '煉', '璉' => '璉', '秊' => '秊', '練' => '練', '聯' => '聯', '輦' => '輦', '蓮' => '蓮', '連' => '連', '鍊' => '鍊', '列' => '列', '劣' => '劣', '咽' => '咽', '烈' => '烈', '裂' => '裂', '說' => '說', '廉' => '廉', '念' => '念', '捻' => '捻', '殮' => '殮', '簾' => '簾', '獵' => '獵', '令' => '令', '囹' => '囹', '寧' => '寧', '嶺' => '嶺', '怜' => '怜', '玲' => '玲', '瑩' => '瑩', '羚' => '羚', '聆' => '聆', '鈴' => '鈴', '零' => '零', '靈' => '靈', '領' => '領', '例' => '例', '禮' => '禮', '醴' => '醴', '隸' => '隸', '惡' => '惡', '了' => '了', '僚' => '僚', '寮' => '寮', '尿' => '尿', '料' => '料', '樂' => '樂', '燎' => '燎', '療' => '療', '蓼' => '蓼', '遼' => '遼', '龍' => '龍', '暈' => '暈', '阮' => '阮', '劉' => '劉', '杻' => '杻', '柳' => '柳', '流' => '流', '溜' => '溜', '琉' => '琉', '留' => '留', '硫' => '硫', '紐' => '紐', '類' => '類', '六' => '六', '戮' => '戮', '陸' => '陸', '倫' => '倫', '崙' => '崙', '淪' => '淪', '輪' => '輪', '律' => '律', '慄' => '慄', '栗' => '栗', '率' => '率', '隆' => '隆', '利' => '利', '吏' => '吏', '履' => '履', '易' => '易', '李' => '李', '梨' => '梨', '泥' => '泥', '理' => '理', '痢' => '痢', '罹' => '罹', '裏' => '裏', '裡' => '裡', '里' => '里', '離' => '離', '匿' => '匿', '溺' => '溺', '吝' => '吝', '燐' => '燐', '璘' => '璘', '藺' => '藺', '隣' => '隣', '鱗' => '鱗', '麟' => '麟', '林' => '林', '淋' => '淋', '臨' => '臨', '立' => '立', '笠' => '笠', '粒' => '粒', '狀' => '狀', '炙' => '炙', '識' => '識', '什' => '什', '茶' => '茶', '刺' => '刺', '切' => '切', '度' => '度', '拓' => '拓', '糖' => '糖', '宅' => '宅', '洞' => '洞', '暴' => '暴', '輻' => '輻', '行' => '行', '降' => '降', '見' => '見', '廓' => '廓', '兀' => '兀', '嗀' => '嗀', '塚' => '塚', '晴' => '晴', '凞' => '凞', '猪' => '猪', '益' => '益', '礼' => '礼', '神' => '神', '祥' => '祥', '福' => '福', '靖' => '靖', '精' => '精', '羽' => '羽', '蘒' => '蘒', '諸' => '諸', '逸' => '逸', '都' => '都', '飯' => '飯', '飼' => '飼', '館' => '館', '鶴' => '鶴', '郞' => '郞', '隷' => '隷', '侮' => '侮', '僧' => '僧', '免' => '免', '勉' => '勉', '勤' => '勤', '卑' => '卑', '喝' => '喝', '嘆' => '嘆', '器' => '器', '塀' => '塀', '墨' => '墨', '層' => '層', '屮' => '屮', '悔' => '悔', '慨' => '慨', '憎' => '憎', '懲' => '懲', '敏' => '敏', '既' => '既', '暑' => '暑', '梅' => '梅', '海' => '海', '渚' => '渚', '漢' => '漢', '煮' => '煮', '爫' => '爫', '琢' => '琢', '碑' => '碑', '社' => '社', '祉' => '祉', '祈' => '祈', '祐' => '祐', '祖' => '祖', '祝' => '祝', '禍' => '禍', '禎' => '禎', '穀' => '穀', '突' => '突', '節' => '節', '練' => '練', '縉' => '縉', '繁' => '繁', '署' => '署', '者' => '者', '臭' => '臭', '艹' => '艹', '艹' => '艹', '著' => '著', '褐' => '褐', '視' => '視', '謁' => '謁', '謹' => '謹', '賓' => '賓', '贈' => '贈', '辶' => '辶', '逸' => '逸', '難' => '難', '響' => '響', '頻' => '頻', '恵' => '恵', '𤋮' => '𤋮', '舘' => '舘', '並' => '並', '况' => '况', '全' => '全', '侀' => '侀', '充' => '充', '冀' => '冀', '勇' => '勇', '勺' => '勺', '喝' => '喝', '啕' => '啕', '喙' => '喙', '嗢' => '嗢', '塚' => '塚', '墳' => '墳', '奄' => '奄', '奔' => '奔', '婢' => '婢', '嬨' => '嬨', '廒' => '廒', '廙' => '廙', '彩' => '彩', '徭' => '徭', '惘' => '惘', '慎' => '慎', '愈' => '愈', '憎' => '憎', '慠' => '慠', '懲' => '懲', '戴' => '戴', '揄' => '揄', '搜' => '搜', '摒' => '摒', '敖' => '敖', '晴' => '晴', '朗' => '朗', '望' => '望', '杖' => '杖', '歹' => '歹', '殺' => '殺', '流' => '流', '滛' => '滛', '滋' => '滋', '漢' => '漢', '瀞' => '瀞', '煮' => '煮', '瞧' => '瞧', '爵' => '爵', '犯' => '犯', '猪' => '猪', '瑱' => '瑱', '甆' => '甆', '画' => '画', '瘝' => '瘝', '瘟' => '瘟', '益' => '益', '盛' => '盛', '直' => '直', '睊' => '睊', '着' => '着', '磌' => '磌', '窱' => '窱', '節' => '節', '类' => '类', '絛' => '絛', '練' => '練', '缾' => '缾', '者' => '者', '荒' => '荒', '華' => '華', '蝹' => '蝹', '襁' => '襁', '覆' => '覆', '視' => '視', '調' => '調', '諸' => '諸', '請' => '請', '謁' => '謁', '諾' => '諾', '諭' => '諭', '謹' => '謹', '變' => '變', '贈' => '贈', '輸' => '輸', '遲' => '遲', '醙' => '醙', '鉶' => '鉶', '陼' => '陼', '難' => '難', '靖' => '靖', '韛' => '韛', '響' => '響', '頋' => '頋', '頻' => '頻', '鬒' => '鬒', '龜' => '龜', '𢡊' => '𢡊', '𢡄' => '𢡄', '𣏕' => '𣏕', '㮝' => '㮝', '䀘' => '䀘', '䀹' => '䀹', '𥉉' => '𥉉', '𥳐' => '𥳐', '𧻓' => '𧻓', '齃' => '齃', '龎' => '龎', 'יִ' => 'יִ', 'ײַ' => 'ײַ', 'שׁ' => 'שׁ', 'שׂ' => 'שׂ', 'שּׁ' => 'שּׁ', 'שּׂ' => 'שּׂ', 'אַ' => 'אַ', 'אָ' => 'אָ', 'אּ' => 'אּ', 'בּ' => 'בּ', 'גּ' => 'גּ', 'דּ' => 'דּ', 'הּ' => 'הּ', 'וּ' => 'וּ', 'זּ' => 'זּ', 'טּ' => 'טּ', 'יּ' => 'יּ', 'ךּ' => 'ךּ', 'כּ' => 'כּ', 'לּ' => 'לּ', 'מּ' => 'מּ', 'נּ' => 'נּ', 'סּ' => 'סּ', 'ףּ' => 'ףּ', 'פּ' => 'פּ', 'צּ' => 'צּ', 'קּ' => 'קּ', 'רּ' => 'רּ', 'שּ' => 'שּ', 'תּ' => 'תּ', 'וֹ' => 'וֹ', 'בֿ' => 'בֿ', 'כֿ' => 'כֿ', 'פֿ' => 'פֿ', '𑂚' => '𑂚', '𑂜' => '𑂜', '𑂫' => '𑂫', '𑄮' => '𑄮', '𑄯' => '𑄯', '𑍋' => '𑍋', '𑍌' => '𑍌', '𑒻' => '𑒻', '𑒼' => '𑒼', '𑒾' => '𑒾', '𑖺' => '𑖺', '𑖻' => '𑖻', '𑤸' => '𑤸', '𝅗𝅥' => '𝅗𝅥', '𝅘𝅥' => '𝅘𝅥', '𝅘𝅥𝅮' => '𝅘𝅥𝅮', '𝅘𝅥𝅯' => '𝅘𝅥𝅯', '𝅘𝅥𝅰' => '𝅘𝅥𝅰', '𝅘𝅥𝅱' => '𝅘𝅥𝅱', '𝅘𝅥𝅲' => '𝅘𝅥𝅲', '𝆹𝅥' => '𝆹𝅥', '𝆺𝅥' => '𝆺𝅥', '𝆹𝅥𝅮' => '𝆹𝅥𝅮', '𝆺𝅥𝅮' => '𝆺𝅥𝅮', '𝆹𝅥𝅯' => '𝆹𝅥𝅯', '𝆺𝅥𝅯' => '𝆺𝅥𝅯', '丽' => '丽', '丸' => '丸', '乁' => '乁', '𠄢' => '𠄢', '你' => '你', '侮' => '侮', '侻' => '侻', '倂' => '倂', '偺' => '偺', '備' => '備', '僧' => '僧', '像' => '像', '㒞' => '㒞', '𠘺' => '𠘺', '免' => '免', '兔' => '兔', '兤' => '兤', '具' => '具', '𠔜' => '𠔜', '㒹' => '㒹', '內' => '內', '再' => '再', '𠕋' => '𠕋', '冗' => '冗', '冤' => '冤', '仌' => '仌', '冬' => '冬', '况' => '况', '𩇟' => '𩇟', '凵' => '凵', '刃' => '刃', '㓟' => '㓟', '刻' => '刻', '剆' => '剆', '割' => '割', '剷' => '剷', '㔕' => '㔕', '勇' => '勇', '勉' => '勉', '勤' => '勤', '勺' => '勺', '包' => '包', '匆' => '匆', '北' => '北', '卉' => '卉', '卑' => '卑', '博' => '博', '即' => '即', '卽' => '卽', '卿' => '卿', '卿' => '卿', '卿' => '卿', '𠨬' => '𠨬', '灰' => '灰', '及' => '及', '叟' => '叟', '𠭣' => '𠭣', '叫' => '叫', '叱' => '叱', '吆' => '吆', '咞' => '咞', '吸' => '吸', '呈' => '呈', '周' => '周', '咢' => '咢', '哶' => '哶', '唐' => '唐', '啓' => '啓', '啣' => '啣', '善' => '善', '善' => '善', '喙' => '喙', '喫' => '喫', '喳' => '喳', '嗂' => '嗂', '圖' => '圖', '嘆' => '嘆', '圗' => '圗', '噑' => '噑', '噴' => '噴', '切' => '切', '壮' => '壮', '城' => '城', '埴' => '埴', '堍' => '堍', '型' => '型', '堲' => '堲', '報' => '報', '墬' => '墬', '𡓤' => '𡓤', '売' => '売', '壷' => '壷', '夆' => '夆', '多' => '多', '夢' => '夢', '奢' => '奢', '𡚨' => '𡚨', '𡛪' => '𡛪', '姬' => '姬', '娛' => '娛', '娧' => '娧', '姘' => '姘', '婦' => '婦', '㛮' => '㛮', '㛼' => '㛼', '嬈' => '嬈', '嬾' => '嬾', '嬾' => '嬾', '𡧈' => '𡧈', '寃' => '寃', '寘' => '寘', '寧' => '寧', '寳' => '寳', '𡬘' => '𡬘', '寿' => '寿', '将' => '将', '当' => '当', '尢' => '尢', '㞁' => '㞁', '屠' => '屠', '屮' => '屮', '峀' => '峀', '岍' => '岍', '𡷤' => '𡷤', '嵃' => '嵃', '𡷦' => '𡷦', '嵮' => '嵮', '嵫' => '嵫', '嵼' => '嵼', '巡' => '巡', '巢' => '巢', '㠯' => '㠯', '巽' => '巽', '帨' => '帨', '帽' => '帽', '幩' => '幩', '㡢' => '㡢', '𢆃' => '𢆃', '㡼' => '㡼', '庰' => '庰', '庳' => '庳', '庶' => '庶', '廊' => '廊', '𪎒' => '𪎒', '廾' => '廾', '𢌱' => '𢌱', '𢌱' => '𢌱', '舁' => '舁', '弢' => '弢', '弢' => '弢', '㣇' => '㣇', '𣊸' => '𣊸', '𦇚' => '𦇚', '形' => '形', '彫' => '彫', '㣣' => '㣣', '徚' => '徚', '忍' => '忍', '志' => '志', '忹' => '忹', '悁' => '悁', '㤺' => '㤺', '㤜' => '㤜', '悔' => '悔', '𢛔' => '𢛔', '惇' => '惇', '慈' => '慈', '慌' => '慌', '慎' => '慎', '慌' => '慌', '慺' => '慺', '憎' => '憎', '憲' => '憲', '憤' => '憤', '憯' => '憯', '懞' => '懞', '懲' => '懲', '懶' => '懶', '成' => '成', '戛' => '戛', '扝' => '扝', '抱' => '抱', '拔' => '拔', '捐' => '捐', '𢬌' => '𢬌', '挽' => '挽', '拼' => '拼', '捨' => '捨', '掃' => '掃', '揤' => '揤', '𢯱' => '𢯱', '搢' => '搢', '揅' => '揅', '掩' => '掩', '㨮' => '㨮', '摩' => '摩', '摾' => '摾', '撝' => '撝', '摷' => '摷', '㩬' => '㩬', '敏' => '敏', '敬' => '敬', '𣀊' => '𣀊', '旣' => '旣', '書' => '書', '晉' => '晉', '㬙' => '㬙', '暑' => '暑', '㬈' => '㬈', '㫤' => '㫤', '冒' => '冒', '冕' => '冕', '最' => '最', '暜' => '暜', '肭' => '肭', '䏙' => '䏙', '朗' => '朗', '望' => '望', '朡' => '朡', '杞' => '杞', '杓' => '杓', '𣏃' => '𣏃', '㭉' => '㭉', '柺' => '柺', '枅' => '枅', '桒' => '桒', '梅' => '梅', '𣑭' => '𣑭', '梎' => '梎', '栟' => '栟', '椔' => '椔', '㮝' => '㮝', '楂' => '楂', '榣' => '榣', '槪' => '槪', '檨' => '檨', '𣚣' => '𣚣', '櫛' => '櫛', '㰘' => '㰘', '次' => '次', '𣢧' => '𣢧', '歔' => '歔', '㱎' => '㱎', '歲' => '歲', '殟' => '殟', '殺' => '殺', '殻' => '殻', '𣪍' => '𣪍', '𡴋' => '𡴋', '𣫺' => '𣫺', '汎' => '汎', '𣲼' => '𣲼', '沿' => '沿', '泍' => '泍', '汧' => '汧', '洖' => '洖', '派' => '派', '海' => '海', '流' => '流', '浩' => '浩', '浸' => '浸', '涅' => '涅', '𣴞' => '𣴞', '洴' => '洴', '港' => '港', '湮' => '湮', '㴳' => '㴳', '滋' => '滋', '滇' => '滇', '𣻑' => '𣻑', '淹' => '淹', '潮' => '潮', '𣽞' => '𣽞', '𣾎' => '𣾎', '濆' => '濆', '瀹' => '瀹', '瀞' => '瀞', '瀛' => '瀛', '㶖' => '㶖', '灊' => '灊', '災' => '災', '灷' => '灷', '炭' => '炭', '𠔥' => '𠔥', '煅' => '煅', '𤉣' => '𤉣', '熜' => '熜', '𤎫' => '𤎫', '爨' => '爨', '爵' => '爵', '牐' => '牐', '𤘈' => '𤘈', '犀' => '犀', '犕' => '犕', '𤜵' => '𤜵', '𤠔' => '𤠔', '獺' => '獺', '王' => '王', '㺬' => '㺬', '玥' => '玥', '㺸' => '㺸', '㺸' => '㺸', '瑇' => '瑇', '瑜' => '瑜', '瑱' => '瑱', '璅' => '璅', '瓊' => '瓊', '㼛' => '㼛', '甤' => '甤', '𤰶' => '𤰶', '甾' => '甾', '𤲒' => '𤲒', '異' => '異', '𢆟' => '𢆟', '瘐' => '瘐', '𤾡' => '𤾡', '𤾸' => '𤾸', '𥁄' => '𥁄', '㿼' => '㿼', '䀈' => '䀈', '直' => '直', '𥃳' => '𥃳', '𥃲' => '𥃲', '𥄙' => '𥄙', '𥄳' => '𥄳', '眞' => '眞', '真' => '真', '真' => '真', '睊' => '睊', '䀹' => '䀹', '瞋' => '瞋', '䁆' => '䁆', '䂖' => '䂖', '𥐝' => '𥐝', '硎' => '硎', '碌' => '碌', '磌' => '磌', '䃣' => '䃣', '𥘦' => '𥘦', '祖' => '祖', '𥚚' => '𥚚', '𥛅' => '𥛅', '福' => '福', '秫' => '秫', '䄯' => '䄯', '穀' => '穀', '穊' => '穊', '穏' => '穏', '𥥼' => '𥥼', '𥪧' => '𥪧', '𥪧' => '𥪧', '竮' => '竮', '䈂' => '䈂', '𥮫' => '𥮫', '篆' => '篆', '築' => '築', '䈧' => '䈧', '𥲀' => '𥲀', '糒' => '糒', '䊠' => '䊠', '糨' => '糨', '糣' => '糣', '紀' => '紀', '𥾆' => '𥾆', '絣' => '絣', '䌁' => '䌁', '緇' => '緇', '縂' => '縂', '繅' => '繅', '䌴' => '䌴', '𦈨' => '𦈨', '𦉇' => '𦉇', '䍙' => '䍙', '𦋙' => '𦋙', '罺' => '罺', '𦌾' => '𦌾', '羕' => '羕', '翺' => '翺', '者' => '者', '𦓚' => '𦓚', '𦔣' => '𦔣', '聠' => '聠', '𦖨' => '𦖨', '聰' => '聰', '𣍟' => '𣍟', '䏕' => '䏕', '育' => '育', '脃' => '脃', '䐋' => '䐋', '脾' => '脾', '媵' => '媵', '𦞧' => '𦞧', '𦞵' => '𦞵', '𣎓' => '𣎓', '𣎜' => '𣎜', '舁' => '舁', '舄' => '舄', '辞' => '辞', '䑫' => '䑫', '芑' => '芑', '芋' => '芋', '芝' => '芝', '劳' => '劳', '花' => '花', '芳' => '芳', '芽' => '芽', '苦' => '苦', '𦬼' => '𦬼', '若' => '若', '茝' => '茝', '荣' => '荣', '莭' => '莭', '茣' => '茣', '莽' => '莽', '菧' => '菧', '著' => '著', '荓' => '荓', '菊' => '菊', '菌' => '菌', '菜' => '菜', '𦰶' => '𦰶', '𦵫' => '𦵫', '𦳕' => '𦳕', '䔫' => '䔫', '蓱' => '蓱', '蓳' => '蓳', '蔖' => '蔖', '𧏊' => '𧏊', '蕤' => '蕤', '𦼬' => '𦼬', '䕝' => '䕝', '䕡' => '䕡', '𦾱' => '𦾱', '𧃒' => '𧃒', '䕫' => '䕫', '虐' => '虐', '虜' => '虜', '虧' => '虧', '虩' => '虩', '蚩' => '蚩', '蚈' => '蚈', '蜎' => '蜎', '蛢' => '蛢', '蝹' => '蝹', '蜨' => '蜨', '蝫' => '蝫', '螆' => '螆', '䗗' => '䗗', '蟡' => '蟡', '蠁' => '蠁', '䗹' => '䗹', '衠' => '衠', '衣' => '衣', '𧙧' => '𧙧', '裗' => '裗', '裞' => '裞', '䘵' => '䘵', '裺' => '裺', '㒻' => '㒻', '𧢮' => '𧢮', '𧥦' => '𧥦', '䚾' => '䚾', '䛇' => '䛇', '誠' => '誠', '諭' => '諭', '變' => '變', '豕' => '豕', '𧲨' => '𧲨', '貫' => '貫', '賁' => '賁', '贛' => '贛', '起' => '起', '𧼯' => '𧼯', '𠠄' => '𠠄', '跋' => '跋', '趼' => '趼', '跰' => '跰', '𠣞' => '𠣞', '軔' => '軔', '輸' => '輸', '𨗒' => '𨗒', '𨗭' => '𨗭', '邔' => '邔', '郱' => '郱', '鄑' => '鄑', '𨜮' => '𨜮', '鄛' => '鄛', '鈸' => '鈸', '鋗' => '鋗', '鋘' => '鋘', '鉼' => '鉼', '鏹' => '鏹', '鐕' => '鐕', '𨯺' => '𨯺', '開' => '開', '䦕' => '䦕', '閷' => '閷', '𨵷' => '𨵷', '䧦' => '䧦', '雃' => '雃', '嶲' => '嶲', '霣' => '霣', '𩅅' => '𩅅', '𩈚' => '𩈚', '䩮' => '䩮', '䩶' => '䩶', '韠' => '韠', '𩐊' => '𩐊', '䪲' => '䪲', '𩒖' => '𩒖', '頋' => '頋', '頋' => '頋', '頩' => '頩', '𩖶' => '𩖶', '飢' => '飢', '䬳' => '䬳', '餩' => '餩', '馧' => '馧', '駂' => '駂', '駾' => '駾', '䯎' => '䯎', '𩬰' => '𩬰', '鬒' => '鬒', '鱀' => '鱀', '鳽' => '鳽', '䳎' => '䳎', '䳭' => '䳭', '鵧' => '鵧', '𪃎' => '𪃎', '䳸' => '䳸', '𪄅' => '𪄅', '𪈎' => '𪈎', '𪊑' => '𪊑', '麻' => '麻', '䵖' => '䵖', '黹' => '黹', '黾' => '黾', '鼅' => '鼅', '鼏' => '鼏', '鼖' => '鼖', '鼻' => '鼻', '𪘀' => '𪘀'); * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ use _HumbugBox7ff99e199a36\Symfony\Polyfill\Intl\Normalizer as p; if (!\function_exists('normalizer_is_normalized')) { function normalizer_is_normalized(?string $string, ?int $form = p\Normalizer::FORM_C) : bool { return p\Normalizer::isNormalized((string) $string, (int) $form); } } if (!\function_exists('normalizer_normalize')) { function normalizer_normalize(?string $string, ?int $form = p\Normalizer::FORM_C) : string|false { return p\Normalizer::normalize((string) $string, (int) $form); } } * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ use _HumbugBox7ff99e199a36\Symfony\Polyfill\Intl\Normalizer as p; if (\PHP_VERSION_ID >= 80000) { return require __DIR__ . '/bootstrap80.php'; } if (!\function_exists('normalizer_is_normalized')) { function normalizer_is_normalized($string, $form = p\Normalizer::FORM_C) { return p\Normalizer::isNormalized($string, $form); } } if (!\function_exists('normalizer_normalize')) { function normalizer_normalize($string, $form = p\Normalizer::FORM_C) { return p\Normalizer::normalize($string, $form); } } * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace _HumbugBox7ff99e199a36\Symfony\Polyfill\Intl\Normalizer; /** * Normalizer is a PHP fallback implementation of the Normalizer class provided by the intl extension. * * It has been validated with Unicode 6.3 Normalization Conformance Test. * See http://www.unicode.org/reports/tr15/ for detailed info about Unicode normalizations. * * @author Nicolas Grekas * * @internal */ class Normalizer { public const FORM_D = \Normalizer::FORM_D; public const FORM_KD = \Normalizer::FORM_KD; public const FORM_C = \Normalizer::FORM_C; public const FORM_KC = \Normalizer::FORM_KC; public const NFD = \Normalizer::NFD; public const NFKD = \Normalizer::NFKD; public const NFC = \Normalizer::NFC; public const NFKC = \Normalizer::NFKC; private static $C; private static $D; private static $KD; private static $cC; private static $ulenMask = ["\xc0" => 2, "\xd0" => 2, "\xe0" => 3, "\xf0" => 4]; private static $ASCII = " eiasntrolud][cmp'\ng|hv.fb,:=-q10C2*yx)(L9AS/P\"EjMIk3>5T \PHP_VERSION_ID) { return \false; } throw new \ValueError('normalizer_normalize(): Argument #2 ($form) must be a a valid normalization form'); } if ('' === $s) { return ''; } if ($K && null === self::$KD) { self::$KD = self::getData('compatibilityDecomposition'); } if (null === self::$D) { self::$D = self::getData('canonicalDecomposition'); self::$cC = self::getData('combiningClass'); } if (null !== ($mbEncoding = 2 & (int) \ini_get('mbstring.func_overload') ? \mb_internal_encoding() : null)) { \mb_internal_encoding('8bit'); } $r = self::decompose($s, $K); if ($C) { if (null === self::$C) { self::$C = self::getData('canonicalComposition'); } $r = self::recompose($r); } if (null !== $mbEncoding) { \mb_internal_encoding($mbEncoding); } return $r; } private static function recompose($s) { $ASCII = self::$ASCII; $compMap = self::$C; $combClass = self::$cC; $ulenMask = self::$ulenMask; $result = $tail = ''; $i = $s[0] < "\x80" ? 1 : $ulenMask[$s[0] & "\xf0"]; $len = \strlen($s); $lastUchr = \substr($s, 0, $i); $lastUcls = isset($combClass[$lastUchr]) ? 256 : 0; while ($i < $len) { if ($s[$i] < "\x80") { // ASCII chars if ($tail) { $lastUchr .= $tail; $tail = ''; } if ($j = \strspn($s, $ASCII, $i + 1)) { $lastUchr .= \substr($s, $i, $j); $i += $j; } $result .= $lastUchr; $lastUchr = $s[$i]; $lastUcls = 0; ++$i; continue; } $ulen = $ulenMask[$s[$i] & "\xf0"]; $uchr = \substr($s, $i, $ulen); if ($lastUchr < "ᄀ" || "ᄒ" < $lastUchr || $uchr < "ᅡ" || "ᅵ" < $uchr || $lastUcls) { // Table lookup and combining chars composition $ucls = $combClass[$uchr] ?? 0; if (isset($compMap[$lastUchr . $uchr]) && (!$lastUcls || $lastUcls < $ucls)) { $lastUchr = $compMap[$lastUchr . $uchr]; } elseif ($lastUcls = $ucls) { $tail .= $uchr; } else { if ($tail) { $lastUchr .= $tail; $tail = ''; } $result .= $lastUchr; $lastUchr = $uchr; } } else { // Hangul chars $L = \ord($lastUchr[2]) - 0x80; $V = \ord($uchr[2]) - 0xa1; $T = 0; $uchr = \substr($s, $i + $ulen, 3); if ("ᆧ" <= $uchr && $uchr <= "ᇂ") { $T = \ord($uchr[2]) - 0xa7; 0 > $T && ($T += 0x40); $ulen += 3; } $L = 0xac00 + ($L * 21 + $V) * 28 + $T; $lastUchr = \chr(0xe0 | $L >> 12) . \chr(0x80 | $L >> 6 & 0x3f) . \chr(0x80 | $L & 0x3f); } $i += $ulen; } return $result . $lastUchr . $tail; } private static function decompose($s, $c) { $result = ''; $ASCII = self::$ASCII; $decompMap = self::$D; $combClass = self::$cC; $ulenMask = self::$ulenMask; if ($c) { $compatMap = self::$KD; } $c = []; $i = 0; $len = \strlen($s); while ($i < $len) { if ($s[$i] < "\x80") { // ASCII chars if ($c) { \ksort($c); $result .= \implode('', $c); $c = []; } $j = 1 + \strspn($s, $ASCII, $i + 1); $result .= \substr($s, $i, $j); $i += $j; continue; } $ulen = $ulenMask[$s[$i] & "\xf0"]; $uchr = \substr($s, $i, $ulen); $i += $ulen; if ($uchr < "가" || "힣" < $uchr) { // Table lookup if ($uchr !== ($j = $compatMap[$uchr] ?? $decompMap[$uchr] ?? $uchr)) { $uchr = $j; $j = \strlen($uchr); $ulen = $uchr[0] < "\x80" ? 1 : $ulenMask[$uchr[0] & "\xf0"]; if ($ulen != $j) { // Put trailing chars in $s $j -= $ulen; $i -= $j; if (0 > $i) { $s = \str_repeat(' ', -$i) . $s; $len -= $i; $i = 0; } while ($j--) { $s[$i + $j] = $uchr[$ulen + $j]; } $uchr = \substr($uchr, 0, $ulen); } } if (isset($combClass[$uchr])) { // Combining chars, for sorting if (!isset($c[$combClass[$uchr]])) { $c[$combClass[$uchr]] = ''; } $c[$combClass[$uchr]] .= $uchr; continue; } } else { // Hangul chars $uchr = \unpack('C*', $uchr); $j = ($uchr[1] - 224 << 12) + ($uchr[2] - 128 << 6) + $uchr[3] - 0xac80; $uchr = "\xe1\x84" . \chr(0x80 + (int) ($j / 588)) . "\xe1\x85" . \chr(0xa1 + (int) ($j % 588 / 28)); if ($j %= 28) { $uchr .= $j < 25 ? "\xe1\x86" . \chr(0xa7 + $j) : "\xe1\x87" . \chr(0x67 + $j); } } if ($c) { \ksort($c); $result .= \implode('', $c); $c = []; } $result .= $uchr; } if ($c) { \ksort($c); $result .= \implode('', $c); } return $result; } private static function getData($file) { if (\file_exists($file = __DIR__ . '/Resources/unidata/' . $file . '.php')) { return require $file; } return \false; } } Copyright (c) 2018-present Fabien Potencier Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace _HumbugBox7ff99e199a36\Symfony\Polyfill\Ctype; /** * Ctype implementation through regex. * * @internal * * @author Gert de Pagter */ final class Ctype { /** * Returns TRUE if every character in text is either a letter or a digit, FALSE otherwise. * * @see https://php.net/ctype-alnum * * @param mixed $text * * @return bool */ public static function ctype_alnum($text) { $text = self::convert_int_to_char_for_ctype($text, __FUNCTION__); return \is_string($text) && '' !== $text && !\preg_match('/[^A-Za-z0-9]/', $text); } /** * Returns TRUE if every character in text is a letter, FALSE otherwise. * * @see https://php.net/ctype-alpha * * @param mixed $text * * @return bool */ public static function ctype_alpha($text) { $text = self::convert_int_to_char_for_ctype($text, __FUNCTION__); return \is_string($text) && '' !== $text && !\preg_match('/[^A-Za-z]/', $text); } /** * Returns TRUE if every character in text is a control character from the current locale, FALSE otherwise. * * @see https://php.net/ctype-cntrl * * @param mixed $text * * @return bool */ public static function ctype_cntrl($text) { $text = self::convert_int_to_char_for_ctype($text, __FUNCTION__); return \is_string($text) && '' !== $text && !\preg_match('/[^\\x00-\\x1f\\x7f]/', $text); } /** * Returns TRUE if every character in the string text is a decimal digit, FALSE otherwise. * * @see https://php.net/ctype-digit * * @param mixed $text * * @return bool */ public static function ctype_digit($text) { $text = self::convert_int_to_char_for_ctype($text, __FUNCTION__); return \is_string($text) && '' !== $text && !\preg_match('/[^0-9]/', $text); } /** * Returns TRUE if every character in text is printable and actually creates visible output (no white space), FALSE otherwise. * * @see https://php.net/ctype-graph * * @param mixed $text * * @return bool */ public static function ctype_graph($text) { $text = self::convert_int_to_char_for_ctype($text, __FUNCTION__); return \is_string($text) && '' !== $text && !\preg_match('/[^!-~]/', $text); } /** * Returns TRUE if every character in text is a lowercase letter. * * @see https://php.net/ctype-lower * * @param mixed $text * * @return bool */ public static function ctype_lower($text) { $text = self::convert_int_to_char_for_ctype($text, __FUNCTION__); return \is_string($text) && '' !== $text && !\preg_match('/[^a-z]/', $text); } /** * Returns TRUE if every character in text will actually create output (including blanks). Returns FALSE if text contains control characters or characters that do not have any output or control function at all. * * @see https://php.net/ctype-print * * @param mixed $text * * @return bool */ public static function ctype_print($text) { $text = self::convert_int_to_char_for_ctype($text, __FUNCTION__); return \is_string($text) && '' !== $text && !\preg_match('/[^ -~]/', $text); } /** * Returns TRUE if every character in text is printable, but neither letter, digit or blank, FALSE otherwise. * * @see https://php.net/ctype-punct * * @param mixed $text * * @return bool */ public static function ctype_punct($text) { $text = self::convert_int_to_char_for_ctype($text, __FUNCTION__); return \is_string($text) && '' !== $text && !\preg_match('/[^!-\\/\\:-@\\[-`\\{-~]/', $text); } /** * Returns TRUE if every character in text creates some sort of white space, FALSE otherwise. Besides the blank character this also includes tab, vertical tab, line feed, carriage return and form feed characters. * * @see https://php.net/ctype-space * * @param mixed $text * * @return bool */ public static function ctype_space($text) { $text = self::convert_int_to_char_for_ctype($text, __FUNCTION__); return \is_string($text) && '' !== $text && !\preg_match('/[^\\s]/', $text); } /** * Returns TRUE if every character in text is an uppercase letter. * * @see https://php.net/ctype-upper * * @param mixed $text * * @return bool */ public static function ctype_upper($text) { $text = self::convert_int_to_char_for_ctype($text, __FUNCTION__); return \is_string($text) && '' !== $text && !\preg_match('/[^A-Z]/', $text); } /** * Returns TRUE if every character in text is a hexadecimal 'digit', that is a decimal digit or a character from [A-Fa-f] , FALSE otherwise. * * @see https://php.net/ctype-xdigit * * @param mixed $text * * @return bool */ public static function ctype_xdigit($text) { $text = self::convert_int_to_char_for_ctype($text, __FUNCTION__); return \is_string($text) && '' !== $text && !\preg_match('/[^A-Fa-f0-9]/', $text); } /** * Converts integers to their char versions according to normal ctype behaviour, if needed. * * If an integer between -128 and 255 inclusive is provided, * it is interpreted as the ASCII value of a single character * (negative values have 256 added in order to allow characters in the Extended ASCII range). * Any other integer is interpreted as a string containing the decimal digits of the integer. * * @param mixed $int * @param string $function * * @return mixed */ private static function convert_int_to_char_for_ctype($int, $function) { if (!\is_int($int)) { return $int; } if ($int < -128 || $int > 255) { return (string) $int; } if (\PHP_VERSION_ID >= 80100) { @\trigger_error($function . '(): Argument of type int will be interpreted as string in the future', \E_USER_DEPRECATED); } if ($int < 0) { $int += 256; } return \chr($int); } } * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ use _HumbugBox7ff99e199a36\Symfony\Polyfill\Ctype as p; if (!\function_exists('ctype_alnum')) { function ctype_alnum(mixed $text) : bool { return p\Ctype::ctype_alnum($text); } } if (!\function_exists('ctype_alpha')) { function ctype_alpha(mixed $text) : bool { return p\Ctype::ctype_alpha($text); } } if (!\function_exists('ctype_cntrl')) { function ctype_cntrl(mixed $text) : bool { return p\Ctype::ctype_cntrl($text); } } if (!\function_exists('ctype_digit')) { function ctype_digit(mixed $text) : bool { return p\Ctype::ctype_digit($text); } } if (!\function_exists('ctype_graph')) { function ctype_graph(mixed $text) : bool { return p\Ctype::ctype_graph($text); } } if (!\function_exists('ctype_lower')) { function ctype_lower(mixed $text) : bool { return p\Ctype::ctype_lower($text); } } if (!\function_exists('ctype_print')) { function ctype_print(mixed $text) : bool { return p\Ctype::ctype_print($text); } } if (!\function_exists('ctype_punct')) { function ctype_punct(mixed $text) : bool { return p\Ctype::ctype_punct($text); } } if (!\function_exists('ctype_space')) { function ctype_space(mixed $text) : bool { return p\Ctype::ctype_space($text); } } if (!\function_exists('ctype_upper')) { function ctype_upper(mixed $text) : bool { return p\Ctype::ctype_upper($text); } } if (!\function_exists('ctype_xdigit')) { function ctype_xdigit(mixed $text) : bool { return p\Ctype::ctype_xdigit($text); } } * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ use _HumbugBox7ff99e199a36\Symfony\Polyfill\Ctype as p; if (\PHP_VERSION_ID >= 80000) { return require __DIR__ . '/bootstrap80.php'; } if (!\function_exists('ctype_alnum')) { function ctype_alnum($text) { return p\Ctype::ctype_alnum($text); } } if (!\function_exists('ctype_alpha')) { function ctype_alpha($text) { return p\Ctype::ctype_alpha($text); } } if (!\function_exists('ctype_cntrl')) { function ctype_cntrl($text) { return p\Ctype::ctype_cntrl($text); } } if (!\function_exists('ctype_digit')) { function ctype_digit($text) { return p\Ctype::ctype_digit($text); } } if (!\function_exists('ctype_graph')) { function ctype_graph($text) { return p\Ctype::ctype_graph($text); } } if (!\function_exists('ctype_lower')) { function ctype_lower($text) { return p\Ctype::ctype_lower($text); } } if (!\function_exists('ctype_print')) { function ctype_print($text) { return p\Ctype::ctype_print($text); } } if (!\function_exists('ctype_punct')) { function ctype_punct($text) { return p\Ctype::ctype_punct($text); } } if (!\function_exists('ctype_space')) { function ctype_space($text) { return p\Ctype::ctype_space($text); } } if (!\function_exists('ctype_upper')) { function ctype_upper($text) { return p\Ctype::ctype_upper($text); } } if (!\function_exists('ctype_xdigit')) { function ctype_xdigit($text) { return p\Ctype::ctype_xdigit($text); } } Copyright (c) 2015-present Fabien Potencier Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ use _HumbugBox7ff99e199a36\Symfony\Polyfill\Intl\Grapheme as p; if (!\defined('GRAPHEME_EXTR_COUNT')) { \define('GRAPHEME_EXTR_COUNT', 0); } if (!\defined('GRAPHEME_EXTR_MAXBYTES')) { \define('GRAPHEME_EXTR_MAXBYTES', 1); } if (!\defined('GRAPHEME_EXTR_MAXCHARS')) { \define('GRAPHEME_EXTR_MAXCHARS', 2); } if (!\function_exists('grapheme_extract')) { function grapheme_extract(?string $haystack, ?int $size, ?int $type = \GRAPHEME_EXTR_COUNT, ?int $offset = 0, &$next = null) : string|false { return p\Grapheme::grapheme_extract((string) $haystack, (int) $size, (int) $type, (int) $offset, $next); } } if (!\function_exists('grapheme_stripos')) { function grapheme_stripos(?string $haystack, ?string $needle, ?int $offset = 0) : int|false { return p\Grapheme::grapheme_stripos((string) $haystack, (string) $needle, (int) $offset); } } if (!\function_exists('grapheme_stristr')) { function grapheme_stristr(?string $haystack, ?string $needle, ?bool $beforeNeedle = \false) : string|false { return p\Grapheme::grapheme_stristr((string) $haystack, (string) $needle, (bool) $beforeNeedle); } } if (!\function_exists('grapheme_strlen')) { function grapheme_strlen(?string $string) : int|false|null { return p\Grapheme::grapheme_strlen((string) $string); } } if (!\function_exists('grapheme_strpos')) { function grapheme_strpos(?string $haystack, ?string $needle, ?int $offset = 0) : int|false { return p\Grapheme::grapheme_strpos((string) $haystack, (string) $needle, (int) $offset); } } if (!\function_exists('grapheme_strripos')) { function grapheme_strripos(?string $haystack, ?string $needle, ?int $offset = 0) : int|false { return p\Grapheme::grapheme_strripos((string) $haystack, (string) $needle, (int) $offset); } } if (!\function_exists('grapheme_strrpos')) { function grapheme_strrpos(?string $haystack, ?string $needle, ?int $offset = 0) : int|false { return p\Grapheme::grapheme_strrpos((string) $haystack, (string) $needle, (int) $offset); } } if (!\function_exists('grapheme_strstr')) { function grapheme_strstr(?string $haystack, ?string $needle, ?bool $beforeNeedle = \false) : string|false { return p\Grapheme::grapheme_strstr((string) $haystack, (string) $needle, (bool) $beforeNeedle); } } if (!\function_exists('grapheme_substr')) { function grapheme_substr(?string $string, ?int $offset, ?int $length = null) : string|false { return p\Grapheme::grapheme_substr((string) $string, (int) $offset, $length); } } * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ use _HumbugBox7ff99e199a36\Symfony\Polyfill\Intl\Grapheme as p; if (\extension_loaded('intl')) { return; } if (\PHP_VERSION_ID >= 80000) { return require __DIR__ . '/bootstrap80.php'; } if (!\defined('GRAPHEME_EXTR_COUNT')) { \define('GRAPHEME_EXTR_COUNT', 0); } if (!\defined('GRAPHEME_EXTR_MAXBYTES')) { \define('GRAPHEME_EXTR_MAXBYTES', 1); } if (!\defined('GRAPHEME_EXTR_MAXCHARS')) { \define('GRAPHEME_EXTR_MAXCHARS', 2); } if (!\function_exists('grapheme_extract')) { function grapheme_extract($haystack, $size, $type = 0, $start = 0, &$next = 0) { return p\Grapheme::grapheme_extract($haystack, $size, $type, $start, $next); } } if (!\function_exists('grapheme_stripos')) { function grapheme_stripos($haystack, $needle, $offset = 0) { return p\Grapheme::grapheme_stripos($haystack, $needle, $offset); } } if (!\function_exists('grapheme_stristr')) { function grapheme_stristr($haystack, $needle, $beforeNeedle = \false) { return p\Grapheme::grapheme_stristr($haystack, $needle, $beforeNeedle); } } if (!\function_exists('grapheme_strlen')) { function grapheme_strlen($input) { return p\Grapheme::grapheme_strlen($input); } } if (!\function_exists('grapheme_strpos')) { function grapheme_strpos($haystack, $needle, $offset = 0) { return p\Grapheme::grapheme_strpos($haystack, $needle, $offset); } } if (!\function_exists('grapheme_strripos')) { function grapheme_strripos($haystack, $needle, $offset = 0) { return p\Grapheme::grapheme_strripos($haystack, $needle, $offset); } } if (!\function_exists('grapheme_strrpos')) { function grapheme_strrpos($haystack, $needle, $offset = 0) { return p\Grapheme::grapheme_strrpos($haystack, $needle, $offset); } } if (!\function_exists('grapheme_strstr')) { function grapheme_strstr($haystack, $needle, $beforeNeedle = \false) { return p\Grapheme::grapheme_strstr($haystack, $needle, $beforeNeedle); } } if (!\function_exists('grapheme_substr')) { function grapheme_substr($string, $offset, $length = null) { return p\Grapheme::grapheme_substr($string, $offset, $length); } } * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace _HumbugBox7ff99e199a36\Symfony\Polyfill\Intl\Grapheme; \define('_HumbugBox7ff99e199a36\\SYMFONY_GRAPHEME_CLUSTER_RX', ((float) \PCRE_VERSION < 10 ? (float) \PCRE_VERSION >= 8.32 : (float) \PCRE_VERSION >= 10.39) ? '\\X' : Grapheme::GRAPHEME_CLUSTER_RX); /** * Partial intl implementation in pure PHP. * * Implemented: * - grapheme_extract - Extract a sequence of grapheme clusters from a text buffer, which must be encoded in UTF-8 * - grapheme_stripos - Find position (in grapheme units) of first occurrence of a case-insensitive string * - grapheme_stristr - Returns part of haystack string from the first occurrence of case-insensitive needle to the end of haystack * - grapheme_strlen - Get string length in grapheme units * - grapheme_strpos - Find position (in grapheme units) of first occurrence of a string * - grapheme_strripos - Find position (in grapheme units) of last occurrence of a case-insensitive string * - grapheme_strrpos - Find position (in grapheme units) of last occurrence of a string * - grapheme_strstr - Returns part of haystack string from the first occurrence of needle to the end of haystack * - grapheme_substr - Return part of a string * * @author Nicolas Grekas * * @internal */ final class Grapheme { // (CRLF|([ZWNJ-ZWJ]|T+|L*(LV?V+|LV|LVT)T*|L+|[^Control])[Extend]*|[Control]) // This regular expression is a work around for http://bugs.exim.org/1279 public const GRAPHEME_CLUSTER_RX = '(?:\\r\\n|(?:[ -~\\x{200C}\\x{200D}]|[ᆨ-ᇹ]+|[ᄀ-ᅟ]*(?:[가개갸걔거게겨계고과괘괴교구궈궤귀규그긔기까깨꺄꺠꺼께껴꼐꼬꽈꽤꾀꾜꾸꿔꿰뀌뀨끄끠끼나내냐냬너네녀녜노놔놰뇌뇨누눠눼뉘뉴느늬니다대댜댸더데뎌뎨도돠돼되됴두둬뒈뒤듀드듸디따때땨떄떠떼뗘뗴또똬뙈뙤뚀뚜뚸뛔뛰뜌뜨띄띠라래랴럐러레려례로롸뢔뢰료루뤄뤠뤼류르릐리마매먀먜머메며몌모뫄뫠뫼묘무뭐뭬뮈뮤므믜미바배뱌뱨버베벼볘보봐봬뵈뵤부붜붸뷔뷰브븨비빠빼뺘뺴뻐뻬뼈뼤뽀뽜뽸뾔뾰뿌뿨쀄쀠쀼쁘쁴삐사새샤섀서세셔셰소솨쇄쇠쇼수숴쉐쉬슈스싀시싸쌔쌰썌써쎄쎠쎼쏘쏴쐐쐬쑈쑤쒀쒜쒸쓔쓰씌씨아애야얘어에여예오와왜외요우워웨위유으의이자재쟈쟤저제져졔조좌좨죄죠주줘줴쥐쥬즈즤지짜째쨔쨰쩌쩨쪄쪠쪼쫘쫴쬐쬬쭈쭤쮀쮜쮸쯔쯰찌차채챠챼처체쳐쳬초촤쵀최쵸추춰췌취츄츠츼치카캐캬컈커케켜켸코콰쾌쾨쿄쿠쿼퀘퀴큐크킈키타태탸턔터테텨톄토톼퇘퇴툐투퉈퉤튀튜트틔티파패퍄퍠퍼페펴폐포퐈퐤푀표푸풔풰퓌퓨프픠피하해햐햬허헤혀혜호화홰회효후훠훼휘휴흐희히]?[ᅠ-ᆢ]+|[가-힣])[ᆨ-ᇹ]*|[ᄀ-ᅟ]+|[^\\p{Cc}\\p{Cf}\\p{Zl}\\p{Zp}])[\\p{Mn}\\p{Me}\\x{09BE}\\x{09D7}\\x{0B3E}\\x{0B57}\\x{0BBE}\\x{0BD7}\\x{0CC2}\\x{0CD5}\\x{0CD6}\\x{0D3E}\\x{0D57}\\x{0DCF}\\x{0DDF}\\x{200C}\\x{200D}\\x{1D165}\\x{1D16E}-\\x{1D172}]*|[\\p{Cc}\\p{Cf}\\p{Zl}\\p{Zp}])'; private const CASE_FOLD = [['µ', 'ſ', "ͅ", 'ς', "ϐ", "ϑ", "ϕ", "ϖ", "ϰ", "ϱ", "ϵ", "ẛ", "ι"], ['μ', 's', 'ι', 'σ', 'β', 'θ', 'φ', 'π', 'κ', 'ρ', 'ε', "ṡ", 'ι']]; public static function grapheme_extract($s, $size, $type = \GRAPHEME_EXTR_COUNT, $start = 0, &$next = 0) { if (0 > $start) { $start = \strlen($s) + $start; } if (!\is_scalar($s)) { $hasError = \false; \set_error_handler(function () use(&$hasError) { $hasError = \true; }); $next = \substr($s, $start); \restore_error_handler(); if ($hasError) { \substr($s, $start); $s = ''; } else { $s = $next; } } else { $s = \substr($s, $start); } $size = (int) $size; $type = (int) $type; $start = (int) $start; if (\GRAPHEME_EXTR_COUNT !== $type && \GRAPHEME_EXTR_MAXBYTES !== $type && \GRAPHEME_EXTR_MAXCHARS !== $type) { if (80000 > \PHP_VERSION_ID) { return \false; } throw new \ValueError('grapheme_extract(): Argument #3 ($type) must be one of GRAPHEME_EXTR_COUNT, GRAPHEME_EXTR_MAXBYTES, or GRAPHEME_EXTR_MAXCHARS'); } if (!isset($s[0]) || 0 > $size || 0 > $start) { return \false; } if (0 === $size) { return ''; } $next = $start; $s = \preg_split('/(' . SYMFONY_GRAPHEME_CLUSTER_RX . ')/u', "\r\n" . $s, $size + 1, \PREG_SPLIT_NO_EMPTY | \PREG_SPLIT_DELIM_CAPTURE); if (!isset($s[1])) { return \false; } $i = 1; $ret = ''; do { if (\GRAPHEME_EXTR_COUNT === $type) { --$size; } elseif (\GRAPHEME_EXTR_MAXBYTES === $type) { $size -= \strlen($s[$i]); } else { $size -= \iconv_strlen($s[$i], 'UTF-8//IGNORE'); } if ($size >= 0) { $ret .= $s[$i]; } } while (isset($s[++$i]) && $size > 0); $next += \strlen($ret); return $ret; } public static function grapheme_strlen($s) { \preg_replace('/' . SYMFONY_GRAPHEME_CLUSTER_RX . '/u', '', $s, -1, $len); return 0 === $len && '' !== $s ? null : $len; } public static function grapheme_substr($s, $start, $len = null) { if (null === $len) { $len = 2147483647; } \preg_match_all('/' . SYMFONY_GRAPHEME_CLUSTER_RX . '/u', $s, $s); $slen = \count($s[0]); $start = (int) $start; if (0 > $start) { $start += $slen; } if (0 > $start) { if (\PHP_VERSION_ID < 80000) { return \false; } $start = 0; } if ($start >= $slen) { return \PHP_VERSION_ID >= 80000 ? '' : \false; } $rem = $slen - $start; if (0 > $len) { $len += $rem; } if (0 === $len) { return ''; } if (0 > $len) { return \PHP_VERSION_ID >= 80000 ? '' : \false; } if ($len > $rem) { $len = $rem; } return \implode('', \array_slice($s[0], $start, $len)); } public static function grapheme_strpos($s, $needle, $offset = 0) { return self::grapheme_position($s, $needle, $offset, 0); } public static function grapheme_stripos($s, $needle, $offset = 0) { return self::grapheme_position($s, $needle, $offset, 1); } public static function grapheme_strrpos($s, $needle, $offset = 0) { return self::grapheme_position($s, $needle, $offset, 2); } public static function grapheme_strripos($s, $needle, $offset = 0) { return self::grapheme_position($s, $needle, $offset, 3); } public static function grapheme_stristr($s, $needle, $beforeNeedle = \false) { return \mb_stristr($s, $needle, $beforeNeedle, 'UTF-8'); } public static function grapheme_strstr($s, $needle, $beforeNeedle = \false) { return \mb_strstr($s, $needle, $beforeNeedle, 'UTF-8'); } private static function grapheme_position($s, $needle, $offset, $mode) { $needle = (string) $needle; if (80000 > \PHP_VERSION_ID && !\preg_match('/./us', $needle)) { return \false; } $s = (string) $s; if (!\preg_match('/./us', $s)) { return \false; } if ($offset > 0) { $s = self::grapheme_substr($s, $offset); } elseif ($offset < 0) { if (2 > $mode) { $offset += self::grapheme_strlen($s); $s = self::grapheme_substr($s, $offset); if (0 > $offset) { $offset = 0; } } elseif (0 > ($offset += self::grapheme_strlen($needle))) { $s = self::grapheme_substr($s, 0, $offset); $offset = 0; } else { $offset = 0; } } // As UTF-8 is self-synchronizing, and we have ensured the strings are valid UTF-8, // we can use normal binary string functions here. For case-insensitive searches, // case fold the strings first. $caseInsensitive = $mode & 1; $reverse = $mode & 2; if ($caseInsensitive) { // Use the same case folding mode as mbstring does for mb_stripos(). // Stick to SIMPLE case folding to avoid changing the length of the string, which // might result in offsets being shifted. $mode = \defined('MB_CASE_FOLD_SIMPLE') ? \MB_CASE_FOLD_SIMPLE : \MB_CASE_LOWER; $s = \mb_convert_case($s, $mode, 'UTF-8'); $needle = \mb_convert_case($needle, $mode, 'UTF-8'); if (!\defined('MB_CASE_FOLD_SIMPLE')) { $s = \str_replace(self::CASE_FOLD[0], self::CASE_FOLD[1], $s); $needle = \str_replace(self::CASE_FOLD[0], self::CASE_FOLD[1], $needle); } } if ($reverse) { $needlePos = \strrpos($s, $needle); } else { $needlePos = \strpos($s, $needle); } return \false !== $needlePos ? self::grapheme_strlen(\substr($s, 0, $needlePos)) + $offset : \false; } } * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace _HumbugBox7ff99e199a36\Symfony\Component\String\Inflector; /** * French inflector. * * This class does only inflect nouns; not adjectives nor composed words like "soixante-dix". */ final class FrenchInflector implements InflectorInterface { /** * A list of all rules for pluralise. * * @see https://la-conjugaison.nouvelobs.com/regles/grammaire/le-pluriel-des-noms-121.php */ private const PLURALIZE_REGEXP = [ // First entry: regexp // Second entry: replacement // Words finishing with "s", "x" or "z" are invariables // Les mots finissant par "s", "x" ou "z" sont invariables ['/(s|x|z)$/i', '\\1'], // Words finishing with "eau" are pluralized with a "x" // Les mots finissant par "eau" prennent tous un "x" au pluriel ['/(eau)$/i', '\\1x'], // Words finishing with "au" are pluralized with a "x" excepted "landau" // Les mots finissant par "au" prennent un "x" au pluriel sauf "landau" ['/^(landau)$/i', '\\1s'], ['/(au)$/i', '\\1x'], // Words finishing with "eu" are pluralized with a "x" excepted "pneu", "bleu", "émeu" // Les mots finissant en "eu" prennent un "x" au pluriel sauf "pneu", "bleu", "émeu" ['/^(pneu|bleu|émeu)$/i', '\\1s'], ['/(eu)$/i', '\\1x'], // Words finishing with "al" are pluralized with a "aux" excepted // Les mots finissant en "al" se terminent en "aux" sauf ['/^(bal|carnaval|caracal|chacal|choral|corral|étal|festival|récital|val)$/i', '\\1s'], ['/al$/i', '\\1aux'], // Aspirail, bail, corail, émail, fermail, soupirail, travail, vantail et vitrail font leur pluriel en -aux ['/^(aspir|b|cor|ém|ferm|soupir|trav|vant|vitr)ail$/i', '\\1aux'], // Bijou, caillou, chou, genou, hibou, joujou et pou qui prennent un x au pluriel ['/^(bij|caill|ch|gen|hib|jouj|p)ou$/i', '\\1oux'], // Invariable words ['/^(cinquante|soixante|mille)$/i', '\\1'], // French titles ['/^(mon|ma)(sieur|dame|demoiselle|seigneur)$/', '_HumbugBox7ff99e199a36\\mes\\2s'], ['/^(Mon|Ma)(sieur|dame|demoiselle|seigneur)$/', '_HumbugBox7ff99e199a36\\Mes\\2s'], ]; /** * A list of all rules for singularize. */ private const SINGULARIZE_REGEXP = [ // First entry: regexp // Second entry: replacement // Aspirail, bail, corail, émail, fermail, soupirail, travail, vantail et vitrail font leur pluriel en -aux ['/((aspir|b|cor|ém|ferm|soupir|trav|vant|vitr))aux$/i', '\\1ail'], // Words finishing with "eau" are pluralized with a "x" // Les mots finissant par "eau" prennent tous un "x" au pluriel ['/(eau)x$/i', '\\1'], // Words finishing with "al" are pluralized with a "aux" expected // Les mots finissant en "al" se terminent en "aux" sauf ['/(amir|anim|arsen|boc|can|capit|capor|chev|crist|génér|hopit|hôpit|idé|journ|littor|loc|m|mét|minér|princip|radic|termin)aux$/i', '\\1al'], // Words finishing with "au" are pluralized with a "x" excepted "landau" // Les mots finissant par "au" prennent un "x" au pluriel sauf "landau" ['/(au)x$/i', '\\1'], // Words finishing with "eu" are pluralized with a "x" excepted "pneu", "bleu", "émeu" // Les mots finissant en "eu" prennent un "x" au pluriel sauf "pneu", "bleu", "émeu" ['/(eu)x$/i', '\\1'], // Words finishing with "ou" are pluralized with a "s" excepted bijou, caillou, chou, genou, hibou, joujou, pou // Les mots finissant par "ou" prennent un "s" sauf bijou, caillou, chou, genou, hibou, joujou, pou ['/(bij|caill|ch|gen|hib|jouj|p)oux$/i', '\\1ou'], // French titles ['/^mes(dame|demoiselle)s$/', '_HumbugBox7ff99e199a36\\ma\\1'], ['/^Mes(dame|demoiselle)s$/', '_HumbugBox7ff99e199a36\\Ma\\1'], ['/^mes(sieur|seigneur)s$/', '_HumbugBox7ff99e199a36\\mon\\1'], ['/^Mes(sieur|seigneur)s$/', '_HumbugBox7ff99e199a36\\Mon\\1'], // Default rule ['/s$/i', ''], ]; /** * A list of words which should not be inflected. * This list is only used by singularize. */ private const UNINFLECTED = '/^(abcès|accès|abus|albatros|anchois|anglais|autobus|bois|brebis|carquois|cas|chas|colis|concours|corps|cours|cyprès|décès|devis|discours|dos|embarras|engrais|entrelacs|excès|fils|fois|gâchis|gars|glas|héros|intrus|jars|jus|kermès|lacis|legs|lilas|marais|mars|matelas|mépris|mets|mois|mors|obus|os|palais|paradis|parcours|pardessus|pays|plusieurs|poids|pois|pouls|printemps|processus|progrès|puits|pus|rabais|radis|recors|recours|refus|relais|remords|remous|rictus|rhinocéros|repas|rubis|sans|sas|secours|sens|souris|succès|talus|tapis|tas|taudis|temps|tiers|univers|velours|verglas|vernis|virus)$/i'; /** * {@inheritdoc} */ public function singularize(string $plural) : array { if ($this->isInflectedWord($plural)) { return [$plural]; } foreach (self::SINGULARIZE_REGEXP as $rule) { [$regexp, $replace] = $rule; if (1 === \preg_match($regexp, $plural)) { return [\preg_replace($regexp, $replace, $plural)]; } } return [$plural]; } /** * {@inheritdoc} */ public function pluralize(string $singular) : array { if ($this->isInflectedWord($singular)) { return [$singular]; } foreach (self::PLURALIZE_REGEXP as $rule) { [$regexp, $replace] = $rule; if (1 === \preg_match($regexp, $singular)) { return [\preg_replace($regexp, $replace, $singular)]; } } return [$singular . 's']; } private function isInflectedWord(string $word) : bool { return 1 === \preg_match(self::UNINFLECTED, $word); } } * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace _HumbugBox7ff99e199a36\Symfony\Component\String\Inflector; interface InflectorInterface { /** * Returns the singular forms of a string. * * If the method can't determine the form with certainty, several possible singulars are returned. * * @return string[] */ public function singularize(string $plural) : array; /** * Returns the plural forms of a string. * * If the method can't determine the form with certainty, several possible plurals are returned. * * @return string[] */ public function pluralize(string $singular) : array; } * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace _HumbugBox7ff99e199a36\Symfony\Component\String\Inflector; final class EnglishInflector implements InflectorInterface { /** * Map English plural to singular suffixes. * * @see http://english-zone.com/spelling/plurals.html */ private const PLURAL_MAP = [ // First entry: plural suffix, reversed // Second entry: length of plural suffix // Third entry: Whether the suffix may succeed a vowel // Fourth entry: Whether the suffix may succeed a consonant // Fifth entry: singular suffix, normal // bacteria (bacterium) ['airetcab', 8, \true, \true, 'bacterium'], // corpora (corpus) ['aroproc', 7, \true, \true, 'corpus'], // criteria (criterion) ['airetirc', 8, \true, \true, 'criterion'], // curricula (curriculum) ['alucirruc', 9, \true, \true, 'curriculum'], // genera (genus) ['areneg', 6, \true, \true, 'genus'], // media (medium) ['aidem', 5, \true, \true, 'medium'], // memoranda (memorandum) ['adnaromem', 9, \true, \true, 'memorandum'], // phenomena (phenomenon) ['anemonehp', 9, \true, \true, 'phenomenon'], // strata (stratum) ['atarts', 6, \true, \true, 'stratum'], // nebulae (nebula) ['ea', 2, \true, \true, 'a'], // services (service) ['secivres', 8, \true, \true, 'service'], // mice (mouse), lice (louse) ['eci', 3, \false, \true, 'ouse'], // geese (goose) ['esee', 4, \false, \true, 'oose'], // fungi (fungus), alumni (alumnus), syllabi (syllabus), radii (radius) ['i', 1, \true, \true, 'us'], // men (man), women (woman) ['nem', 3, \true, \true, 'man'], // children (child) ['nerdlihc', 8, \true, \true, 'child'], // oxen (ox) ['nexo', 4, \false, \false, 'ox'], // indices (index), appendices (appendix), prices (price) ['seci', 4, \false, \true, ['ex', 'ix', 'ice']], // codes (code) ['sedoc', 5, \false, \true, 'code'], // selfies (selfie) ['seifles', 7, \true, \true, 'selfie'], // zombies (zombie) ['seibmoz', 7, \true, \true, 'zombie'], // movies (movie) ['seivom', 6, \true, \true, 'movie'], // names (name) ['seman', 5, \true, \false, 'name'], // conspectuses (conspectus), prospectuses (prospectus) ['sesutcep', 8, \true, \true, 'pectus'], // feet (foot) ['teef', 4, \true, \true, 'foot'], // geese (goose) ['eseeg', 5, \true, \true, 'goose'], // teeth (tooth) ['hteet', 5, \true, \true, 'tooth'], // news (news) ['swen', 4, \true, \true, 'news'], // series (series) ['seires', 6, \true, \true, 'series'], // babies (baby) ['sei', 3, \false, \true, 'y'], // accesses (access), addresses (address), kisses (kiss) ['sess', 4, \true, \false, 'ss'], // statuses (status) ['sesutats', 8, \true, \true, 'status'], // article (articles), ancle (ancles) ['sel', 3, \true, \true, 'le'], // analyses (analysis), ellipses (ellipsis), fungi (fungus), // neuroses (neurosis), theses (thesis), emphases (emphasis), // oases (oasis), crises (crisis), houses (house), bases (base), // atlases (atlas) ['ses', 3, \true, \true, ['s', 'se', 'sis']], // objectives (objective), alternative (alternatives) ['sevit', 5, \true, \true, 'tive'], // drives (drive) ['sevird', 6, \false, \true, 'drive'], // lives (life), wives (wife) ['sevi', 4, \false, \true, 'ife'], // moves (move) ['sevom', 5, \true, \true, 'move'], // hooves (hoof), dwarves (dwarf), elves (elf), leaves (leaf), caves (cave), staves (staff) ['sev', 3, \true, \true, ['f', 've', 'ff']], // axes (axis), axes (ax), axes (axe) ['sexa', 4, \false, \false, ['ax', 'axe', 'axis']], // indexes (index), matrixes (matrix) ['sex', 3, \true, \false, 'x'], // quizzes (quiz) ['sezz', 4, \true, \false, 'z'], // bureaus (bureau) ['suae', 4, \false, \true, 'eau'], // fees (fee), trees (tree), employees (employee) ['see', 3, \true, \true, 'ee'], // edges (edge) ['segd', 4, \true, \true, 'dge'], // roses (rose), garages (garage), cassettes (cassette), // waltzes (waltz), heroes (hero), bushes (bush), arches (arch), // shoes (shoe) ['se', 2, \true, \true, ['', 'e']], // status (status) ['sutats', 6, \true, \true, 'status'], // tags (tag) ['s', 1, \true, \true, ''], // chateaux (chateau) ['xuae', 4, \false, \true, 'eau'], // people (person) ['elpoep', 6, \true, \true, 'person'], ]; /** * Map English singular to plural suffixes. * * @see http://english-zone.com/spelling/plurals.html */ private const SINGULAR_MAP = [ // First entry: singular suffix, reversed // Second entry: length of singular suffix // Third entry: Whether the suffix may succeed a vowel // Fourth entry: Whether the suffix may succeed a consonant // Fifth entry: plural suffix, normal // axes (axis) ['sixa', 4, \false, \false, 'axes'], // criterion (criteria) ['airetirc', 8, \false, \false, 'criterion'], // nebulae (nebula) ['aluben', 6, \false, \false, 'nebulae'], // children (child) ['dlihc', 5, \true, \true, 'children'], // prices (price) ['eci', 3, \false, \true, 'ices'], // services (service) ['ecivres', 7, \true, \true, 'services'], // lives (life), wives (wife) ['efi', 3, \false, \true, 'ives'], // selfies (selfie) ['eifles', 6, \true, \true, 'selfies'], // movies (movie) ['eivom', 5, \true, \true, 'movies'], // lice (louse) ['esuol', 5, \false, \true, 'lice'], // mice (mouse) ['esuom', 5, \false, \true, 'mice'], // geese (goose) ['esoo', 4, \false, \true, 'eese'], // houses (house), bases (base) ['es', 2, \true, \true, 'ses'], // geese (goose) ['esoog', 5, \true, \true, 'geese'], // caves (cave) ['ev', 2, \true, \true, 'ves'], // drives (drive) ['evird', 5, \false, \true, 'drives'], // objectives (objective), alternative (alternatives) ['evit', 4, \true, \true, 'tives'], // moves (move) ['evom', 4, \true, \true, 'moves'], // staves (staff) ['ffats', 5, \true, \true, 'staves'], // hooves (hoof), dwarves (dwarf), elves (elf), leaves (leaf) ['ff', 2, \true, \true, 'ffs'], // hooves (hoof), dwarves (dwarf), elves (elf), leaves (leaf) ['f', 1, \true, \true, ['fs', 'ves']], // arches (arch) ['hc', 2, \true, \true, 'ches'], // bushes (bush) ['hs', 2, \true, \true, 'shes'], // teeth (tooth) ['htoot', 5, \true, \true, 'teeth'], // albums (album) ['mubla', 5, \true, \true, 'albums'], // bacteria (bacterium), curricula (curriculum), media (medium), memoranda (memorandum), phenomena (phenomenon), strata (stratum) ['mu', 2, \true, \true, 'a'], // men (man), women (woman) ['nam', 3, \true, \true, 'men'], // people (person) ['nosrep', 6, \true, \true, ['persons', 'people']], // criteria (criterion) ['noiretirc', 9, \true, \true, 'criteria'], // phenomena (phenomenon) ['nonemonehp', 10, \true, \true, 'phenomena'], // echoes (echo) ['ohce', 4, \true, \true, 'echoes'], // heroes (hero) ['oreh', 4, \true, \true, 'heroes'], // atlases (atlas) ['salta', 5, \true, \true, 'atlases'], // aliases (alias) ['saila', 5, \true, \true, 'aliases'], // irises (iris) ['siri', 4, \true, \true, 'irises'], // analyses (analysis), ellipses (ellipsis), neuroses (neurosis) // theses (thesis), emphases (emphasis), oases (oasis), // crises (crisis) ['sis', 3, \true, \true, 'ses'], // accesses (access), addresses (address), kisses (kiss) ['ss', 2, \true, \false, 'sses'], // syllabi (syllabus) ['suballys', 8, \true, \true, 'syllabi'], // buses (bus) ['sub', 3, \true, \true, 'buses'], // circuses (circus) ['suc', 3, \true, \true, 'cuses'], // hippocampi (hippocampus) ['supmacoppih', 11, \false, \false, 'hippocampi'], // campuses (campus) ['sup', 3, \true, \true, 'puses'], // status (status) ['sutats', 6, \true, \true, ['status', 'statuses']], // conspectuses (conspectus), prospectuses (prospectus) ['sutcep', 6, \true, \true, 'pectuses'], // fungi (fungus), alumni (alumnus), syllabi (syllabus), radii (radius) ['su', 2, \true, \true, 'i'], // news (news) ['swen', 4, \true, \true, 'news'], // feet (foot) ['toof', 4, \true, \true, 'feet'], // chateaux (chateau), bureaus (bureau) ['uae', 3, \false, \true, ['eaus', 'eaux']], // oxen (ox) ['xo', 2, \false, \false, 'oxen'], // hoaxes (hoax) ['xaoh', 4, \true, \false, 'hoaxes'], // indices (index) ['xedni', 5, \false, \true, ['indicies', 'indexes']], // boxes (box) ['xo', 2, \false, \true, 'oxes'], // indexes (index), matrixes (matrix) ['x', 1, \true, \false, ['cies', 'xes']], // appendices (appendix) ['xi', 2, \false, \true, 'ices'], // babies (baby) ['y', 1, \false, \true, 'ies'], // quizzes (quiz) ['ziuq', 4, \true, \false, 'quizzes'], // waltzes (waltz) ['z', 1, \true, \true, 'zes'], ]; /** * A list of words which should not be inflected, reversed. */ private const UNINFLECTED = [ '', // data 'atad', // deer 'reed', // equipment 'tnempiuqe', // feedback 'kcabdeef', // fish 'hsif', // health 'htlaeh', // history 'yrotsih', // info 'ofni', // information 'noitamrofni', // money 'yenom', // moose 'esoom', // series 'seires', // sheep 'peehs', // species 'seiceps', // traffic 'ciffart', // aircraft 'tfarcria', // hardware 'erawdrah', ]; public function singularize(string $plural) : array { $pluralRev = \strrev($plural); $lowerPluralRev = \strtolower($pluralRev); $pluralLength = \strlen($lowerPluralRev); // Check if the word is one which is not inflected, return early if so if (\in_array($lowerPluralRev, self::UNINFLECTED, \true)) { return [$plural]; } // The outer loop iterates over the entries of the plural table // The inner loop $j iterates over the characters of the plural suffix // in the plural table to compare them with the characters of the actual // given plural suffix foreach (self::PLURAL_MAP as $map) { $suffix = $map[0]; $suffixLength = $map[1]; $j = 0; // Compare characters in the plural table and of the suffix of the // given plural one by one while ($suffix[$j] === $lowerPluralRev[$j]) { // Let $j point to the next character ++$j; // Successfully compared the last character // Add an entry with the singular suffix to the singular array if ($j === $suffixLength) { // Is there any character preceding the suffix in the plural string? if ($j < $pluralLength) { $nextIsVowel = \str_contains('aeiou', $lowerPluralRev[$j]); if (!$map[2] && $nextIsVowel) { // suffix may not succeed a vowel but next char is one break; } if (!$map[3] && !$nextIsVowel) { // suffix may not succeed a consonant but next char is one break; } } $newBase = \substr($plural, 0, $pluralLength - $suffixLength); $newSuffix = $map[4]; // Check whether the first character in the plural suffix // is uppercased. If yes, uppercase the first character in // the singular suffix too $firstUpper = \ctype_upper($pluralRev[$j - 1]); if (\is_array($newSuffix)) { $singulars = []; foreach ($newSuffix as $newSuffixEntry) { $singulars[] = $newBase . ($firstUpper ? \ucfirst($newSuffixEntry) : $newSuffixEntry); } return $singulars; } return [$newBase . ($firstUpper ? \ucfirst($newSuffix) : $newSuffix)]; } // Suffix is longer than word if ($j === $pluralLength) { break; } } } // Assume that plural and singular is identical return [$plural]; } public function pluralize(string $singular) : array { $singularRev = \strrev($singular); $lowerSingularRev = \strtolower($singularRev); $singularLength = \strlen($lowerSingularRev); // Check if the word is one which is not inflected, return early if so if (\in_array($lowerSingularRev, self::UNINFLECTED, \true)) { return [$singular]; } // The outer loop iterates over the entries of the singular table // The inner loop $j iterates over the characters of the singular suffix // in the singular table to compare them with the characters of the actual // given singular suffix foreach (self::SINGULAR_MAP as $map) { $suffix = $map[0]; $suffixLength = $map[1]; $j = 0; // Compare characters in the singular table and of the suffix of the // given plural one by one while ($suffix[$j] === $lowerSingularRev[$j]) { // Let $j point to the next character ++$j; // Successfully compared the last character // Add an entry with the plural suffix to the plural array if ($j === $suffixLength) { // Is there any character preceding the suffix in the plural string? if ($j < $singularLength) { $nextIsVowel = \str_contains('aeiou', $lowerSingularRev[$j]); if (!$map[2] && $nextIsVowel) { // suffix may not succeed a vowel but next char is one break; } if (!$map[3] && !$nextIsVowel) { // suffix may not succeed a consonant but next char is one break; } } $newBase = \substr($singular, 0, $singularLength - $suffixLength); $newSuffix = $map[4]; // Check whether the first character in the singular suffix // is uppercased. If yes, uppercase the first character in // the singular suffix too $firstUpper = \ctype_upper($singularRev[$j - 1]); if (\is_array($newSuffix)) { $plurals = []; foreach ($newSuffix as $newSuffixEntry) { $plurals[] = $newBase . ($firstUpper ? \ucfirst($newSuffixEntry) : $newSuffixEntry); } return $plurals; } return [$newBase . ($firstUpper ? \ucfirst($newSuffix) : $newSuffix)]; } // Suffix is longer than word if ($j === $singularLength) { break; } } } // Assume that plural is singular with a trailing `s` return [$singular . 's']; } } * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace _HumbugBox7ff99e199a36\Symfony\Component\String\Slugger; use _HumbugBox7ff99e199a36\Symfony\Component\String\AbstractUnicodeString; use _HumbugBox7ff99e199a36\Symfony\Component\String\UnicodeString; use _HumbugBox7ff99e199a36\Symfony\Contracts\Translation\LocaleAwareInterface; if (!\interface_exists(LocaleAwareInterface::class)) { throw new \LogicException('You cannot use the "Symfony\\Component\\String\\Slugger\\AsciiSlugger" as the "symfony/translation-contracts" package is not installed. Try running "composer require symfony/translation-contracts".'); } /** * @author Titouan Galopin */ class AsciiSlugger implements SluggerInterface, LocaleAwareInterface { private const LOCALE_TO_TRANSLITERATOR_ID = ['am' => 'Amharic-Latin', 'ar' => 'Arabic-Latin', 'az' => 'Azerbaijani-Latin', 'be' => 'Belarusian-Latin', 'bg' => 'Bulgarian-Latin', 'bn' => 'Bengali-Latin', 'de' => 'de-ASCII', 'el' => 'Greek-Latin', 'fa' => 'Persian-Latin', 'he' => 'Hebrew-Latin', 'hy' => 'Armenian-Latin', 'ka' => 'Georgian-Latin', 'kk' => 'Kazakh-Latin', 'ky' => 'Kirghiz-Latin', 'ko' => 'Korean-Latin', 'mk' => 'Macedonian-Latin', 'mn' => 'Mongolian-Latin', 'or' => 'Oriya-Latin', 'ps' => 'Pashto-Latin', 'ru' => 'Russian-Latin', 'sr' => 'Serbian-Latin', 'sr_Cyrl' => 'Serbian-Latin', 'th' => 'Thai-Latin', 'tk' => 'Turkmen-Latin', 'uk' => 'Ukrainian-Latin', 'uz' => 'Uzbek-Latin', 'zh' => 'Han-Latin']; private $defaultLocale; private $symbolsMap = ['en' => ['@' => 'at', '&' => 'and']]; /** * Cache of transliterators per locale. * * @var \Transliterator[] */ private $transliterators = []; /** * @param array|\Closure|null $symbolsMap */ public function __construct(?string $defaultLocale = null, $symbolsMap = null) { if (null !== $symbolsMap && !\is_array($symbolsMap) && !$symbolsMap instanceof \Closure) { throw new \TypeError(\sprintf('Argument 2 passed to "%s()" must be array, Closure or null, "%s" given.', __METHOD__, \gettype($symbolsMap))); } $this->defaultLocale = $defaultLocale; $this->symbolsMap = $symbolsMap ?? $this->symbolsMap; } /** * {@inheritdoc} */ public function setLocale($locale) { $this->defaultLocale = $locale; } /** * {@inheritdoc} */ public function getLocale() { return $this->defaultLocale; } /** * {@inheritdoc} */ public function slug(string $string, string $separator = '-', ?string $locale = null) : AbstractUnicodeString { $locale = $locale ?? $this->defaultLocale; $transliterator = []; if ($locale && ('de' === $locale || 0 === \strpos($locale, 'de_'))) { // Use the shortcut for German in UnicodeString::ascii() if possible (faster and no requirement on intl) $transliterator = ['de-ASCII']; } elseif (\function_exists('transliterator_transliterate') && $locale) { $transliterator = (array) $this->createTransliterator($locale); } if ($this->symbolsMap instanceof \Closure) { // If the symbols map is passed as a closure, there is no need to fallback to the parent locale // as the closure can just provide substitutions for all locales of interest. $symbolsMap = $this->symbolsMap; \array_unshift($transliterator, static function ($s) use($symbolsMap, $locale) { return $symbolsMap($s, $locale); }); } $unicodeString = (new UnicodeString($string))->ascii($transliterator); if (\is_array($this->symbolsMap)) { $map = null; if (isset($this->symbolsMap[$locale])) { $map = $this->symbolsMap[$locale]; } else { $parent = self::getParentLocale($locale); if ($parent && isset($this->symbolsMap[$parent])) { $map = $this->symbolsMap[$parent]; } } if ($map) { foreach ($map as $char => $replace) { $unicodeString = $unicodeString->replace($char, ' ' . $replace . ' '); } } } return $unicodeString->replaceMatches('/[^A-Za-z0-9]++/', $separator)->trim($separator); } private function createTransliterator(string $locale) : ?\Transliterator { if (\array_key_exists($locale, $this->transliterators)) { return $this->transliterators[$locale]; } // Exact locale supported, cache and return if ($id = self::LOCALE_TO_TRANSLITERATOR_ID[$locale] ?? null) { return $this->transliterators[$locale] = \Transliterator::create($id . '/BGN') ?? \Transliterator::create($id); } // Locale not supported and no parent, fallback to any-latin if (!($parent = self::getParentLocale($locale))) { return $this->transliterators[$locale] = null; } // Try to use the parent locale (ie. try "de" for "de_AT") and cache both locales if ($id = self::LOCALE_TO_TRANSLITERATOR_ID[$parent] ?? null) { $transliterator = \Transliterator::create($id . '/BGN') ?? \Transliterator::create($id); } return $this->transliterators[$locale] = $this->transliterators[$parent] = $transliterator ?? null; } private static function getParentLocale(?string $locale) : ?string { if (!$locale) { return null; } if (\false === ($str = \strrchr($locale, '_'))) { // no parent locale return null; } return \substr($locale, 0, -\strlen($str)); } } * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace _HumbugBox7ff99e199a36\Symfony\Component\String\Slugger; use _HumbugBox7ff99e199a36\Symfony\Component\String\AbstractUnicodeString; /** * Creates a URL-friendly slug from a given string. * * @author Titouan Galopin */ interface SluggerInterface { /** * Creates a slug for the given string and locale, using appropriate transliteration when needed. */ public function slug(string $string, string $separator = '-', ?string $locale = null) : AbstractUnicodeString; } * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace _HumbugBox7ff99e199a36\Symfony\Component\String; use _HumbugBox7ff99e199a36\Symfony\Component\String\Exception\ExceptionInterface; use _HumbugBox7ff99e199a36\Symfony\Component\String\Exception\InvalidArgumentException; use _HumbugBox7ff99e199a36\Symfony\Component\String\Exception\RuntimeException; /** * Represents a string of abstract Unicode characters. * * Unicode defines 3 types of "characters" (bytes, code points and grapheme clusters). * This class is the abstract type to use as a type-hint when the logic you want to * implement is Unicode-aware but doesn't care about code points vs grapheme clusters. * * @author Nicolas Grekas * * @throws ExceptionInterface */ abstract class AbstractUnicodeString extends AbstractString { public const NFC = \Normalizer::NFC; public const NFD = \Normalizer::NFD; public const NFKC = \Normalizer::NFKC; public const NFKD = \Normalizer::NFKD; // all ASCII letters sorted by typical frequency of occurrence private const ASCII = " eiasntrolud][cmp'\ng|hv.fb,:=-q10C2*yx)(L9AS/P\"EjMIk3>5T>', '<', '>', '-', '-', '-', '-', '-', '-', '-', '-', '-', '||', '/', '[', ']', '*', ',', '.', '<', '>', '<<', '>>', '[', ']', '[', ']', '[', ']', ',', '.', '[', ']', '<<', '>>', '<', '>', ',', '[', ']', '((', '))', '.', ',', '*', '/', '-', '/', '\\', '|', '||', '<<', '>>', '((', '))']; private static $transliterators = []; private static $tableZero; private static $tableWide; /** * @return static */ public static function fromCodePoints(int ...$codes) : self { $string = ''; foreach ($codes as $code) { if (0x80 > ($code %= 0x200000)) { $string .= \chr($code); } elseif (0x800 > $code) { $string .= \chr(0xc0 | $code >> 6) . \chr(0x80 | $code & 0x3f); } elseif (0x10000 > $code) { $string .= \chr(0xe0 | $code >> 12) . \chr(0x80 | $code >> 6 & 0x3f) . \chr(0x80 | $code & 0x3f); } else { $string .= \chr(0xf0 | $code >> 18) . \chr(0x80 | $code >> 12 & 0x3f) . \chr(0x80 | $code >> 6 & 0x3f) . \chr(0x80 | $code & 0x3f); } } return new static($string); } /** * Generic UTF-8 to ASCII transliteration. * * Install the intl extension for best results. * * @param string[]|\Transliterator[]|\Closure[] $rules See "*-Latin" rules from Transliterator::listIDs() */ public function ascii(array $rules = []) : self { $str = clone $this; $s = $str->string; $str->string = ''; \array_unshift($rules, 'nfd'); $rules[] = 'latin-ascii'; if (\function_exists('transliterator_transliterate')) { $rules[] = 'any-latin/bgn'; } $rules[] = 'nfkd'; $rules[] = '[:nonspacing mark:] remove'; while (\strlen($s) - 1 > ($i = \strspn($s, self::ASCII))) { if (0 < --$i) { $str->string .= \substr($s, 0, $i); $s = \substr($s, $i); } if (!($rule = \array_shift($rules))) { $rules = []; // An empty rule interrupts the next ones } if ($rule instanceof \Transliterator) { $s = $rule->transliterate($s); } elseif ($rule instanceof \Closure) { $s = $rule($s); } elseif ($rule) { if ('nfd' === ($rule = \strtolower($rule))) { \normalizer_is_normalized($s, self::NFD) ?: ($s = \normalizer_normalize($s, self::NFD)); } elseif ('nfkd' === $rule) { \normalizer_is_normalized($s, self::NFKD) ?: ($s = \normalizer_normalize($s, self::NFKD)); } elseif ('[:nonspacing mark:] remove' === $rule) { $s = \preg_replace('/\\p{Mn}++/u', '', $s); } elseif ('latin-ascii' === $rule) { $s = \str_replace(self::TRANSLIT_FROM, self::TRANSLIT_TO, $s); } elseif ('de-ascii' === $rule) { $s = \preg_replace("/([AUO])̈(?=\\p{Ll})/u", '$1e', $s); $s = \str_replace(["ä", "ö", "ü", "Ä", "Ö", "Ü"], ['ae', 'oe', 'ue', 'AE', 'OE', 'UE'], $s); } elseif (\function_exists('transliterator_transliterate')) { if (null === ($transliterator = self::$transliterators[$rule] ?? (self::$transliterators[$rule] = \Transliterator::create($rule)))) { if ('any-latin/bgn' === $rule) { $rule = 'any-latin'; $transliterator = self::$transliterators[$rule] ?? (self::$transliterators[$rule] = \Transliterator::create($rule)); } if (null === $transliterator) { throw new InvalidArgumentException(\sprintf('Unknown transliteration rule "%s".', $rule)); } self::$transliterators['any-latin/bgn'] = $transliterator; } $s = $transliterator->transliterate($s); } } elseif (!\function_exists('iconv')) { $s = \preg_replace('/[^\\x00-\\x7F]/u', '?', $s); } else { $s = @\preg_replace_callback('/[^\\x00-\\x7F]/u', static function ($c) { $c = (string) \iconv('UTF-8', 'ASCII//TRANSLIT', $c[0]); if ('' === $c && '' === \iconv('UTF-8', 'ASCII//TRANSLIT', '²')) { throw new \LogicException(\sprintf('"%s" requires a translit-able iconv implementation, try installing "gnu-libiconv" if you\'re using Alpine Linux.', static::class)); } return 1 < \strlen($c) ? \ltrim($c, '\'`"^~') : ('' !== $c ? $c : '?'); }, $s); } } $str->string .= $s; return $str; } public function camel() : parent { $str = clone $this; $str->string = \str_replace(' ', '', \preg_replace_callback('/\\b.(?!\\p{Lu})/u', static function ($m) use(&$i) { return 1 === ++$i ? 'İ' === $m[0] ? 'i̇' : \mb_strtolower($m[0], 'UTF-8') : \mb_convert_case($m[0], \MB_CASE_TITLE, 'UTF-8'); }, \preg_replace('/[^\\pL0-9]++/u', ' ', $this->string))); return $str; } /** * @return int[] */ public function codePointsAt(int $offset) : array { $str = $this->slice($offset, 1); if ('' === $str->string) { return []; } $codePoints = []; foreach (\preg_split('//u', $str->string, -1, \PREG_SPLIT_NO_EMPTY) as $c) { $codePoints[] = \mb_ord($c, 'UTF-8'); } return $codePoints; } public function folded(bool $compat = \true) : parent { $str = clone $this; if (!$compat || \PHP_VERSION_ID < 70300 || !\defined('Normalizer::NFKC_CF')) { $str->string = \normalizer_normalize($str->string, $compat ? \Normalizer::NFKC : \Normalizer::NFC); $str->string = \mb_strtolower(\str_replace(self::FOLD_FROM, self::FOLD_TO, $str->string), 'UTF-8'); } else { $str->string = \normalizer_normalize($str->string, \Normalizer::NFKC_CF); } return $str; } public function join(array $strings, ?string $lastGlue = null) : parent { $str = clone $this; $tail = null !== $lastGlue && 1 < \count($strings) ? $lastGlue . \array_pop($strings) : ''; $str->string = \implode($this->string, $strings) . $tail; if (!\preg_match('//u', $str->string)) { throw new InvalidArgumentException('Invalid UTF-8 string.'); } return $str; } public function lower() : parent { $str = clone $this; $str->string = \mb_strtolower(\str_replace('İ', 'i̇', $str->string), 'UTF-8'); return $str; } public function match(string $regexp, int $flags = 0, int $offset = 0) : array { $match = (\PREG_PATTERN_ORDER | \PREG_SET_ORDER) & $flags ? 'preg_match_all' : 'preg_match'; if ($this->ignoreCase) { $regexp .= 'i'; } \set_error_handler(static function ($t, $m) { throw new InvalidArgumentException($m); }); try { if (\false === $match($regexp . 'u', $this->string, $matches, $flags | \PREG_UNMATCHED_AS_NULL, $offset)) { $lastError = \preg_last_error(); foreach (\get_defined_constants(\true)['pcre'] as $k => $v) { if ($lastError === $v && '_ERROR' === \substr($k, -6)) { throw new RuntimeException('Matching failed with ' . $k . '.'); } } throw new RuntimeException('Matching failed with unknown error code.'); } } finally { \restore_error_handler(); } return $matches; } /** * @return static */ public function normalize(int $form = self::NFC) : self { if (!\in_array($form, [self::NFC, self::NFD, self::NFKC, self::NFKD])) { throw new InvalidArgumentException('Unsupported normalization form.'); } $str = clone $this; \normalizer_is_normalized($str->string, $form) ?: ($str->string = \normalizer_normalize($str->string, $form)); return $str; } public function padBoth(int $length, string $padStr = ' ') : parent { if ('' === $padStr || !\preg_match('//u', $padStr)) { throw new InvalidArgumentException('Invalid UTF-8 string.'); } $pad = clone $this; $pad->string = $padStr; return $this->pad($length, $pad, \STR_PAD_BOTH); } public function padEnd(int $length, string $padStr = ' ') : parent { if ('' === $padStr || !\preg_match('//u', $padStr)) { throw new InvalidArgumentException('Invalid UTF-8 string.'); } $pad = clone $this; $pad->string = $padStr; return $this->pad($length, $pad, \STR_PAD_RIGHT); } public function padStart(int $length, string $padStr = ' ') : parent { if ('' === $padStr || !\preg_match('//u', $padStr)) { throw new InvalidArgumentException('Invalid UTF-8 string.'); } $pad = clone $this; $pad->string = $padStr; return $this->pad($length, $pad, \STR_PAD_LEFT); } public function replaceMatches(string $fromRegexp, $to) : parent { if ($this->ignoreCase) { $fromRegexp .= 'i'; } if (\is_array($to) || $to instanceof \Closure) { if (!\is_callable($to)) { throw new \TypeError(\sprintf('Argument 2 passed to "%s::replaceMatches()" must be callable, array given.', static::class)); } $replace = 'preg_replace_callback'; $to = static function (array $m) use($to) : string { $to = $to($m); if ('' !== $to && (!\is_string($to) || !\preg_match('//u', $to))) { throw new InvalidArgumentException('Replace callback must return a valid UTF-8 string.'); } return $to; }; } elseif ('' !== $to && !\preg_match('//u', $to)) { throw new InvalidArgumentException('Invalid UTF-8 string.'); } else { $replace = 'preg_replace'; } \set_error_handler(static function ($t, $m) { throw new InvalidArgumentException($m); }); try { if (null === ($string = $replace($fromRegexp . 'u', $to, $this->string))) { $lastError = \preg_last_error(); foreach (\get_defined_constants(\true)['pcre'] as $k => $v) { if ($lastError === $v && '_ERROR' === \substr($k, -6)) { throw new RuntimeException('Matching failed with ' . $k . '.'); } } throw new RuntimeException('Matching failed with unknown error code.'); } } finally { \restore_error_handler(); } $str = clone $this; $str->string = $string; return $str; } public function reverse() : parent { $str = clone $this; $str->string = \implode('', \array_reverse(\preg_split('/(\\X)/u', $str->string, -1, \PREG_SPLIT_DELIM_CAPTURE | \PREG_SPLIT_NO_EMPTY))); return $str; } public function snake() : parent { $str = $this->camel(); $str->string = \mb_strtolower(\preg_replace(['/(\\p{Lu}+)(\\p{Lu}\\p{Ll})/u', '/([\\p{Ll}0-9])(\\p{Lu})/u'], '_HumbugBox7ff99e199a36\\1_\\2', $str->string), 'UTF-8'); return $str; } public function title(bool $allWords = \false) : parent { $str = clone $this; $limit = $allWords ? -1 : 1; $str->string = \preg_replace_callback('/\\b./u', static function (array $m) : string { return \mb_convert_case($m[0], \MB_CASE_TITLE, 'UTF-8'); }, $str->string, $limit); return $str; } public function trim(string $chars = " \t\n\r\x00\v\f ") : parent { if (" \t\n\r\x00\v\f " !== $chars && !\preg_match('//u', $chars)) { throw new InvalidArgumentException('Invalid UTF-8 chars.'); } $chars = \preg_quote($chars); $str = clone $this; $str->string = \preg_replace("{^[{$chars}]++|[{$chars}]++\$}uD", '', $str->string); return $str; } public function trimEnd(string $chars = " \t\n\r\x00\v\f ") : parent { if (" \t\n\r\x00\v\f " !== $chars && !\preg_match('//u', $chars)) { throw new InvalidArgumentException('Invalid UTF-8 chars.'); } $chars = \preg_quote($chars); $str = clone $this; $str->string = \preg_replace("{[{$chars}]++\$}uD", '', $str->string); return $str; } public function trimPrefix($prefix) : parent { if (!$this->ignoreCase) { return parent::trimPrefix($prefix); } $str = clone $this; if ($prefix instanceof \Traversable) { $prefix = \iterator_to_array($prefix, \false); } elseif ($prefix instanceof parent) { $prefix = $prefix->string; } $prefix = \implode('|', \array_map('preg_quote', (array) $prefix)); $str->string = \preg_replace("{^(?:{$prefix})}iuD", '', $this->string); return $str; } public function trimStart(string $chars = " \t\n\r\x00\v\f ") : parent { if (" \t\n\r\x00\v\f " !== $chars && !\preg_match('//u', $chars)) { throw new InvalidArgumentException('Invalid UTF-8 chars.'); } $chars = \preg_quote($chars); $str = clone $this; $str->string = \preg_replace("{^[{$chars}]++}uD", '', $str->string); return $str; } public function trimSuffix($suffix) : parent { if (!$this->ignoreCase) { return parent::trimSuffix($suffix); } $str = clone $this; if ($suffix instanceof \Traversable) { $suffix = \iterator_to_array($suffix, \false); } elseif ($suffix instanceof parent) { $suffix = $suffix->string; } $suffix = \implode('|', \array_map('preg_quote', (array) $suffix)); $str->string = \preg_replace("{(?:{$suffix})\$}iuD", '', $this->string); return $str; } public function upper() : parent { $str = clone $this; $str->string = \mb_strtoupper($str->string, 'UTF-8'); if (\PHP_VERSION_ID < 70300) { $str->string = \str_replace(self::UPPER_FROM, self::UPPER_TO, $str->string); } return $str; } public function width(bool $ignoreAnsiDecoration = \true) : int { $width = 0; $s = \str_replace(["\x00", "\x05", "\x07"], '', $this->string); if (\false !== \strpos($s, "\r")) { $s = \str_replace(["\r\n", "\r"], "\n", $s); } if (!$ignoreAnsiDecoration) { $s = \preg_replace('/[\\p{Cc}\\x7F]++/u', '', $s); } foreach (\explode("\n", $s) as $s) { if ($ignoreAnsiDecoration) { $s = \preg_replace('/(?:\\x1B(?: \\[ [\\x30-\\x3F]*+ [\\x20-\\x2F]*+ [\\x40-\\x7E] | [P\\]X^_] .*? \\x1B\\\\ | [\\x41-\\x7E] )|[\\p{Cc}\\x7F]++)/xu', '', $s); } $lineWidth = $this->wcswidth($s); if ($lineWidth > $width) { $width = $lineWidth; } } return $width; } /** * @return static */ private function pad(int $len, self $pad, int $type) : parent { $sLen = $this->length(); if ($len <= $sLen) { return clone $this; } $padLen = $pad->length(); $freeLen = $len - $sLen; $len = $freeLen % $padLen; switch ($type) { case \STR_PAD_RIGHT: return $this->append(\str_repeat($pad->string, \intdiv($freeLen, $padLen)) . ($len ? $pad->slice(0, $len) : '')); case \STR_PAD_LEFT: return $this->prepend(\str_repeat($pad->string, \intdiv($freeLen, $padLen)) . ($len ? $pad->slice(0, $len) : '')); case \STR_PAD_BOTH: $freeLen /= 2; $rightLen = \ceil($freeLen); $len = $rightLen % $padLen; $str = $this->append(\str_repeat($pad->string, \intdiv($rightLen, $padLen)) . ($len ? $pad->slice(0, $len) : '')); $leftLen = \floor($freeLen); $len = $leftLen % $padLen; return $str->prepend(\str_repeat($pad->string, \intdiv($leftLen, $padLen)) . ($len ? $pad->slice(0, $len) : '')); default: throw new InvalidArgumentException('Invalid padding type.'); } } /** * Based on https://github.com/jquast/wcwidth, a Python implementation of https://www.cl.cam.ac.uk/~mgk25/ucs/wcwidth.c. */ private function wcswidth(string $string) : int { $width = 0; foreach (\preg_split('//u', $string, -1, \PREG_SPLIT_NO_EMPTY) as $c) { $codePoint = \mb_ord($c, 'UTF-8'); if (0 === $codePoint || 0x34f === $codePoint || 0x200b <= $codePoint && 0x200f >= $codePoint || 0x2028 === $codePoint || 0x2029 === $codePoint || 0x202a <= $codePoint && 0x202e >= $codePoint || 0x2060 <= $codePoint && 0x2063 >= $codePoint) { continue; } // Non printable characters if (32 > $codePoint || 0x7f <= $codePoint && 0xa0 > $codePoint) { return -1; } if (null === self::$tableZero) { self::$tableZero = (require __DIR__ . '/Resources/data/wcswidth_table_zero.php'); } if ($codePoint >= self::$tableZero[0][0] && $codePoint <= self::$tableZero[$ubound = \count(self::$tableZero) - 1][1]) { $lbound = 0; while ($ubound >= $lbound) { $mid = \floor(($lbound + $ubound) / 2); if ($codePoint > self::$tableZero[$mid][1]) { $lbound = $mid + 1; } elseif ($codePoint < self::$tableZero[$mid][0]) { $ubound = $mid - 1; } else { continue 2; } } } if (null === self::$tableWide) { self::$tableWide = (require __DIR__ . '/Resources/data/wcswidth_table_wide.php'); } if ($codePoint >= self::$tableWide[0][0] && $codePoint <= self::$tableWide[$ubound = \count(self::$tableWide) - 1][1]) { $lbound = 0; while ($ubound >= $lbound) { $mid = \floor(($lbound + $ubound) / 2); if ($codePoint > self::$tableWide[$mid][1]) { $lbound = $mid + 1; } elseif ($codePoint < self::$tableWide[$mid][0]) { $ubound = $mid - 1; } else { $width += 2; continue 2; } } } ++$width; } return $width; } } Copyright (c) 2019-present Fabien Potencier Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace _HumbugBox7ff99e199a36\Symfony\Component\String; /** * A string whose value is computed lazily by a callback. * * @author Nicolas Grekas */ class LazyString implements \Stringable, \JsonSerializable { private $value; /** * @param callable|array $callback A callable or a [Closure, method] lazy-callable * * @return static */ public static function fromCallable($callback, ...$arguments) : self { if (!\is_callable($callback) && !(\is_array($callback) && isset($callback[0]) && $callback[0] instanceof \Closure && 2 >= \count($callback))) { throw new \TypeError(\sprintf('Argument 1 passed to "%s()" must be a callable or a [Closure, method] lazy-callable, "%s" given.', __METHOD__, \get_debug_type($callback))); } $lazyString = new static(); $lazyString->value = static function () use(&$callback, &$arguments, &$value) : string { if (null !== $arguments) { if (!\is_callable($callback)) { $callback[0] = $callback[0](); $callback[1] = $callback[1] ?? '__invoke'; } $value = $callback(...$arguments); $callback = self::getPrettyName($callback); $arguments = null; } return $value ?? ''; }; return $lazyString; } /** * @param string|int|float|bool|\Stringable $value * * @return static */ public static function fromStringable($value) : self { if (!self::isStringable($value)) { throw new \TypeError(\sprintf('Argument 1 passed to "%s()" must be a scalar or a stringable object, "%s" given.', __METHOD__, \get_debug_type($value))); } if (\is_object($value)) { return static::fromCallable([$value, '__toString']); } $lazyString = new static(); $lazyString->value = (string) $value; return $lazyString; } /** * Tells whether the provided value can be cast to string. */ public static final function isStringable($value) : bool { return \is_string($value) || $value instanceof self || (\is_object($value) ? \method_exists($value, '__toString') : \is_scalar($value)); } /** * Casts scalars and stringable objects to strings. * * @param object|string|int|float|bool $value * * @throws \TypeError When the provided value is not stringable */ public static final function resolve($value) : string { return $value; } /** * @return string */ public function __toString() { if (\is_string($this->value)) { return $this->value; } try { return $this->value = ($this->value)(); } catch (\Throwable $e) { if (\TypeError::class === \get_class($e) && __FILE__ === $e->getFile()) { $type = \explode(', ', $e->getMessage()); $type = \substr(\array_pop($type), 0, -\strlen(' returned')); $r = new \ReflectionFunction($this->value); $callback = $r->getStaticVariables()['callback']; $e = new \TypeError(\sprintf('Return value of %s() passed to %s::fromCallable() must be of the type string, %s returned.', $callback, static::class, $type)); } if (\PHP_VERSION_ID < 70400) { // leverage the ErrorHandler component with graceful fallback when it's not available return \trigger_error($e, \E_USER_ERROR); } throw $e; } } public function __sleep() : array { $this->__toString(); return ['value']; } public function jsonSerialize() : string { return $this->__toString(); } private function __construct() { } private static function getPrettyName(callable $callback) : string { if (\is_string($callback)) { return $callback; } if (\is_array($callback)) { $class = \is_object($callback[0]) ? \get_debug_type($callback[0]) : $callback[0]; $method = $callback[1]; } elseif ($callback instanceof \Closure) { $r = new \ReflectionFunction($callback); if (\str_contains($r->name, '{closure') || !($class = \PHP_VERSION_ID >= 80111 ? $r->getClosureCalledClass() : $r->getClosureScopeClass())) { return $r->name; } $class = $class->name; $method = $r->name; } else { $class = \get_debug_type($callback); $method = '__invoke'; } return $class . '::' . $method; } } * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace _HumbugBox7ff99e199a36\Symfony\Component\String; if (!\function_exists(u::class)) { function u(?string $string = '') : UnicodeString { return new UnicodeString($string ?? ''); } } if (!\function_exists(b::class)) { function b(?string $string = '') : ByteString { return new ByteString($string ?? ''); } } if (!\function_exists(s::class)) { /** * @return UnicodeString|ByteString */ function s(?string $string = '') : AbstractString { $string = $string ?? ''; return \preg_match('//u', $string) ? new UnicodeString($string) : new ByteString($string); } } * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace _HumbugBox7ff99e199a36\Symfony\Component\String; use _HumbugBox7ff99e199a36\Symfony\Component\String\Exception\ExceptionInterface; use _HumbugBox7ff99e199a36\Symfony\Component\String\Exception\InvalidArgumentException; /** * Represents a string of Unicode grapheme clusters encoded as UTF-8. * * A letter followed by combining characters (accents typically) form what Unicode defines * as a grapheme cluster: a character as humans mean it in written texts. This class knows * about the concept and won't split a letter apart from its combining accents. It also * ensures all string comparisons happen on their canonically-composed representation, * ignoring e.g. the order in which accents are listed when a letter has many of them. * * @see https://unicode.org/reports/tr15/ * * @author Nicolas Grekas * @author Hugo Hamon * * @throws ExceptionInterface */ class UnicodeString extends AbstractUnicodeString { public function __construct(string $string = '') { $this->string = \normalizer_is_normalized($string) ? $string : \normalizer_normalize($string); if (\false === $this->string) { throw new InvalidArgumentException('Invalid UTF-8 string.'); } } public function append(string ...$suffix) : AbstractString { $str = clone $this; $str->string = $this->string . (1 >= \count($suffix) ? $suffix[0] ?? '' : \implode('', $suffix)); \normalizer_is_normalized($str->string) ?: ($str->string = \normalizer_normalize($str->string)); if (\false === $str->string) { throw new InvalidArgumentException('Invalid UTF-8 string.'); } return $str; } public function chunk(int $length = 1) : array { if (1 > $length) { throw new InvalidArgumentException('The chunk length must be greater than zero.'); } if ('' === $this->string) { return []; } $rx = '/('; while (65535 < $length) { $rx .= '\\X{65535}'; $length -= 65535; } $rx .= '\\X{' . $length . '})/u'; $str = clone $this; $chunks = []; foreach (\preg_split($rx, $this->string, -1, \PREG_SPLIT_DELIM_CAPTURE | \PREG_SPLIT_NO_EMPTY) as $chunk) { $str->string = $chunk; $chunks[] = clone $str; } return $chunks; } public function endsWith($suffix) : bool { if ($suffix instanceof AbstractString) { $suffix = $suffix->string; } elseif (\is_array($suffix) || $suffix instanceof \Traversable) { return parent::endsWith($suffix); } else { $suffix = (string) $suffix; } $form = null === $this->ignoreCase ? \Normalizer::NFD : \Normalizer::NFC; \normalizer_is_normalized($suffix, $form) ?: ($suffix = \normalizer_normalize($suffix, $form)); if ('' === $suffix || \false === $suffix) { return \false; } if ($this->ignoreCase) { return 0 === \mb_stripos(\grapheme_extract($this->string, \strlen($suffix), \GRAPHEME_EXTR_MAXBYTES, \strlen($this->string) - \strlen($suffix)), $suffix, 0, 'UTF-8'); } return $suffix === \grapheme_extract($this->string, \strlen($suffix), \GRAPHEME_EXTR_MAXBYTES, \strlen($this->string) - \strlen($suffix)); } public function equalsTo($string) : bool { if ($string instanceof AbstractString) { $string = $string->string; } elseif (\is_array($string) || $string instanceof \Traversable) { return parent::equalsTo($string); } else { $string = (string) $string; } $form = null === $this->ignoreCase ? \Normalizer::NFD : \Normalizer::NFC; \normalizer_is_normalized($string, $form) ?: ($string = \normalizer_normalize($string, $form)); if ('' !== $string && \false !== $string && $this->ignoreCase) { return \strlen($string) === \strlen($this->string) && 0 === \mb_stripos($this->string, $string, 0, 'UTF-8'); } return $string === $this->string; } public function indexOf($needle, int $offset = 0) : ?int { if ($needle instanceof AbstractString) { $needle = $needle->string; } elseif (\is_array($needle) || $needle instanceof \Traversable) { return parent::indexOf($needle, $offset); } else { $needle = (string) $needle; } $form = null === $this->ignoreCase ? \Normalizer::NFD : \Normalizer::NFC; \normalizer_is_normalized($needle, $form) ?: ($needle = \normalizer_normalize($needle, $form)); if ('' === $needle || \false === $needle) { return null; } try { $i = $this->ignoreCase ? \grapheme_stripos($this->string, $needle, $offset) : \grapheme_strpos($this->string, $needle, $offset); } catch (\ValueError $e) { return null; } return \false === $i ? null : $i; } public function indexOfLast($needle, int $offset = 0) : ?int { if ($needle instanceof AbstractString) { $needle = $needle->string; } elseif (\is_array($needle) || $needle instanceof \Traversable) { return parent::indexOfLast($needle, $offset); } else { $needle = (string) $needle; } $form = null === $this->ignoreCase ? \Normalizer::NFD : \Normalizer::NFC; \normalizer_is_normalized($needle, $form) ?: ($needle = \normalizer_normalize($needle, $form)); if ('' === $needle || \false === $needle) { return null; } $string = $this->string; if (0 > $offset) { // workaround https://bugs.php.net/74264 if (0 > ($offset += \grapheme_strlen($needle))) { $string = \grapheme_substr($string, 0, $offset); } $offset = 0; } $i = $this->ignoreCase ? \grapheme_strripos($string, $needle, $offset) : \grapheme_strrpos($string, $needle, $offset); return \false === $i ? null : $i; } public function join(array $strings, ?string $lastGlue = null) : AbstractString { $str = parent::join($strings, $lastGlue); \normalizer_is_normalized($str->string) ?: ($str->string = \normalizer_normalize($str->string)); return $str; } public function length() : int { return \grapheme_strlen($this->string); } /** * @return static */ public function normalize(int $form = self::NFC) : parent { $str = clone $this; if (\in_array($form, [self::NFC, self::NFKC], \true)) { \normalizer_is_normalized($str->string, $form) ?: ($str->string = \normalizer_normalize($str->string, $form)); } elseif (!\in_array($form, [self::NFD, self::NFKD], \true)) { throw new InvalidArgumentException('Unsupported normalization form.'); } elseif (!\normalizer_is_normalized($str->string, $form)) { $str->string = \normalizer_normalize($str->string, $form); $str->ignoreCase = null; } return $str; } public function prepend(string ...$prefix) : AbstractString { $str = clone $this; $str->string = (1 >= \count($prefix) ? $prefix[0] ?? '' : \implode('', $prefix)) . $this->string; \normalizer_is_normalized($str->string) ?: ($str->string = \normalizer_normalize($str->string)); if (\false === $str->string) { throw new InvalidArgumentException('Invalid UTF-8 string.'); } return $str; } public function replace(string $from, string $to) : AbstractString { $str = clone $this; \normalizer_is_normalized($from) ?: ($from = \normalizer_normalize($from)); if ('' !== $from && \false !== $from) { $tail = $str->string; $result = ''; $indexOf = $this->ignoreCase ? 'grapheme_stripos' : 'grapheme_strpos'; while ('' !== $tail && \false !== ($i = $indexOf($tail, $from))) { $slice = \grapheme_substr($tail, 0, $i); $result .= $slice . $to; $tail = \substr($tail, \strlen($slice) + \strlen($from)); } $str->string = $result . $tail; \normalizer_is_normalized($str->string) ?: ($str->string = \normalizer_normalize($str->string)); if (\false === $str->string) { throw new InvalidArgumentException('Invalid UTF-8 string.'); } } return $str; } public function replaceMatches(string $fromRegexp, $to) : AbstractString { $str = parent::replaceMatches($fromRegexp, $to); \normalizer_is_normalized($str->string) ?: ($str->string = \normalizer_normalize($str->string)); return $str; } public function slice(int $start = 0, ?int $length = null) : AbstractString { $str = clone $this; if (\PHP_VERSION_ID < 80000 && 0 > $start && \grapheme_strlen($this->string) < -$start) { $start = 0; } $str->string = (string) \grapheme_substr($this->string, $start, $length ?? 2147483647); return $str; } public function splice(string $replacement, int $start = 0, ?int $length = null) : AbstractString { $str = clone $this; if (\PHP_VERSION_ID < 80000 && 0 > $start && \grapheme_strlen($this->string) < -$start) { $start = 0; } $start = $start ? \strlen(\grapheme_substr($this->string, 0, $start)) : 0; $length = $length ? \strlen(\grapheme_substr($this->string, $start, $length ?? 2147483647)) : $length; $str->string = \substr_replace($this->string, $replacement, $start, $length ?? 2147483647); \normalizer_is_normalized($str->string) ?: ($str->string = \normalizer_normalize($str->string)); if (\false === $str->string) { throw new InvalidArgumentException('Invalid UTF-8 string.'); } return $str; } public function split(string $delimiter, ?int $limit = null, ?int $flags = null) : array { if (1 > ($limit = $limit ?? 2147483647)) { throw new InvalidArgumentException('Split limit must be a positive integer.'); } if ('' === $delimiter) { throw new InvalidArgumentException('Split delimiter is empty.'); } if (null !== $flags) { return parent::split($delimiter . 'u', $limit, $flags); } \normalizer_is_normalized($delimiter) ?: ($delimiter = \normalizer_normalize($delimiter)); if (\false === $delimiter) { throw new InvalidArgumentException('Split delimiter is not a valid UTF-8 string.'); } $str = clone $this; $tail = $this->string; $chunks = []; $indexOf = $this->ignoreCase ? 'grapheme_stripos' : 'grapheme_strpos'; while (1 < $limit && \false !== ($i = $indexOf($tail, $delimiter))) { $str->string = \grapheme_substr($tail, 0, $i); $chunks[] = clone $str; $tail = \substr($tail, \strlen($str->string) + \strlen($delimiter)); --$limit; } $str->string = $tail; $chunks[] = clone $str; return $chunks; } public function startsWith($prefix) : bool { if ($prefix instanceof AbstractString) { $prefix = $prefix->string; } elseif (\is_array($prefix) || $prefix instanceof \Traversable) { return parent::startsWith($prefix); } else { $prefix = (string) $prefix; } $form = null === $this->ignoreCase ? \Normalizer::NFD : \Normalizer::NFC; \normalizer_is_normalized($prefix, $form) ?: ($prefix = \normalizer_normalize($prefix, $form)); if ('' === $prefix || \false === $prefix) { return \false; } if ($this->ignoreCase) { return 0 === \mb_stripos(\grapheme_extract($this->string, \strlen($prefix), \GRAPHEME_EXTR_MAXBYTES), $prefix, 0, 'UTF-8'); } return $prefix === \grapheme_extract($this->string, \strlen($prefix), \GRAPHEME_EXTR_MAXBYTES); } public function __wakeup() { if (!\is_string($this->string)) { throw new \BadMethodCallException('Cannot unserialize ' . __CLASS__); } \normalizer_is_normalized($this->string) ?: ($this->string = \normalizer_normalize($this->string)); } public function __clone() { if (null === $this->ignoreCase) { \normalizer_is_normalized($this->string) ?: ($this->string = \normalizer_normalize($this->string)); } $this->ignoreCase = \false; } } * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace _HumbugBox7ff99e199a36\Symfony\Component\String; use _HumbugBox7ff99e199a36\Symfony\Component\String\Exception\ExceptionInterface; use _HumbugBox7ff99e199a36\Symfony\Component\String\Exception\InvalidArgumentException; use _HumbugBox7ff99e199a36\Symfony\Component\String\Exception\RuntimeException; /** * Represents a binary-safe string of bytes. * * @author Nicolas Grekas * @author Hugo Hamon * * @throws ExceptionInterface */ class ByteString extends AbstractString { private const ALPHABET_ALPHANUMERIC = '123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz'; public function __construct(string $string = '') { $this->string = $string; } /* * The following method was derived from code of the Hack Standard Library (v4.40 - 2020-05-03) * * https://github.com/hhvm/hsl/blob/80a42c02f036f72a42f0415e80d6b847f4bf62d5/src/random/private.php#L16 * * Code subject to the MIT license (https://github.com/hhvm/hsl/blob/master/LICENSE). * * Copyright (c) 2004-2020, Facebook, Inc. (https://www.facebook.com/) */ public static function fromRandom(int $length = 16, ?string $alphabet = null) : self { if ($length <= 0) { throw new InvalidArgumentException(\sprintf('A strictly positive length is expected, "%d" given.', $length)); } $alphabet = $alphabet ?? self::ALPHABET_ALPHANUMERIC; $alphabetSize = \strlen($alphabet); $bits = (int) \ceil(\log($alphabetSize, 2.0)); if ($bits <= 0 || $bits > 56) { throw new InvalidArgumentException('The length of the alphabet must in the [2^1, 2^56] range.'); } $ret = ''; while ($length > 0) { $urandomLength = (int) \ceil(2 * $length * $bits / 8.0); $data = \random_bytes($urandomLength); $unpackedData = 0; $unpackedBits = 0; for ($i = 0; $i < $urandomLength && $length > 0; ++$i) { // Unpack 8 bits $unpackedData = $unpackedData << 8 | \ord($data[$i]); $unpackedBits += 8; // While we have enough bits to select a character from the alphabet, keep // consuming the random data for (; $unpackedBits >= $bits && $length > 0; $unpackedBits -= $bits) { $index = $unpackedData & (1 << $bits) - 1; $unpackedData >>= $bits; // Unfortunately, the alphabet size is not necessarily a power of two. // Worst case, it is 2^k + 1, which means we need (k+1) bits and we // have around a 50% chance of missing as k gets larger if ($index < $alphabetSize) { $ret .= $alphabet[$index]; --$length; } } } } return new static($ret); } public function bytesAt(int $offset) : array { $str = $this->string[$offset] ?? ''; return '' === $str ? [] : [\ord($str)]; } public function append(string ...$suffix) : parent { $str = clone $this; $str->string .= 1 >= \count($suffix) ? $suffix[0] ?? '' : \implode('', $suffix); return $str; } public function camel() : parent { $str = clone $this; $parts = \explode(' ', \trim(\ucwords(\preg_replace('/[^a-zA-Z0-9\\x7f-\\xff]++/', ' ', $this->string)))); $parts[0] = 1 !== \strlen($parts[0]) && \ctype_upper($parts[0]) ? $parts[0] : \lcfirst($parts[0]); $str->string = \implode('', $parts); return $str; } public function chunk(int $length = 1) : array { if (1 > $length) { throw new InvalidArgumentException('The chunk length must be greater than zero.'); } if ('' === $this->string) { return []; } $str = clone $this; $chunks = []; foreach (\str_split($this->string, $length) as $chunk) { $str->string = $chunk; $chunks[] = clone $str; } return $chunks; } public function endsWith($suffix) : bool { if ($suffix instanceof parent) { $suffix = $suffix->string; } elseif (\is_array($suffix) || $suffix instanceof \Traversable) { return parent::endsWith($suffix); } else { $suffix = (string) $suffix; } return '' !== $suffix && \strlen($this->string) >= \strlen($suffix) && 0 === \substr_compare($this->string, $suffix, -\strlen($suffix), null, $this->ignoreCase); } public function equalsTo($string) : bool { if ($string instanceof parent) { $string = $string->string; } elseif (\is_array($string) || $string instanceof \Traversable) { return parent::equalsTo($string); } else { $string = (string) $string; } if ('' !== $string && $this->ignoreCase) { return 0 === \strcasecmp($string, $this->string); } return $string === $this->string; } public function folded() : parent { $str = clone $this; $str->string = \strtolower($str->string); return $str; } public function indexOf($needle, int $offset = 0) : ?int { if ($needle instanceof parent) { $needle = $needle->string; } elseif (\is_array($needle) || $needle instanceof \Traversable) { return parent::indexOf($needle, $offset); } else { $needle = (string) $needle; } if ('' === $needle) { return null; } $i = $this->ignoreCase ? \stripos($this->string, $needle, $offset) : \strpos($this->string, $needle, $offset); return \false === $i ? null : $i; } public function indexOfLast($needle, int $offset = 0) : ?int { if ($needle instanceof parent) { $needle = $needle->string; } elseif (\is_array($needle) || $needle instanceof \Traversable) { return parent::indexOfLast($needle, $offset); } else { $needle = (string) $needle; } if ('' === $needle) { return null; } $i = $this->ignoreCase ? \strripos($this->string, $needle, $offset) : \strrpos($this->string, $needle, $offset); return \false === $i ? null : $i; } public function isUtf8() : bool { return '' === $this->string || \preg_match('//u', $this->string); } public function join(array $strings, ?string $lastGlue = null) : parent { $str = clone $this; $tail = null !== $lastGlue && 1 < \count($strings) ? $lastGlue . \array_pop($strings) : ''; $str->string = \implode($this->string, $strings) . $tail; return $str; } public function length() : int { return \strlen($this->string); } public function lower() : parent { $str = clone $this; $str->string = \strtolower($str->string); return $str; } public function match(string $regexp, int $flags = 0, int $offset = 0) : array { $match = (\PREG_PATTERN_ORDER | \PREG_SET_ORDER) & $flags ? 'preg_match_all' : 'preg_match'; if ($this->ignoreCase) { $regexp .= 'i'; } \set_error_handler(static function ($t, $m) { throw new InvalidArgumentException($m); }); try { if (\false === $match($regexp, $this->string, $matches, $flags | \PREG_UNMATCHED_AS_NULL, $offset)) { $lastError = \preg_last_error(); foreach (\get_defined_constants(\true)['pcre'] as $k => $v) { if ($lastError === $v && '_ERROR' === \substr($k, -6)) { throw new RuntimeException('Matching failed with ' . $k . '.'); } } throw new RuntimeException('Matching failed with unknown error code.'); } } finally { \restore_error_handler(); } return $matches; } public function padBoth(int $length, string $padStr = ' ') : parent { $str = clone $this; $str->string = \str_pad($this->string, $length, $padStr, \STR_PAD_BOTH); return $str; } public function padEnd(int $length, string $padStr = ' ') : parent { $str = clone $this; $str->string = \str_pad($this->string, $length, $padStr, \STR_PAD_RIGHT); return $str; } public function padStart(int $length, string $padStr = ' ') : parent { $str = clone $this; $str->string = \str_pad($this->string, $length, $padStr, \STR_PAD_LEFT); return $str; } public function prepend(string ...$prefix) : parent { $str = clone $this; $str->string = (1 >= \count($prefix) ? $prefix[0] ?? '' : \implode('', $prefix)) . $str->string; return $str; } public function replace(string $from, string $to) : parent { $str = clone $this; if ('' !== $from) { $str->string = $this->ignoreCase ? \str_ireplace($from, $to, $this->string) : \str_replace($from, $to, $this->string); } return $str; } public function replaceMatches(string $fromRegexp, $to) : parent { if ($this->ignoreCase) { $fromRegexp .= 'i'; } if (\is_array($to)) { if (!\is_callable($to)) { throw new \TypeError(\sprintf('Argument 2 passed to "%s::replaceMatches()" must be callable, array given.', static::class)); } $replace = 'preg_replace_callback'; } else { $replace = $to instanceof \Closure ? 'preg_replace_callback' : 'preg_replace'; } \set_error_handler(static function ($t, $m) { throw new InvalidArgumentException($m); }); try { if (null === ($string = $replace($fromRegexp, $to, $this->string))) { $lastError = \preg_last_error(); foreach (\get_defined_constants(\true)['pcre'] as $k => $v) { if ($lastError === $v && '_ERROR' === \substr($k, -6)) { throw new RuntimeException('Matching failed with ' . $k . '.'); } } throw new RuntimeException('Matching failed with unknown error code.'); } } finally { \restore_error_handler(); } $str = clone $this; $str->string = $string; return $str; } public function reverse() : parent { $str = clone $this; $str->string = \strrev($str->string); return $str; } public function slice(int $start = 0, ?int $length = null) : parent { $str = clone $this; $str->string = (string) \substr($this->string, $start, $length ?? \PHP_INT_MAX); return $str; } public function snake() : parent { $str = $this->camel(); $str->string = \strtolower(\preg_replace(['/([A-Z]+)([A-Z][a-z])/', '/([a-z\\d])([A-Z])/'], '_HumbugBox7ff99e199a36\\1_\\2', $str->string)); return $str; } public function splice(string $replacement, int $start = 0, ?int $length = null) : parent { $str = clone $this; $str->string = \substr_replace($this->string, $replacement, $start, $length ?? \PHP_INT_MAX); return $str; } public function split(string $delimiter, ?int $limit = null, ?int $flags = null) : array { if (1 > ($limit = $limit ?? \PHP_INT_MAX)) { throw new InvalidArgumentException('Split limit must be a positive integer.'); } if ('' === $delimiter) { throw new InvalidArgumentException('Split delimiter is empty.'); } if (null !== $flags) { return parent::split($delimiter, $limit, $flags); } $str = clone $this; $chunks = $this->ignoreCase ? \preg_split('{' . \preg_quote($delimiter) . '}iD', $this->string, $limit) : \explode($delimiter, $this->string, $limit); foreach ($chunks as &$chunk) { $str->string = $chunk; $chunk = clone $str; } return $chunks; } public function startsWith($prefix) : bool { if ($prefix instanceof parent) { $prefix = $prefix->string; } elseif (!\is_string($prefix)) { return parent::startsWith($prefix); } return '' !== $prefix && 0 === ($this->ignoreCase ? \strncasecmp($this->string, $prefix, \strlen($prefix)) : \strncmp($this->string, $prefix, \strlen($prefix))); } public function title(bool $allWords = \false) : parent { $str = clone $this; $str->string = $allWords ? \ucwords($str->string) : \ucfirst($str->string); return $str; } public function toUnicodeString(?string $fromEncoding = null) : UnicodeString { return new UnicodeString($this->toCodePointString($fromEncoding)->string); } public function toCodePointString(?string $fromEncoding = null) : CodePointString { $u = new CodePointString(); if (\in_array($fromEncoding, [null, 'utf8', 'utf-8', 'UTF8', 'UTF-8'], \true) && \preg_match('//u', $this->string)) { $u->string = $this->string; return $u; } \set_error_handler(static function ($t, $m) { throw new InvalidArgumentException($m); }); try { try { $validEncoding = \false !== \mb_detect_encoding($this->string, $fromEncoding ?? 'Windows-1252', \true); } catch (InvalidArgumentException $e) { if (!\function_exists('iconv')) { throw $e; } $u->string = \iconv($fromEncoding ?? 'Windows-1252', 'UTF-8', $this->string); return $u; } } finally { \restore_error_handler(); } if (!$validEncoding) { throw new InvalidArgumentException(\sprintf('Invalid "%s" string.', $fromEncoding ?? 'Windows-1252')); } $u->string = \mb_convert_encoding($this->string, 'UTF-8', $fromEncoding ?? 'Windows-1252'); return $u; } public function trim(string $chars = " \t\n\r\x00\v\f") : parent { $str = clone $this; $str->string = \trim($str->string, $chars); return $str; } public function trimEnd(string $chars = " \t\n\r\x00\v\f") : parent { $str = clone $this; $str->string = \rtrim($str->string, $chars); return $str; } public function trimStart(string $chars = " \t\n\r\x00\v\f") : parent { $str = clone $this; $str->string = \ltrim($str->string, $chars); return $str; } public function upper() : parent { $str = clone $this; $str->string = \strtoupper($str->string); return $str; } public function width(bool $ignoreAnsiDecoration = \true) : int { $string = \preg_match('//u', $this->string) ? $this->string : \preg_replace('/[\\x80-\\xFF]/', '?', $this->string); return (new CodePointString($string))->width($ignoreAnsiDecoration); } } * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace _HumbugBox7ff99e199a36\Symfony\Component\String\Exception; interface ExceptionInterface extends \Throwable { } * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace _HumbugBox7ff99e199a36\Symfony\Component\String\Exception; class RuntimeException extends \RuntimeException implements ExceptionInterface { } * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace _HumbugBox7ff99e199a36\Symfony\Component\String\Exception; class InvalidArgumentException extends \InvalidArgumentException implements ExceptionInterface { } * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace _HumbugBox7ff99e199a36\Symfony\Component\String; use _HumbugBox7ff99e199a36\Symfony\Component\String\Exception\ExceptionInterface; use _HumbugBox7ff99e199a36\Symfony\Component\String\Exception\InvalidArgumentException; /** * Represents a string of Unicode code points encoded as UTF-8. * * @author Nicolas Grekas * @author Hugo Hamon * * @throws ExceptionInterface */ class CodePointString extends AbstractUnicodeString { public function __construct(string $string = '') { if ('' !== $string && !\preg_match('//u', $string)) { throw new InvalidArgumentException('Invalid UTF-8 string.'); } $this->string = $string; } public function append(string ...$suffix) : AbstractString { $str = clone $this; $str->string .= 1 >= \count($suffix) ? $suffix[0] ?? '' : \implode('', $suffix); if (!\preg_match('//u', $str->string)) { throw new InvalidArgumentException('Invalid UTF-8 string.'); } return $str; } public function chunk(int $length = 1) : array { if (1 > $length) { throw new InvalidArgumentException('The chunk length must be greater than zero.'); } if ('' === $this->string) { return []; } $rx = '/('; while (65535 < $length) { $rx .= '.{65535}'; $length -= 65535; } $rx .= '.{' . $length . '})/us'; $str = clone $this; $chunks = []; foreach (\preg_split($rx, $this->string, -1, \PREG_SPLIT_DELIM_CAPTURE | \PREG_SPLIT_NO_EMPTY) as $chunk) { $str->string = $chunk; $chunks[] = clone $str; } return $chunks; } public function codePointsAt(int $offset) : array { $str = $offset ? $this->slice($offset, 1) : $this; return '' === $str->string ? [] : [\mb_ord($str->string, 'UTF-8')]; } public function endsWith($suffix) : bool { if ($suffix instanceof AbstractString) { $suffix = $suffix->string; } elseif (\is_array($suffix) || $suffix instanceof \Traversable) { return parent::endsWith($suffix); } else { $suffix = (string) $suffix; } if ('' === $suffix || !\preg_match('//u', $suffix)) { return \false; } if ($this->ignoreCase) { return \preg_match('{' . \preg_quote($suffix) . '$}iuD', $this->string); } return \strlen($this->string) >= \strlen($suffix) && 0 === \substr_compare($this->string, $suffix, -\strlen($suffix)); } public function equalsTo($string) : bool { if ($string instanceof AbstractString) { $string = $string->string; } elseif (\is_array($string) || $string instanceof \Traversable) { return parent::equalsTo($string); } else { $string = (string) $string; } if ('' !== $string && $this->ignoreCase) { return \strlen($string) === \strlen($this->string) && 0 === \mb_stripos($this->string, $string, 0, 'UTF-8'); } return $string === $this->string; } public function indexOf($needle, int $offset = 0) : ?int { if ($needle instanceof AbstractString) { $needle = $needle->string; } elseif (\is_array($needle) || $needle instanceof \Traversable) { return parent::indexOf($needle, $offset); } else { $needle = (string) $needle; } if ('' === $needle) { return null; } $i = $this->ignoreCase ? \mb_stripos($this->string, $needle, $offset, 'UTF-8') : \mb_strpos($this->string, $needle, $offset, 'UTF-8'); return \false === $i ? null : $i; } public function indexOfLast($needle, int $offset = 0) : ?int { if ($needle instanceof AbstractString) { $needle = $needle->string; } elseif (\is_array($needle) || $needle instanceof \Traversable) { return parent::indexOfLast($needle, $offset); } else { $needle = (string) $needle; } if ('' === $needle) { return null; } $i = $this->ignoreCase ? \mb_strripos($this->string, $needle, $offset, 'UTF-8') : \mb_strrpos($this->string, $needle, $offset, 'UTF-8'); return \false === $i ? null : $i; } public function length() : int { return \mb_strlen($this->string, 'UTF-8'); } public function prepend(string ...$prefix) : AbstractString { $str = clone $this; $str->string = (1 >= \count($prefix) ? $prefix[0] ?? '' : \implode('', $prefix)) . $this->string; if (!\preg_match('//u', $str->string)) { throw new InvalidArgumentException('Invalid UTF-8 string.'); } return $str; } public function replace(string $from, string $to) : AbstractString { $str = clone $this; if ('' === $from || !\preg_match('//u', $from)) { return $str; } if ('' !== $to && !\preg_match('//u', $to)) { throw new InvalidArgumentException('Invalid UTF-8 string.'); } if ($this->ignoreCase) { $str->string = \implode($to, \preg_split('{' . \preg_quote($from) . '}iuD', $this->string)); } else { $str->string = \str_replace($from, $to, $this->string); } return $str; } public function slice(int $start = 0, ?int $length = null) : AbstractString { $str = clone $this; $str->string = \mb_substr($this->string, $start, $length, 'UTF-8'); return $str; } public function splice(string $replacement, int $start = 0, ?int $length = null) : AbstractString { if (!\preg_match('//u', $replacement)) { throw new InvalidArgumentException('Invalid UTF-8 string.'); } $str = clone $this; $start = $start ? \strlen(\mb_substr($this->string, 0, $start, 'UTF-8')) : 0; $length = $length ? \strlen(\mb_substr($this->string, $start, $length, 'UTF-8')) : $length; $str->string = \substr_replace($this->string, $replacement, $start, $length ?? \PHP_INT_MAX); return $str; } public function split(string $delimiter, ?int $limit = null, ?int $flags = null) : array { if (1 > ($limit = $limit ?? \PHP_INT_MAX)) { throw new InvalidArgumentException('Split limit must be a positive integer.'); } if ('' === $delimiter) { throw new InvalidArgumentException('Split delimiter is empty.'); } if (null !== $flags) { return parent::split($delimiter . 'u', $limit, $flags); } if (!\preg_match('//u', $delimiter)) { throw new InvalidArgumentException('Split delimiter is not a valid UTF-8 string.'); } $str = clone $this; $chunks = $this->ignoreCase ? \preg_split('{' . \preg_quote($delimiter) . '}iuD', $this->string, $limit) : \explode($delimiter, $this->string, $limit); foreach ($chunks as &$chunk) { $str->string = $chunk; $chunk = clone $str; } return $chunks; } public function startsWith($prefix) : bool { if ($prefix instanceof AbstractString) { $prefix = $prefix->string; } elseif (\is_array($prefix) || $prefix instanceof \Traversable) { return parent::startsWith($prefix); } else { $prefix = (string) $prefix; } if ('' === $prefix || !\preg_match('//u', $prefix)) { return \false; } if ($this->ignoreCase) { return 0 === \mb_stripos($this->string, $prefix, 0, 'UTF-8'); } return 0 === \strncmp($this->string, $prefix, \strlen($prefix)); } } * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace _HumbugBox7ff99e199a36\Symfony\Component\String; use _HumbugBox7ff99e199a36\Symfony\Component\String\Exception\ExceptionInterface; use _HumbugBox7ff99e199a36\Symfony\Component\String\Exception\InvalidArgumentException; use _HumbugBox7ff99e199a36\Symfony\Component\String\Exception\RuntimeException; /** * Represents a string of abstract characters. * * Unicode defines 3 types of "characters" (bytes, code points and grapheme clusters). * This class is the abstract type to use as a type-hint when the logic you want to * implement doesn't care about the exact variant it deals with. * * @author Nicolas Grekas * @author Hugo Hamon * * @throws ExceptionInterface */ abstract class AbstractString implements \Stringable, \JsonSerializable { public const PREG_PATTERN_ORDER = \PREG_PATTERN_ORDER; public const PREG_SET_ORDER = \PREG_SET_ORDER; public const PREG_OFFSET_CAPTURE = \PREG_OFFSET_CAPTURE; public const PREG_UNMATCHED_AS_NULL = \PREG_UNMATCHED_AS_NULL; public const PREG_SPLIT = 0; public const PREG_SPLIT_NO_EMPTY = \PREG_SPLIT_NO_EMPTY; public const PREG_SPLIT_DELIM_CAPTURE = \PREG_SPLIT_DELIM_CAPTURE; public const PREG_SPLIT_OFFSET_CAPTURE = \PREG_SPLIT_OFFSET_CAPTURE; protected $string = ''; protected $ignoreCase = \false; public abstract function __construct(string $string = ''); /** * Unwraps instances of AbstractString back to strings. * * @return string[]|array */ public static function unwrap(array $values) : array { foreach ($values as $k => $v) { if ($v instanceof self) { $values[$k] = $v->__toString(); } elseif (\is_array($v) && $values[$k] !== ($v = static::unwrap($v))) { $values[$k] = $v; } } return $values; } /** * Wraps (and normalizes) strings in instances of AbstractString. * * @return static[]|array */ public static function wrap(array $values) : array { $i = 0; $keys = null; foreach ($values as $k => $v) { if (\is_string($k) && '' !== $k && $k !== ($j = (string) new static($k))) { $keys = $keys ?? \array_keys($values); $keys[$i] = $j; } if (\is_string($v)) { $values[$k] = new static($v); } elseif (\is_array($v) && $values[$k] !== ($v = static::wrap($v))) { $values[$k] = $v; } ++$i; } return null !== $keys ? \array_combine($keys, $values) : $values; } /** * @param string|string[] $needle * * @return static */ public function after($needle, bool $includeNeedle = \false, int $offset = 0) : self { $str = clone $this; $i = \PHP_INT_MAX; foreach ((array) $needle as $n) { $n = (string) $n; $j = $this->indexOf($n, $offset); if (null !== $j && $j < $i) { $i = $j; $str->string = $n; } } if (\PHP_INT_MAX === $i) { return $str; } if (!$includeNeedle) { $i += $str->length(); } return $this->slice($i); } /** * @param string|string[] $needle * * @return static */ public function afterLast($needle, bool $includeNeedle = \false, int $offset = 0) : self { $str = clone $this; $i = null; foreach ((array) $needle as $n) { $n = (string) $n; $j = $this->indexOfLast($n, $offset); if (null !== $j && $j >= $i) { $i = $offset = $j; $str->string = $n; } } if (null === $i) { return $str; } if (!$includeNeedle) { $i += $str->length(); } return $this->slice($i); } /** * @return static */ public abstract function append(string ...$suffix) : self; /** * @param string|string[] $needle * * @return static */ public function before($needle, bool $includeNeedle = \false, int $offset = 0) : self { $str = clone $this; $i = \PHP_INT_MAX; foreach ((array) $needle as $n) { $n = (string) $n; $j = $this->indexOf($n, $offset); if (null !== $j && $j < $i) { $i = $j; $str->string = $n; } } if (\PHP_INT_MAX === $i) { return $str; } if ($includeNeedle) { $i += $str->length(); } return $this->slice(0, $i); } /** * @param string|string[] $needle * * @return static */ public function beforeLast($needle, bool $includeNeedle = \false, int $offset = 0) : self { $str = clone $this; $i = null; foreach ((array) $needle as $n) { $n = (string) $n; $j = $this->indexOfLast($n, $offset); if (null !== $j && $j >= $i) { $i = $offset = $j; $str->string = $n; } } if (null === $i) { return $str; } if ($includeNeedle) { $i += $str->length(); } return $this->slice(0, $i); } /** * @return int[] */ public function bytesAt(int $offset) : array { $str = $this->slice($offset, 1); return '' === $str->string ? [] : \array_values(\unpack('C*', $str->string)); } /** * @return static */ public abstract function camel() : self; /** * @return static[] */ public abstract function chunk(int $length = 1) : array; /** * @return static */ public function collapseWhitespace() : self { $str = clone $this; $str->string = \trim(\preg_replace("/(?:[ \n\r\t\f]{2,}+|[\n\r\t\f])/", ' ', $str->string), " \n\r\t\f"); return $str; } /** * @param string|string[] $needle */ public function containsAny($needle) : bool { return null !== $this->indexOf($needle); } /** * @param string|string[] $suffix */ public function endsWith($suffix) : bool { if (!\is_array($suffix) && !$suffix instanceof \Traversable) { throw new \TypeError(\sprintf('Method "%s()" must be overridden by class "%s" to deal with non-iterable values.', __FUNCTION__, static::class)); } foreach ($suffix as $s) { if ($this->endsWith((string) $s)) { return \true; } } return \false; } /** * @return static */ public function ensureEnd(string $suffix) : self { if (!$this->endsWith($suffix)) { return $this->append($suffix); } $suffix = \preg_quote($suffix); $regex = '{(' . $suffix . ')(?:' . $suffix . ')++$}D'; return $this->replaceMatches($regex . ($this->ignoreCase ? 'i' : ''), '$1'); } /** * @return static */ public function ensureStart(string $prefix) : self { $prefix = new static($prefix); if (!$this->startsWith($prefix)) { return $this->prepend($prefix); } $str = clone $this; $i = $prefixLen = $prefix->length(); while ($this->indexOf($prefix, $i) === $i) { $str = $str->slice($prefixLen); $i += $prefixLen; } return $str; } /** * @param string|string[] $string */ public function equalsTo($string) : bool { if (!\is_array($string) && !$string instanceof \Traversable) { throw new \TypeError(\sprintf('Method "%s()" must be overridden by class "%s" to deal with non-iterable values.', __FUNCTION__, static::class)); } foreach ($string as $s) { if ($this->equalsTo((string) $s)) { return \true; } } return \false; } /** * @return static */ public abstract function folded() : self; /** * @return static */ public function ignoreCase() : self { $str = clone $this; $str->ignoreCase = \true; return $str; } /** * @param string|string[] $needle */ public function indexOf($needle, int $offset = 0) : ?int { if (!\is_array($needle) && !$needle instanceof \Traversable) { throw new \TypeError(\sprintf('Method "%s()" must be overridden by class "%s" to deal with non-iterable values.', __FUNCTION__, static::class)); } $i = \PHP_INT_MAX; foreach ($needle as $n) { $j = $this->indexOf((string) $n, $offset); if (null !== $j && $j < $i) { $i = $j; } } return \PHP_INT_MAX === $i ? null : $i; } /** * @param string|string[] $needle */ public function indexOfLast($needle, int $offset = 0) : ?int { if (!\is_array($needle) && !$needle instanceof \Traversable) { throw new \TypeError(\sprintf('Method "%s()" must be overridden by class "%s" to deal with non-iterable values.', __FUNCTION__, static::class)); } $i = null; foreach ($needle as $n) { $j = $this->indexOfLast((string) $n, $offset); if (null !== $j && $j >= $i) { $i = $offset = $j; } } return $i; } public function isEmpty() : bool { return '' === $this->string; } /** * @return static */ public abstract function join(array $strings, ?string $lastGlue = null) : self; public function jsonSerialize() : string { return $this->string; } public abstract function length() : int; /** * @return static */ public abstract function lower() : self; /** * Matches the string using a regular expression. * * Pass PREG_PATTERN_ORDER or PREG_SET_ORDER as $flags to get all occurrences matching the regular expression. * * @return array All matches in a multi-dimensional array ordered according to flags */ public abstract function match(string $regexp, int $flags = 0, int $offset = 0) : array; /** * @return static */ public abstract function padBoth(int $length, string $padStr = ' ') : self; /** * @return static */ public abstract function padEnd(int $length, string $padStr = ' ') : self; /** * @return static */ public abstract function padStart(int $length, string $padStr = ' ') : self; /** * @return static */ public abstract function prepend(string ...$prefix) : self; /** * @return static */ public function repeat(int $multiplier) : self { if (0 > $multiplier) { throw new InvalidArgumentException(\sprintf('Multiplier must be positive, %d given.', $multiplier)); } $str = clone $this; $str->string = \str_repeat($str->string, $multiplier); return $str; } /** * @return static */ public abstract function replace(string $from, string $to) : self; /** * @param string|callable $to * * @return static */ public abstract function replaceMatches(string $fromRegexp, $to) : self; /** * @return static */ public abstract function reverse() : self; /** * @return static */ public abstract function slice(int $start = 0, ?int $length = null) : self; /** * @return static */ public abstract function snake() : self; /** * @return static */ public abstract function splice(string $replacement, int $start = 0, ?int $length = null) : self; /** * @return static[] */ public function split(string $delimiter, ?int $limit = null, ?int $flags = null) : array { if (null === $flags) { throw new \TypeError('Split behavior when $flags is null must be implemented by child classes.'); } if ($this->ignoreCase) { $delimiter .= 'i'; } \set_error_handler(static function ($t, $m) { throw new InvalidArgumentException($m); }); try { if (\false === ($chunks = \preg_split($delimiter, $this->string, $limit, $flags))) { $lastError = \preg_last_error(); foreach (\get_defined_constants(\true)['pcre'] as $k => $v) { if ($lastError === $v && '_ERROR' === \substr($k, -6)) { throw new RuntimeException('Splitting failed with ' . $k . '.'); } } throw new RuntimeException('Splitting failed with unknown error code.'); } } finally { \restore_error_handler(); } $str = clone $this; if (self::PREG_SPLIT_OFFSET_CAPTURE & $flags) { foreach ($chunks as &$chunk) { $str->string = $chunk[0]; $chunk[0] = clone $str; } } else { foreach ($chunks as &$chunk) { $str->string = $chunk; $chunk = clone $str; } } return $chunks; } /** * @param string|string[] $prefix */ public function startsWith($prefix) : bool { if (!\is_array($prefix) && !$prefix instanceof \Traversable) { throw new \TypeError(\sprintf('Method "%s()" must be overridden by class "%s" to deal with non-iterable values.', __FUNCTION__, static::class)); } foreach ($prefix as $prefix) { if ($this->startsWith((string) $prefix)) { return \true; } } return \false; } /** * @return static */ public abstract function title(bool $allWords = \false) : self; public function toByteString(?string $toEncoding = null) : ByteString { $b = new ByteString(); $toEncoding = \in_array($toEncoding, ['utf8', 'utf-8', 'UTF8'], \true) ? 'UTF-8' : $toEncoding; if (null === $toEncoding || $toEncoding === ($fromEncoding = $this instanceof AbstractUnicodeString || \preg_match('//u', $b->string) ? 'UTF-8' : 'Windows-1252')) { $b->string = $this->string; return $b; } \set_error_handler(static function ($t, $m) { throw new InvalidArgumentException($m); }); try { try { $b->string = \mb_convert_encoding($this->string, $toEncoding, 'UTF-8'); } catch (InvalidArgumentException|\ValueError $e) { if (!\function_exists('iconv')) { if ($e instanceof \ValueError) { throw new InvalidArgumentException($e->getMessage(), $e->getCode(), $e); } throw $e; } $b->string = \iconv('UTF-8', $toEncoding, $this->string); } } finally { \restore_error_handler(); } return $b; } public function toCodePointString() : CodePointString { return new CodePointString($this->string); } public function toString() : string { return $this->string; } public function toUnicodeString() : UnicodeString { return new UnicodeString($this->string); } /** * @return static */ public abstract function trim(string $chars = " \t\n\r\x00\v\f ") : self; /** * @return static */ public abstract function trimEnd(string $chars = " \t\n\r\x00\v\f ") : self; /** * @param string|string[] $prefix * * @return static */ public function trimPrefix($prefix) : self { if (\is_array($prefix) || $prefix instanceof \Traversable) { foreach ($prefix as $s) { $t = $this->trimPrefix($s); if ($t->string !== $this->string) { return $t; } } return clone $this; } $str = clone $this; if ($prefix instanceof self) { $prefix = $prefix->string; } else { $prefix = (string) $prefix; } if ('' !== $prefix && \strlen($this->string) >= \strlen($prefix) && 0 === \substr_compare($this->string, $prefix, 0, \strlen($prefix), $this->ignoreCase)) { $str->string = \substr($this->string, \strlen($prefix)); } return $str; } /** * @return static */ public abstract function trimStart(string $chars = " \t\n\r\x00\v\f ") : self; /** * @param string|string[] $suffix * * @return static */ public function trimSuffix($suffix) : self { if (\is_array($suffix) || $suffix instanceof \Traversable) { foreach ($suffix as $s) { $t = $this->trimSuffix($s); if ($t->string !== $this->string) { return $t; } } return clone $this; } $str = clone $this; if ($suffix instanceof self) { $suffix = $suffix->string; } else { $suffix = (string) $suffix; } if ('' !== $suffix && \strlen($this->string) >= \strlen($suffix) && 0 === \substr_compare($this->string, $suffix, -\strlen($suffix), null, $this->ignoreCase)) { $str->string = \substr($this->string, 0, -\strlen($suffix)); } return $str; } /** * @return static */ public function truncate(int $length, string $ellipsis = '', bool $cut = \true) : self { $stringLength = $this->length(); if ($stringLength <= $length) { return clone $this; } $ellipsisLength = '' !== $ellipsis ? (new static($ellipsis))->length() : 0; if ($length < $ellipsisLength) { $ellipsisLength = 0; } if (!$cut) { if (null === ($length = $this->indexOf([' ', "\r", "\n", "\t"], ($length ?: 1) - 1))) { return clone $this; } $length += $ellipsisLength; } $str = $this->slice(0, $length - $ellipsisLength); return $ellipsisLength ? $str->trimEnd()->append($ellipsis) : $str; } /** * @return static */ public abstract function upper() : self; /** * Returns the printable length on a terminal. */ public abstract function width(bool $ignoreAnsiDecoration = \true) : int; /** * @return static */ public function wordwrap(int $width = 75, string $break = "\n", bool $cut = \false) : self { $lines = '' !== $break ? $this->split($break) : [clone $this]; $chars = []; $mask = ''; if (1 === \count($lines) && '' === $lines[0]->string) { return $lines[0]; } foreach ($lines as $i => $line) { if ($i) { $chars[] = $break; $mask .= '#'; } foreach ($line->chunk() as $char) { $chars[] = $char->string; $mask .= ' ' === $char->string ? ' ' : '?'; } } $string = ''; $j = 0; $b = $i = -1; $mask = \wordwrap($mask, $width, '#', $cut); while (\false !== ($b = \strpos($mask, '#', $b + 1))) { for (++$i; $i < $b; ++$i) { $string .= $chars[$j]; unset($chars[$j++]); } if ($break === $chars[$j] || ' ' === $chars[$j]) { unset($chars[$j++]); } $string .= $break; } $str = clone $this; $str->string = $string . \implode('', $chars); return $str; } public function __sleep() : array { return ['string']; } public function __clone() { $this->ignoreCase = \false; } public function __toString() : string { return $this->string; } } document = new DOMDocument($xmlVersion, $xmlEncoding ?? ''); if (!\is_null($xmlStandalone)) { $this->document->xmlStandalone = $xmlStandalone; } if (!empty($domProperties)) { $this->setDomProperties($domProperties); } $this->replaceSpacesByUnderScoresInKeyNames = $replaceSpacesByUnderScoresInKeyNames; if (!empty($array) && $this->isArrayAllKeySequential($array)) { throw new DOMException('Invalid Character Error'); } $root = $this->createRootElement($rootElement); $this->document->appendChild($root); $this->convertElement($root, $array); } public function setNumericTagNamePrefix(string $prefix) { $this->numericTagNamePrefix = $prefix; } public static function convert(array $array, $rootElement = '', bool $replaceSpacesByUnderScoresInKeyNames = \true, string $xmlEncoding = null, string $xmlVersion = '1.0', array $domProperties = [], bool $xmlStandalone = null) { $converter = new static($array, $rootElement, $replaceSpacesByUnderScoresInKeyNames, $xmlEncoding, $xmlVersion, $domProperties, $xmlStandalone); return $converter->toXml(); } public function toXml() : string { return $this->addXmlDeclaration ? $this->document->saveXML() : $this->document->saveXml($this->document->documentElement); } public function toDom() : DOMDocument { return $this->document; } protected function ensureValidDomProperties(array $domProperties) { foreach ($domProperties as $key => $value) { if (!\property_exists($this->document, $key)) { throw new Exception("{$key} is not a valid property of DOMDocument"); } } } public function setDomProperties(array $domProperties) { $this->ensureValidDomProperties($domProperties); foreach ($domProperties as $key => $value) { $this->document->{$key} = $value; } return $this; } public function prettify() { $this->document->preserveWhiteSpace = \false; $this->document->formatOutput = \true; return $this; } public function dropXmlDeclaration() { $this->addXmlDeclaration = \false; return $this; } public function addProcessingInstruction($target, $data) { $elements = $this->document->getElementsByTagName('*'); $rootElement = $elements->count() > 0 ? $elements->item(0) : null; $processingInstruction = $this->document->createProcessingInstruction($target, $data); $this->document->insertBefore($processingInstruction, $rootElement); return $this; } private function convertElement(DOMElement $element, $value) { $sequential = $this->isArrayAllKeySequential($value); if (!\is_array($value)) { $value = \htmlspecialchars($value ?? ''); $value = $this->removeControlCharacters($value); $element->nodeValue = $value; return; } foreach ($value as $key => $data) { if (!$sequential) { if ($key === '_attributes' || $key === '@attributes') { $this->addAttributes($element, $data); } elseif (($key === '_value' || $key === '@value') && \is_string($data)) { $element->nodeValue = \htmlspecialchars($data); } elseif (($key === '_cdata' || $key === '@cdata') && \is_string($data)) { $element->appendChild($this->document->createCDATASection($data)); } elseif (($key === '_mixed' || $key === '@mixed') && \is_string($data)) { $fragment = $this->document->createDocumentFragment(); $fragment->appendXML($data); $element->appendChild($fragment); } elseif ($key === '__numeric') { $this->addNumericNode($element, $data); } elseif (\substr($key, 0, 9) === '__custom:') { $this->addNode($element, \str_replace('\\:', ':', \preg_split('/(?addNode($element, $key, $data); } } elseif (\is_array($data)) { $this->addCollectionNode($element, $data); } else { $this->addSequentialNode($element, $data); } } } protected function addNumericNode(DOMElement $element, $value) { foreach ($value as $key => $item) { $this->convertElement($element, [$this->numericTagNamePrefix . $key => $item]); } } protected function addNode(DOMElement $element, $key, $value) { if ($this->replaceSpacesByUnderScoresInKeyNames) { $key = \str_replace(' ', '_', $key); } $child = $this->document->createElement($key); $element->appendChild($child); $this->convertElement($child, $value); } protected function addCollectionNode(DOMElement $element, $value) { if ($element->childNodes->length === 0 && $element->attributes->length === 0) { $this->convertElement($element, $value); return; } $child = $this->document->createElement($element->tagName); $element->parentNode->appendChild($child); $this->convertElement($child, $value); } protected function addSequentialNode(DOMElement $element, $value) { if (empty($element->nodeValue) && !\is_numeric($element->nodeValue)) { $element->nodeValue = \htmlspecialchars($value); return; } $child = $this->document->createElement($element->tagName); $child->nodeValue = \htmlspecialchars($value); $element->parentNode->appendChild($child); } protected function isArrayAllKeySequential($value) { if (!\is_array($value)) { return \false; } if (\count($value) <= 0) { return \true; } if (\key($value) === '__numeric') { return \false; } return \array_unique(\array_map('is_int', \array_keys($value))) === [\true]; } protected function addAttributes(DOMElement $element, array $data) { foreach ($data as $attrKey => $attrVal) { $element->setAttribute($attrKey, $attrVal ?? ''); } } protected function createRootElement($rootElement) : DOMElement { if (\is_string($rootElement)) { $rootElementName = $rootElement ?: 'root'; return $this->document->createElement($rootElementName); } $rootElementName = $rootElement['rootElementName'] ?? 'root'; $element = $this->document->createElement($rootElementName); foreach ($rootElement as $key => $value) { if ($key !== '_attributes' && $key !== '@attributes') { continue; } $this->addAttributes($element, $rootElement[$key]); } return $element; } protected function removeControlCharacters(string $value) : string { return \preg_replace('/[\\x00-\\x09\\x0B\\x0C\\x0E-\\x1F\\x7F]/', '', $value); } } The MIT License (MIT) Copyright (c) 2016-2021 amphp Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ private $iterator; /** @var \Throwable|null */ private $exception; /** @var bool */ private $pending = \false; /** * @psalm-param Iterator $iterator */ public function __construct(Iterator $iterator) { $this->iterator = $iterator; } /** @inheritdoc */ public function read() : Promise { if ($this->exception) { return new Failure($this->exception); } if ($this->pending) { throw new PendingReadError(); } $this->pending = \true; /** @var Deferred $deferred */ $deferred = new Deferred(); $this->iterator->advance()->onResolve(function ($error, $hasNextElement) use($deferred) { $this->pending = \false; if ($error) { $this->exception = $error; $deferred->fail($error); } elseif ($hasNextElement) { $chunk = $this->iterator->getCurrent(); if (!\is_string($chunk)) { $this->exception = new StreamException(\sprintf("Unexpected iterator value of type '%s', expected string", \is_object($chunk) ? \get_class($chunk) : \gettype($chunk))); $deferred->fail($this->exception); return; } $deferred->resolve($chunk); } else { $deferred->resolve(); } }); return $deferred->promise(); } } read())) !== null) { $written += \strlen($chunk); $writePromise = $destination->write($chunk); $chunk = null; // free memory (yield $writePromise); } return $written; }); } /** * @param \Amp\ByteStream\InputStream $source * * @return \Amp\Promise */ function buffer(InputStream $source) : Promise { return call(function () use($source) : \Generator { $buffer = ""; while (($chunk = (yield $source->read())) !== null) { $buffer .= $chunk; $chunk = null; // free memory } return $buffer; }); } /** * The php://input input buffer stream for the process associated with the currently active event loop. * * @return ResourceInputStream */ function getInputBufferStream() : ResourceInputStream { static $key = InputStream::class . '\\input'; $stream = Loop::getState($key); if (!$stream) { $stream = new ResourceInputStream(\fopen('php://input', 'rb')); Loop::setState($key, $stream); } return $stream; } /** * The php://output output buffer stream for the process associated with the currently active event loop. * * @return ResourceOutputStream */ function getOutputBufferStream() : ResourceOutputStream { static $key = OutputStream::class . '\\output'; $stream = Loop::getState($key); if (!$stream) { $stream = new ResourceOutputStream(\fopen('php://output', 'wb')); Loop::setState($key, $stream); } return $stream; } /** * The STDIN stream for the process associated with the currently active event loop. * * @return ResourceInputStream */ function getStdin() : ResourceInputStream { static $key = InputStream::class . '\\stdin'; $stream = Loop::getState($key); if (!$stream) { $stream = new ResourceInputStream(\STDIN); Loop::setState($key, $stream); } return $stream; } /** * The STDOUT stream for the process associated with the currently active event loop. * * @return ResourceOutputStream */ function getStdout() : ResourceOutputStream { static $key = OutputStream::class . '\\stdout'; $stream = Loop::getState($key); if (!$stream) { $stream = new ResourceOutputStream(\STDOUT); Loop::setState($key, $stream); } return $stream; } /** * The STDERR stream for the process associated with the currently active event loop. * * @return ResourceOutputStream */ function getStderr() : ResourceOutputStream { static $key = OutputStream::class . '\\stderr'; $stream = Loop::getState($key); if (!$stream) { $stream = new ResourceOutputStream(\STDERR); Loop::setState($key, $stream); } return $stream; } function parseLineDelimitedJson(InputStream $stream, bool $assoc = \false, int $depth = 512, int $options = 0) : Iterator { return new Producer(static function (callable $emit) use($stream, $assoc, $depth, $options) { $reader = new LineReader($stream); while (null !== ($line = (yield $reader->readLine()))) { $line = \trim($line); if ($line === '') { continue; } /** @noinspection PhpComposerExtensionStubsInspection */ $data = \json_decode($line, $assoc, $depth, $options); /** @noinspection PhpComposerExtensionStubsInspection */ $error = \json_last_error(); /** @noinspection PhpComposerExtensionStubsInspection */ if ($error !== \JSON_ERROR_NONE) { /** @noinspection PhpComposerExtensionStubsInspection */ throw new StreamException('Failed to parse JSON: ' . \json_last_error_msg(), $error); } (yield $emit($data)); } }); } destination = $destination; } public function write(string $data) : Promise { $this->buffer .= $data; $length = \strlen($this->buffer); $chunk = \base64_encode(\substr($this->buffer, 0, $length - $length % 3)); $this->buffer = \substr($this->buffer, $length - $length % 3); return $this->destination->write($chunk); } public function end(string $finalData = "") : Promise { $chunk = \base64_encode($this->buffer . $finalData); $this->buffer = ''; return $this->destination->end($chunk); } } source = $source; } public function read() : Promise { return call(function () { if ($this->source === null) { throw new StreamException('Failed to read stream chunk due to invalid base64 data'); } $chunk = (yield $this->source->read()); if ($chunk === null) { if ($this->buffer === null) { return null; } $chunk = \base64_decode($this->buffer, \true); if ($chunk === \false) { $this->source = null; $this->buffer = null; throw new StreamException('Failed to read stream chunk due to invalid base64 data'); } $this->buffer = null; return $chunk; } $this->buffer .= $chunk; $length = \strlen($this->buffer); $chunk = \base64_decode(\substr($this->buffer, 0, $length - $length % 4), \true); if ($chunk === \false) { $this->source = null; $this->buffer = null; throw new StreamException('Failed to read stream chunk due to invalid base64 data'); } $this->buffer = \substr($this->buffer, $length - $length % 4); return $chunk; }); } } destination = $destination; } public function write(string $data) : Promise { $this->buffer .= $data; $length = \strlen($this->buffer); $chunk = \base64_decode(\substr($this->buffer, 0, $length - $length % 4), \true); if ($chunk === \false) { return new Failure(new StreamException('Invalid base64 near offset ' . $this->offset)); } $this->offset += $length - $length % 4; $this->buffer = \substr($this->buffer, $length - $length % 4); return $this->destination->write($chunk); } public function end(string $finalData = "") : Promise { $this->offset += \strlen($this->buffer); $chunk = \base64_decode($this->buffer . $finalData, \true); if ($chunk === \false) { return new Failure(new StreamException('Invalid base64 near offset ' . $this->offset)); } $this->buffer = ''; return $this->destination->end($chunk); } } source = $source; } public function read() : Promise { return call(function () { $chunk = (yield $this->source->read()); if ($chunk === null) { if ($this->buffer === null) { return null; } $chunk = \base64_encode($this->buffer); $this->buffer = null; return $chunk; } $this->buffer .= $chunk; $length = \strlen($this->buffer); $chunk = \base64_encode(\substr($this->buffer, 0, $length - $length % 3)); $this->buffer = \substr($this->buffer, $length - $length % 3); return $chunk; }); } } stream = $stream; } public function __destruct() { if (!$this->promise) { Promise\rethrow(new Coroutine($this->consume())); } } private function consume() : \Generator { try { if ($this->lastRead && null === (yield $this->lastRead)) { return; } while (null !== (yield $this->stream->read())) { // Discard unread bytes from message. } } catch (\Throwable $exception) { // If exception is thrown here the connection closed anyway. } } /** * @inheritdoc * * @throws \Error If a buffered message was requested by calling buffer(). */ public final function read() : Promise { if ($this->promise) { throw new \Error("Cannot stream message data once a buffered message has been requested"); } return $this->lastRead = $this->stream->read(); } /** * Buffers the entire message and resolves the returned promise then. * * @return Promise Resolves with the entire message contents. */ public final function buffer() : Promise { if ($this->promise) { return $this->promise; } return $this->promise = call(function () { $buffer = ''; if ($this->lastRead && null === (yield $this->lastRead)) { return $buffer; } while (null !== ($chunk = (yield $this->stream->read()))) { $buffer .= $chunk; } return $buffer; }); } } destination = $destination; $this->encoding = $encoding; $this->options = $options; $this->resource = @\deflate_init($encoding, $options); if ($this->resource === \false) { throw new StreamException("Failed initializing deflate context"); } } /** @inheritdoc */ public function write(string $data) : Promise { if ($this->resource === null) { throw new ClosedException("The stream has already been closed"); } \assert($this->destination !== null); $compressed = \deflate_add($this->resource, $data, \ZLIB_SYNC_FLUSH); if ($compressed === \false) { throw new StreamException("Failed adding data to deflate context"); } $promise = $this->destination->write($compressed); $promise->onResolve(function ($error) { if ($error) { $this->close(); } }); return $promise; } /** @inheritdoc */ public function end(string $finalData = "") : Promise { if ($this->resource === null) { throw new ClosedException("The stream has already been closed"); } \assert($this->destination !== null); $compressed = \deflate_add($this->resource, $finalData, \ZLIB_FINISH); if ($compressed === \false) { throw new StreamException("Failed adding data to deflate context"); } $promise = $this->destination->end($compressed); $promise->onResolve(function () { $this->close(); }); return $promise; } /** * @internal * @return void */ private function close() { $this->resource = null; $this->destination = null; } /** * Gets the used compression encoding. * * @return int Encoding specified on construction time. */ public function getEncoding() : int { return $this->encoding; } /** * Gets the used compression options. * * @return array Options array passed on construction time. */ public function getOptions() : array { return $this->options; } } read()) !== null) { * $buffer .= $chunk; * } * * return $buffer; * }); * } * ``` */ interface InputStream { /** * Reads data from the stream. * * @return Promise Resolves with a string when new data is available or `null` if the stream has closed. * * @psalm-return Promise * * @throws PendingReadError Thrown if another read operation is still pending. */ public function read() : Promise; } source = $source; $this->encoding = $encoding; $this->options = $options; $this->resource = @\inflate_init($encoding, $options); if ($this->resource === \false) { throw new StreamException("Failed initializing deflate context"); } } /** @inheritdoc */ public function read() : Promise { return call(function () { if ($this->resource === null) { return null; } \assert($this->source !== null); $data = (yield $this->source->read()); // Needs a double guard, as stream might have been closed while reading /** @psalm-suppress ParadoxicalCondition */ if ($this->resource === null) { return null; } if ($data === null) { $decompressed = @\inflate_add($this->resource, "", \ZLIB_FINISH); if ($decompressed === \false) { throw new StreamException("Failed adding data to deflate context"); } $this->close(); return $decompressed; } $decompressed = @\inflate_add($this->resource, $data, \ZLIB_SYNC_FLUSH); if ($decompressed === \false) { throw new StreamException("Failed adding data to deflate context"); } return $decompressed; }); } /** * @internal * @return void */ private function close() { $this->resource = null; $this->source = null; } /** * Gets the used compression encoding. * * @return int Encoding specified on construction time. */ public function getEncoding() : int { return $this->encoding; } /** * Gets the used compression options. * * @return array Options array passed on construction time. */ public function getOptions() : array { return $this->options; } } source = $inputStream; $this->delimiter = $delimiter === null ? "\n" : $delimiter; $this->lineMode = $delimiter === null; } /** * @return Promise */ public function readLine() : Promise { return call(function () { if (\false !== \strpos($this->buffer, $this->delimiter)) { list($line, $this->buffer) = \explode($this->delimiter, $this->buffer, 2); return $this->lineMode ? \rtrim($line, "\r") : $line; } while (null !== ($chunk = (yield $this->source->read()))) { $this->buffer .= $chunk; if (\false !== \strpos($this->buffer, $this->delimiter)) { list($line, $this->buffer) = \explode($this->delimiter, $this->buffer, 2); return $this->lineMode ? \rtrim($line, "\r") : $line; } } if ($this->buffer === "") { return null; } $line = $this->buffer; $this->buffer = ""; return $this->lineMode ? \rtrim($line, "\r") : $line; }); } public function getBuffer() : string { return $this->buffer; } /** * @return void */ public function clearBuffer() { $this->buffer = ""; } } */ private $writes; /** @var bool */ private $writable = \true; /** @var int|null */ private $chunkSize; /** * @param resource $stream Stream resource. * @param int|null $chunkSize Chunk size per `fwrite()` operation. */ public function __construct($stream, ?int $chunkSize = null) { if (!\is_resource($stream) || \get_resource_type($stream) !== 'stream') { throw new \Error("Expected a valid stream"); } $meta = \stream_get_meta_data($stream); if (\strpos($meta["mode"], "r") !== \false && \strpos($meta["mode"], "+") === \false) { throw new \Error("Expected a writable stream"); } \stream_set_blocking($stream, \false); \stream_set_write_buffer($stream, 0); $this->resource = $stream; $this->chunkSize =& $chunkSize; $writes = $this->writes = new \SplQueue(); $writable =& $this->writable; $resource =& $this->resource; $this->watcher = Loop::onWritable($stream, static function ($watcher, $stream) use($writes, &$chunkSize, &$writable, &$resource) { static $emptyWrites = 0; try { while (!$writes->isEmpty()) { /** @var Deferred $deferred */ list($data, $previous, $deferred) = $writes->shift(); $length = \strlen($data); if ($length === 0) { $deferred->resolve(0); continue; } if (!\is_resource($stream) || ($metaData = @\stream_get_meta_data($stream)) && $metaData['eof']) { throw new ClosedException("The stream was closed by the peer"); } // Error reporting suppressed since fwrite() emits E_WARNING if the pipe is broken or the buffer is full. // Use conditional, because PHP doesn't like getting null passed if ($chunkSize) { $written = @\fwrite($stream, $data, $chunkSize); } else { $written = @\fwrite($stream, $data); } \assert( $written !== \false || \PHP_VERSION_ID >= 70400, // PHP 7.4+ returns false on EPIPE. "Trying to write on a previously fclose()'d resource. Do NOT manually fclose() resources the still referenced in the loop." ); // PHP 7.4.0 and 7.4.1 may return false on EAGAIN. if ($written === \false && \PHP_VERSION_ID >= 70402) { $message = "Failed to write to stream"; if ($error = \error_get_last()) { $message .= \sprintf("; %s", $error["message"]); } throw new StreamException($message); } // Broken pipes between processes on macOS/FreeBSD do not detect EOF properly. if ($written === 0 || $written === \false) { if ($emptyWrites++ > self::MAX_CONSECUTIVE_EMPTY_WRITES) { $message = "Failed to write to stream after multiple attempts"; if ($error = \error_get_last()) { $message .= \sprintf("; %s", $error["message"]); } throw new StreamException($message); } $writes->unshift([$data, $previous, $deferred]); return; } $emptyWrites = 0; if ($length > $written) { $data = \substr($data, $written); $writes->unshift([$data, $written + $previous, $deferred]); return; } $deferred->resolve($written + $previous); } } catch (\Throwable $exception) { $resource = null; $writable = \false; /** @psalm-suppress PossiblyUndefinedVariable */ $deferred->fail($exception); while (!$writes->isEmpty()) { list(, , $deferred) = $writes->shift(); $deferred->fail($exception); } Loop::cancel($watcher); } finally { if ($writes->isEmpty()) { Loop::disable($watcher); } } }); Loop::disable($this->watcher); } /** * Writes data to the stream. * * @param string $data Bytes to write. * * @return Promise Succeeds once the data has been successfully written to the stream. * * @throws ClosedException If the stream has already been closed. */ public function write(string $data) : Promise { return $this->send($data, \false); } /** * Closes the stream after all pending writes have been completed. Optionally writes a final data chunk before. * * @param string $finalData Bytes to write. * * @return Promise Succeeds once the data has been successfully written to the stream. * * @throws ClosedException If the stream has already been closed. */ public function end(string $finalData = "") : Promise { return $this->send($finalData, \true); } private function send(string $data, bool $end = \false) : Promise { if (!$this->writable) { return new Failure(new ClosedException("The stream is not writable")); } $length = \strlen($data); $written = 0; if ($end) { $this->writable = \false; } if ($this->writes->isEmpty()) { if ($length === 0) { if ($end) { $this->close(); } return new Success(0); } if (!\is_resource($this->resource) || ($metaData = @\stream_get_meta_data($this->resource)) && $metaData['eof']) { return new Failure(new ClosedException("The stream was closed by the peer")); } // Error reporting suppressed since fwrite() emits E_WARNING if the pipe is broken or the buffer is full. // Use conditional, because PHP doesn't like getting null passed. if ($this->chunkSize) { $written = @\fwrite($this->resource, $data, $this->chunkSize); } else { $written = @\fwrite($this->resource, $data); } \assert( $written !== \false || \PHP_VERSION_ID >= 70400, // PHP 7.4+ returns false on EPIPE. "Trying to write on a previously fclose()'d resource. Do NOT manually fclose() resources the still referenced in the loop." ); // PHP 7.4.0 and 7.4.1 may return false on EAGAIN. if ($written === \false && \PHP_VERSION_ID >= 70402) { $message = "Failed to write to stream"; if ($error = \error_get_last()) { $message .= \sprintf("; %s", $error["message"]); } return new Failure(new StreamException($message)); } $written = (int) $written; // Cast potential false to 0. if ($length === $written) { if ($end) { $this->close(); } return new Success($written); } $data = \substr($data, $written); } $deferred = new Deferred(); if ($length - $written > self::LARGE_CHUNK_SIZE) { $chunks = \str_split($data, self::LARGE_CHUNK_SIZE); $data = \array_pop($chunks); foreach ($chunks as $chunk) { $this->writes->push([$chunk, $written, new Deferred()]); $written += self::LARGE_CHUNK_SIZE; } } $this->writes->push([$data, $written, $deferred]); Loop::enable($this->watcher); $promise = $deferred->promise(); if ($end) { $promise->onResolve([$this, "close"]); } return $promise; } /** * Closes the stream forcefully. Multiple `close()` calls are ignored. * * @return void */ public function close() { if (\is_resource($this->resource)) { // Error suppression, as resource might already be closed $meta = @\stream_get_meta_data($this->resource); if ($meta && \strpos($meta["mode"], "+") !== \false) { @\stream_socket_shutdown($this->resource, \STREAM_SHUT_WR); } else { /** @psalm-suppress InvalidPropertyAssignmentValue psalm reports this as closed-resource */ @\fclose($this->resource); } } $this->free(); } /** * Nulls reference to resource, marks stream unwritable, and fails any pending write. * * @return void */ private function free() { $this->resource = null; $this->writable = \false; if (!$this->writes->isEmpty()) { $exception = new ClosedException("The socket was closed before writing completed"); do { /** @var Deferred $deferred */ list(, , $deferred) = $this->writes->shift(); $deferred->fail($exception); } while (!$this->writes->isEmpty()); } Loop::cancel($this->watcher); } /** * @return resource|null Stream resource or null if end() has been called or the stream closed. */ public function getResource() { return $this->resource; } /** * @return void */ public function setChunkSize(int $chunkSize) { $this->chunkSize = $chunkSize; } public function __destruct() { if ($this->resource !== null) { $this->free(); } } } contents = $contents; } /** * Reads data from the stream. * * @return Promise Resolves with the full contents or `null` if the stream has closed / already been consumed. */ public function read() : Promise { if ($this->contents === null) { return new Success(); } $promise = new Success($this->contents); $this->contents = null; return $promise; } } deferred = new Deferred(); } public function write(string $data) : Promise { if ($this->closed) { throw new ClosedException("The stream has already been closed."); } $this->contents .= $data; return new Success(\strlen($data)); } public function end(string $finalData = "") : Promise { if ($this->closed) { throw new ClosedException("The stream has already been closed."); } $this->contents .= $finalData; $this->closed = \true; $this->deferred->resolve($this->contents); $this->contents = ""; return new Success(\strlen($finalData)); } public function onResolve(callable $onResolved) { $this->deferred->promise()->onResolve($onResolved); } } streams = $streams; } /** @inheritDoc */ public function read() : Promise { if ($this->reading) { throw new PendingReadError(); } if (!$this->streams) { return new Success(null); } return call(function () { $this->reading = \true; try { while ($this->streams) { $chunk = (yield $this->streams[0]->read()); if ($chunk === null) { \array_shift($this->streams); continue; } return $chunk; } return null; } finally { $this->reading = \false; } }); } } useSingleRead = $useSingleRead; if (\strpos($meta["mode"], "r") === \false && \strpos($meta["mode"], "+") === \false) { throw new \Error("Expected a readable stream"); } \stream_set_blocking($stream, \false); \stream_set_read_buffer($stream, 0); $this->resource =& $stream; $this->chunkSize =& $chunkSize; $deferred =& $this->deferred; $readable =& $this->readable; $this->watcher = Loop::onReadable($this->resource, static function ($watcher) use(&$deferred, &$readable, &$stream, &$chunkSize, $useSingleRead) { if ($useSingleRead) { $data = @\fread($stream, $chunkSize); } else { $data = @\stream_get_contents($stream, $chunkSize); } \assert($data !== \false, "Trying to read from a previously fclose()'d resource. Do NOT manually fclose() resources the loop still has a reference to."); // Error suppression, because pthreads does crazy things with resources, // which might be closed during two operations. // See https://github.com/amphp/byte-stream/issues/32 if ($data === '' && @\feof($stream)) { $readable = \false; $stream = null; $data = null; // Stream closed, resolve read with null. Loop::cancel($watcher); } else { Loop::disable($watcher); } $temp = $deferred; $deferred = null; \assert($temp instanceof Deferred); $temp->resolve($data); }); $this->immediateCallable = static function ($watcherId, $data) use(&$deferred) { $temp = $deferred; $deferred = null; \assert($temp instanceof Deferred); $temp->resolve($data); }; Loop::disable($this->watcher); } /** @inheritdoc */ public function read() : Promise { if ($this->deferred !== null) { throw new PendingReadError(); } if (!$this->readable) { return new Success(); // Resolve with null on closed stream. } \assert($this->resource !== null); // Attempt a direct read, because Windows suffers from slow I/O on STDIN otherwise. if ($this->useSingleRead) { $data = @\fread($this->resource, $this->chunkSize); } else { $data = @\stream_get_contents($this->resource, $this->chunkSize); } \assert($data !== \false, "Trying to read from a previously fclose()'d resource. Do NOT manually fclose() resources the loop still has a reference to."); if ($data === '') { // Error suppression, because pthreads does crazy things with resources, // which might be closed during two operations. // See https://github.com/amphp/byte-stream/issues/32 if (@\feof($this->resource)) { $this->readable = \false; $this->resource = null; Loop::cancel($this->watcher); return new Success(); // Stream closed, resolve read with null. } $this->deferred = new Deferred(); Loop::enable($this->watcher); return $this->deferred->promise(); } // Prevent an immediate read → write loop from blocking everything // See e.g. examples/benchmark-throughput.php $this->deferred = new Deferred(); $this->immediateWatcher = Loop::defer($this->immediateCallable, $data); return $this->deferred->promise(); } /** * Closes the stream forcefully. Multiple `close()` calls are ignored. * * @return void */ public function close() { if (\is_resource($this->resource)) { // Error suppression, as resource might already be closed $meta = @\stream_get_meta_data($this->resource); if ($meta && \strpos($meta["mode"], "+") !== \false) { @\stream_socket_shutdown($this->resource, \STREAM_SHUT_RD); } else { /** @psalm-suppress InvalidPropertyAssignmentValue */ @\fclose($this->resource); } } $this->free(); } /** * Nulls reference to resource, marks stream unreadable, and succeeds any pending read with null. * * @return void */ private function free() { $this->readable = \false; $this->resource = null; if ($this->deferred !== null) { $deferred = $this->deferred; $this->deferred = null; $deferred->resolve(); } Loop::cancel($this->watcher); if ($this->immediateWatcher !== null) { Loop::cancel($this->immediateWatcher); } } /** * @return resource|null The stream resource or null if the stream has closed. */ public function getResource() { return $this->resource; } /** * @return void */ public function setChunkSize(int $chunkSize) { $this->chunkSize = $chunkSize; } /** * References the read watcher, so the loop keeps running in case there's an active read. * * @return void * * @see Loop::reference() */ public function reference() { if (!$this->resource) { throw new \Error("Resource has already been freed"); } Loop::reference($this->watcher); } /** * Unreferences the read watcher, so the loop doesn't keep running even if there are active reads. * * @return void * * @see Loop::unreference() */ public function unreference() { if (!$this->resource) { throw new \Error("Resource has already been freed"); } Loop::unreference($this->watcher); } public function __destruct() { if ($this->resource !== null) { $this->free(); } } } read()) !== null) { * // Immediately use $chunk, reducing memory consumption since the entire message is never buffered. * } * * @deprecated Use Amp\ByteStream\Payload instead. */ class Message implements InputStream, Promise { /** @var InputStream */ private $source; /** @var string */ private $buffer = ""; /** @var Deferred|null */ private $pendingRead; /** @var Coroutine|null */ private $coroutine; /** @var bool True if onResolve() has been called. */ private $buffering = \false; /** @var Deferred|null */ private $backpressure; /** @var bool True if the iterator has completed. */ private $complete = \false; /** @var \Throwable|null Used to fail future reads on failure. */ private $error; /** * @param InputStream $source An iterator that only emits strings. */ public function __construct(InputStream $source) { $this->source = $source; } private function consume() : \Generator { while (($chunk = (yield $this->source->read())) !== null) { $buffer = $this->buffer .= $chunk; if ($buffer === "") { continue; // Do not succeed reads with empty string. } elseif ($this->pendingRead) { $deferred = $this->pendingRead; $this->pendingRead = null; $this->buffer = ""; $deferred->resolve($buffer); $buffer = ""; // Destroy last emitted chunk to free memory. } elseif (!$this->buffering) { $buffer = ""; // Destroy last emitted chunk to free memory. $this->backpressure = new Deferred(); (yield $this->backpressure->promise()); } } $this->complete = \true; if ($this->pendingRead) { $deferred = $this->pendingRead; $this->pendingRead = null; $deferred->resolve($this->buffer !== "" ? $this->buffer : null); $this->buffer = ""; } return $this->buffer; } /** @inheritdoc */ public final function read() : Promise { if ($this->pendingRead) { throw new PendingReadError(); } if ($this->coroutine === null) { $this->coroutine = new Coroutine($this->consume()); $this->coroutine->onResolve(function ($error) { if ($error) { $this->error = $error; } if ($this->pendingRead) { $deferred = $this->pendingRead; $this->pendingRead = null; $deferred->fail($error); } }); } if ($this->error) { return new Failure($this->error); } if ($this->buffer !== "") { $buffer = $this->buffer; $this->buffer = ""; if ($this->backpressure) { $backpressure = $this->backpressure; $this->backpressure = null; $backpressure->resolve(); } return new Success($buffer); } if ($this->complete) { return new Success(); } $this->pendingRead = new Deferred(); return $this->pendingRead->promise(); } /** @inheritdoc */ public final function onResolve(callable $onResolved) { $this->buffering = \true; if ($this->coroutine === null) { $this->coroutine = new Coroutine($this->consume()); } if ($this->backpressure) { $backpressure = $this->backpressure; $this->backpressure = null; $backpressure->resolve(); } $this->coroutine->onResolve($onResolved); } /** * Exposes the source input stream. * * This might be required to resolve a promise with an InputStream, because promises in Amp can't be resolved with * other promises. * * @return InputStream */ public final function getInputStream() : InputStream { return $this->source; } } The MIT License (MIT) Copyright (c) 2015-2019 amphp Copyright (c) 2016 PHP Asynchronous Interoperability Group Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. Has public resolve and fail methods. */ private $resolver; /** @var Promise Hides placeholder methods */ private $promise; public function __construct() { $this->resolver = new class implements Promise { use Internal\Placeholder { resolve as public; fail as public; isResolved as public; } }; $this->promise = new Internal\PrivatePromise($this->resolver); } /** * @return Promise */ public function promise() : Promise { return $this->promise; } /** * Fulfill the promise with the given value. * * @param mixed $value * * @psalm-param TValue|Promise $value * * @return void */ public function resolve($value = null) { /** @psalm-suppress UndefinedInterfaceMethod */ $this->resolver->resolve($value); } /** * Fails the promise the the given reason. * * @param \Throwable $reason * * @return void */ public function fail(\Throwable $reason) { /** @psalm-suppress UndefinedInterfaceMethod */ $this->resolver->fail($reason); } /** * @return bool True if the promise has been resolved. */ public function isResolved() : bool { return $this->resolver->isResolved(); } } * @template T as TReturn|Promise|\Generator * * @formatter:off * * @param callable(...mixed): T $callback * * @return callable * @psalm-return (T is Promise ? (callable(mixed...): Promise) : (T is \Generator ? (TGenerator is Promise ? (callable(mixed...): Promise) : (callable(mixed...): Promise)) : (callable(mixed...): Promise))) * * @formatter:on * * @see asyncCoroutine() * * @psalm-suppress InvalidReturnType */ function coroutine(callable $callback) : callable { /** @psalm-suppress InvalidReturnStatement */ return static function (...$args) use($callback) : Promise { return call($callback, ...$args); }; } /** * Returns a new function that wraps $callback in a promise/coroutine-aware function that automatically runs * Generators as coroutines. The returned function always returns void when invoked. Errors are forwarded to the * loop's error handler using `Amp\Promise\rethrow()`. * * Use this function to create a coroutine-aware callable for a non-promise-aware callback caller. * * @param callable(...mixed): mixed $callback * * @return callable * @psalm-return callable(mixed...): void * * @see coroutine() */ function asyncCoroutine(callable $callback) : callable { return static function (...$args) use($callback) { Promise\rethrow(call($callback, ...$args)); }; } /** * Calls the given function, always returning a promise. If the function returns a Generator, it will be run as a * coroutine. If the function throws, a failed promise will be returned. * * @template TReturn * @template TPromise * @template TGeneratorReturn * @template TGeneratorPromise * * @template TGenerator as TGeneratorReturn|Promise * @template T as TReturn|Promise|\Generator * * @formatter:off * * @param callable(...mixed): T $callback * @param mixed ...$args Arguments to pass to the function. * * @return Promise * @psalm-return (T is Promise ? Promise : (T is \Generator ? (TGenerator is Promise ? Promise : Promise) : Promise)) * * @formatter:on */ function call(callable $callback, ...$args) : Promise { try { $result = $callback(...$args); } catch (\Throwable $exception) { return new Failure($exception); } if ($result instanceof \Generator) { return new Coroutine($result); } if ($result instanceof Promise) { return $result; } if ($result instanceof ReactPromise) { return Promise\adapt($result); } return new Success($result); } /** * Calls the given function. If the function returns a Generator, it will be run as a coroutine. If the function * throws or returns a failing promise, the failure is forwarded to the loop error handler. * * @param callable(...mixed): mixed $callback * @param mixed ...$args Arguments to pass to the function. * * @return void */ function asyncCall(callable $callback, ...$args) { Promise\rethrow(call($callback, ...$args)); } /** * Sleeps for the specified number of milliseconds. * * @param int $milliseconds * * @return Delayed */ function delay(int $milliseconds) : Delayed { return new Delayed($milliseconds); } /** * Returns the current time relative to an arbitrary point in time. * * @return int Time in milliseconds. */ function getCurrentTime() : int { return Internal\getCurrentTime(); } namespace _HumbugBox7ff99e199a36\Amp\Promise; use _HumbugBox7ff99e199a36\Amp\Deferred; use _HumbugBox7ff99e199a36\Amp\Loop; use _HumbugBox7ff99e199a36\Amp\MultiReasonException; use _HumbugBox7ff99e199a36\Amp\Promise; use _HumbugBox7ff99e199a36\Amp\Success; use _HumbugBox7ff99e199a36\Amp\TimeoutException; use _HumbugBox7ff99e199a36\React\Promise\PromiseInterface as ReactPromise; use function _HumbugBox7ff99e199a36\Amp\call; use function _HumbugBox7ff99e199a36\Amp\Internal\createTypeError; /** * Registers a callback that will forward the failure reason to the event loop's error handler if the promise fails. * * Use this function if you neither return the promise nor handle a possible error yourself to prevent errors from * going entirely unnoticed. * * @param Promise|ReactPromise $promise Promise to register the handler on. * * @return void * @throws \TypeError If $promise is not an instance of \Amp\Promise or \React\Promise\PromiseInterface. * */ function rethrow($promise) { if (!$promise instanceof Promise) { if ($promise instanceof ReactPromise) { $promise = adapt($promise); } else { throw createTypeError([Promise::class, ReactPromise::class], $promise); } } $promise->onResolve(static function ($exception) { if ($exception) { throw $exception; } }); } /** * Runs the event loop until the promise is resolved. Should not be called within a running event loop. * * Use this function only in synchronous contexts to wait for an asynchronous operation. Use coroutines and yield to * await promise resolution in a fully asynchronous application instead. * * @template TPromise * @template T as Promise|ReactPromise * * @param Promise|ReactPromise $promise Promise to wait for. * * @return mixed Promise success value. * * @psalm-param T $promise * @psalm-return (T is Promise ? TPromise : mixed) * * @throws \TypeError If $promise is not an instance of \Amp\Promise or \React\Promise\PromiseInterface. * @throws \Error If the event loop stopped without the $promise being resolved. * @throws \Throwable Promise failure reason. */ function wait($promise) { if (!$promise instanceof Promise) { if ($promise instanceof ReactPromise) { $promise = adapt($promise); } else { throw createTypeError([Promise::class, ReactPromise::class], $promise); } } $resolved = \false; try { Loop::run(function () use(&$resolved, &$value, &$exception, $promise) { $promise->onResolve(function ($e, $v) use(&$resolved, &$value, &$exception) { Loop::stop(); $resolved = \true; $exception = $e; $value = $v; }); }); } catch (\Throwable $throwable) { throw new \Error("Loop exceptionally stopped without resolving the promise", 0, $throwable); } if (!$resolved) { throw new \Error("Loop stopped without resolving the promise"); } if ($exception) { throw $exception; } return $value; } /** * Creates an artificial timeout for any `Promise`. * * If the timeout expires before the promise is resolved, the returned promise fails with an instance of * `Amp\TimeoutException`. * * @template TReturn * * @param Promise|ReactPromise $promise Promise to which the timeout is applied. * @param int $timeout Timeout in milliseconds. * * @return Promise * * @throws \TypeError If $promise is not an instance of \Amp\Promise or \React\Promise\PromiseInterface. */ function timeout($promise, int $timeout) : Promise { if (!$promise instanceof Promise) { if ($promise instanceof ReactPromise) { $promise = adapt($promise); } else { throw createTypeError([Promise::class, ReactPromise::class], $promise); } } $deferred = new Deferred(); $watcher = Loop::delay($timeout, static function () use(&$deferred) { $temp = $deferred; // prevent double resolve $deferred = null; $temp->fail(new TimeoutException()); }); Loop::unreference($watcher); $promise->onResolve(function () use(&$deferred, $promise, $watcher) { if ($deferred !== null) { Loop::cancel($watcher); $deferred->resolve($promise); } }); return $deferred->promise(); } /** * Creates an artificial timeout for any `Promise`. * * If the promise is resolved before the timeout expires, the result is returned * * If the timeout expires before the promise is resolved, a default value is returned * * @template TReturn * * @param Promise|ReactPromise $promise Promise to which the timeout is applied. * @param int $timeout Timeout in milliseconds. * @param TReturn $default * * @return Promise * * @throws \TypeError If $promise is not an instance of \Amp\Promise or \React\Promise\PromiseInterface. */ function timeoutWithDefault($promise, int $timeout, $default = null) : Promise { $promise = timeout($promise, $timeout); return call(static function () use($promise, $default) { try { return (yield $promise); } catch (TimeoutException $exception) { return $default; } }); } /** * Adapts any object with a done(callable $onFulfilled, callable $onRejected) or then(callable $onFulfilled, * callable $onRejected) method to a promise usable by components depending on placeholders implementing * \AsyncInterop\Promise. * * @param object $promise Object with a done() or then() method. * * @return Promise Promise resolved by the $thenable object. * * @throws \Error If the provided object does not have a then() method. */ function adapt($promise) : Promise { if (!\is_object($promise)) { throw new \Error("Object must be provided"); } $deferred = new Deferred(); if (\method_exists($promise, 'done')) { $promise->done([$deferred, 'resolve'], [$deferred, 'fail']); } elseif (\method_exists($promise, 'then')) { $promise->then([$deferred, 'resolve'], [$deferred, 'fail']); } else { throw new \Error("Object must have a 'then' or 'done' method"); } return $deferred->promise(); } /** * Returns a promise that is resolved when all promises are resolved. The returned promise will not fail. * Returned promise succeeds with a two-item array delineating successful and failed promise results, * with keys identical and corresponding to the original given array. * * This function is the same as some() with the notable exception that it will never fail even * if all promises in the array resolve unsuccessfully. * * @template TValue * * @param Promise[]|ReactPromise[] $promises * * @return Promise * * @throws \Error If a non-Promise is in the array. */ function any(array $promises) : Promise { return some($promises, 0); } /** * Returns a promise that succeeds when all promises succeed, and fails if any promise fails. Returned * promise succeeds with an array of values used to succeed each contained promise, with keys corresponding to * the array of promises. * * @param Promise[]|ReactPromise[] $promises Array of only promises. * * @return Promise * * @throws \Error If a non-Promise is in the array. * * @template TValue * * @psalm-param array|ReactPromise> $promises * @psalm-assert array|ReactPromise> $promises $promises * @psalm-return Promise> */ function all(array $promises) : Promise { if (empty($promises)) { return new Success([]); } $deferred = new Deferred(); $result = $deferred->promise(); $pending = \count($promises); $values = []; foreach ($promises as $key => $promise) { if ($promise instanceof ReactPromise) { $promise = adapt($promise); } elseif (!$promise instanceof Promise) { throw createTypeError([Promise::class, ReactPromise::class], $promise); } $values[$key] = null; // add entry to array to preserve order $promise->onResolve(function ($exception, $value) use(&$deferred, &$values, &$pending, $key) { if ($pending === 0) { return; } if ($exception) { $pending = 0; $deferred->fail($exception); $deferred = null; return; } $values[$key] = $value; if (0 === --$pending) { $deferred->resolve($values); } }); } return $result; } /** * Returns a promise that succeeds when the first promise succeeds, and fails only if all promises fail. * * @template TValue * * @param Promise[]|ReactPromise[] $promises Array of only promises. * * @return Promise * * @throws \Error If the array is empty or a non-Promise is in the array. */ function first(array $promises) : Promise { if (empty($promises)) { throw new \Error("No promises provided"); } $deferred = new Deferred(); $result = $deferred->promise(); $pending = \count($promises); $exceptions = []; foreach ($promises as $key => $promise) { if ($promise instanceof ReactPromise) { $promise = adapt($promise); } elseif (!$promise instanceof Promise) { throw createTypeError([Promise::class, ReactPromise::class], $promise); } $exceptions[$key] = null; // add entry to array to preserve order $promise->onResolve(function ($error, $value) use(&$deferred, &$exceptions, &$pending, $key) { if ($pending === 0) { return; } if (!$error) { $pending = 0; $deferred->resolve($value); $deferred = null; return; } $exceptions[$key] = $error; if (0 === --$pending) { $deferred->fail(new MultiReasonException($exceptions)); } }); } return $result; } /** * Resolves with a two-item array delineating successful and failed Promise results. * * The returned promise will only fail if the given number of required promises fail. * * @template TValue * * @param Promise[]|ReactPromise[] $promises Array of only promises. * @param int $required Number of promises that must succeed for the * returned promise to succeed. * * @return Promise * * @throws \Error If a non-Promise is in the array. */ function some(array $promises, int $required = 1) : Promise { if ($required < 0) { throw new \Error("Number of promises required must be non-negative"); } $pending = \count($promises); if ($required > $pending) { throw new \Error("Too few promises provided"); } if (empty($promises)) { return new Success([[], []]); } $deferred = new Deferred(); $result = $deferred->promise(); $values = []; $exceptions = []; foreach ($promises as $key => $promise) { if ($promise instanceof ReactPromise) { $promise = adapt($promise); } elseif (!$promise instanceof Promise) { throw createTypeError([Promise::class, ReactPromise::class], $promise); } $values[$key] = $exceptions[$key] = null; // add entry to arrays to preserve order $promise->onResolve(static function ($exception, $value) use(&$values, &$exceptions, &$pending, $key, $required, $deferred) { if ($exception) { $exceptions[$key] = $exception; unset($values[$key]); } else { $values[$key] = $value; unset($exceptions[$key]); } if (0 === --$pending) { if (\count($values) < $required) { $deferred->fail(new MultiReasonException($exceptions)); } else { $deferred->resolve([$exceptions, $values]); } } }); } return $result; } /** * Wraps a promise into another promise, altering the exception or result. * * @param Promise|ReactPromise $promise * @param callable $callback * * @return Promise */ function wrap($promise, callable $callback) : Promise { if ($promise instanceof ReactPromise) { $promise = adapt($promise); } elseif (!$promise instanceof Promise) { throw createTypeError([Promise::class, ReactPromise::class], $promise); } $deferred = new Deferred(); $promise->onResolve(static function (?\Throwable $exception, $result) use($deferred, $callback) { try { $result = $callback($exception, $result); } catch (\Throwable $exception) { $deferred->fail($exception); return; } $deferred->resolve($result); }); return $deferred->promise(); } namespace _HumbugBox7ff99e199a36\Amp\Iterator; use _HumbugBox7ff99e199a36\Amp\Delayed; use _HumbugBox7ff99e199a36\Amp\Emitter; use _HumbugBox7ff99e199a36\Amp\Iterator; use _HumbugBox7ff99e199a36\Amp\Producer; use _HumbugBox7ff99e199a36\Amp\Promise; use function _HumbugBox7ff99e199a36\Amp\call; use function _HumbugBox7ff99e199a36\Amp\coroutine; use function _HumbugBox7ff99e199a36\Amp\Internal\createTypeError; /** * Creates an iterator from the given iterable, emitting the each value. The iterable may contain promises. If any * promise fails, the iterator will fail with the same reason. * * @param array|\Traversable $iterable Elements to emit. * @param int $delay Delay between element emissions in milliseconds. * * @return Iterator * * @throws \TypeError If the argument is not an array or instance of \Traversable. */ function fromIterable($iterable, int $delay = 0) : Iterator { if (!$iterable instanceof \Traversable && !\is_array($iterable)) { throw createTypeError(["array", "Traversable"], $iterable); } if ($delay) { return new Producer(static function (callable $emit) use($iterable, $delay) { foreach ($iterable as $value) { (yield new Delayed($delay)); (yield $emit($value)); } }); } return new Producer(static function (callable $emit) use($iterable) { foreach ($iterable as $value) { (yield $emit($value)); } }); } /** * @template TValue * @template TReturn * * @param Iterator $iterator * @param callable (TValue $value): TReturn $onEmit * * @return Iterator */ function map(Iterator $iterator, callable $onEmit) : Iterator { return new Producer(static function (callable $emit) use($iterator, $onEmit) { while ((yield $iterator->advance())) { (yield $emit($onEmit($iterator->getCurrent()))); } }); } /** * @template TValue * * @param Iterator $iterator * @param callable(TValue $value):bool $filter * * @return Iterator */ function filter(Iterator $iterator, callable $filter) : Iterator { return new Producer(static function (callable $emit) use($iterator, $filter) { while ((yield $iterator->advance())) { if ($filter($iterator->getCurrent())) { (yield $emit($iterator->getCurrent())); } } }); } /** * Creates an iterator that emits values emitted from any iterator in the array of iterators. * * @param Iterator[] $iterators * * @return Iterator */ function merge(array $iterators) : Iterator { $emitter = new Emitter(); $result = $emitter->iterate(); $coroutine = coroutine(static function (Iterator $iterator) use(&$emitter) { while ((yield $iterator->advance()) && $emitter !== null) { (yield $emitter->emit($iterator->getCurrent())); } }); $coroutines = []; foreach ($iterators as $iterator) { if (!$iterator instanceof Iterator) { throw createTypeError([Iterator::class], $iterator); } $coroutines[] = $coroutine($iterator); } Promise\all($coroutines)->onResolve(static function ($exception) use(&$emitter) { if ($exception) { $emitter->fail($exception); $emitter = null; } else { $emitter->complete(); } }); return $result; } /** * Concatenates the given iterators into a single iterator, emitting values from a single iterator at a time. The * prior iterator must complete before values are emitted from any subsequent iterators. Iterators are concatenated * in the order given (iteration order of the array). * * @param Iterator[] $iterators * * @return Iterator */ function concat(array $iterators) : Iterator { foreach ($iterators as $iterator) { if (!$iterator instanceof Iterator) { throw createTypeError([Iterator::class], $iterator); } } $emitter = new Emitter(); $previous = []; $promise = Promise\all($previous); $coroutine = coroutine(static function (Iterator $iterator, callable $emit) { while ((yield $iterator->advance())) { (yield $emit($iterator->getCurrent())); } }); foreach ($iterators as $iterator) { $emit = coroutine(static function ($value) use($emitter, $promise) { static $pending = \true, $failed = \false; if ($failed) { return; } if ($pending) { try { (yield $promise); $pending = \false; } catch (\Throwable $exception) { $failed = \true; return; // Prior iterator failed. } } (yield $emitter->emit($value)); }); $previous[] = $coroutine($iterator, $emit); $promise = Promise\all($previous); } $promise->onResolve(static function ($exception) use($emitter) { if ($exception) { $emitter->fail($exception); return; } $emitter->complete(); }); return $emitter->iterate(); } /** * Discards all remaining items and returns the number of discarded items. * * @template TValue * * @param Iterator $iterator * * @return Promise * * @psalm-param Iterator $iterator * @psalm-return Promise */ function discard(Iterator $iterator) : Promise { return call(static function () use($iterator) : \Generator { $count = 0; while ((yield $iterator->advance())) { $count++; } return $count; }); } /** * Collects all items from an iterator into an array. * * @template TValue * * @param Iterator $iterator * * @psalm-param Iterator $iterator * * @return Promise * @psalm-return Promise> */ function toArray(Iterator $iterator) : Promise { return call(static function () use($iterator) { /** @psalm-var list $array */ $array = []; while ((yield $iterator->advance())) { $array[] = $iterator->getCurrent(); } return $array; }); } , mixed, * mixed>|null) | callable(\Throwable|null, mixed): void $onResolved * * @return void */ public function onResolve(callable $onResolved); } */ final class Coroutine implements Promise { use Internal\Placeholder; /** * Attempts to transform the non-promise yielded from the generator into a promise, otherwise returns an instance * `Amp\Failure` failed with an instance of `Amp\InvalidYieldError`. * * @param mixed $yielded Non-promise yielded from generator. * @param \Generator $generator No type for performance, we already know the type. * * @return Promise */ private static function transform($yielded, $generator) : Promise { $exception = null; // initialize here, see https://github.com/vimeo/psalm/issues/2951 try { if (\is_array($yielded)) { return Promise\all($yielded); } if ($yielded instanceof ReactPromise) { return Promise\adapt($yielded); } // No match, continue to returning Failure below. } catch (\Throwable $exception) { // Conversion to promise failed, fall-through to returning Failure below. } return new Failure(new InvalidYieldError($generator, \sprintf("Unexpected yield; Expected an instance of %s or %s or an array of such instances", Promise::class, ReactPromise::class), $exception)); } /** * @param \Generator $generator * @psalm-param \Generator,mixed,Promise|ReactPromise|TReturn> $generator */ public function __construct(\Generator $generator) { try { $yielded = $generator->current(); if (!$yielded instanceof Promise) { if (!$generator->valid()) { $this->resolve($generator->getReturn()); return; } $yielded = self::transform($yielded, $generator); } } catch (\Throwable $exception) { $this->fail($exception); return; } /** * @param \Throwable|null $e Exception to be thrown into the generator. * @param mixed $v Value to be sent into the generator. * * @return void * * @psalm-suppress MissingClosureParamType * @psalm-suppress MissingClosureReturnType */ $onResolve = function (?\Throwable $e, $v) use($generator, &$onResolve) { /** @var bool $immediate Used to control iterative coroutine continuation. */ static $immediate = \true; /** @var \Throwable|null $exception Promise failure reason when executing next coroutine step, null at all other times. */ static $exception; /** @var mixed $value Promise success value when executing next coroutine step, null at all other times. */ static $value; $exception = $e; /** @psalm-suppress MixedAssignment */ $value = $v; if (!$immediate) { $immediate = \true; return; } try { try { do { if ($exception) { // Throw exception at current execution point. $yielded = $generator->throw($exception); } else { // Send the new value and execute to next yield statement. $yielded = $generator->send($value); } if (!$yielded instanceof Promise) { if (!$generator->valid()) { $this->resolve($generator->getReturn()); $onResolve = null; return; } $yielded = self::transform($yielded, $generator); } $immediate = \false; $yielded->onResolve($onResolve); } while ($immediate); $immediate = \true; } catch (\Throwable $exception) { $this->fail($exception); $onResolve = null; } finally { $exception = null; $value = null; } } catch (\Throwable $e) { Loop::defer(static function () use($e) { throw $e; }); } }; try { $yielded->onResolve($onResolve); unset($generator, $yielded, $onResolve); } catch (\Throwable $e) { Loop::defer(static function () use($e) { throw $e; }); } } } exception; $thatCallbacks =& $this->callbacks; foreach ($tokens as $token) { $id = $token->subscribe(static function (CancelledException $exception) use(&$thatException, &$thatCallbacks) { $thatException = $exception; $callbacks = $thatCallbacks; $thatCallbacks = []; foreach ($callbacks as $callback) { asyncCall($callback, $thatException); } }); $this->tokens[] = [$token, $id]; } } public function __destruct() { foreach ($this->tokens as list($token, $id)) { /** @var CancellationToken $token */ $token->unsubscribe($id); } } /** @inheritdoc */ public function subscribe(callable $callback) : string { $id = $this->nextId++; if ($this->exception) { asyncCall($callback, $this->exception); } else { $this->callbacks[$id] = $callback; } return $id; } /** @inheritdoc */ public function unsubscribe(string $id) { unset($this->callbacks[$id]); } /** @inheritdoc */ public function isRequested() : bool { foreach ($this->tokens as list($token)) { if ($token->isRequested()) { return \true; } } return \false; } /** @inheritdoc */ public function throwIfRequested() { foreach ($this->tokens as list($token)) { $token->throwIfRequested(); } } } $trace Output of * `debug_backtrace()`. * * @return string Formatted stacktrace. * * @codeCoverageIgnore * @internal */ function formatStacktrace(array $trace) : string { return \implode("\n", \array_map(static function ($e, $i) { $line = "#{$i} "; if (isset($e["file"])) { $line .= "{$e['file']}:{$e['line']} "; } if (isset($e["type"])) { $line .= $e["class"] . $e["type"]; } return $line . $e["function"] . "()"; }, $trace, \array_keys($trace))); } /** * Creates a `TypeError` with a standardized error message. * * @param string[] $expected Expected types. * @param mixed $given Given value. * * @return \TypeError * * @internal */ function createTypeError(array $expected, $given) : \TypeError { $givenType = \is_object($given) ? \sprintf("instance of %s", \get_class($given)) : \gettype($given); if (\count($expected) === 1) { $expectedType = "Expected the following type: " . \array_pop($expected); } else { $expectedType = "Expected one of the following types: " . \implode(", ", $expected); } return new \TypeError("{$expectedType}; {$givenType} given"); } /** * Returns the current time relative to an arbitrary point in time. * * @return int Time in milliseconds. */ function getCurrentTime() : int { /** @var int|null $startTime */ static $startTime; /** @var int|null $nextWarning */ static $nextWarning; if (\PHP_INT_SIZE === 4) { // @codeCoverageIgnoreStart if ($startTime === null) { $startTime = \PHP_VERSION_ID >= 70300 ? \hrtime(\false)[0] : \time(); $nextWarning = \PHP_INT_MAX - 86400 * 7; } if (\PHP_VERSION_ID >= 70300) { list($seconds, $nanoseconds) = \hrtime(\false); $seconds -= $startTime; if ($seconds >= $nextWarning) { $timeToOverflow = (\PHP_INT_MAX - $seconds * 1000) / 1000; \trigger_error("getCurrentTime() will overflow in {$timeToOverflow} seconds, please restart the process before that. " . "You're using a 32 bit version of PHP, so time will overflow about every 24 days. Regular restarts are required.", \E_USER_WARNING); /** @psalm-suppress PossiblyNullOperand */ $nextWarning += 600; // every 10 minutes } return (int) ($seconds * 1000 + $nanoseconds / 1000000); } $seconds = \microtime(\true) - $startTime; if ($seconds >= $nextWarning) { $timeToOverflow = (\PHP_INT_MAX - $seconds * 1000) / 1000; \trigger_error("getCurrentTime() will overflow in {$timeToOverflow} seconds, please restart the process before that. " . "You're using a 32 bit version of PHP, so time will overflow about every 24 days. Regular restarts are required.", \E_USER_WARNING); /** @psalm-suppress PossiblyNullOperand */ $nextWarning += 600; // every 10 minutes } return (int) ($seconds * 1000); // @codeCoverageIgnoreEnd } if (\PHP_VERSION_ID >= 70300) { list($seconds, $nanoseconds) = \hrtime(\false); return (int) ($seconds * 1000 + $nanoseconds / 1000000); } return (int) (\microtime(\true) * 1000); } */ final class PrivateIterator implements Iterator { /** @var Iterator */ private $iterator; /** * @param Iterator $iterator * * @psalm-param Iterator $iterator */ public function __construct(Iterator $iterator) { $this->iterator = $iterator; } /** * @return Promise */ public function advance() : Promise { return $this->iterator->advance(); } /** * @psalm-return TValue */ public function getCurrent() { return $this->iterator->getCurrent(); } } promise = $promise; } public function onResolve(callable $onResolved) { $this->promise->onResolve($onResolved); } } */ public function advance() : Promise { if ($this->waiting !== null) { throw new \Error("The prior promise returned must resolve before invoking this method again"); } unset($this->values[$this->consumePosition]); $position = ++$this->consumePosition; if (\array_key_exists($position, $this->values)) { \assert(isset($this->backPressure[$position])); $deferred = $this->backPressure[$position]; unset($this->backPressure[$position]); $deferred->resolve(); return new Success(\true); } if ($this->complete) { return $this->complete; } $this->waiting = new Deferred(); return $this->waiting->promise(); } /** * {@inheritdoc} * * @return TValue */ public function getCurrent() { if (empty($this->values) && $this->complete) { throw new \Error("The iterator has completed"); } if (!\array_key_exists($this->consumePosition, $this->values)) { throw new \Error("Promise returned from advance() must resolve before calling this method"); } return $this->values[$this->consumePosition]; } /** * Emits a value from the iterator. The returned promise is resolved once the emitted value has been consumed. * * @param mixed $value * * @return Promise * @psalm-return Promise * * @throws \Error If the iterator has completed. */ private function emit($value) : Promise { if ($this->complete) { throw new \Error("Iterators cannot emit values after calling complete"); } if ($value instanceof ReactPromise) { $value = Promise\adapt($value); } if ($value instanceof Promise) { $deferred = new Deferred(); $value->onResolve(function ($e, $v) use($deferred) { if ($this->complete) { $deferred->fail(new \Error("The iterator was completed before the promise result could be emitted")); return; } if ($e) { $this->fail($e); $deferred->fail($e); return; } $deferred->resolve($this->emit($v)); }); return $deferred->promise(); } $position = ++$this->emitPosition; $this->values[$position] = $value; if ($this->waiting !== null) { $waiting = $this->waiting; $this->waiting = null; $waiting->resolve(\true); return new Success(); // Consumer was already waiting for a new value, so back-pressure is unnecessary. } $this->backPressure[$position] = $pressure = new Deferred(); return $pressure->promise(); } /** * Completes the iterator. * * @return void * * @throws \Error If the iterator has already been completed. */ private function complete() { if ($this->complete) { $message = "Iterator has already been completed"; if (isset($this->resolutionTrace)) { $trace = formatStacktrace($this->resolutionTrace); $message .= ". Previous completion trace:\n\n{$trace}\n\n"; } else { // @codeCoverageIgnoreStart $message .= ", define environment variable AMP_DEBUG or const AMP_DEBUG = true and enable assertions " . "for a stacktrace of the previous resolution."; // @codeCoverageIgnoreEnd } throw new \Error($message); } \assert((function () { $env = \getenv("AMP_DEBUG") ?: "0"; if ($env !== "0" && $env !== "false" || \defined("_HumbugBox7ff99e199a36\\AMP_DEBUG") && \_HumbugBox7ff99e199a36\AMP_DEBUG) { $trace = \debug_backtrace(\DEBUG_BACKTRACE_IGNORE_ARGS); \array_shift($trace); // remove current closure $this->resolutionTrace = $trace; } return \true; })()); $this->complete = new Success(\false); if ($this->waiting !== null) { $waiting = $this->waiting; $this->waiting = null; $waiting->resolve($this->complete); } } /** * @param \Throwable $exception * * @return void */ private function fail(\Throwable $exception) { $this->complete = new Failure($exception); if ($this->waiting !== null) { $waiting = $this->waiting; $this->waiting = null; $waiting->resolve($this->complete); } } } , mixed, * mixed>|null) | callable(\Throwable|null, mixed): void> */ private $queue = []; /** * @param callable|null $callback Initial callback to add to queue. * * @psalm-param null|callable(\Throwable|null, mixed): (Promise|\React\Promise\PromiseInterface|\Generator, mixed, * mixed>|null) | callable(\Throwable|null, mixed): void $callback */ public function __construct(?callable $callback = null) { if ($callback !== null) { $this->push($callback); } } /** * Unrolls instances of self to avoid blowing up the call stack on resolution. * * @param callable $callback * * @psalm-param callable(\Throwable|null, mixed): (Promise|\React\Promise\PromiseInterface|\Generator, mixed, * mixed>|null) | callable(\Throwable|null, mixed): void $callback * * @return void */ public function push(callable $callback) { if ($callback instanceof self) { $this->queue = \array_merge($this->queue, $callback->queue); return; } $this->queue[] = $callback; } /** * Calls each callback in the queue, passing the provided values to the function. * * @param \Throwable|null $exception * @param mixed $value * * @return void */ public function __invoke($exception, $value) { foreach ($this->queue as $callback) { try { $result = $callback($exception, $value); if ($result === null) { continue; } if ($result instanceof \Generator) { $result = new Coroutine($result); } if ($result instanceof Promise || $result instanceof ReactPromise) { Promise\rethrow($result); } } catch (\Throwable $exception) { Loop::defer(static function () use($exception) { throw $exception; }); } } } } , mixed, * mixed>|null)|callable(\Throwable|null, mixed): void */ private $onResolved; /** @var null|array */ private $resolutionTrace; /** * @inheritdoc */ public function onResolve(callable $onResolved) { if ($this->resolved) { if ($this->result instanceof Promise) { $this->result->onResolve($onResolved); return; } try { /** @var mixed $result */ $result = $onResolved(null, $this->result); if ($result === null) { return; } if ($result instanceof \Generator) { $result = new Coroutine($result); } if ($result instanceof Promise || $result instanceof ReactPromise) { Promise\rethrow($result); } } catch (\Throwable $exception) { Loop::defer(static function () use($exception) { throw $exception; }); } return; } if (null === $this->onResolved) { $this->onResolved = $onResolved; return; } if (!$this->onResolved instanceof ResolutionQueue) { /** @psalm-suppress InternalClass */ $this->onResolved = new ResolutionQueue($this->onResolved); } /** @psalm-suppress InternalMethod */ $this->onResolved->push($onResolved); } public function __destruct() { try { $this->result = null; } catch (\Throwable $e) { Loop::defer(static function () use($e) { throw $e; }); } } /** * @param mixed $value * * @return void * * @throws \Error Thrown if the promise has already been resolved. */ private function resolve($value = null) { if ($this->resolved) { $message = "Promise has already been resolved"; if (isset($this->resolutionTrace)) { $trace = formatStacktrace($this->resolutionTrace); $message .= ". Previous resolution trace:\n\n{$trace}\n\n"; } else { // @codeCoverageIgnoreStart $message .= ", define environment variable AMP_DEBUG or const AMP_DEBUG = true and enable assertions " . "for a stacktrace of the previous resolution."; // @codeCoverageIgnoreEnd } throw new \Error($message); } \assert((function () { $env = \getenv("AMP_DEBUG") ?: "0"; if ($env !== "0" && $env !== "false" || \defined("_HumbugBox7ff99e199a36\\AMP_DEBUG") && \_HumbugBox7ff99e199a36\AMP_DEBUG) { $trace = \debug_backtrace(\DEBUG_BACKTRACE_IGNORE_ARGS); \array_shift($trace); // remove current closure $this->resolutionTrace = $trace; } return \true; })()); if ($value instanceof ReactPromise) { $value = Promise\adapt($value); } $this->resolved = \true; $this->result = $value; if ($this->onResolved === null) { return; } $onResolved = $this->onResolved; $this->onResolved = null; if ($this->result instanceof Promise) { $this->result->onResolve($onResolved); return; } try { /** @var mixed $result */ $result = $onResolved(null, $this->result); $onResolved = null; // allow garbage collection of $onResolved, to catch any exceptions from destructors if ($result === null) { return; } if ($result instanceof \Generator) { $result = new Coroutine($result); } if ($result instanceof Promise || $result instanceof ReactPromise) { Promise\rethrow($result); } } catch (\Throwable $exception) { Loop::defer(static function () use($exception) { throw $exception; }); } } /** * @param \Throwable $reason Failure reason. * * @return void */ private function fail(\Throwable $reason) { $this->resolve(new Failure($reason)); } /** * @return bool True if the placeholder has been resolved. */ private function isResolved() : bool { return $this->resolved; } } defer($callback); } self::$driver->run(); } /** * Stop the event loop. * * When an event loop is stopped, it continues with its current tick and exits the loop afterwards. Multiple calls * to stop MUST be ignored and MUST NOT raise an exception. * * @return void */ public static function stop() { self::$driver->stop(); } /** * Defer the execution of a callback. * * The deferred callable MUST be executed before any other type of watcher in a tick. Order of enabling MUST be * preserved when executing the callbacks. * * The created watcher MUST immediately be marked as enabled, but only be activated (i.e. callback can be called) * right before the next tick. Callbacks of watchers MUST NOT be called in the tick they were enabled. * * @param callable(string $watcherId, mixed $data) $callback The callback to defer. The `$watcherId` will be * invalidated before the callback call. * @param mixed $data Arbitrary data given to the callback function as the `$data` parameter. * * @return string An unique identifier that can be used to cancel, enable or disable the watcher. */ public static function defer(callable $callback, $data = null) : string { return self::$driver->defer($callback, $data); } /** * Delay the execution of a callback. * * The delay is a minimum and approximate, accuracy is not guaranteed. Order of calls MUST be determined by which * timers expire first, but timers with the same expiration time MAY be executed in any order. * * The created watcher MUST immediately be marked as enabled, but only be activated (i.e. callback can be called) * right before the next tick. Callbacks of watchers MUST NOT be called in the tick they were enabled. * * @param int $delay The amount of time, in milliseconds, to delay the execution for. * @param callable(string $watcherId, mixed $data) $callback The callback to delay. The `$watcherId` will be * invalidated before the callback call. * @param mixed $data Arbitrary data given to the callback function as the `$data` parameter. * * @return string An unique identifier that can be used to cancel, enable or disable the watcher. */ public static function delay(int $delay, callable $callback, $data = null) : string { return self::$driver->delay($delay, $callback, $data); } /** * Repeatedly execute a callback. * * The interval between executions is a minimum and approximate, accuracy is not guaranteed. Order of calls MUST be * determined by which timers expire first, but timers with the same expiration time MAY be executed in any order. * The first execution is scheduled after the first interval period. * * The created watcher MUST immediately be marked as enabled, but only be activated (i.e. callback can be called) * right before the next tick. Callbacks of watchers MUST NOT be called in the tick they were enabled. * * @param int $interval The time interval, in milliseconds, to wait between executions. * @param callable(string $watcherId, mixed $data) $callback The callback to repeat. * @param mixed $data Arbitrary data given to the callback function as the `$data` parameter. * * @return string An unique identifier that can be used to cancel, enable or disable the watcher. */ public static function repeat(int $interval, callable $callback, $data = null) : string { return self::$driver->repeat($interval, $callback, $data); } /** * Execute a callback when a stream resource becomes readable or is closed for reading. * * Warning: Closing resources locally, e.g. with `fclose`, might not invoke the callback. Be sure to `cancel` the * watcher when closing the resource locally. Drivers MAY choose to notify the user if there are watchers on invalid * resources, but are not required to, due to the high performance impact. Watchers on closed resources are * therefore undefined behavior. * * Multiple watchers on the same stream MAY be executed in any order. * * The created watcher MUST immediately be marked as enabled, but only be activated (i.e. callback can be called) * right before the next tick. Callbacks of watchers MUST NOT be called in the tick they were enabled. * * @param resource $stream The stream to monitor. * @param callable(string $watcherId, resource $stream, mixed $data) $callback The callback to execute. * @param mixed $data Arbitrary data given to the callback function as the `$data` parameter. * * @return string An unique identifier that can be used to cancel, enable or disable the watcher. */ public static function onReadable($stream, callable $callback, $data = null) : string { return self::$driver->onReadable($stream, $callback, $data); } /** * Execute a callback when a stream resource becomes writable or is closed for writing. * * Warning: Closing resources locally, e.g. with `fclose`, might not invoke the callback. Be sure to `cancel` the * watcher when closing the resource locally. Drivers MAY choose to notify the user if there are watchers on invalid * resources, but are not required to, due to the high performance impact. Watchers on closed resources are * therefore undefined behavior. * * Multiple watchers on the same stream MAY be executed in any order. * * The created watcher MUST immediately be marked as enabled, but only be activated (i.e. callback can be called) * right before the next tick. Callbacks of watchers MUST NOT be called in the tick they were enabled. * * @param resource $stream The stream to monitor. * @param callable(string $watcherId, resource $stream, mixed $data) $callback The callback to execute. * @param mixed $data Arbitrary data given to the callback function as the `$data` parameter. * * @return string An unique identifier that can be used to cancel, enable or disable the watcher. */ public static function onWritable($stream, callable $callback, $data = null) : string { return self::$driver->onWritable($stream, $callback, $data); } /** * Execute a callback when a signal is received. * * Warning: Installing the same signal on different instances of this interface is deemed undefined behavior. * Implementations MAY try to detect this, if possible, but are not required to. This is due to technical * limitations of the signals being registered globally per process. * * Multiple watchers on the same signal MAY be executed in any order. * * The created watcher MUST immediately be marked as enabled, but only be activated (i.e. callback can be called) * right before the next tick. Callbacks of watchers MUST NOT be called in the tick they were enabled. * * @param int $signo The signal number to monitor. * @param callable(string $watcherId, int $signo, mixed $data) $callback The callback to execute. * @param mixed $data Arbitrary data given to the callback function as the $data parameter. * * @return string An unique identifier that can be used to cancel, enable or disable the watcher. * * @throws UnsupportedFeatureException If signal handling is not supported. */ public static function onSignal(int $signo, callable $callback, $data = null) : string { return self::$driver->onSignal($signo, $callback, $data); } /** * Enable a watcher to be active starting in the next tick. * * Watchers MUST immediately be marked as enabled, but only be activated (i.e. callbacks can be called) right before * the next tick. Callbacks of watchers MUST NOT be called in the tick they were enabled. * * @param string $watcherId The watcher identifier. * * @return void * * @throws InvalidWatcherError If the watcher identifier is invalid. */ public static function enable(string $watcherId) { self::$driver->enable($watcherId); } /** * Disable a watcher immediately. * * A watcher MUST be disabled immediately, e.g. if a defer watcher disables a later defer watcher, the second defer * watcher isn't executed in this tick. * * Disabling a watcher MUST NOT invalidate the watcher. Calling this function MUST NOT fail, even if passed an * invalid watcher. * * @param string $watcherId The watcher identifier. * * @return void */ public static function disable(string $watcherId) { if (\PHP_VERSION_ID < 70200 && !isset(self::$driver)) { // Prior to PHP 7.2, self::$driver may be unset during destruct. // See https://github.com/amphp/amp/issues/212. return; } self::$driver->disable($watcherId); } /** * Cancel a watcher. * * This will detatch the event loop from all resources that are associated to the watcher. After this operation the * watcher is permanently invalid. Calling this function MUST NOT fail, even if passed an invalid watcher. * * @param string $watcherId The watcher identifier. * * @return void */ public static function cancel(string $watcherId) { if (\PHP_VERSION_ID < 70200 && !isset(self::$driver)) { // Prior to PHP 7.2, self::$driver may be unset during destruct. // See https://github.com/amphp/amp/issues/212. return; } self::$driver->cancel($watcherId); } /** * Reference a watcher. * * This will keep the event loop alive whilst the watcher is still being monitored. Watchers have this state by * default. * * @param string $watcherId The watcher identifier. * * @return void * * @throws InvalidWatcherError If the watcher identifier is invalid. */ public static function reference(string $watcherId) { self::$driver->reference($watcherId); } /** * Unreference a watcher. * * The event loop should exit the run method when only unreferenced watchers are still being monitored. Watchers * are all referenced by default. * * @param string $watcherId The watcher identifier. * * @return void */ public static function unreference(string $watcherId) { if (\PHP_VERSION_ID < 70200 && !isset(self::$driver)) { // Prior to PHP 7.2, self::$driver may be unset during destruct. // See https://github.com/amphp/amp/issues/212. return; } self::$driver->unreference($watcherId); } /** * Returns the current loop time in millisecond increments. Note this value does not necessarily correlate to * wall-clock time, rather the value returned is meant to be used in relative comparisons to prior values returned * by this method (intervals, expiration calculations, etc.) and is only updated once per loop tick. * * @return int */ public static function now() : int { return self::$driver->now(); } /** * Stores information in the loop bound registry. * * Stored information is package private. Packages MUST NOT retrieve the stored state of other packages. Packages * MUST use their namespace as prefix for keys. They may do so by using `SomeClass::class` as key. * * If packages want to expose loop bound state to consumers other than the package, they SHOULD provide a dedicated * interface for that purpose instead of sharing the storage key. * * @param string $key The namespaced storage key. * @param mixed $value The value to be stored. * * @return void */ public static function setState(string $key, $value) { self::$driver->setState($key, $value); } /** * Gets information stored bound to the loop. * * Stored information is package private. Packages MUST NOT retrieve the stored state of other packages. Packages * MUST use their namespace as prefix for keys. They may do so by using `SomeClass::class` as key. * * If packages want to expose loop bound state to consumers other than the package, they SHOULD provide a dedicated * interface for that purpose instead of sharing the storage key. * * @param string $key The namespaced storage key. * * @return mixed The previously stored value or `null` if it doesn't exist. */ public static function getState(string $key) { return self::$driver->getState($key); } /** * Set a callback to be executed when an error occurs. * * The callback receives the error as the first and only parameter. The return value of the callback gets ignored. * If it can't handle the error, it MUST throw the error. Errors thrown by the callback or during its invocation * MUST be thrown into the `run` loop and stop the driver. * * Subsequent calls to this method will overwrite the previous handler. * * @param callable(\Throwable $error)|null $callback The callback to execute. `null` will clear the * current handler. * * @return callable(\Throwable $error)|null The previous handler, `null` if there was none. */ public static function setErrorHandler(?callable $callback = null) { return self::$driver->setErrorHandler($callback); } /** * Retrieve an associative array of information about the event loop driver. * * The returned array MUST contain the following data describing the driver's currently registered watchers: * * [ * "defer" => ["enabled" => int, "disabled" => int], * "delay" => ["enabled" => int, "disabled" => int], * "repeat" => ["enabled" => int, "disabled" => int], * "on_readable" => ["enabled" => int, "disabled" => int], * "on_writable" => ["enabled" => int, "disabled" => int], * "on_signal" => ["enabled" => int, "disabled" => int], * "enabled_watchers" => ["referenced" => int, "unreferenced" => int], * "running" => bool * ]; * * Implementations MAY optionally add more information in the array but at minimum the above `key => value` format * MUST always be provided. * * @return array Statistics about the loop in the described format. */ public static function getInfo() : array { return self::$driver->getInfo(); } /** * Retrieve the event loop driver that is in scope. * * @return Driver */ public static function get() : Driver { return self::$driver; } } // Default factory, don't move this to a file loaded by the composer "files" autoload mechanism, otherwise custom // implementations might have issues setting a default loop, because it's overridden by us then. // @codeCoverageIgnoreStart Loop::set((new DriverFactory())->create()); // @codeCoverageIgnoreEnd getMethod($method); } return self::$__reflectionMethods[$method]->getClosure($this); } /** * Creates a callable from a protected or private static method that may be invoked by methods requiring a * publicly invokable callback. * * @param string $method Static method name. * * @return callable * * @psalm-suppress MixedInferredReturnType */ private static function callableFromStaticMethod(string $method) : callable { if (!isset(self::$__reflectionMethods[$method])) { if (self::$__reflectionClass === null) { self::$__reflectionClass = new \ReflectionClass(self::class); } self::$__reflectionMethods[$method] = self::$__reflectionClass->getMethod($method); } return self::$__reflectionMethods[$method]->getClosure(); } } } else { /** @psalm-suppress DuplicateClass */ trait CallableMaker { /** * @deprecated Use \Closure::fromCallable() instead of this method in PHP 7.1. */ private function callableFromInstanceMethod(string $method) : callable { return \Closure::fromCallable([$this, $method]); } /** * @deprecated Use \Closure::fromCallable() instead of this method in PHP 7.1. */ private static function callableFromStaticMethod(string $method) : callable { return \Closure::fromCallable([self::class, $method]); } } } // @codeCoverageIgnoreEnd promisor = $promisor; } /** * {@inheritdoc} */ public function onResolve(callable $onResolved) { if ($this->promise === null) { \assert($this->promisor !== null); $provider = $this->promisor; $this->promisor = null; $this->promise = call($provider); } \assert($this->promise !== null); $this->promise->onResolve($onResolved); } } generateStructPropertyError($property)); } /** * @param string $property * @param mixed $value * * @psalm-return no-return */ public function __set(string $property, $value) { throw new \Error($this->generateStructPropertyError($property)); } private function generateStructPropertyError(string $property) : string { $suggestion = $this->suggestPropertyName($property); $suggestStr = $suggestion == "" ? "" : " ... did you mean \"{$suggestion}?\""; return \sprintf( "%s property \"%s\" does not exist%s", \str_replace("\x00", "@", \get_class($this)), // Handle anonymous class names. $property, $suggestStr ); } private function suggestPropertyName(string $badProperty) : string { $badProperty = \strtolower($badProperty); $bestMatch = ""; $bestMatchPercentage = 0; /** @psalm-suppress RawObjectIteration */ foreach ($this as $property => $value) { // Never suggest properties that begin with an underscore if ($property[0] === "_") { continue; } \similar_text($badProperty, \strtolower($property), $byRefPercentage); if ($byRefPercentage > $bestMatchPercentage) { $bestMatchPercentage = $byRefPercentage; $bestMatch = $property; } } return $bestMatchPercentage >= $this->__propertySuggestThreshold ? $bestMatch : ""; } } */ final class Delayed implements Promise { use Internal\Placeholder; /** @var string|null Event loop watcher identifier. */ private $watcher; /** * @param int $time Milliseconds before succeeding the promise. * @param TReturn $value Succeed the promise with this value. */ public function __construct(int $time, $value = null) { $this->watcher = Loop::delay($time, function () use($value) { $this->watcher = null; $this->resolve($value); }); } /** * References the internal watcher in the event loop, keeping the loop running while this promise is pending. * * @return self */ public function reference() : self { if ($this->watcher !== null) { Loop::reference($this->watcher); } return $this; } /** * Unreferences the internal watcher in the event loop, allowing the loop to stop while this promise is pending if * no other events are pending in the loop. * * @return self */ public function unreference() : self { if ($this->watcher !== null) { Loop::unreference($this->watcher); } return $this; } } getToken(); * * $response = yield $httpClient->request("https://example.com/stream", $token); * $responseBody = $response->getBody(); * * while (($chunk = yield $response->read()) !== null) { * // consume $chunk * * if ($noLongerInterested) { * $cancellationTokenSource->cancel(); * break; * } * } * ``` * * @see CancellationToken * @see CancelledException */ final class CancellationTokenSource { /** @var CancellationToken */ private $token; /** @var callable|null */ private $onCancel; public function __construct() { $onCancel = null; $this->token = new class($onCancel) implements CancellationToken { /** @var string */ private $nextId = "a"; /** @var callable[] */ private $callbacks = []; /** @var \Throwable|null */ private $exception; /** * @param mixed $onCancel * @param-out callable $onCancel */ public function __construct(&$onCancel) { /** @psalm-suppress MissingClosureReturnType We still support PHP 7.0 */ $onCancel = function (\Throwable $exception) { $this->exception = $exception; $callbacks = $this->callbacks; $this->callbacks = []; foreach ($callbacks as $callback) { $this->invokeCallback($callback); } }; } /** * @param callable $callback * * @return void */ private function invokeCallback(callable $callback) { // No type declaration to prevent exception outside the try! try { /** @var mixed $result */ $result = $callback($this->exception); if ($result instanceof \Generator) { /** @psalm-var \Generator $result */ $result = new Coroutine($result); } if ($result instanceof Promise || $result instanceof ReactPromise) { rethrow($result); } } catch (\Throwable $exception) { Loop::defer(static function () use($exception) { throw $exception; }); } } public function subscribe(callable $callback) : string { $id = $this->nextId++; if ($this->exception) { $this->invokeCallback($callback); } else { $this->callbacks[$id] = $callback; } return $id; } public function unsubscribe(string $id) { unset($this->callbacks[$id]); } public function isRequested() : bool { return isset($this->exception); } public function throwIfRequested() { if (isset($this->exception)) { throw $this->exception; } } }; $this->onCancel = $onCancel; } public function getToken() : CancellationToken { return $this->token; } /** * @param \Throwable|null $previous Exception to be used as the previous exception to CancelledException. * * @return void */ public function cancel(?\Throwable $previous = null) { if ($this->onCancel === null) { return; } $onCancel = $this->onCancel; $this->onCancel = null; $onCancel(new CancelledException($previous)); } } */ final class Producer implements Iterator { /** * @use Internal\Producer */ use CallableMaker, Internal\Producer; /** * @param callable(callable(TValue):Promise):\Generator $producer * * @throws \Error Thrown if the callable does not return a Generator. */ public function __construct(callable $producer) { $result = $producer($this->callableFromInstanceMethod("emit")); if (!$result instanceof \Generator) { throw new \Error("The callable did not return a Generator"); } $coroutine = new Coroutine($result); $coroutine->onResolve(function ($exception) { if ($this->complete) { return; } if ($exception) { $this->fail($exception); return; } $this->complete(); }); } } token = $source->getToken(); $trace = \debug_backtrace(\DEBUG_BACKTRACE_IGNORE_ARGS); $this->watcher = Loop::delay($timeout, static function () use($source, $message, $trace) { $trace = formatStacktrace($trace); $source->cancel(new TimeoutException("{$message}\r\nTimeoutCancellationToken was created here:\r\n{$trace}")); }); Loop::unreference($this->watcher); } /** * Cancels the delay watcher. */ public function __destruct() { Loop::cancel($this->watcher); } /** * {@inheritdoc} */ public function subscribe(callable $callback) : string { return $this->token->subscribe($callback); } /** * {@inheritdoc} */ public function unsubscribe(string $id) { $this->token->unsubscribe($id); } /** * {@inheritdoc} */ public function isRequested() : bool { return $this->token->isRequested(); } /** * {@inheritdoc} */ public function throwIfRequested() { $this->token->throwIfRequested(); } } throwIfRequested(); * } * ``` * * potentially multiple times, it allows writing * * ```php * $token = $token ?? new NullCancellationToken; * * // ... * * $token->throwIfRequested(); * ``` * * instead. */ final class NullCancellationToken implements CancellationToken { /** @inheritdoc */ public function subscribe(callable $callback) : string { return "null-token"; } /** @inheritdoc */ public function unsubscribe(string $id) { // nothing to do } /** @inheritdoc */ public function isRequested() : bool { return \false; } /** @inheritdoc */ public function throwIfRequested() { // nothing to do } } Has public emit, complete, and fail methods. */ private $emitter; /** @var Iterator Hides producer methods. */ private $iterator; public function __construct() { $this->emitter = new class implements Iterator { use Internal\Producer { emit as public; complete as public; fail as public; } }; $this->iterator = new Internal\PrivateIterator($this->emitter); } /** * @return Iterator * @psalm-return Iterator */ public function iterate() : Iterator { return $this->iterator; } /** * Emits a value to the iterator. * * @param mixed $value * * @psalm-param TValue $value * * @return Promise * @psalm-return Promise * @psalm-suppress MixedInferredReturnType * @psalm-suppress MixedReturnStatement */ public function emit($value) : Promise { /** @psalm-suppress UndefinedInterfaceMethod */ return $this->emitter->emit($value); } /** * Completes the iterator. * * @return void */ public function complete() { /** @psalm-suppress UndefinedInterfaceMethod */ $this->emitter->complete(); } /** * Fails the iterator with the given reason. * * @param \Throwable $reason * * @return void */ public function fail(\Throwable $reason) { /** @psalm-suppress UndefinedInterfaceMethod */ $this->emitter->fail($reason); } } */ final class Failure implements Promise { /** @var \Throwable $exception */ private $exception; /** * @param \Throwable $exception Rejection reason. */ public function __construct(\Throwable $exception) { $this->exception = $exception; } /** * {@inheritdoc} */ public function onResolve(callable $onResolved) { try { /** @var mixed $result */ $result = $onResolved($this->exception, null); if ($result === null) { return; } if ($result instanceof \Generator) { $result = new Coroutine($result); } if ($result instanceof Promise || $result instanceof ReactPromise) { Promise\rethrow($result); } } catch (\Throwable $exception) { Loop::defer(static function () use($exception) { throw $exception; }); } } } * * @throws \Error If the prior promise returned from this method has not resolved. * @throws \Throwable The exception used to fail the iterator. */ public function advance() : Promise; /** * Gets the last emitted value or throws an exception if the iterator has completed. * * @return mixed Value emitted from the iterator. * @psalm-return TValue * * @throws \Error If the iterator has resolved or advance() was not called before calling this method. * @throws \Throwable The exception used to fail the iterator. */ public function getCurrent(); } current(); $prefix .= \sprintf("; %s yielded at key %s", \is_object($yielded) ? \get_class($yielded) : \gettype($yielded), \var_export($generator->key(), \true)); if (!$generator->valid()) { parent::__construct($prefix, 0, $previous); return; } $reflGen = new \ReflectionGenerator($generator); $exeGen = $reflGen->getExecutingGenerator(); if ($isSubgenerator = $exeGen !== $generator) { $reflGen = new \ReflectionGenerator($exeGen); } parent::__construct(\sprintf("%s on line %s in %s", $prefix, $reflGen->getExecutingLine(), $reflGen->getExecutingFile()), 0, $previous); } } createDriverFromEnv()) { return $driver; } if (UvDriver::isSupported()) { return new UvDriver(); } if (EvDriver::isSupported()) { return new EvDriver(); } if (EventDriver::isSupported()) { return new EventDriver(); } return new NativeDriver(); })(); if (\getenv("AMP_DEBUG_TRACE_WATCHERS")) { return new TracingDriver($driver); } return $driver; } /** * @return Driver|null */ private function createDriverFromEnv() { $driver = \getenv("AMP_LOOP_DRIVER"); if (!$driver) { return null; } if (!\class_exists($driver)) { throw new \Error(\sprintf("Driver '%s' does not exist.", $driver)); } if (!\is_subclass_of($driver, Driver::class)) { throw new \Error(\sprintf("Driver '%s' is not a subclass of '%s'.", $driver, Driver::class)); } return new $driver(); } } // @codeCoverageIgnoreEnd driver = $driver; } public function run() { $this->driver->run(); } public function stop() { $this->driver->stop(); } public function defer(callable $callback, $data = null) : string { $id = $this->driver->defer(function (...$args) use($callback) { $this->cancel($args[0]); return $callback(...$args); }, $data); $this->creationTraces[$id] = formatStacktrace(\debug_backtrace(\DEBUG_BACKTRACE_IGNORE_ARGS)); $this->enabledWatchers[$id] = \true; return $id; } public function delay(int $delay, callable $callback, $data = null) : string { $id = $this->driver->delay($delay, function (...$args) use($callback) { $this->cancel($args[0]); return $callback(...$args); }, $data); $this->creationTraces[$id] = formatStacktrace(\debug_backtrace(\DEBUG_BACKTRACE_IGNORE_ARGS)); $this->enabledWatchers[$id] = \true; return $id; } public function repeat(int $interval, callable $callback, $data = null) : string { $id = $this->driver->repeat($interval, $callback, $data); $this->creationTraces[$id] = formatStacktrace(\debug_backtrace(\DEBUG_BACKTRACE_IGNORE_ARGS)); $this->enabledWatchers[$id] = \true; return $id; } public function onReadable($stream, callable $callback, $data = null) : string { $id = $this->driver->onReadable($stream, $callback, $data); $this->creationTraces[$id] = formatStacktrace(\debug_backtrace(\DEBUG_BACKTRACE_IGNORE_ARGS)); $this->enabledWatchers[$id] = \true; return $id; } public function onWritable($stream, callable $callback, $data = null) : string { $id = $this->driver->onWritable($stream, $callback, $data); $this->creationTraces[$id] = formatStacktrace(\debug_backtrace(\DEBUG_BACKTRACE_IGNORE_ARGS)); $this->enabledWatchers[$id] = \true; return $id; } public function onSignal(int $signo, callable $callback, $data = null) : string { $id = $this->driver->onSignal($signo, $callback, $data); $this->creationTraces[$id] = formatStacktrace(\debug_backtrace(\DEBUG_BACKTRACE_IGNORE_ARGS)); $this->enabledWatchers[$id] = \true; return $id; } public function enable(string $watcherId) { try { $this->driver->enable($watcherId); $this->enabledWatchers[$watcherId] = \true; } catch (InvalidWatcherError $e) { throw new InvalidWatcherError($watcherId, $e->getMessage() . "\r\n\r\n" . $this->getTraces($watcherId)); } } public function cancel(string $watcherId) { $this->driver->cancel($watcherId); if (!isset($this->cancelTraces[$watcherId])) { $this->cancelTraces[$watcherId] = formatStacktrace(\debug_backtrace(\DEBUG_BACKTRACE_IGNORE_ARGS)); } unset($this->enabledWatchers[$watcherId], $this->unreferencedWatchers[$watcherId]); } public function disable(string $watcherId) { $this->driver->disable($watcherId); unset($this->enabledWatchers[$watcherId]); } public function reference(string $watcherId) { try { $this->driver->reference($watcherId); unset($this->unreferencedWatchers[$watcherId]); } catch (InvalidWatcherError $e) { throw new InvalidWatcherError($watcherId, $e->getMessage() . "\r\n\r\n" . $this->getTraces($watcherId)); } } public function unreference(string $watcherId) { $this->driver->unreference($watcherId); $this->unreferencedWatchers[$watcherId] = \true; } public function setErrorHandler(?callable $callback = null) { return $this->driver->setErrorHandler($callback); } /** @inheritdoc */ public function getHandle() { $this->driver->getHandle(); } public function dump() : string { $dump = "Enabled, referenced watchers keeping the loop running: "; foreach ($this->enabledWatchers as $watcher => $_) { if (isset($this->unreferencedWatchers[$watcher])) { continue; } $dump .= "Watcher ID: " . $watcher . "\r\n"; $dump .= $this->getCreationTrace($watcher); $dump .= "\r\n\r\n"; } return \rtrim($dump); } public function getInfo() : array { return $this->driver->getInfo(); } public function __debugInfo() { return $this->driver->__debugInfo(); } public function now() : int { return $this->driver->now(); } protected function error(\Throwable $exception) { $this->driver->error($exception); } /** * @inheritdoc * * @return void */ protected function activate(array $watchers) { // nothing to do in a decorator } /** * @inheritdoc * * @return void */ protected function dispatch(bool $blocking) { // nothing to do in a decorator } /** * @inheritdoc * * @return void */ protected function deactivate(Watcher $watcher) { // nothing to do in a decorator } private function getTraces(string $watcherId) : string { return "Creation Trace:\r\n" . $this->getCreationTrace($watcherId) . "\r\n\r\n" . "Cancellation Trace:\r\n" . $this->getCancelTrace($watcherId); } private function getCreationTrace(string $watcher) : string { if (!isset($this->creationTraces[$watcher])) { return 'No creation trace, yet.'; } return $this->creationTraces[$watcher]; } private function getCancelTrace(string $watcher) : string { if (!isset($this->cancelTraces[$watcher])) { return 'No cancellation trace, yet.'; } return $this->cancelTraces[$watcher]; } } data[$node]; while ($node !== 0 && $entry->expiration < $this->data[$parent = $node - 1 >> 1]->expiration) { $this->swap($node, $parent); $node = $parent; } } /** * @param int $node Rebuild the data array from the given node downward. * * @return void */ private function heapifyDown(int $node) { $length = \count($this->data); while (($child = ($node << 1) + 1) < $length) { if ($this->data[$child]->expiration < $this->data[$node]->expiration && ($child + 1 >= $length || $this->data[$child]->expiration < $this->data[$child + 1]->expiration)) { // Left child is less than parent and right child. $swap = $child; } elseif ($child + 1 < $length && $this->data[$child + 1]->expiration < $this->data[$node]->expiration) { // Right child is less than parent and left child. $swap = $child + 1; } else { // Left and right child are greater than parent. break; } $this->swap($node, $swap); $node = $swap; } } private function swap(int $left, int $right) { $temp = $this->data[$left]; $this->data[$left] = $this->data[$right]; $this->pointers[$this->data[$right]->id] = $left; $this->data[$right] = $temp; $this->pointers[$temp->id] = $right; } /** * Inserts the watcher into the queue. Time complexity: O(log(n)). * * @param Watcher $watcher * * @psalm-param Watcher $watcher * * @return void */ public function insert(Watcher $watcher) { \assert($watcher->expiration !== null); \assert(!isset($this->pointers[$watcher->id])); $node = \count($this->data); $this->data[$node] = $watcher; $this->pointers[$watcher->id] = $node; $this->heapifyUp($node); } /** * Removes the given watcher from the queue. Time complexity: O(log(n)). * * @param Watcher $watcher * * @psalm-param Watcher $watcher * * @return void */ public function remove(Watcher $watcher) { $id = $watcher->id; if (!isset($this->pointers[$id])) { return; } $this->removeAndRebuild($this->pointers[$id]); } /** * Deletes and returns the Watcher on top of the heap if it has expired, otherwise null is returned. * Time complexity: O(log(n)). * * @param int $now Current loop time. * * @return Watcher|null Expired watcher at the top of the heap or null if the watcher has not expired. * * @psalm-return Watcher|null */ public function extract(int $now) { if (empty($this->data)) { return null; } $watcher = $this->data[0]; if ($watcher->expiration > $now) { return null; } $this->removeAndRebuild(0); return $watcher; } /** * Returns the expiration time value at the top of the heap. Time complexity: O(1). * * @return int|null Expiration time of the watcher at the top of the heap or null if the heap is empty. */ public function peek() { return isset($this->data[0]) ? $this->data[0]->expiration : null; } /** * @param int $node Remove the given node and then rebuild the data array. * * @return void */ private function removeAndRebuild(int $node) { $length = \count($this->data) - 1; $id = $this->data[$node]->id; $left = $this->data[$node] = $this->data[$length]; $this->pointers[$left->id] = $node; unset($this->data[$length], $this->pointers[$id]); if ($node < $length) { // don't need to do anything if we removed the last element $parent = $node - 1 >> 1; if ($parent >= 0 && $this->data[$node]->expiration < $this->data[$parent]->expiration) { $this->heapifyUp($node); } else { $this->heapifyDown($node); } } } } timerQueue = new Internal\TimerQueue(); $this->signalHandling = \extension_loaded("pcntl"); $this->nowOffset = getCurrentTime(); $this->now = \random_int(0, $this->nowOffset); $this->nowOffset -= $this->now; $this->streamSelectErrorHandler = function ($errno, $message) { // Casing changed in PHP 8 from 'unable' to 'Unable' if (\stripos($message, "stream_select(): unable to select [4]: ") === 0) { // EINTR $this->streamSelectIgnoreResult = \true; return; } if (\strpos($message, 'FD_SETSIZE') !== \false) { $message = \str_replace(["\r\n", "\n", "\r"], " ", $message); $pattern = '(stream_select\\(\\): You MUST recompile PHP with a larger value of FD_SETSIZE. It is set to (\\d+), but you have descriptors numbered at least as high as (\\d+)\\.)'; if (\preg_match($pattern, $message, $match)) { $helpLink = 'https://amphp.org/amp/event-loop/#implementations'; $message = 'You have reached the limits of stream_select(). It has a FD_SETSIZE of ' . $match[1] . ', but you have file descriptors numbered at least as high as ' . $match[2] . '. ' . "You can install one of the extensions listed on {$helpLink} to support a higher number of " . "concurrent file descriptors. If a large number of open file descriptors is unexpected, you " . "might be leaking file descriptors that aren't closed correctly."; } } throw new \Exception($message, $errno); }; } /** * {@inheritdoc} * * @throws \Amp\Loop\UnsupportedFeatureException If the pcntl extension is not available. */ public function onSignal(int $signo, callable $callback, $data = null) : string { if (!$this->signalHandling) { throw new UnsupportedFeatureException("Signal handling requires the pcntl extension"); } return parent::onSignal($signo, $callback, $data); } /** * {@inheritdoc} */ public function now() : int { $this->now = getCurrentTime() - $this->nowOffset; return $this->now; } /** * {@inheritdoc} */ public function getHandle() { return null; } /** * @param bool $blocking * * @return void * * @throws \Throwable */ protected function dispatch(bool $blocking) { $this->selectStreams($this->readStreams, $this->writeStreams, $blocking ? $this->getTimeout() : 0); $now = $this->now(); while ($watcher = $this->timerQueue->extract($now)) { if ($watcher->type & Watcher::REPEAT) { $watcher->enabled = \false; // Trick base class into adding to enable queue when calling enable() $this->enable($watcher->id); } else { $this->cancel($watcher->id); } try { // Execute the timer. $result = ($watcher->callback)($watcher->id, $watcher->data); if ($result === null) { continue; } if ($result instanceof \Generator) { $result = new Coroutine($result); } if ($result instanceof Promise || $result instanceof ReactPromise) { rethrow($result); } } catch (\Throwable $exception) { $this->error($exception); } } if ($this->signalHandling) { \pcntl_signal_dispatch(); } } /** * {@inheritdoc} * * @return void */ protected function activate(array $watchers) { foreach ($watchers as $watcher) { switch ($watcher->type) { case Watcher::READABLE: \assert(\is_resource($watcher->value)); $streamId = (int) $watcher->value; $this->readWatchers[$streamId][$watcher->id] = $watcher; $this->readStreams[$streamId] = $watcher->value; break; case Watcher::WRITABLE: \assert(\is_resource($watcher->value)); $streamId = (int) $watcher->value; $this->writeWatchers[$streamId][$watcher->id] = $watcher; $this->writeStreams[$streamId] = $watcher->value; break; case Watcher::DELAY: case Watcher::REPEAT: \assert(\is_int($watcher->value)); $this->timerQueue->insert($watcher); break; case Watcher::SIGNAL: \assert(\is_int($watcher->value)); if (!isset($this->signalWatchers[$watcher->value])) { if (!@\pcntl_signal($watcher->value, $this->callableFromInstanceMethod('handleSignal'))) { $message = "Failed to register signal handler"; if ($error = \error_get_last()) { $message .= \sprintf("; Errno: %d; %s", $error["type"], $error["message"]); } throw new \Error($message); } } $this->signalWatchers[$watcher->value][$watcher->id] = $watcher; break; default: // @codeCoverageIgnoreStart throw new \Error("Unknown watcher type"); } } } /** * {@inheritdoc} * * @return void */ protected function deactivate(Watcher $watcher) { switch ($watcher->type) { case Watcher::READABLE: $streamId = (int) $watcher->value; unset($this->readWatchers[$streamId][$watcher->id]); if (empty($this->readWatchers[$streamId])) { unset($this->readWatchers[$streamId], $this->readStreams[$streamId]); } break; case Watcher::WRITABLE: $streamId = (int) $watcher->value; unset($this->writeWatchers[$streamId][$watcher->id]); if (empty($this->writeWatchers[$streamId])) { unset($this->writeWatchers[$streamId], $this->writeStreams[$streamId]); } break; case Watcher::DELAY: case Watcher::REPEAT: $this->timerQueue->remove($watcher); break; case Watcher::SIGNAL: \assert(\is_int($watcher->value)); if (isset($this->signalWatchers[$watcher->value])) { unset($this->signalWatchers[$watcher->value][$watcher->id]); if (empty($this->signalWatchers[$watcher->value])) { unset($this->signalWatchers[$watcher->value]); @\pcntl_signal($watcher->value, \SIG_DFL); } } break; default: // @codeCoverageIgnoreStart throw new \Error("Unknown watcher type"); } } /** * @param resource[] $read * @param resource[] $write * @param int $timeout * * @return void */ private function selectStreams(array $read, array $write, int $timeout) { $timeout /= self::MILLISEC_PER_SEC; if (!empty($read) || !empty($write)) { // Use stream_select() if there are any streams in the loop. if ($timeout >= 0) { $seconds = (int) $timeout; $microseconds = (int) (($timeout - $seconds) * self::MICROSEC_PER_SEC); } else { $seconds = null; $microseconds = null; } // Failed connection attempts are indicated via except on Windows // @link https://github.com/reactphp/event-loop/blob/8bd064ce23c26c4decf186c2a5a818c9a8209eb0/src/StreamSelectLoop.php#L279-L287 // @link https://docs.microsoft.com/de-de/windows/win32/api/winsock2/nf-winsock2-select $except = null; if (\DIRECTORY_SEPARATOR === '\\') { $except = $write; } \set_error_handler($this->streamSelectErrorHandler); try { $result = \stream_select($read, $write, $except, $seconds, $microseconds); } finally { \restore_error_handler(); } if ($this->streamSelectIgnoreResult || $result === 0) { $this->streamSelectIgnoreResult = \false; return; } if (!$result) { $this->error(new \Exception('Unknown error during stream_select')); return; } foreach ($read as $stream) { $streamId = (int) $stream; if (!isset($this->readWatchers[$streamId])) { continue; // All read watchers disabled. } foreach ($this->readWatchers[$streamId] as $watcher) { if (!isset($this->readWatchers[$streamId][$watcher->id])) { continue; // Watcher disabled by another IO watcher. } try { $result = ($watcher->callback)($watcher->id, $stream, $watcher->data); if ($result === null) { continue; } if ($result instanceof \Generator) { $result = new Coroutine($result); } if ($result instanceof Promise || $result instanceof ReactPromise) { rethrow($result); } } catch (\Throwable $exception) { $this->error($exception); } } } \assert(\is_array($write)); // See https://github.com/vimeo/psalm/issues/3036 if ($except) { foreach ($except as $key => $socket) { $write[$key] = $socket; } } foreach ($write as $stream) { $streamId = (int) $stream; if (!isset($this->writeWatchers[$streamId])) { continue; // All write watchers disabled. } foreach ($this->writeWatchers[$streamId] as $watcher) { if (!isset($this->writeWatchers[$streamId][$watcher->id])) { continue; // Watcher disabled by another IO watcher. } try { $result = ($watcher->callback)($watcher->id, $stream, $watcher->data); if ($result === null) { continue; } if ($result instanceof \Generator) { $result = new Coroutine($result); } if ($result instanceof Promise || $result instanceof ReactPromise) { rethrow($result); } } catch (\Throwable $exception) { $this->error($exception); } } } return; } if ($timeout < 0) { // Only signal watchers are enabled, so sleep indefinitely. \usleep(\PHP_INT_MAX); return; } if ($timeout > 0) { // Sleep until next timer expires. \usleep((int) ($timeout * self::MICROSEC_PER_SEC)); } } /** * @return int Milliseconds until next timer expires or -1 if there are no pending times. */ private function getTimeout() : int { $expiration = $this->timerQueue->peek(); if ($expiration === null) { return -1; } $expiration -= getCurrentTime() - $this->nowOffset; return $expiration > 0 ? $expiration : 0; } /** * @param int $signo * * @return void */ private function handleSignal(int $signo) { foreach ($this->signalWatchers[$signo] as $watcher) { if (!isset($this->signalWatchers[$signo][$watcher->id])) { continue; } try { $result = ($watcher->callback)($watcher->id, $signo, $watcher->data); if ($result === null) { continue; } if ($result instanceof \Generator) { $result = new Coroutine($result); } if ($result instanceof Promise || $result instanceof ReactPromise) { rethrow($result); } } catch (\Throwable $exception) { $this->error($exception); } } } } requireFeatures(\EventConfig::FEATURE_FDS); } $this->handle = new \EventBase($config); $this->nowOffset = getCurrentTime(); $this->now = \random_int(0, $this->nowOffset); $this->nowOffset -= $this->now; if (self::$activeSignals === null) { self::$activeSignals =& $this->signals; } /** * @param $resource * @param $what * @param Watcher $watcher * * @return void */ $this->ioCallback = function ($resource, $what, Watcher $watcher) { \assert(\is_resource($watcher->value)); try { $result = ($watcher->callback)($watcher->id, $watcher->value, $watcher->data); if ($result === null) { return; } if ($result instanceof \Generator) { $result = new Coroutine($result); } if ($result instanceof Promise || $result instanceof ReactPromise) { rethrow($result); } } catch (\Throwable $exception) { $this->error($exception); } }; /** * @param $resource * @param $what * @param Watcher $watcher * * @return void */ $this->timerCallback = function ($resource, $what, Watcher $watcher) { \assert(\is_int($watcher->value)); if ($watcher->type & Watcher::DELAY) { $this->cancel($watcher->id); } else { $this->events[$watcher->id]->add($watcher->value / self::MILLISEC_PER_SEC); } try { $result = ($watcher->callback)($watcher->id, $watcher->data); if ($result === null) { return; } if ($result instanceof \Generator) { $result = new Coroutine($result); } if ($result instanceof Promise || $result instanceof ReactPromise) { rethrow($result); } } catch (\Throwable $exception) { $this->error($exception); } }; /** * @param $signum * @param $what * @param Watcher $watcher * * @return void */ $this->signalCallback = function ($signum, $what, Watcher $watcher) { try { $result = ($watcher->callback)($watcher->id, $watcher->value, $watcher->data); if ($result === null) { return; } if ($result instanceof \Generator) { $result = new Coroutine($result); } if ($result instanceof Promise || $result instanceof ReactPromise) { rethrow($result); } } catch (\Throwable $exception) { $this->error($exception); } }; } /** * {@inheritdoc} */ public function cancel(string $watcherId) { parent::cancel($watcherId); if (isset($this->events[$watcherId])) { $this->events[$watcherId]->free(); unset($this->events[$watcherId]); } } public static function isSupported() : bool { return \extension_loaded("event"); } /** * @codeCoverageIgnore */ public function __destruct() { // Unset here, otherwise $event->del() in the loop may fail with a warning, because __destruct order isn't defined. // Related https://github.com/amphp/amp/issues/159. $events = $this->events; $this->events = []; foreach ($events as $event) { if ($event !== null) { // Events may have been nulled in extension depending on destruct order. $event->free(); } } // Manually free the loop handle to fully release loop resources. // See https://github.com/amphp/amp/issues/177. if ($this->handle !== null) { $this->handle->free(); $this->handle = null; } } /** * {@inheritdoc} */ public function run() { $active = self::$activeSignals; \assert($active !== null); foreach ($active as $event) { $event->del(); } self::$activeSignals =& $this->signals; foreach ($this->signals as $event) { /** @psalm-suppress TooFewArguments https://github.com/JetBrains/phpstorm-stubs/pull/763 */ $event->add(); } try { parent::run(); } finally { foreach ($this->signals as $event) { $event->del(); } self::$activeSignals =& $active; foreach ($active as $event) { /** @psalm-suppress TooFewArguments https://github.com/JetBrains/phpstorm-stubs/pull/763 */ $event->add(); } } } /** * {@inheritdoc} */ public function stop() { $this->handle->stop(); parent::stop(); } /** * {@inheritdoc} */ public function now() : int { $this->now = getCurrentTime() - $this->nowOffset; return $this->now; } /** * {@inheritdoc} */ public function getHandle() : \EventBase { return $this->handle; } /** * {@inheritdoc} * * @return void */ protected function dispatch(bool $blocking) { $this->handle->loop($blocking ? \EventBase::LOOP_ONCE : \EventBase::LOOP_ONCE | \EventBase::LOOP_NONBLOCK); } /** * {@inheritdoc} * * @return void */ protected function activate(array $watchers) { $now = $this->now(); foreach ($watchers as $watcher) { if (!isset($this->events[$id = $watcher->id])) { switch ($watcher->type) { case Watcher::READABLE: \assert(\is_resource($watcher->value)); $this->events[$id] = new \Event($this->handle, $watcher->value, \Event::READ | \Event::PERSIST, $this->ioCallback, $watcher); break; case Watcher::WRITABLE: \assert(\is_resource($watcher->value)); $this->events[$id] = new \Event($this->handle, $watcher->value, \Event::WRITE | \Event::PERSIST, $this->ioCallback, $watcher); break; case Watcher::DELAY: case Watcher::REPEAT: \assert(\is_int($watcher->value)); $this->events[$id] = new \Event($this->handle, -1, \Event::TIMEOUT, $this->timerCallback, $watcher); break; case Watcher::SIGNAL: \assert(\is_int($watcher->value)); $this->events[$id] = new \Event($this->handle, $watcher->value, \Event::SIGNAL | \Event::PERSIST, $this->signalCallback, $watcher); break; default: // @codeCoverageIgnoreStart throw new \Error("Unknown watcher type"); } } switch ($watcher->type) { case Watcher::DELAY: case Watcher::REPEAT: \assert(\is_int($watcher->value)); $interval = \max(0, $watcher->expiration - $now); $this->events[$id]->add($interval > 0 ? $interval / self::MILLISEC_PER_SEC : 0); break; case Watcher::SIGNAL: $this->signals[$id] = $this->events[$id]; // no break default: /** @psalm-suppress TooFewArguments https://github.com/JetBrains/phpstorm-stubs/pull/763 */ $this->events[$id]->add(); break; } } } /** * {@inheritdoc} * * @return void */ protected function deactivate(Watcher $watcher) { if (isset($this->events[$id = $watcher->id])) { $this->events[$id]->del(); if ($watcher->type === Watcher::SIGNAL) { unset($this->signals[$id]); } } } } handle = \uv_loop_new(); /** * @param $event * @param $status * @param $events * @param $resource * * @return void */ $this->ioCallback = function ($event, $status, $events, $resource) { $watchers = $this->watchers[(int) $event]; switch ($status) { case 0: // OK break; default: // Invoke the callback on errors, as this matches behavior with other loop back-ends. // Re-enable watcher as libuv disables the watcher on non-zero status. $flags = 0; foreach ($watchers as $watcher) { $flags |= $watcher->enabled ? $watcher->type : 0; } \uv_poll_start($event, $flags, $this->ioCallback); break; } foreach ($watchers as $watcher) { // $events is OR'ed with 4 to trigger watcher if no events are indicated (0) or on UV_DISCONNECT (4). // http://docs.libuv.org/en/v1.x/poll.html if (!($watcher->enabled && ($watcher->type & $events || ($events | 4) === 4))) { continue; } try { $result = ($watcher->callback)($watcher->id, $resource, $watcher->data); if ($result === null) { continue; } if ($result instanceof \Generator) { $result = new Coroutine($result); } if ($result instanceof Promise || $result instanceof ReactPromise) { rethrow($result); } } catch (\Throwable $exception) { $this->error($exception); } } }; /** * @param $event * * @return void */ $this->timerCallback = function ($event) { $watcher = $this->watchers[(int) $event][0]; if ($watcher->type & Watcher::DELAY) { unset($this->events[$watcher->id], $this->watchers[(int) $event]); // Avoid call to uv_is_active(). $this->cancel($watcher->id); // Remove reference to watcher in parent. } elseif ($watcher->value === 0) { // Disable and re-enable so it's not executed repeatedly in the same tick // See https://github.com/amphp/amp/issues/131 $this->disable($watcher->id); $this->enable($watcher->id); } try { $result = ($watcher->callback)($watcher->id, $watcher->data); if ($result === null) { return; } if ($result instanceof \Generator) { $result = new Coroutine($result); } if ($result instanceof Promise || $result instanceof ReactPromise) { rethrow($result); } } catch (\Throwable $exception) { $this->error($exception); } }; /** * @param $event * @param $signo * * @return void */ $this->signalCallback = function ($event, $signo) { $watcher = $this->watchers[(int) $event][0]; try { $result = ($watcher->callback)($watcher->id, $signo, $watcher->data); if ($result === null) { return; } if ($result instanceof \Generator) { $result = new Coroutine($result); } if ($result instanceof Promise || $result instanceof ReactPromise) { rethrow($result); } } catch (\Throwable $exception) { $this->error($exception); } }; } /** * {@inheritdoc} */ public function cancel(string $watcherId) { parent::cancel($watcherId); if (!isset($this->events[$watcherId])) { return; } $event = $this->events[$watcherId]; $eventId = (int) $event; if (isset($this->watchers[$eventId][0])) { // All except IO watchers. unset($this->watchers[$eventId]); } elseif (isset($this->watchers[$eventId][$watcherId])) { $watcher = $this->watchers[$eventId][$watcherId]; unset($this->watchers[$eventId][$watcherId]); if (empty($this->watchers[$eventId])) { unset($this->watchers[$eventId], $this->streams[(int) $watcher->value]); } } unset($this->events[$watcherId]); } public static function isSupported() : bool { return \extension_loaded("uv"); } /** * {@inheritdoc} */ public function now() : int { \uv_update_time($this->handle); /** @psalm-suppress TooManyArguments */ return \uv_now($this->handle); } /** * {@inheritdoc} */ public function getHandle() { return $this->handle; } /** * {@inheritdoc} * * @return void */ protected function dispatch(bool $blocking) { /** @psalm-suppress TooManyArguments */ \uv_run($this->handle, $blocking ? \UV::RUN_ONCE : \UV::RUN_NOWAIT); } /** * {@inheritdoc} * * @return void */ protected function activate(array $watchers) { $now = $this->now(); foreach ($watchers as $watcher) { $id = $watcher->id; switch ($watcher->type) { case Watcher::READABLE: case Watcher::WRITABLE: \assert(\is_resource($watcher->value)); $streamId = (int) $watcher->value; if (isset($this->streams[$streamId])) { $event = $this->streams[$streamId]; } elseif (isset($this->events[$id])) { $event = $this->streams[$streamId] = $this->events[$id]; } else { /** @psalm-suppress UndefinedFunction */ $event = $this->streams[$streamId] = \_HumbugBox7ff99e199a36\uv_poll_init_socket($this->handle, $watcher->value); } $eventId = (int) $event; $this->events[$id] = $event; $this->watchers[$eventId][$id] = $watcher; $flags = 0; foreach ($this->watchers[$eventId] as $w) { $flags |= $w->enabled ? $w->type : 0; } \uv_poll_start($event, $flags, $this->ioCallback); break; case Watcher::DELAY: case Watcher::REPEAT: \assert(\is_int($watcher->value)); if (isset($this->events[$id])) { $event = $this->events[$id]; } else { $event = $this->events[$id] = \uv_timer_init($this->handle); } $this->watchers[(int) $event] = [$watcher]; \uv_timer_start($event, \max(0, $watcher->expiration - $now), $watcher->type & Watcher::REPEAT ? $watcher->value : 0, $this->timerCallback); break; case Watcher::SIGNAL: \assert(\is_int($watcher->value)); if (isset($this->events[$id])) { $event = $this->events[$id]; } else { /** @psalm-suppress UndefinedFunction */ $event = $this->events[$id] = \_HumbugBox7ff99e199a36\uv_signal_init($this->handle); } $this->watchers[(int) $event] = [$watcher]; /** @psalm-suppress UndefinedFunction */ \_HumbugBox7ff99e199a36\uv_signal_start($event, $this->signalCallback, $watcher->value); break; default: // @codeCoverageIgnoreStart throw new \Error("Unknown watcher type"); } } } /** * {@inheritdoc} * * @return void */ protected function deactivate(Watcher $watcher) { $id = $watcher->id; if (!isset($this->events[$id])) { return; } $event = $this->events[$id]; if (!\uv_is_active($event)) { return; } switch ($watcher->type) { case Watcher::READABLE: case Watcher::WRITABLE: $flags = 0; foreach ($this->watchers[(int) $event] as $w) { $flags |= $w->enabled ? $w->type : 0; } if ($flags) { \uv_poll_start($event, $flags, $this->ioCallback); } else { \uv_poll_stop($event); } break; case Watcher::DELAY: case Watcher::REPEAT: \uv_timer_stop($event); break; case Watcher::SIGNAL: \uv_signal_stop($event); break; default: // @codeCoverageIgnoreStart throw new \Error("Unknown watcher type"); } } } running = \true; try { while ($this->running) { if ($this->isEmpty()) { return; } $this->tick(); } } finally { $this->stop(); } } /** * @return bool True if no enabled and referenced watchers remain in the loop. */ private function isEmpty() : bool { foreach ($this->watchers as $watcher) { if ($watcher->enabled && $watcher->referenced) { return \false; } } return \true; } /** * Executes a single tick of the event loop. * * @return void */ private function tick() { if (empty($this->deferQueue)) { $this->deferQueue = $this->nextTickQueue; } else { $this->deferQueue = \array_merge($this->deferQueue, $this->nextTickQueue); } $this->nextTickQueue = []; $this->activate($this->enableQueue); $this->enableQueue = []; foreach ($this->deferQueue as $watcher) { if (!isset($this->deferQueue[$watcher->id])) { continue; // Watcher disabled by another defer watcher. } unset($this->watchers[$watcher->id], $this->deferQueue[$watcher->id]); try { /** @var mixed $result */ $result = ($watcher->callback)($watcher->id, $watcher->data); if ($result === null) { continue; } if ($result instanceof \Generator) { $result = new Coroutine($result); } if ($result instanceof Promise || $result instanceof ReactPromise) { rethrow($result); } } catch (\Throwable $exception) { $this->error($exception); } } /** @psalm-suppress RedundantCondition */ $this->dispatch(empty($this->nextTickQueue) && empty($this->enableQueue) && $this->running && !$this->isEmpty()); } /** * Activates (enables) all the given watchers. * * @param Watcher[] $watchers * * @return void */ protected abstract function activate(array $watchers); /** * Dispatches any pending read/write, timer, and signal events. * * @param bool $blocking * * @return void */ protected abstract function dispatch(bool $blocking); /** * Stop the event loop. * * When an event loop is stopped, it continues with its current tick and exits the loop afterwards. Multiple calls * to stop MUST be ignored and MUST NOT raise an exception. * * @return void */ public function stop() { $this->running = \false; } /** * Defer the execution of a callback. * * The deferred callable MUST be executed before any other type of watcher in a tick. Order of enabling MUST be * preserved when executing the callbacks. * * The created watcher MUST immediately be marked as enabled, but only be activated (i.e. callback can be called) * right before the next tick. Callbacks of watchers MUST NOT be called in the tick they were enabled. * * @param callable (string $watcherId, mixed $data) $callback The callback to defer. The `$watcherId` will be * invalidated before the callback call. * @param mixed $data Arbitrary data given to the callback function as the `$data` parameter. * * @return string An unique identifier that can be used to cancel, enable or disable the watcher. */ public function defer(callable $callback, $data = null) : string { /** @psalm-var Watcher $watcher */ $watcher = new Watcher(); $watcher->type = Watcher::DEFER; $watcher->id = $this->nextId++; $watcher->callback = $callback; $watcher->data = $data; $this->watchers[$watcher->id] = $watcher; $this->nextTickQueue[$watcher->id] = $watcher; return $watcher->id; } /** * Delay the execution of a callback. * * The delay is a minimum and approximate, accuracy is not guaranteed. Order of calls MUST be determined by which * timers expire first, but timers with the same expiration time MAY be executed in any order. * * The created watcher MUST immediately be marked as enabled, but only be activated (i.e. callback can be called) * right before the next tick. Callbacks of watchers MUST NOT be called in the tick they were enabled. * * @param int $delay The amount of time, in milliseconds, to delay the execution for. * @param callable (string $watcherId, mixed $data) $callback The callback to delay. The `$watcherId` will be * invalidated before the callback call. * @param mixed $data Arbitrary data given to the callback function as the `$data` parameter. * * @return string An unique identifier that can be used to cancel, enable or disable the watcher. */ public function delay(int $delay, callable $callback, $data = null) : string { if ($delay < 0) { throw new \Error("Delay must be greater than or equal to zero"); } /** @psalm-var Watcher $watcher */ $watcher = new Watcher(); $watcher->type = Watcher::DELAY; $watcher->id = $this->nextId++; $watcher->callback = $callback; $watcher->value = $delay; $watcher->expiration = $this->now() + $delay; $watcher->data = $data; $this->watchers[$watcher->id] = $watcher; $this->enableQueue[$watcher->id] = $watcher; return $watcher->id; } /** * Repeatedly execute a callback. * * The interval between executions is a minimum and approximate, accuracy is not guaranteed. Order of calls MUST be * determined by which timers expire first, but timers with the same expiration time MAY be executed in any order. * The first execution is scheduled after the first interval period. * * The created watcher MUST immediately be marked as enabled, but only be activated (i.e. callback can be called) * right before the next tick. Callbacks of watchers MUST NOT be called in the tick they were enabled. * * @param int $interval The time interval, in milliseconds, to wait between executions. * @param callable (string $watcherId, mixed $data) $callback The callback to repeat. * @param mixed $data Arbitrary data given to the callback function as the `$data` parameter. * * @return string An unique identifier that can be used to cancel, enable or disable the watcher. */ public function repeat(int $interval, callable $callback, $data = null) : string { if ($interval < 0) { throw new \Error("Interval must be greater than or equal to zero"); } /** @psalm-var Watcher $watcher */ $watcher = new Watcher(); $watcher->type = Watcher::REPEAT; $watcher->id = $this->nextId++; $watcher->callback = $callback; $watcher->value = $interval; $watcher->expiration = $this->now() + $interval; $watcher->data = $data; $this->watchers[$watcher->id] = $watcher; $this->enableQueue[$watcher->id] = $watcher; return $watcher->id; } /** * Execute a callback when a stream resource becomes readable or is closed for reading. * * Warning: Closing resources locally, e.g. with `fclose`, might not invoke the callback. Be sure to `cancel` the * watcher when closing the resource locally. Drivers MAY choose to notify the user if there are watchers on invalid * resources, but are not required to, due to the high performance impact. Watchers on closed resources are * therefore undefined behavior. * * Multiple watchers on the same stream MAY be executed in any order. * * The created watcher MUST immediately be marked as enabled, but only be activated (i.e. callback can be called) * right before the next tick. Callbacks of watchers MUST NOT be called in the tick they were enabled. * * @param resource $stream The stream to monitor. * @param callable (string $watcherId, resource $stream, mixed $data) $callback The callback to execute. * @param mixed $data Arbitrary data given to the callback function as the `$data` parameter. * * @return string An unique identifier that can be used to cancel, enable or disable the watcher. */ public function onReadable($stream, callable $callback, $data = null) : string { /** @psalm-var Watcher $watcher */ $watcher = new Watcher(); $watcher->type = Watcher::READABLE; $watcher->id = $this->nextId++; $watcher->callback = $callback; $watcher->value = $stream; $watcher->data = $data; $this->watchers[$watcher->id] = $watcher; $this->enableQueue[$watcher->id] = $watcher; return $watcher->id; } /** * Execute a callback when a stream resource becomes writable or is closed for writing. * * Warning: Closing resources locally, e.g. with `fclose`, might not invoke the callback. Be sure to `cancel` the * watcher when closing the resource locally. Drivers MAY choose to notify the user if there are watchers on invalid * resources, but are not required to, due to the high performance impact. Watchers on closed resources are * therefore undefined behavior. * * Multiple watchers on the same stream MAY be executed in any order. * * The created watcher MUST immediately be marked as enabled, but only be activated (i.e. callback can be called) * right before the next tick. Callbacks of watchers MUST NOT be called in the tick they were enabled. * * @param resource $stream The stream to monitor. * @param callable (string $watcherId, resource $stream, mixed $data) $callback The callback to execute. * @param mixed $data Arbitrary data given to the callback function as the `$data` parameter. * * @return string An unique identifier that can be used to cancel, enable or disable the watcher. */ public function onWritable($stream, callable $callback, $data = null) : string { /** @psalm-var Watcher $watcher */ $watcher = new Watcher(); $watcher->type = Watcher::WRITABLE; $watcher->id = $this->nextId++; $watcher->callback = $callback; $watcher->value = $stream; $watcher->data = $data; $this->watchers[$watcher->id] = $watcher; $this->enableQueue[$watcher->id] = $watcher; return $watcher->id; } /** * Execute a callback when a signal is received. * * Warning: Installing the same signal on different instances of this interface is deemed undefined behavior. * Implementations MAY try to detect this, if possible, but are not required to. This is due to technical * limitations of the signals being registered globally per process. * * Multiple watchers on the same signal MAY be executed in any order. * * The created watcher MUST immediately be marked as enabled, but only be activated (i.e. callback can be called) * right before the next tick. Callbacks of watchers MUST NOT be called in the tick they were enabled. * * @param int $signo The signal number to monitor. * @param callable (string $watcherId, int $signo, mixed $data) $callback The callback to execute. * @param mixed $data Arbitrary data given to the callback function as the $data parameter. * * @return string An unique identifier that can be used to cancel, enable or disable the watcher. * * @throws UnsupportedFeatureException If signal handling is not supported. */ public function onSignal(int $signo, callable $callback, $data = null) : string { /** @psalm-var Watcher $watcher */ $watcher = new Watcher(); $watcher->type = Watcher::SIGNAL; $watcher->id = $this->nextId++; $watcher->callback = $callback; $watcher->value = $signo; $watcher->data = $data; $this->watchers[$watcher->id] = $watcher; $this->enableQueue[$watcher->id] = $watcher; return $watcher->id; } /** * Enable a watcher to be active starting in the next tick. * * Watchers MUST immediately be marked as enabled, but only be activated (i.e. callbacks can be called) right before * the next tick. Callbacks of watchers MUST NOT be called in the tick they were enabled. * * @param string $watcherId The watcher identifier. * * @return void * * @throws InvalidWatcherError If the watcher identifier is invalid. */ public function enable(string $watcherId) { if (!isset($this->watchers[$watcherId])) { throw new InvalidWatcherError($watcherId, "Cannot enable an invalid watcher identifier: '{$watcherId}'"); } $watcher = $this->watchers[$watcherId]; if ($watcher->enabled) { return; // Watcher already enabled. } $watcher->enabled = \true; switch ($watcher->type) { case Watcher::DEFER: $this->nextTickQueue[$watcher->id] = $watcher; break; case Watcher::REPEAT: case Watcher::DELAY: \assert(\is_int($watcher->value)); $watcher->expiration = $this->now() + $watcher->value; $this->enableQueue[$watcher->id] = $watcher; break; default: $this->enableQueue[$watcher->id] = $watcher; break; } } /** * Cancel a watcher. * * This will detach the event loop from all resources that are associated to the watcher. After this operation the * watcher is permanently invalid. Calling this function MUST NOT fail, even if passed an invalid watcher. * * @param string $watcherId The watcher identifier. * * @return void */ public function cancel(string $watcherId) { $this->disable($watcherId); unset($this->watchers[$watcherId]); } /** * Disable a watcher immediately. * * A watcher MUST be disabled immediately, e.g. if a defer watcher disables a later defer watcher, the second defer * watcher isn't executed in this tick. * * Disabling a watcher MUST NOT invalidate the watcher. Calling this function MUST NOT fail, even if passed an * invalid watcher. * * @param string $watcherId The watcher identifier. * * @return void */ public function disable(string $watcherId) { if (!isset($this->watchers[$watcherId])) { return; } $watcher = $this->watchers[$watcherId]; if (!$watcher->enabled) { return; // Watcher already disabled. } $watcher->enabled = \false; $id = $watcher->id; switch ($watcher->type) { case Watcher::DEFER: if (isset($this->nextTickQueue[$id])) { // Watcher was only queued to be enabled. unset($this->nextTickQueue[$id]); } else { unset($this->deferQueue[$id]); } break; default: if (isset($this->enableQueue[$id])) { // Watcher was only queued to be enabled. unset($this->enableQueue[$id]); } else { $this->deactivate($watcher); } break; } } /** * Deactivates (disables) the given watcher. * * @param Watcher $watcher * * @return void */ protected abstract function deactivate(Watcher $watcher); /** * Reference a watcher. * * This will keep the event loop alive whilst the watcher is still being monitored. Watchers have this state by * default. * * @param string $watcherId The watcher identifier. * * @return void * * @throws InvalidWatcherError If the watcher identifier is invalid. */ public function reference(string $watcherId) { if (!isset($this->watchers[$watcherId])) { throw new InvalidWatcherError($watcherId, "Cannot reference an invalid watcher identifier: '{$watcherId}'"); } $this->watchers[$watcherId]->referenced = \true; } /** * Unreference a watcher. * * The event loop should exit the run method when only unreferenced watchers are still being monitored. Watchers * are all referenced by default. * * @param string $watcherId The watcher identifier. * * @return void */ public function unreference(string $watcherId) { if (!isset($this->watchers[$watcherId])) { return; } $this->watchers[$watcherId]->referenced = \false; } /** * Stores information in the loop bound registry. * * Stored information is package private. Packages MUST NOT retrieve the stored state of other packages. Packages * MUST use their namespace as prefix for keys. They may do so by using `SomeClass::class` as key. * * If packages want to expose loop bound state to consumers other than the package, they SHOULD provide a dedicated * interface for that purpose instead of sharing the storage key. * * @param string $key The namespaced storage key. * @param mixed $value The value to be stored. * * @return void */ public final function setState(string $key, $value) { if ($value === null) { unset($this->registry[$key]); } else { $this->registry[$key] = $value; } } /** * Gets information stored bound to the loop. * * Stored information is package private. Packages MUST NOT retrieve the stored state of other packages. Packages * MUST use their namespace as prefix for keys. They may do so by using `SomeClass::class` as key. * * If packages want to expose loop bound state to consumers other than the package, they SHOULD provide a dedicated * interface for that purpose instead of sharing the storage key. * * @param string $key The namespaced storage key. * * @return mixed The previously stored value or `null` if it doesn't exist. */ public final function getState(string $key) { return isset($this->registry[$key]) ? $this->registry[$key] : null; } /** * Set a callback to be executed when an error occurs. * * The callback receives the error as the first and only parameter. The return value of the callback gets ignored. * If it can't handle the error, it MUST throw the error. Errors thrown by the callback or during its invocation * MUST be thrown into the `run` loop and stop the driver. * * Subsequent calls to this method will overwrite the previous handler. * * @param callable(\Throwable $error):void|null $callback The callback to execute. `null` will clear the * current handler. * * @return callable(\Throwable $error):void|null The previous handler, `null` if there was none. */ public function setErrorHandler(?callable $callback = null) { $previous = $this->errorHandler; $this->errorHandler = $callback; return $previous; } /** * Invokes the error handler with the given exception. * * @param \Throwable $exception The exception thrown from a watcher callback. * * @return void * @throws \Throwable If no error handler has been set. */ protected function error(\Throwable $exception) { if ($this->errorHandler === null) { throw $exception; } ($this->errorHandler)($exception); } /** * Returns the current loop time in millisecond increments. Note this value does not necessarily correlate to * wall-clock time, rather the value returned is meant to be used in relative comparisons to prior values returned * by this method (intervals, expiration calculations, etc.) and is only updated once per loop tick. * * Extending classes should override this function to return a value cached once per loop tick. * * @return int */ public function now() : int { return (int) (\microtime(\true) * self::MILLISEC_PER_SEC); } /** * Get the underlying loop handle. * * Example: the `uv_loop` resource for `libuv` or the `EvLoop` object for `libev` or `null` for a native driver. * * Note: This function is *not* exposed in the `Loop` class. Users shall access it directly on the respective loop * instance. * * @return null|object|resource The loop handle the event loop operates on. `null` if there is none. */ public abstract function getHandle(); /** * Returns the same array of data as getInfo(). * * @return array */ public function __debugInfo() { // @codeCoverageIgnoreStart return $this->getInfo(); // @codeCoverageIgnoreEnd } /** * Retrieve an associative array of information about the event loop driver. * * The returned array MUST contain the following data describing the driver's currently registered watchers: * * [ * "defer" => ["enabled" => int, "disabled" => int], * "delay" => ["enabled" => int, "disabled" => int], * "repeat" => ["enabled" => int, "disabled" => int], * "on_readable" => ["enabled" => int, "disabled" => int], * "on_writable" => ["enabled" => int, "disabled" => int], * "on_signal" => ["enabled" => int, "disabled" => int], * "enabled_watchers" => ["referenced" => int, "unreferenced" => int], * "running" => bool * ]; * * Implementations MAY optionally add more information in the array but at minimum the above `key => value` format * MUST always be provided. * * @return array Statistics about the loop in the described format. */ public function getInfo() : array { $watchers = ["referenced" => 0, "unreferenced" => 0]; $defer = $delay = $repeat = $onReadable = $onWritable = $onSignal = ["enabled" => 0, "disabled" => 0]; foreach ($this->watchers as $watcher) { switch ($watcher->type) { case Watcher::READABLE: $array =& $onReadable; break; case Watcher::WRITABLE: $array =& $onWritable; break; case Watcher::SIGNAL: $array =& $onSignal; break; case Watcher::DEFER: $array =& $defer; break; case Watcher::DELAY: $array =& $delay; break; case Watcher::REPEAT: $array =& $repeat; break; default: // @codeCoverageIgnoreStart throw new \Error("Unknown watcher type"); } if ($watcher->enabled) { ++$array["enabled"]; if ($watcher->referenced) { ++$watchers["referenced"]; } else { ++$watchers["unreferenced"]; } } else { ++$array["disabled"]; } } return ["enabled_watchers" => $watchers, "defer" => $defer, "delay" => $delay, "repeat" => $repeat, "on_readable" => $onReadable, "on_writable" => $onWritable, "on_signal" => $onSignal, "running" => (bool) $this->running]; } } handle = new \EvLoop(); $this->nowOffset = getCurrentTime(); $this->now = \random_int(0, $this->nowOffset); $this->nowOffset -= $this->now; if (self::$activeSignals === null) { self::$activeSignals =& $this->signals; } /** * @param \EvIO $event * * @return void */ $this->ioCallback = function (\EvIO $event) { /** @var Watcher $watcher */ $watcher = $event->data; try { $result = ($watcher->callback)($watcher->id, $watcher->value, $watcher->data); if ($result === null) { return; } if ($result instanceof \Generator) { $result = new Coroutine($result); } if ($result instanceof Promise || $result instanceof ReactPromise) { rethrow($result); } } catch (\Throwable $exception) { $this->error($exception); } }; /** * @param \EvTimer $event * * @return void */ $this->timerCallback = function (\EvTimer $event) { /** @var Watcher $watcher */ $watcher = $event->data; if ($watcher->type & Watcher::DELAY) { $this->cancel($watcher->id); } elseif ($watcher->value === 0) { // Disable and re-enable so it's not executed repeatedly in the same tick // See https://github.com/amphp/amp/issues/131 $this->disable($watcher->id); $this->enable($watcher->id); } try { $result = ($watcher->callback)($watcher->id, $watcher->data); if ($result === null) { return; } if ($result instanceof \Generator) { $result = new Coroutine($result); } if ($result instanceof Promise || $result instanceof ReactPromise) { rethrow($result); } } catch (\Throwable $exception) { $this->error($exception); } }; /** * @param \EvSignal $event * * @return void */ $this->signalCallback = function (\EvSignal $event) { /** @var Watcher $watcher */ $watcher = $event->data; try { $result = ($watcher->callback)($watcher->id, $watcher->value, $watcher->data); if ($result === null) { return; } if ($result instanceof \Generator) { $result = new Coroutine($result); } if ($result instanceof Promise || $result instanceof ReactPromise) { rethrow($result); } } catch (\Throwable $exception) { $this->error($exception); } }; } /** * {@inheritdoc} */ public function cancel(string $watcherId) { parent::cancel($watcherId); unset($this->events[$watcherId]); } public function __destruct() { foreach ($this->events as $event) { /** @psalm-suppress all */ if ($event !== null) { // Events may have been nulled in extension depending on destruct order. $event->stop(); } } // We need to clear all references to events manually, see // https://bitbucket.org/osmanov/pecl-ev/issues/31/segfault-in-ev_timer_stop $this->events = []; } /** * {@inheritdoc} */ public function run() { $active = self::$activeSignals; \assert($active !== null); foreach ($active as $event) { $event->stop(); } self::$activeSignals =& $this->signals; foreach ($this->signals as $event) { $event->start(); } try { parent::run(); } finally { foreach ($this->signals as $event) { $event->stop(); } self::$activeSignals =& $active; foreach ($active as $event) { $event->start(); } } } /** * {@inheritdoc} */ public function stop() { $this->handle->stop(); parent::stop(); } /** * {@inheritdoc} */ public function now() : int { $this->now = getCurrentTime() - $this->nowOffset; return $this->now; } /** * {@inheritdoc} */ public function getHandle() : \EvLoop { return $this->handle; } /** * {@inheritdoc} * * @return void */ protected function dispatch(bool $blocking) { $this->handle->run($blocking ? \Ev::RUN_ONCE : \Ev::RUN_ONCE | \Ev::RUN_NOWAIT); } /** * {@inheritdoc} * * @return void */ protected function activate(array $watchers) { $this->handle->nowUpdate(); $now = $this->now(); foreach ($watchers as $watcher) { if (!isset($this->events[$id = $watcher->id])) { switch ($watcher->type) { case Watcher::READABLE: \assert(\is_resource($watcher->value)); $this->events[$id] = $this->handle->io($watcher->value, \Ev::READ, $this->ioCallback, $watcher); break; case Watcher::WRITABLE: \assert(\is_resource($watcher->value)); $this->events[$id] = $this->handle->io($watcher->value, \Ev::WRITE, $this->ioCallback, $watcher); break; case Watcher::DELAY: case Watcher::REPEAT: \assert(\is_int($watcher->value)); $interval = $watcher->value / self::MILLISEC_PER_SEC; $this->events[$id] = $this->handle->timer(\max(0, ($watcher->expiration - $now) / self::MILLISEC_PER_SEC), $watcher->type & Watcher::REPEAT ? $interval : 0, $this->timerCallback, $watcher); break; case Watcher::SIGNAL: \assert(\is_int($watcher->value)); $this->events[$id] = $this->handle->signal($watcher->value, $this->signalCallback, $watcher); break; default: // @codeCoverageIgnoreStart throw new \Error("Unknown watcher type"); } } else { $this->events[$id]->start(); } if ($watcher->type === Watcher::SIGNAL) { /** @psalm-suppress PropertyTypeCoercion */ $this->signals[$id] = $this->events[$id]; } } } /** * {@inheritdoc} * * @return void */ protected function deactivate(Watcher $watcher) { if (isset($this->events[$id = $watcher->id])) { $this->events[$id]->stop(); if ($watcher->type === Watcher::SIGNAL) { unset($this->signals[$id]); } } } } watcherId = $watcherId; parent::__construct($message); } /** * @return string The watcher identifier. */ public function getWatcherId() { return $this->watcherId; } } */ final class Success implements Promise { /** @var mixed */ private $value; /** * @param mixed $value Anything other than a Promise object. * * @psalm-param TValue $value * * @throws \Error If a promise is given as the value. */ public function __construct($value = null) { if ($value instanceof Promise || $value instanceof ReactPromise) { throw new \Error("Cannot use a promise as success value"); } $this->value = $value; } /** * {@inheritdoc} */ public function onResolve(callable $onResolved) { try { $result = $onResolved(null, $this->value); if ($result === null) { return; } if ($result instanceof \Generator) { $result = new Coroutine($result); } if ($result instanceof Promise || $result instanceof ReactPromise) { Promise\rethrow($result); } } catch (\Throwable $exception) { Loop::defer(static function () use($exception) { throw $exception; }); } } } reasons = $reasons; } /** * @return \Throwable[] */ public function getReasons() : array { return $this->reasons; } } The MIT License (MIT) Copyright (c) 2015 phpDocumentor Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. lineNumber = $lineNumber; $this->columnNumber = $columnNumber; } /** * Returns the line number that is covered by this location. */ public function getLineNumber() : int { return $this->lineNumber; } /** * Returns the column number (character position on a line) for this location object. */ public function getColumnNumber() : int { return $this->columnNumber; } } fqsen = $fqsen; if (isset($matches[2])) { $this->name = $matches[2]; } else { $matches = explode('\\', $fqsen); $name = end($matches); assert(is_string($name)); $this->name = trim($name, '()'); } } /** * converts this class to string. */ public function __toString() : string { return $this->fqsen; } /** * Returns the name of the element without path. */ public function getName() : string { return $this->name; } } The MIT License (MIT) Copyright (c) 2010 Mike van Riel Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. isFqsen($fqsen)) { return new Fqsen($fqsen); } return $this->resolvePartialStructuralElementName($fqsen, $context); } /** * Tests whether the given type is a Fully Qualified Structural Element Name. */ private function isFqsen(string $type) : bool { return strpos($type, self::OPERATOR_NAMESPACE) === 0; } /** * Resolves a partial Structural Element Name (i.e. `Reflection\DocBlock`) to its FQSEN representation * (i.e. `\phpDocumentor\Reflection\DocBlock`) based on the Namespace and aliases mentioned in the Context. * * @throws InvalidArgumentException When type is not a valid FQSEN. */ private function resolvePartialStructuralElementName(string $type, Context $context) : Fqsen { $typeParts = explode(self::OPERATOR_NAMESPACE, $type, 2); $namespaceAliases = $context->getNamespaceAliases(); // if the first segment is not an alias; prepend namespace name and return if (!isset($namespaceAliases[$typeParts[0]])) { $namespace = $context->getNamespace(); if ($namespace !== '') { $namespace .= self::OPERATOR_NAMESPACE; } return new Fqsen(self::OPERATOR_NAMESPACE . $namespace . $type); } $typeParts[0] = $namespaceAliases[$typeParts[0]]; return new Fqsen(self::OPERATOR_NAMESPACE . implode(self::OPERATOR_NAMESPACE, $typeParts)); } } List of recognized keywords and unto which Value Object they map * @psalm-var array> */ private $keywords = ['string' => String_::class, 'class-string' => ClassString::class, 'interface-string' => InterfaceString::class, 'html-escaped-string' => HtmlEscapedString::class, 'lowercase-string' => LowercaseString::class, 'non-empty-lowercase-string' => NonEmptyLowercaseString::class, 'non-empty-string' => NonEmptyString::class, 'numeric-string' => NumericString::class, 'numeric' => Numeric_::class, 'trait-string' => TraitString::class, 'int' => Integer::class, 'integer' => Integer::class, 'positive-int' => PositiveInteger::class, 'negative-int' => NegativeInteger::class, 'bool' => Boolean::class, 'boolean' => Boolean::class, 'real' => Float_::class, 'float' => Float_::class, 'double' => Float_::class, 'object' => Object_::class, 'mixed' => Mixed_::class, 'array' => Array_::class, 'array-key' => ArrayKey::class, 'resource' => Resource_::class, 'void' => Void_::class, 'null' => Null_::class, 'scalar' => Scalar::class, 'callback' => Callable_::class, 'callable' => Callable_::class, 'callable-string' => CallableString::class, 'false' => False_::class, 'true' => True_::class, 'literal-string' => LiteralString::class, 'self' => Self_::class, '$this' => This::class, 'static' => Static_::class, 'parent' => Parent_::class, 'iterable' => Iterable_::class, 'never' => Never_::class, 'list' => List_::class, 'non-empty-list' => NonEmptyList::class]; /** * @psalm-readonly * @var FqsenResolver */ private $fqsenResolver; /** * @psalm-readonly * @var TypeParser */ private $typeParser; /** * @psalm-readonly * @var Lexer */ private $lexer; /** * Initializes this TypeResolver with the means to create and resolve Fqsen objects. */ public function __construct(?FqsenResolver $fqsenResolver = null) { $this->fqsenResolver = $fqsenResolver ?: new FqsenResolver(); $this->typeParser = new TypeParser(new ConstExprParser()); $this->lexer = new Lexer(); } /** * Analyzes the given type and returns the FQCN variant. * * When a type is provided this method checks whether it is not a keyword or * Fully Qualified Class Name. If so it will use the given namespace and * aliases to expand the type to a FQCN representation. * * This method only works as expected if the namespace and aliases are set; * no dynamic reflection is being performed here. * * @uses Context::getNamespace() to determine with what to prefix the type name. * @uses Context::getNamespaceAliases() to check whether the first part of the relative type name should not be * replaced with another namespace. * * @param string $type The relative or absolute type. */ public function resolve(string $type, ?Context $context = null) : Type { $type = trim($type); if (!$type) { throw new InvalidArgumentException('Attempted to resolve "' . $type . '" but it appears to be empty'); } if ($context === null) { $context = new Context(''); } $tokens = $this->lexer->tokenize($type); $tokenIterator = new TokenIterator($tokens); $ast = $this->parse($tokenIterator); $type = $this->createType($ast, $context); return $this->tryParseRemainingCompoundTypes($tokenIterator, $context, $type); } public function createType(?TypeNode $type, Context $context) : Type { if ($type === null) { return new Mixed_(); } switch (get_class($type)) { case ArrayTypeNode::class: return new Array_($this->createType($type->type, $context)); case ArrayShapeNode::class: return new ArrayShape(...array_map(function (ArrayShapeItemNode $item) use($context) : ArrayShapeItem { return new ArrayShapeItem((string) $item->keyName, $this->createType($item->valueType, $context), $item->optional); }, $type->items)); case CallableTypeNode::class: return $this->createFromCallable($type, $context); case ConstTypeNode::class: return $this->createFromConst($type, $context); case GenericTypeNode::class: return $this->createFromGeneric($type, $context); case IdentifierTypeNode::class: return $this->resolveSingleType($type->name, $context); case IntersectionTypeNode::class: return new Intersection(array_filter(array_map(function (TypeNode $nestedType) use($context) : Type { $type = $this->createType($nestedType, $context); if ($type instanceof AggregatedType) { return new Expression($type); } return $type; }, $type->types))); case NullableTypeNode::class: $nestedType = $this->createType($type->type, $context); return new Nullable($nestedType); case UnionTypeNode::class: return new Compound(array_filter(array_map(function (TypeNode $nestedType) use($context) : Type { $type = $this->createType($nestedType, $context); if ($type instanceof AggregatedType) { return new Expression($type); } return $type; }, $type->types))); case ThisTypeNode::class: return new This(); case ConditionalTypeNode::class: case ConditionalTypeForParameterNode::class: case OffsetAccessTypeNode::class: default: return new Mixed_(); } } private function createFromGeneric(GenericTypeNode $type, Context $context) : Type { switch (strtolower($type->type->name)) { case 'array': return $this->createArray($type->genericTypes, $context); case 'class-string': $subType = $this->createType($type->genericTypes[0], $context); if (!$subType instanceof Object_ || $subType->getFqsen() === null) { throw new RuntimeException($subType . ' is not a class string'); } return new ClassString($subType->getFqsen()); case 'interface-string': $subType = $this->createType($type->genericTypes[0], $context); if (!$subType instanceof Object_ || $subType->getFqsen() === null) { throw new RuntimeException($subType . ' is not a class string'); } return new InterfaceString($subType->getFqsen()); case 'list': return new List_($this->createType($type->genericTypes[0], $context)); case 'non-empty-list': return new NonEmptyList($this->createType($type->genericTypes[0], $context)); case 'int': if (isset($type->genericTypes[1]) === \false) { throw new RuntimeException('int has not the correct format'); } return new IntegerRange((string) $type->genericTypes[0], (string) $type->genericTypes[1]); case 'iterable': return new Iterable_(...array_reverse(array_map(function (TypeNode $genericType) use($context) : Type { return $this->createType($genericType, $context); }, $type->genericTypes))); default: $collectionType = $this->createType($type->type, $context); if ($collectionType instanceof Object_ === \false) { throw new RuntimeException(sprintf('%s is not a collection', (string) $collectionType)); } return new Collection($collectionType->getFqsen(), ...array_reverse(array_map(function (TypeNode $genericType) use($context) : Type { return $this->createType($genericType, $context); }, $type->genericTypes))); } } private function createFromCallable(CallableTypeNode $type, Context $context) : Callable_ { return new Callable_(array_map(function (CallableTypeParameterNode $param) use($context) : CallableParameter { return new CallableParameter($this->createType($param->type, $context), $param->parameterName !== '' ? trim($param->parameterName, '$') : null, $param->isReference, $param->isVariadic, $param->isOptional); }, $type->parameters), $this->createType($type->returnType, $context)); } private function createFromConst(ConstTypeNode $type, Context $context) : Type { switch (\true) { case $type->constExpr instanceof ConstExprIntegerNode: return new IntegerValue((int) $type->constExpr->value); case $type->constExpr instanceof ConstExprFloatNode: return new FloatValue((float) $type->constExpr->value); case $type->constExpr instanceof ConstExprStringNode: return new StringValue($type->constExpr->value); case $type->constExpr instanceof ConstFetchNode: return new ConstExpression($this->resolve($type->constExpr->className, $context), $type->constExpr->name); default: throw new RuntimeException(sprintf('Unsupported constant type %s', get_class($type))); } } /** * resolve the given type into a type object * * @param string $type the type string, representing a single type * * @return Type|Array_|Object_ * * @psalm-mutation-free */ private function resolveSingleType(string $type, Context $context) : object { switch (\true) { case $this->isKeyword($type): return $this->resolveKeyword($type); case $this->isFqsen($type): return $this->resolveTypedObject($type); case $this->isPartialStructuralElementName($type): return $this->resolveTypedObject($type, $context); // @codeCoverageIgnoreStart default: // I haven't got the foggiest how the logic would come here but added this as a defense. throw new RuntimeException('Unable to resolve type "' . $type . '", there is no known method to resolve it'); } // @codeCoverageIgnoreEnd } /** * Adds a keyword to the list of Keywords and associates it with a specific Value Object. * * @psalm-param class-string $typeClassName */ public function addKeyword(string $keyword, string $typeClassName) : void { if (!class_exists($typeClassName)) { throw new InvalidArgumentException('The Value Object that needs to be created with a keyword "' . $keyword . '" must be an existing class' . ' but we could not find the class ' . $typeClassName); } $interfaces = class_implements($typeClassName); if ($interfaces === \false) { throw new InvalidArgumentException('The Value Object that needs to be created with a keyword "' . $keyword . '" must be an existing class' . ' but we could not find the class ' . $typeClassName); } if (!in_array(Type::class, $interfaces, \true)) { throw new InvalidArgumentException('The class "' . $typeClassName . '" must implement the interface "phpDocumentor\\Reflection\\Type"'); } $this->keywords[$keyword] = $typeClassName; } /** * Detects whether the given type represents a PHPDoc keyword. * * @param string $type A relative or absolute type as defined in the phpDocumentor documentation. * * @psalm-mutation-free */ private function isKeyword(string $type) : bool { return array_key_exists(strtolower($type), $this->keywords); } /** * Detects whether the given type represents a relative structural element name. * * @param string $type A relative or absolute type as defined in the phpDocumentor documentation. * * @psalm-mutation-free */ private function isPartialStructuralElementName(string $type) : bool { return isset($type[0]) && $type[0] !== self::OPERATOR_NAMESPACE && !$this->isKeyword($type); } /** * Tests whether the given type is a Fully Qualified Structural Element Name. * * @psalm-mutation-free */ private function isFqsen(string $type) : bool { return strpos($type, self::OPERATOR_NAMESPACE) === 0; } /** * Resolves the given keyword (such as `string`) into a Type object representing that keyword. * * @psalm-mutation-free */ private function resolveKeyword(string $type) : Type { $className = $this->keywords[strtolower($type)]; return new $className(); } /** * Resolves the given FQSEN string into an FQSEN object. * * @psalm-mutation-free */ private function resolveTypedObject(string $type, ?Context $context = null) : Object_ { return new Object_($this->fqsenResolver->resolve($type, $context)); } /** @param TypeNode[] $typeNodes */ private function createArray(array $typeNodes, Context $context) : Array_ { $types = array_reverse(array_map(function (TypeNode $node) use($context) : Type { return $this->createType($node, $context); }, $typeNodes)); if (isset($types[1]) === \false) { return new Array_(...$types); } if ($this->validArrayKeyType($types[1]) || $types[1] instanceof ArrayKey) { return new Array_(...$types); } if ($types[1] instanceof Compound && $types[1]->getIterator()->count() === 2) { if ($this->validArrayKeyType($types[1]->get(0)) && $this->validArrayKeyType($types[1]->get(1))) { return new Array_(...$types); } } throw new RuntimeException('An array can have only integers or strings as keys'); } private function validArrayKeyType(?Type $type) : bool { return $type instanceof String_ || $type instanceof Integer; } private function parse(TokenIterator $tokenIterator) : TypeNode { try { $ast = $this->typeParser->parse($tokenIterator); } catch (ParserException $e) { throw new RuntimeException($e->getMessage(), 0, $e); } return $ast; } /** * Will try to parse unsupported type notations by phpstan * * The phpstan parser doesn't support the illegal nullable combinations like this library does. * This method will warn the user about those notations but for bc purposes we will still have it here. */ private function tryParseRemainingCompoundTypes(TokenIterator $tokenIterator, Context $context, Type $type) : Type { if ($tokenIterator->isCurrentTokenType(Lexer::TOKEN_UNION) || $tokenIterator->isCurrentTokenType(Lexer::TOKEN_INTERSECTION)) { Deprecation::trigger('phpdocumentor/type-resolver', 'https://github.com/phpDocumentor/TypeResolver/issues/184', 'Legacy nullable type detected, please update your code as you are using nullable types in a docblock. support will be removed in v2.0.0'); } $continue = \true; while ($continue) { $continue = \false; while ($tokenIterator->tryConsumeTokenType(Lexer::TOKEN_UNION)) { $ast = $this->parse($tokenIterator); $type2 = $this->createType($ast, $context); $type = new Compound([$type, $type2]); $continue = \true; } while ($tokenIterator->tryConsumeTokenType(Lexer::TOKEN_INTERSECTION)) { $ast = $this->typeParser->parse($tokenIterator); $type2 = $this->createType($ast, $context); $type = new Intersection([$type, $type2]); $continue = \true; } } return $type; } } value = $value; } public function getValue() : int { return $this->value; } public function underlyingType() : Type { return new Integer(); } public function __toString() : string { return (string) $this->value; } } valueType instanceof Mixed_) { return 'non-empty-list'; } return 'non-empty-list<' . $this->valueType . '>'; } } key = $key; $this->value = $value ?? new Mixed_(); $this->optional = $optional; } public function getKey() : ?string { return $this->key; } public function getValue() : Type { return $this->value; } public function isOptional() : bool { return $this->optional; } public function __toString() : string { if ($this->key !== null) { return sprintf('%s%s: %s', $this->key, $this->optional ? '?' : '', (string) $this->value); } return (string) $this->value; } } valueType instanceof Mixed_) { return 'list'; } return 'list<' . $this->valueType . '>'; } } owner = $owner; $this->expression = $expression; } public function getOwner() : Type { return $this->owner; } public function getExpression() : string { return $this->expression; } public function underlyingType() : Type { return new Mixed_(); } public function __toString() : string { return sprintf('%s::%s', (string) $this->owner, $this->expression); } } minValue = $minValue; $this->maxValue = $maxValue; } public function underlyingType() : Type { return new Integer(); } public function getMinValue() : string { return $this->minValue; } public function getMaxValue() : string { return $this->maxValue; } /** * Returns a rendered output of the Type as it would be used in a DocBlock. */ public function __toString() : string { return 'int<' . $this->minValue . ', ' . $this->maxValue . '>'; } } value = $value; } public function getValue() : string { return $this->value; } public function underlyingType() : Type { return new String_(); } public function __toString() : string { return sprintf('"%s"', $this->value); } } items = $items; } /** * @return ArrayShapeItem[] */ public function getItems() : array { return $this->items; } public function underlyingType() : Type { return new Array_(new Mixed_(), new ArrayKey()); } public function __toString() : string { return 'array{' . implode(', ', $this->items) . '}'; } } value = $value; } public function getValue() : float { return $this->value; } public function underlyingType() : Type { return new Float_(); } public function __toString() : string { return (string) $this->value; } } type = $type; $this->isReference = $isReference; $this->isVariadic = $isVariadic; $this->isOptional = $isOptional; $this->name = $name; } public function getName() : ?string { return $this->name; } public function getType() : Type { return $this->type; } public function isReference() : bool { return $this->isReference; } public function isVariadic() : bool { return $this->isVariadic; } public function isOptional() : bool { return $this->isOptional; } } valueType = $valueType; } /** * Returns the value for the keys of this array. */ public function getValueType() : Type { return $this->valueType; } /** * Returns a rendered output of the Type as it would be used in a DocBlock. */ public function __toString() : string { return '(' . $this->valueType . ')'; } } keyType) { return 'iterable<' . $this->keyType . ',' . $this->valueType . '>'; } if ($this->valueType instanceof Mixed_) { return 'iterable'; } return 'iterable<' . $this->valueType . '>'; } } $types */ public function __construct(array $types) { parent::__construct($types, '&'); } } */ abstract class AggregatedType implements Type, IteratorAggregate { /** * @psalm-allow-private-mutation * @var array */ private $types = []; /** @var string */ private $token; /** * @param array $types */ public function __construct(array $types, string $token) { foreach ($types as $type) { $this->add($type); } $this->token = $token; } /** * Returns the type at the given index. */ public function get(int $index) : ?Type { if (!$this->has($index)) { return null; } return $this->types[$index]; } /** * Tests if this compound type has a type with the given index. */ public function has(int $index) : bool { return array_key_exists($index, $this->types); } /** * Tests if this compound type contains the given type. */ public function contains(Type $type) : bool { foreach ($this->types as $typePart) { // if the type is duplicate; do not add it if ((string) $typePart === (string) $type) { return \true; } } return \false; } /** * Returns a rendered output of the Type as it would be used in a DocBlock. */ public function __toString() : string { return implode($this->token, $this->types); } /** * @return ArrayIterator */ public function getIterator() : ArrayIterator { return new ArrayIterator($this->types); } /** * @psalm-suppress ImpureMethodCall */ private function add(Type $type) : void { if ($type instanceof static) { foreach ($type->getIterator() as $subType) { $this->add($subType); } return; } // if the type is duplicate; do not add it if ($this->contains($type)) { return; } $this->types[] = $type; } } fqsen = $fqsen; } public function underlyingType() : Type { return new String_(); } /** * Returns the FQSEN associated with this object. */ public function getFqsen() : ?Fqsen { return $this->fqsen; } /** * Returns a rendered output of the Type as it would be used in a DocBlock. */ public function __toString() : string { if ($this->fqsen === null) { return 'class-string'; } return 'class-string<' . (string) $this->fqsen . '>'; } } fqsen = $fqsen; } /** * Returns the FQSEN associated with this object. */ public function getFqsen() : ?Fqsen { return $this->fqsen; } public function __toString() : string { if ($this->fqsen) { return (string) $this->fqsen; } return 'object'; } } Fully Qualified Namespace. * @psalm-var array */ private $namespaceAliases; /** * Initializes the new context and normalizes all passed namespaces to be in Qualified Namespace Name (QNN) * format (without a preceding `\`). * * @param string $namespace The namespace where this DocBlock resides in. * @param string[] $namespaceAliases List of namespace aliases => Fully Qualified Namespace. * @psalm-param array $namespaceAliases */ public function __construct(string $namespace, array $namespaceAliases = []) { $this->namespace = $namespace !== 'global' && $namespace !== 'default' ? trim($namespace, '\\') : ''; foreach ($namespaceAliases as $alias => $fqnn) { if ($fqnn[0] === '\\') { $fqnn = substr($fqnn, 1); } if ($fqnn[strlen($fqnn) - 1] === '\\') { $fqnn = substr($fqnn, 0, -1); } $namespaceAliases[$alias] = $fqnn; } $this->namespaceAliases = $namespaceAliases; } /** * Returns the Qualified Namespace Name (thus without `\` in front) where the associated element is in. */ public function getNamespace() : string { return $this->namespace; } /** * Returns a list of Qualified Namespace Names (thus without `\` in front) that are imported, the keys represent * the alias for the imported Namespace. * * @return string[] * @psalm-return array */ public function getNamespaceAliases() : array { return $this->namespaceAliases; } } $types */ public function __construct(array $types) { parent::__construct($types, '|'); } } parameters = $parameters; $this->returnType = $returnType; } /** @return CallableParameter[] */ public function getParameters() : array { return $this->parameters; } public function getReturnType() : ?Type { return $this->returnType; } /** * Returns a rendered output of the Type as it would be used in a DocBlock. */ public function __toString() : string { return 'callable'; } } valueType = $valueType; $this->defaultKeyType = new Compound([new String_(), new Integer()]); $this->keyType = $keyType; } /** * Returns the type for the keys of this array. */ public function getKeyType() : Type { return $this->keyType ?? $this->defaultKeyType; } /** * Returns the type for the values of this array. */ public function getValueType() : Type { return $this->valueType; } /** * Returns a rendered output of the Type as it would be used in a DocBlock. */ public function __toString() : string { if ($this->keyType) { return 'array<' . $this->keyType . ',' . $this->valueType . '>'; } if ($this->valueType instanceof Mixed_) { return 'array'; } if ($this->valueType instanceof Compound) { return '(' . $this->valueType . ')[]'; } return $this->valueType . '[]'; } } ` * 2. `ACollectionObject` * * - ACollectionObject can be 'array' or an object that can act as an array * - aValueType and aKeyType can be any type expression * * @psalm-immutable */ final class Collection extends AbstractList { /** @var Fqsen|null */ private $fqsen; /** * Initializes this representation of an array with the given Type or Fqsen. */ public function __construct(?Fqsen $fqsen, Type $valueType, ?Type $keyType = null) { parent::__construct($valueType, $keyType); $this->fqsen = $fqsen; } /** * Returns the FQSEN associated with this object. */ public function getFqsen() : ?Fqsen { return $this->fqsen; } /** * Returns a rendered output of the Type as it would be used in a DocBlock. */ public function __toString() : string { $objectType = (string) ($this->fqsen ?? 'object'); if ($this->keyType === null) { return $objectType . '<' . $this->valueType . '>'; } return $objectType . '<' . $this->keyType . ',' . $this->valueType . '>'; } } fqsen = $fqsen; } /** * Returns the FQSEN associated with this object. */ public function getFqsen() : ?Fqsen { return $this->fqsen; } /** * Returns a rendered output of the Type as it would be used in a DocBlock. */ public function __toString() : string { if ($this->fqsen === null) { return 'interface-string'; } return 'interface-string<' . (string) $this->fqsen . '>'; } } realType = $realType; } /** * Provide access to the actual type directly, if needed. */ public function getActualType() : Type { return $this->realType; } /** * Returns a rendered output of the Type as it would be used in a DocBlock. */ public function __toString() : string { return '?' . $this->realType->__toString(); } } $reflector */ return $this->createFromReflectionClass($reflector); } if ($reflector instanceof ReflectionParameter) { return $this->createFromReflectionParameter($reflector); } if ($reflector instanceof ReflectionMethod) { return $this->createFromReflectionMethod($reflector); } if ($reflector instanceof ReflectionProperty) { return $this->createFromReflectionProperty($reflector); } if ($reflector instanceof ReflectionClassConstant) { return $this->createFromReflectionClassConstant($reflector); } throw new UnexpectedValueException('Unhandled \\Reflector instance given: ' . get_class($reflector)); } private function createFromReflectionParameter(ReflectionParameter $parameter) : Context { $class = $parameter->getDeclaringClass(); if (!$class) { throw new InvalidArgumentException('Unable to get class of ' . $parameter->getName()); } return $this->createFromReflectionClass($class); } private function createFromReflectionMethod(ReflectionMethod $method) : Context { $class = $method->getDeclaringClass(); return $this->createFromReflectionClass($class); } private function createFromReflectionProperty(ReflectionProperty $property) : Context { $class = $property->getDeclaringClass(); return $this->createFromReflectionClass($class); } private function createFromReflectionClassConstant(ReflectionClassConstant $constant) : Context { //phpcs:ignore SlevomatCodingStandard.Commenting.InlineDocCommentDeclaration.MissingVariable /** @phpstan-var ReflectionClass $class */ $class = $constant->getDeclaringClass(); return $this->createFromReflectionClass($class); } /** * @phpstan-param ReflectionClass $class */ private function createFromReflectionClass(ReflectionClass $class) : Context { $fileName = $class->getFileName(); $namespace = $class->getNamespaceName(); if (is_string($fileName) && file_exists($fileName)) { $contents = file_get_contents($fileName); if ($contents === \false) { throw new RuntimeException('Unable to read file "' . $fileName . '"'); } return $this->createForNamespace($namespace, $contents); } return new Context($namespace, []); } /** * Build a Context for a namespace in the provided file contents. * * @see Context for more information on Contexts. * * @param string $namespace It does not matter if a `\` precedes the namespace name, * this method first normalizes. * @param string $fileContents The file's contents to retrieve the aliases from with the given namespace. */ public function createForNamespace(string $namespace, string $fileContents) : Context { $namespace = trim($namespace, '\\'); $useStatements = []; $currentNamespace = ''; $tokens = new ArrayIterator(token_get_all($fileContents)); while ($tokens->valid()) { $currentToken = $tokens->current(); switch ($currentToken[0]) { case T_NAMESPACE: $currentNamespace = $this->parseNamespace($tokens); break; case T_CLASS: case T_TRAIT: // Fast-forward the iterator through the class so that any // T_USE tokens found within are skipped - these are not // valid namespace use statements so should be ignored. $braceLevel = 0; $firstBraceFound = \false; while ($tokens->valid() && ($braceLevel > 0 || !$firstBraceFound)) { $currentToken = $tokens->current(); if ($currentToken === '{' || in_array($currentToken[0], [T_CURLY_OPEN, T_DOLLAR_OPEN_CURLY_BRACES], \true)) { if (!$firstBraceFound) { $firstBraceFound = \true; } ++$braceLevel; } if ($currentToken === '}') { --$braceLevel; } $tokens->next(); } break; case T_USE: if ($currentNamespace === $namespace) { $useStatements += $this->parseUseStatement($tokens); } break; } $tokens->next(); } return new Context($namespace, $useStatements); } /** * Deduce the name from tokens when we are at the T_NAMESPACE token. * * @param ArrayIterator $tokens */ private function parseNamespace(ArrayIterator $tokens) : string { // skip to the first string or namespace separator $this->skipToNextStringOrNamespaceSeparator($tokens); $name = ''; $acceptedTokens = [T_STRING, T_NS_SEPARATOR, T_NAME_QUALIFIED]; while ($tokens->valid() && in_array($tokens->current()[0], $acceptedTokens, \true)) { $name .= $tokens->current()[1]; $tokens->next(); } return $name; } /** * Deduce the names of all imports when we are at the T_USE token. * * @param ArrayIterator $tokens * * @return string[] * @psalm-return array */ private function parseUseStatement(ArrayIterator $tokens) : array { $uses = []; while ($tokens->valid()) { $this->skipToNextStringOrNamespaceSeparator($tokens); $uses += $this->extractUseStatements($tokens); $currentToken = $tokens->current(); if ($currentToken[0] === self::T_LITERAL_END_OF_USE) { return $uses; } } return $uses; } /** * Fast-forwards the iterator as longs as we don't encounter a T_STRING or T_NS_SEPARATOR token. * * @param ArrayIterator $tokens */ private function skipToNextStringOrNamespaceSeparator(ArrayIterator $tokens) : void { while ($tokens->valid()) { $currentToken = $tokens->current(); if (in_array($currentToken[0], [T_STRING, T_NS_SEPARATOR], \true)) { break; } if ($currentToken[0] === T_NAME_QUALIFIED) { break; } if (defined('T_NAME_FULLY_QUALIFIED') && $currentToken[0] === T_NAME_FULLY_QUALIFIED) { break; } $tokens->next(); } } /** * Deduce the namespace name and alias of an import when we are at the T_USE token or have not reached the end of * a USE statement yet. This will return a key/value array of the alias => namespace. * * @param ArrayIterator $tokens * * @return string[] * @psalm-return array * * @psalm-suppress TypeDoesNotContainType */ private function extractUseStatements(ArrayIterator $tokens) : array { $extractedUseStatements = []; $groupedNs = ''; $currentNs = ''; $currentAlias = ''; $state = 'start'; while ($tokens->valid()) { $currentToken = $tokens->current(); $tokenId = is_string($currentToken) ? $currentToken : $currentToken[0]; $tokenValue = is_string($currentToken) ? null : $currentToken[1]; switch ($state) { case 'start': switch ($tokenId) { case T_STRING: case T_NS_SEPARATOR: $currentNs .= (string) $tokenValue; $currentAlias = $tokenValue; break; case T_NAME_QUALIFIED: case T_NAME_FULLY_QUALIFIED: $currentNs .= (string) $tokenValue; $currentAlias = substr((string) $tokenValue, (int) strrpos((string) $tokenValue, '\\') + 1); break; case T_CURLY_OPEN: case '{': $state = 'grouped'; $groupedNs = $currentNs; break; case T_AS: $state = 'start-alias'; break; case self::T_LITERAL_USE_SEPARATOR: case self::T_LITERAL_END_OF_USE: $state = 'end'; break; default: break; } break; case 'start-alias': switch ($tokenId) { case T_STRING: $currentAlias = $tokenValue; break; case self::T_LITERAL_USE_SEPARATOR: case self::T_LITERAL_END_OF_USE: $state = 'end'; break; default: break; } break; case 'grouped': switch ($tokenId) { case T_STRING: case T_NS_SEPARATOR: $currentNs .= (string) $tokenValue; $currentAlias = $tokenValue; break; case T_AS: $state = 'grouped-alias'; break; case self::T_LITERAL_USE_SEPARATOR: $state = 'grouped'; $extractedUseStatements[(string) $currentAlias] = $currentNs; $currentNs = $groupedNs; $currentAlias = ''; break; case self::T_LITERAL_END_OF_USE: $state = 'end'; break; default: break; } break; case 'grouped-alias': switch ($tokenId) { case T_STRING: $currentAlias = $tokenValue; break; case self::T_LITERAL_USE_SEPARATOR: $state = 'grouped'; $extractedUseStatements[(string) $currentAlias] = $currentNs; $currentNs = $groupedNs; $currentAlias = ''; break; case self::T_LITERAL_END_OF_USE: $state = 'end'; break; default: break; } } if ($state === 'end') { break; } $tokens->next(); } if ($groupedNs !== $currentNs) { $extractedUseStatements[(string) $currentAlias] = $currentNs; } return $extractedUseStatements; } } The MIT License (MIT) Copyright (c) 2010 Mike van Riel Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. > $additionalTags */ public static function createInstance(array $additionalTags = []) : self; /** * @param string|object $docblock */ public function create($docblock, ?Types\Context $context = null, ?Location $location = null) : DocBlock; } descriptionFactory = $descriptionFactory; $this->tagFactory = $tagFactory; } /** * Factory method for easy instantiation. * * @param array|Factory> $additionalTags */ public static function createInstance(array $additionalTags = []) : DocBlockFactoryInterface { $fqsenResolver = new FqsenResolver(); $tagFactory = new StandardTagFactory($fqsenResolver); $descriptionFactory = new DescriptionFactory($tagFactory); $typeResolver = new TypeResolver($fqsenResolver); $phpstanTagFactory = new AbstractPHPStanFactory(new ParamFactory($typeResolver, $descriptionFactory), new VarFactory($typeResolver, $descriptionFactory), new ReturnFactory($typeResolver, $descriptionFactory), new PropertyFactory($typeResolver, $descriptionFactory), new PropertyReadFactory($typeResolver, $descriptionFactory), new PropertyWriteFactory($typeResolver, $descriptionFactory), new MethodFactory($typeResolver, $descriptionFactory)); $tagFactory->addService($descriptionFactory); $tagFactory->addService($typeResolver); $tagFactory->registerTagHandler('param', $phpstanTagFactory); $tagFactory->registerTagHandler('var', $phpstanTagFactory); $tagFactory->registerTagHandler('return', $phpstanTagFactory); $tagFactory->registerTagHandler('property', $phpstanTagFactory); $tagFactory->registerTagHandler('property-read', $phpstanTagFactory); $tagFactory->registerTagHandler('property-write', $phpstanTagFactory); $tagFactory->registerTagHandler('method', $phpstanTagFactory); $docBlockFactory = new self($descriptionFactory, $tagFactory); foreach ($additionalTags as $tagName => $tagHandler) { $docBlockFactory->registerTagHandler($tagName, $tagHandler); } return $docBlockFactory; } /** * @param object|string $docblock A string containing the DocBlock to parse or an object supporting the * getDocComment method (such as a ReflectionClass object). */ public function create($docblock, ?Types\Context $context = null, ?Location $location = null) : DocBlock { if (is_object($docblock)) { if (!method_exists($docblock, 'getDocComment')) { $exceptionMessage = 'Invalid object passed; the given object must support the getDocComment method'; throw new InvalidArgumentException($exceptionMessage); } $docblock = $docblock->getDocComment(); Assert::string($docblock); } Assert::stringNotEmpty($docblock); if ($context === null) { $context = new Types\Context(''); } $parts = $this->splitDocBlock($this->stripDocComment($docblock)); [$templateMarker, $summary, $description, $tags] = $parts; return new DocBlock($summary, $description ? $this->descriptionFactory->create($description, $context) : null, $this->parseTagBlock($tags, $context), $context, $location, $templateMarker === '#@+', $templateMarker === '#@-'); } /** * @param class-string|Factory $handler */ public function registerTagHandler(string $tagName, $handler) : void { $this->tagFactory->registerTagHandler($tagName, $handler); } /** * Strips the asterisks from the DocBlock comment. * * @param string $comment String containing the comment text. */ private function stripDocComment(string $comment) : string { $comment = preg_replace('#[ \\t]*(?:\\/\\*\\*|\\*\\/|\\*)?[ \\t]?(.*)?#u', '$1', $comment); Assert::string($comment); $comment = trim($comment); // reg ex above is not able to remove */ from a single line docblock if (substr($comment, -2) === '*/') { $comment = trim(substr($comment, 0, -2)); } return str_replace(["\r\n", "\r"], "\n", $comment); } // phpcs:disable /** * Splits the DocBlock into a template marker, summary, description and block of tags. * * @param string $comment Comment to split into the sub-parts. * * @return string[] containing the template marker (if any), summary, description and a string containing the tags. * * @author Mike van Riel for extending the regex with template marker support. * * @author Richard van Velzen (@_richardJ) Special thanks to Richard for the regex responsible for the split. */ private function splitDocBlock(string $comment) : array { // phpcs:enable // Performance improvement cheat: if the first character is an @ then only tags are in this DocBlock. This // method does not split tags so we return this verbatim as the fourth result (tags). This saves us the // performance impact of running a regular expression if (strpos($comment, '@') === 0) { return ['', '', '', $comment]; } // clears all extra horizontal whitespace from the line endings to prevent parsing issues $comment = preg_replace('/\\h*$/Sum', '', $comment); Assert::string($comment); /* * Splits the docblock into a template marker, summary, description and tags section. * * - The template marker is empty, #@+ or #@- if the DocBlock starts with either of those (a newline may * occur after it and will be stripped). * - The short description is started from the first character until a dot is encountered followed by a * newline OR two consecutive newlines (horizontal whitespace is taken into account to consider spacing * errors). This is optional. * - The long description, any character until a new line is encountered followed by an @ and word * characters (a tag). This is optional. * - Tags; the remaining characters * * Big thanks to RichardJ for contributing this Regular Expression */ preg_match('/ \\A # 1. Extract the template marker (?:(\\#\\@\\+|\\#\\@\\-)\\n?)? # 2. Extract the summary (?: (?! @\\pL ) # The summary may not start with an @ ( [^\\n.]+ (?: (?! \\. \\n | \\n{2} ) # End summary upon a dot followed by newline or two newlines [\\n.]* (?! [ \\t]* @\\pL ) # End summary when an @ is found as first character on a new line [^\\n.]+ # Include anything else )* \\.? )? ) # 3. Extract the description (?: \\s* # Some form of whitespace _must_ precede a description because a summary must be there (?! @\\pL ) # The description may not start with an @ ( [^\\n]+ (?: \\n+ (?! [ \\t]* @\\pL ) # End description when an @ is found as first character on a new line [^\\n]+ # Include anything else )* ) )? # 4. Extract the tags (anything that follows) (\\s+ [\\s\\S]*)? # everything that follows /ux', $comment, $matches); array_shift($matches); while (count($matches) < 4) { $matches[] = ''; } return $matches; } /** * Creates the tag objects. * * @param string $tags Tag block to parse. * @param Types\Context $context Context of the parsed Tag * * @return DocBlock\Tag[] */ private function parseTagBlock(string $tags, Types\Context $context) : array { $tags = $this->filterTagBlock($tags); if ($tags === null) { return []; } $result = []; $lines = $this->splitTagBlockIntoTagLines($tags); foreach ($lines as $key => $tagLine) { $result[$key] = $this->tagFactory->create(trim($tagLine), $context); } return $result; } /** * @return string[] */ private function splitTagBlockIntoTagLines(string $tags) : array { $result = []; foreach (explode("\n", $tags) as $tagLine) { if ($tagLine !== '' && strpos($tagLine, '@') === 0) { $result[] = $tagLine; } else { $result[count($result) - 1] .= "\n" . $tagLine; } } return $result; } private function filterTagBlock(string $tags) : ?string { $tags = trim($tags); if (!$tags) { return null; } if ($tags[0] !== '@') { // @codeCoverageIgnoreStart // Can't simulate this; this only happens if there is an error with the parsing of the DocBlock that // we didn't foresee. throw new LogicException('A tag block started with text instead of an at-sign(@): ' . $tags); // @codeCoverageIgnoreEnd } return $tags; } } summary = $summary; $this->description = $description ?: new DocBlock\Description(''); foreach ($tags as $tag) { $this->addTag($tag); } $this->context = $context; $this->location = $location; $this->isTemplateEnd = $isTemplateEnd; $this->isTemplateStart = $isTemplateStart; } public function getSummary() : string { return $this->summary; } public function getDescription() : DocBlock\Description { return $this->description; } /** * Returns the current context. */ public function getContext() : ?Types\Context { return $this->context; } /** * Returns the current location. */ public function getLocation() : ?Location { return $this->location; } /** * Returns whether this DocBlock is the start of a Template section. * * A Docblock may serve as template for a series of subsequent DocBlocks. This is indicated by a special marker * (`#@+`) that is appended directly after the opening `/**` of a DocBlock. * * An example of such an opening is: * * ``` * /**#@+ * * My DocBlock * * / * ``` * * The description and tags (not the summary!) are copied onto all subsequent DocBlocks and also applied to all * elements that follow until another DocBlock is found that contains the closing marker (`#@-`). * * @see self::isTemplateEnd() for the check whether a closing marker was provided. */ public function isTemplateStart() : bool { return $this->isTemplateStart; } /** * Returns whether this DocBlock is the end of a Template section. * * @see self::isTemplateStart() for a more complete description of the Docblock Template functionality. */ public function isTemplateEnd() : bool { return $this->isTemplateEnd; } /** * Returns the tags for this DocBlock. * * @return Tag[] */ public function getTags() : array { return $this->tags; } /** * Returns an array of tags matching the given name. If no tags are found * an empty array is returned. * * @param string $name String to search by. * * @return Tag[] */ public function getTagsByName(string $name) : array { $result = []; foreach ($this->getTags() as $tag) { if ($tag->getName() !== $name) { continue; } $result[] = $tag; } return $result; } /** * Returns an array of tags with type matching the given name. If no tags are found * an empty array is returned. * * @param string $name String to search by. * * @return TagWithType[] */ public function getTagsWithTypeByName(string $name) : array { $result = []; foreach ($this->getTagsByName($name) as $tag) { if (!$tag instanceof TagWithType) { continue; } $result[] = $tag; } return $result; } /** * Checks if a tag of a certain type is present in this DocBlock. * * @param string $name Tag name to check for. */ public function hasTag(string $name) : bool { foreach ($this->getTags() as $tag) { if ($tag->getName() === $name) { return \true; } } return \false; } /** * Remove a tag from this DocBlock. * * @param Tag $tagToRemove The tag to remove. */ public function removeTag(Tag $tagToRemove) : void { foreach ($this->tags as $key => $tag) { if ($tag === $tagToRemove) { unset($this->tags[$key]); break; } } } /** * Adds a tag to this DocBlock. * * @param Tag $tag The tag to add. */ private function addTag(Tag $tag) : void { $this->tags[] = $tag; } } tagFactory = $tagFactory; } /** * Returns the parsed text of this description. */ public function create(string $contents, ?TypeContext $context = null) : Description { $tokens = $this->lex($contents); $count = count($tokens); $tagCount = 0; $tags = []; for ($i = 1; $i < $count; $i += 2) { $tags[] = $this->tagFactory->create($tokens[$i], $context); $tokens[$i] = '%' . ++$tagCount . '$s'; } //In order to allow "literal" inline tags, the otherwise invalid //sequence "{@}" is changed to "@", and "{}" is changed to "}". //"%" is escaped to "%%" because of vsprintf. //See unit tests for examples. for ($i = 0; $i < $count; $i += 2) { $tokens[$i] = str_replace(['{@}', '{}', '%'], ['@', '}', '%%'], $tokens[$i]); } return new Description(implode('', $tokens), $tags); } /** * Strips the contents from superfluous whitespace and splits the description into a series of tokens. * * @return string[] A series of tokens of which the description text is composed. */ private function lex(string $contents) : array { $contents = $this->removeSuperfluousStartingWhitespace($contents); // performance optimalization; if there is no inline tag, don't bother splitting it up. if (strpos($contents, '{@') === \false) { return [$contents]; } return Utils::pregSplit('/\\{ # "{@}" is not a valid inline tag. This ensures that we do not treat it as one, but treat it literally. (?!@\\}) # We want to capture the whole tag line, but without the inline tag delimiters. (\\@ # Match everything up to the next delimiter. [^{}]* # Nested inline tag content should not be captured, or it will appear in the result separately. (?: # Match nested inline tags. (?: # Because we did not catch the tag delimiters earlier, we must be explicit with them here. # Notice that this also matches "{}", as a way to later introduce it as an escape sequence. \\{(?1)?\\} | # Make sure we match hanging "{". \\{ ) # Match content after the nested inline tag. [^{}]* )* # If there are more inline tags, match them as well. We use "*" since there may not be any # nested inline tags. ) \\}/Sux', $contents, 0, PREG_SPLIT_DELIM_CAPTURE); } /** * Removes the superfluous from a multi-line description. * * When a description has more than one line then it can happen that the second and subsequent lines have an * additional indentation. This is commonly in use with tags like this: * * {@}since 1.1.0 This is an example * description where we have an * indentation in the second and * subsequent lines. * * If we do not normalize the indentation then we have superfluous whitespace on the second and subsequent * lines and this may cause rendering issues when, for example, using a Markdown converter. */ private function removeSuperfluousStartingWhitespace(string $contents) : string { $lines = Utils::pregSplit("/\r\n?|\n/", $contents); // if there is only one line then we don't have lines with superfluous whitespace and // can use the contents as-is if (count($lines) <= 1) { return $contents; } // determine how many whitespace characters need to be stripped $startingSpaceCount = 9999999; for ($i = 1, $iMax = count($lines); $i < $iMax; ++$i) { // lines with a no length do not count as they are not indented at all if (trim($lines[$i]) === '') { continue; } // determine the number of prefixing spaces by checking the difference in line length before and after // an ltrim $startingSpaceCount = min($startingSpaceCount, strlen($lines[$i]) - strlen(ltrim($lines[$i]))); } // strip the number of spaces from each line if ($startingSpaceCount > 0) { for ($i = 1, $iMax = count($lines); $i < $iMax; ++$i) { $lines[$i] = substr($lines[$i], $startingSpaceCount); } } return implode("\n", $lines); } } Important: each parameter in addition to the body variable for the `create` method must default to null, otherwise * > it violates the constraint with the interface; it is recommended to use the {@see Assert::notNull()} method to * > verify that a dependency is actually passed. * * This Factory also features a Service Locator component that is used to pass the right dependencies to the * `create` method of a tag; each dependency should be registered as a service or as a parameter. * * When you want to use a Tag of your own with custom handling you need to call the `registerTagHandler` method, pass * the name of the tag and a Fully Qualified Class Name pointing to a class that implements the Tag interface. */ final class StandardTagFactory implements TagFactory { /** PCRE regular expression matching a tag name. */ public const REGEX_TAGNAME = '[\\w\\-\\_\\\\:]+'; /** * @var array|Factory> An array with a tag as a key, and an * FQCN to a class that handles it as an array value. */ private array $tagHandlerMappings = [ 'author' => Author::class, 'covers' => Covers::class, 'deprecated' => Deprecated::class, // 'example' => '\phpDocumentor\Reflection\DocBlock\Tags\Example', 'link' => LinkTag::class, 'method' => Method::class, 'param' => Param::class, 'property-read' => PropertyRead::class, 'property' => Property::class, 'property-write' => PropertyWrite::class, 'return' => Return_::class, 'see' => SeeTag::class, 'since' => Since::class, 'source' => Source::class, 'throw' => Throws::class, 'throws' => Throws::class, 'uses' => Uses::class, 'var' => Var_::class, 'version' => Version::class, ]; /** * @var array> An array with a anotation s a key, and an * FQCN to a class that handles it as an array value. */ private array $annotationMappings = []; /** * @var ReflectionParameter[][] a lazy-loading cache containing parameters * for each tagHandler that has been used. */ private array $tagHandlerParameterCache = []; private FqsenResolver $fqsenResolver; /** * @var mixed[] an array representing a simple Service Locator where we can store parameters and * services that can be inserted into the Factory Methods of Tag Handlers. */ private array $serviceLocator = []; /** * Initialize this tag factory with the means to resolve an FQSEN and optionally a list of tag handlers. * * If no tag handlers are provided than the default list in the {@see self::$tagHandlerMappings} property * is used. * * @see self::registerTagHandler() to add a new tag handler to the existing default list. * * @param array> $tagHandlers */ public function __construct(FqsenResolver $fqsenResolver, ?array $tagHandlers = null) { $this->fqsenResolver = $fqsenResolver; if ($tagHandlers !== null) { $this->tagHandlerMappings = $tagHandlers; } $this->addService($fqsenResolver, FqsenResolver::class); } public function create(string $tagLine, ?TypeContext $context = null) : Tag { if (!$context) { $context = new TypeContext(''); } [$tagName, $tagBody] = $this->extractTagParts($tagLine); return $this->createTag(trim($tagBody), $tagName, $context); } /** * @param mixed $value */ public function addParameter(string $name, $value) : void { $this->serviceLocator[$name] = $value; } public function addService(object $service, ?string $alias = null) : void { $this->serviceLocator[$alias ?: get_class($service)] = $service; } /** {@inheritDoc} */ public function registerTagHandler(string $tagName, $handler) : void { Assert::stringNotEmpty($tagName); if (strpos($tagName, '\\') && $tagName[0] !== '\\') { throw new InvalidArgumentException('A namespaced tag must have a leading backslash as it must be fully qualified'); } if (is_object($handler)) { Assert::isInstanceOf($handler, Factory::class); $this->tagHandlerMappings[$tagName] = $handler; return; } Assert::classExists($handler); Assert::implementsInterface($handler, Tag::class); $this->tagHandlerMappings[$tagName] = $handler; } /** * Extracts all components for a tag. * * @return string[] */ private function extractTagParts(string $tagLine) : array { $matches = []; if (!preg_match('/^@(' . self::REGEX_TAGNAME . ')((?:[\\s\\(\\{])\\s*([^\\s].*)|$)/us', $tagLine, $matches)) { throw new InvalidArgumentException('The tag "' . $tagLine . '" does not seem to be wellformed, please check it for errors'); } if (count($matches) < 3) { $matches[] = ''; } return array_slice($matches, 1); } /** * Creates a new tag object with the given name and body or returns null if the tag name was recognized but the * body was invalid. */ private function createTag(string $body, string $name, TypeContext $context) : Tag { $handlerClassName = $this->findHandlerClassName($name, $context); $arguments = $this->getArgumentsForParametersFromWiring($this->fetchParametersForHandlerFactoryMethod($handlerClassName), $this->getServiceLocatorWithDynamicParameters($context, $name, $body)); if (array_key_exists('tagLine', $arguments)) { $arguments['tagLine'] = sprintf('@%s %s', $name, $body); } try { $callable = [$handlerClassName, 'create']; Assert::isCallable($callable); /** @phpstan-var callable(string): ?Tag $callable */ $tag = call_user_func_array($callable, $arguments); return $tag ?? InvalidTag::create($body, $name); } catch (InvalidArgumentException $e) { return InvalidTag::create($body, $name)->withError($e); } } /** * Determines the Fully Qualified Class Name of the Factory or Tag (containing a Factory Method `create`). * * @return class-string|Factory */ private function findHandlerClassName(string $tagName, TypeContext $context) { $handlerClassName = Generic::class; if (isset($this->tagHandlerMappings[$tagName])) { $handlerClassName = $this->tagHandlerMappings[$tagName]; } elseif ($this->isAnnotation($tagName)) { // TODO: Annotation support is planned for a later stage and as such is disabled for now $tagName = (string) $this->fqsenResolver->resolve($tagName, $context); if (isset($this->annotationMappings[$tagName])) { $handlerClassName = $this->annotationMappings[$tagName]; } } return $handlerClassName; } /** * Retrieves the arguments that need to be passed to the Factory Method with the given Parameters. * * @param ReflectionParameter[] $parameters * @param mixed[] $locator * * @return mixed[] A series of values that can be passed to the Factory Method of the tag whose parameters * is provided with this method. */ private function getArgumentsForParametersFromWiring(array $parameters, array $locator) : array { $arguments = []; foreach ($parameters as $parameter) { $type = $parameter->getType(); $typeHint = null; if ($type instanceof ReflectionNamedType) { $typeHint = $type->getName(); if ($typeHint === 'self') { $declaringClass = $parameter->getDeclaringClass(); if ($declaringClass !== null) { $typeHint = $declaringClass->getName(); } } } $parameterName = $parameter->getName(); if (isset($locator[$typeHint])) { $arguments[$parameterName] = $locator[$typeHint]; continue; } if (isset($locator[$parameterName])) { $arguments[$parameterName] = $locator[$parameterName]; continue; } $arguments[$parameterName] = null; } return $arguments; } /** * Retrieves a series of ReflectionParameter objects for the static 'create' method of the given * tag handler class name. * * @param class-string|Factory $handler * * @return ReflectionParameter[] */ private function fetchParametersForHandlerFactoryMethod($handler) : array { $handlerClassName = is_object($handler) ? get_class($handler) : $handler; if (!isset($this->tagHandlerParameterCache[$handlerClassName])) { $methodReflection = new ReflectionMethod($handlerClassName, 'create'); $this->tagHandlerParameterCache[$handlerClassName] = $methodReflection->getParameters(); } return $this->tagHandlerParameterCache[$handlerClassName]; } /** * Returns a copy of this class' Service Locator with added dynamic parameters, * such as the tag's name, body and Context. * * @param TypeContext $context The Context (namespace and aliasses) that may be * passed and is used to resolve FQSENs. * @param string $tagName The name of the tag that may be * passed onto the factory method of the Tag class. * @param string $tagBody The body of the tag that may be * passed onto the factory method of the Tag class. * * @return mixed[] */ private function getServiceLocatorWithDynamicParameters(TypeContext $context, string $tagName, string $tagBody) : array { return array_merge($this->serviceLocator, ['name' => $tagName, 'body' => $tagBody, TypeContext::class => $context]); } /** * Returns whether the given tag belongs to an annotation. * * @todo this method should be populated once we implement Annotation notation support. */ private function isAnnotation(string $tagContent) : bool { // 1. Contains a namespace separator // 2. Contains parenthesis // 3. Is present in a list of known annotations (make the algorithm smart by first checking is the last part // of the annotation class name matches the found tag name return \false; } } indent = $indent; $this->indentString = $indentString; $this->isFirstLineIndented = $indentFirstLine; $this->lineLength = $lineLength; $this->tagFormatter = $tagFormatter ?: new PassthroughFormatter(); $this->lineEnding = $lineEnding; } /** * Generate a DocBlock comment. * * @param DocBlock $docblock The DocBlock to serialize. * * @return string The serialized doc block. */ public function getDocComment(DocBlock $docblock) : string { $indent = str_repeat($this->indentString, $this->indent); $firstIndent = $this->isFirstLineIndented ? $indent : ''; // 3 === strlen(' * ') $wrapLength = $this->lineLength ? $this->lineLength - strlen($indent) - 3 : null; $text = $this->removeTrailingSpaces($indent, $this->addAsterisksForEachLine($indent, $this->getSummaryAndDescriptionTextBlock($docblock, $wrapLength))); $comment = $firstIndent . "/**\n"; if ($text) { $comment .= $indent . ' * ' . $text . "\n"; $comment .= $indent . " *\n"; } $comment = $this->addTagBlock($docblock, $wrapLength, $indent, $comment); return str_replace("\n", $this->lineEnding, $comment . $indent . ' */'); } private function removeTrailingSpaces(string $indent, string $text) : string { return str_replace(sprintf("\n%s * \n", $indent), sprintf("\n%s *\n", $indent), $text); } private function addAsterisksForEachLine(string $indent, string $text) : string { return str_replace("\n", sprintf("\n%s * ", $indent), $text); } private function getSummaryAndDescriptionTextBlock(DocBlock $docblock, ?int $wrapLength) : string { $text = $docblock->getSummary() . ((string) $docblock->getDescription() ? "\n\n" . $docblock->getDescription() : ''); if ($wrapLength !== null) { $text = wordwrap($text, $wrapLength); return $text; } return $text; } private function addTagBlock(DocBlock $docblock, ?int $wrapLength, string $indent, string $comment) : string { foreach ($docblock->getTags() as $tag) { $tagText = $this->tagFormatter->format($tag); if ($wrapLength !== null) { $tagText = wordwrap($tagText, $wrapLength); } $tagText = str_replace("\n", sprintf("\n%s * ", $indent), $tagText); $comment .= sprintf("%s * %s\n", $indent, $tagText); } return $comment; } } |Factory $handler FQCN of handler. * * @throws InvalidArgumentException If the tag name is not a string. * @throws InvalidArgumentException If the tag name is namespaced (contains backslashes) but * does not start with a backslash. * @throws InvalidArgumentException If the handler is not a string. * @throws InvalidArgumentException If the handler is not an existing class. * @throws InvalidArgumentException If the handler does not implement the {@see Tag} interface. */ public function registerTagHandler(string $tagName, $handler) : void; } version = $version; $this->description = $description; } public static function create(?string $body, ?DescriptionFactory $descriptionFactory = null, ?TypeContext $context = null) : ?self { if (empty($body)) { return new static(); } $matches = []; if (!preg_match('/^(' . self::REGEX_VECTOR . ')\\s*(.+)?$/sux', $body, $matches)) { return null; } Assert::notNull($descriptionFactory); return new static($matches[1], $descriptionFactory->create($matches[2] ?? '', $context)); } /** * Gets the version section of the tag. */ public function getVersion() : ?string { return $this->version; } /** * Returns a string representation for this tag. */ public function __toString() : string { if ($this->description) { $description = $this->description->render(); } else { $description = ''; } $version = (string) $this->version; return $version . ($description !== '' ? ($version !== '' ? ' ' : '') . $description : ''); } } maxLen = max($this->maxLen, strlen($tag->getName())); } } /** * Formats the given tag to return a simple plain text version. */ public function format(Tag $tag) : string { return '@' . $tag->getName() . str_repeat(' ', $this->maxLen - strlen($tag->getName()) + 1) . $tag; } } getName() . ' ' . $tag); } } version = $version; $this->description = $description; } public static function create(?string $body, ?DescriptionFactory $descriptionFactory = null, ?TypeContext $context = null) : ?self { if (empty($body)) { return new static(); } $matches = []; if (!preg_match('/^(' . self::REGEX_VECTOR . ')\\s*(.+)?$/sux', $body, $matches)) { return null; } $description = null; if ($descriptionFactory !== null) { $description = $descriptionFactory->create($matches[2] ?? '', $context); } return new static($matches[1], $description); } /** * Gets the version section of the tag. */ public function getVersion() : ?string { return $this->version; } /** * Returns a string representation for this tag. */ public function __toString() : string { if ($this->description) { $description = $this->description->render(); } else { $description = ''; } $version = (string) $this->version; return $version . ($description !== '' ? ($version !== '' ? ' ' : '') . $description : ''); } } name; } public function getDescription() : ?Description { return $this->description; } public function render(?Formatter $formatter = null) : string { if ($formatter === null) { $formatter = new Formatter\PassthroughFormatter(); } return $formatter->format($this); } } refers = $refers; $this->description = $description; } public static function create(string $body, ?FqsenResolver $typeResolver = null, ?DescriptionFactory $descriptionFactory = null, ?TypeContext $context = null) : self { Assert::notNull($descriptionFactory); $parts = Utils::pregSplit('/\\s+/Su', $body, 2); $description = isset($parts[1]) ? $descriptionFactory->create($parts[1], $context) : null; // https://tools.ietf.org/html/rfc2396#section-3 if (preg_match('#\\w://\\w#', $parts[0])) { return new static(new Url($parts[0]), $description); } return new static(new FqsenRef(self::resolveFqsen($parts[0], $typeResolver, $context)), $description); } private static function resolveFqsen(string $parts, ?FqsenResolver $fqsenResolver, ?TypeContext $context) : Fqsen { Assert::notNull($fqsenResolver); $fqsenParts = explode('::', $parts); $resolved = $fqsenResolver->resolve($fqsenParts[0], $context); if (!array_key_exists(1, $fqsenParts)) { return $resolved; } return new Fqsen($resolved . '::' . $fqsenParts[1]); } /** * Returns the ref of this tag. */ public function getReference() : Reference { return $this->refers; } /** * Returns a string representation of this tag. */ public function __toString() : string { if ($this->description) { $description = $this->description->render(); } else { $description = ''; } $refers = (string) $this->refers; return $refers . ($description !== '' ? ($refers !== '' ? ' ' : '') . $description : ''); } } type; } /** * @return string[] */ protected static function extractTypeFromBody(string $body) : array { $type = ''; $nestingLevel = 0; for ($i = 0, $iMax = strlen($body); $i < $iMax; $i++) { $character = $body[$i]; if ($nestingLevel === 0 && trim($character) === '') { break; } $type .= $character; if (in_array($character, ['<', '(', '[', '{'])) { $nestingLevel++; continue; } if (in_array($character, ['>', ')', ']', '}'])) { $nestingLevel--; continue; } } if ($nestingLevel < 0 || $nestingLevel > 0) { throw new InvalidArgumentException(sprintf('Could not find type in %s, please check for malformed notations', $body)); } $description = trim(substr($body, strlen($type))); return [$type, $description]; } } filePath = $filePath; $this->startingLine = $startingLine; $this->lineCount = $lineCount; if ($content !== null) { $this->content = trim($content); } $this->isURI = $isURI; } public function getContent() : string { if ($this->content === null || $this->content === '') { $filePath = $this->filePath; if ($this->isURI) { $filePath = $this->isUriRelative($this->filePath) ? str_replace('%2F', '/', rawurlencode($this->filePath)) : $this->filePath; } return trim($filePath); } return $this->content; } public function getDescription() : ?string { return $this->content; } public static function create(string $body) : ?Tag { // File component: File path in quotes or File URI / Source information if (!preg_match('/^\\s*(?:(\\"[^\\"]+\\")|(\\S+))(?:\\s+(.*))?$/sux', $body, $matches)) { return null; } $filePath = null; $fileUri = null; if ($matches[1] !== '') { $filePath = $matches[1]; } else { $fileUri = $matches[2]; } $startingLine = 1; $lineCount = 0; $description = null; if (array_key_exists(3, $matches)) { $description = $matches[3]; // Starting line / Number of lines / Description if (preg_match('/^([1-9]\\d*)(?:\\s+((?1))\\s*)?(.*)$/sux', $matches[3], $contentMatches)) { $startingLine = (int) $contentMatches[1]; if (isset($contentMatches[2])) { $lineCount = (int) $contentMatches[2]; } if (array_key_exists(3, $contentMatches)) { $description = $contentMatches[3]; } } } return new static($filePath ?? $fileUri ?? '', $fileUri !== null, $startingLine, $lineCount, $description); } /** * Returns the file path. * * @return string Path to a file to use as an example. * May also be an absolute URI. */ public function getFilePath() : string { return trim($this->filePath, '"'); } /** * Returns a string representation for this tag. */ public function __toString() : string { $filePath = $this->filePath; $isDefaultLine = $this->startingLine === 1 && $this->lineCount === 0; $startingLine = !$isDefaultLine ? (string) $this->startingLine : ''; $lineCount = !$isDefaultLine ? (string) $this->lineCount : ''; $content = (string) $this->content; return $filePath . ($startingLine !== '' ? ($filePath !== '' ? ' ' : '') . $startingLine : '') . ($lineCount !== '' ? ($filePath !== '' || $startingLine !== '' ? ' ' : '') . $lineCount : '') . ($content !== '' ? ($filePath !== '' || $startingLine !== '' || $lineCount !== '' ? ' ' : '') . $content : ''); } /** * Returns true if the provided URI is relative or contains a complete scheme (and thus is absolute). */ private function isUriRelative(string $uri) : bool { return strpos($uri, ':') === \false; } public function getStartingLine() : int { return $this->startingLine; } public function getLineCount() : int { return $this->lineCount; } public function getName() : string { return 'example'; } public function render(?Formatter $formatter = null) : string { if ($formatter === null) { $formatter = new Formatter\PassthroughFormatter(); } return $formatter->format($this); } } uri = $uri; } public function __toString() : string { return $this->uri; } } fqsen = $fqsen; } /** * @return string string representation of the referenced fqsen */ public function __toString() : string { return (string) $this->fqsen; } } startingLine = (int) $startingLine; $this->lineCount = $lineCount !== null ? (int) $lineCount : null; $this->description = $description; } public static function create(string $body, ?DescriptionFactory $descriptionFactory = null, ?TypeContext $context = null) : self { Assert::stringNotEmpty($body); Assert::notNull($descriptionFactory); $startingLine = 1; $lineCount = null; $description = null; // Starting line / Number of lines / Description if (preg_match('/^([1-9]\\d*)\\s*(?:((?1))\\s+)?(.*)$/sux', $body, $matches)) { $startingLine = (int) $matches[1]; if (isset($matches[2]) && $matches[2] !== '') { $lineCount = (int) $matches[2]; } $description = $matches[3]; } return new static($startingLine, $lineCount, $descriptionFactory->create($description ?? '', $context)); } /** * Gets the starting line. * * @return int The starting line, relative to the structural element's * location. */ public function getStartingLine() : int { return $this->startingLine; } /** * Returns the number of lines. * * @return int|null The number of lines, relative to the starting line. NULL * means "to the end". */ public function getLineCount() : ?int { return $this->lineCount; } public function __toString() : string { if ($this->description) { $description = $this->description->render(); } else { $description = ''; } $startingLine = (string) $this->startingLine; $lineCount = $this->lineCount !== null ? ' ' . $this->lineCount : ''; return $startingLine . $lineCount . ($description !== '' ? ' ' . $description : ''); } } name = 'throws'; $this->type = $type; $this->description = $description; } public static function create(string $body, ?TypeResolver $typeResolver = null, ?DescriptionFactory $descriptionFactory = null, ?TypeContext $context = null) : self { Assert::notNull($typeResolver); Assert::notNull($descriptionFactory); [$type, $description] = self::extractTypeFromBody($body); $type = $typeResolver->resolve($type, $context); $description = $descriptionFactory->create($description, $context); return new static($type, $description); } public function __toString() : string { if ($this->description) { $description = $this->description->render(); } else { $description = ''; } $type = (string) $this->type; return $type . ($description !== '' ? ($type !== '' ? ' ' : '') . $description : ''); } } authorName = $authorName; $this->authorEmail = $authorEmail; } /** * Gets the author's name. * * @return string The author's name. */ public function getAuthorName() : string { return $this->authorName; } /** * Returns the author's email. * * @return string The author's email. */ public function getEmail() : string { return $this->authorEmail; } /** * Returns this tag in string form. */ public function __toString() : string { if ($this->authorEmail) { $authorEmail = '<' . $this->authorEmail . '>'; } else { $authorEmail = ''; } $authorName = $this->authorName; return $authorName . ($authorEmail !== '' ? ($authorName !== '' ? ' ' : '') . $authorEmail : ''); } /** * Attempts to create a new Author object based on the tag body. */ public static function create(string $body) : ?self { $splitTagContent = preg_match('/^([^\\<]*)(?:\\<([^\\>]*)\\>)?$/u', $body, $matches); if (!$splitTagContent) { return null; } $authorName = trim($matches[1]); $email = isset($matches[2]) ? trim($matches[2]) : ''; return new static($authorName, $email); } } name = 'param'; $this->variableName = $variableName; $this->type = $type; $this->isVariadic = $isVariadic; $this->description = $description; $this->isReference = $isReference; } /** * @deprecated Create using static factory is deprecated, * this method should not be called directly by library consumers */ public static function create(string $body, ?TypeResolver $typeResolver = null, ?DescriptionFactory $descriptionFactory = null, ?TypeContext $context = null) : self { Deprecation::triggerIfCalledFromOutside('phpdocumentor/reflection-docblock', 'https://github.com/phpDocumentor/ReflectionDocBlock/issues/361', 'Create using static factory is deprecated, this method should not be called directly by library consumers'); Assert::stringNotEmpty($body); Assert::notNull($typeResolver); Assert::notNull($descriptionFactory); [$firstPart, $body] = self::extractTypeFromBody($body); $type = null; $parts = Utils::pregSplit('/(\\s+)/Su', $body, 2, PREG_SPLIT_DELIM_CAPTURE); $variableName = ''; $isVariadic = \false; $isReference = \false; // if the first item that is encountered is not a variable; it is a type if ($firstPart && !self::strStartsWithVariable($firstPart)) { $type = $typeResolver->resolve($firstPart, $context); } else { // first part is not a type; we should prepend it to the parts array for further processing array_unshift($parts, $firstPart); } // if the next item starts with a $ or ...$ or &$ or &...$ it must be the variable name if (isset($parts[0]) && self::strStartsWithVariable($parts[0])) { $variableName = array_shift($parts); if ($type) { array_shift($parts); } Assert::notNull($variableName); if (strpos($variableName, '$') === 0) { $variableName = substr($variableName, 1); } elseif (strpos($variableName, '&$') === 0) { $isReference = \true; $variableName = substr($variableName, 2); } elseif (strpos($variableName, '...$') === 0) { $isVariadic = \true; $variableName = substr($variableName, 4); } elseif (strpos($variableName, '&...$') === 0) { $isVariadic = \true; $isReference = \true; $variableName = substr($variableName, 5); } } $description = $descriptionFactory->create(implode('', $parts), $context); return new static($variableName, $type, $isVariadic, $description, $isReference); } /** * Returns the variable's name. */ public function getVariableName() : ?string { return $this->variableName; } /** * Returns whether this tag is variadic. */ public function isVariadic() : bool { return $this->isVariadic; } /** * Returns whether this tag is passed by reference. */ public function isReference() : bool { return $this->isReference; } /** * Returns a string representation for this tag. */ public function __toString() : string { if ($this->description) { $description = $this->description->render(); } else { $description = ''; } $variableName = ''; if ($this->variableName) { $variableName .= ($this->isReference ? '&' : '') . ($this->isVariadic ? '...' : ''); $variableName .= '$' . $this->variableName; } $type = (string) $this->type; return $type . ($variableName !== '' ? ($type !== '' ? ' ' : '') . $variableName : '') . ($description !== '' ? ($type !== '' || $variableName !== '' ? ' ' : '') . $description : ''); } private static function strStartsWithVariable(string $str) : bool { return strpos($str, '$') === 0 || strpos($str, '...$') === 0 || strpos($str, '&$') === 0 || strpos($str, '&...$') === 0; } } link = $link; $this->description = $description; } public static function create(string $body, ?DescriptionFactory $descriptionFactory = null, ?TypeContext $context = null) : self { Assert::notNull($descriptionFactory); $parts = Utils::pregSplit('/\\s+/Su', $body, 2); $description = isset($parts[1]) ? $descriptionFactory->create($parts[1], $context) : null; return new static($parts[0], $description); } /** * Gets the link */ public function getLink() : string { return $this->link; } /** * Returns a string representation for this tag. */ public function __toString() : string { if ($this->description) { $description = $this->description->render(); } else { $description = ''; } $link = $this->link; return $link . ($description !== '' ? ($link !== '' ? ' ' : '') . $description : ''); } } name = 'return'; $this->type = $type; $this->description = $description; } /** * @deprecated Create using static factory is deprecated, * this method should not be called directly by library consumers */ public static function create(string $body, ?TypeResolver $typeResolver = null, ?DescriptionFactory $descriptionFactory = null, ?TypeContext $context = null) : self { Deprecation::triggerIfCalledFromOutside('phpdocumentor/reflection-docblock', 'https://github.com/phpDocumentor/ReflectionDocBlock/issues/361', 'Create using static factory is deprecated, this method should not be called directly by library consumers'); Assert::notNull($typeResolver); Assert::notNull($descriptionFactory); [$type, $description] = self::extractTypeFromBody($body); $type = $typeResolver->resolve($type, $context); $description = $descriptionFactory->create($description, $context); return new static($type, $description); } public function __toString() : string { if ($this->description) { $description = $this->description->render(); } else { $description = ''; } $type = $this->type ? '' . $this->type : 'mixed'; return $type . ($description !== '' ? ' ' . $description : ''); } } name = $name; $this->body = $body; } public function getException() : ?Throwable { return $this->throwable; } public function getName() : string { return $this->name; } public static function create(string $body, string $name = '') : self { return new self($name, $body); } public function withError(Throwable $exception) : self { $this->flattenExceptionBacktrace($exception); $tag = new self($this->name, $this->body); $tag->throwable = $exception; return $tag; } /** * Removes all complex types from backtrace * * Not all objects are serializable. So we need to remove them from the * stored exception to be sure that we do not break existing library usage. */ private function flattenExceptionBacktrace(Throwable $exception) : void { $traceProperty = (new ReflectionClass(Exception::class))->getProperty('trace'); $traceProperty->setAccessible(\true); do { $trace = $exception->getTrace(); if (isset($trace[0]['args'])) { $trace = array_map(function (array $call) : array { $call['args'] = array_map([$this, 'flattenArguments'], $call['args'] ?? []); return $call; }, $trace); } $traceProperty->setValue($exception, $trace); $exception = $exception->getPrevious(); } while ($exception !== null); $traceProperty->setAccessible(\false); } /** * @param mixed $value * * @return mixed * * @throws ReflectionException */ private function flattenArguments($value) { if ($value instanceof Closure) { $closureReflection = new ReflectionFunction($value); $value = sprintf('(Closure at %s:%s)', $closureReflection->getFileName(), $closureReflection->getStartLine()); } elseif (is_object($value)) { $value = sprintf('object(%s)', get_class($value)); } elseif (is_resource($value)) { $value = sprintf('resource(%s)', get_resource_type($value)); } elseif (is_array($value)) { $value = array_map([$this, 'flattenArguments'], $value); } return $value; } public function render(?Formatter $formatter = null) : string { if ($formatter === null) { $formatter = new Formatter\PassthroughFormatter(); } return $formatter->format($this); } public function __toString() : string { return $this->body; } } version = $version; $this->description = $description; } /** * @return static */ public static function create(?string $body, ?DescriptionFactory $descriptionFactory = null, ?TypeContext $context = null) : self { if (empty($body)) { return new static(); } $matches = []; if (!preg_match('/^(' . self::REGEX_VECTOR . ')\\s*(.+)?$/sux', $body, $matches)) { return new static(null, $descriptionFactory !== null ? $descriptionFactory->create($body, $context) : null); } Assert::notNull($descriptionFactory); return new static($matches[1], $descriptionFactory->create($matches[2] ?? '', $context)); } /** * Gets the version section of the tag. */ public function getVersion() : ?string { return $this->version; } /** * Returns a string representation for this tag. */ public function __toString() : string { if ($this->description) { $description = $this->description->render(); } else { $description = ''; } $version = (string) $this->version; return $version . ($description !== '' ? ($version !== '' ? ' ' : '') . $description : ''); } } refers = $refers; $this->description = $description; } public static function create(string $body, ?DescriptionFactory $descriptionFactory = null, ?FqsenResolver $resolver = null, ?TypeContext $context = null) : self { Assert::stringNotEmpty($body); Assert::notNull($descriptionFactory); Assert::notNull($resolver); $parts = Utils::pregSplit('/\\s+/Su', $body, 2); return new static(self::resolveFqsen($parts[0], $resolver, $context), $descriptionFactory->create($parts[1] ?? '', $context)); } private static function resolveFqsen(string $parts, ?FqsenResolver $fqsenResolver, ?TypeContext $context) : Fqsen { Assert::notNull($fqsenResolver); $fqsenParts = explode('::', $parts); $resolved = $fqsenResolver->resolve($fqsenParts[0], $context); if (!array_key_exists(1, $fqsenParts)) { return $resolved; } return new Fqsen($resolved . '::' . $fqsenParts[1]); } /** * Returns the structural element this tag refers to. */ public function getReference() : Fqsen { return $this->refers; } /** * Returns a string representation of this tag. */ public function __toString() : string { if ($this->description) { $description = $this->description->render(); } else { $description = ''; } $refers = (string) $this->refers; return $refers . ($description !== '' ? ($refers !== '' ? ' ' : '') . $description : ''); } } refers = $refers; $this->description = $description; } public static function create(string $body, ?FqsenResolver $resolver = null, ?DescriptionFactory $descriptionFactory = null, ?TypeContext $context = null) : self { Assert::notNull($resolver); Assert::notNull($descriptionFactory); $parts = Utils::pregSplit('/\\s+/Su', $body, 2); return new static(self::resolveFqsen($parts[0], $resolver, $context), $descriptionFactory->create($parts[1] ?? '', $context)); } private static function resolveFqsen(string $parts, ?FqsenResolver $fqsenResolver, ?TypeContext $context) : Fqsen { Assert::notNull($fqsenResolver); $fqsenParts = explode('::', $parts); $resolved = $fqsenResolver->resolve($fqsenParts[0], $context); if (!array_key_exists(1, $fqsenParts)) { return $resolved; } return new Fqsen($resolved . '::' . $fqsenParts[1]); } /** * Returns the structural element this tag refers to. */ public function getReference() : Fqsen { return $this->refers; } /** * Returns a string representation of this tag. */ public function __toString() : string { if ($this->description) { $description = $this->description->render(); } else { $description = ''; } $refers = (string) $this->refers; return $refers . ($description !== '' ? ($refers !== '' ? ' ' : '') . $description : ''); } } name = 'var'; $this->variableName = $variableName; $this->type = $type; $this->description = $description; } /** * @deprecated Create using static factory is deprecated, * this method should not be called directly by library consumers */ public static function create(string $body, ?TypeResolver $typeResolver = null, ?DescriptionFactory $descriptionFactory = null, ?TypeContext $context = null) : self { Deprecation::triggerIfCalledFromOutside('phpdocumentor/reflection-docblock', 'https://github.com/phpDocumentor/ReflectionDocBlock/issues/361', 'Create using static factory is deprecated, this method should not be called directly by library consumers'); Assert::stringNotEmpty($body); Assert::notNull($typeResolver); Assert::notNull($descriptionFactory); [$firstPart, $body] = self::extractTypeFromBody($body); $parts = Utils::pregSplit('/(\\s+)/Su', $body, 2, PREG_SPLIT_DELIM_CAPTURE); $type = null; $variableName = ''; // if the first item that is encountered is not a variable; it is a type if ($firstPart && $firstPart[0] !== '$') { $type = $typeResolver->resolve($firstPart, $context); } else { // first part is not a type; we should prepend it to the parts array for further processing array_unshift($parts, $firstPart); } // if the next item starts with a $ it must be the variable name if (isset($parts[0]) && strpos($parts[0], '$') === 0) { $variableName = array_shift($parts); if ($type) { array_shift($parts); } Assert::notNull($variableName); $variableName = substr($variableName, 1); } $description = $descriptionFactory->create(implode('', $parts), $context); return new static($variableName, $type, $description); } /** * Returns the variable's name. */ public function getVariableName() : ?string { return $this->variableName; } /** * Returns a string representation for this tag. */ public function __toString() : string { if ($this->description) { $description = $this->description->render(); } else { $description = ''; } if ($this->variableName) { $variableName = '$' . $this->variableName; } else { $variableName = ''; } $type = (string) $this->type; return $type . ($variableName !== '' ? ($type !== '' ? ' ' : '') . $variableName : '') . ($description !== '' ? ($type !== '' || $variableName !== '' ? ' ' : '') . $description : ''); } } name = 'property-write'; $this->variableName = $variableName; $this->type = $type; $this->description = $description; } /** * @deprecated Create using static factory is deprecated, * this method should not be called directly by library consumers */ public static function create(string $body, ?TypeResolver $typeResolver = null, ?DescriptionFactory $descriptionFactory = null, ?TypeContext $context = null) : self { Deprecation::triggerIfCalledFromOutside('phpdocumentor/reflection-docblock', 'https://github.com/phpDocumentor/ReflectionDocBlock/issues/361', 'Create using static factory is deprecated, this method should not be called directly by library consumers'); Assert::stringNotEmpty($body); Assert::notNull($typeResolver); Assert::notNull($descriptionFactory); [$firstPart, $body] = self::extractTypeFromBody($body); $type = null; $parts = Utils::pregSplit('/(\\s+)/Su', $body, 2, PREG_SPLIT_DELIM_CAPTURE); $variableName = ''; // if the first item that is encountered is not a variable; it is a type if ($firstPart && $firstPart[0] !== '$') { $type = $typeResolver->resolve($firstPart, $context); } else { // first part is not a type; we should prepend it to the parts array for further processing array_unshift($parts, $firstPart); } // if the next item starts with a $ it must be the variable name if (isset($parts[0]) && strpos($parts[0], '$') === 0) { $variableName = array_shift($parts); if ($type) { array_shift($parts); } Assert::notNull($variableName); $variableName = substr($variableName, 1); } $description = $descriptionFactory->create(implode('', $parts), $context); return new static($variableName, $type, $description); } /** * Returns the variable's name. */ public function getVariableName() : ?string { return $this->variableName; } /** * Returns a string representation for this tag. */ public function __toString() : string { if ($this->description) { $description = $this->description->render(); } else { $description = ''; } if ($this->variableName) { $variableName = '$' . $this->variableName; } else { $variableName = ''; } $type = (string) $this->type; return $type . ($variableName !== '' ? ($type !== '' ? ' ' : '') . $variableName : '') . ($description !== '' ? ($type !== '' || $variableName !== '' ? ' ' : '') . $description : ''); } } type = $type; $this->isReference = $isReference; $this->isVariadic = $isVariadic; $this->name = $name; $this->defaultValue = $defaultValue; } public function getName() : string { return $this->name; } public function getType() : Type { return $this->type; } public function isReference() : bool { return $this->isReference; } public function isVariadic() : bool { return $this->isVariadic; } public function getDefaultValue() : ?string { return $this->defaultValue; } } > $arguments * @param MethodParameter[] $parameters * @phpstan-param array $arguments */ public function __construct(string $methodName, array $arguments = [], ?Type $returnType = null, bool $static = \false, ?Description $description = null, bool $returnsReference = \false, ?array $parameters = null) { Assert::stringNotEmpty($methodName); if ($returnType === null) { $returnType = new Void_(); } $arguments = $this->filterArguments($arguments); $this->methodName = $methodName; $this->returnType = $returnType; $this->isStatic = $static; $this->description = $description; $this->returnsReference = $returnsReference; $this->parameters = $parameters ?? $this->fromLegacyArguments($arguments); } /** * @deprecated Create using static factory is deprecated, * this method should not be called directly by library consumers */ public static function create(string $body, ?TypeResolver $typeResolver = null, ?DescriptionFactory $descriptionFactory = null, ?TypeContext $context = null) : ?self { trigger_error('Create using static factory is deprecated, this method should not be called directly by library consumers', E_USER_DEPRECATED); Assert::stringNotEmpty($body); Assert::notNull($typeResolver); Assert::notNull($descriptionFactory); // 1. none or more whitespace // 2. optionally the keyword "static" followed by whitespace // 3. optionally a word with underscores followed by whitespace : as // type for the return value // 4. optionally an ampersand followed or not by whitespace : as // a reference // 5. then optionally a word with underscores followed by () and // whitespace : as method name as used by phpDocumentor // 6. then a word with underscores, followed by ( and any character // until a ) and whitespace : as method name with signature // 7. any remaining text : as description if (!preg_match('/^ # Static keyword # Declares a static method ONLY if type is also present (?: (static) \\s+ )? # Return type (?: ( (?:[\\w\\|_\\\\]*\\$this[\\w\\|_\\\\]*) | (?: (?:[\\w\\|_\\\\]+) # array notation (?:\\[\\])* )*+ ) \\s+ )? # Returns reference (?: (&) \\s* )? # Method name ([\\w_]+) # Arguments (?: \\(([^\\)]*)\\) )? \\s* # Description (.*) $/sux', $body, $matches)) { return null; } [, $static, $returnType, $returnsReference, $methodName, $argumentLines, $description] = $matches; $static = $static === 'static'; if ($returnType === '') { $returnType = 'void'; } $returnsReference = $returnsReference === '&'; $returnType = $typeResolver->resolve($returnType, $context); $description = $descriptionFactory->create($description, $context); /** @phpstan-var array $arguments */ $arguments = []; if ($argumentLines !== '') { $argumentsExploded = explode(',', $argumentLines); foreach ($argumentsExploded as $argument) { $argument = explode(' ', self::stripRestArg(trim($argument)), 2); if (strpos($argument[0], '$') === 0) { $argumentName = substr($argument[0], 1); $argumentType = new Mixed_(); } else { $argumentType = $typeResolver->resolve($argument[0], $context); $argumentName = ''; if (isset($argument[1])) { $argument[1] = self::stripRestArg($argument[1]); $argumentName = substr($argument[1], 1); } } $arguments[] = ['name' => $argumentName, 'type' => $argumentType]; } } return new static($methodName, $arguments, $returnType, $static, $description, $returnsReference); } /** * Retrieves the method name. */ public function getMethodName() : string { return $this->methodName; } /** * @deprecated Method deprecated, use {@see self::getParameters()} * * @return array> * @phpstan-return array */ public function getArguments() : array { trigger_error('Method deprecated, use ::getParameters()', E_USER_DEPRECATED); return array_map(static function (MethodParameter $methodParameter) { return ['name' => $methodParameter->getName(), 'type' => $methodParameter->getType()]; }, $this->parameters); } /** @return MethodParameter[] */ public function getParameters() : array { return $this->parameters; } /** * Checks whether the method tag describes a static method or not. * * @return bool TRUE if the method declaration is for a static method, FALSE otherwise. */ public function isStatic() : bool { return $this->isStatic; } public function getReturnType() : Type { return $this->returnType; } public function returnsReference() : bool { return $this->returnsReference; } public function __toString() : string { $arguments = []; foreach ($this->parameters as $parameter) { $arguments[] = $parameter->getType() . ' ' . ($parameter->isReference() ? '&' : '') . ($parameter->isVariadic() ? '...' : '') . '$' . $parameter->getName(); } $argumentStr = '(' . implode(', ', $arguments) . ')'; if ($this->description) { $description = $this->description->render(); } else { $description = ''; } $static = $this->isStatic ? 'static' : ''; $returnType = (string) $this->returnType; $methodName = $this->methodName; $reference = $this->returnsReference ? '&' : ''; return $static . ($returnType !== '' ? ($static !== '' ? ' ' : '') . $returnType : '') . ($methodName !== '' ? ($static !== '' || $returnType !== '' ? ' ' : '') . $reference . $methodName : '') . $argumentStr . ($description !== '' ? ' ' . $description : ''); } /** * @param mixed[][]|string[] $arguments * @phpstan-param array $arguments * * @return mixed[][] * @phpstan-return array */ private function filterArguments(array $arguments = []) : array { $result = []; foreach ($arguments as $argument) { if (is_string($argument)) { $argument = ['name' => $argument]; } if (!isset($argument['type'])) { $argument['type'] = new Mixed_(); } $keys = array_keys($argument); sort($keys); if ($keys !== ['name', 'type']) { throw new InvalidArgumentException('Arguments can only have the "name" and "type" fields, found: ' . var_export($keys, \true)); } $result[] = $argument; } return $result; } private static function stripRestArg(string $argument) : string { if (strpos($argument, '...') === 0) { $argument = trim(substr($argument, 3)); } return $argument; } /** * @param array{name: string, type: Type} $arguments * @phpstan-param array $arguments * * @return MethodParameter[] */ private function fromLegacyArguments(array $arguments) : array { trigger_error('Create method parameters via legacy format is deprecated add parameters via the constructor', E_USER_DEPRECATED); return array_map(static function ($arg) { return new MethodParameter($arg['name'], $arg['type']); }, $arguments); } } name = 'property'; $this->variableName = $variableName; $this->type = $type; $this->description = $description; } /** * @deprecated Create using static factory is deprecated, * this method should not be called directly by library consumers */ public static function create(string $body, ?TypeResolver $typeResolver = null, ?DescriptionFactory $descriptionFactory = null, ?TypeContext $context = null) : self { Deprecation::triggerIfCalledFromOutside('phpdocumentor/reflection-docblock', 'https://github.com/phpDocumentor/ReflectionDocBlock/issues/361', 'Create using static factory is deprecated, this method should not be called directly by library consumers'); Assert::stringNotEmpty($body); Assert::notNull($typeResolver); Assert::notNull($descriptionFactory); [$firstPart, $body] = self::extractTypeFromBody($body); $type = null; $parts = Utils::pregSplit('/(\\s+)/Su', $body, 2, PREG_SPLIT_DELIM_CAPTURE); $variableName = ''; // if the first item that is encountered is not a variable; it is a type if ($firstPart && $firstPart[0] !== '$') { $type = $typeResolver->resolve($firstPart, $context); } else { // first part is not a type; we should prepend it to the parts array for further processing array_unshift($parts, $firstPart); } // if the next item starts with a $ it must be the variable name if (isset($parts[0]) && strpos($parts[0], '$') === 0) { $variableName = array_shift($parts); if ($type) { array_shift($parts); } Assert::notNull($variableName); $variableName = substr($variableName, 1); } $description = $descriptionFactory->create(implode('', $parts), $context); return new static($variableName, $type, $description); } /** * Returns the variable's name. */ public function getVariableName() : ?string { return $this->variableName; } /** * Returns a string representation for this tag. */ public function __toString() : string { if ($this->description) { $description = $this->description->render(); } else { $description = ''; } if ($this->variableName) { $variableName = '$' . $this->variableName; } else { $variableName = ''; } $type = (string) $this->type; return $type . ($variableName !== '' ? ($type !== '' ? ' ' : '') . $variableName : '') . ($description !== '' ? ($type !== '' || $variableName !== '' ? ' ' : '') . $description : ''); } } name = 'property-read'; $this->variableName = $variableName; $this->type = $type; $this->description = $description; } /** * @deprecated Create using static factory is deprecated, * this method should not be called directly by library consumers */ public static function create(string $body, ?TypeResolver $typeResolver = null, ?DescriptionFactory $descriptionFactory = null, ?TypeContext $context = null) : self { Deprecation::triggerIfCalledFromOutside('phpdocumentor/reflection-docblock', 'https://github.com/phpDocumentor/ReflectionDocBlock/issues/361', 'Create using static factory is deprecated, this method should not be called directly by library consumers'); Assert::stringNotEmpty($body); Assert::notNull($typeResolver); Assert::notNull($descriptionFactory); [$firstPart, $body] = self::extractTypeFromBody($body); $type = null; $parts = Utils::pregSplit('/(\\s+)/Su', $body, 2, PREG_SPLIT_DELIM_CAPTURE); $variableName = ''; // if the first item that is encountered is not a variable; it is a type if ($firstPart && $firstPart[0] !== '$') { $type = $typeResolver->resolve($firstPart, $context); } else { // first part is not a type; we should prepend it to the parts array for further processing array_unshift($parts, $firstPart); } // if the next item starts with a $ it must be the variable name if (isset($parts[0]) && strpos($parts[0], '$') === 0) { $variableName = array_shift($parts); if ($type) { array_shift($parts); } Assert::notNull($variableName); $variableName = substr($variableName, 1); } $description = $descriptionFactory->create(implode('', $parts), $context); return new static($variableName, $type, $description); } /** * Returns the variable's name. */ public function getVariableName() : ?string { return $this->variableName; } /** * Returns a string representation for this tag. */ public function __toString() : string { if ($this->description) { $description = $this->description->render(); } else { $description = ''; } if ($this->variableName) { $variableName = '$' . $this->variableName; } else { $variableName = ''; } $type = (string) $this->type; return $type . ($variableName !== '' ? ($type !== '' ? ' ' : '') . $variableName : '') . ($description !== '' ? ($type !== '' || $variableName !== '' ? ' ' : '') . $description : ''); } } typeResolver = $typeResolver; $this->descriptionFactory = $descriptionFactory; } public function create(PhpDocTagNode $node, Context $context) : Tag { $tagValue = $node->value; Assert::isInstanceOf($tagValue, PropertyTagValueNode::class); $description = $tagValue->getAttribute('description'); if (is_string($description) === \false) { $description = $tagValue->description; } return new PropertyRead(trim($tagValue->propertyName, '$'), $this->typeResolver->createType($tagValue->type, $context), $this->descriptionFactory->create($description, $context)); } public function supports(PhpDocTagNode $node, Context $context) : bool { return $node->value instanceof PropertyTagValueNode && $node->name === '@property-read'; } } descriptionFactory = $descriptionFactory; $this->typeResolver = $typeResolver; } public function create(PhpDocTagNode $node, Context $context) : Tag { $tagValue = $node->value; if ($tagValue instanceof InvalidTagValueNode) { Deprecation::trigger('phpdocumentor/reflection-docblock', 'https://github.com/phpDocumentor/ReflectionDocBlock/issues/362', sprintf('Param tag value "%s" is invalid, falling back to legacy parsing. Please update your docblocks.', $tagValue->value)); return Param::create($tagValue->value, $this->typeResolver, $this->descriptionFactory, $context); } Assert::isInstanceOfAny($tagValue, [ParamTagValueNode::class, TypelessParamTagValueNode::class]); if (($tagValue->type ?? null) instanceof OffsetAccessTypeNode) { return InvalidTag::create((string) $tagValue, 'param'); } $description = $tagValue->getAttribute('description'); if (is_string($description) === \false) { $description = $tagValue->description; } return new Param(trim($tagValue->parameterName, '$'), $this->typeResolver->createType($tagValue->type ?? new IdentifierTypeNode('mixed'), $context), $tagValue->isVariadic, $this->descriptionFactory->create($description, $context), $tagValue->isReference); } public function supports(PhpDocTagNode $node, Context $context) : bool { return $node->value instanceof ParamTagValueNode || $node->value instanceof TypelessParamTagValueNode || $node->name === '@param'; } } lexer = new Lexer(\true); $constParser = new ConstExprParser(\true, \true, ['lines' => \true, 'indexes' => \true]); $this->parser = new PhpDocParser(new TypeParser($constParser, \true, ['lines' => \true, 'indexes' => \true]), $constParser, \true, \true, ['lines' => \true, 'indexes' => \true], \true); $this->factories = $factories; } public function create(string $tagLine, ?TypeContext $context = null) : Tag { $tokens = $this->tokenizeLine($tagLine); $ast = $this->parser->parseTag($tokens); if (property_exists($ast->value, 'description') === \true) { $ast->value->setAttribute('description', $ast->value->description . $tokens->joinUntil(Lexer::TOKEN_END)); } if ($context === null) { $context = new TypeContext(''); } try { foreach ($this->factories as $factory) { if ($factory->supports($ast, $context)) { return $factory->create($ast, $context); } } } catch (RuntimeException $e) { return InvalidTag::create((string) $ast->value, 'method')->withError($e); } return InvalidTag::create((string) $ast->value, $ast->name); } /** * Solve the issue with the lexer not tokenizing the line correctly * * This method is a workaround for the lexer that includes newline tokens with spaces. For * phpstan this isn't an issue, as it doesn't do a lot of things with the indentation of descriptions. * But for us is important to keep the indentation of the descriptions, so we need to fix the lexer output. */ private function tokenizeLine(string $tagLine) : TokenIterator { $tokens = $this->lexer->tokenize($tagLine); $fixed = []; foreach ($tokens as $token) { if ($token[1] === Lexer::TOKEN_PHPDOC_EOL && rtrim($token[0], " \t") !== $token[0]) { $fixed[] = [rtrim($token[Lexer::VALUE_OFFSET], " \t"), Lexer::TOKEN_PHPDOC_EOL, $token[2] ?? null]; $fixed[] = [ltrim($token[Lexer::VALUE_OFFSET], "\n\r"), Lexer::TOKEN_HORIZONTAL_WS, ($token[2] ?? null) + 1]; continue; } $fixed[] = $token; } return new TokenIterator($fixed); } } descriptionFactory = $descriptionFactory; $this->typeResolver = $typeResolver; } public function create(PhpDocTagNode $node, Context $context) : Tag { $tagValue = $node->value; Assert::isInstanceOf($tagValue, MethodTagValueNode::class); return new Method($tagValue->methodName, [], $this->createReturnType($tagValue, $context), $tagValue->isStatic, $this->descriptionFactory->create($tagValue->description, $context), \false, array_map(function (MethodTagValueParameterNode $param) use($context) { return new MethodParameter(trim($param->parameterName, '$'), $param->type === null ? new Mixed_() : $this->typeResolver->createType($param->type, $context), $param->isReference, $param->isVariadic, (string) $param->defaultValue); }, $tagValue->parameters)); } public function supports(PhpDocTagNode $node, Context $context) : bool { return $node->value instanceof MethodTagValueNode; } private function createReturnType(MethodTagValueNode $tagValue, Context $context) : Type { if ($tagValue->returnType === null) { return new Void_(); } return $this->typeResolver->createType($tagValue->returnType, $context); } } descriptionFactory = $descriptionFactory; $this->typeResolver = $typeResolver; } public function create(PhpDocTagNode $node, Context $context) : Tag { $tagValue = $node->value; Assert::isInstanceOf($tagValue, PropertyTagValueNode::class); $description = $tagValue->getAttribute('description'); if (is_string($description) === \false) { $description = $tagValue->description; } return new Property(trim($tagValue->propertyName, '$'), $this->typeResolver->createType($tagValue->type, $context), $this->descriptionFactory->create($description, $context)); } public function supports(PhpDocTagNode $node, Context $context) : bool { return $node->value instanceof PropertyTagValueNode && $node->name === '@property'; } } descriptionFactory = $descriptionFactory; $this->typeResolver = $typeResolver; } public function create(PhpDocTagNode $node, Context $context) : Tag { $tagValue = $node->value; Assert::isInstanceOf($tagValue, PropertyTagValueNode::class); $description = $tagValue->getAttribute('description'); if (is_string($description) === \false) { $description = $tagValue->description; } return new PropertyWrite(trim($tagValue->propertyName, '$'), $this->typeResolver->createType($tagValue->type, $context), $this->descriptionFactory->create($description, $context)); } public function supports(PhpDocTagNode $node, Context $context) : bool { return $node->value instanceof PropertyTagValueNode && $node->name === '@property-write'; } } descriptionFactory = $descriptionFactory; $this->typeResolver = $typeResolver; } public function create(PhpDocTagNode $node, Context $context) : Tag { $tagValue = $node->value; Assert::isInstanceOf($tagValue, VarTagValueNode::class); $description = $tagValue->getAttribute('description'); if (is_string($description) === \false) { $description = $tagValue->description; } return new Var_(trim($tagValue->variableName, '$'), $this->typeResolver->createType($tagValue->type, $context), $this->descriptionFactory->create($description, $context)); } public function supports(PhpDocTagNode $node, Context $context) : bool { return $node->value instanceof VarTagValueNode; } } descriptionFactory = $descriptionFactory; $this->typeResolver = $typeResolver; } public function create(PhpDocTagNode $node, Context $context) : Tag { $tagValue = $node->value; Assert::isInstanceOf($tagValue, ReturnTagValueNode::class); $description = $tagValue->getAttribute('description'); if (is_string($description) === \false) { $description = $tagValue->description; } return new Return_($this->typeResolver->createType($tagValue->type, $context), $this->descriptionFactory->create($description, $context)); } public function supports(PhpDocTagNode $node, Context $context) : bool { return $node->value instanceof ReturnTagValueNode; } } validateTagName($name); $this->name = $name; $this->description = $description; } /** * Creates a new tag that represents any unknown tag type. * * @return static */ public static function create(string $body, string $name = '', ?DescriptionFactory $descriptionFactory = null, ?TypeContext $context = null) : self { Assert::stringNotEmpty($name); Assert::notNull($descriptionFactory); $description = $body !== '' ? $descriptionFactory->create($body, $context) : null; return new static($name, $description); } /** * Returns the tag as a serialized string */ public function __toString() : string { if ($this->description) { $description = $this->description->render(); } else { $description = ''; } return $description; } /** * Validates if the tag name matches the expected format, otherwise throws an exception. */ private function validateTagName(string $name) : void { if (!preg_match('/^' . StandardTagFactory::REGEX_TAGNAME . '$/u', $name)) { throw new InvalidArgumentException('The tag name "' . $name . '" is not wellformed. Tags may only consist of letters, underscores, ' . 'hyphens and backslashes.'); } } } getFilePath(); $file = $this->getExampleFileContents($filename); if (!$file) { return sprintf('** File not found : %s **', $filename); } return implode('', array_slice($file, $example->getStartingLine() - 1, $example->getLineCount())); } /** * Registers the project's root directory where an 'examples' folder can be expected. */ public function setSourceDirectory(string $directory = '') : void { $this->sourceDirectory = $directory; } /** * Returns the project's root directory where an 'examples' folder can be expected. */ public function getSourceDirectory() : string { return $this->sourceDirectory; } /** * Registers a series of directories that may contain examples. * * @param string[] $directories */ public function setExampleDirectories(array $directories) : void { $this->exampleDirectories = $directories; } /** * Returns a series of directories that may contain examples. * * @return string[] */ public function getExampleDirectories() : array { return $this->exampleDirectories; } /** * Attempts to find the requested example file and returns its contents or null if no file was found. * * This method will try several methods in search of the given example file, the first one it encounters is * returned: * * 1. Iterates through all examples folders for the given filename * 2. Checks the source folder for the given filename * 3. Checks the 'examples' folder in the current working directory for examples * 4. Checks the path relative to the current working directory for the given filename * * @return string[] all lines of the example file */ private function getExampleFileContents(string $filename) : ?array { $normalizedPath = null; foreach ($this->exampleDirectories as $directory) { $exampleFileFromConfig = $this->constructExamplePath($directory, $filename); if (is_readable($exampleFileFromConfig)) { $normalizedPath = $exampleFileFromConfig; break; } } if (!$normalizedPath) { if (is_readable($this->getExamplePathFromSource($filename))) { $normalizedPath = $this->getExamplePathFromSource($filename); } elseif (is_readable($this->getExamplePathFromExampleDirectory($filename))) { $normalizedPath = $this->getExamplePathFromExampleDirectory($filename); } elseif (is_readable($filename)) { $normalizedPath = $filename; } } $lines = $normalizedPath && is_readable($normalizedPath) ? file($normalizedPath) : \false; return $lines !== \false ? $lines : null; } /** * Get example filepath based on the example directory inside your project. */ private function getExamplePathFromExampleDirectory(string $file) : string { return getcwd() . DIRECTORY_SEPARATOR . 'examples' . DIRECTORY_SEPARATOR . $file; } /** * Returns a path to the example file in the given directory.. */ private function constructExamplePath(string $directory, string $file) : string { return rtrim($directory, '\\/') . DIRECTORY_SEPARATOR . $file; } /** * Get example filepath based on sourcecode. */ private function getExamplePathFromSource(string $file) : string { return sprintf('%s%s%s', trim($this->getSourceDirectory(), '\\/'), DIRECTORY_SEPARATOR, trim($file, '"')); } } create('This is a {@see Description}', $context); * * The description factory will interpret the given body and create a body template and list of tags from them, and pass * that onto the constructor if this class. * * > The $context variable is a class of type {@see \phpDocumentor\Reflection\Types\Context} and contains the namespace * > and the namespace aliases that apply to this DocBlock. These are used by the Factory to resolve and expand partial * > type names and FQSENs. * * If you do not want to use the DescriptionFactory you can pass a body template and tag listing like this: * * $description = new Description( * 'This is a %1$s', * [ new See(new Fqsen('\phpDocumentor\Reflection\DocBlock\Description')) ] * ); * * It is generally recommended to use the Factory as that will also apply escaping rules, while the Description object * is mainly responsible for rendering. * * @see DescriptionFactory to create a new Description. * @see Tags\Formatter for the formatting of the body and tags. */ class Description { private string $bodyTemplate; /** @var Tag[] */ private array $tags; /** * Initializes a Description with its body (template) and a listing of the tags used in the body template. * * @param Tag[] $tags */ public function __construct(string $bodyTemplate, array $tags = []) { $this->bodyTemplate = $bodyTemplate; $this->tags = $tags; } /** * Returns the body template. */ public function getBodyTemplate() : string { return $this->bodyTemplate; } /** * Returns the tags for this DocBlock. * * @return Tag[] */ public function getTags() : array { return $this->tags; } /** * Renders this description as a string where the provided formatter will format the tags in the expected string * format. */ public function render(?Formatter $formatter = null) : string { if ($this->tags === []) { return vsprintf($this->bodyTemplate, []); } if ($formatter === null) { $formatter = new PassthroughFormatter(); } $tags = []; foreach ($this->tags as $tag) { $tags[] = '{' . $formatter->format($tag) . '}'; } return vsprintf($this->bodyTemplate, $tags); } /** * Returns a plain string representation of this description. */ public function __toString() : string { return $this->render(); } } * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace _HumbugBox7ff99e199a36\Webmozart\Assert; use ArrayAccess; use BadMethodCallException; use Closure; use Countable; use DateTime; use DateTimeImmutable; use Exception; use ResourceBundle; use SimpleXMLElement; use Throwable; use Traversable; /** * Efficient assertions to validate the input/output of your methods. * * @since 1.0 * * @author Bernhard Schussek */ class Assert { use Mixin; /** * @psalm-pure * @psalm-assert string $value * * @param mixed $value * @param string $message * * @throws InvalidArgumentException */ public static function string($value, $message = '') { if (!\is_string($value)) { static::reportInvalidArgument(\sprintf($message ?: 'Expected a string. Got: %s', static::typeToString($value))); } } /** * @psalm-pure * @psalm-assert non-empty-string $value * * @param mixed $value * @param string $message * * @throws InvalidArgumentException */ public static function stringNotEmpty($value, $message = '') { static::string($value, $message); static::notEq($value, '', $message); } /** * @psalm-pure * @psalm-assert int $value * * @param mixed $value * @param string $message * * @throws InvalidArgumentException */ public static function integer($value, $message = '') { if (!\is_int($value)) { static::reportInvalidArgument(\sprintf($message ?: 'Expected an integer. Got: %s', static::typeToString($value))); } } /** * @psalm-pure * @psalm-assert numeric $value * * @param mixed $value * @param string $message * * @throws InvalidArgumentException */ public static function integerish($value, $message = '') { if (!\is_numeric($value) || $value != (int) $value) { static::reportInvalidArgument(\sprintf($message ?: 'Expected an integerish value. Got: %s', static::typeToString($value))); } } /** * @psalm-pure * @psalm-assert positive-int $value * * @param mixed $value * @param string $message * * @throws InvalidArgumentException */ public static function positiveInteger($value, $message = '') { if (!(\is_int($value) && $value > 0)) { static::reportInvalidArgument(\sprintf($message ?: 'Expected a positive integer. Got: %s', static::valueToString($value))); } } /** * @psalm-pure * @psalm-assert float $value * * @param mixed $value * @param string $message * * @throws InvalidArgumentException */ public static function float($value, $message = '') { if (!\is_float($value)) { static::reportInvalidArgument(\sprintf($message ?: 'Expected a float. Got: %s', static::typeToString($value))); } } /** * @psalm-pure * @psalm-assert numeric $value * * @param mixed $value * @param string $message * * @throws InvalidArgumentException */ public static function numeric($value, $message = '') { if (!\is_numeric($value)) { static::reportInvalidArgument(\sprintf($message ?: 'Expected a numeric. Got: %s', static::typeToString($value))); } } /** * @psalm-pure * @psalm-assert positive-int|0 $value * * @param mixed $value * @param string $message * * @throws InvalidArgumentException */ public static function natural($value, $message = '') { if (!\is_int($value) || $value < 0) { static::reportInvalidArgument(\sprintf($message ?: 'Expected a non-negative integer. Got: %s', static::valueToString($value))); } } /** * @psalm-pure * @psalm-assert bool $value * * @param mixed $value * @param string $message * * @throws InvalidArgumentException */ public static function boolean($value, $message = '') { if (!\is_bool($value)) { static::reportInvalidArgument(\sprintf($message ?: 'Expected a boolean. Got: %s', static::typeToString($value))); } } /** * @psalm-pure * @psalm-assert scalar $value * * @param mixed $value * @param string $message * * @throws InvalidArgumentException */ public static function scalar($value, $message = '') { if (!\is_scalar($value)) { static::reportInvalidArgument(\sprintf($message ?: 'Expected a scalar. Got: %s', static::typeToString($value))); } } /** * @psalm-pure * @psalm-assert object $value * * @param mixed $value * @param string $message * * @throws InvalidArgumentException */ public static function object($value, $message = '') { if (!\is_object($value)) { static::reportInvalidArgument(\sprintf($message ?: 'Expected an object. Got: %s', static::typeToString($value))); } } /** * @psalm-pure * @psalm-assert resource $value * * @param mixed $value * @param string|null $type type of resource this should be. @see https://www.php.net/manual/en/function.get-resource-type.php * @param string $message * * @throws InvalidArgumentException */ public static function resource($value, $type = null, $message = '') { if (!\is_resource($value)) { static::reportInvalidArgument(\sprintf($message ?: 'Expected a resource. Got: %s', static::typeToString($value))); } if ($type && $type !== \get_resource_type($value)) { static::reportInvalidArgument(\sprintf($message ?: 'Expected a resource of type %2$s. Got: %s', static::typeToString($value), $type)); } } /** * @psalm-pure * @psalm-assert callable $value * * @param mixed $value * @param string $message * * @throws InvalidArgumentException */ public static function isCallable($value, $message = '') { if (!\is_callable($value)) { static::reportInvalidArgument(\sprintf($message ?: 'Expected a callable. Got: %s', static::typeToString($value))); } } /** * @psalm-pure * @psalm-assert array $value * * @param mixed $value * @param string $message * * @throws InvalidArgumentException */ public static function isArray($value, $message = '') { if (!\is_array($value)) { static::reportInvalidArgument(\sprintf($message ?: 'Expected an array. Got: %s', static::typeToString($value))); } } /** * @psalm-pure * @psalm-assert iterable $value * * @deprecated use "isIterable" or "isInstanceOf" instead * * @param mixed $value * @param string $message * * @throws InvalidArgumentException */ public static function isTraversable($value, $message = '') { @\trigger_error(\sprintf('The "%s" assertion is deprecated. You should stop using it, as it will soon be removed in 2.0 version. Use "isIterable" or "isInstanceOf" instead.', __METHOD__), \E_USER_DEPRECATED); if (!\is_array($value) && !$value instanceof Traversable) { static::reportInvalidArgument(\sprintf($message ?: 'Expected a traversable. Got: %s', static::typeToString($value))); } } /** * @psalm-pure * @psalm-assert array|ArrayAccess $value * * @param mixed $value * @param string $message * * @throws InvalidArgumentException */ public static function isArrayAccessible($value, $message = '') { if (!\is_array($value) && !$value instanceof ArrayAccess) { static::reportInvalidArgument(\sprintf($message ?: 'Expected an array accessible. Got: %s', static::typeToString($value))); } } /** * @psalm-pure * @psalm-assert countable $value * * @param mixed $value * @param string $message * * @throws InvalidArgumentException */ public static function isCountable($value, $message = '') { if (!\is_array($value) && !$value instanceof Countable && !$value instanceof ResourceBundle && !$value instanceof SimpleXMLElement) { static::reportInvalidArgument(\sprintf($message ?: 'Expected a countable. Got: %s', static::typeToString($value))); } } /** * @psalm-pure * @psalm-assert iterable $value * * @param mixed $value * @param string $message * * @throws InvalidArgumentException */ public static function isIterable($value, $message = '') { if (!\is_array($value) && !$value instanceof Traversable) { static::reportInvalidArgument(\sprintf($message ?: 'Expected an iterable. Got: %s', static::typeToString($value))); } } /** * @psalm-pure * @psalm-template ExpectedType of object * @psalm-param class-string $class * @psalm-assert ExpectedType $value * * @param mixed $value * @param string|object $class * @param string $message * * @throws InvalidArgumentException */ public static function isInstanceOf($value, $class, $message = '') { if (!$value instanceof $class) { static::reportInvalidArgument(\sprintf($message ?: 'Expected an instance of %2$s. Got: %s', static::typeToString($value), $class)); } } /** * @psalm-pure * @psalm-template ExpectedType of object * @psalm-param class-string $class * @psalm-assert !ExpectedType $value * * @param mixed $value * @param string|object $class * @param string $message * * @throws InvalidArgumentException */ public static function notInstanceOf($value, $class, $message = '') { if ($value instanceof $class) { static::reportInvalidArgument(\sprintf($message ?: 'Expected an instance other than %2$s. Got: %s', static::typeToString($value), $class)); } } /** * @psalm-pure * @psalm-param array $classes * * @param mixed $value * @param array $classes * @param string $message * * @throws InvalidArgumentException */ public static function isInstanceOfAny($value, array $classes, $message = '') { foreach ($classes as $class) { if ($value instanceof $class) { return; } } static::reportInvalidArgument(\sprintf($message ?: 'Expected an instance of any of %2$s. Got: %s', static::typeToString($value), \implode(', ', \array_map(array(static::class, 'valueToString'), $classes)))); } /** * @psalm-pure * @psalm-template ExpectedType of object * @psalm-param class-string $class * @psalm-assert ExpectedType|class-string $value * * @param object|string $value * @param string $class * @param string $message * * @throws InvalidArgumentException */ public static function isAOf($value, $class, $message = '') { static::string($class, 'Expected class as a string. Got: %s'); if (!\is_a($value, $class, \is_string($value))) { static::reportInvalidArgument(\sprintf($message ?: 'Expected an instance of this class or to this class among its parents "%2$s". Got: %s', static::valueToString($value), $class)); } } /** * @psalm-pure * @psalm-template UnexpectedType of object * @psalm-param class-string $class * @psalm-assert !UnexpectedType $value * @psalm-assert !class-string $value * * @param object|string $value * @param string $class * @param string $message * * @throws InvalidArgumentException */ public static function isNotA($value, $class, $message = '') { static::string($class, 'Expected class as a string. Got: %s'); if (\is_a($value, $class, \is_string($value))) { static::reportInvalidArgument(\sprintf($message ?: 'Expected an instance of this class or to this class among its parents other than "%2$s". Got: %s', static::valueToString($value), $class)); } } /** * @psalm-pure * @psalm-param array $classes * * @param object|string $value * @param string[] $classes * @param string $message * * @throws InvalidArgumentException */ public static function isAnyOf($value, array $classes, $message = '') { foreach ($classes as $class) { static::string($class, 'Expected class as a string. Got: %s'); if (\is_a($value, $class, \is_string($value))) { return; } } static::reportInvalidArgument(\sprintf($message ?: 'Expected an instance of any of this classes or any of those classes among their parents "%2$s". Got: %s', static::valueToString($value), \implode(', ', $classes))); } /** * @psalm-pure * @psalm-assert empty $value * * @param mixed $value * @param string $message * * @throws InvalidArgumentException */ public static function isEmpty($value, $message = '') { if (!empty($value)) { static::reportInvalidArgument(\sprintf($message ?: 'Expected an empty value. Got: %s', static::valueToString($value))); } } /** * @psalm-pure * @psalm-assert !empty $value * * @param mixed $value * @param string $message * * @throws InvalidArgumentException */ public static function notEmpty($value, $message = '') { if (empty($value)) { static::reportInvalidArgument(\sprintf($message ?: 'Expected a non-empty value. Got: %s', static::valueToString($value))); } } /** * @psalm-pure * @psalm-assert null $value * * @param mixed $value * @param string $message * * @throws InvalidArgumentException */ public static function null($value, $message = '') { if (null !== $value) { static::reportInvalidArgument(\sprintf($message ?: 'Expected null. Got: %s', static::valueToString($value))); } } /** * @psalm-pure * @psalm-assert !null $value * * @param mixed $value * @param string $message * * @throws InvalidArgumentException */ public static function notNull($value, $message = '') { if (null === $value) { static::reportInvalidArgument($message ?: 'Expected a value other than null.'); } } /** * @psalm-pure * @psalm-assert true $value * * @param mixed $value * @param string $message * * @throws InvalidArgumentException */ public static function true($value, $message = '') { if (\true !== $value) { static::reportInvalidArgument(\sprintf($message ?: 'Expected a value to be true. Got: %s', static::valueToString($value))); } } /** * @psalm-pure * @psalm-assert false $value * * @param mixed $value * @param string $message * * @throws InvalidArgumentException */ public static function false($value, $message = '') { if (\false !== $value) { static::reportInvalidArgument(\sprintf($message ?: 'Expected a value to be false. Got: %s', static::valueToString($value))); } } /** * @psalm-pure * @psalm-assert !false $value * * @param mixed $value * @param string $message * * @throws InvalidArgumentException */ public static function notFalse($value, $message = '') { if (\false === $value) { static::reportInvalidArgument($message ?: 'Expected a value other than false.'); } } /** * @param mixed $value * @param string $message * * @throws InvalidArgumentException */ public static function ip($value, $message = '') { if (\false === \filter_var($value, \FILTER_VALIDATE_IP)) { static::reportInvalidArgument(\sprintf($message ?: 'Expected a value to be an IP. Got: %s', static::valueToString($value))); } } /** * @param mixed $value * @param string $message * * @throws InvalidArgumentException */ public static function ipv4($value, $message = '') { if (\false === \filter_var($value, \FILTER_VALIDATE_IP, \FILTER_FLAG_IPV4)) { static::reportInvalidArgument(\sprintf($message ?: 'Expected a value to be an IPv4. Got: %s', static::valueToString($value))); } } /** * @param mixed $value * @param string $message * * @throws InvalidArgumentException */ public static function ipv6($value, $message = '') { if (\false === \filter_var($value, \FILTER_VALIDATE_IP, \FILTER_FLAG_IPV6)) { static::reportInvalidArgument(\sprintf($message ?: 'Expected a value to be an IPv6. Got: %s', static::valueToString($value))); } } /** * @param mixed $value * @param string $message * * @throws InvalidArgumentException */ public static function email($value, $message = '') { if (\false === \filter_var($value, \FILTER_VALIDATE_EMAIL)) { static::reportInvalidArgument(\sprintf($message ?: 'Expected a value to be a valid e-mail address. Got: %s', static::valueToString($value))); } } /** * Does non strict comparisons on the items, so ['3', 3] will not pass the assertion. * * @param array $values * @param string $message * * @throws InvalidArgumentException */ public static function uniqueValues(array $values, $message = '') { $allValues = \count($values); $uniqueValues = \count(\array_unique($values)); if ($allValues !== $uniqueValues) { $difference = $allValues - $uniqueValues; static::reportInvalidArgument(\sprintf($message ?: 'Expected an array of unique values, but %s of them %s duplicated', $difference, 1 === $difference ? 'is' : 'are')); } } /** * @param mixed $value * @param mixed $expect * @param string $message * * @throws InvalidArgumentException */ public static function eq($value, $expect, $message = '') { if ($expect != $value) { static::reportInvalidArgument(\sprintf($message ?: 'Expected a value equal to %2$s. Got: %s', static::valueToString($value), static::valueToString($expect))); } } /** * @param mixed $value * @param mixed $expect * @param string $message * * @throws InvalidArgumentException */ public static function notEq($value, $expect, $message = '') { if ($expect == $value) { static::reportInvalidArgument(\sprintf($message ?: 'Expected a different value than %s.', static::valueToString($expect))); } } /** * @psalm-pure * * @param mixed $value * @param mixed $expect * @param string $message * * @throws InvalidArgumentException */ public static function same($value, $expect, $message = '') { if ($expect !== $value) { static::reportInvalidArgument(\sprintf($message ?: 'Expected a value identical to %2$s. Got: %s', static::valueToString($value), static::valueToString($expect))); } } /** * @psalm-pure * * @param mixed $value * @param mixed $expect * @param string $message * * @throws InvalidArgumentException */ public static function notSame($value, $expect, $message = '') { if ($expect === $value) { static::reportInvalidArgument(\sprintf($message ?: 'Expected a value not identical to %s.', static::valueToString($expect))); } } /** * @psalm-pure * * @param mixed $value * @param mixed $limit * @param string $message * * @throws InvalidArgumentException */ public static function greaterThan($value, $limit, $message = '') { if ($value <= $limit) { static::reportInvalidArgument(\sprintf($message ?: 'Expected a value greater than %2$s. Got: %s', static::valueToString($value), static::valueToString($limit))); } } /** * @psalm-pure * * @param mixed $value * @param mixed $limit * @param string $message * * @throws InvalidArgumentException */ public static function greaterThanEq($value, $limit, $message = '') { if ($value < $limit) { static::reportInvalidArgument(\sprintf($message ?: 'Expected a value greater than or equal to %2$s. Got: %s', static::valueToString($value), static::valueToString($limit))); } } /** * @psalm-pure * * @param mixed $value * @param mixed $limit * @param string $message * * @throws InvalidArgumentException */ public static function lessThan($value, $limit, $message = '') { if ($value >= $limit) { static::reportInvalidArgument(\sprintf($message ?: 'Expected a value less than %2$s. Got: %s', static::valueToString($value), static::valueToString($limit))); } } /** * @psalm-pure * * @param mixed $value * @param mixed $limit * @param string $message * * @throws InvalidArgumentException */ public static function lessThanEq($value, $limit, $message = '') { if ($value > $limit) { static::reportInvalidArgument(\sprintf($message ?: 'Expected a value less than or equal to %2$s. Got: %s', static::valueToString($value), static::valueToString($limit))); } } /** * Inclusive range, so Assert::(3, 3, 5) passes. * * @psalm-pure * * @param mixed $value * @param mixed $min * @param mixed $max * @param string $message * * @throws InvalidArgumentException */ public static function range($value, $min, $max, $message = '') { if ($value < $min || $value > $max) { static::reportInvalidArgument(\sprintf($message ?: 'Expected a value between %2$s and %3$s. Got: %s', static::valueToString($value), static::valueToString($min), static::valueToString($max))); } } /** * A more human-readable alias of Assert::inArray(). * * @psalm-pure * * @param mixed $value * @param array $values * @param string $message * * @throws InvalidArgumentException */ public static function oneOf($value, array $values, $message = '') { static::inArray($value, $values, $message); } /** * Does strict comparison, so Assert::inArray(3, ['3']) does not pass the assertion. * * @psalm-pure * * @param mixed $value * @param array $values * @param string $message * * @throws InvalidArgumentException */ public static function inArray($value, array $values, $message = '') { if (!\in_array($value, $values, \true)) { static::reportInvalidArgument(\sprintf($message ?: 'Expected one of: %2$s. Got: %s', static::valueToString($value), \implode(', ', \array_map(array(static::class, 'valueToString'), $values)))); } } /** * @psalm-pure * * @param string $value * @param string $subString * @param string $message * * @throws InvalidArgumentException */ public static function contains($value, $subString, $message = '') { if (\false === \strpos($value, $subString)) { static::reportInvalidArgument(\sprintf($message ?: 'Expected a value to contain %2$s. Got: %s', static::valueToString($value), static::valueToString($subString))); } } /** * @psalm-pure * * @param string $value * @param string $subString * @param string $message * * @throws InvalidArgumentException */ public static function notContains($value, $subString, $message = '') { if (\false !== \strpos($value, $subString)) { static::reportInvalidArgument(\sprintf($message ?: '%2$s was not expected to be contained in a value. Got: %s', static::valueToString($value), static::valueToString($subString))); } } /** * @psalm-pure * * @param string $value * @param string $message * * @throws InvalidArgumentException */ public static function notWhitespaceOnly($value, $message = '') { if (\preg_match('/^\\s*$/', $value)) { static::reportInvalidArgument(\sprintf($message ?: 'Expected a non-whitespace string. Got: %s', static::valueToString($value))); } } /** * @psalm-pure * * @param string $value * @param string $prefix * @param string $message * * @throws InvalidArgumentException */ public static function startsWith($value, $prefix, $message = '') { if (0 !== \strpos($value, $prefix)) { static::reportInvalidArgument(\sprintf($message ?: 'Expected a value to start with %2$s. Got: %s', static::valueToString($value), static::valueToString($prefix))); } } /** * @psalm-pure * * @param string $value * @param string $prefix * @param string $message * * @throws InvalidArgumentException */ public static function notStartsWith($value, $prefix, $message = '') { if (0 === \strpos($value, $prefix)) { static::reportInvalidArgument(\sprintf($message ?: 'Expected a value not to start with %2$s. Got: %s', static::valueToString($value), static::valueToString($prefix))); } } /** * @psalm-pure * * @param mixed $value * @param string $message * * @throws InvalidArgumentException */ public static function startsWithLetter($value, $message = '') { static::string($value); $valid = isset($value[0]); if ($valid) { $locale = \setlocale(\LC_CTYPE, 0); \setlocale(\LC_CTYPE, 'C'); $valid = \ctype_alpha($value[0]); \setlocale(\LC_CTYPE, $locale); } if (!$valid) { static::reportInvalidArgument(\sprintf($message ?: 'Expected a value to start with a letter. Got: %s', static::valueToString($value))); } } /** * @psalm-pure * * @param string $value * @param string $suffix * @param string $message * * @throws InvalidArgumentException */ public static function endsWith($value, $suffix, $message = '') { if ($suffix !== \substr($value, -\strlen($suffix))) { static::reportInvalidArgument(\sprintf($message ?: 'Expected a value to end with %2$s. Got: %s', static::valueToString($value), static::valueToString($suffix))); } } /** * @psalm-pure * * @param string $value * @param string $suffix * @param string $message * * @throws InvalidArgumentException */ public static function notEndsWith($value, $suffix, $message = '') { if ($suffix === \substr($value, -\strlen($suffix))) { static::reportInvalidArgument(\sprintf($message ?: 'Expected a value not to end with %2$s. Got: %s', static::valueToString($value), static::valueToString($suffix))); } } /** * @psalm-pure * * @param string $value * @param string $pattern * @param string $message * * @throws InvalidArgumentException */ public static function regex($value, $pattern, $message = '') { if (!\preg_match($pattern, $value)) { static::reportInvalidArgument(\sprintf($message ?: 'The value %s does not match the expected pattern.', static::valueToString($value))); } } /** * @psalm-pure * * @param string $value * @param string $pattern * @param string $message * * @throws InvalidArgumentException */ public static function notRegex($value, $pattern, $message = '') { if (\preg_match($pattern, $value, $matches, \PREG_OFFSET_CAPTURE)) { static::reportInvalidArgument(\sprintf($message ?: 'The value %s matches the pattern %s (at offset %d).', static::valueToString($value), static::valueToString($pattern), $matches[0][1])); } } /** * @psalm-pure * * @param mixed $value * @param string $message * * @throws InvalidArgumentException */ public static function unicodeLetters($value, $message = '') { static::string($value); if (!\preg_match('/^\\p{L}+$/u', $value)) { static::reportInvalidArgument(\sprintf($message ?: 'Expected a value to contain only Unicode letters. Got: %s', static::valueToString($value))); } } /** * @psalm-pure * * @param mixed $value * @param string $message * * @throws InvalidArgumentException */ public static function alpha($value, $message = '') { static::string($value); $locale = \setlocale(\LC_CTYPE, 0); \setlocale(\LC_CTYPE, 'C'); $valid = !\ctype_alpha($value); \setlocale(\LC_CTYPE, $locale); if ($valid) { static::reportInvalidArgument(\sprintf($message ?: 'Expected a value to contain only letters. Got: %s', static::valueToString($value))); } } /** * @psalm-pure * * @param string $value * @param string $message * * @throws InvalidArgumentException */ public static function digits($value, $message = '') { $locale = \setlocale(\LC_CTYPE, 0); \setlocale(\LC_CTYPE, 'C'); $valid = !\ctype_digit($value); \setlocale(\LC_CTYPE, $locale); if ($valid) { static::reportInvalidArgument(\sprintf($message ?: 'Expected a value to contain digits only. Got: %s', static::valueToString($value))); } } /** * @psalm-pure * * @param string $value * @param string $message * * @throws InvalidArgumentException */ public static function alnum($value, $message = '') { $locale = \setlocale(\LC_CTYPE, 0); \setlocale(\LC_CTYPE, 'C'); $valid = !\ctype_alnum($value); \setlocale(\LC_CTYPE, $locale); if ($valid) { static::reportInvalidArgument(\sprintf($message ?: 'Expected a value to contain letters and digits only. Got: %s', static::valueToString($value))); } } /** * @psalm-pure * @psalm-assert lowercase-string $value * * @param string $value * @param string $message * * @throws InvalidArgumentException */ public static function lower($value, $message = '') { $locale = \setlocale(\LC_CTYPE, 0); \setlocale(\LC_CTYPE, 'C'); $valid = !\ctype_lower($value); \setlocale(\LC_CTYPE, $locale); if ($valid) { static::reportInvalidArgument(\sprintf($message ?: 'Expected a value to contain lowercase characters only. Got: %s', static::valueToString($value))); } } /** * @psalm-pure * @psalm-assert !lowercase-string $value * * @param string $value * @param string $message * * @throws InvalidArgumentException */ public static function upper($value, $message = '') { $locale = \setlocale(\LC_CTYPE, 0); \setlocale(\LC_CTYPE, 'C'); $valid = !\ctype_upper($value); \setlocale(\LC_CTYPE, $locale); if ($valid) { static::reportInvalidArgument(\sprintf($message ?: 'Expected a value to contain uppercase characters only. Got: %s', static::valueToString($value))); } } /** * @psalm-pure * * @param string $value * @param int $length * @param string $message * * @throws InvalidArgumentException */ public static function length($value, $length, $message = '') { if ($length !== static::strlen($value)) { static::reportInvalidArgument(\sprintf($message ?: 'Expected a value to contain %2$s characters. Got: %s', static::valueToString($value), $length)); } } /** * Inclusive min. * * @psalm-pure * * @param string $value * @param int|float $min * @param string $message * * @throws InvalidArgumentException */ public static function minLength($value, $min, $message = '') { if (static::strlen($value) < $min) { static::reportInvalidArgument(\sprintf($message ?: 'Expected a value to contain at least %2$s characters. Got: %s', static::valueToString($value), $min)); } } /** * Inclusive max. * * @psalm-pure * * @param string $value * @param int|float $max * @param string $message * * @throws InvalidArgumentException */ public static function maxLength($value, $max, $message = '') { if (static::strlen($value) > $max) { static::reportInvalidArgument(\sprintf($message ?: 'Expected a value to contain at most %2$s characters. Got: %s', static::valueToString($value), $max)); } } /** * Inclusive , so Assert::lengthBetween('asd', 3, 5); passes the assertion. * * @psalm-pure * * @param string $value * @param int|float $min * @param int|float $max * @param string $message * * @throws InvalidArgumentException */ public static function lengthBetween($value, $min, $max, $message = '') { $length = static::strlen($value); if ($length < $min || $length > $max) { static::reportInvalidArgument(\sprintf($message ?: 'Expected a value to contain between %2$s and %3$s characters. Got: %s', static::valueToString($value), $min, $max)); } } /** * Will also pass if $value is a directory, use Assert::file() instead if you need to be sure it is a file. * * @param mixed $value * @param string $message * * @throws InvalidArgumentException */ public static function fileExists($value, $message = '') { static::string($value); if (!\file_exists($value)) { static::reportInvalidArgument(\sprintf($message ?: 'The file %s does not exist.', static::valueToString($value))); } } /** * @param mixed $value * @param string $message * * @throws InvalidArgumentException */ public static function file($value, $message = '') { static::fileExists($value, $message); if (!\is_file($value)) { static::reportInvalidArgument(\sprintf($message ?: 'The path %s is not a file.', static::valueToString($value))); } } /** * @param mixed $value * @param string $message * * @throws InvalidArgumentException */ public static function directory($value, $message = '') { static::fileExists($value, $message); if (!\is_dir($value)) { static::reportInvalidArgument(\sprintf($message ?: 'The path %s is no directory.', static::valueToString($value))); } } /** * @param string $value * @param string $message * * @throws InvalidArgumentException */ public static function readable($value, $message = '') { if (!\is_readable($value)) { static::reportInvalidArgument(\sprintf($message ?: 'The path %s is not readable.', static::valueToString($value))); } } /** * @param string $value * @param string $message * * @throws InvalidArgumentException */ public static function writable($value, $message = '') { if (!\is_writable($value)) { static::reportInvalidArgument(\sprintf($message ?: 'The path %s is not writable.', static::valueToString($value))); } } /** * @psalm-assert class-string $value * * @param mixed $value * @param string $message * * @throws InvalidArgumentException */ public static function classExists($value, $message = '') { if (!\class_exists($value)) { static::reportInvalidArgument(\sprintf($message ?: 'Expected an existing class name. Got: %s', static::valueToString($value))); } } /** * @psalm-pure * @psalm-template ExpectedType of object * @psalm-param class-string $class * @psalm-assert class-string|ExpectedType $value * * @param mixed $value * @param string|object $class * @param string $message * * @throws InvalidArgumentException */ public static function subclassOf($value, $class, $message = '') { if (!\is_subclass_of($value, $class)) { static::reportInvalidArgument(\sprintf($message ?: 'Expected a sub-class of %2$s. Got: %s', static::valueToString($value), static::valueToString($class))); } } /** * @psalm-assert class-string $value * * @param mixed $value * @param string $message * * @throws InvalidArgumentException */ public static function interfaceExists($value, $message = '') { if (!\interface_exists($value)) { static::reportInvalidArgument(\sprintf($message ?: 'Expected an existing interface name. got %s', static::valueToString($value))); } } /** * @psalm-pure * @psalm-template ExpectedType of object * @psalm-param class-string $interface * @psalm-assert class-string $value * * @param mixed $value * @param mixed $interface * @param string $message * * @throws InvalidArgumentException */ public static function implementsInterface($value, $interface, $message = '') { if (!\in_array($interface, \class_implements($value))) { static::reportInvalidArgument(\sprintf($message ?: 'Expected an implementation of %2$s. Got: %s', static::valueToString($value), static::valueToString($interface))); } } /** * @psalm-pure * @psalm-param class-string|object $classOrObject * * @param string|object $classOrObject * @param mixed $property * @param string $message * * @throws InvalidArgumentException */ public static function propertyExists($classOrObject, $property, $message = '') { if (!\property_exists($classOrObject, $property)) { static::reportInvalidArgument(\sprintf($message ?: 'Expected the property %s to exist.', static::valueToString($property))); } } /** * @psalm-pure * @psalm-param class-string|object $classOrObject * * @param string|object $classOrObject * @param mixed $property * @param string $message * * @throws InvalidArgumentException */ public static function propertyNotExists($classOrObject, $property, $message = '') { if (\property_exists($classOrObject, $property)) { static::reportInvalidArgument(\sprintf($message ?: 'Expected the property %s to not exist.', static::valueToString($property))); } } /** * @psalm-pure * @psalm-param class-string|object $classOrObject * * @param string|object $classOrObject * @param mixed $method * @param string $message * * @throws InvalidArgumentException */ public static function methodExists($classOrObject, $method, $message = '') { if (!(\is_string($classOrObject) || \is_object($classOrObject)) || !\method_exists($classOrObject, $method)) { static::reportInvalidArgument(\sprintf($message ?: 'Expected the method %s to exist.', static::valueToString($method))); } } /** * @psalm-pure * @psalm-param class-string|object $classOrObject * * @param string|object $classOrObject * @param mixed $method * @param string $message * * @throws InvalidArgumentException */ public static function methodNotExists($classOrObject, $method, $message = '') { if ((\is_string($classOrObject) || \is_object($classOrObject)) && \method_exists($classOrObject, $method)) { static::reportInvalidArgument(\sprintf($message ?: 'Expected the method %s to not exist.', static::valueToString($method))); } } /** * @psalm-pure * * @param array $array * @param string|int $key * @param string $message * * @throws InvalidArgumentException */ public static function keyExists($array, $key, $message = '') { if (!(isset($array[$key]) || \array_key_exists($key, $array))) { static::reportInvalidArgument(\sprintf($message ?: 'Expected the key %s to exist.', static::valueToString($key))); } } /** * @psalm-pure * * @param array $array * @param string|int $key * @param string $message * * @throws InvalidArgumentException */ public static function keyNotExists($array, $key, $message = '') { if (isset($array[$key]) || \array_key_exists($key, $array)) { static::reportInvalidArgument(\sprintf($message ?: 'Expected the key %s to not exist.', static::valueToString($key))); } } /** * Checks if a value is a valid array key (int or string). * * @psalm-pure * @psalm-assert array-key $value * * @param mixed $value * @param string $message * * @throws InvalidArgumentException */ public static function validArrayKey($value, $message = '') { if (!(\is_int($value) || \is_string($value))) { static::reportInvalidArgument(\sprintf($message ?: 'Expected string or integer. Got: %s', static::typeToString($value))); } } /** * Does not check if $array is countable, this can generate a warning on php versions after 7.2. * * @param Countable|array $array * @param int $number * @param string $message * * @throws InvalidArgumentException */ public static function count($array, $number, $message = '') { static::eq(\count($array), $number, \sprintf($message ?: 'Expected an array to contain %d elements. Got: %d.', $number, \count($array))); } /** * Does not check if $array is countable, this can generate a warning on php versions after 7.2. * * @param Countable|array $array * @param int|float $min * @param string $message * * @throws InvalidArgumentException */ public static function minCount($array, $min, $message = '') { if (\count($array) < $min) { static::reportInvalidArgument(\sprintf($message ?: 'Expected an array to contain at least %2$d elements. Got: %d', \count($array), $min)); } } /** * Does not check if $array is countable, this can generate a warning on php versions after 7.2. * * @param Countable|array $array * @param int|float $max * @param string $message * * @throws InvalidArgumentException */ public static function maxCount($array, $max, $message = '') { if (\count($array) > $max) { static::reportInvalidArgument(\sprintf($message ?: 'Expected an array to contain at most %2$d elements. Got: %d', \count($array), $max)); } } /** * Does not check if $array is countable, this can generate a warning on php versions after 7.2. * * @param Countable|array $array * @param int|float $min * @param int|float $max * @param string $message * * @throws InvalidArgumentException */ public static function countBetween($array, $min, $max, $message = '') { $count = \count($array); if ($count < $min || $count > $max) { static::reportInvalidArgument(\sprintf($message ?: 'Expected an array to contain between %2$d and %3$d elements. Got: %d', $count, $min, $max)); } } /** * @psalm-pure * @psalm-assert list $array * * @param mixed $array * @param string $message * * @throws InvalidArgumentException */ public static function isList($array, $message = '') { if (!\is_array($array)) { static::reportInvalidArgument($message ?: 'Expected list - non-associative array.'); } if ($array === \array_values($array)) { return; } $nextKey = -1; foreach ($array as $k => $v) { if ($k !== ++$nextKey) { static::reportInvalidArgument($message ?: 'Expected list - non-associative array.'); } } } /** * @psalm-pure * @psalm-assert non-empty-list $array * * @param mixed $array * @param string $message * * @throws InvalidArgumentException */ public static function isNonEmptyList($array, $message = '') { static::isList($array, $message); static::notEmpty($array, $message); } /** * @psalm-pure * @psalm-template T * @psalm-param mixed|array $array * @psalm-assert array $array * * @param mixed $array * @param string $message * * @throws InvalidArgumentException */ public static function isMap($array, $message = '') { if (!\is_array($array) || \array_keys($array) !== \array_filter(\array_keys($array), '\\is_string')) { static::reportInvalidArgument($message ?: 'Expected map - associative array with string keys.'); } } /** * @psalm-pure * @psalm-template T * @psalm-param mixed|array $array * @psalm-assert array $array * @psalm-assert !empty $array * * @param mixed $array * @param string $message * * @throws InvalidArgumentException */ public static function isNonEmptyMap($array, $message = '') { static::isMap($array, $message); static::notEmpty($array, $message); } /** * @psalm-pure * * @param string $value * @param string $message * * @throws InvalidArgumentException */ public static function uuid($value, $message = '') { $value = \str_replace(array('urn:', 'uuid:', '{', '}'), '', $value); // The nil UUID is special form of UUID that is specified to have all // 128 bits set to zero. if ('00000000-0000-0000-0000-000000000000' === $value) { return; } if (!\preg_match('/^[0-9A-Fa-f]{8}-[0-9A-Fa-f]{4}-[0-9A-Fa-f]{4}-[0-9A-Fa-f]{4}-[0-9A-Fa-f]{12}$/', $value)) { static::reportInvalidArgument(\sprintf($message ?: 'Value %s is not a valid UUID.', static::valueToString($value))); } } /** * @psalm-param class-string $class * * @param Closure $expression * @param string $class * @param string $message * * @throws InvalidArgumentException */ public static function throws(Closure $expression, $class = 'Exception', $message = '') { static::string($class); $actual = 'none'; try { $expression(); } catch (Exception $e) { $actual = \get_class($e); if ($e instanceof $class) { return; } } catch (Throwable $e) { $actual = \get_class($e); if ($e instanceof $class) { return; } } static::reportInvalidArgument($message ?: \sprintf('Expected to throw "%s", got "%s"', $class, $actual)); } /** * @throws BadMethodCallException */ public static function __callStatic($name, $arguments) { if ('nullOr' === \substr($name, 0, 6)) { if (null !== $arguments[0]) { $method = \lcfirst(\substr($name, 6)); \call_user_func_array(array(static::class, $method), $arguments); } return; } if ('all' === \substr($name, 0, 3)) { static::isIterable($arguments[0]); $method = \lcfirst(\substr($name, 3)); $args = $arguments; foreach ($arguments[0] as $entry) { $args[0] = $entry; \call_user_func_array(array(static::class, $method), $args); } return; } throw new BadMethodCallException('No such method: ' . $name); } /** * @param mixed $value * * @return string */ protected static function valueToString($value) { if (null === $value) { return 'null'; } if (\true === $value) { return 'true'; } if (\false === $value) { return 'false'; } if (\is_array($value)) { return 'array'; } if (\is_object($value)) { if (\method_exists($value, '__toString')) { return \get_class($value) . ': ' . self::valueToString($value->__toString()); } if ($value instanceof DateTime || $value instanceof DateTimeImmutable) { return \get_class($value) . ': ' . self::valueToString($value->format('c')); } return \get_class($value); } if (\is_resource($value)) { return 'resource'; } if (\is_string($value)) { return '"' . $value . '"'; } return (string) $value; } /** * @param mixed $value * * @return string */ protected static function typeToString($value) { return \is_object($value) ? \get_class($value) : \gettype($value); } protected static function strlen($value) { if (!\function_exists('mb_detect_encoding')) { return \strlen($value); } if (\false === ($encoding = \mb_detect_encoding($value))) { return \strlen($value); } return \mb_strlen($value, $encoding); } /** * @param string $message * * @throws InvalidArgumentException * * @psalm-pure this method is not supposed to perform side-effects * @psalm-return never */ protected static function reportInvalidArgument($message) { throw new InvalidArgumentException($message); } private function __construct() { } } $value * * @param mixed $value * @param string $message * * @throws InvalidArgumentException * * @return void */ public static function allString($value, $message = '') { static::isIterable($value); foreach ($value as $entry) { static::string($entry, $message); } } /** * @psalm-pure * @psalm-assert iterable $value * * @param mixed $value * @param string $message * * @throws InvalidArgumentException * * @return void */ public static function allNullOrString($value, $message = '') { static::isIterable($value); foreach ($value as $entry) { null === $entry || static::string($entry, $message); } } /** * @psalm-pure * @psalm-assert non-empty-string|null $value * * @param mixed $value * @param string $message * * @throws InvalidArgumentException * * @return void */ public static function nullOrStringNotEmpty($value, $message = '') { null === $value || static::stringNotEmpty($value, $message); } /** * @psalm-pure * @psalm-assert iterable $value * * @param mixed $value * @param string $message * * @throws InvalidArgumentException * * @return void */ public static function allStringNotEmpty($value, $message = '') { static::isIterable($value); foreach ($value as $entry) { static::stringNotEmpty($entry, $message); } } /** * @psalm-pure * @psalm-assert iterable $value * * @param mixed $value * @param string $message * * @throws InvalidArgumentException * * @return void */ public static function allNullOrStringNotEmpty($value, $message = '') { static::isIterable($value); foreach ($value as $entry) { null === $entry || static::stringNotEmpty($entry, $message); } } /** * @psalm-pure * @psalm-assert int|null $value * * @param mixed $value * @param string $message * * @throws InvalidArgumentException * * @return void */ public static function nullOrInteger($value, $message = '') { null === $value || static::integer($value, $message); } /** * @psalm-pure * @psalm-assert iterable $value * * @param mixed $value * @param string $message * * @throws InvalidArgumentException * * @return void */ public static function allInteger($value, $message = '') { static::isIterable($value); foreach ($value as $entry) { static::integer($entry, $message); } } /** * @psalm-pure * @psalm-assert iterable $value * * @param mixed $value * @param string $message * * @throws InvalidArgumentException * * @return void */ public static function allNullOrInteger($value, $message = '') { static::isIterable($value); foreach ($value as $entry) { null === $entry || static::integer($entry, $message); } } /** * @psalm-pure * @psalm-assert numeric|null $value * * @param mixed $value * @param string $message * * @throws InvalidArgumentException * * @return void */ public static function nullOrIntegerish($value, $message = '') { null === $value || static::integerish($value, $message); } /** * @psalm-pure * @psalm-assert iterable $value * * @param mixed $value * @param string $message * * @throws InvalidArgumentException * * @return void */ public static function allIntegerish($value, $message = '') { static::isIterable($value); foreach ($value as $entry) { static::integerish($entry, $message); } } /** * @psalm-pure * @psalm-assert iterable $value * * @param mixed $value * @param string $message * * @throws InvalidArgumentException * * @return void */ public static function allNullOrIntegerish($value, $message = '') { static::isIterable($value); foreach ($value as $entry) { null === $entry || static::integerish($entry, $message); } } /** * @psalm-pure * @psalm-assert positive-int|null $value * * @param mixed $value * @param string $message * * @throws InvalidArgumentException * * @return void */ public static function nullOrPositiveInteger($value, $message = '') { null === $value || static::positiveInteger($value, $message); } /** * @psalm-pure * @psalm-assert iterable $value * * @param mixed $value * @param string $message * * @throws InvalidArgumentException * * @return void */ public static function allPositiveInteger($value, $message = '') { static::isIterable($value); foreach ($value as $entry) { static::positiveInteger($entry, $message); } } /** * @psalm-pure * @psalm-assert iterable $value * * @param mixed $value * @param string $message * * @throws InvalidArgumentException * * @return void */ public static function allNullOrPositiveInteger($value, $message = '') { static::isIterable($value); foreach ($value as $entry) { null === $entry || static::positiveInteger($entry, $message); } } /** * @psalm-pure * @psalm-assert float|null $value * * @param mixed $value * @param string $message * * @throws InvalidArgumentException * * @return void */ public static function nullOrFloat($value, $message = '') { null === $value || static::float($value, $message); } /** * @psalm-pure * @psalm-assert iterable $value * * @param mixed $value * @param string $message * * @throws InvalidArgumentException * * @return void */ public static function allFloat($value, $message = '') { static::isIterable($value); foreach ($value as $entry) { static::float($entry, $message); } } /** * @psalm-pure * @psalm-assert iterable $value * * @param mixed $value * @param string $message * * @throws InvalidArgumentException * * @return void */ public static function allNullOrFloat($value, $message = '') { static::isIterable($value); foreach ($value as $entry) { null === $entry || static::float($entry, $message); } } /** * @psalm-pure * @psalm-assert numeric|null $value * * @param mixed $value * @param string $message * * @throws InvalidArgumentException * * @return void */ public static function nullOrNumeric($value, $message = '') { null === $value || static::numeric($value, $message); } /** * @psalm-pure * @psalm-assert iterable $value * * @param mixed $value * @param string $message * * @throws InvalidArgumentException * * @return void */ public static function allNumeric($value, $message = '') { static::isIterable($value); foreach ($value as $entry) { static::numeric($entry, $message); } } /** * @psalm-pure * @psalm-assert iterable $value * * @param mixed $value * @param string $message * * @throws InvalidArgumentException * * @return void */ public static function allNullOrNumeric($value, $message = '') { static::isIterable($value); foreach ($value as $entry) { null === $entry || static::numeric($entry, $message); } } /** * @psalm-pure * @psalm-assert positive-int|0|null $value * * @param mixed $value * @param string $message * * @throws InvalidArgumentException * * @return void */ public static function nullOrNatural($value, $message = '') { null === $value || static::natural($value, $message); } /** * @psalm-pure * @psalm-assert iterable $value * * @param mixed $value * @param string $message * * @throws InvalidArgumentException * * @return void */ public static function allNatural($value, $message = '') { static::isIterable($value); foreach ($value as $entry) { static::natural($entry, $message); } } /** * @psalm-pure * @psalm-assert iterable $value * * @param mixed $value * @param string $message * * @throws InvalidArgumentException * * @return void */ public static function allNullOrNatural($value, $message = '') { static::isIterable($value); foreach ($value as $entry) { null === $entry || static::natural($entry, $message); } } /** * @psalm-pure * @psalm-assert bool|null $value * * @param mixed $value * @param string $message * * @throws InvalidArgumentException * * @return void */ public static function nullOrBoolean($value, $message = '') { null === $value || static::boolean($value, $message); } /** * @psalm-pure * @psalm-assert iterable $value * * @param mixed $value * @param string $message * * @throws InvalidArgumentException * * @return void */ public static function allBoolean($value, $message = '') { static::isIterable($value); foreach ($value as $entry) { static::boolean($entry, $message); } } /** * @psalm-pure * @psalm-assert iterable $value * * @param mixed $value * @param string $message * * @throws InvalidArgumentException * * @return void */ public static function allNullOrBoolean($value, $message = '') { static::isIterable($value); foreach ($value as $entry) { null === $entry || static::boolean($entry, $message); } } /** * @psalm-pure * @psalm-assert scalar|null $value * * @param mixed $value * @param string $message * * @throws InvalidArgumentException * * @return void */ public static function nullOrScalar($value, $message = '') { null === $value || static::scalar($value, $message); } /** * @psalm-pure * @psalm-assert iterable $value * * @param mixed $value * @param string $message * * @throws InvalidArgumentException * * @return void */ public static function allScalar($value, $message = '') { static::isIterable($value); foreach ($value as $entry) { static::scalar($entry, $message); } } /** * @psalm-pure * @psalm-assert iterable $value * * @param mixed $value * @param string $message * * @throws InvalidArgumentException * * @return void */ public static function allNullOrScalar($value, $message = '') { static::isIterable($value); foreach ($value as $entry) { null === $entry || static::scalar($entry, $message); } } /** * @psalm-pure * @psalm-assert object|null $value * * @param mixed $value * @param string $message * * @throws InvalidArgumentException * * @return void */ public static function nullOrObject($value, $message = '') { null === $value || static::object($value, $message); } /** * @psalm-pure * @psalm-assert iterable $value * * @param mixed $value * @param string $message * * @throws InvalidArgumentException * * @return void */ public static function allObject($value, $message = '') { static::isIterable($value); foreach ($value as $entry) { static::object($entry, $message); } } /** * @psalm-pure * @psalm-assert iterable $value * * @param mixed $value * @param string $message * * @throws InvalidArgumentException * * @return void */ public static function allNullOrObject($value, $message = '') { static::isIterable($value); foreach ($value as $entry) { null === $entry || static::object($entry, $message); } } /** * @psalm-pure * @psalm-assert resource|null $value * * @param mixed $value * @param string|null $type type of resource this should be. @see https://www.php.net/manual/en/function.get-resource-type.php * @param string $message * * @throws InvalidArgumentException * * @return void */ public static function nullOrResource($value, $type = null, $message = '') { null === $value || static::resource($value, $type, $message); } /** * @psalm-pure * @psalm-assert iterable $value * * @param mixed $value * @param string|null $type type of resource this should be. @see https://www.php.net/manual/en/function.get-resource-type.php * @param string $message * * @throws InvalidArgumentException * * @return void */ public static function allResource($value, $type = null, $message = '') { static::isIterable($value); foreach ($value as $entry) { static::resource($entry, $type, $message); } } /** * @psalm-pure * @psalm-assert iterable $value * * @param mixed $value * @param string|null $type type of resource this should be. @see https://www.php.net/manual/en/function.get-resource-type.php * @param string $message * * @throws InvalidArgumentException * * @return void */ public static function allNullOrResource($value, $type = null, $message = '') { static::isIterable($value); foreach ($value as $entry) { null === $entry || static::resource($entry, $type, $message); } } /** * @psalm-pure * @psalm-assert callable|null $value * * @param mixed $value * @param string $message * * @throws InvalidArgumentException * * @return void */ public static function nullOrIsCallable($value, $message = '') { null === $value || static::isCallable($value, $message); } /** * @psalm-pure * @psalm-assert iterable $value * * @param mixed $value * @param string $message * * @throws InvalidArgumentException * * @return void */ public static function allIsCallable($value, $message = '') { static::isIterable($value); foreach ($value as $entry) { static::isCallable($entry, $message); } } /** * @psalm-pure * @psalm-assert iterable $value * * @param mixed $value * @param string $message * * @throws InvalidArgumentException * * @return void */ public static function allNullOrIsCallable($value, $message = '') { static::isIterable($value); foreach ($value as $entry) { null === $entry || static::isCallable($entry, $message); } } /** * @psalm-pure * @psalm-assert array|null $value * * @param mixed $value * @param string $message * * @throws InvalidArgumentException * * @return void */ public static function nullOrIsArray($value, $message = '') { null === $value || static::isArray($value, $message); } /** * @psalm-pure * @psalm-assert iterable $value * * @param mixed $value * @param string $message * * @throws InvalidArgumentException * * @return void */ public static function allIsArray($value, $message = '') { static::isIterable($value); foreach ($value as $entry) { static::isArray($entry, $message); } } /** * @psalm-pure * @psalm-assert iterable $value * * @param mixed $value * @param string $message * * @throws InvalidArgumentException * * @return void */ public static function allNullOrIsArray($value, $message = '') { static::isIterable($value); foreach ($value as $entry) { null === $entry || static::isArray($entry, $message); } } /** * @psalm-pure * @psalm-assert iterable|null $value * * @deprecated use "isIterable" or "isInstanceOf" instead * * @param mixed $value * @param string $message * * @throws InvalidArgumentException * * @return void */ public static function nullOrIsTraversable($value, $message = '') { null === $value || static::isTraversable($value, $message); } /** * @psalm-pure * @psalm-assert iterable $value * * @deprecated use "isIterable" or "isInstanceOf" instead * * @param mixed $value * @param string $message * * @throws InvalidArgumentException * * @return void */ public static function allIsTraversable($value, $message = '') { static::isIterable($value); foreach ($value as $entry) { static::isTraversable($entry, $message); } } /** * @psalm-pure * @psalm-assert iterable $value * * @deprecated use "isIterable" or "isInstanceOf" instead * * @param mixed $value * @param string $message * * @throws InvalidArgumentException * * @return void */ public static function allNullOrIsTraversable($value, $message = '') { static::isIterable($value); foreach ($value as $entry) { null === $entry || static::isTraversable($entry, $message); } } /** * @psalm-pure * @psalm-assert array|ArrayAccess|null $value * * @param mixed $value * @param string $message * * @throws InvalidArgumentException * * @return void */ public static function nullOrIsArrayAccessible($value, $message = '') { null === $value || static::isArrayAccessible($value, $message); } /** * @psalm-pure * @psalm-assert iterable $value * * @param mixed $value * @param string $message * * @throws InvalidArgumentException * * @return void */ public static function allIsArrayAccessible($value, $message = '') { static::isIterable($value); foreach ($value as $entry) { static::isArrayAccessible($entry, $message); } } /** * @psalm-pure * @psalm-assert iterable $value * * @param mixed $value * @param string $message * * @throws InvalidArgumentException * * @return void */ public static function allNullOrIsArrayAccessible($value, $message = '') { static::isIterable($value); foreach ($value as $entry) { null === $entry || static::isArrayAccessible($entry, $message); } } /** * @psalm-pure * @psalm-assert countable|null $value * * @param mixed $value * @param string $message * * @throws InvalidArgumentException * * @return void */ public static function nullOrIsCountable($value, $message = '') { null === $value || static::isCountable($value, $message); } /** * @psalm-pure * @psalm-assert iterable $value * * @param mixed $value * @param string $message * * @throws InvalidArgumentException * * @return void */ public static function allIsCountable($value, $message = '') { static::isIterable($value); foreach ($value as $entry) { static::isCountable($entry, $message); } } /** * @psalm-pure * @psalm-assert iterable $value * * @param mixed $value * @param string $message * * @throws InvalidArgumentException * * @return void */ public static function allNullOrIsCountable($value, $message = '') { static::isIterable($value); foreach ($value as $entry) { null === $entry || static::isCountable($entry, $message); } } /** * @psalm-pure * @psalm-assert iterable|null $value * * @param mixed $value * @param string $message * * @throws InvalidArgumentException * * @return void */ public static function nullOrIsIterable($value, $message = '') { null === $value || static::isIterable($value, $message); } /** * @psalm-pure * @psalm-assert iterable $value * * @param mixed $value * @param string $message * * @throws InvalidArgumentException * * @return void */ public static function allIsIterable($value, $message = '') { static::isIterable($value); foreach ($value as $entry) { static::isIterable($entry, $message); } } /** * @psalm-pure * @psalm-assert iterable $value * * @param mixed $value * @param string $message * * @throws InvalidArgumentException * * @return void */ public static function allNullOrIsIterable($value, $message = '') { static::isIterable($value); foreach ($value as $entry) { null === $entry || static::isIterable($entry, $message); } } /** * @psalm-pure * @psalm-template ExpectedType of object * @psalm-param class-string $class * @psalm-assert ExpectedType|null $value * * @param mixed $value * @param string|object $class * @param string $message * * @throws InvalidArgumentException * * @return void */ public static function nullOrIsInstanceOf($value, $class, $message = '') { null === $value || static::isInstanceOf($value, $class, $message); } /** * @psalm-pure * @psalm-template ExpectedType of object * @psalm-param class-string $class * @psalm-assert iterable $value * * @param mixed $value * @param string|object $class * @param string $message * * @throws InvalidArgumentException * * @return void */ public static function allIsInstanceOf($value, $class, $message = '') { static::isIterable($value); foreach ($value as $entry) { static::isInstanceOf($entry, $class, $message); } } /** * @psalm-pure * @psalm-template ExpectedType of object * @psalm-param class-string $class * @psalm-assert iterable $value * * @param mixed $value * @param string|object $class * @param string $message * * @throws InvalidArgumentException * * @return void */ public static function allNullOrIsInstanceOf($value, $class, $message = '') { static::isIterable($value); foreach ($value as $entry) { null === $entry || static::isInstanceOf($entry, $class, $message); } } /** * @psalm-pure * @psalm-template ExpectedType of object * @psalm-param class-string $class * * @param mixed $value * @param string|object $class * @param string $message * * @throws InvalidArgumentException * * @return void */ public static function nullOrNotInstanceOf($value, $class, $message = '') { null === $value || static::notInstanceOf($value, $class, $message); } /** * @psalm-pure * @psalm-template ExpectedType of object * @psalm-param class-string $class * * @param mixed $value * @param string|object $class * @param string $message * * @throws InvalidArgumentException * * @return void */ public static function allNotInstanceOf($value, $class, $message = '') { static::isIterable($value); foreach ($value as $entry) { static::notInstanceOf($entry, $class, $message); } } /** * @psalm-pure * @psalm-template ExpectedType of object * @psalm-param class-string $class * @psalm-assert iterable $value * * @param mixed $value * @param string|object $class * @param string $message * * @throws InvalidArgumentException * * @return void */ public static function allNullOrNotInstanceOf($value, $class, $message = '') { static::isIterable($value); foreach ($value as $entry) { null === $entry || static::notInstanceOf($entry, $class, $message); } } /** * @psalm-pure * @psalm-param array $classes * * @param mixed $value * @param array $classes * @param string $message * * @throws InvalidArgumentException * * @return void */ public static function nullOrIsInstanceOfAny($value, $classes, $message = '') { null === $value || static::isInstanceOfAny($value, $classes, $message); } /** * @psalm-pure * @psalm-param array $classes * * @param mixed $value * @param array $classes * @param string $message * * @throws InvalidArgumentException * * @return void */ public static function allIsInstanceOfAny($value, $classes, $message = '') { static::isIterable($value); foreach ($value as $entry) { static::isInstanceOfAny($entry, $classes, $message); } } /** * @psalm-pure * @psalm-param array $classes * * @param mixed $value * @param array $classes * @param string $message * * @throws InvalidArgumentException * * @return void */ public static function allNullOrIsInstanceOfAny($value, $classes, $message = '') { static::isIterable($value); foreach ($value as $entry) { null === $entry || static::isInstanceOfAny($entry, $classes, $message); } } /** * @psalm-pure * @psalm-template ExpectedType of object * @psalm-param class-string $class * @psalm-assert ExpectedType|class-string|null $value * * @param object|string|null $value * @param string $class * @param string $message * * @throws InvalidArgumentException * * @return void */ public static function nullOrIsAOf($value, $class, $message = '') { null === $value || static::isAOf($value, $class, $message); } /** * @psalm-pure * @psalm-template ExpectedType of object * @psalm-param class-string $class * @psalm-assert iterable> $value * * @param iterable $value * @param string $class * @param string $message * * @throws InvalidArgumentException * * @return void */ public static function allIsAOf($value, $class, $message = '') { static::isIterable($value); foreach ($value as $entry) { static::isAOf($entry, $class, $message); } } /** * @psalm-pure * @psalm-template ExpectedType of object * @psalm-param class-string $class * @psalm-assert iterable|null> $value * * @param iterable $value * @param string $class * @param string $message * * @throws InvalidArgumentException * * @return void */ public static function allNullOrIsAOf($value, $class, $message = '') { static::isIterable($value); foreach ($value as $entry) { null === $entry || static::isAOf($entry, $class, $message); } } /** * @psalm-pure * @psalm-template UnexpectedType of object * @psalm-param class-string $class * * @param object|string|null $value * @param string $class * @param string $message * * @throws InvalidArgumentException * * @return void */ public static function nullOrIsNotA($value, $class, $message = '') { null === $value || static::isNotA($value, $class, $message); } /** * @psalm-pure * @psalm-template UnexpectedType of object * @psalm-param class-string $class * * @param iterable $value * @param string $class * @param string $message * * @throws InvalidArgumentException * * @return void */ public static function allIsNotA($value, $class, $message = '') { static::isIterable($value); foreach ($value as $entry) { static::isNotA($entry, $class, $message); } } /** * @psalm-pure * @psalm-template UnexpectedType of object * @psalm-param class-string $class * @psalm-assert iterable $value * @psalm-assert iterable|null> $value * * @param iterable $value * @param string $class * @param string $message * * @throws InvalidArgumentException * * @return void */ public static function allNullOrIsNotA($value, $class, $message = '') { static::isIterable($value); foreach ($value as $entry) { null === $entry || static::isNotA($entry, $class, $message); } } /** * @psalm-pure * @psalm-param array $classes * * @param object|string|null $value * @param string[] $classes * @param string $message * * @throws InvalidArgumentException * * @return void */ public static function nullOrIsAnyOf($value, $classes, $message = '') { null === $value || static::isAnyOf($value, $classes, $message); } /** * @psalm-pure * @psalm-param array $classes * * @param iterable $value * @param string[] $classes * @param string $message * * @throws InvalidArgumentException * * @return void */ public static function allIsAnyOf($value, $classes, $message = '') { static::isIterable($value); foreach ($value as $entry) { static::isAnyOf($entry, $classes, $message); } } /** * @psalm-pure * @psalm-param array $classes * * @param iterable $value * @param string[] $classes * @param string $message * * @throws InvalidArgumentException * * @return void */ public static function allNullOrIsAnyOf($value, $classes, $message = '') { static::isIterable($value); foreach ($value as $entry) { null === $entry || static::isAnyOf($entry, $classes, $message); } } /** * @psalm-pure * @psalm-assert empty $value * * @param mixed $value * @param string $message * * @throws InvalidArgumentException * * @return void */ public static function nullOrIsEmpty($value, $message = '') { null === $value || static::isEmpty($value, $message); } /** * @psalm-pure * @psalm-assert iterable $value * * @param mixed $value * @param string $message * * @throws InvalidArgumentException * * @return void */ public static function allIsEmpty($value, $message = '') { static::isIterable($value); foreach ($value as $entry) { static::isEmpty($entry, $message); } } /** * @psalm-pure * @psalm-assert iterable $value * * @param mixed $value * @param string $message * * @throws InvalidArgumentException * * @return void */ public static function allNullOrIsEmpty($value, $message = '') { static::isIterable($value); foreach ($value as $entry) { null === $entry || static::isEmpty($entry, $message); } } /** * @psalm-pure * * @param mixed $value * @param string $message * * @throws InvalidArgumentException * * @return void */ public static function nullOrNotEmpty($value, $message = '') { null === $value || static::notEmpty($value, $message); } /** * @psalm-pure * * @param mixed $value * @param string $message * * @throws InvalidArgumentException * * @return void */ public static function allNotEmpty($value, $message = '') { static::isIterable($value); foreach ($value as $entry) { static::notEmpty($entry, $message); } } /** * @psalm-pure * @psalm-assert iterable $value * * @param mixed $value * @param string $message * * @throws InvalidArgumentException * * @return void */ public static function allNullOrNotEmpty($value, $message = '') { static::isIterable($value); foreach ($value as $entry) { null === $entry || static::notEmpty($entry, $message); } } /** * @psalm-pure * @psalm-assert iterable $value * * @param mixed $value * @param string $message * * @throws InvalidArgumentException * * @return void */ public static function allNull($value, $message = '') { static::isIterable($value); foreach ($value as $entry) { static::null($entry, $message); } } /** * @psalm-pure * * @param mixed $value * @param string $message * * @throws InvalidArgumentException * * @return void */ public static function allNotNull($value, $message = '') { static::isIterable($value); foreach ($value as $entry) { static::notNull($entry, $message); } } /** * @psalm-pure * @psalm-assert true|null $value * * @param mixed $value * @param string $message * * @throws InvalidArgumentException * * @return void */ public static function nullOrTrue($value, $message = '') { null === $value || static::true($value, $message); } /** * @psalm-pure * @psalm-assert iterable $value * * @param mixed $value * @param string $message * * @throws InvalidArgumentException * * @return void */ public static function allTrue($value, $message = '') { static::isIterable($value); foreach ($value as $entry) { static::true($entry, $message); } } /** * @psalm-pure * @psalm-assert iterable $value * * @param mixed $value * @param string $message * * @throws InvalidArgumentException * * @return void */ public static function allNullOrTrue($value, $message = '') { static::isIterable($value); foreach ($value as $entry) { null === $entry || static::true($entry, $message); } } /** * @psalm-pure * @psalm-assert false|null $value * * @param mixed $value * @param string $message * * @throws InvalidArgumentException * * @return void */ public static function nullOrFalse($value, $message = '') { null === $value || static::false($value, $message); } /** * @psalm-pure * @psalm-assert iterable $value * * @param mixed $value * @param string $message * * @throws InvalidArgumentException * * @return void */ public static function allFalse($value, $message = '') { static::isIterable($value); foreach ($value as $entry) { static::false($entry, $message); } } /** * @psalm-pure * @psalm-assert iterable $value * * @param mixed $value * @param string $message * * @throws InvalidArgumentException * * @return void */ public static function allNullOrFalse($value, $message = '') { static::isIterable($value); foreach ($value as $entry) { null === $entry || static::false($entry, $message); } } /** * @psalm-pure * * @param mixed $value * @param string $message * * @throws InvalidArgumentException * * @return void */ public static function nullOrNotFalse($value, $message = '') { null === $value || static::notFalse($value, $message); } /** * @psalm-pure * * @param mixed $value * @param string $message * * @throws InvalidArgumentException * * @return void */ public static function allNotFalse($value, $message = '') { static::isIterable($value); foreach ($value as $entry) { static::notFalse($entry, $message); } } /** * @psalm-pure * @psalm-assert iterable $value * * @param mixed $value * @param string $message * * @throws InvalidArgumentException * * @return void */ public static function allNullOrNotFalse($value, $message = '') { static::isIterable($value); foreach ($value as $entry) { null === $entry || static::notFalse($entry, $message); } } /** * @param mixed $value * @param string $message * * @throws InvalidArgumentException * * @return void */ public static function nullOrIp($value, $message = '') { null === $value || static::ip($value, $message); } /** * @param mixed $value * @param string $message * * @throws InvalidArgumentException * * @return void */ public static function allIp($value, $message = '') { static::isIterable($value); foreach ($value as $entry) { static::ip($entry, $message); } } /** * @param mixed $value * @param string $message * * @throws InvalidArgumentException * * @return void */ public static function allNullOrIp($value, $message = '') { static::isIterable($value); foreach ($value as $entry) { null === $entry || static::ip($entry, $message); } } /** * @param mixed $value * @param string $message * * @throws InvalidArgumentException * * @return void */ public static function nullOrIpv4($value, $message = '') { null === $value || static::ipv4($value, $message); } /** * @param mixed $value * @param string $message * * @throws InvalidArgumentException * * @return void */ public static function allIpv4($value, $message = '') { static::isIterable($value); foreach ($value as $entry) { static::ipv4($entry, $message); } } /** * @param mixed $value * @param string $message * * @throws InvalidArgumentException * * @return void */ public static function allNullOrIpv4($value, $message = '') { static::isIterable($value); foreach ($value as $entry) { null === $entry || static::ipv4($entry, $message); } } /** * @param mixed $value * @param string $message * * @throws InvalidArgumentException * * @return void */ public static function nullOrIpv6($value, $message = '') { null === $value || static::ipv6($value, $message); } /** * @param mixed $value * @param string $message * * @throws InvalidArgumentException * * @return void */ public static function allIpv6($value, $message = '') { static::isIterable($value); foreach ($value as $entry) { static::ipv6($entry, $message); } } /** * @param mixed $value * @param string $message * * @throws InvalidArgumentException * * @return void */ public static function allNullOrIpv6($value, $message = '') { static::isIterable($value); foreach ($value as $entry) { null === $entry || static::ipv6($entry, $message); } } /** * @param mixed $value * @param string $message * * @throws InvalidArgumentException * * @return void */ public static function nullOrEmail($value, $message = '') { null === $value || static::email($value, $message); } /** * @param mixed $value * @param string $message * * @throws InvalidArgumentException * * @return void */ public static function allEmail($value, $message = '') { static::isIterable($value); foreach ($value as $entry) { static::email($entry, $message); } } /** * @param mixed $value * @param string $message * * @throws InvalidArgumentException * * @return void */ public static function allNullOrEmail($value, $message = '') { static::isIterable($value); foreach ($value as $entry) { null === $entry || static::email($entry, $message); } } /** * @param array|null $values * @param string $message * * @throws InvalidArgumentException * * @return void */ public static function nullOrUniqueValues($values, $message = '') { null === $values || static::uniqueValues($values, $message); } /** * @param iterable $values * @param string $message * * @throws InvalidArgumentException * * @return void */ public static function allUniqueValues($values, $message = '') { static::isIterable($values); foreach ($values as $entry) { static::uniqueValues($entry, $message); } } /** * @param iterable $values * @param string $message * * @throws InvalidArgumentException * * @return void */ public static function allNullOrUniqueValues($values, $message = '') { static::isIterable($values); foreach ($values as $entry) { null === $entry || static::uniqueValues($entry, $message); } } /** * @param mixed $value * @param mixed $expect * @param string $message * * @throws InvalidArgumentException * * @return void */ public static function nullOrEq($value, $expect, $message = '') { null === $value || static::eq($value, $expect, $message); } /** * @param mixed $value * @param mixed $expect * @param string $message * * @throws InvalidArgumentException * * @return void */ public static function allEq($value, $expect, $message = '') { static::isIterable($value); foreach ($value as $entry) { static::eq($entry, $expect, $message); } } /** * @param mixed $value * @param mixed $expect * @param string $message * * @throws InvalidArgumentException * * @return void */ public static function allNullOrEq($value, $expect, $message = '') { static::isIterable($value); foreach ($value as $entry) { null === $entry || static::eq($entry, $expect, $message); } } /** * @param mixed $value * @param mixed $expect * @param string $message * * @throws InvalidArgumentException * * @return void */ public static function nullOrNotEq($value, $expect, $message = '') { null === $value || static::notEq($value, $expect, $message); } /** * @param mixed $value * @param mixed $expect * @param string $message * * @throws InvalidArgumentException * * @return void */ public static function allNotEq($value, $expect, $message = '') { static::isIterable($value); foreach ($value as $entry) { static::notEq($entry, $expect, $message); } } /** * @param mixed $value * @param mixed $expect * @param string $message * * @throws InvalidArgumentException * * @return void */ public static function allNullOrNotEq($value, $expect, $message = '') { static::isIterable($value); foreach ($value as $entry) { null === $entry || static::notEq($entry, $expect, $message); } } /** * @psalm-pure * * @param mixed $value * @param mixed $expect * @param string $message * * @throws InvalidArgumentException * * @return void */ public static function nullOrSame($value, $expect, $message = '') { null === $value || static::same($value, $expect, $message); } /** * @psalm-pure * * @param mixed $value * @param mixed $expect * @param string $message * * @throws InvalidArgumentException * * @return void */ public static function allSame($value, $expect, $message = '') { static::isIterable($value); foreach ($value as $entry) { static::same($entry, $expect, $message); } } /** * @psalm-pure * * @param mixed $value * @param mixed $expect * @param string $message * * @throws InvalidArgumentException * * @return void */ public static function allNullOrSame($value, $expect, $message = '') { static::isIterable($value); foreach ($value as $entry) { null === $entry || static::same($entry, $expect, $message); } } /** * @psalm-pure * * @param mixed $value * @param mixed $expect * @param string $message * * @throws InvalidArgumentException * * @return void */ public static function nullOrNotSame($value, $expect, $message = '') { null === $value || static::notSame($value, $expect, $message); } /** * @psalm-pure * * @param mixed $value * @param mixed $expect * @param string $message * * @throws InvalidArgumentException * * @return void */ public static function allNotSame($value, $expect, $message = '') { static::isIterable($value); foreach ($value as $entry) { static::notSame($entry, $expect, $message); } } /** * @psalm-pure * * @param mixed $value * @param mixed $expect * @param string $message * * @throws InvalidArgumentException * * @return void */ public static function allNullOrNotSame($value, $expect, $message = '') { static::isIterable($value); foreach ($value as $entry) { null === $entry || static::notSame($entry, $expect, $message); } } /** * @psalm-pure * * @param mixed $value * @param mixed $limit * @param string $message * * @throws InvalidArgumentException * * @return void */ public static function nullOrGreaterThan($value, $limit, $message = '') { null === $value || static::greaterThan($value, $limit, $message); } /** * @psalm-pure * * @param mixed $value * @param mixed $limit * @param string $message * * @throws InvalidArgumentException * * @return void */ public static function allGreaterThan($value, $limit, $message = '') { static::isIterable($value); foreach ($value as $entry) { static::greaterThan($entry, $limit, $message); } } /** * @psalm-pure * * @param mixed $value * @param mixed $limit * @param string $message * * @throws InvalidArgumentException * * @return void */ public static function allNullOrGreaterThan($value, $limit, $message = '') { static::isIterable($value); foreach ($value as $entry) { null === $entry || static::greaterThan($entry, $limit, $message); } } /** * @psalm-pure * * @param mixed $value * @param mixed $limit * @param string $message * * @throws InvalidArgumentException * * @return void */ public static function nullOrGreaterThanEq($value, $limit, $message = '') { null === $value || static::greaterThanEq($value, $limit, $message); } /** * @psalm-pure * * @param mixed $value * @param mixed $limit * @param string $message * * @throws InvalidArgumentException * * @return void */ public static function allGreaterThanEq($value, $limit, $message = '') { static::isIterable($value); foreach ($value as $entry) { static::greaterThanEq($entry, $limit, $message); } } /** * @psalm-pure * * @param mixed $value * @param mixed $limit * @param string $message * * @throws InvalidArgumentException * * @return void */ public static function allNullOrGreaterThanEq($value, $limit, $message = '') { static::isIterable($value); foreach ($value as $entry) { null === $entry || static::greaterThanEq($entry, $limit, $message); } } /** * @psalm-pure * * @param mixed $value * @param mixed $limit * @param string $message * * @throws InvalidArgumentException * * @return void */ public static function nullOrLessThan($value, $limit, $message = '') { null === $value || static::lessThan($value, $limit, $message); } /** * @psalm-pure * * @param mixed $value * @param mixed $limit * @param string $message * * @throws InvalidArgumentException * * @return void */ public static function allLessThan($value, $limit, $message = '') { static::isIterable($value); foreach ($value as $entry) { static::lessThan($entry, $limit, $message); } } /** * @psalm-pure * * @param mixed $value * @param mixed $limit * @param string $message * * @throws InvalidArgumentException * * @return void */ public static function allNullOrLessThan($value, $limit, $message = '') { static::isIterable($value); foreach ($value as $entry) { null === $entry || static::lessThan($entry, $limit, $message); } } /** * @psalm-pure * * @param mixed $value * @param mixed $limit * @param string $message * * @throws InvalidArgumentException * * @return void */ public static function nullOrLessThanEq($value, $limit, $message = '') { null === $value || static::lessThanEq($value, $limit, $message); } /** * @psalm-pure * * @param mixed $value * @param mixed $limit * @param string $message * * @throws InvalidArgumentException * * @return void */ public static function allLessThanEq($value, $limit, $message = '') { static::isIterable($value); foreach ($value as $entry) { static::lessThanEq($entry, $limit, $message); } } /** * @psalm-pure * * @param mixed $value * @param mixed $limit * @param string $message * * @throws InvalidArgumentException * * @return void */ public static function allNullOrLessThanEq($value, $limit, $message = '') { static::isIterable($value); foreach ($value as $entry) { null === $entry || static::lessThanEq($entry, $limit, $message); } } /** * @psalm-pure * * @param mixed $value * @param mixed $min * @param mixed $max * @param string $message * * @throws InvalidArgumentException * * @return void */ public static function nullOrRange($value, $min, $max, $message = '') { null === $value || static::range($value, $min, $max, $message); } /** * @psalm-pure * * @param mixed $value * @param mixed $min * @param mixed $max * @param string $message * * @throws InvalidArgumentException * * @return void */ public static function allRange($value, $min, $max, $message = '') { static::isIterable($value); foreach ($value as $entry) { static::range($entry, $min, $max, $message); } } /** * @psalm-pure * * @param mixed $value * @param mixed $min * @param mixed $max * @param string $message * * @throws InvalidArgumentException * * @return void */ public static function allNullOrRange($value, $min, $max, $message = '') { static::isIterable($value); foreach ($value as $entry) { null === $entry || static::range($entry, $min, $max, $message); } } /** * @psalm-pure * * @param mixed $value * @param array $values * @param string $message * * @throws InvalidArgumentException * * @return void */ public static function nullOrOneOf($value, $values, $message = '') { null === $value || static::oneOf($value, $values, $message); } /** * @psalm-pure * * @param mixed $value * @param array $values * @param string $message * * @throws InvalidArgumentException * * @return void */ public static function allOneOf($value, $values, $message = '') { static::isIterable($value); foreach ($value as $entry) { static::oneOf($entry, $values, $message); } } /** * @psalm-pure * * @param mixed $value * @param array $values * @param string $message * * @throws InvalidArgumentException * * @return void */ public static function allNullOrOneOf($value, $values, $message = '') { static::isIterable($value); foreach ($value as $entry) { null === $entry || static::oneOf($entry, $values, $message); } } /** * @psalm-pure * * @param mixed $value * @param array $values * @param string $message * * @throws InvalidArgumentException * * @return void */ public static function nullOrInArray($value, $values, $message = '') { null === $value || static::inArray($value, $values, $message); } /** * @psalm-pure * * @param mixed $value * @param array $values * @param string $message * * @throws InvalidArgumentException * * @return void */ public static function allInArray($value, $values, $message = '') { static::isIterable($value); foreach ($value as $entry) { static::inArray($entry, $values, $message); } } /** * @psalm-pure * * @param mixed $value * @param array $values * @param string $message * * @throws InvalidArgumentException * * @return void */ public static function allNullOrInArray($value, $values, $message = '') { static::isIterable($value); foreach ($value as $entry) { null === $entry || static::inArray($entry, $values, $message); } } /** * @psalm-pure * * @param string|null $value * @param string $subString * @param string $message * * @throws InvalidArgumentException * * @return void */ public static function nullOrContains($value, $subString, $message = '') { null === $value || static::contains($value, $subString, $message); } /** * @psalm-pure * * @param iterable $value * @param string $subString * @param string $message * * @throws InvalidArgumentException * * @return void */ public static function allContains($value, $subString, $message = '') { static::isIterable($value); foreach ($value as $entry) { static::contains($entry, $subString, $message); } } /** * @psalm-pure * * @param iterable $value * @param string $subString * @param string $message * * @throws InvalidArgumentException * * @return void */ public static function allNullOrContains($value, $subString, $message = '') { static::isIterable($value); foreach ($value as $entry) { null === $entry || static::contains($entry, $subString, $message); } } /** * @psalm-pure * * @param string|null $value * @param string $subString * @param string $message * * @throws InvalidArgumentException * * @return void */ public static function nullOrNotContains($value, $subString, $message = '') { null === $value || static::notContains($value, $subString, $message); } /** * @psalm-pure * * @param iterable $value * @param string $subString * @param string $message * * @throws InvalidArgumentException * * @return void */ public static function allNotContains($value, $subString, $message = '') { static::isIterable($value); foreach ($value as $entry) { static::notContains($entry, $subString, $message); } } /** * @psalm-pure * * @param iterable $value * @param string $subString * @param string $message * * @throws InvalidArgumentException * * @return void */ public static function allNullOrNotContains($value, $subString, $message = '') { static::isIterable($value); foreach ($value as $entry) { null === $entry || static::notContains($entry, $subString, $message); } } /** * @psalm-pure * * @param string|null $value * @param string $message * * @throws InvalidArgumentException * * @return void */ public static function nullOrNotWhitespaceOnly($value, $message = '') { null === $value || static::notWhitespaceOnly($value, $message); } /** * @psalm-pure * * @param iterable $value * @param string $message * * @throws InvalidArgumentException * * @return void */ public static function allNotWhitespaceOnly($value, $message = '') { static::isIterable($value); foreach ($value as $entry) { static::notWhitespaceOnly($entry, $message); } } /** * @psalm-pure * * @param iterable $value * @param string $message * * @throws InvalidArgumentException * * @return void */ public static function allNullOrNotWhitespaceOnly($value, $message = '') { static::isIterable($value); foreach ($value as $entry) { null === $entry || static::notWhitespaceOnly($entry, $message); } } /** * @psalm-pure * * @param string|null $value * @param string $prefix * @param string $message * * @throws InvalidArgumentException * * @return void */ public static function nullOrStartsWith($value, $prefix, $message = '') { null === $value || static::startsWith($value, $prefix, $message); } /** * @psalm-pure * * @param iterable $value * @param string $prefix * @param string $message * * @throws InvalidArgumentException * * @return void */ public static function allStartsWith($value, $prefix, $message = '') { static::isIterable($value); foreach ($value as $entry) { static::startsWith($entry, $prefix, $message); } } /** * @psalm-pure * * @param iterable $value * @param string $prefix * @param string $message * * @throws InvalidArgumentException * * @return void */ public static function allNullOrStartsWith($value, $prefix, $message = '') { static::isIterable($value); foreach ($value as $entry) { null === $entry || static::startsWith($entry, $prefix, $message); } } /** * @psalm-pure * * @param string|null $value * @param string $prefix * @param string $message * * @throws InvalidArgumentException * * @return void */ public static function nullOrNotStartsWith($value, $prefix, $message = '') { null === $value || static::notStartsWith($value, $prefix, $message); } /** * @psalm-pure * * @param iterable $value * @param string $prefix * @param string $message * * @throws InvalidArgumentException * * @return void */ public static function allNotStartsWith($value, $prefix, $message = '') { static::isIterable($value); foreach ($value as $entry) { static::notStartsWith($entry, $prefix, $message); } } /** * @psalm-pure * * @param iterable $value * @param string $prefix * @param string $message * * @throws InvalidArgumentException * * @return void */ public static function allNullOrNotStartsWith($value, $prefix, $message = '') { static::isIterable($value); foreach ($value as $entry) { null === $entry || static::notStartsWith($entry, $prefix, $message); } } /** * @psalm-pure * * @param mixed $value * @param string $message * * @throws InvalidArgumentException * * @return void */ public static function nullOrStartsWithLetter($value, $message = '') { null === $value || static::startsWithLetter($value, $message); } /** * @psalm-pure * * @param mixed $value * @param string $message * * @throws InvalidArgumentException * * @return void */ public static function allStartsWithLetter($value, $message = '') { static::isIterable($value); foreach ($value as $entry) { static::startsWithLetter($entry, $message); } } /** * @psalm-pure * * @param mixed $value * @param string $message * * @throws InvalidArgumentException * * @return void */ public static function allNullOrStartsWithLetter($value, $message = '') { static::isIterable($value); foreach ($value as $entry) { null === $entry || static::startsWithLetter($entry, $message); } } /** * @psalm-pure * * @param string|null $value * @param string $suffix * @param string $message * * @throws InvalidArgumentException * * @return void */ public static function nullOrEndsWith($value, $suffix, $message = '') { null === $value || static::endsWith($value, $suffix, $message); } /** * @psalm-pure * * @param iterable $value * @param string $suffix * @param string $message * * @throws InvalidArgumentException * * @return void */ public static function allEndsWith($value, $suffix, $message = '') { static::isIterable($value); foreach ($value as $entry) { static::endsWith($entry, $suffix, $message); } } /** * @psalm-pure * * @param iterable $value * @param string $suffix * @param string $message * * @throws InvalidArgumentException * * @return void */ public static function allNullOrEndsWith($value, $suffix, $message = '') { static::isIterable($value); foreach ($value as $entry) { null === $entry || static::endsWith($entry, $suffix, $message); } } /** * @psalm-pure * * @param string|null $value * @param string $suffix * @param string $message * * @throws InvalidArgumentException * * @return void */ public static function nullOrNotEndsWith($value, $suffix, $message = '') { null === $value || static::notEndsWith($value, $suffix, $message); } /** * @psalm-pure * * @param iterable $value * @param string $suffix * @param string $message * * @throws InvalidArgumentException * * @return void */ public static function allNotEndsWith($value, $suffix, $message = '') { static::isIterable($value); foreach ($value as $entry) { static::notEndsWith($entry, $suffix, $message); } } /** * @psalm-pure * * @param iterable $value * @param string $suffix * @param string $message * * @throws InvalidArgumentException * * @return void */ public static function allNullOrNotEndsWith($value, $suffix, $message = '') { static::isIterable($value); foreach ($value as $entry) { null === $entry || static::notEndsWith($entry, $suffix, $message); } } /** * @psalm-pure * * @param string|null $value * @param string $pattern * @param string $message * * @throws InvalidArgumentException * * @return void */ public static function nullOrRegex($value, $pattern, $message = '') { null === $value || static::regex($value, $pattern, $message); } /** * @psalm-pure * * @param iterable $value * @param string $pattern * @param string $message * * @throws InvalidArgumentException * * @return void */ public static function allRegex($value, $pattern, $message = '') { static::isIterable($value); foreach ($value as $entry) { static::regex($entry, $pattern, $message); } } /** * @psalm-pure * * @param iterable $value * @param string $pattern * @param string $message * * @throws InvalidArgumentException * * @return void */ public static function allNullOrRegex($value, $pattern, $message = '') { static::isIterable($value); foreach ($value as $entry) { null === $entry || static::regex($entry, $pattern, $message); } } /** * @psalm-pure * * @param string|null $value * @param string $pattern * @param string $message * * @throws InvalidArgumentException * * @return void */ public static function nullOrNotRegex($value, $pattern, $message = '') { null === $value || static::notRegex($value, $pattern, $message); } /** * @psalm-pure * * @param iterable $value * @param string $pattern * @param string $message * * @throws InvalidArgumentException * * @return void */ public static function allNotRegex($value, $pattern, $message = '') { static::isIterable($value); foreach ($value as $entry) { static::notRegex($entry, $pattern, $message); } } /** * @psalm-pure * * @param iterable $value * @param string $pattern * @param string $message * * @throws InvalidArgumentException * * @return void */ public static function allNullOrNotRegex($value, $pattern, $message = '') { static::isIterable($value); foreach ($value as $entry) { null === $entry || static::notRegex($entry, $pattern, $message); } } /** * @psalm-pure * * @param mixed $value * @param string $message * * @throws InvalidArgumentException * * @return void */ public static function nullOrUnicodeLetters($value, $message = '') { null === $value || static::unicodeLetters($value, $message); } /** * @psalm-pure * * @param mixed $value * @param string $message * * @throws InvalidArgumentException * * @return void */ public static function allUnicodeLetters($value, $message = '') { static::isIterable($value); foreach ($value as $entry) { static::unicodeLetters($entry, $message); } } /** * @psalm-pure * * @param mixed $value * @param string $message * * @throws InvalidArgumentException * * @return void */ public static function allNullOrUnicodeLetters($value, $message = '') { static::isIterable($value); foreach ($value as $entry) { null === $entry || static::unicodeLetters($entry, $message); } } /** * @psalm-pure * * @param mixed $value * @param string $message * * @throws InvalidArgumentException * * @return void */ public static function nullOrAlpha($value, $message = '') { null === $value || static::alpha($value, $message); } /** * @psalm-pure * * @param mixed $value * @param string $message * * @throws InvalidArgumentException * * @return void */ public static function allAlpha($value, $message = '') { static::isIterable($value); foreach ($value as $entry) { static::alpha($entry, $message); } } /** * @psalm-pure * * @param mixed $value * @param string $message * * @throws InvalidArgumentException * * @return void */ public static function allNullOrAlpha($value, $message = '') { static::isIterable($value); foreach ($value as $entry) { null === $entry || static::alpha($entry, $message); } } /** * @psalm-pure * * @param string|null $value * @param string $message * * @throws InvalidArgumentException * * @return void */ public static function nullOrDigits($value, $message = '') { null === $value || static::digits($value, $message); } /** * @psalm-pure * * @param iterable $value * @param string $message * * @throws InvalidArgumentException * * @return void */ public static function allDigits($value, $message = '') { static::isIterable($value); foreach ($value as $entry) { static::digits($entry, $message); } } /** * @psalm-pure * * @param iterable $value * @param string $message * * @throws InvalidArgumentException * * @return void */ public static function allNullOrDigits($value, $message = '') { static::isIterable($value); foreach ($value as $entry) { null === $entry || static::digits($entry, $message); } } /** * @psalm-pure * * @param string|null $value * @param string $message * * @throws InvalidArgumentException * * @return void */ public static function nullOrAlnum($value, $message = '') { null === $value || static::alnum($value, $message); } /** * @psalm-pure * * @param iterable $value * @param string $message * * @throws InvalidArgumentException * * @return void */ public static function allAlnum($value, $message = '') { static::isIterable($value); foreach ($value as $entry) { static::alnum($entry, $message); } } /** * @psalm-pure * * @param iterable $value * @param string $message * * @throws InvalidArgumentException * * @return void */ public static function allNullOrAlnum($value, $message = '') { static::isIterable($value); foreach ($value as $entry) { null === $entry || static::alnum($entry, $message); } } /** * @psalm-pure * @psalm-assert lowercase-string|null $value * * @param string|null $value * @param string $message * * @throws InvalidArgumentException * * @return void */ public static function nullOrLower($value, $message = '') { null === $value || static::lower($value, $message); } /** * @psalm-pure * @psalm-assert iterable $value * * @param iterable $value * @param string $message * * @throws InvalidArgumentException * * @return void */ public static function allLower($value, $message = '') { static::isIterable($value); foreach ($value as $entry) { static::lower($entry, $message); } } /** * @psalm-pure * @psalm-assert iterable $value * * @param iterable $value * @param string $message * * @throws InvalidArgumentException * * @return void */ public static function allNullOrLower($value, $message = '') { static::isIterable($value); foreach ($value as $entry) { null === $entry || static::lower($entry, $message); } } /** * @psalm-pure * * @param string|null $value * @param string $message * * @throws InvalidArgumentException * * @return void */ public static function nullOrUpper($value, $message = '') { null === $value || static::upper($value, $message); } /** * @psalm-pure * * @param iterable $value * @param string $message * * @throws InvalidArgumentException * * @return void */ public static function allUpper($value, $message = '') { static::isIterable($value); foreach ($value as $entry) { static::upper($entry, $message); } } /** * @psalm-pure * @psalm-assert iterable $value * * @param iterable $value * @param string $message * * @throws InvalidArgumentException * * @return void */ public static function allNullOrUpper($value, $message = '') { static::isIterable($value); foreach ($value as $entry) { null === $entry || static::upper($entry, $message); } } /** * @psalm-pure * * @param string|null $value * @param int $length * @param string $message * * @throws InvalidArgumentException * * @return void */ public static function nullOrLength($value, $length, $message = '') { null === $value || static::length($value, $length, $message); } /** * @psalm-pure * * @param iterable $value * @param int $length * @param string $message * * @throws InvalidArgumentException * * @return void */ public static function allLength($value, $length, $message = '') { static::isIterable($value); foreach ($value as $entry) { static::length($entry, $length, $message); } } /** * @psalm-pure * * @param iterable $value * @param int $length * @param string $message * * @throws InvalidArgumentException * * @return void */ public static function allNullOrLength($value, $length, $message = '') { static::isIterable($value); foreach ($value as $entry) { null === $entry || static::length($entry, $length, $message); } } /** * @psalm-pure * * @param string|null $value * @param int|float $min * @param string $message * * @throws InvalidArgumentException * * @return void */ public static function nullOrMinLength($value, $min, $message = '') { null === $value || static::minLength($value, $min, $message); } /** * @psalm-pure * * @param iterable $value * @param int|float $min * @param string $message * * @throws InvalidArgumentException * * @return void */ public static function allMinLength($value, $min, $message = '') { static::isIterable($value); foreach ($value as $entry) { static::minLength($entry, $min, $message); } } /** * @psalm-pure * * @param iterable $value * @param int|float $min * @param string $message * * @throws InvalidArgumentException * * @return void */ public static function allNullOrMinLength($value, $min, $message = '') { static::isIterable($value); foreach ($value as $entry) { null === $entry || static::minLength($entry, $min, $message); } } /** * @psalm-pure * * @param string|null $value * @param int|float $max * @param string $message * * @throws InvalidArgumentException * * @return void */ public static function nullOrMaxLength($value, $max, $message = '') { null === $value || static::maxLength($value, $max, $message); } /** * @psalm-pure * * @param iterable $value * @param int|float $max * @param string $message * * @throws InvalidArgumentException * * @return void */ public static function allMaxLength($value, $max, $message = '') { static::isIterable($value); foreach ($value as $entry) { static::maxLength($entry, $max, $message); } } /** * @psalm-pure * * @param iterable $value * @param int|float $max * @param string $message * * @throws InvalidArgumentException * * @return void */ public static function allNullOrMaxLength($value, $max, $message = '') { static::isIterable($value); foreach ($value as $entry) { null === $entry || static::maxLength($entry, $max, $message); } } /** * @psalm-pure * * @param string|null $value * @param int|float $min * @param int|float $max * @param string $message * * @throws InvalidArgumentException * * @return void */ public static function nullOrLengthBetween($value, $min, $max, $message = '') { null === $value || static::lengthBetween($value, $min, $max, $message); } /** * @psalm-pure * * @param iterable $value * @param int|float $min * @param int|float $max * @param string $message * * @throws InvalidArgumentException * * @return void */ public static function allLengthBetween($value, $min, $max, $message = '') { static::isIterable($value); foreach ($value as $entry) { static::lengthBetween($entry, $min, $max, $message); } } /** * @psalm-pure * * @param iterable $value * @param int|float $min * @param int|float $max * @param string $message * * @throws InvalidArgumentException * * @return void */ public static function allNullOrLengthBetween($value, $min, $max, $message = '') { static::isIterable($value); foreach ($value as $entry) { null === $entry || static::lengthBetween($entry, $min, $max, $message); } } /** * @param mixed $value * @param string $message * * @throws InvalidArgumentException * * @return void */ public static function nullOrFileExists($value, $message = '') { null === $value || static::fileExists($value, $message); } /** * @param mixed $value * @param string $message * * @throws InvalidArgumentException * * @return void */ public static function allFileExists($value, $message = '') { static::isIterable($value); foreach ($value as $entry) { static::fileExists($entry, $message); } } /** * @param mixed $value * @param string $message * * @throws InvalidArgumentException * * @return void */ public static function allNullOrFileExists($value, $message = '') { static::isIterable($value); foreach ($value as $entry) { null === $entry || static::fileExists($entry, $message); } } /** * @param mixed $value * @param string $message * * @throws InvalidArgumentException * * @return void */ public static function nullOrFile($value, $message = '') { null === $value || static::file($value, $message); } /** * @param mixed $value * @param string $message * * @throws InvalidArgumentException * * @return void */ public static function allFile($value, $message = '') { static::isIterable($value); foreach ($value as $entry) { static::file($entry, $message); } } /** * @param mixed $value * @param string $message * * @throws InvalidArgumentException * * @return void */ public static function allNullOrFile($value, $message = '') { static::isIterable($value); foreach ($value as $entry) { null === $entry || static::file($entry, $message); } } /** * @param mixed $value * @param string $message * * @throws InvalidArgumentException * * @return void */ public static function nullOrDirectory($value, $message = '') { null === $value || static::directory($value, $message); } /** * @param mixed $value * @param string $message * * @throws InvalidArgumentException * * @return void */ public static function allDirectory($value, $message = '') { static::isIterable($value); foreach ($value as $entry) { static::directory($entry, $message); } } /** * @param mixed $value * @param string $message * * @throws InvalidArgumentException * * @return void */ public static function allNullOrDirectory($value, $message = '') { static::isIterable($value); foreach ($value as $entry) { null === $entry || static::directory($entry, $message); } } /** * @param string|null $value * @param string $message * * @throws InvalidArgumentException * * @return void */ public static function nullOrReadable($value, $message = '') { null === $value || static::readable($value, $message); } /** * @param iterable $value * @param string $message * * @throws InvalidArgumentException * * @return void */ public static function allReadable($value, $message = '') { static::isIterable($value); foreach ($value as $entry) { static::readable($entry, $message); } } /** * @param iterable $value * @param string $message * * @throws InvalidArgumentException * * @return void */ public static function allNullOrReadable($value, $message = '') { static::isIterable($value); foreach ($value as $entry) { null === $entry || static::readable($entry, $message); } } /** * @param string|null $value * @param string $message * * @throws InvalidArgumentException * * @return void */ public static function nullOrWritable($value, $message = '') { null === $value || static::writable($value, $message); } /** * @param iterable $value * @param string $message * * @throws InvalidArgumentException * * @return void */ public static function allWritable($value, $message = '') { static::isIterable($value); foreach ($value as $entry) { static::writable($entry, $message); } } /** * @param iterable $value * @param string $message * * @throws InvalidArgumentException * * @return void */ public static function allNullOrWritable($value, $message = '') { static::isIterable($value); foreach ($value as $entry) { null === $entry || static::writable($entry, $message); } } /** * @psalm-assert class-string|null $value * * @param mixed $value * @param string $message * * @throws InvalidArgumentException * * @return void */ public static function nullOrClassExists($value, $message = '') { null === $value || static::classExists($value, $message); } /** * @psalm-assert iterable $value * * @param mixed $value * @param string $message * * @throws InvalidArgumentException * * @return void */ public static function allClassExists($value, $message = '') { static::isIterable($value); foreach ($value as $entry) { static::classExists($entry, $message); } } /** * @psalm-assert iterable $value * * @param mixed $value * @param string $message * * @throws InvalidArgumentException * * @return void */ public static function allNullOrClassExists($value, $message = '') { static::isIterable($value); foreach ($value as $entry) { null === $entry || static::classExists($entry, $message); } } /** * @psalm-pure * @psalm-template ExpectedType of object * @psalm-param class-string $class * @psalm-assert class-string|ExpectedType|null $value * * @param mixed $value * @param string|object $class * @param string $message * * @throws InvalidArgumentException * * @return void */ public static function nullOrSubclassOf($value, $class, $message = '') { null === $value || static::subclassOf($value, $class, $message); } /** * @psalm-pure * @psalm-template ExpectedType of object * @psalm-param class-string $class * @psalm-assert iterable|ExpectedType> $value * * @param mixed $value * @param string|object $class * @param string $message * * @throws InvalidArgumentException * * @return void */ public static function allSubclassOf($value, $class, $message = '') { static::isIterable($value); foreach ($value as $entry) { static::subclassOf($entry, $class, $message); } } /** * @psalm-pure * @psalm-template ExpectedType of object * @psalm-param class-string $class * @psalm-assert iterable|ExpectedType|null> $value * * @param mixed $value * @param string|object $class * @param string $message * * @throws InvalidArgumentException * * @return void */ public static function allNullOrSubclassOf($value, $class, $message = '') { static::isIterable($value); foreach ($value as $entry) { null === $entry || static::subclassOf($entry, $class, $message); } } /** * @psalm-assert class-string|null $value * * @param mixed $value * @param string $message * * @throws InvalidArgumentException * * @return void */ public static function nullOrInterfaceExists($value, $message = '') { null === $value || static::interfaceExists($value, $message); } /** * @psalm-assert iterable $value * * @param mixed $value * @param string $message * * @throws InvalidArgumentException * * @return void */ public static function allInterfaceExists($value, $message = '') { static::isIterable($value); foreach ($value as $entry) { static::interfaceExists($entry, $message); } } /** * @psalm-assert iterable $value * * @param mixed $value * @param string $message * * @throws InvalidArgumentException * * @return void */ public static function allNullOrInterfaceExists($value, $message = '') { static::isIterable($value); foreach ($value as $entry) { null === $entry || static::interfaceExists($entry, $message); } } /** * @psalm-pure * @psalm-template ExpectedType of object * @psalm-param class-string $interface * @psalm-assert class-string|null $value * * @param mixed $value * @param mixed $interface * @param string $message * * @throws InvalidArgumentException * * @return void */ public static function nullOrImplementsInterface($value, $interface, $message = '') { null === $value || static::implementsInterface($value, $interface, $message); } /** * @psalm-pure * @psalm-template ExpectedType of object * @psalm-param class-string $interface * @psalm-assert iterable> $value * * @param mixed $value * @param mixed $interface * @param string $message * * @throws InvalidArgumentException * * @return void */ public static function allImplementsInterface($value, $interface, $message = '') { static::isIterable($value); foreach ($value as $entry) { static::implementsInterface($entry, $interface, $message); } } /** * @psalm-pure * @psalm-template ExpectedType of object * @psalm-param class-string $interface * @psalm-assert iterable|null> $value * * @param mixed $value * @param mixed $interface * @param string $message * * @throws InvalidArgumentException * * @return void */ public static function allNullOrImplementsInterface($value, $interface, $message = '') { static::isIterable($value); foreach ($value as $entry) { null === $entry || static::implementsInterface($entry, $interface, $message); } } /** * @psalm-pure * @psalm-param class-string|object|null $classOrObject * * @param string|object|null $classOrObject * @param mixed $property * @param string $message * * @throws InvalidArgumentException * * @return void */ public static function nullOrPropertyExists($classOrObject, $property, $message = '') { null === $classOrObject || static::propertyExists($classOrObject, $property, $message); } /** * @psalm-pure * @psalm-param iterable $classOrObject * * @param iterable $classOrObject * @param mixed $property * @param string $message * * @throws InvalidArgumentException * * @return void */ public static function allPropertyExists($classOrObject, $property, $message = '') { static::isIterable($classOrObject); foreach ($classOrObject as $entry) { static::propertyExists($entry, $property, $message); } } /** * @psalm-pure * @psalm-param iterable $classOrObject * * @param iterable $classOrObject * @param mixed $property * @param string $message * * @throws InvalidArgumentException * * @return void */ public static function allNullOrPropertyExists($classOrObject, $property, $message = '') { static::isIterable($classOrObject); foreach ($classOrObject as $entry) { null === $entry || static::propertyExists($entry, $property, $message); } } /** * @psalm-pure * @psalm-param class-string|object|null $classOrObject * * @param string|object|null $classOrObject * @param mixed $property * @param string $message * * @throws InvalidArgumentException * * @return void */ public static function nullOrPropertyNotExists($classOrObject, $property, $message = '') { null === $classOrObject || static::propertyNotExists($classOrObject, $property, $message); } /** * @psalm-pure * @psalm-param iterable $classOrObject * * @param iterable $classOrObject * @param mixed $property * @param string $message * * @throws InvalidArgumentException * * @return void */ public static function allPropertyNotExists($classOrObject, $property, $message = '') { static::isIterable($classOrObject); foreach ($classOrObject as $entry) { static::propertyNotExists($entry, $property, $message); } } /** * @psalm-pure * @psalm-param iterable $classOrObject * * @param iterable $classOrObject * @param mixed $property * @param string $message * * @throws InvalidArgumentException * * @return void */ public static function allNullOrPropertyNotExists($classOrObject, $property, $message = '') { static::isIterable($classOrObject); foreach ($classOrObject as $entry) { null === $entry || static::propertyNotExists($entry, $property, $message); } } /** * @psalm-pure * @psalm-param class-string|object|null $classOrObject * * @param string|object|null $classOrObject * @param mixed $method * @param string $message * * @throws InvalidArgumentException * * @return void */ public static function nullOrMethodExists($classOrObject, $method, $message = '') { null === $classOrObject || static::methodExists($classOrObject, $method, $message); } /** * @psalm-pure * @psalm-param iterable $classOrObject * * @param iterable $classOrObject * @param mixed $method * @param string $message * * @throws InvalidArgumentException * * @return void */ public static function allMethodExists($classOrObject, $method, $message = '') { static::isIterable($classOrObject); foreach ($classOrObject as $entry) { static::methodExists($entry, $method, $message); } } /** * @psalm-pure * @psalm-param iterable $classOrObject * * @param iterable $classOrObject * @param mixed $method * @param string $message * * @throws InvalidArgumentException * * @return void */ public static function allNullOrMethodExists($classOrObject, $method, $message = '') { static::isIterable($classOrObject); foreach ($classOrObject as $entry) { null === $entry || static::methodExists($entry, $method, $message); } } /** * @psalm-pure * @psalm-param class-string|object|null $classOrObject * * @param string|object|null $classOrObject * @param mixed $method * @param string $message * * @throws InvalidArgumentException * * @return void */ public static function nullOrMethodNotExists($classOrObject, $method, $message = '') { null === $classOrObject || static::methodNotExists($classOrObject, $method, $message); } /** * @psalm-pure * @psalm-param iterable $classOrObject * * @param iterable $classOrObject * @param mixed $method * @param string $message * * @throws InvalidArgumentException * * @return void */ public static function allMethodNotExists($classOrObject, $method, $message = '') { static::isIterable($classOrObject); foreach ($classOrObject as $entry) { static::methodNotExists($entry, $method, $message); } } /** * @psalm-pure * @psalm-param iterable $classOrObject * * @param iterable $classOrObject * @param mixed $method * @param string $message * * @throws InvalidArgumentException * * @return void */ public static function allNullOrMethodNotExists($classOrObject, $method, $message = '') { static::isIterable($classOrObject); foreach ($classOrObject as $entry) { null === $entry || static::methodNotExists($entry, $method, $message); } } /** * @psalm-pure * * @param array|null $array * @param string|int $key * @param string $message * * @throws InvalidArgumentException * * @return void */ public static function nullOrKeyExists($array, $key, $message = '') { null === $array || static::keyExists($array, $key, $message); } /** * @psalm-pure * * @param iterable $array * @param string|int $key * @param string $message * * @throws InvalidArgumentException * * @return void */ public static function allKeyExists($array, $key, $message = '') { static::isIterable($array); foreach ($array as $entry) { static::keyExists($entry, $key, $message); } } /** * @psalm-pure * * @param iterable $array * @param string|int $key * @param string $message * * @throws InvalidArgumentException * * @return void */ public static function allNullOrKeyExists($array, $key, $message = '') { static::isIterable($array); foreach ($array as $entry) { null === $entry || static::keyExists($entry, $key, $message); } } /** * @psalm-pure * * @param array|null $array * @param string|int $key * @param string $message * * @throws InvalidArgumentException * * @return void */ public static function nullOrKeyNotExists($array, $key, $message = '') { null === $array || static::keyNotExists($array, $key, $message); } /** * @psalm-pure * * @param iterable $array * @param string|int $key * @param string $message * * @throws InvalidArgumentException * * @return void */ public static function allKeyNotExists($array, $key, $message = '') { static::isIterable($array); foreach ($array as $entry) { static::keyNotExists($entry, $key, $message); } } /** * @psalm-pure * * @param iterable $array * @param string|int $key * @param string $message * * @throws InvalidArgumentException * * @return void */ public static function allNullOrKeyNotExists($array, $key, $message = '') { static::isIterable($array); foreach ($array as $entry) { null === $entry || static::keyNotExists($entry, $key, $message); } } /** * @psalm-pure * @psalm-assert array-key|null $value * * @param mixed $value * @param string $message * * @throws InvalidArgumentException * * @return void */ public static function nullOrValidArrayKey($value, $message = '') { null === $value || static::validArrayKey($value, $message); } /** * @psalm-pure * @psalm-assert iterable $value * * @param mixed $value * @param string $message * * @throws InvalidArgumentException * * @return void */ public static function allValidArrayKey($value, $message = '') { static::isIterable($value); foreach ($value as $entry) { static::validArrayKey($entry, $message); } } /** * @psalm-pure * @psalm-assert iterable $value * * @param mixed $value * @param string $message * * @throws InvalidArgumentException * * @return void */ public static function allNullOrValidArrayKey($value, $message = '') { static::isIterable($value); foreach ($value as $entry) { null === $entry || static::validArrayKey($entry, $message); } } /** * @param Countable|array|null $array * @param int $number * @param string $message * * @throws InvalidArgumentException * * @return void */ public static function nullOrCount($array, $number, $message = '') { null === $array || static::count($array, $number, $message); } /** * @param iterable $array * @param int $number * @param string $message * * @throws InvalidArgumentException * * @return void */ public static function allCount($array, $number, $message = '') { static::isIterable($array); foreach ($array as $entry) { static::count($entry, $number, $message); } } /** * @param iterable $array * @param int $number * @param string $message * * @throws InvalidArgumentException * * @return void */ public static function allNullOrCount($array, $number, $message = '') { static::isIterable($array); foreach ($array as $entry) { null === $entry || static::count($entry, $number, $message); } } /** * @param Countable|array|null $array * @param int|float $min * @param string $message * * @throws InvalidArgumentException * * @return void */ public static function nullOrMinCount($array, $min, $message = '') { null === $array || static::minCount($array, $min, $message); } /** * @param iterable $array * @param int|float $min * @param string $message * * @throws InvalidArgumentException * * @return void */ public static function allMinCount($array, $min, $message = '') { static::isIterable($array); foreach ($array as $entry) { static::minCount($entry, $min, $message); } } /** * @param iterable $array * @param int|float $min * @param string $message * * @throws InvalidArgumentException * * @return void */ public static function allNullOrMinCount($array, $min, $message = '') { static::isIterable($array); foreach ($array as $entry) { null === $entry || static::minCount($entry, $min, $message); } } /** * @param Countable|array|null $array * @param int|float $max * @param string $message * * @throws InvalidArgumentException * * @return void */ public static function nullOrMaxCount($array, $max, $message = '') { null === $array || static::maxCount($array, $max, $message); } /** * @param iterable $array * @param int|float $max * @param string $message * * @throws InvalidArgumentException * * @return void */ public static function allMaxCount($array, $max, $message = '') { static::isIterable($array); foreach ($array as $entry) { static::maxCount($entry, $max, $message); } } /** * @param iterable $array * @param int|float $max * @param string $message * * @throws InvalidArgumentException * * @return void */ public static function allNullOrMaxCount($array, $max, $message = '') { static::isIterable($array); foreach ($array as $entry) { null === $entry || static::maxCount($entry, $max, $message); } } /** * @param Countable|array|null $array * @param int|float $min * @param int|float $max * @param string $message * * @throws InvalidArgumentException * * @return void */ public static function nullOrCountBetween($array, $min, $max, $message = '') { null === $array || static::countBetween($array, $min, $max, $message); } /** * @param iterable $array * @param int|float $min * @param int|float $max * @param string $message * * @throws InvalidArgumentException * * @return void */ public static function allCountBetween($array, $min, $max, $message = '') { static::isIterable($array); foreach ($array as $entry) { static::countBetween($entry, $min, $max, $message); } } /** * @param iterable $array * @param int|float $min * @param int|float $max * @param string $message * * @throws InvalidArgumentException * * @return void */ public static function allNullOrCountBetween($array, $min, $max, $message = '') { static::isIterable($array); foreach ($array as $entry) { null === $entry || static::countBetween($entry, $min, $max, $message); } } /** * @psalm-pure * @psalm-assert list|null $array * * @param mixed $array * @param string $message * * @throws InvalidArgumentException * * @return void */ public static function nullOrIsList($array, $message = '') { null === $array || static::isList($array, $message); } /** * @psalm-pure * @psalm-assert iterable $array * * @param mixed $array * @param string $message * * @throws InvalidArgumentException * * @return void */ public static function allIsList($array, $message = '') { static::isIterable($array); foreach ($array as $entry) { static::isList($entry, $message); } } /** * @psalm-pure * @psalm-assert iterable $array * * @param mixed $array * @param string $message * * @throws InvalidArgumentException * * @return void */ public static function allNullOrIsList($array, $message = '') { static::isIterable($array); foreach ($array as $entry) { null === $entry || static::isList($entry, $message); } } /** * @psalm-pure * @psalm-assert non-empty-list|null $array * * @param mixed $array * @param string $message * * @throws InvalidArgumentException * * @return void */ public static function nullOrIsNonEmptyList($array, $message = '') { null === $array || static::isNonEmptyList($array, $message); } /** * @psalm-pure * @psalm-assert iterable $array * * @param mixed $array * @param string $message * * @throws InvalidArgumentException * * @return void */ public static function allIsNonEmptyList($array, $message = '') { static::isIterable($array); foreach ($array as $entry) { static::isNonEmptyList($entry, $message); } } /** * @psalm-pure * @psalm-assert iterable $array * * @param mixed $array * @param string $message * * @throws InvalidArgumentException * * @return void */ public static function allNullOrIsNonEmptyList($array, $message = '') { static::isIterable($array); foreach ($array as $entry) { null === $entry || static::isNonEmptyList($entry, $message); } } /** * @psalm-pure * @psalm-template T * @psalm-param mixed|array|null $array * @psalm-assert array|null $array * * @param mixed $array * @param string $message * * @throws InvalidArgumentException * * @return void */ public static function nullOrIsMap($array, $message = '') { null === $array || static::isMap($array, $message); } /** * @psalm-pure * @psalm-template T * @psalm-param iterable> $array * @psalm-assert iterable> $array * * @param mixed $array * @param string $message * * @throws InvalidArgumentException * * @return void */ public static function allIsMap($array, $message = '') { static::isIterable($array); foreach ($array as $entry) { static::isMap($entry, $message); } } /** * @psalm-pure * @psalm-template T * @psalm-param iterable|null> $array * @psalm-assert iterable|null> $array * * @param mixed $array * @param string $message * * @throws InvalidArgumentException * * @return void */ public static function allNullOrIsMap($array, $message = '') { static::isIterable($array); foreach ($array as $entry) { null === $entry || static::isMap($entry, $message); } } /** * @psalm-pure * @psalm-template T * @psalm-param mixed|array|null $array * * @param mixed $array * @param string $message * * @throws InvalidArgumentException * * @return void */ public static function nullOrIsNonEmptyMap($array, $message = '') { null === $array || static::isNonEmptyMap($array, $message); } /** * @psalm-pure * @psalm-template T * @psalm-param iterable> $array * * @param mixed $array * @param string $message * * @throws InvalidArgumentException * * @return void */ public static function allIsNonEmptyMap($array, $message = '') { static::isIterable($array); foreach ($array as $entry) { static::isNonEmptyMap($entry, $message); } } /** * @psalm-pure * @psalm-template T * @psalm-param iterable|null> $array * @psalm-assert iterable|null> $array * @psalm-assert iterable $array * * @param mixed $array * @param string $message * * @throws InvalidArgumentException * * @return void */ public static function allNullOrIsNonEmptyMap($array, $message = '') { static::isIterable($array); foreach ($array as $entry) { null === $entry || static::isNonEmptyMap($entry, $message); } } /** * @psalm-pure * * @param string|null $value * @param string $message * * @throws InvalidArgumentException * * @return void */ public static function nullOrUuid($value, $message = '') { null === $value || static::uuid($value, $message); } /** * @psalm-pure * * @param iterable $value * @param string $message * * @throws InvalidArgumentException * * @return void */ public static function allUuid($value, $message = '') { static::isIterable($value); foreach ($value as $entry) { static::uuid($entry, $message); } } /** * @psalm-pure * * @param iterable $value * @param string $message * * @throws InvalidArgumentException * * @return void */ public static function allNullOrUuid($value, $message = '') { static::isIterable($value); foreach ($value as $entry) { null === $entry || static::uuid($entry, $message); } } /** * @psalm-param class-string $class * * @param Closure|null $expression * @param string $class * @param string $message * * @throws InvalidArgumentException * * @return void */ public static function nullOrThrows($expression, $class = 'Exception', $message = '') { null === $expression || static::throws($expression, $class, $message); } /** * @psalm-param class-string $class * * @param iterable $expression * @param string $class * @param string $message * * @throws InvalidArgumentException * * @return void */ public static function allThrows($expression, $class = 'Exception', $message = '') { static::isIterable($expression); foreach ($expression as $entry) { static::throws($entry, $class, $message); } } /** * @psalm-param class-string $class * * @param iterable $expression * @param string $class * @param string $message * * @throws InvalidArgumentException * * @return void */ public static function allNullOrThrows($expression, $class = 'Exception', $message = '') { static::isIterable($expression); foreach ($expression as $entry) { null === $entry || static::throws($entry, $class, $message); } } } * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace _HumbugBox7ff99e199a36\Webmozart\Assert; class InvalidArgumentException extends \InvalidArgumentException { } BSD 3-Clause License Copyright (c) 2011, Nikita Popov All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #!/usr/bin/env php ['startLine', 'endLine', 'startFilePos', 'endFilePos', 'comments']]); $parser = (new PhpParser\ParserFactory())->create(PhpParser\ParserFactory::PREFER_PHP7, $lexer); $dumper = new PhpParser\NodeDumper(['dumpComments' => \true, 'dumpPositions' => $attributes['with-positions']]); $prettyPrinter = new PhpParser\PrettyPrinter\Standard(); $traverser = new PhpParser\NodeTraverser(); $traverser->addVisitor(new PhpParser\NodeVisitor\NameResolver()); foreach ($files as $file) { if (\strpos($file, ' Code {$code}\n"); } else { if (!\file_exists($file)) { \fwrite(\STDERR, "File {$file} does not exist.\n"); exit(1); } $code = \file_get_contents($file); \fwrite(\STDERR, "====> File {$file}:\n"); } if ($attributes['with-recovery']) { $errorHandler = new PhpParser\ErrorHandler\Collecting(); $stmts = $parser->parse($code, $errorHandler); foreach ($errorHandler->getErrors() as $error) { $message = formatErrorMessage($error, $code, $attributes['with-column-info']); \fwrite(\STDERR, $message . "\n"); } if (null === $stmts) { continue; } } else { try { $stmts = $parser->parse($code); } catch (PhpParser\Error $error) { $message = formatErrorMessage($error, $code, $attributes['with-column-info']); \fwrite(\STDERR, $message . "\n"); exit(1); } } foreach ($operations as $operation) { if ('dump' === $operation) { \fwrite(\STDERR, "==> Node dump:\n"); echo $dumper->dump($stmts, $code), "\n"; } elseif ('pretty-print' === $operation) { \fwrite(\STDERR, "==> Pretty print:\n"); echo $prettyPrinter->prettyPrintFile($stmts), "\n"; } elseif ('json-dump' === $operation) { \fwrite(\STDERR, "==> JSON dump:\n"); echo \json_encode($stmts, \JSON_PRETTY_PRINT), "\n"; } elseif ('var-dump' === $operation) { \fwrite(\STDERR, "==> var_dump():\n"); \var_dump($stmts); } elseif ('resolve-names' === $operation) { \fwrite(\STDERR, "==> Resolved names.\n"); $stmts = $traverser->traverse($stmts); } } } function formatErrorMessage(PhpParser\Error $e, $code, $withColumnInfo) { if ($withColumnInfo && $e->hasColumnInfo()) { return $e->getMessageWithColumnInfo($code); } else { return $e->getMessage(); } } function showHelp($error = '') { if ($error) { \fwrite(\STDERR, $error . "\n\n"); } \fwrite($error ? \STDERR : \STDOUT, << \false, 'with-positions' => \false, 'with-recovery' => \false]; \array_shift($args); $parseOptions = \true; foreach ($args as $arg) { if (!$parseOptions) { $files[] = $arg; continue; } switch ($arg) { case '--dump': case '-d': $operations[] = 'dump'; break; case '--pretty-print': case '-p': $operations[] = 'pretty-print'; break; case '--json-dump': case '-j': $operations[] = 'json-dump'; break; case '--var-dump': $operations[] = 'var-dump'; break; case '--resolve-names': case '-N': $operations[] = 'resolve-names'; break; case '--with-column-info': case '-c': $attributes['with-column-info'] = \true; break; case '--with-positions': case '-P': $attributes['with-positions'] = \true; break; case '--with-recovery': case '-r': $attributes['with-recovery'] = \true; break; case '--help': case '-h': showHelp(); break; case '--': $parseOptions = \false; break; default: if ($arg[0] === '-') { showHelp("Invalid operation {$arg}."); } else { $files[] = $arg; } } } return [$operations, $files, $attributes]; } [0, 1], Expr\BitwiseNot::class => [10, 1], Expr\PreInc::class => [10, 1], Expr\PreDec::class => [10, 1], Expr\PostInc::class => [10, -1], Expr\PostDec::class => [10, -1], Expr\UnaryPlus::class => [10, 1], Expr\UnaryMinus::class => [10, 1], Cast\Int_::class => [10, 1], Cast\Double::class => [10, 1], Cast\String_::class => [10, 1], Cast\Array_::class => [10, 1], Cast\Object_::class => [10, 1], Cast\Bool_::class => [10, 1], Cast\Unset_::class => [10, 1], Expr\ErrorSuppress::class => [10, 1], Expr\Instanceof_::class => [20, 0], Expr\BooleanNot::class => [30, 1], BinaryOp\Mul::class => [40, -1], BinaryOp\Div::class => [40, -1], BinaryOp\Mod::class => [40, -1], BinaryOp\Plus::class => [50, -1], BinaryOp\Minus::class => [50, -1], BinaryOp\Concat::class => [50, -1], BinaryOp\ShiftLeft::class => [60, -1], BinaryOp\ShiftRight::class => [60, -1], BinaryOp\Smaller::class => [70, 0], BinaryOp\SmallerOrEqual::class => [70, 0], BinaryOp\Greater::class => [70, 0], BinaryOp\GreaterOrEqual::class => [70, 0], BinaryOp\Equal::class => [80, 0], BinaryOp\NotEqual::class => [80, 0], BinaryOp\Identical::class => [80, 0], BinaryOp\NotIdentical::class => [80, 0], BinaryOp\Spaceship::class => [80, 0], BinaryOp\BitwiseAnd::class => [90, -1], BinaryOp\BitwiseXor::class => [100, -1], BinaryOp\BitwiseOr::class => [110, -1], BinaryOp\BooleanAnd::class => [120, -1], BinaryOp\BooleanOr::class => [130, -1], BinaryOp\Coalesce::class => [140, 1], Expr\Ternary::class => [150, 0], // parser uses %left for assignments, but they really behave as %right Expr\Assign::class => [160, 1], Expr\AssignRef::class => [160, 1], AssignOp\Plus::class => [160, 1], AssignOp\Minus::class => [160, 1], AssignOp\Mul::class => [160, 1], AssignOp\Div::class => [160, 1], AssignOp\Concat::class => [160, 1], AssignOp\Mod::class => [160, 1], AssignOp\BitwiseAnd::class => [160, 1], AssignOp\BitwiseOr::class => [160, 1], AssignOp\BitwiseXor::class => [160, 1], AssignOp\ShiftLeft::class => [160, 1], AssignOp\ShiftRight::class => [160, 1], AssignOp\Pow::class => [160, 1], AssignOp\Coalesce::class => [160, 1], Expr\YieldFrom::class => [165, 1], Expr\Print_::class => [168, 1], BinaryOp\LogicalAnd::class => [170, -1], BinaryOp\LogicalXor::class => [180, -1], BinaryOp\LogicalOr::class => [190, -1], Expr\Include_::class => [200, -1], ]; /** @var int Current indentation level. */ protected $indentLevel; /** @var string Newline including current indentation. */ protected $nl; /** @var string Token placed at end of doc string to ensure it is followed by a newline. */ protected $docStringEndToken; /** @var bool Whether semicolon namespaces can be used (i.e. no global namespace is used) */ protected $canUseSemicolonNamespaces; /** @var array Pretty printer options */ protected $options; /** @var TokenStream Original tokens for use in format-preserving pretty print */ protected $origTokens; /** @var Internal\Differ Differ for node lists */ protected $nodeListDiffer; /** @var bool[] Map determining whether a certain character is a label character */ protected $labelCharMap; /** * @var int[][] Map from token classes and subnode names to FIXUP_* constants. This is used * during format-preserving prints to place additional parens/braces if necessary. */ protected $fixupMap; /** * @var int[][] Map from "{$node->getType()}->{$subNode}" to ['left' => $l, 'right' => $r], * where $l and $r specify the token type that needs to be stripped when removing * this node. */ protected $removalMap; /** * @var mixed[] Map from "{$node->getType()}->{$subNode}" to [$find, $beforeToken, $extraLeft, $extraRight]. * $find is an optional token after which the insertion occurs. $extraLeft/Right * are optionally added before/after the main insertions. */ protected $insertionMap; /** * @var string[] Map From "{$node->getType()}->{$subNode}" to string that should be inserted * between elements of this list subnode. */ protected $listInsertionMap; protected $emptyListInsertionMap; /** @var int[] Map from "{$node->getType()}->{$subNode}" to token before which the modifiers * should be reprinted. */ protected $modifierChangeMap; /** * Creates a pretty printer instance using the given options. * * Supported options: * * bool $shortArraySyntax = false: Whether to use [] instead of array() as the default array * syntax, if the node does not specify a format. * * @param array $options Dictionary of formatting options */ public function __construct(array $options = []) { $this->docStringEndToken = '_DOC_STRING_END_' . \mt_rand(); $defaultOptions = ['shortArraySyntax' => \false]; $this->options = $options + $defaultOptions; } /** * Reset pretty printing state. */ protected function resetState() { $this->indentLevel = 0; $this->nl = "\n"; $this->origTokens = null; } /** * Set indentation level * * @param int $level Level in number of spaces */ protected function setIndentLevel(int $level) { $this->indentLevel = $level; $this->nl = "\n" . \str_repeat(' ', $level); } /** * Increase indentation level. */ protected function indent() { $this->indentLevel += 4; $this->nl .= ' '; } /** * Decrease indentation level. */ protected function outdent() { \assert($this->indentLevel >= 4); $this->indentLevel -= 4; $this->nl = "\n" . \str_repeat(' ', $this->indentLevel); } /** * Pretty prints an array of statements. * * @param Node[] $stmts Array of statements * * @return string Pretty printed statements */ public function prettyPrint(array $stmts) : string { $this->resetState(); $this->preprocessNodes($stmts); return \ltrim($this->handleMagicTokens($this->pStmts($stmts, \false))); } /** * Pretty prints an expression. * * @param Expr $node Expression node * * @return string Pretty printed node */ public function prettyPrintExpr(Expr $node) : string { $this->resetState(); return $this->handleMagicTokens($this->p($node)); } /** * Pretty prints a file of statements (includes the opening prettyPrint($stmts); if ($stmts[0] instanceof Stmt\InlineHTML) { $p = \preg_replace('/^<\\?php\\s+\\?>\\n?/', '', $p); } if ($stmts[\count($stmts) - 1] instanceof Stmt\InlineHTML) { $p = \preg_replace('/<\\?php$/', '', \rtrim($p)); } return $p; } /** * Preprocesses the top-level nodes to initialize pretty printer state. * * @param Node[] $nodes Array of nodes */ protected function preprocessNodes(array $nodes) { /* We can use semicolon-namespaces unless there is a global namespace declaration */ $this->canUseSemicolonNamespaces = \true; foreach ($nodes as $node) { if ($node instanceof Stmt\Namespace_ && null === $node->name) { $this->canUseSemicolonNamespaces = \false; break; } } } /** * Handles (and removes) no-indent and doc-string-end tokens. * * @param string $str * @return string */ protected function handleMagicTokens(string $str) : string { // Replace doc-string-end tokens with nothing or a newline $str = \str_replace($this->docStringEndToken . ";\n", ";\n", $str); $str = \str_replace($this->docStringEndToken, "\n", $str); return $str; } /** * Pretty prints an array of nodes (statements) and indents them optionally. * * @param Node[] $nodes Array of nodes * @param bool $indent Whether to indent the printed nodes * * @return string Pretty printed statements */ protected function pStmts(array $nodes, bool $indent = \true) : string { if ($indent) { $this->indent(); } $result = ''; foreach ($nodes as $node) { $comments = $node->getComments(); if ($comments) { $result .= $this->nl . $this->pComments($comments); if ($node instanceof Stmt\Nop) { continue; } } $result .= $this->nl . $this->p($node); } if ($indent) { $this->outdent(); } return $result; } /** * Pretty-print an infix operation while taking precedence into account. * * @param string $class Node class of operator * @param Node $leftNode Left-hand side node * @param string $operatorString String representation of the operator * @param Node $rightNode Right-hand side node * * @return string Pretty printed infix operation */ protected function pInfixOp(string $class, Node $leftNode, string $operatorString, Node $rightNode) : string { list($precedence, $associativity) = $this->precedenceMap[$class]; return $this->pPrec($leftNode, $precedence, $associativity, -1) . $operatorString . $this->pPrec($rightNode, $precedence, $associativity, 1); } /** * Pretty-print a prefix operation while taking precedence into account. * * @param string $class Node class of operator * @param string $operatorString String representation of the operator * @param Node $node Node * * @return string Pretty printed prefix operation */ protected function pPrefixOp(string $class, string $operatorString, Node $node) : string { list($precedence, $associativity) = $this->precedenceMap[$class]; return $operatorString . $this->pPrec($node, $precedence, $associativity, 1); } /** * Pretty-print a postfix operation while taking precedence into account. * * @param string $class Node class of operator * @param string $operatorString String representation of the operator * @param Node $node Node * * @return string Pretty printed postfix operation */ protected function pPostfixOp(string $class, Node $node, string $operatorString) : string { list($precedence, $associativity) = $this->precedenceMap[$class]; return $this->pPrec($node, $precedence, $associativity, -1) . $operatorString; } /** * Prints an expression node with the least amount of parentheses necessary to preserve the meaning. * * @param Node $node Node to pretty print * @param int $parentPrecedence Precedence of the parent operator * @param int $parentAssociativity Associativity of parent operator * (-1 is left, 0 is nonassoc, 1 is right) * @param int $childPosition Position of the node relative to the operator * (-1 is left, 1 is right) * * @return string The pretty printed node */ protected function pPrec(Node $node, int $parentPrecedence, int $parentAssociativity, int $childPosition) : string { $class = \get_class($node); if (isset($this->precedenceMap[$class])) { $childPrecedence = $this->precedenceMap[$class][0]; if ($childPrecedence > $parentPrecedence || $parentPrecedence === $childPrecedence && $parentAssociativity !== $childPosition) { return '(' . $this->p($node) . ')'; } } return $this->p($node); } /** * Pretty prints an array of nodes and implodes the printed values. * * @param Node[] $nodes Array of Nodes to be printed * @param string $glue Character to implode with * * @return string Imploded pretty printed nodes */ protected function pImplode(array $nodes, string $glue = '') : string { $pNodes = []; foreach ($nodes as $node) { if (null === $node) { $pNodes[] = ''; } else { $pNodes[] = $this->p($node); } } return \implode($glue, $pNodes); } /** * Pretty prints an array of nodes and implodes the printed values with commas. * * @param Node[] $nodes Array of Nodes to be printed * * @return string Comma separated pretty printed nodes */ protected function pCommaSeparated(array $nodes) : string { return $this->pImplode($nodes, ', '); } /** * Pretty prints a comma-separated list of nodes in multiline style, including comments. * * The result includes a leading newline and one level of indentation (same as pStmts). * * @param Node[] $nodes Array of Nodes to be printed * @param bool $trailingComma Whether to use a trailing comma * * @return string Comma separated pretty printed nodes in multiline style */ protected function pCommaSeparatedMultiline(array $nodes, bool $trailingComma) : string { $this->indent(); $result = ''; $lastIdx = \count($nodes) - 1; foreach ($nodes as $idx => $node) { if ($node !== null) { $comments = $node->getComments(); if ($comments) { $result .= $this->nl . $this->pComments($comments); } $result .= $this->nl . $this->p($node); } else { $result .= $this->nl; } if ($trailingComma || $idx !== $lastIdx) { $result .= ','; } } $this->outdent(); return $result; } /** * Prints reformatted text of the passed comments. * * @param Comment[] $comments List of comments * * @return string Reformatted text of comments */ protected function pComments(array $comments) : string { $formattedComments = []; foreach ($comments as $comment) { $formattedComments[] = \str_replace("\n", $this->nl, $comment->getReformattedText()); } return \implode($this->nl, $formattedComments); } /** * Perform a format-preserving pretty print of an AST. * * The format preservation is best effort. For some changes to the AST the formatting will not * be preserved (at least not locally). * * In order to use this method a number of prerequisites must be satisfied: * * The startTokenPos and endTokenPos attributes in the lexer must be enabled. * * The CloningVisitor must be run on the AST prior to modification. * * The original tokens must be provided, using the getTokens() method on the lexer. * * @param Node[] $stmts Modified AST with links to original AST * @param Node[] $origStmts Original AST with token offset information * @param array $origTokens Tokens of the original code * * @return string */ public function printFormatPreserving(array $stmts, array $origStmts, array $origTokens) : string { $this->initializeNodeListDiffer(); $this->initializeLabelCharMap(); $this->initializeFixupMap(); $this->initializeRemovalMap(); $this->initializeInsertionMap(); $this->initializeListInsertionMap(); $this->initializeEmptyListInsertionMap(); $this->initializeModifierChangeMap(); $this->resetState(); $this->origTokens = new TokenStream($origTokens); $this->preprocessNodes($stmts); $pos = 0; $result = $this->pArray($stmts, $origStmts, $pos, 0, 'File', 'stmts', null); if (null !== $result) { $result .= $this->origTokens->getTokenCode($pos, \count($origTokens), 0); } else { // Fallback // TODO Add pStmts($stmts, \false); } return \ltrim($this->handleMagicTokens($result)); } protected function pFallback(Node $node) { return $this->{'p' . $node->getType()}($node); } /** * Pretty prints a node. * * This method also handles formatting preservation for nodes. * * @param Node $node Node to be pretty printed * @param bool $parentFormatPreserved Whether parent node has preserved formatting * * @return string Pretty printed node */ protected function p(Node $node, $parentFormatPreserved = \false) : string { // No orig tokens means this is a normal pretty print without preservation of formatting if (!$this->origTokens) { return $this->{'p' . $node->getType()}($node); } /** @var Node $origNode */ $origNode = $node->getAttribute('origNode'); if (null === $origNode) { return $this->pFallback($node); } $class = \get_class($node); \assert($class === \get_class($origNode)); $startPos = $origNode->getStartTokenPos(); $endPos = $origNode->getEndTokenPos(); \assert($startPos >= 0 && $endPos >= 0); $fallbackNode = $node; if ($node instanceof Expr\New_ && $node->class instanceof Stmt\Class_) { // Normalize node structure of anonymous classes $node = PrintableNewAnonClassNode::fromNewNode($node); $origNode = PrintableNewAnonClassNode::fromNewNode($origNode); } // InlineHTML node does not contain closing and opening PHP tags. If the parent formatting // is not preserved, then we need to use the fallback code to make sure the tags are // printed. if ($node instanceof Stmt\InlineHTML && !$parentFormatPreserved) { return $this->pFallback($fallbackNode); } $indentAdjustment = $this->indentLevel - $this->origTokens->getIndentationBefore($startPos); $type = $node->getType(); $fixupInfo = $this->fixupMap[$class] ?? null; $result = ''; $pos = $startPos; foreach ($node->getSubNodeNames() as $subNodeName) { $subNode = $node->{$subNodeName}; $origSubNode = $origNode->{$subNodeName}; if (!$subNode instanceof Node && $subNode !== null || !$origSubNode instanceof Node && $origSubNode !== null) { if ($subNode === $origSubNode) { // Unchanged, can reuse old code continue; } if (\is_array($subNode) && \is_array($origSubNode)) { // Array subnode changed, we might be able to reconstruct it $listResult = $this->pArray($subNode, $origSubNode, $pos, $indentAdjustment, $type, $subNodeName, $fixupInfo[$subNodeName] ?? null); if (null === $listResult) { return $this->pFallback($fallbackNode); } $result .= $listResult; continue; } if (\is_int($subNode) && \is_int($origSubNode)) { // Check if this is a modifier change $key = $type . '->' . $subNodeName; if (!isset($this->modifierChangeMap[$key])) { return $this->pFallback($fallbackNode); } $findToken = $this->modifierChangeMap[$key]; $result .= $this->pModifiers($subNode); $pos = $this->origTokens->findRight($pos, $findToken); continue; } // If a non-node, non-array subnode changed, we don't be able to do a partial // reconstructions, as we don't have enough offset information. Pretty print the // whole node instead. return $this->pFallback($fallbackNode); } $extraLeft = ''; $extraRight = ''; if ($origSubNode !== null) { $subStartPos = $origSubNode->getStartTokenPos(); $subEndPos = $origSubNode->getEndTokenPos(); \assert($subStartPos >= 0 && $subEndPos >= 0); } else { if ($subNode === null) { // Both null, nothing to do continue; } // A node has been inserted, check if we have insertion information for it $key = $type . '->' . $subNodeName; if (!isset($this->insertionMap[$key])) { return $this->pFallback($fallbackNode); } list($findToken, $beforeToken, $extraLeft, $extraRight) = $this->insertionMap[$key]; if (null !== $findToken) { $subStartPos = $this->origTokens->findRight($pos, $findToken) + (int) (!$beforeToken); } else { $subStartPos = $pos; } if (null === $extraLeft && null !== $extraRight) { // If inserting on the right only, skipping whitespace looks better $subStartPos = $this->origTokens->skipRightWhitespace($subStartPos); } $subEndPos = $subStartPos - 1; } if (null === $subNode) { // A node has been removed, check if we have removal information for it $key = $type . '->' . $subNodeName; if (!isset($this->removalMap[$key])) { return $this->pFallback($fallbackNode); } // Adjust positions to account for additional tokens that must be skipped $removalInfo = $this->removalMap[$key]; if (isset($removalInfo['left'])) { $subStartPos = $this->origTokens->skipLeft($subStartPos - 1, $removalInfo['left']) + 1; } if (isset($removalInfo['right'])) { $subEndPos = $this->origTokens->skipRight($subEndPos + 1, $removalInfo['right']) - 1; } } $result .= $this->origTokens->getTokenCode($pos, $subStartPos, $indentAdjustment); if (null !== $subNode) { $result .= $extraLeft; $origIndentLevel = $this->indentLevel; $this->setIndentLevel($this->origTokens->getIndentationBefore($subStartPos) + $indentAdjustment); // If it's the same node that was previously in this position, it certainly doesn't // need fixup. It's important to check this here, because our fixup checks are more // conservative than strictly necessary. if (isset($fixupInfo[$subNodeName]) && $subNode->getAttribute('origNode') !== $origSubNode) { $fixup = $fixupInfo[$subNodeName]; $res = $this->pFixup($fixup, $subNode, $class, $subStartPos, $subEndPos); } else { $res = $this->p($subNode, \true); } $this->safeAppend($result, $res); $this->setIndentLevel($origIndentLevel); $result .= $extraRight; } $pos = $subEndPos + 1; } $result .= $this->origTokens->getTokenCode($pos, $endPos + 1, $indentAdjustment); return $result; } /** * Perform a format-preserving pretty print of an array. * * @param array $nodes New nodes * @param array $origNodes Original nodes * @param int $pos Current token position (updated by reference) * @param int $indentAdjustment Adjustment for indentation * @param string $parentNodeType Type of the containing node. * @param string $subNodeName Name of array subnode. * @param null|int $fixup Fixup information for array item nodes * * @return null|string Result of pretty print or null if cannot preserve formatting */ protected function pArray(array $nodes, array $origNodes, int &$pos, int $indentAdjustment, string $parentNodeType, string $subNodeName, $fixup) { $diff = $this->nodeListDiffer->diffWithReplacements($origNodes, $nodes); $mapKey = $parentNodeType . '->' . $subNodeName; $insertStr = $this->listInsertionMap[$mapKey] ?? null; $isStmtList = $subNodeName === 'stmts'; $beforeFirstKeepOrReplace = \true; $skipRemovedNode = \false; $delayedAdd = []; $lastElemIndentLevel = $this->indentLevel; $insertNewline = \false; if ($insertStr === "\n") { $insertStr = ''; $insertNewline = \true; } if ($isStmtList && \count($origNodes) === 1 && \count($nodes) !== 1) { $startPos = $origNodes[0]->getStartTokenPos(); $endPos = $origNodes[0]->getEndTokenPos(); \assert($startPos >= 0 && $endPos >= 0); if (!$this->origTokens->haveBraces($startPos, $endPos)) { // This was a single statement without braces, but either additional statements // have been added, or the single statement has been removed. This requires the // addition of braces. For now fall back. // TODO: Try to preserve formatting return null; } } $result = ''; foreach ($diff as $i => $diffElem) { $diffType = $diffElem->type; /** @var Node|null $arrItem */ $arrItem = $diffElem->new; /** @var Node|null $origArrItem */ $origArrItem = $diffElem->old; if ($diffType === DiffElem::TYPE_KEEP || $diffType === DiffElem::TYPE_REPLACE) { $beforeFirstKeepOrReplace = \false; if ($origArrItem === null || $arrItem === null) { // We can only handle the case where both are null if ($origArrItem === $arrItem) { continue; } return null; } if (!$arrItem instanceof Node || !$origArrItem instanceof Node) { // We can only deal with nodes. This can occur for Names, which use string arrays. return null; } $itemStartPos = $origArrItem->getStartTokenPos(); $itemEndPos = $origArrItem->getEndTokenPos(); \assert($itemStartPos >= 0 && $itemEndPos >= 0 && $itemStartPos >= $pos); $origIndentLevel = $this->indentLevel; $lastElemIndentLevel = $this->origTokens->getIndentationBefore($itemStartPos) + $indentAdjustment; $this->setIndentLevel($lastElemIndentLevel); $comments = $arrItem->getComments(); $origComments = $origArrItem->getComments(); $commentStartPos = $origComments ? $origComments[0]->getStartTokenPos() : $itemStartPos; \assert($commentStartPos >= 0); if ($commentStartPos < $pos) { // Comments may be assigned to multiple nodes if they start at the same position. // Make sure we don't try to print them multiple times. $commentStartPos = $itemStartPos; } if ($skipRemovedNode) { if ($isStmtList && ($this->origTokens->haveBracesInRange($pos, $itemStartPos) || $this->origTokens->haveTagInRange($pos, $itemStartPos))) { // We'd remove the brace of a code block. // TODO: Preserve formatting. $this->setIndentLevel($origIndentLevel); return null; } } else { $result .= $this->origTokens->getTokenCode($pos, $commentStartPos, $indentAdjustment); } if (!empty($delayedAdd)) { /** @var Node $delayedAddNode */ foreach ($delayedAdd as $delayedAddNode) { if ($insertNewline) { $delayedAddComments = $delayedAddNode->getComments(); if ($delayedAddComments) { $result .= $this->pComments($delayedAddComments) . $this->nl; } } $this->safeAppend($result, $this->p($delayedAddNode, \true)); if ($insertNewline) { $result .= $insertStr . $this->nl; } else { $result .= $insertStr; } } $delayedAdd = []; } if ($comments !== $origComments) { if ($comments) { $result .= $this->pComments($comments) . $this->nl; } } else { $result .= $this->origTokens->getTokenCode($commentStartPos, $itemStartPos, $indentAdjustment); } // If we had to remove anything, we have done so now. $skipRemovedNode = \false; } elseif ($diffType === DiffElem::TYPE_ADD) { if (null === $insertStr) { // We don't have insertion information for this list type return null; } // We go multiline if the original code was multiline, // or if it's an array item with a comment above it. if ($insertStr === ', ' && ($this->isMultiline($origNodes) || $arrItem->getComments())) { $insertStr = ','; $insertNewline = \true; } if ($beforeFirstKeepOrReplace) { // Will be inserted at the next "replace" or "keep" element $delayedAdd[] = $arrItem; continue; } $itemStartPos = $pos; $itemEndPos = $pos - 1; $origIndentLevel = $this->indentLevel; $this->setIndentLevel($lastElemIndentLevel); if ($insertNewline) { $result .= $insertStr . $this->nl; $comments = $arrItem->getComments(); if ($comments) { $result .= $this->pComments($comments) . $this->nl; } } else { $result .= $insertStr; } } elseif ($diffType === DiffElem::TYPE_REMOVE) { if (!$origArrItem instanceof Node) { // We only support removal for nodes return null; } $itemStartPos = $origArrItem->getStartTokenPos(); $itemEndPos = $origArrItem->getEndTokenPos(); \assert($itemStartPos >= 0 && $itemEndPos >= 0); // Consider comments part of the node. $origComments = $origArrItem->getComments(); if ($origComments) { $itemStartPos = $origComments[0]->getStartTokenPos(); } if ($i === 0) { // If we're removing from the start, keep the tokens before the node and drop those after it, // instead of the other way around. $result .= $this->origTokens->getTokenCode($pos, $itemStartPos, $indentAdjustment); $skipRemovedNode = \true; } else { if ($isStmtList && ($this->origTokens->haveBracesInRange($pos, $itemStartPos) || $this->origTokens->haveTagInRange($pos, $itemStartPos))) { // We'd remove the brace of a code block. // TODO: Preserve formatting. return null; } } $pos = $itemEndPos + 1; continue; } else { throw new \Exception("Shouldn't happen"); } if (null !== $fixup && $arrItem->getAttribute('origNode') !== $origArrItem) { $res = $this->pFixup($fixup, $arrItem, null, $itemStartPos, $itemEndPos); } else { $res = $this->p($arrItem, \true); } $this->safeAppend($result, $res); $this->setIndentLevel($origIndentLevel); $pos = $itemEndPos + 1; } if ($skipRemovedNode) { // TODO: Support removing single node. return null; } if (!empty($delayedAdd)) { if (!isset($this->emptyListInsertionMap[$mapKey])) { return null; } list($findToken, $extraLeft, $extraRight) = $this->emptyListInsertionMap[$mapKey]; if (null !== $findToken) { $insertPos = $this->origTokens->findRight($pos, $findToken) + 1; $result .= $this->origTokens->getTokenCode($pos, $insertPos, $indentAdjustment); $pos = $insertPos; } $first = \true; $result .= $extraLeft; foreach ($delayedAdd as $delayedAddNode) { if (!$first) { $result .= $insertStr; if ($insertNewline) { $result .= $this->nl; } } $result .= $this->p($delayedAddNode, \true); $first = \false; } $result .= $extraRight === "\n" ? $this->nl : $extraRight; } return $result; } /** * Print node with fixups. * * Fixups here refer to the addition of extra parentheses, braces or other characters, that * are required to preserve program semantics in a certain context (e.g. to maintain precedence * or because only certain expressions are allowed in certain places). * * @param int $fixup Fixup type * @param Node $subNode Subnode to print * @param string|null $parentClass Class of parent node * @param int $subStartPos Original start pos of subnode * @param int $subEndPos Original end pos of subnode * * @return string Result of fixed-up print of subnode */ protected function pFixup(int $fixup, Node $subNode, $parentClass, int $subStartPos, int $subEndPos) : string { switch ($fixup) { case self::FIXUP_PREC_LEFT: case self::FIXUP_PREC_RIGHT: if (!$this->origTokens->haveParens($subStartPos, $subEndPos)) { list($precedence, $associativity) = $this->precedenceMap[$parentClass]; return $this->pPrec($subNode, $precedence, $associativity, $fixup === self::FIXUP_PREC_LEFT ? -1 : 1); } break; case self::FIXUP_CALL_LHS: if ($this->callLhsRequiresParens($subNode) && !$this->origTokens->haveParens($subStartPos, $subEndPos)) { return '(' . $this->p($subNode) . ')'; } break; case self::FIXUP_DEREF_LHS: if ($this->dereferenceLhsRequiresParens($subNode) && !$this->origTokens->haveParens($subStartPos, $subEndPos)) { return '(' . $this->p($subNode) . ')'; } break; case self::FIXUP_STATIC_DEREF_LHS: if ($this->staticDereferenceLhsRequiresParens($subNode) && !$this->origTokens->haveParens($subStartPos, $subEndPos)) { return '(' . $this->p($subNode) . ')'; } break; case self::FIXUP_NEW: if ($this->newOperandRequiresParens($subNode) && !$this->origTokens->haveParens($subStartPos, $subEndPos)) { return '(' . $this->p($subNode) . ')'; } break; case self::FIXUP_BRACED_NAME: case self::FIXUP_VAR_BRACED_NAME: if ($subNode instanceof Expr && !$this->origTokens->haveBraces($subStartPos, $subEndPos)) { return ($fixup === self::FIXUP_VAR_BRACED_NAME ? '$' : '') . '{' . $this->p($subNode) . '}'; } break; case self::FIXUP_ENCAPSED: if (!$subNode instanceof Scalar\EncapsedStringPart && !$this->origTokens->haveBraces($subStartPos, $subEndPos)) { return '{' . $this->p($subNode) . '}'; } break; default: throw new \Exception('Cannot happen'); } // Nothing special to do return $this->p($subNode); } /** * Appends to a string, ensuring whitespace between label characters. * * Example: "echo" and "$x" result in "echo$x", but "echo" and "x" result in "echo x". * Without safeAppend the result would be "echox", which does not preserve semantics. * * @param string $str * @param string $append */ protected function safeAppend(string &$str, string $append) { if ($str === "") { $str = $append; return; } if ($append === "") { return; } if (!$this->labelCharMap[$append[0]] || !$this->labelCharMap[$str[\strlen($str) - 1]]) { $str .= $append; } else { $str .= " " . $append; } } /** * Determines whether the LHS of a call must be wrapped in parenthesis. * * @param Node $node LHS of a call * * @return bool Whether parentheses are required */ protected function callLhsRequiresParens(Node $node) : bool { return !($node instanceof Node\Name || $node instanceof Expr\Variable || $node instanceof Expr\ArrayDimFetch || $node instanceof Expr\FuncCall || $node instanceof Expr\MethodCall || $node instanceof Expr\NullsafeMethodCall || $node instanceof Expr\StaticCall || $node instanceof Expr\Array_); } /** * Determines whether the LHS of an array/object operation must be wrapped in parentheses. * * @param Node $node LHS of dereferencing operation * * @return bool Whether parentheses are required */ protected function dereferenceLhsRequiresParens(Node $node) : bool { // A constant can occur on the LHS of an array/object deref, but not a static deref. return $this->staticDereferenceLhsRequiresParens($node) && !$node instanceof Expr\ConstFetch; } /** * Determines whether the LHS of a static operation must be wrapped in parentheses. * * @param Node $node LHS of dereferencing operation * * @return bool Whether parentheses are required */ protected function staticDereferenceLhsRequiresParens(Node $node) : bool { return !($node instanceof Expr\Variable || $node instanceof Node\Name || $node instanceof Expr\ArrayDimFetch || $node instanceof Expr\PropertyFetch || $node instanceof Expr\NullsafePropertyFetch || $node instanceof Expr\StaticPropertyFetch || $node instanceof Expr\FuncCall || $node instanceof Expr\MethodCall || $node instanceof Expr\NullsafeMethodCall || $node instanceof Expr\StaticCall || $node instanceof Expr\Array_ || $node instanceof Scalar\String_ || $node instanceof Expr\ClassConstFetch); } /** * Determines whether an expression used in "new" or "instanceof" requires parentheses. * * @param Node $node New or instanceof operand * * @return bool Whether parentheses are required */ protected function newOperandRequiresParens(Node $node) : bool { if ($node instanceof Node\Name || $node instanceof Expr\Variable) { return \false; } if ($node instanceof Expr\ArrayDimFetch || $node instanceof Expr\PropertyFetch || $node instanceof Expr\NullsafePropertyFetch) { return $this->newOperandRequiresParens($node->var); } if ($node instanceof Expr\StaticPropertyFetch) { return $this->newOperandRequiresParens($node->class); } return \true; } /** * Print modifiers, including trailing whitespace. * * @param int $modifiers Modifier mask to print * * @return string Printed modifiers */ protected function pModifiers(int $modifiers) { return ($modifiers & Stmt\Class_::MODIFIER_PUBLIC ? 'public ' : '') . ($modifiers & Stmt\Class_::MODIFIER_PROTECTED ? 'protected ' : '') . ($modifiers & Stmt\Class_::MODIFIER_PRIVATE ? 'private ' : '') . ($modifiers & Stmt\Class_::MODIFIER_STATIC ? 'static ' : '') . ($modifiers & Stmt\Class_::MODIFIER_ABSTRACT ? 'abstract ' : '') . ($modifiers & Stmt\Class_::MODIFIER_FINAL ? 'final ' : '') . ($modifiers & Stmt\Class_::MODIFIER_READONLY ? 'readonly ' : ''); } /** * Determine whether a list of nodes uses multiline formatting. * * @param (Node|null)[] $nodes Node list * * @return bool Whether multiline formatting is used */ protected function isMultiline(array $nodes) : bool { if (\count($nodes) < 2) { return \false; } $pos = -1; foreach ($nodes as $node) { if (null === $node) { continue; } $endPos = $node->getEndTokenPos() + 1; if ($pos >= 0) { $text = $this->origTokens->getTokenCode($pos, $endPos, 0); if (\false === \strpos($text, "\n")) { // We require that a newline is present between *every* item. If the formatting // is inconsistent, with only some items having newlines, we don't consider it // as multiline return \false; } } $pos = $endPos; } return \true; } /** * Lazily initializes label char map. * * The label char map determines whether a certain character may occur in a label. */ protected function initializeLabelCharMap() { if ($this->labelCharMap) { return; } $this->labelCharMap = []; for ($i = 0; $i < 256; $i++) { // Since PHP 7.1 The lower range is 0x80. However, we also want to support code for // older versions. $chr = \chr($i); $this->labelCharMap[$chr] = $i >= 0x7f || \ctype_alnum($chr); } } /** * Lazily initializes node list differ. * * The node list differ is used to determine differences between two array subnodes. */ protected function initializeNodeListDiffer() { if ($this->nodeListDiffer) { return; } $this->nodeListDiffer = new Internal\Differ(function ($a, $b) { if ($a instanceof Node && $b instanceof Node) { return $a === $b->getAttribute('origNode'); } // Can happen for array destructuring return $a === null && $b === null; }); } /** * Lazily initializes fixup map. * * The fixup map is used to determine whether a certain subnode of a certain node may require * some kind of "fixup" operation, e.g. the addition of parenthesis or braces. */ protected function initializeFixupMap() { if ($this->fixupMap) { return; } $this->fixupMap = [Expr\PreInc::class => ['var' => self::FIXUP_PREC_RIGHT], Expr\PreDec::class => ['var' => self::FIXUP_PREC_RIGHT], Expr\PostInc::class => ['var' => self::FIXUP_PREC_LEFT], Expr\PostDec::class => ['var' => self::FIXUP_PREC_LEFT], Expr\Instanceof_::class => ['expr' => self::FIXUP_PREC_LEFT, 'class' => self::FIXUP_NEW], Expr\Ternary::class => ['cond' => self::FIXUP_PREC_LEFT, 'else' => self::FIXUP_PREC_RIGHT], Expr\FuncCall::class => ['name' => self::FIXUP_CALL_LHS], Expr\StaticCall::class => ['class' => self::FIXUP_STATIC_DEREF_LHS], Expr\ArrayDimFetch::class => ['var' => self::FIXUP_DEREF_LHS], Expr\ClassConstFetch::class => ['class' => self::FIXUP_STATIC_DEREF_LHS, 'name' => self::FIXUP_BRACED_NAME], Expr\New_::class => ['class' => self::FIXUP_NEW], Expr\MethodCall::class => ['var' => self::FIXUP_DEREF_LHS, 'name' => self::FIXUP_BRACED_NAME], Expr\NullsafeMethodCall::class => ['var' => self::FIXUP_DEREF_LHS, 'name' => self::FIXUP_BRACED_NAME], Expr\StaticPropertyFetch::class => ['class' => self::FIXUP_STATIC_DEREF_LHS, 'name' => self::FIXUP_VAR_BRACED_NAME], Expr\PropertyFetch::class => ['var' => self::FIXUP_DEREF_LHS, 'name' => self::FIXUP_BRACED_NAME], Expr\NullsafePropertyFetch::class => ['var' => self::FIXUP_DEREF_LHS, 'name' => self::FIXUP_BRACED_NAME], Scalar\Encapsed::class => ['parts' => self::FIXUP_ENCAPSED]]; $binaryOps = [BinaryOp\Pow::class, BinaryOp\Mul::class, BinaryOp\Div::class, BinaryOp\Mod::class, BinaryOp\Plus::class, BinaryOp\Minus::class, BinaryOp\Concat::class, BinaryOp\ShiftLeft::class, BinaryOp\ShiftRight::class, BinaryOp\Smaller::class, BinaryOp\SmallerOrEqual::class, BinaryOp\Greater::class, BinaryOp\GreaterOrEqual::class, BinaryOp\Equal::class, BinaryOp\NotEqual::class, BinaryOp\Identical::class, BinaryOp\NotIdentical::class, BinaryOp\Spaceship::class, BinaryOp\BitwiseAnd::class, BinaryOp\BitwiseXor::class, BinaryOp\BitwiseOr::class, BinaryOp\BooleanAnd::class, BinaryOp\BooleanOr::class, BinaryOp\Coalesce::class, BinaryOp\LogicalAnd::class, BinaryOp\LogicalXor::class, BinaryOp\LogicalOr::class]; foreach ($binaryOps as $binaryOp) { $this->fixupMap[$binaryOp] = ['left' => self::FIXUP_PREC_LEFT, 'right' => self::FIXUP_PREC_RIGHT]; } $assignOps = [Expr\Assign::class, Expr\AssignRef::class, AssignOp\Plus::class, AssignOp\Minus::class, AssignOp\Mul::class, AssignOp\Div::class, AssignOp\Concat::class, AssignOp\Mod::class, AssignOp\BitwiseAnd::class, AssignOp\BitwiseOr::class, AssignOp\BitwiseXor::class, AssignOp\ShiftLeft::class, AssignOp\ShiftRight::class, AssignOp\Pow::class, AssignOp\Coalesce::class]; foreach ($assignOps as $assignOp) { $this->fixupMap[$assignOp] = ['var' => self::FIXUP_PREC_LEFT, 'expr' => self::FIXUP_PREC_RIGHT]; } $prefixOps = [Expr\BitwiseNot::class, Expr\BooleanNot::class, Expr\UnaryPlus::class, Expr\UnaryMinus::class, Cast\Int_::class, Cast\Double::class, Cast\String_::class, Cast\Array_::class, Cast\Object_::class, Cast\Bool_::class, Cast\Unset_::class, Expr\ErrorSuppress::class, Expr\YieldFrom::class, Expr\Print_::class, Expr\Include_::class]; foreach ($prefixOps as $prefixOp) { $this->fixupMap[$prefixOp] = ['expr' => self::FIXUP_PREC_RIGHT]; } } /** * Lazily initializes the removal map. * * The removal map is used to determine which additional tokens should be removed when a * certain node is replaced by null. */ protected function initializeRemovalMap() { if ($this->removalMap) { return; } $stripBoth = ['left' => \T_WHITESPACE, 'right' => \T_WHITESPACE]; $stripLeft = ['left' => \T_WHITESPACE]; $stripRight = ['right' => \T_WHITESPACE]; $stripDoubleArrow = ['right' => \T_DOUBLE_ARROW]; $stripColon = ['left' => ':']; $stripEquals = ['left' => '=']; $this->removalMap = ['Expr_ArrayDimFetch->dim' => $stripBoth, 'Expr_ArrayItem->key' => $stripDoubleArrow, 'Expr_ArrowFunction->returnType' => $stripColon, 'Expr_Closure->returnType' => $stripColon, 'Expr_Exit->expr' => $stripBoth, 'Expr_Ternary->if' => $stripBoth, 'Expr_Yield->key' => $stripDoubleArrow, 'Expr_Yield->value' => $stripBoth, 'Param->type' => $stripRight, 'Param->default' => $stripEquals, 'Stmt_Break->num' => $stripBoth, 'Stmt_Catch->var' => $stripLeft, 'Stmt_ClassConst->type' => $stripRight, 'Stmt_ClassMethod->returnType' => $stripColon, 'Stmt_Class->extends' => ['left' => \T_EXTENDS], 'Stmt_Enum->scalarType' => $stripColon, 'Stmt_EnumCase->expr' => $stripEquals, 'Expr_PrintableNewAnonClass->extends' => ['left' => \T_EXTENDS], 'Stmt_Continue->num' => $stripBoth, 'Stmt_Foreach->keyVar' => $stripDoubleArrow, 'Stmt_Function->returnType' => $stripColon, 'Stmt_If->else' => $stripLeft, 'Stmt_Namespace->name' => $stripLeft, 'Stmt_Property->type' => $stripRight, 'Stmt_PropertyProperty->default' => $stripEquals, 'Stmt_Return->expr' => $stripBoth, 'Stmt_StaticVar->default' => $stripEquals, 'Stmt_TraitUseAdaptation_Alias->newName' => $stripLeft, 'Stmt_TryCatch->finally' => $stripLeft]; } protected function initializeInsertionMap() { if ($this->insertionMap) { return; } // TODO: "yield" where both key and value are inserted doesn't work // [$find, $beforeToken, $extraLeft, $extraRight] $this->insertionMap = [ 'Expr_ArrayDimFetch->dim' => ['[', \false, null, null], 'Expr_ArrayItem->key' => [null, \false, null, ' => '], 'Expr_ArrowFunction->returnType' => [')', \false, ' : ', null], 'Expr_Closure->returnType' => [')', \false, ' : ', null], 'Expr_Ternary->if' => ['?', \false, ' ', ' '], 'Expr_Yield->key' => [\T_YIELD, \false, null, ' => '], 'Expr_Yield->value' => [\T_YIELD, \false, ' ', null], 'Param->type' => [null, \false, null, ' '], 'Param->default' => [null, \false, ' = ', null], 'Stmt_Break->num' => [\T_BREAK, \false, ' ', null], 'Stmt_Catch->var' => [null, \false, ' ', null], 'Stmt_ClassMethod->returnType' => [')', \false, ' : ', null], 'Stmt_ClassConst->type' => [\T_CONST, \false, ' ', null], 'Stmt_Class->extends' => [null, \false, ' extends ', null], 'Stmt_Enum->scalarType' => [null, \false, ' : ', null], 'Stmt_EnumCase->expr' => [null, \false, ' = ', null], 'Expr_PrintableNewAnonClass->extends' => [null, ' extends ', null], 'Stmt_Continue->num' => [\T_CONTINUE, \false, ' ', null], 'Stmt_Foreach->keyVar' => [\T_AS, \false, null, ' => '], 'Stmt_Function->returnType' => [')', \false, ' : ', null], 'Stmt_If->else' => [null, \false, ' ', null], 'Stmt_Namespace->name' => [\T_NAMESPACE, \false, ' ', null], 'Stmt_Property->type' => [\T_VARIABLE, \true, null, ' '], 'Stmt_PropertyProperty->default' => [null, \false, ' = ', null], 'Stmt_Return->expr' => [\T_RETURN, \false, ' ', null], 'Stmt_StaticVar->default' => [null, \false, ' = ', null], //'Stmt_TraitUseAdaptation_Alias->newName' => [T_AS, false, ' ', null], // TODO 'Stmt_TryCatch->finally' => [null, \false, ' ', null], ]; } protected function initializeListInsertionMap() { if ($this->listInsertionMap) { return; } $this->listInsertionMap = [ // special //'Expr_ShellExec->parts' => '', // TODO These need to be treated more carefully //'Scalar_Encapsed->parts' => '', 'Stmt_Catch->types' => '|', 'UnionType->types' => '|', 'IntersectionType->types' => '&', 'Stmt_If->elseifs' => ' ', 'Stmt_TryCatch->catches' => ' ', // comma-separated lists 'Expr_Array->items' => ', ', 'Expr_ArrowFunction->params' => ', ', 'Expr_Closure->params' => ', ', 'Expr_Closure->uses' => ', ', 'Expr_FuncCall->args' => ', ', 'Expr_Isset->vars' => ', ', 'Expr_List->items' => ', ', 'Expr_MethodCall->args' => ', ', 'Expr_NullsafeMethodCall->args' => ', ', 'Expr_New->args' => ', ', 'Expr_PrintableNewAnonClass->args' => ', ', 'Expr_StaticCall->args' => ', ', 'Stmt_ClassConst->consts' => ', ', 'Stmt_ClassMethod->params' => ', ', 'Stmt_Class->implements' => ', ', 'Stmt_Enum->implements' => ', ', 'Expr_PrintableNewAnonClass->implements' => ', ', 'Stmt_Const->consts' => ', ', 'Stmt_Declare->declares' => ', ', 'Stmt_Echo->exprs' => ', ', 'Stmt_For->init' => ', ', 'Stmt_For->cond' => ', ', 'Stmt_For->loop' => ', ', 'Stmt_Function->params' => ', ', 'Stmt_Global->vars' => ', ', 'Stmt_GroupUse->uses' => ', ', 'Stmt_Interface->extends' => ', ', 'Stmt_Match->arms' => ', ', 'Stmt_Property->props' => ', ', 'Stmt_StaticVar->vars' => ', ', 'Stmt_TraitUse->traits' => ', ', 'Stmt_TraitUseAdaptation_Precedence->insteadof' => ', ', 'Stmt_Unset->vars' => ', ', 'Stmt_Use->uses' => ', ', 'MatchArm->conds' => ', ', 'AttributeGroup->attrs' => ', ', // statement lists 'Expr_Closure->stmts' => "\n", 'Stmt_Case->stmts' => "\n", 'Stmt_Catch->stmts' => "\n", 'Stmt_Class->stmts' => "\n", 'Stmt_Enum->stmts' => "\n", 'Expr_PrintableNewAnonClass->stmts' => "\n", 'Stmt_Interface->stmts' => "\n", 'Stmt_Trait->stmts' => "\n", 'Stmt_ClassMethod->stmts' => "\n", 'Stmt_Declare->stmts' => "\n", 'Stmt_Do->stmts' => "\n", 'Stmt_ElseIf->stmts' => "\n", 'Stmt_Else->stmts' => "\n", 'Stmt_Finally->stmts' => "\n", 'Stmt_Foreach->stmts' => "\n", 'Stmt_For->stmts' => "\n", 'Stmt_Function->stmts' => "\n", 'Stmt_If->stmts' => "\n", 'Stmt_Namespace->stmts' => "\n", 'Stmt_Class->attrGroups' => "\n", 'Stmt_Enum->attrGroups' => "\n", 'Stmt_EnumCase->attrGroups' => "\n", 'Stmt_Interface->attrGroups' => "\n", 'Stmt_Trait->attrGroups' => "\n", 'Stmt_Function->attrGroups' => "\n", 'Stmt_ClassMethod->attrGroups' => "\n", 'Stmt_ClassConst->attrGroups' => "\n", 'Stmt_Property->attrGroups' => "\n", 'Expr_PrintableNewAnonClass->attrGroups' => ' ', 'Expr_Closure->attrGroups' => ' ', 'Expr_ArrowFunction->attrGroups' => ' ', 'Param->attrGroups' => ' ', 'Stmt_Switch->cases' => "\n", 'Stmt_TraitUse->adaptations' => "\n", 'Stmt_TryCatch->stmts' => "\n", 'Stmt_While->stmts' => "\n", // dummy for top-level context 'File->stmts' => "\n", ]; } protected function initializeEmptyListInsertionMap() { if ($this->emptyListInsertionMap) { return; } // TODO Insertion into empty statement lists. // [$find, $extraLeft, $extraRight] $this->emptyListInsertionMap = ['Expr_ArrowFunction->params' => ['(', '', ''], 'Expr_Closure->uses' => [')', ' use(', ')'], 'Expr_Closure->params' => ['(', '', ''], 'Expr_FuncCall->args' => ['(', '', ''], 'Expr_MethodCall->args' => ['(', '', ''], 'Expr_NullsafeMethodCall->args' => ['(', '', ''], 'Expr_New->args' => ['(', '', ''], 'Expr_PrintableNewAnonClass->args' => ['(', '', ''], 'Expr_PrintableNewAnonClass->implements' => [null, ' implements ', ''], 'Expr_StaticCall->args' => ['(', '', ''], 'Stmt_Class->implements' => [null, ' implements ', ''], 'Stmt_Enum->implements' => [null, ' implements ', ''], 'Stmt_ClassMethod->params' => ['(', '', ''], 'Stmt_Interface->extends' => [null, ' extends ', ''], 'Stmt_Function->params' => ['(', '', ''], 'Stmt_Interface->attrGroups' => [null, '', "\n"], 'Stmt_Class->attrGroups' => [null, '', "\n"], 'Stmt_ClassConst->attrGroups' => [null, '', "\n"], 'Stmt_ClassMethod->attrGroups' => [null, '', "\n"], 'Stmt_Function->attrGroups' => [null, '', "\n"], 'Stmt_Property->attrGroups' => [null, '', "\n"], 'Stmt_Trait->attrGroups' => [null, '', "\n"], 'Expr_ArrowFunction->attrGroups' => [null, '', ' '], 'Expr_Closure->attrGroups' => [null, '', ' '], 'Expr_PrintableNewAnonClass->attrGroups' => [\T_NEW, ' ', '']]; } protected function initializeModifierChangeMap() { if ($this->modifierChangeMap) { return; } $this->modifierChangeMap = ['Stmt_ClassConst->flags' => \T_CONST, 'Stmt_ClassMethod->flags' => \T_FUNCTION, 'Stmt_Class->flags' => \T_CLASS, 'Stmt_Property->flags' => \T_VARIABLE, 'Expr_PrintableNewAnonClass->flags' => \T_CLASS, 'Param->flags' => \T_VARIABLE]; // List of integer subnodes that are not modifiers: // Expr_Include->type // Stmt_GroupUse->type // Stmt_Use->type // Stmt_UseUse->type } } getLexerOptions())); } /** * Create a parser targeting the host PHP version, that is the PHP version we're currently * running on. This parser will not use any token emulation. * * All supported lexer attributes (comments, startLine, endLine, startTokenPos, endTokenPos, * startFilePos, endFilePos) will be enabled. */ public function createForHostVersion() : Parser { return new Php7(new Lexer($this->getLexerOptions())); } private function getLexerOptions() : array { return ['usedAttributes' => ['comments', 'startLine', 'endLine', 'startTokenPos', 'endTokenPos', 'startFilePos', 'endFilePos']]; } } errors[] = $error; } /** * Get collected errors. * * @return Error[] */ public function getErrors() : array { return $this->errors; } /** * Check whether there are any errors. * * @return bool */ public function hasErrors() : bool { return !empty($this->errors); } /** * Reset/clear collected errors. */ public function clearErrors() { $this->errors = []; } } defineCompatibilityTokens(); $this->tokenMap = $this->createTokenMap(); $this->identifierTokens = $this->createIdentifierTokenMap(); // map of tokens to drop while lexing (the map is only used for isset lookup, // that's why the value is simply set to 1; the value is never actually used.) $this->dropTokens = \array_fill_keys([\T_WHITESPACE, \T_OPEN_TAG, \T_COMMENT, \T_DOC_COMMENT, \T_BAD_CHARACTER], 1); $defaultAttributes = ['comments', 'startLine', 'endLine']; $usedAttributes = \array_fill_keys($options['usedAttributes'] ?? $defaultAttributes, \true); // Create individual boolean properties to make these checks faster. $this->attributeStartLineUsed = isset($usedAttributes['startLine']); $this->attributeEndLineUsed = isset($usedAttributes['endLine']); $this->attributeStartTokenPosUsed = isset($usedAttributes['startTokenPos']); $this->attributeEndTokenPosUsed = isset($usedAttributes['endTokenPos']); $this->attributeStartFilePosUsed = isset($usedAttributes['startFilePos']); $this->attributeEndFilePosUsed = isset($usedAttributes['endFilePos']); $this->attributeCommentsUsed = isset($usedAttributes['comments']); } /** * Initializes the lexer for lexing the provided source code. * * This function does not throw if lexing errors occur. Instead, errors may be retrieved using * the getErrors() method. * * @param string $code The source code to lex * @param ErrorHandler|null $errorHandler Error handler to use for lexing errors. Defaults to * ErrorHandler\Throwing */ public function startLexing(string $code, ?ErrorHandler $errorHandler = null) { if (null === $errorHandler) { $errorHandler = new ErrorHandler\Throwing(); } $this->code = $code; // keep the code around for __halt_compiler() handling $this->pos = -1; $this->line = 1; $this->filePos = 0; // If inline HTML occurs without preceding code, treat it as if it had a leading newline. // This ensures proper composability, because having a newline is the "safe" assumption. $this->prevCloseTagHasNewline = \true; $scream = \ini_set('xdebug.scream', '0'); $this->tokens = @\token_get_all($code); $this->postprocessTokens($errorHandler); if (\false !== $scream) { \ini_set('xdebug.scream', $scream); } } private function handleInvalidCharacterRange($start, $end, $line, ErrorHandler $errorHandler) { $tokens = []; for ($i = $start; $i < $end; $i++) { $chr = $this->code[$i]; if ($chr === "\x00") { // PHP cuts error message after null byte, so need special case $errorMsg = 'Unexpected null byte'; } else { $errorMsg = \sprintf('Unexpected character "%s" (ASCII %d)', $chr, \ord($chr)); } $tokens[] = [\T_BAD_CHARACTER, $chr, $line]; $errorHandler->handleError(new Error($errorMsg, ['startLine' => $line, 'endLine' => $line, 'startFilePos' => $i, 'endFilePos' => $i])); } return $tokens; } /** * Check whether comment token is unterminated. * * @return bool */ private function isUnterminatedComment($token) : bool { return ($token[0] === \T_COMMENT || $token[0] === \T_DOC_COMMENT) && \substr($token[1], 0, 2) === '/*' && \substr($token[1], -2) !== '*/'; } protected function postprocessTokens(ErrorHandler $errorHandler) { // PHP's error handling for token_get_all() is rather bad, so if we want detailed // error information we need to compute it ourselves. Invalid character errors are // detected by finding "gaps" in the token array. Unterminated comments are detected // by checking if a trailing comment has a "*/" at the end. // // Additionally, we perform a number of canonicalizations here: // * Use the PHP 8.0 comment format, which does not include trailing whitespace anymore. // * Use PHP 8.0 T_NAME_* tokens. // * Use PHP 8.1 T_AMPERSAND_NOT_FOLLOWED_BY_VAR_OR_VARARG and // T_AMPERSAND_FOLLOWED_BY_VAR_OR_VARARG tokens used to disambiguate intersection types. $filePos = 0; $line = 1; $numTokens = \count($this->tokens); for ($i = 0; $i < $numTokens; $i++) { $token = $this->tokens[$i]; // Since PHP 7.4 invalid characters are represented by a T_BAD_CHARACTER token. // In this case we only need to emit an error. if ($token[0] === \T_BAD_CHARACTER) { $this->handleInvalidCharacterRange($filePos, $filePos + 1, $line, $errorHandler); } if ($token[0] === \T_COMMENT && \substr($token[1], 0, 2) !== '/*' && \preg_match('/(\\r\\n|\\n|\\r)$/D', $token[1], $matches)) { $trailingNewline = $matches[0]; $token[1] = \substr($token[1], 0, -\strlen($trailingNewline)); $this->tokens[$i] = $token; if (isset($this->tokens[$i + 1]) && $this->tokens[$i + 1][0] === \T_WHITESPACE) { // Move trailing newline into following T_WHITESPACE token, if it already exists. $this->tokens[$i + 1][1] = $trailingNewline . $this->tokens[$i + 1][1]; $this->tokens[$i + 1][2]--; } else { // Otherwise, we need to create a new T_WHITESPACE token. \array_splice($this->tokens, $i + 1, 0, [[\T_WHITESPACE, $trailingNewline, $line]]); $numTokens++; } } // Emulate PHP 8 T_NAME_* tokens, by combining sequences of T_NS_SEPARATOR and T_STRING // into a single token. if (\is_array($token) && ($token[0] === \T_NS_SEPARATOR || isset($this->identifierTokens[$token[0]]))) { $lastWasSeparator = $token[0] === \T_NS_SEPARATOR; $text = $token[1]; for ($j = $i + 1; isset($this->tokens[$j]); $j++) { if ($lastWasSeparator) { if (!isset($this->identifierTokens[$this->tokens[$j][0]])) { break; } $lastWasSeparator = \false; } else { if ($this->tokens[$j][0] !== \T_NS_SEPARATOR) { break; } $lastWasSeparator = \true; } $text .= $this->tokens[$j][1]; } if ($lastWasSeparator) { // Trailing separator is not part of the name. $j--; $text = \substr($text, 0, -1); } if ($j > $i + 1) { if ($token[0] === \T_NS_SEPARATOR) { $type = \T_NAME_FULLY_QUALIFIED; } else { if ($token[0] === \T_NAMESPACE) { $type = \T_NAME_RELATIVE; } else { $type = \T_NAME_QUALIFIED; } } $token = [$type, $text, $line]; \array_splice($this->tokens, $i, $j - $i, [$token]); $numTokens -= $j - $i - 1; } } if ($token === '&') { $next = $i + 1; while (isset($this->tokens[$next]) && $this->tokens[$next][0] === \T_WHITESPACE) { $next++; } $followedByVarOrVarArg = isset($this->tokens[$next]) && ($this->tokens[$next][0] === \T_VARIABLE || $this->tokens[$next][0] === \T_ELLIPSIS); $this->tokens[$i] = $token = [$followedByVarOrVarArg ? \T_AMPERSAND_FOLLOWED_BY_VAR_OR_VARARG : \T_AMPERSAND_NOT_FOLLOWED_BY_VAR_OR_VARARG, '&', $line]; } $tokenValue = \is_string($token) ? $token : $token[1]; $tokenLen = \strlen($tokenValue); if (\substr($this->code, $filePos, $tokenLen) !== $tokenValue) { // Something is missing, must be an invalid character $nextFilePos = \strpos($this->code, $tokenValue, $filePos); $badCharTokens = $this->handleInvalidCharacterRange($filePos, $nextFilePos, $line, $errorHandler); $filePos = (int) $nextFilePos; \array_splice($this->tokens, $i, 0, $badCharTokens); $numTokens += \count($badCharTokens); $i += \count($badCharTokens); } $filePos += $tokenLen; $line += \substr_count($tokenValue, "\n"); } if ($filePos !== \strlen($this->code)) { if (\substr($this->code, $filePos, 2) === '/*') { // Unlike PHP, HHVM will drop unterminated comments entirely $comment = \substr($this->code, $filePos); $errorHandler->handleError(new Error('Unterminated comment', ['startLine' => $line, 'endLine' => $line + \substr_count($comment, "\n"), 'startFilePos' => $filePos, 'endFilePos' => $filePos + \strlen($comment)])); // Emulate the PHP behavior $isDocComment = isset($comment[3]) && $comment[3] === '*'; $this->tokens[] = [$isDocComment ? \T_DOC_COMMENT : \T_COMMENT, $comment, $line]; } else { // Invalid characters at the end of the input $badCharTokens = $this->handleInvalidCharacterRange($filePos, \strlen($this->code), $line, $errorHandler); $this->tokens = \array_merge($this->tokens, $badCharTokens); } return; } if (\count($this->tokens) > 0) { // Check for unterminated comment $lastToken = $this->tokens[\count($this->tokens) - 1]; if ($this->isUnterminatedComment($lastToken)) { $errorHandler->handleError(new Error('Unterminated comment', ['startLine' => $line - \substr_count($lastToken[1], "\n"), 'endLine' => $line, 'startFilePos' => $filePos - \strlen($lastToken[1]), 'endFilePos' => $filePos])); } } } /** * Fetches the next token. * * The available attributes are determined by the 'usedAttributes' option, which can * be specified in the constructor. The following attributes are supported: * * * 'comments' => Array of PhpParser\Comment or PhpParser\Comment\Doc instances, * representing all comments that occurred between the previous * non-discarded token and the current one. * * 'startLine' => Line in which the node starts. * * 'endLine' => Line in which the node ends. * * 'startTokenPos' => Offset into the token array of the first token in the node. * * 'endTokenPos' => Offset into the token array of the last token in the node. * * 'startFilePos' => Offset into the code string of the first character that is part of the node. * * 'endFilePos' => Offset into the code string of the last character that is part of the node. * * @param mixed $value Variable to store token content in * @param mixed $startAttributes Variable to store start attributes in * @param mixed $endAttributes Variable to store end attributes in * * @return int Token id */ public function getNextToken(&$value = null, &$startAttributes = null, &$endAttributes = null) : int { $startAttributes = []; $endAttributes = []; while (1) { if (isset($this->tokens[++$this->pos])) { $token = $this->tokens[$this->pos]; } else { // EOF token with ID 0 $token = "\x00"; } if ($this->attributeStartLineUsed) { $startAttributes['startLine'] = $this->line; } if ($this->attributeStartTokenPosUsed) { $startAttributes['startTokenPos'] = $this->pos; } if ($this->attributeStartFilePosUsed) { $startAttributes['startFilePos'] = $this->filePos; } if (\is_string($token)) { $value = $token; if (isset($token[1])) { // bug in token_get_all $this->filePos += 2; $id = \ord('"'); } else { $this->filePos += 1; $id = \ord($token); } } elseif (!isset($this->dropTokens[$token[0]])) { $value = $token[1]; $id = $this->tokenMap[$token[0]]; if (\T_CLOSE_TAG === $token[0]) { $this->prevCloseTagHasNewline = \false !== \strpos($token[1], "\n") || \false !== \strpos($token[1], "\r"); } elseif (\T_INLINE_HTML === $token[0]) { $startAttributes['hasLeadingNewline'] = $this->prevCloseTagHasNewline; } $this->line += \substr_count($value, "\n"); $this->filePos += \strlen($value); } else { $origLine = $this->line; $origFilePos = $this->filePos; $this->line += \substr_count($token[1], "\n"); $this->filePos += \strlen($token[1]); if (\T_COMMENT === $token[0] || \T_DOC_COMMENT === $token[0]) { if ($this->attributeCommentsUsed) { $comment = \T_DOC_COMMENT === $token[0] ? new Comment\Doc($token[1], $origLine, $origFilePos, $this->pos, $this->line, $this->filePos - 1, $this->pos) : new Comment($token[1], $origLine, $origFilePos, $this->pos, $this->line, $this->filePos - 1, $this->pos); $startAttributes['comments'][] = $comment; } } continue; } if ($this->attributeEndLineUsed) { $endAttributes['endLine'] = $this->line; } if ($this->attributeEndTokenPosUsed) { $endAttributes['endTokenPos'] = $this->pos; } if ($this->attributeEndFilePosUsed) { $endAttributes['endFilePos'] = $this->filePos - 1; } return $id; } throw new \RuntimeException('Reached end of lexer loop'); } /** * Returns the token array for current code. * * The token array is in the same format as provided by the * token_get_all() function and does not discard tokens (i.e. * whitespace and comments are included). The token position * attributes are against this token array. * * @return array Array of tokens in token_get_all() format */ public function getTokens() : array { return $this->tokens; } /** * Handles __halt_compiler() by returning the text after it. * * @return string Remaining text */ public function handleHaltCompiler() : string { // text after T_HALT_COMPILER, still including (); $textAfter = \substr($this->code, $this->filePos); // ensure that it is followed by (); // this simplifies the situation, by not allowing any comments // in between of the tokens. if (!\preg_match('~^\\s*\\(\\s*\\)\\s*(?:;|\\?>\\r?\\n?)~', $textAfter, $matches)) { throw new Error('__HALT_COMPILER must be followed by "();"'); } // prevent the lexer from returning any further tokens $this->pos = \count($this->tokens); // return with (); removed return \substr($textAfter, \strlen($matches[0])); } private function defineCompatibilityTokens() { static $compatTokensDefined = \false; if ($compatTokensDefined) { return; } $compatTokens = [ // PHP 7.4 'T_BAD_CHARACTER', 'T_FN', 'T_COALESCE_EQUAL', // PHP 8.0 'T_NAME_QUALIFIED', 'T_NAME_FULLY_QUALIFIED', 'T_NAME_RELATIVE', 'T_MATCH', 'T_NULLSAFE_OBJECT_OPERATOR', 'T_ATTRIBUTE', // PHP 8.1 'T_ENUM', 'T_AMPERSAND_NOT_FOLLOWED_BY_VAR_OR_VARARG', 'T_AMPERSAND_FOLLOWED_BY_VAR_OR_VARARG', 'T_READONLY', ]; // PHP-Parser might be used together with another library that also emulates some or all // of these tokens. Perform a sanity-check that all already defined tokens have been // assigned a unique ID. $usedTokenIds = []; foreach ($compatTokens as $token) { if (\defined($token)) { $tokenId = \constant($token); $clashingToken = $usedTokenIds[$tokenId] ?? null; if ($clashingToken !== null) { throw new \Error(\sprintf('Token %s has same ID as token %s, ' . 'you may be using a library with broken token emulation', $token, $clashingToken)); } $usedTokenIds[$tokenId] = $token; } } // Now define any tokens that have not yet been emulated. Try to assign IDs from -1 // downwards, but skip any IDs that may already be in use. $newTokenId = -1; foreach ($compatTokens as $token) { if (!\defined($token)) { while (isset($usedTokenIds[$newTokenId])) { $newTokenId--; } \define($token, $newTokenId); $newTokenId--; } } $compatTokensDefined = \true; } /** * Creates the token map. * * The token map maps the PHP internal token identifiers * to the identifiers used by the Parser. Additionally it * maps T_OPEN_TAG_WITH_ECHO to T_ECHO and T_CLOSE_TAG to ';'. * * @return array The token map */ protected function createTokenMap() : array { $tokenMap = []; // 256 is the minimum possible token number, as everything below // it is an ASCII value for ($i = 256; $i < 1000; ++$i) { if (\T_DOUBLE_COLON === $i) { // T_DOUBLE_COLON is equivalent to T_PAAMAYIM_NEKUDOTAYIM $tokenMap[$i] = Tokens::T_PAAMAYIM_NEKUDOTAYIM; } elseif (\T_OPEN_TAG_WITH_ECHO === $i) { // T_OPEN_TAG_WITH_ECHO with dropped T_OPEN_TAG results in T_ECHO $tokenMap[$i] = Tokens::T_ECHO; } elseif (\T_CLOSE_TAG === $i) { // T_CLOSE_TAG is equivalent to ';' $tokenMap[$i] = \ord(';'); } elseif ('UNKNOWN' !== ($name = \token_name($i))) { if ('T_HASHBANG' === $name) { // HHVM uses a special token for #! hashbang lines $tokenMap[$i] = Tokens::T_INLINE_HTML; } elseif (\defined($name = Tokens::class . '::' . $name)) { // Other tokens can be mapped directly $tokenMap[$i] = \constant($name); } } } // HHVM uses a special token for numbers that overflow to double if (\defined('_HumbugBox7ff99e199a36\\T_ONUMBER')) { $tokenMap[\_HumbugBox7ff99e199a36\T_ONUMBER] = Tokens::T_DNUMBER; } // HHVM also has a separate token for the __COMPILER_HALT_OFFSET__ constant if (\defined('_HumbugBox7ff99e199a36\\T_COMPILER_HALT_OFFSET')) { $tokenMap[\_HumbugBox7ff99e199a36\T_COMPILER_HALT_OFFSET] = Tokens::T_STRING; } // Assign tokens for which we define compatibility constants, as token_name() does not know them. $tokenMap[\T_FN] = Tokens::T_FN; $tokenMap[\T_COALESCE_EQUAL] = Tokens::T_COALESCE_EQUAL; $tokenMap[\T_NAME_QUALIFIED] = Tokens::T_NAME_QUALIFIED; $tokenMap[\T_NAME_FULLY_QUALIFIED] = Tokens::T_NAME_FULLY_QUALIFIED; $tokenMap[\T_NAME_RELATIVE] = Tokens::T_NAME_RELATIVE; $tokenMap[\T_MATCH] = Tokens::T_MATCH; $tokenMap[\T_NULLSAFE_OBJECT_OPERATOR] = Tokens::T_NULLSAFE_OBJECT_OPERATOR; $tokenMap[\T_ATTRIBUTE] = Tokens::T_ATTRIBUTE; $tokenMap[\T_AMPERSAND_NOT_FOLLOWED_BY_VAR_OR_VARARG] = Tokens::T_AMPERSAND_NOT_FOLLOWED_BY_VAR_OR_VARARG; $tokenMap[\T_AMPERSAND_FOLLOWED_BY_VAR_OR_VARARG] = Tokens::T_AMPERSAND_FOLLOWED_BY_VAR_OR_VARARG; $tokenMap[\T_ENUM] = Tokens::T_ENUM; $tokenMap[\T_READONLY] = Tokens::T_READONLY; return $tokenMap; } private function createIdentifierTokenMap() : array { // Based on semi_reserved production. return \array_fill_keys([\T_STRING, \T_STATIC, \T_ABSTRACT, \T_FINAL, \T_PRIVATE, \T_PROTECTED, \T_PUBLIC, \T_READONLY, \T_INCLUDE, \T_INCLUDE_ONCE, \T_EVAL, \T_REQUIRE, \T_REQUIRE_ONCE, \T_LOGICAL_OR, \T_LOGICAL_XOR, \T_LOGICAL_AND, \T_INSTANCEOF, \T_NEW, \T_CLONE, \T_EXIT, \T_IF, \T_ELSEIF, \T_ELSE, \T_ENDIF, \T_ECHO, \T_DO, \T_WHILE, \T_ENDWHILE, \T_FOR, \T_ENDFOR, \T_FOREACH, \T_ENDFOREACH, \T_DECLARE, \T_ENDDECLARE, \T_AS, \T_TRY, \T_CATCH, \T_FINALLY, \T_THROW, \T_USE, \T_INSTEADOF, \T_GLOBAL, \T_VAR, \T_UNSET, \T_ISSET, \T_EMPTY, \T_CONTINUE, \T_GOTO, \T_FUNCTION, \T_CONST, \T_RETURN, \T_PRINT, \T_YIELD, \T_LIST, \T_SWITCH, \T_ENDSWITCH, \T_CASE, \T_DEFAULT, \T_BREAK, \T_ARRAY, \T_CALLABLE, \T_EXTENDS, \T_IMPLEMENTS, \T_NAMESPACE, \T_TRAIT, \T_INTERFACE, \T_CLASS, \T_CLASS_C, \T_TRAIT_C, \T_FUNC_C, \T_METHOD_C, \T_LINE, \T_FILE, \T_DIR, \T_NS_C, \T_HALT_COMPILER, \T_FN, \T_MATCH], \true); } } fallbackEvaluator = $fallbackEvaluator ?? function (Expr $expr) { throw new ConstExprEvaluationException("Expression of type {$expr->getType()} cannot be evaluated"); }; } /** * Silently evaluates a constant expression into a PHP value. * * Thrown Errors, warnings or notices will be converted into a ConstExprEvaluationException. * The original source of the exception is available through getPrevious(). * * If some part of the expression cannot be evaluated, the fallback evaluator passed to the * constructor will be invoked. By default, if no fallback is provided, an exception of type * ConstExprEvaluationException is thrown. * * See class doc comment for caveats and limitations. * * @param Expr $expr Constant expression to evaluate * @return mixed Result of evaluation * * @throws ConstExprEvaluationException if the expression cannot be evaluated or an error occurred */ public function evaluateSilently(Expr $expr) { \set_error_handler(function ($num, $str, $file, $line) { throw new \ErrorException($str, 0, $num, $file, $line); }); try { return $this->evaluate($expr); } catch (\Throwable $e) { if (!$e instanceof ConstExprEvaluationException) { $e = new ConstExprEvaluationException("An error occurred during constant expression evaluation", 0, $e); } throw $e; } finally { \restore_error_handler(); } } /** * Directly evaluates a constant expression into a PHP value. * * May generate Error exceptions, warnings or notices. Use evaluateSilently() to convert these * into a ConstExprEvaluationException. * * If some part of the expression cannot be evaluated, the fallback evaluator passed to the * constructor will be invoked. By default, if no fallback is provided, an exception of type * ConstExprEvaluationException is thrown. * * See class doc comment for caveats and limitations. * * @param Expr $expr Constant expression to evaluate * @return mixed Result of evaluation * * @throws ConstExprEvaluationException if the expression cannot be evaluated */ public function evaluateDirectly(Expr $expr) { return $this->evaluate($expr); } private function evaluate(Expr $expr) { if ($expr instanceof Scalar\LNumber || $expr instanceof Scalar\DNumber || $expr instanceof Scalar\String_) { return $expr->value; } if ($expr instanceof Expr\Array_) { return $this->evaluateArray($expr); } // Unary operators if ($expr instanceof Expr\UnaryPlus) { return +$this->evaluate($expr->expr); } if ($expr instanceof Expr\UnaryMinus) { return -$this->evaluate($expr->expr); } if ($expr instanceof Expr\BooleanNot) { return !$this->evaluate($expr->expr); } if ($expr instanceof Expr\BitwiseNot) { return ~$this->evaluate($expr->expr); } if ($expr instanceof Expr\BinaryOp) { return $this->evaluateBinaryOp($expr); } if ($expr instanceof Expr\Ternary) { return $this->evaluateTernary($expr); } if ($expr instanceof Expr\ArrayDimFetch && null !== $expr->dim) { return $this->evaluate($expr->var)[$this->evaluate($expr->dim)]; } if ($expr instanceof Expr\ConstFetch) { return $this->evaluateConstFetch($expr); } return ($this->fallbackEvaluator)($expr); } private function evaluateArray(Expr\Array_ $expr) { $array = []; foreach ($expr->items as $item) { if (null !== $item->key) { $array[$this->evaluate($item->key)] = $this->evaluate($item->value); } elseif ($item->unpack) { $array = array_merge($array, $this->evaluate($item->value)); } else { $array[] = $this->evaluate($item->value); } } return $array; } private function evaluateTernary(Expr\Ternary $expr) { if (null === $expr->if) { return $this->evaluate($expr->cond) ?: $this->evaluate($expr->else); } return $this->evaluate($expr->cond) ? $this->evaluate($expr->if) : $this->evaluate($expr->else); } private function evaluateBinaryOp(Expr\BinaryOp $expr) { if ($expr instanceof Expr\BinaryOp\Coalesce && $expr->left instanceof Expr\ArrayDimFetch) { // This needs to be special cased to respect BP_VAR_IS fetch semantics return $this->evaluate($expr->left->var)[$this->evaluate($expr->left->dim)] ?? $this->evaluate($expr->right); } // The evaluate() calls are repeated in each branch, because some of the operators are // short-circuiting and evaluating the RHS in advance may be illegal in that case $l = $expr->left; $r = $expr->right; switch ($expr->getOperatorSigil()) { case '&': return $this->evaluate($l) & $this->evaluate($r); case '|': return $this->evaluate($l) | $this->evaluate($r); case '^': return $this->evaluate($l) ^ $this->evaluate($r); case '&&': return $this->evaluate($l) && $this->evaluate($r); case '||': return $this->evaluate($l) || $this->evaluate($r); case '??': return $this->evaluate($l) ?? $this->evaluate($r); case '.': return $this->evaluate($l) . $this->evaluate($r); case '/': return $this->evaluate($l) / $this->evaluate($r); case '==': return $this->evaluate($l) == $this->evaluate($r); case '>': return $this->evaluate($l) > $this->evaluate($r); case '>=': return $this->evaluate($l) >= $this->evaluate($r); case '===': return $this->evaluate($l) === $this->evaluate($r); case 'and': return $this->evaluate($l) and $this->evaluate($r); case 'or': return $this->evaluate($l) or $this->evaluate($r); case 'xor': return $this->evaluate($l) xor $this->evaluate($r); case '-': return $this->evaluate($l) - $this->evaluate($r); case '%': return $this->evaluate($l) % $this->evaluate($r); case '*': return $this->evaluate($l) * $this->evaluate($r); case '!=': return $this->evaluate($l) != $this->evaluate($r); case '!==': return $this->evaluate($l) !== $this->evaluate($r); case '+': return $this->evaluate($l) + $this->evaluate($r); case '**': return $this->evaluate($l) ** $this->evaluate($r); case '<<': return $this->evaluate($l) << $this->evaluate($r); case '>>': return $this->evaluate($l) >> $this->evaluate($r); case '<': return $this->evaluate($l) < $this->evaluate($r); case '<=': return $this->evaluate($l) <= $this->evaluate($r); case '<=>': return $this->evaluate($l) <=> $this->evaluate($r); } throw new \Exception('Should not happen'); } private function evaluateConstFetch(Expr\ConstFetch $expr) { $name = $expr->name->toLowerString(); switch ($name) { case 'null': return null; case 'false': return \false; case 'true': return \true; } return ($this->fallbackEvaluator)($expr); } } isEqual = $isEqual; } /** * Calculate diff (edit script) from $old to $new. * * @param array $old Original array * @param array $new New array * * @return DiffElem[] Diff (edit script) */ public function diff(array $old, array $new) { list($trace, $x, $y) = $this->calculateTrace($old, $new); return $this->extractDiff($trace, $x, $y, $old, $new); } /** * Calculate diff, including "replace" operations. * * If a sequence of remove operations is followed by the same number of add operations, these * will be coalesced into replace operations. * * @param array $old Original array * @param array $new New array * * @return DiffElem[] Diff (edit script), including replace operations */ public function diffWithReplacements(array $old, array $new) { return $this->coalesceReplacements($this->diff($old, $new)); } private function calculateTrace(array $a, array $b) { $n = \count($a); $m = \count($b); $max = $n + $m; $v = [1 => 0]; $trace = []; for ($d = 0; $d <= $max; $d++) { $trace[] = $v; for ($k = -$d; $k <= $d; $k += 2) { if ($k === -$d || $k !== $d && $v[$k - 1] < $v[$k + 1]) { $x = $v[$k + 1]; } else { $x = $v[$k - 1] + 1; } $y = $x - $k; while ($x < $n && $y < $m && ($this->isEqual)($a[$x], $b[$y])) { $x++; $y++; } $v[$k] = $x; if ($x >= $n && $y >= $m) { return [$trace, $x, $y]; } } } throw new \Exception('Should not happen'); } private function extractDiff(array $trace, int $x, int $y, array $a, array $b) { $result = []; for ($d = \count($trace) - 1; $d >= 0; $d--) { $v = $trace[$d]; $k = $x - $y; if ($k === -$d || $k !== $d && $v[$k - 1] < $v[$k + 1]) { $prevK = $k + 1; } else { $prevK = $k - 1; } $prevX = $v[$prevK]; $prevY = $prevX - $prevK; while ($x > $prevX && $y > $prevY) { $result[] = new DiffElem(DiffElem::TYPE_KEEP, $a[$x - 1], $b[$y - 1]); $x--; $y--; } if ($d === 0) { break; } while ($x > $prevX) { $result[] = new DiffElem(DiffElem::TYPE_REMOVE, $a[$x - 1], null); $x--; } while ($y > $prevY) { $result[] = new DiffElem(DiffElem::TYPE_ADD, null, $b[$y - 1]); $y--; } } return \array_reverse($result); } /** * Coalesce equal-length sequences of remove+add into a replace operation. * * @param DiffElem[] $diff * @return DiffElem[] */ private function coalesceReplacements(array $diff) { $newDiff = []; $c = \count($diff); for ($i = 0; $i < $c; $i++) { $diffType = $diff[$i]->type; if ($diffType !== DiffElem::TYPE_REMOVE) { $newDiff[] = $diff[$i]; continue; } $j = $i; while ($j < $c && $diff[$j]->type === DiffElem::TYPE_REMOVE) { $j++; } $k = $j; while ($k < $c && $diff[$k]->type === DiffElem::TYPE_ADD) { $k++; } if ($j - $i === $k - $j) { $len = $j - $i; for ($n = 0; $n < $len; $n++) { $newDiff[] = new DiffElem(DiffElem::TYPE_REPLACE, $diff[$i + $n]->old, $diff[$j + $n]->new); } } else { for (; $i < $k; $i++) { $newDiff[] = $diff[$i]; } } $i = $k - 1; } return $newDiff; } } tokens = $tokens; $this->indentMap = $this->calcIndentMap(); } /** * Whether the given position is immediately surrounded by parenthesis. * * @param int $startPos Start position * @param int $endPos End position * * @return bool */ public function haveParens(int $startPos, int $endPos) : bool { return $this->haveTokenImmediatelyBefore($startPos, '(') && $this->haveTokenImmediatelyAfter($endPos, ')'); } /** * Whether the given position is immediately surrounded by braces. * * @param int $startPos Start position * @param int $endPos End position * * @return bool */ public function haveBraces(int $startPos, int $endPos) : bool { return ($this->haveTokenImmediatelyBefore($startPos, '{') || $this->haveTokenImmediatelyBefore($startPos, \T_CURLY_OPEN)) && $this->haveTokenImmediatelyAfter($endPos, '}'); } /** * Check whether the position is directly preceded by a certain token type. * * During this check whitespace and comments are skipped. * * @param int $pos Position before which the token should occur * @param int|string $expectedTokenType Token to check for * * @return bool Whether the expected token was found */ public function haveTokenImmediatelyBefore(int $pos, $expectedTokenType) : bool { $tokens = $this->tokens; $pos--; for (; $pos >= 0; $pos--) { $tokenType = $tokens[$pos][0]; if ($tokenType === $expectedTokenType) { return \true; } if ($tokenType !== \T_WHITESPACE && $tokenType !== \T_COMMENT && $tokenType !== \T_DOC_COMMENT) { break; } } return \false; } /** * Check whether the position is directly followed by a certain token type. * * During this check whitespace and comments are skipped. * * @param int $pos Position after which the token should occur * @param int|string $expectedTokenType Token to check for * * @return bool Whether the expected token was found */ public function haveTokenImmediatelyAfter(int $pos, $expectedTokenType) : bool { $tokens = $this->tokens; $pos++; for (; $pos < \count($tokens); $pos++) { $tokenType = $tokens[$pos][0]; if ($tokenType === $expectedTokenType) { return \true; } if ($tokenType !== \T_WHITESPACE && $tokenType !== \T_COMMENT && $tokenType !== \T_DOC_COMMENT) { break; } } return \false; } public function skipLeft(int $pos, $skipTokenType) { $tokens = $this->tokens; $pos = $this->skipLeftWhitespace($pos); if ($skipTokenType === \T_WHITESPACE) { return $pos; } if ($tokens[$pos][0] !== $skipTokenType) { // Shouldn't happen. The skip token MUST be there throw new \Exception('Encountered unexpected token'); } $pos--; return $this->skipLeftWhitespace($pos); } public function skipRight(int $pos, $skipTokenType) { $tokens = $this->tokens; $pos = $this->skipRightWhitespace($pos); if ($skipTokenType === \T_WHITESPACE) { return $pos; } if ($tokens[$pos][0] !== $skipTokenType) { // Shouldn't happen. The skip token MUST be there throw new \Exception('Encountered unexpected token'); } $pos++; return $this->skipRightWhitespace($pos); } /** * Return first non-whitespace token position smaller or equal to passed position. * * @param int $pos Token position * @return int Non-whitespace token position */ public function skipLeftWhitespace(int $pos) { $tokens = $this->tokens; for (; $pos >= 0; $pos--) { $type = $tokens[$pos][0]; if ($type !== \T_WHITESPACE && $type !== \T_COMMENT && $type !== \T_DOC_COMMENT) { break; } } return $pos; } /** * Return first non-whitespace position greater or equal to passed position. * * @param int $pos Token position * @return int Non-whitespace token position */ public function skipRightWhitespace(int $pos) { $tokens = $this->tokens; for ($count = \count($tokens); $pos < $count; $pos++) { $type = $tokens[$pos][0]; if ($type !== \T_WHITESPACE && $type !== \T_COMMENT && $type !== \T_DOC_COMMENT) { break; } } return $pos; } public function findRight(int $pos, $findTokenType) { $tokens = $this->tokens; for ($count = \count($tokens); $pos < $count; $pos++) { $type = $tokens[$pos][0]; if ($type === $findTokenType) { return $pos; } } return -1; } /** * Whether the given position range contains a certain token type. * * @param int $startPos Starting position (inclusive) * @param int $endPos Ending position (exclusive) * @param int|string $tokenType Token type to look for * @return bool Whether the token occurs in the given range */ public function haveTokenInRange(int $startPos, int $endPos, $tokenType) { $tokens = $this->tokens; for ($pos = $startPos; $pos < $endPos; $pos++) { if ($tokens[$pos][0] === $tokenType) { return \true; } } return \false; } public function haveBracesInRange(int $startPos, int $endPos) { return $this->haveTokenInRange($startPos, $endPos, '{') || $this->haveTokenInRange($startPos, $endPos, \T_CURLY_OPEN) || $this->haveTokenInRange($startPos, $endPos, '}'); } public function haveTagInRange(int $startPos, int $endPos) : bool { return $this->haveTokenInRange($startPos, $endPos, \T_OPEN_TAG) || $this->haveTokenInRange($startPos, $endPos, \T_CLOSE_TAG); } /** * Get indentation before token position. * * @param int $pos Token position * * @return int Indentation depth (in spaces) */ public function getIndentationBefore(int $pos) : int { return $this->indentMap[$pos]; } /** * Get the code corresponding to a token offset range, optionally adjusted for indentation. * * @param int $from Token start position (inclusive) * @param int $to Token end position (exclusive) * @param int $indent By how much the code should be indented (can be negative as well) * * @return string Code corresponding to token range, adjusted for indentation */ public function getTokenCode(int $from, int $to, int $indent) : string { $tokens = $this->tokens; $result = ''; for ($pos = $from; $pos < $to; $pos++) { $token = $tokens[$pos]; if (\is_array($token)) { $type = $token[0]; $content = $token[1]; if ($type === \T_CONSTANT_ENCAPSED_STRING || $type === \T_ENCAPSED_AND_WHITESPACE) { $result .= $content; } else { // TODO Handle non-space indentation if ($indent < 0) { $result .= \str_replace("\n" . \str_repeat(" ", -$indent), "\n", $content); } elseif ($indent > 0) { $result .= \str_replace("\n", "\n" . \str_repeat(" ", $indent), $content); } else { $result .= $content; } } } else { $result .= $token; } } return $result; } /** * Precalculate the indentation at every token position. * * @return int[] Token position to indentation map */ private function calcIndentMap() { $indentMap = []; $indent = 0; foreach ($this->tokens as $token) { $indentMap[] = $indent; if ($token[0] === \T_WHITESPACE) { $content = $token[1]; $newlinePos = \strrpos($content, "\n"); if (\false !== $newlinePos) { $indent = \strlen($content) - $newlinePos - 1; } } } // Add a sentinel for one past end of the file $indentMap[] = $indent; return $indentMap; } } type = $type; $this->old = $old; $this->new = $new; } } attrGroups = $attrGroups; $this->flags = $flags; $this->args = $args; $this->extends = $extends; $this->implements = $implements; $this->stmts = $stmts; } public static function fromNewNode(Expr\New_ $newNode) { $class = $newNode->class; \assert($class instanceof Node\Stmt\Class_); // We don't assert that $class->name is null here, to allow consumers to assign unique names // to anonymous classes for their own purposes. We simplify ignore the name here. return new self($class->attrGroups, $class->flags, $newNode->args, $class->extends, $class->implements, $class->stmts, $newNode->getAttributes()); } public function getType() : string { return 'Expr_PrintableNewAnonClass'; } public function getSubNodeNames() : array { return ['attrGroups', 'flags', 'args', 'extends', 'implements', 'stmts']; } } lexer = $lexer; if (isset($options['throwOnError'])) { throw new \LogicException('"throwOnError" is no longer supported, use "errorHandler" instead'); } $this->initReduceCallbacks(); } /** * Parses PHP code into a node tree. * * If a non-throwing error handler is used, the parser will continue parsing after an error * occurred and attempt to build a partial AST. * * @param string $code The source code to parse * @param ErrorHandler|null $errorHandler Error handler to use for lexer/parser errors, defaults * to ErrorHandler\Throwing. * * @return Node\Stmt[]|null Array of statements (or null non-throwing error handler is used and * the parser was unable to recover from an error). */ public function parse(string $code, ?ErrorHandler $errorHandler = null) { $this->errorHandler = $errorHandler ?: new ErrorHandler\Throwing(); $this->lexer->startLexing($code, $this->errorHandler); $result = $this->doParse(); // Clear out some of the interior state, so we don't hold onto unnecessary // memory between uses of the parser $this->startAttributeStack = []; $this->endAttributeStack = []; $this->semStack = []; $this->semValue = null; return $result; } protected function doParse() { // We start off with no lookahead-token $symbol = self::SYMBOL_NONE; // The attributes for a node are taken from the first and last token of the node. // From the first token only the startAttributes are taken and from the last only // the endAttributes. Both are merged using the array union operator (+). $startAttributes = []; $endAttributes = []; $this->endAttributes = $endAttributes; // Keep stack of start and end attributes $this->startAttributeStack = []; $this->endAttributeStack = [$endAttributes]; // Start off in the initial state and keep a stack of previous states $state = 0; $stateStack = [$state]; // Semantic value stack (contains values of tokens and semantic action results) $this->semStack = []; // Current position in the stack(s) $stackPos = 0; $this->errorState = 0; for (;;) { //$this->traceNewState($state, $symbol); if ($this->actionBase[$state] === 0) { $rule = $this->actionDefault[$state]; } else { if ($symbol === self::SYMBOL_NONE) { // Fetch the next token id from the lexer and fetch additional info by-ref. // The end attributes are fetched into a temporary variable and only set once the token is really // shifted (not during read). Otherwise you would sometimes get off-by-one errors, when a rule is // reduced after a token was read but not yet shifted. $tokenId = $this->lexer->getNextToken($tokenValue, $startAttributes, $endAttributes); // map the lexer token id to the internally used symbols $symbol = $tokenId >= 0 && $tokenId < $this->tokenToSymbolMapSize ? $this->tokenToSymbol[$tokenId] : $this->invalidSymbol; if ($symbol === $this->invalidSymbol) { throw new \RangeException(\sprintf('The lexer returned an invalid token (id=%d, value=%s)', $tokenId, $tokenValue)); } // Allow productions to access the start attributes of the lookahead token. $this->lookaheadStartAttributes = $startAttributes; //$this->traceRead($symbol); } $idx = $this->actionBase[$state] + $symbol; if (($idx >= 0 && $idx < $this->actionTableSize && $this->actionCheck[$idx] === $symbol || $state < $this->YY2TBLSTATE && ($idx = $this->actionBase[$state + $this->numNonLeafStates] + $symbol) >= 0 && $idx < $this->actionTableSize && $this->actionCheck[$idx] === $symbol) && ($action = $this->action[$idx]) !== $this->defaultAction) { /* * >= numNonLeafStates: shift and reduce * > 0: shift * = 0: accept * < 0: reduce * = -YYUNEXPECTED: error */ if ($action > 0) { /* shift */ //$this->traceShift($symbol); ++$stackPos; $stateStack[$stackPos] = $state = $action; $this->semStack[$stackPos] = $tokenValue; $this->startAttributeStack[$stackPos] = $startAttributes; $this->endAttributeStack[$stackPos] = $endAttributes; $this->endAttributes = $endAttributes; $symbol = self::SYMBOL_NONE; if ($this->errorState) { --$this->errorState; } if ($action < $this->numNonLeafStates) { continue; } /* $yyn >= numNonLeafStates means shift-and-reduce */ $rule = $action - $this->numNonLeafStates; } else { $rule = -$action; } } else { $rule = $this->actionDefault[$state]; } } for (;;) { if ($rule === 0) { /* accept */ //$this->traceAccept(); return $this->semValue; } elseif ($rule !== $this->unexpectedTokenRule) { /* reduce */ //$this->traceReduce($rule); try { $this->reduceCallbacks[$rule]($stackPos); } catch (Error $e) { if (-1 === $e->getStartLine() && isset($startAttributes['startLine'])) { $e->setStartLine($startAttributes['startLine']); } $this->emitError($e); // Can't recover from this type of error return null; } /* Goto - shift nonterminal */ $lastEndAttributes = $this->endAttributeStack[$stackPos]; $ruleLength = $this->ruleToLength[$rule]; $stackPos -= $ruleLength; $nonTerminal = $this->ruleToNonTerminal[$rule]; $idx = $this->gotoBase[$nonTerminal] + $stateStack[$stackPos]; if ($idx >= 0 && $idx < $this->gotoTableSize && $this->gotoCheck[$idx] === $nonTerminal) { $state = $this->goto[$idx]; } else { $state = $this->gotoDefault[$nonTerminal]; } ++$stackPos; $stateStack[$stackPos] = $state; $this->semStack[$stackPos] = $this->semValue; $this->endAttributeStack[$stackPos] = $lastEndAttributes; if ($ruleLength === 0) { // Empty productions use the start attributes of the lookahead token. $this->startAttributeStack[$stackPos] = $this->lookaheadStartAttributes; } } else { /* error */ switch ($this->errorState) { case 0: $msg = $this->getErrorMessage($symbol, $state); $this->emitError(new Error($msg, $startAttributes + $endAttributes)); // Break missing intentionally case 1: case 2: $this->errorState = 3; // Pop until error-expecting state uncovered while (!(($idx = $this->actionBase[$state] + $this->errorSymbol) >= 0 && $idx < $this->actionTableSize && $this->actionCheck[$idx] === $this->errorSymbol || $state < $this->YY2TBLSTATE && ($idx = $this->actionBase[$state + $this->numNonLeafStates] + $this->errorSymbol) >= 0 && $idx < $this->actionTableSize && $this->actionCheck[$idx] === $this->errorSymbol) || ($action = $this->action[$idx]) === $this->defaultAction) { // Not totally sure about this if ($stackPos <= 0) { // Could not recover from error return null; } $state = $stateStack[--$stackPos]; //$this->tracePop($state); } //$this->traceShift($this->errorSymbol); ++$stackPos; $stateStack[$stackPos] = $state = $action; // We treat the error symbol as being empty, so we reset the end attributes // to the end attributes of the last non-error symbol $this->startAttributeStack[$stackPos] = $this->lookaheadStartAttributes; $this->endAttributeStack[$stackPos] = $this->endAttributeStack[$stackPos - 1]; $this->endAttributes = $this->endAttributeStack[$stackPos - 1]; break; case 3: if ($symbol === 0) { // Reached EOF without recovering from error return null; } //$this->traceDiscard($symbol); $symbol = self::SYMBOL_NONE; break 2; } } if ($state < $this->numNonLeafStates) { break; } /* >= numNonLeafStates means shift-and-reduce */ $rule = $state - $this->numNonLeafStates; } } throw new \RuntimeException('Reached end of parser loop'); } protected function emitError(Error $error) { $this->errorHandler->handleError($error); } /** * Format error message including expected tokens. * * @param int $symbol Unexpected symbol * @param int $state State at time of error * * @return string Formatted error message */ protected function getErrorMessage(int $symbol, int $state) : string { $expectedString = ''; if ($expected = $this->getExpectedTokens($state)) { $expectedString = ', expecting ' . \implode(' or ', $expected); } return 'Syntax error, unexpected ' . $this->symbolToName[$symbol] . $expectedString; } /** * Get limited number of expected tokens in given state. * * @param int $state State * * @return string[] Expected tokens. If too many, an empty array is returned. */ protected function getExpectedTokens(int $state) : array { $expected = []; $base = $this->actionBase[$state]; foreach ($this->symbolToName as $symbol => $name) { $idx = $base + $symbol; if ($idx >= 0 && $idx < $this->actionTableSize && $this->actionCheck[$idx] === $symbol || $state < $this->YY2TBLSTATE && ($idx = $this->actionBase[$state + $this->numNonLeafStates] + $symbol) >= 0 && $idx < $this->actionTableSize && $this->actionCheck[$idx] === $symbol) { if ($this->action[$idx] !== $this->unexpectedTokenRule && $this->action[$idx] !== $this->defaultAction && $symbol !== $this->errorSymbol) { if (\count($expected) === 4) { /* Too many expected tokens */ return []; } $expected[] = $name; } } } return $expected; } /* * Tracing functions used for debugging the parser. */ /* protected function traceNewState($state, $symbol) { echo '% State ' . $state . ', Lookahead ' . ($symbol == self::SYMBOL_NONE ? '--none--' : $this->symbolToName[$symbol]) . "\n"; } protected function traceRead($symbol) { echo '% Reading ' . $this->symbolToName[$symbol] . "\n"; } protected function traceShift($symbol) { echo '% Shift ' . $this->symbolToName[$symbol] . "\n"; } protected function traceAccept() { echo "% Accepted.\n"; } protected function traceReduce($n) { echo '% Reduce by (' . $n . ') ' . $this->productions[$n] . "\n"; } protected function tracePop($state) { echo '% Recovering, uncovered state ' . $state . "\n"; } protected function traceDiscard($symbol) { echo '% Discard ' . $this->symbolToName[$symbol] . "\n"; } */ /* * Helper functions invoked by semantic actions */ /** * Moves statements of semicolon-style namespaces into $ns->stmts and checks various error conditions. * * @param Node\Stmt[] $stmts * @return Node\Stmt[] */ protected function handleNamespaces(array $stmts) : array { $hasErrored = \false; $style = $this->getNamespacingStyle($stmts); if (null === $style) { // not namespaced, nothing to do return $stmts; } elseif ('brace' === $style) { // For braced namespaces we only have to check that there are no invalid statements between the namespaces $afterFirstNamespace = \false; foreach ($stmts as $stmt) { if ($stmt instanceof Node\Stmt\Namespace_) { $afterFirstNamespace = \true; } elseif (!$stmt instanceof Node\Stmt\HaltCompiler && !$stmt instanceof Node\Stmt\Nop && $afterFirstNamespace && !$hasErrored) { $this->emitError(new Error('No code may exist outside of namespace {}', $stmt->getAttributes())); $hasErrored = \true; // Avoid one error for every statement } } return $stmts; } else { // For semicolon namespaces we have to move the statements after a namespace declaration into ->stmts $resultStmts = []; $targetStmts =& $resultStmts; $lastNs = null; foreach ($stmts as $stmt) { if ($stmt instanceof Node\Stmt\Namespace_) { if ($lastNs !== null) { $this->fixupNamespaceAttributes($lastNs); } if ($stmt->stmts === null) { $stmt->stmts = []; $targetStmts =& $stmt->stmts; $resultStmts[] = $stmt; } else { // This handles the invalid case of mixed style namespaces $resultStmts[] = $stmt; $targetStmts =& $resultStmts; } $lastNs = $stmt; } elseif ($stmt instanceof Node\Stmt\HaltCompiler) { // __halt_compiler() is not moved into the namespace $resultStmts[] = $stmt; } else { $targetStmts[] = $stmt; } } if ($lastNs !== null) { $this->fixupNamespaceAttributes($lastNs); } return $resultStmts; } } private function fixupNamespaceAttributes(Node\Stmt\Namespace_ $stmt) { // We moved the statements into the namespace node, as such the end of the namespace node // needs to be extended to the end of the statements. if (empty($stmt->stmts)) { return; } // We only move the builtin end attributes here. This is the best we can do with the // knowledge we have. $endAttributes = ['endLine', 'endFilePos', 'endTokenPos']; $lastStmt = $stmt->stmts[\count($stmt->stmts) - 1]; foreach ($endAttributes as $endAttribute) { if ($lastStmt->hasAttribute($endAttribute)) { $stmt->setAttribute($endAttribute, $lastStmt->getAttribute($endAttribute)); } } } /** * Determine namespacing style (semicolon or brace) * * @param Node[] $stmts Top-level statements. * * @return null|string One of "semicolon", "brace" or null (no namespaces) */ private function getNamespacingStyle(array $stmts) { $style = null; $hasNotAllowedStmts = \false; foreach ($stmts as $i => $stmt) { if ($stmt instanceof Node\Stmt\Namespace_) { $currentStyle = null === $stmt->stmts ? 'semicolon' : 'brace'; if (null === $style) { $style = $currentStyle; if ($hasNotAllowedStmts) { $this->emitError(new Error('Namespace declaration statement has to be the very first statement in the script', $stmt->getLine())); } } elseif ($style !== $currentStyle) { $this->emitError(new Error('Cannot mix bracketed namespace declarations with unbracketed namespace declarations', $stmt->getLine())); // Treat like semicolon style for namespace normalization return 'semicolon'; } continue; } /* declare(), __halt_compiler() and nops can be used before a namespace declaration */ if ($stmt instanceof Node\Stmt\Declare_ || $stmt instanceof Node\Stmt\HaltCompiler || $stmt instanceof Node\Stmt\Nop) { continue; } /* There may be a hashbang line at the very start of the file */ if ($i === 0 && $stmt instanceof Node\Stmt\InlineHTML && \preg_match('/\\A#!.*\\r?\\n\\z/', $stmt->value)) { continue; } /* Everything else if forbidden before namespace declarations */ $hasNotAllowedStmts = \true; } return $style; } /** * Fix up parsing of static property calls in PHP 5. * * In PHP 5 A::$b[c][d] and A::$b[c][d]() have very different interpretation. The former is * interpreted as (A::$b)[c][d], while the latter is the same as A::{$b[c][d]}(). We parse the * latter as the former initially and this method fixes the AST into the correct form when we * encounter the "()". * * @param Node\Expr\StaticPropertyFetch|Node\Expr\ArrayDimFetch $prop * @param Node\Arg[] $args * @param array $attributes * * @return Expr\StaticCall */ protected function fixupPhp5StaticPropCall($prop, array $args, array $attributes) : Expr\StaticCall { if ($prop instanceof Node\Expr\StaticPropertyFetch) { $name = $prop->name instanceof VarLikeIdentifier ? $prop->name->toString() : $prop->name; $var = new Expr\Variable($name, $prop->name->getAttributes()); return new Expr\StaticCall($prop->class, $var, $args, $attributes); } elseif ($prop instanceof Node\Expr\ArrayDimFetch) { $tmp = $prop; while ($tmp->var instanceof Node\Expr\ArrayDimFetch) { $tmp = $tmp->var; } /** @var Expr\StaticPropertyFetch $staticProp */ $staticProp = $tmp->var; // Set start attributes to attributes of innermost node $tmp = $prop; $this->fixupStartAttributes($tmp, $staticProp->name); while ($tmp->var instanceof Node\Expr\ArrayDimFetch) { $tmp = $tmp->var; $this->fixupStartAttributes($tmp, $staticProp->name); } $name = $staticProp->name instanceof VarLikeIdentifier ? $staticProp->name->toString() : $staticProp->name; $tmp->var = new Expr\Variable($name, $staticProp->name->getAttributes()); return new Expr\StaticCall($staticProp->class, $prop, $args, $attributes); } else { throw new \Exception(); } } protected function fixupStartAttributes(Node $to, Node $from) { $startAttributes = ['startLine', 'startFilePos', 'startTokenPos']; foreach ($startAttributes as $startAttribute) { if ($from->hasAttribute($startAttribute)) { $to->setAttribute($startAttribute, $from->getAttribute($startAttribute)); } } } protected function handleBuiltinTypes(Name $name) { $builtinTypes = ['bool' => \true, 'int' => \true, 'float' => \true, 'string' => \true, 'iterable' => \true, 'void' => \true, 'object' => \true, 'null' => \true, 'false' => \true, 'mixed' => \true, 'never' => \true, 'true' => \true]; if (!$name->isUnqualified()) { return $name; } $lowerName = $name->toLowerString(); if (!isset($builtinTypes[$lowerName])) { return $name; } return new Node\Identifier($lowerName, $name->getAttributes()); } /** * Get combined start and end attributes at a stack location * * @param int $pos Stack location * * @return array Combined start and end attributes */ protected function getAttributesAt(int $pos) : array { return $this->startAttributeStack[$pos] + $this->endAttributeStack[$pos]; } protected function getFloatCastKind(string $cast) : int { $cast = \strtolower($cast); if (\strpos($cast, 'float') !== \false) { return Double::KIND_FLOAT; } if (\strpos($cast, 'real') !== \false) { return Double::KIND_REAL; } return Double::KIND_DOUBLE; } protected function parseLNumber($str, $attributes, $allowInvalidOctal = \false) { try { return LNumber::fromString($str, $attributes, $allowInvalidOctal); } catch (Error $error) { $this->emitError($error); // Use dummy value return new LNumber(0, $attributes); } } /** * Parse a T_NUM_STRING token into either an integer or string node. * * @param string $str Number string * @param array $attributes Attributes * * @return LNumber|String_ Integer or string node. */ protected function parseNumString(string $str, array $attributes) { if (!\preg_match('/^(?:0|-?[1-9][0-9]*)$/', $str)) { return new String_($str, $attributes); } $num = +$str; if (!\is_int($num)) { return new String_($str, $attributes); } return new LNumber($num, $attributes); } protected function stripIndentation(string $string, int $indentLen, string $indentChar, bool $newlineAtStart, bool $newlineAtEnd, array $attributes) { if ($indentLen === 0) { return $string; } $start = $newlineAtStart ? '(?:(?<=\\n)|\\A)' : '(?<=\\n)'; $end = $newlineAtEnd ? '(?:(?=[\\r\\n])|\\z)' : '(?=[\\r\\n])'; $regex = '/' . $start . '([ \\t]*)(' . $end . ')?/'; return \preg_replace_callback($regex, function ($matches) use($indentLen, $indentChar, $attributes) { $prefix = \substr($matches[1], 0, $indentLen); if (\false !== \strpos($prefix, $indentChar === " " ? "\t" : " ")) { $this->emitError(new Error('Invalid indentation - tabs and spaces cannot be mixed', $attributes)); } elseif (\strlen($prefix) < $indentLen && !isset($matches[2])) { $this->emitError(new Error('Invalid body indentation level ' . '(expecting an indentation level of at least ' . $indentLen . ')', $attributes)); } return \substr($matches[0], \strlen($prefix)); }, $string); } protected function parseDocString(string $startToken, $contents, string $endToken, array $attributes, array $endTokenAttributes, bool $parseUnicodeEscape) { $kind = \strpos($startToken, "'") === \false ? String_::KIND_HEREDOC : String_::KIND_NOWDOC; $regex = '/\\A[bB]?<<<[ \\t]*[\'"]?([a-zA-Z_\\x7f-\\xff][a-zA-Z0-9_\\x7f-\\xff]*)[\'"]?(?:\\r\\n|\\n|\\r)\\z/'; $result = \preg_match($regex, $startToken, $matches); \assert($result === 1); $label = $matches[1]; $result = \preg_match('/\\A[ \\t]*/', $endToken, $matches); \assert($result === 1); $indentation = $matches[0]; $attributes['kind'] = $kind; $attributes['docLabel'] = $label; $attributes['docIndentation'] = $indentation; $indentHasSpaces = \false !== \strpos($indentation, " "); $indentHasTabs = \false !== \strpos($indentation, "\t"); if ($indentHasSpaces && $indentHasTabs) { $this->emitError(new Error('Invalid indentation - tabs and spaces cannot be mixed', $endTokenAttributes)); // Proceed processing as if this doc string is not indented $indentation = ''; } $indentLen = \strlen($indentation); $indentChar = $indentHasSpaces ? " " : "\t"; if (\is_string($contents)) { if ($contents === '') { return new String_('', $attributes); } $contents = $this->stripIndentation($contents, $indentLen, $indentChar, \true, \true, $attributes); $contents = \preg_replace('~(\\r\\n|\\n|\\r)\\z~', '', $contents); if ($kind === String_::KIND_HEREDOC) { $contents = String_::parseEscapeSequences($contents, null, $parseUnicodeEscape); } return new String_($contents, $attributes); } else { \assert(\count($contents) > 0); if (!$contents[0] instanceof Node\Scalar\EncapsedStringPart) { // If there is no leading encapsed string part, pretend there is an empty one $this->stripIndentation('', $indentLen, $indentChar, \true, \false, $contents[0]->getAttributes()); } $newContents = []; foreach ($contents as $i => $part) { if ($part instanceof Node\Scalar\EncapsedStringPart) { $isLast = $i === \count($contents) - 1; $part->value = $this->stripIndentation($part->value, $indentLen, $indentChar, $i === 0, $isLast, $part->getAttributes()); $part->value = String_::parseEscapeSequences($part->value, null, $parseUnicodeEscape); if ($isLast) { $part->value = \preg_replace('~(\\r\\n|\\n|\\r)\\z~', '', $part->value); } if ('' === $part->value) { continue; } } $newContents[] = $part; } return new Encapsed($newContents, $attributes); } } /** * Create attributes for a zero-length common-capturing nop. * * @param Comment[] $comments * @return array */ protected function createCommentNopAttributes(array $comments) { $comment = $comments[\count($comments) - 1]; $commentEndLine = $comment->getEndLine(); $commentEndFilePos = $comment->getEndFilePos(); $commentEndTokenPos = $comment->getEndTokenPos(); $attributes = ['comments' => $comments]; if (-1 !== $commentEndLine) { $attributes['startLine'] = $commentEndLine; $attributes['endLine'] = $commentEndLine; } if (-1 !== $commentEndFilePos) { $attributes['startFilePos'] = $commentEndFilePos + 1; $attributes['endFilePos'] = $commentEndFilePos; } if (-1 !== $commentEndTokenPos) { $attributes['startTokenPos'] = $commentEndTokenPos + 1; $attributes['endTokenPos'] = $commentEndTokenPos; } return $attributes; } /** @param ElseIf_|Else_ $node */ protected function fixupAlternativeElse($node) { // Make sure a trailing nop statement carrying comments is part of the node. $numStmts = \count($node->stmts); if ($numStmts !== 0 && $node->stmts[$numStmts - 1] instanceof Nop) { $nopAttrs = $node->stmts[$numStmts - 1]->getAttributes(); if (isset($nopAttrs['endLine'])) { $node->setAttribute('endLine', $nopAttrs['endLine']); } if (isset($nopAttrs['endFilePos'])) { $node->setAttribute('endFilePos', $nopAttrs['endFilePos']); } if (isset($nopAttrs['endTokenPos'])) { $node->setAttribute('endTokenPos', $nopAttrs['endTokenPos']); } } } protected function checkClassModifier($a, $b, $modifierPos) { try { Class_::verifyClassModifier($a, $b); } catch (Error $error) { $error->setAttributes($this->getAttributesAt($modifierPos)); $this->emitError($error); } } protected function checkModifier($a, $b, $modifierPos) { // Jumping through some hoops here because verifyModifier() is also used elsewhere try { Class_::verifyModifier($a, $b); } catch (Error $error) { $error->setAttributes($this->getAttributesAt($modifierPos)); $this->emitError($error); } } protected function checkParam(Param $node) { if ($node->variadic && null !== $node->default) { $this->emitError(new Error('Variadic parameter cannot have a default value', $node->default->getAttributes())); } } protected function checkTryCatch(TryCatch $node) { if (empty($node->catches) && null === $node->finally) { $this->emitError(new Error('Cannot use try without catch or finally', $node->getAttributes())); } } protected function checkNamespace(Namespace_ $node) { if (null !== $node->stmts) { foreach ($node->stmts as $stmt) { if ($stmt instanceof Namespace_) { $this->emitError(new Error('Namespace declarations cannot be nested', $stmt->getAttributes())); } } } } private function checkClassName($name, $namePos) { if (null !== $name && $name->isSpecialClassName()) { $this->emitError(new Error(\sprintf('Cannot use \'%s\' as class name as it is reserved', $name), $this->getAttributesAt($namePos))); } } private function checkImplementedInterfaces(array $interfaces) { foreach ($interfaces as $interface) { if ($interface->isSpecialClassName()) { $this->emitError(new Error(\sprintf('Cannot use \'%s\' as interface name as it is reserved', $interface), $interface->getAttributes())); } } } protected function checkClass(Class_ $node, $namePos) { $this->checkClassName($node->name, $namePos); if ($node->extends && $node->extends->isSpecialClassName()) { $this->emitError(new Error(\sprintf('Cannot use \'%s\' as class name as it is reserved', $node->extends), $node->extends->getAttributes())); } $this->checkImplementedInterfaces($node->implements); } protected function checkInterface(Interface_ $node, $namePos) { $this->checkClassName($node->name, $namePos); $this->checkImplementedInterfaces($node->extends); } protected function checkEnum(Enum_ $node, $namePos) { $this->checkClassName($node->name, $namePos); $this->checkImplementedInterfaces($node->implements); } protected function checkClassMethod(ClassMethod $node, $modifierPos) { if ($node->flags & Class_::MODIFIER_STATIC) { switch ($node->name->toLowerString()) { case '__construct': $this->emitError(new Error(\sprintf('Constructor %s() cannot be static', $node->name), $this->getAttributesAt($modifierPos))); break; case '__destruct': $this->emitError(new Error(\sprintf('Destructor %s() cannot be static', $node->name), $this->getAttributesAt($modifierPos))); break; case '__clone': $this->emitError(new Error(\sprintf('Clone method %s() cannot be static', $node->name), $this->getAttributesAt($modifierPos))); break; } } if ($node->flags & Class_::MODIFIER_READONLY) { $this->emitError(new Error(\sprintf('Method %s() cannot be readonly', $node->name), $this->getAttributesAt($modifierPos))); } } protected function checkClassConst(ClassConst $node, $modifierPos) { if ($node->flags & Class_::MODIFIER_STATIC) { $this->emitError(new Error("Cannot use 'static' as constant modifier", $this->getAttributesAt($modifierPos))); } if ($node->flags & Class_::MODIFIER_ABSTRACT) { $this->emitError(new Error("Cannot use 'abstract' as constant modifier", $this->getAttributesAt($modifierPos))); } if ($node->flags & Class_::MODIFIER_READONLY) { $this->emitError(new Error("Cannot use 'readonly' as constant modifier", $this->getAttributesAt($modifierPos))); } } protected function checkProperty(Property $node, $modifierPos) { if ($node->flags & Class_::MODIFIER_ABSTRACT) { $this->emitError(new Error('Properties cannot be declared abstract', $this->getAttributesAt($modifierPos))); } if ($node->flags & Class_::MODIFIER_FINAL) { $this->emitError(new Error('Properties cannot be declared final', $this->getAttributesAt($modifierPos))); } } protected function checkUseUse(UseUse $node, $namePos) { if ($node->alias && $node->alias->isSpecialClassName()) { $this->emitError(new Error(\sprintf('Cannot use %s as %s because \'%2$s\' is a special class name', $node->name, $node->alias), $this->getAttributesAt($namePos))); } } } text = $text; $this->startLine = $startLine; $this->startFilePos = $startFilePos; $this->startTokenPos = $startTokenPos; $this->endLine = $endLine; $this->endFilePos = $endFilePos; $this->endTokenPos = $endTokenPos; } /** * Gets the comment text. * * @return string The comment text (including comment delimiters like /*) */ public function getText() : string { return $this->text; } /** * Gets the line number the comment started on. * * @return int Line number (or -1 if not available) */ public function getStartLine() : int { return $this->startLine; } /** * Gets the file offset the comment started on. * * @return int File offset (or -1 if not available) */ public function getStartFilePos() : int { return $this->startFilePos; } /** * Gets the token offset the comment started on. * * @return int Token offset (or -1 if not available) */ public function getStartTokenPos() : int { return $this->startTokenPos; } /** * Gets the line number the comment ends on. * * @return int Line number (or -1 if not available) */ public function getEndLine() : int { return $this->endLine; } /** * Gets the file offset the comment ends on. * * @return int File offset (or -1 if not available) */ public function getEndFilePos() : int { return $this->endFilePos; } /** * Gets the token offset the comment ends on. * * @return int Token offset (or -1 if not available) */ public function getEndTokenPos() : int { return $this->endTokenPos; } /** * Gets the line number the comment started on. * * @deprecated Use getStartLine() instead * * @return int Line number */ public function getLine() : int { return $this->startLine; } /** * Gets the file offset the comment started on. * * @deprecated Use getStartFilePos() instead * * @return int File offset */ public function getFilePos() : int { return $this->startFilePos; } /** * Gets the token offset the comment started on. * * @deprecated Use getStartTokenPos() instead * * @return int Token offset */ public function getTokenPos() : int { return $this->startTokenPos; } /** * Gets the comment text. * * @return string The comment text (including comment delimiters like /*) */ public function __toString() : string { return $this->text; } /** * Gets the reformatted comment text. * * "Reformatted" here means that we try to clean up the whitespace at the * starts of the lines. This is necessary because we receive the comments * without trailing whitespace on the first line, but with trailing whitespace * on all subsequent lines. * * @return mixed|string */ public function getReformattedText() { $text = \trim($this->text); $newlinePos = \strpos($text, "\n"); if (\false === $newlinePos) { // Single line comments don't need further processing return $text; } elseif (\preg_match('((*BSR_ANYCRLF)(*ANYCRLF)^.*(?:\\R\\s+\\*.*)+$)', $text)) { // Multi line comment of the type // // /* // * Some text. // * Some more text. // */ // // is handled by replacing the whitespace sequences before the * by a single space return \preg_replace('(^\\s+\\*)m', ' *', $this->text); } elseif (\preg_match('(^/\\*\\*?\\s*[\\r\\n])', $text) && \preg_match('(\\n(\\s*)\\*/$)', $text, $matches)) { // Multi line comment of the type // // /* // Some text. // Some more text. // */ // // is handled by removing the whitespace sequence on the line before the closing // */ on all lines. So if the last line is " */", then " " is removed at the // start of all lines. return \preg_replace('(^' . \preg_quote($matches[1]) . ')m', '', $text); } elseif (\preg_match('(^/\\*\\*?\\s*(?!\\s))', $text, $matches)) { // Multi line comment of the type // // /* Some text. // Some more text. // Indented text. // Even more text. */ // // is handled by removing the difference between the shortest whitespace prefix on all // lines and the length of the "/* " opening sequence. $prefixLen = $this->getShortestWhitespacePrefixLen(\substr($text, $newlinePos + 1)); $removeLen = $prefixLen - \strlen($matches[0]); return \preg_replace('(^\\s{' . $removeLen . '})m', '', $text); } // No idea how to format this comment, so simply return as is return $text; } /** * Get length of shortest whitespace prefix (at the start of a line). * * If there is a line with no prefix whitespace, 0 is a valid return value. * * @param string $str String to check * @return int Length in characters. Tabs count as single characters. */ private function getShortestWhitespacePrefixLen(string $str) : int { $lines = \explode("\n", $str); $shortestPrefixLen = \INF; foreach ($lines as $line) { \preg_match('(^\\s*)', $line, $matches); $prefixLen = \strlen($matches[0]); if ($prefixLen < $shortestPrefixLen) { $shortestPrefixLen = $prefixLen; } } return $shortestPrefixLen; } /** * @return array * @psalm-return array{nodeType:string, text:mixed, line:mixed, filePos:mixed} */ public function jsonSerialize() : array { // Technically not a node, but we make it look like one anyway $type = $this instanceof Comment\Doc ? 'Comment_Doc' : 'Comment'; return [ 'nodeType' => $type, 'text' => $this->text, // TODO: Rename these to include "start". 'line' => $this->startLine, 'filePos' => $this->startFilePos, 'tokenPos' => $this->startTokenPos, 'endLine' => $this->endLine, 'endFilePos' => $this->endFilePos, 'endTokenPos' => $this->endTokenPos, ]; } } $node stays as-is * * NodeTraverser::DONT_TRAVERSE_CHILDREN * => Children of $node are not traversed. $node stays as-is * * NodeTraverser::STOP_TRAVERSAL * => Traversal is aborted. $node stays as-is * * otherwise * => $node is set to the return value * * @param Node $node Node * * @return null|int|Node Replacement node (or special return value) */ public function enterNode(Node $node); /** * Called when leaving a node. * * Return value semantics: * * null * => $node stays as-is * * NodeTraverser::REMOVE_NODE * => $node is removed from the parent array * * NodeTraverser::STOP_TRAVERSAL * => Traversal is aborted. $node stays as-is * * array (of Nodes) * => The return value is merged into the parent array (at the position of the $node) * * otherwise * => $node is set to the return value * * @param Node $node Node * * @return null|int|Node|Node[] Replacement node (or special return value) */ public function leaveNode(Node $node); /** * Called once after traversal. * * Return value semantics: * * null: $nodes stays as-is * * otherwise: $nodes is set to the return value * * @param Node[] $nodes Array of nodes * * @return null|Node[] Array of nodes */ public function afterTraverse(array $nodes); } filterCallback = $filterCallback; } /** * Get found nodes satisfying the filter callback. * * Nodes are returned in pre-order. * * @return Node[] Found nodes */ public function getFoundNodes() : array { return $this->foundNodes; } public function beforeTraverse(array $nodes) { $this->foundNodes = []; return null; } public function enterNode(Node $node) { $filterCallback = $this->filterCallback; if ($filterCallback($node)) { $this->foundNodes[] = $node; } return null; } } $node->getAttribute('parent'). */ final class ParentConnectingVisitor extends NodeVisitorAbstract { /** * @var Node[] */ private $stack = []; public function beforeTraverse(array $nodes) { $this->stack = []; } public function enterNode(Node $node) { if (!empty($this->stack)) { $node->setAttribute('parent', $this->stack[count($this->stack) - 1]); } $this->stack[] = $node; } public function leaveNode(Node $node) { array_pop($this->stack); } } filterCallback = $filterCallback; } /** * Get found node satisfying the filter callback. * * Returns null if no node satisfies the filter callback. * * @return null|Node Found node (or null if not found) */ public function getFoundNode() { return $this->foundNode; } public function beforeTraverse(array $nodes) { $this->foundNode = null; return null; } public function enterNode(Node $node) { $filterCallback = $this->filterCallback; if ($filterCallback($node)) { $this->foundNode = $node; return NodeTraverser::STOP_TRAVERSAL; } return null; } } setAttribute('origNode', $origNode); return $node; } } nameContext = new NameContext($errorHandler ?? new ErrorHandler\Throwing()); $this->preserveOriginalNames = $options['preserveOriginalNames'] ?? \false; $this->replaceNodes = $options['replaceNodes'] ?? \true; } /** * Get name resolution context. * * @return NameContext */ public function getNameContext() : NameContext { return $this->nameContext; } public function beforeTraverse(array $nodes) { $this->nameContext->startNamespace(); return null; } public function enterNode(Node $node) { if ($node instanceof Stmt\Namespace_) { $this->nameContext->startNamespace($node->name); } elseif ($node instanceof Stmt\Use_) { foreach ($node->uses as $use) { $this->addAlias($use, $node->type, null); } } elseif ($node instanceof Stmt\GroupUse) { foreach ($node->uses as $use) { $this->addAlias($use, $node->type, $node->prefix); } } elseif ($node instanceof Stmt\Class_) { if (null !== $node->extends) { $node->extends = $this->resolveClassName($node->extends); } foreach ($node->implements as &$interface) { $interface = $this->resolveClassName($interface); } $this->resolveAttrGroups($node); if (null !== $node->name) { $this->addNamespacedName($node); } } elseif ($node instanceof Stmt\Interface_) { foreach ($node->extends as &$interface) { $interface = $this->resolveClassName($interface); } $this->resolveAttrGroups($node); $this->addNamespacedName($node); } elseif ($node instanceof Stmt\Enum_) { foreach ($node->implements as &$interface) { $interface = $this->resolveClassName($interface); } $this->resolveAttrGroups($node); if (null !== $node->name) { $this->addNamespacedName($node); } } elseif ($node instanceof Stmt\Trait_) { $this->resolveAttrGroups($node); $this->addNamespacedName($node); } elseif ($node instanceof Stmt\Function_) { $this->resolveSignature($node); $this->resolveAttrGroups($node); $this->addNamespacedName($node); } elseif ($node instanceof Stmt\ClassMethod || $node instanceof Expr\Closure || $node instanceof Expr\ArrowFunction) { $this->resolveSignature($node); $this->resolveAttrGroups($node); } elseif ($node instanceof Stmt\Property) { if (null !== $node->type) { $node->type = $this->resolveType($node->type); } $this->resolveAttrGroups($node); } elseif ($node instanceof Stmt\Const_) { foreach ($node->consts as $const) { $this->addNamespacedName($const); } } else { if ($node instanceof Stmt\ClassConst) { if (null !== $node->type) { $node->type = $this->resolveType($node->type); } $this->resolveAttrGroups($node); } else { if ($node instanceof Stmt\EnumCase) { $this->resolveAttrGroups($node); } elseif ($node instanceof Expr\StaticCall || $node instanceof Expr\StaticPropertyFetch || $node instanceof Expr\ClassConstFetch || $node instanceof Expr\New_ || $node instanceof Expr\Instanceof_) { if ($node->class instanceof Name) { $node->class = $this->resolveClassName($node->class); } } elseif ($node instanceof Stmt\Catch_) { foreach ($node->types as &$type) { $type = $this->resolveClassName($type); } } elseif ($node instanceof Expr\FuncCall) { if ($node->name instanceof Name) { $node->name = $this->resolveName($node->name, Stmt\Use_::TYPE_FUNCTION); } } elseif ($node instanceof Expr\ConstFetch) { $node->name = $this->resolveName($node->name, Stmt\Use_::TYPE_CONSTANT); } elseif ($node instanceof Stmt\TraitUse) { foreach ($node->traits as &$trait) { $trait = $this->resolveClassName($trait); } foreach ($node->adaptations as $adaptation) { if (null !== $adaptation->trait) { $adaptation->trait = $this->resolveClassName($adaptation->trait); } if ($adaptation instanceof Stmt\TraitUseAdaptation\Precedence) { foreach ($adaptation->insteadof as &$insteadof) { $insteadof = $this->resolveClassName($insteadof); } } } } } } return null; } private function addAlias(Stmt\UseUse $use, int $type, ?Name $prefix = null) { // Add prefix for group uses $name = $prefix ? Name::concat($prefix, $use->name) : $use->name; // Type is determined either by individual element or whole use declaration $type |= $use->type; $this->nameContext->addAlias($name, (string) $use->getAlias(), $type, $use->getAttributes()); } /** @param Stmt\Function_|Stmt\ClassMethod|Expr\Closure $node */ private function resolveSignature($node) { foreach ($node->params as $param) { $param->type = $this->resolveType($param->type); $this->resolveAttrGroups($param); } $node->returnType = $this->resolveType($node->returnType); } private function resolveType($node) { if ($node instanceof Name) { return $this->resolveClassName($node); } if ($node instanceof Node\NullableType) { $node->type = $this->resolveType($node->type); return $node; } if ($node instanceof Node\UnionType || $node instanceof Node\IntersectionType) { foreach ($node->types as &$type) { $type = $this->resolveType($type); } return $node; } return $node; } /** * Resolve name, according to name resolver options. * * @param Name $name Function or constant name to resolve * @param int $type One of Stmt\Use_::TYPE_* * * @return Name Resolved name, or original name with attribute */ protected function resolveName(Name $name, int $type) : Name { if (!$this->replaceNodes) { $resolvedName = $this->nameContext->getResolvedName($name, $type); if (null !== $resolvedName) { $name->setAttribute('resolvedName', $resolvedName); } else { $name->setAttribute('namespacedName', FullyQualified::concat($this->nameContext->getNamespace(), $name, $name->getAttributes())); } return $name; } if ($this->preserveOriginalNames) { // Save the original name $originalName = $name; $name = clone $originalName; $name->setAttribute('originalName', $originalName); } $resolvedName = $this->nameContext->getResolvedName($name, $type); if (null !== $resolvedName) { return $resolvedName; } // unqualified names inside a namespace cannot be resolved at compile-time // add the namespaced version of the name as an attribute $name->setAttribute('namespacedName', FullyQualified::concat($this->nameContext->getNamespace(), $name, $name->getAttributes())); return $name; } protected function resolveClassName(Name $name) { return $this->resolveName($name, Stmt\Use_::TYPE_NORMAL); } protected function addNamespacedName(Node $node) { $node->namespacedName = Name::concat($this->nameContext->getNamespace(), (string) $node->name); } protected function resolveAttrGroups(Node $node) { foreach ($node->attrGroups as $attrGroup) { foreach ($attrGroup->attrs as $attr) { $attr->name = $this->resolveClassName($attr->name); } } } } $node->getAttribute('parent'), the previous * node can be accessed through $node->getAttribute('previous'), * and the next node can be accessed through $node->getAttribute('next'). */ final class NodeConnectingVisitor extends NodeVisitorAbstract { /** * @var Node[] */ private $stack = []; /** * @var ?Node */ private $previous; public function beforeTraverse(array $nodes) { $this->stack = []; $this->previous = null; } public function enterNode(Node $node) { if (!empty($this->stack)) { $node->setAttribute('parent', $this->stack[\count($this->stack) - 1]); } if ($this->previous !== null && $this->previous->getAttribute('parent') === $node->getAttribute('parent')) { $node->setAttribute('previous', $this->previous); $this->previous->setAttribute('next', $node); } $this->stack[] = $node; } public function leaveNode(Node $node) { $this->previous = $node; \array_pop($this->stack); } } [aliasName => originalName]] */ protected $aliases = []; /** @var Name[][] Same as $aliases but preserving original case */ protected $origAliases = []; /** @var ErrorHandler Error handler */ protected $errorHandler; /** * Create a name context. * * @param ErrorHandler $errorHandler Error handling used to report errors */ public function __construct(ErrorHandler $errorHandler) { $this->errorHandler = $errorHandler; } /** * Start a new namespace. * * This also resets the alias table. * * @param Name|null $namespace Null is the global namespace */ public function startNamespace(?Name $namespace = null) { $this->namespace = $namespace; $this->origAliases = $this->aliases = [Stmt\Use_::TYPE_NORMAL => [], Stmt\Use_::TYPE_FUNCTION => [], Stmt\Use_::TYPE_CONSTANT => []]; } /** * Add an alias / import. * * @param Name $name Original name * @param string $aliasName Aliased name * @param int $type One of Stmt\Use_::TYPE_* * @param array $errorAttrs Attributes to use to report an error */ public function addAlias(Name $name, string $aliasName, int $type, array $errorAttrs = []) { // Constant names are case sensitive, everything else case insensitive if ($type === Stmt\Use_::TYPE_CONSTANT) { $aliasLookupName = $aliasName; } else { $aliasLookupName = \strtolower($aliasName); } if (isset($this->aliases[$type][$aliasLookupName])) { $typeStringMap = [Stmt\Use_::TYPE_NORMAL => '', Stmt\Use_::TYPE_FUNCTION => 'function ', Stmt\Use_::TYPE_CONSTANT => 'const ']; $this->errorHandler->handleError(new Error(\sprintf('Cannot use %s%s as %s because the name is already in use', $typeStringMap[$type], $name, $aliasName), $errorAttrs)); return; } $this->aliases[$type][$aliasLookupName] = $name; $this->origAliases[$type][$aliasName] = $name; } /** * Get current namespace. * * @return null|Name Namespace (or null if global namespace) */ public function getNamespace() { return $this->namespace; } /** * Get resolved name. * * @param Name $name Name to resolve * @param int $type One of Stmt\Use_::TYPE_{FUNCTION|CONSTANT} * * @return null|Name Resolved name, or null if static resolution is not possible */ public function getResolvedName(Name $name, int $type) { // don't resolve special class names if ($type === Stmt\Use_::TYPE_NORMAL && $name->isSpecialClassName()) { if (!$name->isUnqualified()) { $this->errorHandler->handleError(new Error(\sprintf("'\\%s' is an invalid class name", $name->toString()), $name->getAttributes())); } return $name; } // fully qualified names are already resolved if ($name->isFullyQualified()) { return $name; } // Try to resolve aliases if (null !== ($resolvedName = $this->resolveAlias($name, $type))) { return $resolvedName; } if ($type !== Stmt\Use_::TYPE_NORMAL && $name->isUnqualified()) { if (null === $this->namespace) { // outside of a namespace unaliased unqualified is same as fully qualified return new FullyQualified($name, $name->getAttributes()); } // Cannot resolve statically return null; } // if no alias exists prepend current namespace return FullyQualified::concat($this->namespace, $name, $name->getAttributes()); } /** * Get resolved class name. * * @param Name $name Class ame to resolve * * @return Name Resolved name */ public function getResolvedClassName(Name $name) : Name { return $this->getResolvedName($name, Stmt\Use_::TYPE_NORMAL); } /** * Get possible ways of writing a fully qualified name (e.g., by making use of aliases). * * @param string $name Fully-qualified name (without leading namespace separator) * @param int $type One of Stmt\Use_::TYPE_* * * @return Name[] Possible representations of the name */ public function getPossibleNames(string $name, int $type) : array { $lcName = \strtolower($name); if ($type === Stmt\Use_::TYPE_NORMAL) { // self, parent and static must always be unqualified if ($lcName === "self" || $lcName === "parent" || $lcName === "static") { return [new Name($name)]; } } // Collect possible ways to write this name, starting with the fully-qualified name $possibleNames = [new FullyQualified($name)]; if (null !== ($nsRelativeName = $this->getNamespaceRelativeName($name, $lcName, $type))) { // Make sure there is no alias that makes the normally namespace-relative name // into something else if (null === $this->resolveAlias($nsRelativeName, $type)) { $possibleNames[] = $nsRelativeName; } } // Check for relevant namespace use statements foreach ($this->origAliases[Stmt\Use_::TYPE_NORMAL] as $alias => $orig) { $lcOrig = $orig->toLowerString(); if (0 === \strpos($lcName, $lcOrig . '\\')) { $possibleNames[] = new Name($alias . \substr($name, \strlen($lcOrig))); } } // Check for relevant type-specific use statements foreach ($this->origAliases[$type] as $alias => $orig) { if ($type === Stmt\Use_::TYPE_CONSTANT) { // Constants are are complicated-sensitive $normalizedOrig = $this->normalizeConstName($orig->toString()); if ($normalizedOrig === $this->normalizeConstName($name)) { $possibleNames[] = new Name($alias); } } else { // Everything else is case-insensitive if ($orig->toLowerString() === $lcName) { $possibleNames[] = new Name($alias); } } } return $possibleNames; } /** * Get shortest representation of this fully-qualified name. * * @param string $name Fully-qualified name (without leading namespace separator) * @param int $type One of Stmt\Use_::TYPE_* * * @return Name Shortest representation */ public function getShortName(string $name, int $type) : Name { $possibleNames = $this->getPossibleNames($name, $type); // Find shortest name $shortestName = null; $shortestLength = \INF; foreach ($possibleNames as $possibleName) { $length = \strlen($possibleName->toCodeString()); if ($length < $shortestLength) { $shortestName = $possibleName; $shortestLength = $length; } } return $shortestName; } private function resolveAlias(Name $name, $type) { $firstPart = $name->getFirst(); if ($name->isQualified()) { // resolve aliases for qualified names, always against class alias table $checkName = \strtolower($firstPart); if (isset($this->aliases[Stmt\Use_::TYPE_NORMAL][$checkName])) { $alias = $this->aliases[Stmt\Use_::TYPE_NORMAL][$checkName]; return FullyQualified::concat($alias, $name->slice(1), $name->getAttributes()); } } elseif ($name->isUnqualified()) { // constant aliases are case-sensitive, function aliases case-insensitive $checkName = $type === Stmt\Use_::TYPE_CONSTANT ? $firstPart : \strtolower($firstPart); if (isset($this->aliases[$type][$checkName])) { // resolve unqualified aliases return new FullyQualified($this->aliases[$type][$checkName], $name->getAttributes()); } } // No applicable aliases return null; } private function getNamespaceRelativeName(string $name, string $lcName, int $type) { if (null === $this->namespace) { return new Name($name); } if ($type === Stmt\Use_::TYPE_CONSTANT) { // The constants true/false/null always resolve to the global symbols, even inside a // namespace, so they may be used without qualification if ($lcName === "true" || $lcName === "false" || $lcName === "null") { return new Name($name); } } $namespacePrefix = \strtolower($this->namespace . '\\'); if (0 === \strpos($lcName, $namespacePrefix)) { return new Name(\substr($name, \strlen($namespacePrefix))); } return null; } private function normalizeConstName(string $name) { $nsSep = \strrpos($name, '\\'); if (\false === $nsSep) { return $name; } // Constants have case-insensitive namespace and case-sensitive short-name $ns = \substr($name, 0, $nsSep); $shortName = \substr($name, $nsSep + 1); return \strtolower($ns) . '\\' . $shortName; } } decodeRecursive($value); } private function decodeRecursive($value) { if (\is_array($value)) { if (isset($value['nodeType'])) { if ($value['nodeType'] === 'Comment' || $value['nodeType'] === 'Comment_Doc') { return $this->decodeComment($value); } return $this->decodeNode($value); } return $this->decodeArray($value); } return $value; } private function decodeArray(array $array) : array { $decodedArray = []; foreach ($array as $key => $value) { $decodedArray[$key] = $this->decodeRecursive($value); } return $decodedArray; } private function decodeNode(array $value) : Node { $nodeType = $value['nodeType']; if (!\is_string($nodeType)) { throw new \RuntimeException('Node type must be a string'); } $reflectionClass = $this->reflectionClassFromNodeType($nodeType); /** @var Node $node */ $node = $reflectionClass->newInstanceWithoutConstructor(); if (isset($value['attributes'])) { if (!\is_array($value['attributes'])) { throw new \RuntimeException('Attributes must be an array'); } $node->setAttributes($this->decodeArray($value['attributes'])); } foreach ($value as $name => $subNode) { if ($name === 'nodeType' || $name === 'attributes') { continue; } $node->{$name} = $this->decodeRecursive($subNode); } return $node; } private function decodeComment(array $value) : Comment { $className = $value['nodeType'] === 'Comment' ? Comment::class : Comment\Doc::class; if (!isset($value['text'])) { throw new \RuntimeException('Comment must have text'); } return new $className($value['text'], $value['line'] ?? -1, $value['filePos'] ?? -1, $value['tokenPos'] ?? -1, $value['endLine'] ?? -1, $value['endFilePos'] ?? -1, $value['endTokenPos'] ?? -1); } private function reflectionClassFromNodeType(string $nodeType) : \ReflectionClass { if (!isset($this->reflectionClassCache[$nodeType])) { $className = $this->classNameFromNodeType($nodeType); $this->reflectionClassCache[$nodeType] = new \ReflectionClass($className); } return $this->reflectionClassCache[$nodeType]; } private function classNameFromNodeType(string $nodeType) : string { $className = 'PhpParser\\Node\\' . \strtr($nodeType, '_', '\\'); if (\class_exists($className)) { return $className; } $className .= '_'; if (\class_exists($className)) { return $className; } throw new \RuntimeException("Unknown node type \"{$nodeType}\""); } } visitors[] = $visitor; } /** * Removes an added visitor. * * @param NodeVisitor $visitor */ public function removeVisitor(NodeVisitor $visitor) { foreach ($this->visitors as $index => $storedVisitor) { if ($storedVisitor === $visitor) { unset($this->visitors[$index]); break; } } } /** * Traverses an array of nodes using the registered visitors. * * @param Node[] $nodes Array of nodes * * @return Node[] Traversed array of nodes */ public function traverse(array $nodes) : array { $this->stopTraversal = \false; foreach ($this->visitors as $visitor) { if (null !== ($return = $visitor->beforeTraverse($nodes))) { $nodes = $return; } } $nodes = $this->traverseArray($nodes); foreach ($this->visitors as $visitor) { if (null !== ($return = $visitor->afterTraverse($nodes))) { $nodes = $return; } } return $nodes; } /** * Recursively traverse a node. * * @param Node $node Node to traverse. * * @return Node Result of traversal (may be original node or new one) */ protected function traverseNode(Node $node) : Node { foreach ($node->getSubNodeNames() as $name) { $subNode =& $node->{$name}; if (\is_array($subNode)) { $subNode = $this->traverseArray($subNode); if ($this->stopTraversal) { break; } } elseif ($subNode instanceof Node) { $traverseChildren = \true; $breakVisitorIndex = null; foreach ($this->visitors as $visitorIndex => $visitor) { $return = $visitor->enterNode($subNode); if (null !== $return) { if ($return instanceof Node) { $this->ensureReplacementReasonable($subNode, $return); $subNode = $return; } elseif (self::DONT_TRAVERSE_CHILDREN === $return) { $traverseChildren = \false; } elseif (self::DONT_TRAVERSE_CURRENT_AND_CHILDREN === $return) { $traverseChildren = \false; $breakVisitorIndex = $visitorIndex; break; } elseif (self::STOP_TRAVERSAL === $return) { $this->stopTraversal = \true; break 2; } else { throw new \LogicException('enterNode() returned invalid value of type ' . \gettype($return)); } } } if ($traverseChildren) { $subNode = $this->traverseNode($subNode); if ($this->stopTraversal) { break; } } foreach ($this->visitors as $visitorIndex => $visitor) { $return = $visitor->leaveNode($subNode); if (null !== $return) { if ($return instanceof Node) { $this->ensureReplacementReasonable($subNode, $return); $subNode = $return; } elseif (self::STOP_TRAVERSAL === $return) { $this->stopTraversal = \true; break 2; } elseif (\is_array($return)) { throw new \LogicException('leaveNode() may only return an array ' . 'if the parent structure is an array'); } else { throw new \LogicException('leaveNode() returned invalid value of type ' . \gettype($return)); } } if ($breakVisitorIndex === $visitorIndex) { break; } } } } return $node; } /** * Recursively traverse array (usually of nodes). * * @param array $nodes Array to traverse * * @return array Result of traversal (may be original array or changed one) */ protected function traverseArray(array $nodes) : array { $doNodes = []; foreach ($nodes as $i => &$node) { if ($node instanceof Node) { $traverseChildren = \true; $breakVisitorIndex = null; foreach ($this->visitors as $visitorIndex => $visitor) { $return = $visitor->enterNode($node); if (null !== $return) { if ($return instanceof Node) { $this->ensureReplacementReasonable($node, $return); $node = $return; } elseif (self::DONT_TRAVERSE_CHILDREN === $return) { $traverseChildren = \false; } elseif (self::DONT_TRAVERSE_CURRENT_AND_CHILDREN === $return) { $traverseChildren = \false; $breakVisitorIndex = $visitorIndex; break; } elseif (self::STOP_TRAVERSAL === $return) { $this->stopTraversal = \true; break 2; } else { throw new \LogicException('enterNode() returned invalid value of type ' . \gettype($return)); } } } if ($traverseChildren) { $node = $this->traverseNode($node); if ($this->stopTraversal) { break; } } foreach ($this->visitors as $visitorIndex => $visitor) { $return = $visitor->leaveNode($node); if (null !== $return) { if ($return instanceof Node) { $this->ensureReplacementReasonable($node, $return); $node = $return; } elseif (\is_array($return)) { $doNodes[] = [$i, $return]; break; } elseif (self::REMOVE_NODE === $return) { $doNodes[] = [$i, []]; break; } elseif (self::STOP_TRAVERSAL === $return) { $this->stopTraversal = \true; break 2; } elseif (\false === $return) { throw new \LogicException('bool(false) return from leaveNode() no longer supported. ' . 'Return NodeTraverser::REMOVE_NODE instead'); } else { throw new \LogicException('leaveNode() returned invalid value of type ' . \gettype($return)); } } if ($breakVisitorIndex === $visitorIndex) { break; } } } elseif (\is_array($node)) { throw new \LogicException('Invalid node structure: Contains nested arrays'); } } if (!empty($doNodes)) { while (list($i, $replace) = \array_pop($doNodes)) { \array_splice($nodes, $i, 1, $replace); } } return $nodes; } private function ensureReplacementReasonable($old, $new) { if ($old instanceof Node\Stmt && $new instanceof Node\Expr) { throw new \LogicException("Trying to replace statement ({$old->getType()}) " . "with expression ({$new->getType()}). Are you missing a " . "Stmt_Expression wrapper?"); } if ($old instanceof Node\Expr && $new instanceof Node\Stmt) { throw new \LogicException("Trying to replace expression ({$old->getType()}) " . "with statement ({$new->getType()})"); } } } args($args)); } /** * Creates a namespace builder. * * @param null|string|Node\Name $name Name of the namespace * * @return Builder\Namespace_ The created namespace builder */ public function namespace($name) : Builder\Namespace_ { return new Builder\Namespace_($name); } /** * Creates a class builder. * * @param string $name Name of the class * * @return Builder\Class_ The created class builder */ public function class(string $name) : Builder\Class_ { return new Builder\Class_($name); } /** * Creates an interface builder. * * @param string $name Name of the interface * * @return Builder\Interface_ The created interface builder */ public function interface(string $name) : Builder\Interface_ { return new Builder\Interface_($name); } /** * Creates a trait builder. * * @param string $name Name of the trait * * @return Builder\Trait_ The created trait builder */ public function trait(string $name) : Builder\Trait_ { return new Builder\Trait_($name); } /** * Creates an enum builder. * * @param string $name Name of the enum * * @return Builder\Enum_ The created enum builder */ public function enum(string $name) : Builder\Enum_ { return new Builder\Enum_($name); } /** * Creates a trait use builder. * * @param Node\Name|string ...$traits Trait names * * @return Builder\TraitUse The create trait use builder */ public function useTrait(...$traits) : Builder\TraitUse { return new Builder\TraitUse(...$traits); } /** * Creates a trait use adaptation builder. * * @param Node\Name|string|null $trait Trait name * @param Node\Identifier|string $method Method name * * @return Builder\TraitUseAdaptation The create trait use adaptation builder */ public function traitUseAdaptation($trait, $method = null) : Builder\TraitUseAdaptation { if ($method === null) { $method = $trait; $trait = null; } return new Builder\TraitUseAdaptation($trait, $method); } /** * Creates a method builder. * * @param string $name Name of the method * * @return Builder\Method The created method builder */ public function method(string $name) : Builder\Method { return new Builder\Method($name); } /** * Creates a parameter builder. * * @param string $name Name of the parameter * * @return Builder\Param The created parameter builder */ public function param(string $name) : Builder\Param { return new Builder\Param($name); } /** * Creates a property builder. * * @param string $name Name of the property * * @return Builder\Property The created property builder */ public function property(string $name) : Builder\Property { return new Builder\Property($name); } /** * Creates a function builder. * * @param string $name Name of the function * * @return Builder\Function_ The created function builder */ public function function(string $name) : Builder\Function_ { return new Builder\Function_($name); } /** * Creates a namespace/class use builder. * * @param Node\Name|string $name Name of the entity (namespace or class) to alias * * @return Builder\Use_ The created use builder */ public function use($name) : Builder\Use_ { return new Builder\Use_($name, Use_::TYPE_NORMAL); } /** * Creates a function use builder. * * @param Node\Name|string $name Name of the function to alias * * @return Builder\Use_ The created use function builder */ public function useFunction($name) : Builder\Use_ { return new Builder\Use_($name, Use_::TYPE_FUNCTION); } /** * Creates a constant use builder. * * @param Node\Name|string $name Name of the const to alias * * @return Builder\Use_ The created use const builder */ public function useConst($name) : Builder\Use_ { return new Builder\Use_($name, Use_::TYPE_CONSTANT); } /** * Creates a class constant builder. * * @param string|Identifier $name Name * @param Node\Expr|bool|null|int|float|string|array $value Value * * @return Builder\ClassConst The created use const builder */ public function classConst($name, $value) : Builder\ClassConst { return new Builder\ClassConst($name, $value); } /** * Creates an enum case builder. * * @param string|Identifier $name Name * * @return Builder\EnumCase The created use const builder */ public function enumCase($name) : Builder\EnumCase { return new Builder\EnumCase($name); } /** * Creates node a for a literal value. * * @param Expr|bool|null|int|float|string|array $value $value * * @return Expr */ public function val($value) : Expr { return BuilderHelpers::normalizeValue($value); } /** * Creates variable node. * * @param string|Expr $name Name * * @return Expr\Variable */ public function var($name) : Expr\Variable { if (!\is_string($name) && !$name instanceof Expr) { throw new \LogicException('Variable name must be string or Expr'); } return new Expr\Variable($name); } /** * Normalizes an argument list. * * Creates Arg nodes for all arguments and converts literal values to expressions. * * @param array $args List of arguments to normalize * * @return Arg[] */ public function args(array $args) : array { $normalizedArgs = []; foreach ($args as $key => $arg) { if (!$arg instanceof Arg) { $arg = new Arg(BuilderHelpers::normalizeValue($arg)); } if (\is_string($key)) { $arg->name = BuilderHelpers::normalizeIdentifier($key); } $normalizedArgs[] = $arg; } return $normalizedArgs; } /** * Creates a function call node. * * @param string|Name|Expr $name Function name * @param array $args Function arguments * * @return Expr\FuncCall */ public function funcCall($name, array $args = []) : Expr\FuncCall { return new Expr\FuncCall(BuilderHelpers::normalizeNameOrExpr($name), $this->args($args)); } /** * Creates a method call node. * * @param Expr $var Variable the method is called on * @param string|Identifier|Expr $name Method name * @param array $args Method arguments * * @return Expr\MethodCall */ public function methodCall(Expr $var, $name, array $args = []) : Expr\MethodCall { return new Expr\MethodCall($var, BuilderHelpers::normalizeIdentifierOrExpr($name), $this->args($args)); } /** * Creates a static method call node. * * @param string|Name|Expr $class Class name * @param string|Identifier|Expr $name Method name * @param array $args Method arguments * * @return Expr\StaticCall */ public function staticCall($class, $name, array $args = []) : Expr\StaticCall { return new Expr\StaticCall(BuilderHelpers::normalizeNameOrExpr($class), BuilderHelpers::normalizeIdentifierOrExpr($name), $this->args($args)); } /** * Creates an object creation node. * * @param string|Name|Expr $class Class name * @param array $args Constructor arguments * * @return Expr\New_ */ public function new($class, array $args = []) : Expr\New_ { return new Expr\New_(BuilderHelpers::normalizeNameOrExpr($class), $this->args($args)); } /** * Creates a constant fetch node. * * @param string|Name $name Constant name * * @return Expr\ConstFetch */ public function constFetch($name) : Expr\ConstFetch { return new Expr\ConstFetch(BuilderHelpers::normalizeName($name)); } /** * Creates a property fetch node. * * @param Expr $var Variable holding object * @param string|Identifier|Expr $name Property name * * @return Expr\PropertyFetch */ public function propertyFetch(Expr $var, $name) : Expr\PropertyFetch { return new Expr\PropertyFetch($var, BuilderHelpers::normalizeIdentifierOrExpr($name)); } /** * Creates a class constant fetch node. * * @param string|Name|Expr $class Class name * @param string|Identifier|Expr $name Constant name * * @return Expr\ClassConstFetch */ public function classConstFetch($class, $name) : Expr\ClassConstFetch { return new Expr\ClassConstFetch(BuilderHelpers::normalizeNameOrExpr($class), BuilderHelpers::normalizeIdentifierOrExpr($name)); } /** * Creates nested Concat nodes from a list of expressions. * * @param Expr|string ...$exprs Expressions or literal strings * * @return Concat */ public function concat(...$exprs) : Concat { $numExprs = \count($exprs); if ($numExprs < 2) { throw new \LogicException('Expected at least two expressions'); } $lastConcat = $this->normalizeStringExpr($exprs[0]); for ($i = 1; $i < $numExprs; $i++) { $lastConcat = new Concat($lastConcat, $this->normalizeStringExpr($exprs[$i])); } return $lastConcat; } /** * @param string|Expr $expr * @return Expr */ private function normalizeStringExpr($expr) : Expr { if ($expr instanceof Expr) { return $expr; } if (\is_string($expr)) { return new String_($expr); } throw new \LogicException('Expected string or Expr'); } } attributes = $attributes; } /** * Gets line the node started in (alias of getStartLine). * * @return int Start line (or -1 if not available) */ public function getLine() : int { return $this->attributes['startLine'] ?? -1; } /** * Gets line the node started in. * * Requires the 'startLine' attribute to be enabled in the lexer (enabled by default). * * @return int Start line (or -1 if not available) */ public function getStartLine() : int { return $this->attributes['startLine'] ?? -1; } /** * Gets the line the node ended in. * * Requires the 'endLine' attribute to be enabled in the lexer (enabled by default). * * @return int End line (or -1 if not available) */ public function getEndLine() : int { return $this->attributes['endLine'] ?? -1; } /** * Gets the token offset of the first token that is part of this node. * * The offset is an index into the array returned by Lexer::getTokens(). * * Requires the 'startTokenPos' attribute to be enabled in the lexer (DISABLED by default). * * @return int Token start position (or -1 if not available) */ public function getStartTokenPos() : int { return $this->attributes['startTokenPos'] ?? -1; } /** * Gets the token offset of the last token that is part of this node. * * The offset is an index into the array returned by Lexer::getTokens(). * * Requires the 'endTokenPos' attribute to be enabled in the lexer (DISABLED by default). * * @return int Token end position (or -1 if not available) */ public function getEndTokenPos() : int { return $this->attributes['endTokenPos'] ?? -1; } /** * Gets the file offset of the first character that is part of this node. * * Requires the 'startFilePos' attribute to be enabled in the lexer (DISABLED by default). * * @return int File start position (or -1 if not available) */ public function getStartFilePos() : int { return $this->attributes['startFilePos'] ?? -1; } /** * Gets the file offset of the last character that is part of this node. * * Requires the 'endFilePos' attribute to be enabled in the lexer (DISABLED by default). * * @return int File end position (or -1 if not available) */ public function getEndFilePos() : int { return $this->attributes['endFilePos'] ?? -1; } /** * Gets all comments directly preceding this node. * * The comments are also available through the "comments" attribute. * * @return Comment[] */ public function getComments() : array { return $this->attributes['comments'] ?? []; } /** * Gets the doc comment of the node. * * @return null|Comment\Doc Doc comment object or null */ public function getDocComment() { $comments = $this->getComments(); for ($i = \count($comments) - 1; $i >= 0; $i--) { $comment = $comments[$i]; if ($comment instanceof Comment\Doc) { return $comment; } } return null; } /** * Sets the doc comment of the node. * * This will either replace an existing doc comment or add it to the comments array. * * @param Comment\Doc $docComment Doc comment to set */ public function setDocComment(Comment\Doc $docComment) { $comments = $this->getComments(); for ($i = \count($comments) - 1; $i >= 0; $i--) { if ($comments[$i] instanceof Comment\Doc) { // Replace existing doc comment. $comments[$i] = $docComment; $this->setAttribute('comments', $comments); return; } } // Append new doc comment. $comments[] = $docComment; $this->setAttribute('comments', $comments); } public function setAttribute(string $key, $value) { $this->attributes[$key] = $value; } public function hasAttribute(string $key) : bool { return \array_key_exists($key, $this->attributes); } public function getAttribute(string $key, $default = null) { if (\array_key_exists($key, $this->attributes)) { return $this->attributes[$key]; } return $default; } public function getAttributes() : array { return $this->attributes; } public function setAttributes(array $attributes) { $this->attributes = $attributes; } /** * @return array */ public function jsonSerialize() : array { return ['nodeType' => $this->getType()] + \get_object_vars($this); } } dumpComments = !empty($options['dumpComments']); $this->dumpPositions = !empty($options['dumpPositions']); } /** * Dumps a node or array. * * @param array|Node $node Node or array to dump * @param string|null $code Code corresponding to dumped AST. This only needs to be passed if * the dumpPositions option is enabled and the dumping of node offsets * is desired. * * @return string Dumped value */ public function dump($node, ?string $code = null) : string { $this->code = $code; return $this->dumpRecursive($node); } protected function dumpRecursive($node) { if ($node instanceof Node) { $r = $node->getType(); if ($this->dumpPositions && null !== ($p = $this->dumpPosition($node))) { $r .= $p; } $r .= '('; foreach ($node->getSubNodeNames() as $key) { $r .= "\n " . $key . ': '; $value = $node->{$key}; if (null === $value) { $r .= 'null'; } elseif (\false === $value) { $r .= 'false'; } elseif (\true === $value) { $r .= 'true'; } elseif (\is_scalar($value)) { if ('flags' === $key || 'newModifier' === $key) { $r .= $this->dumpFlags($value); } elseif ('type' === $key && $node instanceof Include_) { $r .= $this->dumpIncludeType($value); } elseif ('type' === $key && ($node instanceof Use_ || $node instanceof UseUse || $node instanceof GroupUse)) { $r .= $this->dumpUseType($value); } else { $r .= $value; } } else { $r .= \str_replace("\n", "\n ", $this->dumpRecursive($value)); } } if ($this->dumpComments && ($comments = $node->getComments())) { $r .= "\n comments: " . \str_replace("\n", "\n ", $this->dumpRecursive($comments)); } } elseif (\is_array($node)) { $r = 'array('; foreach ($node as $key => $value) { $r .= "\n " . $key . ': '; if (null === $value) { $r .= 'null'; } elseif (\false === $value) { $r .= 'false'; } elseif (\true === $value) { $r .= 'true'; } elseif (\is_scalar($value)) { $r .= $value; } else { $r .= \str_replace("\n", "\n ", $this->dumpRecursive($value)); } } } elseif ($node instanceof Comment) { return $node->getReformattedText(); } else { throw new \InvalidArgumentException('Can only dump nodes and arrays.'); } return $r . "\n)"; } protected function dumpFlags($flags) { $strs = []; if ($flags & Class_::MODIFIER_PUBLIC) { $strs[] = 'MODIFIER_PUBLIC'; } if ($flags & Class_::MODIFIER_PROTECTED) { $strs[] = 'MODIFIER_PROTECTED'; } if ($flags & Class_::MODIFIER_PRIVATE) { $strs[] = 'MODIFIER_PRIVATE'; } if ($flags & Class_::MODIFIER_ABSTRACT) { $strs[] = 'MODIFIER_ABSTRACT'; } if ($flags & Class_::MODIFIER_STATIC) { $strs[] = 'MODIFIER_STATIC'; } if ($flags & Class_::MODIFIER_FINAL) { $strs[] = 'MODIFIER_FINAL'; } if ($flags & Class_::MODIFIER_READONLY) { $strs[] = 'MODIFIER_READONLY'; } if ($strs) { return \implode(' | ', $strs) . ' (' . $flags . ')'; } else { return $flags; } } protected function dumpIncludeType($type) { $map = [Include_::TYPE_INCLUDE => 'TYPE_INCLUDE', Include_::TYPE_INCLUDE_ONCE => 'TYPE_INCLUDE_ONCE', Include_::TYPE_REQUIRE => 'TYPE_REQUIRE', Include_::TYPE_REQUIRE_ONCE => 'TYPE_REQUIRE_ONCE']; if (!isset($map[$type])) { return $type; } return $map[$type] . ' (' . $type . ')'; } protected function dumpUseType($type) { $map = [Use_::TYPE_UNKNOWN => 'TYPE_UNKNOWN', Use_::TYPE_NORMAL => 'TYPE_NORMAL', Use_::TYPE_FUNCTION => 'TYPE_FUNCTION', Use_::TYPE_CONSTANT => 'TYPE_CONSTANT']; if (!isset($map[$type])) { return $type; } return $map[$type] . ' (' . $type . ')'; } /** * Dump node position, if possible. * * @param Node $node Node for which to dump position * * @return string|null Dump of position, or null if position information not available */ protected function dumpPosition(Node $node) { if (!$node->hasAttribute('startLine') || !$node->hasAttribute('endLine')) { return null; } $start = $node->getStartLine(); $end = $node->getEndLine(); if ($node->hasAttribute('startFilePos') && $node->hasAttribute('endFilePos') && null !== $this->code) { $start .= ':' . $this->toColumn($this->code, $node->getStartFilePos()); $end .= ':' . $this->toColumn($this->code, $node->getEndFilePos()); } return "[{$start} - {$end}]"; } // Copied from Error class private function toColumn($code, $pos) { if ($pos > \strlen($code)) { throw new \RuntimeException('Invalid position information'); } $lineStartPos = \strrpos($code, "\n", $pos - \strlen($code)); if (\false === $lineStartPos) { $lineStartPos = -1; } return $pos - $lineStartPos; } } addVisitor($visitor); $traverser->traverse($nodes); return $visitor->getFoundNodes(); } /** * Find all nodes that are instances of a certain class. * * @param Node|Node[] $nodes Single node or array of nodes to search in * @param string $class Class name * * @return Node[] Found nodes (all instances of $class) */ public function findInstanceOf($nodes, string $class) : array { return $this->find($nodes, function ($node) use($class) { return $node instanceof $class; }); } /** * Find first node satisfying a filter callback. * * @param Node|Node[] $nodes Single node or array of nodes to search in * @param callable $filter Filter callback: function(Node $node) : bool * * @return null|Node Found node (or null if none found) */ public function findFirst($nodes, callable $filter) { if (!\is_array($nodes)) { $nodes = [$nodes]; } $visitor = new FirstFindingVisitor($filter); $traverser = new NodeTraverser(); $traverser->addVisitor($visitor); $traverser->traverse($nodes); return $visitor->getFoundNode(); } /** * Find first node that is an instance of a certain class. * * @param Node|Node[] $nodes Single node or array of nodes to search in * @param string $class Class name * * @return null|Node Found node, which is an instance of $class (or null if none found) */ public function findFirstInstanceOf($nodes, string $class) { return $this->findFirst($nodes, function ($node) use($class) { return $node instanceof $class; }); } } constants = [new Const_($name, BuilderHelpers::normalizeValue($value))]; } /** * Add another constant to const group * * @param string|Identifier $name Name * @param Node\Expr|bool|null|int|float|string|array $value Value * * @return $this The builder instance (for fluid interface) */ public function addConst($name, $value) { $this->constants[] = new Const_($name, BuilderHelpers::normalizeValue($value)); return $this; } /** * Makes the constant public. * * @return $this The builder instance (for fluid interface) */ public function makePublic() { $this->flags = BuilderHelpers::addModifier($this->flags, Stmt\Class_::MODIFIER_PUBLIC); return $this; } /** * Makes the constant protected. * * @return $this The builder instance (for fluid interface) */ public function makeProtected() { $this->flags = BuilderHelpers::addModifier($this->flags, Stmt\Class_::MODIFIER_PROTECTED); return $this; } /** * Makes the constant private. * * @return $this The builder instance (for fluid interface) */ public function makePrivate() { $this->flags = BuilderHelpers::addModifier($this->flags, Stmt\Class_::MODIFIER_PRIVATE); return $this; } /** * Makes the constant final. * * @return $this The builder instance (for fluid interface) */ public function makeFinal() { $this->flags = BuilderHelpers::addModifier($this->flags, Stmt\Class_::MODIFIER_FINAL); return $this; } /** * Sets doc comment for the constant. * * @param PhpParser\Comment\Doc|string $docComment Doc comment to set * * @return $this The builder instance (for fluid interface) */ public function setDocComment($docComment) { $this->attributes = ['comments' => [BuilderHelpers::normalizeDocComment($docComment)]]; return $this; } /** * Adds an attribute group. * * @param Node\Attribute|Node\AttributeGroup $attribute * * @return $this The builder instance (for fluid interface) */ public function addAttribute($attribute) { $this->attributeGroups[] = BuilderHelpers::normalizeAttribute($attribute); return $this; } /** * Sets the constant type. * * @param string|Node\Name|Identifier|Node\ComplexType $type * * @return $this */ public function setType($type) { $this->type = BuilderHelpers::normalizeType($type); return $this; } /** * Returns the built class node. * * @return Stmt\ClassConst The built constant node */ public function getNode() : PhpParser\Node { return new Stmt\ClassConst($this->constants, $this->flags, $this->attributes, $this->attributeGroups, $this->type); } } name = $name; } /** * Sets default value for the parameter. * * @param mixed $value Default value to use * * @return $this The builder instance (for fluid interface) */ public function setDefault($value) { $this->default = BuilderHelpers::normalizeValue($value); return $this; } /** * Sets type for the parameter. * * @param string|Node\Name|Node\Identifier|Node\ComplexType $type Parameter type * * @return $this The builder instance (for fluid interface) */ public function setType($type) { $this->type = BuilderHelpers::normalizeType($type); if ($this->type == 'void') { throw new \LogicException('Parameter type cannot be void'); } return $this; } /** * Sets type for the parameter. * * @param string|Node\Name|Node\Identifier|Node\ComplexType $type Parameter type * * @return $this The builder instance (for fluid interface) * * @deprecated Use setType() instead */ public function setTypeHint($type) { return $this->setType($type); } /** * Make the parameter accept the value by reference. * * @return $this The builder instance (for fluid interface) */ public function makeByRef() { $this->byRef = \true; return $this; } /** * Make the parameter variadic * * @return $this The builder instance (for fluid interface) */ public function makeVariadic() { $this->variadic = \true; return $this; } /** * Makes the (promoted) parameter public. * * @return $this The builder instance (for fluid interface) */ public function makePublic() { $this->flags = BuilderHelpers::addModifier($this->flags, Node\Stmt\Class_::MODIFIER_PUBLIC); return $this; } /** * Makes the (promoted) parameter protected. * * @return $this The builder instance (for fluid interface) */ public function makeProtected() { $this->flags = BuilderHelpers::addModifier($this->flags, Node\Stmt\Class_::MODIFIER_PROTECTED); return $this; } /** * Makes the (promoted) parameter private. * * @return $this The builder instance (for fluid interface) */ public function makePrivate() { $this->flags = BuilderHelpers::addModifier($this->flags, Node\Stmt\Class_::MODIFIER_PRIVATE); return $this; } /** * Makes the (promoted) parameter readonly. * * @return $this The builder instance (for fluid interface) */ public function makeReadonly() { $this->flags = BuilderHelpers::addModifier($this->flags, Node\Stmt\Class_::MODIFIER_READONLY); return $this; } /** * Adds an attribute group. * * @param Node\Attribute|Node\AttributeGroup $attribute * * @return $this The builder instance (for fluid interface) */ public function addAttribute($attribute) { $this->attributeGroups[] = BuilderHelpers::normalizeAttribute($attribute); return $this; } /** * Returns the built parameter node. * * @return Node\Param The built parameter node */ public function getNode() : Node { return new Node\Param(new Node\Expr\Variable($this->name), $this->default, $this->type, $this->byRef, $this->variadic, [], $this->flags, $this->attributeGroups); } } name = $name; } /** * Adds a statement. * * @param Stmt|PhpParser\Builder $stmt The statement to add * * @return $this The builder instance (for fluid interface) */ public function addStmt($stmt) { $stmt = BuilderHelpers::normalizeNode($stmt); if ($stmt instanceof Stmt\Property) { $this->properties[] = $stmt; } elseif ($stmt instanceof Stmt\ClassMethod) { $this->methods[] = $stmt; } elseif ($stmt instanceof Stmt\TraitUse) { $this->uses[] = $stmt; } else { throw new \LogicException(\sprintf('Unexpected node of type "%s"', $stmt->getType())); } return $this; } /** * Adds an attribute group. * * @param Node\Attribute|Node\AttributeGroup $attribute * * @return $this The builder instance (for fluid interface) */ public function addAttribute($attribute) { $this->attributeGroups[] = BuilderHelpers::normalizeAttribute($attribute); return $this; } /** * Returns the built trait node. * * @return Stmt\Trait_ The built interface node */ public function getNode() : PhpParser\Node { return new Stmt\Trait_($this->name, ['stmts' => \array_merge($this->uses, $this->properties, $this->methods), 'attrGroups' => $this->attributeGroups], $this->attributes); } } returnByRef = \true; return $this; } /** * Adds a parameter. * * @param Node\Param|Param $param The parameter to add * * @return $this The builder instance (for fluid interface) */ public function addParam($param) { $param = BuilderHelpers::normalizeNode($param); if (!$param instanceof Node\Param) { throw new \LogicException(\sprintf('Expected parameter node, got "%s"', $param->getType())); } $this->params[] = $param; return $this; } /** * Adds multiple parameters. * * @param array $params The parameters to add * * @return $this The builder instance (for fluid interface) */ public function addParams(array $params) { foreach ($params as $param) { $this->addParam($param); } return $this; } /** * Sets the return type for PHP 7. * * @param string|Node\Name|Node\Identifier|Node\ComplexType $type * * @return $this The builder instance (for fluid interface) */ public function setReturnType($type) { $this->returnType = BuilderHelpers::normalizeType($type); return $this; } } type = self::TYPE_UNDEFINED; $this->trait = \is_null($trait) ? null : BuilderHelpers::normalizeName($trait); $this->method = BuilderHelpers::normalizeIdentifier($method); } /** * Sets alias of method. * * @param Node\Identifier|string $alias Alias for adaptated method * * @return $this The builder instance (for fluid interface) */ public function as($alias) { if ($this->type === self::TYPE_UNDEFINED) { $this->type = self::TYPE_ALIAS; } if ($this->type !== self::TYPE_ALIAS) { throw new \LogicException('Cannot set alias for not alias adaptation buider'); } $this->alias = $alias; return $this; } /** * Sets adaptated method public. * * @return $this The builder instance (for fluid interface) */ public function makePublic() { $this->setModifier(Stmt\Class_::MODIFIER_PUBLIC); return $this; } /** * Sets adaptated method protected. * * @return $this The builder instance (for fluid interface) */ public function makeProtected() { $this->setModifier(Stmt\Class_::MODIFIER_PROTECTED); return $this; } /** * Sets adaptated method private. * * @return $this The builder instance (for fluid interface) */ public function makePrivate() { $this->setModifier(Stmt\Class_::MODIFIER_PRIVATE); return $this; } /** * Adds overwritten traits. * * @param Node\Name|string ...$traits Traits for overwrite * * @return $this The builder instance (for fluid interface) */ public function insteadof(...$traits) { if ($this->type === self::TYPE_UNDEFINED) { if (\is_null($this->trait)) { throw new \LogicException('Precedence adaptation must have trait'); } $this->type = self::TYPE_PRECEDENCE; } if ($this->type !== self::TYPE_PRECEDENCE) { throw new \LogicException('Cannot add overwritten traits for not precedence adaptation buider'); } foreach ($traits as $trait) { $this->insteadof[] = BuilderHelpers::normalizeName($trait); } return $this; } protected function setModifier(int $modifier) { if ($this->type === self::TYPE_UNDEFINED) { $this->type = self::TYPE_ALIAS; } if ($this->type !== self::TYPE_ALIAS) { throw new \LogicException('Cannot set access modifier for not alias adaptation buider'); } if (\is_null($this->modifier)) { $this->modifier = $modifier; } else { throw new \LogicException('Multiple access type modifiers are not allowed'); } } /** * Returns the built node. * * @return Node The built node */ public function getNode() : Node { switch ($this->type) { case self::TYPE_ALIAS: return new Stmt\TraitUseAdaptation\Alias($this->trait, $this->method, $this->modifier, $this->alias); case self::TYPE_PRECEDENCE: return new Stmt\TraitUseAdaptation\Precedence($this->trait, $this->method, $this->insteadof); default: throw new \LogicException('Type of adaptation is not defined'); } } } name = $name; } /** * Sets the scalar type. * * @param string|Identifier $type * * @return $this */ public function setScalarType($scalarType) { $this->scalarType = BuilderHelpers::normalizeType($scalarType); return $this; } /** * Implements one or more interfaces. * * @param Name|string ...$interfaces Names of interfaces to implement * * @return $this The builder instance (for fluid interface) */ public function implement(...$interfaces) { foreach ($interfaces as $interface) { $this->implements[] = BuilderHelpers::normalizeName($interface); } return $this; } /** * Adds a statement. * * @param Stmt|PhpParser\Builder $stmt The statement to add * * @return $this The builder instance (for fluid interface) */ public function addStmt($stmt) { $stmt = BuilderHelpers::normalizeNode($stmt); $targets = [Stmt\TraitUse::class => &$this->uses, Stmt\EnumCase::class => &$this->enumCases, Stmt\ClassConst::class => &$this->constants, Stmt\ClassMethod::class => &$this->methods]; $class = \get_class($stmt); if (!isset($targets[$class])) { throw new \LogicException(\sprintf('Unexpected node of type "%s"', $stmt->getType())); } $targets[$class][] = $stmt; return $this; } /** * Adds an attribute group. * * @param Node\Attribute|Node\AttributeGroup $attribute * * @return $this The builder instance (for fluid interface) */ public function addAttribute($attribute) { $this->attributeGroups[] = BuilderHelpers::normalizeAttribute($attribute); return $this; } /** * Returns the built class node. * * @return Stmt\Enum_ The built enum node */ public function getNode() : PhpParser\Node { return new Stmt\Enum_($this->name, ['scalarType' => $this->scalarType, 'implements' => $this->implements, 'stmts' => \array_merge($this->uses, $this->enumCases, $this->constants, $this->methods), 'attrGroups' => $this->attributeGroups], $this->attributes); } } name = null !== $name ? BuilderHelpers::normalizeName($name) : null; } /** * Adds a statement. * * @param Node|PhpParser\Builder $stmt The statement to add * * @return $this The builder instance (for fluid interface) */ public function addStmt($stmt) { $this->stmts[] = BuilderHelpers::normalizeStmt($stmt); return $this; } /** * Returns the built node. * * @return Stmt\Namespace_ The built node */ public function getNode() : Node { return new Stmt\Namespace_($this->name, $this->stmts, $this->attributes); } } name = $name; } /** * Extends one or more interfaces. * * @param Name|string ...$interfaces Names of interfaces to extend * * @return $this The builder instance (for fluid interface) */ public function extend(...$interfaces) { foreach ($interfaces as $interface) { $this->extends[] = BuilderHelpers::normalizeName($interface); } return $this; } /** * Adds a statement. * * @param Stmt|PhpParser\Builder $stmt The statement to add * * @return $this The builder instance (for fluid interface) */ public function addStmt($stmt) { $stmt = BuilderHelpers::normalizeNode($stmt); if ($stmt instanceof Stmt\ClassConst) { $this->constants[] = $stmt; } elseif ($stmt instanceof Stmt\ClassMethod) { // we erase all statements in the body of an interface method $stmt->stmts = null; $this->methods[] = $stmt; } else { throw new \LogicException(\sprintf('Unexpected node of type "%s"', $stmt->getType())); } return $this; } /** * Adds an attribute group. * * @param Node\Attribute|Node\AttributeGroup $attribute * * @return $this The builder instance (for fluid interface) */ public function addAttribute($attribute) { $this->attributeGroups[] = BuilderHelpers::normalizeAttribute($attribute); return $this; } /** * Returns the built interface node. * * @return Stmt\Interface_ The built interface node */ public function getNode() : PhpParser\Node { return new Stmt\Interface_($this->name, ['extends' => $this->extends, 'stmts' => \array_merge($this->constants, $this->methods), 'attrGroups' => $this->attributeGroups], $this->attributes); } } name = $name; } /** * Sets the value. * * @param Node\Expr|string|int $value * * @return $this */ public function setValue($value) { $this->value = BuilderHelpers::normalizeValue($value); return $this; } /** * Sets doc comment for the constant. * * @param PhpParser\Comment\Doc|string $docComment Doc comment to set * * @return $this The builder instance (for fluid interface) */ public function setDocComment($docComment) { $this->attributes = ['comments' => [BuilderHelpers::normalizeDocComment($docComment)]]; return $this; } /** * Adds an attribute group. * * @param Node\Attribute|Node\AttributeGroup $attribute * * @return $this The builder instance (for fluid interface) */ public function addAttribute($attribute) { $this->attributeGroups[] = BuilderHelpers::normalizeAttribute($attribute); return $this; } /** * Returns the built enum case node. * * @return Stmt\EnumCase The built constant node */ public function getNode() : PhpParser\Node { return new Stmt\EnumCase($this->name, $this->value, $this->attributeGroups, $this->attributes); } } addStmt($stmt); } return $this; } /** * Sets doc comment for the declaration. * * @param PhpParser\Comment\Doc|string $docComment Doc comment to set * * @return $this The builder instance (for fluid interface) */ public function setDocComment($docComment) { $this->attributes['comments'] = [BuilderHelpers::normalizeDocComment($docComment)]; return $this; } } name = $name; } /** * Makes the method public. * * @return $this The builder instance (for fluid interface) */ public function makePublic() { $this->flags = BuilderHelpers::addModifier($this->flags, Stmt\Class_::MODIFIER_PUBLIC); return $this; } /** * Makes the method protected. * * @return $this The builder instance (for fluid interface) */ public function makeProtected() { $this->flags = BuilderHelpers::addModifier($this->flags, Stmt\Class_::MODIFIER_PROTECTED); return $this; } /** * Makes the method private. * * @return $this The builder instance (for fluid interface) */ public function makePrivate() { $this->flags = BuilderHelpers::addModifier($this->flags, Stmt\Class_::MODIFIER_PRIVATE); return $this; } /** * Makes the method static. * * @return $this The builder instance (for fluid interface) */ public function makeStatic() { $this->flags = BuilderHelpers::addModifier($this->flags, Stmt\Class_::MODIFIER_STATIC); return $this; } /** * Makes the method abstract. * * @return $this The builder instance (for fluid interface) */ public function makeAbstract() { if (!empty($this->stmts)) { throw new \LogicException('Cannot make method with statements abstract'); } $this->flags = BuilderHelpers::addModifier($this->flags, Stmt\Class_::MODIFIER_ABSTRACT); $this->stmts = null; // abstract methods don't have statements return $this; } /** * Makes the method final. * * @return $this The builder instance (for fluid interface) */ public function makeFinal() { $this->flags = BuilderHelpers::addModifier($this->flags, Stmt\Class_::MODIFIER_FINAL); return $this; } /** * Adds a statement. * * @param Node|PhpParser\Builder $stmt The statement to add * * @return $this The builder instance (for fluid interface) */ public function addStmt($stmt) { if (null === $this->stmts) { throw new \LogicException('Cannot add statements to an abstract method'); } $this->stmts[] = BuilderHelpers::normalizeStmt($stmt); return $this; } /** * Adds an attribute group. * * @param Node\Attribute|Node\AttributeGroup $attribute * * @return $this The builder instance (for fluid interface) */ public function addAttribute($attribute) { $this->attributeGroups[] = BuilderHelpers::normalizeAttribute($attribute); return $this; } /** * Returns the built method node. * * @return Stmt\ClassMethod The built method node */ public function getNode() : Node { return new Stmt\ClassMethod($this->name, ['flags' => $this->flags, 'byRef' => $this->returnByRef, 'params' => $this->params, 'returnType' => $this->returnType, 'stmts' => $this->stmts, 'attrGroups' => $this->attributeGroups], $this->attributes); } } name = $name; } /** * Makes the property public. * * @return $this The builder instance (for fluid interface) */ public function makePublic() { $this->flags = BuilderHelpers::addModifier($this->flags, Stmt\Class_::MODIFIER_PUBLIC); return $this; } /** * Makes the property protected. * * @return $this The builder instance (for fluid interface) */ public function makeProtected() { $this->flags = BuilderHelpers::addModifier($this->flags, Stmt\Class_::MODIFIER_PROTECTED); return $this; } /** * Makes the property private. * * @return $this The builder instance (for fluid interface) */ public function makePrivate() { $this->flags = BuilderHelpers::addModifier($this->flags, Stmt\Class_::MODIFIER_PRIVATE); return $this; } /** * Makes the property static. * * @return $this The builder instance (for fluid interface) */ public function makeStatic() { $this->flags = BuilderHelpers::addModifier($this->flags, Stmt\Class_::MODIFIER_STATIC); return $this; } /** * Makes the property readonly. * * @return $this The builder instance (for fluid interface) */ public function makeReadonly() { $this->flags = BuilderHelpers::addModifier($this->flags, Stmt\Class_::MODIFIER_READONLY); return $this; } /** * Sets default value for the property. * * @param mixed $value Default value to use * * @return $this The builder instance (for fluid interface) */ public function setDefault($value) { $this->default = BuilderHelpers::normalizeValue($value); return $this; } /** * Sets doc comment for the property. * * @param PhpParser\Comment\Doc|string $docComment Doc comment to set * * @return $this The builder instance (for fluid interface) */ public function setDocComment($docComment) { $this->attributes = ['comments' => [BuilderHelpers::normalizeDocComment($docComment)]]; return $this; } /** * Sets the property type for PHP 7.4+. * * @param string|Name|Identifier|ComplexType $type * * @return $this */ public function setType($type) { $this->type = BuilderHelpers::normalizeType($type); return $this; } /** * Adds an attribute group. * * @param Node\Attribute|Node\AttributeGroup $attribute * * @return $this The builder instance (for fluid interface) */ public function addAttribute($attribute) { $this->attributeGroups[] = BuilderHelpers::normalizeAttribute($attribute); return $this; } /** * Returns the built class node. * * @return Stmt\Property The built property node */ public function getNode() : PhpParser\Node { return new Stmt\Property($this->flags !== 0 ? $this->flags : Stmt\Class_::MODIFIER_PUBLIC, [new Stmt\PropertyProperty($this->name, $this->default)], $this->attributes, $this->type, $this->attributeGroups); } } name = $name; } /** * Adds a statement. * * @param Node|PhpParser\Builder $stmt The statement to add * * @return $this The builder instance (for fluid interface) */ public function addStmt($stmt) { $this->stmts[] = BuilderHelpers::normalizeStmt($stmt); return $this; } /** * Adds an attribute group. * * @param Node\Attribute|Node\AttributeGroup $attribute * * @return $this The builder instance (for fluid interface) */ public function addAttribute($attribute) { $this->attributeGroups[] = BuilderHelpers::normalizeAttribute($attribute); return $this; } /** * Returns the built function node. * * @return Stmt\Function_ The built function node */ public function getNode() : Node { return new Stmt\Function_($this->name, ['byRef' => $this->returnByRef, 'params' => $this->params, 'returnType' => $this->returnType, 'stmts' => $this->stmts, 'attrGroups' => $this->attributeGroups], $this->attributes); } } name = $name; } /** * Extends a class. * * @param Name|string $class Name of class to extend * * @return $this The builder instance (for fluid interface) */ public function extend($class) { $this->extends = BuilderHelpers::normalizeName($class); return $this; } /** * Implements one or more interfaces. * * @param Name|string ...$interfaces Names of interfaces to implement * * @return $this The builder instance (for fluid interface) */ public function implement(...$interfaces) { foreach ($interfaces as $interface) { $this->implements[] = BuilderHelpers::normalizeName($interface); } return $this; } /** * Makes the class abstract. * * @return $this The builder instance (for fluid interface) */ public function makeAbstract() { $this->flags = BuilderHelpers::addClassModifier($this->flags, Stmt\Class_::MODIFIER_ABSTRACT); return $this; } /** * Makes the class final. * * @return $this The builder instance (for fluid interface) */ public function makeFinal() { $this->flags = BuilderHelpers::addClassModifier($this->flags, Stmt\Class_::MODIFIER_FINAL); return $this; } public function makeReadonly() { $this->flags = BuilderHelpers::addClassModifier($this->flags, Stmt\Class_::MODIFIER_READONLY); return $this; } /** * Adds a statement. * * @param Stmt|PhpParser\Builder $stmt The statement to add * * @return $this The builder instance (for fluid interface) */ public function addStmt($stmt) { $stmt = BuilderHelpers::normalizeNode($stmt); $targets = [Stmt\TraitUse::class => &$this->uses, Stmt\ClassConst::class => &$this->constants, Stmt\Property::class => &$this->properties, Stmt\ClassMethod::class => &$this->methods]; $class = \get_class($stmt); if (!isset($targets[$class])) { throw new \LogicException(\sprintf('Unexpected node of type "%s"', $stmt->getType())); } $targets[$class][] = $stmt; return $this; } /** * Adds an attribute group. * * @param Node\Attribute|Node\AttributeGroup $attribute * * @return $this The builder instance (for fluid interface) */ public function addAttribute($attribute) { $this->attributeGroups[] = BuilderHelpers::normalizeAttribute($attribute); return $this; } /** * Returns the built class node. * * @return Stmt\Class_ The built class node */ public function getNode() : PhpParser\Node { return new Stmt\Class_($this->name, ['flags' => $this->flags, 'extends' => $this->extends, 'implements' => $this->implements, 'stmts' => \array_merge($this->uses, $this->constants, $this->properties, $this->methods), 'attrGroups' => $this->attributeGroups], $this->attributes); } } name = BuilderHelpers::normalizeName($name); $this->type = $type; } /** * Sets alias for used name. * * @param string $alias Alias to use (last component of full name by default) * * @return $this The builder instance (for fluid interface) */ public function as(string $alias) { $this->alias = $alias; return $this; } /** * Returns the built node. * * @return Stmt\Use_ The built node */ public function getNode() : Node { return new Stmt\Use_([new Stmt\UseUse($this->name, $this->alias)], $this->type); } } and($trait); } } /** * Adds used trait. * * @param Node\Name|string $trait Trait name * * @return $this The builder instance (for fluid interface) */ public function and($trait) { $this->traits[] = BuilderHelpers::normalizeName($trait); return $this; } /** * Adds trait adaptation. * * @param Stmt\TraitUseAdaptation|Builder\TraitUseAdaptation $adaptation Trait adaptation * * @return $this The builder instance (for fluid interface) */ public function with($adaptation) { $adaptation = BuilderHelpers::normalizeNode($adaptation); if (!$adaptation instanceof Stmt\TraitUseAdaptation) { throw new \LogicException('Adaptation must have type TraitUseAdaptation'); } $this->adaptations[] = $adaptation; return $this; } /** * Returns the built node. * * @return Node The built node */ public function getNode() : Node { return new Stmt\TraitUse($this->traits, $this->adaptations); } } attributes = $attributes; $this->attrs = $attrs; } public function getSubNodeNames() : array { return ['attrs']; } public function getType() : string { return 'AttributeGroup'; } } attributes = $attributes; $this->type = \is_string($type) ? new Identifier($type) : $type; } public function getSubNodeNames() : array { return ['type']; } public function getType() : string { return 'NullableType'; } } attributes = $attributes; $this->type = \is_string($type) ? new Identifier($type) : $type; $this->byRef = $byRef; $this->variadic = $variadic; $this->var = $var; $this->default = $default; $this->flags = $flags; $this->attrGroups = $attrGroups; } public function getSubNodeNames() : array { return ['attrGroups', 'flags', 'type', 'byRef', 'variadic', 'var', 'default']; } public function getType() : string { return 'Param'; } } '; } public function getType() : string { return 'Expr_BinaryOp_Greater'; } } '; } public function getType() : string { return 'Expr_BinaryOp_Spaceship'; } } ='; } public function getType() : string { return 'Expr_BinaryOp_GreaterOrEqual'; } } >'; } public function getType() : string { return 'Expr_BinaryOp_ShiftRight'; } } attributes = $attributes; $this->var = $var; $this->byRef = $byRef; } public function getSubNodeNames() : array { return ['var', 'byRef']; } public function getType() : string { return 'Expr_ClosureUse'; } } attributes = $attributes; $this->var = $var; $this->expr = $expr; } public function getSubNodeNames() : array { return ['var', 'expr']; } public function getType() : string { return 'Expr_AssignRef'; } } attributes = $attributes; $this->expr = $expr; } public function getSubNodeNames() : array { return ['expr']; } public function getType() : string { return 'Expr_YieldFrom'; } } attributes = $attributes; $this->var = $var; $this->name = \is_string($name) ? new Identifier($name) : $name; } public function getSubNodeNames() : array { return ['var', 'name']; } public function getType() : string { return 'Expr_NullsafePropertyFetch'; } } Arguments */ public $args; /** * Constructs a function call node. * * @param Node\Name|Expr|Node\Stmt\Class_ $class Class name (or class node for anonymous classes) * @param array $args Arguments * @param array $attributes Additional attributes */ public function __construct($class, array $args = [], array $attributes = []) { $this->attributes = $attributes; $this->class = $class; $this->args = $args; } public function getSubNodeNames() : array { return ['class', 'args']; } public function getType() : string { return 'Expr_New'; } public function getRawArgs() : array { return $this->args; } } false : Whether the closure is static * 'byRef' => false : Whether to return by reference * 'params' => array() : Parameters * 'returnType' => null : Return type * 'expr' => Expr : Expression body * 'attrGroups' => array() : PHP attribute groups * @param array $attributes Additional attributes */ public function __construct(array $subNodes = [], array $attributes = []) { $this->attributes = $attributes; $this->static = $subNodes['static'] ?? \false; $this->byRef = $subNodes['byRef'] ?? \false; $this->params = $subNodes['params'] ?? []; $returnType = $subNodes['returnType'] ?? null; $this->returnType = \is_string($returnType) ? new Node\Identifier($returnType) : $returnType; $this->expr = $subNodes['expr']; $this->attrGroups = $subNodes['attrGroups'] ?? []; } public function getSubNodeNames() : array { return ['attrGroups', 'static', 'byRef', 'params', 'returnType', 'expr']; } public function returnsByRef() : bool { return $this->byRef; } public function getParams() : array { return $this->params; } public function getReturnType() { return $this->returnType; } public function getAttrGroups() : array { return $this->attrGroups; } /** * @return Node\Stmt\Return_[] */ public function getStmts() : array { return [new Node\Stmt\Return_($this->expr)]; } public function getType() : string { return 'Expr_ArrowFunction'; } } attributes = $attributes; $this->key = $key; $this->value = $value; } public function getSubNodeNames() : array { return ['key', 'value']; } public function getType() : string { return 'Expr_Yield'; } } attributes = $attributes; $this->var = $var; $this->expr = $expr; } public function getSubNodeNames() : array { return ['var', 'expr']; } } attributes = $attributes; $this->vars = $vars; } public function getSubNodeNames() : array { return ['vars']; } public function getType() : string { return 'Expr_Isset'; } } attributes = $attributes; $this->expr = $expr; } public function getSubNodeNames() : array { return ['expr']; } public function getType() : string { return 'Expr_Clone'; } } attributes = $attributes; $this->var = $var; } public function getSubNodeNames() : array { return ['var']; } public function getType() : string { return 'Expr_PreInc'; } } attributes = $attributes; $this->var = $var; } public function getSubNodeNames() : array { return ['var']; } public function getType() : string { return 'Expr_PostDec'; } } attributes = $attributes; $this->expr = $expr; } public function getSubNodeNames() : array { return ['expr']; } public function getType() : string { return 'Expr_ErrorSuppress'; } } attributes = $attributes; $this->class = $class; $this->name = \is_string($name) ? new Identifier($name) : $name; } public function getSubNodeNames() : array { return ['class', 'name']; } public function getType() : string { return 'Expr_ClassConstFetch'; } } attributes = $attributes; $this->expr = $expr; $this->class = $class; } public function getSubNodeNames() : array { return ['expr', 'class']; } public function getType() : string { return 'Expr_Instanceof'; } } attributes = $attributes; $this->parts = $parts; } public function getSubNodeNames() : array { return ['parts']; } public function getType() : string { return 'Expr_ShellExec'; } } Arguments */ public $args; /** * Constructs a nullsafe method call node. * * @param Expr $var Variable holding object * @param string|Identifier|Expr $name Method name * @param array $args Arguments * @param array $attributes Additional attributes */ public function __construct(Expr $var, $name, array $args = [], array $attributes = []) { $this->attributes = $attributes; $this->var = $var; $this->name = \is_string($name) ? new Identifier($name) : $name; $this->args = $args; } public function getSubNodeNames() : array { return ['var', 'name', 'args']; } public function getType() : string { return 'Expr_NullsafeMethodCall'; } public function getRawArgs() : array { return $this->args; } } attributes = $attributes; $this->var = $var; $this->name = \is_string($name) ? new Identifier($name) : $name; } public function getSubNodeNames() : array { return ['var', 'name']; } public function getType() : string { return 'Expr_PropertyFetch'; } } attributes = $attributes; $this->left = $left; $this->right = $right; } public function getSubNodeNames() : array { return ['left', 'right']; } /** * Get the operator sigil for this binary operation. * * In the case there are multiple possible sigils for an operator, this method does not * necessarily return the one used in the parsed code. * * @return string */ public abstract function getOperatorSigil() : string; } attributes = $attributes; $this->expr = $expr; } public function getSubNodeNames() : array { return ['expr']; } public function getType() : string { return 'Expr_Eval'; } } Arguments */ public $args; /** * Constructs a static method call node. * * @param Node\Name|Expr $class Class name * @param string|Identifier|Expr $name Method name * @param array $args Arguments * @param array $attributes Additional attributes */ public function __construct($class, $name, array $args = [], array $attributes = []) { $this->attributes = $attributes; $this->class = $class; $this->name = \is_string($name) ? new Identifier($name) : $name; $this->args = $args; } public function getSubNodeNames() : array { return ['class', 'name', 'args']; } public function getType() : string { return 'Expr_StaticCall'; } public function getRawArgs() : array { return $this->args; } } attributes = $attributes; $this->items = $items; } public function getSubNodeNames() : array { return ['items']; } public function getType() : string { return 'Expr_List'; } } false : Whether the closure is static * 'byRef' => false : Whether to return by reference * 'params' => array(): Parameters * 'uses' => array(): use()s * 'returnType' => null : Return type * 'stmts' => array(): Statements * 'attrGroups' => array(): PHP attributes groups * @param array $attributes Additional attributes */ public function __construct(array $subNodes = [], array $attributes = []) { $this->attributes = $attributes; $this->static = $subNodes['static'] ?? \false; $this->byRef = $subNodes['byRef'] ?? \false; $this->params = $subNodes['params'] ?? []; $this->uses = $subNodes['uses'] ?? []; $returnType = $subNodes['returnType'] ?? null; $this->returnType = \is_string($returnType) ? new Node\Identifier($returnType) : $returnType; $this->stmts = $subNodes['stmts'] ?? []; $this->attrGroups = $subNodes['attrGroups'] ?? []; } public function getSubNodeNames() : array { return ['attrGroups', 'static', 'byRef', 'params', 'uses', 'returnType', 'stmts']; } public function returnsByRef() : bool { return $this->byRef; } public function getParams() : array { return $this->params; } public function getReturnType() { return $this->returnType; } /** @return Node\Stmt[] */ public function getStmts() : array { return $this->stmts; } public function getAttrGroups() : array { return $this->attrGroups; } public function getType() : string { return 'Expr_Closure'; } } attributes = $attributes; $this->cond = $cond; $this->arms = $arms; } public function getSubNodeNames() : array { return ['cond', 'arms']; } public function getType() : string { return 'Expr_Match'; } } Arguments */ public $args; /** * Constructs a function call node. * * @param Node\Name|Expr $name Function name * @param array $args Arguments * @param array $attributes Additional attributes */ public function __construct($name, array $args = [], array $attributes = []) { $this->attributes = $attributes; $this->name = $name; $this->args = $args; } public function getSubNodeNames() : array { return ['name', 'args']; } public function getType() : string { return 'Expr_FuncCall'; } public function getRawArgs() : array { return $this->args; } } attributes = $attributes; $this->class = $class; $this->name = \is_string($name) ? new VarLikeIdentifier($name) : $name; } public function getSubNodeNames() : array { return ['class', 'name']; } public function getType() : string { return 'Expr_StaticPropertyFetch'; } } attributes = $attributes; $this->expr = $expr; $this->type = $type; } public function getSubNodeNames() : array { return ['expr', 'type']; } public function getType() : string { return 'Expr_Include'; } } attributes = $attributes; $this->items = $items; } public function getSubNodeNames() : array { return ['items']; } public function getType() : string { return 'Expr_Array'; } } attributes = $attributes; $this->expr = $expr; } public function getSubNodeNames() : array { return ['expr']; } public function getType() : string { return 'Expr_BooleanNot'; } } attributes = $attributes; $this->expr = $expr; } public function getSubNodeNames() : array { return ['expr']; } public function getType() : string { return 'Expr_Print'; } } attributes = $attributes; $this->expr = $expr; } public function getSubNodeNames() : array { return ['expr']; } public function getType() : string { return 'Expr_BitwiseNot'; } } attributes = $attributes; $this->var = $var; $this->dim = $dim; } public function getSubNodeNames() : array { return ['var', 'dim']; } public function getType() : string { return 'Expr_ArrayDimFetch'; } } attributes = $attributes; } public function getSubNodeNames() : array { return []; } public function getType() : string { return 'Expr_Error'; } } Arguments */ public $args; /** * Constructs a function call node. * * @param Expr $var Variable holding object * @param string|Identifier|Expr $name Method name * @param array $args Arguments * @param array $attributes Additional attributes */ public function __construct(Expr $var, $name, array $args = [], array $attributes = []) { $this->attributes = $attributes; $this->var = $var; $this->name = \is_string($name) ? new Identifier($name) : $name; $this->args = $args; } public function getSubNodeNames() : array { return ['var', 'name', 'args']; } public function getType() : string { return 'Expr_MethodCall'; } public function getRawArgs() : array { return $this->args; } } attributes = $attributes; $this->expr = $expr; } public function getSubNodeNames() : array { return ['expr']; } public function getType() : string { return 'Expr_Empty'; } } attributes = $attributes; $this->var = $var; } public function getSubNodeNames() : array { return ['var']; } public function getType() : string { return 'Expr_PreDec'; } } attributes = $attributes; $this->expr = $expr; } public function getSubNodeNames() : array { return ['expr']; } public function getType() : string { return 'Expr_UnaryPlus'; } } attributes = $attributes; $this->expr = $expr; } public function getSubNodeNames() : array { return ['expr']; } } attributes = $attributes; $this->expr = $expr; } public function getSubNodeNames() : array { return ['expr']; } public function getType() : string { return 'Expr_Exit'; } } attributes = $attributes; $this->var = $var; } public function getSubNodeNames() : array { return ['var']; } public function getType() : string { return 'Expr_PostInc'; } } attributes = $attributes; $this->cond = $cond; $this->if = $if; $this->else = $else; } public function getSubNodeNames() : array { return ['cond', 'if', 'else']; } public function getType() : string { return 'Expr_Ternary'; } } attributes = $attributes; $this->name = $name; } public function getSubNodeNames() : array { return ['name']; } public function getType() : string { return 'Expr_ConstFetch'; } } attributes = $attributes; $this->expr = $expr; } public function getSubNodeNames() : array { return ['expr']; } public function getType() : string { return 'Expr_Throw'; } } attributes = $attributes; $this->var = $var; $this->expr = $expr; } public function getSubNodeNames() : array { return ['var', 'expr']; } public function getType() : string { return 'Expr_Assign'; } } */ public abstract function getRawArgs() : array; /** * Returns whether this call expression is actually a first class callable. */ public function isFirstClassCallable() : bool { foreach ($this->getRawArgs() as $arg) { if ($arg instanceof VariadicPlaceholder) { return \true; } } return \false; } /** * Assert that this is not a first-class callable and return only ordinary Args. * * @return Arg[] */ public function getArgs() : array { \assert(!$this->isFirstClassCallable()); return $this->getRawArgs(); } } attributes = $attributes; $this->key = $key; $this->value = $value; $this->byRef = $byRef; $this->unpack = $unpack; } public function getSubNodeNames() : array { return ['key', 'value', 'byRef', 'unpack']; } public function getType() : string { return 'Expr_ArrayItem'; } } attributes = $attributes; $this->name = $name; } public function getSubNodeNames() : array { return ['name']; } public function getType() : string { return 'Expr_Variable'; } } attributes = $attributes; $this->expr = $expr; } public function getSubNodeNames() : array { return ['expr']; } public function getType() : string { return 'Expr_UnaryMinus'; } } attributes = $attributes; $this->name = $name; $this->args = $args; } public function getSubNodeNames() : array { return ['name', 'args']; } public function getType() : string { return 'Attribute'; } } attributes = $attributes; $this->types = $types; } public function getSubNodeNames() : array { return ['types']; } public function getType() : string { return 'IntersectionType'; } } attributes = $attributes; $this->vars = $vars; } public function getSubNodeNames() : array { return ['vars']; } public function getType() : string { return 'Stmt_Static'; } } attributes = $attributes; $this->cond = $cond; $this->cases = $cases; } public function getSubNodeNames() : array { return ['cond', 'cases']; } public function getType() : string { return 'Stmt_Switch'; } } stmts as $stmt) { if ($stmt instanceof TraitUse) { $traitUses[] = $stmt; } } return $traitUses; } /** * @return ClassConst[] */ public function getConstants() : array { $constants = []; foreach ($this->stmts as $stmt) { if ($stmt instanceof ClassConst) { $constants[] = $stmt; } } return $constants; } /** * @return Property[] */ public function getProperties() : array { $properties = []; foreach ($this->stmts as $stmt) { if ($stmt instanceof Property) { $properties[] = $stmt; } } return $properties; } /** * Gets property with the given name defined directly in this class/interface/trait. * * @param string $name Name of the property * * @return Property|null Property node or null if the property does not exist */ public function getProperty(string $name) { foreach ($this->stmts as $stmt) { if ($stmt instanceof Property) { foreach ($stmt->props as $prop) { if ($prop instanceof PropertyProperty && $name === $prop->name->toString()) { return $stmt; } } } } return null; } /** * Gets all methods defined directly in this class/interface/trait * * @return ClassMethod[] */ public function getMethods() : array { $methods = []; foreach ($this->stmts as $stmt) { if ($stmt instanceof ClassMethod) { $methods[] = $stmt; } } return $methods; } /** * Gets method with the given name defined directly in this class/interface/trait. * * @param string $name Name of the method (compared case-insensitively) * * @return ClassMethod|null Method node or null if the method does not exist */ public function getMethod(string $name) { $lowerName = \strtolower($name); foreach ($this->stmts as $stmt) { if ($stmt instanceof ClassMethod && $lowerName === $stmt->name->toLowerString()) { return $stmt; } } return null; } } attributes = $attributes; $this->vars = $vars; } public function getSubNodeNames() : array { return ['vars']; } public function getType() : string { return 'Stmt_Unset'; } } attributes = $attributes; $this->expr = $expr; } public function getSubNodeNames() : array { return ['expr']; } public function getType() : string { return 'Stmt_Expression'; } } attributes = $attributes; $this->types = $types; $this->var = $var; $this->stmts = $stmts; } public function getSubNodeNames() : array { return ['types', 'var', 'stmts']; } public function getType() : string { return 'Stmt_Catch'; } } attributes = $attributes; $this->flags = $flags; $this->consts = $consts; $this->attrGroups = $attrGroups; $this->type = \is_string($type) ? new Node\Identifier($type) : $type; } public function getSubNodeNames() : array { return ['attrGroups', 'flags', 'type', 'consts']; } /** * Whether constant is explicitly or implicitly public. * * @return bool */ public function isPublic() : bool { return ($this->flags & Class_::MODIFIER_PUBLIC) !== 0 || ($this->flags & Class_::VISIBILITY_MODIFIER_MASK) === 0; } /** * Whether constant is protected. * * @return bool */ public function isProtected() : bool { return (bool) ($this->flags & Class_::MODIFIER_PROTECTED); } /** * Whether constant is private. * * @return bool */ public function isPrivate() : bool { return (bool) ($this->flags & Class_::MODIFIER_PRIVATE); } /** * Whether constant is final. * * @return bool */ public function isFinal() : bool { return (bool) ($this->flags & Class_::MODIFIER_FINAL); } public function getType() : string { return 'Stmt_ClassConst'; } } array(): Init expressions * 'cond' => array(): Loop conditions * 'loop' => array(): Loop expressions * 'stmts' => array(): Statements * @param array $attributes Additional attributes */ public function __construct(array $subNodes = [], array $attributes = []) { $this->attributes = $attributes; $this->init = $subNodes['init'] ?? []; $this->cond = $subNodes['cond'] ?? []; $this->loop = $subNodes['loop'] ?? []; $this->stmts = $subNodes['stmts'] ?? []; } public function getSubNodeNames() : array { return ['init', 'cond', 'loop', 'stmts']; } public function getType() : string { return 'Stmt_For'; } } attributes = $attributes; $this->trait = $trait; $this->method = \is_string($method) ? new Node\Identifier($method) : $method; $this->newModifier = $newModifier; $this->newName = \is_string($newName) ? new Node\Identifier($newName) : $newName; } public function getSubNodeNames() : array { return ['trait', 'method', 'newModifier', 'newName']; } public function getType() : string { return 'Stmt_TraitUseAdaptation_Alias'; } } attributes = $attributes; $this->trait = $trait; $this->method = \is_string($method) ? new Node\Identifier($method) : $method; $this->insteadof = $insteadof; } public function getSubNodeNames() : array { return ['trait', 'method', 'insteadof']; } public function getType() : string { return 'Stmt_TraitUseAdaptation_Precedence'; } } array(): Statements * 'attrGroups' => array(): PHP attribute groups * @param array $attributes Additional attributes */ public function __construct($name, array $subNodes = [], array $attributes = []) { $this->attributes = $attributes; $this->name = \is_string($name) ? new Node\Identifier($name) : $name; $this->stmts = $subNodes['stmts'] ?? []; $this->attrGroups = $subNodes['attrGroups'] ?? []; } public function getSubNodeNames() : array { return ['attrGroups', 'name', 'stmts']; } public function getType() : string { return 'Stmt_Trait'; } } attributes = $attributes; $this->cond = $cond; $this->stmts = $stmts; } public function getSubNodeNames() : array { return ['cond', 'stmts']; } public function getType() : string { return 'Stmt_Case'; } } value pair node. * * @param string|Node\Identifier $key Key * @param Node\Expr $value Value * @param array $attributes Additional attributes */ public function __construct($key, Node\Expr $value, array $attributes = []) { $this->attributes = $attributes; $this->key = \is_string($key) ? new Node\Identifier($key) : $key; $this->value = $value; } public function getSubNodeNames() : array { return ['key', 'value']; } public function getType() : string { return 'Stmt_DeclareDeclare'; } } attributes = $attributes; $this->value = $value; } public function getSubNodeNames() : array { return ['value']; } public function getType() : string { return 'Stmt_InlineHTML'; } } attributes = $attributes; $this->expr = $expr; } public function getSubNodeNames() : array { return ['expr']; } public function getType() : string { return 'Stmt_Return'; } } attributes = $attributes; $this->name = \is_string($name) ? new Node\VarLikeIdentifier($name) : $name; $this->default = $default; } public function getSubNodeNames() : array { return ['name', 'default']; } public function getType() : string { return 'Stmt_PropertyProperty'; } } attributes = $attributes; $this->type = $type; $this->name = $name; $this->alias = \is_string($alias) ? new Identifier($alias) : $alias; } public function getSubNodeNames() : array { return ['type', 'name', 'alias']; } /** * Get alias. If not explicitly given this is the last component of the used name. * * @return Identifier */ public function getAlias() : Identifier { if (null !== $this->alias) { return $this->alias; } return new Identifier($this->name->getLast()); } public function getType() : string { return 'Stmt_UseUse'; } } attributes = $attributes; $this->vars = $vars; } public function getSubNodeNames() : array { return ['vars']; } public function getType() : string { return 'Stmt_Global'; } } attributes = $attributes; $this->consts = $consts; } public function getSubNodeNames() : array { return ['consts']; } public function getType() : string { return 'Stmt_Const'; } } null : Scalar type * 'implements' => array() : Names of implemented interfaces * 'stmts' => array() : Statements * 'attrGroups' => array() : PHP attribute groups * @param array $attributes Additional attributes */ public function __construct($name, array $subNodes = [], array $attributes = []) { $this->name = \is_string($name) ? new Node\Identifier($name) : $name; $this->scalarType = $subNodes['scalarType'] ?? null; $this->implements = $subNodes['implements'] ?? []; $this->stmts = $subNodes['stmts'] ?? []; $this->attrGroups = $subNodes['attrGroups'] ?? []; parent::__construct($attributes); } public function getSubNodeNames() : array { return ['attrGroups', 'name', 'scalarType', 'implements', 'stmts']; } public function getType() : string { return 'Stmt_Enum'; } } attributes = $attributes; $this->stmts = $stmts; $this->catches = $catches; $this->finally = $finally; } public function getSubNodeNames() : array { return ['stmts', 'catches', 'finally']; } public function getType() : string { return 'Stmt_TryCatch'; } } attributes = $attributes; $this->num = $num; } public function getSubNodeNames() : array { return ['num']; } public function getType() : string { return 'Stmt_Break'; } } attributes = $attributes; $this->declares = $declares; $this->stmts = $stmts; } public function getSubNodeNames() : array { return ['declares', 'stmts']; } public function getType() : string { return 'Stmt_Declare'; } } attributes = $attributes; $this->name = $name; $this->stmts = $stmts; } public function getSubNodeNames() : array { return ['name', 'stmts']; } public function getType() : string { return 'Stmt_Namespace'; } } array(): Name of extended interfaces * 'stmts' => array(): Statements * 'attrGroups' => array(): PHP attribute groups * @param array $attributes Additional attributes */ public function __construct($name, array $subNodes = [], array $attributes = []) { $this->attributes = $attributes; $this->name = \is_string($name) ? new Node\Identifier($name) : $name; $this->extends = $subNodes['extends'] ?? []; $this->stmts = $subNodes['stmts'] ?? []; $this->attrGroups = $subNodes['attrGroups'] ?? []; } public function getSubNodeNames() : array { return ['attrGroups', 'name', 'extends', 'stmts']; } public function getType() : string { return 'Stmt_Interface'; } } \true, '__destruct' => \true, '__call' => \true, '__callstatic' => \true, '__get' => \true, '__set' => \true, '__isset' => \true, '__unset' => \true, '__sleep' => \true, '__wakeup' => \true, '__tostring' => \true, '__set_state' => \true, '__clone' => \true, '__invoke' => \true, '__debuginfo' => \true, '__serialize' => \true, '__unserialize' => \true]; /** * Constructs a class method node. * * @param string|Node\Identifier $name Name * @param array $subNodes Array of the following optional subnodes: * 'flags => MODIFIER_PUBLIC: Flags * 'byRef' => false : Whether to return by reference * 'params' => array() : Parameters * 'returnType' => null : Return type * 'stmts' => array() : Statements * 'attrGroups' => array() : PHP attribute groups * @param array $attributes Additional attributes */ public function __construct($name, array $subNodes = [], array $attributes = []) { $this->attributes = $attributes; $this->flags = $subNodes['flags'] ?? $subNodes['type'] ?? 0; $this->byRef = $subNodes['byRef'] ?? \false; $this->name = \is_string($name) ? new Node\Identifier($name) : $name; $this->params = $subNodes['params'] ?? []; $returnType = $subNodes['returnType'] ?? null; $this->returnType = \is_string($returnType) ? new Node\Identifier($returnType) : $returnType; $this->stmts = \array_key_exists('stmts', $subNodes) ? $subNodes['stmts'] : []; $this->attrGroups = $subNodes['attrGroups'] ?? []; } public function getSubNodeNames() : array { return ['attrGroups', 'flags', 'byRef', 'name', 'params', 'returnType', 'stmts']; } public function returnsByRef() : bool { return $this->byRef; } public function getParams() : array { return $this->params; } public function getReturnType() { return $this->returnType; } public function getStmts() { return $this->stmts; } public function getAttrGroups() : array { return $this->attrGroups; } /** * Whether the method is explicitly or implicitly public. * * @return bool */ public function isPublic() : bool { return ($this->flags & Class_::MODIFIER_PUBLIC) !== 0 || ($this->flags & Class_::VISIBILITY_MODIFIER_MASK) === 0; } /** * Whether the method is protected. * * @return bool */ public function isProtected() : bool { return (bool) ($this->flags & Class_::MODIFIER_PROTECTED); } /** * Whether the method is private. * * @return bool */ public function isPrivate() : bool { return (bool) ($this->flags & Class_::MODIFIER_PRIVATE); } /** * Whether the method is abstract. * * @return bool */ public function isAbstract() : bool { return (bool) ($this->flags & Class_::MODIFIER_ABSTRACT); } /** * Whether the method is final. * * @return bool */ public function isFinal() : bool { return (bool) ($this->flags & Class_::MODIFIER_FINAL); } /** * Whether the method is static. * * @return bool */ public function isStatic() : bool { return (bool) ($this->flags & Class_::MODIFIER_STATIC); } /** * Whether the method is magic. * * @return bool */ public function isMagic() : bool { return isset(self::$magicNames[$this->name->toLowerString()]); } public function getType() : string { return 'Stmt_ClassMethod'; } } attributes = $attributes; $this->num = $num; } public function getSubNodeNames() : array { return ['num']; } public function getType() : string { return 'Stmt_Continue'; } } name = \is_string($name) ? new Node\Identifier($name) : $name; $this->expr = $expr; $this->attrGroups = $attrGroups; } public function getSubNodeNames() : array { return ['attrGroups', 'name', 'expr']; } public function getType() : string { return 'Stmt_EnumCase'; } } attributes = $attributes; $this->name = \is_string($name) ? new Identifier($name) : $name; } public function getSubNodeNames() : array { return ['name']; } public function getType() : string { return 'Stmt_Goto'; } } attributes = $attributes; $this->cond = $cond; $this->stmts = $stmts; } public function getSubNodeNames() : array { return ['cond', 'stmts']; } public function getType() : string { return 'Stmt_ElseIf'; } } attributes = $attributes; $this->stmts = $stmts; } public function getSubNodeNames() : array { return ['stmts']; } public function getType() : string { return 'Stmt_Else'; } } attributes = $attributes; $this->type = $type; $this->prefix = $prefix; $this->uses = $uses; } public function getSubNodeNames() : array { return ['type', 'prefix', 'uses']; } public function getType() : string { return 'Stmt_GroupUse'; } } attributes = $attributes; $this->flags = $flags; $this->props = $props; $this->type = \is_string($type) ? new Identifier($type) : $type; $this->attrGroups = $attrGroups; } public function getSubNodeNames() : array { return ['attrGroups', 'flags', 'type', 'props']; } /** * Whether the property is explicitly or implicitly public. * * @return bool */ public function isPublic() : bool { return ($this->flags & Class_::MODIFIER_PUBLIC) !== 0 || ($this->flags & Class_::VISIBILITY_MODIFIER_MASK) === 0; } /** * Whether the property is protected. * * @return bool */ public function isProtected() : bool { return (bool) ($this->flags & Class_::MODIFIER_PROTECTED); } /** * Whether the property is private. * * @return bool */ public function isPrivate() : bool { return (bool) ($this->flags & Class_::MODIFIER_PRIVATE); } /** * Whether the property is static. * * @return bool */ public function isStatic() : bool { return (bool) ($this->flags & Class_::MODIFIER_STATIC); } /** * Whether the property is readonly. * * @return bool */ public function isReadonly() : bool { return (bool) ($this->flags & Class_::MODIFIER_READONLY); } public function getType() : string { return 'Stmt_Property'; } } attributes = $attributes; $this->remaining = $remaining; } public function getSubNodeNames() : array { return ['remaining']; } public function getType() : string { return 'Stmt_HaltCompiler'; } } false : Whether to return by reference * 'params' => array(): Parameters * 'returnType' => null : Return type * 'stmts' => array(): Statements * 'attrGroups' => array(): PHP attribute groups * @param array $attributes Additional attributes */ public function __construct($name, array $subNodes = [], array $attributes = []) { $this->attributes = $attributes; $this->byRef = $subNodes['byRef'] ?? \false; $this->name = \is_string($name) ? new Node\Identifier($name) : $name; $this->params = $subNodes['params'] ?? []; $returnType = $subNodes['returnType'] ?? null; $this->returnType = \is_string($returnType) ? new Node\Identifier($returnType) : $returnType; $this->stmts = $subNodes['stmts'] ?? []; $this->attrGroups = $subNodes['attrGroups'] ?? []; } public function getSubNodeNames() : array { return ['attrGroups', 'byRef', 'name', 'params', 'returnType', 'stmts']; } public function returnsByRef() : bool { return $this->byRef; } public function getParams() : array { return $this->params; } public function getReturnType() { return $this->returnType; } public function getAttrGroups() : array { return $this->attrGroups; } /** @return Node\Stmt[] */ public function getStmts() : array { return $this->stmts; } public function getType() : string { return 'Stmt_Function'; } } attributes = $attributes; $this->cond = $cond; $this->stmts = $stmts; } public function getSubNodeNames() : array { return ['stmts', 'cond']; } public function getType() : string { return 'Stmt_Do'; } } attributes = $attributes; $this->var = $var; $this->default = $default; } public function getSubNodeNames() : array { return ['var', 'default']; } public function getType() : string { return 'Stmt_StaticVar'; } } attributes = $attributes; $this->stmts = $stmts; } public function getSubNodeNames() : array { return ['stmts']; } public function getType() : string { return 'Stmt_Finally'; } } 0 : Flags * 'extends' => null : Name of extended class * 'implements' => array(): Names of implemented interfaces * 'stmts' => array(): Statements * 'attrGroups' => array(): PHP attribute groups * @param array $attributes Additional attributes */ public function __construct($name, array $subNodes = [], array $attributes = []) { $this->attributes = $attributes; $this->flags = $subNodes['flags'] ?? $subNodes['type'] ?? 0; $this->name = \is_string($name) ? new Node\Identifier($name) : $name; $this->extends = $subNodes['extends'] ?? null; $this->implements = $subNodes['implements'] ?? []; $this->stmts = $subNodes['stmts'] ?? []; $this->attrGroups = $subNodes['attrGroups'] ?? []; } public function getSubNodeNames() : array { return ['attrGroups', 'flags', 'name', 'extends', 'implements', 'stmts']; } /** * Whether the class is explicitly abstract. * * @return bool */ public function isAbstract() : bool { return (bool) ($this->flags & self::MODIFIER_ABSTRACT); } /** * Whether the class is final. * * @return bool */ public function isFinal() : bool { return (bool) ($this->flags & self::MODIFIER_FINAL); } public function isReadonly() : bool { return (bool) ($this->flags & self::MODIFIER_READONLY); } /** * Whether the class is anonymous. * * @return bool */ public function isAnonymous() : bool { return null === $this->name; } /** * @internal */ public static function verifyClassModifier($a, $b) { if ($a & self::MODIFIER_ABSTRACT && $b & self::MODIFIER_ABSTRACT) { throw new Error('Multiple abstract modifiers are not allowed'); } if ($a & self::MODIFIER_FINAL && $b & self::MODIFIER_FINAL) { throw new Error('Multiple final modifiers are not allowed'); } if ($a & self::MODIFIER_READONLY && $b & self::MODIFIER_READONLY) { throw new Error('Multiple readonly modifiers are not allowed'); } if ($a & 48 && $b & 48) { throw new Error('Cannot use the final modifier on an abstract class'); } } /** * @internal */ public static function verifyModifier($a, $b) { if ($a & self::VISIBILITY_MODIFIER_MASK && $b & self::VISIBILITY_MODIFIER_MASK) { throw new Error('Multiple access type modifiers are not allowed'); } if ($a & self::MODIFIER_ABSTRACT && $b & self::MODIFIER_ABSTRACT) { throw new Error('Multiple abstract modifiers are not allowed'); } if ($a & self::MODIFIER_STATIC && $b & self::MODIFIER_STATIC) { throw new Error('Multiple static modifiers are not allowed'); } if ($a & self::MODIFIER_FINAL && $b & self::MODIFIER_FINAL) { throw new Error('Multiple final modifiers are not allowed'); } if ($a & self::MODIFIER_READONLY && $b & self::MODIFIER_READONLY) { throw new Error('Multiple readonly modifiers are not allowed'); } if ($a & 48 && $b & 48) { throw new Error('Cannot use the final modifier on an abstract class member'); } } public function getType() : string { return 'Stmt_Class'; } } attributes = $attributes; $this->type = $type; $this->uses = $uses; } public function getSubNodeNames() : array { return ['type', 'uses']; } public function getType() : string { return 'Stmt_Use'; } } attributes = $attributes; $this->cond = $cond; $this->stmts = $stmts; } public function getSubNodeNames() : array { return ['cond', 'stmts']; } public function getType() : string { return 'Stmt_While'; } } attributes = $attributes; $this->name = \is_string($name) ? new Identifier($name) : $name; } public function getSubNodeNames() : array { return ['name']; } public function getType() : string { return 'Stmt_Label'; } } attributes = $attributes; $this->traits = $traits; $this->adaptations = $adaptations; } public function getSubNodeNames() : array { return ['traits', 'adaptations']; } public function getType() : string { return 'Stmt_TraitUse'; } } attributes = $attributes; $this->expr = $expr; } public function getSubNodeNames() : array { return ['expr']; } public function getType() : string { return 'Stmt_Throw'; } } array(): Statements * 'elseifs' => array(): Elseif clauses * 'else' => null : Else clause * @param array $attributes Additional attributes */ public function __construct(Node\Expr $cond, array $subNodes = [], array $attributes = []) { $this->attributes = $attributes; $this->cond = $cond; $this->stmts = $subNodes['stmts'] ?? []; $this->elseifs = $subNodes['elseifs'] ?? []; $this->else = $subNodes['else'] ?? null; } public function getSubNodeNames() : array { return ['cond', 'stmts', 'elseifs', 'else']; } public function getType() : string { return 'Stmt_If'; } } attributes = $attributes; $this->exprs = $exprs; } public function getSubNodeNames() : array { return ['exprs']; } public function getType() : string { return 'Stmt_Echo'; } } null : Variable to assign key to * 'byRef' => false : Whether to assign value by reference * 'stmts' => array(): Statements * @param array $attributes Additional attributes */ public function __construct(Node\Expr $expr, Node\Expr $valueVar, array $subNodes = [], array $attributes = []) { $this->attributes = $attributes; $this->expr = $expr; $this->keyVar = $subNodes['keyVar'] ?? null; $this->byRef = $subNodes['byRef'] ?? \false; $this->valueVar = $valueVar; $this->stmts = $subNodes['stmts'] ?? []; } public function getSubNodeNames() : array { return ['expr', 'keyVar', 'byRef', 'valueVar', 'stmts']; } public function getType() : string { return 'Stmt_Foreach'; } } attributes = $attributes; $this->name = $name; $this->value = $value; $this->byRef = $byRef; $this->unpack = $unpack; } public function getSubNodeNames() : array { return ['name', 'value', 'byRef', 'unpack']; } public function getType() : string { return 'Arg'; } } toString(); } public function getType() : string { return 'Name_FullyQualified'; } } toString(); } public function getType() : string { return 'Name_Relative'; } } attributes = $attributes; $this->name = \is_string($name) ? new Identifier($name) : $name; $this->value = $value; } public function getSubNodeNames() : array { return ['name', 'value']; } public function getType() : string { return 'Const'; } } attributes = $attributes; $this->types = $types; } public function getSubNodeNames() : array { return ['types']; } public function getType() : string { return 'UnionType'; } } '\\', '$' => '$', 'n' => "\n", 'r' => "\r", 't' => "\t", 'f' => "\f", 'v' => "\v", 'e' => "\x1b"]; /** * Constructs a string scalar node. * * @param string $value Value of the string * @param array $attributes Additional attributes */ public function __construct(string $value, array $attributes = []) { $this->attributes = $attributes; $this->value = $value; } public function getSubNodeNames() : array { return ['value']; } /** * @param bool $parseUnicodeEscape Whether to parse PHP 7 \u escapes */ public static function fromString(string $str, array $attributes = [], bool $parseUnicodeEscape = \true) : self { $attributes['kind'] = $str[0] === "'" || $str[1] === "'" && ($str[0] === 'b' || $str[0] === 'B') ? Scalar\String_::KIND_SINGLE_QUOTED : Scalar\String_::KIND_DOUBLE_QUOTED; $attributes['rawValue'] = $str; $string = self::parse($str, $parseUnicodeEscape); return new self($string, $attributes); } /** * @internal * * Parses a string token. * * @param string $str String token content * @param bool $parseUnicodeEscape Whether to parse PHP 7 \u escapes * * @return string The parsed string */ public static function parse(string $str, bool $parseUnicodeEscape = \true) : string { $bLength = 0; if ('b' === $str[0] || 'B' === $str[0]) { $bLength = 1; } if ('\'' === $str[$bLength]) { return \str_replace(['\\\\', '\\\''], ['\\', '\''], \substr($str, $bLength + 1, -1)); } else { return self::parseEscapeSequences(\substr($str, $bLength + 1, -1), '"', $parseUnicodeEscape); } } /** * @internal * * Parses escape sequences in strings (all string types apart from single quoted). * * @param string $str String without quotes * @param null|string $quote Quote type * @param bool $parseUnicodeEscape Whether to parse PHP 7 \u escapes * * @return string String with escape sequences parsed */ public static function parseEscapeSequences(string $str, $quote, bool $parseUnicodeEscape = \true) : string { if (null !== $quote) { $str = \str_replace('\\' . $quote, $quote, $str); } $extra = ''; if ($parseUnicodeEscape) { $extra = '|u\\{([0-9a-fA-F]+)\\}'; } return \preg_replace_callback('~\\\\([\\\\$nrtfve]|[xX][0-9a-fA-F]{1,2}|[0-7]{1,3}' . $extra . ')~', function ($matches) { $str = $matches[1]; if (isset(self::$replacements[$str])) { return self::$replacements[$str]; } elseif ('x' === $str[0] || 'X' === $str[0]) { return \chr(\hexdec(\substr($str, 1))); } elseif ('u' === $str[0]) { return self::codePointToUtf8(\hexdec($matches[2])); } else { return \chr(\octdec($str)); } }, $str); } /** * Converts a Unicode code point to its UTF-8 encoded representation. * * @param int $num Code point * * @return string UTF-8 representation of code point */ private static function codePointToUtf8(int $num) : string { if ($num <= 0x7f) { return \chr($num); } if ($num <= 0x7ff) { return \chr(($num >> 6) + 0xc0) . \chr(($num & 0x3f) + 0x80); } if ($num <= 0xffff) { return \chr(($num >> 12) + 0xe0) . \chr(($num >> 6 & 0x3f) + 0x80) . \chr(($num & 0x3f) + 0x80); } if ($num <= 0x1fffff) { return \chr(($num >> 18) + 0xf0) . \chr(($num >> 12 & 0x3f) + 0x80) . \chr(($num >> 6 & 0x3f) + 0x80) . \chr(($num & 0x3f) + 0x80); } throw new Error('Invalid UTF-8 codepoint escape sequence: Codepoint too large'); } public function getType() : string { return 'Scalar_String'; } } attributes = $attributes; $this->value = $value; } public function getSubNodeNames() : array { return ['value']; } /** * @param mixed[] $attributes */ public static function fromString(string $str, array $attributes = []) : DNumber { $attributes['rawValue'] = $str; $float = self::parse($str); return new DNumber($float, $attributes); } /** * @internal * * Parses a DNUMBER token like PHP would. * * @param string $str A string number * * @return float The parsed number */ public static function parse(string $str) : float { $str = \str_replace('_', '', $str); // Check whether this is one of the special integer notations. if ('0' === $str[0]) { // hex if ('x' === $str[1] || 'X' === $str[1]) { return \hexdec($str); } // bin if ('b' === $str[1] || 'B' === $str[1]) { return \bindec($str); } // oct, but only if the string does not contain any of '.eE'. if (\false === \strpbrk($str, '.eE')) { // substr($str, 0, strcspn($str, '89')) cuts the string at the first invalid digit // (8 or 9) so that only the digits before that are used. return \octdec(\substr($str, 0, \strcspn($str, '89'))); } } // dec return (float) $str; } public function getType() : string { return 'Scalar_DNumber'; } } attributes = $attributes; } public function getSubNodeNames() : array { return []; } /** * Get name of magic constant. * * @return string Name of magic constant */ public abstract function getName() : string; } attributes = $attributes; $this->parts = $parts; } public function getSubNodeNames() : array { return ['parts']; } public function getType() : string { return 'Scalar_Encapsed'; } } attributes = $attributes; $this->value = $value; } public function getSubNodeNames() : array { return ['value']; } public function getType() : string { return 'Scalar_EncapsedStringPart'; } } attributes = $attributes; $this->value = $value; } public function getSubNodeNames() : array { return ['value']; } /** * Constructs an LNumber node from a string number literal. * * @param string $str String number literal (decimal, octal, hex or binary) * @param array $attributes Additional attributes * @param bool $allowInvalidOctal Whether to allow invalid octal numbers (PHP 5) * * @return LNumber The constructed LNumber, including kind attribute */ public static function fromString(string $str, array $attributes = [], bool $allowInvalidOctal = \false) : LNumber { $attributes['rawValue'] = $str; $str = \str_replace('_', '', $str); if ('0' !== $str[0] || '0' === $str) { $attributes['kind'] = LNumber::KIND_DEC; return new LNumber((int) $str, $attributes); } if ('x' === $str[1] || 'X' === $str[1]) { $attributes['kind'] = LNumber::KIND_HEX; return new LNumber(\hexdec($str), $attributes); } if ('b' === $str[1] || 'B' === $str[1]) { $attributes['kind'] = LNumber::KIND_BIN; return new LNumber(\bindec($str), $attributes); } if (!$allowInvalidOctal && \strpbrk($str, '89')) { throw new Error('Invalid numeric literal', $attributes); } // Strip optional explicit octal prefix. if ('o' === $str[1] || 'O' === $str[1]) { $str = \substr($str, 2); } // use intval instead of octdec to get proper cutting behavior with malformed numbers $attributes['kind'] = LNumber::KIND_OCT; return new LNumber(\intval($str, 8), $attributes); } public function getType() : string { return 'Scalar_LNumber'; } } attributes = $attributes; } public function getType() : string { return 'VariadicPlaceholder'; } public function getSubNodeNames() : array { return []; } } conds = $conds; $this->body = $body; $this->attributes = $attributes; } public function getSubNodeNames() : array { return ['conds', 'body']; } public function getType() : string { return 'MatchArm'; } } \true, 'parent' => \true, 'static' => \true]; /** * Constructs an identifier node. * * @param string $name Identifier as string * @param array $attributes Additional attributes */ public function __construct(string $name, array $attributes = []) { $this->attributes = $attributes; $this->name = $name; } public function getSubNodeNames() : array { return ['name']; } /** * Get identifier as string. * * @return string Identifier as string. */ public function toString() : string { return $this->name; } /** * Get lowercased identifier as string. * * @return string Lowercased identifier as string */ public function toLowerString() : string { return \strtolower($this->name); } /** * Checks whether the identifier is a special class name (self, parent or static). * * @return bool Whether identifier is a special class name */ public function isSpecialClassName() : bool { return isset(self::$specialClassNames[\strtolower($this->name)]); } /** * Get identifier as string. * * @return string Identifier as string */ public function __toString() : string { return $this->name; } public function getType() : string { return 'Identifier'; } } \true, 'parent' => \true, 'static' => \true]; /** * Constructs a name node. * * @param string|string[]|self $name Name as string, part array or Name instance (copy ctor) * @param array $attributes Additional attributes */ public function __construct($name, array $attributes = []) { $this->attributes = $attributes; $this->parts = self::prepareName($name); } public function getSubNodeNames() : array { return ['parts']; } /** * Get parts of name (split by the namespace separator). * * @return string[] Parts of name */ public function getParts() : array { return $this->parts; } /** * Gets the first part of the name, i.e. everything before the first namespace separator. * * @return string First part of the name */ public function getFirst() : string { return $this->parts[0]; } /** * Gets the last part of the name, i.e. everything after the last namespace separator. * * @return string Last part of the name */ public function getLast() : string { return $this->parts[\count($this->parts) - 1]; } /** * Checks whether the name is unqualified. (E.g. Name) * * @return bool Whether the name is unqualified */ public function isUnqualified() : bool { return 1 === \count($this->parts); } /** * Checks whether the name is qualified. (E.g. Name\Name) * * @return bool Whether the name is qualified */ public function isQualified() : bool { return 1 < \count($this->parts); } /** * Checks whether the name is fully qualified. (E.g. \Name) * * @return bool Whether the name is fully qualified */ public function isFullyQualified() : bool { return \false; } /** * Checks whether the name is explicitly relative to the current namespace. (E.g. namespace\Name) * * @return bool Whether the name is relative */ public function isRelative() : bool { return \false; } /** * Returns a string representation of the name itself, without taking the name type into * account (e.g., not including a leading backslash for fully qualified names). * * @return string String representation */ public function toString() : string { return \implode('\\', $this->parts); } /** * Returns a string representation of the name as it would occur in code (e.g., including * leading backslash for fully qualified names. * * @return string String representation */ public function toCodeString() : string { return $this->toString(); } /** * Returns lowercased string representation of the name, without taking the name type into * account (e.g., no leading backslash for fully qualified names). * * @return string Lowercased string representation */ public function toLowerString() : string { return \strtolower(\implode('\\', $this->parts)); } /** * Checks whether the identifier is a special class name (self, parent or static). * * @return bool Whether identifier is a special class name */ public function isSpecialClassName() : bool { return \count($this->parts) === 1 && isset(self::$specialClassNames[\strtolower($this->parts[0])]); } /** * Returns a string representation of the name by imploding the namespace parts with the * namespace separator. * * @return string String representation */ public function __toString() : string { return \implode('\\', $this->parts); } /** * Gets a slice of a name (similar to array_slice). * * This method returns a new instance of the same type as the original and with the same * attributes. * * If the slice is empty, null is returned. The null value will be correctly handled in * concatenations using concat(). * * Offset and length have the same meaning as in array_slice(). * * @param int $offset Offset to start the slice at (may be negative) * @param int|null $length Length of the slice (may be negative) * * @return static|null Sliced name */ public function slice(int $offset, ?int $length = null) { $numParts = \count($this->parts); $realOffset = $offset < 0 ? $offset + $numParts : $offset; if ($realOffset < 0 || $realOffset > $numParts) { throw new \OutOfBoundsException(\sprintf('Offset %d is out of bounds', $offset)); } if (null === $length) { $realLength = $numParts - $realOffset; } else { $realLength = $length < 0 ? $length + $numParts - $realOffset : $length; if ($realLength < 0 || $realLength > $numParts - $realOffset) { throw new \OutOfBoundsException(\sprintf('Length %d is out of bounds', $length)); } } if ($realLength === 0) { // Empty slice is represented as null return null; } return new static(\array_slice($this->parts, $realOffset, $realLength), $this->attributes); } /** * Concatenate two names, yielding a new Name instance. * * The type of the generated instance depends on which class this method is called on, for * example Name\FullyQualified::concat() will yield a Name\FullyQualified instance. * * If one of the arguments is null, a new instance of the other name will be returned. If both * arguments are null, null will be returned. As such, writing * Name::concat($namespace, $shortName) * where $namespace is a Name node or null will work as expected. * * @param string|string[]|self|null $name1 The first name * @param string|string[]|self|null $name2 The second name * @param array $attributes Attributes to assign to concatenated name * * @return static|null Concatenated name */ public static function concat($name1, $name2, array $attributes = []) { if (null === $name1 && null === $name2) { return null; } elseif (null === $name1) { return new static(self::prepareName($name2), $attributes); } elseif (null === $name2) { return new static(self::prepareName($name1), $attributes); } else { return new static(\array_merge(self::prepareName($name1), self::prepareName($name2)), $attributes); } } /** * Prepares a (string, array or Name node) name for use in name changing methods by converting * it to an array. * * @param string|string[]|self $name Name to prepare * * @return string[] Prepared name */ private static function prepareName($name) : array { if (\is_string($name)) { if ('' === $name) { throw new \InvalidArgumentException('Name cannot be empty'); } return \explode('\\', $name); } elseif (\is_array($name)) { if (empty($name)) { throw new \InvalidArgumentException('Name cannot be empty'); } return $name; } elseif ($name instanceof self) { return $name->parts; } throw new \InvalidArgumentException('Expected string, array of parts or Name instance'); } public function getType() : string { return 'Name'; } } rawMessage = $message; if (\is_array($attributes)) { $this->attributes = $attributes; } else { $this->attributes = ['startLine' => $attributes]; } $this->updateMessage(); } /** * Gets the error message * * @return string Error message */ public function getRawMessage() : string { return $this->rawMessage; } /** * Gets the line the error starts in. * * @return int Error start line */ public function getStartLine() : int { return $this->attributes['startLine'] ?? -1; } /** * Gets the line the error ends in. * * @return int Error end line */ public function getEndLine() : int { return $this->attributes['endLine'] ?? -1; } /** * Gets the attributes of the node/token the error occurred at. * * @return array */ public function getAttributes() : array { return $this->attributes; } /** * Sets the attributes of the node/token the error occurred at. * * @param array $attributes */ public function setAttributes(array $attributes) { $this->attributes = $attributes; $this->updateMessage(); } /** * Sets the line of the PHP file the error occurred in. * * @param string $message Error message */ public function setRawMessage(string $message) { $this->rawMessage = $message; $this->updateMessage(); } /** * Sets the line the error starts in. * * @param int $line Error start line */ public function setStartLine(int $line) { $this->attributes['startLine'] = $line; $this->updateMessage(); } /** * Returns whether the error has start and end column information. * * For column information enable the startFilePos and endFilePos in the lexer options. * * @return bool */ public function hasColumnInfo() : bool { return isset($this->attributes['startFilePos'], $this->attributes['endFilePos']); } /** * Gets the start column (1-based) into the line where the error started. * * @param string $code Source code of the file * @return int */ public function getStartColumn(string $code) : int { if (!$this->hasColumnInfo()) { throw new \RuntimeException('Error does not have column information'); } return $this->toColumn($code, $this->attributes['startFilePos']); } /** * Gets the end column (1-based) into the line where the error ended. * * @param string $code Source code of the file * @return int */ public function getEndColumn(string $code) : int { if (!$this->hasColumnInfo()) { throw new \RuntimeException('Error does not have column information'); } return $this->toColumn($code, $this->attributes['endFilePos']); } /** * Formats message including line and column information. * * @param string $code Source code associated with the error, for calculation of the columns * * @return string Formatted message */ public function getMessageWithColumnInfo(string $code) : string { return \sprintf('%s from %d:%d to %d:%d', $this->getRawMessage(), $this->getStartLine(), $this->getStartColumn($code), $this->getEndLine(), $this->getEndColumn($code)); } /** * Converts a file offset into a column. * * @param string $code Source code that $pos indexes into * @param int $pos 0-based position in $code * * @return int 1-based column (relative to start of line) */ private function toColumn(string $code, int $pos) : int { if ($pos > \strlen($code)) { throw new \RuntimeException('Invalid position information'); } $lineStartPos = \strrpos($code, "\n", $pos - \strlen($code)); if (\false === $lineStartPos) { $lineStartPos = -1; } return $pos - $lineStartPos; } /** * Updates the exception message after a change to rawMessage or rawLine. */ protected function updateMessage() { $this->message = $this->rawMessage; if (-1 === $this->getStartLine()) { $this->message .= ' on unknown line'; } else { $this->message .= ' on line ' . $this->getStartLine(); } } } '", "T_IS_GREATER_OR_EQUAL", "T_SL", "T_SR", "'+'", "'-'", "'.'", "'*'", "'/'", "'%'", "'!'", "T_INSTANCEOF", "'~'", "T_INC", "T_DEC", "T_INT_CAST", "T_DOUBLE_CAST", "T_STRING_CAST", "T_ARRAY_CAST", "T_OBJECT_CAST", "T_BOOL_CAST", "T_UNSET_CAST", "'@'", "T_POW", "'['", "T_NEW", "T_CLONE", "T_EXIT", "T_IF", "T_ELSEIF", "T_ELSE", "T_ENDIF", "T_LNUMBER", "T_DNUMBER", "T_STRING", "T_STRING_VARNAME", "T_VARIABLE", "T_NUM_STRING", "T_INLINE_HTML", "T_ENCAPSED_AND_WHITESPACE", "T_CONSTANT_ENCAPSED_STRING", "T_ECHO", "T_DO", "T_WHILE", "T_ENDWHILE", "T_FOR", "T_ENDFOR", "T_FOREACH", "T_ENDFOREACH", "T_DECLARE", "T_ENDDECLARE", "T_AS", "T_SWITCH", "T_MATCH", "T_ENDSWITCH", "T_CASE", "T_DEFAULT", "T_BREAK", "T_CONTINUE", "T_GOTO", "T_FUNCTION", "T_FN", "T_CONST", "T_RETURN", "T_TRY", "T_CATCH", "T_FINALLY", "T_USE", "T_INSTEADOF", "T_GLOBAL", "T_STATIC", "T_ABSTRACT", "T_FINAL", "T_PRIVATE", "T_PROTECTED", "T_PUBLIC", "T_READONLY", "T_VAR", "T_UNSET", "T_ISSET", "T_EMPTY", "T_HALT_COMPILER", "T_CLASS", "T_TRAIT", "T_INTERFACE", "T_ENUM", "T_EXTENDS", "T_IMPLEMENTS", "T_OBJECT_OPERATOR", "T_NULLSAFE_OBJECT_OPERATOR", "T_LIST", "T_ARRAY", "T_CALLABLE", "T_CLASS_C", "T_TRAIT_C", "T_METHOD_C", "T_FUNC_C", "T_LINE", "T_FILE", "T_START_HEREDOC", "T_END_HEREDOC", "T_DOLLAR_OPEN_CURLY_BRACES", "T_CURLY_OPEN", "T_PAAMAYIM_NEKUDOTAYIM", "T_NAMESPACE", "T_NS_C", "T_DIR", "T_NS_SEPARATOR", "T_ELLIPSIS", "T_NAME_FULLY_QUALIFIED", "T_NAME_QUALIFIED", "T_NAME_RELATIVE", "T_ATTRIBUTE", "';'", "']'", "'{'", "'}'", "'('", "')'", "'`'", "'\"'", "'\$'"); protected $tokenToSymbol = array(0, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 56, 166, 168, 167, 55, 168, 168, 163, 164, 53, 50, 8, 51, 52, 54, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 31, 159, 44, 16, 46, 30, 68, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 70, 168, 160, 36, 168, 165, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 161, 35, 162, 58, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 1, 2, 3, 4, 5, 6, 7, 9, 10, 11, 12, 13, 14, 15, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 32, 33, 34, 37, 38, 39, 40, 41, 42, 43, 45, 47, 48, 49, 57, 59, 60, 61, 62, 63, 64, 65, 66, 67, 69, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158); protected $action = array(133, 134, 135, 579, 136, 137, 0, 748, 749, 750, 138, 38, 327, -32766, -32766, -32766, -32766, -32766, -32766, -32767, -32767, -32767, -32767, 102, 103, 104, 105, 106, 1109, 1110, 1111, 1108, 1107, 1106, 1112, 742, 741, -32766, 1232, -32766, -32766, -32766, -32766, -32766, -32766, -32766, -32767, -32767, -32767, -32767, -32767, 2, 107, 108, 109, 751, 274, 381, 380, -32766, -32766, -32766, -32766, 104, 105, 106, 1024, 422, 110, 265, 139, 403, 755, 756, 757, 758, 466, 467, 428, 938, 291, -32766, 287, -32766, -32766, 759, 760, 761, 762, 763, 764, 765, 766, 767, 768, 769, 789, 580, 790, 791, 792, 793, 781, 782, 344, 345, 784, 785, 770, 771, 772, 774, 775, 776, 355, 816, 817, 818, 819, 820, 581, 777, 778, 582, 583, 810, 801, 799, 800, 813, 796, 797, 687, -545, 584, 585, 795, 586, 587, 588, 589, 590, 591, -328, -593, -367, 1234, -367, 798, 592, 593, -593, 140, -32766, -32766, -32766, 133, 134, 135, 579, 136, 137, 1057, 748, 749, 750, 138, 38, 688, 1020, 1019, 1018, 1021, 390, -32766, 7, -32766, -32766, -32766, -32766, -32766, -32766, -32766, -32766, -32766, -32766, 379, 380, 1033, 689, 690, 742, 741, -32766, -32766, -32766, 422, -545, -545, -590, -32766, -32766, -32766, 1032, -32766, 127, -590, 1236, 1235, 1237, 1318, 751, -545, 290, -32766, 283, -32766, -32766, -32766, -32766, -32766, 1236, 1235, 1237, -545, 265, 139, 403, 755, 756, 757, 758, 16, 481, 428, 458, 459, 460, 298, 722, 35, 759, 760, 761, 762, 763, 764, 765, 766, 767, 768, 769, 789, 580, 790, 791, 792, 793, 781, 782, 344, 345, 784, 785, 770, 771, 772, 774, 775, 776, 355, 816, 817, 818, 819, 820, 581, 777, 778, 582, 583, 810, 801, 799, 800, 813, 796, 797, 129, 824, 584, 585, 795, 586, 587, 588, 589, 590, 591, -328, 83, 84, 85, -593, 798, 592, 593, -593, 149, 773, 743, 744, 745, 746, 747, 824, 748, 749, 750, 786, 787, 37, 145, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 291, 274, 835, 254, 1109, 1110, 1111, 1108, 1107, 1106, 1112, -590, 860, 110, 861, -590, 482, 751, -32766, -32766, -32766, -32766, -32766, 142, 603, 1085, 742, 741, 1262, 326, 987, 752, 753, 754, 755, 756, 757, 758, 309, -32766, 822, -32766, -32766, -32766, -32766, 242, 553, 759, 760, 761, 762, 763, 764, 765, 766, 767, 768, 769, 789, 812, 790, 791, 792, 793, 781, 782, 783, 811, 784, 785, 770, 771, 772, 774, 775, 776, 815, 816, 817, 818, 819, 820, 821, 777, 778, 779, 780, 810, 801, 799, 800, 813, 796, 797, 311, 940, 788, 794, 795, 802, 803, 805, 804, 806, 807, 323, 609, 1274, 1033, 833, 798, 809, 808, 50, 51, 52, 512, 53, 54, 860, 241, 861, 918, 55, 56, -111, 57, -32766, -32766, -32766, -111, 826, -111, 290, 1302, 1347, 356, 305, 1348, 339, -111, -111, -111, -111, -111, -111, -111, -111, -32766, -194, -32766, -32766, -32766, -193, 956, 957, 829, -86, 988, 958, 834, 58, 59, 340, 428, 952, -544, 60, 832, 61, 247, 248, 62, 63, 64, 65, 66, 67, 68, 69, 1241, 28, 267, 70, 444, 513, -342, -32766, 141, 1268, 1269, 514, 918, 833, 326, -272, 918, 1266, 42, 25, 515, 940, 516, 14, 517, 908, 518, 828, 369, 519, 520, 373, 709, 1033, 44, 45, 445, 376, 375, 388, 46, 521, 712, -86, 440, 1101, 367, 338, -543, 441, -544, -544, 830, 1227, 442, 523, 524, 525, 290, 1236, 1235, 1237, 361, 1030, 443, -544, 1087, 526, 527, 839, 1255, 1256, 1257, 1258, 1252, 1253, 297, -544, 151, -550, -584, 833, 1259, 1254, -584, 1033, 1236, 1235, 1237, 298, -154, -154, -154, 152, 71, 908, 321, 322, 326, 908, 920, 1030, 707, 833, 154, -154, 1337, -154, 155, -154, 283, -154, -543, -543, 82, 1232, 1086, 1322, 734, 156, 326, 374, 158, 1033, 1321, -194, -79, -543, -88, -193, 742, 741, 956, 957, 653, 26, -32766, 522, -51, -543, 33, -549, 894, 952, -111, -111, -111, 32, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, -59, 75, 28, 672, 673, 326, -58, 36, 250, 920, 124, 707, 125, 920, 833, 707, -154, 130, 1266, 131, -32766, -547, 144, -542, 150, 406, 1234, 377, 378, 1146, 1148, 382, 383, -32766, -32766, -32766, -85, -32766, 1056, -32766, -542, -32766, 644, 645, -32766, 159, 160, 161, 1232, -32766, -32766, -32766, 162, -79, 1227, -32766, -32766, 742, 741, 163, -302, -32766, 419, -75, -4, 918, -73, 287, 526, 527, -32766, 1255, 1256, 1257, 1258, 1252, 1253, -72, -71, -70, -69, -68, -67, 1259, 1254, -547, -547, -542, -542, 742, 741, -66, -47, -18, -32766, 73, 148, 918, 322, 326, 1234, 273, -542, 284, -542, -542, 723, -32766, -32766, -32766, 726, -32766, -547, -32766, -542, -32766, 917, 147, -32766, -542, 288, 289, -298, -32766, -32766, -32766, -32766, 713, 279, -32766, -32766, -542, 1234, 280, 285, -32766, 419, 48, 286, -32766, -32766, -32766, 332, -32766, -32766, -32766, 292, -32766, 908, 293, -32766, 934, 274, 1030, 918, -32766, -32766, -32766, 110, 682, 132, -32766, -32766, 833, 146, -32766, 559, -32766, 419, 659, 374, 824, 435, 1349, 74, 1033, -32766, 296, 654, 1116, 908, 956, 957, 306, 714, 698, 522, 555, 303, 13, 310, 852, 952, -111, -111, -111, 700, 463, 492, 953, 283, 299, 300, -32766, 49, 675, 918, 304, 660, 1234, 676, 936, 1273, -32766, 10, 1263, -32766, -32766, -32766, 642, -32766, 918, -32766, 920, -32766, 707, -4, -32766, 126, 34, 918, 565, -32766, -32766, -32766, -32766, 0, 908, -32766, -32766, 0, 1234, 918, 0, -32766, 419, 0, 0, -32766, -32766, -32766, 717, -32766, -32766, -32766, 920, -32766, 707, 1033, -32766, 724, 1275, 0, 487, -32766, -32766, -32766, -32766, 301, 302, -32766, -32766, -507, 1234, 571, -497, -32766, 419, 607, 8, -32766, -32766, -32766, 372, -32766, -32766, -32766, 17, -32766, 908, 371, -32766, 832, 298, 320, 128, -32766, -32766, -32766, 40, 370, 41, -32766, -32766, 908, -250, -250, -250, -32766, 419, 731, 374, 973, 908, 707, 732, 899, -32766, 997, 974, 728, 981, 956, 957, 971, 908, 982, 522, 897, 969, 1090, 1093, 894, 952, -111, -111, -111, 28, 1094, 1091, 1092, -249, -249, -249, 1241, 1098, 708, 374, 844, 833, 1288, 1306, 1340, 1266, 647, 1267, 711, 715, 956, 957, 716, 1241, 718, 522, 920, 719, 707, -250, 894, 952, -111, -111, -111, 720, -16, 721, 725, 710, -511, 920, 895, 707, -578, 1232, 1344, 1346, 855, 854, 920, 1227, 707, -577, 863, 946, 989, 862, 1345, 945, 943, 944, 920, 947, 707, -249, 527, 1218, 1255, 1256, 1257, 1258, 1252, 1253, 927, 937, 925, 979, 980, 631, 1259, 1254, 1343, 1300, -32766, 1289, 1307, 833, 1316, -275, 1234, -576, 73, -550, -549, 322, 326, -32766, -32766, -32766, -548, -32766, -491, -32766, 833, -32766, 1, 29, -32766, 30, 39, 43, 47, -32766, -32766, -32766, 72, 76, 77, -32766, -32766, 1232, -111, -111, 78, -32766, 419, -111, 79, 80, 81, 143, 153, -111, -32766, 157, 246, 328, 1232, -111, -111, 356, -32766, 357, -111, 358, 359, 360, 361, 362, -111, 363, 364, 365, 366, 368, 436, 0, -273, -32766, -272, 19, 20, 298, 21, 22, 24, 405, 75, 1203, 483, 484, 326, 491, 0, 494, 495, 496, 497, 501, 298, 502, 503, 510, 693, 75, 0, 1245, 1186, 326, 1264, 1059, 1058, 1039, 1222, 1035, -277, -103, 18, 23, 27, 295, 404, 600, 604, 633, 699, 1190, 1240, 1187, 1319, 0, 0, 0, 326); protected $actionCheck = array(2, 3, 4, 5, 6, 7, 0, 9, 10, 11, 12, 13, 70, 9, 10, 11, 9, 10, 11, 44, 45, 46, 47, 48, 49, 50, 51, 52, 116, 117, 118, 119, 120, 121, 122, 37, 38, 30, 116, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 8, 53, 54, 55, 57, 57, 106, 107, 137, 9, 10, 11, 50, 51, 52, 1, 116, 69, 71, 72, 73, 74, 75, 76, 77, 134, 135, 80, 1, 30, 30, 30, 32, 33, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 80, 70, 136, 137, 138, 139, 140, 141, 142, 143, 144, 8, 1, 106, 80, 108, 150, 151, 152, 8, 154, 9, 10, 11, 2, 3, 4, 5, 6, 7, 164, 9, 10, 11, 12, 13, 116, 119, 120, 121, 122, 106, 30, 108, 32, 33, 34, 35, 36, 37, 38, 9, 10, 11, 106, 107, 138, 137, 138, 37, 38, 9, 10, 11, 116, 134, 135, 1, 9, 10, 11, 137, 30, 14, 8, 155, 156, 157, 1, 57, 149, 163, 30, 163, 32, 33, 34, 35, 36, 155, 156, 157, 161, 71, 72, 73, 74, 75, 76, 77, 8, 31, 80, 129, 130, 131, 158, 161, 8, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 8, 80, 136, 137, 138, 139, 140, 141, 142, 143, 144, 164, 9, 10, 11, 160, 150, 151, 152, 164, 154, 2, 3, 4, 5, 6, 7, 80, 9, 10, 11, 12, 13, 30, 8, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 30, 57, 1, 8, 116, 117, 118, 119, 120, 121, 122, 160, 106, 69, 108, 164, 161, 57, 9, 10, 11, 9, 10, 161, 1, 1, 37, 38, 1, 167, 31, 71, 72, 73, 74, 75, 76, 77, 8, 30, 80, 32, 33, 34, 35, 14, 85, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 8, 122, 136, 137, 138, 139, 140, 141, 142, 143, 144, 8, 51, 146, 138, 82, 150, 151, 152, 2, 3, 4, 5, 6, 7, 106, 97, 108, 1, 12, 13, 101, 15, 9, 10, 11, 106, 80, 108, 163, 1, 80, 163, 113, 83, 8, 116, 117, 118, 119, 120, 121, 122, 123, 30, 8, 32, 33, 34, 8, 117, 118, 80, 31, 159, 122, 159, 50, 51, 8, 80, 128, 70, 56, 155, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 1, 70, 71, 72, 73, 74, 162, 9, 161, 78, 79, 80, 1, 82, 167, 164, 1, 86, 87, 88, 89, 122, 91, 101, 93, 84, 95, 156, 8, 98, 99, 8, 161, 138, 103, 104, 105, 106, 107, 8, 109, 110, 31, 97, 8, 123, 115, 116, 70, 8, 134, 135, 156, 122, 8, 124, 125, 126, 163, 155, 156, 157, 163, 116, 8, 149, 162, 136, 137, 8, 139, 140, 141, 142, 143, 144, 145, 161, 14, 163, 160, 82, 151, 152, 164, 138, 155, 156, 157, 158, 75, 76, 77, 14, 163, 84, 165, 166, 167, 84, 159, 116, 161, 82, 14, 90, 85, 92, 14, 94, 163, 96, 134, 135, 161, 116, 159, 1, 161, 14, 167, 106, 14, 138, 8, 164, 16, 149, 31, 164, 37, 38, 117, 118, 75, 76, 137, 122, 31, 161, 14, 163, 127, 128, 129, 130, 131, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 16, 163, 70, 75, 76, 167, 16, 147, 148, 159, 16, 161, 16, 159, 82, 161, 162, 16, 86, 16, 74, 70, 16, 70, 101, 102, 80, 106, 107, 59, 60, 106, 107, 87, 88, 89, 31, 91, 1, 93, 70, 95, 111, 112, 98, 16, 16, 16, 116, 103, 104, 105, 16, 31, 122, 109, 110, 37, 38, 16, 35, 115, 116, 31, 0, 1, 31, 30, 136, 137, 124, 139, 140, 141, 142, 143, 144, 31, 31, 31, 31, 31, 31, 151, 152, 134, 135, 134, 135, 37, 38, 31, 31, 31, 74, 163, 31, 1, 166, 167, 80, 31, 149, 31, 134, 135, 31, 87, 88, 89, 31, 91, 161, 93, 161, 95, 31, 31, 98, 149, 37, 37, 35, 103, 104, 105, 74, 31, 35, 109, 110, 161, 80, 35, 35, 115, 116, 70, 35, 87, 88, 89, 35, 91, 124, 93, 37, 95, 84, 37, 98, 38, 57, 116, 1, 103, 104, 105, 69, 77, 31, 109, 110, 82, 70, 85, 89, 115, 116, 96, 106, 80, 108, 83, 154, 138, 124, 113, 90, 82, 84, 117, 118, 114, 31, 80, 122, 85, 132, 97, 132, 127, 128, 129, 130, 131, 92, 97, 97, 128, 163, 134, 135, 74, 70, 94, 1, 133, 100, 80, 100, 154, 146, 137, 150, 160, 87, 88, 89, 113, 91, 1, 93, 159, 95, 161, 162, 98, 161, 161, 1, 153, 103, 104, 105, 74, -1, 84, 109, 110, -1, 80, 1, -1, 115, 116, -1, -1, 87, 88, 89, 31, 91, 124, 93, 159, 95, 161, 138, 98, 31, 146, -1, 102, 103, 104, 105, 74, 134, 135, 109, 110, 149, 80, 81, 149, 115, 116, 153, 149, 87, 88, 89, 149, 91, 124, 93, 149, 95, 84, 149, 98, 155, 158, 161, 161, 103, 104, 105, 159, 161, 159, 109, 110, 84, 100, 101, 102, 115, 116, 159, 106, 159, 84, 161, 159, 159, 124, 159, 159, 162, 159, 117, 118, 159, 84, 159, 122, 159, 159, 159, 159, 127, 128, 129, 130, 131, 70, 159, 159, 159, 100, 101, 102, 1, 159, 161, 106, 160, 82, 160, 160, 160, 86, 160, 166, 161, 161, 117, 118, 161, 1, 161, 122, 159, 161, 161, 162, 127, 128, 129, 130, 131, 161, 31, 161, 161, 161, 165, 159, 162, 161, 163, 116, 162, 162, 162, 162, 159, 122, 161, 163, 162, 162, 162, 162, 162, 162, 162, 162, 159, 162, 161, 162, 137, 162, 139, 140, 141, 142, 143, 144, 162, 162, 162, 162, 162, 162, 151, 152, 162, 162, 74, 162, 162, 82, 162, 164, 80, 163, 163, 163, 163, 166, 167, 87, 88, 89, 163, 91, 163, 93, 82, 95, 163, 163, 98, 163, 163, 163, 163, 103, 104, 105, 163, 163, 163, 109, 110, 116, 117, 118, 163, 115, 116, 122, 163, 163, 163, 163, 163, 128, 124, 163, 163, 163, 116, 117, 118, 163, 137, 163, 122, 163, 163, 163, 163, 163, 128, 163, 163, 163, 163, 163, 163, -1, 164, 137, 164, 164, 164, 158, 164, 164, 164, 164, 163, 165, 164, 164, 167, 164, -1, 164, 164, 164, 164, 164, 158, 164, 164, 164, 164, 163, -1, 164, 164, 167, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, -1, -1, -1, 167); protected $actionBase = array(0, -2, 154, 542, 752, 893, 929, 52, 374, 431, 398, 869, 793, 235, 307, 307, 793, 307, 784, 908, 908, 917, 908, 538, 841, 468, 468, 468, 708, 708, 708, 708, 740, 740, 849, 849, 881, 817, 634, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 348, 346, 370, 653, 1063, 1069, 1065, 1070, 1061, 1060, 1064, 1066, 1071, 946, 947, 774, 949, 950, 943, 952, 1067, 882, 1062, 1068, 291, 291, 291, 291, 291, 291, 291, 291, 291, 291, 291, 291, 291, 291, 291, 291, 291, 291, 291, 291, 291, 291, 291, 291, 291, 291, 291, 525, 191, 359, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 174, 174, 174, 620, 620, 51, 465, 356, 955, 955, 955, 955, 955, 955, 955, 955, 955, 955, 658, 184, 144, 144, 7, 7, 7, 7, 7, 1031, 371, 1048, -25, -25, -25, -25, 50, 725, 526, 449, 39, 317, 80, 474, 474, 13, 13, 512, 512, 422, 422, 512, 512, 512, 808, 808, 808, 808, 443, 505, 360, 308, -78, 209, 209, 209, 209, -78, -78, -78, -78, 803, 877, -78, -78, -78, 63, 641, 641, 822, -1, -1, -1, 641, 253, 790, 548, 253, 384, 548, 480, 402, 764, 759, -49, 447, 764, 639, 755, 198, 143, 825, 609, 825, 1059, 320, 768, 426, 749, 720, 874, 904, 1072, 796, 941, 798, 942, 106, -58, 710, 1058, 1058, 1058, 1058, 1058, 1058, 1058, 1058, 1058, 1058, 1058, 1073, 336, 1059, 423, 1073, 1073, 1073, 336, 336, 336, 336, 336, 336, 336, 336, 336, 336, 619, 423, 586, 616, 423, 795, 336, 348, 814, 348, 348, 348, 348, 348, 348, 348, 348, 348, 348, 750, 202, 348, 346, 78, 78, 484, 65, 78, 78, 78, 78, 348, 348, 348, 348, 609, 783, 766, 613, 813, 492, 783, 783, 783, 473, 135, 378, 488, 713, 775, 67, 779, 779, 785, 969, 969, 779, 769, 779, 785, 975, 779, 779, 969, 969, 823, 280, 563, 478, 550, 568, 969, 377, 779, 779, 779, 779, 746, 573, 779, 342, 314, 779, 779, 746, 744, 760, 43, 762, 969, 969, 969, 746, 547, 762, 762, 762, 839, 844, 794, 758, 444, 433, 588, 232, 801, 758, 758, 779, 558, 794, 758, 794, 758, 745, 758, 758, 758, 794, 758, 769, 502, 758, 717, 583, 224, 758, 6, 979, 980, 624, 981, 973, 987, 1019, 991, 992, 873, 965, 999, 974, 993, 972, 970, 773, 682, 684, 818, 811, 963, 777, 777, 777, 956, 777, 777, 777, 777, 777, 777, 777, 777, 682, 743, 829, 765, 1006, 689, 691, 754, 906, 901, 1030, 1004, 1049, 994, 828, 694, 1028, 1008, 846, 821, 1009, 1010, 1029, 1050, 1052, 910, 782, 911, 912, 876, 1012, 883, 777, 979, 992, 693, 974, 993, 972, 970, 748, 739, 737, 738, 736, 735, 723, 734, 753, 1053, 954, 907, 878, 1011, 957, 682, 879, 1023, 756, 1032, 1033, 827, 788, 778, 880, 913, 1014, 1015, 1016, 884, 1054, 887, 830, 1024, 951, 1035, 789, 918, 1037, 1038, 1039, 1040, 889, 919, 892, 916, 900, 845, 776, 1020, 761, 920, 591, 787, 791, 800, 1018, 606, 1000, 902, 921, 922, 1041, 1043, 1044, 923, 924, 995, 847, 1026, 799, 1027, 1022, 848, 850, 617, 797, 1055, 781, 786, 772, 621, 632, 925, 927, 931, 998, 763, 770, 853, 855, 1056, 771, 1057, 938, 635, 857, 718, 939, 1046, 719, 724, 637, 678, 672, 731, 792, 903, 826, 757, 780, 1017, 724, 767, 858, 940, 859, 860, 867, 1045, 868, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 458, 458, 458, 458, 458, 458, 307, 307, 307, 307, 307, 307, 307, 0, 0, 307, 0, 458, 458, 458, 458, 458, 458, 458, 458, 458, 458, 458, 458, 458, 458, 458, 458, 458, 458, 458, 458, 458, 458, 458, 458, 458, 458, 458, 458, 458, 458, 458, 458, 458, 458, 458, 458, 458, 458, 458, 458, 458, 458, 458, 458, 458, 458, 458, 458, 458, 458, 458, 458, 458, 458, 458, 458, 458, 458, 458, 458, 458, 458, 458, 458, 458, 458, 458, 458, 458, 458, 458, 458, 458, 458, 458, 458, 458, 458, 458, 458, 458, 458, 458, 458, 458, 458, 458, 458, 458, 458, 458, 458, 458, 458, 458, 458, 458, 458, 458, 458, 458, 458, 458, 458, 458, 458, 458, 458, 458, 458, 458, 458, 458, 458, 458, 458, 458, 458, 458, 458, 458, 458, 458, 458, 458, 458, 458, 458, 458, 458, 458, 458, 458, 458, 458, 458, 458, 458, 458, 458, 458, 458, 458, 458, 458, 458, 291, 291, 291, 291, 291, 291, 291, 291, 291, 291, 291, 291, 291, 291, 291, 291, 291, 291, 291, 291, 291, 291, 291, 291, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 291, 291, 291, 291, 291, 291, 291, 291, 291, 291, 291, 291, 291, 291, 291, 291, 291, 291, 291, 291, 291, 291, 291, 291, 291, 291, 66, 66, 291, 291, 291, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 0, 291, 291, 291, 291, 291, 291, 291, 291, 66, 823, 66, -1, -1, -1, -1, 66, 66, 66, -88, -88, 66, 384, 66, 66, -1, -1, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 0, 0, 423, 548, 66, 769, 769, 769, 769, 66, 66, 66, 66, 548, 548, 66, 66, 66, 0, 0, 0, 0, 0, 0, 0, 0, 423, 548, 0, 423, 0, 0, 769, 769, 66, 384, 823, 643, 66, 0, 0, 0, 0, 423, 769, 423, 336, 779, 548, 779, 336, 336, 78, 348, 643, 611, 611, 611, 611, 0, 0, 609, 823, 823, 823, 823, 823, 823, 823, 823, 823, 823, 823, 769, 0, 823, 0, 769, 769, 769, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 769, 0, 0, 969, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 975, 0, 0, 0, 0, 0, 0, 769, 0, 0, 0, 0, 0, 0, 0, 0, 0, 777, 788, 0, 788, 0, 777, 777, 777, 0, 0, 0, 0, 797, 771); protected $actionDefault = array(3, 32767, 103, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 101, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 596, 596, 596, 596, 32767, 32767, 254, 103, 32767, 32767, 469, 387, 387, 387, 32767, 32767, 540, 540, 540, 540, 540, 540, 32767, 32767, 32767, 32767, 32767, 32767, 469, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 101, 32767, 32767, 32767, 37, 7, 8, 10, 11, 50, 17, 324, 32767, 32767, 32767, 32767, 103, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 589, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 473, 452, 453, 455, 456, 386, 541, 595, 327, 592, 385, 146, 339, 329, 242, 330, 258, 474, 259, 475, 478, 479, 215, 287, 382, 150, 151, 416, 470, 418, 468, 472, 417, 392, 397, 398, 399, 400, 401, 402, 403, 404, 405, 406, 407, 408, 409, 390, 391, 471, 449, 448, 447, 32767, 32767, 414, 415, 419, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 103, 32767, 389, 422, 420, 421, 438, 439, 436, 437, 440, 32767, 32767, 32767, 441, 442, 443, 444, 316, 32767, 32767, 366, 364, 316, 112, 32767, 32767, 429, 430, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 534, 446, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 103, 32767, 101, 536, 411, 413, 503, 424, 425, 423, 393, 32767, 510, 32767, 103, 32767, 512, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 535, 32767, 542, 542, 32767, 496, 101, 195, 32767, 32767, 32767, 195, 195, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 603, 496, 111, 111, 111, 111, 111, 111, 111, 111, 111, 111, 111, 32767, 195, 111, 32767, 32767, 32767, 101, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 190, 32767, 268, 270, 103, 557, 195, 32767, 515, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 508, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 496, 434, 139, 32767, 139, 542, 426, 427, 428, 498, 542, 542, 542, 312, 289, 32767, 32767, 32767, 32767, 513, 513, 101, 101, 101, 101, 508, 32767, 32767, 32767, 32767, 112, 100, 100, 100, 100, 100, 104, 102, 32767, 32767, 32767, 32767, 223, 100, 32767, 102, 102, 32767, 32767, 223, 225, 212, 102, 227, 32767, 561, 562, 223, 102, 227, 227, 227, 247, 247, 485, 318, 102, 100, 102, 102, 197, 318, 318, 32767, 102, 485, 318, 485, 318, 199, 318, 318, 318, 485, 318, 32767, 102, 318, 214, 100, 100, 318, 32767, 32767, 32767, 498, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 222, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 529, 32767, 546, 559, 432, 433, 435, 544, 457, 458, 459, 460, 461, 462, 463, 465, 591, 32767, 502, 32767, 32767, 32767, 338, 601, 32767, 601, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 602, 32767, 542, 32767, 32767, 32767, 32767, 431, 9, 76, 491, 43, 44, 52, 58, 519, 520, 521, 522, 516, 517, 523, 518, 32767, 32767, 524, 567, 32767, 32767, 543, 594, 32767, 32767, 32767, 32767, 32767, 32767, 139, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 529, 32767, 137, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 525, 32767, 32767, 32767, 542, 32767, 32767, 32767, 32767, 314, 311, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 542, 32767, 32767, 32767, 32767, 32767, 291, 32767, 308, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 286, 32767, 32767, 381, 498, 294, 296, 297, 32767, 32767, 32767, 32767, 360, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 153, 153, 3, 3, 341, 153, 153, 153, 341, 341, 153, 341, 341, 341, 153, 153, 153, 153, 153, 153, 280, 185, 262, 265, 247, 247, 153, 352, 153); protected $goto = array(196, 196, 1031, 703, 694, 430, 658, 1062, 1334, 1334, 424, 313, 314, 335, 573, 319, 429, 336, 431, 635, 651, 652, 850, 669, 670, 671, 1334, 167, 167, 167, 167, 221, 197, 193, 193, 177, 179, 216, 193, 193, 193, 193, 193, 194, 194, 194, 194, 194, 194, 188, 189, 190, 191, 192, 218, 216, 219, 534, 535, 420, 536, 538, 539, 540, 541, 542, 543, 544, 545, 1132, 168, 169, 170, 195, 171, 172, 173, 166, 174, 175, 176, 178, 215, 217, 220, 238, 243, 244, 245, 257, 258, 259, 260, 261, 262, 263, 264, 268, 269, 270, 271, 281, 282, 316, 317, 318, 425, 426, 427, 578, 222, 223, 224, 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 180, 237, 181, 198, 199, 200, 239, 188, 189, 190, 191, 192, 218, 1132, 201, 182, 183, 184, 202, 198, 185, 240, 203, 201, 165, 204, 205, 186, 206, 207, 208, 187, 209, 210, 211, 212, 213, 214, 853, 851, 278, 278, 278, 278, 418, 620, 620, 350, 570, 597, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1283, 1283, 831, 618, 655, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 353, 353, 353, 353, 866, 557, 550, 858, 825, 907, 902, 903, 916, 859, 904, 856, 905, 906, 857, 878, 457, 910, 865, 884, 546, 546, 546, 546, 831, 601, 831, 1084, 1079, 1080, 1081, 341, 550, 557, 566, 567, 343, 576, 599, 613, 614, 407, 408, 972, 465, 465, 667, 15, 668, 1323, 411, 412, 413, 465, 681, 348, 1233, 414, 1233, 478, 569, 346, 439, 1031, 1031, 1233, 993, 480, 1031, 393, 1031, 1031, 1104, 1105, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1315, 1315, 1315, 1315, 1233, 657, 1333, 1333, 1055, 1233, 1233, 1233, 1233, 1037, 1036, 1233, 1233, 1233, 1034, 1034, 1181, 354, 678, 949, 1333, 437, 1026, 1042, 1043, 337, 691, 354, 354, 827, 923, 691, 1040, 1041, 924, 691, 663, 1336, 939, 871, 939, 354, 354, 1281, 1281, 354, 679, 1350, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 552, 537, 537, 911, 354, 912, 537, 537, 537, 537, 537, 537, 537, 537, 537, 537, 548, 564, 548, 574, 611, 730, 634, 636, 849, 548, 656, 475, 1308, 1309, 680, 684, 1007, 692, 701, 1003, 252, 252, 996, 970, 970, 968, 970, 729, 843, 549, 1005, 1000, 423, 455, 608, 1294, 846, 955, 966, 966, 966, 966, 325, 308, 455, 960, 967, 249, 249, 249, 249, 251, 253, 402, 351, 352, 683, 868, 551, 561, 449, 449, 449, 551, 1305, 561, 1305, 612, 396, 461, 1010, 1010, 1224, 1305, 395, 398, 558, 598, 602, 1015, 468, 577, 469, 470, 1310, 1311, 876, 552, 846, 1341, 1342, 964, 409, 702, 733, 324, 275, 324, 1317, 1317, 1317, 1317, 606, 621, 624, 625, 626, 627, 648, 649, 650, 705, 1068, 596, 1097, 874, 706, 476, 1228, 507, 697, 880, 1095, 1115, 432, 1301, 628, 630, 632, 432, 879, 867, 1067, 1071, 5, 1072, 6, 1038, 1038, 977, 0, 975, 662, 1049, 1045, 1046, 0, 0, 0, 0, 1226, 449, 449, 449, 449, 449, 449, 449, 449, 449, 449, 449, 928, 1120, 449, 965, 1070, 0, 0, 616, 1303, 1303, 1070, 1229, 1230, 1012, 499, 0, 500, 0, 0, 841, 0, 870, 506, 661, 991, 1113, 883, 1212, 941, 864, 0, 1213, 1216, 942, 1217, 0, 0, 1231, 1291, 1292, 0, 1223, 0, 0, 0, 846, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255); protected $gotoCheck = array(42, 42, 72, 9, 72, 65, 65, 126, 181, 181, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 85, 85, 26, 85, 85, 85, 181, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 15, 27, 23, 23, 23, 23, 43, 107, 107, 96, 170, 129, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 168, 168, 12, 55, 55, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 24, 24, 24, 24, 35, 75, 75, 15, 6, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 35, 82, 15, 35, 45, 106, 106, 106, 106, 12, 106, 12, 15, 15, 15, 15, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 81, 81, 49, 148, 148, 81, 75, 81, 179, 81, 81, 81, 148, 81, 177, 72, 81, 72, 83, 103, 81, 82, 72, 72, 72, 102, 83, 72, 61, 72, 72, 143, 143, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 9, 9, 9, 9, 72, 63, 180, 180, 113, 72, 72, 72, 72, 117, 117, 72, 72, 72, 88, 88, 150, 14, 88, 88, 180, 112, 88, 88, 88, 29, 7, 14, 14, 7, 72, 7, 118, 118, 72, 7, 119, 180, 9, 39, 9, 14, 14, 169, 169, 14, 115, 14, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 14, 171, 171, 64, 14, 64, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 19, 48, 19, 2, 2, 48, 48, 48, 25, 19, 48, 174, 174, 174, 48, 48, 48, 48, 48, 48, 5, 5, 25, 25, 25, 25, 25, 25, 18, 25, 25, 25, 13, 19, 13, 14, 22, 91, 19, 19, 19, 19, 167, 167, 19, 19, 19, 5, 5, 5, 5, 5, 5, 28, 96, 96, 14, 37, 9, 9, 23, 23, 23, 9, 129, 9, 129, 79, 9, 9, 106, 106, 159, 129, 58, 58, 58, 58, 58, 109, 9, 9, 9, 9, 176, 176, 9, 14, 22, 9, 9, 92, 92, 92, 98, 24, 24, 24, 129, 129, 129, 129, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 128, 8, 8, 9, 8, 156, 20, 8, 8, 41, 8, 146, 116, 129, 84, 84, 84, 116, 16, 16, 16, 16, 46, 131, 46, 116, 116, 95, -1, 16, 116, 116, 116, 116, -1, -1, -1, -1, 14, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 17, 17, 23, 16, 129, -1, -1, 17, 129, 129, 129, 20, 20, 17, 154, -1, 154, -1, -1, 20, -1, 17, 154, 17, 17, 16, 16, 78, 78, 17, -1, 78, 78, 78, 78, -1, -1, 20, 20, 20, -1, 17, -1, -1, -1, 22, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 5, 5); protected $gotoBase = array(0, 0, -339, 0, 0, 386, 195, 312, 472, -10, 0, 0, -109, 62, 13, -184, 46, 65, 86, 102, 93, 0, 125, 162, 197, 371, 18, 160, 83, 22, 0, 0, 0, 0, 0, -166, 0, 85, 0, 9, 0, 48, -1, 157, 0, 207, -232, 0, -340, 223, 0, 0, 0, 0, 0, 148, 0, 0, 396, 0, 0, 231, 0, 52, 334, -236, 0, 0, 0, 0, 0, 0, -5, 0, 0, -139, 0, 0, 149, 91, 112, -245, -58, -205, 15, -695, 0, 0, 28, 0, 0, 75, 154, 0, 0, 64, -310, 0, 55, 0, 0, 0, 235, 221, 0, 0, 196, -71, 0, 77, 0, 0, 37, 24, 0, 56, 219, 23, 40, 39, 0, 0, 0, 0, 0, 0, 5, 0, 106, 166, 0, 61, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 47, 0, 214, 0, 35, 0, 0, 0, 49, 0, 45, 0, 0, 71, 0, 0, 0, 0, 0, 0, 0, 88, -56, 95, 144, 111, 0, 0, 78, 0, 80, 229, 0, 222, -12, -299, 0, 0); protected $gotoDefault = array(-32768, 511, 737, 4, 738, 932, 814, 823, 594, 528, 704, 347, 622, 421, 1299, 909, 1119, 575, 842, 1242, 1250, 456, 845, 330, 727, 891, 892, 893, 399, 385, 391, 397, 646, 623, 493, 877, 452, 869, 485, 872, 451, 881, 164, 417, 509, 885, 3, 888, 554, 919, 386, 896, 387, 674, 898, 560, 900, 901, 394, 400, 401, 1124, 568, 619, 913, 256, 562, 914, 384, 915, 922, 389, 392, 685, 464, 504, 498, 410, 1099, 563, 605, 643, 446, 472, 617, 629, 615, 479, 433, 415, 329, 954, 962, 486, 462, 976, 349, 984, 735, 1131, 637, 488, 992, 638, 999, 1002, 529, 530, 477, 1014, 272, 1017, 489, 12, 664, 1028, 1029, 665, 639, 1051, 640, 666, 641, 1053, 471, 595, 1061, 453, 1069, 1287, 454, 1073, 266, 1076, 277, 416, 434, 1082, 1083, 9, 1089, 695, 696, 11, 276, 508, 1114, 686, 450, 1130, 438, 1200, 1202, 556, 490, 1220, 1219, 677, 505, 1225, 447, 1290, 448, 531, 473, 315, 532, 307, 333, 312, 547, 294, 334, 533, 474, 1296, 1304, 331, 31, 1324, 1335, 342, 572, 610); protected $ruleToNonTerminal = array(0, 1, 3, 3, 2, 5, 5, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, 7, 7, 8, 8, 9, 10, 11, 11, 11, 12, 12, 13, 13, 14, 15, 15, 16, 16, 17, 17, 18, 18, 21, 21, 22, 23, 23, 24, 24, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 29, 29, 30, 30, 32, 34, 34, 28, 36, 36, 33, 38, 38, 35, 35, 37, 37, 39, 39, 31, 40, 40, 41, 43, 44, 44, 45, 45, 46, 46, 48, 47, 47, 47, 47, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 25, 25, 68, 68, 71, 71, 70, 69, 69, 62, 74, 74, 75, 75, 76, 76, 77, 77, 78, 78, 79, 79, 26, 26, 27, 27, 27, 27, 27, 87, 87, 89, 89, 82, 82, 90, 90, 91, 91, 91, 83, 83, 86, 86, 84, 84, 92, 93, 93, 56, 56, 64, 64, 67, 67, 67, 66, 94, 94, 95, 57, 57, 57, 57, 96, 96, 97, 97, 98, 98, 99, 100, 100, 101, 101, 102, 102, 54, 54, 50, 50, 104, 52, 52, 105, 51, 51, 53, 53, 63, 63, 63, 63, 80, 80, 108, 108, 110, 110, 111, 111, 111, 111, 109, 109, 109, 113, 113, 113, 113, 88, 88, 116, 116, 116, 117, 117, 114, 114, 118, 118, 120, 120, 121, 121, 115, 122, 122, 119, 123, 123, 123, 123, 112, 112, 81, 81, 81, 20, 20, 20, 125, 124, 124, 126, 126, 126, 126, 59, 127, 127, 128, 60, 130, 130, 131, 131, 132, 132, 85, 133, 133, 133, 133, 133, 133, 133, 138, 138, 139, 139, 140, 140, 140, 140, 140, 141, 142, 142, 137, 137, 134, 134, 136, 136, 144, 144, 143, 143, 143, 143, 143, 143, 143, 135, 145, 145, 147, 146, 146, 61, 103, 148, 148, 55, 55, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 155, 149, 149, 154, 154, 157, 158, 158, 159, 160, 161, 161, 161, 161, 19, 19, 72, 72, 72, 72, 150, 150, 150, 150, 163, 163, 151, 151, 153, 153, 153, 156, 156, 168, 168, 168, 168, 168, 168, 168, 168, 168, 169, 169, 169, 107, 171, 171, 171, 171, 152, 152, 152, 152, 152, 152, 152, 152, 58, 58, 166, 166, 166, 166, 172, 172, 162, 162, 162, 173, 173, 173, 173, 173, 173, 73, 73, 65, 65, 65, 65, 129, 129, 129, 129, 176, 175, 165, 165, 165, 165, 165, 165, 165, 164, 164, 164, 174, 174, 174, 174, 106, 170, 178, 178, 177, 177, 179, 179, 179, 179, 179, 179, 179, 179, 167, 167, 167, 167, 181, 182, 180, 180, 180, 180, 180, 180, 180, 180, 183, 183, 183, 183); protected $ruleToLength = array(1, 1, 2, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 1, 1, 2, 1, 3, 4, 1, 2, 0, 1, 1, 1, 1, 1, 3, 5, 4, 3, 4, 2, 3, 1, 1, 7, 6, 2, 3, 1, 2, 3, 1, 2, 3, 1, 1, 3, 1, 3, 1, 2, 2, 3, 1, 3, 2, 3, 1, 3, 3, 2, 0, 1, 1, 1, 1, 1, 3, 7, 10, 5, 7, 9, 5, 3, 3, 3, 3, 3, 3, 1, 2, 5, 7, 9, 6, 5, 6, 3, 2, 1, 1, 1, 0, 2, 1, 3, 8, 0, 4, 2, 1, 3, 0, 1, 0, 1, 0, 1, 3, 1, 1, 1, 8, 9, 7, 8, 7, 6, 8, 0, 2, 0, 2, 1, 2, 1, 2, 1, 1, 1, 0, 2, 0, 2, 0, 2, 2, 1, 3, 1, 4, 1, 4, 1, 1, 4, 2, 1, 3, 3, 3, 4, 4, 5, 0, 2, 4, 3, 1, 1, 7, 0, 2, 1, 3, 3, 4, 1, 4, 0, 2, 5, 0, 2, 6, 0, 2, 0, 3, 1, 2, 1, 1, 2, 0, 1, 3, 0, 2, 1, 1, 1, 1, 6, 8, 6, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 3, 3, 3, 1, 3, 3, 3, 3, 3, 1, 3, 3, 1, 1, 2, 1, 1, 0, 1, 0, 2, 2, 2, 4, 3, 1, 1, 3, 1, 2, 2, 3, 2, 3, 1, 1, 2, 3, 1, 1, 3, 2, 0, 1, 5, 5, 6, 10, 3, 5, 1, 1, 3, 0, 2, 4, 5, 4, 4, 4, 3, 1, 1, 1, 1, 1, 1, 0, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 2, 1, 3, 1, 1, 3, 2, 2, 3, 1, 0, 1, 1, 3, 3, 3, 4, 1, 1, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 5, 4, 3, 4, 4, 2, 2, 4, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 3, 2, 1, 2, 4, 2, 2, 8, 9, 8, 9, 9, 10, 9, 10, 8, 3, 2, 0, 4, 2, 1, 3, 2, 1, 2, 2, 2, 4, 1, 1, 1, 1, 1, 1, 1, 1, 3, 1, 1, 1, 0, 3, 0, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3, 5, 3, 3, 4, 1, 1, 3, 1, 1, 1, 1, 1, 3, 2, 3, 0, 1, 1, 3, 1, 1, 1, 1, 1, 3, 1, 1, 4, 4, 1, 4, 4, 0, 1, 1, 1, 3, 3, 1, 4, 2, 2, 1, 3, 1, 4, 4, 3, 3, 3, 3, 1, 3, 1, 1, 3, 1, 1, 4, 1, 1, 1, 3, 1, 1, 2, 1, 3, 4, 3, 2, 0, 2, 2, 1, 2, 1, 1, 1, 4, 3, 3, 3, 3, 6, 3, 1, 1, 2, 1); protected function initReduceCallbacks() { $this->reduceCallbacks = [0 => function ($stackPos) { $this->semValue = $this->semStack[$stackPos]; }, 1 => function ($stackPos) { $this->semValue = $this->handleNamespaces($this->semStack[$stackPos - (1 - 1)]); }, 2 => function ($stackPos) { if (\is_array($this->semStack[$stackPos - (2 - 2)])) { $this->semValue = \array_merge($this->semStack[$stackPos - (2 - 1)], $this->semStack[$stackPos - (2 - 2)]); } else { $this->semStack[$stackPos - (2 - 1)][] = $this->semStack[$stackPos - (2 - 2)]; $this->semValue = $this->semStack[$stackPos - (2 - 1)]; } }, 3 => function ($stackPos) { $this->semValue = array(); }, 4 => function ($stackPos) { $startAttributes = $this->lookaheadStartAttributes; if (isset($startAttributes['comments'])) { $nop = new Stmt\Nop($this->createCommentNopAttributes($startAttributes['comments'])); } else { $nop = null; } if ($nop !== null) { $this->semStack[$stackPos - (1 - 1)][] = $nop; } $this->semValue = $this->semStack[$stackPos - (1 - 1)]; }, 5 => function ($stackPos) { $this->semValue = $this->semStack[$stackPos]; }, 6 => function ($stackPos) { $this->semValue = $this->semStack[$stackPos]; }, 7 => function ($stackPos) { $this->semValue = $this->semStack[$stackPos]; }, 8 => function ($stackPos) { $this->semValue = $this->semStack[$stackPos]; }, 9 => function ($stackPos) { $this->semValue = $this->semStack[$stackPos]; }, 10 => function ($stackPos) { $this->semValue = $this->semStack[$stackPos]; }, 11 => function ($stackPos) { $this->semValue = $this->semStack[$stackPos]; }, 12 => function ($stackPos) { $this->semValue = $this->semStack[$stackPos]; }, 13 => function ($stackPos) { $this->semValue = $this->semStack[$stackPos]; }, 14 => function ($stackPos) { $this->semValue = $this->semStack[$stackPos]; }, 15 => function ($stackPos) { $this->semValue = $this->semStack[$stackPos]; }, 16 => function ($stackPos) { $this->semValue = $this->semStack[$stackPos]; }, 17 => function ($stackPos) { $this->semValue = $this->semStack[$stackPos]; }, 18 => function ($stackPos) { $this->semValue = $this->semStack[$stackPos]; }, 19 => function ($stackPos) { $this->semValue = $this->semStack[$stackPos]; }, 20 => function ($stackPos) { $this->semValue = $this->semStack[$stackPos]; }, 21 => function ($stackPos) { $this->semValue = $this->semStack[$stackPos]; }, 22 => function ($stackPos) { $this->semValue = $this->semStack[$stackPos]; }, 23 => function ($stackPos) { $this->semValue = $this->semStack[$stackPos]; }, 24 => function ($stackPos) { $this->semValue = $this->semStack[$stackPos]; }, 25 => function ($stackPos) { $this->semValue = $this->semStack[$stackPos]; }, 26 => function ($stackPos) { $this->semValue = $this->semStack[$stackPos]; }, 27 => function ($stackPos) { $this->semValue = $this->semStack[$stackPos]; }, 28 => function ($stackPos) { $this->semValue = $this->semStack[$stackPos]; }, 29 => function ($stackPos) { $this->semValue = $this->semStack[$stackPos]; }, 30 => function ($stackPos) { $this->semValue = $this->semStack[$stackPos]; }, 31 => function ($stackPos) { $this->semValue = $this->semStack[$stackPos]; }, 32 => function ($stackPos) { $this->semValue = $this->semStack[$stackPos]; }, 33 => function ($stackPos) { $this->semValue = $this->semStack[$stackPos]; }, 34 => function ($stackPos) { $this->semValue = $this->semStack[$stackPos]; }, 35 => function ($stackPos) { $this->semValue = $this->semStack[$stackPos]; }, 36 => function ($stackPos) { $this->semValue = $this->semStack[$stackPos]; }, 37 => function ($stackPos) { $this->semValue = $this->semStack[$stackPos]; }, 38 => function ($stackPos) { $this->semValue = $this->semStack[$stackPos]; }, 39 => function ($stackPos) { $this->semValue = $this->semStack[$stackPos]; }, 40 => function ($stackPos) { $this->semValue = $this->semStack[$stackPos]; }, 41 => function ($stackPos) { $this->semValue = $this->semStack[$stackPos]; }, 42 => function ($stackPos) { $this->semValue = $this->semStack[$stackPos]; }, 43 => function ($stackPos) { $this->semValue = $this->semStack[$stackPos]; }, 44 => function ($stackPos) { $this->semValue = $this->semStack[$stackPos]; }, 45 => function ($stackPos) { $this->semValue = $this->semStack[$stackPos]; }, 46 => function ($stackPos) { $this->semValue = $this->semStack[$stackPos]; }, 47 => function ($stackPos) { $this->semValue = $this->semStack[$stackPos]; }, 48 => function ($stackPos) { $this->semValue = $this->semStack[$stackPos]; }, 49 => function ($stackPos) { $this->semValue = $this->semStack[$stackPos]; }, 50 => function ($stackPos) { $this->semValue = $this->semStack[$stackPos]; }, 51 => function ($stackPos) { $this->semValue = $this->semStack[$stackPos]; }, 52 => function ($stackPos) { $this->semValue = $this->semStack[$stackPos]; }, 53 => function ($stackPos) { $this->semValue = $this->semStack[$stackPos]; }, 54 => function ($stackPos) { $this->semValue = $this->semStack[$stackPos]; }, 55 => function ($stackPos) { $this->semValue = $this->semStack[$stackPos]; }, 56 => function ($stackPos) { $this->semValue = $this->semStack[$stackPos]; }, 57 => function ($stackPos) { $this->semValue = $this->semStack[$stackPos]; }, 58 => function ($stackPos) { $this->semValue = $this->semStack[$stackPos]; }, 59 => function ($stackPos) { $this->semValue = $this->semStack[$stackPos]; }, 60 => function ($stackPos) { $this->semValue = $this->semStack[$stackPos]; }, 61 => function ($stackPos) { $this->semValue = $this->semStack[$stackPos]; }, 62 => function ($stackPos) { $this->semValue = $this->semStack[$stackPos]; }, 63 => function ($stackPos) { $this->semValue = $this->semStack[$stackPos]; }, 64 => function ($stackPos) { $this->semValue = $this->semStack[$stackPos]; }, 65 => function ($stackPos) { $this->semValue = $this->semStack[$stackPos]; }, 66 => function ($stackPos) { $this->semValue = $this->semStack[$stackPos]; }, 67 => function ($stackPos) { $this->semValue = $this->semStack[$stackPos]; }, 68 => function ($stackPos) { $this->semValue = $this->semStack[$stackPos]; }, 69 => function ($stackPos) { $this->semValue = $this->semStack[$stackPos]; }, 70 => function ($stackPos) { $this->semValue = $this->semStack[$stackPos]; }, 71 => function ($stackPos) { $this->semValue = $this->semStack[$stackPos]; }, 72 => function ($stackPos) { $this->semValue = $this->semStack[$stackPos]; }, 73 => function ($stackPos) { $this->semValue = $this->semStack[$stackPos]; }, 74 => function ($stackPos) { $this->semValue = $this->semStack[$stackPos]; }, 75 => function ($stackPos) { $this->semValue = $this->semStack[$stackPos]; }, 76 => function ($stackPos) { $this->semValue = $this->semStack[$stackPos]; }, 77 => function ($stackPos) { $this->semValue = $this->semStack[$stackPos]; }, 78 => function ($stackPos) { $this->semValue = $this->semStack[$stackPos]; }, 79 => function ($stackPos) { $this->semValue = $this->semStack[$stackPos]; }, 80 => function ($stackPos) { $this->semValue = $this->semStack[$stackPos]; }, 81 => function ($stackPos) { $this->semValue = $this->semStack[$stackPos]; }, 82 => function ($stackPos) { $this->semValue = $this->semStack[$stackPos]; }, 83 => function ($stackPos) { $this->semValue = $this->semStack[$stackPos]; }, 84 => function ($stackPos) { $this->semValue = $this->semStack[$stackPos]; }, 85 => function ($stackPos) { $this->semValue = $this->semStack[$stackPos]; }, 86 => function ($stackPos) { $this->semValue = new Node\Identifier($this->semStack[$stackPos - (1 - 1)], $this->startAttributeStack[$stackPos - (1 - 1)] + $this->endAttributes); }, 87 => function ($stackPos) { $this->semValue = new Node\Identifier($this->semStack[$stackPos - (1 - 1)], $this->startAttributeStack[$stackPos - (1 - 1)] + $this->endAttributes); }, 88 => function ($stackPos) { $this->semValue = new Node\Identifier($this->semStack[$stackPos - (1 - 1)], $this->startAttributeStack[$stackPos - (1 - 1)] + $this->endAttributes); }, 89 => function ($stackPos) { $this->semValue = new Node\Identifier($this->semStack[$stackPos - (1 - 1)], $this->startAttributeStack[$stackPos - (1 - 1)] + $this->endAttributes); }, 90 => function ($stackPos) { $this->semValue = new Name($this->semStack[$stackPos - (1 - 1)], $this->startAttributeStack[$stackPos - (1 - 1)] + $this->endAttributes); }, 91 => function ($stackPos) { $this->semValue = new Name($this->semStack[$stackPos - (1 - 1)], $this->startAttributeStack[$stackPos - (1 - 1)] + $this->endAttributes); }, 92 => function ($stackPos) { $this->semValue = new Name($this->semStack[$stackPos - (1 - 1)], $this->startAttributeStack[$stackPos - (1 - 1)] + $this->endAttributes); }, 93 => function ($stackPos) { $this->semValue = new Name($this->semStack[$stackPos - (1 - 1)], $this->startAttributeStack[$stackPos - (1 - 1)] + $this->endAttributes); }, 94 => function ($stackPos) { $this->semValue = new Name($this->semStack[$stackPos - (1 - 1)], $this->startAttributeStack[$stackPos - (1 - 1)] + $this->endAttributes); }, 95 => function ($stackPos) { $this->semValue = $this->semStack[$stackPos - (1 - 1)]; }, 96 => function ($stackPos) { $this->semValue = new Name(\substr($this->semStack[$stackPos - (1 - 1)], 1), $this->startAttributeStack[$stackPos - (1 - 1)] + $this->endAttributes); }, 97 => function ($stackPos) { $this->semValue = new Expr\Variable(\substr($this->semStack[$stackPos - (1 - 1)], 1), $this->startAttributeStack[$stackPos - (1 - 1)] + $this->endAttributes); }, 98 => function ($stackPos) { /* nothing */ }, 99 => function ($stackPos) { /* nothing */ }, 100 => function ($stackPos) { /* nothing */ }, 101 => function ($stackPos) { $this->emitError(new Error('A trailing comma is not allowed here', $this->startAttributeStack[$stackPos - (1 - 1)] + $this->endAttributes)); }, 102 => function ($stackPos) { $this->semValue = $this->semStack[$stackPos]; }, 103 => function ($stackPos) { $this->semValue = $this->semStack[$stackPos]; }, 104 => function ($stackPos) { $this->semValue = new Node\Attribute($this->semStack[$stackPos - (1 - 1)], [], $this->startAttributeStack[$stackPos - (1 - 1)] + $this->endAttributes); }, 105 => function ($stackPos) { $this->semValue = new Node\Attribute($this->semStack[$stackPos - (2 - 1)], $this->semStack[$stackPos - (2 - 2)], $this->startAttributeStack[$stackPos - (2 - 1)] + $this->endAttributes); }, 106 => function ($stackPos) { $this->semValue = array($this->semStack[$stackPos - (1 - 1)]); }, 107 => function ($stackPos) { $this->semStack[$stackPos - (3 - 1)][] = $this->semStack[$stackPos - (3 - 3)]; $this->semValue = $this->semStack[$stackPos - (3 - 1)]; }, 108 => function ($stackPos) { $this->semValue = new Node\AttributeGroup($this->semStack[$stackPos - (4 - 2)], $this->startAttributeStack[$stackPos - (4 - 1)] + $this->endAttributes); }, 109 => function ($stackPos) { $this->semValue = array($this->semStack[$stackPos - (1 - 1)]); }, 110 => function ($stackPos) { $this->semStack[$stackPos - (2 - 1)][] = $this->semStack[$stackPos - (2 - 2)]; $this->semValue = $this->semStack[$stackPos - (2 - 1)]; }, 111 => function ($stackPos) { $this->semValue = []; }, 112 => function ($stackPos) { $this->semValue = $this->semStack[$stackPos - (1 - 1)]; }, 113 => function ($stackPos) { $this->semValue = $this->semStack[$stackPos - (1 - 1)]; }, 114 => function ($stackPos) { $this->semValue = $this->semStack[$stackPos - (1 - 1)]; }, 115 => function ($stackPos) { $this->semValue = $this->semStack[$stackPos - (1 - 1)]; }, 116 => function ($stackPos) { $this->semValue = new Stmt\HaltCompiler($this->lexer->handleHaltCompiler(), $this->startAttributeStack[$stackPos - (1 - 1)] + $this->endAttributes); }, 117 => function ($stackPos) { $this->semValue = new Stmt\Namespace_($this->semStack[$stackPos - (3 - 2)], null, $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); $this->semValue->setAttribute('kind', Stmt\Namespace_::KIND_SEMICOLON); $this->checkNamespace($this->semValue); }, 118 => function ($stackPos) { $this->semValue = new Stmt\Namespace_($this->semStack[$stackPos - (5 - 2)], $this->semStack[$stackPos - (5 - 4)], $this->startAttributeStack[$stackPos - (5 - 1)] + $this->endAttributes); $this->semValue->setAttribute('kind', Stmt\Namespace_::KIND_BRACED); $this->checkNamespace($this->semValue); }, 119 => function ($stackPos) { $this->semValue = new Stmt\Namespace_(null, $this->semStack[$stackPos - (4 - 3)], $this->startAttributeStack[$stackPos - (4 - 1)] + $this->endAttributes); $this->semValue->setAttribute('kind', Stmt\Namespace_::KIND_BRACED); $this->checkNamespace($this->semValue); }, 120 => function ($stackPos) { $this->semValue = new Stmt\Use_($this->semStack[$stackPos - (3 - 2)], Stmt\Use_::TYPE_NORMAL, $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); }, 121 => function ($stackPos) { $this->semValue = new Stmt\Use_($this->semStack[$stackPos - (4 - 3)], $this->semStack[$stackPos - (4 - 2)], $this->startAttributeStack[$stackPos - (4 - 1)] + $this->endAttributes); }, 122 => function ($stackPos) { $this->semValue = $this->semStack[$stackPos - (2 - 1)]; }, 123 => function ($stackPos) { $this->semValue = new Stmt\Const_($this->semStack[$stackPos - (3 - 2)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); }, 124 => function ($stackPos) { $this->semValue = Stmt\Use_::TYPE_FUNCTION; }, 125 => function ($stackPos) { $this->semValue = Stmt\Use_::TYPE_CONSTANT; }, 126 => function ($stackPos) { $this->semValue = new Stmt\GroupUse($this->semStack[$stackPos - (7 - 3)], $this->semStack[$stackPos - (7 - 6)], $this->semStack[$stackPos - (7 - 2)], $this->startAttributeStack[$stackPos - (7 - 1)] + $this->endAttributes); }, 127 => function ($stackPos) { $this->semValue = new Stmt\GroupUse($this->semStack[$stackPos - (6 - 2)], $this->semStack[$stackPos - (6 - 5)], Stmt\Use_::TYPE_UNKNOWN, $this->startAttributeStack[$stackPos - (6 - 1)] + $this->endAttributes); }, 128 => function ($stackPos) { $this->semValue = $this->semStack[$stackPos - (2 - 1)]; }, 129 => function ($stackPos) { $this->semStack[$stackPos - (3 - 1)][] = $this->semStack[$stackPos - (3 - 3)]; $this->semValue = $this->semStack[$stackPos - (3 - 1)]; }, 130 => function ($stackPos) { $this->semValue = array($this->semStack[$stackPos - (1 - 1)]); }, 131 => function ($stackPos) { $this->semValue = $this->semStack[$stackPos - (2 - 1)]; }, 132 => function ($stackPos) { $this->semStack[$stackPos - (3 - 1)][] = $this->semStack[$stackPos - (3 - 3)]; $this->semValue = $this->semStack[$stackPos - (3 - 1)]; }, 133 => function ($stackPos) { $this->semValue = array($this->semStack[$stackPos - (1 - 1)]); }, 134 => function ($stackPos) { $this->semValue = $this->semStack[$stackPos - (2 - 1)]; }, 135 => function ($stackPos) { $this->semStack[$stackPos - (3 - 1)][] = $this->semStack[$stackPos - (3 - 3)]; $this->semValue = $this->semStack[$stackPos - (3 - 1)]; }, 136 => function ($stackPos) { $this->semValue = array($this->semStack[$stackPos - (1 - 1)]); }, 137 => function ($stackPos) { $this->semValue = new Stmt\UseUse($this->semStack[$stackPos - (1 - 1)], null, Stmt\Use_::TYPE_UNKNOWN, $this->startAttributeStack[$stackPos - (1 - 1)] + $this->endAttributes); $this->checkUseUse($this->semValue, $stackPos - (1 - 1)); }, 138 => function ($stackPos) { $this->semValue = new Stmt\UseUse($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], Stmt\Use_::TYPE_UNKNOWN, $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); $this->checkUseUse($this->semValue, $stackPos - (3 - 3)); }, 139 => function ($stackPos) { $this->semValue = new Stmt\UseUse($this->semStack[$stackPos - (1 - 1)], null, Stmt\Use_::TYPE_UNKNOWN, $this->startAttributeStack[$stackPos - (1 - 1)] + $this->endAttributes); $this->checkUseUse($this->semValue, $stackPos - (1 - 1)); }, 140 => function ($stackPos) { $this->semValue = new Stmt\UseUse($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], Stmt\Use_::TYPE_UNKNOWN, $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); $this->checkUseUse($this->semValue, $stackPos - (3 - 3)); }, 141 => function ($stackPos) { $this->semValue = $this->semStack[$stackPos - (1 - 1)]; $this->semValue->type = Stmt\Use_::TYPE_NORMAL; }, 142 => function ($stackPos) { $this->semValue = $this->semStack[$stackPos - (2 - 2)]; $this->semValue->type = $this->semStack[$stackPos - (2 - 1)]; }, 143 => function ($stackPos) { $this->semValue = $this->semStack[$stackPos - (2 - 1)]; }, 144 => function ($stackPos) { $this->semStack[$stackPos - (3 - 1)][] = $this->semStack[$stackPos - (3 - 3)]; $this->semValue = $this->semStack[$stackPos - (3 - 1)]; }, 145 => function ($stackPos) { $this->semValue = array($this->semStack[$stackPos - (1 - 1)]); }, 146 => function ($stackPos) { $this->semValue = new Node\Const_($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); }, 147 => function ($stackPos) { $this->semValue = $this->semStack[$stackPos - (2 - 1)]; }, 148 => function ($stackPos) { $this->semStack[$stackPos - (3 - 1)][] = $this->semStack[$stackPos - (3 - 3)]; $this->semValue = $this->semStack[$stackPos - (3 - 1)]; }, 149 => function ($stackPos) { $this->semValue = array($this->semStack[$stackPos - (1 - 1)]); }, 150 => function ($stackPos) { $this->semValue = new Node\Const_(new Node\Identifier($this->semStack[$stackPos - (3 - 1)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributeStack[$stackPos - (3 - 1)]), $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); }, 151 => function ($stackPos) { $this->semValue = new Node\Const_(new Node\Identifier($this->semStack[$stackPos - (3 - 1)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributeStack[$stackPos - (3 - 1)]), $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); }, 152 => function ($stackPos) { if (\is_array($this->semStack[$stackPos - (2 - 2)])) { $this->semValue = \array_merge($this->semStack[$stackPos - (2 - 1)], $this->semStack[$stackPos - (2 - 2)]); } else { $this->semStack[$stackPos - (2 - 1)][] = $this->semStack[$stackPos - (2 - 2)]; $this->semValue = $this->semStack[$stackPos - (2 - 1)]; } }, 153 => function ($stackPos) { $this->semValue = array(); }, 154 => function ($stackPos) { $startAttributes = $this->lookaheadStartAttributes; if (isset($startAttributes['comments'])) { $nop = new Stmt\Nop($this->createCommentNopAttributes($startAttributes['comments'])); } else { $nop = null; } if ($nop !== null) { $this->semStack[$stackPos - (1 - 1)][] = $nop; } $this->semValue = $this->semStack[$stackPos - (1 - 1)]; }, 155 => function ($stackPos) { $this->semValue = $this->semStack[$stackPos - (1 - 1)]; }, 156 => function ($stackPos) { $this->semValue = $this->semStack[$stackPos - (1 - 1)]; }, 157 => function ($stackPos) { $this->semValue = $this->semStack[$stackPos - (1 - 1)]; }, 158 => function ($stackPos) { throw new Error('__HALT_COMPILER() can only be used from the outermost scope', $this->startAttributeStack[$stackPos - (1 - 1)] + $this->endAttributes); }, 159 => function ($stackPos) { if ($this->semStack[$stackPos - (3 - 2)]) { $this->semValue = $this->semStack[$stackPos - (3 - 2)]; $attrs = $this->startAttributeStack[$stackPos - (3 - 1)]; $stmts = $this->semValue; if (!empty($attrs['comments'])) { $stmts[0]->setAttribute('comments', \array_merge($attrs['comments'], $stmts[0]->getAttribute('comments', []))); } } else { $startAttributes = $this->startAttributeStack[$stackPos - (3 - 1)]; if (isset($startAttributes['comments'])) { $this->semValue = new Stmt\Nop($startAttributes + $this->endAttributes); } else { $this->semValue = null; } if (null === $this->semValue) { $this->semValue = array(); } } }, 160 => function ($stackPos) { $this->semValue = new Stmt\If_($this->semStack[$stackPos - (7 - 3)], ['stmts' => \is_array($this->semStack[$stackPos - (7 - 5)]) ? $this->semStack[$stackPos - (7 - 5)] : array($this->semStack[$stackPos - (7 - 5)]), 'elseifs' => $this->semStack[$stackPos - (7 - 6)], 'else' => $this->semStack[$stackPos - (7 - 7)]], $this->startAttributeStack[$stackPos - (7 - 1)] + $this->endAttributes); }, 161 => function ($stackPos) { $this->semValue = new Stmt\If_($this->semStack[$stackPos - (10 - 3)], ['stmts' => $this->semStack[$stackPos - (10 - 6)], 'elseifs' => $this->semStack[$stackPos - (10 - 7)], 'else' => $this->semStack[$stackPos - (10 - 8)]], $this->startAttributeStack[$stackPos - (10 - 1)] + $this->endAttributes); }, 162 => function ($stackPos) { $this->semValue = new Stmt\While_($this->semStack[$stackPos - (5 - 3)], $this->semStack[$stackPos - (5 - 5)], $this->startAttributeStack[$stackPos - (5 - 1)] + $this->endAttributes); }, 163 => function ($stackPos) { $this->semValue = new Stmt\Do_($this->semStack[$stackPos - (7 - 5)], \is_array($this->semStack[$stackPos - (7 - 2)]) ? $this->semStack[$stackPos - (7 - 2)] : array($this->semStack[$stackPos - (7 - 2)]), $this->startAttributeStack[$stackPos - (7 - 1)] + $this->endAttributes); }, 164 => function ($stackPos) { $this->semValue = new Stmt\For_(['init' => $this->semStack[$stackPos - (9 - 3)], 'cond' => $this->semStack[$stackPos - (9 - 5)], 'loop' => $this->semStack[$stackPos - (9 - 7)], 'stmts' => $this->semStack[$stackPos - (9 - 9)]], $this->startAttributeStack[$stackPos - (9 - 1)] + $this->endAttributes); }, 165 => function ($stackPos) { $this->semValue = new Stmt\Switch_($this->semStack[$stackPos - (5 - 3)], $this->semStack[$stackPos - (5 - 5)], $this->startAttributeStack[$stackPos - (5 - 1)] + $this->endAttributes); }, 166 => function ($stackPos) { $this->semValue = new Stmt\Break_($this->semStack[$stackPos - (3 - 2)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); }, 167 => function ($stackPos) { $this->semValue = new Stmt\Continue_($this->semStack[$stackPos - (3 - 2)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); }, 168 => function ($stackPos) { $this->semValue = new Stmt\Return_($this->semStack[$stackPos - (3 - 2)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); }, 169 => function ($stackPos) { $this->semValue = new Stmt\Global_($this->semStack[$stackPos - (3 - 2)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); }, 170 => function ($stackPos) { $this->semValue = new Stmt\Static_($this->semStack[$stackPos - (3 - 2)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); }, 171 => function ($stackPos) { $this->semValue = new Stmt\Echo_($this->semStack[$stackPos - (3 - 2)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); }, 172 => function ($stackPos) { $this->semValue = new Stmt\InlineHTML($this->semStack[$stackPos - (1 - 1)], $this->startAttributeStack[$stackPos - (1 - 1)] + $this->endAttributes); }, 173 => function ($stackPos) { $e = $this->semStack[$stackPos - (2 - 1)]; if ($e instanceof Expr\Throw_) { // For backwards-compatibility reasons, convert throw in statement position into // Stmt\Throw_ rather than Stmt\Expression(Expr\Throw_). $this->semValue = new Stmt\Throw_($e->expr, $this->startAttributeStack[$stackPos - (2 - 1)] + $this->endAttributes); } else { $this->semValue = new Stmt\Expression($e, $this->startAttributeStack[$stackPos - (2 - 1)] + $this->endAttributes); } }, 174 => function ($stackPos) { $this->semValue = new Stmt\Unset_($this->semStack[$stackPos - (5 - 3)], $this->startAttributeStack[$stackPos - (5 - 1)] + $this->endAttributes); }, 175 => function ($stackPos) { $this->semValue = new Stmt\Foreach_($this->semStack[$stackPos - (7 - 3)], $this->semStack[$stackPos - (7 - 5)][0], ['keyVar' => null, 'byRef' => $this->semStack[$stackPos - (7 - 5)][1], 'stmts' => $this->semStack[$stackPos - (7 - 7)]], $this->startAttributeStack[$stackPos - (7 - 1)] + $this->endAttributes); }, 176 => function ($stackPos) { $this->semValue = new Stmt\Foreach_($this->semStack[$stackPos - (9 - 3)], $this->semStack[$stackPos - (9 - 7)][0], ['keyVar' => $this->semStack[$stackPos - (9 - 5)], 'byRef' => $this->semStack[$stackPos - (9 - 7)][1], 'stmts' => $this->semStack[$stackPos - (9 - 9)]], $this->startAttributeStack[$stackPos - (9 - 1)] + $this->endAttributes); }, 177 => function ($stackPos) { $this->semValue = new Stmt\Foreach_($this->semStack[$stackPos - (6 - 3)], new Expr\Error($this->startAttributeStack[$stackPos - (6 - 4)] + $this->endAttributeStack[$stackPos - (6 - 4)]), ['stmts' => $this->semStack[$stackPos - (6 - 6)]], $this->startAttributeStack[$stackPos - (6 - 1)] + $this->endAttributes); }, 178 => function ($stackPos) { $this->semValue = new Stmt\Declare_($this->semStack[$stackPos - (5 - 3)], $this->semStack[$stackPos - (5 - 5)], $this->startAttributeStack[$stackPos - (5 - 1)] + $this->endAttributes); }, 179 => function ($stackPos) { $this->semValue = new Stmt\TryCatch($this->semStack[$stackPos - (6 - 3)], $this->semStack[$stackPos - (6 - 5)], $this->semStack[$stackPos - (6 - 6)], $this->startAttributeStack[$stackPos - (6 - 1)] + $this->endAttributes); $this->checkTryCatch($this->semValue); }, 180 => function ($stackPos) { $this->semValue = new Stmt\Goto_($this->semStack[$stackPos - (3 - 2)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); }, 181 => function ($stackPos) { $this->semValue = new Stmt\Label($this->semStack[$stackPos - (2 - 1)], $this->startAttributeStack[$stackPos - (2 - 1)] + $this->endAttributes); }, 182 => function ($stackPos) { $this->semValue = array(); /* means: no statement */ }, 183 => function ($stackPos) { $this->semValue = $this->semStack[$stackPos - (1 - 1)]; }, 184 => function ($stackPos) { $startAttributes = $this->startAttributeStack[$stackPos - (1 - 1)]; if (isset($startAttributes['comments'])) { $this->semValue = new Stmt\Nop($startAttributes + $this->endAttributes); } else { $this->semValue = null; } if ($this->semValue === null) { $this->semValue = array(); } /* means: no statement */ }, 185 => function ($stackPos) { $this->semValue = array(); }, 186 => function ($stackPos) { $this->semStack[$stackPos - (2 - 1)][] = $this->semStack[$stackPos - (2 - 2)]; $this->semValue = $this->semStack[$stackPos - (2 - 1)]; }, 187 => function ($stackPos) { $this->semValue = array($this->semStack[$stackPos - (1 - 1)]); }, 188 => function ($stackPos) { $this->semStack[$stackPos - (3 - 1)][] = $this->semStack[$stackPos - (3 - 3)]; $this->semValue = $this->semStack[$stackPos - (3 - 1)]; }, 189 => function ($stackPos) { $this->semValue = new Stmt\Catch_($this->semStack[$stackPos - (8 - 3)], $this->semStack[$stackPos - (8 - 4)], $this->semStack[$stackPos - (8 - 7)], $this->startAttributeStack[$stackPos - (8 - 1)] + $this->endAttributes); }, 190 => function ($stackPos) { $this->semValue = null; }, 191 => function ($stackPos) { $this->semValue = new Stmt\Finally_($this->semStack[$stackPos - (4 - 3)], $this->startAttributeStack[$stackPos - (4 - 1)] + $this->endAttributes); }, 192 => function ($stackPos) { $this->semValue = $this->semStack[$stackPos - (2 - 1)]; }, 193 => function ($stackPos) { $this->semValue = array($this->semStack[$stackPos - (1 - 1)]); }, 194 => function ($stackPos) { $this->semStack[$stackPos - (3 - 1)][] = $this->semStack[$stackPos - (3 - 3)]; $this->semValue = $this->semStack[$stackPos - (3 - 1)]; }, 195 => function ($stackPos) { $this->semValue = \false; }, 196 => function ($stackPos) { $this->semValue = \true; }, 197 => function ($stackPos) { $this->semValue = \false; }, 198 => function ($stackPos) { $this->semValue = \true; }, 199 => function ($stackPos) { $this->semValue = \false; }, 200 => function ($stackPos) { $this->semValue = \true; }, 201 => function ($stackPos) { $this->semValue = $this->semStack[$stackPos - (3 - 2)]; }, 202 => function ($stackPos) { $this->semValue = []; }, 203 => function ($stackPos) { $this->semValue = $this->semStack[$stackPos - (1 - 1)]; }, 204 => function ($stackPos) { $this->semValue = new Node\Identifier($this->semStack[$stackPos - (1 - 1)], $this->startAttributeStack[$stackPos - (1 - 1)] + $this->endAttributes); }, 205 => function ($stackPos) { $this->semValue = new Stmt\Function_($this->semStack[$stackPos - (8 - 3)], ['byRef' => $this->semStack[$stackPos - (8 - 2)], 'params' => $this->semStack[$stackPos - (8 - 5)], 'returnType' => $this->semStack[$stackPos - (8 - 7)], 'stmts' => $this->semStack[$stackPos - (8 - 8)], 'attrGroups' => []], $this->startAttributeStack[$stackPos - (8 - 1)] + $this->endAttributes); }, 206 => function ($stackPos) { $this->semValue = new Stmt\Function_($this->semStack[$stackPos - (9 - 4)], ['byRef' => $this->semStack[$stackPos - (9 - 3)], 'params' => $this->semStack[$stackPos - (9 - 6)], 'returnType' => $this->semStack[$stackPos - (9 - 8)], 'stmts' => $this->semStack[$stackPos - (9 - 9)], 'attrGroups' => $this->semStack[$stackPos - (9 - 1)]], $this->startAttributeStack[$stackPos - (9 - 1)] + $this->endAttributes); }, 207 => function ($stackPos) { $this->semValue = new Stmt\Class_($this->semStack[$stackPos - (7 - 2)], ['type' => $this->semStack[$stackPos - (7 - 1)], 'extends' => $this->semStack[$stackPos - (7 - 3)], 'implements' => $this->semStack[$stackPos - (7 - 4)], 'stmts' => $this->semStack[$stackPos - (7 - 6)], 'attrGroups' => []], $this->startAttributeStack[$stackPos - (7 - 1)] + $this->endAttributes); $this->checkClass($this->semValue, $stackPos - (7 - 2)); }, 208 => function ($stackPos) { $this->semValue = new Stmt\Class_($this->semStack[$stackPos - (8 - 3)], ['type' => $this->semStack[$stackPos - (8 - 2)], 'extends' => $this->semStack[$stackPos - (8 - 4)], 'implements' => $this->semStack[$stackPos - (8 - 5)], 'stmts' => $this->semStack[$stackPos - (8 - 7)], 'attrGroups' => $this->semStack[$stackPos - (8 - 1)]], $this->startAttributeStack[$stackPos - (8 - 1)] + $this->endAttributes); $this->checkClass($this->semValue, $stackPos - (8 - 3)); }, 209 => function ($stackPos) { $this->semValue = new Stmt\Interface_($this->semStack[$stackPos - (7 - 3)], ['extends' => $this->semStack[$stackPos - (7 - 4)], 'stmts' => $this->semStack[$stackPos - (7 - 6)], 'attrGroups' => $this->semStack[$stackPos - (7 - 1)]], $this->startAttributeStack[$stackPos - (7 - 1)] + $this->endAttributes); $this->checkInterface($this->semValue, $stackPos - (7 - 3)); }, 210 => function ($stackPos) { $this->semValue = new Stmt\Trait_($this->semStack[$stackPos - (6 - 3)], ['stmts' => $this->semStack[$stackPos - (6 - 5)], 'attrGroups' => $this->semStack[$stackPos - (6 - 1)]], $this->startAttributeStack[$stackPos - (6 - 1)] + $this->endAttributes); }, 211 => function ($stackPos) { $this->semValue = new Stmt\Enum_($this->semStack[$stackPos - (8 - 3)], ['scalarType' => $this->semStack[$stackPos - (8 - 4)], 'implements' => $this->semStack[$stackPos - (8 - 5)], 'stmts' => $this->semStack[$stackPos - (8 - 7)], 'attrGroups' => $this->semStack[$stackPos - (8 - 1)]], $this->startAttributeStack[$stackPos - (8 - 1)] + $this->endAttributes); $this->checkEnum($this->semValue, $stackPos - (8 - 3)); }, 212 => function ($stackPos) { $this->semValue = null; }, 213 => function ($stackPos) { $this->semValue = $this->semStack[$stackPos - (2 - 2)]; }, 214 => function ($stackPos) { $this->semValue = null; }, 215 => function ($stackPos) { $this->semValue = $this->semStack[$stackPos - (2 - 2)]; }, 216 => function ($stackPos) { $this->semValue = 0; }, 217 => function ($stackPos) { $this->semValue = $this->semStack[$stackPos - (2 - 1)]; }, 218 => function ($stackPos) { $this->semValue = $this->semStack[$stackPos - (1 - 1)]; }, 219 => function ($stackPos) { $this->checkClassModifier($this->semStack[$stackPos - (2 - 1)], $this->semStack[$stackPos - (2 - 2)], $stackPos - (2 - 2)); $this->semValue = $this->semStack[$stackPos - (2 - 1)] | $this->semStack[$stackPos - (2 - 2)]; }, 220 => function ($stackPos) { $this->semValue = Stmt\Class_::MODIFIER_ABSTRACT; }, 221 => function ($stackPos) { $this->semValue = Stmt\Class_::MODIFIER_FINAL; }, 222 => function ($stackPos) { $this->semValue = Stmt\Class_::MODIFIER_READONLY; }, 223 => function ($stackPos) { $this->semValue = null; }, 224 => function ($stackPos) { $this->semValue = $this->semStack[$stackPos - (2 - 2)]; }, 225 => function ($stackPos) { $this->semValue = array(); }, 226 => function ($stackPos) { $this->semValue = $this->semStack[$stackPos - (2 - 2)]; }, 227 => function ($stackPos) { $this->semValue = array(); }, 228 => function ($stackPos) { $this->semValue = $this->semStack[$stackPos - (2 - 2)]; }, 229 => function ($stackPos) { $this->semValue = $this->semStack[$stackPos - (2 - 1)]; }, 230 => function ($stackPos) { $this->semValue = array($this->semStack[$stackPos - (1 - 1)]); }, 231 => function ($stackPos) { $this->semStack[$stackPos - (3 - 1)][] = $this->semStack[$stackPos - (3 - 3)]; $this->semValue = $this->semStack[$stackPos - (3 - 1)]; }, 232 => function ($stackPos) { $this->semValue = \is_array($this->semStack[$stackPos - (1 - 1)]) ? $this->semStack[$stackPos - (1 - 1)] : array($this->semStack[$stackPos - (1 - 1)]); }, 233 => function ($stackPos) { $this->semValue = $this->semStack[$stackPos - (4 - 2)]; }, 234 => function ($stackPos) { $this->semValue = \is_array($this->semStack[$stackPos - (1 - 1)]) ? $this->semStack[$stackPos - (1 - 1)] : array($this->semStack[$stackPos - (1 - 1)]); }, 235 => function ($stackPos) { $this->semValue = $this->semStack[$stackPos - (4 - 2)]; }, 236 => function ($stackPos) { $this->semValue = \is_array($this->semStack[$stackPos - (1 - 1)]) ? $this->semStack[$stackPos - (1 - 1)] : array($this->semStack[$stackPos - (1 - 1)]); }, 237 => function ($stackPos) { $this->semValue = null; }, 238 => function ($stackPos) { $this->semValue = $this->semStack[$stackPos - (4 - 2)]; }, 239 => function ($stackPos) { $this->semValue = $this->semStack[$stackPos - (2 - 1)]; }, 240 => function ($stackPos) { $this->semValue = array($this->semStack[$stackPos - (1 - 1)]); }, 241 => function ($stackPos) { $this->semStack[$stackPos - (3 - 1)][] = $this->semStack[$stackPos - (3 - 3)]; $this->semValue = $this->semStack[$stackPos - (3 - 1)]; }, 242 => function ($stackPos) { $this->semValue = new Stmt\DeclareDeclare($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); }, 243 => function ($stackPos) { $this->semValue = $this->semStack[$stackPos - (3 - 2)]; }, 244 => function ($stackPos) { $this->semValue = $this->semStack[$stackPos - (4 - 3)]; }, 245 => function ($stackPos) { $this->semValue = $this->semStack[$stackPos - (4 - 2)]; }, 246 => function ($stackPos) { $this->semValue = $this->semStack[$stackPos - (5 - 3)]; }, 247 => function ($stackPos) { $this->semValue = array(); }, 248 => function ($stackPos) { $this->semStack[$stackPos - (2 - 1)][] = $this->semStack[$stackPos - (2 - 2)]; $this->semValue = $this->semStack[$stackPos - (2 - 1)]; }, 249 => function ($stackPos) { $this->semValue = new Stmt\Case_($this->semStack[$stackPos - (4 - 2)], $this->semStack[$stackPos - (4 - 4)], $this->startAttributeStack[$stackPos - (4 - 1)] + $this->endAttributes); }, 250 => function ($stackPos) { $this->semValue = new Stmt\Case_(null, $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); }, 251 => function ($stackPos) { $this->semValue = $this->semStack[$stackPos]; }, 252 => function ($stackPos) { $this->semValue = $this->semStack[$stackPos]; }, 253 => function ($stackPos) { $this->semValue = new Expr\Match_($this->semStack[$stackPos - (7 - 3)], $this->semStack[$stackPos - (7 - 6)], $this->startAttributeStack[$stackPos - (7 - 1)] + $this->endAttributes); }, 254 => function ($stackPos) { $this->semValue = []; }, 255 => function ($stackPos) { $this->semValue = $this->semStack[$stackPos - (2 - 1)]; }, 256 => function ($stackPos) { $this->semValue = array($this->semStack[$stackPos - (1 - 1)]); }, 257 => function ($stackPos) { $this->semStack[$stackPos - (3 - 1)][] = $this->semStack[$stackPos - (3 - 3)]; $this->semValue = $this->semStack[$stackPos - (3 - 1)]; }, 258 => function ($stackPos) { $this->semValue = new Node\MatchArm($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); }, 259 => function ($stackPos) { $this->semValue = new Node\MatchArm(null, $this->semStack[$stackPos - (4 - 4)], $this->startAttributeStack[$stackPos - (4 - 1)] + $this->endAttributes); }, 260 => function ($stackPos) { $this->semValue = \is_array($this->semStack[$stackPos - (1 - 1)]) ? $this->semStack[$stackPos - (1 - 1)] : array($this->semStack[$stackPos - (1 - 1)]); }, 261 => function ($stackPos) { $this->semValue = $this->semStack[$stackPos - (4 - 2)]; }, 262 => function ($stackPos) { $this->semValue = array(); }, 263 => function ($stackPos) { $this->semStack[$stackPos - (2 - 1)][] = $this->semStack[$stackPos - (2 - 2)]; $this->semValue = $this->semStack[$stackPos - (2 - 1)]; }, 264 => function ($stackPos) { $this->semValue = new Stmt\ElseIf_($this->semStack[$stackPos - (5 - 3)], \is_array($this->semStack[$stackPos - (5 - 5)]) ? $this->semStack[$stackPos - (5 - 5)] : array($this->semStack[$stackPos - (5 - 5)]), $this->startAttributeStack[$stackPos - (5 - 1)] + $this->endAttributes); }, 265 => function ($stackPos) { $this->semValue = array(); }, 266 => function ($stackPos) { $this->semStack[$stackPos - (2 - 1)][] = $this->semStack[$stackPos - (2 - 2)]; $this->semValue = $this->semStack[$stackPos - (2 - 1)]; }, 267 => function ($stackPos) { $this->semValue = new Stmt\ElseIf_($this->semStack[$stackPos - (6 - 3)], $this->semStack[$stackPos - (6 - 6)], $this->startAttributeStack[$stackPos - (6 - 1)] + $this->endAttributes); $this->fixupAlternativeElse($this->semValue); }, 268 => function ($stackPos) { $this->semValue = null; }, 269 => function ($stackPos) { $this->semValue = new Stmt\Else_(\is_array($this->semStack[$stackPos - (2 - 2)]) ? $this->semStack[$stackPos - (2 - 2)] : array($this->semStack[$stackPos - (2 - 2)]), $this->startAttributeStack[$stackPos - (2 - 1)] + $this->endAttributes); }, 270 => function ($stackPos) { $this->semValue = null; }, 271 => function ($stackPos) { $this->semValue = new Stmt\Else_($this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); $this->fixupAlternativeElse($this->semValue); }, 272 => function ($stackPos) { $this->semValue = array($this->semStack[$stackPos - (1 - 1)], \false); }, 273 => function ($stackPos) { $this->semValue = array($this->semStack[$stackPos - (2 - 2)], \true); }, 274 => function ($stackPos) { $this->semValue = array($this->semStack[$stackPos - (1 - 1)], \false); }, 275 => function ($stackPos) { $this->semValue = array($this->semStack[$stackPos - (1 - 1)], \false); }, 276 => function ($stackPos) { $this->semValue = $this->semStack[$stackPos - (2 - 1)]; }, 277 => function ($stackPos) { $this->semValue = array(); }, 278 => function ($stackPos) { $this->semValue = array($this->semStack[$stackPos - (1 - 1)]); }, 279 => function ($stackPos) { $this->semStack[$stackPos - (3 - 1)][] = $this->semStack[$stackPos - (3 - 3)]; $this->semValue = $this->semStack[$stackPos - (3 - 1)]; }, 280 => function ($stackPos) { $this->semValue = 0; }, 281 => function ($stackPos) { $this->checkModifier($this->semStack[$stackPos - (2 - 1)], $this->semStack[$stackPos - (2 - 2)], $stackPos - (2 - 2)); $this->semValue = $this->semStack[$stackPos - (2 - 1)] | $this->semStack[$stackPos - (2 - 2)]; }, 282 => function ($stackPos) { $this->semValue = Stmt\Class_::MODIFIER_PUBLIC; }, 283 => function ($stackPos) { $this->semValue = Stmt\Class_::MODIFIER_PROTECTED; }, 284 => function ($stackPos) { $this->semValue = Stmt\Class_::MODIFIER_PRIVATE; }, 285 => function ($stackPos) { $this->semValue = Stmt\Class_::MODIFIER_READONLY; }, 286 => function ($stackPos) { $this->semValue = new Node\Param($this->semStack[$stackPos - (6 - 6)], null, $this->semStack[$stackPos - (6 - 3)], $this->semStack[$stackPos - (6 - 4)], $this->semStack[$stackPos - (6 - 5)], $this->startAttributeStack[$stackPos - (6 - 1)] + $this->endAttributes, $this->semStack[$stackPos - (6 - 2)], $this->semStack[$stackPos - (6 - 1)]); $this->checkParam($this->semValue); }, 287 => function ($stackPos) { $this->semValue = new Node\Param($this->semStack[$stackPos - (8 - 6)], $this->semStack[$stackPos - (8 - 8)], $this->semStack[$stackPos - (8 - 3)], $this->semStack[$stackPos - (8 - 4)], $this->semStack[$stackPos - (8 - 5)], $this->startAttributeStack[$stackPos - (8 - 1)] + $this->endAttributes, $this->semStack[$stackPos - (8 - 2)], $this->semStack[$stackPos - (8 - 1)]); $this->checkParam($this->semValue); }, 288 => function ($stackPos) { $this->semValue = new Node\Param(new Expr\Error($this->startAttributeStack[$stackPos - (6 - 1)] + $this->endAttributes), null, $this->semStack[$stackPos - (6 - 3)], $this->semStack[$stackPos - (6 - 4)], $this->semStack[$stackPos - (6 - 5)], $this->startAttributeStack[$stackPos - (6 - 1)] + $this->endAttributes, $this->semStack[$stackPos - (6 - 2)], $this->semStack[$stackPos - (6 - 1)]); }, 289 => function ($stackPos) { $this->semValue = $this->semStack[$stackPos - (1 - 1)]; }, 290 => function ($stackPos) { $this->semValue = new Node\NullableType($this->semStack[$stackPos - (2 - 2)], $this->startAttributeStack[$stackPos - (2 - 1)] + $this->endAttributes); }, 291 => function ($stackPos) { $this->semValue = new Node\UnionType($this->semStack[$stackPos - (1 - 1)], $this->startAttributeStack[$stackPos - (1 - 1)] + $this->endAttributes); }, 292 => function ($stackPos) { $this->semValue = $this->semStack[$stackPos - (1 - 1)]; }, 293 => function ($stackPos) { $this->semValue = $this->semStack[$stackPos - (1 - 1)]; }, 294 => function ($stackPos) { $this->semValue = new Node\Name('static', $this->startAttributeStack[$stackPos - (1 - 1)] + $this->endAttributes); }, 295 => function ($stackPos) { $this->semValue = $this->handleBuiltinTypes($this->semStack[$stackPos - (1 - 1)]); }, 296 => function ($stackPos) { $this->semValue = new Node\Identifier('array', $this->startAttributeStack[$stackPos - (1 - 1)] + $this->endAttributes); }, 297 => function ($stackPos) { $this->semValue = new Node\Identifier('callable', $this->startAttributeStack[$stackPos - (1 - 1)] + $this->endAttributes); }, 298 => function ($stackPos) { $this->semValue = $this->semStack[$stackPos - (1 - 1)]; }, 299 => function ($stackPos) { $this->semValue = $this->semStack[$stackPos - (3 - 2)]; }, 300 => function ($stackPos) { $this->semValue = array($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)]); }, 301 => function ($stackPos) { $this->semStack[$stackPos - (3 - 1)][] = $this->semStack[$stackPos - (3 - 3)]; $this->semValue = $this->semStack[$stackPos - (3 - 1)]; }, 302 => function ($stackPos) { $this->semValue = $this->semStack[$stackPos - (1 - 1)]; }, 303 => function ($stackPos) { $this->semValue = $this->semStack[$stackPos - (3 - 2)]; }, 304 => function ($stackPos) { $this->semValue = array($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)]); }, 305 => function ($stackPos) { $this->semStack[$stackPos - (3 - 1)][] = $this->semStack[$stackPos - (3 - 3)]; $this->semValue = $this->semStack[$stackPos - (3 - 1)]; }, 306 => function ($stackPos) { $this->semValue = array($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)]); }, 307 => function ($stackPos) { $this->semStack[$stackPos - (3 - 1)][] = $this->semStack[$stackPos - (3 - 3)]; $this->semValue = $this->semStack[$stackPos - (3 - 1)]; }, 308 => function ($stackPos) { $this->semValue = new Node\IntersectionType($this->semStack[$stackPos - (1 - 1)], $this->startAttributeStack[$stackPos - (1 - 1)] + $this->endAttributes); }, 309 => function ($stackPos) { $this->semValue = array($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)]); }, 310 => function ($stackPos) { $this->semStack[$stackPos - (3 - 1)][] = $this->semStack[$stackPos - (3 - 3)]; $this->semValue = $this->semStack[$stackPos - (3 - 1)]; }, 311 => function ($stackPos) { $this->semValue = new Node\IntersectionType($this->semStack[$stackPos - (1 - 1)], $this->startAttributeStack[$stackPos - (1 - 1)] + $this->endAttributes); }, 312 => function ($stackPos) { $this->semValue = $this->semStack[$stackPos - (1 - 1)]; }, 313 => function ($stackPos) { $this->semValue = new Node\NullableType($this->semStack[$stackPos - (2 - 2)], $this->startAttributeStack[$stackPos - (2 - 1)] + $this->endAttributes); }, 314 => function ($stackPos) { $this->semValue = new Node\UnionType($this->semStack[$stackPos - (1 - 1)], $this->startAttributeStack[$stackPos - (1 - 1)] + $this->endAttributes); }, 315 => function ($stackPos) { $this->semValue = $this->semStack[$stackPos - (1 - 1)]; }, 316 => function ($stackPos) { $this->semValue = null; }, 317 => function ($stackPos) { $this->semValue = $this->semStack[$stackPos - (1 - 1)]; }, 318 => function ($stackPos) { $this->semValue = null; }, 319 => function ($stackPos) { $this->semValue = $this->semStack[$stackPos - (2 - 2)]; }, 320 => function ($stackPos) { $this->semValue = null; }, 321 => function ($stackPos) { $this->semValue = array(); }, 322 => function ($stackPos) { $this->semValue = $this->semStack[$stackPos - (4 - 2)]; }, 323 => function ($stackPos) { $this->semValue = array($this->semStack[$stackPos - (3 - 2)]); }, 324 => function ($stackPos) { $this->semValue = new Node\VariadicPlaceholder($this->startAttributeStack[$stackPos - (1 - 1)] + $this->endAttributes); }, 325 => function ($stackPos) { $this->semValue = array($this->semStack[$stackPos - (1 - 1)]); }, 326 => function ($stackPos) { $this->semStack[$stackPos - (3 - 1)][] = $this->semStack[$stackPos - (3 - 3)]; $this->semValue = $this->semStack[$stackPos - (3 - 1)]; }, 327 => function ($stackPos) { $this->semValue = new Node\Arg($this->semStack[$stackPos - (1 - 1)], \false, \false, $this->startAttributeStack[$stackPos - (1 - 1)] + $this->endAttributes); }, 328 => function ($stackPos) { $this->semValue = new Node\Arg($this->semStack[$stackPos - (2 - 2)], \true, \false, $this->startAttributeStack[$stackPos - (2 - 1)] + $this->endAttributes); }, 329 => function ($stackPos) { $this->semValue = new Node\Arg($this->semStack[$stackPos - (2 - 2)], \false, \true, $this->startAttributeStack[$stackPos - (2 - 1)] + $this->endAttributes); }, 330 => function ($stackPos) { $this->semValue = new Node\Arg($this->semStack[$stackPos - (3 - 3)], \false, \false, $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes, $this->semStack[$stackPos - (3 - 1)]); }, 331 => function ($stackPos) { $this->semValue = $this->semStack[$stackPos - (2 - 1)]; }, 332 => function ($stackPos) { $this->semStack[$stackPos - (3 - 1)][] = $this->semStack[$stackPos - (3 - 3)]; $this->semValue = $this->semStack[$stackPos - (3 - 1)]; }, 333 => function ($stackPos) { $this->semValue = array($this->semStack[$stackPos - (1 - 1)]); }, 334 => function ($stackPos) { $this->semValue = $this->semStack[$stackPos - (1 - 1)]; }, 335 => function ($stackPos) { $this->semValue = $this->semStack[$stackPos - (2 - 1)]; }, 336 => function ($stackPos) { $this->semStack[$stackPos - (3 - 1)][] = $this->semStack[$stackPos - (3 - 3)]; $this->semValue = $this->semStack[$stackPos - (3 - 1)]; }, 337 => function ($stackPos) { $this->semValue = array($this->semStack[$stackPos - (1 - 1)]); }, 338 => function ($stackPos) { $this->semValue = new Stmt\StaticVar($this->semStack[$stackPos - (1 - 1)], null, $this->startAttributeStack[$stackPos - (1 - 1)] + $this->endAttributes); }, 339 => function ($stackPos) { $this->semValue = new Stmt\StaticVar($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); }, 340 => function ($stackPos) { if ($this->semStack[$stackPos - (2 - 2)] !== null) { $this->semStack[$stackPos - (2 - 1)][] = $this->semStack[$stackPos - (2 - 2)]; $this->semValue = $this->semStack[$stackPos - (2 - 1)]; } else { $this->semValue = $this->semStack[$stackPos - (2 - 1)]; } }, 341 => function ($stackPos) { $this->semValue = array(); }, 342 => function ($stackPos) { $startAttributes = $this->lookaheadStartAttributes; if (isset($startAttributes['comments'])) { $nop = new Stmt\Nop($this->createCommentNopAttributes($startAttributes['comments'])); } else { $nop = null; } if ($nop !== null) { $this->semStack[$stackPos - (1 - 1)][] = $nop; } $this->semValue = $this->semStack[$stackPos - (1 - 1)]; }, 343 => function ($stackPos) { $this->semValue = new Stmt\Property($this->semStack[$stackPos - (5 - 2)], $this->semStack[$stackPos - (5 - 4)], $this->startAttributeStack[$stackPos - (5 - 1)] + $this->endAttributes, $this->semStack[$stackPos - (5 - 3)], $this->semStack[$stackPos - (5 - 1)]); $this->checkProperty($this->semValue, $stackPos - (5 - 2)); }, 344 => function ($stackPos) { $this->semValue = new Stmt\ClassConst($this->semStack[$stackPos - (5 - 4)], $this->semStack[$stackPos - (5 - 2)], $this->startAttributeStack[$stackPos - (5 - 1)] + $this->endAttributes, $this->semStack[$stackPos - (5 - 1)]); $this->checkClassConst($this->semValue, $stackPos - (5 - 2)); }, 345 => function ($stackPos) { $this->semValue = new Stmt\ClassConst($this->semStack[$stackPos - (6 - 5)], $this->semStack[$stackPos - (6 - 2)], $this->startAttributeStack[$stackPos - (6 - 1)] + $this->endAttributes, $this->semStack[$stackPos - (6 - 1)], $this->semStack[$stackPos - (6 - 4)]); $this->checkClassConst($this->semValue, $stackPos - (6 - 2)); }, 346 => function ($stackPos) { $this->semValue = new Stmt\ClassMethod($this->semStack[$stackPos - (10 - 5)], ['type' => $this->semStack[$stackPos - (10 - 2)], 'byRef' => $this->semStack[$stackPos - (10 - 4)], 'params' => $this->semStack[$stackPos - (10 - 7)], 'returnType' => $this->semStack[$stackPos - (10 - 9)], 'stmts' => $this->semStack[$stackPos - (10 - 10)], 'attrGroups' => $this->semStack[$stackPos - (10 - 1)]], $this->startAttributeStack[$stackPos - (10 - 1)] + $this->endAttributes); $this->checkClassMethod($this->semValue, $stackPos - (10 - 2)); }, 347 => function ($stackPos) { $this->semValue = new Stmt\TraitUse($this->semStack[$stackPos - (3 - 2)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); }, 348 => function ($stackPos) { $this->semValue = new Stmt\EnumCase($this->semStack[$stackPos - (5 - 3)], $this->semStack[$stackPos - (5 - 4)], $this->semStack[$stackPos - (5 - 1)], $this->startAttributeStack[$stackPos - (5 - 1)] + $this->endAttributes); }, 349 => function ($stackPos) { $this->semValue = null; /* will be skipped */ }, 350 => function ($stackPos) { $this->semValue = array(); }, 351 => function ($stackPos) { $this->semValue = $this->semStack[$stackPos - (3 - 2)]; }, 352 => function ($stackPos) { $this->semValue = array(); }, 353 => function ($stackPos) { $this->semStack[$stackPos - (2 - 1)][] = $this->semStack[$stackPos - (2 - 2)]; $this->semValue = $this->semStack[$stackPos - (2 - 1)]; }, 354 => function ($stackPos) { $this->semValue = new Stmt\TraitUseAdaptation\Precedence($this->semStack[$stackPos - (4 - 1)][0], $this->semStack[$stackPos - (4 - 1)][1], $this->semStack[$stackPos - (4 - 3)], $this->startAttributeStack[$stackPos - (4 - 1)] + $this->endAttributes); }, 355 => function ($stackPos) { $this->semValue = new Stmt\TraitUseAdaptation\Alias($this->semStack[$stackPos - (5 - 1)][0], $this->semStack[$stackPos - (5 - 1)][1], $this->semStack[$stackPos - (5 - 3)], $this->semStack[$stackPos - (5 - 4)], $this->startAttributeStack[$stackPos - (5 - 1)] + $this->endAttributes); }, 356 => function ($stackPos) { $this->semValue = new Stmt\TraitUseAdaptation\Alias($this->semStack[$stackPos - (4 - 1)][0], $this->semStack[$stackPos - (4 - 1)][1], $this->semStack[$stackPos - (4 - 3)], null, $this->startAttributeStack[$stackPos - (4 - 1)] + $this->endAttributes); }, 357 => function ($stackPos) { $this->semValue = new Stmt\TraitUseAdaptation\Alias($this->semStack[$stackPos - (4 - 1)][0], $this->semStack[$stackPos - (4 - 1)][1], null, $this->semStack[$stackPos - (4 - 3)], $this->startAttributeStack[$stackPos - (4 - 1)] + $this->endAttributes); }, 358 => function ($stackPos) { $this->semValue = new Stmt\TraitUseAdaptation\Alias($this->semStack[$stackPos - (4 - 1)][0], $this->semStack[$stackPos - (4 - 1)][1], null, $this->semStack[$stackPos - (4 - 3)], $this->startAttributeStack[$stackPos - (4 - 1)] + $this->endAttributes); }, 359 => function ($stackPos) { $this->semValue = array($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)]); }, 360 => function ($stackPos) { $this->semValue = $this->semStack[$stackPos - (1 - 1)]; }, 361 => function ($stackPos) { $this->semValue = array(null, $this->semStack[$stackPos - (1 - 1)]); }, 362 => function ($stackPos) { $this->semValue = null; }, 363 => function ($stackPos) { $this->semValue = $this->semStack[$stackPos - (1 - 1)]; }, 364 => function ($stackPos) { $this->semValue = $this->semStack[$stackPos - (1 - 1)]; }, 365 => function ($stackPos) { $this->semValue = 0; }, 366 => function ($stackPos) { $this->semValue = 0; }, 367 => function ($stackPos) { $this->semValue = $this->semStack[$stackPos - (1 - 1)]; }, 368 => function ($stackPos) { $this->semValue = $this->semStack[$stackPos - (1 - 1)]; }, 369 => function ($stackPos) { $this->checkModifier($this->semStack[$stackPos - (2 - 1)], $this->semStack[$stackPos - (2 - 2)], $stackPos - (2 - 2)); $this->semValue = $this->semStack[$stackPos - (2 - 1)] | $this->semStack[$stackPos - (2 - 2)]; }, 370 => function ($stackPos) { $this->semValue = Stmt\Class_::MODIFIER_PUBLIC; }, 371 => function ($stackPos) { $this->semValue = Stmt\Class_::MODIFIER_PROTECTED; }, 372 => function ($stackPos) { $this->semValue = Stmt\Class_::MODIFIER_PRIVATE; }, 373 => function ($stackPos) { $this->semValue = Stmt\Class_::MODIFIER_STATIC; }, 374 => function ($stackPos) { $this->semValue = Stmt\Class_::MODIFIER_ABSTRACT; }, 375 => function ($stackPos) { $this->semValue = Stmt\Class_::MODIFIER_FINAL; }, 376 => function ($stackPos) { $this->semValue = Stmt\Class_::MODIFIER_READONLY; }, 377 => function ($stackPos) { $this->semValue = $this->semStack[$stackPos - (2 - 1)]; }, 378 => function ($stackPos) { $this->semValue = array($this->semStack[$stackPos - (1 - 1)]); }, 379 => function ($stackPos) { $this->semStack[$stackPos - (3 - 1)][] = $this->semStack[$stackPos - (3 - 3)]; $this->semValue = $this->semStack[$stackPos - (3 - 1)]; }, 380 => function ($stackPos) { $this->semValue = new Node\VarLikeIdentifier(\substr($this->semStack[$stackPos - (1 - 1)], 1), $this->startAttributeStack[$stackPos - (1 - 1)] + $this->endAttributes); }, 381 => function ($stackPos) { $this->semValue = new Stmt\PropertyProperty($this->semStack[$stackPos - (1 - 1)], null, $this->startAttributeStack[$stackPos - (1 - 1)] + $this->endAttributes); }, 382 => function ($stackPos) { $this->semValue = new Stmt\PropertyProperty($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); }, 383 => function ($stackPos) { $this->semValue = $this->semStack[$stackPos - (2 - 1)]; }, 384 => function ($stackPos) { $this->semValue = $this->semStack[$stackPos - (2 - 1)]; }, 385 => function ($stackPos) { $this->semStack[$stackPos - (3 - 1)][] = $this->semStack[$stackPos - (3 - 3)]; $this->semValue = $this->semStack[$stackPos - (3 - 1)]; }, 386 => function ($stackPos) { $this->semValue = array($this->semStack[$stackPos - (1 - 1)]); }, 387 => function ($stackPos) { $this->semValue = array(); }, 388 => function ($stackPos) { $this->semValue = $this->semStack[$stackPos - (1 - 1)]; }, 389 => function ($stackPos) { $this->semValue = $this->semStack[$stackPos - (1 - 1)]; }, 390 => function ($stackPos) { $this->semValue = new Expr\Assign($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); }, 391 => function ($stackPos) { $this->semValue = new Expr\Assign($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); }, 392 => function ($stackPos) { $this->semValue = new Expr\Assign($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); }, 393 => function ($stackPos) { $this->semValue = new Expr\AssignRef($this->semStack[$stackPos - (4 - 1)], $this->semStack[$stackPos - (4 - 4)], $this->startAttributeStack[$stackPos - (4 - 1)] + $this->endAttributes); }, 394 => function ($stackPos) { $this->semValue = $this->semStack[$stackPos - (1 - 1)]; }, 395 => function ($stackPos) { $this->semValue = $this->semStack[$stackPos - (1 - 1)]; }, 396 => function ($stackPos) { $this->semValue = new Expr\Clone_($this->semStack[$stackPos - (2 - 2)], $this->startAttributeStack[$stackPos - (2 - 1)] + $this->endAttributes); }, 397 => function ($stackPos) { $this->semValue = new Expr\AssignOp\Plus($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); }, 398 => function ($stackPos) { $this->semValue = new Expr\AssignOp\Minus($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); }, 399 => function ($stackPos) { $this->semValue = new Expr\AssignOp\Mul($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); }, 400 => function ($stackPos) { $this->semValue = new Expr\AssignOp\Div($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); }, 401 => function ($stackPos) { $this->semValue = new Expr\AssignOp\Concat($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); }, 402 => function ($stackPos) { $this->semValue = new Expr\AssignOp\Mod($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); }, 403 => function ($stackPos) { $this->semValue = new Expr\AssignOp\BitwiseAnd($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); }, 404 => function ($stackPos) { $this->semValue = new Expr\AssignOp\BitwiseOr($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); }, 405 => function ($stackPos) { $this->semValue = new Expr\AssignOp\BitwiseXor($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); }, 406 => function ($stackPos) { $this->semValue = new Expr\AssignOp\ShiftLeft($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); }, 407 => function ($stackPos) { $this->semValue = new Expr\AssignOp\ShiftRight($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); }, 408 => function ($stackPos) { $this->semValue = new Expr\AssignOp\Pow($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); }, 409 => function ($stackPos) { $this->semValue = new Expr\AssignOp\Coalesce($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); }, 410 => function ($stackPos) { $this->semValue = new Expr\PostInc($this->semStack[$stackPos - (2 - 1)], $this->startAttributeStack[$stackPos - (2 - 1)] + $this->endAttributes); }, 411 => function ($stackPos) { $this->semValue = new Expr\PreInc($this->semStack[$stackPos - (2 - 2)], $this->startAttributeStack[$stackPos - (2 - 1)] + $this->endAttributes); }, 412 => function ($stackPos) { $this->semValue = new Expr\PostDec($this->semStack[$stackPos - (2 - 1)], $this->startAttributeStack[$stackPos - (2 - 1)] + $this->endAttributes); }, 413 => function ($stackPos) { $this->semValue = new Expr\PreDec($this->semStack[$stackPos - (2 - 2)], $this->startAttributeStack[$stackPos - (2 - 1)] + $this->endAttributes); }, 414 => function ($stackPos) { $this->semValue = new Expr\BinaryOp\BooleanOr($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); }, 415 => function ($stackPos) { $this->semValue = new Expr\BinaryOp\BooleanAnd($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); }, 416 => function ($stackPos) { $this->semValue = new Expr\BinaryOp\LogicalOr($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); }, 417 => function ($stackPos) { $this->semValue = new Expr\BinaryOp\LogicalAnd($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); }, 418 => function ($stackPos) { $this->semValue = new Expr\BinaryOp\LogicalXor($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); }, 419 => function ($stackPos) { $this->semValue = new Expr\BinaryOp\BitwiseOr($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); }, 420 => function ($stackPos) { $this->semValue = new Expr\BinaryOp\BitwiseAnd($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); }, 421 => function ($stackPos) { $this->semValue = new Expr\BinaryOp\BitwiseAnd($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); }, 422 => function ($stackPos) { $this->semValue = new Expr\BinaryOp\BitwiseXor($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); }, 423 => function ($stackPos) { $this->semValue = new Expr\BinaryOp\Concat($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); }, 424 => function ($stackPos) { $this->semValue = new Expr\BinaryOp\Plus($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); }, 425 => function ($stackPos) { $this->semValue = new Expr\BinaryOp\Minus($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); }, 426 => function ($stackPos) { $this->semValue = new Expr\BinaryOp\Mul($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); }, 427 => function ($stackPos) { $this->semValue = new Expr\BinaryOp\Div($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); }, 428 => function ($stackPos) { $this->semValue = new Expr\BinaryOp\Mod($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); }, 429 => function ($stackPos) { $this->semValue = new Expr\BinaryOp\ShiftLeft($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); }, 430 => function ($stackPos) { $this->semValue = new Expr\BinaryOp\ShiftRight($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); }, 431 => function ($stackPos) { $this->semValue = new Expr\BinaryOp\Pow($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); }, 432 => function ($stackPos) { $this->semValue = new Expr\UnaryPlus($this->semStack[$stackPos - (2 - 2)], $this->startAttributeStack[$stackPos - (2 - 1)] + $this->endAttributes); }, 433 => function ($stackPos) { $this->semValue = new Expr\UnaryMinus($this->semStack[$stackPos - (2 - 2)], $this->startAttributeStack[$stackPos - (2 - 1)] + $this->endAttributes); }, 434 => function ($stackPos) { $this->semValue = new Expr\BooleanNot($this->semStack[$stackPos - (2 - 2)], $this->startAttributeStack[$stackPos - (2 - 1)] + $this->endAttributes); }, 435 => function ($stackPos) { $this->semValue = new Expr\BitwiseNot($this->semStack[$stackPos - (2 - 2)], $this->startAttributeStack[$stackPos - (2 - 1)] + $this->endAttributes); }, 436 => function ($stackPos) { $this->semValue = new Expr\BinaryOp\Identical($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); }, 437 => function ($stackPos) { $this->semValue = new Expr\BinaryOp\NotIdentical($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); }, 438 => function ($stackPos) { $this->semValue = new Expr\BinaryOp\Equal($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); }, 439 => function ($stackPos) { $this->semValue = new Expr\BinaryOp\NotEqual($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); }, 440 => function ($stackPos) { $this->semValue = new Expr\BinaryOp\Spaceship($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); }, 441 => function ($stackPos) { $this->semValue = new Expr\BinaryOp\Smaller($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); }, 442 => function ($stackPos) { $this->semValue = new Expr\BinaryOp\SmallerOrEqual($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); }, 443 => function ($stackPos) { $this->semValue = new Expr\BinaryOp\Greater($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); }, 444 => function ($stackPos) { $this->semValue = new Expr\BinaryOp\GreaterOrEqual($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); }, 445 => function ($stackPos) { $this->semValue = new Expr\Instanceof_($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); }, 446 => function ($stackPos) { $this->semValue = $this->semStack[$stackPos - (3 - 2)]; }, 447 => function ($stackPos) { $this->semValue = new Expr\Ternary($this->semStack[$stackPos - (5 - 1)], $this->semStack[$stackPos - (5 - 3)], $this->semStack[$stackPos - (5 - 5)], $this->startAttributeStack[$stackPos - (5 - 1)] + $this->endAttributes); }, 448 => function ($stackPos) { $this->semValue = new Expr\Ternary($this->semStack[$stackPos - (4 - 1)], null, $this->semStack[$stackPos - (4 - 4)], $this->startAttributeStack[$stackPos - (4 - 1)] + $this->endAttributes); }, 449 => function ($stackPos) { $this->semValue = new Expr\BinaryOp\Coalesce($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); }, 450 => function ($stackPos) { $this->semValue = new Expr\Isset_($this->semStack[$stackPos - (4 - 3)], $this->startAttributeStack[$stackPos - (4 - 1)] + $this->endAttributes); }, 451 => function ($stackPos) { $this->semValue = new Expr\Empty_($this->semStack[$stackPos - (4 - 3)], $this->startAttributeStack[$stackPos - (4 - 1)] + $this->endAttributes); }, 452 => function ($stackPos) { $this->semValue = new Expr\Include_($this->semStack[$stackPos - (2 - 2)], Expr\Include_::TYPE_INCLUDE, $this->startAttributeStack[$stackPos - (2 - 1)] + $this->endAttributes); }, 453 => function ($stackPos) { $this->semValue = new Expr\Include_($this->semStack[$stackPos - (2 - 2)], Expr\Include_::TYPE_INCLUDE_ONCE, $this->startAttributeStack[$stackPos - (2 - 1)] + $this->endAttributes); }, 454 => function ($stackPos) { $this->semValue = new Expr\Eval_($this->semStack[$stackPos - (4 - 3)], $this->startAttributeStack[$stackPos - (4 - 1)] + $this->endAttributes); }, 455 => function ($stackPos) { $this->semValue = new Expr\Include_($this->semStack[$stackPos - (2 - 2)], Expr\Include_::TYPE_REQUIRE, $this->startAttributeStack[$stackPos - (2 - 1)] + $this->endAttributes); }, 456 => function ($stackPos) { $this->semValue = new Expr\Include_($this->semStack[$stackPos - (2 - 2)], Expr\Include_::TYPE_REQUIRE_ONCE, $this->startAttributeStack[$stackPos - (2 - 1)] + $this->endAttributes); }, 457 => function ($stackPos) { $this->semValue = new Expr\Cast\Int_($this->semStack[$stackPos - (2 - 2)], $this->startAttributeStack[$stackPos - (2 - 1)] + $this->endAttributes); }, 458 => function ($stackPos) { $attrs = $this->startAttributeStack[$stackPos - (2 - 1)] + $this->endAttributes; $attrs['kind'] = $this->getFloatCastKind($this->semStack[$stackPos - (2 - 1)]); $this->semValue = new Expr\Cast\Double($this->semStack[$stackPos - (2 - 2)], $attrs); }, 459 => function ($stackPos) { $this->semValue = new Expr\Cast\String_($this->semStack[$stackPos - (2 - 2)], $this->startAttributeStack[$stackPos - (2 - 1)] + $this->endAttributes); }, 460 => function ($stackPos) { $this->semValue = new Expr\Cast\Array_($this->semStack[$stackPos - (2 - 2)], $this->startAttributeStack[$stackPos - (2 - 1)] + $this->endAttributes); }, 461 => function ($stackPos) { $this->semValue = new Expr\Cast\Object_($this->semStack[$stackPos - (2 - 2)], $this->startAttributeStack[$stackPos - (2 - 1)] + $this->endAttributes); }, 462 => function ($stackPos) { $this->semValue = new Expr\Cast\Bool_($this->semStack[$stackPos - (2 - 2)], $this->startAttributeStack[$stackPos - (2 - 1)] + $this->endAttributes); }, 463 => function ($stackPos) { $this->semValue = new Expr\Cast\Unset_($this->semStack[$stackPos - (2 - 2)], $this->startAttributeStack[$stackPos - (2 - 1)] + $this->endAttributes); }, 464 => function ($stackPos) { $attrs = $this->startAttributeStack[$stackPos - (2 - 1)] + $this->endAttributes; $attrs['kind'] = \strtolower($this->semStack[$stackPos - (2 - 1)]) === 'exit' ? Expr\Exit_::KIND_EXIT : Expr\Exit_::KIND_DIE; $this->semValue = new Expr\Exit_($this->semStack[$stackPos - (2 - 2)], $attrs); }, 465 => function ($stackPos) { $this->semValue = new Expr\ErrorSuppress($this->semStack[$stackPos - (2 - 2)], $this->startAttributeStack[$stackPos - (2 - 1)] + $this->endAttributes); }, 466 => function ($stackPos) { $this->semValue = $this->semStack[$stackPos - (1 - 1)]; }, 467 => function ($stackPos) { $this->semValue = new Expr\ShellExec($this->semStack[$stackPos - (3 - 2)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); }, 468 => function ($stackPos) { $this->semValue = new Expr\Print_($this->semStack[$stackPos - (2 - 2)], $this->startAttributeStack[$stackPos - (2 - 1)] + $this->endAttributes); }, 469 => function ($stackPos) { $this->semValue = new Expr\Yield_(null, null, $this->startAttributeStack[$stackPos - (1 - 1)] + $this->endAttributes); }, 470 => function ($stackPos) { $this->semValue = new Expr\Yield_($this->semStack[$stackPos - (2 - 2)], null, $this->startAttributeStack[$stackPos - (2 - 1)] + $this->endAttributes); }, 471 => function ($stackPos) { $this->semValue = new Expr\Yield_($this->semStack[$stackPos - (4 - 4)], $this->semStack[$stackPos - (4 - 2)], $this->startAttributeStack[$stackPos - (4 - 1)] + $this->endAttributes); }, 472 => function ($stackPos) { $this->semValue = new Expr\YieldFrom($this->semStack[$stackPos - (2 - 2)], $this->startAttributeStack[$stackPos - (2 - 1)] + $this->endAttributes); }, 473 => function ($stackPos) { $this->semValue = new Expr\Throw_($this->semStack[$stackPos - (2 - 2)], $this->startAttributeStack[$stackPos - (2 - 1)] + $this->endAttributes); }, 474 => function ($stackPos) { $this->semValue = new Expr\ArrowFunction(['static' => \false, 'byRef' => $this->semStack[$stackPos - (8 - 2)], 'params' => $this->semStack[$stackPos - (8 - 4)], 'returnType' => $this->semStack[$stackPos - (8 - 6)], 'expr' => $this->semStack[$stackPos - (8 - 8)], 'attrGroups' => []], $this->startAttributeStack[$stackPos - (8 - 1)] + $this->endAttributes); }, 475 => function ($stackPos) { $this->semValue = new Expr\ArrowFunction(['static' => \true, 'byRef' => $this->semStack[$stackPos - (9 - 3)], 'params' => $this->semStack[$stackPos - (9 - 5)], 'returnType' => $this->semStack[$stackPos - (9 - 7)], 'expr' => $this->semStack[$stackPos - (9 - 9)], 'attrGroups' => []], $this->startAttributeStack[$stackPos - (9 - 1)] + $this->endAttributes); }, 476 => function ($stackPos) { $this->semValue = new Expr\Closure(['static' => \false, 'byRef' => $this->semStack[$stackPos - (8 - 2)], 'params' => $this->semStack[$stackPos - (8 - 4)], 'uses' => $this->semStack[$stackPos - (8 - 6)], 'returnType' => $this->semStack[$stackPos - (8 - 7)], 'stmts' => $this->semStack[$stackPos - (8 - 8)], 'attrGroups' => []], $this->startAttributeStack[$stackPos - (8 - 1)] + $this->endAttributes); }, 477 => function ($stackPos) { $this->semValue = new Expr\Closure(['static' => \true, 'byRef' => $this->semStack[$stackPos - (9 - 3)], 'params' => $this->semStack[$stackPos - (9 - 5)], 'uses' => $this->semStack[$stackPos - (9 - 7)], 'returnType' => $this->semStack[$stackPos - (9 - 8)], 'stmts' => $this->semStack[$stackPos - (9 - 9)], 'attrGroups' => []], $this->startAttributeStack[$stackPos - (9 - 1)] + $this->endAttributes); }, 478 => function ($stackPos) { $this->semValue = new Expr\ArrowFunction(['static' => \false, 'byRef' => $this->semStack[$stackPos - (9 - 3)], 'params' => $this->semStack[$stackPos - (9 - 5)], 'returnType' => $this->semStack[$stackPos - (9 - 7)], 'expr' => $this->semStack[$stackPos - (9 - 9)], 'attrGroups' => $this->semStack[$stackPos - (9 - 1)]], $this->startAttributeStack[$stackPos - (9 - 1)] + $this->endAttributes); }, 479 => function ($stackPos) { $this->semValue = new Expr\ArrowFunction(['static' => \true, 'byRef' => $this->semStack[$stackPos - (10 - 4)], 'params' => $this->semStack[$stackPos - (10 - 6)], 'returnType' => $this->semStack[$stackPos - (10 - 8)], 'expr' => $this->semStack[$stackPos - (10 - 10)], 'attrGroups' => $this->semStack[$stackPos - (10 - 1)]], $this->startAttributeStack[$stackPos - (10 - 1)] + $this->endAttributes); }, 480 => function ($stackPos) { $this->semValue = new Expr\Closure(['static' => \false, 'byRef' => $this->semStack[$stackPos - (9 - 3)], 'params' => $this->semStack[$stackPos - (9 - 5)], 'uses' => $this->semStack[$stackPos - (9 - 7)], 'returnType' => $this->semStack[$stackPos - (9 - 8)], 'stmts' => $this->semStack[$stackPos - (9 - 9)], 'attrGroups' => $this->semStack[$stackPos - (9 - 1)]], $this->startAttributeStack[$stackPos - (9 - 1)] + $this->endAttributes); }, 481 => function ($stackPos) { $this->semValue = new Expr\Closure(['static' => \true, 'byRef' => $this->semStack[$stackPos - (10 - 4)], 'params' => $this->semStack[$stackPos - (10 - 6)], 'uses' => $this->semStack[$stackPos - (10 - 8)], 'returnType' => $this->semStack[$stackPos - (10 - 9)], 'stmts' => $this->semStack[$stackPos - (10 - 10)], 'attrGroups' => $this->semStack[$stackPos - (10 - 1)]], $this->startAttributeStack[$stackPos - (10 - 1)] + $this->endAttributes); }, 482 => function ($stackPos) { $this->semValue = array(new Stmt\Class_(null, ['type' => $this->semStack[$stackPos - (8 - 2)], 'extends' => $this->semStack[$stackPos - (8 - 4)], 'implements' => $this->semStack[$stackPos - (8 - 5)], 'stmts' => $this->semStack[$stackPos - (8 - 7)], 'attrGroups' => $this->semStack[$stackPos - (8 - 1)]], $this->startAttributeStack[$stackPos - (8 - 1)] + $this->endAttributes), $this->semStack[$stackPos - (8 - 3)]); $this->checkClass($this->semValue[0], -1); }, 483 => function ($stackPos) { $this->semValue = new Expr\New_($this->semStack[$stackPos - (3 - 2)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); }, 484 => function ($stackPos) { list($class, $ctorArgs) = $this->semStack[$stackPos - (2 - 2)]; $this->semValue = new Expr\New_($class, $ctorArgs, $this->startAttributeStack[$stackPos - (2 - 1)] + $this->endAttributes); }, 485 => function ($stackPos) { $this->semValue = array(); }, 486 => function ($stackPos) { $this->semValue = $this->semStack[$stackPos - (4 - 3)]; }, 487 => function ($stackPos) { $this->semValue = $this->semStack[$stackPos - (2 - 1)]; }, 488 => function ($stackPos) { $this->semValue = array($this->semStack[$stackPos - (1 - 1)]); }, 489 => function ($stackPos) { $this->semStack[$stackPos - (3 - 1)][] = $this->semStack[$stackPos - (3 - 3)]; $this->semValue = $this->semStack[$stackPos - (3 - 1)]; }, 490 => function ($stackPos) { $this->semValue = new Expr\ClosureUse($this->semStack[$stackPos - (2 - 2)], $this->semStack[$stackPos - (2 - 1)], $this->startAttributeStack[$stackPos - (2 - 1)] + $this->endAttributes); }, 491 => function ($stackPos) { $this->semValue = new Name($this->semStack[$stackPos - (1 - 1)], $this->startAttributeStack[$stackPos - (1 - 1)] + $this->endAttributes); }, 492 => function ($stackPos) { $this->semValue = new Expr\FuncCall($this->semStack[$stackPos - (2 - 1)], $this->semStack[$stackPos - (2 - 2)], $this->startAttributeStack[$stackPos - (2 - 1)] + $this->endAttributes); }, 493 => function ($stackPos) { $this->semValue = new Expr\FuncCall($this->semStack[$stackPos - (2 - 1)], $this->semStack[$stackPos - (2 - 2)], $this->startAttributeStack[$stackPos - (2 - 1)] + $this->endAttributes); }, 494 => function ($stackPos) { $this->semValue = new Expr\FuncCall($this->semStack[$stackPos - (2 - 1)], $this->semStack[$stackPos - (2 - 2)], $this->startAttributeStack[$stackPos - (2 - 1)] + $this->endAttributes); }, 495 => function ($stackPos) { $this->semValue = new Expr\StaticCall($this->semStack[$stackPos - (4 - 1)], $this->semStack[$stackPos - (4 - 3)], $this->semStack[$stackPos - (4 - 4)], $this->startAttributeStack[$stackPos - (4 - 1)] + $this->endAttributes); }, 496 => function ($stackPos) { $this->semValue = new Name($this->semStack[$stackPos - (1 - 1)], $this->startAttributeStack[$stackPos - (1 - 1)] + $this->endAttributes); }, 497 => function ($stackPos) { $this->semValue = $this->semStack[$stackPos - (1 - 1)]; }, 498 => function ($stackPos) { $this->semValue = new Name($this->semStack[$stackPos - (1 - 1)], $this->startAttributeStack[$stackPos - (1 - 1)] + $this->endAttributes); }, 499 => function ($stackPos) { $this->semValue = new Name($this->semStack[$stackPos - (1 - 1)], $this->startAttributeStack[$stackPos - (1 - 1)] + $this->endAttributes); }, 500 => function ($stackPos) { $this->semValue = new Name\FullyQualified(\substr($this->semStack[$stackPos - (1 - 1)], 1), $this->startAttributeStack[$stackPos - (1 - 1)] + $this->endAttributes); }, 501 => function ($stackPos) { $this->semValue = new Name\Relative(\substr($this->semStack[$stackPos - (1 - 1)], 10), $this->startAttributeStack[$stackPos - (1 - 1)] + $this->endAttributes); }, 502 => function ($stackPos) { $this->semValue = $this->semStack[$stackPos - (1 - 1)]; }, 503 => function ($stackPos) { $this->semValue = $this->semStack[$stackPos - (1 - 1)]; }, 504 => function ($stackPos) { $this->semValue = $this->semStack[$stackPos - (3 - 2)]; }, 505 => function ($stackPos) { $this->semValue = new Expr\Error($this->startAttributeStack[$stackPos - (1 - 1)] + $this->endAttributes); $this->errorState = 2; }, 506 => function ($stackPos) { $this->semValue = $this->semStack[$stackPos - (1 - 1)]; }, 507 => function ($stackPos) { $this->semValue = $this->semStack[$stackPos - (1 - 1)]; }, 508 => function ($stackPos) { $this->semValue = null; }, 509 => function ($stackPos) { $this->semValue = $this->semStack[$stackPos - (3 - 2)]; }, 510 => function ($stackPos) { $this->semValue = array(); }, 511 => function ($stackPos) { $this->semValue = array(new Scalar\EncapsedStringPart(Scalar\String_::parseEscapeSequences($this->semStack[$stackPos - (1 - 1)], '`'), $this->startAttributeStack[$stackPos - (1 - 1)] + $this->endAttributes)); }, 512 => function ($stackPos) { foreach ($this->semStack[$stackPos - (1 - 1)] as $s) { if ($s instanceof Node\Scalar\EncapsedStringPart) { $s->value = Node\Scalar\String_::parseEscapeSequences($s->value, '`', \true); } } $this->semValue = $this->semStack[$stackPos - (1 - 1)]; }, 513 => function ($stackPos) { $this->semValue = array(); }, 514 => function ($stackPos) { $this->semValue = $this->semStack[$stackPos - (1 - 1)]; }, 515 => function ($stackPos) { $this->semValue = new Expr\ConstFetch($this->semStack[$stackPos - (1 - 1)], $this->startAttributeStack[$stackPos - (1 - 1)] + $this->endAttributes); }, 516 => function ($stackPos) { $this->semValue = new Scalar\MagicConst\Line($this->startAttributeStack[$stackPos - (1 - 1)] + $this->endAttributes); }, 517 => function ($stackPos) { $this->semValue = new Scalar\MagicConst\File($this->startAttributeStack[$stackPos - (1 - 1)] + $this->endAttributes); }, 518 => function ($stackPos) { $this->semValue = new Scalar\MagicConst\Dir($this->startAttributeStack[$stackPos - (1 - 1)] + $this->endAttributes); }, 519 => function ($stackPos) { $this->semValue = new Scalar\MagicConst\Class_($this->startAttributeStack[$stackPos - (1 - 1)] + $this->endAttributes); }, 520 => function ($stackPos) { $this->semValue = new Scalar\MagicConst\Trait_($this->startAttributeStack[$stackPos - (1 - 1)] + $this->endAttributes); }, 521 => function ($stackPos) { $this->semValue = new Scalar\MagicConst\Method($this->startAttributeStack[$stackPos - (1 - 1)] + $this->endAttributes); }, 522 => function ($stackPos) { $this->semValue = new Scalar\MagicConst\Function_($this->startAttributeStack[$stackPos - (1 - 1)] + $this->endAttributes); }, 523 => function ($stackPos) { $this->semValue = new Scalar\MagicConst\Namespace_($this->startAttributeStack[$stackPos - (1 - 1)] + $this->endAttributes); }, 524 => function ($stackPos) { $this->semValue = new Expr\ClassConstFetch($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); }, 525 => function ($stackPos) { $this->semValue = new Expr\ClassConstFetch($this->semStack[$stackPos - (5 - 1)], $this->semStack[$stackPos - (5 - 4)], $this->startAttributeStack[$stackPos - (5 - 1)] + $this->endAttributes); }, 526 => function ($stackPos) { $this->semValue = new Expr\ClassConstFetch($this->semStack[$stackPos - (3 - 1)], new Expr\Error($this->startAttributeStack[$stackPos - (3 - 3)] + $this->endAttributeStack[$stackPos - (3 - 3)]), $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); $this->errorState = 2; }, 527 => function ($stackPos) { $attrs = $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes; $attrs['kind'] = Expr\Array_::KIND_SHORT; $this->semValue = new Expr\Array_($this->semStack[$stackPos - (3 - 2)], $attrs); }, 528 => function ($stackPos) { $attrs = $this->startAttributeStack[$stackPos - (4 - 1)] + $this->endAttributes; $attrs['kind'] = Expr\Array_::KIND_LONG; $this->semValue = new Expr\Array_($this->semStack[$stackPos - (4 - 3)], $attrs); }, 529 => function ($stackPos) { $this->semValue = $this->semStack[$stackPos - (1 - 1)]; }, 530 => function ($stackPos) { $this->semValue = Scalar\String_::fromString($this->semStack[$stackPos - (1 - 1)], $this->startAttributeStack[$stackPos - (1 - 1)] + $this->endAttributes); }, 531 => function ($stackPos) { $attrs = $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes; $attrs['kind'] = Scalar\String_::KIND_DOUBLE_QUOTED; foreach ($this->semStack[$stackPos - (3 - 2)] as $s) { if ($s instanceof Node\Scalar\EncapsedStringPart) { $s->value = Node\Scalar\String_::parseEscapeSequences($s->value, '"', \true); } } $this->semValue = new Scalar\Encapsed($this->semStack[$stackPos - (3 - 2)], $attrs); }, 532 => function ($stackPos) { $this->semValue = $this->parseLNumber($this->semStack[$stackPos - (1 - 1)], $this->startAttributeStack[$stackPos - (1 - 1)] + $this->endAttributes); }, 533 => function ($stackPos) { $this->semValue = Scalar\DNumber::fromString($this->semStack[$stackPos - (1 - 1)], $this->startAttributeStack[$stackPos - (1 - 1)] + $this->endAttributes); }, 534 => function ($stackPos) { $this->semValue = $this->semStack[$stackPos - (1 - 1)]; }, 535 => function ($stackPos) { $this->semValue = $this->semStack[$stackPos - (1 - 1)]; }, 536 => function ($stackPos) { $this->semValue = $this->semStack[$stackPos - (1 - 1)]; }, 537 => function ($stackPos) { $this->semValue = $this->parseDocString($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 2)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes, $this->startAttributeStack[$stackPos - (3 - 3)] + $this->endAttributeStack[$stackPos - (3 - 3)], \true); }, 538 => function ($stackPos) { $this->semValue = $this->parseDocString($this->semStack[$stackPos - (2 - 1)], '', $this->semStack[$stackPos - (2 - 2)], $this->startAttributeStack[$stackPos - (2 - 1)] + $this->endAttributes, $this->startAttributeStack[$stackPos - (2 - 2)] + $this->endAttributeStack[$stackPos - (2 - 2)], \true); }, 539 => function ($stackPos) { $this->semValue = $this->parseDocString($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 2)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes, $this->startAttributeStack[$stackPos - (3 - 3)] + $this->endAttributeStack[$stackPos - (3 - 3)], \true); }, 540 => function ($stackPos) { $this->semValue = null; }, 541 => function ($stackPos) { $this->semValue = $this->semStack[$stackPos - (1 - 1)]; }, 542 => function ($stackPos) { $this->semValue = $this->semStack[$stackPos - (1 - 1)]; }, 543 => function ($stackPos) { $this->semValue = $this->semStack[$stackPos - (3 - 2)]; }, 544 => function ($stackPos) { $this->semValue = $this->semStack[$stackPos - (1 - 1)]; }, 545 => function ($stackPos) { $this->semValue = $this->semStack[$stackPos - (1 - 1)]; }, 546 => function ($stackPos) { $this->semValue = $this->semStack[$stackPos - (1 - 1)]; }, 547 => function ($stackPos) { $this->semValue = $this->semStack[$stackPos - (1 - 1)]; }, 548 => function ($stackPos) { $this->semValue = $this->semStack[$stackPos - (1 - 1)]; }, 549 => function ($stackPos) { $this->semValue = $this->semStack[$stackPos - (3 - 2)]; }, 550 => function ($stackPos) { $this->semValue = $this->semStack[$stackPos - (1 - 1)]; }, 551 => function ($stackPos) { $this->semValue = $this->semStack[$stackPos - (1 - 1)]; }, 552 => function ($stackPos) { $this->semValue = new Expr\ArrayDimFetch($this->semStack[$stackPos - (4 - 1)], $this->semStack[$stackPos - (4 - 3)], $this->startAttributeStack[$stackPos - (4 - 1)] + $this->endAttributes); }, 553 => function ($stackPos) { $this->semValue = new Expr\ArrayDimFetch($this->semStack[$stackPos - (4 - 1)], $this->semStack[$stackPos - (4 - 3)], $this->startAttributeStack[$stackPos - (4 - 1)] + $this->endAttributes); }, 554 => function ($stackPos) { $this->semValue = $this->semStack[$stackPos - (1 - 1)]; }, 555 => function ($stackPos) { $this->semValue = new Expr\MethodCall($this->semStack[$stackPos - (4 - 1)], $this->semStack[$stackPos - (4 - 3)], $this->semStack[$stackPos - (4 - 4)], $this->startAttributeStack[$stackPos - (4 - 1)] + $this->endAttributes); }, 556 => function ($stackPos) { $this->semValue = new Expr\NullsafeMethodCall($this->semStack[$stackPos - (4 - 1)], $this->semStack[$stackPos - (4 - 3)], $this->semStack[$stackPos - (4 - 4)], $this->startAttributeStack[$stackPos - (4 - 1)] + $this->endAttributes); }, 557 => function ($stackPos) { $this->semValue = null; }, 558 => function ($stackPos) { $this->semValue = $this->semStack[$stackPos - (1 - 1)]; }, 559 => function ($stackPos) { $this->semValue = $this->semStack[$stackPos - (1 - 1)]; }, 560 => function ($stackPos) { $this->semValue = $this->semStack[$stackPos - (1 - 1)]; }, 561 => function ($stackPos) { $this->semValue = new Expr\PropertyFetch($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); }, 562 => function ($stackPos) { $this->semValue = new Expr\NullsafePropertyFetch($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); }, 563 => function ($stackPos) { $this->semValue = $this->semStack[$stackPos - (1 - 1)]; }, 564 => function ($stackPos) { $this->semValue = new Expr\Variable($this->semStack[$stackPos - (4 - 3)], $this->startAttributeStack[$stackPos - (4 - 1)] + $this->endAttributes); }, 565 => function ($stackPos) { $this->semValue = new Expr\Variable($this->semStack[$stackPos - (2 - 2)], $this->startAttributeStack[$stackPos - (2 - 1)] + $this->endAttributes); }, 566 => function ($stackPos) { $this->semValue = new Expr\Variable(new Expr\Error($this->startAttributeStack[$stackPos - (2 - 1)] + $this->endAttributes), $this->startAttributeStack[$stackPos - (2 - 1)] + $this->endAttributes); $this->errorState = 2; }, 567 => function ($stackPos) { $var = $this->semStack[$stackPos - (1 - 1)]->name; $this->semValue = \is_string($var) ? new Node\VarLikeIdentifier($var, $this->startAttributeStack[$stackPos - (1 - 1)] + $this->endAttributes) : $var; }, 568 => function ($stackPos) { $this->semValue = new Expr\StaticPropertyFetch($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); }, 569 => function ($stackPos) { $this->semValue = $this->semStack[$stackPos - (1 - 1)]; }, 570 => function ($stackPos) { $this->semValue = new Expr\ArrayDimFetch($this->semStack[$stackPos - (4 - 1)], $this->semStack[$stackPos - (4 - 3)], $this->startAttributeStack[$stackPos - (4 - 1)] + $this->endAttributes); }, 571 => function ($stackPos) { $this->semValue = new Expr\ArrayDimFetch($this->semStack[$stackPos - (4 - 1)], $this->semStack[$stackPos - (4 - 3)], $this->startAttributeStack[$stackPos - (4 - 1)] + $this->endAttributes); }, 572 => function ($stackPos) { $this->semValue = new Expr\PropertyFetch($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); }, 573 => function ($stackPos) { $this->semValue = new Expr\NullsafePropertyFetch($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); }, 574 => function ($stackPos) { $this->semValue = new Expr\StaticPropertyFetch($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); }, 575 => function ($stackPos) { $this->semValue = new Expr\StaticPropertyFetch($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); }, 576 => function ($stackPos) { $this->semValue = $this->semStack[$stackPos - (1 - 1)]; }, 577 => function ($stackPos) { $this->semValue = $this->semStack[$stackPos - (3 - 2)]; }, 578 => function ($stackPos) { $this->semValue = $this->semStack[$stackPos - (1 - 1)]; }, 579 => function ($stackPos) { $this->semValue = $this->semStack[$stackPos - (1 - 1)]; }, 580 => function ($stackPos) { $this->semValue = $this->semStack[$stackPos - (3 - 2)]; }, 581 => function ($stackPos) { $this->semValue = $this->semStack[$stackPos - (1 - 1)]; }, 582 => function ($stackPos) { $this->semValue = new Expr\Error($this->startAttributeStack[$stackPos - (1 - 1)] + $this->endAttributes); $this->errorState = 2; }, 583 => function ($stackPos) { $this->semValue = new Expr\List_($this->semStack[$stackPos - (4 - 3)], $this->startAttributeStack[$stackPos - (4 - 1)] + $this->endAttributes); }, 584 => function ($stackPos) { $this->semValue = $this->semStack[$stackPos - (1 - 1)]; $end = \count($this->semValue) - 1; if ($this->semValue[$end] === null) { \array_pop($this->semValue); } }, 585 => function ($stackPos) { $this->semValue = $this->semStack[$stackPos]; }, 586 => function ($stackPos) { /* do nothing -- prevent default action of $$=$this->semStack[$1]. See $551. */ }, 587 => function ($stackPos) { $this->semStack[$stackPos - (3 - 1)][] = $this->semStack[$stackPos - (3 - 3)]; $this->semValue = $this->semStack[$stackPos - (3 - 1)]; }, 588 => function ($stackPos) { $this->semValue = array($this->semStack[$stackPos - (1 - 1)]); }, 589 => function ($stackPos) { $this->semValue = new Expr\ArrayItem($this->semStack[$stackPos - (1 - 1)], null, \false, $this->startAttributeStack[$stackPos - (1 - 1)] + $this->endAttributes); }, 590 => function ($stackPos) { $this->semValue = new Expr\ArrayItem($this->semStack[$stackPos - (2 - 2)], null, \true, $this->startAttributeStack[$stackPos - (2 - 1)] + $this->endAttributes); }, 591 => function ($stackPos) { $this->semValue = new Expr\ArrayItem($this->semStack[$stackPos - (1 - 1)], null, \false, $this->startAttributeStack[$stackPos - (1 - 1)] + $this->endAttributes); }, 592 => function ($stackPos) { $this->semValue = new Expr\ArrayItem($this->semStack[$stackPos - (3 - 3)], $this->semStack[$stackPos - (3 - 1)], \false, $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); }, 593 => function ($stackPos) { $this->semValue = new Expr\ArrayItem($this->semStack[$stackPos - (4 - 4)], $this->semStack[$stackPos - (4 - 1)], \true, $this->startAttributeStack[$stackPos - (4 - 1)] + $this->endAttributes); }, 594 => function ($stackPos) { $this->semValue = new Expr\ArrayItem($this->semStack[$stackPos - (3 - 3)], $this->semStack[$stackPos - (3 - 1)], \false, $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); }, 595 => function ($stackPos) { $this->semValue = new Expr\ArrayItem($this->semStack[$stackPos - (2 - 2)], null, \false, $this->startAttributeStack[$stackPos - (2 - 1)] + $this->endAttributes, \true); }, 596 => function ($stackPos) { $this->semValue = null; }, 597 => function ($stackPos) { $this->semStack[$stackPos - (2 - 1)][] = $this->semStack[$stackPos - (2 - 2)]; $this->semValue = $this->semStack[$stackPos - (2 - 1)]; }, 598 => function ($stackPos) { $this->semStack[$stackPos - (2 - 1)][] = $this->semStack[$stackPos - (2 - 2)]; $this->semValue = $this->semStack[$stackPos - (2 - 1)]; }, 599 => function ($stackPos) { $this->semValue = array($this->semStack[$stackPos - (1 - 1)]); }, 600 => function ($stackPos) { $this->semValue = array($this->semStack[$stackPos - (2 - 1)], $this->semStack[$stackPos - (2 - 2)]); }, 601 => function ($stackPos) { $this->semValue = new Scalar\EncapsedStringPart($this->semStack[$stackPos - (1 - 1)], $this->startAttributeStack[$stackPos - (1 - 1)] + $this->endAttributes); }, 602 => function ($stackPos) { $this->semValue = new Expr\Variable($this->semStack[$stackPos - (1 - 1)], $this->startAttributeStack[$stackPos - (1 - 1)] + $this->endAttributes); }, 603 => function ($stackPos) { $this->semValue = $this->semStack[$stackPos - (1 - 1)]; }, 604 => function ($stackPos) { $this->semValue = new Expr\ArrayDimFetch($this->semStack[$stackPos - (4 - 1)], $this->semStack[$stackPos - (4 - 3)], $this->startAttributeStack[$stackPos - (4 - 1)] + $this->endAttributes); }, 605 => function ($stackPos) { $this->semValue = new Expr\PropertyFetch($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); }, 606 => function ($stackPos) { $this->semValue = new Expr\NullsafePropertyFetch($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); }, 607 => function ($stackPos) { $this->semValue = new Expr\Variable($this->semStack[$stackPos - (3 - 2)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); }, 608 => function ($stackPos) { $this->semValue = new Expr\Variable($this->semStack[$stackPos - (3 - 2)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); }, 609 => function ($stackPos) { $this->semValue = new Expr\ArrayDimFetch($this->semStack[$stackPos - (6 - 2)], $this->semStack[$stackPos - (6 - 4)], $this->startAttributeStack[$stackPos - (6 - 1)] + $this->endAttributes); }, 610 => function ($stackPos) { $this->semValue = $this->semStack[$stackPos - (3 - 2)]; }, 611 => function ($stackPos) { $this->semValue = new Scalar\String_($this->semStack[$stackPos - (1 - 1)], $this->startAttributeStack[$stackPos - (1 - 1)] + $this->endAttributes); }, 612 => function ($stackPos) { $this->semValue = $this->parseNumString($this->semStack[$stackPos - (1 - 1)], $this->startAttributeStack[$stackPos - (1 - 1)] + $this->endAttributes); }, 613 => function ($stackPos) { $this->semValue = $this->parseNumString('-' . $this->semStack[$stackPos - (2 - 2)], $this->startAttributeStack[$stackPos - (2 - 1)] + $this->endAttributes); }, 614 => function ($stackPos) { $this->semValue = $this->semStack[$stackPos - (1 - 1)]; }]; } } '", "T_IS_GREATER_OR_EQUAL", "T_SL", "T_SR", "'+'", "'-'", "'.'", "'*'", "'/'", "'%'", "'!'", "T_INSTANCEOF", "'~'", "T_INC", "T_DEC", "T_INT_CAST", "T_DOUBLE_CAST", "T_STRING_CAST", "T_ARRAY_CAST", "T_OBJECT_CAST", "T_BOOL_CAST", "T_UNSET_CAST", "'@'", "T_POW", "'['", "T_NEW", "T_CLONE", "T_EXIT", "T_IF", "T_ELSEIF", "T_ELSE", "T_ENDIF", "T_LNUMBER", "T_DNUMBER", "T_STRING", "T_STRING_VARNAME", "T_VARIABLE", "T_NUM_STRING", "T_INLINE_HTML", "T_ENCAPSED_AND_WHITESPACE", "T_CONSTANT_ENCAPSED_STRING", "T_ECHO", "T_DO", "T_WHILE", "T_ENDWHILE", "T_FOR", "T_ENDFOR", "T_FOREACH", "T_ENDFOREACH", "T_DECLARE", "T_ENDDECLARE", "T_AS", "T_SWITCH", "T_MATCH", "T_ENDSWITCH", "T_CASE", "T_DEFAULT", "T_BREAK", "T_CONTINUE", "T_GOTO", "T_FUNCTION", "T_FN", "T_CONST", "T_RETURN", "T_TRY", "T_CATCH", "T_FINALLY", "T_USE", "T_INSTEADOF", "T_GLOBAL", "T_STATIC", "T_ABSTRACT", "T_FINAL", "T_PRIVATE", "T_PROTECTED", "T_PUBLIC", "T_READONLY", "T_VAR", "T_UNSET", "T_ISSET", "T_EMPTY", "T_HALT_COMPILER", "T_CLASS", "T_TRAIT", "T_INTERFACE", "T_EXTENDS", "T_IMPLEMENTS", "T_OBJECT_OPERATOR", "T_LIST", "T_ARRAY", "T_CALLABLE", "T_CLASS_C", "T_TRAIT_C", "T_METHOD_C", "T_FUNC_C", "T_LINE", "T_FILE", "T_START_HEREDOC", "T_END_HEREDOC", "T_DOLLAR_OPEN_CURLY_BRACES", "T_CURLY_OPEN", "T_PAAMAYIM_NEKUDOTAYIM", "T_NAMESPACE", "T_NS_C", "T_DIR", "T_NS_SEPARATOR", "T_ELLIPSIS", "T_NAME_FULLY_QUALIFIED", "T_NAME_QUALIFIED", "T_NAME_RELATIVE", "';'", "'{'", "'}'", "'('", "')'", "'\$'", "'`'", "']'", "'\"'", "T_ENUM", "T_NULLSAFE_OBJECT_OPERATOR", "T_ATTRIBUTE"); protected $tokenToSymbol = array(0, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 56, 164, 168, 161, 55, 168, 168, 159, 160, 53, 50, 8, 51, 52, 54, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 31, 156, 44, 16, 46, 30, 68, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 70, 168, 163, 36, 168, 162, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 157, 35, 158, 58, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 1, 2, 3, 4, 5, 6, 7, 9, 10, 11, 12, 13, 14, 15, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 32, 33, 34, 37, 38, 39, 40, 41, 42, 43, 45, 47, 48, 49, 57, 59, 60, 61, 62, 63, 64, 65, 66, 67, 69, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 165, 131, 132, 133, 166, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 167); protected $action = array(700, 670, 671, 672, 673, 674, 286, 675, 676, 677, 713, 714, 223, 224, 225, 226, 227, 228, 229, 230, 231, 232, 0, 233, 234, 235, 236, 237, 238, 239, 240, 241, 242, 243, 244, -32766, -32766, -32766, -32766, -32766, -32766, -32766, -32766, -32766, -32767, -32767, -32767, -32767, 245, 246, 242, 243, 244, -32766, -32766, 678, -32766, -32766, -32766, -32766, -32766, -32766, -32766, -32766, -32766, 1229, 245, 246, 1230, 679, 680, 681, 682, 683, 684, 685, 899, 900, 747, -32766, -32766, -32766, -32766, -32766, -32766, 686, 687, 688, 689, 690, 691, 692, 693, 694, 695, 696, 716, 739, 717, 718, 719, 720, 708, 709, 710, 738, 711, 712, 697, 698, 699, 701, 702, 703, 741, 742, 743, 744, 745, 746, 875, 704, 705, 706, 707, 737, 728, 726, 727, 723, 724, 1046, 715, 721, 722, 729, 730, 732, 731, 733, 734, 55, 56, 425, 57, 58, 725, 736, 735, 755, 59, 60, -226, 61, -32766, -32766, -32766, -32766, -32766, -32766, -32766, -32766, -32766, -32766, 337, -32767, -32767, -32767, -32767, 29, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 620, -32766, -32766, -32766, -32766, 62, 63, 1046, -32766, -32766, -32766, 64, 419, 65, 294, 295, 66, 67, 68, 69, 70, 71, 72, 73, 823, 25, 302, 74, 418, 984, 986, 669, 668, 1100, 1101, 1078, 755, 755, 767, 1220, 768, 470, -32766, -32766, -32766, 341, 749, 824, 54, -32767, -32767, -32767, -32767, 98, 99, 100, 101, 102, 220, 221, 222, 362, 876, -32766, 27, -32766, -32766, -32766, -32766, -32766, 1046, 493, 126, 1080, 1079, 1081, 370, 1068, 930, 207, 478, 479, 952, 953, 954, 951, 950, 949, 128, 480, 481, 803, 1106, 1107, 1108, 1109, 1103, 1104, 319, 32, 297, 10, 211, -515, 1110, 1105, 669, 668, 1080, 1079, 1081, 220, 221, 222, 41, 364, 341, 334, 421, 336, 426, -128, -128, -128, 313, 1046, 469, -4, 824, 54, 812, 770, 207, 40, 21, 427, -128, 471, -128, 472, -128, 473, -128, 1046, 428, 220, 221, 222, -32766, 33, 34, 429, 361, 327, 52, 35, 474, -32766, -32766, -32766, 342, 357, 358, 475, 476, 48, 207, 249, 669, 668, 477, 443, 300, 795, 846, 430, 431, 28, -32766, 814, -32766, -32766, -32766, -32766, -32766, -32766, -32766, -32767, -32767, -32767, -32767, -32767, 952, 953, 954, 951, 950, 949, 422, 755, 424, 426, 826, 634, -128, -32766, -32766, 469, 824, 54, 288, 812, 1151, 755, 40, 21, 427, 317, 471, 345, 472, 129, 473, 9, 1186, 428, 769, 360, 324, 905, 33, 34, 429, 361, 1046, 415, 35, 474, 944, 1068, 315, 125, 357, 358, 475, 476, -32766, -32766, -32766, 926, 302, 477, 121, 1068, 759, 846, 430, 431, 669, 668, 423, 755, 1152, 809, 1046, 480, 766, -32766, 805, -32766, -32766, -32766, -32766, -261, 127, 347, 436, 841, 341, 1078, 1200, 426, 446, 826, 634, -4, 807, 469, 824, 54, 436, 812, 341, 755, 40, 21, 427, 444, 471, 130, 472, 1068, 473, 346, 767, 428, 768, -211, -211, -211, 33, 34, 429, 361, 308, 1076, 35, 474, -32766, -32766, -32766, 1046, 357, 358, 475, 476, -32766, -32766, -32766, 906, 120, 477, 539, 1068, 795, 846, 430, 431, 436, -32766, 341, -32766, -32766, -32766, 1046, 480, 810, -32766, 925, -32766, -32766, 754, 1080, 1079, 1081, 49, -32766, -32766, -32766, 749, 751, 426, 1201, 826, 634, -211, 30, 469, 669, 668, 436, 812, 341, 75, 40, 21, 427, -32766, 471, 1064, 472, 124, 473, 669, 668, 428, 212, -210, -210, -210, 33, 34, 429, 361, 51, 1186, 35, 474, 755, -32766, -32766, -32766, 357, 358, 475, 476, 213, 824, 54, 221, 222, 477, 20, 581, 795, 846, 430, 431, 220, 221, 222, 755, 222, 247, 78, 79, 80, 81, 341, 207, 517, 103, 104, 105, 752, 307, 131, 637, 1068, 207, 341, 207, 122, 826, 634, -210, 36, 106, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 1112, 307, 346, 436, 214, 341, 824, 54, 426, 123, 250, 129, 134, 106, 469, -32766, 572, 1112, 812, 245, 246, 40, 21, 427, 251, 471, 252, 472, 341, 473, 453, 22, 428, 207, 899, 900, 638, 33, 34, 429, 824, 54, -86, 35, 474, 220, 221, 222, 314, 357, 358, 100, 101, 102, 239, 240, 241, 645, 477, -230, 458, 589, 135, 374, 596, 597, 207, 760, 640, 648, 642, 941, 654, 929, 662, 822, 133, 307, 837, 426, -32766, 106, 749, 43, 44, 469, 45, 442, 46, 812, 826, 634, 40, 21, 427, 47, 471, 50, 472, 53, 473, 132, 608, 428, 302, 604, -280, -32766, 33, 34, 429, 824, 54, 426, 35, 474, 755, 957, -84, 469, 357, 358, 521, 812, 628, 363, 40, 21, 427, 477, 471, 575, 472, -515, 473, 847, 616, 428, -423, -32766, 11, 646, 33, 34, 429, 824, 54, 445, 35, 474, 462, 285, 578, 1111, 357, 358, 593, 369, 848, 594, 290, 826, 634, 477, 0, 0, 532, 0, 0, 325, 0, 0, 0, 0, 0, 651, 0, 0, 0, 322, 326, 0, 0, 0, 426, 0, 0, 0, 0, 323, 469, 316, 318, -516, 812, 862, 634, 40, 21, 427, 0, 471, 0, 472, 0, 473, 1158, 0, 428, 0, -414, 6, 7, 33, 34, 429, 824, 54, 426, 35, 474, 12, 14, 373, 469, 357, 358, -424, 812, 563, 754, 40, 21, 427, 477, 471, 248, 472, 839, 473, 38, 39, 428, 657, 658, 765, 813, 33, 34, 429, 821, 800, 815, 35, 474, 215, 216, 878, 869, 357, 358, 217, 870, 218, 798, 863, 826, 634, 477, 860, 858, 936, 937, 934, 820, 209, 804, 806, 808, 811, 933, 763, 764, 1100, 1101, 935, 659, 78, 335, 426, 359, 1102, 635, 639, 641, 469, 643, 644, 647, 812, 826, 634, 40, 21, 427, 649, 471, 650, 472, 652, 473, 653, 636, 428, 796, 1226, 1228, 762, 33, 34, 429, 215, 216, 845, 35, 474, 761, 217, 844, 218, 357, 358, 1227, 843, 1060, 831, 1048, 842, 1049, 477, 559, 209, 1106, 1107, 1108, 1109, 1103, 1104, 398, 1100, 1101, 829, 942, 867, 1110, 1105, 868, 1102, 457, 1225, 1194, 1192, 1177, 1157, 219, 1190, 1091, 917, 1198, 1188, 0, 826, 634, 24, -433, 26, 31, 37, 42, 76, 77, 210, 287, 292, 293, 308, 309, 310, 311, 339, 356, 416, 0, -227, -226, 16, 17, 18, 393, 454, 461, 463, 467, 553, 625, 1051, 559, 1054, 1106, 1107, 1108, 1109, 1103, 1104, 398, 907, 1116, 1050, 1026, 564, 1110, 1105, 1025, 1093, 1055, 0, 1044, 0, 1057, 1056, 219, 1059, 1058, 1075, 0, 1191, 1176, 1172, 1189, 1090, 1223, 1117, 1171, 600); protected $actionCheck = array(2, 3, 4, 5, 6, 7, 14, 9, 10, 11, 12, 13, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 0, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 9, 10, 11, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 69, 70, 53, 54, 55, 9, 10, 57, 30, 116, 32, 33, 34, 35, 36, 37, 38, 80, 69, 70, 83, 71, 72, 73, 74, 75, 76, 77, 135, 136, 80, 33, 34, 35, 36, 37, 38, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 31, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 13, 134, 135, 136, 137, 138, 139, 140, 141, 142, 3, 4, 5, 6, 7, 148, 149, 150, 82, 12, 13, 160, 15, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 8, 44, 45, 46, 47, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 80, 33, 34, 35, 36, 50, 51, 13, 9, 10, 11, 56, 128, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 1, 70, 71, 72, 73, 59, 60, 37, 38, 78, 79, 80, 82, 82, 106, 85, 108, 86, 9, 10, 11, 161, 80, 1, 2, 44, 45, 46, 47, 48, 49, 50, 51, 52, 9, 10, 11, 106, 156, 30, 8, 32, 33, 34, 35, 36, 13, 116, 8, 153, 154, 155, 8, 122, 158, 30, 125, 126, 116, 117, 118, 119, 120, 121, 31, 134, 135, 156, 137, 138, 139, 140, 141, 142, 143, 145, 146, 8, 8, 133, 149, 150, 37, 38, 153, 154, 155, 9, 10, 11, 159, 8, 161, 162, 8, 164, 74, 75, 76, 77, 8, 13, 80, 0, 1, 2, 84, 158, 30, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 13, 98, 9, 10, 11, 9, 103, 104, 105, 106, 8, 70, 109, 110, 9, 10, 11, 8, 115, 116, 117, 118, 70, 30, 31, 37, 38, 124, 31, 8, 127, 128, 129, 130, 8, 30, 156, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 116, 117, 118, 119, 120, 121, 8, 82, 8, 74, 156, 157, 158, 33, 34, 80, 1, 2, 8, 84, 163, 82, 87, 88, 89, 133, 91, 70, 93, 152, 95, 108, 82, 98, 158, 8, 113, 160, 103, 104, 105, 106, 13, 108, 109, 110, 123, 122, 113, 157, 115, 116, 117, 118, 9, 10, 11, 156, 71, 124, 157, 122, 127, 128, 129, 130, 37, 38, 8, 82, 160, 156, 13, 134, 156, 30, 156, 32, 33, 34, 35, 158, 157, 148, 159, 122, 161, 80, 1, 74, 133, 156, 157, 158, 156, 80, 1, 2, 159, 84, 161, 82, 87, 88, 89, 157, 91, 157, 93, 122, 95, 161, 106, 98, 108, 100, 101, 102, 103, 104, 105, 106, 159, 116, 109, 110, 9, 10, 11, 13, 115, 116, 117, 118, 9, 10, 11, 160, 16, 124, 81, 122, 127, 128, 129, 130, 159, 30, 161, 32, 33, 34, 13, 134, 156, 30, 156, 32, 33, 153, 153, 154, 155, 70, 9, 10, 11, 80, 80, 74, 160, 156, 157, 158, 14, 80, 37, 38, 159, 84, 161, 152, 87, 88, 89, 30, 91, 160, 93, 14, 95, 37, 38, 98, 16, 100, 101, 102, 103, 104, 105, 106, 70, 82, 109, 110, 82, 33, 34, 35, 115, 116, 117, 118, 16, 1, 2, 10, 11, 124, 160, 85, 127, 128, 129, 130, 9, 10, 11, 82, 11, 14, 157, 9, 10, 11, 161, 30, 85, 53, 54, 55, 154, 57, 157, 31, 122, 30, 161, 30, 157, 156, 157, 158, 30, 69, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 144, 57, 161, 159, 16, 161, 1, 2, 74, 157, 16, 152, 157, 69, 80, 116, 161, 144, 84, 69, 70, 87, 88, 89, 16, 91, 16, 93, 161, 95, 75, 76, 98, 30, 135, 136, 31, 103, 104, 105, 1, 2, 31, 109, 110, 9, 10, 11, 31, 115, 116, 50, 51, 52, 50, 51, 52, 31, 124, 160, 75, 76, 101, 102, 111, 112, 30, 156, 157, 31, 31, 156, 157, 156, 157, 31, 31, 57, 38, 74, 33, 69, 80, 70, 70, 80, 70, 89, 70, 84, 156, 157, 87, 88, 89, 70, 91, 70, 93, 70, 95, 70, 96, 98, 71, 77, 82, 85, 103, 104, 105, 1, 2, 74, 109, 110, 82, 82, 97, 80, 115, 116, 85, 84, 92, 106, 87, 88, 89, 124, 91, 90, 93, 133, 95, 128, 94, 98, 147, 116, 97, 31, 103, 104, 105, 1, 2, 97, 109, 110, 97, 97, 100, 144, 115, 116, 100, 106, 128, 113, 161, 156, 157, 124, -1, -1, 151, -1, -1, 114, -1, -1, -1, -1, -1, 31, -1, -1, -1, 131, 131, -1, -1, -1, 74, -1, -1, -1, -1, 132, 80, 133, 133, 133, 84, 156, 157, 87, 88, 89, -1, 91, -1, 93, -1, 95, 144, -1, 98, -1, 147, 147, 147, 103, 104, 105, 1, 2, 74, 109, 110, 147, 147, 147, 80, 115, 116, 147, 84, 151, 153, 87, 88, 89, 124, 91, 31, 93, 152, 95, 156, 156, 98, 156, 156, 156, 156, 103, 104, 105, 156, 156, 156, 109, 110, 50, 51, 156, 156, 115, 116, 56, 156, 58, 156, 156, 156, 157, 124, 156, 156, 156, 156, 156, 156, 70, 156, 156, 156, 156, 156, 156, 156, 78, 79, 156, 158, 157, 157, 74, 157, 86, 157, 157, 157, 80, 157, 157, 157, 84, 156, 157, 87, 88, 89, 157, 91, 157, 93, 157, 95, 157, 157, 98, 158, 158, 158, 158, 103, 104, 105, 50, 51, 158, 109, 110, 158, 56, 158, 58, 115, 116, 158, 158, 158, 158, 158, 158, 158, 124, 135, 70, 137, 138, 139, 140, 141, 142, 143, 78, 79, 158, 158, 158, 149, 150, 158, 86, 158, 158, 158, 158, 158, 164, 159, 158, 158, 158, 158, 158, -1, 156, 157, 159, 162, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, -1, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 135, 160, 137, 138, 139, 140, 141, 142, 143, 160, 160, 160, 160, 160, 149, 150, 160, 160, 163, -1, 162, -1, 163, 163, 159, 163, 163, 163, -1, 163, 163, 163, 163, 163, 163, 163, 163, 163); protected $actionBase = array(0, 229, 310, 390, 470, 103, 325, 325, 784, -2, -2, 149, -2, -2, -2, 660, 765, 799, 765, 589, 694, 870, 870, 870, 252, 404, 404, 404, 514, 177, 177, 918, 434, 118, 295, 313, 240, 491, 491, 491, 491, 138, 138, 491, 491, 491, 491, 491, 491, 491, 491, 491, 491, 491, 491, 491, 491, 491, 491, 491, 491, 491, 491, 491, 491, 491, 491, 491, 491, 491, 491, 491, 491, 491, 491, 491, 491, 491, 491, 491, 491, 491, 491, 491, 491, 491, 491, 491, 491, 491, 491, 491, 491, 491, 491, 491, 491, 491, 491, 491, 491, 491, 491, 491, 491, 491, 491, 491, 491, 491, 491, 491, 491, 491, 491, 491, 491, 491, 491, 491, 491, 491, 491, 491, 491, 491, 491, 491, 491, 491, 491, 491, 491, 491, 491, 491, 89, 206, 773, 550, 535, 775, 776, 777, 912, 709, 913, 856, 857, 700, 858, 859, 862, 863, 864, 855, 865, 935, 866, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 322, 592, 285, 319, 232, 44, 691, 691, 691, 691, 691, 691, 691, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 582, 530, 530, 530, 594, 860, 658, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 500, -21, -21, 492, 702, 420, 355, 216, 549, 151, 26, 26, 331, 331, 331, 331, 331, 46, 46, 5, 5, 5, 5, 153, 188, 188, 188, 188, 121, 121, 121, 121, 314, 314, 394, 394, 362, 300, 298, 499, 499, 499, 499, 499, 499, 499, 499, 499, 499, 67, 656, 656, 659, 659, 522, 554, 554, 554, 554, 679, -59, -59, 381, 462, 462, 462, 528, 717, 854, 382, 382, 382, 382, 382, 382, 561, 561, 561, -3, -3, -3, 692, 115, 137, 115, 137, 678, 732, 450, 732, 338, 677, -15, 510, 810, 468, 707, 850, 711, 853, 572, 735, 267, 529, 654, 674, 463, 529, 529, 529, 529, 654, 610, 640, 608, 463, 529, 463, 718, 323, 496, 89, 570, 507, 675, 778, 293, 670, 780, 290, 373, 332, 566, 278, 435, 733, 781, 914, 917, 385, 715, 675, 675, 675, 352, 511, 278, -8, 605, 605, 605, 605, 156, 605, 605, 605, 605, 251, 276, 375, 402, 779, 657, 657, 690, 872, 869, 869, 657, 689, 657, 690, 874, 874, 874, 874, 657, 657, 657, 657, 869, 869, 869, 688, 869, 239, 703, 704, 704, 874, 742, 743, 657, 657, 712, 869, 869, 869, 712, 695, 874, 701, 741, 277, 869, 874, 672, 689, 672, 657, 701, 672, 689, 689, 672, 22, 666, 668, 873, 875, 887, 790, 662, 685, 879, 880, 876, 878, 871, 699, 744, 745, 497, 669, 671, 673, 680, 719, 682, 713, 674, 667, 667, 667, 655, 720, 655, 667, 667, 667, 667, 667, 667, 667, 667, 916, 646, 731, 714, 653, 749, 553, 573, 791, 664, 811, 900, 893, 867, 919, 881, 898, 655, 920, 739, 247, 643, 882, 783, 786, 655, 883, 655, 792, 655, 902, 812, 686, 813, 814, 667, 910, 921, 923, 924, 925, 927, 928, 929, 930, 684, 931, 750, 696, 894, 299, 877, 718, 729, 705, 788, 751, 820, 328, 932, 823, 655, 655, 794, 785, 655, 795, 756, 740, 890, 757, 895, 933, 664, 708, 896, 655, 706, 825, 934, 328, 681, 683, 888, 661, 761, 886, 911, 885, 796, 649, 663, 829, 830, 831, 693, 763, 891, 892, 889, 764, 803, 665, 805, 697, 832, 807, 884, 768, 833, 834, 899, 676, 730, 710, 698, 687, 809, 835, 897, 769, 770, 771, 848, 772, 849, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 138, 138, 138, 138, -2, -2, -2, -2, 0, 0, -2, 0, 0, 0, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 0, 0, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 599, -21, -21, -21, -21, 599, -21, -21, -21, -21, -21, -21, -21, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, -21, 599, 599, 599, -21, 382, -21, 382, 382, 382, 382, 382, 382, 382, 382, 382, 382, 382, 382, 382, 382, 382, 382, 382, 382, 382, 382, 382, 382, 382, 382, 382, 382, 382, 382, 382, 382, 382, 382, 382, 382, 382, 382, 382, 382, 382, 382, 382, 382, 382, 382, 599, 0, 0, 599, -21, 599, -21, 599, -21, -21, 599, 599, 599, 599, 599, 599, 599, -21, -21, -21, -21, -21, -21, 0, 561, 561, 561, 561, -21, -21, -21, -21, 382, 382, 382, 382, 382, 382, 259, 382, 382, 382, 382, 382, 382, 382, 382, 382, 382, 382, 561, 561, -3, -3, 382, 382, 382, 382, 382, 259, 382, 382, 463, 689, 689, 689, 137, 137, 137, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 137, 463, 0, 463, 0, 382, 463, 689, 463, 657, 137, 689, 689, 463, 869, 616, 616, 616, 616, 328, 278, 0, 0, 689, 689, 0, 0, 0, 0, 0, 689, 0, 0, 0, 0, 0, 0, 869, 0, 0, 0, 0, 0, 667, 247, 0, 705, 335, 0, 0, 0, 0, 0, 0, 705, 335, 347, 347, 0, 684, 667, 667, 667, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 328); protected $actionDefault = array(3, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 544, 544, 499, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 299, 299, 299, 32767, 32767, 32767, 532, 532, 532, 532, 532, 532, 532, 532, 532, 532, 532, 32767, 32767, 32767, 32767, 32767, 32767, 383, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 389, 549, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 364, 365, 367, 368, 298, 552, 533, 247, 390, 548, 297, 249, 327, 503, 32767, 32767, 32767, 329, 122, 258, 203, 502, 125, 296, 234, 382, 384, 328, 303, 308, 309, 310, 311, 312, 313, 314, 315, 316, 317, 318, 319, 320, 302, 458, 361, 360, 359, 460, 32767, 459, 496, 496, 499, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 325, 487, 486, 326, 456, 330, 457, 333, 461, 464, 331, 332, 349, 350, 347, 348, 351, 462, 463, 480, 481, 478, 479, 301, 352, 353, 354, 355, 482, 483, 484, 485, 32767, 32767, 543, 543, 32767, 32767, 282, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 340, 341, 471, 472, 32767, 238, 238, 238, 238, 283, 238, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 335, 336, 334, 466, 467, 465, 432, 32767, 32767, 32767, 434, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 504, 32767, 32767, 32767, 32767, 32767, 517, 421, 171, 32767, 413, 32767, 171, 171, 171, 171, 32767, 222, 224, 167, 32767, 171, 32767, 490, 32767, 32767, 32767, 32767, 522, 345, 32767, 32767, 116, 32767, 32767, 32767, 559, 32767, 517, 32767, 116, 32767, 32767, 32767, 32767, 358, 337, 338, 339, 32767, 32767, 521, 515, 474, 475, 476, 477, 32767, 468, 469, 470, 473, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 429, 435, 435, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 520, 519, 32767, 414, 498, 188, 186, 186, 32767, 208, 208, 32767, 32767, 190, 491, 510, 32767, 190, 173, 32767, 400, 175, 498, 32767, 32767, 240, 32767, 240, 32767, 400, 240, 32767, 32767, 240, 32767, 415, 439, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 379, 380, 493, 506, 32767, 507, 32767, 413, 343, 344, 346, 322, 32767, 324, 369, 370, 371, 372, 373, 374, 375, 377, 32767, 419, 32767, 422, 32767, 32767, 32767, 257, 32767, 557, 32767, 32767, 306, 557, 32767, 32767, 32767, 551, 32767, 32767, 300, 32767, 32767, 32767, 32767, 253, 32767, 169, 32767, 541, 32767, 558, 32767, 515, 32767, 342, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 516, 32767, 32767, 32767, 32767, 229, 32767, 452, 32767, 116, 32767, 32767, 32767, 189, 32767, 32767, 304, 248, 32767, 32767, 550, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 114, 32767, 170, 32767, 32767, 32767, 191, 32767, 32767, 515, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 295, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 515, 32767, 32767, 233, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 415, 32767, 276, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 127, 127, 3, 127, 127, 260, 3, 260, 127, 260, 260, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 216, 219, 208, 208, 164, 127, 127, 268); protected $goto = array(166, 140, 140, 140, 166, 187, 168, 144, 147, 141, 142, 143, 149, 163, 163, 163, 163, 144, 144, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 138, 159, 160, 161, 162, 184, 139, 185, 494, 495, 377, 496, 500, 501, 502, 503, 504, 505, 506, 507, 970, 164, 145, 146, 148, 171, 176, 186, 203, 253, 256, 258, 260, 263, 264, 265, 266, 267, 268, 269, 277, 278, 279, 280, 303, 304, 328, 329, 330, 394, 395, 396, 543, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 150, 151, 152, 167, 153, 169, 154, 204, 170, 155, 156, 157, 205, 158, 136, 621, 561, 757, 561, 561, 561, 561, 561, 561, 561, 561, 561, 561, 561, 561, 561, 561, 561, 561, 561, 561, 561, 561, 561, 561, 561, 561, 561, 561, 561, 561, 561, 561, 561, 561, 561, 561, 561, 561, 561, 561, 561, 561, 561, 561, 561, 561, 1113, 629, 1113, 1113, 1113, 1113, 1113, 1113, 1113, 1113, 1113, 1113, 1113, 1113, 1113, 1113, 1113, 1113, 1113, 1113, 1113, 1113, 1113, 1113, 1113, 1113, 1113, 1113, 1113, 1113, 1113, 1113, 1113, 1113, 1113, 1113, 1113, 1113, 1113, 1113, 1113, 1113, 1113, 1113, 1113, 1113, 758, 520, 531, 509, 656, 556, 1183, 750, 509, 592, 786, 1183, 888, 612, 613, 884, 617, 618, 624, 626, 631, 633, 817, 855, 855, 855, 855, 850, 856, 174, 891, 891, 1205, 1205, 177, 178, 179, 401, 402, 403, 404, 173, 202, 206, 208, 257, 259, 261, 262, 270, 271, 272, 273, 274, 275, 281, 282, 283, 284, 305, 306, 331, 332, 333, 406, 407, 408, 409, 175, 180, 254, 255, 181, 182, 183, 498, 498, 498, 498, 498, 498, 861, 498, 498, 498, 498, 498, 498, 498, 498, 498, 498, 510, 586, 538, 601, 602, 510, 545, 546, 547, 548, 549, 550, 551, 552, 554, 587, 1209, 560, 350, 560, 560, 560, 560, 560, 560, 560, 560, 560, 560, 560, 560, 560, 560, 560, 560, 560, 560, 560, 560, 560, 560, 560, 560, 560, 560, 560, 560, 560, 560, 560, 560, 560, 560, 560, 560, 560, 560, 560, 560, 560, 560, 560, 560, 400, 607, 537, 537, 569, 533, 909, 535, 535, 497, 499, 525, 541, 570, 573, 584, 591, 298, 296, 296, 296, 298, 289, 299, 611, 378, 511, 614, 595, 947, 375, 511, 437, 437, 437, 437, 437, 437, 1163, 437, 437, 437, 437, 437, 437, 437, 437, 437, 437, 1077, 948, 338, 1175, 321, 1077, 898, 898, 898, 898, 606, 898, 898, 1217, 1217, 1202, 753, 576, 605, 756, 1077, 1077, 1077, 1077, 1077, 1077, 1069, 384, 384, 384, 391, 1217, 877, 859, 857, 859, 655, 466, 512, 886, 881, 753, 384, 753, 384, 968, 384, 895, 385, 588, 353, 414, 384, 1231, 1019, 542, 1197, 1197, 1197, 568, 1094, 386, 386, 386, 904, 915, 515, 1029, 19, 15, 372, 389, 915, 940, 448, 450, 632, 340, 1216, 1216, 1114, 615, 938, 840, 555, 775, 386, 913, 1070, 1073, 1074, 399, 1069, 1182, 660, 23, 1216, 773, 1182, 544, 603, 1066, 1219, 1071, 1174, 1071, 519, 1199, 1199, 1199, 1089, 1088, 1072, 343, 523, 534, 519, 519, 772, 351, 352, 13, 579, 583, 627, 1061, 388, 782, 562, 771, 515, 783, 1181, 3, 4, 918, 956, 865, 451, 574, 1160, 464, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 514, 529, 0, 0, 0, 0, 514, 0, 529, 0, 0, 0, 0, 610, 513, 516, 439, 440, 1067, 619, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 780, 1224, 0, 0, 0, 0, 0, 524, 0, 0, 0, 0, 0, 0, 0, 0, 0, 778, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 301, 301); protected $gotoCheck = array(43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 57, 69, 15, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 128, 9, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 16, 102, 32, 69, 32, 32, 120, 6, 69, 32, 29, 120, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 50, 69, 69, 69, 69, 69, 69, 27, 77, 77, 77, 77, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 119, 119, 119, 119, 119, 119, 33, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 67, 110, 67, 67, 119, 111, 111, 111, 111, 111, 111, 111, 111, 111, 111, 142, 57, 72, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 51, 51, 51, 51, 51, 51, 84, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 5, 5, 5, 5, 5, 5, 5, 63, 46, 124, 63, 129, 98, 63, 124, 57, 57, 57, 57, 57, 57, 133, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 98, 127, 82, 127, 57, 57, 57, 57, 57, 49, 57, 57, 144, 144, 140, 11, 40, 40, 14, 57, 57, 57, 57, 57, 57, 82, 13, 13, 13, 48, 144, 14, 14, 14, 14, 14, 57, 14, 14, 14, 11, 13, 11, 13, 102, 13, 79, 11, 70, 70, 70, 13, 13, 103, 2, 9, 9, 9, 2, 34, 125, 125, 125, 81, 13, 13, 34, 34, 34, 34, 17, 13, 8, 8, 8, 8, 18, 143, 143, 8, 8, 8, 9, 34, 25, 125, 85, 82, 82, 82, 125, 82, 121, 74, 34, 143, 24, 121, 47, 34, 116, 143, 82, 82, 82, 47, 121, 121, 121, 126, 126, 82, 58, 58, 58, 47, 47, 23, 72, 72, 58, 62, 62, 62, 114, 12, 23, 12, 23, 13, 26, 121, 30, 30, 86, 100, 71, 65, 66, 132, 109, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 9, 9, -1, -1, -1, -1, 9, -1, 9, -1, -1, -1, -1, 13, 9, 9, 9, 9, 13, 13, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 9, 9, -1, -1, -1, -1, -1, 102, -1, -1, -1, -1, -1, -1, -1, -1, -1, 9, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 5, 5); protected $gotoBase = array(0, 0, -172, 0, 0, 353, 201, 0, 477, 149, 0, 110, 195, 117, 426, 112, 203, 140, 171, 0, 0, 0, 0, 168, 164, 157, 119, 27, 0, 205, -118, 0, -428, 266, 51, 0, 0, 0, 0, 0, 388, 0, 0, -24, 0, 0, 345, 484, 146, 133, 209, 75, 0, 0, 0, 0, 0, 107, 161, 0, 0, 0, 222, -77, 0, 106, 97, -343, 0, -94, 135, 123, -129, 0, 129, 0, 0, -50, 0, 143, 0, 159, 64, 0, 338, 132, 122, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 98, 0, 121, 0, 165, 156, 0, 0, 0, 0, 0, 87, 273, 259, 0, 0, 114, 0, 150, 0, 0, -5, -91, 200, 0, 0, 84, 154, 202, 77, -48, 178, 0, 0, 93, 187, 0, 0, 0, 0, 0, 0, 136, 0, 286, 167, 102, 0, 0); protected $gotoDefault = array(-32768, 468, 664, 2, 665, 835, 740, 748, 598, 482, 630, 582, 380, 1193, 792, 793, 794, 381, 368, 483, 379, 410, 405, 781, 774, 776, 784, 172, 411, 787, 1, 789, 518, 825, 1020, 365, 797, 366, 590, 799, 527, 801, 802, 137, 382, 383, 528, 484, 390, 577, 816, 276, 387, 818, 367, 819, 828, 371, 465, 455, 460, 530, 557, 609, 432, 447, 571, 565, 536, 1086, 566, 864, 349, 872, 661, 880, 883, 485, 558, 894, 452, 902, 1099, 397, 908, 914, 919, 291, 922, 417, 412, 585, 927, 928, 5, 932, 622, 623, 8, 312, 955, 599, 969, 420, 1039, 1041, 486, 487, 522, 459, 508, 526, 488, 1062, 441, 413, 1065, 433, 489, 490, 434, 435, 1083, 355, 1168, 354, 449, 320, 1155, 580, 1118, 456, 1208, 1164, 348, 491, 492, 376, 1187, 392, 1203, 438, 1210, 1218, 344, 540, 567); protected $ruleToNonTerminal = array(0, 1, 3, 3, 2, 5, 5, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, 7, 8, 8, 9, 10, 11, 11, 12, 12, 13, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 18, 18, 19, 19, 21, 21, 17, 17, 22, 22, 23, 23, 24, 24, 25, 25, 20, 20, 26, 28, 28, 29, 30, 30, 32, 31, 31, 31, 31, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 14, 14, 54, 54, 56, 55, 55, 48, 48, 58, 58, 59, 59, 60, 60, 61, 61, 15, 16, 16, 16, 64, 64, 64, 65, 65, 68, 68, 66, 66, 70, 70, 41, 41, 50, 50, 53, 53, 53, 52, 52, 71, 42, 42, 42, 42, 72, 72, 73, 73, 74, 74, 39, 39, 35, 35, 75, 37, 37, 76, 36, 36, 38, 38, 49, 49, 49, 62, 62, 78, 78, 79, 79, 81, 81, 81, 80, 80, 63, 63, 82, 82, 82, 83, 83, 84, 84, 84, 44, 44, 85, 85, 85, 45, 45, 86, 86, 87, 87, 67, 88, 88, 88, 88, 93, 93, 94, 94, 95, 95, 95, 95, 95, 96, 97, 97, 92, 92, 89, 89, 91, 91, 99, 99, 98, 98, 98, 98, 98, 98, 90, 90, 101, 100, 100, 46, 46, 40, 40, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 34, 34, 47, 47, 106, 106, 107, 107, 107, 107, 113, 102, 102, 109, 109, 115, 115, 116, 117, 118, 118, 118, 118, 118, 118, 118, 69, 69, 57, 57, 57, 57, 103, 103, 122, 122, 119, 119, 123, 123, 123, 123, 104, 104, 104, 108, 108, 108, 114, 114, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 27, 27, 27, 27, 27, 27, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 112, 112, 105, 105, 105, 105, 129, 129, 132, 132, 131, 131, 133, 133, 51, 51, 51, 51, 135, 135, 134, 134, 134, 134, 134, 136, 136, 121, 121, 124, 124, 120, 120, 138, 137, 137, 137, 137, 125, 125, 125, 125, 111, 111, 126, 126, 126, 126, 77, 139, 139, 140, 140, 140, 110, 110, 141, 141, 142, 142, 142, 142, 142, 127, 127, 127, 127, 144, 145, 143, 143, 143, 143, 143, 143, 143, 146, 146, 146); protected $ruleToLength = array(1, 1, 2, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3, 5, 4, 3, 4, 2, 3, 1, 1, 7, 6, 3, 1, 3, 1, 3, 1, 1, 3, 1, 3, 1, 2, 3, 1, 3, 3, 1, 3, 2, 0, 1, 1, 1, 1, 1, 3, 5, 8, 3, 5, 9, 3, 2, 3, 2, 3, 2, 3, 3, 3, 3, 1, 2, 2, 5, 7, 9, 5, 6, 3, 3, 2, 2, 1, 1, 1, 0, 2, 8, 0, 4, 1, 3, 0, 1, 0, 1, 0, 1, 1, 1, 10, 7, 6, 5, 1, 2, 2, 0, 2, 0, 2, 0, 2, 1, 3, 1, 4, 1, 4, 1, 1, 4, 1, 3, 3, 3, 4, 4, 5, 0, 2, 4, 3, 1, 1, 1, 4, 0, 2, 3, 0, 2, 4, 0, 2, 0, 3, 1, 2, 1, 1, 0, 1, 3, 4, 6, 1, 1, 1, 0, 1, 0, 2, 2, 3, 3, 1, 3, 1, 2, 2, 3, 1, 1, 2, 4, 3, 1, 1, 3, 2, 0, 1, 3, 3, 9, 3, 1, 3, 0, 2, 4, 5, 4, 4, 4, 3, 1, 1, 1, 3, 1, 1, 0, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 3, 1, 1, 3, 3, 1, 0, 1, 1, 3, 3, 4, 4, 1, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 1, 3, 5, 4, 3, 4, 4, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 3, 2, 1, 2, 10, 11, 3, 3, 2, 4, 4, 3, 4, 4, 4, 4, 7, 3, 2, 0, 4, 1, 3, 2, 1, 2, 2, 4, 6, 2, 2, 4, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3, 3, 4, 4, 0, 2, 1, 0, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3, 2, 1, 3, 1, 4, 3, 1, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 5, 4, 4, 3, 1, 3, 1, 1, 3, 3, 0, 2, 0, 1, 3, 1, 3, 1, 1, 1, 1, 1, 6, 4, 3, 4, 2, 4, 4, 1, 3, 1, 2, 1, 1, 4, 1, 1, 3, 6, 4, 4, 4, 4, 1, 4, 0, 1, 1, 3, 1, 1, 4, 3, 1, 1, 1, 0, 0, 2, 3, 1, 3, 1, 4, 2, 2, 2, 2, 1, 2, 1, 1, 1, 4, 3, 3, 3, 6, 3, 1, 1, 1); protected function initReduceCallbacks() { $this->reduceCallbacks = [0 => function ($stackPos) { $this->semValue = $this->semStack[$stackPos]; }, 1 => function ($stackPos) { $this->semValue = $this->handleNamespaces($this->semStack[$stackPos - (1 - 1)]); }, 2 => function ($stackPos) { if (\is_array($this->semStack[$stackPos - (2 - 2)])) { $this->semValue = \array_merge($this->semStack[$stackPos - (2 - 1)], $this->semStack[$stackPos - (2 - 2)]); } else { $this->semStack[$stackPos - (2 - 1)][] = $this->semStack[$stackPos - (2 - 2)]; $this->semValue = $this->semStack[$stackPos - (2 - 1)]; } }, 3 => function ($stackPos) { $this->semValue = array(); }, 4 => function ($stackPos) { $startAttributes = $this->lookaheadStartAttributes; if (isset($startAttributes['comments'])) { $nop = new Stmt\Nop($this->createCommentNopAttributes($startAttributes['comments'])); } else { $nop = null; } if ($nop !== null) { $this->semStack[$stackPos - (1 - 1)][] = $nop; } $this->semValue = $this->semStack[$stackPos - (1 - 1)]; }, 5 => function ($stackPos) { $this->semValue = $this->semStack[$stackPos]; }, 6 => function ($stackPos) { $this->semValue = $this->semStack[$stackPos]; }, 7 => function ($stackPos) { $this->semValue = $this->semStack[$stackPos]; }, 8 => function ($stackPos) { $this->semValue = $this->semStack[$stackPos]; }, 9 => function ($stackPos) { $this->semValue = $this->semStack[$stackPos]; }, 10 => function ($stackPos) { $this->semValue = $this->semStack[$stackPos]; }, 11 => function ($stackPos) { $this->semValue = $this->semStack[$stackPos]; }, 12 => function ($stackPos) { $this->semValue = $this->semStack[$stackPos]; }, 13 => function ($stackPos) { $this->semValue = $this->semStack[$stackPos]; }, 14 => function ($stackPos) { $this->semValue = $this->semStack[$stackPos]; }, 15 => function ($stackPos) { $this->semValue = $this->semStack[$stackPos]; }, 16 => function ($stackPos) { $this->semValue = $this->semStack[$stackPos]; }, 17 => function ($stackPos) { $this->semValue = $this->semStack[$stackPos]; }, 18 => function ($stackPos) { $this->semValue = $this->semStack[$stackPos]; }, 19 => function ($stackPos) { $this->semValue = $this->semStack[$stackPos]; }, 20 => function ($stackPos) { $this->semValue = $this->semStack[$stackPos]; }, 21 => function ($stackPos) { $this->semValue = $this->semStack[$stackPos]; }, 22 => function ($stackPos) { $this->semValue = $this->semStack[$stackPos]; }, 23 => function ($stackPos) { $this->semValue = $this->semStack[$stackPos]; }, 24 => function ($stackPos) { $this->semValue = $this->semStack[$stackPos]; }, 25 => function ($stackPos) { $this->semValue = $this->semStack[$stackPos]; }, 26 => function ($stackPos) { $this->semValue = $this->semStack[$stackPos]; }, 27 => function ($stackPos) { $this->semValue = $this->semStack[$stackPos]; }, 28 => function ($stackPos) { $this->semValue = $this->semStack[$stackPos]; }, 29 => function ($stackPos) { $this->semValue = $this->semStack[$stackPos]; }, 30 => function ($stackPos) { $this->semValue = $this->semStack[$stackPos]; }, 31 => function ($stackPos) { $this->semValue = $this->semStack[$stackPos]; }, 32 => function ($stackPos) { $this->semValue = $this->semStack[$stackPos]; }, 33 => function ($stackPos) { $this->semValue = $this->semStack[$stackPos]; }, 34 => function ($stackPos) { $this->semValue = $this->semStack[$stackPos]; }, 35 => function ($stackPos) { $this->semValue = $this->semStack[$stackPos]; }, 36 => function ($stackPos) { $this->semValue = $this->semStack[$stackPos]; }, 37 => function ($stackPos) { $this->semValue = $this->semStack[$stackPos]; }, 38 => function ($stackPos) { $this->semValue = $this->semStack[$stackPos]; }, 39 => function ($stackPos) { $this->semValue = $this->semStack[$stackPos]; }, 40 => function ($stackPos) { $this->semValue = $this->semStack[$stackPos]; }, 41 => function ($stackPos) { $this->semValue = $this->semStack[$stackPos]; }, 42 => function ($stackPos) { $this->semValue = $this->semStack[$stackPos]; }, 43 => function ($stackPos) { $this->semValue = $this->semStack[$stackPos]; }, 44 => function ($stackPos) { $this->semValue = $this->semStack[$stackPos]; }, 45 => function ($stackPos) { $this->semValue = $this->semStack[$stackPos]; }, 46 => function ($stackPos) { $this->semValue = $this->semStack[$stackPos]; }, 47 => function ($stackPos) { $this->semValue = $this->semStack[$stackPos]; }, 48 => function ($stackPos) { $this->semValue = $this->semStack[$stackPos]; }, 49 => function ($stackPos) { $this->semValue = $this->semStack[$stackPos]; }, 50 => function ($stackPos) { $this->semValue = $this->semStack[$stackPos]; }, 51 => function ($stackPos) { $this->semValue = $this->semStack[$stackPos]; }, 52 => function ($stackPos) { $this->semValue = $this->semStack[$stackPos]; }, 53 => function ($stackPos) { $this->semValue = $this->semStack[$stackPos]; }, 54 => function ($stackPos) { $this->semValue = $this->semStack[$stackPos]; }, 55 => function ($stackPos) { $this->semValue = $this->semStack[$stackPos]; }, 56 => function ($stackPos) { $this->semValue = $this->semStack[$stackPos]; }, 57 => function ($stackPos) { $this->semValue = $this->semStack[$stackPos]; }, 58 => function ($stackPos) { $this->semValue = $this->semStack[$stackPos]; }, 59 => function ($stackPos) { $this->semValue = $this->semStack[$stackPos]; }, 60 => function ($stackPos) { $this->semValue = $this->semStack[$stackPos]; }, 61 => function ($stackPos) { $this->semValue = $this->semStack[$stackPos]; }, 62 => function ($stackPos) { $this->semValue = $this->semStack[$stackPos]; }, 63 => function ($stackPos) { $this->semValue = $this->semStack[$stackPos]; }, 64 => function ($stackPos) { $this->semValue = $this->semStack[$stackPos]; }, 65 => function ($stackPos) { $this->semValue = $this->semStack[$stackPos]; }, 66 => function ($stackPos) { $this->semValue = $this->semStack[$stackPos]; }, 67 => function ($stackPos) { $this->semValue = $this->semStack[$stackPos]; }, 68 => function ($stackPos) { $this->semValue = $this->semStack[$stackPos]; }, 69 => function ($stackPos) { $this->semValue = $this->semStack[$stackPos]; }, 70 => function ($stackPos) { $this->semValue = $this->semStack[$stackPos]; }, 71 => function ($stackPos) { $this->semValue = $this->semStack[$stackPos]; }, 72 => function ($stackPos) { $this->semValue = $this->semStack[$stackPos]; }, 73 => function ($stackPos) { $this->semValue = $this->semStack[$stackPos]; }, 74 => function ($stackPos) { $this->semValue = $this->semStack[$stackPos]; }, 75 => function ($stackPos) { $this->semValue = $this->semStack[$stackPos]; }, 76 => function ($stackPos) { $this->semValue = $this->semStack[$stackPos]; }, 77 => function ($stackPos) { $this->semValue = $this->semStack[$stackPos]; }, 78 => function ($stackPos) { $this->semValue = $this->semStack[$stackPos]; }, 79 => function ($stackPos) { $this->semValue = $this->semStack[$stackPos]; }, 80 => function ($stackPos) { $this->semValue = $this->semStack[$stackPos]; }, 81 => function ($stackPos) { $this->semValue = $this->semStack[$stackPos]; }, 82 => function ($stackPos) { $this->semValue = $this->semStack[$stackPos]; }, 83 => function ($stackPos) { $this->semValue = $this->semStack[$stackPos]; }, 84 => function ($stackPos) { $this->semValue = new Node\Identifier($this->semStack[$stackPos - (1 - 1)], $this->startAttributeStack[$stackPos - (1 - 1)] + $this->endAttributes); }, 85 => function ($stackPos) { $this->semValue = new Node\Identifier($this->semStack[$stackPos - (1 - 1)], $this->startAttributeStack[$stackPos - (1 - 1)] + $this->endAttributes); }, 86 => function ($stackPos) { $this->semValue = new Node\Identifier($this->semStack[$stackPos - (1 - 1)], $this->startAttributeStack[$stackPos - (1 - 1)] + $this->endAttributes); }, 87 => function ($stackPos) { $this->semValue = new Node\Identifier($this->semStack[$stackPos - (1 - 1)], $this->startAttributeStack[$stackPos - (1 - 1)] + $this->endAttributes); }, 88 => function ($stackPos) { $this->semValue = new Name($this->semStack[$stackPos - (1 - 1)], $this->startAttributeStack[$stackPos - (1 - 1)] + $this->endAttributes); }, 89 => function ($stackPos) { $this->semValue = new Name($this->semStack[$stackPos - (1 - 1)], $this->startAttributeStack[$stackPos - (1 - 1)] + $this->endAttributes); }, 90 => function ($stackPos) { $this->semValue = $this->semStack[$stackPos - (1 - 1)]; }, 91 => function ($stackPos) { $this->semValue = new Name(\substr($this->semStack[$stackPos - (1 - 1)], 1), $this->startAttributeStack[$stackPos - (1 - 1)] + $this->endAttributes); }, 92 => function ($stackPos) { $this->semValue = new Expr\Variable(\substr($this->semStack[$stackPos - (1 - 1)], 1), $this->startAttributeStack[$stackPos - (1 - 1)] + $this->endAttributes); }, 93 => function ($stackPos) { $this->semValue = $this->semStack[$stackPos - (1 - 1)]; }, 94 => function ($stackPos) { $this->semValue = $this->semStack[$stackPos - (1 - 1)]; }, 95 => function ($stackPos) { $this->semValue = $this->semStack[$stackPos - (1 - 1)]; }, 96 => function ($stackPos) { $this->semValue = new Stmt\HaltCompiler($this->lexer->handleHaltCompiler(), $this->startAttributeStack[$stackPos - (1 - 1)] + $this->endAttributes); }, 97 => function ($stackPos) { $this->semValue = new Stmt\Namespace_($this->semStack[$stackPos - (3 - 2)], null, $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); $this->semValue->setAttribute('kind', Stmt\Namespace_::KIND_SEMICOLON); $this->checkNamespace($this->semValue); }, 98 => function ($stackPos) { $this->semValue = new Stmt\Namespace_($this->semStack[$stackPos - (5 - 2)], $this->semStack[$stackPos - (5 - 4)], $this->startAttributeStack[$stackPos - (5 - 1)] + $this->endAttributes); $this->semValue->setAttribute('kind', Stmt\Namespace_::KIND_BRACED); $this->checkNamespace($this->semValue); }, 99 => function ($stackPos) { $this->semValue = new Stmt\Namespace_(null, $this->semStack[$stackPos - (4 - 3)], $this->startAttributeStack[$stackPos - (4 - 1)] + $this->endAttributes); $this->semValue->setAttribute('kind', Stmt\Namespace_::KIND_BRACED); $this->checkNamespace($this->semValue); }, 100 => function ($stackPos) { $this->semValue = new Stmt\Use_($this->semStack[$stackPos - (3 - 2)], Stmt\Use_::TYPE_NORMAL, $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); }, 101 => function ($stackPos) { $this->semValue = new Stmt\Use_($this->semStack[$stackPos - (4 - 3)], $this->semStack[$stackPos - (4 - 2)], $this->startAttributeStack[$stackPos - (4 - 1)] + $this->endAttributes); }, 102 => function ($stackPos) { $this->semValue = $this->semStack[$stackPos - (2 - 1)]; }, 103 => function ($stackPos) { $this->semValue = new Stmt\Const_($this->semStack[$stackPos - (3 - 2)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); }, 104 => function ($stackPos) { $this->semValue = Stmt\Use_::TYPE_FUNCTION; }, 105 => function ($stackPos) { $this->semValue = Stmt\Use_::TYPE_CONSTANT; }, 106 => function ($stackPos) { $this->semValue = new Stmt\GroupUse($this->semStack[$stackPos - (7 - 3)], $this->semStack[$stackPos - (7 - 6)], $this->semStack[$stackPos - (7 - 2)], $this->startAttributeStack[$stackPos - (7 - 1)] + $this->endAttributes); }, 107 => function ($stackPos) { $this->semValue = new Stmt\GroupUse($this->semStack[$stackPos - (6 - 2)], $this->semStack[$stackPos - (6 - 5)], Stmt\Use_::TYPE_UNKNOWN, $this->startAttributeStack[$stackPos - (6 - 1)] + $this->endAttributes); }, 108 => function ($stackPos) { $this->semStack[$stackPos - (3 - 1)][] = $this->semStack[$stackPos - (3 - 3)]; $this->semValue = $this->semStack[$stackPos - (3 - 1)]; }, 109 => function ($stackPos) { $this->semValue = array($this->semStack[$stackPos - (1 - 1)]); }, 110 => function ($stackPos) { $this->semStack[$stackPos - (3 - 1)][] = $this->semStack[$stackPos - (3 - 3)]; $this->semValue = $this->semStack[$stackPos - (3 - 1)]; }, 111 => function ($stackPos) { $this->semValue = array($this->semStack[$stackPos - (1 - 1)]); }, 112 => function ($stackPos) { $this->semStack[$stackPos - (3 - 1)][] = $this->semStack[$stackPos - (3 - 3)]; $this->semValue = $this->semStack[$stackPos - (3 - 1)]; }, 113 => function ($stackPos) { $this->semValue = array($this->semStack[$stackPos - (1 - 1)]); }, 114 => function ($stackPos) { $this->semValue = new Stmt\UseUse($this->semStack[$stackPos - (1 - 1)], null, Stmt\Use_::TYPE_UNKNOWN, $this->startAttributeStack[$stackPos - (1 - 1)] + $this->endAttributes); $this->checkUseUse($this->semValue, $stackPos - (1 - 1)); }, 115 => function ($stackPos) { $this->semValue = new Stmt\UseUse($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], Stmt\Use_::TYPE_UNKNOWN, $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); $this->checkUseUse($this->semValue, $stackPos - (3 - 3)); }, 116 => function ($stackPos) { $this->semValue = new Stmt\UseUse($this->semStack[$stackPos - (1 - 1)], null, Stmt\Use_::TYPE_UNKNOWN, $this->startAttributeStack[$stackPos - (1 - 1)] + $this->endAttributes); $this->checkUseUse($this->semValue, $stackPos - (1 - 1)); }, 117 => function ($stackPos) { $this->semValue = new Stmt\UseUse($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], Stmt\Use_::TYPE_UNKNOWN, $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); $this->checkUseUse($this->semValue, $stackPos - (3 - 3)); }, 118 => function ($stackPos) { $this->semValue = $this->semStack[$stackPos - (1 - 1)]; $this->semValue->type = Stmt\Use_::TYPE_NORMAL; }, 119 => function ($stackPos) { $this->semValue = $this->semStack[$stackPos - (2 - 2)]; $this->semValue->type = $this->semStack[$stackPos - (2 - 1)]; }, 120 => function ($stackPos) { $this->semStack[$stackPos - (3 - 1)][] = $this->semStack[$stackPos - (3 - 3)]; $this->semValue = $this->semStack[$stackPos - (3 - 1)]; }, 121 => function ($stackPos) { $this->semValue = array($this->semStack[$stackPos - (1 - 1)]); }, 122 => function ($stackPos) { $this->semValue = new Node\Const_($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); }, 123 => function ($stackPos) { $this->semStack[$stackPos - (3 - 1)][] = $this->semStack[$stackPos - (3 - 3)]; $this->semValue = $this->semStack[$stackPos - (3 - 1)]; }, 124 => function ($stackPos) { $this->semValue = array($this->semStack[$stackPos - (1 - 1)]); }, 125 => function ($stackPos) { $this->semValue = new Node\Const_($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); }, 126 => function ($stackPos) { if (\is_array($this->semStack[$stackPos - (2 - 2)])) { $this->semValue = \array_merge($this->semStack[$stackPos - (2 - 1)], $this->semStack[$stackPos - (2 - 2)]); } else { $this->semStack[$stackPos - (2 - 1)][] = $this->semStack[$stackPos - (2 - 2)]; $this->semValue = $this->semStack[$stackPos - (2 - 1)]; } }, 127 => function ($stackPos) { $this->semValue = array(); }, 128 => function ($stackPos) { $startAttributes = $this->lookaheadStartAttributes; if (isset($startAttributes['comments'])) { $nop = new Stmt\Nop($this->createCommentNopAttributes($startAttributes['comments'])); } else { $nop = null; } if ($nop !== null) { $this->semStack[$stackPos - (1 - 1)][] = $nop; } $this->semValue = $this->semStack[$stackPos - (1 - 1)]; }, 129 => function ($stackPos) { $this->semValue = $this->semStack[$stackPos - (1 - 1)]; }, 130 => function ($stackPos) { $this->semValue = $this->semStack[$stackPos - (1 - 1)]; }, 131 => function ($stackPos) { $this->semValue = $this->semStack[$stackPos - (1 - 1)]; }, 132 => function ($stackPos) { throw new Error('__HALT_COMPILER() can only be used from the outermost scope', $this->startAttributeStack[$stackPos - (1 - 1)] + $this->endAttributes); }, 133 => function ($stackPos) { if ($this->semStack[$stackPos - (3 - 2)]) { $this->semValue = $this->semStack[$stackPos - (3 - 2)]; $attrs = $this->startAttributeStack[$stackPos - (3 - 1)]; $stmts = $this->semValue; if (!empty($attrs['comments'])) { $stmts[0]->setAttribute('comments', \array_merge($attrs['comments'], $stmts[0]->getAttribute('comments', []))); } } else { $startAttributes = $this->startAttributeStack[$stackPos - (3 - 1)]; if (isset($startAttributes['comments'])) { $this->semValue = new Stmt\Nop($startAttributes + $this->endAttributes); } else { $this->semValue = null; } if (null === $this->semValue) { $this->semValue = array(); } } }, 134 => function ($stackPos) { $this->semValue = new Stmt\If_($this->semStack[$stackPos - (5 - 2)], ['stmts' => \is_array($this->semStack[$stackPos - (5 - 3)]) ? $this->semStack[$stackPos - (5 - 3)] : array($this->semStack[$stackPos - (5 - 3)]), 'elseifs' => $this->semStack[$stackPos - (5 - 4)], 'else' => $this->semStack[$stackPos - (5 - 5)]], $this->startAttributeStack[$stackPos - (5 - 1)] + $this->endAttributes); }, 135 => function ($stackPos) { $this->semValue = new Stmt\If_($this->semStack[$stackPos - (8 - 2)], ['stmts' => $this->semStack[$stackPos - (8 - 4)], 'elseifs' => $this->semStack[$stackPos - (8 - 5)], 'else' => $this->semStack[$stackPos - (8 - 6)]], $this->startAttributeStack[$stackPos - (8 - 1)] + $this->endAttributes); }, 136 => function ($stackPos) { $this->semValue = new Stmt\While_($this->semStack[$stackPos - (3 - 2)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); }, 137 => function ($stackPos) { $this->semValue = new Stmt\Do_($this->semStack[$stackPos - (5 - 4)], \is_array($this->semStack[$stackPos - (5 - 2)]) ? $this->semStack[$stackPos - (5 - 2)] : array($this->semStack[$stackPos - (5 - 2)]), $this->startAttributeStack[$stackPos - (5 - 1)] + $this->endAttributes); }, 138 => function ($stackPos) { $this->semValue = new Stmt\For_(['init' => $this->semStack[$stackPos - (9 - 3)], 'cond' => $this->semStack[$stackPos - (9 - 5)], 'loop' => $this->semStack[$stackPos - (9 - 7)], 'stmts' => $this->semStack[$stackPos - (9 - 9)]], $this->startAttributeStack[$stackPos - (9 - 1)] + $this->endAttributes); }, 139 => function ($stackPos) { $this->semValue = new Stmt\Switch_($this->semStack[$stackPos - (3 - 2)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); }, 140 => function ($stackPos) { $this->semValue = new Stmt\Break_(null, $this->startAttributeStack[$stackPos - (2 - 1)] + $this->endAttributes); }, 141 => function ($stackPos) { $this->semValue = new Stmt\Break_($this->semStack[$stackPos - (3 - 2)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); }, 142 => function ($stackPos) { $this->semValue = new Stmt\Continue_(null, $this->startAttributeStack[$stackPos - (2 - 1)] + $this->endAttributes); }, 143 => function ($stackPos) { $this->semValue = new Stmt\Continue_($this->semStack[$stackPos - (3 - 2)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); }, 144 => function ($stackPos) { $this->semValue = new Stmt\Return_(null, $this->startAttributeStack[$stackPos - (2 - 1)] + $this->endAttributes); }, 145 => function ($stackPos) { $this->semValue = new Stmt\Return_($this->semStack[$stackPos - (3 - 2)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); }, 146 => function ($stackPos) { $this->semValue = new Stmt\Global_($this->semStack[$stackPos - (3 - 2)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); }, 147 => function ($stackPos) { $this->semValue = new Stmt\Static_($this->semStack[$stackPos - (3 - 2)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); }, 148 => function ($stackPos) { $this->semValue = new Stmt\Echo_($this->semStack[$stackPos - (3 - 2)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); }, 149 => function ($stackPos) { $this->semValue = new Stmt\InlineHTML($this->semStack[$stackPos - (1 - 1)], $this->startAttributeStack[$stackPos - (1 - 1)] + $this->endAttributes); }, 150 => function ($stackPos) { $this->semValue = new Stmt\Expression($this->semStack[$stackPos - (2 - 1)], $this->startAttributeStack[$stackPos - (2 - 1)] + $this->endAttributes); }, 151 => function ($stackPos) { $this->semValue = new Stmt\Expression($this->semStack[$stackPos - (2 - 1)], $this->startAttributeStack[$stackPos - (2 - 1)] + $this->endAttributes); }, 152 => function ($stackPos) { $this->semValue = new Stmt\Unset_($this->semStack[$stackPos - (5 - 3)], $this->startAttributeStack[$stackPos - (5 - 1)] + $this->endAttributes); }, 153 => function ($stackPos) { $this->semValue = new Stmt\Foreach_($this->semStack[$stackPos - (7 - 3)], $this->semStack[$stackPos - (7 - 5)][0], ['keyVar' => null, 'byRef' => $this->semStack[$stackPos - (7 - 5)][1], 'stmts' => $this->semStack[$stackPos - (7 - 7)]], $this->startAttributeStack[$stackPos - (7 - 1)] + $this->endAttributes); }, 154 => function ($stackPos) { $this->semValue = new Stmt\Foreach_($this->semStack[$stackPos - (9 - 3)], $this->semStack[$stackPos - (9 - 7)][0], ['keyVar' => $this->semStack[$stackPos - (9 - 5)], 'byRef' => $this->semStack[$stackPos - (9 - 7)][1], 'stmts' => $this->semStack[$stackPos - (9 - 9)]], $this->startAttributeStack[$stackPos - (9 - 1)] + $this->endAttributes); }, 155 => function ($stackPos) { $this->semValue = new Stmt\Declare_($this->semStack[$stackPos - (5 - 3)], $this->semStack[$stackPos - (5 - 5)], $this->startAttributeStack[$stackPos - (5 - 1)] + $this->endAttributes); }, 156 => function ($stackPos) { $this->semValue = new Stmt\TryCatch($this->semStack[$stackPos - (6 - 3)], $this->semStack[$stackPos - (6 - 5)], $this->semStack[$stackPos - (6 - 6)], $this->startAttributeStack[$stackPos - (6 - 1)] + $this->endAttributes); $this->checkTryCatch($this->semValue); }, 157 => function ($stackPos) { $this->semValue = new Stmt\Throw_($this->semStack[$stackPos - (3 - 2)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); }, 158 => function ($stackPos) { $this->semValue = new Stmt\Goto_($this->semStack[$stackPos - (3 - 2)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); }, 159 => function ($stackPos) { $this->semValue = new Stmt\Label($this->semStack[$stackPos - (2 - 1)], $this->startAttributeStack[$stackPos - (2 - 1)] + $this->endAttributes); }, 160 => function ($stackPos) { $this->semValue = new Stmt\Expression($this->semStack[$stackPos - (2 - 1)], $this->startAttributeStack[$stackPos - (2 - 1)] + $this->endAttributes); }, 161 => function ($stackPos) { $this->semValue = array(); /* means: no statement */ }, 162 => function ($stackPos) { $this->semValue = $this->semStack[$stackPos - (1 - 1)]; }, 163 => function ($stackPos) { $startAttributes = $this->startAttributeStack[$stackPos - (1 - 1)]; if (isset($startAttributes['comments'])) { $this->semValue = new Stmt\Nop($startAttributes + $this->endAttributes); } else { $this->semValue = null; } if ($this->semValue === null) { $this->semValue = array(); } /* means: no statement */ }, 164 => function ($stackPos) { $this->semValue = array(); }, 165 => function ($stackPos) { $this->semStack[$stackPos - (2 - 1)][] = $this->semStack[$stackPos - (2 - 2)]; $this->semValue = $this->semStack[$stackPos - (2 - 1)]; }, 166 => function ($stackPos) { $this->semValue = new Stmt\Catch_(array($this->semStack[$stackPos - (8 - 3)]), $this->semStack[$stackPos - (8 - 4)], $this->semStack[$stackPos - (8 - 7)], $this->startAttributeStack[$stackPos - (8 - 1)] + $this->endAttributes); }, 167 => function ($stackPos) { $this->semValue = null; }, 168 => function ($stackPos) { $this->semValue = new Stmt\Finally_($this->semStack[$stackPos - (4 - 3)], $this->startAttributeStack[$stackPos - (4 - 1)] + $this->endAttributes); }, 169 => function ($stackPos) { $this->semValue = array($this->semStack[$stackPos - (1 - 1)]); }, 170 => function ($stackPos) { $this->semStack[$stackPos - (3 - 1)][] = $this->semStack[$stackPos - (3 - 3)]; $this->semValue = $this->semStack[$stackPos - (3 - 1)]; }, 171 => function ($stackPos) { $this->semValue = \false; }, 172 => function ($stackPos) { $this->semValue = \true; }, 173 => function ($stackPos) { $this->semValue = \false; }, 174 => function ($stackPos) { $this->semValue = \true; }, 175 => function ($stackPos) { $this->semValue = \false; }, 176 => function ($stackPos) { $this->semValue = \true; }, 177 => function ($stackPos) { $this->semValue = $this->semStack[$stackPos - (1 - 1)]; }, 178 => function ($stackPos) { $this->semValue = new Node\Identifier($this->semStack[$stackPos - (1 - 1)], $this->startAttributeStack[$stackPos - (1 - 1)] + $this->endAttributes); }, 179 => function ($stackPos) { $this->semValue = new Stmt\Function_($this->semStack[$stackPos - (10 - 3)], ['byRef' => $this->semStack[$stackPos - (10 - 2)], 'params' => $this->semStack[$stackPos - (10 - 5)], 'returnType' => $this->semStack[$stackPos - (10 - 7)], 'stmts' => $this->semStack[$stackPos - (10 - 9)]], $this->startAttributeStack[$stackPos - (10 - 1)] + $this->endAttributes); }, 180 => function ($stackPos) { $this->semValue = new Stmt\Class_($this->semStack[$stackPos - (7 - 2)], ['type' => $this->semStack[$stackPos - (7 - 1)], 'extends' => $this->semStack[$stackPos - (7 - 3)], 'implements' => $this->semStack[$stackPos - (7 - 4)], 'stmts' => $this->semStack[$stackPos - (7 - 6)]], $this->startAttributeStack[$stackPos - (7 - 1)] + $this->endAttributes); $this->checkClass($this->semValue, $stackPos - (7 - 2)); }, 181 => function ($stackPos) { $this->semValue = new Stmt\Interface_($this->semStack[$stackPos - (6 - 2)], ['extends' => $this->semStack[$stackPos - (6 - 3)], 'stmts' => $this->semStack[$stackPos - (6 - 5)]], $this->startAttributeStack[$stackPos - (6 - 1)] + $this->endAttributes); $this->checkInterface($this->semValue, $stackPos - (6 - 2)); }, 182 => function ($stackPos) { $this->semValue = new Stmt\Trait_($this->semStack[$stackPos - (5 - 2)], ['stmts' => $this->semStack[$stackPos - (5 - 4)]], $this->startAttributeStack[$stackPos - (5 - 1)] + $this->endAttributes); }, 183 => function ($stackPos) { $this->semValue = 0; }, 184 => function ($stackPos) { $this->semValue = Stmt\Class_::MODIFIER_ABSTRACT; }, 185 => function ($stackPos) { $this->semValue = Stmt\Class_::MODIFIER_FINAL; }, 186 => function ($stackPos) { $this->semValue = null; }, 187 => function ($stackPos) { $this->semValue = $this->semStack[$stackPos - (2 - 2)]; }, 188 => function ($stackPos) { $this->semValue = array(); }, 189 => function ($stackPos) { $this->semValue = $this->semStack[$stackPos - (2 - 2)]; }, 190 => function ($stackPos) { $this->semValue = array(); }, 191 => function ($stackPos) { $this->semValue = $this->semStack[$stackPos - (2 - 2)]; }, 192 => function ($stackPos) { $this->semValue = array($this->semStack[$stackPos - (1 - 1)]); }, 193 => function ($stackPos) { $this->semStack[$stackPos - (3 - 1)][] = $this->semStack[$stackPos - (3 - 3)]; $this->semValue = $this->semStack[$stackPos - (3 - 1)]; }, 194 => function ($stackPos) { $this->semValue = \is_array($this->semStack[$stackPos - (1 - 1)]) ? $this->semStack[$stackPos - (1 - 1)] : array($this->semStack[$stackPos - (1 - 1)]); }, 195 => function ($stackPos) { $this->semValue = $this->semStack[$stackPos - (4 - 2)]; }, 196 => function ($stackPos) { $this->semValue = \is_array($this->semStack[$stackPos - (1 - 1)]) ? $this->semStack[$stackPos - (1 - 1)] : array($this->semStack[$stackPos - (1 - 1)]); }, 197 => function ($stackPos) { $this->semValue = $this->semStack[$stackPos - (4 - 2)]; }, 198 => function ($stackPos) { $this->semValue = \is_array($this->semStack[$stackPos - (1 - 1)]) ? $this->semStack[$stackPos - (1 - 1)] : array($this->semStack[$stackPos - (1 - 1)]); }, 199 => function ($stackPos) { $this->semValue = null; }, 200 => function ($stackPos) { $this->semValue = $this->semStack[$stackPos - (4 - 2)]; }, 201 => function ($stackPos) { $this->semValue = array($this->semStack[$stackPos - (1 - 1)]); }, 202 => function ($stackPos) { $this->semStack[$stackPos - (3 - 1)][] = $this->semStack[$stackPos - (3 - 3)]; $this->semValue = $this->semStack[$stackPos - (3 - 1)]; }, 203 => function ($stackPos) { $this->semValue = new Stmt\DeclareDeclare($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); }, 204 => function ($stackPos) { $this->semValue = $this->semStack[$stackPos - (3 - 2)]; }, 205 => function ($stackPos) { $this->semValue = $this->semStack[$stackPos - (4 - 3)]; }, 206 => function ($stackPos) { $this->semValue = $this->semStack[$stackPos - (4 - 2)]; }, 207 => function ($stackPos) { $this->semValue = $this->semStack[$stackPos - (5 - 3)]; }, 208 => function ($stackPos) { $this->semValue = array(); }, 209 => function ($stackPos) { $this->semStack[$stackPos - (2 - 1)][] = $this->semStack[$stackPos - (2 - 2)]; $this->semValue = $this->semStack[$stackPos - (2 - 1)]; }, 210 => function ($stackPos) { $this->semValue = new Stmt\Case_($this->semStack[$stackPos - (4 - 2)], $this->semStack[$stackPos - (4 - 4)], $this->startAttributeStack[$stackPos - (4 - 1)] + $this->endAttributes); }, 211 => function ($stackPos) { $this->semValue = new Stmt\Case_(null, $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); }, 212 => function ($stackPos) { $this->semValue = $this->semStack[$stackPos]; }, 213 => function ($stackPos) { $this->semValue = $this->semStack[$stackPos]; }, 214 => function ($stackPos) { $this->semValue = \is_array($this->semStack[$stackPos - (1 - 1)]) ? $this->semStack[$stackPos - (1 - 1)] : array($this->semStack[$stackPos - (1 - 1)]); }, 215 => function ($stackPos) { $this->semValue = $this->semStack[$stackPos - (4 - 2)]; }, 216 => function ($stackPos) { $this->semValue = array(); }, 217 => function ($stackPos) { $this->semStack[$stackPos - (2 - 1)][] = $this->semStack[$stackPos - (2 - 2)]; $this->semValue = $this->semStack[$stackPos - (2 - 1)]; }, 218 => function ($stackPos) { $this->semValue = new Stmt\ElseIf_($this->semStack[$stackPos - (3 - 2)], \is_array($this->semStack[$stackPos - (3 - 3)]) ? $this->semStack[$stackPos - (3 - 3)] : array($this->semStack[$stackPos - (3 - 3)]), $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); }, 219 => function ($stackPos) { $this->semValue = array(); }, 220 => function ($stackPos) { $this->semStack[$stackPos - (2 - 1)][] = $this->semStack[$stackPos - (2 - 2)]; $this->semValue = $this->semStack[$stackPos - (2 - 1)]; }, 221 => function ($stackPos) { $this->semValue = new Stmt\ElseIf_($this->semStack[$stackPos - (4 - 2)], $this->semStack[$stackPos - (4 - 4)], $this->startAttributeStack[$stackPos - (4 - 1)] + $this->endAttributes); }, 222 => function ($stackPos) { $this->semValue = null; }, 223 => function ($stackPos) { $this->semValue = new Stmt\Else_(\is_array($this->semStack[$stackPos - (2 - 2)]) ? $this->semStack[$stackPos - (2 - 2)] : array($this->semStack[$stackPos - (2 - 2)]), $this->startAttributeStack[$stackPos - (2 - 1)] + $this->endAttributes); }, 224 => function ($stackPos) { $this->semValue = null; }, 225 => function ($stackPos) { $this->semValue = new Stmt\Else_($this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); }, 226 => function ($stackPos) { $this->semValue = array($this->semStack[$stackPos - (1 - 1)], \false); }, 227 => function ($stackPos) { $this->semValue = array($this->semStack[$stackPos - (2 - 2)], \true); }, 228 => function ($stackPos) { $this->semValue = array($this->semStack[$stackPos - (1 - 1)], \false); }, 229 => function ($stackPos) { $this->semValue = $this->semStack[$stackPos - (1 - 1)]; }, 230 => function ($stackPos) { $this->semValue = array(); }, 231 => function ($stackPos) { $this->semValue = array($this->semStack[$stackPos - (1 - 1)]); }, 232 => function ($stackPos) { $this->semStack[$stackPos - (3 - 1)][] = $this->semStack[$stackPos - (3 - 3)]; $this->semValue = $this->semStack[$stackPos - (3 - 1)]; }, 233 => function ($stackPos) { $this->semValue = new Node\Param($this->semStack[$stackPos - (4 - 4)], null, $this->semStack[$stackPos - (4 - 1)], $this->semStack[$stackPos - (4 - 2)], $this->semStack[$stackPos - (4 - 3)], $this->startAttributeStack[$stackPos - (4 - 1)] + $this->endAttributes); $this->checkParam($this->semValue); }, 234 => function ($stackPos) { $this->semValue = new Node\Param($this->semStack[$stackPos - (6 - 4)], $this->semStack[$stackPos - (6 - 6)], $this->semStack[$stackPos - (6 - 1)], $this->semStack[$stackPos - (6 - 2)], $this->semStack[$stackPos - (6 - 3)], $this->startAttributeStack[$stackPos - (6 - 1)] + $this->endAttributes); $this->checkParam($this->semValue); }, 235 => function ($stackPos) { $this->semValue = $this->semStack[$stackPos - (1 - 1)]; }, 236 => function ($stackPos) { $this->semValue = new Node\Identifier('array', $this->startAttributeStack[$stackPos - (1 - 1)] + $this->endAttributes); }, 237 => function ($stackPos) { $this->semValue = new Node\Identifier('callable', $this->startAttributeStack[$stackPos - (1 - 1)] + $this->endAttributes); }, 238 => function ($stackPos) { $this->semValue = null; }, 239 => function ($stackPos) { $this->semValue = $this->semStack[$stackPos - (1 - 1)]; }, 240 => function ($stackPos) { $this->semValue = null; }, 241 => function ($stackPos) { $this->semValue = $this->semStack[$stackPos - (2 - 2)]; }, 242 => function ($stackPos) { $this->semValue = array(); }, 243 => function ($stackPos) { $this->semValue = $this->semStack[$stackPos - (3 - 2)]; }, 244 => function ($stackPos) { $this->semValue = array(new Node\Arg($this->semStack[$stackPos - (3 - 2)], \false, \false, $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes)); }, 245 => function ($stackPos) { $this->semValue = array($this->semStack[$stackPos - (1 - 1)]); }, 246 => function ($stackPos) { $this->semStack[$stackPos - (3 - 1)][] = $this->semStack[$stackPos - (3 - 3)]; $this->semValue = $this->semStack[$stackPos - (3 - 1)]; }, 247 => function ($stackPos) { $this->semValue = new Node\Arg($this->semStack[$stackPos - (1 - 1)], \false, \false, $this->startAttributeStack[$stackPos - (1 - 1)] + $this->endAttributes); }, 248 => function ($stackPos) { $this->semValue = new Node\Arg($this->semStack[$stackPos - (2 - 2)], \true, \false, $this->startAttributeStack[$stackPos - (2 - 1)] + $this->endAttributes); }, 249 => function ($stackPos) { $this->semValue = new Node\Arg($this->semStack[$stackPos - (2 - 2)], \false, \true, $this->startAttributeStack[$stackPos - (2 - 1)] + $this->endAttributes); }, 250 => function ($stackPos) { $this->semStack[$stackPos - (3 - 1)][] = $this->semStack[$stackPos - (3 - 3)]; $this->semValue = $this->semStack[$stackPos - (3 - 1)]; }, 251 => function ($stackPos) { $this->semValue = array($this->semStack[$stackPos - (1 - 1)]); }, 252 => function ($stackPos) { $this->semValue = $this->semStack[$stackPos - (1 - 1)]; }, 253 => function ($stackPos) { $this->semValue = new Expr\Variable($this->semStack[$stackPos - (2 - 2)], $this->startAttributeStack[$stackPos - (2 - 1)] + $this->endAttributes); }, 254 => function ($stackPos) { $this->semValue = new Expr\Variable($this->semStack[$stackPos - (4 - 3)], $this->startAttributeStack[$stackPos - (4 - 1)] + $this->endAttributes); }, 255 => function ($stackPos) { $this->semStack[$stackPos - (3 - 1)][] = $this->semStack[$stackPos - (3 - 3)]; $this->semValue = $this->semStack[$stackPos - (3 - 1)]; }, 256 => function ($stackPos) { $this->semValue = array($this->semStack[$stackPos - (1 - 1)]); }, 257 => function ($stackPos) { $this->semValue = new Stmt\StaticVar($this->semStack[$stackPos - (1 - 1)], null, $this->startAttributeStack[$stackPos - (1 - 1)] + $this->endAttributes); }, 258 => function ($stackPos) { $this->semValue = new Stmt\StaticVar($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); }, 259 => function ($stackPos) { if ($this->semStack[$stackPos - (2 - 2)] !== null) { $this->semStack[$stackPos - (2 - 1)][] = $this->semStack[$stackPos - (2 - 2)]; $this->semValue = $this->semStack[$stackPos - (2 - 1)]; } else { $this->semValue = $this->semStack[$stackPos - (2 - 1)]; } }, 260 => function ($stackPos) { $this->semValue = array(); }, 261 => function ($stackPos) { $startAttributes = $this->lookaheadStartAttributes; if (isset($startAttributes['comments'])) { $nop = new Stmt\Nop($this->createCommentNopAttributes($startAttributes['comments'])); } else { $nop = null; } if ($nop !== null) { $this->semStack[$stackPos - (1 - 1)][] = $nop; } $this->semValue = $this->semStack[$stackPos - (1 - 1)]; }, 262 => function ($stackPos) { $this->semValue = new Stmt\Property($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 2)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); $this->checkProperty($this->semValue, $stackPos - (3 - 1)); }, 263 => function ($stackPos) { $this->semValue = new Stmt\ClassConst($this->semStack[$stackPos - (3 - 2)], 0, $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); }, 264 => function ($stackPos) { $this->semValue = new Stmt\ClassMethod($this->semStack[$stackPos - (9 - 4)], ['type' => $this->semStack[$stackPos - (9 - 1)], 'byRef' => $this->semStack[$stackPos - (9 - 3)], 'params' => $this->semStack[$stackPos - (9 - 6)], 'returnType' => $this->semStack[$stackPos - (9 - 8)], 'stmts' => $this->semStack[$stackPos - (9 - 9)]], $this->startAttributeStack[$stackPos - (9 - 1)] + $this->endAttributes); $this->checkClassMethod($this->semValue, $stackPos - (9 - 1)); }, 265 => function ($stackPos) { $this->semValue = new Stmt\TraitUse($this->semStack[$stackPos - (3 - 2)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); }, 266 => function ($stackPos) { $this->semValue = array(); }, 267 => function ($stackPos) { $this->semValue = $this->semStack[$stackPos - (3 - 2)]; }, 268 => function ($stackPos) { $this->semValue = array(); }, 269 => function ($stackPos) { $this->semStack[$stackPos - (2 - 1)][] = $this->semStack[$stackPos - (2 - 2)]; $this->semValue = $this->semStack[$stackPos - (2 - 1)]; }, 270 => function ($stackPos) { $this->semValue = new Stmt\TraitUseAdaptation\Precedence($this->semStack[$stackPos - (4 - 1)][0], $this->semStack[$stackPos - (4 - 1)][1], $this->semStack[$stackPos - (4 - 3)], $this->startAttributeStack[$stackPos - (4 - 1)] + $this->endAttributes); }, 271 => function ($stackPos) { $this->semValue = new Stmt\TraitUseAdaptation\Alias($this->semStack[$stackPos - (5 - 1)][0], $this->semStack[$stackPos - (5 - 1)][1], $this->semStack[$stackPos - (5 - 3)], $this->semStack[$stackPos - (5 - 4)], $this->startAttributeStack[$stackPos - (5 - 1)] + $this->endAttributes); }, 272 => function ($stackPos) { $this->semValue = new Stmt\TraitUseAdaptation\Alias($this->semStack[$stackPos - (4 - 1)][0], $this->semStack[$stackPos - (4 - 1)][1], $this->semStack[$stackPos - (4 - 3)], null, $this->startAttributeStack[$stackPos - (4 - 1)] + $this->endAttributes); }, 273 => function ($stackPos) { $this->semValue = new Stmt\TraitUseAdaptation\Alias($this->semStack[$stackPos - (4 - 1)][0], $this->semStack[$stackPos - (4 - 1)][1], null, $this->semStack[$stackPos - (4 - 3)], $this->startAttributeStack[$stackPos - (4 - 1)] + $this->endAttributes); }, 274 => function ($stackPos) { $this->semValue = new Stmt\TraitUseAdaptation\Alias($this->semStack[$stackPos - (4 - 1)][0], $this->semStack[$stackPos - (4 - 1)][1], null, $this->semStack[$stackPos - (4 - 3)], $this->startAttributeStack[$stackPos - (4 - 1)] + $this->endAttributes); }, 275 => function ($stackPos) { $this->semValue = array($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)]); }, 276 => function ($stackPos) { $this->semValue = $this->semStack[$stackPos - (1 - 1)]; }, 277 => function ($stackPos) { $this->semValue = array(null, $this->semStack[$stackPos - (1 - 1)]); }, 278 => function ($stackPos) { $this->semValue = null; }, 279 => function ($stackPos) { $this->semValue = $this->semStack[$stackPos - (3 - 2)]; }, 280 => function ($stackPos) { $this->semValue = $this->semStack[$stackPos - (1 - 1)]; }, 281 => function ($stackPos) { $this->semValue = 0; }, 282 => function ($stackPos) { $this->semValue = 0; }, 283 => function ($stackPos) { $this->semValue = $this->semStack[$stackPos - (1 - 1)]; }, 284 => function ($stackPos) { $this->semValue = $this->semStack[$stackPos - (1 - 1)]; }, 285 => function ($stackPos) { $this->checkModifier($this->semStack[$stackPos - (2 - 1)], $this->semStack[$stackPos - (2 - 2)], $stackPos - (2 - 2)); $this->semValue = $this->semStack[$stackPos - (2 - 1)] | $this->semStack[$stackPos - (2 - 2)]; }, 286 => function ($stackPos) { $this->semValue = Stmt\Class_::MODIFIER_PUBLIC; }, 287 => function ($stackPos) { $this->semValue = Stmt\Class_::MODIFIER_PROTECTED; }, 288 => function ($stackPos) { $this->semValue = Stmt\Class_::MODIFIER_PRIVATE; }, 289 => function ($stackPos) { $this->semValue = Stmt\Class_::MODIFIER_STATIC; }, 290 => function ($stackPos) { $this->semValue = Stmt\Class_::MODIFIER_ABSTRACT; }, 291 => function ($stackPos) { $this->semValue = Stmt\Class_::MODIFIER_FINAL; }, 292 => function ($stackPos) { $this->semValue = array($this->semStack[$stackPos - (1 - 1)]); }, 293 => function ($stackPos) { $this->semStack[$stackPos - (3 - 1)][] = $this->semStack[$stackPos - (3 - 3)]; $this->semValue = $this->semStack[$stackPos - (3 - 1)]; }, 294 => function ($stackPos) { $this->semValue = new Node\VarLikeIdentifier(\substr($this->semStack[$stackPos - (1 - 1)], 1), $this->startAttributeStack[$stackPos - (1 - 1)] + $this->endAttributes); }, 295 => function ($stackPos) { $this->semValue = new Stmt\PropertyProperty($this->semStack[$stackPos - (1 - 1)], null, $this->startAttributeStack[$stackPos - (1 - 1)] + $this->endAttributes); }, 296 => function ($stackPos) { $this->semValue = new Stmt\PropertyProperty($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); }, 297 => function ($stackPos) { $this->semStack[$stackPos - (3 - 1)][] = $this->semStack[$stackPos - (3 - 3)]; $this->semValue = $this->semStack[$stackPos - (3 - 1)]; }, 298 => function ($stackPos) { $this->semValue = array($this->semStack[$stackPos - (1 - 1)]); }, 299 => function ($stackPos) { $this->semValue = array(); }, 300 => function ($stackPos) { $this->semValue = $this->semStack[$stackPos - (1 - 1)]; }, 301 => function ($stackPos) { $this->semValue = $this->semStack[$stackPos - (1 - 1)]; }, 302 => function ($stackPos) { $this->semValue = new Expr\Assign($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); }, 303 => function ($stackPos) { $this->semValue = new Expr\Assign($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); }, 304 => function ($stackPos) { $this->semValue = new Expr\AssignRef($this->semStack[$stackPos - (4 - 1)], $this->semStack[$stackPos - (4 - 4)], $this->startAttributeStack[$stackPos - (4 - 1)] + $this->endAttributes); }, 305 => function ($stackPos) { $this->semValue = new Expr\AssignRef($this->semStack[$stackPos - (4 - 1)], $this->semStack[$stackPos - (4 - 4)], $this->startAttributeStack[$stackPos - (4 - 1)] + $this->endAttributes); }, 306 => function ($stackPos) { $this->semValue = $this->semStack[$stackPos - (1 - 1)]; }, 307 => function ($stackPos) { $this->semValue = new Expr\Clone_($this->semStack[$stackPos - (2 - 2)], $this->startAttributeStack[$stackPos - (2 - 1)] + $this->endAttributes); }, 308 => function ($stackPos) { $this->semValue = new Expr\AssignOp\Plus($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); }, 309 => function ($stackPos) { $this->semValue = new Expr\AssignOp\Minus($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); }, 310 => function ($stackPos) { $this->semValue = new Expr\AssignOp\Mul($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); }, 311 => function ($stackPos) { $this->semValue = new Expr\AssignOp\Div($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); }, 312 => function ($stackPos) { $this->semValue = new Expr\AssignOp\Concat($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); }, 313 => function ($stackPos) { $this->semValue = new Expr\AssignOp\Mod($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); }, 314 => function ($stackPos) { $this->semValue = new Expr\AssignOp\BitwiseAnd($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); }, 315 => function ($stackPos) { $this->semValue = new Expr\AssignOp\BitwiseOr($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); }, 316 => function ($stackPos) { $this->semValue = new Expr\AssignOp\BitwiseXor($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); }, 317 => function ($stackPos) { $this->semValue = new Expr\AssignOp\ShiftLeft($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); }, 318 => function ($stackPos) { $this->semValue = new Expr\AssignOp\ShiftRight($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); }, 319 => function ($stackPos) { $this->semValue = new Expr\AssignOp\Pow($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); }, 320 => function ($stackPos) { $this->semValue = new Expr\AssignOp\Coalesce($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); }, 321 => function ($stackPos) { $this->semValue = new Expr\PostInc($this->semStack[$stackPos - (2 - 1)], $this->startAttributeStack[$stackPos - (2 - 1)] + $this->endAttributes); }, 322 => function ($stackPos) { $this->semValue = new Expr\PreInc($this->semStack[$stackPos - (2 - 2)], $this->startAttributeStack[$stackPos - (2 - 1)] + $this->endAttributes); }, 323 => function ($stackPos) { $this->semValue = new Expr\PostDec($this->semStack[$stackPos - (2 - 1)], $this->startAttributeStack[$stackPos - (2 - 1)] + $this->endAttributes); }, 324 => function ($stackPos) { $this->semValue = new Expr\PreDec($this->semStack[$stackPos - (2 - 2)], $this->startAttributeStack[$stackPos - (2 - 1)] + $this->endAttributes); }, 325 => function ($stackPos) { $this->semValue = new Expr\BinaryOp\BooleanOr($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); }, 326 => function ($stackPos) { $this->semValue = new Expr\BinaryOp\BooleanAnd($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); }, 327 => function ($stackPos) { $this->semValue = new Expr\BinaryOp\LogicalOr($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); }, 328 => function ($stackPos) { $this->semValue = new Expr\BinaryOp\LogicalAnd($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); }, 329 => function ($stackPos) { $this->semValue = new Expr\BinaryOp\LogicalXor($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); }, 330 => function ($stackPos) { $this->semValue = new Expr\BinaryOp\BitwiseOr($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); }, 331 => function ($stackPos) { $this->semValue = new Expr\BinaryOp\BitwiseAnd($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); }, 332 => function ($stackPos) { $this->semValue = new Expr\BinaryOp\BitwiseAnd($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); }, 333 => function ($stackPos) { $this->semValue = new Expr\BinaryOp\BitwiseXor($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); }, 334 => function ($stackPos) { $this->semValue = new Expr\BinaryOp\Concat($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); }, 335 => function ($stackPos) { $this->semValue = new Expr\BinaryOp\Plus($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); }, 336 => function ($stackPos) { $this->semValue = new Expr\BinaryOp\Minus($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); }, 337 => function ($stackPos) { $this->semValue = new Expr\BinaryOp\Mul($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); }, 338 => function ($stackPos) { $this->semValue = new Expr\BinaryOp\Div($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); }, 339 => function ($stackPos) { $this->semValue = new Expr\BinaryOp\Mod($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); }, 340 => function ($stackPos) { $this->semValue = new Expr\BinaryOp\ShiftLeft($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); }, 341 => function ($stackPos) { $this->semValue = new Expr\BinaryOp\ShiftRight($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); }, 342 => function ($stackPos) { $this->semValue = new Expr\BinaryOp\Pow($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); }, 343 => function ($stackPos) { $this->semValue = new Expr\UnaryPlus($this->semStack[$stackPos - (2 - 2)], $this->startAttributeStack[$stackPos - (2 - 1)] + $this->endAttributes); }, 344 => function ($stackPos) { $this->semValue = new Expr\UnaryMinus($this->semStack[$stackPos - (2 - 2)], $this->startAttributeStack[$stackPos - (2 - 1)] + $this->endAttributes); }, 345 => function ($stackPos) { $this->semValue = new Expr\BooleanNot($this->semStack[$stackPos - (2 - 2)], $this->startAttributeStack[$stackPos - (2 - 1)] + $this->endAttributes); }, 346 => function ($stackPos) { $this->semValue = new Expr\BitwiseNot($this->semStack[$stackPos - (2 - 2)], $this->startAttributeStack[$stackPos - (2 - 1)] + $this->endAttributes); }, 347 => function ($stackPos) { $this->semValue = new Expr\BinaryOp\Identical($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); }, 348 => function ($stackPos) { $this->semValue = new Expr\BinaryOp\NotIdentical($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); }, 349 => function ($stackPos) { $this->semValue = new Expr\BinaryOp\Equal($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); }, 350 => function ($stackPos) { $this->semValue = new Expr\BinaryOp\NotEqual($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); }, 351 => function ($stackPos) { $this->semValue = new Expr\BinaryOp\Spaceship($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); }, 352 => function ($stackPos) { $this->semValue = new Expr\BinaryOp\Smaller($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); }, 353 => function ($stackPos) { $this->semValue = new Expr\BinaryOp\SmallerOrEqual($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); }, 354 => function ($stackPos) { $this->semValue = new Expr\BinaryOp\Greater($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); }, 355 => function ($stackPos) { $this->semValue = new Expr\BinaryOp\GreaterOrEqual($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); }, 356 => function ($stackPos) { $this->semValue = new Expr\Instanceof_($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); }, 357 => function ($stackPos) { $this->semValue = $this->semStack[$stackPos - (1 - 1)]; }, 358 => function ($stackPos) { $this->semValue = $this->semStack[$stackPos - (3 - 2)]; }, 359 => function ($stackPos) { $this->semValue = new Expr\Ternary($this->semStack[$stackPos - (5 - 1)], $this->semStack[$stackPos - (5 - 3)], $this->semStack[$stackPos - (5 - 5)], $this->startAttributeStack[$stackPos - (5 - 1)] + $this->endAttributes); }, 360 => function ($stackPos) { $this->semValue = new Expr\Ternary($this->semStack[$stackPos - (4 - 1)], null, $this->semStack[$stackPos - (4 - 4)], $this->startAttributeStack[$stackPos - (4 - 1)] + $this->endAttributes); }, 361 => function ($stackPos) { $this->semValue = new Expr\BinaryOp\Coalesce($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); }, 362 => function ($stackPos) { $this->semValue = new Expr\Isset_($this->semStack[$stackPos - (4 - 3)], $this->startAttributeStack[$stackPos - (4 - 1)] + $this->endAttributes); }, 363 => function ($stackPos) { $this->semValue = new Expr\Empty_($this->semStack[$stackPos - (4 - 3)], $this->startAttributeStack[$stackPos - (4 - 1)] + $this->endAttributes); }, 364 => function ($stackPos) { $this->semValue = new Expr\Include_($this->semStack[$stackPos - (2 - 2)], Expr\Include_::TYPE_INCLUDE, $this->startAttributeStack[$stackPos - (2 - 1)] + $this->endAttributes); }, 365 => function ($stackPos) { $this->semValue = new Expr\Include_($this->semStack[$stackPos - (2 - 2)], Expr\Include_::TYPE_INCLUDE_ONCE, $this->startAttributeStack[$stackPos - (2 - 1)] + $this->endAttributes); }, 366 => function ($stackPos) { $this->semValue = new Expr\Eval_($this->semStack[$stackPos - (2 - 2)], $this->startAttributeStack[$stackPos - (2 - 1)] + $this->endAttributes); }, 367 => function ($stackPos) { $this->semValue = new Expr\Include_($this->semStack[$stackPos - (2 - 2)], Expr\Include_::TYPE_REQUIRE, $this->startAttributeStack[$stackPos - (2 - 1)] + $this->endAttributes); }, 368 => function ($stackPos) { $this->semValue = new Expr\Include_($this->semStack[$stackPos - (2 - 2)], Expr\Include_::TYPE_REQUIRE_ONCE, $this->startAttributeStack[$stackPos - (2 - 1)] + $this->endAttributes); }, 369 => function ($stackPos) { $this->semValue = new Expr\Cast\Int_($this->semStack[$stackPos - (2 - 2)], $this->startAttributeStack[$stackPos - (2 - 1)] + $this->endAttributes); }, 370 => function ($stackPos) { $attrs = $this->startAttributeStack[$stackPos - (2 - 1)] + $this->endAttributes; $attrs['kind'] = $this->getFloatCastKind($this->semStack[$stackPos - (2 - 1)]); $this->semValue = new Expr\Cast\Double($this->semStack[$stackPos - (2 - 2)], $attrs); }, 371 => function ($stackPos) { $this->semValue = new Expr\Cast\String_($this->semStack[$stackPos - (2 - 2)], $this->startAttributeStack[$stackPos - (2 - 1)] + $this->endAttributes); }, 372 => function ($stackPos) { $this->semValue = new Expr\Cast\Array_($this->semStack[$stackPos - (2 - 2)], $this->startAttributeStack[$stackPos - (2 - 1)] + $this->endAttributes); }, 373 => function ($stackPos) { $this->semValue = new Expr\Cast\Object_($this->semStack[$stackPos - (2 - 2)], $this->startAttributeStack[$stackPos - (2 - 1)] + $this->endAttributes); }, 374 => function ($stackPos) { $this->semValue = new Expr\Cast\Bool_($this->semStack[$stackPos - (2 - 2)], $this->startAttributeStack[$stackPos - (2 - 1)] + $this->endAttributes); }, 375 => function ($stackPos) { $this->semValue = new Expr\Cast\Unset_($this->semStack[$stackPos - (2 - 2)], $this->startAttributeStack[$stackPos - (2 - 1)] + $this->endAttributes); }, 376 => function ($stackPos) { $attrs = $this->startAttributeStack[$stackPos - (2 - 1)] + $this->endAttributes; $attrs['kind'] = \strtolower($this->semStack[$stackPos - (2 - 1)]) === 'exit' ? Expr\Exit_::KIND_EXIT : Expr\Exit_::KIND_DIE; $this->semValue = new Expr\Exit_($this->semStack[$stackPos - (2 - 2)], $attrs); }, 377 => function ($stackPos) { $this->semValue = new Expr\ErrorSuppress($this->semStack[$stackPos - (2 - 2)], $this->startAttributeStack[$stackPos - (2 - 1)] + $this->endAttributes); }, 378 => function ($stackPos) { $this->semValue = $this->semStack[$stackPos - (1 - 1)]; }, 379 => function ($stackPos) { $this->semValue = $this->semStack[$stackPos - (1 - 1)]; }, 380 => function ($stackPos) { $this->semValue = $this->semStack[$stackPos - (1 - 1)]; }, 381 => function ($stackPos) { $this->semValue = new Expr\ShellExec($this->semStack[$stackPos - (3 - 2)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); }, 382 => function ($stackPos) { $this->semValue = new Expr\Print_($this->semStack[$stackPos - (2 - 2)], $this->startAttributeStack[$stackPos - (2 - 1)] + $this->endAttributes); }, 383 => function ($stackPos) { $this->semValue = new Expr\Yield_(null, null, $this->startAttributeStack[$stackPos - (1 - 1)] + $this->endAttributes); }, 384 => function ($stackPos) { $this->semValue = new Expr\YieldFrom($this->semStack[$stackPos - (2 - 2)], $this->startAttributeStack[$stackPos - (2 - 1)] + $this->endAttributes); }, 385 => function ($stackPos) { $this->semValue = new Expr\Closure(['static' => \false, 'byRef' => $this->semStack[$stackPos - (10 - 2)], 'params' => $this->semStack[$stackPos - (10 - 4)], 'uses' => $this->semStack[$stackPos - (10 - 6)], 'returnType' => $this->semStack[$stackPos - (10 - 7)], 'stmts' => $this->semStack[$stackPos - (10 - 9)]], $this->startAttributeStack[$stackPos - (10 - 1)] + $this->endAttributes); }, 386 => function ($stackPos) { $this->semValue = new Expr\Closure(['static' => \true, 'byRef' => $this->semStack[$stackPos - (11 - 3)], 'params' => $this->semStack[$stackPos - (11 - 5)], 'uses' => $this->semStack[$stackPos - (11 - 7)], 'returnType' => $this->semStack[$stackPos - (11 - 8)], 'stmts' => $this->semStack[$stackPos - (11 - 10)]], $this->startAttributeStack[$stackPos - (11 - 1)] + $this->endAttributes); }, 387 => function ($stackPos) { $this->semValue = $this->semStack[$stackPos - (3 - 2)]; }, 388 => function ($stackPos) { $this->semValue = $this->semStack[$stackPos - (3 - 2)]; }, 389 => function ($stackPos) { $this->semValue = new Expr\Yield_($this->semStack[$stackPos - (2 - 2)], null, $this->startAttributeStack[$stackPos - (2 - 1)] + $this->endAttributes); }, 390 => function ($stackPos) { $this->semValue = new Expr\Yield_($this->semStack[$stackPos - (4 - 4)], $this->semStack[$stackPos - (4 - 2)], $this->startAttributeStack[$stackPos - (4 - 1)] + $this->endAttributes); }, 391 => function ($stackPos) { $attrs = $this->startAttributeStack[$stackPos - (4 - 1)] + $this->endAttributes; $attrs['kind'] = Expr\Array_::KIND_LONG; $this->semValue = new Expr\Array_($this->semStack[$stackPos - (4 - 3)], $attrs); }, 392 => function ($stackPos) { $attrs = $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes; $attrs['kind'] = Expr\Array_::KIND_SHORT; $this->semValue = new Expr\Array_($this->semStack[$stackPos - (3 - 2)], $attrs); }, 393 => function ($stackPos) { $this->semValue = new Expr\ArrayDimFetch($this->semStack[$stackPos - (4 - 1)], $this->semStack[$stackPos - (4 - 3)], $this->startAttributeStack[$stackPos - (4 - 1)] + $this->endAttributes); }, 394 => function ($stackPos) { $this->semValue = new Expr\ArrayDimFetch(Scalar\String_::fromString($this->semStack[$stackPos - (4 - 1)], $this->startAttributeStack[$stackPos - (4 - 1)] + $this->endAttributes), $this->semStack[$stackPos - (4 - 3)], $this->startAttributeStack[$stackPos - (4 - 1)] + $this->endAttributes); }, 395 => function ($stackPos) { $this->semValue = new Expr\ArrayDimFetch($this->semStack[$stackPos - (4 - 1)], $this->semStack[$stackPos - (4 - 3)], $this->startAttributeStack[$stackPos - (4 - 1)] + $this->endAttributes); }, 396 => function ($stackPos) { $this->semValue = new Expr\ArrayDimFetch($this->semStack[$stackPos - (4 - 1)], $this->semStack[$stackPos - (4 - 3)], $this->startAttributeStack[$stackPos - (4 - 1)] + $this->endAttributes); }, 397 => function ($stackPos) { $this->semValue = array(new Stmt\Class_(null, ['type' => 0, 'extends' => $this->semStack[$stackPos - (7 - 3)], 'implements' => $this->semStack[$stackPos - (7 - 4)], 'stmts' => $this->semStack[$stackPos - (7 - 6)]], $this->startAttributeStack[$stackPos - (7 - 1)] + $this->endAttributes), $this->semStack[$stackPos - (7 - 2)]); $this->checkClass($this->semValue[0], -1); }, 398 => function ($stackPos) { $this->semValue = new Expr\New_($this->semStack[$stackPos - (3 - 2)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); }, 399 => function ($stackPos) { list($class, $ctorArgs) = $this->semStack[$stackPos - (2 - 2)]; $this->semValue = new Expr\New_($class, $ctorArgs, $this->startAttributeStack[$stackPos - (2 - 1)] + $this->endAttributes); }, 400 => function ($stackPos) { $this->semValue = array(); }, 401 => function ($stackPos) { $this->semValue = $this->semStack[$stackPos - (4 - 3)]; }, 402 => function ($stackPos) { $this->semValue = array($this->semStack[$stackPos - (1 - 1)]); }, 403 => function ($stackPos) { $this->semStack[$stackPos - (3 - 1)][] = $this->semStack[$stackPos - (3 - 3)]; $this->semValue = $this->semStack[$stackPos - (3 - 1)]; }, 404 => function ($stackPos) { $this->semValue = new Expr\ClosureUse($this->semStack[$stackPos - (2 - 2)], $this->semStack[$stackPos - (2 - 1)], $this->startAttributeStack[$stackPos - (2 - 1)] + $this->endAttributes); }, 405 => function ($stackPos) { $this->semValue = new Name($this->semStack[$stackPos - (1 - 1)], $this->startAttributeStack[$stackPos - (1 - 1)] + $this->endAttributes); }, 406 => function ($stackPos) { $this->semValue = new Expr\FuncCall($this->semStack[$stackPos - (2 - 1)], $this->semStack[$stackPos - (2 - 2)], $this->startAttributeStack[$stackPos - (2 - 1)] + $this->endAttributes); }, 407 => function ($stackPos) { $this->semValue = new Expr\FuncCall($this->semStack[$stackPos - (2 - 1)], $this->semStack[$stackPos - (2 - 2)], $this->startAttributeStack[$stackPos - (2 - 1)] + $this->endAttributes); }, 408 => function ($stackPos) { $this->semValue = new Expr\StaticCall($this->semStack[$stackPos - (4 - 1)], $this->semStack[$stackPos - (4 - 3)], $this->semStack[$stackPos - (4 - 4)], $this->startAttributeStack[$stackPos - (4 - 1)] + $this->endAttributes); }, 409 => function ($stackPos) { $this->semValue = new Expr\StaticCall($this->semStack[$stackPos - (6 - 1)], $this->semStack[$stackPos - (6 - 4)], $this->semStack[$stackPos - (6 - 6)], $this->startAttributeStack[$stackPos - (6 - 1)] + $this->endAttributes); }, 410 => function ($stackPos) { $this->semValue = $this->fixupPhp5StaticPropCall($this->semStack[$stackPos - (2 - 1)], $this->semStack[$stackPos - (2 - 2)], $this->startAttributeStack[$stackPos - (2 - 1)] + $this->endAttributes); }, 411 => function ($stackPos) { $this->semValue = new Expr\FuncCall($this->semStack[$stackPos - (2 - 1)], $this->semStack[$stackPos - (2 - 2)], $this->startAttributeStack[$stackPos - (2 - 1)] + $this->endAttributes); }, 412 => function ($stackPos) { $this->semValue = new Expr\ArrayDimFetch($this->semStack[$stackPos - (4 - 1)], $this->semStack[$stackPos - (4 - 3)], $this->startAttributeStack[$stackPos - (4 - 1)] + $this->endAttributes); }, 413 => function ($stackPos) { $this->semValue = new Name($this->semStack[$stackPos - (1 - 1)], $this->startAttributeStack[$stackPos - (1 - 1)] + $this->endAttributes); }, 414 => function ($stackPos) { $this->semValue = $this->semStack[$stackPos - (1 - 1)]; }, 415 => function ($stackPos) { $this->semValue = new Name($this->semStack[$stackPos - (1 - 1)], $this->startAttributeStack[$stackPos - (1 - 1)] + $this->endAttributes); }, 416 => function ($stackPos) { $this->semValue = new Name($this->semStack[$stackPos - (1 - 1)], $this->startAttributeStack[$stackPos - (1 - 1)] + $this->endAttributes); }, 417 => function ($stackPos) { $this->semValue = new Name\FullyQualified(\substr($this->semStack[$stackPos - (1 - 1)], 1), $this->startAttributeStack[$stackPos - (1 - 1)] + $this->endAttributes); }, 418 => function ($stackPos) { $this->semValue = new Name\Relative(\substr($this->semStack[$stackPos - (1 - 1)], 10), $this->startAttributeStack[$stackPos - (1 - 1)] + $this->endAttributes); }, 419 => function ($stackPos) { $this->semValue = $this->semStack[$stackPos - (1 - 1)]; }, 420 => function ($stackPos) { $this->semValue = $this->semStack[$stackPos - (1 - 1)]; }, 421 => function ($stackPos) { $this->semValue = $this->semStack[$stackPos - (1 - 1)]; }, 422 => function ($stackPos) { $this->semValue = $this->semStack[$stackPos - (1 - 1)]; }, 423 => function ($stackPos) { $this->semValue = $this->semStack[$stackPos - (1 - 1)]; }, 424 => function ($stackPos) { $this->semValue = $this->semStack[$stackPos - (1 - 1)]; }, 425 => function ($stackPos) { $this->semValue = new Expr\PropertyFetch($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); }, 426 => function ($stackPos) { $this->semValue = new Expr\PropertyFetch($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); }, 427 => function ($stackPos) { $this->semValue = new Expr\ArrayDimFetch($this->semStack[$stackPos - (4 - 1)], $this->semStack[$stackPos - (4 - 3)], $this->startAttributeStack[$stackPos - (4 - 1)] + $this->endAttributes); }, 428 => function ($stackPos) { $this->semValue = new Expr\ArrayDimFetch($this->semStack[$stackPos - (4 - 1)], $this->semStack[$stackPos - (4 - 3)], $this->startAttributeStack[$stackPos - (4 - 1)] + $this->endAttributes); }, 429 => function ($stackPos) { $this->semValue = null; }, 430 => function ($stackPos) { $this->semValue = null; }, 431 => function ($stackPos) { $this->semValue = $this->semStack[$stackPos - (1 - 1)]; }, 432 => function ($stackPos) { $this->semValue = array(); }, 433 => function ($stackPos) { $this->semValue = array(new Scalar\EncapsedStringPart(Scalar\String_::parseEscapeSequences($this->semStack[$stackPos - (1 - 1)], '`', \false), $this->startAttributeStack[$stackPos - (1 - 1)] + $this->endAttributes)); }, 434 => function ($stackPos) { foreach ($this->semStack[$stackPos - (1 - 1)] as $s) { if ($s instanceof Node\Scalar\EncapsedStringPart) { $s->value = Node\Scalar\String_::parseEscapeSequences($s->value, '`', \false); } } $this->semValue = $this->semStack[$stackPos - (1 - 1)]; }, 435 => function ($stackPos) { $this->semValue = array(); }, 436 => function ($stackPos) { $this->semValue = $this->semStack[$stackPos - (1 - 1)]; }, 437 => function ($stackPos) { $this->semValue = $this->parseLNumber($this->semStack[$stackPos - (1 - 1)], $this->startAttributeStack[$stackPos - (1 - 1)] + $this->endAttributes, \true); }, 438 => function ($stackPos) { $this->semValue = Scalar\DNumber::fromString($this->semStack[$stackPos - (1 - 1)], $this->startAttributeStack[$stackPos - (1 - 1)] + $this->endAttributes); }, 439 => function ($stackPos) { $this->semValue = Scalar\String_::fromString($this->semStack[$stackPos - (1 - 1)], $this->startAttributeStack[$stackPos - (1 - 1)] + $this->endAttributes, \false); }, 440 => function ($stackPos) { $this->semValue = new Scalar\MagicConst\Line($this->startAttributeStack[$stackPos - (1 - 1)] + $this->endAttributes); }, 441 => function ($stackPos) { $this->semValue = new Scalar\MagicConst\File($this->startAttributeStack[$stackPos - (1 - 1)] + $this->endAttributes); }, 442 => function ($stackPos) { $this->semValue = new Scalar\MagicConst\Dir($this->startAttributeStack[$stackPos - (1 - 1)] + $this->endAttributes); }, 443 => function ($stackPos) { $this->semValue = new Scalar\MagicConst\Class_($this->startAttributeStack[$stackPos - (1 - 1)] + $this->endAttributes); }, 444 => function ($stackPos) { $this->semValue = new Scalar\MagicConst\Trait_($this->startAttributeStack[$stackPos - (1 - 1)] + $this->endAttributes); }, 445 => function ($stackPos) { $this->semValue = new Scalar\MagicConst\Method($this->startAttributeStack[$stackPos - (1 - 1)] + $this->endAttributes); }, 446 => function ($stackPos) { $this->semValue = new Scalar\MagicConst\Function_($this->startAttributeStack[$stackPos - (1 - 1)] + $this->endAttributes); }, 447 => function ($stackPos) { $this->semValue = new Scalar\MagicConst\Namespace_($this->startAttributeStack[$stackPos - (1 - 1)] + $this->endAttributes); }, 448 => function ($stackPos) { $this->semValue = $this->parseDocString($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 2)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes, $this->startAttributeStack[$stackPos - (3 - 3)] + $this->endAttributeStack[$stackPos - (3 - 3)], \false); }, 449 => function ($stackPos) { $this->semValue = $this->parseDocString($this->semStack[$stackPos - (2 - 1)], '', $this->semStack[$stackPos - (2 - 2)], $this->startAttributeStack[$stackPos - (2 - 1)] + $this->endAttributes, $this->startAttributeStack[$stackPos - (2 - 2)] + $this->endAttributeStack[$stackPos - (2 - 2)], \false); }, 450 => function ($stackPos) { $this->semValue = $this->semStack[$stackPos - (1 - 1)]; }, 451 => function ($stackPos) { $this->semValue = new Expr\ClassConstFetch($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); }, 452 => function ($stackPos) { $this->semValue = new Expr\ConstFetch($this->semStack[$stackPos - (1 - 1)], $this->startAttributeStack[$stackPos - (1 - 1)] + $this->endAttributes); }, 453 => function ($stackPos) { $this->semValue = new Expr\Array_($this->semStack[$stackPos - (4 - 3)], $this->startAttributeStack[$stackPos - (4 - 1)] + $this->endAttributes); }, 454 => function ($stackPos) { $this->semValue = new Expr\Array_($this->semStack[$stackPos - (3 - 2)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); }, 455 => function ($stackPos) { $this->semValue = $this->semStack[$stackPos - (1 - 1)]; }, 456 => function ($stackPos) { $this->semValue = new Expr\BinaryOp\BooleanOr($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); }, 457 => function ($stackPos) { $this->semValue = new Expr\BinaryOp\BooleanAnd($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); }, 458 => function ($stackPos) { $this->semValue = new Expr\BinaryOp\LogicalOr($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); }, 459 => function ($stackPos) { $this->semValue = new Expr\BinaryOp\LogicalAnd($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); }, 460 => function ($stackPos) { $this->semValue = new Expr\BinaryOp\LogicalXor($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); }, 461 => function ($stackPos) { $this->semValue = new Expr\BinaryOp\BitwiseOr($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); }, 462 => function ($stackPos) { $this->semValue = new Expr\BinaryOp\BitwiseAnd($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); }, 463 => function ($stackPos) { $this->semValue = new Expr\BinaryOp\BitwiseAnd($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); }, 464 => function ($stackPos) { $this->semValue = new Expr\BinaryOp\BitwiseXor($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); }, 465 => function ($stackPos) { $this->semValue = new Expr\BinaryOp\Concat($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); }, 466 => function ($stackPos) { $this->semValue = new Expr\BinaryOp\Plus($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); }, 467 => function ($stackPos) { $this->semValue = new Expr\BinaryOp\Minus($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); }, 468 => function ($stackPos) { $this->semValue = new Expr\BinaryOp\Mul($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); }, 469 => function ($stackPos) { $this->semValue = new Expr\BinaryOp\Div($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); }, 470 => function ($stackPos) { $this->semValue = new Expr\BinaryOp\Mod($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); }, 471 => function ($stackPos) { $this->semValue = new Expr\BinaryOp\ShiftLeft($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); }, 472 => function ($stackPos) { $this->semValue = new Expr\BinaryOp\ShiftRight($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); }, 473 => function ($stackPos) { $this->semValue = new Expr\BinaryOp\Pow($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); }, 474 => function ($stackPos) { $this->semValue = new Expr\UnaryPlus($this->semStack[$stackPos - (2 - 2)], $this->startAttributeStack[$stackPos - (2 - 1)] + $this->endAttributes); }, 475 => function ($stackPos) { $this->semValue = new Expr\UnaryMinus($this->semStack[$stackPos - (2 - 2)], $this->startAttributeStack[$stackPos - (2 - 1)] + $this->endAttributes); }, 476 => function ($stackPos) { $this->semValue = new Expr\BooleanNot($this->semStack[$stackPos - (2 - 2)], $this->startAttributeStack[$stackPos - (2 - 1)] + $this->endAttributes); }, 477 => function ($stackPos) { $this->semValue = new Expr\BitwiseNot($this->semStack[$stackPos - (2 - 2)], $this->startAttributeStack[$stackPos - (2 - 1)] + $this->endAttributes); }, 478 => function ($stackPos) { $this->semValue = new Expr\BinaryOp\Identical($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); }, 479 => function ($stackPos) { $this->semValue = new Expr\BinaryOp\NotIdentical($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); }, 480 => function ($stackPos) { $this->semValue = new Expr\BinaryOp\Equal($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); }, 481 => function ($stackPos) { $this->semValue = new Expr\BinaryOp\NotEqual($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); }, 482 => function ($stackPos) { $this->semValue = new Expr\BinaryOp\Smaller($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); }, 483 => function ($stackPos) { $this->semValue = new Expr\BinaryOp\SmallerOrEqual($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); }, 484 => function ($stackPos) { $this->semValue = new Expr\BinaryOp\Greater($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); }, 485 => function ($stackPos) { $this->semValue = new Expr\BinaryOp\GreaterOrEqual($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); }, 486 => function ($stackPos) { $this->semValue = new Expr\Ternary($this->semStack[$stackPos - (5 - 1)], $this->semStack[$stackPos - (5 - 3)], $this->semStack[$stackPos - (5 - 5)], $this->startAttributeStack[$stackPos - (5 - 1)] + $this->endAttributes); }, 487 => function ($stackPos) { $this->semValue = new Expr\Ternary($this->semStack[$stackPos - (4 - 1)], null, $this->semStack[$stackPos - (4 - 4)], $this->startAttributeStack[$stackPos - (4 - 1)] + $this->endAttributes); }, 488 => function ($stackPos) { $this->semValue = new Expr\ArrayDimFetch($this->semStack[$stackPos - (4 - 1)], $this->semStack[$stackPos - (4 - 3)], $this->startAttributeStack[$stackPos - (4 - 1)] + $this->endAttributes); }, 489 => function ($stackPos) { $this->semValue = $this->semStack[$stackPos - (3 - 2)]; }, 490 => function ($stackPos) { $this->semValue = new Expr\ConstFetch($this->semStack[$stackPos - (1 - 1)], $this->startAttributeStack[$stackPos - (1 - 1)] + $this->endAttributes); }, 491 => function ($stackPos) { $this->semValue = new Expr\ClassConstFetch($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); }, 492 => function ($stackPos) { $this->semValue = $this->semStack[$stackPos - (1 - 1)]; }, 493 => function ($stackPos) { $this->semValue = $this->semStack[$stackPos - (1 - 1)]; }, 494 => function ($stackPos) { $attrs = $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes; $attrs['kind'] = Scalar\String_::KIND_DOUBLE_QUOTED; foreach ($this->semStack[$stackPos - (3 - 2)] as $s) { if ($s instanceof Node\Scalar\EncapsedStringPart) { $s->value = Node\Scalar\String_::parseEscapeSequences($s->value, '"', \true); } } $this->semValue = new Scalar\Encapsed($this->semStack[$stackPos - (3 - 2)], $attrs); }, 495 => function ($stackPos) { $this->semValue = $this->parseDocString($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 2)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes, $this->startAttributeStack[$stackPos - (3 - 3)] + $this->endAttributeStack[$stackPos - (3 - 3)], \true); }, 496 => function ($stackPos) { $this->semValue = array(); }, 497 => function ($stackPos) { $this->semValue = $this->semStack[$stackPos - (2 - 1)]; }, 498 => function ($stackPos) { $this->semValue = $this->semStack[$stackPos]; }, 499 => function ($stackPos) { $this->semValue = $this->semStack[$stackPos]; }, 500 => function ($stackPos) { $this->semStack[$stackPos - (3 - 1)][] = $this->semStack[$stackPos - (3 - 3)]; $this->semValue = $this->semStack[$stackPos - (3 - 1)]; }, 501 => function ($stackPos) { $this->semValue = array($this->semStack[$stackPos - (1 - 1)]); }, 502 => function ($stackPos) { $this->semValue = new Expr\ArrayItem($this->semStack[$stackPos - (3 - 3)], $this->semStack[$stackPos - (3 - 1)], \false, $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); }, 503 => function ($stackPos) { $this->semValue = new Expr\ArrayItem($this->semStack[$stackPos - (1 - 1)], null, \false, $this->startAttributeStack[$stackPos - (1 - 1)] + $this->endAttributes); }, 504 => function ($stackPos) { $this->semValue = $this->semStack[$stackPos - (1 - 1)]; }, 505 => function ($stackPos) { $this->semValue = $this->semStack[$stackPos - (1 - 1)]; }, 506 => function ($stackPos) { $this->semValue = $this->semStack[$stackPos - (1 - 1)]; }, 507 => function ($stackPos) { $this->semValue = $this->semStack[$stackPos - (1 - 1)]; }, 508 => function ($stackPos) { $this->semValue = new Expr\ArrayDimFetch($this->semStack[$stackPos - (6 - 2)], $this->semStack[$stackPos - (6 - 5)], $this->startAttributeStack[$stackPos - (6 - 1)] + $this->endAttributes); }, 509 => function ($stackPos) { $this->semValue = new Expr\ArrayDimFetch($this->semStack[$stackPos - (4 - 1)], $this->semStack[$stackPos - (4 - 3)], $this->startAttributeStack[$stackPos - (4 - 1)] + $this->endAttributes); }, 510 => function ($stackPos) { $this->semValue = new Expr\PropertyFetch($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); }, 511 => function ($stackPos) { $this->semValue = new Expr\MethodCall($this->semStack[$stackPos - (4 - 1)], $this->semStack[$stackPos - (4 - 3)], $this->semStack[$stackPos - (4 - 4)], $this->startAttributeStack[$stackPos - (4 - 1)] + $this->endAttributes); }, 512 => function ($stackPos) { $this->semValue = new Expr\FuncCall($this->semStack[$stackPos - (2 - 1)], $this->semStack[$stackPos - (2 - 2)], $this->startAttributeStack[$stackPos - (2 - 1)] + $this->endAttributes); }, 513 => function ($stackPos) { $this->semValue = new Expr\ArrayDimFetch($this->semStack[$stackPos - (4 - 1)], $this->semStack[$stackPos - (4 - 3)], $this->startAttributeStack[$stackPos - (4 - 1)] + $this->endAttributes); }, 514 => function ($stackPos) { $this->semValue = new Expr\ArrayDimFetch($this->semStack[$stackPos - (4 - 1)], $this->semStack[$stackPos - (4 - 3)], $this->startAttributeStack[$stackPos - (4 - 1)] + $this->endAttributes); }, 515 => function ($stackPos) { $this->semValue = $this->semStack[$stackPos - (1 - 1)]; }, 516 => function ($stackPos) { $this->semValue = $this->semStack[$stackPos - (3 - 2)]; }, 517 => function ($stackPos) { $this->semValue = $this->semStack[$stackPos - (1 - 1)]; }, 518 => function ($stackPos) { $this->semValue = new Expr\Variable($this->semStack[$stackPos - (2 - 2)], $this->startAttributeStack[$stackPos - (2 - 1)] + $this->endAttributes); }, 519 => function ($stackPos) { $this->semValue = $this->semStack[$stackPos - (1 - 1)]; }, 520 => function ($stackPos) { $this->semValue = $this->semStack[$stackPos - (1 - 1)]; }, 521 => function ($stackPos) { $this->semValue = new Expr\StaticPropertyFetch($this->semStack[$stackPos - (4 - 1)], $this->semStack[$stackPos - (4 - 4)], $this->startAttributeStack[$stackPos - (4 - 1)] + $this->endAttributes); }, 522 => function ($stackPos) { $this->semValue = $this->semStack[$stackPos - (1 - 1)]; }, 523 => function ($stackPos) { $var = \substr($this->semStack[$stackPos - (1 - 1)], 1); $this->semValue = \is_string($var) ? new Node\VarLikeIdentifier($var, $this->startAttributeStack[$stackPos - (1 - 1)] + $this->endAttributes) : $var; }, 524 => function ($stackPos) { $this->semValue = new Expr\StaticPropertyFetch($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); }, 525 => function ($stackPos) { $this->semValue = new Expr\StaticPropertyFetch($this->semStack[$stackPos - (6 - 1)], $this->semStack[$stackPos - (6 - 5)], $this->startAttributeStack[$stackPos - (6 - 1)] + $this->endAttributes); }, 526 => function ($stackPos) { $this->semValue = new Expr\ArrayDimFetch($this->semStack[$stackPos - (4 - 1)], $this->semStack[$stackPos - (4 - 3)], $this->startAttributeStack[$stackPos - (4 - 1)] + $this->endAttributes); }, 527 => function ($stackPos) { $this->semValue = new Expr\ArrayDimFetch($this->semStack[$stackPos - (4 - 1)], $this->semStack[$stackPos - (4 - 3)], $this->startAttributeStack[$stackPos - (4 - 1)] + $this->endAttributes); }, 528 => function ($stackPos) { $this->semValue = new Expr\ArrayDimFetch($this->semStack[$stackPos - (4 - 1)], $this->semStack[$stackPos - (4 - 3)], $this->startAttributeStack[$stackPos - (4 - 1)] + $this->endAttributes); }, 529 => function ($stackPos) { $this->semValue = new Expr\ArrayDimFetch($this->semStack[$stackPos - (4 - 1)], $this->semStack[$stackPos - (4 - 3)], $this->startAttributeStack[$stackPos - (4 - 1)] + $this->endAttributes); }, 530 => function ($stackPos) { $this->semValue = $this->semStack[$stackPos - (1 - 1)]; }, 531 => function ($stackPos) { $this->semValue = new Expr\Variable($this->semStack[$stackPos - (4 - 3)], $this->startAttributeStack[$stackPos - (4 - 1)] + $this->endAttributes); }, 532 => function ($stackPos) { $this->semValue = null; }, 533 => function ($stackPos) { $this->semValue = $this->semStack[$stackPos - (1 - 1)]; }, 534 => function ($stackPos) { $this->semValue = $this->semStack[$stackPos - (1 - 1)]; }, 535 => function ($stackPos) { $this->semValue = $this->semStack[$stackPos - (3 - 2)]; }, 536 => function ($stackPos) { $this->semValue = $this->semStack[$stackPos - (1 - 1)]; }, 537 => function ($stackPos) { $this->semValue = new Expr\Error($this->startAttributeStack[$stackPos - (1 - 1)] + $this->endAttributes); $this->errorState = 2; }, 538 => function ($stackPos) { $this->semValue = new Expr\List_($this->semStack[$stackPos - (4 - 3)], $this->startAttributeStack[$stackPos - (4 - 1)] + $this->endAttributes); }, 539 => function ($stackPos) { $this->semStack[$stackPos - (3 - 1)][] = $this->semStack[$stackPos - (3 - 3)]; $this->semValue = $this->semStack[$stackPos - (3 - 1)]; }, 540 => function ($stackPos) { $this->semValue = array($this->semStack[$stackPos - (1 - 1)]); }, 541 => function ($stackPos) { $this->semValue = new Expr\ArrayItem($this->semStack[$stackPos - (1 - 1)], null, \false, $this->startAttributeStack[$stackPos - (1 - 1)] + $this->endAttributes); }, 542 => function ($stackPos) { $this->semValue = new Expr\ArrayItem($this->semStack[$stackPos - (1 - 1)], null, \false, $this->startAttributeStack[$stackPos - (1 - 1)] + $this->endAttributes); }, 543 => function ($stackPos) { $this->semValue = null; }, 544 => function ($stackPos) { $this->semValue = array(); }, 545 => function ($stackPos) { $this->semValue = $this->semStack[$stackPos - (2 - 1)]; }, 546 => function ($stackPos) { $this->semStack[$stackPos - (3 - 1)][] = $this->semStack[$stackPos - (3 - 3)]; $this->semValue = $this->semStack[$stackPos - (3 - 1)]; }, 547 => function ($stackPos) { $this->semValue = array($this->semStack[$stackPos - (1 - 1)]); }, 548 => function ($stackPos) { $this->semValue = new Expr\ArrayItem($this->semStack[$stackPos - (3 - 3)], $this->semStack[$stackPos - (3 - 1)], \false, $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); }, 549 => function ($stackPos) { $this->semValue = new Expr\ArrayItem($this->semStack[$stackPos - (1 - 1)], null, \false, $this->startAttributeStack[$stackPos - (1 - 1)] + $this->endAttributes); }, 550 => function ($stackPos) { $this->semValue = new Expr\ArrayItem($this->semStack[$stackPos - (4 - 4)], $this->semStack[$stackPos - (4 - 1)], \true, $this->startAttributeStack[$stackPos - (4 - 1)] + $this->endAttributes); }, 551 => function ($stackPos) { $this->semValue = new Expr\ArrayItem($this->semStack[$stackPos - (2 - 2)], null, \true, $this->startAttributeStack[$stackPos - (2 - 1)] + $this->endAttributes); }, 552 => function ($stackPos) { $this->semValue = new Expr\ArrayItem($this->semStack[$stackPos - (2 - 2)], null, \false, $this->startAttributeStack[$stackPos - (2 - 1)] + $this->endAttributes, \true); }, 553 => function ($stackPos) { $this->semStack[$stackPos - (2 - 1)][] = $this->semStack[$stackPos - (2 - 2)]; $this->semValue = $this->semStack[$stackPos - (2 - 1)]; }, 554 => function ($stackPos) { $this->semStack[$stackPos - (2 - 1)][] = $this->semStack[$stackPos - (2 - 2)]; $this->semValue = $this->semStack[$stackPos - (2 - 1)]; }, 555 => function ($stackPos) { $this->semValue = array($this->semStack[$stackPos - (1 - 1)]); }, 556 => function ($stackPos) { $this->semValue = array($this->semStack[$stackPos - (2 - 1)], $this->semStack[$stackPos - (2 - 2)]); }, 557 => function ($stackPos) { $this->semValue = new Scalar\EncapsedStringPart($this->semStack[$stackPos - (1 - 1)], $this->startAttributeStack[$stackPos - (1 - 1)] + $this->endAttributes); }, 558 => function ($stackPos) { $this->semValue = new Expr\Variable($this->semStack[$stackPos - (1 - 1)], $this->startAttributeStack[$stackPos - (1 - 1)] + $this->endAttributes); }, 559 => function ($stackPos) { $this->semValue = $this->semStack[$stackPos - (1 - 1)]; }, 560 => function ($stackPos) { $this->semValue = new Expr\ArrayDimFetch($this->semStack[$stackPos - (4 - 1)], $this->semStack[$stackPos - (4 - 3)], $this->startAttributeStack[$stackPos - (4 - 1)] + $this->endAttributes); }, 561 => function ($stackPos) { $this->semValue = new Expr\PropertyFetch($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); }, 562 => function ($stackPos) { $this->semValue = new Expr\Variable($this->semStack[$stackPos - (3 - 2)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); }, 563 => function ($stackPos) { $this->semValue = new Expr\Variable($this->semStack[$stackPos - (3 - 2)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); }, 564 => function ($stackPos) { $this->semValue = new Expr\ArrayDimFetch($this->semStack[$stackPos - (6 - 2)], $this->semStack[$stackPos - (6 - 4)], $this->startAttributeStack[$stackPos - (6 - 1)] + $this->endAttributes); }, 565 => function ($stackPos) { $this->semValue = $this->semStack[$stackPos - (3 - 2)]; }, 566 => function ($stackPos) { $this->semValue = new Scalar\String_($this->semStack[$stackPos - (1 - 1)], $this->startAttributeStack[$stackPos - (1 - 1)] + $this->endAttributes); }, 567 => function ($stackPos) { $this->semValue = $this->parseNumString($this->semStack[$stackPos - (1 - 1)], $this->startAttributeStack[$stackPos - (1 - 1)] + $this->endAttributes); }, 568 => function ($stackPos) { $this->semValue = $this->semStack[$stackPos - (1 - 1)]; }]; } } parsers = $parsers; } public function parse(string $code, ?ErrorHandler $errorHandler = null) { if (null === $errorHandler) { $errorHandler = new ErrorHandler\Throwing(); } list($firstStmts, $firstError) = $this->tryParse($this->parsers[0], $errorHandler, $code); if ($firstError === null) { return $firstStmts; } for ($i = 1, $c = \count($this->parsers); $i < $c; ++$i) { list($stmts, $error) = $this->tryParse($this->parsers[$i], $errorHandler, $code); if ($error === null) { return $stmts; } } throw $firstError; } private function tryParse(Parser $parser, ErrorHandler $errorHandler, $code) { $stmts = null; $error = null; try { $stmts = $parser->parse($code, $errorHandler); } catch (Error $error) { } return [$stmts, $error]; } } pAttrGroups($node->attrGroups, \true) . $this->pModifiers($node->flags) . ($node->type ? $this->p($node->type) . ' ' : '') . ($node->byRef ? '&' : '') . ($node->variadic ? '...' : '') . $this->p($node->var) . ($node->default ? ' = ' . $this->p($node->default) : ''); } protected function pArg(Node\Arg $node) { return ($node->name ? $node->name->toString() . ': ' : '') . ($node->byRef ? '&' : '') . ($node->unpack ? '...' : '') . $this->p($node->value); } protected function pVariadicPlaceholder(Node\VariadicPlaceholder $node) { return '...'; } protected function pConst(Node\Const_ $node) { return $node->name . ' = ' . $this->p($node->value); } protected function pNullableType(Node\NullableType $node) { return '?' . $this->p($node->type); } protected function pUnionType(Node\UnionType $node) { $types = []; foreach ($node->types as $typeNode) { if ($typeNode instanceof Node\IntersectionType) { $types[] = '(' . $this->p($typeNode) . ')'; continue; } $types[] = $this->p($typeNode); } return \implode('|', $types); } protected function pIntersectionType(Node\IntersectionType $node) { return $this->pImplode($node->types, '&'); } protected function pIdentifier(Node\Identifier $node) { return $node->name; } protected function pVarLikeIdentifier(Node\VarLikeIdentifier $node) { return '$' . $node->name; } protected function pAttribute(Node\Attribute $node) { return $this->p($node->name) . ($node->args ? '(' . $this->pCommaSeparated($node->args) . ')' : ''); } protected function pAttributeGroup(Node\AttributeGroup $node) { return '#[' . $this->pCommaSeparated($node->attrs) . ']'; } // Names protected function pName(Name $node) { return \implode('\\', $node->parts); } protected function pName_FullyQualified(Name\FullyQualified $node) { return '\\' . \implode('\\', $node->parts); } protected function pName_Relative(Name\Relative $node) { return 'namespace\\' . \implode('\\', $node->parts); } // Magic Constants protected function pScalar_MagicConst_Class(MagicConst\Class_ $node) { return '__CLASS__'; } protected function pScalar_MagicConst_Dir(MagicConst\Dir $node) { return '__DIR__'; } protected function pScalar_MagicConst_File(MagicConst\File $node) { return '__FILE__'; } protected function pScalar_MagicConst_Function(MagicConst\Function_ $node) { return '__FUNCTION__'; } protected function pScalar_MagicConst_Line(MagicConst\Line $node) { return '__LINE__'; } protected function pScalar_MagicConst_Method(MagicConst\Method $node) { return '__METHOD__'; } protected function pScalar_MagicConst_Namespace(MagicConst\Namespace_ $node) { return '__NAMESPACE__'; } protected function pScalar_MagicConst_Trait(MagicConst\Trait_ $node) { return '__TRAIT__'; } // Scalars protected function pScalar_String(Scalar\String_ $node) { $kind = $node->getAttribute('kind', Scalar\String_::KIND_SINGLE_QUOTED); switch ($kind) { case Scalar\String_::KIND_NOWDOC: $label = $node->getAttribute('docLabel'); if ($label && !$this->containsEndLabel($node->value, $label)) { if ($node->value === '') { return "<<<'{$label}'\n{$label}" . $this->docStringEndToken; } return "<<<'{$label}'\n{$node->value}\n{$label}" . $this->docStringEndToken; } /* break missing intentionally */ case Scalar\String_::KIND_SINGLE_QUOTED: return $this->pSingleQuotedString($node->value); case Scalar\String_::KIND_HEREDOC: $label = $node->getAttribute('docLabel'); if ($label && !$this->containsEndLabel($node->value, $label)) { if ($node->value === '') { return "<<<{$label}\n{$label}" . $this->docStringEndToken; } $escaped = $this->escapeString($node->value, null); return "<<<{$label}\n" . $escaped . "\n{$label}" . $this->docStringEndToken; } /* break missing intentionally */ case Scalar\String_::KIND_DOUBLE_QUOTED: return '"' . $this->escapeString($node->value, '"') . '"'; } throw new \Exception('Invalid string kind'); } protected function pScalar_Encapsed(Scalar\Encapsed $node) { if ($node->getAttribute('kind') === Scalar\String_::KIND_HEREDOC) { $label = $node->getAttribute('docLabel'); if ($label && !$this->encapsedContainsEndLabel($node->parts, $label)) { if (\count($node->parts) === 1 && $node->parts[0] instanceof Scalar\EncapsedStringPart && $node->parts[0]->value === '') { return "<<<{$label}\n{$label}" . $this->docStringEndToken; } return "<<<{$label}\n" . $this->pEncapsList($node->parts, null) . "\n{$label}" . $this->docStringEndToken; } } return '"' . $this->pEncapsList($node->parts, '"') . '"'; } protected function pScalar_LNumber(Scalar\LNumber $node) { if ($node->value === -\PHP_INT_MAX - 1) { // PHP_INT_MIN cannot be represented as a literal, // because the sign is not part of the literal return '(-' . \PHP_INT_MAX . '-1)'; } $kind = $node->getAttribute('kind', Scalar\LNumber::KIND_DEC); if (Scalar\LNumber::KIND_DEC === $kind) { return (string) $node->value; } if ($node->value < 0) { $sign = '-'; $str = (string) -$node->value; } else { $sign = ''; $str = (string) $node->value; } switch ($kind) { case Scalar\LNumber::KIND_BIN: return $sign . '0b' . \base_convert($str, 10, 2); case Scalar\LNumber::KIND_OCT: return $sign . '0' . \base_convert($str, 10, 8); case Scalar\LNumber::KIND_HEX: return $sign . '0x' . \base_convert($str, 10, 16); } throw new \Exception('Invalid number kind'); } protected function pScalar_DNumber(Scalar\DNumber $node) { if (!\is_finite($node->value)) { if ($node->value === \INF) { return '\\INF'; } elseif ($node->value === -\INF) { return '-\\INF'; } else { return '\\NAN'; } } // Try to find a short full-precision representation $stringValue = \sprintf('%.16G', $node->value); if ($node->value !== (double) $stringValue) { $stringValue = \sprintf('%.17G', $node->value); } // %G is locale dependent and there exists no locale-independent alternative. We don't want // mess with switching locales here, so let's assume that a comma is the only non-standard // decimal separator we may encounter... $stringValue = \str_replace(',', '.', $stringValue); // ensure that number is really printed as float return \preg_match('/^-?[0-9]+$/', $stringValue) ? $stringValue . '.0' : $stringValue; } protected function pScalar_EncapsedStringPart(Scalar\EncapsedStringPart $node) { throw new \LogicException('Cannot directly print EncapsedStringPart'); } // Assignments protected function pExpr_Assign(Expr\Assign $node) { return $this->pInfixOp(Expr\Assign::class, $node->var, ' = ', $node->expr); } protected function pExpr_AssignRef(Expr\AssignRef $node) { return $this->pInfixOp(Expr\AssignRef::class, $node->var, ' =& ', $node->expr); } protected function pExpr_AssignOp_Plus(AssignOp\Plus $node) { return $this->pInfixOp(AssignOp\Plus::class, $node->var, ' += ', $node->expr); } protected function pExpr_AssignOp_Minus(AssignOp\Minus $node) { return $this->pInfixOp(AssignOp\Minus::class, $node->var, ' -= ', $node->expr); } protected function pExpr_AssignOp_Mul(AssignOp\Mul $node) { return $this->pInfixOp(AssignOp\Mul::class, $node->var, ' *= ', $node->expr); } protected function pExpr_AssignOp_Div(AssignOp\Div $node) { return $this->pInfixOp(AssignOp\Div::class, $node->var, ' /= ', $node->expr); } protected function pExpr_AssignOp_Concat(AssignOp\Concat $node) { return $this->pInfixOp(AssignOp\Concat::class, $node->var, ' .= ', $node->expr); } protected function pExpr_AssignOp_Mod(AssignOp\Mod $node) { return $this->pInfixOp(AssignOp\Mod::class, $node->var, ' %= ', $node->expr); } protected function pExpr_AssignOp_BitwiseAnd(AssignOp\BitwiseAnd $node) { return $this->pInfixOp(AssignOp\BitwiseAnd::class, $node->var, ' &= ', $node->expr); } protected function pExpr_AssignOp_BitwiseOr(AssignOp\BitwiseOr $node) { return $this->pInfixOp(AssignOp\BitwiseOr::class, $node->var, ' |= ', $node->expr); } protected function pExpr_AssignOp_BitwiseXor(AssignOp\BitwiseXor $node) { return $this->pInfixOp(AssignOp\BitwiseXor::class, $node->var, ' ^= ', $node->expr); } protected function pExpr_AssignOp_ShiftLeft(AssignOp\ShiftLeft $node) { return $this->pInfixOp(AssignOp\ShiftLeft::class, $node->var, ' <<= ', $node->expr); } protected function pExpr_AssignOp_ShiftRight(AssignOp\ShiftRight $node) { return $this->pInfixOp(AssignOp\ShiftRight::class, $node->var, ' >>= ', $node->expr); } protected function pExpr_AssignOp_Pow(AssignOp\Pow $node) { return $this->pInfixOp(AssignOp\Pow::class, $node->var, ' **= ', $node->expr); } protected function pExpr_AssignOp_Coalesce(AssignOp\Coalesce $node) { return $this->pInfixOp(AssignOp\Coalesce::class, $node->var, ' ??= ', $node->expr); } // Binary expressions protected function pExpr_BinaryOp_Plus(BinaryOp\Plus $node) { return $this->pInfixOp(BinaryOp\Plus::class, $node->left, ' + ', $node->right); } protected function pExpr_BinaryOp_Minus(BinaryOp\Minus $node) { return $this->pInfixOp(BinaryOp\Minus::class, $node->left, ' - ', $node->right); } protected function pExpr_BinaryOp_Mul(BinaryOp\Mul $node) { return $this->pInfixOp(BinaryOp\Mul::class, $node->left, ' * ', $node->right); } protected function pExpr_BinaryOp_Div(BinaryOp\Div $node) { return $this->pInfixOp(BinaryOp\Div::class, $node->left, ' / ', $node->right); } protected function pExpr_BinaryOp_Concat(BinaryOp\Concat $node) { return $this->pInfixOp(BinaryOp\Concat::class, $node->left, ' . ', $node->right); } protected function pExpr_BinaryOp_Mod(BinaryOp\Mod $node) { return $this->pInfixOp(BinaryOp\Mod::class, $node->left, ' % ', $node->right); } protected function pExpr_BinaryOp_BooleanAnd(BinaryOp\BooleanAnd $node) { return $this->pInfixOp(BinaryOp\BooleanAnd::class, $node->left, ' && ', $node->right); } protected function pExpr_BinaryOp_BooleanOr(BinaryOp\BooleanOr $node) { return $this->pInfixOp(BinaryOp\BooleanOr::class, $node->left, ' || ', $node->right); } protected function pExpr_BinaryOp_BitwiseAnd(BinaryOp\BitwiseAnd $node) { return $this->pInfixOp(BinaryOp\BitwiseAnd::class, $node->left, ' & ', $node->right); } protected function pExpr_BinaryOp_BitwiseOr(BinaryOp\BitwiseOr $node) { return $this->pInfixOp(BinaryOp\BitwiseOr::class, $node->left, ' | ', $node->right); } protected function pExpr_BinaryOp_BitwiseXor(BinaryOp\BitwiseXor $node) { return $this->pInfixOp(BinaryOp\BitwiseXor::class, $node->left, ' ^ ', $node->right); } protected function pExpr_BinaryOp_ShiftLeft(BinaryOp\ShiftLeft $node) { return $this->pInfixOp(BinaryOp\ShiftLeft::class, $node->left, ' << ', $node->right); } protected function pExpr_BinaryOp_ShiftRight(BinaryOp\ShiftRight $node) { return $this->pInfixOp(BinaryOp\ShiftRight::class, $node->left, ' >> ', $node->right); } protected function pExpr_BinaryOp_Pow(BinaryOp\Pow $node) { return $this->pInfixOp(BinaryOp\Pow::class, $node->left, ' ** ', $node->right); } protected function pExpr_BinaryOp_LogicalAnd(BinaryOp\LogicalAnd $node) { return $this->pInfixOp(BinaryOp\LogicalAnd::class, $node->left, ' and ', $node->right); } protected function pExpr_BinaryOp_LogicalOr(BinaryOp\LogicalOr $node) { return $this->pInfixOp(BinaryOp\LogicalOr::class, $node->left, ' or ', $node->right); } protected function pExpr_BinaryOp_LogicalXor(BinaryOp\LogicalXor $node) { return $this->pInfixOp(BinaryOp\LogicalXor::class, $node->left, ' xor ', $node->right); } protected function pExpr_BinaryOp_Equal(BinaryOp\Equal $node) { return $this->pInfixOp(BinaryOp\Equal::class, $node->left, ' == ', $node->right); } protected function pExpr_BinaryOp_NotEqual(BinaryOp\NotEqual $node) { return $this->pInfixOp(BinaryOp\NotEqual::class, $node->left, ' != ', $node->right); } protected function pExpr_BinaryOp_Identical(BinaryOp\Identical $node) { return $this->pInfixOp(BinaryOp\Identical::class, $node->left, ' === ', $node->right); } protected function pExpr_BinaryOp_NotIdentical(BinaryOp\NotIdentical $node) { return $this->pInfixOp(BinaryOp\NotIdentical::class, $node->left, ' !== ', $node->right); } protected function pExpr_BinaryOp_Spaceship(BinaryOp\Spaceship $node) { return $this->pInfixOp(BinaryOp\Spaceship::class, $node->left, ' <=> ', $node->right); } protected function pExpr_BinaryOp_Greater(BinaryOp\Greater $node) { return $this->pInfixOp(BinaryOp\Greater::class, $node->left, ' > ', $node->right); } protected function pExpr_BinaryOp_GreaterOrEqual(BinaryOp\GreaterOrEqual $node) { return $this->pInfixOp(BinaryOp\GreaterOrEqual::class, $node->left, ' >= ', $node->right); } protected function pExpr_BinaryOp_Smaller(BinaryOp\Smaller $node) { return $this->pInfixOp(BinaryOp\Smaller::class, $node->left, ' < ', $node->right); } protected function pExpr_BinaryOp_SmallerOrEqual(BinaryOp\SmallerOrEqual $node) { return $this->pInfixOp(BinaryOp\SmallerOrEqual::class, $node->left, ' <= ', $node->right); } protected function pExpr_BinaryOp_Coalesce(BinaryOp\Coalesce $node) { return $this->pInfixOp(BinaryOp\Coalesce::class, $node->left, ' ?? ', $node->right); } protected function pExpr_Instanceof(Expr\Instanceof_ $node) { list($precedence, $associativity) = $this->precedenceMap[Expr\Instanceof_::class]; return $this->pPrec($node->expr, $precedence, $associativity, -1) . ' instanceof ' . $this->pNewVariable($node->class); } // Unary expressions protected function pExpr_BooleanNot(Expr\BooleanNot $node) { return $this->pPrefixOp(Expr\BooleanNot::class, '!', $node->expr); } protected function pExpr_BitwiseNot(Expr\BitwiseNot $node) { return $this->pPrefixOp(Expr\BitwiseNot::class, '~', $node->expr); } protected function pExpr_UnaryMinus(Expr\UnaryMinus $node) { if ($node->expr instanceof Expr\UnaryMinus || $node->expr instanceof Expr\PreDec) { // Enforce -(-$expr) instead of --$expr return '-(' . $this->p($node->expr) . ')'; } return $this->pPrefixOp(Expr\UnaryMinus::class, '-', $node->expr); } protected function pExpr_UnaryPlus(Expr\UnaryPlus $node) { if ($node->expr instanceof Expr\UnaryPlus || $node->expr instanceof Expr\PreInc) { // Enforce +(+$expr) instead of ++$expr return '+(' . $this->p($node->expr) . ')'; } return $this->pPrefixOp(Expr\UnaryPlus::class, '+', $node->expr); } protected function pExpr_PreInc(Expr\PreInc $node) { return $this->pPrefixOp(Expr\PreInc::class, '++', $node->var); } protected function pExpr_PreDec(Expr\PreDec $node) { return $this->pPrefixOp(Expr\PreDec::class, '--', $node->var); } protected function pExpr_PostInc(Expr\PostInc $node) { return $this->pPostfixOp(Expr\PostInc::class, $node->var, '++'); } protected function pExpr_PostDec(Expr\PostDec $node) { return $this->pPostfixOp(Expr\PostDec::class, $node->var, '--'); } protected function pExpr_ErrorSuppress(Expr\ErrorSuppress $node) { return $this->pPrefixOp(Expr\ErrorSuppress::class, '@', $node->expr); } protected function pExpr_YieldFrom(Expr\YieldFrom $node) { return $this->pPrefixOp(Expr\YieldFrom::class, 'yield from ', $node->expr); } protected function pExpr_Print(Expr\Print_ $node) { return $this->pPrefixOp(Expr\Print_::class, 'print ', $node->expr); } // Casts protected function pExpr_Cast_Int(Cast\Int_ $node) { return $this->pPrefixOp(Cast\Int_::class, '(int) ', $node->expr); } protected function pExpr_Cast_Double(Cast\Double $node) { $kind = $node->getAttribute('kind', Cast\Double::KIND_DOUBLE); if ($kind === Cast\Double::KIND_DOUBLE) { $cast = '(double)'; } elseif ($kind === Cast\Double::KIND_FLOAT) { $cast = '(float)'; } elseif ($kind === Cast\Double::KIND_REAL) { $cast = '(real)'; } return $this->pPrefixOp(Cast\Double::class, $cast . ' ', $node->expr); } protected function pExpr_Cast_String(Cast\String_ $node) { return $this->pPrefixOp(Cast\String_::class, '(string) ', $node->expr); } protected function pExpr_Cast_Array(Cast\Array_ $node) { return $this->pPrefixOp(Cast\Array_::class, '(array) ', $node->expr); } protected function pExpr_Cast_Object(Cast\Object_ $node) { return $this->pPrefixOp(Cast\Object_::class, '(object) ', $node->expr); } protected function pExpr_Cast_Bool(Cast\Bool_ $node) { return $this->pPrefixOp(Cast\Bool_::class, '(bool) ', $node->expr); } protected function pExpr_Cast_Unset(Cast\Unset_ $node) { return $this->pPrefixOp(Cast\Unset_::class, '(unset) ', $node->expr); } // Function calls and similar constructs protected function pExpr_FuncCall(Expr\FuncCall $node) { return $this->pCallLhs($node->name) . '(' . $this->pMaybeMultiline($node->args) . ')'; } protected function pExpr_MethodCall(Expr\MethodCall $node) { return $this->pDereferenceLhs($node->var) . '->' . $this->pObjectProperty($node->name) . '(' . $this->pMaybeMultiline($node->args) . ')'; } protected function pExpr_NullsafeMethodCall(Expr\NullsafeMethodCall $node) { return $this->pDereferenceLhs($node->var) . '?->' . $this->pObjectProperty($node->name) . '(' . $this->pMaybeMultiline($node->args) . ')'; } protected function pExpr_StaticCall(Expr\StaticCall $node) { return $this->pStaticDereferenceLhs($node->class) . '::' . ($node->name instanceof Expr ? $node->name instanceof Expr\Variable ? $this->p($node->name) : '{' . $this->p($node->name) . '}' : $node->name) . '(' . $this->pMaybeMultiline($node->args) . ')'; } protected function pExpr_Empty(Expr\Empty_ $node) { return 'empty(' . $this->p($node->expr) . ')'; } protected function pExpr_Isset(Expr\Isset_ $node) { return 'isset(' . $this->pCommaSeparated($node->vars) . ')'; } protected function pExpr_Eval(Expr\Eval_ $node) { return 'eval(' . $this->p($node->expr) . ')'; } protected function pExpr_Include(Expr\Include_ $node) { static $map = [Expr\Include_::TYPE_INCLUDE => 'include', Expr\Include_::TYPE_INCLUDE_ONCE => 'include_once', Expr\Include_::TYPE_REQUIRE => 'require', Expr\Include_::TYPE_REQUIRE_ONCE => 'require_once']; return $map[$node->type] . ' ' . $this->p($node->expr); } protected function pExpr_List(Expr\List_ $node) { return 'list(' . $this->pCommaSeparated($node->items) . ')'; } // Other protected function pExpr_Error(Expr\Error $node) { throw new \LogicException('Cannot pretty-print AST with Error nodes'); } protected function pExpr_Variable(Expr\Variable $node) { if ($node->name instanceof Expr) { return '${' . $this->p($node->name) . '}'; } else { return '$' . $node->name; } } protected function pExpr_Array(Expr\Array_ $node) { $syntax = $node->getAttribute('kind', $this->options['shortArraySyntax'] ? Expr\Array_::KIND_SHORT : Expr\Array_::KIND_LONG); if ($syntax === Expr\Array_::KIND_SHORT) { return '[' . $this->pMaybeMultiline($node->items, \true) . ']'; } else { return 'array(' . $this->pMaybeMultiline($node->items, \true) . ')'; } } protected function pExpr_ArrayItem(Expr\ArrayItem $node) { return (null !== $node->key ? $this->p($node->key) . ' => ' : '') . ($node->byRef ? '&' : '') . ($node->unpack ? '...' : '') . $this->p($node->value); } protected function pExpr_ArrayDimFetch(Expr\ArrayDimFetch $node) { return $this->pDereferenceLhs($node->var) . '[' . (null !== $node->dim ? $this->p($node->dim) : '') . ']'; } protected function pExpr_ConstFetch(Expr\ConstFetch $node) { return $this->p($node->name); } protected function pExpr_ClassConstFetch(Expr\ClassConstFetch $node) { return $this->pStaticDereferenceLhs($node->class) . '::' . $this->pObjectProperty($node->name); } protected function pExpr_PropertyFetch(Expr\PropertyFetch $node) { return $this->pDereferenceLhs($node->var) . '->' . $this->pObjectProperty($node->name); } protected function pExpr_NullsafePropertyFetch(Expr\NullsafePropertyFetch $node) { return $this->pDereferenceLhs($node->var) . '?->' . $this->pObjectProperty($node->name); } protected function pExpr_StaticPropertyFetch(Expr\StaticPropertyFetch $node) { return $this->pStaticDereferenceLhs($node->class) . '::$' . $this->pObjectProperty($node->name); } protected function pExpr_ShellExec(Expr\ShellExec $node) { return '`' . $this->pEncapsList($node->parts, '`') . '`'; } protected function pExpr_Closure(Expr\Closure $node) { return $this->pAttrGroups($node->attrGroups, \true) . ($node->static ? 'static ' : '') . 'function ' . ($node->byRef ? '&' : '') . '(' . $this->pCommaSeparated($node->params) . ')' . (!empty($node->uses) ? ' use(' . $this->pCommaSeparated($node->uses) . ')' : '') . (null !== $node->returnType ? ' : ' . $this->p($node->returnType) : '') . ' {' . $this->pStmts($node->stmts) . $this->nl . '}'; } protected function pExpr_Match(Expr\Match_ $node) { return 'match (' . $this->p($node->cond) . ') {' . $this->pCommaSeparatedMultiline($node->arms, \true) . $this->nl . '}'; } protected function pMatchArm(Node\MatchArm $node) { return ($node->conds ? $this->pCommaSeparated($node->conds) : 'default') . ' => ' . $this->p($node->body); } protected function pExpr_ArrowFunction(Expr\ArrowFunction $node) { return $this->pAttrGroups($node->attrGroups, \true) . ($node->static ? 'static ' : '') . 'fn' . ($node->byRef ? '&' : '') . '(' . $this->pCommaSeparated($node->params) . ')' . (null !== $node->returnType ? ': ' . $this->p($node->returnType) : '') . ' => ' . $this->p($node->expr); } protected function pExpr_ClosureUse(Expr\ClosureUse $node) { return ($node->byRef ? '&' : '') . $this->p($node->var); } protected function pExpr_New(Expr\New_ $node) { if ($node->class instanceof Stmt\Class_) { $args = $node->args ? '(' . $this->pMaybeMultiline($node->args) . ')' : ''; return 'new ' . $this->pClassCommon($node->class, $args); } return 'new ' . $this->pNewVariable($node->class) . '(' . $this->pMaybeMultiline($node->args) . ')'; } protected function pExpr_Clone(Expr\Clone_ $node) { return 'clone ' . $this->p($node->expr); } protected function pExpr_Ternary(Expr\Ternary $node) { // a bit of cheating: we treat the ternary as a binary op where the ?...: part is the operator. // this is okay because the part between ? and : never needs parentheses. return $this->pInfixOp(Expr\Ternary::class, $node->cond, ' ?' . (null !== $node->if ? ' ' . $this->p($node->if) . ' ' : '') . ': ', $node->else); } protected function pExpr_Exit(Expr\Exit_ $node) { $kind = $node->getAttribute('kind', Expr\Exit_::KIND_DIE); return ($kind === Expr\Exit_::KIND_EXIT ? 'exit' : 'die') . (null !== $node->expr ? '(' . $this->p($node->expr) . ')' : ''); } protected function pExpr_Throw(Expr\Throw_ $node) { return 'throw ' . $this->p($node->expr); } protected function pExpr_Yield(Expr\Yield_ $node) { if ($node->value === null) { return 'yield'; } else { // this is a bit ugly, but currently there is no way to detect whether the parentheses are necessary return '(yield ' . ($node->key !== null ? $this->p($node->key) . ' => ' : '') . $this->p($node->value) . ')'; } } // Declarations protected function pStmt_Namespace(Stmt\Namespace_ $node) { if ($this->canUseSemicolonNamespaces) { return 'namespace ' . $this->p($node->name) . ';' . $this->nl . $this->pStmts($node->stmts, \false); } else { return 'namespace' . (null !== $node->name ? ' ' . $this->p($node->name) : '') . ' {' . $this->pStmts($node->stmts) . $this->nl . '}'; } } protected function pStmt_Use(Stmt\Use_ $node) { return 'use ' . $this->pUseType($node->type) . $this->pCommaSeparated($node->uses) . ';'; } protected function pStmt_GroupUse(Stmt\GroupUse $node) { return 'use ' . $this->pUseType($node->type) . $this->pName($node->prefix) . '\\{' . $this->pCommaSeparated($node->uses) . '};'; } protected function pStmt_UseUse(Stmt\UseUse $node) { return $this->pUseType($node->type) . $this->p($node->name) . (null !== $node->alias ? ' as ' . $node->alias : ''); } protected function pUseType($type) { return $type === Stmt\Use_::TYPE_FUNCTION ? 'function ' : ($type === Stmt\Use_::TYPE_CONSTANT ? 'const ' : ''); } protected function pStmt_Interface(Stmt\Interface_ $node) { return $this->pAttrGroups($node->attrGroups) . 'interface ' . $node->name . (!empty($node->extends) ? ' extends ' . $this->pCommaSeparated($node->extends) : '') . $this->nl . '{' . $this->pStmts($node->stmts) . $this->nl . '}'; } protected function pStmt_Enum(Stmt\Enum_ $node) { return $this->pAttrGroups($node->attrGroups) . 'enum ' . $node->name . ($node->scalarType ? " : {$node->scalarType}" : '') . (!empty($node->implements) ? ' implements ' . $this->pCommaSeparated($node->implements) : '') . $this->nl . '{' . $this->pStmts($node->stmts) . $this->nl . '}'; } protected function pStmt_Class(Stmt\Class_ $node) { return $this->pClassCommon($node, ' ' . $node->name); } protected function pStmt_Trait(Stmt\Trait_ $node) { return $this->pAttrGroups($node->attrGroups) . 'trait ' . $node->name . $this->nl . '{' . $this->pStmts($node->stmts) . $this->nl . '}'; } protected function pStmt_EnumCase(Stmt\EnumCase $node) { return $this->pAttrGroups($node->attrGroups) . 'case ' . $node->name . ($node->expr ? ' = ' . $this->p($node->expr) : '') . ';'; } protected function pStmt_TraitUse(Stmt\TraitUse $node) { return 'use ' . $this->pCommaSeparated($node->traits) . (empty($node->adaptations) ? ';' : ' {' . $this->pStmts($node->adaptations) . $this->nl . '}'); } protected function pStmt_TraitUseAdaptation_Precedence(Stmt\TraitUseAdaptation\Precedence $node) { return $this->p($node->trait) . '::' . $node->method . ' insteadof ' . $this->pCommaSeparated($node->insteadof) . ';'; } protected function pStmt_TraitUseAdaptation_Alias(Stmt\TraitUseAdaptation\Alias $node) { return (null !== $node->trait ? $this->p($node->trait) . '::' : '') . $node->method . ' as' . (null !== $node->newModifier ? ' ' . \rtrim($this->pModifiers($node->newModifier), ' ') : '') . (null !== $node->newName ? ' ' . $node->newName : '') . ';'; } protected function pStmt_Property(Stmt\Property $node) { return $this->pAttrGroups($node->attrGroups) . (0 === $node->flags ? 'var ' : $this->pModifiers($node->flags)) . ($node->type ? $this->p($node->type) . ' ' : '') . $this->pCommaSeparated($node->props) . ';'; } protected function pStmt_PropertyProperty(Stmt\PropertyProperty $node) { return '$' . $node->name . (null !== $node->default ? ' = ' . $this->p($node->default) : ''); } protected function pStmt_ClassMethod(Stmt\ClassMethod $node) { return $this->pAttrGroups($node->attrGroups) . $this->pModifiers($node->flags) . 'function ' . ($node->byRef ? '&' : '') . $node->name . '(' . $this->pMaybeMultiline($node->params) . ')' . (null !== $node->returnType ? ' : ' . $this->p($node->returnType) : '') . (null !== $node->stmts ? $this->nl . '{' . $this->pStmts($node->stmts) . $this->nl . '}' : ';'); } protected function pStmt_ClassConst(Stmt\ClassConst $node) { return $this->pAttrGroups($node->attrGroups) . $this->pModifiers($node->flags) . 'const ' . (null !== $node->type ? $this->p($node->type) . ' ' : '') . $this->pCommaSeparated($node->consts) . ';'; } protected function pStmt_Function(Stmt\Function_ $node) { return $this->pAttrGroups($node->attrGroups) . 'function ' . ($node->byRef ? '&' : '') . $node->name . '(' . $this->pCommaSeparated($node->params) . ')' . (null !== $node->returnType ? ' : ' . $this->p($node->returnType) : '') . $this->nl . '{' . $this->pStmts($node->stmts) . $this->nl . '}'; } protected function pStmt_Const(Stmt\Const_ $node) { return 'const ' . $this->pCommaSeparated($node->consts) . ';'; } protected function pStmt_Declare(Stmt\Declare_ $node) { return 'declare (' . $this->pCommaSeparated($node->declares) . ')' . (null !== $node->stmts ? ' {' . $this->pStmts($node->stmts) . $this->nl . '}' : ';'); } protected function pStmt_DeclareDeclare(Stmt\DeclareDeclare $node) { return $node->key . '=' . $this->p($node->value); } // Control flow protected function pStmt_If(Stmt\If_ $node) { return 'if (' . $this->p($node->cond) . ') {' . $this->pStmts($node->stmts) . $this->nl . '}' . ($node->elseifs ? ' ' . $this->pImplode($node->elseifs, ' ') : '') . (null !== $node->else ? ' ' . $this->p($node->else) : ''); } protected function pStmt_ElseIf(Stmt\ElseIf_ $node) { return 'elseif (' . $this->p($node->cond) . ') {' . $this->pStmts($node->stmts) . $this->nl . '}'; } protected function pStmt_Else(Stmt\Else_ $node) { return 'else {' . $this->pStmts($node->stmts) . $this->nl . '}'; } protected function pStmt_For(Stmt\For_ $node) { return 'for (' . $this->pCommaSeparated($node->init) . ';' . (!empty($node->cond) ? ' ' : '') . $this->pCommaSeparated($node->cond) . ';' . (!empty($node->loop) ? ' ' : '') . $this->pCommaSeparated($node->loop) . ') {' . $this->pStmts($node->stmts) . $this->nl . '}'; } protected function pStmt_Foreach(Stmt\Foreach_ $node) { return 'foreach (' . $this->p($node->expr) . ' as ' . (null !== $node->keyVar ? $this->p($node->keyVar) . ' => ' : '') . ($node->byRef ? '&' : '') . $this->p($node->valueVar) . ') {' . $this->pStmts($node->stmts) . $this->nl . '}'; } protected function pStmt_While(Stmt\While_ $node) { return 'while (' . $this->p($node->cond) . ') {' . $this->pStmts($node->stmts) . $this->nl . '}'; } protected function pStmt_Do(Stmt\Do_ $node) { return 'do {' . $this->pStmts($node->stmts) . $this->nl . '} while (' . $this->p($node->cond) . ');'; } protected function pStmt_Switch(Stmt\Switch_ $node) { return 'switch (' . $this->p($node->cond) . ') {' . $this->pStmts($node->cases) . $this->nl . '}'; } protected function pStmt_Case(Stmt\Case_ $node) { return (null !== $node->cond ? 'case ' . $this->p($node->cond) : 'default') . ':' . $this->pStmts($node->stmts); } protected function pStmt_TryCatch(Stmt\TryCatch $node) { return 'try {' . $this->pStmts($node->stmts) . $this->nl . '}' . ($node->catches ? ' ' . $this->pImplode($node->catches, ' ') : '') . ($node->finally !== null ? ' ' . $this->p($node->finally) : ''); } protected function pStmt_Catch(Stmt\Catch_ $node) { return 'catch (' . $this->pImplode($node->types, '|') . ($node->var !== null ? ' ' . $this->p($node->var) : '') . ') {' . $this->pStmts($node->stmts) . $this->nl . '}'; } protected function pStmt_Finally(Stmt\Finally_ $node) { return 'finally {' . $this->pStmts($node->stmts) . $this->nl . '}'; } protected function pStmt_Break(Stmt\Break_ $node) { return 'break' . ($node->num !== null ? ' ' . $this->p($node->num) : '') . ';'; } protected function pStmt_Continue(Stmt\Continue_ $node) { return 'continue' . ($node->num !== null ? ' ' . $this->p($node->num) : '') . ';'; } protected function pStmt_Return(Stmt\Return_ $node) { return 'return' . (null !== $node->expr ? ' ' . $this->p($node->expr) : '') . ';'; } protected function pStmt_Throw(Stmt\Throw_ $node) { return 'throw ' . $this->p($node->expr) . ';'; } protected function pStmt_Label(Stmt\Label $node) { return $node->name . ':'; } protected function pStmt_Goto(Stmt\Goto_ $node) { return 'goto ' . $node->name . ';'; } // Other protected function pStmt_Expression(Stmt\Expression $node) { return $this->p($node->expr) . ';'; } protected function pStmt_Echo(Stmt\Echo_ $node) { return 'echo ' . $this->pCommaSeparated($node->exprs) . ';'; } protected function pStmt_Static(Stmt\Static_ $node) { return 'static ' . $this->pCommaSeparated($node->vars) . ';'; } protected function pStmt_Global(Stmt\Global_ $node) { return 'global ' . $this->pCommaSeparated($node->vars) . ';'; } protected function pStmt_StaticVar(Stmt\StaticVar $node) { return $this->p($node->var) . (null !== $node->default ? ' = ' . $this->p($node->default) : ''); } protected function pStmt_Unset(Stmt\Unset_ $node) { return 'unset(' . $this->pCommaSeparated($node->vars) . ');'; } protected function pStmt_InlineHTML(Stmt\InlineHTML $node) { $newline = $node->getAttribute('hasLeadingNewline', \true) ? "\n" : ''; return '?>' . $newline . $node->value . 'remaining; } protected function pStmt_Nop(Stmt\Nop $node) { return ''; } // Helpers protected function pClassCommon(Stmt\Class_ $node, $afterClassToken) { return $this->pAttrGroups($node->attrGroups, $node->name === null) . $this->pModifiers($node->flags) . 'class' . $afterClassToken . (null !== $node->extends ? ' extends ' . $this->p($node->extends) : '') . (!empty($node->implements) ? ' implements ' . $this->pCommaSeparated($node->implements) : '') . $this->nl . '{' . $this->pStmts($node->stmts) . $this->nl . '}'; } protected function pObjectProperty($node) { if ($node instanceof Expr) { return '{' . $this->p($node) . '}'; } else { return $node; } } protected function pEncapsList(array $encapsList, $quote) { $return = ''; foreach ($encapsList as $element) { if ($element instanceof Scalar\EncapsedStringPart) { $return .= $this->escapeString($element->value, $quote); } else { $return .= '{' . $this->p($element) . '}'; } } return $return; } protected function pSingleQuotedString(string $string) { return '\'' . \addcslashes($string, '\'\\') . '\''; } protected function escapeString($string, $quote) { if (null === $quote) { // For doc strings, don't escape newlines $escaped = \addcslashes($string, "\t\f\v\$\\"); } else { $escaped = \addcslashes($string, "\n\r\t\f\v\$" . $quote . "\\"); } // Escape control characters and non-UTF-8 characters. // Regex based on https://stackoverflow.com/a/11709412/385378. $regex = '/( [\\x00-\\x08\\x0E-\\x1F] # Control characters | [\\xC0-\\xC1] # Invalid UTF-8 Bytes | [\\xF5-\\xFF] # Invalid UTF-8 Bytes | \\xE0(?=[\\x80-\\x9F]) # Overlong encoding of prior code point | \\xF0(?=[\\x80-\\x8F]) # Overlong encoding of prior code point | [\\xC2-\\xDF](?![\\x80-\\xBF]) # Invalid UTF-8 Sequence Start | [\\xE0-\\xEF](?![\\x80-\\xBF]{2}) # Invalid UTF-8 Sequence Start | [\\xF0-\\xF4](?![\\x80-\\xBF]{3}) # Invalid UTF-8 Sequence Start | (?<=[\\x00-\\x7F\\xF5-\\xFF])[\\x80-\\xBF] # Invalid UTF-8 Sequence Middle | (? $part) { $atStart = $i === 0; $atEnd = $i === \count($parts) - 1; if ($part instanceof Scalar\EncapsedStringPart && $this->containsEndLabel($part->value, $label, $atStart, $atEnd)) { return \true; } } return \false; } protected function pDereferenceLhs(Node $node) { if (!$this->dereferenceLhsRequiresParens($node)) { return $this->p($node); } else { return '(' . $this->p($node) . ')'; } } protected function pStaticDereferenceLhs(Node $node) { if (!$this->staticDereferenceLhsRequiresParens($node)) { return $this->p($node); } else { return '(' . $this->p($node) . ')'; } } protected function pCallLhs(Node $node) { if (!$this->callLhsRequiresParens($node)) { return $this->p($node); } else { return '(' . $this->p($node) . ')'; } } protected function pNewVariable(Node $node) : string { if (!$this->newOperandRequiresParens($node)) { return $this->p($node); } else { return '(' . $this->p($node) . ')'; } } /** * @param Node[] $nodes * @return bool */ protected function hasNodeWithComments(array $nodes) { foreach ($nodes as $node) { if ($node && $node->getComments()) { return \true; } } return \false; } protected function pMaybeMultiline(array $nodes, bool $trailingComma = \false) { if (!$this->hasNodeWithComments($nodes)) { return $this->pCommaSeparated($nodes); } else { return $this->pCommaSeparatedMultiline($nodes, $trailingComma) . $this->nl; } } protected function pAttrGroups(array $nodes, bool $inline = \false) : string { $result = ''; $sep = $inline ? ' ' : $this->nl; foreach ($nodes as $node) { $result .= $this->p($node) . $sep; } return $result; } } getNode(); } if ($node instanceof Node) { return $node; } throw new \LogicException('Expected node or builder object'); } /** * Normalizes a node to a statement. * * Expressions are wrapped in a Stmt\Expression node. * * @param Node|Builder $node The node to normalize * * @return Stmt The normalized statement node */ public static function normalizeStmt($node) : Stmt { $node = self::normalizeNode($node); if ($node instanceof Stmt) { return $node; } if ($node instanceof Expr) { return new Stmt\Expression($node); } throw new \LogicException('Expected statement or expression node'); } /** * Normalizes strings to Identifier. * * @param string|Identifier $name The identifier to normalize * * @return Identifier The normalized identifier */ public static function normalizeIdentifier($name) : Identifier { if ($name instanceof Identifier) { return $name; } if (\is_string($name)) { return new Identifier($name); } throw new \LogicException('_HumbugBox7ff99e199a36\\Expected string or instance of Node\\Identifier'); } /** * Normalizes strings to Identifier, also allowing expressions. * * @param string|Identifier|Expr $name The identifier to normalize * * @return Identifier|Expr The normalized identifier or expression */ public static function normalizeIdentifierOrExpr($name) { if ($name instanceof Identifier || $name instanceof Expr) { return $name; } if (\is_string($name)) { return new Identifier($name); } throw new \LogicException('_HumbugBox7ff99e199a36\\Expected string or instance of Node\\Identifier or Node\\Expr'); } /** * Normalizes a name: Converts string names to Name nodes. * * @param Name|string $name The name to normalize * * @return Name The normalized name */ public static function normalizeName($name) : Name { if ($name instanceof Name) { return $name; } if (\is_string($name)) { if (!$name) { throw new \LogicException('Name cannot be empty'); } if ($name[0] === '\\') { return new Name\FullyQualified(\substr($name, 1)); } if (0 === \strpos($name, 'namespace\\')) { return new Name\Relative(\substr($name, \strlen('namespace\\'))); } return new Name($name); } throw new \LogicException('_HumbugBox7ff99e199a36\\Name must be a string or an instance of Node\\Name'); } /** * Normalizes a name: Converts string names to Name nodes, while also allowing expressions. * * @param Expr|Name|string $name The name to normalize * * @return Name|Expr The normalized name or expression */ public static function normalizeNameOrExpr($name) { if ($name instanceof Expr) { return $name; } if (!\is_string($name) && !$name instanceof Name) { throw new \LogicException('_HumbugBox7ff99e199a36\\Name must be a string or an instance of Node\\Name or Node\\Expr'); } return self::normalizeName($name); } /** * Normalizes a type: Converts plain-text type names into proper AST representation. * * In particular, builtin types become Identifiers, custom types become Names and nullables * are wrapped in NullableType nodes. * * @param string|Name|Identifier|ComplexType $type The type to normalize * * @return Name|Identifier|ComplexType The normalized type */ public static function normalizeType($type) { if (!\is_string($type)) { if (!$type instanceof Name && !$type instanceof Identifier && !$type instanceof ComplexType) { throw new \LogicException('Type must be a string, or an instance of Name, Identifier or ComplexType'); } return $type; } $nullable = \false; if (\strlen($type) > 0 && $type[0] === '?') { $nullable = \true; $type = \substr($type, 1); } $builtinTypes = ['array', 'callable', 'bool', 'int', 'float', 'string', 'iterable', 'void', 'object', 'null', 'false', 'mixed', 'never', 'true']; $lowerType = \strtolower($type); if (\in_array($lowerType, $builtinTypes)) { $type = new Identifier($lowerType); } else { $type = self::normalizeName($type); } $notNullableTypes = ['void', 'mixed', 'never']; if ($nullable && \in_array((string) $type, $notNullableTypes)) { throw new \LogicException(\sprintf('%s type cannot be nullable', $type)); } return $nullable ? new NullableType($type) : $type; } /** * Normalizes a value: Converts nulls, booleans, integers, * floats, strings and arrays into their respective nodes * * @param Node\Expr|bool|null|int|float|string|array $value The value to normalize * * @return Expr The normalized value */ public static function normalizeValue($value) : Expr { if ($value instanceof Node\Expr) { return $value; } if (\is_null($value)) { return new Expr\ConstFetch(new Name('null')); } if (\is_bool($value)) { return new Expr\ConstFetch(new Name($value ? 'true' : 'false')); } if (\is_int($value)) { return new Scalar\LNumber($value); } if (\is_float($value)) { return new Scalar\DNumber($value); } if (\is_string($value)) { return new Scalar\String_($value); } if (\is_array($value)) { $items = []; $lastKey = -1; foreach ($value as $itemKey => $itemValue) { // for consecutive, numeric keys don't generate keys if (null !== $lastKey && ++$lastKey === $itemKey) { $items[] = new Expr\ArrayItem(self::normalizeValue($itemValue)); } else { $lastKey = null; $items[] = new Expr\ArrayItem(self::normalizeValue($itemValue), self::normalizeValue($itemKey)); } } return new Expr\Array_($items); } throw new \LogicException('Invalid value'); } /** * Normalizes a doc comment: Converts plain strings to PhpParser\Comment\Doc. * * @param Comment\Doc|string $docComment The doc comment to normalize * * @return Comment\Doc The normalized doc comment */ public static function normalizeDocComment($docComment) : Comment\Doc { if ($docComment instanceof Comment\Doc) { return $docComment; } if (\is_string($docComment)) { return new Comment\Doc($docComment); } throw new \LogicException('_HumbugBox7ff99e199a36\\Doc comment must be a string or an instance of PhpParser\\Comment\\Doc'); } /** * Normalizes a attribute: Converts attribute to the Attribute Group if needed. * * @param Node\Attribute|Node\AttributeGroup $attribute * * @return Node\AttributeGroup The Attribute Group */ public static function normalizeAttribute($attribute) : Node\AttributeGroup { if ($attribute instanceof Node\AttributeGroup) { return $attribute; } if (!$attribute instanceof Node\Attribute) { throw new \LogicException('_HumbugBox7ff99e199a36\\Attribute must be an instance of PhpParser\\Node\\Attribute or PhpParser\\Node\\AttributeGroup'); } return new Node\AttributeGroup([$attribute]); } /** * Adds a modifier and returns new modifier bitmask. * * @param int $modifiers Existing modifiers * @param int $modifier Modifier to set * * @return int New modifiers */ public static function addModifier(int $modifiers, int $modifier) : int { Stmt\Class_::verifyModifier($modifiers, $modifier); return $modifiers | $modifier; } /** * Adds a modifier and returns new modifier bitmask. * @return int New modifiers */ public static function addClassModifier(int $existingModifiers, int $modifierToSet) : int { Stmt\Class_::verifyClassModifier($existingModifiers, $modifierToSet); return $existingModifiers | $modifierToSet; } } ') !== \false; } public function emulate(string $code, array $tokens) : array { // We need to manually iterate and manage a count because we'll change // the tokens array on the way $line = 1; for ($i = 0, $c = \count($tokens); $i < $c; ++$i) { if ($tokens[$i] === '?' && isset($tokens[$i + 1]) && $tokens[$i + 1][0] === \T_OBJECT_OPERATOR) { \array_splice($tokens, $i, 2, [[\T_NULLSAFE_OBJECT_OPERATOR, '?->', $line]]); $c--; continue; } // Handle ?-> inside encapsed string. if ($tokens[$i][0] === \T_ENCAPSED_AND_WHITESPACE && isset($tokens[$i - 1]) && $tokens[$i - 1][0] === \T_VARIABLE && \preg_match('/^\\?->([a-zA-Z_\\x80-\\xff][a-zA-Z0-9_\\x80-\\xff]*)/', $tokens[$i][1], $matches)) { $replacement = [[\T_NULLSAFE_OBJECT_OPERATOR, '?->', $line], [\T_STRING, $matches[1], $line]]; if (\strlen($matches[0]) !== \strlen($tokens[$i][1])) { $replacement[] = [\T_ENCAPSED_AND_WHITESPACE, \substr($tokens[$i][1], \strlen($matches[0])), $line]; } \array_splice($tokens, $i, 1, $replacement); $c += \count($replacement) - 1; continue; } if (\is_array($tokens[$i])) { $line += \substr_count($tokens[$i][1], "\n"); } } return $tokens; } public function reverseEmulate(string $code, array $tokens) : array { // ?-> was not valid code previously, don't bother. return $tokens; } } \h*)\2(?![a-zA-Z0-9_\x80-\xff])(?(?:;?[\r\n])?)/x REGEX; public function getPhpVersion() : string { return Emulative::PHP_7_3; } public function isEmulationNeeded(string $code) : bool { return \strpos($code, '<<<') !== \false; } public function emulate(string $code, array $tokens) : array { // Handled by preprocessing + fixup. return $tokens; } public function reverseEmulate(string $code, array $tokens) : array { // Not supported. return $tokens; } public function preprocessCode(string $code, array &$patches) : string { if (!\preg_match_all(self::FLEXIBLE_DOC_STRING_REGEX, $code, $matches, \PREG_SET_ORDER | \PREG_OFFSET_CAPTURE)) { // No heredoc/nowdoc found return $code; } // Keep track of how much we need to adjust string offsets due to the modifications we // already made $posDelta = 0; foreach ($matches as $match) { $indentation = $match['indentation'][0]; $indentationStart = $match['indentation'][1]; $separator = $match['separator'][0]; $separatorStart = $match['separator'][1]; if ($indentation === '' && $separator !== '') { // Ordinary heredoc/nowdoc continue; } if ($indentation !== '') { // Remove indentation $indentationLen = \strlen($indentation); $code = \substr_replace($code, '', $indentationStart + $posDelta, $indentationLen); $patches[] = [$indentationStart + $posDelta, 'add', $indentation]; $posDelta -= $indentationLen; } if ($separator === '') { // Insert newline as separator $code = \substr_replace($code, "\n", $separatorStart + $posDelta, 0); $patches[] = [$separatorStart + $posDelta, 'remove', "\n"]; $posDelta += 1; } } return $code; } } getKeywordString()) !== \false; } protected function isKeywordContext(array $tokens, int $pos) : bool { $previousNonSpaceToken = $this->getPreviousNonSpaceToken($tokens, $pos); return $previousNonSpaceToken === null || $previousNonSpaceToken[0] !== \T_OBJECT_OPERATOR; } public function emulate(string $code, array $tokens) : array { $keywordString = $this->getKeywordString(); foreach ($tokens as $i => $token) { if ($token[0] === \T_STRING && \strtolower($token[1]) === $keywordString && $this->isKeywordContext($tokens, $i)) { $tokens[$i][0] = $this->getKeywordToken(); } } return $tokens; } /** * @param mixed[] $tokens * @return array|string|null */ private function getPreviousNonSpaceToken(array $tokens, int $start) { for ($i = $start - 1; $i >= 0; --$i) { if ($tokens[$i][0] === \T_WHITESPACE) { continue; } return $tokens[$i]; } return null; } public function reverseEmulate(string $code, array $tokens) : array { $keywordToken = $this->getKeywordToken(); foreach ($tokens as $i => $token) { if ($token[0] === $keywordToken) { $tokens[$i][0] = \T_STRING; } } return $tokens; } } resolveIntegerOrFloatToken($tokens[$i + 1][1]); \array_splice($tokens, $i, 2, [[$tokenKind, '0' . $tokens[$i + 1][1], $tokens[$i][2]]]); $c--; } } return $tokens; } private function resolveIntegerOrFloatToken(string $str) : int { $str = \substr($str, 1); $str = \str_replace('_', '', $str); $num = \octdec($str); return \is_float($num) ? \T_DNUMBER : \T_LNUMBER; } public function reverseEmulate(string $code, array $tokens) : array { // Explicit octals were not legal code previously, don't bother. return $tokens; } } emulator = $emulator; } public function getPhpVersion() : string { return $this->emulator->getPhpVersion(); } public function isEmulationNeeded(string $code) : bool { return $this->emulator->isEmulationNeeded($code); } public function emulate(string $code, array $tokens) : array { return $this->emulator->reverseEmulate($code, $tokens); } public function reverseEmulate(string $code, array $tokens) : array { return $this->emulator->emulate($code, $tokens); } public function preprocessCode(string $code, array &$patches) : string { return $code; } } resolveIntegerOrFloatToken($match); $newTokens = [[$tokenKind, $match, $token[2]]]; $numTokens = 1; $len = $tokenLen; while ($matchLen > $len) { $nextToken = $tokens[$i + $numTokens]; $nextTokenText = \is_array($nextToken) ? $nextToken[1] : $nextToken; $nextTokenLen = \strlen($nextTokenText); $numTokens++; if ($matchLen < $len + $nextTokenLen) { // Split trailing characters into a partial token. \assert(\is_array($nextToken), "Partial token should be an array token"); $partialText = \substr($nextTokenText, $matchLen - $len); $newTokens[] = [$nextToken[0], $partialText, $nextToken[2]]; break; } $len += $nextTokenLen; } \array_splice($tokens, $i, $numTokens, $newTokens); $c -= $numTokens - \count($newTokens); $codeOffset += $matchLen; } return $tokens; } private function resolveIntegerOrFloatToken(string $str) : int { $str = \str_replace('_', '', $str); if (\stripos($str, '0b') === 0) { $num = \bindec($str); } elseif (\stripos($str, '0x') === 0) { $num = \hexdec($str); } elseif (\stripos($str, '0') === 0 && \ctype_digit($str)) { $num = \octdec($str); } else { $num = +$str; } return \is_float($num) ? \T_DNUMBER : \T_LNUMBER; } public function reverseEmulate(string $code, array $tokens) : array { // Numeric separators were not legal code previously, don't bother. return $tokens; } } targetPhpVersion = $options['phpVersion'] ?? Emulative::PHP_8_2; unset($options['phpVersion']); parent::__construct($options); $emulators = [new FlexibleDocStringEmulator(), new FnTokenEmulator(), new MatchTokenEmulator(), new CoaleseEqualTokenEmulator(), new NumericLiteralSeparatorEmulator(), new NullsafeTokenEmulator(), new AttributeEmulator(), new EnumTokenEmulator(), new ReadonlyTokenEmulator(), new ExplicitOctalEmulator(), new ReadonlyFunctionTokenEmulator()]; // Collect emulators that are relevant for the PHP version we're running // and the PHP version we're targeting for emulation. foreach ($emulators as $emulator) { $emulatorPhpVersion = $emulator->getPhpVersion(); if ($this->isForwardEmulationNeeded($emulatorPhpVersion)) { $this->emulators[] = $emulator; } else { if ($this->isReverseEmulationNeeded($emulatorPhpVersion)) { $this->emulators[] = new ReverseEmulator($emulator); } } } } public function startLexing(string $code, ?ErrorHandler $errorHandler = null) { $emulators = \array_filter($this->emulators, function ($emulator) use($code) { return $emulator->isEmulationNeeded($code); }); if (empty($emulators)) { // Nothing to emulate, yay parent::startLexing($code, $errorHandler); return; } $this->patches = []; foreach ($emulators as $emulator) { $code = $emulator->preprocessCode($code, $this->patches); } $collector = new ErrorHandler\Collecting(); parent::startLexing($code, $collector); $this->sortPatches(); $this->fixupTokens(); $errors = $collector->getErrors(); if (!empty($errors)) { $this->fixupErrors($errors); foreach ($errors as $error) { $errorHandler->handleError($error); } } foreach ($emulators as $emulator) { $this->tokens = $emulator->emulate($code, $this->tokens); } } private function isForwardEmulationNeeded(string $emulatorPhpVersion) : bool { return \version_compare(\PHP_VERSION, $emulatorPhpVersion, '<') && \version_compare($this->targetPhpVersion, $emulatorPhpVersion, '>='); } private function isReverseEmulationNeeded(string $emulatorPhpVersion) : bool { return \version_compare(\PHP_VERSION, $emulatorPhpVersion, '>=') && \version_compare($this->targetPhpVersion, $emulatorPhpVersion, '<'); } private function sortPatches() { // Patches may be contributed by different emulators. // Make sure they are sorted by increasing patch position. \usort($this->patches, function ($p1, $p2) { return $p1[0] <=> $p2[0]; }); } private function fixupTokens() { if (\count($this->patches) === 0) { return; } // Load first patch $patchIdx = 0; list($patchPos, $patchType, $patchText) = $this->patches[$patchIdx]; // We use a manual loop over the tokens, because we modify the array on the fly $pos = 0; for ($i = 0, $c = \count($this->tokens); $i < $c; $i++) { $token = $this->tokens[$i]; if (\is_string($token)) { if ($patchPos === $pos) { // Only support replacement for string tokens. \assert($patchType === 'replace'); $this->tokens[$i] = $patchText; // Fetch the next patch $patchIdx++; if ($patchIdx >= \count($this->patches)) { // No more patches, we're done return; } list($patchPos, $patchType, $patchText) = $this->patches[$patchIdx]; } $pos += \strlen($token); continue; } $len = \strlen($token[1]); $posDelta = 0; while ($patchPos >= $pos && $patchPos < $pos + $len) { $patchTextLen = \strlen($patchText); if ($patchType === 'remove') { if ($patchPos === $pos && $patchTextLen === $len) { // Remove token entirely \array_splice($this->tokens, $i, 1, []); $i--; $c--; } else { // Remove from token string $this->tokens[$i][1] = \substr_replace($token[1], '', $patchPos - $pos + $posDelta, $patchTextLen); $posDelta -= $patchTextLen; } } elseif ($patchType === 'add') { // Insert into the token string $this->tokens[$i][1] = \substr_replace($token[1], $patchText, $patchPos - $pos + $posDelta, 0); $posDelta += $patchTextLen; } else { if ($patchType === 'replace') { // Replace inside the token string $this->tokens[$i][1] = \substr_replace($token[1], $patchText, $patchPos - $pos + $posDelta, $patchTextLen); } else { \assert(\false); } } // Fetch the next patch $patchIdx++; if ($patchIdx >= \count($this->patches)) { // No more patches, we're done return; } list($patchPos, $patchType, $patchText) = $this->patches[$patchIdx]; // Multiple patches may apply to the same token. Reload the current one to check // If the new patch applies $token = $this->tokens[$i]; } $pos += $len; } // A patch did not apply \assert(\false); } /** * Fixup line and position information in errors. * * @param Error[] $errors */ private function fixupErrors(array $errors) { foreach ($errors as $error) { $attrs = $error->getAttributes(); $posDelta = 0; $lineDelta = 0; foreach ($this->patches as $patch) { list($patchPos, $patchType, $patchText) = $patch; if ($patchPos >= $attrs['startFilePos']) { // No longer relevant break; } if ($patchType === 'add') { $posDelta += \strlen($patchText); $lineDelta += \substr_count($patchText, "\n"); } else { if ($patchType === 'remove') { $posDelta -= \strlen($patchText); $lineDelta -= \substr_count($patchText, "\n"); } } } $attrs['startFilePos'] += $posDelta; $attrs['endFilePos'] += $posDelta; $attrs['startLine'] += $lineDelta; $attrs['endLine'] += $lineDelta; $error->setAttributes($attrs); } } } type = $type; } public function __toString() : string { if ($this->type instanceof CallableTypeNode || $this->type instanceof ConstTypeNode || $this->type instanceof NullableTypeNode) { return '(' . $this->type . ')[]'; } return $this->type . '[]'; } } parameterName = $parameterName; $this->targetType = $targetType; $this->if = $if; $this->else = $else; $this->negated = $negated; } public function __toString() : string { return sprintf('(%s %s %s ? %s : %s)', $this->parameterName, $this->negated ? 'is not' : 'is', $this->targetType, $this->if, $this->else); } } identifier = $identifier; $this->parameters = $parameters; $this->returnType = $returnType; $this->templateTypes = $templateTypes; } public function __toString() : string { $returnType = $this->returnType; if ($returnType instanceof self) { $returnType = "({$returnType})"; } $template = $this->templateTypes !== [] ? '<' . implode(', ', $this->templateTypes) . '>' : ''; $parameters = implode(', ', $this->parameters); return "{$this->identifier}{$template}({$parameters}): {$returnType}"; } } keyName = $keyName; $this->optional = $optional; $this->valueType = $valueType; } public function __toString() : string { if ($this->keyName !== null) { return sprintf('%s%s: %s', (string) $this->keyName, $this->optional ? '?' : '', (string) $this->valueType); } return (string) $this->valueType; } } type = $type; $this->offset = $offset; } public function __toString() : string { if ($this->type instanceof CallableTypeNode || $this->type instanceof NullableTypeNode) { return '(' . $this->type . ')[' . $this->offset . ']'; } return $this->type . '[' . $this->offset . ']'; } } type = $type; } public function __toString() : string { return '?' . $this->type; } } valueType = $valueType; $this->keyType = $keyType; } public function __toString() : string { if ($this->keyType !== null) { return sprintf('<%s, %s>', $this->keyType, $this->valueType); } return sprintf('<%s>', $this->valueType); } } type = $type; $this->isReference = $isReference; $this->isVariadic = $isVariadic; $this->parameterName = $parameterName; $this->isOptional = $isOptional; } public function __toString() : string { $type = "{$this->type} "; $isReference = $this->isReference ? '&' : ''; $isVariadic = $this->isVariadic ? '...' : ''; $isOptional = $this->isOptional ? '=' : ''; return trim("{$type}{$isReference}{$isVariadic}{$this->parameterName}") . $isOptional; } } constExpr = $constExpr; } public function __toString() : string { return $this->constExpr->__toString(); } } name = $name; } public function __toString() : string { return $this->name; } } subjectType = $subjectType; $this->targetType = $targetType; $this->if = $if; $this->else = $else; $this->negated = $negated; } public function __toString() : string { return sprintf('(%s %s %s ? %s : %s)', $this->subjectType, $this->negated ? 'is not' : 'is', $this->targetType, $this->if, $this->else); } } keyName = $keyName; $this->optional = $optional; $this->valueType = $valueType; } public function __toString() : string { if ($this->keyName !== null) { return sprintf('%s%s: %s', (string) $this->keyName, $this->optional ? '?' : '', (string) $this->valueType); } return (string) $this->valueType; } } exceptionArgs = [$exception->getCurrentTokenValue(), $exception->getCurrentTokenType(), $exception->getCurrentOffset(), $exception->getExpectedTokenType(), $exception->getExpectedTokenValue(), $exception->getCurrentTokenLine()]; } public function getException() : ParserException { return new ParserException(...$this->exceptionArgs); } public function __toString() : string { return '*Invalid type*'; } } items = $items; $this->sealed = $sealed; $this->kind = $kind; $this->unsealedType = $unsealedType; } public function __toString() : string { $items = $this->items; if (!$this->sealed) { $items[] = '...' . $this->unsealedType; } return $this->kind . '{' . implode(', ', $items) . '}'; } } type = $type; $this->genericTypes = $genericTypes; $this->variances = $variances; } public function __toString() : string { $genericTypes = []; foreach ($this->genericTypes as $index => $type) { $variance = $this->variances[$index] ?? self::VARIANCE_INVARIANT; if ($variance === self::VARIANCE_INVARIANT) { $genericTypes[] = (string) $type; } elseif ($variance === self::VARIANCE_BIVARIANT) { $genericTypes[] = '*'; } else { $genericTypes[] = sprintf('%s %s', $variance, $type); } } return $this->type . '<' . implode(', ', $genericTypes) . '>'; } } items = $items; } public function __toString() : string { $items = $this->items; return 'object{' . implode(', ', $items) . '}'; } } types = $types; } public function __toString() : string { return '(' . implode(' & ', array_map(static function (TypeNode $type) : string { if ($type instanceof NullableTypeNode) { return '(' . $type . ')'; } return (string) $type; }, $this->types)) . ')'; } } types = $types; } public function __toString() : string { return '(' . implode(' | ', array_map(static function (TypeNode $type) : string { if ($type instanceof NullableTypeNode) { return '(' . $type . ')'; } return (string) $type; }, $this->types)) . ')'; } } $node stays as-is * * array (of Nodes) * => The return value is merged into the parent array (at the position of the $node) * * NodeTraverser::REMOVE_NODE * => $node is removed from the parent array * * NodeTraverser::DONT_TRAVERSE_CHILDREN * => Children of $node are not traversed. $node stays as-is * * NodeTraverser::DONT_TRAVERSE_CURRENT_AND_CHILDREN * => Further visitors for the current node are skipped, and its children are not * traversed. $node stays as-is. * * NodeTraverser::STOP_TRAVERSAL * => Traversal is aborted. $node stays as-is * * otherwise * => $node is set to the return value * * @param Node $node Node * * @return Node|Node[]|NodeTraverser::*|null Replacement node (or special return value) */ public function enterNode(Node $node); /** * Called when leaving a node. * * Return value semantics: * * null * => $node stays as-is * * NodeTraverser::REMOVE_NODE * => $node is removed from the parent array * * NodeTraverser::STOP_TRAVERSAL * => Traversal is aborted. $node stays as-is * * array (of Nodes) * => The return value is merged into the parent array (at the position of the $node) * * otherwise * => $node is set to the return value * * @param Node $node Node * * @return Node|Node[]|NodeTraverser::REMOVE_NODE|NodeTraverser::STOP_TRAVERSAL|null Replacement node (or special return value) */ public function leaveNode(Node $node); /** * Called once after traversal. * * Return value semantics: * * null: $nodes stays as-is * * otherwise: $nodes is set to the return value * * @param Node[] $nodes Array of nodes * * @return Node[]|null Array of nodes */ public function afterTraverse(array $nodes) : ?array; } setAttribute(Attribute::ORIGINAL_NODE, $originalNode); return $node; } } */ private $attributes = []; /** * @param mixed $value */ public function setAttribute(string $key, $value) : void { $this->attributes[$key] = $value; } public function hasAttribute(string $key) : bool { return array_key_exists($key, $this->attributes); } /** * @return mixed */ public function getAttribute(string $key) { if ($this->hasAttribute($key)) { return $this->attributes[$key]; } return null; } } importedAlias = $importedAlias; $this->importedFrom = $importedFrom; $this->importedAs = $importedAs; } public function __toString() : string { return trim("{$this->importedAlias} from {$this->importedFrom}" . ($this->importedAs !== null ? " as {$this->importedAs}" : '')); } } type = $type; $this->propertyName = $propertyName; $this->description = $description; } public function __toString() : string { return trim("{$this->type} {$this->propertyName} {$this->description}"); } } type = $type; $this->description = $description; } public function __toString() : string { return trim("{$this->type} {$this->description}"); } } isStatic = $isStatic; $this->returnType = $returnType; $this->methodName = $methodName; $this->parameters = $parameters; $this->description = $description; $this->templateTypes = $templateTypes; } public function __toString() : string { $static = $this->isStatic ? 'static ' : ''; $returnType = $this->returnType !== null ? "{$this->returnType} " : ''; $parameters = implode(', ', $this->parameters); $description = $this->description !== '' ? " {$this->description}" : ''; $templateTypes = count($this->templateTypes) > 0 ? '<' . implode(', ', $this->templateTypes) . '>' : ''; return "{$static}{$returnType}{$this->methodName}{$templateTypes}({$parameters}){$description}"; } } type = $type; $this->isReference = $isReference; $this->isVariadic = $isVariadic; $this->parameterName = $parameterName; $this->defaultValue = $defaultValue; } public function __toString() : string { $type = $this->type !== null ? "{$this->type} " : ''; $isReference = $this->isReference ? '&' : ''; $isVariadic = $this->isVariadic ? '...' : ''; $default = $this->defaultValue !== null ? " = {$this->defaultValue}" : ''; return "{$type}{$isReference}{$isVariadic}{$this->parameterName}{$default}"; } } type = $type; $this->parameter = $parameter; $this->method = $method; $this->isNegated = $isNegated; $this->isEquality = $isEquality; $this->description = $description; } public function __toString() : string { $isNegated = $this->isNegated ? '!' : ''; $isEquality = $this->isEquality ? '=' : ''; return trim("{$isNegated}{$isEquality}{$this->type} {$this->parameter}->{$this->method}() {$this->description}"); } } type = $type; $this->parameterName = $parameterName; $this->description = $description; } public function __toString() : string { return trim("{$this->type} {$this->parameterName} {$this->description}"); } } name = $name; $this->value = $value; } public function __toString() : string { if ($this->value instanceof DoctrineTagValueNode) { return (string) $this->value; } return trim("{$this->name} {$this->value}"); } } parameterName = $parameterName; $this->description = $description; } public function __toString() : string { return trim("{$this->parameterName} {$this->description}"); } } type = $type; $this->description = $description; } public function __toString() : string { return trim("{$this->type} {$this->description}"); } } value = $value; } public function __toString() : string { return $this->value; } } isReference = $isReference; $this->isVariadic = $isVariadic; $this->parameterName = $parameterName; $this->description = $description; } public function __toString() : string { $reference = $this->isReference ? '&' : ''; $variadic = $this->isVariadic ? '...' : ''; return trim("{$reference}{$variadic}{$this->parameterName} {$this->description}"); } } type = $type; $this->description = $description; } public function __toString() : string { return trim("{$this->type} {$this->description}"); } } type = $type; $this->parameter = $parameter; $this->isNegated = $isNegated; $this->isEquality = $isEquality; $this->description = $description; } public function __toString() : string { $isNegated = $this->isNegated ? '!' : ''; $isEquality = $this->isEquality ? '=' : ''; return trim("{$isNegated}{$isEquality}{$this->type} {$this->parameter} {$this->description}"); } } value = $value; $this->exceptionArgs = [$exception->getCurrentTokenValue(), $exception->getCurrentTokenType(), $exception->getCurrentOffset(), $exception->getExpectedTokenType(), $exception->getExpectedTokenValue(), $exception->getCurrentTokenLine()]; } public function __get(string $name) : ?ParserException { if ($name !== 'exception') { trigger_error(sprintf('Undefined property: %s::$%s', self::class, $name), E_USER_WARNING); return null; } return new ParserException(...$this->exceptionArgs); } public function __toString() : string { return $this->value; } } type = $type; $this->description = $description; } public function __toString() : string { return trim("{$this->type} {$this->description}"); } } name = $name; $this->bound = $bound; $this->default = $default; $this->description = $description; } public function __toString() : string { $bound = $this->bound !== null ? " of {$this->bound}" : ''; $default = $this->default !== null ? " = {$this->default}" : ''; return trim("{$this->name}{$bound}{$default} {$this->description}"); } } type = $type; $this->isReference = $isReference; $this->isVariadic = $isVariadic; $this->parameterName = $parameterName; $this->description = $description; } public function __toString() : string { $reference = $this->isReference ? '&' : ''; $variadic = $this->isVariadic ? '...' : ''; return trim("{$this->type} {$reference}{$variadic}{$this->parameterName} {$this->description}"); } } alias = $alias; $this->type = $type; } public function __toString() : string { return trim("{$this->alias} {$this->type}"); } } text = $text; } public function __toString() : string { return $this->text; } } type = $type; $this->description = $description; } public function __toString() : string { return trim("{$this->type} {$this->description}"); } } description = $description; } public function __toString() : string { return trim($this->description); } } type = $type; $this->variableName = $variableName; $this->description = $description; } public function __toString() : string { return trim("{$this->type} " . trim("{$this->variableName} {$this->description}")); } } type = $type; $this->parameterName = $parameterName; $this->description = $description; } public function __toString() : string { return trim("{$this->type} {$this->parameterName} {$this->description}"); } } type = $type; $this->parameter = $parameter; $this->property = $property; $this->isNegated = $isNegated; $this->isEquality = $isEquality; $this->description = $description; } public function __toString() : string { $isNegated = $this->isNegated ? '!' : ''; $isEquality = $this->isEquality ? '=' : ''; return trim("{$isNegated}{$isEquality}{$this->type} {$this->parameter}->{$this->property} {$this->description}"); } } type = $type; $this->description = $description; } public function __toString() : string { return trim("{$this->type} {$this->description}"); } } type = $type; $this->description = $description; } public function __toString() : string { return trim("{$this->type} {$this->description}"); } } key = $key; $this->value = $value; } public function __toString() : string { if ($this->key === null) { return (string) $this->value; } return $this->key . '=' . $this->value; } } */ public $items; /** * @param list $items */ public function __construct(array $items) { $this->items = $items; } public function __toString() : string { $items = implode(', ', $this->items); return '{' . $items . '}'; } } annotation = $annotation; $this->description = $description; } public function __toString() : string { return trim("{$this->annotation} {$this->description}"); } } */ public $arguments; /** * @param list $arguments */ public function __construct(string $name, array $arguments) { $this->name = $name; $this->arguments = $arguments; } public function __toString() : string { $arguments = implode(', ', $this->arguments); return $this->name . '(' . $arguments . ')'; } } key = $key; $this->value = $value; } public function __toString() : string { if ($this->key === null) { return (string) $this->value; } return $this->key . '=' . $this->value; } } children = $children; } /** * @return PhpDocTagNode[] */ public function getTags() : array { return array_filter($this->children, static function (PhpDocChildNode $child) : bool { return $child instanceof PhpDocTagNode; }); } /** * @return PhpDocTagNode[] */ public function getTagsByName(string $tagName) : array { return array_filter($this->getTags(), static function (PhpDocTagNode $tag) use($tagName) : bool { return $tag->name === $tagName; }); } /** * @return VarTagValueNode[] */ public function getVarTagValues(string $tagName = '@var') : array { return array_filter(array_column($this->getTagsByName($tagName), 'value'), static function (PhpDocTagValueNode $value) : bool { return $value instanceof VarTagValueNode; }); } /** * @return ParamTagValueNode[] */ public function getParamTagValues(string $tagName = '@param') : array { return array_filter(array_column($this->getTagsByName($tagName), 'value'), static function (PhpDocTagValueNode $value) : bool { return $value instanceof ParamTagValueNode; }); } /** * @return TypelessParamTagValueNode[] */ public function getTypelessParamTagValues(string $tagName = '@param') : array { return array_filter(array_column($this->getTagsByName($tagName), 'value'), static function (PhpDocTagValueNode $value) : bool { return $value instanceof TypelessParamTagValueNode; }); } /** * @return ParamImmediatelyInvokedCallableTagValueNode[] */ public function getParamImmediatelyInvokedCallableTagValues(string $tagName = '@param-immediately-invoked-callable') : array { return array_filter(array_column($this->getTagsByName($tagName), 'value'), static function (PhpDocTagValueNode $value) : bool { return $value instanceof ParamImmediatelyInvokedCallableTagValueNode; }); } /** * @return ParamLaterInvokedCallableTagValueNode[] */ public function getParamLaterInvokedCallableTagValues(string $tagName = '@param-later-invoked-callable') : array { return array_filter(array_column($this->getTagsByName($tagName), 'value'), static function (PhpDocTagValueNode $value) : bool { return $value instanceof ParamLaterInvokedCallableTagValueNode; }); } /** * @return ParamClosureThisTagValueNode[] */ public function getParamClosureThisTagValues(string $tagName = '@param-closure-this') : array { return array_filter(array_column($this->getTagsByName($tagName), 'value'), static function (PhpDocTagValueNode $value) : bool { return $value instanceof ParamClosureThisTagValueNode; }); } /** * @return TemplateTagValueNode[] */ public function getTemplateTagValues(string $tagName = '@template') : array { return array_filter(array_column($this->getTagsByName($tagName), 'value'), static function (PhpDocTagValueNode $value) : bool { return $value instanceof TemplateTagValueNode; }); } /** * @return ExtendsTagValueNode[] */ public function getExtendsTagValues(string $tagName = '@extends') : array { return array_filter(array_column($this->getTagsByName($tagName), 'value'), static function (PhpDocTagValueNode $value) : bool { return $value instanceof ExtendsTagValueNode; }); } /** * @return ImplementsTagValueNode[] */ public function getImplementsTagValues(string $tagName = '@implements') : array { return array_filter(array_column($this->getTagsByName($tagName), 'value'), static function (PhpDocTagValueNode $value) : bool { return $value instanceof ImplementsTagValueNode; }); } /** * @return UsesTagValueNode[] */ public function getUsesTagValues(string $tagName = '@use') : array { return array_filter(array_column($this->getTagsByName($tagName), 'value'), static function (PhpDocTagValueNode $value) : bool { return $value instanceof UsesTagValueNode; }); } /** * @return ReturnTagValueNode[] */ public function getReturnTagValues(string $tagName = '@return') : array { return array_filter(array_column($this->getTagsByName($tagName), 'value'), static function (PhpDocTagValueNode $value) : bool { return $value instanceof ReturnTagValueNode; }); } /** * @return ThrowsTagValueNode[] */ public function getThrowsTagValues(string $tagName = '@throws') : array { return array_filter(array_column($this->getTagsByName($tagName), 'value'), static function (PhpDocTagValueNode $value) : bool { return $value instanceof ThrowsTagValueNode; }); } /** * @return MixinTagValueNode[] */ public function getMixinTagValues(string $tagName = '@mixin') : array { return array_filter(array_column($this->getTagsByName($tagName), 'value'), static function (PhpDocTagValueNode $value) : bool { return $value instanceof MixinTagValueNode; }); } /** * @return RequireExtendsTagValueNode[] */ public function getRequireExtendsTagValues(string $tagName = '@phpstan-require-extends') : array { return array_filter(array_column($this->getTagsByName($tagName), 'value'), static function (PhpDocTagValueNode $value) : bool { return $value instanceof RequireExtendsTagValueNode; }); } /** * @return RequireImplementsTagValueNode[] */ public function getRequireImplementsTagValues(string $tagName = '@phpstan-require-implements') : array { return array_filter(array_column($this->getTagsByName($tagName), 'value'), static function (PhpDocTagValueNode $value) : bool { return $value instanceof RequireImplementsTagValueNode; }); } /** * @return DeprecatedTagValueNode[] */ public function getDeprecatedTagValues() : array { return array_filter(array_column($this->getTagsByName('@deprecated'), 'value'), static function (PhpDocTagValueNode $value) : bool { return $value instanceof DeprecatedTagValueNode; }); } /** * @return PropertyTagValueNode[] */ public function getPropertyTagValues(string $tagName = '@property') : array { return array_filter(array_column($this->getTagsByName($tagName), 'value'), static function (PhpDocTagValueNode $value) : bool { return $value instanceof PropertyTagValueNode; }); } /** * @return PropertyTagValueNode[] */ public function getPropertyReadTagValues(string $tagName = '@property-read') : array { return array_filter(array_column($this->getTagsByName($tagName), 'value'), static function (PhpDocTagValueNode $value) : bool { return $value instanceof PropertyTagValueNode; }); } /** * @return PropertyTagValueNode[] */ public function getPropertyWriteTagValues(string $tagName = '@property-write') : array { return array_filter(array_column($this->getTagsByName($tagName), 'value'), static function (PhpDocTagValueNode $value) : bool { return $value instanceof PropertyTagValueNode; }); } /** * @return MethodTagValueNode[] */ public function getMethodTagValues(string $tagName = '@method') : array { return array_filter(array_column($this->getTagsByName($tagName), 'value'), static function (PhpDocTagValueNode $value) : bool { return $value instanceof MethodTagValueNode; }); } /** * @return TypeAliasTagValueNode[] */ public function getTypeAliasTagValues(string $tagName = '@phpstan-type') : array { return array_filter(array_column($this->getTagsByName($tagName), 'value'), static function (PhpDocTagValueNode $value) : bool { return $value instanceof TypeAliasTagValueNode; }); } /** * @return TypeAliasImportTagValueNode[] */ public function getTypeAliasImportTagValues(string $tagName = '@phpstan-import-type') : array { return array_filter(array_column($this->getTagsByName($tagName), 'value'), static function (PhpDocTagValueNode $value) : bool { return $value instanceof TypeAliasImportTagValueNode; }); } /** * @return AssertTagValueNode[] */ public function getAssertTagValues(string $tagName = '@phpstan-assert') : array { return array_filter(array_column($this->getTagsByName($tagName), 'value'), static function (PhpDocTagValueNode $value) : bool { return $value instanceof AssertTagValueNode; }); } /** * @return AssertTagPropertyValueNode[] */ public function getAssertPropertyTagValues(string $tagName = '@phpstan-assert') : array { return array_filter(array_column($this->getTagsByName($tagName), 'value'), static function (PhpDocTagValueNode $value) : bool { return $value instanceof AssertTagPropertyValueNode; }); } /** * @return AssertTagMethodValueNode[] */ public function getAssertMethodTagValues(string $tagName = '@phpstan-assert') : array { return array_filter(array_column($this->getTagsByName($tagName), 'value'), static function (PhpDocTagValueNode $value) : bool { return $value instanceof AssertTagMethodValueNode; }); } /** * @return SelfOutTagValueNode[] */ public function getSelfOutTypeTagValues(string $tagName = '@phpstan-this-out') : array { return array_filter(array_column($this->getTagsByName($tagName), 'value'), static function (PhpDocTagValueNode $value) : bool { return $value instanceof SelfOutTagValueNode; }); } /** * @return ParamOutTagValueNode[] */ public function getParamOutTypeTagValues(string $tagName = '@param-out') : array { return array_filter(array_column($this->getTagsByName($tagName), 'value'), static function (PhpDocTagValueNode $value) : bool { return $value instanceof ParamOutTagValueNode; }); } public function __toString() : string { $children = array_map(static function (PhpDocChildNode $child) : string { $s = (string) $child; return $s === '' ? '' : ' ' . $s; }, $this->children); return "/**\n *" . implode("\n *", $children) . "\n */"; } } parameterName = $parameterName; $this->description = $description; } public function __toString() : string { return trim("{$this->parameterName} {$this->description}"); } } type = $type; $this->description = $description; } public function __toString() : string { return trim("{$this->type} {$this->description}"); } } type = $type; $this->description = $description; } public function __toString() : string { return trim($this->type . ' ' . $this->description); } } Visitors */ private $visitors = []; /** @var bool Whether traversal should be stopped */ private $stopTraversal; /** * @param list $visitors */ public function __construct(array $visitors) { $this->visitors = $visitors; } /** * Traverses an array of nodes using the registered visitors. * * @param Node[] $nodes Array of nodes * * @return Node[] Traversed array of nodes */ public function traverse(array $nodes) : array { $this->stopTraversal = \false; foreach ($this->visitors as $visitor) { $return = $visitor->beforeTraverse($nodes); if ($return === null) { continue; } $nodes = $return; } $nodes = $this->traverseArray($nodes); foreach ($this->visitors as $visitor) { $return = $visitor->afterTraverse($nodes); if ($return === null) { continue; } $nodes = $return; } return $nodes; } /** * Recursively traverse a node. * * @param Node $node Node to traverse. * * @return Node Result of traversal (may be original node or new one) */ private function traverseNode(Node $node) : Node { $subNodeNames = array_keys(get_object_vars($node)); foreach ($subNodeNames as $name) { $subNode =& $node->{$name}; if (is_array($subNode)) { $subNode = $this->traverseArray($subNode); if ($this->stopTraversal) { break; } } elseif ($subNode instanceof Node) { $traverseChildren = \true; $breakVisitorIndex = null; foreach ($this->visitors as $visitorIndex => $visitor) { $return = $visitor->enterNode($subNode); if ($return === null) { continue; } if ($return instanceof Node) { $this->ensureReplacementReasonable($subNode, $return); $subNode = $return; } elseif ($return === self::DONT_TRAVERSE_CHILDREN) { $traverseChildren = \false; } elseif ($return === self::DONT_TRAVERSE_CURRENT_AND_CHILDREN) { $traverseChildren = \false; $breakVisitorIndex = $visitorIndex; break; } elseif ($return === self::STOP_TRAVERSAL) { $this->stopTraversal = \true; break 2; } else { throw new LogicException('enterNode() returned invalid value of type ' . gettype($return)); } } if ($traverseChildren) { $subNode = $this->traverseNode($subNode); if ($this->stopTraversal) { break; } } foreach ($this->visitors as $visitorIndex => $visitor) { $return = $visitor->leaveNode($subNode); if ($return !== null) { if ($return instanceof Node) { $this->ensureReplacementReasonable($subNode, $return); $subNode = $return; } elseif ($return === self::STOP_TRAVERSAL) { $this->stopTraversal = \true; break 2; } elseif (is_array($return)) { throw new LogicException('leaveNode() may only return an array ' . 'if the parent structure is an array'); } else { throw new LogicException('leaveNode() returned invalid value of type ' . gettype($return)); } } if ($breakVisitorIndex === $visitorIndex) { break; } } } } return $node; } /** * Recursively traverse array (usually of nodes). * * @param mixed[] $nodes Array to traverse * * @return mixed[] Result of traversal (may be original array or changed one) */ private function traverseArray(array $nodes) : array { $doNodes = []; foreach ($nodes as $i => &$node) { if ($node instanceof Node) { $traverseChildren = \true; $breakVisitorIndex = null; foreach ($this->visitors as $visitorIndex => $visitor) { $return = $visitor->enterNode($node); if ($return === null) { continue; } if ($return instanceof Node) { $this->ensureReplacementReasonable($node, $return); $node = $return; } elseif (is_array($return)) { $doNodes[] = [$i, $return]; continue 2; } elseif ($return === self::REMOVE_NODE) { $doNodes[] = [$i, []]; continue 2; } elseif ($return === self::DONT_TRAVERSE_CHILDREN) { $traverseChildren = \false; } elseif ($return === self::DONT_TRAVERSE_CURRENT_AND_CHILDREN) { $traverseChildren = \false; $breakVisitorIndex = $visitorIndex; break; } elseif ($return === self::STOP_TRAVERSAL) { $this->stopTraversal = \true; break 2; } else { throw new LogicException('enterNode() returned invalid value of type ' . gettype($return)); } } if ($traverseChildren) { $node = $this->traverseNode($node); if ($this->stopTraversal) { break; } } foreach ($this->visitors as $visitorIndex => $visitor) { $return = $visitor->leaveNode($node); if ($return !== null) { if ($return instanceof Node) { $this->ensureReplacementReasonable($node, $return); $node = $return; } elseif (is_array($return)) { $doNodes[] = [$i, $return]; break; } elseif ($return === self::REMOVE_NODE) { $doNodes[] = [$i, []]; break; } elseif ($return === self::STOP_TRAVERSAL) { $this->stopTraversal = \true; break 2; } else { throw new LogicException('leaveNode() returned invalid value of type ' . gettype($return)); } } if ($breakVisitorIndex === $visitorIndex) { break; } } } elseif (is_array($node)) { throw new LogicException('Invalid node structure: Contains nested arrays'); } } if (count($doNodes) > 0) { while ([$i, $replace] = array_pop($doNodes)) { array_splice($nodes, $i, 1, $replace); } } return $nodes; } private function ensureReplacementReasonable(Node $old, Node $new) : void { if ($old instanceof TypeNode && !$new instanceof TypeNode) { throw new LogicException(sprintf('Trying to replace TypeNode with %s', get_class($new))); } if ($old instanceof ConstExprNode && !$new instanceof ConstExprNode) { throw new LogicException(sprintf('Trying to replace ConstExprNode with %s', get_class($new))); } if ($old instanceof PhpDocChildNode && !$new instanceof PhpDocChildNode) { throw new LogicException(sprintf('Trying to replace PhpDocChildNode with %s', get_class($new))); } if ($old instanceof PhpDocTagValueNode && !$new instanceof PhpDocTagValueNode) { throw new LogicException(sprintf('Trying to replace PhpDocTagValueNode with %s', get_class($new))); } } } value = $value; } public function __toString() : string { return $this->value; } } value = $value; } public function __toString() : string { return $this->value; } } key = $key; $this->value = $value; } public function __toString() : string { if ($this->key !== null) { return sprintf('%s => %s', $this->key, $this->value); } return (string) $this->value; } } items = $items; } public function __toString() : string { return '[' . implode(', ', $this->items) . ']'; } } className = $className; $this->name = $name; } public function __toString() : string { if ($this->className === '') { return $this->name; } return "{$this->className}::{$this->name}"; } } quoteType = $quoteType; } public function __toString() : string { if ($this->quoteType === self::SINGLE_QUOTED) { // from https://github.com/nikic/PHP-Parser/blob/0ffddce52d816f72d0efc4d9b02e276d3309ef01/lib/PhpParser/PrettyPrinter/Standard.php#L1007 return sprintf("'%s'", addcslashes($this->value, '\'\\')); } // from https://github.com/nikic/PHP-Parser/blob/0ffddce52d816f72d0efc4d9b02e276d3309ef01/lib/PhpParser/PrettyPrinter/Standard.php#L1010-L1040 return sprintf('"%s"', $this->escapeDoubleQuotedString()); } private function escapeDoubleQuotedString() : string { $quote = '"'; $escaped = addcslashes($this->value, "\n\r\t\f\v\$" . $quote . '\\'); // Escape control characters and non-UTF-8 characters. // Regex based on https://stackoverflow.com/a/11709412/385378. $regex = '/( [\\x00-\\x08\\x0E-\\x1F] # Control characters | [\\xC0-\\xC1] # Invalid UTF-8 Bytes | [\\xF5-\\xFF] # Invalid UTF-8 Bytes | \\xE0(?=[\\x80-\\x9F]) # Overlong encoding of prior code point | \\xF0(?=[\\x80-\\x8F]) # Overlong encoding of prior code point | [\\xC2-\\xDF](?![\\x80-\\xBF]) # Invalid UTF-8 Sequence Start | [\\xE0-\\xEF](?![\\x80-\\xBF]{2}) # Invalid UTF-8 Sequence Start | [\\xF0-\\xF4](?![\\x80-\\xBF]{3}) # Invalid UTF-8 Sequence Start | (?<=[\\x00-\\x7F\\xF5-\\xFF])[\\x80-\\xBF] # Invalid UTF-8 Sequence Middle | (?value = $value; } public function __toString() : string { return $this->value; } } value = $value; } public function __toString() : string { return self::escape($this->value); } public static function unescape(string $value) : string { // from https://github.com/doctrine/annotations/blob/a9ec7af212302a75d1f92fa65d3abfbd16245a2a/lib/Doctrine/Common/Annotations/DocLexer.php#L103-L107 return str_replace('""', '"', substr($value, 1, strlen($value) - 2)); } private static function escape(string $value) : string { // from https://github.com/phpstan/phpdoc-parser/issues/205#issuecomment-1662323656 return sprintf('"%s"', str_replace('"', '""', $value)); } } isEqual = $isEqual; } /** * Calculate diff (edit script) from $old to $new. * * @param T[] $old Original array * @param T[] $new New array * * @return DiffElem[] Diff (edit script) */ public function diff(array $old, array $new) : array { [$trace, $x, $y] = $this->calculateTrace($old, $new); return $this->extractDiff($trace, $x, $y, $old, $new); } /** * Calculate diff, including "replace" operations. * * If a sequence of remove operations is followed by the same number of add operations, these * will be coalesced into replace operations. * * @param T[] $old Original array * @param T[] $new New array * * @return DiffElem[] Diff (edit script), including replace operations */ public function diffWithReplacements(array $old, array $new) : array { return $this->coalesceReplacements($this->diff($old, $new)); } /** * @param T[] $old * @param T[] $new * @return array{array>, int, int} */ private function calculateTrace(array $old, array $new) : array { $n = count($old); $m = count($new); $max = $n + $m; $v = [1 => 0]; $trace = []; for ($d = 0; $d <= $max; $d++) { $trace[] = $v; for ($k = -$d; $k <= $d; $k += 2) { if ($k === -$d || $k !== $d && $v[$k - 1] < $v[$k + 1]) { $x = $v[$k + 1]; } else { $x = $v[$k - 1] + 1; } $y = $x - $k; while ($x < $n && $y < $m && ($this->isEqual)($old[$x], $new[$y])) { $x++; $y++; } $v[$k] = $x; if ($x >= $n && $y >= $m) { return [$trace, $x, $y]; } } } throw new Exception('Should not happen'); } /** * @param array> $trace * @param T[] $old * @param T[] $new * @return DiffElem[] */ private function extractDiff(array $trace, int $x, int $y, array $old, array $new) : array { $result = []; for ($d = count($trace) - 1; $d >= 0; $d--) { $v = $trace[$d]; $k = $x - $y; if ($k === -$d || $k !== $d && $v[$k - 1] < $v[$k + 1]) { $prevK = $k + 1; } else { $prevK = $k - 1; } $prevX = $v[$prevK]; $prevY = $prevX - $prevK; while ($x > $prevX && $y > $prevY) { $result[] = new DiffElem(DiffElem::TYPE_KEEP, $old[$x - 1], $new[$y - 1]); $x--; $y--; } if ($d === 0) { break; } while ($x > $prevX) { $result[] = new DiffElem(DiffElem::TYPE_REMOVE, $old[$x - 1], null); $x--; } while ($y > $prevY) { $result[] = new DiffElem(DiffElem::TYPE_ADD, null, $new[$y - 1]); $y--; } } return array_reverse($result); } /** * Coalesce equal-length sequences of remove+add into a replace operation. * * @param DiffElem[] $diff * @return DiffElem[] */ private function coalesceReplacements(array $diff) : array { $newDiff = []; $c = count($diff); for ($i = 0; $i < $c; $i++) { $diffType = $diff[$i]->type; if ($diffType !== DiffElem::TYPE_REMOVE) { $newDiff[] = $diff[$i]; continue; } $j = $i; while ($j < $c && $diff[$j]->type === DiffElem::TYPE_REMOVE) { $j++; } $k = $j; while ($k < $c && $diff[$k]->type === DiffElem::TYPE_ADD) { $k++; } if ($j - $i === $k - $j) { $len = $j - $i; for ($n = 0; $n < $len; $n++) { $newDiff[] = new DiffElem(DiffElem::TYPE_REPLACE, $diff[$i + $n]->old, $diff[$j + $n]->new); } } else { for (; $i < $k; $i++) { $newDiff[] = $diff[$i]; } } $i = $k - 1; } return $newDiff; } } type = $type; $this->old = $old; $this->new = $new; } } */ private $differ; /** * Map From "{$class}->{$subNode}" to string that should be inserted * between elements of this list subnode * * @var array */ private $listInsertionMap = [PhpDocNode::class . '->children' => "\n * ", UnionTypeNode::class . '->types' => '|', IntersectionTypeNode::class . '->types' => '&', ArrayShapeNode::class . '->items' => ', ', ObjectShapeNode::class . '->items' => ', ', CallableTypeNode::class . '->parameters' => ', ', CallableTypeNode::class . '->templateTypes' => ', ', GenericTypeNode::class . '->genericTypes' => ', ', ConstExprArrayNode::class . '->items' => ', ', MethodTagValueNode::class . '->parameters' => ', ', DoctrineArray::class . '->items' => ', ', DoctrineAnnotation::class . '->arguments' => ', ']; /** * [$find, $extraLeft, $extraRight] * * @var array */ private $emptyListInsertionMap = [CallableTypeNode::class . '->parameters' => ['(', '', ''], ArrayShapeNode::class . '->items' => ['{', '', ''], ObjectShapeNode::class . '->items' => ['{', '', ''], DoctrineArray::class . '->items' => ['{', '', ''], DoctrineAnnotation::class . '->arguments' => ['(', '', '']]; /** @var array>> */ private $parenthesesMap = [CallableTypeNode::class . '->returnType' => [CallableTypeNode::class, UnionTypeNode::class, IntersectionTypeNode::class], ArrayTypeNode::class . '->type' => [CallableTypeNode::class, UnionTypeNode::class, IntersectionTypeNode::class, ConstTypeNode::class, NullableTypeNode::class], OffsetAccessTypeNode::class . '->type' => [CallableTypeNode::class, UnionTypeNode::class, IntersectionTypeNode::class, NullableTypeNode::class]]; /** @var array>> */ private $parenthesesListMap = [IntersectionTypeNode::class . '->types' => [IntersectionTypeNode::class, UnionTypeNode::class, NullableTypeNode::class], UnionTypeNode::class . '->types' => [IntersectionTypeNode::class, UnionTypeNode::class, NullableTypeNode::class]]; public function printFormatPreserving(PhpDocNode $node, PhpDocNode $originalNode, TokenIterator $originalTokens) : string { $this->differ = new Differ(static function ($a, $b) { if ($a instanceof Node && $b instanceof Node) { return $a === $b->getAttribute(Attribute::ORIGINAL_NODE); } return \false; }); $tokenIndex = 0; $result = $this->printArrayFormatPreserving($node->children, $originalNode->children, $originalTokens, $tokenIndex, PhpDocNode::class, 'children'); if ($result !== null) { return $result . $originalTokens->getContentBetween($tokenIndex, $originalTokens->getTokenCount()); } return $this->print($node); } public function print(Node $node) : string { if ($node instanceof PhpDocNode) { return "/**\n *" . implode("\n *", array_map(function (PhpDocChildNode $child) : string { $s = $this->print($child); return $s === '' ? '' : ' ' . $s; }, $node->children)) . "\n */"; } if ($node instanceof PhpDocTextNode) { return $node->text; } if ($node instanceof PhpDocTagNode) { if ($node->value instanceof DoctrineTagValueNode) { return $this->print($node->value); } return trim(sprintf('%s %s', $node->name, $this->print($node->value))); } if ($node instanceof PhpDocTagValueNode) { return $this->printTagValue($node); } if ($node instanceof TypeNode) { return $this->printType($node); } if ($node instanceof ConstExprNode) { return $this->printConstExpr($node); } if ($node instanceof MethodTagValueParameterNode) { $type = $node->type !== null ? $this->print($node->type) . ' ' : ''; $isReference = $node->isReference ? '&' : ''; $isVariadic = $node->isVariadic ? '...' : ''; $default = $node->defaultValue !== null ? ' = ' . $this->print($node->defaultValue) : ''; return "{$type}{$isReference}{$isVariadic}{$node->parameterName}{$default}"; } if ($node instanceof CallableTypeParameterNode) { $type = $this->print($node->type) . ' '; $isReference = $node->isReference ? '&' : ''; $isVariadic = $node->isVariadic ? '...' : ''; $isOptional = $node->isOptional ? '=' : ''; return trim("{$type}{$isReference}{$isVariadic}{$node->parameterName}") . $isOptional; } if ($node instanceof ArrayShapeUnsealedTypeNode) { if ($node->keyType !== null) { return sprintf('<%s, %s>', $this->printType($node->keyType), $this->printType($node->valueType)); } return sprintf('<%s>', $this->printType($node->valueType)); } if ($node instanceof DoctrineAnnotation) { return (string) $node; } if ($node instanceof DoctrineArgument) { return (string) $node; } if ($node instanceof DoctrineArray) { return (string) $node; } if ($node instanceof DoctrineArrayItem) { return (string) $node; } throw new LogicException(sprintf('Unknown node type %s', get_class($node))); } private function printTagValue(PhpDocTagValueNode $node) : string { // only nodes that contain another node are handled here // the rest falls back on (string) $node if ($node instanceof AssertTagMethodValueNode) { $isNegated = $node->isNegated ? '!' : ''; $isEquality = $node->isEquality ? '=' : ''; $type = $this->printType($node->type); return trim("{$isNegated}{$isEquality}{$type} {$node->parameter}->{$node->method}() {$node->description}"); } if ($node instanceof AssertTagPropertyValueNode) { $isNegated = $node->isNegated ? '!' : ''; $isEquality = $node->isEquality ? '=' : ''; $type = $this->printType($node->type); return trim("{$isNegated}{$isEquality}{$type} {$node->parameter}->{$node->property} {$node->description}"); } if ($node instanceof AssertTagValueNode) { $isNegated = $node->isNegated ? '!' : ''; $isEquality = $node->isEquality ? '=' : ''; $type = $this->printType($node->type); return trim("{$isNegated}{$isEquality}{$type} {$node->parameter} {$node->description}"); } if ($node instanceof ExtendsTagValueNode || $node instanceof ImplementsTagValueNode) { $type = $this->printType($node->type); return trim("{$type} {$node->description}"); } if ($node instanceof MethodTagValueNode) { $static = $node->isStatic ? 'static ' : ''; $returnType = $node->returnType !== null ? $this->printType($node->returnType) . ' ' : ''; $parameters = implode(', ', array_map(function (MethodTagValueParameterNode $parameter) : string { return $this->print($parameter); }, $node->parameters)); $description = $node->description !== '' ? " {$node->description}" : ''; $templateTypes = count($node->templateTypes) > 0 ? '<' . implode(', ', array_map(function (TemplateTagValueNode $templateTag) : string { return $this->print($templateTag); }, $node->templateTypes)) . '>' : ''; return "{$static}{$returnType}{$node->methodName}{$templateTypes}({$parameters}){$description}"; } if ($node instanceof MixinTagValueNode) { $type = $this->printType($node->type); return trim("{$type} {$node->description}"); } if ($node instanceof RequireExtendsTagValueNode) { $type = $this->printType($node->type); return trim("{$type} {$node->description}"); } if ($node instanceof RequireImplementsTagValueNode) { $type = $this->printType($node->type); return trim("{$type} {$node->description}"); } if ($node instanceof ParamOutTagValueNode) { $type = $this->printType($node->type); return trim("{$type} {$node->parameterName} {$node->description}"); } if ($node instanceof ParamTagValueNode) { $reference = $node->isReference ? '&' : ''; $variadic = $node->isVariadic ? '...' : ''; $type = $this->printType($node->type); return trim("{$type} {$reference}{$variadic}{$node->parameterName} {$node->description}"); } if ($node instanceof ParamImmediatelyInvokedCallableTagValueNode) { return trim("{$node->parameterName} {$node->description}"); } if ($node instanceof ParamLaterInvokedCallableTagValueNode) { return trim("{$node->parameterName} {$node->description}"); } if ($node instanceof ParamClosureThisTagValueNode) { return trim("{$node->type} {$node->parameterName} {$node->description}"); } if ($node instanceof PropertyTagValueNode) { $type = $this->printType($node->type); return trim("{$type} {$node->propertyName} {$node->description}"); } if ($node instanceof ReturnTagValueNode) { $type = $this->printType($node->type); return trim("{$type} {$node->description}"); } if ($node instanceof SelfOutTagValueNode) { $type = $this->printType($node->type); return trim($type . ' ' . $node->description); } if ($node instanceof TemplateTagValueNode) { $bound = $node->bound !== null ? ' of ' . $this->printType($node->bound) : ''; $default = $node->default !== null ? ' = ' . $this->printType($node->default) : ''; return trim("{$node->name}{$bound}{$default} {$node->description}"); } if ($node instanceof ThrowsTagValueNode) { $type = $this->printType($node->type); return trim("{$type} {$node->description}"); } if ($node instanceof TypeAliasImportTagValueNode) { return trim("{$node->importedAlias} from " . $this->printType($node->importedFrom) . ($node->importedAs !== null ? " as {$node->importedAs}" : '')); } if ($node instanceof TypeAliasTagValueNode) { $type = $this->printType($node->type); return trim("{$node->alias} {$type}"); } if ($node instanceof UsesTagValueNode) { $type = $this->printType($node->type); return trim("{$type} {$node->description}"); } if ($node instanceof VarTagValueNode) { $type = $this->printType($node->type); return trim("{$type} " . trim("{$node->variableName} {$node->description}")); } return (string) $node; } private function printType(TypeNode $node) : string { if ($node instanceof ArrayShapeNode) { $items = array_map(function (ArrayShapeItemNode $item) : string { return $this->printType($item); }, $node->items); if (!$node->sealed) { $items[] = '...' . ($node->unsealedType === null ? '' : $this->print($node->unsealedType)); } return $node->kind . '{' . implode(', ', $items) . '}'; } if ($node instanceof ArrayShapeItemNode) { if ($node->keyName !== null) { return sprintf('%s%s: %s', $this->print($node->keyName), $node->optional ? '?' : '', $this->printType($node->valueType)); } return $this->printType($node->valueType); } if ($node instanceof ArrayTypeNode) { return $this->printOffsetAccessType($node->type) . '[]'; } if ($node instanceof CallableTypeNode) { if ($node->returnType instanceof CallableTypeNode || $node->returnType instanceof UnionTypeNode || $node->returnType instanceof IntersectionTypeNode) { $returnType = $this->wrapInParentheses($node->returnType); } else { $returnType = $this->printType($node->returnType); } $template = $node->templateTypes !== [] ? '<' . implode(', ', array_map(function (TemplateTagValueNode $templateNode) : string { return $this->print($templateNode); }, $node->templateTypes)) . '>' : ''; $parameters = implode(', ', array_map(function (CallableTypeParameterNode $parameterNode) : string { return $this->print($parameterNode); }, $node->parameters)); return "{$node->identifier}{$template}({$parameters}): {$returnType}"; } if ($node instanceof ConditionalTypeForParameterNode) { return sprintf('(%s %s %s ? %s : %s)', $node->parameterName, $node->negated ? 'is not' : 'is', $this->printType($node->targetType), $this->printType($node->if), $this->printType($node->else)); } if ($node instanceof ConditionalTypeNode) { return sprintf('(%s %s %s ? %s : %s)', $this->printType($node->subjectType), $node->negated ? 'is not' : 'is', $this->printType($node->targetType), $this->printType($node->if), $this->printType($node->else)); } if ($node instanceof ConstTypeNode) { return $this->printConstExpr($node->constExpr); } if ($node instanceof GenericTypeNode) { $genericTypes = []; foreach ($node->genericTypes as $index => $type) { $variance = $node->variances[$index] ?? GenericTypeNode::VARIANCE_INVARIANT; if ($variance === GenericTypeNode::VARIANCE_INVARIANT) { $genericTypes[] = $this->printType($type); } elseif ($variance === GenericTypeNode::VARIANCE_BIVARIANT) { $genericTypes[] = '*'; } else { $genericTypes[] = sprintf('%s %s', $variance, $this->print($type)); } } return $node->type . '<' . implode(', ', $genericTypes) . '>'; } if ($node instanceof IdentifierTypeNode) { return $node->name; } if ($node instanceof IntersectionTypeNode || $node instanceof UnionTypeNode) { $items = []; foreach ($node->types as $type) { if ($type instanceof IntersectionTypeNode || $type instanceof UnionTypeNode || $type instanceof NullableTypeNode) { $items[] = $this->wrapInParentheses($type); continue; } $items[] = $this->printType($type); } return implode($node instanceof IntersectionTypeNode ? '&' : '|', $items); } if ($node instanceof InvalidTypeNode) { return (string) $node; } if ($node instanceof NullableTypeNode) { if ($node->type instanceof IntersectionTypeNode || $node->type instanceof UnionTypeNode) { return '?(' . $this->printType($node->type) . ')'; } return '?' . $this->printType($node->type); } if ($node instanceof ObjectShapeNode) { $items = array_map(function (ObjectShapeItemNode $item) : string { return $this->printType($item); }, $node->items); return 'object{' . implode(', ', $items) . '}'; } if ($node instanceof ObjectShapeItemNode) { if ($node->keyName !== null) { return sprintf('%s%s: %s', $this->print($node->keyName), $node->optional ? '?' : '', $this->printType($node->valueType)); } return $this->printType($node->valueType); } if ($node instanceof OffsetAccessTypeNode) { return $this->printOffsetAccessType($node->type) . '[' . $this->printType($node->offset) . ']'; } if ($node instanceof ThisTypeNode) { return (string) $node; } throw new LogicException(sprintf('Unknown node type %s', get_class($node))); } private function wrapInParentheses(TypeNode $node) : string { return '(' . $this->printType($node) . ')'; } private function printOffsetAccessType(TypeNode $type) : string { if ($type instanceof CallableTypeNode || $type instanceof UnionTypeNode || $type instanceof IntersectionTypeNode || $type instanceof NullableTypeNode) { return $this->wrapInParentheses($type); } return $this->printType($type); } private function printConstExpr(ConstExprNode $node) : string { // this is fine - ConstExprNode classes do not contain nodes that need smart printer logic return (string) $node; } /** * @param Node[] $nodes * @param Node[] $originalNodes */ private function printArrayFormatPreserving(array $nodes, array $originalNodes, TokenIterator $originalTokens, int &$tokenIndex, string $parentNodeClass, string $subNodeName) : ?string { $diff = $this->differ->diffWithReplacements($originalNodes, $nodes); $mapKey = $parentNodeClass . '->' . $subNodeName; $insertStr = $this->listInsertionMap[$mapKey] ?? null; $result = ''; $beforeFirstKeepOrReplace = \true; $delayedAdd = []; $insertNewline = \false; [$isMultiline, $beforeAsteriskIndent, $afterAsteriskIndent] = $this->isMultiline($tokenIndex, $originalNodes, $originalTokens); if ($insertStr === "\n * ") { $insertStr = sprintf('%s%s*%s', $originalTokens->getDetectedNewline() ?? "\n", $beforeAsteriskIndent, $afterAsteriskIndent); } foreach ($diff as $i => $diffElem) { $diffType = $diffElem->type; $newNode = $diffElem->new; $originalNode = $diffElem->old; if ($diffType === DiffElem::TYPE_KEEP || $diffType === DiffElem::TYPE_REPLACE) { $beforeFirstKeepOrReplace = \false; if (!$newNode instanceof Node || !$originalNode instanceof Node) { return null; } $itemStartPos = $originalNode->getAttribute(Attribute::START_INDEX); $itemEndPos = $originalNode->getAttribute(Attribute::END_INDEX); if ($itemStartPos < 0 || $itemEndPos < 0 || $itemStartPos < $tokenIndex) { throw new LogicException(); } $result .= $originalTokens->getContentBetween($tokenIndex, $itemStartPos); if (count($delayedAdd) > 0) { foreach ($delayedAdd as $delayedAddNode) { $parenthesesNeeded = isset($this->parenthesesListMap[$mapKey]) && in_array(get_class($delayedAddNode), $this->parenthesesListMap[$mapKey], \true); if ($parenthesesNeeded) { $result .= '('; } $result .= $this->printNodeFormatPreserving($delayedAddNode, $originalTokens); if ($parenthesesNeeded) { $result .= ')'; } if ($insertNewline) { $result .= $insertStr . sprintf('%s%s*%s', $originalTokens->getDetectedNewline() ?? "\n", $beforeAsteriskIndent, $afterAsteriskIndent); } else { $result .= $insertStr; } } $delayedAdd = []; } $parenthesesNeeded = isset($this->parenthesesListMap[$mapKey]) && in_array(get_class($newNode), $this->parenthesesListMap[$mapKey], \true) && !in_array(get_class($originalNode), $this->parenthesesListMap[$mapKey], \true); $addParentheses = $parenthesesNeeded && !$originalTokens->hasParentheses($itemStartPos, $itemEndPos); if ($addParentheses) { $result .= '('; } $result .= $this->printNodeFormatPreserving($newNode, $originalTokens); if ($addParentheses) { $result .= ')'; } $tokenIndex = $itemEndPos + 1; } elseif ($diffType === DiffElem::TYPE_ADD) { if ($insertStr === null) { return null; } if (!$newNode instanceof Node) { return null; } if ($insertStr === ', ' && $isMultiline) { $insertStr = ','; $insertNewline = \true; } if ($beforeFirstKeepOrReplace) { // Will be inserted at the next "replace" or "keep" element $delayedAdd[] = $newNode; continue; } $itemEndPos = $tokenIndex - 1; if ($insertNewline) { $result .= $insertStr . sprintf('%s%s*%s', $originalTokens->getDetectedNewline() ?? "\n", $beforeAsteriskIndent, $afterAsteriskIndent); } else { $result .= $insertStr; } $parenthesesNeeded = isset($this->parenthesesListMap[$mapKey]) && in_array(get_class($newNode), $this->parenthesesListMap[$mapKey], \true); if ($parenthesesNeeded) { $result .= '('; } $result .= $this->printNodeFormatPreserving($newNode, $originalTokens); if ($parenthesesNeeded) { $result .= ')'; } $tokenIndex = $itemEndPos + 1; } elseif ($diffType === DiffElem::TYPE_REMOVE) { if (!$originalNode instanceof Node) { return null; } $itemStartPos = $originalNode->getAttribute(Attribute::START_INDEX); $itemEndPos = $originalNode->getAttribute(Attribute::END_INDEX); if ($itemStartPos < 0 || $itemEndPos < 0) { throw new LogicException(); } if ($i === 0) { // If we're removing from the start, keep the tokens before the node and drop those after it, // instead of the other way around. $originalTokensArray = $originalTokens->getTokens(); for ($j = $tokenIndex; $j < $itemStartPos; $j++) { if ($originalTokensArray[$j][Lexer::TYPE_OFFSET] === Lexer::TOKEN_PHPDOC_EOL) { break; } $result .= $originalTokensArray[$j][Lexer::VALUE_OFFSET]; } } $tokenIndex = $itemEndPos + 1; } } if (count($delayedAdd) > 0) { if (!isset($this->emptyListInsertionMap[$mapKey])) { return null; } [$findToken, $extraLeft, $extraRight] = $this->emptyListInsertionMap[$mapKey]; if ($findToken !== null) { $originalTokensArray = $originalTokens->getTokens(); for (; $tokenIndex < count($originalTokensArray); $tokenIndex++) { $result .= $originalTokensArray[$tokenIndex][Lexer::VALUE_OFFSET]; if ($originalTokensArray[$tokenIndex][Lexer::VALUE_OFFSET] !== $findToken) { continue; } $tokenIndex++; break; } } $first = \true; $result .= $extraLeft; foreach ($delayedAdd as $delayedAddNode) { if (!$first) { $result .= $insertStr; if ($insertNewline) { $result .= sprintf('%s%s*%s', $originalTokens->getDetectedNewline() ?? "\n", $beforeAsteriskIndent, $afterAsteriskIndent); } } $result .= $this->printNodeFormatPreserving($delayedAddNode, $originalTokens); $first = \false; } $result .= $extraRight; } return $result; } /** * @param Node[] $nodes * @return array{bool, string, string} */ private function isMultiline(int $initialIndex, array $nodes, TokenIterator $originalTokens) : array { $isMultiline = count($nodes) > 1; $pos = $initialIndex; $allText = ''; /** @var Node|null $node */ foreach ($nodes as $node) { if (!$node instanceof Node) { continue; } $endPos = $node->getAttribute(Attribute::END_INDEX) + 1; $text = $originalTokens->getContentBetween($pos, $endPos); $allText .= $text; if (strpos($text, "\n") === \false) { // We require that a newline is present between *every* item. If the formatting // is inconsistent, with only some items having newlines, we don't consider it // as multiline $isMultiline = \false; } $pos = $endPos; } $c = preg_match_all('~\\n(?[\\x09\\x20]*)\\*(?\\x20*)~', $allText, $matches, PREG_SET_ORDER); if ($c === 0) { return [$isMultiline, '', '']; } $before = ''; $after = ''; foreach ($matches as $match) { if (strlen($match['before']) > strlen($before)) { $before = $match['before']; } if (strlen($match['after']) <= strlen($after)) { continue; } $after = $match['after']; } return [$isMultiline, $before, $after]; } private function printNodeFormatPreserving(Node $node, TokenIterator $originalTokens) : string { /** @var Node|null $originalNode */ $originalNode = $node->getAttribute(Attribute::ORIGINAL_NODE); if ($originalNode === null) { return $this->print($node); } $class = get_class($node); if ($class !== get_class($originalNode)) { throw new LogicException(); } $startPos = $originalNode->getAttribute(Attribute::START_INDEX); $endPos = $originalNode->getAttribute(Attribute::END_INDEX); if ($startPos < 0 || $endPos < 0) { throw new LogicException(); } $result = ''; $pos = $startPos; $subNodeNames = array_keys(get_object_vars($node)); foreach ($subNodeNames as $subNodeName) { $subNode = $node->{$subNodeName}; $origSubNode = $originalNode->{$subNodeName}; if (!$subNode instanceof Node && $subNode !== null || !$origSubNode instanceof Node && $origSubNode !== null) { if ($subNode === $origSubNode) { // Unchanged, can reuse old code continue; } if (is_array($subNode) && is_array($origSubNode)) { // Array subnode changed, we might be able to reconstruct it $listResult = $this->printArrayFormatPreserving($subNode, $origSubNode, $originalTokens, $pos, $class, $subNodeName); if ($listResult === null) { return $this->print($node); } $result .= $listResult; continue; } return $this->print($node); } if ($origSubNode === null) { if ($subNode === null) { // Both null, nothing to do continue; } return $this->print($node); } $subStartPos = $origSubNode->getAttribute(Attribute::START_INDEX); $subEndPos = $origSubNode->getAttribute(Attribute::END_INDEX); if ($subStartPos < 0 || $subEndPos < 0) { throw new LogicException(); } if ($subEndPos < $subStartPos) { return $this->print($node); } if ($subNode === null) { return $this->print($node); } $result .= $originalTokens->getContentBetween($pos, $subStartPos); $mapKey = get_class($node) . '->' . $subNodeName; $parenthesesNeeded = isset($this->parenthesesMap[$mapKey]) && in_array(get_class($subNode), $this->parenthesesMap[$mapKey], \true); if ($subNode->getAttribute(Attribute::ORIGINAL_NODE) !== null) { $parenthesesNeeded = $parenthesesNeeded && !in_array(get_class($subNode->getAttribute(Attribute::ORIGINAL_NODE)), $this->parenthesesMap[$mapKey], \true); } $addParentheses = $parenthesesNeeded && !$originalTokens->hasParentheses($subStartPos, $subEndPos); if ($addParentheses) { $result .= '('; } $result .= $this->printNodeFormatPreserving($subNode, $originalTokens); if ($addParentheses) { $result .= ')'; } $pos = $subEndPos + 1; } return $result . $originalTokens->getContentBetween($pos, $endPos + 1); } } '\\', 'n' => "\n", 'r' => "\r", 't' => "\t", 'f' => "\f", 'v' => "\v", 'e' => "\x1b"]; public static function unescapeString(string $string) : string { $quote = $string[0]; if ($quote === '\'') { return str_replace(['\\\\', '\\\''], ['\\', '\''], substr($string, 1, -1)); } return self::parseEscapeSequences(substr($string, 1, -1), '"'); } /** * Implementation based on https://github.com/nikic/PHP-Parser/blob/b0edd4c41111042d43bb45c6c657b2e0db367d9e/lib/PhpParser/Node/Scalar/String_.php#L90-L130 */ private static function parseEscapeSequences(string $str, string $quote) : string { $str = str_replace('\\' . $quote, $quote, $str); return preg_replace_callback('~\\\\([\\\\nrtfve]|[xX][0-9a-fA-F]{1,2}|[0-7]{1,3}|u\\{([0-9a-fA-F]+)\\})~', static function ($matches) { $str = $matches[1]; if (isset(self::REPLACEMENTS[$str])) { return self::REPLACEMENTS[$str]; } if ($str[0] === 'x' || $str[0] === 'X') { return chr((int) hexdec(substr($str, 1))); } if ($str[0] === 'u') { if (!isset($matches[2])) { throw new ShouldNotHappenException(); } return self::codePointToUtf8((int) hexdec($matches[2])); } return chr((int) octdec($str)); }, $str); } /** * Implementation based on https://github.com/nikic/PHP-Parser/blob/b0edd4c41111042d43bb45c6c657b2e0db367d9e/lib/PhpParser/Node/Scalar/String_.php#L132-L154 */ private static function codePointToUtf8(int $num) : string { if ($num <= 0x7f) { return chr($num); } if ($num <= 0x7ff) { return chr(($num >> 6) + 0xc0) . chr(($num & 0x3f) + 0x80); } if ($num <= 0xffff) { return chr(($num >> 12) + 0xe0) . chr(($num >> 6 & 0x3f) + 0x80) . chr(($num & 0x3f) + 0x80); } if ($num <= 0x1fffff) { return chr(($num >> 18) + 0xf0) . chr(($num >> 12 & 0x3f) + 0x80) . chr(($num >> 6 & 0x3f) + 0x80) . chr(($num & 0x3f) + 0x80); } // Invalid UTF-8 codepoint escape sequence: Codepoint too large return "�"; } } typeParser = $typeParser; $this->constantExprParser = $constantExprParser; $this->doctrineConstantExprParser = $constantExprParser->toDoctrine(); $this->requireWhitespaceBeforeDescription = $requireWhitespaceBeforeDescription; $this->preserveTypeAliasesWithInvalidTypes = $preserveTypeAliasesWithInvalidTypes; $this->parseDoctrineAnnotations = $parseDoctrineAnnotations; $this->useLinesAttributes = $usedAttributes['lines'] ?? \false; $this->useIndexAttributes = $usedAttributes['indexes'] ?? \false; $this->textBetweenTagsBelongsToDescription = $textBetweenTagsBelongsToDescription; } public function parse(TokenIterator $tokens) : Ast\PhpDoc\PhpDocNode { $tokens->consumeTokenType(Lexer::TOKEN_OPEN_PHPDOC); $tokens->tryConsumeTokenType(Lexer::TOKEN_PHPDOC_EOL); $children = []; if ($this->parseDoctrineAnnotations) { if (!$tokens->isCurrentTokenType(Lexer::TOKEN_CLOSE_PHPDOC)) { $lastChild = $this->parseChild($tokens); $children[] = $lastChild; while (!$tokens->isCurrentTokenType(Lexer::TOKEN_CLOSE_PHPDOC)) { if ($lastChild instanceof Ast\PhpDoc\PhpDocTagNode && ($lastChild->value instanceof Doctrine\DoctrineTagValueNode || $lastChild->value instanceof Ast\PhpDoc\GenericTagValueNode)) { $tokens->tryConsumeTokenType(Lexer::TOKEN_PHPDOC_EOL); if ($tokens->isCurrentTokenType(Lexer::TOKEN_CLOSE_PHPDOC)) { break; } $lastChild = $this->parseChild($tokens); $children[] = $lastChild; continue; } if (!$tokens->tryConsumeTokenType(Lexer::TOKEN_PHPDOC_EOL)) { break; } if ($tokens->isCurrentTokenType(Lexer::TOKEN_CLOSE_PHPDOC)) { break; } $lastChild = $this->parseChild($tokens); $children[] = $lastChild; } } } else { if (!$tokens->isCurrentTokenType(Lexer::TOKEN_CLOSE_PHPDOC)) { $children[] = $this->parseChild($tokens); while ($tokens->tryConsumeTokenType(Lexer::TOKEN_PHPDOC_EOL) && !$tokens->isCurrentTokenType(Lexer::TOKEN_CLOSE_PHPDOC)) { $children[] = $this->parseChild($tokens); } } } try { $tokens->consumeTokenType(Lexer::TOKEN_CLOSE_PHPDOC); } catch (ParserException $e) { $name = ''; $startLine = $tokens->currentTokenLine(); $startIndex = $tokens->currentTokenIndex(); if (count($children) > 0) { $lastChild = $children[count($children) - 1]; if ($lastChild instanceof Ast\PhpDoc\PhpDocTagNode) { $name = $lastChild->name; $startLine = $tokens->currentTokenLine(); $startIndex = $tokens->currentTokenIndex(); } } $tag = new Ast\PhpDoc\PhpDocTagNode($name, $this->enrichWithAttributes($tokens, new Ast\PhpDoc\InvalidTagValueNode($e->getMessage(), $e), $startLine, $startIndex)); $tokens->forwardToTheEnd(); return $this->enrichWithAttributes($tokens, new Ast\PhpDoc\PhpDocNode([$this->enrichWithAttributes($tokens, $tag, $startLine, $startIndex)]), 1, 0); } return $this->enrichWithAttributes($tokens, new Ast\PhpDoc\PhpDocNode(array_values($children)), 1, 0); } /** @phpstan-impure */ private function parseChild(TokenIterator $tokens) : Ast\PhpDoc\PhpDocChildNode { if ($tokens->isCurrentTokenType(Lexer::TOKEN_PHPDOC_TAG)) { $startLine = $tokens->currentTokenLine(); $startIndex = $tokens->currentTokenIndex(); return $this->enrichWithAttributes($tokens, $this->parseTag($tokens), $startLine, $startIndex); } if ($tokens->isCurrentTokenType(Lexer::TOKEN_DOCTRINE_TAG)) { $startLine = $tokens->currentTokenLine(); $startIndex = $tokens->currentTokenIndex(); $tag = $tokens->currentTokenValue(); $tokens->next(); $tagStartLine = $tokens->currentTokenLine(); $tagStartIndex = $tokens->currentTokenIndex(); return $this->enrichWithAttributes($tokens, new Ast\PhpDoc\PhpDocTagNode($tag, $this->enrichWithAttributes($tokens, $this->parseDoctrineTagValue($tokens, $tag), $tagStartLine, $tagStartIndex)), $startLine, $startIndex); } $startLine = $tokens->currentTokenLine(); $startIndex = $tokens->currentTokenIndex(); $text = $this->parseText($tokens); return $this->enrichWithAttributes($tokens, $text, $startLine, $startIndex); } /** * @template T of Ast\Node * @param T $tag * @return T */ private function enrichWithAttributes(TokenIterator $tokens, Ast\Node $tag, int $startLine, int $startIndex) : Ast\Node { if ($this->useLinesAttributes) { $tag->setAttribute(Ast\Attribute::START_LINE, $startLine); $tag->setAttribute(Ast\Attribute::END_LINE, $tokens->currentTokenLine()); } if ($this->useIndexAttributes) { $tag->setAttribute(Ast\Attribute::START_INDEX, $startIndex); $tag->setAttribute(Ast\Attribute::END_INDEX, $tokens->endIndexOfLastRelevantToken()); } return $tag; } private function parseText(TokenIterator $tokens) : Ast\PhpDoc\PhpDocTextNode { $text = ''; $endTokens = [Lexer::TOKEN_PHPDOC_EOL, Lexer::TOKEN_CLOSE_PHPDOC, Lexer::TOKEN_END]; if ($this->textBetweenTagsBelongsToDescription) { $endTokens = [Lexer::TOKEN_CLOSE_PHPDOC, Lexer::TOKEN_END]; } $savepoint = \false; // if the next token is EOL, everything below is skipped and empty string is returned while ($this->textBetweenTagsBelongsToDescription || !$tokens->isCurrentTokenType(Lexer::TOKEN_PHPDOC_EOL)) { $tmpText = $tokens->getSkippedHorizontalWhiteSpaceIfAny() . $tokens->joinUntil(Lexer::TOKEN_PHPDOC_EOL, ...$endTokens); $text .= $tmpText; // stop if we're not at EOL - meaning it's the end of PHPDoc if (!$tokens->isCurrentTokenType(Lexer::TOKEN_PHPDOC_EOL, Lexer::TOKEN_CLOSE_PHPDOC)) { break; } if ($this->textBetweenTagsBelongsToDescription) { if (!$savepoint) { $tokens->pushSavePoint(); $savepoint = \true; } elseif ($tmpText !== '') { $tokens->dropSavePoint(); $tokens->pushSavePoint(); } } $tokens->pushSavePoint(); $tokens->next(); // if we're at EOL, check what's next // if next is a PHPDoc tag, EOL, or end of PHPDoc, stop if ($tokens->isCurrentTokenType(Lexer::TOKEN_PHPDOC_TAG, Lexer::TOKEN_DOCTRINE_TAG, ...$endTokens)) { $tokens->rollback(); break; } // otherwise if the next is text, continue building the description string $tokens->dropSavePoint(); $text .= $tokens->getDetectedNewline() ?? "\n"; } if ($savepoint) { $tokens->rollback(); $text = rtrim($text, $tokens->getDetectedNewline() ?? "\n"); } return new Ast\PhpDoc\PhpDocTextNode(trim($text, " \t")); } private function parseOptionalDescriptionAfterDoctrineTag(TokenIterator $tokens) : string { $text = ''; $endTokens = [Lexer::TOKEN_PHPDOC_EOL, Lexer::TOKEN_CLOSE_PHPDOC, Lexer::TOKEN_END]; if ($this->textBetweenTagsBelongsToDescription) { $endTokens = [Lexer::TOKEN_CLOSE_PHPDOC, Lexer::TOKEN_END]; } $savepoint = \false; // if the next token is EOL, everything below is skipped and empty string is returned while ($this->textBetweenTagsBelongsToDescription || !$tokens->isCurrentTokenType(Lexer::TOKEN_PHPDOC_EOL)) { $tmpText = $tokens->getSkippedHorizontalWhiteSpaceIfAny() . $tokens->joinUntil(Lexer::TOKEN_PHPDOC_TAG, Lexer::TOKEN_DOCTRINE_TAG, Lexer::TOKEN_PHPDOC_EOL, ...$endTokens); $text .= $tmpText; // stop if we're not at EOL - meaning it's the end of PHPDoc if (!$tokens->isCurrentTokenType(Lexer::TOKEN_PHPDOC_EOL, Lexer::TOKEN_CLOSE_PHPDOC)) { if (!$tokens->isPrecededByHorizontalWhitespace()) { return trim($text . $this->parseText($tokens)->text, " \t"); } if ($tokens->isCurrentTokenType(Lexer::TOKEN_PHPDOC_TAG)) { $tokens->pushSavePoint(); $child = $this->parseChild($tokens); if ($child instanceof Ast\PhpDoc\PhpDocTagNode) { if ($child->value instanceof Ast\PhpDoc\GenericTagValueNode || $child->value instanceof Doctrine\DoctrineTagValueNode) { $tokens->rollback(); break; } if ($child->value instanceof Ast\PhpDoc\InvalidTagValueNode) { $tokens->rollback(); $tokens->pushSavePoint(); $tokens->next(); if ($tokens->isCurrentTokenType(Lexer::TOKEN_OPEN_PARENTHESES)) { $tokens->rollback(); break; } $tokens->rollback(); return trim($text . $this->parseText($tokens)->text, " \t"); } } $tokens->rollback(); return trim($text . $this->parseText($tokens)->text, " \t"); } break; } if ($this->textBetweenTagsBelongsToDescription) { if (!$savepoint) { $tokens->pushSavePoint(); $savepoint = \true; } elseif ($tmpText !== '') { $tokens->dropSavePoint(); $tokens->pushSavePoint(); } } $tokens->pushSavePoint(); $tokens->next(); // if we're at EOL, check what's next // if next is a PHPDoc tag, EOL, or end of PHPDoc, stop if ($tokens->isCurrentTokenType(Lexer::TOKEN_PHPDOC_TAG, Lexer::TOKEN_DOCTRINE_TAG, ...$endTokens)) { $tokens->rollback(); break; } // otherwise if the next is text, continue building the description string $tokens->dropSavePoint(); $text .= $tokens->getDetectedNewline() ?? "\n"; } if ($savepoint) { $tokens->rollback(); $text = rtrim($text, $tokens->getDetectedNewline() ?? "\n"); } return trim($text, " \t"); } public function parseTag(TokenIterator $tokens) : Ast\PhpDoc\PhpDocTagNode { $tag = $tokens->currentTokenValue(); $tokens->next(); $value = $this->parseTagValue($tokens, $tag); return new Ast\PhpDoc\PhpDocTagNode($tag, $value); } public function parseTagValue(TokenIterator $tokens, string $tag) : Ast\PhpDoc\PhpDocTagValueNode { $startLine = $tokens->currentTokenLine(); $startIndex = $tokens->currentTokenIndex(); try { $tokens->pushSavePoint(); switch ($tag) { case '@param': case '@phpstan-param': case '@psalm-param': case '@phan-param': $tagValue = $this->parseParamTagValue($tokens); break; case '@param-immediately-invoked-callable': case '@phpstan-param-immediately-invoked-callable': $tagValue = $this->parseParamImmediatelyInvokedCallableTagValue($tokens); break; case '@param-later-invoked-callable': case '@phpstan-param-later-invoked-callable': $tagValue = $this->parseParamLaterInvokedCallableTagValue($tokens); break; case '@param-closure-this': case '@phpstan-param-closure-this': $tagValue = $this->parseParamClosureThisTagValue($tokens); break; case '@var': case '@phpstan-var': case '@psalm-var': case '@phan-var': $tagValue = $this->parseVarTagValue($tokens); break; case '@return': case '@phpstan-return': case '@psalm-return': case '@phan-return': case '@phan-real-return': $tagValue = $this->parseReturnTagValue($tokens); break; case '@throws': case '@phpstan-throws': $tagValue = $this->parseThrowsTagValue($tokens); break; case '@mixin': case '@phan-mixin': $tagValue = $this->parseMixinTagValue($tokens); break; case '@psalm-require-extends': case '@phpstan-require-extends': $tagValue = $this->parseRequireExtendsTagValue($tokens); break; case '@psalm-require-implements': case '@phpstan-require-implements': $tagValue = $this->parseRequireImplementsTagValue($tokens); break; case '@deprecated': $tagValue = $this->parseDeprecatedTagValue($tokens); break; case '@property': case '@property-read': case '@property-write': case '@phpstan-property': case '@phpstan-property-read': case '@phpstan-property-write': case '@psalm-property': case '@psalm-property-read': case '@psalm-property-write': case '@phan-property': case '@phan-property-read': case '@phan-property-write': $tagValue = $this->parsePropertyTagValue($tokens); break; case '@method': case '@phpstan-method': case '@psalm-method': case '@phan-method': $tagValue = $this->parseMethodTagValue($tokens); break; case '@template': case '@phpstan-template': case '@psalm-template': case '@phan-template': case '@template-covariant': case '@phpstan-template-covariant': case '@psalm-template-covariant': case '@template-contravariant': case '@phpstan-template-contravariant': case '@psalm-template-contravariant': $tagValue = $this->typeParser->parseTemplateTagValue($tokens, function ($tokens) { return $this->parseOptionalDescription($tokens); }); break; case '@extends': case '@phpstan-extends': case '@phan-extends': case '@phan-inherits': case '@template-extends': $tagValue = $this->parseExtendsTagValue('@extends', $tokens); break; case '@implements': case '@phpstan-implements': case '@template-implements': $tagValue = $this->parseExtendsTagValue('@implements', $tokens); break; case '@use': case '@phpstan-use': case '@template-use': $tagValue = $this->parseExtendsTagValue('@use', $tokens); break; case '@phpstan-type': case '@psalm-type': case '@phan-type': $tagValue = $this->parseTypeAliasTagValue($tokens); break; case '@phpstan-import-type': case '@psalm-import-type': $tagValue = $this->parseTypeAliasImportTagValue($tokens); break; case '@phpstan-assert': case '@phpstan-assert-if-true': case '@phpstan-assert-if-false': case '@psalm-assert': case '@psalm-assert-if-true': case '@psalm-assert-if-false': case '@phan-assert': case '@phan-assert-if-true': case '@phan-assert-if-false': $tagValue = $this->parseAssertTagValue($tokens); break; case '@phpstan-this-out': case '@phpstan-self-out': case '@psalm-this-out': case '@psalm-self-out': $tagValue = $this->parseSelfOutTagValue($tokens); break; case '@param-out': case '@phpstan-param-out': case '@psalm-param-out': $tagValue = $this->parseParamOutTagValue($tokens); break; default: if ($this->parseDoctrineAnnotations) { if ($tokens->isCurrentTokenType(Lexer::TOKEN_OPEN_PARENTHESES)) { $tagValue = $this->parseDoctrineTagValue($tokens, $tag); } else { $tagValue = new Ast\PhpDoc\GenericTagValueNode($this->parseOptionalDescriptionAfterDoctrineTag($tokens)); } break; } $tagValue = new Ast\PhpDoc\GenericTagValueNode($this->parseOptionalDescription($tokens)); break; } $tokens->dropSavePoint(); } catch (ParserException $e) { $tokens->rollback(); $tagValue = new Ast\PhpDoc\InvalidTagValueNode($this->parseOptionalDescription($tokens), $e); } return $this->enrichWithAttributes($tokens, $tagValue, $startLine, $startIndex); } private function parseDoctrineTagValue(TokenIterator $tokens, string $tag) : Ast\PhpDoc\PhpDocTagValueNode { $startLine = $tokens->currentTokenLine(); $startIndex = $tokens->currentTokenIndex(); return new Doctrine\DoctrineTagValueNode($this->enrichWithAttributes($tokens, new Doctrine\DoctrineAnnotation($tag, $this->parseDoctrineArguments($tokens, \false)), $startLine, $startIndex), $this->parseOptionalDescriptionAfterDoctrineTag($tokens)); } /** * @return list */ private function parseDoctrineArguments(TokenIterator $tokens, bool $deep) : array { if (!$tokens->isCurrentTokenType(Lexer::TOKEN_OPEN_PARENTHESES)) { return []; } if (!$deep) { $tokens->addEndOfLineToSkippedTokens(); } $arguments = []; try { $tokens->consumeTokenType(Lexer::TOKEN_OPEN_PARENTHESES); do { if ($tokens->isCurrentTokenType(Lexer::TOKEN_CLOSE_PARENTHESES)) { break; } $arguments[] = $this->parseDoctrineArgument($tokens); } while ($tokens->tryConsumeTokenType(Lexer::TOKEN_COMMA)); } finally { if (!$deep) { $tokens->removeEndOfLineFromSkippedTokens(); } } $tokens->consumeTokenType(Lexer::TOKEN_CLOSE_PARENTHESES); return $arguments; } private function parseDoctrineArgument(TokenIterator $tokens) : Doctrine\DoctrineArgument { if (!$tokens->isCurrentTokenType(Lexer::TOKEN_IDENTIFIER)) { $startLine = $tokens->currentTokenLine(); $startIndex = $tokens->currentTokenIndex(); return $this->enrichWithAttributes($tokens, new Doctrine\DoctrineArgument(null, $this->parseDoctrineArgumentValue($tokens)), $startLine, $startIndex); } $startLine = $tokens->currentTokenLine(); $startIndex = $tokens->currentTokenIndex(); try { $tokens->pushSavePoint(); $currentValue = $tokens->currentTokenValue(); $tokens->consumeTokenType(Lexer::TOKEN_IDENTIFIER); $key = $this->enrichWithAttributes($tokens, new IdentifierTypeNode($currentValue), $startLine, $startIndex); $tokens->consumeTokenType(Lexer::TOKEN_EQUAL); $value = $this->parseDoctrineArgumentValue($tokens); $tokens->dropSavePoint(); return $this->enrichWithAttributes($tokens, new Doctrine\DoctrineArgument($key, $value), $startLine, $startIndex); } catch (ParserException $e) { $tokens->rollback(); return $this->enrichWithAttributes($tokens, new Doctrine\DoctrineArgument(null, $this->parseDoctrineArgumentValue($tokens)), $startLine, $startIndex); } } /** * @return DoctrineValueType */ private function parseDoctrineArgumentValue(TokenIterator $tokens) { $startLine = $tokens->currentTokenLine(); $startIndex = $tokens->currentTokenIndex(); if ($tokens->isCurrentTokenType(Lexer::TOKEN_PHPDOC_TAG, Lexer::TOKEN_DOCTRINE_TAG)) { $name = $tokens->currentTokenValue(); $tokens->next(); return $this->enrichWithAttributes($tokens, new Doctrine\DoctrineAnnotation($name, $this->parseDoctrineArguments($tokens, \true)), $startLine, $startIndex); } if ($tokens->tryConsumeTokenType(Lexer::TOKEN_OPEN_CURLY_BRACKET)) { $items = []; do { if ($tokens->isCurrentTokenType(Lexer::TOKEN_CLOSE_CURLY_BRACKET)) { break; } $items[] = $this->parseDoctrineArrayItem($tokens); } while ($tokens->tryConsumeTokenType(Lexer::TOKEN_COMMA)); $tokens->consumeTokenType(Lexer::TOKEN_CLOSE_CURLY_BRACKET); return $this->enrichWithAttributes($tokens, new Doctrine\DoctrineArray($items), $startLine, $startIndex); } $currentTokenValue = $tokens->currentTokenValue(); $tokens->pushSavePoint(); // because of ConstFetchNode if ($tokens->tryConsumeTokenType(Lexer::TOKEN_IDENTIFIER)) { $identifier = $this->enrichWithAttributes($tokens, new Ast\Type\IdentifierTypeNode($currentTokenValue), $startLine, $startIndex); if (!$tokens->isCurrentTokenType(Lexer::TOKEN_DOUBLE_COLON)) { $tokens->dropSavePoint(); return $identifier; } $tokens->rollback(); // because of ConstFetchNode } else { $tokens->dropSavePoint(); // because of ConstFetchNode } $currentTokenValue = $tokens->currentTokenValue(); $currentTokenType = $tokens->currentTokenType(); $currentTokenOffset = $tokens->currentTokenOffset(); $currentTokenLine = $tokens->currentTokenLine(); try { $constExpr = $this->doctrineConstantExprParser->parse($tokens, \true); if ($constExpr instanceof Ast\ConstExpr\ConstExprArrayNode) { throw new ParserException($currentTokenValue, $currentTokenType, $currentTokenOffset, Lexer::TOKEN_IDENTIFIER, null, $currentTokenLine); } return $constExpr; } catch (LogicException $e) { throw new ParserException($currentTokenValue, $currentTokenType, $currentTokenOffset, Lexer::TOKEN_IDENTIFIER, null, $currentTokenLine); } } private function parseDoctrineArrayItem(TokenIterator $tokens) : Doctrine\DoctrineArrayItem { $startLine = $tokens->currentTokenLine(); $startIndex = $tokens->currentTokenIndex(); try { $tokens->pushSavePoint(); $key = $this->parseDoctrineArrayKey($tokens); if (!$tokens->tryConsumeTokenType(Lexer::TOKEN_EQUAL)) { if (!$tokens->tryConsumeTokenType(Lexer::TOKEN_COLON)) { $tokens->consumeTokenType(Lexer::TOKEN_EQUAL); // will throw exception } } $value = $this->parseDoctrineArgumentValue($tokens); $tokens->dropSavePoint(); return $this->enrichWithAttributes($tokens, new Doctrine\DoctrineArrayItem($key, $value), $startLine, $startIndex); } catch (ParserException $e) { $tokens->rollback(); return $this->enrichWithAttributes($tokens, new Doctrine\DoctrineArrayItem(null, $this->parseDoctrineArgumentValue($tokens)), $startLine, $startIndex); } } /** * @return ConstExprIntegerNode|ConstExprStringNode|IdentifierTypeNode|ConstFetchNode */ private function parseDoctrineArrayKey(TokenIterator $tokens) { $startLine = $tokens->currentTokenLine(); $startIndex = $tokens->currentTokenIndex(); if ($tokens->isCurrentTokenType(Lexer::TOKEN_INTEGER)) { $key = new Ast\ConstExpr\ConstExprIntegerNode(str_replace('_', '', $tokens->currentTokenValue())); $tokens->next(); } elseif ($tokens->isCurrentTokenType(Lexer::TOKEN_DOCTRINE_ANNOTATION_STRING)) { $key = new Ast\ConstExpr\DoctrineConstExprStringNode(Ast\ConstExpr\DoctrineConstExprStringNode::unescape($tokens->currentTokenValue())); $tokens->next(); } elseif ($tokens->isCurrentTokenType(Lexer::TOKEN_DOUBLE_QUOTED_STRING)) { $value = $tokens->currentTokenValue(); $tokens->next(); $key = $this->doctrineConstantExprParser->parseDoctrineString($value, $tokens); } else { $currentTokenValue = $tokens->currentTokenValue(); $tokens->pushSavePoint(); // because of ConstFetchNode if (!$tokens->tryConsumeTokenType(Lexer::TOKEN_IDENTIFIER)) { $tokens->dropSavePoint(); throw new ParserException($tokens->currentTokenValue(), $tokens->currentTokenType(), $tokens->currentTokenOffset(), Lexer::TOKEN_IDENTIFIER, null, $tokens->currentTokenLine()); } if (!$tokens->isCurrentTokenType(Lexer::TOKEN_DOUBLE_COLON)) { $tokens->dropSavePoint(); return $this->enrichWithAttributes($tokens, new IdentifierTypeNode($currentTokenValue), $startLine, $startIndex); } $tokens->rollback(); $constExpr = $this->doctrineConstantExprParser->parse($tokens, \true); if (!$constExpr instanceof Ast\ConstExpr\ConstFetchNode) { throw new ParserException($tokens->currentTokenValue(), $tokens->currentTokenType(), $tokens->currentTokenOffset(), Lexer::TOKEN_IDENTIFIER, null, $tokens->currentTokenLine()); } return $constExpr; } return $this->enrichWithAttributes($tokens, $key, $startLine, $startIndex); } /** * @return Ast\PhpDoc\ParamTagValueNode|Ast\PhpDoc\TypelessParamTagValueNode */ private function parseParamTagValue(TokenIterator $tokens) : Ast\PhpDoc\PhpDocTagValueNode { if ($tokens->isCurrentTokenType(Lexer::TOKEN_REFERENCE, Lexer::TOKEN_VARIADIC, Lexer::TOKEN_VARIABLE)) { $type = null; } else { $type = $this->typeParser->parse($tokens); } $isReference = $tokens->tryConsumeTokenType(Lexer::TOKEN_REFERENCE); $isVariadic = $tokens->tryConsumeTokenType(Lexer::TOKEN_VARIADIC); $parameterName = $this->parseRequiredVariableName($tokens); $description = $this->parseOptionalDescription($tokens); if ($type !== null) { return new Ast\PhpDoc\ParamTagValueNode($type, $isVariadic, $parameterName, $description, $isReference); } return new Ast\PhpDoc\TypelessParamTagValueNode($isVariadic, $parameterName, $description, $isReference); } private function parseParamImmediatelyInvokedCallableTagValue(TokenIterator $tokens) : Ast\PhpDoc\ParamImmediatelyInvokedCallableTagValueNode { $parameterName = $this->parseRequiredVariableName($tokens); $description = $this->parseOptionalDescription($tokens); return new Ast\PhpDoc\ParamImmediatelyInvokedCallableTagValueNode($parameterName, $description); } private function parseParamLaterInvokedCallableTagValue(TokenIterator $tokens) : Ast\PhpDoc\ParamLaterInvokedCallableTagValueNode { $parameterName = $this->parseRequiredVariableName($tokens); $description = $this->parseOptionalDescription($tokens); return new Ast\PhpDoc\ParamLaterInvokedCallableTagValueNode($parameterName, $description); } private function parseParamClosureThisTagValue(TokenIterator $tokens) : Ast\PhpDoc\ParamClosureThisTagValueNode { $type = $this->typeParser->parse($tokens); $parameterName = $this->parseRequiredVariableName($tokens); $description = $this->parseOptionalDescription($tokens); return new Ast\PhpDoc\ParamClosureThisTagValueNode($type, $parameterName, $description); } private function parseVarTagValue(TokenIterator $tokens) : Ast\PhpDoc\VarTagValueNode { $type = $this->typeParser->parse($tokens); $variableName = $this->parseOptionalVariableName($tokens); $description = $this->parseOptionalDescription($tokens, $variableName === ''); return new Ast\PhpDoc\VarTagValueNode($type, $variableName, $description); } private function parseReturnTagValue(TokenIterator $tokens) : Ast\PhpDoc\ReturnTagValueNode { $type = $this->typeParser->parse($tokens); $description = $this->parseOptionalDescription($tokens, \true); return new Ast\PhpDoc\ReturnTagValueNode($type, $description); } private function parseThrowsTagValue(TokenIterator $tokens) : Ast\PhpDoc\ThrowsTagValueNode { $type = $this->typeParser->parse($tokens); $description = $this->parseOptionalDescription($tokens, \true); return new Ast\PhpDoc\ThrowsTagValueNode($type, $description); } private function parseMixinTagValue(TokenIterator $tokens) : Ast\PhpDoc\MixinTagValueNode { $type = $this->typeParser->parse($tokens); $description = $this->parseOptionalDescription($tokens, \true); return new Ast\PhpDoc\MixinTagValueNode($type, $description); } private function parseRequireExtendsTagValue(TokenIterator $tokens) : Ast\PhpDoc\RequireExtendsTagValueNode { $type = $this->typeParser->parse($tokens); $description = $this->parseOptionalDescription($tokens, \true); return new Ast\PhpDoc\RequireExtendsTagValueNode($type, $description); } private function parseRequireImplementsTagValue(TokenIterator $tokens) : Ast\PhpDoc\RequireImplementsTagValueNode { $type = $this->typeParser->parse($tokens); $description = $this->parseOptionalDescription($tokens, \true); return new Ast\PhpDoc\RequireImplementsTagValueNode($type, $description); } private function parseDeprecatedTagValue(TokenIterator $tokens) : Ast\PhpDoc\DeprecatedTagValueNode { $description = $this->parseOptionalDescription($tokens); return new Ast\PhpDoc\DeprecatedTagValueNode($description); } private function parsePropertyTagValue(TokenIterator $tokens) : Ast\PhpDoc\PropertyTagValueNode { $type = $this->typeParser->parse($tokens); $parameterName = $this->parseRequiredVariableName($tokens); $description = $this->parseOptionalDescription($tokens); return new Ast\PhpDoc\PropertyTagValueNode($type, $parameterName, $description); } private function parseMethodTagValue(TokenIterator $tokens) : Ast\PhpDoc\MethodTagValueNode { $staticKeywordOrReturnTypeOrMethodName = $this->typeParser->parse($tokens); if ($staticKeywordOrReturnTypeOrMethodName instanceof Ast\Type\IdentifierTypeNode && $staticKeywordOrReturnTypeOrMethodName->name === 'static') { $isStatic = \true; $returnTypeOrMethodName = $this->typeParser->parse($tokens); } else { $isStatic = \false; $returnTypeOrMethodName = $staticKeywordOrReturnTypeOrMethodName; } if ($tokens->isCurrentTokenType(Lexer::TOKEN_IDENTIFIER)) { $returnType = $returnTypeOrMethodName; $methodName = $tokens->currentTokenValue(); $tokens->next(); } elseif ($returnTypeOrMethodName instanceof Ast\Type\IdentifierTypeNode) { $returnType = $isStatic ? $staticKeywordOrReturnTypeOrMethodName : null; $methodName = $returnTypeOrMethodName->name; $isStatic = \false; } else { $tokens->consumeTokenType(Lexer::TOKEN_IDENTIFIER); // will throw exception exit; } $templateTypes = []; if ($tokens->tryConsumeTokenType(Lexer::TOKEN_OPEN_ANGLE_BRACKET)) { do { $startLine = $tokens->currentTokenLine(); $startIndex = $tokens->currentTokenIndex(); $templateTypes[] = $this->enrichWithAttributes($tokens, $this->typeParser->parseTemplateTagValue($tokens), $startLine, $startIndex); } while ($tokens->tryConsumeTokenType(Lexer::TOKEN_COMMA)); $tokens->consumeTokenType(Lexer::TOKEN_CLOSE_ANGLE_BRACKET); } $parameters = []; $tokens->consumeTokenType(Lexer::TOKEN_OPEN_PARENTHESES); if (!$tokens->isCurrentTokenType(Lexer::TOKEN_CLOSE_PARENTHESES)) { $parameters[] = $this->parseMethodTagValueParameter($tokens); while ($tokens->tryConsumeTokenType(Lexer::TOKEN_COMMA)) { $parameters[] = $this->parseMethodTagValueParameter($tokens); } } $tokens->consumeTokenType(Lexer::TOKEN_CLOSE_PARENTHESES); $description = $this->parseOptionalDescription($tokens); return new Ast\PhpDoc\MethodTagValueNode($isStatic, $returnType, $methodName, $parameters, $description, $templateTypes); } private function parseMethodTagValueParameter(TokenIterator $tokens) : Ast\PhpDoc\MethodTagValueParameterNode { $startLine = $tokens->currentTokenLine(); $startIndex = $tokens->currentTokenIndex(); switch ($tokens->currentTokenType()) { case Lexer::TOKEN_IDENTIFIER: case Lexer::TOKEN_OPEN_PARENTHESES: case Lexer::TOKEN_NULLABLE: $parameterType = $this->typeParser->parse($tokens); break; default: $parameterType = null; } $isReference = $tokens->tryConsumeTokenType(Lexer::TOKEN_REFERENCE); $isVariadic = $tokens->tryConsumeTokenType(Lexer::TOKEN_VARIADIC); $parameterName = $tokens->currentTokenValue(); $tokens->consumeTokenType(Lexer::TOKEN_VARIABLE); if ($tokens->tryConsumeTokenType(Lexer::TOKEN_EQUAL)) { $defaultValue = $this->constantExprParser->parse($tokens); } else { $defaultValue = null; } return $this->enrichWithAttributes($tokens, new Ast\PhpDoc\MethodTagValueParameterNode($parameterType, $isReference, $isVariadic, $parameterName, $defaultValue), $startLine, $startIndex); } private function parseExtendsTagValue(string $tagName, TokenIterator $tokens) : Ast\PhpDoc\PhpDocTagValueNode { $startLine = $tokens->currentTokenLine(); $startIndex = $tokens->currentTokenIndex(); $baseType = new IdentifierTypeNode($tokens->currentTokenValue()); $tokens->consumeTokenType(Lexer::TOKEN_IDENTIFIER); $type = $this->typeParser->parseGeneric($tokens, $this->typeParser->enrichWithAttributes($tokens, $baseType, $startLine, $startIndex)); $description = $this->parseOptionalDescription($tokens); switch ($tagName) { case '@extends': return new Ast\PhpDoc\ExtendsTagValueNode($type, $description); case '@implements': return new Ast\PhpDoc\ImplementsTagValueNode($type, $description); case '@use': return new Ast\PhpDoc\UsesTagValueNode($type, $description); } throw new ShouldNotHappenException(); } private function parseTypeAliasTagValue(TokenIterator $tokens) : Ast\PhpDoc\TypeAliasTagValueNode { $alias = $tokens->currentTokenValue(); $tokens->consumeTokenType(Lexer::TOKEN_IDENTIFIER); // support phan-type/psalm-type syntax $tokens->tryConsumeTokenType(Lexer::TOKEN_EQUAL); if ($this->preserveTypeAliasesWithInvalidTypes) { $startLine = $tokens->currentTokenLine(); $startIndex = $tokens->currentTokenIndex(); try { $type = $this->typeParser->parse($tokens); if (!$tokens->isCurrentTokenType(Lexer::TOKEN_CLOSE_PHPDOC)) { if (!$tokens->isCurrentTokenType(Lexer::TOKEN_PHPDOC_EOL)) { throw new ParserException($tokens->currentTokenValue(), $tokens->currentTokenType(), $tokens->currentTokenOffset(), Lexer::TOKEN_PHPDOC_EOL, null, $tokens->currentTokenLine()); } } return new Ast\PhpDoc\TypeAliasTagValueNode($alias, $type); } catch (ParserException $e) { $this->parseOptionalDescription($tokens); return new Ast\PhpDoc\TypeAliasTagValueNode($alias, $this->enrichWithAttributes($tokens, new Ast\Type\InvalidTypeNode($e), $startLine, $startIndex)); } } $type = $this->typeParser->parse($tokens); return new Ast\PhpDoc\TypeAliasTagValueNode($alias, $type); } private function parseTypeAliasImportTagValue(TokenIterator $tokens) : Ast\PhpDoc\TypeAliasImportTagValueNode { $importedAlias = $tokens->currentTokenValue(); $tokens->consumeTokenType(Lexer::TOKEN_IDENTIFIER); $tokens->consumeTokenValue(Lexer::TOKEN_IDENTIFIER, 'from'); $identifierStartLine = $tokens->currentTokenLine(); $identifierStartIndex = $tokens->currentTokenIndex(); $importedFrom = $tokens->currentTokenValue(); $tokens->consumeTokenType(Lexer::TOKEN_IDENTIFIER); $importedFromType = $this->enrichWithAttributes($tokens, new IdentifierTypeNode($importedFrom), $identifierStartLine, $identifierStartIndex); $importedAs = null; if ($tokens->tryConsumeTokenValue('as')) { $importedAs = $tokens->currentTokenValue(); $tokens->consumeTokenType(Lexer::TOKEN_IDENTIFIER); } return new Ast\PhpDoc\TypeAliasImportTagValueNode($importedAlias, $importedFromType, $importedAs); } /** * @return Ast\PhpDoc\AssertTagValueNode|Ast\PhpDoc\AssertTagPropertyValueNode|Ast\PhpDoc\AssertTagMethodValueNode */ private function parseAssertTagValue(TokenIterator $tokens) : Ast\PhpDoc\PhpDocTagValueNode { $isNegated = $tokens->tryConsumeTokenType(Lexer::TOKEN_NEGATED); $isEquality = $tokens->tryConsumeTokenType(Lexer::TOKEN_EQUAL); $type = $this->typeParser->parse($tokens); $parameter = $this->parseAssertParameter($tokens); $description = $this->parseOptionalDescription($tokens); if (array_key_exists('method', $parameter)) { return new Ast\PhpDoc\AssertTagMethodValueNode($type, $parameter['parameter'], $parameter['method'], $isNegated, $description, $isEquality); } elseif (array_key_exists('property', $parameter)) { return new Ast\PhpDoc\AssertTagPropertyValueNode($type, $parameter['parameter'], $parameter['property'], $isNegated, $description, $isEquality); } return new Ast\PhpDoc\AssertTagValueNode($type, $parameter['parameter'], $isNegated, $description, $isEquality); } /** * @return array{parameter: string}|array{parameter: string, property: string}|array{parameter: string, method: string} */ private function parseAssertParameter(TokenIterator $tokens) : array { if ($tokens->isCurrentTokenType(Lexer::TOKEN_THIS_VARIABLE)) { $parameter = '$this'; $tokens->next(); } else { $parameter = $tokens->currentTokenValue(); $tokens->consumeTokenType(Lexer::TOKEN_VARIABLE); } if ($tokens->isCurrentTokenType(Lexer::TOKEN_ARROW)) { $tokens->consumeTokenType(Lexer::TOKEN_ARROW); $propertyOrMethod = $tokens->currentTokenValue(); $tokens->consumeTokenType(Lexer::TOKEN_IDENTIFIER); if ($tokens->tryConsumeTokenType(Lexer::TOKEN_OPEN_PARENTHESES)) { $tokens->consumeTokenType(Lexer::TOKEN_CLOSE_PARENTHESES); return ['parameter' => $parameter, 'method' => $propertyOrMethod]; } return ['parameter' => $parameter, 'property' => $propertyOrMethod]; } return ['parameter' => $parameter]; } private function parseSelfOutTagValue(TokenIterator $tokens) : Ast\PhpDoc\SelfOutTagValueNode { $type = $this->typeParser->parse($tokens); $description = $this->parseOptionalDescription($tokens); return new Ast\PhpDoc\SelfOutTagValueNode($type, $description); } private function parseParamOutTagValue(TokenIterator $tokens) : Ast\PhpDoc\ParamOutTagValueNode { $type = $this->typeParser->parse($tokens); $parameterName = $this->parseRequiredVariableName($tokens); $description = $this->parseOptionalDescription($tokens); return new Ast\PhpDoc\ParamOutTagValueNode($type, $parameterName, $description); } private function parseOptionalVariableName(TokenIterator $tokens) : string { if ($tokens->isCurrentTokenType(Lexer::TOKEN_VARIABLE)) { $parameterName = $tokens->currentTokenValue(); $tokens->next(); } elseif ($tokens->isCurrentTokenType(Lexer::TOKEN_THIS_VARIABLE)) { $parameterName = '$this'; $tokens->next(); } else { $parameterName = ''; } return $parameterName; } private function parseRequiredVariableName(TokenIterator $tokens) : string { $parameterName = $tokens->currentTokenValue(); $tokens->consumeTokenType(Lexer::TOKEN_VARIABLE); return $parameterName; } private function parseOptionalDescription(TokenIterator $tokens, bool $limitStartToken = \false) : string { if ($limitStartToken) { foreach (self::DISALLOWED_DESCRIPTION_START_TOKENS as $disallowedStartToken) { if (!$tokens->isCurrentTokenType($disallowedStartToken)) { continue; } $tokens->consumeTokenType(Lexer::TOKEN_OTHER); // will throw exception } if ($this->requireWhitespaceBeforeDescription && !$tokens->isCurrentTokenType(Lexer::TOKEN_PHPDOC_EOL, Lexer::TOKEN_CLOSE_PHPDOC, Lexer::TOKEN_END) && !$tokens->isPrecededByHorizontalWhitespace()) { $tokens->consumeTokenType(Lexer::TOKEN_HORIZONTAL_WS); // will throw exception } } return $this->parseText($tokens)->text; } } currentTokenValue = $currentTokenValue; $this->currentTokenType = $currentTokenType; $this->currentOffset = $currentOffset; $this->expectedTokenType = $expectedTokenType; $this->expectedTokenValue = $expectedTokenValue; $this->currentTokenLine = $currentTokenLine; parent::__construct(sprintf('Unexpected token %s, expected %s%s at offset %d%s', $this->formatValue($currentTokenValue), Lexer::TOKEN_LABELS[$expectedTokenType], $expectedTokenValue !== null ? sprintf(' (%s)', $this->formatValue($expectedTokenValue)) : '', $currentOffset, $currentTokenLine === null ? '' : sprintf(' on line %d', $currentTokenLine))); } public function getCurrentTokenValue() : string { return $this->currentTokenValue; } public function getCurrentTokenType() : int { return $this->currentTokenType; } public function getCurrentOffset() : int { return $this->currentOffset; } public function getExpectedTokenType() : int { return $this->expectedTokenType; } public function getExpectedTokenValue() : ?string { return $this->expectedTokenValue; } public function getCurrentTokenLine() : ?int { return $this->currentTokenLine; } private function formatValue(string $value) : string { $json = json_encode($value, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES | JSON_INVALID_UTF8_SUBSTITUTE); assert($json !== \false); return $json; } } constExprParser = $constExprParser; $this->quoteAwareConstExprString = $quoteAwareConstExprString; $this->useLinesAttributes = $usedAttributes['lines'] ?? \false; $this->useIndexAttributes = $usedAttributes['indexes'] ?? \false; } /** @phpstan-impure */ public function parse(TokenIterator $tokens) : Ast\Type\TypeNode { $startLine = $tokens->currentTokenLine(); $startIndex = $tokens->currentTokenIndex(); if ($tokens->isCurrentTokenType(Lexer::TOKEN_NULLABLE)) { $type = $this->parseNullable($tokens); } else { $type = $this->parseAtomic($tokens); if ($tokens->isCurrentTokenType(Lexer::TOKEN_UNION)) { $type = $this->parseUnion($tokens, $type); } elseif ($tokens->isCurrentTokenType(Lexer::TOKEN_INTERSECTION)) { $type = $this->parseIntersection($tokens, $type); } } return $this->enrichWithAttributes($tokens, $type, $startLine, $startIndex); } /** * @internal * @template T of Ast\Node * @param T $type * @return T */ public function enrichWithAttributes(TokenIterator $tokens, Ast\Node $type, int $startLine, int $startIndex) : Ast\Node { if ($this->useLinesAttributes) { $type->setAttribute(Ast\Attribute::START_LINE, $startLine); $type->setAttribute(Ast\Attribute::END_LINE, $tokens->currentTokenLine()); } if ($this->useIndexAttributes) { $type->setAttribute(Ast\Attribute::START_INDEX, $startIndex); $type->setAttribute(Ast\Attribute::END_INDEX, $tokens->endIndexOfLastRelevantToken()); } return $type; } /** @phpstan-impure */ private function subParse(TokenIterator $tokens) : Ast\Type\TypeNode { $startLine = $tokens->currentTokenLine(); $startIndex = $tokens->currentTokenIndex(); if ($tokens->isCurrentTokenType(Lexer::TOKEN_NULLABLE)) { $type = $this->parseNullable($tokens); } elseif ($tokens->isCurrentTokenType(Lexer::TOKEN_VARIABLE)) { $type = $this->parseConditionalForParameter($tokens, $tokens->currentTokenValue()); } else { $type = $this->parseAtomic($tokens); if ($tokens->isCurrentTokenValue('is')) { $type = $this->parseConditional($tokens, $type); } else { $tokens->tryConsumeTokenType(Lexer::TOKEN_PHPDOC_EOL); if ($tokens->isCurrentTokenType(Lexer::TOKEN_UNION)) { $type = $this->subParseUnion($tokens, $type); } elseif ($tokens->isCurrentTokenType(Lexer::TOKEN_INTERSECTION)) { $type = $this->subParseIntersection($tokens, $type); } } } return $this->enrichWithAttributes($tokens, $type, $startLine, $startIndex); } /** @phpstan-impure */ private function parseAtomic(TokenIterator $tokens) : Ast\Type\TypeNode { $startLine = $tokens->currentTokenLine(); $startIndex = $tokens->currentTokenIndex(); if ($tokens->tryConsumeTokenType(Lexer::TOKEN_OPEN_PARENTHESES)) { $tokens->tryConsumeTokenType(Lexer::TOKEN_PHPDOC_EOL); $type = $this->subParse($tokens); $tokens->tryConsumeTokenType(Lexer::TOKEN_PHPDOC_EOL); $tokens->consumeTokenType(Lexer::TOKEN_CLOSE_PARENTHESES); if ($tokens->isCurrentTokenType(Lexer::TOKEN_OPEN_SQUARE_BRACKET)) { $type = $this->tryParseArrayOrOffsetAccess($tokens, $type); } return $this->enrichWithAttributes($tokens, $type, $startLine, $startIndex); } if ($tokens->tryConsumeTokenType(Lexer::TOKEN_THIS_VARIABLE)) { $type = $this->enrichWithAttributes($tokens, new Ast\Type\ThisTypeNode(), $startLine, $startIndex); if ($tokens->isCurrentTokenType(Lexer::TOKEN_OPEN_SQUARE_BRACKET)) { $type = $this->tryParseArrayOrOffsetAccess($tokens, $type); } return $this->enrichWithAttributes($tokens, $type, $startLine, $startIndex); } $currentTokenValue = $tokens->currentTokenValue(); $tokens->pushSavePoint(); // because of ConstFetchNode if ($tokens->tryConsumeTokenType(Lexer::TOKEN_IDENTIFIER)) { $type = $this->enrichWithAttributes($tokens, new Ast\Type\IdentifierTypeNode($currentTokenValue), $startLine, $startIndex); if (!$tokens->isCurrentTokenType(Lexer::TOKEN_DOUBLE_COLON)) { $tokens->dropSavePoint(); // because of ConstFetchNode if ($tokens->isCurrentTokenType(Lexer::TOKEN_OPEN_ANGLE_BRACKET)) { $tokens->pushSavePoint(); $isHtml = $this->isHtml($tokens); $tokens->rollback(); if ($isHtml) { return $type; } $origType = $type; $type = $this->tryParseCallable($tokens, $type, \true); if ($type === $origType) { $type = $this->parseGeneric($tokens, $type); if ($tokens->isCurrentTokenType(Lexer::TOKEN_OPEN_SQUARE_BRACKET)) { $type = $this->tryParseArrayOrOffsetAccess($tokens, $type); } } } elseif ($tokens->isCurrentTokenType(Lexer::TOKEN_OPEN_PARENTHESES)) { $type = $this->tryParseCallable($tokens, $type, \false); } elseif ($tokens->isCurrentTokenType(Lexer::TOKEN_OPEN_SQUARE_BRACKET)) { $type = $this->tryParseArrayOrOffsetAccess($tokens, $type); } elseif (in_array($type->name, ['array', 'list', 'object'], \true) && $tokens->isCurrentTokenType(Lexer::TOKEN_OPEN_CURLY_BRACKET) && !$tokens->isPrecededByHorizontalWhitespace()) { if ($type->name === 'object') { $type = $this->parseObjectShape($tokens); } else { $type = $this->parseArrayShape($tokens, $type, $type->name); } if ($tokens->isCurrentTokenType(Lexer::TOKEN_OPEN_SQUARE_BRACKET)) { $type = $this->tryParseArrayOrOffsetAccess($tokens, $this->enrichWithAttributes($tokens, $type, $startLine, $startIndex)); } } return $this->enrichWithAttributes($tokens, $type, $startLine, $startIndex); } else { $tokens->rollback(); // because of ConstFetchNode } } else { $tokens->dropSavePoint(); // because of ConstFetchNode } $currentTokenValue = $tokens->currentTokenValue(); $currentTokenType = $tokens->currentTokenType(); $currentTokenOffset = $tokens->currentTokenOffset(); $currentTokenLine = $tokens->currentTokenLine(); if ($this->constExprParser === null) { throw new ParserException($currentTokenValue, $currentTokenType, $currentTokenOffset, Lexer::TOKEN_IDENTIFIER, null, $currentTokenLine); } try { $constExpr = $this->constExprParser->parse($tokens, \true); if ($constExpr instanceof Ast\ConstExpr\ConstExprArrayNode) { throw new ParserException($currentTokenValue, $currentTokenType, $currentTokenOffset, Lexer::TOKEN_IDENTIFIER, null, $currentTokenLine); } $type = $this->enrichWithAttributes($tokens, new Ast\Type\ConstTypeNode($constExpr), $startLine, $startIndex); if ($tokens->isCurrentTokenType(Lexer::TOKEN_OPEN_SQUARE_BRACKET)) { $type = $this->tryParseArrayOrOffsetAccess($tokens, $type); } return $type; } catch (LogicException $e) { throw new ParserException($currentTokenValue, $currentTokenType, $currentTokenOffset, Lexer::TOKEN_IDENTIFIER, null, $currentTokenLine); } } /** @phpstan-impure */ private function parseUnion(TokenIterator $tokens, Ast\Type\TypeNode $type) : Ast\Type\TypeNode { $types = [$type]; while ($tokens->tryConsumeTokenType(Lexer::TOKEN_UNION)) { $types[] = $this->parseAtomic($tokens); } return new Ast\Type\UnionTypeNode($types); } /** @phpstan-impure */ private function subParseUnion(TokenIterator $tokens, Ast\Type\TypeNode $type) : Ast\Type\TypeNode { $types = [$type]; while ($tokens->tryConsumeTokenType(Lexer::TOKEN_UNION)) { $tokens->tryConsumeTokenType(Lexer::TOKEN_PHPDOC_EOL); $types[] = $this->parseAtomic($tokens); $tokens->tryConsumeTokenType(Lexer::TOKEN_PHPDOC_EOL); } return new Ast\Type\UnionTypeNode($types); } /** @phpstan-impure */ private function parseIntersection(TokenIterator $tokens, Ast\Type\TypeNode $type) : Ast\Type\TypeNode { $types = [$type]; while ($tokens->tryConsumeTokenType(Lexer::TOKEN_INTERSECTION)) { $types[] = $this->parseAtomic($tokens); } return new Ast\Type\IntersectionTypeNode($types); } /** @phpstan-impure */ private function subParseIntersection(TokenIterator $tokens, Ast\Type\TypeNode $type) : Ast\Type\TypeNode { $types = [$type]; while ($tokens->tryConsumeTokenType(Lexer::TOKEN_INTERSECTION)) { $tokens->tryConsumeTokenType(Lexer::TOKEN_PHPDOC_EOL); $types[] = $this->parseAtomic($tokens); $tokens->tryConsumeTokenType(Lexer::TOKEN_PHPDOC_EOL); } return new Ast\Type\IntersectionTypeNode($types); } /** @phpstan-impure */ private function parseConditional(TokenIterator $tokens, Ast\Type\TypeNode $subjectType) : Ast\Type\TypeNode { $tokens->consumeTokenType(Lexer::TOKEN_IDENTIFIER); $negated = \false; if ($tokens->isCurrentTokenValue('not')) { $negated = \true; $tokens->consumeTokenType(Lexer::TOKEN_IDENTIFIER); } $targetType = $this->parse($tokens); $tokens->tryConsumeTokenType(Lexer::TOKEN_PHPDOC_EOL); $tokens->consumeTokenType(Lexer::TOKEN_NULLABLE); $tokens->tryConsumeTokenType(Lexer::TOKEN_PHPDOC_EOL); $ifType = $this->parse($tokens); $tokens->tryConsumeTokenType(Lexer::TOKEN_PHPDOC_EOL); $tokens->consumeTokenType(Lexer::TOKEN_COLON); $tokens->tryConsumeTokenType(Lexer::TOKEN_PHPDOC_EOL); $elseType = $this->subParse($tokens); return new Ast\Type\ConditionalTypeNode($subjectType, $targetType, $ifType, $elseType, $negated); } /** @phpstan-impure */ private function parseConditionalForParameter(TokenIterator $tokens, string $parameterName) : Ast\Type\TypeNode { $tokens->consumeTokenType(Lexer::TOKEN_VARIABLE); $tokens->consumeTokenValue(Lexer::TOKEN_IDENTIFIER, 'is'); $negated = \false; if ($tokens->isCurrentTokenValue('not')) { $negated = \true; $tokens->consumeTokenType(Lexer::TOKEN_IDENTIFIER); } $targetType = $this->parse($tokens); $tokens->tryConsumeTokenType(Lexer::TOKEN_PHPDOC_EOL); $tokens->consumeTokenType(Lexer::TOKEN_NULLABLE); $tokens->tryConsumeTokenType(Lexer::TOKEN_PHPDOC_EOL); $ifType = $this->parse($tokens); $tokens->tryConsumeTokenType(Lexer::TOKEN_PHPDOC_EOL); $tokens->consumeTokenType(Lexer::TOKEN_COLON); $tokens->tryConsumeTokenType(Lexer::TOKEN_PHPDOC_EOL); $elseType = $this->subParse($tokens); return new Ast\Type\ConditionalTypeForParameterNode($parameterName, $targetType, $ifType, $elseType, $negated); } /** @phpstan-impure */ private function parseNullable(TokenIterator $tokens) : Ast\Type\TypeNode { $tokens->consumeTokenType(Lexer::TOKEN_NULLABLE); $type = $this->parseAtomic($tokens); return new Ast\Type\NullableTypeNode($type); } /** @phpstan-impure */ public function isHtml(TokenIterator $tokens) : bool { $tokens->consumeTokenType(Lexer::TOKEN_OPEN_ANGLE_BRACKET); if (!$tokens->isCurrentTokenType(Lexer::TOKEN_IDENTIFIER)) { return \false; } $htmlTagName = $tokens->currentTokenValue(); $tokens->next(); if (!$tokens->tryConsumeTokenType(Lexer::TOKEN_CLOSE_ANGLE_BRACKET)) { return \false; } $endTag = ''; $endTagSearchOffset = -strlen($endTag); while (!$tokens->isCurrentTokenType(Lexer::TOKEN_END)) { if ($tokens->tryConsumeTokenType(Lexer::TOKEN_OPEN_ANGLE_BRACKET) && strpos($tokens->currentTokenValue(), '/' . $htmlTagName . '>') !== \false || substr_compare($tokens->currentTokenValue(), $endTag, $endTagSearchOffset) === 0) { return \true; } $tokens->next(); } return \false; } /** @phpstan-impure */ public function parseGeneric(TokenIterator $tokens, Ast\Type\IdentifierTypeNode $baseType) : Ast\Type\GenericTypeNode { $tokens->consumeTokenType(Lexer::TOKEN_OPEN_ANGLE_BRACKET); $startLine = $baseType->getAttribute(Ast\Attribute::START_LINE); $startIndex = $baseType->getAttribute(Ast\Attribute::START_INDEX); $genericTypes = []; $variances = []; $isFirst = \true; while ($isFirst || $tokens->tryConsumeTokenType(Lexer::TOKEN_COMMA)) { $tokens->tryConsumeTokenType(Lexer::TOKEN_PHPDOC_EOL); // trailing comma case if (!$isFirst && $tokens->isCurrentTokenType(Lexer::TOKEN_CLOSE_ANGLE_BRACKET)) { break; } $isFirst = \false; [$genericTypes[], $variances[]] = $this->parseGenericTypeArgument($tokens); $tokens->tryConsumeTokenType(Lexer::TOKEN_PHPDOC_EOL); } $type = new Ast\Type\GenericTypeNode($baseType, $genericTypes, $variances); if ($startLine !== null && $startIndex !== null) { $type = $this->enrichWithAttributes($tokens, $type, $startLine, $startIndex); } $tokens->consumeTokenType(Lexer::TOKEN_CLOSE_ANGLE_BRACKET); return $type; } /** * @phpstan-impure * @return array{Ast\Type\TypeNode, Ast\Type\GenericTypeNode::VARIANCE_*} */ public function parseGenericTypeArgument(TokenIterator $tokens) : array { $startLine = $tokens->currentTokenLine(); $startIndex = $tokens->currentTokenIndex(); if ($tokens->tryConsumeTokenType(Lexer::TOKEN_WILDCARD)) { return [$this->enrichWithAttributes($tokens, new Ast\Type\IdentifierTypeNode('mixed'), $startLine, $startIndex), Ast\Type\GenericTypeNode::VARIANCE_BIVARIANT]; } if ($tokens->tryConsumeTokenValue('contravariant')) { $variance = Ast\Type\GenericTypeNode::VARIANCE_CONTRAVARIANT; } elseif ($tokens->tryConsumeTokenValue('covariant')) { $variance = Ast\Type\GenericTypeNode::VARIANCE_COVARIANT; } else { $variance = Ast\Type\GenericTypeNode::VARIANCE_INVARIANT; } $type = $this->parse($tokens); return [$type, $variance]; } /** * @throws ParserException * @param ?callable(TokenIterator): string $parseDescription */ public function parseTemplateTagValue(TokenIterator $tokens, ?callable $parseDescription = null) : TemplateTagValueNode { $name = $tokens->currentTokenValue(); $tokens->consumeTokenType(Lexer::TOKEN_IDENTIFIER); if ($tokens->tryConsumeTokenValue('of') || $tokens->tryConsumeTokenValue('as')) { $bound = $this->parse($tokens); } else { $bound = null; } if ($tokens->tryConsumeTokenValue('=')) { $default = $this->parse($tokens); } else { $default = null; } if ($parseDescription !== null) { $description = $parseDescription($tokens); } else { $description = ''; } if ($name === '') { throw new LogicException('Template tag name cannot be empty.'); } return new Ast\PhpDoc\TemplateTagValueNode($name, $bound, $description, $default); } /** @phpstan-impure */ private function parseCallable(TokenIterator $tokens, Ast\Type\IdentifierTypeNode $identifier, bool $hasTemplate) : Ast\Type\TypeNode { $templates = $hasTemplate ? $this->parseCallableTemplates($tokens) : []; $tokens->consumeTokenType(Lexer::TOKEN_OPEN_PARENTHESES); $tokens->tryConsumeTokenType(Lexer::TOKEN_PHPDOC_EOL); $parameters = []; if (!$tokens->isCurrentTokenType(Lexer::TOKEN_CLOSE_PARENTHESES)) { $parameters[] = $this->parseCallableParameter($tokens); $tokens->tryConsumeTokenType(Lexer::TOKEN_PHPDOC_EOL); while ($tokens->tryConsumeTokenType(Lexer::TOKEN_COMMA)) { $tokens->tryConsumeTokenType(Lexer::TOKEN_PHPDOC_EOL); if ($tokens->isCurrentTokenType(Lexer::TOKEN_CLOSE_PARENTHESES)) { break; } $parameters[] = $this->parseCallableParameter($tokens); $tokens->tryConsumeTokenType(Lexer::TOKEN_PHPDOC_EOL); } } $tokens->consumeTokenType(Lexer::TOKEN_CLOSE_PARENTHESES); $tokens->consumeTokenType(Lexer::TOKEN_COLON); $startLine = $tokens->currentTokenLine(); $startIndex = $tokens->currentTokenIndex(); $returnType = $this->enrichWithAttributes($tokens, $this->parseCallableReturnType($tokens), $startLine, $startIndex); return new Ast\Type\CallableTypeNode($identifier, $parameters, $returnType, $templates); } /** * @return Ast\PhpDoc\TemplateTagValueNode[] * * @phpstan-impure */ private function parseCallableTemplates(TokenIterator $tokens) : array { $tokens->consumeTokenType(Lexer::TOKEN_OPEN_ANGLE_BRACKET); $templates = []; $isFirst = \true; while ($isFirst || $tokens->tryConsumeTokenType(Lexer::TOKEN_COMMA)) { $tokens->tryConsumeTokenType(Lexer::TOKEN_PHPDOC_EOL); // trailing comma case if (!$isFirst && $tokens->isCurrentTokenType(Lexer::TOKEN_CLOSE_ANGLE_BRACKET)) { break; } $isFirst = \false; $templates[] = $this->parseCallableTemplateArgument($tokens); $tokens->tryConsumeTokenType(Lexer::TOKEN_PHPDOC_EOL); } $tokens->consumeTokenType(Lexer::TOKEN_CLOSE_ANGLE_BRACKET); return $templates; } private function parseCallableTemplateArgument(TokenIterator $tokens) : Ast\PhpDoc\TemplateTagValueNode { $startLine = $tokens->currentTokenLine(); $startIndex = $tokens->currentTokenIndex(); return $this->enrichWithAttributes($tokens, $this->parseTemplateTagValue($tokens), $startLine, $startIndex); } /** @phpstan-impure */ private function parseCallableParameter(TokenIterator $tokens) : Ast\Type\CallableTypeParameterNode { $startLine = $tokens->currentTokenLine(); $startIndex = $tokens->currentTokenIndex(); $type = $this->parse($tokens); $isReference = $tokens->tryConsumeTokenType(Lexer::TOKEN_REFERENCE); $isVariadic = $tokens->tryConsumeTokenType(Lexer::TOKEN_VARIADIC); if ($tokens->isCurrentTokenType(Lexer::TOKEN_VARIABLE)) { $parameterName = $tokens->currentTokenValue(); $tokens->consumeTokenType(Lexer::TOKEN_VARIABLE); } else { $parameterName = ''; } $isOptional = $tokens->tryConsumeTokenType(Lexer::TOKEN_EQUAL); return $this->enrichWithAttributes($tokens, new Ast\Type\CallableTypeParameterNode($type, $isReference, $isVariadic, $parameterName, $isOptional), $startLine, $startIndex); } /** @phpstan-impure */ private function parseCallableReturnType(TokenIterator $tokens) : Ast\Type\TypeNode { $startLine = $tokens->currentTokenLine(); $startIndex = $tokens->currentTokenIndex(); if ($tokens->isCurrentTokenType(Lexer::TOKEN_NULLABLE)) { return $this->parseNullable($tokens); } elseif ($tokens->tryConsumeTokenType(Lexer::TOKEN_OPEN_PARENTHESES)) { $type = $this->subParse($tokens); $tokens->consumeTokenType(Lexer::TOKEN_CLOSE_PARENTHESES); if ($tokens->isCurrentTokenType(Lexer::TOKEN_OPEN_SQUARE_BRACKET)) { $type = $this->tryParseArrayOrOffsetAccess($tokens, $type); } return $type; } elseif ($tokens->tryConsumeTokenType(Lexer::TOKEN_THIS_VARIABLE)) { $type = new Ast\Type\ThisTypeNode(); if ($tokens->isCurrentTokenType(Lexer::TOKEN_OPEN_SQUARE_BRACKET)) { $type = $this->tryParseArrayOrOffsetAccess($tokens, $this->enrichWithAttributes($tokens, $type, $startLine, $startIndex)); } return $type; } else { $currentTokenValue = $tokens->currentTokenValue(); $tokens->pushSavePoint(); // because of ConstFetchNode if ($tokens->tryConsumeTokenType(Lexer::TOKEN_IDENTIFIER)) { $type = new Ast\Type\IdentifierTypeNode($currentTokenValue); if (!$tokens->isCurrentTokenType(Lexer::TOKEN_DOUBLE_COLON)) { if ($tokens->isCurrentTokenType(Lexer::TOKEN_OPEN_ANGLE_BRACKET)) { $type = $this->parseGeneric($tokens, $this->enrichWithAttributes($tokens, $type, $startLine, $startIndex)); if ($tokens->isCurrentTokenType(Lexer::TOKEN_OPEN_SQUARE_BRACKET)) { $type = $this->tryParseArrayOrOffsetAccess($tokens, $this->enrichWithAttributes($tokens, $type, $startLine, $startIndex)); } } elseif ($tokens->isCurrentTokenType(Lexer::TOKEN_OPEN_SQUARE_BRACKET)) { $type = $this->tryParseArrayOrOffsetAccess($tokens, $this->enrichWithAttributes($tokens, $type, $startLine, $startIndex)); } elseif (in_array($type->name, ['array', 'list', 'object'], \true) && $tokens->isCurrentTokenType(Lexer::TOKEN_OPEN_CURLY_BRACKET) && !$tokens->isPrecededByHorizontalWhitespace()) { if ($type->name === 'object') { $type = $this->parseObjectShape($tokens); } else { $type = $this->parseArrayShape($tokens, $this->enrichWithAttributes($tokens, $type, $startLine, $startIndex), $type->name); } if ($tokens->isCurrentTokenType(Lexer::TOKEN_OPEN_SQUARE_BRACKET)) { $type = $this->tryParseArrayOrOffsetAccess($tokens, $this->enrichWithAttributes($tokens, $type, $startLine, $startIndex)); } } return $type; } else { $tokens->rollback(); // because of ConstFetchNode } } else { $tokens->dropSavePoint(); // because of ConstFetchNode } } $currentTokenValue = $tokens->currentTokenValue(); $currentTokenType = $tokens->currentTokenType(); $currentTokenOffset = $tokens->currentTokenOffset(); $currentTokenLine = $tokens->currentTokenLine(); if ($this->constExprParser === null) { throw new ParserException($currentTokenValue, $currentTokenType, $currentTokenOffset, Lexer::TOKEN_IDENTIFIER, null, $currentTokenLine); } try { $constExpr = $this->constExprParser->parse($tokens, \true); if ($constExpr instanceof Ast\ConstExpr\ConstExprArrayNode) { throw new ParserException($currentTokenValue, $currentTokenType, $currentTokenOffset, Lexer::TOKEN_IDENTIFIER, null, $currentTokenLine); } $type = $this->enrichWithAttributes($tokens, new Ast\Type\ConstTypeNode($constExpr), $startLine, $startIndex); if ($tokens->isCurrentTokenType(Lexer::TOKEN_OPEN_SQUARE_BRACKET)) { $type = $this->tryParseArrayOrOffsetAccess($tokens, $type); } return $type; } catch (LogicException $e) { throw new ParserException($currentTokenValue, $currentTokenType, $currentTokenOffset, Lexer::TOKEN_IDENTIFIER, null, $currentTokenLine); } } /** @phpstan-impure */ private function tryParseCallable(TokenIterator $tokens, Ast\Type\IdentifierTypeNode $identifier, bool $hasTemplate) : Ast\Type\TypeNode { try { $tokens->pushSavePoint(); $type = $this->parseCallable($tokens, $identifier, $hasTemplate); $tokens->dropSavePoint(); } catch (ParserException $e) { $tokens->rollback(); $type = $identifier; } return $type; } /** @phpstan-impure */ private function tryParseArrayOrOffsetAccess(TokenIterator $tokens, Ast\Type\TypeNode $type) : Ast\Type\TypeNode { $startLine = $type->getAttribute(Ast\Attribute::START_LINE); $startIndex = $type->getAttribute(Ast\Attribute::START_INDEX); try { while ($tokens->isCurrentTokenType(Lexer::TOKEN_OPEN_SQUARE_BRACKET)) { $tokens->pushSavePoint(); $canBeOffsetAccessType = !$tokens->isPrecededByHorizontalWhitespace(); $tokens->consumeTokenType(Lexer::TOKEN_OPEN_SQUARE_BRACKET); if ($canBeOffsetAccessType && !$tokens->isCurrentTokenType(Lexer::TOKEN_CLOSE_SQUARE_BRACKET)) { $offset = $this->parse($tokens); $tokens->consumeTokenType(Lexer::TOKEN_CLOSE_SQUARE_BRACKET); $tokens->dropSavePoint(); $type = new Ast\Type\OffsetAccessTypeNode($type, $offset); if ($startLine !== null && $startIndex !== null) { $type = $this->enrichWithAttributes($tokens, $type, $startLine, $startIndex); } } else { $tokens->consumeTokenType(Lexer::TOKEN_CLOSE_SQUARE_BRACKET); $tokens->dropSavePoint(); $type = new Ast\Type\ArrayTypeNode($type); if ($startLine !== null && $startIndex !== null) { $type = $this->enrichWithAttributes($tokens, $type, $startLine, $startIndex); } } } } catch (ParserException $e) { $tokens->rollback(); } return $type; } /** * @phpstan-impure * @param Ast\Type\ArrayShapeNode::KIND_* $kind */ private function parseArrayShape(TokenIterator $tokens, Ast\Type\TypeNode $type, string $kind) : Ast\Type\ArrayShapeNode { $tokens->consumeTokenType(Lexer::TOKEN_OPEN_CURLY_BRACKET); $items = []; $sealed = \true; $unsealedType = null; do { $tokens->tryConsumeTokenType(Lexer::TOKEN_PHPDOC_EOL); if ($tokens->tryConsumeTokenType(Lexer::TOKEN_CLOSE_CURLY_BRACKET)) { return new Ast\Type\ArrayShapeNode($items, \true, $kind); } if ($tokens->tryConsumeTokenType(Lexer::TOKEN_VARIADIC)) { $sealed = \false; $tokens->tryConsumeTokenType(Lexer::TOKEN_PHPDOC_EOL); if ($tokens->isCurrentTokenType(Lexer::TOKEN_OPEN_ANGLE_BRACKET)) { if ($kind === Ast\Type\ArrayShapeNode::KIND_ARRAY) { $unsealedType = $this->parseArrayShapeUnsealedType($tokens); } else { $unsealedType = $this->parseListShapeUnsealedType($tokens); } $tokens->tryConsumeTokenType(Lexer::TOKEN_PHPDOC_EOL); } $tokens->tryConsumeTokenType(Lexer::TOKEN_COMMA); break; } $items[] = $this->parseArrayShapeItem($tokens); $tokens->tryConsumeTokenType(Lexer::TOKEN_PHPDOC_EOL); } while ($tokens->tryConsumeTokenType(Lexer::TOKEN_COMMA)); $tokens->tryConsumeTokenType(Lexer::TOKEN_PHPDOC_EOL); $tokens->consumeTokenType(Lexer::TOKEN_CLOSE_CURLY_BRACKET); return new Ast\Type\ArrayShapeNode($items, $sealed, $kind, $unsealedType); } /** @phpstan-impure */ private function parseArrayShapeItem(TokenIterator $tokens) : Ast\Type\ArrayShapeItemNode { $startLine = $tokens->currentTokenLine(); $startIndex = $tokens->currentTokenIndex(); try { $tokens->pushSavePoint(); $key = $this->parseArrayShapeKey($tokens); $optional = $tokens->tryConsumeTokenType(Lexer::TOKEN_NULLABLE); $tokens->consumeTokenType(Lexer::TOKEN_COLON); $value = $this->parse($tokens); $tokens->dropSavePoint(); return $this->enrichWithAttributes($tokens, new Ast\Type\ArrayShapeItemNode($key, $optional, $value), $startLine, $startIndex); } catch (ParserException $e) { $tokens->rollback(); $value = $this->parse($tokens); return $this->enrichWithAttributes($tokens, new Ast\Type\ArrayShapeItemNode(null, \false, $value), $startLine, $startIndex); } } /** * @phpstan-impure * @return Ast\ConstExpr\ConstExprIntegerNode|Ast\ConstExpr\ConstExprStringNode|Ast\Type\IdentifierTypeNode */ private function parseArrayShapeKey(TokenIterator $tokens) { $startIndex = $tokens->currentTokenIndex(); $startLine = $tokens->currentTokenLine(); if ($tokens->isCurrentTokenType(Lexer::TOKEN_INTEGER)) { $key = new Ast\ConstExpr\ConstExprIntegerNode(str_replace('_', '', $tokens->currentTokenValue())); $tokens->next(); } elseif ($tokens->isCurrentTokenType(Lexer::TOKEN_SINGLE_QUOTED_STRING)) { if ($this->quoteAwareConstExprString) { $key = new Ast\ConstExpr\QuoteAwareConstExprStringNode(StringUnescaper::unescapeString($tokens->currentTokenValue()), Ast\ConstExpr\QuoteAwareConstExprStringNode::SINGLE_QUOTED); } else { $key = new Ast\ConstExpr\ConstExprStringNode(trim($tokens->currentTokenValue(), "'")); } $tokens->next(); } elseif ($tokens->isCurrentTokenType(Lexer::TOKEN_DOUBLE_QUOTED_STRING)) { if ($this->quoteAwareConstExprString) { $key = new Ast\ConstExpr\QuoteAwareConstExprStringNode(StringUnescaper::unescapeString($tokens->currentTokenValue()), Ast\ConstExpr\QuoteAwareConstExprStringNode::DOUBLE_QUOTED); } else { $key = new Ast\ConstExpr\ConstExprStringNode(trim($tokens->currentTokenValue(), '"')); } $tokens->next(); } else { $key = new Ast\Type\IdentifierTypeNode($tokens->currentTokenValue()); $tokens->consumeTokenType(Lexer::TOKEN_IDENTIFIER); } return $this->enrichWithAttributes($tokens, $key, $startLine, $startIndex); } /** * @phpstan-impure */ private function parseArrayShapeUnsealedType(TokenIterator $tokens) : Ast\Type\ArrayShapeUnsealedTypeNode { $startLine = $tokens->currentTokenLine(); $startIndex = $tokens->currentTokenIndex(); $tokens->consumeTokenType(Lexer::TOKEN_OPEN_ANGLE_BRACKET); $tokens->tryConsumeTokenType(Lexer::TOKEN_PHPDOC_EOL); $valueType = $this->parse($tokens); $tokens->tryConsumeTokenType(Lexer::TOKEN_PHPDOC_EOL); $keyType = null; if ($tokens->tryConsumeTokenType(Lexer::TOKEN_COMMA)) { $tokens->tryConsumeTokenType(Lexer::TOKEN_PHPDOC_EOL); $keyType = $valueType; $valueType = $this->parse($tokens); $tokens->tryConsumeTokenType(Lexer::TOKEN_PHPDOC_EOL); } $tokens->consumeTokenType(Lexer::TOKEN_CLOSE_ANGLE_BRACKET); return $this->enrichWithAttributes($tokens, new Ast\Type\ArrayShapeUnsealedTypeNode($valueType, $keyType), $startLine, $startIndex); } /** * @phpstan-impure */ private function parseListShapeUnsealedType(TokenIterator $tokens) : Ast\Type\ArrayShapeUnsealedTypeNode { $startLine = $tokens->currentTokenLine(); $startIndex = $tokens->currentTokenIndex(); $tokens->consumeTokenType(Lexer::TOKEN_OPEN_ANGLE_BRACKET); $tokens->tryConsumeTokenType(Lexer::TOKEN_PHPDOC_EOL); $valueType = $this->parse($tokens); $tokens->tryConsumeTokenType(Lexer::TOKEN_PHPDOC_EOL); $tokens->consumeTokenType(Lexer::TOKEN_CLOSE_ANGLE_BRACKET); return $this->enrichWithAttributes($tokens, new Ast\Type\ArrayShapeUnsealedTypeNode($valueType, null), $startLine, $startIndex); } /** * @phpstan-impure */ private function parseObjectShape(TokenIterator $tokens) : Ast\Type\ObjectShapeNode { $tokens->consumeTokenType(Lexer::TOKEN_OPEN_CURLY_BRACKET); $items = []; do { $tokens->tryConsumeTokenType(Lexer::TOKEN_PHPDOC_EOL); if ($tokens->tryConsumeTokenType(Lexer::TOKEN_CLOSE_CURLY_BRACKET)) { return new Ast\Type\ObjectShapeNode($items); } $items[] = $this->parseObjectShapeItem($tokens); $tokens->tryConsumeTokenType(Lexer::TOKEN_PHPDOC_EOL); } while ($tokens->tryConsumeTokenType(Lexer::TOKEN_COMMA)); $tokens->tryConsumeTokenType(Lexer::TOKEN_PHPDOC_EOL); $tokens->consumeTokenType(Lexer::TOKEN_CLOSE_CURLY_BRACKET); return new Ast\Type\ObjectShapeNode($items); } /** @phpstan-impure */ private function parseObjectShapeItem(TokenIterator $tokens) : Ast\Type\ObjectShapeItemNode { $startLine = $tokens->currentTokenLine(); $startIndex = $tokens->currentTokenIndex(); $key = $this->parseObjectShapeKey($tokens); $optional = $tokens->tryConsumeTokenType(Lexer::TOKEN_NULLABLE); $tokens->consumeTokenType(Lexer::TOKEN_COLON); $value = $this->parse($tokens); return $this->enrichWithAttributes($tokens, new Ast\Type\ObjectShapeItemNode($key, $optional, $value), $startLine, $startIndex); } /** * @phpstan-impure * @return Ast\ConstExpr\ConstExprStringNode|Ast\Type\IdentifierTypeNode */ private function parseObjectShapeKey(TokenIterator $tokens) { $startLine = $tokens->currentTokenLine(); $startIndex = $tokens->currentTokenIndex(); if ($tokens->isCurrentTokenType(Lexer::TOKEN_SINGLE_QUOTED_STRING)) { if ($this->quoteAwareConstExprString) { $key = new Ast\ConstExpr\QuoteAwareConstExprStringNode(StringUnescaper::unescapeString($tokens->currentTokenValue()), Ast\ConstExpr\QuoteAwareConstExprStringNode::SINGLE_QUOTED); } else { $key = new Ast\ConstExpr\ConstExprStringNode(trim($tokens->currentTokenValue(), "'")); } $tokens->next(); } elseif ($tokens->isCurrentTokenType(Lexer::TOKEN_DOUBLE_QUOTED_STRING)) { if ($this->quoteAwareConstExprString) { $key = new Ast\ConstExpr\QuoteAwareConstExprStringNode(StringUnescaper::unescapeString($tokens->currentTokenValue()), Ast\ConstExpr\QuoteAwareConstExprStringNode::DOUBLE_QUOTED); } else { $key = new Ast\ConstExpr\ConstExprStringNode(trim($tokens->currentTokenValue(), '"')); } $tokens->next(); } else { $key = new Ast\Type\IdentifierTypeNode($tokens->currentTokenValue()); $tokens->consumeTokenType(Lexer::TOKEN_IDENTIFIER); } return $this->enrichWithAttributes($tokens, $key, $startLine, $startIndex); } } */ private $tokens; /** @var int */ private $index; /** @var int[] */ private $savePoints = []; /** @var list */ private $skippedTokenTypes = [Lexer::TOKEN_HORIZONTAL_WS]; /** @var string|null */ private $newline = null; /** * @param list $tokens */ public function __construct(array $tokens, int $index = 0) { $this->tokens = $tokens; $this->index = $index; $this->skipIrrelevantTokens(); } /** * @return list */ public function getTokens() : array { return $this->tokens; } public function getContentBetween(int $startPos, int $endPos) : string { if ($startPos < 0 || $endPos > count($this->tokens)) { throw new LogicException(); } $content = ''; for ($i = $startPos; $i < $endPos; $i++) { $content .= $this->tokens[$i][Lexer::VALUE_OFFSET]; } return $content; } public function getTokenCount() : int { return count($this->tokens); } public function currentTokenValue() : string { return $this->tokens[$this->index][Lexer::VALUE_OFFSET]; } public function currentTokenType() : int { return $this->tokens[$this->index][Lexer::TYPE_OFFSET]; } public function currentTokenOffset() : int { $offset = 0; for ($i = 0; $i < $this->index; $i++) { $offset += strlen($this->tokens[$i][Lexer::VALUE_OFFSET]); } return $offset; } public function currentTokenLine() : int { return $this->tokens[$this->index][Lexer::LINE_OFFSET]; } public function currentTokenIndex() : int { return $this->index; } public function endIndexOfLastRelevantToken() : int { $endIndex = $this->currentTokenIndex(); $endIndex--; while (in_array($this->tokens[$endIndex][Lexer::TYPE_OFFSET], $this->skippedTokenTypes, \true)) { if (!isset($this->tokens[$endIndex - 1])) { break; } $endIndex--; } return $endIndex; } public function isCurrentTokenValue(string $tokenValue) : bool { return $this->tokens[$this->index][Lexer::VALUE_OFFSET] === $tokenValue; } public function isCurrentTokenType(int ...$tokenType) : bool { return in_array($this->tokens[$this->index][Lexer::TYPE_OFFSET], $tokenType, \true); } public function isPrecededByHorizontalWhitespace() : bool { return ($this->tokens[$this->index - 1][Lexer::TYPE_OFFSET] ?? -1) === Lexer::TOKEN_HORIZONTAL_WS; } /** * @throws ParserException */ public function consumeTokenType(int $tokenType) : void { if ($this->tokens[$this->index][Lexer::TYPE_OFFSET] !== $tokenType) { $this->throwError($tokenType); } if ($tokenType === Lexer::TOKEN_PHPDOC_EOL) { if ($this->newline === null) { $this->detectNewline(); } } $this->index++; $this->skipIrrelevantTokens(); } /** * @throws ParserException */ public function consumeTokenValue(int $tokenType, string $tokenValue) : void { if ($this->tokens[$this->index][Lexer::TYPE_OFFSET] !== $tokenType || $this->tokens[$this->index][Lexer::VALUE_OFFSET] !== $tokenValue) { $this->throwError($tokenType, $tokenValue); } $this->index++; $this->skipIrrelevantTokens(); } /** @phpstan-impure */ public function tryConsumeTokenValue(string $tokenValue) : bool { if ($this->tokens[$this->index][Lexer::VALUE_OFFSET] !== $tokenValue) { return \false; } $this->index++; $this->skipIrrelevantTokens(); return \true; } /** @phpstan-impure */ public function tryConsumeTokenType(int $tokenType) : bool { if ($this->tokens[$this->index][Lexer::TYPE_OFFSET] !== $tokenType) { return \false; } if ($tokenType === Lexer::TOKEN_PHPDOC_EOL) { if ($this->newline === null) { $this->detectNewline(); } } $this->index++; $this->skipIrrelevantTokens(); return \true; } private function detectNewline() : void { $value = $this->currentTokenValue(); if (substr($value, 0, 2) === "\r\n") { $this->newline = "\r\n"; } elseif (substr($value, 0, 1) === "\n") { $this->newline = "\n"; } } public function getSkippedHorizontalWhiteSpaceIfAny() : string { if ($this->index > 0 && $this->tokens[$this->index - 1][Lexer::TYPE_OFFSET] === Lexer::TOKEN_HORIZONTAL_WS) { return $this->tokens[$this->index - 1][Lexer::VALUE_OFFSET]; } return ''; } /** @phpstan-impure */ public function joinUntil(int ...$tokenType) : string { $s = ''; while (!in_array($this->tokens[$this->index][Lexer::TYPE_OFFSET], $tokenType, \true)) { $s .= $this->tokens[$this->index++][Lexer::VALUE_OFFSET]; } return $s; } public function next() : void { $this->index++; $this->skipIrrelevantTokens(); } private function skipIrrelevantTokens() : void { if (!isset($this->tokens[$this->index])) { return; } while (in_array($this->tokens[$this->index][Lexer::TYPE_OFFSET], $this->skippedTokenTypes, \true)) { if (!isset($this->tokens[$this->index + 1])) { break; } $this->index++; } } public function addEndOfLineToSkippedTokens() : void { $this->skippedTokenTypes = [Lexer::TOKEN_HORIZONTAL_WS, Lexer::TOKEN_PHPDOC_EOL]; } public function removeEndOfLineFromSkippedTokens() : void { $this->skippedTokenTypes = [Lexer::TOKEN_HORIZONTAL_WS]; } /** @phpstan-impure */ public function forwardToTheEnd() : void { $lastToken = count($this->tokens) - 1; $this->index = $lastToken; } public function pushSavePoint() : void { $this->savePoints[] = $this->index; } public function dropSavePoint() : void { array_pop($this->savePoints); } public function rollback() : void { $index = array_pop($this->savePoints); assert($index !== null); $this->index = $index; } /** * @throws ParserException */ private function throwError(int $expectedTokenType, ?string $expectedTokenValue = null) : void { throw new ParserException($this->currentTokenValue(), $this->currentTokenType(), $this->currentTokenOffset(), $expectedTokenType, $expectedTokenValue, $this->currentTokenLine()); } /** * Check whether the position is directly preceded by a certain token type. * * During this check TOKEN_HORIZONTAL_WS and TOKEN_PHPDOC_EOL are skipped */ public function hasTokenImmediatelyBefore(int $pos, int $expectedTokenType) : bool { $tokens = $this->tokens; $pos--; for (; $pos >= 0; $pos--) { $token = $tokens[$pos]; $type = $token[Lexer::TYPE_OFFSET]; if ($type === $expectedTokenType) { return \true; } if (!in_array($type, [Lexer::TOKEN_HORIZONTAL_WS, Lexer::TOKEN_PHPDOC_EOL], \true)) { break; } } return \false; } /** * Check whether the position is directly followed by a certain token type. * * During this check TOKEN_HORIZONTAL_WS and TOKEN_PHPDOC_EOL are skipped */ public function hasTokenImmediatelyAfter(int $pos, int $expectedTokenType) : bool { $tokens = $this->tokens; $pos++; for ($c = count($tokens); $pos < $c; $pos++) { $token = $tokens[$pos]; $type = $token[Lexer::TYPE_OFFSET]; if ($type === $expectedTokenType) { return \true; } if (!in_array($type, [Lexer::TOKEN_HORIZONTAL_WS, Lexer::TOKEN_PHPDOC_EOL], \true)) { break; } } return \false; } public function getDetectedNewline() : ?string { return $this->newline; } /** * Whether the given position is immediately surrounded by parenthesis. */ public function hasParentheses(int $startPos, int $endPos) : bool { return $this->hasTokenImmediatelyBefore($startPos, Lexer::TOKEN_OPEN_PARENTHESES) && $this->hasTokenImmediatelyAfter($endPos, Lexer::TOKEN_CLOSE_PARENTHESES); } } unescapeStrings = $unescapeStrings; $this->quoteAwareConstExprString = $quoteAwareConstExprString; $this->useLinesAttributes = $usedAttributes['lines'] ?? \false; $this->useIndexAttributes = $usedAttributes['indexes'] ?? \false; $this->parseDoctrineStrings = \false; } /** * @internal */ public function toDoctrine() : self { $self = new self($this->unescapeStrings, $this->quoteAwareConstExprString, ['lines' => $this->useLinesAttributes, 'indexes' => $this->useIndexAttributes]); $self->parseDoctrineStrings = \true; return $self; } public function parse(TokenIterator $tokens, bool $trimStrings = \false) : Ast\ConstExpr\ConstExprNode { $startLine = $tokens->currentTokenLine(); $startIndex = $tokens->currentTokenIndex(); if ($tokens->isCurrentTokenType(Lexer::TOKEN_FLOAT)) { $value = $tokens->currentTokenValue(); $tokens->next(); return $this->enrichWithAttributes($tokens, new Ast\ConstExpr\ConstExprFloatNode(str_replace('_', '', $value)), $startLine, $startIndex); } if ($tokens->isCurrentTokenType(Lexer::TOKEN_INTEGER)) { $value = $tokens->currentTokenValue(); $tokens->next(); return $this->enrichWithAttributes($tokens, new Ast\ConstExpr\ConstExprIntegerNode(str_replace('_', '', $value)), $startLine, $startIndex); } if ($this->parseDoctrineStrings && $tokens->isCurrentTokenType(Lexer::TOKEN_DOCTRINE_ANNOTATION_STRING)) { $value = $tokens->currentTokenValue(); $tokens->next(); return $this->enrichWithAttributes($tokens, new Ast\ConstExpr\DoctrineConstExprStringNode(Ast\ConstExpr\DoctrineConstExprStringNode::unescape($value)), $startLine, $startIndex); } if ($tokens->isCurrentTokenType(Lexer::TOKEN_SINGLE_QUOTED_STRING, Lexer::TOKEN_DOUBLE_QUOTED_STRING)) { if ($this->parseDoctrineStrings) { if ($tokens->isCurrentTokenType(Lexer::TOKEN_SINGLE_QUOTED_STRING)) { throw new ParserException($tokens->currentTokenValue(), $tokens->currentTokenType(), $tokens->currentTokenOffset(), Lexer::TOKEN_DOUBLE_QUOTED_STRING, null, $tokens->currentTokenLine()); } $value = $tokens->currentTokenValue(); $tokens->next(); return $this->enrichWithAttributes($tokens, $this->parseDoctrineString($value, $tokens), $startLine, $startIndex); } $value = $tokens->currentTokenValue(); $type = $tokens->currentTokenType(); if ($trimStrings) { if ($this->unescapeStrings) { $value = StringUnescaper::unescapeString($value); } else { $value = substr($value, 1, -1); } } $tokens->next(); if ($this->quoteAwareConstExprString) { return $this->enrichWithAttributes($tokens, new Ast\ConstExpr\QuoteAwareConstExprStringNode($value, $type === Lexer::TOKEN_SINGLE_QUOTED_STRING ? Ast\ConstExpr\QuoteAwareConstExprStringNode::SINGLE_QUOTED : Ast\ConstExpr\QuoteAwareConstExprStringNode::DOUBLE_QUOTED), $startLine, $startIndex); } return $this->enrichWithAttributes($tokens, new Ast\ConstExpr\ConstExprStringNode($value), $startLine, $startIndex); } elseif ($tokens->isCurrentTokenType(Lexer::TOKEN_IDENTIFIER)) { $identifier = $tokens->currentTokenValue(); $tokens->next(); switch (strtolower($identifier)) { case 'true': return $this->enrichWithAttributes($tokens, new Ast\ConstExpr\ConstExprTrueNode(), $startLine, $startIndex); case 'false': return $this->enrichWithAttributes($tokens, new Ast\ConstExpr\ConstExprFalseNode(), $startLine, $startIndex); case 'null': return $this->enrichWithAttributes($tokens, new Ast\ConstExpr\ConstExprNullNode(), $startLine, $startIndex); case 'array': $tokens->consumeTokenType(Lexer::TOKEN_OPEN_PARENTHESES); return $this->parseArray($tokens, Lexer::TOKEN_CLOSE_PARENTHESES, $startIndex); } if ($tokens->tryConsumeTokenType(Lexer::TOKEN_DOUBLE_COLON)) { $classConstantName = ''; $lastType = null; while (\true) { if ($lastType !== Lexer::TOKEN_IDENTIFIER && $tokens->currentTokenType() === Lexer::TOKEN_IDENTIFIER) { $classConstantName .= $tokens->currentTokenValue(); $tokens->consumeTokenType(Lexer::TOKEN_IDENTIFIER); $lastType = Lexer::TOKEN_IDENTIFIER; continue; } if ($lastType !== Lexer::TOKEN_WILDCARD && $tokens->tryConsumeTokenType(Lexer::TOKEN_WILDCARD)) { $classConstantName .= '*'; $lastType = Lexer::TOKEN_WILDCARD; if ($tokens->getSkippedHorizontalWhiteSpaceIfAny() !== '') { break; } continue; } if ($lastType === null) { // trigger parse error if nothing valid was consumed $tokens->consumeTokenType(Lexer::TOKEN_WILDCARD); } break; } return $this->enrichWithAttributes($tokens, new Ast\ConstExpr\ConstFetchNode($identifier, $classConstantName), $startLine, $startIndex); } return $this->enrichWithAttributes($tokens, new Ast\ConstExpr\ConstFetchNode('', $identifier), $startLine, $startIndex); } elseif ($tokens->tryConsumeTokenType(Lexer::TOKEN_OPEN_SQUARE_BRACKET)) { return $this->parseArray($tokens, Lexer::TOKEN_CLOSE_SQUARE_BRACKET, $startIndex); } throw new ParserException($tokens->currentTokenValue(), $tokens->currentTokenType(), $tokens->currentTokenOffset(), Lexer::TOKEN_IDENTIFIER, null, $tokens->currentTokenLine()); } private function parseArray(TokenIterator $tokens, int $endToken, int $startIndex) : Ast\ConstExpr\ConstExprArrayNode { $items = []; $startLine = $tokens->currentTokenLine(); if (!$tokens->tryConsumeTokenType($endToken)) { do { $items[] = $this->parseArrayItem($tokens); } while ($tokens->tryConsumeTokenType(Lexer::TOKEN_COMMA) && !$tokens->isCurrentTokenType($endToken)); $tokens->consumeTokenType($endToken); } return $this->enrichWithAttributes($tokens, new Ast\ConstExpr\ConstExprArrayNode($items), $startLine, $startIndex); } /** * This method is supposed to be called with TokenIterator after reading TOKEN_DOUBLE_QUOTED_STRING and shifting * to the next token. */ public function parseDoctrineString(string $text, TokenIterator $tokens) : Ast\ConstExpr\DoctrineConstExprStringNode { // Because of how Lexer works, a valid Doctrine string // can consist of a sequence of TOKEN_DOUBLE_QUOTED_STRING and TOKEN_DOCTRINE_ANNOTATION_STRING while ($tokens->isCurrentTokenType(Lexer::TOKEN_DOUBLE_QUOTED_STRING, Lexer::TOKEN_DOCTRINE_ANNOTATION_STRING)) { $text .= $tokens->currentTokenValue(); $tokens->next(); } return new Ast\ConstExpr\DoctrineConstExprStringNode(Ast\ConstExpr\DoctrineConstExprStringNode::unescape($text)); } private function parseArrayItem(TokenIterator $tokens) : Ast\ConstExpr\ConstExprArrayItemNode { $startLine = $tokens->currentTokenLine(); $startIndex = $tokens->currentTokenIndex(); $expr = $this->parse($tokens); if ($tokens->tryConsumeTokenType(Lexer::TOKEN_DOUBLE_ARROW)) { $key = $expr; $value = $this->parse($tokens); } else { $key = null; $value = $expr; } return $this->enrichWithAttributes($tokens, new Ast\ConstExpr\ConstExprArrayItemNode($key, $value), $startLine, $startIndex); } /** * @template T of Ast\ConstExpr\ConstExprNode * @param T $node * @return T */ private function enrichWithAttributes(TokenIterator $tokens, Ast\ConstExpr\ConstExprNode $node, int $startLine, int $startIndex) : Ast\ConstExpr\ConstExprNode { if ($this->useLinesAttributes) { $node->setAttribute(Ast\Attribute::START_LINE, $startLine); $node->setAttribute(Ast\Attribute::END_LINE, $tokens->currentTokenLine()); } if ($this->useIndexAttributes) { $node->setAttribute(Ast\Attribute::START_INDEX, $startIndex); $node->setAttribute(Ast\Attribute::END_INDEX, $tokens->endIndexOfLastRelevantToken()); } return $node; } } '\'&\'', self::TOKEN_UNION => '\'|\'', self::TOKEN_INTERSECTION => '\'&\'', self::TOKEN_NULLABLE => '\'?\'', self::TOKEN_NEGATED => '\'!\'', self::TOKEN_OPEN_PARENTHESES => '\'(\'', self::TOKEN_CLOSE_PARENTHESES => '\')\'', self::TOKEN_OPEN_ANGLE_BRACKET => '\'<\'', self::TOKEN_CLOSE_ANGLE_BRACKET => '\'>\'', self::TOKEN_OPEN_SQUARE_BRACKET => '\'[\'', self::TOKEN_CLOSE_SQUARE_BRACKET => '\']\'', self::TOKEN_OPEN_CURLY_BRACKET => '\'{\'', self::TOKEN_CLOSE_CURLY_BRACKET => '\'}\'', self::TOKEN_COMMA => '\',\'', self::TOKEN_COLON => '\':\'', self::TOKEN_VARIADIC => '\'...\'', self::TOKEN_DOUBLE_COLON => '\'::\'', self::TOKEN_DOUBLE_ARROW => '\'=>\'', self::TOKEN_ARROW => '\'->\'', self::TOKEN_EQUAL => '\'=\'', self::TOKEN_OPEN_PHPDOC => '\'/**\'', self::TOKEN_CLOSE_PHPDOC => '\'*/\'', self::TOKEN_PHPDOC_TAG => 'TOKEN_PHPDOC_TAG', self::TOKEN_DOCTRINE_TAG => 'TOKEN_DOCTRINE_TAG', self::TOKEN_PHPDOC_EOL => 'TOKEN_PHPDOC_EOL', self::TOKEN_FLOAT => 'TOKEN_FLOAT', self::TOKEN_INTEGER => 'TOKEN_INTEGER', self::TOKEN_SINGLE_QUOTED_STRING => 'TOKEN_SINGLE_QUOTED_STRING', self::TOKEN_DOUBLE_QUOTED_STRING => 'TOKEN_DOUBLE_QUOTED_STRING', self::TOKEN_DOCTRINE_ANNOTATION_STRING => 'TOKEN_DOCTRINE_ANNOTATION_STRING', self::TOKEN_IDENTIFIER => 'type', self::TOKEN_THIS_VARIABLE => '\'$this\'', self::TOKEN_VARIABLE => 'variable', self::TOKEN_HORIZONTAL_WS => 'TOKEN_HORIZONTAL_WS', self::TOKEN_OTHER => 'TOKEN_OTHER', self::TOKEN_END => 'TOKEN_END', self::TOKEN_WILDCARD => '*']; public const VALUE_OFFSET = 0; public const TYPE_OFFSET = 1; public const LINE_OFFSET = 2; /** @var bool */ private $parseDoctrineAnnotations; /** @var string|null */ private $regexp; public function __construct(bool $parseDoctrineAnnotations = \false) { $this->parseDoctrineAnnotations = $parseDoctrineAnnotations; } /** * @return list */ public function tokenize(string $s) : array { if ($this->regexp === null) { $this->regexp = $this->generateRegexp(); } preg_match_all($this->regexp, $s, $matches, PREG_SET_ORDER); $tokens = []; $line = 1; foreach ($matches as $match) { $type = (int) $match['MARK']; $tokens[] = [$match[0], $type, $line]; if ($type !== self::TOKEN_PHPDOC_EOL) { continue; } $line++; } $tokens[] = ['', self::TOKEN_END, $line]; return $tokens; } private function generateRegexp() : string { $patterns = [ self::TOKEN_HORIZONTAL_WS => '[\\x09\\x20]++', self::TOKEN_IDENTIFIER => '(?:[\\\\]?+[a-z_\\x80-\\xFF][0-9a-z_\\x80-\\xFF-]*+)++', self::TOKEN_THIS_VARIABLE => '\\$this(?![0-9a-z_\\x80-\\xFF])', self::TOKEN_VARIABLE => '\\$[a-z_\\x80-\\xFF][0-9a-z_\\x80-\\xFF]*+', // '&' followed by TOKEN_VARIADIC, TOKEN_VARIABLE, TOKEN_EQUAL, TOKEN_EQUAL or TOKEN_CLOSE_PARENTHESES self::TOKEN_REFERENCE => '&(?=\\s*+(?:[.,=)]|(?:\\$(?!this(?![0-9a-z_\\x80-\\xFF])))))', self::TOKEN_UNION => '\\|', self::TOKEN_INTERSECTION => '&', self::TOKEN_NULLABLE => '\\?', self::TOKEN_NEGATED => '!', self::TOKEN_OPEN_PARENTHESES => '\\(', self::TOKEN_CLOSE_PARENTHESES => '\\)', self::TOKEN_OPEN_ANGLE_BRACKET => '<', self::TOKEN_CLOSE_ANGLE_BRACKET => '>', self::TOKEN_OPEN_SQUARE_BRACKET => '\\[', self::TOKEN_CLOSE_SQUARE_BRACKET => '\\]', self::TOKEN_OPEN_CURLY_BRACKET => '\\{', self::TOKEN_CLOSE_CURLY_BRACKET => '\\}', self::TOKEN_COMMA => ',', self::TOKEN_VARIADIC => '\\.\\.\\.', self::TOKEN_DOUBLE_COLON => '::', self::TOKEN_DOUBLE_ARROW => '=>', self::TOKEN_ARROW => '->', self::TOKEN_EQUAL => '=', self::TOKEN_COLON => ':', self::TOKEN_OPEN_PHPDOC => '/\\*\\*(?=\\s)\\x20?+', self::TOKEN_CLOSE_PHPDOC => '\\*/', self::TOKEN_PHPDOC_TAG => '@(?:[a-z][a-z0-9-\\\\]+:)?[a-z][a-z0-9-\\\\]*+', self::TOKEN_PHPDOC_EOL => '\\r?+\\n[\\x09\\x20]*+(?:\\*(?!/)\\x20?+)?', self::TOKEN_FLOAT => '[+\\-]?(?:(?:[0-9]++(_[0-9]++)*\\.[0-9]*+(_[0-9]++)*(?:e[+\\-]?[0-9]++(_[0-9]++)*)?)|(?:[0-9]*+(_[0-9]++)*\\.[0-9]++(_[0-9]++)*(?:e[+\\-]?[0-9]++(_[0-9]++)*)?)|(?:[0-9]++(_[0-9]++)*e[+\\-]?[0-9]++(_[0-9]++)*))', self::TOKEN_INTEGER => '[+\\-]?(?:(?:0b[0-1]++(_[0-1]++)*)|(?:0o[0-7]++(_[0-7]++)*)|(?:0x[0-9a-f]++(_[0-9a-f]++)*)|(?:[0-9]++(_[0-9]++)*))', self::TOKEN_SINGLE_QUOTED_STRING => '\'(?:\\\\[^\\r\\n]|[^\'\\r\\n\\\\])*+\'', self::TOKEN_DOUBLE_QUOTED_STRING => '"(?:\\\\[^\\r\\n]|[^"\\r\\n\\\\])*+"', self::TOKEN_WILDCARD => '\\*', ]; if ($this->parseDoctrineAnnotations) { $patterns[self::TOKEN_DOCTRINE_TAG] = '@[a-z_\\\\][a-z0-9_\\:\\\\]*[a-z_][a-z0-9_]*'; $patterns[self::TOKEN_DOCTRINE_ANNOTATION_STRING] = '"(?:""|[^"])*+"'; } // anything but TOKEN_CLOSE_PHPDOC or TOKEN_HORIZONTAL_WS or TOKEN_EOL $patterns[self::TOKEN_OTHER] = '(?:(?!\\*/)[^\\s])++'; foreach ($patterns as $type => &$pattern) { $pattern = '(?:' . $pattern . ')(*MARK:' . $type . ')'; } return '~' . implode('|', $patterns) . '~Asi'; } } Copyright (c) 2020-2021 Doctrine Project Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. |null */ private static $type; /** @var LoggerInterface|null */ private static $logger; /** @var array */ private static $ignoredPackages = []; /** @var array */ private static $triggeredDeprecations = []; /** @var array */ private static $ignoredLinks = []; /** @var bool */ private static $deduplication = \true; /** * Trigger a deprecation for the given package and identfier. * * The link should point to a Github issue or Wiki entry detailing the * deprecation. It is additionally used to de-duplicate the trigger of the * same deprecation during a request. * * @param float|int|string $args */ public static function trigger(string $package, string $link, string $message, ...$args) : void { $type = self::$type ?? self::getTypeFromEnv(); if ($type === self::TYPE_NONE) { return; } if (isset(self::$ignoredLinks[$link])) { return; } if (array_key_exists($link, self::$triggeredDeprecations)) { self::$triggeredDeprecations[$link]++; } else { self::$triggeredDeprecations[$link] = 1; } if (self::$deduplication === \true && self::$triggeredDeprecations[$link] > 1) { return; } if (isset(self::$ignoredPackages[$package])) { return; } $backtrace = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 2); $message = sprintf($message, ...$args); self::delegateTriggerToBackend($message, $backtrace, $link, $package); } /** * Trigger a deprecation for the given package and identifier when called from outside. * * "Outside" means we assume that $package is currently installed as a * dependency and the caller is not a file in that package. When $package * is installed as a root package then deprecations triggered from the * tests folder are also considered "outside". * * This deprecation method assumes that you are using Composer to install * the dependency and are using the default /vendor/ folder and not a * Composer plugin to change the install location. The assumption is also * that $package is the exact composer packge name. * * Compared to {@link trigger()} this method causes some overhead when * deprecation tracking is enabled even during deduplication, because it * needs to call {@link debug_backtrace()} * * @param float|int|string $args */ public static function triggerIfCalledFromOutside(string $package, string $link, string $message, ...$args) : void { $type = self::$type ?? self::getTypeFromEnv(); if ($type === self::TYPE_NONE) { return; } $backtrace = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 2); // first check that the caller is not from a tests folder, in which case we always let deprecations pass if (isset($backtrace[1]['file'], $backtrace[0]['file']) && strpos($backtrace[1]['file'], DIRECTORY_SEPARATOR . 'tests' . DIRECTORY_SEPARATOR) === \false) { $path = DIRECTORY_SEPARATOR . 'vendor' . DIRECTORY_SEPARATOR . str_replace('/', DIRECTORY_SEPARATOR, $package) . DIRECTORY_SEPARATOR; if (strpos($backtrace[0]['file'], $path) === \false) { return; } if (strpos($backtrace[1]['file'], $path) !== \false) { return; } } if (isset(self::$ignoredLinks[$link])) { return; } if (array_key_exists($link, self::$triggeredDeprecations)) { self::$triggeredDeprecations[$link]++; } else { self::$triggeredDeprecations[$link] = 1; } if (self::$deduplication === \true && self::$triggeredDeprecations[$link] > 1) { return; } if (isset(self::$ignoredPackages[$package])) { return; } $message = sprintf($message, ...$args); self::delegateTriggerToBackend($message, $backtrace, $link, $package); } /** * @param list $backtrace */ private static function delegateTriggerToBackend(string $message, array $backtrace, string $link, string $package) : void { $type = self::$type ?? self::getTypeFromEnv(); if (($type & self::TYPE_PSR_LOGGER) > 0) { $context = ['file' => $backtrace[0]['file'] ?? null, 'line' => $backtrace[0]['line'] ?? null, 'package' => $package, 'link' => $link]; assert(self::$logger !== null); self::$logger->notice($message, $context); } if (!(($type & self::TYPE_TRIGGER_ERROR) > 0)) { return; } $message .= sprintf(' (%s:%d called by %s:%d, %s, package %s)', self::basename($backtrace[0]['file'] ?? 'native code'), $backtrace[0]['line'] ?? 0, self::basename($backtrace[1]['file'] ?? 'native code'), $backtrace[1]['line'] ?? 0, $link, $package); @trigger_error($message, E_USER_DEPRECATED); } /** * A non-local-aware version of PHPs basename function. */ private static function basename(string $filename) : string { $pos = strrpos($filename, DIRECTORY_SEPARATOR); if ($pos === \false) { return $filename; } return substr($filename, $pos + 1); } public static function enableTrackingDeprecations() : void { self::$type = self::$type ?? 0; self::$type |= self::TYPE_TRACK_DEPRECATIONS; } public static function enableWithTriggerError() : void { self::$type = self::$type ?? 0; self::$type |= self::TYPE_TRIGGER_ERROR; } public static function enableWithPsrLogger(LoggerInterface $logger) : void { self::$type = self::$type ?? 0; self::$type |= self::TYPE_PSR_LOGGER; self::$logger = $logger; } public static function withoutDeduplication() : void { self::$deduplication = \false; } public static function disable() : void { self::$type = self::TYPE_NONE; self::$logger = null; self::$deduplication = \true; self::$ignoredLinks = []; foreach (self::$triggeredDeprecations as $link => $count) { self::$triggeredDeprecations[$link] = 0; } } public static function ignorePackage(string $packageName) : void { self::$ignoredPackages[$packageName] = \true; } public static function ignoreDeprecations(string ...$links) : void { foreach ($links as $link) { self::$ignoredLinks[$link] = \true; } } public static function getUniqueTriggeredDeprecationsCount() : int { return array_reduce(self::$triggeredDeprecations, static function (int $carry, int $count) { return $carry + $count; }, 0); } /** * Returns each triggered deprecation link identifier and the amount of occurrences. * * @return array */ public static function getTriggeredDeprecations() : array { return self::$triggeredDeprecations; } /** * @return int-mask-of */ private static function getTypeFromEnv() : int { switch ($_SERVER['DOCTRINE_DEPRECATIONS'] ?? $_ENV['DOCTRINE_DEPRECATIONS'] ?? null) { case 'trigger': self::$type = self::TYPE_TRIGGER_ERROR; break; case 'track': self::$type = self::TYPE_TRACK_DEPRECATIONS; break; default: self::$type = self::TYPE_NONE; break; } return self::$type; } } */ private $doctrineDeprecationsExpectations = []; /** @var array */ private $doctrineNoDeprecationsExpectations = []; public function expectDeprecationWithIdentifier(string $identifier) : void { $this->doctrineDeprecationsExpectations[$identifier] = Deprecation::getTriggeredDeprecations()[$identifier] ?? 0; } public function expectNoDeprecationWithIdentifier(string $identifier) : void { $this->doctrineNoDeprecationsExpectations[$identifier] = Deprecation::getTriggeredDeprecations()[$identifier] ?? 0; } /** * @before */ public function enableDeprecationTracking() : void { Deprecation::enableTrackingDeprecations(); } /** * @after */ public function verifyDeprecationsAreTriggered() : void { foreach ($this->doctrineDeprecationsExpectations as $identifier => $expectation) { $actualCount = Deprecation::getTriggeredDeprecations()[$identifier] ?? 0; $this->assertTrue($actualCount > $expectation, sprintf("Expected deprecation with identifier '%s' was not triggered by code executed in test.", $identifier)); } foreach ($this->doctrineNoDeprecationsExpectations as $identifier => $expectation) { $actualCount = Deprecation::getTriggeredDeprecations()[$identifier] ?? 0; $this->assertTrue($actualCount === $expectation, sprintf("Expected deprecation with identifier '%s' was triggered by code executed in test, but expected not to.", $identifier)); } } } $vendorDir . '/symfony/polyfill-mbstring/bootstrap.php', 'a4a119a56e50fbb293281d9a48007e0e' => $vendorDir . '/symfony/polyfill-php80/bootstrap.php', '6e3fae29631ef280660b3cdad06f25a8' => $vendorDir . '/symfony/deprecation-contracts/function.php', '320cde22f66dd4f5d3fd621d3e88b98f' => $vendorDir . '/symfony/polyfill-ctype/bootstrap.php', '8825ede83f2f289127722d4e842cf7e8' => $vendorDir . '/symfony/polyfill-intl-grapheme/bootstrap.php', 'e69f7f6ee287b969198c3c9d6777bd38' => $vendorDir . '/symfony/polyfill-intl-normalizer/bootstrap.php', 'e8aa6e4b5a1db2f56ae794f1505391a8' => $vendorDir . '/amphp/amp/lib/functions.php', '76cd0796156622033397994f25b0d8fc' => $vendorDir . '/amphp/amp/lib/Internal/functions.php', '0d59ee240a4cd96ddbb4ff164fccea4d' => $vendorDir . '/symfony/polyfill-php73/bootstrap.php', 'b6b991a57620e2fb6b2f66f03fe9ddc2' => $vendorDir . '/symfony/string/Resources/functions.php', '6cd5651c4fef5ed6b63e8d8b8ffbf3cc' => $vendorDir . '/amphp/byte-stream/lib/functions.php', ); MIT License Copyright (c) 2017 Composer Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * * For the full copyright and license information, please view * the LICENSE file that was distributed with this source code. */ namespace _HumbugBox7ff99e199a36\Composer\XdebugHandler; /** * @author John Stevenson * * @phpstan-type restartData array{tmpIni: string, scannedInis: bool, scanDir: false|string, phprc: false|string, inis: string[], skipped: string} */ class PhpConfig { /** * Use the original PHP configuration * * @return string[] Empty array of PHP cli options */ public function useOriginal() : array { $this->getDataAndReset(); return []; } /** * Use standard restart settings * * @return string[] PHP cli options */ public function useStandard() : array { $data = $this->getDataAndReset(); if ($data !== null) { return ['-n', '-c', $data['tmpIni']]; } return []; } /** * Use environment variables to persist settings * * @return string[] Empty array of PHP cli options */ public function usePersistent() : array { $data = $this->getDataAndReset(); if ($data !== null) { $this->updateEnv('PHPRC', $data['tmpIni']); $this->updateEnv('PHP_INI_SCAN_DIR', ''); } return []; } /** * Returns restart data if available and resets the environment * * @phpstan-return restartData|null */ private function getDataAndReset() : ?array { $data = XdebugHandler::getRestartSettings(); if ($data !== null) { $this->updateEnv('PHPRC', $data['phprc']); $this->updateEnv('PHP_INI_SCAN_DIR', $data['scanDir']); } return $data; } /** * Updates a restart settings value in the environment * * @param string $name * @param string|false $value */ private function updateEnv(string $name, $value) : void { Process::setEnv($name, \false !== $value ? $value : null); } } * * For the full copyright and license information, please view * the LICENSE file that was distributed with this source code. */ declare (strict_types=1); namespace _HumbugBox7ff99e199a36\Composer\XdebugHandler; use _HumbugBox7ff99e199a36\Composer\Pcre\Preg; /** * Process utility functions * * @author John Stevenson */ class Process { /** * Escapes a string to be used as a shell argument. * * From https://github.com/johnstevenson/winbox-args * MIT Licensed (c) John Stevenson * * @param string $arg The argument to be escaped * @param bool $meta Additionally escape cmd.exe meta characters * @param bool $module The argument is the module to invoke */ public static function escape(string $arg, bool $meta = \true, bool $module = \false) : string { if (!\defined('PHP_WINDOWS_VERSION_BUILD')) { return "'" . \str_replace("'", "'\\''", $arg) . "'"; } $quote = \strpbrk($arg, " \t") !== \false || $arg === ''; $arg = Preg::replace('/(\\\\*)"/', '$1$1\\"', $arg, -1, $dquotes); $dquotes = (bool) $dquotes; if ($meta) { $meta = $dquotes || Preg::isMatch('/%[^%]+%/', $arg); if (!$meta) { $quote = $quote || \strpbrk($arg, '^&|<>()') !== \false; } elseif ($module && !$dquotes && $quote) { $meta = \false; } } if ($quote) { $arg = '"' . Preg::replace('/(\\\\*)$/', '$1$1', $arg) . '"'; } if ($meta) { $arg = Preg::replace('/(["^&|<>()%])/', '^$1', $arg); } return $arg; } /** * Escapes an array of arguments that make up a shell command * * @param string[] $args Argument list, with the module name first */ public static function escapeShellCommand(array $args) : string { $command = ''; $module = \array_shift($args); if ($module !== null) { $command = self::escape($module, \true, \true); foreach ($args as $arg) { $command .= ' ' . self::escape($arg); } } return $command; } /** * Makes putenv environment changes available in $_SERVER and $_ENV * * @param string $name * @param ?string $value A null value unsets the variable */ public static function setEnv(string $name, ?string $value = null) : bool { $unset = null === $value; if (!\putenv($unset ? $name : $name . '=' . $value)) { return \false; } if ($unset) { unset($_SERVER[$name]); } else { $_SERVER[$name] = $value; } // Update $_ENV if it is being used if (\false !== \stripos((string) \ini_get('variables_order'), 'E')) { if ($unset) { unset($_ENV[$name]); } else { $_ENV[$name] = $value; } } return \true; } } * * For the full copyright and license information, please view * the LICENSE file that was distributed with this source code. */ declare (strict_types=1); namespace _HumbugBox7ff99e199a36\Composer\XdebugHandler; use _HumbugBox7ff99e199a36\Composer\Pcre\Preg; use _HumbugBox7ff99e199a36\Psr\Log\LoggerInterface; /** * @author John Stevenson * * @phpstan-import-type restartData from PhpConfig */ class XdebugHandler { const SUFFIX_ALLOW = '_ALLOW_XDEBUG'; const SUFFIX_INIS = '_ORIGINAL_INIS'; const RESTART_ID = 'internal'; const RESTART_SETTINGS = 'XDEBUG_HANDLER_SETTINGS'; const DEBUG = 'XDEBUG_HANDLER_DEBUG'; /** @var string|null */ protected $tmpIni; /** @var bool */ private static $inRestart; /** @var string */ private static $name; /** @var string|null */ private static $skipped; /** @var bool */ private static $xdebugActive; /** @var string|null */ private static $xdebugMode; /** @var string|null */ private static $xdebugVersion; /** @var bool */ private $cli; /** @var string|null */ private $debug; /** @var string */ private $envAllowXdebug; /** @var string */ private $envOriginalInis; /** @var bool */ private $persistent; /** @var string|null */ private $script; /** @var Status */ private $statusWriter; /** * Constructor * * The $envPrefix is used to create distinct environment variables. It is * uppercased and prepended to the default base values. For example 'myapp' * would result in MYAPP_ALLOW_XDEBUG and MYAPP_ORIGINAL_INIS. * * @param string $envPrefix Value used in environment variables * @throws \RuntimeException If the parameter is invalid */ public function __construct(string $envPrefix) { if ($envPrefix === '') { throw new \RuntimeException('Invalid constructor parameter'); } self::$name = \strtoupper($envPrefix); $this->envAllowXdebug = self::$name . self::SUFFIX_ALLOW; $this->envOriginalInis = self::$name . self::SUFFIX_INIS; self::setXdebugDetails(); self::$inRestart = \false; if ($this->cli = \PHP_SAPI === 'cli') { $this->debug = (string) \getenv(self::DEBUG); } $this->statusWriter = new Status($this->envAllowXdebug, (bool) $this->debug); } /** * Activates status message output to a PSR3 logger */ public function setLogger(LoggerInterface $logger) : self { $this->statusWriter->setLogger($logger); return $this; } /** * Sets the main script location if it cannot be called from argv */ public function setMainScript(string $script) : self { $this->script = $script; return $this; } /** * Persist the settings to keep Xdebug out of sub-processes */ public function setPersistent() : self { $this->persistent = \true; return $this; } /** * Checks if Xdebug is loaded and the process needs to be restarted * * This behaviour can be disabled by setting the MYAPP_ALLOW_XDEBUG * environment variable to 1. This variable is used internally so that * the restarted process is created only once. */ public function check() : void { $this->notify(Status::CHECK, self::$xdebugVersion . '|' . self::$xdebugMode); $envArgs = \explode('|', (string) \getenv($this->envAllowXdebug)); if (!(bool) $envArgs[0] && $this->requiresRestart(self::$xdebugActive)) { // Restart required $this->notify(Status::RESTART); $command = $this->prepareRestart(); if ($command !== null) { $this->restart($command); } return; } if (self::RESTART_ID === $envArgs[0] && \count($envArgs) === 5) { // Restarted, so unset environment variable and use saved values $this->notify(Status::RESTARTED); Process::setEnv($this->envAllowXdebug); self::$inRestart = \true; if (self::$xdebugVersion === null) { // Skipped version is only set if Xdebug is not loaded self::$skipped = $envArgs[1]; } $this->tryEnableSignals(); // Put restart settings in the environment $this->setEnvRestartSettings($envArgs); return; } $this->notify(Status::NORESTART); $settings = self::getRestartSettings(); if ($settings !== null) { // Called with existing settings, so sync our settings $this->syncSettings($settings); } } /** * Returns an array of php.ini locations with at least one entry * * The equivalent of calling php_ini_loaded_file then php_ini_scanned_files. * The loaded ini location is the first entry and may be an empty string. * * @return non-empty-list */ public static function getAllIniFiles() : array { if (self::$name !== null) { $env = \getenv(self::$name . self::SUFFIX_INIS); if (\false !== $env) { return \explode(\PATH_SEPARATOR, $env); } } $paths = [(string) \php_ini_loaded_file()]; $scanned = \php_ini_scanned_files(); if ($scanned !== \false) { $paths = \array_merge($paths, \array_map('trim', \explode(',', $scanned))); } return $paths; } /** * Returns an array of restart settings or null * * Settings will be available if the current process was restarted, or * called with the settings from an existing restart. * * @phpstan-return restartData|null */ public static function getRestartSettings() : ?array { $envArgs = \explode('|', (string) \getenv(self::RESTART_SETTINGS)); if (\count($envArgs) !== 6 || !self::$inRestart && \php_ini_loaded_file() !== $envArgs[0]) { return null; } return ['tmpIni' => $envArgs[0], 'scannedInis' => (bool) $envArgs[1], 'scanDir' => '*' === $envArgs[2] ? \false : $envArgs[2], 'phprc' => '*' === $envArgs[3] ? \false : $envArgs[3], 'inis' => \explode(\PATH_SEPARATOR, $envArgs[4]), 'skipped' => $envArgs[5]]; } /** * Returns the Xdebug version that triggered a successful restart */ public static function getSkippedVersion() : string { return (string) self::$skipped; } /** * Returns whether Xdebug is loaded and active * * true: if Xdebug is loaded and is running in an active mode. * false: if Xdebug is not loaded, or it is running with xdebug.mode=off. */ public static function isXdebugActive() : bool { self::setXdebugDetails(); return self::$xdebugActive; } /** * Allows an extending class to decide if there should be a restart * * The default is to restart if Xdebug is loaded and its mode is not "off". */ protected function requiresRestart(bool $default) : bool { return $default; } /** * Allows an extending class to access the tmpIni * * @param non-empty-list $command */ protected function restart(array $command) : void { $this->doRestart($command); } /** * Executes the restarted command then deletes the tmp ini * * @param non-empty-list $command * @phpstan-return never */ private function doRestart(array $command) : void { if (\PHP_VERSION_ID >= 70400) { $cmd = $command; $displayCmd = \sprintf('[%s]', \implode(', ', $cmd)); } else { $cmd = Process::escapeShellCommand($command); if (\defined('PHP_WINDOWS_VERSION_BUILD')) { // Outer quotes required on cmd string below PHP 8 $cmd = '"' . $cmd . '"'; } $displayCmd = $cmd; } $this->tryEnableSignals(); $this->notify(Status::RESTARTING, $displayCmd); $process = \proc_open($cmd, [], $pipes); if (\is_resource($process)) { $exitCode = \proc_close($process); } if (!isset($exitCode)) { // Unlikely that php or the default shell cannot be invoked $this->notify(Status::ERROR, 'Unable to restart process'); $exitCode = -1; } else { $this->notify(Status::INFO, 'Restarted process exited ' . $exitCode); } if ($this->debug === '2') { $this->notify(Status::INFO, 'Temp ini saved: ' . $this->tmpIni); } else { @\unlink((string) $this->tmpIni); } exit($exitCode); } /** * Returns the command line array if everything was written for the restart * * If any of the following fails (however unlikely) we must return false to * stop potential recursion: * - tmp ini file creation * - environment variable creation * * @return non-empty-list|null */ private function prepareRestart() : ?array { if (!$this->cli) { $this->notify(Status::ERROR, 'Unsupported SAPI: ' . \PHP_SAPI); return null; } if (($argv = $this->checkServerArgv()) === null) { $this->notify(Status::ERROR, '$_SERVER[argv] is not as expected'); return null; } if (!$this->checkConfiguration($info)) { $this->notify(Status::ERROR, $info); return null; } $mainScript = (string) $this->script; if (!$this->checkMainScript($mainScript, $argv)) { $this->notify(Status::ERROR, 'Unable to access main script: ' . $mainScript); return null; } $tmpDir = \sys_get_temp_dir(); $iniError = 'Unable to create temp ini file at: ' . $tmpDir; if (($tmpfile = @\tempnam($tmpDir, '')) === \false) { $this->notify(Status::ERROR, $iniError); return null; } $error = null; $iniFiles = self::getAllIniFiles(); $scannedInis = \count($iniFiles) > 1; if (!$this->writeTmpIni($tmpfile, $iniFiles, $error)) { $this->notify(Status::ERROR, $error ?? $iniError); @\unlink($tmpfile); return null; } if (!$this->setEnvironment($scannedInis, $iniFiles, $tmpfile)) { $this->notify(Status::ERROR, 'Unable to set environment variables'); @\unlink($tmpfile); return null; } $this->tmpIni = $tmpfile; return $this->getCommand($argv, $tmpfile, $mainScript); } /** * Returns true if the tmp ini file was written * * @param non-empty-list $iniFiles All ini files used in the current process */ private function writeTmpIni(string $tmpFile, array $iniFiles, ?string &$error) : bool { // $iniFiles has at least one item and it may be empty if ($iniFiles[0] === '') { \array_shift($iniFiles); } $content = ''; $sectionRegex = '/^\\s*\\[(?:PATH|HOST)\\s*=/mi'; $xdebugRegex = '/^\\s*(zend_extension\\s*=.*xdebug.*)$/mi'; foreach ($iniFiles as $file) { // Check for inaccessible ini files if (($data = @\file_get_contents($file)) === \false) { $error = 'Unable to read ini: ' . $file; return \false; } // Check and remove directives after HOST and PATH sections if (Preg::isMatchWithOffsets($sectionRegex, $data, $matches)) { $data = \substr($data, 0, $matches[0][1]); } $content .= Preg::replace($xdebugRegex, ';$1', $data) . \PHP_EOL; } // Merge loaded settings into our ini content, if it is valid $config = \parse_ini_string($content); $loaded = \ini_get_all(null, \false); if (\false === $config || \false === $loaded) { $error = 'Unable to parse ini data'; return \false; } $content .= $this->mergeLoadedConfig($loaded, $config); // Work-around for https://bugs.php.net/bug.php?id=75932 $content .= 'opcache.enable_cli=0' . \PHP_EOL; return (bool) @\file_put_contents($tmpFile, $content); } /** * Returns the command line arguments for the restart * * @param non-empty-list $argv * @return non-empty-list */ private function getCommand(array $argv, string $tmpIni, string $mainScript) : array { $php = [\PHP_BINARY]; $args = \array_slice($argv, 1); if (!$this->persistent) { // Use command-line options \array_push($php, '-n', '-c', $tmpIni); } return \array_merge($php, [$mainScript], $args); } /** * Returns true if the restart environment variables were set * * No need to update $_SERVER since this is set in the restarted process. * * @param non-empty-list $iniFiles All ini files used in the current process */ private function setEnvironment(bool $scannedInis, array $iniFiles, string $tmpIni) : bool { $scanDir = \getenv('PHP_INI_SCAN_DIR'); $phprc = \getenv('PHPRC'); // Make original inis available to restarted process if (!\putenv($this->envOriginalInis . '=' . \implode(\PATH_SEPARATOR, $iniFiles))) { return \false; } if ($this->persistent) { // Use the environment to persist the settings if (!\putenv('PHP_INI_SCAN_DIR=') || !\putenv('PHPRC=' . $tmpIni)) { return \false; } } // Flag restarted process and save values for it to use $envArgs = [self::RESTART_ID, self::$xdebugVersion, (int) $scannedInis, \false === $scanDir ? '*' : $scanDir, \false === $phprc ? '*' : $phprc]; return \putenv($this->envAllowXdebug . '=' . \implode('|', $envArgs)); } /** * Logs status messages */ private function notify(string $op, ?string $data = null) : void { $this->statusWriter->report($op, $data); } /** * Returns default, changed and command-line ini settings * * @param mixed[] $loadedConfig All current ini settings * @param mixed[] $iniConfig Settings from user ini files * */ private function mergeLoadedConfig(array $loadedConfig, array $iniConfig) : string { $content = ''; foreach ($loadedConfig as $name => $value) { // Value will either be null, string or array (HHVM only) if (!\is_string($value) || \strpos($name, 'xdebug') === 0 || $name === 'apc.mmap_file_mask') { continue; } if (!isset($iniConfig[$name]) || $iniConfig[$name] !== $value) { // Double-quote escape each value $content .= $name . '="' . \addcslashes($value, '\\"') . '"' . \PHP_EOL; } } return $content; } /** * Returns true if the script name can be used * * @param non-empty-list $argv */ private function checkMainScript(string &$mainScript, array $argv) : bool { if ($mainScript !== '') { // Allow an application to set -- for standard input return \file_exists($mainScript) || '--' === $mainScript; } if (\file_exists($mainScript = $argv[0])) { return \true; } // Use a backtrace to resolve Phar and chdir issues. $trace = \debug_backtrace(\DEBUG_BACKTRACE_IGNORE_ARGS); $main = \end($trace); if ($main !== \false && isset($main['file'])) { return \file_exists($mainScript = $main['file']); } return \false; } /** * Adds restart settings to the environment * * @param non-empty-list $envArgs */ private function setEnvRestartSettings(array $envArgs) : void { $settings = [\php_ini_loaded_file(), $envArgs[2], $envArgs[3], $envArgs[4], \getenv($this->envOriginalInis), self::$skipped]; Process::setEnv(self::RESTART_SETTINGS, \implode('|', $settings)); } /** * Syncs settings and the environment if called with existing settings * * @phpstan-param restartData $settings */ private function syncSettings(array $settings) : void { if (\false === \getenv($this->envOriginalInis)) { // Called by another app, so make original inis available Process::setEnv($this->envOriginalInis, \implode(\PATH_SEPARATOR, $settings['inis'])); } self::$skipped = $settings['skipped']; $this->notify(Status::INFO, 'Process called with existing restart settings'); } /** * Returns true if there are no known configuration issues */ private function checkConfiguration(?string &$info) : bool { if (!\function_exists('proc_open')) { $info = 'proc_open function is disabled'; return \false; } if (!\file_exists(\PHP_BINARY)) { $info = 'PHP_BINARY is not available'; return \false; } if (\extension_loaded('uopz') && !(bool) \ini_get('uopz.disable')) { // uopz works at opcode level and disables exit calls if (\function_exists('uopz_allow_exit')) { @\uopz_allow_exit(\true); } else { $info = 'uopz extension is not compatible'; return \false; } } // Check UNC paths when using cmd.exe if (\defined('PHP_WINDOWS_VERSION_BUILD') && \PHP_VERSION_ID < 70400) { $workingDir = \getcwd(); if ($workingDir === \false) { $info = 'unable to determine working directory'; return \false; } if (0 === \strpos($workingDir, '\\\\')) { $info = 'cmd.exe does not support UNC paths: ' . $workingDir; return \false; } } return \true; } /** * Enables async signals and control interrupts in the restarted process * * Available on Unix PHP 7.1+ with the pcntl extension and Windows PHP 7.4+. */ private function tryEnableSignals() : void { if (\function_exists('pcntl_async_signals') && \function_exists('pcntl_signal')) { \pcntl_async_signals(\true); $message = 'Async signals enabled'; if (!self::$inRestart) { // Restarting, so ignore SIGINT in parent \pcntl_signal(\SIGINT, \SIG_IGN); } elseif (\is_int(\pcntl_signal_get_handler(\SIGINT))) { // Restarted, no handler set so force default action \pcntl_signal(\SIGINT, \SIG_DFL); } } if (!self::$inRestart && \function_exists('sapi_windows_set_ctrl_handler')) { // Restarting, so set a handler to ignore CTRL events in the parent. // This ensures that CTRL+C events will be available in the child // process without having to enable them there, which is unreliable. \sapi_windows_set_ctrl_handler(function ($evt) { }); } } /** * Returns $_SERVER['argv'] if it is as expected * * @return non-empty-list|null */ private function checkServerArgv() : ?array { $result = []; if (isset($_SERVER['argv']) && \is_array($_SERVER['argv'])) { foreach ($_SERVER['argv'] as $value) { if (!\is_string($value)) { return null; } $result[] = $value; } } return \count($result) > 0 ? $result : null; } /** * Sets static properties $xdebugActive, $xdebugVersion and $xdebugMode */ private static function setXdebugDetails() : void { if (self::$xdebugActive !== null) { return; } self::$xdebugActive = \false; if (!\extension_loaded('xdebug')) { return; } $version = \phpversion('xdebug'); self::$xdebugVersion = $version !== \false ? $version : 'unknown'; if (\version_compare(self::$xdebugVersion, '3.1', '>=')) { $modes = \xdebug_info('mode'); self::$xdebugMode = \count($modes) === 0 ? 'off' : \implode(',', $modes); self::$xdebugActive = self::$xdebugMode !== 'off'; return; } // See if xdebug.mode is supported in this version $iniMode = \ini_get('xdebug.mode'); if ($iniMode === \false) { self::$xdebugActive = \true; return; } // Environment value wins but cannot be empty $envMode = (string) \getenv('XDEBUG_MODE'); if ($envMode !== '') { self::$xdebugMode = $envMode; } else { self::$xdebugMode = $iniMode !== '' ? $iniMode : 'off'; } // An empty comma-separated list is treated as mode 'off' if (Preg::isMatch('/^,+$/', \str_replace(' ', '', self::$xdebugMode))) { self::$xdebugMode = 'off'; } self::$xdebugActive = self::$xdebugMode !== 'off'; } } * * For the full copyright and license information, please view * the LICENSE file that was distributed with this source code. */ declare (strict_types=1); namespace _HumbugBox7ff99e199a36\Composer\XdebugHandler; use _HumbugBox7ff99e199a36\Psr\Log\LoggerInterface; use _HumbugBox7ff99e199a36\Psr\Log\LogLevel; /** * @author John Stevenson * @internal */ class Status { const ENV_RESTART = 'XDEBUG_HANDLER_RESTART'; const CHECK = 'Check'; const ERROR = 'Error'; const INFO = 'Info'; const NORESTART = 'NoRestart'; const RESTART = 'Restart'; const RESTARTING = 'Restarting'; const RESTARTED = 'Restarted'; /** @var bool */ private $debug; /** @var string */ private $envAllowXdebug; /** @var string|null */ private $loaded; /** @var LoggerInterface|null */ private $logger; /** @var bool */ private $modeOff; /** @var float */ private $time; /** * @param string $envAllowXdebug Prefixed _ALLOW_XDEBUG name * @param bool $debug Whether debug output is required */ public function __construct(string $envAllowXdebug, bool $debug) { $start = \getenv(self::ENV_RESTART); Process::setEnv(self::ENV_RESTART); $this->time = \is_numeric($start) ? \round((\microtime(\true) - $start) * 1000) : 0; $this->envAllowXdebug = $envAllowXdebug; $this->debug = $debug && \defined('STDERR'); $this->modeOff = \false; } /** * Activates status message output to a PSR3 logger * * @return void */ public function setLogger(LoggerInterface $logger) : void { $this->logger = $logger; } /** * Calls a handler method to report a message * * @throws \InvalidArgumentException If $op is not known */ public function report(string $op, ?string $data) : void { if ($this->logger !== null || $this->debug) { $param = (string) $data; switch ($op) { case self::CHECK: $this->reportCheck($param); break; case self::ERROR: $this->reportError($param); break; case self::INFO: $this->reportInfo($param); break; case self::NORESTART: $this->reportNoRestart(); break; case self::RESTART: $this->reportRestart(); break; case self::RESTARTED: $this->reportRestarted(); break; case self::RESTARTING: $this->reportRestarting($param); break; default: throw new \InvalidArgumentException('Unknown op handler: ' . $op); } } } /** * Outputs a status message */ private function output(string $text, ?string $level = null) : void { if ($this->logger !== null) { $this->logger->log($level !== null ? $level : LogLevel::DEBUG, $text); } if ($this->debug) { \fwrite(\STDERR, \sprintf('xdebug-handler[%d] %s', \getmypid(), $text . \PHP_EOL)); } } /** * Checking status message */ private function reportCheck(string $loaded) : void { list($version, $mode) = \explode('|', $loaded); if ($version !== '') { $this->loaded = '(' . $version . ')' . ($mode !== '' ? ' xdebug.mode=' . $mode : ''); } $this->modeOff = $mode === 'off'; $this->output('Checking ' . $this->envAllowXdebug); } /** * Error status message */ private function reportError(string $error) : void { $this->output(\sprintf('No restart (%s)', $error), LogLevel::WARNING); } /** * Info status message */ private function reportInfo(string $info) : void { $this->output($info); } /** * No restart status message */ private function reportNoRestart() : void { $this->output($this->getLoadedMessage()); if ($this->loaded !== null) { $text = \sprintf('No restart (%s)', $this->getEnvAllow()); if (!(bool) \getenv($this->envAllowXdebug)) { $text .= ' Allowed by ' . ($this->modeOff ? 'xdebug.mode' : 'application'); } $this->output($text); } } /** * Restart status message */ private function reportRestart() : void { $this->output($this->getLoadedMessage()); Process::setEnv(self::ENV_RESTART, (string) \microtime(\true)); } /** * Restarted status message */ private function reportRestarted() : void { $loaded = $this->getLoadedMessage(); $text = \sprintf('Restarted (%d ms). %s', $this->time, $loaded); $level = $this->loaded !== null ? LogLevel::WARNING : null; $this->output($text, $level); } /** * Restarting status message */ private function reportRestarting(string $command) : void { $text = \sprintf('Process restarting (%s)', $this->getEnvAllow()); $this->output($text); $text = 'Running: ' . $command; $this->output($text); } /** * Returns the _ALLOW_XDEBUG environment variable as name=value */ private function getEnvAllow() : string { return $this->envAllowXdebug . '=' . \getenv($this->envAllowXdebug); } /** * Returns the Xdebug status and version */ private function getLoadedMessage() : string { $loaded = $this->loaded !== null ? \sprintf('loaded %s', $this->loaded) : 'not loaded'; return 'The Xdebug extension is ' . $loaded; } } Copyright (c) Nils Adermann, Jordi Boggiano Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. array('name' => 'vimeo/psalm', 'pretty_version' => '5.26.1', 'version' => '5.26.1.0', 'reference' => 'd747f6500b38ac4f7dfc5edbcae6e4b637d7add0', 'type' => 'project', 'install_path' => __DIR__ . '/../../', 'aliases' => array(), 'dev' => \true), 'versions' => array('amphp/amp' => array('pretty_version' => 'v2.6.4', 'version' => '2.6.4.0', 'reference' => 'ded3d9be08f526089eb7ee8d9f16a9768f9dec2d', 'type' => 'library', 'install_path' => __DIR__ . '/../amphp/amp', 'aliases' => array(), 'dev_requirement' => \false), 'amphp/byte-stream' => array('pretty_version' => 'v1.8.2', 'version' => '1.8.2.0', 'reference' => '4f0e968ba3798a423730f567b1b50d3441c16ddc', 'type' => 'library', 'install_path' => __DIR__ . '/../amphp/byte-stream', 'aliases' => array(), 'dev_requirement' => \false), 'amphp/phpunit-util' => array('pretty_version' => 'v2.0.0', 'version' => '2.0.0.0', 'reference' => 'be64a5285aa1671cea8e546963a21cca67044842', 'type' => 'library', 'install_path' => __DIR__ . '/../amphp/phpunit-util', 'aliases' => array(), 'dev_requirement' => \true), 'bamarni/composer-bin-plugin' => array('pretty_version' => '1.8.2', 'version' => '1.8.2.0', 'reference' => '92fd7b1e6e9cdae19b0d57369d8ad31a37b6a880', 'type' => 'composer-plugin', 'install_path' => __DIR__ . '/../bamarni/composer-bin-plugin', 'aliases' => array(), 'dev_requirement' => \true), 'brianium/paratest' => array('pretty_version' => 'v6.11.1', 'version' => '6.11.1.0', 'reference' => '78e297a969049ca7cc370e80ff5e102921ef39a3', 'type' => 'library', 'install_path' => __DIR__ . '/../brianium/paratest', 'aliases' => array(), 'dev_requirement' => \true), 'composer/package-versions-deprecated' => array('pretty_version' => '1.11.99.5', 'version' => '1.11.99.5', 'reference' => 'b4f54f74ef3453349c24a845d22392cd31e65f1d', 'type' => 'composer-plugin', 'install_path' => __DIR__ . '/./package-versions-deprecated', 'aliases' => array(), 'dev_requirement' => \true), 'composer/pcre' => array('pretty_version' => '3.3.1', 'version' => '3.3.1.0', 'reference' => '63aaeac21d7e775ff9bc9d45021e1745c97521c4', 'type' => 'library', 'install_path' => __DIR__ . '/./pcre', 'aliases' => array(), 'dev_requirement' => \false), 'composer/semver' => array('pretty_version' => '3.4.2', 'version' => '3.4.2.0', 'reference' => 'c51258e759afdb17f1fd1fe83bc12baaef6309d6', 'type' => 'library', 'install_path' => __DIR__ . '/./semver', 'aliases' => array(), 'dev_requirement' => \false), 'composer/xdebug-handler' => array('pretty_version' => '3.0.5', 'version' => '3.0.5.0', 'reference' => '6c1925561632e83d60a44492e0b344cf48ab85ef', 'type' => 'library', 'install_path' => __DIR__ . '/./xdebug-handler', 'aliases' => array(), 'dev_requirement' => \false), 'cordoval/hamcrest-php' => array('dev_requirement' => \true, 'replaced' => array(0 => '*')), 'davedevelopment/hamcrest-php' => array('dev_requirement' => \true, 'replaced' => array(0 => '*')), 'dealerdirect/phpcodesniffer-composer-installer' => array('pretty_version' => 'v1.0.0', 'version' => '1.0.0.0', 'reference' => '4be43904336affa5c2f70744a348312336afd0da', 'type' => 'composer-plugin', 'install_path' => __DIR__ . '/../dealerdirect/phpcodesniffer-composer-installer', 'aliases' => array(), 'dev_requirement' => \true), 'dg/bypass-finals' => array('pretty_version' => 'v1.8.0', 'version' => '1.8.0.0', 'reference' => '86b00f0d900c7e15d3341e687e0df89e8c2d4632', 'type' => 'library', 'install_path' => __DIR__ . '/../dg/bypass-finals', 'aliases' => array(), 'dev_requirement' => \true), 'dnoegel/php-xdg-base-dir' => array('pretty_version' => 'v0.1.1', 'version' => '0.1.1.0', 'reference' => '8f8a6e48c5ecb0f991c2fdcf5f154a47d85f9ffd', 'type' => 'library', 'install_path' => __DIR__ . '/../dnoegel/php-xdg-base-dir', 'aliases' => array(), 'dev_requirement' => \false), 'doctrine/deprecations' => array('pretty_version' => '1.1.3', 'version' => '1.1.3.0', 'reference' => 'dfbaa3c2d2e9a9df1118213f3b8b0c597bb99fab', 'type' => 'library', 'install_path' => __DIR__ . '/../doctrine/deprecations', 'aliases' => array(), 'dev_requirement' => \false), 'doctrine/instantiator' => array('pretty_version' => '1.5.0', 'version' => '1.5.0.0', 'reference' => '0a0fa9780f5d4e507415a065172d26a98d02047b', 'type' => 'library', 'install_path' => __DIR__ . '/../doctrine/instantiator', 'aliases' => array(), 'dev_requirement' => \true), 'felixfbecker/advanced-json-rpc' => array('pretty_version' => 'v3.2.1', 'version' => '3.2.1.0', 'reference' => 'b5f37dbff9a8ad360ca341f3240dc1c168b45447', 'type' => 'library', 'install_path' => __DIR__ . '/../felixfbecker/advanced-json-rpc', 'aliases' => array(), 'dev_requirement' => \false), 'felixfbecker/language-server-protocol' => array('pretty_version' => 'v1.5.2', 'version' => '1.5.2.0', 'reference' => '6e82196ffd7c62f7794d778ca52b69feec9f2842', 'type' => 'library', 'install_path' => __DIR__ . '/../felixfbecker/language-server-protocol', 'aliases' => array(), 'dev_requirement' => \false), 'fidry/cpu-core-counter' => array('pretty_version' => '1.2.0', 'version' => '1.2.0.0', 'reference' => '8520451a140d3f46ac33042715115e290cf5785f', 'type' => 'library', 'install_path' => __DIR__ . '/../fidry/cpu-core-counter', 'aliases' => array(), 'dev_requirement' => \false), 'grogy/php-parallel-lint' => array('dev_requirement' => \true, 'replaced' => array(0 => '*')), 'hamcrest/hamcrest-php' => array('pretty_version' => 'v2.0.1', 'version' => '2.0.1.0', 'reference' => '8c3d0a3f6af734494ad8f6fbbee0ba92422859f3', 'type' => 'library', 'install_path' => __DIR__ . '/../hamcrest/hamcrest-php', 'aliases' => array(), 'dev_requirement' => \true), 'jakub-onderka/php-parallel-lint' => array('dev_requirement' => \true, 'replaced' => array(0 => '*')), 'jean85/pretty-package-versions' => array('pretty_version' => '2.0.6', 'version' => '2.0.6.0', 'reference' => 'f9fdd29ad8e6d024f52678b570e5593759b550b4', 'type' => 'library', 'install_path' => __DIR__ . '/../jean85/pretty-package-versions', 'aliases' => array(), 'dev_requirement' => \true), 'kodova/hamcrest-php' => array('dev_requirement' => \true, 'replaced' => array(0 => '*')), 'mockery/mockery' => array('pretty_version' => '1.6.12', 'version' => '1.6.12.0', 'reference' => '1f4efdd7d3beafe9807b08156dfcb176d18f1699', 'type' => 'library', 'install_path' => __DIR__ . '/../mockery/mockery', 'aliases' => array(), 'dev_requirement' => \true), 'myclabs/deep-copy' => array('pretty_version' => '1.12.0', 'version' => '1.12.0.0', 'reference' => '3a6b9a42cd8f8771bd4295d13e1423fa7f3d942c', 'type' => 'library', 'install_path' => __DIR__ . '/../myclabs/deep-copy', 'aliases' => array(), 'dev_requirement' => \true), 'netresearch/jsonmapper' => array('pretty_version' => 'v4.5.0', 'version' => '4.5.0.0', 'reference' => '8e76efb98ee8b6afc54687045e1b8dba55ac76e5', 'type' => 'library', 'install_path' => __DIR__ . '/../netresearch/jsonmapper', 'aliases' => array(), 'dev_requirement' => \false), 'nikic/php-parser' => array('pretty_version' => 'v4.19.1', 'version' => '4.19.1.0', 'reference' => '4e1b88d21c69391150ace211e9eaf05810858d0b', 'type' => 'library', 'install_path' => __DIR__ . '/../nikic/php-parser', 'aliases' => array(), 'dev_requirement' => \false), 'nunomaduro/mock-final-classes' => array('pretty_version' => 'v1.2.0', 'version' => '1.2.0.0', 'reference' => 'b13fc71acd9d6f1e2de8209217103cbd2035871f', 'type' => 'library', 'install_path' => __DIR__ . '/../nunomaduro/mock-final-classes', 'aliases' => array(), 'dev_requirement' => \true), 'ocramius/package-versions' => array('dev_requirement' => \true, 'replaced' => array(0 => '1.11.99')), 'phar-io/manifest' => array('pretty_version' => '2.0.4', 'version' => '2.0.4.0', 'reference' => '54750ef60c58e43759730615a392c31c80e23176', 'type' => 'library', 'install_path' => __DIR__ . '/../phar-io/manifest', 'aliases' => array(), 'dev_requirement' => \true), 'phar-io/version' => array('pretty_version' => '3.2.1', 'version' => '3.2.1.0', 'reference' => '4f7fd7836c6f332bb2933569e566a0d6c4cbed74', 'type' => 'library', 'install_path' => __DIR__ . '/../phar-io/version', 'aliases' => array(), 'dev_requirement' => \true), 'php-parallel-lint/php-parallel-lint' => array('pretty_version' => 'v1.4.0', 'version' => '1.4.0.0', 'reference' => '6db563514f27e19595a19f45a4bf757b6401194e', 'type' => 'library', 'install_path' => __DIR__ . '/../php-parallel-lint/php-parallel-lint', 'aliases' => array(), 'dev_requirement' => \true), 'phpdocumentor/reflection-common' => array('pretty_version' => '2.2.0', 'version' => '2.2.0.0', 'reference' => '1d01c49d4ed62f25aa84a747ad35d5a16924662b', 'type' => 'library', 'install_path' => __DIR__ . '/../phpdocumentor/reflection-common', 'aliases' => array(), 'dev_requirement' => \false), 'phpdocumentor/reflection-docblock' => array('pretty_version' => '5.4.1', 'version' => '5.4.1.0', 'reference' => '9d07b3f7fdcf5efec5d1609cba3c19c5ea2bdc9c', 'type' => 'library', 'install_path' => __DIR__ . '/../phpdocumentor/reflection-docblock', 'aliases' => array(), 'dev_requirement' => \false), 'phpdocumentor/type-resolver' => array('pretty_version' => '1.8.2', 'version' => '1.8.2.0', 'reference' => '153ae662783729388a584b4361f2545e4d841e3c', 'type' => 'library', 'install_path' => __DIR__ . '/../phpdocumentor/type-resolver', 'aliases' => array(), 'dev_requirement' => \false), 'phpstan/phpdoc-parser' => array('pretty_version' => '1.30.1', 'version' => '1.30.1.0', 'reference' => '51b95ec8670af41009e2b2b56873bad96682413e', 'type' => 'library', 'install_path' => __DIR__ . '/../phpstan/phpdoc-parser', 'aliases' => array(), 'dev_requirement' => \false), 'phpunit/php-code-coverage' => array('pretty_version' => '9.2.32', 'version' => '9.2.32.0', 'reference' => '85402a822d1ecf1db1096959413d35e1c37cf1a5', 'type' => 'library', 'install_path' => __DIR__ . '/../phpunit/php-code-coverage', 'aliases' => array(), 'dev_requirement' => \true), 'phpunit/php-file-iterator' => array('pretty_version' => '3.0.6', 'version' => '3.0.6.0', 'reference' => 'cf1c2e7c203ac650e352f4cc675a7021e7d1b3cf', 'type' => 'library', 'install_path' => __DIR__ . '/../phpunit/php-file-iterator', 'aliases' => array(), 'dev_requirement' => \true), 'phpunit/php-invoker' => array('pretty_version' => '3.1.1', 'version' => '3.1.1.0', 'reference' => '5a10147d0aaf65b58940a0b72f71c9ac0423cc67', 'type' => 'library', 'install_path' => __DIR__ . '/../phpunit/php-invoker', 'aliases' => array(), 'dev_requirement' => \true), 'phpunit/php-text-template' => array('pretty_version' => '2.0.4', 'version' => '2.0.4.0', 'reference' => '5da5f67fc95621df9ff4c4e5a84d6a8a2acf7c28', 'type' => 'library', 'install_path' => __DIR__ . '/../phpunit/php-text-template', 'aliases' => array(), 'dev_requirement' => \true), 'phpunit/php-timer' => array('pretty_version' => '5.0.3', 'version' => '5.0.3.0', 'reference' => '5a63ce20ed1b5bf577850e2c4e87f4aa902afbd2', 'type' => 'library', 'install_path' => __DIR__ . '/../phpunit/php-timer', 'aliases' => array(), 'dev_requirement' => \true), 'phpunit/phpunit' => array('pretty_version' => '9.6.20', 'version' => '9.6.20.0', 'reference' => '49d7820565836236411f5dc002d16dd689cde42f', 'type' => 'library', 'install_path' => __DIR__ . '/../phpunit/phpunit', 'aliases' => array(), 'dev_requirement' => \true), 'psalm/plugin-mockery' => array('pretty_version' => '1.1.0', 'version' => '1.1.0.0', 'reference' => '876247d15f91df08240d00dac69c5135b6689283', 'type' => 'psalm-plugin', 'install_path' => __DIR__ . '/../psalm/plugin-mockery', 'aliases' => array(), 'dev_requirement' => \true), 'psalm/plugin-phpunit' => array('pretty_version' => '0.18.4', 'version' => '0.18.4.0', 'reference' => 'e4ab3096653d9eb6f6d0ea5f4461898d59ae4dbc', 'type' => 'psalm-plugin', 'install_path' => __DIR__ . '/../psalm/plugin-phpunit', 'aliases' => array(), 'dev_requirement' => \true), 'psalm/psalm' => array('dev_requirement' => \false, 'provided' => array(0 => '5.26.1')), 'psr/container' => array('pretty_version' => '1.1.2', 'version' => '1.1.2.0', 'reference' => '513e0666f7216c7459170d56df27dfcefe1689ea', 'type' => 'library', 'install_path' => __DIR__ . '/../psr/container', 'aliases' => array(), 'dev_requirement' => \false), 'psr/log' => array('pretty_version' => '1.1.4', 'version' => '1.1.4.0', 'reference' => 'd49695b909c3b7628b6289db5479a1c204601f11', 'type' => 'library', 'install_path' => __DIR__ . '/../psr/log', 'aliases' => array(), 'dev_requirement' => \false), 'psr/log-implementation' => array('dev_requirement' => \false, 'provided' => array(0 => '1.0|2.0')), 'sebastian/cli-parser' => array('pretty_version' => '1.0.2', 'version' => '1.0.2.0', 'reference' => '2b56bea83a09de3ac06bb18b92f068e60cc6f50b', 'type' => 'library', 'install_path' => __DIR__ . '/../sebastian/cli-parser', 'aliases' => array(), 'dev_requirement' => \true), 'sebastian/code-unit' => array('pretty_version' => '1.0.8', 'version' => '1.0.8.0', 'reference' => '1fc9f64c0927627ef78ba436c9b17d967e68e120', 'type' => 'library', 'install_path' => __DIR__ . '/../sebastian/code-unit', 'aliases' => array(), 'dev_requirement' => \true), 'sebastian/code-unit-reverse-lookup' => array('pretty_version' => '2.0.3', 'version' => '2.0.3.0', 'reference' => 'ac91f01ccec49fb77bdc6fd1e548bc70f7faa3e5', 'type' => 'library', 'install_path' => __DIR__ . '/../sebastian/code-unit-reverse-lookup', 'aliases' => array(), 'dev_requirement' => \true), 'sebastian/comparator' => array('pretty_version' => '4.0.8', 'version' => '4.0.8.0', 'reference' => 'fa0f136dd2334583309d32b62544682ee972b51a', 'type' => 'library', 'install_path' => __DIR__ . '/../sebastian/comparator', 'aliases' => array(), 'dev_requirement' => \true), 'sebastian/complexity' => array('pretty_version' => '2.0.3', 'version' => '2.0.3.0', 'reference' => '25f207c40d62b8b7aa32f5ab026c53561964053a', 'type' => 'library', 'install_path' => __DIR__ . '/../sebastian/complexity', 'aliases' => array(), 'dev_requirement' => \true), 'sebastian/diff' => array('pretty_version' => '4.0.6', 'version' => '4.0.6.0', 'reference' => 'ba01945089c3a293b01ba9badc29ad55b106b0bc', 'type' => 'library', 'install_path' => __DIR__ . '/../sebastian/diff', 'aliases' => array(), 'dev_requirement' => \false), 'sebastian/environment' => array('pretty_version' => '5.1.5', 'version' => '5.1.5.0', 'reference' => '830c43a844f1f8d5b7a1f6d6076b784454d8b7ed', 'type' => 'library', 'install_path' => __DIR__ . '/../sebastian/environment', 'aliases' => array(), 'dev_requirement' => \true), 'sebastian/exporter' => array('pretty_version' => '4.0.6', 'version' => '4.0.6.0', 'reference' => '78c00df8f170e02473b682df15bfcdacc3d32d72', 'type' => 'library', 'install_path' => __DIR__ . '/../sebastian/exporter', 'aliases' => array(), 'dev_requirement' => \true), 'sebastian/global-state' => array('pretty_version' => '5.0.7', 'version' => '5.0.7.0', 'reference' => 'bca7df1f32ee6fe93b4d4a9abbf69e13a4ada2c9', 'type' => 'library', 'install_path' => __DIR__ . '/../sebastian/global-state', 'aliases' => array(), 'dev_requirement' => \true), 'sebastian/lines-of-code' => array('pretty_version' => '1.0.4', 'version' => '1.0.4.0', 'reference' => 'e1e4a170560925c26d424b6a03aed157e7dcc5c5', 'type' => 'library', 'install_path' => __DIR__ . '/../sebastian/lines-of-code', 'aliases' => array(), 'dev_requirement' => \true), 'sebastian/object-enumerator' => array('pretty_version' => '4.0.4', 'version' => '4.0.4.0', 'reference' => '5c9eeac41b290a3712d88851518825ad78f45c71', 'type' => 'library', 'install_path' => __DIR__ . '/../sebastian/object-enumerator', 'aliases' => array(), 'dev_requirement' => \true), 'sebastian/object-reflector' => array('pretty_version' => '2.0.4', 'version' => '2.0.4.0', 'reference' => 'b4f479ebdbf63ac605d183ece17d8d7fe49c15c7', 'type' => 'library', 'install_path' => __DIR__ . '/../sebastian/object-reflector', 'aliases' => array(), 'dev_requirement' => \true), 'sebastian/recursion-context' => array('pretty_version' => '4.0.5', 'version' => '4.0.5.0', 'reference' => 'e75bd0f07204fec2a0af9b0f3cfe97d05f92efc1', 'type' => 'library', 'install_path' => __DIR__ . '/../sebastian/recursion-context', 'aliases' => array(), 'dev_requirement' => \true), 'sebastian/resource-operations' => array('pretty_version' => '3.0.4', 'version' => '3.0.4.0', 'reference' => '05d5692a7993ecccd56a03e40cd7e5b09b1d404e', 'type' => 'library', 'install_path' => __DIR__ . '/../sebastian/resource-operations', 'aliases' => array(), 'dev_requirement' => \true), 'sebastian/type' => array('pretty_version' => '3.2.1', 'version' => '3.2.1.0', 'reference' => '75e2c2a32f5e0b3aef905b9ed0b179b953b3d7c7', 'type' => 'library', 'install_path' => __DIR__ . '/../sebastian/type', 'aliases' => array(), 'dev_requirement' => \true), 'sebastian/version' => array('pretty_version' => '3.0.2', 'version' => '3.0.2.0', 'reference' => 'c6c1022351a901512170118436c764e473f6de8c', 'type' => 'library', 'install_path' => __DIR__ . '/../sebastian/version', 'aliases' => array(), 'dev_requirement' => \true), 'slevomat/coding-standard' => array('pretty_version' => '8.15.0', 'version' => '8.15.0.0', 'reference' => '7d1d957421618a3803b593ec31ace470177d7817', 'type' => 'phpcodesniffer-standard', 'install_path' => __DIR__ . '/../slevomat/coding-standard', 'aliases' => array(), 'dev_requirement' => \true), 'spatie/array-to-xml' => array('pretty_version' => '2.17.1', 'version' => '2.17.1.0', 'reference' => '5cbec9c6ab17e320c58a259f0cebe88bde4a7c46', 'type' => 'library', 'install_path' => __DIR__ . '/../spatie/array-to-xml', 'aliases' => array(), 'dev_requirement' => \false), 'squizlabs/php_codesniffer' => array('pretty_version' => '3.10.2', 'version' => '3.10.2.0', 'reference' => '86e5f5dd9a840c46810ebe5ff1885581c42a3017', 'type' => 'library', 'install_path' => __DIR__ . '/../squizlabs/php_codesniffer', 'aliases' => array(), 'dev_requirement' => \true), 'symfony/console' => array('pretty_version' => 'v5.4.43', 'version' => '5.4.43.0', 'reference' => 'e86f8554de667c16dde8aeb89a3990cfde924df9', 'type' => 'library', 'install_path' => __DIR__ . '/../symfony/console', 'aliases' => array(), 'dev_requirement' => \false), 'symfony/deprecation-contracts' => array('pretty_version' => 'v2.5.3', 'version' => '2.5.3.0', 'reference' => '80d075412b557d41002320b96a096ca65aa2c98d', 'type' => 'library', 'install_path' => __DIR__ . '/../symfony/deprecation-contracts', 'aliases' => array(), 'dev_requirement' => \false), 'symfony/filesystem' => array('pretty_version' => 'v5.4.41', 'version' => '5.4.41.0', 'reference' => '6d29dd9340b372fa603f04e6df4dd76bb808591e', 'type' => 'library', 'install_path' => __DIR__ . '/../symfony/filesystem', 'aliases' => array(), 'dev_requirement' => \false), 'symfony/polyfill-ctype' => array('pretty_version' => 'v1.31.0', 'version' => '1.31.0.0', 'reference' => 'a3cc8b044a6ea513310cbd48ef7333b384945638', 'type' => 'library', 'install_path' => __DIR__ . '/../symfony/polyfill-ctype', 'aliases' => array(), 'dev_requirement' => \false), 'symfony/polyfill-intl-grapheme' => array('pretty_version' => 'v1.31.0', 'version' => '1.31.0.0', 'reference' => 'b9123926e3b7bc2f98c02ad54f6a4b02b91a8abe', 'type' => 'library', 'install_path' => __DIR__ . '/../symfony/polyfill-intl-grapheme', 'aliases' => array(), 'dev_requirement' => \false), 'symfony/polyfill-intl-normalizer' => array('pretty_version' => 'v1.31.0', 'version' => '1.31.0.0', 'reference' => '3833d7255cc303546435cb650316bff708a1c75c', 'type' => 'library', 'install_path' => __DIR__ . '/../symfony/polyfill-intl-normalizer', 'aliases' => array(), 'dev_requirement' => \false), 'symfony/polyfill-mbstring' => array('pretty_version' => 'v1.31.0', 'version' => '1.31.0.0', 'reference' => '85181ba99b2345b0ef10ce42ecac37612d9fd341', 'type' => 'library', 'install_path' => __DIR__ . '/../symfony/polyfill-mbstring', 'aliases' => array(), 'dev_requirement' => \false), 'symfony/polyfill-php73' => array('pretty_version' => 'v1.31.0', 'version' => '1.31.0.0', 'reference' => '0f68c03565dcaaf25a890667542e8bd75fe7e5bb', 'type' => 'library', 'install_path' => __DIR__ . '/../symfony/polyfill-php73', 'aliases' => array(), 'dev_requirement' => \false), 'symfony/polyfill-php80' => array('pretty_version' => 'v1.31.0', 'version' => '1.31.0.0', 'reference' => '60328e362d4c2c802a54fcbf04f9d3fb892b4cf8', 'type' => 'library', 'install_path' => __DIR__ . '/../symfony/polyfill-php80', 'aliases' => array(), 'dev_requirement' => \false), 'symfony/process' => array('pretty_version' => 'v5.4.40', 'version' => '5.4.40.0', 'reference' => 'deedcb3bb4669cae2148bc920eafd2b16dc7c046', 'type' => 'library', 'install_path' => __DIR__ . '/../symfony/process', 'aliases' => array(), 'dev_requirement' => \true), 'symfony/service-contracts' => array('pretty_version' => 'v2.5.3', 'version' => '2.5.3.0', 'reference' => 'a2329596ddc8fd568900e3fc76cba42489ecc7f3', 'type' => 'library', 'install_path' => __DIR__ . '/../symfony/service-contracts', 'aliases' => array(), 'dev_requirement' => \false), 'symfony/string' => array('pretty_version' => 'v5.4.43', 'version' => '5.4.43.0', 'reference' => '8be1d484951ff5ca995eaf8edcbcb8b9a5888450', 'type' => 'library', 'install_path' => __DIR__ . '/../symfony/string', 'aliases' => array(), 'dev_requirement' => \false), 'theseer/tokenizer' => array('pretty_version' => '1.2.3', 'version' => '1.2.3.0', 'reference' => '737eda637ed5e28c3413cb1ebe8bb52cbf1ca7a2', 'type' => 'library', 'install_path' => __DIR__ . '/../theseer/tokenizer', 'aliases' => array(), 'dev_requirement' => \true), 'vimeo/psalm' => array('pretty_version' => '5.26.1', 'version' => '5.26.1.0', 'reference' => 'd747f6500b38ac4f7dfc5edbcae6e4b637d7add0', 'type' => 'project', 'install_path' => __DIR__ . '/../../', 'aliases' => array(), 'dev_requirement' => \false), 'webmozart/assert' => array('pretty_version' => '1.11.0', 'version' => '1.11.0.0', 'reference' => '11cb2199493b2f8a3b53e7f19068fc6aac760991', 'type' => 'library', 'install_path' => __DIR__ . '/../webmozart/assert', 'aliases' => array(), 'dev_requirement' => \false))); * Jordi Boggiano * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Composer\Autoload; /** * ClassLoader implements a PSR-0, PSR-4 and classmap class loader. * * $loader = new \Composer\Autoload\ClassLoader(); * * // register classes with namespaces * $loader->add('Symfony\Component', __DIR__.'/component'); * $loader->add('Symfony', __DIR__.'/framework'); * * // activate the autoloader * $loader->register(); * * // to enable searching the include path (eg. for PEAR packages) * $loader->setUseIncludePath(true); * * In this example, if you try to use a class in the Symfony\Component * namespace or one of its children (Symfony\Component\Console for instance), * the autoloader will first look for the class under the component/ * directory, and it will then fallback to the framework/ directory if not * found before giving up. * * This class is loosely based on the Symfony UniversalClassLoader. * * @author Fabien Potencier * @author Jordi Boggiano * @see https://www.php-fig.org/psr/psr-0/ * @see https://www.php-fig.org/psr/psr-4/ */ class ClassLoader { /** @var \Closure(string):void */ private static $includeFile; /** @var string|null */ private $vendorDir; // PSR-4 /** * @var array> */ private $prefixLengthsPsr4 = array(); /** * @var array> */ private $prefixDirsPsr4 = array(); /** * @var list */ private $fallbackDirsPsr4 = array(); // PSR-0 /** * List of PSR-0 prefixes * * Structured as array('F (first letter)' => array('Foo\Bar (full prefix)' => array('path', 'path2'))) * * @var array>> */ private $prefixesPsr0 = array(); /** * @var list */ private $fallbackDirsPsr0 = array(); /** @var bool */ private $useIncludePath = false; /** * @var array */ private $classMap = array(); /** @var bool */ private $classMapAuthoritative = false; /** * @var array */ private $missingClasses = array(); /** @var string|null */ private $apcuPrefix; /** * @var array */ private static $registeredLoaders = array(); /** * @param string|null $vendorDir */ public function __construct($vendorDir = null) { $this->vendorDir = $vendorDir; self::initializeIncludeClosure(); } /** * @return array> */ public function getPrefixes() { if (!empty($this->prefixesPsr0)) { return call_user_func_array('array_merge', array_values($this->prefixesPsr0)); } return array(); } /** * @return array> */ public function getPrefixesPsr4() { return $this->prefixDirsPsr4; } /** * @return list */ public function getFallbackDirs() { return $this->fallbackDirsPsr0; } /** * @return list */ public function getFallbackDirsPsr4() { return $this->fallbackDirsPsr4; } /** * @return array Array of classname => path */ public function getClassMap() { return $this->classMap; } /** * @param array $classMap Class to filename map * * @return void */ public function addClassMap(array $classMap) { if ($this->classMap) { $this->classMap = array_merge($this->classMap, $classMap); } else { $this->classMap = $classMap; } } /** * Registers a set of PSR-0 directories for a given prefix, either * appending or prepending to the ones previously set for this prefix. * * @param string $prefix The prefix * @param list|string $paths The PSR-0 root directories * @param bool $prepend Whether to prepend the directories * * @return void */ public function add($prefix, $paths, $prepend = false) { $paths = (array) $paths; if (!$prefix) { if ($prepend) { $this->fallbackDirsPsr0 = array_merge( $paths, $this->fallbackDirsPsr0 ); } else { $this->fallbackDirsPsr0 = array_merge( $this->fallbackDirsPsr0, $paths ); } return; } $first = $prefix[0]; if (!isset($this->prefixesPsr0[$first][$prefix])) { $this->prefixesPsr0[$first][$prefix] = $paths; return; } if ($prepend) { $this->prefixesPsr0[$first][$prefix] = array_merge( $paths, $this->prefixesPsr0[$first][$prefix] ); } else { $this->prefixesPsr0[$first][$prefix] = array_merge( $this->prefixesPsr0[$first][$prefix], $paths ); } } /** * Registers a set of PSR-4 directories for a given namespace, either * appending or prepending to the ones previously set for this namespace. * * @param string $prefix The prefix/namespace, with trailing '\\' * @param list|string $paths The PSR-4 base directories * @param bool $prepend Whether to prepend the directories * * @throws \InvalidArgumentException * * @return void */ public function addPsr4($prefix, $paths, $prepend = false) { $paths = (array) $paths; if (!$prefix) { // Register directories for the root namespace. if ($prepend) { $this->fallbackDirsPsr4 = array_merge( $paths, $this->fallbackDirsPsr4 ); } else { $this->fallbackDirsPsr4 = array_merge( $this->fallbackDirsPsr4, $paths ); } } elseif (!isset($this->prefixDirsPsr4[$prefix])) { // Register directories for a new namespace. $length = strlen($prefix); if ('\\' !== $prefix[$length - 1]) { throw new \InvalidArgumentException("A non-empty PSR-4 prefix must end with a namespace separator."); } $this->prefixLengthsPsr4[$prefix[0]][$prefix] = $length; $this->prefixDirsPsr4[$prefix] = $paths; } elseif ($prepend) { // Prepend directories for an already registered namespace. $this->prefixDirsPsr4[$prefix] = array_merge( $paths, $this->prefixDirsPsr4[$prefix] ); } else { // Append directories for an already registered namespace. $this->prefixDirsPsr4[$prefix] = array_merge( $this->prefixDirsPsr4[$prefix], $paths ); } } /** * Registers a set of PSR-0 directories for a given prefix, * replacing any others previously set for this prefix. * * @param string $prefix The prefix * @param list|string $paths The PSR-0 base directories * * @return void */ public function set($prefix, $paths) { if (!$prefix) { $this->fallbackDirsPsr0 = (array) $paths; } else { $this->prefixesPsr0[$prefix[0]][$prefix] = (array) $paths; } } /** * Registers a set of PSR-4 directories for a given namespace, * replacing any others previously set for this namespace. * * @param string $prefix The prefix/namespace, with trailing '\\' * @param list|string $paths The PSR-4 base directories * * @throws \InvalidArgumentException * * @return void */ public function setPsr4($prefix, $paths) { if (!$prefix) { $this->fallbackDirsPsr4 = (array) $paths; } else { $length = strlen($prefix); if ('\\' !== $prefix[$length - 1]) { throw new \InvalidArgumentException("A non-empty PSR-4 prefix must end with a namespace separator."); } $this->prefixLengthsPsr4[$prefix[0]][$prefix] = $length; $this->prefixDirsPsr4[$prefix] = (array) $paths; } } /** * Turns on searching the include path for class files. * * @param bool $useIncludePath * * @return void */ public function setUseIncludePath($useIncludePath) { $this->useIncludePath = $useIncludePath; } /** * Can be used to check if the autoloader uses the include path to check * for classes. * * @return bool */ public function getUseIncludePath() { return $this->useIncludePath; } /** * Turns off searching the prefix and fallback directories for classes * that have not been registered with the class map. * * @param bool $classMapAuthoritative * * @return void */ public function setClassMapAuthoritative($classMapAuthoritative) { $this->classMapAuthoritative = $classMapAuthoritative; } /** * Should class lookup fail if not found in the current class map? * * @return bool */ public function isClassMapAuthoritative() { return $this->classMapAuthoritative; } /** * APCu prefix to use to cache found/not-found classes, if the extension is enabled. * * @param string|null $apcuPrefix * * @return void */ public function setApcuPrefix($apcuPrefix) { $this->apcuPrefix = function_exists('apcu_fetch') && filter_var(ini_get('apc.enabled'), FILTER_VALIDATE_BOOLEAN) ? $apcuPrefix : null; } /** * The APCu prefix in use, or null if APCu caching is not enabled. * * @return string|null */ public function getApcuPrefix() { return $this->apcuPrefix; } /** * Registers this instance as an autoloader. * * @param bool $prepend Whether to prepend the autoloader or not * * @return void */ public function register($prepend = false) { spl_autoload_register(array($this, 'loadClass'), true, $prepend); if (null === $this->vendorDir) { return; } if ($prepend) { self::$registeredLoaders = array($this->vendorDir => $this) + self::$registeredLoaders; } else { unset(self::$registeredLoaders[$this->vendorDir]); self::$registeredLoaders[$this->vendorDir] = $this; } } /** * Unregisters this instance as an autoloader. * * @return void */ public function unregister() { spl_autoload_unregister(array($this, 'loadClass')); if (null !== $this->vendorDir) { unset(self::$registeredLoaders[$this->vendorDir]); } } /** * Loads the given class or interface. * * @param string $class The name of the class * @return true|null True if loaded, null otherwise */ public function loadClass($class) { if ($file = $this->findFile($class)) { $includeFile = self::$includeFile; $includeFile($file); return true; } return null; } /** * Finds the path to the file where the class is defined. * * @param string $class The name of the class * * @return string|false The path if found, false otherwise */ public function findFile($class) { // class map lookup if (isset($this->classMap[$class])) { return $this->classMap[$class]; } if ($this->classMapAuthoritative || isset($this->missingClasses[$class])) { return false; } if (null !== $this->apcuPrefix) { $file = apcu_fetch($this->apcuPrefix.$class, $hit); if ($hit) { return $file; } } $file = $this->findFileWithExtension($class, '.php'); // Search for Hack files if we are running on HHVM if (false === $file && defined('HHVM_VERSION')) { $file = $this->findFileWithExtension($class, '.hh'); } if (null !== $this->apcuPrefix) { apcu_add($this->apcuPrefix.$class, $file); } if (false === $file) { // Remember that this class does not exist. $this->missingClasses[$class] = true; } return $file; } /** * Returns the currently registered loaders keyed by their corresponding vendor directories. * * @return array */ public static function getRegisteredLoaders() { return self::$registeredLoaders; } /** * @param string $class * @param string $ext * @return string|false */ private function findFileWithExtension($class, $ext) { // PSR-4 lookup $logicalPathPsr4 = strtr($class, '\\', DIRECTORY_SEPARATOR) . $ext; $first = $class[0]; if (isset($this->prefixLengthsPsr4[$first])) { $subPath = $class; while (false !== $lastPos = strrpos($subPath, '\\')) { $subPath = substr($subPath, 0, $lastPos); $search = $subPath . '\\'; if (isset($this->prefixDirsPsr4[$search])) { $pathEnd = DIRECTORY_SEPARATOR . substr($logicalPathPsr4, $lastPos + 1); foreach ($this->prefixDirsPsr4[$search] as $dir) { if (file_exists($file = $dir . $pathEnd)) { return $file; } } } } } // PSR-4 fallback dirs foreach ($this->fallbackDirsPsr4 as $dir) { if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr4)) { return $file; } } // PSR-0 lookup if (false !== $pos = strrpos($class, '\\')) { // namespaced class name $logicalPathPsr0 = substr($logicalPathPsr4, 0, $pos + 1) . strtr(substr($logicalPathPsr4, $pos + 1), '_', DIRECTORY_SEPARATOR); } else { // PEAR-like class name $logicalPathPsr0 = strtr($class, '_', DIRECTORY_SEPARATOR) . $ext; } if (isset($this->prefixesPsr0[$first])) { foreach ($this->prefixesPsr0[$first] as $prefix => $dirs) { if (0 === strpos($class, $prefix)) { foreach ($dirs as $dir) { if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr0)) { return $file; } } } } } // PSR-0 fallback dirs foreach ($this->fallbackDirsPsr0 as $dir) { if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr0)) { return $file; } } // PSR-0 include paths. if ($this->useIncludePath && $file = stream_resolve_include_path($logicalPathPsr0)) { return $file; } return false; } /** * @return void */ private static function initializeIncludeClosure() { if (self::$includeFile !== null) { return; } /** * Scope isolated include. * * Prevents access to $this/self from included files. * * @param string $file * @return void */ self::$includeFile = \Closure::bind(static function($file) { include $file; }, null, null); } } setClassMapAuthoritative(true); $loader->register(true); $filesToLoad = \Composer\Autoload\ComposerStaticInitdffbc805a242803aefef6b513be4e6ec::$files; $requireFile = \Closure::bind(static function ($fileIdentifier, $file) { if (empty($GLOBALS['__composer_autoload_files'][$fileIdentifier])) { $GLOBALS['__composer_autoload_files'][$fileIdentifier] = true; require $file; } }, null, null); foreach ($filesToLoad as $fileIdentifier => $file) { $requireFile($fileIdentifier, $file); } return $loader; } } = 70400)) { $issues[] = 'Your Composer dependencies require a PHP version ">= 7.4.0". You are running ' . PHP_VERSION . '.'; } $missingExtensions = array(); extension_loaded('dom') || $missingExtensions[] = 'dom'; extension_loaded('filter') || $missingExtensions[] = 'filter'; extension_loaded('json') || $missingExtensions[] = 'json'; extension_loaded('libxml') || $missingExtensions[] = 'libxml'; extension_loaded('pcre') || $missingExtensions[] = 'pcre'; extension_loaded('reflection') || $missingExtensions[] = 'reflection'; extension_loaded('simplexml') || $missingExtensions[] = 'simplexml'; extension_loaded('spl') || $missingExtensions[] = 'spl'; extension_loaded('tokenizer') || $missingExtensions[] = 'tokenizer'; if ($missingExtensions) { $issues[] = 'Your Composer dependencies require the following PHP extensions to be installed: ' . implode(', ', $missingExtensions) . '.'; } if ($issues) { if (!headers_sent()) { header('HTTP/1.1 500 Internal Server Error'); } if (!ini_get('display_errors')) { if (PHP_SAPI === 'cli' || PHP_SAPI === 'phpdbg') { fwrite(STDERR, 'Composer detected issues in your platform:' . PHP_EOL.PHP_EOL . implode(PHP_EOL, $issues) . PHP_EOL.PHP_EOL); } elseif (!headers_sent()) { echo 'Composer detected issues in your platform:' . PHP_EOL.PHP_EOL . str_replace('You are running '.PHP_VERSION.'.', '', implode(PHP_EOL, $issues)) . PHP_EOL.PHP_EOL; } } trigger_error( 'Composer detected issues in your platform: ' . implode(' ', $issues), E_USER_ERROR ); } __DIR__ . '/..' . '/symfony/polyfill-mbstring/bootstrap.php', 'a4a119a56e50fbb293281d9a48007e0e' => __DIR__ . '/..' . '/symfony/polyfill-php80/bootstrap.php', '6e3fae29631ef280660b3cdad06f25a8' => __DIR__ . '/..' . '/symfony/deprecation-contracts/function.php', '320cde22f66dd4f5d3fd621d3e88b98f' => __DIR__ . '/..' . '/symfony/polyfill-ctype/bootstrap.php', '8825ede83f2f289127722d4e842cf7e8' => __DIR__ . '/..' . '/symfony/polyfill-intl-grapheme/bootstrap.php', 'e69f7f6ee287b969198c3c9d6777bd38' => __DIR__ . '/..' . '/symfony/polyfill-intl-normalizer/bootstrap.php', 'e8aa6e4b5a1db2f56ae794f1505391a8' => __DIR__ . '/..' . '/amphp/amp/lib/functions.php', '76cd0796156622033397994f25b0d8fc' => __DIR__ . '/..' . '/amphp/amp/lib/Internal/functions.php', '0d59ee240a4cd96ddbb4ff164fccea4d' => __DIR__ . '/..' . '/symfony/polyfill-php73/bootstrap.php', 'b6b991a57620e2fb6b2f66f03fe9ddc2' => __DIR__ . '/..' . '/symfony/string/Resources/functions.php', '6cd5651c4fef5ed6b63e8d8b8ffbf3cc' => __DIR__ . '/..' . '/amphp/byte-stream/lib/functions.php', ); public static $prefixLengthsPsr4 = array ( '_' => array ( '_HumbugBox7ff99e199a36\\phpDocumentor\\Reflection\\' => 48, '_HumbugBox7ff99e199a36\\XdgBaseDir\\' => 34, '_HumbugBox7ff99e199a36\\Webmozart\\Assert\\' => 40, '_HumbugBox7ff99e199a36\\Symfony\\Polyfill\\Php80\\' => 46, '_HumbugBox7ff99e199a36\\Symfony\\Polyfill\\Php73\\' => 46, '_HumbugBox7ff99e199a36\\Symfony\\Polyfill\\Mbstring\\' => 49, '_HumbugBox7ff99e199a36\\Symfony\\Polyfill\\Intl\\Normalizer\\' => 56, '_HumbugBox7ff99e199a36\\Symfony\\Polyfill\\Intl\\Grapheme\\' => 54, '_HumbugBox7ff99e199a36\\Symfony\\Polyfill\\Ctype\\' => 46, '_HumbugBox7ff99e199a36\\Symfony\\Contracts\\Service\\' => 49, '_HumbugBox7ff99e199a36\\Symfony\\Component\\String\\' => 48, '_HumbugBox7ff99e199a36\\Symfony\\Component\\Filesystem\\' => 52, '_HumbugBox7ff99e199a36\\Symfony\\Component\\Console\\' => 49, '_HumbugBox7ff99e199a36\\Spatie\\ArrayToXml\\' => 41, '_HumbugBox7ff99e199a36\\Psr\\Log\\' => 31, '_HumbugBox7ff99e199a36\\Psr\\Container\\' => 37, '_HumbugBox7ff99e199a36\\PhpParser\\' => 33, '_HumbugBox7ff99e199a36\\PHPStan\\PhpDocParser\\' => 44, '_HumbugBox7ff99e199a36\\LanguageServerProtocol\\' => 46, '_HumbugBox7ff99e199a36\\JsonMapper\\' => 34, '_HumbugBox7ff99e199a36\\Fidry\\CpuCoreCounter\\' => 44, '_HumbugBox7ff99e199a36\\Doctrine\\Deprecations\\' => 45, '_HumbugBox7ff99e199a36\\Composer\\XdebugHandler\\' => 46, '_HumbugBox7ff99e199a36\\Composer\\Semver\\' => 39, '_HumbugBox7ff99e199a36\\Composer\\Pcre\\' => 37, '_HumbugBox7ff99e199a36\\Amp\\ByteStream\\' => 38, '_HumbugBox7ff99e199a36\\Amp\\' => 27, '_HumbugBox7ff99e199a36\\AdvancedJsonRpc\\' => 39, ), 'P' => array ( 'Psalm\\' => 6, ), ); public static $prefixDirsPsr4 = array ( '_HumbugBox7ff99e199a36\\phpDocumentor\\Reflection\\' => array ( 0 => __DIR__ . '/..' . '/phpdocumentor/reflection-common/src', 1 => __DIR__ . '/..' . '/phpdocumentor/reflection-docblock/src', 2 => __DIR__ . '/..' . '/phpdocumentor/type-resolver/src', ), '_HumbugBox7ff99e199a36\\XdgBaseDir\\' => array ( 0 => __DIR__ . '/..' . '/dnoegel/php-xdg-base-dir/src', ), '_HumbugBox7ff99e199a36\\Webmozart\\Assert\\' => array ( 0 => __DIR__ . '/..' . '/webmozart/assert/src', ), '_HumbugBox7ff99e199a36\\Symfony\\Polyfill\\Php80\\' => array ( 0 => __DIR__ . '/..' . '/symfony/polyfill-php80', ), '_HumbugBox7ff99e199a36\\Symfony\\Polyfill\\Php73\\' => array ( 0 => __DIR__ . '/..' . '/symfony/polyfill-php73', ), '_HumbugBox7ff99e199a36\\Symfony\\Polyfill\\Mbstring\\' => array ( 0 => __DIR__ . '/..' . '/symfony/polyfill-mbstring', ), '_HumbugBox7ff99e199a36\\Symfony\\Polyfill\\Intl\\Normalizer\\' => array ( 0 => __DIR__ . '/..' . '/symfony/polyfill-intl-normalizer', ), '_HumbugBox7ff99e199a36\\Symfony\\Polyfill\\Intl\\Grapheme\\' => array ( 0 => __DIR__ . '/..' . '/symfony/polyfill-intl-grapheme', ), '_HumbugBox7ff99e199a36\\Symfony\\Polyfill\\Ctype\\' => array ( 0 => __DIR__ . '/..' . '/symfony/polyfill-ctype', ), '_HumbugBox7ff99e199a36\\Symfony\\Contracts\\Service\\' => array ( 0 => __DIR__ . '/..' . '/symfony/service-contracts', ), '_HumbugBox7ff99e199a36\\Symfony\\Component\\String\\' => array ( 0 => __DIR__ . '/..' . '/symfony/string', ), '_HumbugBox7ff99e199a36\\Symfony\\Component\\Filesystem\\' => array ( 0 => __DIR__ . '/..' . '/symfony/filesystem', ), '_HumbugBox7ff99e199a36\\Symfony\\Component\\Console\\' => array ( 0 => __DIR__ . '/..' . '/symfony/console', ), '_HumbugBox7ff99e199a36\\Spatie\\ArrayToXml\\' => array ( 0 => __DIR__ . '/..' . '/spatie/array-to-xml/src', ), '_HumbugBox7ff99e199a36\\Psr\\Log\\' => array ( 0 => __DIR__ . '/..' . '/psr/log/Psr/Log', ), '_HumbugBox7ff99e199a36\\Psr\\Container\\' => array ( 0 => __DIR__ . '/..' . '/psr/container/src', ), '_HumbugBox7ff99e199a36\\PhpParser\\' => array ( 0 => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser', ), '_HumbugBox7ff99e199a36\\PHPStan\\PhpDocParser\\' => array ( 0 => __DIR__ . '/..' . '/phpstan/phpdoc-parser/src', ), '_HumbugBox7ff99e199a36\\LanguageServerProtocol\\' => array ( 0 => __DIR__ . '/..' . '/felixfbecker/language-server-protocol/src', ), '_HumbugBox7ff99e199a36\\JsonMapper\\' => array ( 0 => __DIR__ . '/..' . '/netresearch/jsonmapper/src/JsonMapper', ), '_HumbugBox7ff99e199a36\\Fidry\\CpuCoreCounter\\' => array ( 0 => __DIR__ . '/..' . '/fidry/cpu-core-counter/src', ), '_HumbugBox7ff99e199a36\\Doctrine\\Deprecations\\' => array ( 0 => __DIR__ . '/..' . '/doctrine/deprecations/lib/Doctrine/Deprecations', ), '_HumbugBox7ff99e199a36\\Composer\\XdebugHandler\\' => array ( 0 => __DIR__ . '/..' . '/composer/xdebug-handler/src', ), '_HumbugBox7ff99e199a36\\Composer\\Semver\\' => array ( 0 => __DIR__ . '/..' . '/composer/semver/src', ), '_HumbugBox7ff99e199a36\\Composer\\Pcre\\' => array ( 0 => __DIR__ . '/..' . '/composer/pcre/src', ), '_HumbugBox7ff99e199a36\\Amp\\ByteStream\\' => array ( 0 => __DIR__ . '/..' . '/amphp/byte-stream/lib', ), '_HumbugBox7ff99e199a36\\Amp\\' => array ( 0 => __DIR__ . '/..' . '/amphp/amp/lib', ), '_HumbugBox7ff99e199a36\\AdvancedJsonRpc\\' => array ( 0 => __DIR__ . '/..' . '/felixfbecker/advanced-json-rpc/lib', ), 'Psalm\\' => array ( 0 => __DIR__ . '/../..' . '/src/Psalm', ), ); public static $classMap = array ( 'Attribute' => __DIR__ . '/..' . '/symfony/polyfill-php80/Resources/stubs/Attribute.php', 'Composer\\InstalledVersions' => __DIR__ . '/..' . '/composer/InstalledVersions.php', 'PhpToken' => __DIR__ . '/..' . '/symfony/polyfill-php80/Resources/stubs/PhpToken.php', 'Psalm\\Aliases' => __DIR__ . '/../..' . '/src/Psalm/Aliases.php', 'Psalm\\CodeLocation' => __DIR__ . '/../..' . '/src/Psalm/CodeLocation.php', 'Psalm\\CodeLocation\\DocblockTypeLocation' => __DIR__ . '/../..' . '/src/Psalm/CodeLocation/DocblockTypeLocation.php', 'Psalm\\CodeLocation\\ParseErrorLocation' => __DIR__ . '/../..' . '/src/Psalm/CodeLocation/ParseErrorLocation.php', 'Psalm\\CodeLocation\\Raw' => __DIR__ . '/../..' . '/src/Psalm/CodeLocation/Raw.php', 'Psalm\\Codebase' => __DIR__ . '/../..' . '/src/Psalm/Codebase.php', 'Psalm\\Config' => __DIR__ . '/../..' . '/src/Psalm/Config.php', 'Psalm\\Config\\Creator' => __DIR__ . '/../..' . '/src/Psalm/Config/Creator.php', 'Psalm\\Config\\ErrorLevelFileFilter' => __DIR__ . '/../..' . '/src/Psalm/Config/ErrorLevelFileFilter.php', 'Psalm\\Config\\FileFilter' => __DIR__ . '/../..' . '/src/Psalm/Config/FileFilter.php', 'Psalm\\Config\\IssueHandler' => __DIR__ . '/../..' . '/src/Psalm/Config/IssueHandler.php', 'Psalm\\Config\\ProjectFileFilter' => __DIR__ . '/../..' . '/src/Psalm/Config/ProjectFileFilter.php', 'Psalm\\Config\\TaintAnalysisFileFilter' => __DIR__ . '/../..' . '/src/Psalm/Config/TaintAnalysisFileFilter.php', 'Psalm\\Context' => __DIR__ . '/../..' . '/src/Psalm/Context.php', 'Psalm\\DocComment' => __DIR__ . '/../..' . '/src/Psalm/DocComment.php', 'Psalm\\ErrorBaseline' => __DIR__ . '/../..' . '/src/Psalm/ErrorBaseline.php', 'Psalm\\Exception\\CircularReferenceException' => __DIR__ . '/../..' . '/src/Psalm/Exception/CircularReferenceException.php', 'Psalm\\Exception\\CodeException' => __DIR__ . '/../..' . '/src/Psalm/Exception/CodeException.php', 'Psalm\\Exception\\ComplicatedExpressionException' => __DIR__ . '/../..' . '/src/Psalm/Exception/ComplicatedExpressionException.php', 'Psalm\\Exception\\ConfigCreationException' => __DIR__ . '/../..' . '/src/Psalm/Exception/ConfigCreationException.php', 'Psalm\\Exception\\ConfigException' => __DIR__ . '/../..' . '/src/Psalm/Exception/ConfigException.php', 'Psalm\\Exception\\ConfigNotFoundException' => __DIR__ . '/../..' . '/src/Psalm/Exception/ConfigNotFoundException.php', 'Psalm\\Exception\\DocblockParseException' => __DIR__ . '/../..' . '/src/Psalm/Exception/DocblockParseException.php', 'Psalm\\Exception\\FileIncludeException' => __DIR__ . '/../..' . '/src/Psalm/Exception/FileIncludeException.php', 'Psalm\\Exception\\IncorrectDocblockException' => __DIR__ . '/../..' . '/src/Psalm/Exception/IncorrectDocblockException.php', 'Psalm\\Exception\\InvalidClasslikeOverrideException' => __DIR__ . '/../..' . '/src/Psalm/Exception/InvalidClasslikeOverrideException.php', 'Psalm\\Exception\\InvalidMethodOverrideException' => __DIR__ . '/../..' . '/src/Psalm/Exception/InvalidMethodOverrideException.php', 'Psalm\\Exception\\RefactorException' => __DIR__ . '/../..' . '/src/Psalm/Exception/RefactorException.php', 'Psalm\\Exception\\ScopeAnalysisException' => __DIR__ . '/../..' . '/src/Psalm/Exception/ScopeAnalysisException.php', 'Psalm\\Exception\\TypeParseTreeException' => __DIR__ . '/../..' . '/src/Psalm/Exception/TypeParseTreeException.php', 'Psalm\\Exception\\UnanalyzedFileException' => __DIR__ . '/../..' . '/src/Psalm/Exception/UnanalyzedFileException.php', 'Psalm\\Exception\\UnpopulatedClasslikeException' => __DIR__ . '/../..' . '/src/Psalm/Exception/UnpopulatedClasslikeException.php', 'Psalm\\Exception\\UnpreparedAnalysisException' => __DIR__ . '/../..' . '/src/Psalm/Exception/UnpreparedAnalysisException.php', 'Psalm\\Exception\\UnresolvableConstantException' => __DIR__ . '/../..' . '/src/Psalm/Exception/UnresolvableConstantException.php', 'Psalm\\Exception\\UnsupportedIssueToFixException' => __DIR__ . '/../..' . '/src/Psalm/Exception/UnsupportedIssueToFixException.php', 'Psalm\\FileBasedPluginAdapter' => __DIR__ . '/../..' . '/src/Psalm/FileBasedPluginAdapter.php', 'Psalm\\FileManipulation' => __DIR__ . '/../..' . '/src/Psalm/FileManipulation.php', 'Psalm\\FileSource' => __DIR__ . '/../..' . '/src/Psalm/FileSource.php', 'Psalm\\Internal\\Algebra' => __DIR__ . '/../..' . '/src/Psalm/Internal/Algebra.php', 'Psalm\\Internal\\Algebra\\FormulaGenerator' => __DIR__ . '/../..' . '/src/Psalm/Internal/Algebra/FormulaGenerator.php', 'Psalm\\Internal\\Analyzer\\AlgebraAnalyzer' => __DIR__ . '/../..' . '/src/Psalm/Internal/Analyzer/AlgebraAnalyzer.php', 'Psalm\\Internal\\Analyzer\\AttributesAnalyzer' => __DIR__ . '/../..' . '/src/Psalm/Internal/Analyzer/AttributesAnalyzer.php', 'Psalm\\Internal\\Analyzer\\CanAlias' => __DIR__ . '/../..' . '/src/Psalm/Internal/Analyzer/CanAlias.php', 'Psalm\\Internal\\Analyzer\\ClassAnalyzer' => __DIR__ . '/../..' . '/src/Psalm/Internal/Analyzer/ClassAnalyzer.php', 'Psalm\\Internal\\Analyzer\\ClassLikeAnalyzer' => __DIR__ . '/../..' . '/src/Psalm/Internal/Analyzer/ClassLikeAnalyzer.php', 'Psalm\\Internal\\Analyzer\\ClassLikeNameOptions' => __DIR__ . '/../..' . '/src/Psalm/Internal/Analyzer/ClassLikeNameOptions.php', 'Psalm\\Internal\\Analyzer\\ClosureAnalyzer' => __DIR__ . '/../..' . '/src/Psalm/Internal/Analyzer/ClosureAnalyzer.php', 'Psalm\\Internal\\Analyzer\\CommentAnalyzer' => __DIR__ . '/../..' . '/src/Psalm/Internal/Analyzer/CommentAnalyzer.php', 'Psalm\\Internal\\Analyzer\\DataFlowNodeData' => __DIR__ . '/../..' . '/src/Psalm/Internal/Analyzer/DataFlowNodeData.php', 'Psalm\\Internal\\Analyzer\\FileAnalyzer' => __DIR__ . '/../..' . '/src/Psalm/Internal/Analyzer/FileAnalyzer.php', 'Psalm\\Internal\\Analyzer\\FunctionAnalyzer' => __DIR__ . '/../..' . '/src/Psalm/Internal/Analyzer/FunctionAnalyzer.php', 'Psalm\\Internal\\Analyzer\\FunctionLikeAnalyzer' => __DIR__ . '/../..' . '/src/Psalm/Internal/Analyzer/FunctionLikeAnalyzer.php', 'Psalm\\Internal\\Analyzer\\FunctionLike\\ReturnTypeAnalyzer' => __DIR__ . '/../..' . '/src/Psalm/Internal/Analyzer/FunctionLike/ReturnTypeAnalyzer.php', 'Psalm\\Internal\\Analyzer\\FunctionLike\\ReturnTypeCollector' => __DIR__ . '/../..' . '/src/Psalm/Internal/Analyzer/FunctionLike/ReturnTypeCollector.php', 'Psalm\\Internal\\Analyzer\\InterfaceAnalyzer' => __DIR__ . '/../..' . '/src/Psalm/Internal/Analyzer/InterfaceAnalyzer.php', 'Psalm\\Internal\\Analyzer\\IssueData' => __DIR__ . '/../..' . '/src/Psalm/Internal/Analyzer/IssueData.php', 'Psalm\\Internal\\Analyzer\\MethodAnalyzer' => __DIR__ . '/../..' . '/src/Psalm/Internal/Analyzer/MethodAnalyzer.php', 'Psalm\\Internal\\Analyzer\\MethodComparator' => __DIR__ . '/../..' . '/src/Psalm/Internal/Analyzer/MethodComparator.php', 'Psalm\\Internal\\Analyzer\\NamespaceAnalyzer' => __DIR__ . '/../..' . '/src/Psalm/Internal/Analyzer/NamespaceAnalyzer.php', 'Psalm\\Internal\\Analyzer\\ProjectAnalyzer' => __DIR__ . '/../..' . '/src/Psalm/Internal/Analyzer/ProjectAnalyzer.php', 'Psalm\\Internal\\Analyzer\\ScopeAnalyzer' => __DIR__ . '/../..' . '/src/Psalm/Internal/Analyzer/ScopeAnalyzer.php', 'Psalm\\Internal\\Analyzer\\SourceAnalyzer' => __DIR__ . '/../..' . '/src/Psalm/Internal/Analyzer/SourceAnalyzer.php', 'Psalm\\Internal\\Analyzer\\StatementsAnalyzer' => __DIR__ . '/../..' . '/src/Psalm/Internal/Analyzer/StatementsAnalyzer.php', 'Psalm\\Internal\\Analyzer\\Statements\\Block\\DoAnalyzer' => __DIR__ . '/../..' . '/src/Psalm/Internal/Analyzer/Statements/Block/DoAnalyzer.php', 'Psalm\\Internal\\Analyzer\\Statements\\Block\\ForAnalyzer' => __DIR__ . '/../..' . '/src/Psalm/Internal/Analyzer/Statements/Block/ForAnalyzer.php', 'Psalm\\Internal\\Analyzer\\Statements\\Block\\ForeachAnalyzer' => __DIR__ . '/../..' . '/src/Psalm/Internal/Analyzer/Statements/Block/ForeachAnalyzer.php', 'Psalm\\Internal\\Analyzer\\Statements\\Block\\IfConditionalAnalyzer' => __DIR__ . '/../..' . '/src/Psalm/Internal/Analyzer/Statements/Block/IfConditionalAnalyzer.php', 'Psalm\\Internal\\Analyzer\\Statements\\Block\\IfElseAnalyzer' => __DIR__ . '/../..' . '/src/Psalm/Internal/Analyzer/Statements/Block/IfElseAnalyzer.php', 'Psalm\\Internal\\Analyzer\\Statements\\Block\\IfElse\\ElseAnalyzer' => __DIR__ . '/../..' . '/src/Psalm/Internal/Analyzer/Statements/Block/IfElse/ElseAnalyzer.php', 'Psalm\\Internal\\Analyzer\\Statements\\Block\\IfElse\\ElseIfAnalyzer' => __DIR__ . '/../..' . '/src/Psalm/Internal/Analyzer/Statements/Block/IfElse/ElseIfAnalyzer.php', 'Psalm\\Internal\\Analyzer\\Statements\\Block\\IfElse\\IfAnalyzer' => __DIR__ . '/../..' . '/src/Psalm/Internal/Analyzer/Statements/Block/IfElse/IfAnalyzer.php', 'Psalm\\Internal\\Analyzer\\Statements\\Block\\LoopAnalyzer' => __DIR__ . '/../..' . '/src/Psalm/Internal/Analyzer/Statements/Block/LoopAnalyzer.php', 'Psalm\\Internal\\Analyzer\\Statements\\Block\\SwitchAnalyzer' => __DIR__ . '/../..' . '/src/Psalm/Internal/Analyzer/Statements/Block/SwitchAnalyzer.php', 'Psalm\\Internal\\Analyzer\\Statements\\Block\\SwitchCaseAnalyzer' => __DIR__ . '/../..' . '/src/Psalm/Internal/Analyzer/Statements/Block/SwitchCaseAnalyzer.php', 'Psalm\\Internal\\Analyzer\\Statements\\Block\\TryAnalyzer' => __DIR__ . '/../..' . '/src/Psalm/Internal/Analyzer/Statements/Block/TryAnalyzer.php', 'Psalm\\Internal\\Analyzer\\Statements\\Block\\WhileAnalyzer' => __DIR__ . '/../..' . '/src/Psalm/Internal/Analyzer/Statements/Block/WhileAnalyzer.php', 'Psalm\\Internal\\Analyzer\\Statements\\BreakAnalyzer' => __DIR__ . '/../..' . '/src/Psalm/Internal/Analyzer/Statements/BreakAnalyzer.php', 'Psalm\\Internal\\Analyzer\\Statements\\ContinueAnalyzer' => __DIR__ . '/../..' . '/src/Psalm/Internal/Analyzer/Statements/ContinueAnalyzer.php', 'Psalm\\Internal\\Analyzer\\Statements\\DeclareAnalyzer' => __DIR__ . '/../..' . '/src/Psalm/Internal/Analyzer/Statements/DeclareAnalyzer.php', 'Psalm\\Internal\\Analyzer\\Statements\\EchoAnalyzer' => __DIR__ . '/../..' . '/src/Psalm/Internal/Analyzer/Statements/EchoAnalyzer.php', 'Psalm\\Internal\\Analyzer\\Statements\\ExpressionAnalyzer' => __DIR__ . '/../..' . '/src/Psalm/Internal/Analyzer/Statements/ExpressionAnalyzer.php', 'Psalm\\Internal\\Analyzer\\Statements\\Expression\\ArrayAnalyzer' => __DIR__ . '/../..' . '/src/Psalm/Internal/Analyzer/Statements/Expression/ArrayAnalyzer.php', 'Psalm\\Internal\\Analyzer\\Statements\\Expression\\ArrayCreationInfo' => __DIR__ . '/../..' . '/src/Psalm/Internal/Analyzer/Statements/Expression/ArrayCreationInfo.php', 'Psalm\\Internal\\Analyzer\\Statements\\Expression\\AssertionFinder' => __DIR__ . '/../..' . '/src/Psalm/Internal/Analyzer/Statements/Expression/AssertionFinder.php', 'Psalm\\Internal\\Analyzer\\Statements\\Expression\\AssignmentAnalyzer' => __DIR__ . '/../..' . '/src/Psalm/Internal/Analyzer/Statements/Expression/AssignmentAnalyzer.php', 'Psalm\\Internal\\Analyzer\\Statements\\Expression\\Assignment\\ArrayAssignmentAnalyzer' => __DIR__ . '/../..' . '/src/Psalm/Internal/Analyzer/Statements/Expression/Assignment/ArrayAssignmentAnalyzer.php', 'Psalm\\Internal\\Analyzer\\Statements\\Expression\\Assignment\\AssignedProperty' => __DIR__ . '/../..' . '/src/Psalm/Internal/Analyzer/Statements/Expression/Assignment/AssignedProperty.php', 'Psalm\\Internal\\Analyzer\\Statements\\Expression\\Assignment\\InstancePropertyAssignmentAnalyzer' => __DIR__ . '/../..' . '/src/Psalm/Internal/Analyzer/Statements/Expression/Assignment/InstancePropertyAssignmentAnalyzer.php', 'Psalm\\Internal\\Analyzer\\Statements\\Expression\\Assignment\\StaticPropertyAssignmentAnalyzer' => __DIR__ . '/../..' . '/src/Psalm/Internal/Analyzer/Statements/Expression/Assignment/StaticPropertyAssignmentAnalyzer.php', 'Psalm\\Internal\\Analyzer\\Statements\\Expression\\BinaryOpAnalyzer' => __DIR__ . '/../..' . '/src/Psalm/Internal/Analyzer/Statements/Expression/BinaryOpAnalyzer.php', 'Psalm\\Internal\\Analyzer\\Statements\\Expression\\BinaryOp\\AndAnalyzer' => __DIR__ . '/../..' . '/src/Psalm/Internal/Analyzer/Statements/Expression/BinaryOp/AndAnalyzer.php', 'Psalm\\Internal\\Analyzer\\Statements\\Expression\\BinaryOp\\ArithmeticOpAnalyzer' => __DIR__ . '/../..' . '/src/Psalm/Internal/Analyzer/Statements/Expression/BinaryOp/ArithmeticOpAnalyzer.php', 'Psalm\\Internal\\Analyzer\\Statements\\Expression\\BinaryOp\\CoalesceAnalyzer' => __DIR__ . '/../..' . '/src/Psalm/Internal/Analyzer/Statements/Expression/BinaryOp/CoalesceAnalyzer.php', 'Psalm\\Internal\\Analyzer\\Statements\\Expression\\BinaryOp\\ConcatAnalyzer' => __DIR__ . '/../..' . '/src/Psalm/Internal/Analyzer/Statements/Expression/BinaryOp/ConcatAnalyzer.php', 'Psalm\\Internal\\Analyzer\\Statements\\Expression\\BinaryOp\\NonComparisonOpAnalyzer' => __DIR__ . '/../..' . '/src/Psalm/Internal/Analyzer/Statements/Expression/BinaryOp/NonComparisonOpAnalyzer.php', 'Psalm\\Internal\\Analyzer\\Statements\\Expression\\BinaryOp\\OrAnalyzer' => __DIR__ . '/../..' . '/src/Psalm/Internal/Analyzer/Statements/Expression/BinaryOp/OrAnalyzer.php', 'Psalm\\Internal\\Analyzer\\Statements\\Expression\\BitwiseNotAnalyzer' => __DIR__ . '/../..' . '/src/Psalm/Internal/Analyzer/Statements/Expression/BitwiseNotAnalyzer.php', 'Psalm\\Internal\\Analyzer\\Statements\\Expression\\BooleanNotAnalyzer' => __DIR__ . '/../..' . '/src/Psalm/Internal/Analyzer/Statements/Expression/BooleanNotAnalyzer.php', 'Psalm\\Internal\\Analyzer\\Statements\\Expression\\CallAnalyzer' => __DIR__ . '/../..' . '/src/Psalm/Internal/Analyzer/Statements/Expression/CallAnalyzer.php', 'Psalm\\Internal\\Analyzer\\Statements\\Expression\\Call\\ArgumentAnalyzer' => __DIR__ . '/../..' . '/src/Psalm/Internal/Analyzer/Statements/Expression/Call/ArgumentAnalyzer.php', 'Psalm\\Internal\\Analyzer\\Statements\\Expression\\Call\\ArgumentMapPopulator' => __DIR__ . '/../..' . '/src/Psalm/Internal/Analyzer/Statements/Expression/Call/ArgumentMapPopulator.php', 'Psalm\\Internal\\Analyzer\\Statements\\Expression\\Call\\ArgumentsAnalyzer' => __DIR__ . '/../..' . '/src/Psalm/Internal/Analyzer/Statements/Expression/Call/ArgumentsAnalyzer.php', 'Psalm\\Internal\\Analyzer\\Statements\\Expression\\Call\\ArrayFunctionArgumentsAnalyzer' => __DIR__ . '/../..' . '/src/Psalm/Internal/Analyzer/Statements/Expression/Call/ArrayFunctionArgumentsAnalyzer.php', 'Psalm\\Internal\\Analyzer\\Statements\\Expression\\Call\\ClassTemplateParamCollector' => __DIR__ . '/../..' . '/src/Psalm/Internal/Analyzer/Statements/Expression/Call/ClassTemplateParamCollector.php', 'Psalm\\Internal\\Analyzer\\Statements\\Expression\\Call\\FunctionCallAnalyzer' => __DIR__ . '/../..' . '/src/Psalm/Internal/Analyzer/Statements/Expression/Call/FunctionCallAnalyzer.php', 'Psalm\\Internal\\Analyzer\\Statements\\Expression\\Call\\FunctionCallInfo' => __DIR__ . '/../..' . '/src/Psalm/Internal/Analyzer/Statements/Expression/Call/FunctionCallInfo.php', 'Psalm\\Internal\\Analyzer\\Statements\\Expression\\Call\\FunctionCallReturnTypeFetcher' => __DIR__ . '/../..' . '/src/Psalm/Internal/Analyzer/Statements/Expression/Call/FunctionCallReturnTypeFetcher.php', 'Psalm\\Internal\\Analyzer\\Statements\\Expression\\Call\\HighOrderFunctionArgHandler' => __DIR__ . '/../..' . '/src/Psalm/Internal/Analyzer/Statements/Expression/Call/HighOrderFunctionArgHandler.php', 'Psalm\\Internal\\Analyzer\\Statements\\Expression\\Call\\HighOrderFunctionArgInfo' => __DIR__ . '/../..' . '/src/Psalm/Internal/Analyzer/Statements/Expression/Call/HighOrderFunctionArgInfo.php', 'Psalm\\Internal\\Analyzer\\Statements\\Expression\\Call\\MethodCallAnalyzer' => __DIR__ . '/../..' . '/src/Psalm/Internal/Analyzer/Statements/Expression/Call/MethodCallAnalyzer.php', 'Psalm\\Internal\\Analyzer\\Statements\\Expression\\Call\\Method\\AtomicCallContext' => __DIR__ . '/../..' . '/src/Psalm/Internal/Analyzer/Statements/Expression/Call/Method/AtomicCallContext.php', 'Psalm\\Internal\\Analyzer\\Statements\\Expression\\Call\\Method\\AtomicMethodCallAnalysisResult' => __DIR__ . '/../..' . '/src/Psalm/Internal/Analyzer/Statements/Expression/Call/Method/AtomicMethodCallAnalysisResult.php', 'Psalm\\Internal\\Analyzer\\Statements\\Expression\\Call\\Method\\AtomicMethodCallAnalyzer' => __DIR__ . '/../..' . '/src/Psalm/Internal/Analyzer/Statements/Expression/Call/Method/AtomicMethodCallAnalyzer.php', 'Psalm\\Internal\\Analyzer\\Statements\\Expression\\Call\\Method\\ExistingAtomicMethodCallAnalyzer' => __DIR__ . '/../..' . '/src/Psalm/Internal/Analyzer/Statements/Expression/Call/Method/ExistingAtomicMethodCallAnalyzer.php', 'Psalm\\Internal\\Analyzer\\Statements\\Expression\\Call\\Method\\MethodCallProhibitionAnalyzer' => __DIR__ . '/../..' . '/src/Psalm/Internal/Analyzer/Statements/Expression/Call/Method/MethodCallProhibitionAnalyzer.php', 'Psalm\\Internal\\Analyzer\\Statements\\Expression\\Call\\Method\\MethodCallPurityAnalyzer' => __DIR__ . '/../..' . '/src/Psalm/Internal/Analyzer/Statements/Expression/Call/Method/MethodCallPurityAnalyzer.php', 'Psalm\\Internal\\Analyzer\\Statements\\Expression\\Call\\Method\\MethodCallReturnTypeFetcher' => __DIR__ . '/../..' . '/src/Psalm/Internal/Analyzer/Statements/Expression/Call/Method/MethodCallReturnTypeFetcher.php', 'Psalm\\Internal\\Analyzer\\Statements\\Expression\\Call\\Method\\MethodVisibilityAnalyzer' => __DIR__ . '/../..' . '/src/Psalm/Internal/Analyzer/Statements/Expression/Call/Method/MethodVisibilityAnalyzer.php', 'Psalm\\Internal\\Analyzer\\Statements\\Expression\\Call\\Method\\MissingMethodCallHandler' => __DIR__ . '/../..' . '/src/Psalm/Internal/Analyzer/Statements/Expression/Call/Method/MissingMethodCallHandler.php', 'Psalm\\Internal\\Analyzer\\Statements\\Expression\\Call\\NamedFunctionCallHandler' => __DIR__ . '/../..' . '/src/Psalm/Internal/Analyzer/Statements/Expression/Call/NamedFunctionCallHandler.php', 'Psalm\\Internal\\Analyzer\\Statements\\Expression\\Call\\NewAnalyzer' => __DIR__ . '/../..' . '/src/Psalm/Internal/Analyzer/Statements/Expression/Call/NewAnalyzer.php', 'Psalm\\Internal\\Analyzer\\Statements\\Expression\\Call\\StaticCallAnalyzer' => __DIR__ . '/../..' . '/src/Psalm/Internal/Analyzer/Statements/Expression/Call/StaticCallAnalyzer.php', 'Psalm\\Internal\\Analyzer\\Statements\\Expression\\Call\\StaticMethod\\AtomicStaticCallAnalyzer' => __DIR__ . '/../..' . '/src/Psalm/Internal/Analyzer/Statements/Expression/Call/StaticMethod/AtomicStaticCallAnalyzer.php', 'Psalm\\Internal\\Analyzer\\Statements\\Expression\\Call\\StaticMethod\\ExistingAtomicStaticCallAnalyzer' => __DIR__ . '/../..' . '/src/Psalm/Internal/Analyzer/Statements/Expression/Call/StaticMethod/ExistingAtomicStaticCallAnalyzer.php', 'Psalm\\Internal\\Analyzer\\Statements\\Expression\\CastAnalyzer' => __DIR__ . '/../..' . '/src/Psalm/Internal/Analyzer/Statements/Expression/CastAnalyzer.php', 'Psalm\\Internal\\Analyzer\\Statements\\Expression\\ClassConstAnalyzer' => __DIR__ . '/../..' . '/src/Psalm/Internal/Analyzer/Statements/Expression/ClassConstAnalyzer.php', 'Psalm\\Internal\\Analyzer\\Statements\\Expression\\CloneAnalyzer' => __DIR__ . '/../..' . '/src/Psalm/Internal/Analyzer/Statements/Expression/CloneAnalyzer.php', 'Psalm\\Internal\\Analyzer\\Statements\\Expression\\EmptyAnalyzer' => __DIR__ . '/../..' . '/src/Psalm/Internal/Analyzer/Statements/Expression/EmptyAnalyzer.php', 'Psalm\\Internal\\Analyzer\\Statements\\Expression\\EncapsulatedStringAnalyzer' => __DIR__ . '/../..' . '/src/Psalm/Internal/Analyzer/Statements/Expression/EncapsulatedStringAnalyzer.php', 'Psalm\\Internal\\Analyzer\\Statements\\Expression\\EvalAnalyzer' => __DIR__ . '/../..' . '/src/Psalm/Internal/Analyzer/Statements/Expression/EvalAnalyzer.php', 'Psalm\\Internal\\Analyzer\\Statements\\Expression\\ExitAnalyzer' => __DIR__ . '/../..' . '/src/Psalm/Internal/Analyzer/Statements/Expression/ExitAnalyzer.php', 'Psalm\\Internal\\Analyzer\\Statements\\Expression\\ExpressionIdentifier' => __DIR__ . '/../..' . '/src/Psalm/Internal/Analyzer/Statements/Expression/ExpressionIdentifier.php', 'Psalm\\Internal\\Analyzer\\Statements\\Expression\\Fetch\\ArrayFetchAnalyzer' => __DIR__ . '/../..' . '/src/Psalm/Internal/Analyzer/Statements/Expression/Fetch/ArrayFetchAnalyzer.php', 'Psalm\\Internal\\Analyzer\\Statements\\Expression\\Fetch\\AtomicPropertyFetchAnalyzer' => __DIR__ . '/../..' . '/src/Psalm/Internal/Analyzer/Statements/Expression/Fetch/AtomicPropertyFetchAnalyzer.php', 'Psalm\\Internal\\Analyzer\\Statements\\Expression\\Fetch\\ConstFetchAnalyzer' => __DIR__ . '/../..' . '/src/Psalm/Internal/Analyzer/Statements/Expression/Fetch/ConstFetchAnalyzer.php', 'Psalm\\Internal\\Analyzer\\Statements\\Expression\\Fetch\\InstancePropertyFetchAnalyzer' => __DIR__ . '/../..' . '/src/Psalm/Internal/Analyzer/Statements/Expression/Fetch/InstancePropertyFetchAnalyzer.php', 'Psalm\\Internal\\Analyzer\\Statements\\Expression\\Fetch\\StaticPropertyFetchAnalyzer' => __DIR__ . '/../..' . '/src/Psalm/Internal/Analyzer/Statements/Expression/Fetch/StaticPropertyFetchAnalyzer.php', 'Psalm\\Internal\\Analyzer\\Statements\\Expression\\Fetch\\VariableFetchAnalyzer' => __DIR__ . '/../..' . '/src/Psalm/Internal/Analyzer/Statements/Expression/Fetch/VariableFetchAnalyzer.php', 'Psalm\\Internal\\Analyzer\\Statements\\Expression\\IncDecExpressionAnalyzer' => __DIR__ . '/../..' . '/src/Psalm/Internal/Analyzer/Statements/Expression/IncDecExpressionAnalyzer.php', 'Psalm\\Internal\\Analyzer\\Statements\\Expression\\IncludeAnalyzer' => __DIR__ . '/../..' . '/src/Psalm/Internal/Analyzer/Statements/Expression/IncludeAnalyzer.php', 'Psalm\\Internal\\Analyzer\\Statements\\Expression\\InstanceofAnalyzer' => __DIR__ . '/../..' . '/src/Psalm/Internal/Analyzer/Statements/Expression/InstanceofAnalyzer.php', 'Psalm\\Internal\\Analyzer\\Statements\\Expression\\IssetAnalyzer' => __DIR__ . '/../..' . '/src/Psalm/Internal/Analyzer/Statements/Expression/IssetAnalyzer.php', 'Psalm\\Internal\\Analyzer\\Statements\\Expression\\MagicConstAnalyzer' => __DIR__ . '/../..' . '/src/Psalm/Internal/Analyzer/Statements/Expression/MagicConstAnalyzer.php', 'Psalm\\Internal\\Analyzer\\Statements\\Expression\\MatchAnalyzer' => __DIR__ . '/../..' . '/src/Psalm/Internal/Analyzer/Statements/Expression/MatchAnalyzer.php', 'Psalm\\Internal\\Analyzer\\Statements\\Expression\\NullsafeAnalyzer' => __DIR__ . '/../..' . '/src/Psalm/Internal/Analyzer/Statements/Expression/NullsafeAnalyzer.php', 'Psalm\\Internal\\Analyzer\\Statements\\Expression\\PrintAnalyzer' => __DIR__ . '/../..' . '/src/Psalm/Internal/Analyzer/Statements/Expression/PrintAnalyzer.php', 'Psalm\\Internal\\Analyzer\\Statements\\Expression\\SimpleTypeInferer' => __DIR__ . '/../..' . '/src/Psalm/Internal/Analyzer/Statements/Expression/SimpleTypeInferer.php', 'Psalm\\Internal\\Analyzer\\Statements\\Expression\\TernaryAnalyzer' => __DIR__ . '/../..' . '/src/Psalm/Internal/Analyzer/Statements/Expression/TernaryAnalyzer.php', 'Psalm\\Internal\\Analyzer\\Statements\\Expression\\UnaryPlusMinusAnalyzer' => __DIR__ . '/../..' . '/src/Psalm/Internal/Analyzer/Statements/Expression/UnaryPlusMinusAnalyzer.php', 'Psalm\\Internal\\Analyzer\\Statements\\Expression\\YieldAnalyzer' => __DIR__ . '/../..' . '/src/Psalm/Internal/Analyzer/Statements/Expression/YieldAnalyzer.php', 'Psalm\\Internal\\Analyzer\\Statements\\Expression\\YieldFromAnalyzer' => __DIR__ . '/../..' . '/src/Psalm/Internal/Analyzer/Statements/Expression/YieldFromAnalyzer.php', 'Psalm\\Internal\\Analyzer\\Statements\\GlobalAnalyzer' => __DIR__ . '/../..' . '/src/Psalm/Internal/Analyzer/Statements/GlobalAnalyzer.php', 'Psalm\\Internal\\Analyzer\\Statements\\ReturnAnalyzer' => __DIR__ . '/../..' . '/src/Psalm/Internal/Analyzer/Statements/ReturnAnalyzer.php', 'Psalm\\Internal\\Analyzer\\Statements\\StaticAnalyzer' => __DIR__ . '/../..' . '/src/Psalm/Internal/Analyzer/Statements/StaticAnalyzer.php', 'Psalm\\Internal\\Analyzer\\Statements\\ThrowAnalyzer' => __DIR__ . '/../..' . '/src/Psalm/Internal/Analyzer/Statements/ThrowAnalyzer.php', 'Psalm\\Internal\\Analyzer\\Statements\\UnsetAnalyzer' => __DIR__ . '/../..' . '/src/Psalm/Internal/Analyzer/Statements/UnsetAnalyzer.php', 'Psalm\\Internal\\Analyzer\\Statements\\UnusedAssignmentRemover' => __DIR__ . '/../..' . '/src/Psalm/Internal/Analyzer/Statements/UnusedAssignmentRemover.php', 'Psalm\\Internal\\Analyzer\\TraitAnalyzer' => __DIR__ . '/../..' . '/src/Psalm/Internal/Analyzer/TraitAnalyzer.php', 'Psalm\\Internal\\Analyzer\\TypeAnalyzer' => __DIR__ . '/../..' . '/src/Psalm/Internal/Analyzer/TypeAnalyzer.php', 'Psalm\\Internal\\Cache' => __DIR__ . '/../..' . '/src/Psalm/Internal/Cache.php', 'Psalm\\Internal\\Clause' => __DIR__ . '/../..' . '/src/Psalm/Internal/Clause.php', 'Psalm\\Internal\\CliUtils' => __DIR__ . '/../..' . '/src/Psalm/Internal/CliUtils.php', 'Psalm\\Internal\\Cli\\LanguageServer' => __DIR__ . '/../..' . '/src/Psalm/Internal/Cli/LanguageServer.php', 'Psalm\\Internal\\Cli\\Plugin' => __DIR__ . '/../..' . '/src/Psalm/Internal/Cli/Plugin.php', 'Psalm\\Internal\\Cli\\Psalm' => __DIR__ . '/../..' . '/src/Psalm/Internal/Cli/Psalm.php', 'Psalm\\Internal\\Cli\\Psalter' => __DIR__ . '/../..' . '/src/Psalm/Internal/Cli/Psalter.php', 'Psalm\\Internal\\Cli\\Refactor' => __DIR__ . '/../..' . '/src/Psalm/Internal/Cli/Refactor.php', 'Psalm\\Internal\\Codebase\\Analyzer' => __DIR__ . '/../..' . '/src/Psalm/Internal/Codebase/Analyzer.php', 'Psalm\\Internal\\Codebase\\AssertionsFromInheritanceResolver' => __DIR__ . '/../..' . '/src/Psalm/Internal/Codebase/AssertionsFromInheritanceResolver.php', 'Psalm\\Internal\\Codebase\\ClassConstantByWildcardResolver' => __DIR__ . '/../..' . '/src/Psalm/Internal/Codebase/ClassConstantByWildcardResolver.php', 'Psalm\\Internal\\Codebase\\ClassLikes' => __DIR__ . '/../..' . '/src/Psalm/Internal/Codebase/ClassLikes.php', 'Psalm\\Internal\\Codebase\\ConstantTypeResolver' => __DIR__ . '/../..' . '/src/Psalm/Internal/Codebase/ConstantTypeResolver.php', 'Psalm\\Internal\\Codebase\\DataFlowGraph' => __DIR__ . '/../..' . '/src/Psalm/Internal/Codebase/DataFlowGraph.php', 'Psalm\\Internal\\Codebase\\Functions' => __DIR__ . '/../..' . '/src/Psalm/Internal/Codebase/Functions.php', 'Psalm\\Internal\\Codebase\\ImpureFunctionsList' => __DIR__ . '/../..' . '/src/Psalm/Internal/Codebase/ImpureFunctionsList.php', 'Psalm\\Internal\\Codebase\\InternalCallMapHandler' => __DIR__ . '/../..' . '/src/Psalm/Internal/Codebase/InternalCallMapHandler.php', 'Psalm\\Internal\\Codebase\\Methods' => __DIR__ . '/../..' . '/src/Psalm/Internal/Codebase/Methods.php', 'Psalm\\Internal\\Codebase\\Populator' => __DIR__ . '/../..' . '/src/Psalm/Internal/Codebase/Populator.php', 'Psalm\\Internal\\Codebase\\Properties' => __DIR__ . '/../..' . '/src/Psalm/Internal/Codebase/Properties.php', 'Psalm\\Internal\\Codebase\\PropertyMap' => __DIR__ . '/../..' . '/src/Psalm/Internal/Codebase/PropertyMap.php', 'Psalm\\Internal\\Codebase\\ReferenceMapGenerator' => __DIR__ . '/../..' . '/src/Psalm/Internal/Codebase/ReferenceMapGenerator.php', 'Psalm\\Internal\\Codebase\\Reflection' => __DIR__ . '/../..' . '/src/Psalm/Internal/Codebase/Reflection.php', 'Psalm\\Internal\\Codebase\\Scanner' => __DIR__ . '/../..' . '/src/Psalm/Internal/Codebase/Scanner.php', 'Psalm\\Internal\\Codebase\\StorageByPatternResolver' => __DIR__ . '/../..' . '/src/Psalm/Internal/Codebase/StorageByPatternResolver.php', 'Psalm\\Internal\\Codebase\\TaintFlowGraph' => __DIR__ . '/../..' . '/src/Psalm/Internal/Codebase/TaintFlowGraph.php', 'Psalm\\Internal\\Codebase\\VariableUseGraph' => __DIR__ . '/../..' . '/src/Psalm/Internal/Codebase/VariableUseGraph.php', 'Psalm\\Internal\\Composer' => __DIR__ . '/../..' . '/src/Psalm/Internal/Composer.php', 'Psalm\\Internal\\DataFlow\\DataFlowNode' => __DIR__ . '/../..' . '/src/Psalm/Internal/DataFlow/DataFlowNode.php', 'Psalm\\Internal\\DataFlow\\Path' => __DIR__ . '/../..' . '/src/Psalm/Internal/DataFlow/Path.php', 'Psalm\\Internal\\DataFlow\\TaintSink' => __DIR__ . '/../..' . '/src/Psalm/Internal/DataFlow/TaintSink.php', 'Psalm\\Internal\\DataFlow\\TaintSource' => __DIR__ . '/../..' . '/src/Psalm/Internal/DataFlow/TaintSource.php', 'Psalm\\Internal\\Diff\\AstDiffer' => __DIR__ . '/../..' . '/src/Psalm/Internal/Diff/AstDiffer.php', 'Psalm\\Internal\\Diff\\ClassStatementsDiffer' => __DIR__ . '/../..' . '/src/Psalm/Internal/Diff/ClassStatementsDiffer.php', 'Psalm\\Internal\\Diff\\DiffElem' => __DIR__ . '/../..' . '/src/Psalm/Internal/Diff/DiffElem.php', 'Psalm\\Internal\\Diff\\FileDiffer' => __DIR__ . '/../..' . '/src/Psalm/Internal/Diff/FileDiffer.php', 'Psalm\\Internal\\Diff\\FileStatementsDiffer' => __DIR__ . '/../..' . '/src/Psalm/Internal/Diff/FileStatementsDiffer.php', 'Psalm\\Internal\\Diff\\NamespaceStatementsDiffer' => __DIR__ . '/../..' . '/src/Psalm/Internal/Diff/NamespaceStatementsDiffer.php', 'Psalm\\Internal\\ErrorHandler' => __DIR__ . '/../..' . '/src/Psalm/Internal/ErrorHandler.php', 'Psalm\\Internal\\EventDispatcher' => __DIR__ . '/../..' . '/src/Psalm/Internal/EventDispatcher.php', 'Psalm\\Internal\\ExecutionEnvironment\\BuildInfoCollector' => __DIR__ . '/../..' . '/src/Psalm/Internal/ExecutionEnvironment/BuildInfoCollector.php', 'Psalm\\Internal\\ExecutionEnvironment\\GitInfoCollector' => __DIR__ . '/../..' . '/src/Psalm/Internal/ExecutionEnvironment/GitInfoCollector.php', 'Psalm\\Internal\\ExecutionEnvironment\\SystemCommandExecutor' => __DIR__ . '/../..' . '/src/Psalm/Internal/ExecutionEnvironment/SystemCommandExecutor.php', 'Psalm\\Internal\\FileManipulation\\ClassDocblockManipulator' => __DIR__ . '/../..' . '/src/Psalm/Internal/FileManipulation/ClassDocblockManipulator.php', 'Psalm\\Internal\\FileManipulation\\CodeMigration' => __DIR__ . '/../..' . '/src/Psalm/Internal/FileManipulation/CodeMigration.php', 'Psalm\\Internal\\FileManipulation\\FileManipulationBuffer' => __DIR__ . '/../..' . '/src/Psalm/Internal/FileManipulation/FileManipulationBuffer.php', 'Psalm\\Internal\\FileManipulation\\FunctionDocblockManipulator' => __DIR__ . '/../..' . '/src/Psalm/Internal/FileManipulation/FunctionDocblockManipulator.php', 'Psalm\\Internal\\FileManipulation\\PropertyDocblockManipulator' => __DIR__ . '/../..' . '/src/Psalm/Internal/FileManipulation/PropertyDocblockManipulator.php', 'Psalm\\Internal\\Fork\\ForkMessage' => __DIR__ . '/../..' . '/src/Psalm/Internal/Fork/ForkMessage.php', 'Psalm\\Internal\\Fork\\ForkProcessDoneMessage' => __DIR__ . '/../..' . '/src/Psalm/Internal/Fork/ForkProcessDoneMessage.php', 'Psalm\\Internal\\Fork\\ForkProcessErrorMessage' => __DIR__ . '/../..' . '/src/Psalm/Internal/Fork/ForkProcessErrorMessage.php', 'Psalm\\Internal\\Fork\\ForkTaskDoneMessage' => __DIR__ . '/../..' . '/src/Psalm/Internal/Fork/ForkTaskDoneMessage.php', 'Psalm\\Internal\\Fork\\Pool' => __DIR__ . '/../..' . '/src/Psalm/Internal/Fork/Pool.php', 'Psalm\\Internal\\Fork\\PsalmRestarter' => __DIR__ . '/../..' . '/src/Psalm/Internal/Fork/PsalmRestarter.php', 'Psalm\\Internal\\IncludeCollector' => __DIR__ . '/../..' . '/src/Psalm/Internal/IncludeCollector.php', 'Psalm\\Internal\\Json\\Json' => __DIR__ . '/../..' . '/src/Psalm/Internal/Json/Json.php', 'Psalm\\Internal\\LanguageServer\\ClientConfiguration' => __DIR__ . '/../..' . '/src/Psalm/Internal/LanguageServer/ClientConfiguration.php', 'Psalm\\Internal\\LanguageServer\\ClientHandler' => __DIR__ . '/../..' . '/src/Psalm/Internal/LanguageServer/ClientHandler.php', 'Psalm\\Internal\\LanguageServer\\Client\\Progress\\LegacyProgress' => __DIR__ . '/../..' . '/src/Psalm/Internal/LanguageServer/Client/Progress/LegacyProgress.php', 'Psalm\\Internal\\LanguageServer\\Client\\Progress\\Progress' => __DIR__ . '/../..' . '/src/Psalm/Internal/LanguageServer/Client/Progress/Progress.php', 'Psalm\\Internal\\LanguageServer\\Client\\Progress\\ProgressInterface' => __DIR__ . '/../..' . '/src/Psalm/Internal/LanguageServer/Client/Progress/ProgressInterface.php', 'Psalm\\Internal\\LanguageServer\\Client\\TextDocument' => __DIR__ . '/../..' . '/src/Psalm/Internal/LanguageServer/Client/TextDocument.php', 'Psalm\\Internal\\LanguageServer\\Client\\Workspace' => __DIR__ . '/../..' . '/src/Psalm/Internal/LanguageServer/Client/Workspace.php', 'Psalm\\Internal\\LanguageServer\\EmitterInterface' => __DIR__ . '/../..' . '/src/Psalm/Internal/LanguageServer/EmitterInterface.php', 'Psalm\\Internal\\LanguageServer\\EmitterTrait' => __DIR__ . '/../..' . '/src/Psalm/Internal/LanguageServer/EmitterTrait.php', 'Psalm\\Internal\\LanguageServer\\IdGenerator' => __DIR__ . '/../..' . '/src/Psalm/Internal/LanguageServer/IdGenerator.php', 'Psalm\\Internal\\LanguageServer\\LanguageClient' => __DIR__ . '/../..' . '/src/Psalm/Internal/LanguageServer/LanguageClient.php', 'Psalm\\Internal\\LanguageServer\\LanguageServer' => __DIR__ . '/../..' . '/src/Psalm/Internal/LanguageServer/LanguageServer.php', 'Psalm\\Internal\\LanguageServer\\Message' => __DIR__ . '/../..' . '/src/Psalm/Internal/LanguageServer/Message.php', 'Psalm\\Internal\\LanguageServer\\PHPMarkdownContent' => __DIR__ . '/../..' . '/src/Psalm/Internal/LanguageServer/PHPMarkdownContent.php', 'Psalm\\Internal\\LanguageServer\\PathMapper' => __DIR__ . '/../..' . '/src/Psalm/Internal/LanguageServer/PathMapper.php', 'Psalm\\Internal\\LanguageServer\\Progress' => __DIR__ . '/../..' . '/src/Psalm/Internal/LanguageServer/Progress.php', 'Psalm\\Internal\\LanguageServer\\ProtocolReader' => __DIR__ . '/../..' . '/src/Psalm/Internal/LanguageServer/ProtocolReader.php', 'Psalm\\Internal\\LanguageServer\\ProtocolStreamReader' => __DIR__ . '/../..' . '/src/Psalm/Internal/LanguageServer/ProtocolStreamReader.php', 'Psalm\\Internal\\LanguageServer\\ProtocolStreamWriter' => __DIR__ . '/../..' . '/src/Psalm/Internal/LanguageServer/ProtocolStreamWriter.php', 'Psalm\\Internal\\LanguageServer\\ProtocolWriter' => __DIR__ . '/../..' . '/src/Psalm/Internal/LanguageServer/ProtocolWriter.php', 'Psalm\\Internal\\LanguageServer\\Provider\\ClassLikeStorageCacheProvider' => __DIR__ . '/../..' . '/src/Psalm/Internal/LanguageServer/Provider/ClassLikeStorageCacheProvider.php', 'Psalm\\Internal\\LanguageServer\\Provider\\FileReferenceCacheProvider' => __DIR__ . '/../..' . '/src/Psalm/Internal/LanguageServer/Provider/FileReferenceCacheProvider.php', 'Psalm\\Internal\\LanguageServer\\Provider\\FileStorageCacheProvider' => __DIR__ . '/../..' . '/src/Psalm/Internal/LanguageServer/Provider/FileStorageCacheProvider.php', 'Psalm\\Internal\\LanguageServer\\Provider\\ParserCacheProvider' => __DIR__ . '/../..' . '/src/Psalm/Internal/LanguageServer/Provider/ParserCacheProvider.php', 'Psalm\\Internal\\LanguageServer\\Provider\\ProjectCacheProvider' => __DIR__ . '/../..' . '/src/Psalm/Internal/LanguageServer/Provider/ProjectCacheProvider.php', 'Psalm\\Internal\\LanguageServer\\Reference' => __DIR__ . '/../..' . '/src/Psalm/Internal/LanguageServer/Reference.php', 'Psalm\\Internal\\LanguageServer\\Server\\TextDocument' => __DIR__ . '/../..' . '/src/Psalm/Internal/LanguageServer/Server/TextDocument.php', 'Psalm\\Internal\\LanguageServer\\Server\\Workspace' => __DIR__ . '/../..' . '/src/Psalm/Internal/LanguageServer/Server/Workspace.php', 'Psalm\\Internal\\MethodIdentifier' => __DIR__ . '/../..' . '/src/Psalm/Internal/MethodIdentifier.php', 'Psalm\\Internal\\PhpTraverser\\CustomTraverser' => __DIR__ . '/../..' . '/src/Psalm/Internal/PhpTraverser/CustomTraverser.php', 'Psalm\\Internal\\PhpVisitor\\AssignmentMapVisitor' => __DIR__ . '/../..' . '/src/Psalm/Internal/PhpVisitor/AssignmentMapVisitor.php', 'Psalm\\Internal\\PhpVisitor\\CheckTrivialExprVisitor' => __DIR__ . '/../..' . '/src/Psalm/Internal/PhpVisitor/CheckTrivialExprVisitor.php', 'Psalm\\Internal\\PhpVisitor\\CloningVisitor' => __DIR__ . '/../..' . '/src/Psalm/Internal/PhpVisitor/CloningVisitor.php', 'Psalm\\Internal\\PhpVisitor\\ConditionCloningVisitor' => __DIR__ . '/../..' . '/src/Psalm/Internal/PhpVisitor/ConditionCloningVisitor.php', 'Psalm\\Internal\\PhpVisitor\\NodeCleanerVisitor' => __DIR__ . '/../..' . '/src/Psalm/Internal/PhpVisitor/NodeCleanerVisitor.php', 'Psalm\\Internal\\PhpVisitor\\NodeCounterVisitor' => __DIR__ . '/../..' . '/src/Psalm/Internal/PhpVisitor/NodeCounterVisitor.php', 'Psalm\\Internal\\PhpVisitor\\OffsetShifterVisitor' => __DIR__ . '/../..' . '/src/Psalm/Internal/PhpVisitor/OffsetShifterVisitor.php', 'Psalm\\Internal\\PhpVisitor\\ParamReplacementVisitor' => __DIR__ . '/../..' . '/src/Psalm/Internal/PhpVisitor/ParamReplacementVisitor.php', 'Psalm\\Internal\\PhpVisitor\\PartialParserVisitor' => __DIR__ . '/../..' . '/src/Psalm/Internal/PhpVisitor/PartialParserVisitor.php', 'Psalm\\Internal\\PhpVisitor\\ReflectorVisitor' => __DIR__ . '/../..' . '/src/Psalm/Internal/PhpVisitor/ReflectorVisitor.php', 'Psalm\\Internal\\PhpVisitor\\Reflector\\AttributeResolver' => __DIR__ . '/../..' . '/src/Psalm/Internal/PhpVisitor/Reflector/AttributeResolver.php', 'Psalm\\Internal\\PhpVisitor\\Reflector\\ClassLikeDocblockParser' => __DIR__ . '/../..' . '/src/Psalm/Internal/PhpVisitor/Reflector/ClassLikeDocblockParser.php', 'Psalm\\Internal\\PhpVisitor\\Reflector\\ClassLikeNodeScanner' => __DIR__ . '/../..' . '/src/Psalm/Internal/PhpVisitor/Reflector/ClassLikeNodeScanner.php', 'Psalm\\Internal\\PhpVisitor\\Reflector\\ExpressionResolver' => __DIR__ . '/../..' . '/src/Psalm/Internal/PhpVisitor/Reflector/ExpressionResolver.php', 'Psalm\\Internal\\PhpVisitor\\Reflector\\ExpressionScanner' => __DIR__ . '/../..' . '/src/Psalm/Internal/PhpVisitor/Reflector/ExpressionScanner.php', 'Psalm\\Internal\\PhpVisitor\\Reflector\\FunctionLikeDocblockParser' => __DIR__ . '/../..' . '/src/Psalm/Internal/PhpVisitor/Reflector/FunctionLikeDocblockParser.php', 'Psalm\\Internal\\PhpVisitor\\Reflector\\FunctionLikeDocblockScanner' => __DIR__ . '/../..' . '/src/Psalm/Internal/PhpVisitor/Reflector/FunctionLikeDocblockScanner.php', 'Psalm\\Internal\\PhpVisitor\\Reflector\\FunctionLikeNodeScanner' => __DIR__ . '/../..' . '/src/Psalm/Internal/PhpVisitor/Reflector/FunctionLikeNodeScanner.php', 'Psalm\\Internal\\PhpVisitor\\Reflector\\TypeHintResolver' => __DIR__ . '/../..' . '/src/Psalm/Internal/PhpVisitor/Reflector/TypeHintResolver.php', 'Psalm\\Internal\\PhpVisitor\\ShortClosureVisitor' => __DIR__ . '/../..' . '/src/Psalm/Internal/PhpVisitor/ShortClosureVisitor.php', 'Psalm\\Internal\\PhpVisitor\\SimpleNameResolver' => __DIR__ . '/../..' . '/src/Psalm/Internal/PhpVisitor/SimpleNameResolver.php', 'Psalm\\Internal\\PhpVisitor\\TraitFinder' => __DIR__ . '/../..' . '/src/Psalm/Internal/PhpVisitor/TraitFinder.php', 'Psalm\\Internal\\PhpVisitor\\TypeMappingVisitor' => __DIR__ . '/../..' . '/src/Psalm/Internal/PhpVisitor/TypeMappingVisitor.php', 'Psalm\\Internal\\PhpVisitor\\YieldTypeCollector' => __DIR__ . '/../..' . '/src/Psalm/Internal/PhpVisitor/YieldTypeCollector.php', 'Psalm\\Internal\\PluginManager\\Command\\DisableCommand' => __DIR__ . '/../..' . '/src/Psalm/Internal/PluginManager/Command/DisableCommand.php', 'Psalm\\Internal\\PluginManager\\Command\\EnableCommand' => __DIR__ . '/../..' . '/src/Psalm/Internal/PluginManager/Command/EnableCommand.php', 'Psalm\\Internal\\PluginManager\\Command\\ShowCommand' => __DIR__ . '/../..' . '/src/Psalm/Internal/PluginManager/Command/ShowCommand.php', 'Psalm\\Internal\\PluginManager\\ComposerLock' => __DIR__ . '/../..' . '/src/Psalm/Internal/PluginManager/ComposerLock.php', 'Psalm\\Internal\\PluginManager\\ConfigFile' => __DIR__ . '/../..' . '/src/Psalm/Internal/PluginManager/ConfigFile.php', 'Psalm\\Internal\\PluginManager\\PluginList' => __DIR__ . '/../..' . '/src/Psalm/Internal/PluginManager/PluginList.php', 'Psalm\\Internal\\PluginManager\\PluginListFactory' => __DIR__ . '/../..' . '/src/Psalm/Internal/PluginManager/PluginListFactory.php', 'Psalm\\Internal\\Provider\\AddRemoveTaints\\HtmlFunctionTainter' => __DIR__ . '/../..' . '/src/Psalm/Internal/Provider/AddRemoveTaints/HtmlFunctionTainter.php', 'Psalm\\Internal\\Provider\\ClassLikeStorageCacheProvider' => __DIR__ . '/../..' . '/src/Psalm/Internal/Provider/ClassLikeStorageCacheProvider.php', 'Psalm\\Internal\\Provider\\ClassLikeStorageProvider' => __DIR__ . '/../..' . '/src/Psalm/Internal/Provider/ClassLikeStorageProvider.php', 'Psalm\\Internal\\Provider\\DynamicFunctionStorageProvider' => __DIR__ . '/../..' . '/src/Psalm/Internal/Provider/DynamicFunctionStorageProvider.php', 'Psalm\\Internal\\Provider\\FakeFileProvider' => __DIR__ . '/../..' . '/src/Psalm/Internal/Provider/FakeFileProvider.php', 'Psalm\\Internal\\Provider\\FileProvider' => __DIR__ . '/../..' . '/src/Psalm/Internal/Provider/FileProvider.php', 'Psalm\\Internal\\Provider\\FileReferenceCacheProvider' => __DIR__ . '/../..' . '/src/Psalm/Internal/Provider/FileReferenceCacheProvider.php', 'Psalm\\Internal\\Provider\\FileReferenceProvider' => __DIR__ . '/../..' . '/src/Psalm/Internal/Provider/FileReferenceProvider.php', 'Psalm\\Internal\\Provider\\FileStorageCacheProvider' => __DIR__ . '/../..' . '/src/Psalm/Internal/Provider/FileStorageCacheProvider.php', 'Psalm\\Internal\\Provider\\FileStorageProvider' => __DIR__ . '/../..' . '/src/Psalm/Internal/Provider/FileStorageProvider.php', 'Psalm\\Internal\\Provider\\FunctionExistenceProvider' => __DIR__ . '/../..' . '/src/Psalm/Internal/Provider/FunctionExistenceProvider.php', 'Psalm\\Internal\\Provider\\FunctionParamsProvider' => __DIR__ . '/../..' . '/src/Psalm/Internal/Provider/FunctionParamsProvider.php', 'Psalm\\Internal\\Provider\\FunctionReturnTypeProvider' => __DIR__ . '/../..' . '/src/Psalm/Internal/Provider/FunctionReturnTypeProvider.php', 'Psalm\\Internal\\Provider\\MethodExistenceProvider' => __DIR__ . '/../..' . '/src/Psalm/Internal/Provider/MethodExistenceProvider.php', 'Psalm\\Internal\\Provider\\MethodParamsProvider' => __DIR__ . '/../..' . '/src/Psalm/Internal/Provider/MethodParamsProvider.php', 'Psalm\\Internal\\Provider\\MethodReturnTypeProvider' => __DIR__ . '/../..' . '/src/Psalm/Internal/Provider/MethodReturnTypeProvider.php', 'Psalm\\Internal\\Provider\\MethodVisibilityProvider' => __DIR__ . '/../..' . '/src/Psalm/Internal/Provider/MethodVisibilityProvider.php', 'Psalm\\Internal\\Provider\\NodeDataProvider' => __DIR__ . '/../..' . '/src/Psalm/Internal/Provider/NodeDataProvider.php', 'Psalm\\Internal\\Provider\\ParamsProvider\\ArrayFilterParamsProvider' => __DIR__ . '/../..' . '/src/Psalm/Internal/Provider/ParamsProvider/ArrayFilterParamsProvider.php', 'Psalm\\Internal\\Provider\\ParamsProvider\\ArrayMultisortParamsProvider' => __DIR__ . '/../..' . '/src/Psalm/Internal/Provider/ParamsProvider/ArrayMultisortParamsProvider.php', 'Psalm\\Internal\\Provider\\ParserCacheProvider' => __DIR__ . '/../..' . '/src/Psalm/Internal/Provider/ParserCacheProvider.php', 'Psalm\\Internal\\Provider\\ProjectCacheProvider' => __DIR__ . '/../..' . '/src/Psalm/Internal/Provider/ProjectCacheProvider.php', 'Psalm\\Internal\\Provider\\PropertyExistenceProvider' => __DIR__ . '/../..' . '/src/Psalm/Internal/Provider/PropertyExistenceProvider.php', 'Psalm\\Internal\\Provider\\PropertyTypeProvider' => __DIR__ . '/../..' . '/src/Psalm/Internal/Provider/PropertyTypeProvider.php', 'Psalm\\Internal\\Provider\\PropertyTypeProvider\\DomDocumentPropertyTypeProvider' => __DIR__ . '/../..' . '/src/Psalm/Internal/Provider/PropertyTypeProvider/DomDocumentPropertyTypeProvider.php', 'Psalm\\Internal\\Provider\\PropertyVisibilityProvider' => __DIR__ . '/../..' . '/src/Psalm/Internal/Provider/PropertyVisibilityProvider.php', 'Psalm\\Internal\\Provider\\Providers' => __DIR__ . '/../..' . '/src/Psalm/Internal/Provider/Providers.php', 'Psalm\\Internal\\Provider\\ReturnTypeProvider\\ArrayChunkReturnTypeProvider' => __DIR__ . '/../..' . '/src/Psalm/Internal/Provider/ReturnTypeProvider/ArrayChunkReturnTypeProvider.php', 'Psalm\\Internal\\Provider\\ReturnTypeProvider\\ArrayColumnReturnTypeProvider' => __DIR__ . '/../..' . '/src/Psalm/Internal/Provider/ReturnTypeProvider/ArrayColumnReturnTypeProvider.php', 'Psalm\\Internal\\Provider\\ReturnTypeProvider\\ArrayCombineReturnTypeProvider' => __DIR__ . '/../..' . '/src/Psalm/Internal/Provider/ReturnTypeProvider/ArrayCombineReturnTypeProvider.php', 'Psalm\\Internal\\Provider\\ReturnTypeProvider\\ArrayFillKeysReturnTypeProvider' => __DIR__ . '/../..' . '/src/Psalm/Internal/Provider/ReturnTypeProvider/ArrayFillKeysReturnTypeProvider.php', 'Psalm\\Internal\\Provider\\ReturnTypeProvider\\ArrayFillReturnTypeProvider' => __DIR__ . '/../..' . '/src/Psalm/Internal/Provider/ReturnTypeProvider/ArrayFillReturnTypeProvider.php', 'Psalm\\Internal\\Provider\\ReturnTypeProvider\\ArrayFilterReturnTypeProvider' => __DIR__ . '/../..' . '/src/Psalm/Internal/Provider/ReturnTypeProvider/ArrayFilterReturnTypeProvider.php', 'Psalm\\Internal\\Provider\\ReturnTypeProvider\\ArrayMapReturnTypeProvider' => __DIR__ . '/../..' . '/src/Psalm/Internal/Provider/ReturnTypeProvider/ArrayMapReturnTypeProvider.php', 'Psalm\\Internal\\Provider\\ReturnTypeProvider\\ArrayMergeReturnTypeProvider' => __DIR__ . '/../..' . '/src/Psalm/Internal/Provider/ReturnTypeProvider/ArrayMergeReturnTypeProvider.php', 'Psalm\\Internal\\Provider\\ReturnTypeProvider\\ArrayPadReturnTypeProvider' => __DIR__ . '/../..' . '/src/Psalm/Internal/Provider/ReturnTypeProvider/ArrayPadReturnTypeProvider.php', 'Psalm\\Internal\\Provider\\ReturnTypeProvider\\ArrayPointerAdjustmentReturnTypeProvider' => __DIR__ . '/../..' . '/src/Psalm/Internal/Provider/ReturnTypeProvider/ArrayPointerAdjustmentReturnTypeProvider.php', 'Psalm\\Internal\\Provider\\ReturnTypeProvider\\ArrayPopReturnTypeProvider' => __DIR__ . '/../..' . '/src/Psalm/Internal/Provider/ReturnTypeProvider/ArrayPopReturnTypeProvider.php', 'Psalm\\Internal\\Provider\\ReturnTypeProvider\\ArrayRandReturnTypeProvider' => __DIR__ . '/../..' . '/src/Psalm/Internal/Provider/ReturnTypeProvider/ArrayRandReturnTypeProvider.php', 'Psalm\\Internal\\Provider\\ReturnTypeProvider\\ArrayReduceReturnTypeProvider' => __DIR__ . '/../..' . '/src/Psalm/Internal/Provider/ReturnTypeProvider/ArrayReduceReturnTypeProvider.php', 'Psalm\\Internal\\Provider\\ReturnTypeProvider\\ArrayReverseReturnTypeProvider' => __DIR__ . '/../..' . '/src/Psalm/Internal/Provider/ReturnTypeProvider/ArrayReverseReturnTypeProvider.php', 'Psalm\\Internal\\Provider\\ReturnTypeProvider\\ArraySliceReturnTypeProvider' => __DIR__ . '/../..' . '/src/Psalm/Internal/Provider/ReturnTypeProvider/ArraySliceReturnTypeProvider.php', 'Psalm\\Internal\\Provider\\ReturnTypeProvider\\ArraySpliceReturnTypeProvider' => __DIR__ . '/../..' . '/src/Psalm/Internal/Provider/ReturnTypeProvider/ArraySpliceReturnTypeProvider.php', 'Psalm\\Internal\\Provider\\ReturnTypeProvider\\BasenameReturnTypeProvider' => __DIR__ . '/../..' . '/src/Psalm/Internal/Provider/ReturnTypeProvider/BasenameReturnTypeProvider.php', 'Psalm\\Internal\\Provider\\ReturnTypeProvider\\ClosureFromCallableReturnTypeProvider' => __DIR__ . '/../..' . '/src/Psalm/Internal/Provider/ReturnTypeProvider/ClosureFromCallableReturnTypeProvider.php', 'Psalm\\Internal\\Provider\\ReturnTypeProvider\\DateReturnTypeProvider' => __DIR__ . '/../..' . '/src/Psalm/Internal/Provider/ReturnTypeProvider/DateReturnTypeProvider.php', 'Psalm\\Internal\\Provider\\ReturnTypeProvider\\DateTimeModifyReturnTypeProvider' => __DIR__ . '/../..' . '/src/Psalm/Internal/Provider/ReturnTypeProvider/DateTimeModifyReturnTypeProvider.php', 'Psalm\\Internal\\Provider\\ReturnTypeProvider\\DirnameReturnTypeProvider' => __DIR__ . '/../..' . '/src/Psalm/Internal/Provider/ReturnTypeProvider/DirnameReturnTypeProvider.php', 'Psalm\\Internal\\Provider\\ReturnTypeProvider\\DomNodeAppendChild' => __DIR__ . '/../..' . '/src/Psalm/Internal/Provider/ReturnTypeProvider/DomNodeAppendChild.php', 'Psalm\\Internal\\Provider\\ReturnTypeProvider\\FilterInputReturnTypeProvider' => __DIR__ . '/../..' . '/src/Psalm/Internal/Provider/ReturnTypeProvider/FilterInputReturnTypeProvider.php', 'Psalm\\Internal\\Provider\\ReturnTypeProvider\\FilterUtils' => __DIR__ . '/../..' . '/src/Psalm/Internal/Provider/ReturnTypeProvider/FilterUtils.php', 'Psalm\\Internal\\Provider\\ReturnTypeProvider\\FilterVarReturnTypeProvider' => __DIR__ . '/../..' . '/src/Psalm/Internal/Provider/ReturnTypeProvider/FilterVarReturnTypeProvider.php', 'Psalm\\Internal\\Provider\\ReturnTypeProvider\\FirstArgStringReturnTypeProvider' => __DIR__ . '/../..' . '/src/Psalm/Internal/Provider/ReturnTypeProvider/FirstArgStringReturnTypeProvider.php', 'Psalm\\Internal\\Provider\\ReturnTypeProvider\\GetClassMethodsReturnTypeProvider' => __DIR__ . '/../..' . '/src/Psalm/Internal/Provider/ReturnTypeProvider/GetClassMethodsReturnTypeProvider.php', 'Psalm\\Internal\\Provider\\ReturnTypeProvider\\GetObjectVarsReturnTypeProvider' => __DIR__ . '/../..' . '/src/Psalm/Internal/Provider/ReturnTypeProvider/GetObjectVarsReturnTypeProvider.php', 'Psalm\\Internal\\Provider\\ReturnTypeProvider\\HexdecReturnTypeProvider' => __DIR__ . '/../..' . '/src/Psalm/Internal/Provider/ReturnTypeProvider/HexdecReturnTypeProvider.php', 'Psalm\\Internal\\Provider\\ReturnTypeProvider\\ImagickPixelColorReturnTypeProvider' => __DIR__ . '/../..' . '/src/Psalm/Internal/Provider/ReturnTypeProvider/ImagickPixelColorReturnTypeProvider.php', 'Psalm\\Internal\\Provider\\ReturnTypeProvider\\InArrayReturnTypeProvider' => __DIR__ . '/../..' . '/src/Psalm/Internal/Provider/ReturnTypeProvider/InArrayReturnTypeProvider.php', 'Psalm\\Internal\\Provider\\ReturnTypeProvider\\IteratorToArrayReturnTypeProvider' => __DIR__ . '/../..' . '/src/Psalm/Internal/Provider/ReturnTypeProvider/IteratorToArrayReturnTypeProvider.php', 'Psalm\\Internal\\Provider\\ReturnTypeProvider\\MbInternalEncodingReturnTypeProvider' => __DIR__ . '/../..' . '/src/Psalm/Internal/Provider/ReturnTypeProvider/MbInternalEncodingReturnTypeProvider.php', 'Psalm\\Internal\\Provider\\ReturnTypeProvider\\MinMaxReturnTypeProvider' => __DIR__ . '/../..' . '/src/Psalm/Internal/Provider/ReturnTypeProvider/MinMaxReturnTypeProvider.php', 'Psalm\\Internal\\Provider\\ReturnTypeProvider\\MktimeReturnTypeProvider' => __DIR__ . '/../..' . '/src/Psalm/Internal/Provider/ReturnTypeProvider/MktimeReturnTypeProvider.php', 'Psalm\\Internal\\Provider\\ReturnTypeProvider\\ParseUrlReturnTypeProvider' => __DIR__ . '/../..' . '/src/Psalm/Internal/Provider/ReturnTypeProvider/ParseUrlReturnTypeProvider.php', 'Psalm\\Internal\\Provider\\ReturnTypeProvider\\PdoStatementReturnTypeProvider' => __DIR__ . '/../..' . '/src/Psalm/Internal/Provider/ReturnTypeProvider/PdoStatementReturnTypeProvider.php', 'Psalm\\Internal\\Provider\\ReturnTypeProvider\\PdoStatementSetFetchMode' => __DIR__ . '/../..' . '/src/Psalm/Internal/Provider/ReturnTypeProvider/PdoStatementSetFetchMode.php', 'Psalm\\Internal\\Provider\\ReturnTypeProvider\\PowReturnTypeProvider' => __DIR__ . '/../..' . '/src/Psalm/Internal/Provider/ReturnTypeProvider/PowReturnTypeProvider.php', 'Psalm\\Internal\\Provider\\ReturnTypeProvider\\RandReturnTypeProvider' => __DIR__ . '/../..' . '/src/Psalm/Internal/Provider/ReturnTypeProvider/RandReturnTypeProvider.php', 'Psalm\\Internal\\Provider\\ReturnTypeProvider\\RoundReturnTypeProvider' => __DIR__ . '/../..' . '/src/Psalm/Internal/Provider/ReturnTypeProvider/RoundReturnTypeProvider.php', 'Psalm\\Internal\\Provider\\ReturnTypeProvider\\SprintfReturnTypeProvider' => __DIR__ . '/../..' . '/src/Psalm/Internal/Provider/ReturnTypeProvider/SprintfReturnTypeProvider.php', 'Psalm\\Internal\\Provider\\ReturnTypeProvider\\StrReplaceReturnTypeProvider' => __DIR__ . '/../..' . '/src/Psalm/Internal/Provider/ReturnTypeProvider/StrReplaceReturnTypeProvider.php', 'Psalm\\Internal\\Provider\\ReturnTypeProvider\\StrTrReturnTypeProvider' => __DIR__ . '/../..' . '/src/Psalm/Internal/Provider/ReturnTypeProvider/StrTrReturnTypeProvider.php', 'Psalm\\Internal\\Provider\\ReturnTypeProvider\\TriggerErrorReturnTypeProvider' => __DIR__ . '/../..' . '/src/Psalm/Internal/Provider/ReturnTypeProvider/TriggerErrorReturnTypeProvider.php', 'Psalm\\Internal\\Provider\\ReturnTypeProvider\\VersionCompareReturnTypeProvider' => __DIR__ . '/../..' . '/src/Psalm/Internal/Provider/ReturnTypeProvider/VersionCompareReturnTypeProvider.php', 'Psalm\\Internal\\Provider\\StatementsProvider' => __DIR__ . '/../..' . '/src/Psalm/Internal/Provider/StatementsProvider.php', 'Psalm\\Internal\\ReferenceConstraint' => __DIR__ . '/../..' . '/src/Psalm/Internal/ReferenceConstraint.php', 'Psalm\\Internal\\RuntimeCaches' => __DIR__ . '/../..' . '/src/Psalm/Internal/RuntimeCaches.php', 'Psalm\\Internal\\Scanner\\ClassLikeDocblockComment' => __DIR__ . '/../..' . '/src/Psalm/Internal/Scanner/ClassLikeDocblockComment.php', 'Psalm\\Internal\\Scanner\\DocblockParser' => __DIR__ . '/../..' . '/src/Psalm/Internal/Scanner/DocblockParser.php', 'Psalm\\Internal\\Scanner\\FileScanner' => __DIR__ . '/../..' . '/src/Psalm/Internal/Scanner/FileScanner.php', 'Psalm\\Internal\\Scanner\\FunctionDocblockComment' => __DIR__ . '/../..' . '/src/Psalm/Internal/Scanner/FunctionDocblockComment.php', 'Psalm\\Internal\\Scanner\\ParsedDocblock' => __DIR__ . '/../..' . '/src/Psalm/Internal/Scanner/ParsedDocblock.php', 'Psalm\\Internal\\Scanner\\PhpStormMetaScanner' => __DIR__ . '/../..' . '/src/Psalm/Internal/Scanner/PhpStormMetaScanner.php', 'Psalm\\Internal\\Scanner\\UnresolvedConstantComponent' => __DIR__ . '/../..' . '/src/Psalm/Internal/Scanner/UnresolvedConstantComponent.php', 'Psalm\\Internal\\Scanner\\UnresolvedConstant\\ArrayOffsetFetch' => __DIR__ . '/../..' . '/src/Psalm/Internal/Scanner/UnresolvedConstant/ArrayOffsetFetch.php', 'Psalm\\Internal\\Scanner\\UnresolvedConstant\\ArraySpread' => __DIR__ . '/../..' . '/src/Psalm/Internal/Scanner/UnresolvedConstant/ArraySpread.php', 'Psalm\\Internal\\Scanner\\UnresolvedConstant\\ArrayValue' => __DIR__ . '/../..' . '/src/Psalm/Internal/Scanner/UnresolvedConstant/ArrayValue.php', 'Psalm\\Internal\\Scanner\\UnresolvedConstant\\ClassConstant' => __DIR__ . '/../..' . '/src/Psalm/Internal/Scanner/UnresolvedConstant/ClassConstant.php', 'Psalm\\Internal\\Scanner\\UnresolvedConstant\\Constant' => __DIR__ . '/../..' . '/src/Psalm/Internal/Scanner/UnresolvedConstant/Constant.php', 'Psalm\\Internal\\Scanner\\UnresolvedConstant\\EnumNameFetch' => __DIR__ . '/../..' . '/src/Psalm/Internal/Scanner/UnresolvedConstant/EnumNameFetch.php', 'Psalm\\Internal\\Scanner\\UnresolvedConstant\\EnumPropertyFetch' => __DIR__ . '/../..' . '/src/Psalm/Internal/Scanner/UnresolvedConstant/EnumPropertyFetch.php', 'Psalm\\Internal\\Scanner\\UnresolvedConstant\\EnumValueFetch' => __DIR__ . '/../..' . '/src/Psalm/Internal/Scanner/UnresolvedConstant/EnumValueFetch.php', 'Psalm\\Internal\\Scanner\\UnresolvedConstant\\KeyValuePair' => __DIR__ . '/../..' . '/src/Psalm/Internal/Scanner/UnresolvedConstant/KeyValuePair.php', 'Psalm\\Internal\\Scanner\\UnresolvedConstant\\ScalarValue' => __DIR__ . '/../..' . '/src/Psalm/Internal/Scanner/UnresolvedConstant/ScalarValue.php', 'Psalm\\Internal\\Scanner\\UnresolvedConstant\\UnresolvedAdditionOp' => __DIR__ . '/../..' . '/src/Psalm/Internal/Scanner/UnresolvedConstant/UnresolvedAdditionOp.php', 'Psalm\\Internal\\Scanner\\UnresolvedConstant\\UnresolvedBinaryOp' => __DIR__ . '/../..' . '/src/Psalm/Internal/Scanner/UnresolvedConstant/UnresolvedBinaryOp.php', 'Psalm\\Internal\\Scanner\\UnresolvedConstant\\UnresolvedBitwiseAnd' => __DIR__ . '/../..' . '/src/Psalm/Internal/Scanner/UnresolvedConstant/UnresolvedBitwiseAnd.php', 'Psalm\\Internal\\Scanner\\UnresolvedConstant\\UnresolvedBitwiseOr' => __DIR__ . '/../..' . '/src/Psalm/Internal/Scanner/UnresolvedConstant/UnresolvedBitwiseOr.php', 'Psalm\\Internal\\Scanner\\UnresolvedConstant\\UnresolvedBitwiseXor' => __DIR__ . '/../..' . '/src/Psalm/Internal/Scanner/UnresolvedConstant/UnresolvedBitwiseXor.php', 'Psalm\\Internal\\Scanner\\UnresolvedConstant\\UnresolvedConcatOp' => __DIR__ . '/../..' . '/src/Psalm/Internal/Scanner/UnresolvedConstant/UnresolvedConcatOp.php', 'Psalm\\Internal\\Scanner\\UnresolvedConstant\\UnresolvedDivisionOp' => __DIR__ . '/../..' . '/src/Psalm/Internal/Scanner/UnresolvedConstant/UnresolvedDivisionOp.php', 'Psalm\\Internal\\Scanner\\UnresolvedConstant\\UnresolvedMultiplicationOp' => __DIR__ . '/../..' . '/src/Psalm/Internal/Scanner/UnresolvedConstant/UnresolvedMultiplicationOp.php', 'Psalm\\Internal\\Scanner\\UnresolvedConstant\\UnresolvedSubtractionOp' => __DIR__ . '/../..' . '/src/Psalm/Internal/Scanner/UnresolvedConstant/UnresolvedSubtractionOp.php', 'Psalm\\Internal\\Scanner\\UnresolvedConstant\\UnresolvedTernary' => __DIR__ . '/../..' . '/src/Psalm/Internal/Scanner/UnresolvedConstant/UnresolvedTernary.php', 'Psalm\\Internal\\Scanner\\VarDocblockComment' => __DIR__ . '/../..' . '/src/Psalm/Internal/Scanner/VarDocblockComment.php', 'Psalm\\Internal\\Scope\\CaseScope' => __DIR__ . '/../..' . '/src/Psalm/Internal/Scope/CaseScope.php', 'Psalm\\Internal\\Scope\\FinallyScope' => __DIR__ . '/../..' . '/src/Psalm/Internal/Scope/FinallyScope.php', 'Psalm\\Internal\\Scope\\IfConditionalScope' => __DIR__ . '/../..' . '/src/Psalm/Internal/Scope/IfConditionalScope.php', 'Psalm\\Internal\\Scope\\IfScope' => __DIR__ . '/../..' . '/src/Psalm/Internal/Scope/IfScope.php', 'Psalm\\Internal\\Scope\\LoopScope' => __DIR__ . '/../..' . '/src/Psalm/Internal/Scope/LoopScope.php', 'Psalm\\Internal\\Scope\\SwitchScope' => __DIR__ . '/../..' . '/src/Psalm/Internal/Scope/SwitchScope.php', 'Psalm\\Internal\\Stubs\\Generator\\ClassLikeStubGenerator' => __DIR__ . '/../..' . '/src/Psalm/Internal/Stubs/Generator/ClassLikeStubGenerator.php', 'Psalm\\Internal\\Stubs\\Generator\\StubsGenerator' => __DIR__ . '/../..' . '/src/Psalm/Internal/Stubs/Generator/StubsGenerator.php', 'Psalm\\Internal\\TypeVisitor\\CanContainObjectTypeVisitor' => __DIR__ . '/../..' . '/src/Psalm/Internal/TypeVisitor/CanContainObjectTypeVisitor.php', 'Psalm\\Internal\\TypeVisitor\\ClasslikeReplacer' => __DIR__ . '/../..' . '/src/Psalm/Internal/TypeVisitor/ClasslikeReplacer.php', 'Psalm\\Internal\\TypeVisitor\\ContainsClassLikeVisitor' => __DIR__ . '/../..' . '/src/Psalm/Internal/TypeVisitor/ContainsClassLikeVisitor.php', 'Psalm\\Internal\\TypeVisitor\\ContainsLiteralVisitor' => __DIR__ . '/../..' . '/src/Psalm/Internal/TypeVisitor/ContainsLiteralVisitor.php', 'Psalm\\Internal\\TypeVisitor\\ContainsStaticVisitor' => __DIR__ . '/../..' . '/src/Psalm/Internal/TypeVisitor/ContainsStaticVisitor.php', 'Psalm\\Internal\\TypeVisitor\\FromDocblockSetter' => __DIR__ . '/../..' . '/src/Psalm/Internal/TypeVisitor/FromDocblockSetter.php', 'Psalm\\Internal\\TypeVisitor\\TemplateTypeCollector' => __DIR__ . '/../..' . '/src/Psalm/Internal/TypeVisitor/TemplateTypeCollector.php', 'Psalm\\Internal\\TypeVisitor\\TypeChecker' => __DIR__ . '/../..' . '/src/Psalm/Internal/TypeVisitor/TypeChecker.php', 'Psalm\\Internal\\TypeVisitor\\TypeLocalizer' => __DIR__ . '/../..' . '/src/Psalm/Internal/TypeVisitor/TypeLocalizer.php', 'Psalm\\Internal\\TypeVisitor\\TypeScanner' => __DIR__ . '/../..' . '/src/Psalm/Internal/TypeVisitor/TypeScanner.php', 'Psalm\\Internal\\Type\\ArrayType' => __DIR__ . '/../..' . '/src/Psalm/Internal/Type/ArrayType.php', 'Psalm\\Internal\\Type\\AssertionReconciler' => __DIR__ . '/../..' . '/src/Psalm/Internal/Type/AssertionReconciler.php', 'Psalm\\Internal\\Type\\ClosedInheritanceToUnion' => __DIR__ . '/../..' . '/src/Psalm/Internal/Type/ClosedInheritanceToUnion.php', 'Psalm\\Internal\\Type\\Comparator\\ArrayTypeComparator' => __DIR__ . '/../..' . '/src/Psalm/Internal/Type/Comparator/ArrayTypeComparator.php', 'Psalm\\Internal\\Type\\Comparator\\AtomicTypeComparator' => __DIR__ . '/../..' . '/src/Psalm/Internal/Type/Comparator/AtomicTypeComparator.php', 'Psalm\\Internal\\Type\\Comparator\\CallableTypeComparator' => __DIR__ . '/../..' . '/src/Psalm/Internal/Type/Comparator/CallableTypeComparator.php', 'Psalm\\Internal\\Type\\Comparator\\ClassLikeStringComparator' => __DIR__ . '/../..' . '/src/Psalm/Internal/Type/Comparator/ClassLikeStringComparator.php', 'Psalm\\Internal\\Type\\Comparator\\GenericTypeComparator' => __DIR__ . '/../..' . '/src/Psalm/Internal/Type/Comparator/GenericTypeComparator.php', 'Psalm\\Internal\\Type\\Comparator\\IntegerRangeComparator' => __DIR__ . '/../..' . '/src/Psalm/Internal/Type/Comparator/IntegerRangeComparator.php', 'Psalm\\Internal\\Type\\Comparator\\KeyedArrayComparator' => __DIR__ . '/../..' . '/src/Psalm/Internal/Type/Comparator/KeyedArrayComparator.php', 'Psalm\\Internal\\Type\\Comparator\\ObjectComparator' => __DIR__ . '/../..' . '/src/Psalm/Internal/Type/Comparator/ObjectComparator.php', 'Psalm\\Internal\\Type\\Comparator\\ScalarTypeComparator' => __DIR__ . '/../..' . '/src/Psalm/Internal/Type/Comparator/ScalarTypeComparator.php', 'Psalm\\Internal\\Type\\Comparator\\TypeComparisonResult' => __DIR__ . '/../..' . '/src/Psalm/Internal/Type/Comparator/TypeComparisonResult.php', 'Psalm\\Internal\\Type\\Comparator\\UnionTypeComparator' => __DIR__ . '/../..' . '/src/Psalm/Internal/Type/Comparator/UnionTypeComparator.php', 'Psalm\\Internal\\Type\\NegatedAssertionReconciler' => __DIR__ . '/../..' . '/src/Psalm/Internal/Type/NegatedAssertionReconciler.php', 'Psalm\\Internal\\Type\\ParseTree' => __DIR__ . '/../..' . '/src/Psalm/Internal/Type/ParseTree.php', 'Psalm\\Internal\\Type\\ParseTreeCreator' => __DIR__ . '/../..' . '/src/Psalm/Internal/Type/ParseTreeCreator.php', 'Psalm\\Internal\\Type\\ParseTree\\CallableParamTree' => __DIR__ . '/../..' . '/src/Psalm/Internal/Type/ParseTree/CallableParamTree.php', 'Psalm\\Internal\\Type\\ParseTree\\CallableTree' => __DIR__ . '/../..' . '/src/Psalm/Internal/Type/ParseTree/CallableTree.php', 'Psalm\\Internal\\Type\\ParseTree\\CallableWithReturnTypeTree' => __DIR__ . '/../..' . '/src/Psalm/Internal/Type/ParseTree/CallableWithReturnTypeTree.php', 'Psalm\\Internal\\Type\\ParseTree\\ConditionalTree' => __DIR__ . '/../..' . '/src/Psalm/Internal/Type/ParseTree/ConditionalTree.php', 'Psalm\\Internal\\Type\\ParseTree\\EncapsulationTree' => __DIR__ . '/../..' . '/src/Psalm/Internal/Type/ParseTree/EncapsulationTree.php', 'Psalm\\Internal\\Type\\ParseTree\\FieldEllipsis' => __DIR__ . '/../..' . '/src/Psalm/Internal/Type/ParseTree/FieldEllipsis.php', 'Psalm\\Internal\\Type\\ParseTree\\GenericTree' => __DIR__ . '/../..' . '/src/Psalm/Internal/Type/ParseTree/GenericTree.php', 'Psalm\\Internal\\Type\\ParseTree\\IndexedAccessTree' => __DIR__ . '/../..' . '/src/Psalm/Internal/Type/ParseTree/IndexedAccessTree.php', 'Psalm\\Internal\\Type\\ParseTree\\IntersectionTree' => __DIR__ . '/../..' . '/src/Psalm/Internal/Type/ParseTree/IntersectionTree.php', 'Psalm\\Internal\\Type\\ParseTree\\KeyedArrayPropertyTree' => __DIR__ . '/../..' . '/src/Psalm/Internal/Type/ParseTree/KeyedArrayPropertyTree.php', 'Psalm\\Internal\\Type\\ParseTree\\KeyedArrayTree' => __DIR__ . '/../..' . '/src/Psalm/Internal/Type/ParseTree/KeyedArrayTree.php', 'Psalm\\Internal\\Type\\ParseTree\\MethodParamTree' => __DIR__ . '/../..' . '/src/Psalm/Internal/Type/ParseTree/MethodParamTree.php', 'Psalm\\Internal\\Type\\ParseTree\\MethodTree' => __DIR__ . '/../..' . '/src/Psalm/Internal/Type/ParseTree/MethodTree.php', 'Psalm\\Internal\\Type\\ParseTree\\MethodWithReturnTypeTree' => __DIR__ . '/../..' . '/src/Psalm/Internal/Type/ParseTree/MethodWithReturnTypeTree.php', 'Psalm\\Internal\\Type\\ParseTree\\NullableTree' => __DIR__ . '/../..' . '/src/Psalm/Internal/Type/ParseTree/NullableTree.php', 'Psalm\\Internal\\Type\\ParseTree\\Root' => __DIR__ . '/../..' . '/src/Psalm/Internal/Type/ParseTree/Root.php', 'Psalm\\Internal\\Type\\ParseTree\\TemplateAsTree' => __DIR__ . '/../..' . '/src/Psalm/Internal/Type/ParseTree/TemplateAsTree.php', 'Psalm\\Internal\\Type\\ParseTree\\TemplateIsTree' => __DIR__ . '/../..' . '/src/Psalm/Internal/Type/ParseTree/TemplateIsTree.php', 'Psalm\\Internal\\Type\\ParseTree\\UnionTree' => __DIR__ . '/../..' . '/src/Psalm/Internal/Type/ParseTree/UnionTree.php', 'Psalm\\Internal\\Type\\ParseTree\\Value' => __DIR__ . '/../..' . '/src/Psalm/Internal/Type/ParseTree/Value.php', 'Psalm\\Internal\\Type\\SimpleAssertionReconciler' => __DIR__ . '/../..' . '/src/Psalm/Internal/Type/SimpleAssertionReconciler.php', 'Psalm\\Internal\\Type\\SimpleNegatedAssertionReconciler' => __DIR__ . '/../..' . '/src/Psalm/Internal/Type/SimpleNegatedAssertionReconciler.php', 'Psalm\\Internal\\Type\\TemplateBound' => __DIR__ . '/../..' . '/src/Psalm/Internal/Type/TemplateBound.php', 'Psalm\\Internal\\Type\\TemplateInferredTypeReplacer' => __DIR__ . '/../..' . '/src/Psalm/Internal/Type/TemplateInferredTypeReplacer.php', 'Psalm\\Internal\\Type\\TemplateResult' => __DIR__ . '/../..' . '/src/Psalm/Internal/Type/TemplateResult.php', 'Psalm\\Internal\\Type\\TemplateStandinTypeReplacer' => __DIR__ . '/../..' . '/src/Psalm/Internal/Type/TemplateStandinTypeReplacer.php', 'Psalm\\Internal\\Type\\TypeAlias' => __DIR__ . '/../..' . '/src/Psalm/Internal/Type/TypeAlias.php', 'Psalm\\Internal\\Type\\TypeAlias\\ClassTypeAlias' => __DIR__ . '/../..' . '/src/Psalm/Internal/Type/TypeAlias/ClassTypeAlias.php', 'Psalm\\Internal\\Type\\TypeAlias\\InlineTypeAlias' => __DIR__ . '/../..' . '/src/Psalm/Internal/Type/TypeAlias/InlineTypeAlias.php', 'Psalm\\Internal\\Type\\TypeAlias\\LinkableTypeAlias' => __DIR__ . '/../..' . '/src/Psalm/Internal/Type/TypeAlias/LinkableTypeAlias.php', 'Psalm\\Internal\\Type\\TypeCombination' => __DIR__ . '/../..' . '/src/Psalm/Internal/Type/TypeCombination.php', 'Psalm\\Internal\\Type\\TypeCombiner' => __DIR__ . '/../..' . '/src/Psalm/Internal/Type/TypeCombiner.php', 'Psalm\\Internal\\Type\\TypeExpander' => __DIR__ . '/../..' . '/src/Psalm/Internal/Type/TypeExpander.php', 'Psalm\\Internal\\Type\\TypeParser' => __DIR__ . '/../..' . '/src/Psalm/Internal/Type/TypeParser.php', 'Psalm\\Internal\\Type\\TypeTokenizer' => __DIR__ . '/../..' . '/src/Psalm/Internal/Type/TypeTokenizer.php', 'Psalm\\Internal\\VersionUtils' => __DIR__ . '/../..' . '/src/Psalm/Internal/VersionUtils.php', 'Psalm\\IssueBuffer' => __DIR__ . '/../..' . '/src/Psalm/IssueBuffer.php', 'Psalm\\Issue\\AbstractInstantiation' => __DIR__ . '/../..' . '/src/Psalm/Issue/AbstractInstantiation.php', 'Psalm\\Issue\\AbstractMethodCall' => __DIR__ . '/../..' . '/src/Psalm/Issue/AbstractMethodCall.php', 'Psalm\\Issue\\AmbiguousConstantInheritance' => __DIR__ . '/../..' . '/src/Psalm/Issue/AmbiguousConstantInheritance.php', 'Psalm\\Issue\\ArgumentIssue' => __DIR__ . '/../..' . '/src/Psalm/Issue/ArgumentIssue.php', 'Psalm\\Issue\\ArgumentTypeCoercion' => __DIR__ . '/../..' . '/src/Psalm/Issue/ArgumentTypeCoercion.php', 'Psalm\\Issue\\AssignmentToVoid' => __DIR__ . '/../..' . '/src/Psalm/Issue/AssignmentToVoid.php', 'Psalm\\Issue\\CheckType' => __DIR__ . '/../..' . '/src/Psalm/Issue/CheckType.php', 'Psalm\\Issue\\CircularReference' => __DIR__ . '/../..' . '/src/Psalm/Issue/CircularReference.php', 'Psalm\\Issue\\ClassConstantIssue' => __DIR__ . '/../..' . '/src/Psalm/Issue/ClassConstantIssue.php', 'Psalm\\Issue\\ClassIssue' => __DIR__ . '/../..' . '/src/Psalm/Issue/ClassIssue.php', 'Psalm\\Issue\\CodeIssue' => __DIR__ . '/../..' . '/src/Psalm/Issue/CodeIssue.php', 'Psalm\\Issue\\ComplexFunction' => __DIR__ . '/../..' . '/src/Psalm/Issue/ComplexFunction.php', 'Psalm\\Issue\\ComplexMethod' => __DIR__ . '/../..' . '/src/Psalm/Issue/ComplexMethod.php', 'Psalm\\Issue\\ConfigIssue' => __DIR__ . '/../..' . '/src/Psalm/Issue/ConfigIssue.php', 'Psalm\\Issue\\ConflictingReferenceConstraint' => __DIR__ . '/../..' . '/src/Psalm/Issue/ConflictingReferenceConstraint.php', 'Psalm\\Issue\\ConstantDeclarationInTrait' => __DIR__ . '/../..' . '/src/Psalm/Issue/ConstantDeclarationInTrait.php', 'Psalm\\Issue\\ConstructorSignatureMismatch' => __DIR__ . '/../..' . '/src/Psalm/Issue/ConstructorSignatureMismatch.php', 'Psalm\\Issue\\ContinueOutsideLoop' => __DIR__ . '/../..' . '/src/Psalm/Issue/ContinueOutsideLoop.php', 'Psalm\\Issue\\DeprecatedClass' => __DIR__ . '/../..' . '/src/Psalm/Issue/DeprecatedClass.php', 'Psalm\\Issue\\DeprecatedConstant' => __DIR__ . '/../..' . '/src/Psalm/Issue/DeprecatedConstant.php', 'Psalm\\Issue\\DeprecatedFunction' => __DIR__ . '/../..' . '/src/Psalm/Issue/DeprecatedFunction.php', 'Psalm\\Issue\\DeprecatedInterface' => __DIR__ . '/../..' . '/src/Psalm/Issue/DeprecatedInterface.php', 'Psalm\\Issue\\DeprecatedMethod' => __DIR__ . '/../..' . '/src/Psalm/Issue/DeprecatedMethod.php', 'Psalm\\Issue\\DeprecatedProperty' => __DIR__ . '/../..' . '/src/Psalm/Issue/DeprecatedProperty.php', 'Psalm\\Issue\\DeprecatedTrait' => __DIR__ . '/../..' . '/src/Psalm/Issue/DeprecatedTrait.php', 'Psalm\\Issue\\DirectConstructorCall' => __DIR__ . '/../..' . '/src/Psalm/Issue/DirectConstructorCall.php', 'Psalm\\Issue\\DocblockTypeContradiction' => __DIR__ . '/../..' . '/src/Psalm/Issue/DocblockTypeContradiction.php', 'Psalm\\Issue\\DuplicateArrayKey' => __DIR__ . '/../..' . '/src/Psalm/Issue/DuplicateArrayKey.php', 'Psalm\\Issue\\DuplicateClass' => __DIR__ . '/../..' . '/src/Psalm/Issue/DuplicateClass.php', 'Psalm\\Issue\\DuplicateConstant' => __DIR__ . '/../..' . '/src/Psalm/Issue/DuplicateConstant.php', 'Psalm\\Issue\\DuplicateEnumCase' => __DIR__ . '/../..' . '/src/Psalm/Issue/DuplicateEnumCase.php', 'Psalm\\Issue\\DuplicateEnumCaseValue' => __DIR__ . '/../..' . '/src/Psalm/Issue/DuplicateEnumCaseValue.php', 'Psalm\\Issue\\DuplicateFunction' => __DIR__ . '/../..' . '/src/Psalm/Issue/DuplicateFunction.php', 'Psalm\\Issue\\DuplicateMethod' => __DIR__ . '/../..' . '/src/Psalm/Issue/DuplicateMethod.php', 'Psalm\\Issue\\DuplicateParam' => __DIR__ . '/../..' . '/src/Psalm/Issue/DuplicateParam.php', 'Psalm\\Issue\\EmptyArrayAccess' => __DIR__ . '/../..' . '/src/Psalm/Issue/EmptyArrayAccess.php', 'Psalm\\Issue\\ExtensionRequirementViolation' => __DIR__ . '/../..' . '/src/Psalm/Issue/ExtensionRequirementViolation.php', 'Psalm\\Issue\\FalsableReturnStatement' => __DIR__ . '/../..' . '/src/Psalm/Issue/FalsableReturnStatement.php', 'Psalm\\Issue\\FalseOperand' => __DIR__ . '/../..' . '/src/Psalm/Issue/FalseOperand.php', 'Psalm\\Issue\\ForbiddenCode' => __DIR__ . '/../..' . '/src/Psalm/Issue/ForbiddenCode.php', 'Psalm\\Issue\\FunctionIssue' => __DIR__ . '/../..' . '/src/Psalm/Issue/FunctionIssue.php', 'Psalm\\Issue\\IfThisIsMismatch' => __DIR__ . '/../..' . '/src/Psalm/Issue/IfThisIsMismatch.php', 'Psalm\\Issue\\ImplementationRequirementViolation' => __DIR__ . '/../..' . '/src/Psalm/Issue/ImplementationRequirementViolation.php', 'Psalm\\Issue\\ImplementedParamTypeMismatch' => __DIR__ . '/../..' . '/src/Psalm/Issue/ImplementedParamTypeMismatch.php', 'Psalm\\Issue\\ImplementedReturnTypeMismatch' => __DIR__ . '/../..' . '/src/Psalm/Issue/ImplementedReturnTypeMismatch.php', 'Psalm\\Issue\\ImplicitToStringCast' => __DIR__ . '/../..' . '/src/Psalm/Issue/ImplicitToStringCast.php', 'Psalm\\Issue\\ImpureByReferenceAssignment' => __DIR__ . '/../..' . '/src/Psalm/Issue/ImpureByReferenceAssignment.php', 'Psalm\\Issue\\ImpureFunctionCall' => __DIR__ . '/../..' . '/src/Psalm/Issue/ImpureFunctionCall.php', 'Psalm\\Issue\\ImpureMethodCall' => __DIR__ . '/../..' . '/src/Psalm/Issue/ImpureMethodCall.php', 'Psalm\\Issue\\ImpurePropertyAssignment' => __DIR__ . '/../..' . '/src/Psalm/Issue/ImpurePropertyAssignment.php', 'Psalm\\Issue\\ImpurePropertyFetch' => __DIR__ . '/../..' . '/src/Psalm/Issue/ImpurePropertyFetch.php', 'Psalm\\Issue\\ImpureStaticProperty' => __DIR__ . '/../..' . '/src/Psalm/Issue/ImpureStaticProperty.php', 'Psalm\\Issue\\ImpureStaticVariable' => __DIR__ . '/../..' . '/src/Psalm/Issue/ImpureStaticVariable.php', 'Psalm\\Issue\\ImpureVariable' => __DIR__ . '/../..' . '/src/Psalm/Issue/ImpureVariable.php', 'Psalm\\Issue\\InaccessibleClassConstant' => __DIR__ . '/../..' . '/src/Psalm/Issue/InaccessibleClassConstant.php', 'Psalm\\Issue\\InaccessibleMethod' => __DIR__ . '/../..' . '/src/Psalm/Issue/InaccessibleMethod.php', 'Psalm\\Issue\\InaccessibleProperty' => __DIR__ . '/../..' . '/src/Psalm/Issue/InaccessibleProperty.php', 'Psalm\\Issue\\InheritorViolation' => __DIR__ . '/../..' . '/src/Psalm/Issue/InheritorViolation.php', 'Psalm\\Issue\\InterfaceInstantiation' => __DIR__ . '/../..' . '/src/Psalm/Issue/InterfaceInstantiation.php', 'Psalm\\Issue\\InternalClass' => __DIR__ . '/../..' . '/src/Psalm/Issue/InternalClass.php', 'Psalm\\Issue\\InternalMethod' => __DIR__ . '/../..' . '/src/Psalm/Issue/InternalMethod.php', 'Psalm\\Issue\\InternalProperty' => __DIR__ . '/../..' . '/src/Psalm/Issue/InternalProperty.php', 'Psalm\\Issue\\InvalidArgument' => __DIR__ . '/../..' . '/src/Psalm/Issue/InvalidArgument.php', 'Psalm\\Issue\\InvalidArrayAccess' => __DIR__ . '/../..' . '/src/Psalm/Issue/InvalidArrayAccess.php', 'Psalm\\Issue\\InvalidArrayAssignment' => __DIR__ . '/../..' . '/src/Psalm/Issue/InvalidArrayAssignment.php', 'Psalm\\Issue\\InvalidArrayOffset' => __DIR__ . '/../..' . '/src/Psalm/Issue/InvalidArrayOffset.php', 'Psalm\\Issue\\InvalidAttribute' => __DIR__ . '/../..' . '/src/Psalm/Issue/InvalidAttribute.php', 'Psalm\\Issue\\InvalidCast' => __DIR__ . '/../..' . '/src/Psalm/Issue/InvalidCast.php', 'Psalm\\Issue\\InvalidCatch' => __DIR__ . '/../..' . '/src/Psalm/Issue/InvalidCatch.php', 'Psalm\\Issue\\InvalidClass' => __DIR__ . '/../..' . '/src/Psalm/Issue/InvalidClass.php', 'Psalm\\Issue\\InvalidClassConstantType' => __DIR__ . '/../..' . '/src/Psalm/Issue/InvalidClassConstantType.php', 'Psalm\\Issue\\InvalidClone' => __DIR__ . '/../..' . '/src/Psalm/Issue/InvalidClone.php', 'Psalm\\Issue\\InvalidConstantAssignmentValue' => __DIR__ . '/../..' . '/src/Psalm/Issue/InvalidConstantAssignmentValue.php', 'Psalm\\Issue\\InvalidDocblock' => __DIR__ . '/../..' . '/src/Psalm/Issue/InvalidDocblock.php', 'Psalm\\Issue\\InvalidDocblockParamName' => __DIR__ . '/../..' . '/src/Psalm/Issue/InvalidDocblockParamName.php', 'Psalm\\Issue\\InvalidEnumBackingType' => __DIR__ . '/../..' . '/src/Psalm/Issue/InvalidEnumBackingType.php', 'Psalm\\Issue\\InvalidEnumCaseValue' => __DIR__ . '/../..' . '/src/Psalm/Issue/InvalidEnumCaseValue.php', 'Psalm\\Issue\\InvalidEnumMethod' => __DIR__ . '/../..' . '/src/Psalm/Issue/InvalidEnumMethod.php', 'Psalm\\Issue\\InvalidExtendClass' => __DIR__ . '/../..' . '/src/Psalm/Issue/InvalidExtendClass.php', 'Psalm\\Issue\\InvalidFalsableReturnType' => __DIR__ . '/../..' . '/src/Psalm/Issue/InvalidFalsableReturnType.php', 'Psalm\\Issue\\InvalidFunctionCall' => __DIR__ . '/../..' . '/src/Psalm/Issue/InvalidFunctionCall.php', 'Psalm\\Issue\\InvalidGlobal' => __DIR__ . '/../..' . '/src/Psalm/Issue/InvalidGlobal.php', 'Psalm\\Issue\\InvalidInterfaceImplementation' => __DIR__ . '/../..' . '/src/Psalm/Issue/InvalidInterfaceImplementation.php', 'Psalm\\Issue\\InvalidIterator' => __DIR__ . '/../..' . '/src/Psalm/Issue/InvalidIterator.php', 'Psalm\\Issue\\InvalidLiteralArgument' => __DIR__ . '/../..' . '/src/Psalm/Issue/InvalidLiteralArgument.php', 'Psalm\\Issue\\InvalidMethodCall' => __DIR__ . '/../..' . '/src/Psalm/Issue/InvalidMethodCall.php', 'Psalm\\Issue\\InvalidNamedArgument' => __DIR__ . '/../..' . '/src/Psalm/Issue/InvalidNamedArgument.php', 'Psalm\\Issue\\InvalidNullableReturnType' => __DIR__ . '/../..' . '/src/Psalm/Issue/InvalidNullableReturnType.php', 'Psalm\\Issue\\InvalidOperand' => __DIR__ . '/../..' . '/src/Psalm/Issue/InvalidOperand.php', 'Psalm\\Issue\\InvalidOverride' => __DIR__ . '/../..' . '/src/Psalm/Issue/InvalidOverride.php', 'Psalm\\Issue\\InvalidParamDefault' => __DIR__ . '/../..' . '/src/Psalm/Issue/InvalidParamDefault.php', 'Psalm\\Issue\\InvalidParent' => __DIR__ . '/../..' . '/src/Psalm/Issue/InvalidParent.php', 'Psalm\\Issue\\InvalidPassByReference' => __DIR__ . '/../..' . '/src/Psalm/Issue/InvalidPassByReference.php', 'Psalm\\Issue\\InvalidPropertyAssignment' => __DIR__ . '/../..' . '/src/Psalm/Issue/InvalidPropertyAssignment.php', 'Psalm\\Issue\\InvalidPropertyAssignmentValue' => __DIR__ . '/../..' . '/src/Psalm/Issue/InvalidPropertyAssignmentValue.php', 'Psalm\\Issue\\InvalidPropertyFetch' => __DIR__ . '/../..' . '/src/Psalm/Issue/InvalidPropertyFetch.php', 'Psalm\\Issue\\InvalidReturnStatement' => __DIR__ . '/../..' . '/src/Psalm/Issue/InvalidReturnStatement.php', 'Psalm\\Issue\\InvalidReturnType' => __DIR__ . '/../..' . '/src/Psalm/Issue/InvalidReturnType.php', 'Psalm\\Issue\\InvalidScalarArgument' => __DIR__ . '/../..' . '/src/Psalm/Issue/InvalidScalarArgument.php', 'Psalm\\Issue\\InvalidScope' => __DIR__ . '/../..' . '/src/Psalm/Issue/InvalidScope.php', 'Psalm\\Issue\\InvalidStaticInvocation' => __DIR__ . '/../..' . '/src/Psalm/Issue/InvalidStaticInvocation.php', 'Psalm\\Issue\\InvalidStringClass' => __DIR__ . '/../..' . '/src/Psalm/Issue/InvalidStringClass.php', 'Psalm\\Issue\\InvalidTemplateParam' => __DIR__ . '/../..' . '/src/Psalm/Issue/InvalidTemplateParam.php', 'Psalm\\Issue\\InvalidThrow' => __DIR__ . '/../..' . '/src/Psalm/Issue/InvalidThrow.php', 'Psalm\\Issue\\InvalidToString' => __DIR__ . '/../..' . '/src/Psalm/Issue/InvalidToString.php', 'Psalm\\Issue\\InvalidTraversableImplementation' => __DIR__ . '/../..' . '/src/Psalm/Issue/InvalidTraversableImplementation.php', 'Psalm\\Issue\\InvalidTypeImport' => __DIR__ . '/../..' . '/src/Psalm/Issue/InvalidTypeImport.php', 'Psalm\\Issue\\LessSpecificClassConstantType' => __DIR__ . '/../..' . '/src/Psalm/Issue/LessSpecificClassConstantType.php', 'Psalm\\Issue\\LessSpecificImplementedReturnType' => __DIR__ . '/../..' . '/src/Psalm/Issue/LessSpecificImplementedReturnType.php', 'Psalm\\Issue\\LessSpecificReturnStatement' => __DIR__ . '/../..' . '/src/Psalm/Issue/LessSpecificReturnStatement.php', 'Psalm\\Issue\\LessSpecificReturnType' => __DIR__ . '/../..' . '/src/Psalm/Issue/LessSpecificReturnType.php', 'Psalm\\Issue\\LoopInvalidation' => __DIR__ . '/../..' . '/src/Psalm/Issue/LoopInvalidation.php', 'Psalm\\Issue\\MethodIssue' => __DIR__ . '/../..' . '/src/Psalm/Issue/MethodIssue.php', 'Psalm\\Issue\\MethodSignatureMismatch' => __DIR__ . '/../..' . '/src/Psalm/Issue/MethodSignatureMismatch.php', 'Psalm\\Issue\\MethodSignatureMustOmitReturnType' => __DIR__ . '/../..' . '/src/Psalm/Issue/MethodSignatureMustOmitReturnType.php', 'Psalm\\Issue\\MethodSignatureMustProvideReturnType' => __DIR__ . '/../..' . '/src/Psalm/Issue/MethodSignatureMustProvideReturnType.php', 'Psalm\\Issue\\MismatchingDocblockParamType' => __DIR__ . '/../..' . '/src/Psalm/Issue/MismatchingDocblockParamType.php', 'Psalm\\Issue\\MismatchingDocblockPropertyType' => __DIR__ . '/../..' . '/src/Psalm/Issue/MismatchingDocblockPropertyType.php', 'Psalm\\Issue\\MismatchingDocblockReturnType' => __DIR__ . '/../..' . '/src/Psalm/Issue/MismatchingDocblockReturnType.php', 'Psalm\\Issue\\MissingClassConstType' => __DIR__ . '/../..' . '/src/Psalm/Issue/MissingClassConstType.php', 'Psalm\\Issue\\MissingClosureParamType' => __DIR__ . '/../..' . '/src/Psalm/Issue/MissingClosureParamType.php', 'Psalm\\Issue\\MissingClosureReturnType' => __DIR__ . '/../..' . '/src/Psalm/Issue/MissingClosureReturnType.php', 'Psalm\\Issue\\MissingConstructor' => __DIR__ . '/../..' . '/src/Psalm/Issue/MissingConstructor.php', 'Psalm\\Issue\\MissingDependency' => __DIR__ . '/../..' . '/src/Psalm/Issue/MissingDependency.php', 'Psalm\\Issue\\MissingDocblockType' => __DIR__ . '/../..' . '/src/Psalm/Issue/MissingDocblockType.php', 'Psalm\\Issue\\MissingFile' => __DIR__ . '/../..' . '/src/Psalm/Issue/MissingFile.php', 'Psalm\\Issue\\MissingImmutableAnnotation' => __DIR__ . '/../..' . '/src/Psalm/Issue/MissingImmutableAnnotation.php', 'Psalm\\Issue\\MissingOverrideAttribute' => __DIR__ . '/../..' . '/src/Psalm/Issue/MissingOverrideAttribute.php', 'Psalm\\Issue\\MissingParamType' => __DIR__ . '/../..' . '/src/Psalm/Issue/MissingParamType.php', 'Psalm\\Issue\\MissingPropertyType' => __DIR__ . '/../..' . '/src/Psalm/Issue/MissingPropertyType.php', 'Psalm\\Issue\\MissingReturnType' => __DIR__ . '/../..' . '/src/Psalm/Issue/MissingReturnType.php', 'Psalm\\Issue\\MissingTemplateParam' => __DIR__ . '/../..' . '/src/Psalm/Issue/MissingTemplateParam.php', 'Psalm\\Issue\\MissingThrowsDocblock' => __DIR__ . '/../..' . '/src/Psalm/Issue/MissingThrowsDocblock.php', 'Psalm\\Issue\\MixedArgument' => __DIR__ . '/../..' . '/src/Psalm/Issue/MixedArgument.php', 'Psalm\\Issue\\MixedArgumentTypeCoercion' => __DIR__ . '/../..' . '/src/Psalm/Issue/MixedArgumentTypeCoercion.php', 'Psalm\\Issue\\MixedArrayAccess' => __DIR__ . '/../..' . '/src/Psalm/Issue/MixedArrayAccess.php', 'Psalm\\Issue\\MixedArrayAssignment' => __DIR__ . '/../..' . '/src/Psalm/Issue/MixedArrayAssignment.php', 'Psalm\\Issue\\MixedArrayOffset' => __DIR__ . '/../..' . '/src/Psalm/Issue/MixedArrayOffset.php', 'Psalm\\Issue\\MixedArrayTypeCoercion' => __DIR__ . '/../..' . '/src/Psalm/Issue/MixedArrayTypeCoercion.php', 'Psalm\\Issue\\MixedAssignment' => __DIR__ . '/../..' . '/src/Psalm/Issue/MixedAssignment.php', 'Psalm\\Issue\\MixedClone' => __DIR__ . '/../..' . '/src/Psalm/Issue/MixedClone.php', 'Psalm\\Issue\\MixedFunctionCall' => __DIR__ . '/../..' . '/src/Psalm/Issue/MixedFunctionCall.php', 'Psalm\\Issue\\MixedInferredReturnType' => __DIR__ . '/../..' . '/src/Psalm/Issue/MixedInferredReturnType.php', 'Psalm\\Issue\\MixedIssue' => __DIR__ . '/../..' . '/src/Psalm/Issue/MixedIssue.php', 'Psalm\\Issue\\MixedIssueTrait' => __DIR__ . '/../..' . '/src/Psalm/Issue/MixedIssueTrait.php', 'Psalm\\Issue\\MixedMethodCall' => __DIR__ . '/../..' . '/src/Psalm/Issue/MixedMethodCall.php', 'Psalm\\Issue\\MixedOperand' => __DIR__ . '/../..' . '/src/Psalm/Issue/MixedOperand.php', 'Psalm\\Issue\\MixedPropertyAssignment' => __DIR__ . '/../..' . '/src/Psalm/Issue/MixedPropertyAssignment.php', 'Psalm\\Issue\\MixedPropertyFetch' => __DIR__ . '/../..' . '/src/Psalm/Issue/MixedPropertyFetch.php', 'Psalm\\Issue\\MixedPropertyTypeCoercion' => __DIR__ . '/../..' . '/src/Psalm/Issue/MixedPropertyTypeCoercion.php', 'Psalm\\Issue\\MixedReturnStatement' => __DIR__ . '/../..' . '/src/Psalm/Issue/MixedReturnStatement.php', 'Psalm\\Issue\\MixedReturnTypeCoercion' => __DIR__ . '/../..' . '/src/Psalm/Issue/MixedReturnTypeCoercion.php', 'Psalm\\Issue\\MixedStringOffsetAssignment' => __DIR__ . '/../..' . '/src/Psalm/Issue/MixedStringOffsetAssignment.php', 'Psalm\\Issue\\MoreSpecificImplementedParamType' => __DIR__ . '/../..' . '/src/Psalm/Issue/MoreSpecificImplementedParamType.php', 'Psalm\\Issue\\MoreSpecificReturnType' => __DIR__ . '/../..' . '/src/Psalm/Issue/MoreSpecificReturnType.php', 'Psalm\\Issue\\MutableDependency' => __DIR__ . '/../..' . '/src/Psalm/Issue/MutableDependency.php', 'Psalm\\Issue\\NamedArgumentNotAllowed' => __DIR__ . '/../..' . '/src/Psalm/Issue/NamedArgumentNotAllowed.php', 'Psalm\\Issue\\NoEnumProperties' => __DIR__ . '/../..' . '/src/Psalm/Issue/NoEnumProperties.php', 'Psalm\\Issue\\NoInterfaceProperties' => __DIR__ . '/../..' . '/src/Psalm/Issue/NoInterfaceProperties.php', 'Psalm\\Issue\\NoValue' => __DIR__ . '/../..' . '/src/Psalm/Issue/NoValue.php', 'Psalm\\Issue\\NonInvariantDocblockPropertyType' => __DIR__ . '/../..' . '/src/Psalm/Issue/NonInvariantDocblockPropertyType.php', 'Psalm\\Issue\\NonInvariantPropertyType' => __DIR__ . '/../..' . '/src/Psalm/Issue/NonInvariantPropertyType.php', 'Psalm\\Issue\\NonStaticSelfCall' => __DIR__ . '/../..' . '/src/Psalm/Issue/NonStaticSelfCall.php', 'Psalm\\Issue\\NullArgument' => __DIR__ . '/../..' . '/src/Psalm/Issue/NullArgument.php', 'Psalm\\Issue\\NullArrayAccess' => __DIR__ . '/../..' . '/src/Psalm/Issue/NullArrayAccess.php', 'Psalm\\Issue\\NullArrayOffset' => __DIR__ . '/../..' . '/src/Psalm/Issue/NullArrayOffset.php', 'Psalm\\Issue\\NullFunctionCall' => __DIR__ . '/../..' . '/src/Psalm/Issue/NullFunctionCall.php', 'Psalm\\Issue\\NullIterator' => __DIR__ . '/../..' . '/src/Psalm/Issue/NullIterator.php', 'Psalm\\Issue\\NullOperand' => __DIR__ . '/../..' . '/src/Psalm/Issue/NullOperand.php', 'Psalm\\Issue\\NullPropertyAssignment' => __DIR__ . '/../..' . '/src/Psalm/Issue/NullPropertyAssignment.php', 'Psalm\\Issue\\NullPropertyFetch' => __DIR__ . '/../..' . '/src/Psalm/Issue/NullPropertyFetch.php', 'Psalm\\Issue\\NullReference' => __DIR__ . '/../..' . '/src/Psalm/Issue/NullReference.php', 'Psalm\\Issue\\NullableReturnStatement' => __DIR__ . '/../..' . '/src/Psalm/Issue/NullableReturnStatement.php', 'Psalm\\Issue\\OverriddenFinalConstant' => __DIR__ . '/../..' . '/src/Psalm/Issue/OverriddenFinalConstant.php', 'Psalm\\Issue\\OverriddenInterfaceConstant' => __DIR__ . '/../..' . '/src/Psalm/Issue/OverriddenInterfaceConstant.php', 'Psalm\\Issue\\OverriddenMethodAccess' => __DIR__ . '/../..' . '/src/Psalm/Issue/OverriddenMethodAccess.php', 'Psalm\\Issue\\OverriddenPropertyAccess' => __DIR__ . '/../..' . '/src/Psalm/Issue/OverriddenPropertyAccess.php', 'Psalm\\Issue\\ParadoxicalCondition' => __DIR__ . '/../..' . '/src/Psalm/Issue/ParadoxicalCondition.php', 'Psalm\\Issue\\ParamNameMismatch' => __DIR__ . '/../..' . '/src/Psalm/Issue/ParamNameMismatch.php', 'Psalm\\Issue\\ParentNotFound' => __DIR__ . '/../..' . '/src/Psalm/Issue/ParentNotFound.php', 'Psalm\\Issue\\ParseError' => __DIR__ . '/../..' . '/src/Psalm/Issue/ParseError.php', 'Psalm\\Issue\\PluginIssue' => __DIR__ . '/../..' . '/src/Psalm/Issue/PluginIssue.php', 'Psalm\\Issue\\PossibleRawObjectIteration' => __DIR__ . '/../..' . '/src/Psalm/Issue/PossibleRawObjectIteration.php', 'Psalm\\Issue\\PossiblyFalseArgument' => __DIR__ . '/../..' . '/src/Psalm/Issue/PossiblyFalseArgument.php', 'Psalm\\Issue\\PossiblyFalseIterator' => __DIR__ . '/../..' . '/src/Psalm/Issue/PossiblyFalseIterator.php', 'Psalm\\Issue\\PossiblyFalseOperand' => __DIR__ . '/../..' . '/src/Psalm/Issue/PossiblyFalseOperand.php', 'Psalm\\Issue\\PossiblyFalsePropertyAssignmentValue' => __DIR__ . '/../..' . '/src/Psalm/Issue/PossiblyFalsePropertyAssignmentValue.php', 'Psalm\\Issue\\PossiblyFalseReference' => __DIR__ . '/../..' . '/src/Psalm/Issue/PossiblyFalseReference.php', 'Psalm\\Issue\\PossiblyInvalidArgument' => __DIR__ . '/../..' . '/src/Psalm/Issue/PossiblyInvalidArgument.php', 'Psalm\\Issue\\PossiblyInvalidArrayAccess' => __DIR__ . '/../..' . '/src/Psalm/Issue/PossiblyInvalidArrayAccess.php', 'Psalm\\Issue\\PossiblyInvalidArrayAssignment' => __DIR__ . '/../..' . '/src/Psalm/Issue/PossiblyInvalidArrayAssignment.php', 'Psalm\\Issue\\PossiblyInvalidArrayOffset' => __DIR__ . '/../..' . '/src/Psalm/Issue/PossiblyInvalidArrayOffset.php', 'Psalm\\Issue\\PossiblyInvalidCast' => __DIR__ . '/../..' . '/src/Psalm/Issue/PossiblyInvalidCast.php', 'Psalm\\Issue\\PossiblyInvalidClone' => __DIR__ . '/../..' . '/src/Psalm/Issue/PossiblyInvalidClone.php', 'Psalm\\Issue\\PossiblyInvalidDocblockTag' => __DIR__ . '/../..' . '/src/Psalm/Issue/PossiblyInvalidDocblockTag.php', 'Psalm\\Issue\\PossiblyInvalidFunctionCall' => __DIR__ . '/../..' . '/src/Psalm/Issue/PossiblyInvalidFunctionCall.php', 'Psalm\\Issue\\PossiblyInvalidIterator' => __DIR__ . '/../..' . '/src/Psalm/Issue/PossiblyInvalidIterator.php', 'Psalm\\Issue\\PossiblyInvalidMethodCall' => __DIR__ . '/../..' . '/src/Psalm/Issue/PossiblyInvalidMethodCall.php', 'Psalm\\Issue\\PossiblyInvalidOperand' => __DIR__ . '/../..' . '/src/Psalm/Issue/PossiblyInvalidOperand.php', 'Psalm\\Issue\\PossiblyInvalidPropertyAssignment' => __DIR__ . '/../..' . '/src/Psalm/Issue/PossiblyInvalidPropertyAssignment.php', 'Psalm\\Issue\\PossiblyInvalidPropertyAssignmentValue' => __DIR__ . '/../..' . '/src/Psalm/Issue/PossiblyInvalidPropertyAssignmentValue.php', 'Psalm\\Issue\\PossiblyInvalidPropertyFetch' => __DIR__ . '/../..' . '/src/Psalm/Issue/PossiblyInvalidPropertyFetch.php', 'Psalm\\Issue\\PossiblyNullArgument' => __DIR__ . '/../..' . '/src/Psalm/Issue/PossiblyNullArgument.php', 'Psalm\\Issue\\PossiblyNullArrayAccess' => __DIR__ . '/../..' . '/src/Psalm/Issue/PossiblyNullArrayAccess.php', 'Psalm\\Issue\\PossiblyNullArrayAssignment' => __DIR__ . '/../..' . '/src/Psalm/Issue/PossiblyNullArrayAssignment.php', 'Psalm\\Issue\\PossiblyNullArrayOffset' => __DIR__ . '/../..' . '/src/Psalm/Issue/PossiblyNullArrayOffset.php', 'Psalm\\Issue\\PossiblyNullFunctionCall' => __DIR__ . '/../..' . '/src/Psalm/Issue/PossiblyNullFunctionCall.php', 'Psalm\\Issue\\PossiblyNullIterator' => __DIR__ . '/../..' . '/src/Psalm/Issue/PossiblyNullIterator.php', 'Psalm\\Issue\\PossiblyNullOperand' => __DIR__ . '/../..' . '/src/Psalm/Issue/PossiblyNullOperand.php', 'Psalm\\Issue\\PossiblyNullPropertyAssignment' => __DIR__ . '/../..' . '/src/Psalm/Issue/PossiblyNullPropertyAssignment.php', 'Psalm\\Issue\\PossiblyNullPropertyAssignmentValue' => __DIR__ . '/../..' . '/src/Psalm/Issue/PossiblyNullPropertyAssignmentValue.php', 'Psalm\\Issue\\PossiblyNullPropertyFetch' => __DIR__ . '/../..' . '/src/Psalm/Issue/PossiblyNullPropertyFetch.php', 'Psalm\\Issue\\PossiblyNullReference' => __DIR__ . '/../..' . '/src/Psalm/Issue/PossiblyNullReference.php', 'Psalm\\Issue\\PossiblyUndefinedArrayOffset' => __DIR__ . '/../..' . '/src/Psalm/Issue/PossiblyUndefinedArrayOffset.php', 'Psalm\\Issue\\PossiblyUndefinedGlobalVariable' => __DIR__ . '/../..' . '/src/Psalm/Issue/PossiblyUndefinedGlobalVariable.php', 'Psalm\\Issue\\PossiblyUndefinedIntArrayOffset' => __DIR__ . '/../..' . '/src/Psalm/Issue/PossiblyUndefinedIntArrayOffset.php', 'Psalm\\Issue\\PossiblyUndefinedMethod' => __DIR__ . '/../..' . '/src/Psalm/Issue/PossiblyUndefinedMethod.php', 'Psalm\\Issue\\PossiblyUndefinedStringArrayOffset' => __DIR__ . '/../..' . '/src/Psalm/Issue/PossiblyUndefinedStringArrayOffset.php', 'Psalm\\Issue\\PossiblyUndefinedVariable' => __DIR__ . '/../..' . '/src/Psalm/Issue/PossiblyUndefinedVariable.php', 'Psalm\\Issue\\PossiblyUnusedMethod' => __DIR__ . '/../..' . '/src/Psalm/Issue/PossiblyUnusedMethod.php', 'Psalm\\Issue\\PossiblyUnusedParam' => __DIR__ . '/../..' . '/src/Psalm/Issue/PossiblyUnusedParam.php', 'Psalm\\Issue\\PossiblyUnusedProperty' => __DIR__ . '/../..' . '/src/Psalm/Issue/PossiblyUnusedProperty.php', 'Psalm\\Issue\\PossiblyUnusedReturnValue' => __DIR__ . '/../..' . '/src/Psalm/Issue/PossiblyUnusedReturnValue.php', 'Psalm\\Issue\\PrivateFinalMethod' => __DIR__ . '/../..' . '/src/Psalm/Issue/PrivateFinalMethod.php', 'Psalm\\Issue\\PropertyIssue' => __DIR__ . '/../..' . '/src/Psalm/Issue/PropertyIssue.php', 'Psalm\\Issue\\PropertyNotSetInConstructor' => __DIR__ . '/../..' . '/src/Psalm/Issue/PropertyNotSetInConstructor.php', 'Psalm\\Issue\\PropertyTypeCoercion' => __DIR__ . '/../..' . '/src/Psalm/Issue/PropertyTypeCoercion.php', 'Psalm\\Issue\\PsalmInternalError' => __DIR__ . '/../..' . '/src/Psalm/Issue/PsalmInternalError.php', 'Psalm\\Issue\\RawObjectIteration' => __DIR__ . '/../..' . '/src/Psalm/Issue/RawObjectIteration.php', 'Psalm\\Issue\\RedundantCast' => __DIR__ . '/../..' . '/src/Psalm/Issue/RedundantCast.php', 'Psalm\\Issue\\RedundantCastGivenDocblockType' => __DIR__ . '/../..' . '/src/Psalm/Issue/RedundantCastGivenDocblockType.php', 'Psalm\\Issue\\RedundantCondition' => __DIR__ . '/../..' . '/src/Psalm/Issue/RedundantCondition.php', 'Psalm\\Issue\\RedundantConditionGivenDocblockType' => __DIR__ . '/../..' . '/src/Psalm/Issue/RedundantConditionGivenDocblockType.php', 'Psalm\\Issue\\RedundantFlag' => __DIR__ . '/../..' . '/src/Psalm/Issue/RedundantFlag.php', 'Psalm\\Issue\\RedundantFunctionCall' => __DIR__ . '/../..' . '/src/Psalm/Issue/RedundantFunctionCall.php', 'Psalm\\Issue\\RedundantFunctionCallGivenDocblockType' => __DIR__ . '/../..' . '/src/Psalm/Issue/RedundantFunctionCallGivenDocblockType.php', 'Psalm\\Issue\\RedundantIdentityWithTrue' => __DIR__ . '/../..' . '/src/Psalm/Issue/RedundantIdentityWithTrue.php', 'Psalm\\Issue\\RedundantPropertyInitializationCheck' => __DIR__ . '/../..' . '/src/Psalm/Issue/RedundantPropertyInitializationCheck.php', 'Psalm\\Issue\\ReferenceConstraintViolation' => __DIR__ . '/../..' . '/src/Psalm/Issue/ReferenceConstraintViolation.php', 'Psalm\\Issue\\ReferenceReusedFromConfusingScope' => __DIR__ . '/../..' . '/src/Psalm/Issue/ReferenceReusedFromConfusingScope.php', 'Psalm\\Issue\\ReservedWord' => __DIR__ . '/../..' . '/src/Psalm/Issue/ReservedWord.php', 'Psalm\\Issue\\RiskyCast' => __DIR__ . '/../..' . '/src/Psalm/Issue/RiskyCast.php', 'Psalm\\Issue\\RiskyTruthyFalsyComparison' => __DIR__ . '/../..' . '/src/Psalm/Issue/RiskyTruthyFalsyComparison.php', 'Psalm\\Issue\\StringIncrement' => __DIR__ . '/../..' . '/src/Psalm/Issue/StringIncrement.php', 'Psalm\\Issue\\TaintedCallable' => __DIR__ . '/../..' . '/src/Psalm/Issue/TaintedCallable.php', 'Psalm\\Issue\\TaintedCookie' => __DIR__ . '/../..' . '/src/Psalm/Issue/TaintedCookie.php', 'Psalm\\Issue\\TaintedCustom' => __DIR__ . '/../..' . '/src/Psalm/Issue/TaintedCustom.php', 'Psalm\\Issue\\TaintedEval' => __DIR__ . '/../..' . '/src/Psalm/Issue/TaintedEval.php', 'Psalm\\Issue\\TaintedFile' => __DIR__ . '/../..' . '/src/Psalm/Issue/TaintedFile.php', 'Psalm\\Issue\\TaintedHeader' => __DIR__ . '/../..' . '/src/Psalm/Issue/TaintedHeader.php', 'Psalm\\Issue\\TaintedHtml' => __DIR__ . '/../..' . '/src/Psalm/Issue/TaintedHtml.php', 'Psalm\\Issue\\TaintedInclude' => __DIR__ . '/../..' . '/src/Psalm/Issue/TaintedInclude.php', 'Psalm\\Issue\\TaintedInput' => __DIR__ . '/../..' . '/src/Psalm/Issue/TaintedInput.php', 'Psalm\\Issue\\TaintedLdap' => __DIR__ . '/../..' . '/src/Psalm/Issue/TaintedLdap.php', 'Psalm\\Issue\\TaintedSSRF' => __DIR__ . '/../..' . '/src/Psalm/Issue/TaintedSSRF.php', 'Psalm\\Issue\\TaintedShell' => __DIR__ . '/../..' . '/src/Psalm/Issue/TaintedShell.php', 'Psalm\\Issue\\TaintedSql' => __DIR__ . '/../..' . '/src/Psalm/Issue/TaintedSql.php', 'Psalm\\Issue\\TaintedSystemSecret' => __DIR__ . '/../..' . '/src/Psalm/Issue/TaintedSystemSecret.php', 'Psalm\\Issue\\TaintedTextWithQuotes' => __DIR__ . '/../..' . '/src/Psalm/Issue/TaintedTextWithQuotes.php', 'Psalm\\Issue\\TaintedUnserialize' => __DIR__ . '/../..' . '/src/Psalm/Issue/TaintedUnserialize.php', 'Psalm\\Issue\\TaintedUserSecret' => __DIR__ . '/../..' . '/src/Psalm/Issue/TaintedUserSecret.php', 'Psalm\\Issue\\TooFewArguments' => __DIR__ . '/../..' . '/src/Psalm/Issue/TooFewArguments.php', 'Psalm\\Issue\\TooManyArguments' => __DIR__ . '/../..' . '/src/Psalm/Issue/TooManyArguments.php', 'Psalm\\Issue\\TooManyTemplateParams' => __DIR__ . '/../..' . '/src/Psalm/Issue/TooManyTemplateParams.php', 'Psalm\\Issue\\Trace' => __DIR__ . '/../..' . '/src/Psalm/Issue/Trace.php', 'Psalm\\Issue\\TraitMethodSignatureMismatch' => __DIR__ . '/../..' . '/src/Psalm/Issue/TraitMethodSignatureMismatch.php', 'Psalm\\Issue\\TypeDoesNotContainNull' => __DIR__ . '/../..' . '/src/Psalm/Issue/TypeDoesNotContainNull.php', 'Psalm\\Issue\\TypeDoesNotContainType' => __DIR__ . '/../..' . '/src/Psalm/Issue/TypeDoesNotContainType.php', 'Psalm\\Issue\\UncaughtThrowInGlobalScope' => __DIR__ . '/../..' . '/src/Psalm/Issue/UncaughtThrowInGlobalScope.php', 'Psalm\\Issue\\UndefinedAttributeClass' => __DIR__ . '/../..' . '/src/Psalm/Issue/UndefinedAttributeClass.php', 'Psalm\\Issue\\UndefinedClass' => __DIR__ . '/../..' . '/src/Psalm/Issue/UndefinedClass.php', 'Psalm\\Issue\\UndefinedConstant' => __DIR__ . '/../..' . '/src/Psalm/Issue/UndefinedConstant.php', 'Psalm\\Issue\\UndefinedDocblockClass' => __DIR__ . '/../..' . '/src/Psalm/Issue/UndefinedDocblockClass.php', 'Psalm\\Issue\\UndefinedFunction' => __DIR__ . '/../..' . '/src/Psalm/Issue/UndefinedFunction.php', 'Psalm\\Issue\\UndefinedGlobalVariable' => __DIR__ . '/../..' . '/src/Psalm/Issue/UndefinedGlobalVariable.php', 'Psalm\\Issue\\UndefinedInterface' => __DIR__ . '/../..' . '/src/Psalm/Issue/UndefinedInterface.php', 'Psalm\\Issue\\UndefinedInterfaceMethod' => __DIR__ . '/../..' . '/src/Psalm/Issue/UndefinedInterfaceMethod.php', 'Psalm\\Issue\\UndefinedMagicMethod' => __DIR__ . '/../..' . '/src/Psalm/Issue/UndefinedMagicMethod.php', 'Psalm\\Issue\\UndefinedMagicPropertyAssignment' => __DIR__ . '/../..' . '/src/Psalm/Issue/UndefinedMagicPropertyAssignment.php', 'Psalm\\Issue\\UndefinedMagicPropertyFetch' => __DIR__ . '/../..' . '/src/Psalm/Issue/UndefinedMagicPropertyFetch.php', 'Psalm\\Issue\\UndefinedMethod' => __DIR__ . '/../..' . '/src/Psalm/Issue/UndefinedMethod.php', 'Psalm\\Issue\\UndefinedPropertyAssignment' => __DIR__ . '/../..' . '/src/Psalm/Issue/UndefinedPropertyAssignment.php', 'Psalm\\Issue\\UndefinedPropertyFetch' => __DIR__ . '/../..' . '/src/Psalm/Issue/UndefinedPropertyFetch.php', 'Psalm\\Issue\\UndefinedThisPropertyAssignment' => __DIR__ . '/../..' . '/src/Psalm/Issue/UndefinedThisPropertyAssignment.php', 'Psalm\\Issue\\UndefinedThisPropertyFetch' => __DIR__ . '/../..' . '/src/Psalm/Issue/UndefinedThisPropertyFetch.php', 'Psalm\\Issue\\UndefinedTrace' => __DIR__ . '/../..' . '/src/Psalm/Issue/UndefinedTrace.php', 'Psalm\\Issue\\UndefinedTrait' => __DIR__ . '/../..' . '/src/Psalm/Issue/UndefinedTrait.php', 'Psalm\\Issue\\UndefinedVariable' => __DIR__ . '/../..' . '/src/Psalm/Issue/UndefinedVariable.php', 'Psalm\\Issue\\UnevaluatedCode' => __DIR__ . '/../..' . '/src/Psalm/Issue/UnevaluatedCode.php', 'Psalm\\Issue\\UnhandledMatchCondition' => __DIR__ . '/../..' . '/src/Psalm/Issue/UnhandledMatchCondition.php', 'Psalm\\Issue\\UnimplementedAbstractMethod' => __DIR__ . '/../..' . '/src/Psalm/Issue/UnimplementedAbstractMethod.php', 'Psalm\\Issue\\UnimplementedInterfaceMethod' => __DIR__ . '/../..' . '/src/Psalm/Issue/UnimplementedInterfaceMethod.php', 'Psalm\\Issue\\UninitializedProperty' => __DIR__ . '/../..' . '/src/Psalm/Issue/UninitializedProperty.php', 'Psalm\\Issue\\UnnecessaryVarAnnotation' => __DIR__ . '/../..' . '/src/Psalm/Issue/UnnecessaryVarAnnotation.php', 'Psalm\\Issue\\UnrecognizedExpression' => __DIR__ . '/../..' . '/src/Psalm/Issue/UnrecognizedExpression.php', 'Psalm\\Issue\\UnrecognizedStatement' => __DIR__ . '/../..' . '/src/Psalm/Issue/UnrecognizedStatement.php', 'Psalm\\Issue\\UnresolvableConstant' => __DIR__ . '/../..' . '/src/Psalm/Issue/UnresolvableConstant.php', 'Psalm\\Issue\\UnresolvableInclude' => __DIR__ . '/../..' . '/src/Psalm/Issue/UnresolvableInclude.php', 'Psalm\\Issue\\UnsafeGenericInstantiation' => __DIR__ . '/../..' . '/src/Psalm/Issue/UnsafeGenericInstantiation.php', 'Psalm\\Issue\\UnsafeInstantiation' => __DIR__ . '/../..' . '/src/Psalm/Issue/UnsafeInstantiation.php', 'Psalm\\Issue\\UnsupportedPropertyReferenceUsage' => __DIR__ . '/../..' . '/src/Psalm/Issue/UnsupportedPropertyReferenceUsage.php', 'Psalm\\Issue\\UnsupportedReferenceUsage' => __DIR__ . '/../..' . '/src/Psalm/Issue/UnsupportedReferenceUsage.php', 'Psalm\\Issue\\UnusedBaselineEntry' => __DIR__ . '/../..' . '/src/Psalm/Issue/UnusedBaselineEntry.php', 'Psalm\\Issue\\UnusedClass' => __DIR__ . '/../..' . '/src/Psalm/Issue/UnusedClass.php', 'Psalm\\Issue\\UnusedClosureParam' => __DIR__ . '/../..' . '/src/Psalm/Issue/UnusedClosureParam.php', 'Psalm\\Issue\\UnusedConstructor' => __DIR__ . '/../..' . '/src/Psalm/Issue/UnusedConstructor.php', 'Psalm\\Issue\\UnusedDocblockParam' => __DIR__ . '/../..' . '/src/Psalm/Issue/UnusedDocblockParam.php', 'Psalm\\Issue\\UnusedForeachValue' => __DIR__ . '/../..' . '/src/Psalm/Issue/UnusedForeachValue.php', 'Psalm\\Issue\\UnusedFunctionCall' => __DIR__ . '/../..' . '/src/Psalm/Issue/UnusedFunctionCall.php', 'Psalm\\Issue\\UnusedMethod' => __DIR__ . '/../..' . '/src/Psalm/Issue/UnusedMethod.php', 'Psalm\\Issue\\UnusedMethodCall' => __DIR__ . '/../..' . '/src/Psalm/Issue/UnusedMethodCall.php', 'Psalm\\Issue\\UnusedParam' => __DIR__ . '/../..' . '/src/Psalm/Issue/UnusedParam.php', 'Psalm\\Issue\\UnusedProperty' => __DIR__ . '/../..' . '/src/Psalm/Issue/UnusedProperty.php', 'Psalm\\Issue\\UnusedPsalmSuppress' => __DIR__ . '/../..' . '/src/Psalm/Issue/UnusedPsalmSuppress.php', 'Psalm\\Issue\\UnusedReturnValue' => __DIR__ . '/../..' . '/src/Psalm/Issue/UnusedReturnValue.php', 'Psalm\\Issue\\UnusedVariable' => __DIR__ . '/../..' . '/src/Psalm/Issue/UnusedVariable.php', 'Psalm\\Issue\\VariableIssue' => __DIR__ . '/../..' . '/src/Psalm/Issue/VariableIssue.php', 'Psalm\\NodeTypeProvider' => __DIR__ . '/../..' . '/src/Psalm/NodeTypeProvider.php', 'Psalm\\Node\\Expr\\AssignOp\\VirtualBitwiseAnd' => __DIR__ . '/../..' . '/src/Psalm/Node/Expr/AssignOp/VirtualBitwiseAnd.php', 'Psalm\\Node\\Expr\\AssignOp\\VirtualBitwiseOr' => __DIR__ . '/../..' . '/src/Psalm/Node/Expr/AssignOp/VirtualBitwiseOr.php', 'Psalm\\Node\\Expr\\AssignOp\\VirtualBitwiseXor' => __DIR__ . '/../..' . '/src/Psalm/Node/Expr/AssignOp/VirtualBitwiseXor.php', 'Psalm\\Node\\Expr\\AssignOp\\VirtualCoalesce' => __DIR__ . '/../..' . '/src/Psalm/Node/Expr/AssignOp/VirtualCoalesce.php', 'Psalm\\Node\\Expr\\AssignOp\\VirtualConcat' => __DIR__ . '/../..' . '/src/Psalm/Node/Expr/AssignOp/VirtualConcat.php', 'Psalm\\Node\\Expr\\AssignOp\\VirtualDiv' => __DIR__ . '/../..' . '/src/Psalm/Node/Expr/AssignOp/VirtualDiv.php', 'Psalm\\Node\\Expr\\AssignOp\\VirtualMinus' => __DIR__ . '/../..' . '/src/Psalm/Node/Expr/AssignOp/VirtualMinus.php', 'Psalm\\Node\\Expr\\AssignOp\\VirtualMod' => __DIR__ . '/../..' . '/src/Psalm/Node/Expr/AssignOp/VirtualMod.php', 'Psalm\\Node\\Expr\\AssignOp\\VirtualMul' => __DIR__ . '/../..' . '/src/Psalm/Node/Expr/AssignOp/VirtualMul.php', 'Psalm\\Node\\Expr\\AssignOp\\VirtualPlus' => __DIR__ . '/../..' . '/src/Psalm/Node/Expr/AssignOp/VirtualPlus.php', 'Psalm\\Node\\Expr\\AssignOp\\VirtualPow' => __DIR__ . '/../..' . '/src/Psalm/Node/Expr/AssignOp/VirtualPow.php', 'Psalm\\Node\\Expr\\AssignOp\\VirtualShiftLeft' => __DIR__ . '/../..' . '/src/Psalm/Node/Expr/AssignOp/VirtualShiftLeft.php', 'Psalm\\Node\\Expr\\AssignOp\\VirtualShiftRight' => __DIR__ . '/../..' . '/src/Psalm/Node/Expr/AssignOp/VirtualShiftRight.php', 'Psalm\\Node\\Expr\\BinaryOp\\VirtualBitwiseAnd' => __DIR__ . '/../..' . '/src/Psalm/Node/Expr/BinaryOp/VirtualBitwiseAnd.php', 'Psalm\\Node\\Expr\\BinaryOp\\VirtualBitwiseOr' => __DIR__ . '/../..' . '/src/Psalm/Node/Expr/BinaryOp/VirtualBitwiseOr.php', 'Psalm\\Node\\Expr\\BinaryOp\\VirtualBitwiseXor' => __DIR__ . '/../..' . '/src/Psalm/Node/Expr/BinaryOp/VirtualBitwiseXor.php', 'Psalm\\Node\\Expr\\BinaryOp\\VirtualBooleanAnd' => __DIR__ . '/../..' . '/src/Psalm/Node/Expr/BinaryOp/VirtualBooleanAnd.php', 'Psalm\\Node\\Expr\\BinaryOp\\VirtualBooleanOr' => __DIR__ . '/../..' . '/src/Psalm/Node/Expr/BinaryOp/VirtualBooleanOr.php', 'Psalm\\Node\\Expr\\BinaryOp\\VirtualCoalesce' => __DIR__ . '/../..' . '/src/Psalm/Node/Expr/BinaryOp/VirtualCoalesce.php', 'Psalm\\Node\\Expr\\BinaryOp\\VirtualConcat' => __DIR__ . '/../..' . '/src/Psalm/Node/Expr/BinaryOp/VirtualConcat.php', 'Psalm\\Node\\Expr\\BinaryOp\\VirtualDiv' => __DIR__ . '/../..' . '/src/Psalm/Node/Expr/BinaryOp/VirtualDiv.php', 'Psalm\\Node\\Expr\\BinaryOp\\VirtualEqual' => __DIR__ . '/../..' . '/src/Psalm/Node/Expr/BinaryOp/VirtualEqual.php', 'Psalm\\Node\\Expr\\BinaryOp\\VirtualGreater' => __DIR__ . '/../..' . '/src/Psalm/Node/Expr/BinaryOp/VirtualGreater.php', 'Psalm\\Node\\Expr\\BinaryOp\\VirtualGreaterOrEqual' => __DIR__ . '/../..' . '/src/Psalm/Node/Expr/BinaryOp/VirtualGreaterOrEqual.php', 'Psalm\\Node\\Expr\\BinaryOp\\VirtualIdentical' => __DIR__ . '/../..' . '/src/Psalm/Node/Expr/BinaryOp/VirtualIdentical.php', 'Psalm\\Node\\Expr\\BinaryOp\\VirtualLogicalAnd' => __DIR__ . '/../..' . '/src/Psalm/Node/Expr/BinaryOp/VirtualLogicalAnd.php', 'Psalm\\Node\\Expr\\BinaryOp\\VirtualLogicalOr' => __DIR__ . '/../..' . '/src/Psalm/Node/Expr/BinaryOp/VirtualLogicalOr.php', 'Psalm\\Node\\Expr\\BinaryOp\\VirtualLogicalXor' => __DIR__ . '/../..' . '/src/Psalm/Node/Expr/BinaryOp/VirtualLogicalXor.php', 'Psalm\\Node\\Expr\\BinaryOp\\VirtualMinus' => __DIR__ . '/../..' . '/src/Psalm/Node/Expr/BinaryOp/VirtualMinus.php', 'Psalm\\Node\\Expr\\BinaryOp\\VirtualMod' => __DIR__ . '/../..' . '/src/Psalm/Node/Expr/BinaryOp/VirtualMod.php', 'Psalm\\Node\\Expr\\BinaryOp\\VirtualMul' => __DIR__ . '/../..' . '/src/Psalm/Node/Expr/BinaryOp/VirtualMul.php', 'Psalm\\Node\\Expr\\BinaryOp\\VirtualNotEqual' => __DIR__ . '/../..' . '/src/Psalm/Node/Expr/BinaryOp/VirtualNotEqual.php', 'Psalm\\Node\\Expr\\BinaryOp\\VirtualNotIdentical' => __DIR__ . '/../..' . '/src/Psalm/Node/Expr/BinaryOp/VirtualNotIdentical.php', 'Psalm\\Node\\Expr\\BinaryOp\\VirtualPlus' => __DIR__ . '/../..' . '/src/Psalm/Node/Expr/BinaryOp/VirtualPlus.php', 'Psalm\\Node\\Expr\\BinaryOp\\VirtualPow' => __DIR__ . '/../..' . '/src/Psalm/Node/Expr/BinaryOp/VirtualPow.php', 'Psalm\\Node\\Expr\\BinaryOp\\VirtualShiftLeft' => __DIR__ . '/../..' . '/src/Psalm/Node/Expr/BinaryOp/VirtualShiftLeft.php', 'Psalm\\Node\\Expr\\BinaryOp\\VirtualShiftRight' => __DIR__ . '/../..' . '/src/Psalm/Node/Expr/BinaryOp/VirtualShiftRight.php', 'Psalm\\Node\\Expr\\BinaryOp\\VirtualSmaller' => __DIR__ . '/../..' . '/src/Psalm/Node/Expr/BinaryOp/VirtualSmaller.php', 'Psalm\\Node\\Expr\\BinaryOp\\VirtualSmallerOrEqual' => __DIR__ . '/../..' . '/src/Psalm/Node/Expr/BinaryOp/VirtualSmallerOrEqual.php', 'Psalm\\Node\\Expr\\BinaryOp\\VirtualSpaceship' => __DIR__ . '/../..' . '/src/Psalm/Node/Expr/BinaryOp/VirtualSpaceship.php', 'Psalm\\Node\\Expr\\Cast\\VirtualArray' => __DIR__ . '/../..' . '/src/Psalm/Node/Expr/Cast/VirtualArray.php', 'Psalm\\Node\\Expr\\Cast\\VirtualBool' => __DIR__ . '/../..' . '/src/Psalm/Node/Expr/Cast/VirtualBool.php', 'Psalm\\Node\\Expr\\Cast\\VirtualDouble' => __DIR__ . '/../..' . '/src/Psalm/Node/Expr/Cast/VirtualDouble.php', 'Psalm\\Node\\Expr\\Cast\\VirtualInt' => __DIR__ . '/../..' . '/src/Psalm/Node/Expr/Cast/VirtualInt.php', 'Psalm\\Node\\Expr\\Cast\\VirtualObject' => __DIR__ . '/../..' . '/src/Psalm/Node/Expr/Cast/VirtualObject.php', 'Psalm\\Node\\Expr\\Cast\\VirtualString' => __DIR__ . '/../..' . '/src/Psalm/Node/Expr/Cast/VirtualString.php', 'Psalm\\Node\\Expr\\Cast\\VirtualUnset' => __DIR__ . '/../..' . '/src/Psalm/Node/Expr/Cast/VirtualUnset.php', 'Psalm\\Node\\Expr\\VirtualArray' => __DIR__ . '/../..' . '/src/Psalm/Node/Expr/VirtualArray.php', 'Psalm\\Node\\Expr\\VirtualArrayDimFetch' => __DIR__ . '/../..' . '/src/Psalm/Node/Expr/VirtualArrayDimFetch.php', 'Psalm\\Node\\Expr\\VirtualArrayItem' => __DIR__ . '/../..' . '/src/Psalm/Node/Expr/VirtualArrayItem.php', 'Psalm\\Node\\Expr\\VirtualArrowFunction' => __DIR__ . '/../..' . '/src/Psalm/Node/Expr/VirtualArrowFunction.php', 'Psalm\\Node\\Expr\\VirtualAssign' => __DIR__ . '/../..' . '/src/Psalm/Node/Expr/VirtualAssign.php', 'Psalm\\Node\\Expr\\VirtualAssignRef' => __DIR__ . '/../..' . '/src/Psalm/Node/Expr/VirtualAssignRef.php', 'Psalm\\Node\\Expr\\VirtualBitwiseNot' => __DIR__ . '/../..' . '/src/Psalm/Node/Expr/VirtualBitwiseNot.php', 'Psalm\\Node\\Expr\\VirtualBooleanNot' => __DIR__ . '/../..' . '/src/Psalm/Node/Expr/VirtualBooleanNot.php', 'Psalm\\Node\\Expr\\VirtualClassConstFetch' => __DIR__ . '/../..' . '/src/Psalm/Node/Expr/VirtualClassConstFetch.php', 'Psalm\\Node\\Expr\\VirtualClone' => __DIR__ . '/../..' . '/src/Psalm/Node/Expr/VirtualClone.php', 'Psalm\\Node\\Expr\\VirtualClosure' => __DIR__ . '/../..' . '/src/Psalm/Node/Expr/VirtualClosure.php', 'Psalm\\Node\\Expr\\VirtualClosureUse' => __DIR__ . '/../..' . '/src/Psalm/Node/Expr/VirtualClosureUse.php', 'Psalm\\Node\\Expr\\VirtualConstFetch' => __DIR__ . '/../..' . '/src/Psalm/Node/Expr/VirtualConstFetch.php', 'Psalm\\Node\\Expr\\VirtualEmpty' => __DIR__ . '/../..' . '/src/Psalm/Node/Expr/VirtualEmpty.php', 'Psalm\\Node\\Expr\\VirtualError' => __DIR__ . '/../..' . '/src/Psalm/Node/Expr/VirtualError.php', 'Psalm\\Node\\Expr\\VirtualErrorSuppress' => __DIR__ . '/../..' . '/src/Psalm/Node/Expr/VirtualErrorSuppress.php', 'Psalm\\Node\\Expr\\VirtualEval' => __DIR__ . '/../..' . '/src/Psalm/Node/Expr/VirtualEval.php', 'Psalm\\Node\\Expr\\VirtualExit' => __DIR__ . '/../..' . '/src/Psalm/Node/Expr/VirtualExit.php', 'Psalm\\Node\\Expr\\VirtualFuncCall' => __DIR__ . '/../..' . '/src/Psalm/Node/Expr/VirtualFuncCall.php', 'Psalm\\Node\\Expr\\VirtualInclude' => __DIR__ . '/../..' . '/src/Psalm/Node/Expr/VirtualInclude.php', 'Psalm\\Node\\Expr\\VirtualInstanceof' => __DIR__ . '/../..' . '/src/Psalm/Node/Expr/VirtualInstanceof.php', 'Psalm\\Node\\Expr\\VirtualIsset' => __DIR__ . '/../..' . '/src/Psalm/Node/Expr/VirtualIsset.php', 'Psalm\\Node\\Expr\\VirtualList' => __DIR__ . '/../..' . '/src/Psalm/Node/Expr/VirtualList.php', 'Psalm\\Node\\Expr\\VirtualMatch' => __DIR__ . '/../..' . '/src/Psalm/Node/Expr/VirtualMatch.php', 'Psalm\\Node\\Expr\\VirtualMethodCall' => __DIR__ . '/../..' . '/src/Psalm/Node/Expr/VirtualMethodCall.php', 'Psalm\\Node\\Expr\\VirtualNew' => __DIR__ . '/../..' . '/src/Psalm/Node/Expr/VirtualNew.php', 'Psalm\\Node\\Expr\\VirtualNullsafeMethodCall' => __DIR__ . '/../..' . '/src/Psalm/Node/Expr/VirtualNullsafeMethodCall.php', 'Psalm\\Node\\Expr\\VirtualNullsafePropertyFetch' => __DIR__ . '/../..' . '/src/Psalm/Node/Expr/VirtualNullsafePropertyFetch.php', 'Psalm\\Node\\Expr\\VirtualPostDec' => __DIR__ . '/../..' . '/src/Psalm/Node/Expr/VirtualPostDec.php', 'Psalm\\Node\\Expr\\VirtualPostInc' => __DIR__ . '/../..' . '/src/Psalm/Node/Expr/VirtualPostInc.php', 'Psalm\\Node\\Expr\\VirtualPreDec' => __DIR__ . '/../..' . '/src/Psalm/Node/Expr/VirtualPreDec.php', 'Psalm\\Node\\Expr\\VirtualPreInc' => __DIR__ . '/../..' . '/src/Psalm/Node/Expr/VirtualPreInc.php', 'Psalm\\Node\\Expr\\VirtualPrint' => __DIR__ . '/../..' . '/src/Psalm/Node/Expr/VirtualPrint.php', 'Psalm\\Node\\Expr\\VirtualPropertyFetch' => __DIR__ . '/../..' . '/src/Psalm/Node/Expr/VirtualPropertyFetch.php', 'Psalm\\Node\\Expr\\VirtualShellExec' => __DIR__ . '/../..' . '/src/Psalm/Node/Expr/VirtualShellExec.php', 'Psalm\\Node\\Expr\\VirtualStaticCall' => __DIR__ . '/../..' . '/src/Psalm/Node/Expr/VirtualStaticCall.php', 'Psalm\\Node\\Expr\\VirtualStaticPropertyFetch' => __DIR__ . '/../..' . '/src/Psalm/Node/Expr/VirtualStaticPropertyFetch.php', 'Psalm\\Node\\Expr\\VirtualTernary' => __DIR__ . '/../..' . '/src/Psalm/Node/Expr/VirtualTernary.php', 'Psalm\\Node\\Expr\\VirtualThrow' => __DIR__ . '/../..' . '/src/Psalm/Node/Expr/VirtualThrow.php', 'Psalm\\Node\\Expr\\VirtualUnaryMinus' => __DIR__ . '/../..' . '/src/Psalm/Node/Expr/VirtualUnaryMinus.php', 'Psalm\\Node\\Expr\\VirtualUnaryPlus' => __DIR__ . '/../..' . '/src/Psalm/Node/Expr/VirtualUnaryPlus.php', 'Psalm\\Node\\Expr\\VirtualVariable' => __DIR__ . '/../..' . '/src/Psalm/Node/Expr/VirtualVariable.php', 'Psalm\\Node\\Expr\\VirtualYield' => __DIR__ . '/../..' . '/src/Psalm/Node/Expr/VirtualYield.php', 'Psalm\\Node\\Expr\\VirtualYieldFrom' => __DIR__ . '/../..' . '/src/Psalm/Node/Expr/VirtualYieldFrom.php', 'Psalm\\Node\\Name\\VirtualFullyQualified' => __DIR__ . '/../..' . '/src/Psalm/Node/Name/VirtualFullyQualified.php', 'Psalm\\Node\\Name\\VirtualRelative' => __DIR__ . '/../..' . '/src/Psalm/Node/Name/VirtualRelative.php', 'Psalm\\Node\\Scalar\\MagicConst\\VirtualClass' => __DIR__ . '/../..' . '/src/Psalm/Node/Scalar/MagicConst/VirtualClass.php', 'Psalm\\Node\\Scalar\\MagicConst\\VirtualDir' => __DIR__ . '/../..' . '/src/Psalm/Node/Scalar/MagicConst/VirtualDir.php', 'Psalm\\Node\\Scalar\\MagicConst\\VirtualFile' => __DIR__ . '/../..' . '/src/Psalm/Node/Scalar/MagicConst/VirtualFile.php', 'Psalm\\Node\\Scalar\\MagicConst\\VirtualFunction' => __DIR__ . '/../..' . '/src/Psalm/Node/Scalar/MagicConst/VirtualFunction.php', 'Psalm\\Node\\Scalar\\MagicConst\\VirtualLine' => __DIR__ . '/../..' . '/src/Psalm/Node/Scalar/MagicConst/VirtualLine.php', 'Psalm\\Node\\Scalar\\MagicConst\\VirtualMethod' => __DIR__ . '/../..' . '/src/Psalm/Node/Scalar/MagicConst/VirtualMethod.php', 'Psalm\\Node\\Scalar\\MagicConst\\VirtualNamespace' => __DIR__ . '/../..' . '/src/Psalm/Node/Scalar/MagicConst/VirtualNamespace.php', 'Psalm\\Node\\Scalar\\MagicConst\\VirtualTrait' => __DIR__ . '/../..' . '/src/Psalm/Node/Scalar/MagicConst/VirtualTrait.php', 'Psalm\\Node\\Scalar\\VirtualDNumber' => __DIR__ . '/../..' . '/src/Psalm/Node/Scalar/VirtualDNumber.php', 'Psalm\\Node\\Scalar\\VirtualEncapsed' => __DIR__ . '/../..' . '/src/Psalm/Node/Scalar/VirtualEncapsed.php', 'Psalm\\Node\\Scalar\\VirtualEncapsedStringPart' => __DIR__ . '/../..' . '/src/Psalm/Node/Scalar/VirtualEncapsedStringPart.php', 'Psalm\\Node\\Scalar\\VirtualLNumber' => __DIR__ . '/../..' . '/src/Psalm/Node/Scalar/VirtualLNumber.php', 'Psalm\\Node\\Scalar\\VirtualString' => __DIR__ . '/../..' . '/src/Psalm/Node/Scalar/VirtualString.php', 'Psalm\\Node\\Stmt\\TraitUseAdaptation\\VirtualAlias' => __DIR__ . '/../..' . '/src/Psalm/Node/Stmt/TraitUseAdaptation/VirtualAlias.php', 'Psalm\\Node\\Stmt\\TraitUseAdaptation\\VirtualPrecedence' => __DIR__ . '/../..' . '/src/Psalm/Node/Stmt/TraitUseAdaptation/VirtualPrecedence.php', 'Psalm\\Node\\Stmt\\VirtualBreak' => __DIR__ . '/../..' . '/src/Psalm/Node/Stmt/VirtualBreak.php', 'Psalm\\Node\\Stmt\\VirtualCase' => __DIR__ . '/../..' . '/src/Psalm/Node/Stmt/VirtualCase.php', 'Psalm\\Node\\Stmt\\VirtualCatch' => __DIR__ . '/../..' . '/src/Psalm/Node/Stmt/VirtualCatch.php', 'Psalm\\Node\\Stmt\\VirtualClass' => __DIR__ . '/../..' . '/src/Psalm/Node/Stmt/VirtualClass.php', 'Psalm\\Node\\Stmt\\VirtualClassConst' => __DIR__ . '/../..' . '/src/Psalm/Node/Stmt/VirtualClassConst.php', 'Psalm\\Node\\Stmt\\VirtualClassMethod' => __DIR__ . '/../..' . '/src/Psalm/Node/Stmt/VirtualClassMethod.php', 'Psalm\\Node\\Stmt\\VirtualConst' => __DIR__ . '/../..' . '/src/Psalm/Node/Stmt/VirtualConst.php', 'Psalm\\Node\\Stmt\\VirtualContinue' => __DIR__ . '/../..' . '/src/Psalm/Node/Stmt/VirtualContinue.php', 'Psalm\\Node\\Stmt\\VirtualDeclare' => __DIR__ . '/../..' . '/src/Psalm/Node/Stmt/VirtualDeclare.php', 'Psalm\\Node\\Stmt\\VirtualDeclareDeclare' => __DIR__ . '/../..' . '/src/Psalm/Node/Stmt/VirtualDeclareDeclare.php', 'Psalm\\Node\\Stmt\\VirtualDo' => __DIR__ . '/../..' . '/src/Psalm/Node/Stmt/VirtualDo.php', 'Psalm\\Node\\Stmt\\VirtualEcho' => __DIR__ . '/../..' . '/src/Psalm/Node/Stmt/VirtualEcho.php', 'Psalm\\Node\\Stmt\\VirtualElse' => __DIR__ . '/../..' . '/src/Psalm/Node/Stmt/VirtualElse.php', 'Psalm\\Node\\Stmt\\VirtualElseIf' => __DIR__ . '/../..' . '/src/Psalm/Node/Stmt/VirtualElseIf.php', 'Psalm\\Node\\Stmt\\VirtualExpression' => __DIR__ . '/../..' . '/src/Psalm/Node/Stmt/VirtualExpression.php', 'Psalm\\Node\\Stmt\\VirtualFinally' => __DIR__ . '/../..' . '/src/Psalm/Node/Stmt/VirtualFinally.php', 'Psalm\\Node\\Stmt\\VirtualFor' => __DIR__ . '/../..' . '/src/Psalm/Node/Stmt/VirtualFor.php', 'Psalm\\Node\\Stmt\\VirtualForeach' => __DIR__ . '/../..' . '/src/Psalm/Node/Stmt/VirtualForeach.php', 'Psalm\\Node\\Stmt\\VirtualFunction' => __DIR__ . '/../..' . '/src/Psalm/Node/Stmt/VirtualFunction.php', 'Psalm\\Node\\Stmt\\VirtualGlobal' => __DIR__ . '/../..' . '/src/Psalm/Node/Stmt/VirtualGlobal.php', 'Psalm\\Node\\Stmt\\VirtualGoto' => __DIR__ . '/../..' . '/src/Psalm/Node/Stmt/VirtualGoto.php', 'Psalm\\Node\\Stmt\\VirtualGroupUse' => __DIR__ . '/../..' . '/src/Psalm/Node/Stmt/VirtualGroupUse.php', 'Psalm\\Node\\Stmt\\VirtualHaltCompiler' => __DIR__ . '/../..' . '/src/Psalm/Node/Stmt/VirtualHaltCompiler.php', 'Psalm\\Node\\Stmt\\VirtualIf' => __DIR__ . '/../..' . '/src/Psalm/Node/Stmt/VirtualIf.php', 'Psalm\\Node\\Stmt\\VirtualInlineHTML' => __DIR__ . '/../..' . '/src/Psalm/Node/Stmt/VirtualInlineHTML.php', 'Psalm\\Node\\Stmt\\VirtualInterface' => __DIR__ . '/../..' . '/src/Psalm/Node/Stmt/VirtualInterface.php', 'Psalm\\Node\\Stmt\\VirtualLabel' => __DIR__ . '/../..' . '/src/Psalm/Node/Stmt/VirtualLabel.php', 'Psalm\\Node\\Stmt\\VirtualNamespace' => __DIR__ . '/../..' . '/src/Psalm/Node/Stmt/VirtualNamespace.php', 'Psalm\\Node\\Stmt\\VirtualNop' => __DIR__ . '/../..' . '/src/Psalm/Node/Stmt/VirtualNop.php', 'Psalm\\Node\\Stmt\\VirtualProperty' => __DIR__ . '/../..' . '/src/Psalm/Node/Stmt/VirtualProperty.php', 'Psalm\\Node\\Stmt\\VirtualPropertyProperty' => __DIR__ . '/../..' . '/src/Psalm/Node/Stmt/VirtualPropertyProperty.php', 'Psalm\\Node\\Stmt\\VirtualReturn' => __DIR__ . '/../..' . '/src/Psalm/Node/Stmt/VirtualReturn.php', 'Psalm\\Node\\Stmt\\VirtualStatic' => __DIR__ . '/../..' . '/src/Psalm/Node/Stmt/VirtualStatic.php', 'Psalm\\Node\\Stmt\\VirtualStaticVar' => __DIR__ . '/../..' . '/src/Psalm/Node/Stmt/VirtualStaticVar.php', 'Psalm\\Node\\Stmt\\VirtualSwitch' => __DIR__ . '/../..' . '/src/Psalm/Node/Stmt/VirtualSwitch.php', 'Psalm\\Node\\Stmt\\VirtualThrow' => __DIR__ . '/../..' . '/src/Psalm/Node/Stmt/VirtualThrow.php', 'Psalm\\Node\\Stmt\\VirtualTrait' => __DIR__ . '/../..' . '/src/Psalm/Node/Stmt/VirtualTrait.php', 'Psalm\\Node\\Stmt\\VirtualTraitUse' => __DIR__ . '/../..' . '/src/Psalm/Node/Stmt/VirtualTraitUse.php', 'Psalm\\Node\\Stmt\\VirtualTryCatch' => __DIR__ . '/../..' . '/src/Psalm/Node/Stmt/VirtualTryCatch.php', 'Psalm\\Node\\Stmt\\VirtualUnset' => __DIR__ . '/../..' . '/src/Psalm/Node/Stmt/VirtualUnset.php', 'Psalm\\Node\\Stmt\\VirtualUse' => __DIR__ . '/../..' . '/src/Psalm/Node/Stmt/VirtualUse.php', 'Psalm\\Node\\Stmt\\VirtualUseUse' => __DIR__ . '/../..' . '/src/Psalm/Node/Stmt/VirtualUseUse.php', 'Psalm\\Node\\Stmt\\VirtualWhile' => __DIR__ . '/../..' . '/src/Psalm/Node/Stmt/VirtualWhile.php', 'Psalm\\Node\\VirtualArg' => __DIR__ . '/../..' . '/src/Psalm/Node/VirtualArg.php', 'Psalm\\Node\\VirtualAttribute' => __DIR__ . '/../..' . '/src/Psalm/Node/VirtualAttribute.php', 'Psalm\\Node\\VirtualAttributeGroup' => __DIR__ . '/../..' . '/src/Psalm/Node/VirtualAttributeGroup.php', 'Psalm\\Node\\VirtualConst' => __DIR__ . '/../..' . '/src/Psalm/Node/VirtualConst.php', 'Psalm\\Node\\VirtualIdentifier' => __DIR__ . '/../..' . '/src/Psalm/Node/VirtualIdentifier.php', 'Psalm\\Node\\VirtualMatchArm' => __DIR__ . '/../..' . '/src/Psalm/Node/VirtualMatchArm.php', 'Psalm\\Node\\VirtualName' => __DIR__ . '/../..' . '/src/Psalm/Node/VirtualName.php', 'Psalm\\Node\\VirtualNode' => __DIR__ . '/../..' . '/src/Psalm/Node/VirtualNode.php', 'Psalm\\Node\\VirtualNullableType' => __DIR__ . '/../..' . '/src/Psalm/Node/VirtualNullableType.php', 'Psalm\\Node\\VirtualParam' => __DIR__ . '/../..' . '/src/Psalm/Node/VirtualParam.php', 'Psalm\\Node\\VirtualUnionType' => __DIR__ . '/../..' . '/src/Psalm/Node/VirtualUnionType.php', 'Psalm\\Node\\VirtualVarLikeIdentifier' => __DIR__ . '/../..' . '/src/Psalm/Node/VirtualVarLikeIdentifier.php', 'Psalm\\PluginFileExtensionsSocket' => __DIR__ . '/../..' . '/src/Psalm/PluginFileExtensionsSocket.php', 'Psalm\\PluginRegistrationSocket' => __DIR__ . '/../..' . '/src/Psalm/PluginRegistrationSocket.php', 'Psalm\\Plugin\\ArgTypeInferer' => __DIR__ . '/../..' . '/src/Psalm/Plugin/ArgTypeInferer.php', 'Psalm\\Plugin\\DynamicFunctionStorage' => __DIR__ . '/../..' . '/src/Psalm/Plugin/DynamicFunctionStorage.php', 'Psalm\\Plugin\\DynamicTemplateProvider' => __DIR__ . '/../..' . '/src/Psalm/Plugin/DynamicTemplateProvider.php', 'Psalm\\Plugin\\EventHandler\\AddTaintsInterface' => __DIR__ . '/../..' . '/src/Psalm/Plugin/EventHandler/AddTaintsInterface.php', 'Psalm\\Plugin\\EventHandler\\AfterAnalysisInterface' => __DIR__ . '/../..' . '/src/Psalm/Plugin/EventHandler/AfterAnalysisInterface.php', 'Psalm\\Plugin\\EventHandler\\AfterClassLikeAnalysisInterface' => __DIR__ . '/../..' . '/src/Psalm/Plugin/EventHandler/AfterClassLikeAnalysisInterface.php', 'Psalm\\Plugin\\EventHandler\\AfterClassLikeExistenceCheckInterface' => __DIR__ . '/../..' . '/src/Psalm/Plugin/EventHandler/AfterClassLikeExistenceCheckInterface.php', 'Psalm\\Plugin\\EventHandler\\AfterClassLikeVisitInterface' => __DIR__ . '/../..' . '/src/Psalm/Plugin/EventHandler/AfterClassLikeVisitInterface.php', 'Psalm\\Plugin\\EventHandler\\AfterCodebasePopulatedInterface' => __DIR__ . '/../..' . '/src/Psalm/Plugin/EventHandler/AfterCodebasePopulatedInterface.php', 'Psalm\\Plugin\\EventHandler\\AfterEveryFunctionCallAnalysisInterface' => __DIR__ . '/../..' . '/src/Psalm/Plugin/EventHandler/AfterEveryFunctionCallAnalysisInterface.php', 'Psalm\\Plugin\\EventHandler\\AfterExpressionAnalysisInterface' => __DIR__ . '/../..' . '/src/Psalm/Plugin/EventHandler/AfterExpressionAnalysisInterface.php', 'Psalm\\Plugin\\EventHandler\\AfterFileAnalysisInterface' => __DIR__ . '/../..' . '/src/Psalm/Plugin/EventHandler/AfterFileAnalysisInterface.php', 'Psalm\\Plugin\\EventHandler\\AfterFunctionCallAnalysisInterface' => __DIR__ . '/../..' . '/src/Psalm/Plugin/EventHandler/AfterFunctionCallAnalysisInterface.php', 'Psalm\\Plugin\\EventHandler\\AfterFunctionLikeAnalysisInterface' => __DIR__ . '/../..' . '/src/Psalm/Plugin/EventHandler/AfterFunctionLikeAnalysisInterface.php', 'Psalm\\Plugin\\EventHandler\\AfterMethodCallAnalysisInterface' => __DIR__ . '/../..' . '/src/Psalm/Plugin/EventHandler/AfterMethodCallAnalysisInterface.php', 'Psalm\\Plugin\\EventHandler\\AfterStatementAnalysisInterface' => __DIR__ . '/../..' . '/src/Psalm/Plugin/EventHandler/AfterStatementAnalysisInterface.php', 'Psalm\\Plugin\\EventHandler\\BeforeAddIssueInterface' => __DIR__ . '/../..' . '/src/Psalm/Plugin/EventHandler/BeforeAddIssueInterface.php', 'Psalm\\Plugin\\EventHandler\\BeforeExpressionAnalysisInterface' => __DIR__ . '/../..' . '/src/Psalm/Plugin/EventHandler/BeforeExpressionAnalysisInterface.php', 'Psalm\\Plugin\\EventHandler\\BeforeFileAnalysisInterface' => __DIR__ . '/../..' . '/src/Psalm/Plugin/EventHandler/BeforeFileAnalysisInterface.php', 'Psalm\\Plugin\\EventHandler\\BeforeStatementAnalysisInterface' => __DIR__ . '/../..' . '/src/Psalm/Plugin/EventHandler/BeforeStatementAnalysisInterface.php', 'Psalm\\Plugin\\EventHandler\\DynamicFunctionStorageProviderInterface' => __DIR__ . '/../..' . '/src/Psalm/Plugin/EventHandler/DynamicFunctionStorageProviderInterface.php', 'Psalm\\Plugin\\EventHandler\\Event\\AddRemoveTaintsEvent' => __DIR__ . '/../..' . '/src/Psalm/Plugin/EventHandler/Event/AddRemoveTaintsEvent.php', 'Psalm\\Plugin\\EventHandler\\Event\\AfterAnalysisEvent' => __DIR__ . '/../..' . '/src/Psalm/Plugin/EventHandler/Event/AfterAnalysisEvent.php', 'Psalm\\Plugin\\EventHandler\\Event\\AfterClassLikeAnalysisEvent' => __DIR__ . '/../..' . '/src/Psalm/Plugin/EventHandler/Event/AfterClassLikeAnalysisEvent.php', 'Psalm\\Plugin\\EventHandler\\Event\\AfterClassLikeExistenceCheckEvent' => __DIR__ . '/../..' . '/src/Psalm/Plugin/EventHandler/Event/AfterClassLikeExistenceCheckEvent.php', 'Psalm\\Plugin\\EventHandler\\Event\\AfterClassLikeVisitEvent' => __DIR__ . '/../..' . '/src/Psalm/Plugin/EventHandler/Event/AfterClassLikeVisitEvent.php', 'Psalm\\Plugin\\EventHandler\\Event\\AfterCodebasePopulatedEvent' => __DIR__ . '/../..' . '/src/Psalm/Plugin/EventHandler/Event/AfterCodebasePopulatedEvent.php', 'Psalm\\Plugin\\EventHandler\\Event\\AfterEveryFunctionCallAnalysisEvent' => __DIR__ . '/../..' . '/src/Psalm/Plugin/EventHandler/Event/AfterEveryFunctionCallAnalysisEvent.php', 'Psalm\\Plugin\\EventHandler\\Event\\AfterExpressionAnalysisEvent' => __DIR__ . '/../..' . '/src/Psalm/Plugin/EventHandler/Event/AfterExpressionAnalysisEvent.php', 'Psalm\\Plugin\\EventHandler\\Event\\AfterFileAnalysisEvent' => __DIR__ . '/../..' . '/src/Psalm/Plugin/EventHandler/Event/AfterFileAnalysisEvent.php', 'Psalm\\Plugin\\EventHandler\\Event\\AfterFunctionCallAnalysisEvent' => __DIR__ . '/../..' . '/src/Psalm/Plugin/EventHandler/Event/AfterFunctionCallAnalysisEvent.php', 'Psalm\\Plugin\\EventHandler\\Event\\AfterFunctionLikeAnalysisEvent' => __DIR__ . '/../..' . '/src/Psalm/Plugin/EventHandler/Event/AfterFunctionLikeAnalysisEvent.php', 'Psalm\\Plugin\\EventHandler\\Event\\AfterMethodCallAnalysisEvent' => __DIR__ . '/../..' . '/src/Psalm/Plugin/EventHandler/Event/AfterMethodCallAnalysisEvent.php', 'Psalm\\Plugin\\EventHandler\\Event\\AfterStatementAnalysisEvent' => __DIR__ . '/../..' . '/src/Psalm/Plugin/EventHandler/Event/AfterStatementAnalysisEvent.php', 'Psalm\\Plugin\\EventHandler\\Event\\BeforeAddIssueEvent' => __DIR__ . '/../..' . '/src/Psalm/Plugin/EventHandler/Event/BeforeAddIssueEvent.php', 'Psalm\\Plugin\\EventHandler\\Event\\BeforeExpressionAnalysisEvent' => __DIR__ . '/../..' . '/src/Psalm/Plugin/EventHandler/Event/BeforeExpressionAnalysisEvent.php', 'Psalm\\Plugin\\EventHandler\\Event\\BeforeFileAnalysisEvent' => __DIR__ . '/../..' . '/src/Psalm/Plugin/EventHandler/Event/BeforeFileAnalysisEvent.php', 'Psalm\\Plugin\\EventHandler\\Event\\BeforeStatementAnalysisEvent' => __DIR__ . '/../..' . '/src/Psalm/Plugin/EventHandler/Event/BeforeStatementAnalysisEvent.php', 'Psalm\\Plugin\\EventHandler\\Event\\DynamicFunctionStorageProviderEvent' => __DIR__ . '/../..' . '/src/Psalm/Plugin/EventHandler/Event/DynamicFunctionStorageProviderEvent.php', 'Psalm\\Plugin\\EventHandler\\Event\\FunctionExistenceProviderEvent' => __DIR__ . '/../..' . '/src/Psalm/Plugin/EventHandler/Event/FunctionExistenceProviderEvent.php', 'Psalm\\Plugin\\EventHandler\\Event\\FunctionParamsProviderEvent' => __DIR__ . '/../..' . '/src/Psalm/Plugin/EventHandler/Event/FunctionParamsProviderEvent.php', 'Psalm\\Plugin\\EventHandler\\Event\\FunctionReturnTypeProviderEvent' => __DIR__ . '/../..' . '/src/Psalm/Plugin/EventHandler/Event/FunctionReturnTypeProviderEvent.php', 'Psalm\\Plugin\\EventHandler\\Event\\MethodExistenceProviderEvent' => __DIR__ . '/../..' . '/src/Psalm/Plugin/EventHandler/Event/MethodExistenceProviderEvent.php', 'Psalm\\Plugin\\EventHandler\\Event\\MethodParamsProviderEvent' => __DIR__ . '/../..' . '/src/Psalm/Plugin/EventHandler/Event/MethodParamsProviderEvent.php', 'Psalm\\Plugin\\EventHandler\\Event\\MethodReturnTypeProviderEvent' => __DIR__ . '/../..' . '/src/Psalm/Plugin/EventHandler/Event/MethodReturnTypeProviderEvent.php', 'Psalm\\Plugin\\EventHandler\\Event\\MethodVisibilityProviderEvent' => __DIR__ . '/../..' . '/src/Psalm/Plugin/EventHandler/Event/MethodVisibilityProviderEvent.php', 'Psalm\\Plugin\\EventHandler\\Event\\PropertyExistenceProviderEvent' => __DIR__ . '/../..' . '/src/Psalm/Plugin/EventHandler/Event/PropertyExistenceProviderEvent.php', 'Psalm\\Plugin\\EventHandler\\Event\\PropertyTypeProviderEvent' => __DIR__ . '/../..' . '/src/Psalm/Plugin/EventHandler/Event/PropertyTypeProviderEvent.php', 'Psalm\\Plugin\\EventHandler\\Event\\PropertyVisibilityProviderEvent' => __DIR__ . '/../..' . '/src/Psalm/Plugin/EventHandler/Event/PropertyVisibilityProviderEvent.php', 'Psalm\\Plugin\\EventHandler\\Event\\StringInterpreterEvent' => __DIR__ . '/../..' . '/src/Psalm/Plugin/EventHandler/Event/StringInterpreterEvent.php', 'Psalm\\Plugin\\EventHandler\\FunctionExistenceProviderInterface' => __DIR__ . '/../..' . '/src/Psalm/Plugin/EventHandler/FunctionExistenceProviderInterface.php', 'Psalm\\Plugin\\EventHandler\\FunctionParamsProviderInterface' => __DIR__ . '/../..' . '/src/Psalm/Plugin/EventHandler/FunctionParamsProviderInterface.php', 'Psalm\\Plugin\\EventHandler\\FunctionReturnTypeProviderInterface' => __DIR__ . '/../..' . '/src/Psalm/Plugin/EventHandler/FunctionReturnTypeProviderInterface.php', 'Psalm\\Plugin\\EventHandler\\MethodExistenceProviderInterface' => __DIR__ . '/../..' . '/src/Psalm/Plugin/EventHandler/MethodExistenceProviderInterface.php', 'Psalm\\Plugin\\EventHandler\\MethodParamsProviderInterface' => __DIR__ . '/../..' . '/src/Psalm/Plugin/EventHandler/MethodParamsProviderInterface.php', 'Psalm\\Plugin\\EventHandler\\MethodReturnTypeProviderInterface' => __DIR__ . '/../..' . '/src/Psalm/Plugin/EventHandler/MethodReturnTypeProviderInterface.php', 'Psalm\\Plugin\\EventHandler\\MethodVisibilityProviderInterface' => __DIR__ . '/../..' . '/src/Psalm/Plugin/EventHandler/MethodVisibilityProviderInterface.php', 'Psalm\\Plugin\\EventHandler\\PropertyExistenceProviderInterface' => __DIR__ . '/../..' . '/src/Psalm/Plugin/EventHandler/PropertyExistenceProviderInterface.php', 'Psalm\\Plugin\\EventHandler\\PropertyTypeProviderInterface' => __DIR__ . '/../..' . '/src/Psalm/Plugin/EventHandler/PropertyTypeProviderInterface.php', 'Psalm\\Plugin\\EventHandler\\PropertyVisibilityProviderInterface' => __DIR__ . '/../..' . '/src/Psalm/Plugin/EventHandler/PropertyVisibilityProviderInterface.php', 'Psalm\\Plugin\\EventHandler\\RemoveTaintsInterface' => __DIR__ . '/../..' . '/src/Psalm/Plugin/EventHandler/RemoveTaintsInterface.php', 'Psalm\\Plugin\\EventHandler\\StringInterpreterInterface' => __DIR__ . '/../..' . '/src/Psalm/Plugin/EventHandler/StringInterpreterInterface.php', 'Psalm\\Plugin\\FileExtensionsInterface' => __DIR__ . '/../..' . '/src/Psalm/Plugin/FileExtensionsInterface.php', 'Psalm\\Plugin\\PluginEntryPointInterface' => __DIR__ . '/../..' . '/src/Psalm/Plugin/PluginEntryPointInterface.php', 'Psalm\\Plugin\\PluginFileExtensionsInterface' => __DIR__ . '/../..' . '/src/Psalm/Plugin/PluginFileExtensionsInterface.php', 'Psalm\\Plugin\\PluginInterface' => __DIR__ . '/../..' . '/src/Psalm/Plugin/PluginInterface.php', 'Psalm\\Plugin\\RegistrationInterface' => __DIR__ . '/../..' . '/src/Psalm/Plugin/RegistrationInterface.php', 'Psalm\\Plugin\\Shepherd' => __DIR__ . '/../..' . '/src/Psalm/Plugin/Shepherd.php', 'Psalm\\Progress\\DebugProgress' => __DIR__ . '/../..' . '/src/Psalm/Progress/DebugProgress.php', 'Psalm\\Progress\\DefaultProgress' => __DIR__ . '/../..' . '/src/Psalm/Progress/DefaultProgress.php', 'Psalm\\Progress\\LongProgress' => __DIR__ . '/../..' . '/src/Psalm/Progress/LongProgress.php', 'Psalm\\Progress\\Progress' => __DIR__ . '/../..' . '/src/Psalm/Progress/Progress.php', 'Psalm\\Progress\\VoidProgress' => __DIR__ . '/../..' . '/src/Psalm/Progress/VoidProgress.php', 'Psalm\\Report' => __DIR__ . '/../..' . '/src/Psalm/Report.php', 'Psalm\\Report\\ByIssueLevelAndTypeReport' => __DIR__ . '/../..' . '/src/Psalm/Report/ByIssueLevelAndTypeReport.php', 'Psalm\\Report\\CheckstyleReport' => __DIR__ . '/../..' . '/src/Psalm/Report/CheckstyleReport.php', 'Psalm\\Report\\CodeClimateReport' => __DIR__ . '/../..' . '/src/Psalm/Report/CodeClimateReport.php', 'Psalm\\Report\\CompactReport' => __DIR__ . '/../..' . '/src/Psalm/Report/CompactReport.php', 'Psalm\\Report\\ConsoleReport' => __DIR__ . '/../..' . '/src/Psalm/Report/ConsoleReport.php', 'Psalm\\Report\\CountReport' => __DIR__ . '/../..' . '/src/Psalm/Report/CountReport.php', 'Psalm\\Report\\EmacsReport' => __DIR__ . '/../..' . '/src/Psalm/Report/EmacsReport.php', 'Psalm\\Report\\GithubActionsReport' => __DIR__ . '/../..' . '/src/Psalm/Report/GithubActionsReport.php', 'Psalm\\Report\\JsonReport' => __DIR__ . '/../..' . '/src/Psalm/Report/JsonReport.php', 'Psalm\\Report\\JsonSummaryReport' => __DIR__ . '/../..' . '/src/Psalm/Report/JsonSummaryReport.php', 'Psalm\\Report\\JunitReport' => __DIR__ . '/../..' . '/src/Psalm/Report/JunitReport.php', 'Psalm\\Report\\PhpStormReport' => __DIR__ . '/../..' . '/src/Psalm/Report/PhpStormReport.php', 'Psalm\\Report\\PylintReport' => __DIR__ . '/../..' . '/src/Psalm/Report/PylintReport.php', 'Psalm\\Report\\ReportOptions' => __DIR__ . '/../..' . '/src/Psalm/Report/ReportOptions.php', 'Psalm\\Report\\SarifReport' => __DIR__ . '/../..' . '/src/Psalm/Report/SarifReport.php', 'Psalm\\Report\\SonarqubeReport' => __DIR__ . '/../..' . '/src/Psalm/Report/SonarqubeReport.php', 'Psalm\\Report\\TextReport' => __DIR__ . '/../..' . '/src/Psalm/Report/TextReport.php', 'Psalm\\Report\\XmlReport' => __DIR__ . '/../..' . '/src/Psalm/Report/XmlReport.php', 'Psalm\\SourceControl\\Git\\CommitInfo' => __DIR__ . '/../..' . '/src/Psalm/SourceControl/Git/CommitInfo.php', 'Psalm\\SourceControl\\Git\\GitInfo' => __DIR__ . '/../..' . '/src/Psalm/SourceControl/Git/GitInfo.php', 'Psalm\\SourceControl\\Git\\RemoteInfo' => __DIR__ . '/../..' . '/src/Psalm/SourceControl/Git/RemoteInfo.php', 'Psalm\\SourceControl\\SourceControlInfo' => __DIR__ . '/../..' . '/src/Psalm/SourceControl/SourceControlInfo.php', 'Psalm\\StatementsSource' => __DIR__ . '/../..' . '/src/Psalm/StatementsSource.php', 'Psalm\\Storage\\Assertion' => __DIR__ . '/../..' . '/src/Psalm/Storage/Assertion.php', 'Psalm\\Storage\\Assertion\\Any' => __DIR__ . '/../..' . '/src/Psalm/Storage/Assertion/Any.php', 'Psalm\\Storage\\Assertion\\ArrayKeyDoesNotExist' => __DIR__ . '/../..' . '/src/Psalm/Storage/Assertion/ArrayKeyDoesNotExist.php', 'Psalm\\Storage\\Assertion\\ArrayKeyExists' => __DIR__ . '/../..' . '/src/Psalm/Storage/Assertion/ArrayKeyExists.php', 'Psalm\\Storage\\Assertion\\DoesNotHaveAtLeastCount' => __DIR__ . '/../..' . '/src/Psalm/Storage/Assertion/DoesNotHaveAtLeastCount.php', 'Psalm\\Storage\\Assertion\\DoesNotHaveExactCount' => __DIR__ . '/../..' . '/src/Psalm/Storage/Assertion/DoesNotHaveExactCount.php', 'Psalm\\Storage\\Assertion\\DoesNotHaveMethod' => __DIR__ . '/../..' . '/src/Psalm/Storage/Assertion/DoesNotHaveMethod.php', 'Psalm\\Storage\\Assertion\\Empty_' => __DIR__ . '/../..' . '/src/Psalm/Storage/Assertion/Empty_.php', 'Psalm\\Storage\\Assertion\\Falsy' => __DIR__ . '/../..' . '/src/Psalm/Storage/Assertion/Falsy.php', 'Psalm\\Storage\\Assertion\\HasArrayKey' => __DIR__ . '/../..' . '/src/Psalm/Storage/Assertion/HasArrayKey.php', 'Psalm\\Storage\\Assertion\\HasAtLeastCount' => __DIR__ . '/../..' . '/src/Psalm/Storage/Assertion/HasAtLeastCount.php', 'Psalm\\Storage\\Assertion\\HasExactCount' => __DIR__ . '/../..' . '/src/Psalm/Storage/Assertion/HasExactCount.php', 'Psalm\\Storage\\Assertion\\HasIntOrStringArrayAccess' => __DIR__ . '/../..' . '/src/Psalm/Storage/Assertion/HasIntOrStringArrayAccess.php', 'Psalm\\Storage\\Assertion\\HasMethod' => __DIR__ . '/../..' . '/src/Psalm/Storage/Assertion/HasMethod.php', 'Psalm\\Storage\\Assertion\\HasStringArrayAccess' => __DIR__ . '/../..' . '/src/Psalm/Storage/Assertion/HasStringArrayAccess.php', 'Psalm\\Storage\\Assertion\\InArray' => __DIR__ . '/../..' . '/src/Psalm/Storage/Assertion/InArray.php', 'Psalm\\Storage\\Assertion\\IsAClass' => __DIR__ . '/../..' . '/src/Psalm/Storage/Assertion/IsAClass.php', 'Psalm\\Storage\\Assertion\\IsClassEqual' => __DIR__ . '/../..' . '/src/Psalm/Storage/Assertion/IsClassEqual.php', 'Psalm\\Storage\\Assertion\\IsClassNotEqual' => __DIR__ . '/../..' . '/src/Psalm/Storage/Assertion/IsClassNotEqual.php', 'Psalm\\Storage\\Assertion\\IsCountable' => __DIR__ . '/../..' . '/src/Psalm/Storage/Assertion/IsCountable.php', 'Psalm\\Storage\\Assertion\\IsEqualIsset' => __DIR__ . '/../..' . '/src/Psalm/Storage/Assertion/IsEqualIsset.php', 'Psalm\\Storage\\Assertion\\IsGreaterThan' => __DIR__ . '/../..' . '/src/Psalm/Storage/Assertion/IsGreaterThan.php', 'Psalm\\Storage\\Assertion\\IsGreaterThanOrEqualTo' => __DIR__ . '/../..' . '/src/Psalm/Storage/Assertion/IsGreaterThanOrEqualTo.php', 'Psalm\\Storage\\Assertion\\IsIdentical' => __DIR__ . '/../..' . '/src/Psalm/Storage/Assertion/IsIdentical.php', 'Psalm\\Storage\\Assertion\\IsIsset' => __DIR__ . '/../..' . '/src/Psalm/Storage/Assertion/IsIsset.php', 'Psalm\\Storage\\Assertion\\IsLessThan' => __DIR__ . '/../..' . '/src/Psalm/Storage/Assertion/IsLessThan.php', 'Psalm\\Storage\\Assertion\\IsLessThanOrEqualTo' => __DIR__ . '/../..' . '/src/Psalm/Storage/Assertion/IsLessThanOrEqualTo.php', 'Psalm\\Storage\\Assertion\\IsLooselyEqual' => __DIR__ . '/../..' . '/src/Psalm/Storage/Assertion/IsLooselyEqual.php', 'Psalm\\Storage\\Assertion\\IsNotAClass' => __DIR__ . '/../..' . '/src/Psalm/Storage/Assertion/IsNotAClass.php', 'Psalm\\Storage\\Assertion\\IsNotCountable' => __DIR__ . '/../..' . '/src/Psalm/Storage/Assertion/IsNotCountable.php', 'Psalm\\Storage\\Assertion\\IsNotIdentical' => __DIR__ . '/../..' . '/src/Psalm/Storage/Assertion/IsNotIdentical.php', 'Psalm\\Storage\\Assertion\\IsNotIsset' => __DIR__ . '/../..' . '/src/Psalm/Storage/Assertion/IsNotIsset.php', 'Psalm\\Storage\\Assertion\\IsNotLooselyEqual' => __DIR__ . '/../..' . '/src/Psalm/Storage/Assertion/IsNotLooselyEqual.php', 'Psalm\\Storage\\Assertion\\IsNotType' => __DIR__ . '/../..' . '/src/Psalm/Storage/Assertion/IsNotType.php', 'Psalm\\Storage\\Assertion\\IsType' => __DIR__ . '/../..' . '/src/Psalm/Storage/Assertion/IsType.php', 'Psalm\\Storage\\Assertion\\NestedAssertions' => __DIR__ . '/../..' . '/src/Psalm/Storage/Assertion/NestedAssertions.php', 'Psalm\\Storage\\Assertion\\NonEmpty' => __DIR__ . '/../..' . '/src/Psalm/Storage/Assertion/NonEmpty.php', 'Psalm\\Storage\\Assertion\\NonEmptyCountable' => __DIR__ . '/../..' . '/src/Psalm/Storage/Assertion/NonEmptyCountable.php', 'Psalm\\Storage\\Assertion\\NotInArray' => __DIR__ . '/../..' . '/src/Psalm/Storage/Assertion/NotInArray.php', 'Psalm\\Storage\\Assertion\\NotNestedAssertions' => __DIR__ . '/../..' . '/src/Psalm/Storage/Assertion/NotNestedAssertions.php', 'Psalm\\Storage\\Assertion\\NotNonEmptyCountable' => __DIR__ . '/../..' . '/src/Psalm/Storage/Assertion/NotNonEmptyCountable.php', 'Psalm\\Storage\\Assertion\\Truthy' => __DIR__ . '/../..' . '/src/Psalm/Storage/Assertion/Truthy.php', 'Psalm\\Storage\\AttributeArg' => __DIR__ . '/../..' . '/src/Psalm/Storage/AttributeArg.php', 'Psalm\\Storage\\AttributeStorage' => __DIR__ . '/../..' . '/src/Psalm/Storage/AttributeStorage.php', 'Psalm\\Storage\\ClassConstantStorage' => __DIR__ . '/../..' . '/src/Psalm/Storage/ClassConstantStorage.php', 'Psalm\\Storage\\ClassLikeStorage' => __DIR__ . '/../..' . '/src/Psalm/Storage/ClassLikeStorage.php', 'Psalm\\Storage\\CustomMetadataTrait' => __DIR__ . '/../..' . '/src/Psalm/Storage/CustomMetadataTrait.php', 'Psalm\\Storage\\EnumCaseStorage' => __DIR__ . '/../..' . '/src/Psalm/Storage/EnumCaseStorage.php', 'Psalm\\Storage\\FileStorage' => __DIR__ . '/../..' . '/src/Psalm/Storage/FileStorage.php', 'Psalm\\Storage\\FunctionLikeParameter' => __DIR__ . '/../..' . '/src/Psalm/Storage/FunctionLikeParameter.php', 'Psalm\\Storage\\FunctionLikeStorage' => __DIR__ . '/../..' . '/src/Psalm/Storage/FunctionLikeStorage.php', 'Psalm\\Storage\\FunctionStorage' => __DIR__ . '/../..' . '/src/Psalm/Storage/FunctionStorage.php', 'Psalm\\Storage\\HasAttributesInterface' => __DIR__ . '/../..' . '/src/Psalm/Storage/HasAttributesInterface.php', 'Psalm\\Storage\\ImmutableNonCloneableTrait' => __DIR__ . '/../..' . '/src/Psalm/Storage/ImmutableNonCloneableTrait.php', 'Psalm\\Storage\\MethodStorage' => __DIR__ . '/../..' . '/src/Psalm/Storage/MethodStorage.php', 'Psalm\\Storage\\Possibilities' => __DIR__ . '/../..' . '/src/Psalm/Storage/Possibilities.php', 'Psalm\\Storage\\PropertyStorage' => __DIR__ . '/../..' . '/src/Psalm/Storage/PropertyStorage.php', 'Psalm\\Storage\\UnserializeMemoryUsageSuppressionTrait' => __DIR__ . '/../..' . '/src/Psalm/Storage/UnserializeMemoryUsageSuppressionTrait.php', 'Psalm\\Type' => __DIR__ . '/../..' . '/src/Psalm/Type.php', 'Psalm\\Type\\Atomic' => __DIR__ . '/../..' . '/src/Psalm/Type/Atomic.php', 'Psalm\\Type\\Atomic\\CallableTrait' => __DIR__ . '/../..' . '/src/Psalm/Type/Atomic/CallableTrait.php', 'Psalm\\Type\\Atomic\\DependentType' => __DIR__ . '/../..' . '/src/Psalm/Type/Atomic/DependentType.php', 'Psalm\\Type\\Atomic\\GenericTrait' => __DIR__ . '/../..' . '/src/Psalm/Type/Atomic/GenericTrait.php', 'Psalm\\Type\\Atomic\\HasIntersectionTrait' => __DIR__ . '/../..' . '/src/Psalm/Type/Atomic/HasIntersectionTrait.php', 'Psalm\\Type\\Atomic\\Scalar' => __DIR__ . '/../..' . '/src/Psalm/Type/Atomic/Scalar.php', 'Psalm\\Type\\Atomic\\TAnonymousClassInstance' => __DIR__ . '/../..' . '/src/Psalm/Type/Atomic/TAnonymousClassInstance.php', 'Psalm\\Type\\Atomic\\TArray' => __DIR__ . '/../..' . '/src/Psalm/Type/Atomic/TArray.php', 'Psalm\\Type\\Atomic\\TArrayKey' => __DIR__ . '/../..' . '/src/Psalm/Type/Atomic/TArrayKey.php', 'Psalm\\Type\\Atomic\\TBool' => __DIR__ . '/../..' . '/src/Psalm/Type/Atomic/TBool.php', 'Psalm\\Type\\Atomic\\TCallable' => __DIR__ . '/../..' . '/src/Psalm/Type/Atomic/TCallable.php', 'Psalm\\Type\\Atomic\\TCallableArray' => __DIR__ . '/../..' . '/src/Psalm/Type/Atomic/TCallableArray.php', 'Psalm\\Type\\Atomic\\TCallableInterface' => __DIR__ . '/../..' . '/src/Psalm/Type/Atomic/TCallableInterface.php', 'Psalm\\Type\\Atomic\\TCallableKeyedArray' => __DIR__ . '/../..' . '/src/Psalm/Type/Atomic/TCallableKeyedArray.php', 'Psalm\\Type\\Atomic\\TCallableList' => __DIR__ . '/../..' . '/src/Psalm/Type/Atomic/TCallableList.php', 'Psalm\\Type\\Atomic\\TCallableObject' => __DIR__ . '/../..' . '/src/Psalm/Type/Atomic/TCallableObject.php', 'Psalm\\Type\\Atomic\\TCallableString' => __DIR__ . '/../..' . '/src/Psalm/Type/Atomic/TCallableString.php', 'Psalm\\Type\\Atomic\\TClassConstant' => __DIR__ . '/../..' . '/src/Psalm/Type/Atomic/TClassConstant.php', 'Psalm\\Type\\Atomic\\TClassString' => __DIR__ . '/../..' . '/src/Psalm/Type/Atomic/TClassString.php', 'Psalm\\Type\\Atomic\\TClassStringMap' => __DIR__ . '/../..' . '/src/Psalm/Type/Atomic/TClassStringMap.php', 'Psalm\\Type\\Atomic\\TClosedResource' => __DIR__ . '/../..' . '/src/Psalm/Type/Atomic/TClosedResource.php', 'Psalm\\Type\\Atomic\\TClosure' => __DIR__ . '/../..' . '/src/Psalm/Type/Atomic/TClosure.php', 'Psalm\\Type\\Atomic\\TConditional' => __DIR__ . '/../..' . '/src/Psalm/Type/Atomic/TConditional.php', 'Psalm\\Type\\Atomic\\TDependentGetClass' => __DIR__ . '/../..' . '/src/Psalm/Type/Atomic/TDependentGetClass.php', 'Psalm\\Type\\Atomic\\TDependentGetDebugType' => __DIR__ . '/../..' . '/src/Psalm/Type/Atomic/TDependentGetDebugType.php', 'Psalm\\Type\\Atomic\\TDependentGetType' => __DIR__ . '/../..' . '/src/Psalm/Type/Atomic/TDependentGetType.php', 'Psalm\\Type\\Atomic\\TDependentListKey' => __DIR__ . '/../..' . '/src/Psalm/Type/Atomic/TDependentListKey.php', 'Psalm\\Type\\Atomic\\TEmptyMixed' => __DIR__ . '/../..' . '/src/Psalm/Type/Atomic/TEmptyMixed.php', 'Psalm\\Type\\Atomic\\TEmptyNumeric' => __DIR__ . '/../..' . '/src/Psalm/Type/Atomic/TEmptyNumeric.php', 'Psalm\\Type\\Atomic\\TEmptyScalar' => __DIR__ . '/../..' . '/src/Psalm/Type/Atomic/TEmptyScalar.php', 'Psalm\\Type\\Atomic\\TEnumCase' => __DIR__ . '/../..' . '/src/Psalm/Type/Atomic/TEnumCase.php', 'Psalm\\Type\\Atomic\\TFalse' => __DIR__ . '/../..' . '/src/Psalm/Type/Atomic/TFalse.php', 'Psalm\\Type\\Atomic\\TFloat' => __DIR__ . '/../..' . '/src/Psalm/Type/Atomic/TFloat.php', 'Psalm\\Type\\Atomic\\TGenericObject' => __DIR__ . '/../..' . '/src/Psalm/Type/Atomic/TGenericObject.php', 'Psalm\\Type\\Atomic\\TInt' => __DIR__ . '/../..' . '/src/Psalm/Type/Atomic/TInt.php', 'Psalm\\Type\\Atomic\\TIntMask' => __DIR__ . '/../..' . '/src/Psalm/Type/Atomic/TIntMask.php', 'Psalm\\Type\\Atomic\\TIntMaskOf' => __DIR__ . '/../..' . '/src/Psalm/Type/Atomic/TIntMaskOf.php', 'Psalm\\Type\\Atomic\\TIntRange' => __DIR__ . '/../..' . '/src/Psalm/Type/Atomic/TIntRange.php', 'Psalm\\Type\\Atomic\\TIterable' => __DIR__ . '/../..' . '/src/Psalm/Type/Atomic/TIterable.php', 'Psalm\\Type\\Atomic\\TKeyOf' => __DIR__ . '/../..' . '/src/Psalm/Type/Atomic/TKeyOf.php', 'Psalm\\Type\\Atomic\\TKeyedArray' => __DIR__ . '/../..' . '/src/Psalm/Type/Atomic/TKeyedArray.php', 'Psalm\\Type\\Atomic\\TList' => __DIR__ . '/../..' . '/src/Psalm/Type/Atomic/TList.php', 'Psalm\\Type\\Atomic\\TLiteralClassString' => __DIR__ . '/../..' . '/src/Psalm/Type/Atomic/TLiteralClassString.php', 'Psalm\\Type\\Atomic\\TLiteralFloat' => __DIR__ . '/../..' . '/src/Psalm/Type/Atomic/TLiteralFloat.php', 'Psalm\\Type\\Atomic\\TLiteralInt' => __DIR__ . '/../..' . '/src/Psalm/Type/Atomic/TLiteralInt.php', 'Psalm\\Type\\Atomic\\TLiteralString' => __DIR__ . '/../..' . '/src/Psalm/Type/Atomic/TLiteralString.php', 'Psalm\\Type\\Atomic\\TLowercaseString' => __DIR__ . '/../..' . '/src/Psalm/Type/Atomic/TLowercaseString.php', 'Psalm\\Type\\Atomic\\TMixed' => __DIR__ . '/../..' . '/src/Psalm/Type/Atomic/TMixed.php', 'Psalm\\Type\\Atomic\\TNamedObject' => __DIR__ . '/../..' . '/src/Psalm/Type/Atomic/TNamedObject.php', 'Psalm\\Type\\Atomic\\TNever' => __DIR__ . '/../..' . '/src/Psalm/Type/Atomic/TNever.php', 'Psalm\\Type\\Atomic\\TNonEmptyArray' => __DIR__ . '/../..' . '/src/Psalm/Type/Atomic/TNonEmptyArray.php', 'Psalm\\Type\\Atomic\\TNonEmptyList' => __DIR__ . '/../..' . '/src/Psalm/Type/Atomic/TNonEmptyList.php', 'Psalm\\Type\\Atomic\\TNonEmptyLowercaseString' => __DIR__ . '/../..' . '/src/Psalm/Type/Atomic/TNonEmptyLowercaseString.php', 'Psalm\\Type\\Atomic\\TNonEmptyMixed' => __DIR__ . '/../..' . '/src/Psalm/Type/Atomic/TNonEmptyMixed.php', 'Psalm\\Type\\Atomic\\TNonEmptyNonspecificLiteralString' => __DIR__ . '/../..' . '/src/Psalm/Type/Atomic/TNonEmptyNonspecificLiteralString.php', 'Psalm\\Type\\Atomic\\TNonEmptyScalar' => __DIR__ . '/../..' . '/src/Psalm/Type/Atomic/TNonEmptyScalar.php', 'Psalm\\Type\\Atomic\\TNonEmptyString' => __DIR__ . '/../..' . '/src/Psalm/Type/Atomic/TNonEmptyString.php', 'Psalm\\Type\\Atomic\\TNonFalsyString' => __DIR__ . '/../..' . '/src/Psalm/Type/Atomic/TNonFalsyString.php', 'Psalm\\Type\\Atomic\\TNonspecificLiteralInt' => __DIR__ . '/../..' . '/src/Psalm/Type/Atomic/TNonspecificLiteralInt.php', 'Psalm\\Type\\Atomic\\TNonspecificLiteralString' => __DIR__ . '/../..' . '/src/Psalm/Type/Atomic/TNonspecificLiteralString.php', 'Psalm\\Type\\Atomic\\TNull' => __DIR__ . '/../..' . '/src/Psalm/Type/Atomic/TNull.php', 'Psalm\\Type\\Atomic\\TNumeric' => __DIR__ . '/../..' . '/src/Psalm/Type/Atomic/TNumeric.php', 'Psalm\\Type\\Atomic\\TNumericString' => __DIR__ . '/../..' . '/src/Psalm/Type/Atomic/TNumericString.php', 'Psalm\\Type\\Atomic\\TObject' => __DIR__ . '/../..' . '/src/Psalm/Type/Atomic/TObject.php', 'Psalm\\Type\\Atomic\\TObjectWithProperties' => __DIR__ . '/../..' . '/src/Psalm/Type/Atomic/TObjectWithProperties.php', 'Psalm\\Type\\Atomic\\TPropertiesOf' => __DIR__ . '/../..' . '/src/Psalm/Type/Atomic/TPropertiesOf.php', 'Psalm\\Type\\Atomic\\TResource' => __DIR__ . '/../..' . '/src/Psalm/Type/Atomic/TResource.php', 'Psalm\\Type\\Atomic\\TScalar' => __DIR__ . '/../..' . '/src/Psalm/Type/Atomic/TScalar.php', 'Psalm\\Type\\Atomic\\TSingleLetter' => __DIR__ . '/../..' . '/src/Psalm/Type/Atomic/TSingleLetter.php', 'Psalm\\Type\\Atomic\\TString' => __DIR__ . '/../..' . '/src/Psalm/Type/Atomic/TString.php', 'Psalm\\Type\\Atomic\\TTemplateIndexedAccess' => __DIR__ . '/../..' . '/src/Psalm/Type/Atomic/TTemplateIndexedAccess.php', 'Psalm\\Type\\Atomic\\TTemplateKeyOf' => __DIR__ . '/../..' . '/src/Psalm/Type/Atomic/TTemplateKeyOf.php', 'Psalm\\Type\\Atomic\\TTemplateParam' => __DIR__ . '/../..' . '/src/Psalm/Type/Atomic/TTemplateParam.php', 'Psalm\\Type\\Atomic\\TTemplateParamClass' => __DIR__ . '/../..' . '/src/Psalm/Type/Atomic/TTemplateParamClass.php', 'Psalm\\Type\\Atomic\\TTemplatePropertiesOf' => __DIR__ . '/../..' . '/src/Psalm/Type/Atomic/TTemplatePropertiesOf.php', 'Psalm\\Type\\Atomic\\TTemplateValueOf' => __DIR__ . '/../..' . '/src/Psalm/Type/Atomic/TTemplateValueOf.php', 'Psalm\\Type\\Atomic\\TTraitString' => __DIR__ . '/../..' . '/src/Psalm/Type/Atomic/TTraitString.php', 'Psalm\\Type\\Atomic\\TTrue' => __DIR__ . '/../..' . '/src/Psalm/Type/Atomic/TTrue.php', 'Psalm\\Type\\Atomic\\TTypeAlias' => __DIR__ . '/../..' . '/src/Psalm/Type/Atomic/TTypeAlias.php', 'Psalm\\Type\\Atomic\\TUnknownClassString' => __DIR__ . '/../..' . '/src/Psalm/Type/Atomic/TUnknownClassString.php', 'Psalm\\Type\\Atomic\\TValueOf' => __DIR__ . '/../..' . '/src/Psalm/Type/Atomic/TValueOf.php', 'Psalm\\Type\\Atomic\\TVoid' => __DIR__ . '/../..' . '/src/Psalm/Type/Atomic/TVoid.php', 'Psalm\\Type\\MutableTypeVisitor' => __DIR__ . '/../..' . '/src/Psalm/Type/MutableTypeVisitor.php', 'Psalm\\Type\\MutableUnion' => __DIR__ . '/../..' . '/src/Psalm/Type/MutableUnion.php', 'Psalm\\Type\\Reconciler' => __DIR__ . '/../..' . '/src/Psalm/Type/Reconciler.php', 'Psalm\\Type\\TaintKind' => __DIR__ . '/../..' . '/src/Psalm/Type/TaintKind.php', 'Psalm\\Type\\TaintKindGroup' => __DIR__ . '/../..' . '/src/Psalm/Type/TaintKindGroup.php', 'Psalm\\Type\\TypeNode' => __DIR__ . '/../..' . '/src/Psalm/Type/TypeNode.php', 'Psalm\\Type\\TypeVisitor' => __DIR__ . '/../..' . '/src/Psalm/Type/TypeVisitor.php', 'Psalm\\Type\\Union' => __DIR__ . '/../..' . '/src/Psalm/Type/Union.php', 'Psalm\\Type\\UnionTrait' => __DIR__ . '/../..' . '/src/Psalm/Type/UnionTrait.php', 'Stringable' => __DIR__ . '/..' . '/symfony/polyfill-php80/Resources/stubs/Stringable.php', '_HumbugBox7ff99e199a36\\AdvancedJsonRpc\\Dispatcher' => __DIR__ . '/..' . '/felixfbecker/advanced-json-rpc/lib/Dispatcher.php', '_HumbugBox7ff99e199a36\\AdvancedJsonRpc\\Error' => __DIR__ . '/..' . '/felixfbecker/advanced-json-rpc/lib/Error.php', '_HumbugBox7ff99e199a36\\AdvancedJsonRpc\\ErrorCode' => __DIR__ . '/..' . '/felixfbecker/advanced-json-rpc/lib/ErrorCode.php', '_HumbugBox7ff99e199a36\\AdvancedJsonRpc\\ErrorResponse' => __DIR__ . '/..' . '/felixfbecker/advanced-json-rpc/lib/ErrorResponse.php', '_HumbugBox7ff99e199a36\\AdvancedJsonRpc\\Message' => __DIR__ . '/..' . '/felixfbecker/advanced-json-rpc/lib/Message.php', '_HumbugBox7ff99e199a36\\AdvancedJsonRpc\\Notification' => __DIR__ . '/..' . '/felixfbecker/advanced-json-rpc/lib/Notification.php', '_HumbugBox7ff99e199a36\\AdvancedJsonRpc\\Request' => __DIR__ . '/..' . '/felixfbecker/advanced-json-rpc/lib/Request.php', '_HumbugBox7ff99e199a36\\AdvancedJsonRpc\\Response' => __DIR__ . '/..' . '/felixfbecker/advanced-json-rpc/lib/Response.php', '_HumbugBox7ff99e199a36\\AdvancedJsonRpc\\SuccessResponse' => __DIR__ . '/..' . '/felixfbecker/advanced-json-rpc/lib/SuccessResponse.php', '_HumbugBox7ff99e199a36\\Amp\\ByteStream\\Base64\\Base64DecodingInputStream' => __DIR__ . '/..' . '/amphp/byte-stream/lib/Base64/Base64DecodingInputStream.php', '_HumbugBox7ff99e199a36\\Amp\\ByteStream\\Base64\\Base64DecodingOutputStream' => __DIR__ . '/..' . '/amphp/byte-stream/lib/Base64/Base64DecodingOutputStream.php', '_HumbugBox7ff99e199a36\\Amp\\ByteStream\\Base64\\Base64EncodingInputStream' => __DIR__ . '/..' . '/amphp/byte-stream/lib/Base64/Base64EncodingInputStream.php', '_HumbugBox7ff99e199a36\\Amp\\ByteStream\\Base64\\Base64EncodingOutputStream' => __DIR__ . '/..' . '/amphp/byte-stream/lib/Base64/Base64EncodingOutputStream.php', '_HumbugBox7ff99e199a36\\Amp\\ByteStream\\ClosedException' => __DIR__ . '/..' . '/amphp/byte-stream/lib/ClosedException.php', '_HumbugBox7ff99e199a36\\Amp\\ByteStream\\InMemoryStream' => __DIR__ . '/..' . '/amphp/byte-stream/lib/InMemoryStream.php', '_HumbugBox7ff99e199a36\\Amp\\ByteStream\\InputStream' => __DIR__ . '/..' . '/amphp/byte-stream/lib/InputStream.php', '_HumbugBox7ff99e199a36\\Amp\\ByteStream\\InputStreamChain' => __DIR__ . '/..' . '/amphp/byte-stream/lib/InputStreamChain.php', '_HumbugBox7ff99e199a36\\Amp\\ByteStream\\IteratorStream' => __DIR__ . '/..' . '/amphp/byte-stream/lib/IteratorStream.php', '_HumbugBox7ff99e199a36\\Amp\\ByteStream\\LineReader' => __DIR__ . '/..' . '/amphp/byte-stream/lib/LineReader.php', '_HumbugBox7ff99e199a36\\Amp\\ByteStream\\Message' => __DIR__ . '/..' . '/amphp/byte-stream/lib/Message.php', '_HumbugBox7ff99e199a36\\Amp\\ByteStream\\OutputBuffer' => __DIR__ . '/..' . '/amphp/byte-stream/lib/OutputBuffer.php', '_HumbugBox7ff99e199a36\\Amp\\ByteStream\\OutputStream' => __DIR__ . '/..' . '/amphp/byte-stream/lib/OutputStream.php', '_HumbugBox7ff99e199a36\\Amp\\ByteStream\\Payload' => __DIR__ . '/..' . '/amphp/byte-stream/lib/Payload.php', '_HumbugBox7ff99e199a36\\Amp\\ByteStream\\PendingReadError' => __DIR__ . '/..' . '/amphp/byte-stream/lib/PendingReadError.php', '_HumbugBox7ff99e199a36\\Amp\\ByteStream\\ResourceInputStream' => __DIR__ . '/..' . '/amphp/byte-stream/lib/ResourceInputStream.php', '_HumbugBox7ff99e199a36\\Amp\\ByteStream\\ResourceOutputStream' => __DIR__ . '/..' . '/amphp/byte-stream/lib/ResourceOutputStream.php', '_HumbugBox7ff99e199a36\\Amp\\ByteStream\\StreamException' => __DIR__ . '/..' . '/amphp/byte-stream/lib/StreamException.php', '_HumbugBox7ff99e199a36\\Amp\\ByteStream\\ZlibInputStream' => __DIR__ . '/..' . '/amphp/byte-stream/lib/ZlibInputStream.php', '_HumbugBox7ff99e199a36\\Amp\\ByteStream\\ZlibOutputStream' => __DIR__ . '/..' . '/amphp/byte-stream/lib/ZlibOutputStream.php', '_HumbugBox7ff99e199a36\\Amp\\CallableMaker' => __DIR__ . '/..' . '/amphp/amp/lib/CallableMaker.php', '_HumbugBox7ff99e199a36\\Amp\\CancellationToken' => __DIR__ . '/..' . '/amphp/amp/lib/CancellationToken.php', '_HumbugBox7ff99e199a36\\Amp\\CancellationTokenSource' => __DIR__ . '/..' . '/amphp/amp/lib/CancellationTokenSource.php', '_HumbugBox7ff99e199a36\\Amp\\CancelledException' => __DIR__ . '/..' . '/amphp/amp/lib/CancelledException.php', '_HumbugBox7ff99e199a36\\Amp\\CombinedCancellationToken' => __DIR__ . '/..' . '/amphp/amp/lib/CombinedCancellationToken.php', '_HumbugBox7ff99e199a36\\Amp\\Coroutine' => __DIR__ . '/..' . '/amphp/amp/lib/Coroutine.php', '_HumbugBox7ff99e199a36\\Amp\\Deferred' => __DIR__ . '/..' . '/amphp/amp/lib/Deferred.php', '_HumbugBox7ff99e199a36\\Amp\\Delayed' => __DIR__ . '/..' . '/amphp/amp/lib/Delayed.php', '_HumbugBox7ff99e199a36\\Amp\\Emitter' => __DIR__ . '/..' . '/amphp/amp/lib/Emitter.php', '_HumbugBox7ff99e199a36\\Amp\\Failure' => __DIR__ . '/..' . '/amphp/amp/lib/Failure.php', '_HumbugBox7ff99e199a36\\Amp\\Internal\\Placeholder' => __DIR__ . '/..' . '/amphp/amp/lib/Internal/Placeholder.php', '_HumbugBox7ff99e199a36\\Amp\\Internal\\PrivateIterator' => __DIR__ . '/..' . '/amphp/amp/lib/Internal/PrivateIterator.php', '_HumbugBox7ff99e199a36\\Amp\\Internal\\PrivatePromise' => __DIR__ . '/..' . '/amphp/amp/lib/Internal/PrivatePromise.php', '_HumbugBox7ff99e199a36\\Amp\\Internal\\Producer' => __DIR__ . '/..' . '/amphp/amp/lib/Internal/Producer.php', '_HumbugBox7ff99e199a36\\Amp\\Internal\\ResolutionQueue' => __DIR__ . '/..' . '/amphp/amp/lib/Internal/ResolutionQueue.php', '_HumbugBox7ff99e199a36\\Amp\\InvalidYieldError' => __DIR__ . '/..' . '/amphp/amp/lib/InvalidYieldError.php', '_HumbugBox7ff99e199a36\\Amp\\Iterator' => __DIR__ . '/..' . '/amphp/amp/lib/Iterator.php', '_HumbugBox7ff99e199a36\\Amp\\LazyPromise' => __DIR__ . '/..' . '/amphp/amp/lib/LazyPromise.php', '_HumbugBox7ff99e199a36\\Amp\\Loop' => __DIR__ . '/..' . '/amphp/amp/lib/Loop.php', '_HumbugBox7ff99e199a36\\Amp\\Loop\\Driver' => __DIR__ . '/..' . '/amphp/amp/lib/Loop/Driver.php', '_HumbugBox7ff99e199a36\\Amp\\Loop\\DriverFactory' => __DIR__ . '/..' . '/amphp/amp/lib/Loop/DriverFactory.php', '_HumbugBox7ff99e199a36\\Amp\\Loop\\EvDriver' => __DIR__ . '/..' . '/amphp/amp/lib/Loop/EvDriver.php', '_HumbugBox7ff99e199a36\\Amp\\Loop\\EventDriver' => __DIR__ . '/..' . '/amphp/amp/lib/Loop/EventDriver.php', '_HumbugBox7ff99e199a36\\Amp\\Loop\\Internal\\TimerQueue' => __DIR__ . '/..' . '/amphp/amp/lib/Loop/Internal/TimerQueue.php', '_HumbugBox7ff99e199a36\\Amp\\Loop\\InvalidWatcherError' => __DIR__ . '/..' . '/amphp/amp/lib/Loop/InvalidWatcherError.php', '_HumbugBox7ff99e199a36\\Amp\\Loop\\NativeDriver' => __DIR__ . '/..' . '/amphp/amp/lib/Loop/NativeDriver.php', '_HumbugBox7ff99e199a36\\Amp\\Loop\\TracingDriver' => __DIR__ . '/..' . '/amphp/amp/lib/Loop/TracingDriver.php', '_HumbugBox7ff99e199a36\\Amp\\Loop\\UnsupportedFeatureException' => __DIR__ . '/..' . '/amphp/amp/lib/Loop/UnsupportedFeatureException.php', '_HumbugBox7ff99e199a36\\Amp\\Loop\\UvDriver' => __DIR__ . '/..' . '/amphp/amp/lib/Loop/UvDriver.php', '_HumbugBox7ff99e199a36\\Amp\\Loop\\Watcher' => __DIR__ . '/..' . '/amphp/amp/lib/Loop/Watcher.php', '_HumbugBox7ff99e199a36\\Amp\\MultiReasonException' => __DIR__ . '/..' . '/amphp/amp/lib/MultiReasonException.php', '_HumbugBox7ff99e199a36\\Amp\\NullCancellationToken' => __DIR__ . '/..' . '/amphp/amp/lib/NullCancellationToken.php', '_HumbugBox7ff99e199a36\\Amp\\Producer' => __DIR__ . '/..' . '/amphp/amp/lib/Producer.php', '_HumbugBox7ff99e199a36\\Amp\\Promise' => __DIR__ . '/..' . '/amphp/amp/lib/Promise.php', '_HumbugBox7ff99e199a36\\Amp\\Struct' => __DIR__ . '/..' . '/amphp/amp/lib/Struct.php', '_HumbugBox7ff99e199a36\\Amp\\Success' => __DIR__ . '/..' . '/amphp/amp/lib/Success.php', '_HumbugBox7ff99e199a36\\Amp\\TimeoutCancellationToken' => __DIR__ . '/..' . '/amphp/amp/lib/TimeoutCancellationToken.php', '_HumbugBox7ff99e199a36\\Amp\\TimeoutException' => __DIR__ . '/..' . '/amphp/amp/lib/TimeoutException.php', '_HumbugBox7ff99e199a36\\Composer\\Pcre\\MatchAllResult' => __DIR__ . '/..' . '/composer/pcre/src/MatchAllResult.php', '_HumbugBox7ff99e199a36\\Composer\\Pcre\\MatchAllStrictGroupsResult' => __DIR__ . '/..' . '/composer/pcre/src/MatchAllStrictGroupsResult.php', '_HumbugBox7ff99e199a36\\Composer\\Pcre\\MatchAllWithOffsetsResult' => __DIR__ . '/..' . '/composer/pcre/src/MatchAllWithOffsetsResult.php', '_HumbugBox7ff99e199a36\\Composer\\Pcre\\MatchResult' => __DIR__ . '/..' . '/composer/pcre/src/MatchResult.php', '_HumbugBox7ff99e199a36\\Composer\\Pcre\\MatchStrictGroupsResult' => __DIR__ . '/..' . '/composer/pcre/src/MatchStrictGroupsResult.php', '_HumbugBox7ff99e199a36\\Composer\\Pcre\\MatchWithOffsetsResult' => __DIR__ . '/..' . '/composer/pcre/src/MatchWithOffsetsResult.php', '_HumbugBox7ff99e199a36\\Composer\\Pcre\\PHPStan\\InvalidRegexPatternRule' => __DIR__ . '/..' . '/composer/pcre/src/PHPStan/InvalidRegexPatternRule.php', '_HumbugBox7ff99e199a36\\Composer\\Pcre\\PHPStan\\PregMatchFlags' => __DIR__ . '/..' . '/composer/pcre/src/PHPStan/PregMatchFlags.php', '_HumbugBox7ff99e199a36\\Composer\\Pcre\\PHPStan\\PregMatchParameterOutTypeExtension' => __DIR__ . '/..' . '/composer/pcre/src/PHPStan/PregMatchParameterOutTypeExtension.php', '_HumbugBox7ff99e199a36\\Composer\\Pcre\\PHPStan\\PregMatchTypeSpecifyingExtension' => __DIR__ . '/..' . '/composer/pcre/src/PHPStan/PregMatchTypeSpecifyingExtension.php', '_HumbugBox7ff99e199a36\\Composer\\Pcre\\PHPStan\\PregReplaceCallbackClosureTypeExtension' => __DIR__ . '/..' . '/composer/pcre/src/PHPStan/PregReplaceCallbackClosureTypeExtension.php', '_HumbugBox7ff99e199a36\\Composer\\Pcre\\PHPStan\\UnsafeStrictGroupsCallRule' => __DIR__ . '/..' . '/composer/pcre/src/PHPStan/UnsafeStrictGroupsCallRule.php', '_HumbugBox7ff99e199a36\\Composer\\Pcre\\PcreException' => __DIR__ . '/..' . '/composer/pcre/src/PcreException.php', '_HumbugBox7ff99e199a36\\Composer\\Pcre\\Preg' => __DIR__ . '/..' . '/composer/pcre/src/Preg.php', '_HumbugBox7ff99e199a36\\Composer\\Pcre\\Regex' => __DIR__ . '/..' . '/composer/pcre/src/Regex.php', '_HumbugBox7ff99e199a36\\Composer\\Pcre\\ReplaceResult' => __DIR__ . '/..' . '/composer/pcre/src/ReplaceResult.php', '_HumbugBox7ff99e199a36\\Composer\\Pcre\\UnexpectedNullMatchException' => __DIR__ . '/..' . '/composer/pcre/src/UnexpectedNullMatchException.php', '_HumbugBox7ff99e199a36\\Composer\\Semver\\Comparator' => __DIR__ . '/..' . '/composer/semver/src/Comparator.php', '_HumbugBox7ff99e199a36\\Composer\\Semver\\CompilingMatcher' => __DIR__ . '/..' . '/composer/semver/src/CompilingMatcher.php', '_HumbugBox7ff99e199a36\\Composer\\Semver\\Constraint\\Bound' => __DIR__ . '/..' . '/composer/semver/src/Constraint/Bound.php', '_HumbugBox7ff99e199a36\\Composer\\Semver\\Constraint\\Constraint' => __DIR__ . '/..' . '/composer/semver/src/Constraint/Constraint.php', '_HumbugBox7ff99e199a36\\Composer\\Semver\\Constraint\\ConstraintInterface' => __DIR__ . '/..' . '/composer/semver/src/Constraint/ConstraintInterface.php', '_HumbugBox7ff99e199a36\\Composer\\Semver\\Constraint\\MatchAllConstraint' => __DIR__ . '/..' . '/composer/semver/src/Constraint/MatchAllConstraint.php', '_HumbugBox7ff99e199a36\\Composer\\Semver\\Constraint\\MatchNoneConstraint' => __DIR__ . '/..' . '/composer/semver/src/Constraint/MatchNoneConstraint.php', '_HumbugBox7ff99e199a36\\Composer\\Semver\\Constraint\\MultiConstraint' => __DIR__ . '/..' . '/composer/semver/src/Constraint/MultiConstraint.php', '_HumbugBox7ff99e199a36\\Composer\\Semver\\Interval' => __DIR__ . '/..' . '/composer/semver/src/Interval.php', '_HumbugBox7ff99e199a36\\Composer\\Semver\\Intervals' => __DIR__ . '/..' . '/composer/semver/src/Intervals.php', '_HumbugBox7ff99e199a36\\Composer\\Semver\\Semver' => __DIR__ . '/..' . '/composer/semver/src/Semver.php', '_HumbugBox7ff99e199a36\\Composer\\Semver\\VersionParser' => __DIR__ . '/..' . '/composer/semver/src/VersionParser.php', '_HumbugBox7ff99e199a36\\Composer\\XdebugHandler\\PhpConfig' => __DIR__ . '/..' . '/composer/xdebug-handler/src/PhpConfig.php', '_HumbugBox7ff99e199a36\\Composer\\XdebugHandler\\Process' => __DIR__ . '/..' . '/composer/xdebug-handler/src/Process.php', '_HumbugBox7ff99e199a36\\Composer\\XdebugHandler\\Status' => __DIR__ . '/..' . '/composer/xdebug-handler/src/Status.php', '_HumbugBox7ff99e199a36\\Composer\\XdebugHandler\\XdebugHandler' => __DIR__ . '/..' . '/composer/xdebug-handler/src/XdebugHandler.php', '_HumbugBox7ff99e199a36\\Doctrine\\Deprecations\\Deprecation' => __DIR__ . '/..' . '/doctrine/deprecations/lib/Doctrine/Deprecations/Deprecation.php', '_HumbugBox7ff99e199a36\\Doctrine\\Deprecations\\PHPUnit\\VerifyDeprecations' => __DIR__ . '/..' . '/doctrine/deprecations/lib/Doctrine/Deprecations/PHPUnit/VerifyDeprecations.php', '_HumbugBox7ff99e199a36\\Fidry\\CpuCoreCounter\\CpuCoreCounter' => __DIR__ . '/..' . '/fidry/cpu-core-counter/src/CpuCoreCounter.php', '_HumbugBox7ff99e199a36\\Fidry\\CpuCoreCounter\\Diagnoser' => __DIR__ . '/..' . '/fidry/cpu-core-counter/src/Diagnoser.php', '_HumbugBox7ff99e199a36\\Fidry\\CpuCoreCounter\\Executor\\ProcOpenExecutor' => __DIR__ . '/..' . '/fidry/cpu-core-counter/src/Executor/ProcOpenExecutor.php', '_HumbugBox7ff99e199a36\\Fidry\\CpuCoreCounter\\Executor\\ProcessExecutor' => __DIR__ . '/..' . '/fidry/cpu-core-counter/src/Executor/ProcessExecutor.php', '_HumbugBox7ff99e199a36\\Fidry\\CpuCoreCounter\\Finder\\CmiCmdletLogicalFinder' => __DIR__ . '/..' . '/fidry/cpu-core-counter/src/Finder/CmiCmdletLogicalFinder.php', '_HumbugBox7ff99e199a36\\Fidry\\CpuCoreCounter\\Finder\\CmiCmdletPhysicalFinder' => __DIR__ . '/..' . '/fidry/cpu-core-counter/src/Finder/CmiCmdletPhysicalFinder.php', '_HumbugBox7ff99e199a36\\Fidry\\CpuCoreCounter\\Finder\\CpuCoreFinder' => __DIR__ . '/..' . '/fidry/cpu-core-counter/src/Finder/CpuCoreFinder.php', '_HumbugBox7ff99e199a36\\Fidry\\CpuCoreCounter\\Finder\\CpuInfoFinder' => __DIR__ . '/..' . '/fidry/cpu-core-counter/src/Finder/CpuInfoFinder.php', '_HumbugBox7ff99e199a36\\Fidry\\CpuCoreCounter\\Finder\\DummyCpuCoreFinder' => __DIR__ . '/..' . '/fidry/cpu-core-counter/src/Finder/DummyCpuCoreFinder.php', '_HumbugBox7ff99e199a36\\Fidry\\CpuCoreCounter\\Finder\\EnvVariableFinder' => __DIR__ . '/..' . '/fidry/cpu-core-counter/src/Finder/EnvVariableFinder.php', '_HumbugBox7ff99e199a36\\Fidry\\CpuCoreCounter\\Finder\\FinderRegistry' => __DIR__ . '/..' . '/fidry/cpu-core-counter/src/Finder/FinderRegistry.php', '_HumbugBox7ff99e199a36\\Fidry\\CpuCoreCounter\\Finder\\HwLogicalFinder' => __DIR__ . '/..' . '/fidry/cpu-core-counter/src/Finder/HwLogicalFinder.php', '_HumbugBox7ff99e199a36\\Fidry\\CpuCoreCounter\\Finder\\HwPhysicalFinder' => __DIR__ . '/..' . '/fidry/cpu-core-counter/src/Finder/HwPhysicalFinder.php', '_HumbugBox7ff99e199a36\\Fidry\\CpuCoreCounter\\Finder\\LscpuLogicalFinder' => __DIR__ . '/..' . '/fidry/cpu-core-counter/src/Finder/LscpuLogicalFinder.php', '_HumbugBox7ff99e199a36\\Fidry\\CpuCoreCounter\\Finder\\LscpuPhysicalFinder' => __DIR__ . '/..' . '/fidry/cpu-core-counter/src/Finder/LscpuPhysicalFinder.php', '_HumbugBox7ff99e199a36\\Fidry\\CpuCoreCounter\\Finder\\NProcFinder' => __DIR__ . '/..' . '/fidry/cpu-core-counter/src/Finder/NProcFinder.php', '_HumbugBox7ff99e199a36\\Fidry\\CpuCoreCounter\\Finder\\NProcessorFinder' => __DIR__ . '/..' . '/fidry/cpu-core-counter/src/Finder/NProcessorFinder.php', '_HumbugBox7ff99e199a36\\Fidry\\CpuCoreCounter\\Finder\\NullCpuCoreFinder' => __DIR__ . '/..' . '/fidry/cpu-core-counter/src/Finder/NullCpuCoreFinder.php', '_HumbugBox7ff99e199a36\\Fidry\\CpuCoreCounter\\Finder\\OnlyInPowerShellFinder' => __DIR__ . '/..' . '/fidry/cpu-core-counter/src/Finder/OnlyInPowerShellFinder.php', '_HumbugBox7ff99e199a36\\Fidry\\CpuCoreCounter\\Finder\\OnlyOnOSFamilyFinder' => __DIR__ . '/..' . '/fidry/cpu-core-counter/src/Finder/OnlyOnOSFamilyFinder.php', '_HumbugBox7ff99e199a36\\Fidry\\CpuCoreCounter\\Finder\\ProcOpenBasedFinder' => __DIR__ . '/..' . '/fidry/cpu-core-counter/src/Finder/ProcOpenBasedFinder.php', '_HumbugBox7ff99e199a36\\Fidry\\CpuCoreCounter\\Finder\\SkipOnOSFamilyFinder' => __DIR__ . '/..' . '/fidry/cpu-core-counter/src/Finder/SkipOnOSFamilyFinder.php', '_HumbugBox7ff99e199a36\\Fidry\\CpuCoreCounter\\Finder\\WindowsRegistryLogicalFinder' => __DIR__ . '/..' . '/fidry/cpu-core-counter/src/Finder/WindowsRegistryLogicalFinder.php', '_HumbugBox7ff99e199a36\\Fidry\\CpuCoreCounter\\Finder\\WmicLogicalFinder' => __DIR__ . '/..' . '/fidry/cpu-core-counter/src/Finder/WmicLogicalFinder.php', '_HumbugBox7ff99e199a36\\Fidry\\CpuCoreCounter\\Finder\\WmicPhysicalFinder' => __DIR__ . '/..' . '/fidry/cpu-core-counter/src/Finder/WmicPhysicalFinder.php', '_HumbugBox7ff99e199a36\\Fidry\\CpuCoreCounter\\Finder\\_NProcessorFinder' => __DIR__ . '/..' . '/fidry/cpu-core-counter/src/Finder/_NProcessorFinder.php', '_HumbugBox7ff99e199a36\\Fidry\\CpuCoreCounter\\NumberOfCpuCoreNotFound' => __DIR__ . '/..' . '/fidry/cpu-core-counter/src/NumberOfCpuCoreNotFound.php', '_HumbugBox7ff99e199a36\\Fidry\\CpuCoreCounter\\ParallelisationResult' => __DIR__ . '/..' . '/fidry/cpu-core-counter/src/ParallelisationResult.php', '_HumbugBox7ff99e199a36\\JsonException' => __DIR__ . '/..' . '/symfony/polyfill-php73/Resources/stubs/JsonException.php', '_HumbugBox7ff99e199a36\\JsonMapper_Exception' => __DIR__ . '/..' . '/netresearch/jsonmapper/src/JsonMapper/Exception.php', '_HumbugBox7ff99e199a36\\LanguageServerProtocol\\CallHierarchyClientCapabilities' => __DIR__ . '/..' . '/felixfbecker/language-server-protocol/src/CallHierarchyClientCapabilities.php', '_HumbugBox7ff99e199a36\\LanguageServerProtocol\\ChangeAnnotation' => __DIR__ . '/..' . '/felixfbecker/language-server-protocol/src/ChangeAnnotation.php', '_HumbugBox7ff99e199a36\\LanguageServerProtocol\\ClientCapabilities' => __DIR__ . '/..' . '/felixfbecker/language-server-protocol/src/ClientCapabilities.php', '_HumbugBox7ff99e199a36\\LanguageServerProtocol\\ClientCapabilitiesGeneral' => __DIR__ . '/..' . '/felixfbecker/language-server-protocol/src/ClientCapabilitiesGeneral.php', '_HumbugBox7ff99e199a36\\LanguageServerProtocol\\ClientCapabilitiesWindow' => __DIR__ . '/..' . '/felixfbecker/language-server-protocol/src/ClientCapabilitiesWindow.php', '_HumbugBox7ff99e199a36\\LanguageServerProtocol\\ClientCapabilitiesWorkspace' => __DIR__ . '/..' . '/felixfbecker/language-server-protocol/src/ClientCapabilitiesWorkspace.php', '_HumbugBox7ff99e199a36\\LanguageServerProtocol\\ClientCapabilitiesWorkspaceFileOperations' => __DIR__ . '/..' . '/felixfbecker/language-server-protocol/src/ClientCapabilitiesWorkspaceFileOperations.php', '_HumbugBox7ff99e199a36\\LanguageServerProtocol\\ClientInfo' => __DIR__ . '/..' . '/felixfbecker/language-server-protocol/src/ClientInfo.php', '_HumbugBox7ff99e199a36\\LanguageServerProtocol\\CodeAction' => __DIR__ . '/..' . '/felixfbecker/language-server-protocol/src/CodeAction.php', '_HumbugBox7ff99e199a36\\LanguageServerProtocol\\CodeActionClientCapabilities' => __DIR__ . '/..' . '/felixfbecker/language-server-protocol/src/CodeActionClientCapabilities.php', '_HumbugBox7ff99e199a36\\LanguageServerProtocol\\CodeActionClientCapabilitiesCodeActionLiteralSupport' => __DIR__ . '/..' . '/felixfbecker/language-server-protocol/src/CodeActionClientCapabilitiesCodeActionLiteralSupport.php', '_HumbugBox7ff99e199a36\\LanguageServerProtocol\\CodeActionClientCapabilitiesCodeActionLiteralSupportcodeActionKind' => __DIR__ . '/..' . '/felixfbecker/language-server-protocol/src/CodeActionClientCapabilitiesCodeActionLiteralSupportcodeActionKind.php', '_HumbugBox7ff99e199a36\\LanguageServerProtocol\\CodeActionClientCapabilitiesResolveSupport' => __DIR__ . '/..' . '/felixfbecker/language-server-protocol/src/CodeActionClientCapabilitiesResolveSupport.php', '_HumbugBox7ff99e199a36\\LanguageServerProtocol\\CodeActionContext' => __DIR__ . '/..' . '/felixfbecker/language-server-protocol/src/CodeActionContext.php', '_HumbugBox7ff99e199a36\\LanguageServerProtocol\\CodeActionDisabled' => __DIR__ . '/..' . '/felixfbecker/language-server-protocol/src/CodeActionDisabled.php', '_HumbugBox7ff99e199a36\\LanguageServerProtocol\\CodeActionKind' => __DIR__ . '/..' . '/felixfbecker/language-server-protocol/src/CodeActionKind.php', '_HumbugBox7ff99e199a36\\LanguageServerProtocol\\CodeActionTriggerKind' => __DIR__ . '/..' . '/felixfbecker/language-server-protocol/src/CodeActionTriggerKind.php', '_HumbugBox7ff99e199a36\\LanguageServerProtocol\\CodeDescription' => __DIR__ . '/..' . '/felixfbecker/language-server-protocol/src/CodeDescription.php', '_HumbugBox7ff99e199a36\\LanguageServerProtocol\\CodeLens' => __DIR__ . '/..' . '/felixfbecker/language-server-protocol/src/CodeLens.php', '_HumbugBox7ff99e199a36\\LanguageServerProtocol\\CodeLensClientCapabilities' => __DIR__ . '/..' . '/felixfbecker/language-server-protocol/src/CodeLensClientCapabilities.php', '_HumbugBox7ff99e199a36\\LanguageServerProtocol\\CodeLensOptions' => __DIR__ . '/..' . '/felixfbecker/language-server-protocol/src/CodeLensOptions.php', '_HumbugBox7ff99e199a36\\LanguageServerProtocol\\CodeLensWorkspaceClientCapabilities' => __DIR__ . '/..' . '/felixfbecker/language-server-protocol/src/CodeLensWorkspaceClientCapabilities.php', '_HumbugBox7ff99e199a36\\LanguageServerProtocol\\Command' => __DIR__ . '/..' . '/felixfbecker/language-server-protocol/src/Command.php', '_HumbugBox7ff99e199a36\\LanguageServerProtocol\\CompletionClientCapabilities' => __DIR__ . '/..' . '/felixfbecker/language-server-protocol/src/CompletionClientCapabilities.php', '_HumbugBox7ff99e199a36\\LanguageServerProtocol\\CompletionClientCapabilitiesCompletionItem' => __DIR__ . '/..' . '/felixfbecker/language-server-protocol/src/CompletionClientCapabilitiesCompletionItem.php', '_HumbugBox7ff99e199a36\\LanguageServerProtocol\\CompletionClientCapabilitiesCompletionItemInsertTextModeSupport' => __DIR__ . '/..' . '/felixfbecker/language-server-protocol/src/CompletionClientCapabilitiesCompletionItemInsertTextModeSupport.php', '_HumbugBox7ff99e199a36\\LanguageServerProtocol\\CompletionClientCapabilitiesCompletionItemResolveSupport' => __DIR__ . '/..' . '/felixfbecker/language-server-protocol/src/CompletionClientCapabilitiesCompletionItemResolveSupport.php', '_HumbugBox7ff99e199a36\\LanguageServerProtocol\\CompletionClientCapabilitiesCompletionItemTagSupport' => __DIR__ . '/..' . '/felixfbecker/language-server-protocol/src/CompletionClientCapabilitiesCompletionItemTagSupport.php', '_HumbugBox7ff99e199a36\\LanguageServerProtocol\\CompletionClientCapabilitiesCompletionList' => __DIR__ . '/..' . '/felixfbecker/language-server-protocol/src/CompletionClientCapabilitiesCompletionList.php', '_HumbugBox7ff99e199a36\\LanguageServerProtocol\\CompletionContext' => __DIR__ . '/..' . '/felixfbecker/language-server-protocol/src/CompletionContext.php', '_HumbugBox7ff99e199a36\\LanguageServerProtocol\\CompletionItem' => __DIR__ . '/..' . '/felixfbecker/language-server-protocol/src/CompletionItem.php', '_HumbugBox7ff99e199a36\\LanguageServerProtocol\\CompletionItemKind' => __DIR__ . '/..' . '/felixfbecker/language-server-protocol/src/CompletionItemKind.php', '_HumbugBox7ff99e199a36\\LanguageServerProtocol\\CompletionItemLabelDetails' => __DIR__ . '/..' . '/felixfbecker/language-server-protocol/src/CompletionItemLabelDetails.php', '_HumbugBox7ff99e199a36\\LanguageServerProtocol\\CompletionItemTag' => __DIR__ . '/..' . '/felixfbecker/language-server-protocol/src/CompletionItemTag.php', '_HumbugBox7ff99e199a36\\LanguageServerProtocol\\CompletionList' => __DIR__ . '/..' . '/felixfbecker/language-server-protocol/src/CompletionList.php', '_HumbugBox7ff99e199a36\\LanguageServerProtocol\\CompletionOptions' => __DIR__ . '/..' . '/felixfbecker/language-server-protocol/src/CompletionOptions.php', '_HumbugBox7ff99e199a36\\LanguageServerProtocol\\CompletionTriggerKind' => __DIR__ . '/..' . '/felixfbecker/language-server-protocol/src/CompletionTriggerKind.php', '_HumbugBox7ff99e199a36\\LanguageServerProtocol\\ContentChangeEvent' => __DIR__ . '/..' . '/felixfbecker/language-server-protocol/src/ContentChangeEvent.php', '_HumbugBox7ff99e199a36\\LanguageServerProtocol\\DeclarationClientCapabilities' => __DIR__ . '/..' . '/felixfbecker/language-server-protocol/src/DeclarationClientCapabilities.php', '_HumbugBox7ff99e199a36\\LanguageServerProtocol\\DefinitionClientCapabilities' => __DIR__ . '/..' . '/felixfbecker/language-server-protocol/src/DefinitionClientCapabilities.php', '_HumbugBox7ff99e199a36\\LanguageServerProtocol\\DependencyReference' => __DIR__ . '/..' . '/felixfbecker/language-server-protocol/src/DependencyReference.php', '_HumbugBox7ff99e199a36\\LanguageServerProtocol\\Diagnostic' => __DIR__ . '/..' . '/felixfbecker/language-server-protocol/src/Diagnostic.php', '_HumbugBox7ff99e199a36\\LanguageServerProtocol\\DiagnosticRelatedInformation' => __DIR__ . '/..' . '/felixfbecker/language-server-protocol/src/DiagnosticRelatedInformation.php', '_HumbugBox7ff99e199a36\\LanguageServerProtocol\\DiagnosticSeverity' => __DIR__ . '/..' . '/felixfbecker/language-server-protocol/src/DiagnosticSeverity.php', '_HumbugBox7ff99e199a36\\LanguageServerProtocol\\DiagnosticTag' => __DIR__ . '/..' . '/felixfbecker/language-server-protocol/src/DiagnosticTag.php', '_HumbugBox7ff99e199a36\\LanguageServerProtocol\\DidChangeConfigurationClientCapabilities' => __DIR__ . '/..' . '/felixfbecker/language-server-protocol/src/DidChangeConfigurationClientCapabilities.php', '_HumbugBox7ff99e199a36\\LanguageServerProtocol\\DidChangeWatchedFilesClientCapabilities' => __DIR__ . '/..' . '/felixfbecker/language-server-protocol/src/DidChangeWatchedFilesClientCapabilities.php', '_HumbugBox7ff99e199a36\\LanguageServerProtocol\\DocumentColorClientCapabilities' => __DIR__ . '/..' . '/felixfbecker/language-server-protocol/src/DocumentColorClientCapabilities.php', '_HumbugBox7ff99e199a36\\LanguageServerProtocol\\DocumentFormattingClientCapabilities' => __DIR__ . '/..' . '/felixfbecker/language-server-protocol/src/DocumentFormattingClientCapabilities.php', '_HumbugBox7ff99e199a36\\LanguageServerProtocol\\DocumentHighlight' => __DIR__ . '/..' . '/felixfbecker/language-server-protocol/src/DocumentHighlight.php', '_HumbugBox7ff99e199a36\\LanguageServerProtocol\\DocumentHighlightClientCapabilities' => __DIR__ . '/..' . '/felixfbecker/language-server-protocol/src/DocumentHighlightClientCapabilities.php', '_HumbugBox7ff99e199a36\\LanguageServerProtocol\\DocumentHighlightKind' => __DIR__ . '/..' . '/felixfbecker/language-server-protocol/src/DocumentHighlightKind.php', '_HumbugBox7ff99e199a36\\LanguageServerProtocol\\DocumentLinkClientCapabilities' => __DIR__ . '/..' . '/felixfbecker/language-server-protocol/src/DocumentLinkClientCapabilities.php', '_HumbugBox7ff99e199a36\\LanguageServerProtocol\\DocumentOnTypeFormattingClientCapabilities' => __DIR__ . '/..' . '/felixfbecker/language-server-protocol/src/DocumentOnTypeFormattingClientCapabilities.php', '_HumbugBox7ff99e199a36\\LanguageServerProtocol\\DocumentOnTypeFormattingOptions' => __DIR__ . '/..' . '/felixfbecker/language-server-protocol/src/DocumentOnTypeFormattingOptions.php', '_HumbugBox7ff99e199a36\\LanguageServerProtocol\\DocumentRangeFormattingClientCapabilities' => __DIR__ . '/..' . '/felixfbecker/language-server-protocol/src/DocumentRangeFormattingClientCapabilities.php', '_HumbugBox7ff99e199a36\\LanguageServerProtocol\\DocumentSymbolClientCapabilities' => __DIR__ . '/..' . '/felixfbecker/language-server-protocol/src/DocumentSymbolClientCapabilities.php', '_HumbugBox7ff99e199a36\\LanguageServerProtocol\\DocumentSymbolClientCapabilitiesSymbolKind' => __DIR__ . '/..' . '/felixfbecker/language-server-protocol/src/DocumentSymbolClientCapabilitiesSymbolKind.php', '_HumbugBox7ff99e199a36\\LanguageServerProtocol\\DocumentSymbolClientCapabilitiesTagSupport' => __DIR__ . '/..' . '/felixfbecker/language-server-protocol/src/DocumentSymbolClientCapabilitiesTagSupport.php', '_HumbugBox7ff99e199a36\\LanguageServerProtocol\\ErrorCode' => __DIR__ . '/..' . '/felixfbecker/language-server-protocol/src/ErrorCode.php', '_HumbugBox7ff99e199a36\\LanguageServerProtocol\\ExecuteCommandClientCapabilities' => __DIR__ . '/..' . '/felixfbecker/language-server-protocol/src/ExecuteCommandClientCapabilities.php', '_HumbugBox7ff99e199a36\\LanguageServerProtocol\\ExecuteCommandOptions' => __DIR__ . '/..' . '/felixfbecker/language-server-protocol/src/ExecuteCommandOptions.php', '_HumbugBox7ff99e199a36\\LanguageServerProtocol\\FailureHandlingKind' => __DIR__ . '/..' . '/felixfbecker/language-server-protocol/src/FailureHandlingKind.php', '_HumbugBox7ff99e199a36\\LanguageServerProtocol\\FileChangeType' => __DIR__ . '/..' . '/felixfbecker/language-server-protocol/src/FileChangeType.php', '_HumbugBox7ff99e199a36\\LanguageServerProtocol\\FileEvent' => __DIR__ . '/..' . '/felixfbecker/language-server-protocol/src/FileEvent.php', '_HumbugBox7ff99e199a36\\LanguageServerProtocol\\FoldingRangeClientCapabilities' => __DIR__ . '/..' . '/felixfbecker/language-server-protocol/src/FoldingRangeClientCapabilities.php', '_HumbugBox7ff99e199a36\\LanguageServerProtocol\\FormattingOptions' => __DIR__ . '/..' . '/felixfbecker/language-server-protocol/src/FormattingOptions.php', '_HumbugBox7ff99e199a36\\LanguageServerProtocol\\Hover' => __DIR__ . '/..' . '/felixfbecker/language-server-protocol/src/Hover.php', '_HumbugBox7ff99e199a36\\LanguageServerProtocol\\HoverClientCapabilities' => __DIR__ . '/..' . '/felixfbecker/language-server-protocol/src/HoverClientCapabilities.php', '_HumbugBox7ff99e199a36\\LanguageServerProtocol\\ImplementationClientCapabilities' => __DIR__ . '/..' . '/felixfbecker/language-server-protocol/src/ImplementationClientCapabilities.php', '_HumbugBox7ff99e199a36\\LanguageServerProtocol\\InitializeResult' => __DIR__ . '/..' . '/felixfbecker/language-server-protocol/src/InitializeResult.php', '_HumbugBox7ff99e199a36\\LanguageServerProtocol\\InitializeResultServerInfo' => __DIR__ . '/..' . '/felixfbecker/language-server-protocol/src/InitializeResultServerInfo.php', '_HumbugBox7ff99e199a36\\LanguageServerProtocol\\InsertTextFormat' => __DIR__ . '/..' . '/felixfbecker/language-server-protocol/src/InsertTextFormat.php', '_HumbugBox7ff99e199a36\\LanguageServerProtocol\\InsertTextMode' => __DIR__ . '/..' . '/felixfbecker/language-server-protocol/src/InsertTextMode.php', '_HumbugBox7ff99e199a36\\LanguageServerProtocol\\LinkedEditingRangeClientCapabilities' => __DIR__ . '/..' . '/felixfbecker/language-server-protocol/src/LinkedEditingRangeClientCapabilities.php', '_HumbugBox7ff99e199a36\\LanguageServerProtocol\\Location' => __DIR__ . '/..' . '/felixfbecker/language-server-protocol/src/Location.php', '_HumbugBox7ff99e199a36\\LanguageServerProtocol\\LogMessage' => __DIR__ . '/..' . '/felixfbecker/language-server-protocol/src/LogMessage.php', '_HumbugBox7ff99e199a36\\LanguageServerProtocol\\LogTrace' => __DIR__ . '/..' . '/felixfbecker/language-server-protocol/src/LogTrace.php', '_HumbugBox7ff99e199a36\\LanguageServerProtocol\\MarkdownClientCapabilities' => __DIR__ . '/..' . '/felixfbecker/language-server-protocol/src/MarkdownClientCapabilities.php', '_HumbugBox7ff99e199a36\\LanguageServerProtocol\\MarkedString' => __DIR__ . '/..' . '/felixfbecker/language-server-protocol/src/MarkedString.php', '_HumbugBox7ff99e199a36\\LanguageServerProtocol\\MarkupContent' => __DIR__ . '/..' . '/felixfbecker/language-server-protocol/src/MarkupContent.php', '_HumbugBox7ff99e199a36\\LanguageServerProtocol\\MarkupKind' => __DIR__ . '/..' . '/felixfbecker/language-server-protocol/src/MarkupKind.php', '_HumbugBox7ff99e199a36\\LanguageServerProtocol\\MessageActionItem' => __DIR__ . '/..' . '/felixfbecker/language-server-protocol/src/MessageActionItem.php', '_HumbugBox7ff99e199a36\\LanguageServerProtocol\\MessageType' => __DIR__ . '/..' . '/felixfbecker/language-server-protocol/src/MessageType.php', '_HumbugBox7ff99e199a36\\LanguageServerProtocol\\MonikerClientCapabilities' => __DIR__ . '/..' . '/felixfbecker/language-server-protocol/src/MonikerClientCapabilities.php', '_HumbugBox7ff99e199a36\\LanguageServerProtocol\\PackageDescriptor' => __DIR__ . '/..' . '/felixfbecker/language-server-protocol/src/PackageDescriptor.php', '_HumbugBox7ff99e199a36\\LanguageServerProtocol\\ParameterInformation' => __DIR__ . '/..' . '/felixfbecker/language-server-protocol/src/ParameterInformation.php', '_HumbugBox7ff99e199a36\\LanguageServerProtocol\\Position' => __DIR__ . '/..' . '/felixfbecker/language-server-protocol/src/Position.php', '_HumbugBox7ff99e199a36\\LanguageServerProtocol\\PrepareSupportDefaultBehavior' => __DIR__ . '/..' . '/felixfbecker/language-server-protocol/src/PrepareSupportDefaultBehavior.php', '_HumbugBox7ff99e199a36\\LanguageServerProtocol\\PublishDiagnosticsClientCapabilities' => __DIR__ . '/..' . '/felixfbecker/language-server-protocol/src/PublishDiagnosticsClientCapabilities.php', '_HumbugBox7ff99e199a36\\LanguageServerProtocol\\PublishDiagnosticsClientCapabilitiesTagSupport' => __DIR__ . '/..' . '/felixfbecker/language-server-protocol/src/PublishDiagnosticsClientCapabilitiesTagSupport.php', '_HumbugBox7ff99e199a36\\LanguageServerProtocol\\Range' => __DIR__ . '/..' . '/felixfbecker/language-server-protocol/src/Range.php', '_HumbugBox7ff99e199a36\\LanguageServerProtocol\\ReferenceClientCapabilities' => __DIR__ . '/..' . '/felixfbecker/language-server-protocol/src/ReferenceClientCapabilities.php', '_HumbugBox7ff99e199a36\\LanguageServerProtocol\\ReferenceContext' => __DIR__ . '/..' . '/felixfbecker/language-server-protocol/src/ReferenceContext.php', '_HumbugBox7ff99e199a36\\LanguageServerProtocol\\ReferenceInformation' => __DIR__ . '/..' . '/felixfbecker/language-server-protocol/src/ReferenceInformation.php', '_HumbugBox7ff99e199a36\\LanguageServerProtocol\\RegularExpressionsClientCapabilities' => __DIR__ . '/..' . '/felixfbecker/language-server-protocol/src/RegularExpressionsClientCapabilities.php', '_HumbugBox7ff99e199a36\\LanguageServerProtocol\\RenameClientCapabilities' => __DIR__ . '/..' . '/felixfbecker/language-server-protocol/src/RenameClientCapabilities.php', '_HumbugBox7ff99e199a36\\LanguageServerProtocol\\ResourceOperationKind' => __DIR__ . '/..' . '/felixfbecker/language-server-protocol/src/ResourceOperationKind.php', '_HumbugBox7ff99e199a36\\LanguageServerProtocol\\SaveOptions' => __DIR__ . '/..' . '/felixfbecker/language-server-protocol/src/SaveOptions.php', '_HumbugBox7ff99e199a36\\LanguageServerProtocol\\SelectionRangeClientCapabilities' => __DIR__ . '/..' . '/felixfbecker/language-server-protocol/src/SelectionRangeClientCapabilities.php', '_HumbugBox7ff99e199a36\\LanguageServerProtocol\\SemanticTokensClientCapabilities' => __DIR__ . '/..' . '/felixfbecker/language-server-protocol/src/SemanticTokensClientCapabilities.php', '_HumbugBox7ff99e199a36\\LanguageServerProtocol\\SemanticTokensClientCapabilitiesRequests' => __DIR__ . '/..' . '/felixfbecker/language-server-protocol/src/SemanticTokensClientCapabilitiesRequests.php', '_HumbugBox7ff99e199a36\\LanguageServerProtocol\\SemanticTokensWorkspaceClientCapabilities' => __DIR__ . '/..' . '/felixfbecker/language-server-protocol/src/SemanticTokensWorkspaceClientCapabilities.php', '_HumbugBox7ff99e199a36\\LanguageServerProtocol\\ServerCapabilities' => __DIR__ . '/..' . '/felixfbecker/language-server-protocol/src/ServerCapabilities.php', '_HumbugBox7ff99e199a36\\LanguageServerProtocol\\ShowDocumentClientCapabilities' => __DIR__ . '/..' . '/felixfbecker/language-server-protocol/src/ShowDocumentClientCapabilities.php', '_HumbugBox7ff99e199a36\\LanguageServerProtocol\\ShowMessageRequestClientCapabilities' => __DIR__ . '/..' . '/felixfbecker/language-server-protocol/src/ShowMessageRequestClientCapabilities.php', '_HumbugBox7ff99e199a36\\LanguageServerProtocol\\ShowMessageRequestClientCapabilitiesMessageActionItem' => __DIR__ . '/..' . '/felixfbecker/language-server-protocol/src/ShowMessageRequestClientCapabilitiesMessageActionItem.php', '_HumbugBox7ff99e199a36\\LanguageServerProtocol\\SignatureHelp' => __DIR__ . '/..' . '/felixfbecker/language-server-protocol/src/SignatureHelp.php', '_HumbugBox7ff99e199a36\\LanguageServerProtocol\\SignatureHelpClientCapabilities' => __DIR__ . '/..' . '/felixfbecker/language-server-protocol/src/SignatureHelpClientCapabilities.php', '_HumbugBox7ff99e199a36\\LanguageServerProtocol\\SignatureHelpClientCapabilitiesSignatureInformation' => __DIR__ . '/..' . '/felixfbecker/language-server-protocol/src/SignatureHelpClientCapabilitiesSignatureInformation.php', '_HumbugBox7ff99e199a36\\LanguageServerProtocol\\SignatureHelpClientCapabilitiesSignatureInformationParameterInformation' => __DIR__ . '/..' . '/felixfbecker/language-server-protocol/src/SignatureHelpClientCapabilitiesSignatureInformationParameterInformation.php', '_HumbugBox7ff99e199a36\\LanguageServerProtocol\\SignatureHelpOptions' => __DIR__ . '/..' . '/felixfbecker/language-server-protocol/src/SignatureHelpOptions.php', '_HumbugBox7ff99e199a36\\LanguageServerProtocol\\SignatureInformation' => __DIR__ . '/..' . '/felixfbecker/language-server-protocol/src/SignatureInformation.php', '_HumbugBox7ff99e199a36\\LanguageServerProtocol\\SymbolDescriptor' => __DIR__ . '/..' . '/felixfbecker/language-server-protocol/src/SymbolDescriptor.php', '_HumbugBox7ff99e199a36\\LanguageServerProtocol\\SymbolInformation' => __DIR__ . '/..' . '/felixfbecker/language-server-protocol/src/SymbolInformation.php', '_HumbugBox7ff99e199a36\\LanguageServerProtocol\\SymbolKind' => __DIR__ . '/..' . '/felixfbecker/language-server-protocol/src/SymbolKind.php', '_HumbugBox7ff99e199a36\\LanguageServerProtocol\\SymbolLocationInformation' => __DIR__ . '/..' . '/felixfbecker/language-server-protocol/src/SymbolLocationInformation.php', '_HumbugBox7ff99e199a36\\LanguageServerProtocol\\SymbolTag' => __DIR__ . '/..' . '/felixfbecker/language-server-protocol/src/SymbolTag.php', '_HumbugBox7ff99e199a36\\LanguageServerProtocol\\TextDocumentClientCapabilities' => __DIR__ . '/..' . '/felixfbecker/language-server-protocol/src/TextDocumentClientCapabilities.php', '_HumbugBox7ff99e199a36\\LanguageServerProtocol\\TextDocumentContentChangeEvent' => __DIR__ . '/..' . '/felixfbecker/language-server-protocol/src/TextDocumentContentChangeEvent.php', '_HumbugBox7ff99e199a36\\LanguageServerProtocol\\TextDocumentIdentifier' => __DIR__ . '/..' . '/felixfbecker/language-server-protocol/src/TextDocumentIdentifier.php', '_HumbugBox7ff99e199a36\\LanguageServerProtocol\\TextDocumentItem' => __DIR__ . '/..' . '/felixfbecker/language-server-protocol/src/TextDocumentItem.php', '_HumbugBox7ff99e199a36\\LanguageServerProtocol\\TextDocumentSyncClientCapabilities' => __DIR__ . '/..' . '/felixfbecker/language-server-protocol/src/TextDocumentSyncClientCapabilities.php', '_HumbugBox7ff99e199a36\\LanguageServerProtocol\\TextDocumentSyncKind' => __DIR__ . '/..' . '/felixfbecker/language-server-protocol/src/TextDocumentSyncKind.php', '_HumbugBox7ff99e199a36\\LanguageServerProtocol\\TextDocumentSyncOptions' => __DIR__ . '/..' . '/felixfbecker/language-server-protocol/src/TextDocumentSyncOptions.php', '_HumbugBox7ff99e199a36\\LanguageServerProtocol\\TextEdit' => __DIR__ . '/..' . '/felixfbecker/language-server-protocol/src/TextEdit.php', '_HumbugBox7ff99e199a36\\LanguageServerProtocol\\TokenFormat' => __DIR__ . '/..' . '/felixfbecker/language-server-protocol/src/TokenFormat.php', '_HumbugBox7ff99e199a36\\LanguageServerProtocol\\TypeDefinitionClientCapabilities' => __DIR__ . '/..' . '/felixfbecker/language-server-protocol/src/TypeDefinitionClientCapabilities.php', '_HumbugBox7ff99e199a36\\LanguageServerProtocol\\VersionedTextDocumentIdentifier' => __DIR__ . '/..' . '/felixfbecker/language-server-protocol/src/VersionedTextDocumentIdentifier.php', '_HumbugBox7ff99e199a36\\LanguageServerProtocol\\WorkspaceEdit' => __DIR__ . '/..' . '/felixfbecker/language-server-protocol/src/WorkspaceEdit.php', '_HumbugBox7ff99e199a36\\LanguageServerProtocol\\WorkspaceEditClientCapabilities' => __DIR__ . '/..' . '/felixfbecker/language-server-protocol/src/WorkspaceEditClientCapabilities.php', '_HumbugBox7ff99e199a36\\LanguageServerProtocol\\WorkspaceEditClientCapabilitiesChangeAnnotationSupport' => __DIR__ . '/..' . '/felixfbecker/language-server-protocol/src/WorkspaceEditClientCapabilitiesChangeAnnotationSupport.php', '_HumbugBox7ff99e199a36\\LanguageServerProtocol\\WorkspaceFolder' => __DIR__ . '/..' . '/felixfbecker/language-server-protocol/src/WorkspaceFolder.php', '_HumbugBox7ff99e199a36\\LanguageServerProtocol\\WorkspaceSymbolClientCapabilities' => __DIR__ . '/..' . '/felixfbecker/language-server-protocol/src/WorkspaceSymbolClientCapabilities.php', '_HumbugBox7ff99e199a36\\LanguageServerProtocol\\WorkspaceSymbolClientCapabilitiesResolveSupport' => __DIR__ . '/..' . '/felixfbecker/language-server-protocol/src/WorkspaceSymbolClientCapabilitiesResolveSupport.php', '_HumbugBox7ff99e199a36\\LanguageServerProtocol\\WorkspaceSymbolClientCapabilitiesSymbolKind' => __DIR__ . '/..' . '/felixfbecker/language-server-protocol/src/WorkspaceSymbolClientCapabilitiesSymbolKind.php', '_HumbugBox7ff99e199a36\\LanguageServerProtocol\\WorkspaceSymbolClientCapabilitiesTagSupport' => __DIR__ . '/..' . '/felixfbecker/language-server-protocol/src/WorkspaceSymbolClientCapabilitiesTagSupport.php', '_HumbugBox7ff99e199a36\\Normalizer' => __DIR__ . '/..' . '/symfony/polyfill-intl-normalizer/Resources/stubs/Normalizer.php', '_HumbugBox7ff99e199a36\\PHPStan\\PhpDocParser\\Ast\\AbstractNodeVisitor' => __DIR__ . '/..' . '/phpstan/phpdoc-parser/src/Ast/AbstractNodeVisitor.php', '_HumbugBox7ff99e199a36\\PHPStan\\PhpDocParser\\Ast\\Attribute' => __DIR__ . '/..' . '/phpstan/phpdoc-parser/src/Ast/Attribute.php', '_HumbugBox7ff99e199a36\\PHPStan\\PhpDocParser\\Ast\\ConstExpr\\ConstExprArrayItemNode' => __DIR__ . '/..' . '/phpstan/phpdoc-parser/src/Ast/ConstExpr/ConstExprArrayItemNode.php', '_HumbugBox7ff99e199a36\\PHPStan\\PhpDocParser\\Ast\\ConstExpr\\ConstExprArrayNode' => __DIR__ . '/..' . '/phpstan/phpdoc-parser/src/Ast/ConstExpr/ConstExprArrayNode.php', '_HumbugBox7ff99e199a36\\PHPStan\\PhpDocParser\\Ast\\ConstExpr\\ConstExprFalseNode' => __DIR__ . '/..' . '/phpstan/phpdoc-parser/src/Ast/ConstExpr/ConstExprFalseNode.php', '_HumbugBox7ff99e199a36\\PHPStan\\PhpDocParser\\Ast\\ConstExpr\\ConstExprFloatNode' => __DIR__ . '/..' . '/phpstan/phpdoc-parser/src/Ast/ConstExpr/ConstExprFloatNode.php', '_HumbugBox7ff99e199a36\\PHPStan\\PhpDocParser\\Ast\\ConstExpr\\ConstExprIntegerNode' => __DIR__ . '/..' . '/phpstan/phpdoc-parser/src/Ast/ConstExpr/ConstExprIntegerNode.php', '_HumbugBox7ff99e199a36\\PHPStan\\PhpDocParser\\Ast\\ConstExpr\\ConstExprNode' => __DIR__ . '/..' . '/phpstan/phpdoc-parser/src/Ast/ConstExpr/ConstExprNode.php', '_HumbugBox7ff99e199a36\\PHPStan\\PhpDocParser\\Ast\\ConstExpr\\ConstExprNullNode' => __DIR__ . '/..' . '/phpstan/phpdoc-parser/src/Ast/ConstExpr/ConstExprNullNode.php', '_HumbugBox7ff99e199a36\\PHPStan\\PhpDocParser\\Ast\\ConstExpr\\ConstExprStringNode' => __DIR__ . '/..' . '/phpstan/phpdoc-parser/src/Ast/ConstExpr/ConstExprStringNode.php', '_HumbugBox7ff99e199a36\\PHPStan\\PhpDocParser\\Ast\\ConstExpr\\ConstExprTrueNode' => __DIR__ . '/..' . '/phpstan/phpdoc-parser/src/Ast/ConstExpr/ConstExprTrueNode.php', '_HumbugBox7ff99e199a36\\PHPStan\\PhpDocParser\\Ast\\ConstExpr\\ConstFetchNode' => __DIR__ . '/..' . '/phpstan/phpdoc-parser/src/Ast/ConstExpr/ConstFetchNode.php', '_HumbugBox7ff99e199a36\\PHPStan\\PhpDocParser\\Ast\\ConstExpr\\DoctrineConstExprStringNode' => __DIR__ . '/..' . '/phpstan/phpdoc-parser/src/Ast/ConstExpr/DoctrineConstExprStringNode.php', '_HumbugBox7ff99e199a36\\PHPStan\\PhpDocParser\\Ast\\ConstExpr\\QuoteAwareConstExprStringNode' => __DIR__ . '/..' . '/phpstan/phpdoc-parser/src/Ast/ConstExpr/QuoteAwareConstExprStringNode.php', '_HumbugBox7ff99e199a36\\PHPStan\\PhpDocParser\\Ast\\Node' => __DIR__ . '/..' . '/phpstan/phpdoc-parser/src/Ast/Node.php', '_HumbugBox7ff99e199a36\\PHPStan\\PhpDocParser\\Ast\\NodeAttributes' => __DIR__ . '/..' . '/phpstan/phpdoc-parser/src/Ast/NodeAttributes.php', '_HumbugBox7ff99e199a36\\PHPStan\\PhpDocParser\\Ast\\NodeTraverser' => __DIR__ . '/..' . '/phpstan/phpdoc-parser/src/Ast/NodeTraverser.php', '_HumbugBox7ff99e199a36\\PHPStan\\PhpDocParser\\Ast\\NodeVisitor' => __DIR__ . '/..' . '/phpstan/phpdoc-parser/src/Ast/NodeVisitor.php', '_HumbugBox7ff99e199a36\\PHPStan\\PhpDocParser\\Ast\\NodeVisitor\\CloningVisitor' => __DIR__ . '/..' . '/phpstan/phpdoc-parser/src/Ast/NodeVisitor/CloningVisitor.php', '_HumbugBox7ff99e199a36\\PHPStan\\PhpDocParser\\Ast\\PhpDoc\\AssertTagMethodValueNode' => __DIR__ . '/..' . '/phpstan/phpdoc-parser/src/Ast/PhpDoc/AssertTagMethodValueNode.php', '_HumbugBox7ff99e199a36\\PHPStan\\PhpDocParser\\Ast\\PhpDoc\\AssertTagPropertyValueNode' => __DIR__ . '/..' . '/phpstan/phpdoc-parser/src/Ast/PhpDoc/AssertTagPropertyValueNode.php', '_HumbugBox7ff99e199a36\\PHPStan\\PhpDocParser\\Ast\\PhpDoc\\AssertTagValueNode' => __DIR__ . '/..' . '/phpstan/phpdoc-parser/src/Ast/PhpDoc/AssertTagValueNode.php', '_HumbugBox7ff99e199a36\\PHPStan\\PhpDocParser\\Ast\\PhpDoc\\DeprecatedTagValueNode' => __DIR__ . '/..' . '/phpstan/phpdoc-parser/src/Ast/PhpDoc/DeprecatedTagValueNode.php', '_HumbugBox7ff99e199a36\\PHPStan\\PhpDocParser\\Ast\\PhpDoc\\Doctrine\\DoctrineAnnotation' => __DIR__ . '/..' . '/phpstan/phpdoc-parser/src/Ast/PhpDoc/Doctrine/DoctrineAnnotation.php', '_HumbugBox7ff99e199a36\\PHPStan\\PhpDocParser\\Ast\\PhpDoc\\Doctrine\\DoctrineArgument' => __DIR__ . '/..' . '/phpstan/phpdoc-parser/src/Ast/PhpDoc/Doctrine/DoctrineArgument.php', '_HumbugBox7ff99e199a36\\PHPStan\\PhpDocParser\\Ast\\PhpDoc\\Doctrine\\DoctrineArray' => __DIR__ . '/..' . '/phpstan/phpdoc-parser/src/Ast/PhpDoc/Doctrine/DoctrineArray.php', '_HumbugBox7ff99e199a36\\PHPStan\\PhpDocParser\\Ast\\PhpDoc\\Doctrine\\DoctrineArrayItem' => __DIR__ . '/..' . '/phpstan/phpdoc-parser/src/Ast/PhpDoc/Doctrine/DoctrineArrayItem.php', '_HumbugBox7ff99e199a36\\PHPStan\\PhpDocParser\\Ast\\PhpDoc\\Doctrine\\DoctrineTagValueNode' => __DIR__ . '/..' . '/phpstan/phpdoc-parser/src/Ast/PhpDoc/Doctrine/DoctrineTagValueNode.php', '_HumbugBox7ff99e199a36\\PHPStan\\PhpDocParser\\Ast\\PhpDoc\\ExtendsTagValueNode' => __DIR__ . '/..' . '/phpstan/phpdoc-parser/src/Ast/PhpDoc/ExtendsTagValueNode.php', '_HumbugBox7ff99e199a36\\PHPStan\\PhpDocParser\\Ast\\PhpDoc\\GenericTagValueNode' => __DIR__ . '/..' . '/phpstan/phpdoc-parser/src/Ast/PhpDoc/GenericTagValueNode.php', '_HumbugBox7ff99e199a36\\PHPStan\\PhpDocParser\\Ast\\PhpDoc\\ImplementsTagValueNode' => __DIR__ . '/..' . '/phpstan/phpdoc-parser/src/Ast/PhpDoc/ImplementsTagValueNode.php', '_HumbugBox7ff99e199a36\\PHPStan\\PhpDocParser\\Ast\\PhpDoc\\InvalidTagValueNode' => __DIR__ . '/..' . '/phpstan/phpdoc-parser/src/Ast/PhpDoc/InvalidTagValueNode.php', '_HumbugBox7ff99e199a36\\PHPStan\\PhpDocParser\\Ast\\PhpDoc\\MethodTagValueNode' => __DIR__ . '/..' . '/phpstan/phpdoc-parser/src/Ast/PhpDoc/MethodTagValueNode.php', '_HumbugBox7ff99e199a36\\PHPStan\\PhpDocParser\\Ast\\PhpDoc\\MethodTagValueParameterNode' => __DIR__ . '/..' . '/phpstan/phpdoc-parser/src/Ast/PhpDoc/MethodTagValueParameterNode.php', '_HumbugBox7ff99e199a36\\PHPStan\\PhpDocParser\\Ast\\PhpDoc\\MixinTagValueNode' => __DIR__ . '/..' . '/phpstan/phpdoc-parser/src/Ast/PhpDoc/MixinTagValueNode.php', '_HumbugBox7ff99e199a36\\PHPStan\\PhpDocParser\\Ast\\PhpDoc\\ParamClosureThisTagValueNode' => __DIR__ . '/..' . '/phpstan/phpdoc-parser/src/Ast/PhpDoc/ParamClosureThisTagValueNode.php', '_HumbugBox7ff99e199a36\\PHPStan\\PhpDocParser\\Ast\\PhpDoc\\ParamImmediatelyInvokedCallableTagValueNode' => __DIR__ . '/..' . '/phpstan/phpdoc-parser/src/Ast/PhpDoc/ParamImmediatelyInvokedCallableTagValueNode.php', '_HumbugBox7ff99e199a36\\PHPStan\\PhpDocParser\\Ast\\PhpDoc\\ParamLaterInvokedCallableTagValueNode' => __DIR__ . '/..' . '/phpstan/phpdoc-parser/src/Ast/PhpDoc/ParamLaterInvokedCallableTagValueNode.php', '_HumbugBox7ff99e199a36\\PHPStan\\PhpDocParser\\Ast\\PhpDoc\\ParamOutTagValueNode' => __DIR__ . '/..' . '/phpstan/phpdoc-parser/src/Ast/PhpDoc/ParamOutTagValueNode.php', '_HumbugBox7ff99e199a36\\PHPStan\\PhpDocParser\\Ast\\PhpDoc\\ParamTagValueNode' => __DIR__ . '/..' . '/phpstan/phpdoc-parser/src/Ast/PhpDoc/ParamTagValueNode.php', '_HumbugBox7ff99e199a36\\PHPStan\\PhpDocParser\\Ast\\PhpDoc\\PhpDocChildNode' => __DIR__ . '/..' . '/phpstan/phpdoc-parser/src/Ast/PhpDoc/PhpDocChildNode.php', '_HumbugBox7ff99e199a36\\PHPStan\\PhpDocParser\\Ast\\PhpDoc\\PhpDocNode' => __DIR__ . '/..' . '/phpstan/phpdoc-parser/src/Ast/PhpDoc/PhpDocNode.php', '_HumbugBox7ff99e199a36\\PHPStan\\PhpDocParser\\Ast\\PhpDoc\\PhpDocTagNode' => __DIR__ . '/..' . '/phpstan/phpdoc-parser/src/Ast/PhpDoc/PhpDocTagNode.php', '_HumbugBox7ff99e199a36\\PHPStan\\PhpDocParser\\Ast\\PhpDoc\\PhpDocTagValueNode' => __DIR__ . '/..' . '/phpstan/phpdoc-parser/src/Ast/PhpDoc/PhpDocTagValueNode.php', '_HumbugBox7ff99e199a36\\PHPStan\\PhpDocParser\\Ast\\PhpDoc\\PhpDocTextNode' => __DIR__ . '/..' . '/phpstan/phpdoc-parser/src/Ast/PhpDoc/PhpDocTextNode.php', '_HumbugBox7ff99e199a36\\PHPStan\\PhpDocParser\\Ast\\PhpDoc\\PropertyTagValueNode' => __DIR__ . '/..' . '/phpstan/phpdoc-parser/src/Ast/PhpDoc/PropertyTagValueNode.php', '_HumbugBox7ff99e199a36\\PHPStan\\PhpDocParser\\Ast\\PhpDoc\\RequireExtendsTagValueNode' => __DIR__ . '/..' . '/phpstan/phpdoc-parser/src/Ast/PhpDoc/RequireExtendsTagValueNode.php', '_HumbugBox7ff99e199a36\\PHPStan\\PhpDocParser\\Ast\\PhpDoc\\RequireImplementsTagValueNode' => __DIR__ . '/..' . '/phpstan/phpdoc-parser/src/Ast/PhpDoc/RequireImplementsTagValueNode.php', '_HumbugBox7ff99e199a36\\PHPStan\\PhpDocParser\\Ast\\PhpDoc\\ReturnTagValueNode' => __DIR__ . '/..' . '/phpstan/phpdoc-parser/src/Ast/PhpDoc/ReturnTagValueNode.php', '_HumbugBox7ff99e199a36\\PHPStan\\PhpDocParser\\Ast\\PhpDoc\\SelfOutTagValueNode' => __DIR__ . '/..' . '/phpstan/phpdoc-parser/src/Ast/PhpDoc/SelfOutTagValueNode.php', '_HumbugBox7ff99e199a36\\PHPStan\\PhpDocParser\\Ast\\PhpDoc\\TemplateTagValueNode' => __DIR__ . '/..' . '/phpstan/phpdoc-parser/src/Ast/PhpDoc/TemplateTagValueNode.php', '_HumbugBox7ff99e199a36\\PHPStan\\PhpDocParser\\Ast\\PhpDoc\\ThrowsTagValueNode' => __DIR__ . '/..' . '/phpstan/phpdoc-parser/src/Ast/PhpDoc/ThrowsTagValueNode.php', '_HumbugBox7ff99e199a36\\PHPStan\\PhpDocParser\\Ast\\PhpDoc\\TypeAliasImportTagValueNode' => __DIR__ . '/..' . '/phpstan/phpdoc-parser/src/Ast/PhpDoc/TypeAliasImportTagValueNode.php', '_HumbugBox7ff99e199a36\\PHPStan\\PhpDocParser\\Ast\\PhpDoc\\TypeAliasTagValueNode' => __DIR__ . '/..' . '/phpstan/phpdoc-parser/src/Ast/PhpDoc/TypeAliasTagValueNode.php', '_HumbugBox7ff99e199a36\\PHPStan\\PhpDocParser\\Ast\\PhpDoc\\TypelessParamTagValueNode' => __DIR__ . '/..' . '/phpstan/phpdoc-parser/src/Ast/PhpDoc/TypelessParamTagValueNode.php', '_HumbugBox7ff99e199a36\\PHPStan\\PhpDocParser\\Ast\\PhpDoc\\UsesTagValueNode' => __DIR__ . '/..' . '/phpstan/phpdoc-parser/src/Ast/PhpDoc/UsesTagValueNode.php', '_HumbugBox7ff99e199a36\\PHPStan\\PhpDocParser\\Ast\\PhpDoc\\VarTagValueNode' => __DIR__ . '/..' . '/phpstan/phpdoc-parser/src/Ast/PhpDoc/VarTagValueNode.php', '_HumbugBox7ff99e199a36\\PHPStan\\PhpDocParser\\Ast\\Type\\ArrayShapeItemNode' => __DIR__ . '/..' . '/phpstan/phpdoc-parser/src/Ast/Type/ArrayShapeItemNode.php', '_HumbugBox7ff99e199a36\\PHPStan\\PhpDocParser\\Ast\\Type\\ArrayShapeNode' => __DIR__ . '/..' . '/phpstan/phpdoc-parser/src/Ast/Type/ArrayShapeNode.php', '_HumbugBox7ff99e199a36\\PHPStan\\PhpDocParser\\Ast\\Type\\ArrayShapeUnsealedTypeNode' => __DIR__ . '/..' . '/phpstan/phpdoc-parser/src/Ast/Type/ArrayShapeUnsealedTypeNode.php', '_HumbugBox7ff99e199a36\\PHPStan\\PhpDocParser\\Ast\\Type\\ArrayTypeNode' => __DIR__ . '/..' . '/phpstan/phpdoc-parser/src/Ast/Type/ArrayTypeNode.php', '_HumbugBox7ff99e199a36\\PHPStan\\PhpDocParser\\Ast\\Type\\CallableTypeNode' => __DIR__ . '/..' . '/phpstan/phpdoc-parser/src/Ast/Type/CallableTypeNode.php', '_HumbugBox7ff99e199a36\\PHPStan\\PhpDocParser\\Ast\\Type\\CallableTypeParameterNode' => __DIR__ . '/..' . '/phpstan/phpdoc-parser/src/Ast/Type/CallableTypeParameterNode.php', '_HumbugBox7ff99e199a36\\PHPStan\\PhpDocParser\\Ast\\Type\\ConditionalTypeForParameterNode' => __DIR__ . '/..' . '/phpstan/phpdoc-parser/src/Ast/Type/ConditionalTypeForParameterNode.php', '_HumbugBox7ff99e199a36\\PHPStan\\PhpDocParser\\Ast\\Type\\ConditionalTypeNode' => __DIR__ . '/..' . '/phpstan/phpdoc-parser/src/Ast/Type/ConditionalTypeNode.php', '_HumbugBox7ff99e199a36\\PHPStan\\PhpDocParser\\Ast\\Type\\ConstTypeNode' => __DIR__ . '/..' . '/phpstan/phpdoc-parser/src/Ast/Type/ConstTypeNode.php', '_HumbugBox7ff99e199a36\\PHPStan\\PhpDocParser\\Ast\\Type\\GenericTypeNode' => __DIR__ . '/..' . '/phpstan/phpdoc-parser/src/Ast/Type/GenericTypeNode.php', '_HumbugBox7ff99e199a36\\PHPStan\\PhpDocParser\\Ast\\Type\\IdentifierTypeNode' => __DIR__ . '/..' . '/phpstan/phpdoc-parser/src/Ast/Type/IdentifierTypeNode.php', '_HumbugBox7ff99e199a36\\PHPStan\\PhpDocParser\\Ast\\Type\\IntersectionTypeNode' => __DIR__ . '/..' . '/phpstan/phpdoc-parser/src/Ast/Type/IntersectionTypeNode.php', '_HumbugBox7ff99e199a36\\PHPStan\\PhpDocParser\\Ast\\Type\\InvalidTypeNode' => __DIR__ . '/..' . '/phpstan/phpdoc-parser/src/Ast/Type/InvalidTypeNode.php', '_HumbugBox7ff99e199a36\\PHPStan\\PhpDocParser\\Ast\\Type\\NullableTypeNode' => __DIR__ . '/..' . '/phpstan/phpdoc-parser/src/Ast/Type/NullableTypeNode.php', '_HumbugBox7ff99e199a36\\PHPStan\\PhpDocParser\\Ast\\Type\\ObjectShapeItemNode' => __DIR__ . '/..' . '/phpstan/phpdoc-parser/src/Ast/Type/ObjectShapeItemNode.php', '_HumbugBox7ff99e199a36\\PHPStan\\PhpDocParser\\Ast\\Type\\ObjectShapeNode' => __DIR__ . '/..' . '/phpstan/phpdoc-parser/src/Ast/Type/ObjectShapeNode.php', '_HumbugBox7ff99e199a36\\PHPStan\\PhpDocParser\\Ast\\Type\\OffsetAccessTypeNode' => __DIR__ . '/..' . '/phpstan/phpdoc-parser/src/Ast/Type/OffsetAccessTypeNode.php', '_HumbugBox7ff99e199a36\\PHPStan\\PhpDocParser\\Ast\\Type\\ThisTypeNode' => __DIR__ . '/..' . '/phpstan/phpdoc-parser/src/Ast/Type/ThisTypeNode.php', '_HumbugBox7ff99e199a36\\PHPStan\\PhpDocParser\\Ast\\Type\\TypeNode' => __DIR__ . '/..' . '/phpstan/phpdoc-parser/src/Ast/Type/TypeNode.php', '_HumbugBox7ff99e199a36\\PHPStan\\PhpDocParser\\Ast\\Type\\UnionTypeNode' => __DIR__ . '/..' . '/phpstan/phpdoc-parser/src/Ast/Type/UnionTypeNode.php', '_HumbugBox7ff99e199a36\\PHPStan\\PhpDocParser\\Lexer\\Lexer' => __DIR__ . '/..' . '/phpstan/phpdoc-parser/src/Lexer/Lexer.php', '_HumbugBox7ff99e199a36\\PHPStan\\PhpDocParser\\Parser\\ConstExprParser' => __DIR__ . '/..' . '/phpstan/phpdoc-parser/src/Parser/ConstExprParser.php', '_HumbugBox7ff99e199a36\\PHPStan\\PhpDocParser\\Parser\\ParserException' => __DIR__ . '/..' . '/phpstan/phpdoc-parser/src/Parser/ParserException.php', '_HumbugBox7ff99e199a36\\PHPStan\\PhpDocParser\\Parser\\PhpDocParser' => __DIR__ . '/..' . '/phpstan/phpdoc-parser/src/Parser/PhpDocParser.php', '_HumbugBox7ff99e199a36\\PHPStan\\PhpDocParser\\Parser\\StringUnescaper' => __DIR__ . '/..' . '/phpstan/phpdoc-parser/src/Parser/StringUnescaper.php', '_HumbugBox7ff99e199a36\\PHPStan\\PhpDocParser\\Parser\\TokenIterator' => __DIR__ . '/..' . '/phpstan/phpdoc-parser/src/Parser/TokenIterator.php', '_HumbugBox7ff99e199a36\\PHPStan\\PhpDocParser\\Parser\\TypeParser' => __DIR__ . '/..' . '/phpstan/phpdoc-parser/src/Parser/TypeParser.php', '_HumbugBox7ff99e199a36\\PHPStan\\PhpDocParser\\Printer\\DiffElem' => __DIR__ . '/..' . '/phpstan/phpdoc-parser/src/Printer/DiffElem.php', '_HumbugBox7ff99e199a36\\PHPStan\\PhpDocParser\\Printer\\Differ' => __DIR__ . '/..' . '/phpstan/phpdoc-parser/src/Printer/Differ.php', '_HumbugBox7ff99e199a36\\PHPStan\\PhpDocParser\\Printer\\Printer' => __DIR__ . '/..' . '/phpstan/phpdoc-parser/src/Printer/Printer.php', '_HumbugBox7ff99e199a36\\PhpParser\\Builder' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Builder.php', '_HumbugBox7ff99e199a36\\PhpParser\\BuilderFactory' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/BuilderFactory.php', '_HumbugBox7ff99e199a36\\PhpParser\\BuilderHelpers' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/BuilderHelpers.php', '_HumbugBox7ff99e199a36\\PhpParser\\Builder\\ClassConst' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Builder/ClassConst.php', '_HumbugBox7ff99e199a36\\PhpParser\\Builder\\Class_' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Builder/Class_.php', '_HumbugBox7ff99e199a36\\PhpParser\\Builder\\Declaration' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Builder/Declaration.php', '_HumbugBox7ff99e199a36\\PhpParser\\Builder\\EnumCase' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Builder/EnumCase.php', '_HumbugBox7ff99e199a36\\PhpParser\\Builder\\Enum_' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Builder/Enum_.php', '_HumbugBox7ff99e199a36\\PhpParser\\Builder\\FunctionLike' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Builder/FunctionLike.php', '_HumbugBox7ff99e199a36\\PhpParser\\Builder\\Function_' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Builder/Function_.php', '_HumbugBox7ff99e199a36\\PhpParser\\Builder\\Interface_' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Builder/Interface_.php', '_HumbugBox7ff99e199a36\\PhpParser\\Builder\\Method' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Builder/Method.php', '_HumbugBox7ff99e199a36\\PhpParser\\Builder\\Namespace_' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Builder/Namespace_.php', '_HumbugBox7ff99e199a36\\PhpParser\\Builder\\Param' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Builder/Param.php', '_HumbugBox7ff99e199a36\\PhpParser\\Builder\\Property' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Builder/Property.php', '_HumbugBox7ff99e199a36\\PhpParser\\Builder\\TraitUse' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Builder/TraitUse.php', '_HumbugBox7ff99e199a36\\PhpParser\\Builder\\TraitUseAdaptation' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Builder/TraitUseAdaptation.php', '_HumbugBox7ff99e199a36\\PhpParser\\Builder\\Trait_' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Builder/Trait_.php', '_HumbugBox7ff99e199a36\\PhpParser\\Builder\\Use_' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Builder/Use_.php', '_HumbugBox7ff99e199a36\\PhpParser\\Comment' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Comment.php', '_HumbugBox7ff99e199a36\\PhpParser\\Comment\\Doc' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Comment/Doc.php', '_HumbugBox7ff99e199a36\\PhpParser\\ConstExprEvaluationException' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/ConstExprEvaluationException.php', '_HumbugBox7ff99e199a36\\PhpParser\\ConstExprEvaluator' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/ConstExprEvaluator.php', '_HumbugBox7ff99e199a36\\PhpParser\\Error' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Error.php', '_HumbugBox7ff99e199a36\\PhpParser\\ErrorHandler' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/ErrorHandler.php', '_HumbugBox7ff99e199a36\\PhpParser\\ErrorHandler\\Collecting' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/ErrorHandler/Collecting.php', '_HumbugBox7ff99e199a36\\PhpParser\\ErrorHandler\\Throwing' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/ErrorHandler/Throwing.php', '_HumbugBox7ff99e199a36\\PhpParser\\Internal\\DiffElem' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Internal/DiffElem.php', '_HumbugBox7ff99e199a36\\PhpParser\\Internal\\Differ' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Internal/Differ.php', '_HumbugBox7ff99e199a36\\PhpParser\\Internal\\PrintableNewAnonClassNode' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Internal/PrintableNewAnonClassNode.php', '_HumbugBox7ff99e199a36\\PhpParser\\Internal\\TokenStream' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Internal/TokenStream.php', '_HumbugBox7ff99e199a36\\PhpParser\\JsonDecoder' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/JsonDecoder.php', '_HumbugBox7ff99e199a36\\PhpParser\\Lexer' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Lexer.php', '_HumbugBox7ff99e199a36\\PhpParser\\Lexer\\Emulative' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Lexer/Emulative.php', '_HumbugBox7ff99e199a36\\PhpParser\\Lexer\\TokenEmulator\\AttributeEmulator' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Lexer/TokenEmulator/AttributeEmulator.php', '_HumbugBox7ff99e199a36\\PhpParser\\Lexer\\TokenEmulator\\CoaleseEqualTokenEmulator' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Lexer/TokenEmulator/CoaleseEqualTokenEmulator.php', '_HumbugBox7ff99e199a36\\PhpParser\\Lexer\\TokenEmulator\\EnumTokenEmulator' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Lexer/TokenEmulator/EnumTokenEmulator.php', '_HumbugBox7ff99e199a36\\PhpParser\\Lexer\\TokenEmulator\\ExplicitOctalEmulator' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Lexer/TokenEmulator/ExplicitOctalEmulator.php', '_HumbugBox7ff99e199a36\\PhpParser\\Lexer\\TokenEmulator\\FlexibleDocStringEmulator' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Lexer/TokenEmulator/FlexibleDocStringEmulator.php', '_HumbugBox7ff99e199a36\\PhpParser\\Lexer\\TokenEmulator\\FnTokenEmulator' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Lexer/TokenEmulator/FnTokenEmulator.php', '_HumbugBox7ff99e199a36\\PhpParser\\Lexer\\TokenEmulator\\KeywordEmulator' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Lexer/TokenEmulator/KeywordEmulator.php', '_HumbugBox7ff99e199a36\\PhpParser\\Lexer\\TokenEmulator\\MatchTokenEmulator' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Lexer/TokenEmulator/MatchTokenEmulator.php', '_HumbugBox7ff99e199a36\\PhpParser\\Lexer\\TokenEmulator\\NullsafeTokenEmulator' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Lexer/TokenEmulator/NullsafeTokenEmulator.php', '_HumbugBox7ff99e199a36\\PhpParser\\Lexer\\TokenEmulator\\NumericLiteralSeparatorEmulator' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Lexer/TokenEmulator/NumericLiteralSeparatorEmulator.php', '_HumbugBox7ff99e199a36\\PhpParser\\Lexer\\TokenEmulator\\ReadonlyFunctionTokenEmulator' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Lexer/TokenEmulator/ReadonlyFunctionTokenEmulator.php', '_HumbugBox7ff99e199a36\\PhpParser\\Lexer\\TokenEmulator\\ReadonlyTokenEmulator' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Lexer/TokenEmulator/ReadonlyTokenEmulator.php', '_HumbugBox7ff99e199a36\\PhpParser\\Lexer\\TokenEmulator\\ReverseEmulator' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Lexer/TokenEmulator/ReverseEmulator.php', '_HumbugBox7ff99e199a36\\PhpParser\\Lexer\\TokenEmulator\\TokenEmulator' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Lexer/TokenEmulator/TokenEmulator.php', '_HumbugBox7ff99e199a36\\PhpParser\\NameContext' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/NameContext.php', '_HumbugBox7ff99e199a36\\PhpParser\\Node' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Node.php', '_HumbugBox7ff99e199a36\\PhpParser\\NodeAbstract' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/NodeAbstract.php', '_HumbugBox7ff99e199a36\\PhpParser\\NodeDumper' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/NodeDumper.php', '_HumbugBox7ff99e199a36\\PhpParser\\NodeFinder' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/NodeFinder.php', '_HumbugBox7ff99e199a36\\PhpParser\\NodeTraverser' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/NodeTraverser.php', '_HumbugBox7ff99e199a36\\PhpParser\\NodeTraverserInterface' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/NodeTraverserInterface.php', '_HumbugBox7ff99e199a36\\PhpParser\\NodeVisitor' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/NodeVisitor.php', '_HumbugBox7ff99e199a36\\PhpParser\\NodeVisitorAbstract' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/NodeVisitorAbstract.php', '_HumbugBox7ff99e199a36\\PhpParser\\NodeVisitor\\CloningVisitor' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/NodeVisitor/CloningVisitor.php', '_HumbugBox7ff99e199a36\\PhpParser\\NodeVisitor\\FindingVisitor' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/NodeVisitor/FindingVisitor.php', '_HumbugBox7ff99e199a36\\PhpParser\\NodeVisitor\\FirstFindingVisitor' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/NodeVisitor/FirstFindingVisitor.php', '_HumbugBox7ff99e199a36\\PhpParser\\NodeVisitor\\NameResolver' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/NodeVisitor/NameResolver.php', '_HumbugBox7ff99e199a36\\PhpParser\\NodeVisitor\\NodeConnectingVisitor' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/NodeVisitor/NodeConnectingVisitor.php', '_HumbugBox7ff99e199a36\\PhpParser\\NodeVisitor\\ParentConnectingVisitor' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/NodeVisitor/ParentConnectingVisitor.php', '_HumbugBox7ff99e199a36\\PhpParser\\Node\\Arg' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Node/Arg.php', '_HumbugBox7ff99e199a36\\PhpParser\\Node\\Attribute' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Node/Attribute.php', '_HumbugBox7ff99e199a36\\PhpParser\\Node\\AttributeGroup' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Node/AttributeGroup.php', '_HumbugBox7ff99e199a36\\PhpParser\\Node\\ComplexType' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Node/ComplexType.php', '_HumbugBox7ff99e199a36\\PhpParser\\Node\\Const_' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Node/Const_.php', '_HumbugBox7ff99e199a36\\PhpParser\\Node\\Expr' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Node/Expr.php', '_HumbugBox7ff99e199a36\\PhpParser\\Node\\Expr\\ArrayDimFetch' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Node/Expr/ArrayDimFetch.php', '_HumbugBox7ff99e199a36\\PhpParser\\Node\\Expr\\ArrayItem' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Node/Expr/ArrayItem.php', '_HumbugBox7ff99e199a36\\PhpParser\\Node\\Expr\\Array_' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Node/Expr/Array_.php', '_HumbugBox7ff99e199a36\\PhpParser\\Node\\Expr\\ArrowFunction' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Node/Expr/ArrowFunction.php', '_HumbugBox7ff99e199a36\\PhpParser\\Node\\Expr\\Assign' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Node/Expr/Assign.php', '_HumbugBox7ff99e199a36\\PhpParser\\Node\\Expr\\AssignOp' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Node/Expr/AssignOp.php', '_HumbugBox7ff99e199a36\\PhpParser\\Node\\Expr\\AssignOp\\BitwiseAnd' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Node/Expr/AssignOp/BitwiseAnd.php', '_HumbugBox7ff99e199a36\\PhpParser\\Node\\Expr\\AssignOp\\BitwiseOr' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Node/Expr/AssignOp/BitwiseOr.php', '_HumbugBox7ff99e199a36\\PhpParser\\Node\\Expr\\AssignOp\\BitwiseXor' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Node/Expr/AssignOp/BitwiseXor.php', '_HumbugBox7ff99e199a36\\PhpParser\\Node\\Expr\\AssignOp\\Coalesce' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Node/Expr/AssignOp/Coalesce.php', '_HumbugBox7ff99e199a36\\PhpParser\\Node\\Expr\\AssignOp\\Concat' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Node/Expr/AssignOp/Concat.php', '_HumbugBox7ff99e199a36\\PhpParser\\Node\\Expr\\AssignOp\\Div' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Node/Expr/AssignOp/Div.php', '_HumbugBox7ff99e199a36\\PhpParser\\Node\\Expr\\AssignOp\\Minus' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Node/Expr/AssignOp/Minus.php', '_HumbugBox7ff99e199a36\\PhpParser\\Node\\Expr\\AssignOp\\Mod' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Node/Expr/AssignOp/Mod.php', '_HumbugBox7ff99e199a36\\PhpParser\\Node\\Expr\\AssignOp\\Mul' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Node/Expr/AssignOp/Mul.php', '_HumbugBox7ff99e199a36\\PhpParser\\Node\\Expr\\AssignOp\\Plus' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Node/Expr/AssignOp/Plus.php', '_HumbugBox7ff99e199a36\\PhpParser\\Node\\Expr\\AssignOp\\Pow' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Node/Expr/AssignOp/Pow.php', '_HumbugBox7ff99e199a36\\PhpParser\\Node\\Expr\\AssignOp\\ShiftLeft' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Node/Expr/AssignOp/ShiftLeft.php', '_HumbugBox7ff99e199a36\\PhpParser\\Node\\Expr\\AssignOp\\ShiftRight' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Node/Expr/AssignOp/ShiftRight.php', '_HumbugBox7ff99e199a36\\PhpParser\\Node\\Expr\\AssignRef' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Node/Expr/AssignRef.php', '_HumbugBox7ff99e199a36\\PhpParser\\Node\\Expr\\BinaryOp' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Node/Expr/BinaryOp.php', '_HumbugBox7ff99e199a36\\PhpParser\\Node\\Expr\\BinaryOp\\BitwiseAnd' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Node/Expr/BinaryOp/BitwiseAnd.php', '_HumbugBox7ff99e199a36\\PhpParser\\Node\\Expr\\BinaryOp\\BitwiseOr' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Node/Expr/BinaryOp/BitwiseOr.php', '_HumbugBox7ff99e199a36\\PhpParser\\Node\\Expr\\BinaryOp\\BitwiseXor' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Node/Expr/BinaryOp/BitwiseXor.php', '_HumbugBox7ff99e199a36\\PhpParser\\Node\\Expr\\BinaryOp\\BooleanAnd' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Node/Expr/BinaryOp/BooleanAnd.php', '_HumbugBox7ff99e199a36\\PhpParser\\Node\\Expr\\BinaryOp\\BooleanOr' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Node/Expr/BinaryOp/BooleanOr.php', '_HumbugBox7ff99e199a36\\PhpParser\\Node\\Expr\\BinaryOp\\Coalesce' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Node/Expr/BinaryOp/Coalesce.php', '_HumbugBox7ff99e199a36\\PhpParser\\Node\\Expr\\BinaryOp\\Concat' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Node/Expr/BinaryOp/Concat.php', '_HumbugBox7ff99e199a36\\PhpParser\\Node\\Expr\\BinaryOp\\Div' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Node/Expr/BinaryOp/Div.php', '_HumbugBox7ff99e199a36\\PhpParser\\Node\\Expr\\BinaryOp\\Equal' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Node/Expr/BinaryOp/Equal.php', '_HumbugBox7ff99e199a36\\PhpParser\\Node\\Expr\\BinaryOp\\Greater' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Node/Expr/BinaryOp/Greater.php', '_HumbugBox7ff99e199a36\\PhpParser\\Node\\Expr\\BinaryOp\\GreaterOrEqual' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Node/Expr/BinaryOp/GreaterOrEqual.php', '_HumbugBox7ff99e199a36\\PhpParser\\Node\\Expr\\BinaryOp\\Identical' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Node/Expr/BinaryOp/Identical.php', '_HumbugBox7ff99e199a36\\PhpParser\\Node\\Expr\\BinaryOp\\LogicalAnd' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Node/Expr/BinaryOp/LogicalAnd.php', '_HumbugBox7ff99e199a36\\PhpParser\\Node\\Expr\\BinaryOp\\LogicalOr' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Node/Expr/BinaryOp/LogicalOr.php', '_HumbugBox7ff99e199a36\\PhpParser\\Node\\Expr\\BinaryOp\\LogicalXor' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Node/Expr/BinaryOp/LogicalXor.php', '_HumbugBox7ff99e199a36\\PhpParser\\Node\\Expr\\BinaryOp\\Minus' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Node/Expr/BinaryOp/Minus.php', '_HumbugBox7ff99e199a36\\PhpParser\\Node\\Expr\\BinaryOp\\Mod' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Node/Expr/BinaryOp/Mod.php', '_HumbugBox7ff99e199a36\\PhpParser\\Node\\Expr\\BinaryOp\\Mul' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Node/Expr/BinaryOp/Mul.php', '_HumbugBox7ff99e199a36\\PhpParser\\Node\\Expr\\BinaryOp\\NotEqual' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Node/Expr/BinaryOp/NotEqual.php', '_HumbugBox7ff99e199a36\\PhpParser\\Node\\Expr\\BinaryOp\\NotIdentical' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Node/Expr/BinaryOp/NotIdentical.php', '_HumbugBox7ff99e199a36\\PhpParser\\Node\\Expr\\BinaryOp\\Plus' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Node/Expr/BinaryOp/Plus.php', '_HumbugBox7ff99e199a36\\PhpParser\\Node\\Expr\\BinaryOp\\Pow' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Node/Expr/BinaryOp/Pow.php', '_HumbugBox7ff99e199a36\\PhpParser\\Node\\Expr\\BinaryOp\\ShiftLeft' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Node/Expr/BinaryOp/ShiftLeft.php', '_HumbugBox7ff99e199a36\\PhpParser\\Node\\Expr\\BinaryOp\\ShiftRight' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Node/Expr/BinaryOp/ShiftRight.php', '_HumbugBox7ff99e199a36\\PhpParser\\Node\\Expr\\BinaryOp\\Smaller' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Node/Expr/BinaryOp/Smaller.php', '_HumbugBox7ff99e199a36\\PhpParser\\Node\\Expr\\BinaryOp\\SmallerOrEqual' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Node/Expr/BinaryOp/SmallerOrEqual.php', '_HumbugBox7ff99e199a36\\PhpParser\\Node\\Expr\\BinaryOp\\Spaceship' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Node/Expr/BinaryOp/Spaceship.php', '_HumbugBox7ff99e199a36\\PhpParser\\Node\\Expr\\BitwiseNot' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Node/Expr/BitwiseNot.php', '_HumbugBox7ff99e199a36\\PhpParser\\Node\\Expr\\BooleanNot' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Node/Expr/BooleanNot.php', '_HumbugBox7ff99e199a36\\PhpParser\\Node\\Expr\\CallLike' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Node/Expr/CallLike.php', '_HumbugBox7ff99e199a36\\PhpParser\\Node\\Expr\\Cast' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Node/Expr/Cast.php', '_HumbugBox7ff99e199a36\\PhpParser\\Node\\Expr\\Cast\\Array_' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Node/Expr/Cast/Array_.php', '_HumbugBox7ff99e199a36\\PhpParser\\Node\\Expr\\Cast\\Bool_' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Node/Expr/Cast/Bool_.php', '_HumbugBox7ff99e199a36\\PhpParser\\Node\\Expr\\Cast\\Double' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Node/Expr/Cast/Double.php', '_HumbugBox7ff99e199a36\\PhpParser\\Node\\Expr\\Cast\\Int_' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Node/Expr/Cast/Int_.php', '_HumbugBox7ff99e199a36\\PhpParser\\Node\\Expr\\Cast\\Object_' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Node/Expr/Cast/Object_.php', '_HumbugBox7ff99e199a36\\PhpParser\\Node\\Expr\\Cast\\String_' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Node/Expr/Cast/String_.php', '_HumbugBox7ff99e199a36\\PhpParser\\Node\\Expr\\Cast\\Unset_' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Node/Expr/Cast/Unset_.php', '_HumbugBox7ff99e199a36\\PhpParser\\Node\\Expr\\ClassConstFetch' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Node/Expr/ClassConstFetch.php', '_HumbugBox7ff99e199a36\\PhpParser\\Node\\Expr\\Clone_' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Node/Expr/Clone_.php', '_HumbugBox7ff99e199a36\\PhpParser\\Node\\Expr\\Closure' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Node/Expr/Closure.php', '_HumbugBox7ff99e199a36\\PhpParser\\Node\\Expr\\ClosureUse' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Node/Expr/ClosureUse.php', '_HumbugBox7ff99e199a36\\PhpParser\\Node\\Expr\\ConstFetch' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Node/Expr/ConstFetch.php', '_HumbugBox7ff99e199a36\\PhpParser\\Node\\Expr\\Empty_' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Node/Expr/Empty_.php', '_HumbugBox7ff99e199a36\\PhpParser\\Node\\Expr\\Error' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Node/Expr/Error.php', '_HumbugBox7ff99e199a36\\PhpParser\\Node\\Expr\\ErrorSuppress' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Node/Expr/ErrorSuppress.php', '_HumbugBox7ff99e199a36\\PhpParser\\Node\\Expr\\Eval_' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Node/Expr/Eval_.php', '_HumbugBox7ff99e199a36\\PhpParser\\Node\\Expr\\Exit_' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Node/Expr/Exit_.php', '_HumbugBox7ff99e199a36\\PhpParser\\Node\\Expr\\FuncCall' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Node/Expr/FuncCall.php', '_HumbugBox7ff99e199a36\\PhpParser\\Node\\Expr\\Include_' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Node/Expr/Include_.php', '_HumbugBox7ff99e199a36\\PhpParser\\Node\\Expr\\Instanceof_' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Node/Expr/Instanceof_.php', '_HumbugBox7ff99e199a36\\PhpParser\\Node\\Expr\\Isset_' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Node/Expr/Isset_.php', '_HumbugBox7ff99e199a36\\PhpParser\\Node\\Expr\\List_' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Node/Expr/List_.php', '_HumbugBox7ff99e199a36\\PhpParser\\Node\\Expr\\Match_' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Node/Expr/Match_.php', '_HumbugBox7ff99e199a36\\PhpParser\\Node\\Expr\\MethodCall' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Node/Expr/MethodCall.php', '_HumbugBox7ff99e199a36\\PhpParser\\Node\\Expr\\New_' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Node/Expr/New_.php', '_HumbugBox7ff99e199a36\\PhpParser\\Node\\Expr\\NullsafeMethodCall' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Node/Expr/NullsafeMethodCall.php', '_HumbugBox7ff99e199a36\\PhpParser\\Node\\Expr\\NullsafePropertyFetch' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Node/Expr/NullsafePropertyFetch.php', '_HumbugBox7ff99e199a36\\PhpParser\\Node\\Expr\\PostDec' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Node/Expr/PostDec.php', '_HumbugBox7ff99e199a36\\PhpParser\\Node\\Expr\\PostInc' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Node/Expr/PostInc.php', '_HumbugBox7ff99e199a36\\PhpParser\\Node\\Expr\\PreDec' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Node/Expr/PreDec.php', '_HumbugBox7ff99e199a36\\PhpParser\\Node\\Expr\\PreInc' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Node/Expr/PreInc.php', '_HumbugBox7ff99e199a36\\PhpParser\\Node\\Expr\\Print_' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Node/Expr/Print_.php', '_HumbugBox7ff99e199a36\\PhpParser\\Node\\Expr\\PropertyFetch' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Node/Expr/PropertyFetch.php', '_HumbugBox7ff99e199a36\\PhpParser\\Node\\Expr\\ShellExec' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Node/Expr/ShellExec.php', '_HumbugBox7ff99e199a36\\PhpParser\\Node\\Expr\\StaticCall' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Node/Expr/StaticCall.php', '_HumbugBox7ff99e199a36\\PhpParser\\Node\\Expr\\StaticPropertyFetch' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Node/Expr/StaticPropertyFetch.php', '_HumbugBox7ff99e199a36\\PhpParser\\Node\\Expr\\Ternary' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Node/Expr/Ternary.php', '_HumbugBox7ff99e199a36\\PhpParser\\Node\\Expr\\Throw_' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Node/Expr/Throw_.php', '_HumbugBox7ff99e199a36\\PhpParser\\Node\\Expr\\UnaryMinus' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Node/Expr/UnaryMinus.php', '_HumbugBox7ff99e199a36\\PhpParser\\Node\\Expr\\UnaryPlus' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Node/Expr/UnaryPlus.php', '_HumbugBox7ff99e199a36\\PhpParser\\Node\\Expr\\Variable' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Node/Expr/Variable.php', '_HumbugBox7ff99e199a36\\PhpParser\\Node\\Expr\\YieldFrom' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Node/Expr/YieldFrom.php', '_HumbugBox7ff99e199a36\\PhpParser\\Node\\Expr\\Yield_' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Node/Expr/Yield_.php', '_HumbugBox7ff99e199a36\\PhpParser\\Node\\FunctionLike' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Node/FunctionLike.php', '_HumbugBox7ff99e199a36\\PhpParser\\Node\\Identifier' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Node/Identifier.php', '_HumbugBox7ff99e199a36\\PhpParser\\Node\\IntersectionType' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Node/IntersectionType.php', '_HumbugBox7ff99e199a36\\PhpParser\\Node\\MatchArm' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Node/MatchArm.php', '_HumbugBox7ff99e199a36\\PhpParser\\Node\\Name' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Node/Name.php', '_HumbugBox7ff99e199a36\\PhpParser\\Node\\Name\\FullyQualified' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Node/Name/FullyQualified.php', '_HumbugBox7ff99e199a36\\PhpParser\\Node\\Name\\Relative' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Node/Name/Relative.php', '_HumbugBox7ff99e199a36\\PhpParser\\Node\\NullableType' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Node/NullableType.php', '_HumbugBox7ff99e199a36\\PhpParser\\Node\\Param' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Node/Param.php', '_HumbugBox7ff99e199a36\\PhpParser\\Node\\Scalar' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Node/Scalar.php', '_HumbugBox7ff99e199a36\\PhpParser\\Node\\Scalar\\DNumber' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Node/Scalar/DNumber.php', '_HumbugBox7ff99e199a36\\PhpParser\\Node\\Scalar\\Encapsed' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Node/Scalar/Encapsed.php', '_HumbugBox7ff99e199a36\\PhpParser\\Node\\Scalar\\EncapsedStringPart' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Node/Scalar/EncapsedStringPart.php', '_HumbugBox7ff99e199a36\\PhpParser\\Node\\Scalar\\LNumber' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Node/Scalar/LNumber.php', '_HumbugBox7ff99e199a36\\PhpParser\\Node\\Scalar\\MagicConst' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Node/Scalar/MagicConst.php', '_HumbugBox7ff99e199a36\\PhpParser\\Node\\Scalar\\MagicConst\\Class_' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Node/Scalar/MagicConst/Class_.php', '_HumbugBox7ff99e199a36\\PhpParser\\Node\\Scalar\\MagicConst\\Dir' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Node/Scalar/MagicConst/Dir.php', '_HumbugBox7ff99e199a36\\PhpParser\\Node\\Scalar\\MagicConst\\File' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Node/Scalar/MagicConst/File.php', '_HumbugBox7ff99e199a36\\PhpParser\\Node\\Scalar\\MagicConst\\Function_' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Node/Scalar/MagicConst/Function_.php', '_HumbugBox7ff99e199a36\\PhpParser\\Node\\Scalar\\MagicConst\\Line' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Node/Scalar/MagicConst/Line.php', '_HumbugBox7ff99e199a36\\PhpParser\\Node\\Scalar\\MagicConst\\Method' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Node/Scalar/MagicConst/Method.php', '_HumbugBox7ff99e199a36\\PhpParser\\Node\\Scalar\\MagicConst\\Namespace_' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Node/Scalar/MagicConst/Namespace_.php', '_HumbugBox7ff99e199a36\\PhpParser\\Node\\Scalar\\MagicConst\\Trait_' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Node/Scalar/MagicConst/Trait_.php', '_HumbugBox7ff99e199a36\\PhpParser\\Node\\Scalar\\String_' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Node/Scalar/String_.php', '_HumbugBox7ff99e199a36\\PhpParser\\Node\\Stmt' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Node/Stmt.php', '_HumbugBox7ff99e199a36\\PhpParser\\Node\\Stmt\\Break_' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Node/Stmt/Break_.php', '_HumbugBox7ff99e199a36\\PhpParser\\Node\\Stmt\\Case_' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Node/Stmt/Case_.php', '_HumbugBox7ff99e199a36\\PhpParser\\Node\\Stmt\\Catch_' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Node/Stmt/Catch_.php', '_HumbugBox7ff99e199a36\\PhpParser\\Node\\Stmt\\ClassConst' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Node/Stmt/ClassConst.php', '_HumbugBox7ff99e199a36\\PhpParser\\Node\\Stmt\\ClassLike' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Node/Stmt/ClassLike.php', '_HumbugBox7ff99e199a36\\PhpParser\\Node\\Stmt\\ClassMethod' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Node/Stmt/ClassMethod.php', '_HumbugBox7ff99e199a36\\PhpParser\\Node\\Stmt\\Class_' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Node/Stmt/Class_.php', '_HumbugBox7ff99e199a36\\PhpParser\\Node\\Stmt\\Const_' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Node/Stmt/Const_.php', '_HumbugBox7ff99e199a36\\PhpParser\\Node\\Stmt\\Continue_' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Node/Stmt/Continue_.php', '_HumbugBox7ff99e199a36\\PhpParser\\Node\\Stmt\\DeclareDeclare' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Node/Stmt/DeclareDeclare.php', '_HumbugBox7ff99e199a36\\PhpParser\\Node\\Stmt\\Declare_' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Node/Stmt/Declare_.php', '_HumbugBox7ff99e199a36\\PhpParser\\Node\\Stmt\\Do_' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Node/Stmt/Do_.php', '_HumbugBox7ff99e199a36\\PhpParser\\Node\\Stmt\\Echo_' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Node/Stmt/Echo_.php', '_HumbugBox7ff99e199a36\\PhpParser\\Node\\Stmt\\ElseIf_' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Node/Stmt/ElseIf_.php', '_HumbugBox7ff99e199a36\\PhpParser\\Node\\Stmt\\Else_' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Node/Stmt/Else_.php', '_HumbugBox7ff99e199a36\\PhpParser\\Node\\Stmt\\EnumCase' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Node/Stmt/EnumCase.php', '_HumbugBox7ff99e199a36\\PhpParser\\Node\\Stmt\\Enum_' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Node/Stmt/Enum_.php', '_HumbugBox7ff99e199a36\\PhpParser\\Node\\Stmt\\Expression' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Node/Stmt/Expression.php', '_HumbugBox7ff99e199a36\\PhpParser\\Node\\Stmt\\Finally_' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Node/Stmt/Finally_.php', '_HumbugBox7ff99e199a36\\PhpParser\\Node\\Stmt\\For_' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Node/Stmt/For_.php', '_HumbugBox7ff99e199a36\\PhpParser\\Node\\Stmt\\Foreach_' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Node/Stmt/Foreach_.php', '_HumbugBox7ff99e199a36\\PhpParser\\Node\\Stmt\\Function_' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Node/Stmt/Function_.php', '_HumbugBox7ff99e199a36\\PhpParser\\Node\\Stmt\\Global_' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Node/Stmt/Global_.php', '_HumbugBox7ff99e199a36\\PhpParser\\Node\\Stmt\\Goto_' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Node/Stmt/Goto_.php', '_HumbugBox7ff99e199a36\\PhpParser\\Node\\Stmt\\GroupUse' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Node/Stmt/GroupUse.php', '_HumbugBox7ff99e199a36\\PhpParser\\Node\\Stmt\\HaltCompiler' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Node/Stmt/HaltCompiler.php', '_HumbugBox7ff99e199a36\\PhpParser\\Node\\Stmt\\If_' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Node/Stmt/If_.php', '_HumbugBox7ff99e199a36\\PhpParser\\Node\\Stmt\\InlineHTML' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Node/Stmt/InlineHTML.php', '_HumbugBox7ff99e199a36\\PhpParser\\Node\\Stmt\\Interface_' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Node/Stmt/Interface_.php', '_HumbugBox7ff99e199a36\\PhpParser\\Node\\Stmt\\Label' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Node/Stmt/Label.php', '_HumbugBox7ff99e199a36\\PhpParser\\Node\\Stmt\\Namespace_' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Node/Stmt/Namespace_.php', '_HumbugBox7ff99e199a36\\PhpParser\\Node\\Stmt\\Nop' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Node/Stmt/Nop.php', '_HumbugBox7ff99e199a36\\PhpParser\\Node\\Stmt\\Property' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Node/Stmt/Property.php', '_HumbugBox7ff99e199a36\\PhpParser\\Node\\Stmt\\PropertyProperty' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Node/Stmt/PropertyProperty.php', '_HumbugBox7ff99e199a36\\PhpParser\\Node\\Stmt\\Return_' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Node/Stmt/Return_.php', '_HumbugBox7ff99e199a36\\PhpParser\\Node\\Stmt\\StaticVar' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Node/Stmt/StaticVar.php', '_HumbugBox7ff99e199a36\\PhpParser\\Node\\Stmt\\Static_' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Node/Stmt/Static_.php', '_HumbugBox7ff99e199a36\\PhpParser\\Node\\Stmt\\Switch_' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Node/Stmt/Switch_.php', '_HumbugBox7ff99e199a36\\PhpParser\\Node\\Stmt\\Throw_' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Node/Stmt/Throw_.php', '_HumbugBox7ff99e199a36\\PhpParser\\Node\\Stmt\\TraitUse' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Node/Stmt/TraitUse.php', '_HumbugBox7ff99e199a36\\PhpParser\\Node\\Stmt\\TraitUseAdaptation' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Node/Stmt/TraitUseAdaptation.php', '_HumbugBox7ff99e199a36\\PhpParser\\Node\\Stmt\\TraitUseAdaptation\\Alias' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Node/Stmt/TraitUseAdaptation/Alias.php', '_HumbugBox7ff99e199a36\\PhpParser\\Node\\Stmt\\TraitUseAdaptation\\Precedence' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Node/Stmt/TraitUseAdaptation/Precedence.php', '_HumbugBox7ff99e199a36\\PhpParser\\Node\\Stmt\\Trait_' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Node/Stmt/Trait_.php', '_HumbugBox7ff99e199a36\\PhpParser\\Node\\Stmt\\TryCatch' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Node/Stmt/TryCatch.php', '_HumbugBox7ff99e199a36\\PhpParser\\Node\\Stmt\\Unset_' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Node/Stmt/Unset_.php', '_HumbugBox7ff99e199a36\\PhpParser\\Node\\Stmt\\UseUse' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Node/Stmt/UseUse.php', '_HumbugBox7ff99e199a36\\PhpParser\\Node\\Stmt\\Use_' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Node/Stmt/Use_.php', '_HumbugBox7ff99e199a36\\PhpParser\\Node\\Stmt\\While_' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Node/Stmt/While_.php', '_HumbugBox7ff99e199a36\\PhpParser\\Node\\UnionType' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Node/UnionType.php', '_HumbugBox7ff99e199a36\\PhpParser\\Node\\VarLikeIdentifier' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Node/VarLikeIdentifier.php', '_HumbugBox7ff99e199a36\\PhpParser\\Node\\VariadicPlaceholder' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Node/VariadicPlaceholder.php', '_HumbugBox7ff99e199a36\\PhpParser\\Parser' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Parser.php', '_HumbugBox7ff99e199a36\\PhpParser\\ParserAbstract' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/ParserAbstract.php', '_HumbugBox7ff99e199a36\\PhpParser\\ParserFactory' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/ParserFactory.php', '_HumbugBox7ff99e199a36\\PhpParser\\Parser\\Multiple' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Parser/Multiple.php', '_HumbugBox7ff99e199a36\\PhpParser\\Parser\\Php5' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Parser/Php5.php', '_HumbugBox7ff99e199a36\\PhpParser\\Parser\\Php7' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Parser/Php7.php', '_HumbugBox7ff99e199a36\\PhpParser\\Parser\\Tokens' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Parser/Tokens.php', '_HumbugBox7ff99e199a36\\PhpParser\\PrettyPrinterAbstract' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/PrettyPrinterAbstract.php', '_HumbugBox7ff99e199a36\\PhpParser\\PrettyPrinter\\Standard' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/PrettyPrinter/Standard.php', '_HumbugBox7ff99e199a36\\Psr\\Container\\ContainerExceptionInterface' => __DIR__ . '/..' . '/psr/container/src/ContainerExceptionInterface.php', '_HumbugBox7ff99e199a36\\Psr\\Container\\ContainerInterface' => __DIR__ . '/..' . '/psr/container/src/ContainerInterface.php', '_HumbugBox7ff99e199a36\\Psr\\Container\\NotFoundExceptionInterface' => __DIR__ . '/..' . '/psr/container/src/NotFoundExceptionInterface.php', '_HumbugBox7ff99e199a36\\Psr\\Log\\AbstractLogger' => __DIR__ . '/..' . '/psr/log/Psr/Log/AbstractLogger.php', '_HumbugBox7ff99e199a36\\Psr\\Log\\InvalidArgumentException' => __DIR__ . '/..' . '/psr/log/Psr/Log/InvalidArgumentException.php', '_HumbugBox7ff99e199a36\\Psr\\Log\\LogLevel' => __DIR__ . '/..' . '/psr/log/Psr/Log/LogLevel.php', '_HumbugBox7ff99e199a36\\Psr\\Log\\LoggerAwareInterface' => __DIR__ . '/..' . '/psr/log/Psr/Log/LoggerAwareInterface.php', '_HumbugBox7ff99e199a36\\Psr\\Log\\LoggerAwareTrait' => __DIR__ . '/..' . '/psr/log/Psr/Log/LoggerAwareTrait.php', '_HumbugBox7ff99e199a36\\Psr\\Log\\LoggerInterface' => __DIR__ . '/..' . '/psr/log/Psr/Log/LoggerInterface.php', '_HumbugBox7ff99e199a36\\Psr\\Log\\LoggerTrait' => __DIR__ . '/..' . '/psr/log/Psr/Log/LoggerTrait.php', '_HumbugBox7ff99e199a36\\Psr\\Log\\NullLogger' => __DIR__ . '/..' . '/psr/log/Psr/Log/NullLogger.php', '_HumbugBox7ff99e199a36\\SebastianBergmann\\Diff\\Chunk' => __DIR__ . '/..' . '/sebastian/diff/src/Chunk.php', '_HumbugBox7ff99e199a36\\SebastianBergmann\\Diff\\ConfigurationException' => __DIR__ . '/..' . '/sebastian/diff/src/Exception/ConfigurationException.php', '_HumbugBox7ff99e199a36\\SebastianBergmann\\Diff\\Diff' => __DIR__ . '/..' . '/sebastian/diff/src/Diff.php', '_HumbugBox7ff99e199a36\\SebastianBergmann\\Diff\\Differ' => __DIR__ . '/..' . '/sebastian/diff/src/Differ.php', '_HumbugBox7ff99e199a36\\SebastianBergmann\\Diff\\Exception' => __DIR__ . '/..' . '/sebastian/diff/src/Exception/Exception.php', '_HumbugBox7ff99e199a36\\SebastianBergmann\\Diff\\InvalidArgumentException' => __DIR__ . '/..' . '/sebastian/diff/src/Exception/InvalidArgumentException.php', '_HumbugBox7ff99e199a36\\SebastianBergmann\\Diff\\Line' => __DIR__ . '/..' . '/sebastian/diff/src/Line.php', '_HumbugBox7ff99e199a36\\SebastianBergmann\\Diff\\LongestCommonSubsequenceCalculator' => __DIR__ . '/..' . '/sebastian/diff/src/LongestCommonSubsequenceCalculator.php', '_HumbugBox7ff99e199a36\\SebastianBergmann\\Diff\\MemoryEfficientLongestCommonSubsequenceCalculator' => __DIR__ . '/..' . '/sebastian/diff/src/MemoryEfficientLongestCommonSubsequenceCalculator.php', '_HumbugBox7ff99e199a36\\SebastianBergmann\\Diff\\Output\\AbstractChunkOutputBuilder' => __DIR__ . '/..' . '/sebastian/diff/src/Output/AbstractChunkOutputBuilder.php', '_HumbugBox7ff99e199a36\\SebastianBergmann\\Diff\\Output\\DiffOnlyOutputBuilder' => __DIR__ . '/..' . '/sebastian/diff/src/Output/DiffOnlyOutputBuilder.php', '_HumbugBox7ff99e199a36\\SebastianBergmann\\Diff\\Output\\DiffOutputBuilderInterface' => __DIR__ . '/..' . '/sebastian/diff/src/Output/DiffOutputBuilderInterface.php', '_HumbugBox7ff99e199a36\\SebastianBergmann\\Diff\\Output\\StrictUnifiedDiffOutputBuilder' => __DIR__ . '/..' . '/sebastian/diff/src/Output/StrictUnifiedDiffOutputBuilder.php', '_HumbugBox7ff99e199a36\\SebastianBergmann\\Diff\\Output\\UnifiedDiffOutputBuilder' => __DIR__ . '/..' . '/sebastian/diff/src/Output/UnifiedDiffOutputBuilder.php', '_HumbugBox7ff99e199a36\\SebastianBergmann\\Diff\\Parser' => __DIR__ . '/..' . '/sebastian/diff/src/Parser.php', '_HumbugBox7ff99e199a36\\SebastianBergmann\\Diff\\TimeEfficientLongestCommonSubsequenceCalculator' => __DIR__ . '/..' . '/sebastian/diff/src/TimeEfficientLongestCommonSubsequenceCalculator.php', '_HumbugBox7ff99e199a36\\Spatie\\ArrayToXml\\ArrayToXml' => __DIR__ . '/..' . '/spatie/array-to-xml/src/ArrayToXml.php', '_HumbugBox7ff99e199a36\\Symfony\\Component\\Console\\Application' => __DIR__ . '/..' . '/symfony/console/Application.php', '_HumbugBox7ff99e199a36\\Symfony\\Component\\Console\\Attribute\\AsCommand' => __DIR__ . '/..' . '/symfony/console/Attribute/AsCommand.php', '_HumbugBox7ff99e199a36\\Symfony\\Component\\Console\\CI\\GithubActionReporter' => __DIR__ . '/..' . '/symfony/console/CI/GithubActionReporter.php', '_HumbugBox7ff99e199a36\\Symfony\\Component\\Console\\Color' => __DIR__ . '/..' . '/symfony/console/Color.php', '_HumbugBox7ff99e199a36\\Symfony\\Component\\Console\\CommandLoader\\CommandLoaderInterface' => __DIR__ . '/..' . '/symfony/console/CommandLoader/CommandLoaderInterface.php', '_HumbugBox7ff99e199a36\\Symfony\\Component\\Console\\CommandLoader\\ContainerCommandLoader' => __DIR__ . '/..' . '/symfony/console/CommandLoader/ContainerCommandLoader.php', '_HumbugBox7ff99e199a36\\Symfony\\Component\\Console\\CommandLoader\\FactoryCommandLoader' => __DIR__ . '/..' . '/symfony/console/CommandLoader/FactoryCommandLoader.php', '_HumbugBox7ff99e199a36\\Symfony\\Component\\Console\\Command\\Command' => __DIR__ . '/..' . '/symfony/console/Command/Command.php', '_HumbugBox7ff99e199a36\\Symfony\\Component\\Console\\Command\\CompleteCommand' => __DIR__ . '/..' . '/symfony/console/Command/CompleteCommand.php', '_HumbugBox7ff99e199a36\\Symfony\\Component\\Console\\Command\\DumpCompletionCommand' => __DIR__ . '/..' . '/symfony/console/Command/DumpCompletionCommand.php', '_HumbugBox7ff99e199a36\\Symfony\\Component\\Console\\Command\\HelpCommand' => __DIR__ . '/..' . '/symfony/console/Command/HelpCommand.php', '_HumbugBox7ff99e199a36\\Symfony\\Component\\Console\\Command\\LazyCommand' => __DIR__ . '/..' . '/symfony/console/Command/LazyCommand.php', '_HumbugBox7ff99e199a36\\Symfony\\Component\\Console\\Command\\ListCommand' => __DIR__ . '/..' . '/symfony/console/Command/ListCommand.php', '_HumbugBox7ff99e199a36\\Symfony\\Component\\Console\\Command\\LockableTrait' => __DIR__ . '/..' . '/symfony/console/Command/LockableTrait.php', '_HumbugBox7ff99e199a36\\Symfony\\Component\\Console\\Command\\SignalableCommandInterface' => __DIR__ . '/..' . '/symfony/console/Command/SignalableCommandInterface.php', '_HumbugBox7ff99e199a36\\Symfony\\Component\\Console\\Completion\\CompletionInput' => __DIR__ . '/..' . '/symfony/console/Completion/CompletionInput.php', '_HumbugBox7ff99e199a36\\Symfony\\Component\\Console\\Completion\\CompletionSuggestions' => __DIR__ . '/..' . '/symfony/console/Completion/CompletionSuggestions.php', '_HumbugBox7ff99e199a36\\Symfony\\Component\\Console\\Completion\\Output\\BashCompletionOutput' => __DIR__ . '/..' . '/symfony/console/Completion/Output/BashCompletionOutput.php', '_HumbugBox7ff99e199a36\\Symfony\\Component\\Console\\Completion\\Output\\CompletionOutputInterface' => __DIR__ . '/..' . '/symfony/console/Completion/Output/CompletionOutputInterface.php', '_HumbugBox7ff99e199a36\\Symfony\\Component\\Console\\Completion\\Suggestion' => __DIR__ . '/..' . '/symfony/console/Completion/Suggestion.php', '_HumbugBox7ff99e199a36\\Symfony\\Component\\Console\\ConsoleEvents' => __DIR__ . '/..' . '/symfony/console/ConsoleEvents.php', '_HumbugBox7ff99e199a36\\Symfony\\Component\\Console\\Cursor' => __DIR__ . '/..' . '/symfony/console/Cursor.php', '_HumbugBox7ff99e199a36\\Symfony\\Component\\Console\\DependencyInjection\\AddConsoleCommandPass' => __DIR__ . '/..' . '/symfony/console/DependencyInjection/AddConsoleCommandPass.php', '_HumbugBox7ff99e199a36\\Symfony\\Component\\Console\\Descriptor\\ApplicationDescription' => __DIR__ . '/..' . '/symfony/console/Descriptor/ApplicationDescription.php', '_HumbugBox7ff99e199a36\\Symfony\\Component\\Console\\Descriptor\\Descriptor' => __DIR__ . '/..' . '/symfony/console/Descriptor/Descriptor.php', '_HumbugBox7ff99e199a36\\Symfony\\Component\\Console\\Descriptor\\DescriptorInterface' => __DIR__ . '/..' . '/symfony/console/Descriptor/DescriptorInterface.php', '_HumbugBox7ff99e199a36\\Symfony\\Component\\Console\\Descriptor\\JsonDescriptor' => __DIR__ . '/..' . '/symfony/console/Descriptor/JsonDescriptor.php', '_HumbugBox7ff99e199a36\\Symfony\\Component\\Console\\Descriptor\\MarkdownDescriptor' => __DIR__ . '/..' . '/symfony/console/Descriptor/MarkdownDescriptor.php', '_HumbugBox7ff99e199a36\\Symfony\\Component\\Console\\Descriptor\\TextDescriptor' => __DIR__ . '/..' . '/symfony/console/Descriptor/TextDescriptor.php', '_HumbugBox7ff99e199a36\\Symfony\\Component\\Console\\Descriptor\\XmlDescriptor' => __DIR__ . '/..' . '/symfony/console/Descriptor/XmlDescriptor.php', '_HumbugBox7ff99e199a36\\Symfony\\Component\\Console\\EventListener\\ErrorListener' => __DIR__ . '/..' . '/symfony/console/EventListener/ErrorListener.php', '_HumbugBox7ff99e199a36\\Symfony\\Component\\Console\\Event\\ConsoleCommandEvent' => __DIR__ . '/..' . '/symfony/console/Event/ConsoleCommandEvent.php', '_HumbugBox7ff99e199a36\\Symfony\\Component\\Console\\Event\\ConsoleErrorEvent' => __DIR__ . '/..' . '/symfony/console/Event/ConsoleErrorEvent.php', '_HumbugBox7ff99e199a36\\Symfony\\Component\\Console\\Event\\ConsoleEvent' => __DIR__ . '/..' . '/symfony/console/Event/ConsoleEvent.php', '_HumbugBox7ff99e199a36\\Symfony\\Component\\Console\\Event\\ConsoleSignalEvent' => __DIR__ . '/..' . '/symfony/console/Event/ConsoleSignalEvent.php', '_HumbugBox7ff99e199a36\\Symfony\\Component\\Console\\Event\\ConsoleTerminateEvent' => __DIR__ . '/..' . '/symfony/console/Event/ConsoleTerminateEvent.php', '_HumbugBox7ff99e199a36\\Symfony\\Component\\Console\\Exception\\CommandNotFoundException' => __DIR__ . '/..' . '/symfony/console/Exception/CommandNotFoundException.php', '_HumbugBox7ff99e199a36\\Symfony\\Component\\Console\\Exception\\ExceptionInterface' => __DIR__ . '/..' . '/symfony/console/Exception/ExceptionInterface.php', '_HumbugBox7ff99e199a36\\Symfony\\Component\\Console\\Exception\\InvalidArgumentException' => __DIR__ . '/..' . '/symfony/console/Exception/InvalidArgumentException.php', '_HumbugBox7ff99e199a36\\Symfony\\Component\\Console\\Exception\\InvalidOptionException' => __DIR__ . '/..' . '/symfony/console/Exception/InvalidOptionException.php', '_HumbugBox7ff99e199a36\\Symfony\\Component\\Console\\Exception\\LogicException' => __DIR__ . '/..' . '/symfony/console/Exception/LogicException.php', '_HumbugBox7ff99e199a36\\Symfony\\Component\\Console\\Exception\\MissingInputException' => __DIR__ . '/..' . '/symfony/console/Exception/MissingInputException.php', '_HumbugBox7ff99e199a36\\Symfony\\Component\\Console\\Exception\\NamespaceNotFoundException' => __DIR__ . '/..' . '/symfony/console/Exception/NamespaceNotFoundException.php', '_HumbugBox7ff99e199a36\\Symfony\\Component\\Console\\Exception\\RuntimeException' => __DIR__ . '/..' . '/symfony/console/Exception/RuntimeException.php', '_HumbugBox7ff99e199a36\\Symfony\\Component\\Console\\Formatter\\NullOutputFormatter' => __DIR__ . '/..' . '/symfony/console/Formatter/NullOutputFormatter.php', '_HumbugBox7ff99e199a36\\Symfony\\Component\\Console\\Formatter\\NullOutputFormatterStyle' => __DIR__ . '/..' . '/symfony/console/Formatter/NullOutputFormatterStyle.php', '_HumbugBox7ff99e199a36\\Symfony\\Component\\Console\\Formatter\\OutputFormatter' => __DIR__ . '/..' . '/symfony/console/Formatter/OutputFormatter.php', '_HumbugBox7ff99e199a36\\Symfony\\Component\\Console\\Formatter\\OutputFormatterInterface' => __DIR__ . '/..' . '/symfony/console/Formatter/OutputFormatterInterface.php', '_HumbugBox7ff99e199a36\\Symfony\\Component\\Console\\Formatter\\OutputFormatterStyle' => __DIR__ . '/..' . '/symfony/console/Formatter/OutputFormatterStyle.php', '_HumbugBox7ff99e199a36\\Symfony\\Component\\Console\\Formatter\\OutputFormatterStyleInterface' => __DIR__ . '/..' . '/symfony/console/Formatter/OutputFormatterStyleInterface.php', '_HumbugBox7ff99e199a36\\Symfony\\Component\\Console\\Formatter\\OutputFormatterStyleStack' => __DIR__ . '/..' . '/symfony/console/Formatter/OutputFormatterStyleStack.php', '_HumbugBox7ff99e199a36\\Symfony\\Component\\Console\\Formatter\\WrappableOutputFormatterInterface' => __DIR__ . '/..' . '/symfony/console/Formatter/WrappableOutputFormatterInterface.php', '_HumbugBox7ff99e199a36\\Symfony\\Component\\Console\\Helper\\DebugFormatterHelper' => __DIR__ . '/..' . '/symfony/console/Helper/DebugFormatterHelper.php', '_HumbugBox7ff99e199a36\\Symfony\\Component\\Console\\Helper\\DescriptorHelper' => __DIR__ . '/..' . '/symfony/console/Helper/DescriptorHelper.php', '_HumbugBox7ff99e199a36\\Symfony\\Component\\Console\\Helper\\Dumper' => __DIR__ . '/..' . '/symfony/console/Helper/Dumper.php', '_HumbugBox7ff99e199a36\\Symfony\\Component\\Console\\Helper\\FormatterHelper' => __DIR__ . '/..' . '/symfony/console/Helper/FormatterHelper.php', '_HumbugBox7ff99e199a36\\Symfony\\Component\\Console\\Helper\\Helper' => __DIR__ . '/..' . '/symfony/console/Helper/Helper.php', '_HumbugBox7ff99e199a36\\Symfony\\Component\\Console\\Helper\\HelperInterface' => __DIR__ . '/..' . '/symfony/console/Helper/HelperInterface.php', '_HumbugBox7ff99e199a36\\Symfony\\Component\\Console\\Helper\\HelperSet' => __DIR__ . '/..' . '/symfony/console/Helper/HelperSet.php', '_HumbugBox7ff99e199a36\\Symfony\\Component\\Console\\Helper\\InputAwareHelper' => __DIR__ . '/..' . '/symfony/console/Helper/InputAwareHelper.php', '_HumbugBox7ff99e199a36\\Symfony\\Component\\Console\\Helper\\ProcessHelper' => __DIR__ . '/..' . '/symfony/console/Helper/ProcessHelper.php', '_HumbugBox7ff99e199a36\\Symfony\\Component\\Console\\Helper\\ProgressBar' => __DIR__ . '/..' . '/symfony/console/Helper/ProgressBar.php', '_HumbugBox7ff99e199a36\\Symfony\\Component\\Console\\Helper\\ProgressIndicator' => __DIR__ . '/..' . '/symfony/console/Helper/ProgressIndicator.php', '_HumbugBox7ff99e199a36\\Symfony\\Component\\Console\\Helper\\QuestionHelper' => __DIR__ . '/..' . '/symfony/console/Helper/QuestionHelper.php', '_HumbugBox7ff99e199a36\\Symfony\\Component\\Console\\Helper\\SymfonyQuestionHelper' => __DIR__ . '/..' . '/symfony/console/Helper/SymfonyQuestionHelper.php', '_HumbugBox7ff99e199a36\\Symfony\\Component\\Console\\Helper\\Table' => __DIR__ . '/..' . '/symfony/console/Helper/Table.php', '_HumbugBox7ff99e199a36\\Symfony\\Component\\Console\\Helper\\TableCell' => __DIR__ . '/..' . '/symfony/console/Helper/TableCell.php', '_HumbugBox7ff99e199a36\\Symfony\\Component\\Console\\Helper\\TableCellStyle' => __DIR__ . '/..' . '/symfony/console/Helper/TableCellStyle.php', '_HumbugBox7ff99e199a36\\Symfony\\Component\\Console\\Helper\\TableRows' => __DIR__ . '/..' . '/symfony/console/Helper/TableRows.php', '_HumbugBox7ff99e199a36\\Symfony\\Component\\Console\\Helper\\TableSeparator' => __DIR__ . '/..' . '/symfony/console/Helper/TableSeparator.php', '_HumbugBox7ff99e199a36\\Symfony\\Component\\Console\\Helper\\TableStyle' => __DIR__ . '/..' . '/symfony/console/Helper/TableStyle.php', '_HumbugBox7ff99e199a36\\Symfony\\Component\\Console\\Input\\ArgvInput' => __DIR__ . '/..' . '/symfony/console/Input/ArgvInput.php', '_HumbugBox7ff99e199a36\\Symfony\\Component\\Console\\Input\\ArrayInput' => __DIR__ . '/..' . '/symfony/console/Input/ArrayInput.php', '_HumbugBox7ff99e199a36\\Symfony\\Component\\Console\\Input\\Input' => __DIR__ . '/..' . '/symfony/console/Input/Input.php', '_HumbugBox7ff99e199a36\\Symfony\\Component\\Console\\Input\\InputArgument' => __DIR__ . '/..' . '/symfony/console/Input/InputArgument.php', '_HumbugBox7ff99e199a36\\Symfony\\Component\\Console\\Input\\InputAwareInterface' => __DIR__ . '/..' . '/symfony/console/Input/InputAwareInterface.php', '_HumbugBox7ff99e199a36\\Symfony\\Component\\Console\\Input\\InputDefinition' => __DIR__ . '/..' . '/symfony/console/Input/InputDefinition.php', '_HumbugBox7ff99e199a36\\Symfony\\Component\\Console\\Input\\InputInterface' => __DIR__ . '/..' . '/symfony/console/Input/InputInterface.php', '_HumbugBox7ff99e199a36\\Symfony\\Component\\Console\\Input\\InputOption' => __DIR__ . '/..' . '/symfony/console/Input/InputOption.php', '_HumbugBox7ff99e199a36\\Symfony\\Component\\Console\\Input\\StreamableInputInterface' => __DIR__ . '/..' . '/symfony/console/Input/StreamableInputInterface.php', '_HumbugBox7ff99e199a36\\Symfony\\Component\\Console\\Input\\StringInput' => __DIR__ . '/..' . '/symfony/console/Input/StringInput.php', '_HumbugBox7ff99e199a36\\Symfony\\Component\\Console\\Logger\\ConsoleLogger' => __DIR__ . '/..' . '/symfony/console/Logger/ConsoleLogger.php', '_HumbugBox7ff99e199a36\\Symfony\\Component\\Console\\Output\\BufferedOutput' => __DIR__ . '/..' . '/symfony/console/Output/BufferedOutput.php', '_HumbugBox7ff99e199a36\\Symfony\\Component\\Console\\Output\\ConsoleOutput' => __DIR__ . '/..' . '/symfony/console/Output/ConsoleOutput.php', '_HumbugBox7ff99e199a36\\Symfony\\Component\\Console\\Output\\ConsoleOutputInterface' => __DIR__ . '/..' . '/symfony/console/Output/ConsoleOutputInterface.php', '_HumbugBox7ff99e199a36\\Symfony\\Component\\Console\\Output\\ConsoleSectionOutput' => __DIR__ . '/..' . '/symfony/console/Output/ConsoleSectionOutput.php', '_HumbugBox7ff99e199a36\\Symfony\\Component\\Console\\Output\\NullOutput' => __DIR__ . '/..' . '/symfony/console/Output/NullOutput.php', '_HumbugBox7ff99e199a36\\Symfony\\Component\\Console\\Output\\Output' => __DIR__ . '/..' . '/symfony/console/Output/Output.php', '_HumbugBox7ff99e199a36\\Symfony\\Component\\Console\\Output\\OutputInterface' => __DIR__ . '/..' . '/symfony/console/Output/OutputInterface.php', '_HumbugBox7ff99e199a36\\Symfony\\Component\\Console\\Output\\StreamOutput' => __DIR__ . '/..' . '/symfony/console/Output/StreamOutput.php', '_HumbugBox7ff99e199a36\\Symfony\\Component\\Console\\Output\\TrimmedBufferOutput' => __DIR__ . '/..' . '/symfony/console/Output/TrimmedBufferOutput.php', '_HumbugBox7ff99e199a36\\Symfony\\Component\\Console\\Question\\ChoiceQuestion' => __DIR__ . '/..' . '/symfony/console/Question/ChoiceQuestion.php', '_HumbugBox7ff99e199a36\\Symfony\\Component\\Console\\Question\\ConfirmationQuestion' => __DIR__ . '/..' . '/symfony/console/Question/ConfirmationQuestion.php', '_HumbugBox7ff99e199a36\\Symfony\\Component\\Console\\Question\\Question' => __DIR__ . '/..' . '/symfony/console/Question/Question.php', '_HumbugBox7ff99e199a36\\Symfony\\Component\\Console\\SignalRegistry\\SignalRegistry' => __DIR__ . '/..' . '/symfony/console/SignalRegistry/SignalRegistry.php', '_HumbugBox7ff99e199a36\\Symfony\\Component\\Console\\SingleCommandApplication' => __DIR__ . '/..' . '/symfony/console/SingleCommandApplication.php', '_HumbugBox7ff99e199a36\\Symfony\\Component\\Console\\Style\\OutputStyle' => __DIR__ . '/..' . '/symfony/console/Style/OutputStyle.php', '_HumbugBox7ff99e199a36\\Symfony\\Component\\Console\\Style\\StyleInterface' => __DIR__ . '/..' . '/symfony/console/Style/StyleInterface.php', '_HumbugBox7ff99e199a36\\Symfony\\Component\\Console\\Style\\SymfonyStyle' => __DIR__ . '/..' . '/symfony/console/Style/SymfonyStyle.php', '_HumbugBox7ff99e199a36\\Symfony\\Component\\Console\\Terminal' => __DIR__ . '/..' . '/symfony/console/Terminal.php', '_HumbugBox7ff99e199a36\\Symfony\\Component\\Console\\Tester\\ApplicationTester' => __DIR__ . '/..' . '/symfony/console/Tester/ApplicationTester.php', '_HumbugBox7ff99e199a36\\Symfony\\Component\\Console\\Tester\\CommandCompletionTester' => __DIR__ . '/..' . '/symfony/console/Tester/CommandCompletionTester.php', '_HumbugBox7ff99e199a36\\Symfony\\Component\\Console\\Tester\\CommandTester' => __DIR__ . '/..' . '/symfony/console/Tester/CommandTester.php', '_HumbugBox7ff99e199a36\\Symfony\\Component\\Console\\Tester\\Constraint\\CommandIsSuccessful' => __DIR__ . '/..' . '/symfony/console/Tester/Constraint/CommandIsSuccessful.php', '_HumbugBox7ff99e199a36\\Symfony\\Component\\Console\\Tester\\TesterTrait' => __DIR__ . '/..' . '/symfony/console/Tester/TesterTrait.php', '_HumbugBox7ff99e199a36\\Symfony\\Component\\Filesystem\\Exception\\ExceptionInterface' => __DIR__ . '/..' . '/symfony/filesystem/Exception/ExceptionInterface.php', '_HumbugBox7ff99e199a36\\Symfony\\Component\\Filesystem\\Exception\\FileNotFoundException' => __DIR__ . '/..' . '/symfony/filesystem/Exception/FileNotFoundException.php', '_HumbugBox7ff99e199a36\\Symfony\\Component\\Filesystem\\Exception\\IOException' => __DIR__ . '/..' . '/symfony/filesystem/Exception/IOException.php', '_HumbugBox7ff99e199a36\\Symfony\\Component\\Filesystem\\Exception\\IOExceptionInterface' => __DIR__ . '/..' . '/symfony/filesystem/Exception/IOExceptionInterface.php', '_HumbugBox7ff99e199a36\\Symfony\\Component\\Filesystem\\Exception\\InvalidArgumentException' => __DIR__ . '/..' . '/symfony/filesystem/Exception/InvalidArgumentException.php', '_HumbugBox7ff99e199a36\\Symfony\\Component\\Filesystem\\Exception\\RuntimeException' => __DIR__ . '/..' . '/symfony/filesystem/Exception/RuntimeException.php', '_HumbugBox7ff99e199a36\\Symfony\\Component\\Filesystem\\Filesystem' => __DIR__ . '/..' . '/symfony/filesystem/Filesystem.php', '_HumbugBox7ff99e199a36\\Symfony\\Component\\Filesystem\\Path' => __DIR__ . '/..' . '/symfony/filesystem/Path.php', '_HumbugBox7ff99e199a36\\Symfony\\Component\\String\\AbstractString' => __DIR__ . '/..' . '/symfony/string/AbstractString.php', '_HumbugBox7ff99e199a36\\Symfony\\Component\\String\\AbstractUnicodeString' => __DIR__ . '/..' . '/symfony/string/AbstractUnicodeString.php', '_HumbugBox7ff99e199a36\\Symfony\\Component\\String\\ByteString' => __DIR__ . '/..' . '/symfony/string/ByteString.php', '_HumbugBox7ff99e199a36\\Symfony\\Component\\String\\CodePointString' => __DIR__ . '/..' . '/symfony/string/CodePointString.php', '_HumbugBox7ff99e199a36\\Symfony\\Component\\String\\Exception\\ExceptionInterface' => __DIR__ . '/..' . '/symfony/string/Exception/ExceptionInterface.php', '_HumbugBox7ff99e199a36\\Symfony\\Component\\String\\Exception\\InvalidArgumentException' => __DIR__ . '/..' . '/symfony/string/Exception/InvalidArgumentException.php', '_HumbugBox7ff99e199a36\\Symfony\\Component\\String\\Exception\\RuntimeException' => __DIR__ . '/..' . '/symfony/string/Exception/RuntimeException.php', '_HumbugBox7ff99e199a36\\Symfony\\Component\\String\\Inflector\\EnglishInflector' => __DIR__ . '/..' . '/symfony/string/Inflector/EnglishInflector.php', '_HumbugBox7ff99e199a36\\Symfony\\Component\\String\\Inflector\\FrenchInflector' => __DIR__ . '/..' . '/symfony/string/Inflector/FrenchInflector.php', '_HumbugBox7ff99e199a36\\Symfony\\Component\\String\\Inflector\\InflectorInterface' => __DIR__ . '/..' . '/symfony/string/Inflector/InflectorInterface.php', '_HumbugBox7ff99e199a36\\Symfony\\Component\\String\\LazyString' => __DIR__ . '/..' . '/symfony/string/LazyString.php', '_HumbugBox7ff99e199a36\\Symfony\\Component\\String\\Slugger\\AsciiSlugger' => __DIR__ . '/..' . '/symfony/string/Slugger/AsciiSlugger.php', '_HumbugBox7ff99e199a36\\Symfony\\Component\\String\\Slugger\\SluggerInterface' => __DIR__ . '/..' . '/symfony/string/Slugger/SluggerInterface.php', '_HumbugBox7ff99e199a36\\Symfony\\Component\\String\\UnicodeString' => __DIR__ . '/..' . '/symfony/string/UnicodeString.php', '_HumbugBox7ff99e199a36\\Symfony\\Contracts\\Service\\Attribute\\Required' => __DIR__ . '/..' . '/symfony/service-contracts/Attribute/Required.php', '_HumbugBox7ff99e199a36\\Symfony\\Contracts\\Service\\Attribute\\SubscribedService' => __DIR__ . '/..' . '/symfony/service-contracts/Attribute/SubscribedService.php', '_HumbugBox7ff99e199a36\\Symfony\\Contracts\\Service\\ResetInterface' => __DIR__ . '/..' . '/symfony/service-contracts/ResetInterface.php', '_HumbugBox7ff99e199a36\\Symfony\\Contracts\\Service\\ServiceLocatorTrait' => __DIR__ . '/..' . '/symfony/service-contracts/ServiceLocatorTrait.php', '_HumbugBox7ff99e199a36\\Symfony\\Contracts\\Service\\ServiceProviderInterface' => __DIR__ . '/..' . '/symfony/service-contracts/ServiceProviderInterface.php', '_HumbugBox7ff99e199a36\\Symfony\\Contracts\\Service\\ServiceSubscriberInterface' => __DIR__ . '/..' . '/symfony/service-contracts/ServiceSubscriberInterface.php', '_HumbugBox7ff99e199a36\\Symfony\\Contracts\\Service\\ServiceSubscriberTrait' => __DIR__ . '/..' . '/symfony/service-contracts/ServiceSubscriberTrait.php', '_HumbugBox7ff99e199a36\\Symfony\\Polyfill\\Ctype\\Ctype' => __DIR__ . '/..' . '/symfony/polyfill-ctype/Ctype.php', '_HumbugBox7ff99e199a36\\Symfony\\Polyfill\\Intl\\Grapheme\\Grapheme' => __DIR__ . '/..' . '/symfony/polyfill-intl-grapheme/Grapheme.php', '_HumbugBox7ff99e199a36\\Symfony\\Polyfill\\Intl\\Normalizer\\Normalizer' => __DIR__ . '/..' . '/symfony/polyfill-intl-normalizer/Normalizer.php', '_HumbugBox7ff99e199a36\\Symfony\\Polyfill\\Mbstring\\Mbstring' => __DIR__ . '/..' . '/symfony/polyfill-mbstring/Mbstring.php', '_HumbugBox7ff99e199a36\\Symfony\\Polyfill\\Php73\\Php73' => __DIR__ . '/..' . '/symfony/polyfill-php73/Php73.php', '_HumbugBox7ff99e199a36\\UnhandledMatchError' => __DIR__ . '/..' . '/symfony/polyfill-php80/Resources/stubs/UnhandledMatchError.php', '_HumbugBox7ff99e199a36\\ValueError' => __DIR__ . '/..' . '/symfony/polyfill-php80/Resources/stubs/ValueError.php', '_HumbugBox7ff99e199a36\\Webmozart\\Assert\\Assert' => __DIR__ . '/..' . '/webmozart/assert/src/Assert.php', '_HumbugBox7ff99e199a36\\Webmozart\\Assert\\InvalidArgumentException' => __DIR__ . '/..' . '/webmozart/assert/src/InvalidArgumentException.php', '_HumbugBox7ff99e199a36\\Webmozart\\Assert\\Mixin' => __DIR__ . '/..' . '/webmozart/assert/src/Mixin.php', '_HumbugBox7ff99e199a36\\XdgBaseDir\\Xdg' => __DIR__ . '/..' . '/dnoegel/php-xdg-base-dir/src/Xdg.php', '_HumbugBox7ff99e199a36\\phpDocumentor\\Reflection\\DocBlock' => __DIR__ . '/..' . '/phpdocumentor/reflection-docblock/src/DocBlock.php', '_HumbugBox7ff99e199a36\\phpDocumentor\\Reflection\\DocBlockFactory' => __DIR__ . '/..' . '/phpdocumentor/reflection-docblock/src/DocBlockFactory.php', '_HumbugBox7ff99e199a36\\phpDocumentor\\Reflection\\DocBlockFactoryInterface' => __DIR__ . '/..' . '/phpdocumentor/reflection-docblock/src/DocBlockFactoryInterface.php', '_HumbugBox7ff99e199a36\\phpDocumentor\\Reflection\\DocBlock\\Description' => __DIR__ . '/..' . '/phpdocumentor/reflection-docblock/src/DocBlock/Description.php', '_HumbugBox7ff99e199a36\\phpDocumentor\\Reflection\\DocBlock\\DescriptionFactory' => __DIR__ . '/..' . '/phpdocumentor/reflection-docblock/src/DocBlock/DescriptionFactory.php', '_HumbugBox7ff99e199a36\\phpDocumentor\\Reflection\\DocBlock\\ExampleFinder' => __DIR__ . '/..' . '/phpdocumentor/reflection-docblock/src/DocBlock/ExampleFinder.php', '_HumbugBox7ff99e199a36\\phpDocumentor\\Reflection\\DocBlock\\Serializer' => __DIR__ . '/..' . '/phpdocumentor/reflection-docblock/src/DocBlock/Serializer.php', '_HumbugBox7ff99e199a36\\phpDocumentor\\Reflection\\DocBlock\\StandardTagFactory' => __DIR__ . '/..' . '/phpdocumentor/reflection-docblock/src/DocBlock/StandardTagFactory.php', '_HumbugBox7ff99e199a36\\phpDocumentor\\Reflection\\DocBlock\\Tag' => __DIR__ . '/..' . '/phpdocumentor/reflection-docblock/src/DocBlock/Tag.php', '_HumbugBox7ff99e199a36\\phpDocumentor\\Reflection\\DocBlock\\TagFactory' => __DIR__ . '/..' . '/phpdocumentor/reflection-docblock/src/DocBlock/TagFactory.php', '_HumbugBox7ff99e199a36\\phpDocumentor\\Reflection\\DocBlock\\Tags\\Author' => __DIR__ . '/..' . '/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Author.php', '_HumbugBox7ff99e199a36\\phpDocumentor\\Reflection\\DocBlock\\Tags\\BaseTag' => __DIR__ . '/..' . '/phpdocumentor/reflection-docblock/src/DocBlock/Tags/BaseTag.php', '_HumbugBox7ff99e199a36\\phpDocumentor\\Reflection\\DocBlock\\Tags\\Covers' => __DIR__ . '/..' . '/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Covers.php', '_HumbugBox7ff99e199a36\\phpDocumentor\\Reflection\\DocBlock\\Tags\\Deprecated' => __DIR__ . '/..' . '/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Deprecated.php', '_HumbugBox7ff99e199a36\\phpDocumentor\\Reflection\\DocBlock\\Tags\\Example' => __DIR__ . '/..' . '/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Example.php', '_HumbugBox7ff99e199a36\\phpDocumentor\\Reflection\\DocBlock\\Tags\\Factory\\AbstractPHPStanFactory' => __DIR__ . '/..' . '/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Factory/AbstractPHPStanFactory.php', '_HumbugBox7ff99e199a36\\phpDocumentor\\Reflection\\DocBlock\\Tags\\Factory\\Factory' => __DIR__ . '/..' . '/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Factory/Factory.php', '_HumbugBox7ff99e199a36\\phpDocumentor\\Reflection\\DocBlock\\Tags\\Factory\\MethodFactory' => __DIR__ . '/..' . '/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Factory/MethodFactory.php', '_HumbugBox7ff99e199a36\\phpDocumentor\\Reflection\\DocBlock\\Tags\\Factory\\PHPStanFactory' => __DIR__ . '/..' . '/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Factory/PHPStanFactory.php', '_HumbugBox7ff99e199a36\\phpDocumentor\\Reflection\\DocBlock\\Tags\\Factory\\ParamFactory' => __DIR__ . '/..' . '/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Factory/ParamFactory.php', '_HumbugBox7ff99e199a36\\phpDocumentor\\Reflection\\DocBlock\\Tags\\Factory\\PropertyFactory' => __DIR__ . '/..' . '/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Factory/PropertyFactory.php', '_HumbugBox7ff99e199a36\\phpDocumentor\\Reflection\\DocBlock\\Tags\\Factory\\PropertyReadFactory' => __DIR__ . '/..' . '/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Factory/PropertyReadFactory.php', '_HumbugBox7ff99e199a36\\phpDocumentor\\Reflection\\DocBlock\\Tags\\Factory\\PropertyWriteFactory' => __DIR__ . '/..' . '/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Factory/PropertyWriteFactory.php', '_HumbugBox7ff99e199a36\\phpDocumentor\\Reflection\\DocBlock\\Tags\\Factory\\ReturnFactory' => __DIR__ . '/..' . '/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Factory/ReturnFactory.php', '_HumbugBox7ff99e199a36\\phpDocumentor\\Reflection\\DocBlock\\Tags\\Factory\\StaticMethod' => __DIR__ . '/..' . '/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Factory/StaticMethod.php', '_HumbugBox7ff99e199a36\\phpDocumentor\\Reflection\\DocBlock\\Tags\\Factory\\VarFactory' => __DIR__ . '/..' . '/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Factory/VarFactory.php', '_HumbugBox7ff99e199a36\\phpDocumentor\\Reflection\\DocBlock\\Tags\\Formatter' => __DIR__ . '/..' . '/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Formatter.php', '_HumbugBox7ff99e199a36\\phpDocumentor\\Reflection\\DocBlock\\Tags\\Formatter\\AlignFormatter' => __DIR__ . '/..' . '/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Formatter/AlignFormatter.php', '_HumbugBox7ff99e199a36\\phpDocumentor\\Reflection\\DocBlock\\Tags\\Formatter\\PassthroughFormatter' => __DIR__ . '/..' . '/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Formatter/PassthroughFormatter.php', '_HumbugBox7ff99e199a36\\phpDocumentor\\Reflection\\DocBlock\\Tags\\Generic' => __DIR__ . '/..' . '/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Generic.php', '_HumbugBox7ff99e199a36\\phpDocumentor\\Reflection\\DocBlock\\Tags\\InvalidTag' => __DIR__ . '/..' . '/phpdocumentor/reflection-docblock/src/DocBlock/Tags/InvalidTag.php', '_HumbugBox7ff99e199a36\\phpDocumentor\\Reflection\\DocBlock\\Tags\\Link' => __DIR__ . '/..' . '/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Link.php', '_HumbugBox7ff99e199a36\\phpDocumentor\\Reflection\\DocBlock\\Tags\\Method' => __DIR__ . '/..' . '/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Method.php', '_HumbugBox7ff99e199a36\\phpDocumentor\\Reflection\\DocBlock\\Tags\\MethodParameter' => __DIR__ . '/..' . '/phpdocumentor/reflection-docblock/src/DocBlock/Tags/MethodParameter.php', '_HumbugBox7ff99e199a36\\phpDocumentor\\Reflection\\DocBlock\\Tags\\Param' => __DIR__ . '/..' . '/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Param.php', '_HumbugBox7ff99e199a36\\phpDocumentor\\Reflection\\DocBlock\\Tags\\Property' => __DIR__ . '/..' . '/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Property.php', '_HumbugBox7ff99e199a36\\phpDocumentor\\Reflection\\DocBlock\\Tags\\PropertyRead' => __DIR__ . '/..' . '/phpdocumentor/reflection-docblock/src/DocBlock/Tags/PropertyRead.php', '_HumbugBox7ff99e199a36\\phpDocumentor\\Reflection\\DocBlock\\Tags\\PropertyWrite' => __DIR__ . '/..' . '/phpdocumentor/reflection-docblock/src/DocBlock/Tags/PropertyWrite.php', '_HumbugBox7ff99e199a36\\phpDocumentor\\Reflection\\DocBlock\\Tags\\Reference\\Fqsen' => __DIR__ . '/..' . '/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Reference/Fqsen.php', '_HumbugBox7ff99e199a36\\phpDocumentor\\Reflection\\DocBlock\\Tags\\Reference\\Reference' => __DIR__ . '/..' . '/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Reference/Reference.php', '_HumbugBox7ff99e199a36\\phpDocumentor\\Reflection\\DocBlock\\Tags\\Reference\\Url' => __DIR__ . '/..' . '/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Reference/Url.php', '_HumbugBox7ff99e199a36\\phpDocumentor\\Reflection\\DocBlock\\Tags\\Return_' => __DIR__ . '/..' . '/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Return_.php', '_HumbugBox7ff99e199a36\\phpDocumentor\\Reflection\\DocBlock\\Tags\\See' => __DIR__ . '/..' . '/phpdocumentor/reflection-docblock/src/DocBlock/Tags/See.php', '_HumbugBox7ff99e199a36\\phpDocumentor\\Reflection\\DocBlock\\Tags\\Since' => __DIR__ . '/..' . '/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Since.php', '_HumbugBox7ff99e199a36\\phpDocumentor\\Reflection\\DocBlock\\Tags\\Source' => __DIR__ . '/..' . '/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Source.php', '_HumbugBox7ff99e199a36\\phpDocumentor\\Reflection\\DocBlock\\Tags\\TagWithType' => __DIR__ . '/..' . '/phpdocumentor/reflection-docblock/src/DocBlock/Tags/TagWithType.php', '_HumbugBox7ff99e199a36\\phpDocumentor\\Reflection\\DocBlock\\Tags\\Throws' => __DIR__ . '/..' . '/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Throws.php', '_HumbugBox7ff99e199a36\\phpDocumentor\\Reflection\\DocBlock\\Tags\\Uses' => __DIR__ . '/..' . '/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Uses.php', '_HumbugBox7ff99e199a36\\phpDocumentor\\Reflection\\DocBlock\\Tags\\Var_' => __DIR__ . '/..' . '/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Var_.php', '_HumbugBox7ff99e199a36\\phpDocumentor\\Reflection\\DocBlock\\Tags\\Version' => __DIR__ . '/..' . '/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Version.php', '_HumbugBox7ff99e199a36\\phpDocumentor\\Reflection\\Element' => __DIR__ . '/..' . '/phpdocumentor/reflection-common/src/Element.php', '_HumbugBox7ff99e199a36\\phpDocumentor\\Reflection\\Exception\\PcreException' => __DIR__ . '/..' . '/phpdocumentor/reflection-docblock/src/Exception/PcreException.php', '_HumbugBox7ff99e199a36\\phpDocumentor\\Reflection\\File' => __DIR__ . '/..' . '/phpdocumentor/reflection-common/src/File.php', '_HumbugBox7ff99e199a36\\phpDocumentor\\Reflection\\Fqsen' => __DIR__ . '/..' . '/phpdocumentor/reflection-common/src/Fqsen.php', '_HumbugBox7ff99e199a36\\phpDocumentor\\Reflection\\FqsenResolver' => __DIR__ . '/..' . '/phpdocumentor/type-resolver/src/FqsenResolver.php', '_HumbugBox7ff99e199a36\\phpDocumentor\\Reflection\\Location' => __DIR__ . '/..' . '/phpdocumentor/reflection-common/src/Location.php', '_HumbugBox7ff99e199a36\\phpDocumentor\\Reflection\\Project' => __DIR__ . '/..' . '/phpdocumentor/reflection-common/src/Project.php', '_HumbugBox7ff99e199a36\\phpDocumentor\\Reflection\\ProjectFactory' => __DIR__ . '/..' . '/phpdocumentor/reflection-common/src/ProjectFactory.php', '_HumbugBox7ff99e199a36\\phpDocumentor\\Reflection\\PseudoType' => __DIR__ . '/..' . '/phpdocumentor/type-resolver/src/PseudoType.php', '_HumbugBox7ff99e199a36\\phpDocumentor\\Reflection\\PseudoTypes\\ArrayShape' => __DIR__ . '/..' . '/phpdocumentor/type-resolver/src/PseudoTypes/ArrayShape.php', '_HumbugBox7ff99e199a36\\phpDocumentor\\Reflection\\PseudoTypes\\ArrayShapeItem' => __DIR__ . '/..' . '/phpdocumentor/type-resolver/src/PseudoTypes/ArrayShapeItem.php', '_HumbugBox7ff99e199a36\\phpDocumentor\\Reflection\\PseudoTypes\\CallableString' => __DIR__ . '/..' . '/phpdocumentor/type-resolver/src/PseudoTypes/CallableString.php', '_HumbugBox7ff99e199a36\\phpDocumentor\\Reflection\\PseudoTypes\\ConstExpression' => __DIR__ . '/..' . '/phpdocumentor/type-resolver/src/PseudoTypes/ConstExpression.php', '_HumbugBox7ff99e199a36\\phpDocumentor\\Reflection\\PseudoTypes\\False_' => __DIR__ . '/..' . '/phpdocumentor/type-resolver/src/PseudoTypes/False_.php', '_HumbugBox7ff99e199a36\\phpDocumentor\\Reflection\\PseudoTypes\\FloatValue' => __DIR__ . '/..' . '/phpdocumentor/type-resolver/src/PseudoTypes/FloatValue.php', '_HumbugBox7ff99e199a36\\phpDocumentor\\Reflection\\PseudoTypes\\HtmlEscapedString' => __DIR__ . '/..' . '/phpdocumentor/type-resolver/src/PseudoTypes/HtmlEscapedString.php', '_HumbugBox7ff99e199a36\\phpDocumentor\\Reflection\\PseudoTypes\\IntegerRange' => __DIR__ . '/..' . '/phpdocumentor/type-resolver/src/PseudoTypes/IntegerRange.php', '_HumbugBox7ff99e199a36\\phpDocumentor\\Reflection\\PseudoTypes\\IntegerValue' => __DIR__ . '/..' . '/phpdocumentor/type-resolver/src/PseudoTypes/IntegerValue.php', '_HumbugBox7ff99e199a36\\phpDocumentor\\Reflection\\PseudoTypes\\List_' => __DIR__ . '/..' . '/phpdocumentor/type-resolver/src/PseudoTypes/List_.php', '_HumbugBox7ff99e199a36\\phpDocumentor\\Reflection\\PseudoTypes\\LiteralString' => __DIR__ . '/..' . '/phpdocumentor/type-resolver/src/PseudoTypes/LiteralString.php', '_HumbugBox7ff99e199a36\\phpDocumentor\\Reflection\\PseudoTypes\\LowercaseString' => __DIR__ . '/..' . '/phpdocumentor/type-resolver/src/PseudoTypes/LowercaseString.php', '_HumbugBox7ff99e199a36\\phpDocumentor\\Reflection\\PseudoTypes\\NegativeInteger' => __DIR__ . '/..' . '/phpdocumentor/type-resolver/src/PseudoTypes/NegativeInteger.php', '_HumbugBox7ff99e199a36\\phpDocumentor\\Reflection\\PseudoTypes\\NonEmptyList' => __DIR__ . '/..' . '/phpdocumentor/type-resolver/src/PseudoTypes/NonEmptyList.php', '_HumbugBox7ff99e199a36\\phpDocumentor\\Reflection\\PseudoTypes\\NonEmptyLowercaseString' => __DIR__ . '/..' . '/phpdocumentor/type-resolver/src/PseudoTypes/NonEmptyLowercaseString.php', '_HumbugBox7ff99e199a36\\phpDocumentor\\Reflection\\PseudoTypes\\NonEmptyString' => __DIR__ . '/..' . '/phpdocumentor/type-resolver/src/PseudoTypes/NonEmptyString.php', '_HumbugBox7ff99e199a36\\phpDocumentor\\Reflection\\PseudoTypes\\NumericString' => __DIR__ . '/..' . '/phpdocumentor/type-resolver/src/PseudoTypes/NumericString.php', '_HumbugBox7ff99e199a36\\phpDocumentor\\Reflection\\PseudoTypes\\Numeric_' => __DIR__ . '/..' . '/phpdocumentor/type-resolver/src/PseudoTypes/Numeric_.php', '_HumbugBox7ff99e199a36\\phpDocumentor\\Reflection\\PseudoTypes\\PositiveInteger' => __DIR__ . '/..' . '/phpdocumentor/type-resolver/src/PseudoTypes/PositiveInteger.php', '_HumbugBox7ff99e199a36\\phpDocumentor\\Reflection\\PseudoTypes\\StringValue' => __DIR__ . '/..' . '/phpdocumentor/type-resolver/src/PseudoTypes/StringValue.php', '_HumbugBox7ff99e199a36\\phpDocumentor\\Reflection\\PseudoTypes\\TraitString' => __DIR__ . '/..' . '/phpdocumentor/type-resolver/src/PseudoTypes/TraitString.php', '_HumbugBox7ff99e199a36\\phpDocumentor\\Reflection\\PseudoTypes\\True_' => __DIR__ . '/..' . '/phpdocumentor/type-resolver/src/PseudoTypes/True_.php', '_HumbugBox7ff99e199a36\\phpDocumentor\\Reflection\\Type' => __DIR__ . '/..' . '/phpdocumentor/type-resolver/src/Type.php', '_HumbugBox7ff99e199a36\\phpDocumentor\\Reflection\\TypeResolver' => __DIR__ . '/..' . '/phpdocumentor/type-resolver/src/TypeResolver.php', '_HumbugBox7ff99e199a36\\phpDocumentor\\Reflection\\Types\\AbstractList' => __DIR__ . '/..' . '/phpdocumentor/type-resolver/src/Types/AbstractList.php', '_HumbugBox7ff99e199a36\\phpDocumentor\\Reflection\\Types\\AggregatedType' => __DIR__ . '/..' . '/phpdocumentor/type-resolver/src/Types/AggregatedType.php', '_HumbugBox7ff99e199a36\\phpDocumentor\\Reflection\\Types\\ArrayKey' => __DIR__ . '/..' . '/phpdocumentor/type-resolver/src/Types/ArrayKey.php', '_HumbugBox7ff99e199a36\\phpDocumentor\\Reflection\\Types\\Array_' => __DIR__ . '/..' . '/phpdocumentor/type-resolver/src/Types/Array_.php', '_HumbugBox7ff99e199a36\\phpDocumentor\\Reflection\\Types\\Boolean' => __DIR__ . '/..' . '/phpdocumentor/type-resolver/src/Types/Boolean.php', '_HumbugBox7ff99e199a36\\phpDocumentor\\Reflection\\Types\\CallableParameter' => __DIR__ . '/..' . '/phpdocumentor/type-resolver/src/Types/CallableParameter.php', '_HumbugBox7ff99e199a36\\phpDocumentor\\Reflection\\Types\\Callable_' => __DIR__ . '/..' . '/phpdocumentor/type-resolver/src/Types/Callable_.php', '_HumbugBox7ff99e199a36\\phpDocumentor\\Reflection\\Types\\ClassString' => __DIR__ . '/..' . '/phpdocumentor/type-resolver/src/Types/ClassString.php', '_HumbugBox7ff99e199a36\\phpDocumentor\\Reflection\\Types\\Collection' => __DIR__ . '/..' . '/phpdocumentor/type-resolver/src/Types/Collection.php', '_HumbugBox7ff99e199a36\\phpDocumentor\\Reflection\\Types\\Compound' => __DIR__ . '/..' . '/phpdocumentor/type-resolver/src/Types/Compound.php', '_HumbugBox7ff99e199a36\\phpDocumentor\\Reflection\\Types\\Context' => __DIR__ . '/..' . '/phpdocumentor/type-resolver/src/Types/Context.php', '_HumbugBox7ff99e199a36\\phpDocumentor\\Reflection\\Types\\ContextFactory' => __DIR__ . '/..' . '/phpdocumentor/type-resolver/src/Types/ContextFactory.php', '_HumbugBox7ff99e199a36\\phpDocumentor\\Reflection\\Types\\Expression' => __DIR__ . '/..' . '/phpdocumentor/type-resolver/src/Types/Expression.php', '_HumbugBox7ff99e199a36\\phpDocumentor\\Reflection\\Types\\Float_' => __DIR__ . '/..' . '/phpdocumentor/type-resolver/src/Types/Float_.php', '_HumbugBox7ff99e199a36\\phpDocumentor\\Reflection\\Types\\Integer' => __DIR__ . '/..' . '/phpdocumentor/type-resolver/src/Types/Integer.php', '_HumbugBox7ff99e199a36\\phpDocumentor\\Reflection\\Types\\InterfaceString' => __DIR__ . '/..' . '/phpdocumentor/type-resolver/src/Types/InterfaceString.php', '_HumbugBox7ff99e199a36\\phpDocumentor\\Reflection\\Types\\Intersection' => __DIR__ . '/..' . '/phpdocumentor/type-resolver/src/Types/Intersection.php', '_HumbugBox7ff99e199a36\\phpDocumentor\\Reflection\\Types\\Iterable_' => __DIR__ . '/..' . '/phpdocumentor/type-resolver/src/Types/Iterable_.php', '_HumbugBox7ff99e199a36\\phpDocumentor\\Reflection\\Types\\Mixed_' => __DIR__ . '/..' . '/phpdocumentor/type-resolver/src/Types/Mixed_.php', '_HumbugBox7ff99e199a36\\phpDocumentor\\Reflection\\Types\\Never_' => __DIR__ . '/..' . '/phpdocumentor/type-resolver/src/Types/Never_.php', '_HumbugBox7ff99e199a36\\phpDocumentor\\Reflection\\Types\\Null_' => __DIR__ . '/..' . '/phpdocumentor/type-resolver/src/Types/Null_.php', '_HumbugBox7ff99e199a36\\phpDocumentor\\Reflection\\Types\\Nullable' => __DIR__ . '/..' . '/phpdocumentor/type-resolver/src/Types/Nullable.php', '_HumbugBox7ff99e199a36\\phpDocumentor\\Reflection\\Types\\Object_' => __DIR__ . '/..' . '/phpdocumentor/type-resolver/src/Types/Object_.php', '_HumbugBox7ff99e199a36\\phpDocumentor\\Reflection\\Types\\Parent_' => __DIR__ . '/..' . '/phpdocumentor/type-resolver/src/Types/Parent_.php', '_HumbugBox7ff99e199a36\\phpDocumentor\\Reflection\\Types\\Resource_' => __DIR__ . '/..' . '/phpdocumentor/type-resolver/src/Types/Resource_.php', '_HumbugBox7ff99e199a36\\phpDocumentor\\Reflection\\Types\\Scalar' => __DIR__ . '/..' . '/phpdocumentor/type-resolver/src/Types/Scalar.php', '_HumbugBox7ff99e199a36\\phpDocumentor\\Reflection\\Types\\Self_' => __DIR__ . '/..' . '/phpdocumentor/type-resolver/src/Types/Self_.php', '_HumbugBox7ff99e199a36\\phpDocumentor\\Reflection\\Types\\Static_' => __DIR__ . '/..' . '/phpdocumentor/type-resolver/src/Types/Static_.php', '_HumbugBox7ff99e199a36\\phpDocumentor\\Reflection\\Types\\String_' => __DIR__ . '/..' . '/phpdocumentor/type-resolver/src/Types/String_.php', '_HumbugBox7ff99e199a36\\phpDocumentor\\Reflection\\Types\\This' => __DIR__ . '/..' . '/phpdocumentor/type-resolver/src/Types/This.php', '_HumbugBox7ff99e199a36\\phpDocumentor\\Reflection\\Types\\Void_' => __DIR__ . '/..' . '/phpdocumentor/type-resolver/src/Types/Void_.php', '_HumbugBox7ff99e199a36\\phpDocumentor\\Reflection\\Utils' => __DIR__ . '/..' . '/phpdocumentor/reflection-docblock/src/Utils.php', ); public static function getInitializer(ClassLoader $loader) { return \Closure::bind(function () use ($loader) { $loader->prefixLengthsPsr4 = ComposerStaticInitdffbc805a242803aefef6b513be4e6ec::$prefixLengthsPsr4; $loader->prefixDirsPsr4 = ComposerStaticInitdffbc805a242803aefef6b513be4e6ec::$prefixDirsPsr4; $loader->classMap = ComposerStaticInitdffbc805a242803aefef6b513be4e6ec::$classMap; }, null, ClassLoader::class); } } Copyright (C) 2015 Composer Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * * For the full copyright and license information, please view * the LICENSE file that was distributed with this source code. */ namespace _HumbugBox7ff99e199a36\Composer\Semver; use _HumbugBox7ff99e199a36\Composer\Semver\Constraint\ConstraintInterface; use _HumbugBox7ff99e199a36\Composer\Semver\Constraint\MatchAllConstraint; use _HumbugBox7ff99e199a36\Composer\Semver\Constraint\MultiConstraint; use _HumbugBox7ff99e199a36\Composer\Semver\Constraint\Constraint; /** * Version parser. * * @author Jordi Boggiano */ class VersionParser { /** * Regex to match pre-release data (sort of). * * Due to backwards compatibility: * - Instead of enforcing hyphen, an underscore, dot or nothing at all are also accepted. * - Only stabilities as recognized by Composer are allowed to precede a numerical identifier. * - Numerical-only pre-release identifiers are not supported, see tests. * * |--------------| * [major].[minor].[patch] -[pre-release] +[build-metadata] * * @var string */ private static $modifierRegex = '[._-]?(?:(stable|beta|b|RC|alpha|a|patch|pl|p)((?:[.-]?\\d+)*+)?)?([.-]?dev)?'; /** @var string */ private static $stabilitiesRegex = 'stable|RC|beta|alpha|dev'; /** * Returns the stability of a version. * * @param string $version * * @return string * @phpstan-return 'stable'|'RC'|'beta'|'alpha'|'dev' */ public static function parseStability($version) { $version = (string) \preg_replace('{#.+$}', '', (string) $version); if (\strpos($version, 'dev-') === 0 || '-dev' === \substr($version, -4)) { return 'dev'; } \preg_match('{' . self::$modifierRegex . '(?:\\+.*)?$}i', \strtolower($version), $match); if (!empty($match[3])) { return 'dev'; } if (!empty($match[1])) { if ('beta' === $match[1] || 'b' === $match[1]) { return 'beta'; } if ('alpha' === $match[1] || 'a' === $match[1]) { return 'alpha'; } if ('rc' === $match[1]) { return 'RC'; } } return 'stable'; } /** * @param string $stability * * @return string * @phpstan-return 'stable'|'RC'|'beta'|'alpha'|'dev' */ public static function normalizeStability($stability) { $stability = \strtolower((string) $stability); if (!\in_array($stability, array('stable', 'rc', 'beta', 'alpha', 'dev'), \true)) { throw new \InvalidArgumentException('Invalid stability string "' . $stability . '", expected one of stable, RC, beta, alpha or dev'); } return $stability === 'rc' ? 'RC' : $stability; } /** * Normalizes a version string to be able to perform comparisons on it. * * @param string $version * @param ?string $fullVersion optional complete version string to give more context * * @throws \UnexpectedValueException * * @return string */ public function normalize($version, $fullVersion = null) { $version = \trim((string) $version); $origVersion = $version; if (null === $fullVersion) { $fullVersion = $version; } // strip off aliasing if (\preg_match('{^([^,\\s]++) ++as ++([^,\\s]++)$}', $version, $match)) { $version = $match[1]; } // strip off stability flag if (\preg_match('{@(?:' . self::$stabilitiesRegex . ')$}i', $version, $match)) { $version = \substr($version, 0, \strlen($version) - \strlen($match[0])); } // normalize master/trunk/default branches to dev-name for BC with 1.x as these used to be valid constraints if (\in_array($version, array('master', 'trunk', 'default'), \true)) { $version = 'dev-' . $version; } // if requirement is branch-like, use full name if (\stripos($version, 'dev-') === 0) { return 'dev-' . \substr($version, 4); } // strip off build metadata if (\preg_match('{^([^,\\s+]++)\\+[^\\s]++$}', $version, $match)) { $version = $match[1]; } // match classical versioning if (\preg_match('{^v?(\\d{1,5}+)(\\.\\d++)?(\\.\\d++)?(\\.\\d++)?' . self::$modifierRegex . '$}i', $version, $matches)) { $version = $matches[1] . (!empty($matches[2]) ? $matches[2] : '.0') . (!empty($matches[3]) ? $matches[3] : '.0') . (!empty($matches[4]) ? $matches[4] : '.0'); $index = 5; // match date(time) based versioning } elseif (\preg_match('{^v?(\\d{4}(?:[.:-]?\\d{2}){1,6}(?:[.:-]?\\d{1,3}){0,2})' . self::$modifierRegex . '$}i', $version, $matches)) { $version = (string) \preg_replace('{\\D}', '.', $matches[1]); $index = 2; } // add version modifiers if a version was matched if (isset($index)) { if (!empty($matches[$index])) { if ('stable' === $matches[$index]) { return $version; } $version .= '-' . $this->expandStability($matches[$index]) . (isset($matches[$index + 1]) && '' !== $matches[$index + 1] ? \ltrim($matches[$index + 1], '.-') : ''); } if (!empty($matches[$index + 2])) { $version .= '-dev'; } return $version; } // match dev branches if (\preg_match('{(.*?)[.-]?dev$}i', $version, $match)) { try { $normalized = $this->normalizeBranch($match[1]); // a branch ending with -dev is only valid if it is numeric // if it gets prefixed with dev- it means the branch name should // have had a dev- prefix already when passed to normalize if (\strpos($normalized, 'dev-') === \false) { return $normalized; } } catch (\Exception $e) { } } $extraMessage = ''; if (\preg_match('{ +as +' . \preg_quote($version) . '(?:@(?:' . self::$stabilitiesRegex . '))?$}', $fullVersion)) { $extraMessage = ' in "' . $fullVersion . '", the alias must be an exact version'; } elseif (\preg_match('{^' . \preg_quote($version) . '(?:@(?:' . self::$stabilitiesRegex . '))? +as +}', $fullVersion)) { $extraMessage = ' in "' . $fullVersion . '", the alias source must be an exact version, if it is a branch name you should prefix it with dev-'; } throw new \UnexpectedValueException('Invalid version string "' . $origVersion . '"' . $extraMessage); } /** * Extract numeric prefix from alias, if it is in numeric format, suitable for version comparison. * * @param string $branch Branch name (e.g. 2.1.x-dev) * * @return string|false Numeric prefix if present (e.g. 2.1.) or false */ public function parseNumericAliasPrefix($branch) { if (\preg_match('{^(?P(\\d++\\.)*\\d++)(?:\\.x)?-dev$}i', (string) $branch, $matches)) { return $matches['version'] . '.'; } return \false; } /** * Normalizes a branch name to be able to perform comparisons on it. * * @param string $name * * @return string */ public function normalizeBranch($name) { $name = \trim((string) $name); if (\preg_match('{^v?(\\d++)(\\.(?:\\d++|[xX*]))?(\\.(?:\\d++|[xX*]))?(\\.(?:\\d++|[xX*]))?$}i', $name, $matches)) { $version = ''; for ($i = 1; $i < 5; ++$i) { $version .= isset($matches[$i]) ? \str_replace(array('*', 'X'), 'x', $matches[$i]) : '.x'; } return \str_replace('x', '9999999', $version) . '-dev'; } return 'dev-' . $name; } /** * Normalizes a default branch name (i.e. master on git) to 9999999-dev. * * @param string $name * * @return string * * @deprecated No need to use this anymore in theory, Composer 2 does not normalize any branch names to 9999999-dev anymore */ public function normalizeDefaultBranch($name) { if ($name === 'dev-master' || $name === 'dev-default' || $name === 'dev-trunk') { return '9999999-dev'; } return (string) $name; } /** * Parses a constraint string into MultiConstraint and/or Constraint objects. * * @param string $constraints * * @return ConstraintInterface */ public function parseConstraints($constraints) { $prettyConstraint = (string) $constraints; $orConstraints = \preg_split('{\\s*\\|\\|?\\s*}', \trim((string) $constraints)); if (\false === $orConstraints) { throw new \RuntimeException('Failed to preg_split string: ' . $constraints); } $orGroups = array(); foreach ($orConstraints as $orConstraint) { $andConstraints = \preg_split('{(?< ,]) *(? 1) { $constraintObjects = array(); foreach ($andConstraints as $andConstraint) { foreach ($this->parseConstraint($andConstraint) as $parsedAndConstraint) { $constraintObjects[] = $parsedAndConstraint; } } } else { $constraintObjects = $this->parseConstraint($andConstraints[0]); } if (1 === \count($constraintObjects)) { $constraint = $constraintObjects[0]; } else { $constraint = new MultiConstraint($constraintObjects); } $orGroups[] = $constraint; } $parsedConstraint = MultiConstraint::create($orGroups, \false); $parsedConstraint->setPrettyString($prettyConstraint); return $parsedConstraint; } /** * @param string $constraint * * @throws \UnexpectedValueException * * @return array * * @phpstan-return non-empty-array */ private function parseConstraint($constraint) { // strip off aliasing if (\preg_match('{^([^,\\s]++) ++as ++([^,\\s]++)$}', $constraint, $match)) { $constraint = $match[1]; } // strip @stability flags, and keep it for later use if (\preg_match('{^([^,\\s]*?)@(' . self::$stabilitiesRegex . ')$}i', $constraint, $match)) { $constraint = '' !== $match[1] ? $match[1] : '*'; if ($match[2] !== 'stable') { $stabilityModifier = $match[2]; } } // get rid of #refs as those are used by composer only if (\preg_match('{^(dev-[^,\\s@]+?|[^,\\s@]+?\\.x-dev)#.+$}i', $constraint, $match)) { $constraint = $match[1]; } if (\preg_match('{^(v)?[xX*](\\.[xX*])*$}i', $constraint, $match)) { if (!empty($match[1]) || !empty($match[2])) { return array(new Constraint('>=', '0.0.0.0-dev')); } return array(new MatchAllConstraint()); } $versionRegex = 'v?(\\d++)(?:\\.(\\d++))?(?:\\.(\\d++))?(?:\\.(\\d++))?(?:' . self::$modifierRegex . '|\\.([xX*][.-]?dev))(?:\\+[^\\s]+)?'; // Tilde Range // // Like wildcard constraints, unsuffixed tilde constraints say that they must be greater than the previous // version, to ensure that unstable instances of the current version are allowed. However, if a stability // suffix is added to the constraint, then a >= match on the current version is used instead. if (\preg_match('{^~>?' . $versionRegex . '$}i', $constraint, $matches)) { if (\strpos($constraint, '~>') === 0) { throw new \UnexpectedValueException('Could not parse version constraint ' . $constraint . ': ' . 'Invalid operator "~>", you probably meant to use the "~" operator'); } // Work out which position in the version we are operating at if (isset($matches[4]) && '' !== $matches[4] && null !== $matches[4]) { $position = 4; } elseif (isset($matches[3]) && '' !== $matches[3] && null !== $matches[3]) { $position = 3; } elseif (isset($matches[2]) && '' !== $matches[2] && null !== $matches[2]) { $position = 2; } else { $position = 1; } // when matching 2.x-dev or 3.0.x-dev we have to shift the second or third number, despite no second/third number matching above if (!empty($matches[8])) { $position++; } // Calculate the stability suffix $stabilitySuffix = ''; if (empty($matches[5]) && empty($matches[7]) && empty($matches[8])) { $stabilitySuffix .= '-dev'; } $lowVersion = $this->normalize(\substr($constraint . $stabilitySuffix, 1)); $lowerBound = new Constraint('>=', $lowVersion); // For upper bound, we increment the position of one more significance, // but highPosition = 0 would be illegal $highPosition = \max(1, $position - 1); $highVersion = $this->manipulateVersionString($matches, $highPosition, 1) . '-dev'; $upperBound = new Constraint('<', $highVersion); return array($lowerBound, $upperBound); } // Caret Range // // Allows changes that do not modify the left-most non-zero digit in the [major, minor, patch] tuple. // In other words, this allows patch and minor updates for versions 1.0.0 and above, patch updates for // versions 0.X >=0.1.0, and no updates for versions 0.0.X if (\preg_match('{^\\^' . $versionRegex . '($)}i', $constraint, $matches)) { // Work out which position in the version we are operating at if ('0' !== $matches[1] || '' === $matches[2] || null === $matches[2]) { $position = 1; } elseif ('0' !== $matches[2] || '' === $matches[3] || null === $matches[3]) { $position = 2; } else { $position = 3; } // Calculate the stability suffix $stabilitySuffix = ''; if (empty($matches[5]) && empty($matches[7]) && empty($matches[8])) { $stabilitySuffix .= '-dev'; } $lowVersion = $this->normalize(\substr($constraint . $stabilitySuffix, 1)); $lowerBound = new Constraint('>=', $lowVersion); // For upper bound, we increment the position of one more significance, // but highPosition = 0 would be illegal $highVersion = $this->manipulateVersionString($matches, $position, 1) . '-dev'; $upperBound = new Constraint('<', $highVersion); return array($lowerBound, $upperBound); } // X Range // // Any of X, x, or * may be used to "stand in" for one of the numeric values in the [major, minor, patch] tuple. // A partial version range is treated as an X-Range, so the special character is in fact optional. if (\preg_match('{^v?(\\d++)(?:\\.(\\d++))?(?:\\.(\\d++))?(?:\\.[xX*])++$}', $constraint, $matches)) { if (isset($matches[3]) && '' !== $matches[3] && null !== $matches[3]) { $position = 3; } elseif (isset($matches[2]) && '' !== $matches[2] && null !== $matches[2]) { $position = 2; } else { $position = 1; } $lowVersion = $this->manipulateVersionString($matches, $position) . '-dev'; $highVersion = $this->manipulateVersionString($matches, $position, 1) . '-dev'; if ($lowVersion === '0.0.0.0-dev') { return array(new Constraint('<', $highVersion)); } return array(new Constraint('>=', $lowVersion), new Constraint('<', $highVersion)); } // Hyphen Range // // Specifies an inclusive set. If a partial version is provided as the first version in the inclusive range, // then the missing pieces are replaced with zeroes. If a partial version is provided as the second version in // the inclusive range, then all versions that start with the supplied parts of the tuple are accepted, but // nothing that would be greater than the provided tuple parts. if (\preg_match('{^(?P' . $versionRegex . ') +- +(?P' . $versionRegex . ')($)}i', $constraint, $matches)) { // Calculate the stability suffix $lowStabilitySuffix = ''; if (empty($matches[6]) && empty($matches[8]) && empty($matches[9])) { $lowStabilitySuffix = '-dev'; } $lowVersion = $this->normalize($matches['from']); $lowerBound = new Constraint('>=', $lowVersion . $lowStabilitySuffix); $empty = function ($x) { return $x === 0 || $x === '0' ? \false : empty($x); }; if (!$empty($matches[12]) && !$empty($matches[13]) || !empty($matches[15]) || !empty($matches[17]) || !empty($matches[18])) { $highVersion = $this->normalize($matches['to']); $upperBound = new Constraint('<=', $highVersion); } else { $highMatch = array('', $matches[11], $matches[12], $matches[13], $matches[14]); // validate to version $this->normalize($matches['to']); $highVersion = $this->manipulateVersionString($highMatch, $empty($matches[12]) ? 1 : 2, 1) . '-dev'; $upperBound = new Constraint('<', $highVersion); } return array($lowerBound, $upperBound); } // Basic Comparators if (\preg_match('{^(<>|!=|>=?|<=?|==?)?\\s*(.*)}', $constraint, $matches)) { try { try { $version = $this->normalize($matches[2]); } catch (\UnexpectedValueException $e) { // recover from an invalid constraint like foobar-dev which should be dev-foobar // except if the constraint uses a known operator, in which case it must be a parse error if (\substr($matches[2], -4) === '-dev' && \preg_match('{^[0-9a-zA-Z-./]+$}', $matches[2])) { $version = $this->normalize('dev-' . \substr($matches[2], 0, -4)); } else { throw $e; } } $op = $matches[1] ?: '='; if ($op !== '==' && $op !== '=' && !empty($stabilityModifier) && self::parseStability($version) === 'stable') { $version .= '-' . $stabilityModifier; } elseif ('<' === $op || '>=' === $op) { if (!\preg_match('/-' . self::$modifierRegex . '$/', \strtolower($matches[2]))) { if (\strpos($matches[2], 'dev-') !== 0) { $version .= '-dev'; } } } return array(new Constraint($matches[1] ?: '=', $version)); } catch (\Exception $e) { } } $message = 'Could not parse version constraint ' . $constraint; if (isset($e)) { $message .= ': ' . $e->getMessage(); } throw new \UnexpectedValueException($message); } /** * Increment, decrement, or simply pad a version number. * * Support function for {@link parseConstraint()} * * @param array $matches Array with version parts in array indexes 1,2,3,4 * @param int $position 1,2,3,4 - which segment of the version to increment/decrement * @param int $increment * @param string $pad The string to pad version parts after $position * * @return string|null The new version * * @phpstan-param string[] $matches */ private function manipulateVersionString(array $matches, $position, $increment = 0, $pad = '0') { for ($i = 4; $i > 0; --$i) { if ($i > $position) { $matches[$i] = $pad; } elseif ($i === $position && $increment) { $matches[$i] += $increment; // If $matches[$i] was 0, carry the decrement if ($matches[$i] < 0) { $matches[$i] = $pad; --$position; // Return null on a carry overflow if ($i === 1) { return null; } } } } return $matches[1] . '.' . $matches[2] . '.' . $matches[3] . '.' . $matches[4]; } /** * Expand shorthand stability string to long version. * * @param string $stability * * @return string */ private function expandStability($stability) { $stability = \strtolower($stability); switch ($stability) { case 'a': return 'alpha'; case 'b': return 'beta'; case 'p': case 'pl': return 'patch'; case 'rc': return 'RC'; default: return $stability; } } } * * For the full copyright and license information, please view * the LICENSE file that was distributed with this source code. */ namespace _HumbugBox7ff99e199a36\Composer\Semver; use _HumbugBox7ff99e199a36\Composer\Semver\Constraint\Constraint; class Comparator { /** * Evaluates the expression: $version1 > $version2. * * @param string $version1 * @param string $version2 * * @return bool */ public static function greaterThan($version1, $version2) { return self::compare($version1, '>', $version2); } /** * Evaluates the expression: $version1 >= $version2. * * @param string $version1 * @param string $version2 * * @return bool */ public static function greaterThanOrEqualTo($version1, $version2) { return self::compare($version1, '>=', $version2); } /** * Evaluates the expression: $version1 < $version2. * * @param string $version1 * @param string $version2 * * @return bool */ public static function lessThan($version1, $version2) { return self::compare($version1, '<', $version2); } /** * Evaluates the expression: $version1 <= $version2. * * @param string $version1 * @param string $version2 * * @return bool */ public static function lessThanOrEqualTo($version1, $version2) { return self::compare($version1, '<=', $version2); } /** * Evaluates the expression: $version1 == $version2. * * @param string $version1 * @param string $version2 * * @return bool */ public static function equalTo($version1, $version2) { return self::compare($version1, '==', $version2); } /** * Evaluates the expression: $version1 != $version2. * * @param string $version1 * @param string $version2 * * @return bool */ public static function notEqualTo($version1, $version2) { return self::compare($version1, '!=', $version2); } /** * Evaluates the expression: $version1 $operator $version2. * * @param string $version1 * @param string $operator * @param string $version2 * * @return bool * * @phpstan-param Constraint::STR_OP_* $operator */ public static function compare($version1, $operator, $version2) { $constraint = new Constraint($operator, $version2); return $constraint->matchSpecific(new Constraint('==', $version1), \true); } } * * For the full copyright and license information, please view * the LICENSE file that was distributed with this source code. */ namespace _HumbugBox7ff99e199a36\Composer\Semver; use _HumbugBox7ff99e199a36\Composer\Semver\Constraint\Constraint; use _HumbugBox7ff99e199a36\Composer\Semver\Constraint\ConstraintInterface; use _HumbugBox7ff99e199a36\Composer\Semver\Constraint\MatchAllConstraint; use _HumbugBox7ff99e199a36\Composer\Semver\Constraint\MatchNoneConstraint; use _HumbugBox7ff99e199a36\Composer\Semver\Constraint\MultiConstraint; /** * Helper class generating intervals from constraints * * This contains utilities for: * * - compacting an existing constraint which can be used to combine several into one * by creating a MultiConstraint out of the many constraints you have. * * - checking whether one subset is a subset of another. * * Note: You should call clear to free memoization memory usage when you are done using this class */ class Intervals { /** * @phpstan-var array */ private static $intervalsCache = array(); /** * @phpstan-var array */ private static $opSortOrder = array('>=' => -3, '<' => -2, '>' => 2, '<=' => 3); /** * Clears the memoization cache once you are done * * @return void */ public static function clear() { self::$intervalsCache = array(); } /** * Checks whether $candidate is a subset of $constraint * * @return bool */ public static function isSubsetOf(ConstraintInterface $candidate, ConstraintInterface $constraint) { if ($constraint instanceof MatchAllConstraint) { return \true; } if ($candidate instanceof MatchNoneConstraint || $constraint instanceof MatchNoneConstraint) { return \false; } $intersectionIntervals = self::get(new MultiConstraint(array($candidate, $constraint), \true)); $candidateIntervals = self::get($candidate); if (\count($intersectionIntervals['numeric']) !== \count($candidateIntervals['numeric'])) { return \false; } foreach ($intersectionIntervals['numeric'] as $index => $interval) { if (!isset($candidateIntervals['numeric'][$index])) { return \false; } if ((string) $candidateIntervals['numeric'][$index]->getStart() !== (string) $interval->getStart()) { return \false; } if ((string) $candidateIntervals['numeric'][$index]->getEnd() !== (string) $interval->getEnd()) { return \false; } } if ($intersectionIntervals['branches']['exclude'] !== $candidateIntervals['branches']['exclude']) { return \false; } if (\count($intersectionIntervals['branches']['names']) !== \count($candidateIntervals['branches']['names'])) { return \false; } foreach ($intersectionIntervals['branches']['names'] as $index => $name) { if ($name !== $candidateIntervals['branches']['names'][$index]) { return \false; } } return \true; } /** * Checks whether $a and $b have any intersection, equivalent to $a->matches($b) * * @return bool */ public static function haveIntersections(ConstraintInterface $a, ConstraintInterface $b) { if ($a instanceof MatchAllConstraint || $b instanceof MatchAllConstraint) { return \true; } if ($a instanceof MatchNoneConstraint || $b instanceof MatchNoneConstraint) { return \false; } $intersectionIntervals = self::generateIntervals(new MultiConstraint(array($a, $b), \true), \true); return \count($intersectionIntervals['numeric']) > 0 || $intersectionIntervals['branches']['exclude'] || \count($intersectionIntervals['branches']['names']) > 0; } /** * Attempts to optimize a MultiConstraint * * When merging MultiConstraints together they can get very large, this will * compact it by looking at the real intervals covered by all the constraints * and then creates a new constraint containing only the smallest amount of rules * to match the same intervals. * * @return ConstraintInterface */ public static function compactConstraint(ConstraintInterface $constraint) { if (!$constraint instanceof MultiConstraint) { return $constraint; } $intervals = self::generateIntervals($constraint); $constraints = array(); $hasNumericMatchAll = \false; if (\count($intervals['numeric']) === 1 && (string) $intervals['numeric'][0]->getStart() === (string) Interval::fromZero() && (string) $intervals['numeric'][0]->getEnd() === (string) Interval::untilPositiveInfinity()) { $constraints[] = $intervals['numeric'][0]->getStart(); $hasNumericMatchAll = \true; } else { $unEqualConstraints = array(); for ($i = 0, $count = \count($intervals['numeric']); $i < $count; $i++) { $interval = $intervals['numeric'][$i]; // if current interval ends with < N and next interval begins with > N we can swap this out for != N // but this needs to happen as a conjunctive expression together with the start of the current interval // and end of next interval, so [>=M, N, [>=M, !=N, getEnd()->getOperator() === '<' && $i + 1 < $count) { $nextInterval = $intervals['numeric'][$i + 1]; if ($interval->getEnd()->getVersion() === $nextInterval->getStart()->getVersion() && $nextInterval->getStart()->getOperator() === '>') { // only add a start if we didn't already do so, can be skipped if we're looking at second // interval in [>=M, N, P, =M, !=N] already and we only want to add !=P right now if (\count($unEqualConstraints) === 0 && (string) $interval->getStart() !== (string) Interval::fromZero()) { $unEqualConstraints[] = $interval->getStart(); } $unEqualConstraints[] = new Constraint('!=', $interval->getEnd()->getVersion()); continue; } } if (\count($unEqualConstraints) > 0) { // this is where the end of the following interval of a != constraint is added as explained above if ((string) $interval->getEnd() !== (string) Interval::untilPositiveInfinity()) { $unEqualConstraints[] = $interval->getEnd(); } // count is 1 if entire constraint is just one != expression if (\count($unEqualConstraints) > 1) { $constraints[] = new MultiConstraint($unEqualConstraints, \true); } else { $constraints[] = $unEqualConstraints[0]; } $unEqualConstraints = array(); continue; } // convert back >= x - <= x intervals to == x if ($interval->getStart()->getVersion() === $interval->getEnd()->getVersion() && $interval->getStart()->getOperator() === '>=' && $interval->getEnd()->getOperator() === '<=') { $constraints[] = new Constraint('==', $interval->getStart()->getVersion()); continue; } if ((string) $interval->getStart() === (string) Interval::fromZero()) { $constraints[] = $interval->getEnd(); } elseif ((string) $interval->getEnd() === (string) Interval::untilPositiveInfinity()) { $constraints[] = $interval->getStart(); } else { $constraints[] = new MultiConstraint(array($interval->getStart(), $interval->getEnd()), \true); } } } $devConstraints = array(); if (0 === \count($intervals['branches']['names'])) { if ($intervals['branches']['exclude']) { if ($hasNumericMatchAll) { return new MatchAllConstraint(); } // otherwise constraint should contain a != operator and already cover this } } else { foreach ($intervals['branches']['names'] as $branchName) { if ($intervals['branches']['exclude']) { $devConstraints[] = new Constraint('!=', $branchName); } else { $devConstraints[] = new Constraint('==', $branchName); } } // excluded branches, e.g. != dev-foo are conjunctive with the interval, so // > 2.0 != dev-foo must return a conjunctive constraint if ($intervals['branches']['exclude']) { if (\count($constraints) > 1) { return new MultiConstraint(\array_merge(array(new MultiConstraint($constraints, \false)), $devConstraints), \true); } if (\count($constraints) === 1 && (string) $constraints[0] === (string) Interval::fromZero()) { if (\count($devConstraints) > 1) { return new MultiConstraint($devConstraints, \true); } return $devConstraints[0]; } return new MultiConstraint(\array_merge($constraints, $devConstraints), \true); } // otherwise devConstraints contains a list of == operators for branches which are disjunctive with the // rest of the constraint $constraints = \array_merge($constraints, $devConstraints); } if (\count($constraints) > 1) { return new MultiConstraint($constraints, \false); } if (\count($constraints) === 1) { return $constraints[0]; } return new MatchNoneConstraint(); } /** * Creates an array of numeric intervals and branch constraints representing a given constraint * * if the returned numeric array is empty it means the constraint matches nothing in the numeric range (0 - +inf) * if the returned branches array is empty it means no dev-* versions are matched * if a constraint matches all possible dev-* versions, branches will contain Interval::anyDev() * * @return array * @phpstan-return array{'numeric': Interval[], 'branches': array{'names': string[], 'exclude': bool}} */ public static function get(ConstraintInterface $constraint) { $key = (string) $constraint; if (!isset(self::$intervalsCache[$key])) { self::$intervalsCache[$key] = self::generateIntervals($constraint); } return self::$intervalsCache[$key]; } /** * @param bool $stopOnFirstValidInterval * * @phpstan-return array{'numeric': Interval[], 'branches': array{'names': string[], 'exclude': bool}} */ private static function generateIntervals(ConstraintInterface $constraint, $stopOnFirstValidInterval = \false) { if ($constraint instanceof MatchAllConstraint) { return array('numeric' => array(new Interval(Interval::fromZero(), Interval::untilPositiveInfinity())), 'branches' => Interval::anyDev()); } if ($constraint instanceof MatchNoneConstraint) { return array('numeric' => array(), 'branches' => array('names' => array(), 'exclude' => \false)); } if ($constraint instanceof Constraint) { return self::generateSingleConstraintIntervals($constraint); } if (!$constraint instanceof MultiConstraint) { throw new \UnexpectedValueException('The constraint passed in should be an MatchAllConstraint, Constraint or MultiConstraint instance, got ' . \get_class($constraint) . '.'); } $constraints = $constraint->getConstraints(); $numericGroups = array(); $constraintBranches = array(); foreach ($constraints as $c) { $res = self::get($c); $numericGroups[] = $res['numeric']; $constraintBranches[] = $res['branches']; } if ($constraint->isDisjunctive()) { $branches = Interval::noDev(); foreach ($constraintBranches as $b) { if ($b['exclude']) { if ($branches['exclude']) { // disjunctive constraint, so only exclude what's excluded in all constraints // !=a,!=b || !=b,!=c => !=b $branches['names'] = \array_intersect($branches['names'], $b['names']); } else { // disjunctive constraint so exclude all names which are not explicitly included in the alternative // (==b || ==c) || !=a,!=b => !=a $branches['exclude'] = \true; $branches['names'] = \array_diff($b['names'], $branches['names']); } } else { if ($branches['exclude']) { // disjunctive constraint so exclude all names which are not explicitly included in the alternative // !=a,!=b || (==b || ==c) => !=a $branches['names'] = \array_diff($branches['names'], $b['names']); } else { // disjunctive constraint, so just add all the other branches // (==a || ==b) || ==c => ==a || ==b || ==c $branches['names'] = \array_merge($branches['names'], $b['names']); } } } } else { $branches = Interval::anyDev(); foreach ($constraintBranches as $b) { if ($b['exclude']) { if ($branches['exclude']) { // conjunctive, so just add all branch names to be excluded // !=a && !=b => !=a,!=b $branches['names'] = \array_merge($branches['names'], $b['names']); } else { // conjunctive, so only keep included names which are not excluded // (==a||==c) && !=a,!=b => ==c $branches['names'] = \array_diff($branches['names'], $b['names']); } } else { if ($branches['exclude']) { // conjunctive, so only keep included names which are not excluded // !=a,!=b && (==a||==c) => ==c $branches['names'] = \array_diff($b['names'], $branches['names']); $branches['exclude'] = \false; } else { // conjunctive, so only keep names that are included in both // (==a||==b) && (==a||==c) => ==a $branches['names'] = \array_intersect($branches['names'], $b['names']); } } } } $branches['names'] = \array_unique($branches['names']); if (\count($numericGroups) === 1) { return array('numeric' => $numericGroups[0], 'branches' => $branches); } $borders = array(); foreach ($numericGroups as $group) { foreach ($group as $interval) { $borders[] = array('version' => $interval->getStart()->getVersion(), 'operator' => $interval->getStart()->getOperator(), 'side' => 'start'); $borders[] = array('version' => $interval->getEnd()->getVersion(), 'operator' => $interval->getEnd()->getOperator(), 'side' => 'end'); } } $opSortOrder = self::$opSortOrder; \usort($borders, function ($a, $b) use($opSortOrder) { $order = \version_compare($a['version'], $b['version']); if ($order === 0) { return $opSortOrder[$a['operator']] - $opSortOrder[$b['operator']]; } return $order; }); $activeIntervals = 0; $intervals = array(); $index = 0; $activationThreshold = $constraint->isConjunctive() ? \count($numericGroups) : 1; $start = null; foreach ($borders as $border) { if ($border['side'] === 'start') { $activeIntervals++; } else { $activeIntervals--; } if (!$start && $activeIntervals >= $activationThreshold) { $start = new Constraint($border['operator'], $border['version']); } elseif ($start && $activeIntervals < $activationThreshold) { // filter out invalid intervals like > x - <= x, or >= x - < x if (\version_compare($start->getVersion(), $border['version'], '=') && ($start->getOperator() === '>' && $border['operator'] === '<=' || $start->getOperator() === '>=' && $border['operator'] === '<')) { unset($intervals[$index]); } else { $intervals[$index] = new Interval($start, new Constraint($border['operator'], $border['version'])); $index++; if ($stopOnFirstValidInterval) { break; } } $start = null; } } return array('numeric' => $intervals, 'branches' => $branches); } /** * @phpstan-return array{'numeric': Interval[], 'branches': array{'names': string[], 'exclude': bool}} */ private static function generateSingleConstraintIntervals(Constraint $constraint) { $op = $constraint->getOperator(); // handle branch constraints first if (\strpos($constraint->getVersion(), 'dev-') === 0) { $intervals = array(); $branches = array('names' => array(), 'exclude' => \false); // != dev-foo means any numeric version may match, we treat >/< like != they are not really defined for branches if ($op === '!=') { $intervals[] = new Interval(Interval::fromZero(), Interval::untilPositiveInfinity()); $branches = array('names' => array($constraint->getVersion()), 'exclude' => \true); } elseif ($op === '==') { $branches['names'][] = $constraint->getVersion(); } return array('numeric' => $intervals, 'branches' => $branches); } if ($op[0] === '>') { // > & >= return array('numeric' => array(new Interval($constraint, Interval::untilPositiveInfinity())), 'branches' => Interval::noDev()); } if ($op[0] === '<') { // < & <= return array('numeric' => array(new Interval(Interval::fromZero(), $constraint)), 'branches' => Interval::noDev()); } if ($op === '!=') { // convert !=x to intervals of 0 - x - +inf + dev* return array('numeric' => array(new Interval(Interval::fromZero(), new Constraint('<', $constraint->getVersion())), new Interval(new Constraint('>', $constraint->getVersion()), Interval::untilPositiveInfinity())), 'branches' => Interval::anyDev()); } // convert ==x to an interval of >=x - <=x return array('numeric' => array(new Interval(new Constraint('>=', $constraint->getVersion()), new Constraint('<=', $constraint->getVersion()))), 'branches' => Interval::noDev()); } } * * For the full copyright and license information, please view * the LICENSE file that was distributed with this source code. */ namespace _HumbugBox7ff99e199a36\Composer\Semver; use _HumbugBox7ff99e199a36\Composer\Semver\Constraint\Constraint; use _HumbugBox7ff99e199a36\Composer\Semver\Constraint\ConstraintInterface; /** * Helper class to evaluate constraint by compiling and reusing the code to evaluate */ class CompilingMatcher { /** * @var array * @phpstan-var array */ private static $compiledCheckerCache = array(); /** * @var array * @phpstan-var array */ private static $resultCache = array(); /** @var bool */ private static $enabled; /** * @phpstan-var array */ private static $transOpInt = array(Constraint::OP_EQ => Constraint::STR_OP_EQ, Constraint::OP_LT => Constraint::STR_OP_LT, Constraint::OP_LE => Constraint::STR_OP_LE, Constraint::OP_GT => Constraint::STR_OP_GT, Constraint::OP_GE => Constraint::STR_OP_GE, Constraint::OP_NE => Constraint::STR_OP_NE); /** * Clears the memoization cache once you are done * * @return void */ public static function clear() { self::$resultCache = array(); self::$compiledCheckerCache = array(); } /** * Evaluates the expression: $constraint match $operator $version * * @param ConstraintInterface $constraint * @param int $operator * @phpstan-param Constraint::OP_* $operator * @param string $version * * @return mixed */ public static function match(ConstraintInterface $constraint, $operator, $version) { $resultCacheKey = $operator . $constraint . ';' . $version; if (isset(self::$resultCache[$resultCacheKey])) { return self::$resultCache[$resultCacheKey]; } if (self::$enabled === null) { self::$enabled = !\in_array('eval', \explode(',', (string) \ini_get('disable_functions')), \true); } if (!self::$enabled) { return self::$resultCache[$resultCacheKey] = $constraint->matches(new Constraint(self::$transOpInt[$operator], $version)); } $cacheKey = $operator . $constraint; if (!isset(self::$compiledCheckerCache[$cacheKey])) { $code = $constraint->compile($operator); self::$compiledCheckerCache[$cacheKey] = $function = eval('return function($v, $b){return ' . $code . ';};'); } else { $function = self::$compiledCheckerCache[$cacheKey]; } return self::$resultCache[$resultCacheKey] = $function($version, \strpos($version, 'dev-') === 0); } } * * For the full copyright and license information, please view * the LICENSE file that was distributed with this source code. */ namespace _HumbugBox7ff99e199a36\Composer\Semver; use _HumbugBox7ff99e199a36\Composer\Semver\Constraint\Constraint; class Interval { /** @var Constraint */ private $start; /** @var Constraint */ private $end; public function __construct(Constraint $start, Constraint $end) { $this->start = $start; $this->end = $end; } /** * @return Constraint */ public function getStart() { return $this->start; } /** * @return Constraint */ public function getEnd() { return $this->end; } /** * @return Constraint */ public static function fromZero() { static $zero; if (null === $zero) { $zero = new Constraint('>=', '0.0.0.0-dev'); } return $zero; } /** * @return Constraint */ public static function untilPositiveInfinity() { static $positiveInfinity; if (null === $positiveInfinity) { $positiveInfinity = new Constraint('<', \PHP_INT_MAX . '.0.0.0'); } return $positiveInfinity; } /** * @return self */ public static function any() { return new self(self::fromZero(), self::untilPositiveInfinity()); } /** * @return array{'names': string[], 'exclude': bool} */ public static function anyDev() { // any == exclude nothing return array('names' => array(), 'exclude' => \true); } /** * @return array{'names': string[], 'exclude': bool} */ public static function noDev() { // nothing == no names included return array('names' => array(), 'exclude' => \false); } } * * For the full copyright and license information, please view * the LICENSE file that was distributed with this source code. */ namespace _HumbugBox7ff99e199a36\Composer\Semver\Constraint; /** * Defines a constraint. */ class Constraint implements ConstraintInterface { /* operator integer values */ const OP_EQ = 0; const OP_LT = 1; const OP_LE = 2; const OP_GT = 3; const OP_GE = 4; const OP_NE = 5; /* operator string values */ const STR_OP_EQ = '=='; const STR_OP_EQ_ALT = '='; const STR_OP_LT = '<'; const STR_OP_LE = '<='; const STR_OP_GT = '>'; const STR_OP_GE = '>='; const STR_OP_NE = '!='; const STR_OP_NE_ALT = '<>'; /** * Operator to integer translation table. * * @var array * @phpstan-var array */ private static $transOpStr = array('=' => self::OP_EQ, '==' => self::OP_EQ, '<' => self::OP_LT, '<=' => self::OP_LE, '>' => self::OP_GT, '>=' => self::OP_GE, '<>' => self::OP_NE, '!=' => self::OP_NE); /** * Integer to operator translation table. * * @var array * @phpstan-var array */ private static $transOpInt = array(self::OP_EQ => '==', self::OP_LT => '<', self::OP_LE => '<=', self::OP_GT => '>', self::OP_GE => '>=', self::OP_NE => '!='); /** * @var int * @phpstan-var self::OP_* */ protected $operator; /** @var string */ protected $version; /** @var string|null */ protected $prettyString; /** @var Bound */ protected $lowerBound; /** @var Bound */ protected $upperBound; /** * Sets operator and version to compare with. * * @param string $operator * @param string $version * * @throws \InvalidArgumentException if invalid operator is given. * * @phpstan-param self::STR_OP_* $operator */ public function __construct($operator, $version) { if (!isset(self::$transOpStr[$operator])) { throw new \InvalidArgumentException(\sprintf('Invalid operator "%s" given, expected one of: %s', $operator, \implode(', ', self::getSupportedOperators()))); } $this->operator = self::$transOpStr[$operator]; $this->version = $version; } /** * @return string */ public function getVersion() { return $this->version; } /** * @return string * * @phpstan-return self::STR_OP_* */ public function getOperator() { return self::$transOpInt[$this->operator]; } /** * @param ConstraintInterface $provider * * @return bool */ public function matches(ConstraintInterface $provider) { if ($provider instanceof self) { return $this->matchSpecific($provider); } // turn matching around to find a match return $provider->matches($this); } /** * {@inheritDoc} */ public function setPrettyString($prettyString) { $this->prettyString = $prettyString; } /** * {@inheritDoc} */ public function getPrettyString() { if ($this->prettyString) { return $this->prettyString; } return $this->__toString(); } /** * Get all supported comparison operators. * * @return array * * @phpstan-return list */ public static function getSupportedOperators() { return \array_keys(self::$transOpStr); } /** * @param string $operator * @return int * * @phpstan-param self::STR_OP_* $operator * @phpstan-return self::OP_* */ public static function getOperatorConstant($operator) { return self::$transOpStr[$operator]; } /** * @param string $a * @param string $b * @param string $operator * @param bool $compareBranches * * @throws \InvalidArgumentException if invalid operator is given. * * @return bool * * @phpstan-param self::STR_OP_* $operator */ public function versionCompare($a, $b, $operator, $compareBranches = \false) { if (!isset(self::$transOpStr[$operator])) { throw new \InvalidArgumentException(\sprintf('Invalid operator "%s" given, expected one of: %s', $operator, \implode(', ', self::getSupportedOperators()))); } $aIsBranch = \strpos($a, 'dev-') === 0; $bIsBranch = \strpos($b, 'dev-') === 0; if ($operator === '!=' && ($aIsBranch || $bIsBranch)) { return $a !== $b; } if ($aIsBranch && $bIsBranch) { return $operator === '==' && $a === $b; } // when branches are not comparable, we make sure dev branches never match anything if (!$compareBranches && ($aIsBranch || $bIsBranch)) { return \false; } return \version_compare($a, $b, $operator); } /** * {@inheritDoc} */ public function compile($otherOperator) { if (\strpos($this->version, 'dev-') === 0) { if (self::OP_EQ === $this->operator) { if (self::OP_EQ === $otherOperator) { return \sprintf('$b && $v === %s', \var_export($this->version, \true)); } if (self::OP_NE === $otherOperator) { return \sprintf('!$b || $v !== %s', \var_export($this->version, \true)); } return 'false'; } if (self::OP_NE === $this->operator) { if (self::OP_EQ === $otherOperator) { return \sprintf('!$b || $v !== %s', \var_export($this->version, \true)); } if (self::OP_NE === $otherOperator) { return 'true'; } return '!$b'; } return 'false'; } if (self::OP_EQ === $this->operator) { if (self::OP_EQ === $otherOperator) { return \sprintf('\\version_compare($v, %s, \'==\')', \var_export($this->version, \true)); } if (self::OP_NE === $otherOperator) { return \sprintf('$b || \\version_compare($v, %s, \'!=\')', \var_export($this->version, \true)); } return \sprintf('!$b && \\version_compare(%s, $v, \'%s\')', \var_export($this->version, \true), self::$transOpInt[$otherOperator]); } if (self::OP_NE === $this->operator) { if (self::OP_EQ === $otherOperator) { return \sprintf('$b || (!$b && \\version_compare($v, %s, \'!=\'))', \var_export($this->version, \true)); } if (self::OP_NE === $otherOperator) { return 'true'; } return '!$b'; } if (self::OP_LT === $this->operator || self::OP_LE === $this->operator) { if (self::OP_LT === $otherOperator || self::OP_LE === $otherOperator) { return '!$b'; } } else { // $this->operator must be self::OP_GT || self::OP_GE here if (self::OP_GT === $otherOperator || self::OP_GE === $otherOperator) { return '!$b'; } } if (self::OP_NE === $otherOperator) { return 'true'; } $codeComparison = \sprintf('\\version_compare($v, %s, \'%s\')', \var_export($this->version, \true), self::$transOpInt[$this->operator]); if ($this->operator === self::OP_LE) { if ($otherOperator === self::OP_GT) { return \sprintf('!$b && \\version_compare($v, %s, \'!=\') && ', \var_export($this->version, \true)) . $codeComparison; } } elseif ($this->operator === self::OP_GE) { if ($otherOperator === self::OP_LT) { return \sprintf('!$b && \\version_compare($v, %s, \'!=\') && ', \var_export($this->version, \true)) . $codeComparison; } } return \sprintf('!$b && %s', $codeComparison); } /** * @param Constraint $provider * @param bool $compareBranches * * @return bool */ public function matchSpecific(Constraint $provider, $compareBranches = \false) { $noEqualOp = \str_replace('=', '', self::$transOpInt[$this->operator]); $providerNoEqualOp = \str_replace('=', '', self::$transOpInt[$provider->operator]); $isEqualOp = self::OP_EQ === $this->operator; $isNonEqualOp = self::OP_NE === $this->operator; $isProviderEqualOp = self::OP_EQ === $provider->operator; $isProviderNonEqualOp = self::OP_NE === $provider->operator; // '!=' operator is match when other operator is not '==' operator or version is not match // these kinds of comparisons always have a solution if ($isNonEqualOp || $isProviderNonEqualOp) { if ($isNonEqualOp && !$isProviderNonEqualOp && !$isProviderEqualOp && \strpos($provider->version, 'dev-') === 0) { return \false; } if ($isProviderNonEqualOp && !$isNonEqualOp && !$isEqualOp && \strpos($this->version, 'dev-') === 0) { return \false; } if (!$isEqualOp && !$isProviderEqualOp) { return \true; } return $this->versionCompare($provider->version, $this->version, '!=', $compareBranches); } // an example for the condition is <= 2.0 & < 1.0 // these kinds of comparisons always have a solution if ($this->operator !== self::OP_EQ && $noEqualOp === $providerNoEqualOp) { return !(\strpos($this->version, 'dev-') === 0 || \strpos($provider->version, 'dev-') === 0); } $version1 = $isEqualOp ? $this->version : $provider->version; $version2 = $isEqualOp ? $provider->version : $this->version; $operator = $isEqualOp ? $provider->operator : $this->operator; if ($this->versionCompare($version1, $version2, self::$transOpInt[$operator], $compareBranches)) { // special case, e.g. require >= 1.0 and provide < 1.0 // 1.0 >= 1.0 but 1.0 is outside of the provided interval return !(self::$transOpInt[$provider->operator] === $providerNoEqualOp && self::$transOpInt[$this->operator] !== $noEqualOp && \version_compare($provider->version, $this->version, '==')); } return \false; } /** * @return string */ public function __toString() { return self::$transOpInt[$this->operator] . ' ' . $this->version; } /** * {@inheritDoc} */ public function getLowerBound() { $this->extractBounds(); return $this->lowerBound; } /** * {@inheritDoc} */ public function getUpperBound() { $this->extractBounds(); return $this->upperBound; } /** * @return void */ private function extractBounds() { if (null !== $this->lowerBound) { return; } // Branches if (\strpos($this->version, 'dev-') === 0) { $this->lowerBound = Bound::zero(); $this->upperBound = Bound::positiveInfinity(); return; } switch ($this->operator) { case self::OP_EQ: $this->lowerBound = new Bound($this->version, \true); $this->upperBound = new Bound($this->version, \true); break; case self::OP_LT: $this->lowerBound = Bound::zero(); $this->upperBound = new Bound($this->version, \false); break; case self::OP_LE: $this->lowerBound = Bound::zero(); $this->upperBound = new Bound($this->version, \true); break; case self::OP_GT: $this->lowerBound = new Bound($this->version, \false); $this->upperBound = Bound::positiveInfinity(); break; case self::OP_GE: $this->lowerBound = new Bound($this->version, \true); $this->upperBound = Bound::positiveInfinity(); break; case self::OP_NE: $this->lowerBound = Bound::zero(); $this->upperBound = Bound::positiveInfinity(); break; } } } * * For the full copyright and license information, please view * the LICENSE file that was distributed with this source code. */ namespace _HumbugBox7ff99e199a36\Composer\Semver\Constraint; /** * DO NOT IMPLEMENT this interface. It is only meant for usage as a type hint * in libraries relying on composer/semver but creating your own constraint class * that implements this interface is not a supported use case and will cause the * composer/semver components to return unexpected results. */ interface ConstraintInterface { /** * Checks whether the given constraint intersects in any way with this constraint * * @param ConstraintInterface $provider * * @return bool */ public function matches(ConstraintInterface $provider); /** * Provides a compiled version of the constraint for the given operator * The compiled version must be a PHP expression. * Executor of compile version must provide 2 variables: * - $v = the string version to compare with * - $b = whether or not the version is a non-comparable branch (starts with "dev-") * * @see Constraint::OP_* for the list of available operators. * @example return '!$b && version_compare($v, '1.0', '>')'; * * @param int $otherOperator one Constraint::OP_* * * @return string * * @phpstan-param Constraint::OP_* $otherOperator */ public function compile($otherOperator); /** * @return Bound */ public function getUpperBound(); /** * @return Bound */ public function getLowerBound(); /** * @return string */ public function getPrettyString(); /** * @param string|null $prettyString * * @return void */ public function setPrettyString($prettyString); /** * @return string */ public function __toString(); } * * For the full copyright and license information, please view * the LICENSE file that was distributed with this source code. */ namespace _HumbugBox7ff99e199a36\Composer\Semver\Constraint; /** * Defines a conjunctive or disjunctive set of constraints. */ class MultiConstraint implements ConstraintInterface { /** * @var ConstraintInterface[] * @phpstan-var non-empty-array */ protected $constraints; /** @var string|null */ protected $prettyString; /** @var string|null */ protected $string; /** @var bool */ protected $conjunctive; /** @var Bound|null */ protected $lowerBound; /** @var Bound|null */ protected $upperBound; /** * @param ConstraintInterface[] $constraints A set of constraints * @param bool $conjunctive Whether the constraints should be treated as conjunctive or disjunctive * * @throws \InvalidArgumentException If less than 2 constraints are passed */ public function __construct(array $constraints, $conjunctive = \true) { if (\count($constraints) < 2) { throw new \InvalidArgumentException('Must provide at least two constraints for a MultiConstraint. Use ' . 'the regular Constraint class for one constraint only or MatchAllConstraint for none. You may use ' . 'MultiConstraint::create() which optimizes and handles those cases automatically.'); } $this->constraints = $constraints; $this->conjunctive = $conjunctive; } /** * @return ConstraintInterface[] */ public function getConstraints() { return $this->constraints; } /** * @return bool */ public function isConjunctive() { return $this->conjunctive; } /** * @return bool */ public function isDisjunctive() { return !$this->conjunctive; } /** * {@inheritDoc} */ public function compile($otherOperator) { $parts = array(); foreach ($this->constraints as $constraint) { $code = $constraint->compile($otherOperator); if ($code === 'true') { if (!$this->conjunctive) { return 'true'; } } elseif ($code === 'false') { if ($this->conjunctive) { return 'false'; } } else { $parts[] = '(' . $code . ')'; } } if (!$parts) { return $this->conjunctive ? 'true' : 'false'; } return $this->conjunctive ? \implode('&&', $parts) : \implode('||', $parts); } /** * @param ConstraintInterface $provider * * @return bool */ public function matches(ConstraintInterface $provider) { if (\false === $this->conjunctive) { foreach ($this->constraints as $constraint) { if ($provider->matches($constraint)) { return \true; } } return \false; } // when matching a conjunctive and a disjunctive multi constraint we have to iterate over the disjunctive one // otherwise we'd return true if different parts of the disjunctive constraint match the conjunctive one // which would lead to incorrect results, e.g. [>1 and <2] would match [<1 or >2] although they do not intersect if ($provider instanceof MultiConstraint && $provider->isDisjunctive()) { return $provider->matches($this); } foreach ($this->constraints as $constraint) { if (!$provider->matches($constraint)) { return \false; } } return \true; } /** * {@inheritDoc} */ public function setPrettyString($prettyString) { $this->prettyString = $prettyString; } /** * {@inheritDoc} */ public function getPrettyString() { if ($this->prettyString) { return $this->prettyString; } return (string) $this; } /** * {@inheritDoc} */ public function __toString() { if ($this->string !== null) { return $this->string; } $constraints = array(); foreach ($this->constraints as $constraint) { $constraints[] = (string) $constraint; } return $this->string = '[' . \implode($this->conjunctive ? ' ' : ' || ', $constraints) . ']'; } /** * {@inheritDoc} */ public function getLowerBound() { $this->extractBounds(); if (null === $this->lowerBound) { throw new \LogicException('extractBounds should have populated the lowerBound property'); } return $this->lowerBound; } /** * {@inheritDoc} */ public function getUpperBound() { $this->extractBounds(); if (null === $this->upperBound) { throw new \LogicException('extractBounds should have populated the upperBound property'); } return $this->upperBound; } /** * Tries to optimize the constraints as much as possible, meaning * reducing/collapsing congruent constraints etc. * Does not necessarily return a MultiConstraint instance if * things can be reduced to a simple constraint * * @param ConstraintInterface[] $constraints A set of constraints * @param bool $conjunctive Whether the constraints should be treated as conjunctive or disjunctive * * @return ConstraintInterface */ public static function create(array $constraints, $conjunctive = \true) { if (0 === \count($constraints)) { return new MatchAllConstraint(); } if (1 === \count($constraints)) { return $constraints[0]; } $optimized = self::optimizeConstraints($constraints, $conjunctive); if ($optimized !== null) { list($constraints, $conjunctive) = $optimized; if (\count($constraints) === 1) { return $constraints[0]; } } return new self($constraints, $conjunctive); } /** * @param ConstraintInterface[] $constraints * @param bool $conjunctive * @return ?array * * @phpstan-return array{0: list, 1: bool}|null */ private static function optimizeConstraints(array $constraints, $conjunctive) { // parse the two OR groups and if they are contiguous we collapse // them into one constraint // [>= 1 < 2] || [>= 2 < 3] || [>= 3 < 4] => [>= 1 < 4] if (!$conjunctive) { $left = $constraints[0]; $mergedConstraints = array(); $optimized = \false; for ($i = 1, $l = \count($constraints); $i < $l; $i++) { $right = $constraints[$i]; if ($left instanceof self && $left->conjunctive && $right instanceof self && $right->conjunctive && \count($left->constraints) === 2 && \count($right->constraints) === 2 && ($left0 = (string) $left->constraints[0]) && $left0[0] === '>' && $left0[1] === '=' && ($left1 = (string) $left->constraints[1]) && $left1[0] === '<' && ($right0 = (string) $right->constraints[0]) && $right0[0] === '>' && $right0[1] === '=' && ($right1 = (string) $right->constraints[1]) && $right1[0] === '<' && \substr($left1, 2) === \substr($right0, 3)) { $optimized = \true; $left = new MultiConstraint(array($left->constraints[0], $right->constraints[1]), \true); } else { $mergedConstraints[] = $left; $left = $right; } } if ($optimized) { $mergedConstraints[] = $left; return array($mergedConstraints, \false); } } // TODO: Here's the place to put more optimizations return null; } /** * @return void */ private function extractBounds() { if (null !== $this->lowerBound) { return; } foreach ($this->constraints as $constraint) { if (null === $this->lowerBound || null === $this->upperBound) { $this->lowerBound = $constraint->getLowerBound(); $this->upperBound = $constraint->getUpperBound(); continue; } if ($constraint->getLowerBound()->compareTo($this->lowerBound, $this->isConjunctive() ? '>' : '<')) { $this->lowerBound = $constraint->getLowerBound(); } if ($constraint->getUpperBound()->compareTo($this->upperBound, $this->isConjunctive() ? '<' : '>')) { $this->upperBound = $constraint->getUpperBound(); } } } } * * For the full copyright and license information, please view * the LICENSE file that was distributed with this source code. */ namespace _HumbugBox7ff99e199a36\Composer\Semver\Constraint; /** * Blackhole of constraints, nothing escapes it */ class MatchNoneConstraint implements ConstraintInterface { /** @var string|null */ protected $prettyString; /** * @param ConstraintInterface $provider * * @return bool */ public function matches(ConstraintInterface $provider) { return \false; } /** * {@inheritDoc} */ public function compile($otherOperator) { return 'false'; } /** * {@inheritDoc} */ public function setPrettyString($prettyString) { $this->prettyString = $prettyString; } /** * {@inheritDoc} */ public function getPrettyString() { if ($this->prettyString) { return $this->prettyString; } return (string) $this; } /** * {@inheritDoc} */ public function __toString() { return '[]'; } /** * {@inheritDoc} */ public function getUpperBound() { return new Bound('0.0.0.0-dev', \false); } /** * {@inheritDoc} */ public function getLowerBound() { return new Bound('0.0.0.0-dev', \false); } } * * For the full copyright and license information, please view * the LICENSE file that was distributed with this source code. */ namespace _HumbugBox7ff99e199a36\Composer\Semver\Constraint; /** * Defines the absence of a constraint. * * This constraint matches everything. */ class MatchAllConstraint implements ConstraintInterface { /** @var string|null */ protected $prettyString; /** * @param ConstraintInterface $provider * * @return bool */ public function matches(ConstraintInterface $provider) { return \true; } /** * {@inheritDoc} */ public function compile($otherOperator) { return 'true'; } /** * {@inheritDoc} */ public function setPrettyString($prettyString) { $this->prettyString = $prettyString; } /** * {@inheritDoc} */ public function getPrettyString() { if ($this->prettyString) { return $this->prettyString; } return (string) $this; } /** * {@inheritDoc} */ public function __toString() { return '*'; } /** * {@inheritDoc} */ public function getUpperBound() { return Bound::positiveInfinity(); } /** * {@inheritDoc} */ public function getLowerBound() { return Bound::zero(); } } * * For the full copyright and license information, please view * the LICENSE file that was distributed with this source code. */ namespace _HumbugBox7ff99e199a36\Composer\Semver\Constraint; class Bound { /** * @var string */ private $version; /** * @var bool */ private $isInclusive; /** * @param string $version * @param bool $isInclusive */ public function __construct($version, $isInclusive) { $this->version = $version; $this->isInclusive = $isInclusive; } /** * @return string */ public function getVersion() { return $this->version; } /** * @return bool */ public function isInclusive() { return $this->isInclusive; } /** * @return bool */ public function isZero() { return $this->getVersion() === '0.0.0.0-dev' && $this->isInclusive(); } /** * @return bool */ public function isPositiveInfinity() { return $this->getVersion() === \PHP_INT_MAX . '.0.0.0' && !$this->isInclusive(); } /** * Compares a bound to another with a given operator. * * @param Bound $other * @param string $operator * * @return bool */ public function compareTo(Bound $other, $operator) { if (!\in_array($operator, array('<', '>'), \true)) { throw new \InvalidArgumentException('Does not support any other operator other than > or <.'); } // If they are the same it doesn't matter if ($this == $other) { return \false; } $compareResult = \version_compare($this->getVersion(), $other->getVersion()); // Not the same version means we don't need to check if the bounds are inclusive or not if (0 !== $compareResult) { return ('>' === $operator ? 1 : -1) === $compareResult; } // Question we're answering here is "am I higher than $other?" return '>' === $operator ? $other->isInclusive() : !$other->isInclusive(); } public function __toString() { return \sprintf('%s [%s]', $this->getVersion(), $this->isInclusive() ? 'inclusive' : 'exclusive'); } /** * @return self */ public static function zero() { return new Bound('0.0.0.0-dev', \true); } /** * @return self */ public static function positiveInfinity() { return new Bound(\PHP_INT_MAX . '.0.0.0', \false); } } * * For the full copyright and license information, please view * the LICENSE file that was distributed with this source code. */ namespace _HumbugBox7ff99e199a36\Composer\Semver; use _HumbugBox7ff99e199a36\Composer\Semver\Constraint\Constraint; class Semver { const SORT_ASC = 1; const SORT_DESC = -1; /** @var VersionParser */ private static $versionParser; /** * Determine if given version satisfies given constraints. * * @param string $version * @param string $constraints * * @return bool */ public static function satisfies($version, $constraints) { if (null === self::$versionParser) { self::$versionParser = new VersionParser(); } $versionParser = self::$versionParser; $provider = new Constraint('==', $versionParser->normalize($version)); $parsedConstraints = $versionParser->parseConstraints($constraints); return $parsedConstraints->matches($provider); } /** * Return all versions that satisfy given constraints. * * @param string[] $versions * @param string $constraints * * @return string[] */ public static function satisfiedBy(array $versions, $constraints) { $versions = \array_filter($versions, function ($version) use($constraints) { return Semver::satisfies($version, $constraints); }); return \array_values($versions); } /** * Sort given array of versions. * * @param string[] $versions * * @return string[] */ public static function sort(array $versions) { return self::usort($versions, self::SORT_ASC); } /** * Sort given array of versions in reverse. * * @param string[] $versions * * @return string[] */ public static function rsort(array $versions) { return self::usort($versions, self::SORT_DESC); } /** * @param string[] $versions * @param int $direction * * @return string[] */ private static function usort(array $versions, $direction) { if (null === self::$versionParser) { self::$versionParser = new VersionParser(); } $versionParser = self::$versionParser; $normalized = array(); // Normalize outside of usort() scope for minor performance increase. // Creates an array of arrays: [[normalized, key], ...] foreach ($versions as $key => $version) { $normalizedVersion = $versionParser->normalize($version); $normalizedVersion = $versionParser->normalizeDefaultBranch($normalizedVersion); $normalized[] = array($normalizedVersion, $key); } \usort($normalized, function (array $left, array $right) use($direction) { if ($left[0] === $right[0]) { return 0; } if (Comparator::lessThan($left[0], $right[0])) { return -$direction; } return $direction; }); // Recreate input array, using the original indexes which are now in sorted order. $sorted = array(); foreach ($normalized as $item) { $sorted[] = $versions[$item[1]]; } return $sorted; } } $vendorDir . '/symfony/polyfill-php80/Resources/stubs/Attribute.php', 'Composer\\InstalledVersions' => $vendorDir . '/composer/InstalledVersions.php', 'PhpToken' => $vendorDir . '/symfony/polyfill-php80/Resources/stubs/PhpToken.php', 'Psalm\\Aliases' => $baseDir . '/src/Psalm/Aliases.php', 'Psalm\\CodeLocation' => $baseDir . '/src/Psalm/CodeLocation.php', 'Psalm\\CodeLocation\\DocblockTypeLocation' => $baseDir . '/src/Psalm/CodeLocation/DocblockTypeLocation.php', 'Psalm\\CodeLocation\\ParseErrorLocation' => $baseDir . '/src/Psalm/CodeLocation/ParseErrorLocation.php', 'Psalm\\CodeLocation\\Raw' => $baseDir . '/src/Psalm/CodeLocation/Raw.php', 'Psalm\\Codebase' => $baseDir . '/src/Psalm/Codebase.php', 'Psalm\\Config' => $baseDir . '/src/Psalm/Config.php', 'Psalm\\Config\\Creator' => $baseDir . '/src/Psalm/Config/Creator.php', 'Psalm\\Config\\ErrorLevelFileFilter' => $baseDir . '/src/Psalm/Config/ErrorLevelFileFilter.php', 'Psalm\\Config\\FileFilter' => $baseDir . '/src/Psalm/Config/FileFilter.php', 'Psalm\\Config\\IssueHandler' => $baseDir . '/src/Psalm/Config/IssueHandler.php', 'Psalm\\Config\\ProjectFileFilter' => $baseDir . '/src/Psalm/Config/ProjectFileFilter.php', 'Psalm\\Config\\TaintAnalysisFileFilter' => $baseDir . '/src/Psalm/Config/TaintAnalysisFileFilter.php', 'Psalm\\Context' => $baseDir . '/src/Psalm/Context.php', 'Psalm\\DocComment' => $baseDir . '/src/Psalm/DocComment.php', 'Psalm\\ErrorBaseline' => $baseDir . '/src/Psalm/ErrorBaseline.php', 'Psalm\\Exception\\CircularReferenceException' => $baseDir . '/src/Psalm/Exception/CircularReferenceException.php', 'Psalm\\Exception\\CodeException' => $baseDir . '/src/Psalm/Exception/CodeException.php', 'Psalm\\Exception\\ComplicatedExpressionException' => $baseDir . '/src/Psalm/Exception/ComplicatedExpressionException.php', 'Psalm\\Exception\\ConfigCreationException' => $baseDir . '/src/Psalm/Exception/ConfigCreationException.php', 'Psalm\\Exception\\ConfigException' => $baseDir . '/src/Psalm/Exception/ConfigException.php', 'Psalm\\Exception\\ConfigNotFoundException' => $baseDir . '/src/Psalm/Exception/ConfigNotFoundException.php', 'Psalm\\Exception\\DocblockParseException' => $baseDir . '/src/Psalm/Exception/DocblockParseException.php', 'Psalm\\Exception\\FileIncludeException' => $baseDir . '/src/Psalm/Exception/FileIncludeException.php', 'Psalm\\Exception\\IncorrectDocblockException' => $baseDir . '/src/Psalm/Exception/IncorrectDocblockException.php', 'Psalm\\Exception\\InvalidClasslikeOverrideException' => $baseDir . '/src/Psalm/Exception/InvalidClasslikeOverrideException.php', 'Psalm\\Exception\\InvalidMethodOverrideException' => $baseDir . '/src/Psalm/Exception/InvalidMethodOverrideException.php', 'Psalm\\Exception\\RefactorException' => $baseDir . '/src/Psalm/Exception/RefactorException.php', 'Psalm\\Exception\\ScopeAnalysisException' => $baseDir . '/src/Psalm/Exception/ScopeAnalysisException.php', 'Psalm\\Exception\\TypeParseTreeException' => $baseDir . '/src/Psalm/Exception/TypeParseTreeException.php', 'Psalm\\Exception\\UnanalyzedFileException' => $baseDir . '/src/Psalm/Exception/UnanalyzedFileException.php', 'Psalm\\Exception\\UnpopulatedClasslikeException' => $baseDir . '/src/Psalm/Exception/UnpopulatedClasslikeException.php', 'Psalm\\Exception\\UnpreparedAnalysisException' => $baseDir . '/src/Psalm/Exception/UnpreparedAnalysisException.php', 'Psalm\\Exception\\UnresolvableConstantException' => $baseDir . '/src/Psalm/Exception/UnresolvableConstantException.php', 'Psalm\\Exception\\UnsupportedIssueToFixException' => $baseDir . '/src/Psalm/Exception/UnsupportedIssueToFixException.php', 'Psalm\\FileBasedPluginAdapter' => $baseDir . '/src/Psalm/FileBasedPluginAdapter.php', 'Psalm\\FileManipulation' => $baseDir . '/src/Psalm/FileManipulation.php', 'Psalm\\FileSource' => $baseDir . '/src/Psalm/FileSource.php', 'Psalm\\Internal\\Algebra' => $baseDir . '/src/Psalm/Internal/Algebra.php', 'Psalm\\Internal\\Algebra\\FormulaGenerator' => $baseDir . '/src/Psalm/Internal/Algebra/FormulaGenerator.php', 'Psalm\\Internal\\Analyzer\\AlgebraAnalyzer' => $baseDir . '/src/Psalm/Internal/Analyzer/AlgebraAnalyzer.php', 'Psalm\\Internal\\Analyzer\\AttributesAnalyzer' => $baseDir . '/src/Psalm/Internal/Analyzer/AttributesAnalyzer.php', 'Psalm\\Internal\\Analyzer\\CanAlias' => $baseDir . '/src/Psalm/Internal/Analyzer/CanAlias.php', 'Psalm\\Internal\\Analyzer\\ClassAnalyzer' => $baseDir . '/src/Psalm/Internal/Analyzer/ClassAnalyzer.php', 'Psalm\\Internal\\Analyzer\\ClassLikeAnalyzer' => $baseDir . '/src/Psalm/Internal/Analyzer/ClassLikeAnalyzer.php', 'Psalm\\Internal\\Analyzer\\ClassLikeNameOptions' => $baseDir . '/src/Psalm/Internal/Analyzer/ClassLikeNameOptions.php', 'Psalm\\Internal\\Analyzer\\ClosureAnalyzer' => $baseDir . '/src/Psalm/Internal/Analyzer/ClosureAnalyzer.php', 'Psalm\\Internal\\Analyzer\\CommentAnalyzer' => $baseDir . '/src/Psalm/Internal/Analyzer/CommentAnalyzer.php', 'Psalm\\Internal\\Analyzer\\DataFlowNodeData' => $baseDir . '/src/Psalm/Internal/Analyzer/DataFlowNodeData.php', 'Psalm\\Internal\\Analyzer\\FileAnalyzer' => $baseDir . '/src/Psalm/Internal/Analyzer/FileAnalyzer.php', 'Psalm\\Internal\\Analyzer\\FunctionAnalyzer' => $baseDir . '/src/Psalm/Internal/Analyzer/FunctionAnalyzer.php', 'Psalm\\Internal\\Analyzer\\FunctionLikeAnalyzer' => $baseDir . '/src/Psalm/Internal/Analyzer/FunctionLikeAnalyzer.php', 'Psalm\\Internal\\Analyzer\\FunctionLike\\ReturnTypeAnalyzer' => $baseDir . '/src/Psalm/Internal/Analyzer/FunctionLike/ReturnTypeAnalyzer.php', 'Psalm\\Internal\\Analyzer\\FunctionLike\\ReturnTypeCollector' => $baseDir . '/src/Psalm/Internal/Analyzer/FunctionLike/ReturnTypeCollector.php', 'Psalm\\Internal\\Analyzer\\InterfaceAnalyzer' => $baseDir . '/src/Psalm/Internal/Analyzer/InterfaceAnalyzer.php', 'Psalm\\Internal\\Analyzer\\IssueData' => $baseDir . '/src/Psalm/Internal/Analyzer/IssueData.php', 'Psalm\\Internal\\Analyzer\\MethodAnalyzer' => $baseDir . '/src/Psalm/Internal/Analyzer/MethodAnalyzer.php', 'Psalm\\Internal\\Analyzer\\MethodComparator' => $baseDir . '/src/Psalm/Internal/Analyzer/MethodComparator.php', 'Psalm\\Internal\\Analyzer\\NamespaceAnalyzer' => $baseDir . '/src/Psalm/Internal/Analyzer/NamespaceAnalyzer.php', 'Psalm\\Internal\\Analyzer\\ProjectAnalyzer' => $baseDir . '/src/Psalm/Internal/Analyzer/ProjectAnalyzer.php', 'Psalm\\Internal\\Analyzer\\ScopeAnalyzer' => $baseDir . '/src/Psalm/Internal/Analyzer/ScopeAnalyzer.php', 'Psalm\\Internal\\Analyzer\\SourceAnalyzer' => $baseDir . '/src/Psalm/Internal/Analyzer/SourceAnalyzer.php', 'Psalm\\Internal\\Analyzer\\StatementsAnalyzer' => $baseDir . '/src/Psalm/Internal/Analyzer/StatementsAnalyzer.php', 'Psalm\\Internal\\Analyzer\\Statements\\Block\\DoAnalyzer' => $baseDir . '/src/Psalm/Internal/Analyzer/Statements/Block/DoAnalyzer.php', 'Psalm\\Internal\\Analyzer\\Statements\\Block\\ForAnalyzer' => $baseDir . '/src/Psalm/Internal/Analyzer/Statements/Block/ForAnalyzer.php', 'Psalm\\Internal\\Analyzer\\Statements\\Block\\ForeachAnalyzer' => $baseDir . '/src/Psalm/Internal/Analyzer/Statements/Block/ForeachAnalyzer.php', 'Psalm\\Internal\\Analyzer\\Statements\\Block\\IfConditionalAnalyzer' => $baseDir . '/src/Psalm/Internal/Analyzer/Statements/Block/IfConditionalAnalyzer.php', 'Psalm\\Internal\\Analyzer\\Statements\\Block\\IfElseAnalyzer' => $baseDir . '/src/Psalm/Internal/Analyzer/Statements/Block/IfElseAnalyzer.php', 'Psalm\\Internal\\Analyzer\\Statements\\Block\\IfElse\\ElseAnalyzer' => $baseDir . '/src/Psalm/Internal/Analyzer/Statements/Block/IfElse/ElseAnalyzer.php', 'Psalm\\Internal\\Analyzer\\Statements\\Block\\IfElse\\ElseIfAnalyzer' => $baseDir . '/src/Psalm/Internal/Analyzer/Statements/Block/IfElse/ElseIfAnalyzer.php', 'Psalm\\Internal\\Analyzer\\Statements\\Block\\IfElse\\IfAnalyzer' => $baseDir . '/src/Psalm/Internal/Analyzer/Statements/Block/IfElse/IfAnalyzer.php', 'Psalm\\Internal\\Analyzer\\Statements\\Block\\LoopAnalyzer' => $baseDir . '/src/Psalm/Internal/Analyzer/Statements/Block/LoopAnalyzer.php', 'Psalm\\Internal\\Analyzer\\Statements\\Block\\SwitchAnalyzer' => $baseDir . '/src/Psalm/Internal/Analyzer/Statements/Block/SwitchAnalyzer.php', 'Psalm\\Internal\\Analyzer\\Statements\\Block\\SwitchCaseAnalyzer' => $baseDir . '/src/Psalm/Internal/Analyzer/Statements/Block/SwitchCaseAnalyzer.php', 'Psalm\\Internal\\Analyzer\\Statements\\Block\\TryAnalyzer' => $baseDir . '/src/Psalm/Internal/Analyzer/Statements/Block/TryAnalyzer.php', 'Psalm\\Internal\\Analyzer\\Statements\\Block\\WhileAnalyzer' => $baseDir . '/src/Psalm/Internal/Analyzer/Statements/Block/WhileAnalyzer.php', 'Psalm\\Internal\\Analyzer\\Statements\\BreakAnalyzer' => $baseDir . '/src/Psalm/Internal/Analyzer/Statements/BreakAnalyzer.php', 'Psalm\\Internal\\Analyzer\\Statements\\ContinueAnalyzer' => $baseDir . '/src/Psalm/Internal/Analyzer/Statements/ContinueAnalyzer.php', 'Psalm\\Internal\\Analyzer\\Statements\\DeclareAnalyzer' => $baseDir . '/src/Psalm/Internal/Analyzer/Statements/DeclareAnalyzer.php', 'Psalm\\Internal\\Analyzer\\Statements\\EchoAnalyzer' => $baseDir . '/src/Psalm/Internal/Analyzer/Statements/EchoAnalyzer.php', 'Psalm\\Internal\\Analyzer\\Statements\\ExpressionAnalyzer' => $baseDir . '/src/Psalm/Internal/Analyzer/Statements/ExpressionAnalyzer.php', 'Psalm\\Internal\\Analyzer\\Statements\\Expression\\ArrayAnalyzer' => $baseDir . '/src/Psalm/Internal/Analyzer/Statements/Expression/ArrayAnalyzer.php', 'Psalm\\Internal\\Analyzer\\Statements\\Expression\\ArrayCreationInfo' => $baseDir . '/src/Psalm/Internal/Analyzer/Statements/Expression/ArrayCreationInfo.php', 'Psalm\\Internal\\Analyzer\\Statements\\Expression\\AssertionFinder' => $baseDir . '/src/Psalm/Internal/Analyzer/Statements/Expression/AssertionFinder.php', 'Psalm\\Internal\\Analyzer\\Statements\\Expression\\AssignmentAnalyzer' => $baseDir . '/src/Psalm/Internal/Analyzer/Statements/Expression/AssignmentAnalyzer.php', 'Psalm\\Internal\\Analyzer\\Statements\\Expression\\Assignment\\ArrayAssignmentAnalyzer' => $baseDir . '/src/Psalm/Internal/Analyzer/Statements/Expression/Assignment/ArrayAssignmentAnalyzer.php', 'Psalm\\Internal\\Analyzer\\Statements\\Expression\\Assignment\\AssignedProperty' => $baseDir . '/src/Psalm/Internal/Analyzer/Statements/Expression/Assignment/AssignedProperty.php', 'Psalm\\Internal\\Analyzer\\Statements\\Expression\\Assignment\\InstancePropertyAssignmentAnalyzer' => $baseDir . '/src/Psalm/Internal/Analyzer/Statements/Expression/Assignment/InstancePropertyAssignmentAnalyzer.php', 'Psalm\\Internal\\Analyzer\\Statements\\Expression\\Assignment\\StaticPropertyAssignmentAnalyzer' => $baseDir . '/src/Psalm/Internal/Analyzer/Statements/Expression/Assignment/StaticPropertyAssignmentAnalyzer.php', 'Psalm\\Internal\\Analyzer\\Statements\\Expression\\BinaryOpAnalyzer' => $baseDir . '/src/Psalm/Internal/Analyzer/Statements/Expression/BinaryOpAnalyzer.php', 'Psalm\\Internal\\Analyzer\\Statements\\Expression\\BinaryOp\\AndAnalyzer' => $baseDir . '/src/Psalm/Internal/Analyzer/Statements/Expression/BinaryOp/AndAnalyzer.php', 'Psalm\\Internal\\Analyzer\\Statements\\Expression\\BinaryOp\\ArithmeticOpAnalyzer' => $baseDir . '/src/Psalm/Internal/Analyzer/Statements/Expression/BinaryOp/ArithmeticOpAnalyzer.php', 'Psalm\\Internal\\Analyzer\\Statements\\Expression\\BinaryOp\\CoalesceAnalyzer' => $baseDir . '/src/Psalm/Internal/Analyzer/Statements/Expression/BinaryOp/CoalesceAnalyzer.php', 'Psalm\\Internal\\Analyzer\\Statements\\Expression\\BinaryOp\\ConcatAnalyzer' => $baseDir . '/src/Psalm/Internal/Analyzer/Statements/Expression/BinaryOp/ConcatAnalyzer.php', 'Psalm\\Internal\\Analyzer\\Statements\\Expression\\BinaryOp\\NonComparisonOpAnalyzer' => $baseDir . '/src/Psalm/Internal/Analyzer/Statements/Expression/BinaryOp/NonComparisonOpAnalyzer.php', 'Psalm\\Internal\\Analyzer\\Statements\\Expression\\BinaryOp\\OrAnalyzer' => $baseDir . '/src/Psalm/Internal/Analyzer/Statements/Expression/BinaryOp/OrAnalyzer.php', 'Psalm\\Internal\\Analyzer\\Statements\\Expression\\BitwiseNotAnalyzer' => $baseDir . '/src/Psalm/Internal/Analyzer/Statements/Expression/BitwiseNotAnalyzer.php', 'Psalm\\Internal\\Analyzer\\Statements\\Expression\\BooleanNotAnalyzer' => $baseDir . '/src/Psalm/Internal/Analyzer/Statements/Expression/BooleanNotAnalyzer.php', 'Psalm\\Internal\\Analyzer\\Statements\\Expression\\CallAnalyzer' => $baseDir . '/src/Psalm/Internal/Analyzer/Statements/Expression/CallAnalyzer.php', 'Psalm\\Internal\\Analyzer\\Statements\\Expression\\Call\\ArgumentAnalyzer' => $baseDir . '/src/Psalm/Internal/Analyzer/Statements/Expression/Call/ArgumentAnalyzer.php', 'Psalm\\Internal\\Analyzer\\Statements\\Expression\\Call\\ArgumentMapPopulator' => $baseDir . '/src/Psalm/Internal/Analyzer/Statements/Expression/Call/ArgumentMapPopulator.php', 'Psalm\\Internal\\Analyzer\\Statements\\Expression\\Call\\ArgumentsAnalyzer' => $baseDir . '/src/Psalm/Internal/Analyzer/Statements/Expression/Call/ArgumentsAnalyzer.php', 'Psalm\\Internal\\Analyzer\\Statements\\Expression\\Call\\ArrayFunctionArgumentsAnalyzer' => $baseDir . '/src/Psalm/Internal/Analyzer/Statements/Expression/Call/ArrayFunctionArgumentsAnalyzer.php', 'Psalm\\Internal\\Analyzer\\Statements\\Expression\\Call\\ClassTemplateParamCollector' => $baseDir . '/src/Psalm/Internal/Analyzer/Statements/Expression/Call/ClassTemplateParamCollector.php', 'Psalm\\Internal\\Analyzer\\Statements\\Expression\\Call\\FunctionCallAnalyzer' => $baseDir . '/src/Psalm/Internal/Analyzer/Statements/Expression/Call/FunctionCallAnalyzer.php', 'Psalm\\Internal\\Analyzer\\Statements\\Expression\\Call\\FunctionCallInfo' => $baseDir . '/src/Psalm/Internal/Analyzer/Statements/Expression/Call/FunctionCallInfo.php', 'Psalm\\Internal\\Analyzer\\Statements\\Expression\\Call\\FunctionCallReturnTypeFetcher' => $baseDir . '/src/Psalm/Internal/Analyzer/Statements/Expression/Call/FunctionCallReturnTypeFetcher.php', 'Psalm\\Internal\\Analyzer\\Statements\\Expression\\Call\\HighOrderFunctionArgHandler' => $baseDir . '/src/Psalm/Internal/Analyzer/Statements/Expression/Call/HighOrderFunctionArgHandler.php', 'Psalm\\Internal\\Analyzer\\Statements\\Expression\\Call\\HighOrderFunctionArgInfo' => $baseDir . '/src/Psalm/Internal/Analyzer/Statements/Expression/Call/HighOrderFunctionArgInfo.php', 'Psalm\\Internal\\Analyzer\\Statements\\Expression\\Call\\MethodCallAnalyzer' => $baseDir . '/src/Psalm/Internal/Analyzer/Statements/Expression/Call/MethodCallAnalyzer.php', 'Psalm\\Internal\\Analyzer\\Statements\\Expression\\Call\\Method\\AtomicCallContext' => $baseDir . '/src/Psalm/Internal/Analyzer/Statements/Expression/Call/Method/AtomicCallContext.php', 'Psalm\\Internal\\Analyzer\\Statements\\Expression\\Call\\Method\\AtomicMethodCallAnalysisResult' => $baseDir . '/src/Psalm/Internal/Analyzer/Statements/Expression/Call/Method/AtomicMethodCallAnalysisResult.php', 'Psalm\\Internal\\Analyzer\\Statements\\Expression\\Call\\Method\\AtomicMethodCallAnalyzer' => $baseDir . '/src/Psalm/Internal/Analyzer/Statements/Expression/Call/Method/AtomicMethodCallAnalyzer.php', 'Psalm\\Internal\\Analyzer\\Statements\\Expression\\Call\\Method\\ExistingAtomicMethodCallAnalyzer' => $baseDir . '/src/Psalm/Internal/Analyzer/Statements/Expression/Call/Method/ExistingAtomicMethodCallAnalyzer.php', 'Psalm\\Internal\\Analyzer\\Statements\\Expression\\Call\\Method\\MethodCallProhibitionAnalyzer' => $baseDir . '/src/Psalm/Internal/Analyzer/Statements/Expression/Call/Method/MethodCallProhibitionAnalyzer.php', 'Psalm\\Internal\\Analyzer\\Statements\\Expression\\Call\\Method\\MethodCallPurityAnalyzer' => $baseDir . '/src/Psalm/Internal/Analyzer/Statements/Expression/Call/Method/MethodCallPurityAnalyzer.php', 'Psalm\\Internal\\Analyzer\\Statements\\Expression\\Call\\Method\\MethodCallReturnTypeFetcher' => $baseDir . '/src/Psalm/Internal/Analyzer/Statements/Expression/Call/Method/MethodCallReturnTypeFetcher.php', 'Psalm\\Internal\\Analyzer\\Statements\\Expression\\Call\\Method\\MethodVisibilityAnalyzer' => $baseDir . '/src/Psalm/Internal/Analyzer/Statements/Expression/Call/Method/MethodVisibilityAnalyzer.php', 'Psalm\\Internal\\Analyzer\\Statements\\Expression\\Call\\Method\\MissingMethodCallHandler' => $baseDir . '/src/Psalm/Internal/Analyzer/Statements/Expression/Call/Method/MissingMethodCallHandler.php', 'Psalm\\Internal\\Analyzer\\Statements\\Expression\\Call\\NamedFunctionCallHandler' => $baseDir . '/src/Psalm/Internal/Analyzer/Statements/Expression/Call/NamedFunctionCallHandler.php', 'Psalm\\Internal\\Analyzer\\Statements\\Expression\\Call\\NewAnalyzer' => $baseDir . '/src/Psalm/Internal/Analyzer/Statements/Expression/Call/NewAnalyzer.php', 'Psalm\\Internal\\Analyzer\\Statements\\Expression\\Call\\StaticCallAnalyzer' => $baseDir . '/src/Psalm/Internal/Analyzer/Statements/Expression/Call/StaticCallAnalyzer.php', 'Psalm\\Internal\\Analyzer\\Statements\\Expression\\Call\\StaticMethod\\AtomicStaticCallAnalyzer' => $baseDir . '/src/Psalm/Internal/Analyzer/Statements/Expression/Call/StaticMethod/AtomicStaticCallAnalyzer.php', 'Psalm\\Internal\\Analyzer\\Statements\\Expression\\Call\\StaticMethod\\ExistingAtomicStaticCallAnalyzer' => $baseDir . '/src/Psalm/Internal/Analyzer/Statements/Expression/Call/StaticMethod/ExistingAtomicStaticCallAnalyzer.php', 'Psalm\\Internal\\Analyzer\\Statements\\Expression\\CastAnalyzer' => $baseDir . '/src/Psalm/Internal/Analyzer/Statements/Expression/CastAnalyzer.php', 'Psalm\\Internal\\Analyzer\\Statements\\Expression\\ClassConstAnalyzer' => $baseDir . '/src/Psalm/Internal/Analyzer/Statements/Expression/ClassConstAnalyzer.php', 'Psalm\\Internal\\Analyzer\\Statements\\Expression\\CloneAnalyzer' => $baseDir . '/src/Psalm/Internal/Analyzer/Statements/Expression/CloneAnalyzer.php', 'Psalm\\Internal\\Analyzer\\Statements\\Expression\\EmptyAnalyzer' => $baseDir . '/src/Psalm/Internal/Analyzer/Statements/Expression/EmptyAnalyzer.php', 'Psalm\\Internal\\Analyzer\\Statements\\Expression\\EncapsulatedStringAnalyzer' => $baseDir . '/src/Psalm/Internal/Analyzer/Statements/Expression/EncapsulatedStringAnalyzer.php', 'Psalm\\Internal\\Analyzer\\Statements\\Expression\\EvalAnalyzer' => $baseDir . '/src/Psalm/Internal/Analyzer/Statements/Expression/EvalAnalyzer.php', 'Psalm\\Internal\\Analyzer\\Statements\\Expression\\ExitAnalyzer' => $baseDir . '/src/Psalm/Internal/Analyzer/Statements/Expression/ExitAnalyzer.php', 'Psalm\\Internal\\Analyzer\\Statements\\Expression\\ExpressionIdentifier' => $baseDir . '/src/Psalm/Internal/Analyzer/Statements/Expression/ExpressionIdentifier.php', 'Psalm\\Internal\\Analyzer\\Statements\\Expression\\Fetch\\ArrayFetchAnalyzer' => $baseDir . '/src/Psalm/Internal/Analyzer/Statements/Expression/Fetch/ArrayFetchAnalyzer.php', 'Psalm\\Internal\\Analyzer\\Statements\\Expression\\Fetch\\AtomicPropertyFetchAnalyzer' => $baseDir . '/src/Psalm/Internal/Analyzer/Statements/Expression/Fetch/AtomicPropertyFetchAnalyzer.php', 'Psalm\\Internal\\Analyzer\\Statements\\Expression\\Fetch\\ConstFetchAnalyzer' => $baseDir . '/src/Psalm/Internal/Analyzer/Statements/Expression/Fetch/ConstFetchAnalyzer.php', 'Psalm\\Internal\\Analyzer\\Statements\\Expression\\Fetch\\InstancePropertyFetchAnalyzer' => $baseDir . '/src/Psalm/Internal/Analyzer/Statements/Expression/Fetch/InstancePropertyFetchAnalyzer.php', 'Psalm\\Internal\\Analyzer\\Statements\\Expression\\Fetch\\StaticPropertyFetchAnalyzer' => $baseDir . '/src/Psalm/Internal/Analyzer/Statements/Expression/Fetch/StaticPropertyFetchAnalyzer.php', 'Psalm\\Internal\\Analyzer\\Statements\\Expression\\Fetch\\VariableFetchAnalyzer' => $baseDir . '/src/Psalm/Internal/Analyzer/Statements/Expression/Fetch/VariableFetchAnalyzer.php', 'Psalm\\Internal\\Analyzer\\Statements\\Expression\\IncDecExpressionAnalyzer' => $baseDir . '/src/Psalm/Internal/Analyzer/Statements/Expression/IncDecExpressionAnalyzer.php', 'Psalm\\Internal\\Analyzer\\Statements\\Expression\\IncludeAnalyzer' => $baseDir . '/src/Psalm/Internal/Analyzer/Statements/Expression/IncludeAnalyzer.php', 'Psalm\\Internal\\Analyzer\\Statements\\Expression\\InstanceofAnalyzer' => $baseDir . '/src/Psalm/Internal/Analyzer/Statements/Expression/InstanceofAnalyzer.php', 'Psalm\\Internal\\Analyzer\\Statements\\Expression\\IssetAnalyzer' => $baseDir . '/src/Psalm/Internal/Analyzer/Statements/Expression/IssetAnalyzer.php', 'Psalm\\Internal\\Analyzer\\Statements\\Expression\\MagicConstAnalyzer' => $baseDir . '/src/Psalm/Internal/Analyzer/Statements/Expression/MagicConstAnalyzer.php', 'Psalm\\Internal\\Analyzer\\Statements\\Expression\\MatchAnalyzer' => $baseDir . '/src/Psalm/Internal/Analyzer/Statements/Expression/MatchAnalyzer.php', 'Psalm\\Internal\\Analyzer\\Statements\\Expression\\NullsafeAnalyzer' => $baseDir . '/src/Psalm/Internal/Analyzer/Statements/Expression/NullsafeAnalyzer.php', 'Psalm\\Internal\\Analyzer\\Statements\\Expression\\PrintAnalyzer' => $baseDir . '/src/Psalm/Internal/Analyzer/Statements/Expression/PrintAnalyzer.php', 'Psalm\\Internal\\Analyzer\\Statements\\Expression\\SimpleTypeInferer' => $baseDir . '/src/Psalm/Internal/Analyzer/Statements/Expression/SimpleTypeInferer.php', 'Psalm\\Internal\\Analyzer\\Statements\\Expression\\TernaryAnalyzer' => $baseDir . '/src/Psalm/Internal/Analyzer/Statements/Expression/TernaryAnalyzer.php', 'Psalm\\Internal\\Analyzer\\Statements\\Expression\\UnaryPlusMinusAnalyzer' => $baseDir . '/src/Psalm/Internal/Analyzer/Statements/Expression/UnaryPlusMinusAnalyzer.php', 'Psalm\\Internal\\Analyzer\\Statements\\Expression\\YieldAnalyzer' => $baseDir . '/src/Psalm/Internal/Analyzer/Statements/Expression/YieldAnalyzer.php', 'Psalm\\Internal\\Analyzer\\Statements\\Expression\\YieldFromAnalyzer' => $baseDir . '/src/Psalm/Internal/Analyzer/Statements/Expression/YieldFromAnalyzer.php', 'Psalm\\Internal\\Analyzer\\Statements\\GlobalAnalyzer' => $baseDir . '/src/Psalm/Internal/Analyzer/Statements/GlobalAnalyzer.php', 'Psalm\\Internal\\Analyzer\\Statements\\ReturnAnalyzer' => $baseDir . '/src/Psalm/Internal/Analyzer/Statements/ReturnAnalyzer.php', 'Psalm\\Internal\\Analyzer\\Statements\\StaticAnalyzer' => $baseDir . '/src/Psalm/Internal/Analyzer/Statements/StaticAnalyzer.php', 'Psalm\\Internal\\Analyzer\\Statements\\ThrowAnalyzer' => $baseDir . '/src/Psalm/Internal/Analyzer/Statements/ThrowAnalyzer.php', 'Psalm\\Internal\\Analyzer\\Statements\\UnsetAnalyzer' => $baseDir . '/src/Psalm/Internal/Analyzer/Statements/UnsetAnalyzer.php', 'Psalm\\Internal\\Analyzer\\Statements\\UnusedAssignmentRemover' => $baseDir . '/src/Psalm/Internal/Analyzer/Statements/UnusedAssignmentRemover.php', 'Psalm\\Internal\\Analyzer\\TraitAnalyzer' => $baseDir . '/src/Psalm/Internal/Analyzer/TraitAnalyzer.php', 'Psalm\\Internal\\Analyzer\\TypeAnalyzer' => $baseDir . '/src/Psalm/Internal/Analyzer/TypeAnalyzer.php', 'Psalm\\Internal\\Cache' => $baseDir . '/src/Psalm/Internal/Cache.php', 'Psalm\\Internal\\Clause' => $baseDir . '/src/Psalm/Internal/Clause.php', 'Psalm\\Internal\\CliUtils' => $baseDir . '/src/Psalm/Internal/CliUtils.php', 'Psalm\\Internal\\Cli\\LanguageServer' => $baseDir . '/src/Psalm/Internal/Cli/LanguageServer.php', 'Psalm\\Internal\\Cli\\Plugin' => $baseDir . '/src/Psalm/Internal/Cli/Plugin.php', 'Psalm\\Internal\\Cli\\Psalm' => $baseDir . '/src/Psalm/Internal/Cli/Psalm.php', 'Psalm\\Internal\\Cli\\Psalter' => $baseDir . '/src/Psalm/Internal/Cli/Psalter.php', 'Psalm\\Internal\\Cli\\Refactor' => $baseDir . '/src/Psalm/Internal/Cli/Refactor.php', 'Psalm\\Internal\\Codebase\\Analyzer' => $baseDir . '/src/Psalm/Internal/Codebase/Analyzer.php', 'Psalm\\Internal\\Codebase\\AssertionsFromInheritanceResolver' => $baseDir . '/src/Psalm/Internal/Codebase/AssertionsFromInheritanceResolver.php', 'Psalm\\Internal\\Codebase\\ClassConstantByWildcardResolver' => $baseDir . '/src/Psalm/Internal/Codebase/ClassConstantByWildcardResolver.php', 'Psalm\\Internal\\Codebase\\ClassLikes' => $baseDir . '/src/Psalm/Internal/Codebase/ClassLikes.php', 'Psalm\\Internal\\Codebase\\ConstantTypeResolver' => $baseDir . '/src/Psalm/Internal/Codebase/ConstantTypeResolver.php', 'Psalm\\Internal\\Codebase\\DataFlowGraph' => $baseDir . '/src/Psalm/Internal/Codebase/DataFlowGraph.php', 'Psalm\\Internal\\Codebase\\Functions' => $baseDir . '/src/Psalm/Internal/Codebase/Functions.php', 'Psalm\\Internal\\Codebase\\ImpureFunctionsList' => $baseDir . '/src/Psalm/Internal/Codebase/ImpureFunctionsList.php', 'Psalm\\Internal\\Codebase\\InternalCallMapHandler' => $baseDir . '/src/Psalm/Internal/Codebase/InternalCallMapHandler.php', 'Psalm\\Internal\\Codebase\\Methods' => $baseDir . '/src/Psalm/Internal/Codebase/Methods.php', 'Psalm\\Internal\\Codebase\\Populator' => $baseDir . '/src/Psalm/Internal/Codebase/Populator.php', 'Psalm\\Internal\\Codebase\\Properties' => $baseDir . '/src/Psalm/Internal/Codebase/Properties.php', 'Psalm\\Internal\\Codebase\\PropertyMap' => $baseDir . '/src/Psalm/Internal/Codebase/PropertyMap.php', 'Psalm\\Internal\\Codebase\\ReferenceMapGenerator' => $baseDir . '/src/Psalm/Internal/Codebase/ReferenceMapGenerator.php', 'Psalm\\Internal\\Codebase\\Reflection' => $baseDir . '/src/Psalm/Internal/Codebase/Reflection.php', 'Psalm\\Internal\\Codebase\\Scanner' => $baseDir . '/src/Psalm/Internal/Codebase/Scanner.php', 'Psalm\\Internal\\Codebase\\StorageByPatternResolver' => $baseDir . '/src/Psalm/Internal/Codebase/StorageByPatternResolver.php', 'Psalm\\Internal\\Codebase\\TaintFlowGraph' => $baseDir . '/src/Psalm/Internal/Codebase/TaintFlowGraph.php', 'Psalm\\Internal\\Codebase\\VariableUseGraph' => $baseDir . '/src/Psalm/Internal/Codebase/VariableUseGraph.php', 'Psalm\\Internal\\Composer' => $baseDir . '/src/Psalm/Internal/Composer.php', 'Psalm\\Internal\\DataFlow\\DataFlowNode' => $baseDir . '/src/Psalm/Internal/DataFlow/DataFlowNode.php', 'Psalm\\Internal\\DataFlow\\Path' => $baseDir . '/src/Psalm/Internal/DataFlow/Path.php', 'Psalm\\Internal\\DataFlow\\TaintSink' => $baseDir . '/src/Psalm/Internal/DataFlow/TaintSink.php', 'Psalm\\Internal\\DataFlow\\TaintSource' => $baseDir . '/src/Psalm/Internal/DataFlow/TaintSource.php', 'Psalm\\Internal\\Diff\\AstDiffer' => $baseDir . '/src/Psalm/Internal/Diff/AstDiffer.php', 'Psalm\\Internal\\Diff\\ClassStatementsDiffer' => $baseDir . '/src/Psalm/Internal/Diff/ClassStatementsDiffer.php', 'Psalm\\Internal\\Diff\\DiffElem' => $baseDir . '/src/Psalm/Internal/Diff/DiffElem.php', 'Psalm\\Internal\\Diff\\FileDiffer' => $baseDir . '/src/Psalm/Internal/Diff/FileDiffer.php', 'Psalm\\Internal\\Diff\\FileStatementsDiffer' => $baseDir . '/src/Psalm/Internal/Diff/FileStatementsDiffer.php', 'Psalm\\Internal\\Diff\\NamespaceStatementsDiffer' => $baseDir . '/src/Psalm/Internal/Diff/NamespaceStatementsDiffer.php', 'Psalm\\Internal\\ErrorHandler' => $baseDir . '/src/Psalm/Internal/ErrorHandler.php', 'Psalm\\Internal\\EventDispatcher' => $baseDir . '/src/Psalm/Internal/EventDispatcher.php', 'Psalm\\Internal\\ExecutionEnvironment\\BuildInfoCollector' => $baseDir . '/src/Psalm/Internal/ExecutionEnvironment/BuildInfoCollector.php', 'Psalm\\Internal\\ExecutionEnvironment\\GitInfoCollector' => $baseDir . '/src/Psalm/Internal/ExecutionEnvironment/GitInfoCollector.php', 'Psalm\\Internal\\ExecutionEnvironment\\SystemCommandExecutor' => $baseDir . '/src/Psalm/Internal/ExecutionEnvironment/SystemCommandExecutor.php', 'Psalm\\Internal\\FileManipulation\\ClassDocblockManipulator' => $baseDir . '/src/Psalm/Internal/FileManipulation/ClassDocblockManipulator.php', 'Psalm\\Internal\\FileManipulation\\CodeMigration' => $baseDir . '/src/Psalm/Internal/FileManipulation/CodeMigration.php', 'Psalm\\Internal\\FileManipulation\\FileManipulationBuffer' => $baseDir . '/src/Psalm/Internal/FileManipulation/FileManipulationBuffer.php', 'Psalm\\Internal\\FileManipulation\\FunctionDocblockManipulator' => $baseDir . '/src/Psalm/Internal/FileManipulation/FunctionDocblockManipulator.php', 'Psalm\\Internal\\FileManipulation\\PropertyDocblockManipulator' => $baseDir . '/src/Psalm/Internal/FileManipulation/PropertyDocblockManipulator.php', 'Psalm\\Internal\\Fork\\ForkMessage' => $baseDir . '/src/Psalm/Internal/Fork/ForkMessage.php', 'Psalm\\Internal\\Fork\\ForkProcessDoneMessage' => $baseDir . '/src/Psalm/Internal/Fork/ForkProcessDoneMessage.php', 'Psalm\\Internal\\Fork\\ForkProcessErrorMessage' => $baseDir . '/src/Psalm/Internal/Fork/ForkProcessErrorMessage.php', 'Psalm\\Internal\\Fork\\ForkTaskDoneMessage' => $baseDir . '/src/Psalm/Internal/Fork/ForkTaskDoneMessage.php', 'Psalm\\Internal\\Fork\\Pool' => $baseDir . '/src/Psalm/Internal/Fork/Pool.php', 'Psalm\\Internal\\Fork\\PsalmRestarter' => $baseDir . '/src/Psalm/Internal/Fork/PsalmRestarter.php', 'Psalm\\Internal\\IncludeCollector' => $baseDir . '/src/Psalm/Internal/IncludeCollector.php', 'Psalm\\Internal\\Json\\Json' => $baseDir . '/src/Psalm/Internal/Json/Json.php', 'Psalm\\Internal\\LanguageServer\\ClientConfiguration' => $baseDir . '/src/Psalm/Internal/LanguageServer/ClientConfiguration.php', 'Psalm\\Internal\\LanguageServer\\ClientHandler' => $baseDir . '/src/Psalm/Internal/LanguageServer/ClientHandler.php', 'Psalm\\Internal\\LanguageServer\\Client\\Progress\\LegacyProgress' => $baseDir . '/src/Psalm/Internal/LanguageServer/Client/Progress/LegacyProgress.php', 'Psalm\\Internal\\LanguageServer\\Client\\Progress\\Progress' => $baseDir . '/src/Psalm/Internal/LanguageServer/Client/Progress/Progress.php', 'Psalm\\Internal\\LanguageServer\\Client\\Progress\\ProgressInterface' => $baseDir . '/src/Psalm/Internal/LanguageServer/Client/Progress/ProgressInterface.php', 'Psalm\\Internal\\LanguageServer\\Client\\TextDocument' => $baseDir . '/src/Psalm/Internal/LanguageServer/Client/TextDocument.php', 'Psalm\\Internal\\LanguageServer\\Client\\Workspace' => $baseDir . '/src/Psalm/Internal/LanguageServer/Client/Workspace.php', 'Psalm\\Internal\\LanguageServer\\EmitterInterface' => $baseDir . '/src/Psalm/Internal/LanguageServer/EmitterInterface.php', 'Psalm\\Internal\\LanguageServer\\EmitterTrait' => $baseDir . '/src/Psalm/Internal/LanguageServer/EmitterTrait.php', 'Psalm\\Internal\\LanguageServer\\IdGenerator' => $baseDir . '/src/Psalm/Internal/LanguageServer/IdGenerator.php', 'Psalm\\Internal\\LanguageServer\\LanguageClient' => $baseDir . '/src/Psalm/Internal/LanguageServer/LanguageClient.php', 'Psalm\\Internal\\LanguageServer\\LanguageServer' => $baseDir . '/src/Psalm/Internal/LanguageServer/LanguageServer.php', 'Psalm\\Internal\\LanguageServer\\Message' => $baseDir . '/src/Psalm/Internal/LanguageServer/Message.php', 'Psalm\\Internal\\LanguageServer\\PHPMarkdownContent' => $baseDir . '/src/Psalm/Internal/LanguageServer/PHPMarkdownContent.php', 'Psalm\\Internal\\LanguageServer\\PathMapper' => $baseDir . '/src/Psalm/Internal/LanguageServer/PathMapper.php', 'Psalm\\Internal\\LanguageServer\\Progress' => $baseDir . '/src/Psalm/Internal/LanguageServer/Progress.php', 'Psalm\\Internal\\LanguageServer\\ProtocolReader' => $baseDir . '/src/Psalm/Internal/LanguageServer/ProtocolReader.php', 'Psalm\\Internal\\LanguageServer\\ProtocolStreamReader' => $baseDir . '/src/Psalm/Internal/LanguageServer/ProtocolStreamReader.php', 'Psalm\\Internal\\LanguageServer\\ProtocolStreamWriter' => $baseDir . '/src/Psalm/Internal/LanguageServer/ProtocolStreamWriter.php', 'Psalm\\Internal\\LanguageServer\\ProtocolWriter' => $baseDir . '/src/Psalm/Internal/LanguageServer/ProtocolWriter.php', 'Psalm\\Internal\\LanguageServer\\Provider\\ClassLikeStorageCacheProvider' => $baseDir . '/src/Psalm/Internal/LanguageServer/Provider/ClassLikeStorageCacheProvider.php', 'Psalm\\Internal\\LanguageServer\\Provider\\FileReferenceCacheProvider' => $baseDir . '/src/Psalm/Internal/LanguageServer/Provider/FileReferenceCacheProvider.php', 'Psalm\\Internal\\LanguageServer\\Provider\\FileStorageCacheProvider' => $baseDir . '/src/Psalm/Internal/LanguageServer/Provider/FileStorageCacheProvider.php', 'Psalm\\Internal\\LanguageServer\\Provider\\ParserCacheProvider' => $baseDir . '/src/Psalm/Internal/LanguageServer/Provider/ParserCacheProvider.php', 'Psalm\\Internal\\LanguageServer\\Provider\\ProjectCacheProvider' => $baseDir . '/src/Psalm/Internal/LanguageServer/Provider/ProjectCacheProvider.php', 'Psalm\\Internal\\LanguageServer\\Reference' => $baseDir . '/src/Psalm/Internal/LanguageServer/Reference.php', 'Psalm\\Internal\\LanguageServer\\Server\\TextDocument' => $baseDir . '/src/Psalm/Internal/LanguageServer/Server/TextDocument.php', 'Psalm\\Internal\\LanguageServer\\Server\\Workspace' => $baseDir . '/src/Psalm/Internal/LanguageServer/Server/Workspace.php', 'Psalm\\Internal\\MethodIdentifier' => $baseDir . '/src/Psalm/Internal/MethodIdentifier.php', 'Psalm\\Internal\\PhpTraverser\\CustomTraverser' => $baseDir . '/src/Psalm/Internal/PhpTraverser/CustomTraverser.php', 'Psalm\\Internal\\PhpVisitor\\AssignmentMapVisitor' => $baseDir . '/src/Psalm/Internal/PhpVisitor/AssignmentMapVisitor.php', 'Psalm\\Internal\\PhpVisitor\\CheckTrivialExprVisitor' => $baseDir . '/src/Psalm/Internal/PhpVisitor/CheckTrivialExprVisitor.php', 'Psalm\\Internal\\PhpVisitor\\CloningVisitor' => $baseDir . '/src/Psalm/Internal/PhpVisitor/CloningVisitor.php', 'Psalm\\Internal\\PhpVisitor\\ConditionCloningVisitor' => $baseDir . '/src/Psalm/Internal/PhpVisitor/ConditionCloningVisitor.php', 'Psalm\\Internal\\PhpVisitor\\NodeCleanerVisitor' => $baseDir . '/src/Psalm/Internal/PhpVisitor/NodeCleanerVisitor.php', 'Psalm\\Internal\\PhpVisitor\\NodeCounterVisitor' => $baseDir . '/src/Psalm/Internal/PhpVisitor/NodeCounterVisitor.php', 'Psalm\\Internal\\PhpVisitor\\OffsetShifterVisitor' => $baseDir . '/src/Psalm/Internal/PhpVisitor/OffsetShifterVisitor.php', 'Psalm\\Internal\\PhpVisitor\\ParamReplacementVisitor' => $baseDir . '/src/Psalm/Internal/PhpVisitor/ParamReplacementVisitor.php', 'Psalm\\Internal\\PhpVisitor\\PartialParserVisitor' => $baseDir . '/src/Psalm/Internal/PhpVisitor/PartialParserVisitor.php', 'Psalm\\Internal\\PhpVisitor\\ReflectorVisitor' => $baseDir . '/src/Psalm/Internal/PhpVisitor/ReflectorVisitor.php', 'Psalm\\Internal\\PhpVisitor\\Reflector\\AttributeResolver' => $baseDir . '/src/Psalm/Internal/PhpVisitor/Reflector/AttributeResolver.php', 'Psalm\\Internal\\PhpVisitor\\Reflector\\ClassLikeDocblockParser' => $baseDir . '/src/Psalm/Internal/PhpVisitor/Reflector/ClassLikeDocblockParser.php', 'Psalm\\Internal\\PhpVisitor\\Reflector\\ClassLikeNodeScanner' => $baseDir . '/src/Psalm/Internal/PhpVisitor/Reflector/ClassLikeNodeScanner.php', 'Psalm\\Internal\\PhpVisitor\\Reflector\\ExpressionResolver' => $baseDir . '/src/Psalm/Internal/PhpVisitor/Reflector/ExpressionResolver.php', 'Psalm\\Internal\\PhpVisitor\\Reflector\\ExpressionScanner' => $baseDir . '/src/Psalm/Internal/PhpVisitor/Reflector/ExpressionScanner.php', 'Psalm\\Internal\\PhpVisitor\\Reflector\\FunctionLikeDocblockParser' => $baseDir . '/src/Psalm/Internal/PhpVisitor/Reflector/FunctionLikeDocblockParser.php', 'Psalm\\Internal\\PhpVisitor\\Reflector\\FunctionLikeDocblockScanner' => $baseDir . '/src/Psalm/Internal/PhpVisitor/Reflector/FunctionLikeDocblockScanner.php', 'Psalm\\Internal\\PhpVisitor\\Reflector\\FunctionLikeNodeScanner' => $baseDir . '/src/Psalm/Internal/PhpVisitor/Reflector/FunctionLikeNodeScanner.php', 'Psalm\\Internal\\PhpVisitor\\Reflector\\TypeHintResolver' => $baseDir . '/src/Psalm/Internal/PhpVisitor/Reflector/TypeHintResolver.php', 'Psalm\\Internal\\PhpVisitor\\ShortClosureVisitor' => $baseDir . '/src/Psalm/Internal/PhpVisitor/ShortClosureVisitor.php', 'Psalm\\Internal\\PhpVisitor\\SimpleNameResolver' => $baseDir . '/src/Psalm/Internal/PhpVisitor/SimpleNameResolver.php', 'Psalm\\Internal\\PhpVisitor\\TraitFinder' => $baseDir . '/src/Psalm/Internal/PhpVisitor/TraitFinder.php', 'Psalm\\Internal\\PhpVisitor\\TypeMappingVisitor' => $baseDir . '/src/Psalm/Internal/PhpVisitor/TypeMappingVisitor.php', 'Psalm\\Internal\\PhpVisitor\\YieldTypeCollector' => $baseDir . '/src/Psalm/Internal/PhpVisitor/YieldTypeCollector.php', 'Psalm\\Internal\\PluginManager\\Command\\DisableCommand' => $baseDir . '/src/Psalm/Internal/PluginManager/Command/DisableCommand.php', 'Psalm\\Internal\\PluginManager\\Command\\EnableCommand' => $baseDir . '/src/Psalm/Internal/PluginManager/Command/EnableCommand.php', 'Psalm\\Internal\\PluginManager\\Command\\ShowCommand' => $baseDir . '/src/Psalm/Internal/PluginManager/Command/ShowCommand.php', 'Psalm\\Internal\\PluginManager\\ComposerLock' => $baseDir . '/src/Psalm/Internal/PluginManager/ComposerLock.php', 'Psalm\\Internal\\PluginManager\\ConfigFile' => $baseDir . '/src/Psalm/Internal/PluginManager/ConfigFile.php', 'Psalm\\Internal\\PluginManager\\PluginList' => $baseDir . '/src/Psalm/Internal/PluginManager/PluginList.php', 'Psalm\\Internal\\PluginManager\\PluginListFactory' => $baseDir . '/src/Psalm/Internal/PluginManager/PluginListFactory.php', 'Psalm\\Internal\\Provider\\AddRemoveTaints\\HtmlFunctionTainter' => $baseDir . '/src/Psalm/Internal/Provider/AddRemoveTaints/HtmlFunctionTainter.php', 'Psalm\\Internal\\Provider\\ClassLikeStorageCacheProvider' => $baseDir . '/src/Psalm/Internal/Provider/ClassLikeStorageCacheProvider.php', 'Psalm\\Internal\\Provider\\ClassLikeStorageProvider' => $baseDir . '/src/Psalm/Internal/Provider/ClassLikeStorageProvider.php', 'Psalm\\Internal\\Provider\\DynamicFunctionStorageProvider' => $baseDir . '/src/Psalm/Internal/Provider/DynamicFunctionStorageProvider.php', 'Psalm\\Internal\\Provider\\FakeFileProvider' => $baseDir . '/src/Psalm/Internal/Provider/FakeFileProvider.php', 'Psalm\\Internal\\Provider\\FileProvider' => $baseDir . '/src/Psalm/Internal/Provider/FileProvider.php', 'Psalm\\Internal\\Provider\\FileReferenceCacheProvider' => $baseDir . '/src/Psalm/Internal/Provider/FileReferenceCacheProvider.php', 'Psalm\\Internal\\Provider\\FileReferenceProvider' => $baseDir . '/src/Psalm/Internal/Provider/FileReferenceProvider.php', 'Psalm\\Internal\\Provider\\FileStorageCacheProvider' => $baseDir . '/src/Psalm/Internal/Provider/FileStorageCacheProvider.php', 'Psalm\\Internal\\Provider\\FileStorageProvider' => $baseDir . '/src/Psalm/Internal/Provider/FileStorageProvider.php', 'Psalm\\Internal\\Provider\\FunctionExistenceProvider' => $baseDir . '/src/Psalm/Internal/Provider/FunctionExistenceProvider.php', 'Psalm\\Internal\\Provider\\FunctionParamsProvider' => $baseDir . '/src/Psalm/Internal/Provider/FunctionParamsProvider.php', 'Psalm\\Internal\\Provider\\FunctionReturnTypeProvider' => $baseDir . '/src/Psalm/Internal/Provider/FunctionReturnTypeProvider.php', 'Psalm\\Internal\\Provider\\MethodExistenceProvider' => $baseDir . '/src/Psalm/Internal/Provider/MethodExistenceProvider.php', 'Psalm\\Internal\\Provider\\MethodParamsProvider' => $baseDir . '/src/Psalm/Internal/Provider/MethodParamsProvider.php', 'Psalm\\Internal\\Provider\\MethodReturnTypeProvider' => $baseDir . '/src/Psalm/Internal/Provider/MethodReturnTypeProvider.php', 'Psalm\\Internal\\Provider\\MethodVisibilityProvider' => $baseDir . '/src/Psalm/Internal/Provider/MethodVisibilityProvider.php', 'Psalm\\Internal\\Provider\\NodeDataProvider' => $baseDir . '/src/Psalm/Internal/Provider/NodeDataProvider.php', 'Psalm\\Internal\\Provider\\ParamsProvider\\ArrayFilterParamsProvider' => $baseDir . '/src/Psalm/Internal/Provider/ParamsProvider/ArrayFilterParamsProvider.php', 'Psalm\\Internal\\Provider\\ParamsProvider\\ArrayMultisortParamsProvider' => $baseDir . '/src/Psalm/Internal/Provider/ParamsProvider/ArrayMultisortParamsProvider.php', 'Psalm\\Internal\\Provider\\ParserCacheProvider' => $baseDir . '/src/Psalm/Internal/Provider/ParserCacheProvider.php', 'Psalm\\Internal\\Provider\\ProjectCacheProvider' => $baseDir . '/src/Psalm/Internal/Provider/ProjectCacheProvider.php', 'Psalm\\Internal\\Provider\\PropertyExistenceProvider' => $baseDir . '/src/Psalm/Internal/Provider/PropertyExistenceProvider.php', 'Psalm\\Internal\\Provider\\PropertyTypeProvider' => $baseDir . '/src/Psalm/Internal/Provider/PropertyTypeProvider.php', 'Psalm\\Internal\\Provider\\PropertyTypeProvider\\DomDocumentPropertyTypeProvider' => $baseDir . '/src/Psalm/Internal/Provider/PropertyTypeProvider/DomDocumentPropertyTypeProvider.php', 'Psalm\\Internal\\Provider\\PropertyVisibilityProvider' => $baseDir . '/src/Psalm/Internal/Provider/PropertyVisibilityProvider.php', 'Psalm\\Internal\\Provider\\Providers' => $baseDir . '/src/Psalm/Internal/Provider/Providers.php', 'Psalm\\Internal\\Provider\\ReturnTypeProvider\\ArrayChunkReturnTypeProvider' => $baseDir . '/src/Psalm/Internal/Provider/ReturnTypeProvider/ArrayChunkReturnTypeProvider.php', 'Psalm\\Internal\\Provider\\ReturnTypeProvider\\ArrayColumnReturnTypeProvider' => $baseDir . '/src/Psalm/Internal/Provider/ReturnTypeProvider/ArrayColumnReturnTypeProvider.php', 'Psalm\\Internal\\Provider\\ReturnTypeProvider\\ArrayCombineReturnTypeProvider' => $baseDir . '/src/Psalm/Internal/Provider/ReturnTypeProvider/ArrayCombineReturnTypeProvider.php', 'Psalm\\Internal\\Provider\\ReturnTypeProvider\\ArrayFillKeysReturnTypeProvider' => $baseDir . '/src/Psalm/Internal/Provider/ReturnTypeProvider/ArrayFillKeysReturnTypeProvider.php', 'Psalm\\Internal\\Provider\\ReturnTypeProvider\\ArrayFillReturnTypeProvider' => $baseDir . '/src/Psalm/Internal/Provider/ReturnTypeProvider/ArrayFillReturnTypeProvider.php', 'Psalm\\Internal\\Provider\\ReturnTypeProvider\\ArrayFilterReturnTypeProvider' => $baseDir . '/src/Psalm/Internal/Provider/ReturnTypeProvider/ArrayFilterReturnTypeProvider.php', 'Psalm\\Internal\\Provider\\ReturnTypeProvider\\ArrayMapReturnTypeProvider' => $baseDir . '/src/Psalm/Internal/Provider/ReturnTypeProvider/ArrayMapReturnTypeProvider.php', 'Psalm\\Internal\\Provider\\ReturnTypeProvider\\ArrayMergeReturnTypeProvider' => $baseDir . '/src/Psalm/Internal/Provider/ReturnTypeProvider/ArrayMergeReturnTypeProvider.php', 'Psalm\\Internal\\Provider\\ReturnTypeProvider\\ArrayPadReturnTypeProvider' => $baseDir . '/src/Psalm/Internal/Provider/ReturnTypeProvider/ArrayPadReturnTypeProvider.php', 'Psalm\\Internal\\Provider\\ReturnTypeProvider\\ArrayPointerAdjustmentReturnTypeProvider' => $baseDir . '/src/Psalm/Internal/Provider/ReturnTypeProvider/ArrayPointerAdjustmentReturnTypeProvider.php', 'Psalm\\Internal\\Provider\\ReturnTypeProvider\\ArrayPopReturnTypeProvider' => $baseDir . '/src/Psalm/Internal/Provider/ReturnTypeProvider/ArrayPopReturnTypeProvider.php', 'Psalm\\Internal\\Provider\\ReturnTypeProvider\\ArrayRandReturnTypeProvider' => $baseDir . '/src/Psalm/Internal/Provider/ReturnTypeProvider/ArrayRandReturnTypeProvider.php', 'Psalm\\Internal\\Provider\\ReturnTypeProvider\\ArrayReduceReturnTypeProvider' => $baseDir . '/src/Psalm/Internal/Provider/ReturnTypeProvider/ArrayReduceReturnTypeProvider.php', 'Psalm\\Internal\\Provider\\ReturnTypeProvider\\ArrayReverseReturnTypeProvider' => $baseDir . '/src/Psalm/Internal/Provider/ReturnTypeProvider/ArrayReverseReturnTypeProvider.php', 'Psalm\\Internal\\Provider\\ReturnTypeProvider\\ArraySliceReturnTypeProvider' => $baseDir . '/src/Psalm/Internal/Provider/ReturnTypeProvider/ArraySliceReturnTypeProvider.php', 'Psalm\\Internal\\Provider\\ReturnTypeProvider\\ArraySpliceReturnTypeProvider' => $baseDir . '/src/Psalm/Internal/Provider/ReturnTypeProvider/ArraySpliceReturnTypeProvider.php', 'Psalm\\Internal\\Provider\\ReturnTypeProvider\\BasenameReturnTypeProvider' => $baseDir . '/src/Psalm/Internal/Provider/ReturnTypeProvider/BasenameReturnTypeProvider.php', 'Psalm\\Internal\\Provider\\ReturnTypeProvider\\ClosureFromCallableReturnTypeProvider' => $baseDir . '/src/Psalm/Internal/Provider/ReturnTypeProvider/ClosureFromCallableReturnTypeProvider.php', 'Psalm\\Internal\\Provider\\ReturnTypeProvider\\DateReturnTypeProvider' => $baseDir . '/src/Psalm/Internal/Provider/ReturnTypeProvider/DateReturnTypeProvider.php', 'Psalm\\Internal\\Provider\\ReturnTypeProvider\\DateTimeModifyReturnTypeProvider' => $baseDir . '/src/Psalm/Internal/Provider/ReturnTypeProvider/DateTimeModifyReturnTypeProvider.php', 'Psalm\\Internal\\Provider\\ReturnTypeProvider\\DirnameReturnTypeProvider' => $baseDir . '/src/Psalm/Internal/Provider/ReturnTypeProvider/DirnameReturnTypeProvider.php', 'Psalm\\Internal\\Provider\\ReturnTypeProvider\\DomNodeAppendChild' => $baseDir . '/src/Psalm/Internal/Provider/ReturnTypeProvider/DomNodeAppendChild.php', 'Psalm\\Internal\\Provider\\ReturnTypeProvider\\FilterInputReturnTypeProvider' => $baseDir . '/src/Psalm/Internal/Provider/ReturnTypeProvider/FilterInputReturnTypeProvider.php', 'Psalm\\Internal\\Provider\\ReturnTypeProvider\\FilterUtils' => $baseDir . '/src/Psalm/Internal/Provider/ReturnTypeProvider/FilterUtils.php', 'Psalm\\Internal\\Provider\\ReturnTypeProvider\\FilterVarReturnTypeProvider' => $baseDir . '/src/Psalm/Internal/Provider/ReturnTypeProvider/FilterVarReturnTypeProvider.php', 'Psalm\\Internal\\Provider\\ReturnTypeProvider\\FirstArgStringReturnTypeProvider' => $baseDir . '/src/Psalm/Internal/Provider/ReturnTypeProvider/FirstArgStringReturnTypeProvider.php', 'Psalm\\Internal\\Provider\\ReturnTypeProvider\\GetClassMethodsReturnTypeProvider' => $baseDir . '/src/Psalm/Internal/Provider/ReturnTypeProvider/GetClassMethodsReturnTypeProvider.php', 'Psalm\\Internal\\Provider\\ReturnTypeProvider\\GetObjectVarsReturnTypeProvider' => $baseDir . '/src/Psalm/Internal/Provider/ReturnTypeProvider/GetObjectVarsReturnTypeProvider.php', 'Psalm\\Internal\\Provider\\ReturnTypeProvider\\HexdecReturnTypeProvider' => $baseDir . '/src/Psalm/Internal/Provider/ReturnTypeProvider/HexdecReturnTypeProvider.php', 'Psalm\\Internal\\Provider\\ReturnTypeProvider\\ImagickPixelColorReturnTypeProvider' => $baseDir . '/src/Psalm/Internal/Provider/ReturnTypeProvider/ImagickPixelColorReturnTypeProvider.php', 'Psalm\\Internal\\Provider\\ReturnTypeProvider\\InArrayReturnTypeProvider' => $baseDir . '/src/Psalm/Internal/Provider/ReturnTypeProvider/InArrayReturnTypeProvider.php', 'Psalm\\Internal\\Provider\\ReturnTypeProvider\\IteratorToArrayReturnTypeProvider' => $baseDir . '/src/Psalm/Internal/Provider/ReturnTypeProvider/IteratorToArrayReturnTypeProvider.php', 'Psalm\\Internal\\Provider\\ReturnTypeProvider\\MbInternalEncodingReturnTypeProvider' => $baseDir . '/src/Psalm/Internal/Provider/ReturnTypeProvider/MbInternalEncodingReturnTypeProvider.php', 'Psalm\\Internal\\Provider\\ReturnTypeProvider\\MinMaxReturnTypeProvider' => $baseDir . '/src/Psalm/Internal/Provider/ReturnTypeProvider/MinMaxReturnTypeProvider.php', 'Psalm\\Internal\\Provider\\ReturnTypeProvider\\MktimeReturnTypeProvider' => $baseDir . '/src/Psalm/Internal/Provider/ReturnTypeProvider/MktimeReturnTypeProvider.php', 'Psalm\\Internal\\Provider\\ReturnTypeProvider\\ParseUrlReturnTypeProvider' => $baseDir . '/src/Psalm/Internal/Provider/ReturnTypeProvider/ParseUrlReturnTypeProvider.php', 'Psalm\\Internal\\Provider\\ReturnTypeProvider\\PdoStatementReturnTypeProvider' => $baseDir . '/src/Psalm/Internal/Provider/ReturnTypeProvider/PdoStatementReturnTypeProvider.php', 'Psalm\\Internal\\Provider\\ReturnTypeProvider\\PdoStatementSetFetchMode' => $baseDir . '/src/Psalm/Internal/Provider/ReturnTypeProvider/PdoStatementSetFetchMode.php', 'Psalm\\Internal\\Provider\\ReturnTypeProvider\\PowReturnTypeProvider' => $baseDir . '/src/Psalm/Internal/Provider/ReturnTypeProvider/PowReturnTypeProvider.php', 'Psalm\\Internal\\Provider\\ReturnTypeProvider\\RandReturnTypeProvider' => $baseDir . '/src/Psalm/Internal/Provider/ReturnTypeProvider/RandReturnTypeProvider.php', 'Psalm\\Internal\\Provider\\ReturnTypeProvider\\RoundReturnTypeProvider' => $baseDir . '/src/Psalm/Internal/Provider/ReturnTypeProvider/RoundReturnTypeProvider.php', 'Psalm\\Internal\\Provider\\ReturnTypeProvider\\SprintfReturnTypeProvider' => $baseDir . '/src/Psalm/Internal/Provider/ReturnTypeProvider/SprintfReturnTypeProvider.php', 'Psalm\\Internal\\Provider\\ReturnTypeProvider\\StrReplaceReturnTypeProvider' => $baseDir . '/src/Psalm/Internal/Provider/ReturnTypeProvider/StrReplaceReturnTypeProvider.php', 'Psalm\\Internal\\Provider\\ReturnTypeProvider\\StrTrReturnTypeProvider' => $baseDir . '/src/Psalm/Internal/Provider/ReturnTypeProvider/StrTrReturnTypeProvider.php', 'Psalm\\Internal\\Provider\\ReturnTypeProvider\\TriggerErrorReturnTypeProvider' => $baseDir . '/src/Psalm/Internal/Provider/ReturnTypeProvider/TriggerErrorReturnTypeProvider.php', 'Psalm\\Internal\\Provider\\ReturnTypeProvider\\VersionCompareReturnTypeProvider' => $baseDir . '/src/Psalm/Internal/Provider/ReturnTypeProvider/VersionCompareReturnTypeProvider.php', 'Psalm\\Internal\\Provider\\StatementsProvider' => $baseDir . '/src/Psalm/Internal/Provider/StatementsProvider.php', 'Psalm\\Internal\\ReferenceConstraint' => $baseDir . '/src/Psalm/Internal/ReferenceConstraint.php', 'Psalm\\Internal\\RuntimeCaches' => $baseDir . '/src/Psalm/Internal/RuntimeCaches.php', 'Psalm\\Internal\\Scanner\\ClassLikeDocblockComment' => $baseDir . '/src/Psalm/Internal/Scanner/ClassLikeDocblockComment.php', 'Psalm\\Internal\\Scanner\\DocblockParser' => $baseDir . '/src/Psalm/Internal/Scanner/DocblockParser.php', 'Psalm\\Internal\\Scanner\\FileScanner' => $baseDir . '/src/Psalm/Internal/Scanner/FileScanner.php', 'Psalm\\Internal\\Scanner\\FunctionDocblockComment' => $baseDir . '/src/Psalm/Internal/Scanner/FunctionDocblockComment.php', 'Psalm\\Internal\\Scanner\\ParsedDocblock' => $baseDir . '/src/Psalm/Internal/Scanner/ParsedDocblock.php', 'Psalm\\Internal\\Scanner\\PhpStormMetaScanner' => $baseDir . '/src/Psalm/Internal/Scanner/PhpStormMetaScanner.php', 'Psalm\\Internal\\Scanner\\UnresolvedConstantComponent' => $baseDir . '/src/Psalm/Internal/Scanner/UnresolvedConstantComponent.php', 'Psalm\\Internal\\Scanner\\UnresolvedConstant\\ArrayOffsetFetch' => $baseDir . '/src/Psalm/Internal/Scanner/UnresolvedConstant/ArrayOffsetFetch.php', 'Psalm\\Internal\\Scanner\\UnresolvedConstant\\ArraySpread' => $baseDir . '/src/Psalm/Internal/Scanner/UnresolvedConstant/ArraySpread.php', 'Psalm\\Internal\\Scanner\\UnresolvedConstant\\ArrayValue' => $baseDir . '/src/Psalm/Internal/Scanner/UnresolvedConstant/ArrayValue.php', 'Psalm\\Internal\\Scanner\\UnresolvedConstant\\ClassConstant' => $baseDir . '/src/Psalm/Internal/Scanner/UnresolvedConstant/ClassConstant.php', 'Psalm\\Internal\\Scanner\\UnresolvedConstant\\Constant' => $baseDir . '/src/Psalm/Internal/Scanner/UnresolvedConstant/Constant.php', 'Psalm\\Internal\\Scanner\\UnresolvedConstant\\EnumNameFetch' => $baseDir . '/src/Psalm/Internal/Scanner/UnresolvedConstant/EnumNameFetch.php', 'Psalm\\Internal\\Scanner\\UnresolvedConstant\\EnumPropertyFetch' => $baseDir . '/src/Psalm/Internal/Scanner/UnresolvedConstant/EnumPropertyFetch.php', 'Psalm\\Internal\\Scanner\\UnresolvedConstant\\EnumValueFetch' => $baseDir . '/src/Psalm/Internal/Scanner/UnresolvedConstant/EnumValueFetch.php', 'Psalm\\Internal\\Scanner\\UnresolvedConstant\\KeyValuePair' => $baseDir . '/src/Psalm/Internal/Scanner/UnresolvedConstant/KeyValuePair.php', 'Psalm\\Internal\\Scanner\\UnresolvedConstant\\ScalarValue' => $baseDir . '/src/Psalm/Internal/Scanner/UnresolvedConstant/ScalarValue.php', 'Psalm\\Internal\\Scanner\\UnresolvedConstant\\UnresolvedAdditionOp' => $baseDir . '/src/Psalm/Internal/Scanner/UnresolvedConstant/UnresolvedAdditionOp.php', 'Psalm\\Internal\\Scanner\\UnresolvedConstant\\UnresolvedBinaryOp' => $baseDir . '/src/Psalm/Internal/Scanner/UnresolvedConstant/UnresolvedBinaryOp.php', 'Psalm\\Internal\\Scanner\\UnresolvedConstant\\UnresolvedBitwiseAnd' => $baseDir . '/src/Psalm/Internal/Scanner/UnresolvedConstant/UnresolvedBitwiseAnd.php', 'Psalm\\Internal\\Scanner\\UnresolvedConstant\\UnresolvedBitwiseOr' => $baseDir . '/src/Psalm/Internal/Scanner/UnresolvedConstant/UnresolvedBitwiseOr.php', 'Psalm\\Internal\\Scanner\\UnresolvedConstant\\UnresolvedBitwiseXor' => $baseDir . '/src/Psalm/Internal/Scanner/UnresolvedConstant/UnresolvedBitwiseXor.php', 'Psalm\\Internal\\Scanner\\UnresolvedConstant\\UnresolvedConcatOp' => $baseDir . '/src/Psalm/Internal/Scanner/UnresolvedConstant/UnresolvedConcatOp.php', 'Psalm\\Internal\\Scanner\\UnresolvedConstant\\UnresolvedDivisionOp' => $baseDir . '/src/Psalm/Internal/Scanner/UnresolvedConstant/UnresolvedDivisionOp.php', 'Psalm\\Internal\\Scanner\\UnresolvedConstant\\UnresolvedMultiplicationOp' => $baseDir . '/src/Psalm/Internal/Scanner/UnresolvedConstant/UnresolvedMultiplicationOp.php', 'Psalm\\Internal\\Scanner\\UnresolvedConstant\\UnresolvedSubtractionOp' => $baseDir . '/src/Psalm/Internal/Scanner/UnresolvedConstant/UnresolvedSubtractionOp.php', 'Psalm\\Internal\\Scanner\\UnresolvedConstant\\UnresolvedTernary' => $baseDir . '/src/Psalm/Internal/Scanner/UnresolvedConstant/UnresolvedTernary.php', 'Psalm\\Internal\\Scanner\\VarDocblockComment' => $baseDir . '/src/Psalm/Internal/Scanner/VarDocblockComment.php', 'Psalm\\Internal\\Scope\\CaseScope' => $baseDir . '/src/Psalm/Internal/Scope/CaseScope.php', 'Psalm\\Internal\\Scope\\FinallyScope' => $baseDir . '/src/Psalm/Internal/Scope/FinallyScope.php', 'Psalm\\Internal\\Scope\\IfConditionalScope' => $baseDir . '/src/Psalm/Internal/Scope/IfConditionalScope.php', 'Psalm\\Internal\\Scope\\IfScope' => $baseDir . '/src/Psalm/Internal/Scope/IfScope.php', 'Psalm\\Internal\\Scope\\LoopScope' => $baseDir . '/src/Psalm/Internal/Scope/LoopScope.php', 'Psalm\\Internal\\Scope\\SwitchScope' => $baseDir . '/src/Psalm/Internal/Scope/SwitchScope.php', 'Psalm\\Internal\\Stubs\\Generator\\ClassLikeStubGenerator' => $baseDir . '/src/Psalm/Internal/Stubs/Generator/ClassLikeStubGenerator.php', 'Psalm\\Internal\\Stubs\\Generator\\StubsGenerator' => $baseDir . '/src/Psalm/Internal/Stubs/Generator/StubsGenerator.php', 'Psalm\\Internal\\TypeVisitor\\CanContainObjectTypeVisitor' => $baseDir . '/src/Psalm/Internal/TypeVisitor/CanContainObjectTypeVisitor.php', 'Psalm\\Internal\\TypeVisitor\\ClasslikeReplacer' => $baseDir . '/src/Psalm/Internal/TypeVisitor/ClasslikeReplacer.php', 'Psalm\\Internal\\TypeVisitor\\ContainsClassLikeVisitor' => $baseDir . '/src/Psalm/Internal/TypeVisitor/ContainsClassLikeVisitor.php', 'Psalm\\Internal\\TypeVisitor\\ContainsLiteralVisitor' => $baseDir . '/src/Psalm/Internal/TypeVisitor/ContainsLiteralVisitor.php', 'Psalm\\Internal\\TypeVisitor\\ContainsStaticVisitor' => $baseDir . '/src/Psalm/Internal/TypeVisitor/ContainsStaticVisitor.php', 'Psalm\\Internal\\TypeVisitor\\FromDocblockSetter' => $baseDir . '/src/Psalm/Internal/TypeVisitor/FromDocblockSetter.php', 'Psalm\\Internal\\TypeVisitor\\TemplateTypeCollector' => $baseDir . '/src/Psalm/Internal/TypeVisitor/TemplateTypeCollector.php', 'Psalm\\Internal\\TypeVisitor\\TypeChecker' => $baseDir . '/src/Psalm/Internal/TypeVisitor/TypeChecker.php', 'Psalm\\Internal\\TypeVisitor\\TypeLocalizer' => $baseDir . '/src/Psalm/Internal/TypeVisitor/TypeLocalizer.php', 'Psalm\\Internal\\TypeVisitor\\TypeScanner' => $baseDir . '/src/Psalm/Internal/TypeVisitor/TypeScanner.php', 'Psalm\\Internal\\Type\\ArrayType' => $baseDir . '/src/Psalm/Internal/Type/ArrayType.php', 'Psalm\\Internal\\Type\\AssertionReconciler' => $baseDir . '/src/Psalm/Internal/Type/AssertionReconciler.php', 'Psalm\\Internal\\Type\\ClosedInheritanceToUnion' => $baseDir . '/src/Psalm/Internal/Type/ClosedInheritanceToUnion.php', 'Psalm\\Internal\\Type\\Comparator\\ArrayTypeComparator' => $baseDir . '/src/Psalm/Internal/Type/Comparator/ArrayTypeComparator.php', 'Psalm\\Internal\\Type\\Comparator\\AtomicTypeComparator' => $baseDir . '/src/Psalm/Internal/Type/Comparator/AtomicTypeComparator.php', 'Psalm\\Internal\\Type\\Comparator\\CallableTypeComparator' => $baseDir . '/src/Psalm/Internal/Type/Comparator/CallableTypeComparator.php', 'Psalm\\Internal\\Type\\Comparator\\ClassLikeStringComparator' => $baseDir . '/src/Psalm/Internal/Type/Comparator/ClassLikeStringComparator.php', 'Psalm\\Internal\\Type\\Comparator\\GenericTypeComparator' => $baseDir . '/src/Psalm/Internal/Type/Comparator/GenericTypeComparator.php', 'Psalm\\Internal\\Type\\Comparator\\IntegerRangeComparator' => $baseDir . '/src/Psalm/Internal/Type/Comparator/IntegerRangeComparator.php', 'Psalm\\Internal\\Type\\Comparator\\KeyedArrayComparator' => $baseDir . '/src/Psalm/Internal/Type/Comparator/KeyedArrayComparator.php', 'Psalm\\Internal\\Type\\Comparator\\ObjectComparator' => $baseDir . '/src/Psalm/Internal/Type/Comparator/ObjectComparator.php', 'Psalm\\Internal\\Type\\Comparator\\ScalarTypeComparator' => $baseDir . '/src/Psalm/Internal/Type/Comparator/ScalarTypeComparator.php', 'Psalm\\Internal\\Type\\Comparator\\TypeComparisonResult' => $baseDir . '/src/Psalm/Internal/Type/Comparator/TypeComparisonResult.php', 'Psalm\\Internal\\Type\\Comparator\\UnionTypeComparator' => $baseDir . '/src/Psalm/Internal/Type/Comparator/UnionTypeComparator.php', 'Psalm\\Internal\\Type\\NegatedAssertionReconciler' => $baseDir . '/src/Psalm/Internal/Type/NegatedAssertionReconciler.php', 'Psalm\\Internal\\Type\\ParseTree' => $baseDir . '/src/Psalm/Internal/Type/ParseTree.php', 'Psalm\\Internal\\Type\\ParseTreeCreator' => $baseDir . '/src/Psalm/Internal/Type/ParseTreeCreator.php', 'Psalm\\Internal\\Type\\ParseTree\\CallableParamTree' => $baseDir . '/src/Psalm/Internal/Type/ParseTree/CallableParamTree.php', 'Psalm\\Internal\\Type\\ParseTree\\CallableTree' => $baseDir . '/src/Psalm/Internal/Type/ParseTree/CallableTree.php', 'Psalm\\Internal\\Type\\ParseTree\\CallableWithReturnTypeTree' => $baseDir . '/src/Psalm/Internal/Type/ParseTree/CallableWithReturnTypeTree.php', 'Psalm\\Internal\\Type\\ParseTree\\ConditionalTree' => $baseDir . '/src/Psalm/Internal/Type/ParseTree/ConditionalTree.php', 'Psalm\\Internal\\Type\\ParseTree\\EncapsulationTree' => $baseDir . '/src/Psalm/Internal/Type/ParseTree/EncapsulationTree.php', 'Psalm\\Internal\\Type\\ParseTree\\FieldEllipsis' => $baseDir . '/src/Psalm/Internal/Type/ParseTree/FieldEllipsis.php', 'Psalm\\Internal\\Type\\ParseTree\\GenericTree' => $baseDir . '/src/Psalm/Internal/Type/ParseTree/GenericTree.php', 'Psalm\\Internal\\Type\\ParseTree\\IndexedAccessTree' => $baseDir . '/src/Psalm/Internal/Type/ParseTree/IndexedAccessTree.php', 'Psalm\\Internal\\Type\\ParseTree\\IntersectionTree' => $baseDir . '/src/Psalm/Internal/Type/ParseTree/IntersectionTree.php', 'Psalm\\Internal\\Type\\ParseTree\\KeyedArrayPropertyTree' => $baseDir . '/src/Psalm/Internal/Type/ParseTree/KeyedArrayPropertyTree.php', 'Psalm\\Internal\\Type\\ParseTree\\KeyedArrayTree' => $baseDir . '/src/Psalm/Internal/Type/ParseTree/KeyedArrayTree.php', 'Psalm\\Internal\\Type\\ParseTree\\MethodParamTree' => $baseDir . '/src/Psalm/Internal/Type/ParseTree/MethodParamTree.php', 'Psalm\\Internal\\Type\\ParseTree\\MethodTree' => $baseDir . '/src/Psalm/Internal/Type/ParseTree/MethodTree.php', 'Psalm\\Internal\\Type\\ParseTree\\MethodWithReturnTypeTree' => $baseDir . '/src/Psalm/Internal/Type/ParseTree/MethodWithReturnTypeTree.php', 'Psalm\\Internal\\Type\\ParseTree\\NullableTree' => $baseDir . '/src/Psalm/Internal/Type/ParseTree/NullableTree.php', 'Psalm\\Internal\\Type\\ParseTree\\Root' => $baseDir . '/src/Psalm/Internal/Type/ParseTree/Root.php', 'Psalm\\Internal\\Type\\ParseTree\\TemplateAsTree' => $baseDir . '/src/Psalm/Internal/Type/ParseTree/TemplateAsTree.php', 'Psalm\\Internal\\Type\\ParseTree\\TemplateIsTree' => $baseDir . '/src/Psalm/Internal/Type/ParseTree/TemplateIsTree.php', 'Psalm\\Internal\\Type\\ParseTree\\UnionTree' => $baseDir . '/src/Psalm/Internal/Type/ParseTree/UnionTree.php', 'Psalm\\Internal\\Type\\ParseTree\\Value' => $baseDir . '/src/Psalm/Internal/Type/ParseTree/Value.php', 'Psalm\\Internal\\Type\\SimpleAssertionReconciler' => $baseDir . '/src/Psalm/Internal/Type/SimpleAssertionReconciler.php', 'Psalm\\Internal\\Type\\SimpleNegatedAssertionReconciler' => $baseDir . '/src/Psalm/Internal/Type/SimpleNegatedAssertionReconciler.php', 'Psalm\\Internal\\Type\\TemplateBound' => $baseDir . '/src/Psalm/Internal/Type/TemplateBound.php', 'Psalm\\Internal\\Type\\TemplateInferredTypeReplacer' => $baseDir . '/src/Psalm/Internal/Type/TemplateInferredTypeReplacer.php', 'Psalm\\Internal\\Type\\TemplateResult' => $baseDir . '/src/Psalm/Internal/Type/TemplateResult.php', 'Psalm\\Internal\\Type\\TemplateStandinTypeReplacer' => $baseDir . '/src/Psalm/Internal/Type/TemplateStandinTypeReplacer.php', 'Psalm\\Internal\\Type\\TypeAlias' => $baseDir . '/src/Psalm/Internal/Type/TypeAlias.php', 'Psalm\\Internal\\Type\\TypeAlias\\ClassTypeAlias' => $baseDir . '/src/Psalm/Internal/Type/TypeAlias/ClassTypeAlias.php', 'Psalm\\Internal\\Type\\TypeAlias\\InlineTypeAlias' => $baseDir . '/src/Psalm/Internal/Type/TypeAlias/InlineTypeAlias.php', 'Psalm\\Internal\\Type\\TypeAlias\\LinkableTypeAlias' => $baseDir . '/src/Psalm/Internal/Type/TypeAlias/LinkableTypeAlias.php', 'Psalm\\Internal\\Type\\TypeCombination' => $baseDir . '/src/Psalm/Internal/Type/TypeCombination.php', 'Psalm\\Internal\\Type\\TypeCombiner' => $baseDir . '/src/Psalm/Internal/Type/TypeCombiner.php', 'Psalm\\Internal\\Type\\TypeExpander' => $baseDir . '/src/Psalm/Internal/Type/TypeExpander.php', 'Psalm\\Internal\\Type\\TypeParser' => $baseDir . '/src/Psalm/Internal/Type/TypeParser.php', 'Psalm\\Internal\\Type\\TypeTokenizer' => $baseDir . '/src/Psalm/Internal/Type/TypeTokenizer.php', 'Psalm\\Internal\\VersionUtils' => $baseDir . '/src/Psalm/Internal/VersionUtils.php', 'Psalm\\IssueBuffer' => $baseDir . '/src/Psalm/IssueBuffer.php', 'Psalm\\Issue\\AbstractInstantiation' => $baseDir . '/src/Psalm/Issue/AbstractInstantiation.php', 'Psalm\\Issue\\AbstractMethodCall' => $baseDir . '/src/Psalm/Issue/AbstractMethodCall.php', 'Psalm\\Issue\\AmbiguousConstantInheritance' => $baseDir . '/src/Psalm/Issue/AmbiguousConstantInheritance.php', 'Psalm\\Issue\\ArgumentIssue' => $baseDir . '/src/Psalm/Issue/ArgumentIssue.php', 'Psalm\\Issue\\ArgumentTypeCoercion' => $baseDir . '/src/Psalm/Issue/ArgumentTypeCoercion.php', 'Psalm\\Issue\\AssignmentToVoid' => $baseDir . '/src/Psalm/Issue/AssignmentToVoid.php', 'Psalm\\Issue\\CheckType' => $baseDir . '/src/Psalm/Issue/CheckType.php', 'Psalm\\Issue\\CircularReference' => $baseDir . '/src/Psalm/Issue/CircularReference.php', 'Psalm\\Issue\\ClassConstantIssue' => $baseDir . '/src/Psalm/Issue/ClassConstantIssue.php', 'Psalm\\Issue\\ClassIssue' => $baseDir . '/src/Psalm/Issue/ClassIssue.php', 'Psalm\\Issue\\CodeIssue' => $baseDir . '/src/Psalm/Issue/CodeIssue.php', 'Psalm\\Issue\\ComplexFunction' => $baseDir . '/src/Psalm/Issue/ComplexFunction.php', 'Psalm\\Issue\\ComplexMethod' => $baseDir . '/src/Psalm/Issue/ComplexMethod.php', 'Psalm\\Issue\\ConfigIssue' => $baseDir . '/src/Psalm/Issue/ConfigIssue.php', 'Psalm\\Issue\\ConflictingReferenceConstraint' => $baseDir . '/src/Psalm/Issue/ConflictingReferenceConstraint.php', 'Psalm\\Issue\\ConstantDeclarationInTrait' => $baseDir . '/src/Psalm/Issue/ConstantDeclarationInTrait.php', 'Psalm\\Issue\\ConstructorSignatureMismatch' => $baseDir . '/src/Psalm/Issue/ConstructorSignatureMismatch.php', 'Psalm\\Issue\\ContinueOutsideLoop' => $baseDir . '/src/Psalm/Issue/ContinueOutsideLoop.php', 'Psalm\\Issue\\DeprecatedClass' => $baseDir . '/src/Psalm/Issue/DeprecatedClass.php', 'Psalm\\Issue\\DeprecatedConstant' => $baseDir . '/src/Psalm/Issue/DeprecatedConstant.php', 'Psalm\\Issue\\DeprecatedFunction' => $baseDir . '/src/Psalm/Issue/DeprecatedFunction.php', 'Psalm\\Issue\\DeprecatedInterface' => $baseDir . '/src/Psalm/Issue/DeprecatedInterface.php', 'Psalm\\Issue\\DeprecatedMethod' => $baseDir . '/src/Psalm/Issue/DeprecatedMethod.php', 'Psalm\\Issue\\DeprecatedProperty' => $baseDir . '/src/Psalm/Issue/DeprecatedProperty.php', 'Psalm\\Issue\\DeprecatedTrait' => $baseDir . '/src/Psalm/Issue/DeprecatedTrait.php', 'Psalm\\Issue\\DirectConstructorCall' => $baseDir . '/src/Psalm/Issue/DirectConstructorCall.php', 'Psalm\\Issue\\DocblockTypeContradiction' => $baseDir . '/src/Psalm/Issue/DocblockTypeContradiction.php', 'Psalm\\Issue\\DuplicateArrayKey' => $baseDir . '/src/Psalm/Issue/DuplicateArrayKey.php', 'Psalm\\Issue\\DuplicateClass' => $baseDir . '/src/Psalm/Issue/DuplicateClass.php', 'Psalm\\Issue\\DuplicateConstant' => $baseDir . '/src/Psalm/Issue/DuplicateConstant.php', 'Psalm\\Issue\\DuplicateEnumCase' => $baseDir . '/src/Psalm/Issue/DuplicateEnumCase.php', 'Psalm\\Issue\\DuplicateEnumCaseValue' => $baseDir . '/src/Psalm/Issue/DuplicateEnumCaseValue.php', 'Psalm\\Issue\\DuplicateFunction' => $baseDir . '/src/Psalm/Issue/DuplicateFunction.php', 'Psalm\\Issue\\DuplicateMethod' => $baseDir . '/src/Psalm/Issue/DuplicateMethod.php', 'Psalm\\Issue\\DuplicateParam' => $baseDir . '/src/Psalm/Issue/DuplicateParam.php', 'Psalm\\Issue\\EmptyArrayAccess' => $baseDir . '/src/Psalm/Issue/EmptyArrayAccess.php', 'Psalm\\Issue\\ExtensionRequirementViolation' => $baseDir . '/src/Psalm/Issue/ExtensionRequirementViolation.php', 'Psalm\\Issue\\FalsableReturnStatement' => $baseDir . '/src/Psalm/Issue/FalsableReturnStatement.php', 'Psalm\\Issue\\FalseOperand' => $baseDir . '/src/Psalm/Issue/FalseOperand.php', 'Psalm\\Issue\\ForbiddenCode' => $baseDir . '/src/Psalm/Issue/ForbiddenCode.php', 'Psalm\\Issue\\FunctionIssue' => $baseDir . '/src/Psalm/Issue/FunctionIssue.php', 'Psalm\\Issue\\IfThisIsMismatch' => $baseDir . '/src/Psalm/Issue/IfThisIsMismatch.php', 'Psalm\\Issue\\ImplementationRequirementViolation' => $baseDir . '/src/Psalm/Issue/ImplementationRequirementViolation.php', 'Psalm\\Issue\\ImplementedParamTypeMismatch' => $baseDir . '/src/Psalm/Issue/ImplementedParamTypeMismatch.php', 'Psalm\\Issue\\ImplementedReturnTypeMismatch' => $baseDir . '/src/Psalm/Issue/ImplementedReturnTypeMismatch.php', 'Psalm\\Issue\\ImplicitToStringCast' => $baseDir . '/src/Psalm/Issue/ImplicitToStringCast.php', 'Psalm\\Issue\\ImpureByReferenceAssignment' => $baseDir . '/src/Psalm/Issue/ImpureByReferenceAssignment.php', 'Psalm\\Issue\\ImpureFunctionCall' => $baseDir . '/src/Psalm/Issue/ImpureFunctionCall.php', 'Psalm\\Issue\\ImpureMethodCall' => $baseDir . '/src/Psalm/Issue/ImpureMethodCall.php', 'Psalm\\Issue\\ImpurePropertyAssignment' => $baseDir . '/src/Psalm/Issue/ImpurePropertyAssignment.php', 'Psalm\\Issue\\ImpurePropertyFetch' => $baseDir . '/src/Psalm/Issue/ImpurePropertyFetch.php', 'Psalm\\Issue\\ImpureStaticProperty' => $baseDir . '/src/Psalm/Issue/ImpureStaticProperty.php', 'Psalm\\Issue\\ImpureStaticVariable' => $baseDir . '/src/Psalm/Issue/ImpureStaticVariable.php', 'Psalm\\Issue\\ImpureVariable' => $baseDir . '/src/Psalm/Issue/ImpureVariable.php', 'Psalm\\Issue\\InaccessibleClassConstant' => $baseDir . '/src/Psalm/Issue/InaccessibleClassConstant.php', 'Psalm\\Issue\\InaccessibleMethod' => $baseDir . '/src/Psalm/Issue/InaccessibleMethod.php', 'Psalm\\Issue\\InaccessibleProperty' => $baseDir . '/src/Psalm/Issue/InaccessibleProperty.php', 'Psalm\\Issue\\InheritorViolation' => $baseDir . '/src/Psalm/Issue/InheritorViolation.php', 'Psalm\\Issue\\InterfaceInstantiation' => $baseDir . '/src/Psalm/Issue/InterfaceInstantiation.php', 'Psalm\\Issue\\InternalClass' => $baseDir . '/src/Psalm/Issue/InternalClass.php', 'Psalm\\Issue\\InternalMethod' => $baseDir . '/src/Psalm/Issue/InternalMethod.php', 'Psalm\\Issue\\InternalProperty' => $baseDir . '/src/Psalm/Issue/InternalProperty.php', 'Psalm\\Issue\\InvalidArgument' => $baseDir . '/src/Psalm/Issue/InvalidArgument.php', 'Psalm\\Issue\\InvalidArrayAccess' => $baseDir . '/src/Psalm/Issue/InvalidArrayAccess.php', 'Psalm\\Issue\\InvalidArrayAssignment' => $baseDir . '/src/Psalm/Issue/InvalidArrayAssignment.php', 'Psalm\\Issue\\InvalidArrayOffset' => $baseDir . '/src/Psalm/Issue/InvalidArrayOffset.php', 'Psalm\\Issue\\InvalidAttribute' => $baseDir . '/src/Psalm/Issue/InvalidAttribute.php', 'Psalm\\Issue\\InvalidCast' => $baseDir . '/src/Psalm/Issue/InvalidCast.php', 'Psalm\\Issue\\InvalidCatch' => $baseDir . '/src/Psalm/Issue/InvalidCatch.php', 'Psalm\\Issue\\InvalidClass' => $baseDir . '/src/Psalm/Issue/InvalidClass.php', 'Psalm\\Issue\\InvalidClassConstantType' => $baseDir . '/src/Psalm/Issue/InvalidClassConstantType.php', 'Psalm\\Issue\\InvalidClone' => $baseDir . '/src/Psalm/Issue/InvalidClone.php', 'Psalm\\Issue\\InvalidConstantAssignmentValue' => $baseDir . '/src/Psalm/Issue/InvalidConstantAssignmentValue.php', 'Psalm\\Issue\\InvalidDocblock' => $baseDir . '/src/Psalm/Issue/InvalidDocblock.php', 'Psalm\\Issue\\InvalidDocblockParamName' => $baseDir . '/src/Psalm/Issue/InvalidDocblockParamName.php', 'Psalm\\Issue\\InvalidEnumBackingType' => $baseDir . '/src/Psalm/Issue/InvalidEnumBackingType.php', 'Psalm\\Issue\\InvalidEnumCaseValue' => $baseDir . '/src/Psalm/Issue/InvalidEnumCaseValue.php', 'Psalm\\Issue\\InvalidEnumMethod' => $baseDir . '/src/Psalm/Issue/InvalidEnumMethod.php', 'Psalm\\Issue\\InvalidExtendClass' => $baseDir . '/src/Psalm/Issue/InvalidExtendClass.php', 'Psalm\\Issue\\InvalidFalsableReturnType' => $baseDir . '/src/Psalm/Issue/InvalidFalsableReturnType.php', 'Psalm\\Issue\\InvalidFunctionCall' => $baseDir . '/src/Psalm/Issue/InvalidFunctionCall.php', 'Psalm\\Issue\\InvalidGlobal' => $baseDir . '/src/Psalm/Issue/InvalidGlobal.php', 'Psalm\\Issue\\InvalidInterfaceImplementation' => $baseDir . '/src/Psalm/Issue/InvalidInterfaceImplementation.php', 'Psalm\\Issue\\InvalidIterator' => $baseDir . '/src/Psalm/Issue/InvalidIterator.php', 'Psalm\\Issue\\InvalidLiteralArgument' => $baseDir . '/src/Psalm/Issue/InvalidLiteralArgument.php', 'Psalm\\Issue\\InvalidMethodCall' => $baseDir . '/src/Psalm/Issue/InvalidMethodCall.php', 'Psalm\\Issue\\InvalidNamedArgument' => $baseDir . '/src/Psalm/Issue/InvalidNamedArgument.php', 'Psalm\\Issue\\InvalidNullableReturnType' => $baseDir . '/src/Psalm/Issue/InvalidNullableReturnType.php', 'Psalm\\Issue\\InvalidOperand' => $baseDir . '/src/Psalm/Issue/InvalidOperand.php', 'Psalm\\Issue\\InvalidOverride' => $baseDir . '/src/Psalm/Issue/InvalidOverride.php', 'Psalm\\Issue\\InvalidParamDefault' => $baseDir . '/src/Psalm/Issue/InvalidParamDefault.php', 'Psalm\\Issue\\InvalidParent' => $baseDir . '/src/Psalm/Issue/InvalidParent.php', 'Psalm\\Issue\\InvalidPassByReference' => $baseDir . '/src/Psalm/Issue/InvalidPassByReference.php', 'Psalm\\Issue\\InvalidPropertyAssignment' => $baseDir . '/src/Psalm/Issue/InvalidPropertyAssignment.php', 'Psalm\\Issue\\InvalidPropertyAssignmentValue' => $baseDir . '/src/Psalm/Issue/InvalidPropertyAssignmentValue.php', 'Psalm\\Issue\\InvalidPropertyFetch' => $baseDir . '/src/Psalm/Issue/InvalidPropertyFetch.php', 'Psalm\\Issue\\InvalidReturnStatement' => $baseDir . '/src/Psalm/Issue/InvalidReturnStatement.php', 'Psalm\\Issue\\InvalidReturnType' => $baseDir . '/src/Psalm/Issue/InvalidReturnType.php', 'Psalm\\Issue\\InvalidScalarArgument' => $baseDir . '/src/Psalm/Issue/InvalidScalarArgument.php', 'Psalm\\Issue\\InvalidScope' => $baseDir . '/src/Psalm/Issue/InvalidScope.php', 'Psalm\\Issue\\InvalidStaticInvocation' => $baseDir . '/src/Psalm/Issue/InvalidStaticInvocation.php', 'Psalm\\Issue\\InvalidStringClass' => $baseDir . '/src/Psalm/Issue/InvalidStringClass.php', 'Psalm\\Issue\\InvalidTemplateParam' => $baseDir . '/src/Psalm/Issue/InvalidTemplateParam.php', 'Psalm\\Issue\\InvalidThrow' => $baseDir . '/src/Psalm/Issue/InvalidThrow.php', 'Psalm\\Issue\\InvalidToString' => $baseDir . '/src/Psalm/Issue/InvalidToString.php', 'Psalm\\Issue\\InvalidTraversableImplementation' => $baseDir . '/src/Psalm/Issue/InvalidTraversableImplementation.php', 'Psalm\\Issue\\InvalidTypeImport' => $baseDir . '/src/Psalm/Issue/InvalidTypeImport.php', 'Psalm\\Issue\\LessSpecificClassConstantType' => $baseDir . '/src/Psalm/Issue/LessSpecificClassConstantType.php', 'Psalm\\Issue\\LessSpecificImplementedReturnType' => $baseDir . '/src/Psalm/Issue/LessSpecificImplementedReturnType.php', 'Psalm\\Issue\\LessSpecificReturnStatement' => $baseDir . '/src/Psalm/Issue/LessSpecificReturnStatement.php', 'Psalm\\Issue\\LessSpecificReturnType' => $baseDir . '/src/Psalm/Issue/LessSpecificReturnType.php', 'Psalm\\Issue\\LoopInvalidation' => $baseDir . '/src/Psalm/Issue/LoopInvalidation.php', 'Psalm\\Issue\\MethodIssue' => $baseDir . '/src/Psalm/Issue/MethodIssue.php', 'Psalm\\Issue\\MethodSignatureMismatch' => $baseDir . '/src/Psalm/Issue/MethodSignatureMismatch.php', 'Psalm\\Issue\\MethodSignatureMustOmitReturnType' => $baseDir . '/src/Psalm/Issue/MethodSignatureMustOmitReturnType.php', 'Psalm\\Issue\\MethodSignatureMustProvideReturnType' => $baseDir . '/src/Psalm/Issue/MethodSignatureMustProvideReturnType.php', 'Psalm\\Issue\\MismatchingDocblockParamType' => $baseDir . '/src/Psalm/Issue/MismatchingDocblockParamType.php', 'Psalm\\Issue\\MismatchingDocblockPropertyType' => $baseDir . '/src/Psalm/Issue/MismatchingDocblockPropertyType.php', 'Psalm\\Issue\\MismatchingDocblockReturnType' => $baseDir . '/src/Psalm/Issue/MismatchingDocblockReturnType.php', 'Psalm\\Issue\\MissingClassConstType' => $baseDir . '/src/Psalm/Issue/MissingClassConstType.php', 'Psalm\\Issue\\MissingClosureParamType' => $baseDir . '/src/Psalm/Issue/MissingClosureParamType.php', 'Psalm\\Issue\\MissingClosureReturnType' => $baseDir . '/src/Psalm/Issue/MissingClosureReturnType.php', 'Psalm\\Issue\\MissingConstructor' => $baseDir . '/src/Psalm/Issue/MissingConstructor.php', 'Psalm\\Issue\\MissingDependency' => $baseDir . '/src/Psalm/Issue/MissingDependency.php', 'Psalm\\Issue\\MissingDocblockType' => $baseDir . '/src/Psalm/Issue/MissingDocblockType.php', 'Psalm\\Issue\\MissingFile' => $baseDir . '/src/Psalm/Issue/MissingFile.php', 'Psalm\\Issue\\MissingImmutableAnnotation' => $baseDir . '/src/Psalm/Issue/MissingImmutableAnnotation.php', 'Psalm\\Issue\\MissingOverrideAttribute' => $baseDir . '/src/Psalm/Issue/MissingOverrideAttribute.php', 'Psalm\\Issue\\MissingParamType' => $baseDir . '/src/Psalm/Issue/MissingParamType.php', 'Psalm\\Issue\\MissingPropertyType' => $baseDir . '/src/Psalm/Issue/MissingPropertyType.php', 'Psalm\\Issue\\MissingReturnType' => $baseDir . '/src/Psalm/Issue/MissingReturnType.php', 'Psalm\\Issue\\MissingTemplateParam' => $baseDir . '/src/Psalm/Issue/MissingTemplateParam.php', 'Psalm\\Issue\\MissingThrowsDocblock' => $baseDir . '/src/Psalm/Issue/MissingThrowsDocblock.php', 'Psalm\\Issue\\MixedArgument' => $baseDir . '/src/Psalm/Issue/MixedArgument.php', 'Psalm\\Issue\\MixedArgumentTypeCoercion' => $baseDir . '/src/Psalm/Issue/MixedArgumentTypeCoercion.php', 'Psalm\\Issue\\MixedArrayAccess' => $baseDir . '/src/Psalm/Issue/MixedArrayAccess.php', 'Psalm\\Issue\\MixedArrayAssignment' => $baseDir . '/src/Psalm/Issue/MixedArrayAssignment.php', 'Psalm\\Issue\\MixedArrayOffset' => $baseDir . '/src/Psalm/Issue/MixedArrayOffset.php', 'Psalm\\Issue\\MixedArrayTypeCoercion' => $baseDir . '/src/Psalm/Issue/MixedArrayTypeCoercion.php', 'Psalm\\Issue\\MixedAssignment' => $baseDir . '/src/Psalm/Issue/MixedAssignment.php', 'Psalm\\Issue\\MixedClone' => $baseDir . '/src/Psalm/Issue/MixedClone.php', 'Psalm\\Issue\\MixedFunctionCall' => $baseDir . '/src/Psalm/Issue/MixedFunctionCall.php', 'Psalm\\Issue\\MixedInferredReturnType' => $baseDir . '/src/Psalm/Issue/MixedInferredReturnType.php', 'Psalm\\Issue\\MixedIssue' => $baseDir . '/src/Psalm/Issue/MixedIssue.php', 'Psalm\\Issue\\MixedIssueTrait' => $baseDir . '/src/Psalm/Issue/MixedIssueTrait.php', 'Psalm\\Issue\\MixedMethodCall' => $baseDir . '/src/Psalm/Issue/MixedMethodCall.php', 'Psalm\\Issue\\MixedOperand' => $baseDir . '/src/Psalm/Issue/MixedOperand.php', 'Psalm\\Issue\\MixedPropertyAssignment' => $baseDir . '/src/Psalm/Issue/MixedPropertyAssignment.php', 'Psalm\\Issue\\MixedPropertyFetch' => $baseDir . '/src/Psalm/Issue/MixedPropertyFetch.php', 'Psalm\\Issue\\MixedPropertyTypeCoercion' => $baseDir . '/src/Psalm/Issue/MixedPropertyTypeCoercion.php', 'Psalm\\Issue\\MixedReturnStatement' => $baseDir . '/src/Psalm/Issue/MixedReturnStatement.php', 'Psalm\\Issue\\MixedReturnTypeCoercion' => $baseDir . '/src/Psalm/Issue/MixedReturnTypeCoercion.php', 'Psalm\\Issue\\MixedStringOffsetAssignment' => $baseDir . '/src/Psalm/Issue/MixedStringOffsetAssignment.php', 'Psalm\\Issue\\MoreSpecificImplementedParamType' => $baseDir . '/src/Psalm/Issue/MoreSpecificImplementedParamType.php', 'Psalm\\Issue\\MoreSpecificReturnType' => $baseDir . '/src/Psalm/Issue/MoreSpecificReturnType.php', 'Psalm\\Issue\\MutableDependency' => $baseDir . '/src/Psalm/Issue/MutableDependency.php', 'Psalm\\Issue\\NamedArgumentNotAllowed' => $baseDir . '/src/Psalm/Issue/NamedArgumentNotAllowed.php', 'Psalm\\Issue\\NoEnumProperties' => $baseDir . '/src/Psalm/Issue/NoEnumProperties.php', 'Psalm\\Issue\\NoInterfaceProperties' => $baseDir . '/src/Psalm/Issue/NoInterfaceProperties.php', 'Psalm\\Issue\\NoValue' => $baseDir . '/src/Psalm/Issue/NoValue.php', 'Psalm\\Issue\\NonInvariantDocblockPropertyType' => $baseDir . '/src/Psalm/Issue/NonInvariantDocblockPropertyType.php', 'Psalm\\Issue\\NonInvariantPropertyType' => $baseDir . '/src/Psalm/Issue/NonInvariantPropertyType.php', 'Psalm\\Issue\\NonStaticSelfCall' => $baseDir . '/src/Psalm/Issue/NonStaticSelfCall.php', 'Psalm\\Issue\\NullArgument' => $baseDir . '/src/Psalm/Issue/NullArgument.php', 'Psalm\\Issue\\NullArrayAccess' => $baseDir . '/src/Psalm/Issue/NullArrayAccess.php', 'Psalm\\Issue\\NullArrayOffset' => $baseDir . '/src/Psalm/Issue/NullArrayOffset.php', 'Psalm\\Issue\\NullFunctionCall' => $baseDir . '/src/Psalm/Issue/NullFunctionCall.php', 'Psalm\\Issue\\NullIterator' => $baseDir . '/src/Psalm/Issue/NullIterator.php', 'Psalm\\Issue\\NullOperand' => $baseDir . '/src/Psalm/Issue/NullOperand.php', 'Psalm\\Issue\\NullPropertyAssignment' => $baseDir . '/src/Psalm/Issue/NullPropertyAssignment.php', 'Psalm\\Issue\\NullPropertyFetch' => $baseDir . '/src/Psalm/Issue/NullPropertyFetch.php', 'Psalm\\Issue\\NullReference' => $baseDir . '/src/Psalm/Issue/NullReference.php', 'Psalm\\Issue\\NullableReturnStatement' => $baseDir . '/src/Psalm/Issue/NullableReturnStatement.php', 'Psalm\\Issue\\OverriddenFinalConstant' => $baseDir . '/src/Psalm/Issue/OverriddenFinalConstant.php', 'Psalm\\Issue\\OverriddenInterfaceConstant' => $baseDir . '/src/Psalm/Issue/OverriddenInterfaceConstant.php', 'Psalm\\Issue\\OverriddenMethodAccess' => $baseDir . '/src/Psalm/Issue/OverriddenMethodAccess.php', 'Psalm\\Issue\\OverriddenPropertyAccess' => $baseDir . '/src/Psalm/Issue/OverriddenPropertyAccess.php', 'Psalm\\Issue\\ParadoxicalCondition' => $baseDir . '/src/Psalm/Issue/ParadoxicalCondition.php', 'Psalm\\Issue\\ParamNameMismatch' => $baseDir . '/src/Psalm/Issue/ParamNameMismatch.php', 'Psalm\\Issue\\ParentNotFound' => $baseDir . '/src/Psalm/Issue/ParentNotFound.php', 'Psalm\\Issue\\ParseError' => $baseDir . '/src/Psalm/Issue/ParseError.php', 'Psalm\\Issue\\PluginIssue' => $baseDir . '/src/Psalm/Issue/PluginIssue.php', 'Psalm\\Issue\\PossibleRawObjectIteration' => $baseDir . '/src/Psalm/Issue/PossibleRawObjectIteration.php', 'Psalm\\Issue\\PossiblyFalseArgument' => $baseDir . '/src/Psalm/Issue/PossiblyFalseArgument.php', 'Psalm\\Issue\\PossiblyFalseIterator' => $baseDir . '/src/Psalm/Issue/PossiblyFalseIterator.php', 'Psalm\\Issue\\PossiblyFalseOperand' => $baseDir . '/src/Psalm/Issue/PossiblyFalseOperand.php', 'Psalm\\Issue\\PossiblyFalsePropertyAssignmentValue' => $baseDir . '/src/Psalm/Issue/PossiblyFalsePropertyAssignmentValue.php', 'Psalm\\Issue\\PossiblyFalseReference' => $baseDir . '/src/Psalm/Issue/PossiblyFalseReference.php', 'Psalm\\Issue\\PossiblyInvalidArgument' => $baseDir . '/src/Psalm/Issue/PossiblyInvalidArgument.php', 'Psalm\\Issue\\PossiblyInvalidArrayAccess' => $baseDir . '/src/Psalm/Issue/PossiblyInvalidArrayAccess.php', 'Psalm\\Issue\\PossiblyInvalidArrayAssignment' => $baseDir . '/src/Psalm/Issue/PossiblyInvalidArrayAssignment.php', 'Psalm\\Issue\\PossiblyInvalidArrayOffset' => $baseDir . '/src/Psalm/Issue/PossiblyInvalidArrayOffset.php', 'Psalm\\Issue\\PossiblyInvalidCast' => $baseDir . '/src/Psalm/Issue/PossiblyInvalidCast.php', 'Psalm\\Issue\\PossiblyInvalidClone' => $baseDir . '/src/Psalm/Issue/PossiblyInvalidClone.php', 'Psalm\\Issue\\PossiblyInvalidDocblockTag' => $baseDir . '/src/Psalm/Issue/PossiblyInvalidDocblockTag.php', 'Psalm\\Issue\\PossiblyInvalidFunctionCall' => $baseDir . '/src/Psalm/Issue/PossiblyInvalidFunctionCall.php', 'Psalm\\Issue\\PossiblyInvalidIterator' => $baseDir . '/src/Psalm/Issue/PossiblyInvalidIterator.php', 'Psalm\\Issue\\PossiblyInvalidMethodCall' => $baseDir . '/src/Psalm/Issue/PossiblyInvalidMethodCall.php', 'Psalm\\Issue\\PossiblyInvalidOperand' => $baseDir . '/src/Psalm/Issue/PossiblyInvalidOperand.php', 'Psalm\\Issue\\PossiblyInvalidPropertyAssignment' => $baseDir . '/src/Psalm/Issue/PossiblyInvalidPropertyAssignment.php', 'Psalm\\Issue\\PossiblyInvalidPropertyAssignmentValue' => $baseDir . '/src/Psalm/Issue/PossiblyInvalidPropertyAssignmentValue.php', 'Psalm\\Issue\\PossiblyInvalidPropertyFetch' => $baseDir . '/src/Psalm/Issue/PossiblyInvalidPropertyFetch.php', 'Psalm\\Issue\\PossiblyNullArgument' => $baseDir . '/src/Psalm/Issue/PossiblyNullArgument.php', 'Psalm\\Issue\\PossiblyNullArrayAccess' => $baseDir . '/src/Psalm/Issue/PossiblyNullArrayAccess.php', 'Psalm\\Issue\\PossiblyNullArrayAssignment' => $baseDir . '/src/Psalm/Issue/PossiblyNullArrayAssignment.php', 'Psalm\\Issue\\PossiblyNullArrayOffset' => $baseDir . '/src/Psalm/Issue/PossiblyNullArrayOffset.php', 'Psalm\\Issue\\PossiblyNullFunctionCall' => $baseDir . '/src/Psalm/Issue/PossiblyNullFunctionCall.php', 'Psalm\\Issue\\PossiblyNullIterator' => $baseDir . '/src/Psalm/Issue/PossiblyNullIterator.php', 'Psalm\\Issue\\PossiblyNullOperand' => $baseDir . '/src/Psalm/Issue/PossiblyNullOperand.php', 'Psalm\\Issue\\PossiblyNullPropertyAssignment' => $baseDir . '/src/Psalm/Issue/PossiblyNullPropertyAssignment.php', 'Psalm\\Issue\\PossiblyNullPropertyAssignmentValue' => $baseDir . '/src/Psalm/Issue/PossiblyNullPropertyAssignmentValue.php', 'Psalm\\Issue\\PossiblyNullPropertyFetch' => $baseDir . '/src/Psalm/Issue/PossiblyNullPropertyFetch.php', 'Psalm\\Issue\\PossiblyNullReference' => $baseDir . '/src/Psalm/Issue/PossiblyNullReference.php', 'Psalm\\Issue\\PossiblyUndefinedArrayOffset' => $baseDir . '/src/Psalm/Issue/PossiblyUndefinedArrayOffset.php', 'Psalm\\Issue\\PossiblyUndefinedGlobalVariable' => $baseDir . '/src/Psalm/Issue/PossiblyUndefinedGlobalVariable.php', 'Psalm\\Issue\\PossiblyUndefinedIntArrayOffset' => $baseDir . '/src/Psalm/Issue/PossiblyUndefinedIntArrayOffset.php', 'Psalm\\Issue\\PossiblyUndefinedMethod' => $baseDir . '/src/Psalm/Issue/PossiblyUndefinedMethod.php', 'Psalm\\Issue\\PossiblyUndefinedStringArrayOffset' => $baseDir . '/src/Psalm/Issue/PossiblyUndefinedStringArrayOffset.php', 'Psalm\\Issue\\PossiblyUndefinedVariable' => $baseDir . '/src/Psalm/Issue/PossiblyUndefinedVariable.php', 'Psalm\\Issue\\PossiblyUnusedMethod' => $baseDir . '/src/Psalm/Issue/PossiblyUnusedMethod.php', 'Psalm\\Issue\\PossiblyUnusedParam' => $baseDir . '/src/Psalm/Issue/PossiblyUnusedParam.php', 'Psalm\\Issue\\PossiblyUnusedProperty' => $baseDir . '/src/Psalm/Issue/PossiblyUnusedProperty.php', 'Psalm\\Issue\\PossiblyUnusedReturnValue' => $baseDir . '/src/Psalm/Issue/PossiblyUnusedReturnValue.php', 'Psalm\\Issue\\PrivateFinalMethod' => $baseDir . '/src/Psalm/Issue/PrivateFinalMethod.php', 'Psalm\\Issue\\PropertyIssue' => $baseDir . '/src/Psalm/Issue/PropertyIssue.php', 'Psalm\\Issue\\PropertyNotSetInConstructor' => $baseDir . '/src/Psalm/Issue/PropertyNotSetInConstructor.php', 'Psalm\\Issue\\PropertyTypeCoercion' => $baseDir . '/src/Psalm/Issue/PropertyTypeCoercion.php', 'Psalm\\Issue\\PsalmInternalError' => $baseDir . '/src/Psalm/Issue/PsalmInternalError.php', 'Psalm\\Issue\\RawObjectIteration' => $baseDir . '/src/Psalm/Issue/RawObjectIteration.php', 'Psalm\\Issue\\RedundantCast' => $baseDir . '/src/Psalm/Issue/RedundantCast.php', 'Psalm\\Issue\\RedundantCastGivenDocblockType' => $baseDir . '/src/Psalm/Issue/RedundantCastGivenDocblockType.php', 'Psalm\\Issue\\RedundantCondition' => $baseDir . '/src/Psalm/Issue/RedundantCondition.php', 'Psalm\\Issue\\RedundantConditionGivenDocblockType' => $baseDir . '/src/Psalm/Issue/RedundantConditionGivenDocblockType.php', 'Psalm\\Issue\\RedundantFlag' => $baseDir . '/src/Psalm/Issue/RedundantFlag.php', 'Psalm\\Issue\\RedundantFunctionCall' => $baseDir . '/src/Psalm/Issue/RedundantFunctionCall.php', 'Psalm\\Issue\\RedundantFunctionCallGivenDocblockType' => $baseDir . '/src/Psalm/Issue/RedundantFunctionCallGivenDocblockType.php', 'Psalm\\Issue\\RedundantIdentityWithTrue' => $baseDir . '/src/Psalm/Issue/RedundantIdentityWithTrue.php', 'Psalm\\Issue\\RedundantPropertyInitializationCheck' => $baseDir . '/src/Psalm/Issue/RedundantPropertyInitializationCheck.php', 'Psalm\\Issue\\ReferenceConstraintViolation' => $baseDir . '/src/Psalm/Issue/ReferenceConstraintViolation.php', 'Psalm\\Issue\\ReferenceReusedFromConfusingScope' => $baseDir . '/src/Psalm/Issue/ReferenceReusedFromConfusingScope.php', 'Psalm\\Issue\\ReservedWord' => $baseDir . '/src/Psalm/Issue/ReservedWord.php', 'Psalm\\Issue\\RiskyCast' => $baseDir . '/src/Psalm/Issue/RiskyCast.php', 'Psalm\\Issue\\RiskyTruthyFalsyComparison' => $baseDir . '/src/Psalm/Issue/RiskyTruthyFalsyComparison.php', 'Psalm\\Issue\\StringIncrement' => $baseDir . '/src/Psalm/Issue/StringIncrement.php', 'Psalm\\Issue\\TaintedCallable' => $baseDir . '/src/Psalm/Issue/TaintedCallable.php', 'Psalm\\Issue\\TaintedCookie' => $baseDir . '/src/Psalm/Issue/TaintedCookie.php', 'Psalm\\Issue\\TaintedCustom' => $baseDir . '/src/Psalm/Issue/TaintedCustom.php', 'Psalm\\Issue\\TaintedEval' => $baseDir . '/src/Psalm/Issue/TaintedEval.php', 'Psalm\\Issue\\TaintedFile' => $baseDir . '/src/Psalm/Issue/TaintedFile.php', 'Psalm\\Issue\\TaintedHeader' => $baseDir . '/src/Psalm/Issue/TaintedHeader.php', 'Psalm\\Issue\\TaintedHtml' => $baseDir . '/src/Psalm/Issue/TaintedHtml.php', 'Psalm\\Issue\\TaintedInclude' => $baseDir . '/src/Psalm/Issue/TaintedInclude.php', 'Psalm\\Issue\\TaintedInput' => $baseDir . '/src/Psalm/Issue/TaintedInput.php', 'Psalm\\Issue\\TaintedLdap' => $baseDir . '/src/Psalm/Issue/TaintedLdap.php', 'Psalm\\Issue\\TaintedSSRF' => $baseDir . '/src/Psalm/Issue/TaintedSSRF.php', 'Psalm\\Issue\\TaintedShell' => $baseDir . '/src/Psalm/Issue/TaintedShell.php', 'Psalm\\Issue\\TaintedSql' => $baseDir . '/src/Psalm/Issue/TaintedSql.php', 'Psalm\\Issue\\TaintedSystemSecret' => $baseDir . '/src/Psalm/Issue/TaintedSystemSecret.php', 'Psalm\\Issue\\TaintedTextWithQuotes' => $baseDir . '/src/Psalm/Issue/TaintedTextWithQuotes.php', 'Psalm\\Issue\\TaintedUnserialize' => $baseDir . '/src/Psalm/Issue/TaintedUnserialize.php', 'Psalm\\Issue\\TaintedUserSecret' => $baseDir . '/src/Psalm/Issue/TaintedUserSecret.php', 'Psalm\\Issue\\TooFewArguments' => $baseDir . '/src/Psalm/Issue/TooFewArguments.php', 'Psalm\\Issue\\TooManyArguments' => $baseDir . '/src/Psalm/Issue/TooManyArguments.php', 'Psalm\\Issue\\TooManyTemplateParams' => $baseDir . '/src/Psalm/Issue/TooManyTemplateParams.php', 'Psalm\\Issue\\Trace' => $baseDir . '/src/Psalm/Issue/Trace.php', 'Psalm\\Issue\\TraitMethodSignatureMismatch' => $baseDir . '/src/Psalm/Issue/TraitMethodSignatureMismatch.php', 'Psalm\\Issue\\TypeDoesNotContainNull' => $baseDir . '/src/Psalm/Issue/TypeDoesNotContainNull.php', 'Psalm\\Issue\\TypeDoesNotContainType' => $baseDir . '/src/Psalm/Issue/TypeDoesNotContainType.php', 'Psalm\\Issue\\UncaughtThrowInGlobalScope' => $baseDir . '/src/Psalm/Issue/UncaughtThrowInGlobalScope.php', 'Psalm\\Issue\\UndefinedAttributeClass' => $baseDir . '/src/Psalm/Issue/UndefinedAttributeClass.php', 'Psalm\\Issue\\UndefinedClass' => $baseDir . '/src/Psalm/Issue/UndefinedClass.php', 'Psalm\\Issue\\UndefinedConstant' => $baseDir . '/src/Psalm/Issue/UndefinedConstant.php', 'Psalm\\Issue\\UndefinedDocblockClass' => $baseDir . '/src/Psalm/Issue/UndefinedDocblockClass.php', 'Psalm\\Issue\\UndefinedFunction' => $baseDir . '/src/Psalm/Issue/UndefinedFunction.php', 'Psalm\\Issue\\UndefinedGlobalVariable' => $baseDir . '/src/Psalm/Issue/UndefinedGlobalVariable.php', 'Psalm\\Issue\\UndefinedInterface' => $baseDir . '/src/Psalm/Issue/UndefinedInterface.php', 'Psalm\\Issue\\UndefinedInterfaceMethod' => $baseDir . '/src/Psalm/Issue/UndefinedInterfaceMethod.php', 'Psalm\\Issue\\UndefinedMagicMethod' => $baseDir . '/src/Psalm/Issue/UndefinedMagicMethod.php', 'Psalm\\Issue\\UndefinedMagicPropertyAssignment' => $baseDir . '/src/Psalm/Issue/UndefinedMagicPropertyAssignment.php', 'Psalm\\Issue\\UndefinedMagicPropertyFetch' => $baseDir . '/src/Psalm/Issue/UndefinedMagicPropertyFetch.php', 'Psalm\\Issue\\UndefinedMethod' => $baseDir . '/src/Psalm/Issue/UndefinedMethod.php', 'Psalm\\Issue\\UndefinedPropertyAssignment' => $baseDir . '/src/Psalm/Issue/UndefinedPropertyAssignment.php', 'Psalm\\Issue\\UndefinedPropertyFetch' => $baseDir . '/src/Psalm/Issue/UndefinedPropertyFetch.php', 'Psalm\\Issue\\UndefinedThisPropertyAssignment' => $baseDir . '/src/Psalm/Issue/UndefinedThisPropertyAssignment.php', 'Psalm\\Issue\\UndefinedThisPropertyFetch' => $baseDir . '/src/Psalm/Issue/UndefinedThisPropertyFetch.php', 'Psalm\\Issue\\UndefinedTrace' => $baseDir . '/src/Psalm/Issue/UndefinedTrace.php', 'Psalm\\Issue\\UndefinedTrait' => $baseDir . '/src/Psalm/Issue/UndefinedTrait.php', 'Psalm\\Issue\\UndefinedVariable' => $baseDir . '/src/Psalm/Issue/UndefinedVariable.php', 'Psalm\\Issue\\UnevaluatedCode' => $baseDir . '/src/Psalm/Issue/UnevaluatedCode.php', 'Psalm\\Issue\\UnhandledMatchCondition' => $baseDir . '/src/Psalm/Issue/UnhandledMatchCondition.php', 'Psalm\\Issue\\UnimplementedAbstractMethod' => $baseDir . '/src/Psalm/Issue/UnimplementedAbstractMethod.php', 'Psalm\\Issue\\UnimplementedInterfaceMethod' => $baseDir . '/src/Psalm/Issue/UnimplementedInterfaceMethod.php', 'Psalm\\Issue\\UninitializedProperty' => $baseDir . '/src/Psalm/Issue/UninitializedProperty.php', 'Psalm\\Issue\\UnnecessaryVarAnnotation' => $baseDir . '/src/Psalm/Issue/UnnecessaryVarAnnotation.php', 'Psalm\\Issue\\UnrecognizedExpression' => $baseDir . '/src/Psalm/Issue/UnrecognizedExpression.php', 'Psalm\\Issue\\UnrecognizedStatement' => $baseDir . '/src/Psalm/Issue/UnrecognizedStatement.php', 'Psalm\\Issue\\UnresolvableConstant' => $baseDir . '/src/Psalm/Issue/UnresolvableConstant.php', 'Psalm\\Issue\\UnresolvableInclude' => $baseDir . '/src/Psalm/Issue/UnresolvableInclude.php', 'Psalm\\Issue\\UnsafeGenericInstantiation' => $baseDir . '/src/Psalm/Issue/UnsafeGenericInstantiation.php', 'Psalm\\Issue\\UnsafeInstantiation' => $baseDir . '/src/Psalm/Issue/UnsafeInstantiation.php', 'Psalm\\Issue\\UnsupportedPropertyReferenceUsage' => $baseDir . '/src/Psalm/Issue/UnsupportedPropertyReferenceUsage.php', 'Psalm\\Issue\\UnsupportedReferenceUsage' => $baseDir . '/src/Psalm/Issue/UnsupportedReferenceUsage.php', 'Psalm\\Issue\\UnusedBaselineEntry' => $baseDir . '/src/Psalm/Issue/UnusedBaselineEntry.php', 'Psalm\\Issue\\UnusedClass' => $baseDir . '/src/Psalm/Issue/UnusedClass.php', 'Psalm\\Issue\\UnusedClosureParam' => $baseDir . '/src/Psalm/Issue/UnusedClosureParam.php', 'Psalm\\Issue\\UnusedConstructor' => $baseDir . '/src/Psalm/Issue/UnusedConstructor.php', 'Psalm\\Issue\\UnusedDocblockParam' => $baseDir . '/src/Psalm/Issue/UnusedDocblockParam.php', 'Psalm\\Issue\\UnusedForeachValue' => $baseDir . '/src/Psalm/Issue/UnusedForeachValue.php', 'Psalm\\Issue\\UnusedFunctionCall' => $baseDir . '/src/Psalm/Issue/UnusedFunctionCall.php', 'Psalm\\Issue\\UnusedMethod' => $baseDir . '/src/Psalm/Issue/UnusedMethod.php', 'Psalm\\Issue\\UnusedMethodCall' => $baseDir . '/src/Psalm/Issue/UnusedMethodCall.php', 'Psalm\\Issue\\UnusedParam' => $baseDir . '/src/Psalm/Issue/UnusedParam.php', 'Psalm\\Issue\\UnusedProperty' => $baseDir . '/src/Psalm/Issue/UnusedProperty.php', 'Psalm\\Issue\\UnusedPsalmSuppress' => $baseDir . '/src/Psalm/Issue/UnusedPsalmSuppress.php', 'Psalm\\Issue\\UnusedReturnValue' => $baseDir . '/src/Psalm/Issue/UnusedReturnValue.php', 'Psalm\\Issue\\UnusedVariable' => $baseDir . '/src/Psalm/Issue/UnusedVariable.php', 'Psalm\\Issue\\VariableIssue' => $baseDir . '/src/Psalm/Issue/VariableIssue.php', 'Psalm\\NodeTypeProvider' => $baseDir . '/src/Psalm/NodeTypeProvider.php', 'Psalm\\Node\\Expr\\AssignOp\\VirtualBitwiseAnd' => $baseDir . '/src/Psalm/Node/Expr/AssignOp/VirtualBitwiseAnd.php', 'Psalm\\Node\\Expr\\AssignOp\\VirtualBitwiseOr' => $baseDir . '/src/Psalm/Node/Expr/AssignOp/VirtualBitwiseOr.php', 'Psalm\\Node\\Expr\\AssignOp\\VirtualBitwiseXor' => $baseDir . '/src/Psalm/Node/Expr/AssignOp/VirtualBitwiseXor.php', 'Psalm\\Node\\Expr\\AssignOp\\VirtualCoalesce' => $baseDir . '/src/Psalm/Node/Expr/AssignOp/VirtualCoalesce.php', 'Psalm\\Node\\Expr\\AssignOp\\VirtualConcat' => $baseDir . '/src/Psalm/Node/Expr/AssignOp/VirtualConcat.php', 'Psalm\\Node\\Expr\\AssignOp\\VirtualDiv' => $baseDir . '/src/Psalm/Node/Expr/AssignOp/VirtualDiv.php', 'Psalm\\Node\\Expr\\AssignOp\\VirtualMinus' => $baseDir . '/src/Psalm/Node/Expr/AssignOp/VirtualMinus.php', 'Psalm\\Node\\Expr\\AssignOp\\VirtualMod' => $baseDir . '/src/Psalm/Node/Expr/AssignOp/VirtualMod.php', 'Psalm\\Node\\Expr\\AssignOp\\VirtualMul' => $baseDir . '/src/Psalm/Node/Expr/AssignOp/VirtualMul.php', 'Psalm\\Node\\Expr\\AssignOp\\VirtualPlus' => $baseDir . '/src/Psalm/Node/Expr/AssignOp/VirtualPlus.php', 'Psalm\\Node\\Expr\\AssignOp\\VirtualPow' => $baseDir . '/src/Psalm/Node/Expr/AssignOp/VirtualPow.php', 'Psalm\\Node\\Expr\\AssignOp\\VirtualShiftLeft' => $baseDir . '/src/Psalm/Node/Expr/AssignOp/VirtualShiftLeft.php', 'Psalm\\Node\\Expr\\AssignOp\\VirtualShiftRight' => $baseDir . '/src/Psalm/Node/Expr/AssignOp/VirtualShiftRight.php', 'Psalm\\Node\\Expr\\BinaryOp\\VirtualBitwiseAnd' => $baseDir . '/src/Psalm/Node/Expr/BinaryOp/VirtualBitwiseAnd.php', 'Psalm\\Node\\Expr\\BinaryOp\\VirtualBitwiseOr' => $baseDir . '/src/Psalm/Node/Expr/BinaryOp/VirtualBitwiseOr.php', 'Psalm\\Node\\Expr\\BinaryOp\\VirtualBitwiseXor' => $baseDir . '/src/Psalm/Node/Expr/BinaryOp/VirtualBitwiseXor.php', 'Psalm\\Node\\Expr\\BinaryOp\\VirtualBooleanAnd' => $baseDir . '/src/Psalm/Node/Expr/BinaryOp/VirtualBooleanAnd.php', 'Psalm\\Node\\Expr\\BinaryOp\\VirtualBooleanOr' => $baseDir . '/src/Psalm/Node/Expr/BinaryOp/VirtualBooleanOr.php', 'Psalm\\Node\\Expr\\BinaryOp\\VirtualCoalesce' => $baseDir . '/src/Psalm/Node/Expr/BinaryOp/VirtualCoalesce.php', 'Psalm\\Node\\Expr\\BinaryOp\\VirtualConcat' => $baseDir . '/src/Psalm/Node/Expr/BinaryOp/VirtualConcat.php', 'Psalm\\Node\\Expr\\BinaryOp\\VirtualDiv' => $baseDir . '/src/Psalm/Node/Expr/BinaryOp/VirtualDiv.php', 'Psalm\\Node\\Expr\\BinaryOp\\VirtualEqual' => $baseDir . '/src/Psalm/Node/Expr/BinaryOp/VirtualEqual.php', 'Psalm\\Node\\Expr\\BinaryOp\\VirtualGreater' => $baseDir . '/src/Psalm/Node/Expr/BinaryOp/VirtualGreater.php', 'Psalm\\Node\\Expr\\BinaryOp\\VirtualGreaterOrEqual' => $baseDir . '/src/Psalm/Node/Expr/BinaryOp/VirtualGreaterOrEqual.php', 'Psalm\\Node\\Expr\\BinaryOp\\VirtualIdentical' => $baseDir . '/src/Psalm/Node/Expr/BinaryOp/VirtualIdentical.php', 'Psalm\\Node\\Expr\\BinaryOp\\VirtualLogicalAnd' => $baseDir . '/src/Psalm/Node/Expr/BinaryOp/VirtualLogicalAnd.php', 'Psalm\\Node\\Expr\\BinaryOp\\VirtualLogicalOr' => $baseDir . '/src/Psalm/Node/Expr/BinaryOp/VirtualLogicalOr.php', 'Psalm\\Node\\Expr\\BinaryOp\\VirtualLogicalXor' => $baseDir . '/src/Psalm/Node/Expr/BinaryOp/VirtualLogicalXor.php', 'Psalm\\Node\\Expr\\BinaryOp\\VirtualMinus' => $baseDir . '/src/Psalm/Node/Expr/BinaryOp/VirtualMinus.php', 'Psalm\\Node\\Expr\\BinaryOp\\VirtualMod' => $baseDir . '/src/Psalm/Node/Expr/BinaryOp/VirtualMod.php', 'Psalm\\Node\\Expr\\BinaryOp\\VirtualMul' => $baseDir . '/src/Psalm/Node/Expr/BinaryOp/VirtualMul.php', 'Psalm\\Node\\Expr\\BinaryOp\\VirtualNotEqual' => $baseDir . '/src/Psalm/Node/Expr/BinaryOp/VirtualNotEqual.php', 'Psalm\\Node\\Expr\\BinaryOp\\VirtualNotIdentical' => $baseDir . '/src/Psalm/Node/Expr/BinaryOp/VirtualNotIdentical.php', 'Psalm\\Node\\Expr\\BinaryOp\\VirtualPlus' => $baseDir . '/src/Psalm/Node/Expr/BinaryOp/VirtualPlus.php', 'Psalm\\Node\\Expr\\BinaryOp\\VirtualPow' => $baseDir . '/src/Psalm/Node/Expr/BinaryOp/VirtualPow.php', 'Psalm\\Node\\Expr\\BinaryOp\\VirtualShiftLeft' => $baseDir . '/src/Psalm/Node/Expr/BinaryOp/VirtualShiftLeft.php', 'Psalm\\Node\\Expr\\BinaryOp\\VirtualShiftRight' => $baseDir . '/src/Psalm/Node/Expr/BinaryOp/VirtualShiftRight.php', 'Psalm\\Node\\Expr\\BinaryOp\\VirtualSmaller' => $baseDir . '/src/Psalm/Node/Expr/BinaryOp/VirtualSmaller.php', 'Psalm\\Node\\Expr\\BinaryOp\\VirtualSmallerOrEqual' => $baseDir . '/src/Psalm/Node/Expr/BinaryOp/VirtualSmallerOrEqual.php', 'Psalm\\Node\\Expr\\BinaryOp\\VirtualSpaceship' => $baseDir . '/src/Psalm/Node/Expr/BinaryOp/VirtualSpaceship.php', 'Psalm\\Node\\Expr\\Cast\\VirtualArray' => $baseDir . '/src/Psalm/Node/Expr/Cast/VirtualArray.php', 'Psalm\\Node\\Expr\\Cast\\VirtualBool' => $baseDir . '/src/Psalm/Node/Expr/Cast/VirtualBool.php', 'Psalm\\Node\\Expr\\Cast\\VirtualDouble' => $baseDir . '/src/Psalm/Node/Expr/Cast/VirtualDouble.php', 'Psalm\\Node\\Expr\\Cast\\VirtualInt' => $baseDir . '/src/Psalm/Node/Expr/Cast/VirtualInt.php', 'Psalm\\Node\\Expr\\Cast\\VirtualObject' => $baseDir . '/src/Psalm/Node/Expr/Cast/VirtualObject.php', 'Psalm\\Node\\Expr\\Cast\\VirtualString' => $baseDir . '/src/Psalm/Node/Expr/Cast/VirtualString.php', 'Psalm\\Node\\Expr\\Cast\\VirtualUnset' => $baseDir . '/src/Psalm/Node/Expr/Cast/VirtualUnset.php', 'Psalm\\Node\\Expr\\VirtualArray' => $baseDir . '/src/Psalm/Node/Expr/VirtualArray.php', 'Psalm\\Node\\Expr\\VirtualArrayDimFetch' => $baseDir . '/src/Psalm/Node/Expr/VirtualArrayDimFetch.php', 'Psalm\\Node\\Expr\\VirtualArrayItem' => $baseDir . '/src/Psalm/Node/Expr/VirtualArrayItem.php', 'Psalm\\Node\\Expr\\VirtualArrowFunction' => $baseDir . '/src/Psalm/Node/Expr/VirtualArrowFunction.php', 'Psalm\\Node\\Expr\\VirtualAssign' => $baseDir . '/src/Psalm/Node/Expr/VirtualAssign.php', 'Psalm\\Node\\Expr\\VirtualAssignRef' => $baseDir . '/src/Psalm/Node/Expr/VirtualAssignRef.php', 'Psalm\\Node\\Expr\\VirtualBitwiseNot' => $baseDir . '/src/Psalm/Node/Expr/VirtualBitwiseNot.php', 'Psalm\\Node\\Expr\\VirtualBooleanNot' => $baseDir . '/src/Psalm/Node/Expr/VirtualBooleanNot.php', 'Psalm\\Node\\Expr\\VirtualClassConstFetch' => $baseDir . '/src/Psalm/Node/Expr/VirtualClassConstFetch.php', 'Psalm\\Node\\Expr\\VirtualClone' => $baseDir . '/src/Psalm/Node/Expr/VirtualClone.php', 'Psalm\\Node\\Expr\\VirtualClosure' => $baseDir . '/src/Psalm/Node/Expr/VirtualClosure.php', 'Psalm\\Node\\Expr\\VirtualClosureUse' => $baseDir . '/src/Psalm/Node/Expr/VirtualClosureUse.php', 'Psalm\\Node\\Expr\\VirtualConstFetch' => $baseDir . '/src/Psalm/Node/Expr/VirtualConstFetch.php', 'Psalm\\Node\\Expr\\VirtualEmpty' => $baseDir . '/src/Psalm/Node/Expr/VirtualEmpty.php', 'Psalm\\Node\\Expr\\VirtualError' => $baseDir . '/src/Psalm/Node/Expr/VirtualError.php', 'Psalm\\Node\\Expr\\VirtualErrorSuppress' => $baseDir . '/src/Psalm/Node/Expr/VirtualErrorSuppress.php', 'Psalm\\Node\\Expr\\VirtualEval' => $baseDir . '/src/Psalm/Node/Expr/VirtualEval.php', 'Psalm\\Node\\Expr\\VirtualExit' => $baseDir . '/src/Psalm/Node/Expr/VirtualExit.php', 'Psalm\\Node\\Expr\\VirtualFuncCall' => $baseDir . '/src/Psalm/Node/Expr/VirtualFuncCall.php', 'Psalm\\Node\\Expr\\VirtualInclude' => $baseDir . '/src/Psalm/Node/Expr/VirtualInclude.php', 'Psalm\\Node\\Expr\\VirtualInstanceof' => $baseDir . '/src/Psalm/Node/Expr/VirtualInstanceof.php', 'Psalm\\Node\\Expr\\VirtualIsset' => $baseDir . '/src/Psalm/Node/Expr/VirtualIsset.php', 'Psalm\\Node\\Expr\\VirtualList' => $baseDir . '/src/Psalm/Node/Expr/VirtualList.php', 'Psalm\\Node\\Expr\\VirtualMatch' => $baseDir . '/src/Psalm/Node/Expr/VirtualMatch.php', 'Psalm\\Node\\Expr\\VirtualMethodCall' => $baseDir . '/src/Psalm/Node/Expr/VirtualMethodCall.php', 'Psalm\\Node\\Expr\\VirtualNew' => $baseDir . '/src/Psalm/Node/Expr/VirtualNew.php', 'Psalm\\Node\\Expr\\VirtualNullsafeMethodCall' => $baseDir . '/src/Psalm/Node/Expr/VirtualNullsafeMethodCall.php', 'Psalm\\Node\\Expr\\VirtualNullsafePropertyFetch' => $baseDir . '/src/Psalm/Node/Expr/VirtualNullsafePropertyFetch.php', 'Psalm\\Node\\Expr\\VirtualPostDec' => $baseDir . '/src/Psalm/Node/Expr/VirtualPostDec.php', 'Psalm\\Node\\Expr\\VirtualPostInc' => $baseDir . '/src/Psalm/Node/Expr/VirtualPostInc.php', 'Psalm\\Node\\Expr\\VirtualPreDec' => $baseDir . '/src/Psalm/Node/Expr/VirtualPreDec.php', 'Psalm\\Node\\Expr\\VirtualPreInc' => $baseDir . '/src/Psalm/Node/Expr/VirtualPreInc.php', 'Psalm\\Node\\Expr\\VirtualPrint' => $baseDir . '/src/Psalm/Node/Expr/VirtualPrint.php', 'Psalm\\Node\\Expr\\VirtualPropertyFetch' => $baseDir . '/src/Psalm/Node/Expr/VirtualPropertyFetch.php', 'Psalm\\Node\\Expr\\VirtualShellExec' => $baseDir . '/src/Psalm/Node/Expr/VirtualShellExec.php', 'Psalm\\Node\\Expr\\VirtualStaticCall' => $baseDir . '/src/Psalm/Node/Expr/VirtualStaticCall.php', 'Psalm\\Node\\Expr\\VirtualStaticPropertyFetch' => $baseDir . '/src/Psalm/Node/Expr/VirtualStaticPropertyFetch.php', 'Psalm\\Node\\Expr\\VirtualTernary' => $baseDir . '/src/Psalm/Node/Expr/VirtualTernary.php', 'Psalm\\Node\\Expr\\VirtualThrow' => $baseDir . '/src/Psalm/Node/Expr/VirtualThrow.php', 'Psalm\\Node\\Expr\\VirtualUnaryMinus' => $baseDir . '/src/Psalm/Node/Expr/VirtualUnaryMinus.php', 'Psalm\\Node\\Expr\\VirtualUnaryPlus' => $baseDir . '/src/Psalm/Node/Expr/VirtualUnaryPlus.php', 'Psalm\\Node\\Expr\\VirtualVariable' => $baseDir . '/src/Psalm/Node/Expr/VirtualVariable.php', 'Psalm\\Node\\Expr\\VirtualYield' => $baseDir . '/src/Psalm/Node/Expr/VirtualYield.php', 'Psalm\\Node\\Expr\\VirtualYieldFrom' => $baseDir . '/src/Psalm/Node/Expr/VirtualYieldFrom.php', 'Psalm\\Node\\Name\\VirtualFullyQualified' => $baseDir . '/src/Psalm/Node/Name/VirtualFullyQualified.php', 'Psalm\\Node\\Name\\VirtualRelative' => $baseDir . '/src/Psalm/Node/Name/VirtualRelative.php', 'Psalm\\Node\\Scalar\\MagicConst\\VirtualClass' => $baseDir . '/src/Psalm/Node/Scalar/MagicConst/VirtualClass.php', 'Psalm\\Node\\Scalar\\MagicConst\\VirtualDir' => $baseDir . '/src/Psalm/Node/Scalar/MagicConst/VirtualDir.php', 'Psalm\\Node\\Scalar\\MagicConst\\VirtualFile' => $baseDir . '/src/Psalm/Node/Scalar/MagicConst/VirtualFile.php', 'Psalm\\Node\\Scalar\\MagicConst\\VirtualFunction' => $baseDir . '/src/Psalm/Node/Scalar/MagicConst/VirtualFunction.php', 'Psalm\\Node\\Scalar\\MagicConst\\VirtualLine' => $baseDir . '/src/Psalm/Node/Scalar/MagicConst/VirtualLine.php', 'Psalm\\Node\\Scalar\\MagicConst\\VirtualMethod' => $baseDir . '/src/Psalm/Node/Scalar/MagicConst/VirtualMethod.php', 'Psalm\\Node\\Scalar\\MagicConst\\VirtualNamespace' => $baseDir . '/src/Psalm/Node/Scalar/MagicConst/VirtualNamespace.php', 'Psalm\\Node\\Scalar\\MagicConst\\VirtualTrait' => $baseDir . '/src/Psalm/Node/Scalar/MagicConst/VirtualTrait.php', 'Psalm\\Node\\Scalar\\VirtualDNumber' => $baseDir . '/src/Psalm/Node/Scalar/VirtualDNumber.php', 'Psalm\\Node\\Scalar\\VirtualEncapsed' => $baseDir . '/src/Psalm/Node/Scalar/VirtualEncapsed.php', 'Psalm\\Node\\Scalar\\VirtualEncapsedStringPart' => $baseDir . '/src/Psalm/Node/Scalar/VirtualEncapsedStringPart.php', 'Psalm\\Node\\Scalar\\VirtualLNumber' => $baseDir . '/src/Psalm/Node/Scalar/VirtualLNumber.php', 'Psalm\\Node\\Scalar\\VirtualString' => $baseDir . '/src/Psalm/Node/Scalar/VirtualString.php', 'Psalm\\Node\\Stmt\\TraitUseAdaptation\\VirtualAlias' => $baseDir . '/src/Psalm/Node/Stmt/TraitUseAdaptation/VirtualAlias.php', 'Psalm\\Node\\Stmt\\TraitUseAdaptation\\VirtualPrecedence' => $baseDir . '/src/Psalm/Node/Stmt/TraitUseAdaptation/VirtualPrecedence.php', 'Psalm\\Node\\Stmt\\VirtualBreak' => $baseDir . '/src/Psalm/Node/Stmt/VirtualBreak.php', 'Psalm\\Node\\Stmt\\VirtualCase' => $baseDir . '/src/Psalm/Node/Stmt/VirtualCase.php', 'Psalm\\Node\\Stmt\\VirtualCatch' => $baseDir . '/src/Psalm/Node/Stmt/VirtualCatch.php', 'Psalm\\Node\\Stmt\\VirtualClass' => $baseDir . '/src/Psalm/Node/Stmt/VirtualClass.php', 'Psalm\\Node\\Stmt\\VirtualClassConst' => $baseDir . '/src/Psalm/Node/Stmt/VirtualClassConst.php', 'Psalm\\Node\\Stmt\\VirtualClassMethod' => $baseDir . '/src/Psalm/Node/Stmt/VirtualClassMethod.php', 'Psalm\\Node\\Stmt\\VirtualConst' => $baseDir . '/src/Psalm/Node/Stmt/VirtualConst.php', 'Psalm\\Node\\Stmt\\VirtualContinue' => $baseDir . '/src/Psalm/Node/Stmt/VirtualContinue.php', 'Psalm\\Node\\Stmt\\VirtualDeclare' => $baseDir . '/src/Psalm/Node/Stmt/VirtualDeclare.php', 'Psalm\\Node\\Stmt\\VirtualDeclareDeclare' => $baseDir . '/src/Psalm/Node/Stmt/VirtualDeclareDeclare.php', 'Psalm\\Node\\Stmt\\VirtualDo' => $baseDir . '/src/Psalm/Node/Stmt/VirtualDo.php', 'Psalm\\Node\\Stmt\\VirtualEcho' => $baseDir . '/src/Psalm/Node/Stmt/VirtualEcho.php', 'Psalm\\Node\\Stmt\\VirtualElse' => $baseDir . '/src/Psalm/Node/Stmt/VirtualElse.php', 'Psalm\\Node\\Stmt\\VirtualElseIf' => $baseDir . '/src/Psalm/Node/Stmt/VirtualElseIf.php', 'Psalm\\Node\\Stmt\\VirtualExpression' => $baseDir . '/src/Psalm/Node/Stmt/VirtualExpression.php', 'Psalm\\Node\\Stmt\\VirtualFinally' => $baseDir . '/src/Psalm/Node/Stmt/VirtualFinally.php', 'Psalm\\Node\\Stmt\\VirtualFor' => $baseDir . '/src/Psalm/Node/Stmt/VirtualFor.php', 'Psalm\\Node\\Stmt\\VirtualForeach' => $baseDir . '/src/Psalm/Node/Stmt/VirtualForeach.php', 'Psalm\\Node\\Stmt\\VirtualFunction' => $baseDir . '/src/Psalm/Node/Stmt/VirtualFunction.php', 'Psalm\\Node\\Stmt\\VirtualGlobal' => $baseDir . '/src/Psalm/Node/Stmt/VirtualGlobal.php', 'Psalm\\Node\\Stmt\\VirtualGoto' => $baseDir . '/src/Psalm/Node/Stmt/VirtualGoto.php', 'Psalm\\Node\\Stmt\\VirtualGroupUse' => $baseDir . '/src/Psalm/Node/Stmt/VirtualGroupUse.php', 'Psalm\\Node\\Stmt\\VirtualHaltCompiler' => $baseDir . '/src/Psalm/Node/Stmt/VirtualHaltCompiler.php', 'Psalm\\Node\\Stmt\\VirtualIf' => $baseDir . '/src/Psalm/Node/Stmt/VirtualIf.php', 'Psalm\\Node\\Stmt\\VirtualInlineHTML' => $baseDir . '/src/Psalm/Node/Stmt/VirtualInlineHTML.php', 'Psalm\\Node\\Stmt\\VirtualInterface' => $baseDir . '/src/Psalm/Node/Stmt/VirtualInterface.php', 'Psalm\\Node\\Stmt\\VirtualLabel' => $baseDir . '/src/Psalm/Node/Stmt/VirtualLabel.php', 'Psalm\\Node\\Stmt\\VirtualNamespace' => $baseDir . '/src/Psalm/Node/Stmt/VirtualNamespace.php', 'Psalm\\Node\\Stmt\\VirtualNop' => $baseDir . '/src/Psalm/Node/Stmt/VirtualNop.php', 'Psalm\\Node\\Stmt\\VirtualProperty' => $baseDir . '/src/Psalm/Node/Stmt/VirtualProperty.php', 'Psalm\\Node\\Stmt\\VirtualPropertyProperty' => $baseDir . '/src/Psalm/Node/Stmt/VirtualPropertyProperty.php', 'Psalm\\Node\\Stmt\\VirtualReturn' => $baseDir . '/src/Psalm/Node/Stmt/VirtualReturn.php', 'Psalm\\Node\\Stmt\\VirtualStatic' => $baseDir . '/src/Psalm/Node/Stmt/VirtualStatic.php', 'Psalm\\Node\\Stmt\\VirtualStaticVar' => $baseDir . '/src/Psalm/Node/Stmt/VirtualStaticVar.php', 'Psalm\\Node\\Stmt\\VirtualSwitch' => $baseDir . '/src/Psalm/Node/Stmt/VirtualSwitch.php', 'Psalm\\Node\\Stmt\\VirtualThrow' => $baseDir . '/src/Psalm/Node/Stmt/VirtualThrow.php', 'Psalm\\Node\\Stmt\\VirtualTrait' => $baseDir . '/src/Psalm/Node/Stmt/VirtualTrait.php', 'Psalm\\Node\\Stmt\\VirtualTraitUse' => $baseDir . '/src/Psalm/Node/Stmt/VirtualTraitUse.php', 'Psalm\\Node\\Stmt\\VirtualTryCatch' => $baseDir . '/src/Psalm/Node/Stmt/VirtualTryCatch.php', 'Psalm\\Node\\Stmt\\VirtualUnset' => $baseDir . '/src/Psalm/Node/Stmt/VirtualUnset.php', 'Psalm\\Node\\Stmt\\VirtualUse' => $baseDir . '/src/Psalm/Node/Stmt/VirtualUse.php', 'Psalm\\Node\\Stmt\\VirtualUseUse' => $baseDir . '/src/Psalm/Node/Stmt/VirtualUseUse.php', 'Psalm\\Node\\Stmt\\VirtualWhile' => $baseDir . '/src/Psalm/Node/Stmt/VirtualWhile.php', 'Psalm\\Node\\VirtualArg' => $baseDir . '/src/Psalm/Node/VirtualArg.php', 'Psalm\\Node\\VirtualAttribute' => $baseDir . '/src/Psalm/Node/VirtualAttribute.php', 'Psalm\\Node\\VirtualAttributeGroup' => $baseDir . '/src/Psalm/Node/VirtualAttributeGroup.php', 'Psalm\\Node\\VirtualConst' => $baseDir . '/src/Psalm/Node/VirtualConst.php', 'Psalm\\Node\\VirtualIdentifier' => $baseDir . '/src/Psalm/Node/VirtualIdentifier.php', 'Psalm\\Node\\VirtualMatchArm' => $baseDir . '/src/Psalm/Node/VirtualMatchArm.php', 'Psalm\\Node\\VirtualName' => $baseDir . '/src/Psalm/Node/VirtualName.php', 'Psalm\\Node\\VirtualNode' => $baseDir . '/src/Psalm/Node/VirtualNode.php', 'Psalm\\Node\\VirtualNullableType' => $baseDir . '/src/Psalm/Node/VirtualNullableType.php', 'Psalm\\Node\\VirtualParam' => $baseDir . '/src/Psalm/Node/VirtualParam.php', 'Psalm\\Node\\VirtualUnionType' => $baseDir . '/src/Psalm/Node/VirtualUnionType.php', 'Psalm\\Node\\VirtualVarLikeIdentifier' => $baseDir . '/src/Psalm/Node/VirtualVarLikeIdentifier.php', 'Psalm\\PluginFileExtensionsSocket' => $baseDir . '/src/Psalm/PluginFileExtensionsSocket.php', 'Psalm\\PluginRegistrationSocket' => $baseDir . '/src/Psalm/PluginRegistrationSocket.php', 'Psalm\\Plugin\\ArgTypeInferer' => $baseDir . '/src/Psalm/Plugin/ArgTypeInferer.php', 'Psalm\\Plugin\\DynamicFunctionStorage' => $baseDir . '/src/Psalm/Plugin/DynamicFunctionStorage.php', 'Psalm\\Plugin\\DynamicTemplateProvider' => $baseDir . '/src/Psalm/Plugin/DynamicTemplateProvider.php', 'Psalm\\Plugin\\EventHandler\\AddTaintsInterface' => $baseDir . '/src/Psalm/Plugin/EventHandler/AddTaintsInterface.php', 'Psalm\\Plugin\\EventHandler\\AfterAnalysisInterface' => $baseDir . '/src/Psalm/Plugin/EventHandler/AfterAnalysisInterface.php', 'Psalm\\Plugin\\EventHandler\\AfterClassLikeAnalysisInterface' => $baseDir . '/src/Psalm/Plugin/EventHandler/AfterClassLikeAnalysisInterface.php', 'Psalm\\Plugin\\EventHandler\\AfterClassLikeExistenceCheckInterface' => $baseDir . '/src/Psalm/Plugin/EventHandler/AfterClassLikeExistenceCheckInterface.php', 'Psalm\\Plugin\\EventHandler\\AfterClassLikeVisitInterface' => $baseDir . '/src/Psalm/Plugin/EventHandler/AfterClassLikeVisitInterface.php', 'Psalm\\Plugin\\EventHandler\\AfterCodebasePopulatedInterface' => $baseDir . '/src/Psalm/Plugin/EventHandler/AfterCodebasePopulatedInterface.php', 'Psalm\\Plugin\\EventHandler\\AfterEveryFunctionCallAnalysisInterface' => $baseDir . '/src/Psalm/Plugin/EventHandler/AfterEveryFunctionCallAnalysisInterface.php', 'Psalm\\Plugin\\EventHandler\\AfterExpressionAnalysisInterface' => $baseDir . '/src/Psalm/Plugin/EventHandler/AfterExpressionAnalysisInterface.php', 'Psalm\\Plugin\\EventHandler\\AfterFileAnalysisInterface' => $baseDir . '/src/Psalm/Plugin/EventHandler/AfterFileAnalysisInterface.php', 'Psalm\\Plugin\\EventHandler\\AfterFunctionCallAnalysisInterface' => $baseDir . '/src/Psalm/Plugin/EventHandler/AfterFunctionCallAnalysisInterface.php', 'Psalm\\Plugin\\EventHandler\\AfterFunctionLikeAnalysisInterface' => $baseDir . '/src/Psalm/Plugin/EventHandler/AfterFunctionLikeAnalysisInterface.php', 'Psalm\\Plugin\\EventHandler\\AfterMethodCallAnalysisInterface' => $baseDir . '/src/Psalm/Plugin/EventHandler/AfterMethodCallAnalysisInterface.php', 'Psalm\\Plugin\\EventHandler\\AfterStatementAnalysisInterface' => $baseDir . '/src/Psalm/Plugin/EventHandler/AfterStatementAnalysisInterface.php', 'Psalm\\Plugin\\EventHandler\\BeforeAddIssueInterface' => $baseDir . '/src/Psalm/Plugin/EventHandler/BeforeAddIssueInterface.php', 'Psalm\\Plugin\\EventHandler\\BeforeExpressionAnalysisInterface' => $baseDir . '/src/Psalm/Plugin/EventHandler/BeforeExpressionAnalysisInterface.php', 'Psalm\\Plugin\\EventHandler\\BeforeFileAnalysisInterface' => $baseDir . '/src/Psalm/Plugin/EventHandler/BeforeFileAnalysisInterface.php', 'Psalm\\Plugin\\EventHandler\\BeforeStatementAnalysisInterface' => $baseDir . '/src/Psalm/Plugin/EventHandler/BeforeStatementAnalysisInterface.php', 'Psalm\\Plugin\\EventHandler\\DynamicFunctionStorageProviderInterface' => $baseDir . '/src/Psalm/Plugin/EventHandler/DynamicFunctionStorageProviderInterface.php', 'Psalm\\Plugin\\EventHandler\\Event\\AddRemoveTaintsEvent' => $baseDir . '/src/Psalm/Plugin/EventHandler/Event/AddRemoveTaintsEvent.php', 'Psalm\\Plugin\\EventHandler\\Event\\AfterAnalysisEvent' => $baseDir . '/src/Psalm/Plugin/EventHandler/Event/AfterAnalysisEvent.php', 'Psalm\\Plugin\\EventHandler\\Event\\AfterClassLikeAnalysisEvent' => $baseDir . '/src/Psalm/Plugin/EventHandler/Event/AfterClassLikeAnalysisEvent.php', 'Psalm\\Plugin\\EventHandler\\Event\\AfterClassLikeExistenceCheckEvent' => $baseDir . '/src/Psalm/Plugin/EventHandler/Event/AfterClassLikeExistenceCheckEvent.php', 'Psalm\\Plugin\\EventHandler\\Event\\AfterClassLikeVisitEvent' => $baseDir . '/src/Psalm/Plugin/EventHandler/Event/AfterClassLikeVisitEvent.php', 'Psalm\\Plugin\\EventHandler\\Event\\AfterCodebasePopulatedEvent' => $baseDir . '/src/Psalm/Plugin/EventHandler/Event/AfterCodebasePopulatedEvent.php', 'Psalm\\Plugin\\EventHandler\\Event\\AfterEveryFunctionCallAnalysisEvent' => $baseDir . '/src/Psalm/Plugin/EventHandler/Event/AfterEveryFunctionCallAnalysisEvent.php', 'Psalm\\Plugin\\EventHandler\\Event\\AfterExpressionAnalysisEvent' => $baseDir . '/src/Psalm/Plugin/EventHandler/Event/AfterExpressionAnalysisEvent.php', 'Psalm\\Plugin\\EventHandler\\Event\\AfterFileAnalysisEvent' => $baseDir . '/src/Psalm/Plugin/EventHandler/Event/AfterFileAnalysisEvent.php', 'Psalm\\Plugin\\EventHandler\\Event\\AfterFunctionCallAnalysisEvent' => $baseDir . '/src/Psalm/Plugin/EventHandler/Event/AfterFunctionCallAnalysisEvent.php', 'Psalm\\Plugin\\EventHandler\\Event\\AfterFunctionLikeAnalysisEvent' => $baseDir . '/src/Psalm/Plugin/EventHandler/Event/AfterFunctionLikeAnalysisEvent.php', 'Psalm\\Plugin\\EventHandler\\Event\\AfterMethodCallAnalysisEvent' => $baseDir . '/src/Psalm/Plugin/EventHandler/Event/AfterMethodCallAnalysisEvent.php', 'Psalm\\Plugin\\EventHandler\\Event\\AfterStatementAnalysisEvent' => $baseDir . '/src/Psalm/Plugin/EventHandler/Event/AfterStatementAnalysisEvent.php', 'Psalm\\Plugin\\EventHandler\\Event\\BeforeAddIssueEvent' => $baseDir . '/src/Psalm/Plugin/EventHandler/Event/BeforeAddIssueEvent.php', 'Psalm\\Plugin\\EventHandler\\Event\\BeforeExpressionAnalysisEvent' => $baseDir . '/src/Psalm/Plugin/EventHandler/Event/BeforeExpressionAnalysisEvent.php', 'Psalm\\Plugin\\EventHandler\\Event\\BeforeFileAnalysisEvent' => $baseDir . '/src/Psalm/Plugin/EventHandler/Event/BeforeFileAnalysisEvent.php', 'Psalm\\Plugin\\EventHandler\\Event\\BeforeStatementAnalysisEvent' => $baseDir . '/src/Psalm/Plugin/EventHandler/Event/BeforeStatementAnalysisEvent.php', 'Psalm\\Plugin\\EventHandler\\Event\\DynamicFunctionStorageProviderEvent' => $baseDir . '/src/Psalm/Plugin/EventHandler/Event/DynamicFunctionStorageProviderEvent.php', 'Psalm\\Plugin\\EventHandler\\Event\\FunctionExistenceProviderEvent' => $baseDir . '/src/Psalm/Plugin/EventHandler/Event/FunctionExistenceProviderEvent.php', 'Psalm\\Plugin\\EventHandler\\Event\\FunctionParamsProviderEvent' => $baseDir . '/src/Psalm/Plugin/EventHandler/Event/FunctionParamsProviderEvent.php', 'Psalm\\Plugin\\EventHandler\\Event\\FunctionReturnTypeProviderEvent' => $baseDir . '/src/Psalm/Plugin/EventHandler/Event/FunctionReturnTypeProviderEvent.php', 'Psalm\\Plugin\\EventHandler\\Event\\MethodExistenceProviderEvent' => $baseDir . '/src/Psalm/Plugin/EventHandler/Event/MethodExistenceProviderEvent.php', 'Psalm\\Plugin\\EventHandler\\Event\\MethodParamsProviderEvent' => $baseDir . '/src/Psalm/Plugin/EventHandler/Event/MethodParamsProviderEvent.php', 'Psalm\\Plugin\\EventHandler\\Event\\MethodReturnTypeProviderEvent' => $baseDir . '/src/Psalm/Plugin/EventHandler/Event/MethodReturnTypeProviderEvent.php', 'Psalm\\Plugin\\EventHandler\\Event\\MethodVisibilityProviderEvent' => $baseDir . '/src/Psalm/Plugin/EventHandler/Event/MethodVisibilityProviderEvent.php', 'Psalm\\Plugin\\EventHandler\\Event\\PropertyExistenceProviderEvent' => $baseDir . '/src/Psalm/Plugin/EventHandler/Event/PropertyExistenceProviderEvent.php', 'Psalm\\Plugin\\EventHandler\\Event\\PropertyTypeProviderEvent' => $baseDir . '/src/Psalm/Plugin/EventHandler/Event/PropertyTypeProviderEvent.php', 'Psalm\\Plugin\\EventHandler\\Event\\PropertyVisibilityProviderEvent' => $baseDir . '/src/Psalm/Plugin/EventHandler/Event/PropertyVisibilityProviderEvent.php', 'Psalm\\Plugin\\EventHandler\\Event\\StringInterpreterEvent' => $baseDir . '/src/Psalm/Plugin/EventHandler/Event/StringInterpreterEvent.php', 'Psalm\\Plugin\\EventHandler\\FunctionExistenceProviderInterface' => $baseDir . '/src/Psalm/Plugin/EventHandler/FunctionExistenceProviderInterface.php', 'Psalm\\Plugin\\EventHandler\\FunctionParamsProviderInterface' => $baseDir . '/src/Psalm/Plugin/EventHandler/FunctionParamsProviderInterface.php', 'Psalm\\Plugin\\EventHandler\\FunctionReturnTypeProviderInterface' => $baseDir . '/src/Psalm/Plugin/EventHandler/FunctionReturnTypeProviderInterface.php', 'Psalm\\Plugin\\EventHandler\\MethodExistenceProviderInterface' => $baseDir . '/src/Psalm/Plugin/EventHandler/MethodExistenceProviderInterface.php', 'Psalm\\Plugin\\EventHandler\\MethodParamsProviderInterface' => $baseDir . '/src/Psalm/Plugin/EventHandler/MethodParamsProviderInterface.php', 'Psalm\\Plugin\\EventHandler\\MethodReturnTypeProviderInterface' => $baseDir . '/src/Psalm/Plugin/EventHandler/MethodReturnTypeProviderInterface.php', 'Psalm\\Plugin\\EventHandler\\MethodVisibilityProviderInterface' => $baseDir . '/src/Psalm/Plugin/EventHandler/MethodVisibilityProviderInterface.php', 'Psalm\\Plugin\\EventHandler\\PropertyExistenceProviderInterface' => $baseDir . '/src/Psalm/Plugin/EventHandler/PropertyExistenceProviderInterface.php', 'Psalm\\Plugin\\EventHandler\\PropertyTypeProviderInterface' => $baseDir . '/src/Psalm/Plugin/EventHandler/PropertyTypeProviderInterface.php', 'Psalm\\Plugin\\EventHandler\\PropertyVisibilityProviderInterface' => $baseDir . '/src/Psalm/Plugin/EventHandler/PropertyVisibilityProviderInterface.php', 'Psalm\\Plugin\\EventHandler\\RemoveTaintsInterface' => $baseDir . '/src/Psalm/Plugin/EventHandler/RemoveTaintsInterface.php', 'Psalm\\Plugin\\EventHandler\\StringInterpreterInterface' => $baseDir . '/src/Psalm/Plugin/EventHandler/StringInterpreterInterface.php', 'Psalm\\Plugin\\FileExtensionsInterface' => $baseDir . '/src/Psalm/Plugin/FileExtensionsInterface.php', 'Psalm\\Plugin\\PluginEntryPointInterface' => $baseDir . '/src/Psalm/Plugin/PluginEntryPointInterface.php', 'Psalm\\Plugin\\PluginFileExtensionsInterface' => $baseDir . '/src/Psalm/Plugin/PluginFileExtensionsInterface.php', 'Psalm\\Plugin\\PluginInterface' => $baseDir . '/src/Psalm/Plugin/PluginInterface.php', 'Psalm\\Plugin\\RegistrationInterface' => $baseDir . '/src/Psalm/Plugin/RegistrationInterface.php', 'Psalm\\Plugin\\Shepherd' => $baseDir . '/src/Psalm/Plugin/Shepherd.php', 'Psalm\\Progress\\DebugProgress' => $baseDir . '/src/Psalm/Progress/DebugProgress.php', 'Psalm\\Progress\\DefaultProgress' => $baseDir . '/src/Psalm/Progress/DefaultProgress.php', 'Psalm\\Progress\\LongProgress' => $baseDir . '/src/Psalm/Progress/LongProgress.php', 'Psalm\\Progress\\Progress' => $baseDir . '/src/Psalm/Progress/Progress.php', 'Psalm\\Progress\\VoidProgress' => $baseDir . '/src/Psalm/Progress/VoidProgress.php', 'Psalm\\Report' => $baseDir . '/src/Psalm/Report.php', 'Psalm\\Report\\ByIssueLevelAndTypeReport' => $baseDir . '/src/Psalm/Report/ByIssueLevelAndTypeReport.php', 'Psalm\\Report\\CheckstyleReport' => $baseDir . '/src/Psalm/Report/CheckstyleReport.php', 'Psalm\\Report\\CodeClimateReport' => $baseDir . '/src/Psalm/Report/CodeClimateReport.php', 'Psalm\\Report\\CompactReport' => $baseDir . '/src/Psalm/Report/CompactReport.php', 'Psalm\\Report\\ConsoleReport' => $baseDir . '/src/Psalm/Report/ConsoleReport.php', 'Psalm\\Report\\CountReport' => $baseDir . '/src/Psalm/Report/CountReport.php', 'Psalm\\Report\\EmacsReport' => $baseDir . '/src/Psalm/Report/EmacsReport.php', 'Psalm\\Report\\GithubActionsReport' => $baseDir . '/src/Psalm/Report/GithubActionsReport.php', 'Psalm\\Report\\JsonReport' => $baseDir . '/src/Psalm/Report/JsonReport.php', 'Psalm\\Report\\JsonSummaryReport' => $baseDir . '/src/Psalm/Report/JsonSummaryReport.php', 'Psalm\\Report\\JunitReport' => $baseDir . '/src/Psalm/Report/JunitReport.php', 'Psalm\\Report\\PhpStormReport' => $baseDir . '/src/Psalm/Report/PhpStormReport.php', 'Psalm\\Report\\PylintReport' => $baseDir . '/src/Psalm/Report/PylintReport.php', 'Psalm\\Report\\ReportOptions' => $baseDir . '/src/Psalm/Report/ReportOptions.php', 'Psalm\\Report\\SarifReport' => $baseDir . '/src/Psalm/Report/SarifReport.php', 'Psalm\\Report\\SonarqubeReport' => $baseDir . '/src/Psalm/Report/SonarqubeReport.php', 'Psalm\\Report\\TextReport' => $baseDir . '/src/Psalm/Report/TextReport.php', 'Psalm\\Report\\XmlReport' => $baseDir . '/src/Psalm/Report/XmlReport.php', 'Psalm\\SourceControl\\Git\\CommitInfo' => $baseDir . '/src/Psalm/SourceControl/Git/CommitInfo.php', 'Psalm\\SourceControl\\Git\\GitInfo' => $baseDir . '/src/Psalm/SourceControl/Git/GitInfo.php', 'Psalm\\SourceControl\\Git\\RemoteInfo' => $baseDir . '/src/Psalm/SourceControl/Git/RemoteInfo.php', 'Psalm\\SourceControl\\SourceControlInfo' => $baseDir . '/src/Psalm/SourceControl/SourceControlInfo.php', 'Psalm\\StatementsSource' => $baseDir . '/src/Psalm/StatementsSource.php', 'Psalm\\Storage\\Assertion' => $baseDir . '/src/Psalm/Storage/Assertion.php', 'Psalm\\Storage\\Assertion\\Any' => $baseDir . '/src/Psalm/Storage/Assertion/Any.php', 'Psalm\\Storage\\Assertion\\ArrayKeyDoesNotExist' => $baseDir . '/src/Psalm/Storage/Assertion/ArrayKeyDoesNotExist.php', 'Psalm\\Storage\\Assertion\\ArrayKeyExists' => $baseDir . '/src/Psalm/Storage/Assertion/ArrayKeyExists.php', 'Psalm\\Storage\\Assertion\\DoesNotHaveAtLeastCount' => $baseDir . '/src/Psalm/Storage/Assertion/DoesNotHaveAtLeastCount.php', 'Psalm\\Storage\\Assertion\\DoesNotHaveExactCount' => $baseDir . '/src/Psalm/Storage/Assertion/DoesNotHaveExactCount.php', 'Psalm\\Storage\\Assertion\\DoesNotHaveMethod' => $baseDir . '/src/Psalm/Storage/Assertion/DoesNotHaveMethod.php', 'Psalm\\Storage\\Assertion\\Empty_' => $baseDir . '/src/Psalm/Storage/Assertion/Empty_.php', 'Psalm\\Storage\\Assertion\\Falsy' => $baseDir . '/src/Psalm/Storage/Assertion/Falsy.php', 'Psalm\\Storage\\Assertion\\HasArrayKey' => $baseDir . '/src/Psalm/Storage/Assertion/HasArrayKey.php', 'Psalm\\Storage\\Assertion\\HasAtLeastCount' => $baseDir . '/src/Psalm/Storage/Assertion/HasAtLeastCount.php', 'Psalm\\Storage\\Assertion\\HasExactCount' => $baseDir . '/src/Psalm/Storage/Assertion/HasExactCount.php', 'Psalm\\Storage\\Assertion\\HasIntOrStringArrayAccess' => $baseDir . '/src/Psalm/Storage/Assertion/HasIntOrStringArrayAccess.php', 'Psalm\\Storage\\Assertion\\HasMethod' => $baseDir . '/src/Psalm/Storage/Assertion/HasMethod.php', 'Psalm\\Storage\\Assertion\\HasStringArrayAccess' => $baseDir . '/src/Psalm/Storage/Assertion/HasStringArrayAccess.php', 'Psalm\\Storage\\Assertion\\InArray' => $baseDir . '/src/Psalm/Storage/Assertion/InArray.php', 'Psalm\\Storage\\Assertion\\IsAClass' => $baseDir . '/src/Psalm/Storage/Assertion/IsAClass.php', 'Psalm\\Storage\\Assertion\\IsClassEqual' => $baseDir . '/src/Psalm/Storage/Assertion/IsClassEqual.php', 'Psalm\\Storage\\Assertion\\IsClassNotEqual' => $baseDir . '/src/Psalm/Storage/Assertion/IsClassNotEqual.php', 'Psalm\\Storage\\Assertion\\IsCountable' => $baseDir . '/src/Psalm/Storage/Assertion/IsCountable.php', 'Psalm\\Storage\\Assertion\\IsEqualIsset' => $baseDir . '/src/Psalm/Storage/Assertion/IsEqualIsset.php', 'Psalm\\Storage\\Assertion\\IsGreaterThan' => $baseDir . '/src/Psalm/Storage/Assertion/IsGreaterThan.php', 'Psalm\\Storage\\Assertion\\IsGreaterThanOrEqualTo' => $baseDir . '/src/Psalm/Storage/Assertion/IsGreaterThanOrEqualTo.php', 'Psalm\\Storage\\Assertion\\IsIdentical' => $baseDir . '/src/Psalm/Storage/Assertion/IsIdentical.php', 'Psalm\\Storage\\Assertion\\IsIsset' => $baseDir . '/src/Psalm/Storage/Assertion/IsIsset.php', 'Psalm\\Storage\\Assertion\\IsLessThan' => $baseDir . '/src/Psalm/Storage/Assertion/IsLessThan.php', 'Psalm\\Storage\\Assertion\\IsLessThanOrEqualTo' => $baseDir . '/src/Psalm/Storage/Assertion/IsLessThanOrEqualTo.php', 'Psalm\\Storage\\Assertion\\IsLooselyEqual' => $baseDir . '/src/Psalm/Storage/Assertion/IsLooselyEqual.php', 'Psalm\\Storage\\Assertion\\IsNotAClass' => $baseDir . '/src/Psalm/Storage/Assertion/IsNotAClass.php', 'Psalm\\Storage\\Assertion\\IsNotCountable' => $baseDir . '/src/Psalm/Storage/Assertion/IsNotCountable.php', 'Psalm\\Storage\\Assertion\\IsNotIdentical' => $baseDir . '/src/Psalm/Storage/Assertion/IsNotIdentical.php', 'Psalm\\Storage\\Assertion\\IsNotIsset' => $baseDir . '/src/Psalm/Storage/Assertion/IsNotIsset.php', 'Psalm\\Storage\\Assertion\\IsNotLooselyEqual' => $baseDir . '/src/Psalm/Storage/Assertion/IsNotLooselyEqual.php', 'Psalm\\Storage\\Assertion\\IsNotType' => $baseDir . '/src/Psalm/Storage/Assertion/IsNotType.php', 'Psalm\\Storage\\Assertion\\IsType' => $baseDir . '/src/Psalm/Storage/Assertion/IsType.php', 'Psalm\\Storage\\Assertion\\NestedAssertions' => $baseDir . '/src/Psalm/Storage/Assertion/NestedAssertions.php', 'Psalm\\Storage\\Assertion\\NonEmpty' => $baseDir . '/src/Psalm/Storage/Assertion/NonEmpty.php', 'Psalm\\Storage\\Assertion\\NonEmptyCountable' => $baseDir . '/src/Psalm/Storage/Assertion/NonEmptyCountable.php', 'Psalm\\Storage\\Assertion\\NotInArray' => $baseDir . '/src/Psalm/Storage/Assertion/NotInArray.php', 'Psalm\\Storage\\Assertion\\NotNestedAssertions' => $baseDir . '/src/Psalm/Storage/Assertion/NotNestedAssertions.php', 'Psalm\\Storage\\Assertion\\NotNonEmptyCountable' => $baseDir . '/src/Psalm/Storage/Assertion/NotNonEmptyCountable.php', 'Psalm\\Storage\\Assertion\\Truthy' => $baseDir . '/src/Psalm/Storage/Assertion/Truthy.php', 'Psalm\\Storage\\AttributeArg' => $baseDir . '/src/Psalm/Storage/AttributeArg.php', 'Psalm\\Storage\\AttributeStorage' => $baseDir . '/src/Psalm/Storage/AttributeStorage.php', 'Psalm\\Storage\\ClassConstantStorage' => $baseDir . '/src/Psalm/Storage/ClassConstantStorage.php', 'Psalm\\Storage\\ClassLikeStorage' => $baseDir . '/src/Psalm/Storage/ClassLikeStorage.php', 'Psalm\\Storage\\CustomMetadataTrait' => $baseDir . '/src/Psalm/Storage/CustomMetadataTrait.php', 'Psalm\\Storage\\EnumCaseStorage' => $baseDir . '/src/Psalm/Storage/EnumCaseStorage.php', 'Psalm\\Storage\\FileStorage' => $baseDir . '/src/Psalm/Storage/FileStorage.php', 'Psalm\\Storage\\FunctionLikeParameter' => $baseDir . '/src/Psalm/Storage/FunctionLikeParameter.php', 'Psalm\\Storage\\FunctionLikeStorage' => $baseDir . '/src/Psalm/Storage/FunctionLikeStorage.php', 'Psalm\\Storage\\FunctionStorage' => $baseDir . '/src/Psalm/Storage/FunctionStorage.php', 'Psalm\\Storage\\HasAttributesInterface' => $baseDir . '/src/Psalm/Storage/HasAttributesInterface.php', 'Psalm\\Storage\\ImmutableNonCloneableTrait' => $baseDir . '/src/Psalm/Storage/ImmutableNonCloneableTrait.php', 'Psalm\\Storage\\MethodStorage' => $baseDir . '/src/Psalm/Storage/MethodStorage.php', 'Psalm\\Storage\\Possibilities' => $baseDir . '/src/Psalm/Storage/Possibilities.php', 'Psalm\\Storage\\PropertyStorage' => $baseDir . '/src/Psalm/Storage/PropertyStorage.php', 'Psalm\\Storage\\UnserializeMemoryUsageSuppressionTrait' => $baseDir . '/src/Psalm/Storage/UnserializeMemoryUsageSuppressionTrait.php', 'Psalm\\Type' => $baseDir . '/src/Psalm/Type.php', 'Psalm\\Type\\Atomic' => $baseDir . '/src/Psalm/Type/Atomic.php', 'Psalm\\Type\\Atomic\\CallableTrait' => $baseDir . '/src/Psalm/Type/Atomic/CallableTrait.php', 'Psalm\\Type\\Atomic\\DependentType' => $baseDir . '/src/Psalm/Type/Atomic/DependentType.php', 'Psalm\\Type\\Atomic\\GenericTrait' => $baseDir . '/src/Psalm/Type/Atomic/GenericTrait.php', 'Psalm\\Type\\Atomic\\HasIntersectionTrait' => $baseDir . '/src/Psalm/Type/Atomic/HasIntersectionTrait.php', 'Psalm\\Type\\Atomic\\Scalar' => $baseDir . '/src/Psalm/Type/Atomic/Scalar.php', 'Psalm\\Type\\Atomic\\TAnonymousClassInstance' => $baseDir . '/src/Psalm/Type/Atomic/TAnonymousClassInstance.php', 'Psalm\\Type\\Atomic\\TArray' => $baseDir . '/src/Psalm/Type/Atomic/TArray.php', 'Psalm\\Type\\Atomic\\TArrayKey' => $baseDir . '/src/Psalm/Type/Atomic/TArrayKey.php', 'Psalm\\Type\\Atomic\\TBool' => $baseDir . '/src/Psalm/Type/Atomic/TBool.php', 'Psalm\\Type\\Atomic\\TCallable' => $baseDir . '/src/Psalm/Type/Atomic/TCallable.php', 'Psalm\\Type\\Atomic\\TCallableArray' => $baseDir . '/src/Psalm/Type/Atomic/TCallableArray.php', 'Psalm\\Type\\Atomic\\TCallableInterface' => $baseDir . '/src/Psalm/Type/Atomic/TCallableInterface.php', 'Psalm\\Type\\Atomic\\TCallableKeyedArray' => $baseDir . '/src/Psalm/Type/Atomic/TCallableKeyedArray.php', 'Psalm\\Type\\Atomic\\TCallableList' => $baseDir . '/src/Psalm/Type/Atomic/TCallableList.php', 'Psalm\\Type\\Atomic\\TCallableObject' => $baseDir . '/src/Psalm/Type/Atomic/TCallableObject.php', 'Psalm\\Type\\Atomic\\TCallableString' => $baseDir . '/src/Psalm/Type/Atomic/TCallableString.php', 'Psalm\\Type\\Atomic\\TClassConstant' => $baseDir . '/src/Psalm/Type/Atomic/TClassConstant.php', 'Psalm\\Type\\Atomic\\TClassString' => $baseDir . '/src/Psalm/Type/Atomic/TClassString.php', 'Psalm\\Type\\Atomic\\TClassStringMap' => $baseDir . '/src/Psalm/Type/Atomic/TClassStringMap.php', 'Psalm\\Type\\Atomic\\TClosedResource' => $baseDir . '/src/Psalm/Type/Atomic/TClosedResource.php', 'Psalm\\Type\\Atomic\\TClosure' => $baseDir . '/src/Psalm/Type/Atomic/TClosure.php', 'Psalm\\Type\\Atomic\\TConditional' => $baseDir . '/src/Psalm/Type/Atomic/TConditional.php', 'Psalm\\Type\\Atomic\\TDependentGetClass' => $baseDir . '/src/Psalm/Type/Atomic/TDependentGetClass.php', 'Psalm\\Type\\Atomic\\TDependentGetDebugType' => $baseDir . '/src/Psalm/Type/Atomic/TDependentGetDebugType.php', 'Psalm\\Type\\Atomic\\TDependentGetType' => $baseDir . '/src/Psalm/Type/Atomic/TDependentGetType.php', 'Psalm\\Type\\Atomic\\TDependentListKey' => $baseDir . '/src/Psalm/Type/Atomic/TDependentListKey.php', 'Psalm\\Type\\Atomic\\TEmptyMixed' => $baseDir . '/src/Psalm/Type/Atomic/TEmptyMixed.php', 'Psalm\\Type\\Atomic\\TEmptyNumeric' => $baseDir . '/src/Psalm/Type/Atomic/TEmptyNumeric.php', 'Psalm\\Type\\Atomic\\TEmptyScalar' => $baseDir . '/src/Psalm/Type/Atomic/TEmptyScalar.php', 'Psalm\\Type\\Atomic\\TEnumCase' => $baseDir . '/src/Psalm/Type/Atomic/TEnumCase.php', 'Psalm\\Type\\Atomic\\TFalse' => $baseDir . '/src/Psalm/Type/Atomic/TFalse.php', 'Psalm\\Type\\Atomic\\TFloat' => $baseDir . '/src/Psalm/Type/Atomic/TFloat.php', 'Psalm\\Type\\Atomic\\TGenericObject' => $baseDir . '/src/Psalm/Type/Atomic/TGenericObject.php', 'Psalm\\Type\\Atomic\\TInt' => $baseDir . '/src/Psalm/Type/Atomic/TInt.php', 'Psalm\\Type\\Atomic\\TIntMask' => $baseDir . '/src/Psalm/Type/Atomic/TIntMask.php', 'Psalm\\Type\\Atomic\\TIntMaskOf' => $baseDir . '/src/Psalm/Type/Atomic/TIntMaskOf.php', 'Psalm\\Type\\Atomic\\TIntRange' => $baseDir . '/src/Psalm/Type/Atomic/TIntRange.php', 'Psalm\\Type\\Atomic\\TIterable' => $baseDir . '/src/Psalm/Type/Atomic/TIterable.php', 'Psalm\\Type\\Atomic\\TKeyOf' => $baseDir . '/src/Psalm/Type/Atomic/TKeyOf.php', 'Psalm\\Type\\Atomic\\TKeyedArray' => $baseDir . '/src/Psalm/Type/Atomic/TKeyedArray.php', 'Psalm\\Type\\Atomic\\TList' => $baseDir . '/src/Psalm/Type/Atomic/TList.php', 'Psalm\\Type\\Atomic\\TLiteralClassString' => $baseDir . '/src/Psalm/Type/Atomic/TLiteralClassString.php', 'Psalm\\Type\\Atomic\\TLiteralFloat' => $baseDir . '/src/Psalm/Type/Atomic/TLiteralFloat.php', 'Psalm\\Type\\Atomic\\TLiteralInt' => $baseDir . '/src/Psalm/Type/Atomic/TLiteralInt.php', 'Psalm\\Type\\Atomic\\TLiteralString' => $baseDir . '/src/Psalm/Type/Atomic/TLiteralString.php', 'Psalm\\Type\\Atomic\\TLowercaseString' => $baseDir . '/src/Psalm/Type/Atomic/TLowercaseString.php', 'Psalm\\Type\\Atomic\\TMixed' => $baseDir . '/src/Psalm/Type/Atomic/TMixed.php', 'Psalm\\Type\\Atomic\\TNamedObject' => $baseDir . '/src/Psalm/Type/Atomic/TNamedObject.php', 'Psalm\\Type\\Atomic\\TNever' => $baseDir . '/src/Psalm/Type/Atomic/TNever.php', 'Psalm\\Type\\Atomic\\TNonEmptyArray' => $baseDir . '/src/Psalm/Type/Atomic/TNonEmptyArray.php', 'Psalm\\Type\\Atomic\\TNonEmptyList' => $baseDir . '/src/Psalm/Type/Atomic/TNonEmptyList.php', 'Psalm\\Type\\Atomic\\TNonEmptyLowercaseString' => $baseDir . '/src/Psalm/Type/Atomic/TNonEmptyLowercaseString.php', 'Psalm\\Type\\Atomic\\TNonEmptyMixed' => $baseDir . '/src/Psalm/Type/Atomic/TNonEmptyMixed.php', 'Psalm\\Type\\Atomic\\TNonEmptyNonspecificLiteralString' => $baseDir . '/src/Psalm/Type/Atomic/TNonEmptyNonspecificLiteralString.php', 'Psalm\\Type\\Atomic\\TNonEmptyScalar' => $baseDir . '/src/Psalm/Type/Atomic/TNonEmptyScalar.php', 'Psalm\\Type\\Atomic\\TNonEmptyString' => $baseDir . '/src/Psalm/Type/Atomic/TNonEmptyString.php', 'Psalm\\Type\\Atomic\\TNonFalsyString' => $baseDir . '/src/Psalm/Type/Atomic/TNonFalsyString.php', 'Psalm\\Type\\Atomic\\TNonspecificLiteralInt' => $baseDir . '/src/Psalm/Type/Atomic/TNonspecificLiteralInt.php', 'Psalm\\Type\\Atomic\\TNonspecificLiteralString' => $baseDir . '/src/Psalm/Type/Atomic/TNonspecificLiteralString.php', 'Psalm\\Type\\Atomic\\TNull' => $baseDir . '/src/Psalm/Type/Atomic/TNull.php', 'Psalm\\Type\\Atomic\\TNumeric' => $baseDir . '/src/Psalm/Type/Atomic/TNumeric.php', 'Psalm\\Type\\Atomic\\TNumericString' => $baseDir . '/src/Psalm/Type/Atomic/TNumericString.php', 'Psalm\\Type\\Atomic\\TObject' => $baseDir . '/src/Psalm/Type/Atomic/TObject.php', 'Psalm\\Type\\Atomic\\TObjectWithProperties' => $baseDir . '/src/Psalm/Type/Atomic/TObjectWithProperties.php', 'Psalm\\Type\\Atomic\\TPropertiesOf' => $baseDir . '/src/Psalm/Type/Atomic/TPropertiesOf.php', 'Psalm\\Type\\Atomic\\TResource' => $baseDir . '/src/Psalm/Type/Atomic/TResource.php', 'Psalm\\Type\\Atomic\\TScalar' => $baseDir . '/src/Psalm/Type/Atomic/TScalar.php', 'Psalm\\Type\\Atomic\\TSingleLetter' => $baseDir . '/src/Psalm/Type/Atomic/TSingleLetter.php', 'Psalm\\Type\\Atomic\\TString' => $baseDir . '/src/Psalm/Type/Atomic/TString.php', 'Psalm\\Type\\Atomic\\TTemplateIndexedAccess' => $baseDir . '/src/Psalm/Type/Atomic/TTemplateIndexedAccess.php', 'Psalm\\Type\\Atomic\\TTemplateKeyOf' => $baseDir . '/src/Psalm/Type/Atomic/TTemplateKeyOf.php', 'Psalm\\Type\\Atomic\\TTemplateParam' => $baseDir . '/src/Psalm/Type/Atomic/TTemplateParam.php', 'Psalm\\Type\\Atomic\\TTemplateParamClass' => $baseDir . '/src/Psalm/Type/Atomic/TTemplateParamClass.php', 'Psalm\\Type\\Atomic\\TTemplatePropertiesOf' => $baseDir . '/src/Psalm/Type/Atomic/TTemplatePropertiesOf.php', 'Psalm\\Type\\Atomic\\TTemplateValueOf' => $baseDir . '/src/Psalm/Type/Atomic/TTemplateValueOf.php', 'Psalm\\Type\\Atomic\\TTraitString' => $baseDir . '/src/Psalm/Type/Atomic/TTraitString.php', 'Psalm\\Type\\Atomic\\TTrue' => $baseDir . '/src/Psalm/Type/Atomic/TTrue.php', 'Psalm\\Type\\Atomic\\TTypeAlias' => $baseDir . '/src/Psalm/Type/Atomic/TTypeAlias.php', 'Psalm\\Type\\Atomic\\TUnknownClassString' => $baseDir . '/src/Psalm/Type/Atomic/TUnknownClassString.php', 'Psalm\\Type\\Atomic\\TValueOf' => $baseDir . '/src/Psalm/Type/Atomic/TValueOf.php', 'Psalm\\Type\\Atomic\\TVoid' => $baseDir . '/src/Psalm/Type/Atomic/TVoid.php', 'Psalm\\Type\\MutableTypeVisitor' => $baseDir . '/src/Psalm/Type/MutableTypeVisitor.php', 'Psalm\\Type\\MutableUnion' => $baseDir . '/src/Psalm/Type/MutableUnion.php', 'Psalm\\Type\\Reconciler' => $baseDir . '/src/Psalm/Type/Reconciler.php', 'Psalm\\Type\\TaintKind' => $baseDir . '/src/Psalm/Type/TaintKind.php', 'Psalm\\Type\\TaintKindGroup' => $baseDir . '/src/Psalm/Type/TaintKindGroup.php', 'Psalm\\Type\\TypeNode' => $baseDir . '/src/Psalm/Type/TypeNode.php', 'Psalm\\Type\\TypeVisitor' => $baseDir . '/src/Psalm/Type/TypeVisitor.php', 'Psalm\\Type\\Union' => $baseDir . '/src/Psalm/Type/Union.php', 'Psalm\\Type\\UnionTrait' => $baseDir . '/src/Psalm/Type/UnionTrait.php', 'Stringable' => $vendorDir . '/symfony/polyfill-php80/Resources/stubs/Stringable.php', '_HumbugBox7ff99e199a36\\AdvancedJsonRpc\\Dispatcher' => $vendorDir . '/felixfbecker/advanced-json-rpc/lib/Dispatcher.php', '_HumbugBox7ff99e199a36\\AdvancedJsonRpc\\Error' => $vendorDir . '/felixfbecker/advanced-json-rpc/lib/Error.php', '_HumbugBox7ff99e199a36\\AdvancedJsonRpc\\ErrorCode' => $vendorDir . '/felixfbecker/advanced-json-rpc/lib/ErrorCode.php', '_HumbugBox7ff99e199a36\\AdvancedJsonRpc\\ErrorResponse' => $vendorDir . '/felixfbecker/advanced-json-rpc/lib/ErrorResponse.php', '_HumbugBox7ff99e199a36\\AdvancedJsonRpc\\Message' => $vendorDir . '/felixfbecker/advanced-json-rpc/lib/Message.php', '_HumbugBox7ff99e199a36\\AdvancedJsonRpc\\Notification' => $vendorDir . '/felixfbecker/advanced-json-rpc/lib/Notification.php', '_HumbugBox7ff99e199a36\\AdvancedJsonRpc\\Request' => $vendorDir . '/felixfbecker/advanced-json-rpc/lib/Request.php', '_HumbugBox7ff99e199a36\\AdvancedJsonRpc\\Response' => $vendorDir . '/felixfbecker/advanced-json-rpc/lib/Response.php', '_HumbugBox7ff99e199a36\\AdvancedJsonRpc\\SuccessResponse' => $vendorDir . '/felixfbecker/advanced-json-rpc/lib/SuccessResponse.php', '_HumbugBox7ff99e199a36\\Amp\\ByteStream\\Base64\\Base64DecodingInputStream' => $vendorDir . '/amphp/byte-stream/lib/Base64/Base64DecodingInputStream.php', '_HumbugBox7ff99e199a36\\Amp\\ByteStream\\Base64\\Base64DecodingOutputStream' => $vendorDir . '/amphp/byte-stream/lib/Base64/Base64DecodingOutputStream.php', '_HumbugBox7ff99e199a36\\Amp\\ByteStream\\Base64\\Base64EncodingInputStream' => $vendorDir . '/amphp/byte-stream/lib/Base64/Base64EncodingInputStream.php', '_HumbugBox7ff99e199a36\\Amp\\ByteStream\\Base64\\Base64EncodingOutputStream' => $vendorDir . '/amphp/byte-stream/lib/Base64/Base64EncodingOutputStream.php', '_HumbugBox7ff99e199a36\\Amp\\ByteStream\\ClosedException' => $vendorDir . '/amphp/byte-stream/lib/ClosedException.php', '_HumbugBox7ff99e199a36\\Amp\\ByteStream\\InMemoryStream' => $vendorDir . '/amphp/byte-stream/lib/InMemoryStream.php', '_HumbugBox7ff99e199a36\\Amp\\ByteStream\\InputStream' => $vendorDir . '/amphp/byte-stream/lib/InputStream.php', '_HumbugBox7ff99e199a36\\Amp\\ByteStream\\InputStreamChain' => $vendorDir . '/amphp/byte-stream/lib/InputStreamChain.php', '_HumbugBox7ff99e199a36\\Amp\\ByteStream\\IteratorStream' => $vendorDir . '/amphp/byte-stream/lib/IteratorStream.php', '_HumbugBox7ff99e199a36\\Amp\\ByteStream\\LineReader' => $vendorDir . '/amphp/byte-stream/lib/LineReader.php', '_HumbugBox7ff99e199a36\\Amp\\ByteStream\\Message' => $vendorDir . '/amphp/byte-stream/lib/Message.php', '_HumbugBox7ff99e199a36\\Amp\\ByteStream\\OutputBuffer' => $vendorDir . '/amphp/byte-stream/lib/OutputBuffer.php', '_HumbugBox7ff99e199a36\\Amp\\ByteStream\\OutputStream' => $vendorDir . '/amphp/byte-stream/lib/OutputStream.php', '_HumbugBox7ff99e199a36\\Amp\\ByteStream\\Payload' => $vendorDir . '/amphp/byte-stream/lib/Payload.php', '_HumbugBox7ff99e199a36\\Amp\\ByteStream\\PendingReadError' => $vendorDir . '/amphp/byte-stream/lib/PendingReadError.php', '_HumbugBox7ff99e199a36\\Amp\\ByteStream\\ResourceInputStream' => $vendorDir . '/amphp/byte-stream/lib/ResourceInputStream.php', '_HumbugBox7ff99e199a36\\Amp\\ByteStream\\ResourceOutputStream' => $vendorDir . '/amphp/byte-stream/lib/ResourceOutputStream.php', '_HumbugBox7ff99e199a36\\Amp\\ByteStream\\StreamException' => $vendorDir . '/amphp/byte-stream/lib/StreamException.php', '_HumbugBox7ff99e199a36\\Amp\\ByteStream\\ZlibInputStream' => $vendorDir . '/amphp/byte-stream/lib/ZlibInputStream.php', '_HumbugBox7ff99e199a36\\Amp\\ByteStream\\ZlibOutputStream' => $vendorDir . '/amphp/byte-stream/lib/ZlibOutputStream.php', '_HumbugBox7ff99e199a36\\Amp\\CallableMaker' => $vendorDir . '/amphp/amp/lib/CallableMaker.php', '_HumbugBox7ff99e199a36\\Amp\\CancellationToken' => $vendorDir . '/amphp/amp/lib/CancellationToken.php', '_HumbugBox7ff99e199a36\\Amp\\CancellationTokenSource' => $vendorDir . '/amphp/amp/lib/CancellationTokenSource.php', '_HumbugBox7ff99e199a36\\Amp\\CancelledException' => $vendorDir . '/amphp/amp/lib/CancelledException.php', '_HumbugBox7ff99e199a36\\Amp\\CombinedCancellationToken' => $vendorDir . '/amphp/amp/lib/CombinedCancellationToken.php', '_HumbugBox7ff99e199a36\\Amp\\Coroutine' => $vendorDir . '/amphp/amp/lib/Coroutine.php', '_HumbugBox7ff99e199a36\\Amp\\Deferred' => $vendorDir . '/amphp/amp/lib/Deferred.php', '_HumbugBox7ff99e199a36\\Amp\\Delayed' => $vendorDir . '/amphp/amp/lib/Delayed.php', '_HumbugBox7ff99e199a36\\Amp\\Emitter' => $vendorDir . '/amphp/amp/lib/Emitter.php', '_HumbugBox7ff99e199a36\\Amp\\Failure' => $vendorDir . '/amphp/amp/lib/Failure.php', '_HumbugBox7ff99e199a36\\Amp\\Internal\\Placeholder' => $vendorDir . '/amphp/amp/lib/Internal/Placeholder.php', '_HumbugBox7ff99e199a36\\Amp\\Internal\\PrivateIterator' => $vendorDir . '/amphp/amp/lib/Internal/PrivateIterator.php', '_HumbugBox7ff99e199a36\\Amp\\Internal\\PrivatePromise' => $vendorDir . '/amphp/amp/lib/Internal/PrivatePromise.php', '_HumbugBox7ff99e199a36\\Amp\\Internal\\Producer' => $vendorDir . '/amphp/amp/lib/Internal/Producer.php', '_HumbugBox7ff99e199a36\\Amp\\Internal\\ResolutionQueue' => $vendorDir . '/amphp/amp/lib/Internal/ResolutionQueue.php', '_HumbugBox7ff99e199a36\\Amp\\InvalidYieldError' => $vendorDir . '/amphp/amp/lib/InvalidYieldError.php', '_HumbugBox7ff99e199a36\\Amp\\Iterator' => $vendorDir . '/amphp/amp/lib/Iterator.php', '_HumbugBox7ff99e199a36\\Amp\\LazyPromise' => $vendorDir . '/amphp/amp/lib/LazyPromise.php', '_HumbugBox7ff99e199a36\\Amp\\Loop' => $vendorDir . '/amphp/amp/lib/Loop.php', '_HumbugBox7ff99e199a36\\Amp\\Loop\\Driver' => $vendorDir . '/amphp/amp/lib/Loop/Driver.php', '_HumbugBox7ff99e199a36\\Amp\\Loop\\DriverFactory' => $vendorDir . '/amphp/amp/lib/Loop/DriverFactory.php', '_HumbugBox7ff99e199a36\\Amp\\Loop\\EvDriver' => $vendorDir . '/amphp/amp/lib/Loop/EvDriver.php', '_HumbugBox7ff99e199a36\\Amp\\Loop\\EventDriver' => $vendorDir . '/amphp/amp/lib/Loop/EventDriver.php', '_HumbugBox7ff99e199a36\\Amp\\Loop\\Internal\\TimerQueue' => $vendorDir . '/amphp/amp/lib/Loop/Internal/TimerQueue.php', '_HumbugBox7ff99e199a36\\Amp\\Loop\\InvalidWatcherError' => $vendorDir . '/amphp/amp/lib/Loop/InvalidWatcherError.php', '_HumbugBox7ff99e199a36\\Amp\\Loop\\NativeDriver' => $vendorDir . '/amphp/amp/lib/Loop/NativeDriver.php', '_HumbugBox7ff99e199a36\\Amp\\Loop\\TracingDriver' => $vendorDir . '/amphp/amp/lib/Loop/TracingDriver.php', '_HumbugBox7ff99e199a36\\Amp\\Loop\\UnsupportedFeatureException' => $vendorDir . '/amphp/amp/lib/Loop/UnsupportedFeatureException.php', '_HumbugBox7ff99e199a36\\Amp\\Loop\\UvDriver' => $vendorDir . '/amphp/amp/lib/Loop/UvDriver.php', '_HumbugBox7ff99e199a36\\Amp\\Loop\\Watcher' => $vendorDir . '/amphp/amp/lib/Loop/Watcher.php', '_HumbugBox7ff99e199a36\\Amp\\MultiReasonException' => $vendorDir . '/amphp/amp/lib/MultiReasonException.php', '_HumbugBox7ff99e199a36\\Amp\\NullCancellationToken' => $vendorDir . '/amphp/amp/lib/NullCancellationToken.php', '_HumbugBox7ff99e199a36\\Amp\\Producer' => $vendorDir . '/amphp/amp/lib/Producer.php', '_HumbugBox7ff99e199a36\\Amp\\Promise' => $vendorDir . '/amphp/amp/lib/Promise.php', '_HumbugBox7ff99e199a36\\Amp\\Struct' => $vendorDir . '/amphp/amp/lib/Struct.php', '_HumbugBox7ff99e199a36\\Amp\\Success' => $vendorDir . '/amphp/amp/lib/Success.php', '_HumbugBox7ff99e199a36\\Amp\\TimeoutCancellationToken' => $vendorDir . '/amphp/amp/lib/TimeoutCancellationToken.php', '_HumbugBox7ff99e199a36\\Amp\\TimeoutException' => $vendorDir . '/amphp/amp/lib/TimeoutException.php', '_HumbugBox7ff99e199a36\\Composer\\Pcre\\MatchAllResult' => $vendorDir . '/composer/pcre/src/MatchAllResult.php', '_HumbugBox7ff99e199a36\\Composer\\Pcre\\MatchAllStrictGroupsResult' => $vendorDir . '/composer/pcre/src/MatchAllStrictGroupsResult.php', '_HumbugBox7ff99e199a36\\Composer\\Pcre\\MatchAllWithOffsetsResult' => $vendorDir . '/composer/pcre/src/MatchAllWithOffsetsResult.php', '_HumbugBox7ff99e199a36\\Composer\\Pcre\\MatchResult' => $vendorDir . '/composer/pcre/src/MatchResult.php', '_HumbugBox7ff99e199a36\\Composer\\Pcre\\MatchStrictGroupsResult' => $vendorDir . '/composer/pcre/src/MatchStrictGroupsResult.php', '_HumbugBox7ff99e199a36\\Composer\\Pcre\\MatchWithOffsetsResult' => $vendorDir . '/composer/pcre/src/MatchWithOffsetsResult.php', '_HumbugBox7ff99e199a36\\Composer\\Pcre\\PHPStan\\InvalidRegexPatternRule' => $vendorDir . '/composer/pcre/src/PHPStan/InvalidRegexPatternRule.php', '_HumbugBox7ff99e199a36\\Composer\\Pcre\\PHPStan\\PregMatchFlags' => $vendorDir . '/composer/pcre/src/PHPStan/PregMatchFlags.php', '_HumbugBox7ff99e199a36\\Composer\\Pcre\\PHPStan\\PregMatchParameterOutTypeExtension' => $vendorDir . '/composer/pcre/src/PHPStan/PregMatchParameterOutTypeExtension.php', '_HumbugBox7ff99e199a36\\Composer\\Pcre\\PHPStan\\PregMatchTypeSpecifyingExtension' => $vendorDir . '/composer/pcre/src/PHPStan/PregMatchTypeSpecifyingExtension.php', '_HumbugBox7ff99e199a36\\Composer\\Pcre\\PHPStan\\PregReplaceCallbackClosureTypeExtension' => $vendorDir . '/composer/pcre/src/PHPStan/PregReplaceCallbackClosureTypeExtension.php', '_HumbugBox7ff99e199a36\\Composer\\Pcre\\PHPStan\\UnsafeStrictGroupsCallRule' => $vendorDir . '/composer/pcre/src/PHPStan/UnsafeStrictGroupsCallRule.php', '_HumbugBox7ff99e199a36\\Composer\\Pcre\\PcreException' => $vendorDir . '/composer/pcre/src/PcreException.php', '_HumbugBox7ff99e199a36\\Composer\\Pcre\\Preg' => $vendorDir . '/composer/pcre/src/Preg.php', '_HumbugBox7ff99e199a36\\Composer\\Pcre\\Regex' => $vendorDir . '/composer/pcre/src/Regex.php', '_HumbugBox7ff99e199a36\\Composer\\Pcre\\ReplaceResult' => $vendorDir . '/composer/pcre/src/ReplaceResult.php', '_HumbugBox7ff99e199a36\\Composer\\Pcre\\UnexpectedNullMatchException' => $vendorDir . '/composer/pcre/src/UnexpectedNullMatchException.php', '_HumbugBox7ff99e199a36\\Composer\\Semver\\Comparator' => $vendorDir . '/composer/semver/src/Comparator.php', '_HumbugBox7ff99e199a36\\Composer\\Semver\\CompilingMatcher' => $vendorDir . '/composer/semver/src/CompilingMatcher.php', '_HumbugBox7ff99e199a36\\Composer\\Semver\\Constraint\\Bound' => $vendorDir . '/composer/semver/src/Constraint/Bound.php', '_HumbugBox7ff99e199a36\\Composer\\Semver\\Constraint\\Constraint' => $vendorDir . '/composer/semver/src/Constraint/Constraint.php', '_HumbugBox7ff99e199a36\\Composer\\Semver\\Constraint\\ConstraintInterface' => $vendorDir . '/composer/semver/src/Constraint/ConstraintInterface.php', '_HumbugBox7ff99e199a36\\Composer\\Semver\\Constraint\\MatchAllConstraint' => $vendorDir . '/composer/semver/src/Constraint/MatchAllConstraint.php', '_HumbugBox7ff99e199a36\\Composer\\Semver\\Constraint\\MatchNoneConstraint' => $vendorDir . '/composer/semver/src/Constraint/MatchNoneConstraint.php', '_HumbugBox7ff99e199a36\\Composer\\Semver\\Constraint\\MultiConstraint' => $vendorDir . '/composer/semver/src/Constraint/MultiConstraint.php', '_HumbugBox7ff99e199a36\\Composer\\Semver\\Interval' => $vendorDir . '/composer/semver/src/Interval.php', '_HumbugBox7ff99e199a36\\Composer\\Semver\\Intervals' => $vendorDir . '/composer/semver/src/Intervals.php', '_HumbugBox7ff99e199a36\\Composer\\Semver\\Semver' => $vendorDir . '/composer/semver/src/Semver.php', '_HumbugBox7ff99e199a36\\Composer\\Semver\\VersionParser' => $vendorDir . '/composer/semver/src/VersionParser.php', '_HumbugBox7ff99e199a36\\Composer\\XdebugHandler\\PhpConfig' => $vendorDir . '/composer/xdebug-handler/src/PhpConfig.php', '_HumbugBox7ff99e199a36\\Composer\\XdebugHandler\\Process' => $vendorDir . '/composer/xdebug-handler/src/Process.php', '_HumbugBox7ff99e199a36\\Composer\\XdebugHandler\\Status' => $vendorDir . '/composer/xdebug-handler/src/Status.php', '_HumbugBox7ff99e199a36\\Composer\\XdebugHandler\\XdebugHandler' => $vendorDir . '/composer/xdebug-handler/src/XdebugHandler.php', '_HumbugBox7ff99e199a36\\Doctrine\\Deprecations\\Deprecation' => $vendorDir . '/doctrine/deprecations/lib/Doctrine/Deprecations/Deprecation.php', '_HumbugBox7ff99e199a36\\Doctrine\\Deprecations\\PHPUnit\\VerifyDeprecations' => $vendorDir . '/doctrine/deprecations/lib/Doctrine/Deprecations/PHPUnit/VerifyDeprecations.php', '_HumbugBox7ff99e199a36\\Fidry\\CpuCoreCounter\\CpuCoreCounter' => $vendorDir . '/fidry/cpu-core-counter/src/CpuCoreCounter.php', '_HumbugBox7ff99e199a36\\Fidry\\CpuCoreCounter\\Diagnoser' => $vendorDir . '/fidry/cpu-core-counter/src/Diagnoser.php', '_HumbugBox7ff99e199a36\\Fidry\\CpuCoreCounter\\Executor\\ProcOpenExecutor' => $vendorDir . '/fidry/cpu-core-counter/src/Executor/ProcOpenExecutor.php', '_HumbugBox7ff99e199a36\\Fidry\\CpuCoreCounter\\Executor\\ProcessExecutor' => $vendorDir . '/fidry/cpu-core-counter/src/Executor/ProcessExecutor.php', '_HumbugBox7ff99e199a36\\Fidry\\CpuCoreCounter\\Finder\\CmiCmdletLogicalFinder' => $vendorDir . '/fidry/cpu-core-counter/src/Finder/CmiCmdletLogicalFinder.php', '_HumbugBox7ff99e199a36\\Fidry\\CpuCoreCounter\\Finder\\CmiCmdletPhysicalFinder' => $vendorDir . '/fidry/cpu-core-counter/src/Finder/CmiCmdletPhysicalFinder.php', '_HumbugBox7ff99e199a36\\Fidry\\CpuCoreCounter\\Finder\\CpuCoreFinder' => $vendorDir . '/fidry/cpu-core-counter/src/Finder/CpuCoreFinder.php', '_HumbugBox7ff99e199a36\\Fidry\\CpuCoreCounter\\Finder\\CpuInfoFinder' => $vendorDir . '/fidry/cpu-core-counter/src/Finder/CpuInfoFinder.php', '_HumbugBox7ff99e199a36\\Fidry\\CpuCoreCounter\\Finder\\DummyCpuCoreFinder' => $vendorDir . '/fidry/cpu-core-counter/src/Finder/DummyCpuCoreFinder.php', '_HumbugBox7ff99e199a36\\Fidry\\CpuCoreCounter\\Finder\\EnvVariableFinder' => $vendorDir . '/fidry/cpu-core-counter/src/Finder/EnvVariableFinder.php', '_HumbugBox7ff99e199a36\\Fidry\\CpuCoreCounter\\Finder\\FinderRegistry' => $vendorDir . '/fidry/cpu-core-counter/src/Finder/FinderRegistry.php', '_HumbugBox7ff99e199a36\\Fidry\\CpuCoreCounter\\Finder\\HwLogicalFinder' => $vendorDir . '/fidry/cpu-core-counter/src/Finder/HwLogicalFinder.php', '_HumbugBox7ff99e199a36\\Fidry\\CpuCoreCounter\\Finder\\HwPhysicalFinder' => $vendorDir . '/fidry/cpu-core-counter/src/Finder/HwPhysicalFinder.php', '_HumbugBox7ff99e199a36\\Fidry\\CpuCoreCounter\\Finder\\LscpuLogicalFinder' => $vendorDir . '/fidry/cpu-core-counter/src/Finder/LscpuLogicalFinder.php', '_HumbugBox7ff99e199a36\\Fidry\\CpuCoreCounter\\Finder\\LscpuPhysicalFinder' => $vendorDir . '/fidry/cpu-core-counter/src/Finder/LscpuPhysicalFinder.php', '_HumbugBox7ff99e199a36\\Fidry\\CpuCoreCounter\\Finder\\NProcFinder' => $vendorDir . '/fidry/cpu-core-counter/src/Finder/NProcFinder.php', '_HumbugBox7ff99e199a36\\Fidry\\CpuCoreCounter\\Finder\\NProcessorFinder' => $vendorDir . '/fidry/cpu-core-counter/src/Finder/NProcessorFinder.php', '_HumbugBox7ff99e199a36\\Fidry\\CpuCoreCounter\\Finder\\NullCpuCoreFinder' => $vendorDir . '/fidry/cpu-core-counter/src/Finder/NullCpuCoreFinder.php', '_HumbugBox7ff99e199a36\\Fidry\\CpuCoreCounter\\Finder\\OnlyInPowerShellFinder' => $vendorDir . '/fidry/cpu-core-counter/src/Finder/OnlyInPowerShellFinder.php', '_HumbugBox7ff99e199a36\\Fidry\\CpuCoreCounter\\Finder\\OnlyOnOSFamilyFinder' => $vendorDir . '/fidry/cpu-core-counter/src/Finder/OnlyOnOSFamilyFinder.php', '_HumbugBox7ff99e199a36\\Fidry\\CpuCoreCounter\\Finder\\ProcOpenBasedFinder' => $vendorDir . '/fidry/cpu-core-counter/src/Finder/ProcOpenBasedFinder.php', '_HumbugBox7ff99e199a36\\Fidry\\CpuCoreCounter\\Finder\\SkipOnOSFamilyFinder' => $vendorDir . '/fidry/cpu-core-counter/src/Finder/SkipOnOSFamilyFinder.php', '_HumbugBox7ff99e199a36\\Fidry\\CpuCoreCounter\\Finder\\WindowsRegistryLogicalFinder' => $vendorDir . '/fidry/cpu-core-counter/src/Finder/WindowsRegistryLogicalFinder.php', '_HumbugBox7ff99e199a36\\Fidry\\CpuCoreCounter\\Finder\\WmicLogicalFinder' => $vendorDir . '/fidry/cpu-core-counter/src/Finder/WmicLogicalFinder.php', '_HumbugBox7ff99e199a36\\Fidry\\CpuCoreCounter\\Finder\\WmicPhysicalFinder' => $vendorDir . '/fidry/cpu-core-counter/src/Finder/WmicPhysicalFinder.php', '_HumbugBox7ff99e199a36\\Fidry\\CpuCoreCounter\\Finder\\_NProcessorFinder' => $vendorDir . '/fidry/cpu-core-counter/src/Finder/_NProcessorFinder.php', '_HumbugBox7ff99e199a36\\Fidry\\CpuCoreCounter\\NumberOfCpuCoreNotFound' => $vendorDir . '/fidry/cpu-core-counter/src/NumberOfCpuCoreNotFound.php', '_HumbugBox7ff99e199a36\\Fidry\\CpuCoreCounter\\ParallelisationResult' => $vendorDir . '/fidry/cpu-core-counter/src/ParallelisationResult.php', '_HumbugBox7ff99e199a36\\JsonException' => $vendorDir . '/symfony/polyfill-php73/Resources/stubs/JsonException.php', '_HumbugBox7ff99e199a36\\JsonMapper_Exception' => $vendorDir . '/netresearch/jsonmapper/src/JsonMapper/Exception.php', '_HumbugBox7ff99e199a36\\LanguageServerProtocol\\CallHierarchyClientCapabilities' => $vendorDir . '/felixfbecker/language-server-protocol/src/CallHierarchyClientCapabilities.php', '_HumbugBox7ff99e199a36\\LanguageServerProtocol\\ChangeAnnotation' => $vendorDir . '/felixfbecker/language-server-protocol/src/ChangeAnnotation.php', '_HumbugBox7ff99e199a36\\LanguageServerProtocol\\ClientCapabilities' => $vendorDir . '/felixfbecker/language-server-protocol/src/ClientCapabilities.php', '_HumbugBox7ff99e199a36\\LanguageServerProtocol\\ClientCapabilitiesGeneral' => $vendorDir . '/felixfbecker/language-server-protocol/src/ClientCapabilitiesGeneral.php', '_HumbugBox7ff99e199a36\\LanguageServerProtocol\\ClientCapabilitiesWindow' => $vendorDir . '/felixfbecker/language-server-protocol/src/ClientCapabilitiesWindow.php', '_HumbugBox7ff99e199a36\\LanguageServerProtocol\\ClientCapabilitiesWorkspace' => $vendorDir . '/felixfbecker/language-server-protocol/src/ClientCapabilitiesWorkspace.php', '_HumbugBox7ff99e199a36\\LanguageServerProtocol\\ClientCapabilitiesWorkspaceFileOperations' => $vendorDir . '/felixfbecker/language-server-protocol/src/ClientCapabilitiesWorkspaceFileOperations.php', '_HumbugBox7ff99e199a36\\LanguageServerProtocol\\ClientInfo' => $vendorDir . '/felixfbecker/language-server-protocol/src/ClientInfo.php', '_HumbugBox7ff99e199a36\\LanguageServerProtocol\\CodeAction' => $vendorDir . '/felixfbecker/language-server-protocol/src/CodeAction.php', '_HumbugBox7ff99e199a36\\LanguageServerProtocol\\CodeActionClientCapabilities' => $vendorDir . '/felixfbecker/language-server-protocol/src/CodeActionClientCapabilities.php', '_HumbugBox7ff99e199a36\\LanguageServerProtocol\\CodeActionClientCapabilitiesCodeActionLiteralSupport' => $vendorDir . '/felixfbecker/language-server-protocol/src/CodeActionClientCapabilitiesCodeActionLiteralSupport.php', '_HumbugBox7ff99e199a36\\LanguageServerProtocol\\CodeActionClientCapabilitiesCodeActionLiteralSupportcodeActionKind' => $vendorDir . '/felixfbecker/language-server-protocol/src/CodeActionClientCapabilitiesCodeActionLiteralSupportcodeActionKind.php', '_HumbugBox7ff99e199a36\\LanguageServerProtocol\\CodeActionClientCapabilitiesResolveSupport' => $vendorDir . '/felixfbecker/language-server-protocol/src/CodeActionClientCapabilitiesResolveSupport.php', '_HumbugBox7ff99e199a36\\LanguageServerProtocol\\CodeActionContext' => $vendorDir . '/felixfbecker/language-server-protocol/src/CodeActionContext.php', '_HumbugBox7ff99e199a36\\LanguageServerProtocol\\CodeActionDisabled' => $vendorDir . '/felixfbecker/language-server-protocol/src/CodeActionDisabled.php', '_HumbugBox7ff99e199a36\\LanguageServerProtocol\\CodeActionKind' => $vendorDir . '/felixfbecker/language-server-protocol/src/CodeActionKind.php', '_HumbugBox7ff99e199a36\\LanguageServerProtocol\\CodeActionTriggerKind' => $vendorDir . '/felixfbecker/language-server-protocol/src/CodeActionTriggerKind.php', '_HumbugBox7ff99e199a36\\LanguageServerProtocol\\CodeDescription' => $vendorDir . '/felixfbecker/language-server-protocol/src/CodeDescription.php', '_HumbugBox7ff99e199a36\\LanguageServerProtocol\\CodeLens' => $vendorDir . '/felixfbecker/language-server-protocol/src/CodeLens.php', '_HumbugBox7ff99e199a36\\LanguageServerProtocol\\CodeLensClientCapabilities' => $vendorDir . '/felixfbecker/language-server-protocol/src/CodeLensClientCapabilities.php', '_HumbugBox7ff99e199a36\\LanguageServerProtocol\\CodeLensOptions' => $vendorDir . '/felixfbecker/language-server-protocol/src/CodeLensOptions.php', '_HumbugBox7ff99e199a36\\LanguageServerProtocol\\CodeLensWorkspaceClientCapabilities' => $vendorDir . '/felixfbecker/language-server-protocol/src/CodeLensWorkspaceClientCapabilities.php', '_HumbugBox7ff99e199a36\\LanguageServerProtocol\\Command' => $vendorDir . '/felixfbecker/language-server-protocol/src/Command.php', '_HumbugBox7ff99e199a36\\LanguageServerProtocol\\CompletionClientCapabilities' => $vendorDir . '/felixfbecker/language-server-protocol/src/CompletionClientCapabilities.php', '_HumbugBox7ff99e199a36\\LanguageServerProtocol\\CompletionClientCapabilitiesCompletionItem' => $vendorDir . '/felixfbecker/language-server-protocol/src/CompletionClientCapabilitiesCompletionItem.php', '_HumbugBox7ff99e199a36\\LanguageServerProtocol\\CompletionClientCapabilitiesCompletionItemInsertTextModeSupport' => $vendorDir . '/felixfbecker/language-server-protocol/src/CompletionClientCapabilitiesCompletionItemInsertTextModeSupport.php', '_HumbugBox7ff99e199a36\\LanguageServerProtocol\\CompletionClientCapabilitiesCompletionItemResolveSupport' => $vendorDir . '/felixfbecker/language-server-protocol/src/CompletionClientCapabilitiesCompletionItemResolveSupport.php', '_HumbugBox7ff99e199a36\\LanguageServerProtocol\\CompletionClientCapabilitiesCompletionItemTagSupport' => $vendorDir . '/felixfbecker/language-server-protocol/src/CompletionClientCapabilitiesCompletionItemTagSupport.php', '_HumbugBox7ff99e199a36\\LanguageServerProtocol\\CompletionClientCapabilitiesCompletionList' => $vendorDir . '/felixfbecker/language-server-protocol/src/CompletionClientCapabilitiesCompletionList.php', '_HumbugBox7ff99e199a36\\LanguageServerProtocol\\CompletionContext' => $vendorDir . '/felixfbecker/language-server-protocol/src/CompletionContext.php', '_HumbugBox7ff99e199a36\\LanguageServerProtocol\\CompletionItem' => $vendorDir . '/felixfbecker/language-server-protocol/src/CompletionItem.php', '_HumbugBox7ff99e199a36\\LanguageServerProtocol\\CompletionItemKind' => $vendorDir . '/felixfbecker/language-server-protocol/src/CompletionItemKind.php', '_HumbugBox7ff99e199a36\\LanguageServerProtocol\\CompletionItemLabelDetails' => $vendorDir . '/felixfbecker/language-server-protocol/src/CompletionItemLabelDetails.php', '_HumbugBox7ff99e199a36\\LanguageServerProtocol\\CompletionItemTag' => $vendorDir . '/felixfbecker/language-server-protocol/src/CompletionItemTag.php', '_HumbugBox7ff99e199a36\\LanguageServerProtocol\\CompletionList' => $vendorDir . '/felixfbecker/language-server-protocol/src/CompletionList.php', '_HumbugBox7ff99e199a36\\LanguageServerProtocol\\CompletionOptions' => $vendorDir . '/felixfbecker/language-server-protocol/src/CompletionOptions.php', '_HumbugBox7ff99e199a36\\LanguageServerProtocol\\CompletionTriggerKind' => $vendorDir . '/felixfbecker/language-server-protocol/src/CompletionTriggerKind.php', '_HumbugBox7ff99e199a36\\LanguageServerProtocol\\ContentChangeEvent' => $vendorDir . '/felixfbecker/language-server-protocol/src/ContentChangeEvent.php', '_HumbugBox7ff99e199a36\\LanguageServerProtocol\\DeclarationClientCapabilities' => $vendorDir . '/felixfbecker/language-server-protocol/src/DeclarationClientCapabilities.php', '_HumbugBox7ff99e199a36\\LanguageServerProtocol\\DefinitionClientCapabilities' => $vendorDir . '/felixfbecker/language-server-protocol/src/DefinitionClientCapabilities.php', '_HumbugBox7ff99e199a36\\LanguageServerProtocol\\DependencyReference' => $vendorDir . '/felixfbecker/language-server-protocol/src/DependencyReference.php', '_HumbugBox7ff99e199a36\\LanguageServerProtocol\\Diagnostic' => $vendorDir . '/felixfbecker/language-server-protocol/src/Diagnostic.php', '_HumbugBox7ff99e199a36\\LanguageServerProtocol\\DiagnosticRelatedInformation' => $vendorDir . '/felixfbecker/language-server-protocol/src/DiagnosticRelatedInformation.php', '_HumbugBox7ff99e199a36\\LanguageServerProtocol\\DiagnosticSeverity' => $vendorDir . '/felixfbecker/language-server-protocol/src/DiagnosticSeverity.php', '_HumbugBox7ff99e199a36\\LanguageServerProtocol\\DiagnosticTag' => $vendorDir . '/felixfbecker/language-server-protocol/src/DiagnosticTag.php', '_HumbugBox7ff99e199a36\\LanguageServerProtocol\\DidChangeConfigurationClientCapabilities' => $vendorDir . '/felixfbecker/language-server-protocol/src/DidChangeConfigurationClientCapabilities.php', '_HumbugBox7ff99e199a36\\LanguageServerProtocol\\DidChangeWatchedFilesClientCapabilities' => $vendorDir . '/felixfbecker/language-server-protocol/src/DidChangeWatchedFilesClientCapabilities.php', '_HumbugBox7ff99e199a36\\LanguageServerProtocol\\DocumentColorClientCapabilities' => $vendorDir . '/felixfbecker/language-server-protocol/src/DocumentColorClientCapabilities.php', '_HumbugBox7ff99e199a36\\LanguageServerProtocol\\DocumentFormattingClientCapabilities' => $vendorDir . '/felixfbecker/language-server-protocol/src/DocumentFormattingClientCapabilities.php', '_HumbugBox7ff99e199a36\\LanguageServerProtocol\\DocumentHighlight' => $vendorDir . '/felixfbecker/language-server-protocol/src/DocumentHighlight.php', '_HumbugBox7ff99e199a36\\LanguageServerProtocol\\DocumentHighlightClientCapabilities' => $vendorDir . '/felixfbecker/language-server-protocol/src/DocumentHighlightClientCapabilities.php', '_HumbugBox7ff99e199a36\\LanguageServerProtocol\\DocumentHighlightKind' => $vendorDir . '/felixfbecker/language-server-protocol/src/DocumentHighlightKind.php', '_HumbugBox7ff99e199a36\\LanguageServerProtocol\\DocumentLinkClientCapabilities' => $vendorDir . '/felixfbecker/language-server-protocol/src/DocumentLinkClientCapabilities.php', '_HumbugBox7ff99e199a36\\LanguageServerProtocol\\DocumentOnTypeFormattingClientCapabilities' => $vendorDir . '/felixfbecker/language-server-protocol/src/DocumentOnTypeFormattingClientCapabilities.php', '_HumbugBox7ff99e199a36\\LanguageServerProtocol\\DocumentOnTypeFormattingOptions' => $vendorDir . '/felixfbecker/language-server-protocol/src/DocumentOnTypeFormattingOptions.php', '_HumbugBox7ff99e199a36\\LanguageServerProtocol\\DocumentRangeFormattingClientCapabilities' => $vendorDir . '/felixfbecker/language-server-protocol/src/DocumentRangeFormattingClientCapabilities.php', '_HumbugBox7ff99e199a36\\LanguageServerProtocol\\DocumentSymbolClientCapabilities' => $vendorDir . '/felixfbecker/language-server-protocol/src/DocumentSymbolClientCapabilities.php', '_HumbugBox7ff99e199a36\\LanguageServerProtocol\\DocumentSymbolClientCapabilitiesSymbolKind' => $vendorDir . '/felixfbecker/language-server-protocol/src/DocumentSymbolClientCapabilitiesSymbolKind.php', '_HumbugBox7ff99e199a36\\LanguageServerProtocol\\DocumentSymbolClientCapabilitiesTagSupport' => $vendorDir . '/felixfbecker/language-server-protocol/src/DocumentSymbolClientCapabilitiesTagSupport.php', '_HumbugBox7ff99e199a36\\LanguageServerProtocol\\ErrorCode' => $vendorDir . '/felixfbecker/language-server-protocol/src/ErrorCode.php', '_HumbugBox7ff99e199a36\\LanguageServerProtocol\\ExecuteCommandClientCapabilities' => $vendorDir . '/felixfbecker/language-server-protocol/src/ExecuteCommandClientCapabilities.php', '_HumbugBox7ff99e199a36\\LanguageServerProtocol\\ExecuteCommandOptions' => $vendorDir . '/felixfbecker/language-server-protocol/src/ExecuteCommandOptions.php', '_HumbugBox7ff99e199a36\\LanguageServerProtocol\\FailureHandlingKind' => $vendorDir . '/felixfbecker/language-server-protocol/src/FailureHandlingKind.php', '_HumbugBox7ff99e199a36\\LanguageServerProtocol\\FileChangeType' => $vendorDir . '/felixfbecker/language-server-protocol/src/FileChangeType.php', '_HumbugBox7ff99e199a36\\LanguageServerProtocol\\FileEvent' => $vendorDir . '/felixfbecker/language-server-protocol/src/FileEvent.php', '_HumbugBox7ff99e199a36\\LanguageServerProtocol\\FoldingRangeClientCapabilities' => $vendorDir . '/felixfbecker/language-server-protocol/src/FoldingRangeClientCapabilities.php', '_HumbugBox7ff99e199a36\\LanguageServerProtocol\\FormattingOptions' => $vendorDir . '/felixfbecker/language-server-protocol/src/FormattingOptions.php', '_HumbugBox7ff99e199a36\\LanguageServerProtocol\\Hover' => $vendorDir . '/felixfbecker/language-server-protocol/src/Hover.php', '_HumbugBox7ff99e199a36\\LanguageServerProtocol\\HoverClientCapabilities' => $vendorDir . '/felixfbecker/language-server-protocol/src/HoverClientCapabilities.php', '_HumbugBox7ff99e199a36\\LanguageServerProtocol\\ImplementationClientCapabilities' => $vendorDir . '/felixfbecker/language-server-protocol/src/ImplementationClientCapabilities.php', '_HumbugBox7ff99e199a36\\LanguageServerProtocol\\InitializeResult' => $vendorDir . '/felixfbecker/language-server-protocol/src/InitializeResult.php', '_HumbugBox7ff99e199a36\\LanguageServerProtocol\\InitializeResultServerInfo' => $vendorDir . '/felixfbecker/language-server-protocol/src/InitializeResultServerInfo.php', '_HumbugBox7ff99e199a36\\LanguageServerProtocol\\InsertTextFormat' => $vendorDir . '/felixfbecker/language-server-protocol/src/InsertTextFormat.php', '_HumbugBox7ff99e199a36\\LanguageServerProtocol\\InsertTextMode' => $vendorDir . '/felixfbecker/language-server-protocol/src/InsertTextMode.php', '_HumbugBox7ff99e199a36\\LanguageServerProtocol\\LinkedEditingRangeClientCapabilities' => $vendorDir . '/felixfbecker/language-server-protocol/src/LinkedEditingRangeClientCapabilities.php', '_HumbugBox7ff99e199a36\\LanguageServerProtocol\\Location' => $vendorDir . '/felixfbecker/language-server-protocol/src/Location.php', '_HumbugBox7ff99e199a36\\LanguageServerProtocol\\LogMessage' => $vendorDir . '/felixfbecker/language-server-protocol/src/LogMessage.php', '_HumbugBox7ff99e199a36\\LanguageServerProtocol\\LogTrace' => $vendorDir . '/felixfbecker/language-server-protocol/src/LogTrace.php', '_HumbugBox7ff99e199a36\\LanguageServerProtocol\\MarkdownClientCapabilities' => $vendorDir . '/felixfbecker/language-server-protocol/src/MarkdownClientCapabilities.php', '_HumbugBox7ff99e199a36\\LanguageServerProtocol\\MarkedString' => $vendorDir . '/felixfbecker/language-server-protocol/src/MarkedString.php', '_HumbugBox7ff99e199a36\\LanguageServerProtocol\\MarkupContent' => $vendorDir . '/felixfbecker/language-server-protocol/src/MarkupContent.php', '_HumbugBox7ff99e199a36\\LanguageServerProtocol\\MarkupKind' => $vendorDir . '/felixfbecker/language-server-protocol/src/MarkupKind.php', '_HumbugBox7ff99e199a36\\LanguageServerProtocol\\MessageActionItem' => $vendorDir . '/felixfbecker/language-server-protocol/src/MessageActionItem.php', '_HumbugBox7ff99e199a36\\LanguageServerProtocol\\MessageType' => $vendorDir . '/felixfbecker/language-server-protocol/src/MessageType.php', '_HumbugBox7ff99e199a36\\LanguageServerProtocol\\MonikerClientCapabilities' => $vendorDir . '/felixfbecker/language-server-protocol/src/MonikerClientCapabilities.php', '_HumbugBox7ff99e199a36\\LanguageServerProtocol\\PackageDescriptor' => $vendorDir . '/felixfbecker/language-server-protocol/src/PackageDescriptor.php', '_HumbugBox7ff99e199a36\\LanguageServerProtocol\\ParameterInformation' => $vendorDir . '/felixfbecker/language-server-protocol/src/ParameterInformation.php', '_HumbugBox7ff99e199a36\\LanguageServerProtocol\\Position' => $vendorDir . '/felixfbecker/language-server-protocol/src/Position.php', '_HumbugBox7ff99e199a36\\LanguageServerProtocol\\PrepareSupportDefaultBehavior' => $vendorDir . '/felixfbecker/language-server-protocol/src/PrepareSupportDefaultBehavior.php', '_HumbugBox7ff99e199a36\\LanguageServerProtocol\\PublishDiagnosticsClientCapabilities' => $vendorDir . '/felixfbecker/language-server-protocol/src/PublishDiagnosticsClientCapabilities.php', '_HumbugBox7ff99e199a36\\LanguageServerProtocol\\PublishDiagnosticsClientCapabilitiesTagSupport' => $vendorDir . '/felixfbecker/language-server-protocol/src/PublishDiagnosticsClientCapabilitiesTagSupport.php', '_HumbugBox7ff99e199a36\\LanguageServerProtocol\\Range' => $vendorDir . '/felixfbecker/language-server-protocol/src/Range.php', '_HumbugBox7ff99e199a36\\LanguageServerProtocol\\ReferenceClientCapabilities' => $vendorDir . '/felixfbecker/language-server-protocol/src/ReferenceClientCapabilities.php', '_HumbugBox7ff99e199a36\\LanguageServerProtocol\\ReferenceContext' => $vendorDir . '/felixfbecker/language-server-protocol/src/ReferenceContext.php', '_HumbugBox7ff99e199a36\\LanguageServerProtocol\\ReferenceInformation' => $vendorDir . '/felixfbecker/language-server-protocol/src/ReferenceInformation.php', '_HumbugBox7ff99e199a36\\LanguageServerProtocol\\RegularExpressionsClientCapabilities' => $vendorDir . '/felixfbecker/language-server-protocol/src/RegularExpressionsClientCapabilities.php', '_HumbugBox7ff99e199a36\\LanguageServerProtocol\\RenameClientCapabilities' => $vendorDir . '/felixfbecker/language-server-protocol/src/RenameClientCapabilities.php', '_HumbugBox7ff99e199a36\\LanguageServerProtocol\\ResourceOperationKind' => $vendorDir . '/felixfbecker/language-server-protocol/src/ResourceOperationKind.php', '_HumbugBox7ff99e199a36\\LanguageServerProtocol\\SaveOptions' => $vendorDir . '/felixfbecker/language-server-protocol/src/SaveOptions.php', '_HumbugBox7ff99e199a36\\LanguageServerProtocol\\SelectionRangeClientCapabilities' => $vendorDir . '/felixfbecker/language-server-protocol/src/SelectionRangeClientCapabilities.php', '_HumbugBox7ff99e199a36\\LanguageServerProtocol\\SemanticTokensClientCapabilities' => $vendorDir . '/felixfbecker/language-server-protocol/src/SemanticTokensClientCapabilities.php', '_HumbugBox7ff99e199a36\\LanguageServerProtocol\\SemanticTokensClientCapabilitiesRequests' => $vendorDir . '/felixfbecker/language-server-protocol/src/SemanticTokensClientCapabilitiesRequests.php', '_HumbugBox7ff99e199a36\\LanguageServerProtocol\\SemanticTokensWorkspaceClientCapabilities' => $vendorDir . '/felixfbecker/language-server-protocol/src/SemanticTokensWorkspaceClientCapabilities.php', '_HumbugBox7ff99e199a36\\LanguageServerProtocol\\ServerCapabilities' => $vendorDir . '/felixfbecker/language-server-protocol/src/ServerCapabilities.php', '_HumbugBox7ff99e199a36\\LanguageServerProtocol\\ShowDocumentClientCapabilities' => $vendorDir . '/felixfbecker/language-server-protocol/src/ShowDocumentClientCapabilities.php', '_HumbugBox7ff99e199a36\\LanguageServerProtocol\\ShowMessageRequestClientCapabilities' => $vendorDir . '/felixfbecker/language-server-protocol/src/ShowMessageRequestClientCapabilities.php', '_HumbugBox7ff99e199a36\\LanguageServerProtocol\\ShowMessageRequestClientCapabilitiesMessageActionItem' => $vendorDir . '/felixfbecker/language-server-protocol/src/ShowMessageRequestClientCapabilitiesMessageActionItem.php', '_HumbugBox7ff99e199a36\\LanguageServerProtocol\\SignatureHelp' => $vendorDir . '/felixfbecker/language-server-protocol/src/SignatureHelp.php', '_HumbugBox7ff99e199a36\\LanguageServerProtocol\\SignatureHelpClientCapabilities' => $vendorDir . '/felixfbecker/language-server-protocol/src/SignatureHelpClientCapabilities.php', '_HumbugBox7ff99e199a36\\LanguageServerProtocol\\SignatureHelpClientCapabilitiesSignatureInformation' => $vendorDir . '/felixfbecker/language-server-protocol/src/SignatureHelpClientCapabilitiesSignatureInformation.php', '_HumbugBox7ff99e199a36\\LanguageServerProtocol\\SignatureHelpClientCapabilitiesSignatureInformationParameterInformation' => $vendorDir . '/felixfbecker/language-server-protocol/src/SignatureHelpClientCapabilitiesSignatureInformationParameterInformation.php', '_HumbugBox7ff99e199a36\\LanguageServerProtocol\\SignatureHelpOptions' => $vendorDir . '/felixfbecker/language-server-protocol/src/SignatureHelpOptions.php', '_HumbugBox7ff99e199a36\\LanguageServerProtocol\\SignatureInformation' => $vendorDir . '/felixfbecker/language-server-protocol/src/SignatureInformation.php', '_HumbugBox7ff99e199a36\\LanguageServerProtocol\\SymbolDescriptor' => $vendorDir . '/felixfbecker/language-server-protocol/src/SymbolDescriptor.php', '_HumbugBox7ff99e199a36\\LanguageServerProtocol\\SymbolInformation' => $vendorDir . '/felixfbecker/language-server-protocol/src/SymbolInformation.php', '_HumbugBox7ff99e199a36\\LanguageServerProtocol\\SymbolKind' => $vendorDir . '/felixfbecker/language-server-protocol/src/SymbolKind.php', '_HumbugBox7ff99e199a36\\LanguageServerProtocol\\SymbolLocationInformation' => $vendorDir . '/felixfbecker/language-server-protocol/src/SymbolLocationInformation.php', '_HumbugBox7ff99e199a36\\LanguageServerProtocol\\SymbolTag' => $vendorDir . '/felixfbecker/language-server-protocol/src/SymbolTag.php', '_HumbugBox7ff99e199a36\\LanguageServerProtocol\\TextDocumentClientCapabilities' => $vendorDir . '/felixfbecker/language-server-protocol/src/TextDocumentClientCapabilities.php', '_HumbugBox7ff99e199a36\\LanguageServerProtocol\\TextDocumentContentChangeEvent' => $vendorDir . '/felixfbecker/language-server-protocol/src/TextDocumentContentChangeEvent.php', '_HumbugBox7ff99e199a36\\LanguageServerProtocol\\TextDocumentIdentifier' => $vendorDir . '/felixfbecker/language-server-protocol/src/TextDocumentIdentifier.php', '_HumbugBox7ff99e199a36\\LanguageServerProtocol\\TextDocumentItem' => $vendorDir . '/felixfbecker/language-server-protocol/src/TextDocumentItem.php', '_HumbugBox7ff99e199a36\\LanguageServerProtocol\\TextDocumentSyncClientCapabilities' => $vendorDir . '/felixfbecker/language-server-protocol/src/TextDocumentSyncClientCapabilities.php', '_HumbugBox7ff99e199a36\\LanguageServerProtocol\\TextDocumentSyncKind' => $vendorDir . '/felixfbecker/language-server-protocol/src/TextDocumentSyncKind.php', '_HumbugBox7ff99e199a36\\LanguageServerProtocol\\TextDocumentSyncOptions' => $vendorDir . '/felixfbecker/language-server-protocol/src/TextDocumentSyncOptions.php', '_HumbugBox7ff99e199a36\\LanguageServerProtocol\\TextEdit' => $vendorDir . '/felixfbecker/language-server-protocol/src/TextEdit.php', '_HumbugBox7ff99e199a36\\LanguageServerProtocol\\TokenFormat' => $vendorDir . '/felixfbecker/language-server-protocol/src/TokenFormat.php', '_HumbugBox7ff99e199a36\\LanguageServerProtocol\\TypeDefinitionClientCapabilities' => $vendorDir . '/felixfbecker/language-server-protocol/src/TypeDefinitionClientCapabilities.php', '_HumbugBox7ff99e199a36\\LanguageServerProtocol\\VersionedTextDocumentIdentifier' => $vendorDir . '/felixfbecker/language-server-protocol/src/VersionedTextDocumentIdentifier.php', '_HumbugBox7ff99e199a36\\LanguageServerProtocol\\WorkspaceEdit' => $vendorDir . '/felixfbecker/language-server-protocol/src/WorkspaceEdit.php', '_HumbugBox7ff99e199a36\\LanguageServerProtocol\\WorkspaceEditClientCapabilities' => $vendorDir . '/felixfbecker/language-server-protocol/src/WorkspaceEditClientCapabilities.php', '_HumbugBox7ff99e199a36\\LanguageServerProtocol\\WorkspaceEditClientCapabilitiesChangeAnnotationSupport' => $vendorDir . '/felixfbecker/language-server-protocol/src/WorkspaceEditClientCapabilitiesChangeAnnotationSupport.php', '_HumbugBox7ff99e199a36\\LanguageServerProtocol\\WorkspaceFolder' => $vendorDir . '/felixfbecker/language-server-protocol/src/WorkspaceFolder.php', '_HumbugBox7ff99e199a36\\LanguageServerProtocol\\WorkspaceSymbolClientCapabilities' => $vendorDir . '/felixfbecker/language-server-protocol/src/WorkspaceSymbolClientCapabilities.php', '_HumbugBox7ff99e199a36\\LanguageServerProtocol\\WorkspaceSymbolClientCapabilitiesResolveSupport' => $vendorDir . '/felixfbecker/language-server-protocol/src/WorkspaceSymbolClientCapabilitiesResolveSupport.php', '_HumbugBox7ff99e199a36\\LanguageServerProtocol\\WorkspaceSymbolClientCapabilitiesSymbolKind' => $vendorDir . '/felixfbecker/language-server-protocol/src/WorkspaceSymbolClientCapabilitiesSymbolKind.php', '_HumbugBox7ff99e199a36\\LanguageServerProtocol\\WorkspaceSymbolClientCapabilitiesTagSupport' => $vendorDir . '/felixfbecker/language-server-protocol/src/WorkspaceSymbolClientCapabilitiesTagSupport.php', '_HumbugBox7ff99e199a36\\Normalizer' => $vendorDir . '/symfony/polyfill-intl-normalizer/Resources/stubs/Normalizer.php', '_HumbugBox7ff99e199a36\\PHPStan\\PhpDocParser\\Ast\\AbstractNodeVisitor' => $vendorDir . '/phpstan/phpdoc-parser/src/Ast/AbstractNodeVisitor.php', '_HumbugBox7ff99e199a36\\PHPStan\\PhpDocParser\\Ast\\Attribute' => $vendorDir . '/phpstan/phpdoc-parser/src/Ast/Attribute.php', '_HumbugBox7ff99e199a36\\PHPStan\\PhpDocParser\\Ast\\ConstExpr\\ConstExprArrayItemNode' => $vendorDir . '/phpstan/phpdoc-parser/src/Ast/ConstExpr/ConstExprArrayItemNode.php', '_HumbugBox7ff99e199a36\\PHPStan\\PhpDocParser\\Ast\\ConstExpr\\ConstExprArrayNode' => $vendorDir . '/phpstan/phpdoc-parser/src/Ast/ConstExpr/ConstExprArrayNode.php', '_HumbugBox7ff99e199a36\\PHPStan\\PhpDocParser\\Ast\\ConstExpr\\ConstExprFalseNode' => $vendorDir . '/phpstan/phpdoc-parser/src/Ast/ConstExpr/ConstExprFalseNode.php', '_HumbugBox7ff99e199a36\\PHPStan\\PhpDocParser\\Ast\\ConstExpr\\ConstExprFloatNode' => $vendorDir . '/phpstan/phpdoc-parser/src/Ast/ConstExpr/ConstExprFloatNode.php', '_HumbugBox7ff99e199a36\\PHPStan\\PhpDocParser\\Ast\\ConstExpr\\ConstExprIntegerNode' => $vendorDir . '/phpstan/phpdoc-parser/src/Ast/ConstExpr/ConstExprIntegerNode.php', '_HumbugBox7ff99e199a36\\PHPStan\\PhpDocParser\\Ast\\ConstExpr\\ConstExprNode' => $vendorDir . '/phpstan/phpdoc-parser/src/Ast/ConstExpr/ConstExprNode.php', '_HumbugBox7ff99e199a36\\PHPStan\\PhpDocParser\\Ast\\ConstExpr\\ConstExprNullNode' => $vendorDir . '/phpstan/phpdoc-parser/src/Ast/ConstExpr/ConstExprNullNode.php', '_HumbugBox7ff99e199a36\\PHPStan\\PhpDocParser\\Ast\\ConstExpr\\ConstExprStringNode' => $vendorDir . '/phpstan/phpdoc-parser/src/Ast/ConstExpr/ConstExprStringNode.php', '_HumbugBox7ff99e199a36\\PHPStan\\PhpDocParser\\Ast\\ConstExpr\\ConstExprTrueNode' => $vendorDir . '/phpstan/phpdoc-parser/src/Ast/ConstExpr/ConstExprTrueNode.php', '_HumbugBox7ff99e199a36\\PHPStan\\PhpDocParser\\Ast\\ConstExpr\\ConstFetchNode' => $vendorDir . '/phpstan/phpdoc-parser/src/Ast/ConstExpr/ConstFetchNode.php', '_HumbugBox7ff99e199a36\\PHPStan\\PhpDocParser\\Ast\\ConstExpr\\DoctrineConstExprStringNode' => $vendorDir . '/phpstan/phpdoc-parser/src/Ast/ConstExpr/DoctrineConstExprStringNode.php', '_HumbugBox7ff99e199a36\\PHPStan\\PhpDocParser\\Ast\\ConstExpr\\QuoteAwareConstExprStringNode' => $vendorDir . '/phpstan/phpdoc-parser/src/Ast/ConstExpr/QuoteAwareConstExprStringNode.php', '_HumbugBox7ff99e199a36\\PHPStan\\PhpDocParser\\Ast\\Node' => $vendorDir . '/phpstan/phpdoc-parser/src/Ast/Node.php', '_HumbugBox7ff99e199a36\\PHPStan\\PhpDocParser\\Ast\\NodeAttributes' => $vendorDir . '/phpstan/phpdoc-parser/src/Ast/NodeAttributes.php', '_HumbugBox7ff99e199a36\\PHPStan\\PhpDocParser\\Ast\\NodeTraverser' => $vendorDir . '/phpstan/phpdoc-parser/src/Ast/NodeTraverser.php', '_HumbugBox7ff99e199a36\\PHPStan\\PhpDocParser\\Ast\\NodeVisitor' => $vendorDir . '/phpstan/phpdoc-parser/src/Ast/NodeVisitor.php', '_HumbugBox7ff99e199a36\\PHPStan\\PhpDocParser\\Ast\\NodeVisitor\\CloningVisitor' => $vendorDir . '/phpstan/phpdoc-parser/src/Ast/NodeVisitor/CloningVisitor.php', '_HumbugBox7ff99e199a36\\PHPStan\\PhpDocParser\\Ast\\PhpDoc\\AssertTagMethodValueNode' => $vendorDir . '/phpstan/phpdoc-parser/src/Ast/PhpDoc/AssertTagMethodValueNode.php', '_HumbugBox7ff99e199a36\\PHPStan\\PhpDocParser\\Ast\\PhpDoc\\AssertTagPropertyValueNode' => $vendorDir . '/phpstan/phpdoc-parser/src/Ast/PhpDoc/AssertTagPropertyValueNode.php', '_HumbugBox7ff99e199a36\\PHPStan\\PhpDocParser\\Ast\\PhpDoc\\AssertTagValueNode' => $vendorDir . '/phpstan/phpdoc-parser/src/Ast/PhpDoc/AssertTagValueNode.php', '_HumbugBox7ff99e199a36\\PHPStan\\PhpDocParser\\Ast\\PhpDoc\\DeprecatedTagValueNode' => $vendorDir . '/phpstan/phpdoc-parser/src/Ast/PhpDoc/DeprecatedTagValueNode.php', '_HumbugBox7ff99e199a36\\PHPStan\\PhpDocParser\\Ast\\PhpDoc\\Doctrine\\DoctrineAnnotation' => $vendorDir . '/phpstan/phpdoc-parser/src/Ast/PhpDoc/Doctrine/DoctrineAnnotation.php', '_HumbugBox7ff99e199a36\\PHPStan\\PhpDocParser\\Ast\\PhpDoc\\Doctrine\\DoctrineArgument' => $vendorDir . '/phpstan/phpdoc-parser/src/Ast/PhpDoc/Doctrine/DoctrineArgument.php', '_HumbugBox7ff99e199a36\\PHPStan\\PhpDocParser\\Ast\\PhpDoc\\Doctrine\\DoctrineArray' => $vendorDir . '/phpstan/phpdoc-parser/src/Ast/PhpDoc/Doctrine/DoctrineArray.php', '_HumbugBox7ff99e199a36\\PHPStan\\PhpDocParser\\Ast\\PhpDoc\\Doctrine\\DoctrineArrayItem' => $vendorDir . '/phpstan/phpdoc-parser/src/Ast/PhpDoc/Doctrine/DoctrineArrayItem.php', '_HumbugBox7ff99e199a36\\PHPStan\\PhpDocParser\\Ast\\PhpDoc\\Doctrine\\DoctrineTagValueNode' => $vendorDir . '/phpstan/phpdoc-parser/src/Ast/PhpDoc/Doctrine/DoctrineTagValueNode.php', '_HumbugBox7ff99e199a36\\PHPStan\\PhpDocParser\\Ast\\PhpDoc\\ExtendsTagValueNode' => $vendorDir . '/phpstan/phpdoc-parser/src/Ast/PhpDoc/ExtendsTagValueNode.php', '_HumbugBox7ff99e199a36\\PHPStan\\PhpDocParser\\Ast\\PhpDoc\\GenericTagValueNode' => $vendorDir . '/phpstan/phpdoc-parser/src/Ast/PhpDoc/GenericTagValueNode.php', '_HumbugBox7ff99e199a36\\PHPStan\\PhpDocParser\\Ast\\PhpDoc\\ImplementsTagValueNode' => $vendorDir . '/phpstan/phpdoc-parser/src/Ast/PhpDoc/ImplementsTagValueNode.php', '_HumbugBox7ff99e199a36\\PHPStan\\PhpDocParser\\Ast\\PhpDoc\\InvalidTagValueNode' => $vendorDir . '/phpstan/phpdoc-parser/src/Ast/PhpDoc/InvalidTagValueNode.php', '_HumbugBox7ff99e199a36\\PHPStan\\PhpDocParser\\Ast\\PhpDoc\\MethodTagValueNode' => $vendorDir . '/phpstan/phpdoc-parser/src/Ast/PhpDoc/MethodTagValueNode.php', '_HumbugBox7ff99e199a36\\PHPStan\\PhpDocParser\\Ast\\PhpDoc\\MethodTagValueParameterNode' => $vendorDir . '/phpstan/phpdoc-parser/src/Ast/PhpDoc/MethodTagValueParameterNode.php', '_HumbugBox7ff99e199a36\\PHPStan\\PhpDocParser\\Ast\\PhpDoc\\MixinTagValueNode' => $vendorDir . '/phpstan/phpdoc-parser/src/Ast/PhpDoc/MixinTagValueNode.php', '_HumbugBox7ff99e199a36\\PHPStan\\PhpDocParser\\Ast\\PhpDoc\\ParamClosureThisTagValueNode' => $vendorDir . '/phpstan/phpdoc-parser/src/Ast/PhpDoc/ParamClosureThisTagValueNode.php', '_HumbugBox7ff99e199a36\\PHPStan\\PhpDocParser\\Ast\\PhpDoc\\ParamImmediatelyInvokedCallableTagValueNode' => $vendorDir . '/phpstan/phpdoc-parser/src/Ast/PhpDoc/ParamImmediatelyInvokedCallableTagValueNode.php', '_HumbugBox7ff99e199a36\\PHPStan\\PhpDocParser\\Ast\\PhpDoc\\ParamLaterInvokedCallableTagValueNode' => $vendorDir . '/phpstan/phpdoc-parser/src/Ast/PhpDoc/ParamLaterInvokedCallableTagValueNode.php', '_HumbugBox7ff99e199a36\\PHPStan\\PhpDocParser\\Ast\\PhpDoc\\ParamOutTagValueNode' => $vendorDir . '/phpstan/phpdoc-parser/src/Ast/PhpDoc/ParamOutTagValueNode.php', '_HumbugBox7ff99e199a36\\PHPStan\\PhpDocParser\\Ast\\PhpDoc\\ParamTagValueNode' => $vendorDir . '/phpstan/phpdoc-parser/src/Ast/PhpDoc/ParamTagValueNode.php', '_HumbugBox7ff99e199a36\\PHPStan\\PhpDocParser\\Ast\\PhpDoc\\PhpDocChildNode' => $vendorDir . '/phpstan/phpdoc-parser/src/Ast/PhpDoc/PhpDocChildNode.php', '_HumbugBox7ff99e199a36\\PHPStan\\PhpDocParser\\Ast\\PhpDoc\\PhpDocNode' => $vendorDir . '/phpstan/phpdoc-parser/src/Ast/PhpDoc/PhpDocNode.php', '_HumbugBox7ff99e199a36\\PHPStan\\PhpDocParser\\Ast\\PhpDoc\\PhpDocTagNode' => $vendorDir . '/phpstan/phpdoc-parser/src/Ast/PhpDoc/PhpDocTagNode.php', '_HumbugBox7ff99e199a36\\PHPStan\\PhpDocParser\\Ast\\PhpDoc\\PhpDocTagValueNode' => $vendorDir . '/phpstan/phpdoc-parser/src/Ast/PhpDoc/PhpDocTagValueNode.php', '_HumbugBox7ff99e199a36\\PHPStan\\PhpDocParser\\Ast\\PhpDoc\\PhpDocTextNode' => $vendorDir . '/phpstan/phpdoc-parser/src/Ast/PhpDoc/PhpDocTextNode.php', '_HumbugBox7ff99e199a36\\PHPStan\\PhpDocParser\\Ast\\PhpDoc\\PropertyTagValueNode' => $vendorDir . '/phpstan/phpdoc-parser/src/Ast/PhpDoc/PropertyTagValueNode.php', '_HumbugBox7ff99e199a36\\PHPStan\\PhpDocParser\\Ast\\PhpDoc\\RequireExtendsTagValueNode' => $vendorDir . '/phpstan/phpdoc-parser/src/Ast/PhpDoc/RequireExtendsTagValueNode.php', '_HumbugBox7ff99e199a36\\PHPStan\\PhpDocParser\\Ast\\PhpDoc\\RequireImplementsTagValueNode' => $vendorDir . '/phpstan/phpdoc-parser/src/Ast/PhpDoc/RequireImplementsTagValueNode.php', '_HumbugBox7ff99e199a36\\PHPStan\\PhpDocParser\\Ast\\PhpDoc\\ReturnTagValueNode' => $vendorDir . '/phpstan/phpdoc-parser/src/Ast/PhpDoc/ReturnTagValueNode.php', '_HumbugBox7ff99e199a36\\PHPStan\\PhpDocParser\\Ast\\PhpDoc\\SelfOutTagValueNode' => $vendorDir . '/phpstan/phpdoc-parser/src/Ast/PhpDoc/SelfOutTagValueNode.php', '_HumbugBox7ff99e199a36\\PHPStan\\PhpDocParser\\Ast\\PhpDoc\\TemplateTagValueNode' => $vendorDir . '/phpstan/phpdoc-parser/src/Ast/PhpDoc/TemplateTagValueNode.php', '_HumbugBox7ff99e199a36\\PHPStan\\PhpDocParser\\Ast\\PhpDoc\\ThrowsTagValueNode' => $vendorDir . '/phpstan/phpdoc-parser/src/Ast/PhpDoc/ThrowsTagValueNode.php', '_HumbugBox7ff99e199a36\\PHPStan\\PhpDocParser\\Ast\\PhpDoc\\TypeAliasImportTagValueNode' => $vendorDir . '/phpstan/phpdoc-parser/src/Ast/PhpDoc/TypeAliasImportTagValueNode.php', '_HumbugBox7ff99e199a36\\PHPStan\\PhpDocParser\\Ast\\PhpDoc\\TypeAliasTagValueNode' => $vendorDir . '/phpstan/phpdoc-parser/src/Ast/PhpDoc/TypeAliasTagValueNode.php', '_HumbugBox7ff99e199a36\\PHPStan\\PhpDocParser\\Ast\\PhpDoc\\TypelessParamTagValueNode' => $vendorDir . '/phpstan/phpdoc-parser/src/Ast/PhpDoc/TypelessParamTagValueNode.php', '_HumbugBox7ff99e199a36\\PHPStan\\PhpDocParser\\Ast\\PhpDoc\\UsesTagValueNode' => $vendorDir . '/phpstan/phpdoc-parser/src/Ast/PhpDoc/UsesTagValueNode.php', '_HumbugBox7ff99e199a36\\PHPStan\\PhpDocParser\\Ast\\PhpDoc\\VarTagValueNode' => $vendorDir . '/phpstan/phpdoc-parser/src/Ast/PhpDoc/VarTagValueNode.php', '_HumbugBox7ff99e199a36\\PHPStan\\PhpDocParser\\Ast\\Type\\ArrayShapeItemNode' => $vendorDir . '/phpstan/phpdoc-parser/src/Ast/Type/ArrayShapeItemNode.php', '_HumbugBox7ff99e199a36\\PHPStan\\PhpDocParser\\Ast\\Type\\ArrayShapeNode' => $vendorDir . '/phpstan/phpdoc-parser/src/Ast/Type/ArrayShapeNode.php', '_HumbugBox7ff99e199a36\\PHPStan\\PhpDocParser\\Ast\\Type\\ArrayShapeUnsealedTypeNode' => $vendorDir . '/phpstan/phpdoc-parser/src/Ast/Type/ArrayShapeUnsealedTypeNode.php', '_HumbugBox7ff99e199a36\\PHPStan\\PhpDocParser\\Ast\\Type\\ArrayTypeNode' => $vendorDir . '/phpstan/phpdoc-parser/src/Ast/Type/ArrayTypeNode.php', '_HumbugBox7ff99e199a36\\PHPStan\\PhpDocParser\\Ast\\Type\\CallableTypeNode' => $vendorDir . '/phpstan/phpdoc-parser/src/Ast/Type/CallableTypeNode.php', '_HumbugBox7ff99e199a36\\PHPStan\\PhpDocParser\\Ast\\Type\\CallableTypeParameterNode' => $vendorDir . '/phpstan/phpdoc-parser/src/Ast/Type/CallableTypeParameterNode.php', '_HumbugBox7ff99e199a36\\PHPStan\\PhpDocParser\\Ast\\Type\\ConditionalTypeForParameterNode' => $vendorDir . '/phpstan/phpdoc-parser/src/Ast/Type/ConditionalTypeForParameterNode.php', '_HumbugBox7ff99e199a36\\PHPStan\\PhpDocParser\\Ast\\Type\\ConditionalTypeNode' => $vendorDir . '/phpstan/phpdoc-parser/src/Ast/Type/ConditionalTypeNode.php', '_HumbugBox7ff99e199a36\\PHPStan\\PhpDocParser\\Ast\\Type\\ConstTypeNode' => $vendorDir . '/phpstan/phpdoc-parser/src/Ast/Type/ConstTypeNode.php', '_HumbugBox7ff99e199a36\\PHPStan\\PhpDocParser\\Ast\\Type\\GenericTypeNode' => $vendorDir . '/phpstan/phpdoc-parser/src/Ast/Type/GenericTypeNode.php', '_HumbugBox7ff99e199a36\\PHPStan\\PhpDocParser\\Ast\\Type\\IdentifierTypeNode' => $vendorDir . '/phpstan/phpdoc-parser/src/Ast/Type/IdentifierTypeNode.php', '_HumbugBox7ff99e199a36\\PHPStan\\PhpDocParser\\Ast\\Type\\IntersectionTypeNode' => $vendorDir . '/phpstan/phpdoc-parser/src/Ast/Type/IntersectionTypeNode.php', '_HumbugBox7ff99e199a36\\PHPStan\\PhpDocParser\\Ast\\Type\\InvalidTypeNode' => $vendorDir . '/phpstan/phpdoc-parser/src/Ast/Type/InvalidTypeNode.php', '_HumbugBox7ff99e199a36\\PHPStan\\PhpDocParser\\Ast\\Type\\NullableTypeNode' => $vendorDir . '/phpstan/phpdoc-parser/src/Ast/Type/NullableTypeNode.php', '_HumbugBox7ff99e199a36\\PHPStan\\PhpDocParser\\Ast\\Type\\ObjectShapeItemNode' => $vendorDir . '/phpstan/phpdoc-parser/src/Ast/Type/ObjectShapeItemNode.php', '_HumbugBox7ff99e199a36\\PHPStan\\PhpDocParser\\Ast\\Type\\ObjectShapeNode' => $vendorDir . '/phpstan/phpdoc-parser/src/Ast/Type/ObjectShapeNode.php', '_HumbugBox7ff99e199a36\\PHPStan\\PhpDocParser\\Ast\\Type\\OffsetAccessTypeNode' => $vendorDir . '/phpstan/phpdoc-parser/src/Ast/Type/OffsetAccessTypeNode.php', '_HumbugBox7ff99e199a36\\PHPStan\\PhpDocParser\\Ast\\Type\\ThisTypeNode' => $vendorDir . '/phpstan/phpdoc-parser/src/Ast/Type/ThisTypeNode.php', '_HumbugBox7ff99e199a36\\PHPStan\\PhpDocParser\\Ast\\Type\\TypeNode' => $vendorDir . '/phpstan/phpdoc-parser/src/Ast/Type/TypeNode.php', '_HumbugBox7ff99e199a36\\PHPStan\\PhpDocParser\\Ast\\Type\\UnionTypeNode' => $vendorDir . '/phpstan/phpdoc-parser/src/Ast/Type/UnionTypeNode.php', '_HumbugBox7ff99e199a36\\PHPStan\\PhpDocParser\\Lexer\\Lexer' => $vendorDir . '/phpstan/phpdoc-parser/src/Lexer/Lexer.php', '_HumbugBox7ff99e199a36\\PHPStan\\PhpDocParser\\Parser\\ConstExprParser' => $vendorDir . '/phpstan/phpdoc-parser/src/Parser/ConstExprParser.php', '_HumbugBox7ff99e199a36\\PHPStan\\PhpDocParser\\Parser\\ParserException' => $vendorDir . '/phpstan/phpdoc-parser/src/Parser/ParserException.php', '_HumbugBox7ff99e199a36\\PHPStan\\PhpDocParser\\Parser\\PhpDocParser' => $vendorDir . '/phpstan/phpdoc-parser/src/Parser/PhpDocParser.php', '_HumbugBox7ff99e199a36\\PHPStan\\PhpDocParser\\Parser\\StringUnescaper' => $vendorDir . '/phpstan/phpdoc-parser/src/Parser/StringUnescaper.php', '_HumbugBox7ff99e199a36\\PHPStan\\PhpDocParser\\Parser\\TokenIterator' => $vendorDir . '/phpstan/phpdoc-parser/src/Parser/TokenIterator.php', '_HumbugBox7ff99e199a36\\PHPStan\\PhpDocParser\\Parser\\TypeParser' => $vendorDir . '/phpstan/phpdoc-parser/src/Parser/TypeParser.php', '_HumbugBox7ff99e199a36\\PHPStan\\PhpDocParser\\Printer\\DiffElem' => $vendorDir . '/phpstan/phpdoc-parser/src/Printer/DiffElem.php', '_HumbugBox7ff99e199a36\\PHPStan\\PhpDocParser\\Printer\\Differ' => $vendorDir . '/phpstan/phpdoc-parser/src/Printer/Differ.php', '_HumbugBox7ff99e199a36\\PHPStan\\PhpDocParser\\Printer\\Printer' => $vendorDir . '/phpstan/phpdoc-parser/src/Printer/Printer.php', '_HumbugBox7ff99e199a36\\PhpParser\\Builder' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Builder.php', '_HumbugBox7ff99e199a36\\PhpParser\\BuilderFactory' => $vendorDir . '/nikic/php-parser/lib/PhpParser/BuilderFactory.php', '_HumbugBox7ff99e199a36\\PhpParser\\BuilderHelpers' => $vendorDir . '/nikic/php-parser/lib/PhpParser/BuilderHelpers.php', '_HumbugBox7ff99e199a36\\PhpParser\\Builder\\ClassConst' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Builder/ClassConst.php', '_HumbugBox7ff99e199a36\\PhpParser\\Builder\\Class_' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Builder/Class_.php', '_HumbugBox7ff99e199a36\\PhpParser\\Builder\\Declaration' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Builder/Declaration.php', '_HumbugBox7ff99e199a36\\PhpParser\\Builder\\EnumCase' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Builder/EnumCase.php', '_HumbugBox7ff99e199a36\\PhpParser\\Builder\\Enum_' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Builder/Enum_.php', '_HumbugBox7ff99e199a36\\PhpParser\\Builder\\FunctionLike' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Builder/FunctionLike.php', '_HumbugBox7ff99e199a36\\PhpParser\\Builder\\Function_' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Builder/Function_.php', '_HumbugBox7ff99e199a36\\PhpParser\\Builder\\Interface_' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Builder/Interface_.php', '_HumbugBox7ff99e199a36\\PhpParser\\Builder\\Method' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Builder/Method.php', '_HumbugBox7ff99e199a36\\PhpParser\\Builder\\Namespace_' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Builder/Namespace_.php', '_HumbugBox7ff99e199a36\\PhpParser\\Builder\\Param' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Builder/Param.php', '_HumbugBox7ff99e199a36\\PhpParser\\Builder\\Property' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Builder/Property.php', '_HumbugBox7ff99e199a36\\PhpParser\\Builder\\TraitUse' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Builder/TraitUse.php', '_HumbugBox7ff99e199a36\\PhpParser\\Builder\\TraitUseAdaptation' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Builder/TraitUseAdaptation.php', '_HumbugBox7ff99e199a36\\PhpParser\\Builder\\Trait_' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Builder/Trait_.php', '_HumbugBox7ff99e199a36\\PhpParser\\Builder\\Use_' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Builder/Use_.php', '_HumbugBox7ff99e199a36\\PhpParser\\Comment' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Comment.php', '_HumbugBox7ff99e199a36\\PhpParser\\Comment\\Doc' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Comment/Doc.php', '_HumbugBox7ff99e199a36\\PhpParser\\ConstExprEvaluationException' => $vendorDir . '/nikic/php-parser/lib/PhpParser/ConstExprEvaluationException.php', '_HumbugBox7ff99e199a36\\PhpParser\\ConstExprEvaluator' => $vendorDir . '/nikic/php-parser/lib/PhpParser/ConstExprEvaluator.php', '_HumbugBox7ff99e199a36\\PhpParser\\Error' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Error.php', '_HumbugBox7ff99e199a36\\PhpParser\\ErrorHandler' => $vendorDir . '/nikic/php-parser/lib/PhpParser/ErrorHandler.php', '_HumbugBox7ff99e199a36\\PhpParser\\ErrorHandler\\Collecting' => $vendorDir . '/nikic/php-parser/lib/PhpParser/ErrorHandler/Collecting.php', '_HumbugBox7ff99e199a36\\PhpParser\\ErrorHandler\\Throwing' => $vendorDir . '/nikic/php-parser/lib/PhpParser/ErrorHandler/Throwing.php', '_HumbugBox7ff99e199a36\\PhpParser\\Internal\\DiffElem' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Internal/DiffElem.php', '_HumbugBox7ff99e199a36\\PhpParser\\Internal\\Differ' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Internal/Differ.php', '_HumbugBox7ff99e199a36\\PhpParser\\Internal\\PrintableNewAnonClassNode' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Internal/PrintableNewAnonClassNode.php', '_HumbugBox7ff99e199a36\\PhpParser\\Internal\\TokenStream' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Internal/TokenStream.php', '_HumbugBox7ff99e199a36\\PhpParser\\JsonDecoder' => $vendorDir . '/nikic/php-parser/lib/PhpParser/JsonDecoder.php', '_HumbugBox7ff99e199a36\\PhpParser\\Lexer' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Lexer.php', '_HumbugBox7ff99e199a36\\PhpParser\\Lexer\\Emulative' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Lexer/Emulative.php', '_HumbugBox7ff99e199a36\\PhpParser\\Lexer\\TokenEmulator\\AttributeEmulator' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Lexer/TokenEmulator/AttributeEmulator.php', '_HumbugBox7ff99e199a36\\PhpParser\\Lexer\\TokenEmulator\\CoaleseEqualTokenEmulator' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Lexer/TokenEmulator/CoaleseEqualTokenEmulator.php', '_HumbugBox7ff99e199a36\\PhpParser\\Lexer\\TokenEmulator\\EnumTokenEmulator' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Lexer/TokenEmulator/EnumTokenEmulator.php', '_HumbugBox7ff99e199a36\\PhpParser\\Lexer\\TokenEmulator\\ExplicitOctalEmulator' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Lexer/TokenEmulator/ExplicitOctalEmulator.php', '_HumbugBox7ff99e199a36\\PhpParser\\Lexer\\TokenEmulator\\FlexibleDocStringEmulator' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Lexer/TokenEmulator/FlexibleDocStringEmulator.php', '_HumbugBox7ff99e199a36\\PhpParser\\Lexer\\TokenEmulator\\FnTokenEmulator' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Lexer/TokenEmulator/FnTokenEmulator.php', '_HumbugBox7ff99e199a36\\PhpParser\\Lexer\\TokenEmulator\\KeywordEmulator' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Lexer/TokenEmulator/KeywordEmulator.php', '_HumbugBox7ff99e199a36\\PhpParser\\Lexer\\TokenEmulator\\MatchTokenEmulator' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Lexer/TokenEmulator/MatchTokenEmulator.php', '_HumbugBox7ff99e199a36\\PhpParser\\Lexer\\TokenEmulator\\NullsafeTokenEmulator' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Lexer/TokenEmulator/NullsafeTokenEmulator.php', '_HumbugBox7ff99e199a36\\PhpParser\\Lexer\\TokenEmulator\\NumericLiteralSeparatorEmulator' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Lexer/TokenEmulator/NumericLiteralSeparatorEmulator.php', '_HumbugBox7ff99e199a36\\PhpParser\\Lexer\\TokenEmulator\\ReadonlyFunctionTokenEmulator' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Lexer/TokenEmulator/ReadonlyFunctionTokenEmulator.php', '_HumbugBox7ff99e199a36\\PhpParser\\Lexer\\TokenEmulator\\ReadonlyTokenEmulator' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Lexer/TokenEmulator/ReadonlyTokenEmulator.php', '_HumbugBox7ff99e199a36\\PhpParser\\Lexer\\TokenEmulator\\ReverseEmulator' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Lexer/TokenEmulator/ReverseEmulator.php', '_HumbugBox7ff99e199a36\\PhpParser\\Lexer\\TokenEmulator\\TokenEmulator' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Lexer/TokenEmulator/TokenEmulator.php', '_HumbugBox7ff99e199a36\\PhpParser\\NameContext' => $vendorDir . '/nikic/php-parser/lib/PhpParser/NameContext.php', '_HumbugBox7ff99e199a36\\PhpParser\\Node' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Node.php', '_HumbugBox7ff99e199a36\\PhpParser\\NodeAbstract' => $vendorDir . '/nikic/php-parser/lib/PhpParser/NodeAbstract.php', '_HumbugBox7ff99e199a36\\PhpParser\\NodeDumper' => $vendorDir . '/nikic/php-parser/lib/PhpParser/NodeDumper.php', '_HumbugBox7ff99e199a36\\PhpParser\\NodeFinder' => $vendorDir . '/nikic/php-parser/lib/PhpParser/NodeFinder.php', '_HumbugBox7ff99e199a36\\PhpParser\\NodeTraverser' => $vendorDir . '/nikic/php-parser/lib/PhpParser/NodeTraverser.php', '_HumbugBox7ff99e199a36\\PhpParser\\NodeTraverserInterface' => $vendorDir . '/nikic/php-parser/lib/PhpParser/NodeTraverserInterface.php', '_HumbugBox7ff99e199a36\\PhpParser\\NodeVisitor' => $vendorDir . '/nikic/php-parser/lib/PhpParser/NodeVisitor.php', '_HumbugBox7ff99e199a36\\PhpParser\\NodeVisitorAbstract' => $vendorDir . '/nikic/php-parser/lib/PhpParser/NodeVisitorAbstract.php', '_HumbugBox7ff99e199a36\\PhpParser\\NodeVisitor\\CloningVisitor' => $vendorDir . '/nikic/php-parser/lib/PhpParser/NodeVisitor/CloningVisitor.php', '_HumbugBox7ff99e199a36\\PhpParser\\NodeVisitor\\FindingVisitor' => $vendorDir . '/nikic/php-parser/lib/PhpParser/NodeVisitor/FindingVisitor.php', '_HumbugBox7ff99e199a36\\PhpParser\\NodeVisitor\\FirstFindingVisitor' => $vendorDir . '/nikic/php-parser/lib/PhpParser/NodeVisitor/FirstFindingVisitor.php', '_HumbugBox7ff99e199a36\\PhpParser\\NodeVisitor\\NameResolver' => $vendorDir . '/nikic/php-parser/lib/PhpParser/NodeVisitor/NameResolver.php', '_HumbugBox7ff99e199a36\\PhpParser\\NodeVisitor\\NodeConnectingVisitor' => $vendorDir . '/nikic/php-parser/lib/PhpParser/NodeVisitor/NodeConnectingVisitor.php', '_HumbugBox7ff99e199a36\\PhpParser\\NodeVisitor\\ParentConnectingVisitor' => $vendorDir . '/nikic/php-parser/lib/PhpParser/NodeVisitor/ParentConnectingVisitor.php', '_HumbugBox7ff99e199a36\\PhpParser\\Node\\Arg' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Node/Arg.php', '_HumbugBox7ff99e199a36\\PhpParser\\Node\\Attribute' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Node/Attribute.php', '_HumbugBox7ff99e199a36\\PhpParser\\Node\\AttributeGroup' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Node/AttributeGroup.php', '_HumbugBox7ff99e199a36\\PhpParser\\Node\\ComplexType' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Node/ComplexType.php', '_HumbugBox7ff99e199a36\\PhpParser\\Node\\Const_' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Node/Const_.php', '_HumbugBox7ff99e199a36\\PhpParser\\Node\\Expr' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Node/Expr.php', '_HumbugBox7ff99e199a36\\PhpParser\\Node\\Expr\\ArrayDimFetch' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Node/Expr/ArrayDimFetch.php', '_HumbugBox7ff99e199a36\\PhpParser\\Node\\Expr\\ArrayItem' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Node/Expr/ArrayItem.php', '_HumbugBox7ff99e199a36\\PhpParser\\Node\\Expr\\Array_' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Node/Expr/Array_.php', '_HumbugBox7ff99e199a36\\PhpParser\\Node\\Expr\\ArrowFunction' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Node/Expr/ArrowFunction.php', '_HumbugBox7ff99e199a36\\PhpParser\\Node\\Expr\\Assign' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Node/Expr/Assign.php', '_HumbugBox7ff99e199a36\\PhpParser\\Node\\Expr\\AssignOp' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Node/Expr/AssignOp.php', '_HumbugBox7ff99e199a36\\PhpParser\\Node\\Expr\\AssignOp\\BitwiseAnd' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Node/Expr/AssignOp/BitwiseAnd.php', '_HumbugBox7ff99e199a36\\PhpParser\\Node\\Expr\\AssignOp\\BitwiseOr' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Node/Expr/AssignOp/BitwiseOr.php', '_HumbugBox7ff99e199a36\\PhpParser\\Node\\Expr\\AssignOp\\BitwiseXor' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Node/Expr/AssignOp/BitwiseXor.php', '_HumbugBox7ff99e199a36\\PhpParser\\Node\\Expr\\AssignOp\\Coalesce' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Node/Expr/AssignOp/Coalesce.php', '_HumbugBox7ff99e199a36\\PhpParser\\Node\\Expr\\AssignOp\\Concat' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Node/Expr/AssignOp/Concat.php', '_HumbugBox7ff99e199a36\\PhpParser\\Node\\Expr\\AssignOp\\Div' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Node/Expr/AssignOp/Div.php', '_HumbugBox7ff99e199a36\\PhpParser\\Node\\Expr\\AssignOp\\Minus' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Node/Expr/AssignOp/Minus.php', '_HumbugBox7ff99e199a36\\PhpParser\\Node\\Expr\\AssignOp\\Mod' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Node/Expr/AssignOp/Mod.php', '_HumbugBox7ff99e199a36\\PhpParser\\Node\\Expr\\AssignOp\\Mul' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Node/Expr/AssignOp/Mul.php', '_HumbugBox7ff99e199a36\\PhpParser\\Node\\Expr\\AssignOp\\Plus' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Node/Expr/AssignOp/Plus.php', '_HumbugBox7ff99e199a36\\PhpParser\\Node\\Expr\\AssignOp\\Pow' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Node/Expr/AssignOp/Pow.php', '_HumbugBox7ff99e199a36\\PhpParser\\Node\\Expr\\AssignOp\\ShiftLeft' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Node/Expr/AssignOp/ShiftLeft.php', '_HumbugBox7ff99e199a36\\PhpParser\\Node\\Expr\\AssignOp\\ShiftRight' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Node/Expr/AssignOp/ShiftRight.php', '_HumbugBox7ff99e199a36\\PhpParser\\Node\\Expr\\AssignRef' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Node/Expr/AssignRef.php', '_HumbugBox7ff99e199a36\\PhpParser\\Node\\Expr\\BinaryOp' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Node/Expr/BinaryOp.php', '_HumbugBox7ff99e199a36\\PhpParser\\Node\\Expr\\BinaryOp\\BitwiseAnd' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Node/Expr/BinaryOp/BitwiseAnd.php', '_HumbugBox7ff99e199a36\\PhpParser\\Node\\Expr\\BinaryOp\\BitwiseOr' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Node/Expr/BinaryOp/BitwiseOr.php', '_HumbugBox7ff99e199a36\\PhpParser\\Node\\Expr\\BinaryOp\\BitwiseXor' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Node/Expr/BinaryOp/BitwiseXor.php', '_HumbugBox7ff99e199a36\\PhpParser\\Node\\Expr\\BinaryOp\\BooleanAnd' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Node/Expr/BinaryOp/BooleanAnd.php', '_HumbugBox7ff99e199a36\\PhpParser\\Node\\Expr\\BinaryOp\\BooleanOr' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Node/Expr/BinaryOp/BooleanOr.php', '_HumbugBox7ff99e199a36\\PhpParser\\Node\\Expr\\BinaryOp\\Coalesce' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Node/Expr/BinaryOp/Coalesce.php', '_HumbugBox7ff99e199a36\\PhpParser\\Node\\Expr\\BinaryOp\\Concat' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Node/Expr/BinaryOp/Concat.php', '_HumbugBox7ff99e199a36\\PhpParser\\Node\\Expr\\BinaryOp\\Div' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Node/Expr/BinaryOp/Div.php', '_HumbugBox7ff99e199a36\\PhpParser\\Node\\Expr\\BinaryOp\\Equal' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Node/Expr/BinaryOp/Equal.php', '_HumbugBox7ff99e199a36\\PhpParser\\Node\\Expr\\BinaryOp\\Greater' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Node/Expr/BinaryOp/Greater.php', '_HumbugBox7ff99e199a36\\PhpParser\\Node\\Expr\\BinaryOp\\GreaterOrEqual' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Node/Expr/BinaryOp/GreaterOrEqual.php', '_HumbugBox7ff99e199a36\\PhpParser\\Node\\Expr\\BinaryOp\\Identical' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Node/Expr/BinaryOp/Identical.php', '_HumbugBox7ff99e199a36\\PhpParser\\Node\\Expr\\BinaryOp\\LogicalAnd' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Node/Expr/BinaryOp/LogicalAnd.php', '_HumbugBox7ff99e199a36\\PhpParser\\Node\\Expr\\BinaryOp\\LogicalOr' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Node/Expr/BinaryOp/LogicalOr.php', '_HumbugBox7ff99e199a36\\PhpParser\\Node\\Expr\\BinaryOp\\LogicalXor' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Node/Expr/BinaryOp/LogicalXor.php', '_HumbugBox7ff99e199a36\\PhpParser\\Node\\Expr\\BinaryOp\\Minus' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Node/Expr/BinaryOp/Minus.php', '_HumbugBox7ff99e199a36\\PhpParser\\Node\\Expr\\BinaryOp\\Mod' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Node/Expr/BinaryOp/Mod.php', '_HumbugBox7ff99e199a36\\PhpParser\\Node\\Expr\\BinaryOp\\Mul' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Node/Expr/BinaryOp/Mul.php', '_HumbugBox7ff99e199a36\\PhpParser\\Node\\Expr\\BinaryOp\\NotEqual' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Node/Expr/BinaryOp/NotEqual.php', '_HumbugBox7ff99e199a36\\PhpParser\\Node\\Expr\\BinaryOp\\NotIdentical' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Node/Expr/BinaryOp/NotIdentical.php', '_HumbugBox7ff99e199a36\\PhpParser\\Node\\Expr\\BinaryOp\\Plus' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Node/Expr/BinaryOp/Plus.php', '_HumbugBox7ff99e199a36\\PhpParser\\Node\\Expr\\BinaryOp\\Pow' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Node/Expr/BinaryOp/Pow.php', '_HumbugBox7ff99e199a36\\PhpParser\\Node\\Expr\\BinaryOp\\ShiftLeft' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Node/Expr/BinaryOp/ShiftLeft.php', '_HumbugBox7ff99e199a36\\PhpParser\\Node\\Expr\\BinaryOp\\ShiftRight' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Node/Expr/BinaryOp/ShiftRight.php', '_HumbugBox7ff99e199a36\\PhpParser\\Node\\Expr\\BinaryOp\\Smaller' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Node/Expr/BinaryOp/Smaller.php', '_HumbugBox7ff99e199a36\\PhpParser\\Node\\Expr\\BinaryOp\\SmallerOrEqual' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Node/Expr/BinaryOp/SmallerOrEqual.php', '_HumbugBox7ff99e199a36\\PhpParser\\Node\\Expr\\BinaryOp\\Spaceship' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Node/Expr/BinaryOp/Spaceship.php', '_HumbugBox7ff99e199a36\\PhpParser\\Node\\Expr\\BitwiseNot' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Node/Expr/BitwiseNot.php', '_HumbugBox7ff99e199a36\\PhpParser\\Node\\Expr\\BooleanNot' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Node/Expr/BooleanNot.php', '_HumbugBox7ff99e199a36\\PhpParser\\Node\\Expr\\CallLike' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Node/Expr/CallLike.php', '_HumbugBox7ff99e199a36\\PhpParser\\Node\\Expr\\Cast' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Node/Expr/Cast.php', '_HumbugBox7ff99e199a36\\PhpParser\\Node\\Expr\\Cast\\Array_' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Node/Expr/Cast/Array_.php', '_HumbugBox7ff99e199a36\\PhpParser\\Node\\Expr\\Cast\\Bool_' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Node/Expr/Cast/Bool_.php', '_HumbugBox7ff99e199a36\\PhpParser\\Node\\Expr\\Cast\\Double' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Node/Expr/Cast/Double.php', '_HumbugBox7ff99e199a36\\PhpParser\\Node\\Expr\\Cast\\Int_' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Node/Expr/Cast/Int_.php', '_HumbugBox7ff99e199a36\\PhpParser\\Node\\Expr\\Cast\\Object_' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Node/Expr/Cast/Object_.php', '_HumbugBox7ff99e199a36\\PhpParser\\Node\\Expr\\Cast\\String_' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Node/Expr/Cast/String_.php', '_HumbugBox7ff99e199a36\\PhpParser\\Node\\Expr\\Cast\\Unset_' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Node/Expr/Cast/Unset_.php', '_HumbugBox7ff99e199a36\\PhpParser\\Node\\Expr\\ClassConstFetch' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Node/Expr/ClassConstFetch.php', '_HumbugBox7ff99e199a36\\PhpParser\\Node\\Expr\\Clone_' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Node/Expr/Clone_.php', '_HumbugBox7ff99e199a36\\PhpParser\\Node\\Expr\\Closure' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Node/Expr/Closure.php', '_HumbugBox7ff99e199a36\\PhpParser\\Node\\Expr\\ClosureUse' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Node/Expr/ClosureUse.php', '_HumbugBox7ff99e199a36\\PhpParser\\Node\\Expr\\ConstFetch' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Node/Expr/ConstFetch.php', '_HumbugBox7ff99e199a36\\PhpParser\\Node\\Expr\\Empty_' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Node/Expr/Empty_.php', '_HumbugBox7ff99e199a36\\PhpParser\\Node\\Expr\\Error' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Node/Expr/Error.php', '_HumbugBox7ff99e199a36\\PhpParser\\Node\\Expr\\ErrorSuppress' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Node/Expr/ErrorSuppress.php', '_HumbugBox7ff99e199a36\\PhpParser\\Node\\Expr\\Eval_' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Node/Expr/Eval_.php', '_HumbugBox7ff99e199a36\\PhpParser\\Node\\Expr\\Exit_' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Node/Expr/Exit_.php', '_HumbugBox7ff99e199a36\\PhpParser\\Node\\Expr\\FuncCall' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Node/Expr/FuncCall.php', '_HumbugBox7ff99e199a36\\PhpParser\\Node\\Expr\\Include_' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Node/Expr/Include_.php', '_HumbugBox7ff99e199a36\\PhpParser\\Node\\Expr\\Instanceof_' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Node/Expr/Instanceof_.php', '_HumbugBox7ff99e199a36\\PhpParser\\Node\\Expr\\Isset_' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Node/Expr/Isset_.php', '_HumbugBox7ff99e199a36\\PhpParser\\Node\\Expr\\List_' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Node/Expr/List_.php', '_HumbugBox7ff99e199a36\\PhpParser\\Node\\Expr\\Match_' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Node/Expr/Match_.php', '_HumbugBox7ff99e199a36\\PhpParser\\Node\\Expr\\MethodCall' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Node/Expr/MethodCall.php', '_HumbugBox7ff99e199a36\\PhpParser\\Node\\Expr\\New_' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Node/Expr/New_.php', '_HumbugBox7ff99e199a36\\PhpParser\\Node\\Expr\\NullsafeMethodCall' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Node/Expr/NullsafeMethodCall.php', '_HumbugBox7ff99e199a36\\PhpParser\\Node\\Expr\\NullsafePropertyFetch' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Node/Expr/NullsafePropertyFetch.php', '_HumbugBox7ff99e199a36\\PhpParser\\Node\\Expr\\PostDec' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Node/Expr/PostDec.php', '_HumbugBox7ff99e199a36\\PhpParser\\Node\\Expr\\PostInc' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Node/Expr/PostInc.php', '_HumbugBox7ff99e199a36\\PhpParser\\Node\\Expr\\PreDec' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Node/Expr/PreDec.php', '_HumbugBox7ff99e199a36\\PhpParser\\Node\\Expr\\PreInc' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Node/Expr/PreInc.php', '_HumbugBox7ff99e199a36\\PhpParser\\Node\\Expr\\Print_' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Node/Expr/Print_.php', '_HumbugBox7ff99e199a36\\PhpParser\\Node\\Expr\\PropertyFetch' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Node/Expr/PropertyFetch.php', '_HumbugBox7ff99e199a36\\PhpParser\\Node\\Expr\\ShellExec' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Node/Expr/ShellExec.php', '_HumbugBox7ff99e199a36\\PhpParser\\Node\\Expr\\StaticCall' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Node/Expr/StaticCall.php', '_HumbugBox7ff99e199a36\\PhpParser\\Node\\Expr\\StaticPropertyFetch' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Node/Expr/StaticPropertyFetch.php', '_HumbugBox7ff99e199a36\\PhpParser\\Node\\Expr\\Ternary' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Node/Expr/Ternary.php', '_HumbugBox7ff99e199a36\\PhpParser\\Node\\Expr\\Throw_' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Node/Expr/Throw_.php', '_HumbugBox7ff99e199a36\\PhpParser\\Node\\Expr\\UnaryMinus' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Node/Expr/UnaryMinus.php', '_HumbugBox7ff99e199a36\\PhpParser\\Node\\Expr\\UnaryPlus' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Node/Expr/UnaryPlus.php', '_HumbugBox7ff99e199a36\\PhpParser\\Node\\Expr\\Variable' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Node/Expr/Variable.php', '_HumbugBox7ff99e199a36\\PhpParser\\Node\\Expr\\YieldFrom' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Node/Expr/YieldFrom.php', '_HumbugBox7ff99e199a36\\PhpParser\\Node\\Expr\\Yield_' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Node/Expr/Yield_.php', '_HumbugBox7ff99e199a36\\PhpParser\\Node\\FunctionLike' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Node/FunctionLike.php', '_HumbugBox7ff99e199a36\\PhpParser\\Node\\Identifier' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Node/Identifier.php', '_HumbugBox7ff99e199a36\\PhpParser\\Node\\IntersectionType' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Node/IntersectionType.php', '_HumbugBox7ff99e199a36\\PhpParser\\Node\\MatchArm' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Node/MatchArm.php', '_HumbugBox7ff99e199a36\\PhpParser\\Node\\Name' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Node/Name.php', '_HumbugBox7ff99e199a36\\PhpParser\\Node\\Name\\FullyQualified' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Node/Name/FullyQualified.php', '_HumbugBox7ff99e199a36\\PhpParser\\Node\\Name\\Relative' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Node/Name/Relative.php', '_HumbugBox7ff99e199a36\\PhpParser\\Node\\NullableType' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Node/NullableType.php', '_HumbugBox7ff99e199a36\\PhpParser\\Node\\Param' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Node/Param.php', '_HumbugBox7ff99e199a36\\PhpParser\\Node\\Scalar' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Node/Scalar.php', '_HumbugBox7ff99e199a36\\PhpParser\\Node\\Scalar\\DNumber' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Node/Scalar/DNumber.php', '_HumbugBox7ff99e199a36\\PhpParser\\Node\\Scalar\\Encapsed' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Node/Scalar/Encapsed.php', '_HumbugBox7ff99e199a36\\PhpParser\\Node\\Scalar\\EncapsedStringPart' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Node/Scalar/EncapsedStringPart.php', '_HumbugBox7ff99e199a36\\PhpParser\\Node\\Scalar\\LNumber' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Node/Scalar/LNumber.php', '_HumbugBox7ff99e199a36\\PhpParser\\Node\\Scalar\\MagicConst' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Node/Scalar/MagicConst.php', '_HumbugBox7ff99e199a36\\PhpParser\\Node\\Scalar\\MagicConst\\Class_' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Node/Scalar/MagicConst/Class_.php', '_HumbugBox7ff99e199a36\\PhpParser\\Node\\Scalar\\MagicConst\\Dir' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Node/Scalar/MagicConst/Dir.php', '_HumbugBox7ff99e199a36\\PhpParser\\Node\\Scalar\\MagicConst\\File' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Node/Scalar/MagicConst/File.php', '_HumbugBox7ff99e199a36\\PhpParser\\Node\\Scalar\\MagicConst\\Function_' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Node/Scalar/MagicConst/Function_.php', '_HumbugBox7ff99e199a36\\PhpParser\\Node\\Scalar\\MagicConst\\Line' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Node/Scalar/MagicConst/Line.php', '_HumbugBox7ff99e199a36\\PhpParser\\Node\\Scalar\\MagicConst\\Method' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Node/Scalar/MagicConst/Method.php', '_HumbugBox7ff99e199a36\\PhpParser\\Node\\Scalar\\MagicConst\\Namespace_' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Node/Scalar/MagicConst/Namespace_.php', '_HumbugBox7ff99e199a36\\PhpParser\\Node\\Scalar\\MagicConst\\Trait_' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Node/Scalar/MagicConst/Trait_.php', '_HumbugBox7ff99e199a36\\PhpParser\\Node\\Scalar\\String_' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Node/Scalar/String_.php', '_HumbugBox7ff99e199a36\\PhpParser\\Node\\Stmt' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Node/Stmt.php', '_HumbugBox7ff99e199a36\\PhpParser\\Node\\Stmt\\Break_' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Node/Stmt/Break_.php', '_HumbugBox7ff99e199a36\\PhpParser\\Node\\Stmt\\Case_' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Node/Stmt/Case_.php', '_HumbugBox7ff99e199a36\\PhpParser\\Node\\Stmt\\Catch_' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Node/Stmt/Catch_.php', '_HumbugBox7ff99e199a36\\PhpParser\\Node\\Stmt\\ClassConst' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Node/Stmt/ClassConst.php', '_HumbugBox7ff99e199a36\\PhpParser\\Node\\Stmt\\ClassLike' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Node/Stmt/ClassLike.php', '_HumbugBox7ff99e199a36\\PhpParser\\Node\\Stmt\\ClassMethod' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Node/Stmt/ClassMethod.php', '_HumbugBox7ff99e199a36\\PhpParser\\Node\\Stmt\\Class_' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Node/Stmt/Class_.php', '_HumbugBox7ff99e199a36\\PhpParser\\Node\\Stmt\\Const_' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Node/Stmt/Const_.php', '_HumbugBox7ff99e199a36\\PhpParser\\Node\\Stmt\\Continue_' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Node/Stmt/Continue_.php', '_HumbugBox7ff99e199a36\\PhpParser\\Node\\Stmt\\DeclareDeclare' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Node/Stmt/DeclareDeclare.php', '_HumbugBox7ff99e199a36\\PhpParser\\Node\\Stmt\\Declare_' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Node/Stmt/Declare_.php', '_HumbugBox7ff99e199a36\\PhpParser\\Node\\Stmt\\Do_' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Node/Stmt/Do_.php', '_HumbugBox7ff99e199a36\\PhpParser\\Node\\Stmt\\Echo_' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Node/Stmt/Echo_.php', '_HumbugBox7ff99e199a36\\PhpParser\\Node\\Stmt\\ElseIf_' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Node/Stmt/ElseIf_.php', '_HumbugBox7ff99e199a36\\PhpParser\\Node\\Stmt\\Else_' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Node/Stmt/Else_.php', '_HumbugBox7ff99e199a36\\PhpParser\\Node\\Stmt\\EnumCase' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Node/Stmt/EnumCase.php', '_HumbugBox7ff99e199a36\\PhpParser\\Node\\Stmt\\Enum_' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Node/Stmt/Enum_.php', '_HumbugBox7ff99e199a36\\PhpParser\\Node\\Stmt\\Expression' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Node/Stmt/Expression.php', '_HumbugBox7ff99e199a36\\PhpParser\\Node\\Stmt\\Finally_' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Node/Stmt/Finally_.php', '_HumbugBox7ff99e199a36\\PhpParser\\Node\\Stmt\\For_' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Node/Stmt/For_.php', '_HumbugBox7ff99e199a36\\PhpParser\\Node\\Stmt\\Foreach_' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Node/Stmt/Foreach_.php', '_HumbugBox7ff99e199a36\\PhpParser\\Node\\Stmt\\Function_' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Node/Stmt/Function_.php', '_HumbugBox7ff99e199a36\\PhpParser\\Node\\Stmt\\Global_' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Node/Stmt/Global_.php', '_HumbugBox7ff99e199a36\\PhpParser\\Node\\Stmt\\Goto_' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Node/Stmt/Goto_.php', '_HumbugBox7ff99e199a36\\PhpParser\\Node\\Stmt\\GroupUse' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Node/Stmt/GroupUse.php', '_HumbugBox7ff99e199a36\\PhpParser\\Node\\Stmt\\HaltCompiler' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Node/Stmt/HaltCompiler.php', '_HumbugBox7ff99e199a36\\PhpParser\\Node\\Stmt\\If_' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Node/Stmt/If_.php', '_HumbugBox7ff99e199a36\\PhpParser\\Node\\Stmt\\InlineHTML' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Node/Stmt/InlineHTML.php', '_HumbugBox7ff99e199a36\\PhpParser\\Node\\Stmt\\Interface_' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Node/Stmt/Interface_.php', '_HumbugBox7ff99e199a36\\PhpParser\\Node\\Stmt\\Label' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Node/Stmt/Label.php', '_HumbugBox7ff99e199a36\\PhpParser\\Node\\Stmt\\Namespace_' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Node/Stmt/Namespace_.php', '_HumbugBox7ff99e199a36\\PhpParser\\Node\\Stmt\\Nop' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Node/Stmt/Nop.php', '_HumbugBox7ff99e199a36\\PhpParser\\Node\\Stmt\\Property' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Node/Stmt/Property.php', '_HumbugBox7ff99e199a36\\PhpParser\\Node\\Stmt\\PropertyProperty' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Node/Stmt/PropertyProperty.php', '_HumbugBox7ff99e199a36\\PhpParser\\Node\\Stmt\\Return_' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Node/Stmt/Return_.php', '_HumbugBox7ff99e199a36\\PhpParser\\Node\\Stmt\\StaticVar' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Node/Stmt/StaticVar.php', '_HumbugBox7ff99e199a36\\PhpParser\\Node\\Stmt\\Static_' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Node/Stmt/Static_.php', '_HumbugBox7ff99e199a36\\PhpParser\\Node\\Stmt\\Switch_' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Node/Stmt/Switch_.php', '_HumbugBox7ff99e199a36\\PhpParser\\Node\\Stmt\\Throw_' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Node/Stmt/Throw_.php', '_HumbugBox7ff99e199a36\\PhpParser\\Node\\Stmt\\TraitUse' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Node/Stmt/TraitUse.php', '_HumbugBox7ff99e199a36\\PhpParser\\Node\\Stmt\\TraitUseAdaptation' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Node/Stmt/TraitUseAdaptation.php', '_HumbugBox7ff99e199a36\\PhpParser\\Node\\Stmt\\TraitUseAdaptation\\Alias' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Node/Stmt/TraitUseAdaptation/Alias.php', '_HumbugBox7ff99e199a36\\PhpParser\\Node\\Stmt\\TraitUseAdaptation\\Precedence' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Node/Stmt/TraitUseAdaptation/Precedence.php', '_HumbugBox7ff99e199a36\\PhpParser\\Node\\Stmt\\Trait_' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Node/Stmt/Trait_.php', '_HumbugBox7ff99e199a36\\PhpParser\\Node\\Stmt\\TryCatch' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Node/Stmt/TryCatch.php', '_HumbugBox7ff99e199a36\\PhpParser\\Node\\Stmt\\Unset_' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Node/Stmt/Unset_.php', '_HumbugBox7ff99e199a36\\PhpParser\\Node\\Stmt\\UseUse' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Node/Stmt/UseUse.php', '_HumbugBox7ff99e199a36\\PhpParser\\Node\\Stmt\\Use_' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Node/Stmt/Use_.php', '_HumbugBox7ff99e199a36\\PhpParser\\Node\\Stmt\\While_' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Node/Stmt/While_.php', '_HumbugBox7ff99e199a36\\PhpParser\\Node\\UnionType' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Node/UnionType.php', '_HumbugBox7ff99e199a36\\PhpParser\\Node\\VarLikeIdentifier' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Node/VarLikeIdentifier.php', '_HumbugBox7ff99e199a36\\PhpParser\\Node\\VariadicPlaceholder' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Node/VariadicPlaceholder.php', '_HumbugBox7ff99e199a36\\PhpParser\\Parser' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Parser.php', '_HumbugBox7ff99e199a36\\PhpParser\\ParserAbstract' => $vendorDir . '/nikic/php-parser/lib/PhpParser/ParserAbstract.php', '_HumbugBox7ff99e199a36\\PhpParser\\ParserFactory' => $vendorDir . '/nikic/php-parser/lib/PhpParser/ParserFactory.php', '_HumbugBox7ff99e199a36\\PhpParser\\Parser\\Multiple' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Parser/Multiple.php', '_HumbugBox7ff99e199a36\\PhpParser\\Parser\\Php5' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Parser/Php5.php', '_HumbugBox7ff99e199a36\\PhpParser\\Parser\\Php7' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Parser/Php7.php', '_HumbugBox7ff99e199a36\\PhpParser\\Parser\\Tokens' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Parser/Tokens.php', '_HumbugBox7ff99e199a36\\PhpParser\\PrettyPrinterAbstract' => $vendorDir . '/nikic/php-parser/lib/PhpParser/PrettyPrinterAbstract.php', '_HumbugBox7ff99e199a36\\PhpParser\\PrettyPrinter\\Standard' => $vendorDir . '/nikic/php-parser/lib/PhpParser/PrettyPrinter/Standard.php', '_HumbugBox7ff99e199a36\\Psr\\Container\\ContainerExceptionInterface' => $vendorDir . '/psr/container/src/ContainerExceptionInterface.php', '_HumbugBox7ff99e199a36\\Psr\\Container\\ContainerInterface' => $vendorDir . '/psr/container/src/ContainerInterface.php', '_HumbugBox7ff99e199a36\\Psr\\Container\\NotFoundExceptionInterface' => $vendorDir . '/psr/container/src/NotFoundExceptionInterface.php', '_HumbugBox7ff99e199a36\\Psr\\Log\\AbstractLogger' => $vendorDir . '/psr/log/Psr/Log/AbstractLogger.php', '_HumbugBox7ff99e199a36\\Psr\\Log\\InvalidArgumentException' => $vendorDir . '/psr/log/Psr/Log/InvalidArgumentException.php', '_HumbugBox7ff99e199a36\\Psr\\Log\\LogLevel' => $vendorDir . '/psr/log/Psr/Log/LogLevel.php', '_HumbugBox7ff99e199a36\\Psr\\Log\\LoggerAwareInterface' => $vendorDir . '/psr/log/Psr/Log/LoggerAwareInterface.php', '_HumbugBox7ff99e199a36\\Psr\\Log\\LoggerAwareTrait' => $vendorDir . '/psr/log/Psr/Log/LoggerAwareTrait.php', '_HumbugBox7ff99e199a36\\Psr\\Log\\LoggerInterface' => $vendorDir . '/psr/log/Psr/Log/LoggerInterface.php', '_HumbugBox7ff99e199a36\\Psr\\Log\\LoggerTrait' => $vendorDir . '/psr/log/Psr/Log/LoggerTrait.php', '_HumbugBox7ff99e199a36\\Psr\\Log\\NullLogger' => $vendorDir . '/psr/log/Psr/Log/NullLogger.php', '_HumbugBox7ff99e199a36\\SebastianBergmann\\Diff\\Chunk' => $vendorDir . '/sebastian/diff/src/Chunk.php', '_HumbugBox7ff99e199a36\\SebastianBergmann\\Diff\\ConfigurationException' => $vendorDir . '/sebastian/diff/src/Exception/ConfigurationException.php', '_HumbugBox7ff99e199a36\\SebastianBergmann\\Diff\\Diff' => $vendorDir . '/sebastian/diff/src/Diff.php', '_HumbugBox7ff99e199a36\\SebastianBergmann\\Diff\\Differ' => $vendorDir . '/sebastian/diff/src/Differ.php', '_HumbugBox7ff99e199a36\\SebastianBergmann\\Diff\\Exception' => $vendorDir . '/sebastian/diff/src/Exception/Exception.php', '_HumbugBox7ff99e199a36\\SebastianBergmann\\Diff\\InvalidArgumentException' => $vendorDir . '/sebastian/diff/src/Exception/InvalidArgumentException.php', '_HumbugBox7ff99e199a36\\SebastianBergmann\\Diff\\Line' => $vendorDir . '/sebastian/diff/src/Line.php', '_HumbugBox7ff99e199a36\\SebastianBergmann\\Diff\\LongestCommonSubsequenceCalculator' => $vendorDir . '/sebastian/diff/src/LongestCommonSubsequenceCalculator.php', '_HumbugBox7ff99e199a36\\SebastianBergmann\\Diff\\MemoryEfficientLongestCommonSubsequenceCalculator' => $vendorDir . '/sebastian/diff/src/MemoryEfficientLongestCommonSubsequenceCalculator.php', '_HumbugBox7ff99e199a36\\SebastianBergmann\\Diff\\Output\\AbstractChunkOutputBuilder' => $vendorDir . '/sebastian/diff/src/Output/AbstractChunkOutputBuilder.php', '_HumbugBox7ff99e199a36\\SebastianBergmann\\Diff\\Output\\DiffOnlyOutputBuilder' => $vendorDir . '/sebastian/diff/src/Output/DiffOnlyOutputBuilder.php', '_HumbugBox7ff99e199a36\\SebastianBergmann\\Diff\\Output\\DiffOutputBuilderInterface' => $vendorDir . '/sebastian/diff/src/Output/DiffOutputBuilderInterface.php', '_HumbugBox7ff99e199a36\\SebastianBergmann\\Diff\\Output\\StrictUnifiedDiffOutputBuilder' => $vendorDir . '/sebastian/diff/src/Output/StrictUnifiedDiffOutputBuilder.php', '_HumbugBox7ff99e199a36\\SebastianBergmann\\Diff\\Output\\UnifiedDiffOutputBuilder' => $vendorDir . '/sebastian/diff/src/Output/UnifiedDiffOutputBuilder.php', '_HumbugBox7ff99e199a36\\SebastianBergmann\\Diff\\Parser' => $vendorDir . '/sebastian/diff/src/Parser.php', '_HumbugBox7ff99e199a36\\SebastianBergmann\\Diff\\TimeEfficientLongestCommonSubsequenceCalculator' => $vendorDir . '/sebastian/diff/src/TimeEfficientLongestCommonSubsequenceCalculator.php', '_HumbugBox7ff99e199a36\\Spatie\\ArrayToXml\\ArrayToXml' => $vendorDir . '/spatie/array-to-xml/src/ArrayToXml.php', '_HumbugBox7ff99e199a36\\Symfony\\Component\\Console\\Application' => $vendorDir . '/symfony/console/Application.php', '_HumbugBox7ff99e199a36\\Symfony\\Component\\Console\\Attribute\\AsCommand' => $vendorDir . '/symfony/console/Attribute/AsCommand.php', '_HumbugBox7ff99e199a36\\Symfony\\Component\\Console\\CI\\GithubActionReporter' => $vendorDir . '/symfony/console/CI/GithubActionReporter.php', '_HumbugBox7ff99e199a36\\Symfony\\Component\\Console\\Color' => $vendorDir . '/symfony/console/Color.php', '_HumbugBox7ff99e199a36\\Symfony\\Component\\Console\\CommandLoader\\CommandLoaderInterface' => $vendorDir . '/symfony/console/CommandLoader/CommandLoaderInterface.php', '_HumbugBox7ff99e199a36\\Symfony\\Component\\Console\\CommandLoader\\ContainerCommandLoader' => $vendorDir . '/symfony/console/CommandLoader/ContainerCommandLoader.php', '_HumbugBox7ff99e199a36\\Symfony\\Component\\Console\\CommandLoader\\FactoryCommandLoader' => $vendorDir . '/symfony/console/CommandLoader/FactoryCommandLoader.php', '_HumbugBox7ff99e199a36\\Symfony\\Component\\Console\\Command\\Command' => $vendorDir . '/symfony/console/Command/Command.php', '_HumbugBox7ff99e199a36\\Symfony\\Component\\Console\\Command\\CompleteCommand' => $vendorDir . '/symfony/console/Command/CompleteCommand.php', '_HumbugBox7ff99e199a36\\Symfony\\Component\\Console\\Command\\DumpCompletionCommand' => $vendorDir . '/symfony/console/Command/DumpCompletionCommand.php', '_HumbugBox7ff99e199a36\\Symfony\\Component\\Console\\Command\\HelpCommand' => $vendorDir . '/symfony/console/Command/HelpCommand.php', '_HumbugBox7ff99e199a36\\Symfony\\Component\\Console\\Command\\LazyCommand' => $vendorDir . '/symfony/console/Command/LazyCommand.php', '_HumbugBox7ff99e199a36\\Symfony\\Component\\Console\\Command\\ListCommand' => $vendorDir . '/symfony/console/Command/ListCommand.php', '_HumbugBox7ff99e199a36\\Symfony\\Component\\Console\\Command\\LockableTrait' => $vendorDir . '/symfony/console/Command/LockableTrait.php', '_HumbugBox7ff99e199a36\\Symfony\\Component\\Console\\Command\\SignalableCommandInterface' => $vendorDir . '/symfony/console/Command/SignalableCommandInterface.php', '_HumbugBox7ff99e199a36\\Symfony\\Component\\Console\\Completion\\CompletionInput' => $vendorDir . '/symfony/console/Completion/CompletionInput.php', '_HumbugBox7ff99e199a36\\Symfony\\Component\\Console\\Completion\\CompletionSuggestions' => $vendorDir . '/symfony/console/Completion/CompletionSuggestions.php', '_HumbugBox7ff99e199a36\\Symfony\\Component\\Console\\Completion\\Output\\BashCompletionOutput' => $vendorDir . '/symfony/console/Completion/Output/BashCompletionOutput.php', '_HumbugBox7ff99e199a36\\Symfony\\Component\\Console\\Completion\\Output\\CompletionOutputInterface' => $vendorDir . '/symfony/console/Completion/Output/CompletionOutputInterface.php', '_HumbugBox7ff99e199a36\\Symfony\\Component\\Console\\Completion\\Suggestion' => $vendorDir . '/symfony/console/Completion/Suggestion.php', '_HumbugBox7ff99e199a36\\Symfony\\Component\\Console\\ConsoleEvents' => $vendorDir . '/symfony/console/ConsoleEvents.php', '_HumbugBox7ff99e199a36\\Symfony\\Component\\Console\\Cursor' => $vendorDir . '/symfony/console/Cursor.php', '_HumbugBox7ff99e199a36\\Symfony\\Component\\Console\\DependencyInjection\\AddConsoleCommandPass' => $vendorDir . '/symfony/console/DependencyInjection/AddConsoleCommandPass.php', '_HumbugBox7ff99e199a36\\Symfony\\Component\\Console\\Descriptor\\ApplicationDescription' => $vendorDir . '/symfony/console/Descriptor/ApplicationDescription.php', '_HumbugBox7ff99e199a36\\Symfony\\Component\\Console\\Descriptor\\Descriptor' => $vendorDir . '/symfony/console/Descriptor/Descriptor.php', '_HumbugBox7ff99e199a36\\Symfony\\Component\\Console\\Descriptor\\DescriptorInterface' => $vendorDir . '/symfony/console/Descriptor/DescriptorInterface.php', '_HumbugBox7ff99e199a36\\Symfony\\Component\\Console\\Descriptor\\JsonDescriptor' => $vendorDir . '/symfony/console/Descriptor/JsonDescriptor.php', '_HumbugBox7ff99e199a36\\Symfony\\Component\\Console\\Descriptor\\MarkdownDescriptor' => $vendorDir . '/symfony/console/Descriptor/MarkdownDescriptor.php', '_HumbugBox7ff99e199a36\\Symfony\\Component\\Console\\Descriptor\\TextDescriptor' => $vendorDir . '/symfony/console/Descriptor/TextDescriptor.php', '_HumbugBox7ff99e199a36\\Symfony\\Component\\Console\\Descriptor\\XmlDescriptor' => $vendorDir . '/symfony/console/Descriptor/XmlDescriptor.php', '_HumbugBox7ff99e199a36\\Symfony\\Component\\Console\\EventListener\\ErrorListener' => $vendorDir . '/symfony/console/EventListener/ErrorListener.php', '_HumbugBox7ff99e199a36\\Symfony\\Component\\Console\\Event\\ConsoleCommandEvent' => $vendorDir . '/symfony/console/Event/ConsoleCommandEvent.php', '_HumbugBox7ff99e199a36\\Symfony\\Component\\Console\\Event\\ConsoleErrorEvent' => $vendorDir . '/symfony/console/Event/ConsoleErrorEvent.php', '_HumbugBox7ff99e199a36\\Symfony\\Component\\Console\\Event\\ConsoleEvent' => $vendorDir . '/symfony/console/Event/ConsoleEvent.php', '_HumbugBox7ff99e199a36\\Symfony\\Component\\Console\\Event\\ConsoleSignalEvent' => $vendorDir . '/symfony/console/Event/ConsoleSignalEvent.php', '_HumbugBox7ff99e199a36\\Symfony\\Component\\Console\\Event\\ConsoleTerminateEvent' => $vendorDir . '/symfony/console/Event/ConsoleTerminateEvent.php', '_HumbugBox7ff99e199a36\\Symfony\\Component\\Console\\Exception\\CommandNotFoundException' => $vendorDir . '/symfony/console/Exception/CommandNotFoundException.php', '_HumbugBox7ff99e199a36\\Symfony\\Component\\Console\\Exception\\ExceptionInterface' => $vendorDir . '/symfony/console/Exception/ExceptionInterface.php', '_HumbugBox7ff99e199a36\\Symfony\\Component\\Console\\Exception\\InvalidArgumentException' => $vendorDir . '/symfony/console/Exception/InvalidArgumentException.php', '_HumbugBox7ff99e199a36\\Symfony\\Component\\Console\\Exception\\InvalidOptionException' => $vendorDir . '/symfony/console/Exception/InvalidOptionException.php', '_HumbugBox7ff99e199a36\\Symfony\\Component\\Console\\Exception\\LogicException' => $vendorDir . '/symfony/console/Exception/LogicException.php', '_HumbugBox7ff99e199a36\\Symfony\\Component\\Console\\Exception\\MissingInputException' => $vendorDir . '/symfony/console/Exception/MissingInputException.php', '_HumbugBox7ff99e199a36\\Symfony\\Component\\Console\\Exception\\NamespaceNotFoundException' => $vendorDir . '/symfony/console/Exception/NamespaceNotFoundException.php', '_HumbugBox7ff99e199a36\\Symfony\\Component\\Console\\Exception\\RuntimeException' => $vendorDir . '/symfony/console/Exception/RuntimeException.php', '_HumbugBox7ff99e199a36\\Symfony\\Component\\Console\\Formatter\\NullOutputFormatter' => $vendorDir . '/symfony/console/Formatter/NullOutputFormatter.php', '_HumbugBox7ff99e199a36\\Symfony\\Component\\Console\\Formatter\\NullOutputFormatterStyle' => $vendorDir . '/symfony/console/Formatter/NullOutputFormatterStyle.php', '_HumbugBox7ff99e199a36\\Symfony\\Component\\Console\\Formatter\\OutputFormatter' => $vendorDir . '/symfony/console/Formatter/OutputFormatter.php', '_HumbugBox7ff99e199a36\\Symfony\\Component\\Console\\Formatter\\OutputFormatterInterface' => $vendorDir . '/symfony/console/Formatter/OutputFormatterInterface.php', '_HumbugBox7ff99e199a36\\Symfony\\Component\\Console\\Formatter\\OutputFormatterStyle' => $vendorDir . '/symfony/console/Formatter/OutputFormatterStyle.php', '_HumbugBox7ff99e199a36\\Symfony\\Component\\Console\\Formatter\\OutputFormatterStyleInterface' => $vendorDir . '/symfony/console/Formatter/OutputFormatterStyleInterface.php', '_HumbugBox7ff99e199a36\\Symfony\\Component\\Console\\Formatter\\OutputFormatterStyleStack' => $vendorDir . '/symfony/console/Formatter/OutputFormatterStyleStack.php', '_HumbugBox7ff99e199a36\\Symfony\\Component\\Console\\Formatter\\WrappableOutputFormatterInterface' => $vendorDir . '/symfony/console/Formatter/WrappableOutputFormatterInterface.php', '_HumbugBox7ff99e199a36\\Symfony\\Component\\Console\\Helper\\DebugFormatterHelper' => $vendorDir . '/symfony/console/Helper/DebugFormatterHelper.php', '_HumbugBox7ff99e199a36\\Symfony\\Component\\Console\\Helper\\DescriptorHelper' => $vendorDir . '/symfony/console/Helper/DescriptorHelper.php', '_HumbugBox7ff99e199a36\\Symfony\\Component\\Console\\Helper\\Dumper' => $vendorDir . '/symfony/console/Helper/Dumper.php', '_HumbugBox7ff99e199a36\\Symfony\\Component\\Console\\Helper\\FormatterHelper' => $vendorDir . '/symfony/console/Helper/FormatterHelper.php', '_HumbugBox7ff99e199a36\\Symfony\\Component\\Console\\Helper\\Helper' => $vendorDir . '/symfony/console/Helper/Helper.php', '_HumbugBox7ff99e199a36\\Symfony\\Component\\Console\\Helper\\HelperInterface' => $vendorDir . '/symfony/console/Helper/HelperInterface.php', '_HumbugBox7ff99e199a36\\Symfony\\Component\\Console\\Helper\\HelperSet' => $vendorDir . '/symfony/console/Helper/HelperSet.php', '_HumbugBox7ff99e199a36\\Symfony\\Component\\Console\\Helper\\InputAwareHelper' => $vendorDir . '/symfony/console/Helper/InputAwareHelper.php', '_HumbugBox7ff99e199a36\\Symfony\\Component\\Console\\Helper\\ProcessHelper' => $vendorDir . '/symfony/console/Helper/ProcessHelper.php', '_HumbugBox7ff99e199a36\\Symfony\\Component\\Console\\Helper\\ProgressBar' => $vendorDir . '/symfony/console/Helper/ProgressBar.php', '_HumbugBox7ff99e199a36\\Symfony\\Component\\Console\\Helper\\ProgressIndicator' => $vendorDir . '/symfony/console/Helper/ProgressIndicator.php', '_HumbugBox7ff99e199a36\\Symfony\\Component\\Console\\Helper\\QuestionHelper' => $vendorDir . '/symfony/console/Helper/QuestionHelper.php', '_HumbugBox7ff99e199a36\\Symfony\\Component\\Console\\Helper\\SymfonyQuestionHelper' => $vendorDir . '/symfony/console/Helper/SymfonyQuestionHelper.php', '_HumbugBox7ff99e199a36\\Symfony\\Component\\Console\\Helper\\Table' => $vendorDir . '/symfony/console/Helper/Table.php', '_HumbugBox7ff99e199a36\\Symfony\\Component\\Console\\Helper\\TableCell' => $vendorDir . '/symfony/console/Helper/TableCell.php', '_HumbugBox7ff99e199a36\\Symfony\\Component\\Console\\Helper\\TableCellStyle' => $vendorDir . '/symfony/console/Helper/TableCellStyle.php', '_HumbugBox7ff99e199a36\\Symfony\\Component\\Console\\Helper\\TableRows' => $vendorDir . '/symfony/console/Helper/TableRows.php', '_HumbugBox7ff99e199a36\\Symfony\\Component\\Console\\Helper\\TableSeparator' => $vendorDir . '/symfony/console/Helper/TableSeparator.php', '_HumbugBox7ff99e199a36\\Symfony\\Component\\Console\\Helper\\TableStyle' => $vendorDir . '/symfony/console/Helper/TableStyle.php', '_HumbugBox7ff99e199a36\\Symfony\\Component\\Console\\Input\\ArgvInput' => $vendorDir . '/symfony/console/Input/ArgvInput.php', '_HumbugBox7ff99e199a36\\Symfony\\Component\\Console\\Input\\ArrayInput' => $vendorDir . '/symfony/console/Input/ArrayInput.php', '_HumbugBox7ff99e199a36\\Symfony\\Component\\Console\\Input\\Input' => $vendorDir . '/symfony/console/Input/Input.php', '_HumbugBox7ff99e199a36\\Symfony\\Component\\Console\\Input\\InputArgument' => $vendorDir . '/symfony/console/Input/InputArgument.php', '_HumbugBox7ff99e199a36\\Symfony\\Component\\Console\\Input\\InputAwareInterface' => $vendorDir . '/symfony/console/Input/InputAwareInterface.php', '_HumbugBox7ff99e199a36\\Symfony\\Component\\Console\\Input\\InputDefinition' => $vendorDir . '/symfony/console/Input/InputDefinition.php', '_HumbugBox7ff99e199a36\\Symfony\\Component\\Console\\Input\\InputInterface' => $vendorDir . '/symfony/console/Input/InputInterface.php', '_HumbugBox7ff99e199a36\\Symfony\\Component\\Console\\Input\\InputOption' => $vendorDir . '/symfony/console/Input/InputOption.php', '_HumbugBox7ff99e199a36\\Symfony\\Component\\Console\\Input\\StreamableInputInterface' => $vendorDir . '/symfony/console/Input/StreamableInputInterface.php', '_HumbugBox7ff99e199a36\\Symfony\\Component\\Console\\Input\\StringInput' => $vendorDir . '/symfony/console/Input/StringInput.php', '_HumbugBox7ff99e199a36\\Symfony\\Component\\Console\\Logger\\ConsoleLogger' => $vendorDir . '/symfony/console/Logger/ConsoleLogger.php', '_HumbugBox7ff99e199a36\\Symfony\\Component\\Console\\Output\\BufferedOutput' => $vendorDir . '/symfony/console/Output/BufferedOutput.php', '_HumbugBox7ff99e199a36\\Symfony\\Component\\Console\\Output\\ConsoleOutput' => $vendorDir . '/symfony/console/Output/ConsoleOutput.php', '_HumbugBox7ff99e199a36\\Symfony\\Component\\Console\\Output\\ConsoleOutputInterface' => $vendorDir . '/symfony/console/Output/ConsoleOutputInterface.php', '_HumbugBox7ff99e199a36\\Symfony\\Component\\Console\\Output\\ConsoleSectionOutput' => $vendorDir . '/symfony/console/Output/ConsoleSectionOutput.php', '_HumbugBox7ff99e199a36\\Symfony\\Component\\Console\\Output\\NullOutput' => $vendorDir . '/symfony/console/Output/NullOutput.php', '_HumbugBox7ff99e199a36\\Symfony\\Component\\Console\\Output\\Output' => $vendorDir . '/symfony/console/Output/Output.php', '_HumbugBox7ff99e199a36\\Symfony\\Component\\Console\\Output\\OutputInterface' => $vendorDir . '/symfony/console/Output/OutputInterface.php', '_HumbugBox7ff99e199a36\\Symfony\\Component\\Console\\Output\\StreamOutput' => $vendorDir . '/symfony/console/Output/StreamOutput.php', '_HumbugBox7ff99e199a36\\Symfony\\Component\\Console\\Output\\TrimmedBufferOutput' => $vendorDir . '/symfony/console/Output/TrimmedBufferOutput.php', '_HumbugBox7ff99e199a36\\Symfony\\Component\\Console\\Question\\ChoiceQuestion' => $vendorDir . '/symfony/console/Question/ChoiceQuestion.php', '_HumbugBox7ff99e199a36\\Symfony\\Component\\Console\\Question\\ConfirmationQuestion' => $vendorDir . '/symfony/console/Question/ConfirmationQuestion.php', '_HumbugBox7ff99e199a36\\Symfony\\Component\\Console\\Question\\Question' => $vendorDir . '/symfony/console/Question/Question.php', '_HumbugBox7ff99e199a36\\Symfony\\Component\\Console\\SignalRegistry\\SignalRegistry' => $vendorDir . '/symfony/console/SignalRegistry/SignalRegistry.php', '_HumbugBox7ff99e199a36\\Symfony\\Component\\Console\\SingleCommandApplication' => $vendorDir . '/symfony/console/SingleCommandApplication.php', '_HumbugBox7ff99e199a36\\Symfony\\Component\\Console\\Style\\OutputStyle' => $vendorDir . '/symfony/console/Style/OutputStyle.php', '_HumbugBox7ff99e199a36\\Symfony\\Component\\Console\\Style\\StyleInterface' => $vendorDir . '/symfony/console/Style/StyleInterface.php', '_HumbugBox7ff99e199a36\\Symfony\\Component\\Console\\Style\\SymfonyStyle' => $vendorDir . '/symfony/console/Style/SymfonyStyle.php', '_HumbugBox7ff99e199a36\\Symfony\\Component\\Console\\Terminal' => $vendorDir . '/symfony/console/Terminal.php', '_HumbugBox7ff99e199a36\\Symfony\\Component\\Console\\Tester\\ApplicationTester' => $vendorDir . '/symfony/console/Tester/ApplicationTester.php', '_HumbugBox7ff99e199a36\\Symfony\\Component\\Console\\Tester\\CommandCompletionTester' => $vendorDir . '/symfony/console/Tester/CommandCompletionTester.php', '_HumbugBox7ff99e199a36\\Symfony\\Component\\Console\\Tester\\CommandTester' => $vendorDir . '/symfony/console/Tester/CommandTester.php', '_HumbugBox7ff99e199a36\\Symfony\\Component\\Console\\Tester\\Constraint\\CommandIsSuccessful' => $vendorDir . '/symfony/console/Tester/Constraint/CommandIsSuccessful.php', '_HumbugBox7ff99e199a36\\Symfony\\Component\\Console\\Tester\\TesterTrait' => $vendorDir . '/symfony/console/Tester/TesterTrait.php', '_HumbugBox7ff99e199a36\\Symfony\\Component\\Filesystem\\Exception\\ExceptionInterface' => $vendorDir . '/symfony/filesystem/Exception/ExceptionInterface.php', '_HumbugBox7ff99e199a36\\Symfony\\Component\\Filesystem\\Exception\\FileNotFoundException' => $vendorDir . '/symfony/filesystem/Exception/FileNotFoundException.php', '_HumbugBox7ff99e199a36\\Symfony\\Component\\Filesystem\\Exception\\IOException' => $vendorDir . '/symfony/filesystem/Exception/IOException.php', '_HumbugBox7ff99e199a36\\Symfony\\Component\\Filesystem\\Exception\\IOExceptionInterface' => $vendorDir . '/symfony/filesystem/Exception/IOExceptionInterface.php', '_HumbugBox7ff99e199a36\\Symfony\\Component\\Filesystem\\Exception\\InvalidArgumentException' => $vendorDir . '/symfony/filesystem/Exception/InvalidArgumentException.php', '_HumbugBox7ff99e199a36\\Symfony\\Component\\Filesystem\\Exception\\RuntimeException' => $vendorDir . '/symfony/filesystem/Exception/RuntimeException.php', '_HumbugBox7ff99e199a36\\Symfony\\Component\\Filesystem\\Filesystem' => $vendorDir . '/symfony/filesystem/Filesystem.php', '_HumbugBox7ff99e199a36\\Symfony\\Component\\Filesystem\\Path' => $vendorDir . '/symfony/filesystem/Path.php', '_HumbugBox7ff99e199a36\\Symfony\\Component\\String\\AbstractString' => $vendorDir . '/symfony/string/AbstractString.php', '_HumbugBox7ff99e199a36\\Symfony\\Component\\String\\AbstractUnicodeString' => $vendorDir . '/symfony/string/AbstractUnicodeString.php', '_HumbugBox7ff99e199a36\\Symfony\\Component\\String\\ByteString' => $vendorDir . '/symfony/string/ByteString.php', '_HumbugBox7ff99e199a36\\Symfony\\Component\\String\\CodePointString' => $vendorDir . '/symfony/string/CodePointString.php', '_HumbugBox7ff99e199a36\\Symfony\\Component\\String\\Exception\\ExceptionInterface' => $vendorDir . '/symfony/string/Exception/ExceptionInterface.php', '_HumbugBox7ff99e199a36\\Symfony\\Component\\String\\Exception\\InvalidArgumentException' => $vendorDir . '/symfony/string/Exception/InvalidArgumentException.php', '_HumbugBox7ff99e199a36\\Symfony\\Component\\String\\Exception\\RuntimeException' => $vendorDir . '/symfony/string/Exception/RuntimeException.php', '_HumbugBox7ff99e199a36\\Symfony\\Component\\String\\Inflector\\EnglishInflector' => $vendorDir . '/symfony/string/Inflector/EnglishInflector.php', '_HumbugBox7ff99e199a36\\Symfony\\Component\\String\\Inflector\\FrenchInflector' => $vendorDir . '/symfony/string/Inflector/FrenchInflector.php', '_HumbugBox7ff99e199a36\\Symfony\\Component\\String\\Inflector\\InflectorInterface' => $vendorDir . '/symfony/string/Inflector/InflectorInterface.php', '_HumbugBox7ff99e199a36\\Symfony\\Component\\String\\LazyString' => $vendorDir . '/symfony/string/LazyString.php', '_HumbugBox7ff99e199a36\\Symfony\\Component\\String\\Slugger\\AsciiSlugger' => $vendorDir . '/symfony/string/Slugger/AsciiSlugger.php', '_HumbugBox7ff99e199a36\\Symfony\\Component\\String\\Slugger\\SluggerInterface' => $vendorDir . '/symfony/string/Slugger/SluggerInterface.php', '_HumbugBox7ff99e199a36\\Symfony\\Component\\String\\UnicodeString' => $vendorDir . '/symfony/string/UnicodeString.php', '_HumbugBox7ff99e199a36\\Symfony\\Contracts\\Service\\Attribute\\Required' => $vendorDir . '/symfony/service-contracts/Attribute/Required.php', '_HumbugBox7ff99e199a36\\Symfony\\Contracts\\Service\\Attribute\\SubscribedService' => $vendorDir . '/symfony/service-contracts/Attribute/SubscribedService.php', '_HumbugBox7ff99e199a36\\Symfony\\Contracts\\Service\\ResetInterface' => $vendorDir . '/symfony/service-contracts/ResetInterface.php', '_HumbugBox7ff99e199a36\\Symfony\\Contracts\\Service\\ServiceLocatorTrait' => $vendorDir . '/symfony/service-contracts/ServiceLocatorTrait.php', '_HumbugBox7ff99e199a36\\Symfony\\Contracts\\Service\\ServiceProviderInterface' => $vendorDir . '/symfony/service-contracts/ServiceProviderInterface.php', '_HumbugBox7ff99e199a36\\Symfony\\Contracts\\Service\\ServiceSubscriberInterface' => $vendorDir . '/symfony/service-contracts/ServiceSubscriberInterface.php', '_HumbugBox7ff99e199a36\\Symfony\\Contracts\\Service\\ServiceSubscriberTrait' => $vendorDir . '/symfony/service-contracts/ServiceSubscriberTrait.php', '_HumbugBox7ff99e199a36\\Symfony\\Polyfill\\Ctype\\Ctype' => $vendorDir . '/symfony/polyfill-ctype/Ctype.php', '_HumbugBox7ff99e199a36\\Symfony\\Polyfill\\Intl\\Grapheme\\Grapheme' => $vendorDir . '/symfony/polyfill-intl-grapheme/Grapheme.php', '_HumbugBox7ff99e199a36\\Symfony\\Polyfill\\Intl\\Normalizer\\Normalizer' => $vendorDir . '/symfony/polyfill-intl-normalizer/Normalizer.php', '_HumbugBox7ff99e199a36\\Symfony\\Polyfill\\Mbstring\\Mbstring' => $vendorDir . '/symfony/polyfill-mbstring/Mbstring.php', '_HumbugBox7ff99e199a36\\Symfony\\Polyfill\\Php73\\Php73' => $vendorDir . '/symfony/polyfill-php73/Php73.php', '_HumbugBox7ff99e199a36\\UnhandledMatchError' => $vendorDir . '/symfony/polyfill-php80/Resources/stubs/UnhandledMatchError.php', '_HumbugBox7ff99e199a36\\ValueError' => $vendorDir . '/symfony/polyfill-php80/Resources/stubs/ValueError.php', '_HumbugBox7ff99e199a36\\Webmozart\\Assert\\Assert' => $vendorDir . '/webmozart/assert/src/Assert.php', '_HumbugBox7ff99e199a36\\Webmozart\\Assert\\InvalidArgumentException' => $vendorDir . '/webmozart/assert/src/InvalidArgumentException.php', '_HumbugBox7ff99e199a36\\Webmozart\\Assert\\Mixin' => $vendorDir . '/webmozart/assert/src/Mixin.php', '_HumbugBox7ff99e199a36\\XdgBaseDir\\Xdg' => $vendorDir . '/dnoegel/php-xdg-base-dir/src/Xdg.php', '_HumbugBox7ff99e199a36\\phpDocumentor\\Reflection\\DocBlock' => $vendorDir . '/phpdocumentor/reflection-docblock/src/DocBlock.php', '_HumbugBox7ff99e199a36\\phpDocumentor\\Reflection\\DocBlockFactory' => $vendorDir . '/phpdocumentor/reflection-docblock/src/DocBlockFactory.php', '_HumbugBox7ff99e199a36\\phpDocumentor\\Reflection\\DocBlockFactoryInterface' => $vendorDir . '/phpdocumentor/reflection-docblock/src/DocBlockFactoryInterface.php', '_HumbugBox7ff99e199a36\\phpDocumentor\\Reflection\\DocBlock\\Description' => $vendorDir . '/phpdocumentor/reflection-docblock/src/DocBlock/Description.php', '_HumbugBox7ff99e199a36\\phpDocumentor\\Reflection\\DocBlock\\DescriptionFactory' => $vendorDir . '/phpdocumentor/reflection-docblock/src/DocBlock/DescriptionFactory.php', '_HumbugBox7ff99e199a36\\phpDocumentor\\Reflection\\DocBlock\\ExampleFinder' => $vendorDir . '/phpdocumentor/reflection-docblock/src/DocBlock/ExampleFinder.php', '_HumbugBox7ff99e199a36\\phpDocumentor\\Reflection\\DocBlock\\Serializer' => $vendorDir . '/phpdocumentor/reflection-docblock/src/DocBlock/Serializer.php', '_HumbugBox7ff99e199a36\\phpDocumentor\\Reflection\\DocBlock\\StandardTagFactory' => $vendorDir . '/phpdocumentor/reflection-docblock/src/DocBlock/StandardTagFactory.php', '_HumbugBox7ff99e199a36\\phpDocumentor\\Reflection\\DocBlock\\Tag' => $vendorDir . '/phpdocumentor/reflection-docblock/src/DocBlock/Tag.php', '_HumbugBox7ff99e199a36\\phpDocumentor\\Reflection\\DocBlock\\TagFactory' => $vendorDir . '/phpdocumentor/reflection-docblock/src/DocBlock/TagFactory.php', '_HumbugBox7ff99e199a36\\phpDocumentor\\Reflection\\DocBlock\\Tags\\Author' => $vendorDir . '/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Author.php', '_HumbugBox7ff99e199a36\\phpDocumentor\\Reflection\\DocBlock\\Tags\\BaseTag' => $vendorDir . '/phpdocumentor/reflection-docblock/src/DocBlock/Tags/BaseTag.php', '_HumbugBox7ff99e199a36\\phpDocumentor\\Reflection\\DocBlock\\Tags\\Covers' => $vendorDir . '/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Covers.php', '_HumbugBox7ff99e199a36\\phpDocumentor\\Reflection\\DocBlock\\Tags\\Deprecated' => $vendorDir . '/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Deprecated.php', '_HumbugBox7ff99e199a36\\phpDocumentor\\Reflection\\DocBlock\\Tags\\Example' => $vendorDir . '/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Example.php', '_HumbugBox7ff99e199a36\\phpDocumentor\\Reflection\\DocBlock\\Tags\\Factory\\AbstractPHPStanFactory' => $vendorDir . '/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Factory/AbstractPHPStanFactory.php', '_HumbugBox7ff99e199a36\\phpDocumentor\\Reflection\\DocBlock\\Tags\\Factory\\Factory' => $vendorDir . '/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Factory/Factory.php', '_HumbugBox7ff99e199a36\\phpDocumentor\\Reflection\\DocBlock\\Tags\\Factory\\MethodFactory' => $vendorDir . '/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Factory/MethodFactory.php', '_HumbugBox7ff99e199a36\\phpDocumentor\\Reflection\\DocBlock\\Tags\\Factory\\PHPStanFactory' => $vendorDir . '/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Factory/PHPStanFactory.php', '_HumbugBox7ff99e199a36\\phpDocumentor\\Reflection\\DocBlock\\Tags\\Factory\\ParamFactory' => $vendorDir . '/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Factory/ParamFactory.php', '_HumbugBox7ff99e199a36\\phpDocumentor\\Reflection\\DocBlock\\Tags\\Factory\\PropertyFactory' => $vendorDir . '/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Factory/PropertyFactory.php', '_HumbugBox7ff99e199a36\\phpDocumentor\\Reflection\\DocBlock\\Tags\\Factory\\PropertyReadFactory' => $vendorDir . '/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Factory/PropertyReadFactory.php', '_HumbugBox7ff99e199a36\\phpDocumentor\\Reflection\\DocBlock\\Tags\\Factory\\PropertyWriteFactory' => $vendorDir . '/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Factory/PropertyWriteFactory.php', '_HumbugBox7ff99e199a36\\phpDocumentor\\Reflection\\DocBlock\\Tags\\Factory\\ReturnFactory' => $vendorDir . '/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Factory/ReturnFactory.php', '_HumbugBox7ff99e199a36\\phpDocumentor\\Reflection\\DocBlock\\Tags\\Factory\\StaticMethod' => $vendorDir . '/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Factory/StaticMethod.php', '_HumbugBox7ff99e199a36\\phpDocumentor\\Reflection\\DocBlock\\Tags\\Factory\\VarFactory' => $vendorDir . '/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Factory/VarFactory.php', '_HumbugBox7ff99e199a36\\phpDocumentor\\Reflection\\DocBlock\\Tags\\Formatter' => $vendorDir . '/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Formatter.php', '_HumbugBox7ff99e199a36\\phpDocumentor\\Reflection\\DocBlock\\Tags\\Formatter\\AlignFormatter' => $vendorDir . '/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Formatter/AlignFormatter.php', '_HumbugBox7ff99e199a36\\phpDocumentor\\Reflection\\DocBlock\\Tags\\Formatter\\PassthroughFormatter' => $vendorDir . '/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Formatter/PassthroughFormatter.php', '_HumbugBox7ff99e199a36\\phpDocumentor\\Reflection\\DocBlock\\Tags\\Generic' => $vendorDir . '/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Generic.php', '_HumbugBox7ff99e199a36\\phpDocumentor\\Reflection\\DocBlock\\Tags\\InvalidTag' => $vendorDir . '/phpdocumentor/reflection-docblock/src/DocBlock/Tags/InvalidTag.php', '_HumbugBox7ff99e199a36\\phpDocumentor\\Reflection\\DocBlock\\Tags\\Link' => $vendorDir . '/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Link.php', '_HumbugBox7ff99e199a36\\phpDocumentor\\Reflection\\DocBlock\\Tags\\Method' => $vendorDir . '/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Method.php', '_HumbugBox7ff99e199a36\\phpDocumentor\\Reflection\\DocBlock\\Tags\\MethodParameter' => $vendorDir . '/phpdocumentor/reflection-docblock/src/DocBlock/Tags/MethodParameter.php', '_HumbugBox7ff99e199a36\\phpDocumentor\\Reflection\\DocBlock\\Tags\\Param' => $vendorDir . '/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Param.php', '_HumbugBox7ff99e199a36\\phpDocumentor\\Reflection\\DocBlock\\Tags\\Property' => $vendorDir . '/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Property.php', '_HumbugBox7ff99e199a36\\phpDocumentor\\Reflection\\DocBlock\\Tags\\PropertyRead' => $vendorDir . '/phpdocumentor/reflection-docblock/src/DocBlock/Tags/PropertyRead.php', '_HumbugBox7ff99e199a36\\phpDocumentor\\Reflection\\DocBlock\\Tags\\PropertyWrite' => $vendorDir . '/phpdocumentor/reflection-docblock/src/DocBlock/Tags/PropertyWrite.php', '_HumbugBox7ff99e199a36\\phpDocumentor\\Reflection\\DocBlock\\Tags\\Reference\\Fqsen' => $vendorDir . '/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Reference/Fqsen.php', '_HumbugBox7ff99e199a36\\phpDocumentor\\Reflection\\DocBlock\\Tags\\Reference\\Reference' => $vendorDir . '/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Reference/Reference.php', '_HumbugBox7ff99e199a36\\phpDocumentor\\Reflection\\DocBlock\\Tags\\Reference\\Url' => $vendorDir . '/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Reference/Url.php', '_HumbugBox7ff99e199a36\\phpDocumentor\\Reflection\\DocBlock\\Tags\\Return_' => $vendorDir . '/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Return_.php', '_HumbugBox7ff99e199a36\\phpDocumentor\\Reflection\\DocBlock\\Tags\\See' => $vendorDir . '/phpdocumentor/reflection-docblock/src/DocBlock/Tags/See.php', '_HumbugBox7ff99e199a36\\phpDocumentor\\Reflection\\DocBlock\\Tags\\Since' => $vendorDir . '/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Since.php', '_HumbugBox7ff99e199a36\\phpDocumentor\\Reflection\\DocBlock\\Tags\\Source' => $vendorDir . '/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Source.php', '_HumbugBox7ff99e199a36\\phpDocumentor\\Reflection\\DocBlock\\Tags\\TagWithType' => $vendorDir . '/phpdocumentor/reflection-docblock/src/DocBlock/Tags/TagWithType.php', '_HumbugBox7ff99e199a36\\phpDocumentor\\Reflection\\DocBlock\\Tags\\Throws' => $vendorDir . '/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Throws.php', '_HumbugBox7ff99e199a36\\phpDocumentor\\Reflection\\DocBlock\\Tags\\Uses' => $vendorDir . '/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Uses.php', '_HumbugBox7ff99e199a36\\phpDocumentor\\Reflection\\DocBlock\\Tags\\Var_' => $vendorDir . '/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Var_.php', '_HumbugBox7ff99e199a36\\phpDocumentor\\Reflection\\DocBlock\\Tags\\Version' => $vendorDir . '/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Version.php', '_HumbugBox7ff99e199a36\\phpDocumentor\\Reflection\\Element' => $vendorDir . '/phpdocumentor/reflection-common/src/Element.php', '_HumbugBox7ff99e199a36\\phpDocumentor\\Reflection\\Exception\\PcreException' => $vendorDir . '/phpdocumentor/reflection-docblock/src/Exception/PcreException.php', '_HumbugBox7ff99e199a36\\phpDocumentor\\Reflection\\File' => $vendorDir . '/phpdocumentor/reflection-common/src/File.php', '_HumbugBox7ff99e199a36\\phpDocumentor\\Reflection\\Fqsen' => $vendorDir . '/phpdocumentor/reflection-common/src/Fqsen.php', '_HumbugBox7ff99e199a36\\phpDocumentor\\Reflection\\FqsenResolver' => $vendorDir . '/phpdocumentor/type-resolver/src/FqsenResolver.php', '_HumbugBox7ff99e199a36\\phpDocumentor\\Reflection\\Location' => $vendorDir . '/phpdocumentor/reflection-common/src/Location.php', '_HumbugBox7ff99e199a36\\phpDocumentor\\Reflection\\Project' => $vendorDir . '/phpdocumentor/reflection-common/src/Project.php', '_HumbugBox7ff99e199a36\\phpDocumentor\\Reflection\\ProjectFactory' => $vendorDir . '/phpdocumentor/reflection-common/src/ProjectFactory.php', '_HumbugBox7ff99e199a36\\phpDocumentor\\Reflection\\PseudoType' => $vendorDir . '/phpdocumentor/type-resolver/src/PseudoType.php', '_HumbugBox7ff99e199a36\\phpDocumentor\\Reflection\\PseudoTypes\\ArrayShape' => $vendorDir . '/phpdocumentor/type-resolver/src/PseudoTypes/ArrayShape.php', '_HumbugBox7ff99e199a36\\phpDocumentor\\Reflection\\PseudoTypes\\ArrayShapeItem' => $vendorDir . '/phpdocumentor/type-resolver/src/PseudoTypes/ArrayShapeItem.php', '_HumbugBox7ff99e199a36\\phpDocumentor\\Reflection\\PseudoTypes\\CallableString' => $vendorDir . '/phpdocumentor/type-resolver/src/PseudoTypes/CallableString.php', '_HumbugBox7ff99e199a36\\phpDocumentor\\Reflection\\PseudoTypes\\ConstExpression' => $vendorDir . '/phpdocumentor/type-resolver/src/PseudoTypes/ConstExpression.php', '_HumbugBox7ff99e199a36\\phpDocumentor\\Reflection\\PseudoTypes\\False_' => $vendorDir . '/phpdocumentor/type-resolver/src/PseudoTypes/False_.php', '_HumbugBox7ff99e199a36\\phpDocumentor\\Reflection\\PseudoTypes\\FloatValue' => $vendorDir . '/phpdocumentor/type-resolver/src/PseudoTypes/FloatValue.php', '_HumbugBox7ff99e199a36\\phpDocumentor\\Reflection\\PseudoTypes\\HtmlEscapedString' => $vendorDir . '/phpdocumentor/type-resolver/src/PseudoTypes/HtmlEscapedString.php', '_HumbugBox7ff99e199a36\\phpDocumentor\\Reflection\\PseudoTypes\\IntegerRange' => $vendorDir . '/phpdocumentor/type-resolver/src/PseudoTypes/IntegerRange.php', '_HumbugBox7ff99e199a36\\phpDocumentor\\Reflection\\PseudoTypes\\IntegerValue' => $vendorDir . '/phpdocumentor/type-resolver/src/PseudoTypes/IntegerValue.php', '_HumbugBox7ff99e199a36\\phpDocumentor\\Reflection\\PseudoTypes\\List_' => $vendorDir . '/phpdocumentor/type-resolver/src/PseudoTypes/List_.php', '_HumbugBox7ff99e199a36\\phpDocumentor\\Reflection\\PseudoTypes\\LiteralString' => $vendorDir . '/phpdocumentor/type-resolver/src/PseudoTypes/LiteralString.php', '_HumbugBox7ff99e199a36\\phpDocumentor\\Reflection\\PseudoTypes\\LowercaseString' => $vendorDir . '/phpdocumentor/type-resolver/src/PseudoTypes/LowercaseString.php', '_HumbugBox7ff99e199a36\\phpDocumentor\\Reflection\\PseudoTypes\\NegativeInteger' => $vendorDir . '/phpdocumentor/type-resolver/src/PseudoTypes/NegativeInteger.php', '_HumbugBox7ff99e199a36\\phpDocumentor\\Reflection\\PseudoTypes\\NonEmptyList' => $vendorDir . '/phpdocumentor/type-resolver/src/PseudoTypes/NonEmptyList.php', '_HumbugBox7ff99e199a36\\phpDocumentor\\Reflection\\PseudoTypes\\NonEmptyLowercaseString' => $vendorDir . '/phpdocumentor/type-resolver/src/PseudoTypes/NonEmptyLowercaseString.php', '_HumbugBox7ff99e199a36\\phpDocumentor\\Reflection\\PseudoTypes\\NonEmptyString' => $vendorDir . '/phpdocumentor/type-resolver/src/PseudoTypes/NonEmptyString.php', '_HumbugBox7ff99e199a36\\phpDocumentor\\Reflection\\PseudoTypes\\NumericString' => $vendorDir . '/phpdocumentor/type-resolver/src/PseudoTypes/NumericString.php', '_HumbugBox7ff99e199a36\\phpDocumentor\\Reflection\\PseudoTypes\\Numeric_' => $vendorDir . '/phpdocumentor/type-resolver/src/PseudoTypes/Numeric_.php', '_HumbugBox7ff99e199a36\\phpDocumentor\\Reflection\\PseudoTypes\\PositiveInteger' => $vendorDir . '/phpdocumentor/type-resolver/src/PseudoTypes/PositiveInteger.php', '_HumbugBox7ff99e199a36\\phpDocumentor\\Reflection\\PseudoTypes\\StringValue' => $vendorDir . '/phpdocumentor/type-resolver/src/PseudoTypes/StringValue.php', '_HumbugBox7ff99e199a36\\phpDocumentor\\Reflection\\PseudoTypes\\TraitString' => $vendorDir . '/phpdocumentor/type-resolver/src/PseudoTypes/TraitString.php', '_HumbugBox7ff99e199a36\\phpDocumentor\\Reflection\\PseudoTypes\\True_' => $vendorDir . '/phpdocumentor/type-resolver/src/PseudoTypes/True_.php', '_HumbugBox7ff99e199a36\\phpDocumentor\\Reflection\\Type' => $vendorDir . '/phpdocumentor/type-resolver/src/Type.php', '_HumbugBox7ff99e199a36\\phpDocumentor\\Reflection\\TypeResolver' => $vendorDir . '/phpdocumentor/type-resolver/src/TypeResolver.php', '_HumbugBox7ff99e199a36\\phpDocumentor\\Reflection\\Types\\AbstractList' => $vendorDir . '/phpdocumentor/type-resolver/src/Types/AbstractList.php', '_HumbugBox7ff99e199a36\\phpDocumentor\\Reflection\\Types\\AggregatedType' => $vendorDir . '/phpdocumentor/type-resolver/src/Types/AggregatedType.php', '_HumbugBox7ff99e199a36\\phpDocumentor\\Reflection\\Types\\ArrayKey' => $vendorDir . '/phpdocumentor/type-resolver/src/Types/ArrayKey.php', '_HumbugBox7ff99e199a36\\phpDocumentor\\Reflection\\Types\\Array_' => $vendorDir . '/phpdocumentor/type-resolver/src/Types/Array_.php', '_HumbugBox7ff99e199a36\\phpDocumentor\\Reflection\\Types\\Boolean' => $vendorDir . '/phpdocumentor/type-resolver/src/Types/Boolean.php', '_HumbugBox7ff99e199a36\\phpDocumentor\\Reflection\\Types\\CallableParameter' => $vendorDir . '/phpdocumentor/type-resolver/src/Types/CallableParameter.php', '_HumbugBox7ff99e199a36\\phpDocumentor\\Reflection\\Types\\Callable_' => $vendorDir . '/phpdocumentor/type-resolver/src/Types/Callable_.php', '_HumbugBox7ff99e199a36\\phpDocumentor\\Reflection\\Types\\ClassString' => $vendorDir . '/phpdocumentor/type-resolver/src/Types/ClassString.php', '_HumbugBox7ff99e199a36\\phpDocumentor\\Reflection\\Types\\Collection' => $vendorDir . '/phpdocumentor/type-resolver/src/Types/Collection.php', '_HumbugBox7ff99e199a36\\phpDocumentor\\Reflection\\Types\\Compound' => $vendorDir . '/phpdocumentor/type-resolver/src/Types/Compound.php', '_HumbugBox7ff99e199a36\\phpDocumentor\\Reflection\\Types\\Context' => $vendorDir . '/phpdocumentor/type-resolver/src/Types/Context.php', '_HumbugBox7ff99e199a36\\phpDocumentor\\Reflection\\Types\\ContextFactory' => $vendorDir . '/phpdocumentor/type-resolver/src/Types/ContextFactory.php', '_HumbugBox7ff99e199a36\\phpDocumentor\\Reflection\\Types\\Expression' => $vendorDir . '/phpdocumentor/type-resolver/src/Types/Expression.php', '_HumbugBox7ff99e199a36\\phpDocumentor\\Reflection\\Types\\Float_' => $vendorDir . '/phpdocumentor/type-resolver/src/Types/Float_.php', '_HumbugBox7ff99e199a36\\phpDocumentor\\Reflection\\Types\\Integer' => $vendorDir . '/phpdocumentor/type-resolver/src/Types/Integer.php', '_HumbugBox7ff99e199a36\\phpDocumentor\\Reflection\\Types\\InterfaceString' => $vendorDir . '/phpdocumentor/type-resolver/src/Types/InterfaceString.php', '_HumbugBox7ff99e199a36\\phpDocumentor\\Reflection\\Types\\Intersection' => $vendorDir . '/phpdocumentor/type-resolver/src/Types/Intersection.php', '_HumbugBox7ff99e199a36\\phpDocumentor\\Reflection\\Types\\Iterable_' => $vendorDir . '/phpdocumentor/type-resolver/src/Types/Iterable_.php', '_HumbugBox7ff99e199a36\\phpDocumentor\\Reflection\\Types\\Mixed_' => $vendorDir . '/phpdocumentor/type-resolver/src/Types/Mixed_.php', '_HumbugBox7ff99e199a36\\phpDocumentor\\Reflection\\Types\\Never_' => $vendorDir . '/phpdocumentor/type-resolver/src/Types/Never_.php', '_HumbugBox7ff99e199a36\\phpDocumentor\\Reflection\\Types\\Null_' => $vendorDir . '/phpdocumentor/type-resolver/src/Types/Null_.php', '_HumbugBox7ff99e199a36\\phpDocumentor\\Reflection\\Types\\Nullable' => $vendorDir . '/phpdocumentor/type-resolver/src/Types/Nullable.php', '_HumbugBox7ff99e199a36\\phpDocumentor\\Reflection\\Types\\Object_' => $vendorDir . '/phpdocumentor/type-resolver/src/Types/Object_.php', '_HumbugBox7ff99e199a36\\phpDocumentor\\Reflection\\Types\\Parent_' => $vendorDir . '/phpdocumentor/type-resolver/src/Types/Parent_.php', '_HumbugBox7ff99e199a36\\phpDocumentor\\Reflection\\Types\\Resource_' => $vendorDir . '/phpdocumentor/type-resolver/src/Types/Resource_.php', '_HumbugBox7ff99e199a36\\phpDocumentor\\Reflection\\Types\\Scalar' => $vendorDir . '/phpdocumentor/type-resolver/src/Types/Scalar.php', '_HumbugBox7ff99e199a36\\phpDocumentor\\Reflection\\Types\\Self_' => $vendorDir . '/phpdocumentor/type-resolver/src/Types/Self_.php', '_HumbugBox7ff99e199a36\\phpDocumentor\\Reflection\\Types\\Static_' => $vendorDir . '/phpdocumentor/type-resolver/src/Types/Static_.php', '_HumbugBox7ff99e199a36\\phpDocumentor\\Reflection\\Types\\String_' => $vendorDir . '/phpdocumentor/type-resolver/src/Types/String_.php', '_HumbugBox7ff99e199a36\\phpDocumentor\\Reflection\\Types\\This' => $vendorDir . '/phpdocumentor/type-resolver/src/Types/This.php', '_HumbugBox7ff99e199a36\\phpDocumentor\\Reflection\\Types\\Void_' => $vendorDir . '/phpdocumentor/type-resolver/src/Types/Void_.php', '_HumbugBox7ff99e199a36\\phpDocumentor\\Reflection\\Utils' => $vendorDir . '/phpdocumentor/reflection-docblock/src/Utils.php', ); * Jordi Boggiano * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace _HumbugBox7ff99e199a36\Composer; use Composer\Autoload\ClassLoader; use _HumbugBox7ff99e199a36\Composer\Semver\VersionParser; /** * This class is copied in every Composer installed project and available to all * * See also https://getcomposer.org/doc/07-runtime.md#installed-versions * * To require its presence, you can require `composer-runtime-api ^2.0` * * @final */ class InstalledVersions { /** * @var mixed[]|null * @psalm-var array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array}|array{}|null */ private static $installed; /** * @var bool|null */ private static $canGetVendors; /** * @var array[] * @psalm-var array}> */ private static $installedByVendor = array(); /** * Returns a list of all package names which are present, either by being installed, replaced or provided * * @return string[] * @psalm-return list */ public static function getInstalledPackages() { $packages = array(); foreach (self::getInstalled() as $installed) { $packages[] = \array_keys($installed['versions']); } if (1 === \count($packages)) { return $packages[0]; } return \array_keys(\array_flip(\call_user_func_array('array_merge', $packages))); } /** * Returns a list of all package names with a specific type e.g. 'library' * * @param string $type * @return string[] * @psalm-return list */ public static function getInstalledPackagesByType($type) { $packagesByType = array(); foreach (self::getInstalled() as $installed) { foreach ($installed['versions'] as $name => $package) { if (isset($package['type']) && $package['type'] === $type) { $packagesByType[] = $name; } } } return $packagesByType; } /** * Checks whether the given package is installed * * This also returns true if the package name is provided or replaced by another package * * @param string $packageName * @param bool $includeDevRequirements * @return bool */ public static function isInstalled($packageName, $includeDevRequirements = \true) { foreach (self::getInstalled() as $installed) { if (isset($installed['versions'][$packageName])) { return $includeDevRequirements || !isset($installed['versions'][$packageName]['dev_requirement']) || $installed['versions'][$packageName]['dev_requirement'] === \false; } } return \false; } /** * Checks whether the given package satisfies a version constraint * * e.g. If you want to know whether version 2.3+ of package foo/bar is installed, you would call: * * Composer\InstalledVersions::satisfies(new VersionParser, 'foo/bar', '^2.3') * * @param VersionParser $parser Install composer/semver to have access to this class and functionality * @param string $packageName * @param string|null $constraint A version constraint to check for, if you pass one you have to make sure composer/semver is required by your package * @return bool */ public static function satisfies(VersionParser $parser, $packageName, $constraint) { $constraint = $parser->parseConstraints((string) $constraint); $provided = $parser->parseConstraints(self::getVersionRanges($packageName)); return $provided->matches($constraint); } /** * Returns a version constraint representing all the range(s) which are installed for a given package * * It is easier to use this via isInstalled() with the $constraint argument if you need to check * whether a given version of a package is installed, and not just whether it exists * * @param string $packageName * @return string Version constraint usable with composer/semver */ public static function getVersionRanges($packageName) { foreach (self::getInstalled() as $installed) { if (!isset($installed['versions'][$packageName])) { continue; } $ranges = array(); if (isset($installed['versions'][$packageName]['pretty_version'])) { $ranges[] = $installed['versions'][$packageName]['pretty_version']; } if (\array_key_exists('aliases', $installed['versions'][$packageName])) { $ranges = \array_merge($ranges, $installed['versions'][$packageName]['aliases']); } if (\array_key_exists('replaced', $installed['versions'][$packageName])) { $ranges = \array_merge($ranges, $installed['versions'][$packageName]['replaced']); } if (\array_key_exists('provided', $installed['versions'][$packageName])) { $ranges = \array_merge($ranges, $installed['versions'][$packageName]['provided']); } return \implode(' || ', $ranges); } throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed'); } /** * @param string $packageName * @return string|null If the package is being replaced or provided but is not really installed, null will be returned as version, use satisfies or getVersionRanges if you need to know if a given version is present */ public static function getVersion($packageName) { foreach (self::getInstalled() as $installed) { if (!isset($installed['versions'][$packageName])) { continue; } if (!isset($installed['versions'][$packageName]['version'])) { return null; } return $installed['versions'][$packageName]['version']; } throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed'); } /** * @param string $packageName * @return string|null If the package is being replaced or provided but is not really installed, null will be returned as version, use satisfies or getVersionRanges if you need to know if a given version is present */ public static function getPrettyVersion($packageName) { foreach (self::getInstalled() as $installed) { if (!isset($installed['versions'][$packageName])) { continue; } if (!isset($installed['versions'][$packageName]['pretty_version'])) { return null; } return $installed['versions'][$packageName]['pretty_version']; } throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed'); } /** * @param string $packageName * @return string|null If the package is being replaced or provided but is not really installed, null will be returned as reference */ public static function getReference($packageName) { foreach (self::getInstalled() as $installed) { if (!isset($installed['versions'][$packageName])) { continue; } if (!isset($installed['versions'][$packageName]['reference'])) { return null; } return $installed['versions'][$packageName]['reference']; } throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed'); } /** * @param string $packageName * @return string|null If the package is being replaced or provided but is not really installed, null will be returned as install path. Packages of type metapackages also have a null install path. */ public static function getInstallPath($packageName) { foreach (self::getInstalled() as $installed) { if (!isset($installed['versions'][$packageName])) { continue; } return isset($installed['versions'][$packageName]['install_path']) ? $installed['versions'][$packageName]['install_path'] : null; } throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed'); } /** * @return array * @psalm-return array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool} */ public static function getRootPackage() { $installed = self::getInstalled(); return $installed[0]['root']; } /** * Returns the raw installed.php data for custom implementations * * @deprecated Use getAllRawData() instead which returns all datasets for all autoloaders present in the process. getRawData only returns the first dataset loaded, which may not be what you expect. * @return array[] * @psalm-return array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array} */ public static function getRawData() { @\trigger_error('getRawData only returns the first dataset loaded, which may not be what you expect. Use getAllRawData() instead which returns all datasets for all autoloaders present in the process.', \E_USER_DEPRECATED); if (null === self::$installed) { // only require the installed.php file if this file is loaded from its dumped location, // and not from its source location in the composer/composer package, see https://github.com/composer/composer/issues/9937 if (\substr(__DIR__, -8, 1) !== 'C') { self::$installed = (include __DIR__ . '/installed.php'); } else { self::$installed = array(); } } return self::$installed; } /** * Returns the raw data of all installed.php which are currently loaded for custom implementations * * @return array[] * @psalm-return list}> */ public static function getAllRawData() { return self::getInstalled(); } /** * Lets you reload the static array from another file * * This is only useful for complex integrations in which a project needs to use * this class but then also needs to execute another project's autoloader in process, * and wants to ensure both projects have access to their version of installed.php. * * A typical case would be PHPUnit, where it would need to make sure it reads all * the data it needs from this class, then call reload() with * `require $CWD/vendor/composer/installed.php` (or similar) as input to make sure * the project in which it runs can then also use this class safely, without * interference between PHPUnit's dependencies and the project's dependencies. * * @param array[] $data A vendor/composer/installed.php data set * @return void * * @psalm-param array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array} $data */ public static function reload($data) { self::$installed = $data; self::$installedByVendor = array(); } /** * @return array[] * @psalm-return list}> */ private static function getInstalled() { if (null === self::$canGetVendors) { self::$canGetVendors = \method_exists('_HumbugBox7ff99e199a36\\Composer\\Autoload\\ClassLoader', 'getRegisteredLoaders'); } $installed = array(); if (self::$canGetVendors) { foreach (ClassLoader::getRegisteredLoaders() as $vendorDir => $loader) { if (isset(self::$installedByVendor[$vendorDir])) { $installed[] = self::$installedByVendor[$vendorDir]; } elseif (\is_file($vendorDir . '/composer/installed.php')) { /** @var array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array} $required */ $required = (require $vendorDir . '/composer/installed.php'); $installed[] = self::$installedByVendor[$vendorDir] = $required; if (null === self::$installed && \strtr($vendorDir . '/composer', '\\', '/') === \strtr(__DIR__, '\\', '/')) { self::$installed = $installed[\count($installed) - 1]; } } } } if (null === self::$installed) { // only require the installed.php file if this file is loaded from its dumped location, // and not from its source location in the composer/composer package, see https://github.com/composer/composer/issues/9937 if (\substr(__DIR__, -8, 1) !== 'C') { /** @var array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array} $required */ $required = (require __DIR__ . '/installed.php'); self::$installed = $required; } else { self::$installed = array(); } } if (self::$installed !== array()) { $installed[] = self::$installed; } return $installed; } } array($vendorDir . '/phpdocumentor/reflection-common/src', $vendorDir . '/phpdocumentor/reflection-docblock/src', $vendorDir . '/phpdocumentor/type-resolver/src'), '_HumbugBox7ff99e199a36\\XdgBaseDir\\' => array($vendorDir . '/dnoegel/php-xdg-base-dir/src'), '_HumbugBox7ff99e199a36\\Webmozart\\Assert\\' => array($vendorDir . '/webmozart/assert/src'), '_HumbugBox7ff99e199a36\\Symfony\\Polyfill\\Php80\\' => array($vendorDir . '/symfony/polyfill-php80'), '_HumbugBox7ff99e199a36\\Symfony\\Polyfill\\Php73\\' => array($vendorDir . '/symfony/polyfill-php73'), '_HumbugBox7ff99e199a36\\Symfony\\Polyfill\\Mbstring\\' => array($vendorDir . '/symfony/polyfill-mbstring'), '_HumbugBox7ff99e199a36\\Symfony\\Polyfill\\Intl\\Normalizer\\' => array($vendorDir . '/symfony/polyfill-intl-normalizer'), '_HumbugBox7ff99e199a36\\Symfony\\Polyfill\\Intl\\Grapheme\\' => array($vendorDir . '/symfony/polyfill-intl-grapheme'), '_HumbugBox7ff99e199a36\\Symfony\\Polyfill\\Ctype\\' => array($vendorDir . '/symfony/polyfill-ctype'), '_HumbugBox7ff99e199a36\\Symfony\\Contracts\\Service\\' => array($vendorDir . '/symfony/service-contracts'), '_HumbugBox7ff99e199a36\\Symfony\\Component\\String\\' => array($vendorDir . '/symfony/string'), '_HumbugBox7ff99e199a36\\Symfony\\Component\\Filesystem\\' => array($vendorDir . '/symfony/filesystem'), '_HumbugBox7ff99e199a36\\Symfony\\Component\\Console\\' => array($vendorDir . '/symfony/console'), '_HumbugBox7ff99e199a36\\Spatie\\ArrayToXml\\' => array($vendorDir . '/spatie/array-to-xml/src'), '_HumbugBox7ff99e199a36\\Psr\\Log\\' => array($vendorDir . '/psr/log/Psr/Log'), '_HumbugBox7ff99e199a36\\Psr\\Container\\' => array($vendorDir . '/psr/container/src'), '_HumbugBox7ff99e199a36\\PhpParser\\' => array($vendorDir . '/nikic/php-parser/lib/PhpParser'), '_HumbugBox7ff99e199a36\\PHPStan\\PhpDocParser\\' => array($vendorDir . '/phpstan/phpdoc-parser/src'), '_HumbugBox7ff99e199a36\\LanguageServerProtocol\\' => array($vendorDir . '/felixfbecker/language-server-protocol/src'), '_HumbugBox7ff99e199a36\\JsonMapper\\' => array($vendorDir . '/netresearch/jsonmapper/src/JsonMapper'), '_HumbugBox7ff99e199a36\\Fidry\\CpuCoreCounter\\' => array($vendorDir . '/fidry/cpu-core-counter/src'), '_HumbugBox7ff99e199a36\\Doctrine\\Deprecations\\' => array($vendorDir . '/doctrine/deprecations/lib/Doctrine/Deprecations'), '_HumbugBox7ff99e199a36\\Composer\\XdebugHandler\\' => array($vendorDir . '/composer/xdebug-handler/src'), '_HumbugBox7ff99e199a36\\Composer\\Semver\\' => array($vendorDir . '/composer/semver/src'), '_HumbugBox7ff99e199a36\\Composer\\Pcre\\' => array($vendorDir . '/composer/pcre/src'), '_HumbugBox7ff99e199a36\\Amp\\ByteStream\\' => array($vendorDir . '/amphp/byte-stream/lib'), '_HumbugBox7ff99e199a36\\Amp\\' => array($vendorDir . '/amphp/amp/lib'), '_HumbugBox7ff99e199a36\\AdvancedJsonRpc\\' => array($vendorDir . '/felixfbecker/advanced-json-rpc/lib'), 'Psalm\\' => array($baseDir . '/src/Psalm'), ); Copyright (C) 2021 Composer Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * * For the full copyright and license information, please view * the LICENSE file that was distributed with this source code. */ namespace _HumbugBox7ff99e199a36\Composer\Pcre; final class MatchAllWithOffsetsResult { /** * An array of match group => list of matches, every match being a pair of string matched + offset in bytes (or -1 if no match) * * @readonly * @var array> * @phpstan-var array}>> */ public $matches; /** * @readonly * @var 0|positive-int */ public $count; /** * @readonly * @var bool */ public $matched; /** * @param 0|positive-int $count * @param array> $matches * @phpstan-param array}>> $matches */ public function __construct(int $count, array $matches) { $this->matches = $matches; $this->matched = (bool) $count; $this->count = $count; } } * * For the full copyright and license information, please view * the LICENSE file that was distributed with this source code. */ namespace _HumbugBox7ff99e199a36\Composer\Pcre; final class MatchWithOffsetsResult { /** * An array of match group => pair of string matched + offset in bytes (or -1 if no match) * * @readonly * @var array * @phpstan-var array}> */ public $matches; /** * @readonly * @var bool */ public $matched; /** * @param 0|positive-int $count * @param array $matches * @phpstan-param array}> $matches */ public function __construct(int $count, array $matches) { $this->matches = $matches; $this->matched = (bool) $count; } } * * For the full copyright and license information, please view * the LICENSE file that was distributed with this source code. */ namespace _HumbugBox7ff99e199a36\Composer\Pcre; class PcreException extends \RuntimeException { /** * @param string $function * @param string|string[] $pattern * @return self */ public static function fromFunction($function, $pattern) { $code = \preg_last_error(); if (\is_array($pattern)) { $pattern = \implode(', ', $pattern); } return new PcreException($function . '(): failed executing "' . $pattern . '": ' . self::pcreLastErrorMessage($code), $code); } /** * @param int $code * @return string */ private static function pcreLastErrorMessage($code) { if (\function_exists('preg_last_error_msg')) { return \preg_last_error_msg(); } // older php versions did not set the code properly in all cases if (\PHP_VERSION_ID < 70201 && $code === 0) { return 'UNDEFINED_ERROR'; } $constants = \get_defined_constants(\true); if (!isset($constants['pcre'])) { return 'UNDEFINED_ERROR'; } foreach ($constants['pcre'] as $const => $val) { if ($val === $code && \substr($const, -6) === '_ERROR') { return $const; } } return 'UNDEFINED_ERROR'; } } * * For the full copyright and license information, please view * the LICENSE file that was distributed with this source code. */ namespace _HumbugBox7ff99e199a36\Composer\Pcre; class Preg { /** @internal */ public const ARRAY_MSG = '$subject as an array is not supported. You can use \'foreach\' instead.'; /** @internal */ public const INVALID_TYPE_MSG = '$subject must be a string, %s given.'; /** * @param non-empty-string $pattern * @param array $matches Set by method * @param int-mask $flags PREG_UNMATCHED_AS_NULL is always set, no other flags are supported * @return 0|1 * * @param-out array $matches */ public static function match(string $pattern, string $subject, ?array &$matches = null, int $flags = 0, int $offset = 0) : int { self::checkOffsetCapture($flags, 'matchWithOffsets'); $result = \preg_match($pattern, $subject, $matches, $flags | \PREG_UNMATCHED_AS_NULL, $offset); if ($result === \false) { throw PcreException::fromFunction('preg_match', $pattern); } return $result; } /** * Variant of `match()` which outputs non-null matches (or throws) * * @param non-empty-string $pattern * @param array $matches Set by method * @param int-mask $flags PREG_UNMATCHED_AS_NULL is always set, no other flags are supported * @return 0|1 * @throws UnexpectedNullMatchException * * @param-out array $matches */ public static function matchStrictGroups(string $pattern, string $subject, ?array &$matches = null, int $flags = 0, int $offset = 0) : int { $result = self::match($pattern, $subject, $matchesInternal, $flags, $offset); $matches = self::enforceNonNullMatches($pattern, $matchesInternal, 'match'); return $result; } /** * Runs preg_match with PREG_OFFSET_CAPTURE * * @param non-empty-string $pattern * @param array $matches Set by method * @param int-mask $flags PREG_UNMATCHED_AS_NULL and PREG_OFFSET_CAPTURE are always set, no other flags are supported * @return 0|1 * * @param-out array}> $matches */ public static function matchWithOffsets(string $pattern, string $subject, ?array &$matches, int $flags = 0, int $offset = 0) : int { $result = \preg_match($pattern, $subject, $matches, $flags | \PREG_UNMATCHED_AS_NULL | \PREG_OFFSET_CAPTURE, $offset); if ($result === \false) { throw PcreException::fromFunction('preg_match', $pattern); } return $result; } /** * @param non-empty-string $pattern * @param array $matches Set by method * @param int-mask $flags PREG_UNMATCHED_AS_NULL is always set, no other flags are supported * @return 0|positive-int * * @param-out array> $matches */ public static function matchAll(string $pattern, string $subject, ?array &$matches = null, int $flags = 0, int $offset = 0) : int { self::checkOffsetCapture($flags, 'matchAllWithOffsets'); self::checkSetOrder($flags); $result = \preg_match_all($pattern, $subject, $matches, $flags | \PREG_UNMATCHED_AS_NULL, $offset); if (!\is_int($result)) { // PHP < 8 may return null, 8+ returns int|false throw PcreException::fromFunction('preg_match_all', $pattern); } return $result; } /** * Variant of `match()` which outputs non-null matches (or throws) * * @param non-empty-string $pattern * @param array $matches Set by method * @param int-mask $flags PREG_UNMATCHED_AS_NULL is always set, no other flags are supported * @return 0|positive-int * @throws UnexpectedNullMatchException * * @param-out array> $matches */ public static function matchAllStrictGroups(string $pattern, string $subject, ?array &$matches = null, int $flags = 0, int $offset = 0) : int { $result = self::matchAll($pattern, $subject, $matchesInternal, $flags, $offset); $matches = self::enforceNonNullMatchAll($pattern, $matchesInternal, 'matchAll'); return $result; } /** * Runs preg_match_all with PREG_OFFSET_CAPTURE * * @param non-empty-string $pattern * @param array $matches Set by method * @param int-mask $flags PREG_UNMATCHED_AS_NULL and PREG_MATCH_OFFSET are always set, no other flags are supported * @return 0|positive-int * * @param-out array}>> $matches */ public static function matchAllWithOffsets(string $pattern, string $subject, ?array &$matches, int $flags = 0, int $offset = 0) : int { self::checkSetOrder($flags); $result = \preg_match_all($pattern, $subject, $matches, $flags | \PREG_UNMATCHED_AS_NULL | \PREG_OFFSET_CAPTURE, $offset); if (!\is_int($result)) { // PHP < 8 may return null, 8+ returns int|false throw PcreException::fromFunction('preg_match_all', $pattern); } return $result; } /** * @param string|string[] $pattern * @param string|string[] $replacement * @param string $subject * @param int $count Set by method * * @param-out int<0, max> $count */ public static function replace($pattern, $replacement, $subject, int $limit = -1, ?int &$count = null) : string { if (!\is_scalar($subject)) { if (\is_array($subject)) { throw new \InvalidArgumentException(static::ARRAY_MSG); } throw new \TypeError(\sprintf(static::INVALID_TYPE_MSG, \gettype($subject))); } $result = \preg_replace($pattern, $replacement, $subject, $limit, $count); if ($result === null) { throw PcreException::fromFunction('preg_replace', $pattern); } return $result; } /** * @param string|string[] $pattern * @param ($flags is PREG_OFFSET_CAPTURE ? (callable(array}>): string) : callable(array): string) $replacement * @param string $subject * @param int $count Set by method * @param int-mask $flags PREG_OFFSET_CAPTURE is supported, PREG_UNMATCHED_AS_NULL is always set * * @param-out int<0, max> $count */ public static function replaceCallback($pattern, callable $replacement, $subject, int $limit = -1, ?int &$count = null, int $flags = 0) : string { if (!\is_scalar($subject)) { if (\is_array($subject)) { throw new \InvalidArgumentException(static::ARRAY_MSG); } throw new \TypeError(\sprintf(static::INVALID_TYPE_MSG, \gettype($subject))); } $result = \preg_replace_callback($pattern, $replacement, $subject, $limit, $count, $flags | \PREG_UNMATCHED_AS_NULL); if ($result === null) { throw PcreException::fromFunction('preg_replace_callback', $pattern); } return $result; } /** * Variant of `replaceCallback()` which outputs non-null matches (or throws) * * @param string $pattern * @param ($flags is PREG_OFFSET_CAPTURE ? (callable(array}>): string) : callable(array): string) $replacement * @param string $subject * @param int $count Set by method * @param int-mask $flags PREG_OFFSET_CAPTURE is supported, PREG_UNMATCHED_AS_NULL is always set * * @param-out int<0, max> $count */ public static function replaceCallbackStrictGroups(string $pattern, callable $replacement, $subject, int $limit = -1, ?int &$count = null, int $flags = 0) : string { return self::replaceCallback($pattern, function (array $matches) use($pattern, $replacement) { return $replacement(self::enforceNonNullMatches($pattern, $matches, 'replaceCallback')); }, $subject, $limit, $count, $flags); } /** * @param ($flags is PREG_OFFSET_CAPTURE ? (array}>): string>) : array): string>) $pattern * @param string $subject * @param int $count Set by method * @param int-mask $flags PREG_OFFSET_CAPTURE is supported, PREG_UNMATCHED_AS_NULL is always set * * @param-out int<0, max> $count */ public static function replaceCallbackArray(array $pattern, $subject, int $limit = -1, ?int &$count = null, int $flags = 0) : string { if (!\is_scalar($subject)) { if (\is_array($subject)) { throw new \InvalidArgumentException(static::ARRAY_MSG); } throw new \TypeError(\sprintf(static::INVALID_TYPE_MSG, \gettype($subject))); } $result = \preg_replace_callback_array($pattern, $subject, $limit, $count, $flags | \PREG_UNMATCHED_AS_NULL); if ($result === null) { $pattern = \array_keys($pattern); throw PcreException::fromFunction('preg_replace_callback_array', $pattern); } return $result; } /** * @param int-mask $flags PREG_SPLIT_NO_EMPTY or PREG_SPLIT_DELIM_CAPTURE * @return list */ public static function split(string $pattern, string $subject, int $limit = -1, int $flags = 0) : array { if (($flags & \PREG_SPLIT_OFFSET_CAPTURE) !== 0) { throw new \InvalidArgumentException('PREG_SPLIT_OFFSET_CAPTURE is not supported as it changes the type of $matches, use splitWithOffsets() instead'); } $result = \preg_split($pattern, $subject, $limit, $flags); if ($result === \false) { throw PcreException::fromFunction('preg_split', $pattern); } return $result; } /** * @param int-mask $flags PREG_SPLIT_NO_EMPTY or PREG_SPLIT_DELIM_CAPTURE, PREG_SPLIT_OFFSET_CAPTURE is always set * @return list * @phpstan-return list}> */ public static function splitWithOffsets(string $pattern, string $subject, int $limit = -1, int $flags = 0) : array { $result = \preg_split($pattern, $subject, $limit, $flags | \PREG_SPLIT_OFFSET_CAPTURE); if ($result === \false) { throw PcreException::fromFunction('preg_split', $pattern); } return $result; } /** * @template T of string|\Stringable * @param string $pattern * @param array $array * @param int-mask $flags PREG_GREP_INVERT * @return array */ public static function grep(string $pattern, array $array, int $flags = 0) : array { $result = \preg_grep($pattern, $array, $flags); if ($result === \false) { throw PcreException::fromFunction('preg_grep', $pattern); } return $result; } /** * Variant of match() which returns a bool instead of int * * @param non-empty-string $pattern * @param array $matches Set by method * @param int-mask $flags PREG_UNMATCHED_AS_NULL is always set, no other flags are supported * * @param-out array $matches */ public static function isMatch(string $pattern, string $subject, ?array &$matches = null, int $flags = 0, int $offset = 0) : bool { return (bool) static::match($pattern, $subject, $matches, $flags, $offset); } /** * Variant of `isMatch()` which outputs non-null matches (or throws) * * @param non-empty-string $pattern * @param array $matches Set by method * @param int-mask $flags PREG_UNMATCHED_AS_NULL is always set, no other flags are supported * @throws UnexpectedNullMatchException * * @param-out array $matches */ public static function isMatchStrictGroups(string $pattern, string $subject, ?array &$matches = null, int $flags = 0, int $offset = 0) : bool { return (bool) self::matchStrictGroups($pattern, $subject, $matches, $flags, $offset); } /** * Variant of matchAll() which returns a bool instead of int * * @param non-empty-string $pattern * @param array $matches Set by method * @param int-mask $flags PREG_UNMATCHED_AS_NULL is always set, no other flags are supported * * @param-out array> $matches */ public static function isMatchAll(string $pattern, string $subject, ?array &$matches = null, int $flags = 0, int $offset = 0) : bool { return (bool) static::matchAll($pattern, $subject, $matches, $flags, $offset); } /** * Variant of `isMatchAll()` which outputs non-null matches (or throws) * * @param non-empty-string $pattern * @param array $matches Set by method * @param int-mask $flags PREG_UNMATCHED_AS_NULL is always set, no other flags are supported * * @param-out array> $matches */ public static function isMatchAllStrictGroups(string $pattern, string $subject, ?array &$matches = null, int $flags = 0, int $offset = 0) : bool { return (bool) self::matchAllStrictGroups($pattern, $subject, $matches, $flags, $offset); } /** * Variant of matchWithOffsets() which returns a bool instead of int * * Runs preg_match with PREG_OFFSET_CAPTURE * * @param non-empty-string $pattern * @param array $matches Set by method * @param int-mask $flags PREG_UNMATCHED_AS_NULL is always set, no other flags are supported * * @param-out array}> $matches */ public static function isMatchWithOffsets(string $pattern, string $subject, ?array &$matches, int $flags = 0, int $offset = 0) : bool { return (bool) static::matchWithOffsets($pattern, $subject, $matches, $flags, $offset); } /** * Variant of matchAllWithOffsets() which returns a bool instead of int * * Runs preg_match_all with PREG_OFFSET_CAPTURE * * @param non-empty-string $pattern * @param array $matches Set by method * @param int-mask $flags PREG_UNMATCHED_AS_NULL is always set, no other flags are supported * * @param-out array}>> $matches */ public static function isMatchAllWithOffsets(string $pattern, string $subject, ?array &$matches, int $flags = 0, int $offset = 0) : bool { return (bool) static::matchAllWithOffsets($pattern, $subject, $matches, $flags, $offset); } private static function checkOffsetCapture(int $flags, string $useFunctionName) : void { if (($flags & \PREG_OFFSET_CAPTURE) !== 0) { throw new \InvalidArgumentException('PREG_OFFSET_CAPTURE is not supported as it changes the type of $matches, use ' . $useFunctionName . '() instead'); } } private static function checkSetOrder(int $flags) : void { if (($flags & \PREG_SET_ORDER) !== 0) { throw new \InvalidArgumentException('PREG_SET_ORDER is not supported as it changes the type of $matches'); } } /** * @param array $matches * @return array * @throws UnexpectedNullMatchException */ private static function enforceNonNullMatches(string $pattern, array $matches, string $variantMethod) { foreach ($matches as $group => $match) { if (\is_string($match) || \is_array($match) && \is_string($match[0])) { continue; } throw new UnexpectedNullMatchException('Pattern "' . $pattern . '" had an unexpected unmatched group "' . $group . '", make sure the pattern always matches or use ' . $variantMethod . '() instead.'); } /** @var array */ return $matches; } /** * @param array> $matches * @return array> * @throws UnexpectedNullMatchException */ private static function enforceNonNullMatchAll(string $pattern, array $matches, string $variantMethod) { foreach ($matches as $group => $groupMatches) { foreach ($groupMatches as $match) { if (null === $match) { throw new UnexpectedNullMatchException('Pattern "' . $pattern . '" had an unexpected unmatched group "' . $group . '", make sure the pattern always matches or use ' . $variantMethod . '() instead.'); } } } /** @var array> */ return $matches; } } * * For the full copyright and license information, please view * the LICENSE file that was distributed with this source code. */ namespace _HumbugBox7ff99e199a36\Composer\Pcre; class UnexpectedNullMatchException extends PcreException { public static function fromFunction($function, $pattern) { throw new \LogicException('fromFunction should not be called on ' . self::class . ', use ' . PcreException::class); } } * * For the full copyright and license information, please view * the LICENSE file that was distributed with this source code. */ namespace _HumbugBox7ff99e199a36\Composer\Pcre; final class MatchAllResult { /** * An array of match group => list of matched strings * * @readonly * @var array> */ public $matches; /** * @readonly * @var 0|positive-int */ public $count; /** * @readonly * @var bool */ public $matched; /** * @param 0|positive-int $count * @param array> $matches */ public function __construct(int $count, array $matches) { $this->matches = $matches; $this->matched = (bool) $count; $this->count = $count; } } * * For the full copyright and license information, please view * the LICENSE file that was distributed with this source code. */ namespace _HumbugBox7ff99e199a36\Composer\Pcre; final class MatchAllStrictGroupsResult { /** * An array of match group => list of matched strings * * @readonly * @var array> */ public $matches; /** * @readonly * @var 0|positive-int */ public $count; /** * @readonly * @var bool */ public $matched; /** * @param 0|positive-int $count * @param array> $matches */ public function __construct(int $count, array $matches) { $this->matches = $matches; $this->matched = (bool) $count; $this->count = $count; } } * * For the full copyright and license information, please view * the LICENSE file that was distributed with this source code. */ namespace _HumbugBox7ff99e199a36\Composer\Pcre; final class MatchResult { /** * An array of match group => string matched * * @readonly * @var array */ public $matches; /** * @readonly * @var bool */ public $matched; /** * @param 0|positive-int $count * @param array $matches */ public function __construct(int $count, array $matches) { $this->matches = $matches; $this->matched = (bool) $count; } } */ class InvalidRegexPatternRule implements Rule { public function getNodeType() : string { return StaticCall::class; } public function processNode(Node $node, Scope $scope) : array { $patterns = $this->extractPatterns($node, $scope); $errors = []; foreach ($patterns as $pattern) { $errorMessage = $this->validatePattern($pattern); if ($errorMessage === null) { continue; } $errors[] = RuleErrorBuilder::message(sprintf('Regex pattern is invalid: %s', $errorMessage))->identifier('regexp.pattern')->build(); } return $errors; } /** * @return string[] */ private function extractPatterns(StaticCall $node, Scope $scope) : array { if (!$node->class instanceof FullyQualified) { return []; } $isRegex = $node->class->toString() === Regex::class; $isPreg = $node->class->toString() === Preg::class; if (!$isRegex && !$isPreg) { return []; } if (!$node->name instanceof Node\Identifier || !Preg::isMatch('{^(match|isMatch|grep|replace|split)}', $node->name->name)) { return []; } $functionName = $node->name->name; if (!isset($node->getArgs()[0])) { return []; } $patternNode = $node->getArgs()[0]->value; $patternType = $scope->getType($patternNode); $patternStrings = []; foreach ($patternType->getConstantStrings() as $constantStringType) { if ($functionName === 'replaceCallbackArray') { continue; } $patternStrings[] = $constantStringType->getValue(); } foreach ($patternType->getConstantArrays() as $constantArrayType) { if (in_array($functionName, ['replace', 'replaceCallback'], \true)) { foreach ($constantArrayType->getValueTypes() as $arrayKeyType) { foreach ($arrayKeyType->getConstantStrings() as $constantString) { $patternStrings[] = $constantString->getValue(); } } } if ($functionName !== 'replaceCallbackArray') { continue; } foreach ($constantArrayType->getKeyTypes() as $arrayKeyType) { foreach ($arrayKeyType->getConstantStrings() as $constantString) { $patternStrings[] = $constantString->getValue(); } } } return $patternStrings; } private function validatePattern(string $pattern) : ?string { try { $msg = null; $prev = \set_error_handler(function (int $severity, string $message, string $file) use(&$msg) : bool { $msg = \preg_replace("#^preg_match(_all)?\\(.*?\\): #", '', $message); return \true; }); if ($pattern === '') { return 'Empty string is not a valid regular expression'; } Preg::match($pattern, ''); if ($msg !== null) { return $msg; } } catch (PcreException $e) { if ($e->getCode() === \PREG_INTERNAL_ERROR && $msg !== null) { return $msg; } return \preg_replace('{.*? failed executing ".*": }', '', $e->getMessage()); } finally { \restore_error_handler(); } return null; } } getType($flagsArg->value); $constantScalars = $flagsType->getConstantScalarValues(); if ($constantScalars === []) { return null; } $internalFlagsTypes = []; foreach ($flagsType->getConstantScalarValues() as $constantScalarValue) { if (!\is_int($constantScalarValue)) { return null; } $internalFlagsTypes[] = new ConstantIntegerType($constantScalarValue | \PREG_UNMATCHED_AS_NULL); } return TypeCombinator::union(...$internalFlagsTypes); } public static function removeNullFromMatches(Type $matchesType) : Type { return TypeTraverser::map($matchesType, static function (Type $type, callable $traverse) : Type { if ($type instanceof UnionType || $type instanceof IntersectionType) { return $traverse($type); } if ($type instanceof ConstantArrayType) { return new ConstantArrayType($type->getKeyTypes(), \array_map(static function (Type $valueType) use($traverse) : Type { return $traverse($valueType); }, $type->getValueTypes()), $type->getNextAutoIndexes(), [], $type->isList()); } if ($type instanceof ArrayType) { return new ArrayType($type->getKeyType(), $traverse($type->getItemType())); } return TypeCombinator::removeNull($type); }); } } regexShapeMatcher = $regexShapeMatcher; } public function isStaticMethodSupported(MethodReflection $methodReflection, ParameterReflection $parameter) : bool { return \in_array($methodReflection->getDeclaringClass()->getName(), [Preg::class, Regex::class], \true) && \in_array($methodReflection->getName(), ['replaceCallback', 'replaceCallbackStrictGroups'], \true) && $parameter->getName() === 'replacement'; } public function getTypeFromStaticMethodCall(MethodReflection $methodReflection, StaticCall $methodCall, ParameterReflection $parameter, Scope $scope) : ?Type { $args = $methodCall->getArgs(); $patternArg = $args[0] ?? null; $flagsArg = $args[5] ?? null; if ($patternArg === null) { return null; } $flagsType = PregMatchFlags::getType($flagsArg, $scope); $matchesType = $this->regexShapeMatcher->matchExpr($patternArg->value, $flagsType, TrinaryLogic::createYes(), $scope); if ($matchesType === null) { return null; } if ($methodReflection->getName() === 'replaceCallbackStrictGroups' && \count($matchesType->getConstantArrays()) === 1) { $matchesType = $matchesType->getConstantArrays()[0]; $matchesType = new ConstantArrayType($matchesType->getKeyTypes(), \array_map(static function (Type $valueType) : Type { if (\count($valueType->getConstantArrays()) === 1) { $valueTypeArray = $valueType->getConstantArrays()[0]; return new ConstantArrayType($valueTypeArray->getKeyTypes(), \array_map(static function (Type $valueType) : Type { return TypeCombinator::removeNull($valueType); }, $valueTypeArray->getValueTypes()), $valueTypeArray->getNextAutoIndexes(), [], $valueTypeArray->isList()); } return TypeCombinator::removeNull($valueType); }, $matchesType->getValueTypes()), $matchesType->getNextAutoIndexes(), [], $matchesType->isList()); } return new ClosureType([new NativeParameterReflection($parameter->getName(), $parameter->isOptional(), $matchesType, $parameter->passedByReference(), $parameter->isVariadic(), $parameter->getDefaultValue())], new StringType()); } } */ final class UnsafeStrictGroupsCallRule implements Rule { /** * @var RegexArrayShapeMatcher */ private $regexShapeMatcher; public function __construct(RegexArrayShapeMatcher $regexShapeMatcher) { $this->regexShapeMatcher = $regexShapeMatcher; } public function getNodeType() : string { return StaticCall::class; } public function processNode(Node $node, Scope $scope) : array { if (!$node->class instanceof FullyQualified) { return []; } $isRegex = $node->class->toString() === Regex::class; $isPreg = $node->class->toString() === Preg::class; if (!$isRegex && !$isPreg) { return []; } if (!$node->name instanceof Node\Identifier || !\in_array($node->name->name, ['matchStrictGroups', 'isMatchStrictGroups', 'matchAllStrictGroups', 'isMatchAllStrictGroups'], \true)) { return []; } $args = $node->getArgs(); if (!isset($args[0])) { return []; } $patternArg = $args[0] ?? null; if ($isPreg) { if (!isset($args[2])) { // no matches set, skip as the matches won't be used anyway return []; } $flagsArg = $args[3] ?? null; } else { $flagsArg = $args[2] ?? null; } if ($patternArg === null) { return []; } $flagsType = PregMatchFlags::getType($flagsArg, $scope); if ($flagsType === null) { return []; } $matchedType = $this->regexShapeMatcher->matchExpr($patternArg->value, $flagsType, TrinaryLogic::createYes(), $scope); if ($matchedType === null) { return [RuleErrorBuilder::message(sprintf('The %s call is potentially unsafe as $matches\' type could not be inferred.', $node->name->name))->identifier('composerPcre.maybeUnsafeStrictGroups')->build()]; } if (\count($matchedType->getConstantArrays()) === 1) { $matchedType = $matchedType->getConstantArrays()[0]; $nullableGroups = []; foreach ($matchedType->getValueTypes() as $index => $type) { if (TypeCombinator::containsNull($type)) { $nullableGroups[] = $matchedType->getKeyTypes()[$index]->getValue(); } } if (\count($nullableGroups) > 0) { return [RuleErrorBuilder::message(sprintf('The %s call is unsafe as match group%s "%s" %s optional and may be null.', $node->name->name, \count($nullableGroups) > 1 ? 's' : '', \implode('", "', $nullableGroups), \count($nullableGroups) > 1 ? 'are' : 'is'))->identifier('composerPcre.unsafeStrictGroups')->build()]; } } return []; } } regexShapeMatcher = $regexShapeMatcher; } public function isStaticMethodSupported(MethodReflection $methodReflection, ParameterReflection $parameter) : bool { return $methodReflection->getDeclaringClass()->getName() === Preg::class && \in_array($methodReflection->getName(), ['match', 'isMatch', 'matchStrictGroups', 'isMatchStrictGroups', 'matchAll', 'isMatchAll', 'matchAllStrictGroups', 'isMatchAllStrictGroups'], \true) && $parameter->getName() === 'matches'; } public function getParameterOutTypeFromStaticMethodCall(MethodReflection $methodReflection, StaticCall $methodCall, ParameterReflection $parameter, Scope $scope) : ?Type { $args = $methodCall->getArgs(); $patternArg = $args[0] ?? null; $matchesArg = $args[2] ?? null; $flagsArg = $args[3] ?? null; if ($patternArg === null || $matchesArg === null) { return null; } $flagsType = PregMatchFlags::getType($flagsArg, $scope); if ($flagsType === null) { return null; } if (\stripos($methodReflection->getName(), 'matchAll') !== \false) { return $this->regexShapeMatcher->matchAllExpr($patternArg->value, $flagsType, TrinaryLogic::createMaybe(), $scope); } return $this->regexShapeMatcher->matchExpr($patternArg->value, $flagsType, TrinaryLogic::createMaybe(), $scope); } } regexShapeMatcher = $regexShapeMatcher; } public function setTypeSpecifier(TypeSpecifier $typeSpecifier) : void { $this->typeSpecifier = $typeSpecifier; } public function getClass() : string { return Preg::class; } public function isStaticMethodSupported(MethodReflection $methodReflection, StaticCall $node, TypeSpecifierContext $context) : bool { return \in_array($methodReflection->getName(), ['match', 'isMatch', 'matchStrictGroups', 'isMatchStrictGroups', 'matchAll', 'isMatchAll', 'matchAllStrictGroups', 'isMatchAllStrictGroups'], \true) && !$context->null(); } public function specifyTypes(MethodReflection $methodReflection, StaticCall $node, Scope $scope, TypeSpecifierContext $context) : SpecifiedTypes { $args = $node->getArgs(); $patternArg = $args[0] ?? null; $matchesArg = $args[2] ?? null; $flagsArg = $args[3] ?? null; if ($patternArg === null || $matchesArg === null) { return new SpecifiedTypes(); } $flagsType = PregMatchFlags::getType($flagsArg, $scope); if ($flagsType === null) { return new SpecifiedTypes(); } if (\stripos($methodReflection->getName(), 'matchAll') !== \false) { $matchedType = $this->regexShapeMatcher->matchAllExpr($patternArg->value, $flagsType, TrinaryLogic::createFromBoolean($context->true()), $scope); } else { $matchedType = $this->regexShapeMatcher->matchExpr($patternArg->value, $flagsType, TrinaryLogic::createFromBoolean($context->true()), $scope); } if ($matchedType === null) { return new SpecifiedTypes(); } if (\in_array($methodReflection->getName(), ['matchStrictGroups', 'isMatchStrictGroups', 'matchAllStrictGroups', 'isMatchAllStrictGroups'], \true)) { $matchedType = PregMatchFlags::removeNullFromMatches($matchedType); } $overwrite = \false; if ($context->false()) { $overwrite = \true; $context = $context->negate(); } return $this->typeSpecifier->create($matchesArg->value, $matchedType, $context, $overwrite, $scope, $node); } } * * For the full copyright and license information, please view * the LICENSE file that was distributed with this source code. */ namespace _HumbugBox7ff99e199a36\Composer\Pcre; class Regex { /** * @param non-empty-string $pattern */ public static function isMatch(string $pattern, string $subject, int $offset = 0) : bool { return (bool) Preg::match($pattern, $subject, $matches, 0, $offset); } /** * @param non-empty-string $pattern * @param int-mask $flags PREG_UNMATCHED_AS_NULL is always set, no other flags are supported */ public static function match(string $pattern, string $subject, int $flags = 0, int $offset = 0) : MatchResult { self::checkOffsetCapture($flags, 'matchWithOffsets'); $count = Preg::match($pattern, $subject, $matches, $flags, $offset); return new MatchResult($count, $matches); } /** * Variant of `match()` which returns non-null matches (or throws) * * @param non-empty-string $pattern * @param int-mask $flags PREG_UNMATCHED_AS_NULL is always set, no other flags are supported * @throws UnexpectedNullMatchException */ public static function matchStrictGroups(string $pattern, string $subject, int $flags = 0, int $offset = 0) : MatchStrictGroupsResult { // @phpstan-ignore composerPcre.maybeUnsafeStrictGroups $count = Preg::matchStrictGroups($pattern, $subject, $matches, $flags, $offset); return new MatchStrictGroupsResult($count, $matches); } /** * Runs preg_match with PREG_OFFSET_CAPTURE * * @param non-empty-string $pattern * @param int-mask $flags PREG_UNMATCHED_AS_NULL and PREG_MATCH_OFFSET are always set, no other flags are supported */ public static function matchWithOffsets(string $pattern, string $subject, int $flags = 0, int $offset = 0) : MatchWithOffsetsResult { $count = Preg::matchWithOffsets($pattern, $subject, $matches, $flags, $offset); return new MatchWithOffsetsResult($count, $matches); } /** * @param non-empty-string $pattern * @param int-mask $flags PREG_UNMATCHED_AS_NULL is always set, no other flags are supported */ public static function matchAll(string $pattern, string $subject, int $flags = 0, int $offset = 0) : MatchAllResult { self::checkOffsetCapture($flags, 'matchAllWithOffsets'); self::checkSetOrder($flags); $count = Preg::matchAll($pattern, $subject, $matches, $flags, $offset); return new MatchAllResult($count, $matches); } /** * Variant of `matchAll()` which returns non-null matches (or throws) * * @param non-empty-string $pattern * @param int-mask $flags PREG_UNMATCHED_AS_NULL is always set, no other flags are supported * @throws UnexpectedNullMatchException */ public static function matchAllStrictGroups(string $pattern, string $subject, int $flags = 0, int $offset = 0) : MatchAllStrictGroupsResult { self::checkOffsetCapture($flags, 'matchAllWithOffsets'); self::checkSetOrder($flags); // @phpstan-ignore composerPcre.maybeUnsafeStrictGroups $count = Preg::matchAllStrictGroups($pattern, $subject, $matches, $flags, $offset); return new MatchAllStrictGroupsResult($count, $matches); } /** * Runs preg_match_all with PREG_OFFSET_CAPTURE * * @param non-empty-string $pattern * @param int-mask $flags PREG_UNMATCHED_AS_NULL and PREG_MATCH_OFFSET are always set, no other flags are supported */ public static function matchAllWithOffsets(string $pattern, string $subject, int $flags = 0, int $offset = 0) : MatchAllWithOffsetsResult { self::checkSetOrder($flags); $count = Preg::matchAllWithOffsets($pattern, $subject, $matches, $flags, $offset); return new MatchAllWithOffsetsResult($count, $matches); } /** * @param string|string[] $pattern * @param string|string[] $replacement * @param string $subject */ public static function replace($pattern, $replacement, $subject, int $limit = -1) : ReplaceResult { $result = Preg::replace($pattern, $replacement, $subject, $limit, $count); return new ReplaceResult($count, $result); } /** * @param string|string[] $pattern * @param ($flags is PREG_OFFSET_CAPTURE ? (callable(array}>): string) : callable(array): string) $replacement * @param string $subject * @param int-mask $flags PREG_OFFSET_CAPTURE is supported, PREG_UNMATCHED_AS_NULL is always set */ public static function replaceCallback($pattern, callable $replacement, $subject, int $limit = -1, int $flags = 0) : ReplaceResult { $result = Preg::replaceCallback($pattern, $replacement, $subject, $limit, $count, $flags); return new ReplaceResult($count, $result); } /** * Variant of `replaceCallback()` which outputs non-null matches (or throws) * * @param string $pattern * @param ($flags is PREG_OFFSET_CAPTURE ? (callable(array}>): string) : callable(array): string) $replacement * @param string $subject * @param int-mask $flags PREG_OFFSET_CAPTURE is supported, PREG_UNMATCHED_AS_NULL is always set */ public static function replaceCallbackStrictGroups($pattern, callable $replacement, $subject, int $limit = -1, int $flags = 0) : ReplaceResult { $result = Preg::replaceCallbackStrictGroups($pattern, $replacement, $subject, $limit, $count, $flags); return new ReplaceResult($count, $result); } /** * @param ($flags is PREG_OFFSET_CAPTURE ? (array}>): string>) : array): string>) $pattern * @param string $subject * @param int-mask $flags PREG_OFFSET_CAPTURE is supported, PREG_UNMATCHED_AS_NULL is always set */ public static function replaceCallbackArray(array $pattern, $subject, int $limit = -1, int $flags = 0) : ReplaceResult { $result = Preg::replaceCallbackArray($pattern, $subject, $limit, $count, $flags); return new ReplaceResult($count, $result); } private static function checkOffsetCapture(int $flags, string $useFunctionName) : void { if (($flags & \PREG_OFFSET_CAPTURE) !== 0) { throw new \InvalidArgumentException('PREG_OFFSET_CAPTURE is not supported as it changes the return type, use ' . $useFunctionName . '() instead'); } } private static function checkSetOrder(int $flags) : void { if (($flags & \PREG_SET_ORDER) !== 0) { throw new \InvalidArgumentException('PREG_SET_ORDER is not supported as it changes the return type'); } } } * * For the full copyright and license information, please view * the LICENSE file that was distributed with this source code. */ namespace _HumbugBox7ff99e199a36\Composer\Pcre; final class ReplaceResult { /** * @readonly * @var string */ public $result; /** * @readonly * @var 0|positive-int */ public $count; /** * @readonly * @var bool */ public $matched; /** * @param 0|positive-int $count */ public function __construct(int $count, string $result) { $this->count = $count; $this->matched = (bool) $count; $this->result = $result; } } * * For the full copyright and license information, please view * the LICENSE file that was distributed with this source code. */ namespace _HumbugBox7ff99e199a36\Composer\Pcre; final class MatchStrictGroupsResult { /** * An array of match group => string matched * * @readonly * @var array */ public $matches; /** * @readonly * @var bool */ public $matched; /** * @param 0|positive-int $count * @param array $matches */ public function __construct(int $count, array $matches) { $this->matches = $matches; $this->matched = (bool) $count; } } # composer/pcre PHPStan extensions # # These can be reused by third party packages by including 'vendor/composer/pcre/extension.neon' # in your phpstan config services: - class: Composer\Pcre\PHPStan\PregMatchParameterOutTypeExtension tags: - phpstan.staticMethodParameterOutTypeExtension - class: Composer\Pcre\PHPStan\PregMatchTypeSpecifyingExtension tags: - phpstan.typeSpecifier.staticMethodTypeSpecifyingExtension - class: Composer\Pcre\PHPStan\PregReplaceCallbackClosureTypeExtension tags: - phpstan.staticMethodParameterClosureTypeExtension rules: - Composer\Pcre\PHPStan\UnsafeStrictGroupsCallRule - Composer\Pcre\PHPStan\InvalidRegexPatternRule composer.phar /vendor/ # Commit your application's lock file https://getcomposer.org/doc/01-basic-usage.md#commit-your-composer-lock-file-to-version-control # You may choose to ignore a library lock file http://getcomposer.org/doc/02-libraries.md#lock-file # composer.lock { "name": "psalm/phar", "description": "Composer-based Psalm Phar", "license": ["MIT"], "require": { "php": "^7.1 || ^8.0" }, "conflict": { "vimeo/psalm" : "*" }, "bin": ["psalm.phar"], "config": { "platform-check": false } } This allows you to install [Psalm](https://github.com/vimeo/psalm) without worrying about composer conflicts. */ public array $params = []; /** * A function return type. Maybe null. * That means we can infer it in {@see FunctionReturnTypeProviderInterface} hook. */ public ?Union $return_type = null; /** * A function can have template args or return type. * Plugin hook must fill all used templates here. * * @var list */ public array $templates = []; /** * Determines if a function can be called with named arguments. */ public bool $allow_named_arg_calls = \true; /** * Function purity. * If function is pure then plugin hook should set it to true. */ public bool $pure = \false; /** * Determines if a function can be called with a various number of arguments. */ public bool $variadic = \false; /** * @internal */ public function toFunctionStorage(string $function_cased_name) : FunctionStorage { $storage = new FunctionStorage(); $storage->cased_name = $function_cased_name; $storage->setParams($this->params); $storage->return_type = $this->return_type; $storage->allow_named_arg_calls = $this->allow_named_arg_calls; $storage->pure = $this->pure; $storage->variadic = $this->variadic; if (!empty($this->templates)) { $storage->template_types = []; foreach ($this->templates as $template) { $storage->template_types[$template->param_name] = [$template->defining_class => $template->as]; } } return $storage; } } context = $context; $this->statements_analyzer = $statements_analyzer; } /** * @return false|Union */ public function infer(PhpParser\Node\Arg $arg) { $already_inferred_type = $this->statements_analyzer->node_data->getType($arg->value); if ($already_inferred_type) { return $already_inferred_type; } if (ExpressionAnalyzer::analyze($this->statements_analyzer, $arg->value, $this->context) === \false) { return \false; } return $this->statements_analyzer->node_data->getType($arg->value) ?? Type::getMixed(); } } $className */ public function addFileTypeScanner(string $fileExtension, string $className) : void; /** * @param string $fileExtension e.g. `'html'` * @param class-string $className */ public function addFileTypeAnalyzer(string $fileExtension, string $className) : void; } */ public static function getFunctionIds() : array; /** * @return ?array */ public static function getFunctionParams(FunctionParamsProviderEvent $event) : ?array; } */ public static function getClassLikeNames() : array; public static function isPropertyVisible(PropertyVisibilityProviderEvent $event) : ?bool; } */ public static function getFunctionIds() : array; public static function getFunctionStorage(DynamicFunctionStorageProviderEvent $event) : ?DynamicFunctionStorage; } */ public static function addTaints(AddRemoveTaintsEvent $event) : array; } */ public static function getClassLikeNames() : array; public static function getPropertyType(PropertyTypeProviderEvent $event) : ?Union; } */ public static function getClassLikeNames() : array; /** * Use this hook for informing whether or not a property exists on a given object. If you know the property does * not exist, return false. If you aren't sure if it exists or not, return null and the default analysis will * continue to determine if the property actually exists. */ public static function doesPropertyExist(PropertyExistenceProviderEvent $event) : ?bool; } */ public static function getFunctionIds() : array; /** * Use this hook for providing custom return type logic. If this plugin does not know what a function should * return but another plugin may be able to determine the type, return null. Otherwise return a mixed union type * if something should be returned, but can't be more specific. */ public static function getFunctionReturnType(FunctionReturnTypeProviderEvent $event) : ?Union; } */ public static function getClassLikeNames() : array; /** * @return ?array */ public static function getMethodParams(MethodParamsProviderEvent $event) : ?array; } */ public static function removeTaints(AddRemoveTaintsEvent $event) : array; } */ public static function getClassLikeNames() : array; /** * Use this hook for providing custom return type logic. If this plugin does not know what a method should return * but another plugin may be able to determine the type, return null. Otherwise return a mixed union type if * something should be returned, but can't be more specific. */ public static function getMethodReturnType(MethodReturnTypeProviderEvent $event) : ?Union; } */ public static function getClassLikeNames() : array; /** * Use this hook for informing whether or not a method exists on a given object. If you know the method does * not exist, return false. If you aren't sure if it exists or not, return null and the default analysis will * continue to determine if the method actually exists. */ public static function doesMethodExist(MethodExistenceProviderEvent $event) : ?bool; } statements_source = $statements_source; $this->function_id = $function_id; $this->stmt = $stmt; $this->context = $context; $this->code_location = $code_location; } public function getStatementsSource() : StatementsSource { return $this->statements_source; } /** * @return non-empty-string */ public function getFunctionId() : string { return $this->function_id; } /** * @return list */ public function getCallArgs() : array { return $this->stmt->getArgs(); } public function getContext() : Context { return $this->context; } public function getCodeLocation() : CodeLocation { return $this->code_location; } public function getStmt() : FuncCall { return $this->stmt; } } codebase = $codebase; } public function getCodebase() : Codebase { return $this->codebase; } } fq_classlike_name = $fq_classlike_name; $this->property_name = $property_name; $this->read_mode = $read_mode; $this->source = $source; $this->context = $context; } public function getFqClasslikeName() : string { return $this->fq_classlike_name; } public function getPropertyName() : string { return $this->property_name; } public function isReadMode() : bool { return $this->read_mode; } public function getSource() : ?StatementsSource { return $this->source; } public function getContext() : ?Context { return $this->context; } } expr = $expr; $this->function_id = $function_id; $this->context = $context; $this->statements_source = $statements_source; $this->codebase = $codebase; } public function getExpr() : FuncCall { return $this->expr; } public function getFunctionId() : string { return $this->function_id; } public function getContext() : Context { return $this->context; } public function getStatementsSource() : StatementsSource { return $this->statements_source; } public function getCodebase() : Codebase { return $this->codebase; } } statements_source = $statements_source; $this->function_id = $function_id; } public function getStatementsSource() : StatementsSource { return $this->statements_source; } public function getFunctionId() : string { return $this->function_id; } } expr = $expr; $this->function_id = $function_id; $this->context = $context; $this->statements_source = $statements_source; $this->codebase = $codebase; $this->return_type_candidate = $return_type_candidate; $this->file_replacements = $file_replacements; } public function getExpr() : FuncCall { return $this->expr; } /** * @return non-empty-string */ public function getFunctionId() : string { return $this->function_id; } public function getContext() : Context { return $this->context; } public function getStatementsSource() : StatementsSource { return $this->statements_source; } public function getCodebase() : Codebase { return $this->codebase; } public function getReturnTypeCandidate() : Union { return $this->return_type_candidate; } /** * @return FileManipulation[] */ public function getFileReplacements() : array { return $this->file_replacements; } /** * @param FileManipulation[] $file_replacements */ public function setFileReplacements(array $file_replacements) : void { $this->file_replacements = $file_replacements; } } issue = $issue; $this->fixable = $fixable; $this->codebase = $codebase; } public function getIssue() : CodeIssue { return $this->issue; } public function isFixable() : bool { return $this->fixable; } public function getCodebase() : Codebase { return $this->codebase; } } $stmts * @internal */ public function __construct(StatementsSource $statements_source, Context $file_context, FileStorage $file_storage, Codebase $codebase, array $stmts) { $this->statements_source = $statements_source; $this->file_context = $file_context; $this->file_storage = $file_storage; $this->codebase = $codebase; $this->stmts = $stmts; } public function getStatementsSource() : StatementsSource { return $this->statements_source; } public function getFileContext() : Context { return $this->file_context; } public function getFileStorage() : FileStorage { return $this->file_storage; } public function getCodebase() : Codebase { return $this->codebase; } /** * @return Stmt[] */ public function getStmts() : array { return $this->stmts; } } stmt = $stmt; $this->functionlike_storage = $functionlike_storage; $this->statements_source = $statements_source; $this->codebase = $codebase; $this->file_replacements = $file_replacements; $this->node_type_provider = $node_type_provider; $this->context = $context; } public function getStmt() : Node\FunctionLike { return $this->stmt; } public function getFunctionlikeStorage() : FunctionLikeStorage { return $this->functionlike_storage; } public function getStatementsSource() : StatementsSource { return $this->statements_source; } public function getCodebase() : Codebase { return $this->codebase; } /** * @return FileManipulation[] */ public function getFileReplacements() : array { return $this->file_replacements; } /** * @param FileManipulation[] $file_replacements */ public function setFileReplacements(array $file_replacements) : void { $this->file_replacements = $file_replacements; } public function getNodeTypeProvider() : NodeTypeProvider { return $this->node_type_provider; } public function getContext() : Context { return $this->context; } } fq_classlike_name = $fq_classlike_name; $this->property_name = $property_name; $this->read_mode = $read_mode; $this->source = $source; $this->context = $context; $this->code_location = $code_location; } public function getFqClasslikeName() : string { return $this->fq_classlike_name; } public function getPropertyName() : string { return $this->property_name; } public function isReadMode() : bool { return $this->read_mode; } public function getSource() : ?StatementsSource { return $this->source; } public function getContext() : ?Context { return $this->context; } public function getCodeLocation() : ?CodeLocation { return $this->code_location; } } stmt = $stmt; $this->storage = $storage; $this->statements_source = $statements_source; $this->codebase = $codebase; $this->file_replacements = $file_replacements; } public function getStmt() : ClassLike { return $this->stmt; } public function getStorage() : ClassLikeStorage { return $this->storage; } public function getStatementsSource() : FileSource { return $this->statements_source; } public function getCodebase() : Codebase { return $this->codebase; } /** * @return FileManipulation[] */ public function getFileReplacements() : array { return $this->file_replacements; } /** * @param FileManipulation[] $file_replacements */ public function setFileReplacements(array $file_replacements) : void { $this->file_replacements = $file_replacements; } } */ private array $call_args; private ?Context $context; private ?CodeLocation $code_location; /** * @param list $call_args * @internal */ public function __construct(StatementsSource $statements_source, string $function_id, array $call_args, ?Context $context = null, ?CodeLocation $code_location = null) { $this->statements_source = $statements_source; $this->function_id = $function_id; $this->call_args = $call_args; $this->context = $context; $this->code_location = $code_location; } public function getStatementsSource() : StatementsSource { return $this->statements_source; } public function getFunctionId() : string { return $this->function_id; } /** * @return list */ public function getCallArgs() : array { return $this->call_args; } public function getContext() : ?Context { return $this->context; } public function getCodeLocation() : ?CodeLocation { return $this->code_location; } } value = $value; $this->codebase = $codebase; } public function getValue() : string { return $this->value; } public function getCodebase() : Codebase { return $this->codebase; } } fq_class_name = $fq_class_name; $this->code_location = $code_location; $this->statements_source = $statements_source; $this->codebase = $codebase; $this->file_replacements = $file_replacements; } public function getFqClassName() : string { return $this->fq_class_name; } public function getCodeLocation() : CodeLocation { return $this->code_location; } public function getStatementsSource() : StatementsSource { return $this->statements_source; } public function getCodebase() : Codebase { return $this->codebase; } /** * @return FileManipulation[] */ public function getFileReplacements() : array { return $this->file_replacements; } /** * @param FileManipulation[] $file_replacements */ public function setFileReplacements(array $file_replacements) : void { $this->file_replacements = $file_replacements; } } expr = $expr; $this->context = $context; $this->statements_source = $statements_source; $this->codebase = $codebase; } public function getExpr() : Expr { return $this->expr; } public function getContext() : Context { return $this->context; } public function getStatementsSource() : StatementsSource { return $this->statements_source; } public function getCodebase() : Codebase { return $this->codebase; } } stmt = $stmt; $this->context = $context; $this->statements_source = $statements_source; $this->codebase = $codebase; $this->file_replacements = $file_replacements; } public function getStmt() : Stmt { return $this->stmt; } public function getContext() : Context { return $this->context; } public function getStatementsSource() : StatementsSource { return $this->statements_source; } public function getCodebase() : Codebase { return $this->codebase; } /** * @return FileManipulation[] */ public function getFileReplacements() : array { return $this->file_replacements; } /** * @param FileManipulation[] $file_replacements */ public function setFileReplacements(array $file_replacements) : void { $this->file_replacements = $file_replacements; } } fq_classlike_name = $fq_classlike_name; $this->method_name_lowercase = $method_name_lowercase; $this->source = $source; $this->code_location = $code_location; } public function getFqClasslikeName() : string { return $this->fq_classlike_name; } public function getMethodNameLowercase() : string { return $this->method_name_lowercase; } public function getSource() : ?StatementsSource { return $this->source; } public function getCodeLocation() : ?CodeLocation { return $this->code_location; } } expr = $expr; $this->context = $context; $this->statements_source = $statements_source; $this->codebase = $codebase; $this->file_replacements = $file_replacements; } public function getExpr() : Expr { return $this->expr; } public function getContext() : Context { return $this->context; } public function getStatementsSource() : StatementsSource { return $this->statements_source; } public function getCodebase() : Codebase { return $this->codebase; } /** * @return FileManipulation[] */ public function getFileReplacements() : array { return $this->file_replacements; } /** * @param FileManipulation[] $file_replacements */ public function setFileReplacements(array $file_replacements) : void { $this->file_replacements = $file_replacements; } } statement_source = $statements_source; $this->function_id = $function_id; $this->func_call = $func_call; $this->context = $context; $this->code_location = $code_location; $this->arg_type_inferer = $arg_type_inferer; $this->template_provider = $template_provider; } public function getArgTypeInferer() : ArgTypeInferer { return $this->arg_type_inferer; } public function getTemplateProvider() : DynamicTemplateProvider { return $this->template_provider; } public function getCodebase() : Codebase { return $this->statement_source->getCodebase(); } public function getStatementSource() : StatementsSource { return $this->statement_source; } public function getFunctionId() : string { return $this->function_id; } /** * @return list */ public function getArgs() : array { return $this->func_call->getArgs(); } public function getContext() : Context { return $this->context; } public function getCodeLocation() : CodeLocation { return $this->code_location; } } */ private array $stmts; /** * Called before a file has been checked * * @param list $stmts * @internal */ public function __construct(StatementsSource $statements_source, Context $file_context, FileStorage $file_storage, Codebase $codebase, array $stmts) { $this->statements_source = $statements_source; $this->file_context = $file_context; $this->file_storage = $file_storage; $this->codebase = $codebase; $this->stmts = $stmts; } public function getStatementsSource() : StatementsSource { return $this->statements_source; } public function getFileContext() : Context { return $this->file_context; } public function getFileStorage() : FileStorage { return $this->file_storage; } public function getCodebase() : Codebase { return $this->codebase; } /** * @return list */ public function getStmts() : array { return $this->stmts; } } */ private array $file_replacements; /** * Called after a statement has been checked * * @param list $file_replacements * @internal */ public function __construct(Stmt $stmt, Context $context, StatementsSource $statements_source, Codebase $codebase, array $file_replacements = []) { $this->stmt = $stmt; $this->context = $context; $this->statements_source = $statements_source; $this->codebase = $codebase; $this->file_replacements = $file_replacements; } public function getStmt() : Stmt { return $this->stmt; } public function setStmt(Stmt $stmt) : void { $this->stmt = $stmt; } public function getContext() : Context { return $this->context; } public function getStatementsSource() : StatementsSource { return $this->statements_source; } public function getCodebase() : Codebase { return $this->codebase; } /** * @return list */ public function getFileReplacements() : array { return $this->file_replacements; } /** * @param list $file_replacements */ public function setFileReplacements(array $file_replacements) : void { $this->file_replacements = $file_replacements; } } source = $source; $this->fq_classlike_name = $fq_classlike_name; $this->method_name_lowercase = $method_name_lowercase; $this->context = $context; $this->code_location = $code_location; } public function getSource() : StatementsSource { return $this->source; } public function getFqClasslikeName() : string { return $this->fq_classlike_name; } public function getMethodNameLowercase() : string { return $this->method_name_lowercase; } public function getContext() : Context { return $this->context; } public function getCodeLocation() : ?CodeLocation { return $this->code_location; } } source = $source; $this->fq_classlike_name = $fq_classlike_name; $this->property_name = $property_name; $this->read_mode = $read_mode; $this->context = $context; $this->code_location = $code_location; } public function getSource() : StatementsSource { return $this->source; } public function getFqClasslikeName() : string { return $this->fq_classlike_name; } public function getPropertyName() : string { return $this->property_name; } public function isReadMode() : bool { return $this->read_mode; } public function getContext() : Context { return $this->context; } public function getCodeLocation() : CodeLocation { return $this->code_location; } } > where string key is a filepath */ private array $issues; private array $build_info; private ?SourceControlInfo $source_control_info; /** * Called after analysis is complete * * @param array> $issues where string key is a filepath * @internal */ public function __construct(Codebase $codebase, array $issues, array $build_info, ?SourceControlInfo $source_control_info = null) { $this->codebase = $codebase; $this->issues = $issues; $this->build_info = $build_info; $this->source_control_info = $source_control_info; } public function getCodebase() : Codebase { return $this->codebase; } /** * @return array> where string key is a filepath */ public function getIssues() : array { return $this->issues; } public function getBuildInfo() : array { return $this->build_info; } public function getSourceControlInfo() : ?SourceControlInfo { return $this->source_control_info; } } expr = $expr; $this->method_id = $method_id; $this->appearing_method_id = $appearing_method_id; $this->declaring_method_id = $declaring_method_id; $this->context = $context; $this->statements_source = $statements_source; $this->codebase = $codebase; $this->file_replacements = $file_replacements; $this->return_type_candidate = $return_type_candidate; } /** * @return MethodCall|StaticCall */ public function getExpr() : Expr { return $this->expr; } public function getMethodId() : string { return $this->method_id; } public function getAppearingMethodId() : string { return $this->appearing_method_id; } public function getDeclaringMethodId() : string { return $this->declaring_method_id; } public function getContext() : Context { return $this->context; } public function getStatementsSource() : StatementsSource { return $this->statements_source; } public function getCodebase() : Codebase { return $this->codebase; } /** * @return FileManipulation[] */ public function getFileReplacements() : array { return $this->file_replacements; } public function getReturnTypeCandidate() : ?Union { return $this->return_type_candidate; } /** * @param FileManipulation[] $file_replacements */ public function setFileReplacements(array $file_replacements) : void { $this->file_replacements = $file_replacements; } public function setReturnTypeCandidate(?Union $return_type_candidate) : void { $this->return_type_candidate = $return_type_candidate; } } |null */ private ?array $template_type_parameters; private ?string $called_fq_classlike_name; /** * @var lowercase-string|null */ private ?string $called_method_name_lowercase; /** * Use this hook for providing custom return type logic. If this plugin does not know what a method should return * but another plugin may be able to determine the type, return null. Otherwise return a mixed union type if * something should be returned, but can't be more specific. * * @param PhpParser\Node\Expr\MethodCall|PhpParser\Node\Expr\StaticCall $stmt * @param non-empty-list|null $template_type_parameters * @param lowercase-string $method_name_lowercase * @param lowercase-string $called_method_name_lowercase * @internal */ public function __construct(StatementsSource $source, string $fq_classlike_name, string $method_name_lowercase, $stmt, Context $context, CodeLocation $code_location, ?array $template_type_parameters = null, ?string $called_fq_classlike_name = null, ?string $called_method_name_lowercase = null) { $this->source = $source; $this->fq_classlike_name = $fq_classlike_name; $this->method_name_lowercase = $method_name_lowercase; $this->context = $context; $this->code_location = $code_location; $this->stmt = $stmt; $this->template_type_parameters = $template_type_parameters; $this->called_fq_classlike_name = $called_fq_classlike_name; $this->called_method_name_lowercase = $called_method_name_lowercase; } public function getSource() : StatementsSource { return $this->source; } public function getFqClasslikeName() : string { return $this->fq_classlike_name; } /** * @return lowercase-string */ public function getMethodNameLowercase() : string { return $this->method_name_lowercase; } /** * @return list */ public function getCallArgs() : array { return $this->stmt->getArgs(); } public function getContext() : Context { return $this->context; } public function getCodeLocation() : CodeLocation { return $this->code_location; } /** * @return non-empty-list|null */ public function getTemplateTypeParameters() : ?array { return $this->template_type_parameters; } public function getCalledFqClasslikeName() : ?string { return $this->called_fq_classlike_name; } /** * @return lowercase-string|null */ public function getCalledMethodNameLowercase() : ?string { return $this->called_method_name_lowercase; } /** * @return PhpParser\Node\Expr\MethodCall|PhpParser\Node\Expr\StaticCall */ public function getStmt() { return $this->stmt; } } */ private array $file_replacements; /** * Called before an expression is checked * * @param list $file_replacements * @internal */ public function __construct(Expr $expr, Context $context, StatementsSource $statements_source, Codebase $codebase, array $file_replacements = []) { $this->expr = $expr; $this->context = $context; $this->statements_source = $statements_source; $this->codebase = $codebase; $this->file_replacements = $file_replacements; } public function getExpr() : Expr { return $this->expr; } public function getContext() : Context { return $this->context; } public function getStatementsSource() : StatementsSource { return $this->statements_source; } public function getCodebase() : Codebase { return $this->codebase; } /** * @return list */ public function getFileReplacements() : array { return $this->file_replacements; } /** * @param list $file_replacements */ public function setFileReplacements(array $file_replacements) : void { $this->file_replacements = $file_replacements; } } |null */ private ?array $call_args; private ?StatementsSource $statements_source; private ?Context $context; private ?CodeLocation $code_location; /** * @param list $call_args * @internal */ public function __construct(string $fq_classlike_name, string $method_name_lowercase, ?array $call_args = null, ?StatementsSource $statements_source = null, ?Context $context = null, ?CodeLocation $code_location = null) { $this->fq_classlike_name = $fq_classlike_name; $this->method_name_lowercase = $method_name_lowercase; $this->call_args = $call_args; $this->statements_source = $statements_source; $this->context = $context; $this->code_location = $code_location; } public function getFqClasslikeName() : string { return $this->fq_classlike_name; } public function getMethodNameLowercase() : string { return $this->method_name_lowercase; } /** * @return list|null */ public function getCallArgs() : ?array { return $this->call_args; } public function getStatementsSource() : ?StatementsSource { return $this->statements_source; } public function getContext() : ?Context { return $this->context; } public function getCodeLocation() : ?CodeLocation { return $this->code_location; } } stmt = $stmt; $this->classlike_storage = $classlike_storage; $this->statements_source = $statements_source; $this->codebase = $codebase; $this->file_replacements = $file_replacements; } public function getStmt() : Node\Stmt\ClassLike { return $this->stmt; } public function getClasslikeStorage() : ClassLikeStorage { return $this->classlike_storage; } public function getStatementsSource() : StatementsSource { return $this->statements_source; } public function getCodebase() : Codebase { return $this->codebase; } /** * @return FileManipulation[] */ public function getFileReplacements() : array { return $this->file_replacements; } /** * @param FileManipulation[] $file_replacements */ public function setFileReplacements(array $file_replacements) : void { $this->file_replacements = $file_replacements; } } */ public static function getClassLikeNames() : array; public static function isMethodVisible(MethodVisibilityProviderEvent $event) : ?bool; } */ public static function getFunctionIds() : array; /** * Use this hook for informing whether or not a global function exists. If you know the function does * not exist, return false. If you aren't sure if it exists or not, return null and the default analysis * will continue to determine if the function actually exists. */ public static function doesFunctionExist(FunctionExistenceProviderEvent $event) : ?bool; } getCodebase()->config; /** * Deprecated logic, in Psalm 6 just use $config->shepherd_endpoint * '#' here is just a hack/marker to use a custom endpoint instead just a custom domain * case 1: empty option (use https://shepherd.dev/hooks/psalm/) * case 2: custom domain (/hooks/psalm should be appended) (use https://custom.domain/hooks/psalm) * case 3: custom endpoint (/hooks/psalm should be appended) (use custom endpoint) */ if (substr_compare($config->shepherd_endpoint, '#', -1) === 0) { $shepherd_endpoint = $config->shepherd_endpoint; } else { /** @psalm-suppress DeprecatedProperty, DeprecatedMethod */ $shepherd_endpoint = self::buildShepherdUrlFromHost($config->shepherd_host); } self::sendPayload($shepherd_endpoint, $rawPayload); } /** * @psalm-pure * @deprecated Will be removed in Psalm 6 */ private static function buildShepherdUrlFromHost(string $host) : string { if (parse_url($host, PHP_URL_SCHEME) === null) { $host = 'https://' . $host; } return $host . '/hooks/psalm'; } /** * @return array{ * build: array, * git: array, * issues: array, * coverage: list, * level: int<1, 8>, * versions: array * }|null */ private static function collectPayloadToSend(AfterAnalysisEvent $event) : ?array { /** @see \Psalm\Internal\ExecutionEnvironment\BuildInfoCollector::collect */ $build_info = $event->getBuildInfo(); $is_ci_env = array_key_exists('CI_NAME', $build_info); // 'git' key always presents if (!$is_ci_env) { return null; } $source_control_info = $event->getSourceControlInfo(); $source_control_data = $source_control_info ? $source_control_info->toArray() : []; if ($source_control_data === [] && isset($build_info['git']) && is_array($build_info['git'])) { $source_control_data = $build_info['git']; } unset($build_info['git']); if ($build_info === []) { return null; } $issues_grouped_by_filename = $event->getIssues(); $normalized_data = $issues_grouped_by_filename === [] ? [] : array_values(array_filter( array_merge(...array_values($issues_grouped_by_filename)), // flatten an array static fn(IssueData $i): bool => $i->severity === IssueData::SEVERITY_ERROR )); $codebase = $event->getCodebase(); return ['build' => $build_info, 'git' => $source_control_data, 'issues' => $normalized_data, 'coverage' => $codebase->analyzer->getTotalTypeCoverage($codebase), 'level' => Config::getInstance()->level, 'versions' => ['psalm' => VersionUtils::getPsalmVersion(), 'parser' => VersionUtils::getPhpParserVersion()]]; } private static function sendPayload(string $endpoint, array $rawPayload) : void { $payload = json_encode($rawPayload, JSON_THROW_ON_ERROR); // Prepare new cURL resource $ch = curl_init($endpoint); curl_setopt($ch, CURLOPT_RETURNTRANSFER, \true); curl_setopt($ch, CURLOPT_FOLLOWLOCATION, \true); curl_setopt($ch, CURLINFO_HEADER_OUT, \true); curl_setopt($ch, CURLOPT_POST, \true); curl_setopt($ch, CURLOPT_POSTFIELDS, $payload); // Set HTTP Header for POST request curl_setopt($ch, CURLOPT_HTTPHEADER, ['Content-Type: application/json', 'Content-Length: ' . strlen($payload)]); // Submit the POST request $curl_result = curl_exec($ch); /** @var array{http_code: int, ssl_verify_result: int} $curl_info */ $curl_info = curl_getinfo($ch); // Close cURL session handle curl_close($ch); $response_status_code = $curl_info['http_code']; if ($response_status_code >= 200 && $response_status_code < 300) { $shepherd_host = parse_url($endpoint, PHP_URL_HOST); fwrite(STDERR, "🐑 results sent to {$shepherd_host} 🐑" . PHP_EOL); return; } $is_ssl_error = $curl_info['ssl_verify_result'] > 1; if ($is_ssl_error) { fwrite(STDERR, self::getCurlSslErrorMessage($curl_info['ssl_verify_result']) . PHP_EOL); return; } $output = "Shepherd error: {$endpoint} endpoint responded with {$response_status_code} HTTP status code.\n"; $response_content = is_string($curl_result) ? strip_tags($curl_result) : 'n/a'; $output .= "Shepherd response: {$response_content}\n"; if ($response_status_code === 0) { $output .= "Please check shepherd endpoint — it should be a valid URL.\n"; } $output .= sprintf("cURL Debug info:\n%s\n", var_export($curl_info, \true)); fwrite(STDERR, $output); } /** * @param mixed $ch * @psalm-pure * @deprecated Will be removed in Psalm 6 */ public static function getCurlErrorMessage($ch) : string { /** * @psalm-suppress MixedArgument * @var array */ $curl_info = curl_getinfo($ch); /** @psalm-suppress MixedAssignment */ $ssl_verify_result = $curl_info['ssl_verify_result'] ?? null; if (is_int($ssl_verify_result) && $ssl_verify_result > 1) { return self::getCurlSslErrorMessage($ssl_verify_result); } return ''; } /** * @psalm-pure */ private static function getCurlSslErrorMessage(int $ssl_verify_result) : string { switch ($ssl_verify_result) { case 1: throw new BadMethodCallException('code 1 means a successful SSL response, there is no error to parse'); case 2: return 'unable to get issuer certificate'; case 3: return 'unable to get certificate CRL'; case 4: return 'unable to decrypt certificate’s signature'; case 5: return 'unable to decrypt CRL’s signature'; case 6: return 'unable to decode issuer public key'; case 7: return 'certificate signature failure'; case 8: return 'CRL signature failure'; case 9: return 'certificate is not yet valid'; case 10: return 'certificate has expired'; case 11: return 'CRL is not yet valid'; case 12: return 'CRL has expired'; case 13: return 'format error in certificate’s notBefore field'; case 14: return 'format error in certificate’s notAfter field'; case 15: return 'format error in CRL’s lastUpdate field'; case 16: return 'format error in CRL’s nextUpdate field'; case 17: return 'out of memory'; case 18: return 'self signed certificate'; case 19: return 'self signed certificate in certificate chain'; case 20: return 'unable to get local issuer certificate'; case 21: return 'unable to verify the first certificate'; case 22: return 'certificate chain too long'; case 23: return 'certificate revoked'; case 24: return 'invalid CA certificate'; case 25: return 'path length constraint exceeded'; case 26: return 'unsupported certificate purpose'; case 27: return 'certificate not trusted'; case 28: return 'certificate rejected'; case 29: return 'subject issuer mismatch'; case 30: return 'authority and subject key identifier mismatch'; case 31: return 'authority and issuer serial number mismatch'; case 32: return 'key usage does not include certificate signing'; case 50: return 'application verification failure'; default: return "unknown cURL SSL error {$ssl_verify_result}"; } } } defining_class = $defining_class; } /** * If {@see DynamicFunctionStorage} requires template params this method can create it. */ public function createTemplate(string $param_name, ?Union $as = null) : TTemplateParam { return new TTemplateParam($param_name, $as ?? Type::getMixed(), $this->defining_class); } } */ public static $ERROR_LEVELS = [self::REPORT_INFO, self::REPORT_ERROR, self::REPORT_SUPPRESS]; /** * @var array */ private const MIXED_ISSUES = ['MixedArgument', 'MixedArrayAccess', 'MixedArrayAssignment', 'MixedArrayOffset', 'MixedArrayTypeCoercion', 'MixedAssignment', 'MixedFunctionCall', 'MixedInferredReturnType', 'MixedMethodCall', 'MixedOperand', 'MixedPropertyFetch', 'MixedPropertyAssignment', 'MixedReturnStatement', 'MixedStringOffsetAssignment', 'MixedArgumentTypeCoercion', 'MixedPropertyTypeCoercion', 'MixedReturnTypeCoercion']; /** * These are special object classes that allow any and all properties to be get/set on them * * @var array */ protected $universal_object_crates; /** * @var static|null */ private static $instance; /** * Whether or not to use types as defined in docblocks * * @var bool */ public $use_docblock_types = \true; /** * Whether or not to use types as defined in property docblocks. * This is distinct from the above because you may want to use * property docblocks, but not function docblocks. * * @var bool */ public $use_docblock_property_types = \false; /** * Whether using property annotations in docblocks should implicitly seal properties * * @var bool */ public $docblock_property_types_seal_properties = \true; /** * Whether or not to throw an exception on first error * * @var bool */ public $throw_exception = \false; /** * The directory to store PHP Parser (and other) caches * * @internal * @var string|null */ public $cache_directory; private bool $cache_directory_initialized = \false; /** * The directory to store all Psalm project caches * * @var string|null */ public $global_cache_directory; /** * Path to the autoader * * @var string|null */ public $autoloader; /** * @var ProjectFileFilter|null */ protected $project_files; /** * @var ProjectFileFilter|null */ protected $extra_files; /** * The base directory of this config file without trailing slash * * @var string */ public $base_dir; /** * The PHP version to assume as declared in the config file */ private ?string $configured_php_version = null; /** * @var array */ private array $file_extensions = ['php']; /** * @var array> */ private array $filetype_scanners = []; /** * @var array> */ private array $filetype_analyzers = []; /** * @var array */ private array $filetype_scanner_paths = []; /** * @var array */ private array $filetype_analyzer_paths = []; /** * @var array */ private array $issue_handlers = []; /** * @var array */ private array $mock_classes = []; /** * @var array */ private array $preloaded_stub_files = []; /** * @var array */ private array $stub_files = []; /** * @var bool */ public $hide_external_errors = \false; /** * @var bool */ public $hide_all_errors_except_passed_files = \false; /** @var bool */ public $allow_includes = \true; /** @var 1|2|3|4|5|6|7|8 */ public $level = 1; /** * @var ?bool */ public $show_mixed_issues; /** @var bool */ public $strict_binary_operands = \false; /** * @var bool */ public $remember_property_assignments_after_call = \true; /** @var bool */ public $use_igbinary = \false; /** @var 'lz4'|'deflate'|'off' */ public $compressor = 'off'; /** * @var bool */ public $allow_string_standin_for_class = \false; /** * @var bool */ public $disable_suppress_all = \false; /** * @var bool */ public $use_phpdoc_method_without_magic_or_parent = \false; /** * @var bool */ public $use_phpdoc_property_without_magic_or_parent = \false; /** * @var bool */ public $skip_checks_on_unresolvable_includes = \false; /** * @var bool */ public $seal_all_methods = \false; /** * @var bool */ public $seal_all_properties = \false; /** * @var bool */ public $memoize_method_calls = \false; /** * @var bool */ public $hoist_constants = \false; /** * @var bool */ public $add_param_default_to_docblock_type = \false; /** * @var bool */ public $disable_var_parsing = \false; /** * @var bool */ public $check_for_throws_docblock = \false; /** * @var bool */ public $check_for_throws_in_global_scope = \false; /** * @var bool */ public $ignore_internal_falsable_issues = \true; /** * @var bool */ public $ignore_internal_nullable_issues = \true; /** * @var array */ public $ignored_exceptions = []; /** * @var array */ public $ignored_exceptions_in_global_scope = []; /** * @var array */ public $ignored_exceptions_and_descendants = []; /** * @var array */ public $ignored_exceptions_and_descendants_in_global_scope = []; /** * @var bool */ public $infer_property_types_from_constructor = \true; /** * @var bool */ public $ensure_array_string_offsets_exist = \false; /** * @var bool */ public $ensure_array_int_offsets_exist = \false; /** * @var bool */ public $ensure_override_attribute = \false; /** * @var array */ public $forbidden_functions = []; /** * TODO: Psalm 6: Update default to be true and remove warning. * * @var bool */ public $find_unused_code = \false; /** * @var bool */ public $find_unused_variables = \false; /** * @var bool */ public $find_unused_psalm_suppress = \false; /** * TODO: Psalm 6: Update default to be true and remove warning. */ public bool $find_unused_baseline_entry = \false; /** * @var bool */ public $run_taint_analysis = \false; /** @var bool */ public $use_phpstorm_meta_path = \true; /** * @var bool */ public $resolve_from_config_file = \true; /** * @var bool */ public $restrict_return_types = \false; /** * @var bool */ public $limit_method_complexity = \false; /** * @var int */ public $max_graph_size = 200; /** * @var int */ public $max_avg_path_length = 70; /** * @var int */ public $max_shaped_array_size = 100; /** * @var string[] */ public $plugin_paths = []; /** * @var array */ private array $plugin_classes = []; /** * @var bool */ public $allow_internal_named_arg_calls = \true; /** * @var bool */ public $allow_named_arg_calls = \true; /** @var array */ private array $predefined_constants = []; /** @var array */ private array $predefined_functions = []; private ?ClassLoader $composer_class_loader = null; /** * @var string */ public $hash = ''; /** @var string|null */ public $error_baseline; /** * @var bool */ public $include_php_versions_in_error_baseline = \false; /** * @var string * @deprecated Please use {@see self::$shepherd_endpoint} instead. Property will be removed in Psalm 6. */ public $shepherd_host = 'shepherd.dev'; /** * @var string * @internal */ public $shepherd_endpoint = 'https://shepherd.dev/hooks/psalm/'; /** * @var array */ public $globals = []; /** * @var int */ public $max_string_length = 1000; private ?IncludeCollector $include_collector = null; /** * @var TaintAnalysisFileFilter|null */ protected $taint_analysis_ignored_files; /** * @var bool whether to emit a backtrace of emitted issues to stderr */ public $debug_emitted_issues = \false; private bool $report_info = \true; /** * @var EventDispatcher */ public $eventDispatcher; /** @var list */ public $config_issues = []; /** * @var 'default'|'never'|'always' */ public $trigger_error_exits = 'default'; /** * @var string[] */ public $internal_stubs = []; /** @var ?int */ public $threads; /** * A list of php extensions supported by Psalm. * Where key - extension name (without ext- prefix), value - whether to load extension’s stub. * Values: * - true: ext enabled explicitly or bundled with PHP (should load stubs) * - false: ext disabled explicitly (should not load stubs) * - null: state is unknown (e.g. config not processed yet) or ext neither explicitly enabled or disabled. * * @psalm-readonly-allow-private-mutation * @var array */ public $php_extensions = ["apcu" => null, "decimal" => null, "dom" => null, "ds" => null, "ffi" => null, "geos" => null, "gmp" => null, "ibm_db2" => null, "mongodb" => null, "mysqli" => null, "pdo" => null, "random" => null, "rdkafka" => null, "redis" => null, "simplexml" => null, "soap" => null, "xdebug" => null]; /** * A list of php extensions described in CallMap Psalm files * as opposite to stub files loaded by condition (see stubs/extensions dir). * * @see https://www.php.net/manual/en/extensions.membership.php * @var list * @readonly */ public $php_extensions_supported_by_psalm_callmaps = ['apache', 'bcmath', 'bzip2', 'calendar', 'ctype', 'curl', 'dom', 'enchant', 'exif', 'filter', 'gd', 'gettext', 'gmp', 'hash', 'ibm_db2', 'iconv', 'imap', 'intl', 'json', 'ldap', 'libxml', 'mbstring', 'mysqli', 'mysqlnd', 'mhash', 'oci8', 'opcache', 'openssl', 'pcntl', 'PDO', 'pdo_mysql', 'pdo-sqlite', 'pdo-pgsql', 'pgsql', 'pspell', 'phar', 'phpdbg', 'posix', 'redis', 'readline', 'session', 'sockets', 'sqlite3', 'snmp', 'soap', 'sodium', 'shmop', 'sysvsem', 'tidy', 'tokenizer', 'uodbc', 'xml', 'xmlreader', 'xmlwriter', 'xsl', 'zip', 'zlib']; /** * A list of php extensions required by the project that aren't fully supported by Psalm. * * @var array */ public $php_extensions_not_supported = []; /** * @var array */ private array $plugins = []; /** @var list */ public array $config_warnings = []; /** @internal */ protected function __construct() { self::$instance = $this; $this->eventDispatcher = new EventDispatcher(); $this->universal_object_crates = [strtolower(stdClass::class)]; } /** * Gets a Config object from an XML file. * * Searches up a folder hierarchy for the most immediate config. * * @throws ConfigException if a config path is not found */ public static function getConfigForPath(string $path, string $current_dir) : \Psalm\Config { $config_path = self::locateConfigFile($path); if (!$config_path) { throw new ConfigNotFoundException('Config not found for path ' . $path); } return self::loadFromXMLFile($config_path, $current_dir); } /** * Searches up a folder hierarchy for the most immediate config. * * @throws ConfigException */ public static function locateConfigFile(string $path) : ?string { $dir_path = realpath($path); if ($dir_path === \false) { throw new ConfigNotFoundException('Config not found for path ' . $path); } if (!is_dir($dir_path)) { $dir_path = dirname($dir_path); } do { foreach (self::DEFAULT_FILE_NAMES as $defaultFileName) { if (file_exists($maybe_path = $dir_path . DIRECTORY_SEPARATOR . $defaultFileName)) { return $maybe_path; } } $dir_path = dirname($dir_path); } while (dirname($dir_path) !== $dir_path); return null; } /** * Creates a new config object from the file */ public static function loadFromXMLFile(string $file_path, string $current_dir) : \Psalm\Config { $file_contents = file_get_contents($file_path); $base_dir = dirname($file_path); if ($file_contents === \false) { throw new InvalidArgumentException('Cannot open ' . $file_path); } if ($file_contents === '') { throw new InvalidArgumentException('Invalid empty file ' . $file_path); } try { $config = self::loadFromXML($base_dir, $file_contents, $current_dir, $file_path); $config->hash = sha1($file_contents . PSALM_VERSION); } catch (ConfigException $e) { throw new ConfigException('Problem parsing ' . $file_path . ":\n" . ' ' . $e->getMessage()); } return $config; } /** * Computes the hash to use for a cache folder from CLI flags and from the config file's xml contents */ public function computeHash() : string { return sha1($this->hash . ':' . $this->level); } /** * Creates a new config object from an XML string * * @param string|null $current_dir Current working directory, if different to $base_dir * @param non-empty-string $file_contents * @throws ConfigException */ public static function loadFromXML(string $base_dir, string $file_contents, ?string $current_dir = null, ?string $file_path = null) : \Psalm\Config { if ($current_dir === null) { $current_dir = $base_dir; } self::validateXmlConfig($base_dir, $file_contents); return self::fromXmlAndPaths($base_dir, $file_contents, $current_dir, $file_path); } /** * @param non-empty-string $file_contents */ private static function loadDomDocument(string $base_dir, string $file_contents) : DOMDocument { $dom_document = new DOMDocument(); // there's no obvious way to set xml:base for a document when loading it from string // so instead we're changing the current directory instead to be able to process XIncludes $oldpwd = getcwd(); chdir($base_dir); $dom_document->loadXML($file_contents, LIBXML_NONET); $dom_document->xinclude(LIBXML_NOWARNING | LIBXML_NONET); chdir($oldpwd); return $dom_document; } /** * @param non-empty-string $file_contents * @throws ConfigException */ private static function validateXmlConfig(string $base_dir, string $file_contents) : void { $schema_path = dirname(__DIR__, 2) . '/config.xsd'; if (!file_exists($schema_path)) { throw new ConfigException('Cannot locate config schema'); } // Enable user error handling $prev_xml_internal_errors = libxml_use_internal_errors(\true); libxml_clear_errors(); $dom_document = self::loadDomDocument($base_dir, $file_contents); $psalm_nodes = $dom_document->getElementsByTagName('psalm'); $psalm_node = $psalm_nodes->item(0); if (!$psalm_node) { throw new ConfigException('Missing psalm node'); } if (!$psalm_node->hasAttribute('xmlns')) { $psalm_node->setAttribute('xmlns', self::CONFIG_NAMESPACE); $old_dom_document = $dom_document; $old_file_contents = $old_dom_document->saveXML(); assert($old_file_contents !== \false && $old_file_contents !== ''); $dom_document = self::loadDomDocument($base_dir, $old_file_contents); } $dom_document->schemaValidate($schema_path); // If it returns false it will generate errors handled below $errors = libxml_get_errors(); libxml_clear_errors(); libxml_use_internal_errors($prev_xml_internal_errors); foreach ($errors as $error) { if ($error->level === LIBXML_ERR_FATAL || $error->level === LIBXML_ERR_ERROR) { throw new ConfigException('Error on line ' . $error->line . ":\n" . ' ' . $error->message); } } } /** * @param positive-int $line_number 1-based line number * @return int 0-based byte offset * @throws OutOfBoundsException */ private static function lineNumberToByteOffset(string $string, int $line_number) : int { if ($line_number === 1) { return 0; } $offset = 0; for ($i = 0; $i < $line_number - 1; $i++) { $newline_offset = strpos($string, "\n", $offset); if (\false === $newline_offset) { throw new OutOfBoundsException('Line ' . $line_number . ' is not found in a string with ' . ($i + 1) . ' lines'); } $offset = $newline_offset + 1; } if ($offset > strlen($string)) { throw new OutOfBoundsException('Line ' . $line_number . ' is not found'); } return $offset; } private static function processDeprecatedAttribute(DOMAttr $attribute, string $file_contents, self $config, string $config_path) : void { $line = $attribute->getLineNo(); assert($line > 0); // getLineNo() always returns non-zero for nodes loaded from file $offset = self::lineNumberToByteOffset($file_contents, $line); $attribute_start = strrpos($file_contents, $attribute->name, $offset - strlen($file_contents)) ?: 0; $attribute_end = $attribute_start + strlen($attribute->name) - 1; $config->config_issues[] = new ConfigIssue('Attribute "' . $attribute->name . '" is deprecated ' . 'and is going to be removed in the next major version', new Raw($file_contents, $config_path, basename($config_path), $attribute_start, $attribute_end)); } private static function processDeprecatedElement(DOMElement $deprecated_element_xml, string $file_contents, self $config, string $config_path) : void { $line = $deprecated_element_xml->getLineNo(); assert($line > 0); $offset = self::lineNumberToByteOffset($file_contents, $line); $element_start = strpos($file_contents, $deprecated_element_xml->localName, $offset) ?: 0; $element_end = $element_start + strlen($deprecated_element_xml->localName) - 1; $config->config_issues[] = new ConfigIssue('Element "' . $deprecated_element_xml->localName . '" is deprecated ' . 'and is going to be removed in the next major version', new Raw($file_contents, $config_path, basename($config_path), $element_start, $element_end)); } private static function processConfigDeprecations(self $config, DOMDocument $dom_document, string $file_contents, string $config_path) : void { $config->config_issues = []; // Attributes to be removed in Psalm 6 $deprecated_attributes = []; /** @var list */ $deprecated_elements = []; $psalm_element_item = $dom_document->getElementsByTagName('psalm')->item(0); assert($psalm_element_item !== null); $attributes = $psalm_element_item->attributes; foreach ($attributes as $attribute) { if (in_array($attribute->name, $deprecated_attributes, \true)) { self::processDeprecatedAttribute($attribute, $file_contents, $config, $config_path); } } foreach ($deprecated_elements as $deprecated_element) { $deprecated_elements_xml = $dom_document->getElementsByTagNameNS(self::CONFIG_NAMESPACE, $deprecated_element); if ($deprecated_elements_xml->length) { $deprecated_element_xml = $deprecated_elements_xml->item(0); self::processDeprecatedElement($deprecated_element_xml, $file_contents, $config, $config_path); } } } /** * @param non-empty-string $file_contents * @psalm-suppress MixedAssignment * @psalm-suppress MixedArgument * @psalm-suppress MixedPropertyFetch * @throws ConfigException */ private static function fromXmlAndPaths(string $base_dir, string $file_contents, string $current_dir, ?string $config_path) : self { $config = new static(); $dom_document = self::loadDomDocument($base_dir, $file_contents); if (null !== $config_path) { self::processConfigDeprecations($config, $dom_document, $file_contents, $config_path); } $config_xml = simplexml_import_dom($dom_document); $booleanAttributes = ['useDocblockTypes' => 'use_docblock_types', 'useDocblockPropertyTypes' => 'use_docblock_property_types', 'docblockPropertyTypesSealProperties' => 'docblock_property_types_seal_properties', 'throwExceptionOnError' => 'throw_exception', 'hideExternalErrors' => 'hide_external_errors', 'hideAllErrorsExceptPassedFiles' => 'hide_all_errors_except_passed_files', 'resolveFromConfigFile' => 'resolve_from_config_file', 'allowFileIncludes' => 'allow_includes', 'strictBinaryOperands' => 'strict_binary_operands', 'rememberPropertyAssignmentsAfterCall' => 'remember_property_assignments_after_call', 'disableVarParsing' => 'disable_var_parsing', 'allowStringToStandInForClass' => 'allow_string_standin_for_class', 'disableSuppressAll' => 'disable_suppress_all', 'usePhpDocMethodsWithoutMagicCall' => 'use_phpdoc_method_without_magic_or_parent', 'usePhpDocPropertiesWithoutMagicCall' => 'use_phpdoc_property_without_magic_or_parent', 'memoizeMethodCallResults' => 'memoize_method_calls', 'hoistConstants' => 'hoist_constants', 'addParamDefaultToDocblockType' => 'add_param_default_to_docblock_type', 'checkForThrowsDocblock' => 'check_for_throws_docblock', 'checkForThrowsInGlobalScope' => 'check_for_throws_in_global_scope', 'ignoreInternalFunctionFalseReturn' => 'ignore_internal_falsable_issues', 'ignoreInternalFunctionNullReturn' => 'ignore_internal_nullable_issues', 'includePhpVersionsInErrorBaseline' => 'include_php_versions_in_error_baseline', 'ensureArrayStringOffsetsExist' => 'ensure_array_string_offsets_exist', 'ensureArrayIntOffsetsExist' => 'ensure_array_int_offsets_exist', 'ensureOverrideAttribute' => 'ensure_override_attribute', 'reportMixedIssues' => 'show_mixed_issues', 'skipChecksOnUnresolvableIncludes' => 'skip_checks_on_unresolvable_includes', 'sealAllMethods' => 'seal_all_methods', 'sealAllProperties' => 'seal_all_properties', 'runTaintAnalysis' => 'run_taint_analysis', 'usePhpStormMetaPath' => 'use_phpstorm_meta_path', 'allowInternalNamedArgumentsCalls' => 'allow_internal_named_arg_calls', 'allowNamedArgumentCalls' => 'allow_named_arg_calls', 'findUnusedPsalmSuppress' => 'find_unused_psalm_suppress', 'findUnusedBaselineEntry' => 'find_unused_baseline_entry', 'reportInfo' => 'report_info', 'restrictReturnTypes' => 'restrict_return_types', 'limitMethodComplexity' => 'limit_method_complexity']; foreach ($booleanAttributes as $xmlName => $internalName) { if (isset($config_xml[$xmlName])) { $attribute_text = (string) $config_xml[$xmlName]; $config->setBooleanAttribute($internalName, $attribute_text === 'true' || $attribute_text === '1'); } } if ($config->resolve_from_config_file) { $config->base_dir = $base_dir; } else { $config->base_dir = $current_dir; $base_dir = $current_dir; } $composer_json_path = Composer::getJsonFilePath($config->base_dir); $composer_json = null; if (file_exists($composer_json_path)) { $composer_json = json_decode(file_get_contents($composer_json_path), \true); if (!is_array($composer_json)) { throw new UnexpectedValueException('Invalid composer.json at ' . $composer_json_path); } } $required_extensions = []; foreach ($composer_json["require"] ?? [] as $required => $_) { if (strpos($required, "ext-") === 0) { $required_extensions[strtolower(substr($required, 4))] = \true; } } foreach ($required_extensions as $required_ext => $_) { if (array_key_exists($required_ext, $config->php_extensions)) { $config->php_extensions[$required_ext] = \true; } else { $config->php_extensions_not_supported[$required_ext] = \true; } } if (isset($config_xml->enableExtensions) && isset($config_xml->enableExtensions->extension)) { foreach ($config_xml->enableExtensions->extension as $extension) { assert(isset($extension["name"])); $extensionName = (string) $extension["name"]; assert(array_key_exists($extensionName, $config->php_extensions)); $config->php_extensions[$extensionName] = \true; } } if (isset($config_xml->disableExtensions) && isset($config_xml->disableExtensions->extension)) { foreach ($config_xml->disableExtensions->extension as $extension) { assert(isset($extension["name"])); $extensionName = (string) $extension["name"]; assert(array_key_exists($extensionName, $config->php_extensions)); $config->php_extensions[$extensionName] = \false; } } if (isset($config_xml['phpVersion'])) { $config->configured_php_version = (string) $config_xml['phpVersion']; } if (isset($config_xml['autoloader'])) { $autoloader = (string) $config_xml['autoloader']; $autoloader_path = $config->base_dir . DIRECTORY_SEPARATOR . $autoloader; if (!file_exists($autoloader_path)) { // in here for legacy reasons where people put absolute paths but psalm resolved it relative if ($autoloader[0] === '/') { $autoloader_path = $autoloader; } if (!file_exists($autoloader_path)) { throw new ConfigException('Cannot locate autoloader'); } } $config->autoloader = realpath($autoloader_path); } if (isset($config_xml['cacheDirectory'])) { $config->cache_directory = (string) $config_xml['cacheDirectory']; } elseif ($user_cache_dir = (new Xdg())->getHomeCacheDir()) { $config->cache_directory = $user_cache_dir . '/psalm'; } else { $config->cache_directory = sys_get_temp_dir() . '/psalm'; } $config->global_cache_directory = $config->cache_directory; $config->cache_directory .= DIRECTORY_SEPARATOR . sha1($base_dir); if (isset($config_xml['serializer'])) { $attribute_text = (string) $config_xml['serializer']; $config->use_igbinary = $attribute_text === 'igbinary'; if ($config->use_igbinary && (!function_exists('igbinary_serialize') || !function_exists('igbinary_unserialize'))) { $config->use_igbinary = \false; $config->config_warnings[] = '"serializer" set to "igbinary" but ext-igbinary seems to be missing on ' . 'the system. Using php\'s build-in serializer.'; } } elseif ($igbinary_version = phpversion('igbinary')) { $config->use_igbinary = version_compare($igbinary_version, '2.0.5') >= 0; } if (isset($config_xml['compressor'])) { $compressor = (string) $config_xml['compressor']; if ($compressor === 'lz4') { if (function_exists('_HumbugBox7ff99e199a36\\lz4_compress') && function_exists('_HumbugBox7ff99e199a36\\lz4_uncompress')) { $config->compressor = 'lz4'; } else { $config->config_warnings[] = '"compressor" set to "lz4" but ext-lz4 seems to be missing on the ' . 'system. Disabling cache compressor.'; } } elseif ($compressor === 'deflate') { if (function_exists('gzinflate') && function_exists('gzdeflate')) { $config->compressor = 'deflate'; } else { $config->config_warnings[] = '"compressor" set to "deflate" but zlib seems to be missing on the ' . 'system. Disabling cache compressor.'; } } } elseif (function_exists('gzinflate') && function_exists('gzdeflate')) { $config->compressor = 'deflate'; } if (!isset($config_xml['findUnusedBaselineEntry'])) { $config->config_warnings[] = '"findUnusedBaselineEntry" will default to "true" in Psalm 6.' . ' You should explicitly enable or disable this setting.'; } if (isset($config_xml['findUnusedCode'])) { $attribute_text = (string) $config_xml['findUnusedCode']; $config->find_unused_code = $attribute_text === 'true' || $attribute_text === '1'; $config->find_unused_variables = $config->find_unused_code; } else { $config->config_warnings[] = '"findUnusedCode" will default to "true" in Psalm 6.' . ' You should explicitly enable or disable this setting.'; } if (isset($config_xml['findUnusedVariablesAndParams'])) { $attribute_text = (string) $config_xml['findUnusedVariablesAndParams']; $config->find_unused_variables = $attribute_text === 'true' || $attribute_text === '1'; } if (isset($config_xml['errorLevel'])) { $attribute_text = (int) $config_xml['errorLevel']; if (!in_array($attribute_text, [1, 2, 3, 4, 5, 6, 7, 8], \true)) { throw new ConfigException('Invalid error level ' . $config_xml['errorLevel']); } $config->level = $attribute_text; } else { $config->level = 2; } // turn on unused variable detection in level 1 if (!isset($config_xml['findUnusedCode']) && !isset($config_xml['findUnusedVariablesAndParams']) && $config->level === 1 && $config->show_mixed_issues !== \false) { $config->find_unused_variables = \true; } if (isset($config_xml['errorBaseline'])) { $attribute_text = (string) $config_xml['errorBaseline']; $config->error_baseline = $attribute_text; } if (isset($config_xml['maxStringLength'])) { $attribute_text = (int) $config_xml['maxStringLength']; $config->max_string_length = $attribute_text; } if (isset($config_xml['maxShapedArraySize'])) { $attribute_text = (int) $config_xml['maxShapedArraySize']; $config->max_shaped_array_size = $attribute_text; } if (isset($config_xml['inferPropertyTypesFromConstructor'])) { $attribute_text = (string) $config_xml['inferPropertyTypesFromConstructor']; $config->infer_property_types_from_constructor = $attribute_text === 'true' || $attribute_text === '1'; } if (isset($config_xml['triggerErrorExits'])) { $attribute_text = (string) $config_xml['triggerErrorExits']; if ($attribute_text === 'always' || $attribute_text === 'never') { $config->trigger_error_exits = $attribute_text; } } if (isset($config_xml->projectFiles)) { $config->project_files = ProjectFileFilter::loadFromXMLElement($config_xml->projectFiles, $base_dir, \true); } // any paths passed via CLI should be added to the projectFiles // as they're getting analyzed like if they are part of the project // ProjectAnalyzer::getInstance()->check_paths_files is not populated at this point in time $paths_to_check = null; global $argv; // Hack for Symfonys own argv resolution. // @see https://github.com/vimeo/psalm/issues/10465 if (!isset($argv[0]) || basename($argv[0]) !== 'psalm-plugin') { $paths_to_check = CliUtils::getPathsToCheck(null); } if ($paths_to_check !== null) { $paths_to_add_to_project_files = array(); foreach ($paths_to_check as $path) { // if we have an .xml arg here, the files passed are invalid // valid cases (in which we don't want to add CLI passed files to projectFiles though) // are e.g. if running phpunit tests for psalm itself if (substr($path, -4) === '.xml') { $paths_to_add_to_project_files = array(); break; } // we need an absolute path for checks if (Path::isRelative($path)) { $prospective_path = $base_dir . DIRECTORY_SEPARATOR . $path; } else { $prospective_path = $path; } // will report an error when config is loaded anyway if (!file_exists($prospective_path)) { continue; } if ($config->isInProjectDirs($prospective_path)) { continue; } $paths_to_add_to_project_files[] = $prospective_path; } if ($paths_to_add_to_project_files !== array() && !isset($config_xml->projectFiles)) { if ($config_xml === null) { $config_xml = new SimpleXMLElement(''); } $config_xml->addChild('projectFiles'); } if ($paths_to_add_to_project_files !== array() && isset($config_xml->projectFiles)) { foreach ($paths_to_add_to_project_files as $path) { if (is_dir($path)) { $child = $config_xml->projectFiles->addChild('directory'); } else { $child = $config_xml->projectFiles->addChild('file'); } $child->addAttribute('name', $path); } $config->project_files = ProjectFileFilter::loadFromXMLElement($config_xml->projectFiles, $base_dir, \true); } } if (isset($config_xml->extraFiles)) { $config->extra_files = ProjectFileFilter::loadFromXMLElement($config_xml->extraFiles, $base_dir, \true); } if (isset($config_xml->taintAnalysis->ignoreFiles)) { $config->taint_analysis_ignored_files = TaintAnalysisFileFilter::loadFromXMLElement($config_xml->taintAnalysis->ignoreFiles, $base_dir, \false); } if (isset($config_xml->fileExtensions->extension)) { $config->file_extensions = []; $config->loadFileExtensions($config_xml->fileExtensions->extension); } if (isset($config_xml->mockClasses) && isset($config_xml->mockClasses->class)) { /** @var SimpleXMLElement $mock_class */ foreach ($config_xml->mockClasses->class as $mock_class) { $config->mock_classes[] = strtolower((string) $mock_class['name']); } } if (isset($config_xml->universalObjectCrates) && isset($config_xml->universalObjectCrates->class)) { /** @var SimpleXMLElement $universal_object_crate */ foreach ($config_xml->universalObjectCrates->class as $universal_object_crate) { /** @var string $classString */ $classString = $universal_object_crate['name']; $config->addUniversalObjectCrate($classString); } } if (isset($config_xml->ignoreExceptions)) { if (isset($config_xml->ignoreExceptions->class)) { foreach ($config_xml->ignoreExceptions->class as $exception_class) { $exception_name = (string) $exception_class['name']; $global_attribute_text = (string) $exception_class['onlyGlobalScope']; if ($global_attribute_text !== 'true' && $global_attribute_text !== '1') { $config->ignored_exceptions[$exception_name] = \true; } $config->ignored_exceptions_in_global_scope[$exception_name] = \true; } } if (isset($config_xml->ignoreExceptions->classAndDescendants)) { foreach ($config_xml->ignoreExceptions->classAndDescendants as $exception_class) { $exception_name = (string) $exception_class['name']; $global_attribute_text = (string) $exception_class['onlyGlobalScope']; if ($global_attribute_text !== 'true' && $global_attribute_text !== '1') { $config->ignored_exceptions_and_descendants[$exception_name] = \true; } $config->ignored_exceptions_and_descendants_in_global_scope[$exception_name] = \true; } } } if (isset($config_xml->forbiddenFunctions) && isset($config_xml->forbiddenFunctions->function)) { /** @var SimpleXMLElement $forbidden_function */ foreach ($config_xml->forbiddenFunctions->function as $forbidden_function) { $config->forbidden_functions[strtolower((string) $forbidden_function['name'])] = \true; } } if (isset($config_xml->stubs) && isset($config_xml->stubs->file)) { /** @var SimpleXMLElement $stub_file */ foreach ($config_xml->stubs->file as $stub_file) { $stub_file_name = (string) $stub_file['name']; if (!Path::isAbsolute($stub_file_name)) { $stub_file_name = $config->base_dir . DIRECTORY_SEPARATOR . $stub_file_name; } $file_path = realpath($stub_file_name); if (!$file_path) { throw new ConfigException('Cannot resolve stubfile path ' . $config->base_dir . DIRECTORY_SEPARATOR . $stub_file['name']); } if (isset($stub_file['preloadClasses'])) { $preload_classes = (string) $stub_file['preloadClasses']; if ($preload_classes === 'true' || $preload_classes === '1') { $config->addPreloadedStubFile($file_path); } else { $config->addStubFile($file_path); } } else { $config->addStubFile($file_path); } } } // this plugin loading system borrows heavily from etsy/phan if (isset($config_xml->plugins)) { if (isset($config_xml->plugins->plugin)) { foreach ($config_xml->plugins->plugin as $plugin) { $plugin_file_name = (string) $plugin['filename']; $path = Path::isAbsolute($plugin_file_name) ? $plugin_file_name : $config->base_dir . DIRECTORY_SEPARATOR . $plugin_file_name; $config->addPluginPath($path); } } if (isset($config_xml->plugins->pluginClass)) { foreach ($config_xml->plugins->pluginClass as $plugin) { $plugin_class_name = $plugin['class']; // any child elements are used as plugin configuration $plugin_config = null; if ($plugin->count()) { $plugin_config = $plugin->children(); } $config->addPluginClass((string) $plugin_class_name, $plugin_config); } } } if (isset($config_xml->issueHandlers)) { foreach ($config_xml->issueHandlers as $issue_handlers) { $issue_handler_children = $issue_handlers->children(); if ($issue_handler_children) { foreach ($issue_handler_children as $key => $issue_handler) { if ($key === 'PluginIssue') { $custom_class_name = (string) $issue_handler['name']; /** @var string $key */ $config->issue_handlers[$custom_class_name] = IssueHandler::loadFromXMLElement($issue_handler, $base_dir); } else { /** @var string $key */ $config->issue_handlers[$key] = IssueHandler::loadFromXMLElement($issue_handler, $base_dir); } } } } } if (isset($config_xml->globals) && isset($config_xml->globals->var)) { /** @var SimpleXMLElement $var */ foreach ($config_xml->globals->var as $var) { $config->globals['$' . (string) $var['name']] = (string) $var['type']; } } if (isset($config_xml['threads'])) { $config->threads = (int) $config_xml['threads']; } return $config; } public static function getInstance() : \Psalm\Config { if (self::$instance) { return self::$instance; } throw new UnexpectedValueException('No config initialized'); } public function setComposerClassLoader(?ClassLoader $loader = null) : void { $this->composer_class_loader = $loader; } public function setAdvancedErrorLevel(string $issue_key, array $config, ?string $default_error_level = null) : void { $this->issue_handlers[$issue_key] = new IssueHandler(); if ($default_error_level !== null) { $this->issue_handlers[$issue_key]->setErrorLevel($default_error_level); } $this->issue_handlers[$issue_key]->setCustomLevels($config, $this->base_dir); } public function safeSetAdvancedErrorLevel(string $issue_key, array $config, ?string $default_error_level = null) : void { if (!isset($this->issue_handlers[$issue_key])) { $this->setAdvancedErrorLevel($issue_key, $config, $default_error_level); } } public function setCustomErrorLevel(string $issue_key, string $error_level) : void { $this->issue_handlers[$issue_key] = new IssueHandler(); $this->issue_handlers[$issue_key]->setErrorLevel($error_level); } public function safeSetCustomErrorLevel(string $issue_key, string $error_level) : void { if (!isset($this->issue_handlers[$issue_key])) { $this->setCustomErrorLevel($issue_key, $error_level); } } /** * @throws ConfigException if a Config file could not be found */ private function loadFileExtensions(SimpleXMLElement $extensions) : void { foreach ($extensions as $extension) { $extension_name = preg_replace('/^\\.?/', '', (string) $extension['name'], 1); $this->file_extensions[] = $extension_name; if (isset($extension['scanner'])) { $path = $this->base_dir . DIRECTORY_SEPARATOR . (string) $extension['scanner']; if (!file_exists($path)) { throw new ConfigException('Error parsing config: cannot find file ' . $path); } $this->filetype_scanner_paths[$extension_name] = $path; } if (isset($extension['checker'])) { $path = $this->base_dir . DIRECTORY_SEPARATOR . (string) $extension['checker']; if (!file_exists($path)) { throw new ConfigException('Error parsing config: cannot find file ' . $path); } $this->filetype_analyzer_paths[$extension_name] = $path; } } } public function addPluginPath(string $path) : void { if (!file_exists($path)) { throw new InvalidArgumentException('Cannot find plugin file ' . $path); } $this->plugin_paths[] = $path; } public function addPluginClass(string $class_name, ?SimpleXMLElement $plugin_config = null) : void { $this->plugin_classes[] = ['class' => $class_name, 'config' => $plugin_config]; } /** @return array */ public function getPluginClasses() : array { return $this->plugin_classes; } public function processPluginFileExtensions(ProjectAnalyzer $projectAnalyzer) : void { $projectAnalyzer->progress->debug('Process plugin adjustments...' . PHP_EOL); $socket = new \Psalm\PluginFileExtensionsSocket($this); foreach ($this->plugin_classes as $pluginClassEntry) { $pluginClassName = $pluginClassEntry['class']; $pluginConfig = $pluginClassEntry['config']; $plugin = $this->loadPlugin($projectAnalyzer, $pluginClassName); if (!$plugin instanceof PluginFileExtensionsInterface) { continue; } try { $plugin->processFileExtensions($socket, $pluginConfig); } catch (Throwable $t) { throw new ConfigException('Failed to process plugin file extensions ' . $pluginClassName, 1635800581, $t); } $projectAnalyzer->progress->debug('Initialized plugin ' . $pluginClassName . ' successfully' . PHP_EOL); } // populate additional aspects after plugins have been initialized foreach ($socket->getAdditionalFileExtensions() as $fileExtension) { $this->file_extensions[] = $fileExtension; } foreach ($socket->getAdditionalFileTypeScanners() as $extension => $className) { $this->filetype_scanners[$extension] = $className; } foreach ($socket->getAdditionalFileTypeAnalyzers() as $extension => $className) { $this->filetype_analyzers[$extension] = $className; } } /** * Initialises all the plugins (done once the config is fully loaded) */ public function initializePlugins(ProjectAnalyzer $project_analyzer) : void { $codebase = $project_analyzer->getCodebase(); $project_analyzer->progress->debug('Initializing plugins...' . PHP_EOL); $socket = new \Psalm\PluginRegistrationSocket($this, $codebase); // initialize plugin classes earlier to let them hook into subsequent load process foreach ($this->plugin_classes as $plugin_class_entry) { $plugin_class_name = $plugin_class_entry['class']; $plugin_config = $plugin_class_entry['config']; $plugin = $this->loadPlugin($project_analyzer, $plugin_class_name); if (!$plugin instanceof PluginEntryPointInterface) { continue; } try { $plugin($socket, $plugin_config); } catch (Throwable $t) { throw new ConfigException('Failed to invoke plugin ' . $plugin_class_name, 1635800582, $t); } $project_analyzer->progress->debug('Initialized plugin ' . $plugin_class_name . ' successfully' . PHP_EOL); } foreach ($this->filetype_scanner_paths as $extension => $path) { $fq_class_name = $this->getPluginClassForPath($codebase, $path, FileScanner::class); self::requirePath($path); $this->filetype_scanners[$extension] = $fq_class_name; } foreach ($this->filetype_analyzer_paths as $extension => $path) { $fq_class_name = $this->getPluginClassForPath($codebase, $path, FileAnalyzer::class); self::requirePath($path); $this->filetype_analyzers[$extension] = $fq_class_name; } foreach ($this->plugin_paths as $path) { try { $plugin = new \Psalm\FileBasedPluginAdapter($path, $this, $codebase); $plugin($socket); } catch (Throwable $e) { throw new ConfigException('Failed to load plugin ' . $path, 0, $e); } } new HtmlFunctionTainter(); $socket->registerHooksFromClass(HtmlFunctionTainter::class); } private function loadPlugin(ProjectAnalyzer $projectAnalyzer, string $pluginClassName) : PluginInterface { if (isset($this->plugins[$pluginClassName])) { return $this->plugins[$pluginClassName]; } try { // Below will attempt to load plugins from the project directory first. // Failing that, it will use registered autoload chain, which will load // plugins from Psalm directory or phar file. If that fails as well, it // will fall back to project autoloader. It may seem that the last step // will always fail, but it's only true if project uses Composer autoloader if ($this->composer_class_loader && ($pluginclas_class_path = $this->composer_class_loader->findFile($pluginClassName))) { $projectAnalyzer->progress->debug('Loading plugin ' . $pluginClassName . ' via require' . PHP_EOL); self::requirePath($pluginclas_class_path); } else { if (!class_exists($pluginClassName)) { throw new UnexpectedValueException($pluginClassName . ' is not a known class'); } } if (!is_a($pluginClassName, PluginInterface::class, \true)) { throw new UnexpectedValueException($pluginClassName . ' is not a PluginInterface implementation'); } $this->plugins[$pluginClassName] = new $pluginClassName(); $projectAnalyzer->progress->debug('Loaded plugin ' . $pluginClassName . PHP_EOL); return $this->plugins[$pluginClassName]; } catch (Throwable $e) { throw new ConfigException('Failed to load plugin ' . $pluginClassName, 0, $e); } } private static function requirePath(string $path) : void { /** @psalm-suppress UnresolvableInclude */ require_once $path; } /** * @template T * @param T::class $must_extend * @return class-string */ private function getPluginClassForPath(\Psalm\Codebase $codebase, string $path, string $must_extend) : string { $file_storage = $codebase->createFileStorageForPath($path); $file_to_scan = new FileScanner($path, $this->shortenFileName($path), \true); $file_to_scan->scan($codebase, $file_storage); $declared_classes = ClassLikeAnalyzer::getClassesForFile($codebase, $path); if (!count($declared_classes)) { throw new InvalidArgumentException('Plugins must have at least one class in the file - ' . $path . ' has ' . count($declared_classes)); } $fq_class_name = reset($declared_classes); if (!$codebase->classlikes->classExtends($fq_class_name, $must_extend)) { throw new InvalidArgumentException('This plugin must extend ' . $must_extend . ' - ' . $path . ' does not'); } /** * @var class-string */ return $fq_class_name; } public function shortenFileName(string $to) : string { if (!is_file($to)) { // if cwd is the root directory it will be just the directory separator - trim it off first return preg_replace('/^' . preg_quote(rtrim($this->base_dir, DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR, '/') . '/', '', $to, 1); } $from = $this->base_dir; // some compatibility fixes for Windows paths $from = is_dir($from) ? rtrim($from, '\\/') . '/' : $from; $to = is_dir($to) ? rtrim($to, '\\/') . '/' : $to; $from = str_replace('\\', '/', $from); $to = str_replace('\\', '/', $to); $from = explode('/', $from); $to = explode('/', $to); $relPath = $to; foreach ($from as $depth => $dir) { // find first non-matching dir if ($dir === $to[$depth]) { // ignore this directory array_shift($relPath); } else { // get number of remaining dirs to $from $remaining = count($from) - $depth; if ($remaining > 1) { // add traversals up to first matching dir $padLength = (count($relPath) + $remaining - 1) * -1; $relPath = array_pad($relPath, $padLength, '..'); break; } } } return implode('/', $relPath); } public function reportIssueInFile(string $issue_type, string $file_path) : bool { if (($this->level < 3 && $this->show_mixed_issues === \false || $this->level > 2 && $this->show_mixed_issues !== \true) && in_array($issue_type, self::MIXED_ISSUES, \true)) { return \false; } if ($this->mustBeIgnored($file_path)) { return \false; } $dependent_files = [strtolower($file_path) => $file_path]; $project_analyzer = ProjectAnalyzer::getInstance(); // if the option is set and at least one file is passed via CLI if ($this->hide_all_errors_except_passed_files && $project_analyzer->check_paths_files && !in_array($file_path, $project_analyzer->check_paths_files, \true)) { return \false; } $codebase = $project_analyzer->getCodebase(); if (!$this->hide_external_errors) { try { $file_storage = $codebase->file_storage_provider->get($file_path); $dependent_files += $file_storage->required_by_file_paths; } catch (InvalidArgumentException $e) { // do nothing } } $any_file_path_matched = \false; foreach ($dependent_files as $dependent_file_path) { if ((!$project_analyzer->full_run && $codebase->analyzer->canReportIssues($dependent_file_path) || $project_analyzer->canReportIssues($dependent_file_path)) && ($file_path === $dependent_file_path || !$this->mustBeIgnored($dependent_file_path))) { $any_file_path_matched = \true; break; } } if (!$any_file_path_matched) { return \false; } if ($this->getReportingLevelForFile($issue_type, $file_path) === self::REPORT_SUPPRESS) { return \false; } return \true; } public function isInProjectDirs(string $file_path) : bool { return $this->project_files && $this->project_files->allows($file_path); } public function isInExtraDirs(string $file_path) : bool { return $this->extra_files && $this->extra_files->allows($file_path); } public function mustBeIgnored(string $file_path) : bool { return $this->project_files && $this->project_files->forbids($file_path); } public function trackTaintsInPath(string $file_path) : bool { return !$this->taint_analysis_ignored_files || $this->taint_analysis_ignored_files->allows($file_path); } public function getReportingLevelForIssue(CodeIssue $e) : string { $fqcn_parts = explode('\\', get_class($e)); $issue_type = array_pop($fqcn_parts); $reporting_level = null; if ($e instanceof ClassIssue) { $reporting_level = $this->getReportingLevelForClass($issue_type, $e->fq_classlike_name); } elseif ($e instanceof MethodIssue) { $reporting_level = $this->getReportingLevelForMethod($issue_type, $e->method_id); } elseif ($e instanceof FunctionIssue) { $reporting_level = $this->getReportingLevelForFunction($issue_type, $e->function_id); } elseif ($e instanceof PropertyIssue) { $reporting_level = $this->getReportingLevelForProperty($issue_type, $e->property_id); } elseif ($e instanceof ClassConstantIssue) { $reporting_level = $this->getReportingLevelForClassConstant($issue_type, $e->const_id); } elseif ($e instanceof ArgumentIssue && $e->function_id) { $reporting_level = $this->getReportingLevelForArgument($issue_type, $e->function_id); } elseif ($e instanceof VariableIssue) { $reporting_level = $this->getReportingLevelForVariable($issue_type, $e->var_name); } if ($reporting_level === null) { $reporting_level = $this->getReportingLevelForFile($issue_type, $e->getFilePath()); } if (!$this->report_info && $reporting_level === self::REPORT_INFO) { $reporting_level = self::REPORT_SUPPRESS; } $parent_issue_type = self::getParentIssueType($issue_type); if ($parent_issue_type && $reporting_level === self::REPORT_ERROR) { $parent_reporting_level = $this->getReportingLevelForFile($parent_issue_type, $e->getFilePath()); if ($parent_reporting_level !== $reporting_level) { return $parent_reporting_level; } } return $reporting_level; } /** * @psalm-pure */ public static function getParentIssueType(string $issue_type) : ?string { if ($issue_type === 'PossiblyUndefinedIntArrayOffset' || $issue_type === 'PossiblyUndefinedStringArrayOffset') { return 'PossiblyUndefinedArrayOffset'; } if ($issue_type === 'PossiblyNullReference') { return 'NullReference'; } if ($issue_type === 'PossiblyFalseReference') { return null; } if ($issue_type === 'PossiblyUndefinedArrayOffset') { return null; } if (strpos($issue_type, 'Possibly') === 0) { $stripped_issue_type = preg_replace('/^Possibly(False|Null)?/', '', $issue_type, 1); if (strpos($stripped_issue_type, 'Invalid') === \false && strpos($stripped_issue_type, 'Un') !== 0) { $stripped_issue_type = 'Invalid' . $stripped_issue_type; } return $stripped_issue_type; } if (strpos($issue_type, 'Tainted') === 0) { return 'TaintedInput'; } if (preg_match('/^(False|Null)[A-Z]/', $issue_type) && !strpos($issue_type, 'Reference')) { return preg_replace('/^(False|Null)/', 'Invalid', $issue_type, 1); } if ($issue_type === 'UndefinedInterfaceMethod') { return 'UndefinedMethod'; } if ($issue_type === 'UndefinedMagicPropertyFetch') { return 'UndefinedPropertyFetch'; } if ($issue_type === 'UndefinedMagicPropertyAssignment') { return 'UndefinedPropertyAssignment'; } if ($issue_type === 'UndefinedMagicMethod') { return 'UndefinedMethod'; } if ($issue_type === 'PossibleRawObjectIteration') { return 'RawObjectIteration'; } if ($issue_type === 'UninitializedProperty') { return 'PropertyNotSetInConstructor'; } if ($issue_type === 'InvalidDocblockParamName') { return 'InvalidDocblock'; } if ($issue_type === 'UnusedClosureParam') { return 'UnusedParam'; } if ($issue_type === 'UnusedConstructor') { return 'UnusedMethod'; } if ($issue_type === 'StringIncrement') { return 'InvalidOperand'; } if ($issue_type === 'InvalidLiteralArgument') { return 'InvalidArgument'; } if ($issue_type === 'RedundantConditionGivenDocblockType') { return 'RedundantCondition'; } if ($issue_type === 'RedundantFunctionCallGivenDocblockType') { return 'RedundantFunctionCall'; } if ($issue_type === 'RedundantCastGivenDocblockType') { return 'RedundantCast'; } if ($issue_type === 'TraitMethodSignatureMismatch') { return 'MethodSignatureMismatch'; } if ($issue_type === 'ImplementedParamTypeMismatch') { return 'MoreSpecificImplementedParamType'; } if ($issue_type === 'UndefinedDocblockClass') { return 'UndefinedClass'; } if ($issue_type === 'UnusedForeachValue') { return 'UnusedVariable'; } return null; } public function getReportingLevelForFile(string $issue_type, string $file_path) : string { if (isset($this->issue_handlers[$issue_type])) { return $this->issue_handlers[$issue_type]->getReportingLevelForFile($file_path); } // this string is replaced by scoper for Phars, so be careful $issue_class = 'Psalm\\Issue\\' . $issue_type; if (!class_exists($issue_class) || !is_a($issue_class, CodeIssue::class, \true)) { return self::REPORT_ERROR; } /** @var int */ $issue_level = $issue_class::ERROR_LEVEL; if ($issue_level > 0 && $issue_level < $this->level) { return self::REPORT_INFO; } return self::REPORT_ERROR; } public function getReportingLevelForClass(string $issue_type, string $fq_classlike_name) : ?string { if (isset($this->issue_handlers[$issue_type])) { return $this->issue_handlers[$issue_type]->getReportingLevelForClass($fq_classlike_name); } return null; } public function getReportingLevelForMethod(string $issue_type, string $method_id) : ?string { if (isset($this->issue_handlers[$issue_type])) { return $this->issue_handlers[$issue_type]->getReportingLevelForMethod($method_id); } return null; } public function getReportingLevelForFunction(string $issue_type, string $function_id) : ?string { $level = null; if (isset($this->issue_handlers[$issue_type])) { $level = $this->issue_handlers[$issue_type]->getReportingLevelForFunction($function_id); if ($level === null && $issue_type === 'UndefinedFunction') { // undefined functions trigger global namespace fallback // so we should also check reporting levels for the symbol in global scope $root_function_id = preg_replace('/.*\\\\/', '', $function_id); if ($root_function_id !== $function_id) { /** @psalm-suppress PossiblyUndefinedStringArrayOffset https://github.com/vimeo/psalm/issues/7656 */ $level = $this->issue_handlers[$issue_type]->getReportingLevelForFunction($root_function_id); } } } return $level; } public function getReportingLevelForArgument(string $issue_type, string $function_id) : ?string { if (isset($this->issue_handlers[$issue_type])) { return $this->issue_handlers[$issue_type]->getReportingLevelForArgument($function_id); } return null; } public function getReportingLevelForProperty(string $issue_type, string $property_id) : ?string { if (isset($this->issue_handlers[$issue_type])) { return $this->issue_handlers[$issue_type]->getReportingLevelForProperty($property_id); } return null; } public function getReportingLevelForClassConstant(string $issue_type, string $constant_id) : ?string { if (isset($this->issue_handlers[$issue_type])) { return $this->issue_handlers[$issue_type]->getReportingLevelForClassConstant($constant_id); } return null; } public function getReportingLevelForVariable(string $issue_type, string $var_name) : ?string { if (isset($this->issue_handlers[$issue_type])) { return $this->issue_handlers[$issue_type]->getReportingLevelForVariable($var_name); } return null; } /** * @return array */ public function getProjectDirectories() : array { if (!$this->project_files) { return []; } return $this->project_files->getDirectories(); } /** * @return array */ public function getProjectFiles() : array { if (!$this->project_files) { return []; } return $this->project_files->getFiles(); } /** * @return array */ public function getExtraDirectories() : array { if (!$this->extra_files) { return []; } return $this->extra_files->getDirectories(); } public function reportTypeStatsForFile(string $file_path) : bool { return $this->project_files && $this->project_files->allows($file_path) && $this->project_files->reportTypeStats($file_path); } public function useStrictTypesForFile(string $file_path) : bool { return $this->project_files && $this->project_files->useStrictTypes($file_path); } /** * @return array */ public function getFileExtensions() : array { return $this->file_extensions; } /** * @return array> */ public function getFiletypeScanners() : array { return $this->filetype_scanners; } /** * @return array> */ public function getFiletypeAnalyzers() : array { return $this->filetype_analyzers; } /** * @return array */ public function getMockClasses() : array { return $this->mock_classes; } public function visitPreloadedStubFiles(\Psalm\Codebase $codebase, ?Progress $progress = null) : void { if ($progress === null) { $progress = new VoidProgress(); } $core_generic_files = []; if (PHP_VERSION_ID < 80000 && $codebase->analysis_php_version_id >= 80000) { $stringable_path = dirname(__DIR__, 2) . '/stubs/Php80.phpstub'; if (!file_exists($stringable_path)) { throw new UnexpectedValueException('Cannot locate PHP 8.0 classes'); } $core_generic_files[] = $stringable_path; } if (PHP_VERSION_ID < 80100 && $codebase->analysis_php_version_id >= 80100) { $stringable_path = dirname(__DIR__, 2) . '/stubs/Php81.phpstub'; if (!file_exists($stringable_path)) { throw new UnexpectedValueException('Cannot locate PHP 8.1 classes'); } $core_generic_files[] = $stringable_path; } if (PHP_VERSION_ID < 80200 && $codebase->analysis_php_version_id >= 80200) { $stringable_path = dirname(__DIR__, 2) . '/stubs/Php82.phpstub'; if (!file_exists($stringable_path)) { throw new UnexpectedValueException('Cannot locate PHP 8.2 classes'); } $core_generic_files[] = $stringable_path; } $stub_files = array_merge($core_generic_files, $this->preloaded_stub_files); if (!$stub_files) { return; } foreach ($stub_files as $file_path) { $file_path = str_replace(['/', '\\'], DIRECTORY_SEPARATOR, $file_path); // fix mangled phar paths on Windows if (strpos($file_path, 'phar:\\\\') === 0) { $file_path = 'phar://' . substr($file_path, 7); } $codebase->scanner->addFileToDeepScan($file_path); } $progress->debug('Registering preloaded stub files' . "\n"); $codebase->register_stub_files = \true; $codebase->scanFiles(); $codebase->register_stub_files = \false; $progress->debug('Finished registering preloaded stub files' . "\n"); } public function visitStubFiles(\Psalm\Codebase $codebase, ?Progress $progress = null) : void { if ($progress === null) { $progress = new VoidProgress(); } $codebase->register_stub_files = \true; $dir_lvl_2 = dirname(__DIR__, 2); $stubsDir = $dir_lvl_2 . DIRECTORY_SEPARATOR . 'stubs' . DIRECTORY_SEPARATOR; $this->internal_stubs = [$stubsDir . 'CoreGenericFunctions.phpstub', $stubsDir . 'CoreGenericClasses.phpstub', $stubsDir . 'CoreGenericIterators.phpstub', $stubsDir . 'CoreImmutableClasses.phpstub', $stubsDir . 'Reflection.phpstub', $stubsDir . 'SPL.phpstub']; if ($codebase->analysis_php_version_id >= 70400) { $this->internal_stubs[] = $stubsDir . 'Php74.phpstub'; } if ($codebase->analysis_php_version_id >= 80000) { $this->internal_stubs[] = $stubsDir . 'CoreGenericAttributes.phpstub'; $this->internal_stubs[] = $stubsDir . 'Php80.phpstub'; } if ($codebase->analysis_php_version_id >= 80100) { $this->internal_stubs[] = $stubsDir . 'Php81.phpstub'; } if ($codebase->analysis_php_version_id >= 80200) { $this->internal_stubs[] = $stubsDir . 'Php82.phpstub'; $this->php_extensions['random'] = \true; // random is a part of the PHP core starting from PHP 8.2 } $ext_stubs_dir = $dir_lvl_2 . DIRECTORY_SEPARATOR . "stubs" . DIRECTORY_SEPARATOR . "extensions"; foreach ($this->php_extensions as $ext => $enabled) { if ($enabled) { $this->internal_stubs[] = $ext_stubs_dir . DIRECTORY_SEPARATOR . "{$ext}.phpstub"; } } /** @deprecated Will be removed in Psalm 6 */ $extensions_to_load_stubs_using_deprecated_way = ['apcu', 'random', 'redis']; foreach ($extensions_to_load_stubs_using_deprecated_way as $ext_name) { $ext_stub_path = $ext_stubs_dir . DIRECTORY_SEPARATOR . "{$ext_name}.phpstub"; $is_stub_already_loaded = in_array($ext_stub_path, $this->internal_stubs, \true); $is_ext_explicitly_disabled = ($this->php_extensions[$ext_name] ?? null) === \false; if (!$is_stub_already_loaded && !$is_ext_explicitly_disabled && extension_loaded($ext_name)) { $this->internal_stubs[] = $ext_stub_path; $this->config_warnings[] = "Psalm 6 will not automatically load stubs for ext-{$ext_name}." . " You should explicitly enable or disable this ext in composer.json or Psalm config."; } } foreach ($this->internal_stubs as $stub_path) { if (!file_exists($stub_path)) { throw new UnexpectedValueException('Cannot locate ' . $stub_path); } } $stub_files = array_merge($this->internal_stubs, $this->stub_files); $phpstorm_meta_path = $this->base_dir . DIRECTORY_SEPARATOR . '.phpstorm.meta.php'; if ($this->use_phpstorm_meta_path) { if (is_file($phpstorm_meta_path)) { $stub_files[] = $phpstorm_meta_path; } elseif (is_dir($phpstorm_meta_path)) { $phpstorm_meta_path = realpath($phpstorm_meta_path); foreach (glob($phpstorm_meta_path . '/*.meta.php', GLOB_NOSORT) as $glob) { if (is_file($glob) && realpath(dirname($glob)) === $phpstorm_meta_path) { $stub_files[] = $glob; } } } } foreach ($stub_files as $file_path) { $file_path = str_replace(['/', '\\'], DIRECTORY_SEPARATOR, $file_path); // fix mangled phar paths on Windows if (strpos($file_path, 'phar:\\\\') === 0) { $file_path = 'phar://' . substr($file_path, 7); } $codebase->scanner->addFileToDeepScan($file_path); } $progress->debug('Registering stub files' . "\n"); $codebase->scanFiles(); $progress->debug('Finished registering stub files' . "\n"); $codebase->register_stub_files = \false; } public function getCacheDirectory() : ?string { if ($this->cache_directory === null) { return null; } if ($this->cache_directory_initialized) { return $this->cache_directory; } $cwd = null; if ($this->resolve_from_config_file) { $cwd = getcwd(); chdir($this->base_dir); } try { if (!is_dir($this->cache_directory)) { try { if (mkdir($this->cache_directory, 0777, \true) === \false) { // any other error than directory already exists/permissions issue throw new RuntimeException('Failed to create Psalm cache directory for unknown reasons'); } } catch (RuntimeException $e) { if (!is_dir($this->cache_directory)) { // rethrow the error with default message // it contains the reason why creation failed throw $e; } } } } finally { if ($cwd) { chdir($cwd); } } $this->cache_directory_initialized = \true; return $this->cache_directory; } public function getGlobalCacheDirectory() : ?string { return $this->global_cache_directory; } /** * @return array */ public function getPredefinedConstants() : array { return $this->predefined_constants; } public function collectPredefinedConstants() : void { $this->predefined_constants = get_defined_constants(); } /** * @return array */ public function getPredefinedFunctions() : array { return $this->predefined_functions; } public function collectPredefinedFunctions() : void { $defined_functions = get_defined_functions(); foreach ($defined_functions['user'] as $function_name) { $this->predefined_functions[$function_name] = \true; } foreach ($defined_functions['internal'] as $function_name) { $this->predefined_functions[$function_name] = \true; } } public function setIncludeCollector(IncludeCollector $include_collector) : void { $this->include_collector = $include_collector; } public function visitComposerAutoloadFiles(ProjectAnalyzer $project_analyzer, ?Progress $progress = null) : void { if ($progress === null) { $progress = new VoidProgress(); } if (!$this->include_collector) { throw new LogicException("IncludeCollector should be set at this point"); } $vendor_autoload_files_path = $this->base_dir . DIRECTORY_SEPARATOR . 'vendor' . DIRECTORY_SEPARATOR . 'composer' . DIRECTORY_SEPARATOR . 'autoload_files.php'; if (file_exists($vendor_autoload_files_path)) { $this->include_collector->runAndCollect(static fn(): array => require $vendor_autoload_files_path); } $codebase = $project_analyzer->getCodebase(); $this->collectPredefinedFunctions(); if ($this->autoloader) { // somee classes that we think are missing may not actually be missing // as they might be autoloadable once we require the autoloader below $codebase->classlikes->forgetMissingClassLikes(); $this->include_collector->runAndCollect([$this, 'requireAutoloader']); } $this->collectPredefinedConstants(); $autoload_included_files = $this->include_collector->getFilteredIncludedFiles(); if ($autoload_included_files) { $codebase->register_autoload_files = \true; $progress->debug('Registering autoloaded files' . "\n"); foreach ($autoload_included_files as $file_path) { $file_path = str_replace(['/', '\\'], DIRECTORY_SEPARATOR, $file_path); $progress->debug(' ' . $file_path . "\n"); $codebase->scanner->addFileToDeepScan($file_path); } $codebase->scanner->scanFiles($codebase->classlikes); $progress->debug('Finished registering autoloaded files' . "\n"); $codebase->register_autoload_files = \false; } } /** * @return string|false */ public function getComposerFilePathForClassLike(string $fq_classlike_name) { if (!$this->composer_class_loader) { return \false; } return $this->composer_class_loader->findFile($fq_classlike_name); } public function getPotentialComposerFilePathForClassLike(string $class) : ?string { if (!$this->composer_class_loader) { return null; } $psr4_prefixes = $this->composer_class_loader->getPrefixesPsr4(); // PSR-4 lookup $logicalPathPsr4 = str_replace('\\', DIRECTORY_SEPARATOR, $class) . '.php'; $candidate_path = null; $maxDepth = 0; $subPath = $class; while (\false !== ($lastPos = strrpos($subPath, '\\'))) { $subPath = substr($subPath, 0, $lastPos); $search = $subPath . '\\'; if (isset($psr4_prefixes[$search])) { $depth = substr_count($search, '\\'); $pathEnd = DIRECTORY_SEPARATOR . substr($logicalPathPsr4, $lastPos + 1); foreach ($psr4_prefixes[$search] as $dir) { $dir = realpath($dir); if ($dir && $depth > $maxDepth && $this->isInProjectDirs($dir . DIRECTORY_SEPARATOR . 'testdummy.php')) { $maxDepth = $depth; $candidate_path = realpath($dir) . $pathEnd; } } } } return $candidate_path; } public static function removeCacheDirectory(string $dir) : void { clearstatcache(\true, $dir); if (is_dir($dir)) { $objects = scandir($dir, SCANDIR_SORT_NONE); if ($objects === \false) { throw new UnexpectedValueException('Not expecting false here'); } foreach ($objects as $object) { if ($object === '.' || $object === '..') { continue; } $full_path = $dir . '/' . $object; // if it was deleted in the meantime/race condition with other psalm process clearstatcache(\true, $full_path); if (!file_exists($full_path)) { continue; } if (is_dir($full_path)) { self::removeCacheDirectory($full_path); } else { $fp = fopen($full_path, 'c'); if ($fp === \false) { continue; } $max_wait_cycles = 5; $has_lock = \false; while ($max_wait_cycles > 0) { if (flock($fp, LOCK_EX)) { $has_lock = \true; break; } $max_wait_cycles--; usleep(50000); } try { if (!$has_lock) { throw new RuntimeException('Could not acquire lock for deletion of ' . $full_path); } unlink($full_path); fclose($fp); } catch (RuntimeException $e) { if (is_resource($fp)) { fclose($fp); } clearstatcache(\true, $full_path); if (file_exists($full_path)) { // rethrow the error with default message // it contains the reason why deletion failed throw $e; } } } } // may have been removed in the meantime clearstatcache(\true, $dir); if (is_dir($dir)) { rmdir($dir); } } } public function setServerMode() : void { if ($this->cache_directory !== null) { $this->cache_directory .= '-s'; } } public function addStubFile(string $stub_file) : void { $this->stub_files[$stub_file] = $stub_file; } public function hasStubFile(string $stub_file) : bool { return isset($this->stub_files[$stub_file]); } /** * @return array */ public function getStubFiles() : array { return $this->stub_files; } public function addPreloadedStubFile(string $stub_file) : void { $this->preloaded_stub_files[$stub_file] = $stub_file; } public function getPhpVersion() : ?string { return $this->getPhpVersionFromConfig() ?? $this->getPHPVersionFromComposerJson(); } public function getPhpVersionFromConfig() : ?string { return $this->configured_php_version; } private function setBooleanAttribute(string $name, bool $value) : void { $this->{$name} = $value; } /** * @psalm-suppress MixedAssignment * @psalm-suppress MixedArrayAccess */ public function getPHPVersionFromComposerJson() : ?string { $composer_json_path = Composer::getJsonFilePath($this->base_dir); if (file_exists($composer_json_path)) { try { $composer_json = json_decode(file_get_contents($composer_json_path), \true, 512, JSON_THROW_ON_ERROR); } catch (JsonException $e) { $composer_json = null; } if (!$composer_json) { throw new UnexpectedValueException('Invalid composer.json at ' . $composer_json_path); } $php_version = $composer_json['require']['php'] ?? null; if (is_string($php_version)) { $version_parser = new VersionParser(); $constraint = $version_parser->parseConstraints($php_version); $php_versions = ['5.4', '5.5', '5.6', '7.0', '7.1', '7.2', '7.3', '7.4', '8.0', '8.1', '8.2', '8.3']; foreach ($php_versions as $candidate) { if ($constraint->matches(new Constraint('<=', "{$candidate}.0.0-dev")) || $constraint->matches(new Constraint('<=', "{$candidate}.999"))) { return $candidate; } } } } return null; } public function addUniversalObjectCrate(string $class) : void { if (!class_exists($class)) { throw new UnexpectedValueException($class . ' is not a known class'); } $this->universal_object_crates[] = strtolower($class); } /** * @return array */ public function getUniversalObjectCrates() : array { return $this->universal_object_crates; } /** @internal */ public function requireAutoloader() : void { /** @psalm-suppress UnresolvableInclude */ require $this->autoloader; } } enterNode($node); if ($result === self::DONT_TRAVERSE_CHILDREN) { return \true; } if ($result === self::STOP_TRAVERSAL) { return \false; } return $node->visit($this); } /** * @psalm-external-mutation-free * @param non-empty-array $nodes */ public function traverseArray(array $nodes) : void { foreach ($nodes as $node) { if ($this->traverse($node) === \false) { return; } } } } $extra_types */ public function __construct(string $value, bool $is_static = \false, bool $definite_class = \false, array $extra_types = [], bool $from_docblock = \false) { if ($value[0] === '\\') { $value = substr($value, 1); } $this->value = $value; $this->is_static = $is_static; $this->definite_class = $definite_class; $this->extra_types = $extra_types; parent::__construct($from_docblock); } /** * @return static */ public function setIsStatic(bool $is_static, ?bool $is_static_resolved = null) : self { $is_static_resolved ??= $this->is_static_resolved; if ($this->is_static === $is_static && $this->is_static_resolved === $is_static_resolved) { return $this; } $cloned = clone $this; $cloned->is_static = $is_static; $cloned->is_static_resolved = $is_static_resolved; return $cloned; } /** * @return static */ public function setValue(string $value) : self { if ($value[0] === '\\') { $value = substr($value, 1); } if ($value === $this->value) { return $this; } $cloned = clone $this; $cloned->value = $value; return $cloned; } /** * @return static */ public function setValueIsStatic(string $value, bool $is_static, ?bool $is_static_resolved = null) : self { $is_static_resolved ??= $this->is_static_resolved; if ($value[0] === '\\') { $value = substr($value, 1); } if ($value === $this->value && $this->is_static === $is_static && $this->is_static_resolved === $is_static_resolved) { return $this; } $cloned = clone $this; $cloned->value = $value; $cloned->is_static = $is_static; $cloned->is_static_resolved = $is_static; return $cloned; } public function getKey(bool $include_extra = \true) : string { if ($include_extra && $this->extra_types) { return $this->value . '&' . implode('&', $this->extra_types); } return $this->value; } public function getId(bool $exact = \true, bool $nested = \false) : string { if ($this->extra_types) { return $this->value . '&' . implode('&', array_map(static fn(Atomic $type): string => $type->getId($exact, \true), $this->extra_types)); } return $this->is_static && $exact ? $this->value . '&static' : $this->value; } /** * @param array $aliased_classes */ public function toNamespacedString(?string $namespace, array $aliased_classes, ?string $this_class, bool $use_phpdoc_format) : string { if ($this->value === 'static') { return 'static'; } $intersection_types = $this->getNamespacedIntersectionTypes($namespace, $aliased_classes, $this_class, $use_phpdoc_format); return Type::getStringFromFQCLN($this->value, $namespace, $aliased_classes, $this_class, \true, $this->is_static) . $intersection_types; } /** * @param array $aliased_classes */ public function toPhpString(?string $namespace, array $aliased_classes, ?string $this_class, int $analysis_php_version_id) : ?string { if ($this->value === 'static') { return $analysis_php_version_id >= 80000 ? 'static' : null; } if ($this->is_static && $this->value === $this_class) { return $analysis_php_version_id >= 80000 ? 'static' : 'self'; } $result = $this->toNamespacedString($namespace, $aliased_classes, $this_class, \false); $intersection = strrpos($result, '&'); if ($intersection === \false || $analysis_php_version_id >= 80100) { return $result; } return substr($result, $intersection + 1); } public function canBeFullyExpressedInPhp(int $analysis_php_version_id) : bool { return $this->value !== 'static' && $this->is_static === \false || $analysis_php_version_id >= 80000; } /** * @return static */ public function replaceTemplateTypesWithArgTypes(TemplateResult $template_result, ?Codebase $codebase) : self { $intersection = $this->replaceIntersectionTemplateTypesWithArgTypes($template_result, $codebase); if (!$intersection) { return $this; } $cloned = clone $this; $cloned->extra_types = $intersection; return $cloned; } /** * @return static */ public function replaceTemplateTypesWithStandins(TemplateResult $template_result, Codebase $codebase, ?StatementsAnalyzer $statements_analyzer = null, ?Atomic $input_type = null, ?int $input_arg_offset = null, ?string $calling_class = null, ?string $calling_function = null, bool $replace = \true, bool $add_lower_bound = \false, int $depth = 0) : self { $intersection = $this->replaceIntersectionTemplateTypesWithStandins($template_result, $codebase, $statements_analyzer, $input_type, $input_arg_offset, $calling_class, $calling_function, $replace, $add_lower_bound, $depth); if ($intersection) { $cloned = clone $this; $cloned->extra_types = $intersection; return $cloned; } return $this; } protected function getChildNodeKeys() : array { return ['extra_types']; } /** * @param array $extra_types */ public static function createFromName(string $value, bool $is_static = \false, bool $definite_class = \false, array $extra_types = [], bool $from_docblock = \false) : \Psalm\Type\Atomic\TNamedObject { if ($value === 'Closure') { return new \Psalm\Type\Atomic\TClosure($value, null, null, null, [], $extra_types, $from_docblock); } return new \Psalm\Type\Atomic\TNamedObject($value, $is_static, $definite_class, $extra_types, $from_docblock); } } $aliased_classes */ public function toPhpString(?string $namespace, array $aliased_classes, ?string $this_class, int $analysis_php_version_id) : ?string { return $analysis_php_version_id >= 70100 ? $this->getKey() : null; } public function canBeFullyExpressedInPhp(int $analysis_php_version_id) : bool { return \true; } } $extra_types */ public function __construct(string $value, bool $is_static = \false, ?string $extends = null, array $extra_types = []) { parent::__construct($value, $is_static, \false, $extra_types); $this->extends = $extends; } public function toPhpString(?string $namespace, array $aliased_classes, ?string $this_class, int $analysis_php_version_id) : ?string { return $analysis_php_version_id >= 70200 ? $this->extends ?? 'object' : null; } /** * @param array $aliased_classes */ public function toNamespacedString(?string $namespace, array $aliased_classes, ?string $this_class, bool $use_phpdoc_format) : string { return $this->extends ?? 'object'; } } $value) * * @deprecated Will be removed in Psalm v6, use TIntRange instead * @psalm-immutable */ final class TDependentListKey extends \Psalm\Type\Atomic\TInt implements \Psalm\Type\Atomic\DependentType { /** * Used to hold information as to what list variable this refers to * * @var string */ public $var_id; /** * @param string $var_id the variable id */ public function __construct(string $var_id) { $this->var_id = $var_id; parent::__construct(\false); } public function getId(bool $exact = \true, bool $nested = \false) : string { return 'list-key<' . $this->var_id . '>'; } public function getVarId() : string { return $this->var_id; } public function getAssertionString() : string { return 'int'; } public function getReplacement() : \Psalm\Type\Atomic\TInt { return new \Psalm\Type\Atomic\TInt(); } public function canBeFullyExpressedInPhp(int $analysis_php_version_id) : bool { return \false; } } typeof = $typeof; $this->as_type = $as_type; parent::__construct(\false); } public function getId(bool $exact = \true, bool $nested = \false) : string { return $this->as_type->isMixed() || $this->as_type->hasObject() ? 'class-string' : 'class-string<' . $this->as_type->getId($exact) . '>'; } public function getKey(bool $include_extra = \true) : string { return 'get-class-of<' . $this->typeof . (!$this->as_type->isMixed() && !$this->as_type->hasObject() ? ', ' . $this->as_type->getId() : '') . '>'; } public function getVarId() : string { return $this->typeof; } public function getReplacement() : \Psalm\Type\Atomic\TClassString { return new \Psalm\Type\Atomic\TClassString(); } public function canBeFullyExpressedInPhp(int $analysis_php_version_id) : bool { return \false; } } getKey(); } public function canBeFullyExpressedInPhp(int $analysis_php_version_id) : bool { return \false; } public function getAssertionString() : string { return 'string'; } } param_name = $param_name; $this->as_type = $as_type; $this->value_param = $value_param; parent::__construct($from_docblock); } public function getId(bool $exact = \true, bool $nested = \false) : string { return 'class-string-map' . '<' . $this->param_name . ' as ' . ($this->as_type ? $this->as_type->getId($exact) : 'object') . ', ' . $this->value_param->getId($exact) . '>'; } /** * @param array $aliased_classes */ public function toNamespacedString(?string $namespace, array $aliased_classes, ?string $this_class, bool $use_phpdoc_format) : string { if ($use_phpdoc_format) { return (new \Psalm\Type\Atomic\TArray([Type::getString(), $this->value_param]))->toNamespacedString($namespace, $aliased_classes, $this_class, \true); } return 'class-string-map' . '<' . $this->param_name . ($this->as_type ? ' as ' . $this->as_type : '') . ', ' . $this->value_param->toNamespacedString($namespace, $aliased_classes, $this_class, \false) . '>'; } /** * @param array $aliased_classes */ public function toPhpString(?string $namespace, array $aliased_classes, ?string $this_class, int $analysis_php_version_id) : string { return 'array'; } public function canBeFullyExpressedInPhp(int $analysis_php_version_id) : bool { return \false; } public function getKey(bool $include_extra = \true) : string { return 'array'; } /** * @psalm-suppress InaccessibleProperty We're only acting on cloned instances * @return static */ public function replaceTemplateTypesWithStandins(TemplateResult $template_result, Codebase $codebase, ?StatementsAnalyzer $statements_analyzer = null, ?Atomic $input_type = null, ?int $input_arg_offset = null, ?string $calling_class = null, ?string $calling_function = null, bool $replace = \true, bool $add_lower_bound = \false, int $depth = 0) : self { $cloned = null; foreach ([Type::getString(), $this->value_param] as $offset => $type_param) { $input_type_param = null; if ($input_type instanceof TList) { $input_type = $input_type->getKeyedArray(); } if (($input_type instanceof \Psalm\Type\Atomic\TGenericObject || $input_type instanceof \Psalm\Type\Atomic\TIterable || $input_type instanceof \Psalm\Type\Atomic\TArray) && isset($input_type->type_params[$offset])) { $input_type_param = $input_type->type_params[$offset]; } elseif ($input_type instanceof \Psalm\Type\Atomic\TKeyedArray) { if ($offset === 0) { if ($input_type->is_list) { continue; } $input_type_param = $input_type->getGenericKeyType(); } else { $input_type_param = $input_type->getGenericValueType(); } } $value_param = TemplateStandinTypeReplacer::replace($type_param, $template_result, $codebase, $statements_analyzer, $input_type_param, $input_arg_offset, $calling_class, $calling_function, $replace, $add_lower_bound, null, $depth + 1); if ($offset === 1 && ($cloned || $this->value_param !== $value_param)) { $cloned ??= clone $this; $cloned->value_param = $value_param; } } return $cloned ?? $this; } /** * @return static */ public function replaceTemplateTypesWithArgTypes(TemplateResult $template_result, ?Codebase $codebase) : self { $value_param = TemplateInferredTypeReplacer::replace($this->value_param, $template_result, $codebase); if ($value_param === $this->value_param) { return $this; } return new static($this->param_name, $this->as_type, $value_param); } protected function getChildNodeKeys() : array { return ['value_param']; } public function equals(Atomic $other_type, bool $ensure_source_equality) : bool { if (get_class($other_type) !== static::class) { return \false; } if (!$this->value_param->equals($other_type->value_param, $ensure_source_equality, \false)) { return \false; } return \true; } public function getAssertionString() : string { return $this->getKey(); } public function getStandinKeyParam() : Union { return new Union([new \Psalm\Type\Atomic\TTemplateParamClass($this->param_name, $this->as_type->value ?? 'object', $this->as_type, 'class-string-map')]); } } $aliased_classes */ public function toPhpString(?string $namespace, array $aliased_classes, ?string $this_class, int $analysis_php_version_id) : ?string { return null; } public function canBeFullyExpressedInPhp(int $analysis_php_version_id) : bool { return \false; } } |null * @deprecated type aliases are resolved within {@see TypeParser::resolveTypeAliases()} and therefore the * referencing type(s) are part of other intersection types. The intersection types are not set anymore * and with v6 this property along with its related methods will get removed. */ public $extra_types; /** @var string */ public $declaring_fq_classlike_name; /** @var string */ public $alias_name; /** * @param array|null $extra_types */ public function __construct(string $declaring_fq_classlike_name, string $alias_name, ?array $extra_types = null) { $this->declaring_fq_classlike_name = $declaring_fq_classlike_name; $this->alias_name = $alias_name; /** @psalm-suppress DeprecatedProperty For backwards compatibility, we have to keep this here. */ $this->extra_types = $extra_types; parent::__construct(\true); } /** * @param array|null $extra_types * @deprecated type aliases are resolved within {@see TypeParser::resolveTypeAliases()} and therefore the * referencing type(s) are part of other intersection types. This method will get removed with v6. * @psalm-suppress PossiblyUnusedMethod For backwards compatibility, we have to keep this here. */ public function setIntersectionTypes(?array $extra_types) : self { /** @psalm-suppress DeprecatedProperty For backwards compatibility, we have to keep this here. */ if ($extra_types === $this->extra_types) { return $this; } return new self($this->declaring_fq_classlike_name, $this->alias_name, $extra_types); } public function getKey(bool $include_extra = \true) : string { return 'type-alias(' . $this->declaring_fq_classlike_name . '::' . $this->alias_name . ')'; } public function getId(bool $exact = \true, bool $nested = \false) : string { /** @psalm-suppress DeprecatedProperty For backwards compatibility, we have to keep this here. */ if ($this->extra_types) { return $this->getKey() . '&' . implode('&', array_map(static fn(Atomic $type): string => $type->getId($exact, \true), $this->extra_types)); } return $this->getKey(); } /** * @param array $aliased_classes */ public function toPhpString(?string $namespace, array $aliased_classes, ?string $this_class, int $analysis_php_version_id) : ?string { return null; } public function canBeFullyExpressedInPhp(int $analysis_php_version_id) : bool { return \false; } public function getAssertionString() : string { return 'mixed'; } } as_unknown_type = $as_unknown_type; } } */ public $byref_uses = []; /** * @param list $params * @param array $byref_uses * @param array $extra_types */ public function __construct(string $value = 'callable', ?array $params = null, ?Union $return_type = null, ?bool $is_pure = null, array $byref_uses = [], array $extra_types = [], bool $from_docblock = \false) { $this->params = $params; $this->return_type = $return_type; $this->is_pure = $is_pure; $this->byref_uses = $byref_uses; parent::__construct($value, \false, \false, $extra_types, $from_docblock); } public function canBeFullyExpressedInPhp(int $analysis_php_version_id) : bool { // it can, if it's just 'Closure' return $this->params === null && $this->return_type === null && $this->is_pure === null; } /** * @return static */ public function replaceTemplateTypesWithArgTypes(TemplateResult $template_result, ?Codebase $codebase) : self { $replaced = $this->replaceCallableTemplateTypesWithArgTypes($template_result, $codebase); $intersection = $this->replaceIntersectionTemplateTypesWithArgTypes($template_result, $codebase); if (!$replaced && !$intersection) { return $this; } return new static($this->value, $replaced[0] ?? $this->params, $replaced[1] ?? $this->return_type, $this->is_pure, $this->byref_uses, $intersection ?? $this->extra_types); } /** * @return static */ public function replaceTemplateTypesWithStandins(TemplateResult $template_result, Codebase $codebase, ?StatementsAnalyzer $statements_analyzer = null, ?Atomic $input_type = null, ?int $input_arg_offset = null, ?string $calling_class = null, ?string $calling_function = null, bool $replace = \true, bool $add_lower_bound = \false, int $depth = 0) : self { $replaced = $this->replaceCallableTemplateTypesWithStandins($template_result, $codebase, $statements_analyzer, $input_type, $input_arg_offset, $calling_class, $calling_function, $replace, $add_lower_bound, $depth); $intersection = $this->replaceIntersectionTemplateTypesWithStandins($template_result, $codebase, $statements_analyzer, $input_type, $input_arg_offset, $calling_class, $calling_function, $replace, $add_lower_bound, $depth); if (!$replaced && !$intersection) { return $this; } return new static($this->value, $replaced[0] ?? $this->params, $replaced[1] ?? $this->return_type, $this->is_pure, $this->byref_uses, $intersection ?? $this->extra_types); } protected function getChildNodeKeys() : array { return [...parent::getChildNodeKeys(), ...$this->getCallableChildNodeKeys()]; } } param_name = $param_name; $this->defining_class = $defining_class; $this->as_type = $as_type; $this->conditional_type = $conditional_type; $this->if_type = $if_type; $this->else_type = $else_type; parent::__construct($from_docblock); } public function setTypes(?Union $as_type, ?Union $conditional_type = null, ?Union $if_type = null, ?Union $else_type = null) : self { $as_type ??= $this->as_type; $conditional_type ??= $this->conditional_type; $if_type ??= $this->if_type; $else_type ??= $this->else_type; if ($as_type === $this->as_type && $conditional_type === $this->conditional_type && $if_type === $this->if_type && $else_type === $this->else_type) { return $this; } $cloned = clone $this; $cloned->as_type = $as_type; $cloned->conditional_type = $conditional_type; $cloned->if_type = $if_type; $cloned->else_type = $else_type; return $cloned; } public function getKey(bool $include_extra = \true) : string { return 'TConditional<' . $this->param_name . '>'; } public function getAssertionString() : string { return ''; } public function getId(bool $exact = \true, bool $nested = \false) : string { return '(' . $this->param_name . ' is ' . $this->conditional_type->getId($exact) . ' ? ' . $this->if_type->getId($exact) . ' : ' . $this->else_type->getId($exact) . ')'; } /** * @param array $aliased_classes * @return null */ public function toPhpString(?string $namespace, array $aliased_classes, ?string $this_class, int $analysis_php_version_id) : ?string { return null; } /** * @param array $aliased_classes */ public function toNamespacedString(?string $namespace, array $aliased_classes, ?string $this_class, bool $use_phpdoc_format) : string { return ''; } protected function getChildNodeKeys() : array { return ['conditional_type', 'if_type', 'else_type']; } public function canBeFullyExpressedInPhp(int $analysis_php_version_id) : bool { return \false; } /** * @return static */ public function replaceTemplateTypesWithArgTypes(TemplateResult $template_result, ?Codebase $codebase) : self { $conditional = TemplateInferredTypeReplacer::replace($this->conditional_type, $template_result, $codebase); if ($conditional === $this->conditional_type) { return $this; } return new static($this->param_name, $this->defining_class, $this->as_type, $conditional, $this->if_type, $this->else_type); } } param_name = $param_name; $this->defining_class = $defining_class; $this->as = $as; parent::__construct($from_docblock); } public function getKey(bool $include_extra = \true) : string { return 'value-of<' . $this->param_name . '>'; } public function getId(bool $exact = \true, bool $nested = \false) : string { if (!$exact) { return 'value-of<' . $this->param_name . '>'; } return 'value-of<' . $this->as->getId($exact) . '>'; } /** * @param array $aliased_classes */ public function toNamespacedString(?string $namespace, array $aliased_classes, ?string $this_class, bool $use_phpdoc_format) : string { return 'value-of<' . $this->param_name . '>'; } /** * @param array $aliased_classes */ public function toPhpString(?string $namespace, array $aliased_classes, ?string $this_class, int $analysis_php_version_id) : ?string { return null; } public function canBeFullyExpressedInPhp(int $analysis_php_version_id) : bool { return \false; } /** * @return static */ public function replaceTemplateTypesWithArgTypes(TemplateResult $template_result, ?Codebase $codebase) : self { $as = TemplateInferredTypeReplacer::replace($this->as, $template_result, $codebase); if ($as === $this->as) { return $this; } return new static($this->param_name, $this->defining_class, $as); } } */ public static function tokenNames() : array { return ['properties-of', 'public-properties-of', 'protected-properties-of', 'private-properties-of']; } /** * @param self::VISIBILITY_*|null $visibility_filter */ public function __construct(\Psalm\Type\Atomic\TNamedObject $classlike_type, ?int $visibility_filter, bool $from_docblock = \false) { $this->classlike_type = $classlike_type; $this->visibility_filter = $visibility_filter; parent::__construct($from_docblock); } /** * @return self::VISIBILITY_*|null */ public static function filterForTokenName(string $token_name) : ?int { switch ($token_name) { case 'public-properties-of': return self::VISIBILITY_PUBLIC; case 'protected-properties-of': return self::VISIBILITY_PROTECTED; case 'private-properties-of': return self::VISIBILITY_PRIVATE; default: return null; } } /** * @psalm-pure * @return TokenName */ public static function tokenNameForFilter(?int $visibility_filter) : string { switch ($visibility_filter) { case self::VISIBILITY_PUBLIC: return 'public-properties-of'; case self::VISIBILITY_PROTECTED: return 'protected-properties-of'; case self::VISIBILITY_PRIVATE: return 'private-properties-of'; default: return 'properties-of'; } } protected function getChildNodeKeys() : array { return ['classlike_type']; } public function getKey(bool $include_extra = \true) : string { return self::tokenNameForFilter($this->visibility_filter) . '<' . $this->classlike_type . '>'; } /** * @param array $aliased_classes */ public function toPhpString(?string $namespace, array $aliased_classes, ?string $this_class, int $analysis_php_version_id) : string { return $this->getKey(); } public function canBeFullyExpressedInPhp(int $analysis_php_version_id) : bool { return \false; } } callable = $callable; } public function getKey(bool $include_extra = \true) : string { $key = 'callable-object'; if ($this->callable !== null) { $key .= $this->callable->getParamString() . $this->callable->getReturnTypeString(); } return $key; } /** * @param array $aliased_classes */ public function toPhpString(?string $namespace, array $aliased_classes, ?string $this_class, int $analysis_php_version_id) : ?string { return $analysis_php_version_id >= 70200 ? 'object' : null; } public function canBeFullyExpressedInPhp(int $analysis_php_version_id) : bool { return \false; } public function getAssertionString() : string { return 'object'; } } = $config->max_string_length) { throw new InvalidArgumentException('Literal string length should be below the configured limit (' . $config->max_string_length . ')'); } $this->value = $value; parent::__construct($from_docblock); } /** * Should only be used by string interpreters to avoid recursive calls. * * For all other purposes use {@see Type::getAtomicStringFromLiteral} * * @psalm-api */ public static function make(string $value, bool $from_docblock = \false) : self { return new self($value, $from_docblock); } /** * @psalm-suppress PossiblyUnusedMethod * @return static */ public function setValue(string $value) : self { if ($value === $this->value) { return $this; } $cloned = clone $this; $cloned->value = $value; return $cloned; } public function getKey(bool $include_extra = \true) : string { return 'string(' . $this->value . ')'; } public function getId(bool $exact = \true, bool $nested = \false) : string { if (!$exact) { return 'string'; } // quote control characters, backslashes and double quote $no_newline_value = addcslashes($this->value, "\x00..\x1f\\\""); if (mb_strlen($this->value) > 80) { return "'" . mb_substr($no_newline_value, 0, 80) . '...' . "'"; } return "'" . $no_newline_value . "'"; } public function getAssertionString() : string { return 'string(' . $this->value . ')'; } /** * @param array $aliased_classes */ public function toNamespacedString(?string $namespace, array $aliased_classes, ?string $this_class, bool $use_phpdoc_format) : string { return $use_phpdoc_format ? 'string' : "'" . $this->value . "'"; } } */ public array $extra_types = []; /** * @param array $aliased_classes */ private function getNamespacedIntersectionTypes(?string $namespace, array $aliased_classes, ?string $this_class, bool $use_phpdoc_format) : string { if (!$this->extra_types) { return ''; } return '&' . implode('&', array_map( /** * @param TNamedObject|TTemplateParam|TIterable|TObjectWithProperties|TCallableObject $extra_type */ static fn(Atomic $extra_type): string => $extra_type->toNamespacedString($namespace, $aliased_classes, $this_class, $use_phpdoc_format), $this->extra_types )); } /** * @param TNamedObject|TTemplateParam|TIterable|TObjectWithProperties|TCallableObject $type * @return static */ public function addIntersectionType(Atomic $type) : self { return $this->setIntersectionTypes(array_merge($this->extra_types, [$type->getKey() => $type])); } /** * @param array $types * @return static */ public function setIntersectionTypes(array $types) : self { if ($types === $this->extra_types) { return $this; } $cloned = clone $this; $cloned->extra_types = $types; return $cloned; } /** * @return array */ public function getIntersectionTypes() : array { return $this->extra_types; } /** * @return array|null */ protected function replaceIntersectionTemplateTypesWithArgTypes(TemplateResult $template_result, ?Codebase $codebase) : ?array { if (!$this->extra_types) { return null; } $new_types = []; foreach ($this->extra_types as $extra_type) { if ($extra_type instanceof \Psalm\Type\Atomic\TTemplateParam && isset($template_result->lower_bounds[$extra_type->param_name][$extra_type->defining_class])) { $template_type = TemplateStandinTypeReplacer::getMostSpecificTypeFromBounds($template_result->lower_bounds[$extra_type->param_name][$extra_type->defining_class], $codebase); foreach ($template_type->getAtomicTypes() as $template_type_part) { if ($template_type_part instanceof \Psalm\Type\Atomic\TNamedObject) { $new_types[$template_type_part->getKey()] = $template_type_part; } elseif ($template_type_part instanceof \Psalm\Type\Atomic\TTemplateParam) { $new_types[$template_type_part->getKey()] = $template_type_part; } } } else { $extra_type = $extra_type->replaceTemplateTypesWithArgTypes($template_result, $codebase); $new_types[$extra_type->getKey()] = $extra_type; } } return $new_types === $this->extra_types ? null : $new_types; } /** * @return array|null */ protected function replaceIntersectionTemplateTypesWithStandins(TemplateResult $template_result, Codebase $codebase, ?StatementsAnalyzer $statements_analyzer = null, ?Atomic $input_type = null, ?int $input_arg_offset = null, ?string $calling_class = null, ?string $calling_function = null, bool $replace = \true, bool $add_lower_bound = \false, int $depth = 0) : ?array { if (!$this->extra_types) { return null; } $new_types = []; foreach ($this->extra_types as $type) { $type = $type->replaceTemplateTypesWithStandins($template_result, $codebase, $statements_analyzer, $input_type, $input_arg_offset, $calling_class, $calling_function, $replace, $add_lower_bound, $depth); $new_types[$type->getKey()] = $type; } return $new_types === $this->extra_types ? null : $new_types; } } $aliased_classes */ public function toPhpString(?string $namespace, array $aliased_classes, ?string $this_class, int $analysis_php_version_id) : ?string { return null; } public function canBeFullyExpressedInPhp(int $analysis_php_version_id) : bool { return \false; } } typeof = $typeof; parent::__construct(\false); } public function canBeFullyExpressedInPhp(int $analysis_php_version_id) : bool { return \false; } } `. It expects an array with two elements, both union types. * * @psalm-immutable */ class TArray extends Atomic { /** * @use GenericTrait */ use \Psalm\Type\Atomic\GenericTrait; /** * @var array{Union, Union} */ public array $type_params; /** * @var string */ public $value = 'array'; /** * Constructs a new instance of a generic type * * @param array{Union, Union} $type_params */ public function __construct(array $type_params, bool $from_docblock = \false) { $this->type_params = $type_params; parent::__construct($from_docblock); } public function getKey(bool $include_extra = \true) : string { return 'array'; } /** * @param array $aliased_classes */ public function toPhpString(?string $namespace, array $aliased_classes, ?string $this_class, int $analysis_php_version_id) : string { return $this->getKey(); } public function canBeFullyExpressedInPhp(int $analysis_php_version_id) : bool { return $this->type_params[0]->isArrayKey() && $this->type_params[1]->isMixed(); } public function equals(Atomic $other_type, bool $ensure_source_equality) : bool { if (get_class($other_type) !== static::class) { return \false; } if ($this instanceof \Psalm\Type\Atomic\TNonEmptyArray && $other_type instanceof \Psalm\Type\Atomic\TNonEmptyArray && $this->count !== $other_type->count) { return \false; } if (count($this->type_params) !== count($other_type->type_params)) { return \false; } foreach ($this->type_params as $i => $type_param) { if (!$type_param->equals($other_type->type_params[$i], $ensure_source_equality, \false)) { return \false; } } return \true; } public function getAssertionString() : string { if ($this->type_params[0]->isMixed() && $this->type_params[1]->isMixed()) { return 'array'; } return $this->getId(); } public function isEmptyArray() : bool { return $this->type_params[1]->isNever(); } /** * @return static */ public function replaceTemplateTypesWithStandins(TemplateResult $template_result, Codebase $codebase, ?StatementsAnalyzer $statements_analyzer = null, ?Atomic $input_type = null, ?int $input_arg_offset = null, ?string $calling_class = null, ?string $calling_function = null, bool $replace = \true, bool $add_lower_bound = \false, int $depth = 0) : self { $type_params = $this->replaceTypeParamsTemplateTypesWithStandins($template_result, $codebase, $statements_analyzer, $input_type, $input_arg_offset, $calling_class, $calling_function, $replace, $add_lower_bound, $depth); if ($type_params) { $cloned = clone $this; $cloned->type_params = $type_params; return $cloned; } return $this; } /** * @return static */ public function replaceTemplateTypesWithArgTypes(TemplateResult $template_result, ?Codebase $codebase) : self { $type_params = $this->replaceTypeParamsTemplateTypesWithArgTypes($template_result, $codebase); if ($type_params) { $cloned = clone $this; $cloned->type_params = $type_params; return $cloned; } return $this; } protected function getChildNodeKeys() : array { return ['type_params']; } } $aliased_classes */ public function toPhpString(?string $namespace, array $aliased_classes, ?string $this_class, int $analysis_php_version_id) : ?string { return $analysis_php_version_id >= 70000 ? 'float' : null; } } */ use \Psalm\Type\Atomic\GenericTrait; /** * @var array{Union, Union} */ public array $type_params; /** * @var string */ public $value = 'iterable'; /** * @var bool */ public $has_docblock_params = \false; /** * @param array{Union, Union}|array $type_params * @param array $extra_types */ public function __construct(array $type_params = [], array $extra_types = [], bool $from_docblock = \false) { if (isset($type_params[0], $type_params[1])) { $this->has_docblock_params = \true; $this->type_params = $type_params; } else { $this->type_params = [Type::getMixed(), Type::getMixed()]; } $this->extra_types = $extra_types; parent::__construct($from_docblock); } public function getKey(bool $include_extra = \true) : string { if ($include_extra && $this->extra_types) { // do nothing } return 'iterable'; } public function getAssertionString() : string { return 'iterable'; } public function getId(bool $exact = \true, bool $nested = \false) : string { $s = ''; foreach ($this->type_params as $type_param) { $s .= $type_param->getId($exact) . ', '; } $extra_types = ''; if ($this->extra_types) { $extra_types = '&' . implode('&', $this->extra_types); } return $this->value . '<' . substr($s, 0, -2) . '>' . $extra_types; } /** * @param array $aliased_classes */ public function toPhpString(?string $namespace, array $aliased_classes, ?string $this_class, int $analysis_php_version_id) : ?string { return $analysis_php_version_id >= 70100 ? 'iterable' : null; } public function canBeFullyExpressedInPhp(int $analysis_php_version_id) : bool { return $this->type_params[0]->isMixed() && $this->type_params[1]->isMixed(); } public function equals(Atomic $other_type, bool $ensure_source_equality) : bool { if (!$other_type instanceof self) { return \false; } if (count($this->type_params) !== count($other_type->type_params)) { return \false; } foreach ($this->type_params as $i => $type_param) { if (!$type_param->equals($other_type->type_params[$i], $ensure_source_equality, \false)) { return \false; } } return \true; } protected function getChildNodeKeys() : array { return ['type_params', 'extra_types']; } /** * @return static */ public function replaceTemplateTypesWithArgTypes(TemplateResult $template_result, ?Codebase $codebase) : self { $type_params = $this->replaceTypeParamsTemplateTypesWithArgTypes($template_result, $codebase); $intersection = $this->replaceIntersectionTemplateTypesWithArgTypes($template_result, $codebase); return new static($type_params ?? $this->type_params, $intersection ?? $this->extra_types); } /** * @return static */ public function replaceTemplateTypesWithStandins(TemplateResult $template_result, Codebase $codebase, ?StatementsAnalyzer $statements_analyzer = null, ?Atomic $input_type = null, ?int $input_arg_offset = null, ?string $calling_class = null, ?string $calling_function = null, bool $replace = \true, bool $add_lower_bound = \false, int $depth = 0) : self { $types = $this->replaceTypeParamsTemplateTypesWithStandins($template_result, $codebase, $statements_analyzer, $input_type, $input_arg_offset, $calling_class, $calling_function, $replace, $add_lower_bound, $depth); $intersection = $this->replaceIntersectionTemplateTypesWithStandins($template_result, $codebase, $statements_analyzer, $input_type, $input_arg_offset, $calling_class, $calling_function, $replace, $add_lower_bound, $depth); if (!$types && !$intersection) { return $this; } return new static($types ?? $this->type_params, $intersection ?? $this->extra_types); } } param_name = $param_name; $this->defining_class = $defining_class; $this->as = $as; parent::__construct($from_docblock); } public function getKey(bool $include_extra = \true) : string { return 'key-of<' . $this->param_name . '>'; } public function getId(bool $exact = \true, bool $nested = \false) : string { if (!$exact) { return 'key-of<' . $this->param_name . '>'; } return 'key-of<' . $this->as->getId($exact) . '>'; } /** * @param array $aliased_classes */ public function toNamespacedString(?string $namespace, array $aliased_classes, ?string $this_class, bool $use_phpdoc_format) : string { return 'key-of<' . $this->param_name . '>'; } /** * @param array $aliased_classes */ public function toPhpString(?string $namespace, array $aliased_classes, ?string $this_class, int $analysis_php_version_id) : ?string { return null; } public function canBeFullyExpressedInPhp(int $analysis_php_version_id) : bool { return \false; } /** * @return static */ public function replaceTemplateTypesWithArgTypes(TemplateResult $template_result, ?Codebase $codebase) : self { $as = TemplateInferredTypeReplacer::replace($this->as, $template_result, $codebase); if ($as === $this->as) { return $this; } return new static($this->param_name, $this->defining_class, $as); } } $aliased_classes */ public function toPhpString(?string $namespace, array $aliased_classes, ?string $this_class, int $analysis_php_version_id) : ?string { return null; } public function canBeFullyExpressedInPhp(int $analysis_php_version_id) : bool { return \false; } } param_name = $param_name; $this->defining_class = $defining_class; parent::__construct($as, $as_type, \false, \false, \false, $from_docblock); } public function getKey(bool $include_extra = \true) : string { return 'class-string<' . $this->param_name . '>'; } public function getId(bool $exact = \true, bool $nested = \false) : string { return 'class-string<' . $this->param_name . ':' . $this->defining_class . ' as ' . ($this->as_type ? $this->as_type->getId($exact) : $this->as) . '>'; } public function getAssertionString() : string { return 'class-string<' . $this->param_name . '>'; } /** * @param array $aliased_classes */ public function toNamespacedString(?string $namespace, array $aliased_classes, ?string $this_class, bool $use_phpdoc_format) : string { return $this->param_name . '::class'; } } typeof = $typeof; parent::__construct(\false); } public function getKey(bool $include_extra = \true) : string { return 'get-debug-type-of<' . $this->typeof . '>'; } public function getVarId() : string { return $this->typeof; } public function getReplacement() : \Psalm\Type\Atomic\TString { return new \Psalm\Type\Atomic\TString(); } public function canBeFullyExpressedInPhp(int $analysis_php_version_id) : bool { return \false; } } definite_class = $definite_class; } public function getKey(bool $include_extra = \true) : string { return 'class-string(' . $this->value . ')'; } /** * @param array $aliased_classes */ public function toPhpString(?string $namespace, array $aliased_classes, ?string $this_class, int $analysis_php_version_id) : string { return 'string'; } public function canBeFullyExpressedInPhp(int $analysis_php_version_id) : bool { return \false; } public function getId(bool $exact = \true, bool $nested = \false) : string { if (!$exact) { return 'class-string'; } return $this->value . '::class'; } public function getAssertionString() : string { return $this->getKey(); } /** * @param array $aliased_classes */ public function toNamespacedString(?string $namespace, array $aliased_classes, ?string $this_class, bool $use_phpdoc_format) : string { if ($use_phpdoc_format) { return 'string'; } if ($this->value === 'static') { return 'static::class'; } if ($this->value === $this_class) { return 'self::class'; } if ($namespace && stripos($this->value, $namespace . '\\') === 0) { return preg_replace('/^' . preg_quote($namespace . '\\') . '/i', '', $this->value) . '::class'; } if (!$namespace && strpos($this->value, '\\') === \false) { return $this->value . '::class'; } if (isset($aliased_classes[strtolower($this->value)])) { return $aliased_classes[strtolower($this->value)] . '::class'; } return '\\' . $this->value . '::class'; } } value = $value; parent::__construct($from_docblock); } public function getKey(bool $include_extra = \true) : string { return 'float(' . $this->value . ')'; } public function getId(bool $exact = \true, bool $nested = \false) : string { if (!$exact) { return 'float'; } return 'float(' . $this->value . ')'; } /** * @param array $aliased_classes */ public function toNamespacedString(?string $namespace, array $aliased_classes, ?string $this_class, bool $use_phpdoc_format) : string { return 'float'; } } $aliased_classes */ public function toPhpString(?string $namespace, array $aliased_classes, ?string $this_class, int $analysis_php_version_id) : ?string { return null; } public function canBeFullyExpressedInPhp(int $analysis_php_version_id) : bool { return \false; } } $aliased_classes */ public function toPhpString(?string $namespace, array $aliased_classes, ?string $this_class, int $analysis_php_version_id) : ?string { return $analysis_php_version_id >= 70000 ? 'int' : null; } } $aliased_classes */ public function toPhpString(?string $namespace, array $aliased_classes, ?string $this_class, int $analysis_php_version_id) : ?string { return null; } public function canBeFullyExpressedInPhp(int $analysis_php_version_id) : bool { return \false; } /** * @param array $aliased_classes */ public function toNamespacedString(?string $namespace, array $aliased_classes, ?string $this_class, bool $use_phpdoc_format) : string { return $use_phpdoc_format ? '(int|string)' : 'array-key'; } } from_loop_isset = $from_loop_isset; parent::__construct($from_docblock); } public function getKey(bool $include_extra = \true) : string { return 'mixed'; } /** * @param array $aliased_classes */ public function toPhpString(?string $namespace, array $aliased_classes, ?string $this_class, int $analysis_php_version_id) : ?string { return $analysis_php_version_id >= 80000 ? 'mixed' : null; } public function canBeFullyExpressedInPhp(int $analysis_php_version_id) : bool { return $analysis_php_version_id >= 80000; } public function getAssertionString() : string { return 'mixed'; } } fq_classlike_name = $fq_classlike_name; $this->const_name = $const_name; parent::__construct($from_docblock); } public function getKey(bool $include_extra = \true) : string { return 'class-constant(' . $this->fq_classlike_name . '::' . $this->const_name . ')'; } public function getId(bool $exact = \true, bool $nested = \false) : string { return $this->fq_classlike_name . '::' . $this->const_name; } public function getAssertionString() : string { return 'class-constant(' . $this->fq_classlike_name . '::' . $this->const_name . ')'; } /** * @param array $aliased_classes */ public function toPhpString(?string $namespace, array $aliased_classes, ?string $this_class, int $analysis_php_version_id) : ?string { return null; } public function canBeFullyExpressedInPhp(int $analysis_php_version_id) : bool { return \false; } /** * @param array $aliased_classes */ public function toNamespacedString(?string $namespace, array $aliased_classes, ?string $this_class, bool $use_phpdoc_format) : string { if ($this->fq_classlike_name === 'static') { return 'static::' . $this->const_name; } return Type::getStringFromFQCLN($this->fq_classlike_name, $namespace, $aliased_classes, $this_class) . '::' . $this->const_name; } } */ public $properties; /** * @var array */ public $methods; /** @var bool */ public $is_stringable_object_only = \false; /** * Constructs a new instance of a generic type * * @param array $properties * @param array $methods * @param array $extra_types */ public function __construct(array $properties, array $methods = [], array $extra_types = [], bool $from_docblock = \false) { $this->properties = $properties; $this->methods = $methods; $this->extra_types = $extra_types; $this->is_stringable_object_only = $this->properties === [] && $this->methods === ['__tostring' => 'string']; parent::__construct($from_docblock); } /** * @param array $properties */ public function setProperties(array $properties) : self { if ($properties === $this->properties) { return $this; } $cloned = clone $this; $cloned->properties = $properties; $cloned->is_stringable_object_only = $cloned->properties === [] && $cloned->methods === ['__tostring' => 'string']; return $cloned; } /** * @param array $methods */ public function setMethods(array $methods) : self { if ($methods === $this->methods) { return $this; } $cloned = clone $this; $cloned->methods = $methods; $cloned->is_stringable_object_only = $cloned->properties === [] && $cloned->methods === ['__tostring' => 'string']; return $cloned; } public function getId(bool $exact = \true, bool $nested = \false) : string { $extra_types = ''; if ($this->extra_types) { $extra_types = '&' . implode('&', $this->extra_types); } $properties_string = implode(', ', array_map( /** * @psalm-pure * @param string|int $name */ static fn($name, Union $type): string => $name . ($type->possibly_undefined ? '?' : '') . ':' . $type->getId($exact), array_keys($this->properties), $this->properties )); $methods_string = implode(', ', array_map( /** * @psalm-pure */ static fn(string $name): string => $name . '()', array_keys($this->methods) )); return 'object{' . $properties_string . ($methods_string && $properties_string ? ', ' : '') . $methods_string . '}' . $extra_types; } /** * @param array $aliased_classes */ public function toNamespacedString(?string $namespace, array $aliased_classes, ?string $this_class, bool $use_phpdoc_format) : string { if ($use_phpdoc_format) { return 'object'; } return 'object{' . implode(', ', array_map( /** * @psalm-pure * @param string|int $name */ static fn($name, Union $type): string => $name . ($type->possibly_undefined ? '?' : '') . ':' . $type->toNamespacedString($namespace, $aliased_classes, $this_class, \false), array_keys($this->properties), $this->properties )) . '}'; } /** * @param array $aliased_classes */ public function toPhpString(?string $namespace, array $aliased_classes, ?string $this_class, int $analysis_php_version_id) : string { return $this->getKey(); } public function canBeFullyExpressedInPhp(int $analysis_php_version_id) : bool { return \false; } public function equals(Atomic $other_type, bool $ensure_source_equality) : bool { if (!$other_type instanceof self) { return \false; } if (count($this->properties) !== count($other_type->properties)) { return \false; } if ($this->methods !== $other_type->methods) { return \false; } foreach ($this->properties as $property_name => $property_type) { if (!isset($other_type->properties[$property_name])) { return \false; } if (!$property_type->equals($other_type->properties[$property_name], $ensure_source_equality, \false)) { return \false; } } return \true; } /** * @return static */ public function replaceTemplateTypesWithStandins(TemplateResult $template_result, Codebase $codebase, ?StatementsAnalyzer $statements_analyzer = null, ?Atomic $input_type = null, ?int $input_arg_offset = null, ?string $calling_class = null, ?string $calling_function = null, bool $replace = \true, bool $add_lower_bound = \false, int $depth = 0) : self { $properties = []; foreach ($this->properties as $offset => $property) { $input_type_param = null; if ($input_type instanceof \Psalm\Type\Atomic\TObjectWithProperties && isset($input_type->properties[$offset])) { $input_type_param = $input_type->properties[$offset]; } $properties[$offset] = TemplateStandinTypeReplacer::replace($property, $template_result, $codebase, $statements_analyzer, $input_type_param, $input_arg_offset, $calling_class, $calling_function, $replace, $add_lower_bound, null, $depth); } $intersection = $this->replaceIntersectionTemplateTypesWithStandins($template_result, $codebase, $statements_analyzer, $input_type, $input_arg_offset, $calling_class, $calling_function, $replace, $add_lower_bound, $depth); if ($properties === $this->properties && !$intersection) { return $this; } return new static($properties, $this->methods, $intersection ?? $this->extra_types); } /** * @return static */ public function replaceTemplateTypesWithArgTypes(TemplateResult $template_result, ?Codebase $codebase) : self { $properties = $this->properties; foreach ($properties as $offset => $property) { $properties[$offset] = TemplateInferredTypeReplacer::replace($property, $template_result, $codebase); } $intersection = $this->replaceIntersectionTemplateTypesWithArgTypes($template_result, $codebase); if ($properties === $this->properties && !$intersection) { return $this; } return new static($properties, $this->methods, $intersection ?? $this->extra_types); } protected function getChildNodeKeys() : array { return ['properties', 'extra_types']; } public function getAssertionString() : string { return $this->getKey(); } } as = $as; $this->as_type = $as_type; $this->is_loaded = $is_loaded; $this->is_interface = $is_interface; $this->is_enum = $is_enum; parent::__construct($from_docblock); } /** * @return static */ public function setAs(string $as, ?\Psalm\Type\Atomic\TNamedObject $as_type) : self { if ($this->as === $as && $this->as_type === $as_type) { return $this; } $cloned = clone $this; $cloned->as = $as; $cloned->as_type = $as_type; return $cloned; } public function getKey(bool $include_extra = \true) : string { if ($this->is_interface) { $key = 'interface-string'; } elseif ($this->is_enum) { $key = 'enum-string'; } else { $key = 'class-string'; } return $key . ($this->as === 'object' ? '' : '<' . $this->as_type . '>'); } public function getId(bool $exact = \true, bool $nested = \false) : string { if ($this->is_interface) { $key = 'interface-string'; } elseif ($this->is_enum) { $key = 'enum-string'; } else { $key = 'class-string'; } return ($this->is_loaded ? 'loaded-' : '') . $key . ($this->as === 'object' ? '' : '<' . $this->as_type . '>'); } public function getAssertionString() : string { return 'class-string'; } /** * @param array $aliased_classes */ public function toPhpString(?string $namespace, array $aliased_classes, ?string $this_class, int $analysis_php_version_id) : ?string { return 'string'; } /** * @param array $aliased_classes */ public function toNamespacedString(?string $namespace, array $aliased_classes, ?string $this_class, bool $use_phpdoc_format) : string { if ($this->as === 'object') { return 'class-string'; } if ($namespace && stripos($this->as, $namespace . '\\') === 0) { return 'class-string<' . preg_replace('/^' . preg_quote($namespace . '\\') . '/i', '', $this->as) . '>'; } if (!$namespace && strpos($this->as, '\\') === \false) { return 'class-string<' . $this->as . '>'; } if (isset($aliased_classes[strtolower($this->as)])) { return 'class-string<' . $aliased_classes[strtolower($this->as)] . '>'; } return 'class-string<\\' . $this->as . '>'; } public function canBeFullyExpressedInPhp(int $analysis_php_version_id) : bool { return \false; } protected function getChildNodeKeys() : array { return $this->as_type ? ['as_type'] : []; } /** * @return static */ public function replaceTemplateTypesWithStandins(TemplateResult $template_result, Codebase $codebase, ?StatementsAnalyzer $statements_analyzer = null, ?Atomic $input_type = null, ?int $input_arg_offset = null, ?string $calling_class = null, ?string $calling_function = null, bool $replace = \true, bool $add_lower_bound = \false, int $depth = 0) : self { if (!$this->as_type) { return $this; } if ($input_type instanceof \Psalm\Type\Atomic\TLiteralClassString) { $input_object_type = new \Psalm\Type\Atomic\TNamedObject($input_type->value); } elseif ($input_type instanceof \Psalm\Type\Atomic\TClassString && $input_type->as_type) { $input_object_type = $input_type->as_type; } else { $input_object_type = new \Psalm\Type\Atomic\TObject(); } $as_type = TemplateStandinTypeReplacer::replace(new Union([$this->as_type]), $template_result, $codebase, $statements_analyzer, new Union([$input_object_type]), $input_arg_offset, $calling_class, $calling_function, $replace, $add_lower_bound, null, $depth); $as_type_types = array_values($as_type->getAtomicTypes()); $as_type = count($as_type_types) === 1 && $as_type_types[0] instanceof \Psalm\Type\Atomic\TNamedObject ? $as_type_types[0] : null; if ($this->as_type === $as_type) { return $this; } $cloned = clone $this; $cloned->as_type = $as_type; if (!$cloned->as_type) { $cloned->as = 'object'; } return $cloned; } } count && !$this->min_count) { return new \Psalm\Type\Atomic\TKeyedArray([$this->type_param], null, [Type::getListKey(), $this->type_param], \true, $this->from_docblock); } if ($this->count) { return new \Psalm\Type\Atomic\TCallableKeyedArray(array_fill(0, $this->count, $this->type_param), null, null, \true, $this->from_docblock); } return new \Psalm\Type\Atomic\TCallableKeyedArray(array_fill(0, $this->min_count, $this->type_param), null, [Type::getListKey(), $this->type_param], \true, $this->from_docblock); } } value = $value; parent::__construct($from_docblock); } public function getKey(bool $include_extra = \true) : string { return 'int(' . $this->value . ')'; } public function getId(bool $exact = \true, bool $nested = \false) : string { if (!$exact) { return 'int'; } return (string) $this->value; } public function getAssertionString() : string { return 'int(' . $this->value . ')'; } /** * @param array $aliased_classes */ public function toNamespacedString(?string $namespace, array $aliased_classes, ?string $this_class, bool $use_phpdoc_format) : string { return $use_phpdoc_format ? 'int' : (string) $this->value; } } type = $type; parent::__construct($from_docblock); } public function getKey(bool $include_extra = \true) : string { return 'key-of<' . $this->type . '>'; } /** * @param array $aliased_classes */ public function toPhpString(?string $namespace, array $aliased_classes, ?string $this_class, int $analysis_php_version_id) : ?string { return null; } public function canBeFullyExpressedInPhp(int $analysis_php_version_id) : bool { return \false; } public function getAssertionString() : string { return 'mixed'; } public static function isViableTemplateType(Union $template_type) : bool { foreach ($template_type->getAtomicTypes() as $type) { if (!$type instanceof \Psalm\Type\Atomic\TArray && !$type instanceof \Psalm\Type\Atomic\TClassConstant && !$type instanceof \Psalm\Type\Atomic\TKeyedArray && !$type instanceof TList && !$type instanceof \Psalm\Type\Atomic\TPropertiesOf) { return \false; } } return \true; } public static function getArrayKeyType(Union $type, bool $keep_template_params = \false) : ?Union { $key_types = []; foreach ($type->getAtomicTypes() as $atomic_type) { if ($atomic_type instanceof TList) { $atomic_type = $atomic_type->getKeyedArray(); } if ($atomic_type instanceof \Psalm\Type\Atomic\TArray) { $array_key_atomics = $atomic_type->type_params[0]; } elseif ($atomic_type instanceof \Psalm\Type\Atomic\TKeyedArray) { $array_key_atomics = $atomic_type->getGenericKeyType(); } elseif ($atomic_type instanceof \Psalm\Type\Atomic\TTemplateParam) { if ($keep_template_params) { $array_key_atomics = new Union([$atomic_type]); } else { $array_key_atomics = static::getArrayKeyType($atomic_type->as, $keep_template_params); if ($array_key_atomics === null) { continue; } } } else { continue; } $key_types = array_merge($key_types, array_values($array_key_atomics->getAtomicTypes())); } if ($key_types === []) { return null; } return new Union($key_types); } } `. * It expects an array with two elements, both union types. * * @psalm-immutable */ class TNonEmptyArray extends \Psalm\Type\Atomic\TArray { /** * @var positive-int|null */ public $count; /** * @var positive-int|null */ public $min_count; /** * @var string */ public $value = 'non-empty-array'; /** * @param array{Union, Union} $type_params * @param positive-int|null $count * @param positive-int|null $min_count */ public function __construct(array $type_params, ?int $count = null, ?int $min_count = null, string $value = 'non-empty-array', bool $from_docblock = \false) { $this->count = $count; $this->min_count = $min_count; $this->value = $value; parent::__construct($type_params, $from_docblock); } /** * @param positive-int|null $count * @return static */ public function setCount(?int $count) : self { if ($count === $this->count) { return $this; } $cloned = clone $this; $cloned->count = $count; return $cloned; } } case_name = $case_name; } public function getKey(bool $include_extra = \true) : string { return 'enum(' . $this->value . '::' . $this->case_name . ')'; } public function getId(bool $exact = \true, bool $nested = \false) : string { return 'enum(' . $this->value . '::' . $this->case_name . ')'; } public function toPhpString(?string $namespace, array $aliased_classes, ?string $this_class, int $analysis_php_version_id) : ?string { return $this->value; } public function canBeFullyExpressedInPhp(int $analysis_php_version_id) : bool { return \false; } /** * @param array $aliased_classes */ public function toNamespacedString(?string $namespace, array $aliased_classes, ?string $this_class, bool $use_phpdoc_format) : string { return $this->value . '::' . $this->case_name; } } $aliased_classes */ public function toPhpString(?string $namespace, array $aliased_classes, ?string $this_class, int $analysis_php_version_id) : ?string { return $analysis_php_version_id >= 70000 ? 'bool' : null; } } ` will corresponds to `0|1|2|3|4|5|6|7` if there are three constant 1, 2 and 4 * * @psalm-immutable */ final class TIntMaskOf extends \Psalm\Type\Atomic\TInt { /** @var TClassConstant|TKeyOf|TValueOf */ public $value; /** * @param TClassConstant|TKeyOf|TValueOf $value */ public function __construct(Atomic $value, bool $from_docblock = \false) { $this->value = $value; parent::__construct($from_docblock); } public function getKey(bool $include_extra = \true) : string { return 'int-mask-of<' . $this->value->getKey() . '>'; } /** * @param array $aliased_classes */ public function toNamespacedString(?string $namespace, array $aliased_classes, ?string $this_class, bool $use_phpdoc_format) : string { if ($use_phpdoc_format) { return 'int'; } return 'int-mask-of<' . $this->value->toNamespacedString($namespace, $aliased_classes, $this_class, \false) . '>'; } protected function getChildNodeKeys() : array { return ['value']; } public function canBeFullyExpressedInPhp(int $analysis_php_version_id) : bool { return \false; } } * @psalm-immutable */ trait GenericTrait { /** * @param TTypeParams $type_params * @return static */ public function setTypeParams(array $type_params) : self { if ($this->type_params === $type_params) { return $this; } $cloned = clone $this; $cloned->type_params = $type_params; return $cloned; } public function getId(bool $exact = \true, bool $nested = \false) : string { $s = ''; foreach ($this->type_params as $type_param) { $s .= $type_param->getId($exact) . ', '; } $extra_types = ''; if ($this instanceof \Psalm\Type\Atomic\TNamedObject) { if ($this->extra_types) { $extra_types = '&' . implode('&', array_map(static fn(Atomic $type): string => $type->getId($exact, \true), $this->extra_types)); } if ($this->is_static) { $extra_types .= '&static'; } } return $this->value . '<' . substr($s, 0, -2) . '>' . $extra_types; } /** * @param array $aliased_classes */ public function toNamespacedString(?string $namespace, array $aliased_classes, ?string $this_class, bool $use_phpdoc_format) : string { $base_value = $this instanceof \Psalm\Type\Atomic\TNamedObject ? parent::toNamespacedString($namespace, $aliased_classes, $this_class, $use_phpdoc_format) : $this->value; if ($base_value === 'non-empty-array') { $base_value = 'array'; } if ($use_phpdoc_format) { if ($this instanceof \Psalm\Type\Atomic\TNamedObject || $this instanceof \Psalm\Type\Atomic\TIterable) { return $base_value; } $value_type = $this->type_params[1]; if ($value_type->isMixed() || $value_type->isNever()) { return $base_value; } $value_type_string = $value_type->toNamespacedString($namespace, $aliased_classes, $this_class, \true); if (!$value_type->isSingle()) { return '(' . $value_type_string . ')[]'; } return $value_type_string . '[]'; } $intersection_pos = strpos($base_value, '&'); if ($intersection_pos !== \false) { $base_value = substr($base_value, 0, $intersection_pos); } $type_params = $this->type_params; //no need for special format if the key is not determined if ($this instanceof \Psalm\Type\Atomic\TArray && count($type_params) === 2 && isset($type_params[0]) && $type_params[0]->isArrayKey()) { //we remove the key for display unset($type_params[0]); $type_params = array_values($type_params); } if ($this instanceof \Psalm\Type\Atomic\TArray && count($type_params) === 1 && isset($type_params[0]) && $type_params[0]->isMixed()) { //when the value of an array is mixed, no need for namespaced phpdoc return 'array'; } $extra_types = ''; if ($this instanceof \Psalm\Type\Atomic\TNamedObject && $this->extra_types) { $extra_types = '&' . implode('&', array_map(static fn(Atomic $extra_type): string => $extra_type->toNamespacedString($namespace, $aliased_classes, $this_class, \false), $this->extra_types)); } return $base_value . '<' . implode(', ', array_map(static fn(Union $type_param): string => $type_param->toNamespacedString($namespace, $aliased_classes, $this_class, \false), $type_params)) . '>' . $extra_types; } /** * @return TTypeParams|null */ protected function replaceTypeParamsTemplateTypesWithStandins(TemplateResult $template_result, Codebase $codebase, ?StatementsAnalyzer $statements_analyzer = null, ?Atomic $input_type = null, ?int $input_arg_offset = null, ?string $calling_class = null, ?string $calling_function = null, bool $replace = \true, bool $add_lower_bound = \false, int $depth = 0) : ?array { if ($input_type instanceof TList) { $input_type = $input_type->getKeyedArray(); } $input_object_type_params = []; $container_type_params_covariant = []; if ($input_type instanceof \Psalm\Type\Atomic\TGenericObject && ($this instanceof \Psalm\Type\Atomic\TGenericObject || $this instanceof \Psalm\Type\Atomic\TIterable)) { $input_object_type_params = TemplateStandinTypeReplacer::getMappedGenericTypeParams($codebase, $input_type, $this, $container_type_params_covariant); } $type_params = $this->type_params; foreach ($type_params as $offset => $type_param) { $input_type_param = null; if (($input_type instanceof \Psalm\Type\Atomic\TIterable || $input_type instanceof \Psalm\Type\Atomic\TArray) && isset($input_type->type_params[$offset])) { $input_type_param = $input_type->type_params[$offset]; } elseif ($input_type instanceof \Psalm\Type\Atomic\TKeyedArray) { if ($offset === 0) { $input_type_param = $input_type->getGenericKeyType(); } else { $input_type_param = $input_type->getGenericValueType(); } } elseif ($input_type instanceof \Psalm\Type\Atomic\TNamedObject && isset($input_object_type_params[$offset])) { $input_type_param = $input_object_type_params[$offset]; } $type_params[$offset] = TemplateStandinTypeReplacer::replace($type_param, $template_result, $codebase, $statements_analyzer, $input_type_param, $input_arg_offset, $calling_class, $calling_function, $replace, $add_lower_bound, !($container_type_params_covariant[$offset] ?? \true) && $this instanceof \Psalm\Type\Atomic\TGenericObject ? $this->value : null, $depth + 1); } return $type_params === $this->type_params ? null : $type_params; } /** * @return TTypeParams|null */ protected function replaceTypeParamsTemplateTypesWithArgTypes(TemplateResult $template_result, ?Codebase $codebase) : ?array { $type_params = $this->type_params; foreach ($type_params as $offset => $type_param) { $type_param = TemplateInferredTypeReplacer::replace($type_param, $template_result, $codebase); if ($this instanceof \Psalm\Type\Atomic\TArray && $offset === 0 && $type_param->isMixed()) { $type_param = Type::getArrayKey(); } $type_params[$offset] = $type_param; } return $type_params === $this->type_params ? null : $type_params; } } $extra_types */ public function __construct(string $param_name, Union $extends, string $defining_class, array $extra_types = [], bool $from_docblock = \false) { $this->param_name = $param_name; $this->as = $extends; $this->defining_class = $defining_class; $this->extra_types = $extra_types; parent::__construct($from_docblock); } /** * @return static */ public function replaceAs(Union $as) : self { if ($as === $this->as) { return $this; } $cloned = clone $this; $cloned->as = $as; return $cloned; } public function getKey(bool $include_extra = \true) : string { if ($include_extra && $this->extra_types) { return $this->param_name . ':' . $this->defining_class . '&' . implode('&', $this->extra_types); } return $this->param_name . ':' . $this->defining_class; } public function getAssertionString() : string { return $this->as->getId(); } public function getId(bool $exact = \true, bool $nested = \false) : string { if (!$exact) { return $this->param_name; } if ($this->extra_types) { return '(' . $this->param_name . ':' . $this->defining_class . ' as ' . $this->as->getId($exact) . ')&' . implode('&', array_map(static fn(Atomic $type): string => $type->getId($exact, \true), $this->extra_types)); } return ($nested ? '(' : '') . $this->param_name . ':' . $this->defining_class . ' as ' . $this->as->getId($exact) . ($nested ? ')' : ''); } /** * @param array $aliased_classes * @return null */ public function toPhpString(?string $namespace, array $aliased_classes, ?string $this_class, int $analysis_php_version_id) : ?string { return null; } /** * @param array $aliased_classes */ public function toNamespacedString(?string $namespace, array $aliased_classes, ?string $this_class, bool $use_phpdoc_format) : string { if ($use_phpdoc_format) { return $this->as->toNamespacedString($namespace, $aliased_classes, $this_class, \true); } $intersection_types = $this->getNamespacedIntersectionTypes($namespace, $aliased_classes, $this_class, \false); return $this->param_name . $intersection_types; } protected function getChildNodeKeys() : array { return ['as', 'extra_types']; } public function canBeFullyExpressedInPhp(int $analysis_php_version_id) : bool { return \false; } /** * @return static */ public function replaceTemplateTypesWithArgTypes(TemplateResult $template_result, ?Codebase $codebase) : self { $intersection = $this->replaceIntersectionTemplateTypesWithArgTypes($template_result, $codebase); if (!$intersection) { return $this; } $cloned = clone $this; $cloned->extra_types = $intersection; return $cloned; } } $aliased_classes */ public function toPhpString(?string $namespace, array $aliased_classes, ?string $this_class, int $analysis_php_version_id) : ?string { return $analysis_php_version_id >= 70000 ? 'string' : null; } public function getKey(bool $include_extra = \true) : string { return 'string'; } } min_bound = $min_bound; $this->max_bound = $max_bound; $this->dependent_list_key = $dependent_list_key; parent::__construct($from_docblock); } public function getKey(bool $include_extra = \true) : string { return 'int<' . ($this->min_bound ?? 'min') . ', ' . ($this->max_bound ?? 'max') . '>'; } public function canBeFullyExpressedInPhp(int $analysis_php_version_id) : bool { return \false; } /** * @param array $aliased_classes */ public function toNamespacedString(?string $namespace, array $aliased_classes, ?string $this_class, bool $use_phpdoc_format) : string { return $use_phpdoc_format ? 'int' : 'int<' . ($this->min_bound ?? 'min') . ', ' . ($this->max_bound ?? 'max') . '>'; } public function isPositive() : bool { return $this->min_bound !== null && $this->min_bound > 0; } public function isNegative() : bool { return $this->max_bound !== null && $this->max_bound < 0; } public function isPositiveOrZero() : bool { return $this->min_bound !== null && $this->min_bound >= 0; } public function isNegativeOrZero() : bool { return $this->max_bound !== null && $this->max_bound <= 0; } public function contains(int $i) : bool { return $this->min_bound === null && $this->max_bound === null || $this->min_bound === null && $this->max_bound >= $i || $this->max_bound === null && $this->min_bound <= $i || $this->min_bound <= $i && $this->max_bound >= $i; } /** * Returns true if every part of the Range is lesser than the given value */ public function isLesserThan(int $i) : bool { return $this->max_bound !== null && $this->max_bound < $i; } /** * Returns true if every part of the Range is greater than the given value */ public function isGreaterThan(int $i) : bool { return $this->min_bound !== null && $this->min_bound > $i; } public static function getNewLowestBound(?int $bound1, ?int $bound2) : ?int { if ($bound1 === null || $bound2 === null) { return null; } return min($bound1, $bound2); } public static function getNewHighestBound(?int $bound1, ?int $bound2) : ?int { if ($bound1 === null || $bound2 === null) { return null; } return max($bound1, $bound2); } /** * convert any int to its equivalent in int range */ public static function convertToIntRange(\Psalm\Type\Atomic\TInt $int_atomic) : \Psalm\Type\Atomic\TIntRange { if ($int_atomic instanceof \Psalm\Type\Atomic\TIntRange) { return $int_atomic; } if ($int_atomic instanceof \Psalm\Type\Atomic\TLiteralInt) { return new \Psalm\Type\Atomic\TIntRange($int_atomic->value, $int_atomic->value); } return new \Psalm\Type\Atomic\TIntRange(null, null); } public static function intersectIntRanges(\Psalm\Type\Atomic\TIntRange $int_range1, \Psalm\Type\Atomic\TIntRange $int_range2) : ?\Psalm\Type\Atomic\TIntRange { if ($int_range1->min_bound === null || $int_range2->min_bound === null) { $new_min_bound = $int_range1->min_bound ?? $int_range2->min_bound; } else { $new_min_bound = self::getNewHighestBound($int_range1->min_bound, $int_range2->min_bound); } if ($int_range1->max_bound === null || $int_range2->max_bound === null) { $new_max_bound = $int_range1->max_bound ?? $int_range2->max_bound; } else { $new_max_bound = self::getNewLowestBound($int_range1->max_bound, $int_range2->max_bound); } if ($new_min_bound !== null && $new_max_bound !== null && $new_min_bound > $new_max_bound) { return null; } return new self($new_min_bound, $new_max_bound); } } |null */ public $params = []; /** * @var Union|null */ public $return_type; /** * @var ?bool */ public $is_pure; /** * Constructs a new instance of a generic type * * @param list $params * @deprecated */ public function __construct(string $value = 'callable', ?array $params = null, ?Union $return_type = null, ?bool $is_pure = null, bool $from_docblock = \false) { $this->value = $value; $this->params = $params; $this->return_type = $return_type; $this->is_pure = $is_pure; $this->from_docblock = $from_docblock; } /** * @param list|null $params * @return static */ public function replace(?array $params, ?Union $return_type) : self { if ($this->params === $params && $this->return_type === $return_type) { return $this; } $cloned = clone $this; $cloned->params = $params; $cloned->return_type = $return_type; return $cloned; } /** @return static */ public function setIsPure(bool $is_pure) : self { if ($this->is_pure === $is_pure) { return $this; } $cloned = clone $this; $cloned->is_pure = $is_pure; return $cloned; } public function getParamString() : string { $param_string = ''; if ($this->params !== null) { $param_string .= '('; foreach ($this->params as $i => $param) { if ($i) { $param_string .= ', '; } $param_string .= $param->getId(); } $param_string .= ')'; } return $param_string; } public function getReturnTypeString() : string { $return_type_string = ''; if ($this->return_type !== null) { $return_type_multiple = count($this->return_type->getAtomicTypes()) > 1; $return_type_string = ':' . ($return_type_multiple ? '(' : '') . $this->return_type->getId() . ($return_type_multiple ? ')' : ''); } return $return_type_string; } public function getKey(bool $include_extra = \true) : string { $param_string = $this->getParamString(); $return_type_string = $this->getReturnTypeString(); return ($this->is_pure ? 'pure-' : ($this->is_pure === null ? '' : 'impure-')) . $this->value . $param_string . $return_type_string; } /** * @param array $aliased_classes */ public function toNamespacedString(?string $namespace, array $aliased_classes, ?string $this_class, bool $use_phpdoc_format) : string { if ($use_phpdoc_format) { if ($this instanceof \Psalm\Type\Atomic\TNamedObject) { return parent::toNamespacedString($namespace, $aliased_classes, $this_class, \true); } return $this->value; } $param_string = ''; $return_type_string = ''; if ($this->params !== null) { $params_array = []; foreach ($this->params as $param) { if (!$param->type) { $type_string = 'mixed'; } else { $type_string = $param->type->toNamespacedString($namespace, $aliased_classes, $this_class, \false); } $params_array[] = ($param->is_variadic ? '...' : '') . $type_string . ($param->is_optional ? '=' : ''); } $param_string = '(' . implode(', ', $params_array) . ')'; } if ($this->return_type !== null) { $return_type_multiple = count($this->return_type->getAtomicTypes()) > 1; $return_type_string = ':' . ($return_type_multiple ? '(' : '') . $this->return_type->toNamespacedString($namespace, $aliased_classes, $this_class, \false) . ($return_type_multiple ? ')' : ''); } if ($this instanceof \Psalm\Type\Atomic\TNamedObject) { return parent::toNamespacedString($namespace, $aliased_classes, $this_class, \true) . $param_string . $return_type_string; } return ($this->is_pure ? 'pure-' : '') . 'callable' . $param_string . $return_type_string; } /** * @param array $aliased_classes */ public function toPhpString(?string $namespace, array $aliased_classes, ?string $this_class, int $analysis_php_version_id) : string { if ($this instanceof \Psalm\Type\Atomic\TNamedObject) { return parent::toNamespacedString($namespace, $aliased_classes, $this_class, \true); } return $this->value; } public function getId(bool $exact = \true, bool $nested = \false) : string { $param_string = ''; $return_type_string = ''; if ($this->params !== null) { $param_string .= '('; foreach ($this->params as $i => $param) { if ($i) { $param_string .= ', '; } $param_string .= $param->getId(); } $param_string .= ')'; } if ($this->return_type !== null) { $return_type_multiple = count($this->return_type->getAtomicTypes()) > 1; $return_type_string = ':' . ($return_type_multiple ? '(' : '') . $this->return_type->getId($exact) . ($return_type_multiple ? ')' : ''); } return ($this->is_pure ? 'pure-' : ($this->is_pure === null ? '' : 'impure-')) . $this->value . $param_string . $return_type_string; } /** * @return array{list|null, Union|null}|null */ protected function replaceCallableTemplateTypesWithStandins(TemplateResult $template_result, Codebase $codebase, ?StatementsAnalyzer $statements_analyzer = null, ?Atomic $input_type = null, ?int $input_arg_offset = null, ?string $calling_class = null, ?string $calling_function = null, bool $replace = \true, bool $add_lower_bound = \false, int $depth = 0) : ?array { $replaced = \false; $params = $this->params; if ($params) { foreach ($params as $offset => $param) { if (!$param->type) { continue; } $input_param_type = null; if (($input_type instanceof \Psalm\Type\Atomic\TClosure || $input_type instanceof \Psalm\Type\Atomic\TCallable) && isset($input_type->params[$offset])) { $input_param_type = $input_type->params[$offset]->type; } $new_param = $param->setType(TemplateStandinTypeReplacer::replace($param->type, $template_result, $codebase, $statements_analyzer, $input_param_type, $input_arg_offset, $calling_class, $calling_function, $replace, !$add_lower_bound, null, $depth)); $replaced = $replaced || $new_param !== $param; $params[$offset] = $new_param; } } $return_type = $this->return_type; if ($return_type) { $return_type = TemplateStandinTypeReplacer::replace($return_type, $template_result, $codebase, $statements_analyzer, $input_type instanceof \Psalm\Type\Atomic\TCallable || $input_type instanceof \Psalm\Type\Atomic\TClosure ? $input_type->return_type : null, $input_arg_offset, $calling_class, $calling_function, $replace, $add_lower_bound); $replaced = $replaced || $this->return_type !== $return_type; } if ($replaced) { return [$params, $return_type]; } return null; } /** * @return array{list|null, Union|null}|null */ protected function replaceCallableTemplateTypesWithArgTypes(TemplateResult $template_result, ?Codebase $codebase) : ?array { $replaced = \false; $params = $this->params; if ($params) { foreach ($params as $k => $param) { if ($param->type) { $new_param = $param->setType(TemplateInferredTypeReplacer::replace($param->type, $template_result, $codebase)); $replaced = $replaced || $new_param !== $param; $params[$k] = $new_param; } } } $return_type = $this->return_type; if ($return_type) { $return_type = TemplateInferredTypeReplacer::replace($return_type, $template_result, $codebase); $replaced = $replaced || $return_type !== $this->return_type; } if ($replaced) { return [$params, $return_type]; } return null; } /** * @return list */ protected function getCallableChildNodeKeys() : array { return ['params', 'return_type']; } } ` corresponds to `0|1|2|3|4|5|6|7` * * @psalm-immutable */ final class TIntMask extends \Psalm\Type\Atomic\TInt { /** @var non-empty-array */ public $values; /** @param non-empty-array $values */ public function __construct(array $values, bool $from_docblock = \false) { $this->values = $values; parent::__construct($from_docblock); } public function getKey(bool $include_extra = \true) : string { $s = ''; foreach ($this->values as $value) { $s .= $value->getKey() . ', '; } return 'int-mask<' . substr($s, 0, -2) . '>'; } public function getId(bool $exact = \true, bool $nested = \false) : string { $s = ''; foreach ($this->values as $value) { $s .= $value->getId($exact) . ', '; } return 'int-mask<' . substr($s, 0, -2) . '>'; } /** * @param array $aliased_classes */ public function toNamespacedString(?string $namespace, array $aliased_classes, ?string $this_class, bool $use_phpdoc_format) : string { if ($use_phpdoc_format) { return 'int'; } $s = ''; foreach ($this->values as $value) { $s .= $value->toNamespacedString($namespace, $aliased_classes, $this_class, \false) . ', '; } return 'int-mask<' . substr($s, 0, -2) . '>'; } public function canBeFullyExpressedInPhp(int $analysis_php_version_id) : bool { return \false; } } type_param = $type_param; parent::__construct($from_docblock); } /** * @return static */ public function setTypeParam(Union $type_param) : self { if ($type_param === $this->type_param) { return $this; } $cloned = clone $this; $cloned->type_param = $type_param; return $cloned; } public function getKeyedArray() : \Psalm\Type\Atomic\TKeyedArray { return Type::getListAtomic($this->type_param); } public function getId(bool $exact = \true, bool $nested = \false) : string { return static::KEY . '<' . $this->type_param->getId($exact) . '>'; } /** * @param array $aliased_classes */ public function toNamespacedString(?string $namespace, array $aliased_classes, ?string $this_class, bool $use_phpdoc_format) : string { if ($use_phpdoc_format) { return (new \Psalm\Type\Atomic\TArray([Type::getInt(), $this->type_param]))->toNamespacedString($namespace, $aliased_classes, $this_class, \true); } return static::KEY . '<' . $this->type_param->toNamespacedString($namespace, $aliased_classes, $this_class, \false) . '>'; } /** * @param array $aliased_classes */ public function toPhpString(?string $namespace, array $aliased_classes, ?string $this_class, int $analysis_php_version_id) : string { return 'array'; } public function canBeFullyExpressedInPhp(int $analysis_php_version_id) : bool { return \false; } public function getKey(bool $include_extra = \true) : string { return 'array'; } /** * @psalm-suppress InaccessibleProperty We're only acting on cloned instances * @return static */ public function replaceTemplateTypesWithStandins(TemplateResult $template_result, Codebase $codebase, ?StatementsAnalyzer $statements_analyzer = null, ?Atomic $input_type = null, ?int $input_arg_offset = null, ?string $calling_class = null, ?string $calling_function = null, bool $replace = \true, bool $add_lower_bound = \false, int $depth = 0) : self { $cloned = null; foreach ([Type::getInt(), $this->type_param] as $offset => $type_param) { $input_type_param = null; if (($input_type instanceof \Psalm\Type\Atomic\TGenericObject || $input_type instanceof \Psalm\Type\Atomic\TIterable || $input_type instanceof \Psalm\Type\Atomic\TArray) && isset($input_type->type_params[$offset])) { $input_type_param = $input_type->type_params[$offset]; } elseif ($input_type instanceof \Psalm\Type\Atomic\TKeyedArray) { if ($offset === 0) { $input_type_param = $input_type->getGenericKeyType(); } else { $input_type_param = $input_type->getGenericValueType(); } } elseif ($input_type instanceof \Psalm\Type\Atomic\TList) { if ($offset === 0) { continue; } $input_type_param = $input_type->type_param; } $type_param = TemplateStandinTypeReplacer::replace($type_param, $template_result, $codebase, $statements_analyzer, $input_type_param, $input_arg_offset, $calling_class, $calling_function, $replace, $add_lower_bound, null, $depth + 1); if ($offset === 1 && ($cloned || $this->type_param !== $type_param)) { $cloned ??= clone $this; $cloned->type_param = $type_param; } } return $cloned ?? $this; } /** * @return static */ public function replaceTemplateTypesWithArgTypes(TemplateResult $template_result, ?Codebase $codebase) : self { return $this->setTypeParam(TemplateInferredTypeReplacer::replace($this->type_param, $template_result, $codebase)); } public function equals(Atomic $other_type, bool $ensure_source_equality) : bool { if (get_class($other_type) !== static::class) { return \false; } if (!$this->type_param->equals($other_type->type_param, $ensure_source_equality, \false)) { return \false; } return \true; } public function getAssertionString() : string { if ($this->type_param->isMixed()) { return 'list'; } return $this->getId(); } protected function getChildNodeKeys() : array { return ['type_param']; } } $aliased_classes */ public function toPhpString(?string $namespace, array $aliased_classes, ?string $this_class, int $analysis_php_version_id) : ?string { return null; } public function canBeFullyExpressedInPhp(int $analysis_php_version_id) : bool { return \false; } } count = $count; $this->min_count = $min_count; /** @psalm-suppress DeprecatedClass */ parent::__construct($type_param, $from_docblock); } public function getKeyedArray() : \Psalm\Type\Atomic\TKeyedArray { if (!$this->count && !$this->min_count) { return Type::getNonEmptyListAtomic($this->type_param); } if ($this->count) { return new \Psalm\Type\Atomic\TKeyedArray(array_fill(0, $this->count, $this->type_param), null, null, \true, $this->from_docblock); } return new \Psalm\Type\Atomic\TKeyedArray(array_fill(0, $this->min_count, $this->type_param), null, [Type::getListKey(), $this->type_param], \true, $this->from_docblock); } /** * @param positive-int|null $count * @return static */ public function setCount(?int $count) : self { if ($count === $this->count) { return $this; } $cloned = clone $this; $cloned->count = $count; return $cloned; } public function getAssertionString() : string { return 'non-empty-list'; } } $params */ public function __construct(string $value = 'callable', ?array $params = null, ?Union $return_type = null, ?bool $is_pure = null, bool $from_docblock = \false) { $this->value = $value; $this->params = $params; $this->return_type = $return_type; $this->is_pure = $is_pure; parent::__construct($from_docblock); } /** * @param array $aliased_classes */ public function toPhpString(?string $namespace, array $aliased_classes, ?string $this_class, int $analysis_php_version_id) : string { return 'callable'; } public function canBeFullyExpressedInPhp(int $analysis_php_version_id) : bool { return $this->params === null && $this->return_type === null; } /** * @return static */ public function replaceTemplateTypesWithArgTypes(TemplateResult $template_result, ?Codebase $codebase) : self { $replaced = $this->replaceCallableTemplateTypesWithArgTypes($template_result, $codebase); if (!$replaced) { return $this; } return new static($this->value, $replaced[0], $replaced[1], $this->is_pure); } /** * @return static */ public function replaceTemplateTypesWithStandins(TemplateResult $template_result, Codebase $codebase, ?StatementsAnalyzer $statements_analyzer = null, ?Atomic $input_type = null, ?int $input_arg_offset = null, ?string $calling_class = null, ?string $calling_function = null, bool $replace = \true, bool $add_lower_bound = \false, int $depth = 0) : self { $replaced = $this->replaceCallableTemplateTypesWithStandins($template_result, $codebase, $statements_analyzer, $input_type, $input_arg_offset, $calling_class, $calling_function, $replace, $add_lower_bound, $depth); if (!$replaced) { return $this; } return new static($this->value, $replaced[0], $replaced[1], $this->is_pure); } protected function getChildNodeKeys() : array { return $this->getCallableChildNodeKeys(); } } $aliased_classes */ public function toPhpString(?string $namespace, array $aliased_classes, ?string $this_class, int $analysis_php_version_id) : ?string { return 'string'; } /** * @param array $aliased_classes */ public function toNamespacedString(?string $namespace, array $aliased_classes, ?string $this_class, bool $use_phpdoc_format) : string { return 'trait-string'; } public function canBeFullyExpressedInPhp(int $analysis_php_version_id) : bool { return \false; } } ` * * @psalm-immutable */ final class TGenericObject extends \Psalm\Type\Atomic\TNamedObject { /** * @use GenericTrait> */ use \Psalm\Type\Atomic\GenericTrait; /** * @var non-empty-list */ public array $type_params; /** @var bool if the parameters have been remapped to another class */ public $remapped_params = \false; /** * @param string $value the name of the object * @param non-empty-list $type_params * @param array $extra_types */ public function __construct(string $value, array $type_params, bool $remapped_params = \false, bool $is_static = \false, array $extra_types = [], bool $from_docblock = \false) { if ($value[0] === '\\') { $value = substr($value, 1); } $this->type_params = $type_params; $this->remapped_params = $remapped_params; parent::__construct($value, $is_static, \false, $extra_types, $from_docblock); } public function getKey(bool $include_extra = \true) : string { $s = ''; foreach ($this->type_params as $type_param) { $s .= $type_param->getKey() . ', '; } $extra_types = ''; if ($include_extra && $this->extra_types) { $extra_types = '&' . implode('&', $this->extra_types); } return $this->value . '<' . substr($s, 0, -2) . '>' . $extra_types; } public function canBeFullyExpressedInPhp(int $analysis_php_version_id) : bool { return \false; } /** * @param array $aliased_classes */ public function toPhpString(?string $namespace, array $aliased_classes, ?string $this_class, int $analysis_php_version_id) : ?string { $result = $this->toNamespacedString($namespace, $aliased_classes, $this_class, \true); $intersection = strrpos($result, '&'); if ($intersection === \false || $analysis_php_version_id >= 80100) { return $result; } return substr($result, $intersection + 1); } public function equals(Atomic $other_type, bool $ensure_source_equality) : bool { if (!$other_type instanceof self) { return \false; } if (count($this->type_params) !== count($other_type->type_params)) { return \false; } foreach ($this->type_params as $i => $type_param) { if (!$type_param->equals($other_type->type_params[$i], $ensure_source_equality, \false)) { return \false; } } return \true; } public function getAssertionString() : string { return $this->value; } protected function getChildNodeKeys() : array { return [...parent::getChildNodeKeys(), 'type_params']; } /** * @return static */ public function replaceTemplateTypesWithStandins(TemplateResult $template_result, Codebase $codebase, ?StatementsAnalyzer $statements_analyzer = null, ?Atomic $input_type = null, ?int $input_arg_offset = null, ?string $calling_class = null, ?string $calling_function = null, bool $replace = \true, bool $add_lower_bound = \false, int $depth = 0) : self { $types = $this->replaceTypeParamsTemplateTypesWithStandins($template_result, $codebase, $statements_analyzer, $input_type, $input_arg_offset, $calling_class, $calling_function, $replace, $add_lower_bound, $depth); $intersection = $this->replaceIntersectionTemplateTypesWithStandins($template_result, $codebase, $statements_analyzer, $input_type, $input_arg_offset, $calling_class, $calling_function, $replace, $add_lower_bound, $depth); if (!$types && !$intersection) { return $this; } return new static($this->value, $types ?? $this->type_params, $this->remapped_params, $this->is_static, $intersection ?? $this->extra_types); } /** * @return static */ public function replaceTemplateTypesWithArgTypes(TemplateResult $template_result, ?Codebase $codebase) : self { $type_params = $this->replaceTypeParamsTemplateTypesWithArgTypes($template_result, $codebase); $intersection = $this->replaceIntersectionTemplateTypesWithArgTypes($template_result, $codebase); if (!$type_params && !$intersection) { return $this; } return new static($this->value, $type_params ?? $this->type_params, \true, $this->is_static, $intersection ?? $this->extra_types); } } */ public $properties; /** * @var array|null */ public $class_strings; /** * If the shape has fallback params then they are here * * @var array{Union, Union}|null */ public $fallback_params; /** * @var bool - if this is a list of sequential elements */ public $is_list = \false; /** @var non-empty-lowercase-string */ protected const NAME_ARRAY = 'array'; /** @var non-empty-lowercase-string */ protected const NAME_LIST = 'list'; /** * Constructs a new instance of a generic type * * @param non-empty-array $properties * @param array{Union, Union}|null $fallback_params * @param array $class_strings */ public function __construct(array $properties, ?array $class_strings = null, ?array $fallback_params = null, bool $is_list = \false, bool $from_docblock = \false) { if ($is_list && $fallback_params) { $fallback_params[0] = Type::getListKey(); } $this->properties = $properties; $this->class_strings = $class_strings; $this->fallback_params = $fallback_params; $this->is_list = $is_list; if ($this->is_list) { $last_k = -1; $had_possibly_undefined = \false; ksort($this->properties); foreach ($this->properties as $k => $v) { if (is_string($k) || $last_k !== $k - 1 || $had_possibly_undefined && !$v->possibly_undefined) { $this->is_list = \false; break; } if ($v->possibly_undefined) { $had_possibly_undefined = \true; } $last_k = $k; } } parent::__construct($from_docblock); } /** * @param non-empty-array $properties * @return static */ public function setProperties(array $properties) : self { if ($properties === $this->properties) { return $this; } $cloned = clone $this; $cloned->properties = $properties; if ($cloned->is_list) { $last_k = -1; $had_possibly_undefined = \false; /** @psalm-suppress InaccessibleProperty */ ksort($cloned->properties); foreach ($cloned->properties as $k => $v) { if (is_string($k) || $last_k !== $k - 1 || $had_possibly_undefined && !$v->possibly_undefined) { $cloned->is_list = \false; break; } if ($v->possibly_undefined) { $had_possibly_undefined = \true; } $last_k = $k; } } return $cloned; } /** * @return static */ public function makeSealed() : self { if ($this->fallback_params === null) { return $this; } $cloned = clone $this; $cloned->fallback_params = null; return $cloned; } public function isSealed() : bool { return $this->fallback_params === null; } /** * @psalm-assert-if-true list{Union} $this->properties * @psalm-assert-if-true list{Union, Union} $this->fallback_params */ public function isGenericList() : bool { return $this->is_list && count($this->properties) === 1 && $this->fallback_params && $this->properties[0]->equals($this->fallback_params[1], \true, \true, \false); } public function getId(bool $exact = \true, bool $nested = \false) : string { $property_strings = []; if ($this->is_list) { if ($this->isGenericList()) { $t = $this->properties[0]->possibly_undefined ? 'list' : 'non-empty-list'; return "{$t}<" . $this->fallback_params[1]->getId($exact) . '>'; } $use_list_syntax = \true; foreach ($this->properties as $property) { if ($property->possibly_undefined) { $use_list_syntax = \false; break; } } } else { $use_list_syntax = \false; } foreach ($this->properties as $name => $type) { if ($use_list_syntax) { $property_strings[$name] = $type->getId($exact); continue; } $class_string_suffix = ''; if (isset($this->class_strings[$name])) { $class_string_suffix = '::class'; } $name = $this->escapeAndQuote($name); $property_strings[$name] = $name . $class_string_suffix . ($type->possibly_undefined ? '?' : '') . ': ' . $type->getId($exact); } if ($this->is_list) { $key = static::NAME_LIST; } else { $key = static::NAME_ARRAY; sort($property_strings); } $params_part = $this->fallback_params !== null ? ', ...<' . ($this->is_list ? $this->fallback_params[1]->getId($exact) : $this->fallback_params[0]->getId($exact) . ', ' . $this->fallback_params[1]->getId($exact)) . '>' : ''; return $key . '{' . implode(', ', $property_strings) . $params_part . '}'; } /** * @param array $aliased_classes */ public function toNamespacedString(?string $namespace, array $aliased_classes, ?string $this_class, bool $use_phpdoc_format) : string { if ($use_phpdoc_format) { return $this->getGenericArrayType()->toNamespacedString($namespace, $aliased_classes, $this_class, \true); } $suffixed_properties = []; if ($this->is_list) { if (count($this->properties) === 1 && $this->fallback_params && $this->properties[0]->equals($this->fallback_params[1], \true, \true, \false)) { $t = $this->properties[0]->possibly_undefined ? 'list' : 'non-empty-list'; return "{$t}<" . $this->fallback_params[1]->getId() . '>'; } $use_list_syntax = \true; foreach ($this->properties as $property) { if ($property->possibly_undefined) { $use_list_syntax = \false; break; } } } else { $use_list_syntax = \false; } foreach ($this->properties as $name => $type) { if ($use_list_syntax) { $suffixed_properties[$name] = $type->toNamespacedString($namespace, $aliased_classes, $this_class, \false); continue; } $class_string_suffix = ''; if (isset($this->class_strings[$name])) { $class_string_suffix = '::class'; } $name = $this->escapeAndQuote($name); $suffixed_properties[$name] = $name . $class_string_suffix . ($type->possibly_undefined ? '?' : '') . ': ' . $type->toNamespacedString($namespace, $aliased_classes, $this_class, \false); } $params_part = $this->fallback_params !== null ? ',...' : ''; return ($this->is_list ? static::NAME_LIST : static::NAME_ARRAY) . '{' . implode(', ', $suffixed_properties) . $params_part . '}'; } /** * @param array $aliased_classes */ public function toPhpString(?string $namespace, array $aliased_classes, ?string $this_class, int $analysis_php_version_id) : string { return 'array'; } public function canBeFullyExpressedInPhp(int $analysis_php_version_id) : bool { return \false; } public function getGenericKeyType(bool $possibly_undefined = \false) : Union { if ($this->is_list) { if ($this->fallback_params) { return Type::getListKey(); } if (count($this->properties) === 1) { return new Union([new \Psalm\Type\Atomic\TLiteralInt(0)]); } return Type::getIntRange(0, count($this->properties) - 1); } $key_types = []; foreach ($this->properties as $key => $_) { if (is_int($key)) { $key_types[] = new \Psalm\Type\Atomic\TLiteralInt($key); } elseif (isset($this->class_strings[$key])) { $key_types[] = new \Psalm\Type\Atomic\TLiteralClassString($key); } else { /** @psalm-suppress ImpureMethodCall let's assume string interpreters are pure */ $key_types[] = Type::getAtomicStringFromLiteral($key); } } $key_type = TypeCombiner::combine($key_types); /** @psalm-suppress InaccessibleProperty We just created this type */ $key_type->possibly_undefined = $possibly_undefined; if ($this->fallback_params === null) { return $key_type; } return Type::combineUnionTypes($this->fallback_params[0], $key_type); } public function getGenericValueType(bool $possibly_undefined = \false) : Union { $value_type = null; foreach ($this->properties as $property) { $value_type = Type::combineUnionTypes($property, $value_type); } return Type::combineUnionTypes($this->fallback_params[1] ?? null, $value_type, null, \false, \true, 500, $possibly_undefined); } /** * @return TArray|TNonEmptyArray */ public function getGenericArrayType(bool $allow_non_empty = \true, ?string $list_var_id = null) : \Psalm\Type\Atomic\TArray { $key_types = []; $value_type = null; $has_defined_keys = \false; foreach ($this->properties as $key => $property) { if ($this->is_list) { // Do nothing } elseif (is_int($key)) { $key_types[] = new \Psalm\Type\Atomic\TLiteralInt($key); } elseif (isset($this->class_strings[$key])) { $key_types[] = new \Psalm\Type\Atomic\TLiteralClassString($key); } else { /** @psalm-suppress ImpureMethodCall let's assume string interpreters are pure */ $key_types[] = Type::getAtomicStringFromLiteral($key); } $value_type = Type::combineUnionTypes($property, $value_type); if (!$property->possibly_undefined) { $has_defined_keys = \true; } } if ($this->is_list) { if ($this->fallback_params !== null) { $value_type = Type::combineUnionTypes($this->fallback_params[1], $value_type); } $value_type = $value_type->setPossiblyUndefined(\false); if ($this->fallback_params === null) { $key_type = new Union([new \Psalm\Type\Atomic\TIntRange(0, count($this->properties) - 1, \false, $list_var_id)]); } else { $key_type = new Union([new \Psalm\Type\Atomic\TIntRange(0, null, \false, $list_var_id)]); } if ($has_defined_keys && $allow_non_empty) { return new \Psalm\Type\Atomic\TNonEmptyArray([$key_type, $value_type]); } return new \Psalm\Type\Atomic\TArray([$key_type, $value_type]); } assert($key_types !== []); $key_type = TypeCombiner::combine($key_types); if ($this->fallback_params !== null) { $key_type = Type::combineUnionTypes($this->fallback_params[0], $key_type); $value_type = Type::combineUnionTypes($this->fallback_params[1], $value_type); } $value_type = $value_type->setPossiblyUndefined(\false); if ($allow_non_empty && ($has_defined_keys || $this->fallback_params !== null)) { return new \Psalm\Type\Atomic\TNonEmptyArray([$key_type, $value_type]); } return new \Psalm\Type\Atomic\TArray([$key_type, $value_type]); } public function isNonEmpty() : bool { if ($this->isGenericList()) { return !$this->properties[0]->possibly_undefined; } foreach ($this->properties as $property) { if (!$property->possibly_undefined) { return \true; } } return \false; } /** * @return int<0, max> */ public function getMinCount() : int { if ($this->is_list) { foreach ($this->properties as $k => $property) { if ($property->possibly_undefined || $property->isNever()) { /** @var int<0, max> */ return $k; } } return count($this->properties); } $prop_min_count = 0; foreach ($this->properties as $property) { if (!($property->possibly_undefined || $property->isNever())) { $prop_min_count++; } } return $prop_min_count; } /** * Returns null if there is no upper limit. * * @return int<1, max>|null */ public function getMaxCount() : ?int { if ($this->fallback_params) { return null; } $prop_max_count = 0; foreach ($this->properties as $property) { if (!$property->isNever()) { $prop_max_count++; } } assert($prop_max_count !== 0); return $prop_max_count; } /** * Whether all keys are always defined (ignores unsealedness). */ public function allShapeKeysAlwaysDefined() : bool { foreach ($this->properties as $property) { if ($property->possibly_undefined) { return \false; } } return \true; } public function getKey(bool $include_extra = \true) : string { return 'array'; } /** * @return static */ public function replaceTemplateTypesWithStandins(TemplateResult $template_result, Codebase $codebase, ?StatementsAnalyzer $statements_analyzer = null, ?Atomic $input_type = null, ?int $input_arg_offset = null, ?string $calling_class = null, ?string $calling_function = null, bool $replace = \true, bool $add_lower_bound = \false, int $depth = 0) : self { if ($input_type instanceof \Psalm\Type\Atomic\TKeyedArray && $input_type->is_list && $input_type->isSealed() && $this->isGenericList()) { $replaced_list_type = $this->getGenericArrayType()->replaceTemplateTypesWithStandins($template_result, $codebase, $statements_analyzer, $input_type->getGenericArrayType(), $input_arg_offset, $calling_class, $calling_function, $replace, $add_lower_bound, $depth)->type_params[1]->setPossiblyUndefined(!$this->isNonEmpty()); $cloned = clone $this; $cloned->properties = [$replaced_list_type]; $cloned->fallback_params = [$this->fallback_params[1], $replaced_list_type]; return $cloned; } $properties = $this->properties; foreach ($properties as $offset => $property) { $input_type_param = null; if ($input_type instanceof \Psalm\Type\Atomic\TKeyedArray && isset($input_type->properties[$offset])) { $input_type_param = $input_type->properties[$offset]; } $properties[$offset] = TemplateStandinTypeReplacer::replace($property, $template_result, $codebase, $statements_analyzer, $input_type_param, $input_arg_offset, $calling_class, $calling_function, $replace, $add_lower_bound, null, $depth); } $fallback_params = $this->fallback_params; foreach ($fallback_params ?? [] as $offset => $property) { $input_type_param = null; if ($input_type instanceof \Psalm\Type\Atomic\TKeyedArray && isset($input_type->fallback_params[$offset])) { $input_type_param = $input_type->fallback_params[$offset]; } $fallback_params[$offset] = TemplateStandinTypeReplacer::replace($property, $template_result, $codebase, $statements_analyzer, $input_type_param, $input_arg_offset, $calling_class, $calling_function, $replace, $add_lower_bound, null, $depth); } if ($properties === $this->properties && $fallback_params === $this->fallback_params) { return $this; } $cloned = clone $this; $cloned->properties = $properties; /** @psalm-suppress PropertyTypeCoercion */ $cloned->fallback_params = $fallback_params; return $cloned; } /** * @return static */ public function replaceTemplateTypesWithArgTypes(TemplateResult $template_result, ?Codebase $codebase) : self { $properties = $this->properties; foreach ($properties as $offset => $property) { $properties[$offset] = TemplateInferredTypeReplacer::replace($property, $template_result, $codebase); } $fallback_params = $this->fallback_params; foreach ($fallback_params ?? [] as $offset => $property) { $fallback_params[$offset] = TemplateInferredTypeReplacer::replace($property, $template_result, $codebase); } if ($properties !== $this->properties || $fallback_params !== $this->fallback_params) { $cloned = clone $this; $cloned->properties = $properties; /** @psalm-suppress PropertyTypeCoercion */ $cloned->fallback_params = $fallback_params; return $cloned; } return $this; } protected function getChildNodeKeys() : array { return ['properties', 'fallback_params']; } public function equals(Atomic $other_type, bool $ensure_source_equality) : bool { if (get_class($other_type) !== static::class) { return \false; } if (count($this->properties) !== count($other_type->properties)) { return \false; } if (($this->fallback_params === null) !== ($other_type->fallback_params === null)) { return \false; } if ($this->fallback_params !== null && $other_type->fallback_params !== null) { if (!$this->fallback_params[0]->equals($other_type->fallback_params[0], \false, \false)) { return \false; } if (!$this->fallback_params[1]->equals($other_type->fallback_params[1], \false, \false)) { return \false; } } foreach ($this->properties as $property_name => $property_type) { if (!isset($other_type->properties[$property_name])) { return \false; } if (!$property_type->equals($other_type->properties[$property_name], $ensure_source_equality, \false)) { return \false; } } return \true; } public function getAssertionString() : string { return $this->is_list ? 'list' : 'array'; } /** * @deprecated Will be removed in Psalm v6 along with the TList type. */ public function getList() : \Psalm\Type\Atomic\TList { if (!$this->is_list) { throw new UnexpectedValueException('Object-like array must be a list for conversion'); } return $this->isNonEmpty() ? new \Psalm\Type\Atomic\TNonEmptyList($this->getGenericValueType()) : new \Psalm\Type\Atomic\TList($this->getGenericValueType()); } /** * @param string|int $name * @return string|int */ private function escapeAndQuote($name) { if (is_string($name)) { $quote = \false; if ($name === '' || preg_match('/[^a-zA-Z0-9_]/', $name)) { $quote = \true; } if (preg_match('/^-?[1-9][0-9]*$/', $name) && (string) (int) $name !== $name) { $quote = \true; } if (preg_match('/^[1-9][0-9]*_([0-9]+_)*[0-9]+$/', $name)) { $quote = \true; } // 08 should be quoted since it's numeric but it's handled as string and not cast to int if (preg_match('/^0[0-9]+$/', $name)) { $quote = \true; } if (preg_match('/^[0-9]+e-?[0-9]+$/', $name)) { $quote = \true; } if ($quote) { $name = '\'' . str_replace("\n", '\\n', addslashes($name)) . '\''; } } return $name; } } type = $type; parent::__construct($from_docblock); } /** * @param non-empty-array $cases */ private static function getValueTypeForNamedObject(array $cases, \Psalm\Type\Atomic\TNamedObject $atomic_type, Codebase $codebase) : Union { if ($atomic_type instanceof \Psalm\Type\Atomic\TEnumCase) { assert(isset($cases[$atomic_type->case_name]), 'Should\'ve been verified in TValueOf#getValueType'); $value = $cases[$atomic_type->case_name]->getValue($codebase->classlikes); assert($value !== null, 'Backed enum must have a value.'); return new Union([ConstantTypeResolver::getLiteralTypeFromScalarValue($value)]); } return new Union(array_map(static function (EnumCaseStorage $case) use($codebase) : Atomic { $case_value = $case->getValue($codebase->classlikes); assert($case_value !== null); // Backed enum must have a value return ConstantTypeResolver::getLiteralTypeFromScalarValue($case_value); }, array_values($cases))); } protected function getChildNodeKeys() : array { return ['type']; } public function getKey(bool $include_extra = \true) : string { return 'value-of<' . $this->type . '>'; } /** * @param array $aliased_classes */ public function toPhpString(?string $namespace, array $aliased_classes, ?string $this_class, int $analysis_php_version_id) : ?string { return null; } public function canBeFullyExpressedInPhp(int $analysis_php_version_id) : bool { return \false; } public function getAssertionString() : string { return 'mixed'; } public static function isViableTemplateType(Union $template_type) : bool { foreach ($template_type->getAtomicTypes() as $type) { if (!$type instanceof \Psalm\Type\Atomic\TArray && !$type instanceof \Psalm\Type\Atomic\TClassConstant && !$type instanceof \Psalm\Type\Atomic\TKeyedArray && !$type instanceof TList && !$type instanceof \Psalm\Type\Atomic\TPropertiesOf && !$type instanceof \Psalm\Type\Atomic\TNamedObject) { return \false; } } return \true; } public static function getValueType(Union $type, Codebase $codebase, bool $keep_template_params = \false) : ?Union { $value_types = []; foreach ($type->getAtomicTypes() as $atomic_type) { if ($atomic_type instanceof \Psalm\Type\Atomic\TArray) { $value_atomics = $atomic_type->type_params[1]; } elseif ($atomic_type instanceof TList) { $value_atomics = $atomic_type->type_param; } elseif ($atomic_type instanceof \Psalm\Type\Atomic\TKeyedArray) { $value_atomics = $atomic_type->getGenericValueType(); } elseif ($atomic_type instanceof \Psalm\Type\Atomic\TTemplateParam) { if ($keep_template_params) { $value_atomics = new Union([$atomic_type]); } else { $value_atomics = static::getValueType($atomic_type->as, $codebase, $keep_template_params); if ($value_atomics === null) { continue; } } } elseif ($atomic_type instanceof \Psalm\Type\Atomic\TNamedObject && $codebase->classlike_storage_provider->has($atomic_type->value)) { $class_storage = $codebase->classlike_storage_provider->get($atomic_type->value); $cases = $class_storage->enum_cases; if (!$class_storage->is_enum || $class_storage->enum_type === null || $cases === [] || $atomic_type instanceof \Psalm\Type\Atomic\TEnumCase && !isset($cases[$atomic_type->case_name])) { // Invalid value-of, skip continue; } $value_atomics = self::getValueTypeForNamedObject($cases, $atomic_type, $codebase); } else { continue; } $value_types = [...$value_types, ...array_values($value_atomics->getAtomicTypes())]; } if ($value_types === []) { return null; } return new Union($value_types); } } $aliased_classes */ public function toPhpString(?string $namespace, array $aliased_classes, ?string $this_class, int $analysis_php_version_id) : ?string { return $analysis_php_version_id >= 70200 ? $this->getKey() : null; } public function canBeFullyExpressedInPhp(int $analysis_php_version_id) : bool { return \true; } } param_name = $param_name; $this->defining_class = $defining_class; $this->as = $as; $this->visibility_filter = $visibility_filter; parent::__construct($from_docblock); } public function getKey(bool $include_extra = \true) : string { return \Psalm\Type\Atomic\TPropertiesOf::tokenNameForFilter($this->visibility_filter) . '<' . $this->param_name . '>'; } public function getId(bool $exact = \true, bool $nested = \false) : string { if (!$exact) { return $this->getKey(); } return \Psalm\Type\Atomic\TPropertiesOf::tokenNameForFilter($this->visibility_filter) . '<' . $this->as->getId($exact) . '>'; } /** * @param array $aliased_classes */ public function toPhpString(?string $namespace, array $aliased_classes, ?string $this_class, int $analysis_php_version_id) : string { return $this->getKey(); } public function canBeFullyExpressedInPhp(int $analysis_php_version_id) : bool { return \false; } /** * @return static */ public function replaceTemplateTypesWithArgTypes(TemplateResult $template_result, ?Codebase $codebase) : self { $param = new \Psalm\Type\Atomic\TTemplateParam($this->as->param_name, TemplateInferredTypeReplacer::replace(new Union([$this->as]), $template_result, $codebase), $this->as->defining_class); if ($param->as === $this->as->as) { return $this; } return new static($this->param_name, $this->defining_class, $param, $this->visibility_filter); } } $aliased_classes */ public function toPhpString(?string $namespace, array $aliased_classes, ?string $this_class, int $analysis_php_version_id) : ?string { return null; } public function canBeFullyExpressedInPhp(int $analysis_php_version_id) : bool { return \false; } public function getAssertionString() : string { return 'scalar'; } } array_param_name = $array_param_name; $this->offset_param_name = $offset_param_name; $this->defining_class = $defining_class; parent::__construct($from_docblock); } public function getKey(bool $include_extra = \true) : string { return $this->array_param_name . '[' . $this->offset_param_name . ']'; } /** * @param array $aliased_classes */ public function toPhpString(?string $namespace, array $aliased_classes, ?string $this_class, int $analysis_php_version_id) : ?string { return null; } public function canBeFullyExpressedInPhp(int $analysis_php_version_id) : bool { return \false; } } enterNode($node); if ($result === self::DONT_TRAVERSE_CHILDREN) { return \true; } if ($result === self::STOP_TRAVERSAL) { return \false; } return $node::visitMutable($this, $node, $node !== $nodeOrig); } /** * @template T as array * @param T $nodes * @param-out T $nodes */ public function traverseArray(array &$nodes) : void { foreach ($nodes as &$node) { if ($this->traverse($node) === \false) { return; } } unset($node); } } > */ private static array $broken_paths = []; /** * Takes two arrays and consolidates them, removing null values from existing types where applicable. * Returns a tuple of [new_types, new_references]. * * @param array>> $new_types * @param array>> $active_new_types - types we can complain about * @param array $existing_types * @param array $existing_references Maps keys of $existing_types that are references to other * keys of $existing_types that they are references to. * @param array $changed_var_ids * @param array $referenced_var_ids * @param array> $template_type_map * @return array{array, array} * @psalm-suppress ComplexMethod */ public static function reconcileKeyedTypes(array $new_types, array $active_new_types, array $existing_types, array $existing_references, array &$changed_var_ids, array $referenced_var_ids, StatementsAnalyzer $statements_analyzer, array $template_type_map = [], bool $inside_loop = \false, ?CodeLocation $code_location = null, bool $negated = \false) : array { if (!$new_types) { return [$existing_types, $existing_references]; } $reference_graph = []; if (!empty($existing_references)) { // PHP behaves oddly when passing an array containing references: https://bugs.php.net/bug.php?id=20993 // To work around the issue, if there are any references, we have to recreate the array and fix the // references so they're properly scoped and won't affect the caller. Starting with a new array is // required for some unclear reason, just cloning elements of the existing array doesn't work properly. $old_existing_types = $existing_types; $existing_types = []; $cloned_referenceds = []; foreach ($existing_references as $reference => $referenced) { if (!isset($cloned_referenceds[$referenced])) { $existing_types[$referenced] = $old_existing_types[$referenced]; $cloned_referenceds[$referenced] = \true; } $existing_types[$reference] =& $existing_types[$referenced]; } $existing_types += $old_existing_types; // Build a map from reference/referenced variables to other variables with the same reference foreach ($existing_references as $reference => $referenced) { $reference_graph[$reference][$referenced] = \true; foreach ($reference_graph[$referenced] ?? [] as $existing_referenced => $_) { $reference_graph[$existing_referenced][$reference] = \true; $reference_graph[$reference][$existing_referenced] = \true; } $reference_graph[$referenced][$reference] = \true; } } $suppressed_issues = $statements_analyzer->getSuppressedIssues(); $old_new_types = $new_types; $new_types = self::addNestedAssertions($new_types, $existing_types); // make sure array keys come after base keys ksort($new_types); $codebase = $statements_analyzer->getCodebase(); foreach ($new_types as $key => $new_type_parts) { if (strpos($key, '::') && !strpos($key, '$') && !strpos($key, '[')) { continue; } $has_negation = \false; $has_isset = \false; $has_inverted_isset = \false; $has_inverted_key_exists = \false; $has_truthy_or_falsy_or_empty = \false; $has_empty = \false; $has_count_check = \false; $is_real = ($old_new_types[$key] ?? null) === $new_type_parts; $is_equality = $is_real; foreach ($new_type_parts as $new_type_part_parts) { foreach ($new_type_part_parts as $new_type_part_part) { if ($new_type_part_part->isNegation()) { $has_negation = \true; } $has_isset = $has_isset || $new_type_part_part instanceof IsIsset || $new_type_part_part instanceof IsEqualIsset || $new_type_part_part instanceof ArrayKeyExists || $new_type_part_part instanceof HasStringArrayAccess; $has_empty = $has_empty || $new_type_part_part instanceof Empty_; $has_truthy_or_falsy_or_empty = $has_truthy_or_falsy_or_empty || $new_type_part_part instanceof NonEmpty || $new_type_part_part instanceof Truthy || $new_type_part_part instanceof Empty_ || $new_type_part_part instanceof Falsy; $is_equality = $is_equality && $new_type_part_part instanceof IsIdentical; $has_inverted_isset = $has_inverted_isset || $new_type_part_part instanceof IsNotIsset; $has_inverted_key_exists = $has_inverted_key_exists || $new_type_part_part instanceof ArrayKeyDoesNotExist; $has_count_check = $has_count_check || $new_type_part_part instanceof NonEmptyCountable; } } $did_type_exist = isset($existing_types[$key]); $has_object_array_access = \false; $result_type = $existing_types[$key] ?? self::getValueForKey($codebase, $key, $existing_types, $new_types, $code_location, $has_isset, $has_inverted_isset, $has_inverted_key_exists, $has_empty, $inside_loop, $has_object_array_access); if ($result_type && $result_type->isUnionEmpty()) { throw new InvalidArgumentException('Union::$types cannot be empty after get value for ' . $key); } $before_adjustment = $result_type; $failed_reconciliation = self::RECONCILIATION_OK; foreach ($new_type_parts as $offset => $new_type_part_parts) { $orred_type = null; foreach ($new_type_part_parts as $new_type_part_part) { if ($new_type_part_part instanceof NestedAssertions || $new_type_part_part instanceof NotNestedAssertions) { $data = $new_type_part_part->assertions; if ($new_type_part_part instanceof NotNestedAssertions) { $nested_negated = !$negated; } else { $nested_negated = $negated; } [$existing_types, $_] = self::reconcileKeyedTypes($data, $data, $existing_types, $existing_references, $changed_var_ids, $referenced_var_ids, $statements_analyzer, $template_type_map, $inside_loop, $code_location, $nested_negated); $new_type_part_part = $nested_negated ? new Falsy() : new Truthy(); } $result_type_candidate = AssertionReconciler::reconcile($new_type_part_part, $result_type, $key, $statements_analyzer, $inside_loop, $template_type_map, $code_location && isset($referenced_var_ids[$key]) && isset($active_new_types[$key][$offset]) ? $code_location : null, $suppressed_issues, $failed_reconciliation, $negated); if ($result_type_candidate->isUnionEmpty()) { $result_type_candidate = $result_type_candidate->getBuilder()->addType(new TNever())->freeze(); } $orred_type = Type::combineUnionTypes($result_type_candidate, $orred_type, $codebase); } $result_type = $orred_type; } if (!$result_type) { throw new UnexpectedValueException('$result_type should not be null'); } if (!$did_type_exist && $result_type->isNever()) { continue; } if ($statements_analyzer->data_flow_graph instanceof TaintFlowGraph && (!$result_type->hasScalarType() || $result_type->hasString() && !$result_type->hasLiteralString()) || $statements_analyzer->data_flow_graph instanceof VariableUseGraph) { if ($before_adjustment && $before_adjustment->parent_nodes) { $result_type = $result_type->setParentNodes($before_adjustment->parent_nodes); } elseif (!$did_type_exist && $code_location) { $result_type = $result_type->setParentNodes($statements_analyzer->getParentNodesForPossiblyUndefinedVariable($key)); } } if ($before_adjustment && $before_adjustment->by_ref) { $result_type = $result_type->setByRef(\true); } $type_changed = !$before_adjustment || !$result_type->equals($before_adjustment) || $result_type->different || $before_adjustment->different; $key_parts = self::breakUpPathIntoParts($key); if ($type_changed || $failed_reconciliation) { $changed_var_ids[$key] = \true; if (substr($key, -1) === ']' && !$has_inverted_isset && !$has_inverted_key_exists && !$has_empty && !$is_equality) { self::adjustTKeyedArrayType($key_parts, $existing_types, $changed_var_ids, $result_type); } elseif ($key !== '$this') { foreach ($existing_types as $new_key => $_) { if ($new_key === $key) { continue; } if (!isset($new_types[$new_key]) && preg_match('/' . preg_quote($key, '/') . '[\\]\\[\\-]/', $new_key) && $is_real) { // Fix any references to the type before removing it. $references_to_fix = array_keys($reference_graph[$new_key] ?? []); if (count($references_to_fix) > 1) { // Still multiple references, just remove $new_key foreach ($references_to_fix as $reference_to_fix) { unset($reference_graph[$reference_to_fix][$new_key]); } // Set references pointing to $new_key to point // to the first other reference from the same group $new_primary_reference = key($reference_graph[$references_to_fix[0]]); unset($existing_references[$new_primary_reference]); foreach ($existing_references as $existing_reference => $existing_referenced) { if ($existing_referenced === $new_key) { $existing_references[$existing_reference] = $new_primary_reference; } } } elseif (count($references_to_fix) === 1) { // Since reference target is going to be removed, // pretend the reference is just a normal variable $reference_to_fix = $references_to_fix[0]; unset($reference_graph[$reference_to_fix], $existing_references[$reference_to_fix]); } unset($existing_types[$new_key], $reference_graph[$new_key], $existing_references[$new_key]); } } } } elseif (!$has_negation && !$has_truthy_or_falsy_or_empty && !$has_isset) { $changed_var_ids[$key] = \true; } if ($failed_reconciliation === self::RECONCILIATION_EMPTY) { $result_type = $result_type->setProperties(['failed_reconciliation' => \true]); } if (!$has_object_array_access) { $existing_types[$key] = $result_type; } if (!$did_type_exist && isset($existing_types[$key]) && isset($reference_graph[$key_parts[0]])) { // If key is new, create references for other variables that reference the root variable. $reference_key_parts = $key_parts; foreach ($reference_graph[$key_parts[0]] as $reference => $_) { $reference_key_parts[0] = $reference; $reference_key = implode("", $reference_key_parts); $existing_types[$reference_key] =& $existing_types[$key]; } } } return [$existing_types, $existing_references]; } /** * This generates a list of extra assertions for an assertion on a nested key. * * For example ['$a[0]->foo->bar' => 'isset'] * * generates the assertions * * [ * '$a' => '=int-or-string-array-access', * '$a[0]' => '=isset', * '$a[0]->foo' => '=isset', * '$a[0]->foo->bar' => 'isset' // original assertion * ] * * @param array>> $new_types * @param array $existing_types * @return array>> */ private static function addNestedAssertions(array $new_types, array $existing_types) : array { foreach ($new_types as $nk => $type) { if (strpos($nk, '[') || strpos($nk, '->')) { $type = array_values($type); if (!isset($type[0][0])) { continue; } if ($type[0][0] instanceof IsEqualIsset || $type[0][0] instanceof IsIsset || $type[0][0] instanceof NonEmpty) { $key_parts = self::breakUpPathIntoParts($nk); $base_key = array_shift($key_parts); if ($base_key[0] !== '$' && count($key_parts) > 2 && $key_parts[0] === '::$') { $base_key .= array_shift($key_parts); $base_key .= array_shift($key_parts); } if (!isset($existing_types[$base_key]) || $existing_types[$base_key]->isNullable()) { if (!isset($new_types[$base_key])) { $new_types[$base_key] = [[new IsEqualIsset()]]; } else { $new_types[$base_key][] = [new IsEqualIsset()]; } } while ($key_parts) { $divider = array_shift($key_parts); if ($divider === '[') { $array_key = array_shift($key_parts); array_shift($key_parts); if ($array_key[0] === '\'' || $array_key[0] === '"') { $possibly_property_key = substr($array_key, 1, -1); $string_to_int = ArrayAnalyzer::getLiteralArrayKeyInt($possibly_property_key); $array_key = $string_to_int === \false ? $array_key : $string_to_int; } $new_base_key = $base_key . '[' . $array_key . ']'; if (is_string($array_key) && strpos($array_key, '\'') !== \false) { $new_types[$base_key][] = [new HasStringArrayAccess()]; } else { $new_types[$base_key][] = [new HasIntOrStringArrayAccess()]; } $base_key = $new_base_key; continue; } if ($divider === '->') { $property_name = array_shift($key_parts); $new_base_key = $base_key . '->' . $property_name; if (!isset($new_types[$base_key])) { $new_types[$base_key] = [[new IsEqualIsset()]]; } $base_key = $new_base_key; } else { break; } if (!$key_parts) { break; } if (!isset($new_types[$base_key])) { $new_types[$base_key] = [[new IsNotLooselyEqual(new TBool())], [new IsNotLooselyEqual(new TInt())], [new IsEqualIsset()]]; } else { $new_types[$base_key][] = [new IsNotLooselyEqual(new TBool())]; $new_types[$base_key][] = [new IsNotLooselyEqual(new TInt())]; $new_types[$base_key][] = [new IsEqualIsset()]; } } } if ($type[0][0] instanceof ArrayKeyExists) { $key_parts = self::breakUpPathIntoParts($nk); if (count($key_parts) === 4 && $key_parts[1] === '[' && $key_parts[2][0] !== '\'' && !is_numeric($key_parts[2]) && strpos($key_parts[2], '::class') === strlen($key_parts[2]) - 7) { if ($key_parts[0][0] === '$') { if (isset($new_types[$key_parts[0]])) { $new_types[$key_parts[0]][] = [new HasArrayKey($key_parts[2])]; } else { $new_types[$key_parts[0]] = [[new HasArrayKey($key_parts[2])]]; } } } } } } return $new_types; } /** * @return non-empty-list */ public static function breakUpPathIntoParts(string $path) : array { if (isset(self::$broken_paths[$path])) { return self::$broken_paths[$path]; } $chars = str_split($path); $string_char = null; $escape_char = \false; $brackets = 0; $parts = ['']; $parts_offset = 0; for ($i = 0, $char_count = count($chars); $i < $char_count; ++$i) { $char = $chars[$i]; if ($string_char) { if ($char === $string_char && !$escape_char) { $string_char = null; } if ($char === '\\') { $escape_char = !$escape_char; } $parts[$parts_offset] .= $char; continue; } switch ($char) { case '[': case ']': $parts_offset++; $parts[$parts_offset] = $char; ++$parts_offset; if ($char === '[') { $brackets++; } else { $brackets--; } continue 2; case '\'': case '"': if (!isset($parts[$parts_offset])) { $parts[$parts_offset] = ''; } $parts[$parts_offset] .= $char; $string_char = $char; continue 2; case ':': if (!$brackets && $i < $char_count - 2 && $chars[$i + 1] === ':' && $chars[$i + 2] === '$') { ++$i; ++$i; ++$parts_offset; $parts[$parts_offset] = '::$'; ++$parts_offset; continue 2; } // fall through case '-': if (!$brackets && $i < $char_count - 1 && $chars[$i + 1] === '>') { ++$i; ++$parts_offset; $parts[$parts_offset] = '->'; ++$parts_offset; continue 2; } // fall through // no break default: if (!isset($parts[$parts_offset])) { $parts[$parts_offset] = ''; } $parts[$parts_offset] .= $char; } } $parts = array_values($parts); self::$broken_paths[$path] = $parts; return $parts; } /** * Gets the type for a given (non-existent key) based on the passed keys * * @param array $existing_keys * @param array $new_assertions */ private static function getValueForKey(Codebase $codebase, string $key, array &$existing_keys, array $new_assertions, ?CodeLocation $code_location, bool $has_isset, bool $has_inverted_isset, bool $has_inverted_key_exists, bool $has_empty, bool $inside_loop, bool &$has_object_array_access) : ?\Psalm\Type\Union { $key_parts = self::breakUpPathIntoParts($key); if (count($key_parts) === 1) { return $existing_keys[$key_parts[0]] ?? null; } $base_key = array_shift($key_parts); if ($base_key[0] !== '$' && count($key_parts) > 2 && $key_parts[0] === '::$') { $base_key .= array_shift($key_parts); $base_key .= array_shift($key_parts); } if (!isset($existing_keys[$base_key])) { if (strpos($base_key, '::')) { [$fq_class_name, $const_name] = explode('::', $base_key); if (!$codebase->classlikes->classOrInterfaceExists($fq_class_name)) { return null; } $class_constant = $codebase->classlikes->getClassConstantType($fq_class_name, $const_name, ReflectionProperty::IS_PRIVATE, null); if ($class_constant) { $existing_keys[$base_key] = $class_constant; } else { return null; } } else { return null; } } while ($key_parts) { $divider = array_shift($key_parts); if ($divider === '[') { $array_key = array_shift($key_parts); array_shift($key_parts); $new_base_key = $base_key . '[' . $array_key . ']'; if (!isset($existing_keys[$new_base_key])) { $new_base_type = null; $atomic_types = $existing_keys[$base_key]->getAtomicTypes(); while ($atomic_types) { $existing_key_type_part = array_shift($atomic_types); if ($existing_key_type_part instanceof TList) { $existing_key_type_part = $existing_key_type_part->getKeyedArray(); } if ($existing_key_type_part instanceof TTemplateParam) { $atomic_types = array_merge($atomic_types, $existing_key_type_part->as->getAtomicTypes()); continue; } if ($existing_key_type_part instanceof TArray) { if ($has_empty) { return null; } $new_base_type_candidate = $existing_key_type_part->type_params[1]; if ($new_base_type_candidate->isMixed() && !$has_isset && !$has_inverted_isset && !$has_inverted_key_exists) { return $new_base_type_candidate; } if (($has_isset || $has_inverted_isset || $has_inverted_key_exists) && isset($new_assertions[$new_base_key])) { if ($has_inverted_isset && $new_base_key === $key) { $new_base_type_candidate = $new_base_type_candidate->getBuilder(); $new_base_type_candidate->addType(new TNull()); $new_base_type_candidate->possibly_undefined = \true; $new_base_type_candidate = $new_base_type_candidate->freeze(); } else { $new_base_type_candidate = $new_base_type_candidate->setPossiblyUndefined(\true); } } } elseif ($existing_key_type_part instanceof TNull || $existing_key_type_part instanceof TFalse) { $new_base_type_candidate = Type::getNull(); if ($existing_keys[$base_key]->ignore_nullable_issues) { /** @psalm-suppress InaccessibleProperty We just created this type */ $new_base_type_candidate->ignore_nullable_issues = \true; } } elseif ($existing_key_type_part instanceof TClassStringMap) { return Type::getMixed(); } elseif ($existing_key_type_part instanceof TNever || $existing_key_type_part instanceof TMixed && $existing_key_type_part->from_loop_isset) { return Type::getMixed($inside_loop); } elseif ($existing_key_type_part instanceof TString) { $new_base_type_candidate = Type::getString(); } elseif ($existing_key_type_part instanceof TNamedObject && ($has_isset || $has_inverted_isset || $has_inverted_key_exists)) { $has_object_array_access = \true; unset($existing_keys[$new_base_key]); return null; } elseif (!$existing_key_type_part instanceof TKeyedArray) { return Type::getMixed(); } elseif ($array_key[0] === '$' || $array_key[0] !== '\'' && ArrayAnalyzer::getLiteralArrayKeyInt($array_key) === \false) { if ($has_empty) { return null; } $new_base_type_candidate = $existing_key_type_part->getGenericValueType(\true); } else { $array_properties = $existing_key_type_part->properties; $key_parts_key = $array_key; if ($array_key[0] === '\'' || $array_key[0] === '"') { $key_parts_key = substr($array_key, 1, -1); } if (!isset($array_properties[$key_parts_key])) { if ($existing_key_type_part->fallback_params !== null) { $new_base_type_candidate = $existing_key_type_part->fallback_params[1]->setDifferent(\true); } else { return null; } } else { $new_base_type_candidate = $array_properties[$key_parts_key]; } } $new_base_type = Type::combineUnionTypes($new_base_type, $new_base_type_candidate, $codebase); $existing_keys[$new_base_key] = $new_base_type; } } $base_key = $new_base_key; } elseif ($divider === '->' || $divider === '::$') { $property_name = array_shift($key_parts); $new_base_key = $base_key . $divider . $property_name; if (!isset($existing_keys[$new_base_key])) { $new_base_type = null; $atomic_types = $existing_keys[$base_key]->getAtomicTypes(); while ($atomic_types) { $existing_key_type_part = array_shift($atomic_types); if ($existing_key_type_part instanceof TTemplateParam) { $atomic_types = array_merge($atomic_types, $existing_key_type_part->as->getAtomicTypes()); continue; } if ($existing_key_type_part instanceof TNull) { $class_property_type = Type::getNull(); } elseif ($existing_key_type_part instanceof TMixed || $existing_key_type_part instanceof TObject || $existing_key_type_part instanceof TNamedObject && strtolower($existing_key_type_part->value) === 'stdclass') { $class_property_type = Type::getMixed(); } elseif ($existing_key_type_part instanceof TNamedObject) { if (!$codebase->classOrInterfaceExists($existing_key_type_part->value)) { $class_property_type = Type::getMixed(); } else { if (substr($property_name, -2) === '()') { $method_id = new MethodIdentifier($existing_key_type_part->value, strtolower(substr($property_name, 0, -2))); if (!$codebase->methods->methodExists($method_id)) { return null; } $declaring_method_id = $codebase->methods->getDeclaringMethodId($method_id); if ($declaring_method_id === null) { return null; } $declaring_class = $declaring_method_id->fq_class_name; $method_return_type = $codebase->methods->getMethodReturnType($method_id, $declaring_class, null, null); if ($method_return_type) { $class_property_type = TypeExpander::expandUnion($codebase, $method_return_type, $declaring_class, $declaring_class, null); } else { $class_property_type = Type::getMixed(); } } else { $class_property_type = self::getPropertyType($codebase, $existing_key_type_part->value, $property_name); if (!$class_property_type) { return null; } } } } else { $class_property_type = Type::getMixed(); } $new_base_type = Type::combineUnionTypes($new_base_type, $class_property_type, $codebase); $existing_keys[$new_base_key] = $new_base_type; } } $base_key = $new_base_key; } else { return null; } } if (!isset($existing_keys[$base_key])) { if ($code_location) { IssueBuffer::add(new PsalmInternalError('Unknown key ' . $base_key, $code_location)); } return null; } return $existing_keys[$base_key]; } private static function getPropertyType(Codebase $codebase, string $fq_class_name, string $property_name) : ?\Psalm\Type\Union { $property_id = $fq_class_name . '::$' . $property_name; if (!$codebase->properties->propertyExists($property_id, \true)) { $declaring_class_storage = $codebase->classlike_storage_provider->get($fq_class_name); if (isset($declaring_class_storage->pseudo_property_get_types['$' . $property_name])) { return $declaring_class_storage->pseudo_property_get_types['$' . $property_name]; } return null; } $declaring_property_class = $codebase->properties->getDeclaringClassForProperty($property_id, \true); if ($declaring_property_class === null) { return null; } $class_property_type = $codebase->properties->getPropertyType($property_id, \false, null, null); $declaring_class_storage = $codebase->classlike_storage_provider->get($declaring_property_class); if ($class_property_type) { return TypeExpander::expandUnion($codebase, $class_property_type, $declaring_class_storage->name, $declaring_class_storage->name, null); } return Type::getMixed(); } /** * @param Union|MutableUnion $existing_var_type * @param string[] $suppressed_issues */ protected static function triggerIssueForImpossible($existing_var_type, string $old_var_type_string, string $key, Assertion $assertion, bool $redundant, bool $negated, CodeLocation $code_location, array $suppressed_issues) : void { $assertion_string = (string) $assertion; $not = $assertion_string[0] === '!'; if ($not) { $assertion_string = substr($assertion_string, 1); } $operator = substr($assertion_string, 0, 1); if ($operator === '>') { $assertion_string = '>= ' . substr($assertion_string, 1); } elseif ($operator === '<') { $assertion_string = '<= ' . substr($assertion_string, 1); } if ($negated) { $redundant = !$redundant; $not = !$not; } $existing_var_atomic_types = $existing_var_type->getAtomicTypes(); $from_docblock = $existing_var_type->from_docblock || isset($existing_var_atomic_types[$assertion_string]) && $existing_var_atomic_types[$assertion_string]->from_docblock; if ($redundant) { if ($existing_var_type->from_property && ($assertion instanceof IsIsset || $assertion instanceof IsNotIsset)) { if ($existing_var_type->from_static_property) { IssueBuffer::maybeAdd(new RedundantPropertyInitializationCheck('Static property ' . $key . ' with type ' . $old_var_type_string . ' has unexpected isset check — should it be nullable?', $code_location), $suppressed_issues); } else { IssueBuffer::maybeAdd(new RedundantPropertyInitializationCheck('Property ' . $key . ' with type ' . $old_var_type_string . ' should already be set in the constructor', $code_location), $suppressed_issues); } } elseif ($from_docblock) { IssueBuffer::maybeAdd(new RedundantConditionGivenDocblockType('Docblock-defined type ' . $old_var_type_string . ' for ' . $key . ' is ' . ($not ? 'never ' : 'always ') . $assertion_string, $code_location, $old_var_type_string . ' ' . $assertion_string), $suppressed_issues); } else { IssueBuffer::maybeAdd(new RedundantCondition('Type ' . $old_var_type_string . ' for ' . $key . ' is ' . ($not ? 'never ' : 'always ') . $assertion_string, $code_location, $old_var_type_string . ' ' . $assertion_string), $suppressed_issues); } } else { if ($from_docblock) { IssueBuffer::maybeAdd(new DocblockTypeContradiction('Docblock-defined type ' . $old_var_type_string . ' for ' . $key . ' is ' . ($not ? 'always ' : 'never ') . $assertion_string, $code_location, $old_var_type_string . ' ' . $assertion_string), $suppressed_issues); } else { if ($assertion_string === 'null' && !$not) { $issue = new TypeDoesNotContainNull('Type ' . $old_var_type_string . ' for ' . $key . ' is never ' . $assertion_string, $code_location, $old_var_type_string . ' ' . $assertion_string); } else { $issue = new TypeDoesNotContainType('Type ' . $old_var_type_string . ' for ' . $key . ' is ' . ($not ? 'always ' : 'never ') . $assertion, $code_location, $old_var_type_string . ' ' . $assertion); } IssueBuffer::maybeAdd($issue, $suppressed_issues); } } } /** * @param string[] $key_parts * @param array $existing_types * @param array $changed_var_ids */ private static function adjustTKeyedArrayType(array $key_parts, array &$existing_types, array &$changed_var_ids, \Psalm\Type\Union $result_type) : void { array_pop($key_parts); $array_key = array_pop($key_parts); array_pop($key_parts); if ($array_key === null) { throw new UnexpectedValueException('Not expecting null array key'); } $array_key_offsets = []; if ($array_key[0] === '$') { if (!isset($existing_types[$array_key])) { return; } $t = $existing_types[$array_key]; foreach ($t->getAtomicTypes() as $lit) { if ($lit instanceof TLiteralInt || $lit instanceof TLiteralString) { $array_key_offsets[] = $lit->value; continue; } return; } } else { $array_key_offsets[] = $array_key[0] === '\'' || $array_key[0] === '"' ? substr($array_key, 1, -1) : $array_key; } $base_key = implode($key_parts); $result_type = $result_type->setPossiblyUndefined($result_type->possibly_undefined || count($array_key_offsets) > 1); foreach ($array_key_offsets as $array_key_offset) { if (isset($existing_types[$base_key]) && $array_key_offset !== \false) { foreach ($existing_types[$base_key]->getAtomicTypes() as $base_atomic_type) { if ($base_atomic_type instanceof TList) { $base_atomic_type = $base_atomic_type->getKeyedArray(); } if ($base_atomic_type instanceof TKeyedArray || $base_atomic_type instanceof TArray && !$base_atomic_type->isEmptyArray() || $base_atomic_type instanceof TClassStringMap) { $new_base_type = $existing_types[$base_key]; if ($base_atomic_type instanceof TArray) { $fallback_key_type = $base_atomic_type->type_params[0]; $fallback_value_type = $base_atomic_type->type_params[1]; $base_atomic_type = new TKeyedArray([$array_key_offset => $result_type], null, $fallback_key_type->isNever() ? null : [$fallback_key_type, $fallback_value_type]); } elseif ($base_atomic_type instanceof TClassStringMap) { // do nothing } else { $properties = $base_atomic_type->properties; $properties[$array_key_offset] = $result_type; if ($base_atomic_type->is_list && (ArrayAnalyzer::getLiteralArrayKeyInt($array_key_offset) === \false || $array_key_offset && !isset($properties[$array_key_offset - 1]))) { if ($base_atomic_type->fallback_params && ArrayAnalyzer::getLiteralArrayKeyInt($array_key_offset) !== \false) { $fallback = $base_atomic_type->fallback_params[1]->setPossiblyUndefined($result_type->isNever()); for ($x = 0; $x < $array_key_offset; $x++) { $properties[$x] ??= $fallback; } ksort($properties); $base_atomic_type = $base_atomic_type->setProperties($properties); } else { // This should actually be a paradox $base_atomic_type = new TKeyedArray($properties, null, $base_atomic_type->fallback_params, \false, $base_atomic_type->from_docblock); } } else { $base_atomic_type = $base_atomic_type->setProperties($properties); } } $new_base_type = $new_base_type->getBuilder()->addType($base_atomic_type)->freeze(); $changed_var_ids[$base_key . '[' . $array_key . ']'] = \true; if ($key_parts[count($key_parts) - 1] === ']') { self::adjustTKeyedArrayType($key_parts, $existing_types, $changed_var_ids, $new_base_type); } $existing_types[$base_key] = $new_base_type; break; } } } } } protected static function refineArrayKey(\Psalm\Type\Union $key_type) : \Psalm\Type\Union { return self::refineArrayKeyInner($key_type) ?? $key_type; } private static function refineArrayKeyInner(\Psalm\Type\Union $key_type) : ?\Psalm\Type\Union { $refined = \false; $types = []; foreach ($key_type->getAtomicTypes() as $cat) { if ($cat instanceof TTemplateParam) { $as = self::refineArrayKeyInner($cat->as); if ($as) { $refined = \true; $types[] = $cat->replaceAs($as); } else { $types[] = $cat; } } elseif ($cat instanceof TArrayKey || $cat instanceof TString || $cat instanceof TInt) { $types[] = $cat; } else { $refined = \true; $types[] = new TArrayKey(); } } if ($refined) { return $key_type->getBuilder()->setTypes($types)->freeze(); } return null; } } */ private array $types; /** * Whether the type originated in a docblock * * @var bool */ public $from_docblock = \false; /** * Whether the type originated from integer calculation * * @var bool */ public $from_calculation = \false; /** * Whether the type originated from a property * * This helps turn isset($foo->bar) into a different sort of issue * * @var bool */ public $from_property = \false; /** * Whether the type originated from *static* property * * Unlike non-static properties, static properties have no prescribed place * like __construct() to be initialized in * * @var bool */ public $from_static_property = \false; /** * Whether the property that this type has been derived from has been initialized in a constructor * * @var bool */ public $initialized = \true; /** * Which class the type was initialised in * * @var ?string */ public $initialized_class; /** * Whether or not the type has been checked yet * * @var bool */ public $checked = \false; /** * @var bool */ public $failed_reconciliation = \false; /** * Whether or not to ignore issues with possibly-null values * * @var bool */ public $ignore_nullable_issues = \false; /** * Whether or not to ignore issues with possibly-false values * * @var bool */ public $ignore_falsable_issues = \false; /** * Whether or not to ignore issues with isset on this type * * @var bool */ public $ignore_isset = \false; /** * Whether or not this variable is possibly undefined * * @var bool */ public $possibly_undefined = \false; /** * Whether or not this variable is possibly undefined * * @var bool */ public $possibly_undefined_from_try = \false; /** * whether this type had never set explicitly * since it's the bottom type, it's combined into everything else and lost * * @psalm-suppress PossiblyUnusedProperty used in setTypes and addType * @var bool */ public $explicit_never = \false; /** * Whether or not this union had a template, since replaced * * @var bool */ public $had_template = \false; /** * Whether or not this union comes from a template "as" default * * @var bool */ public $from_template_default = \false; /** * @var array */ private array $literal_string_types = []; /** * @var array */ private array $typed_class_strings = []; /** * @var array */ private array $literal_int_types = []; /** * @var array */ private array $literal_float_types = []; /** * True if the type was passed or returned by reference, or if the type refers to an object's * property or an item in an array. Note that this is not true for locally created references * that don't refer to properties or array items (see Context::$references_in_scope). * * @var bool */ public $by_ref = \false; /** * @var bool */ public $reference_free = \false; /** * @var bool */ public $allow_mutations = \true; /** * @var bool */ public $has_mutations = \true; /** * This is a cache of getId on non-exact mode */ private ?string $id = null; /** * This is a cache of getId on exact mode */ private ?string $exact_id = null; /** * @var array */ public $parent_nodes = []; /** * @var bool */ public $different = \false; /** @psalm-suppress PossiblyUnusedProperty */ public bool $propagate_parent_nodes = \false; /** * @psalm-external-mutation-free * @param non-empty-array $types */ public function setTypes(array $types) : self { $this->literal_float_types = []; $this->literal_int_types = []; $this->literal_string_types = []; $this->typed_class_strings = []; $this->checked = \false; $from_docblock = \false; $keyed_types = []; foreach ($types as $type) { $key = $type->getKey(); $keyed_types[$key] = $type; if ($type instanceof TLiteralInt) { $this->literal_int_types[$key] = $type; } elseif ($type instanceof TLiteralString) { $this->literal_string_types[$key] = $type; } elseif ($type instanceof TLiteralFloat) { $this->literal_float_types[$key] = $type; } elseif ($type instanceof TClassString && ($type->as_type || $type instanceof TTemplateParamClass)) { $this->typed_class_strings[$key] = $type; } elseif ($type instanceof TNever) { $this->explicit_never = \true; } $from_docblock = $from_docblock || $type->from_docblock; } $this->types = $keyed_types; $this->from_docblock = $from_docblock; return $this; } /** * @psalm-external-mutation-free */ public function addType(\Psalm\Type\Atomic $type) : self { $this->types[$type->getKey()] = $type; if ($type instanceof TLiteralString) { $this->literal_string_types[$type->getKey()] = $type; } elseif ($type instanceof TLiteralInt) { $this->literal_int_types[$type->getKey()] = $type; } elseif ($type instanceof TLiteralFloat) { $this->literal_float_types[$type->getKey()] = $type; } elseif ($type instanceof TString && $this->literal_string_types) { foreach ($this->literal_string_types as $key => $_) { unset($this->literal_string_types[$key], $this->types[$key]); } if (!$type instanceof TClassString || !$type->as_type && !$type instanceof TTemplateParamClass) { foreach ($this->typed_class_strings as $key => $_) { unset($this->typed_class_strings[$key], $this->types[$key]); } } } elseif ($type instanceof TInt && $this->literal_int_types) { //we remove any literal that is already included in a wider type $int_type_in_range = TIntRange::convertToIntRange($type); foreach ($this->literal_int_types as $key => $literal_int_type) { if ($int_type_in_range->contains($literal_int_type->value)) { unset($this->literal_int_types[$key], $this->types[$key]); } } } elseif ($type instanceof TFloat && $this->literal_float_types) { foreach ($this->literal_float_types as $key => $_) { unset($this->literal_float_types[$key], $this->types[$key]); } } elseif ($type instanceof TNever) { $this->explicit_never = \true; } $this->bustCache(); return $this; } /** * @psalm-external-mutation-free */ public function removeType(string $type_string) : bool { if (isset($this->types[$type_string])) { unset($this->types[$type_string]); if (strpos($type_string, '(')) { unset($this->literal_string_types[$type_string], $this->literal_int_types[$type_string], $this->literal_float_types[$type_string]); } $this->bustCache(); return \true; } if ($type_string === 'string') { if ($this->literal_string_types) { foreach ($this->literal_string_types as $literal_key => $_) { unset($this->types[$literal_key]); } $this->literal_string_types = []; } if ($this->typed_class_strings) { foreach ($this->typed_class_strings as $typed_class_key => $_) { unset($this->types[$typed_class_key]); } $this->typed_class_strings = []; } unset($this->types['class-string'], $this->types['trait-string']); } elseif ($type_string === 'int' && $this->literal_int_types) { foreach ($this->literal_int_types as $literal_key => $_) { unset($this->types[$literal_key]); } $this->literal_int_types = []; } elseif ($type_string === 'float' && $this->literal_float_types) { foreach ($this->literal_float_types as $literal_key => $_) { unset($this->types[$literal_key]); } $this->literal_float_types = []; } return \false; } public function setFromDocblock(bool $fromDocblock = \true) : self { $this->from_docblock = $fromDocblock; (new FromDocblockSetter($fromDocblock))->traverseArray($this->types); return $this; } /** * @psalm-external-mutation-free */ public function bustCache() : void { $this->id = null; $this->exact_id = null; } /** * @psalm-external-mutation-free * @param Union|MutableUnion $old_type * @param Union|MutableUnion|null $new_type */ public function substitute($old_type, $new_type = null) : self { if ($this->hasMixed() && !$this->isEmptyMixed()) { return $this; } $old_type = $old_type->getBuilder(); if ($new_type) { $new_type = $new_type->getBuilder(); } if ($new_type && $new_type->ignore_nullable_issues) { $this->ignore_nullable_issues = \true; } if ($new_type && $new_type->ignore_falsable_issues) { $this->ignore_falsable_issues = \true; } foreach ($old_type->types as $old_type_part) { $had = isset($this->types[$old_type_part->getKey()]); $this->removeType($old_type_part->getKey()); if (!$had) { if ($old_type_part instanceof TFalse && isset($this->types['bool']) && !isset($this->types['true'])) { $this->removeType('bool'); $this->types['true'] = new TTrue(); } elseif ($old_type_part instanceof TTrue && isset($this->types['bool']) && !isset($this->types['false'])) { $this->removeType('bool'); $this->types['false'] = new TFalse(); } elseif (isset($this->types['iterable'])) { if ($old_type_part instanceof TNamedObject && $old_type_part->value === 'Traversable' && !isset($this->types['array'])) { $this->removeType('iterable'); $this->types['array'] = new TArray([Type::getArrayKey(), Type::getMixed()]); } if ($old_type_part instanceof TArray && !isset($this->types['traversable'])) { $this->removeType('iterable'); $this->types['traversable'] = new TNamedObject('Traversable'); } } elseif (isset($this->types['array-key'])) { if ($old_type_part instanceof TString && !isset($this->types['int'])) { $this->removeType('array-key'); $this->types['int'] = new TInt(); } if ($old_type_part instanceof TInt && !isset($this->types['string'])) { $this->removeType('array-key'); $this->types['string'] = new TString(); } } } } if ($new_type) { foreach ($new_type->types as $key => $new_type_part) { if (!isset($this->types[$key]) || $new_type_part instanceof Scalar && get_class($new_type_part) === get_class($this->types[$key])) { $this->types[$key] = $new_type_part; } else { $this->types[$key] = TypeCombiner::combine([$new_type_part, $this->types[$key]])->getSingleAtomic(); } } } elseif (count($this->types) === 0) { $this->types['mixed'] = new TMixed(); } $this->bustCache(); return $this; } /** * @psalm-mutation-free */ public function getBuilder() : self { return $this; } /** * @psalm-mutation-free */ public function freeze() : \Psalm\Type\Union { /** @psalm-suppress InvalidArgument It's actually filtered internally */ return new \Psalm\Type\Union($this->getAtomicTypes(), get_object_vars($this)); } /** * @phpcsSuppress SlevomatCodingStandard.TypeHints.ParameterTypeHint.MissingAnyTypeHint */ public static function visitMutable(\Psalm\Type\MutableTypeVisitor $visitor, &$node, bool $cloned) : bool { $result = \true; $changed = \false; foreach ($node->types as &$type) { $type_orig = $type; $result = $visitor->traverse($type); $changed = $changed || $type_orig !== $type; if (!$result) { break; } } unset($type); if ($changed) { $node->setTypes($node->types); } return $result; } } $types * @param TProperties $properties */ public function __construct(array $types, array $properties = []) { foreach ($properties as $key => $value) { $this->{$key} = $value; } $this->literal_int_types = []; $this->literal_string_types = []; $this->literal_float_types = []; $this->typed_class_strings = []; $this->checked = \false; $this->id = null; $this->exact_id = null; $keyed_types = []; $from_docblock = $this->from_docblock; foreach ($types as $type) { $key = $type->getKey(); $keyed_types[$key] = $type; if ($type instanceof TLiteralInt) { $this->literal_int_types[$key] = $type; } elseif ($type instanceof TLiteralString) { $this->literal_string_types[$key] = $type; } elseif ($type instanceof TLiteralFloat) { $this->literal_float_types[$key] = $type; } elseif ($type instanceof TClassString && ($type->as_type || $type instanceof TTemplateParamClass)) { $this->typed_class_strings[$key] = $type; } elseif ($type instanceof TNever) { $this->explicit_never = \true; } $from_docblock = $from_docblock || $type->from_docblock; } $this->from_docblock = $from_docblock; $this->types = $keyed_types; } /** * @psalm-mutation-free * @return non-empty-array */ public function getAtomicTypes() : array { return $this->types; } /** * @psalm-mutation-free */ public function __toString() : string { $types = []; $printed_int = \false; $printed_float = \false; $printed_string = \false; foreach ($this->types as $type) { if ($type instanceof TLiteralFloat) { if ($printed_float) { continue; } $printed_float = \true; } elseif ($type instanceof TLiteralString) { if ($printed_string) { continue; } $printed_string = \true; } elseif ($type instanceof TLiteralInt) { if ($printed_int) { continue; } $printed_int = \true; } $types[] = $type->getId(\false); } sort($types); return implode('|', $types); } /** * @psalm-mutation-free */ public function getKey() : string { $types = []; $printed_int = \false; $printed_float = \false; $printed_string = \false; foreach ($this->types as $type) { if ($type instanceof TLiteralFloat) { if ($printed_float) { continue; } $types[] = 'float'; $printed_float = \true; } elseif ($type instanceof TLiteralString) { if ($printed_string) { continue; } $types[] = 'string'; $printed_string = \true; } elseif ($type instanceof TLiteralInt) { if ($printed_int) { continue; } $types[] = 'int'; $printed_int = \true; } else { $types[] = $type->getKey(); } } sort($types); return implode('|', $types); } /** * @psalm-mutation-free */ public function getId(bool $exact = \true) : string { if ($exact && $this->exact_id) { return $this->exact_id; } elseif (!$exact && $this->id) { return $this->id; } $types = []; foreach ($this->types as $type) { $types[] = $type->getId($exact); } $types = array_unique($types); sort($types); if (count($types) > 1) { foreach ($types as $i => $type) { if (strpos($type, ' as ') && strpos($type, '(') === \false) { $types[$i] = '(' . $type . ')'; } } } $id = implode('|', $types); if ($exact) { /** @psalm-suppress ImpurePropertyAssignment, InaccessibleProperty Cache */ $this->exact_id = $id; } else { /** @psalm-suppress ImpurePropertyAssignment, InaccessibleProperty Cache */ $this->id = $id; } return $id; } /** * @param array $aliased_classes * @psalm-mutation-free */ public function toNamespacedString(?string $namespace, array $aliased_classes, ?string $this_class, bool $use_phpdoc_format) : string { $other_types = []; $literal_ints = []; $literal_strings = []; $has_non_literal_int = \false; $has_non_literal_string = \false; foreach ($this->types as $type) { $type_string = $type->toNamespacedString($namespace, $aliased_classes, $this_class, $use_phpdoc_format); if ($type instanceof TLiteralInt) { $literal_ints[] = $type_string; } elseif ($type instanceof TLiteralString) { $literal_strings[] = $type_string; } else { if (get_class($type) === TString::class) { $has_non_literal_string = \true; } elseif (get_class($type) === TInt::class) { $has_non_literal_int = \true; } $other_types[] = $type_string; } } if (count($literal_ints) <= 3 && !$has_non_literal_int) { $other_types = [...$other_types, ...$literal_ints]; } else { $other_types[] = 'int'; } if (count($literal_strings) <= 3 && !$has_non_literal_string) { $other_types = [...$other_types, ...$literal_strings]; } else { $other_types[] = 'string'; } sort($other_types); return implode('|', array_unique($other_types)); } /** * @psalm-mutation-free * @param array $aliased_classes */ public function toPhpString(?string $namespace, array $aliased_classes, ?string $this_class, int $analysis_php_version_id) : ?string { if (!$this->isSingleAndMaybeNullable()) { if ($analysis_php_version_id < 80000) { return null; } } elseif ($analysis_php_version_id < 70000 || isset($this->types['null']) && $analysis_php_version_id < 70100) { return null; } $types = $this->types; $nullable = \false; if (isset($types['null']) && count($types) > 1) { unset($types['null']); $nullable = \true; } $falsable = \false; if (isset($types['false']) && count($types) > 1) { unset($types['false']); $falsable = \true; } $php_types = []; foreach ($types as $atomic_type) { $php_type = $atomic_type->toPhpString($namespace, $aliased_classes, $this_class, $analysis_php_version_id); if (!$php_type) { return null; } $php_types[] = $php_type; } if ($falsable) { if ($nullable) { $php_types['null'] = 'null'; } $php_types['false'] = 'false'; ksort($php_types); return implode('|', array_unique($php_types)); } if ($analysis_php_version_id < 80000) { return ($nullable ? '?' : '') . implode('|', array_unique($php_types)); } if ($nullable) { $php_types['null'] = 'null'; } return implode('|', array_unique($php_types)); } /** * @psalm-mutation-free */ public function canBeFullyExpressedInPhp(int $analysis_php_version_id) : bool { if (!$this->isSingleAndMaybeNullable() && $analysis_php_version_id < 80000) { return \false; } $types = $this->types; if (isset($types['null'])) { if (count($types) > 1) { unset($types['null']); } else { return \false; } } return !array_filter($types, static fn($atomic_type): bool => !$atomic_type->canBeFullyExpressedInPhp($analysis_php_version_id)); } /** * @psalm-mutation-free */ public function hasType(string $type_string) : bool { return isset($this->types[$type_string]); } /** * @psalm-mutation-free */ public function hasArray() : bool { return isset($this->types['array']); } /** * @return TArray|TKeyedArray|TClassStringMap */ public function getArray() : \Psalm\Type\Atomic { if ($this->types['array'] instanceof TList) { return $this->types['array']->getKeyedArray(); } return $this->types['array']; } /** * @psalm-mutation-free */ public function hasIterable() : bool { return isset($this->types['iterable']); } /** * @psalm-mutation-free */ public function hasList() : bool { return isset($this->types['array']) && $this->types['array'] instanceof TKeyedArray && $this->types['array']->is_list; } /** * @psalm-mutation-free */ public function hasClassStringMap() : bool { return isset($this->types['array']) && $this->types['array'] instanceof TClassStringMap; } /** * @psalm-mutation-free */ public function isTemplatedClassString() : bool { return $this->isSingle() && count(array_filter($this->types, static fn($type): bool => $type instanceof TTemplateParamClass)) === 1; } /** * @psalm-mutation-free */ public function hasArrayAccessInterface(Codebase $codebase) : bool { return (bool) array_filter($this->types, static fn($type): bool => $type->hasArrayAccessInterface($codebase)); } /** * @psalm-mutation-free */ public function hasCallableType() : bool { return $this->getCallableTypes() || $this->getClosureTypes(); } /** * @psalm-mutation-free * @return array */ public function getCallableTypes() : array { return array_filter($this->types, static fn($type): bool => $type instanceof TCallable); } /** * @psalm-mutation-free * @return array */ public function getClosureTypes() : array { return array_filter($this->types, static fn($type): bool => $type instanceof TClosure); } /** * @psalm-mutation-free */ public function hasObject() : bool { return isset($this->types['object']); } /** * @psalm-mutation-free */ public function hasObjectType() : bool { foreach ($this->types as $type) { if ($type->isObjectType()) { return \true; } } return \false; } /** * @psalm-mutation-free */ public function canContainObjectType(Codebase $codebase) : bool { $object_type_visitor = new CanContainObjectTypeVisitor($codebase); $object_type_visitor->traverseArray($this->types); return $object_type_visitor->matches(); } /** * @psalm-mutation-free */ public function isObjectType() : bool { foreach ($this->types as $type) { if (!$type->isObjectType()) { return \false; } } return \true; } /** * @psalm-mutation-free */ public function hasNamedObjectType() : bool { foreach ($this->types as $type) { if ($type->isNamedObjectType()) { return \true; } } return \false; } /** * @psalm-mutation-free */ public function isStaticObject() : bool { foreach ($this->types as $type) { if (!$type instanceof TNamedObject || !$type->is_static) { return \false; } } return \true; } /** * @psalm-mutation-free */ public function hasStaticObject() : bool { foreach ($this->types as $type) { if ($type instanceof TNamedObject && $type->is_static) { return \true; } } return \false; } /** * @psalm-mutation-free */ public function isNullable() : bool { if (isset($this->types['null'])) { return \true; } foreach ($this->types as $type) { if ($type instanceof TTemplateParam && $type->as->isNullable()) { return \true; } } return \false; } /** * @psalm-mutation-free */ public function isFalsable() : bool { if (isset($this->types['false'])) { return \true; } foreach ($this->types as $type) { if ($type instanceof TTemplateParam && $type->as->isFalsable()) { return \true; } } return \false; } /** * @psalm-mutation-free */ public function hasBool() : bool { return isset($this->types['bool']) || isset($this->types['false']) || isset($this->types['true']); } /** * @psalm-mutation-free */ public function hasNull() : bool { return isset($this->types['null']); } /** * @psalm-mutation-free */ public function hasString() : bool { return isset($this->types['string']) || isset($this->types['class-string']) || isset($this->types['trait-string']) || isset($this->types['numeric-string']) || isset($this->types['callable-string']) || isset($this->types['array-key']) || $this->literal_string_types || $this->typed_class_strings; } /** * @psalm-mutation-free */ public function hasLowercaseString() : bool { return isset($this->types['string']) && ($this->types['string'] instanceof TLowercaseString || $this->types['string'] instanceof TNonEmptyLowercaseString); } /** * @psalm-mutation-free */ public function hasLiteralClassString() : bool { return count($this->typed_class_strings) > 0; } /** * @psalm-mutation-free */ public function hasInt() : bool { return isset($this->types['int']) || isset($this->types['array-key']) || $this->literal_int_types || array_filter($this->types, static fn(\Psalm\Type\Atomic $type): bool => $type instanceof TIntRange); } /** * @psalm-mutation-free */ public function hasArrayKey() : bool { return isset($this->types['array-key']); } /** * @psalm-mutation-free */ public function hasFloat() : bool { return isset($this->types['float']) || $this->literal_float_types; } /** * @psalm-mutation-free */ public function hasScalar() : bool { return isset($this->types['scalar']); } /** * @psalm-mutation-free */ public function hasNumeric() : bool { return isset($this->types['numeric']); } /** * @psalm-mutation-free */ public function hasScalarType() : bool { return isset($this->types['int']) || isset($this->types['float']) || isset($this->types['string']) || isset($this->types['class-string']) || isset($this->types['trait-string']) || isset($this->types['bool']) || isset($this->types['false']) || isset($this->types['true']) || isset($this->types['numeric']) || isset($this->types['numeric-string']) || $this->literal_int_types || $this->literal_float_types || $this->literal_string_types || $this->typed_class_strings; } /** * @psalm-mutation-free */ public function hasTemplate() : bool { return (bool) array_filter($this->types, static fn(\Psalm\Type\Atomic $type): bool => $type instanceof TTemplateParam || $type instanceof TNamedObject && $type->extra_types && array_filter($type->extra_types, static fn($t): bool => $t instanceof TTemplateParam)); } /** * @psalm-mutation-free */ public function hasConditional() : bool { return (bool) array_filter($this->types, static fn(\Psalm\Type\Atomic $type): bool => $type instanceof TConditional); } /** * @psalm-mutation-free */ public function hasTemplateOrStatic() : bool { return (bool) array_filter($this->types, static fn(\Psalm\Type\Atomic $type): bool => $type instanceof TTemplateParam || $type instanceof TNamedObject && ($type->is_static || $type->extra_types && array_filter($type->extra_types, static fn($t): bool => $t instanceof TTemplateParam))); } /** * @psalm-mutation-free */ public function hasMixed() : bool { return isset($this->types['mixed']); } /** * @psalm-mutation-free */ public function isMixed(bool $check_templates = \false) : bool { return count(array_filter($this->types, static fn($type, $key): bool => $key === 'mixed' || $type instanceof TMixed || $check_templates && $type instanceof TTemplateParam && $type->as->isMixed(), ARRAY_FILTER_USE_BOTH)) === count($this->types); } /** * @psalm-mutation-free */ public function isEmptyMixed() : bool { return isset($this->types['mixed']) && $this->types['mixed'] instanceof TEmptyMixed && count($this->types) === 1; } /** * @psalm-mutation-free */ public function isVanillaMixed() : bool { return isset($this->types['mixed']) && get_class($this->types['mixed']) === TMixed::class && !$this->types['mixed']->from_loop_isset && count($this->types) === 1; } /** * @psalm-mutation-free */ public function isArrayKey() : bool { return isset($this->types['array-key']) && count($this->types) === 1; } /** * @psalm-mutation-free */ public function isNull() : bool { return count($this->types) === 1 && isset($this->types['null']); } /** * @psalm-mutation-free */ public function isFalse() : bool { return count($this->types) === 1 && isset($this->types['false']); } /** * @psalm-mutation-free */ public function isAlwaysFalsy() : bool { foreach ($this->getAtomicTypes() as $atomic_type) { if (!$atomic_type->isFalsy()) { return \false; } } return \true; } /** * @psalm-mutation-free */ public function isTrue() : bool { return count($this->types) === 1 && isset($this->types['true']); } /** * @psalm-mutation-free */ public function isAlwaysTruthy() : bool { if ($this->possibly_undefined || $this->possibly_undefined_from_try) { return \false; } foreach ($this->getAtomicTypes() as $atomic_type) { if (!$atomic_type->isTruthy()) { return \false; } } return \true; } /** * @psalm-mutation-free */ public function isVoid() : bool { return isset($this->types['void']) && count($this->types) === 1; } /** * @psalm-mutation-free */ public function isNever() : bool { return isset($this->types['never']) && count($this->types) === 1; } /** * @psalm-mutation-free */ public function isGenerator() : bool { return count($this->types) === 1 && ($single_type = reset($this->types)) instanceof TNamedObject && $single_type->value === 'Generator'; } /** * @psalm-mutation-free */ public function isSingle() : bool { $type_count = count($this->types); $int_literal_count = count($this->literal_int_types); $string_literal_count = count($this->literal_string_types); $float_literal_count = count($this->literal_float_types); if ($int_literal_count && $string_literal_count || $int_literal_count && $float_literal_count || $string_literal_count && $float_literal_count) { return \false; } if ($int_literal_count || $string_literal_count || $float_literal_count) { $type_count -= $int_literal_count + $string_literal_count + $float_literal_count - 1; } return $type_count === 1; } /** * @psalm-mutation-free */ public function isSingleAndMaybeNullable() : bool { $is_nullable = isset($this->types['null']); $type_count = count($this->types); if ($type_count === 1 && $is_nullable) { return \false; } $int_literal_count = count($this->literal_int_types); $string_literal_count = count($this->literal_string_types); $float_literal_count = count($this->literal_float_types); if ($int_literal_count && $string_literal_count || $int_literal_count && $float_literal_count || $string_literal_count && $float_literal_count) { return \false; } if ($int_literal_count || $string_literal_count || $float_literal_count) { $type_count -= $int_literal_count + $string_literal_count + $float_literal_count - 1; } return $type_count - (int) $is_nullable === 1; } /** * @psalm-mutation-free * @return bool true if this is an int */ public function isInt(bool $check_templates = \false) : bool { return count(array_filter($this->types, static fn($type): bool => $type instanceof TInt || $check_templates && $type instanceof TTemplateParam && $type->as->isInt())) === count($this->types); } /** * @psalm-mutation-free * @return bool true if this is a float */ public function isFloat() : bool { if (!$this->isSingle()) { return \false; } return isset($this->types['float']) || $this->literal_float_types; } /** * @psalm-mutation-free * @return bool true if this is a string */ public function isString(bool $check_templates = \false) : bool { return count(array_filter($this->types, static fn($type): bool => $type instanceof TString || $check_templates && $type instanceof TTemplateParam && $type->as->isString())) === count($this->types); } /** * @psalm-mutation-free * @return bool true if this is a string */ public function isNonEmptyString(bool $check_templates = \false) : bool { return count(array_filter($this->types, static fn($type): bool => $type instanceof TNonEmptyString || $type instanceof TLiteralString && $type->value !== '' || $check_templates && $type instanceof TTemplateParam && $type->as->isNonEmptyString())) === count($this->types); } /** * @psalm-mutation-free * @return bool true if this is a boolean */ public function isBool() : bool { if (!$this->isSingle()) { return \false; } return isset($this->types['bool']); } /** * @psalm-mutation-free * @return bool true if this is an array */ public function isArray() : bool { if (!$this->isSingle()) { return \false; } return isset($this->types['array']); } /** * @psalm-mutation-free * @return bool true if this is a string literal with only one possible value */ public function isSingleStringLiteral() : bool { return count($this->types) === 1 && count($this->literal_string_types) === 1; } /** * @throws InvalidArgumentException if isSingleStringLiteral is false * @psalm-mutation-free * @return TLiteralString the only string literal represented by this union type */ public function getSingleStringLiteral() : TLiteralString { if (count($this->types) !== 1 || count($this->literal_string_types) !== 1) { throw new InvalidArgumentException('Not a string literal'); } return reset($this->literal_string_types); } /** * @psalm-mutation-free */ public function allStringLiterals() : bool { foreach ($this->types as $atomic_key_type) { if (!$atomic_key_type instanceof TLiteralString) { return \false; } } return \true; } /** * @psalm-mutation-free */ public function allIntLiterals() : bool { foreach ($this->types as $atomic_key_type) { if (!$atomic_key_type instanceof TLiteralInt) { return \false; } } return \true; } /** * @psalm-mutation-free */ public function allFloatLiterals() : bool { foreach ($this->types as $atomic_key_type) { if (!$atomic_key_type instanceof TLiteralFloat) { return \false; } } return \true; } /** * @psalm-mutation-free * @psalm-assert-if-true array< * array-key, * TLiteralString|TLiteralInt|TLiteralFloat|TFalse|TTrue * > $this->getAtomicTypes() */ public function allSpecificLiterals() : bool { foreach ($this->types as $atomic_key_type) { if (!$atomic_key_type instanceof TLiteralString && !$atomic_key_type instanceof TLiteralInt && !$atomic_key_type instanceof TLiteralFloat && !$atomic_key_type instanceof TFalse && !$atomic_key_type instanceof TTrue) { return \false; } } return \true; } /** * @psalm-mutation-free * @psalm-assert-if-true array< * array-key, * TLiteralString|TLiteralInt|TLiteralFloat|TNonspecificLiteralString|TNonSpecificLiteralInt|TFalse|TTrue * > $this->getAtomicTypes() */ public function allLiterals() : bool { foreach ($this->types as $atomic_key_type) { if (!$atomic_key_type instanceof TLiteralString && !$atomic_key_type instanceof TLiteralInt && !$atomic_key_type instanceof TLiteralFloat && !$atomic_key_type instanceof TNonspecificLiteralString && !$atomic_key_type instanceof TNonspecificLiteralInt && !$atomic_key_type instanceof TFalse && !$atomic_key_type instanceof TTrue) { return \false; } } return \true; } /** * @psalm-mutation-free */ public function hasLiteralValue() : bool { return $this->literal_int_types || $this->literal_string_types || $this->literal_float_types || isset($this->types['false']) || isset($this->types['true']); } /** * @psalm-mutation-free */ public function isSingleLiteral() : bool { return count($this->types) === 1 && count($this->literal_int_types) + count($this->literal_string_types) + count($this->literal_float_types) === 1; } /** * @psalm-mutation-free * @return TLiteralInt|TLiteralString|TLiteralFloat */ public function getSingleLiteral() { if (!$this->isSingleLiteral()) { throw new InvalidArgumentException("Not a single literal"); } return ($literal = reset($this->literal_int_types)) !== \false ? $literal : (($literal = reset($this->literal_string_types)) !== \false ? $literal : reset($this->literal_float_types)); } /** * @psalm-mutation-free */ public function hasLiteralString() : bool { return count($this->literal_string_types) > 0; } /** * @psalm-mutation-free */ public function hasLiteralInt() : bool { return count($this->literal_int_types) > 0; } /** * @psalm-mutation-free * @return bool true if this is a int literal with only one possible value */ public function isSingleIntLiteral() : bool { return count($this->types) === 1 && count($this->literal_int_types) === 1; } /** * @throws InvalidArgumentException if isSingleIntLiteral is false * @psalm-mutation-free * @return TLiteralInt the only int literal represented by this union type */ public function getSingleIntLiteral() : TLiteralInt { if (count($this->types) !== 1 || count($this->literal_int_types) !== 1) { throw new InvalidArgumentException('Not an int literal'); } return reset($this->literal_int_types); } /** * @param array $suppressed_issues * @param array $phantom_classes */ public function check(StatementsSource $source, CodeLocation $code_location, array $suppressed_issues, array $phantom_classes = [], bool $inferred = \true, bool $inherited = \false, bool $prevent_template_covariance = \false, ?string $calling_method_id = null) : bool { if ($this->checked) { return \true; } $checker = new TypeChecker($source, $code_location, $suppressed_issues, $phantom_classes, $inferred, $inherited, $prevent_template_covariance, $calling_method_id); $checker->traverseArray($this->types); /** @psalm-suppress InaccessibleProperty, ImpurePropertyAssignment Does not affect anything else */ $this->checked = \true; return !$checker->hasErrors(); } /** * @param array $phantom_classes */ public function queueClassLikesForScanning(Codebase $codebase, ?FileStorage $file_storage = null, array $phantom_classes = []) : void { $scanner_visitor = new TypeScanner($codebase->scanner, $file_storage, $phantom_classes); /** @psalm-suppress ImpureMethodCall */ $scanner_visitor->traverseArray($this->types); } /** * @param lowercase-string $fq_class_like_name * @psalm-mutation-free */ public function containsClassLike(string $fq_class_like_name) : bool { $classlike_visitor = new ContainsClassLikeVisitor($fq_class_like_name); /** @psalm-suppress ImpureMethodCall Actually mutation-free */ $classlike_visitor->traverseArray($this->types); return $classlike_visitor->matches(); } /** * @return static */ public function replaceClassLike(string $old, string $new) : self { $type = $this; (new ClasslikeReplacer($old, $new))->traverse($type); return $type; } /** @psalm-mutation-free */ public function containsAnyLiteral() : bool { $literal_visitor = new ContainsLiteralVisitor(); /** @psalm-suppress ImpureMethodCall Actually mutation-free */ $literal_visitor->traverseArray($this->types); return $literal_visitor->matches(); } /** * @psalm-mutation-free * @return list */ public function getTemplateTypes() : array { $template_type_collector = new TemplateTypeCollector(); /** @psalm-suppress ImpureMethodCall Actually mutation-free */ $template_type_collector->traverseArray($this->types); return $template_type_collector->getTemplateTypes(); } /** * @psalm-mutation-free */ public function equals(self $other_type, bool $ensure_source_equality = \true, bool $ensure_parent_node_equality = \true, bool $ensure_possibly_undefined_equality = \true) : bool { if ($other_type === $this) { return \true; } if ($other_type->id && $this->id && $other_type->id !== $this->id) { return \false; } if ($other_type->exact_id && $this->exact_id && $other_type->exact_id !== $this->exact_id) { return \false; } if ($this->possibly_undefined !== $other_type->possibly_undefined && $ensure_possibly_undefined_equality) { return \false; } if ($this->had_template !== $other_type->had_template) { return \false; } if ($this->possibly_undefined_from_try !== $other_type->possibly_undefined_from_try) { return \false; } if ($this->from_calculation !== $other_type->from_calculation) { return \false; } if ($this->initialized !== $other_type->initialized) { return \false; } if ($ensure_source_equality && $this->from_docblock !== $other_type->from_docblock) { return \false; } if (count($this->types) !== count($other_type->types)) { return \false; } if ($ensure_parent_node_equality && $this->parent_nodes !== $other_type->parent_nodes) { return \false; } if ($this->different || $other_type->different) { return \false; } $other_atomic_types = $other_type->types; foreach ($this->types as $key => $atomic_type) { if (!isset($other_atomic_types[$key])) { return \false; } if (!$atomic_type->equals($other_atomic_types[$key], $ensure_source_equality)) { return \false; } } return \true; } /** * @psalm-mutation-free * @return array */ public function getLiteralStrings() : array { return $this->literal_string_types; } /** * @psalm-mutation-free * @return array */ public function getLiteralInts() : array { return $this->literal_int_types; } /** * @psalm-mutation-free * @return array */ public function getRangeInts() : array { $ranges = []; foreach ($this->getAtomicTypes() as $atomic) { if ($atomic instanceof TIntRange) { $ranges[$atomic->getKey()] = $atomic; } } return $ranges; } /** * @psalm-mutation-free * @return array */ public function getLiteralFloats() : array { return $this->literal_float_types; } /** * @psalm-mutation-free * @return bool true if this is a float literal with only one possible value */ public function isSingleFloatLiteral() : bool { return count($this->types) === 1 && count($this->literal_float_types) === 1; } /** * @psalm-mutation-free * @throws InvalidArgumentException if isSingleFloatLiteral is false * @return TLiteralFloat the only float literal represented by this union type */ public function getSingleFloatLiteral() : TLiteralFloat { if (count($this->types) !== 1 || count($this->literal_float_types) !== 1) { throw new InvalidArgumentException('Not a float literal'); } return reset($this->literal_float_types); } /** * @psalm-mutation-free */ public function hasLiteralFloat() : bool { return count($this->literal_float_types) > 0; } /** * @psalm-mutation-free */ public function getSingleAtomic() : \Psalm\Type\Atomic { return reset($this->types); } /** * @psalm-mutation-free */ public function isEmptyArray() : bool { return count($this->types) === 1 && isset($this->types['array']) && $this->types['array'] instanceof TArray && $this->types['array']->isEmptyArray(); } /** * @psalm-mutation-free */ public function isUnionEmpty() : bool { return $this->types === []; } public function visit(\Psalm\Type\TypeVisitor $visitor) : bool { foreach ($this->types as $type) { if ($visitor->traverse($type) === \false) { return \false; } } return \true; } } from_docblock = $from_docblock; } protected function __clone() { } /** * Whether or not the type has been checked yet * * @var bool */ public $checked = \false; /** * Whether or not the type comes from a docblock * * @var bool */ public $from_docblock = \false; /** * @var ?int */ public $offset_start; /** * @var ?int */ public $offset_end; /** * @var ?string */ public $text; /** * @return static */ public function setFromDocblock(bool $from_docblock) : self { if ($from_docblock === $this->from_docblock) { return $this; } $cloned = clone $this; $cloned->from_docblock = $from_docblock; return $cloned; } /** * @return static */ public function replaceClassLike(string $old, string $new) : self { $type = $this; /** @psalm-suppress ImpureMethodCall ClasslikeReplacer will always clone */ (new ClasslikeReplacer($old, $new))->traverse($type); return $type; } /** * @psalm-suppress InaccessibleProperty Allowed during construction * @param int $analysis_php_version_id contains php version when the type comes from signature * @param array> $template_type_map * @param array $type_aliases */ public static function create(string $value, ?int $analysis_php_version_id = null, array $template_type_map = [], array $type_aliases = [], ?int $offset_start = null, ?int $offset_end = null, ?string $text = null, bool $from_docblock = \false) : \Psalm\Type\Atomic { $result = self::createInner($value, $analysis_php_version_id, $template_type_map, $type_aliases, $from_docblock); $result->offset_start = $offset_start; $result->offset_end = $offset_end; $result->text = $text; $result->from_docblock = $from_docblock; return $result; } /** * @psalm-suppress InaccessibleProperty Allowed during construction * @param int $analysis_php_version_id contains php version when the type comes from signature * @param array> $template_type_map * @param array $type_aliases */ private static function createInner(string $value, ?int $analysis_php_version_id = null, array $template_type_map = [], array $type_aliases = [], bool $from_docblock = \false) : \Psalm\Type\Atomic { switch ($value) { case 'int': return new TInt(); case 'float': return new TFloat(); case 'string': return new TString(); case 'bool': return new TBool(); case 'void': if ($analysis_php_version_id === null || $analysis_php_version_id >= 70100) { return new TVoid(); } break; case 'array-key': return new TArrayKey(); case 'iterable': if ($analysis_php_version_id === null || $analysis_php_version_id >= 70100) { return new TIterable(); } break; case 'never': if ($analysis_php_version_id === null || $analysis_php_version_id >= 80100) { return new TNever(); } break; case 'never-return': case 'never-returns': case 'no-return': case 'empty': return new TNever(); case 'object': if ($analysis_php_version_id === null || $analysis_php_version_id >= 70200) { return new TObject(); } break; case 'callable': return new TCallable(); case 'pure-callable': $type = new TCallable(); $type->is_pure = \true; return $type; case 'array': case 'associative-array': return new TArray([new \Psalm\Type\Union([new TArrayKey($from_docblock)]), new \Psalm\Type\Union([new TMixed(\false, $from_docblock)])]); case 'non-empty-array': return new TNonEmptyArray([new \Psalm\Type\Union([new TArrayKey($from_docblock)]), new \Psalm\Type\Union([new TMixed(\false, $from_docblock)])]); case 'callable-array': return new TCallableArray([new \Psalm\Type\Union([new TArrayKey($from_docblock)]), new \Psalm\Type\Union([new TMixed(\false, $from_docblock)])]); case 'list': return Type::getListAtomic(Type::getMixed(\false, $from_docblock)); case 'non-empty-list': return Type::getNonEmptyListAtomic(Type::getMixed(\false, $from_docblock)); case 'non-empty-string': return new TNonEmptyString(); case 'truthy-string': case 'non-falsy-string': return new TNonFalsyString(); case 'lowercase-string': return new TLowercaseString(); case 'non-empty-lowercase-string': return new TNonEmptyLowercaseString(); case 'resource': return $analysis_php_version_id !== null ? new TNamedObject($value) : new TResource(); case 'resource (closed)': case 'closed-resource': return new TClosedResource(); case 'positive-int': return new TIntRange(1, null); case 'non-positive-int': return new TIntRange(null, 0); case 'negative-int': return new TIntRange(null, -1); case 'non-negative-int': return new TIntRange(0, null); case 'numeric': return $analysis_php_version_id !== null ? new TNamedObject($value) : new TNumeric(); case 'true': if ($analysis_php_version_id === null || $analysis_php_version_id >= 80200) { return new TTrue(); } return new TNamedObject($value); case 'false': if ($analysis_php_version_id === null || $analysis_php_version_id >= 80000) { return new TFalse(); } return new TNamedObject($value); case 'scalar': return $analysis_php_version_id !== null ? new TNamedObject($value) : new TScalar(); case 'null': if ($analysis_php_version_id === null || $analysis_php_version_id >= 70000) { return new TNull(); } return new TNamedObject($value); case 'mixed': if ($analysis_php_version_id === null || $analysis_php_version_id >= 80000) { return new TMixed(); } return new TNamedObject($value); case 'callable-object': return new TCallableObject(); case 'stringable-object': return new TObjectWithProperties([], ['__tostring' => 'string']); case 'class-string': return new TClassString(); case 'interface-string': $type = new TClassString(); $type->is_interface = \true; return $type; case 'enum-string': $type = new TClassString(); $type->is_enum = \true; return $type; case 'trait-string': return new TTraitString(); case 'callable-string': return new TCallableString(); case 'numeric-string': return new TNumericString(); case 'literal-string': return new TNonspecificLiteralString(); case 'non-empty-literal-string': return new TNonEmptyNonspecificLiteralString(); case 'literal-int': return new TNonspecificLiteralInt(); case '$this': return new TNamedObject('static'); case 'non-empty-scalar': return new TNonEmptyScalar(); case 'empty-scalar': return new TEmptyScalar(); case 'non-empty-mixed': return new TNonEmptyMixed(); case 'Closure': return new TClosure('Closure'); } if (strpos($value, '-') && strpos($value, 'OCI-') !== 0) { throw new TypeParseTreeException('Unrecognized type ' . $value); } if (is_numeric($value[0])) { throw new TypeParseTreeException('First character of type cannot be numeric'); } if (isset($template_type_map[$value])) { $first_class = array_keys($template_type_map[$value])[0]; return new TTemplateParam($value, $template_type_map[$value][$first_class], $first_class); } if (isset($type_aliases[$value])) { $type_alias = $type_aliases[$value]; if ($type_alias instanceof LinkableTypeAlias) { return new TTypeAlias($type_alias->declaring_fq_classlike_name, $type_alias->alias_name); } throw new TypeParseTreeException('Invalid type alias ' . $value . ' provided'); } return new TNamedObject($value); } /** * This is the string that will be used to represent the type in Union::$types. This means that two types sharing * the same getKey value will override themselves in an Union */ public abstract function getKey(bool $include_extra = \true) : string; public function isNumericType() : bool { return $this instanceof TInt || $this instanceof TFloat || $this instanceof TNumericString || $this instanceof TNumeric || $this instanceof TLiteralString && is_numeric($this->value); } public function isObjectType() : bool { return $this instanceof TObject || $this instanceof TNamedObject || $this instanceof TTemplateParam && $this->as->hasObjectType(); } public function isNamedObjectType() : bool { return $this instanceof TNamedObject || $this instanceof TTemplateParam && ($this->as->hasNamedObjectType() || array_filter($this->extra_types, static fn($extra_type): bool => $extra_type->isNamedObjectType())); } public function isCallableType() : bool { return $this instanceof TCallable || $this instanceof TCallableObject || $this instanceof TCallableString || $this instanceof TCallableArray || $this instanceof TCallableList || $this instanceof TCallableKeyedArray || $this instanceof TClosure; } public function isIterable(Codebase $codebase) : bool { return $this instanceof TIterable || $this->hasTraversableInterface($codebase) || $this instanceof TArray || $this instanceof TList || $this instanceof TKeyedArray; } /** * @throws InvalidArgumentException if $this is not an iterable type. */ public function getIterable(Codebase $codebase) : TIterable { if ($this instanceof TIterable) { return $this; } if ($this instanceof TArray) { return new TIterable($this->type_params); } if ($this instanceof TKeyedArray) { return new TIterable([$this->getGenericKeyType(), $this->getGenericValueType()]); } if ($this->hasTraversableInterface($codebase)) { if (strtolower($this->value) === "traversable") { if ($this instanceof TGenericObject) { if (count($this->type_params) > 2) { throw new InvalidArgumentException('Too many templates!'); } return new TIterable($this->type_params); } return new TIterable([Type::getMixed(), Type::getMixed()]); } $implemented_traversable_templates = TemplateStandinTypeReplacer::getMappedGenericTypeParams($codebase, $this, new TGenericObject("Traversable", [Type::getMixed(), Type::getMixed()])); if (count($implemented_traversable_templates) > 2) { throw new InvalidArgumentException('Too many templates!'); } return new TIterable($implemented_traversable_templates); } throw new InvalidArgumentException("{$this->getId()} is not an iterable"); } public function isCountable(Codebase $codebase) : bool { return $this->hasCountableInterface($codebase) || $this instanceof TArray || $this instanceof TKeyedArray || $this instanceof TList; } /** * @psalm-assert-if-true TNamedObject $this */ public function hasTraversableInterface(Codebase $codebase) : bool { return $this instanceof TNamedObject && (strtolower($this->value) === 'traversable' || $codebase->classOrInterfaceExists($this->value) && ($codebase->classExtendsOrImplements($this->value, 'Traversable') || $codebase->interfaceExtends($this->value, 'Traversable')) || $this->extra_types && array_filter($this->extra_types, static fn(\Psalm\Type\Atomic $a): bool => $a->hasTraversableInterface($codebase))); } public function hasCountableInterface(Codebase $codebase) : bool { return $this instanceof TNamedObject && (strtolower($this->value) === 'countable' || $codebase->classOrInterfaceExists($this->value) && ($codebase->classExtendsOrImplements($this->value, 'Countable') || $codebase->interfaceExtends($this->value, 'Countable')) || $this->extra_types && array_filter($this->extra_types, static fn(\Psalm\Type\Atomic $a): bool => $a->hasCountableInterface($codebase))); } public function isArrayAccessibleWithStringKey(Codebase $codebase) : bool { return $this instanceof TArray || $this instanceof TKeyedArray || $this instanceof TClassStringMap || $this->hasArrayAccessInterface($codebase) || $this instanceof TNamedObject && $this->value === 'SimpleXMLElement'; } public function isArrayAccessibleWithIntOrStringKey(Codebase $codebase) : bool { return $this instanceof TString || $this->isArrayAccessibleWithStringKey($codebase); } public function hasArrayAccessInterface(Codebase $codebase) : bool { return $this instanceof TNamedObject && (strtolower($this->value) === 'arrayaccess' || $codebase->classOrInterfaceExists($this->value) && ($codebase->classExtendsOrImplements($this->value, 'ArrayAccess') || $codebase->interfaceExtends($this->value, 'ArrayAccess')) || $this->extra_types && array_filter($this->extra_types, static fn(\Psalm\Type\Atomic $a): bool => $a->hasArrayAccessInterface($codebase))); } public function visit(\Psalm\Type\TypeVisitor $visitor) : bool { foreach ($this->getChildNodeKeys() as $key) { /** @psalm-suppress MixedAssignment */ $value = $this->{$key}; if (is_array($value)) { /** @psalm-suppress MixedAssignment */ foreach ($value as $type) { if (!$type instanceof \Psalm\Type\TypeNode) { continue; } if ($visitor->traverse($type) === \false) { return \false; } } } elseif ($value instanceof \Psalm\Type\TypeNode) { if ($visitor->traverse($value) === \false) { return \false; } } } return \true; } /** * @phpcsSuppress SlevomatCodingStandard.TypeHints.ParameterTypeHint.MissingAnyTypeHint */ public static function visitMutable(\Psalm\Type\MutableTypeVisitor $visitor, &$node, bool $cloned) : bool { foreach ($node->getChildNodeKeys() as $key) { /** @psalm-suppress MixedAssignment */ $value = $node->{$key}; $result = \true; if (is_array($value)) { $changed = \false; /** @psalm-suppress MixedAssignment */ foreach ($value as &$type) { if (!$type instanceof \Psalm\Type\TypeNode) { continue; } $type_orig = $type; $result = $visitor->traverse($type); $changed = $changed || $type !== $type_orig; } unset($type); } elseif ($value instanceof \Psalm\Type\TypeNode) { $value_orig = $value; $result = $visitor->traverse($value); $changed = $value !== $value_orig; } else { continue; } if ($changed) { if (!$cloned) { $node = clone $node; $cloned = \true; } if ($key === 'extra_types') { /** @var array $value */ $new = []; foreach ($value as $type) { $new[$type->getKey()] = $type; } $value = $new; } $node->{$key} = $value; } if ($result === \false) { return \false; } } return \true; } /** @return list */ protected function getChildNodeKeys() : array { return []; } public final function __toString() : string { return $this->getId(); } /** * This is the true identifier for the type. It defaults to self::getKey() but can be overrided to be more precise */ public function getId(bool $exact = \true, bool $nested = \false) : string { return $this->getKey(); } /** * This string is used in order to transform a type into an string assertion for the assertion module * Default to self::getId() */ public function getAssertionString() : string { return $this->getId(); } /** * Returns the detailed description of the type, either in phpdoc standard format or Psalm format depending on flag * Default to self::getKey() * * @param array $aliased_classes */ public function toNamespacedString(?string $namespace, array $aliased_classes, ?string $this_class, bool $use_phpdoc_format) : string { return $this->getKey(); } /** * Returns a string representation of the type compatible with php signature or null if the type can't be expressed * with the given php version * * @param array $aliased_classes */ public abstract function toPhpString(?string $namespace, array $aliased_classes, ?string $this_class, int $analysis_php_version_id) : ?string; public abstract function canBeFullyExpressedInPhp(int $analysis_php_version_id) : bool; /** * @return static */ public function replaceTemplateTypesWithStandins(TemplateResult $template_result, Codebase $codebase, ?StatementsAnalyzer $statements_analyzer = null, ?\Psalm\Type\Atomic $input_type = null, ?int $input_arg_offset = null, ?string $calling_class = null, ?string $calling_function = null, bool $replace = \true, bool $add_lower_bound = \false, int $depth = 0) : self { // do nothing return $this; } /** * @return static */ public function replaceTemplateTypesWithArgTypes(TemplateResult $template_result, ?Codebase $codebase) : self { // do nothing return $this; } public function equals(\Psalm\Type\Atomic $other_type, bool $ensure_source_equality) : bool { return get_class($other_type) === get_class($this); } public function isTruthy() : bool { if ($this instanceof TTrue) { return \true; } if ($this instanceof TLiteralInt && $this->value !== 0) { return \true; } if ($this instanceof TLiteralFloat && $this->value !== 0.0) { return \true; } if ($this instanceof TLiteralString && ($this->value !== '' && $this->value !== '0')) { return \true; } if ($this instanceof TNonFalsyString) { return \true; } if ($this instanceof TNonEmptyArray) { return \true; } if ($this instanceof TNonEmptyScalar) { return \true; } if ($this instanceof TNonEmptyMixed) { return \true; } if ($this instanceof TObject) { return \true; } if ($this instanceof TNamedObject && $this->value !== 'SimpleXMLElement' && $this->value !== 'SimpleXMLIterator') { return \true; } if ($this instanceof TIntRange && !$this->contains(0)) { return \true; } if ($this instanceof TLiteralClassString) { return \true; } if ($this instanceof TClassString) { return \true; } if ($this instanceof TDependentGetClass) { return \true; } if ($this instanceof TTraitString) { return \true; } if ($this instanceof TResource) { return \true; } if ($this instanceof TKeyedArray) { return $this->isNonEmpty(); } if ($this instanceof TTemplateParam && $this->as->isAlwaysTruthy()) { return \true; } //we can't be sure the type is always truthy return \false; } public function isFalsy() : bool { if ($this instanceof TFalse) { return \true; } if ($this instanceof TLiteralInt && $this->value === 0) { return \true; } if ($this instanceof TLiteralFloat && $this->value === 0.0) { return \true; } if ($this instanceof TLiteralString && ($this->value === '' || $this->value === '0')) { return \true; } if ($this instanceof TNull) { return \true; } if ($this instanceof TEmptyMixed) { return \true; } if ($this instanceof TEmptyNumeric) { return \true; } if ($this instanceof TEmptyScalar) { return \true; } if ($this instanceof TTemplateParam && $this->as->isAlwaysFalsy()) { return \true; } if ($this instanceof TIntRange && $this->min_bound === 0 && $this->max_bound === 0) { return \true; } if ($this instanceof TArray && $this->isEmptyArray()) { return \true; } //we can't be sure the type is always falsy return \false; } } * } */ final class Union implements \Psalm\Type\TypeNode { use ImmutableNonCloneableTrait; use \Psalm\Type\UnionTrait; /** * @psalm-readonly * @var non-empty-array */ private array $types; /** * Whether the type originated in a docblock * * @var bool */ public $from_docblock = \false; /** * Whether the type originated from integer calculation * * @var bool */ public $from_calculation = \false; /** * Whether the type originated from a property * * This helps turn isset($foo->bar) into a different sort of issue * * @var bool */ public $from_property = \false; /** * Whether the type originated from *static* property * * Unlike non-static properties, static properties have no prescribed place * like __construct() to be initialized in * * @var bool */ public $from_static_property = \false; /** * Whether the property that this type has been derived from has been initialized in a constructor * * @var bool */ public $initialized = \true; /** * Which class the type was initialised in * * @var ?string */ public $initialized_class; /** * Whether or not the type has been checked yet * * @var bool */ public $checked = \false; /** * @var bool */ public $failed_reconciliation = \false; /** * Whether or not to ignore issues with possibly-null values * * @var bool */ public $ignore_nullable_issues = \false; /** * Whether or not to ignore issues with possibly-false values * * @var bool */ public $ignore_falsable_issues = \false; /** * Whether or not to ignore issues with isset on this type * * @var bool */ public $ignore_isset = \false; /** * Whether or not this variable is possibly undefined * * @var bool */ public $possibly_undefined = \false; /** * Whether or not this variable is possibly undefined * * @var bool */ public $possibly_undefined_from_try = \false; /** * whether this type had never set explicitly * since it's the bottom type, it's combined into everything else and lost * * @var bool */ public $explicit_never = \false; /** * Whether or not this union had a template, since replaced * * @var bool */ public $had_template = \false; /** * Whether or not this union comes from a template "as" default * * @var bool */ public $from_template_default = \false; /** * @var array */ private array $literal_string_types = []; /** * @var array */ private array $typed_class_strings = []; /** * @var array */ private array $literal_int_types = []; /** * @var array */ private array $literal_float_types = []; /** * True if the type was passed or returned by reference, or if the type refers to an object's * property or an item in an array. Note that this is not true for locally created references * that don't refer to properties or array items (see Context::$references_in_scope). * * @var bool */ public $by_ref = \false; /** * @var bool */ public $reference_free = \false; /** * @var bool */ public $allow_mutations = \true; /** * @var bool */ public $has_mutations = \true; /** * This is a cache of getId on non-exact mode */ private ?string $id = null; /** * This is a cache of getId on exact mode */ private ?string $exact_id; /** * @var array */ public $parent_nodes = []; public bool $propagate_parent_nodes = \false; /** * @var bool */ public $different = \false; private const PROPERTY_KEYS_FOR_UNSERIALIZE = ["\x00" . self::class . "\x00" . 'types' => 'types', 'from_docblock' => 'from_docblock', 'from_calculation' => 'from_calculation', 'from_property' => 'from_property', 'from_static_property' => 'from_static_property', 'initialized' => 'initialized', 'initialized_class' => 'initialized_class', 'checked' => 'checked', 'failed_reconciliation' => 'failed_reconciliation', 'ignore_nullable_issues' => 'ignore_nullable_issues', 'ignore_falsable_issues' => 'ignore_falsable_issues', 'ignore_isset' => 'ignore_isset', 'possibly_undefined' => 'possibly_undefined', 'possibly_undefined_from_try' => 'possibly_undefined_from_try', 'explicit_never' => 'explicit_never', 'had_template' => 'had_template', 'from_template_default' => 'from_template_default', "\x00" . self::class . "\x00" . 'literal_string_types' => 'literal_string_types', "\x00" . self::class . "\x00" . 'typed_class_strings' => 'typed_class_strings', "\x00" . self::class . "\x00" . 'literal_int_types' => 'literal_int_types', "\x00" . self::class . "\x00" . 'literal_float_types' => 'literal_float_types', 'by_ref' => 'by_ref', 'reference_free' => 'reference_free', 'allow_mutations' => 'allow_mutations', 'has_mutations' => 'has_mutations', "\x00" . self::class . "\x00" . 'id' => 'id', "\x00" . self::class . "\x00" . 'exact_id' => 'exact_id', 'parent_nodes' => 'parent_nodes', 'propagate_parent_nodes' => 'propagate_parent_nodes', 'different' => 'different']; /** * Suppresses memory usage when unserializing objects. * * @see \Psalm\Storage\UnserializeMemoryUsageSuppressionTrait */ public function __unserialize(array $properties) : void { foreach (self::PROPERTY_KEYS_FOR_UNSERIALIZE as $key => $property_name) { /** @psalm-suppress PossiblyUndefinedStringArrayOffset */ $this->{$property_name} = $properties[$key]; } } /** * @param TProperties $properties * @return static */ public function setProperties(array $properties) : self { $obj = null; foreach ($properties as $key => $value) { if ($this->{$key} !== $value) { if ($obj === null) { $obj = clone $this; } /** @psalm-suppress ImpurePropertyAssignment We just cloned this object */ $obj->{$key} = $value; } } return $obj ?? $this; } /** * @return static */ public function setDifferent(bool $different) : self { if ($different === $this->different) { return $this; } $cloned = clone $this; $cloned->different = $different; return $cloned; } /** * @param array $parent_nodes * @return static */ public function setParentNodes(array $parent_nodes, bool $propagate_changes = \false) : self { if ($parent_nodes === $this->parent_nodes) { return $this; } $cloned = clone $this; $cloned->parent_nodes = $parent_nodes; $cloned->propagate_parent_nodes = $propagate_changes; return $cloned; } /** * @param array $parent_nodes * @return static */ public function addParentNodes(array $parent_nodes) : self { if (!$parent_nodes) { return $this; } $parent_nodes = $this->parent_nodes + $parent_nodes; if ($parent_nodes === $this->parent_nodes) { return $this; } $cloned = clone $this; $cloned->parent_nodes = $parent_nodes; return $cloned; } /** @return static */ public function setPossiblyUndefined(bool $possibly_undefined, ?bool $from_try = null) : self { $from_try ??= $this->possibly_undefined_from_try; if ($this->possibly_undefined === $possibly_undefined && $this->possibly_undefined_from_try == $from_try) { return $this; } $cloned = clone $this; $cloned->possibly_undefined = $possibly_undefined; $cloned->possibly_undefined_from_try = $from_try; return $cloned; } /** @return static */ public function setByRef(bool $by_ref) { if ($by_ref === $this->by_ref) { return $this; } $cloned = clone $this; $cloned->by_ref = $by_ref; return $cloned; } /** * @psalm-mutation-free * @param non-empty-array $types */ public function setTypes(array $types) : self { if ($types === $this->types) { return $this; } return $this->getBuilder()->setTypes($types)->freeze(); } /** * @psalm-mutation-free */ public function getBuilder() : \Psalm\Type\MutableUnion { /** @psalm-suppress InvalidArgument It's actually filtered internally */ return new \Psalm\Type\MutableUnion($this->getAtomicTypes(), get_object_vars($this)); } /** * @psalm-mutation-free */ public function setFromDocblock(bool $fromDocblock = \true) : self { $cloned = clone $this; /** @psalm-suppress ImpureMethodCall Acting on clone */ (new FromDocblockSetter($fromDocblock))->traverse($cloned); return $cloned; } /** * @phpcsSuppress SlevomatCodingStandard.TypeHints.ParameterTypeHint.MissingAnyTypeHint */ public static function visitMutable(\Psalm\Type\MutableTypeVisitor $visitor, &$node, bool $cloned) : bool { $result = \true; $changed = \false; $types = $node->types; foreach ($types as &$type) { $type_orig = $type; $result = $visitor->traverse($type); $changed = $changed || $type_orig !== $type; if (!$result) { break; } } unset($type); if ($changed) { $node = $node->setTypes($types); } return $result; } } getText(), $docblock->getStartFilePos()); if ($no_psalm_error) { return $parsed_docblock; } foreach ($parsed_docblock->tags as $special_key => $_) { if (strpos($special_key, 'psalm-') === 0) { $special_key = substr($special_key, 6); if (!in_array($special_key, self::PSALM_ANNOTATIONS, \true)) { throw new DocblockParseException('Unrecognised annotation @psalm-' . $special_key); } } } return $parsed_docblock; } /** * @psalm-pure * @return array */ public static function parseSuppressList(string $suppress_entry) : array { preg_match('/ (?(DEFINE) # either a single issue or comma separated list of issues (? (?&issue) \\s* , \\s* (?&issue_list) | (?&issue) ) # definition of a single issue (? [A-Za-z0-9_-]+ ) ) ^ (?P (?&issue_list) ) (?P .* ) $ /xm', $suppress_entry, $matches); if (!isset($matches['issues'])) { return []; } $issue_offset = 0; $ret = []; foreach (explode(',', $matches['issues']) as $suppressed_issue) { $issue_offset += strspn($suppressed_issue, "\t\n\f\r "); $ret[$issue_offset] = trim($suppressed_issue); $issue_offset += strlen($suppressed_issue) + 1; } return $ret; } } */ public $uses; /** * @var array */ public $uses_flipped; /** * @var array */ public $functions; /** * @var array */ public $functions_flipped; /** * @var array */ public $constants; /** * @var array */ public $constants_flipped; /** @var string|null */ public $namespace; /** @var ?int */ public $namespace_first_stmt_start; /** @var ?int */ public $uses_start; /** @var ?int */ public $uses_end; /** * @param array $uses * @param array $functions * @param array $constants * @param array $uses_flipped * @param array $functions_flipped * @param array $constants_flipped * @internal * @psalm-mutation-free */ public function __construct(?string $namespace = null, array $uses = [], array $functions = [], array $constants = [], array $uses_flipped = [], array $functions_flipped = [], array $constants_flipped = []) { $this->namespace = $namespace; $this->uses = $uses; $this->functions = $functions; $this->constants = $constants; $this->uses_flipped = $uses_flipped; $this->functions_flipped = $functions_flipped; $this->constants_flipped = $constants_flipped; } } */ protected $issues_data; /** @var array */ protected $fixable_issue_counts; /** @var bool */ protected $use_color; /** @var bool */ protected $show_snippet; /** @var bool */ protected $show_info; /** @var bool */ protected $pretty; /** @var bool */ protected $in_ci; /** @var int */ protected $mixed_expression_count; /** @var int */ protected $total_expression_count; /** * @param array $issues_data * @param array $fixable_issue_counts */ public function __construct(array $issues_data, array $fixable_issue_counts, ReportOptions $report_options, int $mixed_expression_count = 1, int $total_expression_count = 1) { if (!$report_options->show_info) { $this->issues_data = array_filter($issues_data, static fn(IssueData $issue_data): bool => $issue_data->severity !== IssueData::SEVERITY_INFO); } else { $this->issues_data = $issues_data; } $this->fixable_issue_counts = $fixable_issue_counts; $this->use_color = $report_options->use_color; $this->show_snippet = $report_options->show_snippet; $this->show_info = $report_options->show_info; $this->pretty = $report_options->pretty; $this->in_ci = $report_options->in_ci; $this->mixed_expression_count = $mixed_expression_count; $this->total_expression_count = $total_expression_count; } protected function xmlEncode(string $data) : string { return htmlspecialchars($data, ENT_XML1 | ENT_QUOTES); } public abstract function create() : string; /** * @return array */ public static function getMapping() : array { return ['checkstyle.xml' => self::TYPE_CHECKSTYLE, 'sonarqube.json' => self::TYPE_SONARQUBE, 'codeclimate.json' => self::TYPE_CODECLIMATE, 'summary.json' => self::TYPE_JSON_SUMMARY, 'junit.xml' => self::TYPE_JUNIT, '.xml' => self::TYPE_XML, '.sarif.json' => self::TYPE_SARIF, '.json' => self::TYPE_JSON, '.txt' => self::TYPE_TEXT, '.emacs' => self::TYPE_EMACS, '.pylint' => self::TYPE_PYLINT, '.console' => self::TYPE_CONSOLE, '.sarif' => self::TYPE_SARIF, 'count.txt' => self::TYPE_COUNT]; } } fq_classlike_name = $fq_classlike_name; } } dupe_key = strtolower($method_id); } } property_id = $property_id; } } code_location = $code_location; $this->message = $message; $this->function_id = $function_id ? strtolower($function_id) : null; $this->origin_location = $origin_location; } } */ public const SHORTCODE = 0; /** * @var CodeLocation * @readonly */ public $code_location; /** * @var string * @readonly */ public $message; /** * @var ?string */ public $dupe_key; public function __construct(string $message, CodeLocation $code_location) { $this->code_location = $code_location; $this->message = $message; } public function getShortLocationWithPrevious() : string { $previous_text = ''; if ($this->code_location->previous_location) { $previous_location = $this->code_location->previous_location; $previous_text = ' from ' . $previous_location->file_name . ':' . $previous_location->getLineNumber(); } return $this->code_location->file_name . ':' . $this->code_location->getLineNumber() . $previous_text; } public function getShortLocation() : string { return $this->code_location->file_name . ':' . $this->code_location->getLineNumber(); } public function getFilePath() : string { return $this->code_location->file_path; } public static function getIssueType() : string { $fqcn_parts = explode('\\', static::class); return array_pop($fqcn_parts); } /** * @param IssueData::SEVERITY_* $severity */ public function toIssueData(string $severity) : IssueData { $location = $this->code_location; $selection_bounds = $location->getSelectionBounds(); $snippet_bounds = $location->getSnippetBounds(); return new IssueData($severity, $location->getLineNumber(), $location->getEndLineNumber(), static::getIssueType(), $this->message, $location->file_name, $location->file_path, $location->getSnippet(), $location->getSelectedText(), $selection_bounds[0], $selection_bounds[1], $snippet_bounds[0], $snippet_bounds[1], $location->getColumn(), $location->getEndColumn(), static::SHORTCODE, static::ERROR_LEVEL, $this instanceof \Psalm\Issue\TaintedInput ? $this->getTaintTrace() : null, $this instanceof \Psalm\Issue\MixedIssue && ($origin_location = $this->getOriginalLocation()) ? [\Psalm\Issue\TaintedInput::nodeToDataFlowNodeData($origin_location, 'The type of ' . $location->getSelectedText() . ' is sourced from here')] : null, $this->dupe_key); } } dupe_key = $dupe_key; } } function_id = $function_id ? strtolower($function_id) : null; } } dupe_key = $property_id; } } dupe_key = $dupe_key; } } code_location = $code_location; $this->message = $message; $this->origin_location = $origin_location; } public function getMixedOriginMessage() : string { return $this->message . ($this->origin_location ? '. Consider improving the type at ' . $this->origin_location->getShortSummary() : ''); } public function getOriginalLocation() : ?CodeLocation { return $this->origin_location; } } dupe_key = $property_id; } } dupe_key = $dupe_key; } } const_id = $const_id; } } $words */ public static function listToPhrase(array $words) : string { $words = array_unique($words); if (count($words) === 1) { return reset($words); } if (count($words) === 2) { return implode(" and ", $words); } $last_word = array_pop($words); $phrase = implode(", ", $words); $phrase = "{$phrase}, and {$last_word}"; return $phrase; } } function_id = strtolower($function_id); } } dupe_key = strtolower($method_id); } } origin_location = $origin_location; } } dupe_key = $dupe_key; } } code_location = $code_location; $this->message = $message; $this->function_id = $function_id ? strtolower($function_id) : null; $this->origin_location = $origin_location; } } method_id = strtolower($method_id); } } dupe_key = $property_id; } } dupe_key = $dupe_key; } } */ public const SHORTCODE = 205; /** * @var string * @readonly */ public $journey_text; /** * @var list * @readonly */ public $journey = []; /** * @param list $journey */ public function __construct(string $message, CodeLocation $code_location, array $journey, string $journey_text) { parent::__construct($message, $code_location); $this->journey = $journey; $this->journey_text = $journey_text; } /** * @return list */ public function getTaintTrace() : array { $nodes = []; foreach ($this->journey as ['location' => $location, 'label' => $label, 'entry_path_type' => $path_type]) { if ($location) { $nodes[] = self::nodeToDataFlowNodeData($location, $label); } else { $nodes[] = ['label' => $label, 'entry_path_type' => $path_type]; } } return $nodes; } public static function nodeToDataFlowNodeData(CodeLocation $location, string $label) : DataFlowNodeData { $selection_bounds = $location->getSelectionBounds(); $snippet_bounds = $location->getSnippetBounds(); return new DataFlowNodeData($label, $location->getLineNumber(), $location->getEndLineNumber(), $location->file_name, $location->file_path, $location->getSnippet(), $selection_bounds[0], $selection_bounds[1], $snippet_bounds[0], $location->getColumn(), $location->getEndColumn()); } public function getJourneyMessage() : string { return $this->message . ' in path: ' . $this->journey_text; } } var_name = strtolower($var_name); } } dupe_key = $dupe_key; } } dupe_key = $dupe_key; } } > */ private static array $manipulators = []; private Property $stmt; private int $docblock_start; private int $docblock_end; private ?int $typehint_start = null; private int $typehint_area_start; private ?int $typehint_end = null; private ?string $new_php_type = null; private bool $type_is_php_compatible = \false; private ?string $new_phpdoc_type = null; private ?string $new_psalm_type = null; private string $indentation; private bool $add_newline = \false; private ?string $type_description = null; public static function getForProperty(ProjectAnalyzer $project_analyzer, string $file_path, Property $stmt) : self { if (isset(self::$manipulators[$file_path][$stmt->getLine()])) { return self::$manipulators[$file_path][$stmt->getLine()]; } $manipulator = self::$manipulators[$file_path][$stmt->getLine()] = new self($project_analyzer, $stmt, $file_path); return $manipulator; } private function __construct(ProjectAnalyzer $project_analyzer, Property $stmt, string $file_path) { $this->stmt = $stmt; $docblock = $stmt->getDocComment(); $this->docblock_start = $docblock ? $docblock->getStartFilePos() : (int) $stmt->getAttribute('startFilePos'); $this->docblock_end = (int) $stmt->getAttribute('startFilePos'); $codebase = $project_analyzer->getCodebase(); $file_contents = $codebase->getFileContents($file_path); if (count($stmt->props) > 1) { $config = Config::getInstance(); if ($config->isInProjectDirs($file_path)) { throw new UnexpectedValueException('Cannot replace multiple inline properties in ' . $file_path); } $this->indentation = ''; return; } $prop = $stmt->props[0]; if ($stmt->type) { $this->typehint_start = (int) $stmt->type->getAttribute('startFilePos'); $this->typehint_end = (int) $stmt->type->getAttribute('endFilePos'); } $this->typehint_area_start = (int) $prop->getAttribute('startFilePos') - 1; $preceding_newline_pos = strrpos($file_contents, "\n", $this->docblock_end - strlen($file_contents)); if ($preceding_newline_pos === \false) { $this->indentation = ''; return; } if (!$docblock) { $preceding_semicolon_pos = strrpos($file_contents, ";", $preceding_newline_pos - strlen($file_contents)); if ($preceding_semicolon_pos) { $preceding_space = substr($file_contents, $preceding_semicolon_pos + 1, $preceding_newline_pos - $preceding_semicolon_pos - 1); if (!substr_count($preceding_space, "\n")) { $this->add_newline = \true; } } } $first_line = substr($file_contents, $preceding_newline_pos + 1, $this->docblock_end - $preceding_newline_pos); $this->indentation = str_replace(ltrim($first_line), '', $first_line); } public function setType(?string $php_type, string $new_type, string $phpdoc_type, bool $is_php_compatible, ?string $description = null) : void { $new_type = str_replace(['', '', ''], '', $new_type); $this->new_php_type = $php_type; $this->new_phpdoc_type = $phpdoc_type; $this->new_psalm_type = $new_type; $this->type_is_php_compatible = $is_php_compatible; $this->type_description = $description; } /** * Gets a new docblock given the existing docblock, if one exists, and the updated return types * and/or parameters */ private function getDocblock() : string { $docblock = $this->stmt->getDocComment(); if ($docblock) { $parsed_docblock = DocComment::parsePreservingLength($docblock); } else { $parsed_docblock = new ParsedDocblock('', []); } $modified_docblock = \false; $old_phpdoc_type = null; if (isset($parsed_docblock->tags['var'])) { $old_phpdoc_type = array_shift($parsed_docblock->tags['var']); } if ($this->new_phpdoc_type && $this->new_phpdoc_type !== $old_phpdoc_type) { $modified_docblock = \true; $parsed_docblock->tags['var'] = [$this->new_phpdoc_type . ($this->type_description ? ' ' . $this->type_description : '')]; } $old_psalm_type = null; if (isset($parsed_docblock->tags['psalm-var'])) { $old_psalm_type = array_shift($parsed_docblock->tags['psalm-var']); } if ($this->new_psalm_type && $this->new_phpdoc_type !== $this->new_psalm_type && $this->new_psalm_type !== $old_psalm_type) { $modified_docblock = \true; $parsed_docblock->tags['psalm-var'] = [$this->new_psalm_type]; } if (!$parsed_docblock->tags && !$parsed_docblock->description) { return ''; } if (!$modified_docblock) { return (string) $docblock . "\n" . $this->indentation; } return $parsed_docblock->render($this->indentation); } /** * @return array */ public static function getManipulationsForFile(string $file_path) : array { if (!isset(self::$manipulators[$file_path])) { return []; } $file_manipulations = []; foreach (self::$manipulators[$file_path] as $manipulator) { if ($manipulator->new_php_type) { if ($manipulator->typehint_start && $manipulator->typehint_end) { $file_manipulations[$manipulator->typehint_start] = new FileManipulation($manipulator->typehint_start, $manipulator->typehint_end, $manipulator->new_php_type); } else { $file_manipulations[$manipulator->typehint_area_start] = new FileManipulation($manipulator->typehint_area_start, $manipulator->typehint_area_start, ' ' . $manipulator->new_php_type); } } elseif ($manipulator->new_php_type === '' && $manipulator->new_phpdoc_type && $manipulator->typehint_start && $manipulator->typehint_end) { $file_manipulations[$manipulator->typehint_start] = new FileManipulation($manipulator->typehint_start, $manipulator->typehint_end, ''); } if (!$manipulator->new_php_type || !$manipulator->type_is_php_compatible || $manipulator->docblock_start !== $manipulator->docblock_end) { $file_manipulations[$manipulator->docblock_start] = new FileManipulation($manipulator->docblock_start - ($manipulator->add_newline ? strlen($manipulator->indentation) : 0), $manipulator->docblock_end, ($manipulator->add_newline ? "\n" . $manipulator->indentation : '') . $manipulator->getDocblock()); } } return $file_manipulations; } public static function clearCache() : void { self::$manipulators = []; } } source_file_path = $source_file_path; $this->source_start = $source_start; $this->source_end = $source_end; $this->destination_file_path = $destination_file_path; $this->destination_start = $destination_start; } } */ private static array $file_manipulations = []; /** @var CodeMigration[] */ private static array $code_migrations = []; /** * @param FileManipulation[] $file_manipulations */ public static function add(string $file_path, array $file_manipulations) : void { if (!isset(self::$file_manipulations[$file_path])) { self::$file_manipulations[$file_path] = []; } foreach ($file_manipulations as $file_manipulation) { self::$file_manipulations[$file_path][$file_manipulation->getKey()] = $file_manipulation; } } /** @param CodeMigration[] $code_migrations */ public static function addCodeMigrations(array $code_migrations) : void { self::$code_migrations = array_merge(self::$code_migrations, $code_migrations); } /** * @return array{int, int} */ private static function getCodeOffsets(string $source_file_path, int $source_start, int $source_end) : array { if (!isset(self::$file_manipulations[$source_file_path])) { return [0, 0]; } $start_offset = 0; $middle_offset = 0; foreach (self::$file_manipulations[$source_file_path] as $fm) { $offset = strlen($fm->insertion_text) - $fm->end + $fm->start; if ($fm->end < $source_start) { $start_offset += $offset; $middle_offset += $offset; } elseif ($fm->start > $source_start && $fm->end < $source_end) { $middle_offset += $offset; } } return [$start_offset, $middle_offset]; } public static function addForCodeLocation(CodeLocation $code_location, string $replacement_text, bool $swallow_newlines = \false) : void { $bounds = $code_location->getSnippetBounds(); if ($swallow_newlines) { $project_analyzer = ProjectAnalyzer::getInstance(); $codebase = $project_analyzer->getCodebase(); $file_contents = $codebase->getFileContents($code_location->file_path); if (($file_contents[$bounds[0] - 1] ?? null) === "\n" && ($file_contents[$bounds[0] - 2] ?? null) === "\n") { $bounds[0] -= 2; } } self::add($code_location->file_path, [new FileManipulation($bounds[0], $bounds[1], $replacement_text)]); } public static function addVarAnnotationToRemove(DocblockTypeLocation $code_location) : void { $bounds = $code_location->getSelectionBounds(); $project_analyzer = ProjectAnalyzer::getInstance(); $codebase = $project_analyzer->getCodebase(); $file_contents = $codebase->getFileContents($code_location->file_path); $comment_start = strrpos($file_contents, '/**', $bounds[0] - strlen($file_contents)); if ($comment_start === \false) { return; } $comment_end = strpos($file_contents, '*/', $bounds[1]); if ($comment_end === \false) { return; } $comment_end += 2; $comment_text = substr($file_contents, $comment_start, $comment_end - $comment_start); $var_type_comment_start = $bounds[0] - $comment_start; $var_type_comment_end = $bounds[1] - $comment_start; $var_start = strrpos($comment_text, '@var', $var_type_comment_start - strlen($comment_text)); $var_end = strpos($comment_text, "\n", $var_type_comment_end); if ($var_start && $var_end) { $var_start = strrpos($comment_text, "\n", $var_start - strlen($comment_text)) ?: $var_start; $comment_text = substr_replace($comment_text, '', $var_start, $var_end - $var_start); if (preg_match('@^/\\*\\*\\n(\\s*\\*\\s*\\n)*\\s*\\*?\\*/$@', $comment_text)) { $comment_text = ''; } } else { $comment_text = ''; } self::add($code_location->file_path, [new FileManipulation($comment_start, $comment_end, $comment_text, \false, $comment_text === '')]); } /** * @return FileManipulation[] */ public static function getManipulationsForFile(string $file_path) : array { return self::$file_manipulations[$file_path] ?? []; } /** * @return array */ public static function getMigrationManipulations(FileProvider $file_provider) : array { $code_migration_manipulations = []; foreach (self::$code_migrations as $code_migration) { [$start_offset, $middle_offset] = self::getCodeOffsets($code_migration->source_file_path, $code_migration->source_start, $code_migration->source_end); if (!isset($code_migration_manipulations[$code_migration->source_file_path])) { $code_migration_manipulations[$code_migration->source_file_path] = []; } if (!isset($code_migration_manipulations[$code_migration->destination_file_path])) { $code_migration_manipulations[$code_migration->destination_file_path] = []; } $delete_file_manipulation = new FileManipulation($code_migration->source_start + $start_offset, $code_migration->source_end + $middle_offset, ''); $code_migration_manipulations[$code_migration->source_file_path][] = $delete_file_manipulation; [$destination_start_offset] = self::getCodeOffsets($code_migration->destination_file_path, $code_migration->destination_start, $code_migration->destination_start); $manipulation = new FileManipulation($code_migration->destination_start + $destination_start_offset, $code_migration->destination_start + $destination_start_offset, "\n" . substr($file_provider->getContents($code_migration->source_file_path), $delete_file_manipulation->start, $delete_file_manipulation->end - $delete_file_manipulation->start) . "\n"); $code_migration_manipulations[$code_migration->destination_file_path][$manipulation->getKey()] = $manipulation; } return $code_migration_manipulations; } /** * @return array */ public static function getAll() : array { return self::$file_manipulations; } public static function clearCache() : void { self::$file_manipulations = []; self::$code_migrations = []; } } > */ private static array $manipulators = []; private Class_ $stmt; private int $docblock_start; private int $docblock_end; private bool $immutable = \false; private string $indentation; public static function getForClass(ProjectAnalyzer $project_analyzer, string $file_path, Class_ $stmt) : self { if (isset(self::$manipulators[$file_path][$stmt->getLine()])) { return self::$manipulators[$file_path][$stmt->getLine()]; } $manipulator = self::$manipulators[$file_path][$stmt->getLine()] = new self($project_analyzer, $stmt, $file_path); return $manipulator; } private function __construct(ProjectAnalyzer $project_analyzer, Class_ $stmt, string $file_path) { $this->stmt = $stmt; $docblock = $stmt->getDocComment(); $this->docblock_start = $docblock ? $docblock->getStartFilePos() : (int) $stmt->getAttribute('startFilePos'); $this->docblock_end = (int) $stmt->getAttribute('startFilePos'); $codebase = $project_analyzer->getCodebase(); $file_contents = $codebase->getFileContents($file_path); $preceding_newline_pos = (int) strrpos($file_contents, "\n", $this->docblock_end - strlen($file_contents)); $first_line = substr($file_contents, $preceding_newline_pos + 1, $this->docblock_end - $preceding_newline_pos); $this->indentation = str_replace(ltrim($first_line), '', $first_line); } public function makeImmutable() : void { $this->immutable = \true; } /** * Gets a new docblock given the existing docblock, if one exists, and the updated return types * and/or parameters */ private function getDocblock() : string { $docblock = $this->stmt->getDocComment(); if ($docblock) { $parsed_docblock = DocComment::parsePreservingLength($docblock); } else { $parsed_docblock = new ParsedDocblock('', []); } $modified_docblock = \false; if ($this->immutable) { $modified_docblock = \true; $parsed_docblock->tags['psalm-immutable'] = ['']; } if (!$modified_docblock) { return (string) $docblock . "\n" . $this->indentation; } return $parsed_docblock->render($this->indentation); } /** * @return array */ public static function getManipulationsForFile(string $file_path) : array { if (!isset(self::$manipulators[$file_path])) { return []; } $file_manipulations = []; foreach (self::$manipulators[$file_path] as $manipulator) { if ($manipulator->immutable) { $file_manipulations[$manipulator->docblock_start] = new FileManipulation($manipulator->docblock_start, $manipulator->docblock_end, $manipulator->getDocblock()); } } return $file_manipulations; } public static function clearCache() : void { self::$manipulators = []; } } > */ private static array $manipulators = []; /** @var Closure|Function_|ClassMethod|ArrowFunction */ private FunctionLike $stmt; private int $docblock_start; private int $docblock_end; private int $return_typehint_area_start; private ?int $return_typehint_colon_start = null; private ?int $return_typehint_start = null; private ?int $return_typehint_end = null; private ?string $new_php_return_type = null; private bool $return_type_is_php_compatible = \false; private ?string $new_phpdoc_return_type = null; private ?string $new_psalm_return_type = null; /** @var array */ private array $new_php_param_types = []; /** @var array */ private array $new_phpdoc_param_types = []; /** @var array */ private array $new_psalm_param_types = []; private string $indentation; private ?string $return_type_description = null; /** @var array */ private array $param_offsets = []; /** @var array */ private array $param_typehint_offsets = []; private bool $is_pure = \false; /** @var list */ private array $throwsExceptions = []; /** * @param Closure|Function_|ClassMethod|ArrowFunction $stmt */ public static function getForFunction(ProjectAnalyzer $project_analyzer, string $file_path, FunctionLike $stmt) : \Psalm\Internal\FileManipulation\FunctionDocblockManipulator { if (isset(self::$manipulators[$file_path][$stmt->getLine()])) { return self::$manipulators[$file_path][$stmt->getLine()]; } $manipulator = self::$manipulators[$file_path][$stmt->getLine()] = new self($file_path, $stmt, $project_analyzer); return $manipulator; } /** * @param Closure|Function_|ClassMethod|ArrowFunction $stmt */ private function __construct(string $file_path, FunctionLike $stmt, ProjectAnalyzer $project_analyzer) { $this->stmt = $stmt; $docblock = $stmt->getDocComment(); $this->docblock_start = $docblock ? $docblock->getStartFilePos() : (int) $stmt->getAttribute('startFilePos'); $this->docblock_end = $function_start = (int) $stmt->getAttribute('startFilePos'); $function_end = (int) $stmt->getAttribute('endFilePos'); $attributes = $stmt->getAttrGroups(); foreach ($attributes as $attribute) { // if we have attribute groups, we need to consider that the function starts after them if ((int) $attribute->getAttribute('endFilePos') > $function_start) { $function_start = (int) $attribute->getAttribute('endFilePos'); } } foreach ($stmt->params as $param) { if ($param->var instanceof PhpParser\Node\Expr\Variable && is_string($param->var->name)) { $this->param_offsets[$param->var->name] = (int) $param->getAttribute('startFilePos'); if ($param->type) { $this->param_typehint_offsets[$param->var->name] = [(int) $param->type->getAttribute('startFilePos'), (int) $param->type->getAttribute('endFilePos') + 1]; } } } $codebase = $project_analyzer->getCodebase(); $file_contents = $codebase->getFileContents($file_path); $last_arg_position = $stmt->params ? (int) $stmt->params[count($stmt->params) - 1]->getAttribute('endFilePos') + 1 : null; if ($stmt instanceof Closure && $stmt->uses) { $last_arg_position = (int) $stmt->uses[count($stmt->uses) - 1]->getAttribute('endFilePos') + 1; } $end_bracket_position = (int) strpos($file_contents, ')', $last_arg_position ?: $function_start); $this->return_typehint_area_start = $end_bracket_position + 1; $function_code = substr($file_contents, $function_start, $function_end); $function_code_after_bracket = substr($function_code, $end_bracket_position + 1 - $function_start); // do a little parsing here $chars = str_split($function_code_after_bracket); $in_single_line_comment = $in_multi_line_comment = \false; for ($i = 0, $iMax = count($chars); $i < $iMax; ++$i) { $char = $chars[$i]; switch ($char) { case "\n": $in_single_line_comment = \false; continue 2; case ':': if ($in_multi_line_comment || $in_single_line_comment) { continue 2; } $this->return_typehint_colon_start = $i + $end_bracket_position + 1; continue 2; case '/': if ($in_multi_line_comment || $in_single_line_comment) { continue 2; } if ($chars[$i + 1] === '*') { $in_multi_line_comment = \true; ++$i; } if ($chars[$i + 1] === '/') { $in_single_line_comment = \true; ++$i; } continue 2; case '*': if ($in_single_line_comment) { continue 2; } if ($chars[$i + 1] === '/') { $in_multi_line_comment = \false; ++$i; } continue 2; case '{': if ($in_multi_line_comment || $in_single_line_comment) { continue 2; } break 2; case '=': if ($in_multi_line_comment || $in_single_line_comment) { continue 2; } break 2; case '?': if ($in_multi_line_comment || $in_single_line_comment) { continue 2; } $this->return_typehint_start = $i + $end_bracket_position + 1; break; } if ($in_multi_line_comment || $in_single_line_comment) { continue; } if ($chars[$i] === '\\' || preg_match('/\\w/', $char)) { if ($this->return_typehint_start === null) { $this->return_typehint_start = $i + $end_bracket_position + 1; } if ($chars[$i + 1] !== '\\' && !preg_match('/[\\w]/', $chars[$i + 1])) { $this->return_typehint_end = $i + $end_bracket_position + 2; break; } } } $preceding_newline_pos = strrpos($file_contents, "\n", $this->docblock_end - strlen($file_contents)); if ($preceding_newline_pos === \false) { $this->indentation = ''; return; } $first_line = substr($file_contents, $preceding_newline_pos + 1, $this->docblock_end - $preceding_newline_pos); $this->indentation = str_replace(ltrim($first_line), '', $first_line); } /** * Sets the new return type */ public function setReturnType(?string $php_type, string $new_type, string $phpdoc_type, bool $is_php_compatible, ?string $description) : void { $new_type = str_replace(['', ''], '', $new_type); $this->new_php_return_type = $php_type; $this->new_phpdoc_return_type = $phpdoc_type; $this->new_psalm_return_type = $new_type; $this->return_type_is_php_compatible = $is_php_compatible; $this->return_type_description = $description; } /** * Sets a new param type */ public function setParamType(string $param_name, ?string $php_type, string $new_type, string $phpdoc_type) : void { $new_type = str_replace(['', '', ''], '', $new_type); if ($php_type === 'static') { $php_type = ''; } if ($php_type) { $this->new_php_param_types[$param_name] = $php_type; } if ($php_type !== $phpdoc_type) { $this->new_phpdoc_param_types[$param_name] = $phpdoc_type; } if ($php_type !== $new_type && $phpdoc_type !== $new_type) { $this->new_psalm_param_types[$param_name] = $new_type; } } /** * Gets a new docblock given the existing docblock, if one exists, and the updated return types * and/or parameters */ private function getDocblock() : string { $docblock = $this->stmt->getDocComment(); if ($docblock) { $parsed_docblock = DocComment::parsePreservingLength($docblock); } else { $parsed_docblock = new ParsedDocblock('', []); } $modified_docblock = \false; foreach ($this->new_phpdoc_param_types as $param_name => $phpdoc_type) { $found_in_params = \false; $new_param_block = $phpdoc_type . ' ' . '$' . $param_name; if (isset($parsed_docblock->tags['param'])) { foreach ($parsed_docblock->tags['param'] as &$param_block) { $doc_parts = CommentAnalyzer::splitDocLine($param_block); // If there's no type if (($doc_parts[0] ?? null) === '$' . $param_name) { // If the parameter has a description add that back if (count($doc_parts) > 1) { $new_param_block .= " " . implode(" ", array_slice($doc_parts, 1)); } if ($param_block !== $new_param_block) { $modified_docblock = \true; } $param_block = $new_param_block; $found_in_params = \true; break; } // If there is a type if (($doc_parts[1] ?? null) === '$' . $param_name) { // If the parameter has a description add that back if (count($doc_parts) > 2) { $new_param_block .= " " . implode(" ", array_slice($doc_parts, 2)); } if ($param_block !== $new_param_block) { $modified_docblock = \true; } $param_block = $new_param_block; $found_in_params = \true; break; } } unset($param_block); } if (!$found_in_params) { $modified_docblock = \true; $parsed_docblock->tags['param'][] = $new_param_block; } } foreach ($this->new_psalm_param_types as $param_name => $psalm_type) { $found_in_params = \false; $new_param_block = $psalm_type . ' ' . '$' . $param_name; if (isset($parsed_docblock->tags['psalm-param'])) { foreach ($parsed_docblock->tags['psalm-param'] as &$param_block) { $doc_parts = CommentAnalyzer::splitDocLine($param_block); if (($doc_parts[1] ?? null) === '$' . $param_name) { if ($param_block !== $new_param_block) { $modified_docblock = \true; } $param_block = $new_param_block; $found_in_params = \true; break; } } unset($param_block); } if (!$found_in_params) { $modified_docblock = \true; $parsed_docblock->tags['psalm-param'][] = $new_param_block; } } $old_phpdoc_return_type = null; if (isset($parsed_docblock->tags['return'])) { $old_phpdoc_return_type = reset($parsed_docblock->tags['return']); } if ($this->is_pure) { $modified_docblock = \true; $parsed_docblock->tags['psalm-pure'] = ['']; } if (count($this->throwsExceptions) > 0) { $modified_docblock = \true; $inferredThrowsClause = array_reduce($this->throwsExceptions, static fn(string $throwsClause, string $exception) => $throwsClause === '' ? $exception : $throwsClause . '|' . $exception, ''); if (array_key_exists('throws', $parsed_docblock->tags)) { $parsed_docblock->tags['throws'][] = $inferredThrowsClause; } else { $parsed_docblock->tags['throws'] = [$inferredThrowsClause]; } } if ($this->new_phpdoc_return_type && $this->new_phpdoc_return_type !== $old_phpdoc_return_type) { $modified_docblock = \true; if ($this->new_phpdoc_return_type !== $this->new_php_return_type || $this->return_type_description) { //only add the type if it's different than signature or if there's a description $parsed_docblock->tags['return'] = [$this->new_phpdoc_return_type . ($this->return_type_description ? ' ' . $this->return_type_description : '')]; } else { unset($parsed_docblock->tags['return']); } } $old_psalm_return_type = null; if (isset($parsed_docblock->tags['psalm-return'])) { $old_psalm_return_type = reset($parsed_docblock->tags['psalm-return']); } if ($this->new_psalm_return_type && $this->new_phpdoc_return_type !== $this->new_psalm_return_type && $this->new_psalm_return_type !== $old_psalm_return_type) { $modified_docblock = \true; $parsed_docblock->tags['psalm-return'] = [$this->new_psalm_return_type]; } if (!$parsed_docblock->tags && !$parsed_docblock->description) { return ''; } if (!$modified_docblock) { return (string) $docblock . "\n" . $this->indentation; } return $parsed_docblock->render($this->indentation); } /** * @return array */ public static function getManipulationsForFile(string $file_path) : array { if (!isset(self::$manipulators[$file_path])) { return []; } $file_manipulations = []; foreach (self::$manipulators[$file_path] as $manipulator) { if ($manipulator->new_php_return_type) { if ($manipulator->return_typehint_start && $manipulator->return_typehint_end) { $file_manipulations[$manipulator->return_typehint_start] = new FileManipulation($manipulator->return_typehint_start, $manipulator->return_typehint_end, $manipulator->new_php_return_type); } else { $file_manipulations[$manipulator->return_typehint_area_start] = new FileManipulation($manipulator->return_typehint_area_start, $manipulator->return_typehint_area_start, ': ' . $manipulator->new_php_return_type); } } elseif ($manipulator->new_php_return_type === '' && $manipulator->return_typehint_colon_start && $manipulator->new_phpdoc_return_type && $manipulator->return_typehint_start && $manipulator->return_typehint_end) { $file_manipulations[$manipulator->return_typehint_start] = new FileManipulation($manipulator->return_typehint_colon_start, $manipulator->return_typehint_end, ''); } if (!$manipulator->new_php_return_type || !$manipulator->return_type_is_php_compatible || $manipulator->docblock_start !== $manipulator->docblock_end || $manipulator->is_pure) { $file_manipulations[$manipulator->docblock_start] = new FileManipulation($manipulator->docblock_start, $manipulator->docblock_end, $manipulator->getDocblock()); } foreach ($manipulator->new_php_param_types as $param_name => $new_php_param_type) { if (!isset($manipulator->param_offsets[$param_name])) { continue; } $param_offset = $manipulator->param_offsets[$param_name]; $typehint_offsets = $manipulator->param_typehint_offsets[$param_name] ?? null; if ($new_php_param_type) { if ($typehint_offsets) { $file_manipulations[$typehint_offsets[0]] = new FileManipulation($typehint_offsets[0], $typehint_offsets[1], $new_php_param_type); } else { $file_manipulations[$param_offset] = new FileManipulation($param_offset, $param_offset, $new_php_param_type . ' '); } } elseif ($new_php_param_type === '' && $typehint_offsets) { $file_manipulations[$typehint_offsets[0]] = new FileManipulation($typehint_offsets[0], $param_offset, ''); } } } return $file_manipulations; } public function makePure() : void { $this->is_pure = \true; } /** * @param list $exceptions */ public function addThrowsDocblock(array $exceptions) : void { $this->throwsExceptions = $exceptions; } public static function clearCache() : void { self::$manipulators = []; } /** * @param array> $manipulators */ public static function addManipulators(array $manipulators) : void { self::$manipulators = array_merge($manipulators, self::$manipulators); } /** * @return array> */ public static function getManipulators() : array { return self::$manipulators; } } >> $all_types * @return array>> * @psalm-pure */ public static function negateTypes(array $all_types) : array { $negated_types = []; foreach ($all_types as $key => $anded_types) { if (count($anded_types) > 1) { $new_anded_types = []; foreach ($anded_types as $orred_types) { if (count($orred_types) === 1) { $new_anded_types[] = $orred_types[0]->getNegation(); } else { continue 2; } } assert($new_anded_types !== []); $negated_types[$key] = [$new_anded_types]; continue; } $new_orred_types = []; foreach ($anded_types[0] as $orred_type) { $new_orred_types[] = [$orred_type->getNegation()]; } $negated_types[$key] = $new_orred_types; } return $negated_types; } /** * This is a very simple simplification heuristic * for CNF formulae. * * It simplifies formulae: * ($a) && ($a || $b) => $a * (!$a) && (!$b) && ($a || $b || $c) => $c * * @param list $clauses * @return list * @psalm-pure */ public static function simplifyCNF(array $clauses) : array { $clause_count = count($clauses); //65536 seems to be a significant threshold, when put at 65537, the code https://psalm.dev/r/216f362ea6 goes //from seconds in analysis to many minutes if ($clause_count > 65536) { return []; } if ($clause_count > 50) { $all_has_unknown = \true; foreach ($clauses as $clause) { $clause_has_unknown = \false; foreach ($clause->possibilities as $key => $_) { if ($key[0] === '*') { $clause_has_unknown = \true; break; } } if (!$clause_has_unknown) { $all_has_unknown = \false; break; } } if ($all_has_unknown) { return $clauses; } } $cloned_clauses = []; // avoid strict duplicates foreach ($clauses as $clause) { $cloned_clauses[$clause->hash] = $clause; } // remove impossible types foreach ($cloned_clauses as $clause_a_hash => $clause_a) { if (!$clause_a->reconcilable || $clause_a->wedge) { continue; } $clause_a_keys = array_keys($clause_a->possibilities); if (count($clause_a->possibilities) !== 1 || count(array_values($clause_a->possibilities)[0]) !== 1) { foreach ($cloned_clauses as $clause_b) { if ($clause_a === $clause_b || !$clause_b->reconcilable || $clause_b->wedge) { continue; } if ($clause_a_keys === array_keys($clause_b->possibilities)) { $opposing_keys = []; foreach ($clause_a->possibilities as $key => $a_possibilities) { $b_possibilities = $clause_b->possibilities[$key]; if (array_keys($clause_a->possibilities[$key]) === array_keys($clause_b->possibilities[$key])) { continue; } if (count($a_possibilities) === 1 && count($b_possibilities) === 1) { if (reset($a_possibilities)->isNegationOf(reset($b_possibilities))) { $opposing_keys[] = $key; continue; } } continue 2; } if (count($opposing_keys) === 1) { unset($cloned_clauses[$clause_a_hash]); $clause_a = $clause_a->removePossibilities($opposing_keys[0]); if (!$clause_a) { continue 2; } $cloned_clauses[$clause_a->hash] = $clause_a; } } } continue; } $clause_var = array_keys($clause_a->possibilities)[0]; $only_type = array_pop(array_values($clause_a->possibilities)[0]); $negated_clause_type = $only_type->getNegation(); $negated_clause_type_string = (string) $negated_clause_type; foreach ($cloned_clauses as $clause_b_hash => $clause_b) { if ($clause_a === $clause_b || !$clause_b->reconcilable || $clause_b->wedge) { continue; } if (isset($clause_b->possibilities[$clause_var])) { $unmatched = []; $matched = []; foreach ($clause_b->possibilities[$clause_var] as $k => $possible_type) { if ((string) $possible_type === $negated_clause_type_string) { $matched[] = $possible_type; } else { $unmatched[$k] = $possible_type; } } if ($matched) { $clause_var_possibilities = $unmatched; unset($cloned_clauses[$clause_b_hash]); if (!$clause_var_possibilities) { $updated_clause = $clause_b->removePossibilities($clause_var); if ($updated_clause) { $cloned_clauses[$updated_clause->hash] = $updated_clause; } } else { $updated_clause = $clause_b->addPossibilities($clause_var, $clause_var_possibilities); $cloned_clauses[$updated_clause->hash] = $updated_clause; } } } } } $simplified_clauses = []; foreach ($cloned_clauses as $clause_a) { $is_redundant = \false; foreach ($cloned_clauses as $clause_b) { if ($clause_a === $clause_b || !$clause_b->reconcilable || $clause_b->wedge || $clause_a->wedge) { continue; } if ($clause_a->contains($clause_b)) { $is_redundant = \true; break; } } if (!$is_redundant) { $simplified_clauses[$clause_a->hash] = $clause_a; } } $clause_count = count($simplified_clauses); // simplify (A || X) && (!A || Y) && (X || Y) // to // simplify (A || X) && (!A || Y) // where X and Y are sets of orred terms if ($clause_count > 2 && $clause_count < 256) { $clauses = array_values($simplified_clauses); for ($i = 0; $i < $clause_count; $i++) { $clause_a = $clauses[$i]; for ($k = $i + 1; $k < $clause_count; $k++) { $clause_b = $clauses[$k]; $common_keys = array_keys(array_intersect_key($clause_a->possibilities, $clause_b->possibilities)); if ($common_keys) { $common_negated_keys = []; foreach ($common_keys as $common_key) { if (count($clause_a->possibilities[$common_key]) === 1 && count($clause_b->possibilities[$common_key]) === 1 && reset($clause_a->possibilities[$common_key])->isNegationOf(reset($clause_b->possibilities[$common_key]))) { $common_negated_keys[] = $common_key; } } if ($common_negated_keys) { $new_possibilities = []; foreach ($clause_a->possibilities as $var_id => $possibilities) { if (in_array($var_id, $common_negated_keys, \true)) { continue; } if (!isset($new_possibilities[$var_id])) { $new_possibilities[$var_id] = $possibilities; } else { $new_possibilities[$var_id] = array_merge($new_possibilities[$var_id], $possibilities); } } foreach ($clause_b->possibilities as $var_id => $possibilities) { if (in_array($var_id, $common_negated_keys, \true)) { continue; } if (!isset($new_possibilities[$var_id])) { $new_possibilities[$var_id] = $possibilities; } else { $new_possibilities[$var_id] = array_merge($new_possibilities[$var_id], $possibilities); } } /** @psalm-suppress MixedArgumentTypeCoercion due I think to Psalm bug */ $conflict_clause = new \Psalm\Internal\Clause($new_possibilities, $clause_a->creating_conditional_id, $clause_a->creating_conditional_id, \false, \true, \true, []); unset($simplified_clauses[$conflict_clause->hash]); } } } } } return array_values($simplified_clauses); } /** * Look for clauses with only one possible value * * doesn't infer the "unset" correctly * * @psalm-suppress MoreSpecificReturnType * @param list $clauses * @param array $cond_referenced_var_ids * @param array>> $active_truths * @return array>> */ public static function getTruthsFromFormula(array $clauses, ?int $creating_conditional_id = null, array &$cond_referenced_var_ids = [], array &$active_truths = []) : array { $truths = []; $active_truths = []; if ($clauses === []) { return []; } foreach ($clauses as $clause) { if (!$clause->reconcilable || count($clause->possibilities) !== 1) { continue; } foreach ($clause->possibilities as $var => $possible_types) { if ($var[0] === '*') { continue; } // if there's only one possible type, return it if (count($possible_types) === 1) { $possible_type = array_pop($possible_types); if (isset($truths[$var]) && !isset($clause->redefined_vars[$var])) { $truths[$var][] = [$possible_type]; } else { $truths[$var] = [[$possible_type]]; } if ($creating_conditional_id && $creating_conditional_id === $clause->creating_conditional_id) { if (!isset($active_truths[$var])) { $active_truths[$var] = []; } $active_truths[$var][count($truths[$var]) - 1] = [$possible_type]; } } else { // if there's only one active clause, return all the non-negation clause members ORed together $things_that_can_be_said = []; foreach ($possible_types as $assertion) { $things_that_can_be_said[(string) $assertion] = $assertion; } if ($clause->generated && count($possible_types) > 1) { unset($cond_referenced_var_ids[$var]); } $truths[$var] = [array_values($things_that_can_be_said)]; if ($creating_conditional_id && $creating_conditional_id === $clause->creating_conditional_id) { $active_truths[$var] = [array_values($things_that_can_be_said)]; } } } } foreach ($truths as $var => $anded_types) { $has_list_or_array = \false; foreach ($anded_types as $orred_types) { foreach ($orred_types as $assertion) { if ($assertion->isNegation()) { continue; } if (!isset($assertion->type)) { continue; } if ($assertion->type instanceof TList || $assertion->type instanceof TArray || $assertion->type instanceof TKeyedArray) { $has_list_or_array = \true; // list/array are collapsed, therefore there can only be 1 and we can abort // otherwise we would have to remove them all individually // e.g. array cannot be array break 2; } } } if ($has_list_or_array === \false) { continue; } foreach ($anded_types as $key => $orred_types) { foreach ($orred_types as $index => $assertion) { // we only need to check negations // due to type collapsing, any negations for arrays are irrelevant if (!$assertion->isNegation()) { continue; } if (!isset($assertion->type)) { continue; } if ($assertion->type instanceof TList || $assertion->type instanceof TArray || $assertion->type instanceof TKeyedArray) { unset($truths[$var][$key][$index]); } } /** * doesn't infer the "unset" correctly * * @psalm-suppress DocblockTypeContradiction */ if ($truths[$var][$key] === []) { unset($truths[$var][$key]); } else { /** * doesn't infer the "unset" correctly * * @psalm-suppress RedundantFunctionCallGivenDocblockType */ $truths[$var][$key] = array_values($truths[$var][$key]); } } } /** @psalm-suppress LessSpecificReturnStatement */ return $truths; } /** * @param non-empty-list $clauses * @return list * @psalm-pure */ public static function groupImpossibilities(array $clauses) : array { $complexity = 1; $seed_clauses = []; $clause = array_pop($clauses); if (!$clause->wedge) { if ($clause->impossibilities === null) { throw new UnexpectedValueException('$clause->impossibilities should not be null'); } foreach ($clause->impossibilities as $var => $impossible_types) { foreach ($impossible_types as $impossible_type) { $seed_clause = new \Psalm\Internal\Clause([$var => [(string) $impossible_type => $impossible_type]], $clause->creating_conditional_id, $clause->creating_object_id); $seed_clauses[] = $seed_clause; ++$complexity; } } } if (!$clauses || !$seed_clauses) { return $seed_clauses; } $complexity_upper_bound = count($seed_clauses); foreach ($clauses as $clause) { $i = 0; foreach ($clause->possibilities as $p) { $i += count($p); } $complexity_upper_bound *= $i; if ($complexity_upper_bound > 20000) { throw new ComplicatedExpressionException(); } } while ($clauses) { $clause = array_pop($clauses); $new_clauses = []; foreach ($seed_clauses as $grouped_clause) { if ($clause->impossibilities === null) { throw new UnexpectedValueException('$clause->impossibilities should not be null'); } foreach ($clause->impossibilities as $var => $impossible_types) { foreach ($impossible_types as $impossible_type) { $new_clause_possibilities = $grouped_clause->possibilities; if (isset($new_clause_possibilities[$var])) { $impossible_type_string = (string) $impossible_type; $new_clause_possibilities[$var][$impossible_type_string] = $impossible_type; foreach ($new_clause_possibilities[$var] as $ak => $av) { foreach ($new_clause_possibilities[$var] as $bk => $bv) { if ($ak == $bk) { break; } if ($ak !== $impossible_type_string && $bk !== $impossible_type_string) { continue; } if ($av->isNegationOf($bv)) { break 3; } } } } else { $new_clause_possibilities[$var] = [(string) $impossible_type => $impossible_type]; } $new_clause = new \Psalm\Internal\Clause($new_clause_possibilities, $grouped_clause->creating_conditional_id, $clause->creating_object_id, \false, \true, \true, []); $new_clauses[] = $new_clause; ++$complexity; if ($complexity > 20000) { throw new ComplicatedExpressionException(); } } } } $seed_clauses = $new_clauses; } return $seed_clauses; } /** * @param list $left_clauses * @param list $right_clauses * @return list * @psalm-pure */ public static function combineOredClauses(array $left_clauses, array $right_clauses, int $conditional_object_id) : array { if (count($left_clauses) > 60000 || count($right_clauses) > 60000) { return []; } $clauses = []; $all_wedges = \true; $has_wedge = \false; foreach ($left_clauses as $left_clause) { foreach ($right_clauses as $right_clause) { $all_wedges = $all_wedges && ($left_clause->wedge && $right_clause->wedge); $has_wedge = $has_wedge || $left_clause->wedge && $right_clause->wedge; } } if ($all_wedges) { return [new \Psalm\Internal\Clause([], $conditional_object_id, $conditional_object_id, \true)]; } foreach ($left_clauses as $left_clause) { foreach ($right_clauses as $right_clause) { if ($left_clause->wedge && $right_clause->wedge) { // handled below continue; } /** @var array> */ $possibilities = []; $can_reconcile = \true; if ($left_clause->wedge || $right_clause->wedge || !$left_clause->reconcilable || !$right_clause->reconcilable) { $can_reconcile = \false; } foreach ($left_clause->possibilities as $var => $possible_types) { if (isset($right_clause->redefined_vars[$var])) { continue; } if (isset($possibilities[$var])) { $possibilities[$var] = array_merge($possibilities[$var], $possible_types); } else { $possibilities[$var] = $possible_types; } } foreach ($right_clause->possibilities as $var => $possible_types) { if (isset($possibilities[$var])) { $possibilities[$var] = array_merge($possibilities[$var], $possible_types); } else { $possibilities[$var] = $possible_types; } } foreach ($possibilities as $var_possibilities) { if (count($var_possibilities) === 2) { $vals = array_values($var_possibilities); /** @psalm-suppress PossiblyUndefinedIntArrayOffset */ if ($vals[0]->isNegationOf($vals[1])) { continue 2; } } } $creating_conditional_id = $right_clause->creating_conditional_id === $left_clause->creating_conditional_id ? $right_clause->creating_conditional_id : $conditional_object_id; $clauses[] = new \Psalm\Internal\Clause($possibilities, $creating_conditional_id, $creating_conditional_id, \false, $can_reconcile, $right_clause->generated || $left_clause->generated || count($left_clauses) > 1 || count($right_clauses) > 1, []); } } if ($has_wedge) { $clauses[] = new \Psalm\Internal\Clause([], $conditional_object_id, $conditional_object_id, \true); } return $clauses; } /** * Negates a set of clauses * negateClauses([$a || $b]) => !$a && !$b * negateClauses([$a, $b]) => !$a || !$b * negateClauses([$a, $b || $c]) => * (!$a || !$b) && * (!$a || !$c) * negateClauses([$a, $b || $c, $d || $e || $f]) => * (!$a || !$b || !$d) && * (!$a || !$b || !$e) && * (!$a || !$b || !$f) && * (!$a || !$c || !$d) && * (!$a || !$c || !$e) && * (!$a || !$c || !$f) * * @param list $clauses * @return non-empty-list */ public static function negateFormula(array $clauses) : array { $clauses = array_filter($clauses, static fn(\Psalm\Internal\Clause $clause): bool => $clause->reconcilable); if (!$clauses) { $cond_id = mt_rand(0, 100000000); return [new \Psalm\Internal\Clause([], $cond_id, $cond_id, \true)]; } $clauses_with_impossibilities = []; foreach ($clauses as $clause) { $clauses_with_impossibilities[] = $clause->calculateNegation(); } unset($clauses); $impossible_clauses = self::groupImpossibilities($clauses_with_impossibilities); if (!$impossible_clauses) { $cond_id = mt_rand(0, 100000000); return [new \Psalm\Internal\Clause([], $cond_id, $cond_id, \true)]; } $negated = self::simplifyCNF($impossible_clauses); if (!$negated) { $cond_id = mt_rand(0, 100000000); return [new \Psalm\Internal\Clause([], $cond_id, $cond_id, \true)]; } return $negated; } } 'unknown', self::PHP_PARSER_PACKAGE => 'unknown']; } /** @return _VersionData|null */ private static function loadPharVersions() : ?array { if (!class_exists(Phar::class)) { return null; } $phar_filename = Phar::running(\true); if (!$phar_filename) { return null; } /** * @psalm-suppress UnresolvableInclude * @var _VersionData */ return require $phar_filename . '/phar-versions.php'; } /** @return _VersionData|null */ private static function loadComposerVersions() : ?array { try { return [self::PSALM_PACKAGE => self::getVersion(self::PSALM_PACKAGE), self::PHP_PARSER_PACKAGE => self::getVersion(self::PHP_PARSER_PACKAGE)]; } catch (OutOfBoundsException $ex) { } return null; } private static function getVersion(string $packageName) : string { return InstalledVersions::getPrettyVersion($packageName) . '@' . InstalledVersions::getReference($packageName); } } $args */ public static function handleOverride(array $args, Codebase $codebase) : void { if (count($args) < 2) { return; } $identifier = $args[0]->value; if (!$args[1]->value instanceof PhpParser\Node\Expr\FuncCall || !$args[1]->value->name instanceof PhpParser\Node\Name) { return; } $map = []; if ($args[1]->value->name->getParts() === ['map'] && $args[1]->value->getArgs() && $args[1]->value->getArgs()[0]->value instanceof PhpParser\Node\Expr\Array_) { foreach ($args[1]->value->getArgs()[0]->value->items as $array_item) { if ($array_item && $array_item->key instanceof PhpParser\Node\Scalar\String_) { if ($array_item->value instanceof PhpParser\Node\Expr\ClassConstFetch && $array_item->value->class instanceof PhpParser\Node\Name\FullyQualified && $array_item->value->name instanceof PhpParser\Node\Identifier && strtolower($array_item->value->name->name)) { $map[$array_item->key->value] = new Union([new TNamedObject($array_item->value->class->toString())]); } elseif ($array_item->value instanceof PhpParser\Node\Scalar\String_) { $map[$array_item->key->value] = $array_item->value->value; } } elseif ($array_item && $array_item->key instanceof PhpParser\Node\Expr\ClassConstFetch && $array_item->key->class instanceof PhpParser\Node\Name\FullyQualified && $array_item->key->name instanceof PhpParser\Node\Identifier) { /** @var string|null $resolved_name */ $resolved_name = $array_item->key->class->getAttribute('resolvedName'); if (!$resolved_name) { continue; } $constant_type = $codebase->classlikes->getClassConstantType($resolved_name, $array_item->key->name->name, ReflectionProperty::IS_PRIVATE); if (!$constant_type instanceof Union || !$constant_type->isSingleStringLiteral()) { continue; } $meta_key = $constant_type->getSingleStringLiteral()->value; if ($array_item->value instanceof PhpParser\Node\Expr\ClassConstFetch && $array_item->value->class instanceof PhpParser\Node\Name\FullyQualified && $array_item->value->name instanceof PhpParser\Node\Identifier && strtolower($array_item->value->name->name)) { $map[$meta_key] = new Union([new TNamedObject($array_item->value->class->toString())]); } elseif ($array_item->value instanceof PhpParser\Node\Scalar\String_) { $map[$meta_key] = $array_item->value->value; } } } } $type_offset = null; if ($args[1]->value->name->getParts() === ['type'] && $args[1]->value->getArgs() && $args[1]->value->getArgs()[0]->value instanceof PhpParser\Node\Scalar\LNumber) { $type_offset = $args[1]->value->getArgs()[0]->value->value; } $element_type_offset = null; if ($args[1]->value->name->getParts() === ['elementType'] && $args[1]->value->getArgs() && $args[1]->value->getArgs()[0]->value instanceof PhpParser\Node\Scalar\LNumber) { $element_type_offset = $args[1]->value->getArgs()[0]->value->value; } if ($identifier instanceof PhpParser\Node\Expr\StaticCall && $identifier->class instanceof PhpParser\Node\Name\FullyQualified && $identifier->name instanceof PhpParser\Node\Identifier && ($identifier->getArgs() === [] || $identifier->getArgs()[0]->value instanceof PhpParser\Node\Scalar\LNumber)) { $meta_fq_classlike_name = $identifier->class->toString(); $meta_method_name = strtolower($identifier->name->name); if ($map) { $offset = 0; if ($identifier->getArgs() && $identifier->getArgs()[0]->value instanceof PhpParser\Node\Scalar\LNumber) { $offset = $identifier->getArgs()[0]->value->value; } $codebase->methods->return_type_provider->registerClosure($meta_fq_classlike_name, static function (MethodReturnTypeProviderEvent $event) use($map, $offset, $meta_fq_classlike_name, $meta_method_name) : ?Union { $statements_analyzer = $event->getSource(); $call_args = $event->getCallArgs(); $method_name = $event->getMethodNameLowercase(); $fq_classlike_name = $event->getFqClasslikeName(); if (!$statements_analyzer instanceof StatementsAnalyzer) { return Type::getMixed(); } if ($meta_method_name !== $method_name || $meta_fq_classlike_name !== $fq_classlike_name) { return null; } if (isset($call_args[$offset]->value) && ($call_arg_type = $statements_analyzer->node_data->getType($call_args[$offset]->value)) && $call_arg_type->isSingleStringLiteral()) { $offset_arg_value = $call_arg_type->getSingleStringLiteral()->value; if ($mapped_type = $map[$offset_arg_value] ?? null) { if ($mapped_type instanceof Union) { return $mapped_type; } } if (($mapped_type = $map[''] ?? null) && is_string($mapped_type)) { if (strpos($mapped_type, '@') !== \false) { $mapped_type = str_replace('@', $offset_arg_value, $mapped_type); if (strpos($mapped_type, '.') === \false) { return new Union([new TNamedObject($mapped_type)]); } } } } return null; }); } elseif ($type_offset !== null) { $codebase->methods->return_type_provider->registerClosure($meta_fq_classlike_name, static function (MethodReturnTypeProviderEvent $event) use($type_offset, $meta_fq_classlike_name, $meta_method_name) : ?Union { $statements_analyzer = $event->getSource(); $call_args = $event->getCallArgs(); $method_name = $event->getMethodNameLowercase(); $fq_classlike_name = $event->getFqClasslikeName(); if (!$statements_analyzer instanceof StatementsAnalyzer) { return Type::getMixed(); } if ($meta_method_name !== $method_name || $meta_fq_classlike_name !== $fq_classlike_name) { return null; } if (isset($call_args[$type_offset]->value) && ($call_arg_type = $statements_analyzer->node_data->getType($call_args[$type_offset]->value))) { return $call_arg_type; } return null; }); } elseif ($element_type_offset !== null) { $codebase->methods->return_type_provider->registerClosure($meta_fq_classlike_name, static function (MethodReturnTypeProviderEvent $event) use($element_type_offset, $meta_fq_classlike_name, $meta_method_name) : ?Union { $statements_analyzer = $event->getSource(); $call_args = $event->getCallArgs(); $method_name = $event->getMethodNameLowercase(); $fq_classlike_name = $event->getFqClasslikeName(); if (!$statements_analyzer instanceof StatementsAnalyzer) { return Type::getMixed(); } if ($meta_method_name !== $method_name || $meta_fq_classlike_name !== $fq_classlike_name) { return null; } if (isset($call_args[$element_type_offset]->value) && ($call_arg_type = $statements_analyzer->node_data->getType($call_args[$element_type_offset]->value)) && $call_arg_type->hasArray()) { /** * @var TArray|TKeyedArray */ $array_atomic_type = $call_arg_type->getArray(); if ($array_atomic_type instanceof TKeyedArray) { return $array_atomic_type->getGenericValueType(); } return $array_atomic_type->type_params[1]; } return null; }); } } if ($identifier instanceof PhpParser\Node\Expr\FuncCall && $identifier->name instanceof PhpParser\Node\Name\FullyQualified && ($identifier->getArgs() === [] || $identifier->getArgs()[0]->value instanceof PhpParser\Node\Scalar\LNumber)) { $function_id = strtolower($identifier->name->toString()); if ($map) { $offset = 0; if ($identifier->getArgs() && $identifier->getArgs()[0]->value instanceof PhpParser\Node\Scalar\LNumber) { $offset = $identifier->getArgs()[0]->value->value; } $codebase->functions->return_type_provider->registerClosure($function_id, static function (FunctionReturnTypeProviderEvent $event) use($map, $offset) : Union { $statements_analyzer = $event->getStatementsSource(); $call_args = $event->getCallArgs(); $function_id = $event->getFunctionId(); if (!$statements_analyzer instanceof StatementsAnalyzer) { return Type::getMixed(); } if (isset($call_args[$offset]->value) && ($call_arg_type = $statements_analyzer->node_data->getType($call_args[$offset]->value)) && $call_arg_type->isSingleStringLiteral()) { $offset_arg_value = $call_arg_type->getSingleStringLiteral()->value; if ($mapped_type = $map[$offset_arg_value] ?? null) { if ($mapped_type instanceof Union) { return $mapped_type; } } if (($mapped_type = $map[''] ?? null) && is_string($mapped_type)) { if (strpos($mapped_type, '@') !== \false) { $mapped_type = str_replace('@', $offset_arg_value, $mapped_type); if (strpos($mapped_type, '.') === \false) { return new Union([new TNamedObject($mapped_type)]); } } } } $storage = $statements_analyzer->getCodebase()->functions->getStorage($statements_analyzer, strtolower($function_id)); return $storage->return_type ?: Type::getMixed(); }); } elseif ($type_offset !== null) { $codebase->functions->return_type_provider->registerClosure($function_id, static function (FunctionReturnTypeProviderEvent $event) use($type_offset) : Union { $statements_analyzer = $event->getStatementsSource(); $call_args = $event->getCallArgs(); $function_id = $event->getFunctionId(); if (!$statements_analyzer instanceof StatementsAnalyzer) { return Type::getMixed(); } if (isset($call_args[$type_offset]->value) && ($call_arg_type = $statements_analyzer->node_data->getType($call_args[$type_offset]->value))) { return $call_arg_type; } $storage = $statements_analyzer->getCodebase()->functions->getStorage($statements_analyzer, strtolower($function_id)); return $storage->return_type ?: Type::getMixed(); }); } elseif ($element_type_offset !== null) { $codebase->functions->return_type_provider->registerClosure($function_id, static function (FunctionReturnTypeProviderEvent $event) use($element_type_offset) : Union { $statements_analyzer = $event->getStatementsSource(); $call_args = $event->getCallArgs(); $function_id = $event->getFunctionId(); if (!$statements_analyzer instanceof StatementsAnalyzer) { return Type::getMixed(); } if (isset($call_args[$element_type_offset]->value) && ($call_arg_type = $statements_analyzer->node_data->getType($call_args[$element_type_offset]->value)) && $call_arg_type->hasArray()) { /** * @var TArray|TKeyedArray */ $array_atomic_type = $call_arg_type->getArray(); if ($array_atomic_type instanceof TKeyedArray) { return $array_atomic_type->getGenericValueType(); } return $array_atomic_type->type_params[1]; } $storage = $statements_analyzer->getCodebase()->functions->getStorage($statements_analyzer, strtolower($function_id)); return $storage->return_type ?: Type::getMixed(); }); } } } } */ public array $params = []; /** * @var array */ public array $params_out = []; /** * @var array{type:string, line_number: int}|null */ public ?array $self_out = null; /** * @var array{type:string, line_number: int}|null */ public ?array $if_this_is = null; /** * @var array */ public array $globals = []; /** * Whether or not the function is deprecated */ public bool $deprecated = \false; /** * If set, the function is internal to the given namespace. * * @var list */ public array $psalm_internal = []; /** * Whether or not the function is internal */ public bool $internal = \false; /** * Whether or not the function uses get_args */ public bool $variadic = \false; /** * Whether or not the function is pure */ public bool $pure = \false; /** * Whether or not to specialize a given call (useful for taint analysis) */ public bool $specialize_call = \false; /** * Represents the flow from function params to return type * * @var array */ public array $flows = []; /** * @var array */ public array $added_taints = []; /** * @var array */ public array $removed_taints = []; /** * @var array */ public array $taint_sink_params = []; /** * @var array */ public array $taint_source_types = []; /** * @var array */ public array $assert_untainted_params = []; /** * Whether or not to ignore the nullability of this function's return type */ public bool $ignore_nullable_return = \false; /** * Whether or not to ignore the nullability of this function's return type */ public bool $ignore_falsable_return = \false; /** * @var array */ public array $suppressed_issues = []; /** * @var array */ public array $throws = []; /** * @var array */ public array $templates = []; /** * @var array */ public array $assertions = []; /** * @var array */ public array $if_true_assertions = []; /** * @var array */ public array $if_false_assertions = []; public bool $inheritdoc = \false; public bool $mutation_free = \false; public bool $external_mutation_free = \false; public bool $no_named_args = \false; public bool $stub_override = \false; public int $since_php_major_version = 0; public int $since_php_minor_version = 0; public ?string $description = null; /** @var array, suggested_replacement?:string}> */ public array $unexpected_tags = []; public bool $public_api = \false; } $line) { if (strpos($line, '@') !== \false && preg_match('/^ *\\*?\\s*@\\w/', $line)) { $last = $k; } elseif (trim($line) === '') { $last = \false; } elseif ($last !== \false) { $old_last_line = $lines[$last]; $lines[$last] = $old_last_line . "\n" . $line; unset($lines[$k]); } } $line_offset = 0; foreach ($lines as $k => $line) { $original_line_length = strlen($line); if ($has_r === \true) { $line = str_replace("\r", '', $line); } if ($first_line_padding === null) { $asterisk_pos = strpos($line, '*'); if ($asterisk_pos === 0 || $asterisk_pos === 1) { $first_line_padding = ''; } elseif ($asterisk_pos > 1) { $first_line_padding = substr($line, 0, $asterisk_pos - 1); } } if (preg_match('/^ *\\*?\\s*@([\\w\\-\\\\:]+) *(.*)$/sm', $line, $matches, PREG_OFFSET_CAPTURE)) { /** @var array $matches */ [, $type_info, $data_info] = $matches; [$type] = $type_info; [$data, $data_offset] = $data_info; if (strpos($data, '*') !== \false) { $data = rtrim(preg_replace('/^ *\\*\\s*$/m', '', $data)); } if (empty($special[$type])) { $special[$type] = []; } $data_offset += $line_offset; $special[$type][$data_offset + 3 + $offsetStart] = $data; unset($lines[$k]); } else { // Strip the leading *, if present. // technically only need to preg_replace('/^ *\*/', '', $lines[$k], 1) // however it's slower and removing all spaces and * is fine $lines[$k] = ltrim($lines[$k], ' *'); } $line_offset += $original_line_length + 1; } // Smush the whole docblock to the left edge. $min_indent = 80; $reached_first_non_empty_line = \false; foreach ($lines as $k => $line) { $indent = strspn($line, ' '); if ($indent === strlen($line)) { // This line consists of only spaces. Trim it completely. if ($reached_first_non_empty_line === \false) { // remove any leading empty lines here, to avoid a preg_replace later unset($lines[$k]); continue; } $lines[$k] = ''; continue; } $reached_first_non_empty_line = \true; $min_indent = min($indent, $min_indent); } if ($min_indent > 0) { foreach ($lines as $k => $line) { if (strlen($line) < $min_indent) { continue; } $lines[$k] = substr($line, $min_indent); } } $docblock = implode("\n", $lines); $docblock = rtrim($docblock); $parsed = new \Psalm\Internal\Scanner\ParsedDocblock($docblock, $special, $first_line_padding ?: ''); self::resolveTags($parsed); return $parsed; } private static function resolveTags(\Psalm\Internal\Scanner\ParsedDocblock $docblock) : void { if (isset($docblock->tags['template']) || isset($docblock->tags['psalm-template']) || isset($docblock->tags['phpstan-template'])) { $docblock->combined_tags['template'] = ($docblock->tags['template'] ?? []) + ($docblock->tags['phpstan-template'] ?? []) + ($docblock->tags['psalm-template'] ?? []); } if (isset($docblock->tags['template-covariant']) || isset($docblock->tags['psalm-template-covariant']) || isset($docblock->tags['phpstan-template-covariant'])) { $docblock->combined_tags['template-covariant'] = ($docblock->tags['template-covariant'] ?? []) + ($docblock->tags['phpstan-template-covariant'] ?? []) + ($docblock->tags['psalm-template-covariant'] ?? []); } if (isset($docblock->tags['template-extends']) || isset($docblock->tags['inherits']) || isset($docblock->tags['extends']) || isset($docblock->tags['psalm-extends']) || isset($docblock->tags['phpstan-extends'])) { $docblock->combined_tags['extends'] = ($docblock->tags['template-extends'] ?? []) + ($docblock->tags['inherits'] ?? []) + ($docblock->tags['extends'] ?? []) + ($docblock->tags['psalm-extends'] ?? []) + ($docblock->tags['phpstan-extends'] ?? []); } if (isset($docblock->tags['template-implements']) || isset($docblock->tags['implements']) || isset($docblock->tags['phpstan-implements']) || isset($docblock->tags['psalm-implements'])) { $docblock->combined_tags['implements'] = ($docblock->tags['template-implements'] ?? []) + ($docblock->tags['implements'] ?? []) + ($docblock->tags['phpstan-implements'] ?? []) + ($docblock->tags['psalm-implements'] ?? []); } if (isset($docblock->tags['template-use']) || isset($docblock->tags['use']) || isset($docblock->tags['phpstan-use']) || isset($docblock->tags['psalm-use'])) { $docblock->combined_tags['use'] = ($docblock->tags['template-use'] ?? []) + ($docblock->tags['use'] ?? []) + ($docblock->tags['phpstan-use'] ?? []) + ($docblock->tags['psalm-use'] ?? []); } if (isset($docblock->tags['method']) || isset($docblock->tags['psalm-method'])) { $docblock->combined_tags['method'] = ($docblock->tags['method'] ?? []) + ($docblock->tags['psalm-method'] ?? []); } if (isset($docblock->tags['return']) || isset($docblock->tags['psalm-return']) || isset($docblock->tags['phpstan-return'])) { if (isset($docblock->tags['psalm-return'])) { $docblock->combined_tags['return'] = $docblock->tags['psalm-return']; } elseif (isset($docblock->tags['phpstan-return'])) { $docblock->combined_tags['return'] = $docblock->tags['phpstan-return']; } else { $docblock->combined_tags['return'] = $docblock->tags['return']; } } if (isset($docblock->tags['param']) || isset($docblock->tags['psalm-param']) || isset($docblock->tags['phpstan-param'])) { $docblock->combined_tags['param'] = ($docblock->tags['param'] ?? []) + ($docblock->tags['phpstan-param'] ?? []) + ($docblock->tags['psalm-param'] ?? []); } if (isset($docblock->tags['var']) || isset($docblock->tags['psalm-var']) || isset($docblock->tags['phpstan-var'])) { if (!isset($docblock->tags['ignore-var']) && !isset($docblock->tags['psalm-ignore-var'])) { $docblock->combined_tags['var'] = ($docblock->tags['var'] ?? []) + ($docblock->tags['phpstan-var'] ?? []) + ($docblock->tags['psalm-var'] ?? []); } } if (isset($docblock->tags['param-out']) || isset($docblock->tags['psalm-param-out']) || isset($docblock->tags['phpstan-param-out'])) { $docblock->combined_tags['param-out'] = ($docblock->tags['param-out'] ?? []) + ($docblock->tags['phpstan-param-out'] ?? []) + ($docblock->tags['psalm-param-out'] ?? []); } } /** * @return list * @throws DocblockParseException when a @psalm-internal tag doesn't include a namespace */ public static function handlePsalmInternal(\Psalm\Internal\Scanner\ParsedDocblock $parsed_docblock) : array { if (isset($parsed_docblock->tags['psalm-internal'])) { $psalm_internal = array_map("trim", $parsed_docblock->tags['psalm-internal']); if (count($psalm_internal) !== count(array_filter($psalm_internal))) { throw new DocblockParseException('psalm-internal annotation used without specifying namespace'); } // assert($psalm_internal === array_filter($psalm_internal)); // TODO get this to work assert(self::assertArrayOfNonEmptyString($psalm_internal)); return array_values($psalm_internal); } return []; } /** @psalm-assert-if-true array $arr */ private static function assertArrayOfNonEmptyString(array $arr) : bool { foreach ($arr as $val) { if (!is_string($val) || $val === "") { return \false; } } return \true; } } file_path = $file_path; $this->file_name = $file_name; $this->will_analyze = $will_analyze; } public function scan(Codebase $codebase, FileStorage $file_storage, bool $storage_from_cache = \false, ?Progress $progress = null) : void { if ($progress === null) { $progress = new VoidProgress(); } if ((!$this->will_analyze || $file_storage->deep_scan) && $storage_from_cache && !$codebase->register_stub_files) { return; } $stmts = $codebase->statements_provider->getStatementsForFile($file_storage->file_path, $codebase->analysis_php_version_id, $progress); foreach ($stmts as $stmt) { if (!$stmt instanceof PhpParser\Node\Stmt\ClassLike && !$stmt instanceof PhpParser\Node\Stmt\Function_ && !($stmt instanceof PhpParser\Node\Stmt\Expression && $stmt->expr instanceof PhpParser\Node\Expr\Include_)) { $file_storage->has_extra_statements = \true; break; } } if ($this->will_analyze) { $progress->debug('Deep scanning ' . $file_storage->file_path . "\n"); } else { $progress->debug('Scanning ' . $file_storage->file_path . "\n"); } $traverser = new NodeTraverser(); $traverser->addVisitor(new ReflectorVisitor($codebase, $this, $file_storage)); $traverser->traverse($stmts); $file_storage->deep_scan = $this->will_analyze; } /** @psalm-mutation-free */ public function getFilePath() : string { return $this->file_path; } /** @psalm-mutation-free */ public function getFileName() : string { return $this->file_name; } /** @psalm-mutation-free */ public function getRootFilePath() : string { return $this->file_path; } /** @psalm-mutation-free */ public function getRootFileName() : string { return $this->file_name; } /** @psalm-mutation-free */ public function getAliases() : Aliases { return new Aliases(); } } */ public array $psalm_internal = []; /** * @var string[] */ public array $mixins = []; /** * @var array */ public array $templates = []; /** * @var array */ public array $template_extends = []; /** * @var array */ public array $template_implements = []; public ?string $yield = null; /** * @var array */ public array $properties = []; /** * @var array */ public array $methods = []; public ?bool $sealed_properties = null; public ?bool $sealed_methods = null; public bool $override_property_visibility = \false; public bool $override_method_visibility = \false; public bool $mutation_free = \false; public bool $external_mutation_free = \false; public bool $taint_specialize = \false; /** * @var array */ public array $suppressed_issues = []; /** * @var list}> */ public array $imported_types = []; public ?string $inheritors = null; public bool $consistent_constructor = \false; public bool $consistent_templates = \false; public bool $stub_override = \false; public ?string $extension_requirement = null; /** * @var array */ public array $implementation_requirements = []; public ?string $description = null; public bool $public_api = \false; } > */ public array $tags = []; /** @var array> */ public array $combined_tags = []; private static bool $shouldAddNewLineBetweenAnnotations = \true; /** @param array> $tags */ public function __construct(string $description, array $tags, string $first_line_padding = '') { $this->description = $description; $this->tags = $tags; $this->first_line_padding = $first_line_padding; } public function render(string $left_padding) : string { $doc_comment_text = '/**' . "\n"; $trimmed_description = trim($this->description); if ($trimmed_description !== '') { $description_lines = explode("\n", $this->description); foreach ($description_lines as $line) { $doc_comment_text .= $left_padding . ' *' . (trim($line) ? ' ' . $line : '') . "\n"; } } if ($this->tags) { if ($trimmed_description !== '') { $doc_comment_text .= $left_padding . ' *' . "\n"; } $last_type = null; foreach ($this->tags as $type => $lines) { if ($last_type !== null && $last_type !== 'psalm-return' && static::shouldAddNewLineBetweenAnnotations()) { $doc_comment_text .= $left_padding . ' *' . "\n"; } foreach ($lines as $line) { $doc_comment_text .= $left_padding . ' * @' . $type . ($line !== '' ? ' ' . $line : '') . "\n"; } $last_type = $type; } } $doc_comment_text .= $left_padding . ' */' . "\n" . $left_padding; return $doc_comment_text; } private static function shouldAddNewLineBetweenAnnotations() : bool { return static::$shouldAddNewLineBetweenAnnotations; } /** * Sets whether a new line should be added between the annotations or not. */ public static function addNewLineBetweenAnnotations(bool $should = \true) : void { static::$shouldAddNewLineBetweenAnnotations = $should; } public static function resetNewlineBetweenAnnotations() : void { static::$shouldAddNewLineBetweenAnnotations = \true; } } */ public array $psalm_internal = []; /** * Whether or not the property is readonly */ public bool $readonly = \false; /** * Whether or not to allow mutation by internal methods */ public bool $allow_private_mutation = \false; /** * @var list */ public array $removed_taints = []; /** * @var array */ public array $suppressed_issues = []; public ?string $description = null; } key = $key; $this->value = $value; } } value = $value; } } left = $left; $this->right = $right; } } array = $left; $this->offset = $right; } } fqcln = $fqcln; $this->name = $name; } } fqcln = $fqcln; $this->case = $case; } } cond = $cond; $this->if = $if; $this->else = $else; } } */ public array $entries; /** @param list $entries */ public function __construct(array $entries) { $this->entries = $entries; } } array = $array; } } name = $name; $this->is_fully_qualified = $is_fully_qualified; } } ['falsy'], * '$b' => ['!falsy'], * '$c' => ['!null'], * '$d' => ['string', 'int'] * ] * * representing the formula * * !$a || $b || $c !== null || is_string($d) || is_int($d) * * @var array> */ public array $possibilities; /** * An array of things that are not true * [ * '$a' => ['!falsy'], * '$b' => ['falsy'], * '$c' => ['null'], * '$d' => ['!string', '!int'] * ] * represents the formula * * $a && !$b && $c === null && !is_string($d) && !is_int($d) * * @var array>|null */ public ?array $impossibilities = null; public bool $wedge; public bool $reconcilable; public bool $generated = \false; /** @var array */ public array $redefined_vars = []; public string $hash; /** * @param array> $possibilities * @param array $redefined_vars */ public function __construct(array $possibilities, int $creating_conditional_id, int $creating_object_id, bool $wedge = \false, bool $reconcilable = \true, bool $generated = \false, array $redefined_vars = []) { if ($wedge || !$reconcilable) { $this->hash = ($wedge ? 'w' : '') . $creating_object_id; } else { ksort($possibilities); $possibility_strings = []; foreach ($possibilities as $i => $v) { if (count($v) > 1) { ksort($v); } $possibility_strings[$i] = array_keys($v); } /** @psalm-suppress ImpureFunctionCall */ $data = serialize($possibility_strings); $this->hash = PHP_VERSION_ID >= 80100 ? hash('xxh128', $data) : hash('md4', $data); } $this->possibilities = $possibilities; $this->wedge = $wedge; $this->reconcilable = $reconcilable; $this->generated = $generated; $this->redefined_vars = $redefined_vars; $this->creating_conditional_id = $creating_conditional_id; $this->creating_object_id = $creating_object_id; } public function contains(\Psalm\Internal\Clause $other_clause) : bool { if (count($other_clause->possibilities) > count($this->possibilities)) { return \false; } foreach ($other_clause->possibilities as $var => $_) { if (!isset($this->possibilities[$var])) { return \false; } } foreach ($other_clause->possibilities as $var => $possible_types) { if (count(array_diff($possible_types, $this->possibilities[$var]))) { return \false; } } return \true; } /** * @psalm-mutation-free */ public function __toString() : string { $clause_strings = []; foreach ($this->possibilities as $var_id => $values) { if ($var_id[0] === '*') { $var_id = ''; } $var_id_clauses = []; foreach ($values as $value) { $value = (string) $value; if ($value === 'falsy') { $var_id_clauses[] = '!' . $var_id; continue; } if ($value === '!falsy') { $var_id_clauses[] = $var_id; continue; } $negate = \false; if ($value[0] === '!') { $negate = \true; $value = substr($value, 1); } if ($value[0] === '=') { $value = substr($value, 1); } if ($negate) { $var_id_clauses[] = $var_id . ' is not ' . $value; continue; } $var_id_clauses[] = $var_id . ' is ' . $value; } if (count($var_id_clauses) > 1) { $clause_strings[] = '(' . implode(') || (', $var_id_clauses) . ')'; } else { $clause_strings[] = reset($var_id_clauses); } } if (count($clause_strings) > 1) { return '(' . implode(') || (', $clause_strings) . ')'; } return reset($clause_strings); } public function removePossibilities(string $var_id) : ?self { $possibilities = $this->possibilities; unset($possibilities[$var_id]); if (!$possibilities) { return null; } return new self($possibilities, $this->creating_conditional_id, $this->creating_object_id, $this->wedge, $this->reconcilable, $this->generated, $this->redefined_vars); } /** * @param non-empty-array $clause_var_possibilities */ public function addPossibilities(string $var_id, array $clause_var_possibilities) : self { $possibilities = $this->possibilities; $possibilities[$var_id] = $clause_var_possibilities; return new self($possibilities, $this->creating_conditional_id, $this->creating_object_id, $this->wedge, $this->reconcilable, $this->generated, $this->redefined_vars); } public function calculateNegation() : self { if ($this->impossibilities !== null) { return $this; } $impossibilities = []; foreach ($this->possibilities as $var_id => $possibility) { $impossibility = []; foreach ($possibility as $type) { if (!$type->hasEquality() || ($inner_type = $type->getAtomicType()) && ($inner_type instanceof TLiteralInt || $inner_type instanceof TLiteralFloat || $inner_type instanceof TLiteralString || $inner_type instanceof TClassConstant || $inner_type instanceof TEnumCase)) { $impossibility[] = $type->getNegation(); } } if ($impossibility) { $impossibilities[$var_id] = $impossibility; } } $clause = clone $this; $clause->impossibilities = $impossibilities; return $clause; } } old = strtolower($old); $this->new = $new; } protected function enterNode(TypeNode &$type) : ?int { if ($type instanceof TClassConstant) { if (strtolower($type->fq_classlike_name) === $this->old) { $type = new TClassConstant($this->new, $type->const_name, $type->from_docblock); } } elseif ($type instanceof TClassString) { if ($type->as !== 'object' && strtolower($type->as) === $this->old) { $type = new TClassString($this->new, $type->as_type, $type->is_loaded, $type->is_interface, $type->is_enum, $type->from_docblock); } } elseif ($type instanceof TNamedObject || $type instanceof TLiteralClassString) { if (strtolower($type->value) === $this->old) { $type = $type->setValue($this->new); } } return null; } } value === 'static' || $type->is_static)) { $this->contains_static = \true; return self::STOP_TRAVERSAL; } return null; } public function matches() : bool { return $this->contains_static; } } */ private array $phantom_classes; /** * @param array $phantom_classes */ public function __construct(Scanner $scanner, ?FileStorage $file_storage, array $phantom_classes) { $this->scanner = $scanner; $this->file_storage = $file_storage; $this->phantom_classes = $phantom_classes; } protected function enterNode(TypeNode $type) : ?int { if ($type instanceof TNamedObject) { $fq_classlike_name_lc = strtolower($type->value); if (!isset($this->phantom_classes[$type->value]) && !isset($this->phantom_classes[$fq_classlike_name_lc])) { $this->scanner->queueClassLikeForScanning($type->value, \false, !$type->from_docblock, $this->phantom_classes); if ($this->file_storage) { $this->file_storage->referenced_classlikes[$fq_classlike_name_lc] = $type->value; } } } if ($type instanceof TClassConstant) { $this->scanner->queueClassLikeForScanning($type->fq_classlike_name, \false, !$type->from_docblock, $this->phantom_classes); if ($this->file_storage) { $fq_classlike_name_lc = strtolower($type->fq_classlike_name); $this->file_storage->referenced_classlikes[$fq_classlike_name_lc] = $type->fq_classlike_name; } } if ($type instanceof TLiteralClassString) { $this->scanner->queueClassLikeForScanning($type->value, \false, !$type->from_docblock, $this->phantom_classes); if ($this->file_storage) { $fq_classlike_name_lc = strtolower($type->value); $this->file_storage->referenced_classlikes[$fq_classlike_name_lc] = $type->value; } } return null; } } contains_literal = \true; return self::STOP_TRAVERSAL; } if ($type instanceof TArray && $type->isEmptyArray()) { $this->contains_literal = \true; return self::STOP_TRAVERSAL; } return null; } public function matches() : bool { return $this->contains_literal; } } > */ private array $extends; private string $base_fq_class_name; /** * @param array> $extends */ public function __construct(array $extends, string $base_fq_class_name) { $this->extends = $extends; $this->base_fq_class_name = $base_fq_class_name; } protected function enterNode(TypeNode &$type) : ?int { if ($type instanceof TTemplateParamClass) { if ($type->defining_class === $this->base_fq_class_name) { if (isset($this->extends[$this->base_fq_class_name][$type->param_name])) { $extended_param = $this->extends[$this->base_fq_class_name][$type->param_name]; $types = array_values($extended_param->getAtomicTypes()); if (count($types) === 1 && $types[0] instanceof TNamedObject) { $type = $type->setAs($type->as, $types[0]); } elseif ($type->as_type !== null) { $type = $type->setAs($type->as, null); } } } } if ($type instanceof Union) { $union = $type->getBuilder(); } elseif ($type instanceof MutableUnion) { $union = $type; } else { return null; } foreach ($union->getAtomicTypes() as $key => $atomic_type) { if ($atomic_type instanceof TTemplateParam && ($atomic_type->defining_class === $this->base_fq_class_name || isset($this->extends[$atomic_type->defining_class]))) { $types_to_add = Methods::getExtendedTemplatedTypes($atomic_type, $this->extends); if ($types_to_add) { $union->removeType($key); foreach ($types_to_add as $extra_added_type) { $union->addType($extra_added_type); } } } } if ($type instanceof Union) { $type = $union->freeze(); } else { $type = $union; } return null; } } from_docblock = $from_docblock; } /** * @return self::STOP_TRAVERSAL|self::DONT_TRAVERSE_CHILDREN|null */ protected function enterNode(TypeNode &$type) : ?int { if (!$type instanceof Atomic && !$type instanceof Union && !$type instanceof MutableUnion) { return null; } if ($type->from_docblock === $this->from_docblock) { return null; } if ($type instanceof MutableUnion) { $type->from_docblock = \true; } elseif ($type instanceof Union) { $type = $type->setProperties(['from_docblock' => $this->from_docblock]); } else { $type = $type->setFromDocblock($this->from_docblock); } if ($type instanceof TTemplateParam && $type->as->isMixed()) { return self::DONT_TRAVERSE_CHILDREN; } return null; } } codebase = $codebase; } protected function enterNode(TypeNode $type) : ?int { if ($type instanceof Union && ($type->hasObjectType() || $type->hasIterable() || $type->hasMixed()) || $type instanceof Atomic && ($type->isObjectType() || $type->isIterable($this->codebase) || $type instanceof TMixed)) { $this->contains_object_type = \true; return self::STOP_TRAVERSAL; } return null; } public function matches() : bool { return $this->contains_object_type; } } */ private array $template_types = []; protected function enterNode(TypeNode $type) : ?int { if ($type instanceof TTemplateParam) { $this->template_types[] = $type; } elseif ($type instanceof TTemplateParamClass) { $extends = $type->as_type; $this->template_types[] = new TTemplateParam($type->param_name, $extends ? new Union([$extends]) : Type::getMixed(), $type->defining_class); } elseif ($type instanceof TConditional) { $this->template_types[] = new TTemplateParam($type->param_name, Type::getMixed(), $type->defining_class); } return null; } /** * @return list */ public function getTemplateTypes() : array { return $this->template_types; } } */ private array $suppressed_issues; /** * @var array */ private array $phantom_classes; private bool $inferred; private bool $inherited; private bool $prevent_template_covariance; private bool $has_errors = \false; private ?string $calling_method_id = null; /** * @param array $suppressed_issues * @param array $phantom_classes */ public function __construct(StatementsSource $source, CodeLocation $code_location, array $suppressed_issues, array $phantom_classes = [], bool $inferred = \true, bool $inherited = \false, bool $prevent_template_covariance = \false, ?string $calling_method_id = null) { $this->source = $source; $this->code_location = $code_location; $this->suppressed_issues = $suppressed_issues; $this->phantom_classes = $phantom_classes; $this->inferred = $inferred; $this->inherited = $inherited; $this->prevent_template_covariance = $prevent_template_covariance; $this->calling_method_id = $calling_method_id; } /** * @return self::STOP_TRAVERSAL|self::DONT_TRAVERSE_CHILDREN|null */ protected function enterNode(TypeNode $type) : ?int { if (!$type instanceof Atomic && !$type instanceof Union && !$type instanceof MutableUnion) { return null; } if ($type->checked) { return self::DONT_TRAVERSE_CHILDREN; } if ($type instanceof TNamedObject) { $this->checkNamedObject($type); } elseif ($type instanceof TClassConstant) { $this->checkScalarClassConstant($type); } elseif ($type instanceof TTemplateParam) { $this->checkTemplateParam($type); } elseif ($type instanceof TResource) { $this->checkResource($type); } /** @psalm-suppress InaccessibleProperty Doesn't affect anything else */ $type->checked = \true; return null; } public function hasErrors() : bool { return $this->has_errors; } private function checkNamedObject(TNamedObject $atomic) : void { $codebase = $this->source->getCodebase(); if ($this->code_location instanceof DocblockTypeLocation && $codebase->store_node_types && $atomic->offset_start !== null && $atomic->offset_end !== null) { $codebase->analyzer->addOffsetReference($this->source->getFilePath(), $this->code_location->raw_file_start + $atomic->offset_start, $this->code_location->raw_file_start + $atomic->offset_end, $atomic->value); } if ($this->calling_method_id && $atomic->text !== null) { $codebase->file_reference_provider->addMethodReferenceToClassMember($this->calling_method_id, 'use:' . $atomic->text . ':' . md5($this->source->getFilePath()), \false); } if (!isset($this->phantom_classes[strtolower($atomic->value)]) && ClassLikeAnalyzer::checkFullyQualifiedClassLikeName($this->source, $atomic->value, $this->code_location, $this->source->getFQCLN(), $this->calling_method_id, $this->suppressed_issues, new ClassLikeNameOptions($this->inferred, \false, \true, \true, $atomic->from_docblock)) === \false) { $this->has_errors = \true; return; } $fq_class_name_lc = strtolower($atomic->value); if (!$this->inherited && $codebase->classlike_storage_provider->has($fq_class_name_lc) && $this->source->getFQCLN() !== $atomic->value) { $class_storage = $codebase->classlike_storage_provider->get($fq_class_name_lc); if ($class_storage->deprecated) { if ($class_storage->is_interface) { IssueBuffer::maybeAdd(new DeprecatedInterface('Interface ' . $atomic->value . ' is marked as deprecated', $this->code_location, $atomic->value), $this->source->getSuppressedIssues() + $this->suppressed_issues); } else { IssueBuffer::maybeAdd(new DeprecatedClass('Class ' . $atomic->value . ' is marked as deprecated', $this->code_location, $atomic->value), $this->source->getSuppressedIssues() + $this->suppressed_issues); } } } if ($atomic instanceof TGenericObject) { $this->checkGenericParams($atomic); } } private function checkGenericParams(TGenericObject $atomic) : void { $codebase = $this->source->getCodebase(); try { $class_storage = $codebase->classlike_storage_provider->get(strtolower($atomic->value)); } catch (InvalidArgumentException $e) { return; } $expected_type_params = $class_storage->template_types ?: []; $expected_param_covariants = $class_storage->template_covariants; $template_type_count = count($expected_type_params); $template_param_count = count($atomic->type_params); if ($template_type_count > $template_param_count) { IssueBuffer::maybeAdd(new MissingTemplateParam($atomic->value . ' has missing template params, expecting ' . $template_type_count, $this->code_location), $this->suppressed_issues); } elseif ($template_type_count < $template_param_count) { IssueBuffer::maybeAdd(new TooManyTemplateParams($atomic->getId() . ' has too many template params, expecting ' . $template_type_count, $this->code_location), $this->suppressed_issues); } $expected_type_param_keys = array_keys($expected_type_params); $template_result = new TemplateResult($expected_type_params, []); foreach ($atomic->type_params as $i => $type_param) { $this->prevent_template_covariance = $this->source instanceof MethodAnalyzer && $this->source->getMethodName() !== '__construct' && empty($expected_param_covariants[$i]); if (isset($expected_type_param_keys[$i])) { $expected_template_name = $expected_type_param_keys[$i]; foreach ($expected_type_params[$expected_template_name] as $defining_class => $expected_type_param) { $expected_type_param = TemplateInferredTypeReplacer::replace(TypeExpander::expandUnion($codebase, $expected_type_param, $defining_class, null, null), $template_result, $codebase); $type_param = TypeExpander::expandUnion($codebase, $type_param, $defining_class, null, null); if (!UnionTypeComparator::isContainedBy($codebase, $type_param, $expected_type_param)) { IssueBuffer::maybeAdd(new InvalidTemplateParam('Extended template param ' . $expected_template_name . ' of ' . $atomic->getId() . ' expects type ' . $expected_type_param->getId() . ', type ' . $type_param->getId() . ' given', $this->code_location), $this->suppressed_issues); } else { $template_result->lower_bounds[$expected_template_name][$defining_class][] = new TemplateBound($type_param); } } } } } public function checkScalarClassConstant(TClassConstant $atomic) : void { $fq_classlike_name = $atomic->fq_classlike_name === 'self' ? $this->source->getClassName() : $atomic->fq_classlike_name; if (!$fq_classlike_name) { return; } if (ClassLikeAnalyzer::checkFullyQualifiedClassLikeName($this->source, $fq_classlike_name, $this->code_location, null, null, $this->suppressed_issues, new ClassLikeNameOptions($this->inferred, \false, \true, \true, $atomic->from_docblock)) === \false) { $this->has_errors = \true; return; } $const_name = $atomic->const_name; if (strpos($const_name, '*') !== \false) { TypeExpander::expandAtomic($this->source->getCodebase(), $atomic, $fq_classlike_name, $fq_classlike_name, null, \true, \true); $is_defined = \true; } else { $class_constant_type = $this->source->getCodebase()->classlikes->getClassConstantType($fq_classlike_name, $atomic->const_name, ReflectionProperty::IS_PRIVATE, null); $is_defined = null !== $class_constant_type; } if (!$is_defined) { IssueBuffer::maybeAdd(new UndefinedConstant('Constant ' . $fq_classlike_name . '::' . $const_name . ' is not defined', $this->code_location), $this->source->getSuppressedIssues()); } } public function checkTemplateParam(TTemplateParam $atomic) : void { if ($this->prevent_template_covariance && strpos($atomic->defining_class, 'fn-') !== 0 && $atomic->defining_class !== 'class-string-map') { $codebase = $this->source->getCodebase(); $class_storage = $codebase->classlike_storage_provider->get($atomic->defining_class); $template_offset = $class_storage->template_types ? array_search($atomic->param_name, array_keys($class_storage->template_types), \true) : \false; if ($template_offset !== \false && isset($class_storage->template_covariants[$template_offset]) && $class_storage->template_covariants[$template_offset]) { $method_storage = $this->source instanceof MethodAnalyzer ? $this->source->getFunctionLikeStorage() : null; if ($method_storage instanceof MethodStorage && $method_storage->mutation_free && !$method_storage->mutation_free_inferred) { // do nothing } else { IssueBuffer::maybeAdd(new InvalidTemplateParam('Template param ' . $atomic->param_name . ' of ' . $atomic->defining_class . ' is marked covariant and cannot be used here', $this->code_location), $this->source->getSuppressedIssues()); } } } } public function checkResource(TResource $atomic) : void { if (!$atomic->from_docblock) { IssueBuffer::maybeAdd(new ReservedWord('\'resource\' is a reserved word', $this->code_location, 'resource'), $this->source->getSuppressedIssues()); } } } fq_classlike_name = $fq_classlike_name; } /** * @psalm-external-mutation-free */ protected function enterNode(TypeNode $type) : ?int { if ($type instanceof TNamedObject) { if (strtolower($type->value) === $this->fq_classlike_name) { $this->contains_classlike = \true; return self::STOP_TRAVERSAL; } } if ($type instanceof TClassConstant) { if (strtolower($type->fq_classlike_name) === $this->fq_classlike_name) { $this->contains_classlike = \true; return self::STOP_TRAVERSAL; } } if ($type instanceof TLiteralClassString) { if (strtolower($type->value) === $this->fq_classlike_name) { $this->contains_classlike = \true; return self::STOP_TRAVERSAL; } } return null; } /** * @psalm-mutation-free */ public function matches() : bool { return $this->contains_classlike; } } offset_start = $offset_start; $this->offset_end = $offset_end; $this->value = $value; $this->parent = $parent; $this->text = $text === $value ? null : $text; } } value = $value; $this->parent = $parent; } } value = $value; $this->parent = $parent; } } value = $value; $this->parent = $parent; } } value = $value; $this->parent = $parent; } } value = $value; $this->parent = $parent; } } param_name = $param_name; $this->as = $as; $this->parent = $parent; } } value = $value; $this->parent = $parent; } } name = $name; $this->byref = $byref; $this->variadic = $variadic; $this->parent = $parent; } } param_name = $param_name; $this->parent = $parent; } } condition = $condition; $this->parent = $parent; } } getAtomicTypes() as $atomic_type) { if ($atomic_type instanceof TNamedObject) { $storage = $codebase->classlikes->getStorageFor($atomic_type->value); if (null === $storage || null === $storage->inheritors) { $new_types[] = $atomic_type; continue; } $template_result = self::getTemplateResult($atomic_type, $codebase); $replaced_inheritors = \Psalm\Internal\Type\TemplateInferredTypeReplacer::replace($storage->inheritors, $template_result, $codebase); foreach ($replaced_inheritors->getAtomicTypes() as $replaced_atomic_type) { $new_types[] = $replaced_atomic_type; } $meet_inheritors = \true; } else { $new_types[] = $atomic_type; } } if (!$meet_inheritors) { return $input; } return $new_types ? $input->setTypes($new_types) : $input; } private static function getTemplateResult(TNamedObject $object, Codebase $codebase) : \Psalm\Internal\Type\TemplateResult { if (!$object instanceof TGenericObject) { return new \Psalm\Internal\Type\TemplateResult([], []); } $storage = $codebase->classlikes->getStorageFor($object->value); if (null === $storage || null === $storage->template_types) { return new \Psalm\Internal\Type\TemplateResult([], []); } $lower_bounds = []; $offset = 0; foreach ($storage->template_types as $template_name => $templates) { foreach (array_keys($templates) as $defining_class) { $lower_bounds[$template_name][$defining_class] = $object->type_params[$offset++]; } } return new \Psalm\Internal\Type\TemplateResult($storage->template_types, $lower_bounds); } } */ public array $replacement_atomic_types; /** * @param list $replacement_atomic_types */ public function __construct(array $replacement_atomic_types) { $this->replacement_atomic_types = $replacement_atomic_types; } } */ public array $replacement_tokens; /** * @param list $replacement_tokens */ public function __construct(array $replacement_tokens) { $this->replacement_tokens = $replacement_tokens; } } declaring_fq_classlike_name = $declaring_fq_classlike_name; $this->alias_name = $alias_name; $this->line_number = $line_number; $this->start_offset = $start_offset; $this->end_offset = $end_offset; } } null, * - empty(bool) => false, * - notEmpty(Object|null) => Object, * - notEmpty(Object|false) => Object * * @param string[] $suppressed_issues * @param array> $template_type_map * @param-out Reconciler::RECONCILIATION_* $failed_reconciliation */ public static function reconcile(Assertion $assertion, ?Union $existing_var_type, ?string $key, StatementsAnalyzer $statements_analyzer, bool $inside_loop, array $template_type_map, ?CodeLocation $code_location = null, array $suppressed_issues = [], ?int &$failed_reconciliation = Reconciler::RECONCILIATION_OK, bool $negated = \false) : Union { $codebase = $statements_analyzer->getCodebase(); $failed_reconciliation = Reconciler::RECONCILIATION_OK; $is_negation = $assertion->isNegation(); if ($assertion instanceof NestedAssertions) { $assertion = new Falsy(); $is_negation = \true; } if ($existing_var_type === null && is_string($key) && VariableFetchAnalyzer::isSuperGlobal($key)) { $existing_var_type = VariableFetchAnalyzer::getGlobalType($key, $codebase->analysis_php_version_id); } if ($existing_var_type === null) { return self::getMissingType($assertion, $inside_loop); } $old_var_type_string = $existing_var_type->getId(); if ($is_negation) { return \Psalm\Internal\Type\NegatedAssertionReconciler::reconcile($statements_analyzer, $assertion, $existing_var_type, $old_var_type_string, $key, $negated, $code_location, $suppressed_issues, $failed_reconciliation, $inside_loop); } $assertion_type = $assertion->getAtomicType(); if ($assertion_type instanceof TLiteralInt || $assertion_type instanceof TLiteralString || $assertion_type instanceof TLiteralFloat || $assertion_type instanceof TEnumCase) { return self::handleLiteralEquality($statements_analyzer, $assertion, $assertion_type, $existing_var_type, $old_var_type_string, $key, $negated, $code_location, $suppressed_issues); } if ($assertion instanceof IsAClass) { $should_return = \false; $new_type_parts = self::handleIsA($assertion, $codebase, $existing_var_type, $code_location, $key, $suppressed_issues, $should_return); if ($should_return) { return new Union($new_type_parts); } $new_type_part = $new_type_parts[0]; } else { $simply_reconciled_type = \Psalm\Internal\Type\SimpleAssertionReconciler::reconcile($assertion, $codebase, $existing_var_type, $key, $negated, $code_location, $suppressed_issues, $failed_reconciliation, $inside_loop); if ($simply_reconciled_type) { return $simply_reconciled_type; } if ($assertion instanceof IsClassEqual) { $new_type_part = Atomic::create($assertion->type, null, $template_type_map); } elseif ($assertion_type = $assertion->getAtomicType()) { $new_type_part = $assertion_type; } else { $new_type_part = new TMixed(); } } if ($existing_var_type->hasMixed()) { if ($assertion instanceof IsLooselyEqual && $new_type_part instanceof Scalar) { return $existing_var_type; } return new Union([$new_type_part]); } $refined_type = self::refine($statements_analyzer, $assertion, $new_type_part, $existing_var_type, $key, $negated, $code_location, $suppressed_issues, $failed_reconciliation); return \Psalm\Internal\Type\TypeExpander::expandUnion($codebase, $refined_type, null, null, null, \true, \false, \false, \true); } private static function getMissingType(Assertion $assertion, bool $inside_loop) : Union { if ($assertion instanceof IsIsset || $assertion instanceof IsEqualIsset || $assertion instanceof NonEmpty) { return Type::getMixed($inside_loop); } if ($assertion instanceof ArrayKeyExists || $assertion instanceof NonEmptyCountable || $assertion instanceof HasExactCount || $assertion instanceof HasAtLeastCount) { return Type::getMixed(); } if (!$assertion->isNegation()) { $assertion_type = $assertion->getAtomicType(); if ($assertion_type) { return new Union([$assertion_type]); } } return Type::getMixed(); } /** * This method is called when SimpleAssertionReconciler was not enough. It receives the existing type, the assertion * and also a new type created from the assertion string. * * @param Reconciler::RECONCILIATION_* $failed_reconciliation * @param string[] $suppressed_issues * @param-out Reconciler::RECONCILIATION_* $failed_reconciliation */ private static function refine(StatementsAnalyzer $statements_analyzer, Assertion $assertion, Atomic $new_type_part, Union &$existing_var_type, ?string $key, bool $negated, ?CodeLocation $code_location, array $suppressed_issues, int &$failed_reconciliation) : Union { $codebase = $statements_analyzer->getCodebase(); $old_var_type_string = $existing_var_type->getId(); if ($new_type_part instanceof TMixed) { return $existing_var_type; } $new_type_has_interface = \false; if ($new_type_part->isObjectType()) { if ($new_type_part instanceof TNamedObject && $codebase->interfaceExists($new_type_part->value)) { $new_type_has_interface = \true; } } $old_type_has_interface = \false; if ($existing_var_type->hasObjectType()) { foreach ($existing_var_type->getAtomicTypes() as $existing_type_part) { if ($existing_type_part instanceof TNamedObject && $codebase->interfaceExists($existing_type_part->value)) { $old_type_has_interface = \true; break; } } } if ($new_type_part instanceof TTemplateParam && $new_type_part->as->isSingle()) { $new_as_atomic = $new_type_part->as->getSingleAtomic(); $acceptable_atomic_types = []; foreach ($existing_var_type->getAtomicTypes() as $existing_var_type_part) { if ($existing_var_type_part instanceof TNamedObject || $existing_var_type_part instanceof TTemplateParam) { $acceptable_atomic_types[] = $existing_var_type_part; } else { if (AtomicTypeComparator::isContainedBy($codebase, $existing_var_type_part, $new_as_atomic)) { $acceptable_atomic_types[] = $existing_var_type_part; } } } if ($acceptable_atomic_types) { $acceptable_atomic_types = count($acceptable_atomic_types) === count($existing_var_type->getAtomicTypes()) ? $existing_var_type : new Union($acceptable_atomic_types); return new Union([$new_type_part->replaceAs($acceptable_atomic_types)]); } } if ($new_type_part instanceof TKeyedArray) { $acceptable_atomic_types = []; foreach ($existing_var_type->getAtomicTypes() as $existing_var_type_part) { if ($existing_var_type_part instanceof TKeyedArray) { if (!array_intersect_key($existing_var_type_part->properties, $new_type_part->properties)) { $acceptable_atomic_types[] = $existing_var_type_part->setProperties(array_merge($existing_var_type_part->properties, $new_type_part->properties)); } } } if ($acceptable_atomic_types) { return new Union($acceptable_atomic_types); } } $new_type = null; if ($new_type_part instanceof TNamedObject && ($new_type_has_interface || $old_type_has_interface) && !UnionTypeComparator::canExpressionTypesBeIdentical($codebase, new Union([$new_type_part]), $existing_var_type, \false)) { $acceptable_atomic_types = []; foreach ($existing_var_type->getAtomicTypes() as $existing_var_type_part) { if (AtomicTypeComparator::isContainedBy($codebase, $existing_var_type_part, $new_type_part)) { $acceptable_atomic_types[] = $existing_var_type_part; continue; } if ($existing_var_type_part instanceof TNamedObject && ($codebase->classExists($existing_var_type_part->value) || $codebase->interfaceExists($existing_var_type_part->value))) { $existing_var_type_part = $existing_var_type_part->addIntersectionType($new_type_part); $acceptable_atomic_types[] = $existing_var_type_part; } if ($existing_var_type_part instanceof TTemplateParam) { $existing_var_type_part = $existing_var_type_part->addIntersectionType($new_type_part); $acceptable_atomic_types[] = $existing_var_type_part; } } if ($acceptable_atomic_types) { return new Union($acceptable_atomic_types); } } elseif (!$new_type_part instanceof TMixed) { $any_scalar_type_match_found = \false; if ($code_location && $key && !$assertion->hasEquality() && $new_type_part instanceof TNamedObject && !$new_type_has_interface && (!$statements_analyzer->getSource()->getSource() instanceof TraitAnalyzer || $key !== '$this') && UnionTypeComparator::isContainedBy($codebase, $existing_var_type, new Union([$new_type_part]), \false, \false, null, \false, \false)) { self::triggerIssueForImpossible($existing_var_type, $old_var_type_string, $key, $assertion, \true, $negated, $code_location, $suppressed_issues); } $intersection_type = self::filterTypeWithAnother($codebase, $existing_var_type, new Union([$new_type_part]), $any_scalar_type_match_found); if ($code_location && !$intersection_type && (!$assertion instanceof IsLooselyEqual || !$any_scalar_type_match_found)) { if ($new_type_part instanceof TNull) { if ($existing_var_type->from_docblock) { IssueBuffer::maybeAdd(new DocblockTypeContradiction('Cannot resolve types for ' . $key . ' - docblock-defined type ' . $existing_var_type . ' does not contain null', $code_location, $existing_var_type->getId() . ' null'), $suppressed_issues); } else { IssueBuffer::maybeAdd(new TypeDoesNotContainNull('Cannot resolve types for ' . $key . ' - ' . $existing_var_type . ' does not contain null', $code_location, $existing_var_type->getId()), $suppressed_issues); } } elseif (!$statements_analyzer->getSource()->getSource() instanceof TraitAnalyzer || $key !== '$this' && !($existing_var_type->hasLiteralClassString() && $assertion instanceof IsAClass)) { if ($existing_var_type->from_docblock) { IssueBuffer::maybeAdd(new DocblockTypeContradiction('Cannot resolve types for ' . $key . ' - docblock-defined type ' . $existing_var_type->getId() . ' does not contain ' . $new_type_part->getId(), $code_location, $existing_var_type->getId() . ' ' . $new_type_part->getId()), $suppressed_issues); } else { IssueBuffer::maybeAdd(new TypeDoesNotContainType('Cannot resolve types for ' . $key . ' - ' . $existing_var_type->getId() . ' does not contain ' . $new_type_part->getId(), $code_location, $existing_var_type->getId() . ' ' . $new_type_part->getId()), $suppressed_issues); } } $failed_reconciliation = Reconciler::RECONCILIATION_EMPTY; } if ($intersection_type) { $new_type = $intersection_type; } } return $new_type ?: new Union([$new_type_part]); } /** * This method receives two types. The goal is to use datas in the new type to reduce the existing_type to a more * precise version. For example: new is `array` old is `list` so the result is `list` */ private static function filterTypeWithAnother(Codebase $codebase, Union &$existing_type, Union $new_type, bool &$any_scalar_type_match_found = \false) : ?Union { $matching_atomic_types = []; $existing_types = $existing_type->getAtomicTypes(); foreach ($new_type->getAtomicTypes() as $new_type_part) { foreach ($existing_types as &$existing_type_part) { $matching_atomic_type = self::filterAtomicWithAnother($existing_type_part, $new_type_part, $codebase, $any_scalar_type_match_found); if ($matching_atomic_type) { $matching_atomic_types[] = $matching_atomic_type; } } unset($existing_type_part); } $existing_type = $existing_type->setTypes($existing_types); if ($matching_atomic_types) { return new Union($matching_atomic_types); } return null; } private static function filterAtomicWithAnother(Atomic &$type_1_atomic, Atomic $type_2_atomic, Codebase $codebase, bool &$any_scalar_type_match_found) : ?Atomic { if ($type_1_atomic instanceof TFloat && $type_2_atomic instanceof TInt) { $any_scalar_type_match_found = \true; return $type_2_atomic; } if ($type_1_atomic instanceof TNamedObject) { $type_1_atomic = $type_1_atomic->setIsStatic(\false); } $atomic_comparison_results = new TypeComparisonResult(); $atomic_contained_by = AtomicTypeComparator::isContainedBy($codebase, $type_2_atomic, $type_1_atomic, !($type_1_atomic instanceof TNamedObject && $type_2_atomic instanceof TNamedObject), \false, $atomic_comparison_results); if ($atomic_contained_by) { return self::refineContainedAtomicWithAnother($type_1_atomic, $type_2_atomic, $codebase, $atomic_comparison_results->type_coerced ?? \false); } $atomic_comparison_results = new TypeComparisonResult(); $atomic_contained_by = AtomicTypeComparator::isContainedBy($codebase, $type_1_atomic, $type_2_atomic, $type_1_atomic instanceof TClassString && $type_2_atomic instanceof TClassString, \false, $atomic_comparison_results); if ($atomic_contained_by) { return self::refineContainedAtomicWithAnother($type_2_atomic, $type_1_atomic, $codebase, $atomic_comparison_results->type_coerced ?? \false); } $matching_atomic_type = null; if ($type_1_atomic instanceof TNamedObject && $type_2_atomic instanceof TNamedObject && ($codebase->interfaceExists($type_1_atomic->value) || $codebase->interfaceExists($type_2_atomic->value))) { return $type_2_atomic->addIntersectionType($type_1_atomic); } /*if ($type_2_atomic instanceof TKeyedArray && $type_1_atomic instanceof \Psalm\Type\Atomic\TList ) { $type_2_key = $type_2_atomic->getGenericKeyType(); $type_2_value = $type_2_atomic->getGenericValueType(); if (!$type_2_key->hasString()) { $type_1_type_param = $type_1_atomic->type_param; $type_2_value = self::filterTypeWithAnother( $codebase, $type_1_type_param, $type_2_value, $any_scalar_type_match_found ); $type_1_atomic = $type_1_atomic->setTypeParam($type_1_type_param); if ($type_2_value === null) { return null; } return new TKeyedArray( $type_2_atomic->properties, null, [Type::getInt(), $type_2_value], true ); } } elseif ($type_1_atomic instanceof TKeyedArray && $type_2_atomic instanceof \Psalm\Type\Atomic\TList ) { $type_1_key = $type_1_atomic->getGenericKeyType(); $type_1_value = $type_1_atomic->getGenericValueType(); if (!$type_1_key->hasString()) { $type_2_type_param = $type_2_atomic->type_param; $type_1_value = self::filterTypeWithAnother( $codebase, $type_2_type_param, $type_1_value, $any_scalar_type_match_found ); if ($type_1_value === null) { return null; } return new TKeyedArray( $type_1_atomic->properties, null, [Type::getInt(), $type_1_value], true ); } }*/ if ($type_2_atomic instanceof TTemplateParam && $type_1_atomic instanceof TTemplateParam && $type_2_atomic->param_name !== $type_1_atomic->param_name && $type_2_atomic->as->hasObject() && $type_1_atomic->as->hasObject()) { return $type_2_atomic->addIntersectionType($type_1_atomic); } //we filter both types of standard iterables if (($type_2_atomic instanceof TGenericObject || $type_2_atomic instanceof TArray || $type_2_atomic instanceof TIterable) && ($type_1_atomic instanceof TGenericObject || $type_1_atomic instanceof TArray || $type_1_atomic instanceof TIterable) && count($type_2_atomic->type_params) === count($type_1_atomic->type_params)) { $type_1_params = $type_1_atomic->type_params; foreach ($type_2_atomic->type_params as $i => $type_2_param) { $type_1_param = $type_1_params[$i]; $type_2_param_id = $type_2_param->getId(); $type_2_param = self::filterTypeWithAnother($codebase, $type_1_param, $type_2_param, $any_scalar_type_match_found); if ($type_2_param === null) { return null; } if ($type_1_params[$i]->getId() !== $type_2_param_id) { $type_1_params[$i] = $type_2_param; } } /** @psalm-suppress InvalidArgument */ $type_1_atomic = $type_1_atomic->setTypeParams($type_1_params); $matching_atomic_type = $type_1_atomic; $atomic_comparison_results->type_coerced = \true; } //we filter the second part of a list with the second part of standard iterables /*if (($type_2_atomic instanceof TArray || $type_2_atomic instanceof TIterable) && $type_1_atomic instanceof \Psalm\Type\Atomic\TList ) { $type_2_param = $type_2_atomic->type_params[1]; $type_1_param = $type_1_atomic->type_param; $type_2_param = self::filterTypeWithAnother( $codebase, $type_1_param, $type_2_param, $any_scalar_type_match_found ); if ($type_2_param === null) { return null; } if ($type_1_param->getId() !== $type_2_param->getId()) { $type_1_atomic = $type_1_atomic->setTypeParam($type_2_param); } elseif ($type_1_param !== $type_1_atomic->type_param) { $type_1_atomic = $type_1_atomic->setTypeParam($type_1_param); } $matching_atomic_type = $type_1_atomic; $atomic_comparison_results->type_coerced = true; }*/ //we filter each property of a Keyed Array with the second part of standard iterables if (($type_2_atomic instanceof TArray || $type_2_atomic instanceof TIterable) && $type_1_atomic instanceof TKeyedArray) { $type_2_param = $type_2_atomic->type_params[1]; $type_1_properties = $type_1_atomic->properties; foreach ($type_1_properties as &$type_1_param) { $type_2_param = self::filterTypeWithAnother($codebase, $type_1_param, $type_2_param, $any_scalar_type_match_found); if ($type_2_param === null) { return null; } if ($type_1_param->getId() !== $type_2_param->getId()) { $type_1_param = $type_2_param->setPossiblyUndefined($type_1_param->possibly_undefined); } } unset($type_1_param); if ($type_1_atomic->fallback_params === null) { $fallback_types = null; } else { //any fallback type is now the value of iterable $fallback_types = [$type_1_atomic->fallback_params[0], $type_2_param]; } $matching_atomic_type = new TKeyedArray($type_1_properties, $type_1_atomic->class_strings, $fallback_types, $type_1_atomic->is_list, $type_1_atomic->from_docblock); $atomic_comparison_results->type_coerced = \true; } //These partial match wouldn't have been handled by AtomicTypeComparator $new_range = null; if ($type_2_atomic instanceof TIntRange && $type_1_atomic instanceof TIntRange) { $new_range = TIntRange::intersectIntRanges($type_1_atomic, $type_2_atomic); } if ($new_range !== null) { $matching_atomic_type = $new_range; } // Lowercase-string and non-empty-string are compatible but none is contained into the other completely if ($type_2_atomic instanceof TLowercaseString && $type_1_atomic instanceof TNonEmptyString || $type_2_atomic instanceof TNonEmptyString && $type_1_atomic instanceof TLowercaseString) { $matching_atomic_type = new TNonEmptyLowercaseString(); } if (!$atomic_comparison_results->type_coerced && $atomic_comparison_results->scalar_type_match_found) { $any_scalar_type_match_found = \true; } return $matching_atomic_type; } private static function refineContainedAtomicWithAnother(Atomic $type_1_atomic, Atomic $type_2_atomic, Codebase $codebase, bool $type_coerced) : ?Atomic { if ($type_coerced && get_class($type_2_atomic) === TNamedObject::class && $type_1_atomic instanceof TGenericObject) { // this is a hack - it's not actually rigorous, as the params may be different return new TGenericObject($type_2_atomic->value, $type_1_atomic->type_params); } elseif ($type_2_atomic instanceof TNamedObject && $type_1_atomic instanceof TTemplateParam && $type_1_atomic->as->hasObjectType()) { $type_1_as_init = $type_1_atomic->as; $type_1_as = self::filterTypeWithAnother($codebase, $type_1_as_init, new Union([$type_2_atomic])); if ($type_1_as === null) { return null; } return $type_1_atomic->replaceAs($type_1_as); } else { return $type_2_atomic; } } /** * @param TLiteralInt|TLiteralFloat|TLiteralString|TEnumCase $assertion_type * @param string[] $suppressed_issues */ private static function handleLiteralEquality(StatementsAnalyzer $statements_analyzer, Assertion $assertion, Atomic $assertion_type, Union $existing_var_type, string $old_var_type_string, ?string $var_id, bool $negated, ?CodeLocation $code_location, array $suppressed_issues) : Union { $existing_var_atomic_types = []; foreach ($existing_var_type->getAtomicTypes() as $existing_var_atomic_type) { if ($existing_var_atomic_type instanceof TClassConstant) { $expanded = \Psalm\Internal\Type\TypeExpander::expandAtomic($statements_analyzer->getCodebase(), $existing_var_atomic_type, $existing_var_atomic_type->fq_classlike_name, $existing_var_atomic_type->fq_classlike_name, null, \true, \true); foreach ($expanded as $atomic_type) { $existing_var_atomic_types[$atomic_type->getKey()] = $atomic_type; } } else { $existing_var_atomic_types[$existing_var_atomic_type->getKey()] = $existing_var_atomic_type; } } if ($assertion_type instanceof TLiteralInt) { return self::handleLiteralEqualityWithInt($statements_analyzer, $assertion, $assertion_type, $existing_var_type, $existing_var_atomic_types, $old_var_type_string, $var_id, $negated, $code_location, $suppressed_issues); } elseif ($assertion_type instanceof TLiteralString) { return self::handleLiteralEqualityWithString($statements_analyzer, $assertion, $assertion_type, $existing_var_type, $existing_var_atomic_types, $old_var_type_string, $var_id, $negated, $code_location, $suppressed_issues); } elseif ($assertion_type instanceof TLiteralFloat) { return self::handleLiteralEqualityWithFloat($statements_analyzer, $assertion, $assertion_type, $existing_var_type, $existing_var_atomic_types, $old_var_type_string, $var_id, $negated, $code_location, $suppressed_issues); } else { $fq_enum_name = $assertion_type->value; $case_name = $assertion_type->case_name; if ($existing_var_type->hasMixed()) { if ($assertion instanceof IsLooselyEqual) { return $existing_var_type; } return new Union([new TEnumCase($fq_enum_name, $case_name)]); } $can_be_equal = \false; $redundant = \true; $existing_var_type = $existing_var_type->getBuilder(); foreach ($existing_var_atomic_types as $atomic_key => $atomic_type) { if (get_class($atomic_type) === TNamedObject::class && $atomic_type->value === $fq_enum_name) { $can_be_equal = \true; $redundant = \false; $existing_var_type->removeType($atomic_key); $existing_var_type->addType(new TEnumCase($fq_enum_name, $case_name)); } elseif (AtomicTypeComparator::canBeIdentical($statements_analyzer->getCodebase(), $atomic_type, $assertion_type)) { $can_be_equal = \true; $redundant = $atomic_key === $assertion_type->getKey(); $existing_var_type->removeType($atomic_key); $existing_var_type->addType(new TEnumCase($fq_enum_name, $case_name)); } elseif ($atomic_key !== $assertion_type->getKey()) { $existing_var_type->removeType($atomic_key); $redundant = \false; } else { $can_be_equal = \true; } } $existing_var_type = $existing_var_type->freeze(); if ($var_id && $code_location && (!$can_be_equal || $redundant && count($existing_var_atomic_types) === 1)) { self::triggerIssueForImpossible($existing_var_type, $old_var_type_string, $var_id, $assertion, $can_be_equal, $negated, $code_location, $suppressed_issues); } } return $existing_var_type; } /** * @param array $existing_var_atomic_types * @param string[] $suppressed_issues */ private static function handleLiteralEqualityWithInt(StatementsAnalyzer $statements_analyzer, Assertion $assertion, TLiteralInt $assertion_type, Union $existing_var_type, array $existing_var_atomic_types, string $old_var_type_string, ?string $var_id, bool $negated, ?CodeLocation $code_location, array $suppressed_issues) : Union { $value = $assertion_type->value; // we create the literal that is being asserted. We'll return this when we're sure this is the resulting type $literal_asserted_type = new Union([new TLiteralInt($value)], ['from_docblock' => $existing_var_type->from_docblock]); $compatible_int_type = self::getCompatibleIntType($existing_var_type, $existing_var_atomic_types, $assertion_type, $assertion instanceof IsLooselyEqual); if ($compatible_int_type !== null) { return $compatible_int_type; } foreach ($existing_var_atomic_types as $existing_var_atomic_type) { if ($existing_var_atomic_type instanceof TIntRange && $existing_var_atomic_type->contains($value)) { return $literal_asserted_type; } if ($existing_var_atomic_type instanceof TLiteralInt && $existing_var_atomic_type->value === $value) { //if we're here, we check that we had at least another type in the union, otherwise it's redundant if ($existing_var_type->isSingleIntLiteral()) { if ($var_id && $code_location) { self::triggerIssueForImpossible($existing_var_type, $old_var_type_string, $var_id, $assertion, \true, $negated, $code_location, $suppressed_issues); } return $existing_var_type; } return $literal_asserted_type; } if ($existing_var_atomic_type instanceof TInt && !$existing_var_atomic_type instanceof TLiteralInt) { return $literal_asserted_type; } if ($existing_var_atomic_type instanceof TTemplateParam) { $compatible_int_type = self::getCompatibleIntType($existing_var_type, $existing_var_atomic_type->as->getAtomicTypes(), $assertion_type, $assertion instanceof IsLooselyEqual); if ($compatible_int_type !== null) { return $compatible_int_type; } $existing_var_atomic_type = $existing_var_atomic_type->replaceAs(self::handleLiteralEquality($statements_analyzer, $assertion, $assertion_type, $existing_var_atomic_type->as, $old_var_type_string, $var_id, $negated, $code_location, $suppressed_issues)); return new Union([$existing_var_atomic_type]); } if ($assertion instanceof IsLooselyEqual && $existing_var_atomic_type instanceof TLiteralFloat && (int) $existing_var_atomic_type->value === $value) { return new Union([$existing_var_atomic_type]); } if ($assertion instanceof IsLooselyEqual && $existing_var_atomic_type instanceof TLiteralString && (int) $existing_var_atomic_type->value === $value) { return new Union([$existing_var_atomic_type]); } } //here we'll accept non-literal type that *could* match on loose equality and return the original type foreach ($existing_var_atomic_types as $existing_var_atomic_type) { //here we'll accept non-literal type that *could* match on loose equality and return the original type if ($assertion instanceof IsLooselyEqual) { if ($existing_var_atomic_type instanceof TString && !$existing_var_atomic_type instanceof TLiteralString) { return $existing_var_type; } if ($existing_var_atomic_type instanceof TFloat && !$existing_var_atomic_type instanceof TLiteralFloat) { return $existing_var_type; } } } //if we're here, no type was eligible for the given literal. We'll emit an impossible error for this assertion if ($var_id && $code_location) { self::triggerIssueForImpossible($existing_var_type, $old_var_type_string, $var_id, $assertion, \false, $negated, $code_location, $suppressed_issues); } return Type::getNever(); } /** * @param array $existing_var_atomic_types * @param string[] $suppressed_issues */ private static function handleLiteralEqualityWithString(StatementsAnalyzer $statements_analyzer, Assertion $assertion, TLiteralString $assertion_type, Union $existing_var_type, array $existing_var_atomic_types, string $old_var_type_string, ?string $var_id, bool $negated, ?CodeLocation $code_location, array $suppressed_issues) : Union { $value = $assertion_type->value; // we create the literal that is being asserted. We'll return this when we're sure this is the resulting type $literal_asserted_type_string = new Union([$assertion_type], ['from_docblock' => $existing_var_type->from_docblock]); $compatible_string_type = self::getCompatibleStringType($existing_var_type, $existing_var_atomic_types, $assertion_type, $assertion instanceof IsLooselyEqual); if ($compatible_string_type !== null) { return $compatible_string_type; } foreach ($existing_var_atomic_types as $existing_var_atomic_type) { if ($existing_var_atomic_type instanceof TLiteralString && $existing_var_atomic_type->value === $value) { //if we're here, we check that we had at least another type in the union, otherwise it's redundant if ($existing_var_type->isSingleStringLiteral()) { if ($var_id && $code_location) { self::triggerIssueForImpossible($existing_var_type, $old_var_type_string, $var_id, $assertion, \true, $negated, $code_location, $suppressed_issues); } return $existing_var_type; } return $literal_asserted_type_string; } if ($existing_var_atomic_type instanceof TString && !$existing_var_atomic_type instanceof TLiteralString) { return $literal_asserted_type_string; } if ($existing_var_atomic_type instanceof TTemplateParam) { $compatible_string_type = self::getCompatibleStringType($existing_var_type, $existing_var_atomic_type->as->getAtomicTypes(), $assertion_type, $assertion instanceof IsLooselyEqual); if ($compatible_string_type !== null) { return $compatible_string_type; } if ($existing_var_atomic_type->as->hasString()) { return $literal_asserted_type_string; } $existing_var_atomic_type = $existing_var_atomic_type->replaceAs(self::handleLiteralEquality($statements_analyzer, $assertion, $assertion_type, $existing_var_atomic_type->as, $old_var_type_string, $var_id, $negated, $code_location, $suppressed_issues)); return new Union([$existing_var_atomic_type]); } if ($assertion instanceof IsLooselyEqual && $existing_var_atomic_type instanceof TLiteralInt && (string) $existing_var_atomic_type->value === $value) { return new Union([$existing_var_atomic_type]); } if ($assertion instanceof IsLooselyEqual && $existing_var_atomic_type instanceof TLiteralFloat && (string) $existing_var_atomic_type->value === $value) { return new Union([$existing_var_atomic_type]); } } //here we'll accept non-literal type that *could* match on loose equality and return the original type foreach ($existing_var_atomic_types as $existing_var_atomic_type) { //here we'll accept non-literal type that *could* match on loose equality and return the original type if ($assertion instanceof IsLooselyEqual) { if ($existing_var_atomic_type instanceof TInt && !$existing_var_atomic_type instanceof TLiteralInt) { return $existing_var_type; } if ($existing_var_atomic_type instanceof TFloat && !$existing_var_atomic_type instanceof TLiteralFloat) { return $existing_var_type; } } } //if we're here, no type was eligible for the given literal. We'll emit an impossible error for this assertion if ($var_id && $code_location) { self::triggerIssueForImpossible($existing_var_type, $old_var_type_string, $var_id, $assertion, \false, $negated, $code_location, $suppressed_issues); } return Type::getNever(); } /** * @param array $existing_var_atomic_types * @param string[] $suppressed_issues */ private static function handleLiteralEqualityWithFloat(StatementsAnalyzer $statements_analyzer, Assertion $assertion, TLiteralFloat $assertion_type, Union $existing_var_type, array $existing_var_atomic_types, string $old_var_type_string, ?string $var_id, bool $negated, ?CodeLocation $code_location, array $suppressed_issues) : Union { $value = $assertion_type->value; // we create the literal that is being asserted. We'll return this when we're sure this is the resulting type $literal_asserted_type = new Union([new TLiteralFloat($value)], ['from_docblock' => $existing_var_type->from_docblock]); $compatible_float_type = self::getCompatibleFloatType($existing_var_type, $existing_var_atomic_types, $assertion_type, $assertion instanceof IsLooselyEqual); if ($compatible_float_type !== null) { return $compatible_float_type; } foreach ($existing_var_atomic_types as $existing_var_atomic_type) { if ($existing_var_atomic_type instanceof TLiteralFloat && $existing_var_atomic_type->value === $value) { //if we're here, we check that we had at least another type in the union, otherwise it's redundant if ($existing_var_type->isSingleFloatLiteral()) { if ($var_id && $code_location) { self::triggerIssueForImpossible($existing_var_type, $old_var_type_string, $var_id, $assertion, \true, $negated, $code_location, $suppressed_issues); } return $existing_var_type; } return $literal_asserted_type; } if ($existing_var_atomic_type instanceof TFloat && !$existing_var_atomic_type instanceof TLiteralFloat) { return $literal_asserted_type; } if ($existing_var_atomic_type instanceof TTemplateParam) { $compatible_float_type = self::getCompatibleFloatType($existing_var_type, $existing_var_atomic_type->as->getAtomicTypes(), $assertion_type, $assertion instanceof IsLooselyEqual); if ($compatible_float_type !== null) { return $compatible_float_type; } if ($existing_var_atomic_type->as->hasFloat()) { return $literal_asserted_type; } $existing_var_atomic_type = $existing_var_atomic_type->replaceAs(self::handleLiteralEquality($statements_analyzer, $assertion, $assertion_type, $existing_var_atomic_type->as, $old_var_type_string, $var_id, $negated, $code_location, $suppressed_issues)); return new Union([$existing_var_atomic_type]); } if ($assertion instanceof IsLooselyEqual && $existing_var_atomic_type instanceof TLiteralInt && (float) $existing_var_atomic_type->value === $value) { return new Union([$existing_var_atomic_type]); } if ($assertion instanceof IsLooselyEqual && $existing_var_atomic_type instanceof TLiteralString && (float) $existing_var_atomic_type->value === $value) { return new Union([$existing_var_atomic_type]); } } //here we'll accept non-literal type that *could* match on loose equality and return the original type foreach ($existing_var_atomic_types as $existing_var_atomic_type) { if ($assertion instanceof IsLooselyEqual) { if ($existing_var_atomic_type instanceof TInt && !$existing_var_atomic_type instanceof TLiteralInt) { return $existing_var_type; } if ($existing_var_atomic_type instanceof TString && !$existing_var_atomic_type instanceof TLiteralString) { return $existing_var_type; } } } //if we're here, no type was eligible for the given literal. We'll emit an impossible error for this assertion if ($var_id && $code_location) { self::triggerIssueForImpossible($existing_var_type, $old_var_type_string, $var_id, $assertion, \false, $negated, $code_location, $suppressed_issues); } return Type::getNever(); } /** * @param array $existing_var_atomic_types */ private static function getCompatibleIntType(Union $existing_var_type, array $existing_var_atomic_types, TLiteralInt $assertion_type, bool $is_loose_equality) : ?Union { foreach ($existing_var_atomic_types as $existing_var_atomic_type) { if ($existing_var_atomic_type instanceof TMixed || $existing_var_atomic_type instanceof TScalar || $existing_var_atomic_type instanceof TNumeric || $existing_var_atomic_type instanceof TArrayKey) { if ($is_loose_equality) { return $existing_var_type; } return new Union([$assertion_type], ['from_docblock' => $existing_var_type->from_docblock]); } } return null; } /** * @param array $existing_var_atomic_types */ private static function getCompatibleStringType(Union $existing_var_type, array $existing_var_atomic_types, TLiteralString $assertion_type, bool $is_loose_equality) : ?Union { foreach ($existing_var_atomic_types as $existing_var_atomic_type) { if ($existing_var_atomic_type instanceof TMixed || $existing_var_atomic_type instanceof TScalar || $existing_var_atomic_type instanceof TArrayKey) { if ($is_loose_equality) { return $existing_var_type; } return new Union([$assertion_type], ['from_docblock' => $existing_var_type->from_docblock]); } } return null; } /** * @param array $existing_var_atomic_types */ private static function getCompatibleFloatType(Union $existing_var_type, array $existing_var_atomic_types, TLiteralFloat $assertion_type, bool $is_loose_equality) : ?Union { foreach ($existing_var_atomic_types as $existing_var_atomic_type) { if ($existing_var_atomic_type instanceof TMixed || $existing_var_atomic_type instanceof TScalar || $existing_var_atomic_type instanceof TNumeric) { if ($is_loose_equality) { return $existing_var_type; } return new Union([$assertion_type], ['from_docblock' => $existing_var_type->from_docblock]); } } return null; } /** * @param array $suppressed_issues * @return non-empty-list */ private static function handleIsA(IsAClass $assertion, Codebase $codebase, Union $existing_var_type, ?CodeLocation $code_location, ?string $key, array $suppressed_issues, bool &$should_return) : array { $allow_string_comparison = $assertion->allow_string; $assertion_type = $assertion->type; if ($existing_var_type->hasMixed()) { if (!$assertion_type instanceof TNamedObject) { return [$assertion_type]; } $types = [$assertion_type]; if ($allow_string_comparison) { $types[] = new TClassString($assertion_type->value, $assertion_type); } $should_return = \true; return $types; } $existing_has_object = $existing_var_type->hasObjectType(); $existing_has_string = $existing_var_type->hasString(); if ($existing_has_object && !$existing_has_string) { if ($assertion_type instanceof TTemplateParamClass) { return [new TTemplateParam($assertion_type->param_name, new Union([$assertion_type->as_type ? $assertion_type->as_type : new TObject()]), $assertion_type->defining_class)]; } return [$assertion_type]; } if ($existing_has_string && !$existing_has_object) { if (!$allow_string_comparison && $code_location) { IssueBuffer::maybeAdd(new TypeDoesNotContainType('Cannot allow string comparison to object for ' . $key, $code_location, "no string comparison to {$key}"), $suppressed_issues); return [new TMixed()]; } else { if (!$assertion_type instanceof TNamedObject) { return [$assertion_type]; } $new_type_has_interface_string = $codebase->interfaceExists($assertion_type->value); $old_type_has_interface_string = \false; foreach ($existing_var_type->getAtomicTypes() as $existing_type_part) { if ($existing_type_part instanceof TClassString && $existing_type_part->as_type && $codebase->interfaceExists($existing_type_part->as_type->value)) { $old_type_has_interface_string = \true; break; } } $new_type = Type::getClassString($assertion_type->value); if ($new_type_has_interface_string && !UnionTypeComparator::isContainedBy($codebase, $existing_var_type, $new_type) || $old_type_has_interface_string && !UnionTypeComparator::isContainedBy($codebase, $new_type, $existing_var_type)) { $new_type_part = $assertion_type; $acceptable_atomic_types = []; foreach ($existing_var_type->getAtomicTypes() as $existing_var_type_part) { if (!$existing_var_type_part instanceof TClassString) { $acceptable_atomic_types = []; break; } if (!$existing_var_type_part->as_type instanceof TNamedObject) { $acceptable_atomic_types = []; break; } $existing_var_type_part = $existing_var_type_part->as_type; if (AtomicTypeComparator::isContainedBy($codebase, $existing_var_type_part, $new_type_part)) { $acceptable_atomic_types[] = $existing_var_type_part; continue; } if ($codebase->classExists($existing_var_type_part->value) || $codebase->interfaceExists($existing_var_type_part->value)) { $existing_var_type_part = $existing_var_type_part->addIntersectionType($new_type_part); $acceptable_atomic_types[] = $existing_var_type_part; } } if (count($acceptable_atomic_types) === 1) { $should_return = \true; return [new TClassString('object', $acceptable_atomic_types[0])]; } } } return [$new_type->getSingleAtomic()]; } else { return [new TMixed()]; } } } getId(); if ($assertion instanceof IsNotIsset) { if ($existing_var_type->possibly_undefined) { return Type::getNever(); } if (!$existing_var_type->isNullable() && $key && strpos($key, '[') === \false && (!$existing_var_type->hasMixed() || $existing_var_type->isAlwaysTruthy())) { if ($code_location) { if ($existing_var_type->from_static_property) { IssueBuffer::maybeAdd(new RedundantPropertyInitializationCheck('Static property ' . $key . ' with type ' . $existing_var_type . ' has unexpected isset check — should it be nullable?', $code_location), $suppressed_issues); } elseif ($existing_var_type->from_property) { IssueBuffer::maybeAdd(new RedundantPropertyInitializationCheck('Property ' . $key . ' with type ' . $existing_var_type . ' should already be set in the constructor', $code_location), $suppressed_issues); } elseif ($existing_var_type->from_docblock) { IssueBuffer::maybeAdd(new DocblockTypeContradiction('Cannot resolve types for ' . $key . ' with docblock-defined type ' . $existing_var_type . ' and !isset assertion', $code_location, 'cannot resolve !isset ' . $existing_var_type . ' ' . $key), $suppressed_issues); } else { IssueBuffer::maybeAdd(new TypeDoesNotContainType('Cannot resolve types for ' . $key . ' with type ' . $existing_var_type . ' and !isset assertion', $code_location, 'cannot resolve !isset ' . $existing_var_type . ' ' . $key), $suppressed_issues); } } return Type::getNever(); } return Type::getNull(); } if ($assertion instanceof ArrayKeyDoesNotExist) { return Type::getNever(); } if ($assertion instanceof NotInArray) { $new_var_type = $assertion->type; $intersection = Type::intersectUnionTypes($new_var_type, $existing_var_type, $codebase); if ($intersection === null) { if ($key && $code_location) { self::triggerIssueForImpossible($existing_var_type, $existing_var_type->getId(), $key, $assertion, \true, $negated, $code_location, $suppressed_issues); } $failed_reconciliation = Reconciler::RECONCILIATION_EMPTY; } return $existing_var_type; } if ($assertion instanceof Falsy || $assertion instanceof Empty_) { return self::reconcileFalsyOrEmpty($assertion, $existing_var_type, $key, $negated, $code_location, $suppressed_issues, $failed_reconciliation, \false); } if ($assertion instanceof NotNonEmptyCountable) { return self::reconcileNotNonEmptyCountable($assertion, $existing_var_type, $key, $negated, $code_location, $suppressed_issues, $is_equality, null); } if ($assertion instanceof DoesNotHaveAtLeastCount) { return self::reconcileNotNonEmptyCountable($assertion, $existing_var_type, $key, $negated, $code_location, $suppressed_issues, $is_equality, $assertion->count); } if ($assertion instanceof DoesNotHaveExactCount) { return $existing_var_type; } if ($assertion instanceof IsLessThanOrEqualTo) { return self::reconcileIsLessThanOrEqualTo($assertion, $existing_var_type, $inside_loop, $old_var_type_string, $key, $negated, $code_location, $suppressed_issues); } if ($assertion instanceof IsGreaterThanOrEqualTo) { return self::reconcileIsGreaterThanOrEqualTo($assertion, $existing_var_type, $inside_loop, $old_var_type_string, $key, $negated, $code_location, $suppressed_issues); } $assertion_type = $assertion->getAtomicType(); if ($assertion_type instanceof TObject && !$existing_var_type->hasMixed()) { return self::reconcileObject($assertion, $existing_var_type, $key, $negated, $code_location, $suppressed_issues, $failed_reconciliation, $is_equality); } if ($assertion_type instanceof TScalar && !$existing_var_type->hasMixed()) { return self::reconcileScalar($assertion, $existing_var_type, $key, $negated, $code_location, $suppressed_issues, $failed_reconciliation, $is_equality); } if ($assertion_type instanceof TResource && !$existing_var_type->hasMixed()) { return self::reconcileResource($assertion, $existing_var_type, $key, $negated, $code_location, $suppressed_issues, $failed_reconciliation, $is_equality); } if ($assertion_type && get_class($assertion_type) === TBool::class && !$existing_var_type->hasMixed()) { return self::reconcileBool($assertion, $existing_var_type, $key, $negated, $code_location, $suppressed_issues, $failed_reconciliation, $is_equality); } if ($assertion_type instanceof TNumeric && !$existing_var_type->hasMixed()) { return self::reconcileNumeric($assertion, $existing_var_type, $key, $negated, $code_location, $suppressed_issues, $failed_reconciliation, $is_equality); } if ($assertion_type instanceof TFloat && !$existing_var_type->hasMixed()) { return self::reconcileFloat($assertion, $existing_var_type, $key, $negated, $code_location, $suppressed_issues, $failed_reconciliation, $is_equality); } if ($assertion_type && get_class($assertion_type) === TInt::class && !$existing_var_type->hasMixed()) { return self::reconcileInt($assertion, $existing_var_type, $key, $negated, $code_location, $suppressed_issues, $failed_reconciliation, $is_equality); } if ($assertion_type && get_class($assertion_type) === TString::class && !$existing_var_type->hasMixed()) { return self::reconcileString($assertion, $existing_var_type, $key, $negated, $code_location, $suppressed_issues, $failed_reconciliation, $is_equality); } if ($assertion_type instanceof TArray && !$existing_var_type->hasMixed() && $assertion_type->type_params[0]->isArrayKey() && $assertion_type->type_params[1]->isMixed()) { return self::reconcileArray($assertion, $existing_var_type, $key, $negated, $code_location, $suppressed_issues, $failed_reconciliation, $is_equality); } if ($assertion_type instanceof TNull && !$existing_var_type->hasMixed()) { return self::reconcileNull($assertion, $existing_var_type, $key, $negated, $code_location, $suppressed_issues, $failed_reconciliation, $is_equality); } if ($assertion_type instanceof TFalse && !$existing_var_type->hasMixed()) { return self::reconcileFalse($assertion, $existing_var_type, $key, $negated, $code_location, $suppressed_issues, $failed_reconciliation, $is_equality); } if ($assertion_type instanceof TTrue && !$existing_var_type->hasMixed()) { return self::reconcileTrue($assertion, $existing_var_type, $key, $negated, $code_location, $suppressed_issues, $failed_reconciliation, $is_equality); } if ($assertion_type instanceof TCallable) { return self::reconcileCallable($existing_var_type, $codebase, $assertion_type); } return null; } private static function reconcileCallable(Union $existing_var_type, Codebase $codebase, TCallable $assertion_type) : Union { $existing_var_type = $existing_var_type->getBuilder(); foreach ($existing_var_type->getAtomicTypes() as $atomic_key => $type) { if ($type instanceof TLiteralString && InternalCallMapHandler::inCallMap($type->value)) { $existing_var_type->removeType($atomic_key); continue; } if ($type->isCallableType()) { $existing_var_type->removeType($atomic_key); continue; } $candidate_callable = CallableTypeComparator::getCallableFromAtomic($codebase, $type, $assertion_type); if ($candidate_callable) { $existing_var_type->removeType($atomic_key); } } return $existing_var_type->freeze(); } /** * @param string[] $suppressed_issues * @param Reconciler::RECONCILIATION_* $failed_reconciliation */ private static function reconcileBool(Assertion $assertion, Union $existing_var_type, ?string $key, bool $negated, ?CodeLocation $code_location, array $suppressed_issues, int &$failed_reconciliation, bool $is_equality) : Union { $old_var_type_string = $existing_var_type->getId(); $non_bool_types = []; $redundant = \true; foreach ($existing_var_type->getAtomicTypes() as $type) { if ($type instanceof TTemplateParam) { if (!$is_equality && !$type->as->isMixed()) { $template_did_fail = 0; $type = $type->replaceAs(self::reconcileBool($assertion, $type->as, null, \false, null, $suppressed_issues, $template_did_fail, $is_equality)); $redundant = \false; if (!$template_did_fail) { $non_bool_types[] = $type; } } else { $redundant = \false; $non_bool_types[] = $type; } } elseif (!$type instanceof TBool || $is_equality && get_class($type) === TBool::class) { if ($type instanceof TScalar) { $redundant = \false; $non_bool_types[] = new TString(); $non_bool_types[] = new TInt(); $non_bool_types[] = new TFloat(); } else { $non_bool_types[] = $type; } } else { $redundant = \false; } } if ($redundant || !$non_bool_types) { if ($key && $code_location && !$is_equality) { self::triggerIssueForImpossible($existing_var_type, $old_var_type_string, $key, $assertion, $redundant, $negated, $code_location, $suppressed_issues); } if ($redundant) { $failed_reconciliation = Reconciler::RECONCILIATION_REDUNDANT; } } if ($non_bool_types) { return new Union($non_bool_types); } $failed_reconciliation = Reconciler::RECONCILIATION_EMPTY; return Type::getNever(); } /** * @param string[] $suppressed_issues */ private static function reconcileNotNonEmptyCountable(Assertion $assertion, Union $existing_var_type, ?string $key, bool $negated, ?CodeLocation $code_location, array $suppressed_issues, bool $is_equality, ?int $count) : Union { $existing_var_type = $existing_var_type->getBuilder(); $old_var_type_string = $existing_var_type->getId(); $existing_var_atomic_types = $existing_var_type->getAtomicTypes(); if (isset($existing_var_atomic_types['array'])) { $array_atomic_type = $existing_var_type->getArray(); $redundant = \true; if ($array_atomic_type instanceof TKeyedArray) { if ($count !== null) { $prop_max_count = $array_atomic_type->getMaxCount(); $prop_min_count = $array_atomic_type->getMinCount(); // !(count($a) >= 3) // count($a) < 3 // We're asserting that count($a) < $count // If it's impossible, remove the type // If it's possible but redundant, mark as redundant // If it's possible, mark as not redundant // Impossible because count($a) >= $count always if ($prop_min_count >= $count) { $redundant = \false; $existing_var_type->removeType('array'); // Redundant because count($a) < $count always } elseif ($prop_max_count && $prop_max_count < $count) { $redundant = \true; // Possible } else { if ($array_atomic_type->is_list && $array_atomic_type->fallback_params) { $properties = []; for ($x = 0; $x < $count - 1; $x++) { $properties[] = $array_atomic_type->properties[$x] ?? $array_atomic_type->fallback_params[1]->setPossiblyUndefined(\true); } $existing_var_type->removeType('array'); if (!$properties) { $existing_var_type->addType(Type::getEmptyArrayAtomic()); } else { $existing_var_type->addType(new TKeyedArray($properties, null, null, \true, $array_atomic_type->from_docblock)); } } $redundant = \false; } } else { if ($array_atomic_type->isNonEmpty()) { // Impossible, never empty $redundant = \false; $existing_var_type->removeType('array'); } else { // Possible, can be empty $redundant = \false; $existing_var_type->removeType('array'); $existing_var_type->addType(new TArray([new Union([new TNever()]), new Union([new TNever()])])); } } } elseif (!$array_atomic_type instanceof TArray || !$array_atomic_type->isEmptyArray()) { $redundant = \false; if (!$count) { $existing_var_type->addType(new TArray([new Union([new TNever()]), new Union([new TNever()])])); } } if (!$is_equality && !$existing_var_type->hasMixed() && ($redundant || $existing_var_type->isUnionEmpty())) { if ($key && $code_location) { self::triggerIssueForImpossible($existing_var_type, $old_var_type_string, $key, $assertion, $redundant, $negated, $code_location, $suppressed_issues); } } } return $existing_var_type->freeze(); } /** * @param string[] $suppressed_issues * @param Reconciler::RECONCILIATION_* $failed_reconciliation */ private static function reconcileNull(Assertion $assertion, Union $existing_var_type, ?string $key, bool $negated, ?CodeLocation $code_location, array $suppressed_issues, int &$failed_reconciliation, bool $is_equality) : Union { $types = $existing_var_type->getAtomicTypes(); $old_var_type_string = $existing_var_type->getId(); $redundant = \true; if (isset($types['null'])) { $redundant = \false; unset($types['null']); } foreach ($types as &$type) { if ($type instanceof TTemplateParam) { $new = $type->replaceAs(self::reconcileNull($assertion, $type->as, null, \false, null, $suppressed_issues, $failed_reconciliation, $is_equality)); //if ($new !== $type) { // $redundant = false; //} // TODO: This is technically wrong, but for some reason we get a // duplicated assertion here when using template types. $redundant = \false; $type = $new; } } unset($type); if ($redundant || !$types) { if ($key && $code_location && !$is_equality) { self::triggerIssueForImpossible($existing_var_type, $old_var_type_string, $key, $assertion, $redundant, $negated, $code_location, $suppressed_issues); } if ($redundant) { $failed_reconciliation = Reconciler::RECONCILIATION_REDUNDANT; } } if ($types) { return $existing_var_type->setTypes($types); } $failed_reconciliation = Reconciler::RECONCILIATION_EMPTY; return Type::getNever(); } /** * @param string[] $suppressed_issues * @param Reconciler::RECONCILIATION_* $failed_reconciliation */ private static function reconcileFalse(Assertion $assertion, Union $existing_var_type, ?string $key, bool $negated, ?CodeLocation $code_location, array $suppressed_issues, int &$failed_reconciliation, bool $is_equality) : Union { $types = $existing_var_type->getAtomicTypes(); $old_var_type_string = $existing_var_type->getId(); $redundant = \true; if (isset($types['scalar'])) { $redundant = \false; } if (isset($types['bool'])) { $redundant = \false; $types[] = new TTrue(); unset($types['bool']); } if (isset($types['false'])) { $redundant = \false; unset($types['false']); } foreach ($types as &$type) { if ($type instanceof TTemplateParam) { $new = $type->replaceAs(self::reconcileFalse($assertion, $type->as, null, \false, null, $suppressed_issues, $failed_reconciliation, $is_equality)); if ($new !== $type) { $redundant = \false; } $type = $new; } } unset($type); if ($redundant || !$types) { if ($key && $code_location && !$is_equality) { self::triggerIssueForImpossible($existing_var_type, $old_var_type_string, $key, $assertion, $redundant, $negated, $code_location, $suppressed_issues); } if ($redundant) { $failed_reconciliation = Reconciler::RECONCILIATION_REDUNDANT; } } if ($types) { return $existing_var_type->setTypes($types); } $failed_reconciliation = Reconciler::RECONCILIATION_EMPTY; return Type::getNever(); } /** * @param string[] $suppressed_issues * @param Reconciler::RECONCILIATION_* $failed_reconciliation */ private static function reconcileTrue(Assertion $assertion, Union $existing_var_type, ?string $key, bool $negated, ?CodeLocation $code_location, array $suppressed_issues, int &$failed_reconciliation, bool $is_equality) : Union { $types = $existing_var_type->getAtomicTypes(); $old_var_type_string = $existing_var_type->getId(); $redundant = \true; if (isset($types['scalar'])) { $redundant = \false; } if (isset($types['bool'])) { $redundant = \false; $types[] = new TFalse(); unset($types['bool']); } if (isset($types['true'])) { $redundant = \false; unset($types['true']); } foreach ($types as &$type) { if ($type instanceof TTemplateParam) { $new = $type->replaceAs(self::reconcileTrue($assertion, $type->as, null, \false, null, $suppressed_issues, $failed_reconciliation, $is_equality)); if ($new !== $type) { $redundant = \false; } $type = $new; } } unset($type); if ($redundant || !$types) { if ($key && $code_location && !$is_equality) { self::triggerIssueForImpossible($existing_var_type, $old_var_type_string, $key, $assertion, $redundant, $negated, $code_location, $suppressed_issues); } if ($redundant) { $failed_reconciliation = Reconciler::RECONCILIATION_REDUNDANT; } } if ($types) { return $existing_var_type->setTypes($types); } $failed_reconciliation = Reconciler::RECONCILIATION_EMPTY; return Type::getNever(); } /** * @param Falsy|Empty_ $assertion * @param string[] $suppressed_issues * @param Reconciler::RECONCILIATION_* $failed_reconciliation */ private static function reconcileFalsyOrEmpty(Assertion $assertion, Union $existing_var_type, ?string $key, bool $negated, ?CodeLocation $code_location, array $suppressed_issues, int &$failed_reconciliation, bool $recursive_check) : Union { $existing_var_type = $existing_var_type->getBuilder(); $old_var_type_string = $existing_var_type->getId(); $redundant = !($existing_var_type->possibly_undefined || $existing_var_type->possibly_undefined_from_try); foreach ($existing_var_type->getAtomicTypes() as $existing_var_type_key => $existing_var_type_part) { //if any atomic in the union is either always truthy, we remove it. If not always falsy, we mark the check //as not redundant. if (!$existing_var_type->possibly_undefined && !$existing_var_type->possibly_undefined_from_try && $existing_var_type_part->isTruthy()) { $redundant = \false; $existing_var_type->removeType($existing_var_type_key); } elseif (!$existing_var_type_part->isFalsy()) { $redundant = \false; } } if (!$redundant && $existing_var_type->isUnionEmpty()) { //every type was removed, this is an impossible assertion if ($code_location && $key && !$recursive_check) { self::triggerIssueForImpossible($existing_var_type, $old_var_type_string, $key, $assertion, \false, $negated, $code_location, $suppressed_issues); } $failed_reconciliation = 2; return Type::getNever(); } if ($redundant) { //nothing was removed, this is a redundant assertion if ($code_location && $key && !$recursive_check) { self::triggerIssueForImpossible($existing_var_type, $old_var_type_string, $key, $assertion, \true, $negated, $code_location, $suppressed_issues); } $failed_reconciliation = 1; return $existing_var_type->freeze(); } if ($existing_var_type->hasType('bool')) { $existing_var_type->removeType('bool'); $existing_var_type->addType(new TFalse()); } if ($existing_var_type->hasArray()) { $existing_var_type->removeType('array'); $existing_var_type->addType(new TArray([new Union([new TNever()]), new Union([new TNever()])])); } if ($existing_var_type->hasMixed()) { $mixed_atomic_type = $existing_var_type->getAtomicTypes()['mixed']; if (get_class($mixed_atomic_type) === TMixed::class) { $existing_var_type->removeType('mixed'); $existing_var_type->addType(new TEmptyMixed()); } } if ($existing_var_type->hasScalar()) { $scalar_atomic_type = $existing_var_type->getAtomicTypes()['scalar']; if (get_class($scalar_atomic_type) === TScalar::class) { $existing_var_type->removeType('scalar'); $existing_var_type->addType(new TEmptyScalar()); } } if ($existing_var_type->hasType('string')) { $string_atomic_type = $existing_var_type->getAtomicTypes()['string']; if (get_class($string_atomic_type) === TString::class) { $existing_var_type->removeType('string'); $existing_var_type->addType(Type::getAtomicStringFromLiteral('')); $existing_var_type->addType(Type::getAtomicStringFromLiteral('0')); } elseif (get_class($string_atomic_type) === TNonEmptyString::class) { $existing_var_type->removeType('string'); $existing_var_type->addType(Type::getAtomicStringFromLiteral('0')); } elseif (get_class($string_atomic_type) === TNonEmptyLowercaseString::class) { $existing_var_type->removeType('string'); $existing_var_type->addType(Type::getAtomicStringFromLiteral('0')); } elseif (get_class($string_atomic_type) === TNonEmptyNonspecificLiteralString::class) { $existing_var_type->removeType('string'); $existing_var_type->addType(Type::getAtomicStringFromLiteral('0')); } } if ($existing_var_type->hasInt()) { $existing_range_types = $existing_var_type->getRangeInts(); if ($existing_range_types) { foreach ($existing_range_types as $int_key => $literal_type) { if ($literal_type->contains(0)) { $existing_var_type->removeType($int_key); $existing_var_type->addType(new TLiteralInt(0)); } } } else { $existing_var_type->removeType('int'); $existing_var_type->addType(new TLiteralInt(0)); } } if ($existing_var_type->hasFloat()) { $existing_var_type->removeType('float'); $existing_var_type->addType(new TLiteralFloat(0.0)); } if ($existing_var_type->hasNumeric()) { $existing_var_type->removeType('numeric'); $existing_var_type->addType(new TEmptyNumeric()); } foreach ($existing_var_type->getAtomicTypes() as $type_key => $existing_var_atomic_type) { if ($existing_var_atomic_type instanceof TTemplateParam) { if (!$existing_var_atomic_type->as->isMixed()) { $template_did_fail = 0; $existing_var_atomic_type = $existing_var_atomic_type->replaceAs(self::reconcileFalsyOrEmpty($assertion, $existing_var_atomic_type->as, $key, $negated, $code_location, $suppressed_issues, $template_did_fail, $recursive_check)); if (!$template_did_fail) { $existing_var_type->removeType($type_key); $existing_var_type->addType($existing_var_atomic_type); } } } } /** @psalm-suppress RedundantCondition Psalm bug */ assert(!$existing_var_type->isUnionEmpty()); return $existing_var_type->freeze(); } /** * @param string[] $suppressed_issues * @param Reconciler::RECONCILIATION_* $failed_reconciliation */ private static function reconcileScalar(Assertion $assertion, Union $existing_var_type, ?string $key, bool $negated, ?CodeLocation $code_location, array $suppressed_issues, int &$failed_reconciliation, bool $is_equality) : Union { $old_var_type_string = $existing_var_type->getId(); $non_scalar_types = []; $redundant = \true; foreach ($existing_var_type->getAtomicTypes() as $type) { if ($type instanceof TTemplateParam) { if (!$is_equality && !$type->as->isMixed()) { $template_did_fail = 0; $type = $type->replaceAs(self::reconcileScalar($assertion, $type->as, null, \false, null, $suppressed_issues, $template_did_fail, $is_equality)); $redundant = \false; if (!$template_did_fail) { $non_scalar_types[] = $type; } } else { $redundant = \false; $non_scalar_types[] = $type; } } elseif (!$type instanceof Scalar) { $non_scalar_types[] = $type; } else { $redundant = \false; if ($is_equality) { $non_scalar_types[] = $type; } } } if ($redundant || !$non_scalar_types) { if ($key && $code_location) { self::triggerIssueForImpossible($existing_var_type, $old_var_type_string, $key, $assertion, $redundant, $negated, $code_location, $suppressed_issues); } if ($redundant) { $failed_reconciliation = Reconciler::RECONCILIATION_REDUNDANT; } } if ($non_scalar_types) { return new Union($non_scalar_types, ['ignore_falsable_issues' => $existing_var_type->ignore_falsable_issues, 'ignore_nullable_issues' => $existing_var_type->ignore_nullable_issues, 'from_docblock' => $existing_var_type->from_docblock]); } $failed_reconciliation = Reconciler::RECONCILIATION_EMPTY; return Type::getNever(); } /** * @param string[] $suppressed_issues * @param Reconciler::RECONCILIATION_* $failed_reconciliation */ private static function reconcileObject(Assertion $assertion, Union $existing_var_type, ?string $key, bool $negated, ?CodeLocation $code_location, array $suppressed_issues, int &$failed_reconciliation, bool $is_equality) : Union { $old_var_type_string = $existing_var_type->getId(); $non_object_types = []; $redundant = \true; foreach ($existing_var_type->getAtomicTypes() as $type) { if ($type instanceof TTemplateParam) { if (!$is_equality && !$type->as->isMixed()) { $template_did_fail = 0; $type = $type->replaceAs(self::reconcileObject($assertion, $type->as, null, \false, null, $suppressed_issues, $template_did_fail, $is_equality)); $redundant = \false; if (!$template_did_fail) { $non_object_types[] = $type; } } else { $redundant = \false; $non_object_types[] = $type; } } elseif ($type instanceof TCallable) { $non_object_types[] = new TCallableArray([Type::getArrayKey(), Type::getMixed()]); $non_object_types[] = new TCallableString(); $redundant = \false; } elseif ($type instanceof TIterable) { $params = $type->type_params; $params[0] = self::refineArrayKey($params[0]); $non_object_types[] = new TArray($params); $redundant = \false; } elseif (!$type->isObjectType()) { $non_object_types[] = $type; } else { $redundant = \false; if ($is_equality) { $non_object_types[] = $type; } } } if (!$non_object_types || $redundant) { if ($key && $code_location) { self::triggerIssueForImpossible($existing_var_type, $old_var_type_string, $key, $assertion, $redundant, $negated, $code_location, $suppressed_issues); } if ($redundant) { $failed_reconciliation = Reconciler::RECONCILIATION_REDUNDANT; } } if ($non_object_types) { return new Union($non_object_types, ['ignore_falsable_issues' => $existing_var_type->ignore_falsable_issues, 'ignore_nullable_issues' => $existing_var_type->ignore_nullable_issues, 'from_docblock' => $existing_var_type->from_docblock]); } $failed_reconciliation = Reconciler::RECONCILIATION_EMPTY; return Type::getNever(); } /** * @param string[] $suppressed_issues * @param Reconciler::RECONCILIATION_* $failed_reconciliation */ private static function reconcileNumeric(Assertion $assertion, Union $existing_var_type, ?string $key, bool $negated, ?CodeLocation $code_location, array $suppressed_issues, int &$failed_reconciliation, bool $is_equality) : Union { $old_var_type_string = $existing_var_type->getId(); $non_numeric_types = []; $redundant = !($existing_var_type->hasString() || $existing_var_type->hasScalar()); foreach ($existing_var_type->getAtomicTypes() as $type) { if ($type instanceof TTemplateParam) { if (!$is_equality && !$type->as->isMixed()) { $template_did_fail = 0; $type = $type->replaceAs(self::reconcileNumeric($assertion, $type->as, null, \false, null, $suppressed_issues, $template_did_fail, $is_equality)); $redundant = \false; if (!$template_did_fail) { $non_numeric_types[] = $type; } } else { $redundant = \false; $non_numeric_types[] = $type; } } elseif ($type instanceof TArrayKey) { $redundant = \false; $non_numeric_types[] = new TString(); } elseif ($type instanceof TScalar) { $redundant = \false; $non_numeric_types[] = new TString(); $non_numeric_types[] = new TBool(); } elseif (!$type->isNumericType()) { $non_numeric_types[] = $type; } else { $redundant = \false; if ($is_equality) { $non_numeric_types[] = $type; } } } if (!$non_numeric_types || $redundant) { if ($key && $code_location && !$is_equality) { self::triggerIssueForImpossible($existing_var_type, $old_var_type_string, $key, $assertion, $redundant, $negated, $code_location, $suppressed_issues); } if ($redundant) { $failed_reconciliation = Reconciler::RECONCILIATION_REDUNDANT; } } if ($non_numeric_types) { return new Union($non_numeric_types, ['ignore_falsable_issues' => $existing_var_type->ignore_falsable_issues, 'ignore_nullable_issues' => $existing_var_type->ignore_nullable_issues, 'from_docblock' => $existing_var_type->from_docblock]); } $failed_reconciliation = Reconciler::RECONCILIATION_EMPTY; return Type::getNever(); } /** * @param string[] $suppressed_issues * @param Reconciler::RECONCILIATION_* $failed_reconciliation */ private static function reconcileInt(Assertion $assertion, Union $existing_var_type, ?string $key, bool $negated, ?CodeLocation $code_location, array $suppressed_issues, int &$failed_reconciliation, bool $is_equality) : Union { $old_var_type_string = $existing_var_type->getId(); $non_int_types = []; $redundant = \true; foreach ($existing_var_type->getAtomicTypes() as $type) { if ($type instanceof TTemplateParam) { if (!$is_equality && !$type->as->isMixed()) { $template_did_fail = 0; $type = $type->replaceAs(self::reconcileInt($assertion, $type->as, null, \false, null, $suppressed_issues, $template_did_fail, $is_equality)); $redundant = \false; if (!$template_did_fail) { $non_int_types[] = $type; } } else { $redundant = \false; $non_int_types[] = $type; } } elseif ($type instanceof TArrayKey) { $redundant = \false; $non_int_types[] = new TString(); } elseif ($type instanceof TScalar) { $redundant = \false; $non_int_types[] = new TString(); $non_int_types[] = new TFloat(); $non_int_types[] = new TBool(); } elseif ($type instanceof TInt) { $redundant = \false; if ($is_equality) { $non_int_types[] = $type; } elseif ($existing_var_type->from_calculation) { $non_int_types[] = new TFloat(); } } elseif ($type instanceof TNumeric) { $redundant = \false; $non_int_types[] = new TString(); $non_int_types[] = new TFloat(); } else { $non_int_types[] = $type; } } if (!$non_int_types || $redundant) { if ($key && $code_location && !$is_equality) { self::triggerIssueForImpossible($existing_var_type, $old_var_type_string, $key, $assertion, $redundant, $negated, $code_location, $suppressed_issues); } if ($redundant) { $failed_reconciliation = Reconciler::RECONCILIATION_REDUNDANT; } } if ($non_int_types) { return new Union($non_int_types, ['ignore_falsable_issues' => $existing_var_type->ignore_falsable_issues, 'ignore_nullable_issues' => $existing_var_type->ignore_nullable_issues, 'from_docblock' => $existing_var_type->from_docblock]); } $failed_reconciliation = Reconciler::RECONCILIATION_EMPTY; return Type::getNever(); } /** * @param string[] $suppressed_issues * @param Reconciler::RECONCILIATION_* $failed_reconciliation */ private static function reconcileFloat(Assertion $assertion, Union $existing_var_type, ?string $key, bool $negated, ?CodeLocation $code_location, array $suppressed_issues, int &$failed_reconciliation, bool $is_equality) : Union { $old_var_type_string = $existing_var_type->getId(); $non_float_types = []; $redundant = \true; foreach ($existing_var_type->getAtomicTypes() as $type) { if ($type instanceof TTemplateParam) { if (!$is_equality && !$type->as->isMixed()) { $template_did_fail = 0; $type = $type->replaceAs(self::reconcileFloat($assertion, $type->as, null, \false, null, $suppressed_issues, $template_did_fail, $is_equality)); $redundant = \false; if (!$template_did_fail) { $non_float_types[] = $type; } } else { $redundant = \false; $non_float_types[] = $type; } } elseif ($type instanceof TScalar) { $redundant = \false; $non_float_types[] = new TString(); $non_float_types[] = new TInt(); $non_float_types[] = new TBool(); } elseif ($type instanceof TFloat) { $redundant = \false; if ($is_equality) { $non_float_types[] = $type; } } elseif ($type instanceof TNumeric) { $redundant = \false; $non_float_types[] = new TString(); $non_float_types[] = new TInt(); } else { $non_float_types[] = $type; } } if (!$non_float_types || $redundant) { if ($key && $code_location && !$is_equality) { self::triggerIssueForImpossible($existing_var_type, $old_var_type_string, $key, $assertion, $redundant, $negated, $code_location, $suppressed_issues); } if ($redundant) { $failed_reconciliation = Reconciler::RECONCILIATION_REDUNDANT; } } if ($non_float_types) { return new Union($non_float_types, ['ignore_falsable_issues' => $existing_var_type->ignore_falsable_issues, 'ignore_nullable_issues' => $existing_var_type->ignore_nullable_issues, 'from_docblock' => $existing_var_type->from_docblock]); } $failed_reconciliation = Reconciler::RECONCILIATION_EMPTY; return Type::getNever(); } /** * @param string[] $suppressed_issues * @param Reconciler::RECONCILIATION_* $failed_reconciliation */ private static function reconcileString(Assertion $assertion, Union $existing_var_type, ?string $key, bool $negated, ?CodeLocation $code_location, array $suppressed_issues, int &$failed_reconciliation, bool $is_equality) : Union { $old_var_type_string = $existing_var_type->getId(); $non_string_types = []; $redundant = !$existing_var_type->hasScalar(); foreach ($existing_var_type->getAtomicTypes() as $type) { if ($type instanceof TTemplateParam) { if (!$is_equality && !$type->as->isMixed()) { $template_did_fail = 0; $type = $type->replaceAs(self::reconcileString($assertion, $type->as, null, \false, null, $suppressed_issues, $template_did_fail, $is_equality)); $redundant = \false; if (!$template_did_fail) { $non_string_types[] = $type; } } else { $redundant = \false; $non_string_types[] = $type; } } elseif ($type instanceof TArrayKey) { $non_string_types[] = new TInt(); $redundant = \false; } elseif ($type instanceof TCallable) { $non_string_types[] = new TCallableArray([Type::getArrayKey(), Type::getMixed()]); $non_string_types[] = new TCallableObject(); $redundant = \false; } elseif ($type instanceof TNumeric) { $non_string_types[] = $type; $redundant = \false; } elseif ($type instanceof TScalar) { $redundant = \false; $non_string_types[] = new TFloat(); $non_string_types[] = new TInt(); $non_string_types[] = new TBool(); } elseif (!$type instanceof TString) { $non_string_types[] = $type; } else { $redundant = \false; if ($is_equality) { $non_string_types[] = $type; } } } if (!$non_string_types || $redundant) { if ($key && $code_location) { self::triggerIssueForImpossible($existing_var_type, $old_var_type_string, $key, $assertion, $redundant, $negated, $code_location, $suppressed_issues); } if ($redundant) { $failed_reconciliation = Reconciler::RECONCILIATION_REDUNDANT; } } if ($non_string_types) { return new Union($non_string_types, ['ignore_falsable_issues' => $existing_var_type->ignore_falsable_issues, 'ignore_nullable_issues' => $existing_var_type->ignore_nullable_issues, 'from_docblock' => $existing_var_type->from_docblock]); } $failed_reconciliation = Reconciler::RECONCILIATION_EMPTY; return Type::getNever(); } /** * @param string[] $suppressed_issues * @param Reconciler::RECONCILIATION_* $failed_reconciliation */ private static function reconcileArray(Assertion $assertion, Union $existing_var_type, ?string $key, bool $negated, ?CodeLocation $code_location, array $suppressed_issues, int &$failed_reconciliation, bool $is_equality) : Union { $old_var_type_string = $existing_var_type->getId(); $non_array_types = []; $redundant = !$existing_var_type->hasScalar(); foreach ($existing_var_type->getAtomicTypes() as $type) { if ($type instanceof TList) { $type = $type->getKeyedArray(); } if ($type instanceof TTemplateParam) { if (!$is_equality && !$type->as->isMixed()) { $template_did_fail = 0; $type = $type->replaceAs(self::reconcileArray($assertion, $type->as, null, \false, null, $suppressed_issues, $template_did_fail, $is_equality)); $redundant = \false; if (!$template_did_fail) { $non_array_types[] = $type; } } else { $redundant = \false; $non_array_types[] = $type; } } elseif ($type instanceof TCallable) { $non_array_types[] = new TCallableString(); $non_array_types[] = new TCallableObject(); $redundant = \false; } elseif ($type instanceof TIterable) { if (!$type->type_params[0]->isMixed() || !$type->type_params[1]->isMixed()) { $non_array_types[] = new TGenericObject('Traversable', $type->type_params); } else { $non_array_types[] = new TNamedObject('Traversable'); } $redundant = \false; } elseif (!$type instanceof TArray && !$type instanceof TKeyedArray) { $non_array_types[] = $type; } else { $redundant = \false; if ($is_equality) { $non_array_types[] = $type; } } } if (!$non_array_types || $redundant) { if ($key && $code_location) { self::triggerIssueForImpossible($existing_var_type, $old_var_type_string, $key, $assertion, $redundant, $negated, $code_location, $suppressed_issues); } if ($redundant) { $failed_reconciliation = Reconciler::RECONCILIATION_REDUNDANT; } } if ($non_array_types) { return new Union($non_array_types, ['ignore_falsable_issues' => $existing_var_type->ignore_falsable_issues, 'ignore_nullable_issues' => $existing_var_type->ignore_nullable_issues, 'from_docblock' => $existing_var_type->from_docblock]); } $failed_reconciliation = Reconciler::RECONCILIATION_EMPTY; return Type::getNever(); } /** * @param string[] $suppressed_issues * @param Reconciler::RECONCILIATION_* $failed_reconciliation */ private static function reconcileResource(Assertion $assertion, Union $existing_var_type, ?string $key, bool $negated, ?CodeLocation $code_location, array $suppressed_issues, int &$failed_reconciliation, bool $is_equality) : Union { $types = $existing_var_type->getAtomicTypes(); $old_var_type_string = $existing_var_type->getId(); $redundant = \true; if (isset($types['resource'])) { $redundant = \false; unset($types['resource']); } foreach ($types as &$type) { if ($type instanceof TTemplateParam) { $new = $type->replaceAs(self::reconcileResource($assertion, $type->as, null, \false, null, $suppressed_issues, $failed_reconciliation, $is_equality)); $redundant = $new === $type; $type = $new; } } unset($type); if ($redundant || !$types) { if ($key && $code_location && !$is_equality) { self::triggerIssueForImpossible($existing_var_type, $old_var_type_string, $key, $assertion, $redundant, $negated, $code_location, $suppressed_issues); } if ($redundant) { $failed_reconciliation = Reconciler::RECONCILIATION_REDUNDANT; } } if ($types) { return $existing_var_type->setTypes($types); } $failed_reconciliation = Reconciler::RECONCILIATION_EMPTY; return Type::getNever(); } /** * @param string[] $suppressed_issues */ private static function reconcileIsLessThanOrEqualTo(IsLessThanOrEqualTo $assertion, Union $existing_var_type, bool $inside_loop, string $old_var_type_string, ?string $var_id, bool $negated, ?CodeLocation $code_location, array $suppressed_issues) : Union { $existing_var_type = $existing_var_type->getBuilder(); $assertion_value = $assertion->value; $redundant = \true; if ($assertion->doesFilterNullOrFalse() && ($existing_var_type->hasType('null') || $existing_var_type->hasType('false'))) { $redundant = \false; $existing_var_type->removeType('null'); $existing_var_type->removeType('false'); } foreach ($existing_var_type->getAtomicTypes() as $atomic_type) { if ($atomic_type instanceof TIntRange) { if ($atomic_type->contains($assertion_value)) { // if the range contains the assertion, the range must be adapted $redundant = \false; $existing_var_type->removeType($atomic_type->getKey()); if ($atomic_type->max_bound === null) { $max_bound = $assertion_value; } else { $max_bound = TIntRange::getNewLowestBound($assertion_value, $atomic_type->max_bound); } $existing_var_type->addType(new TIntRange($atomic_type->min_bound, $max_bound)); } elseif ($atomic_type->isLesserThan($assertion_value)) { // if the range is lesser than the assertion, the check is redundant } elseif ($atomic_type->isGreaterThan($assertion_value)) { // if the range is greater than the assertion, the type must be removed $redundant = \false; $existing_var_type->removeType($atomic_type->getKey()); } } elseif ($atomic_type instanceof TLiteralInt) { if ($atomic_type->value > $assertion_value) { $redundant = \false; $existing_var_type->removeType($atomic_type->getKey()); } /*elseif ($inside_loop) { //when inside a loop, allow the range to extends the type $existing_var_type->removeType($atomic_type->getKey()); if ($atomic_type->value < $assertion_value) { $existing_var_type->addType(new TIntRange($atomic_type->value, $assertion_value)); } else { $existing_var_type->addType(new TIntRange($assertion_value, $atomic_type->value)); } }*/ } elseif ($atomic_type instanceof TInt) { $redundant = \false; $existing_var_type->removeType($atomic_type->getKey()); $existing_var_type->addType(new TIntRange(null, $assertion_value)); } else { // we assume that other types may have been removed (empty strings? numeric strings?) //It may be worth refining to improve reconciliation while keeping in mind we're on loose comparison $redundant = \false; } } if (!$inside_loop && $redundant && $var_id && $code_location) { self::triggerIssueForImpossible($existing_var_type, $old_var_type_string, $var_id, $assertion, \true, $negated, $code_location, $suppressed_issues); } if ($existing_var_type->isUnionEmpty()) { if ($var_id && $code_location) { self::triggerIssueForImpossible($existing_var_type, $old_var_type_string, $var_id, $assertion, \false, $negated, $code_location, $suppressed_issues); } $existing_var_type->addType(new TNever()); } return $existing_var_type->freeze(); } /** * @param string[] $suppressed_issues */ private static function reconcileIsGreaterThanOrEqualTo(IsGreaterThanOrEqualTo $assertion, Union $existing_var_type, bool $inside_loop, string $old_var_type_string, ?string $var_id, bool $negated, ?CodeLocation $code_location, array $suppressed_issues) : Union { $existing_var_type = $existing_var_type->getBuilder(); $assertion_value = $assertion->value; $redundant = \true; if ($assertion->doesFilterNullOrFalse() && ($existing_var_type->hasType('null') || $existing_var_type->hasType('false'))) { $redundant = \false; $existing_var_type->removeType('null'); $existing_var_type->removeType('false'); } foreach ($existing_var_type->getAtomicTypes() as $atomic_type) { if ($atomic_type instanceof TIntRange) { if ($atomic_type->contains($assertion_value)) { // if the range contains the assertion, the range must be adapted $redundant = \false; $existing_var_type->removeType($atomic_type->getKey()); $min_bound = $atomic_type->min_bound; if ($min_bound === null) { $min_bound = $assertion_value; } else { $min_bound = max($min_bound, $assertion_value); } $existing_var_type->addType(new TIntRange($min_bound, $atomic_type->max_bound)); } elseif ($atomic_type->isLesserThan($assertion_value)) { // if the range is lesser than the assertion, the type must be removed $redundant = \false; $existing_var_type->removeType($atomic_type->getKey()); } elseif ($atomic_type->isGreaterThan($assertion_value)) { // if the range is greater than the assertion, the check is redundant } } elseif ($atomic_type instanceof TLiteralInt) { if ($atomic_type->value < $assertion_value) { $redundant = \false; $existing_var_type->removeType($atomic_type->getKey()); } /* elseif ($inside_loop) { //when inside a loop, allow the range to extends the type $existing_var_type->removeType($atomic_type->getKey()); if ($atomic_type->value < $assertion_value) { $existing_var_type->addType(new TIntRange($atomic_type->value, $assertion_value)); } else { $existing_var_type->addType(new TIntRange($assertion_value, $atomic_type->value)); } }*/ } elseif ($atomic_type instanceof TInt) { $redundant = \false; $existing_var_type->removeType($atomic_type->getKey()); $existing_var_type->addType(new TIntRange($assertion_value, null)); } else { // we assume that other types may have been removed (empty strings? numeric strings?) //It may be worth refining to improve reconciliation while keeping in mind we're on loose comparison $redundant = \false; } } if (!$inside_loop && $redundant && $var_id && $code_location) { self::triggerIssueForImpossible($existing_var_type, $old_var_type_string, $var_id, $assertion, \true, $negated, $code_location, $suppressed_issues); } if ($existing_var_type->isUnionEmpty()) { if ($var_id && $code_location) { self::triggerIssueForImpossible($existing_var_type, $old_var_type_string, $var_id, $assertion, \false, $negated, $code_location, $suppressed_issues); } $existing_var_type->addType(new TNever()); } return $existing_var_type->freeze(); } } >> the type T appears at three different depths. * * The shallowest-appearance of the template takes prominence when inferring the type of T. */ public int $appearance_depth; /** * The argument offset where this template was set * * In the type Foo the type appears at argument offsets 0 and 2 */ public ?int $arg_offset = null; /** * When non-null, indicates an equality template bound (vs a lower or upper bound) */ public ?string $equality_bound_classlike = null; public function __construct(Union $type, int $appearance_depth = 0, ?int $arg_offset = null, ?string $equality_bound_classlike = null) { $this->type = $type; $this->appearance_depth = $appearance_depth; $this->arg_offset = $arg_offset; $this->equality_bound_classlike = $equality_bound_classlike; } } key = $key; $this->value = $value; $this->is_list = $is_list; $this->count = $count; } /** * @return ( * $type is TArrayKey ? self : ( * $type is TArray ? self : null * ) * ) */ public static function infer(Atomic $type) : ?self { if ($type instanceof TKeyedArray) { $count = null; if ($type->isSealed()) { $count = count($type->properties); } return new self($type->getGenericKeyType(), $type->getGenericValueType(), $type->is_list, $count); } if ($type instanceof TNonEmptyArray) { return new self($type->type_params[0], $type->type_params[1], \false, $type->count); } if ($type instanceof TArray) { $empty = $type->isEmptyArray(); return new self($type->type_params[0], $type->type_params[1], \false, $empty ? 0 : null); } return null; } } getAtomicTypes(); // here we want to subtract atomic types from the input type // when they're also in the union type, so those shared atomic // types will never be inferred as part of the generic type if ($input_type && !$input_type->isSingle()) { $new_input_type = $input_type->getBuilder(); foreach ($original_atomic_types as $key => $_) { if ($new_input_type->hasType($key)) { $new_input_type->removeType($key); } } if (!$new_input_type->isUnionEmpty()) { $input_type = $new_input_type->freeze(); } else { return $union_type; } } $had_template = \false; foreach ($original_atomic_types as $key => $atomic_type) { $atomic_types = [...$atomic_types, ...self::handleAtomicStandin($atomic_type, $key, $template_result, $codebase, $statements_analyzer, $input_type, $input_arg_offset, $calling_class, $calling_function, $replace, $add_lower_bound, $bound_equality_classlike, $depth, count($original_atomic_types) === 1, $had_template)]; } if ($replace) { if (array_values($original_atomic_types) === $atomic_types) { return $union_type; } if (!$atomic_types) { return $union_type; } if (count($atomic_types) > 1) { return \Psalm\Internal\Type\TypeCombiner::combine($atomic_types, $codebase)->setProperties(['ignore_nullable_issues' => $union_type->ignore_nullable_issues, 'ignore_falsable_issues' => $union_type->ignore_falsable_issues, 'possibly_undefined' => $union_type->possibly_undefined, 'had_template' => $had_template]); } return new Union($atomic_types, ['ignore_nullable_issues' => $union_type->ignore_nullable_issues, 'ignore_falsable_issues' => $union_type->ignore_falsable_issues, 'possibly_undefined' => $union_type->possibly_undefined, 'had_template' => $had_template]); } return $union_type; } /** * @return list */ private static function handleAtomicStandin(Atomic $atomic_type, string $key, \Psalm\Internal\Type\TemplateResult $template_result, Codebase $codebase, ?StatementsAnalyzer $statements_analyzer, ?Union $input_type, ?int $input_arg_offset, ?string $calling_class, ?string $calling_function, bool $replace, bool $add_lower_bound, ?string $bound_equality_classlike, int $depth, bool $was_single, bool &$had_template) : array { if ($bracket_pos = strpos($key, '<')) { $key = substr($key, 0, $bracket_pos); } if ($atomic_type instanceof TTemplateParam && isset($template_result->template_types[$atomic_type->param_name][$atomic_type->defining_class])) { return self::handleTemplateParamStandin($atomic_type, $key, $input_type, $input_arg_offset, $calling_class, $calling_function, $template_result, $codebase, $statements_analyzer, $replace, $add_lower_bound, $bound_equality_classlike, $depth, $had_template); } if ($atomic_type instanceof TTemplateParam && isset($template_result->lower_bounds[$atomic_type->param_name][$atomic_type->defining_class])) { $most_specific_type = self::getMostSpecificTypeFromBounds($template_result->lower_bounds[$atomic_type->param_name][$atomic_type->defining_class], $codebase); return array_values($most_specific_type->getAtomicTypes()); } if ($atomic_type instanceof TTemplateParamClass && isset($template_result->template_types[$atomic_type->param_name][$atomic_type->defining_class])) { if ($replace) { return self::handleTemplateParamClassStandin($atomic_type, $input_type, $input_arg_offset, $calling_class, $calling_function, $template_result, $codebase, $statements_analyzer, \true, $add_lower_bound, $bound_equality_classlike, $depth, $was_single); } } if ($atomic_type instanceof TTemplateIndexedAccess) { if ($replace) { $atomic_types = []; $include_first = \true; if (isset($template_result->lower_bounds[$atomic_type->array_param_name][$atomic_type->defining_class]) && !empty($template_result->lower_bounds[$atomic_type->offset_param_name])) { $array_template_type = self::getMostSpecificTypeFromBounds($template_result->lower_bounds[$atomic_type->array_param_name][$atomic_type->defining_class], $codebase); $offset_template_type = self::getMostSpecificTypeFromBounds(array_values($template_result->lower_bounds[$atomic_type->offset_param_name])[0], $codebase); if ($array_template_type->isSingle() && $offset_template_type->isSingle() && !$array_template_type->isMixed() && !$offset_template_type->isMixed()) { $array_template_type = $array_template_type->getSingleAtomic(); $offset_template_type = $offset_template_type->getSingleAtomic(); if ($array_template_type instanceof TList) { $array_template_type = $array_template_type->getKeyedArray(); } if ($array_template_type instanceof TKeyedArray && ($offset_template_type instanceof TLiteralString || $offset_template_type instanceof TLiteralInt) && isset($array_template_type->properties[$offset_template_type->value])) { $include_first = \false; $replacement_type = $array_template_type->properties[$offset_template_type->value]; foreach ($replacement_type->getAtomicTypes() as $replacement_atomic_type) { $atomic_types[] = $replacement_atomic_type; } } } } if ($include_first) { $atomic_types[] = $atomic_type; } return $atomic_types; } return [$atomic_type]; } if ($atomic_type instanceof TTemplateKeyOf || $atomic_type instanceof TTemplateValueOf) { if (!$replace) { return [$atomic_type]; } $atomic_types = []; $include_first = \true; $template_type = null; if (isset($template_result->lower_bounds[$atomic_type->param_name][$atomic_type->defining_class])) { $template_type = self::getMostSpecificTypeFromBounds($template_result->lower_bounds[$atomic_type->param_name][$atomic_type->defining_class], $codebase); } elseif (isset($template_result->template_types[$atomic_type->param_name][$atomic_type->defining_class])) { $template_type = $template_result->template_types[$atomic_type->param_name][$atomic_type->defining_class]; } if ($template_type) { foreach ($template_type->getAtomicTypes() as $template_atomic) { if ($template_atomic instanceof TList) { $template_atomic = $template_atomic->getKeyedArray(); } if (!$template_atomic instanceof TKeyedArray && !$template_atomic instanceof TArray) { return [$atomic_type]; } if ($atomic_type instanceof TTemplateKeyOf) { if ($template_atomic instanceof TKeyedArray) { $template_atomic = $template_atomic->getGenericKeyType(); } else { $template_atomic = $template_atomic->type_params[0]; } } else { if ($template_atomic instanceof TKeyedArray) { $template_atomic = $template_atomic->getGenericValueType(); } else { $template_atomic = $template_atomic->type_params[1]; } } $include_first = \false; foreach ($template_atomic->getAtomicTypes() as $key_atomic_type) { $atomic_types[] = $key_atomic_type; } } } if ($include_first) { $atomic_types[] = $atomic_type; } return $atomic_types; } if ($atomic_type instanceof TTemplatePropertiesOf) { if (!$replace || !isset($template_result->template_types[$atomic_type->param_name][$atomic_type->defining_class])) { return [$atomic_type]; } $template_type = $template_result->template_types[$atomic_type->param_name][$atomic_type->defining_class]; $classlike_type = $template_type->getSingleAtomic(); if (!$classlike_type instanceof TNamedObject) { return [$atomic_type]; } /** @psalm-suppress ReferenceConstraintViolation Psalm bug, $atomic_type is not a reference */ $atomic_type = new TPropertiesOf($classlike_type, $atomic_type->visibility_filter); return [$atomic_type]; } $matching_atomic_types = []; if ($input_type && !$input_type->hasMixed()) { $matching_atomic_types = self::findMatchingAtomicTypesForTemplate($atomic_type, $key, $codebase, $statements_analyzer, $input_type); } if (!$matching_atomic_types) { /** @psalm-suppress ReferenceConstraintViolation Psalm bug, $atomic_type is not a reference */ $atomic_type = $atomic_type->replaceTemplateTypesWithStandins($template_result, $codebase, $statements_analyzer, null, $input_arg_offset, $calling_class, $calling_function, $replace, $add_lower_bound, $depth + 1); return [$atomic_type]; } $atomic_types = []; foreach ($matching_atomic_types as $matching_atomic_type) { $atomic_types[] = $atomic_type->replaceTemplateTypesWithStandins($template_result, $codebase, $statements_analyzer, $matching_atomic_type, $input_arg_offset, $calling_class, $calling_function, $replace, $add_lower_bound, $depth + 1); } return $atomic_types; } /** * This method attempts to find bits of the input type (normally the argument type of a method call) * that match the base type (normally the param type of the method). These matches are used to infer * more template types * * Example: when passing `array` to a function that expects `array`, a rule in this method * identifies the matching atomic types for `T` as `string|int` * * @return list */ private static function findMatchingAtomicTypesForTemplate(Atomic $base_type, string $key, Codebase $codebase, ?StatementsAnalyzer $statements_analyzer, Union $input_type) : array { $matching_atomic_types = []; foreach ($input_type->getAtomicTypes() as $input_key => $atomic_input_type) { if ($atomic_input_type instanceof TList) { $atomic_input_type = $atomic_input_type->getKeyedArray(); } if ($bracket_pos = strpos($input_key, '<')) { $input_key = substr($input_key, 0, $bracket_pos); } if ($input_key === $key) { $matching_atomic_types[$atomic_input_type->getId()] = $atomic_input_type; continue; } if ($atomic_input_type instanceof TClosure && $base_type instanceof TClosure) { $matching_atomic_types[$atomic_input_type->getId()] = $atomic_input_type; continue; } if ($atomic_input_type instanceof TCallable && $base_type instanceof TCallable) { $matching_atomic_types[$atomic_input_type->getId()] = $atomic_input_type; continue; } if ($atomic_input_type instanceof TClosure && $base_type instanceof TCallable) { $matching_atomic_types[$atomic_input_type->getId()] = $atomic_input_type; continue; } if (($atomic_input_type instanceof TArray || $atomic_input_type instanceof TKeyedArray) && $key === 'iterable') { $matching_atomic_types[$atomic_input_type->getId()] = $atomic_input_type; continue; } if (strpos($input_key, $key . '&') === 0) { $matching_atomic_types[$atomic_input_type->getId()] = $atomic_input_type; continue; } if ($atomic_input_type instanceof TLiteralClassString && $base_type instanceof TClassString && $base_type->as_type) { try { $classlike_storage = $codebase->classlike_storage_provider->get($atomic_input_type->value); if (!empty($classlike_storage->template_extended_params[$base_type->as_type->value])) { $atomic_input_type = new TClassString($base_type->as_type->value, new TGenericObject($base_type->as_type->value, array_values($classlike_storage->template_extended_params[$base_type->as_type->value]))); $matching_atomic_types[$atomic_input_type->getId()] = $atomic_input_type; continue; } } catch (InvalidArgumentException $e) { // do nothing } } if ($base_type instanceof TCallable) { $matching_atomic_type = CallableTypeComparator::getCallableFromAtomic($codebase, $atomic_input_type, null, $statements_analyzer); if ($matching_atomic_type) { $matching_atomic_types[$matching_atomic_type->getId()] = $matching_atomic_type; continue; } } if ($atomic_input_type instanceof TNamedObject && ($base_type instanceof TNamedObject || $base_type instanceof TIterable)) { if ($base_type instanceof TIterable) { if ($atomic_input_type->value === 'Traversable') { $matching_atomic_types[$atomic_input_type->getId()] = $atomic_input_type; continue; } $base_type = new TGenericObject('Traversable', $base_type->type_params); } try { $classlike_storage = $codebase->classlike_storage_provider->get($atomic_input_type->value); if ($atomic_input_type instanceof TGenericObject && isset($classlike_storage->template_extended_params[$base_type->value])) { $matching_atomic_types[$atomic_input_type->getId()] = $atomic_input_type; continue; } if (!empty($classlike_storage->template_extended_params[$base_type->value])) { $atomic_input_type = new TGenericObject($base_type->value, array_values($classlike_storage->template_extended_params[$base_type->value])); $matching_atomic_types[$atomic_input_type->getId()] = $atomic_input_type; continue; } if (in_array('Traversable', $classlike_storage->class_implements) && $base_type->value === 'Iterator') { $matching_atomic_types[$atomic_input_type->getId()] = $atomic_input_type; continue; } } catch (InvalidArgumentException $e) { // do nothing } } if ($atomic_input_type instanceof TNamedObject && $base_type instanceof TObjectWithProperties) { $object_with_keys = KeyedArrayComparator::coerceToObjectWithProperties($codebase, $atomic_input_type, $base_type); if ($object_with_keys) { $matching_atomic_types[$object_with_keys->getId()] = $object_with_keys; } continue; } if ($atomic_input_type instanceof TTemplateParam) { $matching_atomic_types = array_merge($matching_atomic_types, self::findMatchingAtomicTypesForTemplate($base_type, $key, $codebase, $statements_analyzer, $atomic_input_type->as)); continue; } } return array_values($matching_atomic_types); } /** * @return list */ private static function handleTemplateParamStandin(TTemplateParam &$atomic_type, string $key, ?Union $input_type, ?int $input_arg_offset, ?string $calling_class, ?string $calling_function, \Psalm\Internal\Type\TemplateResult $template_result, Codebase $codebase, ?StatementsAnalyzer $statements_analyzer, bool $replace, bool $add_lower_bound, ?string $bound_equality_classlike, int $depth, bool &$had_template) : array { if ($atomic_type->defining_class === $calling_class) { return [$atomic_type]; } $template_type = $template_result->template_types[$atomic_type->param_name][$atomic_type->defining_class]; if ($template_type->getId() === $key) { return array_values($template_type->getAtomicTypes()); } $replacement_type = $template_type; $param_name_key = $atomic_type->param_name; if (strpos($key, '&')) { $param_name_key = $key; } $extra_types = []; if ($atomic_type->extra_types) { foreach ($atomic_type->extra_types as $extra_type) { $extra_type = self::replace(new Union([$extra_type]), $template_result, $codebase, $statements_analyzer, $input_type, $input_arg_offset, $calling_class, $calling_function, $replace, $add_lower_bound, $bound_equality_classlike, $depth + 1); if ($extra_type->isSingle()) { $extra_type = $extra_type->getSingleAtomic(); if ($extra_type instanceof TNamedObject || $extra_type instanceof TTemplateParam || $extra_type instanceof TIterable || $extra_type instanceof TObjectWithProperties) { $extra_types[$extra_type->getKey()] = $extra_type; } } } } if ($replace) { $atomic_types = []; if ($replacement_type->hasMixed() && !$atomic_type->as->hasMixed()) { foreach ($atomic_type->as->getAtomicTypes() as $as_atomic_type) { $atomic_types[] = $as_atomic_type; } } else { $replacement_type = \Psalm\Internal\Type\TypeExpander::expandUnion($codebase, $replacement_type, $calling_class, $calling_class, null); if ($depth < 10) { $replacement_type = self::replace($replacement_type, $template_result, $codebase, $statements_analyzer, $input_type, $input_arg_offset, $calling_class, $calling_function, \true, $add_lower_bound, $bound_equality_classlike, $depth + 1); } foreach ($replacement_type->getAtomicTypes() as $replacement_atomic_type) { $replacements_found = \false; // @codingStandardsIgnoreStart if ($replacement_atomic_type instanceof TTemplateKeyOf && isset($template_result->template_types[$replacement_atomic_type->param_name][$replacement_atomic_type->defining_class]) && count($template_result->lower_bounds[$atomic_type->param_name][$atomic_type->defining_class]) === 1) { $keyed_template = $template_result->template_types[$replacement_atomic_type->param_name][$replacement_atomic_type->defining_class]; if ($keyed_template->isSingle()) { $keyed_template = $keyed_template->getSingleAtomic(); } if ($keyed_template instanceof \Psalm\Type\Atomic\TList) { $keyed_template = $keyed_template->getKeyedArray(); } if ($keyed_template instanceof TKeyedArray || $keyed_template instanceof TArray) { if ($keyed_template instanceof TKeyedArray) { $key_type = $keyed_template->getGenericKeyType(); } else { $key_type = $keyed_template->type_params[0]; } $replacements_found = \true; foreach ($key_type->getAtomicTypes() as $key_type_atomic) { $atomic_types[] = $key_type_atomic; } $existing_lower_bound = reset($template_result->lower_bounds[$atomic_type->param_name][$atomic_type->defining_class]); $existing_lower_bound->type = $key_type; } } if ($replacement_atomic_type instanceof TTemplateParam && $replacement_atomic_type->defining_class !== $calling_class && $replacement_atomic_type->defining_class !== 'fn-' . $calling_function) { foreach ($replacement_atomic_type->as->getAtomicTypes() as $nested_type_atomic) { $replacements_found = \true; $atomic_types[] = $nested_type_atomic; } } // @codingStandardsIgnoreEnd if (!$replacements_found) { $atomic_types[] = $replacement_atomic_type; } $had_template = \true; } } $matching_input_keys = []; $as = \Psalm\Internal\Type\TypeExpander::expandUnion($codebase, $atomic_type->as, $calling_class, $calling_class, null); $as = self::replace($as, $template_result, $codebase, $statements_analyzer, $input_type, $input_arg_offset, $calling_class, $calling_function, \true, $add_lower_bound, $bound_equality_classlike, $depth + 1); $atomic_type = $atomic_type->replaceAs($as); if ($input_type && !$template_result->readonly && ($atomic_type->as->isMixed() || UnionTypeComparator::canBeContainedBy($codebase, $input_type, $atomic_type->as, \false, \false, $matching_input_keys))) { $generic_param = $input_type->getBuilder(); if ($matching_input_keys) { $generic_param_keys = array_keys($generic_param->getAtomicTypes()); foreach ($generic_param_keys as $atomic_key) { if (!isset($matching_input_keys[$atomic_key])) { $generic_param->removeType($atomic_key); } } } if ($add_lower_bound) { return array_values($generic_param->getAtomicTypes()); } $generic_param->possibly_undefined = \false; $generic_param = $generic_param->setFromDocblock()->freeze(); if (isset($template_result->lower_bounds[$param_name_key][$atomic_type->defining_class])) { $existing_lower_bounds = $template_result->lower_bounds[$param_name_key][$atomic_type->defining_class]; $has_matching_lower_bound = \false; foreach ($existing_lower_bounds as $existing_lower_bound) { $existing_depth = $existing_lower_bound->appearance_depth; $existing_arg_offset = $existing_lower_bound->arg_offset ?? $input_arg_offset; if ($existing_depth === $depth && $input_arg_offset === $existing_arg_offset && $existing_lower_bound->type->getId() === $generic_param->getId() && $existing_lower_bound->equality_bound_classlike === $bound_equality_classlike) { $has_matching_lower_bound = \true; break; } } if (!$has_matching_lower_bound) { $template_result->lower_bounds[$param_name_key][$atomic_type->defining_class][] = new \Psalm\Internal\Type\TemplateBound($generic_param, $depth, $input_arg_offset, $bound_equality_classlike); } } else { $template_result->lower_bounds[$param_name_key][$atomic_type->defining_class] = [new \Psalm\Internal\Type\TemplateBound($generic_param, $depth, $input_arg_offset, $bound_equality_classlike)]; } } foreach ($atomic_types as &$t) { if ($t instanceof TNamedObject || $t instanceof TTemplateParam || $t instanceof TIterable || $t instanceof TObjectWithProperties) { $t = $t->setIntersectionTypes($extra_types); } elseif ($t instanceof TObject && $extra_types) { $t = reset($extra_types)->setIntersectionTypes(array_slice($extra_types, 1)); } } unset($t); return $atomic_types; } if ($add_lower_bound && $input_type && !$template_result->readonly) { $matching_input_keys = []; if (UnionTypeComparator::canBeContainedBy($codebase, $input_type, $replacement_type, \false, \false, $matching_input_keys)) { $generic_param = $input_type->getBuilder(); if ($matching_input_keys) { $generic_param_keys = array_keys($generic_param->getAtomicTypes()); foreach ($generic_param_keys as $atomic_key) { if (!isset($matching_input_keys[$atomic_key])) { $generic_param->removeType($atomic_key); } } } $generic_param = $generic_param->freeze(); $upper_bound = $template_result->upper_bounds[$param_name_key][$atomic_type->defining_class] ?? null; if ($upper_bound) { if (!UnionTypeComparator::isContainedBy($codebase, $upper_bound->type, $generic_param) || !UnionTypeComparator::isContainedBy($codebase, $generic_param, $upper_bound->type)) { $intersection_type = Type::intersectUnionTypes($upper_bound->type, $generic_param, $codebase); } else { $intersection_type = $generic_param; } if ($intersection_type) { $upper_bound->type = $intersection_type; } else { $template_result->upper_bounds_unintersectable_types[] = $upper_bound->type; $template_result->upper_bounds_unintersectable_types[] = $generic_param; $upper_bound->type = Type::getMixed(); } } else { $template_result->upper_bounds[$param_name_key][$atomic_type->defining_class] = new \Psalm\Internal\Type\TemplateBound($generic_param); } } } return [$atomic_type]; } /** * @return non-empty-list */ public static function handleTemplateParamClassStandin(TTemplateParamClass $atomic_type, ?Union $input_type, ?int $input_arg_offset, ?string $calling_class, ?string $calling_function, \Psalm\Internal\Type\TemplateResult $template_result, Codebase $codebase, ?StatementsAnalyzer $statements_analyzer, bool $replace, bool $add_lower_bound, ?string $bound_equality_classlike, int $depth, bool $was_single) : array { if ($atomic_type->defining_class === $calling_class) { return [$atomic_type]; } $atomic_types = []; $as_type = $atomic_type->as_type; if ($input_type && !$template_result->readonly) { $valid_input_atomic_types = []; foreach ($input_type->getAtomicTypes() as $input_atomic_type) { if ($input_atomic_type instanceof TLiteralClassString) { $valid_input_atomic_types[] = new TNamedObject($input_atomic_type->value, \false, \false, [], \true); } elseif ($input_atomic_type instanceof TTemplateParamClass) { $valid_input_atomic_types[] = new TTemplateParam($input_atomic_type->param_name, $input_atomic_type->as_type ? new Union([$input_atomic_type->as_type]) : ($input_atomic_type->as === 'object' ? Type::getObject() : Type::getMixed()), $input_atomic_type->defining_class, [], \true); } elseif ($input_atomic_type instanceof TClassString) { if ($input_atomic_type->as_type) { $valid_input_atomic_types[] = $input_atomic_type->as_type->setFromDocblock(\true); } elseif ($input_atomic_type->as !== 'object') { $valid_input_atomic_types[] = new TNamedObject($input_atomic_type->as, \false, \false, [], \true); } else { $valid_input_atomic_types[] = new TObject(\true); } } elseif ($input_atomic_type instanceof TDependentGetClass) { $valid_input_atomic_types[] = new TObject(\true); } } $generic_param = null; if ($valid_input_atomic_types) { $generic_param = new Union($valid_input_atomic_types); } elseif ($was_single) { $generic_param = Type::getMixed(); } if ($as_type) { // sometimes templated class-strings can contain nested templates // in the as type that need to be resolved as well. $as_type_union = self::replace(new Union([$as_type]), $template_result, $codebase, $statements_analyzer, $generic_param, $input_arg_offset, $calling_class, $calling_function, $replace, $add_lower_bound, $bound_equality_classlike, $depth + 1); $first = $as_type_union->getSingleAtomic(); if (count($as_type_union->getAtomicTypes()) === 1 && $first instanceof TNamedObject) { $as_type = $first; } else { $as_type = null; } } if ($generic_param) { if (isset($template_result->lower_bounds[$atomic_type->param_name][$atomic_type->defining_class])) { $template_result->lower_bounds[$atomic_type->param_name][$atomic_type->defining_class] = [new \Psalm\Internal\Type\TemplateBound(Type::combineUnionTypes($generic_param, self::getMostSpecificTypeFromBounds($template_result->lower_bounds[$atomic_type->param_name][$atomic_type->defining_class], $codebase)), $depth)]; } else { $template_result->lower_bounds[$atomic_type->param_name][$atomic_type->defining_class] = [new \Psalm\Internal\Type\TemplateBound($generic_param, $depth, $input_arg_offset)]; } } } else { $template_type = $template_result->template_types[$atomic_type->param_name][$atomic_type->defining_class]; foreach ($template_type->getAtomicTypes() as $template_atomic_type) { if ($template_atomic_type instanceof TNamedObject) { $atomic_types[] = new TClassString($template_atomic_type->value, $template_atomic_type); } elseif ($template_atomic_type instanceof TObject) { $atomic_types[] = new TClassString(); } } } $class_string = new TClassString($atomic_type->as, $as_type); if (!$atomic_types) { $atomic_types[] = $class_string; } return $atomic_types; } /** * @param array>> $template_types */ public static function getRootTemplateType(array $template_types, string $param_name, string $defining_class, array $visited_classes, ?Codebase $codebase) : ?Union { if (isset($visited_classes[$defining_class])) { return null; } if (isset($template_types[$param_name][$defining_class])) { $mapped_type = self::getMostSpecificTypeFromBounds($template_types[$param_name][$defining_class], $codebase); $mapped_type_atomic_types = array_values($mapped_type->getAtomicTypes()); if (count($mapped_type_atomic_types) > 1 || !$mapped_type_atomic_types[0] instanceof TTemplateParam) { return $mapped_type; } $first_template = $mapped_type_atomic_types[0]; return self::getRootTemplateType($template_types, $first_template->param_name, $first_template->defining_class, $visited_classes + [$defining_class => \true], $codebase) ?? $mapped_type; } return null; } /** * This takes a list of lower bounds and returns the most general type. * * If given a single bound that's just the type of that bound. * * If instead given a collection of lower bounds it normally returns a union of those * bound types. * * @param non-empty-list $lower_bounds */ public static function getMostSpecificTypeFromBounds(array $lower_bounds, ?Codebase $codebase) : Union { if (count($lower_bounds) === 1) { return reset($lower_bounds)->type; } usort($lower_bounds, static fn(\Psalm\Internal\Type\TemplateBound $bound_a, \Psalm\Internal\Type\TemplateBound $bound_b): int => $bound_b->appearance_depth <=> $bound_a->appearance_depth); $current_depth = null; $current_type = null; $had_invariant = \false; $last_arg_offset = -1; foreach ($lower_bounds as $template_bound) { if ($current_depth === null) { $current_depth = $template_bound->appearance_depth; } elseif ($current_depth !== $template_bound->appearance_depth && $current_type) { if (!$current_type->isNever() && ($had_invariant || $last_arg_offset === $template_bound->arg_offset)) { // escape switches when matching on invariant generic params // and when matching break; } $current_depth = $template_bound->appearance_depth; } $had_invariant = $had_invariant ?: $template_bound->equality_bound_classlike !== null; $current_type = Type::combineUnionTypes($current_type, $template_bound->type, $codebase); $last_arg_offset = $template_bound->arg_offset; } return $current_type ?? Type::getMixed(); } /** * @param TGenericObject|TNamedObject|TIterable $input_type_part * @param TGenericObject|TIterable $container_type_part * @psalm-external-mutation-free * @return list */ public static function getMappedGenericTypeParams(Codebase $codebase, Atomic $input_type_part, Atomic $container_type_part, ?array &$container_type_params_covariant = null) : array { if ($input_type_part instanceof TGenericObject || $input_type_part instanceof TIterable) { $input_type_params = $input_type_part->type_params; } elseif ($codebase->classlike_storage_provider->has($input_type_part->value)) { $class_storage = $codebase->classlike_storage_provider->get($input_type_part->value); $container_class = $container_type_part->value; if (strtolower($input_type_part->value) === strtolower($container_type_part->value)) { $input_type_params = $class_storage->getClassTemplateTypes(); } elseif (!empty($class_storage->template_extended_params[$container_class])) { $input_type_params = array_values($class_storage->template_extended_params[$container_class]); } else { $input_type_params = array_fill(0, count($class_storage->template_types ?? []), Type::getMixed()); } } else { $input_type_params = []; } $input_class_storage = $codebase->classlike_storage_provider->has($input_type_part->value) ? $codebase->classlike_storage_provider->get($input_type_part->value) : null; $container_type_params_covariant = $codebase->classlike_storage_provider->has($container_type_part->value) ? $codebase->classlike_storage_provider->get($container_type_part->value)->template_covariants : null; if ($input_type_part->value !== $container_type_part->value && $input_class_storage) { $input_template_types = $input_class_storage->template_types; $i = 0; $replacement_templates = []; if ($input_template_types && (!$container_type_part instanceof TGenericObject || !$container_type_part->remapped_params)) { foreach ($input_template_types as $template_name => $_) { if (!isset($input_type_params[$i])) { break; } $replacement_templates[$template_name][$input_type_part->value] = $input_type_params[$i]; $i++; } } $template_extends = $input_class_storage->template_extended_params; $container_type_part_value = $container_type_part->value === 'iterable' ? 'Traversable' : $container_type_part->value; if (isset($template_extends[$container_type_part_value])) { $params = $template_extends[$container_type_part_value]; $new_input_params = []; foreach ($params as $extended_input_param_type) { $new_input_param = null; foreach ($extended_input_param_type->getAtomicTypes() as $extended_template) { $extended_templates = $extended_template instanceof TTemplateParam ? array_values(array_filter(Methods::getExtendedTemplatedTypes($extended_template, $template_extends), static fn(Atomic $a) => $a instanceof TTemplateParam)) : []; $candidate_param_types = []; if ($extended_templates) { foreach ($extended_templates as $template) { if (!isset($input_class_storage->template_types[$template->param_name][$template->defining_class])) { continue; } $old_params_offset = (int) array_search($template->param_name, array_keys($input_class_storage->template_types), \true); $candidate_param_types[] = ($input_type_params[$old_params_offset] ?? Type::getMixed())->setProperties(['from_template_default' => \true]); } } $new_input_param = Type::combineUnionTypes($new_input_param, $candidate_param_types ? Type::combineUnionTypeArray($candidate_param_types, $codebase) : new Union([$extended_template], ['from_template_default' => \true])); } $new_input_param = \Psalm\Internal\Type\TemplateInferredTypeReplacer::replace($new_input_param, new \Psalm\Internal\Type\TemplateResult([], $replacement_templates), $codebase); $new_input_params[] = $new_input_param; } $input_type_params = $new_input_params; } } return $input_type_params; } } + array = array` * - and `array + string = array|string` * - and `array + array = array` * - and `array + array = array` * - and `array + array = array` * * @psalm-external-mutation-free * @psalm-suppress ImpurePropertyAssignment We're not actually mutating any external instance * @param non-empty-list $types * @param int $literal_limit any greater number of literal types than this * will be merged to a scalar */ public static function combine(array $types, ?Codebase $codebase = null, bool $overwrite_empty_array = \false, bool $allow_mixed_union = \true, int $literal_limit = 500) : Union { if (count($types) === 1) { return new Union([$types[0]]); } $combination = new \Psalm\Internal\Type\TypeCombination(); $from_docblock = \false; foreach ($types as $type) { $from_docblock = $from_docblock || $type->from_docblock; $result = self::scrapeTypeProperties($type, $combination, $codebase, $overwrite_empty_array, $allow_mixed_union, $literal_limit); if ($result) { if ($from_docblock) { return $result->setProperties(['from_docblock' => \true]); } return $result; } } if (count($combination->value_types) === 1 && !count($combination->objectlike_entries) && (!$combination->array_type_params || $overwrite_empty_array && $combination->array_type_params[1]->isNever()) && !$combination->builtin_type_params && !$combination->object_type_params && !$combination->named_object_types && !$combination->strings && !$combination->class_string_types && !$combination->ints && !$combination->floats) { if (isset($combination->value_types['false'])) { return Type::getFalse($from_docblock); } if (isset($combination->value_types['true'])) { return Type::getTrue($from_docblock); } } elseif (isset($combination->value_types['void'])) { unset($combination->value_types['void']); // if we're merging with another type, we cannot represent it in PHP $from_docblock = \true; if (!isset($combination->value_types['null'])) { $combination->value_types['null'] = new TNull($from_docblock); } } if (isset($combination->value_types['true']) && isset($combination->value_types['false'])) { unset($combination->value_types['true'], $combination->value_types['false']); $combination->value_types['bool'] = new TBool($from_docblock); } if ($combination->array_type_params && (isset($combination->named_object_types['Traversable']) || isset($combination->builtin_type_params['Traversable'])) && (isset($combination->builtin_type_params['Traversable']) || isset($combination->named_object_types['Traversable']) && $combination->named_object_types['Traversable']->from_docblock) && !$combination->extra_types) { $array_param_types = $combination->array_type_params; $traversable_param_types = $combination->builtin_type_params['Traversable'] ?? [Type::getMixed(), Type::getMixed()]; $combined_param_types = []; foreach ($array_param_types as $i => $array_param_type) { $combined_param_types[] = Type::combineUnionTypes($array_param_type, $traversable_param_types[$i]); } assert(count($combined_param_types) <= 2); $combination->value_types['iterable'] = new TIterable($combined_param_types); $combination->array_type_params = []; /** * @psalm-suppress PossiblyNullArrayAccess */ unset($combination->value_types['array'], $combination->named_object_types['Traversable'], $combination->builtin_type_params['Traversable']); } if ($combination->empty_mixed && $combination->non_empty_mixed) { $combination->value_types['mixed'] = new TMixed((bool) $combination->mixed_from_loop_isset); } $new_types = []; if ($combination->objectlike_entries) { $new_types = self::handleKeyedArrayEntries($combination, $overwrite_empty_array, $from_docblock); } if ($combination->array_type_params) { if (count($combination->array_type_params) !== 2) { throw new UnexpectedValueException('Unexpected number of parameters'); } $new_types[] = self::getArrayTypeFromGenericParams($codebase, $combination, $overwrite_empty_array, $allow_mixed_union, $type, $combination->array_type_params, $from_docblock); } if ($combination->extra_types) { /** @psalm-suppress PropertyTypeCoercion */ $combination->extra_types = self::combine(array_values($combination->extra_types), $codebase)->getAtomicTypes(); } foreach ($combination->builtin_type_params as $generic_type => $generic_type_params) { if ($generic_type === 'iterable') { assert(count($generic_type_params) <= 2); $new_types[] = new TIterable($generic_type_params, [], $from_docblock); } else { /** @psalm-suppress ArgumentTypeCoercion Caused by the PropertyTypeCoercion above */ $generic_object = new TGenericObject($generic_type, $generic_type_params, \false, \false, $combination->extra_types, $from_docblock); $new_types[] = $generic_object; if ($combination->named_object_types) { unset($combination->named_object_types[$generic_type]); } } } foreach ($combination->object_type_params as $generic_type => $generic_type_params) { $generic_type = substr($generic_type, 0, (int) strpos($generic_type, '<')); /** @psalm-suppress ArgumentTypeCoercion Caused by the PropertyTypeCoercion above */ $generic_object = new TGenericObject($generic_type, $generic_type_params, \false, $combination->object_static[$generic_type] ?? \false, $combination->extra_types, $from_docblock); $new_types[] = $generic_object; } if ($combination->class_string_types) { if ($combination->strings) { foreach ($combination->strings as $k => $string) { if ($string instanceof TLiteralClassString) { $combination->class_string_types[$string->value] = new TNamedObject($string->value); unset($combination->strings[$k]); } } } $has_non_specific_string = isset($combination->value_types['string']) && get_class($combination->value_types['string']) === TString::class; if (!$has_non_specific_string) { $object_type = self::combine(array_values($combination->class_string_types), $codebase); foreach ($object_type->getAtomicTypes() as $object_atomic_type) { if ($object_atomic_type instanceof TNamedObject) { $class_type = new TClassString($object_atomic_type->value, $object_atomic_type); } elseif ($object_atomic_type instanceof TObject) { $class_type = new TClassString(); } else { continue; } $new_types[] = $class_type->setFromDocblock($from_docblock); } } } if ($combination->strings) { $new_types = array_merge($new_types, array_values($combination->strings)); } if ($combination->ints) { $new_types = array_merge($new_types, array_values($combination->ints)); } if ($combination->floats) { $new_types = array_merge($new_types, array_values($combination->floats)); } if (isset($combination->value_types['string']) && isset($combination->value_types['int']) && isset($combination->value_types['bool']) && isset($combination->value_types['float'])) { unset($combination->value_types['string'], $combination->value_types['int'], $combination->value_types['bool'], $combination->value_types['float']); $combination->value_types['scalar'] = new TScalar(); } if ($combination->named_object_types !== null) { foreach ($combination->value_types as $key => $atomic_type) { if ($atomic_type instanceof TEnumCase && isset($combination->named_object_types[$atomic_type->value])) { unset($combination->value_types[$key]); } } $combination->value_types += $combination->named_object_types; } $has_never = isset($combination->value_types['never']); foreach ($combination->value_types as $type) { if ($type instanceof TMixed && $combination->mixed_from_loop_isset && (count($combination->value_types) > 1 + (int) $has_never || count($new_types) > (int) $has_never)) { continue; } if ($type instanceof TNever && (count($combination->value_types) > 1 || count($new_types))) { $has_never = \true; continue; } $new_types[] = $type->setFromDocblock($from_docblock); } if (!$new_types) { if (!$has_never) { throw new UnexpectedValueException('There should be types here'); } $union_type = Type::getNever($from_docblock); } else { $union_type = new Union($new_types); } $union_properties = []; if ($from_docblock) { $union_properties['from_docblock'] = \true; } if ($has_never) { $union_properties['explicit_never'] = \true; } if ($union_properties !== []) { return $union_type->setProperties($union_properties); } return $union_type; } /** * @psalm-suppress ComplexMethod Unavoidably complex method */ private static function scrapeTypeProperties(Atomic $type, \Psalm\Internal\Type\TypeCombination $combination, ?Codebase $codebase, bool $overwrite_empty_array, bool $allow_mixed_union, int $literal_limit) : ?Union { if ($type instanceof TList) { $type = $type->getKeyedArray(); } if ($type instanceof TMixed) { if ($type->from_loop_isset) { if ($combination->mixed_from_loop_isset === null) { $combination->mixed_from_loop_isset = \true; } else { return null; } } else { $combination->mixed_from_loop_isset = \false; } if ($type instanceof TNonEmptyMixed) { $combination->non_empty_mixed = \true; if ($combination->empty_mixed) { return null; } } elseif ($type instanceof TEmptyMixed) { $combination->empty_mixed = \true; if ($combination->non_empty_mixed) { return null; } } else { $combination->empty_mixed = \true; $combination->non_empty_mixed = \true; } if (!$allow_mixed_union) { return Type::getMixed($combination->mixed_from_loop_isset); } } // deal with false|bool => bool if (($type instanceof TFalse || $type instanceof TTrue) && isset($combination->value_types['bool'])) { return null; } if (get_class($type) === TBool::class && isset($combination->value_types['false'])) { unset($combination->value_types['false']); } if (get_class($type) === TBool::class && isset($combination->value_types['true'])) { unset($combination->value_types['true']); } if ($type instanceof TArray && isset($combination->builtin_type_params['iterable'])) { $type_key = 'iterable'; } elseif ($type instanceof TArray && $type->type_params[1]->isMixed() && isset($combination->value_types['iterable'])) { $type_key = 'iterable'; $combination->builtin_type_params['iterable'] = [Type::getMixed(), Type::getMixed()]; } elseif ($type instanceof TNamedObject && $type->value === 'Traversable' && (isset($combination->builtin_type_params['iterable']) || isset($combination->value_types['iterable']))) { $type_key = 'iterable'; if (!isset($combination->builtin_type_params['iterable'])) { $combination->builtin_type_params['iterable'] = [Type::getMixed(), Type::getMixed()]; } if (!$type instanceof TGenericObject) { $type = new TGenericObject($type->value, [Type::getMixed(), Type::getMixed()]); } } elseif ($type instanceof TNamedObject && ($type->value === 'Traversable' || $type->value === 'Generator')) { $type_key = $type->value; } else { $type_key = $type->getKey(); } if ($type instanceof TIterable && $combination->array_type_params && ($type->has_docblock_params || $combination->array_type_params[1]->isMixed())) { if (!isset($combination->builtin_type_params['iterable'])) { $combination->builtin_type_params['iterable'] = $combination->array_type_params; } else { foreach ($combination->array_type_params as $i => $array_type_param) { $iterable_type_param = $combination->builtin_type_params['iterable'][$i]; /** @psalm-suppress PropertyTypeCoercion */ $combination->builtin_type_params['iterable'][$i] = Type::combineUnionTypes($iterable_type_param, $array_type_param); } } $combination->array_type_params = []; } if ($type instanceof TIterable && (isset($combination->named_object_types['Traversable']) || isset($combination->builtin_type_params['Traversable']))) { if (!isset($combination->builtin_type_params['iterable'])) { $combination->builtin_type_params['iterable'] = $combination->builtin_type_params['Traversable'] ?? [Type::getMixed(), Type::getMixed()]; } elseif (isset($combination->builtin_type_params['Traversable'])) { foreach ($combination->builtin_type_params['Traversable'] as $i => $array_type_param) { $iterable_type_param = $combination->builtin_type_params['iterable'][$i]; /** @psalm-suppress PropertyTypeCoercion */ $combination->builtin_type_params['iterable'][$i] = Type::combineUnionTypes($iterable_type_param, $array_type_param); } } else { $combination->builtin_type_params['iterable'] = [Type::getMixed(), Type::getMixed()]; } /** @psalm-suppress PossiblyNullArrayAccess */ unset($combination->named_object_types['Traversable'], $combination->builtin_type_params['Traversable']); } if ($type instanceof TNamedObject || $type instanceof TTemplateParam || $type instanceof TIterable || $type instanceof TObjectWithProperties) { if ($type->extra_types) { $combination->extra_types = array_merge($combination->extra_types, $type->extra_types); } } if ($type instanceof TNamedObject) { if (array_key_exists($type->value, $combination->object_static)) { if ($combination->object_static[$type->value] && !$type->is_static) { $combination->object_static[$type->value] = \false; } } else { $combination->object_static[$type->value] = $type->is_static; } } if ($type instanceof TArray && $type_key === 'array') { if ($type instanceof TCallableArray && isset($combination->value_types['callable'])) { return null; } foreach ($type->type_params as $i => $type_param) { // See https://github.com/vimeo/psalm/pull/9439#issuecomment-1464563015 /** @psalm-suppress PropertyTypeCoercion */ $combination->array_type_params[$i] = Type::combineUnionTypes($combination->array_type_params[$i] ?? null, $type_param, $codebase, $overwrite_empty_array); } if ($type instanceof TNonEmptyArray) { if ($combination->array_counts !== null) { if ($type->count === null) { $combination->array_counts = null; } else { $combination->array_counts[$type->count] = \true; } } if ($combination->array_min_counts !== null) { if ($type->min_count === null) { $combination->array_min_counts = null; } else { $combination->array_min_counts[$type->min_count] = \true; } } $combination->array_sometimes_filled = \true; } else { $combination->array_always_filled = \false; } if (!$type->isEmptyArray()) { $combination->all_arrays_lists = \false; $combination->all_arrays_class_string_maps = \false; } if ($type instanceof TCallableArray) { if ($combination->all_arrays_callable !== \false) { $combination->all_arrays_callable = \true; } } else { $combination->all_arrays_callable = \false; } return null; } if ($type instanceof TClassStringMap) { foreach ([$type->getStandinKeyParam(), $type->value_param] as $i => $type_param) { // See https://github.com/vimeo/psalm/pull/9439#issuecomment-1464563015 /** @psalm-suppress PropertyTypeCoercion */ $combination->array_type_params[$i] = Type::combineUnionTypes($combination->array_type_params[$i] ?? null, $type_param, $codebase, $overwrite_empty_array); } $combination->array_always_filled = \false; if ($combination->all_arrays_class_string_maps !== \false) { $combination->all_arrays_class_string_maps = \true; $combination->class_string_map_names[$type->param_name] = \true; $combination->class_string_map_as_types[(string) $type->as_type] = $type->as_type; } return null; } if ($type instanceof TGenericObject && ($type->value === 'Traversable' || $type->value === 'Generator') || $type instanceof TIterable && $type->has_docblock_params || $type instanceof TArray && $type_key === 'iterable') { foreach ($type->type_params as $i => $type_param) { /** @psalm-suppress PropertyTypeCoercion */ $combination->builtin_type_params[$type_key][$i] = Type::combineUnionTypes($combination->builtin_type_params[$type_key][$i] ?? null, $type_param, $codebase, $overwrite_empty_array); } return null; } if ($type instanceof TGenericObject) { foreach ($type->type_params as $i => $type_param) { /** @psalm-suppress PropertyTypeCoercion */ $combination->object_type_params[$type_key][$i] = Type::combineUnionTypes($combination->object_type_params[$type_key][$i] ?? null, $type_param, $codebase, $overwrite_empty_array); } return null; } if ($type instanceof TKeyedArray) { if ($type instanceof TCallableKeyedArray && isset($combination->value_types['callable'])) { return null; } $existing_objectlike_entries = (bool) $combination->objectlike_entries; $missing_entries = $combination->objectlike_entries; $combination->objectlike_sealed = $combination->objectlike_sealed && $type->fallback_params === null; $has_defined_keys = \false; $class_strings = $type->class_strings ?? []; foreach ($type->properties as $candidate_property_name => $candidate_property_type) { $value_type = $combination->objectlike_entries[$candidate_property_name] ?? null; if (!$value_type) { $combination->objectlike_entries[$candidate_property_name] = $candidate_property_type->setPossiblyUndefined($existing_objectlike_entries || $candidate_property_type->possibly_undefined); } else { $combination->objectlike_entries[$candidate_property_name] = Type::combineUnionTypes($value_type, $candidate_property_type, $codebase, $overwrite_empty_array); if ((!$value_type->possibly_undefined || !$candidate_property_type->possibly_undefined) && $overwrite_empty_array) { $combination->objectlike_entries[$candidate_property_name] = $combination->objectlike_entries[$candidate_property_name]->setPossiblyUndefined(\false); } } if (!$candidate_property_type->possibly_undefined) { $has_defined_keys = \true; } if (($candidate_property_type->possibly_undefined || ($value_type->possibly_undefined ?? \true)) && $combination->fallbackKeyContains($candidate_property_name)) { $combination->objectlike_entries[$candidate_property_name] = Type::combineUnionTypes($combination->objectlike_entries[$candidate_property_name], $combination->objectlike_value_type, $codebase, $overwrite_empty_array); } unset($missing_entries[$candidate_property_name]); if (is_int($candidate_property_name)) { continue; } if (isset($combination->objectlike_class_string_keys[$candidate_property_name])) { $combination->objectlike_class_string_keys[$candidate_property_name] = $combination->objectlike_class_string_keys[$candidate_property_name] && ($class_strings[$candidate_property_name] ?? \false); } else { $combination->objectlike_class_string_keys[$candidate_property_name] = $class_strings[$candidate_property_name] ?? \false; } } if ($type->fallback_params) { $combination->objectlike_key_type = Type::combineUnionTypes($type->fallback_params[0], $combination->objectlike_key_type, $codebase, $overwrite_empty_array); $combination->objectlike_value_type = Type::combineUnionTypes($type->fallback_params[1], $combination->objectlike_value_type, $codebase, $overwrite_empty_array); } if (!$has_defined_keys) { $combination->array_always_filled = \false; } if ($combination->array_counts !== null) { $combination->array_counts[count($type->properties)] = \true; } if ($combination->array_min_counts !== null) { $min_prop_count = count(array_filter($type->properties, static fn(Union $p): bool => !$p->possibly_undefined)); $combination->array_min_counts[$min_prop_count] = \true; } foreach ($missing_entries as $k => $_) { $combination->objectlike_entries[$k] = $combination->objectlike_entries[$k]->setPossiblyUndefined(\true); } if ($combination->objectlike_value_type) { foreach ($missing_entries as $k => $_) { if (!$combination->fallbackKeyContains($k)) { continue; } $combination->objectlike_entries[$k] = Type::combineUnionTypes($combination->objectlike_entries[$k], $combination->objectlike_value_type, $codebase, $overwrite_empty_array); } } if (!$type->is_list) { $combination->all_arrays_lists = \false; } elseif ($combination->all_arrays_lists !== \false) { $combination->all_arrays_lists = \true; } if ($type instanceof TCallableKeyedArray) { if ($combination->all_arrays_callable !== \false) { $combination->all_arrays_callable = \true; } } else { $combination->all_arrays_callable = \false; } $combination->all_arrays_class_string_maps = \false; return null; } if ($type instanceof TObject) { if ($type instanceof TCallableObject && isset($combination->value_types['callable'])) { return null; } $combination->named_object_types = null; $combination->value_types[$type_key] = $type; return null; } if ($type instanceof TIterable) { $combination->value_types[$type_key] = $type; return null; } if ($type instanceof TTemplateParam) { if (isset($combination->value_types[$type_key])) { /** @var TTemplateParam */ $existing_template_type = $combination->value_types[$type_key]; if (!$existing_template_type->as->equals($type->as)) { $existing_template_type = $existing_template_type->replaceAs(Type::combineUnionTypes($type->as, $existing_template_type->as, $codebase)); $combination->value_types[$type_key] = $existing_template_type; } return null; } $combination->value_types[$type_key] = $type; return null; } if ($type instanceof TNamedObject) { if ($combination->named_object_types === null) { return null; } if (isset($combination->named_object_types[$type_key])) { return null; } if (!$codebase) { $combination->named_object_types[$type_key] = $type; return null; } if (!$codebase->classlikes->classOrInterfaceOrEnumExists($type_key)) { // write this to the main list $combination->value_types[$type_key] = $type; return null; } $is_class = $codebase->classExists($type_key); foreach ($combination->named_object_types as $key => $_) { if ($codebase->classExists($key)) { if ($codebase->classExtendsOrImplements($key, $type_key)) { unset($combination->named_object_types[$key]); continue; } if ($is_class) { if ($codebase->classExtends($type_key, $key)) { return null; } } } else { if ($codebase->interfaceExtends($key, $type_key)) { unset($combination->named_object_types[$key]); continue; } if ($is_class) { if ($codebase->classImplements($type_key, $key)) { return null; } } else { if ($codebase->interfaceExtends($type_key, $key)) { return null; } } } } $combination->named_object_types[$type_key] = $type; return null; } if ($type instanceof TScalar) { $combination->strings = null; $combination->ints = null; $combination->floats = null; unset($combination->value_types['string'], $combination->value_types['int'], $combination->value_types['bool'], $combination->value_types['true'], $combination->value_types['false'], $combination->value_types['float']); if (!isset($combination->value_types[$type_key]) || $combination->value_types[$type_key]->getId() === $type->getId()) { $combination->value_types[$type_key] = $type; } else { $combination->value_types[$type_key] = new TScalar(); } return null; } if ($type instanceof Scalar && isset($combination->value_types['scalar'])) { return null; } if ($type instanceof TArrayKey) { $combination->strings = null; $combination->ints = null; unset($combination->value_types['string'], $combination->value_types['int']); $combination->value_types[$type_key] = $type; return null; } if ($type instanceof TString) { self::scrapeStringProperties($type_key, $type, $combination, $codebase, $literal_limit); return null; } if ($type instanceof TInt) { self::scrapeIntProperties($type_key, $type, $combination, $literal_limit); return null; } if ($type instanceof TFloat) { if ($type instanceof TLiteralFloat) { if ($combination->floats !== null && count($combination->floats) < $literal_limit) { $combination->floats[$type_key] = $type; } else { $combination->floats = null; $combination->value_types['float'] = new TFloat(); } } else { $combination->floats = null; $combination->value_types['float'] = $type; } return null; } if ($type instanceof TCallable && $type_key === 'callable') { if (($combination->value_types['string'] ?? null) instanceof TCallableString) { unset($combination->value_types['string']); } elseif (!empty($combination->array_type_params) && $combination->all_arrays_callable) { $combination->array_type_params = []; } elseif (isset($combination->value_types['callable-object'])) { unset($combination->value_types['callable-object']); } } $combination->value_types[$type_key] = $type; return null; } private static function scrapeStringProperties(string $type_key, Atomic $type, \Psalm\Internal\Type\TypeCombination $combination, ?Codebase $codebase, int $literal_limit) : void { if ($type instanceof TCallableString && isset($combination->value_types['callable'])) { return; } if (isset($combination->value_types['array-key'])) { return; } if ($type instanceof TTemplateParamClass) { $combination->value_types[$type_key] = $type; } elseif ($type instanceof TClassString) { if (!$type->as_type) { $combination->class_string_types['object'] = new TObject(); } else { if (isset($combination->class_string_types[$type->as]) && $combination->class_string_types[$type->as] instanceof TNamedObject) { if ($combination->class_string_types[$type->as]->extra_types === []) { // do nothing, existing type is wider or the same } elseif ($type->as_type->extra_types === []) { $combination->class_string_types[$type->as] = $type->as_type; } else { // todo: figure out what to do with class-string|class-string $combination->class_string_types[$type->as] = $type->as_type; } } else { $combination->class_string_types[$type->as] = $type->as_type; } } } elseif ($type instanceof TLiteralString) { if ($combination->strings !== null && count($combination->strings) < $literal_limit) { $combination->strings[$type_key] = $type; } else { $shared_classlikes = $codebase ? self::getSharedTypes($combination, $codebase) : []; $combination->strings = null; if (isset($combination->value_types['string']) && $combination->value_types['string'] instanceof TNumericString && is_numeric($type->value)) { // do nothing } elseif (isset($combination->value_types['class-string']) && $type instanceof TLiteralClassString) { // do nothing } elseif ($type instanceof TLiteralClassString) { $type_classlikes = $codebase ? self::getClassLikes($codebase, $type->value) : []; $mutual = array_intersect_key($type_classlikes, $shared_classlikes); if ($mutual) { $first_class = array_keys($mutual)[0]; $combination->class_string_types[$first_class] = new TNamedObject($first_class); } else { $combination->class_string_types['object'] = new TObject(); } } elseif (isset($combination->value_types['string']) && $combination->value_types['string'] instanceof TNonspecificLiteralString) { // do nothing } elseif (isset($combination->value_types['string']) && $combination->value_types['string'] instanceof TLowercaseString && strtolower($type->value) === $type->value) { // do nothing } elseif (isset($combination->value_types['string']) && $combination->value_types['string'] instanceof TNonFalsyString && $type->value) { // do nothing } elseif (isset($combination->value_types['string']) && $combination->value_types['string'] instanceof TNonFalsyString && $type->value === '0') { $combination->value_types['string'] = new TNonEmptyString(); } elseif (isset($combination->value_types['string']) && $combination->value_types['string'] instanceof TNonEmptyString && $type->value !== '') { // do nothing } else { $combination->value_types['string'] = new TString(); } } } else { $type_key = 'string'; if (!isset($combination->value_types['string'])) { if ($combination->strings) { if ($type instanceof TNumericString) { $has_only_numeric_strings = \true; $has_only_non_empty_strings = \true; foreach ($combination->strings as $string_type) { if (!is_numeric($string_type->value)) { $has_only_numeric_strings = \false; } if ($string_type->value === '') { $has_only_non_empty_strings = \false; } } if ($has_only_numeric_strings) { $combination->value_types['string'] = $type; } elseif (count($combination->strings) === 1 && !$has_only_non_empty_strings) { $combination->value_types['string'] = $type; return; } elseif ($has_only_non_empty_strings) { $combination->value_types['string'] = new TNonEmptyString(); } else { $combination->value_types['string'] = new TString(); } } elseif ($type instanceof TLowercaseString) { $has_non_lowercase_string = \false; foreach ($combination->strings as $string_type) { if (strtolower($string_type->value) !== $string_type->value) { $has_non_lowercase_string = \true; break; } } if ($has_non_lowercase_string) { $combination->value_types['string'] = new TString(); } else { $combination->value_types['string'] = $type; } } elseif ($type instanceof TNonFalsyString) { $has_empty_string = \false; $has_falsy_string = \false; foreach ($combination->strings as $string_type) { if ($string_type->value === '') { $has_empty_string = \true; $has_falsy_string = \true; break; } if ($string_type->value === '0') { $has_falsy_string = \true; } } if ($has_empty_string) { $combination->value_types['string'] = new TString(); } elseif ($has_falsy_string) { $combination->value_types['string'] = new TNonEmptyString(); } else { $combination->value_types['string'] = $type; } } elseif ($type instanceof TNonEmptyString) { $has_empty_string = \false; foreach ($combination->strings as $string_type) { if ($string_type->value === '') { $has_empty_string = \true; break; } } $has_non_lowercase_string = \false; if ($type instanceof TNonEmptyLowercaseString) { foreach ($combination->strings as $string_type) { if (strtolower($string_type->value) !== $string_type->value) { $has_non_lowercase_string = \true; break; } } } if ($has_empty_string) { $combination->value_types['string'] = new TString(); } elseif ($has_non_lowercase_string && get_class($type) !== TNonEmptyString::class) { $combination->value_types['string'] = new TNonEmptyString(); } else { $combination->value_types['string'] = $type; } } elseif ($type instanceof TNonspecificLiteralString) { $combination->value_types['string'] = $type; } else { $combination->value_types[$type_key] = new TString(); } } else { $combination->value_types[$type_key] = $type; } } elseif (get_class($combination->value_types['string']) !== TString::class) { if (get_class($type) === TString::class) { $combination->value_types['string'] = $type; } elseif (get_class($combination->value_types['string']) !== get_class($type)) { if (get_class($type) === TNonEmptyString::class && get_class($combination->value_types['string']) === TNumericString::class) { $combination->value_types['string'] = $type; } elseif (get_class($type) === TNumericString::class && get_class($combination->value_types['string']) === TNonEmptyString::class) { // do nothing } elseif ((get_class($type) === TNonEmptyString::class || get_class($type) === TNumericString::class) && get_class($combination->value_types['string']) === TNonFalsyString::class) { $combination->value_types['string'] = $type; } elseif (get_class($type) === TNonFalsyString::class && (get_class($combination->value_types['string']) === TNonEmptyString::class || get_class($combination->value_types['string']) === TNumericString::class)) { // do nothing } elseif ((get_class($type) === TNonEmptyString::class || get_class($type) === TNonFalsyString::class) && get_class($combination->value_types['string']) === TNonEmptyLowercaseString::class) { $combination->value_types['string'] = new TNonEmptyString(); } elseif ((get_class($combination->value_types['string']) === TNonEmptyString::class || get_class($combination->value_types['string']) === TNonFalsyString::class) && get_class($type) === TNonEmptyLowercaseString::class) { $combination->value_types['string'] = new TNonEmptyString(); } elseif (get_class($type) === TLowercaseString::class && get_class($combination->value_types['string']) === TNonEmptyLowercaseString::class) { $combination->value_types['string'] = $type; } elseif (get_class($combination->value_types['string']) === TLowercaseString::class && get_class($type) === TNonEmptyLowercaseString::class) { //no-change } elseif (get_class($combination->value_types['string']) === TNonEmptyNonspecificLiteralString::class && $type instanceof TNonEmptyString) { $combination->value_types['string'] = new TNonEmptyString(); } elseif (get_class($type) === TNonEmptyNonspecificLiteralString::class && ($combination->value_types['string'] instanceof TNonEmptyString || $combination->value_types['string'] instanceof TNonspecificLiteralString)) { // do nothing } elseif (get_class($type) === TNonspecificLiteralString::class && get_class($combination->value_types['string']) === TNonEmptyNonspecificLiteralString::class) { $combination->value_types['string'] = $type; } else { $combination->value_types['string'] = new TString(); } } } $combination->strings = null; } } private static function scrapeIntProperties(string $type_key, Atomic $type, \Psalm\Internal\Type\TypeCombination $combination, int $literal_limit) : void { if (isset($combination->value_types['array-key'])) { return; } if ($type instanceof TLiteralInt) { if ($combination->ints !== null && count($combination->ints) < $literal_limit) { $combination->ints[$type_key] = $type; } else { $combination->ints[$type_key] = $type; $all_nonnegative = !array_filter($combination->ints, static fn($int): bool => $int->value < 0); if (isset($combination->value_types['int'])) { $current_int_type = $combination->value_types['int']; if ($current_int_type instanceof TIntRange) { $min_bound = $current_int_type->min_bound; $max_bound = $current_int_type->max_bound; foreach ($combination->ints as $int) { if (!$current_int_type->contains($int->value)) { $min_bound = TIntRange::getNewLowestBound($min_bound, $int->value); $max_bound = TIntRange::getNewHighestBound($max_bound, $int->value); } } if ($min_bound !== $current_int_type->min_bound || $max_bound !== $current_int_type->max_bound) { $combination->value_types['int'] = new TIntRange($min_bound, $max_bound); } } } $combination->ints = null; if (!isset($combination->value_types['int'])) { $combination->value_types['int'] = $all_nonnegative ? new TIntRange(0, null) : new TNonspecificLiteralInt(); } } } else { if ($type instanceof TNonspecificLiteralInt) { if ($combination->ints || !isset($combination->value_types['int'])) { $combination->value_types['int'] = $type; } elseif (isset($combination->value_types['int']) && get_class($combination->value_types['int']) !== get_class($type)) { $combination->value_types['int'] = new TInt(); } } elseif ($type instanceof TIntRange) { $min_bound = $type->min_bound; $max_bound = $type->max_bound; if ($combination->ints) { foreach ($combination->ints as $int) { if (!$type->contains($int->value)) { $min_bound = TIntRange::getNewLowestBound($min_bound, $int->value); $max_bound = TIntRange::getNewHighestBound($max_bound, $int->value); } } $type = new TIntRange($min_bound, $max_bound); $combination->value_types['int'] = $type; } elseif (!isset($combination->value_types['int'])) { $combination->value_types['int'] = $type; } else { $old_type = $combination->value_types['int']; if ($old_type instanceof TIntRange) { $min_bound = TIntRange::getNewLowestBound($old_type->min_bound, $min_bound); $max_bound = TIntRange::getNewHighestBound($old_type->max_bound, $max_bound); $type = new TIntRange($min_bound, $max_bound); } else { $type = new TInt(); } $combination->value_types['int'] = $type; } } else { $combination->value_types['int'] = $type; } $combination->ints = null; } } /** * @return array */ private static function getSharedTypes(\Psalm\Internal\Type\TypeCombination $combination, Codebase $codebase) : array { /** @var array|null */ $shared_classlikes = null; if ($combination->strings) { foreach ($combination->strings as $string_type) { $classlikes = self::getClassLikes($codebase, $string_type->value); if ($shared_classlikes === null) { $shared_classlikes = $classlikes; } elseif ($shared_classlikes) { $shared_classlikes = array_intersect_key($shared_classlikes, $classlikes); } } } if ($combination->class_string_types) { foreach ($combination->class_string_types as $value_type) { if ($value_type instanceof TNamedObject) { $classlikes = self::getClassLikes($codebase, $value_type->value); if ($shared_classlikes === null) { $shared_classlikes = $classlikes; } elseif ($shared_classlikes) { $shared_classlikes = array_intersect_key($shared_classlikes, $classlikes); } } } } return $shared_classlikes ?: []; } /** * @return array */ private static function getClassLikes(Codebase $codebase, string $fq_classlike_name) : array { try { $class_storage = $codebase->classlike_storage_provider->get($fq_classlike_name); } catch (InvalidArgumentException $e) { return []; } $classlikes = []; $classlikes[$fq_classlike_name] = \true; foreach ($class_storage->parent_classes as $parent_class) { $classlikes[$parent_class] = \true; } foreach ($class_storage->parent_interfaces as $parent_interface) { $classlikes[$parent_interface] = \true; } foreach ($class_storage->class_implements as $interface) { $classlikes[$interface] = \true; } return $classlikes; } /** * @return list */ private static function handleKeyedArrayEntries(\Psalm\Internal\Type\TypeCombination $combination, bool $overwrite_empty_array, bool $from_docblock) : array { $new_types = []; if ($combination->array_type_params && $combination->array_type_params[0]->allStringLiterals() && $combination->array_always_filled) { foreach ($combination->array_type_params[0]->getAtomicTypes() as $atomic_key_type) { if ($atomic_key_type instanceof TLiteralString) { $combination->objectlike_entries[$atomic_key_type->value] = $combination->array_type_params[1]; } } $combination->array_type_params = []; $combination->objectlike_sealed = \false; } if (!$combination->array_type_params || $combination->array_type_params[1]->isNever()) { if (!$overwrite_empty_array && $combination->array_type_params) { foreach ($combination->objectlike_entries as &$objectlike_entry) { $objectlike_entry = $objectlike_entry->setPossiblyUndefined(\true); } unset($objectlike_entry); } if ($combination->objectlike_value_type && $combination->objectlike_value_type->isMixed() && $combination->array_type_params && !$combination->array_type_params[1]->isNever()) { $combination->objectlike_entries = array_filter($combination->objectlike_entries, static fn(Union $type): bool => !$type->possibly_undefined); } if ($combination->objectlike_entries) { $fallback_key_type = null; if ($combination->objectlike_key_type) { $fallback_key_type = $combination->objectlike_key_type; } elseif ($combination->array_type_params && $combination->array_type_params[0]->isArrayKey()) { $fallback_key_type = $combination->array_type_params[0]; } $fallback_value_type = null; if ($combination->objectlike_value_type) { $fallback_value_type = $combination->objectlike_value_type; } elseif ($combination->array_type_params && $combination->array_type_params[1]->isMixed()) { $fallback_value_type = $combination->array_type_params[1]; } $sealed = $combination->objectlike_sealed && (!$combination->array_type_params || isset($combination->array_type_params[1]) && $combination->array_type_params[1]->isNever()); if ($combination->all_arrays_callable) { $objectlike = new TCallableKeyedArray($combination->objectlike_entries, null, $sealed || $fallback_key_type === null || $fallback_value_type === null ? null : [$fallback_key_type, $fallback_value_type], (bool) $combination->all_arrays_lists, $from_docblock); } else { $objectlike = new TKeyedArray($combination->objectlike_entries, array_filter($combination->objectlike_class_string_keys), $sealed || $fallback_key_type === null || $fallback_value_type === null ? null : [$fallback_key_type, $fallback_value_type], (bool) $combination->all_arrays_lists, $from_docblock); } $new_types[] = $objectlike; } else { $key_type = $combination->objectlike_key_type ?? Type::getArrayKey(); $value_type = $combination->objectlike_value_type ?? Type::getMixed(); if ($combination->array_always_filled) { $array_type = new TNonEmptyArray([$key_type, $value_type]); } else { $array_type = new TArray([$key_type, $value_type]); } $new_types[] = $array_type->setFromDocblock($from_docblock); } // if we're merging an empty array with an object-like, clobber empty array $combination->array_type_params = []; } return $new_types; } /** * @param array{Union, Union} $generic_type_params */ private static function getArrayTypeFromGenericParams(?Codebase $codebase, \Psalm\Internal\Type\TypeCombination $combination, bool $overwrite_empty_array, bool $allow_mixed_union, Atomic $type, array $generic_type_params, bool $from_docblock) : Atomic { if ($combination->objectlike_entries) { $objectlike_generic_type = null; $objectlike_keys = []; foreach ($combination->objectlike_entries as $property_name => $property_type) { $objectlike_generic_type = Type::combineUnionTypes($property_type, $objectlike_generic_type, $codebase, $overwrite_empty_array, \true, 500, \false); if (is_int($property_name)) { $objectlike_keys[$property_name] = new TLiteralInt($property_name, $from_docblock); } elseif ($type instanceof TKeyedArray && isset($type->class_strings[$property_name])) { $objectlike_keys[$property_name] = new TLiteralClassString($property_name, $from_docblock); } else { $objectlike_keys[$property_name] = Type::getAtomicStringFromLiteral($property_name, $from_docblock); } } if ($combination->objectlike_value_type) { $objectlike_generic_type = Type::combineUnionTypes($combination->objectlike_value_type, $objectlike_generic_type, $codebase, $overwrite_empty_array, \true, 500, \false); } $objectlike_key_type = new Union(array_values($objectlike_keys)); $objectlike_key_type = Type::combineUnionTypes($combination->objectlike_key_type, $objectlike_key_type, $codebase, $overwrite_empty_array); $generic_type_params[0] = Type::combineUnionTypes($generic_type_params[0], $objectlike_key_type, $codebase, $overwrite_empty_array, $allow_mixed_union); if (!$generic_type_params[1]->isMixed()) { $generic_type_params[1] = Type::combineUnionTypes($generic_type_params[1], $objectlike_generic_type, $codebase, $overwrite_empty_array, $allow_mixed_union); } } if ($combination->all_arrays_callable) { $array_type = new TCallableArray($generic_type_params); } elseif ($combination->array_always_filled || $combination->array_sometimes_filled && $overwrite_empty_array || $combination->objectlike_entries && $combination->objectlike_sealed && ($combination->array_min_counts[0] ?? \false) !== \true && $overwrite_empty_array) { if ($combination->all_arrays_lists) { if ($combination->objectlike_entries && $combination->objectlike_sealed && isset($combination->array_type_params[1])) { $array_type = new TKeyedArray([$generic_type_params[1]], null, [Type::getInt(), $combination->array_type_params[1]], \true); } elseif ($combination->array_counts && count($combination->array_counts) === 1) { $cnt = array_keys($combination->array_counts)[0]; $properties = []; for ($x = 0; $x < $cnt; $x++) { $properties[] = $generic_type_params[1]; } assert($properties !== []); $array_type = new TKeyedArray($properties, null, null, \true); } else { $cnt = $combination->array_min_counts ? min(array_keys($combination->array_min_counts)) : 0; $properties = []; for ($x = 0; $x < $cnt; $x++) { $properties[] = $generic_type_params[1]; } if (!$properties) { $properties[] = $generic_type_params[1]->setPossiblyUndefined(\true); } $array_type = new TKeyedArray($properties, null, [Type::getListKey(), $generic_type_params[1]], \true); } } else { /** @psalm-suppress ArgumentTypeCoercion */ $array_type = new TNonEmptyArray($generic_type_params, $combination->array_min_counts ? min(array_keys($combination->array_min_counts)) : null); } } else { if ($combination->all_arrays_class_string_maps && count($combination->class_string_map_as_types) === 1 && count($combination->class_string_map_names) === 1) { $array_type = new TClassStringMap(array_keys($combination->class_string_map_names)[0], array_values($combination->class_string_map_as_types)[0], $generic_type_params[1]); } elseif ($combination->all_arrays_lists) { $array_type = Type::getListAtomic($generic_type_params[1]); } else { $array_type = new TArray($generic_type_params); } } return $array_type->setFromDocblock($from_docblock); } } */ public array $value_types = []; /** @var array|null */ public ?array $named_object_types = []; /** @var list */ public array $array_type_params = []; /** @var array> */ public array $builtin_type_params = []; /** @var array> */ public array $object_type_params = []; /** @var array */ public array $object_static = []; /** @var array|null */ public ?array $array_counts = []; /** @var array|null */ public ?array $array_min_counts = []; public bool $array_sometimes_filled = \false; public bool $array_always_filled = \true; /** @var array */ public array $objectlike_entries = []; /** @var array */ public array $objectlike_class_string_keys = []; public bool $objectlike_sealed = \true; public ?Union $objectlike_key_type = null; public ?Union $objectlike_value_type = null; public bool $empty_mixed = \false; public bool $non_empty_mixed = \false; public ?bool $mixed_from_loop_isset = null; /** @var array|null */ public ?array $strings = []; /** @var array|null */ public ?array $ints = []; /** @var array|null */ public ?array $floats = []; /** @var array|null */ public ?array $class_string_types = []; /** * @var array */ public array $extra_types = []; public ?bool $all_arrays_lists = null; public ?bool $all_arrays_callable = null; public ?bool $all_arrays_class_string_maps = null; /** @var array */ public array $class_string_map_names = []; /** @var array */ public array $class_string_map_as_types = []; /** * @psalm-assert-if-true !null $this->objectlike_key_type * @psalm-assert-if-true !null $this->objectlike_value_type * @param array-key $k */ public function fallbackKeyContains($k) : bool { if (!$this->objectlike_key_type) { return \false; } foreach ($this->objectlike_key_type->getAtomicTypes() as $t) { if ($t instanceof TArrayKey) { return \true; } elseif ($t instanceof TLiteralInt || $t instanceof TLiteralString) { if ($t->value === $k) { return \true; } } elseif ($t instanceof TIntRange) { if (is_int($k) && $t->contains($k)) { return \true; } } elseif ($t instanceof TString && is_string($k)) { return \true; } elseif ($t instanceof TInt && is_int($k)) { return \true; } } return \false; } } $type_tokens * @param array> $template_type_map * @param array $type_aliases */ public static function parseTokens(array $type_tokens, ?int $analysis_php_version_id = null, array $template_type_map = [], array $type_aliases = [], bool $from_docblock = \false) : Union { if (count($type_tokens) === 1) { $only_token = $type_tokens[0]; // Note: valid identifiers can include class names or $this if (!preg_match('@^(\\$this|\\\\?[a-zA-Z_\\x7f-\\xff][\\\\\\-0-9a-zA-Z_\\x7f-\\xff]*)$@', $only_token[0])) { if (!is_numeric($only_token[0]) && strpos($only_token[0], '\'') !== \false && strpos($only_token[0], '"') !== \false) { throw new TypeParseTreeException("Invalid type '{$only_token[0]}'"); } } else { $only_token[0] = \Psalm\Internal\Type\TypeTokenizer::fixScalarTerms($only_token[0], $analysis_php_version_id); $atomic = Atomic::create($only_token[0], $analysis_php_version_id, $template_type_map, $type_aliases, 0, strlen($only_token[0]), isset($only_token[2]) && $only_token[2] !== $only_token[0] ? $only_token[2] : null, $from_docblock); return new Union([$atomic], ['from_docblock' => $from_docblock]); } } $parse_tree = (new \Psalm\Internal\Type\ParseTreeCreator($type_tokens))->create(); $codebase = ProjectAnalyzer::getInstance()->getCodebase(); $parsed_type = self::getTypeFromTree($parse_tree, $codebase, $analysis_php_version_id, $template_type_map, $type_aliases, $from_docblock); if (!$parsed_type instanceof Union) { $parsed_type = new Union([$parsed_type], ['from_docblock' => $from_docblock]); } return $parsed_type; } /** * @param array> $template_type_map * @param array $type_aliases * @return Atomic|Union */ public static function getTypeFromTree(\Psalm\Internal\Type\ParseTree $parse_tree, Codebase $codebase, ?int $analysis_php_version_id = null, array $template_type_map = [], array $type_aliases = [], bool $from_docblock = \false) : TypeNode { if ($parse_tree instanceof GenericTree) { return self::getTypeFromGenericTree($parse_tree, $codebase, $template_type_map, $type_aliases, $from_docblock); } if ($parse_tree instanceof UnionTree) { return self::getTypeFromUnionTree($parse_tree, $codebase, $template_type_map, $type_aliases, $from_docblock); } if ($parse_tree instanceof IntersectionTree) { return self::getTypeFromIntersectionTree($parse_tree, $codebase, $template_type_map, $type_aliases, $from_docblock); } if ($parse_tree instanceof KeyedArrayTree) { return self::getTypeFromKeyedArrayTree($parse_tree, $codebase, $template_type_map, $type_aliases, $from_docblock); } if ($parse_tree instanceof CallableWithReturnTypeTree) { $callable_type = self::getTypeFromTree($parse_tree->children[0], $codebase, null, $template_type_map, $type_aliases, $from_docblock); if (!$callable_type instanceof TCallable && !$callable_type instanceof TClosure) { throw new InvalidArgumentException('Parsing callable tree node should return TCallable'); } if (!isset($parse_tree->children[1])) { throw new TypeParseTreeException('Invalid return type'); } $return_type = self::getTypeFromTree($parse_tree->children[1], $codebase, null, $template_type_map, $type_aliases, $from_docblock); $callable_type->return_type = $return_type instanceof Union ? $return_type : new Union([$return_type], ['from_docblock' => $from_docblock]); return $callable_type; } if ($parse_tree instanceof CallableTree) { return self::getTypeFromCallableTree($parse_tree, $codebase, $template_type_map, $type_aliases, $from_docblock); } if ($parse_tree instanceof EncapsulationTree) { if (!$parse_tree->terminated) { throw new TypeParseTreeException('Unterminated parentheses'); } if (!isset($parse_tree->children[0])) { throw new TypeParseTreeException('Empty parentheses'); } return self::getTypeFromTree($parse_tree->children[0], $codebase, null, $template_type_map, $type_aliases, $from_docblock); } if ($parse_tree instanceof NullableTree) { if (!isset($parse_tree->children[0])) { throw new TypeParseTreeException('Misplaced question mark'); } $non_nullable_type = self::getTypeFromTree($parse_tree->children[0], $codebase, null, $template_type_map, $type_aliases, $from_docblock); if ($non_nullable_type instanceof Union) { $non_nullable_type = $non_nullable_type->getBuilder()->addType(new TNull($from_docblock))->freeze(); return $non_nullable_type; } return \Psalm\Internal\Type\TypeCombiner::combine([new TNull($from_docblock), $non_nullable_type]); } if ($parse_tree instanceof MethodTree || $parse_tree instanceof MethodWithReturnTypeTree) { throw new TypeParseTreeException('Misplaced brackets'); } if ($parse_tree instanceof IndexedAccessTree) { return self::getTypeFromIndexAccessTree($parse_tree, $template_type_map, $from_docblock); } if ($parse_tree instanceof TemplateAsTree) { $result = new TTemplateParam($parse_tree->param_name, new Union([new TNamedObject($parse_tree->as)]), 'class-string-map', [], $from_docblock); return $result; } if ($parse_tree instanceof ConditionalTree) { $template_param_name = $parse_tree->condition->param_name; if (!isset($template_type_map[$template_param_name])) { throw new TypeParseTreeException('Unrecognized template \'' . $template_param_name . '\''); } if (count($parse_tree->children) !== 2) { throw new TypeParseTreeException('Invalid conditional'); } $first_class = array_keys($template_type_map[$template_param_name])[0]; $conditional_type = self::getTypeFromTree($parse_tree->condition->children[0], $codebase, null, $template_type_map, $type_aliases, $from_docblock); $if_type = self::getTypeFromTree($parse_tree->children[0], $codebase, null, $template_type_map, $type_aliases, $from_docblock); $else_type = self::getTypeFromTree($parse_tree->children[1], $codebase, null, $template_type_map, $type_aliases, $from_docblock); if ($conditional_type instanceof Atomic) { $conditional_type = new Union([$conditional_type], ['from_docblock' => $from_docblock]); } if ($if_type instanceof Atomic) { $if_type = new Union([$if_type], ['from_docblock' => $from_docblock]); } if ($else_type instanceof Atomic) { $else_type = new Union([$else_type], ['from_docblock' => $from_docblock]); } return new TConditional($template_param_name, $first_class, $template_type_map[$template_param_name][$first_class], $conditional_type, $if_type, $else_type, $from_docblock); } if (!$parse_tree instanceof Value) { throw new InvalidArgumentException('Unrecognised parse tree type ' . get_class($parse_tree)); } if ($parse_tree->value[0] === '"' || $parse_tree->value[0] === '\'') { return Type::getAtomicStringFromLiteral(substr($parse_tree->value, 1, -1), $from_docblock); } if (strpos($parse_tree->value, '::')) { [$fq_classlike_name, $const_name] = explode('::', $parse_tree->value); if (isset($template_type_map[$fq_classlike_name]) && $const_name === 'class') { $first_class = array_keys($template_type_map[$fq_classlike_name])[0]; return self::getGenericParamClass($fq_classlike_name, $template_type_map[$fq_classlike_name][$first_class], $first_class, $from_docblock); } if ($const_name === 'class') { return new TLiteralClassString($fq_classlike_name, \false, $from_docblock); } return new TClassConstant($fq_classlike_name, $const_name, $from_docblock); } if (preg_match('/^\\-?(0|[1-9][0-9]*)(\\.[0-9]{1,})$/', $parse_tree->value)) { return new TLiteralFloat((float) $parse_tree->value, $from_docblock); } if (preg_match('/^\\-?(0|[1-9]([0-9_]*[0-9])?)$/', $parse_tree->value)) { return new TLiteralInt((int) strtr($parse_tree->value, ['_' => '']), $from_docblock); } if (!preg_match('@^(\\$this|\\\\?[a-zA-Z_\\x7f-\\xff][\\\\\\-0-9a-zA-Z_\\x7f-\\xff]*)$@', $parse_tree->value)) { throw new TypeParseTreeException('Invalid type \'' . $parse_tree->value . '\''); } $atomic_type_string = \Psalm\Internal\Type\TypeTokenizer::fixScalarTerms($parse_tree->value, $analysis_php_version_id); return Atomic::create($atomic_type_string, $analysis_php_version_id, $template_type_map, $type_aliases, $parse_tree->offset_start, $parse_tree->offset_end, $parse_tree->text, $from_docblock); } private static function getGenericParamClass(string $param_name, Union &$as, string $defining_class, bool $from_docblock = \false) : TTemplateParamClass { if ($as->hasMixed()) { return new TTemplateParamClass($param_name, 'object', null, $defining_class, $from_docblock); } foreach ($as->getAtomicTypes() as $t) { if ($t instanceof TObject) { return new TTemplateParamClass($param_name, 'object', null, $defining_class, $from_docblock); } if ($t instanceof TIterable) { $traversable = new TGenericObject('Traversable', $t->type_params, \false, \false, [], $from_docblock); $as = $as->getBuilder()->substitute(new Union([$t]), new Union([$traversable]))->freeze(); return new TTemplateParamClass($param_name, $traversable->value, $traversable, $defining_class, $from_docblock); } if ($t instanceof TTemplateParam) { $t_atomic_type = count($t->as->getAtomicTypes()) === 1 ? $t->as->getSingleAtomic() : null; if (!$t_atomic_type instanceof TNamedObject) { $t_atomic_type = null; } return new TTemplateParamClass($t->param_name, $t_atomic_type->value ?? 'object', $t_atomic_type, $t->defining_class, $from_docblock); } if (!$t instanceof TNamedObject) { throw new TypeParseTreeException('Invalid templated classname \'' . $t->getId() . '\''); } return new TTemplateParamClass($param_name, $t->value, $t, $defining_class, $from_docblock); } throw new LogicException('Should never get here'); } /** * @param non-empty-list $potential_ints * @return non-empty-list */ public static function getComputedIntsFromMask(array $potential_ints, bool $from_docblock = \false) : array { /** @var list */ $potential_values = []; foreach ($potential_ints as $ith) { $new_values = []; $new_values[] = $ith; if ($ith !== 0) { foreach ($potential_values as $potential_value) { $new_values[] = $ith | $potential_value; } } $potential_values = [...$new_values, ...$potential_values]; } array_unshift($potential_values, 0); $potential_values = array_unique($potential_values); return array_map(static fn($int): TLiteralInt => new TLiteralInt($int, $from_docblock), array_values($potential_values)); } /** * @param array> $template_type_map * @param array $type_aliases * @return Atomic|Union * @throws TypeParseTreeException * @psalm-suppress ComplexMethod to be refactored */ private static function getTypeFromGenericTree(GenericTree $parse_tree, Codebase $codebase, array $template_type_map, array $type_aliases, bool $from_docblock = \false) { $generic_type = $parse_tree->value; $generic_params = []; foreach ($parse_tree->children as $i => $child_tree) { $tree_type = self::getTypeFromTree($child_tree, $codebase, null, $template_type_map, $type_aliases, $from_docblock); if ($generic_type === 'class-string-map' && $i === 0) { if ($tree_type instanceof TTemplateParam) { $template_type_map[$tree_type->param_name] = ['class-string-map' => $tree_type->as]; } elseif ($tree_type instanceof TNamedObject) { $template_type_map[$tree_type->value] = ['class-string-map' => Type::getObject()]; } } $generic_params[] = $tree_type instanceof Union ? $tree_type : new Union([$tree_type], ['from_docblock' => $from_docblock]); } $generic_type_value = \Psalm\Internal\Type\TypeTokenizer::fixScalarTerms($generic_type); if (($generic_type_value === 'array' || $generic_type_value === 'non-empty-array' || $generic_type_value === 'associative-array') && count($generic_params) === 1) { array_unshift($generic_params, new Union([new TArrayKey($from_docblock)])); } elseif (count($generic_params) === 1 && in_array($generic_type_value, ['iterable', 'Traversable', 'Iterator', 'IteratorAggregate', 'arraylike-object'], \true)) { array_unshift($generic_params, new Union([new TMixed(\false, $from_docblock)])); } elseif ($generic_type_value === 'Generator') { if (count($generic_params) === 1) { array_unshift($generic_params, new Union([new TMixed(\false, $from_docblock)])); } for ($i = 0, $l = 4 - count($generic_params); $i < $l; ++$i) { $generic_params[] = new Union([new TMixed(\false, $from_docblock)]); } } if (!$generic_params) { throw new TypeParseTreeException('No generic params provided for type'); } if ($generic_type_value === 'array' || $generic_type_value === 'associative-array' || $generic_type_value === 'non-empty-array') { if ($generic_type_value !== 'non-empty-array') { $generic_type_value = 'array'; } if ($generic_params[0]->isMixed()) { $generic_params[0] = Type::getArrayKey($from_docblock); } if (count($generic_params) !== 2) { throw new TypeParseTreeException('Too many template parameters for ' . $generic_type_value); } if ($type_aliases !== []) { $intersection_types = self::resolveTypeAliases($codebase, $generic_params[0]->getAtomicTypes()); if ($intersection_types !== []) { $generic_params[0] = $generic_params[0]->setTypes($intersection_types); } } foreach ($generic_params[0]->getAtomicTypes() as $key => $atomic_type) { if ($atomic_type instanceof TLiteralString && ($string_to_int = ArrayAnalyzer::getLiteralArrayKeyInt($atomic_type->value)) !== \false) { $builder = $generic_params[0]->getBuilder(); $builder->removeType($key); $generic_params[0] = $builder->addType(new TLiteralInt($string_to_int, $from_docblock))->freeze(); continue; } if ($atomic_type instanceof TInt || $atomic_type instanceof TString || $atomic_type instanceof TArrayKey || $atomic_type instanceof TClassConstant || $atomic_type instanceof TMixed || $atomic_type instanceof TNever || $atomic_type instanceof TTemplateParam || $atomic_type instanceof TTemplateIndexedAccess || $atomic_type instanceof TTemplateValueOf || $atomic_type instanceof TTemplateKeyOf || $atomic_type instanceof TTemplateParamClass || $atomic_type instanceof TTypeAlias || $atomic_type instanceof TValueOf || $atomic_type instanceof TConditional || $atomic_type instanceof TKeyOf || !$from_docblock) { continue; } if ($codebase->register_stub_files || $codebase->register_autoload_files) { $builder = $generic_params[0]->getBuilder(); $builder->removeType($key); if (count($generic_params[0]->getAtomicTypes()) <= 1) { $builder = $builder->addType(new TArrayKey($from_docblock)); } $generic_params[0] = $builder->freeze(); continue; } throw new TypeParseTreeException('Invalid array key type ' . $atomic_type->getKey()); } return $generic_type_value === 'array' ? new TArray($generic_params, $from_docblock) : new TNonEmptyArray($generic_params, null, null, 'non-empty-array', $from_docblock); } if ($generic_type_value === 'arraylike-object') { $array_acccess = new TGenericObject('ArrayAccess', $generic_params, \false, \false, [], $from_docblock); $countable = new TNamedObject('Countable', \false, \false, [], $from_docblock); return new TGenericObject('Traversable', $generic_params, \false, \false, [$array_acccess->getKey() => $array_acccess, $countable->getKey() => $countable], $from_docblock); } if ($generic_type_value === 'iterable') { if (count($generic_params) > 2) { throw new TypeParseTreeException('Too many template parameters for iterable'); } return new TIterable($generic_params, [], $from_docblock); } if ($generic_type_value === 'list') { if (count($generic_params) > 1) { throw new TypeParseTreeException('Too many template parameters for list'); } return Type::getListAtomic($generic_params[0], $from_docblock); } if ($generic_type_value === 'non-empty-list') { return Type::getNonEmptyListAtomic($generic_params[0], $from_docblock); } if ($generic_type_value === 'class-string' || $generic_type_value === 'interface-string' || $generic_type_value === 'enum-string') { $class_name = $generic_params[0]->getId(\false); if (isset($template_type_map[$class_name])) { $first_class = array_keys($template_type_map[$class_name])[0]; return self::getGenericParamClass($class_name, $template_type_map[$class_name][$first_class], $first_class, $from_docblock); } $types = []; foreach ($generic_params[0]->getAtomicTypes() as $type) { if ($type instanceof TNamedObject) { $types[] = new TClassString($type->value, $type, \false, \false, \false, $from_docblock); continue; } if ($type instanceof TCallableObject) { $types[] = new TUnknownClassString($type, \false, $from_docblock); continue; } throw new TypeParseTreeException('class-string param can only target to named or callable objects'); } assert($types !== [], 'Since `Union` cannot be empty and all non-supported atomics lead to thrown exception,' . ' we can safely assert that the types array is non-empty.'); return new Union($types); } if ($generic_type_value === 'class-string-map') { if (count($generic_params) !== 2) { throw new TypeParseTreeException('There should only be two params for class-string-map, ' . count($generic_params) . ' provided'); } $template_marker_parts = array_values($generic_params[0]->getAtomicTypes()); $template_marker = $template_marker_parts[0]; $template_as_type = null; if ($template_marker instanceof TNamedObject) { $template_param_name = $template_marker->value; } elseif ($template_marker instanceof TTemplateParam) { $template_param_name = $template_marker->param_name; $template_as_type = $template_marker->as->getSingleAtomic(); if (!$template_as_type instanceof TNamedObject) { throw new TypeParseTreeException('Unrecognised as type'); } } else { throw new TypeParseTreeException('Unrecognised class-string-map templated param'); } return new TClassStringMap($template_param_name, $template_as_type, $generic_params[1], $from_docblock); } if (in_array($generic_type_value, TPropertiesOf::tokenNames())) { if (count($generic_params) !== 1) { throw new TypeParseTreeException($generic_type_value . ' requires exactly one parameter.'); } $param_name = (string) $generic_params[0]; if (isset($template_type_map[$param_name]) && ($defining_class = array_key_first($template_type_map[$param_name])) !== null) { $template_param = $generic_params[0]->getSingleAtomic(); if (!$template_param instanceof TTemplateParam) { throw new TypeParseTreeException($generic_type_value . '<' . $param_name . '> must be a TTemplateParam.'); } if ($template_param->getIntersectionTypes()) { throw new TypeParseTreeException($generic_type_value . '<' . $param_name . '> must be a TTemplateParam' . ' with no intersection types.'); } return new TTemplatePropertiesOf($param_name, $defining_class, $template_param, TPropertiesOf::filterForTokenName($generic_type_value), $from_docblock); } $param_union_types = array_values($generic_params[0]->getAtomicTypes()); if (count($param_union_types) > 1) { throw new TypeParseTreeException('Union types are not allowed in ' . $generic_type_value . ' param'); } if (!$param_union_types[0] instanceof TNamedObject) { throw new TypeParseTreeException('Param should be a named object in ' . $generic_type_value); } return new TPropertiesOf($param_union_types[0], TPropertiesOf::filterForTokenName($generic_type_value), $from_docblock); } if ($generic_type_value === 'key-of') { $param_name = $generic_params[0]->getId(\false); if (isset($template_type_map[$param_name]) && ($defining_class = array_key_first($template_type_map[$param_name])) !== null) { return new TTemplateKeyOf($param_name, $defining_class, $generic_params[0], $from_docblock); } if (!TKeyOf::isViableTemplateType($generic_params[0])) { throw new TypeParseTreeException('Untemplated key-of param ' . $param_name . ' should be an array'); } return new TKeyOf($generic_params[0], $from_docblock); } if ($generic_type_value === 'value-of') { $param_name = $generic_params[0]->getId(\false); if (isset($template_type_map[$param_name]) && ($defining_class = array_key_first($template_type_map[$param_name])) !== null) { return new TTemplateValueOf($param_name, $defining_class, $generic_params[0], $from_docblock); } if (!TValueOf::isViableTemplateType($generic_params[0])) { throw new TypeParseTreeException('Untemplated value-of param ' . $param_name . ' should be an array'); } return new TValueOf($generic_params[0]); } if ($generic_type_value === 'int-mask') { $atomic_types = []; foreach ($generic_params as $generic_param) { if (!$generic_param->isSingle()) { throw new TypeParseTreeException('int-mask types must all be non-union'); } $generic_param_atomics = $generic_param->getAtomicTypes(); $atomic_type = reset($generic_param_atomics); if ($atomic_type instanceof TNamedObject) { if (defined($atomic_type->value)) { /** @var mixed */ $constant_value = constant($atomic_type->value); if (!is_int($constant_value)) { throw new TypeParseTreeException('int-mask types must all be integer values'); } $atomic_type = new TLiteralInt($constant_value, $from_docblock); } else { throw new TypeParseTreeException('int-mask types must all be integer values'); } } if (!$atomic_type instanceof TLiteralInt && !($atomic_type instanceof TClassConstant && strpos($atomic_type->const_name, '*') === \false)) { throw new TypeParseTreeException('int-mask types must all be integer values or scalar class constants'); } $atomic_types[] = $atomic_type; } $potential_ints = []; foreach ($atomic_types as $atomic_type) { if (!$atomic_type instanceof TLiteralInt) { return new TIntMask($atomic_types, $from_docblock); } $potential_ints[] = $atomic_type->value; } return new Union(self::getComputedIntsFromMask($potential_ints, $from_docblock)); } if ($generic_type_value === 'int-mask-of') { $param_union_types = array_values($generic_params[0]->getAtomicTypes()); if (count($param_union_types) > 1) { throw new TypeParseTreeException('Union types are not allowed in value-of type'); } $param_type = $param_union_types[0]; if (!$param_type instanceof TClassConstant && !$param_type instanceof TValueOf && !$param_type instanceof TKeyOf) { throw new TypeParseTreeException('Invalid reference passed to int-mask-of'); } elseif ($param_type instanceof TClassConstant && strpos($param_type->const_name, '*') === \false) { throw new TypeParseTreeException('Class constant passed to int-mask-of must be a wildcard type'); } return new TIntMaskOf($param_type, $from_docblock); } if ($generic_type_value === 'int') { if (count($generic_params) !== 2) { throw new TypeParseTreeException('int range must have 2 params'); } assert(count($parse_tree->children) === 2); $get_int_range_bound = static function (\Psalm\Internal\Type\ParseTree $parse_tree, Union $generic_param, string $bound_name) : ?int { if (!$parse_tree instanceof Value || count($generic_param->getAtomicTypes()) > 1 || !$generic_param->getSingleAtomic() instanceof TLiteralInt && $parse_tree->value !== $bound_name && $parse_tree->text !== $bound_name) { throw new TypeParseTreeException("Invalid type \"{$generic_param->getId()}\" as int {$bound_name} boundary"); } $generic_param_atomic = $generic_param->getSingleAtomic(); return $generic_param_atomic instanceof TLiteralInt ? $generic_param_atomic->value : null; }; $min_bound = $get_int_range_bound($parse_tree->children[0], $generic_params[0], TIntRange::BOUND_MIN); $max_bound = $get_int_range_bound($parse_tree->children[1], $generic_params[1], TIntRange::BOUND_MAX); if ($min_bound === null && $max_bound === null) { return new TInt($from_docblock); } if (is_int($min_bound) && is_int($max_bound) && $min_bound > $max_bound) { throw new TypeParseTreeException("Min bound can't be greater than max bound, int<{$min_bound}, {$max_bound}> given"); } if (is_int($min_bound) && is_int($max_bound) && $min_bound > $max_bound) { throw new TypeParseTreeException("Min bound can't be greater than max bound, int<{$min_bound}, {$max_bound}> given"); } return new TIntRange($min_bound, $max_bound, $from_docblock); } if (isset(\Psalm\Internal\Type\TypeTokenizer::PSALM_RESERVED_WORDS[$generic_type_value]) && $generic_type_value !== 'self' && $generic_type_value !== 'static') { throw new TypeParseTreeException('Cannot create generic object with reserved word'); } return new TGenericObject($generic_type_value, $generic_params, \false, \false, [], $from_docblock); } /** * @param array> $template_type_map * @param array $type_aliases * @throws TypeParseTreeException */ private static function getTypeFromUnionTree(UnionTree $parse_tree, Codebase $codebase, array $template_type_map, array $type_aliases, bool $from_docblock) : Union { $has_null = \false; $atomic_types = []; foreach ($parse_tree->children as $child_tree) { if ($child_tree instanceof NullableTree) { if (!isset($child_tree->children[0])) { throw new TypeParseTreeException('Invalid ? character'); } $atomic_type = self::getTypeFromTree($child_tree->children[0], $codebase, null, $template_type_map, $type_aliases, $from_docblock); $has_null = \true; } else { $atomic_type = self::getTypeFromTree($child_tree, $codebase, null, $template_type_map, $type_aliases, $from_docblock); } if ($atomic_type instanceof Union) { foreach ($atomic_type->getAtomicTypes() as $type) { $atomic_types[] = $type; } continue; } $atomic_types[] = $atomic_type; } if ($has_null) { $atomic_types[] = new TNull($from_docblock); } if (!$atomic_types) { throw new TypeParseTreeException('No atomic types found'); } return \Psalm\Internal\Type\TypeCombiner::combine($atomic_types); } /** * @param array> $template_type_map * @param array $type_aliases * @throws TypeParseTreeException */ private static function getTypeFromIntersectionTree(IntersectionTree $parse_tree, Codebase $codebase, array $template_type_map, array $type_aliases, bool $from_docblock) : Atomic { $intersection_types = []; foreach ($parse_tree->children as $name => $child_tree) { $atomic_type = self::getTypeFromTree($child_tree, $codebase, null, $template_type_map, $type_aliases, $from_docblock); if (!$atomic_type instanceof Atomic) { throw new TypeParseTreeException('Intersection types cannot contain unions'); } $intersection_types[$name] = $atomic_type; } if ($intersection_types === []) { return new TMixed(); } $first_type = reset($intersection_types); $last_type = end($intersection_types); $onlyTKeyedArray = $first_type instanceof TKeyedArray || $last_type instanceof TKeyedArray; foreach ($intersection_types as $intersection_type) { if (!$intersection_type instanceof TKeyedArray && ($intersection_type !== $first_type || !$first_type instanceof TArray) && ($intersection_type !== $last_type || !$last_type instanceof TArray)) { $onlyTKeyedArray = \false; break; } } if ($onlyTKeyedArray) { /** * @var array $intersection_types * @var TKeyedArray $first_type * @var TKeyedArray $last_type */ return self::getTypeFromKeyedArrays($codebase, $intersection_types, $first_type, $last_type, $from_docblock); } $keyed_intersection_types = self::extractKeyedIntersectionTypes($codebase, $intersection_types); $intersect_static = \false; if (isset($keyed_intersection_types['static'])) { unset($keyed_intersection_types['static']); $intersect_static = \true; } if ($keyed_intersection_types === [] && $intersect_static) { return new TNamedObject('static', \false, \false, [], $from_docblock); } $first_type = array_shift($keyed_intersection_types); // Keyed array intersection are merged together and are not combinable with object-types if ($first_type instanceof TKeyedArray) { // assume all types are keyed arrays array_unshift($keyed_intersection_types, $first_type); /** @var TKeyedArray $last_type */ $last_type = end($keyed_intersection_types); /** @var array $keyed_intersection_types */ return self::getTypeFromKeyedArrays($codebase, $keyed_intersection_types, $first_type, $last_type, $from_docblock); } if ($intersect_static && $first_type instanceof TNamedObject) { $first_type->is_static = \true; } if ($keyed_intersection_types) { /** @var non-empty-array $keyed_intersection_types */ return $first_type->setIntersectionTypes($keyed_intersection_types); } return $first_type; } /** * @param array> $template_type_map * @param array $type_aliases * @return TCallable|TClosure * @throws TypeParseTreeException */ private static function getTypeFromCallableTree(CallableTree $parse_tree, Codebase $codebase, array $template_type_map, array $type_aliases, bool $from_docblock) { $params = []; foreach ($parse_tree->children as $child_tree) { $is_variadic = \false; $is_optional = \false; $param_name = ''; if ($child_tree instanceof CallableParamTree) { if (isset($child_tree->children[0])) { $tree_type = self::getTypeFromTree($child_tree->children[0], $codebase, null, $template_type_map, $type_aliases, $from_docblock); } else { $tree_type = new TMixed(\false, $from_docblock); } $is_variadic = $child_tree->variadic; $is_optional = $child_tree->has_default; $param_name = $child_tree->name ?? ''; } else { if ($child_tree instanceof Value && strpos($child_tree->value, '$') > 0) { $child_tree->value = preg_replace('/(.+)\\$.*/', '$1', $child_tree->value); } $tree_type = self::getTypeFromTree($child_tree, $codebase, null, $template_type_map, $type_aliases, $from_docblock); } $param = new FunctionLikeParameter($param_name, \false, $tree_type instanceof Union ? $tree_type : new Union([$tree_type]), null, null, null, $is_optional, \false, $is_variadic); $params[] = $param; } $pure = strpos($parse_tree->value, 'pure-') === 0 ? \true : null; if (in_array(strtolower($parse_tree->value), ['closure', '\\closure', 'pure-closure'], \true)) { return new TClosure('Closure', $params, null, $pure, [], [], $from_docblock); } return new TCallable('callable', $params, null, $pure, $from_docblock); } /** * @param array> $template_type_map * @throws TypeParseTreeException */ private static function getTypeFromIndexAccessTree(IndexedAccessTree $parse_tree, array $template_type_map, bool $from_docblock) : TTemplateIndexedAccess { if (!isset($parse_tree->children[0]) || !$parse_tree->children[0] instanceof Value) { throw new TypeParseTreeException('Unrecognised indexed access'); } $offset_param_name = $parse_tree->value; $array_param_name = $parse_tree->children[0]->value; if (!isset($template_type_map[$offset_param_name])) { throw new TypeParseTreeException('Unrecognised template param ' . $offset_param_name); } if (!isset($template_type_map[$array_param_name])) { throw new TypeParseTreeException('Unrecognised template param ' . $array_param_name); } $offset_template_data = $template_type_map[$offset_param_name]; $offset_defining_class = array_keys($offset_template_data)[0]; if (!$offset_defining_class && isset($offset_template_data['']) && $offset_template_data['']->isSingle()) { $offset_template_type = $offset_template_data['']->getSingleAtomic(); if ($offset_template_type instanceof TTemplateKeyOf) { $offset_defining_class = $offset_template_type->defining_class; } } $array_defining_class = array_keys($template_type_map[$array_param_name])[0]; if ($offset_defining_class !== $array_defining_class && strpos($offset_defining_class, 'fn-') !== 0) { throw new TypeParseTreeException('Template params are defined in different locations'); } return new TTemplateIndexedAccess($array_param_name, $offset_param_name, $array_defining_class, $from_docblock); } /** * @param array> $template_type_map * @param array $type_aliases * @return TCallableKeyedArray|TKeyedArray|TObjectWithProperties|TArray * @throws TypeParseTreeException */ private static function getTypeFromKeyedArrayTree(KeyedArrayTree $parse_tree, Codebase $codebase, array $template_type_map, array $type_aliases, bool $from_docblock) { $properties = []; $class_strings = []; $type = $parse_tree->value; $had_optional = \false; $had_explicit = \false; $had_implicit = \false; $previous_property_key = -1; $is_list = \true; $sealed = \true; $extra_params = null; $last_property_branch = end($parse_tree->children); if ($last_property_branch instanceof GenericTree && $last_property_branch->value === '') { $extra_params = $last_property_branch->children; array_pop($parse_tree->children); } foreach ($parse_tree->children as $i => $property_branch) { $class_string = \false; if ($property_branch instanceof FieldEllipsis) { if ($i !== count($parse_tree->children) - 1) { throw new TypeParseTreeException('Unexpected ...'); } $sealed = \false; break; } if (!$property_branch instanceof KeyedArrayPropertyTree) { $property_type = self::getTypeFromTree($property_branch, $codebase, null, $template_type_map, $type_aliases, $from_docblock); $property_maybe_undefined = \false; $property_key = $i; $had_implicit = \true; } elseif (count($property_branch->children) === 1) { $property_type = self::getTypeFromTree($property_branch->children[0], $codebase, null, $template_type_map, $type_aliases, $from_docblock); $property_maybe_undefined = $property_branch->possibly_undefined; if (strpos($property_branch->value, '::')) { [$fq_classlike_name, $const_name] = explode('::', $property_branch->value); if ($const_name === 'class') { $property_key = $fq_classlike_name; $class_string = \true; } elseif ($property_branch->value[0] === '"' || $property_branch->value[0] === "'") { $property_key = $property_branch->value; } else { throw new TypeParseTreeException(':: in array key is only allowed for ::class'); } } else { $property_key = $property_branch->value; } if ($is_list && (ArrayAnalyzer::getLiteralArrayKeyInt($property_key) === \false || $had_optional && !$property_maybe_undefined || $type === 'array' || $type === 'callable-array' || $previous_property_key != $property_key - 1)) { $is_list = \false; } $had_explicit = \true; $previous_property_key = $property_key; if ($property_key[0] === '\'' || $property_key[0] === '"') { $property_key = stripslashes(substr($property_key, 1, -1)); } } else { throw new TypeParseTreeException('Missing property type'); } if (!$property_type instanceof Union) { $property_type = new Union([$property_type], ['from_docblock' => $from_docblock]); } if ($property_maybe_undefined) { $property_type->possibly_undefined = \true; $had_optional = \true; } if (isset($properties[$property_key])) { throw new TypeParseTreeException("Duplicate key {$property_key} detected"); } $properties[$property_key] = $property_type; if ($class_string) { $class_strings[$property_key] = \true; } } if ($had_explicit && $had_implicit) { throw new TypeParseTreeException('Cannot mix explicit and implicit keys'); } if ($type === 'object') { return new TObjectWithProperties($properties, [], [], $from_docblock); } $callable = strpos($type, 'callable-') === 0; $class = TKeyedArray::class; if ($callable) { $class = TCallableKeyedArray::class; $type = substr($type, 9); } if ($callable && !$properties) { throw new TypeParseTreeException('A callable array cannot be empty'); } if ($type !== 'array' && $type !== 'list') { throw new TypeParseTreeException('Unexpected brace character'); } if ($type === 'list' && !$is_list) { throw new TypeParseTreeException('A list shape cannot describe a non-list'); } if (!$properties) { return new TArray([Type::getNever($from_docblock), Type::getNever($from_docblock)], $from_docblock); } if ($extra_params) { if ($is_list && count($extra_params) !== 1) { throw new TypeParseTreeException('Must have exactly one extra field!'); } if (!$is_list && count($extra_params) !== 2) { throw new TypeParseTreeException('Must have exactly two extra fields!'); } $final_extra_params = $is_list ? [Type::getListKey(\true)] : []; foreach ($extra_params as $child_tree) { $child_type = self::getTypeFromTree($child_tree, $codebase, null, $template_type_map, $type_aliases, $from_docblock); if ($child_type instanceof Atomic) { $child_type = new Union([$child_type]); } $final_extra_params[] = $child_type; } $extra_params = $final_extra_params; } return new $class($properties, $class_strings, $extra_params ?? ($sealed ? null : [$is_list ? Type::getListKey() : Type::getArrayKey(), Type::getMixed()]), $is_list, $from_docblock); } /** * @param TNamedObject|TObjectWithProperties|TCallableObject|TIterable|TTemplateParam|TKeyedArray $intersection_type */ private static function extractIntersectionKey(Atomic $intersection_type) : string { return $intersection_type instanceof TIterable || $intersection_type instanceof TKeyedArray ? $intersection_type->getId() : $intersection_type->getKey(); } /** * @param non-empty-array $intersection_types * @return non-empty-array */ private static function extractKeyedIntersectionTypes(Codebase $codebase, array $intersection_types) : array { $keyed_intersection_types = []; $callable_intersection = null; $any_object_type_found = $any_array_found = \false; $normalized_intersection_types = self::resolveTypeAliases($codebase, $intersection_types); foreach ($normalized_intersection_types as $intersection_type) { if ($intersection_type instanceof TKeyedArray && !$intersection_type instanceof TCallableKeyedArray) { $any_array_found = \true; if ($any_object_type_found) { throw new TypeParseTreeException('The intersection type must not mix array and object types!'); } $keyed_intersection_types[self::extractIntersectionKey($intersection_type)] = $intersection_type; continue; } $any_object_type_found = \true; if ($intersection_type instanceof TIterable || $intersection_type instanceof TNamedObject || $intersection_type instanceof TTemplateParam || $intersection_type instanceof TObjectWithProperties) { $keyed_intersection_types[self::extractIntersectionKey($intersection_type)] = $intersection_type; continue; } if (get_class($intersection_type) === TObject::class) { continue; } if ($intersection_type instanceof TCallable) { if ($callable_intersection !== null) { throw new TypeParseTreeException('The intersection type must not contain more than one callable type!'); } $callable_intersection = $intersection_type; continue; } throw new TypeParseTreeException('Intersection types must be all objects, ' . get_class($intersection_type) . ' provided'); } if ($callable_intersection !== null) { $callable_object_type = new TCallableObject($callable_intersection->from_docblock, $callable_intersection); $keyed_intersection_types[self::extractIntersectionKey($callable_object_type)] = $callable_object_type; } if ($any_object_type_found && $any_array_found) { throw new TypeParseTreeException('Intersection types must be all objects or all keyed array.'); } assert($keyed_intersection_types !== []); return $keyed_intersection_types; } /** * @param array $intersection_types * @return array */ private static function resolveTypeAliases(Codebase $codebase, array $intersection_types) : array { $normalized_intersection_types = []; $modified = \false; foreach ($intersection_types as $intersection_type) { if (!$intersection_type instanceof TTypeAlias || !$codebase->classlike_storage_provider->has($intersection_type->declaring_fq_classlike_name)) { $normalized_intersection_types[] = [$intersection_type]; continue; } $expanded_intersection_type = \Psalm\Internal\Type\TypeExpander::expandAtomic($codebase, $intersection_type, null, null, null, \true, \false, \false, \true, \true, \true); $modified = $modified || $expanded_intersection_type[0] !== $intersection_type; $normalized_intersection_types[] = $expanded_intersection_type; } if ($modified === \false) { return $intersection_types; } return self::resolveTypeAliases($codebase, array_merge(...$normalized_intersection_types)); } /** * @param array $intersection_types * @param TKeyedArray|TArray $first_type * @param TKeyedArray|TArray $last_type */ private static function getTypeFromKeyedArrays(Codebase $codebase, array $intersection_types, Atomic $first_type, Atomic $last_type, bool $from_docblock) : Atomic { /** @var non-empty-array */ $properties = []; if ($first_type instanceof TArray) { array_shift($intersection_types); } elseif ($last_type instanceof TArray) { array_pop($intersection_types); } $all_sealed = \true; foreach ($intersection_types as $intersection_type) { if ($intersection_type->fallback_params !== null) { $all_sealed = \false; } foreach ($intersection_type->properties as $property => $property_type) { if (!array_key_exists($property, $properties)) { $properties[$property] = $property_type; continue; } $new_type = Type::intersectUnionTypes($properties[$property], $property_type, $codebase); if ($new_type === null) { throw new TypeParseTreeException('Incompatible intersection types for "' . $property . '", ' . $properties[$property] . ' and ' . $property_type . ' provided'); } $properties[$property] = $new_type; } } $first_or_last_type = $first_type instanceof TArray ? $first_type : ($last_type instanceof TArray ? $last_type : null); $fallback_params = null; if ($first_or_last_type !== null) { $fallback_params = [$first_or_last_type->type_params[0], $first_or_last_type->type_params[1]]; } elseif (!$all_sealed) { $fallback_params = [Type::getArrayKey(), Type::getMixed()]; } return new TKeyedArray($properties, null, $fallback_params, \false, $from_docblock); } } getCodebase()); $is_equality = $assertion->hasEquality(); $assertion_type = $assertion->getAtomicType(); // this is a specific value comparison type that cannot be negated if ($is_equality && ($assertion_type instanceof TLiteralFloat || $assertion_type instanceof TLiteralInt || $assertion_type instanceof TLiteralString || $assertion_type instanceof TEnumCase)) { if ($existing_var_type->hasMixed()) { return $existing_var_type; } return self::handleLiteralNegatedEquality($statements_analyzer, $assertion, $assertion_type, $existing_var_type, $old_var_type_string, $key, $negated, $code_location, $suppressed_issues); } $existing_var_atomic_types = $existing_var_type->getAtomicTypes(); $existing_var_type = $existing_var_type->getBuilder(); $simple_negated_type = \Psalm\Internal\Type\SimpleNegatedAssertionReconciler::reconcile($statements_analyzer->getCodebase(), $assertion, $existing_var_type->freeze(), $key, $negated, $code_location, $suppressed_issues, $failed_reconciliation, $is_equality, $inside_loop); if ($simple_negated_type) { return $simple_negated_type; } $assertion_type = $assertion->getAtomicType(); if ($assertion instanceof IsNotType && $assertion_type instanceof TIterable && $assertion_type->type_params[1]->isMixed() || $assertion instanceof IsNotCountable) { $existing_var_type->removeType('array'); } if ($assertion instanceof IsNotType && $assertion_type instanceof TClassString) { $existing_var_type->removeType(TClassString::class); $existing_var_type->addType(new TString()); } if (!$is_equality && isset($existing_var_atomic_types['int']) && $existing_var_type->from_calculation && ($assertion_type instanceof TInt || $assertion_type instanceof TFloat)) { $existing_var_type->removeType($assertion_type->getKey()); if ($assertion_type instanceof TInt) { $existing_var_type->addType(new TFloat()); } else { $existing_var_type->addType(new TInt()); } $existing_var_type->from_calculation = \false; return $existing_var_type->freeze(); } if (!$is_equality && $assertion_type instanceof TNamedObject && ($assertion_type->value === 'DateTime' || $assertion_type->value === 'DateTimeImmutable') && isset($existing_var_atomic_types['DateTimeInterface'])) { $existing_var_type->removeType('DateTimeInterface'); if ($assertion_type->value === 'DateTime') { $existing_var_type->addType(new TNamedObject('DateTimeImmutable')); } else { $existing_var_type->addType(new TNamedObject('DateTime')); } return $existing_var_type->freeze(); } if (!$is_equality && $assertion_type instanceof TNamedObject) { foreach ($existing_var_type->getAtomicTypes() as $key => $type) { if ($type instanceof TEnumCase && $type->value === $assertion_type->value) { $existing_var_type->removeType($key); } } } $codebase = $statements_analyzer->getCodebase(); if ($assertion_type instanceof TNamedObject && strtolower($assertion_type->value) === 'traversable' && isset($existing_var_atomic_types['iterable'])) { /** @var TIterable */ $iterable = $existing_var_atomic_types['iterable']; $existing_var_type->removeType('iterable'); $existing_var_type->addType(new TArray([$iterable->type_params[0]->hasMixed() ? Type::getArrayKey() : $iterable->type_params[0], $iterable->type_params[1]])); } elseif ($assertion_type !== null && get_class($assertion_type) === TInt::class && isset($existing_var_type->getAtomicTypes()['array-key']) && !$is_equality) { $existing_var_type->removeType('array-key'); $existing_var_type->addType(new TString()); } elseif ($assertion_type instanceof TNonEmptyString && $existing_var_type->hasString()) { // do nothing } elseif ($assertion instanceof IsClassNotEqual) { // do nothing } elseif ($assertion_type instanceof TClassString && $assertion_type->is_loaded) { // do nothing } elseif ($existing_var_type->isSingle() && $existing_var_type->hasNamedObjectType() && $assertion_type instanceof TNamedObject && isset($existing_var_type->getAtomicTypes()[$assertion_type->getKey()])) { // checking if two types share a common parent is not enough to guarantee childs are instanceof each other // fall through } elseif ($existing_var_type->isArray() && ($assertion->getAtomicType() instanceof TArray || $assertion->getAtomicType() instanceof TKeyedArray || $assertion->getAtomicType() instanceof TList)) { //if both types are arrays, try to combine them $combined_type = \Psalm\Internal\Type\TypeCombiner::combine(array_merge(array_values($existing_var_type->getAtomicTypes()), [$assertion->getAtomicType()]), $codebase); $existing_var_type->removeType('array'); if ($combined_type->isSingle()) { $existing_var_type->addType($combined_type->getSingleAtomic()); } } elseif (!$is_equality) { $assertion_type = $assertion->getAtomicType(); // if there wasn't a direct hit, go deeper, eliminating subtypes if ($assertion_type && !$existing_var_type->removeType($assertion_type->getKey())) { if ($assertion_type instanceof TNamedObject) { foreach ($existing_var_type->getAtomicTypes() as $part_name => $existing_var_type_part) { if (!$existing_var_type_part->isObjectType()) { continue; } if (!$existing_var_type_part instanceof TTemplateParam && AtomicTypeComparator::isContainedBy($codebase, $existing_var_type_part, $assertion_type, \false, \false)) { $existing_var_type->removeType($part_name); } elseif (AtomicTypeComparator::isContainedBy($codebase, $assertion_type, $existing_var_type_part, \false, \false)) { $existing_var_type->different = \true; } } } } } $existing_var_type = $existing_var_type->freeze(); if ($assertion instanceof IsNotIdentical && ($key !== '$this' || !$statements_analyzer->getSource()->getSource() instanceof TraitAnalyzer)) { $assertion_type = new Union([$assertion->type]); if ($key && $code_location && !UnionTypeComparator::canExpressionTypesBeIdentical($statements_analyzer->getCodebase(), $existing_var_type, $assertion_type)) { self::triggerIssueForImpossible($existing_var_type, $old_var_type_string, $key, $assertion, \true, $negated, $code_location, $suppressed_issues); } } if ($existing_var_type->isUnionEmpty()) { if ($key !== '$this' || !$statements_analyzer->getSource()->getSource() instanceof TraitAnalyzer) { if ($key && $code_location && !$is_equality) { self::triggerIssueForImpossible($existing_var_type, $old_var_type_string, $key, $assertion, \false, $negated, $code_location, $suppressed_issues); } } $failed_reconciliation = Reconciler::RECONCILIATION_EMPTY; return Type::getNever(); } return $existing_var_type; } /** * @param TLiteralInt|TLiteralString|TLiteralFloat|TEnumCase $assertion_type * @param string[] $suppressed_issues */ private static function handleLiteralNegatedEquality(StatementsAnalyzer $statements_analyzer, Assertion $assertion, Atomic $assertion_type, Union $existing_var_type, string $old_var_type_string, ?string $key, bool $negated, ?CodeLocation $code_location, array $suppressed_issues) : Union { $existing_var_type = $existing_var_type->getBuilder(); $existing_var_atomic_types = $existing_var_type->getAtomicTypes(); $redundant = \true; $did_match_literal_type = \false; $scalar_var_type = null; if ($assertion_type instanceof TLiteralInt) { if ($existing_var_type->hasInt()) { if ($existing_var_type->getLiteralInts()) { $did_match_literal_type = \true; if ($existing_var_type->removeType($assertion_type->getKey())) { $redundant = \false; } } $existing_range_types = $existing_var_type->getRangeInts(); if ($existing_range_types) { foreach ($existing_range_types as $int_key => $literal_type) { if ($literal_type->contains($assertion_type->value)) { $redundant = \false; $existing_var_type->removeType($int_key); if ($literal_type->min_bound === null || $literal_type->min_bound <= $assertion_type->value - 1) { $existing_var_type->addType(new Type\Atomic\TIntRange($literal_type->min_bound, $assertion_type->value - 1)); } if ($literal_type->max_bound === null || $literal_type->max_bound >= $assertion_type->value + 1) { $existing_var_type->addType(new Type\Atomic\TIntRange($assertion_type->value + 1, $literal_type->max_bound)); } } } } if (isset($existing_var_type->getAtomicTypes()['int']) && get_class($existing_var_type->getAtomicTypes()['int']) === Type\Atomic\TInt::class) { $redundant = \false; //this may be used to generate a range containing any int except the one that was asserted against //but this is failing some tests /*$existing_var_type->removeType('int'); $existing_var_type->addType(new Type\Atomic\TIntRange(null, $assertion_type->value - 1)); $existing_var_type->addType(new Type\Atomic\TIntRange($assertion_type->value + 1, null));*/ } } else { $scalar_var_type = $assertion_type; } } elseif ($assertion_type instanceof TLiteralString) { if ($existing_var_type->hasString()) { if ($existing_var_type->getLiteralStrings()) { $did_match_literal_type = \true; if ($existing_var_type->removeType($assertion_type->getKey())) { $redundant = \false; } } elseif ($assertion_type->value === "") { $existing_var_type->addType(new TNonEmptyString()); } } elseif (get_class($assertion_type) === TLiteralString::class) { $scalar_var_type = $assertion_type; } } elseif ($assertion_type instanceof TLiteralFloat) { if ($existing_var_type->hasFloat()) { if ($existing_var_type->getLiteralFloats()) { $did_match_literal_type = \true; if ($existing_var_type->removeType($assertion_type->getKey())) { $redundant = \false; } } } else { $scalar_var_type = $assertion_type; } } else { $fq_enum_name = $assertion_type->value; $case_name = $assertion_type->case_name; foreach ($existing_var_type->getAtomicTypes() as $atomic_key => $atomic_type) { if (get_class($atomic_type) === TNamedObject::class && $atomic_type->value === $fq_enum_name) { $codebase = $statements_analyzer->getCodebase(); $enum_storage = $codebase->classlike_storage_provider->get($fq_enum_name); if (!$enum_storage->is_enum || !$enum_storage->enum_cases) { $scalar_var_type = $assertion_type; } else { $existing_var_type->removeType($atomic_type->getKey()); $redundant = \false; foreach ($enum_storage->enum_cases as $alt_case_name => $_) { if ($alt_case_name === $case_name) { continue; } $existing_var_type->addType(new TEnumCase($fq_enum_name, $alt_case_name)); } } } elseif ($atomic_type instanceof TEnumCase && $atomic_type->value === $fq_enum_name && $atomic_type->case_name !== $case_name) { $did_match_literal_type = \true; } elseif ($atomic_key === $assertion_type->getKey()) { $existing_var_type->removeType($assertion_type->getKey()); $redundant = \false; } } } $existing_var_type = $existing_var_type->freeze(); if ($key && $code_location) { if ($did_match_literal_type && ($redundant || count($existing_var_atomic_types) === 1)) { self::triggerIssueForImpossible($existing_var_type, $old_var_type_string, $key, $assertion, $redundant, $negated, $code_location, $suppressed_issues); } elseif ($scalar_var_type && $assertion instanceof IsNotIdentical && ($key !== '$this' || !$statements_analyzer->getSource()->getSource() instanceof TraitAnalyzer)) { if (!UnionTypeComparator::canExpressionTypesBeIdentical($statements_analyzer->getCodebase(), $existing_var_type, new Union([$scalar_var_type]))) { self::triggerIssueForImpossible($existing_var_type, $old_var_type_string, $key, $assertion, \true, $negated, $code_location, $suppressed_issues); } } } return $existing_var_type; } } */ public const PSALM_RESERVED_WORDS = ['int' => \true, 'string' => \true, 'float' => \true, 'bool' => \true, 'false' => \true, 'true' => \true, 'object' => \true, 'empty' => \true, 'callable' => \true, 'array' => \true, 'non-empty-array' => \true, 'non-empty-string' => \true, 'non-falsy-string' => \true, 'truthy-string' => \true, 'iterable' => \true, 'null' => \true, 'mixed' => \true, 'numeric-string' => \true, 'class-string' => \true, 'interface-string' => \true, 'enum-string' => \true, 'trait-string' => \true, 'callable-string' => \true, 'callable-array' => \true, 'callable-object' => \true, 'stringable-object' => \true, 'pure-callable' => \true, 'pure-Closure' => \true, 'literal-string' => \true, 'non-empty-literal-string' => \true, 'lowercase-string' => \true, 'non-empty-lowercase-string' => \true, 'positive-int' => \true, 'non-negative-int' => \true, 'negative-int' => \true, 'non-positive-int' => \true, 'literal-int' => \true, 'boolean' => \true, 'integer' => \true, 'double' => \true, 'real' => \true, 'resource' => \true, 'void' => \true, 'self' => \true, 'static' => \true, 'scalar' => \true, 'numeric' => \true, 'no-return' => \true, 'never-return' => \true, 'never-returns' => \true, 'never' => \true, 'array-key' => \true, 'key-of' => \true, 'value-of' => \true, 'properties-of' => \true, 'public-properties-of' => \true, 'protected-properties-of' => \true, 'private-properties-of' => \true, 'non-empty-countable' => \true, 'list' => \true, 'non-empty-list' => \true, 'class-string-map' => \true, 'open-resource' => \true, 'closed-resource' => \true, 'associative-array' => \true, 'arraylike-object' => \true, 'int-mask' => \true, 'int-mask-of' => \true]; /** * @var array> */ private static array $memoized_tokens = []; /** * Tokenises a type string into an array of tuples where the first element * contains the string token and the second element contains its offset, * * @return list */ public static function tokenize(string $string_type, bool $ignore_space = \true) : array { $type_tokens = [['', 0]]; $was_char = \false; $quote_char = null; $escaped = \false; if (isset(self::$memoized_tokens[$string_type])) { return self::$memoized_tokens[$string_type]; } // index of last type token $rtc = 0; $chars = str_split($string_type); $was_space = \false; for ($i = 0, $c = count($chars); $i < $c; ++$i) { $char = $chars[$i]; if (!$quote_char && $char === ' ' && $ignore_space) { $was_space = \true; continue; } if ($was_space && ($char === '$' || $char === '.' && ($chars[$i + 1] ?? null) === '.' && ($chars[$i + 2] ?? null) === '.' && ($chars[$i + 3] ?? null) === '$')) { $type_tokens[++$rtc] = [' ', $i - 1]; $type_tokens[++$rtc] = ['', $i]; } elseif ($was_space && ($char === 'a' || $char === 'i') && ($chars[$i + 1] ?? null) === 's' && ($chars[$i + 2] ?? null) === ' ') { $type_tokens[++$rtc] = [$char . 's', $i - 1]; $type_tokens[++$rtc] = ['', ++$i]; $was_char = \false; continue; } elseif ($was_char) { $type_tokens[++$rtc] = ['', $i]; } if ($quote_char) { if ($char === $quote_char && $i > 0 && !$escaped) { $quote_char = null; $type_tokens[$rtc][0] .= $char; $was_char = \true; continue; } $was_char = \false; if ($char === '\\' && !$escaped && $i < $c - 1 && ($chars[$i + 1] === $quote_char || $chars[$i + 1] === '\\')) { $escaped = \true; continue; } $escaped = \false; $type_tokens[$rtc][0] .= $char; continue; } if ($char === '"' || $char === '\'') { if ($type_tokens[$rtc][0] === '') { $type_tokens[$rtc] = [$char, $i]; } else { $type_tokens[++$rtc] = [$char, $i]; } $quote_char = $char; $was_char = \false; $was_space = \false; continue; } if ($char === '<' || $char === '>' || $char === '|' || $char === '?' || $char === ',' || $char === '{' || $char === '}' || $char === '[' || $char === ']' || $char === '(' || $char === ')' || $char === ' ' || $char === '&' || $char === '=') { if ($char === '(' && $type_tokens[$rtc][0] === 'func_num_args' && isset($chars[$i + 1]) && $chars[$i + 1] === ')') { $type_tokens[$rtc][0] = 'func_num_args()'; ++$i; continue; } if ($type_tokens[$rtc][0] === '') { $type_tokens[$rtc] = [$char, $i]; } else { $type_tokens[++$rtc] = [$char, $i]; } $was_char = \true; $was_space = \false; continue; } if ($char === ':') { if ($i + 1 < $c && $chars[$i + 1] === ':') { if ($type_tokens[$rtc][0] === '') { $type_tokens[$rtc] = ['::', $i]; } else { $type_tokens[++$rtc] = ['::', $i]; } $was_char = \true; $was_space = \false; ++$i; continue; } if ($type_tokens[$rtc][0] === '') { $type_tokens[$rtc] = [':', $i]; } else { $type_tokens[++$rtc] = [':', $i]; } $was_char = \true; $was_space = \false; continue; } if ($char === '.') { if ($i + 1 < $c && is_numeric($chars[$i + 1]) && $i > 0 && is_numeric($chars[$i - 1])) { $type_tokens[$rtc][0] .= $char; $was_char = \false; $was_space = \false; continue; } if ($i + 2 > $c || $chars[$i + 1] !== '.' || $chars[$i + 2] !== '.') { throw new TypeParseTreeException('Unexpected token ' . $char); } if ($type_tokens[$rtc][0] === '') { $type_tokens[$rtc] = ['...', $i]; } else { $type_tokens[++$rtc] = ['...', $i]; } $was_char = \true; $was_space = \false; $i += 2; continue; } $type_tokens[$rtc][0] .= $char; $was_char = \false; $was_space = \false; } /** @var list $type_tokens */ self::$memoized_tokens[$string_type] = $type_tokens; return $type_tokens; } /** * @psalm-pure */ public static function fixScalarTerms(string $type_string, ?int $analysis_php_version_id = null) : string { $type_string_lc = strtolower($type_string); switch ($type_string_lc) { case 'int': case 'void': case 'float': case 'string': case 'bool': case 'callable': case 'iterable': case 'array': case 'object': case 'true': case 'false': case 'null': case 'mixed': return $type_string_lc; } switch ($type_string) { case 'boolean': return $analysis_php_version_id !== null ? $type_string : 'bool'; case 'integer': return $analysis_php_version_id !== null ? $type_string : 'int'; case 'double': case 'real': return $analysis_php_version_id !== null ? $type_string : 'float'; } return $type_string; } /** * @param array|null $template_type_map * @param array|null $type_aliases * @return list */ public static function getFullyQualifiedTokens(string $string_type, Aliases $aliases, ?array $template_type_map = null, ?array $type_aliases = null, ?string $self_fqcln = null, ?string $parent_fqcln = null, bool $allow_assertions = \false) : array { $type_tokens = self::tokenize($string_type); for ($i = 0, $l = count($type_tokens); $i < $l; ++$i) { $string_type_token = $type_tokens[$i]; if (in_array($string_type_token[0], ['<', '>', '|', '?', ',', '{', '}', ':', '::', '[', ']', '(', ')', '&', '=', '...', 'as', 'is'], \true)) { continue; } if ($string_type_token[0][0] === '\\' && strlen($string_type_token[0]) === 1) { throw new TypeParseTreeException("Backslash \"\\\" has to be part of class name."); } if ($string_type_token[0][0] === '"' || $string_type_token[0][0] === '\'' || preg_match('/[0-9]/', $string_type_token[0][0])) { continue; } if ($string_type_token[0][0] === '-' && is_numeric($string_type_token[0])) { continue; } if (isset($type_tokens[$i + 1]) && $type_tokens[$i + 1][0] === ':' && isset($type_tokens[$i - 1]) && ($type_tokens[$i - 1][0] === '{' || $type_tokens[$i - 1][0] === ',')) { continue; } if ($i > 0 && $type_tokens[$i - 1][0] === '::') { continue; } if (strpos($string_type_token[0], '$')) { $string_type_token[0] = preg_replace('/(.+)\\$.*/', '$1', $string_type_token[0]); } $fixed_token = !isset($type_tokens[$i + 1]) || $type_tokens[$i + 1][0] !== '(' ? self::fixScalarTerms($string_type_token[0]) : $string_type_token[0]; $type_tokens[$i][0] = $fixed_token; $string_type_token[0] = $fixed_token; if ($string_type_token[0] === 'self' && $self_fqcln) { $type_tokens[$i][0] = $self_fqcln; continue; } if ($string_type_token[0] === 'parent' && $parent_fqcln) { $type_tokens[$i][0] = $parent_fqcln; continue; } if (isset(self::PSALM_RESERVED_WORDS[$string_type_token[0]])) { continue; } if (isset($template_type_map[$string_type_token[0]])) { continue; } if ($i > 1 && $type_tokens[$i - 2][0] === 'class-string-map' && $type_tokens[$i - 1][0] === '<') { $template_type_map[$string_type_token[0]] = \true; continue; } if (isset($type_tokens[$i + 1]) && isset($type_tokens[$i - 1]) && ($type_tokens[$i - 1][0] === '{' || $type_tokens[$i - 1][0] === ',')) { $next_char = $type_tokens[$i + 1][0]; if ($next_char === ':') { continue; } if ($next_char === '?' && isset($type_tokens[$i + 2]) && $type_tokens[$i + 2][0] === ':') { continue; } } if ($string_type_token[0][0] === '$' || $string_type_token[0][0] === ' ') { continue; } if (isset($type_tokens[$i + 1]) && $type_tokens[$i + 1][0] === '(') { continue; } if ($allow_assertions && $string_type_token[0] === 'falsy') { $type_tokens[$i][0] = 'false-y'; continue; } if ($string_type_token[0] === 'func_num_args()' || $string_type_token[0] === 'PHP_MAJOR_VERSION' || $string_type_token[0] === 'PHP_VERSION_ID') { continue; } $type_tokens[$i][2] = $string_type_token[0]; if (isset($type_aliases[$string_type_token[0]])) { $type_alias = $type_aliases[$string_type_token[0]]; if ($type_alias instanceof InlineTypeAlias) { $replacement_tokens = $type_alias->replacement_tokens; array_unshift($replacement_tokens, ['(', $i]); $replacement_tokens[] = [')', $i]; $diff = count($replacement_tokens) - 1; array_splice($type_tokens, $i, 1, $replacement_tokens); $i += $diff; $l += $diff; } } else { $type_tokens[$i][0] = Type::getFQCLNFromString($string_type_token[0], $aliases); } } /** @var list */ return $type_tokens; } public static function clearCache() : void { self::$memoized_tokens = []; } } 5` result is `int<6, max>`. * Complex reconciliation takes part in AssertionReconciler if this class couldn't handle the reconciliation * * @internal */ final class SimpleAssertionReconciler extends Reconciler { /** * @param string[] $suppressed_issues * @param Reconciler::RECONCILIATION_* $failed_reconciliation */ public static function reconcile(Assertion $assertion, Codebase $codebase, Union $existing_var_type, ?string $key = null, bool $negated = \false, ?CodeLocation $code_location = null, array $suppressed_issues = [], int &$failed_reconciliation = Reconciler::RECONCILIATION_OK, bool $inside_loop = \false) : ?Union { if ($assertion instanceof Any) { return $existing_var_type; } $old_var_type_string = $existing_var_type->getId(); $is_equality = $assertion->hasEquality(); if ($assertion instanceof IsIsset || $assertion instanceof IsEqualIsset) { return self::reconcileIsset($assertion, $existing_var_type, $key, $negated, $code_location, $suppressed_issues, $failed_reconciliation, $assertion instanceof IsEqualIsset, $inside_loop); } if ($assertion instanceof ArrayKeyExists) { return $existing_var_type->setPossiblyUndefined(\false); } if ($assertion instanceof InArray) { return self::reconcileInArray($assertion, $codebase, $existing_var_type, $key, $negated, $code_location, $suppressed_issues, $failed_reconciliation); } if ($assertion instanceof HasArrayKey) { return self::reconcileHasArrayKey($existing_var_type, $assertion); } if ($assertion instanceof IsGreaterThan) { return self::reconcileIsGreaterThan($assertion, $existing_var_type, $inside_loop, $old_var_type_string, $key, $negated, $code_location, $suppressed_issues); } if ($assertion instanceof IsLessThan) { return self::reconcileIsLessThan($assertion, $existing_var_type, $inside_loop, $old_var_type_string, $key, $negated, $code_location, $suppressed_issues); } if ($assertion instanceof Truthy || $assertion instanceof NonEmpty) { return self::reconcileTruthyOrNonEmpty($assertion, $existing_var_type, $key, $negated, $code_location, $suppressed_issues, $failed_reconciliation, \false); } if ($assertion instanceof IsCountable) { return self::reconcileCountable($assertion, $codebase, $existing_var_type, $key, $negated, $code_location, $suppressed_issues, $failed_reconciliation, $is_equality); } if ($assertion instanceof HasStringArrayAccess) { return self::reconcileStringArrayAccess($assertion, $codebase, $existing_var_type, $key, $negated, $code_location, $suppressed_issues, $failed_reconciliation, $inside_loop); } if ($assertion instanceof HasIntOrStringArrayAccess) { return self::reconcileIntArrayAccess($assertion, $codebase, $existing_var_type, $key, $negated, $code_location, $suppressed_issues, $failed_reconciliation, $inside_loop); } if ($assertion instanceof NonEmptyCountable) { return self::reconcileNonEmptyCountable($assertion, $existing_var_type, $key, $negated, $code_location, $suppressed_issues, $is_equality); } if ($assertion instanceof HasAtLeastCount) { return self::reconcileNonEmptyCountable($assertion, $existing_var_type, $key, $negated, $code_location, $suppressed_issues, $is_equality); } if ($assertion instanceof HasExactCount) { return self::reconcileExactlyCountable($existing_var_type, $assertion, $key, $negated, $code_location, $suppressed_issues, $is_equality); } if ($assertion instanceof HasMethod) { return self::reconcileHasMethod($assertion, $codebase, $existing_var_type, $key, $negated, $code_location, $suppressed_issues, $failed_reconciliation); } $assertion_type = $assertion->getAtomicType(); if ($assertion_type instanceof TObject) { return self::reconcileObject($codebase, $assertion, $assertion_type, $existing_var_type, $key, $negated, $code_location, $suppressed_issues, $failed_reconciliation, $is_equality); } if ($assertion_type instanceof TResource) { return self::reconcileResource($assertion, $existing_var_type, $key, $negated, $code_location, $suppressed_issues, $failed_reconciliation, $is_equality); } if ($assertion_type instanceof TCallable) { return self::reconcileCallable($assertion, $codebase, $existing_var_type, $key, $negated, $code_location, $suppressed_issues, $failed_reconciliation, $is_equality); } if ($assertion_type instanceof TIterable && $assertion_type->type_params[0]->isMixed() && $assertion_type->type_params[1]->isMixed()) { return self::reconcileIterable($assertion, $codebase, $existing_var_type, $key, $negated, $code_location, $suppressed_issues, $failed_reconciliation, $is_equality); } if ($assertion_type instanceof TArray && $assertion_type->type_params[0]->isArrayKey() && $assertion_type->type_params[1]->isMixed()) { return self::reconcileArray($assertion, $existing_var_type, $key, $negated, $code_location, $suppressed_issues, $failed_reconciliation, $is_equality); } if ($assertion_type instanceof TList) { $assertion_type = $assertion_type->getKeyedArray(); } if ($assertion_type instanceof TKeyedArray && $assertion_type->is_list && $assertion_type->getGenericValueType()->isMixed()) { return self::reconcileList($assertion, $existing_var_type, $key, $negated, $code_location, $suppressed_issues, $failed_reconciliation, $is_equality, $assertion_type->isNonEmpty()); } if ($assertion_type instanceof TNamedObject && $assertion_type->value === 'Traversable') { return self::reconcileTraversable($assertion, $codebase, $existing_var_type, $key, $negated, $code_location, $suppressed_issues, $failed_reconciliation, $is_equality); } if ($assertion_type instanceof TNumeric) { return self::reconcileNumeric($assertion, $existing_var_type, $key, $negated, $code_location, $suppressed_issues, $failed_reconciliation, $is_equality); } if ($assertion_type instanceof TScalar) { return self::reconcileScalar($assertion, $existing_var_type, $key, $negated, $code_location, $suppressed_issues, $failed_reconciliation, $is_equality); } if ($assertion_type && get_class($assertion_type) === TBool::class) { return self::reconcileBool($assertion, $existing_var_type, $key, $negated, $code_location, $suppressed_issues, $failed_reconciliation, $is_equality); } if ($assertion_type && $assertion_type instanceof TTrue) { return self::reconcileTrue($assertion, $existing_var_type, $key, $negated, $code_location, $suppressed_issues, $failed_reconciliation, $is_equality); } if ($assertion_type && $assertion_type instanceof TFalse) { return self::reconcileFalse($assertion, $existing_var_type, $key, $negated, $code_location, $suppressed_issues, $failed_reconciliation, $is_equality); } if ($assertion_type && get_class($assertion_type) === TString::class) { return self::reconcileString($assertion, $existing_var_type, $key, $negated, $code_location, $suppressed_issues, $failed_reconciliation, $is_equality); } if ($assertion_type && get_class($assertion_type) === TInt::class) { return self::reconcileInt($assertion, $existing_var_type, $key, $negated, $code_location, $suppressed_issues, $failed_reconciliation); } if ($assertion_type instanceof TFloat) { if ($existing_var_type->from_calculation && $existing_var_type->hasInt()) { return Type::getFloat(); } if ($assertion instanceof IsLooselyEqual && $existing_var_type->isString()) { return Type::getNumericString(); } } if ($assertion_type instanceof TClassConstant) { return self::reconcileClassConstant($codebase, $assertion_type, $existing_var_type, $failed_reconciliation); } if ($existing_var_type->isSingle() && $existing_var_type->hasTemplate()) { $types = $existing_var_type->getAtomicTypes(); foreach ($types as $k => $atomic_type) { if ($atomic_type instanceof TTemplateParam && $assertion_type) { if ($atomic_type->as->hasMixed() || $atomic_type->as->hasObject()) { unset($types[$k]); $atomic_type = $atomic_type->replaceAs(new Union([$assertion_type])); $types[$atomic_type->getKey()] = $atomic_type; return new Union($types); } } } } if ($assertion_type instanceof TValueOf) { return self::reconcileValueOf($codebase, $assertion_type, $failed_reconciliation); } return null; } /** * @param string[] $suppressed_issues * @param Reconciler::RECONCILIATION_* $failed_reconciliation */ private static function reconcileIsset(Assertion $assertion, Union $existing_var_type, ?string $key, bool $negated, ?CodeLocation $code_location, array $suppressed_issues, int &$failed_reconciliation, bool $is_equality, bool $inside_loop) : Union { $existing_var_type = $existing_var_type->getBuilder(); $old_var_type_string = $existing_var_type->getId(); // if key references an array offset $redundant = !($key && strpos($key, '[') || !$existing_var_type->initialized || $existing_var_type->possibly_undefined || $existing_var_type->ignore_isset); if ($existing_var_type->isNullable()) { $existing_var_type->removeType('null'); $redundant = \false; } if (!$existing_var_type->hasMixed() && !$is_equality && ($redundant || $existing_var_type->isUnionEmpty()) && $key && $code_location) { self::triggerIssueForImpossible($existing_var_type, $old_var_type_string, $key, $assertion, $redundant, $negated, $code_location, $suppressed_issues); if ($existing_var_type->isUnionEmpty()) { $failed_reconciliation = Reconciler::RECONCILIATION_EMPTY; return Type::getNever(); } } if ($inside_loop) { if ($existing_var_type->hasType('never')) { $existing_var_type->removeType('never'); $existing_var_type->addType(new TMixed(\true)); } } $existing_var_type->from_property = \false; $existing_var_type->from_static_property = \false; $existing_var_type->possibly_undefined = \false; $existing_var_type->possibly_undefined_from_try = \false; $existing_var_type->ignore_isset = \false; return $existing_var_type->freeze(); } /** * @param NonEmptyCountable|HasAtLeastCount $assertion * @param string[] $suppressed_issues */ private static function reconcileNonEmptyCountable(Assertion $assertion, Union $existing_var_type, ?string $key, bool $negated, ?CodeLocation $code_location, array $suppressed_issues, bool $is_equality) : Union { $old_var_type_string = $existing_var_type->getId(); $existing_var_type = $existing_var_type->getBuilder(); if ($existing_var_type->hasType('array')) { $array_atomic_type = $existing_var_type->getArray(); $redundant = \true; if ($array_atomic_type instanceof TArray) { if (!$array_atomic_type instanceof TNonEmptyArray || $assertion instanceof HasAtLeastCount && $array_atomic_type->min_count < $assertion->count) { if ($array_atomic_type->isEmptyArray()) { $existing_var_type->removeType('array'); } else { $non_empty_array = new TNonEmptyArray($array_atomic_type->type_params, null, $assertion instanceof HasAtLeastCount ? $assertion->count : null); $existing_var_type->addType($non_empty_array); } $redundant = \false; } } elseif ($array_atomic_type instanceof TKeyedArray) { $prop_max_count = count($array_atomic_type->properties); $prop_min_count = $array_atomic_type->getMinCount(); if ($assertion instanceof HasAtLeastCount) { // count($a) > 3 // count($a) >= 4 // 4 $count = $assertion->count; } else { // count($a) >= 1 $count = 1; } if ($array_atomic_type->fallback_params === null) { // We're asserting that count($a) >= $count // If it's impossible, remove the type // If it's possible but redundant, mark as redundant // If it's possible, mark as not redundant // Impossible because count($a) < $count always if ($prop_max_count < $count) { $redundant = \false; $existing_var_type->removeType('array'); // Redundant because count($a) >= $count always } elseif ($prop_min_count >= $count) { $redundant = \true; // If count($a) === $count and there are possibly undefined properties } elseif ($prop_max_count === $count && $prop_min_count !== $prop_max_count) { $existing_var_type->removeType('array'); $existing_var_type->addType($array_atomic_type->setProperties(array_map(static fn(Union $union) => $union->setPossiblyUndefined(\false), $array_atomic_type->properties))); $redundant = \false; // Possible, alter type if we're a list } elseif ($array_atomic_type->is_list) { // Possible $redundant = \false; $properties = $array_atomic_type->properties; for ($i = $prop_min_count; $i < $count; $i++) { $properties[$i] = $properties[$i]->setPossiblyUndefined(\false); } $array_atomic_type = $array_atomic_type->setProperties($properties); $existing_var_type->removeType('array'); $existing_var_type->addType($array_atomic_type); } else { $redundant = \false; } } elseif ($array_atomic_type->is_list) { if ($count <= $prop_min_count) { $redundant = \true; } else { $redundant = \false; $properties = $array_atomic_type->properties; for ($i = $prop_min_count; $i < $count; $i++) { $properties[$i] = isset($properties[$i]) ? $properties[$i]->setPossiblyUndefined(\false) : $array_atomic_type->fallback_params[1]; } $array_atomic_type = $array_atomic_type->setProperties($properties); $existing_var_type->removeType('array'); $existing_var_type->addType($array_atomic_type); } } else { $redundant = \false; } } if (!$is_equality && !$existing_var_type->hasMixed() && ($redundant || $existing_var_type->isUnionEmpty())) { if ($key && $code_location) { self::triggerIssueForImpossible($existing_var_type, $old_var_type_string, $key, $assertion, $redundant, $negated, $code_location, $suppressed_issues); } } } return $existing_var_type->freeze(); } /** * @param array $suppressed_issues */ private static function reconcileExactlyCountable(Union $existing_var_type, HasExactCount $assertion, ?string $key, bool $negated, ?CodeLocation $code_location, array $suppressed_issues, bool $is_equality) : Union { $existing_var_type = $existing_var_type->getBuilder(); if ($existing_var_type->hasType('array')) { $old_var_type_string = $existing_var_type->getId(); $array_atomic_type = $existing_var_type->getArray(); $redundant = \true; if ($array_atomic_type instanceof TArray) { if (!$array_atomic_type instanceof TNonEmptyArray || $array_atomic_type->count !== $assertion->count) { $non_empty_array = new TNonEmptyArray($array_atomic_type->type_params, $assertion->count); $existing_var_type->removeType('array'); $existing_var_type->addType($non_empty_array); $redundant = \false; } else { $redundant = \true; } } elseif ($array_atomic_type instanceof TKeyedArray) { $prop_max_count = count($array_atomic_type->properties); $prop_min_count = $array_atomic_type->getMinCount(); if ($assertion->count < $prop_min_count) { // Impossible $existing_var_type->removeType('array'); $redundant = \false; } elseif ($array_atomic_type->fallback_params === null) { if ($assertion->count === $prop_min_count) { // Redundant $redundant = \true; } elseif ($assertion->count > $prop_max_count) { // Impossible $existing_var_type->removeType('array'); $redundant = \false; } elseif ($assertion->count === $prop_max_count) { $redundant = \false; $existing_var_type->removeType('array'); $existing_var_type->addType($array_atomic_type->setProperties(array_map(static fn(Union $union) => $union->setPossiblyUndefined(\false), $array_atomic_type->properties))); } elseif ($array_atomic_type->is_list) { $redundant = \false; $properties = $array_atomic_type->properties; for ($x = $prop_min_count; $x < $assertion->count; $x++) { $properties[$x] = $properties[$x]->setPossiblyUndefined(\false); } $array_atomic_type = $array_atomic_type->setProperties($properties); $existing_var_type->removeType('array'); $existing_var_type->addType($array_atomic_type); } else { $redundant = \false; } } else { if ($array_atomic_type->is_list) { $redundant = \false; $properties = $array_atomic_type->properties; for ($x = $prop_min_count; $x < $assertion->count; $x++) { $properties[$x] = isset($properties[$x]) ? $properties[$x]->setPossiblyUndefined(\false) : $array_atomic_type->fallback_params[1]; } $array_atomic_type = new TKeyedArray($properties, null, null, \true); $existing_var_type->removeType('array'); $existing_var_type->addType($array_atomic_type); } elseif ($prop_max_count === $prop_min_count && $prop_max_count === $assertion->count) { $existing_var_type->removeType('array'); $existing_var_type->addType($array_atomic_type->makeSealed()); } } } if (!$is_equality && !$existing_var_type->hasMixed() && ($redundant || $existing_var_type->isUnionEmpty())) { if ($key && $code_location) { self::triggerIssueForImpossible($existing_var_type, $old_var_type_string, $key, $assertion, $redundant, $negated, $code_location, $suppressed_issues); } } } return $existing_var_type->freeze(); } /** * @param string[] $suppressed_issues * @param Reconciler::RECONCILIATION_* $failed_reconciliation */ private static function reconcileHasMethod(HasMethod $assertion, Codebase $codebase, Union $existing_var_type, ?string $key, bool $negated, ?CodeLocation $code_location, array $suppressed_issues, int &$failed_reconciliation) : Union { $method_name = $assertion->method; $old_var_type_string = $existing_var_type->getId(); $existing_var_atomic_types = $existing_var_type->getAtomicTypes(); $object_types = []; $redundant = \true; foreach ($existing_var_atomic_types as $type) { if ($type instanceof TNamedObject && $codebase->classOrInterfaceExists($type->value)) { if (!$codebase->methodExists($type->value . '::' . $method_name)) { $match_found = \false; $extra_types = $type->extra_types; foreach ($type->extra_types as $k => $extra_type) { if ($extra_type instanceof TNamedObject && $codebase->classOrInterfaceExists($extra_type->value) && $codebase->methodExists($extra_type->value . '::' . $method_name)) { $match_found = \true; } elseif ($extra_type instanceof TObjectWithProperties) { $match_found = \true; if (!isset($extra_type->methods[strtolower($method_name)])) { unset($extra_types[$k]); $extra_type = $extra_type->setMethods(array_merge($extra_type->methods, [strtolower($method_name) => 'object::' . $method_name])); $extra_types[$extra_type->getKey()] = $extra_type; $redundant = \false; } } } if (!$match_found) { $extra_type = new TObjectWithProperties([], [strtolower($method_name) => $type->value . '::' . $method_name]); $extra_types[$extra_type->getKey()] = $extra_type; $redundant = \false; } $type = $type->setIntersectionTypes($extra_types); } $object_types[] = $type; } elseif ($type instanceof TObjectWithProperties) { if (!isset($type->methods[strtolower($method_name)])) { $type = $type->setMethods(array_merge($type->methods, [strtolower($method_name) => 'object::' . $method_name])); $redundant = \false; } $object_types[] = $type; } elseif ($type instanceof TObject || $type instanceof TMixed) { $object_types[] = new TObjectWithProperties([], [strtolower($method_name) => 'object::' . $method_name]); $redundant = \false; } elseif ($type instanceof TString) { // we don’t know $object_types[] = $type; $redundant = \false; } elseif ($type instanceof TTemplateParam) { $object_types[] = $type; $redundant = \false; } else { $redundant = \false; } } if (!$object_types || $redundant) { if ($key && $code_location) { self::triggerIssueForImpossible($existing_var_type, $old_var_type_string, $key, $assertion, $redundant, $negated, $code_location, $suppressed_issues); } } if ($object_types) { return new Union($object_types); } $failed_reconciliation = Reconciler::RECONCILIATION_EMPTY; return Type::getNever(); } /** * @param string[] $suppressed_issues * @param Reconciler::RECONCILIATION_* $failed_reconciliation */ private static function reconcileString(Assertion $assertion, Union $existing_var_type, ?string $key, bool $negated, ?CodeLocation $code_location, array $suppressed_issues, int &$failed_reconciliation, bool $is_equality) : Union { $old_var_type_string = $existing_var_type->getId(); $existing_var_atomic_types = $existing_var_type->getAtomicTypes(); if ($existing_var_type->hasMixed()) { if ($assertion instanceof IsLooselyEqual) { return $existing_var_type; } return Type::getString(); } $string_types = []; $redundant = \true; foreach ($existing_var_atomic_types as $type) { if ($type instanceof TString) { if (get_class($type) === TString::class) { $type = $type->setFromDocblock(\false); } $string_types[] = $type; } elseif ($type instanceof TCallable) { $string_types[] = new TCallableString(); $redundant = \false; } elseif ($type instanceof TNumeric) { $string_types[] = new TNumericString(); $redundant = \false; } elseif ($type instanceof TScalar || $type instanceof TArrayKey) { $string_types[] = new TString(); $redundant = \false; } elseif ($type instanceof TTemplateParam) { if ($type->as->hasString() || $type->as->hasMixed() || $type->as->hasScalar()) { $type = $type->replaceAs(self::reconcileString($assertion, $type->as, null, \false, null, $suppressed_issues, $failed_reconciliation, $is_equality)); $string_types[] = $type; } $redundant = \false; } elseif ($type instanceof TInt && $assertion instanceof IsLooselyEqual) { // don't change the type of an int for non-strict comparisons $string_types[] = $type; $redundant = \false; } else { $redundant = \false; } } if (($redundant || !$string_types) && !$is_equality) { if ($key && $code_location) { self::triggerIssueForImpossible($existing_var_type, $old_var_type_string, $key, $assertion, $redundant, $negated, $code_location, $suppressed_issues); } } if ($string_types) { return new Union($string_types); } $failed_reconciliation = Reconciler::RECONCILIATION_EMPTY; return Type::getNever(); } /** * @param string[] $suppressed_issues * @param Reconciler::RECONCILIATION_* $failed_reconciliation */ private static function reconcileInt(Assertion $assertion, Union $existing_var_type, ?string $key, bool $negated, ?CodeLocation $code_location, array $suppressed_issues, int &$failed_reconciliation) : Union { if ($existing_var_type->hasMixed()) { if ($assertion instanceof IsLooselyEqual) { return $existing_var_type; } return Type::getInt(); } $old_var_type_string = $existing_var_type->getId(); $existing_var_atomic_types = $existing_var_type->getAtomicTypes(); $int_types = []; $redundant = \true; foreach ($existing_var_atomic_types as $type) { if ($type instanceof TInt) { if (get_class($type) === TInt::class) { $type = $type->setFromDocblock(\false); } $int_types[] = $type; if ($existing_var_type->from_calculation) { $redundant = \false; } } elseif ($type instanceof TNumeric) { $int_types[] = new TInt(); $redundant = \false; } elseif ($type instanceof TScalar || $type instanceof TArrayKey) { $int_types[] = new TInt(); $redundant = \false; } elseif ($type instanceof TTemplateParam) { if ($type->as->hasInt() || $type->as->hasMixed()) { $type = $type->replaceAs(self::reconcileInt($assertion, $type->as, null, \false, null, $suppressed_issues, $failed_reconciliation)); $int_types[] = $type; } $redundant = \false; } elseif ($type instanceof TString && $assertion instanceof IsLooselyEqual) { $int_types[] = new TNumericString(); $redundant = \false; } else { $redundant = \false; } } if (($redundant || !$int_types) && $assertion instanceof IsType) { if ($key && $code_location) { self::triggerIssueForImpossible($existing_var_type, $old_var_type_string, $key, $assertion, $redundant, $negated, $code_location, $suppressed_issues); } } if ($int_types) { return new Union($int_types); } $failed_reconciliation = Reconciler::RECONCILIATION_EMPTY; return Type::getNever(); } /** * @param string[] $suppressed_issues * @param Reconciler::RECONCILIATION_* $failed_reconciliation */ private static function reconcileBool(Assertion $assertion, Union $existing_var_type, ?string $key, bool $negated, ?CodeLocation $code_location, array $suppressed_issues, int &$failed_reconciliation, bool $is_equality) : Union { if ($existing_var_type->hasMixed()) { return Type::getBool(); } $bool_types = []; $redundant = \true; $old_var_type_string = $existing_var_type->getId(); $existing_var_atomic_types = $existing_var_type->getAtomicTypes(); foreach ($existing_var_atomic_types as $type) { if ($type instanceof TBool) { $type = $type->setFromDocblock(\false); $bool_types[] = $type; } elseif ($type instanceof TScalar) { $bool_types[] = new TBool(); $redundant = \false; } elseif ($type instanceof TTemplateParam) { if ($type->as->hasBool() || $type->as->hasMixed()) { $type = $type->replaceAs(self::reconcileBool($assertion, $type->as, null, \false, null, $suppressed_issues, $failed_reconciliation, $is_equality)); $bool_types[] = $type; } $redundant = \false; } else { $redundant = \false; } } if (($redundant || !$bool_types) && !$is_equality) { if ($key && $code_location) { self::triggerIssueForImpossible($existing_var_type, $old_var_type_string, $key, $assertion, $redundant, $negated, $code_location, $suppressed_issues); } } if ($bool_types) { return new Union($bool_types); } $failed_reconciliation = Reconciler::RECONCILIATION_EMPTY; return Type::getNever(); } /** * @param string[] $suppressed_issues * @param Reconciler::RECONCILIATION_* $failed_reconciliation */ private static function reconcileFalse(Assertion $assertion, Union $existing_var_type, ?string $key, bool $negated, ?CodeLocation $code_location, array $suppressed_issues, int &$failed_reconciliation, bool $is_equality) : Union { if ($existing_var_type->hasMixed()) { return Type::getFalse(); } if ($existing_var_type->hasScalar()) { return Type::getFalse(); } $old_var_type_string = $existing_var_type->getId(); $existing_var_atomic_types = $existing_var_type->getAtomicTypes(); $false_types = []; $redundant = \true; foreach ($existing_var_atomic_types as $type) { if ($type instanceof TFalse) { $false_types[] = $type; } elseif ($type instanceof TBool) { $false_types[] = new TFalse(); $redundant = \false; } elseif ($type instanceof TTemplateParam && $type->as->isMixed()) { $type = $type->replaceAs(Type::getFalse()); $false_types[] = $type; $redundant = \false; } elseif ($type instanceof TTemplateParam) { if ($type->as->hasScalar() || $type->as->hasMixed() || $type->as->hasBool()) { $type = $type->replaceAs(self::reconcileFalse($assertion, $type->as, null, \false, null, $suppressed_issues, $failed_reconciliation, $is_equality)); $false_types[] = $type; } $redundant = \false; } else { $redundant = \false; } } if ((!$false_types || $redundant) && !$is_equality) { if ($key && $code_location) { self::triggerIssueForImpossible($existing_var_type, $old_var_type_string, $key, $assertion, $redundant, $negated, $code_location, $suppressed_issues); } } if ($false_types) { return new Union($false_types); } $failed_reconciliation = Reconciler::RECONCILIATION_EMPTY; return Type::getNever(); } /** * @param string[] $suppressed_issues * @param Reconciler::RECONCILIATION_* $failed_reconciliation */ private static function reconcileTrue(Assertion $assertion, Union $existing_var_type, ?string $key, bool $negated, ?CodeLocation $code_location, array $suppressed_issues, int &$failed_reconciliation, bool $is_equality) : Union { if ($existing_var_type->hasMixed()) { return Type::getTrue(); } if ($existing_var_type->hasScalar()) { return Type::getTrue(); } $old_var_type_string = $existing_var_type->getId(); $existing_var_atomic_types = $existing_var_type->getAtomicTypes(); $true_types = []; $redundant = \true; foreach ($existing_var_atomic_types as $type) { if ($type instanceof TTrue) { $true_types[] = $type; } elseif ($type instanceof TBool) { $true_types[] = new TTrue(); $redundant = \false; } elseif ($type instanceof TTemplateParam && $type->as->isMixed()) { $type = $type->replaceAs(Type::getTrue()); $true_types[] = $type; $redundant = \false; } elseif ($type instanceof TTemplateParam) { if ($type->as->hasScalar() || $type->as->hasMixed() || $type->as->hasBool()) { $type = $type->replaceAs(self::reconcileTrue($assertion, $type->as, null, \false, null, $suppressed_issues, $failed_reconciliation, $is_equality)); $true_types[] = $type; } $redundant = \false; } else { $redundant = \false; } } if ((!$true_types || $redundant) && !$is_equality) { if ($key && $code_location) { self::triggerIssueForImpossible($existing_var_type, $old_var_type_string, $key, $assertion, $redundant, $negated, $code_location, $suppressed_issues); } } if ($true_types) { return new Union($true_types); } $failed_reconciliation = Reconciler::RECONCILIATION_EMPTY; return Type::getNever(); } /** * @param string[] $suppressed_issues * @param Reconciler::RECONCILIATION_* $failed_reconciliation */ private static function reconcileScalar(Assertion $assertion, Union $existing_var_type, ?string $key, bool $negated, ?CodeLocation $code_location, array $suppressed_issues, int &$failed_reconciliation, bool $is_equality) : Union { if ($existing_var_type->hasMixed()) { return Type::getScalar(); } $scalar_types = []; $redundant = \true; $old_var_type_string = $existing_var_type->getId(); $existing_var_atomic_types = $existing_var_type->getAtomicTypes(); foreach ($existing_var_atomic_types as $type) { if ($type instanceof Scalar) { $scalar_types[] = $type; } elseif ($type instanceof TTemplateParam) { if ($type->as->hasScalarType() || $type->as->hasMixed()) { $type = $type->replaceAs(self::reconcileScalar($assertion, $type->as, null, \false, null, $suppressed_issues, $failed_reconciliation, $is_equality)); $scalar_types[] = $type; } $redundant = \false; } else { $redundant = \false; } } if (($redundant || !$scalar_types) && !$is_equality) { if ($key && $code_location) { self::triggerIssueForImpossible($existing_var_type, $old_var_type_string, $key, $assertion, $redundant, $negated, $code_location, $suppressed_issues); } } if ($scalar_types) { return new Union($scalar_types); } $failed_reconciliation = Reconciler::RECONCILIATION_EMPTY; return Type::getNever(); } /** * @param string[] $suppressed_issues * @param Reconciler::RECONCILIATION_* $failed_reconciliation */ private static function reconcileNumeric(Assertion $assertion, Union $existing_var_type, ?string $key, bool $negated, ?CodeLocation $code_location, array $suppressed_issues, int &$failed_reconciliation, bool $is_equality) : Union { if ($existing_var_type->hasMixed()) { return Type::getNumeric(); } $existing_var_type = $existing_var_type->getBuilder(); $old_var_type_string = $existing_var_type->getId(); $numeric_types = []; $redundant = \true; if ($existing_var_type->hasString()) { $redundant = \false; $existing_var_type->removeType('string'); $existing_var_type->addType(new TNumericString()); } foreach ($existing_var_type->getAtomicTypes() as $type) { if ($type instanceof TNumeric || $type instanceof TNumericString) { // this is a workaround for a possible issue running // is_numeric($a) && is_string($a) $redundant = \false; $numeric_types[] = $type; } elseif ($type->isNumericType()) { $numeric_types[] = $type; } elseif ($type instanceof TScalar) { $redundant = \false; $numeric_types[] = new TNumeric(); } elseif ($type instanceof TArrayKey) { $redundant = \false; $numeric_types[] = new TInt(); $numeric_types[] = new TNumericString(); } elseif ($type instanceof TTemplateParam) { if ($type->as->hasScalarType() || $type->as->hasMixed()) { $type = $type->replaceAs(self::reconcileNumeric($assertion, $type->as, null, \false, null, $suppressed_issues, $failed_reconciliation, $is_equality)); $numeric_types[] = $type; } $redundant = \false; } else { $redundant = \false; } } if (($redundant || !$numeric_types) && !$is_equality) { if ($key && $code_location) { self::triggerIssueForImpossible($existing_var_type, $old_var_type_string, $key, $assertion, $redundant, $negated, $code_location, $suppressed_issues); } } if ($numeric_types) { return new Union($numeric_types); } $failed_reconciliation = Reconciler::RECONCILIATION_EMPTY; return Type::getNever(); } /** * @param string[] $suppressed_issues * @param Reconciler::RECONCILIATION_* $failed_reconciliation */ private static function reconcileObject(Codebase $codebase, Assertion $assertion, TObject $assertion_type, Union $existing_var_type, ?string $key, bool $negated, ?CodeLocation $code_location, array $suppressed_issues, int &$failed_reconciliation, bool $is_equality) : Union { if ($existing_var_type->hasMixed()) { return new Union([$assertion_type]); } $old_var_type_string = $existing_var_type->getId(); $existing_var_atomic_types = $existing_var_type->getAtomicTypes(); $object_types = []; $redundant = \true; $assertion_type_is_intersectable_type = Type::isIntersectionType($assertion_type); foreach ($existing_var_atomic_types as $type) { if ($assertion_type_is_intersectable_type && self::areIntersectionTypesAllowed($codebase, $type)) { /** @var TNamedObject|TTemplateParam|TIterable|TObjectWithProperties|TCallableObject $assertion_type */ $object_types[] = $type->addIntersectionType($assertion_type); $redundant = \false; } elseif ($type instanceof TCallable) { $callable_object = new TCallableObject($type->from_docblock, $type); $object_types[] = $callable_object; $redundant = \false; } elseif ($type instanceof TTemplateParam && $type->as->isMixed()) { $type = $type->replaceAs(Type::getObject()); $object_types[] = $type; $redundant = \false; } elseif ($type instanceof TTemplateParam) { if ($type->as->hasObjectType() || $type->as->hasMixed()) { /** * @psalm-suppress PossiblyInvalidArgument This looks wrong, psalm assumes that $assertion_type * can contain TNamedObject due to the reconciliation above * regarding {@see Type::isIntersectionType}. Due to the * native argument type `TObject`, the variable object will * never be `TNamedObject`. */ $reconciled_type = self::reconcileObject($codebase, $assertion, $assertion_type, $type->as, null, \false, null, $suppressed_issues, $failed_reconciliation, $is_equality); $type = $type->replaceAs($reconciled_type); $object_types[] = $type; } $redundant = \false; } elseif ($type->isObjectType()) { if ($assertion_type_is_intersectable_type && !self::areIntersectionTypesAllowed($codebase, $type)) { $redundant = \false; } else { $object_types[] = $type; } } elseif ($type instanceof TIterable) { $params = $type->type_params; $params[0] = self::refineArrayKey($params[0]); $object_types[] = new TGenericObject('Traversable', $params); $redundant = \false; } else { $redundant = \false; } } if ((!$object_types || $redundant) && !$is_equality) { if ($key && $code_location) { self::triggerIssueForImpossible($existing_var_type, $old_var_type_string, $key, $assertion, $redundant, $negated, $code_location, $suppressed_issues); } } if ($object_types) { return new Union($object_types); } $failed_reconciliation = Reconciler::RECONCILIATION_EMPTY; return Type::getNever(); } /** * @param string[] $suppressed_issues * @param Reconciler::RECONCILIATION_* $failed_reconciliation */ private static function reconcileResource(Assertion $assertion, Union $existing_var_type, ?string $key, bool $negated, ?CodeLocation $code_location, array $suppressed_issues, int &$failed_reconciliation, bool $is_equality) : Union { if ($existing_var_type->hasMixed()) { return Type::getResource(); } $old_var_type_string = $existing_var_type->getId(); $existing_var_atomic_types = $existing_var_type->getAtomicTypes(); $resource_types = []; $redundant = \true; foreach ($existing_var_atomic_types as $type) { if ($type instanceof TResource) { $resource_types[] = $type; } else { $redundant = \false; } } if ((!$resource_types || $redundant) && !$is_equality) { if ($key && $code_location) { self::triggerIssueForImpossible($existing_var_type, $old_var_type_string, $key, $assertion, $redundant, $negated, $code_location, $suppressed_issues); } } if ($resource_types) { return new Union($resource_types); } $failed_reconciliation = Reconciler::RECONCILIATION_EMPTY; return Type::getNever(); } /** * @param string[] $suppressed_issues * @param Reconciler::RECONCILIATION_* $failed_reconciliation */ private static function reconcileCountable(Assertion $assertion, Codebase $codebase, Union $existing_var_type, ?string $key, bool $negated, ?CodeLocation $code_location, array $suppressed_issues, int &$failed_reconciliation, bool $is_equality) : Union { $old_var_type_string = $existing_var_type->getId(); $existing_var_atomic_types = $existing_var_type->getAtomicTypes(); if ($existing_var_type->hasMixed() || $existing_var_type->hasTemplate()) { return new Union([new TArray([Type::getArrayKey(), Type::getMixed()]), new TNamedObject('Countable')]); } $iterable_types = []; $redundant = \true; foreach ($existing_var_atomic_types as $type) { if ($type->isCountable($codebase)) { $iterable_types[] = $type; } elseif ($type instanceof TObject) { $iterable_types[] = new TNamedObject('Countable'); $redundant = \false; } elseif ($type instanceof TNamedObject || $type instanceof TIterable) { $countable = new TNamedObject('Countable'); $type = $type->addIntersectionType($countable); $iterable_types[] = $type; $redundant = \false; } else { $redundant = \false; } } if ((!$iterable_types || $redundant) && !$is_equality) { if ($key && $code_location) { self::triggerIssueForImpossible($existing_var_type, $old_var_type_string, $key, $assertion, $redundant, $negated, $code_location, $suppressed_issues); } } if ($iterable_types) { return new Union($iterable_types); } $failed_reconciliation = Reconciler::RECONCILIATION_EMPTY; return Type::getNever(); } /** * @param string[] $suppressed_issues * @param Reconciler::RECONCILIATION_* $failed_reconciliation */ private static function reconcileIterable(Assertion $assertion, Codebase $codebase, Union $existing_var_type, ?string $key, bool $negated, ?CodeLocation $code_location, array $suppressed_issues, int &$failed_reconciliation, bool $is_equality) : Union { $old_var_type_string = $existing_var_type->getId(); $existing_var_atomic_types = $existing_var_type->getAtomicTypes(); if ($existing_var_type->hasMixed() || $existing_var_type->hasTemplate()) { return new Union([new TIterable()]); } $iterable_types = []; $redundant = \true; foreach ($existing_var_atomic_types as $type) { if ($type->isIterable($codebase)) { $iterable_types[] = $type; } elseif ($type instanceof TObject) { $iterable_types[] = new TNamedObject('Traversable'); $redundant = \false; } else { $redundant = \false; } } if ((!$iterable_types || $redundant) && !$is_equality) { if ($key && $code_location) { self::triggerIssueForImpossible($existing_var_type, $old_var_type_string, $key, $assertion, $redundant, $negated, $code_location, $suppressed_issues); } } if ($iterable_types) { return new Union($iterable_types); } $failed_reconciliation = Reconciler::RECONCILIATION_EMPTY; return Type::getNever(); } /** * @param string[] $suppressed_issues * @param Reconciler::RECONCILIATION_* $failed_reconciliation */ private static function reconcileInArray(InArray $assertion, Codebase $codebase, Union $existing_var_type, ?string $key, bool $negated, ?CodeLocation $code_location, array $suppressed_issues, int &$failed_reconciliation) : Union { $new_var_type = $assertion->type; if ($new_var_type->isSingle() && $new_var_type->getSingleAtomic() instanceof TClassConstant) { // Can't do assertion on const with non-literal type return $existing_var_type; } $intersection = Type::intersectUnionTypes($new_var_type, $existing_var_type, $codebase); if ($intersection === null) { if ($key && $code_location) { self::triggerIssueForImpossible($existing_var_type, $existing_var_type->getId(), $key, $assertion, \true, $negated, $code_location, $suppressed_issues); } $failed_reconciliation = Reconciler::RECONCILIATION_EMPTY; return Type::getNever(); } return $intersection; } private static function reconcileHasArrayKey(Union $existing_var_type, HasArrayKey $assertion) : Union { $assertion = $assertion->key; $types = $existing_var_type->getAtomicTypes(); foreach ($types as &$atomic_type) { if ($atomic_type instanceof TList) { $atomic_type = $atomic_type->getKeyedArray(); } if ($atomic_type instanceof TKeyedArray) { assert(strpos($assertion, '::class') === strlen($assertion) - 7); [$assertion] = explode('::', $assertion); $atomic_type = new TKeyedArray(array_merge($atomic_type->properties, [$assertion => Type::getMixed()]), array_merge($atomic_type->class_strings ?? [], [$assertion => \true]), $atomic_type->fallback_params, $atomic_type->is_list); } } unset($atomic_type); return $existing_var_type->setTypes($types); } /** * @param string[] $suppressed_issues */ private static function reconcileIsGreaterThan(IsGreaterThan $assertion, Union $existing_var_type, bool $inside_loop, string $old_var_type_string, ?string $var_id, bool $negated, ?CodeLocation $code_location, array $suppressed_issues) : Union { $existing_var_type = $existing_var_type->getBuilder(); //we add 1 from the assertion value because we're on a strict operator $assertion_value = $assertion->value + 1; $redundant = \true; if ($assertion->doesFilterNullOrFalse() && ($existing_var_type->hasType('null') || $existing_var_type->hasType('false'))) { $redundant = \false; $existing_var_type->removeType('null'); $existing_var_type->removeType('false'); } foreach ($existing_var_type->getAtomicTypes() as $atomic_type) { if ($atomic_type instanceof TIntRange) { if ($atomic_type->contains($assertion_value)) { // if the range contains the assertion, the range must be adapted $redundant = \false; $existing_var_type->removeType($atomic_type->getKey()); $min_bound = $atomic_type->min_bound; if ($min_bound === null) { $min_bound = $assertion_value; } else { $min_bound = TIntRange::getNewHighestBound($assertion_value, $min_bound); } $existing_var_type->addType(new TIntRange($min_bound, $atomic_type->max_bound)); } elseif ($atomic_type->isLesserThan($assertion_value)) { // if the range is lesser than the assertion, the type must be removed $redundant = \false; $existing_var_type->removeType($atomic_type->getKey()); } elseif ($atomic_type->isGreaterThan($assertion_value)) { // if the range is greater than the assertion, the check is redundant } } elseif ($atomic_type instanceof TLiteralInt) { if ($atomic_type->value < $assertion_value) { $redundant = \false; $existing_var_type->removeType($atomic_type->getKey()); } /*elseif ($inside_loop) { //when inside a loop, allow the range to extends the type $existing_var_type->removeType($atomic_type->getKey()); if ($atomic_type->value < $assertion_value) { $existing_var_type->addType(new TIntRange($atomic_type->value, $assertion_value)); } else { $existing_var_type->addType(new TIntRange($assertion_value, $atomic_type->value)); } }*/ } elseif ($atomic_type instanceof TInt && is_int($assertion_value)) { $redundant = \false; $existing_var_type->removeType($atomic_type->getKey()); $existing_var_type->addType(new TIntRange($assertion_value, null)); } else { // we assume that other types may have been removed (empty strings? numeric strings?) //It may be worth refining to improve reconciliation while keeping in mind we're on loose comparison $redundant = \false; } } if (!$inside_loop && $redundant && $var_id && $code_location) { self::triggerIssueForImpossible($existing_var_type, $old_var_type_string, $var_id, $assertion, \true, $negated, $code_location, $suppressed_issues); } if ($existing_var_type->isUnionEmpty()) { if ($var_id && $code_location) { self::triggerIssueForImpossible($existing_var_type, $old_var_type_string, $var_id, $assertion, \false, $negated, $code_location, $suppressed_issues); } $existing_var_type->addType(new TNever()); } return $existing_var_type->freeze(); } /** * @param string[] $suppressed_issues */ private static function reconcileIsLessThan(IsLessThan $assertion, Union $existing_var_type, bool $inside_loop, string $old_var_type_string, ?string $var_id, bool $negated, ?CodeLocation $code_location, array $suppressed_issues) : Union { //we remove 1 from the assertion value because we're on a strict operator $assertion_value = $assertion->value - 1; $existing_var_type = $existing_var_type->getBuilder(); $redundant = \true; if ($assertion->doesFilterNullOrFalse() && ($existing_var_type->hasType('null') || $existing_var_type->hasType('false'))) { $redundant = \false; $existing_var_type->removeType('null'); $existing_var_type->removeType('false'); } foreach ($existing_var_type->getAtomicTypes() as $atomic_type) { if ($atomic_type instanceof TIntRange) { if ($atomic_type->contains($assertion_value)) { // if the range contains the assertion, the range must be adapted $redundant = \false; $existing_var_type->removeType($atomic_type->getKey()); $max_bound = $atomic_type->max_bound; if ($max_bound === null) { $max_bound = $assertion_value; } else { $max_bound = min($max_bound, $assertion_value); } $existing_var_type->addType(new TIntRange($atomic_type->min_bound, $max_bound)); } elseif ($atomic_type->isLesserThan($assertion_value)) { // if the range is lesser than the assertion, the check is redundant } elseif ($atomic_type->isGreaterThan($assertion_value)) { // if the range is greater than the assertion, the type must be removed $redundant = \false; $existing_var_type->removeType($atomic_type->getKey()); } } elseif ($atomic_type instanceof TLiteralInt) { if ($atomic_type->value > $assertion_value) { $redundant = \false; $existing_var_type->removeType($atomic_type->getKey()); } /* elseif ($inside_loop) { //when inside a loop, allow the range to extends the type $existing_var_type->removeType($atomic_type->getKey()); if ($atomic_type->value < $assertion_value) { $existing_var_type->addType(new TIntRange($atomic_type->value, $assertion_value)); } else { $existing_var_type->addType(new TIntRange($assertion_value, $atomic_type->value)); } }*/ } elseif ($atomic_type instanceof TInt) { $redundant = \false; $existing_var_type->removeType($atomic_type->getKey()); $existing_var_type->addType(new TIntRange(null, $assertion_value)); } else { // we assume that other types may have been removed (empty strings? numeric strings?) //It may be worth refining to improve reconciliation while keeping in mind we're on loose comparison $redundant = \false; } } if (!$inside_loop && $redundant && $var_id && $code_location) { self::triggerIssueForImpossible($existing_var_type, $old_var_type_string, $var_id, $assertion, \true, $negated, $code_location, $suppressed_issues); } if ($existing_var_type->isUnionEmpty()) { if ($var_id && $code_location) { self::triggerIssueForImpossible($existing_var_type, $old_var_type_string, $var_id, $assertion, \false, $negated, $code_location, $suppressed_issues); } $existing_var_type->addType(new TNever()); } return $existing_var_type->freeze(); } /** * @param string[] $suppressed_issues * @param Reconciler::RECONCILIATION_* $failed_reconciliation */ private static function reconcileTraversable(Assertion $assertion, Codebase $codebase, Union $existing_var_type, ?string $key, bool $negated, ?CodeLocation $code_location, array $suppressed_issues, int &$failed_reconciliation, bool $is_equality) : Union { $old_var_type_string = $existing_var_type->getId(); $existing_var_atomic_types = $existing_var_type->getAtomicTypes(); if ($existing_var_type->hasMixed() || $existing_var_type->hasTemplate()) { return new Union([new TNamedObject('Traversable')]); } $traversable_types = []; $redundant = \true; foreach ($existing_var_atomic_types as $type) { if ($type->hasTraversableInterface($codebase)) { $traversable_types[] = $type; } elseif ($type instanceof TIterable) { $traversable_types[] = new TGenericObject('Traversable', $type->type_params); $redundant = \false; } elseif ($type instanceof TObject) { $traversable_types[] = new TNamedObject('Traversable'); $redundant = \false; } elseif ($type instanceof TNamedObject) { $traversable = new TNamedObject('Traversable'); $type = $type->addIntersectionType($traversable); $traversable_types[] = $type; $redundant = \false; } else { $redundant = \false; } } if ((!$traversable_types || $redundant) && !$is_equality) { if ($key && $code_location) { self::triggerIssueForImpossible($existing_var_type, $old_var_type_string, $key, $assertion, $redundant, $negated, $code_location, $suppressed_issues); } } if ($traversable_types) { return new Union($traversable_types); } $failed_reconciliation = Reconciler::RECONCILIATION_EMPTY; return Type::getNever(); } /** * @param string[] $suppressed_issues * @param Reconciler::RECONCILIATION_* $failed_reconciliation */ private static function reconcileArray(Assertion $assertion, Union $existing_var_type, ?string $key, bool $negated, ?CodeLocation $code_location, array $suppressed_issues, int &$failed_reconciliation, bool $is_equality) : Union { $old_var_type_string = $existing_var_type->getId(); $existing_var_atomic_types = $existing_var_type->getAtomicTypes(); if ($existing_var_type->hasMixed()) { if ($assertion->getAtomicType()) { return new Union([$assertion->getAtomicType()]); } return Type::getArray(); } $atomic_assertion_type = $assertion->getAtomicType(); $array_types = []; $redundant = \true; foreach ($existing_var_atomic_types as $type) { if ($type instanceof TList) { $type = $type->getKeyedArray(); } if ($type instanceof TArray) { if ($atomic_assertion_type instanceof TNonEmptyArray) { $array_types[] = new TNonEmptyArray($type->type_params, $atomic_assertion_type->count, $atomic_assertion_type->min_count, 'non-empty-array', $type->from_docblock); } else { $array_types[] = $type; } } elseif ($type instanceof TKeyedArray) { //we don't currently have "definitely defined" shapes so we keep the one we have even if we have //a non-empty-array assertion $array_types[] = $type; } elseif ($type instanceof TCallable) { $array_types[] = new TCallableKeyedArray([new Union([new TClassString(), new TObject()]), Type::getString()]); $redundant = \false; } elseif ($type instanceof TIterable) { $params = $type->type_params; $params[0] = self::refineArrayKey($params[0]); $array_types[] = new TArray($params); $redundant = \false; } elseif ($type instanceof TTemplateParam) { if ($type->as->hasArray() || $type->as->hasIterable() || $type->as->hasMixed()) { $type = $type->replaceAs(self::reconcileArray($assertion, $type->as, null, \false, null, $suppressed_issues, $failed_reconciliation, $is_equality)); $array_types[] = $type; } $redundant = \false; } else { $redundant = \false; } } if ((!$array_types || $redundant) && !$is_equality) { if ($key && $code_location) { self::triggerIssueForImpossible($existing_var_type, $old_var_type_string, $key, $assertion, $redundant, $negated, $code_location, $suppressed_issues); if ($redundant) { $failed_reconciliation = Reconciler::RECONCILIATION_REDUNDANT; } } } if ($array_types) { return \Psalm\Internal\Type\TypeCombiner::combine($array_types); } $failed_reconciliation = Reconciler::RECONCILIATION_EMPTY; return Type::getNever(); } /** * @param string[] $suppressed_issues * @param Reconciler::RECONCILIATION_* $failed_reconciliation */ private static function reconcileList(Assertion $assertion, Union $existing_var_type, ?string $key, bool $negated, ?CodeLocation $code_location, array $suppressed_issues, int &$failed_reconciliation, bool $is_equality, bool $is_non_empty) : Union { $old_var_type_string = $existing_var_type->getId(); $existing_var_atomic_types = $existing_var_type->getAtomicTypes(); if ($existing_var_type->hasMixed() || $existing_var_type->hasTemplate()) { return $is_non_empty ? Type::getNonEmptyList() : Type::getList(); } $array_types = []; $redundant = \true; foreach ($existing_var_atomic_types as $type) { if ($type instanceof TList) { $type = $type->getKeyedArray(); } if ($type instanceof TKeyedArray && $type->is_list) { if ($is_non_empty && !$type->isNonEmpty()) { $properties = $type->properties; $properties[0] = $properties[0]->setPossiblyUndefined(\false); $array_types[] = $type->setProperties($properties); $redundant = \false; } else { $array_types[] = $type; } } elseif ($type instanceof TArray || $type instanceof TKeyedArray && $type->fallback_params !== null) { if ($type instanceof TKeyedArray) { $type = $type->getGenericArrayType(); } if ($type->type_params[0]->hasArrayKey() || $type->type_params[0]->hasInt()) { if ($type instanceof TNonEmptyArray || $is_non_empty) { $array_types[] = Type::getNonEmptyListAtomic($type->type_params[1]); } else { $array_types[] = Type::getListAtomic($type->type_params[1]); } } if ($type->isEmptyArray()) { //we allow an empty array to pass as a list. We keep the type as empty array though (more precise) $array_types[] = $type; } $redundant = \false; } elseif ($type instanceof TCallable) { $array_types[] = new TCallableKeyedArray([new Union([new TClassString(), new TObject()]), Type::getString()]); $redundant = \false; } elseif ($type instanceof TIterable) { $array_types[] = $is_non_empty ? Type::getNonEmptyListAtomic($type->type_params[1]) : Type::getListAtomic($type->type_params[1]); $redundant = \false; } else { $redundant = \false; } } if ((!$array_types || $redundant) && !$is_equality) { if ($key && $code_location) { self::triggerIssueForImpossible($existing_var_type, $old_var_type_string, $key, $assertion, $redundant, $negated, $code_location, $suppressed_issues); if ($redundant) { $failed_reconciliation = Reconciler::RECONCILIATION_REDUNDANT; } } } if ($array_types) { return \Psalm\Internal\Type\TypeCombiner::combine($array_types); } $failed_reconciliation = Reconciler::RECONCILIATION_EMPTY; return Type::getNever(); } /** * @param string[] $suppressed_issues * @param Reconciler::RECONCILIATION_* $failed_reconciliation */ private static function reconcileStringArrayAccess(Assertion $assertion, Codebase $codebase, Union $existing_var_type, ?string $key, bool $negated, ?CodeLocation $code_location, array $suppressed_issues, int &$failed_reconciliation, bool $inside_loop) : Union { $old_var_type_string = $existing_var_type->getId(); $existing_var_atomic_types = $existing_var_type->getAtomicTypes(); if ($existing_var_type->hasMixed() || $existing_var_type->hasTemplate()) { return new Union([new TNonEmptyArray([Type::getArrayKey(), Type::getMixed()]), new TNamedObject('ArrayAccess')]); } $array_types = []; foreach ($existing_var_atomic_types as $type) { if ($type instanceof TList) { $type = $type->getKeyedArray(); } if ($type->isArrayAccessibleWithStringKey($codebase)) { if (get_class($type) === TArray::class) { $array_types[] = new TNonEmptyArray($type->type_params); } elseif ($type instanceof TKeyedArray && $type->is_list) { $properties = $type->properties; $properties[0] = $properties[0]->setPossiblyUndefined(\false); $array_types[] = $type->setProperties($properties); } else { $array_types[] = $type; } } elseif ($type instanceof TTemplateParam) { $array_types[] = $type; } } if (!$array_types) { if ($key && $code_location) { self::triggerIssueForImpossible($existing_var_type, $old_var_type_string, $key, $assertion, \true, $negated, $code_location, $suppressed_issues); } } if ($array_types) { return new Union($array_types); } $failed_reconciliation = Reconciler::RECONCILIATION_EMPTY; return Type::getMixed($inside_loop); } /** * @param string[] $suppressed_issues * @param Reconciler::RECONCILIATION_* $failed_reconciliation */ private static function reconcileIntArrayAccess(Assertion $assertion, Codebase $codebase, Union $existing_var_type, ?string $key, bool $negated, ?CodeLocation $code_location, array $suppressed_issues, int &$failed_reconciliation, bool $inside_loop) : Union { $old_var_type_string = $existing_var_type->getId(); $existing_var_atomic_types = $existing_var_type->getAtomicTypes(); if ($existing_var_type->hasMixed()) { return Type::getMixed(); } $array_types = []; foreach ($existing_var_atomic_types as $type) { if ($type->isArrayAccessibleWithIntOrStringKey($codebase)) { if (get_class($type) === TArray::class) { $array_types[] = new TNonEmptyArray($type->type_params); } else { $array_types[] = $type; } } elseif ($type instanceof TTemplateParam) { $array_types[] = $type; } } if (!$array_types) { if ($key && $code_location) { self::triggerIssueForImpossible($existing_var_type, $old_var_type_string, $key, $assertion, \true, $negated, $code_location, $suppressed_issues); } } if ($array_types) { return \Psalm\Internal\Type\TypeCombiner::combine($array_types); } $failed_reconciliation = Reconciler::RECONCILIATION_EMPTY; return Type::getMixed($inside_loop); } /** * @param string[] $suppressed_issues * @param Reconciler::RECONCILIATION_* $failed_reconciliation */ private static function reconcileCallable(Assertion $assertion, Codebase $codebase, Union $existing_var_type, ?string $key, bool $negated, ?CodeLocation $code_location, array $suppressed_issues, int &$failed_reconciliation, bool $is_equality) : Union { if ($existing_var_type->hasMixed()) { return Type::parseString('callable'); } $old_var_type_string = $existing_var_type->getId(); $existing_var_atomic_types = $existing_var_type->getAtomicTypes(); $callable_types = []; $redundant = \true; foreach ($existing_var_atomic_types as $type) { if ($type instanceof TList) { $type = $type->getKeyedArray(); } if ($type->isCallableType()) { $callable_types[] = $type; } elseif ($type instanceof TObject) { $callable_types[] = new TCallableObject(); $redundant = \false; } elseif ($type instanceof TNamedObject && $codebase->classExists($type->value) && $codebase->methodExists($type->value . '::__invoke')) { $callable_types[] = $type; } elseif (get_class($type) === TString::class || get_class($type) === TNonEmptyString::class || get_class($type) === TNonFalsyString::class) { $callable_types[] = new TCallableString(); $redundant = \false; } elseif (get_class($type) === TLiteralString::class && InternalCallMapHandler::inCallMap($type->value)) { $callable_types[] = $type; $redundant = \false; } elseif ($type instanceof TArray) { $type = new TCallableArray($type->type_params); $callable_types[] = $type; $redundant = \false; } elseif ($type instanceof TKeyedArray && count($type->properties) === 2) { $type = new TCallableKeyedArray($type->properties); $callable_types[] = $type; $redundant = \false; } elseif ($type instanceof TTemplateParam) { if ($type->as->hasCallableType() || $type->as->hasMixed()) { $type = $type->replaceAs(self::reconcileCallable($assertion, $codebase, $type->as, null, $negated, null, $suppressed_issues, $failed_reconciliation, $is_equality)); } $redundant = \false; $callable_types[] = $type; } elseif ($candidate_callable = CallableTypeComparator::getCallableFromAtomic($codebase, $type)) { $redundant = \false; $callable_types[] = $candidate_callable; } else { $redundant = \false; } } if ((!$callable_types || $redundant) && !$is_equality) { if ($key && $code_location) { self::triggerIssueForImpossible($existing_var_type, $old_var_type_string, $key, $assertion, $redundant, $negated, $code_location, $suppressed_issues); } } if ($callable_types) { return \Psalm\Internal\Type\TypeCombiner::combine($callable_types); } $failed_reconciliation = Reconciler::RECONCILIATION_EMPTY; return Type::getNever(); } /** * @param Truthy|NonEmpty $assertion * @param string[] $suppressed_issues * @param Reconciler::RECONCILIATION_* $failed_reconciliation */ private static function reconcileTruthyOrNonEmpty(Assertion $assertion, Union $existing_var_type, ?string $key, bool $negated, ?CodeLocation $code_location, array $suppressed_issues, int &$failed_reconciliation, bool $recursive_check) : Union { $types = $existing_var_type->getAtomicTypes(); $old_var_type_string = $existing_var_type->getId(); //empty is used a lot to check for array offset existence, so we have to silent errors a lot $is_empty_assertion = $assertion instanceof NonEmpty; $redundant = !($existing_var_type->possibly_undefined || $existing_var_type->possibly_undefined_from_try); foreach ($types as $existing_var_type_key => $existing_var_type_part) { //if any atomic in the union is either always falsy, we remove it. If not always truthy, we mark the check //as not redundant. if ($existing_var_type_part->isFalsy()) { $redundant = \false; unset($types[$existing_var_type_key]); } elseif ($existing_var_type->possibly_undefined || $existing_var_type->possibly_undefined_from_try || !$existing_var_type_part->isTruthy()) { $redundant = \false; } } if (!$redundant && !$types) { //every type was removed, this is an impossible assertion if ($code_location && $key && !$is_empty_assertion && !$recursive_check) { self::triggerIssueForImpossible($existing_var_type, $old_var_type_string, $key, $assertion, \false, $negated, $code_location, $suppressed_issues); } $failed_reconciliation = 2; return Type::getNever(); } if ($redundant) { if ($code_location && $key && !$is_empty_assertion && !$recursive_check) { self::triggerIssueForImpossible($existing_var_type, $old_var_type_string, $key, $assertion, \true, $negated, $code_location, $suppressed_issues); } $failed_reconciliation = 1; if (!$types) { throw new AssertionError("We must have some types here!"); } return $existing_var_type->setTypes($types); } if (isset($types['bool'])) { unset($types['bool']); $types[] = new TTrue(); } if (isset($types['array'])) { $array_atomic_type = $types['array']; if ($array_atomic_type instanceof TList) { $array_atomic_type = $array_atomic_type->getKeyedArray(); } if ($array_atomic_type instanceof TArray && !$array_atomic_type instanceof TNonEmptyArray) { unset($types['array']); $types[] = new TNonEmptyArray($array_atomic_type->type_params); } elseif ($array_atomic_type instanceof TKeyedArray && $array_atomic_type->is_list && $array_atomic_type->properties[0]->possibly_undefined) { unset($types['array']); $properties = $array_atomic_type->properties; $properties[0] = $properties[0]->setPossiblyUndefined(\false); $types[] = $array_atomic_type->setProperties($properties); } } if (isset($types['mixed'])) { $mixed_atomic_type = $types['mixed']; if (get_class($mixed_atomic_type) === TMixed::class) { unset($types['mixed']); $types[] = new TNonEmptyMixed(); } } if (isset($types['scalar'])) { $scalar_atomic_type = $types['scalar']; if (get_class($scalar_atomic_type) === TScalar::class) { unset($types['scalar']); $types[] = new TNonEmptyScalar(); } } if (isset($types['string'])) { $string_atomic_type = $types['string']; if (get_class($string_atomic_type) === TString::class) { unset($types['string']); $types[] = new TNonFalsyString(); } elseif (get_class($string_atomic_type) === TLowercaseString::class) { unset($types['string']); $types[] = new TNonEmptyLowercaseString(); } elseif (get_class($string_atomic_type) === TNonspecificLiteralString::class) { unset($types['string']); $types[] = new TNonEmptyNonspecificLiteralString(); } elseif (get_class($string_atomic_type) === TNonEmptyString::class) { unset($types['string']); $types[] = new TNonFalsyString(); } } if ($existing_var_type->hasInt()) { $existing_range_types = $existing_var_type->getRangeInts(); if ($existing_range_types) { foreach ($existing_range_types as $int_key => $literal_type) { if ($literal_type->contains(0)) { unset($types[$int_key]); if ($literal_type->min_bound === null || $literal_type->min_bound <= -1) { $types[] = new TIntRange($literal_type->min_bound, -1); } if ($literal_type->max_bound === null || $literal_type->max_bound >= 1) { $types[] = new TIntRange(1, $literal_type->max_bound); } } } } } foreach ($types as $type_key => $existing_var_atomic_type) { if ($existing_var_atomic_type instanceof TTemplateParam) { if (!$existing_var_atomic_type->as->isMixed()) { $template_did_fail = 0; $existing_var_atomic_type = $existing_var_atomic_type->replaceAs(self::reconcileTruthyOrNonEmpty($assertion, $existing_var_atomic_type->as, $key, $negated, $code_location, $suppressed_issues, $template_did_fail, \true)); if (!$template_did_fail) { unset($types[$type_key]); $types[] = $existing_var_atomic_type; } } } } if (!$types) { throw new AssertionError("We must have some types here!"); } $new = $existing_var_type->setTypes($types); if ($new === $existing_var_type && ($new->possibly_undefined || $new->possibly_undefined_from_try)) { $new = $existing_var_type->setPossiblyUndefined(\false, \false); } else { /** @psalm-suppress InaccessibleProperty We just created this type */ $new->possibly_undefined = \false; /** @psalm-suppress InaccessibleProperty We just created this type */ $new->possibly_undefined_from_try = \false; } return $new; } /** * @param Reconciler::RECONCILIATION_* $failed_reconciliation */ private static function reconcileClassConstant(Codebase $codebase, TClassConstant $class_constant_expression, Union $existing_type, int &$failed_reconciliation) : Union { $class_name = $class_constant_expression->fq_classlike_name; if (!$codebase->classlike_storage_provider->has($class_name)) { return $existing_type; } $constant_pattern = $class_constant_expression->const_name; $resolver = new ClassConstantByWildcardResolver($codebase); $matched_class_constant_types = $resolver->resolve($class_name, $constant_pattern); if ($matched_class_constant_types === null) { $failed_reconciliation = Reconciler::RECONCILIATION_EMPTY; return Type::getNever(); } return \Psalm\Internal\Type\TypeCombiner::combine(array_values($matched_class_constant_types), $codebase); } /** * @param Reconciler::RECONCILIATION_* $failed_reconciliation */ private static function reconcileValueOf(Codebase $codebase, TValueOf $assertion_type, int &$failed_reconciliation) : ?Union { $reconciled_types = []; // For now, only enums are supported here foreach ($assertion_type->type->getAtomicTypes() as $atomic_type) { $enum_case_to_assert = null; if ($atomic_type instanceof TClassConstant) { $class_name = $atomic_type->fq_classlike_name; $enum_case_to_assert = $atomic_type->const_name; } elseif ($atomic_type instanceof TNamedObject) { $class_name = $atomic_type->value; } else { return null; } if (!$codebase->classOrInterfaceOrEnumExists($class_name)) { return null; } $class_storage = $codebase->classlike_storage_provider->get($class_name); if (!$class_storage->is_enum) { return null; } if (!in_array($class_storage->enum_type, ['string', 'int'], \true)) { return null; } // For value-of, the assertion is meant to return *ANY* value of *ANY* enum case if ($enum_case_to_assert === null) { foreach ($class_storage->enum_cases as $enum_case) { $enum_value = $enum_case->getValue($codebase->classlikes); assert($enum_value !== null, 'Verified enum type above, value can not contain `null` anymore.'); $reconciled_types[] = Type::getLiteral($enum_value); } continue; } $enum_case = $class_storage->enum_cases[$enum_case_to_assert] ?? null; if ($enum_case === null) { return null; } $enum_value = $enum_case->getValue($codebase->classlikes); assert($enum_value !== null, 'Verified enum type above, value can not contain `null` anymore.'); $reconciled_types[] = Type::getLiteral($enum_value); } if ($reconciled_types === []) { $failed_reconciliation = Reconciler::RECONCILIATION_EMPTY; return Type::getNever(); } return \Psalm\Internal\Type\TypeCombiner::combine($reconciled_types, $codebase, \false, \false); } /** * @psalm-assert-if-true TCallableObject|TObjectWithProperties|TNamedObject $type */ private static function areIntersectionTypesAllowed(Codebase $codebase, Atomic $type) : bool { if ($type instanceof TObjectWithProperties || $type instanceof TCallableObject) { return \true; } if (!$type instanceof TNamedObject || !$codebase->classlike_storage_provider->has($type->value)) { return \false; } $class_storage = $codebase->classlike_storage_provider->get($type->value); return !$class_storage->final; } } > */ public array $template_types; /** * @var array>> */ public array $lower_bounds; /** * @var array> */ public array $upper_bounds = []; /** * If set to true then we shouldn't update the template bounds */ public bool $readonly = \false; /** * @var list */ public array $upper_bounds_unintersectable_types = []; /** * @param array> $template_types * @param array> $lower_bounds */ public function __construct(array $template_types, array $lower_bounds) { $this->template_types = $template_types; $this->lower_bounds = []; foreach ($lower_bounds as $key1 => $boundSet) { foreach ($boundSet as $key2 => $bound) { $this->lower_bounds[$key1][$key2] = [new \Psalm\Internal\Type\TemplateBound($bound)]; } } } public function merge(\Psalm\Internal\Type\TemplateResult $result) : \Psalm\Internal\Type\TemplateResult { if ($result === $this) { return $this; } $instance = clone $this; /** @var array>> $lower_bounds */ $lower_bounds = array_replace_recursive($instance->lower_bounds, $result->lower_bounds); $instance->lower_bounds = $lower_bounds; $instance->template_types = array_merge($instance->template_types, $result->template_types); return $instance; } } */ public array $children = []; public ?\Psalm\Internal\Type\ParseTree $parent = null; public bool $possibly_undefined = \false; public function __construct(?\Psalm\Internal\Type\ParseTree $parent = null) { $this->parent = $parent; } public function __destruct() { $this->parent = null; } public function cleanParents() : void { foreach ($this->children as $child) { $child->cleanParents(); } $this->parent = null; } } */ private array $type_tokens; private int $type_token_count; private int $t = 0; /** * @param list $type_tokens */ public function __construct(array $type_tokens) { $this->type_tokens = $type_tokens; $this->type_token_count = count($type_tokens); $this->parse_tree = new Root(); $this->current_leaf = $this->parse_tree; } public function create() : \Psalm\Internal\Type\ParseTree { while ($this->t < $this->type_token_count) { $type_token = $this->type_tokens[$this->t]; switch ($type_token[0]) { case '{': case ']': throw new TypeParseTreeException('Unexpected token ' . $type_token[0]); case '<': $this->handleLessThan(); break; case '[': $this->handleOpenSquareBracket(); break; case '(': $this->handleOpenRoundBracket(); break; case ')': $this->handleClosedRoundBracket(); break; case '>': do { if ($this->current_leaf->parent === null) { throw new TypeParseTreeException('Cannot parse generic type'); } $this->current_leaf = $this->current_leaf->parent; } while (!$this->current_leaf instanceof GenericTree); $this->current_leaf->terminated = \true; break; case '}': do { if ($this->current_leaf->parent === null) { throw new TypeParseTreeException('Cannot parse array type'); } $this->current_leaf = $this->current_leaf->parent; } while (!$this->current_leaf instanceof KeyedArrayTree); $this->current_leaf->terminated = \true; break; case ',': $this->handleComma(); break; case '...': case '=': $this->handleEllipsisOrEquals($type_token); break; case ':': $this->handleColon(); break; case ' ': $this->handleSpace(); break; case '?': $this->handleQuestionMark(); break; case '|': $this->handleBar(); break; case '&': $this->handleAmpersand(); break; case 'is': case 'as': $this->handleIsOrAs($type_token); break; default: $this->handleValue($type_token); break; } $this->t++; } $this->parse_tree->cleanParents(); if ($this->current_leaf !== $this->parse_tree && ($this->parse_tree instanceof GenericTree || $this->parse_tree instanceof CallableTree || $this->parse_tree instanceof KeyedArrayTree)) { throw new TypeParseTreeException('Unterminated bracket'); } return $this->parse_tree; } /** * @param array{0: string, 1: int, 2?: string} $current_token */ private function createMethodParam(array $current_token, \Psalm\Internal\Type\ParseTree $current_parent) : void { $byref = \false; $variadic = \false; $has_default = \false; $default = ''; if ($current_token[0] === '&') { $byref = \true; ++$this->t; $current_token = $this->t < $this->type_token_count ? $this->type_tokens[$this->t] : null; } elseif ($current_token[0] === '...') { $variadic = \true; ++$this->t; $current_token = $this->t < $this->type_token_count ? $this->type_tokens[$this->t] : null; } if (!$current_token || $current_token[0][0] !== '$') { throw new TypeParseTreeException('Unexpected token after space'); } $new_parent_leaf = new MethodParamTree($current_token[0], $byref, $variadic, $current_parent); for ($j = $this->t + 1; $j < $this->type_token_count; ++$j) { $ahead_type_token = $this->type_tokens[$j]; if ($ahead_type_token[0] === ',' || $ahead_type_token[0] === ')' && $this->type_tokens[$j - 1][0] !== '(') { $this->t = $j - 1; break; } if ($has_default) { $default .= $ahead_type_token[0]; } if ($ahead_type_token[0] === '=') { $has_default = \true; continue; } if ($j === $this->type_token_count - 1) { throw new TypeParseTreeException('Unterminated method'); } } $new_parent_leaf->default = $default; if ($this->current_leaf !== $current_parent) { $new_parent_leaf->children = [$this->current_leaf]; array_pop($current_parent->children); } $current_parent->children[] = $new_parent_leaf; $this->current_leaf = $new_parent_leaf; } /** * @param array{0: string, 1: int, 2?: string} $current_token */ private function parseCallableParam(array $current_token, \Psalm\Internal\Type\ParseTree $current_parent) : void { $variadic = \false; $has_default = \false; if ($current_token[0] === '&') { ++$this->t; $current_token = $this->t < $this->type_token_count ? $this->type_tokens[$this->t] : null; } elseif ($current_token[0] === '...') { $variadic = \true; ++$this->t; $current_token = $this->t < $this->type_token_count ? $this->type_tokens[$this->t] : null; } elseif ($current_token[0] === '=') { $has_default = \true; ++$this->t; $current_token = $this->t < $this->type_token_count ? $this->type_tokens[$this->t] : null; } if (!$current_token || $current_token[0][0] !== '$' || strlen($current_token[0]) < 2) { throw new TypeParseTreeException('Unexpected token after space'); } $new_leaf = new CallableParamTree($current_parent); $new_leaf->has_default = $has_default; $new_leaf->variadic = $variadic; $potential_name = substr($current_token[0], 1); if ($potential_name !== \false && $potential_name !== '') { $new_leaf->name = $potential_name; } if ($current_parent !== $this->current_leaf) { $new_leaf->children = [$this->current_leaf]; array_pop($current_parent->children); } $current_parent->children[] = $new_leaf; $this->current_leaf = $new_leaf; } private function handleLessThan() : void { if (!$this->current_leaf instanceof FieldEllipsis) { throw new TypeParseTreeException('Unexpected token <'); } $current_parent = $this->current_leaf->parent; if (!$current_parent instanceof KeyedArrayTree) { throw new TypeParseTreeException('Unexpected token <'); } array_pop($current_parent->children); $generic_leaf = new GenericTree('', $current_parent); $current_parent->children[] = $generic_leaf; $this->current_leaf = $generic_leaf; } private function handleOpenSquareBracket() : void { if ($this->current_leaf instanceof Root) { throw new TypeParseTreeException('Unexpected token ['); } $indexed_access = \false; $next_token = $this->t + 1 < $this->type_token_count ? $this->type_tokens[$this->t + 1] : null; if (!$next_token || $next_token[0] !== ']') { $next_next_token = $this->t + 2 < $this->type_token_count ? $this->type_tokens[$this->t + 2] : null; if ($next_next_token !== null && $next_next_token[0] === ']') { $indexed_access = \true; ++$this->t; } else { throw new TypeParseTreeException('Unexpected token ['); } } $current_parent = $this->current_leaf->parent; if ($indexed_access) { if ($next_token === null) { throw new TypeParseTreeException('Unexpected token ['); } $new_parent_leaf = new IndexedAccessTree($next_token[0], $current_parent); } else { if ($this->current_leaf instanceof KeyedArrayPropertyTree) { throw new TypeParseTreeException('Unexpected token ['); } $new_parent_leaf = new GenericTree('array', $current_parent); } $this->current_leaf->parent = $new_parent_leaf; $new_parent_leaf->children = [$this->current_leaf]; if ($current_parent) { array_pop($current_parent->children); $current_parent->children[] = $new_parent_leaf; } else { $this->parse_tree = $new_parent_leaf; } $this->current_leaf = $new_parent_leaf; ++$this->t; } private function handleOpenRoundBracket() : void { if ($this->current_leaf instanceof Value) { throw new TypeParseTreeException('Unrecognised token ('); } $new_parent = !$this->current_leaf instanceof Root ? $this->current_leaf : null; $new_leaf = new EncapsulationTree($new_parent); if ($this->current_leaf instanceof Root) { $this->current_leaf = $this->parse_tree = $new_leaf; return; } if ($new_leaf->parent) { $new_leaf->parent->children[] = $new_leaf; } $this->current_leaf = $new_leaf; } private function handleClosedRoundBracket() : void { $prev_token = $this->t > 0 ? $this->type_tokens[$this->t - 1] : null; if ($prev_token !== null && $prev_token[0] === '(' && $this->current_leaf instanceof CallableTree) { return; } do { if ($this->current_leaf->parent === null) { break; } $this->current_leaf = $this->current_leaf->parent; } while (!$this->current_leaf instanceof EncapsulationTree && !$this->current_leaf instanceof CallableTree && !$this->current_leaf instanceof MethodTree); if ($this->current_leaf instanceof EncapsulationTree || $this->current_leaf instanceof CallableTree) { $this->current_leaf->terminated = \true; } } private function handleComma() : void { if ($this->current_leaf instanceof Root) { throw new TypeParseTreeException('Unexpected token ,'); } if (!$this->current_leaf->parent) { throw new TypeParseTreeException('Cannot parse comma without a parent node'); } $context_node = $this->current_leaf; if ($context_node instanceof GenericTree || $context_node instanceof KeyedArrayTree || $context_node instanceof CallableTree || $context_node instanceof MethodTree) { $context_node = $context_node->parent; } while ($context_node && !$context_node instanceof GenericTree && !$context_node instanceof KeyedArrayTree && !$context_node instanceof CallableTree && !$context_node instanceof MethodTree) { $context_node = $context_node->parent; } if (!$context_node) { throw new TypeParseTreeException('Cannot parse comma in non-generic/array type'); } $this->current_leaf = $context_node; } /** @param array{0: string, 1: int, 2?: string} $type_token */ private function handleEllipsisOrEquals(array $type_token) : void { $prev_token = $this->t > 0 ? $this->type_tokens[$this->t - 1] : null; if ($prev_token && ($prev_token[0] === '...' || $prev_token[0] === '=')) { throw new TypeParseTreeException('Cannot have duplicate tokens'); } $current_parent = $this->current_leaf->parent; if ($this->current_leaf instanceof MethodTree && $type_token[0] === '...') { $this->createMethodParam($type_token, $this->current_leaf); return; } if ($this->current_leaf instanceof KeyedArrayTree && $type_token[0] === '...') { $leaf = new FieldEllipsis($this->current_leaf); $this->current_leaf->children[] = $leaf; $this->current_leaf = $leaf; return; } while ($current_parent && !$current_parent instanceof CallableTree && !$current_parent instanceof CallableParamTree) { $this->current_leaf = $current_parent; $current_parent = $current_parent->parent; } if (!$current_parent) { if ($type_token[0] === '...') { if ($this->current_leaf instanceof CallableTree) { $current_parent = $this->current_leaf; } else { throw new TypeParseTreeException('Unexpected token ' . $type_token[0]); } } else { throw new TypeParseTreeException('Unexpected token ' . $type_token[0]); } } if ($current_parent instanceof CallableParamTree) { throw new TypeParseTreeException('Cannot have variadic param with a default'); } $new_leaf = new CallableParamTree($current_parent); $new_leaf->has_default = $type_token[0] === '='; $new_leaf->variadic = $type_token[0] === '...'; if ($current_parent !== $this->current_leaf) { $new_leaf->children = [$this->current_leaf]; array_pop($current_parent->children); } $current_parent->children[] = $new_leaf; $this->current_leaf = $new_leaf; } private function handleColon() : void { if ($this->current_leaf instanceof Root) { throw new TypeParseTreeException('Unexpected token :'); } $current_parent = $this->current_leaf->parent; if ($this->current_leaf instanceof CallableTree) { $new_parent_leaf = new CallableWithReturnTypeTree($current_parent); $this->current_leaf->parent = $new_parent_leaf; $new_parent_leaf->children = [$this->current_leaf]; if ($current_parent) { array_pop($current_parent->children); $current_parent->children[] = $new_parent_leaf; } else { $this->parse_tree = $new_parent_leaf; } $this->current_leaf = $new_parent_leaf; return; } if ($this->current_leaf instanceof MethodTree) { $new_parent_leaf = new MethodWithReturnTypeTree($current_parent); $this->current_leaf->parent = $new_parent_leaf; $new_parent_leaf->children = [$this->current_leaf]; if ($current_parent) { array_pop($current_parent->children); $current_parent->children[] = $new_parent_leaf; } else { $this->parse_tree = $new_parent_leaf; } $this->current_leaf = $new_parent_leaf; return; } if ($current_parent instanceof KeyedArrayPropertyTree) { return; } while (($current_parent instanceof UnionTree || $current_parent instanceof CallableWithReturnTypeTree) && $this->current_leaf->parent) { $this->current_leaf = $this->current_leaf->parent; $current_parent = $this->current_leaf->parent; } if ($current_parent instanceof ConditionalTree) { if (count($current_parent->children) > 1) { throw new TypeParseTreeException('Cannot process colon in conditional twice'); } $this->current_leaf = $current_parent; return; } if (!$current_parent) { throw new TypeParseTreeException('Cannot process colon without parent'); } if (!$this->current_leaf instanceof Value) { throw new TypeParseTreeException('Unexpected LHS of property'); } if (!$current_parent instanceof KeyedArrayTree) { throw new TypeParseTreeException('Saw : outside of object-like array'); } $prev_token = $this->t > 0 ? $this->type_tokens[$this->t - 1] : null; $new_parent_leaf = new KeyedArrayPropertyTree($this->current_leaf->value, $current_parent); $new_parent_leaf->possibly_undefined = $prev_token !== null && $prev_token[0] === '?'; array_pop($current_parent->children); $current_parent->children[] = $new_parent_leaf; $this->current_leaf = $new_parent_leaf; } private function handleSpace() : void { if ($this->current_leaf instanceof Root) { throw new TypeParseTreeException('Unexpected space'); } if ($this->current_leaf instanceof KeyedArrayTree) { return; } $current_parent = $this->current_leaf->parent; //while ($current_parent && !$method_or_callable_parent) { while ($current_parent && !$current_parent instanceof MethodTree && !$current_parent instanceof CallableTree) { $this->current_leaf = $current_parent; $current_parent = $current_parent->parent; } $next_token = $this->t + 1 < $this->type_token_count ? $this->type_tokens[$this->t + 1] : null; if (!($current_parent instanceof MethodTree || $current_parent instanceof CallableTree) || !$next_token) { throw new TypeParseTreeException('Unexpected space'); } if ($current_parent instanceof MethodTree) { ++$this->t; $this->createMethodParam($next_token, $current_parent); } if ($current_parent instanceof CallableTree) { ++$this->t; $this->parseCallableParam($next_token, $current_parent); } } private function handleQuestionMark() : void { $next_token = $this->t + 1 < $this->type_token_count ? $this->type_tokens[$this->t + 1] : null; if ($next_token === null || $next_token[0] !== ':') { while (($this->current_leaf instanceof Value || $this->current_leaf instanceof UnionTree || $this->current_leaf instanceof KeyedArrayTree && $this->current_leaf->terminated || $this->current_leaf instanceof GenericTree && $this->current_leaf->terminated || $this->current_leaf instanceof EncapsulationTree && $this->current_leaf->terminated || $this->current_leaf instanceof CallableTree && $this->current_leaf->terminated || $this->current_leaf instanceof IntersectionTree) && $this->current_leaf->parent) { $this->current_leaf = $this->current_leaf->parent; } if ($this->current_leaf instanceof TemplateIsTree && $this->current_leaf->parent) { $current_parent = $this->current_leaf->parent; $new_leaf = new ConditionalTree($this->current_leaf, $this->current_leaf->parent); array_pop($current_parent->children); $current_parent->children[] = $new_leaf; $this->current_leaf = $new_leaf; } else { $new_parent = !$this->current_leaf instanceof Root ? $this->current_leaf : null; if (!$next_token) { throw new TypeParseTreeException('Unexpected token ?'); } $new_leaf = new NullableTree($new_parent); if ($this->current_leaf instanceof Root) { $this->current_leaf = $this->parse_tree = $new_leaf; return; } if ($new_leaf->parent) { $new_leaf->parent->children[] = $new_leaf; } $this->current_leaf = $new_leaf; } } } private function handleBar() : void { if ($this->current_leaf instanceof Root) { throw new TypeParseTreeException('Unexpected token |'); } $current_parent = $this->current_leaf->parent; if ($current_parent instanceof CallableWithReturnTypeTree) { $this->current_leaf = $current_parent; $current_parent = $current_parent->parent; } if ($current_parent instanceof NullableTree) { $this->current_leaf = $current_parent; $current_parent = $current_parent->parent; } if ($this->current_leaf instanceof UnionTree) { throw new TypeParseTreeException('Unexpected token |'); } if ($current_parent instanceof UnionTree) { $this->current_leaf = $current_parent; return; } if ($current_parent instanceof IntersectionTree) { $this->current_leaf = $current_parent; $current_parent = $this->current_leaf->parent; } if ($current_parent instanceof TemplateIsTree) { $new_parent_leaf = new UnionTree($this->current_leaf); $new_parent_leaf->children = [$this->current_leaf]; $new_parent_leaf->parent = $current_parent; } else { $new_parent_leaf = new UnionTree($current_parent); $new_parent_leaf->children = [$this->current_leaf]; } if ($current_parent) { array_pop($current_parent->children); $current_parent->children[] = $new_parent_leaf; } else { $this->parse_tree = $new_parent_leaf; } $this->current_leaf = $new_parent_leaf; } private function handleAmpersand() : void { if ($this->current_leaf instanceof Root) { throw new TypeParseTreeException('Unexpected &'); } $current_parent = $this->current_leaf->parent; if ($current_parent instanceof MethodTree) { $this->createMethodParam($this->type_tokens[$this->t], $current_parent); return; } if ($current_parent instanceof IntersectionTree) { $this->current_leaf = $current_parent; return; } $new_parent_leaf = new IntersectionTree($current_parent); $new_parent_leaf->children = [$this->current_leaf]; if ($current_parent) { array_pop($current_parent->children); $current_parent->children[] = $new_parent_leaf; } else { $this->parse_tree = $new_parent_leaf; } $this->current_leaf = $new_parent_leaf; } /** @param array{0: string, 1: int, 2?: string} $type_token */ private function handleIsOrAs(array $type_token) : void { if ($this->t === 0) { $this->handleValue($type_token); } else { $current_parent = $this->current_leaf->parent; if ($current_parent) { array_pop($current_parent->children); } if ($type_token[0] === 'as') { $next_token = $this->t + 1 < $this->type_token_count ? $this->type_tokens[$this->t + 1] : null; if (!$this->current_leaf instanceof Value || !$current_parent instanceof GenericTree || !$next_token) { throw new TypeParseTreeException('Unexpected token ' . $type_token[0]); } $this->current_leaf = new TemplateAsTree($this->current_leaf->value, $next_token[0], $current_parent); $current_parent->children[] = $this->current_leaf; ++$this->t; } elseif ($this->current_leaf instanceof Value) { $this->current_leaf = new TemplateIsTree($this->current_leaf->value, $current_parent); if ($current_parent) { $current_parent->children[] = $this->current_leaf; } } } } /** @param array{0: string, 1: int, 2?: string} $type_token */ private function handleValue(array $type_token) : void { $new_parent = !$this->current_leaf instanceof Root ? $this->current_leaf : null; if ($this->current_leaf instanceof MethodTree && $type_token[0][0] === '$') { $this->createMethodParam($type_token, $this->current_leaf); return; } $next_token = $this->t + 1 < $this->type_token_count ? $this->type_tokens[$this->t + 1] : null; switch ($next_token[0] ?? null) { case '<': $new_leaf = new GenericTree($type_token[0], $new_parent); ++$this->t; break; case '{': $new_leaf = new KeyedArrayTree($type_token[0], $new_parent); ++$this->t; $nexter_token = $this->t + 1 < $this->type_token_count ? $this->type_tokens[$this->t + 1] : null; if ($nexter_token !== null && $nexter_token[0] === '}') { $new_leaf->terminated = \true; ++$this->t; } elseif ($nexter_token === null) { throw new TypeParseTreeException('Unclosed bracket in keyed array'); } break; case '(': if (in_array($type_token[0], ['callable', 'pure-callable', 'Closure', '\\Closure', 'pure-Closure'], \true)) { $new_leaf = new CallableTree($type_token[0], $new_parent); } elseif ($type_token[0][0] !== '\\' && $this->current_leaf instanceof Root) { $new_leaf = new MethodTree($type_token[0], $new_parent); } else { throw new TypeParseTreeException('Parenthesis must be preceded by “Closure”, “callable”, "pure-callable" or a valid @method' . ' name'); } ++$this->t; break; case '::': $nexter_token = $this->t + 2 < $this->type_token_count ? $this->type_tokens[$this->t + 2] : null; if (!$nexter_token || !preg_match('/^([a-zA-Z_][a-zA-Z_0-9]*\\*?|\\*)$/', $nexter_token[0]) && strtolower($nexter_token[0]) !== 'class') { throw new TypeParseTreeException('Invalid class constant ' . ($nexter_token[0] ?? '')); } $new_leaf = new Value($type_token[0] . '::' . $nexter_token[0], $type_token[1], $type_token[1] + 2 + strlen($nexter_token[0]), $type_token[2] ?? null, $new_parent); $this->t += 2; break; default: if ($type_token[0] === '$this') { $type_token[0] = 'static'; } $new_leaf = new Value($type_token[0], $type_token[1], $type_token[1] + strlen($type_token[0]), $type_token[2] ?? null, $new_parent); break; } if ($this->current_leaf instanceof Root) { $this->current_leaf = $this->parse_tree = $new_leaf; return; } if ($new_leaf->parent) { $new_leaf->parent->children[] = $new_leaf; } $this->current_leaf = $new_leaf; } } lower_bounds ?: []; $types = []; foreach ($union->getAtomicTypes() as $key => $atomic_type) { $should_set = \true; $atomic_type = $atomic_type->replaceTemplateTypesWithArgTypes($template_result, $codebase); if ($atomic_type instanceof TTemplateParam) { $template_type = self::replaceTemplateParam($codebase, $atomic_type, $inferred_lower_bounds, $key); if ($template_type) { $should_set = \false; foreach ($template_type->getAtomicTypes() as $template_type_part) { if ($template_type_part instanceof TMixed) { $is_mixed = \true; } $new_types[] = $template_type_part; } } } elseif ($atomic_type instanceof TTemplateParamClass) { $template_type = isset($inferred_lower_bounds[$atomic_type->param_name][$atomic_type->defining_class]) ? \Psalm\Internal\Type\TemplateStandinTypeReplacer::getMostSpecificTypeFromBounds($inferred_lower_bounds[$atomic_type->param_name][$atomic_type->defining_class], $codebase) : null; $class_template_type = null; if ($template_type) { foreach ($template_type->getAtomicTypes() as $template_type_part) { if ($template_type_part instanceof TMixed || $template_type_part instanceof TObject) { $class_template_type = new TClassString(); } elseif ($template_type_part instanceof TNamedObject) { $class_template_type = new TClassString($template_type_part->value, $template_type_part); } elseif ($template_type_part instanceof TTemplateParam) { $first_atomic_type = $template_type_part->as->getSingleAtomic(); $class_template_type = new TTemplateParamClass($template_type_part->param_name, $template_type_part->as->getId(), $first_atomic_type instanceof TNamedObject ? $first_atomic_type : null, $template_type_part->defining_class); } } } if ($class_template_type) { $should_set = \false; $new_types[] = $class_template_type; } } elseif ($atomic_type instanceof TTemplateIndexedAccess) { $should_set = \false; $template_type = null; if (isset($inferred_lower_bounds[$atomic_type->array_param_name][$atomic_type->defining_class]) && !empty($inferred_lower_bounds[$atomic_type->offset_param_name])) { $array_template_type = \Psalm\Internal\Type\TemplateStandinTypeReplacer::getMostSpecificTypeFromBounds($inferred_lower_bounds[$atomic_type->array_param_name][$atomic_type->defining_class], $codebase); $offset_template_type = \Psalm\Internal\Type\TemplateStandinTypeReplacer::getMostSpecificTypeFromBounds(array_values($inferred_lower_bounds[$atomic_type->offset_param_name])[0], $codebase); if ($array_template_type->isSingle() && $offset_template_type->isSingle() && !$array_template_type->isMixed() && !$offset_template_type->isMixed()) { $array_template_type = $array_template_type->getSingleAtomic(); $offset_template_type = $offset_template_type->getSingleAtomic(); if ($array_template_type instanceof TKeyedArray && ($offset_template_type instanceof TLiteralString || $offset_template_type instanceof TLiteralInt) && isset($array_template_type->properties[$offset_template_type->value])) { $template_type = $array_template_type->properties[$offset_template_type->value]; } } } if ($template_type) { foreach ($template_type->getAtomicTypes() as $template_type_part) { if ($template_type_part instanceof TMixed) { $is_mixed = \true; } $new_types[] = $template_type_part; } } else { $new_types[] = new TMixed(); } } elseif ($atomic_type instanceof TTemplateKeyOf || $atomic_type instanceof TTemplateValueOf) { $new_type = self::replaceTemplateKeyOfValueOf($codebase, $atomic_type, $inferred_lower_bounds); if ($new_type) { $should_set = \false; $new_types[] = $new_type; } } elseif ($atomic_type instanceof TTemplatePropertiesOf) { $new_type = self::replaceTemplatePropertiesOf($codebase, $atomic_type, $inferred_lower_bounds); if ($new_type) { $should_set = \false; $new_types[] = $new_type; } } elseif ($atomic_type instanceof TConditional && $codebase) { $class_template_type = self::replaceConditional($template_result, $codebase, $atomic_type, $inferred_lower_bounds); $should_set = \false; foreach ($class_template_type->getAtomicTypes() as $class_template_atomic_type) { $new_types[] = $class_template_atomic_type; } } if ($should_set) { $types[] = $atomic_type; } } if ($is_mixed) { if (!$new_types) { throw new UnexpectedValueException('This array should be full'); } return $union->getBuilder()->setTypes(\Psalm\Internal\Type\TypeCombiner::combine($new_types, $codebase)->getAtomicTypes())->freeze(); } $atomic_types = [...$types, ...$new_types]; if (!$atomic_types) { throw new UnexpectedValueException('This array should be full'); } return $union->getBuilder()->setTypes(\Psalm\Internal\Type\TypeCombiner::combine($atomic_types, $codebase)->getAtomicTypes())->freeze(); } /** * @param array>> $inferred_lower_bounds */ private static function replaceTemplateParam(?Codebase $codebase, TTemplateParam $atomic_type, array $inferred_lower_bounds, string $key) : ?Union { $template_type = null; $traversed_type = \Psalm\Internal\Type\TemplateStandinTypeReplacer::getRootTemplateType($inferred_lower_bounds, $atomic_type->param_name, $atomic_type->defining_class, [], $codebase); if ($traversed_type) { $template_type = $traversed_type; if ($template_type->isMixed() && !$atomic_type->as->isMixed()) { $template_type = $atomic_type->as; } if ($atomic_type->extra_types) { $types = []; foreach ($template_type->getAtomicTypes() as $atomic_template_type) { if ($atomic_template_type instanceof TNamedObject || $atomic_template_type instanceof TTemplateParam || $atomic_template_type instanceof TIterable || $atomic_template_type instanceof TObjectWithProperties) { $types[] = $atomic_template_type->setIntersectionTypes(array_merge($atomic_type->extra_types, $atomic_template_type->extra_types)); } elseif ($atomic_template_type instanceof TObject) { $first_atomic_type = array_shift($atomic_type->extra_types); if ($atomic_type->extra_types) { $first_atomic_type = $first_atomic_type->setIntersectionTypes($atomic_type->extra_types); } $types[] = $first_atomic_type; } else { $types[] = $atomic_template_type; } } $template_type = $template_type->getBuilder()->setTypes($types)->freeze(); } } elseif ($codebase) { foreach ($inferred_lower_bounds as $template_type_map) { foreach ($template_type_map as $template_class => $_) { if (strpos($template_class, 'fn-') === 0) { continue; } try { $classlike_storage = $codebase->classlike_storage_provider->get($template_class); if ($classlike_storage->template_extended_params) { $defining_class = $atomic_type->defining_class; if (isset($classlike_storage->template_extended_params[$defining_class])) { $param_map = $classlike_storage->template_extended_params[$defining_class]; if (isset($param_map[$key])) { $template_name = (string) $param_map[$key]; if (isset($inferred_lower_bounds[$template_name][$template_class])) { $template_type = \Psalm\Internal\Type\TemplateStandinTypeReplacer::getMostSpecificTypeFromBounds($inferred_lower_bounds[$template_name][$template_class], $codebase); } } } } } catch (InvalidArgumentException $e) { } } } } return $template_type; } /** * @param TTemplateKeyOf|TTemplateValueOf $atomic_type * @param array>> $inferred_lower_bounds */ private static function replaceTemplateKeyOfValueOf(?Codebase $codebase, Atomic $atomic_type, array $inferred_lower_bounds) : ?Atomic { if (!isset($inferred_lower_bounds[$atomic_type->param_name][$atomic_type->defining_class])) { return null; } $template_type = \Psalm\Internal\Type\TemplateStandinTypeReplacer::getMostSpecificTypeFromBounds($inferred_lower_bounds[$atomic_type->param_name][$atomic_type->defining_class], $codebase); if ($atomic_type instanceof TTemplateKeyOf && TKeyOf::isViableTemplateType($template_type)) { return new TKeyOf($template_type); } if ($atomic_type instanceof TTemplateValueOf && TValueOf::isViableTemplateType($template_type)) { return new TValueOf($template_type); } return null; } /** * @param array>> $inferred_lower_bounds */ private static function replaceTemplatePropertiesOf(?Codebase $codebase, TTemplatePropertiesOf $atomic_type, array $inferred_lower_bounds) : ?Atomic { if (!isset($inferred_lower_bounds[$atomic_type->param_name][$atomic_type->defining_class])) { return null; } $template_type = \Psalm\Internal\Type\TemplateStandinTypeReplacer::getMostSpecificTypeFromBounds($inferred_lower_bounds[$atomic_type->param_name][$atomic_type->defining_class], $codebase); $classlike_type = $template_type->getSingleAtomic(); if (!$classlike_type instanceof TNamedObject) { return null; } return new TPropertiesOf($classlike_type, $atomic_type->visibility_filter); } /** * @param array>> $inferred_lower_bounds */ private static function replaceConditional(\Psalm\Internal\Type\TemplateResult $template_result, Codebase $codebase, TConditional &$atomic_type, array $inferred_lower_bounds) : Union { $template_type = isset($inferred_lower_bounds[$atomic_type->param_name][$atomic_type->defining_class]) ? \Psalm\Internal\Type\TemplateStandinTypeReplacer::getMostSpecificTypeFromBounds($inferred_lower_bounds[$atomic_type->param_name][$atomic_type->defining_class], $codebase) : null; $if_template_type = null; $else_template_type = null; $as_type = $atomic_type->as_type; $conditional_type = $atomic_type->conditional_type; $if_type = $atomic_type->if_type; $else_type = $atomic_type->else_type; if ($template_type) { $as_type = self::replace($as_type, $template_result, $codebase); if ($as_type->isNullable() && $template_type->isVoid()) { $template_type = Type::getNull(); } $matching_if_types = []; $matching_else_types = []; foreach ($template_type->getAtomicTypes() as $candidate_atomic_type) { if (UnionTypeComparator::isContainedBy($codebase, new Union([$candidate_atomic_type]), $conditional_type, \false, \false, null, \false, \false) && (!$candidate_atomic_type instanceof TInt || $conditional_type->getId() !== 'float')) { $matching_if_types[] = $candidate_atomic_type; } elseif (!UnionTypeComparator::isContainedBy($codebase, $conditional_type, new Union([$candidate_atomic_type]), \false, \false, null, \false, \false)) { $matching_else_types[] = $candidate_atomic_type; } } $if_candidate_type = $matching_if_types ? new Union($matching_if_types) : null; $else_candidate_type = $matching_else_types ? new Union($matching_else_types) : null; if ($if_candidate_type && UnionTypeComparator::isContainedBy($codebase, $if_candidate_type, $conditional_type, \false, \false, null, \false, \false)) { $if_template_type = $if_type; $refined_template_result = clone $template_result; $refined_template_result->lower_bounds[$atomic_type->param_name][$atomic_type->defining_class] = [new \Psalm\Internal\Type\TemplateBound($if_candidate_type)]; $if_template_type = self::replace($if_template_type, $refined_template_result, $codebase); } if ($else_candidate_type && UnionTypeComparator::isContainedBy($codebase, $else_candidate_type, $as_type, \false, \false, null, \false, \false)) { $else_template_type = $else_type; $refined_template_result = clone $template_result; $refined_template_result->lower_bounds[$atomic_type->param_name][$atomic_type->defining_class] = [new \Psalm\Internal\Type\TemplateBound($else_candidate_type)]; $else_template_type = self::replace($else_template_type, $refined_template_result, $codebase); } } if (!$if_template_type && !$else_template_type) { $if_type = self::replace($if_type, $template_result, $codebase); $else_type = self::replace($else_type, $template_result, $codebase); $class_template_type = Type::combineUnionTypes($if_type, $else_type, $codebase); } else { $class_template_type = Type::combineUnionTypes($if_template_type, $else_template_type, $codebase); } $atomic_type = $atomic_type->setTypes($as_type, $conditional_type, $if_type, $else_type); return $class_template_type; } } isVanillaMixed()) { return \true; } if ($input_type->isNever()) { return \true; } if ($union_comparison_result) { $union_comparison_result->scalar_type_match_found = \true; } if ($input_type->possibly_undefined && !$input_type->possibly_undefined_from_try && !$container_type->possibly_undefined) { return \false; } $container_has_template = $container_type->hasTemplateOrStatic(); $input_atomic_types = array_reverse(self::getTypeParts($codebase, $input_type)); while ($input_type_part = array_pop($input_atomic_types)) { if ($input_type_part instanceof TNull && $ignore_null) { continue; } if ($input_type_part instanceof TFalse && $ignore_false) { continue; } if ($input_type_part instanceof TTemplateParam && !$container_has_template && !$input_type_part->extra_types) { $input_atomic_types = array_merge($input_type_part->as->getAtomicTypes(), $input_atomic_types); continue; } $type_match_found = \false; $scalar_type_match_found = \false; $all_to_string_cast = \true; $all_type_coerced = null; $all_type_coerced_from_mixed = null; $all_type_coerced_from_as_mixed = null; $some_type_coerced = \false; $some_type_coerced_from_mixed = \false; $some_missing_shape_fields = null; if ($input_type_part instanceof TArrayKey && ($container_type->hasInt() && $container_type->hasString())) { continue; } if ($input_type_part instanceof TArrayKey && $container_type->hasTemplate()) { foreach ($container_type->getTemplateTypes() as $template_type) { if ($template_type->as->isArrayKey()) { continue 2; } } } if ($input_type_part instanceof TIntRange && $container_type->hasInt()) { if (\Psalm\Internal\Type\Comparator\IntegerRangeComparator::isContainedByUnion($input_type_part, $container_type)) { continue; } } foreach (self::getTypeParts($codebase, $container_type) as $container_type_part) { if ($ignore_null && $container_type_part instanceof TNull && !$input_type_part instanceof TNull) { continue; } if ($ignore_false && $container_type_part instanceof TFalse && !$input_type_part instanceof TFalse) { continue; } // if params are specified if ($container_type_part instanceof TCallable && is_array($container_type_part->params) && $input_type_part instanceof TCallable) { $container_all_param_count = count($container_type_part->params); $container_required_param_count = 0; foreach ($container_type_part->params as $index => $container_param) { if (!$container_param->is_optional) { $container_required_param_count = $index + 1; } if ($container_param->is_variadic === \true) { $container_all_param_count = PHP_INT_MAX; } } $input_required_param_count = 0; if (!is_array($input_type_part->params)) { // it's not declared, there can be an arbitrary number of params $input_all_param_count = PHP_INT_MAX; } else { $input_all_param_count = count($input_type_part->params); foreach ($input_type_part->params as $index => $input_param) { // can be false or not set at all if (!$input_param->is_optional) { $input_required_param_count = $index + 1; } if ($input_param->is_variadic === \true) { $input_all_param_count = PHP_INT_MAX; } } } // too few or too many non-optional params provided in callback if ($container_all_param_count > $input_all_param_count || $container_required_param_count > $input_all_param_count || $input_required_param_count > $container_all_param_count || $input_required_param_count > $container_required_param_count) { continue; } } if ($union_comparison_result) { $atomic_comparison_result = new \Psalm\Internal\Type\Comparator\TypeComparisonResult(); } else { $atomic_comparison_result = null; } $is_atomic_contained_by = \Psalm\Internal\Type\Comparator\AtomicTypeComparator::isContainedBy($codebase, $input_type_part, $container_type_part, $allow_interface_equality, $allow_float_int_equality, $atomic_comparison_result); if ($input_type_part instanceof TMixed && $input_type->from_template_default && $input_type->from_docblock && $atomic_comparison_result && $atomic_comparison_result->type_coerced_from_mixed) { $atomic_comparison_result->type_coerced_from_as_mixed = \true; } if ($atomic_comparison_result) { if ($atomic_comparison_result->scalar_type_match_found !== null) { $scalar_type_match_found = $atomic_comparison_result->scalar_type_match_found; } if ($union_comparison_result && $atomic_comparison_result->type_coerced_from_scalar !== null) { $union_comparison_result->type_coerced_from_scalar = $atomic_comparison_result->type_coerced_from_scalar; } if ($is_atomic_contained_by && $union_comparison_result && $atomic_comparison_result->replacement_atomic_type) { if (!$union_comparison_result->replacement_union_type) { $union_comparison_result->replacement_union_type = $input_type; } $replacement = $union_comparison_result->replacement_union_type->getBuilder(); $replacement->removeType($input_type->getKey()); $replacement->addType($atomic_comparison_result->replacement_atomic_type); $union_comparison_result->replacement_union_type = $replacement->freeze(); } } if ($input_type_part instanceof TNumeric && $container_type->hasString() && $container_type->hasInt() && $container_type->hasFloat()) { $scalar_type_match_found = \false; $is_atomic_contained_by = \true; } if ($atomic_comparison_result) { if ($atomic_comparison_result->type_coerced) { $some_type_coerced = \true; } if ($atomic_comparison_result->type_coerced_from_mixed) { $some_type_coerced_from_mixed = \true; } if ($atomic_comparison_result->type_coerced !== \true || $all_type_coerced === \false) { $all_type_coerced = \false; } else { $all_type_coerced = \true; } if ($atomic_comparison_result->type_coerced_from_mixed !== \true || $all_type_coerced_from_mixed === \false) { $all_type_coerced_from_mixed = \false; } else { $all_type_coerced_from_mixed = \true; } if ($atomic_comparison_result->type_coerced_from_as_mixed !== \true || $all_type_coerced_from_as_mixed === \false) { $all_type_coerced_from_as_mixed = \false; } else { $all_type_coerced_from_as_mixed = \true; } if ($atomic_comparison_result->missing_shape_fields) { $some_missing_shape_fields = $atomic_comparison_result->missing_shape_fields; } } if ($is_atomic_contained_by) { $type_match_found = \true; if ($atomic_comparison_result) { if ($atomic_comparison_result->to_string_cast !== \true) { $all_to_string_cast = \false; } } $all_type_coerced_from_mixed = \false; $all_type_coerced_from_as_mixed = \false; $all_type_coerced = \false; } } if ($union_comparison_result) { // only set this flag if we're definite that the only // reason the type match has been found is because there // was a __toString cast if ($all_to_string_cast && $type_match_found) { $union_comparison_result->to_string_cast = \true; } if ($all_type_coerced) { $union_comparison_result->type_coerced = \true; } if ($all_type_coerced_from_mixed) { $union_comparison_result->type_coerced_from_mixed = \true; if ($input_type->from_template_default && $input_type->from_docblock || $all_type_coerced_from_as_mixed) { $union_comparison_result->type_coerced_from_as_mixed = \true; } } } if (!$type_match_found) { if ($union_comparison_result) { if ($some_type_coerced) { $union_comparison_result->type_coerced = \true; } if ($some_type_coerced_from_mixed) { $union_comparison_result->type_coerced_from_mixed = \true; if ($input_type->from_template_default && $input_type->from_docblock || $all_type_coerced_from_as_mixed) { $union_comparison_result->type_coerced_from_as_mixed = \true; } } if (!$scalar_type_match_found) { $union_comparison_result->scalar_type_match_found = \false; } if ($some_missing_shape_fields && !$some_type_coerced && !$scalar_type_match_found) { $union_comparison_result->missing_shape_fields = $some_missing_shape_fields; } } return \false; } } return \true; } /** * Used for comparing signature typehints, uses PHP's light contravariance rules */ public static function isContainedByInPhp(?Union $input_type, Union $container_type) : bool { if ($container_type->isMixed()) { return \true; } if (!$input_type) { return \false; } if ($input_type->isNever()) { return \true; } if ($input_type->getId() === $container_type->getId()) { return \true; } if ($input_type->isNullable() && !$container_type->isNullable()) { return \false; } $input_type_not_null = $input_type->getBuilder(); $input_type_not_null->removeType('null'); $container_type_not_null = $container_type->getBuilder(); $container_type_not_null->removeType('null'); if ($input_type_not_null->getId() === $container_type_not_null->getId()) { return \true; } if ($input_type_not_null->hasArray() && $container_type_not_null->hasType('iterable')) { return \true; } return \false; } /** * Does the input param type match the given param type */ public static function canBeContainedBy(Codebase $codebase, Union $input_type, Union $container_type, bool $ignore_null = \false, bool $ignore_false = \false, array &$matching_input_keys = []) : bool { if ($container_type->hasMixed()) { return \true; } if ($input_type->isNever()) { return \true; } if ($input_type->possibly_undefined && !$container_type->possibly_undefined) { return \false; } foreach (self::getTypeParts($codebase, $container_type) as $container_type_part) { if ($container_type_part instanceof TNull && $ignore_null) { continue; } if ($container_type_part instanceof TFalse && $ignore_false) { continue; } foreach (self::getTypeParts($codebase, $input_type) as $input_type_part) { $atomic_comparison_result = new \Psalm\Internal\Type\Comparator\TypeComparisonResult(); $is_atomic_contained_by = \Psalm\Internal\Type\Comparator\AtomicTypeComparator::isContainedBy($codebase, $input_type_part, $container_type_part, \false, \false, $atomic_comparison_result); if ($is_atomic_contained_by && !$atomic_comparison_result->to_string_cast || $atomic_comparison_result->type_coerced_from_mixed) { $matching_input_keys[$input_type_part->getKey()] = \true; } } } return (bool) $matching_input_keys; } /** * Can any part of the $type1 be equal to any part of $type2 */ public static function canExpressionTypesBeIdentical(Codebase $codebase, Union $type1, Union $type2, bool $allow_interface_equality = \true) : bool { if ($type1->hasMixed() || $type2->hasMixed()) { return \true; } if ($type1->isNullable() && $type2->isNullable()) { return \true; } foreach (self::getTypeParts($codebase, $type1) as $type1_part) { foreach (self::getTypeParts($codebase, $type2) as $type2_part) { //special case for TIntRange because it can contain a part of another TIntRange. //For exemple int<0,10> and int<5, 15> can be identical but none contain the other if ($type1_part instanceof TIntRange && $type2_part instanceof TIntRange) { $intersection_range = TIntRange::intersectIntRanges($type1_part, $type2_part); return $intersection_range !== null; } $either_contains = \Psalm\Internal\Type\Comparator\AtomicTypeComparator::canBeIdentical($codebase, $type1_part, $type2_part, $allow_interface_equality); if ($either_contains) { return \true; } } } return \false; } /** * @return list */ private static function getTypeParts(Codebase $codebase, Union $union_type) : array { $atomic_types = []; foreach ($union_type->getAtomicTypes() as $atomic_type) { if (!$atomic_type instanceof TTypeAlias && !$atomic_type instanceof TClassConstant) { $atomic_types[] = $atomic_type; continue; } if ($atomic_type instanceof TTypeAlias) { $fq_classlike_name = $atomic_type->declaring_fq_classlike_name; } else { $fq_classlike_name = $atomic_type->fq_classlike_name; } $expanded = TypeExpander::expandAtomic($codebase, $atomic_type, $fq_classlike_name, $fq_classlike_name, null, \true, \true); array_push($atomic_types, ...$expanded); } return $atomic_types; } } */ public ?array $missing_shape_fields = null; } defining_class != $input_type_part->defining_class && 1 == count($container_type_part->as->getAtomicTypes()) && 1 == count($input_type_part->as->getAtomicTypes())) { $containerDefinedInFunction = strpos($container_type_part->defining_class, 'fn-') === 0; $inputDefinedInFunction = strpos($input_type_part->defining_class, 'fn-') === 0; if ($inputDefinedInFunction) { $separatorPos = strpos($input_type_part->defining_class, '::'); if ($separatorPos === \false) { // Is that possible ? Falling back to default definition. $inputDefiningClass = $input_type_part->defining_class; } else { $inputDefiningClass = substr($input_type_part->defining_class, 3, $separatorPos - 3); } } else { $inputDefiningClass = $input_type_part->defining_class; } // FIXME Missing analysis for additional cases, for example : // - input from a parameter in a static function that is defined in the container class // - input and container are both defined on function parameters if (!$inputDefinedInFunction && !$containerDefinedInFunction || $inputDefinedInFunction && !$containerDefinedInFunction && strtolower($inputDefiningClass) != strtolower($container_type_part->defining_class)) { $containerAs = current($container_type_part->as->getAtomicTypes()); $inputAs = current($input_type_part->as->getAtomicTypes()); if ($containerAs instanceof TNamedObject && $inputAs instanceof TNamedObject) { return self::isShallowlyContainedBy($codebase, $inputAs, $containerAs, $allow_interface_equality, $atomic_comparison_result); } elseif ($containerAs instanceof TMixed && $inputAs instanceof TMixed) { return \true; } } } $intersection_input_types = self::getIntersectionTypes($input_type_part); $intersection_container_types = self::getIntersectionTypes($container_type_part); foreach ($intersection_container_types as $intersection_container_type) { $container_was_static = \false; if ($intersection_container_type instanceof TIterable) { $intersection_container_type_lower = 'iterable'; } elseif ($intersection_container_type instanceof TObjectWithProperties) { $intersection_container_type_lower = 'object'; } elseif ($intersection_container_type instanceof TTemplateParam) { $intersection_container_type_lower = null; } elseif ($intersection_container_type instanceof TCallableObject) { $intersection_container_type_lower = 'callable-object'; } else { $container_was_static = $intersection_container_type->is_static; $intersection_container_type_lower = strtolower($codebase->classlikes->getUnAliasedName($intersection_container_type->value)); } $any_inputs_contained = \false; $container_type_is_interface = $intersection_container_type_lower && $codebase->interfaceExists($intersection_container_type_lower); foreach ($intersection_input_types as $input_type_key => $intersection_input_type) { if ($allow_interface_equality && $container_type_is_interface && !isset($intersection_container_types[$input_type_key])) { $any_inputs_contained = \true; } elseif (self::isIntersectionShallowlyContainedBy($codebase, $intersection_input_type, $intersection_container_type, $intersection_container_type_lower, $container_was_static, $allow_interface_equality, $atomic_comparison_result)) { $any_inputs_contained = \true; } } if (!$any_inputs_contained) { return \false; } } return \true; } /** * @param TNamedObject|TTemplateParam|TIterable $type_part * @return array */ private static function getIntersectionTypes(Atomic $type_part) : array { if (!$type_part->extra_types) { if ($type_part instanceof TTemplateParam) { $intersection_types = []; foreach ($type_part->as->getAtomicTypes() as $as_atomic_type) { // T1 as T2 as object becomes (T1 as object) & (T2 as object) if ($as_atomic_type instanceof TTemplateParam) { $intersection_types += self::getIntersectionTypes($as_atomic_type); $type_part = $type_part->replaceAs($as_atomic_type->as); $intersection_types[$type_part->getKey()] = $type_part; return $intersection_types; } } } return [$type_part->getKey() => $type_part]; } $extra_types = $type_part->extra_types; $type_part = $type_part->setIntersectionTypes([]); $extra_types[$type_part->getKey()] = $type_part; return $extra_types; } /** * @param TNamedObject|TTemplateParam|TIterable|TObjectWithProperties|TCallableObject $intersection_input_type * @param TNamedObject|TTemplateParam|TIterable|TObjectWithProperties|TCallableObject $intersection_container_type */ private static function isIntersectionShallowlyContainedBy(Codebase $codebase, Atomic $intersection_input_type, Atomic $intersection_container_type, ?string $intersection_container_type_lower, bool $container_was_static, bool $allow_interface_equality, ?\Psalm\Internal\Type\Comparator\TypeComparisonResult $atomic_comparison_result) : bool { if ($intersection_container_type instanceof TTemplateParam && $intersection_input_type instanceof TTemplateParam) { if (!$allow_interface_equality) { if (strpos($intersection_container_type->defining_class, 'fn-') === 0 || strpos($intersection_input_type->defining_class, 'fn-') === 0) { if (strpos($intersection_input_type->defining_class, 'fn-') === 0 && strpos($intersection_container_type->defining_class, 'fn-') === 0 && $intersection_input_type->defining_class !== $intersection_container_type->defining_class) { return \true; } foreach ($intersection_input_type->as->getAtomicTypes() as $input_as_atomic) { if ($input_as_atomic->equals($intersection_container_type, \false)) { return \true; } } } } if ($intersection_container_type->param_name === $intersection_input_type->param_name && $intersection_container_type->defining_class === $intersection_input_type->defining_class) { return \true; } if ($intersection_container_type->param_name !== $intersection_input_type->param_name || $intersection_container_type->defining_class !== $intersection_input_type->defining_class && strpos($intersection_input_type->defining_class, 'fn-') !== 0 && strpos($intersection_container_type->defining_class, 'fn-') !== 0) { if (strpos($intersection_input_type->defining_class, 'fn-') === 0 || strpos($intersection_container_type->defining_class, 'fn-') === 0) { return \false; } $input_class_storage = $codebase->classlike_storage_provider->get($intersection_input_type->defining_class); if (isset($input_class_storage->template_extended_params[$intersection_container_type->defining_class][$intersection_container_type->param_name])) { return \true; } } return \false; } if ($intersection_container_type instanceof TTemplateParam || $intersection_container_type_lower === null) { return \false; } if ($intersection_input_type instanceof TTemplateParam) { if ($intersection_container_type instanceof TNamedObject && $intersection_container_type->is_static) { // this is extra check is redundant since we're comparing to a template as type $intersection_container_type = new TNamedObject($intersection_container_type->value, \false, $intersection_container_type->definite_class, $intersection_container_type->extra_types); } return \Psalm\Internal\Type\Comparator\UnionTypeComparator::isContainedBy($codebase, $intersection_input_type->as, new Union([$intersection_container_type]), \false, \false, $atomic_comparison_result, $allow_interface_equality); } $input_was_static = \false; if ($intersection_input_type instanceof TIterable) { $intersection_input_type_lower = 'iterable'; } elseif ($intersection_input_type instanceof TObjectWithProperties) { $intersection_input_type_lower = 'object'; } elseif ($intersection_input_type instanceof TCallableObject) { $intersection_input_type_lower = 'callable-object'; } else { $input_was_static = $intersection_input_type->is_static; $intersection_input_type_lower = strtolower($codebase->classlikes->getUnAliasedName($intersection_input_type->value)); } if ($intersection_container_type_lower === $intersection_input_type_lower) { if ($container_was_static && !$input_was_static) { if ($atomic_comparison_result) { $atomic_comparison_result->type_coerced = \true; } return \false; } return \true; } if ($intersection_input_type_lower === 'generator' && in_array($intersection_container_type_lower, ['iterator', 'traversable', 'iterable'], \true)) { return \true; } if ($intersection_container_type_lower === 'iterable') { if ($intersection_input_type_lower === 'traversable' || $codebase->classlikes->classExists($intersection_input_type_lower) && $codebase->classlikes->classImplements($intersection_input_type_lower, 'Traversable') || $codebase->classlikes->interfaceExists($intersection_input_type_lower) && $codebase->classlikes->interfaceExtends($intersection_input_type_lower, 'Traversable')) { return \true; } } if ($intersection_input_type_lower === 'traversable' && $intersection_container_type_lower === 'iterable') { return \true; } $input_type_is_interface = $codebase->interfaceExists($intersection_input_type_lower); $container_type_is_interface = $codebase->interfaceExists($intersection_container_type_lower); if ($allow_interface_equality && $container_type_is_interface && $input_type_is_interface) { return \true; } if (($codebase->classExists($intersection_input_type_lower) || $codebase->classlikes->enumExists($intersection_input_type_lower)) && $codebase->classOrInterfaceExists($intersection_container_type_lower) && $codebase->classExtendsOrImplements($intersection_input_type_lower, $intersection_container_type_lower)) { if ($container_was_static && !$input_was_static) { if ($atomic_comparison_result) { $atomic_comparison_result->type_coerced = \true; } return \false; } return \true; } if ($input_type_is_interface && $codebase->interfaceExtends($intersection_input_type_lower, $intersection_container_type_lower)) { return \true; } if (ExpressionAnalyzer::isMock($intersection_input_type_lower)) { return \true; } return \false; } } getKeyedArray(); } if ($container_type_part instanceof TList) { $container_type_part = $container_type_part->getKeyedArray(); } if (($container_type_part instanceof TTemplateParam || $container_type_part instanceof TNamedObject && $container_type_part->extra_types) && ($input_type_part instanceof TTemplateParam || $input_type_part instanceof TNamedObject && $input_type_part->extra_types)) { return \Psalm\Internal\Type\Comparator\ObjectComparator::isShallowlyContainedBy($codebase, $input_type_part, $container_type_part, $allow_interface_equality, $atomic_comparison_result); } if ($input_type_part instanceof TValueOf) { if ($container_type_part instanceof TValueOf) { return \Psalm\Internal\Type\Comparator\UnionTypeComparator::isContainedBy($codebase, $input_type_part->type, $container_type_part->type, \false, \false, null, \false, \false); } elseif ($container_type_part instanceof Scalar) { return \Psalm\Internal\Type\Comparator\UnionTypeComparator::isContainedBy($codebase, TValueOf::getValueType($input_type_part->type, $codebase) ?? $input_type_part->type, new Union([$container_type_part]), \false, \false, null, \false, \false); } } if ($container_type_part instanceof TMixed || $container_type_part instanceof TTemplateParam && $container_type_part->as->isMixed() && !$container_type_part->extra_types && $input_type_part instanceof TMixed) { if (get_class($input_type_part) === TMixed::class && (get_class($container_type_part) === TEmptyMixed::class || get_class($container_type_part) === TNonEmptyMixed::class)) { if ($atomic_comparison_result) { $atomic_comparison_result->type_coerced = \true; $atomic_comparison_result->type_coerced_from_mixed = \true; } return \false; } return \true; } if ($input_type_part instanceof TNever) { return \true; } if ($input_type_part instanceof TMixed || $input_type_part instanceof TTemplateParam && $input_type_part->as->isMixed() && !$input_type_part->extra_types) { if ($atomic_comparison_result) { $atomic_comparison_result->type_coerced = \true; $atomic_comparison_result->type_coerced_from_mixed = \true; } return \false; } if ($input_type_part instanceof TNull) { if ($container_type_part instanceof TNull) { return \true; } if ($container_type_part instanceof TTemplateParam && ($container_type_part->as->isNullable() || $container_type_part->as->isMixed())) { return \true; } return \false; } if ($container_type_part instanceof TNull) { return \false; } if ($input_type_part instanceof Scalar && $container_type_part instanceof Scalar) { return \Psalm\Internal\Type\Comparator\ScalarTypeComparator::isContainedBy($codebase, $input_type_part, $container_type_part, $allow_interface_equality, $allow_float_int_equality, $atomic_comparison_result); } if ($input_type_part instanceof TCallableKeyedArray && $container_type_part instanceof TArray) { return \Psalm\Internal\Type\Comparator\ArrayTypeComparator::isContainedBy($codebase, $input_type_part, $container_type_part, $allow_interface_equality, $atomic_comparison_result); } if ($container_type_part instanceof TCallable && $input_type_part instanceof TCallableInterface || $container_type_part instanceof TClosure && $input_type_part instanceof TClosure) { return \Psalm\Internal\Type\Comparator\CallableTypeComparator::isContainedBy($codebase, $input_type_part, $container_type_part, $atomic_comparison_result); } if ($container_type_part instanceof TClosure) { if ($input_type_part instanceof TCallable) { if (\Psalm\Internal\Type\Comparator\CallableTypeComparator::isContainedBy($codebase, $input_type_part, $container_type_part, $atomic_comparison_result) === \false) { return \false; } if ($atomic_comparison_result) { $atomic_comparison_result->type_coerced = \true; } } return \false; } if ($container_type_part instanceof TCallable && $input_type_part instanceof TClosure) { return \Psalm\Internal\Type\Comparator\CallableTypeComparator::isContainedBy($codebase, $input_type_part, $container_type_part, $atomic_comparison_result); } if ($input_type_part instanceof TNamedObject && $input_type_part->value === 'Closure' && $container_type_part instanceof TCallable) { return \true; } if ($input_type_part instanceof TObject && $container_type_part instanceof TCallable) { return \true; } if ($input_type_part instanceof TCallableObject && $container_type_part instanceof TObject) { return \true; } if ($container_type_part instanceof TObjectWithProperties && $container_type_part->is_stringable_object_only) { if ($input_type_part instanceof TObjectWithProperties && $input_type_part->is_stringable_object_only || $input_type_part instanceof TNamedObject && $codebase->methodExists(new MethodIdentifier($input_type_part->value, '__tostring'))) { return \true; } return \false; } if ($container_type_part instanceof TNamedObject && $container_type_part->value === 'Stringable' && $codebase->analysis_php_version_id >= 80000 && $input_type_part instanceof TObjectWithProperties && $input_type_part->is_stringable_object_only) { return \true; } if ($container_type_part instanceof TKeyedArray && $input_type_part instanceof TKeyedArray || $container_type_part instanceof TObjectWithProperties && $input_type_part instanceof TObjectWithProperties) { return \Psalm\Internal\Type\Comparator\KeyedArrayComparator::isContainedBy($codebase, $input_type_part, $container_type_part, $allow_interface_equality, $atomic_comparison_result); } if ($container_type_part instanceof TObjectWithProperties && $input_type_part instanceof TObject && !$input_type_part instanceof TObjectWithProperties && !$input_type_part instanceof TCallableObject) { if ($atomic_comparison_result) { $atomic_comparison_result->type_coerced = \true; } return \false; } if (($input_type_part instanceof TArray || $input_type_part instanceof TKeyedArray || $input_type_part instanceof TClassStringMap) && ($container_type_part instanceof TArray || $container_type_part instanceof TKeyedArray || $container_type_part instanceof TClassStringMap)) { return \Psalm\Internal\Type\Comparator\ArrayTypeComparator::isContainedBy($codebase, $input_type_part, $container_type_part, $allow_interface_equality, $atomic_comparison_result); } if (get_class($container_type_part) === TNamedObject::class && $input_type_part instanceof TEnumCase && $input_type_part->value === $container_type_part->value) { return \true; } if (get_class($input_type_part) === TNamedObject::class && $container_type_part instanceof TEnumCase && $input_type_part->value === $container_type_part->value) { if ($atomic_comparison_result) { $atomic_comparison_result->type_coerced = \true; } return \true; } if ($container_type_part instanceof TEnumCase && $input_type_part instanceof TEnumCase) { return $container_type_part->value === $input_type_part->value && $container_type_part->case_name === $input_type_part->case_name; } if (($input_type_part instanceof TNamedObject || $input_type_part instanceof TTemplateParam && $input_type_part->as->hasObjectType() || $input_type_part instanceof TIterable) && ($container_type_part instanceof TNamedObject || $container_type_part instanceof TTemplateParam && $container_type_part->isObjectType() || $container_type_part instanceof TIterable) && \Psalm\Internal\Type\Comparator\ObjectComparator::isShallowlyContainedBy($codebase, $input_type_part, $container_type_part, $allow_interface_equality, $atomic_comparison_result)) { if ($container_type_part instanceof TGenericObject || $container_type_part instanceof TIterable) { return \Psalm\Internal\Type\Comparator\GenericTypeComparator::isContainedBy($codebase, $input_type_part, $container_type_part, $allow_interface_equality, $atomic_comparison_result); } if ($container_type_part instanceof TNamedObject && $input_type_part instanceof TNamedObject && $container_type_part->is_static && !$input_type_part->is_static) { if ($atomic_comparison_result) { $atomic_comparison_result->type_coerced = \true; } return \false; } if ($atomic_comparison_result) { $atomic_comparison_result->to_string_cast = \false; } return \true; } if (get_class($input_type_part) === TObject::class && get_class($container_type_part) === TObject::class) { return \true; } if ($container_type_part instanceof TTemplateKeyOf) { if (!$input_type_part instanceof TTemplateKeyOf) { return \false; } return \Psalm\Internal\Type\Comparator\UnionTypeComparator::isContainedBy($codebase, $input_type_part->as, $container_type_part->as); } if ($input_type_part instanceof TTemplateKeyOf) { $array_key_type = TKeyOf::getArrayKeyType($input_type_part->as); if ($array_key_type === null) { return \false; } foreach ($array_key_type->getAtomicTypes() as $array_key_atomic) { if (!self::isContainedBy($codebase, $array_key_atomic, $container_type_part, $allow_interface_equality, $allow_float_int_equality, $atomic_comparison_result)) { return \false; } } return \true; } if ($container_type_part instanceof TTemplateValueOf) { if (!$input_type_part instanceof TTemplateValueOf) { return \false; } return \Psalm\Internal\Type\Comparator\UnionTypeComparator::isContainedBy($codebase, $input_type_part->as, $container_type_part->as); } if ($input_type_part instanceof TTemplateValueOf) { $array_value_type = TValueOf::getValueType($input_type_part->as, $codebase); if ($array_value_type === null) { return \false; } foreach ($array_value_type->getAtomicTypes() as $array_value_atomic) { if (!self::isContainedBy($codebase, $array_value_atomic, $container_type_part, $allow_interface_equality, $allow_float_int_equality, $atomic_comparison_result)) { return \false; } } return \true; } if ($container_type_part instanceof TTemplateParam && $input_type_part instanceof TTemplateParam) { return \Psalm\Internal\Type\Comparator\UnionTypeComparator::isContainedBy($codebase, $input_type_part->as, $container_type_part->as, \false, \false, $atomic_comparison_result, $allow_interface_equality); } if ($container_type_part instanceof TTemplateParam) { foreach ($container_type_part->as->getAtomicTypes() as $container_as_type_part) { if (self::isContainedBy($codebase, $input_type_part, $container_as_type_part, $allow_interface_equality, $allow_float_int_equality, $atomic_comparison_result)) { if ($allow_interface_equality) { return \true; } } } return \false; } if ($container_type_part instanceof TConditional) { $atomic_types = array_merge(array_values($container_type_part->if_type->getAtomicTypes()), array_values($container_type_part->else_type->getAtomicTypes())); foreach ($atomic_types as $container_as_type_part) { if (self::isContainedBy($codebase, $input_type_part, $container_as_type_part, $allow_interface_equality, $allow_float_int_equality, $atomic_comparison_result)) { return \true; } } return \false; } if ($input_type_part instanceof TTemplateParam) { if ($input_type_part->extra_types) { foreach ($input_type_part->extra_types as $extra_type) { if (self::isContainedBy($codebase, $extra_type, $container_type_part, $allow_interface_equality, $allow_float_int_equality, $atomic_comparison_result)) { return \true; } } } foreach ($input_type_part->as->getAtomicTypes() as $input_as_type_part) { if (self::isContainedBy($codebase, $input_as_type_part, $container_type_part, $allow_interface_equality, $allow_float_int_equality, $atomic_comparison_result)) { return \true; } } return \false; } if ($input_type_part instanceof TConditional) { $input_atomic_types = array_merge(array_values($input_type_part->if_type->getAtomicTypes()), array_values($input_type_part->else_type->getAtomicTypes())); foreach ($input_atomic_types as $input_as_type_part) { if (self::isContainedBy($codebase, $input_as_type_part, $container_type_part, $allow_interface_equality, $allow_float_int_equality, $atomic_comparison_result)) { return \true; } } return \false; } if ($input_type_part instanceof TNamedObject && $input_type_part->value === 'static' && $container_type_part instanceof TNamedObject && strtolower($container_type_part->value) === 'self') { return \true; } if ($container_type_part instanceof TIterable) { if ($input_type_part instanceof TArray || $input_type_part instanceof TKeyedArray) { if ($input_type_part instanceof TKeyedArray) { $input_type_part = $input_type_part->getGenericArrayType(); } $all_types_contain = \true; foreach ($input_type_part->type_params as $i => $input_param) { $container_param_offset = $i - (2 - count($container_type_part->type_params)); $container_param = $container_type_part->type_params[$container_param_offset]; if ($i === 0 && $input_param->hasMixed() && $container_param->hasString() && $container_param->hasInt()) { continue; } $array_comparison_result = new \Psalm\Internal\Type\Comparator\TypeComparisonResult(); if (!$input_param->isNever()) { if (!\Psalm\Internal\Type\Comparator\UnionTypeComparator::isContainedBy($codebase, $input_param, $container_param, $input_param->ignore_nullable_issues, $input_param->ignore_falsable_issues, $array_comparison_result, $allow_interface_equality) && !$array_comparison_result->type_coerced_from_scalar) { if ($atomic_comparison_result && $array_comparison_result->type_coerced_from_mixed) { $atomic_comparison_result->type_coerced_from_mixed = \true; } $all_types_contain = \false; } else { if ($atomic_comparison_result) { $atomic_comparison_result->to_string_cast = $atomic_comparison_result->to_string_cast === \true || $array_comparison_result->to_string_cast === \true; } } } } return $all_types_contain; } if ($input_type_part->hasTraversableInterface($codebase)) { return \true; } } if ($container_type_part instanceof TString || $container_type_part instanceof TScalar) { if ($input_type_part instanceof TNamedObject) { // check whether the object has a __toString method if ($codebase->classOrInterfaceExists($input_type_part->value)) { if ($codebase->analysis_php_version_id >= 80000 && ($input_type_part->value === 'Stringable' || $codebase->classlikes->classExists($input_type_part->value) && $codebase->classlikes->classImplements($input_type_part->value, 'Stringable') || $codebase->classlikes->interfaceExtends($input_type_part->value, 'Stringable'))) { if ($atomic_comparison_result) { $atomic_comparison_result->to_string_cast = \true; } return \true; } if ($codebase->methods->methodExists(new MethodIdentifier($input_type_part->value, '__tostring'))) { if ($atomic_comparison_result) { $atomic_comparison_result->to_string_cast = \true; } return \true; } } // PHP 5.6 doesn't support this natively, so this introduces a bug *just* when checking PHP 5.6 code if ($input_type_part->value === 'ReflectionType') { if ($atomic_comparison_result) { $atomic_comparison_result->to_string_cast = \true; } return \true; } } elseif ($input_type_part instanceof TObjectWithProperties && isset($input_type_part->methods['__tostring'])) { if ($atomic_comparison_result) { $atomic_comparison_result->to_string_cast = \true; } return \true; } } if ($container_type_part instanceof TCallable && ($input_type_part instanceof TLiteralString || $input_type_part instanceof TCallableString || $input_type_part instanceof TArray || $input_type_part instanceof TKeyedArray || $input_type_part instanceof TNamedObject && $codebase->classOrInterfaceExists($input_type_part->value) && $codebase->methodExists($input_type_part->value . '::__invoke'))) { return \Psalm\Internal\Type\Comparator\CallableTypeComparator::isNotExplicitlyCallableTypeCallable($codebase, $input_type_part, $container_type_part, $atomic_comparison_result); } if ($container_type_part instanceof TObject && $input_type_part instanceof TNamedObject) { if ($container_type_part instanceof TObjectWithProperties && $input_type_part->value !== 'stdClass') { return \Psalm\Internal\Type\Comparator\KeyedArrayComparator::isContainedByObjectWithProperties($codebase, $input_type_part, $container_type_part, $allow_interface_equality, $atomic_comparison_result); } return \true; } if ($container_type_part instanceof TNamedObject && $input_type_part instanceof TNamedObject && $container_type_part->is_static && !$input_type_part->is_static) { if ($atomic_comparison_result) { $atomic_comparison_result->type_coerced = \true; } return \false; } if ($input_type_part instanceof TObject && $container_type_part instanceof TNamedObject) { if ($atomic_comparison_result) { $atomic_comparison_result->type_coerced = \true; } return \false; } if ($container_type_part instanceof TNamedObject && $input_type_part instanceof TNamedObject && $codebase->classOrInterfaceOrEnumExists($input_type_part->value) && ($codebase->classExists($container_type_part->value) && $codebase->classExtendsOrImplements($container_type_part->value, $input_type_part->value) || $codebase->interfaceExists($container_type_part->value) && $codebase->interfaceExtends($container_type_part->value, $input_type_part->value))) { if ($atomic_comparison_result) { $atomic_comparison_result->type_coerced = \true; } return \false; } return $input_type_part->getKey() === $container_type_part->getKey(); } /** * @psalm-assert-if-true TKeyedArray $array */ public static function isLegacyTListLike(Atomic $array) : bool { return $array instanceof TKeyedArray && $array->is_list && $array->fallback_params && count($array->properties) === 1 && $array->properties[0]->possibly_undefined && $array->properties[0]->equals($array->fallback_params[1], \true, \true, \false); } /** * @psalm-assert-if-true TKeyedArray $array */ public static function isLegacyTNonEmptyListLike(Atomic $array) : bool { return $array instanceof TKeyedArray && $array->is_list && $array->fallback_params && count($array->properties) === 1 && !$array->properties[0]->possibly_undefined && $array->properties[0]->equals($array->fallback_params[1]); } /** * Does the input param atomic type match the given param atomic type */ public static function canBeIdentical(Codebase $codebase, Atomic $type1_part, Atomic $type2_part, bool $allow_interface_equality = \true) : bool { if ($type1_part instanceof TList) { $type1_part = $type1_part->getKeyedArray(); } if ($type2_part instanceof TList) { $type2_part = $type2_part->getKeyedArray(); } if (self::isLegacyTListLike($type1_part) && self::isLegacyTNonEmptyListLike($type2_part) || self::isLegacyTListLike($type2_part) && self::isLegacyTNonEmptyListLike($type1_part)) { assert($type1_part->fallback_params !== null); assert($type2_part->fallback_params !== null); return \Psalm\Internal\Type\Comparator\UnionTypeComparator::canExpressionTypesBeIdentical($codebase, $type1_part->fallback_params[1], $type2_part->fallback_params[1]); } if (get_class($type1_part) === TArray::class && $type2_part instanceof TNonEmptyArray || get_class($type2_part) === TArray::class && $type1_part instanceof TNonEmptyArray) { return \Psalm\Internal\Type\Comparator\UnionTypeComparator::canExpressionTypesBeIdentical($codebase, $type1_part->type_params[0], $type2_part->type_params[0]) && \Psalm\Internal\Type\Comparator\UnionTypeComparator::canExpressionTypesBeIdentical($codebase, $type1_part->type_params[1], $type2_part->type_params[1]); } $first_comparison_result = new \Psalm\Internal\Type\Comparator\TypeComparisonResult(); $second_comparison_result = new \Psalm\Internal\Type\Comparator\TypeComparisonResult(); return self::isContainedBy($codebase, $type1_part, $type2_part, $allow_interface_equality, \false, $first_comparison_result) && !$first_comparison_result->to_string_cast || self::isContainedBy($codebase, $type2_part, $type1_part, $allow_interface_equality, \false, $second_comparison_result) && !$second_comparison_result->to_string_cast || $first_comparison_result->type_coerced && $second_comparison_result->type_coerced; } } type_coerced = \true; } return \false; } if ($container_type_part instanceof TNonspecificLiteralString && ($input_type_part instanceof TLiteralString || $input_type_part instanceof TNonspecificLiteralString)) { if ($container_type_part instanceof TNonEmptyNonspecificLiteralString) { return $input_type_part instanceof TLiteralString && $input_type_part->value !== '' || $input_type_part instanceof TNonEmptyNonspecificLiteralString; } return \true; } if ($container_type_part instanceof TNonspecificLiteralString) { if ($input_type_part instanceof TString) { if ($atomic_comparison_result) { $atomic_comparison_result->type_coerced = \true; } } return \false; } if ($container_type_part instanceof TNonspecificLiteralInt && ($input_type_part instanceof TLiteralInt || $input_type_part instanceof TNonspecificLiteralInt)) { return \true; } if ($container_type_part instanceof TNonspecificLiteralInt) { if ($input_type_part instanceof TInt) { if ($atomic_comparison_result) { $atomic_comparison_result->type_coerced = \true; } } return \false; } if ($input_type_part instanceof TCallableString) { if (get_class($container_type_part) === TNonEmptyString::class || get_class($container_type_part) === TNonFalsyString::class) { return \true; } if (get_class($container_type_part) === TLowercaseString::class || get_class($container_type_part) === TSingleLetter::class) { if ($atomic_comparison_result) { $atomic_comparison_result->type_coerced = \true; } return \false; } } if (($container_type_part instanceof TLowercaseString || $container_type_part instanceof TNonEmptyLowercaseString) && $input_type_part instanceof TString) { if ($input_type_part instanceof TLowercaseString && $container_type_part instanceof TLowercaseString || $input_type_part instanceof TNonEmptyLowercaseString && $container_type_part instanceof TNonEmptyLowercaseString) { return \true; } if ($input_type_part instanceof TNonEmptyLowercaseString && $container_type_part instanceof TLowercaseString) { return \true; } if ($input_type_part instanceof TLowercaseString && $container_type_part instanceof TNonEmptyLowercaseString) { if ($atomic_comparison_result) { $atomic_comparison_result->type_coerced = \true; } return \false; } if ($input_type_part instanceof TLiteralString) { if (strtolower($input_type_part->value) === $input_type_part->value) { return $input_type_part->value || $container_type_part instanceof TLowercaseString; } return \false; } if ($input_type_part instanceof TClassString) { return \false; } if ($atomic_comparison_result) { $atomic_comparison_result->type_coerced = \true; } return \false; } if ($container_type_part instanceof TDependentGetClass) { $first_type = $container_type_part->as_type->getSingleAtomic(); $container_type_part = new TClassString('object', $first_type instanceof TNamedObject ? $first_type : null); } if ($input_type_part instanceof TDependentGetClass) { $first_type = $input_type_part->as_type->getSingleAtomic(); if ($first_type instanceof TTemplateParam) { $object_type = $first_type->as->getSingleAtomic(); $input_type_part = new TTemplateParamClass($first_type->param_name, $first_type->as->getId(), $object_type instanceof TNamedObject ? $object_type : null, $first_type->defining_class); } else { $input_type_part = new TClassString('object', $first_type instanceof TNamedObject ? $first_type : null); } } if ($input_type_part instanceof TDependentGetType) { $input_type_part = new TString(); if ($container_type_part instanceof TLiteralString) { return isset(ClassLikeAnalyzer::GETTYPE_TYPES[$container_type_part->value]); } } if ($container_type_part instanceof TDependentGetDebugType) { return $input_type_part instanceof TString; } if ($input_type_part instanceof TDependentGetDebugType) { $input_type_part = new TString(); } if ($container_type_part instanceof TDependentGetType) { $container_type_part = new TString(); if ($input_type_part instanceof TLiteralString) { return isset(ClassLikeAnalyzer::GETTYPE_TYPES[$input_type_part->value]); } } if ($input_type_part instanceof TFalse && $container_type_part instanceof TBool && !$container_type_part instanceof TTrue) { return \true; } if ($input_type_part instanceof TTrue && $container_type_part instanceof TBool && !$container_type_part instanceof TFalse) { return \true; } // from https://wiki.php.net/rfc/scalar_type_hints_v5: // // > int types can resolve a parameter type of float if ($input_type_part instanceof TInt && $container_type_part instanceof TFloat && !$container_type_part instanceof TLiteralFloat && $allow_float_int_equality) { return \true; } if ($container_type_part instanceof TArrayKey && $input_type_part instanceof TNumeric) { return \true; } if ($container_type_part instanceof TArrayKey && ($input_type_part instanceof TInt || $input_type_part instanceof TString)) { return \true; } if ($input_type_part instanceof TArrayKey && ($container_type_part instanceof TInt || $container_type_part instanceof TString)) { if ($atomic_comparison_result) { $atomic_comparison_result->type_coerced = \true; $atomic_comparison_result->type_coerced_from_mixed = \true; $atomic_comparison_result->scalar_type_match_found = !$container_type_part->from_docblock; } return \false; } if ($container_type_part instanceof TScalar && $input_type_part instanceof Scalar) { return \true; } if (get_class($container_type_part) === TFloat::class && $input_type_part instanceof TLiteralFloat) { return \true; } if ((get_class($container_type_part) === TNonEmptyString::class || get_class($container_type_part) === TNonEmptyNonspecificLiteralString::class) && $input_type_part instanceof TNonFalsyString) { return \true; } if ($container_type_part instanceof TNonFalsyString && $input_type_part instanceof TNonFalsyString) { return \true; } if ($container_type_part instanceof TNonFalsyString && ($input_type_part instanceof TNonEmptyString || $input_type_part instanceof TNonEmptyNonspecificLiteralString)) { if ($atomic_comparison_result) { $atomic_comparison_result->type_coerced = \true; } return \false; } if ($container_type_part instanceof TNonEmptyString && $input_type_part instanceof TLiteralString && $input_type_part->value === '') { return \false; } if ($container_type_part instanceof TNonFalsyString && $input_type_part instanceof TLiteralString && $input_type_part->value === '0') { return \false; } if ((get_class($container_type_part) === TNonEmptyString::class || get_class($container_type_part) === TNonFalsyString::class || get_class($container_type_part) === TSingleLetter::class) && $input_type_part instanceof TLiteralString) { return \true; } if (get_class($input_type_part) === TInt::class && $container_type_part instanceof TLiteralInt) { if ($atomic_comparison_result) { $atomic_comparison_result->type_coerced = \true; $atomic_comparison_result->type_coerced_from_scalar = \true; } return \false; } if ($input_type_part instanceof TIntRange && $container_type_part instanceof TIntRange) { return \Psalm\Internal\Type\Comparator\IntegerRangeComparator::isContainedBy($input_type_part, $container_type_part); } if ($input_type_part instanceof TInt && $container_type_part instanceof TIntRange) { if ($input_type_part instanceof TLiteralInt) { $min_bound = $container_type_part->min_bound; $max_bound = $container_type_part->max_bound; return ($min_bound === null || $min_bound <= $input_type_part->value) && ($max_bound === null || $max_bound >= $input_type_part->value); } //any int can't be pushed inside a range without coercion (unless the range is from min to max) if ($container_type_part->min_bound !== null || $container_type_part->max_bound !== null) { if ($atomic_comparison_result) { $atomic_comparison_result->type_coerced = \true; $atomic_comparison_result->type_coerced_from_scalar = \true; } } return \false; } if (get_class($input_type_part) === TFloat::class && $container_type_part instanceof TLiteralFloat) { if ($atomic_comparison_result) { $atomic_comparison_result->type_coerced = \true; $atomic_comparison_result->type_coerced_from_scalar = \true; } return \false; } if ((get_class($input_type_part) === TString::class || get_class($input_type_part) === TSingleLetter::class || $input_type_part instanceof TNonEmptyString || $input_type_part instanceof TNonspecificLiteralString) && $container_type_part instanceof TLiteralString) { if ($atomic_comparison_result) { $atomic_comparison_result->type_coerced = \true; $atomic_comparison_result->type_coerced_from_scalar = \true; } return \false; } if (($input_type_part instanceof TLowercaseString || $input_type_part instanceof TNonEmptyLowercaseString) && $container_type_part instanceof TLiteralString && strtolower($container_type_part->value) === $container_type_part->value) { if ($atomic_comparison_result && $container_type_part->value) { $atomic_comparison_result->type_coerced = \true; $atomic_comparison_result->type_coerced_from_scalar = \true; } return \false; } if (($container_type_part instanceof TClassString || $container_type_part instanceof TLiteralClassString) && ($input_type_part instanceof TClassString || $input_type_part instanceof TLiteralClassString)) { return \Psalm\Internal\Type\Comparator\ClassLikeStringComparator::isContainedBy($codebase, $input_type_part, $container_type_part, $allow_interface_equality, $atomic_comparison_result); } if ($container_type_part instanceof TString && $input_type_part instanceof TTraitString) { return \true; } if ($container_type_part instanceof TTraitString && (get_class($input_type_part) === TString::class || $input_type_part instanceof TNonEmptyString || $input_type_part instanceof TNonEmptyNonspecificLiteralString)) { if ($atomic_comparison_result) { $atomic_comparison_result->type_coerced = \true; } return \false; } if (($input_type_part instanceof TClassString || $input_type_part instanceof TLiteralClassString) && (get_class($container_type_part) === TSingleLetter::class || get_class($container_type_part) === TNonEmptyString::class || get_class($container_type_part) === TNonFalsyString::class)) { return \true; } if ($input_type_part instanceof TNumericString && get_class($container_type_part) === TNonEmptyString::class) { return \true; } if ($container_type_part instanceof TString && $input_type_part instanceof TNumericString) { if ($container_type_part instanceof TLiteralString) { if (is_numeric($container_type_part->value) && $atomic_comparison_result) { $atomic_comparison_result->type_coerced = \true; } return \false; } return \true; } if ($input_type_part instanceof TString && $container_type_part instanceof TNumericString) { if ($input_type_part instanceof TLiteralString) { return is_numeric($input_type_part->value); } if ($atomic_comparison_result) { $atomic_comparison_result->type_coerced = \true; } return \false; } if ($container_type_part instanceof TCallableString && $input_type_part instanceof TLiteralString) { $input_callable = \Psalm\Internal\Type\Comparator\CallableTypeComparator::getCallableFromAtomic($codebase, $input_type_part); $container_callable = \Psalm\Internal\Type\Comparator\CallableTypeComparator::getCallableFromAtomic($codebase, $container_type_part); if ($input_callable && $container_callable) { if (\Psalm\Internal\Type\Comparator\CallableTypeComparator::isContainedBy($codebase, $input_callable, $container_callable, $atomic_comparison_result ?? new \Psalm\Internal\Type\Comparator\TypeComparisonResult()) === \false) { return \false; } } if (!$input_callable) { //we could not find a callable for the input type, so the input is not contained in the container return \false; } return \true; } if ($input_type_part instanceof TLowercaseString && get_class($container_type_part) === TNonEmptyString::class) { return \false; } if ($input_type_part->getKey() === $container_type_part->getKey()) { return \true; } if (($container_type_part instanceof TClassString || $container_type_part instanceof TLiteralClassString || $container_type_part instanceof TCallableString) && $input_type_part instanceof TString) { if ($atomic_comparison_result) { $atomic_comparison_result->type_coerced = \true; } return \false; } if ($container_type_part instanceof TNumeric && $input_type_part->isNumericType()) { return \true; } if ($input_type_part instanceof TNumeric) { if ($container_type_part->isNumericType()) { if ($atomic_comparison_result) { $atomic_comparison_result->type_coerced = \true; $atomic_comparison_result->scalar_type_match_found = !$container_type_part->from_docblock; } } } if (!$container_type_part instanceof TLiteralInt && !$container_type_part instanceof TLiteralString && !$container_type_part instanceof TLiteralFloat) { if ($atomic_comparison_result) { $atomic_comparison_result->type_coerced = $atomic_comparison_result->type_coerced_from_scalar = $input_type_part instanceof TScalar; $atomic_comparison_result->scalar_type_match_found = !$container_type_part->from_docblock; } } return \false; } } value === $input_type_part->value; } if ($container_type_part instanceof TTemplateParamClass && get_class($input_type_part) === TClassString::class) { if ($atomic_comparison_result) { $atomic_comparison_result->type_coerced = \true; } return \false; } if ($container_type_part instanceof TClassString && $container_type_part->as === 'object' && !$container_type_part->as_type) { return \true; } if ($input_type_part instanceof TClassString && $input_type_part->as === 'object' && !$input_type_part->as_type) { if ($atomic_comparison_result) { $atomic_comparison_result->type_coerced = \true; $atomic_comparison_result->type_coerced_from_scalar = \true; } return \false; } $fake_container_object = $container_type_part instanceof TClassString && $container_type_part->as_type ? $container_type_part->as_type : new TNamedObject($container_type_part instanceof TClassString ? $container_type_part->as : $container_type_part->value); $fake_input_object = $input_type_part instanceof TClassString && $input_type_part->as_type ? $input_type_part->as_type : new TNamedObject($input_type_part instanceof TClassString ? $input_type_part->as : $input_type_part->value); $isContainedBy = \Psalm\Internal\Type\Comparator\AtomicTypeComparator::isContainedBy($codebase, $fake_input_object, $fake_container_object, $allow_interface_equality, \false, $atomic_comparison_result); if ($atomic_comparison_result && $atomic_comparison_result->replacement_atomic_type instanceof TNamedObject) { $atomic_comparison_result->replacement_atomic_type = new TClassString('object', $atomic_comparison_result->replacement_atomic_type); } return $isContainedBy; } } extra_types && !$input_type_part instanceof TIterable) { $container_type_part = new TGenericObject('Traversable', $container_type_part->type_params); $container_was_iterable = \true; } if (!$input_type_part instanceof TNamedObject && !$input_type_part instanceof TIterable) { if ($atomic_comparison_result) { $atomic_comparison_result->type_coerced = \true; $atomic_comparison_result->type_coerced_from_mixed = \true; } return \false; } $container_type_params_covariant = []; $input_type_params = TemplateStandinTypeReplacer::getMappedGenericTypeParams($codebase, $input_type_part, $container_type_part, $container_type_params_covariant); $atomic_comparison_result_type_params = null; if ($atomic_comparison_result) { if (!$atomic_comparison_result->replacement_atomic_type) { $atomic_comparison_result->replacement_atomic_type = $input_type_part; } if ($atomic_comparison_result->replacement_atomic_type instanceof TGenericObject) { $atomic_comparison_result_type_params = $atomic_comparison_result->replacement_atomic_type->type_params; } } foreach ($input_type_params as $i => $input_param) { if (!isset($container_type_part->type_params[$i])) { break; } $container_param = $container_type_part->type_params[$i]; if ($input_param->isNever()) { if ($atomic_comparison_result_type_params !== null) { $atomic_comparison_result_type_params[$i] = $container_param; } continue; } $param_comparison_result = new \Psalm\Internal\Type\Comparator\TypeComparisonResult(); if (!\Psalm\Internal\Type\Comparator\UnionTypeComparator::isContainedBy($codebase, $input_param, $container_param, $input_param->ignore_nullable_issues, $input_param->ignore_falsable_issues, $param_comparison_result, $allow_interface_equality)) { if ($input_type_part->value === 'Generator' && $i === 2 && $param_comparison_result->type_coerced_from_mixed) { continue; } if ($atomic_comparison_result) { $atomic_comparison_result->type_coerced = $param_comparison_result->type_coerced === \true && $atomic_comparison_result->type_coerced !== \false; $atomic_comparison_result->type_coerced_from_mixed = $param_comparison_result->type_coerced_from_mixed === \true && $atomic_comparison_result->type_coerced_from_mixed !== \false; $atomic_comparison_result->type_coerced_from_as_mixed = !$container_was_iterable && $param_comparison_result->type_coerced_from_as_mixed === \true && $atomic_comparison_result->type_coerced_from_as_mixed !== \false; $atomic_comparison_result->to_string_cast = $param_comparison_result->to_string_cast === \true && $atomic_comparison_result->to_string_cast !== \false; $atomic_comparison_result->type_coerced_from_scalar = $param_comparison_result->type_coerced_from_scalar === \true && $atomic_comparison_result->type_coerced_from_scalar !== \false; $atomic_comparison_result->scalar_type_match_found = $param_comparison_result->scalar_type_match_found === \true && $atomic_comparison_result->scalar_type_match_found !== \false; } // if the container was an iterable then there was no mapping // from a template type if ($container_was_iterable || !$param_comparison_result->type_coerced_from_as_mixed) { $all_types_contain = \false; } } elseif (!$input_type_part instanceof TIterable && !$container_type_part instanceof TIterable && !$container_param->hasTemplate() && !$input_param->hasTemplate()) { if ($input_param->containsAnyLiteral()) { if ($atomic_comparison_result_type_params !== null) { $atomic_comparison_result_type_params[$i] = $container_param; } } else { if (!($container_type_params_covariant[$i] ?? \false) && !$container_param->had_template) { // Make sure types are basically the same if (!\Psalm\Internal\Type\Comparator\UnionTypeComparator::isContainedBy($codebase, $container_param, $input_param, $container_param->ignore_nullable_issues, $container_param->ignore_falsable_issues, $param_comparison_result, $allow_interface_equality) || $param_comparison_result->type_coerced) { if ($container_param->hasStaticObject() && $input_param->isStaticObject()) { // do nothing } else { $all_types_contain = \false; if ($atomic_comparison_result) { $atomic_comparison_result->type_coerced = \false; } } } } } } } if ($atomic_comparison_result && $atomic_comparison_result->replacement_atomic_type instanceof TGenericObject && $atomic_comparison_result_type_params) { /** @psalm-suppress ArgumentTypeCoercion Psalm bug */ $atomic_comparison_result->replacement_atomic_type = $atomic_comparison_result->replacement_atomic_type->setTypeParams($atomic_comparison_result_type_params); } if ($all_types_contain) { if ($atomic_comparison_result) { $atomic_comparison_result->to_string_cast = \false; } return \true; } return \false; } } min_bound === null; $is_input_max = $input_type_part->max_bound === null; $is_container_min = $container_type_part->min_bound === null; $is_container_max = $container_type_part->max_bound === null; $is_input_min_in_container = $is_container_min || !$is_input_min && $container_type_part->min_bound <= $input_type_part->min_bound; $is_input_max_in_container = $is_container_max || !$is_input_max && $container_type_part->max_bound >= $input_type_part->max_bound; return $is_input_min_in_container && $is_input_max_in_container; } /** * This method is used to check if an integer range can be contained by multiple int types * Worst case scenario, the input is `int<-50,max>` and container is `-50|int<-49,50>|positive-int|57` */ public static function isContainedByUnion(TIntRange $input_type_part, Union $container_type) : bool { $container_atomic_types = $container_type->getAtomicTypes(); $reduced_range = new TIntRange($input_type_part->min_bound, $input_type_part->max_bound, $input_type_part->from_docblock); if (isset($container_atomic_types['int'])) { if (get_class($container_atomic_types['int']) === TInt::class) { return \true; } if (get_class($container_atomic_types['int']) === TNonspecificLiteralInt::class) { return \true; } throw new UnexpectedValueException('Should not happen: unknown int key'); } $new_nb_atomics = count($container_atomic_types); //loop until we get to a stable situation. Either we can't remove atomics or we have a definite result do { $nb_atomics = $new_nb_atomics; $result_reduction = self::reduceRangeIncrementally($container_atomic_types, $reduced_range); $new_nb_atomics = count($container_atomic_types); } while ($result_reduction === null && $nb_atomics !== $new_nb_atomics); if ($result_reduction === null && $nb_atomics === 0) { //the range could not be reduced enough and there is no more atomics, it's not contained return \false; } return $result_reduction ?? \false; } /** * This method receives an array of atomics from the container and a range. * The goal is to use values in atomics in order to reduce the range. * Once the range is empty, it means that every value in range was covered by some atomics combination * * @psalm-suppress InaccessibleProperty $reduced_range was just re-created * @param array $container_atomic_types */ private static function reduceRangeIncrementally(array &$container_atomic_types, TIntRange $reduced_range) : ?bool { foreach ($container_atomic_types as $key => $container_atomic_type) { if ($container_atomic_type instanceof TIntRange) { if (self::isContainedBy($reduced_range, $container_atomic_type)) { if ($container_atomic_type->max_bound === null && $container_atomic_type->min_bound === null) { //this container range covers any integer return \true; } if ($container_atomic_type->max_bound === null) { //this container range is int //X-1 becomes the max of our reduced range if it was higher $reduced_range->max_bound = TIntRange::getNewLowestBound($container_atomic_type->min_bound - 1, $reduced_range->max_bound ?? $container_atomic_type->min_bound - 1); unset($container_atomic_types[$key]); //we don't need this one anymore continue; } if ($container_atomic_type->min_bound === null) { //this container range is int //X+1 becomes the min of our reduced range if it was lower $reduced_range->min_bound = TIntRange::getNewHighestBound($container_atomic_type->max_bound + 1, $reduced_range->min_bound ?? $container_atomic_type->max_bound + 1); unset($container_atomic_types[$key]); //we don't need this one anymore continue; } //if the container range has no 'null' bound, it's more complex //in this case, we can only reduce if the container include one bound of our reduced range if ($reduced_range->min_bound !== null && $container_atomic_type->contains($reduced_range->min_bound)) { //this container range is int and contains the min of our reduced range. //the min from our reduced range becomes Y + 1 $reduced_range->min_bound = $container_atomic_type->max_bound + 1; unset($container_atomic_types[$key]); //we don't need this one anymore } elseif ($reduced_range->max_bound !== null && $container_atomic_type->contains($reduced_range->max_bound)) { //this container range is int and contains the max of our reduced range. //the max from our reduced range becomes X - 1 $reduced_range->max_bound = $container_atomic_type->min_bound - 1; unset($container_atomic_types[$key]); //we don't need this one anymore } //there is probably a case here where we could unset containers when they're not at all in our range } else { //the range in input is wider than container, we return false return \false; } } elseif ($container_atomic_type instanceof TLiteralInt) { if (!$reduced_range->contains($container_atomic_type->value)) { unset($container_atomic_types[$key]); //we don't need this one anymore } elseif ($reduced_range->min_bound === $container_atomic_type->value) { $reduced_range->min_bound++; unset($container_atomic_types[$key]); //we don't need this one anymore } elseif ($reduced_range->max_bound === $container_atomic_type->value) { $reduced_range->max_bound--; unset($container_atomic_types[$key]); //we don't need this one anymore } } } //there is probably a case here if we're left only with TLiteralInt where we could return false if there's less //of them than numbers in the reduced range //there is also a case where if there's not TLiteralInt anymore and we're left with TIntRange that don't contain //bounds from our reduced range where we could return false //if our reduced range has its min bound superior to its max bound, it means the container covers it all. if ($reduced_range->min_bound !== null && $reduced_range->max_bound !== null && $reduced_range->min_bound > $reduced_range->max_bound) { return \true; } //if we didn't return true or false before then the result is inconclusive for this round return null; } } fallback_params === null; if ($container_sealed && $input_type_part instanceof TKeyedArray && $input_type_part->fallback_params !== null) { return \false; } if ($container_type_part instanceof TKeyedArray && $container_type_part->is_list && $input_type_part instanceof TKeyedArray && !$input_type_part->is_list) { if ($atomic_comparison_result) { $atomic_comparison_result->type_coerced = \true; } return \false; } $all_types_contain = \true; $input_properties = $input_type_part->properties; foreach ($container_type_part->properties as $key => $container_property_type) { if (!isset($input_properties[$key])) { if (!$container_property_type->possibly_undefined) { $all_types_contain = \false; } continue; } if ($input_properties[$key]->possibly_undefined && !$container_property_type->possibly_undefined) { $all_types_contain = \false; continue; } $input_property_type = $input_properties[$key]; unset($input_properties[$key]); $property_type_comparison = new \Psalm\Internal\Type\Comparator\TypeComparisonResult(); if (!$input_property_type->isNever()) { $is_input_containedby_container = \Psalm\Internal\Type\Comparator\UnionTypeComparator::isContainedBy($codebase, $input_property_type, $container_property_type, $input_property_type->ignore_nullable_issues, $input_property_type->ignore_falsable_issues, $property_type_comparison, $allow_interface_equality); if (!$is_input_containedby_container) { if ($atomic_comparison_result) { $atomic_comparison_result->type_coerced = $property_type_comparison->type_coerced === \true && $atomic_comparison_result->type_coerced !== \false; if (!$property_type_comparison->type_coerced_from_scalar && !$atomic_comparison_result->type_coerced) { //if we didn't detect a coercion, we try to compare the other way around $inverse_property_type_comparison = new \Psalm\Internal\Type\Comparator\TypeComparisonResult(); if (\Psalm\Internal\Type\Comparator\UnionTypeComparator::isContainedBy($codebase, $container_property_type, $input_property_type, \false, \false, $inverse_property_type_comparison, $allow_interface_equality) || $inverse_property_type_comparison->type_coerced_from_scalar) { $atomic_comparison_result->type_coerced = \true; } } $atomic_comparison_result->type_coerced_from_mixed = $property_type_comparison->type_coerced_from_mixed === \true && $atomic_comparison_result->type_coerced_from_mixed !== \false; $atomic_comparison_result->type_coerced_from_as_mixed = $property_type_comparison->type_coerced_from_as_mixed === \true && $atomic_comparison_result->type_coerced_from_as_mixed !== \false; $atomic_comparison_result->type_coerced_from_scalar = $property_type_comparison->type_coerced_from_scalar === \true && $atomic_comparison_result->type_coerced_from_scalar !== \false; $atomic_comparison_result->scalar_type_match_found = $property_type_comparison->scalar_type_match_found === \true && $atomic_comparison_result->scalar_type_match_found !== \false; if ($property_type_comparison->missing_shape_fields) { $atomic_comparison_result->missing_shape_fields = $property_type_comparison->missing_shape_fields; } } $all_types_contain = \false; } else { if ($atomic_comparison_result) { $atomic_comparison_result->to_string_cast = $atomic_comparison_result->to_string_cast === \true || $property_type_comparison->to_string_cast === \true; } } } } if ($container_sealed && $input_properties) { if ($atomic_comparison_result) { $atomic_comparison_result->missing_shape_fields = array_keys($input_properties); } return \false; } // check remaining $input_properties against container's fallback_params if ($container_type_part instanceof TKeyedArray && $container_type_part->fallback_params !== null) { [$key_type, $value_type] = $container_type_part->fallback_params; // treat fallback params as possibly undefined // otherwise comparison below would fail for list{0?:int} <=> list{..., int>} // as the latter `int` is not marked as possibly_undefined $value_type = $value_type->setPossiblyUndefined(\true); foreach ($input_properties as $key => $input_property_type) { $key_type_comparison = new \Psalm\Internal\Type\Comparator\TypeComparisonResult(); if (!\Psalm\Internal\Type\Comparator\UnionTypeComparator::isContainedBy($codebase, is_string($key) ? Type::getString($key) : Type::getInt(\false, $key), $key_type, \false, \false, $key_type_comparison, $allow_interface_equality)) { if ($atomic_comparison_result) { $atomic_comparison_result->type_coerced = $key_type_comparison->type_coerced === \true && $atomic_comparison_result->type_coerced !== \false; $atomic_comparison_result->type_coerced_from_mixed = $key_type_comparison->type_coerced_from_mixed === \true && $atomic_comparison_result->type_coerced_from_mixed !== \false; $atomic_comparison_result->type_coerced_from_as_mixed = $key_type_comparison->type_coerced_from_as_mixed === \true && $atomic_comparison_result->type_coerced_from_as_mixed !== \false; $atomic_comparison_result->type_coerced_from_scalar = $key_type_comparison->type_coerced_from_scalar === \true && $atomic_comparison_result->type_coerced_from_scalar !== \false; $atomic_comparison_result->scalar_type_match_found = $key_type_comparison->scalar_type_match_found === \true && $atomic_comparison_result->scalar_type_match_found !== \false; } $all_types_contain = \false; } $property_type_comparison = new \Psalm\Internal\Type\Comparator\TypeComparisonResult(); if (!\Psalm\Internal\Type\Comparator\UnionTypeComparator::isContainedBy($codebase, $input_property_type, $value_type, \false, \false, $property_type_comparison, $allow_interface_equality)) { if ($atomic_comparison_result) { $atomic_comparison_result->type_coerced = $property_type_comparison->type_coerced === \true && $atomic_comparison_result->type_coerced !== \false; $atomic_comparison_result->type_coerced_from_mixed = $property_type_comparison->type_coerced_from_mixed === \true && $atomic_comparison_result->type_coerced_from_mixed !== \false; $atomic_comparison_result->type_coerced_from_as_mixed = $property_type_comparison->type_coerced_from_as_mixed === \true && $atomic_comparison_result->type_coerced_from_as_mixed !== \false; $atomic_comparison_result->type_coerced_from_scalar = $property_type_comparison->type_coerced_from_scalar === \true && $atomic_comparison_result->type_coerced_from_scalar !== \false; $atomic_comparison_result->scalar_type_match_found = $property_type_comparison->scalar_type_match_found === \true && $atomic_comparison_result->scalar_type_match_found !== \false; } $all_types_contain = \false; } } } // finally, check input type fallback params against container type fallback params if ($input_type_part instanceof TKeyedArray && $container_type_part instanceof TKeyedArray && $input_type_part->fallback_params !== null && $container_type_part->fallback_params !== null) { foreach ($input_type_part->fallback_params as $i => $input_param) { $container_param = $container_type_part->fallback_params[$i]; $param_comparison = new \Psalm\Internal\Type\Comparator\TypeComparisonResult(); if (!\Psalm\Internal\Type\Comparator\UnionTypeComparator::isContainedBy($codebase, $input_param, $container_param, \false, \false, $param_comparison, $allow_interface_equality)) { if ($atomic_comparison_result) { $atomic_comparison_result->type_coerced = $param_comparison->type_coerced === \true && $atomic_comparison_result->type_coerced !== \false; $atomic_comparison_result->type_coerced_from_mixed = $param_comparison->type_coerced_from_mixed === \true && $atomic_comparison_result->type_coerced_from_mixed !== \false; $atomic_comparison_result->type_coerced_from_as_mixed = $param_comparison->type_coerced_from_as_mixed === \true && $atomic_comparison_result->type_coerced_from_as_mixed !== \false; $atomic_comparison_result->type_coerced_from_scalar = $param_comparison->type_coerced_from_scalar === \true && $atomic_comparison_result->type_coerced_from_scalar !== \false; $atomic_comparison_result->scalar_type_match_found = $param_comparison->scalar_type_match_found === \true && $atomic_comparison_result->scalar_type_match_found !== \false; } $all_types_contain = \false; } } } return $all_types_contain; } public static function isContainedByObjectWithProperties(Codebase $codebase, TNamedObject $input_type_part, TObjectWithProperties $container_type_part, bool $allow_interface_equality, ?\Psalm\Internal\Type\Comparator\TypeComparisonResult $atomic_comparison_result) : bool { $all_types_contain = \true; $input_object_with_keys = self::coerceToObjectWithProperties($codebase, $input_type_part, $container_type_part); foreach ($container_type_part->properties as $property_name => $container_property_type) { if (!$input_object_with_keys || !isset($input_object_with_keys->properties[$property_name])) { $all_types_contain = \false; continue; } $input_property_type = $input_object_with_keys->properties[$property_name]; $property_type_comparison = new \Psalm\Internal\Type\Comparator\TypeComparisonResult(); if (!$input_property_type->isNever() && !\Psalm\Internal\Type\Comparator\UnionTypeComparator::isContainedBy($codebase, $input_property_type, $container_property_type, \false, \false, $property_type_comparison, $allow_interface_equality) && !$property_type_comparison->type_coerced_from_scalar) { $inverse_property_type_comparison = new \Psalm\Internal\Type\Comparator\TypeComparisonResult(); if (\Psalm\Internal\Type\Comparator\UnionTypeComparator::isContainedBy($codebase, $container_property_type, $input_property_type, \false, \false, $inverse_property_type_comparison, $allow_interface_equality) || $inverse_property_type_comparison->type_coerced_from_scalar) { if ($atomic_comparison_result) { $atomic_comparison_result->type_coerced = \true; } } $all_types_contain = \false; } } return $all_types_contain; } public static function coerceToObjectWithProperties(Codebase $codebase, TNamedObject $input_type_part, TObjectWithProperties $container_type_part) : ?TObjectWithProperties { $storage = $codebase->classlikes->getStorageFor($input_type_part->value); if (!$storage) { return null; } $inferred_lower_bounds = []; if ($input_type_part instanceof TGenericObject) { foreach ($storage->template_types ?? [] as $template_name => $templates) { foreach (array_keys($templates) as $offset => $defining_at) { $inferred_lower_bounds[$template_name][$defining_at] = $input_type_part->type_params[$offset]; } } } foreach ($storage->template_extended_params ?? [] as $defining_at => $templates) { foreach ($templates as $template_name => $template_atomic) { $inferred_lower_bounds[$template_name][$defining_at] = $template_atomic; } } $properties = []; foreach ($storage->appearing_property_ids as $property_name => $property_id) { if (!isset($container_type_part->properties[$property_name])) { continue; } $property_type = $codebase->properties->hasStorage($property_id) ? $codebase->properties->getStorage($property_id)->type : null; $properties[$property_name] = $property_type ?? Type::getMixed(); } $replaced_object = TemplateInferredTypeReplacer::replace(new Union([new TObjectWithProperties($properties)]), new TemplateResult($storage->template_types ?? [], $inferred_lower_bounds), $codebase); /** @var TObjectWithProperties */ return $replaced_object->getSingleAtomic(); } } equals(new TArray([new Union([new TNever()]), new Union([new TNever()])]), \false); if ($is_empty_array && ($container_type_part instanceof TArray && !$container_type_part instanceof TNonEmptyArray || $container_type_part instanceof TKeyedArray && !$container_type_part->isNonEmpty())) { return \true; } if ($container_type_part instanceof TKeyedArray && $input_type_part instanceof TArray && !$container_type_part->is_list && !$container_type_part->isNonEmpty() && !$container_type_part->isSealed() && $input_type_part->equals($container_type_part->getGenericArrayType($container_type_part->isNonEmpty()), \false)) { return \true; } if ($container_type_part instanceof TKeyedArray && $input_type_part instanceof TArray) { $all_string_int_literals = \true; $properties = []; $value = $input_type_part->type_params[1]->setPossiblyUndefined(\true); foreach ($input_type_part->type_params[0]->getAtomicTypes() as $atomic_key_type) { if ($atomic_key_type instanceof TLiteralString || $atomic_key_type instanceof TLiteralInt) { $properties[$atomic_key_type->value] = $value; } else { $all_string_int_literals = \false; } } if ($all_string_int_literals && $properties) { $input_type_part = new TKeyedArray($properties); return \Psalm\Internal\Type\Comparator\KeyedArrayComparator::isContainedBy($codebase, $input_type_part, $container_type_part, $allow_interface_equality, $atomic_comparison_result); } } if ($container_type_part instanceof TKeyedArray && $container_type_part->is_list && ($input_type_part instanceof TKeyedArray && !$input_type_part->is_list || $input_type_part instanceof TArray)) { if ($atomic_comparison_result) { $atomic_comparison_result->type_coerced = \true; } return \false; } if ($container_type_part instanceof TKeyedArray && $container_type_part->is_list && $input_type_part instanceof TClassStringMap) { return \false; } if ($container_type_part instanceof TKeyedArray) { $container_type_part = $container_type_part->getGenericArrayType(); } if ($input_type_part instanceof TKeyedArray) { $input_type_part = $input_type_part->getGenericArrayType(); } if ($input_type_part instanceof TClassStringMap) { $input_type_part = new TArray([$input_type_part->getStandinKeyParam(), $input_type_part->value_param]); } if ($container_type_part instanceof TClassStringMap) { $container_type_part = new TArray([$container_type_part->getStandinKeyParam(), $container_type_part->value_param]); } foreach ($input_type_part->type_params as $i => $input_param) { $container_param = $container_type_part->type_params[$i]; if ($i === 0 && $input_param->hasMixed() && $container_param->hasString() && $container_param->hasInt()) { continue; } if ($input_param->isNever() && $container_type_part instanceof TNonEmptyArray) { return \false; } $param_comparison_result = new \Psalm\Internal\Type\Comparator\TypeComparisonResult(); if (!$input_param->isNever()) { if (!\Psalm\Internal\Type\Comparator\UnionTypeComparator::isContainedBy($codebase, $input_param, $container_param, $input_param->ignore_nullable_issues, $input_param->ignore_falsable_issues, $param_comparison_result, $allow_interface_equality)) { if ($atomic_comparison_result) { $atomic_comparison_result->type_coerced = $param_comparison_result->type_coerced === \true && $atomic_comparison_result->type_coerced !== \false; $atomic_comparison_result->type_coerced_from_mixed = $param_comparison_result->type_coerced_from_mixed === \true && $atomic_comparison_result->type_coerced_from_mixed !== \false; $atomic_comparison_result->type_coerced_from_as_mixed = $param_comparison_result->type_coerced_from_as_mixed === \true && $atomic_comparison_result->type_coerced_from_as_mixed !== \false; $atomic_comparison_result->type_coerced_from_scalar = $param_comparison_result->type_coerced_from_scalar === \true && $atomic_comparison_result->type_coerced_from_scalar !== \false; $atomic_comparison_result->scalar_type_match_found = $param_comparison_result->scalar_type_match_found === \true && $atomic_comparison_result->scalar_type_match_found !== \false; } if (!$param_comparison_result->type_coerced_from_as_mixed) { $all_types_contain = \false; } } else { if ($atomic_comparison_result) { $atomic_comparison_result->to_string_cast = $atomic_comparison_result->to_string_cast === \true || $param_comparison_result->to_string_cast === \true; } } } } if ($container_type_part instanceof TNonEmptyArray && !$input_type_part instanceof TNonEmptyArray) { if ($all_types_contain && $atomic_comparison_result) { $atomic_comparison_result->type_coerced = \true; } return \false; } return $all_types_contain; } } type_coerced = \true; } return \false; } } if ($input_type_part instanceof TCallableInterface && !$input_type_part instanceof TCallable) { return \true; } if ($container_type_part->is_pure && !$input_type_part->is_pure) { if ($atomic_comparison_result) { $atomic_comparison_result->type_coerced = $input_type_part->is_pure === null; } return \false; } if ($container_type_part->params !== null && $input_type_part->params === null) { if ($atomic_comparison_result) { $atomic_comparison_result->type_coerced = \true; $atomic_comparison_result->type_coerced_from_mixed = \true; } return \false; } $input_variadic_param_idx = null; if ($input_type_part->params !== null && $container_type_part->params !== null) { foreach ($input_type_part->params as $i => $input_param) { $container_param = null; if (isset($container_type_part->params[$i])) { $container_param = $container_type_part->params[$i]; } elseif ($container_type_part->params) { $last_param = end($container_type_part->params); if ($last_param->is_variadic) { $container_param = $last_param; } } if ($input_param->is_variadic) { $input_variadic_param_idx = $i; } if (!$container_param) { if ($input_param->is_variadic) { break; } if ($input_param->is_optional) { break; } return \false; } if ($container_param->type && !$container_param->type->hasMixed() && !\Psalm\Internal\Type\Comparator\UnionTypeComparator::isContainedBy($codebase, $container_param->type, $input_param->type ?: Type::getMixed(), \false, \false, $atomic_comparison_result)) { return \false; } } } if ($input_variadic_param_idx && isset($input_type_part->params[$input_variadic_param_idx])) { $input_param = $input_type_part->params[$input_variadic_param_idx]; foreach (array_slice($container_type_part->params ?? [], $input_variadic_param_idx) as $container_param) { if ($container_param->type && !$container_param->type->hasMixed() && !\Psalm\Internal\Type\Comparator\UnionTypeComparator::isContainedBy($codebase, $container_param->type, $input_param->type ?: Type::getMixed(), \false, \false, $atomic_comparison_result)) { return \false; } } } if (isset($container_type_part->return_type)) { if (!isset($input_type_part->return_type)) { if ($atomic_comparison_result) { $atomic_comparison_result->type_coerced = \true; $atomic_comparison_result->type_coerced_from_mixed = \true; } return \false; } $input_return = $input_type_part->return_type; if ($input_return->isVoid() && $container_type_part->return_type->isNullable()) { return \true; } if (!$container_type_part->return_type->isVoid() && !\Psalm\Internal\Type\Comparator\UnionTypeComparator::isContainedBy($codebase, $input_return, $container_type_part->return_type, \false, \false, $atomic_comparison_result)) { return \false; } } return \true; } public static function isNotExplicitlyCallableTypeCallable(Codebase $codebase, Atomic $input_type_part, TCallable $container_type_part, ?\Psalm\Internal\Type\Comparator\TypeComparisonResult $atomic_comparison_result) : bool { if ($input_type_part instanceof TList) { $input_type_part = $input_type_part->getKeyedArray(); } if ($input_type_part instanceof TArray) { if ($input_type_part->type_params[1]->isMixed() || $input_type_part->type_params[1]->hasScalar()) { if ($atomic_comparison_result) { $atomic_comparison_result->type_coerced_from_mixed = \true; $atomic_comparison_result->type_coerced = \true; } return \false; } if (!$input_type_part->type_params[1]->hasString()) { return \false; } if (!$input_type_part instanceof TCallableArray) { if ($atomic_comparison_result) { $atomic_comparison_result->type_coerced_from_mixed = \true; $atomic_comparison_result->type_coerced = \true; } return \false; } } elseif ($input_type_part instanceof TKeyedArray) { $method_id = self::getCallableMethodIdFromTKeyedArray($input_type_part); if ($method_id === 'not-callable') { return \false; } if (!$method_id) { return \true; } try { $method_id = $codebase->methods->getDeclaringMethodId($method_id); if (!$method_id) { return \false; } if (!$codebase->methods->hasStorage($method_id)) { return \false; } } catch (Exception $e) { return \false; } } $input_callable = self::getCallableFromAtomic($codebase, $input_type_part, $container_type_part, null, \true); if ($input_callable) { if (self::isContainedBy($codebase, $input_callable, $container_type_part, $atomic_comparison_result) === \false) { return \false; } } return \true; } /** * @return TCallable|TClosure|null */ public static function getCallableFromAtomic(Codebase $codebase, Atomic $input_type_part, ?TCallable $container_type_part = null, ?StatementsAnalyzer $statements_analyzer = null, bool $expand_callable = \false) : ?Atomic { if ($input_type_part instanceof TList) { $input_type_part = $input_type_part->getKeyedArray(); } if ($input_type_part instanceof TCallable || $input_type_part instanceof TClosure) { return $input_type_part; } if ($input_type_part instanceof TLiteralString && $input_type_part->value) { try { $function_storage = $codebase->functions->getStorage($statements_analyzer, strtolower($input_type_part->value)); if ($expand_callable) { $params = []; foreach ($function_storage->params as $param) { if ($param->type) { $param = $param->setType(TypeExpander::expandUnion($codebase, $param->type, null, null, null, \true, \true, \false, \false, \true)); } $params[] = $param; } $return_type = null; if ($function_storage->return_type) { $return_type = TypeExpander::expandUnion($codebase, $function_storage->return_type, null, null, null, \true, \true, \false, \false, \true); } } else { $return_type = $function_storage->return_type; $params = $function_storage->params; } return new TCallable('callable', $params, $return_type, $function_storage->pure); } catch (UnexpectedValueException $e) { if (InternalCallMapHandler::inCallMap($input_type_part->value)) { $args = []; $nodes = new NodeDataProvider(); if ($container_type_part && $container_type_part->params) { foreach ($container_type_part->params as $i => $param) { $arg = new Arg(new Variable('_' . $i)); if ($param->type) { $nodes->setType($arg->value, $param->type); } $args[] = $arg; } } $matching_callable = InternalCallMapHandler::getCallableFromCallMapById($codebase, $input_type_part->value, $args, $nodes); $must_use = \false; $matching_callable = $matching_callable->setIsPure($codebase->functions->isCallMapFunctionPure($codebase, $statements_analyzer->node_data ?? null, $input_type_part->value, null, $must_use)); return $matching_callable; } } } elseif ($input_type_part instanceof TKeyedArray) { $method_id = self::getCallableMethodIdFromTKeyedArray($input_type_part); if ($method_id && $method_id !== 'not-callable') { try { $method_storage = $codebase->methods->getStorage($method_id); $method_fqcln = $method_id->fq_class_name; $converted_return_type = null; if ($method_storage->return_type) { $converted_return_type = TypeExpander::expandUnion($codebase, $method_storage->return_type, $method_fqcln, $method_fqcln, null); } return new TCallable('callable', $method_storage->params, $converted_return_type, $method_storage->pure); } catch (UnexpectedValueException $e) { // do nothing } } } elseif ($input_type_part instanceof TNamedObject && $input_type_part->value === 'Closure') { return new TCallable(); } elseif ($input_type_part instanceof TNamedObject && $codebase->classExists($input_type_part->value)) { $invoke_id = new MethodIdentifier($input_type_part->value, '__invoke'); if ($codebase->methods->methodExists($invoke_id)) { $declaring_method_id = $codebase->methods->getDeclaringMethodId($invoke_id); $template_result = null; if ($input_type_part instanceof Atomic\TGenericObject) { $invokable_storage = $codebase->methods->getClassLikeStorageForMethod($declaring_method_id ?? $invoke_id); $type_params = []; foreach ($invokable_storage->template_types ?? [] as $template => $for_class) { foreach ($for_class as $type) { $type_params[] = new Type\Union([new TTemplateParam($template, $type, $input_type_part->value)]); } } if (!empty($type_params)) { $input_with_templates = new Atomic\TGenericObject($input_type_part->value, $type_params); $template_result = new TemplateResult($invokable_storage->template_types ?? [], []); TemplateStandinTypeReplacer::fillTemplateResult(new Type\Union([$input_with_templates]), $template_result, $codebase, null, new Type\Union([$input_type_part])); } } if ($declaring_method_id) { $method_storage = $codebase->methods->getStorage($declaring_method_id); $method_fqcln = $invoke_id->fq_class_name; $converted_return_type = null; if ($method_storage->return_type) { $converted_return_type = TypeExpander::expandUnion($codebase, $method_storage->return_type, $method_fqcln, $method_fqcln, null); } $callable = new TCallable('callable', $method_storage->params, $converted_return_type, $method_storage->pure); if ($template_result) { $callable = TemplateInferredTypeReplacer::replace(new Union([$callable]), $template_result, $codebase)->getSingleAtomic(); } return $callable; } } } return null; } /** @return null|'not-callable'|MethodIdentifier */ public static function getCallableMethodIdFromTKeyedArray(TKeyedArray $input_type_part, ?Codebase $codebase = null, ?string $calling_method_id = null, ?string $file_name = null) { if (!isset($input_type_part->properties[0]) || !isset($input_type_part->properties[1]) || count($input_type_part->properties) > 2) { return 'not-callable'; } [$lhs, $rhs] = $input_type_part->properties; $rhs_low_info = $rhs->hasMixed() || $rhs->hasScalar(); if ($rhs_low_info || !$rhs->isSingleStringLiteral()) { if (!$rhs_low_info && !$rhs->hasString()) { return 'not-callable'; } if ($codebase && ($calling_method_id || $file_name)) { foreach ($lhs->getAtomicTypes() as $lhs_atomic_type) { if ($lhs_atomic_type instanceof TNamedObject) { $codebase->analyzer->addMixedMemberName(strtolower($lhs_atomic_type->value) . '::', $calling_method_id ?: $file_name); } elseif ($lhs_atomic_type instanceof TTemplateParam) { $lhs_template_type = $lhs_atomic_type->as; if ($lhs_template_type->isSingle()) { $lhs_template_atomic_type = $lhs_template_type->getSingleAtomic(); $member_id = null; if ($lhs_template_atomic_type instanceof TNamedObject) { $member_id = $lhs_template_atomic_type->value; } elseif ($lhs_template_atomic_type instanceof TClassString) { $member_id = $lhs_template_atomic_type->as; } if ($member_id) { /** @psalm-suppress PossiblyNullArgument Psalm bug */ $codebase->analyzer->addMixedMemberName(strtolower($member_id) . '::', $calling_method_id ?: $file_name); } } } } } return null; } $method_name = $rhs->getSingleStringLiteral()->value; $class_name = null; if ($lhs->isSingleStringLiteral()) { $class_name = $lhs->getSingleStringLiteral()->value; if ($class_name[0] === '\\') { $class_name = substr($class_name, 1); } } elseif ($lhs->isSingle()) { foreach ($lhs->getAtomicTypes() as $lhs_atomic_type) { if ($lhs_atomic_type instanceof TNamedObject) { $class_name = $lhs_atomic_type->value; } elseif ($lhs_atomic_type instanceof TTemplateParam) { $lhs_template_type = $lhs_atomic_type->as; if ($lhs_template_type->isSingle()) { $lhs_template_atomic_type = $lhs_template_type->getSingleAtomic(); if ($lhs_template_atomic_type instanceof TNamedObject) { $class_name = $lhs_template_atomic_type->value; } elseif ($lhs_template_atomic_type instanceof TClassString) { $class_name = $lhs_template_atomic_type->as; } } } elseif ($lhs_atomic_type instanceof TClassString && $lhs_atomic_type->as) { $class_name = $lhs_atomic_type->as; } } } if ($class_name === 'self' || $class_name === 'static' || $class_name === 'parent') { return null; } if (!$class_name) { if ($codebase && ($calling_method_id || $file_name)) { $codebase->analyzer->addMixedMemberName(strtolower($method_name), $calling_method_id ?: $file_name); } return null; } return new MethodIdentifier($class_name, strtolower($method_name)); } } getAtomicTypes() as $return_type_part) { $parts = self::expandAtomic($codebase, $return_type_part, $self_class, $static_class_type, $parent_class, $evaluate_class_constants, $evaluate_conditional_types, $final, $expand_generic, $expand_templates, $throw_on_unresolvable_constant); $new_return_type_parts = [...$new_return_type_parts, ...$parts]; } $fleshed_out_type = \Psalm\Internal\Type\TypeCombiner::combine($new_return_type_parts, $codebase); $fleshed_out_type->from_docblock = $return_type->from_docblock; $fleshed_out_type->ignore_nullable_issues = $return_type->ignore_nullable_issues; $fleshed_out_type->ignore_falsable_issues = $return_type->ignore_falsable_issues; $fleshed_out_type->possibly_undefined = $return_type->possibly_undefined; $fleshed_out_type->possibly_undefined_from_try = $return_type->possibly_undefined_from_try; $fleshed_out_type->by_ref = $return_type->by_ref; $fleshed_out_type->initialized = $return_type->initialized; $fleshed_out_type->from_property = $return_type->from_property; $fleshed_out_type->from_static_property = $return_type->from_static_property; $fleshed_out_type->explicit_never = $return_type->explicit_never; $fleshed_out_type->had_template = $return_type->had_template; $fleshed_out_type->parent_nodes = $return_type->parent_nodes; return $fleshed_out_type; } /** * @param string|TNamedObject|TTemplateParam|null $static_class_type * @param-out Atomic $return_type * @return non-empty-list * @psalm-suppress ConflictingReferenceConstraint, ReferenceConstraintViolation The output type is always Atomic * @psalm-suppress ComplexMethod */ public static function expandAtomic(Codebase $codebase, Atomic &$return_type, ?string $self_class, $static_class_type, ?string $parent_class, bool $evaluate_class_constants = \true, bool $evaluate_conditional_types = \false, bool $final = \false, bool $expand_generic = \false, bool $expand_templates = \false, bool $throw_on_unresolvable_constant = \false) : array { if ($return_type instanceof TEnumCase) { return [$return_type]; } if ($return_type instanceof TNamedObject || $return_type instanceof TTemplateParam) { if ($return_type->extra_types) { $new_intersection_types = []; $extra_types = []; foreach ($return_type->extra_types as $extra_type) { self::expandAtomic($codebase, $extra_type, $self_class, $static_class_type, $parent_class, $evaluate_class_constants, $evaluate_conditional_types, $expand_generic, $expand_templates, $throw_on_unresolvable_constant); if ($extra_type instanceof TNamedObject && $extra_type->extra_types) { $new_intersection_types = array_merge($new_intersection_types, $extra_type->extra_types); $extra_type = $extra_type->setIntersectionTypes([]); } $extra_types[$extra_type->getKey()] = $extra_type; } /** @psalm-suppress ArgumentTypeCoercion */ $return_type = $return_type->setIntersectionTypes(array_merge($extra_types, $new_intersection_types)); } if ($return_type instanceof TNamedObject) { $return_type = self::expandNamedObject($codebase, $return_type, $self_class, $static_class_type, $parent_class, $final, $expand_generic); } } if ($return_type instanceof TClassString && $return_type->as_type) { $new_as_type = $return_type->as_type; self::expandAtomic($codebase, $new_as_type, $self_class, $static_class_type, $parent_class, $evaluate_class_constants, $evaluate_conditional_types, $final, $expand_generic, $expand_templates, $throw_on_unresolvable_constant); if ($new_as_type instanceof TNamedObject && $new_as_type !== $return_type->as_type) { $return_type = $return_type->setAs($new_as_type->value, $new_as_type); } } elseif ($return_type instanceof TTemplateParam) { $new_as_type = self::expandUnion($codebase, $return_type->as, $self_class, $static_class_type, $parent_class, $evaluate_class_constants, $evaluate_conditional_types, $final, $expand_generic, $expand_templates, $throw_on_unresolvable_constant); if ($expand_templates) { return array_values($new_as_type->getAtomicTypes()); } $return_type = $return_type->replaceAs($new_as_type); } if ($return_type instanceof TClassConstant) { if ($self_class) { $return_type = $return_type->replaceClassLike('self', $self_class); } if (is_string($static_class_type) || $self_class) { $return_type = $return_type->replaceClassLike('static', is_string($static_class_type) ? $static_class_type : $self_class); } if ($evaluate_class_constants && $codebase->classOrInterfaceOrEnumExists($return_type->fq_classlike_name)) { if (strtolower($return_type->const_name) === 'class') { return [new TLiteralClassString($return_type->fq_classlike_name)]; } try { $class_constant = $codebase->classlikes->getClassConstantType($return_type->fq_classlike_name, $return_type->const_name, ReflectionProperty::IS_PRIVATE); } catch (CircularReferenceException $e) { $class_constant = null; } if ($class_constant) { return array_values($class_constant->getAtomicTypes()); } } return [$return_type]; } if ($return_type instanceof TPropertiesOf) { return self::expandPropertiesOf($codebase, $return_type, $self_class, $static_class_type); } if ($return_type instanceof TTypeAlias) { $declaring_fq_classlike_name = $return_type->declaring_fq_classlike_name; if ($declaring_fq_classlike_name === 'self' && $self_class) { $declaring_fq_classlike_name = $self_class; } if (!($evaluate_class_constants && $codebase->classlikes->doesClassLikeExist(strtolower($declaring_fq_classlike_name)))) { return [$return_type]; } $class_storage = $codebase->classlike_storage_provider->get($declaring_fq_classlike_name); $type_alias_name = $return_type->alias_name; if (!isset($class_storage->type_aliases[$type_alias_name])) { return [$return_type]; } $resolved_type_alias = $class_storage->type_aliases[$type_alias_name]; $replacement_atomic_types = $resolved_type_alias->replacement_atomic_types; if (!$replacement_atomic_types) { return [$return_type]; } $recursively_fleshed_out_types = []; foreach ($replacement_atomic_types as $replacement_atomic_type) { $more_recursively_fleshed_out_types = self::expandAtomic($codebase, $replacement_atomic_type, $self_class, $static_class_type, $parent_class, $evaluate_class_constants, $evaluate_conditional_types, $final, $expand_generic, $expand_templates, $throw_on_unresolvable_constant); $recursively_fleshed_out_types = [...$more_recursively_fleshed_out_types, ...$recursively_fleshed_out_types]; } /** @psalm-suppress DeprecatedProperty For backwards compatibility, we have to keep this here. */ foreach ($return_type->extra_types ?? [] as $alias) { $more_recursively_fleshed_out_types = self::expandAtomic($codebase, $alias, $self_class, $static_class_type, $parent_class, $evaluate_class_constants, $evaluate_conditional_types, $final, $expand_generic, $expand_templates, $throw_on_unresolvable_constant); $recursively_fleshed_out_types = [...$more_recursively_fleshed_out_types, ...$recursively_fleshed_out_types]; } return $recursively_fleshed_out_types; } if ($return_type instanceof TKeyOf || $return_type instanceof TValueOf) { return self::expandKeyOfValueOf($codebase, $return_type, $self_class, $static_class_type, $parent_class, $evaluate_class_constants, $evaluate_conditional_types, $final, $expand_generic, $expand_templates, $throw_on_unresolvable_constant); } if ($return_type instanceof TIntMask) { if (!$evaluate_class_constants) { return [new TInt()]; } $potential_ints = []; foreach ($return_type->values as $value_type) { $new_value_type = self::expandAtomic($codebase, $value_type, $self_class, $static_class_type, $parent_class, $evaluate_class_constants, $evaluate_conditional_types, $final, $expand_generic, $expand_templates, $throw_on_unresolvable_constant); $new_value_type = reset($new_value_type); if (!$new_value_type instanceof TLiteralInt) { return [new TInt()]; } $potential_ints[] = $new_value_type->value; } return \Psalm\Internal\Type\TypeParser::getComputedIntsFromMask($potential_ints); } if ($return_type instanceof TIntMaskOf) { if (!$evaluate_class_constants) { return [new TInt()]; } $value_type = $return_type->value; $new_value_types = self::expandAtomic($codebase, $value_type, $self_class, $static_class_type, $parent_class, $evaluate_class_constants, $evaluate_conditional_types, $final, $expand_generic, $expand_templates, $throw_on_unresolvable_constant); $potential_ints = []; foreach ($new_value_types as $new_value_type) { if (!$new_value_type instanceof TLiteralInt) { return [new TInt()]; } $potential_ints[] = $new_value_type->value; } return \Psalm\Internal\Type\TypeParser::getComputedIntsFromMask($potential_ints); } if ($return_type instanceof TConditional) { return self::expandConditional($codebase, $return_type, $self_class, $static_class_type, $parent_class, $evaluate_class_constants, $evaluate_conditional_types, $final, $expand_generic, $expand_templates, $throw_on_unresolvable_constant); } if ($return_type instanceof TList) { $return_type = $return_type->getKeyedArray(); } if ($return_type instanceof TArray || $return_type instanceof TGenericObject || $return_type instanceof TIterable) { $type_params = $return_type->type_params; foreach ($type_params as &$type_param) { $type_param = self::expandUnion($codebase, $type_param, $self_class, $static_class_type, $parent_class, $evaluate_class_constants, $evaluate_conditional_types, $final, $expand_generic, $expand_templates, $throw_on_unresolvable_constant); } unset($type_param); /** @psalm-suppress InvalidArgument Psalm bug */ $return_type = $return_type->setTypeParams($type_params); } elseif ($return_type instanceof TKeyedArray) { $properties = $return_type->properties; $changed = \false; foreach ($properties as $k => $property_type) { $property_type = self::expandUnion($codebase, $property_type, $self_class, $static_class_type, $parent_class, $evaluate_class_constants, $evaluate_conditional_types, $final, $expand_generic, $expand_templates, $throw_on_unresolvable_constant); if ($property_type !== $properties[$k]) { $changed = \true; $properties[$k] = $property_type; } } unset($property_type); $fallback_params = $return_type->fallback_params; if ($fallback_params) { foreach ($fallback_params as $k => $property_type) { $property_type = self::expandUnion($codebase, $property_type, $self_class, $static_class_type, $parent_class, $evaluate_class_constants, $evaluate_conditional_types, $final, $expand_generic, $expand_templates, $throw_on_unresolvable_constant); if ($property_type !== $fallback_params[$k]) { $changed = \true; $fallback_params[$k] = $property_type; } } unset($property_type); } if ($changed) { $return_type = new TKeyedArray($properties, $return_type->class_strings, $fallback_params, $return_type->is_list, $return_type->from_docblock); } } if ($return_type instanceof TObjectWithProperties) { $properties = $return_type->properties; foreach ($properties as &$property_type) { $property_type = self::expandUnion($codebase, $property_type, $self_class, $static_class_type, $parent_class, $evaluate_class_constants, $evaluate_conditional_types, $final, $expand_generic, $expand_templates, $throw_on_unresolvable_constant); } unset($property_type); $return_type = $return_type->setProperties($properties); } if ($return_type instanceof TCallable || $return_type instanceof TClosure) { $params = $return_type->params; if ($params) { foreach ($params as &$param) { if ($param->type) { $param = $param->setType(self::expandUnion($codebase, $param->type, $self_class, $static_class_type, $parent_class, $evaluate_class_constants, $evaluate_conditional_types, $final, $expand_generic, $expand_templates, $throw_on_unresolvable_constant)); } } unset($param); } $sub_return_type = $return_type->return_type; if ($sub_return_type) { $sub_return_type = self::expandUnion($codebase, $sub_return_type, $self_class, $static_class_type, $parent_class, $evaluate_class_constants, $evaluate_conditional_types, $final, $expand_generic, $expand_templates, $throw_on_unresolvable_constant); } $return_type = $return_type->replace($params, $sub_return_type); } return [$return_type]; } /** * @param string|TNamedObject|TTemplateParam|null $static_class_type * @param-out TNamedObject|TTemplateParam $return_type * @return TNamedObject|TTemplateParam */ private static function expandNamedObject(Codebase $codebase, TNamedObject &$return_type, ?string $self_class, $static_class_type, ?string $parent_class, bool $final = \false, bool &$expand_generic = \false) { if ($expand_generic && get_class($return_type) === TNamedObject::class && !$return_type->extra_types && $codebase->classOrInterfaceExists($return_type->value)) { $value = $codebase->classlikes->getUnAliasedName($return_type->value); $container_class_storage = $codebase->classlike_storage_provider->get($value); if ($container_class_storage->template_types && array_filter($container_class_storage->template_types, static fn($type_map): bool => !reset($type_map)->hasMixed())) { $return_type = new TGenericObject($return_type->value, array_values(array_map(static fn($type_map) => reset($type_map), $container_class_storage->template_types))); // we don't want to expand generic types recursively $expand_generic = \false; } } $return_type_lc = strtolower($return_type->value); if ($static_class_type && ($return_type_lc === 'static' || $return_type_lc === '$this')) { $is_static = $return_type->is_static; $is_static_resolved = null; if (!$final) { $is_static = \true; $is_static_resolved = \true; } if (is_string($static_class_type)) { $return_type = $return_type->setValueIsStatic($static_class_type, $is_static, $is_static_resolved); } else { if ($return_type instanceof TGenericObject && $static_class_type instanceof TGenericObject) { $return_type = $return_type->setValueIsStatic($static_class_type->value, $is_static, $is_static_resolved); } elseif ($static_class_type instanceof TNamedObject) { $return_type = $static_class_type->setIsStatic($is_static, $is_static_resolved); } else { $return_type = $static_class_type; } } } elseif ($return_type->is_static && !$return_type->is_static_resolved && ($static_class_type instanceof TNamedObject || $static_class_type instanceof TTemplateParam)) { $return_type_types = $return_type->getIntersectionTypes(); $cloned_static = $static_class_type->setIntersectionTypes([]); $extra_static = $static_class_type->extra_types; if ($cloned_static->getKey(\false) !== $return_type->getKey(\false)) { $return_type_types[$cloned_static->getKey()] = $cloned_static; } foreach ($extra_static as $extra_static_type) { if ($extra_static_type->getKey(\false) !== $return_type->getKey(\false)) { $return_type_types[$extra_static_type->getKey()] = $extra_static_type; } } $return_type = $return_type->setIntersectionTypes($return_type_types)->setIsStatic(\true, \true); } elseif ($return_type->is_static && is_string($static_class_type) && $final) { $return_type = $return_type->setValueIsStatic($static_class_type, \false); } elseif ($self_class && $return_type_lc === 'self') { $return_type = $return_type->setValue($self_class); } elseif ($parent_class && $return_type_lc === 'parent') { $return_type = $return_type->setValue($parent_class); } else { $new_value = $codebase->classlikes->getUnAliasedName($return_type->value); $return_type = $return_type->setValue($new_value); } return $return_type; } /** * @param string|TNamedObject|TTemplateParam|null $static_class_type * @return non-empty-list */ private static function expandConditional(Codebase $codebase, TConditional &$return_type, ?string $self_class, $static_class_type, ?string $parent_class, bool $evaluate_class_constants = \true, bool $evaluate_conditional_types = \false, bool $final = \false, bool $expand_generic = \false, bool $expand_templates = \false, bool $throw_on_unresolvable_constant = \false) : array { $new_as_type = self::expandUnion($codebase, $return_type->as_type, $self_class, $static_class_type, $parent_class, $evaluate_class_constants, $evaluate_conditional_types, $final, $expand_generic, $expand_templates, $throw_on_unresolvable_constant); if ($evaluate_conditional_types) { $assertion = null; if ($return_type->conditional_type->isSingle()) { foreach ($return_type->conditional_type->getAtomicTypes() as $condition_atomic_type) { $candidate = self::expandAtomic($codebase, $condition_atomic_type, $self_class, $static_class_type, $parent_class, $evaluate_class_constants, $evaluate_conditional_types, $final, $expand_generic, $expand_templates, $throw_on_unresolvable_constant); if (count($candidate) === 1) { $assertion = new IsType($candidate[0]); } } } $if_conditional_return_types = []; foreach ($return_type->if_type->getAtomicTypes() as $if_atomic_type) { $candidate_types = self::expandAtomic($codebase, $if_atomic_type, $self_class, $static_class_type, $parent_class, $evaluate_class_constants, $evaluate_conditional_types, $final, $expand_generic, $expand_templates, $throw_on_unresolvable_constant); $if_conditional_return_types = [...$if_conditional_return_types, ...$candidate_types]; } $else_conditional_return_types = []; foreach ($return_type->else_type->getAtomicTypes() as $else_atomic_type) { $candidate_types = self::expandAtomic($codebase, $else_atomic_type, $self_class, $static_class_type, $parent_class, $evaluate_class_constants, $evaluate_conditional_types, $final, $expand_generic, $expand_templates, $throw_on_unresolvable_constant); $else_conditional_return_types = [...$else_conditional_return_types, ...$candidate_types]; } if ($assertion && $return_type->param_name === (string) $return_type->if_type) { $if_conditional_return_type = \Psalm\Internal\Type\TypeCombiner::combine($if_conditional_return_types, $codebase); $if_conditional_return_type = \Psalm\Internal\Type\SimpleAssertionReconciler::reconcile($assertion, $codebase, $if_conditional_return_type); if ($if_conditional_return_type) { $if_conditional_return_types = array_values($if_conditional_return_type->getAtomicTypes()); } } if ($assertion && $return_type->param_name === (string) $return_type->else_type) { $else_conditional_return_type = \Psalm\Internal\Type\TypeCombiner::combine($else_conditional_return_types, $codebase); $else_conditional_return_type = \Psalm\Internal\Type\SimpleNegatedAssertionReconciler::reconcile($codebase, $assertion, $else_conditional_return_type); if ($else_conditional_return_type) { $else_conditional_return_types = array_values($else_conditional_return_type->getAtomicTypes()); } } $all_conditional_return_types = [...$if_conditional_return_types, ...$else_conditional_return_types]; $number_of_types = count($all_conditional_return_types); // we filter TNever that have no bearing on the return type if ($number_of_types > 1) { $all_conditional_return_types = array_filter($all_conditional_return_types, static fn(Atomic $atomic_type): bool => !$atomic_type instanceof TNever); } // if we still have more than one type, we remove TVoid and replace it by TNull $number_of_types = count($all_conditional_return_types); if ($number_of_types > 1) { $all_conditional_return_types = array_filter($all_conditional_return_types, static fn(Atomic $atomic_type): bool => !$atomic_type instanceof TVoid); if (count($all_conditional_return_types) !== $number_of_types) { $all_conditional_return_types[] = new TNull(\true); } } if ($all_conditional_return_types) { $combined = \Psalm\Internal\Type\TypeCombiner::combine(array_values($all_conditional_return_types), $codebase); $return_type = $return_type->setTypes($new_as_type); return array_values($combined->getAtomicTypes()); } } $return_type = $return_type->setTypes($new_as_type, self::expandUnion($codebase, $return_type->conditional_type, $self_class, $static_class_type, $parent_class, $evaluate_class_constants, $evaluate_conditional_types, $final, $expand_generic, $expand_templates, $throw_on_unresolvable_constant), self::expandUnion($codebase, $return_type->if_type, $self_class, $static_class_type, $parent_class, $evaluate_class_constants, $evaluate_conditional_types, $final, $expand_generic, $expand_templates, $throw_on_unresolvable_constant), self::expandUnion($codebase, $return_type->else_type, $self_class, $static_class_type, $parent_class, $evaluate_class_constants, $evaluate_conditional_types, $final, $expand_generic, $expand_templates, $throw_on_unresolvable_constant)); return [$return_type]; } /** * @param string|TNamedObject|TTemplateParam|null $static_class_type * @return non-empty-list */ private static function expandPropertiesOf(Codebase $codebase, TPropertiesOf &$return_type, ?string $self_class, $static_class_type) : array { if ($self_class) { $return_type = $return_type->replaceClassLike('self', $self_class); $return_type = $return_type->replaceClassLike('static', is_string($static_class_type) ? $static_class_type : $self_class); } $class_storage = null; if ($codebase->classExists($return_type->classlike_type->value)) { $class_storage = $codebase->classlike_storage_provider->get($return_type->classlike_type->value); } else { foreach ($return_type->classlike_type->extra_types as $type) { if ($type instanceof TNamedObject && $codebase->classExists($type->value)) { $class_storage = $codebase->classlike_storage_provider->get($type->value); break; } } } if (!$class_storage) { return [$return_type]; } $all_sealed = \true; $properties = []; foreach ([$class_storage->name, ...array_values($class_storage->parent_classes)] as $class) { if (!$codebase->classExists($class)) { continue; } $storage = $codebase->classlike_storage_provider->get($class); if (!$storage->final) { $all_sealed = \false; } foreach ($storage->properties as $key => $property) { if (isset($properties[$key])) { continue; } if ($return_type->visibility_filter !== null && $property->visibility !== $return_type->visibility_filter) { continue; } if ($property->is_static || !$property->type) { continue; } $type = $return_type->classlike_type instanceof TGenericObject ? AtomicPropertyFetchAnalyzer::localizePropertyType($codebase, $property->type, $return_type->classlike_type, $storage, $storage) : $property->type; $properties[$key] = $type; } } if ($properties === []) { return [$return_type]; } return [new TKeyedArray($properties, null, $all_sealed ? null : [Type::getString(), Type::getMixed()])]; } /** * @param TKeyOf|TValueOf $return_type * @param string|TNamedObject|TTemplateParam|null $static_class_type * @return non-empty-list */ private static function expandKeyOfValueOf(Codebase $codebase, Atomic &$return_type, ?string $self_class, $static_class_type, ?string $parent_class, bool $evaluate_class_constants = \true, bool $evaluate_conditional_types = \false, bool $final = \false, bool $expand_generic = \false, bool $expand_templates = \false, bool $throw_on_unresolvable_constant = \false) : array { // Expand class constants to their atomics $type_atomics = []; foreach ($return_type->type->getAtomicTypes() as $type_param) { if (!$evaluate_class_constants || !$type_param instanceof TClassConstant) { $type_param_expanded = self::expandAtomic($codebase, $type_param, $self_class, $static_class_type, $parent_class, $evaluate_class_constants, $evaluate_conditional_types, $final, $expand_generic, $expand_templates, $throw_on_unresolvable_constant); $type_atomics = [...$type_atomics, ...$type_param_expanded]; continue; } if ($self_class) { $type_param = $type_param->replaceClassLike('self', $self_class); } if ($throw_on_unresolvable_constant && !$codebase->classOrInterfaceOrEnumExists($type_param->fq_classlike_name)) { throw new UnresolvableConstantException($type_param->fq_classlike_name, $type_param->const_name); } try { $constant_type = $codebase->classlikes->getClassConstantType($type_param->fq_classlike_name, $type_param->const_name, ReflectionProperty::IS_PRIVATE, null, [], \false, $return_type instanceof TValueOf); } catch (CircularReferenceException $e) { return [$return_type]; } if (!$constant_type || $return_type instanceof TKeyOf && !TKeyOf::isViableTemplateType($constant_type) || $return_type instanceof TValueOf && !TValueOf::isViableTemplateType($constant_type)) { if ($throw_on_unresolvable_constant) { throw new UnresolvableConstantException($type_param->fq_classlike_name, $type_param->const_name); } else { return [$return_type]; } } $type_atomics = array_merge($type_atomics, array_values($constant_type->getAtomicTypes())); } if ($type_atomics === []) { return [$return_type]; } if ($return_type instanceof TKeyOf) { $new_return_types = TKeyOf::getArrayKeyType(new Union($type_atomics)); } else { $new_return_types = TValueOf::getValueType(new Union($type_atomics), $codebase); } if ($new_return_types === null) { return [$return_type]; } return array_values($new_return_types->getAtomicTypes()); } } */ private array $included_files = []; /** * @template T * @param callable():T $f * @return T */ public function runAndCollect(callable $f) { $before = get_included_files(); $ret = $f(); $after = get_included_files(); $included = array_diff($after, $before); $this->included_files = array_values(array_unique([...$this->included_files, ...$included])); return $ret; } /** @return list */ public function getIncludedFiles() : array { return $this->included_files; } /** @return list */ public function getFilteredIncludedFiles() : array { return array_values(preg_grep('@^phar://@', $this->getIncludedFiles(), PREG_GREP_INVERT)); } } getMessage() . "\n"); exit(1); } if (!$composer_json) { fwrite(STDERR, 'Invalid composer.json at ' . $composer_json_path . "\n"); exit(1); } if (is_array($composer_json) && isset($composer_json['config']) && is_array($composer_json['config']) && isset($composer_json['config']['vendor-dir']) && is_string($composer_json['config']['vendor-dir'])) { return $composer_json['config']['vendor-dir']; } return 'vendor'; } /** * @return list */ public static function getRawCliArguments() : array { global $argv; if (!$argv) { return []; } return array_slice($argv, 1); } /** * @return list */ public static function getArguments() : array { $argv = self::getRawCliArguments(); $filtered_input_paths = []; for ($i = 0, $iMax = count($argv); $i < $iMax; ++$i) { $input_path = $argv[$i]; if (realpath($input_path) !== \false) { continue; } if ($input_path[0] === '-' && strlen($input_path) === 2) { if ($input_path[1] === 'c' || $input_path[1] === 'f' || $input_path[1] === 'r') { ++$i; } continue; } if ($input_path[0] === '-' && $input_path[2] === '=') { continue; } $filtered_input_paths[] = $input_path; } return $filtered_input_paths; } /** * @param string|array|null|false $f_paths * @return list|null */ public static function getPathsToCheck($f_paths) : ?array { $paths_to_check = []; if ($f_paths) { $input_paths = is_array($f_paths) ? $f_paths : [$f_paths]; } else { $input_paths = self::getRawCliArguments(); if (!$input_paths) { return null; } } $filtered_input_paths = []; for ($i = 0, $iMax = count($input_paths); $i < $iMax; ++$i) { /** @var string */ $input_path = $input_paths[$i]; if ($input_path[0] === '-' && strlen($input_path) === 2) { if ($input_path[1] === 'c' || $input_path[1] === 'f' || $input_path[1] === 'r') { ++$i; } continue; } if ($input_path[0] === '-' && $input_path[2] === '=') { continue; } if (strpos($input_path, '--') === 0 && strlen($input_path) > 2) { // ignore --config psalm.xml // ignore common phpunit args that accept a class instead of a path, as this can cause issues on Windows $ignored_arguments = array('config', 'printer', 'root'); if (in_array(substr($input_path, 2), $ignored_arguments, \true)) { ++$i; } continue; } $filtered_input_paths[] = $input_path; } if ($filtered_input_paths === ['-']) { $meta = stream_get_meta_data(STDIN); stream_set_blocking(STDIN, \false); if ($stdin = fgets(STDIN)) { $filtered_input_paths = preg_split('/\\s+/', trim($stdin)); if ($filtered_input_paths === \false) { throw new RuntimeException('Invalid paths: ' . preg_last_error_msg()); } } $blocked = $meta['blocked']; stream_set_blocking(STDIN, $blocked); } foreach ($filtered_input_paths as $path_to_check) { if ($path_to_check[0] === '-') { fwrite(STDERR, 'Invalid usage, expecting psalm [options] [file...]' . PHP_EOL); exit(1); } if (!file_exists($path_to_check)) { fwrite(STDERR, 'Cannot locate ' . $path_to_check . PHP_EOL); exit(1); } $path_to_check = realpath($path_to_check); if (!$path_to_check) { fwrite(STDERR, 'Error getting realpath for file' . PHP_EOL); exit(1); } $paths_to_check[] = $path_to_check; } if (!$paths_to_check) { $paths_to_check = null; } return $paths_to_check; } public static function initializeConfig(?string $path_to_config, string $current_dir, string $output_format, ?ClassLoader $first_autoloader, bool $create_if_non_existent = \false) : Config { try { if ($path_to_config) { $config = Config::loadFromXMLFile($path_to_config, $current_dir); } else { try { $config = Config::getConfigForPath($current_dir, $current_dir); } catch (ConfigNotFoundException $e) { if (!$create_if_non_existent) { if (in_array($output_format, [Report::TYPE_CONSOLE, Report::TYPE_PHP_STORM])) { fwrite(STDERR, 'Could not locate a config XML file in path ' . $current_dir . '. Have you run \'psalm --init\' ?' . PHP_EOL); exit(1); } throw $e; } $config = Creator::createBareConfig($current_dir, null, self::getVendorDir($current_dir)); } } } catch (ConfigException $e) { fwrite(STDERR, $e->getMessage() . PHP_EOL); exit(1); } $config->setComposerClassLoader($first_autoloader); return $config; } public static function updateConfigFile(Config $config, string $config_file_path, string $baseline_path) : void { if ($config->error_baseline === $baseline_path) { return; } $config_file = $config_file_path; if (is_dir($config_file_path)) { $config_file = Config::locateConfigFile($config_file_path); } if (!$config_file) { fwrite(STDERR, "Don't forget to set errorBaseline=\"{$baseline_path}\" to your config."); return; } $config_file_contents = file_get_contents($config_file); if ($config->error_baseline) { $amended_config_file_contents = preg_replace('/errorBaseline=".*?"/', "errorBaseline=\"{$baseline_path}\"", $config_file_contents); } else { $end_psalm_open_tag = strpos($config_file_contents, '>', (int) strpos($config_file_contents, '", $end_psalm_open_tag, 1); } else { $amended_config_file_contents = substr_replace($config_file_contents, " errorBaseline=\"{$baseline_path}\">", $end_psalm_open_tag, 1); } } file_put_contents($config_file, $amended_config_file_contents); } public static function getPathToConfig(array $options) : ?string { $path_to_config = isset($options['c']) && is_string($options['c']) ? realpath($options['c']) : null; if ($path_to_config === \false) { fwrite(STDERR, 'Could not resolve path to config ' . (string) ($options['c'] ?? '') . PHP_EOL); exit(1); } return $path_to_config; } /** * @param array> $options * @throws ConfigException */ public static function setMemoryLimit(array $options) : void { if (!array_key_exists('use-ini-defaults', $options)) { ini_set('display_errors', 'stderr'); ini_set('display_startup_errors', '1'); $memoryLimit = 8 * 1024 * 1024 * 1024; if (array_key_exists('memory-limit', $options)) { $memoryLimit = $options['memory-limit']; if (!is_scalar($memoryLimit)) { throw new ConfigException('Invalid memory limit specified.'); } } ini_set('memory_limit', (string) $memoryLimit); } } public static function initPhpVersion(array $options, Config $config, ProjectAnalyzer $project_analyzer) : void { $source = null; if (isset($options['php-version'])) { if (!is_string($options['php-version'])) { fwrite(STDERR, 'Expecting a version number in the format x.y' . PHP_EOL); exit(1); } $version = $options['php-version']; $source = 'cli'; } elseif ($version = $config->getPhpVersionFromConfig()) { $source = 'config'; } elseif ($version = $config->getPHPVersionFromComposerJson()) { $source = 'composer'; } if ($version !== null && $source !== null) { try { $project_analyzer->setPhpVersion($version, $source); } catch (UnexpectedValueException $e) { fwrite(STDERR, $e->getMessage() . PHP_EOL); exit(1); } } } public static function runningInCI() : bool { return isset($_SERVER['TRAVIS']) || isset($_SERVER['CIRCLECI']) || isset($_SERVER['APPVEYOR']) || isset($_SERVER['JENKINS_URL']) || isset($_SERVER['SCRUTINIZER']) || isset($_SERVER['GITLAB_CI']) || isset($_SERVER['GITHUB_WORKFLOW']) || isset($_SERVER['DRONE']); } public static function checkRuntimeRequirements() : void { $required_php_version = 70400; $required_php_version_text = '7.4.0'; // the following list was taken from vendor/composer/platform_check.php // It includes both Psalm's requirements (from composer.json) and the // requirements of our dependencies `netresearch/jsonmapper` and // `phpdocumentor/reflection-docblock`. The latter is transitive // dependency of `felixfbecker/advanced-json-rpc` $required_extensions = ['dom', 'filter', 'json', 'libxml', 'pcre', 'reflection', 'simplexml', 'spl', 'tokenizer']; $issues = []; if (PHP_VERSION_ID < $required_php_version) { $issues[] = 'Psalm requires a PHP version ">= ' . $required_php_version_text . '".' . ' You are running ' . PHP_VERSION . '.'; } $missing_extensions = array_filter($required_extensions, static fn(string $ext) => !extension_loaded($ext)); if ($missing_extensions) { $issues[] = 'Psalm requires the following PHP extensions to be installed: ' . implode(', ', $missing_extensions) . '.'; } if ($issues) { fwrite(STDERR, 'Psalm has detected issues in your platform:' . PHP_EOL . PHP_EOL . implode(PHP_EOL, $issues) . PHP_EOL . PHP_EOL); exit(1); } } } stopTraversal = \false; } /** * Recursively traverse a node. * * @param Node $node node to traverse * @return Node Result of traversal (may be original node or new one) */ protected function traverseNode(Node $node) : Node { foreach ($node->getSubNodeNames() as $name) { $subNode =& $node->{$name}; if (is_array($subNode)) { $subNode = $this->traverseArray($subNode); if ($this->stopTraversal) { break; } } elseif ($subNode instanceof Node) { $traverseChildren = \true; foreach ($this->visitors as $visitor) { $return = $visitor->enterNode($subNode, $traverseChildren); if (null !== $return) { if ($return instanceof Node) { $subNode = $return; } elseif (self::DONT_TRAVERSE_CHILDREN === $return) { $traverseChildren = \false; } elseif (self::STOP_TRAVERSAL === $return) { $this->stopTraversal = \true; break 2; } else { throw new LogicException('enterNode() returned invalid value of type ' . gettype($return)); } } } if ($traverseChildren) { $subNode = $this->traverseNode($subNode); if ($this->stopTraversal) { break; } } foreach ($this->visitors as $visitor) { $return = $visitor->leaveNode($subNode); if (null !== $return) { if ($return instanceof Node) { $subNode = $return; } elseif (self::STOP_TRAVERSAL === $return) { $this->stopTraversal = \true; break 2; } elseif (is_array($return)) { throw new LogicException('leaveNode() may only return an array ' . 'if the parent structure is an array'); } else { throw new LogicException('leaveNode() returned invalid value of type ' . gettype($return)); } } } } } return $node; } /** * Recursively traverse array (usually of nodes). * * @param array $nodes Array to traverse * @return array Result of traversal (may be original array or changed one) */ protected function traverseArray(array $nodes) : array { $doNodes = []; foreach ($nodes as $i => &$node) { if ($node instanceof Node) { $traverseChildren = \true; foreach ($this->visitors as $visitor) { $return = $visitor->enterNode($node, $traverseChildren); if (null !== $return) { if ($return instanceof Node) { $node = $return; } elseif (self::DONT_TRAVERSE_CHILDREN === $return) { $traverseChildren = \false; } elseif (self::STOP_TRAVERSAL === $return) { $this->stopTraversal = \true; break 2; } else { throw new LogicException('enterNode() returned invalid value of type ' . gettype($return)); } } } if ($traverseChildren) { $node = $this->traverseNode($node); if ($this->stopTraversal) { break; } } foreach ($this->visitors as $visitor) { $return = $visitor->leaveNode($node); if (null !== $return) { if ($return instanceof Node) { $node = $return; } elseif (is_array($return)) { $doNodes[] = [$i, $return]; break; } elseif (self::REMOVE_NODE === $return) { $doNodes[] = [$i, []]; break; } elseif (self::STOP_TRAVERSAL === $return) { $this->stopTraversal = \true; break 2; } elseif (\false === $return) { throw new LogicException('bool(false) return from leaveNode() no longer supported. ' . 'Return NodeTraverser::REMOVE_NODE instead'); } else { throw new LogicException('leaveNode() returned invalid value of type ' . gettype($return)); } } } } elseif (is_array($node)) { throw new LogicException('Invalid node structure: Contains nested arrays'); } } if (!empty($doNodes)) { while ([$i, $replace] = array_pop($doNodes)) { array_splice($nodes, $i, 1, $replace); } } return $nodes; } } getBuilder(); if ($type->getLiteralStrings()) { $type->addType(new TString()); } if ($type->getLiteralInts()) { $type->addType(new TInt()); } if ($type->getLiteralFloats()) { $type->addType(new TFloat()); } $this->type = $type->freeze(); } } } [...self::getConstantNodes($codebase, $storage), ...self::getPropertyNodes($storage), ...self::getMethodNodes($storage)]]; $docblock = new ParsedDocblock('', []); $template_offset = 0; foreach ($storage->template_types ?: [] as $template_name => $map) { $type = \array_values($map)[0]; $key = isset($storage->template_covariants[$template_offset]) ? 'template-covariant' : 'template'; $docblock->tags[$key][] = $template_name . ' as ' . $type->toNamespacedString(null, [], null, \false); $template_offset++; } $attrs = ['comments' => $docblock->tags ? [new PhpParser\Comment\Doc(rtrim($docblock->render(' ')))] : []]; if ($storage->is_interface) { if ($storage->direct_interface_parents) { $subnodes['extends'] = []; foreach ($storage->direct_interface_parents as $direct_interface_parent) { $subnodes['extends'][] = new VirtualFullyQualified($direct_interface_parent); } } return new VirtualInterface($classlike_name, $subnodes, $attrs); } if ($storage->is_trait) { return new VirtualTrait($classlike_name, $subnodes, $attrs); } if ($storage->parent_class) { $subnodes['extends'] = new VirtualFullyQualified($storage->parent_class); } else { if ($storage->direct_class_interfaces) { $subnodes['implements'] = []; foreach ($storage->direct_class_interfaces as $direct_class_interface) { $subnodes['implements'][] = new VirtualFullyQualified($direct_class_interface); } } } return new VirtualClass($classlike_name, $subnodes, $attrs); } /** * @return list */ private static function getConstantNodes(Codebase $codebase, ClassLikeStorage $storage) : array { $constant_nodes = []; foreach ($storage->constants as $constant_name => $constant_storage) { if ($constant_storage->unresolved_node) { $type = new Union([ConstantTypeResolver::resolve($codebase->classlikes, $constant_storage->unresolved_node)]); } elseif ($constant_storage->type) { $type = $constant_storage->type; } else { throw new UnexpectedValueException('bad'); } $constant_nodes[] = new VirtualClassConst([new VirtualConst($constant_name, \Psalm\Internal\Stubs\Generator\StubsGenerator::getExpressionFromType($type))], $constant_storage->visibility === ClassLikeAnalyzer::VISIBILITY_PUBLIC ? PhpParser\Node\Stmt\Class_::MODIFIER_PUBLIC : ($constant_storage->visibility === ClassLikeAnalyzer::VISIBILITY_PROTECTED ? PhpParser\Node\Stmt\Class_::MODIFIER_PROTECTED : PhpParser\Node\Stmt\Class_::MODIFIER_PRIVATE)); } return $constant_nodes; } /** * @return list */ private static function getPropertyNodes(ClassLikeStorage $storage) : array { $namespace_name = \implode('\\', array_slice(\explode('\\', $storage->name), 0, -1)); $property_nodes = []; foreach ($storage->properties as $property_name => $property_storage) { switch ($property_storage->visibility) { case ClassLikeAnalyzer::VISIBILITY_PRIVATE: $flag = PhpParser\Node\Stmt\Class_::MODIFIER_PRIVATE; break; case ClassLikeAnalyzer::VISIBILITY_PROTECTED: $flag = PhpParser\Node\Stmt\Class_::MODIFIER_PROTECTED; break; default: $flag = PhpParser\Node\Stmt\Class_::MODIFIER_PUBLIC; break; } $docblock = new ParsedDocblock('', []); if ($property_storage->type && $property_storage->signature_type !== $property_storage->type) { $docblock->tags['var'][] = $property_storage->type->toNamespacedString($namespace_name, [], null, \false); } $property_nodes[] = new VirtualProperty($flag | ($property_storage->is_static ? PhpParser\Node\Stmt\Class_::MODIFIER_STATIC : 0), [new VirtualPropertyProperty($property_name, $property_storage->suggested_type ? \Psalm\Internal\Stubs\Generator\StubsGenerator::getExpressionFromType($property_storage->suggested_type) : null)], ['comments' => $docblock->tags ? [new PhpParser\Comment\Doc(rtrim($docblock->render(' ')))] : []], $property_storage->signature_type ? \Psalm\Internal\Stubs\Generator\StubsGenerator::getParserTypeFromPsalmType($property_storage->signature_type) : null); } return $property_nodes; } /** * @return list */ private static function getMethodNodes(ClassLikeStorage $storage) : array { $namespace_name = \implode('\\', array_slice(\explode('\\', $storage->name), 0, -1)); $method_nodes = []; foreach ($storage->methods as $method_storage) { if (!$method_storage->cased_name) { throw new UnexpectedValueException('very bad'); } switch ($method_storage->visibility) { case ReflectionProperty::IS_PRIVATE: $flag = PhpParser\Node\Stmt\Class_::MODIFIER_PRIVATE; break; case ReflectionProperty::IS_PROTECTED: $flag = PhpParser\Node\Stmt\Class_::MODIFIER_PROTECTED; break; default: $flag = PhpParser\Node\Stmt\Class_::MODIFIER_PUBLIC; break; } $docblock = new ParsedDocblock('', []); foreach ($method_storage->template_types ?: [] as $template_name => $map) { $type = \array_values($map)[0]; $docblock->tags['template'][] = $template_name . ' as ' . $type->toNamespacedString($namespace_name, [], null, \false); } foreach ($method_storage->params as $param) { if ($param->type && $param->type !== $param->signature_type) { $docblock->tags['param'][] = $param->type->toNamespacedString($namespace_name, [], null, \false) . ' $' . $param->name; } } if ($method_storage->return_type && $method_storage->signature_return_type !== $method_storage->return_type) { $docblock->tags['return'][] = $method_storage->return_type->toNamespacedString($namespace_name, [], null, \false); } foreach ($method_storage->throws ?: [] as $exception_name => $_) { $docblock->tags['throws'][] = Type::getStringFromFQCLN($exception_name, $namespace_name, [], null, \false); } $method_nodes[] = new VirtualClassMethod($method_storage->cased_name, ['flags' => $flag | ($method_storage->is_static ? PhpParser\Node\Stmt\Class_::MODIFIER_STATIC : 0) | ($method_storage->abstract ? PhpParser\Node\Stmt\Class_::MODIFIER_ABSTRACT : 0), 'params' => \Psalm\Internal\Stubs\Generator\StubsGenerator::getFunctionParamNodes($method_storage), 'returnType' => $method_storage->signature_return_type ? \Psalm\Internal\Stubs\Generator\StubsGenerator::getParserTypeFromPsalmType($method_storage->signature_return_type) : null, 'stmts' => $storage->is_interface || $method_storage->abstract ? null : []], ['comments' => $docblock->tags ? [new PhpParser\Comment\Doc(rtrim($docblock->render(' ')))] : []]); } return $method_nodes; } } getAll() as $storage) { if (strpos($storage->name, 'Psalm\\') === 0) { continue; } if ($storage->location && strpos($storage->location->file_path, $psalm_base) === 0) { continue; } if ($storage->stubbed) { continue; } $name_parts = \explode('\\', $storage->name); $classlike_name = \array_pop($name_parts); $namespace_name = \implode('\\', $name_parts); if (!isset($namespaced_nodes[$namespace_name])) { $namespaced_nodes[$namespace_name] = []; } $namespaced_nodes[$namespace_name][$classlike_name] = \Psalm\Internal\Stubs\Generator\ClassLikeStubGenerator::getClassLikeNode($codebase, $storage, $classlike_name); } $all_function_names = []; foreach ($codebase->functions->getAllStubbedFunctions() as $function_storage) { if ($function_storage->location && strpos($function_storage->location->file_path, $psalm_base) === 0) { continue; } if (!$function_storage->cased_name) { throw new UnexpectedValueException('very bad'); } $fq_name = $function_storage->cased_name; $all_function_names[$fq_name] = \true; $name_parts = \explode('\\', $fq_name); $function_name = \array_pop($name_parts); $namespace_name = \implode('\\', $name_parts); $namespaced_nodes[$namespace_name][$fq_name] = self::getFunctionNode($function_storage, $function_name, $namespace_name); } foreach ($codebase->getAllStubbedConstants() as $fq_name => $type) { if ($type->isMixed()) { continue; } $name_parts = \explode('\\', $fq_name); $constant_name = \array_pop($name_parts); $namespace_name = \implode('\\', $name_parts); $namespaced_nodes[$namespace_name][$fq_name] = new StmtVirtualConst_([new VirtualConst($constant_name, self::getExpressionFromType($type))]); } foreach ($file_provider->getAll() as $file_storage) { if (strpos($file_storage->file_path, $psalm_base) === 0) { continue; } foreach ($file_storage->functions as $function_storage) { if (!$function_storage->cased_name) { continue; } $fq_name = $function_storage->cased_name; if (isset($all_function_names[$fq_name])) { continue; } $all_function_names[$fq_name] = \true; $name_parts = \explode('\\', $fq_name); $function_name = \array_pop($name_parts); $namespace_name = \implode('\\', $name_parts); $namespaced_nodes[$namespace_name][$fq_name] = self::getFunctionNode($function_storage, $function_name, $namespace_name); } foreach ($file_storage->constants as $fq_name => $type) { if ($type->isMixed()) { continue; } $name_parts = \explode('\\', $fq_name); $constant_name = \array_pop($name_parts); $namespace_name = \implode('\\', $name_parts); $namespaced_nodes[$namespace_name][$fq_name] = new StmtVirtualConst_([new VirtualConst($constant_name, self::getExpressionFromType($type))]); } } \ksort($namespaced_nodes); $namespace_stmts = []; foreach ($namespaced_nodes as $namespace_name => $stmts) { \ksort($stmts); $namespace_stmts[] = new VirtualNamespace($namespace_name ? new VirtualName($namespace_name) : null, \array_values($stmts), ['kind' => PhpParser\Node\Stmt\Namespace_::KIND_BRACED]); } $prettyPrinter = new PhpParser\PrettyPrinter\Standard(); return $prettyPrinter->prettyPrintFile($namespace_stmts); } private static function getFunctionNode(FunctionLikeStorage $function_storage, string $function_name, string $namespace_name) : PhpParser\Node\Stmt\Function_ { $docblock = new ParsedDocblock('', []); foreach ($function_storage->template_types ?: [] as $template_name => $map) { $type = \array_values($map)[0]; $docblock->tags['template'][] = $template_name . ' as ' . $type->toNamespacedString($namespace_name, [], null, \false); } foreach ($function_storage->params as $param) { if ($param->type && $param->type !== $param->signature_type) { $docblock->tags['param'][] = $param->type->toNamespacedString($namespace_name, [], null, \false) . ' $' . $param->name; } } if ($function_storage->return_type && $function_storage->signature_return_type !== $function_storage->return_type) { $docblock->tags['return'][] = $function_storage->return_type->toNamespacedString($namespace_name, [], null, \false); } foreach ($function_storage->throws ?: [] as $exception_name => $_) { $docblock->tags['throws'][] = Type::getStringFromFQCLN($exception_name, $namespace_name, [], null, \false); } return new VirtualFunction($function_name, ['params' => self::getFunctionParamNodes($function_storage), 'returnType' => $function_storage->signature_return_type ? self::getParserTypeFromPsalmType($function_storage->signature_return_type) : null, 'stmts' => []], ['comments' => $docblock->tags ? [new PhpParser\Comment\Doc(rtrim($docblock->render(' ')))] : []]); } /** * @return list */ public static function getFunctionParamNodes(FunctionLikeStorage $method_storage) : array { $param_nodes = []; foreach ($method_storage->params as $param) { $param_nodes[] = new VirtualParam(new VirtualVariable($param->name), $param->default_type instanceof Union ? self::getExpressionFromType($param->default_type) : null, $param->signature_type ? self::getParserTypeFromPsalmType($param->signature_type) : null, $param->by_ref, $param->is_variadic); } return $param_nodes; } /** * @return PhpParser\Node\Identifier|PhpParser\Node\Name\FullyQualified|PhpParser\Node\NullableType|null */ public static function getParserTypeFromPsalmType(Union $type) : ?PhpParser\NodeAbstract { $nullable = $type->isNullable(); foreach ($type->getAtomicTypes() as $atomic_type) { if ($atomic_type instanceof TNull) { continue; } if ($atomic_type instanceof Scalar || $atomic_type instanceof TObject || $atomic_type instanceof TArray || $atomic_type instanceof TIterable) { $identifier_string = $atomic_type->toPhpString(null, [], null, 80000); if ($identifier_string === null) { throw new UnexpectedValueException($atomic_type->getId() . ' could not be converted to an identifier'); } $identifier = new VirtualIdentifier($identifier_string); if ($nullable) { return new VirtualNullableType($identifier); } return $identifier; } if ($atomic_type instanceof TNamedObject) { $name_node = new VirtualFullyQualified($atomic_type->value); if ($nullable) { return new VirtualNullableType($name_node); } return $name_node; } } return null; } public static function getExpressionFromType(Union $type) : PhpParser\Node\Expr { foreach ($type->getAtomicTypes() as $atomic_type) { if ($atomic_type instanceof TLiteralClassString) { return new VirtualClassConstFetch(new VirtualName('\\' . $atomic_type->value), new VirtualIdentifier('class')); } if ($atomic_type instanceof TLiteralString) { return new VirtualString($atomic_type->value); } if ($atomic_type instanceof TLiteralInt) { return new VirtualLNumber($atomic_type->value); } if ($atomic_type instanceof TLiteralFloat) { return new VirtualDNumber($atomic_type->value); } if ($atomic_type instanceof TFalse) { return new VirtualConstFetch(new VirtualName('false')); } if ($atomic_type instanceof TTrue) { return new VirtualConstFetch(new VirtualName('true')); } if ($atomic_type instanceof TNull) { return new VirtualConstFetch(new VirtualName('null')); } if ($atomic_type instanceof TArray) { return new VirtualArray([]); } if ($atomic_type instanceof TKeyedArray) { $new_items = []; foreach ($atomic_type->properties as $property_name => $property_type) { if ($atomic_type->is_list) { $key_type = null; } elseif (is_int($property_name)) { $key_type = new VirtualLNumber($property_name); } else { $key_type = new VirtualString($property_name); } $new_items[] = new VirtualArrayItem(self::getExpressionFromType($property_type), $key_type); } return new VirtualArray($new_items); } if ($atomic_type instanceof TEnumCase) { return new VirtualClassConstFetch(new VirtualName('\\' . $atomic_type->value), new VirtualIdentifier($atomic_type->case_name)); } } return new VirtualString('Psalm could not infer this type'); } } > * > */ private static array $handlers = []; public function __construct() { self::$handlers = []; $this->registerClass(PdoStatementSetFetchMode::class); } /** * @param class-string $class */ public function registerClass(string $class) : void { if (is_subclass_of($class, MethodParamsProviderInterface::class, \true)) { $callable = Closure::fromCallable([$class, 'getMethodParams']); foreach ($class::getClassLikeNames() as $fq_classlike_name) { $this->registerClosure($fq_classlike_name, $callable); } } } /** * @param Closure(MethodParamsProviderEvent): ?array $c */ public function registerClosure(string $fq_classlike_name, Closure $c) : void { self::$handlers[strtolower($fq_classlike_name)][] = $c; } public function has(string $fq_classlike_name) : bool { return isset(self::$handlers[strtolower($fq_classlike_name)]); } /** * @param ?list $call_args * @return ?list */ public function getMethodParams(string $fq_classlike_name, string $method_name_lowercase, ?array $call_args = null, ?StatementsSource $statements_source = null, ?Context $context = null, ?CodeLocation $code_location = null) : ?array { foreach (self::$handlers[strtolower($fq_classlike_name)] ?? [] as $class_handler) { $event = new MethodParamsProviderEvent($fq_classlike_name, $method_name_lowercase, $call_args, $statements_source, $context, $code_location); $result = $class_handler($event); if ($result !== null) { return array_values($result); } } return null; } } * > */ private static array $handlers = []; public function __construct() { self::$handlers = []; $this->registerClass(DomNodeAppendChild::class); $this->registerClass(ImagickPixelColorReturnTypeProvider::class); $this->registerClass(PdoStatementReturnTypeProvider::class); $this->registerClass(ClosureFromCallableReturnTypeProvider::class); $this->registerClass(DateTimeModifyReturnTypeProvider::class); } /** * @param class-string $class */ public function registerClass(string $class) : void { if (is_subclass_of($class, MethodReturnTypeProviderInterface::class, \true)) { $callable = Closure::fromCallable([$class, 'getMethodReturnType']); foreach ($class::getClassLikeNames() as $fq_classlike_name) { $this->registerClosure($fq_classlike_name, $callable); } } } /** * @param Closure(MethodReturnTypeProviderEvent): ?Union $c */ public function registerClosure(string $fq_classlike_name, Closure $c) : void { self::$handlers[strtolower($fq_classlike_name)][] = $c; } public function has(string $fq_classlike_name) : bool { return isset(self::$handlers[strtolower($fq_classlike_name)]); } /** * @param PhpParser\Node\Expr\MethodCall|PhpParser\Node\Expr\StaticCall $stmt * @param non-empty-list|null $template_type_parameters */ public function getReturnType(StatementsSource $statements_source, string $fq_classlike_name, string $method_name, $stmt, Context $context, CodeLocation $code_location, ?array $template_type_parameters = null, ?string $called_fq_classlike_name = null, ?string $called_method_name = null) : ?Union { foreach (self::$handlers[strtolower($fq_classlike_name)] ?? [] as $class_handler) { $event = new MethodReturnTypeProviderEvent($statements_source, $fq_classlike_name, strtolower($method_name), $stmt, $context, $code_location, $template_type_parameters, $called_fq_classlike_name, $called_method_name ? strtolower($called_method_name) : null); $result = $class_handler($event); if ($result) { return $result; } } return null; } } cache = new Cache($config); $storage_dir = dirname(__DIR__, 2) . DIRECTORY_SEPARATOR . 'Storage' . DIRECTORY_SEPARATOR; $dependent_files = [$storage_dir . 'FileStorage.php', $storage_dir . 'FunctionLikeStorage.php', $storage_dir . 'ClassLikeStorage.php', $storage_dir . 'MethodStorage.php', $storage_dir . 'FunctionLikeParameter.php']; if ($config->eventDispatcher->hasAfterClassLikeVisitHandlers()) { $dependent_files = array_merge($dependent_files, $config->plugin_paths); } foreach ($dependent_files as $dependent_file_path) { if (!file_exists($dependent_file_path)) { throw new UnexpectedValueException($dependent_file_path . ' must exist'); } $this->modified_timestamps .= ' ' . filemtime($dependent_file_path); } $this->modified_timestamps .= $config->computeHash(); } public function writeToCache(FileStorage $storage, string $file_contents) : void { $file_path = strtolower($storage->file_path); $storage->hash = $this->getCacheHash($file_path, $file_contents); $this->storeInCache($file_path, $storage); } /** * @param lowercase-string $file_path */ protected function storeInCache(string $file_path, FileStorage $storage) : void { $cache_location = $this->getCacheLocationForPath($file_path, \true); $this->cache->saveItem($cache_location, $storage); } public function getLatestFromCache(string $file_path, string $file_contents) : ?FileStorage { $file_path = strtolower($file_path); $cached_value = $this->loadFromCache($file_path); if (!$cached_value) { return null; } $cache_hash = $this->getCacheHash($file_path, $file_contents); /** @psalm-suppress TypeDoesNotContainType */ if (@get_class($cached_value) === '__PHP_Incomplete_Class' || $cache_hash !== $cached_value->hash) { $this->removeCacheForFile($file_path); return null; } return $cached_value; } public function removeCacheForFile(string $file_path) : void { $this->cache->deleteItem($this->getCacheLocationForPath(strtolower($file_path))); } private function getCacheHash(string $_unused_file_path, string $file_contents) : string { // do not concatenate, as $file_contents can be big and performance will be bad // the timestamp is only needed if we don't have file contents // as same contents should give same results, independent of when file was modified $data = $file_contents ? $file_contents : $this->modified_timestamps; return PHP_VERSION_ID >= 80100 ? hash('xxh128', $data) : hash('md4', $data); } /** * @param lowercase-string $file_path */ protected function loadFromCache(string $file_path) : ?FileStorage { $storage = $this->cache->getItem($this->getCacheLocationForPath($file_path)); if ($storage instanceof FileStorage) { return $storage; } return null; } private function getCacheLocationForPath(string $file_path, bool $create_directory = \false) : string { $root_cache_directory = $this->cache->getCacheDirectory(); if (!$root_cache_directory) { throw new UnexpectedValueException('No cache directory defined'); } $parser_cache_directory = $root_cache_directory . DIRECTORY_SEPARATOR . self::FILE_STORAGE_CACHE_DIRECTORY; if ($create_directory && !is_dir($parser_cache_directory)) { try { if (mkdir($parser_cache_directory, 0777, \true) === \false) { // any other error than directory already exists/permissions issue throw new RuntimeException('Failed to create ' . $parser_cache_directory . ' cache directory for unknown reasons'); } } catch (RuntimeException $e) { // Race condition (#4483) if (!is_dir($parser_cache_directory)) { // rethrow the error with default message // it contains the reason why creation failed throw $e; } } } if (PHP_VERSION_ID >= 80100) { $hash = hash('xxh128', $file_path); } else { $hash = hash('md4', $file_path); } return $parser_cache_directory . DIRECTORY_SEPARATOR . $hash . ($this->cache->use_igbinary ? '-igbinary' : ''); } } * > */ private static array $handlers = []; public function __construct() { self::$handlers = []; } /** * @param class-string * |class-string $class */ public function registerClass(string $class) : void { if (is_subclass_of($class, MethodVisibilityProviderInterface::class, \true)) { $callable = Closure::fromCallable([$class, 'isMethodVisible']); foreach ($class::getClassLikeNames() as $fq_classlike_name) { $this->registerClosure($fq_classlike_name, $callable); } } } /** * @param Closure(MethodVisibilityProviderEvent): ?bool $c */ public function registerClosure(string $fq_classlike_name, Closure $c) : void { self::$handlers[strtolower($fq_classlike_name)][] = $c; } public function has(string $fq_classlike_name) : bool { return isset(self::$handlers[strtolower($fq_classlike_name)]); } public function isMethodVisible(StatementsSource $source, string $fq_classlike_name, string $method_name, Context $context, ?CodeLocation $code_location = null) : ?bool { foreach (self::$handlers[strtolower($fq_classlike_name)] ?? [] as $method_handler) { $event = new MethodVisibilityProviderEvent($source, $fq_classlike_name, $method_name, $context, $code_location); $method_visible = $method_handler($event); if ($method_visible !== null) { return $method_visible; } } return null; } } * > */ private static array $handlers = []; public function __construct() { self::$handlers = []; } /** * @param class-string $class */ public function registerClass(string $class) : void { $callable = Closure::fromCallable([$class, 'doesMethodExist']); foreach ($class::getClassLikeNames() as $fq_classlike_name) { $this->registerClosure($fq_classlike_name, $callable); } } /** * @param Closure(MethodExistenceProviderEvent): ?bool $c */ public function registerClosure(string $fq_classlike_name, Closure $c) : void { self::$handlers[strtolower($fq_classlike_name)][] = $c; } public function has(string $fq_classlike_name) : bool { return isset(self::$handlers[strtolower($fq_classlike_name)]); } public function doesMethodExist(string $fq_classlike_name, string $method_name_lowercase, ?StatementsSource $source = null, ?CodeLocation $code_location = null) : ?bool { foreach (self::$handlers[strtolower($fq_classlike_name)] ?? [] as $method_handler) { $event = new MethodExistenceProviderEvent($fq_classlike_name, $method_name_lowercase, $source, $code_location); $method_exists = $method_handler($event); if ($method_exists !== null) { return $method_exists; } } return null; } } * > */ private static array $handlers = []; public function __construct() { self::$handlers = []; } /** * @param class-string $class */ public function registerClass(string $class) : void { if (is_subclass_of($class, FunctionExistenceProviderInterface::class, \true)) { $callable = Closure::fromCallable([$class, 'doesFunctionExist']); foreach ($class::getFunctionIds() as $function_id) { $this->registerClosure($function_id, $callable); } } } /** * @param lowercase-string $function_id * @param Closure(FunctionExistenceProviderEvent): ?bool $c */ public function registerClosure(string $function_id, Closure $c) : void { self::$handlers[$function_id][] = $c; } public function has(string $function_id) : bool { return isset(self::$handlers[strtolower($function_id)]); } public function doesFunctionExist(StatementsSource $statements_source, string $function_id) : ?bool { foreach (self::$handlers[strtolower($function_id)] ?? [] as $function_handler) { $event = new FunctionExistenceProviderEvent($statements_source, $function_id); $function_exists = $function_handler($event); if ($function_exists !== null) { return $function_exists; } } return null; } } */ public array $fake_files = []; /** * @var array */ public array $fake_file_times = []; /** * @var array */ public array $fake_directories = []; public function fileExists(string $file_path) : bool { return isset($this->fake_files[$file_path]) || parent::fileExists($file_path); } public function isDirectory(string $file_path) : bool { return isset($this->fake_directories[$file_path]) || parent::isDirectory($file_path); } /** @psalm-external-mutation-free */ public function getContents(string $file_path, bool $go_to_source = \false) : string { if (!$go_to_source && isset($this->temp_files[$file_path])) { return $this->temp_files[$file_path]['content']; } return $this->fake_files[$file_path] ?? parent::getContents($file_path); } public function setContents(string $file_path, string $file_contents) : void { $this->fake_files[$file_path] = $file_contents; } public function setOpenContents(string $file_path, ?string $file_contents = null) : void { if (isset($this->fake_files[$file_path])) { $this->fake_files[$file_path] = $file_contents ?? $this->getContents($file_path, \true); } } public function getModifiedTime(string $file_path) : int { return $this->fake_file_times[$file_path] ?? parent::getModifiedTime($file_path); } public function registerFile(string $file_path, string $file_contents) : void { $this->fake_files[$file_path] = $file_contents; $this->fake_file_times[$file_path] = (int) microtime(\true); } public function deleteFile(string $file_path) : void { unset($this->fake_files[$file_path]); unset($this->fake_file_times[$file_path]); } /** * @param array $file_extensions * @param null|callable(string):bool $filter * @return list */ public function getFilesInDir(string $dir_path, array $file_extensions, ?callable $filter = null) : array { $file_paths = parent::getFilesInDir($dir_path, $file_extensions, $filter); foreach ($this->fake_files as $file_path => $_) { if (strpos($file_path, $dir_path) === 0) { $file_paths[] = $file_path; } } return $file_paths; } } * > */ private static array $handlers = []; public function __construct() { self::$handlers = []; } /** * @param class-string $class */ public function registerClass(string $class) : void { $callable = Closure::fromCallable([$class, 'isPropertyVisible']); foreach ($class::getClassLikeNames() as $fq_classlike_name) { $this->registerClosure($fq_classlike_name, $callable); } } /** * @param Closure(PropertyVisibilityProviderEvent): ?bool $c */ public function registerClosure(string $fq_classlike_name, Closure $c) : void { self::$handlers[strtolower($fq_classlike_name)][] = $c; } public function has(string $fq_classlike_name) : bool { return isset(self::$handlers[strtolower($fq_classlike_name)]); } public function isPropertyVisible(StatementsSource $source, string $fq_classlike_name, string $property_name, bool $read_mode, Context $context, CodeLocation $code_location) : ?bool { foreach (self::$handlers[strtolower($fq_classlike_name)] ?? [] as $property_handler) { $event = new PropertyVisibilityProviderEvent($source, $fq_classlike_name, $property_name, $read_mode, $context, $code_location); $property_visible = $property_handler($event); if ($property_visible !== null) { return $property_visible; } } return null; } } |null */ protected ?array $existing_file_content_hashes = null; /** * A map of recently-added filename hashes to contents hashes * * @var array */ protected array $new_file_content_hashes = []; private bool $use_file_cache; public function __construct(Config $config, bool $use_file_cache = \true) { $this->cache = new Cache($config); $this->use_file_cache = $use_file_cache; } /** * @return list|null */ public function loadStatementsFromCache(string $file_path, int $file_modified_time, string $file_content_hash) : ?array { if (!$this->use_file_cache) { return null; } $cache_location = $this->getCacheLocationForPath($file_path, self::PARSER_CACHE_DIRECTORY); $file_cache_key = $this->getParserCacheKey($file_path); $file_content_hashes = $this->new_file_content_hashes + $this->getExistingFileContentHashes(); if (isset($file_content_hashes[$file_cache_key]) && $file_content_hash === $file_content_hashes[$file_cache_key] && is_readable($cache_location) && filemtime($cache_location) > $file_modified_time) { $stmts = $this->cache->getItem($cache_location); if (is_array($stmts)) { /** @var list $stmts */ return $stmts; } } return null; } /** * @return list|null */ public function loadExistingStatementsFromCache(string $file_path) : ?array { if (!$this->use_file_cache) { return null; } $cache_location = $this->getCacheLocationForPath($file_path, self::PARSER_CACHE_DIRECTORY); if (is_readable($cache_location)) { $stmts = $this->cache->getItem($cache_location); if (is_array($stmts)) { /** @var list $stmts */ return $stmts; } } return null; } public function loadExistingFileContentsFromCache(string $file_path) : ?string { if (!$this->use_file_cache) { return null; } $cache_location = $this->getCacheLocationForPath($file_path, self::FILE_CONTENTS_CACHE_DIRECTORY); $cache_item = $this->cache->getItem($cache_location); if (!is_string($cache_item)) { return null; } return $cache_item; } /** * @return array */ private function getExistingFileContentHashes() : array { if (!$this->use_file_cache) { return []; } if ($this->existing_file_content_hashes === null) { $root_cache_directory = $this->cache->getCacheDirectory(); $file_hashes_path = $root_cache_directory . DIRECTORY_SEPARATOR . self::FILE_HASHES; if (!$root_cache_directory) { throw new UnexpectedValueException('No cache directory defined'); } if (is_readable($file_hashes_path)) { $hashes_encoded = \Psalm\Internal\Provider\Providers::safeFileGetContents($file_hashes_path); if (!$hashes_encoded) { error_log('Unexpected value when loading from file content hashes'); $this->existing_file_content_hashes = []; return []; } try { $hashes_decoded = json_decode($hashes_encoded, \true, 512, JSON_THROW_ON_ERROR); } catch (JsonException $e) { error_log('Failed to parse hashes: ' . $e->getMessage()); $this->existing_file_content_hashes = []; return []; } if (!is_array($hashes_decoded)) { error_log('Unexpected value ' . gettype($hashes_decoded)); $this->existing_file_content_hashes = []; return []; } /** @var array $hashes_decoded */ $this->existing_file_content_hashes = $hashes_decoded; } else { $this->existing_file_content_hashes = []; } if (!is_readable($file_hashes_path)) { // might not exist yet $this->existing_file_content_hashes = []; return $this->existing_file_content_hashes; } $hashes_encoded = \Psalm\Internal\Provider\Providers::safeFileGetContents($file_hashes_path); if (!$hashes_encoded) { throw new UnexpectedValueException('File content hashes should be in cache'); } /** @psalm-suppress MixedAssignment */ $hashes_decoded = json_decode($hashes_encoded, \true); if (!is_array($hashes_decoded)) { throw new UnexpectedValueException('File content hashes are of invalid type ' . gettype($hashes_decoded)); } /** @var array $hashes_decoded */ $this->existing_file_content_hashes = $hashes_decoded; } return $this->existing_file_content_hashes; } /** * @param list $stmts */ public function saveStatementsToCache(string $file_path, string $file_content_hash, array $stmts, bool $touch_only) : void { $cache_location = $this->getCacheLocationForPath($file_path, self::PARSER_CACHE_DIRECTORY, !$touch_only); if ($touch_only) { touch($cache_location); } else { $this->cache->saveItem($cache_location, $stmts); $file_cache_key = $this->getParserCacheKey($file_path); $this->new_file_content_hashes[$file_cache_key] = $file_content_hash; } } /** * @return array */ public function getNewFileContentHashes() : array { return $this->new_file_content_hashes; } /** * @param array $file_content_hashes */ public function addNewFileContentHashes(array $file_content_hashes) : void { $this->new_file_content_hashes = $file_content_hashes + $this->new_file_content_hashes; } public function saveFileContentHashes() : void { if (!$this->use_file_cache) { return; } $root_cache_directory = $this->cache->getCacheDirectory(); if (!$root_cache_directory) { return; } // directory was removed most likely due to a race condition // with other psalm instances that were manually started at // the same time clearstatcache(\true, $root_cache_directory); if (!is_dir($root_cache_directory)) { return; } $file_content_hashes = $this->new_file_content_hashes + $this->getExistingFileContentHashes(); $file_hashes_path = $root_cache_directory . DIRECTORY_SEPARATOR . self::FILE_HASHES; file_put_contents($file_hashes_path, json_encode($file_content_hashes, JSON_THROW_ON_ERROR), LOCK_EX); } public function cacheFileContents(string $file_path, string $file_contents) : void { if (!$this->use_file_cache) { return; } $cache_location = $this->getCacheLocationForPath($file_path, self::FILE_CONTENTS_CACHE_DIRECTORY, \true); $this->cache->saveItem($cache_location, $file_contents); } public function deleteOldParserCaches(float $time_before) : int { $cache_directory = $this->cache->getCacheDirectory(); $this->existing_file_content_hashes = null; $this->new_file_content_hashes = []; if (!$cache_directory) { return 0; } $removed_count = 0; $cache_directory .= DIRECTORY_SEPARATOR . self::PARSER_CACHE_DIRECTORY; if (is_dir($cache_directory)) { $directory_files = scandir($cache_directory, SCANDIR_SORT_NONE); foreach ($directory_files as $directory_file) { $full_path = $cache_directory . DIRECTORY_SEPARATOR . $directory_file; if ($directory_file[0] === '.') { continue; } if (filemtime($full_path) < $time_before) { $this->cache->deleteItem($full_path); ++$removed_count; } } } return $removed_count; } private function getParserCacheKey(string $file_path) : string { if (PHP_VERSION_ID >= 80100) { $hash = hash('xxh128', $file_path); } else { $hash = hash('md4', $file_path); } return $hash . ($this->cache->use_igbinary ? '-igbinary' : '') . '-r'; } private function getCacheLocationForPath(string $file_path, string $subdirectory, bool $create_directory = \false) : string { $root_cache_directory = $this->cache->getCacheDirectory(); if (!$root_cache_directory) { throw new UnexpectedValueException('No cache directory defined'); } $parser_cache_directory = $root_cache_directory . DIRECTORY_SEPARATOR . $subdirectory; if ($create_directory && !is_dir($parser_cache_directory)) { try { if (mkdir($parser_cache_directory, 0777, \true) === \false) { // any other error than directory already exists/permissions issue throw new RuntimeException('Failed to create ' . $parser_cache_directory . ' cache directory for unknown reasons'); } } catch (RuntimeException $e) { // Race condition (#4483) if (!is_dir($parser_cache_directory)) { // rethrow the error with default message // it contains the reason why creation failed throw $e; } } } return $parser_cache_directory . DIRECTORY_SEPARATOR . $this->getParserCacheKey($file_path); } } cache = new Cache($config); $storage_dir = dirname(__DIR__, 2) . DIRECTORY_SEPARATOR . 'Storage' . DIRECTORY_SEPARATOR; $dependent_files = [$storage_dir . 'FileStorage.php', $storage_dir . 'FunctionLikeStorage.php', $storage_dir . 'ClassLikeStorage.php', $storage_dir . 'MethodStorage.php']; if ($config->eventDispatcher->hasAfterClassLikeVisitHandlers()) { $dependent_files = array_merge($dependent_files, $config->plugin_paths); } foreach ($dependent_files as $dependent_file_path) { if (!file_exists($dependent_file_path)) { throw new UnexpectedValueException($dependent_file_path . ' must exist'); } $this->modified_timestamps .= ' ' . filemtime($dependent_file_path); } $this->modified_timestamps .= $config->computeHash(); } public function writeToCache(ClassLikeStorage $storage, string $file_path, string $file_contents) : void { $fq_classlike_name_lc = strtolower($storage->name); $storage->hash = $this->getCacheHash($file_path, $file_contents); // check if we have it in cache already $cached_value = $this->loadFromCache($fq_classlike_name_lc, $file_path); if (!is_null($cached_value) && $cached_value->hash === $storage->hash) { return; } $cache_location = $this->getCacheLocationForClass($fq_classlike_name_lc, $file_path, \true); $this->cache->saveItem($cache_location, $storage); } /** * @param lowercase-string $fq_classlike_name_lc */ public function getLatestFromCache(string $fq_classlike_name_lc, ?string $file_path, ?string $file_contents) : ClassLikeStorage { $cached_value = $this->loadFromCache($fq_classlike_name_lc, $file_path); if (!$cached_value) { throw new UnexpectedValueException($fq_classlike_name_lc . ' should be in cache'); } $cache_hash = $this->getCacheHash($file_path, $file_contents); /** @psalm-suppress TypeDoesNotContainType */ if (@get_class($cached_value) === '__PHP_Incomplete_Class' || $cache_hash !== $cached_value->hash) { $this->cache->deleteItem($this->getCacheLocationForClass($fq_classlike_name_lc, $file_path)); throw new UnexpectedValueException($fq_classlike_name_lc . ' should not be outdated'); } return $cached_value; } private function getCacheHash(?string $_unused_file_path, ?string $file_contents) : string { $data = $file_contents ? $file_contents : $this->modified_timestamps; return PHP_VERSION_ID >= 80100 ? hash('xxh128', $data) : hash('md4', $data); } /** * @param lowercase-string $fq_classlike_name_lc */ private function loadFromCache(string $fq_classlike_name_lc, ?string $file_path) : ?ClassLikeStorage { $storage = $this->cache->getItem($this->getCacheLocationForClass($fq_classlike_name_lc, $file_path)); if ($storage instanceof ClassLikeStorage) { return $storage; } return null; } /** * @param lowercase-string $fq_classlike_name_lc */ private function getCacheLocationForClass(string $fq_classlike_name_lc, ?string $file_path, bool $create_directory = \false) : string { $root_cache_directory = $this->cache->getCacheDirectory(); if (!$root_cache_directory) { throw new UnexpectedValueException('No cache directory defined'); } $parser_cache_directory = $root_cache_directory . DIRECTORY_SEPARATOR . self::CLASS_CACHE_DIRECTORY; if ($create_directory && !is_dir($parser_cache_directory)) { try { if (mkdir($parser_cache_directory, 0777, \true) === \false) { // any other error than directory already exists/permissions issue throw new RuntimeException('Failed to create ' . $parser_cache_directory . ' cache directory for unknown reasons'); } } catch (RuntimeException $e) { // Race condition (#4483) if (!is_dir($parser_cache_directory)) { // rethrow the error with default message // it contains the reason why creation failed throw $e; } } } $data = $file_path ? strtolower($file_path) . ' ' : ''; $data .= $fq_classlike_name_lc; $file_path_sha = PHP_VERSION_ID >= 80100 ? hash('xxh128', $data) : hash('md4', $data); return $parser_cache_directory . DIRECTORY_SEPARATOR . $file_path_sha . ($this->cache->use_igbinary ? '-igbinary' : ''); } } config = $config; $this->cache = new Cache($config); } public function hasConfigChanged() : bool { $new_hash = $this->config->computeHash(); return $new_hash !== $this->getConfigHashCache(); } public function getCachedFileReferences() : ?array { return $this->getCacheItem(self::REFERENCE_CACHE_NAME); } public function getCachedClassLikeFiles() : ?array { return $this->getCacheItem(self::CLASSLIKE_FILE_CACHE_NAME); } public function getCachedNonMethodClassReferences() : ?array { return $this->getCacheItem(self::NONMETHOD_CLASS_REFERENCE_CACHE_NAME); } public function getCachedMethodClassReferences() : ?array { return $this->getCacheItem(self::METHOD_CLASS_REFERENCE_CACHE_NAME); } public function getCachedMethodMemberReferences() : ?array { return $this->getCacheItem(self::CLASS_METHOD_CACHE_NAME); } public function getCachedMethodDependencies() : ?array { return $this->getCacheItem(self::METHOD_DEPENDENCIES_CACHE_NAME); } public function getCachedMethodPropertyReferences() : ?array { return $this->getCacheItem(self::CLASS_PROPERTY_CACHE_NAME); } public function getCachedMethodMethodReturnReferences() : ?array { return $this->getCacheItem(self::CLASS_METHOD_RETURN_CACHE_NAME); } public function getCachedMethodMissingMemberReferences() : ?array { return $this->getCacheItem(self::METHOD_MISSING_MEMBER_CACHE_NAME); } public function getCachedFileMemberReferences() : ?array { return $this->getCacheItem(self::FILE_CLASS_MEMBER_CACHE_NAME); } public function getCachedFilePropertyReferences() : ?array { return $this->getCacheItem(self::FILE_CLASS_PROPERTY_CACHE_NAME); } public function getCachedFileMethodReturnReferences() : ?array { return $this->getCacheItem(self::FILE_METHOD_RETURN_CACHE_NAME); } public function getCachedFileMissingMemberReferences() : ?array { return $this->getCacheItem(self::FILE_MISSING_MEMBER_CACHE_NAME); } public function getCachedMixedMemberNameReferences() : ?array { return $this->getCacheItem(self::UNKNOWN_MEMBER_CACHE_NAME); } public function getCachedMethodParamUses() : ?array { return $this->getCacheItem(self::METHOD_PARAM_USE_CACHE_NAME); } public function getCachedIssues() : ?array { return $this->getCacheItem(self::ISSUES_CACHE_NAME); } public function setCachedFileReferences(array $file_references) : void { $this->saveCacheItem(self::REFERENCE_CACHE_NAME, $file_references); } public function setCachedClassLikeFiles(array $file_references) : void { $this->saveCacheItem(self::CLASSLIKE_FILE_CACHE_NAME, $file_references); } public function setCachedNonMethodClassReferences(array $file_class_references) : void { $this->saveCacheItem(self::NONMETHOD_CLASS_REFERENCE_CACHE_NAME, $file_class_references); } public function setCachedMethodClassReferences(array $method_class_references) : void { $this->saveCacheItem(self::METHOD_CLASS_REFERENCE_CACHE_NAME, $method_class_references); } public function setCachedMethodMemberReferences(array $member_references) : void { $this->saveCacheItem(self::CLASS_METHOD_CACHE_NAME, $member_references); } public function setCachedMethodDependencies(array $member_references) : void { $this->saveCacheItem(self::METHOD_DEPENDENCIES_CACHE_NAME, $member_references); } public function setCachedMethodPropertyReferences(array $property_references) : void { $this->saveCacheItem(self::CLASS_PROPERTY_CACHE_NAME, $property_references); } public function setCachedMethodMethodReturnReferences(array $method_return_references) : void { $this->saveCacheItem(self::CLASS_METHOD_RETURN_CACHE_NAME, $method_return_references); } public function setCachedMethodMissingMemberReferences(array $member_references) : void { $this->saveCacheItem(self::METHOD_MISSING_MEMBER_CACHE_NAME, $member_references); } public function setCachedFileMemberReferences(array $member_references) : void { $this->saveCacheItem(self::FILE_CLASS_MEMBER_CACHE_NAME, $member_references); } public function setCachedFilePropertyReferences(array $property_references) : void { $this->saveCacheItem(self::FILE_CLASS_PROPERTY_CACHE_NAME, $property_references); } public function setCachedFileMethodReturnReferences(array $method_return_references) : void { $this->saveCacheItem(self::FILE_METHOD_RETURN_CACHE_NAME, $method_return_references); } public function setCachedFileMissingMemberReferences(array $member_references) : void { $this->saveCacheItem(self::FILE_MISSING_MEMBER_CACHE_NAME, $member_references); } public function setCachedMixedMemberNameReferences(array $references) : void { $this->saveCacheItem(self::UNKNOWN_MEMBER_CACHE_NAME, $references); } public function setCachedMethodParamUses(array $uses) : void { $this->saveCacheItem(self::METHOD_PARAM_USE_CACHE_NAME, $uses); } public function setCachedIssues(array $issues) : void { $this->saveCacheItem(self::ISSUES_CACHE_NAME, $issues); } /** * @return array>|false */ public function getAnalyzedMethodCache() { /** @var null|array> $cache_item */ $cache_item = $this->getCacheItem(self::ANALYZED_METHODS_CACHE_NAME); return $cache_item ?? \false; } /** * @param array> $analyzed_methods */ public function setAnalyzedMethodCache(array $analyzed_methods) : void { $this->saveCacheItem(self::ANALYZED_METHODS_CACHE_NAME, $analyzed_methods); } /** * @return array|false */ public function getFileMapCache() { /** @var array|null $cache_item */ $cache_item = $this->getCacheItem(self::FILE_MAPS_CACHE_NAME); return $cache_item ?? \false; } /** * @param array $file_maps */ public function setFileMapCache(array $file_maps) : void { $this->saveCacheItem(self::FILE_MAPS_CACHE_NAME, $file_maps); } //phpcs:disable -- Remove this once the phpstan phpdoc parser MR is merged /** * @return array|false */ public function getTypeCoverage() { //phpcs:enable -- Remove this once the phpstan phpdoc parser MR is merged /** @var array|null $cache_item */ $cache_item = $this->getCacheItem(self::TYPE_COVERAGE_CACHE_NAME); return $cache_item ?? \false; } /** * @param array $mixed_counts */ public function setTypeCoverage(array $mixed_counts) : void { $this->saveCacheItem(self::TYPE_COVERAGE_CACHE_NAME, $mixed_counts); } /** * @return string|false */ public function getConfigHashCache() { $cache_directory = $this->config->getCacheDirectory(); $config_hash_cache_location = $cache_directory . DIRECTORY_SEPARATOR . self::CONFIG_HASH_CACHE_NAME; if ($cache_directory && file_exists($config_hash_cache_location)) { return Providers::safeFileGetContents($config_hash_cache_location); } return \false; } public function setConfigHashCache(string $hash = '') : void { $cache_directory = Config::getInstance()->getCacheDirectory(); if (!$cache_directory) { return; } if ($hash === '') { $hash = $this->config->computeHash(); } if (!is_dir($cache_directory)) { try { if (mkdir($cache_directory, 0777, \true) === \false) { // any other error than directory already exists/permissions issue throw new RuntimeException('Failed to create ' . $cache_directory . ' cache directory for unknown reasons'); } } catch (RuntimeException $e) { // Race condition (#4483) if (!is_dir($cache_directory)) { // rethrow the error with default message // it contains the reason why creation failed throw $e; } } } $config_hash_cache_location = $cache_directory . DIRECTORY_SEPARATOR . self::CONFIG_HASH_CACHE_NAME; file_put_contents($config_hash_cache_location, $hash, LOCK_EX); } private function getCacheItem(string $type) : ?array { $cache_directory = $this->config->getCacheDirectory(); if (!$cache_directory) { return null; } $cache_location = $cache_directory . DIRECTORY_SEPARATOR . $type; if (!is_readable($cache_location)) { return null; } $cache_item = $this->cache->getItem($cache_location); if ($cache_item === null) { return null; } elseif (!is_array($cache_item)) { throw new UnexpectedValueException('The reference cache must be an array'); } return $cache_item; } private function saveCacheItem(string $type, array $cache_item) : void { $cache_directory = $this->config->getCacheDirectory(); if (!$cache_directory) { return; } $cache_location = $cache_directory . DIRECTORY_SEPARATOR . $type; $this->cache->saveItem($cache_location, $cache_item); } } > */ private static array $nonmethod_references_to_classes = []; /** * A lookup table used for getting all the methods that reference a class * * @var array> */ private static array $method_references_to_classes = []; /** * A lookup table used for getting all the files that reference a class member * * @var array> */ private static array $file_references_to_class_members = []; /** * A lookup table used for getting all the files that reference a class property * * @var array> */ private static array $file_references_to_class_properties = []; /** * A lookup table used for getting all the files that reference a method's return value * * @var array> */ private static array $file_references_to_method_returns = []; /** * A lookup table used for getting all the files that reference a missing class member * * @var array> */ private static array $file_references_to_missing_class_members = []; /** * @var array> */ private static array $files_inheriting_classes = []; /** * A list of all files deleted since the last successful run * * @var array|null */ private static ?array $deleted_files = null; /** * A lookup table used for getting all the files referenced by a file * * @var array, i:array}> */ private static array $file_references = []; /** * @var array> */ private static array $method_references_to_class_members = []; /** * @var array> */ private static array $method_dependencies = []; /** * @var array> */ private static array $method_references_to_class_properties = []; /** * @var array> */ private static array $method_references_to_method_returns = []; /** * @var array> */ private static array $method_references_to_missing_class_members = []; /** * @var array> */ private static array $references_to_mixed_member_names = []; /** * @var array> */ private static array $class_method_locations = []; /** * @var array> */ private static array $class_property_locations = []; /** * @var array> */ private static array $class_locations = []; /** * @var array */ private static array $classlike_files = []; /** * @var array> */ private static array $analyzed_methods = []; /** * @var array> */ private static array $issues = []; /** * @var array */ private static array $file_maps = []; /** * @var array */ private static array $mixed_counts = []; /** * @var array>> */ private static array $method_param_uses = []; private \Psalm\Internal\Provider\FileProvider $file_provider; public ?\Psalm\Internal\Provider\FileReferenceCacheProvider $cache = null; public function __construct(\Psalm\Internal\Provider\FileProvider $file_provider, ?\Psalm\Internal\Provider\FileReferenceCacheProvider $cache = null) { $this->file_provider = $file_provider; $this->cache = $cache; } /** * @return array */ public function getDeletedReferencedFiles() : array { if (self::$deleted_files === null) { self::$deleted_files = array_filter(array_keys(self::$file_references), fn(string $file_name): bool => !$this->file_provider->fileExists($file_name)); } return self::$deleted_files; } /** * @param lowercase-string $fq_class_name_lc */ public function addNonMethodReferenceToClass(string $source_file, string $fq_class_name_lc) : void { self::$nonmethod_references_to_classes[$fq_class_name_lc][$source_file] = \true; } /** * @return array> */ public function getAllNonMethodReferencesToClasses() : array { return self::$nonmethod_references_to_classes; } /** * @param array> $references */ public function addNonMethodReferencesToClasses(array $references) : void { foreach ($references as $key => $reference) { if (isset(self::$nonmethod_references_to_classes[$key])) { self::$nonmethod_references_to_classes[$key] = array_merge($reference, self::$nonmethod_references_to_classes[$key]); } else { self::$nonmethod_references_to_classes[$key] = $reference; } } } /** * @param array $map */ public function addClassLikeFiles(array $map) : void { self::$classlike_files += $map; } public function addFileReferenceToClassMember(string $source_file, string $referenced_member_id, bool $inside_return) : void { self::$file_references_to_class_members[$referenced_member_id][$source_file] = \true; if ($inside_return) { self::$file_references_to_method_returns[$referenced_member_id][$source_file] = \true; } } public function addFileReferenceToClassProperty(string $source_file, string $referenced_property_id) : void { self::$file_references_to_class_properties[$referenced_property_id][$source_file] = \true; } public function addFileReferenceToMissingClassMember(string $source_file, string $referenced_member_id) : void { self::$file_references_to_missing_class_members[$referenced_member_id][$source_file] = \true; } /** * @return array> */ public function getAllFileReferencesToClassMembers() : array { return self::$file_references_to_class_members; } /** * @return array> */ public function getAllFileReferencesToClassProperties() : array { return self::$file_references_to_class_properties; } /** * @return array> */ public function getAllFileReferencesToMethodReturns() : array { return self::$file_references_to_method_returns; } /** * @return array> */ public function getAllFileReferencesToMissingClassMembers() : array { return self::$file_references_to_missing_class_members; } /** * @param array> $references */ public function addFileReferencesToClassMembers(array $references) : void { foreach ($references as $key => $reference) { if (isset(self::$file_references_to_class_members[$key])) { self::$file_references_to_class_members[$key] = array_merge($reference, self::$file_references_to_class_members[$key]); } else { self::$file_references_to_class_members[$key] = $reference; } } } /** * @param array> $references */ public function addFileReferencesToClassProperties(array $references) : void { foreach ($references as $key => $reference) { if (isset(self::$file_references_to_class_properties[$key])) { self::$file_references_to_class_properties[$key] = array_merge($reference, self::$file_references_to_class_properties[$key]); } else { self::$file_references_to_class_properties[$key] = $reference; } } } /** * @param array> $references */ public function addFileReferencesToMethodReturns(array $references) : void { foreach ($references as $key => $reference) { if (isset(self::$file_references_to_method_returns[$key])) { self::$file_references_to_method_returns[$key] = array_merge($reference, self::$file_references_to_method_returns[$key]); } else { self::$file_references_to_method_returns[$key] = $reference; } } } /** * @param array> $references */ public function addFileReferencesToMissingClassMembers(array $references) : void { foreach ($references as $key => $reference) { if (isset(self::$file_references_to_missing_class_members[$key])) { self::$file_references_to_missing_class_members[$key] = array_merge($reference, self::$file_references_to_missing_class_members[$key]); } else { self::$file_references_to_missing_class_members[$key] = $reference; } } } public function addFileInheritanceToClass(string $source_file, string $fq_class_name_lc) : void { self::$files_inheriting_classes[$fq_class_name_lc][$source_file] = \true; } public function addMethodParamUse(string $method_id, int $offset, string $referencing_method_id) : void { self::$method_param_uses[$method_id][$offset][$referencing_method_id] = \true; } /** * @return array */ private function calculateFilesReferencingFile(Codebase $codebase, string $file) : array { $referenced_files = []; $file_classes = ClassLikeAnalyzer::getClassesForFile($codebase, $file); foreach ($file_classes as $file_class_lc => $_) { if (isset(self::$nonmethod_references_to_classes[$file_class_lc])) { $new_files = array_keys(self::$nonmethod_references_to_classes[$file_class_lc]); $referenced_files = [...$referenced_files, ...$new_files]; } if (isset(self::$method_references_to_classes[$file_class_lc])) { $new_referencing_methods = array_keys(self::$method_references_to_classes[$file_class_lc]); foreach ($new_referencing_methods as $new_referencing_method_id) { $fq_class_name_lc = explode('::', $new_referencing_method_id)[0]; try { $referenced_files[] = $codebase->scanner->getClassLikeFilePath($fq_class_name_lc); } catch (UnexpectedValueException $e) { if (isset(self::$classlike_files[$fq_class_name_lc])) { $referenced_files[] = self::$classlike_files[$fq_class_name_lc]; } } } } } return array_unique($referenced_files); } /** * @return array */ private function calculateFilesInheritingFile(Codebase $codebase, string $file) : array { $referenced_files = []; $file_classes = ClassLikeAnalyzer::getClassesForFile($codebase, $file); foreach ($file_classes as $file_class_lc => $_) { if (isset(self::$files_inheriting_classes[$file_class_lc])) { $referenced_files = [...$referenced_files, ...array_keys(self::$files_inheriting_classes[$file_class_lc])]; } } return array_unique($referenced_files); } public function removeDeletedFilesFromReferences() : void { $deleted_files = $this->getDeletedReferencedFiles(); if ($deleted_files) { foreach ($deleted_files as $file) { unset(self::$file_references[$file]); } if ($this->cache) { $this->cache->setCachedFileReferences(self::$file_references); } } } /** * @return array */ public function getFilesReferencingFile(string $file) : array { return self::$file_references[$file]['a'] ?? []; } /** * @return array */ public function getFilesInheritingFromFile(string $file) : array { return self::$file_references[$file]['i'] ?? []; } /** * @return array> */ public function getAllMethodReferencesToClassMembers() : array { return self::$method_references_to_class_members; } /** * @return array> */ public function getAllMethodDependencies() : array { return self::$method_dependencies; } /** * @return array> */ public function getAllMethodReferencesToClassProperties() : array { return self::$method_references_to_class_properties; } /** * @return array> */ public function getAllMethodReferencesToMethodReturns() : array { return self::$method_references_to_method_returns; } /** * @return array> */ public function getAllMethodReferencesToClasses() : array { return self::$method_references_to_classes; } /** * @return array> */ public function getAllMethodReferencesToMissingClassMembers() : array { return self::$method_references_to_missing_class_members; } /** * @return array> */ public function getAllReferencesToMixedMemberNames() : array { return self::$references_to_mixed_member_names; } /** * @return array>> */ public function getAllMethodParamUses() : array { return self::$method_param_uses; } /** * @psalm-suppress MixedPropertyTypeCoercion */ public function loadReferenceCache(bool $force_reload = \true) : bool { if ($this->cache && (!$this->loaded_from_cache || $force_reload)) { $this->loaded_from_cache = \true; $file_references = $this->cache->getCachedFileReferences(); if ($file_references === null) { return \false; } self::$file_references = $file_references; $nonmethod_references_to_classes = $this->cache->getCachedNonMethodClassReferences(); if ($nonmethod_references_to_classes === null) { return \false; } self::$nonmethod_references_to_classes = $nonmethod_references_to_classes; $method_references_to_classes = $this->cache->getCachedMethodClassReferences(); if ($method_references_to_classes === null) { return \false; } self::$method_references_to_classes = $method_references_to_classes; $method_references_to_class_members = $this->cache->getCachedMethodMemberReferences(); if ($method_references_to_class_members === null) { return \false; } self::$method_references_to_class_members = $method_references_to_class_members; $method_dependencies = $this->cache->getCachedMethodDependencies(); if ($method_dependencies === null) { return \false; } self::$method_dependencies = $method_dependencies; $method_references_to_class_properties = $this->cache->getCachedMethodPropertyReferences(); if ($method_references_to_class_properties === null) { return \false; } self::$method_references_to_class_properties = $method_references_to_class_properties; $method_references_to_method_returns = $this->cache->getCachedMethodMethodReturnReferences(); if ($method_references_to_method_returns === null) { return \false; } self::$method_references_to_method_returns = $method_references_to_method_returns; $method_references_to_missing_class_members = $this->cache->getCachedMethodMissingMemberReferences(); if ($method_references_to_missing_class_members === null) { return \false; } self::$method_references_to_missing_class_members = $method_references_to_missing_class_members; $file_references_to_class_members = $this->cache->getCachedFileMemberReferences(); if ($file_references_to_class_members === null) { return \false; } self::$file_references_to_class_members = $file_references_to_class_members; $file_references_to_class_properties = $this->cache->getCachedFilePropertyReferences(); if ($file_references_to_class_properties === null) { return \false; } self::$file_references_to_class_properties = $file_references_to_class_properties; $file_references_to_method_returns = $this->cache->getCachedFileMethodReturnReferences(); if ($file_references_to_method_returns === null) { return \false; } self::$file_references_to_method_returns = $file_references_to_method_returns; $file_references_to_missing_class_members = $this->cache->getCachedFileMissingMemberReferences(); if ($file_references_to_missing_class_members === null) { return \false; } self::$file_references_to_missing_class_members = $file_references_to_missing_class_members; $references_to_mixed_member_names = $this->cache->getCachedMixedMemberNameReferences(); if ($references_to_mixed_member_names === null) { return \false; } self::$references_to_mixed_member_names = $references_to_mixed_member_names; $analyzed_methods = $this->cache->getAnalyzedMethodCache(); if ($analyzed_methods === \false) { return \false; } self::$analyzed_methods = $analyzed_methods; $issues = $this->cache->getCachedIssues(); if ($issues === null) { return \false; } self::$issues = $issues; $method_param_uses = $this->cache->getCachedMethodParamUses(); if ($method_param_uses === null) { return \false; } self::$method_param_uses = $method_param_uses; $mixed_counts = $this->cache->getTypeCoverage(); if ($mixed_counts === \false) { return \false; } self::$mixed_counts = $mixed_counts; $classlike_files = $this->cache->getCachedClassLikeFiles(); if ($classlike_files === null) { return \false; } self::$classlike_files = $classlike_files; self::$file_maps = $this->cache->getFileMapCache() ?: []; return \true; } return \false; } /** * @param array $visited_files */ public function updateReferenceCache(Codebase $codebase, array $visited_files) : void { foreach ($visited_files as $file => $_) { $all_file_references = array_unique(array_merge(self::$file_references[$file]['a'] ?? [], $this->calculateFilesReferencingFile($codebase, $file))); $inheritance_references = array_unique(array_merge(self::$file_references[$file]['i'] ?? [], $this->calculateFilesInheritingFile($codebase, $file))); self::$file_references[$file] = ['a' => $all_file_references, 'i' => $inheritance_references]; } if ($this->cache) { $this->cache->setCachedFileReferences(self::$file_references); $this->cache->setCachedMethodClassReferences(self::$method_references_to_classes); $this->cache->setCachedNonMethodClassReferences(self::$nonmethod_references_to_classes); $this->cache->setCachedMethodMemberReferences(self::$method_references_to_class_members); $this->cache->setCachedMethodDependencies(self::$method_dependencies); $this->cache->setCachedMethodPropertyReferences(self::$method_references_to_class_properties); $this->cache->setCachedMethodMethodReturnReferences(self::$method_references_to_method_returns); $this->cache->setCachedFileMemberReferences(self::$file_references_to_class_members); $this->cache->setCachedFilePropertyReferences(self::$file_references_to_class_properties); $this->cache->setCachedFileMethodReturnReferences(self::$file_references_to_method_returns); $this->cache->setCachedMethodMissingMemberReferences(self::$method_references_to_missing_class_members); $this->cache->setCachedFileMissingMemberReferences(self::$file_references_to_missing_class_members); $this->cache->setCachedMixedMemberNameReferences(self::$references_to_mixed_member_names); $this->cache->setCachedMethodParamUses(self::$method_param_uses); $this->cache->setCachedIssues(self::$issues); $this->cache->setCachedClassLikeFiles(self::$classlike_files); $this->cache->setFileMapCache(self::$file_maps); $this->cache->setTypeCoverage(self::$mixed_counts); $this->cache->setAnalyzedMethodCache(self::$analyzed_methods); } } /** * @param lowercase-string $fq_class_name_lc */ public function addMethodReferenceToClass(string $calling_function_id, string $fq_class_name_lc) : void { if (!isset(self::$method_references_to_classes[$fq_class_name_lc])) { self::$method_references_to_classes[$fq_class_name_lc] = [$calling_function_id => \true]; } else { self::$method_references_to_classes[$fq_class_name_lc][$calling_function_id] = \true; } } public function addMethodReferenceToClassMember(string $calling_function_id, string $referenced_member_id, bool $inside_return) : void { if (!isset(self::$method_references_to_class_members[$referenced_member_id])) { self::$method_references_to_class_members[$referenced_member_id] = [$calling_function_id => \true]; } else { self::$method_references_to_class_members[$referenced_member_id][$calling_function_id] = \true; } if ($inside_return) { if (!isset(self::$method_references_to_method_returns[$referenced_member_id])) { self::$method_references_to_method_returns[$referenced_member_id] = [$calling_function_id => \true]; } else { self::$method_references_to_method_returns[$referenced_member_id][$calling_function_id] = \true; } } } public function addMethodDependencyToClassMember(string $calling_function_id, string $referenced_member_id) : void { if (!isset(self::$method_dependencies[$referenced_member_id])) { self::$method_dependencies[$referenced_member_id] = [$calling_function_id => \true]; } else { self::$method_dependencies[$referenced_member_id][$calling_function_id] = \true; } } public function addMethodReferenceToClassProperty(string $calling_function_id, string $referenced_property_id) : void { if (!isset(self::$method_references_to_class_properties[$referenced_property_id])) { self::$method_references_to_class_properties[$referenced_property_id] = [$calling_function_id => \true]; } else { self::$method_references_to_class_properties[$referenced_property_id][$calling_function_id] = \true; } } public function addMethodReferenceToMissingClassMember(string $calling_function_id, string $referenced_member_id) : void { if (!isset(self::$method_references_to_missing_class_members[$referenced_member_id])) { self::$method_references_to_missing_class_members[$referenced_member_id] = [$calling_function_id => \true]; } else { self::$method_references_to_missing_class_members[$referenced_member_id][$calling_function_id] = \true; } } public function addCallingLocationForClassMethod(CodeLocation $code_location, string $referenced_member_id) : void { if (!isset(self::$class_method_locations[$referenced_member_id])) { self::$class_method_locations[$referenced_member_id] = [$code_location]; } else { self::$class_method_locations[$referenced_member_id][] = $code_location; } } public function addCallingLocationForClassProperty(CodeLocation $code_location, string $referenced_property_id) : void { if (!isset(self::$class_property_locations[$referenced_property_id])) { self::$class_property_locations[$referenced_property_id] = [$code_location]; } else { self::$class_property_locations[$referenced_property_id][] = $code_location; } } public function addCallingLocationForClass(CodeLocation $code_location, string $referenced_class) : void { if (!isset(self::$class_locations[$referenced_class])) { self::$class_locations[$referenced_class] = [$code_location]; } else { self::$class_locations[$referenced_class][] = $code_location; } } public function isClassMethodReferenced(string $method_id) : bool { return !empty(self::$file_references_to_class_members[$method_id]) || !empty(self::$method_references_to_class_members[$method_id]); } public function isClassPropertyReferenced(string $property_id) : bool { return !empty(self::$file_references_to_class_properties[$property_id]) || !empty(self::$method_references_to_class_properties[$property_id]); } public function isMethodReturnReferenced(string $method_id) : bool { return !empty(self::$file_references_to_method_returns[$method_id]) || !empty(self::$method_references_to_method_returns[$method_id]); } public function isClassReferenced(string $fq_class_name_lc) : bool { return isset(self::$method_references_to_classes[$fq_class_name_lc]) || isset(self::$nonmethod_references_to_classes[$fq_class_name_lc]); } public function isMethodParamUsed(string $method_id, int $offset) : bool { return !empty(self::$method_param_uses[$method_id][$offset]); } /** * @param array> $references */ public function setNonMethodReferencesToClasses(array $references) : void { self::$nonmethod_references_to_classes = $references; } /** * @return array> */ public function getAllClassMethodLocations() : array { return self::$class_method_locations; } /** * @return array> */ public function getAllClassPropertyLocations() : array { return self::$class_property_locations; } /** * @return array> */ public function getAllClassLocations() : array { return self::$class_locations; } /** * @return array */ public function getClassMethodLocations(string $method_id) : array { return self::$class_method_locations[$method_id] ?? []; } /** * @return array */ public function getClassPropertyLocations(string $property_id) : array { return self::$class_property_locations[$property_id] ?? []; } /** * @return array */ public function getClassLocations(string $fq_class_name_lc) : array { return self::$class_locations[$fq_class_name_lc] ?? []; } /** * @param array> $references */ public function addMethodReferencesToClassMembers(array $references) : void { foreach ($references as $key => $reference) { if (isset(self::$method_references_to_class_members[$key])) { self::$method_references_to_class_members[$key] = array_merge($reference, self::$method_references_to_class_members[$key]); } else { self::$method_references_to_class_members[$key] = $reference; } } } /** * @param array> $references */ public function addMethodDependencies(array $references) : void { foreach ($references as $key => $reference) { if (isset(self::$method_dependencies[$key])) { self::$method_dependencies[$key] = array_merge($reference, self::$method_dependencies[$key]); } else { self::$method_dependencies[$key] = $reference; } } } /** * @param array> $references */ public function addMethodReferencesToClassProperties(array $references) : void { foreach ($references as $key => $reference) { if (isset(self::$method_references_to_class_properties[$key])) { self::$method_references_to_class_properties[$key] = array_merge($reference, self::$method_references_to_class_properties[$key]); } else { self::$method_references_to_class_properties[$key] = $reference; } } } /** * @param array> $references */ public function addMethodReferencesToMethodReturns(array $references) : void { foreach ($references as $key => $reference) { if (isset(self::$method_references_to_method_returns[$key])) { self::$method_references_to_method_returns[$key] = array_merge($reference, self::$method_references_to_method_returns[$key]); } else { self::$method_references_to_method_returns[$key] = $reference; } } } /** * @param array> $references */ public function addMethodReferencesToClasses(array $references) : void { foreach ($references as $key => $reference) { if (isset(self::$method_references_to_classes[$key])) { self::$method_references_to_classes[$key] = array_merge($reference, self::$method_references_to_classes[$key]); } else { self::$method_references_to_classes[$key] = $reference; } } } /** * @param array> $references */ public function addMethodReferencesToMissingClassMembers(array $references) : void { foreach ($references as $key => $reference) { if (isset(self::$method_references_to_missing_class_members[$key])) { self::$method_references_to_missing_class_members[$key] = array_merge($reference, self::$method_references_to_missing_class_members[$key]); } else { self::$method_references_to_missing_class_members[$key] = $reference; } } } /** * @param array>> $references */ public function addMethodParamUses(array $references) : void { foreach ($references as $method_id => $method_param_uses) { if (isset(self::$method_param_uses[$method_id])) { foreach ($method_param_uses as $offset => $reference_map) { if (isset(self::$method_param_uses[$method_id][$offset])) { self::$method_param_uses[$method_id][$offset] = array_merge(self::$method_param_uses[$method_id][$offset], $reference_map); } else { self::$method_param_uses[$method_id][$offset] = $reference_map; } } } else { self::$method_param_uses[$method_id] = $method_param_uses; } } } /** * @param array> $references */ public function setCallingMethodReferencesToClasses(array $references) : void { self::$method_references_to_classes = $references; } /** * @param array> $references */ public function setCallingMethodReferencesToClassMembers(array $references) : void { self::$method_references_to_class_members = $references; } /** * @param array> $references */ public function setMethodDependencies(array $references) : void { self::$method_dependencies = $references; } /** * @param array> $references */ public function setCallingMethodReferencesToClassProperties(array $references) : void { self::$method_references_to_class_properties = $references; } /** * @param array> $references */ public function setCallingMethodReferencesToMethodReturns(array $references) : void { self::$method_references_to_method_returns = $references; } /** * @param array> $references */ public function setCallingMethodReferencesToMissingClassMembers(array $references) : void { self::$method_references_to_missing_class_members = $references; } /** * @param array> $references */ public function setFileReferencesToClassMembers(array $references) : void { self::$file_references_to_class_members = $references; } /** * @param array> $references */ public function setFileReferencesToClassProperties(array $references) : void { self::$file_references_to_class_properties = $references; } /** * @param array> $references */ public function setFileReferencesToMethodReturns(array $references) : void { self::$file_references_to_method_returns = $references; } /** * @param array> $references */ public function setFileReferencesToMissingClassMembers(array $references) : void { self::$file_references_to_missing_class_members = $references; } /** * @param array> $references */ public function setReferencesToMixedMemberNames(array $references) : void { self::$references_to_mixed_member_names = $references; } /** * @param array>> $references */ public function setMethodParamUses(array $references) : void { self::$method_param_uses = $references; } /** * @param array> $references */ public function addClassMethodLocations(array $references) : void { foreach ($references as $referenced_member_id => $locations) { if (isset(self::$class_method_locations[$referenced_member_id])) { self::$class_method_locations[$referenced_member_id] = [...self::$class_method_locations[$referenced_member_id], ...$locations]; } else { self::$class_method_locations[$referenced_member_id] = $locations; } } } /** * @param array> $references */ public function addClassPropertyLocations(array $references) : void { foreach ($references as $referenced_member_id => $locations) { if (isset(self::$class_property_locations[$referenced_member_id])) { self::$class_property_locations[$referenced_member_id] = [...self::$class_property_locations[$referenced_member_id], ...$locations]; } else { self::$class_property_locations[$referenced_member_id] = $locations; } } } /** * @param array> $references */ public function addClassLocations(array $references) : void { foreach ($references as $referenced_member_id => $locations) { if (isset(self::$class_locations[$referenced_member_id])) { self::$class_locations[$referenced_member_id] = [...self::$class_locations[$referenced_member_id], ...$locations]; } else { self::$class_locations[$referenced_member_id] = $locations; } } } /** * @return array> */ public function getExistingIssues() : array { return self::$issues; } public function clearExistingIssuesForFile(string $file_path) : void { unset(self::$issues[$file_path]); } public function clearExistingFileMapsForFile(string $file_path) : void { unset(self::$file_maps[$file_path]); } public function addIssue(string $file_path, IssueData $issue) : void { // don’t save parse errors ever, as they're not responsive to AST diffing if ($issue->type === 'ParseError') { return; } if (!isset(self::$issues[$file_path])) { self::$issues[$file_path] = [$issue]; } else { self::$issues[$file_path][] = $issue; } } /** * @param array> $analyzed_methods */ public function setAnalyzedMethods(array $analyzed_methods) : void { self::$analyzed_methods = $analyzed_methods; } /** * @param array $file_maps */ public function setFileMaps(array $file_maps) : void { self::$file_maps = $file_maps; } /** * @return array */ public function getTypeCoverage() : array { return self::$mixed_counts; } /** * @param array $mixed_counts */ public function setTypeCoverage(array $mixed_counts) : void { self::$mixed_counts = array_merge(self::$mixed_counts, $mixed_counts); } /** * @return array> */ public function getAnalyzedMethods() : array { return self::$analyzed_methods; } /** * @return array */ public function getFileMaps() : array { return self::$file_maps; } public static function clearCache() : void { self::$files_inheriting_classes = []; self::$deleted_files = null; self::$file_references = []; self::$file_references_to_class_members = []; self::$file_references_to_class_properties = []; self::$file_references_to_method_returns = []; self::$method_references_to_class_members = []; self::$method_dependencies = []; self::$method_references_to_class_properties = []; self::$method_references_to_method_returns = []; self::$method_references_to_classes = []; self::$nonmethod_references_to_classes = []; self::$file_references_to_missing_class_members = []; self::$method_references_to_missing_class_members = []; self::$references_to_mixed_member_names = []; self::$class_method_locations = []; self::$class_property_locations = []; self::$class_locations = []; self::$analyzed_methods = []; self::$issues = []; self::$file_maps = []; self::$method_param_uses = []; self::$classlike_files = []; self::$mixed_counts = []; } } > * > */ private static array $handlers = []; public function __construct() { self::$handlers = []; $this->registerClass(ArrayFilterParamsProvider::class); $this->registerClass(ArrayMultisortParamsProvider::class); } /** * @param class-string $class */ public function registerClass(string $class) : void { $callable = Closure::fromCallable([$class, 'getFunctionParams']); foreach ($class::getFunctionIds() as $function_id) { $this->registerClosure($function_id, $callable); } } /** * @param Closure(FunctionParamsProviderEvent): ?array $c */ public function registerClosure(string $fq_classlike_name, Closure $c) : void { self::$handlers[strtolower($fq_classlike_name)][] = $c; } public function has(string $fq_classlike_name) : bool { return isset(self::$handlers[strtolower($fq_classlike_name)]); } /** * @param list $call_args * @return ?array */ public function getFunctionParams(StatementsSource $statements_source, string $function_id, array $call_args, ?Context $context = null, ?CodeLocation $code_location = null) : ?array { foreach (self::$handlers[strtolower($function_id)] ?? [] as $class_handler) { $event = new FunctionParamsProviderEvent($statements_source, $function_id, $call_args, $context, $code_location); $result = $class_handler($event); if ($result) { return $result; } } return null; } } */ public static function getFunctionIds() : array { return ['array_filter']; } /** * @return ?list */ public static function getFunctionParams(FunctionParamsProviderEvent $event) : ?array { $call_args = $event->getCallArgs(); if (!isset($call_args[0]) || !isset($call_args[1])) { return null; } $statements_source = $event->getStatementsSource(); if (!$statements_source instanceof StatementsAnalyzer) { // this is practically impossible // but the type in the caller is parent type StatementsSource // even though all callers provide StatementsAnalyzer return null; } $code_location = $event->getCodeLocation(); if ($call_args[1]->value instanceof ConstFetch && strtolower($call_args[1]->value->name->toString()) === 'null' && isset($call_args[2])) { if ($code_location) { // using e.g. ARRAY_FILTER_USE_KEY as 3rd arg won't have any effect if the 2nd arg is null // as it will still filter on the values IssueBuffer::maybeAdd(new InvalidArgument('The 3rd argument of array_filter is not used, when the 2nd argument is null', $code_location, 'array_filter'), $statements_source->getSuppressedIssues()); } return null; } // currently only supports literal types and variables (but not function calls) // due to https://github.com/vimeo/psalm/issues/8905 $first_arg_type = SimpleTypeInferer::infer($statements_source->getCodebase(), $statements_source->node_data, $call_args[0]->value, $statements_source->getAliases(), $statements_source); if (!$first_arg_type) { $extended_var_id = ExpressionIdentifier::getExtendedVarId($call_args[0]->value, null, $statements_source); $first_arg_type = $event->getContext()->vars_in_scope[$extended_var_id] ?? null; } $fallback = new TArray([Type::getArrayKey(), Type::getMixed()]); if (!$first_arg_type || $first_arg_type->isMixed()) { $first_arg_array = $fallback; } else { $first_arg_array = $first_arg_type->hasType('array') && ($array_atomic_type = $first_arg_type->getArray()) && ($array_atomic_type instanceof TArray || $array_atomic_type instanceof TKeyedArray) ? $array_atomic_type : $fallback; } if ($first_arg_array instanceof TArray) { $inner_type = $first_arg_array->type_params[1]; $key_type = $first_arg_array->type_params[0]; } else { $inner_type = $first_arg_array->getGenericValueType(); $key_type = $first_arg_array->getGenericKeyType(); } $has_both = \false; if (isset($call_args[2])) { $mode_type = SimpleTypeInferer::infer($statements_source->getCodebase(), $statements_source->node_data, $call_args[2]->value, $statements_source->getAliases(), $statements_source); if (!$mode_type && $call_args[2]->value instanceof ConstFetch) { $mode_type = ConstFetchAnalyzer::getConstType($statements_source, $call_args[2]->value->name->toString(), \true, $event->getContext()); } elseif (!$mode_type) { $extended_var_id = ExpressionIdentifier::getExtendedVarId($call_args[2]->value, null, $statements_source); $mode_type = $event->getContext()->vars_in_scope[$extended_var_id] ?? null; } if (!$mode_type || !$mode_type->allIntLiterals()) { // if we have multiple possible types, keep the default args return null; } if ($mode_type->isSingleIntLiteral()) { $mode = $mode_type->getSingleIntLiteral()->value; } else { $mode = 0; foreach ($mode_type->getLiteralInts() as $atomic) { if ($atomic->value === ARRAY_FILTER_USE_BOTH) { // we have one which uses both keys and values and one that uses only keys/values $has_both = \true; continue; } if ($atomic->value === ARRAY_FILTER_USE_KEY) { // if one of them is ARRAY_FILTER_USE_KEY, all the other types will behave like mode 0 $inner_type = Type::combineUnionTypes($inner_type, $key_type, $statements_source->getCodebase()); continue; } // to report an error later on if ($mode === 0 && $atomic->value !== 0) { $mode = $atomic->value; } } } if ($mode > ARRAY_FILTER_USE_KEY || $mode < 0) { if ($code_location) { IssueBuffer::maybeAdd(new PossiblyInvalidArgument('The provided 3rd argument of array_filter contains a value of ' . $mode . ', which will behave like 0 and filter on values only', $code_location, 'array_filter'), $statements_source->getSuppressedIssues()); } $mode = 0; } } else { $mode = 0; } $callback_arg_value = new FunctionLikeParameter('value', \false, $inner_type, null, null, null, \false); $callback_arg_key = new FunctionLikeParameter('key', \false, $key_type, null, null, null, \false); if ($mode === ARRAY_FILTER_USE_BOTH) { $callback_arg = [$callback_arg_value, $callback_arg_key]; } elseif ($mode === ARRAY_FILTER_USE_KEY) { $callback_arg = [$callback_arg_key]; } elseif ($has_both) { // if we have both + other flags, the 2nd arg is optional $callback_arg_key->is_optional = \true; $callback_arg = [$callback_arg_value, $callback_arg_key]; } else { $callback_arg = [$callback_arg_value]; } $callable = new TCallable('callable', $callback_arg, Type::getMixed()); return [new FunctionLikeParameter('array', \false, Type::getArray(), Type::getArray(), null, null, \false), new FunctionLikeParameter('callback', \false, new Union([$callable])), new FunctionLikeParameter('mode', \false, Type::getInt(), Type::getInt())]; } } */ public static function getFunctionIds() : array { return ['array_multisort']; } /** * @return ?list */ public static function getFunctionParams(FunctionParamsProviderEvent $event) : ?array { $call_args = $event->getCallArgs(); if (!isset($call_args[0])) { return null; } $statements_source = $event->getStatementsSource(); if (!$statements_source instanceof StatementsAnalyzer) { // this is practically impossible // but the type in the caller is parent type StatementsSource // even though all callers provide StatementsAnalyzer return null; } $code_location = $event->getCodeLocation(); $params = []; $previous_param = \false; $last_array_index = 0; $last_by_ref_index = -1; $first_non_ref_index_after_by_ref = -1; foreach ($call_args as $key => $call_arg) { $param_type = SimpleTypeInferer::infer($statements_source->getCodebase(), $statements_source->node_data, $call_arg->value, $statements_source->getAliases(), $statements_source); if (!$param_type && $call_arg->value instanceof ConstFetch) { $param_type = ConstFetchAnalyzer::getConstType($statements_source, $call_arg->value->name->toString(), \true, $event->getContext()); } // @todo currently assumes any function calls are for array types not for sort order/flags // actually need to check the return type // which isn't possible atm due to https://github.com/vimeo/psalm/issues/8905 if (!$param_type && ($call_arg->value instanceof FuncCall || $call_arg->value instanceof MethodCall)) { if ($first_non_ref_index_after_by_ref < $last_by_ref_index) { $first_non_ref_index_after_by_ref = $key; } $last_array_index = $key; $previous_param = 'array'; $params[] = new FunctionLikeParameter( 'array' . ($last_array_index + 1), // function calls will not be used by reference \false, Type::getArray(), $key === 0 ? Type::getArray() : null ); continue; } $extended_var_id = null; if (!$param_type) { $extended_var_id = ExpressionIdentifier::getExtendedVarId($call_arg->value, null, $statements_source); $param_type = $event->getContext()->vars_in_scope[$extended_var_id] ?? null; } if (!$param_type) { return null; } if ($key === 0 && !$param_type->isArray()) { return null; } if ($param_type->isArray() && $extended_var_id) { $last_by_ref_index = $key; $last_array_index = $key; $previous_param = 'array'; $params[] = new FunctionLikeParameter('array' . ($last_array_index + 1), \true, $param_type, $key === 0 ? Type::getArray() : null); continue; } if ($param_type->allIntLiterals()) { $sort_order = [SORT_ASC, SORT_DESC]; $sort_flags = [SORT_REGULAR, SORT_NUMERIC, SORT_STRING, SORT_LOCALE_STRING, SORT_NATURAL, SORT_STRING | SORT_FLAG_CASE, SORT_NATURAL | SORT_FLAG_CASE]; $sort_param = \false; foreach ($param_type->getLiteralInts() as $atomic) { if (in_array($atomic->value, $sort_order, \true)) { if ($sort_param === 'sort_order_flags') { continue; } if ($sort_param === 'sort_order') { continue; } if ($sort_param === 'sort_flags') { $sort_param = 'sort_order_flags'; continue; } $sort_param = 'sort_order'; continue; } if (in_array($atomic->value, $sort_flags, \true)) { if ($sort_param === 'sort_order_flags') { continue; } if ($sort_param === 'sort_flags') { continue; } if ($sort_param === 'sort_order') { $sort_param = 'sort_order_flags'; continue; } $sort_param = 'sort_flags'; continue; } if ($code_location) { IssueBuffer::maybeAdd(new InvalidArgument('Argument ' . ($key + 1) . ' of array_multisort sort order/flag contains an invalid value of ' . $atomic->value, $code_location, 'array_multisort'), $statements_source->getSuppressedIssues()); } } if ($sort_param === \false) { return null; } if (($sort_param === 'sort_order' || $sort_param === 'sort_order_flags') && $previous_param !== 'array') { if ($code_location) { IssueBuffer::maybeAdd(new InvalidArgument('Argument ' . ($key + 1) . ' of array_multisort contains sort order flags' . ' and can only be used after an array parameter', $code_location, 'array_multisort'), $statements_source->getSuppressedIssues()); } return null; } if ($sort_param === 'sort_flags' && $previous_param !== 'array' && $previous_param !== 'sort_order') { if ($code_location) { IssueBuffer::maybeAdd(new InvalidArgument('Argument ' . ($key + 1) . ' of array_multisort are sort flags' . ' and cannot be used after a parameter with sort flags', $code_location, 'array_multisort'), $statements_source->getSuppressedIssues()); } return null; } if ($sort_param === 'sort_order_flags') { $previous_param = 'sort_order'; } else { $previous_param = $sort_param; } $params[] = new FunctionLikeParameter('array' . ($last_array_index + 1) . '_' . $previous_param, \false, Type::getInt()); continue; } if (!$param_type->isArray()) { // too complex for now return null; } if ($first_non_ref_index_after_by_ref < $last_by_ref_index) { $first_non_ref_index_after_by_ref = $key; } $last_array_index = $key; $previous_param = 'array'; $params[] = new FunctionLikeParameter('array' . ($last_array_index + 1), \false, Type::getArray()); } if ($code_location) { if ($last_by_ref_index === -1) { IssueBuffer::maybeAdd(new InvalidArgument('At least 1 array argument of array_multisort must be a variable,' . ' since the sorting happens by reference and otherwise this function call does nothing', $code_location, 'array_multisort'), $statements_source->getSuppressedIssues()); } elseif ($first_non_ref_index_after_by_ref > $last_by_ref_index) { IssueBuffer::maybeAdd(new InvalidArgument('All arguments of array_multisort after argument ' . $first_non_ref_index_after_by_ref . ', which are after the last by reference passed array argument and its flags,' . ' are redundant and can be removed, since the sorting happens by reference', $code_location, 'array_multisort'), $statements_source->getSuppressedIssues()); } } return $params; } } getPropertyName()) === 'documentelement') { self::$cache ??= new Union([new TNamedObject('DOMElement'), new TNull()], ['ignore_nullable_issues' => \true]); return self::$cache; } return null; } public static function getClassLikeNames() : array { return ['domdocument']; } } > */ private static array $handlers = []; /** @var array */ private static array $dynamic_storages = []; /** * @param class-string $class */ public function registerClass(string $class) : void { $callable = Closure::fromCallable([$class, 'getFunctionStorage']); foreach ($class::getFunctionIds() as $function_id) { $this->registerClosure($function_id, $callable); } } /** * @param Closure(DynamicFunctionStorageProviderEvent): ?DynamicFunctionStorage $c */ public function registerClosure(string $fq_function_name, Closure $c) : void { self::$handlers[strtolower($fq_function_name)][] = $c; } public function has(string $fq_function_name) : bool { return isset(self::$handlers[strtolower($fq_function_name)]); } public function getFunctionStorage(PhpParser\Node\Expr\FuncCall $stmt, StatementsAnalyzer $statements_analyzer, string $function_id, Context $context, CodeLocation $code_location) : ?FunctionStorage { if ($stmt->isFirstClassCallable()) { return null; } $dynamic_storage_id = strtolower($statements_analyzer->getFilePath()) . ':' . $stmt->getLine() . ':' . (int) $stmt->getAttribute('startFilePos') . ':dynamic-storage' . ':-:' . strtolower($function_id); if (isset(self::$dynamic_storages[$dynamic_storage_id])) { return self::$dynamic_storages[$dynamic_storage_id]; } foreach (self::$handlers[strtolower($function_id)] ?? [] as $class_handler) { $event = new DynamicFunctionStorageProviderEvent(new ArgTypeInferer($context, $statements_analyzer), new DynamicTemplateProvider('fn-' . strtolower($function_id)), $statements_analyzer, $function_id, $stmt, $context, $code_location); $result = $class_handler($event); return self::$dynamic_storages[$dynamic_storage_id] = $result ? $result->toFunctionStorage($function_id) : null; } return null; } } */ private SplObjectStorage $node_types; /** * @var SplObjectStorage>>>|null> */ private SplObjectStorage $node_assertions; /** @var SplObjectStorage> */ private SplObjectStorage $node_if_true_assertions; /** @var SplObjectStorage> */ private SplObjectStorage $node_if_false_assertions; public bool $cache_assertions = \true; public function __construct() { $this->node_types = new SplObjectStorage(); $this->node_assertions = new SplObjectStorage(); $this->node_if_true_assertions = new SplObjectStorage(); $this->node_if_false_assertions = new SplObjectStorage(); } /** * @param Expr|Name|Return_ $node */ public function setType(NodeAbstract $node, Union $type) : void { $this->node_types[$node] = $type; } /** * @param Expr|Name|Return_ $node */ public function getType(NodeAbstract $node) : ?Union { return $this->node_types[$node] ?? null; } /** * @param list>>>|null $assertions */ public function setAssertions(Expr $node, ?array $assertions) : void { if (!$this->cache_assertions) { return; } $this->node_assertions[$node] = $assertions; } /** * @return list>>>|null */ public function getAssertions(Expr $node) : ?array { if (!$this->cache_assertions) { return null; } return $this->node_assertions[$node] ?? null; } /** * @param FuncCall|MethodCall|StaticCall|New_ $node * @param array $assertions */ public function setIfTrueAssertions(Expr $node, array $assertions) : void { $this->node_if_true_assertions[$node] = $assertions; } /** * @param Expr\FuncCall|MethodCall|StaticCall|New_ $node * @return array|null */ public function getIfTrueAssertions(Expr $node) : ?array { return $this->node_if_true_assertions[$node] ?? null; } /** * @param FuncCall|MethodCall|StaticCall|New_ $node * @param array $assertions */ public function setIfFalseAssertions(Expr $node, array $assertions) : void { $this->node_if_false_assertions[$node] = $assertions; } /** * @param FuncCall|MethodCall|StaticCall|New_ $node * @return array|null */ public function getIfFalseAssertions(Expr $node) : ?array { return $this->node_if_false_assertions[$node] ?? null; } public function isPureCompatible(Expr $node) : bool { $node_type = $this->getType($node); return $node_type && $node_type->reference_free || $node->getAttribute('pure', \false); } public function clearNodeOfTypeAndAssertions(Expr $node) : void { unset($this->node_types[$node], $this->node_assertions[$node]); } } */ protected array $temp_files = []; /** * @var array */ protected static array $open_files = []; /** * @var array */ protected array $open_files_paths = []; public function getContents(string $file_path, bool $go_to_source = \false) : string { if (!$go_to_source && isset($this->temp_files[$file_path])) { return $this->temp_files[$file_path]['content']; } if (isset(self::$open_files[$file_path])) { return self::$open_files[$file_path]; } if (!file_exists($file_path)) { throw new UnexpectedValueException('File ' . $file_path . ' should exist to get contents'); } if (is_dir($file_path)) { throw new UnexpectedValueException('File ' . $file_path . ' is a directory'); } $file_contents = (string) file_get_contents($file_path); self::$open_files[$file_path] = $file_contents; return $file_contents; } public function setContents(string $file_path, string $file_contents) : void { if (isset(self::$open_files[$file_path])) { self::$open_files[$file_path] = $file_contents; } if (isset($this->temp_files[$file_path])) { $this->temp_files[$file_path] = ['version' => null, 'content' => $file_contents]; } file_put_contents($file_path, $file_contents); } public function setOpenContents(string $file_path, ?string $file_contents = null) : void { if (isset(self::$open_files[$file_path])) { self::$open_files[$file_path] = $file_contents ?? $this->getContents($file_path, \true); } } public function getModifiedTime(string $file_path) : int { if (!file_exists($file_path)) { throw new UnexpectedValueException('File should exist to get modified time'); } return (int) filemtime($file_path); } public function addTemporaryFileChanges(string $file_path, string $new_content, ?int $version = null) : void { if (isset($this->temp_files[$file_path]) && $version !== null && $this->temp_files[$file_path]['version'] !== null && $version < $this->temp_files[$file_path]['version']) { return; } $this->temp_files[$file_path] = ['version' => $version, 'content' => $new_content]; } public function removeTemporaryFileChanges(string $file_path) : void { unset($this->temp_files[$file_path]); } public function getOpenFilesPath() : array { return $this->open_files_paths; } public function openFile(string $file_path) : void { self::$open_files[$file_path] = $this->getContents($file_path, \true); $this->open_files_paths[$file_path] = $file_path; } public function isOpen(string $file_path) : bool { return isset($this->temp_files[$file_path]) || isset(self::$open_files[$file_path]); } public function closeFile(string $file_path) : void { unset($this->temp_files[$file_path], self::$open_files[$file_path], $this->open_files_paths[$file_path]); } public function fileExists(string $file_path) : bool { return file_exists($file_path); } public function isDirectory(string $file_path) : bool { return is_dir($file_path); } /** * @param array $file_extensions * @param null|callable(string):bool $filter * @return list */ public function getFilesInDir(string $dir_path, array $file_extensions, ?callable $filter = null) : array { $file_paths = []; $iterator = new RecursiveDirectoryIterator($dir_path, FilesystemIterator::CURRENT_AS_PATHNAME | FilesystemIterator::SKIP_DOTS); if ($filter !== null) { $iterator = new RecursiveCallbackFilterIterator( $iterator, /** @param mixed $_ */ static function (string $current, $_, RecursiveIterator $iterator) use($filter) : bool { if ($iterator->hasChildren()) { $path = $current . DIRECTORY_SEPARATOR; } else { $path = $current; } return $filter($path); } ); } /** @var RecursiveDirectoryIterator */ $iterator = new RecursiveIteratorIterator($iterator); $iterator->rewind(); while ($iterator->valid()) { $extension = $iterator->getExtension(); if (in_array($extension, $file_extensions, \true)) { $file_paths[] = (string) $iterator->getRealPath(); } $iterator->next(); } return $file_paths; } } */ public static function addTaints(AddRemoveTaintsEvent $event) : array { $item = $event->getExpr(); $statements_analyzer = $event->getStatementsSource(); if (!$statements_analyzer instanceof StatementsAnalyzer || !$item instanceof PhpParser\Node\Expr\FuncCall || $item->isFirstClassCallable() || !$item->name instanceof PhpParser\Node\Name || count($item->name->getParts()) !== 1 || count($item->getArgs()) === 0) { return []; } $function_id = strtolower($item->name->getFirst()); if ($function_id === 'html_entity_decode' || $function_id === 'htmlspecialchars_decode') { $second_arg = $item->getArgs()[1]->value ?? null; if ($second_arg === null) { if ($statements_analyzer->getCodebase()->analysis_php_version_id >= 80100) { return [TaintKind::INPUT_HTML, TaintKind::INPUT_HAS_QUOTES]; } return [TaintKind::INPUT_HTML]; } $second_arg_value = $statements_analyzer->node_data->getType($second_arg); if (!$second_arg_value || !$second_arg_value->isSingleIntLiteral()) { return [TaintKind::INPUT_HTML]; } $second_arg_value = $second_arg_value->getSingleIntLiteral()->value; if (($second_arg_value & ENT_QUOTES) === ENT_QUOTES) { return [TaintKind::INPUT_HTML, TaintKind::INPUT_HAS_QUOTES]; } return [TaintKind::INPUT_HTML]; } return []; } /** * Called to see what taints should be removed * * @return list */ public static function removeTaints(AddRemoveTaintsEvent $event) : array { $item = $event->getExpr(); $statements_analyzer = $event->getStatementsSource(); if (!$statements_analyzer instanceof StatementsAnalyzer || !$item instanceof PhpParser\Node\Expr\FuncCall || $item->isFirstClassCallable() || !$item->name instanceof PhpParser\Node\Name || count($item->name->getParts()) !== 1 || count($item->getArgs()) === 0) { return []; } $function_id = strtolower($item->name->getFirst()); if ($function_id === 'htmlentities' || $function_id === 'htmlspecialchars') { $second_arg = $item->getArgs()[1]->value ?? null; if ($second_arg === null) { if ($statements_analyzer->getCodebase()->analysis_php_version_id >= 80100) { return [TaintKind::INPUT_HTML, TaintKind::INPUT_HAS_QUOTES]; } return [TaintKind::INPUT_HTML]; } $second_arg_value = $statements_analyzer->node_data->getType($second_arg); if (!$second_arg_value || !$second_arg_value->isSingleIntLiteral()) { return [TaintKind::INPUT_HTML]; } $second_arg_value = $second_arg_value->getSingleIntLiteral()->value; if (($second_arg_value & ENT_QUOTES) === ENT_QUOTES) { return [TaintKind::INPUT_HTML, TaintKind::INPUT_HAS_QUOTES]; } return [TaintKind::INPUT_HTML]; } return []; } } file_provider = $file_provider; $this->parser_cache_provider = $parser_cache_provider; $this->project_cache_provider = $project_cache_provider; $this->file_storage_provider = new \Psalm\Internal\Provider\FileStorageProvider($file_storage_cache_provider); $this->classlike_storage_provider = new \Psalm\Internal\Provider\ClassLikeStorageProvider($classlike_storage_cache_provider); $this->statements_provider = new \Psalm\Internal\Provider\StatementsProvider($file_provider, $parser_cache_provider, $file_storage_cache_provider); $this->file_reference_provider = new \Psalm\Internal\Provider\FileReferenceProvider($file_provider, $file_reference_cache_provider); } public static function safeFileGetContents(string $path) : string { // no readable validation as that must be done in the caller $fp = fopen($path, 'r'); if ($fp === \false) { return ''; } $max_wait_cycles = 5; $has_lock = \false; while ($max_wait_cycles > 0) { if (flock($fp, LOCK_SH)) { $has_lock = \true; break; } $max_wait_cycles--; usleep(50000); } if (!$has_lock) { fclose($fp); throw new RuntimeException('Could not acquire lock for ' . $path); } $file_size = filesize($path); $content = ''; if ($file_size > 0) { $content = (string) fread($fp, $file_size); } fclose($fp); return $content; } } > */ private array $unchanged_members = []; /** * @var array> */ private array $unchanged_signature_members = []; /** * @var array> */ private array $changed_members = []; /** * @var array */ private array $errors = []; /** * @var array> */ private array $diff_map = []; /** * @var array> */ private array $deletion_ranges = []; private static ?Emulative $lexer = null; private static ?Parser $parser = null; public function __construct(\Psalm\Internal\Provider\FileProvider $file_provider, ?\Psalm\Internal\Provider\ParserCacheProvider $parser_cache_provider = null, ?\Psalm\Internal\Provider\FileStorageCacheProvider $file_storage_cache_provider = null) { $this->file_provider = $file_provider; $this->parser_cache_provider = $parser_cache_provider; $this->this_modified_time = filemtime(__FILE__); $this->file_storage_cache_provider = $file_storage_cache_provider; } /** * @return list */ public function getStatementsForFile(string $file_path, int $analysis_php_version_id, ?Progress $progress = null) : array { unset($this->errors[$file_path]); if ($progress === null) { $progress = new VoidProgress(); } $from_cache = \false; $version = \PHP_PARSER_VERSION . $this->this_modified_time; $file_contents = $this->file_provider->getContents($file_path); $modified_time = $this->file_provider->getModifiedTime($file_path); $config = Config::getInstance(); if (PHP_VERSION_ID >= 80100) { $file_content_hash = hash('xxh128', $version . $file_contents); } else { $file_content_hash = hash('md4', $version . $file_contents); } if (!$this->parser_cache_provider || !$config->isInProjectDirs($file_path) && strpos($file_path, 'vendor')) { $progress->debug('Parsing ' . $file_path . "\n"); $has_errors = \false; return self::parseStatements($file_contents, $analysis_php_version_id, $has_errors, $file_path); } $stmts = $this->parser_cache_provider->loadStatementsFromCache($file_path, $modified_time, $file_content_hash); if ($stmts === null) { $progress->debug('Parsing ' . $file_path . "\n"); $existing_statements = $this->parser_cache_provider->loadExistingStatementsFromCache($file_path); $existing_file_contents = $this->parser_cache_provider->loadExistingFileContentsFromCache($file_path); // this happens after editing temporary file if ($existing_file_contents === $file_contents && $existing_statements) { $this->diff_map[$file_path] = []; $this->parser_cache_provider->saveStatementsToCache($file_path, $file_content_hash, $existing_statements, \true); return $existing_statements; } $file_changes = null; $existing_statements_copy = null; if ($existing_statements && $existing_file_contents && abs(strlen($existing_file_contents) - strlen($file_contents)) < 5000) { $file_changes = FileDiffer::getDiff($existing_file_contents, $file_contents); if (count($file_changes) < 10) { $traverser = new PhpParser\NodeTraverser(); $traverser->addVisitor(new CloningVisitor()); // performs a deep clone /** @var list */ $existing_statements_copy = $traverser->traverse($existing_statements); } else { $file_changes = null; } } $has_errors = \false; $stmts = self::parseStatements($file_contents, $analysis_php_version_id, $has_errors, $file_path, $existing_file_contents, $existing_statements_copy, $file_changes); if ($existing_file_contents && $existing_statements && (!$has_errors || $stmts)) { [$unchanged_members, $unchanged_signature_members, $changed_members, $diff_map, $deletion_ranges] = FileStatementsDiffer::diff($existing_statements, $stmts, $existing_file_contents, $file_contents); $unchanged_members = array_fill_keys($unchanged_members, \true); $unchanged_signature_members = array_fill_keys($unchanged_signature_members, \true); // do NOT change this to hash, it will fail on Windows for whatever reason $file_path_hash = md5($file_path); $changed_members = array_map(static function (string $key) use($file_path_hash) : string { if (strpos($key, 'use:') === 0) { return $key . ':' . $file_path_hash; } return $key; }, $changed_members); $changed_members = array_fill_keys($changed_members, \true); if (isset($this->unchanged_members[$file_path])) { $this->unchanged_members[$file_path] = array_intersect_key($this->unchanged_members[$file_path], $unchanged_members); } else { $this->unchanged_members[$file_path] = $unchanged_members; } if (isset($this->unchanged_signature_members[$file_path])) { $this->unchanged_signature_members[$file_path] = array_intersect_key($this->unchanged_signature_members[$file_path], $unchanged_signature_members); } else { $this->unchanged_signature_members[$file_path] = $unchanged_signature_members; } if (isset($this->changed_members[$file_path])) { $this->changed_members[$file_path] = array_merge($this->changed_members[$file_path], $changed_members); } else { $this->changed_members[$file_path] = $changed_members; } $this->diff_map[$file_path] = $diff_map; $this->deletion_ranges[$file_path] = $deletion_ranges; } elseif ($has_errors && !$stmts) { $this->errors[$file_path] = \true; } if ($this->file_storage_cache_provider) { $this->file_storage_cache_provider->removeCacheForFile($file_path); } $this->parser_cache_provider->cacheFileContents($file_path, $file_contents); } else { $from_cache = \true; $this->diff_map[$file_path] = []; $this->deletion_ranges[$file_path] = []; } $this->parser_cache_provider->saveStatementsToCache($file_path, $file_content_hash, $stmts, $from_cache); if (!$stmts) { return []; } return $stmts; } /** * @return array> */ public function getChangedMembers() : array { return $this->changed_members; } /** * @param array> $more_changed_members */ public function addChangedMembers(array $more_changed_members) : void { $this->changed_members = array_merge($more_changed_members, $this->changed_members); } /** * @return array> */ public function getUnchangedSignatureMembers() : array { return $this->unchanged_signature_members; } /** * @param array> $more_unchanged_members */ public function addUnchangedSignatureMembers(array $more_unchanged_members) : void { $this->unchanged_signature_members = array_merge($more_unchanged_members, $this->unchanged_signature_members); } /** * @return array */ public function getErrors() : array { return $this->errors; } /** * @param array $errors */ public function addErrors(array $errors) : void { $this->errors += $errors; } public function setUnchangedFile(string $file_path) : void { if (!isset($this->diff_map[$file_path])) { $this->diff_map[$file_path] = []; } if (!isset($this->deletion_ranges[$file_path])) { $this->deletion_ranges[$file_path] = []; } } /** * @return array> */ public function getDiffMap() : array { return $this->diff_map; } /** * @return array> */ public function getDeletionRanges() : array { return $this->deletion_ranges; } /** * @param array> $diff_map */ public function addDiffMap(array $diff_map) : void { $this->diff_map = array_merge($diff_map, $this->diff_map); } /** * @param array> $deletion_ranges */ public function addDeletionRanges(array $deletion_ranges) : void { $this->deletion_ranges = array_merge($deletion_ranges, $this->deletion_ranges); } public function resetDiffs() : void { $this->changed_members = []; $this->unchanged_members = []; $this->unchanged_signature_members = []; $this->diff_map = []; $this->deletion_ranges = []; } /** * @param list $existing_statements * @param array $file_changes * @return list */ public static function parseStatements(string $file_contents, int $analysis_php_version_id, bool &$has_errors, ?string $file_path = null, ?string $existing_file_contents = null, ?array $existing_statements = null, ?array $file_changes = null) : array { $attributes = ['comments', 'startLine', 'startFilePos', 'endFilePos']; if (!self::$lexer) { $major_version = Codebase::transformPhpVersionId($analysis_php_version_id, 10000); $minor_version = Codebase::transformPhpVersionId($analysis_php_version_id % 10000, 100); self::$lexer = new Emulative(['usedAttributes' => $attributes, 'phpVersion' => $major_version . '.' . $minor_version]); } if (!self::$parser) { self::$parser = (new PhpParser\ParserFactory())->create(PhpParser\ParserFactory::ONLY_PHP7, self::$lexer); } $used_cached_statements = \false; $error_handler = new Collecting(); if ($existing_statements && $file_changes && $existing_file_contents) { $clashing_traverser = new CustomTraverser(); $offset_analyzer = new PartialParserVisitor(self::$parser, $error_handler, $file_changes, $existing_file_contents, $file_contents); $clashing_traverser->addVisitor($offset_analyzer); $clashing_traverser->traverse($existing_statements); if (!$offset_analyzer->mustRescan()) { $used_cached_statements = \true; $stmts = $existing_statements; } else { try { /** @var list */ $stmts = self::$parser->parse($file_contents, $error_handler) ?: []; } catch (Throwable $t) { $stmts = []; // hope this got caught below } } } else { try { /** @var list */ $stmts = self::$parser->parse($file_contents, $error_handler) ?: []; } catch (Throwable $t) { $stmts = []; // hope this got caught below } } if ($error_handler->hasErrors() && $file_path) { $config = Config::getInstance(); $has_errors = \true; foreach ($error_handler->getErrors() as $error) { if ($error->hasColumnInfo()) { IssueBuffer::maybeAdd(new ParseError($error->getMessage(), new ParseErrorLocation($error, $file_contents, $file_path, $config->shortenFileName($file_path)))); } } } $error_handler->clearErrors(); $resolving_traverser = new PhpParser\NodeTraverser(); $name_resolver = new SimpleNameResolver($error_handler, $used_cached_statements ? $file_changes : []); $resolving_traverser->addVisitor($name_resolver); $resolving_traverser->traverse($stmts); return $stmts; } public static function clearLexer() : void { self::$lexer = null; } public static function clearParser() : void { self::$parser = null; } } */ private static array $storage = []; /** * A list of data useful to analyse new files * Storing this statically is much faster (at least in PHP 7.2.1) * * @var array */ private static array $new_storage = []; public ?\Psalm\Internal\Provider\FileStorageCacheProvider $cache = null; public function __construct(?\Psalm\Internal\Provider\FileStorageCacheProvider $cache = null) { $this->cache = $cache; } public function get(string $file_path) : FileStorage { $file_path = strtolower($file_path); if (!isset(self::$storage[$file_path])) { throw new InvalidArgumentException('Could not get file storage for ' . $file_path); } return self::$storage[$file_path]; } public function remove(string $file_path) : void { unset(self::$storage[strtolower($file_path)]); } public function has(string $file_path, ?string $file_contents = null) : bool { $file_path = strtolower($file_path); if (isset(self::$storage[$file_path])) { return \true; } if ($file_contents === null) { return \false; } if (!$this->cache) { return \false; } $cached_value = $this->cache->getLatestFromCache($file_path, $file_contents); if (!$cached_value) { return \false; } self::$storage[$file_path] = $cached_value; self::$new_storage[$file_path] = $cached_value; return \true; } /** * @return array */ public function getAll() : array { return self::$storage; } /** * @return array */ public function getNew() : array { return self::$new_storage; } /** * @param array $more */ public function addMore(array $more) : void { self::$new_storage = array_merge(self::$new_storage, $more); self::$storage = array_merge(self::$storage, $more); } public function create(string $file_path) : FileStorage { $file_path_lc = strtolower($file_path); $storage = new FileStorage($file_path); self::$storage[$file_path_lc] = $storage; self::$new_storage[$file_path_lc] = $storage; return $storage; } public static function deleteAll() : void { self::$storage = []; } public static function populated() : void { self::$new_storage = []; } } * > */ private static array $handlers = []; public function __construct() { self::$handlers = []; $this->registerClass(DomDocumentPropertyTypeProvider::class); } /** * @param class-string $class */ public function registerClass(string $class) : void { if (is_subclass_of($class, PropertyTypeProviderInterface::class, \true)) { $callable = Closure::fromCallable([$class, 'getPropertyType']); foreach ($class::getClassLikeNames() as $fq_classlike_name) { $this->registerClosure($fq_classlike_name, $callable); } } } /** * @param Closure(PropertyTypeProviderEvent): ?Union $c */ public function registerClosure(string $fq_classlike_name, Closure $c) : void { self::$handlers[strtolower($fq_classlike_name)][] = $c; } public function has(string $fq_classlike_name) : bool { return isset(self::$handlers[strtolower($fq_classlike_name)]); } public function getPropertyType(string $fq_classlike_name, string $property_name, bool $read_mode, ?StatementsSource $source = null, ?Context $context = null) : ?Union { if ($source) { $source->addSuppressedIssues(['NonInvariantDocblockPropertyType']); } foreach (self::$handlers[strtolower($fq_classlike_name)] ?? [] as $property_handler) { $event = new PropertyTypeProviderEvent($fq_classlike_name, $property_name, $read_mode, $source, $context); $property_type = $property_handler($event); if ($property_type !== null) { return $property_type; } } return null; } } * > */ private static array $handlers = []; public function __construct() { self::$handlers = []; } /** * @param class-string * |class-string $class */ public function registerClass(string $class) : void { if (is_subclass_of($class, PropertyExistenceProviderInterface::class, \true)) { $callable = Closure::fromCallable([$class, 'doesPropertyExist']); foreach ($class::getClassLikeNames() as $fq_classlike_name) { $this->registerClosure($fq_classlike_name, $callable); } } } /** * @param Closure(PropertyExistenceProviderEvent): ?bool $c */ public function registerClosure(string $fq_classlike_name, Closure $c) : void { self::$handlers[strtolower($fq_classlike_name)][] = $c; } public function has(string $fq_classlike_name) : bool { return isset(self::$handlers[strtolower($fq_classlike_name)]); } public function doesPropertyExist(string $fq_classlike_name, string $property_name, bool $read_mode, ?StatementsSource $source = null, ?Context $context = null, ?CodeLocation $code_location = null) : ?bool { foreach (self::$handlers[strtolower($fq_classlike_name)] ?? [] as $property_handler) { $event = new PropertyExistenceProviderEvent($fq_classlike_name, $property_name, $read_mode, $source, $context, $code_location); $property_exists = $property_handler($event); if ($property_exists !== null) { return $property_exists; } } return null; } } */ private static array $storage = []; /** * @var array */ private static array $new_storage = []; public ?\Psalm\Internal\Provider\ClassLikeStorageCacheProvider $cache = null; public function __construct(?\Psalm\Internal\Provider\ClassLikeStorageCacheProvider $cache = null) { $this->cache = $cache; } /** * @psalm-mutation-free * @throws InvalidArgumentException when class does not exist */ public function get(string $fq_classlike_name) : ClassLikeStorage { $fq_classlike_name_lc = strtolower($fq_classlike_name); /** @psalm-suppress ImpureStaticProperty Used only for caching */ if (!isset(self::$storage[$fq_classlike_name_lc])) { throw new InvalidArgumentException('Could not get class storage for ' . $fq_classlike_name_lc); } /** @psalm-suppress ImpureStaticProperty Used only for caching */ return self::$storage[$fq_classlike_name_lc]; } /** * @psalm-mutation-free */ public function has(string $fq_classlike_name) : bool { $fq_classlike_name_lc = strtolower($fq_classlike_name); /** @psalm-suppress ImpureStaticProperty Used only for caching */ return isset(self::$storage[$fq_classlike_name_lc]); } public function exhume(string $fq_classlike_name, string $file_path, string $file_contents) : ClassLikeStorage { $fq_classlike_name_lc = strtolower($fq_classlike_name); if (isset(self::$storage[$fq_classlike_name_lc])) { return self::$storage[$fq_classlike_name_lc]; } if (!$this->cache) { throw new LogicException('Cannot exhume when there’s no cache'); } $cached_value = $this->cache->getLatestFromCache($fq_classlike_name_lc, $file_path, $file_contents); self::$storage[$fq_classlike_name_lc] = $cached_value; self::$new_storage[$fq_classlike_name_lc] = $cached_value; return $cached_value; } /** * @return array */ public function getAll() : array { return self::$storage; } /** * @return array */ public function getNew() : array { return self::$new_storage; } /** * @param array $more */ public function addMore(array $more) : void { self::$new_storage = array_merge(self::$new_storage, $more); self::$storage = array_merge(self::$storage, $more); } public function makeNew(string $fq_classlike_name_lc) : void { self::$new_storage[$fq_classlike_name_lc] = self::$storage[$fq_classlike_name_lc]; } public function create(string $fq_classlike_name) : ClassLikeStorage { $fq_classlike_name_lc = strtolower($fq_classlike_name); $storage = new ClassLikeStorage($fq_classlike_name); self::$storage[$fq_classlike_name_lc] = $storage; self::$new_storage[$fq_classlike_name_lc] = $storage; return $storage; } public function remove(string $fq_classlike_name) : void { $fq_classlike_name_lc = strtolower($fq_classlike_name); unset(self::$storage[$fq_classlike_name_lc]); } public static function deleteAll() : void { self::$storage = []; self::$new_storage = []; } public static function populated() : void { self::$new_storage = []; } } composer_lock_location = $composer_lock_location; } public function canDiffFiles() : bool { $cache_directory = Config::getInstance()->getCacheDirectory(); return $cache_directory && file_exists($cache_directory . DIRECTORY_SEPARATOR . self::GOOD_RUN_NAME); } public function processSuccessfulRun(float $start_time, string $psalm_version) : void { $cache_directory = Config::getInstance()->getCacheDirectory(); if (!$cache_directory) { return; } $run_cache_location = $cache_directory . DIRECTORY_SEPARATOR . self::GOOD_RUN_NAME; file_put_contents($run_cache_location, $psalm_version); touch($run_cache_location, (int) $start_time); } public function getLastRun(string $psalm_version) : int { if ($this->last_run === null) { $cache_directory = Config::getInstance()->getCacheDirectory(); $run_cache_location = $cache_directory . DIRECTORY_SEPARATOR . self::GOOD_RUN_NAME; if (file_exists($run_cache_location) && \Psalm\Internal\Provider\Providers::safeFileGetContents($run_cache_location) === $psalm_version) { $this->last_run = filemtime($run_cache_location); } else { $this->last_run = 0; } } return $this->last_run; } public function hasLockfileChanged() : bool { if (file_exists($this->composer_lock_location)) { $lockfile_contents = \Psalm\Internal\Provider\Providers::safeFileGetContents($this->composer_lock_location); if (!$lockfile_contents) { return \true; } if (PHP_VERSION_ID >= 80100) { $hash = hash('xxh128', $lockfile_contents); } else { $hash = hash('md4', $lockfile_contents); } } else { $hash = ''; } $changed = $hash !== $this->getComposerLockHash(); $this->composer_lock_hash = $hash; return $changed; } public function updateComposerLockHash() : void { $cache_directory = Config::getInstance()->getCacheDirectory(); if (!$cache_directory || !$this->composer_lock_hash) { return; } if (!file_exists($cache_directory)) { mkdir($cache_directory, 0777, \true); } $lock_hash_location = $cache_directory . DIRECTORY_SEPARATOR . self::COMPOSER_LOCK_HASH; file_put_contents($lock_hash_location, $this->composer_lock_hash); } protected function getComposerLockHash() : string { if ($this->composer_lock_hash === null) { $cache_directory = Config::getInstance()->getCacheDirectory(); $lock_hash_location = $cache_directory . DIRECTORY_SEPARATOR . self::COMPOSER_LOCK_HASH; if (file_exists($lock_hash_location)) { $this->composer_lock_hash = \Psalm\Internal\Provider\Providers::safeFileGetContents($lock_hash_location) ?: ''; } else { $this->composer_lock_hash = ''; } } return $this->composer_lock_hash; } } * > */ private static array $handlers = []; public function __construct() { self::$handlers = []; $this->registerClass(ArrayChunkReturnTypeProvider::class); $this->registerClass(ArrayColumnReturnTypeProvider::class); $this->registerClass(ArrayCombineReturnTypeProvider::class); $this->registerClass(ArrayFilterReturnTypeProvider::class); $this->registerClass(ArrayMapReturnTypeProvider::class); $this->registerClass(ArrayMergeReturnTypeProvider::class); $this->registerClass(ArrayPadReturnTypeProvider::class); $this->registerClass(ArrayPointerAdjustmentReturnTypeProvider::class); $this->registerClass(ArrayPopReturnTypeProvider::class); $this->registerClass(ArrayRandReturnTypeProvider::class); $this->registerClass(ArrayReduceReturnTypeProvider::class); $this->registerClass(ArraySliceReturnTypeProvider::class); $this->registerClass(ArraySpliceReturnTypeProvider::class); $this->registerClass(ArrayReverseReturnTypeProvider::class); $this->registerClass(ArrayFillReturnTypeProvider::class); $this->registerClass(ArrayFillKeysReturnTypeProvider::class); $this->registerClass(FilterInputReturnTypeProvider::class); $this->registerClass(FilterVarReturnTypeProvider::class); $this->registerClass(IteratorToArrayReturnTypeProvider::class); $this->registerClass(ParseUrlReturnTypeProvider::class); $this->registerClass(StrReplaceReturnTypeProvider::class); $this->registerClass(StrTrReturnTypeProvider::class); $this->registerClass(VersionCompareReturnTypeProvider::class); $this->registerClass(MktimeReturnTypeProvider::class); $this->registerClass(BasenameReturnTypeProvider::class); $this->registerClass(DirnameReturnTypeProvider::class); $this->registerClass(GetObjectVarsReturnTypeProvider::class); $this->registerClass(GetClassMethodsReturnTypeProvider::class); $this->registerClass(FirstArgStringReturnTypeProvider::class); $this->registerClass(HexdecReturnTypeProvider::class); $this->registerClass(MinMaxReturnTypeProvider::class); $this->registerClass(TriggerErrorReturnTypeProvider::class); $this->registerClass(RandReturnTypeProvider::class); $this->registerClass(InArrayReturnTypeProvider::class); $this->registerClass(RoundReturnTypeProvider::class); $this->registerClass(MbInternalEncodingReturnTypeProvider::class); $this->registerClass(DateReturnTypeProvider::class); $this->registerClass(PowReturnTypeProvider::class); $this->registerClass(SprintfReturnTypeProvider::class); } /** * @param class-string $class */ public function registerClass(string $class) : void { if (is_subclass_of($class, FunctionReturnTypeProviderInterface::class, \true)) { $callable = Closure::fromCallable([$class, 'getFunctionReturnType']); foreach ($class::getFunctionIds() as $function_id) { $this->registerClosure($function_id, $callable); } } } /** * @param lowercase-string $function_id * @param Closure(FunctionReturnTypeProviderEvent): ?Union $c */ public function registerClosure(string $function_id, Closure $c) : void { self::$handlers[$function_id][] = $c; } public function has(string $function_id) : bool { return isset(self::$handlers[strtolower($function_id)]); } /** * @param non-empty-string $function_id */ public function getReturnType(StatementsSource $statements_source, string $function_id, PhpParser\Node\Expr\FuncCall $stmt, Context $context, CodeLocation $code_location) : ?Union { foreach (self::$handlers[strtolower($function_id)] ?? [] as $function_handler) { $event = new FunctionReturnTypeProviderEvent($statements_source, $function_id, $stmt, $context, $code_location); $return_type = $function_handler($event); if ($return_type) { return $return_type; } } return null; } } */ public static function getFunctionIds() : array { return ['trigger_error']; } public static function getFunctionReturnType(FunctionReturnTypeProviderEvent $event) : ?Union { $codebase = $event->getStatementsSource()->getCodebase(); $config = $codebase->config; if ($config->trigger_error_exits === 'always') { return Type::getNever(); } if ($config->trigger_error_exits === 'never') { return new Union([new TTrue()]); } //default behaviour $call_args = $event->getCallArgs(); $statements_source = $event->getStatementsSource(); if (isset($call_args[1]) && ($array_arg_type = $statements_source->getNodeTypeProvider()->getType($call_args[1]->value))) { $return_types = []; foreach ($array_arg_type->getAtomicTypes() as $atomicType) { if ($atomicType instanceof TLiteralInt) { if (in_array($atomicType->value, [E_USER_WARNING, E_USER_DEPRECATED, E_USER_NOTICE], \true)) { $return_types[] = new TTrue(); } elseif ($atomicType->value === E_USER_ERROR) { $return_types[] = new TNever(); } else { // not recognized int literal. return false before PHP8, fatal error since $return_types[] = new TFalse(); } } else { $return_types[] = new TBool(); } } return TypeCombiner::combine($return_types, $codebase); } //default value is E_USER_NOTICE, so return true return new Union([new TTrue()]); } } getSource(); $call_args = $event->getCallArgs(); $method_name_lowercase = $event->getMethodNameLowercase(); if ($method_name_lowercase !== 'appendchild') { return null; } if (!$source instanceof StatementsAnalyzer || !$call_args) { return Type::getMixed(); } if (($first_arg_type = $source->node_data->getType($call_args[0]->value)) && $first_arg_type->hasObjectType()) { return $first_arg_type; } return null; } } */ public static function getFunctionIds() : array { return ['basename']; } public static function getFunctionReturnType(FunctionReturnTypeProviderEvent $event) : ?Union { $call_args = $event->getCallArgs(); if (count($call_args) === 0) { return null; } $statements_source = $event->getStatementsSource(); $evaled_path = IncludeAnalyzer::getPathTo($call_args[0]->value, null, null, $statements_source->getFileName(), $statements_source->getCodebase()->config); if ($evaled_path === null) { $union = $statements_source->getNodeTypeProvider()->getType($call_args[0]->value); $generic = \false; $non_empty = \false; if ($union !== null) { foreach ($union->getAtomicTypes() as $atomic) { if ($atomic instanceof Type\Atomic\TNonFalsyString) { continue; } if ($atomic instanceof Type\Atomic\TLiteralString) { if ($atomic->value === '') { $generic = \true; break; } if ($atomic->value === '0') { $non_empty = \true; continue; } continue; } if ($atomic instanceof Type\Atomic\TNonEmptyString) { $non_empty = \true; continue; } $generic = \true; break; } } if ($union === null || $generic) { return Type::getString(); } if ($non_empty) { return Type::getNonEmptyString(); } return Type::getNonFalsyString(); } $basename = basename($evaled_path); return Type::getString($basename); } } */ public static function getFunctionIds() : array { return ['mktime']; } public static function getFunctionReturnType(FunctionReturnTypeProviderEvent $event) : Union { $statements_source = $event->getStatementsSource(); $call_args = $event->getCallArgs(); if (!$statements_source instanceof StatementsAnalyzer) { return Type::getMixed(); } foreach ($call_args as $call_arg) { if (!($call_arg_type = $statements_source->node_data->getType($call_arg->value)) || !$call_arg_type->isInt()) { $codebase = $statements_source->getCodebase(); return new Union([new TInt(), new TFalse()], ['ignore_falsable_issues' => $codebase->config->ignore_internal_falsable_issues]); } } return Type::getInt(); } } */ public static function getFunctionIds() : array { return ['array_rand']; } public static function getFunctionReturnType(FunctionReturnTypeProviderEvent $event) : Union { $statements_source = $event->getStatementsSource(); $call_args = $event->getCallArgs(); if (!$statements_source instanceof StatementsAnalyzer) { return Type::getMixed(); } $first_arg = $call_args[0]->value ?? null; $second_arg = $call_args[1]->value ?? null; $first_arg_array = $first_arg && ($first_arg_type = $statements_source->node_data->getType($first_arg)) && $first_arg_type->hasType('array') && ($array_atomic_type = $first_arg_type->getArray()) && ($array_atomic_type instanceof TArray || $array_atomic_type instanceof TKeyedArray) ? $array_atomic_type : null; if (!$first_arg_array) { return Type::getMixed(); } if ($first_arg_array instanceof TArray) { $key_type = $first_arg_array->type_params[0]; } else { $key_type = $first_arg_array->getGenericKeyType(); } if (!$second_arg) { return $key_type; } $second_arg_type = $statements_source->node_data->getType($second_arg); if ($second_arg_type && $second_arg_type->isSingleIntLiteral() && $second_arg_type->getSingleIntLiteral()->value === 1) { return $key_type; } $arr_type = Type::getList($key_type); if ($second_arg_type && $second_arg_type->isSingleIntLiteral()) { return $arr_type; } return Type::combineUnionTypes($key_type, $arr_type); } } */ public static function getFunctionIds() : array { return ['array_column']; } public static function getFunctionReturnType(FunctionReturnTypeProviderEvent $event) : Union { $statements_source = $event->getStatementsSource(); $call_args = $event->getCallArgs(); if (!$statements_source instanceof StatementsAnalyzer || count($call_args) < 2) { return Type::getMixed(); } $context = $event->getContext(); $code_location = $event->getCodeLocation(); $value_column_name = null; $value_column_name_is_null = \false; // calculate value column name if ($second_arg_type = $statements_source->node_data->getType($call_args[1]->value)) { if ($second_arg_type->isSingleIntLiteral()) { $value_column_name = $second_arg_type->getSingleIntLiteral()->value; } elseif ($second_arg_type->isSingleStringLiteral()) { $value_column_name = $second_arg_type->getSingleStringLiteral()->value; } $value_column_name_is_null = $second_arg_type->isNull(); } $key_column_name = null; $key_column_name_is_null = \false; $third_arg_type = null; // calculate key column name if (isset($call_args[2])) { $third_arg_type = $statements_source->node_data->getType($call_args[2]->value); if ($third_arg_type) { if ($third_arg_type->isSingleIntLiteral()) { $key_column_name = $third_arg_type->getSingleIntLiteral()->value; } elseif ($third_arg_type->isSingleStringLiteral()) { $key_column_name = $third_arg_type->getSingleStringLiteral()->value; } $key_column_name_is_null = $third_arg_type->isNull(); } } $row_type = $row_shape = null; $input_array_not_empty = \false; // calculate row shape if (($first_arg_type = $statements_source->node_data->getType($call_args[0]->value)) && $first_arg_type->isSingle() && $first_arg_type->hasArray()) { $input_array = $first_arg_type->getArray(); if ($input_array instanceof TKeyedArray && !$input_array->fallback_params && ($value_column_name !== null || $value_column_name_is_null) && !($third_arg_type && !$key_column_name)) { $properties = []; $ok = \true; $last_custom_key = -1; $is_list = \true; $had_possibly_undefined = \false; // This incorrectly assumes that the array is sorted, may be problematic // Will be fixed when order is enforced $key = -1; foreach ($input_array->properties as $property) { $row_shape = self::getRowShape($property, $statements_source, $context, $code_location); if (!$row_shape) { continue; } if (!$row_shape instanceof TKeyedArray) { if ($row_shape instanceof TArray && $row_shape->isEmptyArray()) { continue; } $ok = \false; break; } if ($value_column_name !== null) { if (isset($row_shape->properties[$value_column_name])) { $result_element_type = $row_shape->properties[$value_column_name]; } elseif ($row_shape->fallback_params) { $ok = \false; break; } else { continue; } } else { $result_element_type = $property; } if ($key_column_name !== null) { if (isset($row_shape->properties[$key_column_name])) { $result_key_type = $row_shape->properties[$key_column_name]; if ($result_key_type->isSingleIntLiteral()) { $key = $result_key_type->getSingleIntLiteral()->value; if ($is_list && $last_custom_key != $key - 1) { $is_list = \false; } $last_custom_key = $key; } elseif ($result_key_type->isSingleStringLiteral()) { $key = $result_key_type->getSingleStringLiteral()->value; $is_list = \false; } else { $ok = \false; break; } } else { $ok = \false; break; } } else { /** @psalm-suppress StringIncrement Actually always an int in this branch */ ++$key; } $properties[$key] = $result_element_type->setPossiblyUndefined($property->possibly_undefined); if (!$property->possibly_undefined && $had_possibly_undefined) { $is_list = \false; } $had_possibly_undefined = $had_possibly_undefined || $property->possibly_undefined; } if ($ok) { if (!$properties) { return Type::getEmptyArray(); } return new Union([new TKeyedArray($properties, null, $input_array->fallback_params, $is_list)]); } } if ($input_array instanceof TKeyedArray) { $row_type = $input_array->getGenericValueType(); } elseif ($input_array instanceof TArray) { $row_type = $input_array->type_params[1]; } $row_shape = self::getRowShape($row_type, $statements_source, $context, $code_location); $input_array_not_empty = $input_array instanceof TNonEmptyArray || $input_array instanceof TKeyedArray && $input_array->isNonEmpty(); } $result_key_type = Type::getArrayKey(); $result_element_type = null !== $row_type && $value_column_name_is_null ? $row_type : null; $have_at_least_one_res = \false; // calculate results if ($row_shape instanceof TKeyedArray) { if (null !== $value_column_name && isset($row_shape->properties[$value_column_name])) { $result_element_type = $row_shape->properties[$value_column_name]; // When the selected key is possibly_undefined, the resulting array can be empty if ($input_array_not_empty && $result_element_type->possibly_undefined !== \true) { $have_at_least_one_res = \true; } //array_column skips undefined elements so resulting type is necessarily defined $result_element_type = $result_element_type->setPossiblyUndefined(\false); } elseif (!$value_column_name_is_null) { $result_element_type = Type::getMixed(); } if (null !== $key_column_name && isset($row_shape->properties[$key_column_name])) { $result_key_type = $row_shape->properties[$key_column_name]; } } if ($third_arg_type && !$key_column_name_is_null) { $type = $have_at_least_one_res ? new TNonEmptyArray([$result_key_type, $result_element_type ?? Type::getMixed()]) : new TArray([$result_key_type, $result_element_type ?? Type::getMixed()]); } else { $type = $have_at_least_one_res ? Type::getNonEmptyListAtomic($result_element_type ?? Type::getMixed()) : Type::getListAtomic($result_element_type ?? Type::getMixed()); } return new Union([$type]); } /** * @return TArray|TKeyedArray|TClassStringMap|null */ private static function getRowShape(?Union $row_type, SourceAnalyzer $statements_source, Context $context, CodeLocation $code_location) : ?Atomic { if ($row_type && $row_type->isSingle()) { if ($row_type->hasArray()) { return $row_type->getArray(); } elseif ($row_type->hasObjectType()) { return \Psalm\Internal\Provider\ReturnTypeProvider\GetObjectVarsReturnTypeProvider::getGetObjectVarsReturnType($row_type, $statements_source, $context, $code_location); } } return null; } } */ public static function getFunctionIds() : array { return ['version_compare']; } public static function getFunctionReturnType(FunctionReturnTypeProviderEvent $event) : Union { $statements_source = $event->getStatementsSource(); $call_args = $event->getCallArgs(); if (!$statements_source instanceof StatementsAnalyzer) { return Type::getMixed(); } if (count($call_args) > 2) { $operator_type = $statements_source->node_data->getType($call_args[2]->value); if ($operator_type) { if (!$operator_type->hasMixed()) { $acceptable_operator_type = new Union([Type::getAtomicStringFromLiteral('<'), Type::getAtomicStringFromLiteral('lt'), Type::getAtomicStringFromLiteral('<='), Type::getAtomicStringFromLiteral('le'), Type::getAtomicStringFromLiteral('>'), Type::getAtomicStringFromLiteral('gt'), Type::getAtomicStringFromLiteral('>='), Type::getAtomicStringFromLiteral('ge'), Type::getAtomicStringFromLiteral('=='), Type::getAtomicStringFromLiteral('='), Type::getAtomicStringFromLiteral('eq'), Type::getAtomicStringFromLiteral('!='), Type::getAtomicStringFromLiteral('<>'), Type::getAtomicStringFromLiteral('ne')]); $codebase = $statements_source->getCodebase(); if (UnionTypeComparator::isContainedBy($codebase, $operator_type, $acceptable_operator_type)) { return Type::getBool(); } } } return new Union([new TBool(), new TNull()]); } return new Union([new TLiteralInt(-1), new TLiteralInt(0), new TLiteralInt(1)]); } } */ public static function getFunctionIds() : array { return ['filter_var']; } public static function getFunctionReturnType(FunctionReturnTypeProviderEvent $event) : ?Union { $statements_analyzer = $event->getStatementsSource(); if (!$statements_analyzer instanceof StatementsAnalyzer) { throw new UnexpectedValueException(); } $arg_names = array_flip(['value', 'filter', 'options']); $call_args = []; foreach ($event->getCallArgs() as $idx => $arg) { if (isset($arg->name)) { $call_args[$arg_names[$arg->name->name]] = $arg; } else { $call_args[$idx] = $arg; } } $function_id = $event->getFunctionId(); $code_location = $event->getCodeLocation(); $codebase = $statements_analyzer->getCodebase(); if (!isset($call_args[0])) { return \Psalm\Internal\Provider\ReturnTypeProvider\FilterUtils::missingFirstArg($codebase); } $filter_int_used = FILTER_DEFAULT; if (isset($call_args[1])) { $filter_int_used = \Psalm\Internal\Provider\ReturnTypeProvider\FilterUtils::getFilterArgValueOrError($call_args[1], $statements_analyzer, $codebase); if (!is_int($filter_int_used)) { return $filter_int_used; } } $options = null; $flags_int_used = FILTER_FLAG_NONE; if (isset($call_args[2])) { $helper = \Psalm\Internal\Provider\ReturnTypeProvider\FilterUtils::getOptionsArgValueOrError($call_args[2], $statements_analyzer, $codebase, $code_location, $function_id, $filter_int_used); if (!is_array($helper)) { return $helper; } $flags_int_used = $helper['flags_int_used']; $options = $helper['options']; } // if we reach this point with callback, the callback is missing if ($filter_int_used === FILTER_CALLBACK) { return \Psalm\Internal\Provider\ReturnTypeProvider\FilterUtils::missingFilterCallbackCallable($function_id, $code_location, $statements_analyzer, $codebase); } [$default, $min_range, $max_range, $has_range, $regexp] = \Psalm\Internal\Provider\ReturnTypeProvider\FilterUtils::getOptions($filter_int_used, $flags_int_used, $options, $statements_analyzer, $code_location, $codebase, $function_id); if (!$default) { [$fails_type] = \Psalm\Internal\Provider\ReturnTypeProvider\FilterUtils::getFailsNotSetType($flags_int_used); } else { $fails_type = $default; } if ($filter_int_used === FILTER_VALIDATE_REGEXP && $regexp === null) { if ($codebase->analysis_php_version_id >= 80000) { // throws return Type::getNever(); } // any "array" flags are ignored by this filter! return $fails_type; } $input_type = $statements_analyzer->node_data->getType($call_args[0]->value); // only return now, as we still want to report errors above if (!$input_type) { return null; } $redundant_error_return_type = \Psalm\Internal\Provider\ReturnTypeProvider\FilterUtils::checkRedundantFlags($filter_int_used, $flags_int_used, $fails_type, $statements_analyzer, $code_location, $codebase); if ($redundant_error_return_type !== null) { return $redundant_error_return_type; } return \Psalm\Internal\Provider\ReturnTypeProvider\FilterUtils::getReturnType($filter_int_used, $flags_int_used, $input_type, $fails_type, null, $statements_analyzer, $code_location, $codebase, $function_id, $has_range, $min_range, $max_range, $regexp); } } */ public static function getFunctionIds() : array { return ['array_merge', 'array_replace']; } public static function getFunctionReturnType(FunctionReturnTypeProviderEvent $event) : Union { $statements_source = $event->getStatementsSource(); $call_args = $event->getCallArgs(); if (!$statements_source instanceof StatementsAnalyzer || !$call_args) { return Type::getMixed(); } $is_replace = $event->getFunctionId() === 'array_replace'; $inner_value_types = []; $inner_key_types = []; $codebase = $statements_source->getCodebase(); $generic_properties = []; $class_strings = []; $all_keyed_arrays = \true; $all_int_offsets = \true; $all_nonempty_lists = \true; $any_nonempty = \false; $all_empty = \true; $max_keyed_array_size = 0; foreach ($call_args as $call_arg) { if (!($call_arg_type = $statements_source->node_data->getType($call_arg->value))) { return Type::getArray(); } foreach ($call_arg_type->getAtomicTypes() as $type_part) { if ($type_part instanceof TList) { $type_part = $type_part->getKeyedArray(); } $unpacking_indefinite_number_of_args = \false; $unpacking_possibly_empty = \false; if ($call_arg->unpack) { if ($type_part instanceof TKeyedArray) { if (!$type_part->fallback_params && $type_part->getMinCount() === $type_part->getMaxCount()) { $unpacked_type_parts = []; foreach ($type_part->properties as $t) { $unpacked_type_parts = array_merge($unpacked_type_parts, $t->getAtomicTypes()); } } else { $unpacked_type_parts = $type_part->getGenericValueType()->getAtomicTypes(); $unpacking_indefinite_number_of_args = \true; } $unpacking_possibly_empty = !$type_part->isNonEmpty(); } elseif ($type_part instanceof TArray) { $unpacked_type_parts = $type_part->type_params[1]; $unpacking_indefinite_number_of_args = \true; $unpacking_possibly_empty = !$type_part instanceof TNonEmptyArray; $unpacked_type_parts = $unpacked_type_parts->getAtomicTypes(); } else { return Type::getArray(); } } else { $unpacked_type_parts = [$type_part]; } foreach ($unpacked_type_parts as $unpacked_type_part) { if ($unpacked_type_part instanceof TFalse && $call_arg_type->ignore_falsable_issues || $unpacked_type_part instanceof TNull && $call_arg_type->ignore_nullable_issues) { continue; } if ($unpacked_type_part instanceof TKeyedArray) { $all_empty = \false; $max_keyed_array_size = max($max_keyed_array_size, count($unpacked_type_part->properties)); $added_inner_values = \false; foreach ($unpacked_type_part->properties as $key => $type) { if (!$type->possibly_undefined && !$unpacking_possibly_empty) { $any_nonempty = \true; } if (is_string($key)) { $all_int_offsets = \false; } elseif (!$is_replace) { if ($unpacking_indefinite_number_of_args || $type->possibly_undefined) { $added_inner_values = \true; $inner_value_types = array_merge($inner_value_types, array_values($type->getAtomicTypes())); } else { $generic_properties[] = $type; } continue; } if (isset($unpacked_type_part->class_strings[$key])) { $class_strings[$key] = \true; } if (!isset($generic_properties[$key]) || !$type->possibly_undefined && !$unpacking_possibly_empty) { if ($unpacking_possibly_empty) { $type = $type->setPossiblyUndefined(\true); } $generic_properties[$key] = $type; } else { $was_possibly_undefined = $generic_properties[$key]->possibly_undefined || $unpacking_possibly_empty; $generic_properties[$key] = Type::combineUnionTypes($generic_properties[$key], $type, $codebase, \false, \true, 500, $was_possibly_undefined); } } if (!$unpacked_type_part->is_list) { $all_nonempty_lists = \false; } if ($added_inner_values) { $all_keyed_arrays = \false; $inner_key_types[] = new TInt(); } if ($unpacked_type_part->fallback_params !== null) { $all_keyed_arrays = \false; $inner_value_types = array_merge($inner_value_types, array_values($unpacked_type_part->fallback_params[1]->getAtomicTypes())); $inner_key_types = array_merge($inner_key_types, array_values($unpacked_type_part->fallback_params[0]->getAtomicTypes())); } continue; } if ($unpacked_type_part instanceof TMixed && $unpacked_type_part->from_loop_isset) { $unpacked_type_part = new TArray([Type::getArrayKey(), Type::getMixed(\true)]); } if ($unpacked_type_part instanceof TArray) { if ($unpacked_type_part->isEmptyArray()) { continue; } foreach ($generic_properties as $key => $keyed_type) { $generic_properties[$key] = Type::combineUnionTypes($keyed_type, $unpacked_type_part->type_params[1], $codebase); } $all_keyed_arrays = \false; $all_nonempty_lists = \false; if (!$unpacked_type_part->type_params[0]->isInt()) { $all_int_offsets = \false; } if ($unpacked_type_part instanceof TNonEmptyArray && !$unpacking_possibly_empty) { $any_nonempty = \true; } } else { return Type::getArray(); } $all_empty = \false; $inner_key_types = array_merge($inner_key_types, array_values($unpacked_type_part->type_params[0]->getAtomicTypes())); $inner_value_types = array_merge($inner_value_types, array_values($unpacked_type_part->type_params[1]->getAtomicTypes())); } } } $inner_key_type = null; $inner_value_type = null; if ($inner_key_types) { $inner_key_type = TypeCombiner::combine($inner_key_types, $codebase, \true); } if ($inner_value_types) { $inner_value_type = TypeCombiner::combine($inner_value_types, $codebase, \true); } $generic_property_count = count($generic_properties); if ($generic_properties && $generic_property_count < 64 && ($generic_property_count < $max_keyed_array_size * 2 || $generic_property_count < 16)) { $objectlike = new TKeyedArray($generic_properties, $class_strings ?: null, $all_keyed_arrays || $inner_key_type === null || $inner_value_type === null ? null : [$inner_key_type, $inner_value_type], $all_nonempty_lists || $all_int_offsets); return new Union([$objectlike]); } if ($all_empty) { return Type::getEmptyArray(); } if ($inner_value_type) { if ($all_int_offsets) { if ($any_nonempty) { return Type::getNonEmptyList($inner_value_type); } return Type::getList($inner_value_type); } $inner_key_type ??= Type::getArrayKey(); if ($any_nonempty) { return new Union([new TNonEmptyArray([$inner_key_type, $inner_value_type])]); } return new Union([new TArray([$inner_key_type, $inner_value_type])]); } return Type::getArray(); } } */ public static function getFunctionIds() : array { return ['array_pop', 'array_shift']; } public static function getFunctionReturnType(FunctionReturnTypeProviderEvent $event) : Union { $statements_source = $event->getStatementsSource(); $call_args = $event->getCallArgs(); $function_id = $event->getFunctionId(); if (!$statements_source instanceof StatementsAnalyzer) { return Type::getMixed(); } $first_arg = $call_args[0]->value ?? null; $first_arg_array = $first_arg && ($first_arg_type = $statements_source->node_data->getType($first_arg)) && $first_arg_type->hasType('array') && !$first_arg_type->hasMixed() && ($array_atomic_type = $first_arg_type->getArray()) && ($array_atomic_type instanceof TArray || $array_atomic_type instanceof TKeyedArray) ? $array_atomic_type : null; if (!$first_arg_array) { return Type::getMixed(); } $nullable = \false; if ($first_arg_array instanceof TArray) { $value_type = $first_arg_array->type_params[1]; if ($first_arg_array->isEmptyArray()) { return Type::getNull(); } if (!$first_arg_array instanceof TNonEmptyArray) { $nullable = \true; } } else { // special case where we know the type of the first element if ($function_id === 'array_shift' && $first_arg_array->is_list && isset($first_arg_array->properties[0])) { $value_type = $first_arg_array->properties[0]; if ($value_type->possibly_undefined) { $value_type = $value_type->setPossiblyUndefined(\false); $nullable = \true; } } else { $value_type = $first_arg_array->getGenericValueType(); if (!$first_arg_array->isNonEmpty()) { $nullable = \true; } } } if ($nullable) { $value_type = $value_type->getBuilder()->addType(new TNull()); $codebase = $statements_source->getCodebase(); if ($codebase->config->ignore_internal_nullable_issues) { $value_type->ignore_nullable_issues = \true; } $value_type = $value_type->freeze(); } return $value_type; } } */ public static function getFunctionIds() : array { return ['in_array']; } public static function getFunctionReturnType(FunctionReturnTypeProviderEvent $event) : Union { $call_args = $event->getCallArgs(); $bool = Type::getBool(); if (!isset($call_args[0]) || !isset($call_args[1])) { return $bool; } $needle_type = $event->getStatementsSource()->getNodeTypeProvider()->getType($call_args[0]->value); $haystack_type = $event->getStatementsSource()->getNodeTypeProvider()->getType($call_args[1]->value); if ($needle_type === null || $haystack_type === null) { return $bool; } $false = Type::getFalse(); /** @psalm-suppress InaccessibleProperty We just created these types */ $false->from_docblock = $bool->from_docblock = $needle_type->from_docblock || $haystack_type->from_docblock; if (!isset($call_args[2])) { return $bool; } $strict_type = $event->getStatementsSource()->getNodeTypeProvider()->getType($call_args[2]->value); if ($strict_type === null || !$strict_type->isTrue()) { return $bool; } /** * @var TKeyedArray|TArray|null */ $array_arg_type = ($types = $haystack_type->getAtomicTypes()) && isset($types['array']) ? $types['array'] : null; if ($array_arg_type instanceof TKeyedArray) { $array_arg_type = $array_arg_type->getGenericArrayType(); } if (!$array_arg_type instanceof TArray) { return $bool; } $haystack_item_type = $array_arg_type->type_params[1]; if (UnionTypeComparator::canExpressionTypesBeIdentical($event->getStatementsSource()->getCodebase(), $needle_type, $haystack_item_type)) { return $bool; } return $false; } } */ public static function getFunctionIds() : array { return ['array_slice']; } public static function getFunctionReturnType(FunctionReturnTypeProviderEvent $event) : Union { $statements_source = $event->getStatementsSource(); $call_args = $event->getCallArgs(); if (!$statements_source instanceof StatementsAnalyzer) { return Type::getMixed(); } $first_arg = $call_args[0]->value ?? null; if (!$first_arg) { return Type::getArray(); } $first_arg_type = $statements_source->node_data->getType($first_arg); if (!$first_arg_type) { return Type::getArray(); } $atomic_types = $first_arg_type->getAtomicTypes(); $return_atomic_type = null; while ($atomic_type = array_shift($atomic_types)) { if ($atomic_type instanceof TTemplateParam) { $atomic_types = array_merge($atomic_types, $atomic_type->as->getAtomicTypes()); continue; } if ($atomic_type instanceof TList) { $atomic_type = $atomic_type->getKeyedArray(); } if ($atomic_type instanceof TKeyedArray) { $atomic_type = $atomic_type->getGenericArrayType(); } if ($atomic_type instanceof TArray) { $return_atomic_type = new TArray($atomic_type->type_params); continue; } return Type::getArray(); } if (!$return_atomic_type) { throw new UnexpectedValueException('This should never happen'); } $dont_preserve_int_keys = !isset($call_args[3]->value) || ($third_arg_type = $statements_source->node_data->getType($call_args[3]->value)) && (string) $third_arg_type === 'false'; if ($dont_preserve_int_keys && $return_atomic_type->type_params[0]->isInt()) { $return_atomic_type = Type::getListAtomic($return_atomic_type->type_params[1]); } return new Union([$return_atomic_type]); } } */ public static function getFunctionIds() : array { return ['array_splice']; } public static function getFunctionReturnType(FunctionReturnTypeProviderEvent $event) : Union { $statements_source = $event->getStatementsSource(); $call_args = $event->getCallArgs(); if (!$statements_source instanceof StatementsAnalyzer) { return Type::getMixed(); } $first_arg = $call_args[0]->value ?? null; $array_type = $first_arg && ($first_arg_type = $statements_source->node_data->getType($first_arg)) && $first_arg_type->hasType('array') && ($array_atomic_type = $first_arg_type->getArray()) && ($array_atomic_type instanceof TArray || $array_atomic_type instanceof TKeyedArray) ? $array_atomic_type : null; if (!$array_type) { return Type::getArray(); } if ($array_type instanceof TKeyedArray) { $array_type = $array_type->getGenericArrayType(); } if (!$array_type->type_params[0]->hasString()) { if ($array_type->type_params[1]->isString()) { $array_type = Type::getListAtomic(Type::getString()); } elseif ($array_type->type_params[1]->isInt()) { $array_type = Type::getListAtomic(Type::getInt()); } else { $array_type = Type::getListAtomic(Type::getMixed()); } } return new Union([$array_type]); } } */ public static function getFunctionIds() : array { return ['pow']; } public static function getFunctionReturnType(FunctionReturnTypeProviderEvent $event) : ?Union { $call_args = $event->getCallArgs(); if (count($call_args) !== 2) { return null; } $first_arg = $event->getStatementsSource()->getNodeTypeProvider()->getType($call_args[0]->value); $second_arg = $event->getStatementsSource()->getNodeTypeProvider()->getType($call_args[1]->value); $first_arg_literal = null; $first_arg_is_int = \false; $first_arg_is_float = \false; if ($first_arg !== null && $first_arg->isSingle()) { $first_atomic_type = $first_arg->getSingleAtomic(); if ($first_atomic_type instanceof TInt) { $first_arg_is_int = \true; } elseif ($first_atomic_type instanceof TFloat) { $first_arg_is_float = \true; } if ($first_atomic_type instanceof TLiteralInt || $first_atomic_type instanceof TLiteralFloat) { $first_arg_literal = $first_atomic_type->value; } } $second_arg_literal = null; $second_arg_is_int = \false; $second_arg_is_float = \false; if ($second_arg !== null && $second_arg->isSingle()) { $second_atomic_type = $second_arg->getSingleAtomic(); if ($second_atomic_type instanceof TInt) { $second_arg_is_int = \true; } elseif ($second_atomic_type instanceof TFloat) { $second_arg_is_float = \true; } if ($second_atomic_type instanceof TLiteralInt || $second_atomic_type instanceof TLiteralFloat) { $second_arg_literal = $second_atomic_type->value; } } if ($first_arg_literal === 0) { return Type::getInt(\true, 0); } if ($second_arg_literal === 0) { return Type::getInt(\true, 1); } if ($first_arg_literal !== null && $second_arg_literal !== null) { return Type::getFloat($first_arg_literal ** $second_arg_literal); } if ($first_arg_is_int && $second_arg_is_int) { return Type::getInt(); } if ($first_arg_is_float || $second_arg_is_float) { return Type::getFloat(); } return new Union([new TInt(), new TFloat()]); } } */ public static function getFunctionIds() : array { return ['array_fill_keys']; } public static function getFunctionReturnType(FunctionReturnTypeProviderEvent $event) : ?Union { $statements_source = $event->getStatementsSource(); $call_args = $event->getCallArgs(); if (!$statements_source instanceof StatementsAnalyzer) { return Type::getMixed(); } if (count($call_args) !== 2) { return Type::getNever(); } $first_arg_type = isset($call_args[0]) ? $statements_source->node_data->getType($call_args[0]->value) : null; $second_arg_type = isset($call_args[1]) ? $statements_source->node_data->getType($call_args[1]->value) : null; if ($first_arg_type && $first_arg_type->isArray() && $second_arg_type) { $array = $first_arg_type->getArray(); if ($array instanceof TArray && $array->isEmptyArray()) { return $first_arg_type; } elseif ($array instanceof TKeyedArray && !$array->fallback_params) { $is_list = $array->is_list; $array = $array->properties; } else { return null; } $result = []; $prev_key = -1; $had_possibly_undefined = \false; foreach ($array as $key_k) { if ($had_possibly_undefined && !$key_k->possibly_undefined) { $is_list = \false; } $had_possibly_undefined = $had_possibly_undefined || $key_k->possibly_undefined; if ($key_k->isSingleIntLiteral()) { $key = $key_k->getSingleIntLiteral()->value; if ($prev_key !== $key - 1) { $is_list = \false; } $prev_key = $key; } elseif ($key_k->isSingleStringLiteral()) { $key = $key_k->getSingleStringLiteral()->value; $is_list = \false; } else { return null; } $result[$key] = $second_arg_type->setPossiblyUndefined($key_k->possibly_undefined); } return new Union([new TKeyedArray($result, null, null, $is_list)]); } return null; } } getSource(); $method_name_lowercase = $event->getMethodNameLowercase(); $call_args = $event->getCallArgs(); if (!$source instanceof StatementsAnalyzer) { return null; } $type_provider = $source->getNodeTypeProvider(); $codebase = $source->getCodebase(); if ($method_name_lowercase === 'fromcallable') { $closure_types = []; if (isset($call_args[0]) && ($input_type = $type_provider->getType($call_args[0]->value))) { foreach ($input_type->getAtomicTypes() as $atomic_type) { $candidate_callable = CallableTypeComparator::getCallableFromAtomic($codebase, $atomic_type, null, $source, \true); if ($candidate_callable) { $closure_types[] = new TClosure('Closure', $candidate_callable->params, $candidate_callable->return_type, $candidate_callable->is_pure); } else { return Type::getClosure(); } } } if ($closure_types) { return TypeCombiner::combine($closure_types, $codebase); } return Type::getClosure(); } return null; } } */ public static function getFunctionIds() : array { return ['min', 'max']; } public static function getFunctionReturnType(FunctionReturnTypeProviderEvent $event) : ?Union { $call_args = $event->getCallArgs(); if (count($call_args) === 0) { return null; } $statements_source = $event->getStatementsSource(); $nodeTypeProvider = $statements_source->getNodeTypeProvider(); if (count($call_args) === 1 && ($array_arg_type = $nodeTypeProvider->getType($call_args[0]->value)) && $array_arg_type->isSingle() && $array_arg_type->hasArray() && ($array_type = ArrayType::infer($array_arg_type->getSingleAtomic()))) { return $array_type->value; } $all_int = \true; $min_bounds = []; $max_bounds = []; foreach ($call_args as $arg) { if ($arg_type = $nodeTypeProvider->getType($arg->value)) { if ($arg->unpack) { if (!$arg_type->isSingle() || !$arg_type->isArray()) { return Type::getMixed(); } else { $array_arg_type = $arg_type->getArray(); if ($array_arg_type instanceof TKeyedArray) { $possibly_unpacked_arg_types = $array_arg_type->properties; } else { assert($array_arg_type instanceof TArray); $possibly_unpacked_arg_types = [$array_arg_type->type_params[1]]; } } } else { $possibly_unpacked_arg_types = [$arg_type]; } foreach ($possibly_unpacked_arg_types as $possibly_unpacked_arg_type) { foreach ($possibly_unpacked_arg_type->getAtomicTypes() as $atomic_type) { if (!$atomic_type instanceof TInt) { $all_int = \false; break 2; } if ($atomic_type instanceof TLiteralInt) { $min_bounds[] = $atomic_type->value; $max_bounds[] = $atomic_type->value; } elseif ($atomic_type instanceof TIntRange) { $min_bounds[] = $atomic_type->min_bound; $max_bounds[] = $atomic_type->max_bound; } elseif (get_class($atomic_type) === TInt::class) { $min_bounds[] = null; $max_bounds[] = null; } else { throw new UnexpectedValueException('Unexpected type'); } } } } else { return Type::getMixed(); } } if ($all_int) { if ($event->getFunctionId() === 'min') { assert(count($min_bounds) !== 0); //null values in $max_bounds doesn't make sense for min() so we remove them $max_bounds = array_filter($max_bounds, static fn($v): bool => $v !== null) ?: [null]; $min_potential_int = in_array(null, $min_bounds, \true) ? null : min($min_bounds); $max_potential_int = in_array(null, $max_bounds, \true) ? null : min($max_bounds); } else { assert(count($max_bounds) !== 0); //null values in $min_bounds doesn't make sense for max() so we remove them $min_bounds = array_filter($min_bounds, static fn($v): bool => $v !== null) ?: [null]; $min_potential_int = in_array(null, $min_bounds, \true) ? null : max($min_bounds); $max_potential_int = in_array(null, $max_bounds, \true) ? null : max($max_bounds); } if ($min_potential_int === null && $max_potential_int === null) { return Type::getInt(); } if ($min_potential_int === $max_potential_int) { return Type::getInt(\false, $min_potential_int); } return Type::getIntRange($min_potential_int, $max_potential_int); } //if we're dealing with non-int elements, just combine them all together $return_type = null; foreach ($call_args as $arg) { if ($arg_type = $nodeTypeProvider->getType($arg->value)) { if ($arg->unpack) { if ($arg_type->isSingle() && $arg_type->isArray()) { $array_type = ArrayType::infer($arg_type->getSingleAtomic()); assert($array_type !== null); $additional_type = $array_type->value; } else { $additional_type = Type::getMixed(); } } else { $additional_type = $arg_type; } $return_type = Type::combineUnionTypes($return_type, $additional_type); } else { return Type::getMixed(); } } return $return_type; } } */ public static function getFunctionIds() : array { return ['rand', 'mt_rand', 'random_int']; } public static function getFunctionReturnType(FunctionReturnTypeProviderEvent $event) : ?Union { $call_args = $event->getCallArgs(); if (count($call_args) === 0) { return Type::getInt(); } if (count($call_args) !== 2) { return null; } $statements_source = $event->getStatementsSource(); $nodeTypeProvider = $statements_source->getNodeTypeProvider(); $first_arg = $nodeTypeProvider->getType($call_args[0]->value); $second_arg = $nodeTypeProvider->getType($call_args[1]->value); $min_value = null; if ($first_arg !== null && $first_arg->isSingle()) { $first_atomic_type = $first_arg->getSingleAtomic(); if ($first_atomic_type instanceof TLiteralInt) { $min_value = $first_atomic_type->value; } elseif ($first_atomic_type instanceof TIntRange) { $min_value = $first_atomic_type->min_bound; } } $max_value = null; if ($second_arg !== null && $second_arg->isSingle()) { $second_atomic_type = $second_arg->getSingleAtomic(); if ($second_atomic_type instanceof TLiteralInt) { $max_value = $second_atomic_type->value; } elseif ($second_atomic_type instanceof TIntRange) { $max_value = $second_atomic_type->max_bound; } } return Type::getIntRange($min_value, $max_value); } } getMethodNameLowercase(); if (!$config->php_extensions["pdo"]) { return null; } if ($method_name_lowercase === 'fetch') { return self::handleFetch($event); } if ($method_name_lowercase === 'fetchall') { return self::handleFetchAll($event); } return null; } private static function handleFetch(MethodReturnTypeProviderEvent $event) : ?Union { $source = $event->getSource(); $call_args = $event->getCallArgs(); $fetch_mode = 0; foreach ($call_args as $call_arg) { $arg_name = $call_arg->name; if (!isset($arg_name) || $arg_name->name === "mode") { $arg_type = $source->getNodeTypeProvider()->getType($call_arg->value); if (isset($arg_type) && $arg_type->isSingleIntLiteral()) { $fetch_mode = $arg_type->getSingleIntLiteral()->value; } break; } } switch ($fetch_mode) { case 2: // PDO::FETCH_ASSOC - array|false return new Union([new TArray([Type::getString(), new Union([new TScalar(), new TNull()])]), new TFalse()]); case 4: // PDO::FETCH_BOTH - array|false return new Union([new TArray([Type::getArrayKey(), new Union([new TScalar(), new TNull()])]), new TFalse()]); case 6: // PDO::FETCH_BOUND - bool return Type::getBool(); case 7: // PDO::FETCH_COLUMN - scalar|null|false return new Union([new TScalar(), new TNull(), new TFalse()]); case 8: // PDO::FETCH_CLASS - object|false return new Union([new TObject(), new TFalse()]); case 1: // PDO::FETCH_LAZY - object|false // This actually returns a PDORow object, but that class is // undocumented, and its attributes are all dynamic anyway return new Union([new TObject(), new TFalse()]); case 11: // PDO::FETCH_NAMED - array>|false return new Union([new TArray([Type::getString(), new Union([new TScalar(), new TNull(), Type::getListAtomic(new Union([new TScalar(), new TNull()]))])]), new TFalse()]); case 12: // PDO::FETCH_KEY_PAIR - array return new Union([new TArray([Type::getArrayKey(), new Union([new TScalar(), new TNull()])])]); case 3: // PDO::FETCH_NUM - list|false return new Union([Type::getListAtomic(new Union([new TScalar(), new TNull()])), new TFalse()]); case 5: // PDO::FETCH_OBJ - stdClass|false return new Union([new TNamedObject('stdClass'), new TFalse()]); } return null; } private static function handleFetchAll(MethodReturnTypeProviderEvent $event) : ?Union { $source = $event->getSource(); $call_args = $event->getCallArgs(); $fetch_mode = 0; if (isset($call_args[0]) && ($first_arg_type = $source->getNodeTypeProvider()->getType($call_args[0]->value)) && $first_arg_type->isSingleIntLiteral()) { $fetch_mode = $first_arg_type->getSingleIntLiteral()->value; } $fetch_class_name = null; if (isset($call_args[1]) && ($second_arg_type = $source->getNodeTypeProvider()->getType($call_args[1]->value)) && $second_arg_type->isSingleStringLiteral()) { $fetch_class_name = $second_arg_type->getSingleStringLiteral()->value; } switch ($fetch_mode) { case 2: // PDO::FETCH_ASSOC - list> return new Union([Type::getListAtomic(new Union([new TArray([Type::getString(), new Union([new TScalar(), new TNull()])])]))]); case 4: // PDO::FETCH_BOTH - list> return new Union([Type::getListAtomic(new Union([new TArray([Type::getArrayKey(), new Union([new TScalar(), new TNull()])])]))]); case 6: // PDO::FETCH_BOUND - list return new Union([Type::getListAtomic(Type::getBool())]); case 7: // PDO::FETCH_COLUMN - list return new Union([Type::getListAtomic(new Union([new TScalar(), new TNull()]))]); case 8: // PDO::FETCH_CLASS - list return new Union([Type::getListAtomic(new Union([$fetch_class_name ? new TNamedObject($fetch_class_name) : new TObject()]))]); case 11: // PDO::FETCH_NAMED - list>> return new Union([Type::getListAtomic(new Union([new TArray([Type::getString(), new Union([new TScalar(), new TNull(), Type::getListAtomic(new Union([new TScalar(), new TNull()]))])])]))]); case 12: // PDO::FETCH_KEY_PAIR - array return new Union([new TArray([Type::getArrayKey(), new Union([new TScalar(), new TNull()])])]); case 3: // PDO::FETCH_NUM - list> return new Union([Type::getListAtomic(new Union([Type::getListAtomic(new Union([new TScalar(), new TNull()]))]))]); case 5: // PDO::FETCH_OBJ - list return new Union([Type::getListAtomic(new Union([new TNamedObject('stdClass')]))]); } return null; } } */ public static function getFunctionIds() : array { return ['parse_url']; } private static ?Union $acceptable_int_component_type = null; private static ?Union $acceptable_string_component_type = null; private static ?Union $nullable_falsable_int = null; private static ?Union $nullable_falsable_string = null; private static ?Union $nullable_string_or_int = null; private static ?Union $return_type = null; public static function getFunctionReturnType(FunctionReturnTypeProviderEvent $event) : Union { $statements_source = $event->getStatementsSource(); $call_args = $event->getCallArgs(); if (!$statements_source instanceof StatementsAnalyzer) { return Type::getMixed(); } if (isset($call_args[1])) { $is_default_component = \false; if ($component_type = $statements_source->node_data->getType($call_args[1]->value)) { if (!$component_type->hasMixed()) { $codebase = $statements_source->getCodebase(); self::$acceptable_string_component_type ??= new Union([new TLiteralInt(PHP_URL_SCHEME), new TLiteralInt(PHP_URL_USER), new TLiteralInt(PHP_URL_PASS), new TLiteralInt(PHP_URL_HOST), new TLiteralInt(PHP_URL_PATH), new TLiteralInt(PHP_URL_QUERY), new TLiteralInt(PHP_URL_FRAGMENT)]); self::$acceptable_int_component_type ??= new Union([new TLiteralInt(PHP_URL_PORT)]); if (UnionTypeComparator::isContainedBy($codebase, $component_type, self::$acceptable_string_component_type)) { self::$nullable_falsable_string ??= new Union([new TString(), new TFalse(), new TNull()], ['ignore_nullable_issues' => $statements_source->getCodebase()->config->ignore_internal_nullable_issues, 'ignore_falsable_issues' => $statements_source->getCodebase()->config->ignore_internal_falsable_issues]); return self::$nullable_falsable_string; } if (UnionTypeComparator::isContainedBy($codebase, $component_type, self::$acceptable_int_component_type)) { self::$nullable_falsable_int ??= new Union([new TInt(), new TFalse(), new TNull()], ['ignore_nullable_issues' => $statements_source->getCodebase()->config->ignore_internal_nullable_issues, 'ignore_falsable_issues' => $statements_source->getCodebase()->config->ignore_internal_falsable_issues]); return self::$nullable_falsable_int; } if ($component_type->isSingleIntLiteral()) { $component_type_type = $component_type->getSingleIntLiteral(); $is_default_component = $component_type_type->value <= -1; } } } if (!$is_default_component) { self::$nullable_string_or_int ??= new Union([new TString(), new TInt(), new TNull()], ['ignore_nullable_issues' => $statements_source->getCodebase()->config->ignore_internal_nullable_issues]); return self::$nullable_string_or_int; } } if (!self::$return_type) { $component_types = array_fill_keys(['scheme', 'user', 'pass', 'host', 'path', 'query', 'fragment'], new Union([new TString()], ['possibly_undefined' => \true])); $component_types['port'] = new Union([new TInt()], ['possibly_undefined' => \true]); self::$return_type = new Union([new TKeyedArray($component_types, null), new TFalse()], ['ignore_falsable_issues' => $statements_source->getCodebase()->config->ignore_internal_falsable_issues]); } return self::$return_type; } } */ public static function getFunctionIds() : array { return ['array_fill']; } public static function getFunctionReturnType(FunctionReturnTypeProviderEvent $event) : Union { $statements_source = $event->getStatementsSource(); $call_args = $event->getCallArgs(); if (!$statements_source instanceof StatementsAnalyzer) { return Type::getMixed(); } $codebase = $statements_source->getCodebase(); $first_arg_type = isset($call_args[0]) ? $statements_source->node_data->getType($call_args[0]->value) : null; $second_arg_type = isset($call_args[1]) ? $statements_source->node_data->getType($call_args[1]->value) : null; $third_arg_type = isset($call_args[2]) ? $statements_source->node_data->getType($call_args[2]->value) : null; $value_type_from_third_arg = $third_arg_type ? $third_arg_type : Type::getMixed(); if ($first_arg_type && $second_arg_type && $third_arg_type && $first_arg_type->isSingleIntLiteral() && $second_arg_type->isSingleIntLiteral()) { $first_arg_type = $first_arg_type->getSingleIntLiteral()->value; $second_arg_type = $second_arg_type->getSingleIntLiteral()->value; $is_list = $first_arg_type === 0; if ($second_arg_type < 0) { if ($codebase->analysis_php_version_id < 80000) { return Type::getFalse(); } return Type::getNever(); } $result = []; if ($first_arg_type < 0 && $codebase->analysis_php_version_id < 80000) { $result[$first_arg_type] = $third_arg_type; $first_arg_type = 0; $second_arg_type--; } while ($second_arg_type > 0) { $result[$first_arg_type++] = $third_arg_type; $second_arg_type--; } if (!$result) { return Type::getEmptyArray(); } return new Union([new TKeyedArray($result, null, null, $is_list)]); } if ($first_arg_type && $first_arg_type->isSingleIntLiteral() && $first_arg_type->getSingleIntLiteral()->value === 0) { if ($second_arg_type && self::isPositiveNumericType($second_arg_type)) { return Type::getNonEmptyList($value_type_from_third_arg); } return Type::getList($value_type_from_third_arg); } if ($second_arg_type && self::isPositiveNumericType($second_arg_type)) { if ($first_arg_type && $first_arg_type->isSingleIntLiteral() && $second_arg_type->isSingleIntLiteral()) { return new Union([new TNonEmptyArray([Type::getIntRange($first_arg_type->getSingleIntLiteral()->value, $second_arg_type->getSingleIntLiteral()->value), $value_type_from_third_arg])]); } return new Union([new TNonEmptyArray([Type::getInt(), $value_type_from_third_arg])]); } return new Union([new TArray([Type::getInt(), $value_type_from_third_arg])]); } private static function isPositiveNumericType(Union $arg) : bool { if ($arg->isSingle()) { foreach ($arg->getRangeInts() as $range_int) { if ($range_int->isPositive()) { return \true; } } } return $arg->isSingleIntLiteral() && $arg->getSingleIntLiteral()->value > 0; } } */ public static function getFunctionIds() : array { return ['dirname']; } public static function getFunctionReturnType(FunctionReturnTypeProviderEvent $event) : ?Union { $call_args = $event->getCallArgs(); if (count($call_args) === 0) { return null; } $statements_source = $event->getStatementsSource(); $node_type_provider = $statements_source->getNodeTypeProvider(); $union = $node_type_provider->getType($call_args[0]->value); $generic = \false; if ($union !== null) { foreach ($union->getAtomicTypes() as $atomic) { if ($atomic instanceof Type\Atomic\TNonFalsyString) { continue; } if ($atomic instanceof Type\Atomic\TLiteralString) { if ($atomic->value === '') { $generic = \true; break; } // 0 will be non-falsy too (.) continue; } if ($atomic instanceof Type\Atomic\TNonEmptyString || $atomic instanceof Type\Atomic\TEmptyNumeric) { continue; } // generic string is the only other possible case of empty string // which would result in a generic string $generic = \true; break; } } $fallback_type = Type::getNonFalsyString(); if ($union === null || $generic) { $fallback_type = Type::getString(); } $dir_level = 1; if (isset($call_args[1])) { $type = $node_type_provider->getType($call_args[1]->value); if ($type !== null && $type->isSingle()) { $atomic_type = array_values($type->getAtomicTypes())[0]; if ($atomic_type instanceof TLiteralInt && $atomic_type->value > 0) { $dir_level = $atomic_type->value; } else { return $fallback_type; } } } $evaled_path = IncludeAnalyzer::getPathTo($call_args[0]->value, null, null, $statements_source->getFileName(), $statements_source->getCodebase()->config); if ($evaled_path === null) { return $fallback_type; } $path_to_file = dirname($evaled_path, $dir_level); return Type::getString($path_to_file); } } */ public static function getFunctionIds() : array { return ['crypt']; } public static function getFunctionReturnType(FunctionReturnTypeProviderEvent $event) : ?Union { $statements_source = $event->getStatementsSource(); $call_args = $event->getCallArgs(); if (!$statements_source instanceof StatementsAnalyzer || !$call_args) { return Type::getMixed(); } if (($first_arg_type = $statements_source->node_data->getType($call_args[0]->value)) && $first_arg_type->isString()) { return new Union([new TString()]); } return new Union([new TString(), new TNull()], ['ignore_nullable_issues' => \true]); } } */ public static function getFunctionIds() : array { return ['round']; } public static function getFunctionReturnType(FunctionReturnTypeProviderEvent $event) : ?Type\Union { $call_args = $event->getCallArgs(); if (count($call_args) === 0) { return null; } $statements_source = $event->getStatementsSource(); $nodeTypeProvider = $statements_source->getNodeTypeProvider(); $num_arg = $nodeTypeProvider->getType($call_args[0]->value); $precision_val = 0; if ($statements_source instanceof StatementsAnalyzer && count($call_args) > 1) { $type = $statements_source->node_data->getType($call_args[1]->value); if ($type !== null && $type->isSingle()) { $atomic_type = array_values($type->getAtomicTypes())[0]; if ($atomic_type instanceof Type\Atomic\TLiteralInt) { $precision_val = $atomic_type->value; } } } $mode_val = PHP_ROUND_HALF_UP; if ($statements_source instanceof StatementsAnalyzer && count($call_args) > 2) { $type = $statements_source->node_data->getType($call_args[2]->value); if ($type !== null && $type->isSingle()) { $atomic_type = array_values($type->getAtomicTypes())[0]; if ($atomic_type instanceof Type\Atomic\TLiteralInt) { /** @var positive-int|0 $mode_val */ $mode_val = $atomic_type->value; } } } if ($num_arg !== null && $num_arg->isSingle()) { $num_type = array_values($num_arg->getAtomicTypes())[0]; if ($num_type instanceof Type\Atomic\TLiteralFloat || $num_type instanceof Type\Atomic\TLiteralInt) { $rounded_val = round($num_type->value, $precision_val, $mode_val); return new Type\Union([new Type\Atomic\TLiteralFloat($rounded_val)]); } } return new Type\Union([new Type\Atomic\TFloat()]); } } */ public static function getFunctionIds() : array { return ['iterator_to_array']; } public static function getFunctionReturnType(FunctionReturnTypeProviderEvent $event) : Union { $statements_source = $event->getStatementsSource(); $call_args = $event->getCallArgs(); $function_id = $event->getFunctionId(); $context = $event->getContext(); if (!$statements_source instanceof StatementsAnalyzer || !$call_args) { return Type::getMixed(); } if ($first_arg_type = $statements_source->node_data->getType($call_args[0]->value)) { $key_type = null; $value_type = null; $codebase = $statements_source->getCodebase(); $atomic_types = $first_arg_type->getAtomicTypes(); while ($call_arg_atomic_type = array_shift($atomic_types)) { if ($call_arg_atomic_type instanceof TTemplateParam) { $atomic_types = array_merge($atomic_types, $call_arg_atomic_type->as->getAtomicTypes()); continue; } if ($call_arg_atomic_type instanceof TNamedObject && AtomicTypeComparator::isContainedBy($codebase, $call_arg_atomic_type, new TIterable([Type::getMixed(), Type::getMixed()]))) { $has_valid_iterator = \true; ForeachAnalyzer::handleIterable($statements_source, $call_arg_atomic_type, $call_args[0]->value, $codebase, $context, $key_type, $value_type, $has_valid_iterator); } } if ($value_type) { $second_arg_type = isset($call_args[1]) ? $statements_source->node_data->getType($call_args[1]->value) : null; if ($second_arg_type && (string) $second_arg_type === 'false') { return Type::getList($value_type); } $key_type = $key_type && (!isset($call_args[1]) || $second_arg_type && (string) $second_arg_type === 'true') ? $key_type : Type::getArrayKey(); if ($key_type->hasMixed()) { $key_type = Type::getArrayKey(); } if ($key_type->isSingle() && $key_type->hasTemplate()) { $template_types = $key_type->getTemplateTypes(); $template_type = array_shift($template_types); if ($template_type->as->hasMixed()) { $template_type = $template_type->replaceAs(Type::getArrayKey()); $key_type = new Union([$template_type]); } } return new Union([new TArray([$key_type, $value_type])]); } } $callmap_callables = InternalCallMapHandler::getCallablesFromCallMap($function_id); assert($callmap_callables && $callmap_callables[0]->return_type); return $callmap_callables[0]->return_type; } } */ public static function getFunctionIds() : array { return ['current', 'next', 'prev', 'reset', 'end']; } public static function getFunctionReturnType(FunctionReturnTypeProviderEvent $event) : Union { $statements_source = $event->getStatementsSource(); $call_args = $event->getCallArgs(); $function_id = $event->getFunctionId(); if (!$statements_source instanceof StatementsAnalyzer) { return Type::getMixed(); } $first_arg = $call_args[0]->value ?? null; if (!$first_arg) { return Type::getMixed(); } $first_arg_type = $statements_source->node_data->getType($first_arg); if (!$first_arg_type) { return Type::getMixed(); } $atomic_types = $first_arg_type->getAtomicTypes(); $value_type = null; $definitely_has_items = \false; while ($atomic_type = array_shift($atomic_types)) { if ($atomic_type instanceof TTemplateParam) { $atomic_types = array_merge($atomic_types, $atomic_type->as->getAtomicTypes()); continue; } if ($atomic_type instanceof TList) { $atomic_type = $atomic_type->getKeyedArray(); } if ($atomic_type instanceof TArray) { $value_type = $atomic_type->type_params[1]; $definitely_has_items = $atomic_type instanceof TNonEmptyArray; } elseif ($atomic_type instanceof TKeyedArray) { $value_type = $atomic_type->getGenericValueType(); $definitely_has_items = $atomic_type->getGenericArrayType() instanceof TNonEmptyArray; } else { return Type::getMixed(); } } if (!$value_type) { throw new UnexpectedValueException('This should never happen'); } if ($value_type->isNever()) { $value_type = Type::getFalse(); } elseif (!$definitely_has_items || self::isFunctionAlreadyHandledByStub($function_id)) { $value_type = $value_type->getBuilder()->addType(new TFalse()); $codebase = $statements_source->getCodebase(); if ($codebase->config->ignore_internal_falsable_issues) { $value_type->ignore_falsable_issues = \true; } $value_type = $value_type->freeze(); } $temp = Type::getMixed(); ArrayFetchAnalyzer::taintArrayFetch($statements_source, $first_arg, null, $value_type, $temp); return $value_type; } private static function isFunctionAlreadyHandledByStub(string $function_id) : bool { return !in_array($function_id, self::IGNORE_FUNCTION_IDS_FOR_FALSE_RETURN_TYPE, \true); } } */ public static function getMethodParams(MethodParamsProviderEvent $event) : ?array { $statements_source = $event->getStatementsSource(); $method_name_lowercase = $event->getMethodNameLowercase(); $context = $event->getContext(); $call_args = $event->getCallArgs(); if (!$statements_source instanceof StatementsAnalyzer) { return null; } if ($method_name_lowercase === 'setfetchmode') { if (!$context || !$call_args || ExpressionAnalyzer::analyze($statements_source, $call_args[0]->value, $context) === \false) { return null; } if (($first_call_arg_type = $statements_source->node_data->getType($call_args[0]->value)) && $first_call_arg_type->isSingleIntLiteral()) { $params = [new FunctionLikeParameter('mode', \false, Type::getInt(), Type::getInt(), null, null, \false)]; $value = $first_call_arg_type->getSingleIntLiteral()->value; switch ($value) { case 7: // PDO::FETCH_COLUMN $params[] = new FunctionLikeParameter('colno', \false, Type::getInt(), Type::getInt(), null, null, \false); break; case 8: // PDO::FETCH_CLASS $params[] = new FunctionLikeParameter('classname', \false, Type::getClassString(), Type::getClassString(), null, null, \false); $params[] = new FunctionLikeParameter('ctorargs', \false, Type::getArray(), Type::getArray(), null, null, \true); break; case 9: // PDO::FETCH_INTO $params[] = new FunctionLikeParameter('object', \false, Type::getObject(), Type::getObject(), null, null, \false); break; } return $params; } } return null; } } */ public static function getFunctionIds() : array { return ['hexdec']; } public static function getFunctionReturnType(FunctionReturnTypeProviderEvent $event) : Union { $statements_source = $event->getStatementsSource(); if (!$statements_source instanceof StatementsAnalyzer) { return Type::getMixed(); } return Type::getInt(\true); } } */ public static function getFunctionIds() : array { return ['array_reverse']; } public static function getFunctionReturnType(FunctionReturnTypeProviderEvent $event) : Union { $statements_source = $event->getStatementsSource(); $call_args = $event->getCallArgs(); if (!$statements_source instanceof StatementsAnalyzer) { return Type::getMixed(); } $first_arg = $call_args[0]->value ?? null; $first_arg_type = null; $first_arg_array = $first_arg && ($first_arg_type = $statements_source->node_data->getType($first_arg)) && $first_arg_type->hasType('array') && $first_arg_type->isArray() && ($array_atomic_type = $first_arg_type->getArray()) && ($array_atomic_type instanceof TArray || $array_atomic_type instanceof TKeyedArray) ? $array_atomic_type : null; if (!$first_arg_array || !$first_arg_type) { return Type::getArray(); } if ($first_arg_array instanceof TArray) { return $first_arg_type; } if ($first_arg_array->is_list) { $second_arg = $call_args[1]->value ?? null; if (!$second_arg || ($second_arg_type = $statements_source->node_data->getType($second_arg)) && $second_arg_type->isFalse()) { return $first_arg_array->fallback_params ? $first_arg_array->isNonEmpty() ? Type::getNonEmptyList($first_arg_array->getGenericValueType()) : Type::getList($first_arg_array->getGenericValueType()) : new Union([$first_arg_array->setProperties(array_reverse($first_arg_array->properties))]); } return new Union([new TKeyedArray($first_arg_array->properties, null, $first_arg_array->fallback_params, \false)]); } return new Union([$first_arg_array->getGenericArrayType()]); } } */ public static function getFunctionIds() : array { return ['array_combine']; } public static function getFunctionReturnType(FunctionReturnTypeProviderEvent $event) : ?Union { $statements_source = $event->getStatementsSource(); $call_args = $event->getCallArgs(); if (!$statements_source instanceof StatementsAnalyzer || count($call_args) < 2) { return Type::getNever(); } if (!($keys_type = $statements_source->node_data->getType($call_args[0]->value))) { return null; } if (!$keys_type->isArray()) { return null; } $keys = $keys_type->getArray(); if ($keys instanceof TArray && $keys->isEmptyArray()) { $keys = []; } elseif (!$keys instanceof TKeyedArray || $keys->fallback_params) { return null; } else { $keys = $keys->properties; } if (!($values_type = $statements_source->node_data->getType($call_args[1]->value))) { return null; } if (!$values_type->isArray()) { return null; } $values = $values_type->getArray(); if ($values instanceof TArray && $values->isEmptyArray()) { $values = []; } elseif (!$values instanceof TKeyedArray || $values->fallback_params) { return null; } else { $values = $values->properties; } $keys_array = []; $is_list = \true; $prev_key = -1; foreach ($keys as $key) { if ($key->possibly_undefined) { return null; } if ($key->isSingleIntLiteral()) { $key = $key->getSingleIntLiteral()->value; $keys_array[] = $key; if ($is_list && $key - 1 !== $prev_key) { $is_list = \false; } $prev_key = $key; } elseif ($key->isSingleStringLiteral()) { $keys_array[] = $key->getSingleStringLiteral()->value; $is_list = \false; } else { return null; } } foreach ($values as $value) { if ($value->possibly_undefined) { return null; } } if (count($keys_array) !== count($values)) { IssueBuffer::maybeAdd(new InvalidArgument('The keys array ' . $keys_type->getId() . ' must have exactly the same ' . 'number of elements as the values array ' . $values_type->getId(), $event->getCodeLocation(), 'array_combine'), $statements_source->getSuppressedIssues()); return $statements_source->getCodebase()->analysis_php_version_id >= 80000 ? Type::getNever() : Type::getFalse(); } $result = array_combine($keys_array, $values); assert($result !== \false); if (!$result) { return Type::getEmptyArray(); } return new Union([new TKeyedArray($result, null, null, $is_list)]); } } */ public static function getFunctionIds() : array { return ['printf', 'sprintf']; } public static function getFunctionReturnType(FunctionReturnTypeProviderEvent $event) : ?Union { $statements_source = $event->getStatementsSource(); $call_args = $event->getCallArgs(); // invalid - will already report an error for the params anyway if (count($call_args) < 1) { return null; } $has_splat_args = \false; $node_type_provider = $statements_source->getNodeTypeProvider(); foreach ($call_args as $call_arg) { $type = $node_type_provider->getType($call_arg->value); if ($type === null) { continue; } // if it's an array, used with splat operator // we cannot validate it reliably below and report false positive errors if ($type->isArray()) { $has_splat_args = \true; break; } } // there is only 1 array argument, fall back to the default handling // eventually this could be refined // to check if it's an array with literal string as first element for further checking if (count($call_args) === 1 && $has_splat_args === \true) { IssueBuffer::maybeAdd(new RedundantFunctionCall('Using the splat operator is redundant, as v' . $event->getFunctionId() . ' without splat operator can be used instead of ' . $event->getFunctionId(), $event->getCodeLocation()), $statements_source->getSuppressedIssues()); return null; } // it makes no sense to use sprintf when there is only 1 arg (the format) // as it wouldn't have any placeholders // if it's a literal string, we can check it further though! $first_arg_type = $node_type_provider->getType($call_args[0]->value); if (count($call_args) === 1 && ($first_arg_type === null || !$first_arg_type->isSingleStringLiteral())) { IssueBuffer::maybeAdd(new RedundantFunctionCall('Using ' . $event->getFunctionId() . ' with a single argument is redundant, since there are no placeholder params to be substituted', $event->getCodeLocation()), $statements_source->getSuppressedIssues()); return null; } // PHP 7 handling for formats that do not contain anything but placeholders $is_falsable = \true; foreach ($call_args as $index => $call_arg) { $type = $node_type_provider->getType($call_arg->value); if ($type === null && $index === 0 && $event->getFunctionId() === 'printf') { // printf only has the format validated above // don't change the return type break; } if ($type === null) { continue; } if ($index === 0 && $type->isSingleStringLiteral()) { if ($type->getSingleStringLiteral()->value === '') { IssueBuffer::maybeAdd(new RedundantFunctionCall('Calling ' . $event->getFunctionId() . ' with an empty first argument does nothing', $event->getCodeLocation()), $statements_source->getSuppressedIssues()); if ($event->getFunctionId() === 'printf') { return Type::getInt(\false, 0); } return Type::getString(''); } // there are probably additional formats that return an empty string, this is just a starting point if (preg_match('/^%(?:\\d+\\$)?[-+]?0(?:\\.0)?s$/', $type->getSingleStringLiteral()->value) === 1) { IssueBuffer::maybeAdd(new InvalidArgument('The pattern of argument 1 of ' . $event->getFunctionId() . ' will always return an empty string', $event->getCodeLocation(), $event->getFunctionId()), $statements_source->getSuppressedIssues()); if ($event->getFunctionId() === 'printf') { return Type::getInt(\false, 0); } return Type::getString(''); } // these placeholders are too complex to handle for now if (preg_match('/%(?:\\d+\\$)?[-+]?(?:\\d+|\\*)(?:\\.(?:\\d+|\\*))?[bcdouxXeEfFgGhHs]/', $type->getSingleStringLiteral()->value) === 1) { return null; } // assume a random, high number for tests $provided_placeholders_count = $has_splat_args === \true ? 100 : count($call_args) - 1; $dummy = array_fill(0, $provided_placeholders_count, ''); // check if we have enough/too many arguments and a valid format $initial_result = null; while (count($dummy) > -1) { $result = null; try { // before PHP 8, an uncatchable Warning is thrown if too few arguments are passed // which is ignored and handled below instead $result = @sprintf($type->getSingleStringLiteral()->value, ...$dummy); if ($initial_result === null) { $initial_result = $result; if ($result === $type->getSingleStringLiteral()->value) { if (count($call_args) > 1) { // we need to report this here too, since we return early without further validation // otherwise people who have suspended RedundantFunctionCall errors // will not get an error for this IssueBuffer::maybeAdd(new TooManyArguments('Too many arguments for the number of placeholders in ' . $event->getFunctionId(), $event->getCodeLocation(), $event->getFunctionId()), $statements_source->getSuppressedIssues()); } // the same error as above, but we have validated the pattern now if (count($call_args) === 1) { IssueBuffer::maybeAdd(new RedundantFunctionCall('Using ' . $event->getFunctionId() . ' with a single argument is redundant,' . ' since there are no placeholder params to be substituted', $event->getCodeLocation()), $statements_source->getSuppressedIssues()); } else { IssueBuffer::maybeAdd(new RedundantFunctionCall('Argument 1 of ' . $event->getFunctionId() . ' does not contain any placeholders', $event->getCodeLocation()), $statements_source->getSuppressedIssues()); } if ($event->getFunctionId() === 'printf') { return Type::getInt(\false, strlen($type->getSingleStringLiteral()->value)); } return $type; } } } catch (ValueError $value_error) { // PHP 8 // the format is invalid IssueBuffer::maybeAdd(new InvalidArgument('Argument 1 of ' . $event->getFunctionId() . ' is invalid - ' . $value_error->getMessage(), $event->getCodeLocation(), $event->getFunctionId()), $statements_source->getSuppressedIssues()); break 2; } catch (ArgumentCountError $error) { // PHP 8 if (count($dummy) === $provided_placeholders_count) { IssueBuffer::maybeAdd(new TooFewArguments('Too few arguments for ' . $event->getFunctionId(), $event->getCodeLocation(), $event->getFunctionId()), $statements_source->getSuppressedIssues()); break 2; } } if ($result === \false && count($dummy) === $provided_placeholders_count) { // could be invalid format or too few arguments // we cannot distinguish this in PHP 7 without additional checks $max_dummy = array_fill(0, 100, ''); $result = @sprintf($type->getSingleStringLiteral()->value, ...$max_dummy); if ($result === \false) { // the format is invalid IssueBuffer::maybeAdd(new InvalidArgument('Argument 1 of ' . $event->getFunctionId() . ' is invalid', $event->getCodeLocation(), $event->getFunctionId()), $statements_source->getSuppressedIssues()); } else { IssueBuffer::maybeAdd(new TooFewArguments('Too few arguments for ' . $event->getFunctionId(), $event->getCodeLocation(), $event->getFunctionId()), $statements_source->getSuppressedIssues()); } return Type::getFalse(); } // we can only validate the format and arg 1 when using splat if ($has_splat_args === \true) { break; } if (is_string($result) && count($dummy) + 1 <= $provided_placeholders_count) { IssueBuffer::maybeAdd(new TooManyArguments('Too many arguments for the number of placeholders in ' . $event->getFunctionId(), $event->getCodeLocation(), $event->getFunctionId()), $statements_source->getSuppressedIssues()); break; } if (!is_string($result)) { break; } // abort if it's empty, since we checked everything if (array_pop($dummy) === null) { break; } } if ($event->getFunctionId() === 'printf') { // printf only has the format validated above // don't change the return type return null; } if ($initial_result !== null && $initial_result !== \false && $initial_result !== '') { return Type::getNonEmptyString(); } // if we didn't have any valid result // the pattern is invalid or not yet supported by the return type provider if ($initial_result === null || $initial_result === \false) { return null; } // the initial result is an empty string // which means the format is valid and it depends on the args, whether it is non-empty-string or not $is_falsable = \false; } if ($index === 0 && $event->getFunctionId() === 'printf') { // printf only has the format validated above // don't change the return type break; } if ($index === 0) { continue; } // if the function has more arguments than the pattern has placeholders, this could be a false positive // if the param is not used in the pattern if ($type->isNonEmptyString() || $type->isInt() || $type->isFloat()) { return Type::getNonEmptyString(); } // check for unions of either $atomic_types = $type->getAtomicTypes(); if ($atomic_types === []) { continue; } foreach ($atomic_types as $atomic_type) { if ($atomic_type instanceof TNonEmptyString || $atomic_type instanceof TClassString || $atomic_type instanceof TLiteralString && $atomic_type->value !== '' || $atomic_type instanceof TInt || $atomic_type instanceof TFloat || $atomic_type instanceof TNumeric) { // valid non-empty types, potentially there are more though continue; } // empty or generic string // or other unhandled type continue 2; } return Type::getNonEmptyString(); } if ($is_falsable === \false) { return Type::getString(); } return null; } } */ public static function getFunctionIds() : array { return ['array_map']; } public static function getFunctionReturnType(FunctionReturnTypeProviderEvent $event) : Union { $statements_source = $event->getStatementsSource(); $call_args = $event->getCallArgs(); $context = $event->getContext(); if (!$statements_source instanceof StatementsAnalyzer) { return Type::getMixed(); } $function_call_arg = $call_args[0] ?? null; $function_call_type = $function_call_arg ? $statements_source->node_data->getType($function_call_arg->value) : null; if ($function_call_type && $function_call_type->isNull()) { array_shift($call_args); if (!$call_args) { return Type::getNever(); } $array_arg_types = []; $orig_types = []; foreach ($call_args as $call_arg) { $call_arg_type = $statements_source->node_data->getType($call_arg->value); if ($call_arg_type && $call_arg_type->isSingle() && ($call_arg_atomic = $call_arg_type->getSingleAtomic()) instanceof TKeyedArray && $call_arg_atomic->fallback_params === null) { $array_arg_types[] = array_values($call_arg_atomic->properties); $orig_types[] = $call_arg_type; } elseif ($call_arg_type && $call_arg_type->isSingle() && ($call_arg_atomic = $call_arg_type->getSingleAtomic()) instanceof TArray && $call_arg_atomic->isEmptyArray()) { $array_arg_types[] = []; $orig_types[] = $call_arg_type; } else { return Type::getArray(); } } if (count($orig_types) === 1) { return $orig_types[0]; } $null = Type::getNull(); $array_arg_types = array_map(null, ...$array_arg_types); $array_arg_types = array_map( /** @param non-empty-array $sub */ static function (array $sub) use($null) { $sub = array_map(static fn(?Union $t) => $t ?? $null, $sub); return new Union([new TKeyedArray($sub, null, null, \true)]); }, $array_arg_types ); if (!$array_arg_types) { return Type::getEmptyArray(); } return new Union([new TKeyedArray($array_arg_types, null, null, \true)]); } $array_arg = $call_args[1] ?? null; if (!$array_arg) { return Type::getArray(); } $array_arg_atomic_type = null; $array_arg_type = null; if ($array_arg_union_type = $statements_source->node_data->getType($array_arg->value)) { $arg_types = $array_arg_union_type->getAtomicTypes(); if (isset($arg_types['array'])) { $array_arg_atomic_type = $arg_types['array']; if ($array_arg_atomic_type instanceof TList) { $array_arg_atomic_type = $array_arg_atomic_type->getKeyedArray(); } $array_arg_type = ArrayType::infer($array_arg_atomic_type); } } $generic_key_type = null; $mapping_return_type = null; if ($function_call_arg && $function_call_type) { if (count($call_args) === 2) { $generic_key_type = $array_arg_type->key ?? Type::getArrayKey(); } else { $generic_key_type = Type::getInt(); } if ($function_call_type->hasCallableType()) { $closure_types = $function_call_type->getClosureTypes() ?: $function_call_type->getCallableTypes(); $closure_atomic_type = reset($closure_types); $closure_return_type = $closure_atomic_type->return_type ?: Type::getMixed(); if ($closure_return_type->isVoid()) { $closure_return_type = Type::getNull(); } $mapping_return_type = $closure_return_type; } elseif ($function_call_arg->value instanceof PhpParser\Node\Scalar\String_ || $function_call_arg->value instanceof PhpParser\Node\Expr\Array_ || $function_call_arg->value instanceof PhpParser\Node\Expr\BinaryOp\Concat) { $mapping_function_ids = CallAnalyzer::getFunctionIdsFromCallableArg($statements_source, $function_call_arg->value); if ($mapping_function_ids) { $mapping_return_type = self::getReturnTypeFromMappingIds($statements_source, $mapping_function_ids, $context, $function_call_arg, array_slice($call_args, 1)); } if ($function_call_arg->value instanceof PhpParser\Node\Expr\Array_ && isset($function_call_arg->value->items[0]) && isset($function_call_arg->value->items[1]) && $function_call_arg->value->items[1]->value instanceof PhpParser\Node\Scalar\String_ && $function_call_arg->value->items[0]->value instanceof PhpParser\Node\Expr\Variable && ($variable_type = $statements_source->node_data->getType($function_call_arg->value->items[0]->value))) { $fake_method_call = null; foreach ($variable_type->getAtomicTypes() as $variable_atomic_type) { if ($variable_atomic_type instanceof TTemplateParam || $variable_atomic_type instanceof TTemplateParamClass) { $fake_method_call = new VirtualStaticCall($function_call_arg->value->items[0]->value, $function_call_arg->value->items[1]->value->value, []); } } if ($fake_method_call) { $fake_method_return_type = self::executeFakeCall($statements_source, $fake_method_call, $context); if ($fake_method_return_type) { $mapping_return_type = $fake_method_return_type; } } } } } if ($mapping_return_type && $generic_key_type) { if ($array_arg_atomic_type instanceof TKeyedArray && count($call_args) === 2) { $atomic_type = new TKeyedArray(array_map(static fn(Union $in): Union => $mapping_return_type->setPossiblyUndefined($in->possibly_undefined), $array_arg_atomic_type->properties), null, $array_arg_atomic_type->fallback_params === null ? null : [$array_arg_atomic_type->fallback_params[0], $mapping_return_type], $array_arg_atomic_type->is_list); return new Union([$atomic_type]); } if ($array_arg_atomic_type instanceof TKeyedArray && $array_arg_atomic_type->is_list || count($call_args) !== 2) { if ($array_arg_atomic_type instanceof TKeyedArray && $array_arg_atomic_type->isNonEmpty()) { return Type::getNonEmptyList($mapping_return_type); } return Type::getList($mapping_return_type); } if ($array_arg_atomic_type instanceof TNonEmptyArray) { return new Union([new TNonEmptyArray([$generic_key_type, $mapping_return_type])]); } return new Union([new TArray([$generic_key_type, $mapping_return_type])]); } return count($call_args) === 2 && !($array_arg_type->is_list ?? \false) ? new Union([new TArray([$array_arg_type->key ?? Type::getArrayKey(), Type::getMixed()])]) : Type::getList(); } /** * @param array>>|null $assertions */ private static function executeFakeCall(StatementsAnalyzer $statements_analyzer, PhpParser\Node\Expr $fake_call, Context $context, ?array &$assertions = null) : ?Union { $old_data_provider = $statements_analyzer->node_data; $statements_analyzer->node_data = clone $statements_analyzer->node_data; $suppressed_issues = $statements_analyzer->getSuppressedIssues(); if (!in_array('PossiblyInvalidMethodCall', $suppressed_issues, \true)) { $statements_analyzer->addSuppressedIssues(['PossiblyInvalidMethodCall']); } if (!in_array('MixedArrayOffset', $suppressed_issues, \true)) { $statements_analyzer->addSuppressedIssues(['MixedArrayOffset']); } $was_inside_call = $context->inside_call; $context->inside_call = \true; if ($fake_call instanceof PhpParser\Node\Expr\StaticCall) { StaticCallAnalyzer::analyze($statements_analyzer, $fake_call, $context); } elseif ($fake_call instanceof PhpParser\Node\Expr\MethodCall) { MethodCallAnalyzer::analyze($statements_analyzer, $fake_call, $context); } elseif ($fake_call instanceof PhpParser\Node\Expr\FuncCall) { FunctionCallAnalyzer::analyze($statements_analyzer, $fake_call, $context); } else { throw new UnexpectedValueException('UnrecognizedCall'); } $codebase = $statements_analyzer->getCodebase(); if ($assertions !== null) { $anded_assertions = AssertionFinder::scrapeAssertions($fake_call, null, $statements_analyzer, $codebase); $assertions = $anded_assertions[0] ?? []; } $context->inside_call = $was_inside_call; if (!in_array('PossiblyInvalidMethodCall', $suppressed_issues, \true)) { $statements_analyzer->removeSuppressedIssues(['PossiblyInvalidMethodCall']); } if (!in_array('MixedArrayOffset', $suppressed_issues, \true)) { $statements_analyzer->removeSuppressedIssues(['MixedArrayOffset']); } $return_type = $statements_analyzer->node_data->getType($fake_call) ?? null; $statements_analyzer->node_data = $old_data_provider; return $return_type; } /** * @param non-empty-array $mapping_function_ids * @param list $array_args * @param int|null $fake_var_discriminator Set the fake variable id to a known value with the discriminator * as a substring, and don't clear it from the context. * @param array>>|null $assertions */ public static function getReturnTypeFromMappingIds(StatementsAnalyzer $statements_source, array $mapping_function_ids, Context $context, PhpParser\Node\Arg $function_call_arg, array $array_args, ?array &$assertions = null, ?int $fake_var_discriminator = null) : Union { $mapping_return_type = null; $codebase = $statements_source->getCodebase(); $clean_context = \false; foreach ($mapping_function_ids as $mapping_function_id) { $mapping_function_id_parts = explode('&', $mapping_function_id); if ($fake_var_discriminator === null) { $fake_var_discriminator = mt_rand(); $clean_context = \true; } foreach ($mapping_function_id_parts as $mapping_function_id_part) { $fake_args = []; foreach ($array_args as $array_arg) { $fake_args[] = new VirtualArg(new VirtualArrayDimFetch($array_arg->value, new VirtualVariable("__fake_{$fake_var_discriminator}_offset_var__", $array_arg->value->getAttributes()), $array_arg->value->getAttributes()), \false, \false, $array_arg->getAttributes()); } if (strpos($mapping_function_id_part, '::') !== \false) { $is_instance = \false; if ($mapping_function_id_part[0] === '$') { $mapping_function_id_part = substr($mapping_function_id_part, 1); $is_instance = \true; } $method_id_parts = explode('::', $mapping_function_id_part); [$callable_fq_class_name, $callable_method_name] = $method_id_parts; if ($is_instance) { $fake_method_call = new VirtualMethodCall(new VirtualVariable("__fake_{$fake_var_discriminator}_method_call_var__", $function_call_arg->getAttributes()), new VirtualIdentifier($callable_method_name, $function_call_arg->getAttributes()), $fake_args, $function_call_arg->getAttributes()); $lhs_instance_type = null; $callable_type = $statements_source->node_data->getType($function_call_arg->value); if ($callable_type) { foreach ($callable_type->getAtomicTypes() as $atomic_type) { if ($atomic_type instanceof TKeyedArray && count($atomic_type->properties) === 2 && isset($atomic_type->properties[0])) { $lhs_instance_type = $atomic_type->properties[0]; } } } $context->vars_in_scope["\$__fake_{$fake_var_discriminator}_offset_var__"] = Type::getMixed(); $context->vars_in_scope["\$__fake_{$fake_var_discriminator}_method_call_var__"] = $lhs_instance_type ?: new Union([new TNamedObject($callable_fq_class_name)]); } else { $fake_method_call = new VirtualStaticCall(new VirtualFullyQualified($callable_fq_class_name, $function_call_arg->getAttributes()), new VirtualIdentifier($callable_method_name, $function_call_arg->getAttributes()), $fake_args, $function_call_arg->getAttributes()); $context->vars_in_scope["\$__fake_{$fake_var_discriminator}_offset_var__"] = Type::getMixed(); } $fake_method_return_type = self::executeFakeCall($statements_source, $fake_method_call, $context, $assertions); $function_id_return_type = $fake_method_return_type ?? Type::getMixed(); } else { $fake_function_call = new VirtualFuncCall(new VirtualFullyQualified($mapping_function_id_part, $function_call_arg->getAttributes()), $fake_args, $function_call_arg->getAttributes()); $context->vars_in_scope["\$__fake_{$fake_var_discriminator}_offset_var__"] = Type::getMixed(); $fake_function_return_type = self::executeFakeCall($statements_source, $fake_function_call, $context, $assertions); $function_id_return_type = $fake_function_return_type ?? Type::getMixed(); } } if ($clean_context) { self::cleanContext($context, $fake_var_discriminator); } $fake_var_discriminator = null; $mapping_return_type = Type::combineUnionTypes($function_id_return_type, $mapping_return_type, $codebase); } return $mapping_return_type; } public static function cleanContext(Context $context, int $fake_var_discriminator) : void { foreach ($context->vars_in_scope as $var_in_scope => $_) { if (strpos($var_in_scope, "__fake_{$fake_var_discriminator}_") !== \false) { unset($context->vars_in_scope[$var_in_scope]); } } } } */ public static function getFunctionIds() : array { return ['filter_input']; } public static function getFunctionReturnType(FunctionReturnTypeProviderEvent $event) : ?Union { $statements_analyzer = $event->getStatementsSource(); if (!$statements_analyzer instanceof StatementsAnalyzer) { throw new UnexpectedValueException('Expected StatementsAnalyzer not StatementsSource'); } $arg_names = array_flip(['type', 'var_name', 'filter', 'options']); $call_args = []; foreach ($event->getCallArgs() as $idx => $arg) { if (isset($arg->name)) { $call_args[$arg_names[$arg->name->name]] = $arg; } else { $call_args[$idx] = $arg; } } $function_id = $event->getFunctionId(); $code_location = $event->getCodeLocation(); $codebase = $statements_analyzer->getCodebase(); if (!isset($call_args[0]) || !isset($call_args[1])) { return \Psalm\Internal\Provider\ReturnTypeProvider\FilterUtils::missingFirstArg($codebase); } $first_arg_type = $statements_analyzer->node_data->getType($call_args[0]->value); if ($first_arg_type && !$first_arg_type->isInt()) { if ($codebase->analysis_php_version_id >= 80000) { // throws return Type::getNever(); } // default option won't be used in this case return Type::getNull(); } $filter_int_used = FILTER_DEFAULT; if (isset($call_args[2])) { $filter_int_used = \Psalm\Internal\Provider\ReturnTypeProvider\FilterUtils::getFilterArgValueOrError($call_args[2], $statements_analyzer, $codebase); if (!is_int($filter_int_used)) { return $filter_int_used; } } $options = null; $flags_int_used = FILTER_FLAG_NONE; if (isset($call_args[3])) { $helper = \Psalm\Internal\Provider\ReturnTypeProvider\FilterUtils::getOptionsArgValueOrError($call_args[3], $statements_analyzer, $codebase, $code_location, $function_id, $filter_int_used); if (!is_array($helper)) { return $helper; } $flags_int_used = $helper['flags_int_used']; $options = $helper['options']; } // if we reach this point with callback, the callback is missing if ($filter_int_used === FILTER_CALLBACK) { return \Psalm\Internal\Provider\ReturnTypeProvider\FilterUtils::missingFilterCallbackCallable($function_id, $code_location, $statements_analyzer, $codebase); } [$default, $min_range, $max_range, $has_range, $regexp] = \Psalm\Internal\Provider\ReturnTypeProvider\FilterUtils::getOptions($filter_int_used, $flags_int_used, $options, $statements_analyzer, $code_location, $codebase, $function_id); // only return now, as we still want to report errors above if (!$first_arg_type) { return null; } if (!$first_arg_type->isSingleIntLiteral()) { // eventually complex cases can be handled too, however practically this is irrelevant return null; } if (!$default) { [$fails_type, $not_set_type, $fails_or_not_set_type] = \Psalm\Internal\Provider\ReturnTypeProvider\FilterUtils::getFailsNotSetType($flags_int_used); } else { $fails_type = $default; $not_set_type = $default; $fails_or_not_set_type = $default; } if ($filter_int_used === FILTER_VALIDATE_REGEXP && $regexp === null) { if ($codebase->analysis_php_version_id >= 80000) { // throws return Type::getNever(); } // any "array" flags are ignored by this filter! return $fails_or_not_set_type; } $possible_types = array('$_GET' => INPUT_GET, '$_POST' => INPUT_POST, '$_COOKIE' => INPUT_COOKIE, '$_SERVER' => INPUT_SERVER, '$_ENV' => INPUT_ENV); $first_arg_type_type = $first_arg_type->getSingleIntLiteral(); $global_name = array_search($first_arg_type_type->value, $possible_types); if (!$global_name) { // invalid if ($codebase->analysis_php_version_id >= 80000) { // throws return Type::getNever(); } // the "not set type" is never in an array, even if FILTER_FORCE_ARRAY is set! return $not_set_type; } $second_arg_type = $statements_analyzer->node_data->getType($call_args[1]->value); if (!$second_arg_type) { return null; } if (!$second_arg_type->hasString()) { // for filter_input there can only be string array keys return $not_set_type; } if (!$second_arg_type->isString()) { // already reports an error by default return null; } // in all these cases it can fail or be not set, depending on whether the variable is set or not $redundant_error_return_type = \Psalm\Internal\Provider\ReturnTypeProvider\FilterUtils::checkRedundantFlags($filter_int_used, $flags_int_used, $fails_or_not_set_type, $statements_analyzer, $code_location, $codebase); if ($redundant_error_return_type !== null) { return $redundant_error_return_type; } if (\Psalm\Internal\Provider\ReturnTypeProvider\FilterUtils::hasFlag($flags_int_used, FILTER_REQUIRE_ARRAY) && in_array($first_arg_type_type->value, array(INPUT_COOKIE, INPUT_SERVER, INPUT_ENV), \true)) { // these globals can never be an array return $fails_or_not_set_type; } // @todo eventually this needs to be changed when we fully support filter_has_var $global_type = VariableFetchAnalyzer::getGlobalType($global_name, $codebase->analysis_php_version_id); $input_type = null; if ($global_type->isArray() && $global_type->getArray() instanceof TKeyedArray) { $array_instance = $global_type->getArray(); if ($second_arg_type->isSingleStringLiteral()) { $key = $second_arg_type->getSingleStringLiteral()->value; if (isset($array_instance->properties[$key])) { $input_type = $array_instance->properties[$key]; } } if ($input_type === null) { $input_type = $array_instance->getGenericValueType(); $input_type = $input_type->setPossiblyUndefined(\true); } } elseif ($global_type->isArray() && ($array_atomic = $global_type->getArray()) && $array_atomic instanceof TArray) { [$_, $input_type] = $array_atomic->type_params; $input_type = $input_type->setPossiblyUndefined(\true); } else { // this is impossible throw new UnexpectedValueException('This should not happen'); } return \Psalm\Internal\Provider\ReturnTypeProvider\FilterUtils::getReturnType($filter_int_used, $flags_int_used, $input_type, $fails_type, $not_set_type, $statements_analyzer, $code_location, $codebase, $function_id, $has_range, $min_range, $max_range, $regexp); } } getSource(); $call_args = $event->getCallArgs(); $method_name_lowercase = $event->getMethodNameLowercase(); if (!$statements_source instanceof StatementsAnalyzer || $method_name_lowercase !== 'modify' || !isset($call_args[0])) { return null; } $first_arg = $call_args[0]->value; $first_arg_type = $statements_source->node_data->getType($first_arg); if (!$first_arg_type) { return null; } $has_date_time = \false; $has_false = \false; foreach ($first_arg_type->getAtomicTypes() as $type_part) { if (!$type_part instanceof TLiteralString) { return null; } if (@(new DateTime())->modify($type_part->value) === \false) { $has_false = \true; } else { $has_date_time = \true; } } if ($has_false && !$has_date_time) { return Type::getFalse(); } if ($has_date_time && !$has_false) { return Type::parseString($event->getCalledFqClasslikeName() ?? $event->getFqClasslikeName()); } return null; } } */ public static function getFunctionIds() : array { return ['array_chunk']; } public static function getFunctionReturnType(FunctionReturnTypeProviderEvent $event) : ?Union { $call_args = $event->getCallArgs(); $statements_source = $event->getStatementsSource(); if (count($call_args) >= 2 && ($array_arg_type = $statements_source->getNodeTypeProvider()->getType($call_args[0]->value)) && $array_arg_type->isSingle() && $array_arg_type->hasArray() && ($array_type = ArrayType::infer($array_arg_type->getArray()))) { $preserve_keys = isset($call_args[2]) && ($preserve_keys_arg_type = $statements_source->getNodeTypeProvider()->getType($call_args[2]->value)) && (string) $preserve_keys_arg_type !== 'false'; return Type::getList(new Union([$preserve_keys ? new TNonEmptyArray([$array_type->key, $array_type->value]) : Type::getNonEmptyListAtomic($array_type->value)])); } return new Union([Type::getListAtomic(Type::getArray())]); } } */ public static function getFunctionIds() : array { return ['date', 'gmdate']; } public static function getFunctionReturnType(FunctionReturnTypeProviderEvent $event) : ?Union { $source = $event->getStatementsSource(); if (!$source instanceof StatementsAnalyzer) { return null; } $call_args = $event->getCallArgs(); $format_type = Type::getString(); if (isset($call_args[0])) { $type = $source->node_data->getType($call_args[0]->value); if ($type !== null && $type->isSingleStringLiteral() && is_numeric(date($type->getSingleStringLiteral()->value))) { $format_type = Type::getNumericString(); } } if (!isset($call_args[1])) { return $format_type; } $type = $source->node_data->getType($call_args[1]->value); if ($type !== null && $type->isSingle()) { $atomic_type = array_values($type->getAtomicTypes())[0]; if ($atomic_type instanceof Type\Atomic\TNumeric || $atomic_type instanceof Type\Atomic\TInt || $atomic_type instanceof TLiteralInt || $atomic_type instanceof TLiteralString && is_numeric($atomic_type->value)) { return $format_type; } } return $format_type; } } */ public static function getFunctionIds() : array { return ['mb_internal_encoding']; } public static function getFunctionReturnType(FunctionReturnTypeProviderEvent $event) : ?Union { $call_args = $event->getCallArgs(); if (count($call_args) === 0) { return Type::getString(); } $statements_source = $event->getStatementsSource(); $nodeTypeProvider = $statements_source->getNodeTypeProvider(); $codebase = $statements_source->getCodebase(); $first_arg_type = $nodeTypeProvider->getType($call_args[0]->value); if ($first_arg_type === null) { if ($codebase->analysis_php_version_id >= 80000) { return new Union([new TString(), new TTrue()]); } else { return new Union([new TString(), new TBool()]); } } $has_stringable = \false; $has_tostring = \false; $has_string = \false; $has_null = \false; $has_unknown = \false; foreach ($first_arg_type->getAtomicTypes() as $atomic_type) { if ($atomic_type instanceof Type\Atomic\TNamedObject && $codebase->classlikes->classImplements($atomic_type->value, 'Stringable')) { $has_stringable = \true; continue; } if ($atomic_type instanceof Type\Atomic\TObjectWithProperties && isset($atomic_type->methods['__tostring'])) { $has_tostring = \true; continue; } if ($atomic_type instanceof TString) { $has_string = \true; continue; } if ($atomic_type instanceof TNull) { $has_null = \true; continue; } $has_unknown = \true; } $list_return_atomics = []; if ($has_string || $has_stringable || $has_tostring) { if ($codebase->analysis_php_version_id >= 80000) { $list_return_atomics[] = new TTrue(); } else { $list_return_atomics[] = new TBool(); } } if ($has_null) { if ($codebase->analysis_php_version_id >= 80000) { $list_return_atomics[] = new TString(); } else { $list_return_atomics[] = new TFalse(); } } if ($has_unknown) { if ($codebase->analysis_php_version_id >= 80000) { $list_return_atomics[] = new TNever(); } else { $list_return_atomics[] = new TNull(); } } assert($list_return_atomics !== []); return new Union($list_return_atomics); } } getSource(); $call_args = $event->getCallArgs(); $method_name_lowercase = $event->getMethodNameLowercase(); if ($method_name_lowercase !== 'getcolor') { return null; } if (!$source instanceof StatementsAnalyzer) { return null; } if (!$call_args) { $formats = [0 => \true]; } else { $normalized = $source->node_data->getType($call_args[0]->value) ?? Type::getMixed(); $formats = []; foreach ($normalized->getAtomicTypes() as $t) { if ($t instanceof TLiteralInt && in_array($t->value, [0, 1, 2], \true)) { $formats[$t->value] = \true; } else { $formats[0] = \true; $formats[1] = \true; $formats[2] = \true; } } } $types = []; if (isset($formats[0])) { $types[] = new Union([new TKeyedArray(['r' => Type::getIntRange(0, 255), 'g' => Type::getIntRange(0, 255), 'b' => Type::getIntRange(0, 255), 'a' => Type::getIntRange(0, 1)])]); } if (isset($formats[1])) { $types[] = new Union([new TKeyedArray(['r' => Type::getFloat(), 'g' => Type::getFloat(), 'b' => Type::getFloat(), 'a' => Type::getFloat()])]); } if (isset($formats[2])) { $types[] = new Union([new TKeyedArray(['r' => Type::getIntRange(0, 255), 'g' => Type::getIntRange(0, 255), 'b' => Type::getIntRange(0, 255), 'a' => Type::getIntRange(0, 255)])]); } assert($types !== []); return Type::combineUnionTypeArray($types, $event->getSource()->getCodebase()); } } analysis_php_version_id >= 80000) { // throws return Type::getNever(); } return Type::getNull(); } /** @return int|Union|null */ public static function getFilterArgValueOrError(Arg $filter_arg, StatementsAnalyzer $statements_analyzer, Codebase $codebase) { $filter_arg_type = $statements_analyzer->node_data->getType($filter_arg->value); if (!$filter_arg_type) { return null; } if (!$filter_arg_type->isInt()) { // invalid if ($codebase->analysis_php_version_id >= 80000) { // throws return Type::getNever(); } // will return null independent of FILTER_NULL_ON_FAILURE or default option return Type::getNull(); } if (!$filter_arg_type->isSingleIntLiteral()) { // too complex for now return null; } $all_filters = self::getFilters($codebase); $filter_int_used = $filter_arg_type->getSingleIntLiteral()->value; if (!isset($all_filters[$filter_int_used])) { // inconsistently, this will always return false, even when FILTER_NULL_ON_FAILURE // or a default option is set // and will also not use any default set return Type::getFalse(); } return $filter_int_used; } /** @return array{flags_int_used: int, options: TKeyedArray|null}|Union|null */ public static function getOptionsArgValueOrError(Arg $options_arg, StatementsAnalyzer $statements_analyzer, Codebase $codebase, CodeLocation $code_location, string $function_id, int $filter_int_used) { $options_arg_type = $statements_analyzer->node_data->getType($options_arg->value); if (!$options_arg_type) { return null; } if ($options_arg_type->isArray()) { $return_null = \false; $defaults = array('flags_int_used' => FILTER_FLAG_NONE, 'options' => null); $atomic_type = $options_arg_type->getArray(); if ($atomic_type instanceof TKeyedArray) { $redundant_keys = array_diff(array_keys($atomic_type->properties), array('flags', 'options')); if ($redundant_keys !== array()) { // reported as it's usually an oversight/misunderstanding of how the function works // it's silently ignored by the function though IssueBuffer::maybeAdd(new RedundantFlag('The options array contains unused keys ' . implode(', ', $redundant_keys), $code_location), $statements_analyzer->getSuppressedIssues()); } if (isset($atomic_type->properties['options'])) { if ($filter_int_used === FILTER_CALLBACK) { $only_callables = \true; foreach ($atomic_type->properties['options']->getAtomicTypes() as $option_atomic) { if ($option_atomic->isCallableType()) { continue; } if (CallableTypeComparator::getCallableFromAtomic($codebase, $option_atomic, null, $statements_analyzer)) { continue; } $only_callables = \false; } if ($atomic_type->properties['options']->possibly_undefined) { $only_callables = \false; } if (!$only_callables) { return self::missingFilterCallbackCallable($function_id, $code_location, $statements_analyzer, $codebase); } // eventually can improve it to return the type from the callback // there are no flags or other options/flags, so it can be handled here directly // @todo $return_type = Type::getMixed(); return self::addReturnTaint($statements_analyzer, $code_location, $return_type, $function_id); } if (!$atomic_type->properties['options']->isArray()) { // silently ignored by the function, but this usually indicates a bug IssueBuffer::maybeAdd(new InvalidArgument('The "options" key in ' . $function_id . ' must be a an array', $code_location, $function_id), $statements_analyzer->getSuppressedIssues()); } elseif (($options_array = $atomic_type->properties['options']->getArray()) && $options_array instanceof TKeyedArray) { $defaults['options'] = $options_array; } else { // cannot infer a 100% correct specific return type $return_null = \true; } } if (isset($atomic_type->properties['flags'])) { if ($atomic_type->properties['flags']->isSingleIntLiteral()) { $defaults['flags_int_used'] = $atomic_type->properties['flags']->getSingleIntLiteral()->value; } elseif ($atomic_type->properties['flags']->isInt()) { // cannot infer a 100% correct specific return type $return_null = \true; } else { // silently ignored by the function, but this usually indicates a bug IssueBuffer::maybeAdd(new InvalidArgument('The "flags" key in ' . $function_id . ' must be a valid flag', $code_location, $function_id), $statements_analyzer->getSuppressedIssues()); $defaults['flags_int_used'] = FILTER_FLAG_NONE; } } return $return_null ? null : $defaults; } // cannot infer a 100% correct specific return type return null; } if ($filter_int_used === FILTER_CALLBACK) { return self::missingFilterCallbackCallable($function_id, $code_location, $statements_analyzer, $codebase); } if ($options_arg_type->isSingleIntLiteral()) { return array('flags_int_used' => $options_arg_type->getSingleIntLiteral()->value, 'options' => null); } if ($options_arg_type->isInt()) { // in most cases we cannot infer a 100% correct specific return type though // unless all int are literal // @todo could handle all literal int cases return null; } foreach ($options_arg_type->getAtomicTypes() as $atomic_type) { if ($atomic_type instanceof TArray) { continue; } if ($atomic_type instanceof TInt) { continue; } if ($atomic_type instanceof TFloat) { // ignored continue; } if ($atomic_type instanceof TBool) { // ignored continue; } if ($codebase->analysis_php_version_id >= 80000) { // throws for the invalid type // for the other types it will still work correctly // however "never" is a bottom type // and will be lost, therefore it's better to return it here // to identify hard to find bugs in the code return Type::getNever(); } // before PHP 8, it's ignored but gives a PHP notice } // array|int type which is too complex for now // or any other invalid type return null; } public static function missingFilterCallbackCallable(string $function_id, CodeLocation $code_location, StatementsAnalyzer $statements_analyzer, Codebase $codebase) : Union { IssueBuffer::maybeAdd(new InvalidArgument('The "options" key in ' . $function_id . ' must be a callable for FILTER_CALLBACK', $code_location, $function_id), $statements_analyzer->getSuppressedIssues()); if ($codebase->analysis_php_version_id >= 80000) { // throws return Type::getNever(); } // flags are ignored here return Type::getNull(); } /** @return array{Union, Union, Union} */ public static function getFailsNotSetType(int $flags_int_used) : array { $fails_type = Type::getFalse(); $not_set_type = Type::getNull(); if (self::hasFlag($flags_int_used, FILTER_NULL_ON_FAILURE)) { $fails_type = Type::getNull(); $not_set_type = Type::getFalse(); } $fails_or_not_set_type = new Union([new TNull(), new TFalse()]); return array($fails_type, $not_set_type, $fails_or_not_set_type); } public static function hasFlag(int $flags, int $flag) : bool { if ($flags === 0) { return \false; } if (($flags & $flag) === $flag) { return \true; } return \false; } public static function checkRedundantFlags(int $filter_int_used, int $flags_int_used, Union $fails_type, StatementsAnalyzer $statements_analyzer, CodeLocation $code_location, Codebase $codebase) : ?Union { $all_filters = self::getFilters($codebase); $flags_int_used_rest = $flags_int_used; foreach ($all_filters[$filter_int_used]['flags'] as $flag) { if ($flags_int_used_rest === 0) { break; } if (self::hasFlag($flags_int_used_rest, $flag)) { $flags_int_used_rest = $flags_int_used_rest ^ $flag; } } if ($flags_int_used_rest !== 0) { // invalid flags used // while they are silently ignored // usually it means there's a mistake and the filter doesn't actually do what one expects // as otherwise the flag wouldn't have been provided IssueBuffer::maybeAdd(new RedundantFlag('Not all flags used are supported by the filter used', $code_location), $statements_analyzer->getSuppressedIssues()); } if (self::hasFlag($flags_int_used, FILTER_REQUIRE_ARRAY) && self::hasFlag($flags_int_used, FILTER_FORCE_ARRAY)) { IssueBuffer::maybeAdd(new RedundantFlag('Flag FILTER_FORCE_ARRAY is ignored when using FILTER_REQUIRE_ARRAY', $code_location), $statements_analyzer->getSuppressedIssues()); } if ($filter_int_used === FILTER_VALIDATE_REGEXP && (self::hasFlag($flags_int_used, FILTER_REQUIRE_ARRAY) || self::hasFlag($flags_int_used, FILTER_FORCE_ARRAY) || self::hasFlag($flags_int_used, FILTER_REQUIRE_SCALAR))) { IssueBuffer::maybeAdd(new RedundantFlag('FILTER_VALIDATE_REGEXP will ignore ' . 'FILTER_REQUIRE_ARRAY/FILTER_FORCE_ARRAY/FILTER_REQUIRE_SCALAR ' . 'as it only works on scalar types', $code_location), $statements_analyzer->getSuppressedIssues()); } if (self::hasFlag($flags_int_used, FILTER_FLAG_STRIP_LOW) && self::hasFlag($flags_int_used, FILTER_FLAG_ENCODE_LOW)) { IssueBuffer::maybeAdd(new RedundantFlag('Using flag FILTER_FLAG_ENCODE_LOW is redundant when using FILTER_FLAG_STRIP_LOW', $code_location), $statements_analyzer->getSuppressedIssues()); } if (self::hasFlag($flags_int_used, FILTER_FLAG_STRIP_HIGH) && self::hasFlag($flags_int_used, FILTER_FLAG_ENCODE_HIGH)) { IssueBuffer::maybeAdd(new RedundantFlag('Using flag FILTER_FLAG_ENCODE_HIGH is redundant when using FILTER_FLAG_STRIP_HIGH', $code_location), $statements_analyzer->getSuppressedIssues()); } if (self::hasFlag($flags_int_used, FILTER_REQUIRE_ARRAY) && self::hasFlag($flags_int_used, FILTER_REQUIRE_SCALAR)) { IssueBuffer::maybeAdd(new RedundantFlag('You cannot use FILTER_REQUIRE_ARRAY together with FILTER_REQUIRE_SCALAR flag', $code_location), $statements_analyzer->getSuppressedIssues()); // FILTER_REQUIRE_ARRAY will make PHP ignore FILTER_FORCE_ARRAY return $fails_type; } return null; } /** @return array{Union|null, float|int|null, float|int|null, bool, non-falsy-string|true|null} */ public static function getOptions(int $filter_int_used, int $flags_int_used, ?TKeyedArray $options, StatementsAnalyzer $statements_analyzer, CodeLocation $code_location, Codebase $codebase, string $function_id) : array { $default = null; $min_range = null; $max_range = null; $has_range = \false; $regexp = null; if (!$options) { return [$default, $min_range, $max_range, $has_range, $regexp]; } $all_filters = self::getFilters($codebase); foreach ($options->properties as $option => $option_value) { if (!isset($all_filters[$filter_int_used]['options'][$option])) { IssueBuffer::maybeAdd(new RedundantFlag('The option ' . $option . ' is not valid for the filter used', $code_location), $statements_analyzer->getSuppressedIssues()); continue; } if (!UnionTypeComparator::isContainedBy($codebase, $option_value, $all_filters[$filter_int_used]['options'][$option])) { // silently ignored by the function, but it's a bug in the code // since the filtering/option will not do what you expect IssueBuffer::maybeAdd(new InvalidArgument('The option "' . $option . '" of ' . $function_id . ' expects ' . $all_filters[$filter_int_used]['options'][$option]->getId() . ', but ' . $option_value->getId() . ' provided', $code_location, $function_id), $statements_analyzer->getSuppressedIssues()); continue; } if ($option === 'default') { $default = $option_value; if (self::hasFlag($flags_int_used, FILTER_NULL_ON_FAILURE)) { IssueBuffer::maybeAdd(new RedundantFlag('Redundant flag FILTER_NULL_ON_FAILURE when using the "default" option', $code_location), $statements_analyzer->getSuppressedIssues()); } continue; } // currently only int ranges are supported // must be numeric, otherwise we would have continued above already if ($option === 'min_range' && $option_value->isSingleLiteral()) { if ($filter_int_used === FILTER_VALIDATE_INT) { $min_range = (int) $option_value->getSingleLiteral()->value; } elseif ($filter_int_used === FILTER_VALIDATE_FLOAT) { $min_range = (float) $option_value->getSingleLiteral()->value; } } if ($option === 'max_range' && $option_value->isSingleLiteral()) { if ($filter_int_used === FILTER_VALIDATE_INT) { $max_range = (int) $option_value->getSingleLiteral()->value; } elseif ($filter_int_used === FILTER_VALIDATE_FLOAT) { $max_range = (float) $option_value->getSingleLiteral()->value; } } if (($filter_int_used === FILTER_VALIDATE_INT || $filter_int_used === FILTER_VALIDATE_FLOAT) && ($option === 'min_range' || $option === 'max_range')) { $has_range = \true; } if ($filter_int_used === FILTER_VALIDATE_REGEXP && $option === 'regexp') { if ($option_value->isSingleStringLiteral()) { /** * if it's another type, we would have reported an error above already * @var non-falsy-string $regexp */ $regexp = $option_value->getSingleStringLiteral()->value; } elseif ($option_value->isString()) { $regexp = \true; } } } return [$default, $min_range, $max_range, $has_range, $regexp]; } /** * @param float|int|null $min_range * @param float|int|null $max_range */ protected static function isRangeValid($min_range, $max_range, StatementsAnalyzer $statements_analyzer, CodeLocation $code_location, string $function_id) : bool { if ($min_range !== null && $max_range !== null && $min_range > $max_range) { IssueBuffer::maybeAdd(new InvalidArgument('min_range cannot be larger than max_range', $code_location, $function_id), $statements_analyzer->getSuppressedIssues()); return \false; } return \true; } /** * can't split this because the switch is complex since there are too many possibilities * * @psalm-suppress ComplexMethod * @param Union|null $not_set_type null if undefined filtered variable will return $fails_type * @param float|int|null $min_range * @param float|int|null $max_range * @param non-falsy-string|true|null $regexp */ public static function getReturnType(int $filter_int_used, int $flags_int_used, Union $input_type, Union $fails_type, ?Union $not_set_type, StatementsAnalyzer $statements_analyzer, CodeLocation $code_location, Codebase $codebase, string $function_id, bool $has_range, $min_range, $max_range, $regexp, bool $in_array_recursion = \false) : Union { // if we are inside a recursion of e.g. array // it will never fail or change the type, so we can immediately return if ($in_array_recursion && $input_type->isNever()) { return $input_type; } $from_array = []; // will only handle arrays correctly if either flag is set, otherwise always error // regexp doesn't work on arrays if ((self::hasFlag($flags_int_used, FILTER_FORCE_ARRAY) || self::hasFlag($flags_int_used, FILTER_REQUIRE_ARRAY)) && $filter_int_used !== FILTER_VALIDATE_REGEXP && !self::hasFlag($flags_int_used, FILTER_REQUIRE_SCALAR)) { foreach ($input_type->getAtomicTypes() as $key => $atomic_type) { if ($atomic_type instanceof TList) { $atomic_type = $atomic_type->getKeyedArray(); } if ($atomic_type instanceof TKeyedArray) { $input_type = $input_type->getBuilder(); $input_type->removeType($key); $input_type = $input_type->freeze(); $new = []; foreach ($atomic_type->properties as $k => $property) { if ($property->isNever()) { $new[$k] = $property; continue; } $new[$k] = self::getReturnType( $filter_int_used, $flags_int_used, $property, $fails_type, // irrelevant in nested elements null, $statements_analyzer, $code_location, $codebase, $function_id, $has_range, $min_range, $max_range, $regexp, \true ); } // false positive error in psalm when we loop over a non-empty array if ($new === array()) { throw new UnexpectedValueException('This is impossible'); } $fallback_params = null; if ($atomic_type->fallback_params) { [$keys_union, $values_union] = $atomic_type->fallback_params; $values_union = self::getReturnType( $filter_int_used, $flags_int_used, $values_union, $fails_type, // irrelevant in nested elements null, $statements_analyzer, $code_location, $codebase, $function_id, $has_range, $min_range, $max_range, $regexp, \true ); $fallback_params = [$keys_union, $values_union]; } $from_array[] = new TKeyedArray($new, $atomic_type->class_strings, $fallback_params, $atomic_type->is_list); continue; } if ($atomic_type instanceof TArray) { $input_type = $input_type->getBuilder(); $input_type->removeType($key); $input_type = $input_type->freeze(); [$keys_union, $values_union] = $atomic_type->type_params; $values_union = self::getReturnType( $filter_int_used, $flags_int_used, $values_union, $fails_type, // irrelevant in nested elements null, $statements_analyzer, $code_location, $codebase, $function_id, $has_range, $min_range, $max_range, $regexp, \true ); if ($atomic_type instanceof TNonEmptyArray) { $from_array[] = new TNonEmptyArray([$keys_union, $values_union]); } else { $from_array[] = new TArray([$keys_union, $values_union]); } continue; } // can be an array too if ($atomic_type instanceof TMixed) { $from_array[] = new TArray([new Union([new TArrayKey()]), new Union([new TMixed()])]); } } } $can_fail = \false; $filter_types = array(); switch ($filter_int_used) { case FILTER_VALIDATE_FLOAT: if (!self::isRangeValid($min_range, $max_range, $statements_analyzer, $code_location, $function_id)) { $can_fail = \true; break; } foreach ($input_type->getAtomicTypes() as $atomic_type) { if ($atomic_type instanceof TLiteralFloat) { if ($min_range !== null && $min_range > $atomic_type->value) { $can_fail = \true; continue; } if ($max_range !== null && $max_range < $atomic_type->value) { $can_fail = \true; continue; } if ($min_range !== null || $max_range !== null || $has_range === \false) { $filter_types[] = $atomic_type; continue; } // we don't know what the min/max of the range are // and it might be out of the range too // float ranges aren't supported yet $filter_types[] = new TFloat(); } elseif ($atomic_type instanceof TFloat) { if ($has_range === \false) { $filter_types[] = $atomic_type; continue; } // float ranges aren't supported yet $filter_types[] = new TFloat(); } if ($atomic_type instanceof TLiteralInt) { if ($min_range !== null && $min_range > $atomic_type->value) { $can_fail = \true; continue; } if ($max_range !== null && $max_range < $atomic_type->value) { $can_fail = \true; continue; } if ($min_range !== null || $max_range !== null || $has_range === \false) { $filter_types[] = new TLiteralFloat((float) $atomic_type->value); continue; } // we don't know what the min/max of the range are // and it might be out of the range too $filter_types[] = new TFloat(); } elseif ($atomic_type instanceof TInt) { $filter_types[] = new TFloat(); if ($has_range === \false) { continue; } } if ($atomic_type instanceof TLiteralString) { if (($string_to_float = filter_var($atomic_type->value, FILTER_VALIDATE_FLOAT)) === \false) { $can_fail = \true; continue; } if ($min_range !== null && $min_range > $string_to_float) { $can_fail = \true; continue; } if ($max_range !== null && $max_range < $string_to_float) { $can_fail = \true; continue; } if ($min_range !== null || $max_range !== null || $has_range === \false) { $filter_types[] = new TLiteralFloat($string_to_float); continue; } // we don't know what the min/max of the range are // and it might be out of the range too $filter_types[] = new TFloat(); } elseif ($atomic_type instanceof TString) { $filter_types[] = new TFloat(); } if ($atomic_type instanceof TBool) { if ($min_range !== null && $min_range > 1) { $can_fail = \true; continue; } if ($max_range !== null && $max_range < 1) { $can_fail = \true; continue; } if ($atomic_type instanceof TFalse) { $can_fail = \true; continue; } if ($min_range !== null || $max_range !== null || $has_range === \false) { $filter_types[] = new TLiteralFloat(1.0); if ($atomic_type instanceof TTrue) { continue; } } // we don't know what the min/max of the range are // and it might be out of the range too $filter_types[] = new TFloat(); } // only these specific classes, not any class that extends either // to avoid matching already better handled cases from above, e.g. float is numeric and scalar if ($atomic_type instanceof TMixed || get_class($atomic_type) === TNumeric::class || get_class($atomic_type) === TScalar::class) { $filter_types[] = new TFloat(); } $can_fail = \true; } break; case FILTER_VALIDATE_BOOLEAN: foreach ($input_type->getAtomicTypes() as $atomic_type) { if ($atomic_type instanceof TBool) { $filter_types[] = $atomic_type; continue; } if ($atomic_type instanceof TLiteralInt && $atomic_type->value === 1 || $atomic_type instanceof TLiteralFloat && $atomic_type->value === 1.0 || $atomic_type instanceof TLiteralString && in_array(strtolower($atomic_type->value), ['1', 'true', 'on', 'yes'], \true)) { $filter_types[] = new TTrue(); continue; } if (self::hasFlag($flags_int_used, FILTER_NULL_ON_FAILURE) && ($atomic_type instanceof TLiteralInt && $atomic_type->value === 0 || $atomic_type instanceof TLiteralFloat && $atomic_type->value === 0.0 || $atomic_type instanceof TLiteralString && in_array(strtolower($atomic_type->value), ['0', 'false', 'off', 'no', ''], \true))) { $filter_types[] = new TFalse(); continue; } if ($atomic_type instanceof TLiteralInt || $atomic_type instanceof TLiteralFloat || $atomic_type instanceof TLiteralString) { // all other literals will fail $can_fail = \true; continue; } if ($atomic_type instanceof TMixed || $atomic_type instanceof TString || $atomic_type instanceof TInt || $atomic_type instanceof TFloat || $atomic_type instanceof TNumeric || $atomic_type instanceof TScalar) { $filter_types[] = new TBool(); } $can_fail = \true; } break; case FILTER_VALIDATE_INT: if (!self::isRangeValid($min_range, $max_range, $statements_analyzer, $code_location, $function_id)) { $can_fail = \true; break; } $min_range = $min_range !== null ? (int) $min_range : null; $max_range = $max_range !== null ? (int) $max_range : null; if ($min_range !== null || $max_range !== null) { $int_type = new TIntRange($min_range, $max_range); } else { $int_type = new TInt(); } foreach ($input_type->getAtomicTypes() as $atomic_type) { if ($atomic_type instanceof TLiteralInt) { if ($min_range !== null && $min_range > $atomic_type->value) { $can_fail = \true; continue; } if ($max_range !== null && $max_range < $atomic_type->value) { $can_fail = \true; continue; } if ($min_range !== null || $max_range !== null || $has_range === \false) { $filter_types[] = $atomic_type; continue; } // we don't know what the min/max of the range are // and it might be out of the range too $filter_types[] = new TInt(); } elseif ($atomic_type instanceof TInt) { if ($has_range === \false) { $filter_types[] = $atomic_type; continue; } $filter_types[] = $int_type; } if ($atomic_type instanceof TLiteralFloat) { if ((float) (int) $atomic_type->value !== $atomic_type->value) { $can_fail = \true; continue; } if ($min_range !== null && $min_range > $atomic_type->value) { $can_fail = \true; continue; } if ($max_range !== null && $max_range < $atomic_type->value) { $can_fail = \true; continue; } if ($min_range !== null || $max_range !== null || $has_range === \false) { $filter_types[] = new TLiteralInt((int) $atomic_type->value); continue; } // we don't know what the min/max of the range are // and it might be out of the range too $filter_types[] = $int_type; } elseif ($atomic_type instanceof TFloat) { $filter_types[] = $int_type; } if ($atomic_type instanceof TLiteralString) { if (($string_to_int = filter_var($atomic_type->value, FILTER_VALIDATE_INT)) === \false) { $can_fail = \true; continue; } if ($min_range !== null && $min_range > $string_to_int) { $can_fail = \true; continue; } if ($max_range !== null && $max_range < $string_to_int) { $can_fail = \true; continue; } if ($min_range !== null || $max_range !== null || $has_range === \false) { $filter_types[] = new TLiteralInt($string_to_int); continue; } // we don't know what the min/max of the range are // and it might be out of the range too $filter_types[] = $int_type; } elseif ($atomic_type instanceof TString) { $filter_types[] = $int_type; } if ($atomic_type instanceof TBool) { if ($min_range !== null && $min_range > 1) { $can_fail = \true; continue; } if ($max_range !== null && $max_range < 1) { $can_fail = \true; continue; } if ($atomic_type instanceof TFalse) { $can_fail = \true; continue; } if ($min_range !== null || $max_range !== null || $has_range === \false) { $filter_types[] = new TLiteralInt(1); if ($atomic_type instanceof TTrue) { continue; } } // we don't know what the min/max of the range are // and it might be out of the range too $filter_types[] = $int_type; } if ($atomic_type instanceof TMixed || get_class($atomic_type) === TNumeric::class || get_class($atomic_type) === TScalar::class) { $filter_types[] = $int_type; } $can_fail = \true; } break; case FILTER_VALIDATE_IP: case FILTER_VALIDATE_MAC: case FILTER_VALIDATE_URL: case FILTER_VALIDATE_EMAIL: foreach ($input_type->getAtomicTypes() as $atomic_type) { if ($atomic_type instanceof TNumericString) { $can_fail = \true; continue; } if ($atomic_type instanceof TNonFalsyString) { $filter_types[] = $atomic_type; } elseif ($atomic_type instanceof TString) { $filter_types[] = new TNonFalsyString(); } elseif ($atomic_type instanceof TMixed || $atomic_type instanceof TScalar) { $filter_types[] = new TNonFalsyString(); } $can_fail = \true; } break; case FILTER_VALIDATE_REGEXP: // the regexp key is mandatory for this filter // it will only fail if the value exists, therefore it's after the checks above // this must be (and is) handled BEFORE calling this function though // since PHP 8+ throws instead of returning the fails case if ($regexp === null) { $can_fail = \true; break; } // invalid regex if ($regexp !== \true && @preg_match($regexp, 'placeholder') === \false) { $can_fail = \true; break; } foreach ($input_type->getAtomicTypes() as $atomic_type) { if ($atomic_type instanceof TString || $atomic_type instanceof TInt || $atomic_type instanceof TFloat || $atomic_type instanceof TNumeric || $atomic_type instanceof TScalar || $atomic_type instanceof TMixed) { $filter_types[] = new TString(); } $can_fail = \true; } break; case FILTER_VALIDATE_DOMAIN: if (self::hasFlag($flags_int_used, FILTER_FLAG_HOSTNAME)) { $string_type = new TNonEmptyString(); } else { $string_type = new TString(); } foreach ($input_type->getAtomicTypes() as $atomic_type) { if ($atomic_type instanceof TNonEmptyString) { $filter_types[] = $atomic_type; } elseif ($atomic_type instanceof TString) { if (self::hasFlag($flags_int_used, FILTER_FLAG_HOSTNAME)) { $filter_types[] = $string_type; } else { $filter_types[] = $atomic_type; } } elseif ($atomic_type instanceof TMixed || $atomic_type instanceof TInt || $atomic_type instanceof TFloat || $atomic_type instanceof TScalar) { $filter_types[] = $string_type; } $can_fail = \true; } break; case FILTER_SANITIZE_EMAIL: case FILTER_SANITIZE_URL: foreach ($input_type->getAtomicTypes() as $atomic_type) { if ($atomic_type instanceof TNumericString) { $filter_types[] = $atomic_type; continue; } if ($atomic_type instanceof TString) { $filter_types[] = new TString(); continue; } if ($atomic_type instanceof TFloat || $atomic_type instanceof TInt || $atomic_type instanceof TNumeric) { $filter_types[] = new TNumericString(); continue; } if ($atomic_type instanceof TTrue) { $filter_types[] = Type::getAtomicStringFromLiteral('1'); continue; } if ($atomic_type instanceof TFalse) { $filter_types[] = Type::getAtomicStringFromLiteral(''); continue; } if ($atomic_type instanceof TBool) { $filter_types[] = Type::getAtomicStringFromLiteral('1'); $filter_types[] = Type::getAtomicStringFromLiteral(''); continue; } if ($atomic_type instanceof TMixed || $atomic_type instanceof TScalar) { $filter_types[] = new TString(); } $can_fail = \true; } break; case FILTER_SANITIZE_ENCODED: case FILTER_SANITIZE_ADD_SLASHES: case 521: // 8.0.0 FILTER_SANITIZE_MAGIC_QUOTES has been removed. case FILTER_SANITIZE_SPECIAL_CHARS: case FILTER_SANITIZE_FULL_SPECIAL_CHARS: case FILTER_DEFAULT: foreach ($input_type->getAtomicTypes() as $atomic_type) { if ($filter_int_used === FILTER_DEFAULT && $flags_int_used === 0 && $atomic_type instanceof TString) { $filter_types[] = $atomic_type; continue; } if ($atomic_type instanceof TNumericString) { $filter_types[] = $atomic_type; continue; } if (in_array($filter_int_used, [FILTER_SANITIZE_ENCODED, FILTER_SANITIZE_SPECIAL_CHARS, FILTER_DEFAULT], \true) && $atomic_type instanceof TNonEmptyString && (self::hasFlag($flags_int_used, FILTER_FLAG_STRIP_LOW) || self::hasFlag($flags_int_used, FILTER_FLAG_STRIP_HIGH) || self::hasFlag($flags_int_used, FILTER_FLAG_STRIP_BACKTICK))) { $filter_types[] = new TString(); continue; } if ($atomic_type instanceof TNonFalsyString) { $filter_types[] = new TNonFalsyString(); continue; } if ($atomic_type instanceof TNonEmptyString) { $filter_types[] = new TNonEmptyString(); continue; } if ($atomic_type instanceof TString) { $filter_types[] = new TString(); continue; } if ($atomic_type instanceof TFloat || $atomic_type instanceof TInt || $atomic_type instanceof TNumeric) { $filter_types[] = new TNumericString(); continue; } if ($atomic_type instanceof TTrue) { $filter_types[] = Type::getAtomicStringFromLiteral('1'); continue; } if ($atomic_type instanceof TFalse) { $filter_types[] = Type::getAtomicStringFromLiteral(''); continue; } if ($atomic_type instanceof TBool) { $filter_types[] = Type::getAtomicStringFromLiteral('1'); $filter_types[] = Type::getAtomicStringFromLiteral(''); continue; } if ($atomic_type instanceof TMixed || $atomic_type instanceof TScalar) { $filter_types[] = new TString(); } $can_fail = \true; } break; case 513: // 8.1.0 FILTER_SANITIZE_STRING and FILTER_SANITIZE_STRIPPED (alias) have been deprecated. foreach ($input_type->getAtomicTypes() as $atomic_type) { if ($atomic_type instanceof TBool || $atomic_type instanceof TString || $atomic_type instanceof TInt || $atomic_type instanceof TFloat || $atomic_type instanceof TNumeric) { // only basic checking since it's deprecated anyway and not worth the time $filter_types[] = new TString(); continue; } if ($atomic_type instanceof TMixed || $atomic_type instanceof TScalar) { $filter_types[] = new TString(); } $can_fail = \true; } break; case FILTER_SANITIZE_NUMBER_INT: case FILTER_SANITIZE_NUMBER_FLOAT: foreach ($input_type->getAtomicTypes() as $atomic_type) { if ($atomic_type instanceof TLiteralString || $atomic_type instanceof TLiteralInt || $atomic_type instanceof TLiteralFloat) { /** @var string|false $literal */ $literal = filter_var($atomic_type->value, $filter_int_used); if ($literal === \false) { $can_fail = \true; } else { $filter_types[] = Type::getAtomicStringFromLiteral($literal); } continue; } if ($atomic_type instanceof TFloat || $atomic_type instanceof TNumericString || $atomic_type instanceof TInt || $atomic_type instanceof TNumeric) { $filter_types[] = new TNumericString(); continue; } if ($atomic_type instanceof TString) { $filter_types[] = new TNumericString(); // for numeric-string it won't collapse since https://github.com/vimeo/psalm/pull/10459 // therefore we can add both $filter_types[] = Type::getAtomicStringFromLiteral(''); continue; } if ($atomic_type instanceof TTrue) { $filter_types[] = Type::getAtomicStringFromLiteral('1'); continue; } if ($atomic_type instanceof TFalse) { $filter_types[] = Type::getAtomicStringFromLiteral(''); continue; } if ($atomic_type instanceof TBool) { $filter_types[] = Type::getAtomicStringFromLiteral('1'); $filter_types[] = Type::getAtomicStringFromLiteral(''); continue; } if ($atomic_type instanceof TMixed || $atomic_type instanceof TScalar) { $filter_types[] = new TNumericString(); $filter_types[] = Type::getAtomicStringFromLiteral(''); } $can_fail = \true; } break; } if ($input_type->hasMixed()) { // can always fail if we have mixed // only for redundancy in case there's a mistake in the switch above $can_fail = \true; } // if an array is required, ignore all types we created from non-array on first level if (!$in_array_recursion && self::hasFlag($flags_int_used, FILTER_REQUIRE_ARRAY)) { $filter_types = array(); } $return_type = $fails_type; if ($filter_types !== array() && ($can_fail === \true || !$in_array_recursion && !$not_set_type && $input_type->possibly_undefined)) { $return_type = Type::combineUnionTypes($return_type, TypeCombiner::combine($filter_types, $codebase), $codebase); } elseif ($filter_types !== array()) { $return_type = TypeCombiner::combine($filter_types, $codebase); } if (!$in_array_recursion && !self::hasFlag($flags_int_used, FILTER_REQUIRE_ARRAY) && self::hasFlag($flags_int_used, FILTER_FORCE_ARRAY)) { $return_type = new Union([new TKeyedArray([$return_type], null, null, \true)]); } if ($from_array !== array()) { $from_array_union = TypeCombiner::combine($from_array, $codebase); $return_type = Type::combineUnionTypes($return_type, $from_array_union, $codebase); } if ($in_array_recursion && $input_type->possibly_undefined) { $return_type = $return_type->setPossiblyUndefined(\true); } elseif (!$in_array_recursion && $not_set_type && $input_type->possibly_undefined) { // in case of PHP CLI it will always fail for all filter_input even when they're set // to fix this we would have to add support for environments in Context // e.g. if php_sapi_name() === 'cli' $return_type = Type::combineUnionTypes( $return_type, // the not set type is not coerced into an array when FILTER_FORCE_ARRAY is used $not_set_type, $codebase ); } if (!$in_array_recursion) { $return_type = self::addReturnTaint($statements_analyzer, $code_location, $return_type, $function_id); } return $return_type; } private static function addReturnTaint(StatementsAnalyzer $statements_analyzer, CodeLocation $code_location, Union $return_type, string $function_id) : Union { if ($statements_analyzer->data_flow_graph && !in_array('TaintedInput', $statements_analyzer->getSuppressedIssues())) { $function_return_sink = DataFlowNode::getForMethodReturn($function_id, $function_id, null, $code_location); $statements_analyzer->data_flow_graph->addNode($function_return_sink); $function_param_sink = DataFlowNode::getForMethodArgument($function_id, $function_id, 0, null, $code_location); $statements_analyzer->data_flow_graph->addNode($function_param_sink); $statements_analyzer->data_flow_graph->addPath($function_param_sink, $function_return_sink, 'arg'); $return_type = $return_type->setParentNodes([$function_return_sink->id => $function_return_sink]); } return $return_type; } /** @return array, options: array}> */ public static function getFilters(Codebase $codebase) : array { $general_filter_flags = array(FILTER_REQUIRE_SCALAR, FILTER_REQUIRE_ARRAY, FILTER_FORCE_ARRAY, FILTER_FLAG_NONE); // https://www.php.net/manual/en/filter.filters.sanitize.php $sanitize_filters = array(FILTER_SANITIZE_EMAIL => array('flags' => array(), 'options' => array()), FILTER_SANITIZE_ENCODED => array('flags' => array(FILTER_FLAG_STRIP_LOW, FILTER_FLAG_STRIP_HIGH, FILTER_FLAG_STRIP_BACKTICK, FILTER_FLAG_ENCODE_LOW, FILTER_FLAG_ENCODE_HIGH), 'options' => array()), FILTER_SANITIZE_NUMBER_FLOAT => array('flags' => array(FILTER_FLAG_ALLOW_FRACTION, FILTER_FLAG_ALLOW_THOUSAND, FILTER_FLAG_ALLOW_SCIENTIFIC), 'options' => array()), FILTER_SANITIZE_NUMBER_INT => array('flags' => array(), 'options' => array()), FILTER_SANITIZE_SPECIAL_CHARS => array('flags' => array(FILTER_FLAG_STRIP_LOW, FILTER_FLAG_STRIP_HIGH, FILTER_FLAG_STRIP_BACKTICK, FILTER_FLAG_ENCODE_HIGH), 'options' => array()), FILTER_SANITIZE_FULL_SPECIAL_CHARS => array('flags' => array(FILTER_FLAG_NO_ENCODE_QUOTES), 'options' => array()), FILTER_SANITIZE_URL => array('flags' => array(), 'options' => array()), FILTER_UNSAFE_RAW => array('flags' => array(FILTER_FLAG_STRIP_LOW, FILTER_FLAG_STRIP_HIGH, FILTER_FLAG_STRIP_BACKTICK, FILTER_FLAG_ENCODE_LOW, FILTER_FLAG_ENCODE_HIGH, FILTER_FLAG_ENCODE_AMP), 'options' => array())); if ($codebase->analysis_php_version_id <= 70300) { // FILTER_SANITIZE_MAGIC_QUOTES $sanitize_filters[521] = array('flags' => array(), 'options' => array()); } if ($codebase->analysis_php_version_id <= 80100) { // FILTER_SANITIZE_STRING $sanitize_filters[513] = array('flags' => array(FILTER_FLAG_NO_ENCODE_QUOTES, FILTER_FLAG_STRIP_LOW, FILTER_FLAG_STRIP_HIGH, FILTER_FLAG_STRIP_BACKTICK, FILTER_FLAG_ENCODE_LOW, FILTER_FLAG_ENCODE_HIGH, FILTER_FLAG_ENCODE_AMP), 'options' => array()); } if ($codebase->analysis_php_version_id >= 70300) { // was added as a replacement for FILTER_SANITIZE_MAGIC_QUOTES $sanitize_filters[FILTER_SANITIZE_ADD_SLASHES] = array('flags' => array(), 'options' => array()); } foreach ($sanitize_filters as $filter_int => $filter_data) { $sanitize_filters[$filter_int]['flags'] = array_merge($filter_data['flags'], $general_filter_flags); } // https://www.php.net/manual/en/filter.filters.validate.php // validation filters all match bitmask 0x100 // all support FILTER_NULL_ON_FAILURE flag https://www.php.net/manual/en/filter.filters.flags.php $general_filter_flags_validate = array_merge($general_filter_flags, array(FILTER_NULL_ON_FAILURE)); $validate_filters = array(FILTER_VALIDATE_BOOLEAN => array('flags' => array(), 'options' => array()), FILTER_VALIDATE_EMAIL => array('flags' => array(FILTER_FLAG_EMAIL_UNICODE), 'options' => array()), FILTER_VALIDATE_FLOAT => array('flags' => array(FILTER_FLAG_ALLOW_THOUSAND), 'options' => array('decimal' => new Union([Type::getAtomicStringFromLiteral('.'), Type::getAtomicStringFromLiteral(',')]))), FILTER_VALIDATE_INT => array('flags' => array(FILTER_FLAG_ALLOW_OCTAL, FILTER_FLAG_ALLOW_HEX), 'options' => array('min_range' => Type::getNumeric(), 'max_range' => Type::getNumeric())), FILTER_VALIDATE_IP => array('flags' => array(FILTER_FLAG_IPV4, FILTER_FLAG_IPV6, FILTER_FLAG_NO_PRIV_RANGE, FILTER_FLAG_NO_RES_RANGE), 'options' => array()), FILTER_VALIDATE_MAC => array('flags' => array(), 'options' => array()), FILTER_VALIDATE_REGEXP => array('flags' => array(), 'options' => array('regexp' => Type::getNonFalsyString())), FILTER_VALIDATE_URL => array('flags' => array(FILTER_FLAG_PATH_REQUIRED, FILTER_FLAG_QUERY_REQUIRED), 'options' => array())); if ($codebase->analysis_php_version_id >= 70400) { $validate_filters[FILTER_VALIDATE_FLOAT]['options']['min_range'] = Type::getNumeric(); $validate_filters[FILTER_VALIDATE_FLOAT]['options']['max_range'] = Type::getNumeric(); } if ($codebase->analysis_php_version_id < 80000) { // phpcs:ignore SlevomatCodingStandard.Numbers.RequireNumericLiteralSeparator.RequiredNumericLiteralSeparator $validate_filters[FILTER_VALIDATE_URL]['flags'][] = 65536; // FILTER_FLAG_SCHEME_REQUIRED // phpcs:ignore SlevomatCodingStandard.Numbers.RequireNumericLiteralSeparator.RequiredNumericLiteralSeparator $validate_filters[FILTER_VALIDATE_URL]['flags'][] = 131072; // FILTER_FLAG_HOST_REQUIRED } if ($codebase->analysis_php_version_id >= 80200) { // phpcs:ignore SlevomatCodingStandard.Numbers.RequireNumericLiteralSeparator.RequiredNumericLiteralSeparator $validate_filters[FILTER_VALIDATE_IP]['flags'][] = 268435456; // FILTER_FLAG_GLOBAL_RANGE } if ($codebase->analysis_php_version_id >= 70000) { $validate_filters[FILTER_VALIDATE_DOMAIN] = array('flags' => array(FILTER_FLAG_HOSTNAME), 'options' => array()); } foreach ($validate_filters as $filter_int => $filter_data) { $validate_filters[$filter_int]['flags'] = array_merge($filter_data['flags'], $general_filter_flags_validate); $default_options = array('default' => Type::getMixed()); $validate_filters[$filter_int]['options'] = array_merge($filter_data['options'], $default_options); } // https://www.php.net/manual/en/filter.filters.misc.php $other_filters = array(FILTER_CALLBACK => array( // the docs say that all flags are ignored // however this seems to be incorrect https://github.com/php/doc-en/issues/2708 // however they can only be used in the options array, not as a param directly 'flags' => $general_filter_flags_validate, // the options array is required for this filter // and must be a valid callback instead of an array like in other cases 'options' => array(), )); return $sanitize_filters + $validate_filters + $other_filters; } } */ public static function getFunctionIds() : array { return ['strtr']; } public static function getFunctionReturnType(FunctionReturnTypeProviderEvent $event) : Union { $statements_source = $event->getStatementsSource(); $call_args = $event->getCallArgs(); $function_id = $event->getFunctionId(); $code_location = $event->getCodeLocation(); if (!$statements_source instanceof StatementsAnalyzer) { throw new UnexpectedValueException(); } $type = Type::getString(); if ($statements_source->data_flow_graph && !in_array('TaintedInput', $statements_source->getSuppressedIssues())) { $function_return_sink = DataFlowNode::getForMethodReturn($function_id, $function_id, null, $code_location); $statements_source->data_flow_graph->addNode($function_return_sink); foreach ($call_args as $i => $_) { $function_param_sink = DataFlowNode::getForMethodArgument($function_id, $function_id, $i, null, $code_location); $statements_source->data_flow_graph->addNode($function_param_sink); $statements_source->data_flow_graph->addPath($function_param_sink, $function_return_sink, 'arg'); } return $type->setParentNodes([$function_return_sink->id => $function_return_sink]); } return $type; } } */ public static function getFunctionIds() : array { return ['array_filter']; } public static function getFunctionReturnType(FunctionReturnTypeProviderEvent $event) : Union { $statements_source = $event->getStatementsSource(); $call_args = $event->getCallArgs(); $context = $event->getContext(); $code_location = $event->getCodeLocation(); if (!$statements_source instanceof StatementsAnalyzer || !$call_args) { return Type::getMixed(); } $fallback = new TArray([Type::getArrayKey(), Type::getMixed()]); $array_arg = $call_args[0]->value ?? null; if (!$array_arg) { $first_arg_array = $fallback; } else { $first_arg_type = $statements_source->node_data->getType($array_arg); if (!$first_arg_type || $first_arg_type->isMixed()) { $first_arg_array = $fallback; } else { $first_arg_array = $first_arg_type->hasType('array') && ($array_atomic_type = $first_arg_type->getArray()) && ($array_atomic_type instanceof TArray || $array_atomic_type instanceof TKeyedArray) ? $array_atomic_type : $fallback; } } if ($first_arg_array instanceof TArray) { $inner_type = $first_arg_array->type_params[1]; $key_type = $first_arg_array->type_params[0]; } else { $inner_type = $first_arg_array->getGenericValueType(); $key_type = $first_arg_array->getGenericKeyType(); if (!isset($call_args[1]) && $first_arg_array->fallback_params === null) { $had_one = count($first_arg_array->properties) === 1; $new_properties = array_filter(array_map(static function ($keyed_type) use($statements_source, $context) { $prev_keyed_type = $keyed_type; $keyed_type = AssertionReconciler::reconcile(new Truthy(), $keyed_type, '', $statements_source, $context->inside_loop, [], null, $statements_source->getSuppressedIssues()); return $keyed_type->setPossiblyUndefined(!$prev_keyed_type->isAlwaysTruthy()); }, $first_arg_array->properties), static fn($keyed_type) => !$keyed_type->isNever()); if (!$new_properties) { return Type::getEmptyArray(); } return new Union([new TKeyedArray($new_properties, null, $first_arg_array->fallback_params, $first_arg_array->is_list && $had_one)]); } } if (!isset($call_args[1])) { $inner_type = AssertionReconciler::reconcile(new Truthy(), $inner_type, '', $statements_source, $context->inside_loop, [], null, $statements_source->getSuppressedIssues()); if ($first_arg_array instanceof TKeyedArray && $first_arg_array->is_list && $key_type->isSingleIntLiteral() && $key_type->getSingleIntLiteral()->value === 0) { return Type::getList($inner_type); } if ($key_type->getLiteralStrings()) { $key_type = $key_type->getBuilder()->addType(new TString())->freeze(); } if ($key_type->getLiteralInts()) { $key_type = $key_type->getBuilder()->addType(new TInt())->freeze(); } if ($inner_type->isUnionEmpty()) { return Type::getEmptyArray(); } return new Union([new TArray([$key_type, $inner_type])]); } if (!isset($call_args[2])) { $function_call_arg = $call_args[1]; $callable_extended_var_id = ExpressionIdentifier::getExtendedVarId($function_call_arg->value, null, $statements_source); $mapping_function_ids = array(); if ($callable_extended_var_id) { $possibly_function_ids = $context->vars_in_scope[$callable_extended_var_id] ?? null; // @todo for array callables if ($possibly_function_ids && $possibly_function_ids->allStringLiterals()) { foreach ($possibly_function_ids->getLiteralStrings() as $atomic) { $mapping_function_ids[] = $atomic->value; } } } if ($function_call_arg->value instanceof PhpParser\Node\Scalar\String_ || $function_call_arg->value instanceof PhpParser\Node\Expr\Array_ || $function_call_arg->value instanceof PhpParser\Node\Expr\BinaryOp\Concat || $mapping_function_ids !== array()) { if ($mapping_function_ids === array()) { $mapping_function_ids = CallAnalyzer::getFunctionIdsFromCallableArg($statements_source, $function_call_arg->value); } if ($array_arg && $mapping_function_ids) { $assertions = []; $fake_var_discriminator = mt_rand(); \Psalm\Internal\Provider\ReturnTypeProvider\ArrayMapReturnTypeProvider::getReturnTypeFromMappingIds($statements_source, $mapping_function_ids, $context, $function_call_arg, array_slice($call_args, 0, 1), $assertions, $fake_var_discriminator); $extended_var_id = ExpressionIdentifier::getExtendedVarId($array_arg, null, $statements_source); $assertion_id = $extended_var_id . "[\$__fake_{$fake_var_discriminator}_offset_var__]"; if (isset($assertions[$assertion_id])) { $changed_var_ids = []; $assertions = ['$inner_type' => $assertions[$assertion_id]]; [$reconciled_types, $_] = Reconciler::reconcileKeyedTypes($assertions, $assertions, ['$inner_type' => $inner_type], [], $changed_var_ids, ['$inner_type' => \true], $statements_source, $statements_source->getTemplateTypeMap() ?: [], \false, new CodeLocation($statements_source, $function_call_arg->value)); if (isset($reconciled_types['$inner_type'])) { $inner_type = $reconciled_types['$inner_type']; } } \Psalm\Internal\Provider\ReturnTypeProvider\ArrayMapReturnTypeProvider::cleanContext($context, $fake_var_discriminator); } } elseif (($function_call_arg->value instanceof PhpParser\Node\Expr\Closure || $function_call_arg->value instanceof PhpParser\Node\Expr\ArrowFunction) && ($second_arg_type = $statements_source->node_data->getType($function_call_arg->value)) && ($closure_types = $second_arg_type->getClosureTypes())) { $closure_atomic_type = reset($closure_types); $closure_return_type = $closure_atomic_type->return_type ?: Type::getMixed(); if ($closure_return_type->isVoid()) { IssueBuffer::maybeAdd(new InvalidReturnType('No return type could be found in the closure passed to array_filter', $code_location), $statements_source->getSuppressedIssues()); return Type::getArray(); } /** @var list */ $function_call_stmts = $function_call_arg->value->getStmts(); if (count($function_call_stmts) === 1 && count($function_call_arg->value->params)) { $first_param = $function_call_arg->value->params[0]; $stmt = $function_call_stmts[0]; if ($first_param->variadic === \false && $first_param->var instanceof PhpParser\Node\Expr\Variable && is_string($first_param->var->name) && $stmt instanceof PhpParser\Node\Stmt\Return_ && $stmt->expr) { $codebase = $statements_source->getCodebase(); $cond_object_id = spl_object_id($stmt->expr); try { $filter_clauses = FormulaGenerator::getFormula($cond_object_id, $cond_object_id, $stmt->expr, $context->self, $statements_source, $codebase); } catch (ComplicatedExpressionException $e) { $filter_clauses = []; } $assertions = Algebra::getTruthsFromFormula($filter_clauses, $cond_object_id); if (isset($assertions['$' . $first_param->var->name])) { $changed_var_ids = []; $assertions = ['$inner_type' => $assertions['$' . $first_param->var->name]]; [$reconciled_types, $_] = Reconciler::reconcileKeyedTypes($assertions, $assertions, ['$inner_type' => $inner_type], [], $changed_var_ids, ['$inner_type' => \true], $statements_source, $statements_source->getTemplateTypeMap() ?: [], \false, new CodeLocation($statements_source, $stmt)); if (isset($reconciled_types['$inner_type'])) { $inner_type = $reconciled_types['$inner_type']; } } } } } return new Union([new TArray([$key_type, $inner_type])]); } if ($inner_type->isUnionEmpty()) { return Type::getEmptyArray(); } return new Union([new TArray([$key_type, $inner_type])]); } } */ public static function getFunctionIds() : array { return ['array_pad']; } public static function getFunctionReturnType(FunctionReturnTypeProviderEvent $event) : ?Union { $statements_source = $event->getStatementsSource(); $call_args = $event->getCallArgs(); $type_provider = $statements_source->getNodeTypeProvider(); if (count($call_args) >= 3 && ($array_arg_type = $type_provider->getType($call_args[0]->value)) && ($size_arg_type = $type_provider->getType($call_args[1]->value)) && ($value_arg_type = $type_provider->getType($call_args[2]->value)) && $array_arg_type->isSingle() && $array_arg_type->hasArray() && ($array_type = ArrayType::infer($array_arg_type->getArray()))) { $codebase = $statements_source->getCodebase(); $key_type = Type::combineUnionTypes($array_type->key, Type::getInt(), $codebase); $value_type = Type::combineUnionTypes($array_type->value, $value_arg_type, $codebase); $can_return_empty = !$size_arg_type->isSingleIntLiteral() || $size_arg_type->getSingleIntLiteral()->value === 0; return new Union([$array_type->is_list ? $can_return_empty ? Type::getListAtomic($value_type) : Type::getNonEmptyListAtomic($value_type) : ($can_return_empty ? new TArray([$key_type, $value_type]) : new TNonEmptyArray([$key_type, $value_type]))]); } return Type::getArray(); } } */ public static function getFunctionIds() : array { return ['get_class_methods']; } public static function getFunctionReturnType(FunctionReturnTypeProviderEvent $event) : ?Union { $statements_source = $event->getStatementsSource(); $call_args = $event->getCallArgs(); if (!$statements_source instanceof StatementsAnalyzer || !$call_args) { return Type::getMixed(); } if (($first_arg_type = $statements_source->node_data->getType($call_args[0]->value)) && ($first_arg_type->hasObjectType() || $first_arg_type->hasString())) { return Type::parseString('array'); } return null; } } */ public static function getFunctionIds() : array { return ['array_reduce']; } public static function getFunctionReturnType(FunctionReturnTypeProviderEvent $event) : Union { $statements_source = $event->getStatementsSource(); $call_args = $event->getCallArgs(); $context = $event->getContext(); if (!$statements_source instanceof StatementsAnalyzer) { return Type::getMixed(); } if (!isset($call_args[0]) || !isset($call_args[1])) { return Type::getMixed(); } $codebase = $statements_source->getCodebase(); $array_arg = $call_args[0]->value; $function_call_arg = $call_args[1]->value; $array_arg_type = $statements_source->node_data->getType($array_arg); $function_call_arg_type = $statements_source->node_data->getType($function_call_arg); if (!$array_arg_type || !$function_call_arg_type) { return Type::getMixed(); } $array_arg_types = $array_arg_type->getAtomicTypes(); $array_arg_atomic_type = null; if (isset($array_arg_types['array']) && ($array_arg_types['array'] instanceof TArray || $array_arg_types['array'] instanceof TList || $array_arg_types['array'] instanceof TKeyedArray)) { $array_arg_atomic_type = $array_arg_types['array']; if ($array_arg_atomic_type instanceof TList) { $array_arg_atomic_type = $array_arg_atomic_type->getKeyedArray(); } if ($array_arg_atomic_type instanceof TKeyedArray) { $array_arg_atomic_type = $array_arg_atomic_type->getGenericArrayType(); } } if (!isset($call_args[2])) { $reduce_return_type = new Union([new TNull()], ['ignore_nullable_issues' => \true]); } else { $reduce_return_type = $statements_source->node_data->getType($call_args[2]->value); if (!$reduce_return_type) { return Type::getMixed(); } if ($reduce_return_type->hasMixed()) { return Type::getMixed(); } } $initial_type = $reduce_return_type; $closure_types = $function_call_arg_type->getClosureTypes() ?: $function_call_arg_type->getCallableTypes(); if ($closure_types) { $closure_atomic_type = reset($closure_types); $closure_return_type = $closure_atomic_type->return_type ?: Type::getMixed(); if ($closure_return_type->isVoid()) { $closure_return_type = Type::getNull(); } $reduce_return_type = Type::combineUnionTypes($closure_return_type, $reduce_return_type); if ($closure_atomic_type->params !== null) { if (count($closure_atomic_type->params) < 1) { IssueBuffer::maybeAdd(new InvalidArgument('The closure passed to array_reduce at least one parameter', new CodeLocation($statements_source, $function_call_arg)), $statements_source->getSuppressedIssues()); return Type::getMixed(); } $carry_param = $closure_atomic_type->params[0]; $item_param = $closure_atomic_type->params[1] ?? null; if ($carry_param->type && (!UnionTypeComparator::isContainedBy($codebase, $initial_type, $carry_param->type) || !$reduce_return_type->hasMixed() && !UnionTypeComparator::isContainedBy($codebase, $reduce_return_type, $carry_param->type))) { IssueBuffer::maybeAdd(new InvalidArgument('The first param of the closure passed to array_reduce must take ' . $reduce_return_type . ' but only accepts ' . $carry_param->type, $carry_param->type_location ?: new CodeLocation($statements_source, $function_call_arg)), $statements_source->getSuppressedIssues()); return Type::getMixed(); } if ($item_param && $item_param->type && $array_arg_atomic_type && !$array_arg_atomic_type->type_params[1]->hasMixed() && !UnionTypeComparator::isContainedBy($codebase, $array_arg_atomic_type->type_params[1], $item_param->type)) { IssueBuffer::maybeAdd(new InvalidArgument('The second param of the closure passed to array_reduce must take ' . $array_arg_atomic_type->type_params[1] . ' but only accepts ' . $item_param->type, $item_param->type_location ?: new CodeLocation($statements_source, $function_call_arg)), $statements_source->getSuppressedIssues()); return Type::getMixed(); } } return $reduce_return_type; } if ($function_call_arg instanceof PhpParser\Node\Scalar\String_ || $function_call_arg instanceof PhpParser\Node\Expr\Array_ || $function_call_arg instanceof PhpParser\Node\Expr\BinaryOp\Concat) { $mapping_function_ids = CallAnalyzer::getFunctionIdsFromCallableArg($statements_source, $function_call_arg); $call_map = InternalCallMapHandler::getCallMap(); foreach ($mapping_function_ids as $mapping_function_id) { $mapping_function_id_parts = explode('&', $mapping_function_id); $part_match_found = \false; foreach ($mapping_function_id_parts as $mapping_function_id_part) { if (isset($call_map[$mapping_function_id_part][0])) { if ($call_map[$mapping_function_id_part][0]) { $mapped_function_return = Type::parseString($call_map[$mapping_function_id_part][0]); $reduce_return_type = Type::combineUnionTypes($reduce_return_type, $mapped_function_return); $part_match_found = \true; } } elseif ($mapping_function_id_part) { if (strpos($mapping_function_id_part, '::') !== \false) { if ($mapping_function_id_part[0] === '$') { $mapping_function_id_part = substr($mapping_function_id_part, 1); } [$callable_fq_class_name, $method_name] = explode('::', $mapping_function_id_part); if (in_array($callable_fq_class_name, ['self', 'static'], \true)) { $callable_fq_class_name = $statements_source->getFQCLN(); if ($callable_fq_class_name === null) { continue; } } if ($callable_fq_class_name === 'parent') { continue; } $method_id = new MethodIdentifier($callable_fq_class_name, strtolower($method_name)); if (!$codebase->methods->methodExists($method_id, !$context->collect_initializations && !$context->collect_mutations ? $context->calling_method_id : null, $codebase->collect_locations ? new CodeLocation($statements_source, $function_call_arg) : null, null, $statements_source->getFilePath())) { continue; } $part_match_found = \true; $self_class = 'self'; $return_type = $codebase->methods->getMethodReturnType($method_id, $self_class) ?? Type::getMixed(); } else { if (!$codebase->functions->functionExists($statements_source, strtolower($mapping_function_id_part))) { return Type::getMixed(); } $part_match_found = \true; $function_storage = $codebase->functions->getStorage($statements_source, strtolower($mapping_function_id_part)); $return_type = $function_storage->return_type ?: Type::getMixed(); } $reduce_return_type = Type::combineUnionTypes($reduce_return_type, $return_type); } } if ($part_match_found === \false) { return Type::getMixed(); } } return $reduce_return_type; } return Type::getMixed(); } } */ public static function getFunctionIds() : array { return ['str_replace', 'str_ireplace']; } public static function getFunctionReturnType(FunctionReturnTypeProviderEvent $event) : ?Union { $statements_source = $event->getStatementsSource(); $call_args = $event->getCallArgs(); $function_id = $event->getFunctionId(); if (!$statements_source instanceof StatementsAnalyzer || count($call_args) < 3) { // use the defaults, it will already report an error for the invalid params return null; } if ($subject_type = $statements_source->node_data->getType($call_args[2]->value)) { if (!$subject_type->isSingleStringLiteral()) { return null; } $first_arg = $statements_source->node_data->getType($call_args[0]->value); $second_arg = $statements_source->node_data->getType($call_args[1]->value); if ($first_arg && $second_arg && $first_arg->isSingleStringLiteral() && $second_arg->isSingleStringLiteral()) { /** * @var string $replaced_string */ $replaced_string = call_user_func($function_id, $first_arg->getSingleStringLiteral()->value, $second_arg->getSingleStringLiteral()->value, $subject_type->getSingleStringLiteral()->value); return Type::getString($replaced_string); } } return null; } } isSingle()) { $atomics = $first_arg_type->getAtomicTypes(); $object_type = reset($atomics); if ($object_type instanceof Atomic\TEnumCase) { $properties = ['name' => new Union([Type::getAtomicStringFromLiteral($object_type->case_name)])]; $codebase = $statements_source->getCodebase(); $enum_classlike_storage = $codebase->classlike_storage_provider->get($object_type->value); if ($enum_classlike_storage->enum_type === null) { return new TKeyedArray($properties); } $enum_case_storage = $enum_classlike_storage->enum_cases[$object_type->case_name]; $case_value = $enum_case_storage->getValue($statements_source->getCodebase()->classlikes); if (is_int($case_value)) { $properties['value'] = new Union([new Atomic\TLiteralInt($case_value)]); } elseif (is_string($case_value)) { $properties['value'] = new Union([Type::getAtomicStringFromLiteral($case_value)]); } return new TKeyedArray($properties); } if ($object_type instanceof TObjectWithProperties) { if ([] === $object_type->properties) { return self::$fallback; } return new TKeyedArray($object_type->properties); } if ($object_type instanceof TNamedObject) { if (strtolower($object_type->value) === strtolower(stdClass::class)) { return self::$fallback; } $codebase = $statements_source->getCodebase(); $class_storage = $codebase->classlikes->getStorageFor($object_type->value); if (null === $class_storage) { return self::$fallback; } if ([] === $class_storage->appearing_property_ids) { if ($class_storage->final) { return Type::getEmptyArrayAtomic(); } return self::$fallback; } $properties = []; foreach ($class_storage->appearing_property_ids as $name => $property_id) { if (ClassAnalyzer::checkPropertyVisibility($property_id, $context, $statements_source, $location, $statements_source->getSuppressedIssues(), \false) === \true) { $property_type = $codebase->properties->getPropertyType($property_id, \false, $statements_source, $context); if (!$property_type) { continue; } $property_type = $object_type instanceof TGenericObject ? AtomicPropertyFetchAnalyzer::localizePropertyType($codebase, $property_type, $object_type, $class_storage, $class_storage) : $property_type; $properties[$name] = $property_type; } } if ([] === $properties) { if ($class_storage->final) { return Type::getEmptyArrayAtomic(); } return self::$fallback; } return new TKeyedArray($properties, null, $class_storage->final || $class_storage->name === UnitEnum::class || $codebase->interfaceExtends($class_storage->name, UnitEnum::class) ? null : [Type::getString(), Type::getMixed()]); } } return self::$fallback; } public static function getFunctionReturnType(FunctionReturnTypeProviderEvent $event) : ?Union { $statements_source = $event->getStatementsSource(); $call_args = $event->getCallArgs(); if (!$statements_source instanceof StatementsAnalyzer || !$call_args) { return Type::getMixed(); } if (($first_arg_type = $statements_source->node_data->getType($call_args[0]->value)) && $first_arg_type->isObjectType()) { return new Union([self::getGetObjectVarsReturnType($first_arg_type, $statements_source, $event->getContext(), $event->getCodeLocation())]); } return null; } } message = $message; } } data = $data; } } \true, 'jit' => 1205, 'jit_buffer_size' => 512 * 1024 * 1024, 'optimization_level' => '0x7FFEBFFF', 'preload' => '', 'log_verbosity_level' => 0]; private bool $required = \false; /** * @var string[] */ private array $disabled_extensions = []; public function disableExtension(string $disabled_extension) : void { $this->disabled_extensions[] = $disabled_extension; } /** @param list $disable_extensions */ public function disableExtensions(array $disable_extensions) : void { $this->disabled_extensions = array_merge($this->disabled_extensions, $disable_extensions); } /** * No type hint to allow xdebug-handler v1 and v2 usage * * @param bool $default * @phpcsSuppress SlevomatCodingStandard.TypeHints.ParameterTypeHint.MissingNativeTypeHint */ protected function requiresRestart($default) : bool { $this->required = (bool) array_filter($this->disabled_extensions, static fn(string $extension): bool => extension_loaded($extension)); $opcache_loaded = extension_loaded('opcache') || extension_loaded('Zend OPcache'); if (PHP_VERSION_ID >= 80000 && $opcache_loaded) { // restart to enable JIT if it's not configured in the optimal way $opcache_settings = ['enable_cli' => in_array(ini_get('opcache.enable_cli'), ['1', 'true', \true, 1]), 'jit' => (int) ini_get('opcache.jit'), 'log_verbosity_level' => (int) ini_get('opcache.log_verbosity_level'), 'optimization_level' => (string) ini_get('opcache.optimization_level'), 'preload' => (string) ini_get('opcache.preload'), 'jit_buffer_size' => self::toBytes(ini_get('opcache.jit_buffer_size'))]; foreach (self::REQUIRED_OPCACHE_SETTINGS as $ini_name => $required_value) { if ($opcache_settings[$ini_name] !== $required_value) { return \true; } } } // opcache.save_comments is required for json mapper (used in language server) to work if ($opcache_loaded && in_array(ini_get('opcache.save_comments'), ['0', 'false', 0, \false])) { return \true; } return $default || $this->required; } private static function toBytes(string $value) : int { if (strlen($value) === 0) { return 0; } $unit = strtolower($value[strlen($value) - 1]); if (in_array($unit, ['g', 'm', 'k'], \true)) { $value = (int) $value; } else { $unit = ''; $value = (int) $value; } switch ($unit) { case 'g': $value *= 1024; // no break case 'm': $value *= 1024; // no break case 'k': $value *= 1024; } return $value; } /** * No type hint to allow xdebug-handler v1 and v2 usage * * @param non-empty-list $command * @phpcsSuppress SlevomatCodingStandard.TypeHints.ParameterTypeHint.MissingNativeTypeHint */ protected function restart($command) : void { if ($this->required && $this->tmpIni) { $regex = '/^\\s*(extension\\s*=.*(' . implode('|', $this->disabled_extensions) . ').*)$/mi'; $content = file_get_contents($this->tmpIni); $content = preg_replace($regex, ';$1', $content); file_put_contents($this->tmpIni, $content); } $additional_options = []; $opcache_loaded = extension_loaded('opcache') || extension_loaded('Zend OPcache'); // executed in the parent process (before restart) // if it wasn't loaded then we apparently don't have opcache installed and there's no point trying // to tweak it // If we're running on 7.4 there's no JIT available if (PHP_VERSION_ID >= 80000 && $opcache_loaded) { $additional_options = ['-dopcache.enable_cli=true', '-dopcache.jit_buffer_size=512M', '-dopcache.jit=1205', '-dopcache.optimization_level=0x7FFEBFFF', '-dopcache.preload=', '-dopcache.log_verbosity_level=0']; } if ($opcache_loaded) { $additional_options[] = '-dopcache.save_comments=1'; } array_splice($command, 1, 0, $additional_options); assert(count($command) > 1); parent::restart($command); } } > $process_task_data_iterator * An array of task data items to be divided up among the * workers. The size of this is the number of forked processes. * @phpcsSuppress SlevomatCodingStandard.TypeHints.ParameterTypeHint * @param Closure $startup_closure * A closure to execute upon starting a child * @param Closure(int, mixed):mixed $task_closure * A method to execute on each task data. * This closure must return an array (to be gathered). * @param Closure():mixed $shutdown_closure * A closure to execute upon shutting down a child * @param Closure(mixed $data):void $task_done_closure * A closure to execute when a task is done * @psalm-suppress MixedAssignment */ public function __construct(Config $config, array $process_task_data_iterator, Closure $startup_closure, Closure $task_closure, Closure $shutdown_closure, ?Closure $task_done_closure = null) { $pool_size = count($process_task_data_iterator); $this->task_done_closure = $task_done_closure; $this->config = $config; assert($pool_size > 1, 'The pool size must be >= 2 to use the fork pool.'); if (!extension_loaded('pcntl') || !extension_loaded('posix')) { echo 'The pcntl & posix extensions must be loaded in order for Psalm to be able to use multiple processes.' . PHP_EOL; exit(1); } $disabled_functions = array_map('trim', explode(',', ini_get('disable_functions'))); if (in_array('pcntl_fork', $disabled_functions)) { echo "pcntl_fork() is disabled by php configuration (disable_functions directive).\n" . "Please enable it or run Psalm single-threaded with --threads=1 cli switch.\n"; exit(1); } // We'll keep track of if this is the parent process // so that we can tell who will be doing the waiting $is_parent = \false; $sockets = []; // Fork as many times as requested to get the given // pool size for ($proc_id = 0; $proc_id < $pool_size; ++$proc_id) { // Create an IPC socket pair. $sockets = stream_socket_pair(STREAM_PF_UNIX, STREAM_SOCK_STREAM, STREAM_IPPROTO_IP); if (!$sockets) { error_log('unable to create stream socket pair'); exit(self::EXIT_FAILURE); } // Fork if (($pid = pcntl_fork()) < 0) { error_log(posix_strerror(posix_get_last_error())); exit(self::EXIT_FAILURE); } // Parent if ($pid > 0) { $is_parent = \true; $this->child_pid_list[] = $pid; $this->read_streams[] = self::streamForParent($sockets); continue; } // Child if ($pid === 0) { $is_parent = \false; break; } } // If we're the parent, return if ($is_parent) { return; } // Get the write stream for the child. $write_stream = self::streamForChild($sockets); // Execute anything the children wanted to execute upon // starting up $startup_closure(); // Get the work for this process $task_data_iterator = array_values($process_task_data_iterator)[$proc_id]; $task_done_buffer = ''; try { foreach ($task_data_iterator as $i => $task_data) { $task_result = $task_closure($i, $task_data); $task_done_message = new \Psalm\Internal\Fork\ForkTaskDoneMessage($task_result); if ($this->config->use_igbinary) { $encoded_message = base64_encode(igbinary_serialize($task_done_message)); } else { $encoded_message = base64_encode(serialize($task_done_message)); } $serialized_message = $task_done_buffer . $encoded_message . "\n"; if (strlen($serialized_message) > 200) { $bytes_written = @fwrite($write_stream, $serialized_message); if (strlen($serialized_message) !== $bytes_written) { $task_done_buffer = substr($serialized_message, $bytes_written); } else { $task_done_buffer = ''; } } else { $task_done_buffer = $serialized_message; } } // Execute each child's shutdown closure before // exiting the process $results = $shutdown_closure(); // Serialize this child's produced results and send them to the parent. $process_done_message = new \Psalm\Internal\Fork\ForkProcessDoneMessage($results ?: []); } catch (Throwable $t) { // This can happen when developing Psalm from source without running `composer update`, // or because of rare bugs in Psalm. $process_done_message = new \Psalm\Internal\Fork\ForkProcessErrorMessage(get_class($t) . ' ' . $t->getMessage() . "\n" . "Emitted in " . $t->getFile() . ":" . $t->getLine() . "\n" . "Stack trace in the forked worker:\n" . $t->getTraceAsString()); } if ($this->config->use_igbinary) { $encoded_message = base64_encode(igbinary_serialize($process_done_message)); } else { $encoded_message = base64_encode(serialize($process_done_message)); } $serialized_message = $task_done_buffer . $encoded_message . "\n"; $bytes_to_write = strlen($serialized_message); $bytes_written = 0; while ($bytes_written < $bytes_to_write && !feof($write_stream)) { // attempt to write the remaining unsent part $bytes_written += @fwrite($write_stream, substr($serialized_message, $bytes_written)); if ($bytes_written < $bytes_to_write) { // wait a bit usleep(500000); } } fclose($write_stream); // Children exit after completing their work exit(self::EXIT_SUCCESS); } /** * Prepare the socket pair to be used in a parent process and * return the stream the parent will use to read results. * * @param resource[] $sockets the socket pair for IPC * @return resource */ private static function streamForParent(array $sockets) { [$for_read, $for_write] = $sockets; // The parent will not use the write channel, so it // must be closed to prevent deadlock. fclose($for_write); // stream_select will be used to read multiple streams, so these // must be set to non-blocking mode. if (!stream_set_blocking($for_read, \false)) { error_log('unable to set read stream to non-blocking'); exit(self::EXIT_FAILURE); } return $for_read; } /** * Prepare the socket pair to be used in a child process and return * the stream the child will use to write results. * * @param resource[] $sockets the socket pair for IPC * @return resource */ private static function streamForChild(array $sockets) { [$for_read, $for_write] = $sockets; // The while will not use the read channel, so it must // be closed to prevent deadlock. fclose($for_read); return $for_write; } private function killAllChildren() : void { foreach ($this->child_pid_list as $child_pid) { /** * SIGTERM does not exist on windows * * @psalm-suppress UnusedPsalmSuppress * @psalm-suppress UndefinedConstant * @psalm-suppress MixedArgument */ posix_kill($child_pid, SIGTERM); } } /** * Read the results that each child process has serialized on their write streams. * The results are returned in an array, one for each worker. The order of the results * is not maintained. * * @psalm-suppress MixedAssignment * @return list */ private function readResultsFromChildren() : array { // Create an array of all active streams, indexed by // resource id. $streams = []; foreach ($this->read_streams as $stream) { $streams[(int) $stream] = $stream; } // Create an array for the content received on each stream, // indexed by resource id. $content = array_fill_keys(array_keys($streams), ''); $terminationMessages = []; $done = []; // Read the data off of all the stream. while (count($streams) > 0) { $needs_read = array_values($streams); $needs_write = null; $needs_except = null; // Wait for data on at least one stream. $num = @stream_select($needs_read, $needs_write, $needs_except, null); if ($num === \false) { $err = error_get_last(); // stream_select returns false when the `select` system call is interrupted by an incoming signal if (isset($err['message']) && stripos($err['message'], 'interrupted system call') === \false) { error_log('unable to select on read stream'); exit(self::EXIT_FAILURE); } continue; } // For each stream that was ready, read the content. foreach ($needs_read as $file) { $buffer = fread($file, 1024); if ($buffer !== \false) { $content[(int) $file] .= $buffer; } if (strpos($buffer, "\n") !== \false) { $serialized_messages = explode("\n", $content[(int) $file]); $content[(int) $file] = array_pop($serialized_messages); foreach ($serialized_messages as $serialized_message) { if ($this->config->use_igbinary) { $message = igbinary_unserialize(base64_decode($serialized_message, \true)); } else { $message = unserialize(base64_decode($serialized_message, \true)); } if ($message instanceof \Psalm\Internal\Fork\ForkProcessDoneMessage) { $terminationMessages[] = $message->data; } elseif ($message instanceof \Psalm\Internal\Fork\ForkTaskDoneMessage) { $done[(int) $file] = \true; if ($this->task_done_closure !== null) { ($this->task_done_closure)($message->data); } } elseif ($message instanceof \Psalm\Internal\Fork\ForkProcessErrorMessage) { $this->killAllChildren(); throw new Exception($message->message); } else { $this->killAllChildren(); throw new Exception('Child should return ForkMessage - response type=' . gettype($message)); } } } // If the stream has closed, stop trying to select on it. if (feof($file)) { if ($content[(int) $file] !== '' || !isset($done[(int) $file])) { $this->killAllChildren(); throw new Exception('Child did not send full message before closing the connection'); } fclose($file); unset($streams[(int) $file]); } } } return $terminationMessages; } /** * Wait for all child processes to complete * * @return list */ public function wait() : array { $ignore_return_code = \false; try { // Read all the streams from child processes into an array. $content = $this->readResultsFromChildren(); } catch (Throwable $e) { // If children were killed because one of them threw an exception we don't care about return codes. $ignore_return_code = \true; // PHP guarantees finally is run even after throwing throw $e; } finally { // Wait for all children to return foreach ($this->child_pid_list as $child_pid) { $process_lookup = posix_kill($child_pid, 0); $status = 0; if ($process_lookup) { /** * SIGALRM does not exist on windows * * @psalm-suppress UnusedPsalmSuppress * @psalm-suppress UndefinedConstant * @psalm-suppress MixedArgument */ posix_kill($child_pid, SIGALRM); if (pcntl_waitpid($child_pid, $status) < 0) { error_log(posix_strerror(posix_get_last_error())); } } // Check to see if the child died a graceful death if (!$ignore_return_code && pcntl_wifsignaled($status)) { $return_code = pcntl_wexitstatus($status); $term_sig = pcntl_wtermsig($status); /** * SIGALRM does not exist on windows * * @psalm-suppress UnusedPsalmSuppress * @psalm-suppress UndefinedConstant */ if ($term_sig !== SIGALRM) { $this->killAllChildren(); throw new Exception("Child terminated with return code {$return_code} and signal {$term_sig}"); } } } } return $content; } } data = $data; } } $argv */ public static function install(array $argv = array()) : void { self::$args = implode(' ', $argv); self::setErrorReporting(); self::installErrorHandler(); self::installExceptionHandler(); } /** * @template T * @param callable():T $f * @return T */ public static function runWithExceptionsSuppressed(callable $f) { try { self::$exceptions_enabled = \false; return $f(); } finally { self::$exceptions_enabled = \true; } } /** @psalm-suppress UnusedConstructor added to prevent instantiations */ private function __construct() { } private static function setErrorReporting() : void { error_reporting(E_ALL | E_STRICT); ini_set('display_errors', '1'); } private static function installErrorHandler() : void { set_error_handler(static function (int $error_code, string $error_message, string $error_filename = 'unknown', int $error_line = -1) : bool { if (\Psalm\Internal\ErrorHandler::$exceptions_enabled && $error_code & error_reporting()) { throw new RuntimeException('PHP Error: ' . $error_message . ' in ' . $error_filename . ':' . $error_line . ' for command with CLI args "' . \Psalm\Internal\ErrorHandler::$args . '"', $error_code); } // let PHP handle suppressed errors how it sees fit return \false; }); } private static function installExceptionHandler() : void { /** * If there is an uncaught exception, * then print more of the backtrace than is done by default to stderr, * then exit with a non-zero exit code to indicate failure. */ set_exception_handler(static function (Throwable $throwable) : void { fwrite(STDERR, "Uncaught {$throwable}\n"); $version = defined('PSALM_VERSION') ? \PSALM_VERSION : '(unknown version)'; fwrite(STDERR, "(Psalm {$version} crashed due to an uncaught Throwable)\n"); exit(1); }); } } project_root = $project_root; $this->psalm_root = $psalm_root; } public function __invoke(string $current_dir, ?string $config_file_path = null) : \Psalm\Internal\PluginManager\PluginList { try { $config_file = new \Psalm\Internal\PluginManager\ConfigFile($current_dir, $config_file_path); } catch (RuntimeException $exception) { $config_file = null; } $composer_lock = new \Psalm\Internal\PluginManager\ComposerLock($this->findLockFiles()); return new \Psalm\Internal\PluginManager\PluginList($config_file, $composer_lock); } /** @return non-empty-array */ private function findLockFiles() : array { // use cases // 1. plugins are installed into project vendors - composer.lock is PROJECT_ROOT/composer.lock // 2. plugins are installed into separate composer environment (either global or bamarni-bin) // - composer.lock is PSALM_ROOT/../../../composer.lock // 3. plugins are installed into psalm vendors - composer.lock is PSALM_ROOT/composer.lock // 4. none of the above - use stub (empty virtual composer.lock) if ($this->psalm_root === $this->project_root) { // managing plugins for psalm itself $composer_lock_filenames = [Composer::getLockFilePath($this->psalm_root)]; } else { $composer_lock_filenames = [Composer::getLockFilePath($this->project_root), Composer::getLockFilePath($this->psalm_root . '/../../..'), Composer::getLockFilePath($this->psalm_root)]; } $composer_lock_filenames = array_filter($composer_lock_filenames, 'is_readable'); if (empty($composer_lock_filenames)) { $stub_composer_lock = (object) ['packages' => [], 'packages-dev' => []]; $composer_lock_filenames[] = 'data:application/json,' . urlencode(json_encode($stub_composer_lock, JSON_THROW_ON_ERROR)); } return $composer_lock_filenames; } } current_dir = $current_dir; if ($explicit_path) { $this->path = $explicit_path; } else { $path = Config::locateConfigFile($current_dir); if (!$path) { throw new RuntimeException('Cannot find Psalm config'); } $this->path = $path; } } public function getConfig() : Config { return Config::loadFromXMLFile($this->path, $this->current_dir); } public function removePlugin(string $plugin_class) : void { $config_xml = $this->readXml(); /** @var DOMElement */ $psalm_root = $config_xml->getElementsByTagName('psalm')[0]; $plugins_elements = $psalm_root->getElementsByTagName('plugins'); if (!$plugins_elements->length) { // no plugins, nothing to remove return; } /** @var DOMElement */ $plugins_element = $plugins_elements->item(0); $plugin_elements = $plugins_element->getElementsByTagName('pluginClass'); foreach ($plugin_elements as $plugin_element) { if ($plugin_element->getAttribute('class') === $plugin_class) { $plugins_element->removeChild($plugin_element); break; } } if (!$plugin_elements->length) { // avoid breaking old psalm binaries, whose schema did not allow empty plugins $psalm_root->removeChild($plugins_element); } $this->saveXml($config_xml); } public function addPlugin(string $plugin_class) : void { $config_xml = $this->readXml(); /** @var DOMElement */ $psalm_root = $config_xml->getElementsByTagName('psalm')->item(0); $plugins_elements = $psalm_root->getElementsByTagName('plugins'); if (!$plugins_elements->length) { $plugins_element = $config_xml->createElement('plugins'); if ($plugins_element) { $psalm_root->appendChild($plugins_element); } } else { /** @var DOMElement */ $plugins_element = $plugins_elements->item(0); } $plugin_class_element = $config_xml->createElement('pluginClass'); if ($plugin_class_element) { $plugin_class_element->setAttribute('xmlns', Config::CONFIG_NAMESPACE); $plugin_class_element->setAttribute('class', $plugin_class); if ($plugins_element) { $plugins_element->appendChild($plugin_class_element); } } $this->saveXml($config_xml); } private function readXml() : DOMDocument { $doc = new DOMDocument(); $file_contents = file_get_contents($this->path); if (($tag_start = strpos($file_contents, '', $tag_start + 1); if ($tag_end !== \false) { $this->psalm_tag_end_pos = $tag_end; $this->psalm_header = substr($file_contents, 0, $tag_end); } } assert($file_contents !== ''); $doc->loadXML($file_contents); return $doc; } private function saveXml(DOMDocument $config_xml) : void { $new_file_contents = $config_xml->saveXML($config_xml); if (($tag_start = strpos($new_file_contents, '', $tag_start + 1); if ($tag_end !== \false && $new_file_contents[$tag_end - 1] !== '/' && $this->psalm_tag_end_pos && $this->psalm_header) { $new_file_contents = $this->psalm_header . substr($new_file_contents, $tag_end); } } $result = file_put_contents($this->path, $new_file_contents); if ($result === \false) { throw new RuntimeException(sprintf('Unable to save xml to %s', $this->path)); } } } file_names = $file_names; } /** * @param mixed $package * @psalm-assert-if-true array{ * name: string, * extra: array{psalm: array{pluginClass: string}} * } $package * @psalm-pure */ public function isPlugin($package) : bool { return is_array($package) && isset($package['name'], $package['extra']['psalm']['pluginClass']) && is_string($package['name']) && is_array($package['extra']) && is_array($package['extra']['psalm']) && is_string($package['extra']['psalm']['pluginClass']); } /** * @return array [packageName => pluginClass, ...] */ public function getPlugins() : array { $pluginPackages = $this->getAllPluginPackages(); $ret = []; foreach ($pluginPackages as $package) { $ret[$package['name']] = $package['extra']['psalm']['pluginClass']; } return $ret; } private function read(string $file_name) : array { $contents = json_decode(file_get_contents($file_name), \true); if ($error = json_last_error()) { throw new RuntimeException(json_last_error_msg(), $error); } if (!is_array($contents)) { throw new RuntimeException('Malformed ' . $file_name . ', expecting JSON-encoded object'); } return $contents; } /** * @return list */ private function getAllPluginPackages() : array { $packages = $this->getAllPackages(); $ret = []; /** @psalm-suppress MixedAssignment */ foreach ($packages as $package) { if ($this->isPlugin($package)) { $ret[] = $package; } } return $ret; } private function getAllPackages() : array { $packages = []; foreach ($this->file_names as $file_name) { $composer_lock_contents = $this->read($file_name); if (!isset($composer_lock_contents['packages']) || !is_array($composer_lock_contents['packages'])) { throw new RuntimeException('packages section is missing or not an array'); } if (!isset($composer_lock_contents['packages-dev']) || !is_array($composer_lock_contents['packages-dev'])) { throw new RuntimeException('packages-dev section is missing or not an array'); } $packages = array_merge($packages, array_merge($composer_lock_contents['packages'], $composer_lock_contents['packages-dev'])); } return $packages; } } plugin_list_factory = $plugin_list_factory; parent::__construct(); } protected function configure() : void { $this->setName('show')->setDescription('Lists enabled and available plugins')->addOption('config', 'c', InputOption::VALUE_REQUIRED, 'Path to Psalm config file')->addUsage('[-c path/to/psalm.xml]'); } protected function execute(InputInterface $input, OutputInterface $output) : int { $io = new SymfonyStyle($input, $output); $current_dir = (string) getcwd(); $config_file_path = $input->getOption('config'); if ($config_file_path !== null && !is_string($config_file_path)) { throw new UnexpectedValueException('Config file path should be a string'); } $plugin_list = ($this->plugin_list_factory)($current_dir, $config_file_path); $enabled = $plugin_list->getEnabled(); $available = $plugin_list->getAvailable(); $formatRow = static fn(string $class, ?string $package): array => [$package, $class]; $io->section('Enabled'); if (count($enabled)) { $io->table(['Package', 'Class'], array_map($formatRow, array_keys($enabled), array_values($enabled))); } else { $io->note('No plugins enabled'); } $io->section('Available'); if (count($available)) { $io->table(['Package', 'Class'], array_map($formatRow, array_keys($available), array_values($available))); } else { $io->note('No plugins available'); } return 0; } } plugin_list_factory = $plugin_list_factory; parent::__construct(); } protected function configure() : void { $this->setName('enable')->setDescription('Enables a named plugin')->addArgument('pluginName', InputArgument::REQUIRED, 'Plugin name (fully qualified class name or composer package name)')->addOption('config', 'c', InputOption::VALUE_REQUIRED, 'Path to Psalm config file')->addUsage('vendor/plugin-package-name [-c path/to/psalm.xml]'); $this->addUsage('\'Plugin\\Class\\Name\' [-c path/to/psalm.xml]'); } protected function execute(InputInterface $input, OutputInterface $output) : int { $io = new SymfonyStyle($input, $output); $current_dir = (string) getcwd(); $config_file_path = $input->getOption('config'); if ($config_file_path !== null && !is_string($config_file_path)) { throw new UnexpectedValueException('Config file path should be a string'); } $plugin_list = ($this->plugin_list_factory)($current_dir, $config_file_path); $plugin_name = $input->getArgument('pluginName'); assert(is_string($plugin_name)); try { $plugin_class = $plugin_list->resolvePluginClass($plugin_name); } catch (InvalidArgumentException $e) { $io->error('Unknown plugin class ' . $plugin_name); return 2; } if ($plugin_list->isEnabled($plugin_class)) { $io->note('Plugin already enabled'); return 3; } $plugin_list->enable($plugin_class); $io->success('Plugin enabled'); return 0; } } plugin_list_factory = $plugin_list_factory; parent::__construct(); } protected function configure() : void { $this->setName('disable')->setDescription('Disables a named plugin')->addArgument('pluginName', InputArgument::REQUIRED, 'Plugin name (fully qualified class name or composer package name)')->addOption('config', 'c', InputOption::VALUE_REQUIRED, 'Path to Psalm config file')->addUsage('vendor/plugin-package-name [-c path/to/psalm.xml]'); $this->addUsage('\'Plugin\\Class\\Name\' [-c path/to/psalm.xml]'); } protected function execute(InputInterface $input, OutputInterface $output) : int { $io = new SymfonyStyle($input, $output); $current_dir = (string) getcwd(); $config_file_path = $input->getOption('config'); if ($config_file_path !== null && !is_string($config_file_path)) { throw new UnexpectedValueException('Config file path should be a string'); } $plugin_list = ($this->plugin_list_factory)($current_dir, $config_file_path); $plugin_name = $input->getArgument('pluginName'); assert(is_string($plugin_name)); try { $plugin_class = $plugin_list->resolvePluginClass($plugin_name); } catch (InvalidArgumentException $e) { $io->error('Unknown plugin class ' . $plugin_name); return 2; } if (!$plugin_list->isEnabled($plugin_class)) { $io->note('Plugin already disabled'); return 3; } $plugin_list->disable($plugin_class); $io->success('Plugin disabled'); return 0; } } [pluginClass => packageName] */ private ?array $all_plugins = null; /** @var ?array [pluginClass => ?packageName] */ private ?array $enabled_plugins = null; public function __construct(?\Psalm\Internal\PluginManager\ConfigFile $config_file, \Psalm\Internal\PluginManager\ComposerLock $composer_lock) { $this->config_file = $config_file; $this->composer_lock = $composer_lock; } /** * @return array [pluginClass => ?packageName, ...] */ public function getEnabled() : array { if (!$this->enabled_plugins) { $this->enabled_plugins = []; if ($this->config_file) { foreach ($this->config_file->getConfig()->getPluginClasses() as $plugin_entry) { $plugin_class = $plugin_entry['class']; $this->enabled_plugins[$plugin_class] = $this->findPluginPackage($plugin_class); } } } return $this->enabled_plugins; } /** * @return array [pluginCLass => ?packageName] */ public function getAvailable() : array { return array_diff_key($this->getAll(), $this->getEnabled()); } /** * @return array [pluginClass => packageName] */ public function getAll() : array { if (null === $this->all_plugins) { $this->all_plugins = array_flip($this->composer_lock->getPlugins()); } return $this->all_plugins; } public function resolvePluginClass(string $class_or_package) : string { if (\false === strpos($class_or_package, '/')) { return $class_or_package; // must be a class then } // pluginClass => ?pluginPackage $plugin_classes = $this->getAll(); $class = array_search($class_or_package, $plugin_classes, \true); if (\false === $class) { throw new InvalidArgumentException('Unknown plugin: ' . $class_or_package); } return $class; } public function findPluginPackage(string $class) : ?string { // pluginClass => ?pluginPackage $plugin_classes = $this->getAll(); return $plugin_classes[$class] ?? null; } public function isEnabled(string $class) : bool { return array_key_exists($class, $this->getEnabled()); } public function enable(string $class) : void { if (!$this->config_file) { throw new RuntimeException('Cannot find Psalm config'); } $this->config_file->addPlugin($class); } public function disable(string $class) : void { if (!$this->config_file) { throw new RuntimeException('Cannot find Psalm config'); } $this->config_file->removePlugin($class); } } * @internal */ final class BuildInfoCollector { /** * Environment variables. * * Overwritten through collection process. */ protected array $env; /** * Read environment variables. */ protected array $readEnv = []; public function __construct(array $env) { $this->env = $env; } // API /** * Collect environment variables. */ public function collect() : array { $this->readEnv = []; $this->fillTravisCi()->fillCircleCi()->fillAppVeyor()->fillJenkins()->fillScrutinizer()->fillGithubActions(); return $this->readEnv; } // internal method /** * Fill Travis CI environment variables. * * "TRAVIS", "TRAVIS_JOB_ID" must be set. * * @return $this * @psalm-suppress PossiblyUndefinedStringArrayOffset */ protected function fillTravisCi() : self { if (isset($this->env['TRAVIS']) && $this->env['TRAVIS'] && isset($this->env['TRAVIS_JOB_ID'])) { $this->readEnv['CI_JOB_ID'] = $this->env['TRAVIS_JOB_ID']; $this->env['CI_NAME'] = 'travis-ci'; // backup $this->readEnv['TRAVIS'] = $this->env['TRAVIS']; $this->readEnv['TRAVIS_JOB_ID'] = $this->env['TRAVIS_JOB_ID']; $this->readEnv['CI_NAME'] = $this->env['CI_NAME']; $this->readEnv['TRAVIS_TAG'] = $this->env['TRAVIS_TAG'] ?? ''; $repo_slug = (string) $this->env['TRAVIS_REPO_SLUG']; if ($repo_slug) { $slug_parts = explode('/', $repo_slug); $this->readEnv['CI_REPO_OWNER'] = $slug_parts[0]; $this->readEnv['CI_REPO_NAME'] = $slug_parts[1]; } $pr_slug = (string) ($this->env['TRAVIS_PULL_REQUEST_SLUG'] ?? ''); if ($pr_slug) { $slug_parts = explode('/', $pr_slug); $this->readEnv['CI_PR_REPO_OWNER'] = $slug_parts[0]; $this->readEnv['CI_PR_REPO_NAME'] = $slug_parts[1]; } $this->readEnv['CI_PR_NUMBER'] = $this->env['TRAVIS_PULL_REQUEST']; $this->readEnv['CI_BRANCH'] = $this->env['TRAVIS_BRANCH']; } return $this; } /** * Fill CircleCI environment variables. * * "CIRCLECI", "CIRCLE_BUILD_NUM" must be set. * * @return $this */ protected function fillCircleCi() : self { if (isset($this->env['CIRCLECI']) && $this->env['CIRCLECI'] && isset($this->env['CIRCLE_BUILD_NUM'])) { $this->env['CI_BUILD_NUMBER'] = $this->env['CIRCLE_BUILD_NUM']; $this->env['CI_NAME'] = 'circleci'; // backup $this->readEnv['CIRCLECI'] = $this->env['CIRCLECI']; $this->readEnv['CIRCLE_BUILD_NUM'] = $this->env['CIRCLE_BUILD_NUM']; $this->readEnv['CI_NAME'] = $this->env['CI_NAME']; $this->readEnv['CI_PR_REPO_OWNER'] = $this->env['CIRCLE_PR_USERNAME'] ?? null; $this->readEnv['CI_PR_REPO_NAME'] = $this->env['CIRCLE_PR_REPONAME'] ?? null; $this->readEnv['CI_REPO_OWNER'] = $this->env['CIRCLE_PROJECT_USERNAME'] ?? null; $this->readEnv['CI_REPO_NAME'] = $this->env['CIRCLE_PROJECT_REPONAME'] ?? null; $this->readEnv['CI_PR_NUMBER'] = $this->env['CIRCLE_PR_NUMBER'] ?? null; $this->readEnv['CI_BRANCH'] = $this->env['CIRCLE_BRANCH'] ?? null; } return $this; } /** * Fill AppVeyor environment variables. * * "APPVEYOR", "APPVEYOR_BUILD_NUMBER" must be set. * * @psalm-suppress PossiblyUndefinedStringArrayOffset * @return $this */ protected function fillAppVeyor() : self { if (isset($this->env['APPVEYOR']) && $this->env['APPVEYOR'] && isset($this->env['APPVEYOR_BUILD_NUMBER'])) { $this->readEnv['CI_BUILD_NUMBER'] = $this->env['APPVEYOR_BUILD_NUMBER']; $this->readEnv['CI_JOB_ID'] = $this->env['APPVEYOR_JOB_NUMBER']; $this->readEnv['CI_PR_NUMBER'] = $this->env['APPVEYOR_PULL_REQUEST_NUMBER'] ?? ''; $this->env['CI_NAME'] = 'AppVeyor'; // backup $this->readEnv['APPVEYOR'] = $this->env['APPVEYOR']; $this->readEnv['APPVEYOR_BUILD_NUMBER'] = $this->env['APPVEYOR_BUILD_NUMBER']; $this->readEnv['APPVEYOR_JOB_NUMBER'] = $this->env['APPVEYOR_JOB_NUMBER']; $this->readEnv['APPVEYOR_REPO_BRANCH'] = $this->env['APPVEYOR_REPO_BRANCH']; $this->readEnv['CI_NAME'] = $this->env['CI_NAME']; $repo_slug = (string) ($this->env['APPVEYOR_REPO_NAME'] ?? ''); if ($repo_slug) { $slug_parts = explode('/', $repo_slug); $this->readEnv['CI_REPO_OWNER'] = $slug_parts[0]; $this->readEnv['CI_REPO_NAME'] = $slug_parts[1]; } $pr_slug = (string) ($this->env['APPVEYOR_PULL_REQUEST_HEAD_REPO_NAME'] ?? ''); if ($pr_slug) { $slug_parts = explode('/', $pr_slug); $this->readEnv['CI_PR_REPO_OWNER'] = $slug_parts[0]; $this->readEnv['CI_PR_REPO_NAME'] = $slug_parts[1]; } $this->readEnv['CI_BRANCH'] = $this->env['APPVEYOR_PULL_REQUEST_HEAD_REPO_BRANCH'] ?? $this->env['APPVEYOR_REPO_BRANCH']; } return $this; } /** * Fill Jenkins environment variables. * * "JENKINS_URL", "BUILD_NUMBER" must be set. * * @return $this */ protected function fillJenkins() : self { if (isset($this->env['JENKINS_URL']) && isset($this->env['BUILD_NUMBER'])) { $this->readEnv['CI_BUILD_NUMBER'] = $this->env['BUILD_NUMBER']; $this->readEnv['CI_BUILD_URL'] = $this->env['JENKINS_URL']; $this->env['CI_NAME'] = 'jenkins'; // backup $this->readEnv['BUILD_NUMBER'] = $this->env['BUILD_NUMBER']; $this->readEnv['JENKINS_URL'] = $this->env['JENKINS_URL']; $this->readEnv['CI_NAME'] = $this->env['CI_NAME']; } return $this; } /** * Fill Scrutinizer environment variables. * * "JENKINS_URL", "BUILD_NUMBER" must be set. * * @psalm-suppress PossiblyUndefinedStringArrayOffset * @return $this */ protected function fillScrutinizer() : self { if (isset($this->env['SCRUTINIZER']) && $this->env['SCRUTINIZER']) { $this->readEnv['CI_JOB_ID'] = $this->env['SCRUTINIZER_INSPECTION_UUID']; $this->readEnv['CI_BRANCH'] = $this->env['SCRUTINIZER_BRANCH']; $this->readEnv['CI_PR_NUMBER'] = $this->env['SCRUTINIZER_PR_NUMBER'] ?? ''; // backup $this->readEnv['CI_NAME'] = 'Scrutinizer'; $repo_slug = (string) ($this->env['SCRUTINIZER_PROJECT'] ?? ''); if ($repo_slug) { $slug_parts = explode('/', $repo_slug); if ($this->readEnv['CI_PR_NUMBER']) { $this->readEnv['CI_PR_REPO_OWNER'] = $slug_parts[1]; $this->readEnv['CI_PR_REPO_NAME'] = $slug_parts[2]; } else { $this->readEnv['CI_REPO_OWNER'] = $slug_parts[1]; $this->readEnv['CI_REPO_NAME'] = $slug_parts[2]; } } } return $this; } /** * Fill Github Actions environment variables. * * @return $this * @psalm-suppress PossiblyUndefinedStringArrayOffset */ protected function fillGithubActions() : \Psalm\Internal\ExecutionEnvironment\BuildInfoCollector { if (isset($this->env['GITHUB_ACTIONS'])) { $this->env['CI_NAME'] = 'github-actions'; $this->env['CI_JOB_ID'] = $this->env['GITHUB_ACTIONS']; $githubRef = (string) $this->env['GITHUB_REF']; if (strpos($githubRef, 'refs/heads/') !== \false) { $githubRef = str_replace('refs/heads/', '', $githubRef); } elseif (strpos($githubRef, 'refs/tags/') !== \false) { $githubRef = str_replace('refs/tags/', '', $githubRef); } $this->env['CI_BRANCH'] = $githubRef; $this->readEnv['GITHUB_ACTIONS'] = $this->env['GITHUB_ACTIONS']; $this->readEnv['GITHUB_REF'] = $this->env['GITHUB_REF']; $this->readEnv['CI_NAME'] = $this->env['CI_NAME']; $this->readEnv['CI_BRANCH'] = $this->env['CI_BRANCH']; $slug_parts = explode('/', (string) $this->env['GITHUB_REPOSITORY']); $this->readEnv['CI_REPO_OWNER'] = $slug_parts[0]; $this->readEnv['CI_REPO_NAME'] = $slug_parts[1]; if (isset($this->env['GITHUB_EVENT_PATH'])) { $event_json = file_get_contents((string) $this->env['GITHUB_EVENT_PATH']); /** @var array */ $event_data = json_decode($event_json, \true, 512, JSON_THROW_ON_ERROR); if (isset($event_data['head_commit'])) { /** * @var array{ * id: string, * author: array{name: string, email: string}, * committer: array{name: string, email: string}, * message: string, * timestamp: string * } */ $head_commit_data = $event_data['head_commit']; $gitinfo = new GitInfo($githubRef, (new CommitInfo())->setId($head_commit_data['id'])->setAuthorName($head_commit_data['author']['name'])->setAuthorEmail($head_commit_data['author']['email'])->setCommitterName($head_commit_data['committer']['name'])->setCommitterEmail($head_commit_data['committer']['email'])->setMessage($head_commit_data['message'])->setDate(strtotime($head_commit_data['timestamp'])), []); $this->readEnv['git'] = $gitinfo->toArray(); } if ($this->env['GITHUB_EVENT_PATH'] === 'pull_request') { $this->readEnv['CI_PR_NUMBER'] = $event_data['number']; } } } return $this; } } * @internal */ final class GitInfoCollector { /** * Git command. */ protected \Psalm\Internal\ExecutionEnvironment\SystemCommandExecutor $executor; /** * Constructor. */ public function __construct() { $this->executor = new \Psalm\Internal\ExecutionEnvironment\SystemCommandExecutor(); } // API /** * Collect git repository info. */ public function collect() : GitInfo { $branch = $this->collectBranch(); $commit = $this->collectCommit(); $remotes = $this->collectRemotes(); return new GitInfo($branch, $commit, $remotes); } /** * Collect branch name. * * @throws RuntimeException */ protected function collectBranch() : string { $branchesResult = $this->executor->execute('git branch'); foreach ($branchesResult as $result) { if (strpos($result, '* ') === 0) { $exploded = explode('* ', $result, 2); return $exploded[1]; } } throw new RuntimeException(); } /** * Collect commit info. * * @throws RuntimeException */ protected function collectCommit() : CommitInfo { $commitResult = $this->executor->execute('git log -1 --pretty=format:%H%n%aN%n%ae%n%cN%n%ce%n%s%n%at'); if (count($commitResult) !== 7 || array_keys($commitResult) !== range(0, 6)) { throw new RuntimeException(); } $commit = new CommitInfo(); return $commit->setId(trim($commitResult[0]))->setAuthorName(trim($commitResult[1]))->setAuthorEmail(trim($commitResult[2]))->setCommitterName(trim($commitResult[3]))->setCommitterEmail(trim($commitResult[4]))->setMessage($commitResult[5])->setDate((int) $commitResult[6]); } /** * Collect remotes info. * * @throws RuntimeException * @return list */ protected function collectRemotes() : array { $remotesResult = $this->executor->execute('git remote -v'); if (count($remotesResult) === 0) { throw new RuntimeException(); } // parse command result $results = []; foreach ($remotesResult as $result) { if (strpos($result, ' ') !== \false) { [$remote] = explode(' ', $result, 2); $results[] = $remote; } } // filter $results = array_unique($results); // create Remote instances $remotes = []; foreach ($results as $result) { if (strpos($result, "\t") !== \false) { [$name, $url] = explode("\t", $result, 2); $remote = new RemoteInfo(); $remotes[] = $remote->setName(trim($name))->setUrl(trim($url)); } } return $remotes; } } * @author Dariusz Rumiński * @internal */ final class SystemCommandExecutor { /** * Execute command. * * @throws RuntimeException * @return string[] */ public function execute(string $command) : array { if (!function_exists('exec')) { throw new RuntimeException(sprintf('exec does not exist, failed to execute command: %s', $command)); } exec($command, $result, $returnValue); if ($returnValue === 0) { /** @var string[] */ return $result; } throw new RuntimeException(sprintf('Failed to execute command: %s', $command), $returnValue); } } fq_class_name = $fq_class_name; $this->method_name = $method_name; } /** * Takes any valid reference to a method id and converts * it into a MethodIdentifier * * @param string|MethodIdentifier $method_id * @psalm-pure */ public static function wrap($method_id) : self { return is_string($method_id) ? static::fromMethodIdReference($method_id) : $method_id; } /** * @psalm-pure */ public static function isValidMethodIdReference(string $method_id) : bool { return strpos($method_id, '::') !== \false; } /** * @psalm-pure */ public static function fromMethodIdReference(string $method_id) : self { if (!static::isValidMethodIdReference($method_id)) { throw new InvalidArgumentException('Invalid method id reference provided: ' . $method_id); } // remove leading backslash if it exists $method_id = ltrim($method_id, '\\'); $method_id_parts = explode('::', $method_id); return new self($method_id_parts[0], strtolower($method_id_parts[1])); } /** @return non-empty-string */ public function __toString() : string { return $this->fq_class_name . '::' . $this->method_name; } } */ private array $replacements = []; private bool $new_name_replaced = \false; private bool $new_new_name_used = \false; public function __construct(string $old_name, string $new_name) { $this->old_name = $old_name; $this->new_name = $new_name; } public function enterNode(PhpParser\Node $node) : ?int { if ($node instanceof PhpParser\Node\Expr\Variable) { if ($node->name === $this->old_name) { $this->replacements[] = new FileManipulation((int) $node->getAttribute('startFilePos') + 1, (int) $node->getAttribute('endFilePos') + 1, $this->new_name); } elseif ($node->name === $this->new_name) { if ($this->new_new_name_used) { $this->replacements = []; return PhpParser\NodeTraverser::STOP_TRAVERSAL; } $this->replacements[] = new FileManipulation((int) $node->getAttribute('startFilePos') + 1, (int) $node->getAttribute('endFilePos') + 1, $this->new_name . '_new'); $this->new_name_replaced = \true; } elseif ($node->name === $this->new_name . '_new') { if ($this->new_name_replaced) { $this->replacements = []; return PhpParser\NodeTraverser::STOP_TRAVERSAL; } $this->new_new_name_used = \true; } } elseif ($node instanceof PhpParser\Node\Stmt\ClassMethod && ($docblock = $node->getDocComment())) { $parsed_docblock = DocblockParser::parse($docblock->getText(), $docblock->getStartFilePos()); $replaced = \false; foreach ($parsed_docblock->tags as $tag_name => $tags) { foreach ($tags as $i => $tag) { if ($tag_name === 'param' || $tag_name === 'psalm-param' || $tag_name === 'phpstan-param' || $tag_name === 'phan-param') { $parts = CommentAnalyzer::splitDocLine($tag); if (($parts[1] ?? '') === '$' . $this->old_name) { $parsed_docblock->tags[$tag_name][$i] = str_replace('$' . $this->old_name, '$' . $this->new_name, $tag); $replaced = \true; } } } } if ($replaced) { $this->replacements[] = new FileManipulation($docblock->getStartFilePos(), $docblock->getStartFilePos() + strlen($docblock->getText()), rtrim($parsed_docblock->render($parsed_docblock->first_line_padding)), \false, \false); } } return null; } /** * @return list */ public function getReplacements() : array { return $this->replacements; } } */ private array $matching_trait_nodes = []; private string $fq_trait_name; public function __construct(string $fq_trait_name) { $this->fq_trait_name = $fq_trait_name; } public function enterNode(PhpParser\Node $node, bool &$traverseChildren = \true) : ?int { if ($node instanceof PhpParser\Node\Stmt\Trait_) { /** @var ?string */ $resolved_name = $node->getAttribute('resolvedName'); if ($resolved_name === null) { // compare ends of names, a temporary hack because PHPParser caches // may not have that attribute $fq_trait_name_parts = explode('\\', $this->fq_trait_name); /** @psalm-suppress PossiblyNullPropertyFetch */ if ($node->name->name === end($fq_trait_name_parts)) { $this->matching_trait_nodes[] = $node; } } elseif ($resolved_name === $this->fq_trait_name) { $this->matching_trait_nodes[] = $node; } } if ($node instanceof PhpParser\Node\Stmt\ClassLike || $node instanceof PhpParser\Node\FunctionLike) { return PhpParser\NodeTraverser::DONT_TRAVERSE_CHILDREN; } return null; } public function getNode() : ?PhpParser\Node\Stmt\Trait_ { if (!count($this->matching_trait_nodes)) { return null; } if (count($this->matching_trait_nodes) === 1 || !trait_exists($this->fq_trait_name)) { return $this->matching_trait_nodes[0]; } try { $reflection_trait = new ReflectionClass($this->fq_trait_name); } catch (Throwable $t) { return null; } foreach ($this->matching_trait_nodes as $node) { if ($node->getLine() === $reflection_trait->getStartLine()) { return $node; } } return null; } } fake_type_provider = $fake_type_provider; $this->real_type_provider = $real_type_provider; } /** * @phpcsSuppress SlevomatCodingStandard.TypeHints.ReturnTypeHint.MissingAnyTypeHint */ public function enterNode(Node $node) { $origNode = $node; /** @psalm-suppress ArgumentTypeCoercion */ $node_type = $this->fake_type_provider->getType($origNode); if ($node_type) { /** @psalm-suppress ArgumentTypeCoercion */ $this->real_type_provider->setType($origNode, $node_type); } return null; } } getAttribute('pure', \false)) { return \false; } if ($node instanceof PhpParser\Node\Expr\New_ && $node->getAttribute('external_mutation_free', \false)) { return \false; } return \true; } return \false; } public function enterNode(PhpParser\Node $node) : ?int { if ($node instanceof PhpParser\Node\Expr) { // Check for Non-Trivial Expression first if ($this->checkNonTrivialExpr($node)) { $this->has_non_trivial_expr = \true; return PhpParser\NodeTraverser::STOP_TRAVERSAL; } if ($node instanceof PhpParser\Node\Expr\ClassConstFetch || $node instanceof PhpParser\Node\Expr\ConstFetch || $node instanceof PhpParser\Node\Expr\Error || $node instanceof PhpParser\Node\Expr\PropertyFetch || $node instanceof PhpParser\Node\Expr\StaticPropertyFetch) { return PhpParser\NodeTraverser::STOP_TRAVERSAL; } } return null; } public function hasNonTrivialExpr() : bool { return $this->has_non_trivial_expr; } } */ private array $extra_offsets; /** * @param array $extra_offsets */ public function __construct(int $offset, int $line_offset, array $extra_offsets) { $this->file_offset = $offset; $this->line_offset = $line_offset; $this->extra_offsets = $extra_offsets; } public function enterNode(PhpParser\Node $node) : ?int { /** @var array{startFilePos: int, endFilePos: int, startLine: int} */ $attrs = $node->getAttributes(); if ($cs = $node->getComments()) { $new_comments = []; foreach ($cs as $c) { if ($c instanceof PhpParser\Comment\Doc) { $new_comments[] = new PhpParser\Comment\Doc($c->getText(), $c->getStartLine() + $this->line_offset, $c->getStartFilePos() + $this->file_offset + ($this->extra_offsets[$c->getStartFilePos()] ?? 0)); } else { $new_comments[] = new PhpParser\Comment($c->getText(), $c->getStartLine() + $this->line_offset, $c->getStartFilePos() + $this->file_offset + ($this->extra_offsets[$c->getStartFilePos()] ?? 0)); } } $node->setAttribute('comments', $new_comments); } $node->setAttribute('startFilePos', $attrs['startFilePos'] + $this->file_offset + ($this->extra_offsets[$attrs['startFilePos']] ?? 0)); $node->setAttribute('endFilePos', $attrs['endFilePos'] + $this->file_offset + ($this->extra_offsets[$attrs['endFilePos']] ?? 0)); $node->setAttribute('startLine', $attrs['startLine'] + $this->line_offset); return null; } } */ protected array $used_variables = []; public function enterNode(PhpParser\Node $node) : ?int { if ($node instanceof PhpParser\Node\Expr\Variable && is_string($node->name)) { $this->used_variables['$' . $node->name] = \true; } return null; } /** * @return array */ public function getUsedVariables() : array { return $this->used_variables; } } > */ protected array $assignment_map = []; protected ?string $this_class_name = null; public function __construct(?string $this_class_name) { $this->this_class_name = $this_class_name; } public function enterNode(PhpParser\Node $node) : ?int { if ($node instanceof PhpParser\Node\Expr\Assign) { $right_var_id = ExpressionIdentifier::getRootVarId($node->expr, $this->this_class_name); if ($node->var instanceof PhpParser\Node\Expr\List_ || $node->var instanceof PhpParser\Node\Expr\Array_) { foreach ($node->var->items as $assign_item) { if ($assign_item) { $left_var_id = ExpressionIdentifier::getRootVarId($assign_item->value, $this->this_class_name); if ($left_var_id) { $this->assignment_map[$left_var_id][$right_var_id ?: 'isset'] = \true; } } } } else { $left_var_id = ExpressionIdentifier::getRootVarId($node->var, $this->this_class_name); if ($left_var_id) { $this->assignment_map[$left_var_id][$right_var_id ?: 'isset'] = \true; } } return PhpParser\NodeTraverser::DONT_TRAVERSE_CHILDREN; } if ($node instanceof PhpParser\Node\Expr\PostInc || $node instanceof PhpParser\Node\Expr\PostDec || $node instanceof PhpParser\Node\Expr\PreInc || $node instanceof PhpParser\Node\Expr\PreDec || $node instanceof PhpParser\Node\Expr\AssignOp) { $var_id = ExpressionIdentifier::getRootVarId($node->var, $this->this_class_name); if ($var_id) { $this->assignment_map[$var_id][$var_id] = \true; } return PhpParser\NodeTraverser::DONT_TRAVERSE_CHILDREN; } if ($node instanceof PhpParser\Node\Expr\FuncCall || $node instanceof PhpParser\Node\Expr\MethodCall || $node instanceof PhpParser\Node\Expr\StaticCall) { if (!$node->isFirstClassCallable()) { foreach ($node->getArgs() as $arg) { $arg_var_id = ExpressionIdentifier::getRootVarId($arg->value, $this->this_class_name); if ($arg_var_id) { $this->assignment_map[$arg_var_id][$arg_var_id] = \true; } } } if ($node instanceof PhpParser\Node\Expr\MethodCall) { $var_id = ExpressionIdentifier::getRootVarId($node->var, $this->this_class_name); if ($var_id) { $this->assignment_map[$var_id]['isset'] = \true; } } } elseif ($node instanceof PhpParser\Node\Stmt\Unset_) { foreach ($node->vars as $arg) { $arg_var_id = ExpressionIdentifier::getRootVarId($arg, $this->this_class_name); if ($arg_var_id) { $this->assignment_map[$arg_var_id][$arg_var_id] = \true; } } } return null; } /** * @return array> */ public function getAssignmentMap() : array { return $this->assignment_map; } } getComments()) !== []) { $comments = []; foreach ($cs as $i => $comment) { $comments[$i] = clone $comment; } $node->setAttribute('comments', $comments); } return $node; } } count++; return null; } } type_provider = $old_type_provider; } /** * @return Node\Expr */ public function enterNode(Node $node) : Node { /** @var Expr $node */ $origNode = $node; $node = clone $node; $node_type = $this->type_provider->getType($origNode); if ($node_type) { $this->type_provider->setType($node, $node_type); } return $node; } } type_provider = $type_provider; } public function enterNode(PhpParser\Node $node) : ?int { if ($node instanceof PhpParser\Node\Expr) { $this->type_provider->clearNodeOfTypeAndAssertions($node); } return null; } } */ private array $classlike_type_aliases = []; /** * @var array> */ public array $class_template_types = []; private ?Name $namespace_name = null; private Aliases $aliases; public ?ClassLikeStorage $storage = null; /** * @var array */ public array $type_aliases = []; public function __construct(Codebase $codebase, FileStorage $file_storage, FileScanner $file_scanner, Aliases $aliases, ?Name $namespace_name) { $this->codebase = $codebase; $this->file_storage = $file_storage; $this->file_scanner = $file_scanner; $this->file_path = $file_storage->file_path; $this->aliases = $aliases; $this->config = Config::getInstance(); $this->namespace_name = $namespace_name; } /** * @return false|null * @psalm-suppress ComplexMethod */ public function start(PhpParser\Node\Stmt\ClassLike $node) : ?bool { $class_location = new CodeLocation($this->file_scanner, $node); $name_location = null; $storage = null; $class_name = null; $is_classlike_overridden = \false; if ($node->name === null) { if (!$node instanceof PhpParser\Node\Stmt\Class_) { throw new LogicException('Anonymous classes are always classes'); } $fq_classlike_name = ClassAnalyzer::getAnonymousClassName($node, $this->aliases, $this->file_path); } else { $name_location = new CodeLocation($this->file_scanner, $node->name); $fq_classlike_name = ($this->aliases->namespace ? $this->aliases->namespace . '\\' : '') . $node->name->name; assert($fq_classlike_name !== ""); $fq_classlike_name_lc = strtolower($fq_classlike_name); $class_name = $node->name->name; if ($this->codebase->classlike_storage_provider->has($fq_classlike_name_lc)) { $duplicate_storage = $this->codebase->classlike_storage_provider->get($fq_classlike_name_lc); // don't override data from files that are getting analyzed with data from stubs // if the stubs contain the same class if (!$duplicate_storage->stubbed && $this->codebase->register_stub_files && $duplicate_storage->stmt_location && $this->config->isInProjectDirs($duplicate_storage->stmt_location->file_path)) { return \false; } if (!$this->codebase->register_stub_files) { if (!$duplicate_storage->stmt_location || $duplicate_storage->stmt_location->file_path !== $this->file_path || $class_location->getHash() !== $duplicate_storage->stmt_location->getHash()) { IssueBuffer::maybeAdd(new DuplicateClass('Class ' . $fq_classlike_name . ' has already been defined' . ($duplicate_storage->location ? ' in ' . $duplicate_storage->location->file_path : ''), $name_location)); $this->file_storage->has_visitor_issues = \true; $duplicate_storage->has_visitor_issues = \true; return \false; } } elseif (!$duplicate_storage->location || $duplicate_storage->location->file_path !== $this->file_path || $class_location->getHash() !== $duplicate_storage->location->getHash()) { $is_classlike_overridden = \true; // we're overwriting some methods $storage = $this->storage = $duplicate_storage; $this->codebase->classlike_storage_provider->makeNew(strtolower($fq_classlike_name)); $storage->populated = \false; $storage->class_implements = []; // we do this because reflection reports $storage->parent_interfaces = []; $storage->stubbed = \true; $storage->aliases = $this->aliases; foreach ($storage->dependent_classlikes as $dependent_name_lc => $_) { try { $dependent_storage = $this->codebase->classlike_storage_provider->get($dependent_name_lc); } catch (InvalidArgumentException $exception) { continue; } $dependent_storage->populated = \false; $this->codebase->classlike_storage_provider->makeNew($dependent_name_lc); } } } } $fq_classlike_name_lc = strtolower($fq_classlike_name); $this->file_storage->classlikes_in_file[$fq_classlike_name_lc] = $fq_classlike_name; if (!$storage) { $this->storage = $storage = $this->codebase->classlike_storage_provider->create($fq_classlike_name); } if ($class_name && isset($this->aliases->uses[strtolower($class_name)]) && $this->aliases->uses[strtolower($class_name)] !== $fq_classlike_name) { IssueBuffer::maybeAdd(new ParseError('Class name ' . $class_name . ' clashes with a use statement alias', $name_location ?? $class_location)); $storage->has_visitor_issues = \true; $this->file_storage->has_visitor_issues = \true; } $storage->stmt_location = $class_location; $storage->location = $name_location; if ($this->namespace_name) { $storage->namespace_name_location = new CodeLocation($this->file_scanner, $this->namespace_name); } $storage->user_defined = !$this->codebase->register_stub_files; $storage->stubbed = $this->codebase->register_stub_files; $storage->aliases = $this->aliases; if ($node instanceof PhpParser\Node\Stmt\Class_) { $storage->abstract = $node->isAbstract(); $storage->final = $node->isFinal(); $storage->readonly = $node->isReadonly(); $this->codebase->classlikes->addFullyQualifiedClassName($fq_classlike_name, $this->file_path); if ($node->extends) { $parent_fqcln = ClassLikeAnalyzer::getFQCLNFromNameObject($node->extends, $this->aliases); $parent_fqcln = $this->codebase->classlikes->getUnAliasedName($parent_fqcln); $this->codebase->scanner->queueClassLikeForScanning($parent_fqcln, $this->file_scanner->will_analyze); $parent_fqcln_lc = strtolower($parent_fqcln); $storage->parent_class = $parent_fqcln; $storage->parent_classes[$parent_fqcln_lc] = $parent_fqcln; $this->file_storage->required_classes[strtolower($parent_fqcln)] = $parent_fqcln; } } elseif ($node instanceof PhpParser\Node\Stmt\Interface_) { $storage->is_interface = \true; $this->codebase->classlikes->addFullyQualifiedInterfaceName($fq_classlike_name, $this->file_path); foreach ($node->extends as $interface) { $interface_fqcln = ClassLikeAnalyzer::getFQCLNFromNameObject($interface, $this->aliases); $interface_fqcln = $this->codebase->classlikes->getUnAliasedName($interface_fqcln); $interface_fqcln_lc = strtolower($interface_fqcln); $this->codebase->scanner->queueClassLikeForScanning($interface_fqcln); $storage->parent_interfaces[$interface_fqcln_lc] = $interface_fqcln; $storage->direct_interface_parents[$interface_fqcln_lc] = $interface_fqcln; $this->file_storage->required_interfaces[$interface_fqcln_lc] = $interface_fqcln; } } elseif ($node instanceof PhpParser\Node\Stmt\Trait_) { $storage->is_trait = \true; $this->codebase->classlikes->addFullyQualifiedTraitName($fq_classlike_name, $this->file_path); } elseif ($node instanceof PhpParser\Node\Stmt\Enum_) { $storage->is_enum = \true; $storage->final = \true; if ($node->scalarType) { if ($node->scalarType->name === 'string' || $node->scalarType->name === 'int') { $storage->enum_type = $node->scalarType->name; $storage->class_implements['backedenum'] = 'BackedEnum'; $storage->direct_class_interfaces['backedenum'] = 'BackedEnum'; $this->file_storage->required_interfaces['backedenum'] = 'BackedEnum'; $this->codebase->scanner->queueClassLikeForScanning('BackedEnum'); $storage->declaring_method_ids['from'] = new MethodIdentifier('BackedEnum', 'from'); $storage->appearing_method_ids['from'] = $storage->declaring_method_ids['from']; $storage->declaring_method_ids['tryfrom'] = new MethodIdentifier('BackedEnum', 'tryfrom'); $storage->appearing_method_ids['tryfrom'] = $storage->declaring_method_ids['tryfrom']; } else { IssueBuffer::maybeAdd(new InvalidEnumBackingType('Enums cannot be backed by ' . $node->scalarType->name . ', string or int expected', new CodeLocation($this->file_scanner, $node->scalarType), $fq_classlike_name)); $this->file_storage->has_visitor_issues = \true; $storage->has_visitor_issues = \true; } } $this->codebase->scanner->queueClassLikeForScanning('UnitEnum'); $storage->class_implements['unitenum'] = 'UnitEnum'; $storage->direct_class_interfaces['unitenum'] = 'UnitEnum'; $this->file_storage->required_interfaces['unitenum'] = 'UnitEnum'; $storage->final = \true; $storage->declaring_method_ids['cases'] = new MethodIdentifier('UnitEnum', 'cases'); $storage->appearing_method_ids['cases'] = $storage->declaring_method_ids['cases']; $this->codebase->classlikes->addFullyQualifiedEnumName($fq_classlike_name, $this->file_path); } else { throw new UnexpectedValueException('Unknown classlike type'); } if ($node instanceof PhpParser\Node\Stmt\Class_ || $node instanceof PhpParser\Node\Stmt\Enum_) { foreach ($node->implements as $interface) { $interface_fqcln = ClassLikeAnalyzer::getFQCLNFromNameObject($interface, $this->aliases); $interface_fqcln_lc = strtolower($interface_fqcln); $this->codebase->scanner->queueClassLikeForScanning($interface_fqcln); $storage->class_implements[$interface_fqcln_lc] = $interface_fqcln; $storage->direct_class_interfaces[$interface_fqcln_lc] = $interface_fqcln; $this->file_storage->required_interfaces[$interface_fqcln_lc] = $interface_fqcln; } } $docblock_info = null; $doc_comment = $node->getDocComment(); if ($doc_comment) { try { $docblock_info = \Psalm\Internal\PhpVisitor\Reflector\ClassLikeDocblockParser::parse($node, $doc_comment, $this->aliases); $this->type_aliases += $this->getImportedTypeAliases($docblock_info, $fq_classlike_name); } catch (DocblockParseException $e) { $storage->docblock_issues[] = new InvalidDocblock($e->getMessage() . ' in docblock for ' . $fq_classlike_name, $name_location ?? $class_location); } } foreach ($node->getComments() as $comment) { if (!$comment instanceof PhpParser\Comment\Doc) { continue; } try { $type_aliases = self::getTypeAliasesFromComment($comment, $this->aliases, $this->type_aliases, $fq_classlike_name); foreach ($type_aliases as $type_alias) { // finds issues, if there are any TypeParser::parseTokens($type_alias->replacement_tokens); } $this->type_aliases += $type_aliases; if ($type_aliases) { $this->classlike_type_aliases = $type_aliases; } } catch (DocblockParseException|TypeParseTreeException $e) { $storage->docblock_issues[] = new InvalidDocblock($e->getMessage(), new CodeLocation($this->file_scanner, $node, null, \true)); } } if ($docblock_info) { if ($docblock_info->stub_override && !$is_classlike_overridden) { throw new InvalidClasslikeOverrideException('Class/interface/trait ' . $fq_classlike_name . ' is marked as stub override,' . ' but no original counterpart found'); } if ($docblock_info->templates) { $storage->template_types = []; usort($docblock_info->templates, static fn(array $l, array $r): int => $l[4] > $r[4] ? 1 : -1); foreach ($docblock_info->templates as $i => $template_map) { $template_name = $template_map[0]; if ($template_map[1] !== null && $template_map[2] !== null) { if (trim($template_map[2])) { $type_string = $template_map[2]; try { $type_string = CommentAnalyzer::splitDocLine($type_string)[0]; } catch (DocblockParseException $e) { $storage->docblock_issues[] = new InvalidDocblock($e->getMessage() . ' in docblock for ' . $fq_classlike_name, $name_location ?? $class_location); continue; } $type_string = CommentAnalyzer::sanitizeDocblockType($type_string); try { $template_type = TypeParser::parseTokens(TypeTokenizer::getFullyQualifiedTokens($type_string, $this->aliases, $storage->template_types, $this->type_aliases), null, $storage->template_types, $this->type_aliases); } catch (TypeParseTreeException $e) { $storage->docblock_issues[] = new InvalidDocblock($e->getMessage() . ' in docblock for ' . $fq_classlike_name, $name_location ?? $class_location); continue; } $storage->template_types[$template_name] = [$fq_classlike_name => $template_type]; } else { $storage->docblock_issues[] = new InvalidDocblock('Template missing as type', $name_location ?? $class_location); } } else { /** @psalm-suppress PropertyTypeCoercion due to a Psalm bug */ $storage->template_types[$template_name][$fq_classlike_name] = Type::getMixed(); } $storage->template_covariants[$i] = $template_map[3]; } $this->class_template_types = $storage->template_types; } foreach ($docblock_info->template_extends as $extended_class_name) { $this->extendTemplatedType($storage, $node, $extended_class_name); } foreach ($docblock_info->template_implements as $implemented_class_name) { $this->implementTemplatedType($storage, $node, $implemented_class_name); } if ($docblock_info->yield) { try { $yield_type_tokens = TypeTokenizer::getFullyQualifiedTokens($docblock_info->yield, $this->aliases, $storage->template_types, $this->type_aliases); $yield_type = TypeParser::parseTokens($yield_type_tokens, null, $storage->template_types ?: [], $this->type_aliases, \true); /** @psalm-suppress UnusedMethodCall */ $yield_type->queueClassLikesForScanning($this->codebase, $this->file_storage, $storage->template_types ?: []); $storage->yield = $yield_type; } catch (TypeParseTreeException $e) { // do nothing } } if ($docblock_info->extension_requirement !== null) { $storage->extension_requirement = (string) TypeParser::parseTokens(TypeTokenizer::getFullyQualifiedTokens($docblock_info->extension_requirement, $this->aliases, $this->class_template_types, $this->type_aliases), null, $this->class_template_types, $this->type_aliases); } foreach ($docblock_info->implementation_requirements as $implementation_requirement) { $storage->implementation_requirements[] = (string) TypeParser::parseTokens(TypeTokenizer::getFullyQualifiedTokens($implementation_requirement, $this->aliases, $this->class_template_types, $this->type_aliases), null, $this->class_template_types, $this->type_aliases); } $storage->sealed_properties = $docblock_info->sealed_properties; $storage->sealed_methods = $docblock_info->sealed_methods; if ($docblock_info->inheritors) { try { $storage->inheritors = TypeParser::parseTokens(TypeTokenizer::getFullyQualifiedTokens($docblock_info->inheritors, $storage->aliases, $storage->template_types ?? [], $storage->type_aliases, $fq_classlike_name), null, $storage->template_types ?? [], $storage->type_aliases, \true); } catch (TypeParseTreeException $e) { $storage->docblock_issues[] = new InvalidDocblock('@psalm-inheritors contains invalid reference:' . $e->getMessage(), $name_location ?? $class_location); } } if ($docblock_info->properties) { foreach ($docblock_info->properties as $property) { $pseudo_property_type_tokens = TypeTokenizer::getFullyQualifiedTokens($property['type'], $this->aliases, $this->class_template_types, $this->type_aliases); try { $pseudo_property_type = TypeParser::parseTokens($pseudo_property_type_tokens, null, $this->class_template_types, $this->type_aliases, \true); /** @psalm-suppress UnusedMethodCall */ $pseudo_property_type->queueClassLikesForScanning($this->codebase, $this->file_storage, $storage->template_types ?: []); if ($property['tag'] !== 'property-read' && $property['tag'] !== 'psalm-property-read') { $storage->pseudo_property_set_types[$property['name']] = $pseudo_property_type; } if ($property['tag'] !== 'property-write' && $property['tag'] !== 'psalm-property-write') { $storage->pseudo_property_get_types[$property['name']] = $pseudo_property_type; } } catch (TypeParseTreeException $e) { $storage->docblock_issues[] = new InvalidDocblock($e->getMessage() . ' in docblock for ' . $fq_classlike_name, $name_location ?? $class_location); } } } foreach ($docblock_info->methods as $method) { $functionlike_node_scanner = new \Psalm\Internal\PhpVisitor\Reflector\FunctionLikeNodeScanner($this->codebase, $this->file_scanner, $this->file_storage, $this->aliases, $this->type_aliases, $this->storage, []); /** @var MethodStorage */ $pseudo_method_storage = $functionlike_node_scanner->start($method, \true); $lc_method_name = strtolower($method->name->name); if ($pseudo_method_storage->is_static) { $storage->pseudo_static_methods[$lc_method_name] = $pseudo_method_storage; } else { $storage->pseudo_methods[$lc_method_name] = $pseudo_method_storage; $storage->declaring_pseudo_method_ids[$lc_method_name] = new MethodIdentifier($fq_classlike_name, $lc_method_name); } } $storage->deprecated = $docblock_info->deprecated; if (count($docblock_info->psalm_internal) !== 0) { $storage->internal = $docblock_info->psalm_internal; } elseif ($docblock_info->internal && $this->aliases->namespace) { $storage->internal = [NamespaceAnalyzer::getNameSpaceRoot($this->aliases->namespace)]; } if ($docblock_info->final && !$storage->final) { $storage->final = \true; $storage->final_from_docblock = \true; } $storage->preserve_constructor_signature = $docblock_info->consistent_constructor; if ($storage->preserve_constructor_signature) { $has_constructor = \false; foreach ($node->stmts as $stmt) { if ($stmt instanceof PhpParser\Node\Stmt\ClassMethod && $stmt->name->name === '__construct') { $has_constructor = \true; break; } } if (!$has_constructor) { self::registerEmptyConstructor($storage); } } $storage->enforce_template_inheritance = $docblock_info->consistent_templates; foreach ($docblock_info->mixins as $key => $mixin) { $mixin_type = TypeParser::parseTokens(TypeTokenizer::getFullyQualifiedTokens($mixin, $this->aliases, $this->class_template_types, $this->type_aliases, $fq_classlike_name), null, $this->class_template_types, $this->type_aliases, \true); /** @psalm-suppress UnusedMethodCall */ $mixin_type->queueClassLikesForScanning($this->codebase, $this->file_storage, $storage->template_types ?: []); if ($mixin_type->isSingle()) { $mixin_type = $mixin_type->getSingleAtomic(); if ($mixin_type instanceof TNamedObject) { $storage->namedMixins[] = $mixin_type; } if ($mixin_type instanceof TTemplateParam) { $storage->templatedMixins[] = $mixin_type; } } if ($key === 0) { $storage->mixin_declaring_fqcln = $storage->name; } } $storage->mutation_free = $docblock_info->mutation_free; $storage->external_mutation_free = $docblock_info->external_mutation_free; $storage->specialize_instance = $docblock_info->taint_specialize; $storage->override_property_visibility = $docblock_info->override_property_visibility; $storage->override_method_visibility = $docblock_info->override_method_visibility; $storage->suppressed_issues = $docblock_info->suppressed_issues; if ($docblock_info->description) { $storage->description = $docblock_info->description; } $storage->public_api = $docblock_info->public_api; } foreach ($node->stmts as $node_stmt) { if ($node_stmt instanceof PhpParser\Node\Stmt\ClassConst) { $this->visitClassConstDeclaration($node_stmt, $storage, $fq_classlike_name); } elseif ($node_stmt instanceof PhpParser\Node\Stmt\EnumCase && $node instanceof PhpParser\Node\Stmt\Enum_) { $this->visitEnumDeclaration($node_stmt, $storage, $fq_classlike_name); } } if ($storage->is_enum) { $name_types = []; $values_types = []; foreach ($storage->enum_cases as $name => $enumCaseStorage) { $name_types[] = Type::getAtomicStringFromLiteral($name); if ($storage->enum_type !== null) { if (is_string($enumCaseStorage->value)) { $values_types[] = Type::getAtomicStringFromLiteral($enumCaseStorage->value); } elseif (is_int($enumCaseStorage->value)) { $values_types[] = new Type\Atomic\TLiteralInt($enumCaseStorage->value); } elseif ($enumCaseStorage->value instanceof UnresolvedConstantComponent) { // backed enum with a type yet unknown $values_types[] = new Type\Atomic\TMixed(); } } } if ($name_types !== []) { $storage->declaring_property_ids['name'] = $storage->name; $storage->appearing_property_ids['name'] = "{$storage->name}::\$name"; $storage->properties['name'] = new PropertyStorage(); $storage->properties['name']->type = new Union($name_types); } if ($values_types !== []) { $storage->declaring_property_ids['value'] = $storage->name; $storage->appearing_property_ids['value'] = "{$storage->name}::\$value"; $storage->properties['value'] = new PropertyStorage(); $storage->properties['value']->type = new Union($values_types); } } foreach ($node->stmts as $node_stmt) { if ($node_stmt instanceof PhpParser\Node\Stmt\Property) { $this->visitPropertyDeclaration($node_stmt, $this->config, $storage, $fq_classlike_name); } } foreach ($node->attrGroups as $attr_group) { foreach ($attr_group->attrs as $attr) { $attribute = \Psalm\Internal\PhpVisitor\Reflector\AttributeResolver::resolve($this->codebase, $this->file_scanner, $this->file_storage, $this->aliases, $attr, $this->storage->name ?? null); if ($attribute->fq_class_name === 'Psalm\\Deprecated' || $attribute->fq_class_name === 'JetBrains\\PhpStorm\\Deprecated') { $storage->deprecated = \true; } if ($attribute->fq_class_name === 'Psalm\\Internal' && !$storage->internal) { $storage->internal = [NamespaceAnalyzer::getNameSpaceRoot($fq_classlike_name)]; } if ($attribute->fq_class_name === 'Psalm\\Immutable' || $attribute->fq_class_name === 'JetBrains\\PhpStorm\\Immutable') { $storage->mutation_free = \true; $storage->external_mutation_free = \true; } if ($attribute->fq_class_name === 'Psalm\\ExternalMutationFree') { $storage->external_mutation_free = \true; } if ($attribute->fq_class_name === 'AllowDynamicProperties' && $storage->readonly) { IssueBuffer::maybeAdd(new InvalidAttribute('Readonly classes cannot have dynamic properties', new CodeLocation($this->file_scanner, $attr, null, \true))); continue; } $storage->attributes[] = $attribute; } } return null; } public function finish(PhpParser\Node\Stmt\ClassLike $node) : ClassLikeStorage { if (!$this->storage) { throw new UnexpectedValueException('Storage should exist in ' . $this->file_path . ' at ' . $node->getLine()); } $classlike_storage = $this->storage; $fq_classlike_name = $classlike_storage->name; if (PropertyMap::inPropertyMap($fq_classlike_name)) { $mapped_properties = PropertyMap::getPropertyMap()[strtolower($fq_classlike_name)]; foreach ($mapped_properties as $property_name => $public_mapped_property) { $property_type = Type::parseString($public_mapped_property); /** @psalm-suppress UnusedMethodCall */ $property_type->queueClassLikesForScanning($this->codebase, $this->file_storage); if (!isset($classlike_storage->properties[$property_name])) { $classlike_storage->properties[$property_name] = new PropertyStorage(); } $property_id = $fq_classlike_name . '::$' . $property_name; if ($property_id === 'DateInterval::$days') { /** @psalm-suppress InaccessibleProperty We just parsed this type */ $property_type->ignore_falsable_issues = \true; } $classlike_storage->properties[$property_name]->type = $property_type; $classlike_storage->declaring_property_ids[$property_name] = $fq_classlike_name; $classlike_storage->appearing_property_ids[$property_name] = $property_id; } } $converted_aliases = []; foreach ($this->classlike_type_aliases as $key => $type) { try { $union = TypeParser::parseTokens($type->replacement_tokens, null, [], $this->type_aliases, \true); $converted_aliases[$key] = new ClassTypeAlias(array_values($union->getAtomicTypes())); } catch (TypeParseTreeException $e) { $classlike_storage->docblock_issues[] = new InvalidDocblock('@psalm-type ' . $key . ' contains invalid reference: ' . $e->getMessage(), new CodeLocation($this->file_scanner, $node, null, \true)); } catch (Exception $e) { $classlike_storage->docblock_issues[] = new InvalidDocblock('@psalm-type ' . $key . ' contains invalid references', new CodeLocation($this->file_scanner, $node, null, \true)); } } $classlike_storage->type_aliases = $converted_aliases; return $classlike_storage; } public function handleTraitUse(PhpParser\Node\Stmt\TraitUse $node) : void { $storage = $this->storage; if (!$storage) { throw new UnexpectedValueException('bad'); } foreach ($node->adaptations as $adaptation) { if ($adaptation instanceof PhpParser\Node\Stmt\TraitUseAdaptation\Alias) { $old_name = strtolower($adaptation->method->name); $new_name = $old_name; if ($adaptation->newName) { $new_name = strtolower($adaptation->newName->name); if ($new_name !== $old_name) { $storage->trait_alias_map[$new_name] = $old_name; $storage->trait_alias_map_cased[$adaptation->newName->name] = $adaptation->method->name; } } if ($adaptation->newModifier) { switch ($adaptation->newModifier) { case 1: $storage->trait_visibility_map[$new_name] = ClassLikeAnalyzer::VISIBILITY_PUBLIC; break; case 2: $storage->trait_visibility_map[$new_name] = ClassLikeAnalyzer::VISIBILITY_PROTECTED; break; case 4: $storage->trait_visibility_map[$new_name] = ClassLikeAnalyzer::VISIBILITY_PRIVATE; break; case 32: $storage->trait_final_map[$new_name] = \true; break; } } } } foreach ($node->traits as $trait) { $trait_fqcln = ClassLikeAnalyzer::getFQCLNFromNameObject($trait, $this->aliases); $this->codebase->scanner->queueClassLikeForScanning($trait_fqcln, $this->file_scanner->will_analyze); $storage->used_traits[strtolower($trait_fqcln)] = $trait_fqcln; $this->file_storage->required_classes[strtolower($trait_fqcln)] = $trait_fqcln; } if ($node_comment = $node->getDocComment()) { $comments = DocComment::parsePreservingLength($node_comment); if (isset($comments->combined_tags['use'])) { foreach ($comments->combined_tags['use'] as $template_line) { $this->useTemplatedType($storage, $node, trim(preg_replace('@^[ \\t]*\\*@m', '', $template_line))); } } if (isset($comments->tags['template-extends']) || isset($comments->tags['extends']) || isset($comments->tags['template-implements']) || isset($comments->tags['implements'])) { $storage->docblock_issues[] = new InvalidDocblock('You must use @use or @template-use to parameterize traits', new CodeLocation($this->file_scanner, $node, null, \true)); } } } private function extendTemplatedType(ClassLikeStorage $storage, PhpParser\Node\Stmt\ClassLike $node, string $extended_class_name) : void { if (trim($extended_class_name) === '') { $storage->docblock_issues[] = new InvalidDocblock('Extended class cannot be empty in docblock for ' . $storage->name, new CodeLocation($this->file_scanner, $node, null, \true)); return; } try { $extended_union_type = TypeParser::parseTokens(TypeTokenizer::getFullyQualifiedTokens($extended_class_name, $this->aliases, $this->class_template_types, $this->type_aliases), null, $this->class_template_types, $this->type_aliases, \true); } catch (TypeParseTreeException $e) { $storage->docblock_issues[] = new InvalidDocblock($e->getMessage() . ' in docblock for ' . $storage->name, new CodeLocation($this->file_scanner, $node, null, \true)); return; } if (!$extended_union_type->isSingle()) { $storage->docblock_issues[] = new InvalidDocblock('@template-extends cannot be a union type', new CodeLocation($this->file_scanner, $node, null, \true)); } /** @psalm-suppress UnusedMethodCall */ $extended_union_type->queueClassLikesForScanning($this->codebase, $this->file_storage, $storage->template_types ?: []); foreach ($extended_union_type->getAtomicTypes() as $atomic_type) { if (!$atomic_type instanceof TGenericObject) { $storage->docblock_issues[] = new InvalidDocblock('@template-extends has invalid class ' . $atomic_type->getId(), new CodeLocation($this->file_scanner, $node, null, \true)); return; } $generic_class_lc = strtolower($atomic_type->value); if (!isset($storage->parent_classes[$generic_class_lc]) && !isset($storage->parent_interfaces[$generic_class_lc])) { $storage->docblock_issues[] = new InvalidDocblock('@template-extends must include the name of an extended class,' . ' got ' . $atomic_type->getId(), new CodeLocation($this->file_scanner, $node, null, \true)); } $extended_type_parameters = []; $storage->template_type_extends_count[$atomic_type->value] = count($atomic_type->type_params); foreach ($atomic_type->type_params as $type_param) { $extended_type_parameters[] = $type_param; } $storage->template_extended_offsets[$atomic_type->value] = $extended_type_parameters; } } private function implementTemplatedType(ClassLikeStorage $storage, PhpParser\Node\Stmt\ClassLike $node, string $implemented_class_name) : void { if (trim($implemented_class_name) === '') { $storage->docblock_issues[] = new InvalidDocblock('Extended class cannot be empty in docblock for ' . $storage->name, new CodeLocation($this->file_scanner, $node, null, \true)); return; } try { $implemented_union_type = TypeParser::parseTokens(TypeTokenizer::getFullyQualifiedTokens($implemented_class_name, $this->aliases, $this->class_template_types, $this->type_aliases), null, $this->class_template_types, $this->type_aliases, \true); } catch (TypeParseTreeException $e) { $storage->docblock_issues[] = new InvalidDocblock($e->getMessage() . ' in docblock for ' . $storage->name, new CodeLocation($this->file_scanner, $node, null, \true)); return; } if (!$implemented_union_type->isSingle()) { $storage->docblock_issues[] = new InvalidDocblock('@template-implements cannot be a union type', new CodeLocation($this->file_scanner, $node, null, \true)); return; } /** @psalm-suppress UnusedMethodCall */ $implemented_union_type->queueClassLikesForScanning($this->codebase, $this->file_storage, $storage->template_types ?: []); foreach ($implemented_union_type->getAtomicTypes() as $atomic_type) { if (!$atomic_type instanceof TGenericObject) { $storage->docblock_issues[] = new InvalidDocblock('@template-implements has invalid class ' . $atomic_type->getId(), new CodeLocation($this->file_scanner, $node, null, \true)); return; } $generic_class_lc = strtolower($atomic_type->value); if (!isset($storage->class_implements[$generic_class_lc])) { $storage->docblock_issues[] = new InvalidDocblock('@template-implements must include the name of an implemented class,' . ' got ' . $atomic_type->getId(), new CodeLocation($this->file_scanner, $node, null, \true)); return; } $implemented_type_parameters = []; $storage->template_type_implements_count[$generic_class_lc] = count($atomic_type->type_params); foreach ($atomic_type->type_params as $type_param) { $implemented_type_parameters[] = $type_param; } $storage->template_extended_offsets[$atomic_type->value] = $implemented_type_parameters; } } private function useTemplatedType(ClassLikeStorage $storage, PhpParser\Node\Stmt\TraitUse $node, string $used_class_name) : void { if (trim($used_class_name) === '') { $storage->docblock_issues[] = new InvalidDocblock('Extended class cannot be empty in docblock for ' . $storage->name, new CodeLocation($this->file_scanner, $node, null, \true)); return; } try { $used_union_type = TypeParser::parseTokens(TypeTokenizer::getFullyQualifiedTokens($used_class_name, $this->aliases, $this->class_template_types, $this->type_aliases), null, $this->class_template_types, $this->type_aliases, \true); } catch (TypeParseTreeException $e) { $storage->docblock_issues[] = new InvalidDocblock($e->getMessage() . ' in docblock for ' . $storage->name, new CodeLocation($this->file_scanner, $node, null, \true)); return; } if (!$used_union_type->isSingle()) { $storage->docblock_issues[] = new InvalidDocblock('@template-use cannot be a union type', new CodeLocation($this->file_scanner, $node, null, \true)); return; } /** @psalm-suppress UnusedMethodCall */ $used_union_type->queueClassLikesForScanning($this->codebase, $this->file_storage, $storage->template_types ?: []); foreach ($used_union_type->getAtomicTypes() as $atomic_type) { if (!$atomic_type instanceof TGenericObject) { $storage->docblock_issues[] = new InvalidDocblock('@template-use has invalid class ' . $atomic_type->getId(), new CodeLocation($this->file_scanner, $node, null, \true)); return; } $generic_class_lc = strtolower($atomic_type->value); if (!isset($storage->used_traits[$generic_class_lc])) { $storage->docblock_issues[] = new InvalidDocblock('@template-use must include the name of an used class,' . ' got ' . $atomic_type->getId(), new CodeLocation($this->file_scanner, $node, null, \true)); return; } $used_type_parameters = []; $storage->template_type_uses_count[$generic_class_lc] = count($atomic_type->type_params); foreach ($atomic_type->type_params as $type_param) { $used_type_parameters[] = $type_param->replaceClassLike('self', $storage->name); } $storage->template_extended_offsets[$atomic_type->value] = $used_type_parameters; } } private static function registerEmptyConstructor(ClassLikeStorage $class_storage) : void { $method_name_lc = '__construct'; if (isset($class_storage->methods[$method_name_lc])) { return; } $storage = $class_storage->methods['__construct'] = new MethodStorage(); $storage->cased_name = '__construct'; $storage->defining_fqcln = $class_storage->name; $storage->mutation_free = $storage->external_mutation_free = \true; $storage->mutation_free_inferred = \true; $class_storage->declaring_method_ids['__construct'] = new MethodIdentifier($class_storage->name, '__construct'); $class_storage->inheritable_method_ids['__construct'] = $class_storage->declaring_method_ids['__construct']; $class_storage->appearing_method_ids['__construct'] = $class_storage->declaring_method_ids['__construct']; $class_storage->overridden_method_ids['__construct'] = []; $storage->visibility = ClassLikeAnalyzer::VISIBILITY_PUBLIC; } private function visitClassConstDeclaration(PhpParser\Node\Stmt\ClassConst $stmt, ClassLikeStorage $storage, string $fq_classlike_name) : void { if ($storage->is_trait && $this->codebase->analysis_php_version_id < 80200) { IssueBuffer::maybeAdd(new ConstantDeclarationInTrait('Traits cannot declare constants until PHP 8.2.0', new CodeLocation($this->file_scanner, $stmt))); return; } $existing_constants = $storage->constants; $comment = $stmt->getDocComment(); $var_comment = null; $deprecated = \false; $description = null; $config = $this->config; if ($comment && $comment->getText() && ($config->use_docblock_types || $config->use_docblock_property_types)) { $comments = DocComment::parsePreservingLength($comment); if (isset($comments->tags['deprecated'])) { $deprecated = \true; } $description = $comments->description; try { $var_comments = CommentAnalyzer::getTypeFromComment($comment, $this->file_scanner, $this->aliases, [], $this->type_aliases); $var_comment = array_pop($var_comments); } catch (IncorrectDocblockException $e) { $storage->docblock_issues[] = new MissingDocblockType($e->getMessage(), new CodeLocation($this->file_scanner, $stmt, null, \true)); } catch (DocblockParseException $e) { $storage->docblock_issues[] = new InvalidDocblock($e->getMessage(), new CodeLocation($this->file_scanner, $stmt, null, \true)); } } foreach ($stmt->consts as $const) { if (isset($storage->constants[$const->name->name]) || isset($storage->enum_cases[$const->name->name])) { IssueBuffer::maybeAdd(new DuplicateConstant('Constant names should be unique', new CodeLocation($this->file_scanner, $const), $fq_classlike_name)); continue; } $inferred_type = SimpleTypeInferer::infer($this->codebase, new NodeDataProvider(), $const->value, $this->aliases, null, $existing_constants, $fq_classlike_name); $type_location = null; if ($var_comment && $var_comment->type !== null) { $const_type = $var_comment->type; if ($var_comment->type_start !== null && $var_comment->type_end !== null && $var_comment->line_number !== null) { $type_location = new DocblockTypeLocation($this->file_scanner, $var_comment->type_start, $var_comment->type_end, $var_comment->line_number); } } else { $const_type = $inferred_type; } $suppressed_issues = $var_comment ? $var_comment->suppressed_issues : []; $attributes = []; foreach ($stmt->attrGroups as $attr_group) { foreach ($attr_group->attrs as $attr) { $attributes[] = \Psalm\Internal\PhpVisitor\Reflector\AttributeResolver::resolve($this->codebase, $this->file_scanner, $this->file_storage, $this->aliases, $attr, $this->storage->name ?? null); } } $unresolved_node = null; if ($inferred_type && !($const->value instanceof Concat && $inferred_type->isSingle() && get_class($inferred_type->getSingleAtomic()) === TString::class)) { $exists = \true; } else { $exists = \false; $unresolved_const_expr = \Psalm\Internal\PhpVisitor\Reflector\ExpressionResolver::getUnresolvedClassConstExpr($const->value, $this->aliases, $fq_classlike_name, $storage->parent_class); if ($unresolved_const_expr) { $unresolved_node = $unresolved_const_expr; } else { $const_type = Type::getMixed(); } } $storage->constants[$const->name->name] = $constant_storage = new ClassConstantStorage($const_type, $inferred_type, $stmt->isProtected() ? ClassLikeAnalyzer::VISIBILITY_PROTECTED : ($stmt->isPrivate() ? ClassLikeAnalyzer::VISIBILITY_PRIVATE : ClassLikeAnalyzer::VISIBILITY_PUBLIC), new CodeLocation($this->file_scanner, $const->name), $type_location, new CodeLocation($this->file_scanner, $const), $deprecated, $stmt->isFinal(), $unresolved_node, $attributes, $suppressed_issues, $description); if ($this->codebase->analysis_php_version_id >= 80300 && !$storage->final && $stmt->type === null) { IssueBuffer::maybeAdd(new MissingClassConstType(sprintf('Class constant "%s::%s" should have a declared type.', $storage->name, $const->name->name), new CodeLocation($this->file_scanner, $const)), $suppressed_issues); } if ($exists) { $existing_constants[$const->name->name] = $constant_storage; } } } private function visitEnumDeclaration(PhpParser\Node\Stmt\EnumCase $stmt, ClassLikeStorage $storage, string $fq_classlike_name) : void { if (isset($storage->constants[$stmt->name->name])) { IssueBuffer::maybeAdd(new DuplicateConstant('Constant names should be unique', new CodeLocation($this->file_scanner, $stmt), $fq_classlike_name)); return; } $enum_value = null; $case_location = new CodeLocation($this->file_scanner, $stmt); if ($stmt->expr !== null) { $case_type = SimpleTypeInferer::infer($this->codebase, new NodeDataProvider(), $stmt->expr, $this->aliases, $this->file_scanner, $storage->constants, $fq_classlike_name); if ($case_type) { if ($case_type->isSingleIntLiteral()) { $enum_value = $case_type->getSingleIntLiteral()->value; } elseif ($case_type->isSingleStringLiteral()) { $enum_value = $case_type->getSingleStringLiteral()->value; } else { IssueBuffer::maybeAdd(new InvalidEnumCaseValue('Case of a backed enum should have either string or int value', $case_location, $fq_classlike_name)); } } else { $enum_value = \Psalm\Internal\PhpVisitor\Reflector\ExpressionResolver::getUnresolvedClassConstExpr($stmt->expr, $this->aliases, $fq_classlike_name, $storage->parent_class); } } if (!isset($storage->enum_cases[$stmt->name->name])) { $case = new EnumCaseStorage($enum_value, $case_location); $attrs = $this->getAttributeStorageFromStatement($this->codebase, $this->file_scanner, $this->file_storage, $this->aliases, $stmt, $this->storage->name ?? null); foreach ($attrs as $attribute) { if ($attribute->fq_class_name === 'Psalm\\Deprecated' || $attribute->fq_class_name === 'JetBrains\\PhpStorm\\Deprecated') { $case->deprecated = \true; break; } } $comment = $stmt->getDocComment(); if ($comment) { $comments = DocComment::parsePreservingLength($comment); if (isset($comments->tags['deprecated'])) { $case->deprecated = \true; } } $storage->enum_cases[$stmt->name->name] = $case; } else { IssueBuffer::maybeAdd(new DuplicateEnumCase('Enum case names should be unique', $case_location, $fq_classlike_name)); } } /** * @param PhpParser\Node\Stmt\Property|PhpParser\Node\Stmt\EnumCase $stmt * @return list */ private function getAttributeStorageFromStatement(Codebase $codebase, FileScanner $file_scanner, FileStorage $file_storage, Aliases $aliases, PhpParser\Node\Stmt $stmt, ?string $fq_classlike_name) : array { $storages = []; foreach ($stmt->attrGroups as $attr_group) { foreach ($attr_group->attrs as $attr) { $storages[] = \Psalm\Internal\PhpVisitor\Reflector\AttributeResolver::resolve($codebase, $file_scanner, $file_storage, $aliases, $attr, $fq_classlike_name); } } return $storages; } /** * @param non-empty-string $fq_classlike_name */ private function visitPropertyDeclaration(PhpParser\Node\Stmt\Property $stmt, Config $config, ClassLikeStorage $storage, string $fq_classlike_name) : void { $comment = $stmt->getDocComment(); $var_comment = null; $property_is_initialized = \false; $existing_constants = $storage->constants; if ($comment && $comment->getText() && ($config->use_docblock_types || $config->use_docblock_property_types)) { if (preg_match('/[ \\t\\*]+@psalm-suppress[ \\t]+PropertyNotSetInConstructor/', (string) $comment)) { $property_is_initialized = \true; } if (preg_match('/[ \\t\\*]+@property[ \\t]+/', (string) $comment)) { $storage->docblock_issues[] = new InvalidDocblock('@property is valid only in docblocks for class', new CodeLocation($this->file_scanner, $stmt, null, \true)); } try { $var_comments = CommentAnalyzer::getTypeFromComment($comment, $this->file_scanner, $this->aliases, !$stmt->isStatic() ? $this->class_template_types : [], $this->type_aliases); $var_comment = array_pop($var_comments); } catch (IncorrectDocblockException $e) { $storage->docblock_issues[] = new MissingDocblockType($e->getMessage(), new CodeLocation($this->file_scanner, $stmt, null, \true)); } catch (DocblockParseException $e) { $storage->docblock_issues[] = new InvalidDocblock($e->getMessage(), new CodeLocation($this->file_scanner, $stmt, null, \true)); } } $signature_type = null; $signature_type_location = null; if ($stmt->type) { $parser_property_type = $stmt->type; /** @var Identifier|IntersectionType|Name|NullableType|UnionType $parser_property_type */ $signature_type_location = new CodeLocation($this->file_scanner, $parser_property_type, null, \false, CodeLocation::FUNCTION_RETURN_TYPE); $signature_type = \Psalm\Internal\PhpVisitor\Reflector\TypeHintResolver::resolve($parser_property_type, $signature_type_location, $this->codebase, $this->file_storage, $this->storage, $this->aliases, $this->codebase->analysis_php_version_id); } $doc_var_group_type = $var_comment->type ?? null; if ($doc_var_group_type) { /** @psalm-suppress UnusedMethodCall */ $doc_var_group_type->queueClassLikesForScanning($this->codebase, $this->file_storage); } foreach ($stmt->props as $property) { $doc_var_location = null; $property_storage = $storage->properties[$property->name->name] = new PropertyStorage(); $property_storage->is_static = $stmt->isStatic(); $property_storage->type = $signature_type; $property_storage->signature_type = $signature_type; $property_storage->signature_type_location = $signature_type_location; $property_storage->type_location = $signature_type_location; $property_storage->location = new CodeLocation($this->file_scanner, $property->name); $property_storage->stmt_location = new CodeLocation($this->file_scanner, $stmt); $property_storage->has_default = (bool) $property->default; $property_storage->deprecated = $var_comment ? $var_comment->deprecated : \false; $property_storage->suppressed_issues = $var_comment ? $var_comment->suppressed_issues : []; $property_storage->internal = $var_comment ? $var_comment->psalm_internal : []; if (count($property_storage->internal) === 0 && $var_comment && $var_comment->internal) { $property_storage->internal = [NamespaceAnalyzer::getNameSpaceRoot($fq_classlike_name)]; } $property_storage->readonly = $storage->readonly || $stmt->isReadonly() || $var_comment && $var_comment->readonly; $property_storage->allow_private_mutation = $var_comment ? $var_comment->allow_private_mutation : \false; $property_storage->description = $var_comment ? $var_comment->description : null; if (!$signature_type && $storage->readonly) { IssueBuffer::maybeAdd(new MissingPropertyType('Properties of readonly classes must have a type', new CodeLocation($this->file_scanner, $stmt, null, \true), $fq_classlike_name . '::$' . $property->name->name)); } if (!$signature_type && !$doc_var_group_type) { if ($property->default) { $property_storage->suggested_type = SimpleTypeInferer::infer($this->codebase, new NodeDataProvider(), $property->default, $this->aliases, null, $existing_constants, $fq_classlike_name); } $property_storage->type = null; } else { if ($var_comment && $var_comment->type_start && $var_comment->type_end && $var_comment->line_number) { $doc_var_location = new DocblockTypeLocation($this->file_scanner, $var_comment->type_start, $var_comment->type_end, $var_comment->line_number); } if ($doc_var_group_type) { $property_storage->type = $doc_var_group_type; } } if ($property_storage->type && $property_storage->type !== $property_storage->signature_type) { if (!$property_storage->signature_type) { $property_storage->type_location = $doc_var_location; } if ($property_storage->signature_type) { $all_typehint_types_match = \true; $signature_atomic_types = $property_storage->signature_type->getAtomicTypes(); foreach ($property_storage->type->getAtomicTypes() as $key => $type) { if (isset($signature_atomic_types[$key])) { /** @psalm-suppress InaccessibleProperty We just created this type */ $type->from_docblock = \false; } else { $all_typehint_types_match = \false; } } if ($all_typehint_types_match) { /** @psalm-suppress InaccessibleProperty We just created this type */ $property_storage->type->from_docblock = \false; } if ($property_storage->signature_type->isNullable() && !$property_storage->type->isNullable()) { $property_storage->type = $property_storage->type->getBuilder()->addType(new TNull())->freeze(); } } /** @psalm-suppress UnusedMethodCall */ $property_storage->type->queueClassLikesForScanning($this->codebase, $this->file_storage); } if ($stmt->isPublic()) { $property_storage->visibility = ClassLikeAnalyzer::VISIBILITY_PUBLIC; } elseif ($stmt->isProtected()) { $property_storage->visibility = ClassLikeAnalyzer::VISIBILITY_PROTECTED; } elseif ($stmt->isPrivate()) { $property_storage->visibility = ClassLikeAnalyzer::VISIBILITY_PRIVATE; } $property_id = $fq_classlike_name . '::$' . $property->name->name; $storage->declaring_property_ids[$property->name->name] = $fq_classlike_name; $storage->appearing_property_ids[$property->name->name] = $property_id; if ($property_is_initialized) { $storage->initialized_properties[$property->name->name] = \true; } if (!$stmt->isPrivate()) { $storage->inheritable_property_ids[$property->name->name] = $property_id; } $attrs = $this->getAttributeStorageFromStatement($this->codebase, $this->file_scanner, $this->file_storage, $this->aliases, $stmt, $this->storage->name ?? null); foreach ($attrs as $attribute) { if ($attribute->fq_class_name === 'Psalm\\Deprecated' || $attribute->fq_class_name === 'JetBrains\\PhpStorm\\Deprecated') { $property_storage->deprecated = \true; } if ($attribute->fq_class_name === 'Psalm\\Internal' && !$property_storage->internal) { $property_storage->internal = [NamespaceAnalyzer::getNameSpaceRoot($fq_classlike_name)]; } if ($attribute->fq_class_name === 'Psalm\\Readonly') { $property_storage->readonly = \true; } $property_storage->attributes[] = $attribute; } } } /** * @return array */ private function getImportedTypeAliases(ClassLikeDocblockComment $comment, string $fq_classlike_name) : array { /** @var array $results */ $results = []; foreach ($comment->imported_types as $import_type_entry) { $imported_type_data = $import_type_entry['parts']; $location = new DocblockTypeLocation($this->file_scanner, $import_type_entry['start_offset'], $import_type_entry['end_offset'], $import_type_entry['line_number']); // There are two valid forms: // @psalm-import Thing from Something // @psalm-import Thing from Something as Alias // but there could be leftovers after that if (count($imported_type_data) < 3) { $this->file_storage->docblock_issues[] = new InvalidTypeImport('Invalid import in docblock for ' . $fq_classlike_name . ', expecting " from ",' . ' got "' . implode(' ', $imported_type_data) . '" instead.', $location); continue; } if ($imported_type_data[1] === 'from' && !empty($imported_type_data[0]) && !empty($imported_type_data[2])) { $type_alias_name = $as_alias_name = $imported_type_data[0]; $declaring_classlike_name = $imported_type_data[2]; } else { $this->file_storage->docblock_issues[] = new InvalidTypeImport('Invalid import in docblock for ' . $fq_classlike_name . ', expecting " from ", got "' . implode(' ', [$imported_type_data[0], $imported_type_data[1], $imported_type_data[2]]) . '" instead.', $location); continue; } if (count($imported_type_data) >= 4 && $imported_type_data[3] === 'as') { // long form if (empty($imported_type_data[4])) { $this->file_storage->docblock_issues[] = new InvalidTypeImport('Invalid import in docblock for ' . $fq_classlike_name . ', expecting "as ", got "' . $imported_type_data[3] . ' ' . ($imported_type_data[4] ?? '') . '" instead.', $location); continue; } $as_alias_name = $imported_type_data[4]; } $declaring_fq_classlike_name = Type::getFQCLNFromString($declaring_classlike_name, $this->aliases); $this->codebase->scanner->queueClassLikeForScanning($declaring_fq_classlike_name); $this->file_storage->referenced_classlikes[strtolower($declaring_fq_classlike_name)] = $declaring_fq_classlike_name; $results[$as_alias_name] = new LinkableTypeAlias($declaring_fq_classlike_name, $type_alias_name, $import_type_entry['line_number'], $import_type_entry['start_offset'], $import_type_entry['end_offset']); } return $results; } /** * @param array $type_aliases * @return array * @throws DocblockParseException if there was a problem parsing the docblock */ public static function getTypeAliasesFromComment(PhpParser\Comment\Doc $comment, Aliases $aliases, ?array $type_aliases, ?string $self_fqcln) : array { $parsed_docblock = DocComment::parsePreservingLength($comment); if (!isset($parsed_docblock->tags['psalm-type']) && !isset($parsed_docblock->tags['phpstan-type'])) { return []; } $type_alias_comment_lines = array_merge($parsed_docblock->tags['phpstan-type'] ?? [], $parsed_docblock->tags['psalm-type'] ?? []); return self::getTypeAliasesFromCommentLines($type_alias_comment_lines, $aliases, $type_aliases, $self_fqcln); } /** * @param array $type_alias_comment_lines * @param array $type_aliases * @return array * @throws DocblockParseException if there was a problem parsing the docblock */ private static function getTypeAliasesFromCommentLines(array $type_alias_comment_lines, Aliases $aliases, ?array $type_aliases, ?string $self_fqcln) : array { $type_alias_tokens = []; foreach ($type_alias_comment_lines as $var_line) { $var_line = trim($var_line); if (!$var_line) { continue; } $var_line_parts = preg_split('/( |=)/', $var_line, -1, PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_NO_EMPTY); if (!$var_line_parts) { continue; } $type_alias = array_shift($var_line_parts); if (!isset($var_line_parts[0])) { continue; } while (isset($var_line_parts[0]) && $var_line_parts[0] === ' ') { array_shift($var_line_parts); } if (!isset($var_line_parts[0])) { continue; } if ($var_line_parts[0] === '=') { array_shift($var_line_parts); } if (!isset($var_line_parts[0])) { continue; } while (isset($var_line_parts[0]) && $var_line_parts[0] === ' ') { array_shift($var_line_parts); } $type_string = implode('', $var_line_parts); $type_string = ltrim($type_string, "* \n\r"); try { $type_string = CommentAnalyzer::splitDocLine($type_string)[0]; } catch (DocblockParseException $e) { throw new DocblockParseException($type_string . ' is not a valid type: ' . $e->getMessage()); } $type_string = CommentAnalyzer::sanitizeDocblockType($type_string); try { $type_tokens = TypeTokenizer::getFullyQualifiedTokens($type_string, $aliases, null, $type_alias_tokens + $type_aliases, $self_fqcln); } catch (TypeParseTreeException $e) { throw new DocblockParseException($type_string . ' is not a valid type: ' . $e->getMessage()); } $type_alias_tokens[$type_alias] = new InlineTypeAlias($type_tokens); } return $type_alias_tokens; } } types) { throw new UnexpectedValueException('Union type should not be empty'); } if ($analysis_php_version_id < 80000) { IssueBuffer::maybeAdd(new ParseError('Union types are not supported in PHP < 8', $code_location)); } foreach ($hint->types as $atomic_typehint) { $resolved_type = self::resolve($atomic_typehint, $code_location, $codebase, $file_storage, $classlike_storage, $aliases, $analysis_php_version_id); $type = Type::combineUnionTypes($resolved_type, $type); } return $type; } if ($hint instanceof PhpParser\Node\IntersectionType) { $type = null; if (!$hint->types) { throw new UnexpectedValueException('Intersection type should not be empty'); } if ($analysis_php_version_id < 80100) { IssueBuffer::maybeAdd(new ParseError('Intersection types are not supported in PHP < 8.1', $code_location)); } foreach ($hint->types as $atomic_typehint) { $resolved_type = self::resolve($atomic_typehint, $code_location, $codebase, $file_storage, $classlike_storage, $aliases, $analysis_php_version_id); if ($resolved_type->hasScalarType()) { IssueBuffer::maybeAdd(new ParseError('Intersection types cannot contain scalar types', $code_location)); } $type = Type::intersectUnionTypes($resolved_type, $type, $codebase); } if ($type === null) { $type = Type::getNever(); } return $type; } $is_nullable = \false; if ($hint instanceof PhpParser\Node\NullableType) { $is_nullable = \true; $hint = $hint->type; } $type_string = null; if ($hint instanceof PhpParser\Node\Identifier) { $fq_type_string = $hint->name; } elseif ($hint instanceof PhpParser\Node\Name\FullyQualified) { $fq_type_string = (string) $hint; $codebase->scanner->queueClassLikeForScanning($fq_type_string); $file_storage->referenced_classlikes[strtolower($fq_type_string)] = $fq_type_string; } else { $lower_hint = strtolower($hint->getFirst()); if ($classlike_storage && ($lower_hint === 'self' || $lower_hint === 'static') && !$classlike_storage->is_trait) { $fq_type_string = $classlike_storage->name; if ($lower_hint === 'static') { $fq_type_string .= '&static'; } } else { $type_string = $hint->toString(); $fq_type_string = ClassLikeAnalyzer::getFQCLNFromNameObject($hint, $aliases); $codebase->scanner->queueClassLikeForScanning($fq_type_string); $file_storage->referenced_classlikes[strtolower($fq_type_string)] = $fq_type_string; } } $type = Type::parseString($fq_type_string, $analysis_php_version_id, []); if ($type_string) { $atomic_type = $type->getSingleAtomic(); /** @psalm-suppress InaccessibleProperty We just created this type */ $atomic_type->text = $type_string; } if ($is_nullable) { $type = $type->getBuilder()->addType(new TNull())->freeze(); } return $type; } } > */ private array $existing_function_template_types; private Aliases $aliases; /** * @var array */ private array $type_aliases; public ?FunctionLikeStorage $storage = null; /** * @param array> $existing_function_template_types * @param array $type_aliases */ public function __construct(Codebase $codebase, FileScanner $file_scanner, FileStorage $file_storage, Aliases $aliases, array $type_aliases, ?ClassLikeStorage $classlike_storage, array $existing_function_template_types) { $this->codebase = $codebase; $this->file_storage = $file_storage; $this->file_scanner = $file_scanner; $this->file_path = $file_storage->file_path; $this->aliases = $aliases; $this->type_aliases = $type_aliases; $this->config = Config::getInstance(); $this->classlike_storage = $classlike_storage; $this->existing_function_template_types = $existing_function_template_types; } /** * @param bool $fake_method in the case of @method annotations we do something a little strange * @return FunctionStorage|MethodStorage|false */ public function start(PhpParser\Node\FunctionLike $stmt, bool $fake_method = \false) { if ($stmt instanceof PhpParser\Node\Expr\Closure || $stmt instanceof PhpParser\Node\Expr\ArrowFunction) { $this->codebase->scanner->queueClassLikeForScanning('Closure'); } $functionlike_info = $this->createStorageForFunctionLike($stmt, $fake_method); if ($functionlike_info === \false) { return \false; } [$cased_function_id, $storage, $function_id, $fq_classlike_name, $method_name_lc, $classlike_storage, $is_functionlike_override, $method_id, $is_dupe] = $functionlike_info; if ($is_dupe) { return $storage; } if ($stmt instanceof PhpParser\Node\Stmt\ClassMethod) { $storage->cased_name = $stmt->name->name; } elseif ($stmt instanceof PhpParser\Node\Stmt\Function_) { $storage->cased_name = ($this->aliases->namespace ? $this->aliases->namespace . '\\' : '') . $stmt->name->name; } if ($stmt instanceof PhpParser\Node\Stmt\ClassMethod || $stmt instanceof PhpParser\Node\Stmt\Function_) { $storage->location = new CodeLocation($this->file_scanner, $stmt->name, null, \true); } else { $storage->location = new CodeLocation($this->file_scanner, $stmt, null, \true); } $storage->stmt_location = new CodeLocation($this->file_scanner, $stmt); $required_param_count = 0; $i = 0; $has_optional_param = \false; $existing_params = []; $storage->setParams([]); foreach ($stmt->getParams() as $param) { if ($param->var instanceof PhpParser\Node\Expr\Error) { $storage->docblock_issues[] = new InvalidDocblock('Param' . ($i + 1) . ' of ' . $cased_function_id . ' has invalid syntax', new CodeLocation($this->file_scanner, $param, null, \true)); ++$i; continue; } $param_storage = $this->getTranslatedFunctionParam($param, $stmt, $fake_method, $fq_classlike_name); foreach ($param->attrGroups as $attr_group) { foreach ($attr_group->attrs as $attr) { $param_storage->attributes[] = \Psalm\Internal\PhpVisitor\Reflector\AttributeResolver::resolve($this->codebase, $this->file_scanner, $this->file_storage, $this->aliases, $attr, $this->classlike_storage->name ?? null); } } if ($param_storage->name === 'haystack' && in_array($this->file_path, $this->codebase->config->internal_stubs)) { $param_storage->expect_variable = \true; } if (isset($existing_params['$' . $param_storage->name])) { $storage->docblock_issues[] = new DuplicateParam('Duplicate param $' . $param_storage->name . ' in docblock for ' . $cased_function_id, new CodeLocation($this->file_scanner, $param, null, \true)); ++$i; continue; } $existing_params['$' . $param_storage->name] = $i; $storage->addParam($param_storage, (bool) $param->type); if (!$param_storage->is_optional && !$param_storage->is_variadic) { $required_param_count = $i + 1; if (!$param->variadic && $has_optional_param) { foreach ($storage->params as $param) { $param->is_optional = \false; } } } else { $has_optional_param = \true; } ++$i; } $storage->required_param_count = $required_param_count; if ($stmt instanceof PhpParser\Node\Stmt\Function_ || $stmt instanceof PhpParser\Node\Stmt\ClassMethod) { if ($stmt instanceof PhpParser\Node\Stmt\ClassMethod && $storage instanceof MethodStorage && $classlike_storage && !$classlike_storage->mutation_free && $stmt->stmts && count($stmt->stmts) === 1 && !count($stmt->params) && $stmt->stmts[0] instanceof PhpParser\Node\Stmt\Return_ && $stmt->stmts[0]->expr instanceof PhpParser\Node\Expr\PropertyFetch && $stmt->stmts[0]->expr->var instanceof PhpParser\Node\Expr\Variable && $stmt->stmts[0]->expr->var->name === 'this' && $stmt->stmts[0]->expr->name instanceof PhpParser\Node\Identifier) { $property_name = $stmt->stmts[0]->expr->name->name; if (isset($classlike_storage->properties[$property_name]) && $classlike_storage->properties[$property_name]->type) { $storage->mutation_free = \true; $storage->external_mutation_free = \true; $storage->mutation_free_inferred = !$stmt->isFinal() && !$classlike_storage->final; $classlike_storage->properties[$property_name]->getter_method = strtolower($stmt->name->name); } } elseif (strpos($stmt->name->name, 'assert') === 0 && $stmt->stmts) { $var_assertions = []; foreach ($stmt->stmts as $function_stmt) { if ($function_stmt instanceof PhpParser\Node\Stmt\If_) { $final_actions = ScopeAnalyzer::getControlActions($function_stmt->stmts, null, [], \false); if ($final_actions !== [ScopeAnalyzer::ACTION_END]) { $var_assertions = []; break; } $cond_id = spl_object_id($function_stmt->cond); $if_clauses = FormulaGenerator::getFormula($cond_id, $cond_id, $function_stmt->cond, $this->classlike_storage->name ?? null, $this->file_scanner, null); try { $negated_formula = Algebra::negateFormula($if_clauses); } catch (ComplicatedExpressionException $e) { $var_assertions = []; break; } $rules = Algebra::getTruthsFromFormula($negated_formula); if (!$rules) { $var_assertions = []; break; } foreach ($rules as $var_id => $rule) { foreach ($rule as $rule_part) { if (count($rule_part) > 1) { $var_assertions = []; continue 2; } if (isset($existing_params[$var_id])) { $param_offset = $existing_params[$var_id]; $var_assertions[] = new Possibilities($param_offset, $rule_part); } elseif (strpos($var_id, '$this->') === 0) { $var_assertions[] = new Possibilities($var_id, $rule_part); } } } } else { $var_assertions = []; break; } } $storage->assertions = $var_assertions; } if ($stmt instanceof PhpParser\Node\Stmt\ClassMethod && $stmt->stmts && $storage instanceof MethodStorage) { $last_stmt = end($stmt->stmts); if ($last_stmt instanceof PhpParser\Node\Stmt\Return_ && $last_stmt->expr instanceof PhpParser\Node\Expr\Variable && $last_stmt->expr->name === 'this') { $storage->probably_fluent = \true; } } } if (!$this->file_scanner->will_analyze && ($stmt instanceof PhpParser\Node\Stmt\Function_ || $stmt instanceof PhpParser\Node\Stmt\ClassMethod || $stmt instanceof PhpParser\Node\Expr\Closure) && $stmt->stmts) { // pick up func_get_args that would otherwise be missed foreach ($stmt->stmts as $function_stmt) { if ($function_stmt instanceof PhpParser\Node\Stmt\Expression && $function_stmt->expr instanceof PhpParser\Node\Expr\Assign && $function_stmt->expr->expr instanceof PhpParser\Node\Expr\FuncCall && $function_stmt->expr->expr->name instanceof PhpParser\Node\Name) { $inner_function_id = $function_stmt->expr->expr->name->toString(); if ($inner_function_id === 'func_get_arg' || $inner_function_id === 'func_get_args' || $inner_function_id === 'func_num_args') { $storage->variadic = \true; } } elseif ($function_stmt instanceof PhpParser\Node\Stmt\If_ && $function_stmt->cond instanceof PhpParser\Node\Expr\BinaryOp && $function_stmt->cond->left instanceof PhpParser\Node\Expr\BinaryOp\Equal && $function_stmt->cond->left->left instanceof PhpParser\Node\Expr\FuncCall && $function_stmt->cond->left->left->name instanceof PhpParser\Node\Name) { $inner_function_id = $function_stmt->cond->left->left->name->toString(); if ($inner_function_id === 'func_get_arg' || $inner_function_id === 'func_get_args' || $inner_function_id === 'func_num_args') { $storage->variadic = \true; } } } } $parser_return_type = $stmt->getReturnType(); if ($parser_return_type) { $original_type = $parser_return_type; /** @var Identifier|IntersectionType|Name|NullableType|UnionType $original_type */ $storage->return_type = \Psalm\Internal\PhpVisitor\Reflector\TypeHintResolver::resolve($original_type, new CodeLocation($this->file_scanner, $original_type), $this->codebase, $this->file_storage, $this->classlike_storage, $this->aliases, $this->codebase->analysis_php_version_id); $storage->return_type_location = new CodeLocation($this->file_scanner, $original_type); if ($stmt->returnsByRef()) { /** @psalm-suppress InaccessibleProperty We just created this type */ $storage->return_type->by_ref = \true; } $storage->signature_return_type = $storage->return_type; $storage->signature_return_type_location = $storage->return_type_location; } if ($stmt->returnsByRef()) { $storage->returns_by_ref = \true; } $doc_comment = $stmt->getDocComment(); if ($classlike_storage && !$classlike_storage->is_trait) { $storage->internal = [...$classlike_storage->internal, ...$storage->internal]; } if ($doc_comment) { try { $code_location = new CodeLocation($this->file_scanner, $stmt, null, \true); $docblock_info = \Psalm\Internal\PhpVisitor\Reflector\FunctionLikeDocblockParser::parse($doc_comment, $code_location, $cased_function_id); } catch (IncorrectDocblockException $e) { $storage->docblock_issues[] = new MissingDocblockType($e->getMessage() . ' in docblock for ' . $cased_function_id, new CodeLocation($this->file_scanner, $stmt, null, \true)); $docblock_info = null; } catch (DocblockParseException $e) { $storage->docblock_issues[] = new InvalidDocblock($e->getMessage() . ' in docblock for ' . $cased_function_id, new CodeLocation($this->file_scanner, $stmt, null, \true)); $docblock_info = null; } if ($docblock_info) { if ($docblock_info->since_php_major_version && !$this->aliases->namespace) { $analysis_major_php_version = $this->codebase->getMajorAnalysisPhpVersion(); $analysis_minor_php_version = $this->codebase->getMinorAnalysisPhpVersion(); if ($docblock_info->since_php_major_version > $analysis_major_php_version) { return \false; } if ($docblock_info->since_php_major_version === $analysis_major_php_version && $docblock_info->since_php_minor_version > $analysis_minor_php_version) { return \false; } } if ($stmt instanceof PhpParser\Node\Expr\Closure || $stmt instanceof PhpParser\Node\Expr\ArrowFunction) { if ($docblock_info->templates !== []) { $docblock_info->templates = []; $storage->docblock_issues[] = new InvalidDocblock('Templated closures are not supported', new CodeLocation($this->file_scanner, $stmt, null, \true)); } } \Psalm\Internal\PhpVisitor\Reflector\FunctionLikeDocblockScanner::addDocblockInfo($this->codebase, $this->file_scanner, $this->file_storage, $this->aliases, $this->type_aliases, $this->classlike_storage, $this->existing_function_template_types, $storage, $stmt, $docblock_info, $is_functionlike_override, $fake_method, $cased_function_id); } } // register the functionlike once the @since check has been completed if ($stmt instanceof PhpParser\Node\Stmt\Function_ && $function_id && $storage instanceof FunctionStorage) { if ($this->codebase->register_stub_files || $this->codebase->register_autoload_files && !$this->codebase->functions->hasStubbedFunction($function_id)) { $this->codebase->functions->addGlobalFunction($function_id, $storage); } $this->file_storage->functions[$function_id] = $storage; $this->file_storage->declaring_function_ids[$function_id] = strtolower($this->file_path); } elseif ($stmt instanceof PhpParser\Node\Stmt\ClassMethod && $classlike_storage && $storage instanceof MethodStorage && $method_name_lc && !$fake_method && $method_id) { $classlike_storage->methods[$method_name_lc] = $storage; $classlike_storage->declaring_method_ids[$method_name_lc] = $classlike_storage->appearing_method_ids[$method_name_lc] = $method_id; if (!$stmt->isPrivate() || $method_name_lc === '__construct' || $method_name_lc === '__clone' || $classlike_storage->is_trait) { $classlike_storage->inheritable_method_ids[$method_name_lc] = $method_id; } if (!isset($classlike_storage->overridden_method_ids[$method_name_lc])) { $classlike_storage->overridden_method_ids[$method_name_lc] = []; } if ($storage->final && $method_name_lc === '__construct') { // a bit of a hack, but makes sure that `new static` works for these classes $classlike_storage->preserve_constructor_signature = \true; } } elseif (($stmt instanceof PhpParser\Node\Expr\Closure || $stmt instanceof PhpParser\Node\Expr\ArrowFunction) && $function_id && $storage instanceof FunctionStorage) { $this->file_storage->functions[$function_id] = $storage; } if ($classlike_storage && $method_name_lc === '__construct') { foreach ($stmt->getParams() as $param) { if (!$param->flags || !$param->var instanceof PhpParser\Node\Expr\Variable) { continue; } $param_storage = null; foreach ($storage->params as $param_storage) { if ($param_storage->name === $param->var->name) { break; } } if (!$param_storage) { continue; } if (isset($classlike_storage->properties[$param_storage->name]) && $param_storage->location) { IssueBuffer::maybeAdd(new ParseError('Promoted property ' . $param_storage->name . ' clashes with an existing property', $param_storage->location)); $storage->has_visitor_issues = \true; $this->file_storage->has_visitor_issues = \true; continue; } $doc_comment = $param->getDocComment(); $var_comment_type = null; $var_comment_readonly = \false; $var_comment_allow_private_mutation = \false; if ($doc_comment) { $template_types = ($this->existing_function_template_types ?: []) + ($classlike_storage->template_types ?: []); $var_comments = CommentAnalyzer::getTypeFromComment($doc_comment, $this->file_scanner, $this->aliases, $template_types, $this->type_aliases); $var_comment = array_pop($var_comments); if ($var_comment !== null) { $var_comment_type = $var_comment->type; $var_comment_readonly = $var_comment->readonly; $var_comment_allow_private_mutation = $var_comment->allow_private_mutation; } } //both way to document type were used if ($param_storage->type && $param_storage->type->from_docblock && $var_comment_type) { if (IssueBuffer::accepts(new InvalidDocblock('Param ' . $param_storage->name . ' of ' . $cased_function_id . ' should be documented as a param or a property, not both', new CodeLocation($this->file_scanner, $param, null, \true)))) { return \false; } } //no docblock type was provided for param but we have one for property if ($var_comment_type) { $param_storage->type = $var_comment_type; } $property_storage = $classlike_storage->properties[$param_storage->name] = new PropertyStorage(); $property_storage->is_static = \false; $property_storage->type = $param_storage->type; $property_storage->signature_type = $param_storage->signature_type; $property_storage->signature_type_location = $param_storage->signature_type_location; $property_storage->type_location = $param_storage->type_location; $property_storage->location = $param_storage->location; $property_storage->stmt_location = new CodeLocation($this->file_scanner, $param); $property_storage->has_default = (bool) $param->default; $param_type_readonly = (bool) ($param->flags & PhpParser\Node\Stmt\Class_::MODIFIER_READONLY); $property_storage->readonly = $param_type_readonly ?: $var_comment_readonly; $property_storage->allow_private_mutation = $var_comment_allow_private_mutation; $param_storage->promoted_property = \true; $property_storage->is_promoted = \true; $property_id = $fq_classlike_name . '::$' . $param_storage->name; switch ($param->flags & Class_::VISIBILITY_MODIFIER_MASK) { case Class_::MODIFIER_PUBLIC: $property_storage->visibility = ClassLikeAnalyzer::VISIBILITY_PUBLIC; $classlike_storage->inheritable_property_ids[$param_storage->name] = $property_id; break; case Class_::MODIFIER_PROTECTED: $property_storage->visibility = ClassLikeAnalyzer::VISIBILITY_PROTECTED; $classlike_storage->inheritable_property_ids[$param_storage->name] = $property_id; break; case Class_::MODIFIER_PRIVATE: $property_storage->visibility = ClassLikeAnalyzer::VISIBILITY_PRIVATE; break; } $fq_classlike_name = $classlike_storage->name; $property_id = $fq_classlike_name . '::$' . $param_storage->name; $classlike_storage->declaring_property_ids[$param_storage->name] = $fq_classlike_name; $classlike_storage->appearing_property_ids[$param_storage->name] = $property_id; $classlike_storage->initialized_properties[$param_storage->name] = \true; } if ($stmt instanceof PhpParser\Node\Stmt\ClassMethod && $storage instanceof MethodStorage && $storage->params && $this->config->infer_property_types_from_constructor) { $this->inferPropertyTypeFromConstructor($stmt, $storage, $classlike_storage); } } foreach ($stmt->getAttrGroups() as $attr_group) { foreach ($attr_group->attrs as $attr) { $attribute = \Psalm\Internal\PhpVisitor\Reflector\AttributeResolver::resolve($this->codebase, $this->file_scanner, $this->file_storage, $this->aliases, $attr, $this->classlike_storage->name ?? null); if ($attribute->fq_class_name === 'Psalm\\Pure' || $attribute->fq_class_name === 'JetBrains\\PhpStorm\\Pure') { $storage->specialize_call = \true; $storage->mutation_free = \true; if ($storage instanceof MethodStorage) { $storage->external_mutation_free = \true; } } if ($attribute->fq_class_name === 'Psalm\\Deprecated' || $attribute->fq_class_name === 'JetBrains\\PhpStorm\\Deprecated') { $storage->deprecated = \true; } if ($attribute->fq_class_name === 'Psalm\\Internal' && !$storage->internal && $fq_classlike_name) { $storage->internal = [NamespaceAnalyzer::getNameSpaceRoot($fq_classlike_name)]; } if ($attribute->fq_class_name === 'Psalm\\ExternalMutationFree' && $storage instanceof MethodStorage) { $storage->external_mutation_free = \true; } if ($attribute->fq_class_name === 'JetBrains\\PhpStorm\\NoReturn') { $storage->return_type = Type::getNever(); } $storage->attributes[] = $attribute; } } return $storage; } private function inferPropertyTypeFromConstructor(PhpParser\Node\Stmt\ClassMethod $stmt, MethodStorage $storage, ClassLikeStorage $classlike_storage) : void { if (!$stmt->stmts) { return; } $assigned_properties = []; foreach ($stmt->stmts as $function_stmt) { if ($function_stmt instanceof PhpParser\Node\Stmt\Expression && $function_stmt->expr instanceof PhpParser\Node\Expr\Assign && $function_stmt->expr->var instanceof PhpParser\Node\Expr\PropertyFetch && $function_stmt->expr->var->var instanceof PhpParser\Node\Expr\Variable && $function_stmt->expr->var->var->name === 'this' && $function_stmt->expr->var->name instanceof PhpParser\Node\Identifier && ($property_name = $function_stmt->expr->var->name->name) && isset($classlike_storage->properties[$property_name]) && $function_stmt->expr->expr instanceof PhpParser\Node\Expr\Variable && is_string($function_stmt->expr->expr->name) && ($param_name = $function_stmt->expr->expr->name) && isset($storage->param_lookup[$param_name])) { if ($classlike_storage->properties[$property_name]->type || !$storage->param_lookup[$param_name]) { continue; } $param_index = array_search($param_name, array_keys($storage->param_lookup), \true); if ($param_index === \false || !isset($storage->params[$param_index]->type)) { continue; } $param_type = $storage->params[$param_index]->type; $assigned_properties[$property_name] = $storage->params[$param_index]->is_variadic ? new Union([new TArray([Type::getInt(), $param_type])]) : $param_type; } else { $assigned_properties = []; break; } } if (!$assigned_properties) { return; } $storage->external_mutation_free = \true; $storage->mutation_free_inferred = \true; foreach ($assigned_properties as $property_name => $property_type) { $classlike_storage->properties[$property_name]->type = $property_type; } } private function getTranslatedFunctionParam(PhpParser\Node\Param $param, PhpParser\Node\FunctionLike $stmt, bool $fake_method, ?string $fq_classlike_name) : FunctionLikeParameter { $param_type = null; $is_nullable = $param->default instanceof PhpParser\Node\Expr\ConstFetch && strtolower($param->default->name->getFirst()) === 'null'; $param_typehint = $param->type; if ($param_typehint) { /** @var Identifier|IntersectionType|Name|NullableType|UnionType $param_typehint */ $param_type = \Psalm\Internal\PhpVisitor\Reflector\TypeHintResolver::resolve($param_typehint, new CodeLocation($this->file_scanner, $param_typehint), $this->codebase, $this->file_storage, $this->classlike_storage, $this->aliases, $this->codebase->analysis_php_version_id); if ($param_type->isMixed()) { $is_nullable = \false; } elseif ($is_nullable) { $param_type = $param_type->getBuilder()->addType(new TNull())->freeze(); } else { $is_nullable = $param_type->isNullable(); } } $is_optional = $param->default !== null; if ($param->var instanceof PhpParser\Node\Expr\Error || !is_string($param->var->name)) { throw new UnexpectedValueException('Not expecting param name to be non-string'); } $default_type = null; if ($param->default) { $default_type = SimpleTypeInferer::infer($this->codebase, new NodeDataProvider(), $param->default, $this->aliases, null, null, $fq_classlike_name); if (!$default_type) { $default_type = \Psalm\Internal\PhpVisitor\Reflector\ExpressionResolver::getUnresolvedClassConstExpr($param->default, $this->aliases, $fq_classlike_name); } } return new FunctionLikeParameter($param->var->name, $param->byRef, $param_type, $param_type, new CodeLocation($this->file_scanner, $fake_method ? $stmt : $param->var, null, \false, !$fake_method ? CodeLocation::FUNCTION_PARAM_VAR : CodeLocation::FUNCTION_PHPDOC_METHOD), $param_typehint ? new CodeLocation($this->file_scanner, $fake_method ? $stmt : $param, null, \false, CodeLocation::FUNCTION_PARAM_TYPE) : null, $is_optional, $is_nullable, $param->variadic, $default_type); } //phpcs:disable -- Remove this once the phpstan phpdoc parser MR is merged /** * @return array{ * string, * FunctionStorage|MethodStorage, * null|string, * null|string, * null|lowercase-string, * ClassLikeStorage|null, * bool, * MethodIdentifier|null, * bool * }|false */ private function createStorageForFunctionLike(PhpParser\Node\FunctionLike $stmt, bool $fake_method) { //phpcs:enable -- Remove this once the phpstan phpdoc parser MR is merged $classlike_storage = null; $fq_classlike_name = null; $is_functionlike_override = \false; $function_id = null; $method_name_lc = null; $method_id = null; if ($fake_method && $stmt instanceof PhpParser\Node\Stmt\ClassMethod) { $cased_function_id = '@method ' . $stmt->name->name; $storage = $this->storage = new MethodStorage(); $storage->defining_fqcln = ''; $storage->is_static = $stmt->isStatic(); $storage->final = $this->classlike_storage && $this->classlike_storage->final; $storage->final_from_docblock = $this->classlike_storage && $this->classlike_storage->final_from_docblock; } elseif ($stmt instanceof PhpParser\Node\Stmt\Function_) { $cased_function_id = ($this->aliases->namespace ? $this->aliases->namespace . '\\' : '') . $stmt->name->name; $function_id = strtolower($cased_function_id); $storage = $this->storage = new FunctionStorage(); if ($this->codebase->register_stub_files || $this->codebase->register_autoload_files) { if (isset($this->file_storage->functions[$function_id]) && ($this->codebase->register_stub_files || !$this->codebase->functions->hasStubbedFunction($function_id))) { $this->codebase->functions->addGlobalFunction($function_id, $this->file_storage->functions[$function_id]); $storage = $this->storage = $this->file_storage->functions[$function_id]; return [$function_id, $storage, null, null, null, null, \false, null, \true]; } } else { if (isset($this->file_storage->functions[$function_id])) { $duplicate_function_storage = $this->file_storage->functions[$function_id]; if ($duplicate_function_storage->location && $duplicate_function_storage->location->getLineNumber() === $stmt->getLine()) { $storage = $this->storage = $this->file_storage->functions[$function_id]; return [$function_id, $storage, null, null, null, null, \false, null, \true]; } IssueBuffer::maybeAdd(new DuplicateFunction('Method ' . $function_id . ' has already been defined' . ($duplicate_function_storage->location ? ' in ' . $duplicate_function_storage->location->file_path : ''), new CodeLocation($this->file_scanner, $stmt, null, \true))); $this->file_storage->has_visitor_issues = \true; $duplicate_function_storage->has_visitor_issues = \true; $storage = $this->storage = $this->file_storage->functions[$function_id]; return [$function_id, $storage, null, null, null, null, \false, null, \true]; } if (isset($this->config->getPredefinedFunctions()[$function_id])) { /** @psalm-suppress ArgumentTypeCoercion */ $reflection_function = new ReflectionFunction($function_id); if ($reflection_function->getFileName() !== $this->file_path) { IssueBuffer::maybeAdd(new DuplicateFunction('Method ' . $function_id . ' has already been defined as a core function', new CodeLocation($this->file_scanner, $stmt, null, \true))); } } } } elseif ($stmt instanceof PhpParser\Node\Stmt\ClassMethod) { if (!$this->classlike_storage) { throw new LogicException('$this->classlike_storage should not be null'); } $fq_classlike_name = $this->classlike_storage->name; $method_name_lc = strtolower($stmt->name->name); $function_id = $fq_classlike_name . '::' . $method_name_lc; $cased_function_id = $fq_classlike_name . '::' . $stmt->name->name; $classlike_storage = $this->classlike_storage; $storage = null; if (isset($classlike_storage->methods[$method_name_lc])) { if (!$this->codebase->register_stub_files) { $duplicate_method_storage = $classlike_storage->methods[$method_name_lc]; IssueBuffer::maybeAdd(new DuplicateMethod('Method ' . $function_id . ' has already been defined' . ($duplicate_method_storage->location ? ' in ' . $duplicate_method_storage->location->file_path : ''), new CodeLocation($this->file_scanner, $stmt, null, \true))); $this->file_storage->has_visitor_issues = \true; $duplicate_method_storage->has_visitor_issues = \true; return \false; } // skip methods based on @since docblock tag $doc_comment = $stmt->getDocComment(); if ($doc_comment) { $docblock_info = null; try { $code_location = new CodeLocation($this->file_scanner, $stmt, null, \true); $docblock_info = \Psalm\Internal\PhpVisitor\Reflector\FunctionLikeDocblockParser::parse($doc_comment, $code_location, $cased_function_id); } catch (IncorrectDocblockException|DocblockParseException $e) { } if ($docblock_info) { if ($docblock_info->since_php_major_version && !$this->aliases->namespace) { $analysis_major_php_version = $this->codebase->getMajorAnalysisPhpVersion(); $analysis_minor_php_version = $this->codebase->getMinorAnalysisPhpVersion(); if ($docblock_info->since_php_major_version > $analysis_major_php_version) { return \false; } if ($docblock_info->since_php_major_version === $analysis_major_php_version && $docblock_info->since_php_minor_version > $analysis_minor_php_version) { return \false; } } } } $is_functionlike_override = \true; $storage = $this->storage = $classlike_storage->methods[$method_name_lc]; } if (!$storage) { $storage = $this->storage = new MethodStorage(); } $storage->stubbed = $this->codebase->register_stub_files; $storage->defining_fqcln = $fq_classlike_name; $class_name_parts = explode('\\', $fq_classlike_name); $class_name = array_pop($class_name_parts); if ($method_name_lc === strtolower($class_name) && !isset($classlike_storage->methods['__construct']) && strpos($fq_classlike_name, '\\') === \false && $this->codebase->analysis_php_version_id <= 70400) { $this->codebase->methods->setDeclaringMethodId($fq_classlike_name, '__construct', $fq_classlike_name, $method_name_lc); $this->codebase->methods->setAppearingMethodId($fq_classlike_name, '__construct', $fq_classlike_name, $method_name_lc); } $method_id = new MethodIdentifier($fq_classlike_name, $method_name_lc); $storage->is_static = $stmt->isStatic(); $storage->abstract = $stmt->isAbstract(); if ($stmt->isPrivate() && $stmt->isFinal() && $method_name_lc !== '__construct') { IssueBuffer::maybeAdd(new PrivateFinalMethod('Private methods cannot be final', new CodeLocation($this->file_scanner, $stmt, null, \true), (string) $method_id)); if ($this->codebase->analysis_php_version_id >= 80000) { // ignore `final` on the method as that's what PHP does $storage->final = $classlike_storage->final; } else { $storage->final = \true; } } else { $storage->final = $classlike_storage->final || $stmt->isFinal(); } $storage->final_from_docblock = $classlike_storage->final_from_docblock; if ($stmt->isPrivate()) { $storage->visibility = ClassLikeAnalyzer::VISIBILITY_PRIVATE; } elseif ($stmt->isProtected()) { $storage->visibility = ClassLikeAnalyzer::VISIBILITY_PROTECTED; } else { $storage->visibility = ClassLikeAnalyzer::VISIBILITY_PUBLIC; } } elseif ($stmt instanceof PhpParser\Node\Expr\Closure || $stmt instanceof PhpParser\Node\Expr\ArrowFunction) { $function_id = $cased_function_id = strtolower($this->file_path) . ':' . $stmt->getLine() . ':' . (int) $stmt->getAttribute('startFilePos') . ':-:closure'; $storage = $this->storage = $this->file_storage->functions[$function_id] = new FunctionStorage(); $storage->is_static = $stmt->static; if ($stmt instanceof PhpParser\Node\Expr\Closure) { foreach ($stmt->uses as $closure_use) { if ($closure_use->byRef && is_string($closure_use->var->name)) { $storage->byref_uses[$closure_use->var->name] = \true; } } } } else { throw new UnexpectedValueException('Unrecognized functionlike'); } return [$cased_function_id, $storage, $function_id, $fq_classlike_name, $method_name_lc, $classlike_storage, $is_functionlike_override, $method_id, \false]; } } getCodebase(); $info = new ClassLikeDocblockComment(); $templates = []; if (isset($parsed_docblock->combined_tags['template'])) { foreach ($parsed_docblock->combined_tags['template'] as $offset => $template_line) { $template_type = preg_split('/[\\s]+/', preg_replace('@^[ \\t]*\\*@m', '', $template_line)); if ($template_type === \false) { throw new IncorrectDocblockException('Invalid @ŧemplate tag: ' . preg_last_error_msg()); } $template_name = array_shift($template_type); if (!$template_name) { throw new IncorrectDocblockException('Empty @template tag'); } $source_prefix = 'none'; if (isset($parsed_docblock->tags['psalm-template'][$offset])) { $source_prefix = 'psalm'; } elseif (isset($parsed_docblock->tags['phpstan-template'][$offset])) { $source_prefix = 'phpstan'; } if (count($template_type) > 1 && in_array(strtolower($template_type[0]), ['as', 'super', 'of'], \true)) { $template_modifier = strtolower(array_shift($template_type)); $templates[$template_name][$source_prefix] = [$template_name, $template_modifier, implode(' ', $template_type), \false, $offset - $comment->getStartFilePos()]; } else { $templates[$template_name][$source_prefix] = [$template_name, null, null, \false, $offset - $comment->getStartFilePos()]; } } } if (isset($parsed_docblock->combined_tags['template-covariant'])) { foreach ($parsed_docblock->combined_tags['template-covariant'] as $offset => $template_line) { $template_type = preg_split('/[\\s]+/', preg_replace('@^[ \\t]*\\*@m', '', $template_line)); if ($template_type === \false) { throw new IncorrectDocblockException('Invalid @template-covariant tag: ' . preg_last_error_msg()); } $template_name = array_shift($template_type); if (!$template_name) { throw new IncorrectDocblockException('Empty @template-covariant tag'); } $source_prefix = 'none'; if (isset($parsed_docblock->tags['psalm-template-covariant'][$offset])) { $source_prefix = 'psalm'; } elseif (isset($parsed_docblock->tags['phpstan-template-covariant'][$offset])) { $source_prefix = 'phpstan'; } if (count($template_type) > 1 && in_array(strtolower($template_type[0]), ['as', 'super', 'of'], \true)) { $template_modifier = strtolower(array_shift($template_type)); $templates[$template_name][$source_prefix] = [$template_name, $template_modifier, implode(' ', $template_type), \true, $offset - $comment->getStartFilePos()]; } else { $templates[$template_name][$source_prefix] = [$template_name, null, null, \true, $offset - $comment->getStartFilePos()]; } } } foreach ($templates as $template_entries) { foreach (['psalm', 'phpstan', 'none'] as $source_prefix) { if (isset($template_entries[$source_prefix])) { $info->templates[] = $template_entries[$source_prefix]; break; } } } if (isset($parsed_docblock->combined_tags['extends'])) { foreach ($parsed_docblock->combined_tags['extends'] as $template_line) { $doc_line_parts = CommentAnalyzer::splitDocLine($template_line); $doc_line_parts[0] = CommentAnalyzer::sanitizeDocblockType($doc_line_parts[0]); $info->template_extends[] = $doc_line_parts[0]; } } if (isset($parsed_docblock->tags['psalm-require-extends']) && count($extension_requirements = $parsed_docblock->tags['psalm-require-extends']) > 0) { $info->extension_requirement = trim(preg_replace('@^[ \\t]*\\*@m', '', $extension_requirements[array_key_first($extension_requirements)])); } if (isset($parsed_docblock->tags['psalm-require-implements'])) { foreach ($parsed_docblock->tags['psalm-require-implements'] as $implementation_requirement) { $info->implementation_requirements[] = trim(preg_replace('@^[ \\t]*\\*@m', '', $implementation_requirement)); } } if (isset($parsed_docblock->combined_tags['implements'])) { foreach ($parsed_docblock->combined_tags['implements'] as $template_line) { $doc_line_parts = CommentAnalyzer::splitDocLine($template_line); $doc_line_parts[0] = CommentAnalyzer::sanitizeDocblockType($doc_line_parts[0]); $info->template_implements[] = $doc_line_parts[0]; } } if (isset($parsed_docblock->tags['psalm-yield'])) { $yield = reset($parsed_docblock->tags['psalm-yield']); $info->yield = trim(preg_replace('@^[ \\t]*\\*@m', '', $yield)); } if (isset($parsed_docblock->tags['deprecated'])) { $info->deprecated = \true; } if (isset($parsed_docblock->tags['internal'])) { $info->internal = \true; } if (isset($parsed_docblock->tags['final'])) { $info->final = \true; } if (isset($parsed_docblock->tags['psalm-consistent-constructor'])) { $info->consistent_constructor = \true; } if (isset($parsed_docblock->tags['psalm-consistent-templates'])) { $info->consistent_templates = \true; } if (count($info->psalm_internal = DocblockParser::handlePsalmInternal($parsed_docblock)) !== 0) { $info->internal = \true; } if (isset($parsed_docblock->tags['mixin'])) { foreach ($parsed_docblock->tags['mixin'] as $rawMixin) { $mixin = trim($rawMixin); $doc_line_parts = CommentAnalyzer::splitDocLine($mixin); $mixin = $doc_line_parts[0]; if ($mixin) { $info->mixins[] = $mixin; } else { throw new DocblockParseException('@mixin annotation used without specifying class'); } } } if (isset($parsed_docblock->tags['psalm-seal-properties'])) { $info->sealed_properties = \true; } if (isset($parsed_docblock->tags['psalm-no-seal-properties'])) { $info->sealed_properties = \false; } if (isset($parsed_docblock->tags['psalm-seal-methods'])) { $info->sealed_methods = \true; } if (isset($parsed_docblock->tags['psalm-no-seal-methods'])) { $info->sealed_methods = \false; } if (isset($parsed_docblock->tags['psalm-inheritors'])) { foreach ($parsed_docblock->tags['psalm-inheritors'] as $template_line) { $doc_line_parts = CommentAnalyzer::splitDocLine($template_line); $doc_line_parts[0] = CommentAnalyzer::sanitizeDocblockType($doc_line_parts[0]); $info->inheritors = $doc_line_parts[0]; } } if (isset($parsed_docblock->tags['psalm-immutable']) || isset($parsed_docblock->tags['psalm-mutation-free'])) { $info->mutation_free = \true; $info->external_mutation_free = \true; $info->taint_specialize = \true; } if (isset($parsed_docblock->tags['psalm-external-mutation-free'])) { $info->external_mutation_free = \true; } if (isset($parsed_docblock->tags['psalm-taint-specialize'])) { $info->taint_specialize = \true; } if (isset($parsed_docblock->tags['psalm-override-property-visibility'])) { $info->override_property_visibility = \true; } if (isset($parsed_docblock->tags['psalm-override-method-visibility'])) { $info->override_method_visibility = \true; } if (isset($parsed_docblock->tags['psalm-suppress'])) { foreach ($parsed_docblock->tags['psalm-suppress'] as $offset => $suppress_entry) { foreach (DocComment::parseSuppressList($suppress_entry) as $issue_offset => $suppressed_issue) { $info->suppressed_issues[$issue_offset + $offset] = $suppressed_issue; } } } $imported_types = ($parsed_docblock->tags['phpstan-import-type'] ?? []) + ($parsed_docblock->tags['psalm-import-type'] ?? []); foreach ($imported_types as $offset => $imported_type_entry) { $info->imported_types[] = ['line_number' => $comment->getStartLine() + substr_count($comment->getText(), "\n", 0, $offset - $comment->getStartFilePos()), 'start_offset' => $offset, 'end_offset' => $offset + strlen($imported_type_entry), 'parts' => CommentAnalyzer::splitDocLine($imported_type_entry)]; } if (isset($parsed_docblock->combined_tags['method'])) { if ($info->sealed_methods === null) { $info->sealed_methods = \true; } foreach ($parsed_docblock->combined_tags['method'] as $offset => $method_entry) { $method_entry = preg_replace('/[ \\t]+/', ' ', trim($method_entry)); $docblock_lines = []; $is_static = \false; $has_return = \false; $doc_line_parts = CommentAnalyzer::splitDocLine($method_entry); if (count($doc_line_parts) > 2 && $doc_line_parts[0] === 'static' && !strpos($doc_line_parts[1], '(')) { $is_static = \true; array_shift($doc_line_parts); $method_entry = implode(' ', $doc_line_parts); $doc_line_parts = CommentAnalyzer::splitDocLine($method_entry); } if (!preg_match('/^([a-z_A-Z][a-z_0-9A-Z]+) *\\(/', $method_entry, $matches)) { if (count($doc_line_parts) > 1) { $docblock_lines[] = '@return ' . array_shift($doc_line_parts); $has_return = \true; $method_entry = implode(' ', $doc_line_parts); } } $method_entry = trim(preg_replace('/\\/\\/.*/', '', $method_entry)); $method_entry = preg_replace('/array\\(([0-9a-zA-Z_\'\\" ]+,)*([0-9a-zA-Z_\'\\" ]+)\\)/', '[]', $method_entry); $end_of_method_regex = '/(?create(); } catch (TypeParseTreeException $e) { throw new DocblockParseException($method_entry . ' is not a valid method: ' . $e->getMessage(), 0, $e); } if (!$method_tree instanceof MethodWithReturnTypeTree && !$method_tree instanceof MethodTree) { throw new DocblockParseException($method_entry . ' is not a valid method'); } if ($method_tree instanceof MethodWithReturnTypeTree) { if (!$has_return) { $docblock_lines[] = '@return ' . TypeParser::getTypeFromTree($method_tree->children[1], $codebase)->toNamespacedString($aliases->namespace, $aliases->uses, null, \false); } $method_tree = $method_tree->children[0]; } if (!$method_tree instanceof MethodTree) { throw new DocblockParseException($method_entry . ' is not a valid method'); } $args = []; foreach ($method_tree->children as $method_tree_child) { if (!$method_tree_child instanceof MethodParamTree) { throw new DocblockParseException($method_entry . ' is not a valid method'); } $args[] = ($method_tree_child->byref ? '&' : '') . ($method_tree_child->variadic ? '...' : '') . $method_tree_child->name . ($method_tree_child->default != '' ? ' = ' . $method_tree_child->default : ''); if ($method_tree_child->children) { try { $param_type = TypeParser::getTypeFromTree($method_tree_child->children[0], $codebase); } catch (Exception $e) { throw new DocblockParseException('Badly-formatted @method string ' . $method_entry . ' - ' . $e); } $param_type_string = $param_type->toNamespacedString('\\', [], null, \false); $docblock_lines[] = '@param ' . $param_type_string . ' ' . ($method_tree_child->variadic ? '...' : '') . $method_tree_child->name; } } $function_string = 'function ' . $method_tree->value . '(' . implode(', ', $args) . ')'; if ($is_static) { $function_string = 'static ' . $function_string; } $function_docblock = $docblock_lines ? "/**\n * " . implode("\n * ", $docblock_lines) . "\n*/\n" : ""; $php_string = 'analysis_php_version_id, $has_errors); } catch (Exception $e) { throw new DocblockParseException('Badly-formatted @method string ' . $method_entry); } if (!$statements || !$statements[0] instanceof Class_ || !isset($statements[0]->stmts[0]) || !$statements[0]->stmts[0] instanceof ClassMethod) { throw new DocblockParseException('Badly-formatted @method string ' . $method_entry); } /** @var Doc */ $node_doc_comment = $node->getDocComment(); $method_offset = self::getMethodOffset($comment, $method_entry); $statements[0]->stmts[0]->setAttribute('startLine', $node_doc_comment->getStartLine() + $method_offset); $statements[0]->stmts[0]->setAttribute('startFilePos', $node_doc_comment->getStartFilePos()); $statements[0]->stmts[0]->setAttribute('endFilePos', $node->getAttribute('startFilePos')); if ($doc_comment = $statements[0]->stmts[0]->getDocComment()) { $statements[0]->stmts[0]->setDocComment(new Doc($doc_comment->getText(), $comment->getStartLine() + substr_count($comment->getText(), "\n", 0, $offset - $comment->getStartFilePos()), $node_doc_comment->getStartFilePos())); } $info->methods[] = $statements[0]->stmts[0]; } } if (isset($parsed_docblock->tags['psalm-stub-override'])) { $info->stub_override = \true; } if ($parsed_docblock->description) { $info->description = $parsed_docblock->description; } $info->public_api = isset($parsed_docblock->tags['psalm-api']) || isset($parsed_docblock->tags['api']); if (isset($parsed_docblock->tags['property']) && $codebase->config->docblock_property_types_seal_properties && $info->sealed_properties === null) { $info->sealed_properties = \true; } self::addMagicPropertyToInfo($comment, $info, $parsed_docblock->tags, 'property'); self::addMagicPropertyToInfo($comment, $info, $parsed_docblock->tags, 'psalm-property'); self::addMagicPropertyToInfo($comment, $info, $parsed_docblock->tags, 'property-read'); self::addMagicPropertyToInfo($comment, $info, $parsed_docblock->tags, 'psalm-property-read'); self::addMagicPropertyToInfo($comment, $info, $parsed_docblock->tags, 'property-write'); self::addMagicPropertyToInfo($comment, $info, $parsed_docblock->tags, 'psalm-property-write'); return $info; } /** * @param array> $specials * @param 'property'|'psalm-property'|'property-read'| * 'psalm-property-read'|'property-write'|'psalm-property-write' $property_tag * @throws DocblockParseException */ protected static function addMagicPropertyToInfo(Doc $comment, ClassLikeDocblockComment $info, array $specials, string $property_tag) : void { $magic_property_comments = $specials[$property_tag] ?? []; foreach ($magic_property_comments as $offset => $property) { $line_parts = CommentAnalyzer::splitDocLine($property); if (count($line_parts) === 1 && isset($line_parts[0][0]) && $line_parts[0][0] === '$') { continue; } if (count($line_parts) > 1) { if (preg_match('/^&?\\$[A-Za-z0-9_]+,?$/', $line_parts[1]) && $line_parts[0][0] !== '{') { $line_parts[1] = str_replace('&', '', $line_parts[1]); $line_parts[1] = preg_replace('/,$/', '', $line_parts[1], 1); $end = $offset + strlen($line_parts[0]); $line_parts[0] = str_replace("\n", '', preg_replace('@^[ \\t]*\\*@m', '', $line_parts[0])); if ($line_parts[0] === '' || $line_parts[0][0] === '$' && !preg_match('/^\\$this(\\||$)/', $line_parts[0])) { throw new IncorrectDocblockException('Misplaced variable'); } $name = trim($line_parts[1]); if (!preg_match('/^\\$([a-zA-Z_\\x7f-\\xff][a-zA-Z0-9_\\x7f-\\xff]*)$/', $name)) { throw new DocblockParseException('Badly-formatted @property name'); } $info->properties[] = ['name' => $name, 'type' => $line_parts[0], 'line_number' => $comment->getStartLine() + substr_count($comment->getText(), "\n", 0, $offset - $comment->getStartFilePos()), 'tag' => $property_tag, 'start' => $offset, 'end' => $end]; } } else { throw new DocblockParseException('Badly-formatted @property'); } } } private static function getMethodOffset(Doc $comment, string $method_entry) : int { $lines = explode("\n", $comment->getText()); $method_offset = 0; foreach ($lines as $i => $line) { if (strpos($line, $method_entry) !== \false) { $method_offset = $i; break; } } return $method_offset; } } getText(); $info = new FunctionDocblockComment(); self::checkDuplicatedTags($parsed_docblock); self::checkUnexpectedTags($parsed_docblock, $info, $comment); if (isset($parsed_docblock->combined_tags['return'])) { self::extractReturnType($comment, $parsed_docblock->combined_tags['return'], $info, $code_location, $cased_function_id); } if (isset($parsed_docblock->combined_tags['param'])) { foreach ($parsed_docblock->combined_tags['param'] as $offset => $param) { $line_parts = CommentAnalyzer::splitDocLine($param); if (count($line_parts) === 1 && isset($line_parts[0][0]) && $line_parts[0][0] === '$') { continue; } if (count($line_parts) > 1) { if (preg_match('/^&?(\\.\\.\\.)?&?\\$[A-Za-z0-9_]+,?$/', $line_parts[1]) && ($line_parts[0] === '' || $line_parts[0][0] !== '{')) { $line_parts[1] = str_replace('&', '', $line_parts[1]); $line_parts[1] = preg_replace('/,$/', '', $line_parts[1], 1); $end = $offset + strlen($line_parts[0]); $line_parts[0] = CommentAnalyzer::sanitizeDocblockType($line_parts[0]); if ($line_parts[0] === '' || $line_parts[0][0] === '$' && !preg_match('/^\\$this(\\||$)/', $line_parts[0])) { throw new IncorrectDocblockException('Misplaced variable'); } $info_param = ['name' => trim($line_parts[1]), 'type' => $line_parts[0], 'line_number' => $comment->getStartLine() + substr_count($comment_text, "\n", 0, $offset - $comment->getStartFilePos()), 'start' => $offset, 'end' => $end]; if (isset($line_parts[1]) && isset($line_parts[2])) { $description = substr($param, strlen($line_parts[0]) + strlen($line_parts[1]) + 2); $info_param['description'] = trim($description); // Handle multiline description. $info_param['description'] = preg_replace('/\\n \\*\\s+/um', ' ', $info_param['description']); } $info->params[] = $info_param; } } else { IssueBuffer::maybeAdd(new InvalidDocblock('Badly-formatted @param in docblock for ' . $cased_function_id, $code_location)); } } } if (isset($parsed_docblock->combined_tags['param-out'])) { foreach ($parsed_docblock->combined_tags['param-out'] as $offset => $param) { $line_parts = CommentAnalyzer::splitDocLine($param); if (count($line_parts) === 1 && isset($line_parts[0][0]) && $line_parts[0][0] === '$') { continue; } if (count($line_parts) > 1) { if (!preg_match('/\\[[^\\]]+\\]/', $line_parts[0]) && preg_match('/^(\\.\\.\\.)?&?\\$[A-Za-z0-9_]+,?$/', $line_parts[1]) && $line_parts[0][0] !== '{') { if ($line_parts[1][0] === '&') { $line_parts[1] = substr($line_parts[1], 1); } $line_parts[0] = str_replace("\n", '', preg_replace('@^[ \\t]*\\*@m', '', $line_parts[0])); if ($line_parts[0] === '' || $line_parts[0][0] === '$' && !preg_match('/^\\$this(\\||$)/', $line_parts[0])) { throw new IncorrectDocblockException('Misplaced variable'); } $line_parts[1] = preg_replace('/,$/', '', $line_parts[1], 1); $info->params_out[] = ['name' => trim($line_parts[1]), 'type' => str_replace("\n", '', $line_parts[0]), 'line_number' => $comment->getStartLine() + substr_count($comment_text, "\n", 0, $offset - $comment->getStartFilePos())]; } } else { IssueBuffer::maybeAdd(new InvalidDocblock('Badly-formatted @param in docblock for ' . $cased_function_id, $code_location)); } } } foreach (['psalm-self-out', 'psalm-this-out', 'phpstan-self-out', 'phpstan-this-out'] as $alias) { if (isset($parsed_docblock->tags[$alias])) { foreach ($parsed_docblock->tags[$alias] as $offset => $param) { $line_parts = CommentAnalyzer::splitDocLine($param); if (count($line_parts) > 0) { $line_parts[0] = str_replace("\n", '', preg_replace('@^[ \\t]*\\*@m', '', $line_parts[0])); $info->self_out = ['type' => str_replace("\n", '', $line_parts[0]), 'line_number' => $comment->getStartLine() + substr_count($comment_text, "\n", 0, $offset - $comment->getStartFilePos())]; } } break; } } if (isset($parsed_docblock->tags['psalm-flow'])) { foreach ($parsed_docblock->tags['psalm-flow'] as $param) { $info->flows[] = trim($param); } } if (isset($parsed_docblock->tags['psalm-if-this-is'])) { foreach ($parsed_docblock->tags['psalm-if-this-is'] as $offset => $param) { $line_parts = CommentAnalyzer::splitDocLine($param); $line_parts[0] = str_replace("\n", '', preg_replace('@^[ \\t]*\\*@m', '', $line_parts[0])); $info->if_this_is = ['type' => str_replace("\n", '', $line_parts[0]), 'line_number' => $comment->getStartLine() + substr_count($comment->getText(), "\n", 0, $offset - $comment->getStartFilePos())]; } } if (isset($parsed_docblock->tags['psalm-taint-sink'])) { foreach ($parsed_docblock->tags['psalm-taint-sink'] as $param) { $param_parts = preg_split('/\\s+/', trim($param)); if ($param_parts === \false) { throw new AssertionError(preg_last_error_msg()); } if (count($param_parts) >= 2) { $info->taint_sink_params[] = ['name' => $param_parts[1], 'taint' => $param_parts[0]]; } else { IssueBuffer::maybeAdd(new InvalidDocblock('@psalm-taint-sink expects 2 arguments', $code_location)); } } } // support for MediaWiki taint plugin if (isset($parsed_docblock->tags['param-taint'])) { foreach ($parsed_docblock->tags['param-taint'] as $param) { $param_parts = preg_split('/\\s+/', trim($param)); if ($param_parts === \false) { throw new AssertionError(preg_last_error_msg()); } if (count($param_parts) === 2) { $taint_type = $param_parts[1]; if (strpos($taint_type, 'exec_') === 0) { $taint_type = substr($taint_type, 5); if ($taint_type === 'tainted') { $taint_type = TaintKindGroup::GROUP_INPUT; } if ($taint_type === 'misc') { // @todo `text` is semantically not defined in `TaintKind`, maybe drop it $taint_type = 'text'; } $info->taint_sink_params[] = ['name' => $param_parts[0], 'taint' => $taint_type]; } } } } if (isset($parsed_docblock->tags['psalm-taint-source'])) { foreach ($parsed_docblock->tags['psalm-taint-source'] as $param) { $param_parts = preg_split('/\\s+/', trim($param)); if ($param_parts === \false) { throw new AssertionError(preg_last_error_msg()); } if ($param_parts[0]) { $info->taint_source_types[] = $param_parts[0]; } else { IssueBuffer::maybeAdd(new InvalidDocblock('@psalm-taint-source expects 1 argument', $code_location)); } } } elseif (isset($parsed_docblock->tags['return-taint'])) { // support for MediaWiki taint plugin foreach ($parsed_docblock->tags['return-taint'] as $param) { $param_parts = preg_split('/\\s+/', trim($param)); if ($param_parts === \false) { throw new AssertionError(preg_last_error_msg()); } if ($param_parts[0]) { if ($param_parts[0] === 'tainted') { $param_parts[0] = TaintKindGroup::GROUP_INPUT; } if ($param_parts[0] === 'misc') { // @todo `text` is semantically not defined in `TaintKind`, maybe drop it $param_parts[0] = 'text'; } if ($param_parts[0] !== 'none') { $info->taint_source_types[] = $param_parts[0]; } } } } if (isset($parsed_docblock->tags['psalm-taint-unescape'])) { foreach ($parsed_docblock->tags['psalm-taint-unescape'] as $param) { $param = trim($param); if ($param === '') { IssueBuffer::maybeAdd(new InvalidDocblock('@psalm-taint-unescape expects 1 argument', $code_location)); } else { $info->added_taints[] = $param; } } } if (isset($parsed_docblock->tags['psalm-taint-escape'])) { foreach ($parsed_docblock->tags['psalm-taint-escape'] as $param) { $param = trim($param); if ($param === '') { IssueBuffer::maybeAdd(new InvalidDocblock('@psalm-taint-escape expects 1 argument', $code_location)); } elseif ($param[0] === '(') { $line_parts = CommentAnalyzer::splitDocLine($param); $info->removed_taints[] = CommentAnalyzer::sanitizeDocblockType($line_parts[0]); } else { $info->removed_taints[] = explode(' ', $param)[0]; } } } if (isset($parsed_docblock->tags['psalm-assert-untainted'])) { foreach ($parsed_docblock->tags['psalm-assert-untainted'] as $param) { $param = trim($param); $info->assert_untainted_params[] = ['name' => $param]; } } if (isset($parsed_docblock->tags['psalm-taint-specialize'])) { $info->specialize_call = \true; } if (isset($parsed_docblock->tags['global'])) { foreach ($parsed_docblock->tags['global'] as $offset => $global) { $line_parts = CommentAnalyzer::splitDocLine($global); if (count($line_parts) === 1 && isset($line_parts[0][0]) && $line_parts[0][0] === '$') { continue; } if (count($line_parts) > 1) { if (!preg_match('/\\[[^\\]]+\\]/', $line_parts[0]) && preg_match('/^(\\.\\.\\.)?&?\\$[A-Za-z0-9_]+,?$/', $line_parts[1]) && $line_parts[0][0] !== '{') { if ($line_parts[1][0] === '&') { $line_parts[1] = substr($line_parts[1], 1); } if ($line_parts[0][0] === '$' && !preg_match('/^\\$this(\\||$)/', $line_parts[0])) { throw new IncorrectDocblockException('Misplaced variable'); } $line_parts[1] = preg_replace('/,$/', '', $line_parts[1], 1); $info->globals[] = ['name' => $line_parts[1], 'type' => $line_parts[0], 'line_number' => $comment->getStartLine() + substr_count($comment_text, "\n", 0, $offset - $comment->getStartFilePos())]; } } else { IssueBuffer::maybeAdd(new InvalidDocblock('Badly-formatted @param in docblock for ' . $cased_function_id, $code_location)); } } } if (isset($parsed_docblock->tags['since'])) { $since = trim(reset($parsed_docblock->tags['since'])); // only for phpstub files or @since 8.0.0 PHP // since @since is commonly used with the project version, not the PHP version // https://docs.phpdoc.org/3.0/guide/references/phpdoc/tags/since.html // https://github.com/vimeo/psalm/issues/10761 if (preg_match('/^([4578])\\.(\\d)(\\.\\d+)?(\\s+PHP)?$/i', $since, $since_match) && isset($since_match[1]) && isset($since_match[2]) && (!empty($since_match[4]) || pathinfo($code_location->file_name, PATHINFO_EXTENSION) === 'phpstub')) { $info->since_php_major_version = (int) $since_match[1]; $info->since_php_minor_version = (int) $since_match[2]; } } if (isset($parsed_docblock->tags['deprecated'])) { $info->deprecated = \true; } if (isset($parsed_docblock->tags['internal'])) { $info->internal = \true; } if (count($info->psalm_internal = DocblockParser::handlePsalmInternal($parsed_docblock)) !== 0) { $info->internal = \true; } if (isset($parsed_docblock->tags['psalm-suppress'])) { foreach ($parsed_docblock->tags['psalm-suppress'] as $offset => $suppress_entry) { foreach (DocComment::parseSuppressList($suppress_entry) as $issue_offset => $suppressed_issue) { $info->suppressed_issues[$issue_offset + $offset] = $suppressed_issue; } } } if (isset($parsed_docblock->tags['throws'])) { foreach ($parsed_docblock->tags['throws'] as $offset => $throws_entry) { $throws_class = preg_split('/[\\s]+/', $throws_entry)[0]; if (!$throws_class) { throw new IncorrectDocblockException('Unexpectedly empty @throws'); } $info->throws[] = [$throws_class, $offset, $comment->getStartLine() + substr_count($comment->getText(), "\n", 0, $offset - $comment->getStartFilePos())]; } } if (stripos($parsed_docblock->description, '@inheritdoc') !== \false || isset($parsed_docblock->tags['inheritdoc']) || isset($parsed_docblock->tags['inheritDoc'])) { $info->inheritdoc = \true; } $templates = []; if (isset($parsed_docblock->combined_tags['template'])) { foreach ($parsed_docblock->combined_tags['template'] as $offset => $template_line) { $template_type = preg_split('/[\\s]+/', preg_replace('@^[ \\t]*\\*@m', '', $template_line)); if ($template_type === \false) { throw new AssertionError(preg_last_error_msg()); } $template_name = array_shift($template_type); if (!$template_name) { throw new IncorrectDocblockException('Empty @template tag'); } $source_prefix = 'none'; if (isset($parsed_docblock->tags['psalm-template'][$offset])) { $source_prefix = 'psalm'; } elseif (isset($parsed_docblock->tags['phpstan-template'][$offset])) { $source_prefix = 'phpstan'; } if (count($template_type) > 1 && in_array(strtolower($template_type[0]), ['as', 'super', 'of'], \true)) { $template_modifier = strtolower(array_shift($template_type)); $templates[$template_name][$source_prefix] = [$template_name, $template_modifier, implode(' ', $template_type), \false]; } else { $templates[$template_name][$source_prefix] = [$template_name, null, null, \false]; } } } foreach ($templates as $template_entries) { foreach (['psalm', 'phpstan', 'none'] as $source_prefix) { if (isset($template_entries[$source_prefix])) { $info->templates[] = $template_entries[$source_prefix]; break; } } } foreach (['psalm-assert', 'phpstan-assert'] as $assert) { if (isset($parsed_docblock->tags[$assert])) { foreach ($parsed_docblock->tags[$assert] as $assertion) { $line_parts = self::sanitizeAssertionLineParts(CommentAnalyzer::splitDocLine($assertion)); $info->assertions[] = ['type' => $line_parts[0], 'param_name' => $line_parts[1][0] === '$' ? substr($line_parts[1], 1) : $line_parts[1]]; } break; } } foreach (['psalm-assert-if-true', 'phpstan-assert-if-true'] as $assert) { if (isset($parsed_docblock->tags[$assert])) { foreach ($parsed_docblock->tags[$assert] as $assertion) { $line_parts = self::sanitizeAssertionLineParts(CommentAnalyzer::splitDocLine($assertion)); $info->if_true_assertions[] = ['type' => $line_parts[0], 'param_name' => $line_parts[1][0] === '$' ? substr($line_parts[1], 1) : $line_parts[1]]; } break; } } foreach (['psalm-assert-if-false', 'phpstan-assert-if-false'] as $assert) { if (isset($parsed_docblock->tags[$assert])) { foreach ($parsed_docblock->tags[$assert] as $assertion) { $line_parts = self::sanitizeAssertionLineParts(CommentAnalyzer::splitDocLine($assertion)); $info->if_false_assertions[] = ['type' => $line_parts[0], 'param_name' => $line_parts[1][0] === '$' ? substr($line_parts[1], 1) : $line_parts[1]]; } break; } } $info->variadic = isset($parsed_docblock->tags['psalm-variadic']); $info->pure = isset($parsed_docblock->tags['psalm-pure']) || isset($parsed_docblock->tags['phpstan-pure']) || isset($parsed_docblock->tags['pure']); if (isset($parsed_docblock->tags['psalm-mutation-free'])) { $info->mutation_free = \true; } if (isset($parsed_docblock->tags['psalm-external-mutation-free'])) { $info->external_mutation_free = \true; } if (isset($parsed_docblock->tags['no-named-arguments'])) { $info->no_named_args = \true; } $info->ignore_nullable_return = isset($parsed_docblock->tags['psalm-ignore-nullable-return']); $info->ignore_falsable_return = isset($parsed_docblock->tags['psalm-ignore-falsable-return']); $info->stub_override = isset($parsed_docblock->tags['psalm-stub-override']); if (!empty($parsed_docblock->description)) { $info->description = $parsed_docblock->description; } $info->public_api = isset($parsed_docblock->tags['psalm-api']) || isset($parsed_docblock->tags['api']); return $info; } /** * @psalm-pure * @param list $line_parts * @return array{string, string}&array, string> $line_parts */ private static function sanitizeAssertionLineParts(array $line_parts) : array { if (count($line_parts) < 2 || strpos($line_parts[1], '$') === \false) { throw new IncorrectDocblockException('Misplaced variable'); } $line_parts[0] = CommentAnalyzer::sanitizeDocblockType($line_parts[0]); if ($line_parts[1][0] === '$') { $param_name_parts = explode('->', $line_parts[1]); foreach ($param_name_parts as $i => $param_name_part) { if (substr($param_name_part, -2) === '()') { $param_name_parts[$i] = strtolower($param_name_part); } } $line_parts[1] = implode('->', $param_name_parts); } return $line_parts; } /** * @param array $return_specials */ private static function extractReturnType(PhpParser\Comment\Doc $comment, array $return_specials, FunctionDocblockComment $info, CodeLocation $code_location, string $cased_function_id) : void { foreach ($return_specials as $offset => $return_block) { $return_lines = explode("\n", $return_block); if (trim($return_lines[0]) === '') { return; } $return_block = trim($return_block); if ($return_block === '') { return; } $line_parts = CommentAnalyzer::splitDocLine($return_block); if ($line_parts[0][0] !== '{') { if ($line_parts[0][0] === '$' && !preg_match('/^\\$this(\\||$)/', $line_parts[0])) { throw new IncorrectDocblockException('Misplaced variable'); } $end = $offset + strlen($line_parts[0]); $line_parts[0] = CommentAnalyzer::sanitizeDocblockType($line_parts[0]); $info->return_type = array_shift($line_parts); $info->return_type_description = $line_parts ? implode(' ', $line_parts) : null; $info->return_type_line_number = $comment->getStartLine() + substr_count($comment->getText(), "\n", 0, $offset - $comment->getStartFilePos()); $info->return_type_start = $offset; $info->return_type_end = $end; } else { IssueBuffer::maybeAdd(new InvalidDocblock('Badly-formatted @param in docblock for ' . $cased_function_id, $code_location)); } break; } } /** * @throws DocblockParseException if a duplicate is found */ private static function checkDuplicatedTags(ParsedDocblock $parsed_docblock) : void { if (count($parsed_docblock->tags['return'] ?? []) > 1 || count($parsed_docblock->tags['psalm-return'] ?? []) > 1 || count($parsed_docblock->tags['phpstan-return'] ?? []) > 1) { throw new DocblockParseException('Found duplicated @return or prefixed @return tag'); } self::checkDuplicatedParams($parsed_docblock->tags['param'] ?? []); self::checkDuplicatedParams($parsed_docblock->tags['psalm-param'] ?? []); self::checkDuplicatedParams($parsed_docblock->tags['phpstan-param'] ?? []); } /** * @param array $param * @throws DocblockParseException if a duplicate is found */ private static function checkDuplicatedParams(array $param) : void { $list_names = self::extractAllParamNames($param); if (count($list_names) !== count(array_unique($list_names))) { throw new DocblockParseException('Found duplicated @param or prefixed @param tag'); } } /** * @param array $lines * @return list * @psalm-pure */ private static function extractAllParamNames(array $lines) : array { $names = []; foreach ($lines as $line) { $split_by_dollar = explode('$', $line, 2); if (count($split_by_dollar) > 1) { $split_by_space = explode(' ', $split_by_dollar[1], 2); $names[] = $split_by_space[0]; } } return $names; } private static function checkUnexpectedTags(ParsedDocblock $parsed_docblock, FunctionDocblockComment $info, PhpParser\Comment\Doc $comment) : void { if (isset($parsed_docblock->tags['psalm-import-type'])) { $info->unexpected_tags['psalm-import-type']['lines'] = self::tagOffsetsToLines(array_keys($parsed_docblock->tags['psalm-import-type']), $comment); } if (isset($parsed_docblock->combined_tags['var'])) { $info->unexpected_tags['var'] = ['lines' => self::tagOffsetsToLines(array_keys($parsed_docblock->combined_tags['var']), $comment), 'suggested_replacement' => 'param']; } if (isset($parsed_docblock->tags['psalm-consistent-constructor'])) { $info->unexpected_tags['psalm-consistent-constructor'] = ['lines' => self::tagOffsetsToLines(array_keys($parsed_docblock->tags['psalm-consistent-constructor']), $comment), 'suggested_replacement' => 'psalm-consistent-constructor on a class level']; } } /** * @param list $offsets * @return list */ private static function tagOffsetsToLines(array $offsets, PhpParser\Comment\Doc $comment) : array { $ret = []; foreach ($offsets as $offset) { $ret[] = self::docblockLineNumber($comment, $offset); } return $ret; } private static function docblockLineNumber(PhpParser\Comment\Doc $comment, int $offset) : int { return $comment->getStartLine() + substr_count($comment->getText(), "\n", 0, $offset - $comment->getStartFilePos()); } } will_analyze); } elseif ($node instanceof PhpParser\Node\Expr\Yield_ || $node instanceof PhpParser\Node\Expr\YieldFrom) { if ($functionlike_storage) { $functionlike_storage->has_yield = \true; } } elseif ($node instanceof PhpParser\Node\Expr\Cast\Object_) { $codebase->scanner->queueClassLikeForScanning('stdClass', \false, \false); $file_storage->referenced_classlikes['stdclass'] = 'stdClass'; } elseif (($node instanceof PhpParser\Node\Expr\New_ || $node instanceof PhpParser\Node\Expr\Instanceof_ || $node instanceof PhpParser\Node\Expr\StaticPropertyFetch || $node instanceof PhpParser\Node\Expr\ClassConstFetch || $node instanceof PhpParser\Node\Expr\StaticCall) && $node->class instanceof PhpParser\Node\Name) { $fq_classlike_name = ClassLikeAnalyzer::getFQCLNFromNameObject($node->class, $aliases); if (!in_array(strtolower($fq_classlike_name), ['self', 'static', 'parent'], \true)) { $codebase->scanner->queueClassLikeForScanning($fq_classlike_name, \false, !$node instanceof PhpParser\Node\Expr\ClassConstFetch || !$node->name instanceof PhpParser\Node\Identifier || strtolower($node->name->name) !== 'class'); $file_storage->referenced_classlikes[strtolower($fq_classlike_name)] = $fq_classlike_name; } } elseif ($node instanceof PhpParser\Node\Expr\FuncCall && $node->name instanceof PhpParser\Node\Name) { $function_id = $node->name->toString(); if (InternalCallMapHandler::inCallMap($function_id)) { self::registerClassMapFunctionCall($codebase, $file_storage, $file_scanner, $aliases, $function_id, $node, $functionlike_storage, $skip_if_descendants); } } } private static function registerClassMapFunctionCall(Codebase $codebase, FileStorage $file_storage, FileScanner $file_scanner, Aliases $aliases, string $function_id, PhpParser\Node\Expr\FuncCall $node, ?FunctionLikeStorage $functionlike_storage, ?int $skip_if_descendants) : void { $callables = InternalCallMapHandler::getCallablesFromCallMap($function_id); if ($callables) { foreach ($callables as $callable) { assert($callable->params !== null); foreach ($callable->params as $function_param) { if ($function_param->type) { /** @psalm-suppress UnusedMethodCall */ $function_param->type->queueClassLikesForScanning($codebase, $file_storage); } } if ($callable->return_type && !$callable->return_type->hasMixed()) { /** @psalm-suppress UnusedMethodCall */ $callable->return_type->queueClassLikesForScanning($codebase, $file_storage); } } } if ($node->isFirstClassCallable()) { return; } if ($function_id === 'define') { $first_arg_value = isset($node->getArgs()[0]) ? $node->getArgs()[0]->value : null; $second_arg_value = isset($node->getArgs()[1]) ? $node->getArgs()[1]->value : null; if ($first_arg_value && $second_arg_value) { $type_provider = new NodeDataProvider(); $const_name = ConstFetchAnalyzer::getConstName($first_arg_value, $type_provider, $codebase, $aliases); if ($const_name !== null) { $const_type = SimpleTypeInferer::infer($codebase, $type_provider, $second_arg_value, $aliases); // allow docblocks to override the declared value to make constants in stubs configurable $doc_comment = $second_arg_value->getDocComment(); if ($doc_comment) { try { $var_comments = CommentAnalyzer::getTypeFromComment($doc_comment, $file_scanner, $aliases); foreach ($var_comments as $var_comment) { if ($var_comment->type) { $const_type = $var_comment->type; } // only check the first @var comment break; } } catch (DocblockParseException $e) { // do nothing } } if ($const_type === null) { $const_type = Type::getMixed(); } $config = Config::getInstance(); if ($functionlike_storage && !$config->hoist_constants) { $functionlike_storage->defined_constants[$const_name] = $const_type; } else { $file_storage->constants[$const_name] = $const_type; $file_storage->declaring_constants[$const_name] = $file_storage->file_path; } if (($codebase->register_stub_files || $codebase->register_autoload_files) && (!defined($const_name) || $const_type->isMixed())) { $codebase->addGlobalConstantType($const_name, $const_type); } } } } $mapping_function_ids = []; if ($function_id === 'array_map' && isset($node->getArgs()[0]) || $function_id === 'array_filter' && isset($node->getArgs()[1])) { $node_arg_value = $function_id === 'array_map' ? $node->getArgs()[0]->value : $node->getArgs()[1]->value; if ($node_arg_value instanceof PhpParser\Node\Scalar\String_ || $node_arg_value instanceof PhpParser\Node\Expr\Array_ || $node_arg_value instanceof PhpParser\Node\Expr\BinaryOp\Concat) { $mapping_function_ids = CallAnalyzer::getFunctionIdsFromCallableArg($file_scanner, $node_arg_value); } foreach ($mapping_function_ids as $potential_method_id) { if (strpos($potential_method_id, '::') === \false) { continue; } [$callable_fqcln] = explode('::', $potential_method_id); if (!in_array(strtolower($callable_fqcln), ['self', 'parent', 'static'], \true)) { $codebase->scanner->queueClassLikeForScanning($callable_fqcln); } } } if ($function_id === 'func_get_arg' || $function_id === 'func_get_args' || $function_id === 'func_num_args') { if ($functionlike_storage) { $functionlike_storage->variadic = \true; } } if ($function_id === 'is_a' || $function_id === 'is_subclass_of') { $second_arg = $node->getArgs()[1]->value ?? null; if ($second_arg instanceof PhpParser\Node\Scalar\String_) { $codebase->scanner->queueClassLikeForScanning($second_arg->value); } } if ($function_id === 'class_alias' && !$skip_if_descendants) { $first_arg = $node->getArgs()[0]->value ?? null; $second_arg = $node->getArgs()[1]->value ?? null; if ($first_arg instanceof PhpParser\Node\Scalar\String_) { $first_arg_value = $first_arg->value; } elseif ($first_arg instanceof PhpParser\Node\Expr\ClassConstFetch && $first_arg->class instanceof PhpParser\Node\Name && $first_arg->name instanceof PhpParser\Node\Identifier && strtolower($first_arg->name->name) === 'class') { /** @var string */ $first_arg_value = $first_arg->class->getAttribute('resolvedName'); } else { $first_arg_value = null; } if ($second_arg instanceof PhpParser\Node\Scalar\String_) { $second_arg_value = $second_arg->value; } elseif ($second_arg instanceof PhpParser\Node\Expr\ClassConstFetch && $second_arg->class instanceof PhpParser\Node\Name && $second_arg->name instanceof PhpParser\Node\Identifier && strtolower($second_arg->name->name) === 'class') { /** @var string */ $second_arg_value = $second_arg->class->getAttribute('resolvedName'); } else { $second_arg_value = null; } if ($first_arg_value !== null && $second_arg_value !== null) { if ($first_arg_value[0] === '\\') { $first_arg_value = substr($first_arg_value, 1); } if ($second_arg_value[0] === '\\') { $second_arg_value = substr($second_arg_value, 1); } $codebase->classlikes->addClassAlias($first_arg_value, $second_arg_value); $file_storage->classlike_aliases[$second_arg_value] = $first_arg_value; } } } public static function visitInclude(Codebase $codebase, FileStorage $file_storage, PhpParser\Node\Expr\Include_ $stmt, bool $scan_deep) : void { $config = Config::getInstance(); if (!$config->allow_includes) { throw new FileIncludeException('File includes are not allowed per your Psalm config - check the allowFileIncludes flag.'); } if ($stmt->expr instanceof PhpParser\Node\Scalar\String_) { $path_to_file = $stmt->expr->value; // attempts to resolve using get_include_path dirs $include_path = IncludeAnalyzer::resolveIncludePath($path_to_file, dirname($file_storage->file_path)); $path_to_file = $include_path ?: $path_to_file; if (Path::isRelative($path_to_file)) { $path_to_file = $config->base_dir . DIRECTORY_SEPARATOR . $path_to_file; } } else { $path_to_file = IncludeAnalyzer::getPathTo($stmt->expr, null, null, $file_storage->file_path, $config); } if ($path_to_file) { $path_to_file = IncludeAnalyzer::normalizeFilePath($path_to_file); if ($file_storage->file_path === $path_to_file) { return; } if ($codebase->fileExists($path_to_file)) { if ($scan_deep) { $codebase->scanner->addFileToDeepScan($path_to_file); } else { $codebase->scanner->addFileToShallowScan($path_to_file); } $file_storage->required_file_paths[strtolower($path_to_file)] = $path_to_file; return; } } } } > $existing_function_template_types * @param array $type_aliases */ public static function addDocblockInfo(Codebase $codebase, FileScanner $file_scanner, FileStorage $file_storage, Aliases $aliases, array $type_aliases, ?ClassLikeStorage $classlike_storage, array $existing_function_template_types, FunctionLikeStorage $storage, PhpParser\Node\FunctionLike $stmt, FunctionDocblockComment $docblock_info, bool $is_functionlike_override, bool $fake_method, string $cased_function_id) : void { self::handleUnexpectedTags($docblock_info, $storage, $stmt, $file_scanner, $cased_function_id); $config = Config::getInstance(); if ($docblock_info->mutation_free) { $storage->mutation_free = \true; if ($storage instanceof MethodStorage) { $storage->external_mutation_free = \true; $storage->mutation_free_inferred = \false; } } if ($storage instanceof MethodStorage && $docblock_info->external_mutation_free) { $storage->external_mutation_free = \true; } if ($docblock_info->deprecated) { $storage->deprecated = \true; } if (count($docblock_info->psalm_internal) !== 0) { $storage->internal = $docblock_info->psalm_internal; } elseif ($docblock_info->internal && $aliases->namespace) { $storage->internal = [NamespaceAnalyzer::getNameSpaceRoot($aliases->namespace)]; } if (($storage->internal || $classlike_storage && $classlike_storage->internal) && !$config->allow_internal_named_arg_calls) { $storage->allow_named_arg_calls = \false; } elseif ($docblock_info->no_named_args) { $storage->allow_named_arg_calls = \false; } if ($docblock_info->variadic) { $storage->variadic = \true; } if ($docblock_info->pure) { $storage->pure = \true; $storage->specialize_call = \true; $storage->mutation_free = \true; if ($storage instanceof MethodStorage) { $storage->external_mutation_free = \true; } } if ($docblock_info->specialize_call) { $storage->specialize_call = \true; } // we make sure we only add ignore flag for internal stubs if the config is set to true if ($docblock_info->ignore_nullable_return && $storage->return_type && ($codebase->config->ignore_internal_nullable_issues || !in_array($file_storage->file_path, $codebase->config->internal_stubs))) { /** @psalm-suppress InaccessibleProperty We just created this type */ $storage->return_type->ignore_nullable_issues = \true; } // we make sure we only add ignore flag for internal stubs if the config is set to true if ($docblock_info->ignore_falsable_return && $storage->return_type && ($codebase->config->ignore_internal_falsable_issues || !in_array($file_storage->file_path, $codebase->config->internal_stubs))) { /** @psalm-suppress InaccessibleProperty We just created this type */ $storage->return_type->ignore_falsable_issues = \true; } if ($docblock_info->stub_override && !$is_functionlike_override) { throw new InvalidMethodOverrideException('Method ' . $cased_function_id . ' is marked as stub override,' . ' but no original counterpart found'); } $storage->suppressed_issues = $docblock_info->suppressed_issues; foreach ($docblock_info->throws as [$throw, $offset, $line]) { $throw_location = new DocblockTypeLocation($file_scanner, $offset, $offset + strlen($throw), $line); foreach (explode('|', $throw) as $throw_class) { $throw_class = trim($throw_class); if ($throw_class === '') { continue; } if ($throw_class !== 'self' && $throw_class !== 'static' && $throw_class !== 'parent') { $exception_fqcln = Type::getFQCLNFromString($throw_class, $aliases); } else { $exception_fqcln = $throw_class; } $codebase->scanner->queueClassLikeForScanning($exception_fqcln); $file_storage->referenced_classlikes[strtolower($exception_fqcln)] = $exception_fqcln; $storage->throws[$exception_fqcln] = \true; $storage->throw_locations[$exception_fqcln] = $throw_location; } } if (!$config->use_docblock_types) { return; } if ($storage instanceof MethodStorage && $docblock_info->inheritdoc) { $storage->inheritdoc = \true; } $template_types = $classlike_storage && $classlike_storage->template_types ? $classlike_storage->template_types : null; $function_template_types = $existing_function_template_types; $class_template_types = $classlike_storage ? $classlike_storage->template_types ?: [] : []; if ($docblock_info->templates) { $function_template_types = self::handleTemplates($storage, $docblock_info, $aliases, $template_types, $type_aliases, $file_scanner, $stmt, $cased_function_id); } self::handleAssertions($docblock_info, $storage, $codebase, $file_scanner, $file_storage, $aliases, $stmt, $class_template_types, $function_template_types, $type_aliases, $classlike_storage); foreach ($docblock_info->globals as $global) { try { $storage->global_types[$global['name']] = TypeParser::parseTokens(TypeTokenizer::getFullyQualifiedTokens($global['type'], $aliases, null, $type_aliases), null); } catch (TypeParseTreeException $e) { $storage->docblock_issues[] = new InvalidDocblock($e->getMessage() . ' in docblock for ' . $cased_function_id, new CodeLocation($file_scanner, $stmt, null, \true)); continue; } } if ($docblock_info->params) { self::improveParamsFromDocblock($codebase, $file_scanner, $file_storage, $aliases, $type_aliases, $classlike_storage, $storage, $function_template_types, $class_template_types, $docblock_info->params, $stmt, $fake_method, $classlike_storage && !$classlike_storage->is_trait ? $classlike_storage->name : null); } if ($storage instanceof MethodStorage) { $storage->has_docblock_param_types = (bool) array_filter($storage->params, static fn(FunctionLikeParameter $p): bool => $p->type !== null && $p->has_docblock_type); } foreach ($docblock_info->params_out as $docblock_param_out) { self::handleParamOut($docblock_param_out, $aliases, $function_template_types, $class_template_types, $type_aliases, $cased_function_id, $file_scanner, $stmt, $storage, $codebase, $file_storage); } if ($docblock_info->self_out && $storage instanceof MethodStorage) { $out_type = TypeParser::parseTokens(TypeTokenizer::getFullyQualifiedTokens($docblock_info->self_out['type'], $aliases, $function_template_types + $class_template_types, $type_aliases, $classlike_storage ? $classlike_storage->name : null), null, $function_template_types + $class_template_types, $type_aliases); $storage->self_out_type = $out_type; } if ($docblock_info->if_this_is && $storage instanceof MethodStorage) { $out_type = TypeParser::parseTokens(TypeTokenizer::getFullyQualifiedTokens($docblock_info->if_this_is['type'], $aliases, $function_template_types + $class_template_types, $type_aliases, $classlike_storage ? $classlike_storage->name : null), null, $function_template_types + $class_template_types, $type_aliases); $storage->if_this_is_type = $out_type; } foreach ($docblock_info->taint_sink_params as $taint_sink_param) { $param_name = substr($taint_sink_param['name'], 1); foreach ($storage->params as $param_storage) { if ($param_storage->name === $param_name) { $param_storage->sinks[] = $taint_sink_param['taint']; } } } $docblock_info->taint_source_types = array_values(array_unique($docblock_info->taint_source_types)); // expand 'input' group to all items, e.g. `['other', 'input']` -> `['other', 'html', 'sql', 'shell', ...]` $inputIndex = array_search(TaintKindGroup::GROUP_INPUT, $docblock_info->taint_source_types, \true); if ($inputIndex !== \false) { array_splice($docblock_info->taint_source_types, $inputIndex, 1, TaintKindGroup::ALL_INPUT); } // merge taints from doc block to storage, enforce uniqueness and having consecutive index keys $storage->taint_source_types = array_merge($storage->taint_source_types, $docblock_info->taint_source_types); $storage->taint_source_types = array_values(array_unique($storage->taint_source_types)); $storage->added_taints = $docblock_info->added_taints; foreach ($docblock_info->removed_taints as $removed_taint) { if ($removed_taint[0] === '(') { self::handleRemovedTaint($codebase, $stmt, $aliases, $removed_taint, $function_template_types, $class_template_types, $type_aliases, $storage, $classlike_storage, $cased_function_id, $file_storage, $file_scanner); } else { $storage->removed_taints[] = $removed_taint; } } self::handleTaintFlow($docblock_info, $storage); foreach ($docblock_info->assert_untainted_params as $untainted_assert_param) { $param_name = substr($untainted_assert_param['name'], 1); foreach ($storage->params as $param_storage) { if ($param_storage->name === $param_name) { $param_storage->assert_untainted = \true; } } } if ($docblock_info->return_type !== null) { self::handleReturn($codebase, $docblock_info, $docblock_info->return_type, $fake_method, $file_scanner, $storage, $stmt, $aliases, $function_template_types, $class_template_types, $type_aliases, $classlike_storage, $cased_function_id, $file_storage); } if ($docblock_info->description) { $storage->description = $docblock_info->description; } $storage->public_api = $docblock_info->public_api; } /** * @param array> $template_types * @param array|null $type_aliases * @param array> $function_template_types * @return array{ * array, * array> * } */ private static function getConditionalSanitizedTypeTokens(string $docblock_return_type, Aliases $aliases, array $template_types, ?array $type_aliases, FunctionLikeStorage $storage, ?ClassLikeStorage $classlike_storage, string $cased_function_id, array $function_template_types) : array { $fixed_type_tokens = TypeTokenizer::getFullyQualifiedTokens($docblock_return_type, $aliases, $template_types, $type_aliases, $classlike_storage && !$classlike_storage->is_trait ? $classlike_storage->name : null); $param_type_mapping = []; $template_function_id = 'fn-' . strtolower($cased_function_id); // This checks for param references in the return type tokens // If found, the param is replaced with a generated template param foreach ($fixed_type_tokens as $i => $type_token) { $token_body = $type_token[0]; if ($token_body[0] === '$') { foreach ($storage->params as $j => $param_storage) { if ('$' . $param_storage->name === $token_body) { if (!isset($param_type_mapping[$token_body])) { $template_name = 'TGeneratedFromParam' . $j; if (isset($storage->template_types[$template_name])) { $function_template_types[$template_name] = $storage->template_types[$template_name]; $param_type_mapping[$token_body] = $template_name; } else { $template_as_type = $param_storage->type ? $param_storage->type : Type::getMixed(); $storage->template_types[$template_name] = [$template_function_id => $template_as_type]; $function_template_types[$template_name] = $storage->template_types[$template_name]; $param_type_mapping[$token_body] = $template_name; $param_storage->type = new Union([new TTemplateParam($template_name, $template_as_type, $template_function_id)]); } } // spaces are allowed before $foo in get(string $foo) magic method // definitions, but we want to remove them in this instance if ($i > 0 && isset($fixed_type_tokens[$i - 1]) && $fixed_type_tokens[$i - 1][0][0] === ' ') { unset($fixed_type_tokens[$i - 1]); } $fixed_type_tokens[$i][0] = $param_type_mapping[$token_body]; continue 2; } } } if ($token_body === 'func_num_args()') { $template_name = 'TFunctionArgCount'; $storage->template_types[$template_name] = [$template_function_id => Type::getInt()]; $function_template_types[$template_name] = $storage->template_types[$template_name]; $fixed_type_tokens[$i][0] = $template_name; } if ($token_body === 'PHP_MAJOR_VERSION') { $template_name = 'TPhpMajorVersion'; $storage->template_types[$template_name] = [$template_function_id => Type::getInt()]; $function_template_types[$template_name] = $storage->template_types[$template_name]; $fixed_type_tokens[$i][0] = $template_name; } if ($token_body === 'PHP_VERSION_ID') { $template_name = 'TPhpVersionId'; $storage->template_types[$template_name] = [$template_function_id => Type::getInt()]; $function_template_types[$template_name] = $storage->template_types[$template_name]; $fixed_type_tokens[$i][0] = $template_name; } } return [$fixed_type_tokens, $function_template_types]; } /** * @param array> $class_template_types * @param array> $function_template_types * @param array $type_aliases * @return non-empty-list|null */ private static function getAssertionParts(Codebase $codebase, FileScanner $file_scanner, FileStorage $file_storage, Aliases $aliases, PhpParser\Node\FunctionLike $stmt, FunctionLikeStorage $storage, string $assertion_type, array $class_template_types, array $function_template_types, array $type_aliases, ?string $self_fqcln) : ?array { $is_negation = \false; $is_loose_equality = \false; $is_strict_equality = \false; if ($assertion_type[0] === '!') { $is_negation = \true; $assertion_type = substr($assertion_type, 1); } if ($assertion_type[0] === '~') { $is_loose_equality = \true; $assertion_type = substr($assertion_type, 1); } if ($assertion_type[0] === '=') { $is_strict_equality = \true; $assertion_type = substr($assertion_type, 1); } $class_template_types = !$stmt instanceof PhpParser\Node\Stmt\ClassMethod || !$stmt->isStatic() ? $class_template_types : []; if ($assertion_type === 'falsy') { return [$is_negation ? new Truthy() : new Falsy()]; } if ($assertion_type === 'truthy') { return [$is_negation ? new Falsy() : new Truthy()]; } if ($assertion_type === 'empty') { return [$is_negation ? new NonEmpty() : new Empty_()]; } $template_types = $function_template_types + $class_template_types; try { $namespaced_type = TypeParser::parseTokens(TypeTokenizer::getFullyQualifiedTokens($assertion_type, $aliases, $template_types, $type_aliases, $self_fqcln, null, \true), null, $template_types, $type_aliases); } catch (TypeParseTreeException $e) { $storage->docblock_issues[] = new InvalidDocblock('Invalid @psalm-assert union type: ' . $e->getMessage(), new CodeLocation($file_scanner, $stmt, null, \true)); return null; } if (($is_negation || $is_loose_equality || $is_strict_equality) && count($namespaced_type->getAtomicTypes()) > 1) { $storage->docblock_issues[] = new InvalidDocblock('Docblock assertions cannot contain | characters together with a prefix', new CodeLocation($file_scanner, $stmt, null, \true)); return null; } /** @psalm-suppress UnusedMethodCall */ $namespaced_type->queueClassLikesForScanning($codebase, $file_storage, $function_template_types + $class_template_types); $assertion_type_parts = []; foreach ($namespaced_type->getAtomicTypes() as $namespaced_type_part) { if ($is_negation) { if ($is_strict_equality) { $assertion_type_parts[] = new IsNotIdentical($namespaced_type_part); } elseif ($is_loose_equality) { $assertion_type_parts[] = new IsNotLooselyEqual($namespaced_type_part); } else { $assertion_type_parts[] = new IsNotType($namespaced_type_part); } } else { if ($is_strict_equality) { $assertion_type_parts[] = new IsIdentical($namespaced_type_part); } elseif ($is_loose_equality) { $assertion_type_parts[] = new IsLooselyEqual($namespaced_type_part); } else { $assertion_type_parts[] = new IsType($namespaced_type_part); } } } return $assertion_type_parts; } /** * @param array> $class_template_types * @param array> $function_template_types * @param array $type_aliases * @param array< * int, * array{ * type:string, * name:string, * line_number:int, * start:int, * end:int, * description?:string * } * > $docblock_params */ private static function improveParamsFromDocblock(Codebase $codebase, FileScanner $file_scanner, FileStorage $file_storage, Aliases $aliases, array $type_aliases, ?ClassLikeStorage $classlike_storage, FunctionLikeStorage $storage, array &$function_template_types, array $class_template_types, array $docblock_params, PhpParser\Node\FunctionLike $function, bool $fake_method, ?string $fq_classlike_name) : void { $base = $classlike_storage ? $classlike_storage->name . '::' : ''; $cased_method_id = $base . $storage->cased_name; $unused_docblock_params = []; $class_template_types = !$function instanceof PhpParser\Node\Stmt\ClassMethod || !$function->isStatic() ? $class_template_types : []; foreach ($docblock_params as $docblock_param) { $param_name = $docblock_param['name']; $docblock_param_variadic = \false; if (strpos($param_name, '...') === 0) { $docblock_param_variadic = \true; $param_name = substr($param_name, 3); } $param_name = substr($param_name, 1); $storage_param = null; foreach ($storage->params as $function_signature_param) { if ($function_signature_param->name === $param_name) { $storage_param = $function_signature_param; break; } } if (!$fake_method) { $docblock_type_location = new DocblockTypeLocation($file_scanner, $docblock_param['start'], $docblock_param['end'], $docblock_param['line_number']); } else { $docblock_type_location = new CodeLocation($file_scanner, $function, null, \false, CodeLocation::FUNCTION_PHPDOC_METHOD, null); } if ($storage_param === null) { $param_location = new CodeLocation($file_scanner, $function, null, \true, CodeLocation::FUNCTION_PARAM_VAR, null, $docblock_param['line_number']); $unused_docblock_params[$param_name] = $param_location; if (!$docblock_param_variadic || $storage->params || $file_scanner->will_analyze) { continue; } $storage_param = new FunctionLikeParameter($param_name, \false, null, null, null, null, \false, \false, \true, null); $storage->addParam($storage_param); } try { $new_param_type = TypeParser::parseTokens(TypeTokenizer::getFullyQualifiedTokens($docblock_param['type'], $aliases, $function_template_types + $class_template_types, $type_aliases, $fq_classlike_name), null, $function_template_types + $class_template_types, $type_aliases, \true); } catch (TypeParseTreeException $e) { $storage->docblock_issues[] = new InvalidDocblock($e->getMessage() . ' in docblock for ' . $cased_method_id, $docblock_type_location); continue; } $storage_param->has_docblock_type = \true; /** @psalm-suppress UnusedMethodCall */ $new_param_type->queueClassLikesForScanning($codebase, $file_storage, $storage->template_types ?: []); if ($storage->template_types) { foreach ($storage->template_types as $t => $type_map) { foreach ($type_map as $obj => $type) { if ($type->isMixed() && $docblock_param['type'] === 'class-string<' . $t . '>') { $storage->template_types[$t][$obj] = Type::getObject(); if (isset($function_template_types[$t])) { $function_template_types[$t][$obj] = $storage->template_types[$t][$obj]; } } } } } if (!$docblock_param_variadic && $storage_param->is_variadic && $new_param_type->hasArray()) { /** * @var TArray|TKeyedArray */ $array_type = $new_param_type->getArray(); if ($array_type instanceof TKeyedArray) { $new_param_type = $array_type->getGenericValueType(); } else { $new_param_type = $array_type->type_params[1]; } } $existing_param_type_nullable = $storage_param->is_nullable; if (isset($docblock_param['description'])) { $storage_param->description = $docblock_param['description']; } if (!$storage_param->type || $storage_param->type->hasMixed() || $storage->template_types) { if ($existing_param_type_nullable && !$new_param_type->isNullable() && !$new_param_type->hasTemplate()) { $new_param_type = $new_param_type->getBuilder()->addType(new TNull())->freeze(); } $config = Config::getInstance(); if ($config->add_param_default_to_docblock_type && $storage_param->default_type instanceof Union && !$storage_param->default_type->hasMixed() && (!$storage_param->type || !$storage_param->type->hasMixed())) { $new_param_type = Type::combineUnionTypes($new_param_type, $storage_param->default_type); } $storage_param->type = $new_param_type; $storage_param->type_location = $docblock_type_location; continue; } $storage_param_atomic_types = $storage_param->type->getAtomicTypes(); $all_typehint_types_match = \true; foreach ($new_param_type->getAtomicTypes() as $key => $type) { if (isset($storage_param_atomic_types[$key])) { /** @psalm-suppress InaccessibleProperty We just created this type */ $type->from_docblock = \false; if ($storage_param_atomic_types[$key] instanceof TArray && $type instanceof TArray && $type->type_params[0]->hasArrayKey()) { /** @psalm-suppress InaccessibleProperty We just created this type */ $type->type_params[0]->from_docblock = \false; } } else { $all_typehint_types_match = \false; } } if ($all_typehint_types_match) { /** @psalm-suppress InaccessibleProperty We just created this type */ $new_param_type->from_docblock = \false; } if ($existing_param_type_nullable && !$new_param_type->isNullable()) { $new_param_type = $new_param_type->getBuilder()->addType(new TNull())->freeze(); } $storage_param->type = $new_param_type; $storage_param->type_location = $docblock_type_location; } $params_without_docblock_type = array_filter($storage->params, static fn(FunctionLikeParameter $p): bool => !$p->has_docblock_type && (!$p->type || $p->type->hasArray())); if ($params_without_docblock_type) { /** @psalm-suppress DeprecatedProperty remove in Psalm 6 */ $storage->unused_docblock_params = $unused_docblock_params; } $storage->has_undertyped_native_parameters = $params_without_docblock_type !== []; $storage->unused_docblock_parameters = $unused_docblock_params; } /** * @param array $type_aliases * @param array> $function_template_types * @param array> $class_template_types */ private static function handleReturn(Codebase $codebase, FunctionDocblockComment $docblock_info, string $docblock_return_type, bool $fake_method, FileScanner $file_scanner, FunctionLikeStorage $storage, PhpParser\Node\FunctionLike $stmt, Aliases $aliases, array $function_template_types, array $class_template_types, array $type_aliases, ?ClassLikeStorage $classlike_storage, string $cased_function_id, FileStorage $file_storage) : void { if (!$fake_method && $docblock_info->return_type_line_number && $docblock_info->return_type_start && $docblock_info->return_type_end) { $storage->return_type_location = new DocblockTypeLocation($file_scanner, $docblock_info->return_type_start, $docblock_info->return_type_end, $docblock_info->return_type_line_number); } else { $storage->return_type_location = new CodeLocation($file_scanner, $stmt, null, \false, !$fake_method ? CodeLocation::FUNCTION_PHPDOC_RETURN_TYPE : CodeLocation::FUNCTION_PHPDOC_METHOD, $docblock_info->return_type, $docblock_info->return_type_line_number && !$fake_method ? $docblock_info->return_type_line_number : null); } try { [$fixed_type_tokens, $function_template_types] = self::getConditionalSanitizedTypeTokens($docblock_return_type, $aliases, $function_template_types + $class_template_types, $type_aliases, $storage, $classlike_storage, $cased_function_id, $function_template_types); $storage->return_type = TypeParser::parseTokens(array_values($fixed_type_tokens), null, $function_template_types + $class_template_types, $type_aliases, \true); if ($storage instanceof MethodStorage) { $storage->has_docblock_return_type = \true; } if ($storage->signature_return_type) { $all_typehint_types_match = \true; $signature_return_atomic_types = $storage->signature_return_type->getAtomicTypes(); foreach ($storage->return_type->getAtomicTypes() as $key => $type) { if (isset($signature_return_atomic_types[$key])) { /** @psalm-suppress InaccessibleProperty We just created this atomic type */ $type->from_docblock = \false; } else { $all_typehint_types_match = \false; } } if ($all_typehint_types_match) { /** @psalm-suppress InaccessibleProperty We just created this type */ $storage->return_type->from_docblock = \false; if ($storage instanceof MethodStorage) { $storage->has_docblock_return_type = \true; } } // if the signature type contains null, we add null into the final return type too if ($storage->signature_return_type->isNullable() && !$storage->return_type->isNullable() && !$storage->return_type->hasTemplate() && !$storage->return_type->hasConditional()) { //don't add null to final type if signature type don't match the docblock type // however, we can't check for object types at this point (#6931), so we'll assume it's ok if ($storage->return_type->hasObjectType() || UnionTypeComparator::isContainedBy($codebase, $storage->return_type, $storage->signature_return_type)) { $storage->return_type = $storage->return_type->getBuilder()->addType(new TNull())->freeze(); } } } /** @psalm-suppress UnusedMethodCall */ $storage->return_type->queueClassLikesForScanning($codebase, $file_storage); } catch (TypeParseTreeException $e) { $storage->docblock_issues[] = new InvalidDocblock($e->getMessage() . ' in docblock for ' . $cased_function_id, new CodeLocation($file_scanner, $stmt, null, \true)); } // we make sure we only add ignore flag for internal stubs if the config is set to true if ($docblock_info->ignore_nullable_return && $storage->return_type && ($codebase->config->ignore_internal_nullable_issues || !in_array($file_storage->file_path, $codebase->config->internal_stubs))) { /** @psalm-suppress InaccessibleProperty We just created this type */ $storage->return_type->ignore_nullable_issues = \true; } // we make sure we only add ignore flag for internal stubs if the config is set to true if ($docblock_info->ignore_falsable_return && $storage->return_type && ($codebase->config->ignore_internal_falsable_issues || !in_array($file_storage->file_path, $codebase->config->internal_stubs))) { /** @psalm-suppress InaccessibleProperty We just created this type */ $storage->return_type->ignore_falsable_issues = \true; } if ($stmt->returnsByRef() && $storage->return_type) { /** @psalm-suppress InaccessibleProperty We just created this type */ $storage->return_type->by_ref = \true; } $storage->return_type_description = $docblock_info->return_type_description; } private static function handleTaintFlow(FunctionDocblockComment $docblock_info, FunctionLikeStorage $storage) : void { if ($docblock_info->flows) { foreach ($docblock_info->flows as $flow) { $path_type = 'arg'; $fancy_path_regex = '/-\\(([a-z\\-]+)\\)->/'; if (preg_match($fancy_path_regex, $flow, $matches)) { if (isset($matches[1])) { $path_type = $matches[1]; } $flow = preg_replace($fancy_path_regex, '->', $flow); } $flow_parts = explode('->', $flow); if (isset($flow_parts[1]) && trim($flow_parts[1]) === 'return') { $source_param_string = trim($flow_parts[0]); if ($source_param_string[0] === '(' && substr($source_param_string, -1) === ')') { $source_params = preg_split('/, ?/', substr($source_param_string, 1, -1)); if ($source_params === \false) { throw new AssertionError(preg_last_error_msg()); } foreach ($source_params as $source_param) { $source_param = substr($source_param, 1); foreach ($storage->params as $i => $param_storage) { if ($param_storage->name === $source_param) { $storage->return_source_params[$i] = $path_type; } } } } } if (isset($flow_parts[0]) && strpos(trim($flow_parts[0]), 'proxy') === 0) { $proxy_call = trim(substr($flow_parts[0], strlen('proxy'))); [$fully_qualified_name, $source_param_string] = explode('(', $proxy_call, 2); if (!empty($fully_qualified_name) && !empty($source_param_string)) { $source_params = preg_split('/, ?/', substr($source_param_string, 0, -1)) ?: []; $call_params = []; foreach ($source_params as $source_param) { $source_param = substr($source_param, 1); foreach ($storage->params as $i => $param_storage) { if ($param_storage->name === $source_param) { $call_params[] = $i; } } } if ($storage->proxy_calls === null) { $storage->proxy_calls = []; } $storage->proxy_calls[] = ['fqn' => $fully_qualified_name, 'params' => $call_params, 'return' => isset($flow_parts[1]) && trim($flow_parts[1]) === 'return']; } } } } } /** * @param array $type_aliases * @param array> $function_template_types * @param array> $class_template_types */ private static function handleRemovedTaint(Codebase $codebase, PhpParser\Node\FunctionLike $stmt, Aliases $aliases, string $removed_taint, array $function_template_types, array $class_template_types, array $type_aliases, FunctionLikeStorage $storage, ?ClassLikeStorage $classlike_storage, string $cased_function_id, FileStorage $file_storage, FileScanner $file_scanner) : void { try { [$fixed_type_tokens, $function_template_types] = self::getConditionalSanitizedTypeTokens($removed_taint, $aliases, $function_template_types + $class_template_types, $type_aliases, $storage, $classlike_storage, $cased_function_id, $function_template_types); $removed_taint = TypeParser::parseTokens(array_values($fixed_type_tokens), null, $function_template_types + $class_template_types, $type_aliases); /** @psalm-suppress UnusedMethodCall */ $removed_taint->queueClassLikesForScanning($codebase, $file_storage); $removed_taint_single = $removed_taint->getSingleAtomic(); if (!$removed_taint_single instanceof TConditional) { throw new TypeParseTreeException('Escaped taint must be a conditional'); } $storage->conditionally_removed_taints[] = $removed_taint; } catch (TypeParseTreeException $e) { $storage->docblock_issues[] = new InvalidDocblock($e->getMessage() . ' in docblock for ' . $cased_function_id, new CodeLocation($file_scanner, $stmt, null, \true)); } } /** * @param array $type_aliases * @param array> $function_template_types * @param array> $class_template_types */ private static function handleAssertions(FunctionDocblockComment $docblock_info, FunctionLikeStorage $storage, Codebase $codebase, FileScanner $file_scanner, FileStorage $file_storage, Aliases $aliases, PhpParser\Node\FunctionLike $stmt, array $class_template_types, array $function_template_types, array $type_aliases, ?ClassLikeStorage $classlike_storage) : void { if ($docblock_info->assertions) { $storage->assertions = []; foreach ($docblock_info->assertions as $assertion) { $assertion_type_parts = self::getAssertionParts($codebase, $file_scanner, $file_storage, $aliases, $stmt, $storage, $assertion['type'], $class_template_types, $function_template_types, $type_aliases, $classlike_storage && !$classlike_storage->is_trait ? $classlike_storage->name : null); if (!$assertion_type_parts) { continue; } foreach ($storage->params as $i => $param) { if ($param->name === $assertion['param_name']) { $storage->assertions[] = new Possibilities($i, $assertion_type_parts); continue 2; } if (strpos($assertion['param_name'], $param->name . '->') === 0) { $storage->assertions[] = new Possibilities(substr_replace($assertion['param_name'], (string) $i, 0, strlen($param->name)), $assertion_type_parts); continue 2; } } $storage->assertions[] = new Possibilities((strpos($assertion['param_name'], '$') === \false ? '$' : '') . $assertion['param_name'], $assertion_type_parts); } } if ($docblock_info->if_true_assertions) { $storage->if_true_assertions = []; foreach ($docblock_info->if_true_assertions as $assertion) { $assertion_type_parts = self::getAssertionParts($codebase, $file_scanner, $file_storage, $aliases, $stmt, $storage, $assertion['type'], $class_template_types, $function_template_types, $type_aliases, $classlike_storage && !$classlike_storage->is_trait ? $classlike_storage->name : null); if (!$assertion_type_parts) { continue; } foreach ($storage->params as $i => $param) { if ($param->name === $assertion['param_name']) { $storage->if_true_assertions[] = new Possibilities($i, $assertion_type_parts); continue 2; } if (strpos($assertion['param_name'], $param->name . '->') === 0) { $storage->if_true_assertions[] = new Possibilities(str_replace($param->name, (string) $i, $assertion['param_name']), $assertion_type_parts); continue 2; } } $storage->if_true_assertions[] = new Possibilities((strpos($assertion['param_name'], '$') === \false ? '$' : '') . $assertion['param_name'], $assertion_type_parts); } } if ($docblock_info->if_false_assertions) { $storage->if_false_assertions = []; foreach ($docblock_info->if_false_assertions as $assertion) { $assertion_type_parts = self::getAssertionParts($codebase, $file_scanner, $file_storage, $aliases, $stmt, $storage, $assertion['type'], $class_template_types, $function_template_types, $type_aliases, $classlike_storage && !$classlike_storage->is_trait ? $classlike_storage->name : null); if (!$assertion_type_parts) { continue; } foreach ($storage->params as $i => $param) { if ($param->name === $assertion['param_name']) { $storage->if_false_assertions[] = new Possibilities($i, $assertion_type_parts); continue 2; } if (strpos($assertion['param_name'], $param->name . '->') === 0) { $storage->if_false_assertions[] = new Possibilities(str_replace($param->name, (string) $i, $assertion['param_name']), $assertion_type_parts); continue 2; } } $storage->if_false_assertions[] = new Possibilities((strpos($assertion['param_name'], '$') === \false ? '$' : '') . $assertion['param_name'], $assertion_type_parts); } } } /** * @param array $type_aliases * @param array> $function_template_types * @param array> $class_template_types * @param array{name:string, type:string, line_number: int} $docblock_param_out */ private static function handleParamOut(array $docblock_param_out, Aliases $aliases, array $function_template_types, array $class_template_types, array $type_aliases, string $cased_function_id, FileScanner $file_scanner, PhpParser\Node\FunctionLike $stmt, FunctionLikeStorage $storage, Codebase $codebase, FileStorage $file_storage) : void { $param_name = substr($docblock_param_out['name'], 1); try { $out_type = TypeParser::parseTokens(TypeTokenizer::getFullyQualifiedTokens($docblock_param_out['type'], $aliases, $function_template_types + $class_template_types, $type_aliases), null, $function_template_types + $class_template_types, $type_aliases); } catch (TypeParseTreeException $e) { $storage->docblock_issues[] = new InvalidDocblock($e->getMessage() . ' in docblock for ' . $cased_function_id, new CodeLocation($file_scanner, $stmt, null, \true)); return; } /** @psalm-suppress UnusedMethodCall */ $out_type->queueClassLikesForScanning($codebase, $file_storage, $storage->template_types ?: []); foreach ($storage->params as $param_storage) { if ($param_storage->name === $param_name) { $param_storage->out_type = $out_type; } } } /** * @param ?array> $template_types * @param array $type_aliases * @return array> */ private static function handleTemplates(FunctionLikeStorage $storage, FunctionDocblockComment $docblock_info, Aliases $aliases, ?array $template_types, array $type_aliases, FileScanner $file_scanner, PhpParser\Node\FunctionLike $stmt, string $cased_function_id) : array { $storage->template_types = []; foreach ($docblock_info->templates as $template_map) { $template_name = $template_map[0]; if ($template_map[1] !== null && $template_map[2] !== null) { if (trim($template_map[2])) { $type_string = $template_map[2]; try { $type_string = CommentAnalyzer::splitDocLine($type_string)[0]; } catch (DocblockParseException $e) { throw new DocblockParseException($type_string . ' is not a valid type: ' . $e->getMessage()); } $type_string = CommentAnalyzer::sanitizeDocblockType($type_string); try { $template_type = TypeParser::parseTokens(TypeTokenizer::getFullyQualifiedTokens($type_string, $aliases, $storage->template_types + ($template_types ?: []), $type_aliases), null, $storage->template_types + ($template_types ?: []), $type_aliases); } catch (TypeParseTreeException $e) { $storage->docblock_issues[] = new InvalidDocblock('Template ' . $template_name . ' has invalid as type - ' . $e->getMessage(), new CodeLocation($file_scanner, $stmt, null, \true)); $template_type = Type::getMixed(); } } else { $storage->docblock_issues[] = new InvalidDocblock('Template ' . $template_name . ' missing as type', new CodeLocation($file_scanner, $stmt, null, \true)); $template_type = Type::getMixed(); } } else { $template_type = Type::getMixed(); } if (isset($template_types[$template_name])) { $storage->docblock_issues[] = new InvalidDocblock('Duplicate template param ' . $template_name . ' in docblock for ' . $cased_function_id, new CodeLocation($file_scanner, $stmt, null, \true)); } else { $storage->template_types[$template_name] = ['fn-' . strtolower($cased_function_id) => $template_type]; } } return array_merge($template_types ?: [], $storage->template_types); } private static function handleUnexpectedTags(FunctionDocblockComment $docblock_info, FunctionLikeStorage $storage, PhpParser\Node\FunctionLike $stmt, FileScanner $file_scanner, string $cased_function_id) : void { foreach ($docblock_info->unexpected_tags as $tag => $details) { foreach ($details['lines'] as $line) { $tag_location = new CodeLocation($file_scanner, $stmt, null, \true, null, null, $line); $message = 'Docblock tag @' . $tag . ' is not recognized in the function docblock ' . 'for ' . $cased_function_id; if (isset($details['suggested_replacement'])) { $message .= ', did you mean to use @' . $details['suggested_replacement'] . '?'; } $storage->docblock_issues[] = new PossiblyInvalidDocblockTag($message, $tag_location); } } } } name instanceof PhpParser\Node\Name\FullyQualified) { $fq_type_string = (string) $stmt->name; } else { $fq_type_string = ClassLikeAnalyzer::getFQCLNFromNameObject($stmt->name, $aliases); } $codebase->scanner->queueClassLikeForScanning($fq_type_string); $file_storage->referenced_classlikes[strtolower($fq_type_string)] = $fq_type_string; $args = []; foreach ($stmt->args as $arg_node) { $key = $arg_node->name->name ?? null; $const_type = SimpleTypeInferer::infer($codebase, new NodeDataProvider(), $arg_node->value, $aliases, null, [], $fq_classlike_name); if (!$const_type) { $const_type = \Psalm\Internal\PhpVisitor\Reflector\ExpressionResolver::getUnresolvedClassConstExpr($arg_node->value, $aliases, $fq_classlike_name); } if (!$const_type) { $const_type = Type::getMixed(); } $args[] = new AttributeArg($key, $const_type, new CodeLocation($file_scanner, $arg_node->value)); } return new AttributeStorage($fq_type_string, $args, new CodeLocation($file_scanner, $stmt), new CodeLocation($file_scanner, $stmt->name)); } } left, $aliases, $fq_classlike_name, $parent_fq_class_name); $right = self::getUnresolvedClassConstExpr($stmt->right, $aliases, $fq_classlike_name, $parent_fq_class_name); if (!$left || !$right) { return null; } if ($stmt instanceof PhpParser\Node\Expr\BinaryOp\Plus) { return new UnresolvedAdditionOp($left, $right); } if ($stmt instanceof PhpParser\Node\Expr\BinaryOp\Minus) { return new UnresolvedSubtractionOp($left, $right); } if ($stmt instanceof PhpParser\Node\Expr\BinaryOp\Mul) { return new UnresolvedMultiplicationOp($left, $right); } if ($stmt instanceof PhpParser\Node\Expr\BinaryOp\Div) { return new UnresolvedDivisionOp($left, $right); } if ($stmt instanceof PhpParser\Node\Expr\BinaryOp\Concat) { return new UnresolvedConcatOp($left, $right); } if ($stmt instanceof PhpParser\Node\Expr\BinaryOp\BitwiseOr) { return new UnresolvedBitwiseOr($left, $right); } if ($stmt instanceof PhpParser\Node\Expr\BinaryOp\BitwiseXor) { return new UnresolvedBitwiseXor($left, $right); } if ($stmt instanceof PhpParser\Node\Expr\BinaryOp\BitwiseAnd) { return new UnresolvedBitwiseAnd($left, $right); } } if ($stmt instanceof PhpParser\Node\Expr\Ternary) { $cond = self::getUnresolvedClassConstExpr($stmt->cond, $aliases, $fq_classlike_name, $parent_fq_class_name); $if = null; if ($stmt->if) { $if = self::getUnresolvedClassConstExpr($stmt->if, $aliases, $fq_classlike_name, $parent_fq_class_name); if ($if === null) { $if = \false; } } $else = self::getUnresolvedClassConstExpr($stmt->else, $aliases, $fq_classlike_name, $parent_fq_class_name); if ($cond && $else && $if !== \false) { return new UnresolvedTernary($cond, $if, $else); } } if ($stmt instanceof PhpParser\Node\Expr\ConstFetch) { $part0_lc = strtolower($stmt->name->getFirst()); if ($part0_lc === 'false') { return new ScalarValue(\false); } if ($part0_lc === 'true') { return new ScalarValue(\true); } if ($part0_lc === 'null') { return new ScalarValue(null); } if ($part0_lc === '__namespace__') { return new ScalarValue($aliases->namespace); } return new Constant($stmt->name->toString(), $stmt->name instanceof PhpParser\Node\Name\FullyQualified); } if ($stmt instanceof PhpParser\Node\Scalar\MagicConst\Namespace_) { return new ScalarValue($aliases->namespace); } if ($stmt instanceof PhpParser\Node\Expr\ArrayDimFetch && $stmt->dim) { $left = self::getUnresolvedClassConstExpr($stmt->var, $aliases, $fq_classlike_name, $parent_fq_class_name); $right = self::getUnresolvedClassConstExpr($stmt->dim, $aliases, $fq_classlike_name, $parent_fq_class_name); if ($left && $right) { return new ArrayOffsetFetch($left, $right); } } if ($stmt instanceof PhpParser\Node\Expr\ClassConstFetch) { if ($stmt->class instanceof PhpParser\Node\Name && $stmt->name instanceof PhpParser\Node\Identifier && $fq_classlike_name && $stmt->class->getParts() !== ['static'] && ($stmt->class->getParts() !== ['parent'] || $parent_fq_class_name !== null)) { if ($stmt->class->getParts() === ['self']) { $const_fq_class_name = $fq_classlike_name; } else { if ($stmt->class->getParts() === ['parent']) { assert($parent_fq_class_name !== null); $const_fq_class_name = $parent_fq_class_name; } else { $const_fq_class_name = ClassLikeAnalyzer::getFQCLNFromNameObject($stmt->class, $aliases); } } return new ClassConstant($const_fq_class_name, $stmt->name->name); } return null; } if ($stmt instanceof PhpParser\Node\Scalar\String_ || $stmt instanceof PhpParser\Node\Scalar\LNumber || $stmt instanceof PhpParser\Node\Scalar\DNumber) { return new ScalarValue($stmt->value); } if ($stmt instanceof PhpParser\Node\Expr\UnaryPlus) { $right = self::getUnresolvedClassConstExpr($stmt->expr, $aliases, $fq_classlike_name, $parent_fq_class_name); if (!$right) { return null; } return new UnresolvedAdditionOp(new ScalarValue(0), $right); } if ($stmt instanceof PhpParser\Node\Expr\UnaryMinus) { $right = self::getUnresolvedClassConstExpr($stmt->expr, $aliases, $fq_classlike_name, $parent_fq_class_name); if (!$right) { return null; } return new UnresolvedSubtractionOp(new ScalarValue(0), $right); } if ($stmt instanceof PhpParser\Node\Expr\Array_) { $items = []; foreach ($stmt->items as $item) { if ($item === null) { return null; } if ($item->key) { $item_key_type = self::getUnresolvedClassConstExpr($item->key, $aliases, $fq_classlike_name, $parent_fq_class_name); if (!$item_key_type) { return null; } } else { $item_key_type = null; } $item_value_type = self::getUnresolvedClassConstExpr($item->value, $aliases, $fq_classlike_name, $parent_fq_class_name); if (!$item_value_type) { return null; } if ($item->unpack) { $items[] = new ArraySpread($item_value_type); } else { $items[] = new KeyValuePair($item_key_type, $item_value_type); } } return new ArrayValue($items); } if ($stmt instanceof PhpParser\Node\Expr\PropertyFetch && $stmt->var instanceof PhpParser\Node\Expr\ClassConstFetch && $stmt->var->class instanceof PhpParser\Node\Name && $stmt->var->name instanceof PhpParser\Node\Identifier && $stmt->name instanceof PhpParser\Node\Identifier && in_array($stmt->name->name, ['name', 'value'], \true) && ($stmt->var->class->getParts() !== ['self'] || $fq_classlike_name !== null) && $stmt->var->class->getParts() !== ['static'] && ($stmt->var->class->getParts() !== ['parent'] || $parent_fq_class_name !== null)) { if ($stmt->var->class->getParts() === ['self']) { assert($fq_classlike_name !== null); $enum_fq_class_name = $fq_classlike_name; } else { if ($stmt->var->class->getParts() === ['parent']) { assert($parent_fq_class_name !== null); $enum_fq_class_name = $parent_fq_class_name; } else { $enum_fq_class_name = ClassLikeAnalyzer::getFQCLNFromNameObject($stmt->var->class, $aliases); } } if ($stmt->name->name === 'value') { return new EnumValueFetch($enum_fq_class_name, $stmt->var->name->name); } else { /*if ($stmt->name->name === 'name')*/ return new EnumNameFetch($enum_fq_class_name, $stmt->var->name->name); } } return null; } public static function enterConditional(Codebase $codebase, string $file_path, PhpParser\Node\Expr $expr) : ?bool { if ($expr instanceof PhpParser\Node\Expr\BooleanNot) { $enter_negated = self::enterConditional($codebase, $file_path, $expr->expr); return $enter_negated === null ? null : !$enter_negated; } if ($expr instanceof PhpParser\Node\Expr\BinaryOp\BooleanAnd) { $enter_conditional_left = self::enterConditional($codebase, $file_path, $expr->left); $enter_conditional_right = self::enterConditional($codebase, $file_path, $expr->right); return $enter_conditional_left !== \false && $enter_conditional_right !== \false; } if ($expr instanceof PhpParser\Node\Expr\BinaryOp\BooleanOr) { $enter_conditional_left = self::enterConditional($codebase, $file_path, $expr->left); $enter_conditional_right = self::enterConditional($codebase, $file_path, $expr->right); return $enter_conditional_left !== \false || $enter_conditional_right !== \false; } if ($codebase->register_autoload_files) { if (($expr instanceof PhpParser\Node\Expr\BinaryOp\GreaterOrEqual || $expr instanceof PhpParser\Node\Expr\BinaryOp\Greater || $expr instanceof PhpParser\Node\Expr\BinaryOp\SmallerOrEqual || $expr instanceof PhpParser\Node\Expr\BinaryOp\Smaller) && ($expr->left instanceof PhpParser\Node\Expr\ConstFetch && $expr->left->name->getParts() === ['PHP_VERSION_ID'] && $expr->right instanceof PhpParser\Node\Scalar\LNumber || $expr->right instanceof PhpParser\Node\Expr\ConstFetch && $expr->right->name->getParts() === ['PHP_VERSION_ID'] && $expr->left instanceof PhpParser\Node\Scalar\LNumber)) { $php_version_id = $codebase->analysis_php_version_id; $evaluator = new ConstExprEvaluator(static function (Expr $expr) use($php_version_id) { if ($expr instanceof ConstFetch && $expr->name->getParts() === ['PHP_VERSION_ID']) { return $php_version_id; } throw new ConstExprEvaluationException('unexpected'); }); try { return (bool) $evaluator->evaluateSilently($expr); } catch (ConstExprEvaluationException $e) { return null; } } } if (!$expr instanceof PhpParser\Node\Expr\FuncCall) { return null; } return self::functionEvaluatesToTrue($codebase, $file_path, $expr); } private static function functionEvaluatesToTrue(Codebase $codebase, string $file_path, PhpParser\Node\Expr\FuncCall $function) : ?bool { if (!$function->name instanceof PhpParser\Node\Name) { return null; } if ($function->name->getParts() === ['function_exists'] && isset($function->getArgs()[0]) && $function->getArgs()[0]->value instanceof PhpParser\Node\Scalar\String_ && function_exists($function->getArgs()[0]->value->value)) { $reflection_function = new ReflectionFunction($function->getArgs()[0]->value->value); if ($reflection_function->isInternal()) { return \true; } return \false; } if ($function->name->getParts() === ['class_exists'] && isset($function->getArgs()[0])) { $string_value = null; if ($function->getArgs()[0]->value instanceof PhpParser\Node\Scalar\String_) { $string_value = $function->getArgs()[0]->value->value; } elseif ($function->getArgs()[0]->value instanceof PhpParser\Node\Expr\ClassConstFetch && $function->getArgs()[0]->value->class instanceof PhpParser\Node\Name && $function->getArgs()[0]->value->name instanceof PhpParser\Node\Identifier && strtolower($function->getArgs()[0]->value->name->name) === 'class') { $string_value = (string) $function->getArgs()[0]->value->class->getAttribute('resolvedName'); } if ($string_value && class_exists($string_value)) { $reflection_class = new ReflectionClass($string_value); if ($reflection_class->getFileName() !== $file_path) { $codebase->scanner->queueClassLikeForScanning($string_value); return \true; } } return \false; } if ($function->name->getParts() === ['interface_exists'] && isset($function->getArgs()[0])) { $string_value = null; if ($function->getArgs()[0]->value instanceof PhpParser\Node\Scalar\String_) { $string_value = $function->getArgs()[0]->value->value; } elseif ($function->getArgs()[0]->value instanceof PhpParser\Node\Expr\ClassConstFetch && $function->getArgs()[0]->value->class instanceof PhpParser\Node\Name && $function->getArgs()[0]->value->name instanceof PhpParser\Node\Identifier && strtolower($function->getArgs()[0]->value->name->name) === 'class') { $string_value = (string) $function->getArgs()[0]->value->class->getAttribute('resolvedName'); } if ($string_value && interface_exists($string_value)) { $reflection_class = new ReflectionClass($string_value); if ($reflection_class->getFileName() !== $file_path) { $codebase->scanner->queueClassLikeForScanning($string_value); return \true; } } return \false; } if ($function->name->getParts() === ['enum_exists'] && isset($function->getArgs()[0])) { $string_value = null; if ($function->getArgs()[0]->value instanceof PhpParser\Node\Scalar\String_) { $string_value = $function->getArgs()[0]->value->value; } elseif ($function->getArgs()[0]->value instanceof PhpParser\Node\Expr\ClassConstFetch && $function->getArgs()[0]->value->class instanceof PhpParser\Node\Name && $function->getArgs()[0]->value->name instanceof PhpParser\Node\Identifier && strtolower($function->getArgs()[0]->value->name->name) === 'class') { $string_value = (string) $function->getArgs()[0]->value->class->getAttribute('resolvedName'); } // We're using class_exists here because enum_exists doesn't exist on old versions of PHP // Not sure what happens if we try to autoload or reflect on an enum on an old version of PHP though... if ($string_value && class_exists($string_value)) { $reflection_class = new ReflectionClass($string_value); if ($reflection_class->getFileName() !== $file_path) { $codebase->scanner->queueClassLikeForScanning($string_value); return \true; } } return \false; } if ($function->name->getParts() === ['defined'] && isset($function->getArgs()[0]) && $function->getArgs()[0]->value instanceof PhpParser\Node\Scalar\String_) { $predefined_constants = get_defined_constants(\true); if (isset($predefined_constants['user'])) { unset($predefined_constants['user']); } $predefined_constants = array_merge(...array_values($predefined_constants)); return isset($predefined_constants[$function->getArgs()[0]->value->value]); } return null; } } */ private array $offset_map; private bool $must_rescan = \false; private int $non_method_changes; private string $a_file_contents; private string $b_file_contents; private int $a_file_contents_length; private Parser $parser; private Collecting $error_handler; /** @param array $offset_map */ public function __construct(Parser $parser, Collecting $error_handler, array $offset_map, string $a_file_contents, string $b_file_contents) { $this->parser = $parser; $this->error_handler = $error_handler; $this->offset_map = $offset_map; $this->a_file_contents = $a_file_contents; $this->a_file_contents_length = strlen($a_file_contents); $this->b_file_contents = $b_file_contents; $this->non_method_changes = count($offset_map); } /** * @return null|int|PhpParser\Node */ public function enterNode(PhpParser\Node $node, bool &$traverseChildren = \true) { /** @var array{startFilePos: int, endFilePos: int, startLine: int} */ $attrs = $node->getAttributes(); if ($cs = $node->getComments()) { $stmt_start_pos = $cs[0]->getStartFilePos(); } else { $stmt_start_pos = $attrs['startFilePos']; } $stmt_end_pos = $attrs['endFilePos']; $start_offset = 0; $end_offset = 0; $line_offset = 0; foreach ($this->offset_map as [$a_s, $a_e, $b_s, $b_e, $line_diff]) { if ($a_s > $stmt_end_pos) { break; } $end_offset = $b_e - $a_e; if ($a_s < $stmt_start_pos) { $start_offset = $b_s - $a_s; } if ($a_e < $stmt_start_pos) { $start_offset = $end_offset; $line_offset = $line_diff; continue; } if ($node instanceof PhpParser\Node\Stmt\ClassMethod || $node instanceof PhpParser\Node\Stmt\Namespace_ || $node instanceof PhpParser\Node\Stmt\ClassLike) { if ($node instanceof PhpParser\Node\Stmt\ClassMethod) { if ($a_s >= $stmt_start_pos && $a_e <= $stmt_end_pos) { foreach ($this->offset_map as [$a_s2, $a_e2, $b_s2, $b_e2]) { if ($a_s2 > $stmt_end_pos) { break; } // we have a diff that goes outside the bounds that we care about if ($a_e2 > $stmt_end_pos) { $this->must_rescan = \true; return PhpParser\NodeTraverser::STOP_TRAVERSAL; } $end_offset = $b_e2 - $a_e2; if ($a_s2 < $stmt_start_pos) { $start_offset = $b_s2 - $a_s2; } if ($a_e2 < $stmt_start_pos) { $start_offset = $end_offset; $line_offset = $line_diff; continue; } if ($a_s2 >= $stmt_start_pos && $a_e2 <= $stmt_end_pos) { --$this->non_method_changes; } } $stmt_start_pos += $start_offset; $stmt_end_pos += $end_offset; $current_line = substr_count(substr($this->b_file_contents, 0, $stmt_start_pos), "\n"); $method_contents = substr($this->b_file_contents, $stmt_start_pos, $stmt_end_pos - $stmt_start_pos + 1); if (!$method_contents) { $this->must_rescan = \true; return PhpParser\NodeTraverser::STOP_TRAVERSAL; } $error_handler = new Collecting(); $fake_class = '|::)(\\n\\s*(if|list)\\s*\\()/', $fake_class, $matches, PREG_OFFSET_CAPTURE | PREG_SET_ORDER); foreach ($matches as $match) { $fake_class = substr_replace($fake_class, $match[1][0] . ';' . $match[2][0], $match[0][1], strlen($match[0][0])); $extra_characters[] = $match[2][1]; } $replacement_stmts = $this->parser->parse($fake_class, $error_handler) ?: []; if (!$replacement_stmts || !$replacement_stmts[0] instanceof PhpParser\Node\Stmt\ClassLike || count($replacement_stmts[0]->stmts) !== 1) { $hacky_class_fix = self::balanceBrackets($fake_class); if ($replacement_stmts && $replacement_stmts[0] instanceof PhpParser\Node\Stmt\ClassLike && count($replacement_stmts[0]->stmts) !== 1) { $this->must_rescan = \true; return PhpParser\NodeTraverser::STOP_TRAVERSAL; } // changes "): {" to ") {" $hacky_class_fix = preg_replace('/(\\)[\\s]*):([\\s]*\\{)/', '$1 $2', $hacky_class_fix); if ($hacky_class_fix !== $fake_class) { $replacement_stmts = $this->parser->parse($hacky_class_fix, $error_handler) ?: []; } if (!$replacement_stmts || !$replacement_stmts[0] instanceof PhpParser\Node\Stmt\ClassLike || count($replacement_stmts[0]->stmts) > 1) { $this->must_rescan = \true; return PhpParser\NodeTraverser::STOP_TRAVERSAL; } } $replacement_stmts = $replacement_stmts[0]->stmts; $extra_offsets = []; foreach ($extra_characters as $extra_offset) { $l = strlen($fake_class); for ($i = $extra_offset; $i < $l; $i++) { if (isset($extra_offsets[$i])) { $extra_offsets[$i]--; } else { $extra_offsets[$i] = -1; } } } $renumbering_traverser = new PhpParser\NodeTraverser(); $position_shifter = new \Psalm\Internal\PhpVisitor\OffsetShifterVisitor($stmt_start_pos - 15, $current_line, $extra_offsets); $renumbering_traverser->addVisitor($position_shifter); $replacement_stmts = $renumbering_traverser->traverse($replacement_stmts); if ($error_handler->hasErrors()) { foreach ($error_handler->getErrors() as $error) { if ($error->hasColumnInfo()) { /** @var array{startFilePos: int, endFilePos: int} */ $error_attrs = $error->getAttributes(); $error = new PhpParser\Error($error->getRawMessage(), ['startFilePos' => $stmt_start_pos + $error_attrs['startFilePos'] - 15, 'endFilePos' => $stmt_start_pos + $error_attrs['endFilePos'] - 15, 'startLine' => $error->getStartLine() + $current_line + $line_offset]); } $this->error_handler->handleError($error); } } $error_handler->clearErrors(); $traverseChildren = \false; return reset($replacement_stmts); } $this->must_rescan = \true; return PhpParser\NodeTraverser::STOP_TRAVERSAL; } if ($node->stmts) { /** @var int */ $stmt_inner_start_pos = $node->stmts[0]->getAttribute('startFilePos'); /** @var int */ $stmt_inner_end_pos = $node->stmts[count($node->stmts) - 1]->getAttribute('endFilePos'); if ($node instanceof PhpParser\Node\Stmt\ClassLike) { /** @psalm-suppress PossiblyFalseOperand */ $stmt_inner_start_pos = strrpos($this->a_file_contents, '{', $stmt_inner_start_pos - $this->a_file_contents_length) + 1; if ($stmt_inner_end_pos < $this->a_file_contents_length) { $stmt_inner_end_pos = strpos($this->a_file_contents, '}', $stmt_inner_end_pos + 1); } } if ($a_s > $stmt_inner_start_pos && $a_e < $stmt_inner_end_pos) { continue; } } } $this->must_rescan = \true; return PhpParser\NodeTraverser::STOP_TRAVERSAL; } if ($start_offset !== 0 || $end_offset !== 0 || $line_offset !== 0) { if ($start_offset !== 0) { if ($cs) { $new_comments = []; foreach ($cs as $c) { if ($c instanceof PhpParser\Comment\Doc) { $new_comments[] = new PhpParser\Comment\Doc($c->getText(), $c->getStartLine() + $line_offset, $c->getStartFilePos() + $start_offset); } else { $new_comments[] = new PhpParser\Comment($c->getText(), $c->getStartLine() + $line_offset, $c->getStartFilePos() + $start_offset); } } $node->setAttribute('comments', $new_comments); $node->setAttribute('startFilePos', $attrs['startFilePos'] + $start_offset); } else { $node->setAttribute('startFilePos', $stmt_start_pos + $start_offset); } } if ($end_offset !== 0) { $node->setAttribute('endFilePos', $stmt_end_pos + $end_offset); } if ($line_offset !== 0) { $node->setAttribute('startLine', $attrs['startLine'] + $line_offset); } return $node; } return null; } public function mustRescan() : bool { return $this->must_rescan || $this->non_method_changes; } /** * @psalm-pure */ private static function balanceBrackets(string $fake_class) : string { $tokens = token_get_all($fake_class); $brace_count = 0; foreach ($tokens as $token) { if ($token === '{') { ++$brace_count; } elseif ($token === '}') { --$brace_count; } } if ($brace_count > 0) { $fake_class .= str_repeat('}', $brace_count); } return $fake_class; } } $offset_map */ public function __construct(ErrorHandler $errorHandler, ?array $offset_map = null) { if ($offset_map) { foreach ($offset_map as [, , $b_s, $b_e]) { if ($this->start_change === null) { $this->start_change = $b_s; } $this->end_change = $b_e; } } $this->nameContext = new NameContext($errorHandler); } public function beforeTraverse(array $nodes) : ?array { $this->nameContext->startNamespace(); return null; } public function enterNode(Node $node) : ?int { if ($node instanceof Stmt\Namespace_) { $this->nameContext->startNamespace($node->name); } elseif ($node instanceof Stmt\Use_) { foreach ($node->uses as $use) { $this->addAlias($use, $node->type); } } elseif ($node instanceof Stmt\GroupUse) { foreach ($node->uses as $use) { $this->addAlias($use, $node->type, $node->prefix); } } elseif ($node instanceof Stmt\Class_) { if (null !== $node->extends) { $node->extends = $this->resolveClassName($node->extends); } foreach ($node->implements as &$interface) { $interface = $this->resolveClassName($interface); } unset($interface); $this->resolveAttrGroups($node); if (null !== $node->name) { $this->addNamespacedName($node); } } if ($node instanceof Stmt\ClassMethod && $this->start_change && $this->end_change) { /** @var array{startFilePos: int, endFilePos: int} */ $attrs = $node->getAttributes(); if ($cs = $node->getComments()) { $attrs['startFilePos'] = $cs[0]->getStartFilePos(); } if ($attrs['endFilePos'] < $this->start_change || $attrs['startFilePos'] > $this->end_change) { return PhpParser\NodeTraverser::DONT_TRAVERSE_CHILDREN; } } if ($node instanceof Stmt\ClassMethod || $node instanceof Expr\Closure) { $this->resolveSignature($node); } elseif ($node instanceof Expr\StaticCall || $node instanceof Expr\StaticPropertyFetch || $node instanceof Expr\ClassConstFetch || $node instanceof Expr\New_ || $node instanceof Expr\Instanceof_) { if ($node->class instanceof Name) { $node->class = $this->resolveClassName($node->class); } } elseif ($node instanceof Stmt\Catch_) { foreach ($node->types as &$type) { $type = $this->resolveClassName($type); } unset($type); } elseif ($node instanceof Expr\FuncCall) { if ($node->name instanceof Name) { $node->name = $this->resolveName($node->name, Stmt\Use_::TYPE_FUNCTION); } } elseif ($node instanceof Expr\ConstFetch) { $node->name = $this->resolveName($node->name, Stmt\Use_::TYPE_CONSTANT); } elseif ($node instanceof Stmt\Trait_) { $this->resolveTrait($node); } elseif ($node instanceof Stmt\TraitUse) { foreach ($node->traits as &$trait) { $trait = $this->resolveClassName($trait); } unset($trait); foreach ($node->adaptations as $adaptation) { if (null !== $adaptation->trait) { $adaptation->trait = $this->resolveClassName($adaptation->trait); } if ($adaptation instanceof Stmt\TraitUseAdaptation\Precedence) { foreach ($adaptation->insteadof as &$insteadof) { $insteadof = $this->resolveClassName($insteadof); } unset($insteadof); } } } return null; } private function addAlias(Stmt\UseUse $use, int $type, ?Name $prefix = null) : void { // Add prefix for group uses /** @var Name $name */ $name = $prefix ? Name::concat($prefix, $use->name) : $use->name; // Type is determined either by individual element or whole use declaration $type |= $use->type; $this->nameContext->addAlias($name, (string) $use->getAlias(), $type, $use->getAttributes()); } /** * @param Stmt\Function_|Stmt\ClassMethod|Expr\Closure $node */ private function resolveSignature(PhpParser\NodeAbstract $node) : void { foreach ($node->params as $param) { $param->type = $this->resolveType($param->type); } $node->returnType = $this->resolveType($node->returnType); } /** * @template T of Node|null * @param T $node * @return ($node is NullableType ? NullableType : ($node is Name ? Name : T)) */ private function resolveType(?Node $node) : ?Node { if ($node instanceof NullableType) { $node->type = $this->resolveType($node->type); return $node; } if ($node instanceof Name) { return $this->resolveClassName($node); } return $node; } /** * Resolve name, according to name resolver options. * * CAVE: Attribute values are of type `string`, this is * different to PhpParser's `NameResolver` using objects. * * @param Name $name Function or constant name to resolve * @param Stmt\Use_::TYPE_* $type One of Stmt\Use_::TYPE_* * @return Name Resolved name, or original name with attribute */ protected function resolveName(Name $name, int $type) : Name { $resolvedName = $this->nameContext->getResolvedName($name, $type); if (null !== $resolvedName) { $name->setAttribute('resolvedName', $resolvedName->toString()); } else { $namespaceName = Name\FullyQualified::concat($this->nameContext->getNamespace(), $name, $name->getAttributes()); if ($namespaceName instanceof Name) { $name->setAttribute('namespacedName', $namespaceName->toString()); } } return $name; } protected function resolveClassName(Name $name) : Name { return $this->resolveName($name, Stmt\Use_::TYPE_NORMAL); } protected function addNamespacedName(Stmt\Class_ $node) : void { $node->setAttribute('namespacedName', Name::concat($this->nameContext->getNamespace(), (string) $node->name)); } protected function resolveAttrGroups(Stmt\Class_ $node) : void { foreach ($node->attrGroups as $attrGroup) { foreach ($attrGroup->attrs as $attr) { $attr->name = $this->resolveClassName($attr->name); } } } protected function resolveTrait(Stmt\Trait_ $node) : void { $resolvedName = Name::concat($this->nameContext->getNamespace(), (string) $node->name); if (null !== $resolvedName) { $node->setAttribute('resolvedName', $resolvedName->toString()); } } } */ private array $functionlike_node_scanners = []; /** * @var array */ private array $classlike_node_scanners = []; private ?Name $namespace_name = null; private ?Expr $exists_cond_expr = null; private ?int $skip_if_descendants = null; /** * @var array */ private array $type_aliases = []; /** * @var array */ private array $bad_classes = []; private EventDispatcher $eventDispatcher; public function __construct(Codebase $codebase, FileScanner $file_scanner, FileStorage $file_storage) { $this->codebase = $codebase; $this->file_scanner = $file_scanner; $this->file_path = $file_scanner->file_path; $this->scan_deep = $file_scanner->will_analyze; $this->file_storage = $file_storage; $this->aliases = $this->file_storage->aliases = new Aliases(); $this->eventDispatcher = $this->codebase->config->eventDispatcher; } public function enterNode(PhpParser\Node $node) : ?int { foreach ($node->getComments() as $comment) { if ($comment instanceof PhpParser\Comment\Doc && !$node instanceof PhpParser\Node\Stmt\ClassLike) { try { $type_aliases = ClassLikeNodeScanner::getTypeAliasesFromComment($comment, $this->aliases, $this->type_aliases, null); foreach ($type_aliases as $type_alias) { // finds issues, if there are any TypeParser::parseTokens($type_alias->replacement_tokens); } $this->type_aliases += $type_aliases; } catch (DocblockParseException|TypeParseTreeException $e) { $this->file_storage->docblock_issues[] = new InvalidDocblock($e->getMessage(), new CodeLocation($this->file_scanner, $node, null, \true)); } } } if ($node instanceof PhpParser\Node\Stmt\Namespace_) { $this->handleNamespace($node); } elseif ($node instanceof PhpParser\Node\Stmt\Use_) { $this->handleUse($node); } elseif ($node instanceof PhpParser\Node\Stmt\GroupUse) { $this->handleGroupUse($node); } elseif ($node instanceof PhpParser\Node\Stmt\ClassLike) { if ($this->skip_if_descendants) { return null; } $classlike_node_scanner = new ClassLikeNodeScanner($this->codebase, $this->file_storage, $this->file_scanner, $this->aliases, $this->namespace_name); if ($classlike_node_scanner->start($node) === \false) { $this->bad_classes[spl_object_id($node)] = \true; return PhpParser\NodeTraverser::DONT_TRAVERSE_CURRENT_AND_CHILDREN; } $this->classlike_node_scanners[] = $classlike_node_scanner; $this->type_aliases = array_merge($this->type_aliases, $classlike_node_scanner->type_aliases); } elseif ($node instanceof PhpParser\Node\Stmt\TryCatch) { foreach ($node->catches as $catch) { foreach ($catch->types as $catch_type) { $catch_fqcln = ClassLikeAnalyzer::getFQCLNFromNameObject($catch_type, $this->aliases); if (!in_array(strtolower($catch_fqcln), ['self', 'static', 'parent'], \true)) { $this->codebase->scanner->queueClassLikeForScanning($catch_fqcln); $this->file_storage->referenced_classlikes[strtolower($catch_fqcln)] = $catch_fqcln; } } } } elseif ($node instanceof PhpParser\Node\FunctionLike) { if ($node instanceof PhpParser\Node\Stmt\Function_ || $node instanceof PhpParser\Node\Stmt\ClassMethod) { if ($this->skip_if_descendants) { return null; } } $classlike_storage = null; if ($this->classlike_node_scanners) { $classlike_node_scanner = end($this->classlike_node_scanners); $classlike_storage = $classlike_node_scanner->storage; } $functionlike_types = []; foreach ($this->functionlike_node_scanners as $functionlike_node_scanner) { $functionlike_storage = $functionlike_node_scanner->storage; $functionlike_types += $functionlike_storage->template_types ?? []; } $functionlike_node_scanner = new FunctionLikeNodeScanner($this->codebase, $this->file_scanner, $this->file_storage, $this->aliases, $this->type_aliases, $classlike_storage, $functionlike_types); $functionlike_node_scanner->start($node); $this->functionlike_node_scanners[] = $functionlike_node_scanner; if ($classlike_storage && $this->codebase->analysis_php_version_id >= 80000 && $node instanceof PhpParser\Node\Stmt\ClassMethod && strtolower($node->name->name) === '__tostring') { if ($classlike_storage->is_interface) { $classlike_storage->parent_interfaces['stringable'] = 'Stringable'; } else { $classlike_storage->class_implements['stringable'] = 'Stringable'; } if (PHP_VERSION_ID >= 80000) { $this->codebase->scanner->queueClassLikeForScanning('Stringable'); } } if (!$this->scan_deep) { return PhpParser\NodeTraverser::DONT_TRAVERSE_CHILDREN; } } elseif ($node instanceof PhpParser\Node\Stmt\Global_) { $functionlike_node_scanner = end($this->functionlike_node_scanners); if ($functionlike_node_scanner && $functionlike_node_scanner->storage) { foreach ($node->vars as $var) { if ($var instanceof PhpParser\Node\Expr\Variable) { if (is_string($var->name) && $var->name !== 'argv' && $var->name !== 'argc') { $var_id = '$' . $var->name; $functionlike_node_scanner->storage->global_variables[$var_id] = \true; if (isset($this->codebase->config->globals[$var_id])) { $var_type = Type::parseString($this->codebase->config->globals[$var_id]); /** @psalm-suppress UnusedMethodCall */ $var_type->queueClassLikesForScanning($this->codebase, $this->file_storage); } } } } } } elseif ($node instanceof PhpParser\Node\Stmt\TraitUse) { if ($this->skip_if_descendants) { return null; } if (!$this->classlike_node_scanners) { throw new LogicException('$this->classlike_node_scanners should not be empty'); } $classlike_node_scanner = end($this->classlike_node_scanners); $classlike_node_scanner->handleTraitUse($node); } elseif ($node instanceof PhpParser\Node\Stmt\Const_) { foreach ($node->consts as $const) { $const_type = SimpleTypeInferer::infer($this->codebase, new NodeDataProvider(), $const->value, $this->aliases) ?? Type::getMixed(); $fq_const_name = Type::getFQCLNFromString($const->name->name, $this->aliases); if ($this->codebase->register_stub_files || $this->codebase->register_autoload_files) { $this->codebase->addGlobalConstantType($fq_const_name, $const_type); } $this->file_storage->constants[$fq_const_name] = $const_type; $this->file_storage->declaring_constants[$fq_const_name] = $this->file_path; } } elseif ($node instanceof PhpParser\Node\Stmt\If_ && !$this->skip_if_descendants) { if (!$this->functionlike_node_scanners) { $this->exists_cond_expr = $node->cond; if (ExpressionResolver::enterConditional($this->codebase, $this->file_path, $this->exists_cond_expr) === \false) { // the else node should terminate the agreement $this->skip_if_descendants = $node->else ? $node->else->getLine() : $node->getLine(); } } } elseif ($node instanceof PhpParser\Node\Stmt\Else_) { if ($this->skip_if_descendants === $node->getLine()) { $this->skip_if_descendants = null; $this->exists_cond_expr = null; } elseif (!$this->skip_if_descendants) { if ($this->exists_cond_expr && ExpressionResolver::enterConditional($this->codebase, $this->file_path, $this->exists_cond_expr) === \true) { $this->skip_if_descendants = $node->getLine(); } } } elseif ($node instanceof Expr) { $functionlike_storage = null; if ($this->functionlike_node_scanners) { $functionlike_node_scanner = end($this->functionlike_node_scanners); $functionlike_storage = $functionlike_node_scanner->storage; } ExpressionScanner::scan($this->codebase, $this->file_scanner, $this->file_storage, $this->aliases, $node, $functionlike_storage, $this->skip_if_descendants); } if ($doc_comment = $node->getDocComment()) { $var_comments = []; $template_types = []; if ($this->classlike_node_scanners) { $classlike_node_scanner = end($this->classlike_node_scanners); $classlike_storage = $classlike_node_scanner->storage; $template_types = $classlike_storage->template_types ?? []; } foreach ($this->functionlike_node_scanners as $functionlike_node_scanner) { $functionlike_storage = $functionlike_node_scanner->storage; $template_types += $functionlike_storage->template_types ?? []; } try { $var_comments = CommentAnalyzer::getTypeFromComment($doc_comment, $this->file_scanner, $this->aliases, $template_types, $this->type_aliases); } catch (DocblockParseException $e) { // do nothing } foreach ($var_comments as $var_comment) { if (!$var_comment->type) { continue; } $var_type = $var_comment->type; /** @psalm-suppress UnusedMethodCall */ $var_type->queueClassLikesForScanning($this->codebase, $this->file_storage); } } if ($node instanceof PhpParser\Node\Expr\Assign || $node instanceof PhpParser\Node\Expr\AssignOp || $node instanceof PhpParser\Node\Expr\AssignRef) { if ($node->var instanceof PhpParser\Node\Expr\PropertyFetch && $node->var->var instanceof PhpParser\Node\Expr\Variable && $node->var->var->name === 'this' && $node->var->name instanceof PhpParser\Node\Identifier) { if ($this->functionlike_node_scanners) { $functionlike_node_scanner = end($this->functionlike_node_scanners); $functionlike_storage = $functionlike_node_scanner->storage; if ($functionlike_storage instanceof MethodStorage) { $functionlike_storage->this_property_mutations[$node->var->name->name] = \true; } } } } return null; } private function handleNamespace(PhpParser\Node\Stmt\Namespace_ $node) : void { $this->file_storage->aliases = $this->aliases; $this->namespace_name = $node->name; $this->aliases = new Aliases($node->name ? $node->name->toString() : '', $this->aliases->uses, $this->aliases->functions, $this->aliases->constants, $this->aliases->uses_flipped, $this->aliases->functions_flipped, $this->aliases->constants_flipped); $this->file_storage->namespace_aliases[(int) $node->getAttribute('startFilePos')] = $this->aliases; if ($node->stmts) { $this->aliases->namespace_first_stmt_start = (int) $node->stmts[0]->getAttribute('startFilePos'); } } private function handleUse(PhpParser\Node\Stmt\Use_ $node) : void { foreach ($node->uses as $use) { $use_path = $use->name->toString(); $use_alias = $use->alias->name ?? $use->name->getLast(); switch ($use->type !== PhpParser\Node\Stmt\Use_::TYPE_UNKNOWN ? $use->type : $node->type) { case PhpParser\Node\Stmt\Use_::TYPE_FUNCTION: $this->aliases->functions[strtolower($use_alias)] = $use_path; $this->aliases->functions_flipped[strtolower($use_path)] = $use_alias; break; case PhpParser\Node\Stmt\Use_::TYPE_CONSTANT: $this->aliases->constants[$use_alias] = $use_path; $this->aliases->constants_flipped[$use_path] = $use_alias; break; case PhpParser\Node\Stmt\Use_::TYPE_NORMAL: $this->aliases->uses[strtolower($use_alias)] = $use_path; $this->aliases->uses_flipped[strtolower($use_path)] = $use_alias; break; } } if (!$this->aliases->uses_start) { $this->aliases->uses_start = (int) $node->getAttribute('startFilePos'); } $this->aliases->uses_end = (int) $node->getAttribute('endFilePos') + 1; } private function handleGroupUse(PhpParser\Node\Stmt\GroupUse $node) : void { $use_prefix = $node->prefix->toString(); foreach ($node->uses as $use) { $use_path = $use_prefix . '\\' . $use->name->toString(); $use_alias = $use->alias->name ?? $use->name->getLast(); switch ($use->type !== PhpParser\Node\Stmt\Use_::TYPE_UNKNOWN ? $use->type : $node->type) { case PhpParser\Node\Stmt\Use_::TYPE_FUNCTION: $this->aliases->functions[strtolower($use_alias)] = $use_path; $this->aliases->functions_flipped[strtolower($use_path)] = $use_alias; break; case PhpParser\Node\Stmt\Use_::TYPE_CONSTANT: $this->aliases->constants[$use_alias] = $use_path; $this->aliases->constants_flipped[$use_path] = $use_alias; break; case PhpParser\Node\Stmt\Use_::TYPE_NORMAL: $this->aliases->uses[strtolower($use_alias)] = $use_path; $this->aliases->uses_flipped[strtolower($use_path)] = $use_alias; break; } } if (!$this->aliases->uses_start) { $this->aliases->uses_start = (int) $node->getAttribute('startFilePos'); } $this->aliases->uses_end = (int) $node->getAttribute('endFilePos') + 1; } /** * @return null */ public function leaveNode(PhpParser\Node $node) { if ($node instanceof PhpParser\Node\Stmt\Namespace_) { if (!$this->file_storage->aliases) { throw new UnexpectedValueException('File storage liases should not be null'); } $this->aliases = $this->file_storage->aliases; if ($this->codebase->register_stub_files && $node->name && $node->name->getParts() === ['PHPSTORM_META']) { foreach ($node->stmts as $meta_stmt) { if ($meta_stmt instanceof PhpParser\Node\Stmt\Expression && $meta_stmt->expr instanceof PhpParser\Node\Expr\FuncCall && $meta_stmt->expr->name instanceof Name && $meta_stmt->expr->name->getParts() === ['override']) { PhpStormMetaScanner::handleOverride($meta_stmt->expr->getArgs(), $this->codebase); } } } } elseif ($node instanceof PhpParser\Node\Stmt\ClassLike) { if ($this->skip_if_descendants) { return null; } if (isset($this->bad_classes[spl_object_id($node)])) { return null; } if (!$this->classlike_node_scanners) { throw new UnexpectedValueException('$this->classlike_node_scanners cannot be empty'); } $classlike_node_scanner = array_pop($this->classlike_node_scanners); $classlike_storage = $classlike_node_scanner->finish($node); if ($classlike_storage->has_visitor_issues) { $this->file_storage->has_visitor_issues = \true; } $event = new AfterClassLikeVisitEvent($node, $classlike_storage, $this, $this->codebase, []); $this->eventDispatcher->dispatchAfterClassLikeVisit($event); if (!$this->file_storage->has_visitor_issues) { $this->codebase->cacheClassLikeStorage($classlike_storage, $this->file_path); } } elseif ($node instanceof PhpParser\Node\FunctionLike) { if ($this->skip_if_descendants) { return null; } if (!$this->functionlike_node_scanners) { if ($this->file_storage->has_visitor_issues) { return null; } throw new UnexpectedValueException('There should be function storages for line ' . $this->file_path . ':' . $node->getStartLine()); } $functionlike_node_scanner = array_pop($this->functionlike_node_scanners); if ($functionlike_node_scanner->storage) { foreach ($functionlike_node_scanner->storage->docblock_issues as $docblock_issue) { if (strpos($docblock_issue->code_location->file_path, 'CoreGenericFunctions.phpstub') || strpos($docblock_issue->code_location->file_path, 'CoreGenericClasses.phpstub') || strpos($this->file_path, 'CoreGenericIterators.phpstub')) { $e = reset($functionlike_node_scanner->storage->docblock_issues); $fqcn_parts = explode('\\', get_class($e)); $issue_type = array_pop($fqcn_parts); $message = $e instanceof TaintedInput ? $e->getJourneyMessage() : $e->message; throw new CodeException('Error with core stub file docblocks: ' . $issue_type . ' - ' . $e->getShortLocationWithPrevious() . ':' . $e->code_location->getColumn() . ' - ' . $message); } } if ($functionlike_node_scanner->storage->has_visitor_issues) { $this->file_storage->has_visitor_issues = \true; } } } elseif ($node instanceof PhpParser\Node\Stmt\If_ && $node->getLine() === $this->skip_if_descendants) { $this->exists_cond_expr = null; $this->skip_if_descendants = null; } elseif ($node instanceof PhpParser\Node\Stmt\Else_ && $node->getLine() === $this->skip_if_descendants) { $this->exists_cond_expr = null; $this->skip_if_descendants = null; } return null; } /** @psalm-mutation-free */ public function getFilePath() : string { return $this->file_path; } /** @psalm-mutation-free */ public function getFileName() : string { return $this->file_scanner->getFileName(); } /** @psalm-mutation-free */ public function getRootFilePath() : string { return $this->file_scanner->getRootFilePath(); } /** @psalm-mutation-free */ public function getRootFileName() : string { return $this->file_scanner->getRootFileName(); } /** @psalm-mutation-free */ public function getAliases() : Aliases { return $this->aliases; } /** * @phpcsSuppress SlevomatCodingStandard.TypeHints.ReturnTypeHint.MissingAnyTypeHint */ public function afterTraverse(array $nodes) { $this->file_storage->type_aliases = $this->type_aliases; return null; } } */ private array $yield_types = []; private NodeDataProvider $nodes; public function __construct(NodeDataProvider $nodes) { $this->nodes = $nodes; } public function enterNode(Node $node) : ?int { if ($node instanceof Yield_) { $key_type = null; if ($node->key && ($node_key_type = $this->nodes->getType($node->key))) { $key_type = $node_key_type; } if ($node->value && ($value_type = $this->nodes->getType($node->value))) { $generator_type = new TGenericObject('Generator', [$key_type ? $key_type : Type::getInt(), $value_type, Type::getMixed(), Type::getMixed()]); $this->yield_types[] = new Union([$generator_type]); return null; } $this->yield_types[] = Type::getMixed(); } elseif ($node instanceof YieldFrom) { if ($node_expr_type = $this->nodes->getType($node->expr)) { $this->yield_types[] = $node_expr_type; return null; } $this->yield_types[] = Type::getMixed(); } elseif ($node instanceof FunctionLike) { return NodeTraverser::DONT_TRAVERSE_CHILDREN; } return null; } /** * @return list */ public function getYieldTypes() : array { return $this->yield_types; } } */ public static function getFormula(int $conditional_object_id, int $creating_object_id, PhpParser\Node\Expr $conditional, ?string $this_class_name, FileSource $source, ?Codebase $codebase = null, bool $inside_negation = \false, bool $cache = \true) : array { if ($conditional instanceof PhpParser\Node\Expr\BinaryOp\BooleanAnd || $conditional instanceof PhpParser\Node\Expr\BinaryOp\LogicalAnd) { $left_assertions = self::getFormula($conditional_object_id, spl_object_id($conditional->left), $conditional->left, $this_class_name, $source, $codebase, $inside_negation, $cache); $right_assertions = self::getFormula($conditional_object_id, spl_object_id($conditional->right), $conditional->right, $this_class_name, $source, $codebase, $inside_negation, $cache); return [...$left_assertions, ...$right_assertions]; } if ($conditional instanceof PhpParser\Node\Expr\BinaryOp\BooleanOr || $conditional instanceof PhpParser\Node\Expr\BinaryOp\LogicalOr) { $left_clauses = self::getFormula($conditional_object_id, spl_object_id($conditional->left), $conditional->left, $this_class_name, $source, $codebase, $inside_negation, $cache); $right_clauses = self::getFormula($conditional_object_id, spl_object_id($conditional->right), $conditional->right, $this_class_name, $source, $codebase, $inside_negation, $cache); return Algebra::combineOredClauses($left_clauses, $right_clauses, $conditional_object_id); } if ($conditional instanceof PhpParser\Node\Expr\BooleanNot) { if ($conditional->expr instanceof PhpParser\Node\Expr\BinaryOp\BooleanOr) { $and_expr = new VirtualBooleanAnd(new VirtualBooleanNot($conditional->expr->left, $conditional->getAttributes()), new VirtualBooleanNot($conditional->expr->right, $conditional->getAttributes()), $conditional->expr->getAttributes()); return self::getFormula($conditional_object_id, $conditional_object_id, $and_expr, $this_class_name, $source, $codebase, $inside_negation, \false); } if ($conditional->expr instanceof PhpParser\Node\Expr\Isset_ && count($conditional->expr->vars) > 1) { $anded_assertions = null; if ($cache && $source instanceof StatementsAnalyzer) { $anded_assertions = $source->node_data->getAssertions($conditional->expr); } if ($anded_assertions === null) { $anded_assertions = AssertionFinder::scrapeAssertions($conditional->expr, $this_class_name, $source, $codebase, $inside_negation, $cache); if ($cache && $source instanceof StatementsAnalyzer) { $source->node_data->setAssertions($conditional->expr, $anded_assertions); } } $clauses = []; foreach ($anded_assertions as $assertions) { foreach ($assertions as $var => $anded_types) { $redefined = \false; if ($var[0] === '=') { /** @var string */ $var = substr($var, 1); $redefined = \true; } foreach ($anded_types as $orred_types) { $mapped_orred_types = []; foreach ($orred_types as $orred_type) { $mapped_orred_types[(string) $orred_type] = $orred_type; } $clauses[] = new Clause([$var => $mapped_orred_types], $conditional_object_id, spl_object_id($conditional->expr), \false, \true, $orred_types[0]->hasEquality(), $redefined ? [$var => \true] : []); } } } return Algebra::negateFormula($clauses); } if ($conditional->expr instanceof PhpParser\Node\Expr\BinaryOp\BooleanAnd) { $and_expr = new VirtualBooleanOr(new VirtualBooleanNot($conditional->expr->left, $conditional->getAttributes()), new VirtualBooleanNot($conditional->expr->right, $conditional->getAttributes()), $conditional->expr->getAttributes()); return self::getFormula($conditional_object_id, spl_object_id($conditional->expr), $and_expr, $this_class_name, $source, $codebase, $inside_negation, \false); } return Algebra::negateFormula(self::getFormula($conditional_object_id, spl_object_id($conditional->expr), $conditional->expr, $this_class_name, $source, $codebase, !$inside_negation)); } if ($conditional instanceof PhpParser\Node\Expr\BinaryOp\Identical || $conditional instanceof PhpParser\Node\Expr\BinaryOp\Equal) { $false_pos = AssertionFinder::hasFalseVariable($conditional); $true_pos = AssertionFinder::hasTrueVariable($conditional); if ($false_pos === AssertionFinder::ASSIGNMENT_TO_RIGHT && ($conditional instanceof PhpParser\Node\Expr\BinaryOp\Equal || $conditional->left instanceof PhpParser\Node\Expr\BinaryOp\BooleanAnd || $conditional->left instanceof PhpParser\Node\Expr\BinaryOp\BooleanOr || $conditional->left instanceof PhpParser\Node\Expr\BooleanNot)) { return Algebra::negateFormula(self::getFormula($conditional_object_id, spl_object_id($conditional->left), $conditional->left, $this_class_name, $source, $codebase, !$inside_negation, $cache)); } if ($false_pos === AssertionFinder::ASSIGNMENT_TO_LEFT && ($conditional instanceof PhpParser\Node\Expr\BinaryOp\Equal || $conditional->right instanceof PhpParser\Node\Expr\BinaryOp\BooleanAnd || $conditional->right instanceof PhpParser\Node\Expr\BinaryOp\BooleanOr || $conditional->right instanceof PhpParser\Node\Expr\BooleanNot)) { return Algebra::negateFormula(self::getFormula($conditional_object_id, spl_object_id($conditional->right), $conditional->right, $this_class_name, $source, $codebase, !$inside_negation, $cache)); } if ($true_pos === AssertionFinder::ASSIGNMENT_TO_RIGHT && ($conditional instanceof PhpParser\Node\Expr\BinaryOp\Equal || $conditional->left instanceof PhpParser\Node\Expr\BinaryOp\BooleanAnd || $conditional->left instanceof PhpParser\Node\Expr\BinaryOp\BooleanOr || $conditional->left instanceof PhpParser\Node\Expr\BooleanNot)) { return self::getFormula($conditional_object_id, spl_object_id($conditional->left), $conditional->left, $this_class_name, $source, $codebase, $inside_negation, $cache); } if ($true_pos === AssertionFinder::ASSIGNMENT_TO_LEFT && ($conditional instanceof PhpParser\Node\Expr\BinaryOp\Equal || $conditional->right instanceof PhpParser\Node\Expr\BinaryOp\BooleanAnd || $conditional->right instanceof PhpParser\Node\Expr\BinaryOp\BooleanOr || $conditional->right instanceof PhpParser\Node\Expr\BooleanNot)) { return self::getFormula($conditional_object_id, spl_object_id($conditional->right), $conditional->right, $this_class_name, $source, $codebase, $inside_negation, $cache); } } if ($conditional instanceof PhpParser\Node\Expr\BinaryOp\NotIdentical || $conditional instanceof PhpParser\Node\Expr\BinaryOp\NotEqual) { $false_pos = AssertionFinder::hasFalseVariable($conditional); $true_pos = AssertionFinder::hasTrueVariable($conditional); if ($true_pos === AssertionFinder::ASSIGNMENT_TO_RIGHT && ($conditional instanceof PhpParser\Node\Expr\BinaryOp\NotEqual || $conditional->left instanceof PhpParser\Node\Expr\BinaryOp\BooleanAnd || $conditional->left instanceof PhpParser\Node\Expr\BinaryOp\BooleanOr || $conditional->left instanceof PhpParser\Node\Expr\BooleanNot)) { return Algebra::negateFormula(self::getFormula($conditional_object_id, spl_object_id($conditional->left), $conditional->left, $this_class_name, $source, $codebase, !$inside_negation, $cache)); } if ($true_pos === AssertionFinder::ASSIGNMENT_TO_LEFT && ($conditional instanceof PhpParser\Node\Expr\BinaryOp\NotEqual || $conditional->right instanceof PhpParser\Node\Expr\BinaryOp\BooleanAnd || $conditional->right instanceof PhpParser\Node\Expr\BinaryOp\BooleanOr || $conditional->right instanceof PhpParser\Node\Expr\BooleanNot)) { return Algebra::negateFormula(self::getFormula($conditional_object_id, spl_object_id($conditional->right), $conditional->right, $this_class_name, $source, $codebase, !$inside_negation, $cache)); } if ($false_pos === AssertionFinder::ASSIGNMENT_TO_RIGHT && ($conditional instanceof PhpParser\Node\Expr\BinaryOp\NotEqual || $conditional->left instanceof PhpParser\Node\Expr\BinaryOp\BooleanAnd || $conditional->left instanceof PhpParser\Node\Expr\BinaryOp\BooleanOr || $conditional->left instanceof PhpParser\Node\Expr\BooleanNot)) { return self::getFormula($conditional_object_id, spl_object_id($conditional->left), $conditional->left, $this_class_name, $source, $codebase, $inside_negation, $cache); } if ($false_pos === AssertionFinder::ASSIGNMENT_TO_LEFT && ($conditional instanceof PhpParser\Node\Expr\BinaryOp\NotEqual || $conditional->right instanceof PhpParser\Node\Expr\BinaryOp\BooleanAnd || $conditional->right instanceof PhpParser\Node\Expr\BinaryOp\BooleanOr || $conditional->right instanceof PhpParser\Node\Expr\BooleanNot)) { return self::getFormula($conditional_object_id, spl_object_id($conditional->right), $conditional->right, $this_class_name, $source, $codebase, $inside_negation, $cache); } } if ($conditional instanceof PhpParser\Node\Expr\Cast\Bool_) { return self::getFormula($conditional_object_id, spl_object_id($conditional->expr), $conditional->expr, $this_class_name, $source, $codebase, $inside_negation, $cache); } $anded_assertions = null; if ($cache && $source instanceof StatementsAnalyzer) { $anded_assertions = $source->node_data->getAssertions($conditional); } if ($anded_assertions === null) { $anded_assertions = AssertionFinder::scrapeAssertions($conditional, $this_class_name, $source, $codebase, $inside_negation, $cache); if ($cache && $source instanceof StatementsAnalyzer) { $source->node_data->setAssertions($conditional, $anded_assertions); } } $clauses = []; foreach ($anded_assertions as $assertions) { foreach ($assertions as $var => $anded_types) { $redefined = \false; if ($var[0] === '=') { /** @var string */ $var = substr($var, 1); $redefined = \true; } foreach ($anded_types as $orred_types) { $mapped_orred_types = []; foreach ($orred_types as $orred_type) { $mapped_orred_types[(string) $orred_type] = $orred_type; } $clauses[] = new Clause([$var => $mapped_orred_types], $conditional_object_id, $creating_object_id, \false, \true, $orred_types[0]->hasEquality(), $redefined ? [$var => \true] : []); } } } if ($clauses) { return $clauses; } /** @psalm-suppress MixedOperand */ $conditional_ref = '*' . $conditional->getAttribute('startFilePos') . ':' . $conditional->getAttribute('endFilePos'); return [new Clause([$conditional_ref => ['truthy' => new Truthy()]], $conditional_object_id, $creating_object_id)]; } } $data * @psalm-pure */ public static function encode(array $data, ?int $options = null) : string { if ($options === null) { $options = self::DEFAULT; } $result = json_encode($data, $options); if ($result == \false) { $result = json_encode(self::scrub($data), $options); } if ($result === \false) { /** @psalm-suppress ImpureFunctionCall */ throw new RuntimeException('Cannot create JSON string: ' . json_last_error_msg()); } return $result; } /** @psalm-pure */ private static function scrub(array $data) : array { /** @psalm-suppress ImpureFunctionCall */ array_walk_recursive( $data, /** * @psalm-pure * @param mixed $value */ function (&$value) : void { if (is_string($value)) { $value = preg_replace_callback(self::INVALID_UTF_REGEXP, static fn(array $matches): string => '', $value); } } ); return $data; } } $argv */ public static function run(array $argv) : void { CliUtils::checkRuntimeRequirements(); gc_collect_cycles(); gc_disable(); ErrorHandler::install($argv); $args = array_slice($argv, 1); // get options from command line $options = getopt(implode('', self::SHORT_OPTIONS), self::LONG_OPTIONS); self::validateCliArguments($args); CliUtils::setMemoryLimit($options); self::syncShortOptions($options); if (isset($options['c']) && is_array($options['c'])) { fwrite(STDERR, 'Too many config files provided' . PHP_EOL); exit(1); } if (array_key_exists('h', $options)) { echo <<runAndCollect( // we ignore the FQN because of a hack in scoper.inc that needs full path // phpcs:ignore SlevomatCodingStandard.Namespaces.ReferenceUsedNamesOnly.ReferenceViaFullyQualifiedName static fn(): ?\Composer\Autoload\ClassLoader => CliUtils::requireAutoloaders($current_dir, isset($options['r']), $vendor_dir) ); $ini_handler = new PsalmRestarter('PSALTER'); $ini_handler->disableExtensions(['grpc', 'uopz', 'pcov', 'blackfire']); // If Xdebug is enabled, restart without it $ini_handler->check(); $paths_to_check = CliUtils::getPathsToCheck($options['f'] ?? null); $path_to_config = CliUtils::getPathToConfig($options); $config = CliUtils::initializeConfig($path_to_config, $current_dir, Report::TYPE_CONSOLE, $first_autoloader); if (isset($options['no-cache'])) { $config->cache_directory = null; } $config->setIncludeCollector($include_collector); if ($config->resolve_from_config_file) { $current_dir = $config->base_dir; chdir($current_dir); } $threads = isset($options['threads']) && is_numeric($options['threads']) ? (int) $options['threads'] : 1; if (isset($options['no-cache'])) { $providers = new Providers(new FileProvider()); } else { $providers = new Providers(new FileProvider(), new ParserCacheProvider($config, \false), new FileStorageCacheProvider($config), new ClassLikeStorageCacheProvider($config), null, new ProjectCacheProvider(Composer::getLockFilePath($current_dir))); } if (array_key_exists('list-supported-issues', $options)) { echo implode(',', ProjectAnalyzer::getSupportedIssuesToFix()) . PHP_EOL; exit; } $debug = array_key_exists('debug', $options) || array_key_exists('debug-by-line', $options); if ($debug) { $progress = new DebugProgress(); } elseif (isset($options['no-progress'])) { $progress = new VoidProgress(); } else { $progress = new DefaultProgress(); } $stdout_report_options = new ReportOptions(); $stdout_report_options->use_color = !array_key_exists('m', $options); $project_analyzer = new ProjectAnalyzer($config, $providers, $stdout_report_options, [], $threads, $progress); if (array_key_exists('debug-by-line', $options)) { $project_analyzer->debug_lines = \true; } if (array_key_exists('debug-emitted-issues', $options)) { $config->debug_emitted_issues = \true; } if (array_key_exists('issues', $options)) { if (!is_string($options['issues']) || !$options['issues']) { fwrite(STDERR, 'Expecting a comma-separated list of issues' . PHP_EOL); exit(1); } $issues = explode(',', $options['issues']); $keyed_issues = []; foreach ($issues as $issue) { $keyed_issues[$issue] = \true; } } else { $keyed_issues = []; } CliUtils::initPhpVersion($options, $config, $project_analyzer); if (isset($options['codeowner'])) { $codeowner_files = self::loadCodeowners($providers); $desired_codeowners = is_array($options['codeowner']) ? $options['codeowner'] : [$options['codeowner']]; $files_for_codeowners = self::loadCodeownersFiles($desired_codeowners, $codeowner_files); $paths_to_check = is_array($paths_to_check) ? [...$paths_to_check, ...$files_for_codeowners] : $files_for_codeowners; } if (isset($options['allow-backwards-incompatible-changes'])) { $allow_backwards_incompatible_changes = filter_var($options['allow-backwards-incompatible-changes'], FILTER_VALIDATE_BOOLEAN, ['flags' => FILTER_NULL_ON_FAILURE]); if ($allow_backwards_incompatible_changes === null) { fwrite(STDERR, '--allow-backwards-incompatible-changes expects a boolean value [true|false|1|0]' . PHP_EOL); exit(1); } $project_analyzer->getCodebase()->allow_backwards_incompatible_changes = $allow_backwards_incompatible_changes; } if (isset($options['add-newline-between-docblock-annotations'])) { $doc_block_add_new_line_before_return = filter_var($options['add-newline-between-docblock-annotations'], FILTER_VALIDATE_BOOLEAN, ['flags' => FILTER_NULL_ON_FAILURE]); if ($doc_block_add_new_line_before_return === null) { fwrite(STDERR, '--add-newline-between-docblock-annotations expects a boolean value [true|false|1|0]' . PHP_EOL); exit(1); } ParsedDocblock::addNewLineBetweenAnnotations($doc_block_add_new_line_before_return); } $plugins = []; if (isset($options['plugin'])) { $plugins = $options['plugin']; if (!is_array($plugins)) { $plugins = [$plugins]; } } /** @var string $plugin_path */ foreach ($plugins as $plugin_path) { Config::getInstance()->addPluginPath($current_dir . $plugin_path); } $find_unused_code = array_key_exists('find-unused-code', $options); foreach ($keyed_issues as $issue_name => $_) { // MissingParamType requires the scanning of all files to inform possible params if (strpos($issue_name, 'Unused') !== \false || $issue_name === 'MissingParamType' || $issue_name === 'UnnecessaryVarAnnotation' || $issue_name === 'all') { $find_unused_code = \true; break; } } if ($find_unused_code) { $project_analyzer->getCodebase()->reportUnusedCode(); } $project_analyzer->alterCodeAfterCompletion(array_key_exists('dry-run', $options), array_key_exists('safe-types', $options)); if ($keyed_issues === ['all' => \true]) { $project_analyzer->setAllIssuesToFix(); } else { try { $project_analyzer->setIssuesToFix($keyed_issues); } catch (UnsupportedIssueToFixException $e) { fwrite(STDERR, $e->getMessage() . PHP_EOL); exit(1); } } $start_time = microtime(\true); if ($paths_to_check === null || count($paths_to_check) > 1 || $find_unused_code) { if ($paths_to_check) { $files_to_update = []; foreach ($paths_to_check as $path_to_check) { if (!is_dir($path_to_check)) { $files_to_update[] = (string) realpath($path_to_check); } else { foreach ($providers->file_provider->getFilesInDir($path_to_check, ['php']) as $php_file_path) { $files_to_update[] = $php_file_path; } } } $project_analyzer->getCodebase()->analyzer->setFilesToUpdate($files_to_update); } $project_analyzer->check($current_dir); } elseif ($paths_to_check) { foreach ($paths_to_check as $path_to_check) { if (is_dir($path_to_check)) { $project_analyzer->checkDir($path_to_check); } else { $project_analyzer->checkFile($path_to_check); } } } IssueBuffer::finish($project_analyzer, \false, $start_time); } /** @param array $args */ private static function validateCliArguments(array $args) : void { array_map(static function (string $arg) : void { if (strpos($arg, '--') === 0 && $arg !== '--') { $arg_name = preg_replace('/=.*$/', '', substr($arg, 2), 1); if ($arg_name === 'alter') { // valid option for psalm, ignored by psalter return; } if (!in_array($arg_name, self::LONG_OPTIONS) && !in_array($arg_name . ':', self::LONG_OPTIONS) && !in_array($arg_name . '::', self::LONG_OPTIONS)) { fwrite(STDERR, 'Unrecognised argument "--' . $arg_name . '"' . PHP_EOL . 'Type --help to see a list of supported arguments' . PHP_EOL); exit(1); } } }, $args); } /** * @param array|string> $options * @param-out array|string> $options */ private static function syncShortOptions(array &$options) : void { if (array_key_exists('help', $options)) { $options['h'] = \false; } if (array_key_exists('monochrome', $options)) { $options['m'] = \false; } if (isset($options['config'])) { $options['c'] = $options['config']; } if (isset($options['root'])) { $options['r'] = $options['root']; } } /** @return array> */ private static function loadCodeowners(Providers $providers) : array { if (file_exists('CODEOWNERS')) { $codeowners_file_path = realpath('CODEOWNERS'); } elseif (file_exists('.github/CODEOWNERS')) { $codeowners_file_path = realpath('.github/CODEOWNERS'); } elseif (file_exists('docs/CODEOWNERS')) { $codeowners_file_path = realpath('docs/CODEOWNERS'); } else { fwrite(STDERR, 'Cannot use --codeowner without a CODEOWNERS file' . PHP_EOL); exit(1); } $codeowners_file = file_get_contents($codeowners_file_path); $codeowner_lines = array_map(static function (string $line) : array { $line_parts = preg_split('/\\s+/', $line); if ($line_parts === \false) { throw new AssertionError("An error occurred: " . preg_last_error_msg()); } $file_selector = substr(array_shift($line_parts), 1); return [$file_selector, $line_parts]; }, array_filter(explode("\n", $codeowners_file), static function (string $line) : bool { $line = trim($line); // currently we don’t match wildcard files or files that could appear anywhere // in the repo return $line && $line[0] === '/' && strpos($line, '*') === \false; })); $codeowner_files = []; foreach ($codeowner_lines as [$path, $owners]) { if (!file_exists($path)) { continue; } foreach ($owners as $i => $owner) { $owners[$i] = strtolower($owner); } if (!is_dir($path)) { if (pathinfo($path, PATHINFO_EXTENSION) === 'php') { $codeowner_files[$path] = $owners; } } else { foreach ($providers->file_provider->getFilesInDir($path, ['php']) as $php_file_path) { $codeowner_files[$php_file_path] = $owners; } } } if (!$codeowner_files) { fwrite(STDERR, 'Could not find any available entries in CODEOWNERS' . PHP_EOL); exit(1); } return $codeowner_files; } /** * @param array> $codeowner_files * @return list */ private static function loadCodeownersFiles(array $desired_codeowners, array $codeowner_files) : array { $paths_to_check = []; /** @psalm-suppress MixedAssignment */ foreach ($desired_codeowners as $desired_codeowner) { if (!is_string($desired_codeowner)) { fwrite(STDERR, 'Invalid --codeowner ' . (string) $desired_codeowner . PHP_EOL); exit(1); } if ($desired_codeowner[0] !== '@') { fwrite(STDERR, '--codeowner option must start with @' . PHP_EOL); exit(1); } $matched_file = \false; foreach ($codeowner_files as $file_path => $owners) { if (in_array(strtolower($desired_codeowner), $owners)) { $paths_to_check[] = $file_path; $matched_file = \true; } } if (!$matched_file) { fwrite(STDERR, 'User/group ' . $desired_codeowner . ' does not own any PHP files' . PHP_EOL); exit(1); } } return $paths_to_check; } } $argv * @psalm-suppress ComplexMethod Maybe some of the option handling could be moved to its own function... */ public static function run(array $argv) : void { CliUtils::checkRuntimeRequirements(); gc_collect_cycles(); gc_disable(); ErrorHandler::install($argv); $args = array_slice($argv, 1); // get options from command line $options = getopt(implode('', self::SHORT_OPTIONS), self::LONG_OPTIONS); if (\false === $options) { throw new RuntimeException('Failed to parse CLI options'); } // debug CI environment if (!array_key_exists('debug', $options) && 'true' === getenv('GITHUB_ACTIONS') && '1' === getenv('RUNNER_DEBUG')) { $options['debug'] = \false; } self::forwardCliCall($options, $argv); self::validateCliArguments($args); CliUtils::setMemoryLimit($options); self::syncShortOptions($options); if (isset($options['c']) && is_array($options['c'])) { fwrite(STDERR, 'Too many config files provided' . PHP_EOL); exit(1); } if (array_key_exists('h', $options)) { echo self::getHelpText(); /* --shepherd[=endpoint] Send analysis statistics to Shepherd server. `endpoint` is the URL to the Shepherd server. It defaults to shepherd.dev */ exit; } $current_dir = self::getCurrentDir($options); $path_to_config = CliUtils::getPathToConfig($options); $vendor_dir = CliUtils::getVendorDir($current_dir); // capture environment before registering autoloader (it may destroy it) IssueBuffer::captureServer($_SERVER); $include_collector = new IncludeCollector(); $first_autoloader = $include_collector->runAndCollect( // we ignore the FQN because of a hack in scoper.inc that needs full path // phpcs:ignore SlevomatCodingStandard.Namespaces.ReferenceUsedNamesOnly.ReferenceViaFullyQualifiedName static fn(): ?\Composer\Autoload\ClassLoader => CliUtils::requireAutoloaders($current_dir, isset($options['r']), $vendor_dir) ); $run_taint_analysis = self::shouldRunTaintAnalysis($options); if (array_key_exists('v', $options)) { echo 'Psalm ' . \PSALM_VERSION . PHP_EOL; exit; } $output_format = self::initOutputFormat($options); [$config, $init_source_dir] = self::initConfig($current_dir, $args, $vendor_dir, $first_autoloader, $path_to_config, $output_format, $run_taint_analysis, $options); if (isset($options['no-cache'])) { $config->cache_directory = null; } $config->setIncludeCollector($include_collector); $in_ci = CliUtils::runningInCI(); // disable progressbar on CI if ($in_ci) { $options['long-progress'] = \true; } $threads = self::detectThreads($options, $config, $in_ci); $progress = self::initProgress($options, $config); self::restart($options, $threads, $progress); if (isset($options['debug-emitted-issues'])) { $config->debug_emitted_issues = \true; } setlocale(LC_CTYPE, 'C'); if (isset($options['set-baseline'])) { if (is_array($options['set-baseline'])) { fwrite(STDERR, 'Only one baseline file can be created at a time' . PHP_EOL); exit(1); } } $paths_to_check = CliUtils::getPathsToCheck($options['f'] ?? null); if ($config->resolve_from_config_file) { $current_dir = $config->base_dir; chdir($current_dir); } /** @var list $plugins List of paths to plugin files */ $plugins = []; if (isset($options['plugin'])) { $plugins_from_options = $options['plugin']; if (is_array($plugins_from_options)) { $plugins = $plugins_from_options; } elseif (is_string($plugins_from_options)) { $plugins = [$plugins_from_options]; } } $show_info = self::initShowInfo($options); $is_diff = self::initIsDiff($options); $find_unused_code = self::shouldFindUnusedCode($options, $config); $find_unused_variables = isset($options['find-unused-variables']); $find_references_to = isset($options['find-references-to']) && is_string($options['find-references-to']) ? $options['find-references-to'] : null; self::configureShepherd($config, $options, $plugins); if (isset($options['clear-cache'])) { self::clearCache($config); } if (isset($options['clear-global-cache'])) { self::clearGlobalCache($config); } $providers = self::initProviders($options, $config, $current_dir); $stdout_report_options = self::initStdoutReportOptions($options, $show_info, $output_format, $in_ci); /** @var list|string $report_file_paths type guaranteed by argument to getopt() */ $report_file_paths = $options['report'] ?? []; if (is_string($report_file_paths)) { $report_file_paths = [$report_file_paths]; } $project_analyzer = new ProjectAnalyzer($config, $providers, $stdout_report_options, ProjectAnalyzer::getFileReportOptions($report_file_paths, isset($options['report-show-info']) ? $options['report-show-info'] !== 'false' && $options['report-show-info'] !== '0' : \true), $threads, $progress); CliUtils::initPhpVersion($options, $config, $project_analyzer); $start_time = microtime(\true); self::configureProjectAnalyzer($options, $config, $project_analyzer, $find_references_to, $find_unused_code, $find_unused_variables, $run_taint_analysis); if ($config->run_taint_analysis || $run_taint_analysis) { $is_diff = \false; } /** @var string $plugin_path */ foreach ($plugins as $plugin_path) { $config->addPluginPath($plugin_path); } if ($paths_to_check === null) { $project_analyzer->check($current_dir, $is_diff); } elseif ($paths_to_check) { $project_analyzer->checkPaths($paths_to_check); } if ($find_references_to) { $project_analyzer->findReferencesTo($find_references_to); } self::storeFlowGraph($options, $project_analyzer); if (isset($options['generate-json-map']) && is_string($options['generate-json-map'])) { self::storeTypeMap($providers, $config, $options['generate-json-map']); } if (isset($options['generate-stubs'])) { self::generateStubs($options, $providers, $project_analyzer); } if (!isset($options['i'])) { IssueBuffer::finish($project_analyzer, !$paths_to_check, $start_time, isset($options['stats']), self::initBaseline($options, $config, $current_dir, $path_to_config, $paths_to_check)); } else { self::autoGenerateConfig($project_analyzer, $current_dir, $init_source_dir, $vendor_dir); } } private static function initOutputFormat(array $options) : string { return isset($options['output-format']) && is_string($options['output-format']) ? $options['output-format'] : self::findDefaultOutputFormat(); } /** * @return Report::TYPE_* */ private static function findDefaultOutputFormat() : string { $emulator = getenv('TERMINAL_EMULATOR'); if (is_string($emulator) && substr($emulator, 0, 9) === 'JetBrains') { return Report::TYPE_PHP_STORM; } if ('true' === getenv('GITHUB_ACTIONS')) { return Report::TYPE_GITHUB_ACTIONS; } return Report::TYPE_CONSOLE; } private static function initShowInfo(array $options) : bool { return isset($options['show-info']) ? $options['show-info'] === 'true' || $options['show-info'] === '1' : \false; } private static function initIsDiff(array $options) : bool { return !isset($options['no-diff']) && !isset($options['set-baseline']) && !isset($options['update-baseline']); } /** * @param array $args */ private static function validateCliArguments(array $args) : void { array_map(static function (string $arg) : void { if (strpos($arg, '--') === 0 && $arg !== '--') { $arg_name = preg_replace('/=.*$/', '', substr($arg, 2), 1); if (!in_array($arg_name, self::LONG_OPTIONS) && !in_array($arg_name . ':', self::LONG_OPTIONS) && !in_array($arg_name . '::', self::LONG_OPTIONS)) { fwrite(STDERR, 'Unrecognised argument "--' . $arg_name . '"' . PHP_EOL . 'Type --help to see a list of supported arguments' . PHP_EOL); exit(1); } } elseif (strpos($arg, '-') === 0 && $arg !== '-' && $arg !== '--') { $arg_name = preg_replace('/=.*$/', '', substr($arg, 1)); if (!in_array($arg_name, self::SHORT_OPTIONS) && !in_array($arg_name . ':', self::SHORT_OPTIONS)) { fwrite(STDERR, 'Unrecognised argument "-' . $arg_name . '"' . PHP_EOL . 'Type --help to see a list of supported arguments' . PHP_EOL); exit(1); } } }, $args); } /** * @param array $args */ private static function generateConfig(string $current_dir, array &$args) : void { if (file_exists($current_dir . DIRECTORY_SEPARATOR . 'psalm.xml')) { fwrite(STDERR, 'A config file already exists in the current directory' . PHP_EOL); exit(1); } $args = array_values(array_filter($args, static fn(string $arg): bool => $arg !== '--ansi' && $arg !== '--no-ansi' && $arg !== '-i' && $arg !== '--init' && $arg !== '--debug' && $arg !== '--debug-by-line' && $arg !== '--debug-emitted-issues' && strpos($arg, '--disable-extension=') !== 0 && strpos($arg, '--root=') !== 0 && strpos($arg, '--r=') !== 0)); $init_level = null; $init_source_dir = null; if (count($args)) { if (count($args) > 2) { fwrite(STDERR, 'Too many arguments provided for psalm --init' . PHP_EOL); exit(1); } if (isset($args[1])) { if (!preg_match('/^[1-8]$/', $args[1])) { fwrite(STDERR, 'Config strictness must be a number between 1 and 8 inclusive' . PHP_EOL); exit(1); } $init_level = (int) $args[1]; } $init_source_dir = $args[0]; } $vendor_dir = CliUtils::getVendorDir($current_dir); if (null !== $init_level) { try { $template_contents = Creator::getContents($current_dir, $init_source_dir, $init_level, $vendor_dir); } catch (ConfigCreationException $e) { fwrite(STDERR, $e->getMessage() . PHP_EOL); exit(1); } if (file_put_contents($current_dir . DIRECTORY_SEPARATOR . 'psalm.xml', $template_contents) === \false) { fwrite(STDERR, 'Could not write to psalm.xml' . PHP_EOL); exit(1); } exit('Config file created successfully. Please re-run psalm.' . PHP_EOL); } } private static function loadConfig(?string $path_to_config, string $current_dir, string $output_format, ?ClassLoader $first_autoloader, bool $run_taint_analysis, array $options) : Config { $config = CliUtils::initializeConfig($path_to_config, $current_dir, $output_format, $first_autoloader, $run_taint_analysis); if (isset($options['error-level']) && is_numeric($options['error-level'])) { $config_level = (int) $options['error-level']; if (!in_array($config_level, [1, 2, 3, 4, 5, 6, 7, 8], \true)) { throw new ConfigException('Invalid error level ' . $config_level); } $config->level = $config_level; } return $config; } private static function initProgress(array $options, Config $config) : Progress { $debug = array_key_exists('debug', $options) || array_key_exists('debug-by-line', $options); $show_info = isset($options['show-info']) ? $options['show-info'] === 'true' || $options['show-info'] === '1' : \false; if ($debug) { $progress = new DebugProgress(); } elseif (isset($options['no-progress'])) { $progress = new VoidProgress(); } else { $show_errors = !$config->error_baseline || isset($options['ignore-baseline']); if (isset($options['long-progress'])) { $progress = new LongProgress($show_errors, $show_info); } else { $progress = new DefaultProgress($show_errors, $show_info); } } // output buffered warnings foreach ($config->config_warnings as $warning) { $progress->warning($warning); } return $progress; } private static function initProviders(array $options, Config $config, string $current_dir) : Providers { if (isset($options['no-cache']) || isset($options['i'])) { $providers = new Providers(new FileProvider()); } else { $no_reflection_cache = isset($options['no-reflection-cache']); $no_file_cache = isset($options['no-file-cache']); $file_storage_cache_provider = $no_reflection_cache ? null : new FileStorageCacheProvider($config); $classlike_storage_cache_provider = $no_reflection_cache ? null : new ClassLikeStorageCacheProvider($config); $providers = new Providers(new FileProvider(), new ParserCacheProvider($config, !$no_file_cache), $file_storage_cache_provider, $classlike_storage_cache_provider, new FileReferenceCacheProvider($config), new ProjectCacheProvider(Composer::getLockFilePath($current_dir))); } return $providers; } /** * @param array{"set-baseline": string, ...} $options * @return array}>> */ private static function generateBaseline(array $options, Config $config, string $current_dir, ?string $path_to_config) : array { fwrite(STDERR, 'Writing error baseline to file...' . PHP_EOL); try { $issue_baseline = ErrorBaseline::read(new FileProvider(), $options['set-baseline']); } catch (ConfigException $e) { $issue_baseline = []; } ErrorBaseline::create(new FileProvider(), $options['set-baseline'], IssueBuffer::getIssuesData(), $config->include_php_versions_in_error_baseline || isset($options['include-php-versions'])); fwrite(STDERR, "Baseline saved to {$options['set-baseline']}."); CliUtils::updateConfigFile($config, $path_to_config ?? $current_dir, $options['set-baseline']); fwrite(STDERR, PHP_EOL); return $issue_baseline; } /** * @return array}>> */ private static function updateBaseline(array $options, Config $config) : array { $baselineFile = $config->error_baseline; if (empty($baselineFile)) { fwrite(STDERR, 'Cannot update baseline, because no baseline file is configured.' . PHP_EOL); exit(1); } try { $issue_current_baseline = ErrorBaseline::read(new FileProvider(), $baselineFile); $total_issues_current_baseline = ErrorBaseline::countTotalIssues($issue_current_baseline); $issue_baseline = ErrorBaseline::update(new FileProvider(), $baselineFile, IssueBuffer::getIssuesData(), $config->include_php_versions_in_error_baseline || isset($options['include-php-versions'])); $total_issues_updated_baseline = ErrorBaseline::countTotalIssues($issue_baseline); $total_fixed_issues = $total_issues_current_baseline - $total_issues_updated_baseline; if ($total_fixed_issues > 0) { echo str_repeat('-', 30) . "\n"; echo $total_fixed_issues . ' errors fixed' . "\n"; } } catch (ConfigException $exception) { fwrite(STDERR, 'Could not update baseline file: ' . $exception->getMessage() . PHP_EOL); exit(1); } return $issue_baseline; } private static function storeTypeMap(Providers $providers, Config $config, string $type_map_location) : void { $file_map = $providers->file_reference_provider->getFileMaps(); $name_file_map = []; $expected_references = []; foreach ($file_map as $file_path => $map) { $file_name = $config->shortenFileName($file_path); foreach ($map[0] as $map_parts) { $expected_references[$map_parts[1]] = \true; } $map[2] = []; $name_file_map[$file_name] = $map; } $reference_dictionary = ReferenceMapGenerator::getReferenceMap($providers->classlike_storage_provider, $expected_references); $type_map_string = json_encode(['files' => $name_file_map, 'references' => $reference_dictionary], JSON_THROW_ON_ERROR); $providers->file_provider->setContents($type_map_location, $type_map_string); } private static function autoGenerateConfig(ProjectAnalyzer $project_analyzer, string $current_dir, ?string $init_source_dir, string $vendor_dir) : void { $issues_by_file = IssueBuffer::getIssuesData(); if (!$issues_by_file) { $init_level = 1; } else { $codebase = $project_analyzer->getCodebase(); $mixed_counts = $codebase->analyzer->getTotalTypeCoverage($codebase); $init_level = Creator::getLevel(array_merge(...array_values($issues_by_file)), array_sum($mixed_counts)); } echo "\n" . 'Detected level ' . $init_level . ' as a suitable initial default' . "\n"; try { $template_contents = Creator::getContents($current_dir, $init_source_dir, $init_level, $vendor_dir); } catch (ConfigCreationException $e) { fwrite(STDERR, $e->getMessage() . PHP_EOL); exit(1); } if (file_put_contents($current_dir . DIRECTORY_SEPARATOR . 'psalm.xml', $template_contents) === \false) { fwrite(STDERR, 'Could not write to psalm.xml' . PHP_EOL); exit(1); } exit('Config file created successfully. Please re-run psalm.' . PHP_EOL); } private static function initStdoutReportOptions(array $options, bool $show_info, string $output_format, bool $in_ci) : ReportOptions { $stdout_report_options = new ReportOptions(); $stdout_report_options->use_color = !array_key_exists('m', $options); $stdout_report_options->show_info = $show_info; $stdout_report_options->show_suggestions = !array_key_exists('no-suggestions', $options); /** * @psalm-suppress PropertyTypeCoercion */ $stdout_report_options->format = $output_format; $stdout_report_options->show_snippet = !isset($options['show-snippet']) || $options['show-snippet'] !== "false"; $stdout_report_options->pretty = isset($options['pretty-print']) && $options['pretty-print'] !== "false"; $stdout_report_options->in_ci = $in_ci; return $stdout_report_options; } /** @return never */ private static function clearGlobalCache(Config $config) : void { $cache_directory = $config->getGlobalCacheDirectory(); if ($cache_directory) { Config::removeCacheDirectory($cache_directory); echo 'Global cache directory deleted' . PHP_EOL; } exit; } /** @return never */ private static function clearCache(Config $config) : void { $cache_directory = $config->getCacheDirectory(); if ($cache_directory !== null) { Config::removeCacheDirectory($cache_directory); } echo 'Cache directory deleted' . PHP_EOL; exit; } private static function getCurrentDir(array $options) : string { $cwd = getcwd(); if (\false === $cwd) { fwrite(STDERR, 'Cannot get current working directory' . PHP_EOL); exit(1); } $current_dir = $cwd; if (isset($options['r']) && is_string($options['r'])) { $root_path = realpath($options['r']); if ($root_path === \false) { fwrite(STDERR, 'Could not locate root directory ' . $current_dir . DIRECTORY_SEPARATOR . $options['r'] . PHP_EOL); exit(1); } $current_dir = $root_path; } return $current_dir; } private static function restart(array $options, int $threads, Progress $progress) : void { $ini_handler = new PsalmRestarter('PSALM'); if (isset($options['disable-extension'])) { if (is_array($options['disable-extension'])) { /** @psalm-suppress MixedAssignment */ foreach ($options['disable-extension'] as $extension) { if (is_string($extension)) { $ini_handler->disableExtension($extension); } } } elseif (is_string($options['disable-extension'])) { $ini_handler->disableExtension($options['disable-extension']); } } if ($threads > 1 && extension_loaded('grpc') && (ini_get('grpc.enable_fork_support') === '1' && ini_get('grpc.poll_strategy') === 'epoll1') === \false) { $ini_handler->disableExtension('grpc'); $progress->warning(PHP_EOL . 'grpc extension has been disabled. ' . 'Set grpc.enable_fork_support = 1 and grpc.poll_strategy = epoll1 in php.ini to enable it. ' . 'See https://github.com/grpc/grpc/issues/20250#issuecomment-531321945 for more information.' . PHP_EOL . PHP_EOL); } $ini_handler->disableExtensions([ 'uopz', // extesions that are incompatible with JIT (they are also usually make Psalm slow) 'pcov', 'blackfire', ]); // If Xdebug is enabled, restart without it $ini_handler->check(); if (!function_exists('opcache_get_status')) { $progress->write(PHP_EOL . 'Install the opcache extension to make use of JIT on PHP 8.0+ for a 20%+ performance boost!' . PHP_EOL . PHP_EOL); } } private static function detectThreads(array $options, Config $config, bool $in_ci) : int { if (isset($options['threads'])) { $threads = (int) $options['threads']; } elseif (isset($options['debug']) || $in_ci) { $threads = 1; } elseif ($config->threads) { $threads = $config->threads; } else { $threads = max(1, ProjectAnalyzer::getCpuCount() - 1); } return $threads; } /** @psalm-suppress UnusedParam $argv is being reported as unused */ private static function forwardCliCall(array $options, array $argv) : void { if (isset($options['alter'])) { require_once __DIR__ . '/Psalter.php'; \Psalm\Internal\Cli\Psalter::run($argv); exit; } if (isset($options['language-server'])) { require_once __DIR__ . '/LanguageServer.php'; \Psalm\Internal\Cli\LanguageServer::run($argv); exit; } if (isset($options['refactor'])) { require_once __DIR__ . '/Refactor.php'; \Psalm\Internal\Cli\Refactor::run($argv); exit; } } /** * @param array|string> $options * @param-out array|string> $options */ private static function syncShortOptions(array &$options) : void { if (array_key_exists('help', $options)) { $options['h'] = \false; } if (array_key_exists('version', $options)) { $options['v'] = \false; } if (array_key_exists('init', $options)) { $options['i'] = \false; } if (array_key_exists('monochrome', $options)) { $options['m'] = \false; } if (isset($options['config'])) { $options['c'] = $options['config']; } if (isset($options['root'])) { $options['r'] = $options['root']; } } /** * @param array $args * @return array{Config,?string} */ private static function initConfig(string $current_dir, array $args, string $vendor_dir, ?ClassLoader $first_autoloader, ?string $path_to_config, string $output_format, bool $run_taint_analysis, array $options) : array { $init_source_dir = null; if (isset($options['i'])) { self::generateConfig($current_dir, $args); // if we ever got here, it means we need to run Psalm once and generate the config // based on the errors we find $init_source_dir = $args[0] ?? null; echo "Calculating best config level based on project files\n"; Creator::createBareConfig($current_dir, $init_source_dir, $vendor_dir); $config = Config::getInstance(); $config->setComposerClassLoader($first_autoloader); } else { $config = self::loadConfig($path_to_config, $current_dir, $output_format, $first_autoloader, $run_taint_analysis, $options); } return [$config, $init_source_dir]; } /** * @param ?list $paths_to_check * @return array}>> */ private static function initBaseline(array $options, Config $config, string $current_dir, ?string $path_to_config, ?array $paths_to_check) : array { $issue_baseline = []; if (isset($options['set-baseline']) && is_string($options['set-baseline'])) { if ($paths_to_check !== null) { fwrite(STDERR, PHP_EOL . 'Cannot generate baseline when checking specific files' . PHP_EOL); exit(1); } $issue_baseline = self::generateBaseline($options, $config, $current_dir, $path_to_config); } if (isset($options['use-baseline'])) { if (!is_string($options['use-baseline'])) { fwrite(STDERR, '--use-baseline must be a string' . PHP_EOL); exit(1); } $baseline_file_path = $options['use-baseline']; $config->error_baseline = $baseline_file_path; } else { $baseline_file_path = $config->error_baseline; } if (isset($options['update-baseline'])) { if ($paths_to_check !== null) { fwrite(STDERR, PHP_EOL . 'Cannot update baseline when checking specific files' . PHP_EOL); exit(1); } $issue_baseline = self::updateBaseline($options, $config); } if (!$issue_baseline && $baseline_file_path && !isset($options['ignore-baseline'])) { try { $issue_baseline = ErrorBaseline::read(new FileProvider(), $baseline_file_path); } catch (ConfigException $exception) { fwrite(STDERR, 'Error while reading baseline: ' . $exception->getMessage() . PHP_EOL); exit(1); } } if ($paths_to_check !== null) { $filtered_issue_baseline = []; foreach ($paths_to_check as $path_to_check) { // +1 to remove the initial slash from $path_to_check $path_to_check = substr($path_to_check, strlen($config->base_dir) + 1); if (isset($issue_baseline[$path_to_check])) { $filtered_issue_baseline[$path_to_check] = $issue_baseline[$path_to_check]; } } $issue_baseline = $filtered_issue_baseline; } return $issue_baseline; } private static function storeFlowGraph(array $options, ProjectAnalyzer $project_analyzer) : void { /** @var string|null $dump_taint_graph */ $dump_taint_graph = $options['dump-taint-graph'] ?? null; $flow_graph = $project_analyzer->getCodebase()->taint_flow_graph; if ($flow_graph !== null && $dump_taint_graph !== null) { file_put_contents($dump_taint_graph, "digraph Taints {\n\t" . implode("\n\t", array_map(static fn(array $edges) => '"' . implode('" -> "', $edges) . '"', $flow_graph->summarizeEdges())) . "\n}\n"); } } /** @return false|'always'|'auto' */ private static function shouldFindUnusedCode(array $options, Config $config) { $find_unused_code = \false; if (isset($options['find-dead-code'])) { $options['find-unused-code'] = $options['find-dead-code'] === 'always' ? 'always' : 'auto'; } if (isset($options['find-unused-code'])) { if ($options['find-unused-code'] === 'always') { $find_unused_code = 'always'; } else { $find_unused_code = 'auto'; } } elseif ($config->find_unused_code) { $find_unused_code = 'auto'; } return $find_unused_code; } private static function shouldRunTaintAnalysis(array $options) : bool { return isset($options['track-tainted-input']) || isset($options['security-analysis']) || isset($options['taint-analysis']); } /** * @param string|bool|null $find_references_to * @param false|'always'|'auto' $find_unused_code */ private static function configureProjectAnalyzer(array $options, Config $config, ProjectAnalyzer $project_analyzer, $find_references_to, $find_unused_code, bool $find_unused_variables, bool $run_taint_analysis) : void { if (isset($options['generate-json-map']) && is_string($options['generate-json-map'])) { $project_analyzer->getCodebase()->store_node_types = \true; } if (array_key_exists('debug-by-line', $options)) { $project_analyzer->debug_lines = \true; } if (array_key_exists('debug-performance', $options)) { $project_analyzer->debug_performance = \true; } if ($find_references_to !== null) { $project_analyzer->getCodebase()->collectLocations(); $project_analyzer->show_issues = \false; } if ($find_unused_code) { $project_analyzer->getCodebase()->reportUnusedCode($find_unused_code); } if ($config->find_unused_variables || $find_unused_variables) { $project_analyzer->getCodebase()->reportUnusedVariables(); } if ($config->run_taint_analysis || $run_taint_analysis) { $project_analyzer->trackTaintedInputs(); } if ($config->find_unused_psalm_suppress || isset($options['find-unused-psalm-suppress'])) { $project_analyzer->trackUnusedSuppressions(); } } private static function configureShepherd(Config $config, array $options, array &$plugins) : void { if (is_string(getenv('PSALM_SHEPHERD_HOST'))) { // remove this block in Psalm 6 fwrite(STDERR, 'Warning: PSALM_SHEPHERD_HOST env variable will be removed in Psalm 6.' . ' Please use "--shepherd" cli option or PSALM_SHEPHERD env variable' . ' to specify a custom Shepherd host/endpoint.' . PHP_EOL); } $is_shepherd_enabled = isset($options['shepherd']) || getenv('PSALM_SHEPHERD'); if (!$is_shepherd_enabled) { return; } $plugins[] = Path::canonicalize(__DIR__ . '/../../Plugin/Shepherd.php'); /** @psalm-suppress MixedAssignment */ $custom_shepherd_endpoint = $options['shepherd'] ?? getenv('PSALM_SHEPHERD'); if (is_string($custom_shepherd_endpoint) && strlen($custom_shepherd_endpoint) > 2) { if (parse_url($custom_shepherd_endpoint, PHP_URL_SCHEME) === null) { $custom_shepherd_endpoint = 'https://' . $custom_shepherd_endpoint; } /** @psalm-suppress DeprecatedProperty */ $config->shepherd_host = str_replace('/hooks/psalm', '', $custom_shepherd_endpoint); $config->shepherd_endpoint = $custom_shepherd_endpoint; return; } // Legacy part, will be removed in Psalm 6 $custom_shepherd_host = getenv('PSALM_SHEPHERD_HOST'); if (is_string($custom_shepherd_host)) { if (parse_url($custom_shepherd_host, PHP_URL_SCHEME) === null) { $custom_shepherd_host = 'https://' . $custom_shepherd_host; } /** @psalm-suppress DeprecatedProperty */ $config->shepherd_host = $custom_shepherd_host; $config->shepherd_endpoint = $custom_shepherd_host . '/hooks/psalm'; } } private static function generateStubs(array $options, Providers $providers, ProjectAnalyzer $project_analyzer) : void { if (isset($options['generate-stubs']) && is_string($options['generate-stubs'])) { $stubs_location = $options['generate-stubs']; $providers->file_provider->setContents($stubs_location, StubsGenerator::getAll($project_analyzer->getCodebase(), $providers->classlike_storage_provider, $providers->file_storage_provider)); } } /** * @psalm-pure */ private static function getHelpText() : string { $formats = []; /** @var string $value */ foreach ((new ReflectionClass(Report::class))->getConstants() as $constant => $value) { if (strpos($constant, 'TYPE_') === 0) { $formats[] = $value; } } sort($formats); $outputFormats = wordwrap(implode(', ', $formats), 75, "\n "); /** @psalm-suppress ImpureMethodCall */ $reports = array_keys(Report::getMapping()); sort($reports); $reportFormats = wordwrap('"' . implode('", "', $reports) . '"', 75, "\n "); return <<addCommands([new ShowCommand($plugin_list_factory), new EnableCommand($plugin_list_factory), new DisableCommand($plugin_list_factory)]); $app->setDefaultCommand('show'); $app->run(); } } $argv */ public static function run(array $argv) : void { CliUtils::checkRuntimeRequirements(); ini_set('memory_limit', '8192M'); gc_collect_cycles(); gc_disable(); ErrorHandler::install($argv); $args = array_slice($argv, 1); $valid_short_options = ['f:', 'm', 'h', 'r:', 'c:']; $valid_long_options = ['help', 'debug', 'debug-by-line', 'debug-emitted-issues', 'config:', 'root:', 'threads:', 'move:', 'into:', 'rename:', 'to:']; // get options from command line $options = getopt(implode('', $valid_short_options), $valid_long_options); array_map(static function (string $arg) use($valid_long_options) : void { if (strpos($arg, '--') === 0 && $arg !== '--') { $arg_name = preg_replace('/=.*$/', '', substr($arg, 2), 1); if ($arg_name === 'refactor') { // valid option for psalm, ignored by psalter return; } if (!in_array($arg_name, $valid_long_options) && !in_array($arg_name . ':', $valid_long_options) && !in_array($arg_name . '::', $valid_long_options)) { fwrite(STDERR, 'Unrecognised argument "--' . $arg_name . '"' . PHP_EOL . 'Type --help to see a list of supported arguments' . PHP_EOL); exit(1); } } }, $args); if (array_key_exists('help', $options)) { $options['h'] = \false; } if (isset($options['config'])) { $options['c'] = $options['config']; } if (isset($options['c']) && is_array($options['c'])) { fwrite(STDERR, 'Too many config files provided' . PHP_EOL); exit(1); } if (array_key_exists('h', $options)) { echo <<runAndCollect( // we ignore the FQN because of a hack in scoper.inc that needs full path // phpcs:ignore SlevomatCodingStandard.Namespaces.ReferenceUsedNamesOnly.ReferenceViaFullyQualifiedName static fn(): ?\Composer\Autoload\ClassLoader => CliUtils::requireAutoloaders($current_dir, isset($options['r']), $vendor_dir) ); // If Xdebug is enabled, restart without it (new XdebugHandler('PSALTER'))->check(); $path_to_config = CliUtils::getPathToConfig($options); $args = CliUtils::getArguments(); $operation = null; $last_arg = null; $to_refactor = []; foreach ($args as $arg) { if ($arg === '--move') { $operation = 'move'; continue; } if ($arg === '--into') { if ($operation !== 'move' || !$last_arg) { fwrite(STDERR, '--into is not expected here' . PHP_EOL); exit(1); } $operation = 'move_into'; continue; } if ($arg === '--rename') { $operation = 'rename'; continue; } if ($arg === '--to') { if ($operation !== 'rename' || !$last_arg) { fwrite(STDERR, '--to is not expected here' . PHP_EOL); exit(1); } $operation = 'rename_to'; continue; } if ($arg[0] === '-') { $operation = null; continue; } if ($operation === 'move_into' || $operation === 'rename_to') { if (!$last_arg) { fwrite(STDERR, 'Expecting a previous argument' . PHP_EOL); exit(1); } if ($operation === 'move_into') { $last_arg_parts = preg_split('/, ?/', $last_arg); if ($last_arg_parts === \false) { throw new AssertionError(preg_last_error_msg()); } foreach ($last_arg_parts as $last_arg_part) { if (strpos($last_arg_part, '::')) { [, $identifier_name] = explode('::', $last_arg_part); $to_refactor[$last_arg_part] = $arg . '::' . $identifier_name; } else { $namespace_parts = explode('\\', $last_arg_part); $class_name = end($namespace_parts); $to_refactor[$last_arg_part] = $arg . '\\' . $class_name; } } } else { $to_refactor[$last_arg] = $arg; } $last_arg = null; $operation = null; continue; } if ($operation === 'move' || $operation === 'rename') { $last_arg = $arg; continue; } fwrite(STDERR, 'Unexpected argument "' . $arg . '"' . PHP_EOL); exit(1); } if (!$to_refactor) { fwrite(STDERR, 'No --move or --rename arguments supplied' . PHP_EOL); exit(1); } $config = CliUtils::initializeConfig($path_to_config, $current_dir, Report::TYPE_CONSOLE, $first_autoloader); $config->setIncludeCollector($include_collector); if ($config->resolve_from_config_file) { $current_dir = $config->base_dir; chdir($current_dir); } $threads = isset($options['threads']) && is_numeric($options['threads']) ? (int) $options['threads'] : max(1, ProjectAnalyzer::getCpuCount() - 2); $providers = new Providers(new FileProvider(), new ParserCacheProvider($config, \false), new FileStorageCacheProvider($config), new ClassLikeStorageCacheProvider($config), null, new ProjectCacheProvider(Composer::getLockFilePath($current_dir))); $debug = array_key_exists('debug', $options) || array_key_exists('debug-by-line', $options); $progress = $debug ? new DebugProgress() : new DefaultProgress(); if (array_key_exists('debug-emitted-issues', $options)) { $config->debug_emitted_issues = \true; } $project_analyzer = new ProjectAnalyzer($config, $providers, new ReportOptions(), [], $threads, $progress); if (array_key_exists('debug-by-line', $options)) { $project_analyzer->debug_lines = \true; } $project_analyzer->refactorCodeAfterCompletion($to_refactor); $start_time = microtime(\true); $project_analyzer->check($current_dir); IssueBuffer::finish($project_analyzer, \false, $start_time); } } $argv * @psalm-suppress ComplexMethod */ public static function run(array $argv) : void { CliUtils::checkRuntimeRequirements(); $clientConfiguration = new ClientConfiguration(); gc_disable(); ErrorHandler::install($argv); $valid_short_options = ['h', 'v', 'c:', 'r:']; $valid_long_options = ['config:', 'find-dead-code', 'help', 'root:', 'map-folder::', 'use-ini-defaults', 'version', 'tcp:', 'tcp-server', 'disable-on-change::', 'use-baseline:', 'enable-autocomplete::', 'enable-code-actions::', 'enable-provide-diagnostics::', 'enable-provide-hover::', 'enable-provide-signature-help::', 'enable-provide-definition::', 'show-diagnostic-warnings::', 'in-memory::', 'disable-xdebug::', 'on-change-debounce-ms::', 'use-extended-diagnostic-codes', 'verbose']; $args = array_slice($argv, 1); $psalm_proxy = array_search('--language-server', $args, \true); if ($psalm_proxy !== \false) { unset($args[$psalm_proxy]); } array_map(static function (string $arg) use($valid_long_options) : void { if (strpos($arg, '--') === 0 && $arg !== '--') { $arg_name = preg_replace('/=.*$/', '', substr($arg, 2), 1); if (!in_array($arg_name, $valid_long_options, \true) && !in_array($arg_name . ':', $valid_long_options, \true) && !in_array($arg_name . '::', $valid_long_options, \true)) { fwrite(STDERR, 'Unrecognised argument "--' . $arg_name . '"' . PHP_EOL . 'Type --help to see a list of supported arguments' . PHP_EOL); error_log('Bad argument'); exit(1); } } }, $args); // get options from command line $options = getopt(implode('', $valid_short_options), $valid_long_options); if ($options === \false) { // shouldn't really happen, but just in case fwrite(STDERR, 'Failed to get CLI args' . PHP_EOL); exit(1); } if (!array_key_exists('use-ini-defaults', $options)) { ini_set('display_errors', '1'); ini_set('display_startup_errors', '1'); ini_set('memory_limit', (string) (8 * 1024 * 1024 * 1024)); } if (array_key_exists('help', $options)) { $options['h'] = \false; } if (array_key_exists('version', $options)) { $options['v'] = \false; } if (isset($options['config'])) { $options['c'] = $options['config']; } if (isset($options['c']) && is_array($options['c'])) { fwrite(STDERR, 'Too many config files provided' . PHP_EOL); exit(1); } if (array_key_exists('h', $options)) { echo <<runAndCollect( // we ignore the FQN because of a hack in scoper.inc that needs full path // phpcs:ignore SlevomatCodingStandard.Namespaces.ReferenceUsedNamesOnly.ReferenceViaFullyQualifiedName static fn(): ?\Composer\Autoload\ClassLoader => CliUtils::requireAutoloaders($current_dir, isset($options['r']), $vendor_dir) ); if (array_key_exists('v', $options)) { echo 'Psalm ' . \PSALM_VERSION . PHP_EOL; exit; } $ini_handler = new PsalmRestarter('PSALM'); $ini_handler->disableExtensions([ 'grpc', 'uopz', // extensions bellow are incompatible with JIT 'pcov', 'blackfire', ]); $disableXdebug = !isset($options['disable-xdebug']) || !is_string($options['disable-xdebug']) || strtolower($options['disable-xdebug']) !== 'false'; // If Xdebug is enabled, restart without it based on cli if ($disableXdebug) { $ini_handler->check(); } setlocale(LC_CTYPE, 'C'); $path_mapper = self::createPathMapper($options, $current_dir); $path_to_config = CliUtils::getPathToConfig($options); if (isset($options['tcp']) && !is_string($options['tcp'])) { fwrite(STDERR, 'tcp url should be a string' . PHP_EOL); exit(1); } $config = CliUtils::initializeConfig($path_to_config, $current_dir, Report::TYPE_CONSOLE, $first_autoloader); $config->setIncludeCollector($include_collector); if ($config->resolve_from_config_file) { $current_dir = $config->base_dir; chdir($current_dir); } $config->setServerMode(); $inMemory = isset($options['in-memory']) && is_string($options['in-memory']) && strtolower($options['in-memory']) === 'true'; if ($inMemory) { $config->cache_directory = null; } else { $cache_directory = $config->getCacheDirectory(); if ($cache_directory !== null) { Config::removeCacheDirectory($cache_directory); } } if (isset($options['use-baseline']) && is_string($options['use-baseline'])) { $clientConfiguration->baseline = $options['use-baseline']; } if (isset($options['disable-on-change']) && is_numeric($options['disable-on-change'])) { $clientConfiguration->onchangeLineLimit = (int) $options['disable-on-change']; } if (isset($options['on-change-debounce-ms']) && is_numeric($options['on-change-debounce-ms'])) { $clientConfiguration->onChangeDebounceMs = (int) $options['on-change-debounce-ms']; } $clientConfiguration->provideDefinition = !isset($options['enable-provide-definition']) || !is_string($options['enable-provide-definition']) || strtolower($options['enable-provide-definition']) !== 'false'; $clientConfiguration->provideSignatureHelp = !isset($options['enable-provide-signature-help']) || !is_string($options['enable-provide-signature-help']) || strtolower($options['enable-provide-signature-help']) !== 'false'; $clientConfiguration->provideHover = !isset($options['enable-provide-hover']) || !is_string($options['enable-provide-hover']) || strtolower($options['enable-provide-hover']) !== 'false'; $clientConfiguration->provideDiagnostics = !isset($options['enable-provide-diagnostics']) || !is_string($options['enable-provide-diagnostics']) || strtolower($options['enable-provide-diagnostics']) !== 'false'; $clientConfiguration->provideCodeActions = !isset($options['enable-code-actions']) || !is_string($options['enable-code-actions']) || strtolower($options['enable-code-actions']) !== 'false'; $clientConfiguration->provideCompletion = !isset($options['enable-autocomplete']) || !is_string($options['enable-autocomplete']) || strtolower($options['enable-autocomplete']) !== 'false'; $clientConfiguration->hideWarnings = !(!isset($options['show-diagnostic-warnings']) || !is_string($options['show-diagnostic-warnings']) || strtolower($options['show-diagnostic-warnings']) !== 'false'); /** * if ($config->find_unused_variables) { * $project_analyzer->getCodebase()->reportUnusedVariables(); * } */ $find_unused_code = isset($options['find-dead-code']) ? 'auto' : null; if ($config->find_unused_code) { $find_unused_code = 'auto'; } if ($find_unused_code) { $clientConfiguration->findUnusedCode = $find_unused_code; } if (isset($options['verbose'])) { $clientConfiguration->logLevel = $options['verbose'] ? MessageType::LOG : MessageType::INFO; } else { $clientConfiguration->logLevel = MessageType::INFO; } $clientConfiguration->TCPServerAddress = $options['tcp'] ?? null; $clientConfiguration->TCPServerMode = isset($options['tcp-server']); LanguageServerLanguageServer::run($config, $clientConfiguration, $current_dir, $path_mapper, $inMemory); } /** @param array> $options */ private static function createPathMapper(array $options, string $server_start_dir) : PathMapper { if (!isset($options['map-folder'])) { // dummy no-op mapper return new PathMapper('/', '/'); } $map_folder = $options['map-folder']; if ($map_folder === \false) { // autoconfigured mapper return new PathMapper($server_start_dir, null); } if (is_string($map_folder)) { if (strpos($map_folder, ':') === \false) { fwrite(STDERR, 'invalid format for --map-folder option' . PHP_EOL); exit(1); } /** @psalm-suppress PossiblyUndefinedArrayOffset we just checked that we have the separator*/ [$server_dir, $client_dir] = explode(':', $map_folder, 2); if (!strlen($server_dir) || !strlen($client_dir)) { fwrite(STDERR, 'invalid format for --map-folder option, ' . 'neither SERVER_FOLDER nor CLIENT_FOLDER can be empty' . PHP_EOL); exit(1); } return new PathMapper($server_dir, $client_dir); } fwrite(STDERR, '--map-folder option can only be specified once' . PHP_EOL); exit(1); } } $arguments */ public function emit(string $eventName, array $arguments = [], ?callable $continueCallBack = null) : void; /** * Returns the list of listeners for an event. * * The list is returned as an array, and the list of events are sorted by * their priority. * * @return callable[] */ public function listeners(string $eventName) : array; /** * Removes a specific listener from an event. * * If the listener could not be found, this method will return false. If it * was removed it will return true. * * @psalm-suppress PossiblyUnusedReturnValue */ public function removeListener(string $eventName, callable $listener) : bool; } counter++; } } */ private array $cache = []; public function __construct() { } /** * @param lowercase-string $file_path */ protected function storeInCache(string $file_path, FileStorage $storage) : void { $this->cache[$file_path] = $storage; } public function removeCacheForFile(string $file_path) : void { unset($this->cache[strtolower($file_path)]); } /** * @param lowercase-string $file_path */ protected function loadFromCache(string $file_path) : ?FileStorage { return $this->cache[$file_path] ?? null; } } */ private array $file_contents_cache = []; /** * @var array */ private array $file_content_hash = []; /** * @var array> */ private array $statements_cache = []; /** * @var array */ private array $statements_cache_time = []; public function __construct() { } public function loadStatementsFromCache(string $file_path, int $file_modified_time, string $file_content_hash) : ?array { if (isset($this->statements_cache[$file_path]) && $this->statements_cache_time[$file_path] >= $file_modified_time && $this->file_content_hash[$file_path] === $file_content_hash) { return $this->statements_cache[$file_path]; } return null; } /** * @return list|null */ public function loadExistingStatementsFromCache(string $file_path) : ?array { if (isset($this->statements_cache[$file_path])) { return $this->statements_cache[$file_path]; } return null; } /** * @param list $stmts */ public function saveStatementsToCache(string $file_path, string $file_content_hash, array $stmts, bool $touch_only) : void { $this->statements_cache[$file_path] = $stmts; $this->statements_cache_time[$file_path] = microtime(\true); $this->file_content_hash[$file_path] = $file_content_hash; } public function loadExistingFileContentsFromCache(string $file_path) : ?string { if (isset($this->file_contents_cache[$file_path])) { return $this->file_contents_cache[$file_path]; } return null; } public function cacheFileContents(string $file_path, string $file_contents) : void { $this->file_contents_cache[$file_path] = $file_contents; } public function deleteOldParserCaches(float $time_before) : int { $this->existing_file_content_hashes = null; $this->new_file_content_hashes = []; $this->file_contents_cache = []; $this->file_content_hash = []; $this->statements_cache = []; $this->statements_cache_time = []; return 0; } public function saveFileContentHashes() : void { } } */ private array $cache = []; public function __construct() { } public function writeToCache(ClassLikeStorage $storage, ?string $file_path, ?string $file_contents) : void { $fq_classlike_name_lc = strtolower($storage->name); $this->cache[$fq_classlike_name_lc] = $storage; } /** * @param lowercase-string $fq_classlike_name_lc */ public function getLatestFromCache(string $fq_classlike_name_lc, ?string $file_path, ?string $file_contents) : ClassLikeStorage { $cached_value = $this->loadFromCache($fq_classlike_name_lc); if (!$cached_value) { throw new UnexpectedValueException('Should be in cache'); } return $cached_value; } /** * @param lowercase-string $fq_classlike_name_lc */ private function loadFromCache(string $fq_classlike_name_lc) : ?ClassLikeStorage { return $this->cache[$fq_classlike_name_lc] ?? null; } } > */ private array $cached_correct_methods = []; /** * @var array< * string, * array{ * 0: array, * 1: array, * 2: array * } * > */ private array $cached_file_maps = []; public function __construct(Config $config) { parent::__construct($config); } public function getCachedFileReferences() : ?array { return $this->cached_file_references; } public function getCachedClassLikeFiles() : ?array { return $this->cached_classlike_files; } public function getCachedMethodClassReferences() : ?array { return $this->cached_method_class_references; } public function getCachedNonMethodClassReferences() : ?array { return $this->cached_nonmethod_class_references; } public function getCachedFileMemberReferences() : ?array { return $this->cached_file_member_references; } public function getCachedFilePropertyReferences() : ?array { return $this->cached_file_property_references; } public function getCachedFileMethodReturnReferences() : ?array { return $this->cached_file_method_return_references; } public function getCachedMethodMemberReferences() : ?array { return $this->cached_method_member_references; } public function getCachedMethodDependencies() : ?array { return $this->cached_method_dependencies; } public function getCachedMethodPropertyReferences() : ?array { return $this->cached_method_property_references; } public function getCachedMethodMethodReturnReferences() : ?array { return $this->cached_method_method_return_references; } public function getCachedFileMissingMemberReferences() : ?array { return $this->cached_file_missing_member_references; } public function getCachedMixedMemberNameReferences() : ?array { return $this->cached_unknown_member_references; } public function getCachedMethodMissingMemberReferences() : ?array { return $this->cached_method_missing_member_references; } public function getCachedMethodParamUses() : ?array { return $this->cached_method_param_uses; } public function getCachedIssues() : ?array { return $this->cached_issues; } public function setCachedFileReferences(array $file_references) : void { $this->cached_file_references = $file_references; } public function setCachedClassLikeFiles(array $file_references) : void { $this->cached_classlike_files = $file_references; } public function setCachedMethodClassReferences(array $method_class_references) : void { $this->cached_method_class_references = $method_class_references; } public function setCachedNonMethodClassReferences(array $file_class_references) : void { $this->cached_nonmethod_class_references = $file_class_references; } public function setCachedMethodMemberReferences(array $member_references) : void { $this->cached_method_member_references = $member_references; } public function setCachedMethodDependencies(array $member_references) : void { $this->cached_method_dependencies = $member_references; } public function setCachedMethodPropertyReferences(array $property_references) : void { $this->cached_method_property_references = $property_references; } public function setCachedMethodMethodReturnReferences(array $method_return_references) : void { $this->cached_method_method_return_references = $method_return_references; } public function setCachedMethodMissingMemberReferences(array $member_references) : void { $this->cached_method_missing_member_references = $member_references; } public function setCachedFileMemberReferences(array $member_references) : void { $this->cached_file_member_references = $member_references; } public function setCachedFilePropertyReferences(array $property_references) : void { $this->cached_file_property_references = $property_references; } public function setCachedFileMethodReturnReferences(array $method_return_references) : void { $this->cached_file_method_return_references = $method_return_references; } public function setCachedFileMissingMemberReferences(array $member_references) : void { $this->cached_file_missing_member_references = $member_references; } public function setCachedMixedMemberNameReferences(array $references) : void { $this->cached_unknown_member_references = $references; } public function setCachedMethodParamUses(array $uses) : void { $this->cached_method_param_uses = $uses; } public function setCachedIssues(array $issues) : void { $this->cached_issues = $issues; } /** * @return array> */ public function getAnalyzedMethodCache() : array { return $this->cached_correct_methods; } /** * @param array> $analyzed_methods */ public function setAnalyzedMethodCache(array $analyzed_methods) : void { $this->cached_correct_methods = $analyzed_methods; } /** * @return array< * string, * array{ * 0: array, * 1: array, * 2: array * } * > */ public function getFileMapCache() : array { return $this->cached_file_maps; } /** * @param array< * string, * array{ * 0: array, * 1: array, * 2: array * } * > $file_maps */ public function setFileMapCache(array $file_maps) : void { $this->cached_file_maps = $file_maps; } /** * @param array $mixed_counts */ public function setTypeCoverage(array $mixed_counts) : void { } } last_run; } public function processSuccessfulRun(float $start_time, string $psalm_version) : void { $this->last_run = (int) $start_time; } public function canDiffFiles() : bool { return $this->last_run > 0; } public function hasLockfileChanged() : bool { return \false; } public function updateComposerLockHash() : void { } } */ protected array $listeners = []; /** * Subscribe to an event. */ public function on(string $eventName, callable $callBack, int $priority = 100) : void { if (!isset($this->listeners[$eventName])) { $this->listeners[$eventName] = [ \true, // If there's only one item, it's sorted [$priority], [$callBack], ]; } else { $this->listeners[$eventName][0] = \false; // marked as unsorted $this->listeners[$eventName][1][] = $priority; $this->listeners[$eventName][2][] = $callBack; } } /** * Emits an event. * * This method will return true if 0 or more listeners were successfully * handled. false is returned if one of the events broke the event chain. * * If the continueCallBack is specified, this callback will be called every * time before the next event handler is called. * * If the continueCallback returns false, event propagation stops. This * allows you to use the eventEmitter as a means for listeners to implement * functionality in your application, and break the event loop as soon as * some condition is fulfilled. * * Note that returning false from an event subscriber breaks propagation * and returns false, but if the continue-callback stops propagation, this * is still considered a 'successful' operation and returns true. * * Lastly, if there are 5 event handlers for an event. The continueCallback * will be called at most 4 times. * * @param list $arguments */ public function emit(string $eventName, array $arguments = [], ?callable $continueCallBack = null) : void { if ($continueCallBack === null) { foreach ($this->listeners($eventName) as $listener) { /** @psalm-suppress MixedAssignment */ $result = call_user_func_array($listener, $arguments); if ($result === \false) { return; } } } else { $listeners = $this->listeners($eventName); $counter = count($listeners); foreach ($listeners as $listener) { --$counter; /** @psalm-suppress MixedAssignment */ $result = call_user_func_array($listener, $arguments); if ($result === \false) { return; } if ($counter > 0) { if (!$continueCallBack()) { break; } } } } } /** * Returns the list of listeners for an event. * * The list is returned as an array, and the list of events are sorted by * their priority. * * @return callable[] */ public function listeners(string $eventName) : array { if (!isset($this->listeners[$eventName])) { return []; } // The list is not sorted if (!$this->listeners[$eventName][0]) { // Sorting array_multisort($this->listeners[$eventName][1], SORT_NUMERIC, $this->listeners[$eventName][2]); // Marking the listeners as sorted $this->listeners[$eventName][0] = \true; } return $this->listeners[$eventName][2]; } /** * Removes a specific listener from an event. * * If the listener could not be found, this method will return false. If it * was removed it will return true. */ public function removeListener(string $eventName, callable $listener) : bool { if (!isset($this->listeners[$eventName])) { return \false; } foreach ($this->listeners[$eventName][2] as $index => $check) { if ($check === $listener) { unset($this->listeners[$eventName][1][$index], $this->listeners[$eventName][2][$index]); return \true; } } return \false; } } code = $code; $this->title = $title; $this->description = $description; $markdown = ''; if ($title !== null) { $markdown = "**{$title}**\n\n"; } if ($description !== null) { $markdown = "{$markdown}{$description}\n\n"; } parent::__construct(MarkupKind::MARKDOWN, "{$markdown}```php\nserver_root = $this->sanitizeFolderPath($server_root); $this->client_root = $this->sanitizeFolderPath($client_root); } public function configureClientRoot(string $client_root) : void { // ignore if preconfigured if ($this->client_root === null) { $this->client_root = $this->sanitizeFolderPath($client_root); } } public function mapClientToServer(string $client_path) : string { if ($this->client_root === null) { return $client_path; } if (substr($client_path, 0, strlen($this->client_root)) === $this->client_root) { return $this->server_root . substr($client_path, strlen($this->client_root)); } return $client_path; } public function mapServerToClient(string $server_path) : string { if ($this->client_root === null) { return $server_path; } if (substr($server_path, 0, strlen($this->server_root)) === $this->server_root) { return $this->client_root . substr($server_path, strlen($this->server_root)); } return $server_path; } /** @return ($path is null ? null : string) */ private function sanitizeFolderPath(?string $path) : ?string { if ($path === null) { return $path; } return rtrim($path, '/'); } } file_path = $file_path; $this->symbol = $symbol; $this->range = $range; } } protocolReader = $protocolReader; $this->protocolWriter = $protocolWriter; $this->idGenerator = new \Psalm\Internal\LanguageServer\IdGenerator(); } /** * Sends a request to the client and returns a promise that is resolved with the result or rejected with the error * * @param string $method The method to call * @param array|object $params The method parameters * @return Promise Resolved with the result of the request or rejected with an error */ public function request(string $method, $params) : Promise { $id = $this->idGenerator->generate(); return call( /** * @return Generator> */ function () use($id, $method, $params) : Generator { (yield $this->protocolWriter->write(new \Psalm\Internal\LanguageServer\Message(new Request($id, $method, (object) $params)))); $deferred = new Deferred(); $listener = function (\Psalm\Internal\LanguageServer\Message $msg) use($id, $deferred, &$listener) : void { /** * @psalm-suppress UndefinedPropertyFetch * @psalm-suppress MixedArgument */ if ($msg->body && Response::isResponse($msg->body) && $msg->body->id === $id) { // Received a response $this->protocolReader->removeListener('message', $listener); if (SuccessResponse::isSuccessResponse($msg->body)) { $deferred->resolve($msg->body->result); } else { $deferred->fail($msg->body->error); } } }; $this->protocolReader->on('message', $listener); return $deferred->promise(); } ); } /** * Sends a notification to the client * * @param string $method The method to call * @param array|object $params The method parameters */ public function notify(string $method, $params) : void { $this->protocolWriter->write(new \Psalm\Internal\LanguageServer\Message(new Notification($method, (object) $params))); } } , ?string, void> */ function () use($input) : Generator { while ($this->is_accepting_new_requests) { $read_promise = $input->read(); $chunk = (yield $read_promise); if ($chunk === null) { break; } if ($this->readMessages($chunk) > 0) { $this->emit('readMessageGroup'); } } $this->emitClose(); } ); $this->on('close', static function () use($input) : void { $input->close(); }); } private function readMessages(string $buffer) : int { $emitted_messages = 0; $i = 0; while (($buffer[$i] ?? '') !== '') { $this->buffer .= $buffer[$i++]; switch ($this->parsing_mode) { case self::PARSE_HEADERS: if ($this->buffer === "\r\n") { $this->parsing_mode = self::PARSE_BODY; $this->content_length = (int) ($this->headers['Content-Length'] ?? 0); $this->buffer = ''; } elseif (substr($this->buffer, -2) === "\r\n") { $parts = explode(':', $this->buffer); if (isset($parts[1])) { $this->headers[$parts[0]] = trim($parts[1]); } $this->buffer = ''; } break; case self::PARSE_BODY: if (strlen($this->buffer) === $this->content_length) { if (!$this->is_accepting_new_requests) { // If we fork, don't read any bytes in the input buffer from the worker process. $this->emitClose(); return $emitted_messages; } // MessageBody::parse can throw an Error, maybe log an error? try { $msg = new \Psalm\Internal\LanguageServer\Message(MessageBody::parse($this->buffer), $this->headers); } catch (Exception $_) { $msg = null; } if ($msg) { ++$emitted_messages; $this->emit('message', [$msg]); /** * @psalm-suppress TypeDoesNotContainType */ if (!$this->is_accepting_new_requests) { // If we fork, don't read any bytes in the input buffer from the worker process. $this->emitClose(); return $emitted_messages; } } $this->parsing_mode = self::PARSE_HEADERS; $this->headers = []; $this->buffer = ''; } break; } } return $emitted_messages; } private function emitClose() : void { if ($this->did_emit_close) { return; } $this->did_emit_close = \true; $this->emit('close'); } } handler = new \Psalm\Internal\LanguageServer\ClientHandler($reader, $writer); $this->server = $server; $this->textDocument = new ClientTextDocument($this->handler, $this->server); $this->workspace = new ClientWorkspace($this->handler, new JsonMapper(), $this->server); $this->clientConfiguration = $clientConfiguration; } /** * Request Configuration from Client and save it */ public function refreshConfiguration() : void { $capabilities = $this->server->clientCapabilities; if ($capabilities->workspace->configuration ?? \false) { $this->workspace->requestConfiguration('psalm')->onResolve(function ($error, $value) : void { if ($error) { $this->server->logError('There was an error getting configuration'); } else { /** @var array $value */ [$config] = $value; $this->configurationRefreshed((array) $config); } }); } } /** * A notification to log the trace of the server’s execution. * The amount and content of these notifications depends on the current trace configuration. * * @psalm-suppress PossiblyUnusedMethod */ public function logTrace(LogTrace $logTrace) : void { //If trace is 'off', the server should not send any logTrace notification. if (is_null($this->server->trace) || $this->server->trace === 'off') { return; } //If trace is 'messages', the server should not add the 'verbose' field in the LogTraceParams. if ($this->server->trace === 'messages') { $logTrace->verbose = null; } $this->handler->notify('$/logTrace', $logTrace); } /** * Send a log message to the client. */ public function logMessage(LogMessage $logMessage) : void { $this->handler->notify('window/logMessage', $logMessage); } /** * The telemetry notification is sent from the * server to the client to ask the client to log * a telemetry event. * * The protocol doesn’t specify the payload since no * interpretation of the data happens in the protocol. * Most clients even don’t handle the event directly * but forward them to the extensions owing the corresponding * server issuing the event. */ public function event(LogMessage $logMessage) : void { $this->handler->notify('telemetry/event', $logMessage); } public function makeProgress(string $token) : ProgressInterface { if ($this->server->clientCapabilities->window->workDoneProgress ?? \false) { return new Progress($this->handler, $token); } else { return new LegacyProgress($this->handler); } } /** * Configuration Refreshed from Client */ private function configurationRefreshed(array $config) : void { //do things when the config is refreshed if (empty($config)) { return; } /** @var array */ $array = json_decode(json_encode($config), \true); if (isset($array['hideWarnings'])) { $this->clientConfiguration->hideWarnings = (bool) $array['hideWarnings']; } if (isset($array['provideCompletion'])) { $this->clientConfiguration->provideCompletion = (bool) $array['provideCompletion']; } if (isset($array['provideDefinition'])) { $this->clientConfiguration->provideDefinition = (bool) $array['provideDefinition']; } if (isset($array['provideHover'])) { $this->clientConfiguration->provideHover = (bool) $array['provideHover']; } if (isset($array['provideSignatureHelp'])) { $this->clientConfiguration->provideSignatureHelp = (bool) $array['provideSignatureHelp']; } if (isset($array['provideCodeActions'])) { $this->clientConfiguration->provideCodeActions = (bool) $array['provideCodeActions']; } if (isset($array['provideDiagnostics'])) { $this->clientConfiguration->provideDiagnostics = (bool) $array['provideDiagnostics']; } if (isset($array['findUnusedVariables'])) { $this->clientConfiguration->findUnusedVariables = (bool) $array['findUnusedVariables']; } } } hideWarnings = $hideWarnings; $this->provideCompletion = $provideCompletion; $this->provideDefinition = $provideDefinition; $this->provideHover = $provideHover; $this->provideSignatureHelp = $provideSignatureHelp; $this->provideCodeActions = $provideCodeActions; $this->provideDiagnostics = $provideDiagnostics; $this->findUnusedVariables = $findUnusedVariables; $this->findUnusedCode = $findUnusedCode; $this->logLevel = $logLevel; $this->onchangeLineLimit = $onchangeLineLimit; $this->baseline = $baseline; } } server = $server; } public function debug(string $message) : void { if ($this->server) { $this->server->logDebug(str_replace("\n", "", $message)); } } public function write(string $message) : void { if ($this->server) { $this->server->logInfo(str_replace("\n", "", $message)); } } } server = $server; $this->codebase = $codebase; $this->project_analyzer = $project_analyzer; } /** * The document open notification is sent from the client to the server to signal newly opened text documents. The * document’s content is now managed by the client and the server must not try to read the document’s content using * the document’s Uri. Open in this sense means it is managed by the client. It doesn’t necessarily mean that its * content is presented in an editor. An open notification must not be sent more than once without a corresponding * close notification send before. This means open and close notification must be balanced and the max open count * for a particular textDocument is one. Note that a server’s ability to fulfill requests is independent of whether * a text document is open or closed. * * @param TextDocumentItem $textDocument the document that was opened */ public function didOpen(TextDocumentItem $textDocument) : void { $this->server->logDebug('textDocument/didOpen', ['version' => $textDocument->version, 'uri' => $textDocument->uri]); $file_path = $this->server->uriToPath($textDocument->uri); $this->codebase->removeTemporaryFileChanges($file_path); $this->codebase->file_provider->openFile($file_path); $this->codebase->file_provider->setOpenContents($file_path, $textDocument->text); $this->server->queueOpenFileAnalysis($file_path, $textDocument->uri, $textDocument->version); } /** * The document save notification is sent from the client to the server when the document was saved in the client * * @param TextDocumentIdentifier $textDocument the document that was opened * @param string|null $text Optional the content when saved. Depends on the includeText value * when the save notification was requested. */ public function didSave(TextDocumentIdentifier $textDocument, ?string $text = null) : void { $this->server->logDebug('textDocument/didSave', ['uri' => (array) $textDocument]); $file_path = $this->server->uriToPath($textDocument->uri); // reopen file $this->codebase->removeTemporaryFileChanges($file_path); $this->codebase->file_provider->setOpenContents($file_path, $text); $this->server->queueSaveFileAnalysis($file_path, $textDocument->uri); } /** * The document change notification is sent from the client to the server to signal changes to a text document. * * @param VersionedTextDocumentIdentifier $textDocument the document that was changed * @param TextDocumentContentChangeEvent[] $contentChanges */ public function didChange(VersionedTextDocumentIdentifier $textDocument, array $contentChanges) : void { $this->server->logDebug('textDocument/didChange', ['version' => $textDocument->version, 'uri' => $textDocument->uri]); $file_path = $this->server->uriToPath($textDocument->uri); if (count($contentChanges) === 1 && isset($contentChanges[0]) && $contentChanges[0]->range === null) { $new_content = $contentChanges[0]->text; } else { throw new UnexpectedValueException('Not expecting partial diff'); } if ($this->project_analyzer->onchange_line_limit !== null) { if (substr_count($new_content, "\n") > $this->project_analyzer->onchange_line_limit) { return; } } $this->codebase->addTemporaryFileChanges($file_path, $new_content, $textDocument->version); $this->server->queueChangeFileAnalysis($file_path, $textDocument->uri, $textDocument->version); } /** * The document close notification is sent from the client to the server when the document got closed in the client. * The document’s master now exists where the document’s Uri points to (e.g. if the document’s Uri is a file Uri the * master now exists on disk). As with the open notification the close notification is about managing the document’s * content. Receiving a close notification doesn’t mean that the document was open in an editor before. A close * notification requires a previous open notification to be sent. Note that a server’s ability to fulfill requests * is independent of whether a text document is open or closed. * * @param TextDocumentIdentifier $textDocument The document that was closed */ public function didClose(TextDocumentIdentifier $textDocument) : void { $this->server->logDebug('textDocument/didClose', ['uri' => $textDocument->uri]); $file_path = $this->server->uriToPath($textDocument->uri); $this->codebase->file_provider->closeFile($file_path); $this->server->client->textDocument->publishDiagnostics($textDocument->uri, []); } /** * The goto definition request is sent from the client to the server to resolve the definition location of a symbol * at a given text document position. * * @param TextDocumentIdentifier $textDocument The text document * @param Position $position The position inside the text document * @psalm-return Promise|Promise */ public function definition(TextDocumentIdentifier $textDocument, Position $position) : Promise { if (!$this->server->client->clientConfiguration->provideDefinition) { return new Success(null); } $this->server->logDebug('textDocument/definition'); $file_path = $this->server->uriToPath($textDocument->uri); //This currently doesnt work right with out of project files if (!$this->codebase->config->isInProjectDirs($file_path)) { return new Success(null); } try { $reference = $this->codebase->getReferenceAtPositionAsReference($file_path, $position); } catch (UnanalyzedFileException $e) { $this->server->logThrowable($e); return new Success(null); } if ($reference === null) { return new Success(null); } $code_location = $this->codebase->getSymbolLocationByReference($reference); if (!$code_location) { return new Success(null); } return new Success(new Location($this->server->pathToUri($code_location->file_path), new Range(new Position($code_location->getLineNumber() - 1, $code_location->getColumn() - 1), new Position($code_location->getEndLineNumber() - 1, $code_location->getEndColumn() - 1)))); } /** * The hover request is sent from the client to the server to request * hover information at a given text document position. * * @param TextDocumentIdentifier $textDocument The text document * @param Position $position The position inside the text document * @psalm-return Promise|Promise */ public function hover(TextDocumentIdentifier $textDocument, Position $position) : Promise { if (!$this->server->client->clientConfiguration->provideHover) { return new Success(null); } $this->server->logDebug('textDocument/hover'); $file_path = $this->server->uriToPath($textDocument->uri); //This currently doesnt work right with out of project files if (!$this->codebase->config->isInProjectDirs($file_path)) { return new Success(null); } try { $reference = $this->codebase->getReferenceAtPositionAsReference($file_path, $position); } catch (UnanalyzedFileException $e) { $this->server->logThrowable($e); return new Success(null); } if ($reference === null) { return new Success(null); } try { $markup = $this->codebase->getMarkupContentForSymbolByReference($reference); } catch (UnexpectedValueException $e) { $this->server->logThrowable($e); return new Success(null); } if ($markup === null) { return new Success(null); } return new Success(new Hover($markup, $reference->range)); } /** * The Completion request is sent from the client to the server to compute completion items at a given cursor * position. Completion items are presented in the IntelliSense user interface. If computing full completion items * is expensive, servers can additionally provide a handler for the completion item resolve request * ('completionItem/resolve'). This request is sent when a completion item is selected in the user interface. A * typically use case is for example: the 'textDocument/completion' request doesn't fill in the documentation * property for returned completion items since it is expensive to compute. When the item is selected in the user * interface then a 'completionItem/resolve' request is sent with the selected completion item as a param. The * returned completion item should have the documentation property filled in. * * @param TextDocumentIdentifier $textDocument The text document * @param Position $position The position * @psalm-return Promise>|Promise|Promise */ public function completion(TextDocumentIdentifier $textDocument, Position $position) : Promise { if (!$this->server->client->clientConfiguration->provideCompletion) { return new Success(null); } $this->server->logDebug('textDocument/completion'); $file_path = $this->server->uriToPath($textDocument->uri); //This currently doesnt work right with out of project files if (!$this->codebase->config->isInProjectDirs($file_path)) { return new Success(null); } try { $completion_data = $this->codebase->getCompletionDataAtPosition($file_path, $position); if ($completion_data) { [$recent_type, $gap, $offset] = $completion_data; if ($gap === '->' || $gap === '::') { $snippetSupport = $this->server->clientCapabilities->textDocument->completion->completionItem->snippetSupport ?? \false; $completion_items = $this->codebase->getCompletionItemsForClassishThing($recent_type, $gap, $snippetSupport); } elseif ($gap === '[') { $completion_items = $this->codebase->getCompletionItemsForArrayKeys($recent_type); } else { $completion_items = $this->codebase->getCompletionItemsForPartialSymbol($recent_type, $offset, $file_path); } return new Success(new CompletionList($completion_items, \false)); } } catch (UnanalyzedFileException $e) { $this->server->logThrowable($e); return new Success(null); } catch (TypeParseTreeException $e) { $this->server->logThrowable($e); return new Success(null); } try { $type_context = $this->codebase->getTypeContextAtPosition($file_path, $position); if ($type_context) { $completion_items = $this->codebase->getCompletionItemsForType($type_context); return new Success(new CompletionList($completion_items, \false)); } } catch (UnexpectedValueException $e) { $this->server->logThrowable($e); return new Success(null); } catch (TypeParseTreeException $e) { $this->server->logThrowable($e); return new Success(null); } $this->server->logError('completion not found at ' . $position->line . ':' . $position->character); return new Success(null); } /** * The signature help request is sent from the client to the server to request signature * information at a given cursor position. */ public function signatureHelp(TextDocumentIdentifier $textDocument, Position $position) : Promise { if (!$this->server->client->clientConfiguration->provideSignatureHelp) { return new Success(null); } $this->server->logDebug('textDocument/signatureHelp'); $file_path = $this->server->uriToPath($textDocument->uri); //This currently doesnt work right with out of project files if (!$this->codebase->config->isInProjectDirs($file_path)) { return new Success(null); } try { $argument_location = $this->codebase->getFunctionArgumentAtPosition($file_path, $position); } catch (UnanalyzedFileException $e) { $this->server->logThrowable($e); return new Success(null); } if ($argument_location === null) { return new Success(null); } try { $signature_information = $this->codebase->getSignatureInformation($argument_location[0], $file_path); } catch (UnexpectedValueException $e) { $this->server->logThrowable($e); return new Success(null); } if (!$signature_information) { return new Success(null); } return new Success(new SignatureHelp([$signature_information], 0, $argument_location[1])); } /** * The code action request is sent from the client to the server to compute commands * for a given text document and range. These commands are typically code fixes to * either fix problems or to beautify/refactor code. */ public function codeAction(TextDocumentIdentifier $textDocument, CodeActionContext $context) : Promise { if (!$this->server->client->clientConfiguration->provideCodeActions) { return new Success(null); } $this->server->logDebug('textDocument/codeAction'); $file_path = $this->server->uriToPath($textDocument->uri); //Don't report code actions for files we arent watching if (!$this->codebase->config->isInProjectDirs($file_path)) { return new Success(null); } $fixers = []; foreach ($context->diagnostics as $diagnostic) { if ($diagnostic->source !== 'psalm') { continue; } /** @var array{type: string, snippet: string, line_from: int, line_to: int} */ $data = (array) $diagnostic->data; //$file_path = $this->server->uriToPath($textDocument->uri); //$contents = $this->codebase->file_provider->getContents($file_path); $snippetRange = new Range(new Position($data['line_from'] - 1, 0), new Position($data['line_to'], 0)); $indentation = ''; if (preg_match('/^(\\s*)/', $data['snippet'], $matches)) { $indentation = $matches[1] ?? ''; } //Suppress Ability $fixers["suppress.{$data['type']}"] = new CodeAction("Suppress {$data['type']} for this line", CodeActionKind::QUICK_FIX, null, null, null, new WorkspaceEdit([$textDocument->uri => [new TextEdit($snippetRange, "{$indentation}/** @psalm-suppress {$data['type']} */\n" . "{$data['snippet']}\n")]])); } if (empty($fixers)) { return new Success(null); } return new Success(array_values($fixers)); } } server = $server; $this->codebase = $codebase; $this->project_analyzer = $project_analyzer; } /** * The watched files notification is sent from the client to the server when the client * detects changes to files and folders watched by the language client (note although * the name suggest that only file events are sent it is about file system events * which include folders as well). It is recommended that servers register for these * file system events using the registration mechanism. In former implementations clients * pushed file events without the server actively asking for it. * * @param FileEvent[] $changes * @psalm-suppress PossiblyUnusedMethod */ public function didChangeWatchedFiles(array $changes) : void { $this->server->logDebug('workspace/didChangeWatchedFiles'); $realFiles = array_filter(array_map(function (FileEvent $change) { try { return $this->server->uriToPath($change->uri); } catch (InvalidArgumentException $e) { return null; } }, $changes)); $composerLockFile = realpath(Composer::getLockFilePath($this->codebase->config->base_dir)); if (in_array($composerLockFile, $realFiles)) { $this->server->logInfo('Composer.lock file changed. Reloading codebase'); FileReferenceProvider::clearCache(); $this->server->queueFileAnalysisWithOpenedFiles(); return; } foreach ($changes as $change) { $file_path = $this->server->uriToPath($change->uri); if ($composerLockFile === $file_path) { continue; } if ($change->type === FileChangeType::DELETED) { $this->codebase->invalidateInformationForFile($file_path); continue; } if (!$this->codebase->config->isInProjectDirs($file_path)) { continue; } if ($this->project_analyzer->onchange_line_limit === 0) { continue; } //If the file is currently open then dont analize it because its tracked in didChange if (!$this->codebase->file_provider->isOpen($file_path)) { $this->server->queueClosedFileAnalysis($file_path, $change->uri); } } } /** * A notification sent from the client to the server to signal the change of configuration settings. * * @psalm-suppress PossiblyUnusedMethod */ public function didChangeConfiguration() : void { $this->server->logDebug('workspace/didChangeConfiguration'); $this->server->client->refreshConfiguration(); } /** * The workspace/executeCommand request is sent from the client to the server to * trigger command execution on the server. * * @param mixed $arguments * @psalm-suppress PossiblyUnusedMethod */ public function executeCommand(string $command, $arguments) : Promise { $this->server->logDebug('workspace/executeCommand', ['command' => $command, 'arguments' => $arguments]); switch ($command) { case 'psalm.analyze.uri': /** @var array{uri: string} */ $arguments = (array) $arguments; $file = $this->server->uriToPath($arguments['uri']); $this->codebase->reloadFiles($this->project_analyzer, [$file], \true); $this->codebase->analyzer->addFilesToAnalyze([$file => $file]); $this->codebase->analyzer->analyzeFiles($this->project_analyzer, 1, \false); $this->server->emitVersionedIssues([$file => $arguments['uri']]); break; } return new Success(null); } } output = new ResourceOutputStream($output); } /** * {@inheritdoc} */ public function write(\Psalm\Internal\LanguageServer\Message $msg) : Promise { return $this->output->write((string) $msg); } } }>> */ protected array $issue_baseline = []; /** * This should actually be a private property on `parent` * * @psalm-suppress UnusedProperty */ protected JsonMapper $mapper; protected \Psalm\Internal\LanguageServer\PathMapper $path_mapper; public function __construct(\Psalm\Internal\LanguageServer\ProtocolReader $reader, \Psalm\Internal\LanguageServer\ProtocolWriter $writer, ProjectAnalyzer $project_analyzer, Codebase $codebase, \Psalm\Internal\LanguageServer\ClientConfiguration $clientConfiguration, \Psalm\Internal\LanguageServer\Progress $progress, \Psalm\Internal\LanguageServer\PathMapper $path_mapper) { parent::__construct($this, '/'); $progress->setServer($this); $this->project_analyzer = $project_analyzer; $this->codebase = $codebase; $this->path_mapper = $path_mapper; $this->protocolWriter = $writer; $this->protocolReader = $reader; $this->protocolReader->on('close', function () : void { $this->shutdown(); $this->exit(); }); $this->protocolReader->on('message', asyncCoroutine( /** * @return Generator */ function (\Psalm\Internal\LanguageServer\Message $msg) : Generator { if (!$msg->body) { return; } // Ignore responses, this is the handler for requests and notifications if (Response::isResponse($msg->body)) { return; } $result = null; $error = null; try { // Invoke the method handler to get a result /** * @var Promise|null */ $dispatched = $this->dispatch($msg->body); if ($dispatched !== null) { $result = (yield $dispatched); } else { $result = null; } } catch (Error $e) { // If a ResponseError is thrown, send it back in the Response $error = $e; } catch (Throwable $e) { // If an unexpected error occurred, send back an INTERNAL_ERROR error response $error = new Error((string) $e, ErrorCode::INTERNAL_ERROR, null, $e); } if ($error !== null) { $this->logError($error->message); } // Only send a Response for a Request // Notifications do not send Responses /** * @psalm-suppress UndefinedPropertyFetch * @psalm-suppress MixedArgument */ if (Request::isRequest($msg->body)) { if ($error !== null) { $responseBody = new ErrorResponse($msg->body->id, $error); } else { $responseBody = new SuccessResponse($msg->body->id, $result); } (yield $this->protocolWriter->write(new \Psalm\Internal\LanguageServer\Message($responseBody))); } } )); $this->protocolReader->on('readMessageGroup', static function () : void { //$this->verboseLog('Received message group'); //$this->doAnalysis(); }); $this->client = new \Psalm\Internal\LanguageServer\LanguageClient($reader, $writer, $this, $clientConfiguration); $this->logInfo("Psalm Language Server " . \PSALM_VERSION . " has started."); } /** * Start the Server */ public static function run(Config $config, \Psalm\Internal\LanguageServer\ClientConfiguration $clientConfiguration, string $base_dir, \Psalm\Internal\LanguageServer\PathMapper $path_mapper, bool $inMemory = \false) : void { $progress = new \Psalm\Internal\LanguageServer\Progress(); if ($inMemory) { $providers = new Providers(new FileProvider(), new InMemoryParserCacheProvider(), new InMemoryFileStorageCacheProvider(), new InMemoryClassLikeStorageCacheProvider(), new InMemoryFileReferenceCacheProvider($config), new InMemoryProjectCacheProvider()); } else { $providers = new Providers(new FileProvider(), new ParserCacheProvider($config), new FileStorageCacheProvider($config), new ClassLikeStorageCacheProvider($config), new FileReferenceCacheProvider($config), new ProjectCacheProvider(Composer::getLockFilePath($base_dir))); } $codebase = new Codebase($config, $providers, $progress); if ($config->find_unused_variables) { $codebase->reportUnusedVariables(); } if ($clientConfiguration->findUnusedCode) { $codebase->reportUnusedCode($clientConfiguration->findUnusedCode); } $project_analyzer = new ProjectAnalyzer($config, $providers, null, [], 1, $progress, $codebase); if ($clientConfiguration->onchangeLineLimit) { $project_analyzer->onchange_line_limit = $clientConfiguration->onchangeLineLimit; } //Setup Project Analyzer $project_analyzer->provide_completion = (bool) $clientConfiguration->provideCompletion; @cli_set_process_title('Psalm ' . \PSALM_VERSION . ' - PHP Language Server'); if (!$clientConfiguration->TCPServerMode && $clientConfiguration->TCPServerAddress) { // Connect to a TCP server $socket = stream_socket_client('tcp://' . $clientConfiguration->TCPServerAddress, $errno, $errstr); if ($socket === \false) { fwrite(STDERR, "Could not connect to language client. Error {$errno}\n{$errstr}"); exit(1); } stream_set_blocking($socket, \false); new self(new \Psalm\Internal\LanguageServer\ProtocolStreamReader($socket), new \Psalm\Internal\LanguageServer\ProtocolStreamWriter($socket), $project_analyzer, $codebase, $clientConfiguration, $progress, $path_mapper); Loop::run(); } elseif ($clientConfiguration->TCPServerMode && $clientConfiguration->TCPServerAddress) { // Run a TCP Server $tcpServer = stream_socket_server('tcp://' . $clientConfiguration->TCPServerAddress, $errno, $errstr); if ($tcpServer === \false) { fwrite(STDERR, "Could not listen on {$clientConfiguration->TCPServerAddress}. Error {$errno}\n{$errstr}"); exit(1); } fwrite(STDOUT, "Server listening on {$clientConfiguration->TCPServerAddress}\n"); while ($socket = stream_socket_accept($tcpServer, -1)) { fwrite(STDOUT, "Connection accepted\n"); stream_set_blocking($socket, \false); //we only accept one connection. //An exit notification will terminate the server new \Psalm\Internal\LanguageServer\LanguageServer(new \Psalm\Internal\LanguageServer\ProtocolStreamReader($socket), new \Psalm\Internal\LanguageServer\ProtocolStreamWriter($socket), $project_analyzer, $codebase, $clientConfiguration, $progress, $path_mapper); Loop::run(); } } else { // Use STDIO stream_set_blocking(STDIN, \false); new \Psalm\Internal\LanguageServer\LanguageServer(new \Psalm\Internal\LanguageServer\ProtocolStreamReader(STDIN), new \Psalm\Internal\LanguageServer\ProtocolStreamWriter(STDOUT), $project_analyzer, $codebase, $clientConfiguration, $progress, $path_mapper); Loop::run(); } } /** * The initialize request is sent as the first request from the client to the server. * * @param ClientCapabilities $capabilities The capabilities provided by the client (editor) * Is null if the process has not been started by another process. If the parent process is * not alive then the server should exit (see exit notification) its process. * @param ClientInfo|null $clientInfo Information about the client * @param string|null $trace The initial trace setting. If omitted trace is disabled ('off'). * @param string|null $workDoneToken The token to be used to report progress during init. * @psalm-return Promise */ public function initialize(ClientCapabilities $capabilities, ?ClientInfo $clientInfo = null, ?string $rootUri = null, ?string $trace = null, ?string $workDoneToken = null) : Promise { $this->clientInfo = $clientInfo; $this->clientCapabilities = $capabilities; $this->trace = $trace; if ($rootUri !== null) { $this->path_mapper->configureClientRoot($this->getPathPart($rootUri)); } return call( /** @return Generator */ function () use($workDoneToken) { $progress = $this->client->makeProgress($workDoneToken ?? uniqid('tkn', \true)); $this->logInfo("Initializing..."); $progress->begin('Psalm', 'initializing'); // Eventually, this might block on something. Leave it as a generator. /** @psalm-suppress TypeDoesNotContainType */ if (\false) { (yield \true); } $this->project_analyzer->serverMode($this); $this->logInfo("Initializing: Getting code base..."); $progress->update('getting code base'); $this->logInfo("Initializing: Scanning files ({$this->project_analyzer->threads} Threads)..."); $progress->update('scanning files'); $this->codebase->scanFiles($this->project_analyzer->threads); $this->logInfo("Initializing: Registering stub files..."); $progress->update('registering stub files'); $this->codebase->config->visitStubFiles($this->codebase, $this->project_analyzer->progress); if ($this->textDocument === null) { $this->textDocument = new ServerTextDocument($this, $this->codebase, $this->project_analyzer); } if ($this->workspace === null) { $this->workspace = new ServerWorkspace($this, $this->codebase, $this->project_analyzer); } $serverCapabilities = new ServerCapabilities(); $textDocumentSyncOptions = new TextDocumentSyncOptions(); //Open and close notifications are sent to the server. $textDocumentSyncOptions->openClose = \true; $saveOptions = new SaveOptions(); //The client is supposed to include the content on save. $saveOptions->includeText = \true; $textDocumentSyncOptions->save = $saveOptions; /** * Change notifications are sent to the server. See * TextDocumentSyncKind.None, TextDocumentSyncKind.Full and * TextDocumentSyncKind.Incremental. If omitted it defaults to * TextDocumentSyncKind.None. */ if ($this->project_analyzer->onchange_line_limit === 0) { /** * Documents should not be synced at all. */ $textDocumentSyncOptions->change = TextDocumentSyncKind::NONE; } else { /** * Documents are synced by always sending the full content * of the document. */ $textDocumentSyncOptions->change = TextDocumentSyncKind::FULL; } /** * Defines how text documents are synced. Is either a detailed structure * defining each notification or for backwards compatibility the * TextDocumentSyncKind number. If omitted it defaults to * `TextDocumentSyncKind.None`. */ $serverCapabilities->textDocumentSync = $textDocumentSyncOptions; /** * The server provides document symbol support. * Support "Find all symbols" */ $serverCapabilities->documentSymbolProvider = \false; /** * The server provides workspace symbol support. * Support "Find all symbols in workspace" */ $serverCapabilities->workspaceSymbolProvider = \false; /** * The server provides goto definition support. * Support "Go to definition" */ $serverCapabilities->definitionProvider = \true; /** * The server provides find references support. * Support "Find all references" */ $serverCapabilities->referencesProvider = \false; /** * The server provides hover support. * Support "Hover" */ $serverCapabilities->hoverProvider = \true; /** * The server does not support documentHighlight-ing * Ref: https://github.com/vimeo/psalm/issues/10397 */ $serverCapabilities->documentHighlightProvider = \false; /** * The server provides completion support. * Support "Completion" */ if ($this->project_analyzer->provide_completion) { $serverCapabilities->completionProvider = new CompletionOptions(); /** * The server provides support to resolve additional * information for a completion item. */ $serverCapabilities->completionProvider->resolveProvider = \false; /** * Most tools trigger completion request automatically without explicitly * requesting it using a keyboard shortcut (e.g. Ctrl+Space). Typically they * do so when the user starts to type an identifier. For example if the user * types `c` in a JavaScript file code complete will automatically pop up * present `console` besides others as a completion item. Characters that * make up identifiers don't need to be listed here. * * If code complete should automatically be trigger on characters not being * valid inside an identifier (for example `.` in JavaScript) list them in * `triggerCharacters`. */ $serverCapabilities->completionProvider->triggerCharacters = ['$', '>', ':', "[", "(", ",", " "]; } /** * Whether code action supports the `data` property which is * preserved between a `textDocument/codeAction` and a * `codeAction/resolve` request. * * Support "Code Actions" if we support data * * @since LSP 3.16.0 */ if ($this->clientCapabilities->textDocument->publishDiagnostics->dataSupport ?? \false) { $serverCapabilities->codeActionProvider = \true; } /** * The server provides signature help support. */ $serverCapabilities->signatureHelpProvider = new SignatureHelpOptions(['(', ',']); if ($this->client->clientConfiguration->baseline !== null) { $this->logInfo('Utilizing Baseline: ' . $this->client->clientConfiguration->baseline); $this->issue_baseline = ErrorBaseline::read(new FileProvider(), $this->client->clientConfiguration->baseline); } $this->logInfo("Initializing: Complete."); $progress->end('initialized'); /** * Information about the server. * * @since LSP 3.15.0 */ $initializeResultServerInfo = new InitializeResultServerInfo('Psalm Language Server', \PSALM_VERSION); return new InitializeResult($serverCapabilities, $initializeResultServerInfo); } ); } /** * The initialized notification is sent from the client to the server after the client received the result of the * initialize request but before the client is sending any other request or notification to the server. * The server can use the initialized notification for example to dynamically register capabilities. * The initialized notification may only be sent once. */ public function initialized() : void { try { $this->client->refreshConfiguration(); } catch (Throwable $e) { $this->logError((string) $e); } $this->clientStatus('running'); } /** * Queue Change File Analysis */ public function queueChangeFileAnalysis(string $file_path, string $uri, ?int $version = null) : void { $this->doVersionedAnalysisDebounce([$file_path => $uri], $version); } /** * Queue Open File Analysis */ public function queueOpenFileAnalysis(string $file_path, string $uri, ?int $version = null) : void { $this->doVersionedAnalysis([$file_path => $uri], $version); } /** * Queue Closed File Analysis */ public function queueClosedFileAnalysis(string $file_path, string $uri) : void { $this->doVersionedAnalysis([$file_path => $uri]); } /** * Queue Saved File Analysis */ public function queueSaveFileAnalysis(string $file_path, string $uri) : void { $this->queueFileAnalysisWithOpenedFiles([$file_path => $uri]); } /** * Queue File Analysis appending any opened files * * This allows for reanalysis of files that have been opened * * @param array $files */ public function queueFileAnalysisWithOpenedFiles(array $files = []) : void { /** @var array $opened */ $opened = array_reduce($this->project_analyzer->getCodebase()->file_provider->getOpenFilesPath(), function (array $opened, string $file_path) { $opened[$file_path] = $this->pathToUri($file_path); return $opened; }, $files); $this->doVersionedAnalysis($opened); } /** * Debounced Queue File Analysis with optional version * * @param array $files */ public function doVersionedAnalysisDebounce(array $files, ?int $version = null) : void { Loop::cancel($this->versionedAnalysisDelayToken); if ($this->client->clientConfiguration->onChangeDebounceMs === null) { $this->doVersionedAnalysis($files, $version); } else { /** @psalm-suppress MixedAssignment,UnusedPsalmSuppress */ $this->versionedAnalysisDelayToken = Loop::delay($this->client->clientConfiguration->onChangeDebounceMs, fn() => $this->doVersionedAnalysis($files, $version)); } } /** * Queue File Analysis with optional version * * @param array $files */ public function doVersionedAnalysis(array $files, ?int $version = null) : void { Loop::cancel($this->versionedAnalysisDelayToken); try { $this->logDebug("Doing Analysis from version: {$version}"); $this->codebase->reloadFiles($this->project_analyzer, array_keys($files)); $this->codebase->analyzer->addFilesToAnalyze(array_combine(array_keys($files), array_keys($files))); $this->logDebug("Reloading Files"); $this->codebase->analyzer->analyzeFiles($this->project_analyzer, 1, \false); $this->emitVersionedIssues($files, $version); } catch (Throwable $e) { $this->logError((string) $e); } } /** * Emit Publish Diagnostics * * @param array $files */ public function emitVersionedIssues(array $files, ?int $version = null) : void { $this->logDebug("Perform Analysis", ['files' => array_keys($files), 'version' => $version]); //Copy variable here to be able to process it $issue_baseline = $this->issue_baseline; $data = IssueBuffer::clear(); foreach ($files as $file_path => $uri) { //Dont report errors in files we are not watching if (!$this->project_analyzer->getCodebase()->config->isInProjectDirs($file_path)) { continue; } $diagnostics = array_map(function (IssueData $issue_data) : Diagnostic { //$check_name = $issue->check_name; $description = '[' . $issue_data->type . '] ' . $issue_data->message; $severity = $issue_data->severity; $start_line = max($issue_data->line_from, 1); $end_line = $issue_data->line_to; $start_column = $issue_data->column_from; $end_column = $issue_data->column_to; // Language server has 0 based lines and columns, phan has 1-based lines and columns. $range = new Range(new Position($start_line - 1, $start_column - 1), new Position($end_line - 1, $end_column - 1)); switch ($severity) { case IssueData::SEVERITY_INFO: $diagnostic_severity = DiagnosticSeverity::WARNING; break; default: $diagnostic_severity = DiagnosticSeverity::ERROR; break; } $diagnostic = new Diagnostic($description, $range, null, $diagnostic_severity, 'psalm'); $diagnostic->data = ['type' => $issue_data->type, 'snippet' => $issue_data->snippet, 'line_from' => $issue_data->line_from, 'line_to' => $issue_data->line_to]; $diagnostic->code = $issue_data->shortcode; /** * Client supports a codeDescription property * * @since LSP 3.16.0 */ if ($this->clientCapabilities->textDocument->publishDiagnostics->codeDescriptionSupport ?? \false) { $diagnostic->codeDescription = new CodeDescription($issue_data->link); } return $diagnostic; }, array_filter(array_map(static function (IssueData $issue_data) use(&$issue_baseline) { if (empty($issue_baseline)) { return $issue_data; } //Process Baseline $file = $issue_data->file_name; $type = $issue_data->type; if (isset($issue_baseline[$file][$type]) && $issue_baseline[$file][$type]['o'] > 0) { if ($issue_baseline[$file][$type]['o'] === count($issue_baseline[$file][$type]['s'])) { $position = array_search(str_replace("\r\n", "\n", trim($issue_data->selected_text)), $issue_baseline[$file][$type]['s'], \true); if ($position !== \false) { $issue_data->severity = IssueData::SEVERITY_INFO; array_splice($issue_baseline[$file][$type]['s'], $position, 1); $issue_baseline[$file][$type]['o']--; } } else { $issue_baseline[$file][$type]['s'] = []; $issue_data->severity = IssueData::SEVERITY_INFO; $issue_baseline[$file][$type]['o']--; } } return $issue_data; }, $data[$file_path] ?? []), function (IssueData $issue_data) { //Hide Warnings if ($issue_data->severity === IssueData::SEVERITY_INFO && $this->client->clientConfiguration->hideWarnings) { return \false; } return \true; })); $this->client->textDocument->publishDiagnostics($uri, array_values($diagnostics), $version); } } /** * The shutdown request is sent from the client to the server. It asks the server to shut down, but to not exit * (otherwise the response might not be delivered correctly to the client). There is a separate exit notification * that asks the server to exit. Clients must not send any notifications other than exit or requests to a server to * which they have sent a shutdown request. Clients should also wait with sending the exit notification until they * have received a response from the shutdown request. */ public function shutdown() : Promise { $this->clientStatus('closing'); $this->logInfo("Shutting down..."); $codebase = $this->project_analyzer->getCodebase(); $scanned_files = $codebase->scanner->getScannedFiles(); $codebase->file_reference_provider->updateReferenceCache($codebase, $scanned_files); $this->clientStatus('closed'); return new Success(null); } /** * A notification to ask the server to exit its process. * The server should exit with success code 0 if the shutdown request has been received before; * otherwise with error code 1. */ public function exit() : void { exit(0); } /** * Send log message to the client * * @psalm-param 1|2|3|4 $type * @param int $type The log type: * - 1 = Error * - 2 = Warning * - 3 = Info * - 4 = Log * @see MessageType * @param string $message The log message to send to the client. * @param mixed[] $context The log context */ public function log(int $type, string $message, array $context = []) : void { $logLevel = $this->client->clientConfiguration->logLevel; if ($logLevel === null) { return; } if ($type > $logLevel) { return; } if (!empty($context)) { $message .= "\n" . json_encode($context, JSON_PRETTY_PRINT); } try { $this->client->logMessage(new LogMessage($type, $message)); } catch (Throwable $err) { // do nothing as we could potentially go into a loop here is not careful //TODO: Investigate if we can use error_log instead } } /** * Log Throwable Error */ public function logThrowable(Throwable $throwable) : void { $this->log(MessageType::ERROR, (string) $throwable); } /** * Log Error message to the client */ public function logError(string $message, array $context = []) : void { $this->log(MessageType::ERROR, $message, $context); } /** * Log Warning message to the client */ public function logWarning(string $message, array $context = []) : void { $this->log(MessageType::WARNING, $message, $context); } /** * Log Info message to the client */ public function logInfo(string $message, array $context = []) : void { $this->log(MessageType::INFO, $message, $context); } /** * Log Debug message to the client */ public function logDebug(string $message, array $context = []) : void { $this->log(MessageType::LOG, $message, $context); } /** * Send status message to client. This is the same as sending a log message, * except this is meant for parsing by the client to present status updates in a UI. * * @param string $status The log message to send to the client. Should not contain colons `:`. * @param string|null $additional_info This is additional info that the client * can use as part of the display message. */ private function clientStatus(string $status, ?string $additional_info = null) : void { try { $this->client->event(new LogMessage(MessageType::INFO, $status . (!empty($additional_info) ? ': ' . $additional_info : ''))); } catch (Throwable $err) { // do nothing } } /** * Transforms an absolute file path into a URI as used by the language server protocol. */ public function pathToUri(string $filepath) : string { $filepath = str_replace('\\', '/', $filepath); $filepath = $this->path_mapper->mapServerToClient($oldpath = $filepath); $this->logDebug('Translated path to URI', ['from' => $oldpath, 'to' => $filepath]); $filepath = trim($filepath, '/'); $parts = explode('/', $filepath); // Don't %-encode the colon after a Windows drive letter $first = array_shift($parts); if (substr($first, -1) !== ':') { $first = rawurlencode($first); } $parts = array_map('rawurlencode', $parts); array_unshift($parts, $first); $filepath = implode('/', $parts); return 'file:///' . $filepath; } /** * Transforms URI into file path */ public function uriToPath(string $uri) : string { $filepath = urldecode($this->getPathPart($uri)); if (strpos($filepath, ':') !== \false) { if ($filepath[0] === '/') { $filepath = substr($filepath, 1); } $filepath = str_replace('/', '\\', $filepath); } $filepath = $this->path_mapper->mapClientToServer($oldpath = $filepath); $this->logDebug('Translated URI to path', ['from' => $oldpath, 'to' => $filepath]); $realpath = realpath($filepath); if ($realpath !== \false) { return $realpath; } return $filepath; } private function getPathPart(string $uri) : string { $fragments = parse_url($uri); if ($fragments === \false || !isset($fragments['scheme']) || $fragments['scheme'] !== 'file' || !isset($fragments['path'])) { throw new InvalidArgumentException("Not a valid file URI: {$uri}"); } return $fragments['path']; } // the methods below forward special paths // like `$/cancelRequest` to `$this->cancelRequest()` // and `$/a/b/c` to `$this->a->b->c()` public function __isset(string $prop_name) : bool { return $prop_name === '$'; } /** @return static */ public function __get(string $_prop_name) : self { return $this; } } handler = $handler; $this->server = $server; } /** * Diagnostics notification are sent from the server to the client to signal results of validation runs. * * @param Diagnostic[] $diagnostics */ public function publishDiagnostics(string $uri, array $diagnostics, ?int $version = null) : void { if (!$this->server->client->clientConfiguration->provideDiagnostics) { return; } $this->server->logDebug("textDocument/publishDiagnostics"); $this->handler->notify('textDocument/publishDiagnostics', ['uri' => $uri, 'diagnostics' => $diagnostics, 'version' => $version]); } } handler = $handler; $this->mapper = $mapper; $this->server = $server; } /** * The workspace/configuration request is sent from the server to the client to * fetch configuration settings from the client. The request can fetch several * configuration settings in one roundtrip. The order of the returned configuration * settings correspond to the order of the passed ConfigurationItems (e.g. the first * item in the response is the result for the first configuration item in the params). * * @param string $section The configuration section asked for. * @param string|null $scopeUri The scope to get the configuration section for. */ public function requestConfiguration(string $section, ?string $scopeUri = null) : Promise { $this->server->logDebug("workspace/configuration"); /** @var Promise */ return $this->handler->request('workspace/configuration', ['items' => [['section' => $section, 'scopeUri' => $scopeUri]]]); } } handler = $handler; } public function begin(string $title, ?string $message = null, ?int $percentage = null) : void { if ($this->status === self::STATUS_ACTIVE) { throw new LogicException('Progress has already been started'); } if ($this->status === self::STATUS_FINISHED) { throw new LogicException('Progress has already been finished'); } $this->title = $title; $this->notify($message); $this->status = self::STATUS_ACTIVE; } public function update(?string $message = null, ?int $percentage = null) : void { if ($this->status === self::STATUS_FINISHED) { throw new LogicException('Progress has already been finished'); } if ($this->status === self::STATUS_INACTIVE) { throw new LogicException('Progress has not been started yet'); } $this->notify($message); } public function end(?string $message = null) : void { if ($this->status === self::STATUS_FINISHED) { throw new LogicException('Progress has already been finished'); } if ($this->status === self::STATUS_INACTIVE) { throw new LogicException('Progress has not been started yet'); } $this->notify($message); $this->status = self::STATUS_FINISHED; } private function notify(?string $message) : void { $this->handler->notify('telemetry/event', new LogMessage(MessageType::INFO, $this->title . (empty($message) ? '' : ': ' . $message))); } } handler = $handler; $this->token = $token; } public function begin(string $title, ?string $message = null, ?int $percentage = null) : void { if ($this->status === self::STATUS_ACTIVE) { throw new LogicException('Progress has already been started'); } if ($this->status === self::STATUS_FINISHED) { throw new LogicException('Progress has already been finished'); } $notification = ['token' => $this->token, 'value' => ['kind' => 'begin', 'title' => $title]]; if ($message !== null) { $notification['value']['message'] = $message; } if ($percentage !== null) { $notification['value']['percentage'] = $percentage; $this->withPercentage = \true; } $this->handler->notify('$/progress', $notification); $this->status = self::STATUS_ACTIVE; } public function end(?string $message = null) : void { if ($this->status === self::STATUS_FINISHED) { throw new LogicException('Progress has already been finished'); } if ($this->status === self::STATUS_INACTIVE) { throw new LogicException('Progress has not been started yet'); } $notification = ['token' => $this->token, 'value' => ['kind' => 'end']]; if ($message !== null) { $notification['value']['message'] = $message; } $this->handler->notify('$/progress', $notification); $this->status = self::STATUS_FINISHED; } public function update(?string $message = null, ?int $percentage = null) : void { if ($this->status === self::STATUS_FINISHED) { throw new LogicException('Progress has already been finished'); } if ($this->status === self::STATUS_INACTIVE) { throw new LogicException('Progress has not been started yet'); } $notification = ['token' => $this->token, 'value' => ['kind' => 'report']]; if ($message !== null) { $notification['value']['message'] = $message; } if ($percentage !== null) { if (!$this->withPercentage) { throw new LogicException('Cannot update percentage for progress ' . 'that was started without percentage'); } $notification['value']['percentage'] = $percentage; } $this->handler->notify('$/progress', $notification); } } body = MessageBody::parse(array_pop($parts)); foreach ($parts as $line) { if ($line) { $pair = explode(': ', $line); if (isset($pair[1])) { $obj->headers[$pair[0]] = $pair[1]; } } } return $obj; } /** * @param string[] $headers */ public function __construct(?MessageBody $body = null, array $headers = []) { $this->body = $body; if (!isset($headers['Content-Type'])) { $headers['Content-Type'] = 'application/vscode-jsonrpc; charset=utf8'; } $this->headers = $headers; } public function __toString() : string { $body = (string) $this->body; $contentLength = strlen($body); $this->headers['Content-Length'] = (string) $contentLength; $headers = ''; foreach ($this->headers as $name => $value) { $headers .= "{$name}: {$value}\r\n"; } return $headers . "\r\n" . $body; } } codebase = $codebase; } /** * @return array */ public function resolve(MethodStorage $method_storage, ClassLikeStorage $called_class) : array { $method_name_lc = strtolower($method_storage->cased_name ?? ''); $assertions = $method_storage->assertions; $inherited_classes_and_interfaces = array_values(array_filter(array_merge($called_class->parent_classes, $called_class->class_implements), fn(string $classOrInterface) => $this->codebase->classOrInterfaceOrEnumExists($classOrInterface))); foreach ($inherited_classes_and_interfaces as $potential_assertion_providing_class) { $potential_assertion_providing_classlike_storage = $this->codebase->classlike_storage_provider->get($potential_assertion_providing_class); if (!isset($potential_assertion_providing_classlike_storage->methods[$method_name_lc])) { continue; } $potential_assertion_providing_method_storage = $potential_assertion_providing_classlike_storage->methods[$method_name_lc]; /** * Since the inheritance does not provide its own assertions, we have to detect those * from inherited classes */ $assertions += $potential_assertion_providing_method_storage->assertions; } return $assertions; } } > */ protected array $backward_edges = []; /** @var array */ private array $nodes = []; /** @var array> */ private array $origin_locations_by_id = []; public function addNode(DataFlowNode $node) : void { $this->nodes[$node->id] = $node; } /** * @param array $added_taints * @param array $removed_taints */ public function addPath(DataFlowNode $from, DataFlowNode $to, string $path_type, ?array $added_taints = null, ?array $removed_taints = null) : void { $from_id = $from->id; $to_id = $to->id; if ($from_id === $to_id) { return; } $length = 0; if ($from->code_location && $to->code_location && $from->code_location->file_path === $to->code_location->file_path) { $to_line = $to->code_location->raw_line_number; $from_line = $from->code_location->raw_line_number; $length = abs($to_line - $from_line); } $this->backward_edges[$to_id][$from_id] = \true; $this->forward_edges[$from_id][$to_id] = new Path($path_type, $length); } public function isVariableUsed(DataFlowNode $assignment_node) : bool { $visited_source_ids = []; $sources = [$assignment_node]; for ($i = 0; count($sources) && $i < 200; $i++) { $new_child_nodes = []; foreach ($sources as $source) { $visited_source_ids[$source->id] = \true; $child_nodes = $this->getChildNodes($source, $visited_source_ids); if ($child_nodes === null) { return \true; } $new_child_nodes = array_merge($new_child_nodes, $child_nodes); } $sources = $new_child_nodes; } return \false; } /** * @return list */ public function getOriginLocations(DataFlowNode $assignment_node) : array { if (isset($this->origin_locations_by_id[$assignment_node->id])) { return $this->origin_locations_by_id[$assignment_node->id]; } $visited_child_ids = []; $origin_locations = []; $child_nodes = [$assignment_node]; for ($i = 0; count($child_nodes) && $i < 200; $i++) { $new_parent_nodes = []; foreach ($child_nodes as $child_node) { $visited_child_ids[$child_node->id] = \true; $parent_nodes = $this->getParentNodes($child_node, $visited_child_ids); if (!$parent_nodes) { if ($child_node->code_location) { $origin_locations[] = $child_node->code_location; } continue; } $new_parent_nodes = [...$new_parent_nodes, ...$parent_nodes]; } $child_nodes = $new_parent_nodes; } $this->origin_locations_by_id[$assignment_node->id] = $origin_locations; return $origin_locations; } /** * @param array $visited_source_ids * @return array|null */ private function getChildNodes(DataFlowNode $generated_source, array $visited_source_ids) : ?array { $new_child_nodes = []; if (!isset($this->forward_edges[$generated_source->id])) { return []; } foreach ($this->forward_edges[$generated_source->id] as $to_id => $path) { $path_type = $path->type; if ($path->type === 'variable-use' || $path->type === 'closure-use' || $path->type === 'global-use' || $path->type === 'use-inside-instance-property' || $path->type === 'use-inside-static-property' || $path->type === 'use-inside-call' || $path->type === 'use-inside-conditional' || $path->type === 'use-inside-isset' || $path->type === 'arg' || $path->type === 'comparison') { return null; } if (isset($visited_source_ids[$to_id])) { continue; } if (self::shouldIgnoreFetch($path_type, 'arraykey', $generated_source->path_types)) { continue; } if (self::shouldIgnoreFetch($path_type, 'arrayvalue', $generated_source->path_types)) { continue; } if (self::shouldIgnoreFetch($path_type, 'property', $generated_source->path_types)) { continue; } $new_destination = new DataFlowNode($to_id, $to_id, null); $new_destination->path_types = [...$generated_source->path_types, ...[$path_type]]; $new_child_nodes[$to_id] = $new_destination; } return $new_child_nodes; } /** * @param array $visited_source_ids * @return list */ private function getParentNodes(DataFlowNode $destination, array $visited_source_ids) : array { $new_parent_nodes = []; if (!isset($this->backward_edges[$destination->id])) { return []; } foreach ($this->backward_edges[$destination->id] as $from_id => $_) { if (isset($visited_source_ids[$from_id])) { continue; } if (isset($this->nodes[$from_id])) { $new_parent_nodes[] = $this->nodes[$from_id]; } } return $new_parent_nodes; } } value); } if ($c instanceof UnresolvedBinaryOp) { $left = self::resolve($classlikes, $c->left, $statements_analyzer, $visited_constant_ids + [$c_id => \true]); $right = self::resolve($classlikes, $c->right, $statements_analyzer, $visited_constant_ids + [$c_id => \true]); if ($left instanceof TMixed || $right instanceof TMixed) { return new TMixed(); } if ($c instanceof UnresolvedConcatOp) { if (($left instanceof TLiteralString || $left instanceof TLiteralFloat || $left instanceof TLiteralInt) && ($right instanceof TLiteralString || $right instanceof TLiteralFloat || $right instanceof TLiteralInt)) { return Type::getAtomicStringFromLiteral($left->value . $right->value); } return new TString(); } if ($c instanceof UnresolvedAdditionOp || $c instanceof UnresolvedSubtractionOp || $c instanceof UnresolvedDivisionOp || $c instanceof UnresolvedMultiplicationOp || $c instanceof UnresolvedBitwiseOr || $c instanceof UnresolvedBitwiseXor || $c instanceof UnresolvedBitwiseAnd) { if (($left instanceof TLiteralFloat || $left instanceof TLiteralInt) && ($right instanceof TLiteralFloat || $right instanceof TLiteralInt)) { if ($c instanceof UnresolvedAdditionOp) { return self::getLiteralTypeFromScalarValue($left->value + $right->value); } if ($c instanceof UnresolvedSubtractionOp) { return self::getLiteralTypeFromScalarValue($left->value - $right->value); } if ($c instanceof UnresolvedDivisionOp) { return self::getLiteralTypeFromScalarValue($left->value / $right->value); } if ($c instanceof UnresolvedBitwiseOr) { return self::getLiteralTypeFromScalarValue($left->value | $right->value); } if ($c instanceof UnresolvedBitwiseXor) { return self::getLiteralTypeFromScalarValue($left->value ^ $right->value); } if ($c instanceof UnresolvedBitwiseAnd) { return self::getLiteralTypeFromScalarValue($left->value & $right->value); } return self::getLiteralTypeFromScalarValue($left->value * $right->value); } if ($left instanceof TKeyedArray && $right instanceof TKeyedArray) { $type = new TKeyedArray($left->properties + $right->properties, null); return $type; } return new TMixed(); } return new TMixed(); } if ($c instanceof UnresolvedTernary) { $cond = self::resolve($classlikes, $c->cond, $statements_analyzer, $visited_constant_ids + [$c_id => \true]); $if = $c->if ? self::resolve($classlikes, $c->if, $statements_analyzer, $visited_constant_ids + [$c_id => \true]) : null; $else = self::resolve($classlikes, $c->else, $statements_analyzer, $visited_constant_ids + [$c_id => \true]); if ($cond instanceof TLiteralFloat || $cond instanceof TLiteralInt || $cond instanceof TLiteralString) { if ($cond->value) { return $if ?? $cond; } } elseif ($cond instanceof TFalse || $cond instanceof TNull) { return $else; } elseif ($cond instanceof TTrue) { return $if ?? $cond; } } if ($c instanceof ArrayValue) { $properties = []; $auto_key = 0; if (!$c->entries) { return new TArray([Type::getNever(), Type::getNever()]); } $is_list = \true; foreach ($c->entries as $entry) { if ($entry instanceof ArraySpread) { $spread_array = self::resolve($classlikes, $entry->array, $statements_analyzer, $visited_constant_ids + [$c_id => \true]); if ($spread_array instanceof TArray && $spread_array->isEmptyArray()) { continue; } if (!$spread_array instanceof TKeyedArray) { return new TArray([Type::getArrayKey(), Type::getMixed()]); } foreach ($spread_array->properties as $k => $spread_array_type) { $properties[is_string($k) ? $k : $auto_key++] = $spread_array_type; } continue; } if ($entry->key) { $key_type = self::resolve($classlikes, $entry->key, $statements_analyzer, $visited_constant_ids + [$c_id => \true]); if (!$key_type instanceof TLiteralInt || $key_type->value !== $auto_key) { $is_list = \false; } } else { $key_type = new TLiteralInt($auto_key); } if ($key_type instanceof TLiteralInt || $key_type instanceof TLiteralString) { $key_value = $key_type->value; if ($key_type instanceof TLiteralInt) { $auto_key = $key_type->value + 1; } elseif (ctype_digit($key_type->value)) { $auto_key = (int) $key_type->value + 1; } } else { return new TArray([Type::getArrayKey(), Type::getMixed()]); } $value_type = new Union([self::resolve($classlikes, $entry->value, $statements_analyzer, $visited_constant_ids + [$c_id => \true])]); $properties[$key_value] = $value_type; } if (empty($properties)) { $resolved_type = new TArray([new Union([new TNever()]), new Union([new TNever()])]); } else { $resolved_type = new TKeyedArray($properties, null, null, $is_list); } return $resolved_type; } if ($c instanceof ClassConstant) { if ($c->name === 'class') { return new TLiteralClassString($c->fqcln); } $found_type = $classlikes->getClassConstantType($c->fqcln, $c->name, ReflectionProperty::IS_PRIVATE, $statements_analyzer, $visited_constant_ids + [$c_id => \true]); if ($found_type) { return $found_type->getSingleAtomic(); } } if ($c instanceof ArrayOffsetFetch) { $var_type = self::resolve($classlikes, $c->array, $statements_analyzer, $visited_constant_ids + [$c_id => \true]); $offset_type = self::resolve($classlikes, $c->offset, $statements_analyzer, $visited_constant_ids + [$c_id => \true]); if ($var_type instanceof TKeyedArray && ($offset_type instanceof TLiteralInt || $offset_type instanceof TLiteralString)) { $union = $var_type->properties[$offset_type->value] ?? null; if ($union && $union->isSingle()) { return $union->getSingleAtomic(); } } } if ($c instanceof Constant) { if ($statements_analyzer) { $found_type = ConstFetchAnalyzer::getConstType($statements_analyzer, $c->name, $c->is_fully_qualified, null); if ($found_type) { return $found_type->getSingleAtomic(); } } } if ($c instanceof EnumPropertyFetch) { if ($classlikes->enumExists($c->fqcln)) { $enum_storage = $classlikes->getStorageFor($c->fqcln); if (isset($enum_storage->enum_cases[$c->case])) { if ($c instanceof EnumValueFetch) { $value = $enum_storage->enum_cases[$c->case]->value; if (is_string($value)) { return Type::getString($value)->getSingleAtomic(); } elseif (is_int($value)) { return Type::getInt(\false, $value)->getSingleAtomic(); } elseif ($value instanceof UnresolvedConstantComponent) { return self::resolve($classlikes, $value, $statements_analyzer, $visited_constant_ids + [$c_id => \true]); } } elseif ($c instanceof EnumNameFetch) { return Type::getString($c->case)->getSingleAtomic(); } } } } return new TMixed(); } /** * Note: This takes an array, but any array should only contain other arrays and scalars. * * @param array|string|int|float|bool|null $value */ public static function getLiteralTypeFromScalarValue($value) : Atomic { if (is_array($value)) { if (empty($value)) { return Type::getEmptyArray()->getSingleAtomic(); } $types = []; /** @var array|scalar|null $val */ foreach ($value as $key => $val) { $types[$key] = new Union([self::getLiteralTypeFromScalarValue($val)]); } return new TKeyedArray($types, null); } if (is_string($value)) { return Type::getAtomicStringFromLiteral($value); } if (is_int($value)) { return new TLiteralInt($value); } if (is_float($value)) { return new TLiteralFloat($value); } if ($value === \false) { return new TFalse(); } if ($value === \true) { return new TTrue(); } if ($value === null) { return new TNull(); } throw new InvalidArgumentException('$value must be a scalar.'); } } */ private static array $stubbed_functions; public FunctionReturnTypeProvider $return_type_provider; public FunctionExistenceProvider $existence_provider; public FunctionParamsProvider $params_provider; public DynamicFunctionStorageProvider $dynamic_storage_provider; private \Psalm\Internal\Codebase\Reflection $reflection; public function __construct(FileStorageProvider $storage_provider, \Psalm\Internal\Codebase\Reflection $reflection) { $this->file_storage_provider = $storage_provider; $this->reflection = $reflection; $this->return_type_provider = new FunctionReturnTypeProvider(); $this->existence_provider = new FunctionExistenceProvider(); $this->params_provider = new FunctionParamsProvider(); $this->dynamic_storage_provider = new DynamicFunctionStorageProvider(); self::$stubbed_functions = []; } /** * @param non-empty-lowercase-string $function_id */ public function getStorage(?StatementsAnalyzer $statements_analyzer, string $function_id, ?string $root_file_path = null, ?string $checked_file_path = null) : FunctionStorage { if ($function_id[0] === '\\') { $function_id = substr($function_id, 1); } $from_stubs = \false; if (isset(self::$stubbed_functions[$function_id])) { $from_stubs = self::$stubbed_functions[$function_id]; } $file_storage = null; if ($statements_analyzer) { $root_file_path = $statements_analyzer->getRootFilePath(); $checked_file_path = $statements_analyzer->getFilePath(); $file_storage = $this->file_storage_provider->get($root_file_path); $function_analyzers = $statements_analyzer->getFunctionAnalyzers(); if (isset($function_analyzers[$function_id])) { $function_id = $function_analyzers[$function_id]->getFunctionId(); if (isset($file_storage->functions[$function_id])) { return $file_storage->functions[$function_id]; } } // closures can be returned here if (isset($file_storage->functions[$function_id])) { return $file_storage->functions[$function_id]; } } if (!$root_file_path || !$checked_file_path) { if ($this->reflection->hasFunction($function_id)) { return $this->reflection->getFunctionStorage($function_id); } if ($from_stubs) { return $from_stubs; } throw new UnexpectedValueException('Expecting non-empty $root_file_path and $checked_file_path'); } if ($this->reflection->hasFunction($function_id)) { return $this->reflection->getFunctionStorage($function_id); } if (!isset($file_storage->declaring_function_ids[$function_id])) { if ($checked_file_path !== $root_file_path) { $file_storage = $this->file_storage_provider->get($checked_file_path); if (isset($file_storage->functions[$function_id])) { return $file_storage->functions[$function_id]; } } if ($from_stubs) { return $from_stubs; } throw new UnexpectedValueException('Expecting ' . $function_id . ' to have storage in ' . $checked_file_path); } $declaring_file_path = $file_storage->declaring_function_ids[$function_id]; $declaring_file_storage = $this->file_storage_provider->get($declaring_file_path); if (!isset($declaring_file_storage->functions[$function_id])) { if ($from_stubs) { return $from_stubs; } throw new UnexpectedValueException('Not expecting ' . $function_id . ' to not have storage in ' . $declaring_file_path); } return $declaring_file_storage->functions[$function_id]; } public function addGlobalFunction(string $function_id, FunctionStorage $storage) : void { self::$stubbed_functions[strtolower($function_id)] = $storage; } public function hasStubbedFunction(string $function_id) : bool { return isset(self::$stubbed_functions[strtolower($function_id)]); } /** * @return array */ public function getAllStubbedFunctions() : array { return self::$stubbed_functions; } /** * @param lowercase-string $function_id */ public function functionExists(StatementsAnalyzer $statements_analyzer, string $function_id) : bool { if ($this->existence_provider->has($function_id)) { $function_exists = $this->existence_provider->doesFunctionExist($statements_analyzer, $function_id); if ($function_exists !== null) { return $function_exists; } } $file_storage = $this->file_storage_provider->get($statements_analyzer->getRootFilePath()); if (isset($file_storage->declaring_function_ids[$function_id])) { return \true; } if ($this->reflection->hasFunction($function_id)) { return \true; } if (isset(self::$stubbed_functions[$function_id])) { return \true; } if (isset($statements_analyzer->getFunctionAnalyzers()[$function_id])) { return \true; } $predefined_functions = $statements_analyzer->getCodebase()->config->getPredefinedFunctions(); if (isset($predefined_functions[$function_id])) { /** @psalm-suppress ArgumentTypeCoercion */ if ($this->reflection->registerFunction($function_id) === \false) { return \false; } return \true; } return \false; } /** * @param non-empty-string $function_name * @return non-empty-string */ public function getFullyQualifiedFunctionNameFromString(string $function_name, StatementsSource $source) : string { if ($function_name[0] === '\\') { $function_name = substr($function_name, 1); if ($function_name === '') { throw new UnexpectedValueException('Malformed function name'); } return $function_name; } $function_name_lcase = strtolower($function_name); $aliases = $source->getAliases(); $imported_function_namespaces = $aliases->functions; $imported_namespaces = $aliases->uses; if (strpos($function_name, '\\') !== \false) { $function_name_parts = explode('\\', $function_name); $first_namespace = array_shift($function_name_parts); $first_namespace_lcase = strtolower($first_namespace); if (isset($imported_namespaces[$first_namespace_lcase])) { return $imported_namespaces[$first_namespace_lcase] . '\\' . implode('\\', $function_name_parts); } if (isset($imported_function_namespaces[$first_namespace_lcase])) { return $imported_function_namespaces[$first_namespace_lcase] . '\\' . implode('\\', $function_name_parts); } } elseif (isset($imported_function_namespaces[$function_name_lcase])) { return $imported_function_namespaces[$function_name_lcase]; } $namespace = $source->getNamespace(); return ($namespace ? $namespace . '\\' : '') . $function_name; } /** * @return array */ public function getMatchingFunctionNames(string $stub, int $offset, string $file_path, Codebase $codebase) : array { if ($stub[0] === '*') { $stub = substr($stub, 1); } $fully_qualified = \false; if ($stub[0] === '\\') { $fully_qualified = \true; $stub = substr($stub, 1); $stub_namespace = ''; } else { // functions can reference either the current namespace or root-namespaced // equivalents. We therefore want to make both candidates. [$stub_namespace, $stub] = explode('-', $stub); } /** @var array */ $matching_functions = []; $file_storage = $this->file_storage_provider->get($file_path); $current_namespace_aliases = null; foreach ($file_storage->namespace_aliases as $namespace_start => $namespace_aliases) { if ($namespace_start < $offset) { $current_namespace_aliases = $namespace_aliases; break; } } // We will search all functions for several patterns. This will // be for all used namespaces, the global namespace and matched // used functions. $match_function_patterns = [$stub . '*']; if ($stub_namespace) { $match_function_patterns[] = $stub_namespace . '\\' . $stub . '*'; } if ($current_namespace_aliases) { foreach ($current_namespace_aliases->functions as $alias_name => $function_name) { if (strpos($alias_name, $stub) === 0) { try { $match_function_patterns[] = $function_name; } catch (Exception $e) { } } } if (!$fully_qualified) { foreach ($current_namespace_aliases->uses as $namespace_name) { $match_function_patterns[] = $namespace_name . '\\' . $stub . '*'; } } } $function_map = $file_storage->functions + $this->getAllStubbedFunctions() + $this->reflection->getFunctions() + $codebase->config->getPredefinedFunctions(); foreach ($function_map as $function_name => $function) { foreach ($match_function_patterns as $pattern) { $pattern_lc = strtolower($pattern); if (substr($pattern, -1, 1) === '*') { if (strpos($function_name, rtrim($pattern_lc, '*')) !== 0) { continue; } } elseif ($function_name !== $pattern) { continue; } if (is_bool($function)) { /** @var callable-string $function_name */ if ($this->reflection->registerFunction($function_name) === \false) { continue; } $function = $this->reflection->getFunctionStorage($function_name); } if ($function->cased_name) { $cased_name_parts = explode('\\', $function->cased_name); $pattern_parts = explode('\\', $pattern); if (end($cased_name_parts)[0] !== end($pattern_parts)[0]) { continue; } } /** @var lowercase-string $function_name */ $matching_functions[$function_name] = $function; } } return $matching_functions; } public static function isVariadic(Codebase $codebase, string $function_id, string $file_path) : bool { $file_storage = $codebase->file_storage_provider->get($file_path); if (!isset($file_storage->declaring_function_ids[$function_id])) { return \false; } $declaring_file_path = $file_storage->declaring_function_ids[$function_id]; $file_storage = $declaring_file_path === $file_path ? $file_storage : $codebase->file_storage_provider->get($declaring_file_path); return isset($file_storage->functions[$function_id]) && $file_storage->functions[$function_id]->variadic; } /** * @param ?list $args */ public function isCallMapFunctionPure(Codebase $codebase, ?NodeTypeProvider $type_provider, string $function_id, ?array $args, bool &$must_use = \true) : bool { if (\Psalm\Internal\Codebase\ImpureFunctionsList::isImpure($function_id)) { return \false; } if ($function_id === 'serialize' && isset($args[0]) && $type_provider) { $serialize_type = $type_provider->getType($args[0]->value); if ($serialize_type && $serialize_type->canContainObjectType($codebase)) { return \false; } } if (strpos($function_id, 'image') === 0) { return \false; } if (strpos($function_id, 'readline') === 0) { return \false; } if (($function_id === 'var_export' || $function_id === 'print_r') && !isset($args[1])) { return \false; } if ($function_id === 'assert') { $must_use = \false; return \true; } if ($function_id === 'func_num_args' || $function_id === 'func_get_args') { return \true; } if (in_array($function_id, ['count', 'sizeof']) && isset($args[0]) && $type_provider) { $count_type = $type_provider->getType($args[0]->value); if ($count_type) { foreach ($count_type->getAtomicTypes() as $atomic_count_type) { if ($atomic_count_type instanceof TNamedObject) { $count_method_id = new MethodIdentifier($atomic_count_type->value, 'count'); try { return $codebase->methods->getStorage($count_method_id)->mutation_free; } catch (Exception $e) { // do nothing } } } } } $function_callable = \Psalm\Internal\Codebase\InternalCallMapHandler::getCallableFromCallMapById($codebase, $function_id, $args ?: [], null); if (!isset($function_callable->params) || $args !== null && count($args) === 0 || $function_callable->return_type && $function_callable->return_type->isVoid()) { return \false; } $must_use = $function_id !== 'array_map' || isset($args[0]) && !$args[0]->value instanceof ClosureNode; foreach ($function_callable->params as $i => $param) { if ($type_provider && $param->type && $param->type->hasCallableType() && isset($args[$i])) { $arg_type = $type_provider->getType($args[$i]->value); if ($arg_type) { foreach ($arg_type->getAtomicTypes() as $possible_callable) { $possible_callable = CallableTypeComparator::getCallableFromAtomic($codebase, $possible_callable); if ($possible_callable && !$possible_callable->is_pure) { return \false; } } } } if ($param->by_ref && isset($args[$i])) { $must_use = \false; } } return \true; } public static function clearCache() : void { self::$stubbed_functions = []; } } >|null */ private static ?array $call_map = null; /** * @var array>|null */ private static ?array $call_map_callables = []; /** * @var non-empty-array>>|null */ private static ?array $taint_sink_map = null; /** * @param list $args */ public static function getCallableFromCallMapById(Codebase $codebase, string $method_id, array $args, ?NodeDataProvider $nodes) : TCallable { $possible_callables = self::getCallablesFromCallMap($method_id); if ($possible_callables === null) { throw new UnexpectedValueException('Not expecting $function_param_options to be null for ' . $method_id); } return self::getMatchingCallableFromCallMapOptions($codebase, $possible_callables, $args, $nodes, $method_id); } /** * @param non-empty-list $callables * @param list $args */ public static function getMatchingCallableFromCallMapOptions(Codebase $codebase, array $callables, array $args, ?NodeTypeProvider $nodes, string $method_id) : TCallable { if (count($callables) === 1) { return $callables[0]; } $matching_param_count_callable = null; $matching_coerced_param_count_callable = null; foreach ($callables as $possible_callable) { $possible_function_params = $possible_callable->params; assert($possible_function_params !== null); $all_args_match = \true; $type_coerced = \false; $last_param = count($possible_function_params) ? $possible_function_params[count($possible_function_params) - 1] : null; $mandatory_param_count = count($possible_function_params); foreach ($possible_function_params as $i => $possible_function_param) { if ($possible_function_param->is_optional) { $mandatory_param_count = $i; break; } } if ($mandatory_param_count > count($args) && !($last_param && $last_param->is_variadic)) { continue; } foreach ($args as $argument_offset => $arg) { if ($argument_offset >= count($possible_function_params)) { if (!$last_param || !$last_param->is_variadic) { $all_args_match = \false; break; } $function_param = $last_param; } else { $function_param = $possible_function_params[$argument_offset]; } $param_type = $function_param->type; if (!$param_type) { continue; } if (!$nodes || !($arg_type = $nodes->getType($arg->value))) { continue; } if ($arg_type->hasMixed()) { continue; } if ($arg->unpack && !$function_param->is_variadic) { if ($arg_type->hasArray()) { /** * @var TArray|TKeyedArray */ $array_atomic_type = $arg_type->getArray(); if ($array_atomic_type instanceof TKeyedArray) { $arg_type = $array_atomic_type->getGenericValueType(); } else { $arg_type = $array_atomic_type->type_params[1]; } } } $arg_result = new TypeComparisonResult(); if (UnionTypeComparator::isContainedBy($codebase, $arg_type, $param_type, \true, \true, $arg_result) || $arg_result->type_coerced) { if ($arg_result->type_coerced) { $type_coerced = \true; } continue; } $all_args_match = \false; break; } if (count($args) === count($possible_function_params)) { $matching_param_count_callable = $possible_callable; } if ($all_args_match && (!$type_coerced || $method_id === 'max' || $method_id === 'min')) { return $possible_callable; } if ($all_args_match) { $matching_coerced_param_count_callable = $possible_callable; } } if ($matching_coerced_param_count_callable) { return $matching_coerced_param_count_callable; } if ($matching_param_count_callable) { return $matching_param_count_callable; } // if we don't succeed in finding a match, set to the first possible and wait for issues below return $callables[0]; } /** * @return non-empty-list|null */ public static function getCallablesFromCallMap(string $function_id) : ?array { $call_map_key = strtolower($function_id); if (isset(self::$call_map_callables[$call_map_key])) { return self::$call_map_callables[$call_map_key]; } $call_map = self::getCallMap(); if (!isset($call_map[$call_map_key])) { return null; } $call_map_functions = []; $call_map_functions[] = $call_map[$call_map_key]; for ($i = 1; $i < 10; ++$i) { if (!isset($call_map[$call_map_key . '\'' . $i])) { break; } $call_map_functions[] = $call_map[$call_map_key . '\'' . $i]; } $possible_callables = []; foreach ($call_map_functions as $call_map_function_args) { $return_type_string = array_shift($call_map_function_args); if (!$return_type_string) { $return_type = Type::getMixed(); } else { $return_type = Type::parseString($return_type_string); } $function_params = []; $arg_offset = 0; /** @var string $arg_name - key type changed with above array_shift */ foreach ($call_map_function_args as $arg_name => $arg_type) { $by_reference = \false; $optional = \false; $variadic = \false; if ($arg_name[0] === '&') { $arg_name = substr($arg_name, 1); $by_reference = \true; } if (substr($arg_name, -1) === '=') { $arg_name = substr($arg_name, 0, -1); $optional = \true; } if (strpos($arg_name, '...') === 0) { $arg_name = substr($arg_name, 3); $variadic = \true; } $param_type = $arg_type ? Type::parseString($arg_type) : Type::getMixed(); $out_type = null; if ($by_reference && strlen($arg_name) > 2 && $arg_name[0] === 'w' && $arg_name[1] === '_') { // strip prefix that is not actually a part of the parameter name $arg_name = substr($arg_name, 2); $out_type = $param_type; $param_type = Type::getMixed(); } // removes `rw_` leftover from `&rw_haystack` or `&rw_needle` or `&rw_actual_name` // it doesn't have any specific meaning apart from `&` signifying that // the parameter is passed by reference (handled above) if ($by_reference && strlen($arg_name) > 3 && strpos($arg_name, 'rw_') === 0) { $arg_name = substr($arg_name, 3); } $function_param = new FunctionLikeParameter($arg_name, $by_reference, $param_type, $param_type, null, null, $optional, \false, $variadic); if ($out_type) { $function_param->out_type = $out_type; } if ($arg_name === 'haystack') { $function_param->expect_variable = \true; } if (isset(self::$taint_sink_map[$call_map_key][$arg_offset])) { $function_param->sinks = self::$taint_sink_map[$call_map_key][$arg_offset]; } $function_param->signature_type = null; $function_params[] = $function_param; $arg_offset++; } $possible_callables[] = new TCallable('callable', $function_params, $return_type); } self::$call_map_callables[$call_map_key] = $possible_callables; return $possible_callables; } /** * Gets the method/function call map * * @return non-empty-array> * @psalm-assert !null self::$taint_sink_map * @psalm-assert !null self::$call_map */ public static function getCallMap() : array { $codebase = ProjectAnalyzer::getInstance()->getCodebase(); $analyzer_major_version = $codebase->getMajorAnalysisPhpVersion(); $analyzer_minor_version = $codebase->getMinorAnalysisPhpVersion(); $analyzer_version = $analyzer_major_version . '.' . $analyzer_minor_version; $current_version = self::PHP_MAJOR_VERSION . '.' . self::PHP_MINOR_VERSION; $analyzer_version_int = (int) ($analyzer_major_version . $analyzer_minor_version); $current_version_int = (int) (self::PHP_MAJOR_VERSION . self::PHP_MINOR_VERSION); if (self::$call_map !== null && $analyzer_major_version === self::$loaded_php_major_version && $analyzer_minor_version === self::$loaded_php_minor_version) { return self::$call_map; } /** @var non-empty-array> */ $call_map_data = (require dirname(__DIR__, 4) . '/dictionaries/CallMap.php'); $call_map = []; foreach ($call_map_data as $key => $value) { $cased_key = strtolower($key); $call_map[$cased_key] = $value; } self::$call_map = $call_map; /** * @var non-empty-array>> */ $taint_map_data = (require dirname(__DIR__, 4) . '/dictionaries/InternalTaintSinkMap.php'); $taint_map = []; foreach ($taint_map_data as $key => $value) { $cased_key = strtolower($key); $taint_map[$cased_key] = $value; } self::$taint_sink_map = $taint_map; if (version_compare($analyzer_version, $current_version, '<')) { // the following assumes both minor and major versions a single digits for ($i = $current_version_int; $i > $analyzer_version_int && $i >= self::LOWEST_AVAILABLE_DELTA; --$i) { $delta_file = dirname(__DIR__, 4) . '/dictionaries/CallMap_' . $i . '_delta.php'; if (!file_exists($delta_file)) { continue; } /** * @var array{ * added: array>, * changed: array, * new: array * }>, * removed: array> * } */ $diff_call_map = (require $delta_file); foreach ($diff_call_map['added'] as $key => $_) { $cased_key = strtolower($key); unset(self::$call_map[$cased_key]); } foreach ($diff_call_map['removed'] as $key => $value) { $cased_key = strtolower($key); self::$call_map[$cased_key] = $value; } foreach ($diff_call_map['changed'] as $key => ['old' => $value]) { $cased_key = strtolower($key); self::$call_map[$cased_key] = $value; } } } assert(!empty(self::$call_map)); self::$loaded_php_major_version = $analyzer_major_version; self::$loaded_php_minor_version = $analyzer_minor_version; return self::$call_map; } public static function inCallMap(string $key) : bool { return isset(self::getCallMap()[strtolower($key)]); } public static function clearCache() : void { self::$call_map_callables = []; } } , * array, * array, * array, * array, * array, * array, * array, * array * } * * @psalm-type PoolData = array{ * classlikes_data:array{ * array, * array, * array, * array, * array, * array, * array, * array, * array * }, * scanner_data: ThreadData, * issues:array>, * changed_members:array>, * unchanged_signature_members:array>, * diff_map:array>, * deletion_ranges:array>, * errors:array, * classlike_storage:array, * file_storage:array, * new_file_content_hashes: array, * taint_data: ?TaintFlowGraph * } */ /** * @internal * * Contains methods that aid in the scanning of Psalm's codebase */ final class Scanner { private Codebase $codebase; /** * @var array */ private array $classlike_files = []; /** * @var array */ private array $deep_scanned_classlike_files = []; /** * @var array */ private array $files_to_scan = []; /** * @var array */ private array $classes_to_scan = []; /** * @var array */ private array $classes_to_deep_scan = []; /** * @var array */ private array $files_to_deep_scan = []; /** * @var array */ private array $scanned_files = []; /** * @var array */ private array $store_scan_failure = []; /** * @var array */ private array $reflected_classlikes_lc = []; private \Psalm\Internal\Codebase\Reflection $reflection; private Config $config; private Progress $progress; private FileStorageProvider $file_storage_provider; private FileProvider $file_provider; private FileReferenceProvider $file_reference_provider; private bool $is_forked = \false; public function __construct(Codebase $codebase, Config $config, FileStorageProvider $file_storage_provider, FileProvider $file_provider, \Psalm\Internal\Codebase\Reflection $reflection, FileReferenceProvider $file_reference_provider, Progress $progress) { $this->codebase = $codebase; $this->reflection = $reflection; $this->file_provider = $file_provider; $this->progress = $progress; $this->file_storage_provider = $file_storage_provider; $this->config = $config; $this->file_reference_provider = $file_reference_provider; } /** * @param array $files_to_scan */ public function addFilesToShallowScan(array $files_to_scan) : void { $this->files_to_scan += $files_to_scan; } /** * @param array $files_to_scan */ public function addFilesToDeepScan(array $files_to_scan) : void { $this->files_to_scan += $files_to_scan; $this->files_to_deep_scan += $files_to_scan; } public function addFileToShallowScan(string $file_path) : void { $this->files_to_scan[$file_path] = $file_path; } public function addFileToDeepScan(string $file_path) : void { $this->files_to_scan[$file_path] = $file_path; $this->files_to_deep_scan[$file_path] = $file_path; } public function removeFile(string $file_path) : void { unset($this->scanned_files[$file_path]); } public function removeClassLike(string $fq_classlike_name_lc) : void { unset($this->classlike_files[$fq_classlike_name_lc], $this->deep_scanned_classlike_files[$fq_classlike_name_lc]); } public function setClassLikeFilePath(string $fq_classlike_name_lc, string $file_path) : void { $this->classlike_files[$fq_classlike_name_lc] = $file_path; } public function getClassLikeFilePath(string $fq_classlike_name_lc) : string { if (!isset($this->classlike_files[$fq_classlike_name_lc])) { throw new UnexpectedValueException('Could not find file for ' . $fq_classlike_name_lc); } return $this->classlike_files[$fq_classlike_name_lc]; } /** * @param array $phantom_classes */ public function queueClassLikeForScanning(string $fq_classlike_name, bool $analyze_too = \false, bool $store_failure = \true, array $phantom_classes = []) : void { if ($fq_classlike_name[0] === '\\') { $fq_classlike_name = substr($fq_classlike_name, 1); } $fq_classlike_name_lc = strtolower($fq_classlike_name); if ($fq_classlike_name_lc === 'static') { return; } // avoid checking classes that we know will just end in failure if ($fq_classlike_name_lc === 'null' || substr($fq_classlike_name_lc, -5) === '\\null') { return; } if (!isset($this->classlike_files[$fq_classlike_name_lc]) || $analyze_too && !isset($this->deep_scanned_classlike_files[$fq_classlike_name_lc])) { if (!isset($this->classes_to_scan[$fq_classlike_name_lc]) || $store_failure) { $this->classes_to_scan[$fq_classlike_name_lc] = $fq_classlike_name; } if ($analyze_too) { $this->classes_to_deep_scan[$fq_classlike_name_lc] = \true; } $this->store_scan_failure[$fq_classlike_name] = $store_failure; if (\Psalm\Internal\Codebase\PropertyMap::inPropertyMap($fq_classlike_name_lc)) { $public_mapped_properties = \Psalm\Internal\Codebase\PropertyMap::getPropertyMap()[$fq_classlike_name_lc]; foreach ($public_mapped_properties as $public_mapped_property) { $property_type = Type::parseString($public_mapped_property); /** @psalm-suppress UnusedMethodCall */ $property_type->queueClassLikesForScanning($this->codebase, null, $phantom_classes + [$fq_classlike_name_lc => \true]); } } } } public function scanFiles(\Psalm\Internal\Codebase\ClassLikes $classlikes, int $pool_size = 1) : bool { $has_changes = \false; while ($this->files_to_scan || $this->classes_to_scan) { if ($this->files_to_scan) { if ($this->scanFilePaths($pool_size)) { $has_changes = \true; } } else { $this->convertClassesToFilePaths($classlikes); } } return $has_changes; } private function shouldScan(string $file_path) : bool { return $this->file_provider->fileExists($file_path) && !$this->file_provider->isDirectory($file_path) && (!isset($this->scanned_files[$file_path]) || isset($this->files_to_deep_scan[$file_path]) && !$this->scanned_files[$file_path]); } private function scanFilePaths(int $pool_size) : bool { $files_to_scan = array_filter($this->files_to_scan, [$this, 'shouldScan']); $this->files_to_scan = []; if (!$files_to_scan) { return \false; } if (!$this->is_forked && $pool_size > 1 && count($files_to_scan) > 512) { $pool_size = ceil(min($pool_size, count($files_to_scan) / 256)); } else { $pool_size = 1; } if ($pool_size > 1) { $process_file_paths = []; $i = 0; foreach ($files_to_scan as $file_path) { $process_file_paths[$i % $pool_size][] = $file_path; ++$i; } $this->progress->debug('Forking process for scanning' . PHP_EOL); // Run scanning one file at a time, splitting the set of // files up among a given number of child processes. $pool = new Pool( $this->config, $process_file_paths, function () : void { $this->progress->debug('Initialising forked process for scanning' . PHP_EOL); $project_analyzer = ProjectAnalyzer::getInstance(); $codebase = $project_analyzer->getCodebase(); $statements_provider = $codebase->statements_provider; $codebase->scanner->isForked(); FileStorageProvider::deleteAll(); ClassLikeStorageProvider::deleteAll(); $statements_provider->resetDiffs(); $this->progress->debug('Have initialised forked process for scanning' . PHP_EOL); }, Closure::fromCallable([$this, 'scanAPath']), /** * @return PoolData */ function () { $this->progress->debug('Collecting data from forked scanner process' . PHP_EOL); $project_analyzer = ProjectAnalyzer::getInstance(); $codebase = $project_analyzer->getCodebase(); $statements_provider = $codebase->statements_provider; return ['classlikes_data' => $codebase->classlikes->getThreadData(), 'scanner_data' => $codebase->scanner->getThreadData(), 'issues' => IssueBuffer::getIssuesData(), 'changed_members' => $statements_provider->getChangedMembers(), 'unchanged_signature_members' => $statements_provider->getUnchangedSignatureMembers(), 'diff_map' => $statements_provider->getDiffMap(), 'deletion_ranges' => $statements_provider->getDeletionRanges(), 'errors' => $statements_provider->getErrors(), 'classlike_storage' => $codebase->classlike_storage_provider->getAll(), 'file_storage' => $codebase->file_storage_provider->getAll(), 'new_file_content_hashes' => $statements_provider->parser_cache_provider ? $statements_provider->parser_cache_provider->getNewFileContentHashes() : [], 'taint_data' => $codebase->taint_flow_graph]; } ); // Wait for all tasks to complete and collect the results. /** * @var array */ $forked_pool_data = $pool->wait(); foreach ($forked_pool_data as $pool_data) { IssueBuffer::addIssues($pool_data['issues']); $this->codebase->statements_provider->addChangedMembers($pool_data['changed_members']); $this->codebase->statements_provider->addUnchangedSignatureMembers($pool_data['unchanged_signature_members']); $this->codebase->statements_provider->addDiffMap($pool_data['diff_map']); $this->codebase->statements_provider->addDeletionRanges($pool_data['deletion_ranges']); $this->codebase->statements_provider->addErrors($pool_data['errors']); if ($this->codebase->taint_flow_graph && $pool_data['taint_data']) { $this->codebase->taint_flow_graph->addGraph($pool_data['taint_data']); } $this->codebase->file_storage_provider->addMore($pool_data['file_storage']); $this->codebase->classlike_storage_provider->addMore($pool_data['classlike_storage']); $this->codebase->classlikes->addThreadData($pool_data['classlikes_data']); $this->addThreadData($pool_data['scanner_data']); if ($this->codebase->statements_provider->parser_cache_provider) { $this->codebase->statements_provider->parser_cache_provider->addNewFileContentHashes($pool_data['new_file_content_hashes']); } } } else { $i = 0; foreach ($files_to_scan as $file_path => $_) { $this->scanAPath($i, $file_path); ++$i; } } if ($this->codebase->statements_provider->parser_cache_provider) { $this->codebase->statements_provider->parser_cache_provider->saveFileContentHashes(); } foreach ($files_to_scan as $scanned_file) { if ($this->config->hasStubFile($scanned_file)) { $file_storage = $this->file_storage_provider->get($scanned_file); foreach ($file_storage->functions as $function_storage) { if ($function_storage->cased_name && !$this->codebase->functions->hasStubbedFunction($function_storage->cased_name)) { $this->codebase->functions->addGlobalFunction($function_storage->cased_name, $function_storage); } } foreach ($file_storage->constants as $name => $type) { $this->codebase->addGlobalConstantType($name, $type); } } } $this->file_reference_provider->addClassLikeFiles($this->classlike_files); return \true; } private function convertClassesToFilePaths(\Psalm\Internal\Codebase\ClassLikes $classlikes) : void { $classes_to_scan = $this->classes_to_scan; $this->classes_to_scan = []; foreach ($classes_to_scan as $fq_classlike_name) { $fq_classlike_name_lc = strtolower($fq_classlike_name); if (isset($this->reflected_classlikes_lc[$fq_classlike_name_lc])) { continue; } if ($classlikes->isMissingClassLike($fq_classlike_name_lc)) { continue; } if (!isset($this->classlike_files[$fq_classlike_name_lc])) { if ($classlikes->doesClassLikeExist($fq_classlike_name_lc)) { if ($fq_classlike_name_lc === 'self') { continue; } $this->progress->debug('Using reflection to get metadata for ' . $fq_classlike_name . "\n"); /** @psalm-suppress ArgumentTypeCoercion */ $reflected_class = new ReflectionClass($fq_classlike_name); $this->reflection->registerClass($reflected_class); $this->reflected_classlikes_lc[$fq_classlike_name_lc] = \true; } elseif ($this->fileExistsForClassLike($classlikes, $fq_classlike_name)) { $fq_classlike_name_lc = strtolower($classlikes->getUnAliasedName($fq_classlike_name_lc)); // even though we've checked this above, calling the method invalidates it if (isset($this->classlike_files[$fq_classlike_name_lc])) { $file_path = $this->classlike_files[$fq_classlike_name_lc]; $this->files_to_scan[$file_path] = $file_path; if (isset($this->classes_to_deep_scan[$fq_classlike_name_lc])) { unset($this->classes_to_deep_scan[$fq_classlike_name_lc]); $this->files_to_deep_scan[$file_path] = $file_path; } } } elseif ($this->store_scan_failure[$fq_classlike_name]) { $classlikes->registerMissingClassLike($fq_classlike_name_lc); } } elseif (isset($this->classes_to_deep_scan[$fq_classlike_name_lc]) && !isset($this->deep_scanned_classlike_files[$fq_classlike_name_lc])) { $file_path = $this->classlike_files[$fq_classlike_name_lc]; $this->files_to_scan[$file_path] = $file_path; unset($this->classes_to_deep_scan[$fq_classlike_name_lc]); $this->files_to_deep_scan[$file_path] = $file_path; $this->deep_scanned_classlike_files[$fq_classlike_name_lc] = \true; } } } /** * @param array> $filetype_scanners */ private function scanFile(string $file_path, array $filetype_scanners, bool $will_analyze = \false) : void { $file_scanner = $this->getScannerForPath($file_path, $filetype_scanners, $will_analyze); if (isset($this->scanned_files[$file_path]) && (!$will_analyze || $this->scanned_files[$file_path])) { throw new UnexpectedValueException('Should not be rescanning ' . $file_path); } if (!$this->file_provider->fileExists($file_path) && $this->config->mustBeIgnored($file_path)) { // this should not happen, but might if the file was temporary return; } $file_contents = $this->file_provider->getContents($file_path); $from_cache = $this->file_storage_provider->has($file_path, $file_contents); if (!$from_cache) { $this->file_storage_provider->create($file_path); } $this->scanned_files[$file_path] = $will_analyze; $file_storage = $this->file_storage_provider->get($file_path); $file_scanner->scan($this->codebase, $file_storage, $from_cache, $this->progress); if (!$from_cache) { if (!$file_storage->has_visitor_issues && $this->file_storage_provider->cache) { $this->file_storage_provider->cache->writeToCache($file_storage, $file_contents); } } else { $this->codebase->statements_provider->setUnchangedFile($file_path); foreach ($file_storage->required_file_paths as $required_file_path) { if ($will_analyze) { $this->addFileToDeepScan($required_file_path); } else { $this->addFileToShallowScan($required_file_path); } } foreach ($file_storage->classlikes_in_file as $fq_classlike_name) { $this->codebase->exhumeClassLikeStorage($fq_classlike_name, $file_path); } foreach ($file_storage->required_classes as $fq_classlike_name) { $this->queueClassLikeForScanning($fq_classlike_name, $will_analyze, \false); } foreach ($file_storage->required_interfaces as $fq_classlike_name) { $this->queueClassLikeForScanning($fq_classlike_name, \false, \false); } foreach ($file_storage->referenced_classlikes as $fq_classlike_name) { $this->queueClassLikeForScanning($fq_classlike_name, \false, \false); } if ($this->codebase->register_autoload_files) { foreach ($file_storage->functions as $function_storage) { if ($function_storage->cased_name && !$this->codebase->functions->hasStubbedFunction($function_storage->cased_name)) { $this->codebase->functions->addGlobalFunction($function_storage->cased_name, $function_storage); } } foreach ($file_storage->constants as $name => $type) { $this->codebase->addGlobalConstantType($name, $type); } } foreach ($file_storage->classlike_aliases as $aliased_name => $unaliased_name) { $this->codebase->classlikes->addClassAlias($unaliased_name, $aliased_name); } } } /** * @param array> $filetype_scanners */ private function getScannerForPath(string $file_path, array $filetype_scanners, bool $will_analyze = \false) : FileScanner { $path_parts = explode(DIRECTORY_SEPARATOR, $file_path); $file_name_parts = explode('.', array_pop($path_parts)); $extension = count($file_name_parts) > 1 ? array_pop($file_name_parts) : null; $file_name = $this->config->shortenFileName($file_path); if (isset($filetype_scanners[$extension])) { return new $filetype_scanners[$extension]($file_path, $file_name, $will_analyze); } return new FileScanner($file_path, $file_name, $will_analyze); } /** * @return array */ public function getScannedFiles() : array { return $this->scanned_files; } /** * Checks whether a class exists, and if it does then records what file it's in * for later checking */ private function fileExistsForClassLike(\Psalm\Internal\Codebase\ClassLikes $classlikes, string $fq_class_name) : bool { $fq_class_name_lc = strtolower($fq_class_name); if (isset($this->classlike_files[$fq_class_name_lc])) { return \true; } if ($fq_class_name === 'self') { return \false; } $composer_file_path = $this->config->getComposerFilePathForClassLike($fq_class_name); if ($composer_file_path && file_exists($composer_file_path)) { $this->progress->debug('Using composer to locate file for ' . $fq_class_name . "\n"); $classlikes->addFullyQualifiedClassLikeName($fq_class_name_lc, realpath($composer_file_path)); return \true; } $reflected_class = ErrorHandler::runWithExceptionsSuppressed(function () use($fq_class_name) : ?ReflectionClass { $old_level = error_reporting(); $this->progress->setErrorReporting(); try { $this->progress->debug('Using reflection to locate file for ' . $fq_class_name . "\n"); /** @psalm-suppress ArgumentTypeCoercion */ return new ReflectionClass($fq_class_name); } catch (Throwable $e) { // do not cache any results here (as case-sensitive filenames can screw things up) return null; } finally { error_reporting($old_level); } }); if (null === $reflected_class) { return \false; } $file_path = (string) $reflected_class->getFileName(); // if the file was autoloaded but exists in evaled code only, return false if (!file_exists($file_path)) { return \false; } $new_fq_class_name = $reflected_class->getName(); $new_fq_class_name_lc = strtolower($new_fq_class_name); if ($new_fq_class_name_lc !== $fq_class_name_lc) { $classlikes->addClassAlias($new_fq_class_name, $fq_class_name); $fq_class_name_lc = $new_fq_class_name_lc; } $fq_class_name = $new_fq_class_name; $classlikes->addFullyQualifiedClassLikeName($fq_class_name_lc); if ($reflected_class->isInterface()) { $classlikes->addFullyQualifiedInterfaceName($fq_class_name, $file_path); } elseif ($reflected_class->isTrait()) { $classlikes->addFullyQualifiedTraitName($fq_class_name, $file_path); } else { $classlikes->addFullyQualifiedClassName($fq_class_name, $file_path); } return \true; } /** * @return ThreadData */ public function getThreadData() : array { return [$this->files_to_scan, $this->files_to_deep_scan, $this->classes_to_scan, $this->classes_to_deep_scan, $this->store_scan_failure, $this->classlike_files, $this->deep_scanned_classlike_files, $this->scanned_files, $this->reflected_classlikes_lc]; } /** * @param ThreadData $thread_data */ public function addThreadData(array $thread_data) : void { [$files_to_scan, $files_to_deep_scan, $classes_to_scan, $classes_to_deep_scan, $store_scan_failure, $classlike_files, $deep_scanned_classlike_files, $scanned_files, $reflected_classlikes_lc] = $thread_data; $this->files_to_scan = array_merge($files_to_scan, $this->files_to_scan); $this->files_to_deep_scan = array_merge($files_to_deep_scan, $this->files_to_deep_scan); $this->classes_to_scan = array_merge($classes_to_scan, $this->classes_to_scan); $this->classes_to_deep_scan = array_merge($classes_to_deep_scan, $this->classes_to_deep_scan); $this->store_scan_failure = array_merge($store_scan_failure, $this->store_scan_failure); $this->classlike_files = array_merge($classlike_files, $this->classlike_files); $this->deep_scanned_classlike_files = array_merge($deep_scanned_classlike_files, $this->deep_scanned_classlike_files); $this->scanned_files = array_merge($scanned_files, $this->scanned_files); $this->reflected_classlikes_lc = array_merge($reflected_classlikes_lc, $this->reflected_classlikes_lc); } public function isForked() : void { $this->is_forked = \true; } private function scanAPath(int $_, string $file_path) : void { $this->scanFile($file_path, $this->config->getFiletypeScanners(), isset($this->files_to_deep_scan[$file_path])); } } * * @psalm-type FileMapType = array{ * 0: TaggedCodeType, * 1: TaggedCodeType, * 2: array * } * * @psalm-type WorkerData = array{ * issues: array>, * fixable_issue_counts: array, * nonmethod_references_to_classes: array>, * method_references_to_classes: array>, * file_references_to_class_members: array>, * file_references_to_class_properties: array>, * file_references_to_method_returns: array>, * file_references_to_missing_class_members: array>, * mixed_counts: array, * mixed_member_names: array>, * function_timings: array, * file_manipulations: array, * method_references_to_class_members: array>, * method_dependencies: array>, * method_references_to_method_returns: array>, * method_references_to_class_properties: array>, * method_references_to_missing_class_members: array>, * method_param_uses: array>>, * analyzed_methods: array>, * file_maps: array, * class_locations: array>, * class_method_locations: array>, * class_property_locations: array>, * possible_method_param_types: array>, * taint_data: ?TaintFlowGraph, * unused_suppressions: array>, * used_suppressions: array>, * function_docblock_manipulators: array>, * mutable_classes: array, * } */ /** * @internal * * Called in the analysis phase of Psalm's execution */ final class Analyzer { private Config $config; private FileProvider $file_provider; private FileStorageProvider $file_storage_provider; private Progress $progress; /** * Used to store counts of mixed vs non-mixed variables * * @var array */ private array $mixed_counts = []; /** * Used to store member names of mixed property/method access * * @var array> */ private array $mixed_member_names = []; private bool $count_mixed = \true; /** * Used to store debug performance data * * @var array */ private array $function_timings = []; /** * We analyze more files than we necessarily report errors in * * @var array */ private array $files_to_analyze = []; /** * We can show analysis results on more files than we analyze * because the results can be cached * * @var array */ private array $files_with_analysis_results = []; /** * We may update fewer files than we analyse (i.e. for dead code detection) * * @var array|null */ private ?array $files_to_update = null; /** * @var array> */ private array $analyzed_methods = []; /** * @var array> */ private array $existing_issues = []; /** * @var array> */ private array $reference_map = []; /** * @var array> */ private array $type_map = []; /** * @var array> */ private array $argument_map = []; /** * @var array> */ public array $possible_method_param_types = []; /** * @var array */ public array $mutable_classes = []; public function __construct(Config $config, FileProvider $file_provider, FileStorageProvider $file_storage_provider, Progress $progress) { $this->config = $config; $this->file_provider = $file_provider; $this->file_storage_provider = $file_storage_provider; $this->progress = $progress; } /** * @param array $files_to_analyze */ public function addFilesToAnalyze(array $files_to_analyze) : void { $this->files_to_analyze += $files_to_analyze; $this->files_with_analysis_results += $files_to_analyze; } /** * @param array $files_to_analyze */ public function addFilesToShowResults(array $files_to_analyze) : void { $this->files_with_analysis_results += $files_to_analyze; } /** * @param array $files_to_update */ public function setFilesToUpdate(array $files_to_update) : void { $this->files_to_update = $files_to_update; } public function canReportIssues(string $file_path) : bool { return isset($this->files_with_analysis_results[$file_path]); } /** * @param array> $filetype_analyzers */ private function getFileAnalyzer(ProjectAnalyzer $project_analyzer, string $file_path, array $filetype_analyzers) : FileAnalyzer { $extension = pathinfo($file_path, PATHINFO_EXTENSION); $file_name = $this->config->shortenFileName($file_path); if (isset($filetype_analyzers[$extension])) { $file_analyzer = new $filetype_analyzers[$extension]($project_analyzer, $file_path, $file_name); } else { $file_analyzer = new FileAnalyzer($project_analyzer, $file_path, $file_name); } $this->progress->debug('Getting ' . $file_path . "\n"); return $file_analyzer; } public function analyzeFiles(ProjectAnalyzer $project_analyzer, int $pool_size, bool $alter_code, bool $consolidate_analyzed_data = \false) : void { $this->loadCachedResults($project_analyzer); $codebase = $project_analyzer->getCodebase(); if ($alter_code) { $project_analyzer->interpretRefactors(); } $this->files_to_analyze = array_filter($this->files_to_analyze, [$this->file_provider, 'fileExists']); $this->doAnalysis($project_analyzer, $pool_size); $scanned_files = $codebase->scanner->getScannedFiles(); if ($codebase->taint_flow_graph) { $codebase->taint_flow_graph->connectSinksAndSources(); } $this->progress->finish(); if ($consolidate_analyzed_data) { $project_analyzer->consolidateAnalyzedData(); } foreach (IssueBuffer::getIssuesData() as $file_path => $file_issues) { $codebase->file_reference_provider->clearExistingIssuesForFile($file_path); foreach ($file_issues as $issue_data) { $codebase->file_reference_provider->addIssue($file_path, $issue_data); } } $codebase->file_reference_provider->updateReferenceCache($codebase, $scanned_files); if ($codebase->track_unused_suppressions) { IssueBuffer::processUnusedSuppressions($codebase->file_provider); } $codebase->file_reference_provider->setAnalyzedMethods($this->analyzed_methods); $codebase->file_reference_provider->setFileMaps($this->getFileMaps()); $codebase->file_reference_provider->setTypeCoverage($this->mixed_counts); $codebase->file_reference_provider->updateReferenceCache($codebase, $scanned_files); if ($codebase->diff_methods) { $codebase->statements_provider->resetDiffs(); } if ($alter_code) { $this->progress->startAlteringFiles(); $project_analyzer->prepareMigration(); $files_to_update = $this->files_to_update ?? $this->files_to_analyze; foreach ($files_to_update as $file_path) { $this->updateFile($file_path, $project_analyzer->dry_run); } $project_analyzer->migrateCode(); } } private function doAnalysis(ProjectAnalyzer $project_analyzer, int $pool_size) : void { $this->progress->start(count($this->files_to_analyze)); ksort($this->files_to_analyze); $codebase = $project_analyzer->getCodebase(); $analysis_worker = Closure::fromCallable([$this, 'analysisWorker']); $task_done_closure = Closure::fromCallable([$this, 'taskDoneClosure']); if ($pool_size > 1 && count($this->files_to_analyze) > $pool_size) { $shuffle_count = $pool_size + 1; $file_paths = array_values($this->files_to_analyze); $count = count($file_paths); /** @var int<0, max> */ $middle = intdiv($count, $shuffle_count); $remainder = $count % $shuffle_count; $new_file_paths = []; for ($i = 0; $i < $shuffle_count; $i++) { for ($j = 0; $j < $middle; $j++) { if ($j * $shuffle_count + $i < $count) { $new_file_paths[] = $file_paths[$j * $shuffle_count + $i]; } } if ($remainder) { $new_file_paths[] = $file_paths[$middle * $shuffle_count + $remainder - 1]; $remainder--; } } $process_file_paths = []; $i = 0; foreach ($new_file_paths as $file_path) { $process_file_paths[$i % $pool_size][] = $file_path; ++$i; } // Run analysis one file at a time, splitting the set of // files up among a given number of child processes. $pool = new Pool($this->config, $process_file_paths, static function () : void { $project_analyzer = ProjectAnalyzer::getInstance(); $codebase = $project_analyzer->getCodebase(); $file_reference_provider = $codebase->file_reference_provider; if ($codebase->taint_flow_graph) { $codebase->taint_flow_graph = new \Psalm\Internal\Codebase\TaintFlowGraph(); } $file_reference_provider->setNonMethodReferencesToClasses([]); $file_reference_provider->setCallingMethodReferencesToClassMembers([]); $file_reference_provider->setCallingMethodReferencesToClassProperties([]); $file_reference_provider->setFileReferencesToClassMembers([]); $file_reference_provider->setFileReferencesToClassProperties([]); $file_reference_provider->setCallingMethodReferencesToMissingClassMembers([]); $file_reference_provider->setFileReferencesToMissingClassMembers([]); $file_reference_provider->setReferencesToMixedMemberNames([]); $file_reference_provider->setMethodParamUses([]); }, $analysis_worker, Closure::fromCallable([$this, 'getWorkerData']), $task_done_closure); $this->progress->debug('Forking analysis' . "\n"); // Wait for all tasks to complete and collect the results. /** * @var array */ $forked_pool_data = $pool->wait(); $this->progress->debug('Collecting forked analysis results' . "\n"); foreach ($forked_pool_data as $pool_data) { IssueBuffer::addIssues($pool_data['issues']); IssueBuffer::addFixableIssues($pool_data['fixable_issue_counts']); if ($codebase->track_unused_suppressions) { IssueBuffer::addUnusedSuppressions($pool_data['unused_suppressions']); IssueBuffer::addUsedSuppressions($pool_data['used_suppressions']); } if ($codebase->taint_flow_graph && $pool_data['taint_data']) { $codebase->taint_flow_graph->addGraph($pool_data['taint_data']); } $codebase->file_reference_provider->addNonMethodReferencesToClasses($pool_data['nonmethod_references_to_classes']); $codebase->file_reference_provider->addMethodReferencesToClasses($pool_data['method_references_to_classes']); $codebase->file_reference_provider->addFileReferencesToClassMembers($pool_data['file_references_to_class_members']); $codebase->file_reference_provider->addFileReferencesToClassProperties($pool_data['file_references_to_class_properties']); $codebase->file_reference_provider->addFileReferencesToMethodReturns($pool_data['file_references_to_method_returns']); $codebase->file_reference_provider->addMethodReferencesToClassMembers($pool_data['method_references_to_class_members']); $codebase->file_reference_provider->addMethodDependencies($pool_data['method_dependencies']); $codebase->file_reference_provider->addMethodReferencesToClassProperties($pool_data['method_references_to_class_properties']); $codebase->file_reference_provider->addMethodReferencesToMethodReturns($pool_data['method_references_to_method_returns']); $codebase->file_reference_provider->addFileReferencesToMissingClassMembers($pool_data['file_references_to_missing_class_members']); $codebase->file_reference_provider->addMethodReferencesToMissingClassMembers($pool_data['method_references_to_missing_class_members']); $codebase->file_reference_provider->addMethodParamUses($pool_data['method_param_uses']); $this->addMixedMemberNames($pool_data['mixed_member_names']); $this->function_timings += $pool_data['function_timings']; $codebase->file_reference_provider->addClassLocations($pool_data['class_locations']); $codebase->file_reference_provider->addClassMethodLocations($pool_data['class_method_locations']); $codebase->file_reference_provider->addClassPropertyLocations($pool_data['class_property_locations']); $this->mutable_classes = array_merge($this->mutable_classes, $pool_data['mutable_classes']); FunctionDocblockManipulator::addManipulators($pool_data['function_docblock_manipulators']); $this->analyzed_methods = array_merge($pool_data['analyzed_methods'], $this->analyzed_methods); foreach ($pool_data['mixed_counts'] as $file_path => [$mixed_count, $nonmixed_count]) { if (!isset($this->mixed_counts[$file_path])) { $this->mixed_counts[$file_path] = [$mixed_count, $nonmixed_count]; } else { $this->mixed_counts[$file_path][0] += $mixed_count; $this->mixed_counts[$file_path][1] += $nonmixed_count; } } foreach ($pool_data['possible_method_param_types'] as $declaring_method_id => $possible_param_types) { if (!isset($this->possible_method_param_types[$declaring_method_id])) { $this->possible_method_param_types[$declaring_method_id] = $possible_param_types; } else { foreach ($possible_param_types as $offset => $possible_param_type) { $this->possible_method_param_types[$declaring_method_id][$offset] = Type::combineUnionTypes($this->possible_method_param_types[$declaring_method_id][$offset] ?? null, $possible_param_type, $codebase); } } } foreach ($pool_data['file_manipulations'] as $file_path => $manipulations) { FileManipulationBuffer::add($file_path, $manipulations); } foreach ($pool_data['file_maps'] as $file_path => $file_maps) { [$reference_map, $type_map, $argument_map] = $file_maps; $this->reference_map[$file_path] = $reference_map; $this->type_map[$file_path] = $type_map; $this->argument_map[$file_path] = $argument_map; } } } else { $i = 0; foreach ($this->files_to_analyze as $file_path => $_) { $analysis_worker($i, $file_path); ++$i; $issues = IssueBuffer::getIssuesDataForFile($file_path); $task_done_closure($issues); } } } /** * @psalm-suppress ComplexMethod */ public function loadCachedResults(ProjectAnalyzer $project_analyzer) : void { $codebase = $project_analyzer->getCodebase(); if ($codebase->diff_methods) { $this->analyzed_methods = $codebase->file_reference_provider->getAnalyzedMethods(); $this->existing_issues = $codebase->file_reference_provider->getExistingIssues(); $file_maps = $codebase->file_reference_provider->getFileMaps(); foreach ($file_maps as $file_path => [$reference_map, $type_map, $argument_map]) { $this->reference_map[$file_path] = $reference_map; $this->type_map[$file_path] = $type_map; $this->argument_map[$file_path] = $argument_map; } } $statements_provider = $codebase->statements_provider; $file_reference_provider = $codebase->file_reference_provider; $changed_members = $statements_provider->getChangedMembers(); $unchanged_signature_members = $statements_provider->getUnchangedSignatureMembers(); $errored_files = $statements_provider->getErrors(); $diff_map = $statements_provider->getDiffMap(); $deletion_ranges = $statements_provider->getDeletionRanges(); $method_references_to_class_members = $file_reference_provider->getAllMethodReferencesToClassMembers(); $method_dependencies = $file_reference_provider->getAllMethodDependencies(); $method_references_to_class_properties = $file_reference_provider->getAllMethodReferencesToClassProperties(); $method_references_to_method_returns = $file_reference_provider->getAllMethodReferencesToMethodReturns(); $method_references_to_missing_class_members = $file_reference_provider->getAllMethodReferencesToMissingClassMembers(); $all_referencing_methods = $method_references_to_class_members + $method_references_to_missing_class_members + $method_dependencies; $nonmethod_references_to_classes = $file_reference_provider->getAllNonMethodReferencesToClasses(); $method_references_to_classes = $file_reference_provider->getAllMethodReferencesToClasses(); $method_param_uses = $file_reference_provider->getAllMethodParamUses(); $file_references_to_class_members = $file_reference_provider->getAllFileReferencesToClassMembers(); $file_references_to_class_properties = $file_reference_provider->getAllFileReferencesToClassProperties(); $file_references_to_method_returns = $file_reference_provider->getAllFileReferencesToMethodReturns(); $file_references_to_missing_class_members = $file_reference_provider->getAllFileReferencesToMissingClassMembers(); $references_to_mixed_member_names = $file_reference_provider->getAllReferencesToMixedMemberNames(); $this->mixed_counts = $file_reference_provider->getTypeCoverage(); foreach ($changed_members as $file_path => $members_by_file) { foreach ($members_by_file as $changed_member => $_) { if (!strpos($changed_member, '&')) { continue; } [$base_class, $trait] = explode('&', $changed_member); foreach ($all_referencing_methods as $member_id => $_) { if (strpos($member_id, $base_class . '::') !== 0) { continue; } $member_bit = substr($member_id, strlen($base_class) + 2); if (isset($all_referencing_methods[$trait . '::' . $member_bit])) { $changed_members[$file_path][$member_id] = \true; } } } } $newly_invalidated_methods = []; foreach ($unchanged_signature_members as $file_unchanged_signature_members) { $newly_invalidated_methods = array_merge($newly_invalidated_methods, $file_unchanged_signature_members); foreach ($file_unchanged_signature_members as $unchanged_signature_member_id => $_) { // also check for things that might invalidate constructor property initialisation if (isset($all_referencing_methods[$unchanged_signature_member_id])) { foreach ($all_referencing_methods[$unchanged_signature_member_id] as $referencing_method_id => $_) { if (substr($referencing_method_id, -13) === '::__construct') { $referencing_base_classlike = explode('::', $referencing_method_id)[0]; $unchanged_signature_classlike = explode('::', $unchanged_signature_member_id)[0]; if ($referencing_base_classlike === $unchanged_signature_classlike) { $newly_invalidated_methods[$referencing_method_id] = \true; } else { try { $referencing_storage = $codebase->classlike_storage_provider->get($referencing_base_classlike); } catch (InvalidArgumentException $_) { // Workaround for #3671 $newly_invalidated_methods[$referencing_method_id] = \true; $referencing_storage = null; } if (isset($referencing_storage->used_traits[$unchanged_signature_classlike]) || isset($referencing_storage->parent_classes[$unchanged_signature_classlike])) { $newly_invalidated_methods[$referencing_method_id] = \true; } } } } } } } foreach ($changed_members as $file_changed_members) { foreach ($file_changed_members as $member_id => $_) { $newly_invalidated_methods[$member_id] = \true; if (isset($all_referencing_methods[$member_id])) { $newly_invalidated_methods = array_merge($all_referencing_methods[$member_id], $newly_invalidated_methods); } unset($method_references_to_class_members[$member_id], $method_dependencies[$member_id], $method_references_to_class_properties[$member_id], $method_references_to_method_returns[$member_id], $file_references_to_class_members[$member_id], $file_references_to_class_properties[$member_id], $file_references_to_method_returns[$member_id], $method_references_to_missing_class_members[$member_id], $file_references_to_missing_class_members[$member_id], $references_to_mixed_member_names[$member_id], $method_param_uses[$member_id]); $member_stub = preg_replace('/::.*$/', '::*', $member_id, 1); if (isset($all_referencing_methods[$member_stub])) { $newly_invalidated_methods = array_merge($all_referencing_methods[$member_stub], $newly_invalidated_methods); } } } // This could be optimized by storing method references to files foreach ($file_reference_provider->getDeletedReferencedFiles() as $deleted_file) { foreach ($file_reference_provider->getFilesReferencingFile($deleted_file) as $file_referencing_deleted) { $methods_referencing_deleted = $this->analyzed_methods[$file_referencing_deleted] ?? []; foreach ($methods_referencing_deleted as $method_referencing_deleted => $_) { $newly_invalidated_methods[$method_referencing_deleted] = \true; } } } foreach ($newly_invalidated_methods as $method_id => $_) { foreach ($method_references_to_class_members as $i => $_) { unset($method_references_to_class_members[$i][$method_id]); } foreach ($method_dependencies as $i => $_) { unset($method_dependencies[$i][$method_id]); } foreach ($method_references_to_class_properties as $i => $_) { unset($method_references_to_class_properties[$i][$method_id]); } foreach ($method_references_to_method_returns as $i => $_) { unset($method_references_to_method_returns[$i][$method_id]); } foreach ($method_references_to_classes as $i => $_) { unset($method_references_to_classes[$i][$method_id]); } foreach ($method_references_to_missing_class_members as $i => $_) { unset($method_references_to_missing_class_members[$i][$method_id]); } foreach ($references_to_mixed_member_names as $i => $_) { unset($references_to_mixed_member_names[$i][$method_id]); } foreach ($method_param_uses as $i => $_) { foreach ($method_param_uses[$i] as $j => $_) { unset($method_param_uses[$i][$j][$method_id]); } } } foreach ($errored_files as $file_path => $_) { unset($this->analyzed_methods[$file_path]); unset($this->existing_issues[$file_path]); } foreach ($this->analyzed_methods as $file_path => $analyzed_methods) { foreach ($analyzed_methods as $correct_method_id => $_) { $trait_safe_method_id = $correct_method_id; $correct_method_ids = explode('&', $correct_method_id); $correct_method_id = $correct_method_ids[0]; if (isset($newly_invalidated_methods[$correct_method_id]) || isset($correct_method_ids[1]) && isset($newly_invalidated_methods[$correct_method_ids[1]])) { unset($this->analyzed_methods[$file_path][$trait_safe_method_id]); } } } $this->shiftFileOffsets($diff_map, $deletion_ranges); foreach ($this->files_to_analyze as $file_path) { $file_reference_provider->clearExistingIssuesForFile($file_path); $file_reference_provider->clearExistingFileMapsForFile($file_path); $this->setMixedCountsForFile($file_path, [0, 0]); foreach ($file_references_to_class_members as $i => $_) { unset($file_references_to_class_members[$i][$file_path]); } foreach ($file_references_to_class_properties as $i => $_) { unset($file_references_to_class_properties[$i][$file_path]); } foreach ($file_references_to_method_returns as $i => $_) { unset($file_references_to_method_returns[$i][$file_path]); } foreach ($nonmethod_references_to_classes as $i => $_) { unset($nonmethod_references_to_classes[$i][$file_path]); } foreach ($references_to_mixed_member_names as $i => $_) { unset($references_to_mixed_member_names[$i][$file_path]); } foreach ($file_references_to_missing_class_members as $i => $_) { unset($file_references_to_missing_class_members[$i][$file_path]); } } foreach ($this->existing_issues as $file_path => $issues) { if (!isset($this->files_to_analyze[$file_path])) { unset($this->existing_issues[$file_path]); if ($this->file_provider->fileExists($file_path)) { IssueBuffer::addIssues([$file_path => array_values($issues)]); } } } $method_references_to_class_members = array_filter($method_references_to_class_members); $method_dependencies = array_filter($method_dependencies); $method_references_to_class_properties = array_filter($method_references_to_class_properties); $method_references_to_method_returns = array_filter($method_references_to_method_returns); $method_references_to_missing_class_members = array_filter($method_references_to_missing_class_members); $file_references_to_class_members = array_filter($file_references_to_class_members); $file_references_to_class_properties = array_filter($file_references_to_class_properties); $file_references_to_method_returns = array_filter($file_references_to_method_returns); $file_references_to_missing_class_members = array_filter($file_references_to_missing_class_members); $references_to_mixed_member_names = array_filter($references_to_mixed_member_names); $nonmethod_references_to_classes = array_filter($nonmethod_references_to_classes); $method_references_to_classes = array_filter($method_references_to_classes); $method_param_uses = array_filter($method_param_uses); $file_reference_provider->setCallingMethodReferencesToClassMembers($method_references_to_class_members); $file_reference_provider->setMethodDependencies($method_dependencies); $file_reference_provider->setCallingMethodReferencesToClassProperties($method_references_to_class_properties); $file_reference_provider->setCallingMethodReferencesToMethodReturns($method_references_to_method_returns); $file_reference_provider->setFileReferencesToClassMembers($file_references_to_class_members); $file_reference_provider->setFileReferencesToClassProperties($file_references_to_class_properties); $file_reference_provider->setFileReferencesToMethodReturns($file_references_to_method_returns); $file_reference_provider->setCallingMethodReferencesToMissingClassMembers($method_references_to_missing_class_members); $file_reference_provider->setFileReferencesToMissingClassMembers($file_references_to_missing_class_members); $file_reference_provider->setReferencesToMixedMemberNames($references_to_mixed_member_names); $file_reference_provider->setCallingMethodReferencesToClasses($method_references_to_classes); $file_reference_provider->setNonMethodReferencesToClasses($nonmethod_references_to_classes); $file_reference_provider->setMethodParamUses($method_param_uses); } /** * @param array> $diff_map * @param array> $deletion_ranges */ public function shiftFileOffsets(array $diff_map, array $deletion_ranges) : void { foreach ($this->existing_issues as $file_path => $file_issues) { if (!isset($this->analyzed_methods[$file_path])) { continue; } $file_diff_map = $diff_map[$file_path] ?? []; $file_deletion_ranges = $deletion_ranges[$file_path] ?? []; if ($file_deletion_ranges) { foreach ($file_issues as $i => $issue_data) { foreach ($file_deletion_ranges as [$from, $to]) { if ($issue_data->from >= $from && $issue_data->from <= $to) { unset($this->existing_issues[$file_path][$i]); break; } } } } if ($file_diff_map) { foreach ($file_issues as $issue_data) { foreach ($file_diff_map as [$from, $to, $file_offset, $line_offset]) { if ($issue_data->from >= $from && $issue_data->from <= $to) { $issue_data->from += $file_offset; $issue_data->to += $file_offset; $issue_data->snippet_from += $file_offset; $issue_data->snippet_to += $file_offset; $issue_data->line_from += $line_offset; $issue_data->line_to += $line_offset; break; } } } } } foreach ($this->reference_map as $file_path => $reference_map) { if (!isset($this->analyzed_methods[$file_path])) { unset($this->reference_map[$file_path]); continue; } $file_diff_map = $diff_map[$file_path] ?? []; $file_deletion_ranges = $deletion_ranges[$file_path] ?? []; if ($file_deletion_ranges) { foreach ($reference_map as $reference_from => $_) { foreach ($file_deletion_ranges as [$from, $to]) { if ($reference_from >= $from && $reference_from <= $to) { unset($this->reference_map[$file_path][$reference_from]); break; } } } } if ($file_diff_map) { foreach ($reference_map as $reference_from => [$reference_to, $tag]) { foreach ($file_diff_map as [$from, $to, $file_offset]) { if ($reference_from >= $from && $reference_from <= $to) { unset($this->reference_map[$file_path][$reference_from]); $this->reference_map[$file_path][$reference_from + $file_offset] = [$reference_to + $file_offset, $tag]; break; } } } } } foreach ($this->type_map as $file_path => $type_map) { if (!isset($this->analyzed_methods[$file_path])) { unset($this->type_map[$file_path]); continue; } $file_diff_map = $diff_map[$file_path] ?? []; $file_deletion_ranges = $deletion_ranges[$file_path] ?? []; if ($file_deletion_ranges) { foreach ($type_map as $type_from => $_) { foreach ($file_deletion_ranges as [$from, $to]) { if ($type_from >= $from && $type_from <= $to) { unset($this->type_map[$file_path][$type_from]); break; } } } } if ($file_diff_map) { foreach ($type_map as $type_from => [$type_to, $tag]) { foreach ($file_diff_map as [$from, $to, $file_offset]) { if ($type_from >= $from && $type_from <= $to) { unset($this->type_map[$file_path][$type_from]); $this->type_map[$file_path][$type_from + $file_offset] = [$type_to + $file_offset, $tag]; break; } } } } } foreach ($this->argument_map as $file_path => $argument_map) { if (!isset($this->analyzed_methods[$file_path])) { unset($this->argument_map[$file_path]); continue; } $file_diff_map = $diff_map[$file_path] ?? []; $file_deletion_ranges = $deletion_ranges[$file_path] ?? []; if ($file_deletion_ranges) { foreach ($argument_map as $argument_from => $_) { foreach ($file_deletion_ranges as [$from, $to]) { if ($argument_from >= $from && $argument_from <= $to) { unset($argument_map[$argument_from]); break; } } } } if ($file_diff_map) { foreach ($argument_map as $argument_from => [$argument_to, $method_id, $argument_number]) { foreach ($file_diff_map as [$from, $to, $file_offset]) { if ($argument_from >= $from && $argument_from <= $to) { unset($this->argument_map[$file_path][$argument_from]); $this->argument_map[$file_path][$argument_from + $file_offset] = [$argument_to + $file_offset, $method_id, $argument_number]; break; } } } } } } /** * @return array> */ public function getMixedMemberNames() : array { return $this->mixed_member_names; } public function addMixedMemberName(string $member_id, string $reference) : void { $this->mixed_member_names[$member_id][$reference] = \true; } public function hasMixedMemberName(string $member_id) : bool { return isset($this->mixed_member_names[$member_id]); } /** * @param array> $names */ public function addMixedMemberNames(array $names) : void { foreach ($names as $key => $name) { if (isset($this->mixed_member_names[$key])) { $this->mixed_member_names[$key] = array_merge($this->mixed_member_names[$key], $name); } else { $this->mixed_member_names[$key] = $name; } } } /** * @return list{int, int} */ public function getMixedCountsForFile(string $file_path) : array { if (!isset($this->mixed_counts[$file_path])) { $this->mixed_counts[$file_path] = [0, 0]; } return $this->mixed_counts[$file_path]; } /** * @param list{int, int} $mixed_counts */ public function setMixedCountsForFile(string $file_path, array $mixed_counts) : void { $this->mixed_counts[$file_path] = $mixed_counts; } public function incrementMixedCount(string $file_path) : void { if (!$this->count_mixed) { return; } if (!isset($this->mixed_counts[$file_path])) { $this->mixed_counts[$file_path] = [0, 0]; } ++$this->mixed_counts[$file_path][0]; } public function decrementMixedCount(string $file_path) : void { if (!$this->count_mixed) { return; } if (!isset($this->mixed_counts[$file_path])) { return; } if ($this->mixed_counts[$file_path][0] === 0) { return; } --$this->mixed_counts[$file_path][0]; } public function incrementNonMixedCount(string $file_path) : void { if (!$this->count_mixed) { return; } if (!isset($this->mixed_counts[$file_path])) { $this->mixed_counts[$file_path] = [0, 0]; } ++$this->mixed_counts[$file_path][1]; } /** * @return array */ public function getMixedCounts() : array { $all_deep_scanned_files = []; foreach ($this->files_to_analyze as $file_path => $_) { $all_deep_scanned_files[$file_path] = \true; } return array_intersect_key($this->mixed_counts, $all_deep_scanned_files); } /** * @return array */ public function getFunctionTimings() : array { return $this->function_timings; } public function addFunctionTiming(string $function_id, float $time_per_node) : void { $this->function_timings[$function_id] = $time_per_node; } public function addNodeType(string $file_path, PhpParser\Node $node, string $node_type, ?PhpParser\Node $parent_node = null) : void { if ($node_type === '') { throw new UnexpectedValueException('non-empty node_type expected'); } $this->type_map[$file_path][(int) $node->getAttribute('startFilePos')] = [($parent_node ? (int) $parent_node->getAttribute('endFilePos') : (int) $node->getAttribute('endFilePos')) + 1, $node_type]; } public function addNodeArgument(string $file_path, int $start_position, int $end_position, string $reference, int $argument_number) : void { if ($reference === '') { throw new UnexpectedValueException('non-empty reference expected'); } $this->argument_map[$file_path][$start_position] = [$end_position, $reference, $argument_number]; } /** * @param string $reference The symbol name for the reference. * Prepend with an asterisk (*) to signify a reference that doesn't exist. */ public function addNodeReference(string $file_path, PhpParser\Node $node, string $reference) : void { if (!$reference) { throw new UnexpectedValueException('non-empty node_type expected'); } $this->reference_map[$file_path][(int) $node->getAttribute('startFilePos')] = [(int) $node->getAttribute('endFilePos') + 1, $reference]; } public function addOffsetReference(string $file_path, int $start, int $end, string $reference) : void { if (!$reference) { throw new UnexpectedValueException('non-empty node_type expected'); } $this->reference_map[$file_path][$start] = [$end, $reference]; } /** * @return array{int, int} */ public function getTotalTypeCoverage(Codebase $codebase) : array { $mixed_count = 0; $nonmixed_count = 0; foreach ($codebase->file_reference_provider->getTypeCoverage() as $file_path => $counts) { if (!$this->config->reportTypeStatsForFile($file_path)) { continue; } [$path_mixed_count, $path_nonmixed_count] = $counts; if (isset($this->mixed_counts[$file_path])) { $mixed_count += $path_mixed_count; $nonmixed_count += $path_nonmixed_count; } } return [$mixed_count, $nonmixed_count]; } public function getTypeInferenceSummary(Codebase $codebase) : string { $all_deep_scanned_files = []; foreach ($this->files_to_analyze as $file_path => $_) { $all_deep_scanned_files[$file_path] = \true; foreach ($this->file_storage_provider->get($file_path)->required_file_paths as $required_file_path) { $all_deep_scanned_files[$required_file_path] = \true; } } [$mixed_count, $nonmixed_count] = $this->getTotalTypeCoverage($codebase); $total = $mixed_count + $nonmixed_count; $total_files = count($all_deep_scanned_files); $lines = []; if (!$total_files) { $lines[] = 'No files analyzed'; } if (!$total) { $lines[] = 'Psalm was unable to infer types in the codebase'; } else { $percentage = $nonmixed_count === $total ? '100' : number_format(100 * $nonmixed_count / $total, 4); $lines[] = 'Psalm was able to infer types for ' . $percentage . '%' . ' of the codebase'; } return implode("\n", $lines); } public function getNonMixedStats() : string { $stats = ''; $all_deep_scanned_files = []; foreach ($this->files_to_analyze as $file_path => $_) { $all_deep_scanned_files[$file_path] = \true; if (!$this->config->reportTypeStatsForFile($file_path)) { continue; } foreach ($this->file_storage_provider->get($file_path)->required_file_paths as $required_file_path) { $all_deep_scanned_files[$required_file_path] = \true; } } foreach ($all_deep_scanned_files as $file_path => $_) { if (isset($this->mixed_counts[$file_path])) { [$path_mixed_count, $path_nonmixed_count] = $this->mixed_counts[$file_path]; if ($path_mixed_count + $path_nonmixed_count) { $stats .= number_format(100 * $path_nonmixed_count / ($path_mixed_count + $path_nonmixed_count), 3) . '% ' . $this->config->shortenFileName($file_path) . ' (' . $path_mixed_count . ' mixed)' . "\n"; } } } return $stats; } public function disableMixedCounts() : void { $this->count_mixed = \false; } public function enableMixedCounts() : void { $this->count_mixed = \true; } public function updateFile(string $file_path, bool $dry_run) : void { FileManipulationBuffer::add($file_path, FunctionDocblockManipulator::getManipulationsForFile($file_path)); FileManipulationBuffer::add($file_path, PropertyDocblockManipulator::getManipulationsForFile($file_path)); FileManipulationBuffer::add($file_path, ClassDocblockManipulator::getManipulationsForFile($file_path)); $file_manipulations = FileManipulationBuffer::getManipulationsForFile($file_path); if (!$file_manipulations) { return; } usort($file_manipulations, static function (FileManipulation $a, FileManipulation $b) : int { if ($b->end === $a->end) { if ($a->start === $b->start) { return $b->insertion_text > $a->insertion_text ? 1 : -1; } return $b->start > $a->start ? 1 : -1; } return $b->end > $a->end ? 1 : -1; }); $last_start = PHP_INT_MAX; $existing_contents = $this->file_provider->getContents($file_path); foreach ($file_manipulations as $manipulation) { if ($manipulation->start <= $last_start) { $existing_contents = $manipulation->transform($existing_contents); $last_start = $manipulation->start; } } if ($dry_run) { echo $file_path . ':' . "\n"; $differ = new Differ(new StrictUnifiedDiffOutputBuilder(['fromFile' => $file_path, 'toFile' => $file_path])); echo $differ->diff($this->file_provider->getContents($file_path), $existing_contents); return; } $this->progress->alterFileDone($file_path); $this->file_provider->setContents($file_path, $existing_contents); } /** * @return list */ public function getExistingIssuesForFile(string $file_path, int $start, int $end, ?string $issue_type = null) : array { if (!isset($this->existing_issues[$file_path])) { return []; } $applicable_issues = []; foreach ($this->existing_issues[$file_path] as $issue_data) { if ($issue_data->from >= $start && $issue_data->from <= $end) { if ($issue_type === null || $issue_type === $issue_data->type) { $applicable_issues[] = $issue_data; } } } return $applicable_issues; } public function removeExistingDataForFile(string $file_path, int $start, int $end, ?string $issue_type = null) : void { if (isset($this->existing_issues[$file_path])) { foreach ($this->existing_issues[$file_path] as $i => $issue_data) { if ($issue_data->from >= $start && $issue_data->from <= $end) { if ($issue_type === null || $issue_type === $issue_data->type) { unset($this->existing_issues[$file_path][$i]); } } } } if (isset($this->type_map[$file_path])) { foreach ($this->type_map[$file_path] as $map_start => $_) { if ($map_start >= $start && $map_start <= $end) { unset($this->type_map[$file_path][$map_start]); } } } if (isset($this->reference_map[$file_path])) { foreach ($this->reference_map[$file_path] as $map_start => $_) { if ($map_start >= $start && $map_start <= $end) { unset($this->reference_map[$file_path][$map_start]); } } } if (isset($this->argument_map[$file_path])) { foreach ($this->argument_map[$file_path] as $map_start => $_) { if ($map_start >= $start && $map_start <= $end) { unset($this->argument_map[$file_path][$map_start]); } } } } /** * @return array> */ public function getAnalyzedMethods() : array { return $this->analyzed_methods; } /** * @return array */ public function getFileMaps() : array { $file_maps = []; foreach ($this->reference_map as $file_path => $reference_map) { $file_maps[$file_path] = [$reference_map, [], []]; } foreach ($this->type_map as $file_path => $type_map) { if (isset($file_maps[$file_path])) { $file_maps[$file_path][1] = $type_map; } else { $file_maps[$file_path] = [[], $type_map, []]; } } foreach ($this->argument_map as $file_path => $argument_map) { if (isset($file_maps[$file_path])) { $file_maps[$file_path][2] = $argument_map; } else { $file_maps[$file_path] = [[], [], $argument_map]; } } return $file_maps; } /** * @return FileMapType */ public function getMapsForFile(string $file_path) : array { return [$this->reference_map[$file_path] ?? [], $this->type_map[$file_path] ?? [], $this->argument_map[$file_path] ?? []]; } /** * @return array> */ public function getPossibleMethodParamTypes() : array { return $this->possible_method_param_types; } public function addMutableClass(string $fqcln) : void { $this->mutable_classes[strtolower($fqcln)] = \true; } public function setAnalyzedMethod(string $file_path, string $method_id, bool $is_constructor = \false) : void { $this->analyzed_methods[$file_path][$method_id] = $is_constructor ? 2 : 1; } public function isMethodAlreadyAnalyzed(string $file_path, string $method_id, bool $is_constructor = \false) : bool { if ($is_constructor) { return isset($this->analyzed_methods[$file_path][$method_id]) && $this->analyzed_methods[$file_path][$method_id] === 2; } return isset($this->analyzed_methods[$file_path][$method_id]); } /** * @param list $issues */ private function taskDoneClosure(array $issues) : void { $has_error = \false; $has_info = \false; foreach ($issues as $issue) { switch ($issue->severity) { case IssueData::SEVERITY_INFO: $has_info = \true; break; default: $has_error = \true; break; } } $this->progress->taskDone($has_error ? 2 : ($has_info ? 1 : 0)); } /** * @return list */ private function analysisWorker(int $_, string $file_path) : array { $file_analyzer = $this->getFileAnalyzer(ProjectAnalyzer::getInstance(), $file_path, $this->config->getFiletypeAnalyzers()); $this->progress->debug('Analyzing ' . $file_analyzer->getFilePath() . "\n"); $file_analyzer->analyze(); $file_analyzer->context = null; $file_analyzer->clearSourceBeforeDestruction(); unset($file_analyzer); return IssueBuffer::getIssuesDataForFile($file_path); } /** @return WorkerData */ private function getWorkerData() : array { $project_analyzer = ProjectAnalyzer::getInstance(); $codebase = $project_analyzer->getCodebase(); $analyzer = $codebase->analyzer; $file_reference_provider = $codebase->file_reference_provider; $this->progress->debug('Gathering data for forked process' . "\n"); // @codingStandardsIgnoreStart return ['issues' => IssueBuffer::getIssuesData(), 'fixable_issue_counts' => IssueBuffer::getFixableIssues(), 'nonmethod_references_to_classes' => $file_reference_provider->getAllNonMethodReferencesToClasses(), 'method_references_to_classes' => $file_reference_provider->getAllMethodReferencesToClasses(), 'file_references_to_class_members' => $file_reference_provider->getAllFileReferencesToClassMembers(), 'method_references_to_class_members' => $file_reference_provider->getAllMethodReferencesToClassMembers(), 'method_dependencies' => $file_reference_provider->getAllMethodDependencies(), 'file_references_to_class_properties' => $file_reference_provider->getAllFileReferencesToClassProperties(), 'file_references_to_method_returns' => $file_reference_provider->getAllFileReferencesToMethodReturns(), 'method_references_to_class_properties' => $file_reference_provider->getAllMethodReferencesToClassProperties(), 'method_references_to_method_returns' => $file_reference_provider->getAllMethodReferencesToMethodReturns(), 'file_references_to_missing_class_members' => $file_reference_provider->getAllFileReferencesToMissingClassMembers(), 'method_references_to_missing_class_members' => $file_reference_provider->getAllMethodReferencesToMissingClassMembers(), 'method_param_uses' => $file_reference_provider->getAllMethodParamUses(), 'mixed_member_names' => $analyzer->getMixedMemberNames(), 'file_manipulations' => FileManipulationBuffer::getAll(), 'mixed_counts' => $analyzer->getMixedCounts(), 'function_timings' => $analyzer->getFunctionTimings(), 'analyzed_methods' => $analyzer->getAnalyzedMethods(), 'file_maps' => $analyzer->getFileMaps(), 'class_locations' => $file_reference_provider->getAllClassLocations(), 'class_method_locations' => $file_reference_provider->getAllClassMethodLocations(), 'class_property_locations' => $file_reference_provider->getAllClassPropertyLocations(), 'possible_method_param_types' => $analyzer->getPossibleMethodParamTypes(), 'taint_data' => $codebase->taint_flow_graph, 'unused_suppressions' => $codebase->track_unused_suppressions ? IssueBuffer::getUnusedSuppressions() : [], 'used_suppressions' => $codebase->track_unused_suppressions ? IssueBuffer::getUsedSuppressions() : [], 'function_docblock_manipulators' => FunctionDocblockManipulator::getManipulators(), 'mutable_classes' => $codebase->analyzer->mutable_classes]; // @codingStandardsIgnoreEnd } } classlike_storage_provider = $storage_provider; $this->file_reference_provider = $file_reference_provider; $this->classlikes = $classlikes; $this->return_type_provider = new MethodReturnTypeProvider(); $this->existence_provider = new MethodExistenceProvider(); $this->visibility_provider = new MethodVisibilityProvider(); $this->params_provider = new MethodParamsProvider(); } /** * Whether or not a given method exists * * If you pass true in $is_used argument the method return is considered used * * @param lowercase-string|null $calling_method_id */ public function methodExists(MethodIdentifier $method_id, ?string $calling_method_id = null, ?CodeLocation $code_location = null, ?StatementsSource $source = null, ?string $source_file_path = null, bool $use_method_existence_provider = \true, bool $is_used = \false, bool $with_pseudo = \false) : bool { $fq_class_name = $method_id->fq_class_name; $method_name = $method_id->method_name; if ($use_method_existence_provider && $this->existence_provider->has($fq_class_name)) { $method_exists = $this->existence_provider->doesMethodExist($fq_class_name, $method_name, $source, $code_location); if ($method_exists !== null) { return $method_exists; } } $old_method_id = null; $fq_class_name = strtolower($this->classlikes->getUnAliasedName($fq_class_name)); try { $class_storage = $this->classlike_storage_provider->get($fq_class_name); } catch (InvalidArgumentException $e) { return \false; } if ($class_storage->is_enum) { if ($method_name === 'cases') { return \true; } if ($class_storage->enum_type && in_array($method_name, ['from', 'tryFrom'], \true)) { return \true; } } $source_file_path = $source ? $source->getFilePath() : $source_file_path; $calling_class_name = $source ? $source->getFQCLN() : null; if (!$calling_class_name && $calling_method_id) { $calling_class_name = explode('::', $calling_method_id)[0]; } $declaring_method_id = $class_storage->declaring_method_ids[$method_name] ?? null; if ($declaring_method_id === null && $with_pseudo) { $declaring_method_id = $class_storage->declaring_pseudo_method_ids[$method_name] ?? null; } if ($declaring_method_id !== null) { if ($calling_method_id === strtolower((string) $declaring_method_id)) { return \true; } $declaring_fq_class_name = strtolower($declaring_method_id->fq_class_name); if ($declaring_fq_class_name !== strtolower((string) $calling_class_name)) { if ($calling_method_id) { $this->file_reference_provider->addMethodReferenceToClass($calling_method_id, $declaring_fq_class_name); } elseif ($source_file_path) { $this->file_reference_provider->addNonMethodReferenceToClass($source_file_path, $declaring_fq_class_name); } } if ((string) $method_id !== (string) $declaring_method_id && $class_storage->user_defined && isset($class_storage->potential_declaring_method_ids[$method_name])) { foreach ($class_storage->potential_declaring_method_ids[$method_name] as $potential_id => $_) { if ($calling_method_id) { $this->file_reference_provider->addMethodReferenceToClassMember($calling_method_id, $potential_id, $is_used); } elseif ($source_file_path) { $this->file_reference_provider->addFileReferenceToClassMember($source_file_path, $potential_id, $is_used); } } } else { if ($calling_method_id) { $this->file_reference_provider->addMethodReferenceToClassMember($calling_method_id, strtolower((string) $declaring_method_id), $is_used); } elseif ($source_file_path) { $this->file_reference_provider->addFileReferenceToClassMember($source_file_path, strtolower((string) $declaring_method_id), $is_used); } } if ($this->collect_locations && $code_location) { $this->file_reference_provider->addCallingLocationForClassMethod($code_location, strtolower((string) $declaring_method_id)); } foreach ($class_storage->class_implements as $fq_interface_name) { $interface_method_id_lc = strtolower($fq_interface_name . '::' . $method_name); if ($this->collect_locations && $code_location) { $this->file_reference_provider->addCallingLocationForClassMethod($code_location, $interface_method_id_lc); } if ($calling_method_id) { $this->file_reference_provider->addMethodReferenceToClassMember($calling_method_id, $interface_method_id_lc, $is_used); } elseif ($source_file_path) { $this->file_reference_provider->addFileReferenceToClassMember($source_file_path, $interface_method_id_lc, $is_used); } } $declaring_method_class = $declaring_method_id->fq_class_name; $declaring_method_name = $declaring_method_id->method_name; $declaring_class_storage = $this->classlike_storage_provider->get($declaring_method_class); if (isset($declaring_class_storage->overridden_method_ids[$declaring_method_name])) { $overridden_method_ids = $declaring_class_storage->overridden_method_ids[$declaring_method_name]; foreach ($overridden_method_ids as $overridden_method_id) { if ($this->collect_locations && $code_location) { $this->file_reference_provider->addCallingLocationForClassMethod($code_location, strtolower((string) $overridden_method_id)); } if ($calling_method_id) { // also store failures in case the method is added later $this->file_reference_provider->addMethodReferenceToClassMember($calling_method_id, strtolower((string) $overridden_method_id), $is_used); } elseif ($source_file_path) { $this->file_reference_provider->addFileReferenceToClassMember($source_file_path, strtolower((string) $overridden_method_id), $is_used); } } } return \true; } if ($source_file_path && $fq_class_name !== strtolower((string) $calling_class_name)) { if ($calling_method_id) { $this->file_reference_provider->addMethodReferenceToClass($calling_method_id, $fq_class_name); } else { $this->file_reference_provider->addNonMethodReferenceToClass($source_file_path, $fq_class_name); } } if ($class_storage->abstract && isset($class_storage->overridden_method_ids[$method_name])) { return \true; } // support checking oldstyle constructors if ($method_name === '__construct') { $method_name_parts = explode('\\', $fq_class_name); $old_constructor_name = array_pop($method_name_parts); $old_method_id = $fq_class_name . '::' . $old_constructor_name; } if (!$class_storage->user_defined && (\Psalm\Internal\Codebase\InternalCallMapHandler::inCallMap((string) $method_id) || $old_method_id && \Psalm\Internal\Codebase\InternalCallMapHandler::inCallMap($old_method_id))) { return \true; } foreach ($class_storage->parent_classes + $class_storage->used_traits as $potential_future_declaring_fqcln) { $potential_id = strtolower($potential_future_declaring_fqcln) . '::' . $method_name; if ($calling_method_id) { // also store failures in case the method is added later $this->file_reference_provider->addMethodReferenceToMissingClassMember($calling_method_id, $potential_id); } elseif ($source_file_path) { $this->file_reference_provider->addFileReferenceToMissingClassMember($source_file_path, $potential_id); } } if ($calling_method_id) { // also store failures in case the method is added later $this->file_reference_provider->addMethodReferenceToMissingClassMember($calling_method_id, strtolower((string) $method_id)); } elseif ($source_file_path) { $this->file_reference_provider->addFileReferenceToMissingClassMember($source_file_path, strtolower((string) $method_id)); } return \false; } /** * @param list $args * @return list */ public function getMethodParams(MethodIdentifier $method_id, ?StatementsSource $source = null, ?array $args = null, ?Context $context = null) : array { $fq_class_name = $method_id->fq_class_name; $method_name = $method_id->method_name; if ($this->params_provider->has($fq_class_name)) { $method_params = $this->params_provider->getMethodParams($fq_class_name, $method_name, $args, $source, $context); if ($method_params !== null) { return $method_params; } } $declaring_method_id = $this->getDeclaringMethodId($method_id, \true); $callmap_id = $declaring_method_id ?? $method_id; // functions if (\Psalm\Internal\Codebase\InternalCallMapHandler::inCallMap((string) $callmap_id)) { $class_storage = $this->classlike_storage_provider->get($callmap_id->fq_class_name); $declaring_method_name = $declaring_method_id->method_name ?? $method_name; if (!$class_storage->stubbed || empty($class_storage->methods[$declaring_method_name]->stubbed)) { $function_callables = \Psalm\Internal\Codebase\InternalCallMapHandler::getCallablesFromCallMap((string) $callmap_id); if ($function_callables === null) { throw new UnexpectedValueException('Not expecting $function_callables to be null for ' . $callmap_id); } if (!$source || $args === null || count($function_callables) === 1) { assert($function_callables[0]->params !== null); return $function_callables[0]->params; } if ($context && $source instanceof StatementsAnalyzer) { $was_inside_call = $context->inside_call; $context->inside_call = \true; foreach ($args as $arg) { ExpressionAnalyzer::analyze($source, $arg->value, $context); } $context->inside_call = $was_inside_call; } $matching_callable = \Psalm\Internal\Codebase\InternalCallMapHandler::getMatchingCallableFromCallMapOptions($source->getCodebase(), $function_callables, $args, $source->getNodeTypeProvider(), (string) $callmap_id); assert($matching_callable->params !== null); return $matching_callable->params; } } if ($declaring_method_id) { $storage = $this->getStorage($declaring_method_id, \true); $params = $storage->params; if ($storage->has_docblock_param_types) { return $params; } $appearing_method_id = $this->getAppearingMethodId($declaring_method_id); if (!$appearing_method_id) { return $params; } $appearing_fq_class_name = $appearing_method_id->fq_class_name; $appearing_method_name = $appearing_method_id->method_name; $class_storage = $this->classlike_storage_provider->get($appearing_fq_class_name); if (!isset($class_storage->overridden_method_ids[$appearing_method_name])) { return $params; } if (!isset($class_storage->documenting_method_ids[$appearing_method_name])) { return $params; } $overridden_method_id = $class_storage->documenting_method_ids[$appearing_method_name]; $overridden_storage = $this->getStorage($overridden_method_id); $overriding_fq_class_name = $overridden_method_id->fq_class_name; foreach ($params as $i => $param) { if (isset($overridden_storage->params[$i]->type) && $overridden_storage->params[$i]->has_docblock_type) { $params[$i] = clone $param; /** @var Union $params[$i]->type */ $params[$i]->type = $overridden_storage->params[$i]->type; if ($source) { $overridden_class_storage = $this->classlike_storage_provider->get($overriding_fq_class_name); $params[$i]->type = self::localizeType($source->getCodebase(), $params[$i]->type, $appearing_fq_class_name, $overridden_class_storage->name); } if ($params[$i]->signature_type && $params[$i]->signature_type->isNullable()) { $params[$i]->type = $params[$i]->type->getBuilder()->addType(new TNull())->freeze(); } $params[$i]->type_location = $overridden_storage->params[$i]->type_location; } } return $params; } throw new UnexpectedValueException('Cannot get method params for ' . $method_id); } public static function localizeType(Codebase $codebase, Union $type, string $appearing_fq_class_name, string $base_fq_class_name) : Union { $class_storage = $codebase->classlike_storage_provider->get($appearing_fq_class_name); $extends = $class_storage->template_extended_params; if (!$extends) { return $type; } (new TypeLocalizer($extends, $base_fq_class_name))->traverse($type); return $type; } /** * @param array> $extends * @return list */ public static function getExtendedTemplatedTypes(TTemplateParam $atomic_type, array $extends) : array { $extra_added_types = []; if (isset($extends[$atomic_type->defining_class][$atomic_type->param_name])) { $extended_param = $extends[$atomic_type->defining_class][$atomic_type->param_name]; foreach ($extended_param->getAtomicTypes() as $extended_atomic_type) { if ($extended_atomic_type instanceof TTemplateParam) { $extra_added_types = [...$extra_added_types, ...self::getExtendedTemplatedTypes($extended_atomic_type, $extends)]; } else { $extra_added_types[] = $extended_atomic_type; } } } else { $extra_added_types[] = $atomic_type; } return $extra_added_types; } public function isVariadic(MethodIdentifier $method_id) : bool { $declaring_method_id = $this->getDeclaringMethodId($method_id); if (!$declaring_method_id) { return \false; } return $this->getStorage($declaring_method_id)->variadic; } /** * @param list|null $args */ public function getMethodReturnType(MethodIdentifier $method_id, ?string &$self_class, ?SourceAnalyzer $source_analyzer = null, ?array $args = null, ?TemplateResult $template_result = null) : ?Union { $original_fq_class_name = $method_id->fq_class_name; $original_method_name = $method_id->method_name; $adjusted_fq_class_name = $this->classlikes->getUnAliasedName($original_fq_class_name); if ($adjusted_fq_class_name !== $original_fq_class_name) { $original_fq_class_name = strtolower($adjusted_fq_class_name); } $original_class_storage = $this->classlike_storage_provider->get($original_fq_class_name); if (isset($original_class_storage->pseudo_methods[$original_method_name])) { return $original_class_storage->pseudo_methods[$original_method_name]->return_type; } $declaring_method_id = $this->getDeclaringMethodId($method_id); if (!$declaring_method_id) { return null; } $appearing_method_id = $this->getAppearingMethodId($method_id); if (!$appearing_method_id) { $class_storage = $this->classlike_storage_provider->get($original_fq_class_name); if ($class_storage->abstract && isset($class_storage->overridden_method_ids[$original_method_name])) { $appearing_method_id = reset($class_storage->overridden_method_ids[$original_method_name]); } else { return null; } } $appearing_fq_class_name = $appearing_method_id->fq_class_name; $appearing_method_name = $appearing_method_id->method_name; $appearing_fq_class_storage = $this->classlike_storage_provider->get($appearing_fq_class_name); if ($appearing_fq_class_name === 'UnitEnum' && $original_class_storage->is_enum) { if ($original_method_name === 'cases') { if ($original_class_storage->enum_cases === []) { return Type::getEmptyArray(); } $types = []; foreach ($original_class_storage->enum_cases as $case_name => $_) { $types[] = new Union([new TEnumCase($original_fq_class_name, $case_name)]); } $list = new TKeyedArray($types, null, null, \true); return new Union([$list]); } } if ($appearing_fq_class_name === 'BackedEnum' && $original_class_storage->is_enum && $original_class_storage->enum_type) { if (($original_method_name === 'from' || $original_method_name === 'tryfrom') && $source_analyzer && isset($args[0]) && ($first_arg_type = $source_analyzer->getNodeTypeProvider()->getType($args[0]->value))) { $types = []; foreach ($original_class_storage->enum_cases as $case_name => $case_storage) { $case_value = $case_storage->getValue($this->classlikes); if (UnionTypeComparator::isContainedBy($source_analyzer->getCodebase(), is_int($case_value) ? Type::getInt(\false, $case_value) : Type::getString($case_value), $first_arg_type)) { $types[] = new TEnumCase($original_fq_class_name, $case_name); } } if ($types) { if ($original_method_name === 'tryfrom') { $types[] = new TNull(); } return new Union($types); } return $original_method_name === 'tryfrom' ? Type::getNull() : Type::getNever(); } } if (!$appearing_fq_class_storage->user_defined && !$appearing_fq_class_storage->stubbed && \Psalm\Internal\Codebase\InternalCallMapHandler::inCallMap((string) $appearing_method_id)) { if ((string) $appearing_method_id === 'Closure::fromcallable' && isset($args[0]) && $source_analyzer && ($first_arg_type = $source_analyzer->getNodeTypeProvider()->getType($args[0]->value)) && $first_arg_type->isSingle()) { foreach ($first_arg_type->getAtomicTypes() as $atomic_type) { if ($atomic_type instanceof TCallable || $atomic_type instanceof TClosure) { $callable_type = $atomic_type; return new Union([new TClosure('Closure', $callable_type->params, $callable_type->return_type)]); } if ($atomic_type instanceof TNamedObject && $this->methodExists(new MethodIdentifier($atomic_type->value, '__invoke'))) { $invokable_storage = $this->getStorage(new MethodIdentifier($atomic_type->value, '__invoke')); return new Union([new TClosure('Closure', $invokable_storage->params, $invokable_storage->return_type)]); } } } $callmap_callables = \Psalm\Internal\Codebase\InternalCallMapHandler::getCallablesFromCallMap((string) $appearing_method_id); if (!$callmap_callables || $callmap_callables[0]->return_type === null) { throw new UnexpectedValueException('Shouldn’t get here'); } $return_type_candidate = $callmap_callables[0]->return_type; if ($return_type_candidate->isFalsable()) { return $return_type_candidate->setProperties(['ignore_falsable_issues' => \true]); } return $return_type_candidate; } $class_storage = $this->classlike_storage_provider->get($appearing_fq_class_name); $storage = $this->getStorage($declaring_method_id); $candidate_type = $storage->return_type; if ($candidate_type && $candidate_type->isVoid()) { return $candidate_type; } if (isset($class_storage->documenting_method_ids[$appearing_method_name])) { $overridden_method_id = $class_storage->documenting_method_ids[$appearing_method_name]; // special override to allow inference of Iterator types if ($overridden_method_id->fq_class_name === 'Iterator' && $storage->return_type && $storage->return_type === $storage->signature_return_type) { return $storage->return_type; } $overridden_storage = $this->getStorage($overridden_method_id); if ($overridden_storage->return_type) { if ($overridden_storage->return_type->isNull()) { return Type::getVoid(); } if (!$candidate_type || !$source_analyzer) { $self_class = $overridden_method_id->fq_class_name; return $overridden_storage->return_type; } if ($candidate_type->getId() === $overridden_storage->return_type->getId()) { $self_class = $appearing_fq_class_storage->name; return $candidate_type; } $overridden_class_storage = $this->classlike_storage_provider->get($overridden_method_id->fq_class_name); $overridden_storage_return_type = TypeExpander::expandUnion($source_analyzer->getCodebase(), $overridden_storage->return_type, $overridden_method_id->fq_class_name, $appearing_fq_class_name, $overridden_class_storage->parent_class, \true, \false, $storage->final); $old_contained_by_new = UnionTypeComparator::isContainedBy($source_analyzer->getCodebase(), $candidate_type, $overridden_storage_return_type); $new_contained_by_old = UnionTypeComparator::isContainedBy($source_analyzer->getCodebase(), $overridden_storage_return_type, $candidate_type); if (!$old_contained_by_new && !$new_contained_by_old || $old_contained_by_new && $new_contained_by_old) { $found_generic_params = ClassTemplateParamCollector::collect($source_analyzer->getCodebase(), $appearing_fq_class_storage, $appearing_fq_class_storage, $appearing_method_name, null, \true); if ($found_generic_params) { $passed_template_result = $template_result; $template_result = new TemplateResult([], $found_generic_params); if ($passed_template_result !== null) { $template_result = $template_result->merge($passed_template_result); } $overridden_storage_return_type = TemplateInferredTypeReplacer::replace($overridden_storage_return_type, $template_result, $source_analyzer->getCodebase()); } $attempted_intersection = null; if ($old_contained_by_new) { //implicitly $new_contained_by_old as well try { $attempted_intersection = Type::intersectUnionTypes($candidate_type, $overridden_storage_return_type, $source_analyzer->getCodebase()); } catch (InvalidArgumentException $e) { // TODO: fix } } else { $attempted_intersection = Type::intersectUnionTypes($overridden_storage_return_type, $candidate_type, $source_analyzer->getCodebase()); } if ($attempted_intersection) { $self_class = $overridden_method_id->fq_class_name; return $attempted_intersection; } $self_class = $appearing_fq_class_storage->name; return $candidate_type; } if ($old_contained_by_new) { $self_class = $appearing_fq_class_storage->name; return $candidate_type; } $self_class = $overridden_method_id->fq_class_name; return $overridden_storage_return_type; } } if ($candidate_type) { $self_class = $appearing_fq_class_storage->name; return $candidate_type; } if (!isset($class_storage->overridden_method_ids[$appearing_method_name])) { return null; } foreach ($class_storage->overridden_method_ids[$appearing_method_name] as $overridden_method_id) { $overridden_storage = $this->getStorage($overridden_method_id); if ($overridden_storage->return_type) { if ($overridden_storage->return_type->isNull()) { if ($candidate_type && !$candidate_type->isVoid()) { return null; } $candidate_type = Type::getVoid(); continue; } $fq_overridden_class = $overridden_method_id->fq_class_name; $overridden_class_storage = $this->classlike_storage_provider->get($fq_overridden_class); $overridden_return_type = $overridden_storage->return_type; $self_class = $overridden_class_storage->name; if ($candidate_type && $source_analyzer && !$candidate_type->isMixed()) { $old_contained_by_new = UnionTypeComparator::isContainedBy($source_analyzer->getCodebase(), $candidate_type, $overridden_return_type); $new_contained_by_old = UnionTypeComparator::isContainedBy($source_analyzer->getCodebase(), $overridden_return_type, $candidate_type); if (!$old_contained_by_new && !$new_contained_by_old || $old_contained_by_new && $new_contained_by_old) { $attempted_intersection = Type::intersectUnionTypes($candidate_type, $overridden_return_type, $source_analyzer->getCodebase()); if ($attempted_intersection) { $candidate_type = $attempted_intersection; continue; } return null; } if ($old_contained_by_new) { continue; } } $candidate_type = $overridden_return_type; } } return $candidate_type; } public function getMethodReturnsByRef(MethodIdentifier $method_id) : bool { $method_id = $this->getDeclaringMethodId($method_id); if (!$method_id) { return \false; } $fq_class_storage = $this->classlike_storage_provider->get($method_id->fq_class_name); if (!$fq_class_storage->user_defined && \Psalm\Internal\Codebase\InternalCallMapHandler::inCallMap((string) $method_id)) { return \false; } return $this->getStorage($method_id)->returns_by_ref; } public function getMethodReturnTypeLocation(MethodIdentifier $method_id, ?CodeLocation &$defined_location = null) : ?CodeLocation { $method_id = $this->getDeclaringMethodId($method_id); if ($method_id === null) { return null; } $storage = $this->getStorage($method_id); // if function exists in stubs and in analyzed code // use the return type location of the analyzed code instead of the stubbed location if ($storage->stubbed) { return null; } if (!$storage->return_type_location) { $overridden_method_ids = $this->getOverriddenMethodIds($method_id); foreach ($overridden_method_ids as $overridden_method_id) { $overridden_storage = $this->getStorage($overridden_method_id); if ($overridden_storage->return_type_location && !$overridden_storage->stubbed) { $defined_location = $overridden_storage->return_type_location; break; } } } return $storage->return_type_location; } /** * @param lowercase-string $method_name_lc * @param lowercase-string $declaring_method_name_lc */ public function setDeclaringMethodId(string $fq_class_name, string $method_name_lc, string $declaring_fq_class_name, string $declaring_method_name_lc) : void { $class_storage = $this->classlike_storage_provider->get($fq_class_name); $class_storage->declaring_method_ids[$method_name_lc] = new MethodIdentifier($declaring_fq_class_name, $declaring_method_name_lc); } /** * @param lowercase-string $method_name_lc * @param lowercase-string $appearing_method_name_lc */ public function setAppearingMethodId(string $fq_class_name, string $method_name_lc, string $appearing_fq_class_name, string $appearing_method_name_lc) : void { $class_storage = $this->classlike_storage_provider->get($fq_class_name); $class_storage->appearing_method_ids[$method_name_lc] = new MethodIdentifier($appearing_fq_class_name, $appearing_method_name_lc); } /** @psalm-mutation-free */ public function getDeclaringMethodId(MethodIdentifier $method_id, bool $with_pseudo = \false) : ?MethodIdentifier { $fq_class_name = $this->classlikes->getUnAliasedName($method_id->fq_class_name); $class_storage = $this->classlike_storage_provider->get($fq_class_name); $method_name = $method_id->method_name; if (isset($class_storage->declaring_method_ids[$method_name])) { return $class_storage->declaring_method_ids[$method_name]; } if ($class_storage->abstract && isset($class_storage->overridden_method_ids[$method_name])) { return reset($class_storage->overridden_method_ids[$method_name]); } if ($with_pseudo && isset($class_storage->declaring_pseudo_method_ids[$method_name])) { return $class_storage->declaring_pseudo_method_ids[$method_name]; } return null; } /** * Get the class this method appears in (vs is declared in, which could give a trait */ public function getAppearingMethodId(MethodIdentifier $method_id) : ?MethodIdentifier { $fq_class_name = $this->classlikes->getUnAliasedName($method_id->fq_class_name); $class_storage = $this->classlike_storage_provider->get($fq_class_name); $method_name = $method_id->method_name; return $class_storage->appearing_method_ids[$method_name] ?? null; } /** * @return array */ public function getOverriddenMethodIds(MethodIdentifier $method_id) : array { $class_storage = $this->classlike_storage_provider->get($method_id->fq_class_name); $method_name = $method_id->method_name; return $class_storage->overridden_method_ids[$method_name] ?? []; } public function getCasedMethodId(MethodIdentifier $original_method_id) : string { $method_id = $this->getDeclaringMethodId($original_method_id); if ($method_id === null) { return (string) $original_method_id; } $fq_class_name = $method_id->fq_class_name; $new_method_name = $method_id->method_name; $old_fq_class_name = $original_method_id->fq_class_name; $old_method_name = $original_method_id->method_name; $storage = $this->getStorage($method_id); if ($old_method_name === $new_method_name && strtolower($old_fq_class_name) !== $old_fq_class_name) { return $old_fq_class_name . '::' . $storage->cased_name; } return $fq_class_name . '::' . $storage->cased_name; } public function getUserMethodStorage(MethodIdentifier $method_id) : ?MethodStorage { $declaring_method_id = $this->getDeclaringMethodId($method_id, \true); if (!$declaring_method_id) { if (\Psalm\Internal\Codebase\InternalCallMapHandler::inCallMap((string) $method_id)) { return null; } throw new UnexpectedValueException('$storage should not be null for ' . $method_id); } $storage = $this->getStorage($declaring_method_id, \true); if (!$storage->location) { return null; } return $storage; } public function getClassLikeStorageForMethod(MethodIdentifier $method_id) : ClassLikeStorage { $fq_class_name = $method_id->fq_class_name; $method_name = $method_id->method_name; if ($this->existence_provider->has($fq_class_name)) { if ($this->existence_provider->doesMethodExist($fq_class_name, $method_name, null, null)) { return $this->classlike_storage_provider->get($fq_class_name); } } $declaring_method_id = $this->getDeclaringMethodId($method_id); if ($declaring_method_id === null) { if (\Psalm\Internal\Codebase\InternalCallMapHandler::inCallMap((string) $method_id)) { $declaring_method_id = $method_id; } else { throw new UnexpectedValueException('$storage should not be null for ' . $method_id); } } $declaring_fq_class_name = $declaring_method_id->fq_class_name; return $this->classlike_storage_provider->get($declaring_fq_class_name); } /** @psalm-mutation-free */ public function getStorage(MethodIdentifier $method_id, bool $with_pseudo = \false) : MethodStorage { try { $class_storage = $this->classlike_storage_provider->get($method_id->fq_class_name); } catch (InvalidArgumentException $e) { throw new UnexpectedValueException($e->getMessage()); } $method_name = $method_id->method_name; $storage = $class_storage->methods[$method_name] ?? null; if ($storage === null && $with_pseudo) { $storage = $class_storage->pseudo_methods[$method_name] ?? $class_storage->pseudo_static_methods[$method_name] ?? null; } if ($storage === null) { throw new UnexpectedValueException('$storage should not be null for ' . $method_id); } return $storage; } /** @psalm-mutation-free */ public function hasStorage(MethodIdentifier $method_id) : bool { try { $class_storage = $this->classlike_storage_provider->get($method_id->fq_class_name); } catch (InvalidArgumentException $e) { return \false; } $method_name = $method_id->method_name; if (!isset($class_storage->methods[$method_name])) { return \false; } return \true; } } resolver = new \Psalm\Internal\Codebase\StorageByPatternResolver(); $this->codebase = $codebase; } /** * @return non-empty-array|null */ public function resolve(string $class_name, string $constant_pattern) : ?array { if (!$this->codebase->classlike_storage_provider->has($class_name)) { return null; } $classlike_storage = $this->codebase->classlike_storage_provider->get($class_name); $constants = $this->resolver->resolveConstants($classlike_storage, $constant_pattern); $types = []; foreach ($constants as $class_constant_storage) { if (!$class_constant_storage->type) { $types[] = [new TMixed()]; continue; } $types[] = $class_constant_storage->type->getAtomicTypes(); } if ($types === []) { return null; } return array_merge([], ...$types); } } >|null */ private static ?array $property_map = null; /** * Gets the method/function call map * * @return array> */ public static function getPropertyMap() : array { if (self::$property_map !== null) { return self::$property_map; } /** @var array> */ $property_map = (require dirname(__DIR__, 4) . '/dictionaries/PropertyMap.php'); self::$property_map = $property_map; return self::$property_map; } public static function inPropertyMap(string $class_name) : bool { return isset(self::getPropertyMap()[strtolower($class_name)]); } } */ private static ?array $impure_functions_list = null; /** @psalm-assert !null self::$impure_functions_list */ private static function load() : void { if (self::$impure_functions_list !== null) { return; } /** @var array */ self::$impure_functions_list = (require dirname(__DIR__, 4) . '/dictionaries/ImpureFunctionsList.php'); } public static function isImpure(string $function_id) : bool { self::load(); return isset(self::$impure_functions_list[strtolower($function_id)]); } } */ private array $existing_classlikes_lc = []; /** * @var array */ private array $existing_classes_lc = []; /** * @var array */ private array $existing_classes = []; /** * @var array */ private array $existing_interfaces_lc = []; /** * @var array */ private array $existing_interfaces = []; /** * @var array */ private array $existing_traits_lc = []; /** * @var array */ private array $existing_traits = []; /** * @var array */ private array $existing_enums_lc = []; /** * @var array */ private array $existing_enums = []; /** * @var array */ private array $classlike_aliases_map = []; /** * @var array */ private array $existing_classlike_aliases = []; /** * @var array */ private array $trait_nodes = []; public bool $collect_references = \false; public bool $collect_locations = \false; private StatementsProvider $statements_provider; private Config $config; private \Psalm\Internal\Codebase\Scanner $scanner; public function __construct(Config $config, ClassLikeStorageProvider $storage_provider, FileReferenceProvider $file_reference_provider, StatementsProvider $statements_provider, \Psalm\Internal\Codebase\Scanner $scanner) { $this->config = $config; $this->classlike_storage_provider = $storage_provider; $this->file_reference_provider = $file_reference_provider; $this->statements_provider = $statements_provider; $this->scanner = $scanner; $this->collectPredefinedClassLikes(); } private function collectPredefinedClassLikes() : void { /** @var array */ $predefined_classes = get_declared_classes(); foreach ($predefined_classes as $predefined_class) { $predefined_class = preg_replace('/^\\\\/', '', $predefined_class, 1); /** @psalm-suppress ArgumentTypeCoercion */ $reflection_class = new ReflectionClass($predefined_class); if (!$reflection_class->isUserDefined() && $reflection_class->name === $predefined_class) { $predefined_class_lc = strtolower($predefined_class); $this->existing_classlikes_lc[$predefined_class_lc] = \true; $this->existing_classes_lc[$predefined_class_lc] = \true; $this->existing_classes[$predefined_class] = \true; } } /** @var array */ $predefined_interfaces = get_declared_interfaces(); foreach ($predefined_interfaces as $predefined_interface) { $predefined_interface = preg_replace('/^\\\\/', '', $predefined_interface, 1); /** @psalm-suppress ArgumentTypeCoercion */ $reflection_class = new ReflectionClass($predefined_interface); if (!$reflection_class->isUserDefined() && $reflection_class->name === $predefined_interface) { $predefined_interface_lc = strtolower($predefined_interface); $this->existing_classlikes_lc[$predefined_interface_lc] = \true; $this->existing_interfaces_lc[$predefined_interface_lc] = \true; $this->existing_interfaces[$predefined_interface] = \true; } } } public function addFullyQualifiedClassName(string $fq_class_name, ?string $file_path = null) : void { $fq_class_name_lc = strtolower($fq_class_name); $this->existing_classlikes_lc[$fq_class_name_lc] = \true; $this->existing_classes_lc[$fq_class_name_lc] = \true; $this->existing_classes[$fq_class_name] = \true; $this->existing_traits_lc[$fq_class_name_lc] = \false; $this->existing_interfaces_lc[$fq_class_name_lc] = \false; $this->existing_enums_lc[$fq_class_name_lc] = \false; if ($file_path) { $this->scanner->setClassLikeFilePath($fq_class_name_lc, $file_path); } } public function addFullyQualifiedInterfaceName(string $fq_class_name, ?string $file_path = null) : void { $fq_class_name_lc = strtolower($fq_class_name); $this->existing_classlikes_lc[$fq_class_name_lc] = \true; $this->existing_interfaces_lc[$fq_class_name_lc] = \true; $this->existing_interfaces[$fq_class_name] = \true; $this->existing_classes_lc[$fq_class_name_lc] = \false; $this->existing_traits_lc[$fq_class_name_lc] = \false; $this->existing_enums_lc[$fq_class_name_lc] = \false; if ($file_path) { $this->scanner->setClassLikeFilePath($fq_class_name_lc, $file_path); } } public function addFullyQualifiedTraitName(string $fq_class_name, ?string $file_path = null) : void { $fq_class_name_lc = strtolower($fq_class_name); $this->existing_classlikes_lc[$fq_class_name_lc] = \true; $this->existing_traits_lc[$fq_class_name_lc] = \true; $this->existing_traits[$fq_class_name] = \true; $this->existing_classes_lc[$fq_class_name_lc] = \false; $this->existing_interfaces_lc[$fq_class_name_lc] = \false; $this->existing_enums[$fq_class_name] = \false; if ($file_path) { $this->scanner->setClassLikeFilePath($fq_class_name_lc, $file_path); } } public function addFullyQualifiedEnumName(string $fq_class_name, ?string $file_path = null) : void { $fq_class_name_lc = strtolower($fq_class_name); $this->existing_classlikes_lc[$fq_class_name_lc] = \true; $this->existing_enums_lc[$fq_class_name_lc] = \true; $this->existing_enums[$fq_class_name] = \true; $this->existing_traits_lc[$fq_class_name_lc] = \false; $this->existing_classes_lc[$fq_class_name_lc] = \false; $this->existing_interfaces_lc[$fq_class_name_lc] = \false; if ($file_path) { $this->scanner->setClassLikeFilePath($fq_class_name_lc, $file_path); } } public function addFullyQualifiedClassLikeName(string $fq_class_name_lc, ?string $file_path = null) : void { if ($file_path) { $this->scanner->setClassLikeFilePath($fq_class_name_lc, $file_path); } } /** * @return list */ public function getMatchingClassLikeNames(string $stub) : array { $matching_classes = []; if ($stub[0] === '*') { $stub = substr($stub, 1); } $fully_qualified = \false; if ($stub[0] === '\\') { $fully_qualified = \true; $stub = substr($stub, 1); } else { // for any not-fully-qualified class name the bit we care about comes after a dash [, $stub] = explode('-', $stub); } $stub = preg_quote(strtolower($stub)); if ($fully_qualified) { $stub = '^' . $stub; } else { $stub = '(^|\\\\)' . $stub; } foreach ($this->existing_classes as $fq_classlike_name => $found) { if (!$found) { continue; } if (preg_match('@' . $stub . '.*@i', $fq_classlike_name)) { $matching_classes[] = $fq_classlike_name; } } foreach ($this->existing_interfaces as $fq_classlike_name => $found) { if (!$found) { continue; } if (preg_match('@' . $stub . '.*@i', $fq_classlike_name)) { $matching_classes[] = $fq_classlike_name; } } return $matching_classes; } public function hasFullyQualifiedClassName(string $fq_class_name, ?CodeLocation $code_location = null, ?string $calling_fq_class_name = null, ?string $calling_method_id = null) : bool { $fq_class_name_lc = strtolower($this->getUnAliasedName($fq_class_name)); if ($code_location) { if ($calling_method_id) { $this->file_reference_provider->addMethodReferenceToClass($calling_method_id, $fq_class_name_lc); } elseif (!$calling_fq_class_name || strtolower($calling_fq_class_name) !== $fq_class_name_lc) { $this->file_reference_provider->addNonMethodReferenceToClass($code_location->file_path, $fq_class_name_lc); if ($calling_fq_class_name) { $class_storage = $this->classlike_storage_provider->get($calling_fq_class_name); if ($class_storage->location && $class_storage->location->file_path !== $code_location->file_path) { $this->file_reference_provider->addNonMethodReferenceToClass($class_storage->location->file_path, $fq_class_name_lc); } } } } // fixme: this looks like a crazy caching hack if (!isset($this->existing_classes_lc[$fq_class_name_lc]) || !$this->existing_classes_lc[$fq_class_name_lc] || !$this->classlike_storage_provider->has($fq_class_name_lc)) { if ((!isset($this->existing_classes_lc[$fq_class_name_lc]) || $this->existing_classes_lc[$fq_class_name_lc]) && !$this->classlike_storage_provider->has($fq_class_name_lc)) { if (!isset($this->existing_classes_lc[$fq_class_name_lc])) { $this->existing_classes_lc[$fq_class_name_lc] = \false; return \false; } return $this->existing_classes_lc[$fq_class_name_lc]; } return \false; } if ($this->collect_locations && $code_location) { $this->file_reference_provider->addCallingLocationForClass($code_location, strtolower($fq_class_name)); } return \true; } public function hasFullyQualifiedInterfaceName(string $fq_class_name, ?CodeLocation $code_location = null, ?string $calling_fq_class_name = null, ?string $calling_method_id = null) : bool { $fq_class_name_lc = strtolower($this->getUnAliasedName($fq_class_name)); // fixme: this looks like a crazy caching hack if (!isset($this->existing_interfaces_lc[$fq_class_name_lc]) || !$this->existing_interfaces_lc[$fq_class_name_lc] || !$this->classlike_storage_provider->has($fq_class_name_lc)) { if ((!isset($this->existing_interfaces_lc[$fq_class_name_lc]) || $this->existing_interfaces_lc[$fq_class_name_lc]) && !$this->classlike_storage_provider->has($fq_class_name_lc)) { if (!isset($this->existing_interfaces_lc[$fq_class_name_lc])) { $this->existing_interfaces_lc[$fq_class_name_lc] = \false; return \false; } return $this->existing_interfaces_lc[$fq_class_name_lc]; } return \false; } if ($this->collect_references && $code_location) { if ($calling_method_id) { $this->file_reference_provider->addMethodReferenceToClass($calling_method_id, $fq_class_name_lc); } else { $this->file_reference_provider->addNonMethodReferenceToClass($code_location->file_path, $fq_class_name_lc); if ($calling_fq_class_name) { $class_storage = $this->classlike_storage_provider->get($calling_fq_class_name); if ($class_storage->location && $class_storage->location->file_path !== $code_location->file_path) { $this->file_reference_provider->addNonMethodReferenceToClass($class_storage->location->file_path, $fq_class_name_lc); } } } } if ($this->collect_locations && $code_location) { $this->file_reference_provider->addCallingLocationForClass($code_location, strtolower($fq_class_name)); } return \true; } public function hasFullyQualifiedEnumName(string $fq_class_name, ?CodeLocation $code_location = null, ?string $calling_fq_class_name = null, ?string $calling_method_id = null) : bool { $fq_class_name_lc = strtolower($this->getUnAliasedName($fq_class_name)); // fixme: this looks like a crazy caching hack if (!isset($this->existing_enums_lc[$fq_class_name_lc]) || !$this->existing_enums_lc[$fq_class_name_lc] || !$this->classlike_storage_provider->has($fq_class_name_lc)) { if ((!isset($this->existing_enums_lc[$fq_class_name_lc]) || $this->existing_enums_lc[$fq_class_name_lc]) && !$this->classlike_storage_provider->has($fq_class_name_lc)) { if (!isset($this->existing_enums_lc[$fq_class_name_lc])) { $this->existing_enums_lc[$fq_class_name_lc] = \false; return \false; } return $this->existing_enums_lc[$fq_class_name_lc]; } return \false; } if ($this->collect_references && $code_location) { if ($calling_method_id) { $this->file_reference_provider->addMethodReferenceToClass($calling_method_id, $fq_class_name_lc); } else { $this->file_reference_provider->addNonMethodReferenceToClass($code_location->file_path, $fq_class_name_lc); if ($calling_fq_class_name) { $class_storage = $this->classlike_storage_provider->get($calling_fq_class_name); if ($class_storage->location && $class_storage->location->file_path !== $code_location->file_path) { $this->file_reference_provider->addNonMethodReferenceToClass($class_storage->location->file_path, $fq_class_name_lc); } } } } if ($this->collect_locations && $code_location) { $this->file_reference_provider->addCallingLocationForClass($code_location, strtolower($fq_class_name)); } return \true; } public function hasFullyQualifiedTraitName(string $fq_class_name, ?CodeLocation $code_location = null) : bool { $fq_class_name_lc = strtolower($this->getUnAliasedName($fq_class_name)); if (!isset($this->existing_traits_lc[$fq_class_name_lc]) || !$this->existing_traits_lc[$fq_class_name_lc]) { return \false; } if ($this->collect_references && $code_location) { $this->file_reference_provider->addNonMethodReferenceToClass($code_location->file_path, $fq_class_name_lc); } return \true; } /** * Check whether a class/interface exists */ public function classOrInterfaceExists(string $fq_class_name, ?CodeLocation $code_location = null, ?string $calling_fq_class_name = null, ?string $calling_method_id = null) : bool { return $this->classExists($fq_class_name, $code_location, $calling_fq_class_name, $calling_method_id) || $this->interfaceExists($fq_class_name, $code_location, $calling_fq_class_name, $calling_method_id); } /** * Check whether a class/interface exists */ public function classOrInterfaceOrEnumExists(string $fq_class_name, ?CodeLocation $code_location = null, ?string $calling_fq_class_name = null, ?string $calling_method_id = null) : bool { return $this->classExists($fq_class_name, $code_location, $calling_fq_class_name, $calling_method_id) || $this->interfaceExists($fq_class_name, $code_location, $calling_fq_class_name, $calling_method_id) || $this->enumExists($fq_class_name, $code_location, $calling_fq_class_name, $calling_method_id); } /** * Determine whether or not a given class exists */ public function classExists(string $fq_class_name, ?CodeLocation $code_location = null, ?string $calling_fq_class_name = null, ?string $calling_method_id = null) : bool { if (isset(ClassLikeAnalyzer::SPECIAL_TYPES[$fq_class_name])) { return \false; } if ($fq_class_name === 'Generator') { return \true; } return $this->hasFullyQualifiedClassName($fq_class_name, $code_location, $calling_fq_class_name, $calling_method_id); } /** * Determine whether or not a class extends a parent * * @psalm-mutation-free * @throws UnpopulatedClasslikeException when called on unpopulated class * @throws InvalidArgumentException when class does not exist */ public function classExtends(string $fq_class_name, string $possible_parent, bool $from_api = \false) : bool { $unaliased_fq_class_name = $this->getUnAliasedName($fq_class_name); $unaliased_fq_class_name_lc = strtolower($unaliased_fq_class_name); if ($unaliased_fq_class_name_lc === 'generator') { return \false; } $class_storage = $this->classlike_storage_provider->get($unaliased_fq_class_name); if ($from_api && !$class_storage->populated) { throw new UnpopulatedClasslikeException($fq_class_name); } return isset($class_storage->parent_classes[strtolower($possible_parent)]); } /** * Check whether a class implements an interface * * @psalm-mutation-free */ public function classImplements(string $fq_class_name, string $interface) : bool { $interface_id = strtolower($interface); $fq_class_name = strtolower($fq_class_name); if ($interface_id === 'callable' && $fq_class_name === 'closure') { return \true; } if ($interface_id === 'traversable' && $fq_class_name === 'generator') { return \true; } if ($interface_id === 'traversable' && $fq_class_name === 'iterator') { return \true; } if (isset(ClassLikeAnalyzer::SPECIAL_TYPES[$interface_id]) || isset(ClassLikeAnalyzer::SPECIAL_TYPES[$fq_class_name])) { return \false; } $fq_class_name = $this->getUnAliasedName($fq_class_name); if (!$this->classlike_storage_provider->has($fq_class_name)) { return \false; } $class_storage = $this->classlike_storage_provider->get($fq_class_name); if (isset($class_storage->class_implements[$interface_id])) { return \true; } foreach ($class_storage->class_implements as $implementing_interface_lc => $_) { $aliased_interface_lc = strtolower($this->getUnAliasedName($implementing_interface_lc)); if ($aliased_interface_lc === $interface_id) { return \true; } } return \false; } public function interfaceExists(string $fq_interface_name, ?CodeLocation $code_location = null, ?string $calling_fq_class_name = null, ?string $calling_method_id = null) : bool { if (isset(ClassLikeAnalyzer::SPECIAL_TYPES[strtolower($fq_interface_name)])) { return \false; } return $this->hasFullyQualifiedInterfaceName($fq_interface_name, $code_location, $calling_fq_class_name, $calling_method_id); } public function enumExists(string $fq_enum_name, ?CodeLocation $code_location = null, ?string $calling_fq_class_name = null, ?string $calling_method_id = null) : bool { if (isset(ClassLikeAnalyzer::SPECIAL_TYPES[strtolower($fq_enum_name)])) { return \false; } return $this->hasFullyQualifiedEnumName($fq_enum_name, $code_location, $calling_fq_class_name, $calling_method_id); } public function interfaceExtends(string $interface_name, string $possible_parent) : bool { return isset($this->getParentInterfaces($interface_name)[strtolower($possible_parent)]); } /** * @return array all interfaces extended by $interface_name */ public function getParentInterfaces(string $fq_interface_name) : array { $fq_interface_name = strtolower($fq_interface_name); return $this->classlike_storage_provider->get($fq_interface_name)->parent_interfaces; } public function traitExists(string $fq_trait_name, ?CodeLocation $code_location = null) : bool { return $this->hasFullyQualifiedTraitName($fq_trait_name, $code_location); } /** * Determine whether or not a class has the correct casing */ public function classHasCorrectCasing(string $fq_class_name) : bool { if ($fq_class_name === 'Generator') { return \true; } if (isset($this->existing_classlike_aliases[$fq_class_name])) { return \true; } return isset($this->existing_classes[$fq_class_name]); } public function interfaceHasCorrectCasing(string $fq_interface_name) : bool { if (isset($this->existing_classlike_aliases[$fq_interface_name])) { return \true; } return isset($this->existing_interfaces[$fq_interface_name]); } public function enumHasCorrectCasing(string $fq_enum_name) : bool { if (isset($this->existing_classlike_aliases[$fq_enum_name])) { return \true; } return isset($this->existing_enums[$fq_enum_name]); } public function traitHasCorrectCasing(string $fq_trait_name) : bool { if (isset($this->existing_classlike_aliases[$fq_trait_name])) { return \true; } return isset($this->existing_traits[$fq_trait_name]); } public function getTraitNode(string $fq_trait_name) : PhpParser\Node\Stmt\Trait_ { $fq_trait_name_lc = strtolower($fq_trait_name); if (isset($this->trait_nodes[$fq_trait_name_lc])) { return $this->trait_nodes[$fq_trait_name_lc]; } $storage = $this->classlike_storage_provider->get($fq_trait_name); if (!$storage->location) { throw new UnexpectedValueException('Storage should exist for ' . $fq_trait_name); } $file_statements = $this->statements_provider->getStatementsForFile($storage->location->file_path, ProjectAnalyzer::getInstance()->getCodebase()->analysis_php_version_id); $trait_finder = new TraitFinder($fq_trait_name); $traverser = new NodeTraverser(); $traverser->addVisitor($trait_finder); $traverser->traverse($file_statements); $trait_node = $trait_finder->getNode(); if ($trait_node) { $this->trait_nodes[$fq_trait_name_lc] = $trait_node; return $trait_node; } throw new UnexpectedValueException('Could not locate trait statement'); } public function addClassAlias(string $fq_class_name, string $alias_name) : void { $this->classlike_aliases_map[strtolower($alias_name)] = $fq_class_name; $this->existing_classlike_aliases[$alias_name] = \true; } /** @psalm-mutation-free */ public function getUnAliasedName(string $alias_name) : string { $alias_name_lc = strtolower($alias_name); if ($this->existing_classlikes_lc[$alias_name_lc] ?? \false) { return $alias_name; } $result = $this->classlike_aliases_map[$alias_name_lc] ?? $alias_name; if ($result === $alias_name) { return $result; } return $this->getUnAliasedName($result); } public function consolidateAnalyzedData(\Psalm\Internal\Codebase\Methods $methods, ?Progress $progress, bool $find_unused_code) : void { if ($progress === null) { $progress = new VoidProgress(); } $progress->debug('Checking class references' . PHP_EOL); $project_analyzer = ProjectAnalyzer::getInstance(); $codebase = $project_analyzer->getCodebase(); foreach ($this->existing_classlikes_lc as $fq_class_name_lc => $_) { try { $classlike_storage = $this->classlike_storage_provider->get($fq_class_name_lc); } catch (InvalidArgumentException $e) { continue; } if ($classlike_storage->location && $this->config->isInProjectDirs($classlike_storage->location->file_path) && !$classlike_storage->is_trait) { if ($find_unused_code) { if ($classlike_storage->public_api || $this->file_reference_provider->isClassReferenced($fq_class_name_lc)) { $this->checkMethodReferences($classlike_storage, $methods); $this->checkPropertyReferences($classlike_storage); } else { IssueBuffer::maybeAdd(new UnusedClass('Class ' . $classlike_storage->name . ' is never used', $classlike_storage->location, $classlike_storage->name), $classlike_storage->suppressed_issues); } $this->checkMethodParamReferences($classlike_storage); } $this->findPossibleMethodParamTypes($classlike_storage); if ($codebase->alter_code && isset($project_analyzer->getIssuesToFix()['MissingImmutableAnnotation']) && !isset($codebase->analyzer->mutable_classes[$fq_class_name_lc]) && !$classlike_storage->external_mutation_free && $classlike_storage->properties && isset($classlike_storage->methods['__construct'])) { $stmts = $codebase->getStatementsForFile($classlike_storage->location->file_path); foreach ($stmts as $stmt) { if ($stmt instanceof PhpParser\Node\Stmt\Namespace_) { foreach ($stmt->stmts as $namespace_stmt) { if ($namespace_stmt instanceof PhpParser\Node\Stmt\Class_ && strtolower((string) $stmt->name . '\\' . (string) $namespace_stmt->name) === $fq_class_name_lc) { self::makeImmutable($namespace_stmt, $project_analyzer, $classlike_storage->location->file_path); } } } elseif ($stmt instanceof PhpParser\Node\Stmt\Class_ && strtolower((string) $stmt->name) === $fq_class_name_lc) { self::makeImmutable($stmt, $project_analyzer, $classlike_storage->location->file_path); } } } } } } public static function makeImmutable(PhpParser\Node\Stmt\Class_ $class_stmt, ProjectAnalyzer $project_analyzer, string $file_path) : void { $manipulator = ClassDocblockManipulator::getForClass($project_analyzer, $file_path, $class_stmt); $manipulator->makeImmutable(); } public function moveMethods(\Psalm\Internal\Codebase\Methods $methods, ?Progress $progress = null) : void { if ($progress === null) { $progress = new VoidProgress(); } $project_analyzer = ProjectAnalyzer::getInstance(); $codebase = $project_analyzer->getCodebase(); if (!$codebase->methods_to_move) { return; } $progress->debug('Refactoring methods ' . PHP_EOL); $code_migrations = []; foreach ($codebase->methods_to_move as $source => $destination) { $source_parts = explode('::', $source); try { $source_method_storage = $methods->getStorage(new MethodIdentifier(...$source_parts)); } catch (InvalidArgumentException $e) { continue; } [$destination_fq_class_name, $destination_name] = explode('::', $destination); try { $classlike_storage = $this->classlike_storage_provider->get($destination_fq_class_name); } catch (InvalidArgumentException $e) { continue; } if ($classlike_storage->stmt_location && $this->config->isInProjectDirs($classlike_storage->stmt_location->file_path) && $source_method_storage->stmt_location && $source_method_storage->stmt_location->file_path && $source_method_storage->location) { $new_class_bounds = $classlike_storage->stmt_location->getSnippetBounds(); $old_method_bounds = $source_method_storage->stmt_location->getSnippetBounds(); $old_method_name_bounds = $source_method_storage->location->getSelectionBounds(); FileManipulationBuffer::add($source_method_storage->stmt_location->file_path, [new FileManipulation($old_method_name_bounds[0], $old_method_name_bounds[1], $destination_name)]); $selection = $classlike_storage->stmt_location->getSnippet(); $insert_pos = strrpos($selection, "\n", -1); if (!$insert_pos) { $insert_pos = strlen($selection) - 1; } else { ++$insert_pos; } $code_migrations[] = new CodeMigration($source_method_storage->stmt_location->file_path, $old_method_bounds[0], $old_method_bounds[1], $classlike_storage->stmt_location->file_path, $new_class_bounds[0] + $insert_pos); } } FileManipulationBuffer::addCodeMigrations($code_migrations); } public function moveProperties(\Psalm\Internal\Codebase\Properties $properties, ?Progress $progress = null) : void { if ($progress === null) { $progress = new VoidProgress(); } $project_analyzer = ProjectAnalyzer::getInstance(); $codebase = $project_analyzer->getCodebase(); if (!$codebase->properties_to_move) { return; } $progress->debug('Refacting properties ' . PHP_EOL); $code_migrations = []; foreach ($codebase->properties_to_move as $source => $destination) { try { $source_property_storage = $properties->getStorage($source); } catch (InvalidArgumentException $e) { continue; } [$source_fq_class_name] = explode('::$', $source); [$destination_fq_class_name, $destination_name] = explode('::$', $destination); $source_classlike_storage = $this->classlike_storage_provider->get($source_fq_class_name); $destination_classlike_storage = $this->classlike_storage_provider->get($destination_fq_class_name); if ($destination_classlike_storage->stmt_location && $this->config->isInProjectDirs($destination_classlike_storage->stmt_location->file_path) && $source_property_storage->stmt_location && $source_property_storage->stmt_location->file_path && $source_property_storage->location) { if ($source_property_storage->type && $source_property_storage->type_location && $source_property_storage->type_location !== $source_property_storage->signature_type_location) { $bounds = $source_property_storage->type_location->getSelectionBounds(); $replace_type = TypeExpander::expandUnion($codebase, $source_property_storage->type, $source_classlike_storage->name, $source_classlike_storage->name, $source_classlike_storage->parent_class); $this->airliftClassDefinedDocblockType($replace_type, $destination_fq_class_name, $source_property_storage->stmt_location->file_path, $bounds[0], $bounds[1]); } $new_class_bounds = $destination_classlike_storage->stmt_location->getSnippetBounds(); $old_property_bounds = $source_property_storage->stmt_location->getSnippetBounds(); $old_property_name_bounds = $source_property_storage->location->getSelectionBounds(); FileManipulationBuffer::add($source_property_storage->stmt_location->file_path, [new FileManipulation($old_property_name_bounds[0], $old_property_name_bounds[1], '$' . $destination_name)]); $selection = $destination_classlike_storage->stmt_location->getSnippet(); $insert_pos = strrpos($selection, "\n", -1); if (!$insert_pos) { $insert_pos = strlen($selection) - 1; } else { ++$insert_pos; } $code_migrations[] = new CodeMigration($source_property_storage->stmt_location->file_path, $old_property_bounds[0], $old_property_bounds[1], $destination_classlike_storage->stmt_location->file_path, $new_class_bounds[0] + $insert_pos); } } FileManipulationBuffer::addCodeMigrations($code_migrations); } public function moveClassConstants(?Progress $progress = null) : void { if ($progress === null) { $progress = new VoidProgress(); } $project_analyzer = ProjectAnalyzer::getInstance(); $codebase = $project_analyzer->getCodebase(); if (!$codebase->class_constants_to_move) { return; } $progress->debug('Refacting constants ' . PHP_EOL); $code_migrations = []; foreach ($codebase->class_constants_to_move as $source => $destination) { [$source_fq_class_name, $source_const_name] = explode('::', $source); [$destination_fq_class_name, $destination_name] = explode('::', $destination); $source_classlike_storage = $this->classlike_storage_provider->get($source_fq_class_name); $destination_classlike_storage = $this->classlike_storage_provider->get($destination_fq_class_name); $constant_storage = $source_classlike_storage->constants[$source_const_name]; $source_const_stmt_location = $constant_storage->stmt_location; $source_const_location = $constant_storage->location; if (!$source_const_location || !$source_const_stmt_location) { continue; } if ($destination_classlike_storage->stmt_location && $this->config->isInProjectDirs($destination_classlike_storage->stmt_location->file_path) && $source_const_stmt_location->file_path) { $new_class_bounds = $destination_classlike_storage->stmt_location->getSnippetBounds(); $old_const_bounds = $source_const_stmt_location->getSnippetBounds(); $old_const_name_bounds = $source_const_location->getSelectionBounds(); FileManipulationBuffer::add($source_const_stmt_location->file_path, [new FileManipulation($old_const_name_bounds[0], $old_const_name_bounds[1], $destination_name)]); $selection = $destination_classlike_storage->stmt_location->getSnippet(); $insert_pos = strrpos($selection, "\n", -1); if (!$insert_pos) { $insert_pos = strlen($selection) - 1; } else { ++$insert_pos; } $code_migrations[] = new CodeMigration($source_const_stmt_location->file_path, $old_const_bounds[0], $old_const_bounds[1], $destination_classlike_storage->stmt_location->file_path, $new_class_bounds[0] + $insert_pos); } } FileManipulationBuffer::addCodeMigrations($code_migrations); } /** * @param lowercase-string|null $calling_method_id */ public function handleClassLikeReferenceInMigration(Codebase $codebase, StatementsSource $source, PhpParser\Node $class_name_node, string $fq_class_name, ?string $calling_method_id, bool $force_change = \false, bool $was_self = \false) : bool { if ($class_name_node instanceof VirtualNode) { return \false; } $calling_fq_class_name = $source->getFQCLN(); // if we're inside a moved class static method if ($codebase->methods_to_move && $calling_fq_class_name && $calling_method_id && isset($codebase->methods_to_move[$calling_method_id])) { $destination_class = explode('::', $codebase->methods_to_move[$calling_method_id])[0]; $intended_fq_class_name = strtolower($calling_fq_class_name) === strtolower($fq_class_name) && isset($codebase->classes_to_move[strtolower($calling_fq_class_name)]) ? $destination_class : $fq_class_name; $this->airliftClassLikeReference($intended_fq_class_name, $destination_class, $source->getFilePath(), (int) $class_name_node->getAttribute('startFilePos'), (int) $class_name_node->getAttribute('endFilePos') + 1, $class_name_node instanceof PhpParser\Node\Scalar\MagicConst\Class_, $was_self); return \true; } // if we're outside a moved class, but we're changing all references to a class if (isset($codebase->class_transforms[strtolower($fq_class_name)])) { $new_fq_class_name = $codebase->class_transforms[strtolower($fq_class_name)]; $file_manipulations = []; if ($class_name_node instanceof PhpParser\Node\Identifier) { $destination_parts = explode('\\', $new_fq_class_name); $destination_class_name = array_pop($destination_parts); $file_manipulations[] = new FileManipulation((int) $class_name_node->getAttribute('startFilePos'), (int) $class_name_node->getAttribute('endFilePos') + 1, $destination_class_name); FileManipulationBuffer::add($source->getFilePath(), $file_manipulations); return \true; } $uses_flipped = $source->getAliasedClassesFlipped(); $uses_flipped_replaceable = $source->getAliasedClassesFlippedReplaceable(); $old_fq_class_name = strtolower($fq_class_name); $migrated_source_fqcln = $calling_fq_class_name; if ($calling_fq_class_name && isset($codebase->class_transforms[strtolower($calling_fq_class_name)])) { $migrated_source_fqcln = $codebase->class_transforms[strtolower($calling_fq_class_name)]; } $source_namespace = $source->getNamespace(); if ($migrated_source_fqcln && $calling_fq_class_name !== $migrated_source_fqcln) { $new_source_parts = explode('\\', $migrated_source_fqcln, -1); $source_namespace = implode('\\', $new_source_parts); } if (isset($uses_flipped_replaceable[$old_fq_class_name])) { $alias = $uses_flipped_replaceable[$old_fq_class_name]; unset($uses_flipped[$old_fq_class_name]); $old_class_name_parts = explode('\\', $old_fq_class_name); $old_class_name = end($old_class_name_parts); if ($old_class_name === strtolower($alias)) { $new_class_name_parts = explode('\\', $new_fq_class_name); $new_class_name = end($new_class_name_parts); $uses_flipped[strtolower($new_fq_class_name)] = $new_class_name; } else { $uses_flipped[strtolower($new_fq_class_name)] = $alias; } } $file_manipulations[] = new FileManipulation((int) $class_name_node->getAttribute('startFilePos'), (int) $class_name_node->getAttribute('endFilePos') + 1, Type::getStringFromFQCLN($new_fq_class_name, $source_namespace, $uses_flipped, $migrated_source_fqcln, $was_self) . ($class_name_node instanceof PhpParser\Node\Scalar\MagicConst\Class_ ? '::class' : '')); FileManipulationBuffer::add($source->getFilePath(), $file_manipulations); return \true; } // if we're inside a moved class (could be a method, could be a property/class const default) if ($codebase->classes_to_move && $calling_fq_class_name && isset($codebase->classes_to_move[strtolower($calling_fq_class_name)])) { $destination_class = $codebase->classes_to_move[strtolower($calling_fq_class_name)]; if ($class_name_node instanceof PhpParser\Node\Identifier) { $destination_parts = explode('\\', $destination_class); $destination_class_name = array_pop($destination_parts); $file_manipulations = []; $file_manipulations[] = new FileManipulation((int) $class_name_node->getAttribute('startFilePos'), (int) $class_name_node->getAttribute('endFilePos') + 1, $destination_class_name); FileManipulationBuffer::add($source->getFilePath(), $file_manipulations); } else { $this->airliftClassLikeReference(strtolower($calling_fq_class_name) === strtolower($fq_class_name) ? $destination_class : $fq_class_name, $destination_class, $source->getFilePath(), (int) $class_name_node->getAttribute('startFilePos'), (int) $class_name_node->getAttribute('endFilePos') + 1, $class_name_node instanceof PhpParser\Node\Scalar\MagicConst\Class_); } return \true; } if ($force_change) { if ($calling_fq_class_name) { $this->airliftClassLikeReference($fq_class_name, $calling_fq_class_name, $source->getFilePath(), (int) $class_name_node->getAttribute('startFilePos'), (int) $class_name_node->getAttribute('endFilePos') + 1); } else { $file_manipulations = []; $file_manipulations[] = new FileManipulation((int) $class_name_node->getAttribute('startFilePos'), (int) $class_name_node->getAttribute('endFilePos') + 1, Type::getStringFromFQCLN($fq_class_name, $source->getNamespace(), $source->getAliasedClassesFlipped(), null)); FileManipulationBuffer::add($source->getFilePath(), $file_manipulations); } return \true; } return \false; } /** * @param lowercase-string|null $calling_method_id */ public function handleDocblockTypeInMigration(Codebase $codebase, StatementsSource $source, Union $type, CodeLocation $type_location, ?string $calling_method_id) : void { $calling_fq_class_name = $source->getFQCLN(); $fq_class_name_lc = strtolower($calling_fq_class_name ?? ''); $moved_type = \false; // if we're inside a moved class static method if ($codebase->methods_to_move && $calling_fq_class_name && $calling_method_id && isset($codebase->methods_to_move[$calling_method_id])) { $bounds = $type_location->getSelectionBounds(); $destination_class = explode('::', $codebase->methods_to_move[$calling_method_id])[0]; $this->airliftClassDefinedDocblockType($type, $destination_class, $source->getFilePath(), $bounds[0], $bounds[1]); $moved_type = \true; } // if we're outside a moved class, but we're changing all references to a class if (!$moved_type && $codebase->class_transforms) { $uses_flipped = $source->getAliasedClassesFlipped(); $uses_flipped_replaceable = $source->getAliasedClassesFlippedReplaceable(); $migrated_source_fqcln = $calling_fq_class_name; if ($calling_fq_class_name && isset($codebase->class_transforms[$fq_class_name_lc])) { $migrated_source_fqcln = $codebase->class_transforms[$fq_class_name_lc]; } $source_namespace = $source->getNamespace(); if ($migrated_source_fqcln && $calling_fq_class_name !== $migrated_source_fqcln) { $new_source_parts = explode('\\', $migrated_source_fqcln, -1); $source_namespace = implode('\\', $new_source_parts); } foreach ($codebase->class_transforms as $old_fq_class_name => $new_fq_class_name) { if (isset($uses_flipped_replaceable[$old_fq_class_name])) { $alias = $uses_flipped_replaceable[$old_fq_class_name]; unset($uses_flipped[$old_fq_class_name]); $old_class_name_parts = explode('\\', $old_fq_class_name); $old_class_name = end($old_class_name_parts); if ($old_class_name === strtolower($alias)) { $new_class_name_parts = explode('\\', $new_fq_class_name); $new_class_name = end($new_class_name_parts); $uses_flipped[strtolower($new_fq_class_name)] = $new_class_name; } else { $uses_flipped[strtolower($new_fq_class_name)] = $alias; } } } foreach ($codebase->class_transforms as $old_fq_class_name => $new_fq_class_name) { if ($type->containsClassLike($old_fq_class_name)) { $type = $type->replaceClassLike($old_fq_class_name, $new_fq_class_name); $bounds = $type_location->getSelectionBounds(); $file_manipulations = []; $file_manipulations[] = new FileManipulation($bounds[0], $bounds[1], $type->toNamespacedString($source_namespace, $uses_flipped, $migrated_source_fqcln, \false)); FileManipulationBuffer::add($source->getFilePath(), $file_manipulations); $moved_type = \true; } } } // if we're inside a moved class (could be a method, could be a property/class const default) if (!$moved_type && $codebase->classes_to_move && $calling_fq_class_name && isset($codebase->classes_to_move[$fq_class_name_lc])) { $bounds = $type_location->getSelectionBounds(); $destination_class = $codebase->classes_to_move[$fq_class_name_lc]; if ($type->containsClassLike($fq_class_name_lc)) { $type = $type->replaceClassLike($fq_class_name_lc, $destination_class); } $this->airliftClassDefinedDocblockType($type, $destination_class, $source->getFilePath(), $bounds[0], $bounds[1]); } } public function airliftClassLikeReference(string $fq_class_name, string $destination_fq_class_name, string $source_file_path, int $source_start, int $source_end, bool $add_class_constant = \false, bool $allow_self = \false) : void { $project_analyzer = ProjectAnalyzer::getInstance(); $codebase = $project_analyzer->getCodebase(); $destination_class_storage = $codebase->classlike_storage_provider->get($destination_fq_class_name); if (!$destination_class_storage->aliases) { throw new UnexpectedValueException('Aliases should not be null'); } $file_manipulations = []; $file_manipulations[] = new FileManipulation($source_start, $source_end, Type::getStringFromFQCLN($fq_class_name, $destination_class_storage->aliases->namespace, $destination_class_storage->aliases->uses_flipped, $destination_class_storage->name, $allow_self) . ($add_class_constant ? '::class' : '')); FileManipulationBuffer::add($source_file_path, $file_manipulations); } public function airliftClassDefinedDocblockType(Union $type, string $destination_fq_class_name, string $source_file_path, int $source_start, int $source_end) : void { $project_analyzer = ProjectAnalyzer::getInstance(); $codebase = $project_analyzer->getCodebase(); $destination_class_storage = $codebase->classlike_storage_provider->get($destination_fq_class_name); if (!$destination_class_storage->aliases) { throw new UnexpectedValueException('Aliases should not be null'); } $file_manipulations = []; $file_manipulations[] = new FileManipulation($source_start, $source_end, $type->toNamespacedString($destination_class_storage->aliases->namespace, $destination_class_storage->aliases->uses_flipped, $destination_class_storage->name, \false)); FileManipulationBuffer::add($source_file_path, $file_manipulations); } /** * @param ReflectionProperty::IS_PUBLIC|ReflectionProperty::IS_PROTECTED|ReflectionProperty::IS_PRIVATE * $visibility * @return array */ public function getConstantsForClass(string $class_name, int $visibility) : array { $class_name = strtolower($class_name); $storage = $this->classlike_storage_provider->get($class_name); if ($visibility === ReflectionProperty::IS_PUBLIC) { return array_filter($storage->constants, static fn(ClassConstantStorage $constant): bool => $constant->type && $constant->visibility === ClassLikeAnalyzer::VISIBILITY_PUBLIC); } if ($visibility === ReflectionProperty::IS_PROTECTED) { return array_filter($storage->constants, static fn(ClassConstantStorage $constant): bool => $constant->type && ($constant->visibility === ClassLikeAnalyzer::VISIBILITY_PUBLIC || $constant->visibility === ClassLikeAnalyzer::VISIBILITY_PROTECTED)); } return array_filter($storage->constants, static fn(ClassConstantStorage $constant): bool => $constant->type !== null); } /** * @param ReflectionProperty::IS_PUBLIC|ReflectionProperty::IS_PROTECTED|ReflectionProperty::IS_PRIVATE $visibility */ public function getClassConstantType(string $class_name, string $constant_name, int $visibility, ?StatementsAnalyzer $statements_analyzer = null, array $visited_constant_ids = [], bool $late_static_binding = \false, bool $in_value_of_context = \false) : ?Union { $class_name = strtolower($class_name); if (!$this->classlike_storage_provider->has($class_name)) { return null; } $storage = $this->classlike_storage_provider->get($class_name); $enum_types = null; if ($storage->is_enum) { $enum_types = $this->getEnumType($storage, $constant_name); if ($in_value_of_context) { return $enum_types; } } $constant_types = $this->getConstantType($storage, $constant_name, $visibility, $statements_analyzer, $visited_constant_ids, $late_static_binding); $types = []; if ($enum_types !== null) { $types = array_merge($types, $enum_types->getAtomicTypes()); } if ($constant_types !== null) { $types = array_merge($types, $constant_types->getAtomicTypes()); } if ($types === []) { return null; } return new Union($types); } private function checkMethodReferences(ClassLikeStorage $classlike_storage, \Psalm\Internal\Codebase\Methods $methods) : void { $project_analyzer = ProjectAnalyzer::getInstance(); $codebase = $project_analyzer->getCodebase(); foreach ($classlike_storage->appearing_method_ids as $method_name => $appearing_method_id) { $appearing_fq_classlike_name = $appearing_method_id->fq_class_name; if ($appearing_fq_classlike_name !== $classlike_storage->name) { continue; } $method_id = $appearing_method_id; $declaring_classlike_storage = $classlike_storage; if (isset($classlike_storage->methods[$method_name])) { $method_storage = $classlike_storage->methods[$method_name]; } else { $declaring_method_id = $classlike_storage->declaring_method_ids[$method_name]; $declaring_fq_classlike_name = $declaring_method_id->fq_class_name; $declaring_method_name = $declaring_method_id->method_name; try { $declaring_classlike_storage = $this->classlike_storage_provider->get($declaring_fq_classlike_name); } catch (InvalidArgumentException $e) { continue; } $method_storage = $declaring_classlike_storage->methods[$declaring_method_name]; $method_id = $declaring_method_id; } if ($classlike_storage->public_api && ($method_storage->visibility === ClassLikeAnalyzer::VISIBILITY_PUBLIC || $method_storage->visibility === ClassLikeAnalyzer::VISIBILITY_PROTECTED && !$classlike_storage->final)) { continue; } if ($method_storage->public_api) { continue; } if ($method_storage->location && !$project_analyzer->canReportIssues($method_storage->location->file_path) && !$codebase->analyzer->canReportIssues($method_storage->location->file_path)) { continue; } $method_referenced = $this->file_reference_provider->isClassMethodReferenced(strtolower((string) $method_id)); if (!$method_referenced && $method_storage->location) { if ($method_name !== '__destruct' && $method_name !== '__clone' && $method_name !== '__invoke' && $method_name !== '__unset' && $method_name !== '__isset' && $method_name !== '__sleep' && $method_name !== '__wakeup' && $method_name !== '__serialize' && $method_name !== '__unserialize' && $method_name !== '__set_state' && $method_name !== '__debuginfo' && $method_name !== '__tostring') { $method_location = $method_storage->location; $method_id = $classlike_storage->name . '::' . $method_storage->cased_name; if ($method_storage->visibility !== ClassLikeAnalyzer::VISIBILITY_PRIVATE) { $has_parent_references = \false; if ($codebase->classImplements($classlike_storage->name, 'Serializable') && ($method_name === 'serialize' || $method_name === 'unserialize')) { continue; } if ($codebase->classImplements($classlike_storage->name, 'JsonSerializable') && $method_name === 'jsonserialize') { continue; } $has_variable_calls = $codebase->analyzer->hasMixedMemberName($method_name) || $codebase->analyzer->hasMixedMemberName(strtolower($classlike_storage->name . '::')); if (isset($classlike_storage->overridden_method_ids[$method_name])) { foreach ($classlike_storage->overridden_method_ids[$method_name] as $parent_method_id) { $parent_method_storage = $methods->getStorage($parent_method_id); if ($parent_method_storage->location && !$project_analyzer->canReportIssues($parent_method_storage->location->file_path)) { // here we just don’t know $has_parent_references = \true; break; } $parent_method_referenced = $this->file_reference_provider->isClassMethodReferenced(strtolower((string) $parent_method_id)); if (!$parent_method_storage->abstract || $parent_method_referenced) { $has_parent_references = \true; break; } } } foreach ($classlike_storage->parent_classes as $parent_method_fqcln) { if ($codebase->analyzer->hasMixedMemberName(strtolower($parent_method_fqcln) . '::')) { $has_variable_calls = \true; break; } } foreach ($classlike_storage->class_implements as $fq_interface_name_lc => $_) { try { $interface_storage = $this->classlike_storage_provider->get($fq_interface_name_lc); } catch (InvalidArgumentException $e) { continue; } if ($codebase->analyzer->hasMixedMemberName($fq_interface_name_lc . '::')) { $has_variable_calls = \true; } if (isset($interface_storage->methods[$method_name])) { $interface_method_referenced = $this->file_reference_provider->isClassMethodReferenced($fq_interface_name_lc . '::' . $method_name); if ($interface_method_referenced) { $has_parent_references = \true; } } } if (!$has_parent_references) { $issue = new PossiblyUnusedMethod('Cannot find ' . ($has_variable_calls ? 'explicit' : 'any') . ' calls to method ' . $method_id . ($has_variable_calls ? ' (but did find some potential callers)' : ''), $method_storage->location, $method_id); if ($codebase->alter_code) { if ($method_storage->stmt_location && !$declaring_classlike_storage->is_trait && isset($project_analyzer->getIssuesToFix()['PossiblyUnusedMethod']) && !$has_variable_calls && !IssueBuffer::isSuppressed($issue, $method_storage->suppressed_issues)) { FileManipulationBuffer::addForCodeLocation($method_storage->stmt_location, '', \true); } } else { IssueBuffer::maybeAdd($issue, $method_storage->suppressed_issues, $method_storage->stmt_location && !$declaring_classlike_storage->is_trait && !$has_variable_calls); } } } elseif (!isset($classlike_storage->declaring_method_ids['__call'])) { $has_variable_calls = $codebase->analyzer->hasMixedMemberName(strtolower($classlike_storage->name . '::')) || $codebase->analyzer->hasMixedMemberName($method_name); if ($method_name === '__construct') { $issue = new UnusedConstructor('Cannot find ' . ($has_variable_calls ? 'explicit' : 'any') . ' calls to private constructor ' . $method_id . ($has_variable_calls ? ' (but did find some potential callers)' : ''), $method_location, $method_id); } else { $issue = new UnusedMethod('Cannot find ' . ($has_variable_calls ? 'explicit' : 'any') . ' calls to private method ' . $method_id . ($has_variable_calls ? ' (but did find some potential callers)' : ''), $method_location, $method_id); } if ($codebase->alter_code) { if ($method_storage->stmt_location && !$declaring_classlike_storage->is_trait && isset($project_analyzer->getIssuesToFix()['UnusedMethod']) && !$has_variable_calls && !IssueBuffer::isSuppressed($issue, $method_storage->suppressed_issues)) { FileManipulationBuffer::addForCodeLocation($method_storage->stmt_location, '', \true); } } else { IssueBuffer::maybeAdd($issue, $method_storage->suppressed_issues, $method_storage->stmt_location && !$declaring_classlike_storage->is_trait && !$has_variable_calls); } } } } else { if ($method_storage->return_type && $method_storage->return_type_location && !$method_storage->return_type->isVoid() && !$method_storage->return_type->isNever() && $method_id->method_name !== '__tostring' && ($method_storage->is_static || !$method_storage->probably_fluent)) { $method_return_referenced = $this->file_reference_provider->isMethodReturnReferenced(strtolower((string) $method_id)); if (!$method_return_referenced) { if ($method_storage->visibility === ClassLikeAnalyzer::VISIBILITY_PRIVATE) { IssueBuffer::maybeAdd(new UnusedReturnValue('The return value for this private method is never used', $method_storage->return_type_location), $method_storage->suppressed_issues); } else { IssueBuffer::maybeAdd(new PossiblyUnusedReturnValue('The return value for this method is never used', $method_storage->return_type_location), $method_storage->suppressed_issues); } } } } } } private function checkMethodParamReferences(ClassLikeStorage $classlike_storage) : void { foreach ($classlike_storage->appearing_method_ids as $method_name => $appearing_method_id) { $appearing_fq_classlike_name = $appearing_method_id->fq_class_name; if ($appearing_fq_classlike_name !== $classlike_storage->name) { continue; } $method_id = $appearing_method_id; if (isset($classlike_storage->methods[$method_name])) { $method_storage = $classlike_storage->methods[$method_name]; } else { $declaring_method_id = $classlike_storage->declaring_method_ids[$method_name]; $declaring_fq_classlike_name = $declaring_method_id->fq_class_name; $declaring_method_name = $declaring_method_id->method_name; try { $declaring_classlike_storage = $this->classlike_storage_provider->get($declaring_fq_classlike_name); } catch (InvalidArgumentException $e) { continue; } $method_storage = $declaring_classlike_storage->methods[$declaring_method_name]; $method_id = $declaring_method_id; } if ($method_storage->visibility !== ClassLikeAnalyzer::VISIBILITY_PRIVATE && !$classlike_storage->is_interface) { foreach ($method_storage->params as $offset => $param_storage) { if (empty($classlike_storage->overridden_method_ids[$method_name]) && $param_storage->location && !$param_storage->promoted_property && !$this->file_reference_provider->isMethodParamUsed(strtolower((string) $method_id), $offset)) { if ($method_storage->final) { IssueBuffer::maybeAdd(new UnusedParam('Param #' . ($offset + 1) . ' is never referenced in this method', $param_storage->location), $method_storage->suppressed_issues); } else { IssueBuffer::maybeAdd(new PossiblyUnusedParam('Param #' . ($offset + 1) . ' is never referenced in this method', $param_storage->location), $method_storage->suppressed_issues); } } } } } } private function findPossibleMethodParamTypes(ClassLikeStorage $classlike_storage) : void { $project_analyzer = ProjectAnalyzer::getInstance(); $codebase = $project_analyzer->getCodebase(); foreach ($classlike_storage->appearing_method_ids as $method_name => $appearing_method_id) { $appearing_fq_classlike_name = $appearing_method_id->fq_class_name; if ($appearing_fq_classlike_name !== $classlike_storage->name) { continue; } $method_id = $appearing_method_id; $declaring_classlike_storage = $classlike_storage; if (isset($classlike_storage->methods[$method_name])) { $method_storage = $classlike_storage->methods[$method_name]; } else { $declaring_method_id = $classlike_storage->declaring_method_ids[$method_name]; $declaring_fq_classlike_name = $declaring_method_id->fq_class_name; $declaring_method_name = $declaring_method_id->method_name; try { $declaring_classlike_storage = $this->classlike_storage_provider->get($declaring_fq_classlike_name); } catch (InvalidArgumentException $e) { continue; } $method_storage = $declaring_classlike_storage->methods[$declaring_method_name]; $method_id = $declaring_method_id; } if ($method_storage->location && !$project_analyzer->canReportIssues($method_storage->location->file_path) && !$codebase->analyzer->canReportIssues($method_storage->location->file_path)) { continue; } if ($declaring_classlike_storage->is_trait) { continue; } $method_id_lc = strtolower((string) $method_id); if (isset($codebase->analyzer->possible_method_param_types[$method_id_lc])) { if ($method_storage->location) { $possible_param_types = $codebase->analyzer->possible_method_param_types[$method_id_lc]; if ($possible_param_types) { foreach ($possible_param_types as $offset => $possible_type) { if (!isset($method_storage->params[$offset])) { continue; } $param_name = $method_storage->params[$offset]->name; if ($possible_type->hasMixed() || $possible_type->isNull()) { continue; } if ($method_storage->params[$offset]->default_type) { if ($method_storage->params[$offset]->default_type instanceof Union) { $default_type = $method_storage->params[$offset]->default_type; } else { $default_type_atomic = \Psalm\Internal\Codebase\ConstantTypeResolver::resolve($codebase->classlikes, $method_storage->params[$offset]->default_type, null); $default_type = new Union([$default_type_atomic]); } $possible_type = Type::combineUnionTypes($possible_type, $default_type); } if ($codebase->alter_code && isset($project_analyzer->getIssuesToFix()['MissingParamType'])) { $function_analyzer = $project_analyzer->getFunctionLikeAnalyzer($method_id, $method_storage->location->file_path); $has_variable_calls = $codebase->analyzer->hasMixedMemberName($method_name) || $codebase->analyzer->hasMixedMemberName(strtolower($classlike_storage->name . '::')); if ($has_variable_calls) { $possible_type = $possible_type->setProperties(['from_docblock' => \true]); } if ($function_analyzer) { $function_analyzer->addOrUpdateParamType($project_analyzer, $param_name, $possible_type, $possible_type->from_docblock && $project_analyzer->only_replace_php_types_with_non_docblock_types); } } else { IssueBuffer::addFixableIssue('MissingParamType'); } } } } } } } private function checkPropertyReferences(ClassLikeStorage $classlike_storage) : void { $project_analyzer = ProjectAnalyzer::getInstance(); $codebase = $project_analyzer->getCodebase(); foreach ($classlike_storage->properties as $property_name => $property_storage) { if ($classlike_storage->public_api && ($property_storage->visibility === ClassLikeAnalyzer::VISIBILITY_PUBLIC || $property_storage->visibility === ClassLikeAnalyzer::VISIBILITY_PROTECTED && !$classlike_storage->final)) { continue; } $referenced_property_name = strtolower($classlike_storage->name) . '::$' . $property_name; $property_referenced = $this->file_reference_provider->isClassPropertyReferenced($referenced_property_name); $property_constructor_referenced = \false; if ($property_referenced && $property_storage->visibility === ClassLikeAnalyzer::VISIBILITY_PRIVATE) { $all_method_references = $this->file_reference_provider->getAllMethodReferencesToClassProperties(); if (isset($all_method_references[$referenced_property_name]) && count($all_method_references[$referenced_property_name]) === 1) { $constructor_name = strtolower($classlike_storage->name) . '::__construct'; $property_references = $all_method_references[$referenced_property_name]; $property_constructor_referenced = isset($property_references[$constructor_name]) && !$property_storage->is_static; } } if ((!$property_referenced || $property_constructor_referenced) && $property_storage->location) { $property_id = $classlike_storage->name . '::$' . $property_name; if ($property_storage->visibility === ClassLikeAnalyzer::VISIBILITY_PUBLIC || $property_storage->visibility === ClassLikeAnalyzer::VISIBILITY_PROTECTED) { $has_parent_references = isset($classlike_storage->overridden_property_ids[$property_name]); $has_variable_calls = $codebase->analyzer->hasMixedMemberName('$' . $property_name) || $codebase->analyzer->hasMixedMemberName(strtolower($classlike_storage->name) . '::$'); foreach ($classlike_storage->parent_classes as $parent_method_fqcln) { if ($codebase->analyzer->hasMixedMemberName(strtolower($parent_method_fqcln) . '::$')) { $has_variable_calls = \true; break; } } foreach ($classlike_storage->class_implements as $fq_interface_name) { if ($codebase->analyzer->hasMixedMemberName(strtolower($fq_interface_name) . '::$')) { $has_variable_calls = \true; break; } } if (!$has_parent_references && ($property_storage->visibility === ClassLikeAnalyzer::VISIBILITY_PUBLIC || !isset($classlike_storage->declaring_method_ids['__get']))) { $issue = new PossiblyUnusedProperty('Cannot find ' . ($has_variable_calls ? 'explicit' : 'any') . ' references to property ' . $property_id . ($has_variable_calls ? ' (but did find some potential references)' : ''), $property_storage->location, $property_id); if ($codebase->alter_code) { if ($property_storage->stmt_location && isset($project_analyzer->getIssuesToFix()['PossiblyUnusedProperty']) && !$has_variable_calls && !IssueBuffer::isSuppressed($issue, $classlike_storage->suppressed_issues)) { FileManipulationBuffer::addForCodeLocation($property_storage->stmt_location, '', \true); } } else { IssueBuffer::maybeAdd($issue, $classlike_storage->suppressed_issues + $property_storage->suppressed_issues); } } } elseif (!isset($classlike_storage->declaring_method_ids['__get'])) { $has_variable_calls = $codebase->analyzer->hasMixedMemberName('$' . $property_name); $issue = new UnusedProperty('Cannot find ' . ($has_variable_calls ? 'explicit' : 'any') . ' references to private property ' . $property_id . ($has_variable_calls ? ' (but did find some potential references)' : ''), $property_storage->location, $property_id); if ($codebase->alter_code) { if (!$property_constructor_referenced && $property_storage->stmt_location && isset($project_analyzer->getIssuesToFix()['UnusedProperty']) && !$has_variable_calls && !IssueBuffer::isSuppressed($issue, $classlike_storage->suppressed_issues)) { FileManipulationBuffer::addForCodeLocation($property_storage->stmt_location, '', \true); } } else { IssueBuffer::maybeAdd($issue, $classlike_storage->suppressed_issues + $property_storage->suppressed_issues); } } } } } /** * @param lowercase-string $fq_classlike_name_lc */ public function registerMissingClassLike(string $fq_classlike_name_lc) : void { $this->existing_classlikes_lc[$fq_classlike_name_lc] = \false; } /** * @param lowercase-string $fq_classlike_name_lc */ public function isMissingClassLike(string $fq_classlike_name_lc) : bool { return isset($this->existing_classlikes_lc[$fq_classlike_name_lc]) && $this->existing_classlikes_lc[$fq_classlike_name_lc] === \false; } /** * @param lowercase-string $fq_classlike_name_lc */ public function doesClassLikeExist(string $fq_classlike_name_lc) : bool { return isset($this->existing_classlikes_lc[$fq_classlike_name_lc]) && $this->existing_classlikes_lc[$fq_classlike_name_lc]; } public function forgetMissingClassLikes() : void { $this->existing_classlikes_lc = array_filter($this->existing_classlikes_lc); } public function removeClassLike(string $fq_class_name) : void { $fq_class_name_lc = strtolower($fq_class_name); unset($this->existing_classlikes_lc[$fq_class_name_lc], $this->existing_traits_lc[$fq_class_name_lc], $this->existing_traits[$fq_class_name], $this->existing_enums_lc[$fq_class_name_lc], $this->existing_enums[$fq_class_name], $this->existing_interfaces_lc[$fq_class_name_lc], $this->existing_interfaces[$fq_class_name], $this->existing_classes_lc[$fq_class_name_lc], $this->existing_classes[$fq_class_name], $this->trait_nodes[$fq_class_name_lc]); $this->scanner->removeClassLike($fq_class_name_lc); } /** * @return array{ * array, * array, * array, * array, * array, * array, * array, * array, * array, * } */ public function getThreadData() : array { return [$this->existing_classlikes_lc, $this->existing_classes_lc, $this->existing_traits_lc, $this->existing_traits, $this->existing_enums_lc, $this->existing_enums, $this->existing_interfaces_lc, $this->existing_interfaces, $this->existing_classes]; } /** * @param array{ * 0: array, * 1: array, * 2: array, * 3: array, * 4: array, * 5: array, * 6: array, * 7: array, * 8: array, * } $thread_data */ public function addThreadData(array $thread_data) : void { [$existing_classlikes_lc, $existing_classes_lc, $existing_traits_lc, $existing_traits, $existing_enums_lc, $existing_enums, $existing_interfaces_lc, $existing_interfaces, $existing_classes] = $thread_data; $this->existing_classlikes_lc = self::mergeThreadData($existing_classlikes_lc, $this->existing_classlikes_lc); $this->existing_classes_lc = self::mergeThreadData($existing_classes_lc, $this->existing_classes_lc); $this->existing_traits_lc = self::mergeThreadData($existing_traits_lc, $this->existing_traits_lc); $this->existing_traits = self::mergeThreadData($existing_traits, $this->existing_traits); $this->existing_enums_lc = self::mergeThreadData($existing_enums_lc, $this->existing_enums_lc); $this->existing_enums = self::mergeThreadData($existing_enums, $this->existing_enums); $this->existing_interfaces_lc = self::mergeThreadData($existing_interfaces_lc, $this->existing_interfaces_lc); $this->existing_interfaces = self::mergeThreadData($existing_interfaces, $this->existing_interfaces); $this->existing_classes = self::mergeThreadData($existing_classes, $this->existing_classes); } /** * @template T as string|lowercase-string * @param array $old * @param array $new * @return array */ private static function mergeThreadData(array $old, array $new) : array { foreach ($new as $name => $value) { if (!isset($old[$name]) || !$old[$name] && $value) { $old[$name] = $value; } } return $old; } public function getStorageFor(string $fq_class_name) : ?ClassLikeStorage { $fq_class_name = $this->getUnAliasedName($fq_class_name); try { return $this->classlike_storage_provider->get($fq_class_name); } catch (InvalidArgumentException $e) { return null; } } private function getConstantType(ClassLikeStorage $class_like_storage, string $constant_name, int $visibility, ?StatementsAnalyzer $statements_analyzer, array $visited_constant_ids, bool $late_static_binding) : ?Union { $constant_resolver = new \Psalm\Internal\Codebase\StorageByPatternResolver(); $resolved_constants = $constant_resolver->resolveConstants($class_like_storage, $constant_name); $filtered_constants_by_visibility = array_filter($resolved_constants, fn(ClassConstantStorage $resolved_constant) => $this->filterConstantNameByVisibility($resolved_constant, $visibility)); if ($filtered_constants_by_visibility === []) { return null; } $new_atomic_types = []; foreach ($filtered_constants_by_visibility as $filtered_constant_name => $constant_storage) { if (!isset($class_like_storage->constants[$filtered_constant_name])) { continue; } if ($constant_storage->unresolved_node) { /** @psalm-suppress InaccessibleProperty Lazy resolution */ $constant_storage->inferred_type = new Union([\Psalm\Internal\Codebase\ConstantTypeResolver::resolve($this, $constant_storage->unresolved_node, $statements_analyzer, $visited_constant_ids)]); if ($constant_storage->type === null || !$constant_storage->type->from_docblock) { /** @psalm-suppress InaccessibleProperty Lazy resolution */ $constant_storage->type = $constant_storage->inferred_type; } } $constant_type = $late_static_binding ? $constant_storage->type : $constant_storage->inferred_type ?? null; if ($constant_type === null) { continue; } $new_atomic_types[] = $constant_type->getAtomicTypes(); } if ($new_atomic_types === []) { return null; } return new Union(array_merge([], ...$new_atomic_types)); } private function getEnumType(ClassLikeStorage $class_like_storage, string $constant_name) : ?Union { $constant_resolver = new \Psalm\Internal\Codebase\StorageByPatternResolver(); $resolved_enums = $constant_resolver->resolveEnums($class_like_storage, $constant_name); if ($resolved_enums === []) { return null; } $types = []; foreach (array_keys($resolved_enums) as $enum_case_name) { $types[$enum_case_name] = new TEnumCase($class_like_storage->name, $enum_case_name); } return new Union($types); } private function filterConstantNameByVisibility(ClassConstantStorage $constant_storage, int $visibility) : bool { if ($visibility === ReflectionProperty::IS_PUBLIC && $constant_storage->visibility !== ClassLikeAnalyzer::VISIBILITY_PUBLIC) { return \false; } if ($visibility === ReflectionProperty::IS_PROTECTED && $constant_storage->visibility !== ClassLikeAnalyzer::VISIBILITY_PUBLIC && $constant_storage->visibility !== ClassLikeAnalyzer::VISIBILITY_PROTECTED) { return \false; } return \true; } } */ private array $sources = []; /** @var array */ private array $nodes = []; /** @var array */ private array $sinks = []; /** @var array> */ private array $specialized_calls = []; /** @var array> */ private array $specializations = []; public function addNode(DataFlowNode $node) : void { $this->nodes[$node->id] = $node; if ($node->unspecialized_id && $node->specialization_key) { $this->specialized_calls[$node->specialization_key][$node->unspecialized_id] = \true; $this->specializations[$node->unspecialized_id][$node->specialization_key] = \true; } } public function addSource(TaintSource $node) : void { $this->sources[$node->id] = $node; } public function addSink(TaintSink $node) : void { $this->sinks[$node->id] = $node; // in the rare case the sink is the _next_ node, this is necessary $this->nodes[$node->id] = $node; } public function addGraph(self $taint) : void { $this->sources += $taint->sources; $this->sinks += $taint->sinks; $this->nodes += $taint->nodes; $this->specialized_calls += $taint->specialized_calls; foreach ($taint->forward_edges as $key => $map) { if (!isset($this->forward_edges[$key])) { $this->forward_edges[$key] = $map; } else { $this->forward_edges[$key] += $map; } } foreach ($taint->specializations as $key => $map) { if (!isset($this->specializations[$key])) { $this->specializations[$key] = $map; } else { $this->specializations[$key] += $map; } } } public function getPredecessorPath(DataFlowNode $source) : string { $location_summary = ''; if ($source->code_location) { $location_summary = $source->code_location->getShortSummary(); } $source_descriptor = $source->label . ($location_summary ? ' (' . $location_summary . ')' : ''); $previous_source = $source->previous; if ($previous_source) { if ($previous_source === $source) { return ''; } if ($source->code_location && $previous_source->code_location && $previous_source->code_location->getHash() === $source->code_location->getHash() && $previous_source->previous) { return $this->getPredecessorPath($previous_source->previous) . ' -> ' . $source_descriptor; } return $this->getPredecessorPath($previous_source) . ' -> ' . $source_descriptor; } return $source_descriptor; } public function getSuccessorPath(DataFlowNode $sink) : string { $location_summary = ''; if ($sink->code_location) { $location_summary = $sink->code_location->getShortSummary(); } $sink_descriptor = $sink->label . ($location_summary ? ' (' . $location_summary . ')' : ''); $next_sink = $sink->previous; if ($next_sink) { if ($next_sink === $sink) { return ''; } if ($sink->code_location && $next_sink->code_location && $next_sink->code_location->getHash() === $sink->code_location->getHash() && $next_sink->previous) { return $sink_descriptor . ' -> ' . $this->getSuccessorPath($next_sink->previous); } return $sink_descriptor . ' -> ' . $this->getSuccessorPath($next_sink); } return $sink_descriptor; } /** * @return list */ public function getIssueTrace(DataFlowNode $source) : array { $previous_source = $source->previous; $node = ['location' => $source->code_location, 'label' => $source->label, 'entry_path_type' => end($source->path_types) ?: '']; if ($previous_source) { if ($previous_source === $source) { return []; } return [...$this->getIssueTrace($previous_source), ...[$node]]; } return [$node]; } public function connectSinksAndSources() : void { $visited_source_ids = []; $sources = $this->sources; $sinks = $this->sinks; ksort($this->specializations); ksort($this->forward_edges); // reprocess resolved descendants up to a maximum nesting level of 40 for ($i = 0; count($sinks) && count($sources) && $i < 40; $i++) { $new_sources = []; ksort($sources); foreach ($sources as $source) { $source_taints = $source->taints; sort($source_taints); $visited_source_ids[$source->id][implode(',', $source_taints)] = \true; $generated_sources = $this->getSpecializedSources($source); foreach ($generated_sources as $generated_source) { $new_sources = array_merge($new_sources, $this->getChildNodes($generated_source, $source_taints, $sinks, $visited_source_ids)); } } $sources = $new_sources; } } /** * @param array $source_taints * @param array $sinks * @return array */ private function getChildNodes(DataFlowNode $generated_source, array $source_taints, array $sinks, array $visited_source_ids) : array { $new_sources = []; $config = Config::getInstance(); $project_analyzer = ProjectAnalyzer::getInstance(); foreach ($this->forward_edges[$generated_source->id] as $to_id => $path) { $path_type = $path->type; $added_taints = $path->unescaped_taints ?: []; $removed_taints = $path->escaped_taints ?: []; if (!isset($this->nodes[$to_id])) { continue; } $destination_node = $this->nodes[$to_id]; $new_taints = array_unique(array_diff(array_merge($source_taints, $added_taints), $removed_taints)); sort($new_taints); if (isset($visited_source_ids[$to_id][implode(',', $new_taints)])) { continue; } if (self::shouldIgnoreFetch($path_type, 'arraykey', $generated_source->path_types)) { continue; } if (self::shouldIgnoreFetch($path_type, 'arrayvalue', $generated_source->path_types)) { continue; } if (self::shouldIgnoreFetch($path_type, 'property', $generated_source->path_types)) { continue; } if ($generated_source->code_location && $project_analyzer->canReportIssues($generated_source->code_location->file_path) && !$config->reportIssueInFile('TaintedInput', $generated_source->code_location->file_path)) { continue; } if (isset($sinks[$to_id])) { $matching_taints = array_intersect($sinks[$to_id]->taints, $new_taints); if ($matching_taints && $generated_source->code_location) { if ($sinks[$to_id]->code_location && $config->reportIssueInFile('TaintedInput', $sinks[$to_id]->code_location->file_path)) { $issue_location = $sinks[$to_id]->code_location; } else { $issue_location = $generated_source->code_location; } $issue_trace = $this->getIssueTrace($generated_source); $path = $this->getPredecessorPath($generated_source) . ' -> ' . $this->getSuccessorPath($sinks[$to_id]); foreach ($matching_taints as $matching_taint) { switch ($matching_taint) { case TaintKind::INPUT_CALLABLE: $issue = new TaintedCallable('Detected tainted text', $issue_location, $issue_trace, $path); break; case TaintKind::INPUT_UNSERIALIZE: $issue = new TaintedUnserialize('Detected tainted code passed to unserialize or similar', $issue_location, $issue_trace, $path); break; case TaintKind::INPUT_INCLUDE: $issue = new TaintedInclude('Detected tainted code passed to include or similar', $issue_location, $issue_trace, $path); break; case TaintKind::INPUT_EVAL: $issue = new TaintedEval('Detected tainted code passed to eval or similar', $issue_location, $issue_trace, $path); break; case TaintKind::INPUT_SQL: $issue = new TaintedSql('Detected tainted SQL', $issue_location, $issue_trace, $path); break; case TaintKind::INPUT_HTML: $issue = new TaintedHtml('Detected tainted HTML', $issue_location, $issue_trace, $path); break; case TaintKind::INPUT_HAS_QUOTES: $issue = new TaintedTextWithQuotes('Detected tainted text with possible quotes', $issue_location, $issue_trace, $path); break; case TaintKind::INPUT_SHELL: $issue = new TaintedShell('Detected tainted shell code', $issue_location, $issue_trace, $path); break; case TaintKind::USER_SECRET: $issue = new TaintedUserSecret('Detected tainted user secret leaking', $issue_location, $issue_trace, $path); break; case TaintKind::SYSTEM_SECRET: $issue = new TaintedSystemSecret('Detected tainted system secret leaking', $issue_location, $issue_trace, $path); break; case TaintKind::INPUT_SSRF: $issue = new TaintedSSRF('Detected tainted network request', $issue_location, $issue_trace, $path); break; case TaintKind::INPUT_LDAP: $issue = new TaintedLdap('Detected tainted LDAP request', $issue_location, $issue_trace, $path); break; case TaintKind::INPUT_COOKIE: $issue = new TaintedCookie('Detected tainted cookie', $issue_location, $issue_trace, $path); break; case TaintKind::INPUT_FILE: $issue = new TaintedFile('Detected tainted file handling', $issue_location, $issue_trace, $path); break; case TaintKind::INPUT_HEADER: $issue = new TaintedHeader('Detected tainted header', $issue_location, $issue_trace, $path); break; default: $issue = new TaintedCustom('Detected tainted ' . $matching_taint, $issue_location, $issue_trace, $path); } IssueBuffer::maybeAdd($issue); } } } $new_destination = clone $destination_node; $new_destination->previous = $generated_source; $new_destination->taints = $new_taints; $new_destination->specialized_calls = $generated_source->specialized_calls; $new_destination->path_types = [...$generated_source->path_types, ...[$path_type]]; $key = $to_id . ' ' . json_encode($new_destination->specialized_calls, JSON_THROW_ON_ERROR) . ' ' . json_encode($new_destination->taints, JSON_THROW_ON_ERROR); $new_sources[$key] = $new_destination; } return $new_sources; } /** @return array */ private function getSpecializedSources(DataFlowNode $source) : array { $generated_sources = []; if (isset($this->forward_edges[$source->id])) { return [$source]; } if ($source->specialization_key && isset($this->specialized_calls[$source->specialization_key])) { $generated_source = clone $source; $generated_source->id = substr($source->id, 0, -strlen($source->specialization_key) - 1); $generated_source->specialized_calls[$source->specialization_key][$generated_source->id] = \true; $generated_sources[] = $generated_source; } elseif (isset($this->specializations[$source->id])) { foreach ($this->specializations[$source->id] as $specialization => $_) { if (!$source->specialized_calls || isset($source->specialized_calls[$specialization])) { $new_source = clone $source; $new_source->id = $source->id . '-' . $specialization; unset($new_source->specialized_calls[$specialization]); $generated_sources[] = $new_source; } } } else { foreach ($source->specialized_calls as $key => $map) { if (isset($map[$source->id]) && isset($this->forward_edges[$source->id . '-' . $key])) { $new_source = clone $source; $new_source->id = $source->id . '-' . $key; $generated_sources[] = $new_source; } } } return array_filter($generated_sources, [$this, 'doesForwardEdgeExist']); } private function doesForwardEdgeExist(DataFlowNode $new_source) : bool { return isset($this->forward_edges[$new_source->id]); } } */ public static function getReferenceMap(ClassLikeStorageProvider $classlike_storage_provider, array $expected_references) : array { $reference_dictionary = []; foreach ($classlike_storage_provider->getAll() as $storage) { if (!$storage->location) { continue; } $fq_classlike_name = $storage->name; if (isset($expected_references[$fq_classlike_name])) { $reference_dictionary[$fq_classlike_name] = $storage->location->file_name . ':' . $storage->location->getLineNumber() . ':' . $storage->location->getColumn(); } foreach ($storage->methods as $method_name => $method_storage) { if (!$method_storage->location) { continue; } if (isset($expected_references[$fq_classlike_name . '::' . $method_name . '()'])) { $reference_dictionary[$fq_classlike_name . '::' . $method_name . '()'] = $method_storage->location->file_name . ':' . $method_storage->location->getLineNumber() . ':' . $method_storage->location->getColumn(); } } foreach ($storage->properties as $property_name => $property_storage) { if (!$property_storage->location) { continue; } if (isset($expected_references[$fq_classlike_name . '::$' . $property_name])) { $reference_dictionary[$fq_classlike_name . '::$' . $property_name] = $property_storage->location->file_name . ':' . $property_storage->location->getLineNumber() . ':' . $property_storage->location->getColumn(); } } } return $reference_dictionary; } } */ public function resolveConstants(ClassLikeStorage $class_like_storage, string $pattern) : array { $constants = $class_like_storage->constants; if (strpos($pattern, '*') === \false) { if (isset($constants[$pattern])) { return [$pattern => $constants[$pattern]]; } return []; } elseif ($pattern === '*') { return $constants; } $regex_pattern = sprintf('#^%s$#', str_replace('*', '.*?', $pattern)); $matched_constants = []; foreach ($constants as $constant => $class_constant_storage) { if (preg_match($regex_pattern, $constant) === 0) { continue; } $matched_constants[$constant] = $class_constant_storage; } return $matched_constants; } /** * @return array */ public function resolveEnums(ClassLikeStorage $class_like_storage, string $pattern) : array { $enum_cases = $class_like_storage->enum_cases; if (strpos($pattern, '*') === \false) { if (isset($enum_cases[$pattern])) { return [$pattern => $enum_cases[$pattern]]; } return []; } elseif ($pattern === '*') { return $enum_cases; } $regex_pattern = sprintf('#^%s$#', str_replace('*', '.*?', $pattern)); $matched_enums = []; foreach ($enum_cases as $enum_case_name => $enum_case_storage) { if (preg_match($regex_pattern, $enum_case_name) === 0) { continue; } $matched_enums[$enum_case_name] = $enum_case_storage; } return $matched_enums; } } > */ protected array $forward_edges = []; public abstract function addNode(DataFlowNode $node) : void; /** * @param array $added_taints * @param array $removed_taints */ public function addPath(DataFlowNode $from, DataFlowNode $to, string $path_type, ?array $added_taints = null, ?array $removed_taints = null) : void { $from_id = $from->id; $to_id = $to->id; if ($from_id === $to_id) { return; } $length = 0; if ($from->code_location && $to->code_location && $from->code_location->file_path === $to->code_location->file_path) { $to_line = $to->code_location->raw_line_number; $from_line = $from->code_location->raw_line_number; $length = abs($to_line - $from_line); } $this->forward_edges[$from_id][$to_id] = new Path($path_type, $length, $added_taints, $removed_taints); } /** * @param array $previous_path_types * @psalm-pure */ protected static function shouldIgnoreFetch(string $path_type, string $expression_type, array $previous_path_types) : bool { $el = strlen($expression_type); // arraykey-fetch requires a matching arraykey-assignment at the same level // otherwise the tainting is not valid if (strpos($path_type, $expression_type . '-fetch-') === 0 || $path_type === 'arraykey-fetch' && $expression_type === 'arrayvalue') { $fetch_nesting = 0; $previous_path_types = array_reverse($previous_path_types); foreach ($previous_path_types as $previous_path_type) { if ($previous_path_type === $expression_type . '-assignment') { if ($fetch_nesting === 0) { return \false; } $fetch_nesting--; } if (strpos($previous_path_type, $expression_type . '-fetch') === 0) { $fetch_nesting++; } if (strpos($previous_path_type, $expression_type . '-assignment-') === 0) { if ($fetch_nesting > 0) { $fetch_nesting--; continue; } if (substr($previous_path_type, $el + 12) === substr($path_type, $el + 7)) { return \false; } return \true; } } } return \false; } /** * @return array{int, int, int, float} */ public function getEdgeStats() : array { $lengths = 0; $destination_counts = []; $origin_counts = []; foreach ($this->forward_edges as $from_id => $destinations) { foreach ($destinations as $to_id => $path) { if ($path->length === 0) { continue; } $lengths += $path->length; if (!isset($destination_counts[$to_id])) { $destination_counts[$to_id] = 0; } $destination_counts[$to_id]++; $origin_counts[$from_id] = \true; } } $count = array_sum($destination_counts); if (!$count) { return [0, 0, 0, 0.0]; } $mean = $lengths / $count; return [$count, count($origin_counts), count($destination_counts), $mean]; } /** * @psalm-return list> */ public function summarizeEdges() : array { $edges = []; foreach ($this->forward_edges as $source => $destinations) { $edges[] = [...[$source], ...array_keys($destinations)]; } return $edges; } } classlike_storage_provider = $storage_provider; $this->file_reference_provider = $file_reference_provider; $this->property_existence_provider = new PropertyExistenceProvider(); $this->property_visibility_provider = new PropertyVisibilityProvider(); $this->property_type_provider = new PropertyTypeProvider(); $this->classlikes = $classlikes; } /** * Whether or not a given property exists */ public function propertyExists(string $property_id, bool $read_mode, ?StatementsSource $source = null, ?Context $context = null, ?CodeLocation $code_location = null) : bool { // remove leading backslash if it exists $property_id = ltrim($property_id, '\\'); [$fq_class_name, $property_name] = explode('::$', $property_id); $fq_class_name_lc = strtolower($fq_class_name); if ($this->property_existence_provider->has($fq_class_name)) { $property_exists = $this->property_existence_provider->doesPropertyExist($fq_class_name, $property_name, $read_mode, $source, $context, $code_location); if ($property_exists !== null) { return $property_exists; } } $class_storage = $this->classlikes->getStorageFor($fq_class_name); if (!$class_storage) { return \false; } if ($source && $context && $context->self !== $fq_class_name && !$context->collect_initializations && !$context->collect_mutations) { if ($context->calling_method_id) { $this->file_reference_provider->addMethodReferenceToClass($context->calling_method_id, $fq_class_name_lc); } else { $this->file_reference_provider->addNonMethodReferenceToClass($source->getFilePath(), $fq_class_name_lc); } } if (isset($class_storage->declaring_property_ids[$property_name])) { $declaring_property_class = strtolower($class_storage->declaring_property_ids[$property_name]); if ($context && $context->calling_method_id) { $this->file_reference_provider->addMethodReferenceToClassMember($context->calling_method_id, $declaring_property_class . '::$' . $property_name, \false); if ($read_mode) { $this->file_reference_provider->addMethodReferenceToClassProperty($context->calling_method_id, $declaring_property_class . '::$' . $property_name); } } elseif ($source) { $this->file_reference_provider->addFileReferenceToClassMember($source->getFilePath(), $declaring_property_class . '::$' . $property_name, \false); if ($read_mode) { $this->file_reference_provider->addFileReferenceToClassProperty($source->getFilePath(), $declaring_property_class . '::$' . $property_name); } } if ($this->collect_locations && $code_location) { $this->file_reference_provider->addCallingLocationForClassProperty($code_location, $declaring_property_class . '::$' . $property_name); } return \true; } if ($context && $context->calling_method_id) { $this->file_reference_provider->addMethodReferenceToMissingClassMember($context->calling_method_id, $fq_class_name_lc . '::$' . $property_name); } elseif ($source) { $this->file_reference_provider->addFileReferenceToMissingClassMember($source->getFilePath(), $fq_class_name_lc . '::$' . $property_name); } return \false; } public function getDeclaringClassForProperty(string $property_id, bool $read_mode, ?StatementsSource $source = null) : ?string { [$fq_class_name, $property_name] = explode('::$', $property_id); if ($this->property_existence_provider->has($fq_class_name)) { if ($this->property_existence_provider->doesPropertyExist($fq_class_name, $property_name, $read_mode, $source, null)) { return $fq_class_name; } } $class_storage = $this->classlikes->getStorageFor($fq_class_name); if ($class_storage && isset($class_storage->declaring_property_ids[$property_name])) { return $class_storage->declaring_property_ids[$property_name]; } return null; } /** * Get the class this property appears in (vs is declared in, which could give a trait) */ public function getAppearingClassForProperty(string $property_id, bool $read_mode, ?StatementsSource $source = null) : ?string { [$fq_class_name, $property_name] = explode('::$', $property_id); if ($this->property_existence_provider->has($fq_class_name)) { if ($this->property_existence_provider->doesPropertyExist($fq_class_name, $property_name, $read_mode, $source, null)) { return $fq_class_name; } } $class_storage = $this->classlikes->getStorageFor($fq_class_name); if ($class_storage && isset($class_storage->appearing_property_ids[$property_name])) { $appearing_property_id = $class_storage->appearing_property_ids[$property_name]; return explode('::$', $appearing_property_id)[0]; } return null; } public function getStorage(string $property_id) : PropertyStorage { // remove leading backslash if it exists $property_id = ltrim($property_id, '\\'); [$fq_class_name, $property_name] = explode('::$', $property_id); $class_storage = $this->classlike_storage_provider->get($fq_class_name); if (isset($class_storage->declaring_property_ids[$property_name])) { $declaring_property_class = $class_storage->declaring_property_ids[$property_name]; $declaring_class_storage = $this->classlike_storage_provider->get($declaring_property_class); if (isset($declaring_class_storage->properties[$property_name])) { return $declaring_class_storage->properties[$property_name]; } } throw new UnexpectedValueException('Property ' . $property_id . ' should exist'); } public function hasStorage(string $property_id) : bool { // remove leading backslash if it exists $property_id = ltrim($property_id, '\\'); [$fq_class_name, $property_name] = explode('::$', $property_id); $class_storage = $this->classlike_storage_provider->get($fq_class_name); if (isset($class_storage->declaring_property_ids[$property_name])) { $declaring_property_class = $class_storage->declaring_property_ids[$property_name]; $declaring_class_storage = $this->classlike_storage_provider->get($declaring_property_class); return isset($declaring_class_storage->properties[$property_name]); } return \false; } public function getPropertyType(string $property_id, bool $property_set, ?StatementsSource $source = null, ?Context $context = null) : ?Union { // remove leading backslash if it exists $property_id = ltrim($property_id, '\\'); [$fq_class_name, $property_name] = explode('::$', $property_id); if ($this->property_type_provider->has($fq_class_name)) { $property_type = $this->property_type_provider->getPropertyType($fq_class_name, $property_name, !$property_set, $source, $context); if ($property_type !== null) { return $property_type; } } $class_storage = $this->classlikes->getStorageFor($fq_class_name); if ($class_storage && isset($class_storage->declaring_property_ids[$property_name])) { $declaring_property_class = $class_storage->declaring_property_ids[$property_name]; $declaring_class_storage = $this->classlike_storage_provider->get($declaring_property_class); if (isset($declaring_class_storage->properties[$property_name])) { $storage = $declaring_class_storage->properties[$property_name]; } else { throw new UnexpectedValueException('Property ' . $property_id . ' should exist'); } } else { throw new UnexpectedValueException('Property ' . $property_id . ' should exist'); } if ($storage->type) { if ($property_set) { if (isset($class_storage->pseudo_property_set_types['$' . $property_name])) { return $class_storage->pseudo_property_set_types['$' . $property_name]; } } else { if (isset($class_storage->pseudo_property_get_types['$' . $property_name])) { return $class_storage->pseudo_property_get_types['$' . $property_name]; } } return $storage->type; } if (!isset($class_storage->overridden_property_ids[$property_name])) { return null; } foreach ($class_storage->overridden_property_ids[$property_name] as $overridden_property_id) { $overridden_storage = $this->getStorage($overridden_property_id); if ($overridden_storage->type) { return $overridden_storage->type; } } return null; } } > */ private array $invalid_class_storages = []; private Progress $progress; private \Psalm\Internal\Codebase\ClassLikes $classlikes; private FileReferenceProvider $file_reference_provider; public function __construct(ClassLikeStorageProvider $classlike_storage_provider, FileStorageProvider $file_storage_provider, \Psalm\Internal\Codebase\ClassLikes $classlikes, FileReferenceProvider $file_reference_provider, Progress $progress) { $this->classlike_storage_provider = $classlike_storage_provider; $this->file_storage_provider = $file_storage_provider; $this->classlikes = $classlikes; $this->progress = $progress; $this->file_reference_provider = $file_reference_provider; } public function populateCodebase() : void { $this->progress->debug('ClassLikeStorage is populating' . "\n"); foreach ($this->classlike_storage_provider->getNew() as $class_storage) { $this->populateClassLikeStorage($class_storage); } $this->progress->debug('ClassLikeStorage is populated' . "\n"); $this->progress->debug('FileStorage is populating' . "\n"); $all_file_storage = $this->file_storage_provider->getNew(); foreach ($all_file_storage as $file_storage) { $this->populateFileStorage($file_storage); } foreach ($this->classlike_storage_provider->getNew() as $class_storage) { foreach ($class_storage->dependent_classlikes as $dependent_classlike_lc => $_) { try { $dependee_storage = $this->classlike_storage_provider->get($dependent_classlike_lc); } catch (InvalidArgumentException $exception) { continue; } $class_storage->dependent_classlikes += $dependee_storage->dependent_classlikes; } } $this->progress->debug('FileStorage is populated' . "\n"); ClassLikeStorageProvider::populated(); FileStorageProvider::populated(); } private function populateClassLikeStorage(ClassLikeStorage $storage, array $dependent_classlikes = []) : void { if ($storage->populated) { return; } $fq_classlike_name_lc = strtolower($storage->name); if (isset($dependent_classlikes[$fq_classlike_name_lc])) { if ($storage->location) { IssueBuffer::maybeAdd(new CircularReference('Circular reference discovered when loading ' . $storage->name, $storage->location)); } return; } $storage_provider = $this->classlike_storage_provider; $dependent_classlikes[$fq_classlike_name_lc] = \true; foreach ($storage->used_traits as $used_trait_lc => $_) { $this->populateDataFromTrait($storage, $storage_provider, $dependent_classlikes, $used_trait_lc); } if ($storage->parent_classes) { $this->populateDataFromParentClass($storage, $storage_provider, $dependent_classlikes, reset($storage->parent_classes)); } if (!strpos($fq_classlike_name_lc, '\\') && !isset($storage->methods['__construct']) && isset($storage->methods[$fq_classlike_name_lc]) && !$storage->is_interface && !$storage->is_trait) { $storage->methods['__construct'] = $storage->methods[$fq_classlike_name_lc]; } foreach ($storage->direct_interface_parents as $parent_interface_lc => $_) { $this->populateInterfaceDataFromParentInterface($storage, $storage_provider, $dependent_classlikes, $parent_interface_lc); } foreach ($storage->direct_class_interfaces as $implemented_interface_lc => $_) { $this->populateDataFromImplementedInterface($storage, $storage_provider, $dependent_classlikes, $implemented_interface_lc); } if ($storage->location) { $file_path = $storage->location->file_path; foreach ($storage->parent_interfaces as $parent_interface_lc) { $this->file_reference_provider->addFileInheritanceToClass($file_path, $parent_interface_lc); } foreach ($storage->parent_classes as $parent_class_lc => $_) { $this->file_reference_provider->addFileInheritanceToClass($file_path, $parent_class_lc); } foreach ($storage->class_implements as $implemented_interface) { $this->file_reference_provider->addFileInheritanceToClass($file_path, strtolower($implemented_interface)); } foreach ($storage->used_traits as $used_trait_lc => $_) { $this->file_reference_provider->addFileInheritanceToClass($file_path, $used_trait_lc); } } if ($storage->mutation_free || $storage->external_mutation_free) { foreach ($storage->methods as $method) { if (!$method->is_static && !$method->external_mutation_free) { $method->mutation_free = $storage->mutation_free; $method->external_mutation_free = $storage->external_mutation_free; $method->immutable = $storage->mutation_free; } } if ($storage->mutation_free) { foreach ($storage->properties as $property) { if (!$property->is_static) { $property->readonly = \true; } } } } if ($storage->specialize_instance) { foreach ($storage->methods as $method) { if (!$method->is_static) { $method->specialize_call = \true; } } } if (!$storage->is_interface && !$storage->is_trait) { foreach ($storage->methods as $method) { $method->internal = [...$storage->internal, ...$method->internal]; } foreach ($storage->properties as $property) { $property->internal = [...$storage->internal, ...$property->internal]; } } $this->populateOverriddenMethods($storage, $storage_provider); $this->progress->debug('Have populated ' . $storage->name . "\n"); $storage->populated = \true; if (isset($this->invalid_class_storages[$fq_classlike_name_lc])) { foreach ($this->invalid_class_storages[$fq_classlike_name_lc] as $dependency) { // Dependencies may not be fully set yet, so we have to loop through dependencies of dependencies $dependencies = [strtolower($dependency->name) => \true]; do { $current_dependency_name = key(array_splice($dependencies, 0, 1)); // Key shift $current_dependency = $storage_provider->get($current_dependency_name); $dependencies += $current_dependency->dependent_classlikes; if (isset($current_dependency->dependent_classlikes[$fq_classlike_name_lc])) { if ($dependency->location) { IssueBuffer::maybeAdd(new CircularReference('Circular reference discovered when loading ' . $dependency->name, $dependency->location)); } continue 2; } } while (!empty($dependencies)); $dependency->populated = \false; unset($dependency->invalid_dependencies[$fq_classlike_name_lc]); $this->populateClassLikeStorage($dependency, $dependent_classlikes); } unset($this->invalid_class_storages[$fq_classlike_name_lc]); } } private function populateOverriddenMethods(ClassLikeStorage $storage, ClassLikeStorageProvider $storage_provider) : void { $interface_method_implementers = []; foreach ($storage->class_implements as $interface) { try { $implemented_interface = strtolower($this->classlikes->getUnAliasedName($interface)); $implemented_interface_storage = $storage_provider->get($implemented_interface); } catch (InvalidArgumentException $e) { continue; } $implemented_interface_storage->dependent_classlikes[strtolower($storage->name)] = \true; foreach ($implemented_interface_storage->methods as $method_name => $method) { if ($method->visibility === ClassLikeAnalyzer::VISIBILITY_PUBLIC) { $interface_method_implementers[$method_name][] = new MethodIdentifier($implemented_interface_storage->name, $method_name); } } } foreach ($interface_method_implementers as $method_name => $interface_method_ids) { if (count($interface_method_ids) === 1) { if (isset($storage->methods[$method_name])) { $method_storage = $storage->methods[$method_name]; if ($method_storage->signature_return_type && !$method_storage->signature_return_type->isVoid() && $method_storage->return_type === $method_storage->signature_return_type) { $interface_fqcln = $interface_method_ids[0]->fq_class_name; $interface_storage = $storage_provider->get($interface_fqcln); if (isset($interface_storage->methods[$method_name])) { $interface_method_storage = $interface_storage->methods[$method_name]; if ($interface_method_storage->throws && (!$method_storage->throws || $method_storage->inheritdoc)) { $method_storage->throws += $interface_method_storage->throws; } } } } } foreach ($interface_method_ids as $interface_method_id) { $storage->overridden_method_ids[$method_name][$interface_method_id->fq_class_name] = $interface_method_id; } } $storage->documenting_method_ids = []; foreach ($storage->methods as $method_name => $method_storage) { if (isset($storage->overridden_method_ids[$method_name])) { $overridden_method_ids = $storage->overridden_method_ids[$method_name]; $candidate_overridden_ids = null; $declaring_class_storages = []; foreach ($overridden_method_ids as $declaring_method_id) { $declaring_class = $declaring_method_id->fq_class_name; $declaring_class_storage = $declaring_class_storages[$declaring_class] = $this->classlike_storage_provider->get($declaring_class); if ($candidate_overridden_ids === null) { $candidate_overridden_ids = ($declaring_class_storage->overridden_method_ids[$method_name] ?? []) + [$declaring_method_id->fq_class_name => $declaring_method_id]; } else { $candidate_overridden_ids = array_intersect_key($candidate_overridden_ids, ($declaring_class_storage->overridden_method_ids[$method_name] ?? []) + [$declaring_method_id->fq_class_name => $declaring_method_id]); } } foreach ($overridden_method_ids as $declaring_method_id) { $declaring_class = $declaring_method_id->fq_class_name; $declaring_method_name = $declaring_method_id->method_name; $declaring_class_storage = $declaring_class_storages[$declaring_class]; $declaring_method_storage = $declaring_class_storage->methods[$declaring_method_name]; if (($declaring_method_storage->has_docblock_param_types || $declaring_method_storage->has_docblock_return_type) && !$method_storage->has_docblock_param_types && !$method_storage->has_docblock_return_type && $method_storage->inherited_return_type !== null) { if (!isset($storage->documenting_method_ids[$method_name]) || (string) $storage->documenting_method_ids[$method_name] === (string) $declaring_method_id) { $storage->documenting_method_ids[$method_name] = $declaring_method_id; $method_storage->inherited_return_type = \true; } else { if (in_array($storage->documenting_method_ids[$method_name]->fq_class_name, $declaring_class_storage->parent_interfaces)) { $storage->documenting_method_ids[$method_name] = $declaring_method_id; $method_storage->inherited_return_type = \true; } else { $documenting_class_storage = $declaring_class_storages[$storage->documenting_method_ids[$method_name]->fq_class_name]; if (!in_array($declaring_class, $documenting_class_storage->parent_interfaces) && $documenting_class_storage->is_interface) { unset($storage->documenting_method_ids[$method_name]); $method_storage->inherited_return_type = null; } } } } // tell the declaring class it's overridden downstream $declaring_method_storage->overridden_downstream = \true; $declaring_method_storage->overridden_somewhere = \true; if ($declaring_method_storage->mutation_free_inferred) { $declaring_method_storage->mutation_free = \false; $declaring_method_storage->external_mutation_free = \false; $declaring_method_storage->mutation_free_inferred = \false; } if ($declaring_method_storage->throws && (!$method_storage->throws || $method_storage->inheritdoc)) { $method_storage->throws += $declaring_method_storage->throws; } } } } } private function populateDataFromTrait(ClassLikeStorage $storage, ClassLikeStorageProvider $storage_provider, array $dependent_classlikes, string $used_trait_lc) : void { try { $used_trait_lc = strtolower($this->classlikes->getUnAliasedName($used_trait_lc)); $trait_storage = $storage_provider->get($used_trait_lc); } catch (InvalidArgumentException $e) { return; } $this->populateClassLikeStorage($trait_storage, $dependent_classlikes); $this->inheritConstantsFromTrait($storage, $trait_storage); $this->inheritMethodsFromParent($storage, $trait_storage); $this->inheritPropertiesFromParent($storage, $trait_storage); self::extendTemplateParams($storage, $trait_storage, \false); $storage->pseudo_property_get_types += $trait_storage->pseudo_property_get_types; $storage->pseudo_property_set_types += $trait_storage->pseudo_property_set_types; $storage->pseudo_static_methods += $trait_storage->pseudo_static_methods; $storage->pseudo_methods += $trait_storage->pseudo_methods; $storage->declaring_pseudo_method_ids += $trait_storage->declaring_pseudo_method_ids; } private static function extendType(Union $type, ClassLikeStorage $storage) : Union { $extended_types = []; foreach ($type->getAtomicTypes() as $atomic_type) { if ($atomic_type instanceof TTemplateParam) { $referenced_type = $storage->template_extended_params[$atomic_type->defining_class][$atomic_type->param_name] ?? null; if ($referenced_type) { foreach ($referenced_type->getAtomicTypes() as $atomic_referenced_type) { if (!$atomic_referenced_type instanceof TTemplateParam) { $extended_types[] = $atomic_referenced_type; } else { $extended_types[] = $atomic_type; } } } else { $extended_types[] = $atomic_type; } } else { $extended_types[] = $atomic_type; } } return new Union($extended_types); } private function populateDataFromParentClass(ClassLikeStorage $storage, ClassLikeStorageProvider $storage_provider, array $dependent_classlikes, string $parent_storage_class) : void { $parent_storage_class = strtolower($this->classlikes->getUnAliasedName($parent_storage_class)); try { $parent_storage = $storage_provider->get($parent_storage_class); } catch (InvalidArgumentException $e) { $this->progress->debug('Populator could not find dependency (' . __LINE__ . ")\n"); $storage->invalid_dependencies[$parent_storage_class] = \true; $this->invalid_class_storages[$parent_storage_class][] = $storage; return; } $this->populateClassLikeStorage($parent_storage, $dependent_classlikes); $storage->parent_classes = array_merge($storage->parent_classes, $parent_storage->parent_classes); self::extendTemplateParams($storage, $parent_storage, \true); $this->inheritMethodsFromParent($storage, $parent_storage); $this->inheritPropertiesFromParent($storage, $parent_storage); $storage->class_implements = array_merge($storage->class_implements, $parent_storage->class_implements); $storage->invalid_dependencies = array_merge($storage->invalid_dependencies, $parent_storage->invalid_dependencies); if ($parent_storage->has_visitor_issues) { $storage->has_visitor_issues = \true; } $storage->constants = array_merge(array_filter($parent_storage->constants, static fn(ClassConstantStorage $constant): bool => $constant->visibility === ClassLikeAnalyzer::VISIBILITY_PUBLIC || $constant->visibility === ClassLikeAnalyzer::VISIBILITY_PROTECTED), $storage->constants); if ($parent_storage->preserve_constructor_signature) { $storage->preserve_constructor_signature = \true; } if (($parent_storage->namedMixins || $parent_storage->templatedMixins) && (!$storage->namedMixins || !$storage->templatedMixins)) { $storage->mixin_declaring_fqcln = $parent_storage->mixin_declaring_fqcln; if (!$storage->namedMixins) { $storage->namedMixins = $parent_storage->namedMixins; } if (!$storage->templatedMixins) { $storage->templatedMixins = $parent_storage->templatedMixins; } } $storage->pseudo_property_get_types += $parent_storage->pseudo_property_get_types; $storage->pseudo_property_set_types += $parent_storage->pseudo_property_set_types; $parent_storage->dependent_classlikes[strtolower($storage->name)] = \true; $storage->pseudo_static_methods += $parent_storage->pseudo_static_methods; $storage->pseudo_methods += $parent_storage->pseudo_methods; $storage->declaring_pseudo_method_ids += $parent_storage->declaring_pseudo_method_ids; } private function populateInterfaceData(ClassLikeStorage $storage, ClassLikeStorage $interface_storage, ClassLikeStorageProvider $storage_provider, array $dependent_classlikes) : void { $this->populateClassLikeStorage($interface_storage, $dependent_classlikes); // copy over any constants $storage->constants = array_merge(array_filter($interface_storage->constants, static fn(ClassConstantStorage $constant): bool => $constant->visibility === ClassLikeAnalyzer::VISIBILITY_PUBLIC), $storage->constants); $storage->invalid_dependencies = array_merge($storage->invalid_dependencies, $interface_storage->invalid_dependencies); self::extendTemplateParams($storage, $interface_storage, \false); $new_parents = array_keys($interface_storage->parent_interfaces); $new_parents[] = $interface_storage->name; foreach ($new_parents as $new_parent) { try { $new_parent = strtolower($this->classlikes->getUnAliasedName($new_parent)); $new_parent_interface_storage = $storage_provider->get($new_parent); } catch (InvalidArgumentException $e) { continue; } $new_parent_interface_storage->dependent_classlikes[strtolower($storage->name)] = \true; } } private static function extendTemplateParams(ClassLikeStorage $storage, ClassLikeStorage $parent_storage, bool $from_direct_parent) : void { if ($parent_storage->yield && !$storage->yield) { $storage->yield = $parent_storage->yield; $storage->declaring_yield_fqcn ??= $parent_storage->name; } if ($parent_storage->template_types) { $storage->template_extended_params[$parent_storage->name] = []; if (isset($storage->template_extended_offsets[$parent_storage->name])) { foreach ($storage->template_extended_offsets[$parent_storage->name] as $i => $type) { $parent_template_type_names = array_keys($parent_storage->template_types); $mapped_name = $parent_template_type_names[$i] ?? null; if ($mapped_name) { $storage->template_extended_params[$parent_storage->name][$mapped_name] = $type; } } if ($parent_storage->template_extended_params) { foreach ($parent_storage->template_extended_params as $t_storage_class => $type_map) { foreach ($type_map as $i => $type) { $storage->template_extended_params[$t_storage_class][$i] = self::extendType($type, $storage); } } } } else { foreach ($parent_storage->template_types as $template_name => $template_type_map) { foreach ($template_type_map as $template_type) { $default_param = $template_type->setProperties(['from_docblock' => \false]); $storage->template_extended_params[$parent_storage->name][$template_name] = $default_param; } } if ($from_direct_parent) { if ($parent_storage->template_extended_params) { $storage->template_extended_params = array_merge($storage->template_extended_params, $parent_storage->template_extended_params); } } } } elseif ($parent_storage->template_extended_params) { $storage->template_extended_params = array_merge($storage->template_extended_params ?: [], $parent_storage->template_extended_params); } } private function populateInterfaceDataFromParentInterface(ClassLikeStorage $storage, ClassLikeStorageProvider $storage_provider, array $dependent_classlikes, string $parent_interface_lc) : void { try { $parent_interface_lc = strtolower($this->classlikes->getUnAliasedName($parent_interface_lc)); $parent_interface_storage = $storage_provider->get($parent_interface_lc); } catch (InvalidArgumentException $e) { $this->progress->debug('Populator could not find dependency (' . __LINE__ . ")\n"); $storage->invalid_dependencies[$parent_interface_lc] = \true; return; } $this->populateInterfaceData($storage, $parent_interface_storage, $storage_provider, $dependent_classlikes); $this->inheritMethodsFromParent($storage, $parent_interface_storage); $storage->pseudo_methods += $parent_interface_storage->pseudo_methods; $storage->declaring_pseudo_method_ids += $parent_interface_storage->declaring_pseudo_method_ids; $storage->parent_interfaces = array_merge($parent_interface_storage->parent_interfaces, $storage->parent_interfaces); if (isset($storage->parent_interfaces[strtolower(UnitEnum::class)])) { $storage->declaring_property_ids['name'] = $storage->name; $storage->appearing_property_ids['name'] = "{$storage->name}::\$name"; $storage->properties['name'] = new PropertyStorage(); $storage->properties['name']->type = new Union([new TNonEmptyString()]); } if (isset($storage->parent_interfaces[strtolower(BackedEnum::class)])) { $storage->declaring_property_ids['value'] = $storage->name; $storage->appearing_property_ids['value'] = "{$storage->name}::\$value"; $storage->properties['value'] = new PropertyStorage(); $storage->properties['value']->type = new Union([new TInt(), new TString()]); } } private function populateDataFromImplementedInterface(ClassLikeStorage $storage, ClassLikeStorageProvider $storage_provider, array $dependent_classlikes, string $implemented_interface_lc) : void { try { $implemented_interface_lc = strtolower($this->classlikes->getUnAliasedName($implemented_interface_lc)); $implemented_interface_storage = $storage_provider->get($implemented_interface_lc); } catch (InvalidArgumentException $e) { $this->progress->debug('Populator could not find dependency (' . __LINE__ . ")\n"); $storage->invalid_dependencies[$implemented_interface_lc] = \true; return; } $this->populateInterfaceData($storage, $implemented_interface_storage, $storage_provider, $dependent_classlikes); $storage->class_implements = array_merge($storage->class_implements, $implemented_interface_storage->parent_interfaces); } /** * @param array $dependent_file_paths */ private function populateFileStorage(FileStorage $storage, array $dependent_file_paths = []) : void { if ($storage->populated) { return; } $file_path_lc = strtolower($storage->file_path); if (isset($dependent_file_paths[$file_path_lc])) { return; } $dependent_file_paths[$file_path_lc] = \true; $all_required_file_paths = $storage->required_file_paths; foreach ($storage->required_file_paths as $included_file_path => $_) { try { $included_file_storage = $this->file_storage_provider->get($included_file_path); } catch (InvalidArgumentException $e) { continue; } $this->populateFileStorage($included_file_storage, $dependent_file_paths); $all_required_file_paths = $all_required_file_paths + $included_file_storage->required_file_paths; } foreach ($all_required_file_paths as $included_file_path => $_) { try { $included_file_storage = $this->file_storage_provider->get($included_file_path); } catch (InvalidArgumentException $e) { continue; } $storage->declaring_function_ids = array_merge($included_file_storage->declaring_function_ids, $storage->declaring_function_ids); $storage->declaring_constants = array_merge($included_file_storage->declaring_constants, $storage->declaring_constants); } foreach ($storage->referenced_classlikes as $fq_class_name) { try { $classlike_storage = $this->classlike_storage_provider->get($fq_class_name); } catch (InvalidArgumentException $e) { continue; } if (!$classlike_storage->location) { continue; } try { $included_file_storage = $this->file_storage_provider->get($classlike_storage->location->file_path); } catch (InvalidArgumentException $e) { continue; } foreach ($classlike_storage->used_traits as $used_trait) { try { $trait_storage = $this->classlike_storage_provider->get($used_trait); } catch (InvalidArgumentException $e) { continue; } if (!$trait_storage->location) { continue; } try { $included_trait_file_storage = $this->file_storage_provider->get($trait_storage->location->file_path); } catch (InvalidArgumentException $e) { continue; } $storage->declaring_function_ids = array_merge($included_trait_file_storage->declaring_function_ids, $storage->declaring_function_ids); } $storage->declaring_function_ids = array_merge($included_file_storage->declaring_function_ids, $storage->declaring_function_ids); } $storage->required_file_paths = $all_required_file_paths; foreach ($all_required_file_paths as $required_file_path) { try { $required_file_storage = $this->file_storage_provider->get($required_file_path); } catch (InvalidArgumentException $e) { continue; } $required_file_storage->required_by_file_paths += [$file_path_lc => $storage->file_path]; } foreach ($storage->required_classes as $required_classlike) { try { $classlike_storage = $this->classlike_storage_provider->get($required_classlike); } catch (InvalidArgumentException $e) { continue; } if (!$classlike_storage->location) { continue; } try { $required_file_storage = $this->file_storage_provider->get($classlike_storage->location->file_path); } catch (InvalidArgumentException $e) { continue; } $required_file_storage->required_by_file_paths += [$file_path_lc => $storage->file_path]; } $storage->populated = \true; } private function inheritConstantsFromTrait(ClassLikeStorage $storage, ClassLikeStorage $trait_storage) : void { if (!$trait_storage->is_trait) { throw new Exception('Class like storage is not for a trait.'); } foreach ($trait_storage->constants as $constant_name => $class_constant_storage) { $trait_alias_map_cased = array_flip($storage->trait_alias_map_cased); if (isset($trait_alias_map_cased[$constant_name])) { $aliased_constant_name_lc = strtolower($trait_alias_map_cased[$constant_name]); $aliased_constant_name = $trait_alias_map_cased[$constant_name]; } else { $aliased_constant_name_lc = strtolower($constant_name); $aliased_constant_name = $constant_name; } $visibility = $storage->trait_visibility_map[$aliased_constant_name_lc] ?? $class_constant_storage->visibility; $final = $storage->trait_final_map[$aliased_constant_name_lc] ?? $class_constant_storage->final; $storage->constants[$aliased_constant_name] = new ClassConstantStorage($class_constant_storage->type, $class_constant_storage->inferred_type, $visibility, $class_constant_storage->location, $class_constant_storage->type_location, $class_constant_storage->stmt_location, $class_constant_storage->deprecated, $final, $class_constant_storage->unresolved_node, $class_constant_storage->attributes, $class_constant_storage->suppressed_issues, $class_constant_storage->description); } } protected function inheritMethodsFromParent(ClassLikeStorage $storage, ClassLikeStorage $parent_storage) : void { $fq_class_name = $storage->name; $fq_class_name_lc = strtolower($fq_class_name); if ($parent_storage->sealed_methods !== null) { $storage->sealed_methods = $parent_storage->sealed_methods; } // register where they appear (can never be in a trait) foreach ($parent_storage->appearing_method_ids as $method_name_lc => $appearing_method_id) { $aliased_method_names = [$method_name_lc]; if ($parent_storage->is_trait && $storage->trait_alias_map) { $aliased_method_names = [...$aliased_method_names, ...array_keys($storage->trait_alias_map, $method_name_lc, \true)]; } foreach ($aliased_method_names as $aliased_method_name) { if (isset($storage->appearing_method_ids[$aliased_method_name])) { continue; } $implemented_method_id = new MethodIdentifier($fq_class_name, $aliased_method_name); $storage->appearing_method_ids[$aliased_method_name] = $parent_storage->is_trait ? $implemented_method_id : $appearing_method_id; $this_method_id = $fq_class_name_lc . '::' . $method_name_lc; if (isset($storage->methods[$aliased_method_name])) { $storage->potential_declaring_method_ids[$aliased_method_name] = [$this_method_id => \true]; } else { if (isset($parent_storage->potential_declaring_method_ids[$aliased_method_name])) { $storage->potential_declaring_method_ids[$aliased_method_name] = $parent_storage->potential_declaring_method_ids[$aliased_method_name]; } $storage->potential_declaring_method_ids[$aliased_method_name][$this_method_id] = \true; $parent_method_id = strtolower($parent_storage->name) . '::' . $method_name_lc; $storage->potential_declaring_method_ids[$aliased_method_name][$parent_method_id] = \true; } } } // register where they're declared foreach ($parent_storage->inheritable_method_ids as $method_name_lc => $declaring_method_id) { if ($method_name_lc !== '__construct' || $parent_storage->preserve_constructor_signature) { if ($parent_storage->is_trait) { $declaring_class = $declaring_method_id->fq_class_name; $declaring_class_storage = $this->classlike_storage_provider->get($declaring_class); if (isset($declaring_class_storage->methods[$method_name_lc]) && $declaring_class_storage->methods[$method_name_lc]->abstract) { $storage->overridden_method_ids[$method_name_lc][$declaring_method_id->fq_class_name] = $declaring_method_id; } } else { $storage->overridden_method_ids[$method_name_lc][$declaring_method_id->fq_class_name] = $declaring_method_id; } if (isset($parent_storage->overridden_method_ids[$method_name_lc]) && isset($storage->overridden_method_ids[$method_name_lc])) { $storage->overridden_method_ids[$method_name_lc] += $parent_storage->overridden_method_ids[$method_name_lc]; } } $aliased_method_names = [$method_name_lc]; if ($parent_storage->is_trait && $storage->trait_alias_map) { $aliased_method_names = [...$aliased_method_names, ...array_keys($storage->trait_alias_map, $method_name_lc, \true)]; } foreach ($aliased_method_names as $aliased_method_name) { if (isset($storage->declaring_method_ids[$aliased_method_name])) { $implementing_method_id = $storage->declaring_method_ids[$aliased_method_name]; $implementing_class_storage = $this->classlike_storage_provider->get($implementing_method_id->fq_class_name); if (!$implementing_class_storage->methods[$implementing_method_id->method_name]->abstract || !empty($storage->methods[$implementing_method_id->method_name]->abstract)) { continue; } } $storage->declaring_method_ids[$aliased_method_name] = $declaring_method_id; $storage->inheritable_method_ids[$aliased_method_name] = $declaring_method_id; } } } private function inheritPropertiesFromParent(ClassLikeStorage $storage, ClassLikeStorage $parent_storage) : void { if ($parent_storage->sealed_properties !== null) { $storage->sealed_properties = $parent_storage->sealed_properties; } // register where they appear (can never be in a trait) foreach ($parent_storage->appearing_property_ids as $property_name => $appearing_property_id) { if (isset($storage->appearing_property_ids[$property_name])) { continue; } if (!$parent_storage->is_trait && isset($parent_storage->properties[$property_name]) && $parent_storage->properties[$property_name]->visibility === ClassLikeAnalyzer::VISIBILITY_PRIVATE) { continue; } $implemented_property_id = $storage->name . '::$' . $property_name; $storage->appearing_property_ids[$property_name] = $parent_storage->is_trait ? $implemented_property_id : $appearing_property_id; } // register where they're declared foreach ($parent_storage->declaring_property_ids as $property_name => $declaring_property_class) { if (isset($storage->declaring_property_ids[$property_name])) { continue; } if (!$parent_storage->is_trait && isset($parent_storage->properties[$property_name]) && $parent_storage->properties[$property_name]->visibility === ClassLikeAnalyzer::VISIBILITY_PRIVATE) { continue; } $storage->declaring_property_ids[$property_name] = $declaring_property_class; } // register where they're declared foreach ($parent_storage->inheritable_property_ids as $property_name => $inheritable_property_id) { if (!$parent_storage->is_trait && isset($parent_storage->properties[$property_name]) && $parent_storage->properties[$property_name]->visibility === ClassLikeAnalyzer::VISIBILITY_PRIVATE) { continue; } if (!$parent_storage->is_trait) { $storage->overridden_property_ids[$property_name][] = $inheritable_property_id; } $storage->inheritable_property_ids[$property_name] = $inheritable_property_id; } } } */ private static array $builtin_functions = []; public function __construct(ClassLikeStorageProvider $storage_provider, Codebase $codebase) { $this->storage_provider = $storage_provider; $this->codebase = $codebase; self::$builtin_functions = []; } public function registerClass(ReflectionClass $reflected_class) : void { $class_name = $reflected_class->name; if ($class_name === LibXMLError::class) { $class_name = 'libXMLError'; } $class_name_lower = strtolower($class_name); try { $this->storage_provider->get($class_name_lower); return; } catch (Exception $e) { // this is fine } $reflected_parent_class = $reflected_class->getParentClass(); $storage = $this->storage_provider->create($class_name); $storage->abstract = $reflected_class->isAbstract(); $storage->is_interface = $reflected_class->isInterface(); $storage->potential_declaring_method_ids['__construct'][$class_name_lower . '::__construct'] = \true; if ($reflected_parent_class) { $parent_class_name = $reflected_parent_class->getName(); $this->registerClass($reflected_parent_class); $parent_class_name_lc = strtolower($parent_class_name); $parent_storage = $this->storage_provider->get($parent_class_name_lc); $this->registerInheritedMethods($class_name_lower, $parent_class_name_lc); $this->registerInheritedProperties($class_name_lower, $parent_class_name_lc); $storage->class_implements = $parent_storage->class_implements; $storage->constants = $parent_storage->constants; $storage->parent_classes = array_merge([$parent_class_name_lc => $parent_class_name], $parent_storage->parent_classes); $storage->used_traits = $parent_storage->used_traits; } $class_properties = $reflected_class->getProperties(); $public_mapped_properties = \Psalm\Internal\Codebase\PropertyMap::inPropertyMap($class_name) ? \Psalm\Internal\Codebase\PropertyMap::getPropertyMap()[strtolower($class_name)] : []; foreach ($class_properties as $class_property) { $property_name = $class_property->getName(); $storage->properties[$property_name] = new PropertyStorage(); $storage->properties[$property_name]->type = Type::getMixed(); if ($class_property->isStatic()) { $storage->properties[$property_name]->is_static = \true; } if ($class_property->isPublic()) { $storage->properties[$property_name]->visibility = ClassLikeAnalyzer::VISIBILITY_PUBLIC; } elseif ($class_property->isProtected()) { $storage->properties[$property_name]->visibility = ClassLikeAnalyzer::VISIBILITY_PROTECTED; } elseif ($class_property->isPrivate()) { $storage->properties[$property_name]->visibility = ClassLikeAnalyzer::VISIBILITY_PRIVATE; } $property_id = $class_property->class . '::$' . $property_name; $storage->declaring_property_ids[$property_name] = $class_property->class; $storage->appearing_property_ids[$property_name] = $property_id; if (!$class_property->isPrivate()) { $storage->inheritable_property_ids[$property_name] = $property_id; } } // have to do this separately as there can be new properties here foreach ($public_mapped_properties as $property_name => $type_string) { $property_id = $class_name . '::$' . $property_name; if (!isset($storage->properties[$property_name])) { $storage->properties[$property_name] = new PropertyStorage(); $storage->properties[$property_name]->visibility = ClassLikeAnalyzer::VISIBILITY_PUBLIC; $storage->declaring_property_ids[$property_name] = $class_name; $storage->appearing_property_ids[$property_name] = $property_id; $storage->inheritable_property_ids[$property_name] = $property_id; } $type = Type::parseString($type_string); if ($property_id === 'DateInterval::$days') { /** @psalm-suppress InaccessibleProperty We just parsed this type */ $type->ignore_falsable_issues = \true; } $storage->properties[$property_name]->type = $type; } /** @var array */ $class_constants = $reflected_class->getConstants(); foreach ($class_constants as $name => $value) { $storage->constants[$name] = new ClassConstantStorage(ClassLikeAnalyzer::getTypeFromValue($value), new Union([\Psalm\Internal\Codebase\ConstantTypeResolver::getLiteralTypeFromScalarValue($value)]), ClassLikeAnalyzer::VISIBILITY_PUBLIC, null); } if ($reflected_class->isInterface()) { $this->codebase->classlikes->addFullyQualifiedInterfaceName($class_name); } elseif ($reflected_class->isTrait()) { $this->codebase->classlikes->addFullyQualifiedTraitName($class_name); } else { $this->codebase->classlikes->addFullyQualifiedClassName($class_name); } $reflection_methods = $reflected_class->getMethods(ReflectionMethod::IS_PUBLIC | ReflectionMethod::IS_PROTECTED); if ($class_name_lower === 'generator') { $storage->template_types = ['TKey' => ['Generator' => Type::getMixed()], 'TValue' => ['Generator' => Type::getMixed()]]; } $interfaces = $reflected_class->getInterfaces(); foreach ($interfaces as $interface) { $interface_name = $interface->getName(); $this->registerClass($interface); if ($reflected_class->isInterface()) { $storage->parent_interfaces[strtolower($interface_name)] = $interface_name; } else { $storage->class_implements[strtolower($interface_name)] = $interface_name; } } foreach ($reflection_methods as $reflection_method) { $method_reflection_class = $reflection_method->getDeclaringClass(); $this->registerClass($method_reflection_class); $this->extractReflectionMethodInfo($reflection_method); if ($reflection_method->class !== $class_name && ($class_name !== 'SoapFault' || $reflection_method->name !== '__construct')) { $reflection_method_name = strtolower($reflection_method->name); $reflection_method_class = $reflection_method->class; $this->codebase->methods->setDeclaringMethodId($class_name, $reflection_method_name, $reflection_method_class, $reflection_method_name); $this->codebase->methods->setAppearingMethodId($class_name, $reflection_method_name, $reflection_method_class, $reflection_method_name); } } } public function extractReflectionMethodInfo(ReflectionMethod $method) : void { $method_name_lc = strtolower($method->getName()); $fq_class_name = $method->class; $fq_class_name_lc = strtolower($fq_class_name); $class_storage = $this->storage_provider->get($fq_class_name_lc); if (isset($class_storage->methods[$method_name_lc])) { return; } $method_id = $method->class . '::' . $method_name_lc; $storage = $class_storage->methods[$method_name_lc] = new MethodStorage(); $storage->cased_name = $method->name; $storage->defining_fqcln = $method->class; if ($method_name_lc === $fq_class_name_lc) { $this->codebase->methods->setDeclaringMethodId($fq_class_name, '__construct', $fq_class_name, $method_name_lc); $this->codebase->methods->setAppearingMethodId($fq_class_name, '__construct', $fq_class_name, $method_name_lc); } $declaring_class = $method->getDeclaringClass(); $storage->is_static = $method->isStatic(); $storage->abstract = $method->isAbstract(); $storage->mutation_free = $storage->external_mutation_free = $method_name_lc === '__construct' && $fq_class_name_lc === 'datetimezone'; $class_storage->declaring_method_ids[$method_name_lc] = new MethodIdentifier($declaring_class->name, $method_name_lc); $class_storage->inheritable_method_ids[$method_name_lc] = $class_storage->declaring_method_ids[$method_name_lc]; $class_storage->appearing_method_ids[$method_name_lc] = $class_storage->declaring_method_ids[$method_name_lc]; $class_storage->overridden_method_ids[$method_name_lc] = []; $storage->visibility = $method->isPrivate() ? ClassLikeAnalyzer::VISIBILITY_PRIVATE : ($method->isProtected() ? ClassLikeAnalyzer::VISIBILITY_PROTECTED : ClassLikeAnalyzer::VISIBILITY_PUBLIC); $callables = \Psalm\Internal\Codebase\InternalCallMapHandler::getCallablesFromCallMap($method_id); if ($callables && $callables[0]->params !== null && $callables[0]->return_type !== null) { $storage->setParams([]); foreach ($callables[0]->params as $param) { if ($param->type) { /** @psalm-suppress UnusedMethodCall */ $param->type->queueClassLikesForScanning($this->codebase); } } $storage->setParams($callables[0]->params); $storage->return_type = $callables[0]->return_type; /** @psalm-suppress UnusedMethodCall */ $storage->return_type->queueClassLikesForScanning($this->codebase); } else { $params = $method->getParameters(); $storage->setParams([]); foreach ($params as $param) { $param_array = $this->getReflectionParamData($param); $storage->addParam($param_array); } } $storage->required_param_count = 0; foreach ($storage->params as $i => $param) { if (!$param->is_optional && !$param->is_variadic) { $storage->required_param_count = $i + 1; } } } private function getReflectionParamData(ReflectionParameter $param) : FunctionLikeParameter { $param_type = self::getPsalmTypeFromReflectionType($param->getType()); $param_name = $param->getName(); $is_optional = $param->isOptional(); $parameter = new FunctionLikeParameter($param_name, $param->isPassedByReference(), $param_type, $param_type, null, null, $is_optional, $param_type->isNullable(), $param->isVariadic()); $parameter->signature_type = Type::getMixed(); return $parameter; } /** * @param callable-string $function_id * @return false|null */ public function registerFunction(string $function_id) : ?bool { try { $reflection_function = new ReflectionFunction($function_id); $callmap_callable = null; if (isset(self::$builtin_functions[$function_id])) { return null; } $storage = self::$builtin_functions[$function_id] = new FunctionStorage(); if (\Psalm\Internal\Codebase\InternalCallMapHandler::inCallMap($function_id)) { $callmap_callable = \Psalm\Internal\Codebase\InternalCallMapHandler::getCallableFromCallMapById($this->codebase, $function_id, [], null); } if ($callmap_callable !== null && $callmap_callable->params !== null && $callmap_callable->return_type !== null) { $storage->setParams($callmap_callable->params); $storage->return_type = $callmap_callable->return_type; } else { $reflection_params = $reflection_function->getParameters(); foreach ($reflection_params as $param) { $param_obj = $this->getReflectionParamData($param); $storage->addParam($param_obj); } if ($reflection_return_type = $reflection_function->getReturnType()) { $storage->return_type = self::getPsalmTypeFromReflectionType($reflection_return_type); } } $storage->pure = \true; $storage->required_param_count = 0; foreach ($storage->params as $i => $param) { if (!$param->is_optional && !$param->is_variadic) { $storage->required_param_count = $i + 1; } } $storage->cased_name = $reflection_function->getName(); } catch (ReflectionException $e) { return \false; } return null; } /** @psalm-suppress UnusedPsalmSuppress,UndefinedClass,TypeDoesNotContainType 7.4 has no ReflectionUnionType */ public static function getPsalmTypeFromReflectionType(?ReflectionType $reflection_type = null) : Union { if (!$reflection_type) { return Type::getMixed(); } if ($reflection_type instanceof ReflectionNamedType) { $type = $reflection_type->getName(); } elseif ($reflection_type instanceof ReflectionUnionType) { /** @psalm-suppress MixedArgument */ $type = implode('|', array_map(static fn(ReflectionNamedType $reflection): string => $reflection->getName(), $reflection_type->getTypes())); } else { throw new LogicException('Unexpected reflection class ' . get_class($reflection_type) . ' found.'); } if ($reflection_type->allowsNull()) { $type .= '|null'; } return Type::parseString($type); } private function registerInheritedMethods(string $fq_class_name, string $parent_class) : void { $parent_storage = $this->storage_provider->get($parent_class); $storage = $this->storage_provider->get($fq_class_name); // register where they appear (can never be in a trait) foreach ($parent_storage->appearing_method_ids as $method_name => $appearing_method_id) { $storage->appearing_method_ids[$method_name] = $appearing_method_id; } // register where they're declared foreach ($parent_storage->inheritable_method_ids as $method_name => $declaring_method_id) { $storage->declaring_method_ids[$method_name] = $declaring_method_id; $storage->inheritable_method_ids[$method_name] = $declaring_method_id; $storage->overridden_method_ids[$method_name][$declaring_method_id->fq_class_name] = $declaring_method_id; } } /** * @param lowercase-string $fq_class_name * @param lowercase-string $parent_class */ private function registerInheritedProperties(string $fq_class_name, string $parent_class) : void { $parent_storage = $this->storage_provider->get($parent_class); $storage = $this->storage_provider->get($fq_class_name); // register where they appear (can never be in a trait) foreach ($parent_storage->appearing_property_ids as $property_name => $appearing_property_id) { if (!$parent_storage->is_trait && isset($parent_storage->properties[$property_name]) && $parent_storage->properties[$property_name]->visibility === ClassLikeAnalyzer::VISIBILITY_PRIVATE) { continue; } $storage->appearing_property_ids[$property_name] = $appearing_property_id; } // register where they're declared foreach ($parent_storage->declaring_property_ids as $property_name => $declaring_property_class) { if (!$parent_storage->is_trait && isset($parent_storage->properties[$property_name]) && $parent_storage->properties[$property_name]->visibility === ClassLikeAnalyzer::VISIBILITY_PRIVATE) { continue; } $storage->declaring_property_ids[$property_name] = strtolower($declaring_property_class); } // register where they're declared foreach ($parent_storage->inheritable_property_ids as $property_name => $inheritable_property_id) { if (!$parent_storage->is_trait && isset($parent_storage->properties[$property_name]) && $parent_storage->properties[$property_name]->visibility === ClassLikeAnalyzer::VISIBILITY_PRIVATE) { continue; } $storage->inheritable_property_ids[$property_name] = $inheritable_property_id; } } public function hasFunction(string $function_id) : bool { return isset(self::$builtin_functions[$function_id]); } public function getFunctionStorage(string $function_id) : FunctionStorage { if (isset(self::$builtin_functions[$function_id])) { return self::$builtin_functions[$function_id]; } throw new UnexpectedValueException('Expecting to have a function for ' . $function_id); } /** * @return array */ public function getFunctions() : array { return self::$builtin_functions; } public static function clearCache() : void { self::$builtin_functions = []; } } |null */ public ?array $new_vars = null; /** * @var array */ public array $new_vars_possibly_in_scope = []; /** * @var array|null */ public ?array $redefined_vars = null; /** * @var array|null */ public ?array $assigned_var_ids = null; /** * @var array */ public array $possibly_assigned_var_ids = []; /** * @var array */ public array $possibly_redefined_vars = []; /** * @var array */ public array $updated_vars = []; /** * @var array>> */ public array $negated_types = []; /** * @var array */ public array $if_cond_changed_var_ids = []; /** * @var array|null */ public ?array $negatable_if_types = null; /** * @var list */ public array $negated_clauses = []; /** * These are the set of clauses that could be applied after the `if` * statement, if the `if` statement contains branches with leaving statements, * and the else leaves too * * @var list */ public array $reasonable_clauses = []; /** * @var string[] */ public array $if_actions = []; /** * @var string[] */ public array $final_actions = []; public ?Context $post_leaving_if_context = null; } |null */ public ?array $break_vars = null; public function __construct(Context $parent_context) { $this->parent_context = $parent_context; } public function __destruct() { unset($this->parent_context); } } */ public array $cond_referenced_var_ids; /** * @var array */ public array $assigned_in_conditional_var_ids; /** @var list */ public array $entry_clauses; /** * @param array $cond_referenced_var_ids * @param array $assigned_in_conditional_var_ids * @param list $entry_clauses */ public function __construct(Context $if_context, Context $post_if_context, array $cond_referenced_var_ids, array $assigned_in_conditional_var_ids, array $entry_clauses) { $this->if_context = $if_context; $this->post_if_context = $post_if_context; $this->cond_referenced_var_ids = $cond_referenced_var_ids; $this->assigned_in_conditional_var_ids = $assigned_in_conditional_var_ids; $this->entry_clauses = $entry_clauses; } } |null */ public ?array $new_vars_in_scope = null; /** * @var array */ public array $new_vars_possibly_in_scope = []; /** * @var array|null */ public ?array $redefined_vars = null; /** * @var array|null */ public ?array $possibly_redefined_vars = null; /** * @var array */ public array $leftover_statements = []; public ?PhpParser\Node\Expr $leftover_case_equality_expr = null; /** * @var list */ public array $negated_clauses = []; /** * @var array|null */ public ?array $new_assigned_var_ids = null; } */ public array $redefined_loop_vars = []; /** * @var array */ public array $possibly_redefined_loop_vars = []; /** * @var array */ public array $possibly_redefined_loop_parent_vars = []; /** * @var array */ public array $possibly_defined_loop_parent_vars = []; /** * @var array */ public array $vars_possibly_in_scope = []; /** * @var array */ public array $protected_var_ids = []; /** * @var string[] */ public array $final_actions = []; public function __construct(Context $loop_context, Context $parent_context) { $this->loop_context = $loop_context; $this->loop_parent_context = $parent_context; } public function __destruct() { unset($this->loop_context); unset($this->loop_parent_context); } } */ public array $vars_in_scope = []; /** * @param array $vars_in_scope */ public function __construct(array $vars_in_scope) { $this->vars_in_scope = $vars_in_scope; } } type = $type; $this->old = $old; $this->new = $new; } } $a * @param list $b * @return array{0:non-empty-list>, 1: int, 2: int} * @psalm-pure */ private static function calculateTrace(array $a, array $b) : array { $n = count($a); $m = count($b); $max = $n + $m; /** @var array $v */ $v = [1 => 0]; $trace = []; for ($d = 0; $d <= $max; ++$d) { $trace[] = $v; for ($k = -$d; $k <= $d; $k += 2) { if ($k === -$d || $k !== $d && $v[$k - 1] < $v[$k + 1]) { $x = $v[$k + 1]; } else { $x = $v[$k - 1] + 1; } $y = $x - $k; while ($x < $n && $y < $m && $a[$x] === $b[$y]) { ++$x; ++$y; } $v[$k] = $x; if ($x >= $n && $y >= $m) { return [$trace, $x, $y]; } } } throw new Exception('Should not happen'); } /** * @param list> $trace * @param list $a * @param list $b * @return list * @psalm-pure */ private static function extractDiff(array $trace, int $x, int $y, array $a, array $b) : array { $result = []; for ($d = count($trace) - 1; $d >= 0; --$d) { $v = $trace[$d]; $k = $x - $y; if ($k === -$d || $k !== $d && $v[$k - 1] < $v[$k + 1]) { $prevK = $k + 1; } else { $prevK = $k - 1; } $prevX = $v[$prevK]; $prevY = $prevX - $prevK; while ($x > $prevX && $y > $prevY) { $result[] = new \Psalm\Internal\Diff\DiffElem(\Psalm\Internal\Diff\DiffElem::TYPE_KEEP, $a[$x - 1], $b[$y - 1]); --$x; --$y; } if ($d === 0) { break; } while ($x > $prevX) { $result[] = new \Psalm\Internal\Diff\DiffElem(\Psalm\Internal\Diff\DiffElem::TYPE_REMOVE, $a[$x - 1], null); --$x; } while ($y > $prevY) { $result[] = new \Psalm\Internal\Diff\DiffElem(\Psalm\Internal\Diff\DiffElem::TYPE_ADD, null, $b[$y - 1]); --$y; } } return array_reverse($result); } /** * @return array * @psalm-pure */ public static function getDiff(string $a_code, string $b_code) : array { $a = explode("\n", $a_code); $b = explode("\n", $b_code); [$trace, $x, $y] = self::calculateTrace($a, $b); $diff = self::coalesceReplacements(self::extractDiff($trace, $x, $y, $a, $b)); $a_offset = 0; $b_offset = 0; $last_diff_type = null; /** @var array{0:int, 1:int, 2:int, 3:int, 4:int, 5:string}|null */ $last_change = null; $changes = []; $i = 0; $line_diff = 0; foreach ($diff as $diff_elem) { $diff_type = $diff_elem->type; if ($diff_type !== $last_diff_type) { $last_change = null; } if ($diff_type === \Psalm\Internal\Diff\DiffElem::TYPE_REMOVE) { /** @var string $diff_elem->old */ $diff_text = $diff_elem->old . "\n"; $text_length = strlen($diff_text); --$line_diff; if ($last_change === null) { ++$i; $last_change = [$a_offset, $a_offset + $text_length, $b_offset, $b_offset, $line_diff, '']; $changes[$i - 1] = $last_change; } else { $last_change[1] += $text_length; $last_change[4] = $line_diff; $changes[$i - 1] = $last_change; } $a_offset += $text_length; } elseif ($diff_type === \Psalm\Internal\Diff\DiffElem::TYPE_ADD) { /** @var string $diff_elem->new */ $diff_text = $diff_elem->new . "\n"; $text_length = strlen($diff_text); ++$line_diff; if ($last_change === null) { ++$i; $last_change = [$a_offset, $a_offset, $b_offset, $b_offset + $text_length, $line_diff, $diff_text]; $changes[$i - 1] = $last_change; } else { $last_change[3] += $text_length; $last_change[4] = $line_diff; $last_change[5] .= $diff_text; $changes[$i - 1] = $last_change; } $b_offset += $text_length; } elseif ($diff_type === \Psalm\Internal\Diff\DiffElem::TYPE_REPLACE) { /** @var string $diff_elem->old */ $old_diff_text = $diff_elem->old . "\n"; /** @var string $diff_elem->new */ $new_diff_text = $diff_elem->new . "\n"; $old_text_length = strlen($old_diff_text); $new_text_length = strlen($new_diff_text); $max_same_count = min($old_text_length, $new_text_length); for ($j = 0; $j < $max_same_count; ++$j) { if ($old_diff_text[$j] !== $new_diff_text[$j]) { break; } ++$a_offset; ++$b_offset; --$old_text_length; --$new_text_length; } $new_diff_text = substr($new_diff_text, $j); if ($last_change === null || $j) { ++$i; $last_change = [$a_offset, $a_offset + $old_text_length, $b_offset, $b_offset + $new_text_length, $line_diff, $new_diff_text]; $changes[$i - 1] = $last_change; } else { $last_change[1] += $old_text_length; $last_change[3] += $new_text_length; $last_change[5] .= $new_diff_text; $changes[$i - 1] = $last_change; } $a_offset += $old_text_length; $b_offset += $new_text_length; } else { /** @psalm-suppress MixedArgument */ $same_text_length = strlen($diff_elem->new) + 1; $a_offset += $same_text_length; $b_offset += $same_text_length; } $last_diff_type = $diff_elem->type; } return $changes; } /** * Coalesce equal-length sequences of remove+add into a replace operation. * * @param DiffElem[] $diff * @return list * @psalm-pure */ private static function coalesceReplacements(array $diff) : array { $newDiff = []; $c = count($diff); for ($i = 0; $i < $c; ++$i) { $diffType = $diff[$i]->type; if ($diffType !== \Psalm\Internal\Diff\DiffElem::TYPE_REMOVE) { $newDiff[] = $diff[$i]; continue; } $j = $i; while ($j < $c && $diff[$j]->type === \Psalm\Internal\Diff\DiffElem::TYPE_REMOVE) { ++$j; } $k = $j; while ($k < $c && $diff[$k]->type === \Psalm\Internal\Diff\DiffElem::TYPE_ADD) { ++$k; } if ($j - $i === $k - $j) { $len = $j - $i; for ($n = 0; $n < $len; ++$n) { $newDiff[] = new \Psalm\Internal\Diff\DiffElem(\Psalm\Internal\Diff\DiffElem::TYPE_REPLACE, $diff[$i + $n]->old, $diff[$j + $n]->new); } } else { for (; $i < $k; ++$i) { $newDiff[] = $diff[$i]; } } $i = $k - 1; } return $newDiff; } } $a * @param array $b * @return array{ * 0: list, * 1: list, * 2: list, * 3: array, * 4: list * } */ public static function diff(string $name, array $a, array $b, string $a_code, string $b_code) : array { $diff_map = []; [$trace, $x, $y, $bc] = self::calculateTrace(static function (PhpParser\Node\Stmt $a, PhpParser\Node\Stmt $b, string $a_code, string $b_code, bool &$body_change = \false) use(&$diff_map) : bool { if (get_class($a) !== get_class($b)) { return \false; } $a_start = (int) $a->getAttribute('startFilePos'); $a_end = (int) $a->getAttribute('endFilePos'); $b_start = (int) $b->getAttribute('startFilePos'); $b_end = (int) $b->getAttribute('endFilePos'); $a_comments_end = $a_start; $b_comments_end = $b_start; /** @var list */ $a_comments = $a->getComments(); /** @var list */ $b_comments = $b->getComments(); $signature_change = \false; $body_change = \false; if ($a_comments) { if (!$b_comments) { $signature_change = \true; } $a_start = $a_comments[0]->getStartFilePos(); } if ($b_comments) { if (!$a_comments) { $signature_change = \true; } $b_start = $b_comments[0]->getStartFilePos(); } $a_size = $a_end - $a_start; $b_size = $b_end - $b_start; if ($a_size === $b_size && substr($a_code, $a_start, $a_size) === substr($b_code, $b_start, $b_size)) { $start_diff = $b_start - $a_start; $line_diff = $b->getLine() - $a->getLine(); $diff_map[] = [$a_start, $a_end, $start_diff, $line_diff]; return \true; } if (!$signature_change && substr($a_code, $a_start, $a_comments_end - $a_start) !== substr($b_code, $b_start, $b_comments_end - $b_start)) { $signature_change = \true; } if ($a instanceof PhpParser\Node\Stmt\ClassMethod && $b instanceof PhpParser\Node\Stmt\ClassMethod) { if ((string) $a->name !== (string) $b->name) { return \false; } if ($a->stmts) { $first_stmt = $a->stmts[0]; $a_stmts_start = (int) $first_stmt->getAttribute('startFilePos'); if ($a_stmt_comments = $first_stmt->getComments()) { $a_stmts_start = $a_stmt_comments[0]->getStartFilePos(); } } else { $a_stmts_start = $a_end; } if ($b->stmts) { $first_stmt = $b->stmts[0]; $b_stmts_start = (int) $first_stmt->getAttribute('startFilePos'); if ($b_stmt_comments = $first_stmt->getComments()) { $b_stmts_start = $b_stmt_comments[0]->getStartFilePos(); } } else { $b_stmts_start = $b_end; } $a_body_size = $a_end - $a_stmts_start; $b_body_size = $b_end - $b_stmts_start; $body_change = $a_body_size !== $b_body_size || substr($a_code, $a_stmts_start, $a_end - $a_stmts_start) !== substr($b_code, $b_stmts_start, $b_end - $b_stmts_start); if (!$signature_change) { $a_signature = substr($a_code, $a_start, $a_stmts_start - $a_start); $b_signature = substr($b_code, $b_start, $b_stmts_start - $b_start); if ($a_signature !== $b_signature) { $a_signature = trim($a_signature); $b_signature = trim($b_signature); if (strpos($a_signature, $b_signature) === \false && strpos($b_signature, $a_signature) === \false) { $signature_change = \true; } } } } elseif ($a instanceof PhpParser\Node\Stmt\Property && $b instanceof PhpParser\Node\Stmt\Property) { if (count($a->props) !== 1 || count($b->props) !== 1) { return \false; } if ((string) $a->props[0]->name !== (string) $b->props[0]->name || $a->flags !== $b->flags) { return \false; } if ($a->type xor $b->type) { return \false; } if ($a->type && $b->type) { $a_type_start = (int) $a->type->getAttribute('startFilePos'); $a_type_end = (int) $a->type->getAttribute('endFilePos'); $b_type_start = (int) $b->type->getAttribute('startFilePos'); $b_type_end = (int) $b->type->getAttribute('endFilePos'); if (substr($a_code, $a_type_start, $a_type_end - $a_type_start + 1) !== substr($b_code, $b_type_start, $b_type_end - $b_type_start + 1)) { return \false; } } $body_change = substr($a_code, $a_comments_end, $a_end - $a_comments_end) !== substr($b_code, $b_comments_end, $b_end - $b_comments_end); } else { $signature_change = \true; } if (!$signature_change && !$body_change) { $diff_map[] = [$a_start, $a_end, $b_start - $a_start, $b->getLine() - $a->getLine()]; } return !$signature_change; }, $a, $b, $a_code, $b_code); $diff = self::extractDiff($trace, $x, $y, $a, $b, $bc); $keep = []; $keep_signature = []; $add_or_delete = []; $deletion_ranges = []; $name_lc = strtolower($name); foreach ($diff as $diff_elem) { if ($diff_elem->type === \Psalm\Internal\Diff\DiffElem::TYPE_KEEP) { if ($diff_elem->old instanceof PhpParser\Node\Stmt\ClassMethod) { $keep[] = $name_lc . '::' . strtolower((string) $diff_elem->old->name); } elseif ($diff_elem->old instanceof PhpParser\Node\Stmt\Property) { foreach ($diff_elem->old->props as $prop) { $keep[] = $name_lc . '::$' . $prop->name; } } elseif ($diff_elem->old instanceof PhpParser\Node\Stmt\ClassConst) { foreach ($diff_elem->old->consts as $const) { $keep[] = $name_lc . '::' . $const->name; } } elseif ($diff_elem->old instanceof PhpParser\Node\Stmt\TraitUse) { foreach ($diff_elem->old->traits as $trait) { $keep[] = $name_lc . '&' . strtolower((string) $trait->getAttribute('resolvedName')); } } } elseif ($diff_elem->type === \Psalm\Internal\Diff\DiffElem::TYPE_KEEP_SIGNATURE) { if ($diff_elem->old instanceof PhpParser\Node\Stmt\ClassMethod) { $keep_signature[] = $name_lc . '::' . strtolower((string) $diff_elem->old->name); } elseif ($diff_elem->old instanceof PhpParser\Node\Stmt\Property) { foreach ($diff_elem->old->props as $prop) { $keep_signature[] = $name_lc . '::$' . $prop->name; } } } elseif ($diff_elem->type === \Psalm\Internal\Diff\DiffElem::TYPE_REMOVE || $diff_elem->type === \Psalm\Internal\Diff\DiffElem::TYPE_ADD) { /** @var PhpParser\Node */ $affected_elem = $diff_elem->type === \Psalm\Internal\Diff\DiffElem::TYPE_REMOVE ? $diff_elem->old : $diff_elem->new; if ($affected_elem instanceof PhpParser\Node\Stmt\ClassMethod) { $method_name = strtolower((string) $affected_elem->name); $add_or_delete[] = $name_lc . '::' . $method_name; if ($method_name === '__construct') { foreach ($affected_elem->getParams() as $param) { if (!$param->flags || !$param->var instanceof PhpParser\Node\Expr\Variable) { continue; } if ($param->var instanceof PhpParser\Node\Expr\Error || !is_string($param->var->name)) { throw new UnexpectedValueException('Not expecting param name to be non-string'); } $add_or_delete[] = $name_lc . '::$' . $param->var->name; } } } elseif ($affected_elem instanceof PhpParser\Node\Stmt\Property) { foreach ($affected_elem->props as $prop) { $add_or_delete[] = $name_lc . '::$' . $prop->name; } } elseif ($affected_elem instanceof PhpParser\Node\Stmt\ClassConst) { foreach ($affected_elem->consts as $const) { $add_or_delete[] = $name_lc . '::' . $const->name; } } elseif ($affected_elem instanceof PhpParser\Node\Stmt\TraitUse) { foreach ($affected_elem->traits as $trait) { $add_or_delete[] = $name_lc . '&' . strtolower((string) $trait->getAttribute('resolvedName')); } } if ($diff_elem->type === \Psalm\Internal\Diff\DiffElem::TYPE_REMOVE) { if ($doc = $affected_elem->getDocComment()) { $start = $doc->getStartFilePos(); } else { $start = (int) $affected_elem->getAttribute('startFilePos'); } $deletion_ranges[] = [$start, (int) $affected_elem->getAttribute('endFilePos')]; } } } /** @var array $diff_map */ return [$keep, $keep_signature, $add_or_delete, $diff_map, $deletion_ranges]; } } $a * @param array $b * @return array{ * 0: list, * 1: list, * 2: list, * 3: list, * 4: list * } */ public static function diff(string $name, array $a, array $b, string $a_code, string $b_code) : array { [$trace, $x, $y, $bc] = self::calculateTrace(static function (PhpParser\Node\Stmt $a, PhpParser\Node\Stmt $b, string $a_code, string $b_code) : bool { if (get_class($a) !== get_class($b)) { return \false; } if ($a instanceof PhpParser\Node\Stmt\Class_ && $b instanceof PhpParser\Node\Stmt\Class_ || $a instanceof PhpParser\Node\Stmt\Interface_ && $b instanceof PhpParser\Node\Stmt\Interface_ || $a instanceof PhpParser\Node\Stmt\Trait_ && $b instanceof PhpParser\Node\Stmt\Trait_) { // @todo add check for comments comparison return (string) $a->name === (string) $b->name; } if ($a instanceof PhpParser\Node\Stmt\Use_ && $b instanceof PhpParser\Node\Stmt\Use_ || $a instanceof PhpParser\Node\Stmt\GroupUse && $b instanceof PhpParser\Node\Stmt\GroupUse) { $a_start = (int) $a->getAttribute('startFilePos'); $a_end = (int) $a->getAttribute('endFilePos'); $b_start = (int) $b->getAttribute('startFilePos'); $b_end = (int) $b->getAttribute('endFilePos'); $a_size = $a_end - $a_start; $b_size = $b_end - $b_start; if (substr($a_code, $a_start, $a_size) === substr($b_code, $b_start, $b_size)) { return \true; } } return \false; }, $a, $b, $a_code, $b_code); $diff = self::extractDiff($trace, $x, $y, $a, $b, $bc); $keep = []; $keep_signature = []; $add_or_delete = []; $diff_map = []; $deletion_ranges = []; foreach ($diff as $diff_elem) { if ($diff_elem->type === \Psalm\Internal\Diff\DiffElem::TYPE_KEEP) { if ($diff_elem->old instanceof PhpParser\Node\Stmt\Class_ && $diff_elem->new instanceof PhpParser\Node\Stmt\Class_ || $diff_elem->old instanceof PhpParser\Node\Stmt\Interface_ && $diff_elem->new instanceof PhpParser\Node\Stmt\Interface_ || $diff_elem->old instanceof PhpParser\Node\Stmt\Trait_ && $diff_elem->new instanceof PhpParser\Node\Stmt\Trait_) { $class_keep = \Psalm\Internal\Diff\ClassStatementsDiffer::diff(($name ? $name . '\\' : '') . $diff_elem->old->name, $diff_elem->old->stmts, $diff_elem->new->stmts, $a_code, $b_code); $keep = [...$keep, ...$class_keep[0]]; $keep_signature = [...$keep_signature, ...$class_keep[1]]; $add_or_delete = [...$add_or_delete, ...$class_keep[2]]; $diff_map = [...$diff_map, ...$class_keep[3]]; $deletion_ranges = [...$deletion_ranges, ...$class_keep[4]]; } } elseif ($diff_elem->type === \Psalm\Internal\Diff\DiffElem::TYPE_REMOVE) { if ($diff_elem->old instanceof PhpParser\Node\Stmt\Use_ || $diff_elem->old instanceof PhpParser\Node\Stmt\GroupUse) { foreach ($diff_elem->old->uses as $use) { if ($use->alias) { $add_or_delete[] = 'use:' . (string) $use->alias; } else { $name_parts = $use->name->getParts(); $add_or_delete[] = 'use:' . end($name_parts); } } } } elseif ($diff_elem->type === \Psalm\Internal\Diff\DiffElem::TYPE_ADD) { if ($diff_elem->new instanceof PhpParser\Node\Stmt\Use_ || $diff_elem->new instanceof PhpParser\Node\Stmt\GroupUse) { foreach ($diff_elem->new->uses as $use) { if ($use->alias) { $add_or_delete[] = 'use:' . (string) $use->alias; } else { $name_parts = $use->name->getParts(); $add_or_delete[] = 'use:' . end($name_parts); } } } } } return [$keep, $keep_signature, $add_or_delete, $diff_map, $deletion_ranges]; } } $a * @param list $b * @return array{ * 0: list, * 1: list, * 2: list, * 3: list, * 4: list * } */ public static function diff(array $a, array $b, string $a_code, string $b_code) : array { [$trace, $x, $y, $bc] = self::calculateTrace(static function (PhpParser\Node\Stmt $a, PhpParser\Node\Stmt $b, string $a_code, string $b_code) : bool { if (get_class($a) !== get_class($b)) { return \false; } if ($a instanceof PhpParser\Node\Stmt\Namespace_ && $b instanceof PhpParser\Node\Stmt\Namespace_ || $a instanceof PhpParser\Node\Stmt\Class_ && $b instanceof PhpParser\Node\Stmt\Class_ || $a instanceof PhpParser\Node\Stmt\Interface_ && $b instanceof PhpParser\Node\Stmt\Interface_ || $a instanceof PhpParser\Node\Stmt\Trait_ && $b instanceof PhpParser\Node\Stmt\Trait_) { return (string) $a->name === (string) $b->name; } if ($a instanceof PhpParser\Node\Stmt\Use_ && $b instanceof PhpParser\Node\Stmt\Use_ || $a instanceof PhpParser\Node\Stmt\GroupUse && $b instanceof PhpParser\Node\Stmt\GroupUse) { $a_start = (int) $a->getAttribute('startFilePos'); $a_end = (int) $a->getAttribute('endFilePos'); $b_start = (int) $b->getAttribute('startFilePos'); $b_end = (int) $b->getAttribute('endFilePos'); $a_size = $a_end - $a_start; $b_size = $b_end - $b_start; if (substr($a_code, $a_start, $a_size) === substr($b_code, $b_start, $b_size)) { return \true; } } return \false; }, $a, $b, $a_code, $b_code); $diff = self::extractDiff($trace, $x, $y, $a, $b, $bc); $keep = []; $keep_signature = []; $add_or_delete = []; $diff_map = []; $deletion_ranges = []; foreach ($diff as $diff_elem) { if ($diff_elem->type === \Psalm\Internal\Diff\DiffElem::TYPE_KEEP) { if ($diff_elem->old instanceof PhpParser\Node\Stmt\Namespace_ && $diff_elem->new instanceof PhpParser\Node\Stmt\Namespace_) { $namespace_keep = \Psalm\Internal\Diff\NamespaceStatementsDiffer::diff((string) $diff_elem->old->name, $diff_elem->old->stmts, $diff_elem->new->stmts, $a_code, $b_code); $keep = [...$keep, ...$namespace_keep[0]]; $keep_signature = [...$keep_signature, ...$namespace_keep[1]]; $add_or_delete = [...$add_or_delete, ...$namespace_keep[2]]; $diff_map = [...$diff_map, ...$namespace_keep[3]]; $deletion_ranges = [...$deletion_ranges, ...$namespace_keep[4]]; } elseif ($diff_elem->old instanceof PhpParser\Node\Stmt\Class_ && $diff_elem->new instanceof PhpParser\Node\Stmt\Class_ || $diff_elem->old instanceof PhpParser\Node\Stmt\Interface_ && $diff_elem->new instanceof PhpParser\Node\Stmt\Interface_ || $diff_elem->old instanceof PhpParser\Node\Stmt\Trait_ && $diff_elem->new instanceof PhpParser\Node\Stmt\Trait_) { $class_keep = \Psalm\Internal\Diff\ClassStatementsDiffer::diff((string) $diff_elem->old->name, $diff_elem->old->stmts, $diff_elem->new->stmts, $a_code, $b_code); if ($diff_elem->old->getDocComment() === $diff_elem->new->getDocComment()) { $keep = [...$keep, ...$class_keep[0]]; } else { $add_or_delete = [...$add_or_delete, ...$class_keep[0]]; } $keep_signature = [...$keep_signature, ...$class_keep[1]]; $add_or_delete = [...$add_or_delete, ...$class_keep[2]]; $diff_map = [...$diff_map, ...$class_keep[3]]; $deletion_ranges = [...$deletion_ranges, ...$class_keep[4]]; } } elseif ($diff_elem->type === \Psalm\Internal\Diff\DiffElem::TYPE_REMOVE) { if ($diff_elem->old instanceof PhpParser\Node\Stmt\Use_ || $diff_elem->old instanceof PhpParser\Node\Stmt\GroupUse) { foreach ($diff_elem->old->uses as $use) { if ($use->alias) { $add_or_delete[] = 'use:' . (string) $use->alias; } else { $name_parts = $use->name->getParts(); $add_or_delete[] = 'use:' . end($name_parts); } } } elseif ($diff_elem->old instanceof PhpParser\Node && !$diff_elem->old instanceof PhpParser\Node\Stmt\Namespace_) { if ($doc = $diff_elem->old->getDocComment()) { $start = $doc->getStartFilePos(); } else { $start = (int) $diff_elem->old->getAttribute('startFilePos'); } $deletion_ranges[] = [$start, (int) $diff_elem->old->getAttribute('endFilePos')]; } } elseif ($diff_elem->type === \Psalm\Internal\Diff\DiffElem::TYPE_ADD) { if ($diff_elem->new instanceof PhpParser\Node\Stmt\Use_ || $diff_elem->new instanceof PhpParser\Node\Stmt\GroupUse) { foreach ($diff_elem->new->uses as $use) { if ($use->alias) { $add_or_delete[] = 'use:' . (string) $use->alias; } else { $name_parts = $use->name->getParts(); $add_or_delete[] = 'use:' . end($name_parts); } } } } } return [$keep, $keep_signature, $add_or_delete, $diff_map, $deletion_ranges]; } } $a * @param array $b * @return array{0:non-empty-list>, 1: int, 2: int, 3: array} */ protected static function calculateTrace(Closure $is_equal, array $a, array $b, string $a_code, string $b_code) : array { $n = count($a); $m = count($b); $max = $n + $m; /** @var array $v */ $v = [1 => 0]; $bc = []; $trace = []; for ($d = 0; $d <= $max; ++$d) { $trace[] = $v; for ($k = -$d; $k <= $d; $k += 2) { if ($k === -$d || $k !== $d && $v[$k - 1] < $v[$k + 1]) { $x = $v[$k + 1]; } else { $x = $v[$k - 1] + 1; } $y = $x - $k; $body_change = \false; while ($x < $n && $y < $m && $is_equal($a[$x], $b[$y], $a_code, $b_code, $body_change)) { $bc[$x] = $body_change; ++$x; ++$y; $body_change = \false; } $v[$k] = $x; if ($x >= $n && $y >= $m) { return [$trace, $x, $y, $bc]; } } } throw new Exception('Should not happen'); } /** * @param array> $trace * @param array $a * @param array $b * @param array $bc * @return list * @psalm-pure */ protected static function extractDiff(array $trace, int $x, int $y, array $a, array $b, array $bc) : array { $result = []; for ($d = count($trace) - 1; $d >= 0; --$d) { $v = $trace[$d]; $k = $x - $y; if ($k === -$d || $k !== $d && $v[$k - 1] < $v[$k + 1]) { $prevK = $k + 1; } else { $prevK = $k - 1; } $prevX = $v[$prevK]; $prevY = $prevX - $prevK; while ($x > $prevX && $y > $prevY) { $result[] = new \Psalm\Internal\Diff\DiffElem($bc[$x - 1] ? \Psalm\Internal\Diff\DiffElem::TYPE_KEEP_SIGNATURE : \Psalm\Internal\Diff\DiffElem::TYPE_KEEP, $a[$x - 1], $b[$y - 1]); --$x; --$y; } if ($d === 0) { break; } while ($x > $prevX) { $result[] = new \Psalm\Internal\Diff\DiffElem(\Psalm\Internal\Diff\DiffElem::TYPE_REMOVE, $a[$x - 1], null); --$x; } while ($y > $prevY) { $result[] = new \Psalm\Internal\Diff\DiffElem(\Psalm\Internal\Diff\DiffElem::TYPE_ADD, null, $b[$y - 1]); --$y; } } return array_reverse($result); } } config = $config; $this->use_igbinary = $config->use_igbinary; } /** * @return array|object|string|null */ public function getItem(string $path) { if (!file_exists($path)) { return null; } $cache = Providers::safeFileGetContents($path); if ($cache === '') { return null; } if ($this->config->compressor === 'deflate') { $inflated = @gzinflate($cache); } elseif ($this->config->compressor === 'lz4') { /** * @psalm-suppress UndefinedFunction * @var string|false $inflated */ $inflated = lz4_uncompress($cache); } else { $inflated = $cache; } // invalid cache data if ($inflated === \false) { $this->deleteItem($path); return null; } if ($this->use_igbinary) { /** @var object|false $unserialized */ $unserialized = @igbinary_unserialize($inflated); } else { /** @var object|false $unserialized */ $unserialized = @unserialize($inflated); } if ($unserialized === \false) { $this->deleteItem($path); return null; } return $unserialized; } public function deleteItem(string $path) : void { if (@is_writable($path)) { @unlink($path); } } /** * @param array|object|string $item */ public function saveItem(string $path, $item) : void { if ($this->use_igbinary) { $serialized = igbinary_serialize($item); } else { $serialized = serialize($item); } if ($this->config->compressor === 'deflate') { $compressed = gzdeflate($serialized); } elseif ($this->config->compressor === 'lz4') { /** * @psalm-suppress UndefinedFunction * @var string|false $compressed */ $compressed = lz4_compress($serialized, 4); } else { $compressed = $serialized; } if ($compressed !== \false) { file_put_contents($path, $compressed, LOCK_EX); } // TODO: Error handling } public function getCacheDirectory() : ?string { return $this->config->getCacheDirectory(); } } > */ private array $after_method_checks = []; /** * Static methods to be called after project function checks have completed * * Called after function calls to functions defined in the project. * * Allows influencing the return type and adding of modifications. * * @var list> */ public array $after_function_checks = []; /** * Static methods to be called after every function call * * Called after each function call, including php internal functions. * * Cannot change the call or influence its return type * * @var list> */ public array $after_every_function_checks = []; /** * Static methods to be called before expression checks are completed * * @var list> */ public array $before_expression_checks = []; /** * Static methods to be called after expression checks have completed * * @var list> */ public array $after_expression_checks = []; /** * Static methods to be called before statement checks are processed * * @var list> */ public array $before_statement_checks = []; /** * Static methods to be called after statement checks have completed * * @var list> */ public array $after_statement_checks = []; /** * Static methods to be called after method checks have completed * * @var list> */ public array $string_interpreters = []; /** * Static methods to be called after classlike exists checks have completed * * @var list> */ public array $after_classlike_exists_checks = []; /** * Static methods to be called after classlike checks have completed * * @var list> */ public array $after_classlike_checks = []; /** * Static methods to be called after classlikes have been scanned * * @var list> */ private array $after_visit_classlikes = []; /** * Static methods to be called after codebase has been populated * * @var list> */ public array $after_codebase_populated = []; /** * @var list> */ private array $before_add_issue = []; /** * Static methods to be called after codebase has been populated * * @var list> */ public array $after_analysis = []; /** * Static methods to be called after a file has been analyzed * * @var list> */ public array $after_file_checks = []; /** * Static methods to be called before a file is analyzed * * @var list> */ public array $before_file_checks = []; /** * Static methods to be called after functionlike checks have completed * * @var list> */ public array $after_functionlike_checks = []; /** * Static methods to be called to see if taints should be added * * @var list> */ public array $add_taints_checks = []; /** * Static methods to be called to see if taints should be removed * * @var list> */ public array $remove_taints_checks = []; /** * @param class-string $class */ public function registerClass(string $class) : void { if (is_subclass_of($class, AfterMethodCallAnalysisInterface::class)) { $this->after_method_checks[] = $class; } if (is_subclass_of($class, AfterFunctionCallAnalysisInterface::class)) { $this->after_function_checks[] = $class; } if (is_subclass_of($class, AfterEveryFunctionCallAnalysisInterface::class)) { $this->after_every_function_checks[] = $class; } if (is_subclass_of($class, BeforeExpressionAnalysisInterface::class)) { $this->before_expression_checks[] = $class; } if (is_subclass_of($class, AfterExpressionAnalysisInterface::class)) { $this->after_expression_checks[] = $class; } if (is_subclass_of($class, BeforeStatementAnalysisInterface::class)) { $this->before_statement_checks[] = $class; } if (is_subclass_of($class, AfterStatementAnalysisInterface::class)) { $this->after_statement_checks[] = $class; } if (is_subclass_of($class, StringInterpreterInterface::class)) { $this->string_interpreters[] = $class; } if (is_subclass_of($class, AfterClassLikeExistenceCheckInterface::class)) { $this->after_classlike_exists_checks[] = $class; } if (is_subclass_of($class, AfterClassLikeAnalysisInterface::class)) { $this->after_classlike_checks[] = $class; } if (is_subclass_of($class, AfterClassLikeVisitInterface::class)) { $this->after_visit_classlikes[] = $class; } if (is_subclass_of($class, AfterCodebasePopulatedInterface::class)) { $this->after_codebase_populated[] = $class; } if (is_subclass_of($class, BeforeAddIssueInterface::class)) { $this->before_add_issue[] = $class; } if (is_subclass_of($class, AfterAnalysisInterface::class)) { $this->after_analysis[] = $class; } if (is_subclass_of($class, AfterFileAnalysisInterface::class)) { $this->after_file_checks[] = $class; } if (is_subclass_of($class, BeforeFileAnalysisInterface::class)) { $this->before_file_checks[] = $class; } if (is_subclass_of($class, AfterFunctionLikeAnalysisInterface::class)) { $this->after_functionlike_checks[] = $class; } if (is_subclass_of($class, AddTaintsInterface::class)) { $this->add_taints_checks[] = $class; } if (is_subclass_of($class, RemoveTaintsInterface::class)) { $this->remove_taints_checks[] = $class; } } public function hasAfterMethodCallAnalysisHandlers() : bool { return count($this->after_method_checks) > 0; } public function dispatchAfterMethodCallAnalysis(AfterMethodCallAnalysisEvent $event) : void { foreach ($this->after_method_checks as $handler) { $handler::afterMethodCallAnalysis($event); } } public function dispatchAfterFunctionCallAnalysis(AfterFunctionCallAnalysisEvent $event) : void { foreach ($this->after_function_checks as $handler) { $handler::afterFunctionCallAnalysis($event); } } public function dispatchAfterEveryFunctionCallAnalysis(AfterEveryFunctionCallAnalysisEvent $event) : void { foreach ($this->after_every_function_checks as $handler) { $handler::afterEveryFunctionCallAnalysis($event); } } public function dispatchBeforeExpressionAnalysis(BeforeExpressionAnalysisEvent $event) : ?bool { foreach ($this->before_expression_checks as $handler) { if ($handler::beforeExpressionAnalysis($event) === \false) { return \false; } } return null; } public function dispatchAfterExpressionAnalysis(AfterExpressionAnalysisEvent $event) : ?bool { foreach ($this->after_expression_checks as $handler) { if ($handler::afterExpressionAnalysis($event) === \false) { return \false; } } return null; } public function dispatchBeforeStatementAnalysis(BeforeStatementAnalysisEvent $event) : ?bool { foreach ($this->before_statement_checks as $handler) { if ($handler::beforeStatementAnalysis($event) === \false) { return \false; } } return null; } public function dispatchAfterStatementAnalysis(AfterStatementAnalysisEvent $event) : ?bool { foreach ($this->after_statement_checks as $handler) { if ($handler::afterStatementAnalysis($event) === \false) { return \false; } } return null; } public function dispatchStringInterpreter(StringInterpreterEvent $event) : ?TLiteralString { foreach ($this->string_interpreters as $handler) { if ($type = $handler::getTypeFromValue($event)) { return $type; } } return null; } public function dispatchAfterClassLikeExistenceCheck(AfterClassLikeExistenceCheckEvent $event) : void { foreach ($this->after_classlike_exists_checks as $handler) { $handler::afterClassLikeExistenceCheck($event); } } public function dispatchAfterClassLikeAnalysis(AfterClassLikeAnalysisEvent $event) : ?bool { foreach ($this->after_classlike_checks as $handler) { if ($handler::afterStatementAnalysis($event) === \false) { return \false; } } return null; } public function hasAfterClassLikeVisitHandlers() : bool { return count($this->after_visit_classlikes) > 0; } public function dispatchAfterClassLikeVisit(AfterClassLikeVisitEvent $event) : void { foreach ($this->after_visit_classlikes as $handler) { $handler::afterClassLikeVisit($event); } } public function dispatchAfterCodebasePopulated(AfterCodebasePopulatedEvent $event) : void { foreach ($this->after_codebase_populated as $handler) { $handler::afterCodebasePopulated($event); } } public function dispatchBeforeAddIssue(BeforeAddIssueEvent $event) : ?bool { foreach ($this->before_add_issue as $handler) { $result = $handler::beforeAddIssue($event); if (is_bool($result)) { return $result; } } return null; } public function dispatchAfterAnalysis(AfterAnalysisEvent $event) : void { foreach ($this->after_analysis as $handler) { $handler::afterAnalysis($event); } } public function dispatchAfterFileAnalysis(AfterFileAnalysisEvent $event) : void { foreach ($this->after_file_checks as $handler) { $handler::afterAnalyzeFile($event); } } public function dispatchBeforeFileAnalysis(BeforeFileAnalysisEvent $event) : void { foreach ($this->before_file_checks as $handler) { $handler::beforeAnalyzeFile($event); } } public function dispatchAfterFunctionLikeAnalysis(AfterFunctionLikeAnalysisEvent $event) : ?bool { foreach ($this->after_functionlike_checks as $handler) { if ($handler::afterStatementAnalysis($event) === \false) { return \false; } } return null; } /** * @return list */ public function dispatchAddTaints(AddRemoveTaintsEvent $event) : array { $added_taints = []; foreach ($this->add_taints_checks as $handler) { $added_taints = [...$added_taints, ...$handler::addTaints($event)]; } return $added_taints; } /** * @return list */ public function dispatchRemoveTaints(AddRemoveTaintsEvent $event) : array { $removed_taints = []; foreach ($this->remove_taints_checks as $handler) { $removed_taints = [...$removed_taints, ...$handler::removeTaints($event)]; } return $removed_taints; } } > */ protected static array $public_namespace_constants = []; public function __construct(Namespace_ $namespace, \Psalm\Internal\Analyzer\FileAnalyzer $source) { $this->source = $source; $this->namespace = $namespace; $this->namespace_name = $this->namespace->name ? $this->namespace->name->toString() : ''; } public function collectAnalyzableInformation() : void { $leftover_stmts = []; if (!isset(self::$public_namespace_constants[$this->namespace_name])) { self::$public_namespace_constants[$this->namespace_name] = []; } $codebase = $this->getCodebase(); foreach ($this->namespace->stmts as $stmt) { if ($stmt instanceof PhpParser\Node\Stmt\ClassLike) { $this->collectAnalyzableClassLike($stmt); } elseif ($stmt instanceof PhpParser\Node\Stmt\Use_) { $this->visitUse($stmt); } elseif ($stmt instanceof PhpParser\Node\Stmt\GroupUse) { $this->visitGroupUse($stmt); } elseif ($stmt instanceof PhpParser\Node\Stmt\Const_) { foreach ($stmt->consts as $const) { self::$public_namespace_constants[$this->namespace_name][$const->name->name] = Type::getMixed(); } $leftover_stmts[] = $stmt; } else { $leftover_stmts[] = $stmt; } } if ($leftover_stmts) { $statements_analyzer = new \Psalm\Internal\Analyzer\StatementsAnalyzer($this, new NodeDataProvider()); $file_context = $this->source->context; if ($file_context !== null) { $context = $file_context; } else { $context = new Context(); $context->is_global = \true; $context->defineGlobals(); $context->collect_exceptions = $codebase->config->check_for_throws_in_global_scope; } $statements_analyzer->analyze($leftover_stmts, $context, null, \true); } } public function collectAnalyzableClassLike(PhpParser\Node\Stmt\ClassLike $stmt) : void { if (!$stmt->name) { throw new UnexpectedValueException('Did not expect anonymous class here'); } $fq_class_name = Type::getFQCLNFromString($stmt->name->name, $this->getAliases()); if ($stmt instanceof PhpParser\Node\Stmt\Class_ || $stmt instanceof PhpParser\Node\Stmt\Enum_) { $this->source->addNamespacedClassAnalyzer($fq_class_name, new \Psalm\Internal\Analyzer\ClassAnalyzer($stmt, $this, $fq_class_name)); } elseif ($stmt instanceof PhpParser\Node\Stmt\Interface_) { $this->source->addNamespacedInterfaceAnalyzer($fq_class_name, new \Psalm\Internal\Analyzer\InterfaceAnalyzer($stmt, $this, $fq_class_name)); } } public function getNamespace() : string { return $this->namespace_name; } public function setConstType(string $const_name, Union $const_type) : void { self::$public_namespace_constants[$this->namespace_name][$const_name] = $const_type; } /** * @return array */ public static function getConstantsForNamespace(string $namespace_name, int $visibility) : array { // @todo this does not allow for loading in namespace constants not already defined in the current sweep if (!isset(self::$public_namespace_constants[$namespace_name])) { self::$public_namespace_constants[$namespace_name] = []; } if ($visibility === ReflectionProperty::IS_PUBLIC) { return self::$public_namespace_constants[$namespace_name]; } throw new InvalidArgumentException('Given $visibility not supported'); } public function getFileAnalyzer() : \Psalm\Internal\Analyzer\FileAnalyzer { return $this->source; } /** * Returns true if $calling_identifier is the same as, or is within with $identifier, in a * case-insensitive comparison. Identifiers can be namespaces, classlikes, functions, or methods. * * @psalm-pure * @throws InvalidArgumentException if $identifier is not a valid identifier */ public static function isWithin(string $calling_identifier, string $identifier) : bool { $normalized_calling_ident = self::normalizeIdentifier($calling_identifier); $normalized_ident = self::normalizeIdentifier($identifier); if ($normalized_calling_ident === $normalized_ident) { return \true; } $normalized_calling_ident_parts = self::getIdentifierParts($normalized_calling_ident); $normalized_ident_parts = self::getIdentifierParts($normalized_ident); if (count($normalized_calling_ident_parts) < count($normalized_ident_parts)) { return \false; } for ($i = 0; $i < count($normalized_ident_parts); ++$i) { if ($normalized_ident_parts[$i] !== $normalized_calling_ident_parts[$i]) { return \false; } } return \true; } /** * Returns true if $calling_identifier is the same as or is within any identifier * in $identifiers in a case-insensitive comparison, or if $identifiers is empty. * Identifiers can be namespaces, classlikes, functions, or methods. * * @psalm-pure * @psalm-assert-if-false !empty $identifiers * @param list $identifiers */ public static function isWithinAny(string $calling_identifier, array $identifiers) : bool { if (count($identifiers) === 0) { return \true; } foreach ($identifiers as $identifier) { if (self::isWithin($calling_identifier, $identifier)) { return \true; } } return \false; } /** * @param non-empty-string $fullyQualifiedClassName e.g. '\Psalm\Internal\Analyzer\NamespaceAnalyzer' * @return non-empty-string , e.g. 'Psalm' * @psalm-pure */ public static function getNameSpaceRoot(string $fullyQualifiedClassName) : string { $root_namespace = preg_replace('/^([^\\\\]+).*/', '$1', $fullyQualifiedClassName, 1); if ($root_namespace === "") { throw new InvalidArgumentException("Invalid classname \"{$fullyQualifiedClassName}\""); } return $root_namespace; } /** * @return ($lowercase is true ? lowercase-string : string) * @psalm-pure */ public static function normalizeIdentifier(string $identifier, bool $lowercase = \true) : string { if ($identifier === "") { return ""; } $identifier = $identifier[0] === "\\" ? substr($identifier, 1) : $identifier; return $lowercase ? strtolower($identifier) : $identifier; } /** * Splits an identifier into parts, eg `Foo\Bar::baz` becomes ["Foo", "\\", "Bar", "::", "baz"]. * * @return list * @psalm-pure */ public static function getIdentifierParts(string $identifier) : array { $parts = []; while (($pos = strpos($identifier, "\\")) !== \false) { if ($pos > 0) { $part = substr($identifier, 0, $pos); assert(is_string($part) && $part !== ""); $parts[] = $part; } $parts[] = "\\"; $identifier = substr($identifier, $pos + 1); } if (($pos = strpos($identifier, "::")) !== \false) { if ($pos > 0) { $part = substr($identifier, 0, $pos); assert(is_string($part) && $part !== ""); $parts[] = $part; } $parts[] = "::"; $identifier = substr($identifier, $pos + 2); } if ($identifier !== "" && $identifier !== \false) { $parts[] = $identifier; } return $parts; } } source); } /** @psalm-mutation-free */ public function getAliases() : Aliases { return $this->source->getAliases(); } /** * @psalm-mutation-free * @return array */ public function getAliasedClassesFlipped() : array { return $this->source->getAliasedClassesFlipped(); } /** * @psalm-mutation-free * @return array */ public function getAliasedClassesFlippedReplaceable() : array { return $this->source->getAliasedClassesFlippedReplaceable(); } /** @psalm-mutation-free */ public function getFQCLN() : ?string { return $this->source->getFQCLN(); } /** @psalm-mutation-free */ public function getClassName() : ?string { return $this->source->getClassName(); } /** @psalm-mutation-free */ public function getParentFQCLN() : ?string { return $this->source->getParentFQCLN(); } /** @psalm-mutation-free */ public function getFileName() : string { return $this->source->getFileName(); } /** @psalm-mutation-free */ public function getFilePath() : string { return $this->source->getFilePath(); } /** @psalm-mutation-free */ public function getRootFileName() : string { return $this->source->getRootFileName(); } /** @psalm-mutation-free */ public function getRootFilePath() : string { return $this->source->getRootFilePath(); } public function setRootFilePath(string $file_path, string $file_name) : void { $this->source->setRootFilePath($file_path, $file_name); } /** @psalm-mutation-free */ public function hasParentFilePath(string $file_path) : bool { return $this->source->hasParentFilePath($file_path); } /** @psalm-mutation-free */ public function hasAlreadyRequiredFilePath(string $file_path) : bool { return $this->source->hasAlreadyRequiredFilePath($file_path); } /** @psalm-mutation-free */ public function getRequireNesting() : int { return $this->source->getRequireNesting(); } /** * @psalm-mutation-free */ public function getSource() : StatementsSource { return $this->source; } /** * Get a list of suppressed issues * * @psalm-mutation-free * @return array */ public function getSuppressedIssues() : array { return $this->source->getSuppressedIssues(); } /** * @param array $new_issues */ public function addSuppressedIssues(array $new_issues) : void { $this->source->addSuppressedIssues($new_issues); } /** * @param array $new_issues */ public function removeSuppressedIssues(array $new_issues) : void { $this->source->removeSuppressedIssues($new_issues); } /** @psalm-mutation-free */ public function getNamespace() : ?string { return $this->source->getNamespace(); } /** @psalm-mutation-free */ public function isStatic() : bool { return $this->source->isStatic(); } /** * @psalm-mutation-free */ public function getCodebase() : Codebase { return $this->source->getCodebase(); } /** * @psalm-mutation-free */ public function getProjectAnalyzer() : \Psalm\Internal\Analyzer\ProjectAnalyzer { return $this->source->getProjectAnalyzer(); } /** * @psalm-mutation-free */ public function getFileAnalyzer() : \Psalm\Internal\Analyzer\FileAnalyzer { return $this->source->getFileAnalyzer(); } /** * @psalm-mutation-free * @return array>|null */ public function getTemplateTypeMap() : ?array { return $this->source->getTemplateTypeMap(); } /** @psalm-mutation-free */ public function getNodeTypeProvider() : NodeTypeProvider { return $this->source->getNodeTypeProvider(); } } */ public array $inferred_property_types = []; /** * @param PhpParser\Node\Stmt\Class_|PhpParser\Node\Stmt\Enum_ $class */ public function __construct(PhpParser\Node\Stmt $class, \Psalm\Internal\Analyzer\SourceAnalyzer $source, ?string $fq_class_name) { if (!$fq_class_name) { if (!$class instanceof PhpParser\Node\Stmt\Class_) { throw new UnexpectedValueException('Anonymous enums are not allowed'); } $fq_class_name = self::getAnonymousClassName($class, $source->getAliases(), $source->getFilePath()); } parent::__construct($class, $source, $fq_class_name); if ($this->class instanceof PhpParser\Node\Stmt\Class_ && $this->class->extends) { $this->parent_fq_class_name = self::getFQCLNFromNameObject($this->class->extends, $this->source->getAliases()); } } /** @return non-empty-string */ public static function getAnonymousClassName(PhpParser\Node\Stmt\Class_ $class, Aliases $aliases, string $file_path) : string { $class_name = preg_replace('/[^A-Za-z0-9]/', '_', $file_path) . '_' . $class->getLine() . '_' . (int) $class->getAttribute('startFilePos'); $fq_class_name = Type::getFQCLNFromString($class_name, $aliases); if ($fq_class_name === '') { throw new LogicException('Invalid class name, should never happen'); } return $fq_class_name; } public function analyze(?Context $class_context = null, ?Context $global_context = null) : void { $class = $this->class; if (!$class instanceof PhpParser\Node\Stmt\Class_ && !$class instanceof PhpParser\Node\Stmt\Enum_) { throw new LogicException('Something went badly wrong'); } $fq_class_name = $class_context && $class_context->self ? $class_context->self : $this->fq_class_name; $storage = $this->storage; if ($storage->has_visitor_issues) { return; } if ($class->name && (preg_match('/(^|\\\\)(int|float|bool|string|void|null|false|true|object|mixed)$/i', $fq_class_name) || strtolower($fq_class_name) === 'resource')) { $class_name_parts = explode('\\', $fq_class_name); $class_name = array_pop($class_name_parts); IssueBuffer::maybeAdd(new ReservedWord($class_name . ' is a reserved word', new CodeLocation($this, $class->name, null, \true), $class_name), $storage->suppressed_issues + $this->getSuppressedIssues()); return; } $project_analyzer = $this->file_analyzer->project_analyzer; $codebase = $this->getCodebase(); if ($codebase->alter_code && $class->name && $codebase->classes_to_move) { if (isset($codebase->classes_to_move[strtolower($this->fq_class_name)])) { $destination_class = $codebase->classes_to_move[strtolower($this->fq_class_name)]; $source_class_parts = explode('\\', $this->fq_class_name); $destination_class_parts = explode('\\', $destination_class); array_pop($source_class_parts); array_pop($destination_class_parts); $source_ns = implode('\\', $source_class_parts); $destination_ns = implode('\\', $destination_class_parts); if (strtolower($source_ns) !== strtolower($destination_ns)) { if ($storage->namespace_name_location) { $bounds = $storage->namespace_name_location->getSelectionBounds(); $file_manipulations = [new FileManipulation($bounds[0], $bounds[1], $destination_ns)]; FileManipulationBuffer::add($this->getFilePath(), $file_manipulations); } elseif (!$source_ns) { $first_statement_pos = $this->getFileAnalyzer()->getFirstStatementOffset(); if ($first_statement_pos === -1) { $first_statement_pos = (int) $class->getAttribute('startFilePos'); } $file_manipulations = [new FileManipulation($first_statement_pos, $first_statement_pos, 'namespace ' . $destination_ns . ';' . "\n\n", \true)]; FileManipulationBuffer::add($this->getFilePath(), $file_manipulations); } } } $codebase->classlikes->handleClassLikeReferenceInMigration($codebase, $this, $class->name, $this->fq_class_name, null); } foreach ($storage->docblock_issues as $docblock_issue) { IssueBuffer::maybeAdd($docblock_issue); } $classlike_storage_provider = $codebase->classlike_storage_provider; $parent_fq_class_name = $this->parent_fq_class_name; if ($class instanceof PhpParser\Node\Stmt\Class_ && $class->extends && $parent_fq_class_name) { $this->checkParentClass($class, $class->extends, $fq_class_name, $parent_fq_class_name, $storage, $codebase, $class_context); } $class_union = new Union([new TNamedObject($fq_class_name)]); foreach ($storage->parent_classes + $storage->direct_class_interfaces as $parent_class) { $parent_storage = $codebase->classlikes->getStorageFor($parent_class); if ($parent_storage && $parent_storage->inheritors) { if (!UnionTypeComparator::isContainedBy($codebase, $class_union, $parent_storage->inheritors)) { IssueBuffer::maybeAdd(new InheritorViolation('Class ' . $fq_class_name . ' is not an allowed inheritor of parent class ' . $parent_class, new CodeLocation($this, $this->class)), $this->getSuppressedIssues()); } } } if ($storage->template_types) { foreach ($storage->template_types as $param_name => $_) { $fq_classlike_name = Type::getFQCLNFromString($param_name, $this->getAliases()); if ($codebase->classOrInterfaceExists($fq_classlike_name)) { IssueBuffer::maybeAdd(new ReservedWord('Cannot use ' . $param_name . ' as template name since the class already exists', new CodeLocation($this, $this->class), 'resource'), $this->getSuppressedIssues()); } } } if (($storage->templatedMixins || $storage->namedMixins) && $storage->mixin_declaring_fqcln === $storage->name) { /** @var non-empty-array $mixins */ $mixins = array_merge($storage->templatedMixins, $storage->namedMixins); $union = new Union($mixins); $static_self = new TNamedObject($storage->name, \true); $union = TypeExpander::expandUnion($codebase, $union, $storage->name, $static_self, null); /** @psalm-suppress UnusedMethodCall This call actually has the side effect of creating issues */ $union->check($this, new CodeLocation($this, $class->name ?: $class, null, \true), $this->getSuppressedIssues()); } if ($storage->template_extended_params) { foreach ($storage->template_extended_params as $type_map) { foreach ($type_map as $atomic_type) { /** @psalm-suppress UnusedMethodCall This call actually has the side effect of creating issues */ $atomic_type->check($this, new CodeLocation($this, $class->name ?: $class, null, \true), $storage->getSuppressedIssuesForTemplateExtendParams() + $this->getSuppressedIssues()); } } } if (!$class_context) { $class_context = new Context($this->fq_class_name); $class_context->parent = $parent_fq_class_name; } if ($global_context) { $class_context->strict_types = $global_context->strict_types; } if ($this->checkImplementedInterfaces($class_context, $class, $codebase, $fq_class_name, $storage) === \false) { return; } if ($storage->invalid_dependencies) { return; } if (!$storage->abstract) { foreach ($storage->declaring_method_ids as $declaring_method_id) { $method_storage = $codebase->methods->getStorage($declaring_method_id); $declaring_class_name = $declaring_method_id->fq_class_name; $method_name_lc = $declaring_method_id->method_name; if ($method_storage->abstract) { if (IssueBuffer::accepts(new UnimplementedAbstractMethod('Method ' . $method_name_lc . ' is not defined on class ' . $this->fq_class_name . ', defined abstract in ' . $declaring_class_name, new CodeLocation($this, $class->name ?? $class, $class_context->include_location, \true)), $storage->suppressed_issues + $this->getSuppressedIssues())) { return; } } } } \Psalm\Internal\Analyzer\AttributesAnalyzer::analyze($this, $class_context, $storage, $class->attrGroups, \Psalm\Internal\Analyzer\AttributesAnalyzer::TARGET_CLASS, $storage->suppressed_issues + $this->getSuppressedIssues()); self::addContextProperties($this, $storage, $class_context, $this->fq_class_name, $this->parent_fq_class_name, $class->stmts); $constructor_analyzer = null; $member_stmts = []; foreach ($class->stmts as $stmt) { if ($stmt instanceof PhpParser\Node\Stmt\ClassMethod) { $method_analyzer = $this->analyzeClassMethod($stmt, $storage, $this, $class_context, $global_context); if ($stmt->name->name === '__construct') { $constructor_analyzer = $method_analyzer; } } elseif ($stmt instanceof PhpParser\Node\Stmt\TraitUse) { if ($this->analyzeTraitUse($this->source->getAliases(), $stmt, $project_analyzer, $storage, $class_context, $global_context, $constructor_analyzer) === \false) { return; } } elseif ($stmt instanceof PhpParser\Node\Stmt\Property) { foreach ($stmt->props as $prop) { if ($storage->is_enum) { IssueBuffer::maybeAdd(new NoEnumProperties('Enums cannot have properties', new CodeLocation($this, $prop), $fq_class_name)); continue; } if ($prop->default) { $member_stmts[] = $stmt; } if ($codebase->alter_code) { $property_id = strtolower($this->fq_class_name) . '::$' . $prop->name; $property_storage = $codebase->properties->getStorage($property_id); if ($property_storage->type && $property_storage->type_location && $property_storage->type_location !== $property_storage->signature_type_location) { $replace_type = TypeExpander::expandUnion($codebase, $property_storage->type, $this->getFQCLN(), $this->getFQCLN(), $this->getParentFQCLN()); $codebase->classlikes->handleDocblockTypeInMigration($codebase, $this, $replace_type, $property_storage->type_location, null); } foreach ($codebase->properties_to_rename as $original_property_id => $new_property_name) { if ($property_id === $original_property_id) { $file_manipulations = [new FileManipulation((int) $prop->name->getAttribute('startFilePos'), (int) $prop->name->getAttribute('endFilePos') + 1, '$' . $new_property_name)]; FileManipulationBuffer::add($this->getFilePath(), $file_manipulations); } } } } } elseif ($stmt instanceof PhpParser\Node\Stmt\ClassConst) { $member_stmts[] = $stmt; foreach ($stmt->consts as $const) { if ($const->name->toLowerString() === 'class') { IssueBuffer::maybeAdd(new ReservedWord('A class constant cannot be named \'class\'', new CodeLocation($this, $this->class), $this->fq_class_name)); } $const_id = strtolower($this->fq_class_name) . '::' . $const->name; foreach ($codebase->class_constants_to_rename as $original_const_id => $new_const_name) { if ($const_id === $original_const_id) { $file_manipulations = [new FileManipulation((int) $const->name->getAttribute('startFilePos'), (int) $const->name->getAttribute('endFilePos') + 1, $new_const_name)]; FileManipulationBuffer::add($this->getFilePath(), $file_manipulations); } } } } } $statements_analyzer = new \Psalm\Internal\Analyzer\StatementsAnalyzer($this, new NodeDataProvider()); $statements_analyzer->analyze($member_stmts, $class_context, $global_context, \true); ClassConstAnalyzer::analyze($storage, $this->getCodebase()); $config = Config::getInstance(); if ($class instanceof PhpParser\Node\Stmt\Class_) { $this->checkPropertyInitialization($codebase, $config, $storage, $class_context, $global_context, $constructor_analyzer); } if ($class instanceof PhpParser\Node\Stmt\Enum_) { $this->checkEnum(); } foreach ($class->stmts as $stmt) { if ($stmt instanceof PhpParser\Node\Stmt\Property) { $this->analyzeProperty($this, $stmt, $class_context); } elseif ($stmt instanceof PhpParser\Node\Stmt\TraitUse) { foreach ($stmt->traits as $trait) { $fq_trait_name = self::getFQCLNFromNameObject($trait, $this->source->getAliases()); try { $trait_file_analyzer = $project_analyzer->getFileAnalyzerForClassLike($fq_trait_name); } catch (Exception $e) { continue; } $trait_storage = $codebase->classlike_storage_provider->get($fq_trait_name); $trait_node = $codebase->classlikes->getTraitNode($fq_trait_name); $trait_aliases = $trait_storage->aliases; if ($trait_aliases === null) { continue; } $trait_analyzer = new \Psalm\Internal\Analyzer\TraitAnalyzer($trait_node, $trait_file_analyzer, $fq_trait_name, $trait_aliases); $fq_trait_name_lc = strtolower($fq_trait_name); $this->checkTemplateParams($codebase, $storage, $trait_storage, new CodeLocation($this, $trait), $storage->template_type_uses_count[$fq_trait_name_lc] ?? 0); foreach ($trait_node->stmts as $trait_stmt) { if ($trait_stmt instanceof PhpParser\Node\Stmt\Property) { $this->analyzeProperty($trait_analyzer, $trait_stmt, $class_context); } } $trait_file_analyzer->clearSourceBeforeDestruction(); } } } $pseudo_methods = $storage->pseudo_methods + $storage->pseudo_static_methods; foreach ($pseudo_methods as $pseudo_method_name => $pseudo_method_storage) { $pseudo_method_id = new MethodIdentifier($this->fq_class_name, $pseudo_method_name); $overridden_method_ids = $codebase->methods->getOverriddenMethodIds($pseudo_method_id); if ($overridden_method_ids && $pseudo_method_name !== '__construct' && $pseudo_method_storage->location) { foreach ($overridden_method_ids as $overridden_method_id) { $parent_method_storage = $codebase->methods->getStorage($overridden_method_id); $overridden_fq_class_name = $overridden_method_id->fq_class_name; $parent_storage = $classlike_storage_provider->get($overridden_fq_class_name); \Psalm\Internal\Analyzer\MethodComparator::compare($codebase, null, $storage, $parent_storage, $pseudo_method_storage, $parent_method_storage, $this->fq_class_name, $pseudo_method_storage->visibility ?: 0, $storage->location ?: $pseudo_method_storage->location, $storage->suppressed_issues, \true, \false); } } } $event = new AfterClassLikeAnalysisEvent($class, $storage, $this, $codebase, []); if ($codebase->config->eventDispatcher->dispatchAfterClassLikeAnalysis($event) === \false) { return; } $file_manipulations = $event->getFileReplacements(); if ($file_manipulations) { FileManipulationBuffer::add($this->getFilePath(), $file_manipulations); } } public static function addContextProperties(StatementsSource $statements_source, ClassLikeStorage $storage, Context $class_context, string $fq_class_name, ?string $parent_fq_class_name, array $stmts = []) : void { $codebase = $statements_source->getCodebase(); foreach ($storage->appearing_property_ids as $property_name => $appearing_property_id) { $property_class_name = $codebase->properties->getDeclaringClassForProperty($appearing_property_id, \true); if ($property_class_name === null) { continue; } $property_class_storage = $codebase->classlike_storage_provider->get($property_class_name); $property_storage = $property_class_storage->properties[$property_name]; if (isset($storage->overridden_property_ids[$property_name])) { foreach ($storage->overridden_property_ids[$property_name] as $overridden_property_id) { [$guide_class_name] = explode('::$', $overridden_property_id); $guide_class_storage = $codebase->classlike_storage_provider->get($guide_class_name); $guide_property_storage = $guide_class_storage->properties[$property_name]; if ($property_storage->visibility > $guide_property_storage->visibility && $property_storage->location) { IssueBuffer::maybeAdd(new OverriddenPropertyAccess('Property ' . $fq_class_name . '::$' . $property_name . ' has different access level than ' . $guide_class_name . '::$' . $property_name, $property_storage->location)); } if (($property_storage->signature_type && !$guide_property_storage->signature_type || !$property_storage->signature_type && $guide_property_storage->signature_type || $property_storage->signature_type && !$property_storage->signature_type->equals($guide_property_storage->signature_type)) && $property_storage->location) { IssueBuffer::maybeAdd(new NonInvariantPropertyType('Property ' . $fq_class_name . '::$' . $property_name . ' has type ' . ($property_storage->signature_type ? $property_storage->signature_type->getId() : '') . ", not invariant with " . $guide_class_name . '::$' . $property_name . ' of type ' . ($guide_property_storage->signature_type ? $guide_property_storage->signature_type->getId() : ''), $property_storage->location), $property_storage->suppressed_issues); } if ($property_storage->type === null) { // Property type not set, no need to check for docblock invariance continue; } $property_type = $property_storage->type; $guide_property_type = $guide_property_storage->type ?? Type::getMixed(); // Set upper bounds for all templates $lower_bounds = []; $extended_templates = $storage->template_extended_params ?? []; foreach ($extended_templates as $et_name => $et_array) { foreach ($et_array as $et_class_name => $extended_template) { if (!isset($lower_bounds[$et_class_name][$et_name])) { $lower_bounds[$et_class_name][$et_name] = $extended_template; } } } // Get actual types used for templates (to support @template-covariant) $template_standins = new TemplateResult($lower_bounds, []); TemplateStandinTypeReplacer::fillTemplateResult($guide_property_type, $template_standins, $codebase, null, $property_type); // Iterate over parent classes to find template-covariants, and replace the upper bound with the // standin. Since @template-covariant allows child classes, we want to use the standin type // instead of the template extended type. $parent_class = $storage->parent_class; while ($parent_class !== null) { $parent_storage = $codebase->classlike_storage_provider->get($parent_class); foreach ($parent_storage->template_covariants ?? [] as $pt_offset => $covariant) { if ($covariant) { // If template_covariants is set template_types should also be set assert($parent_storage->template_types !== null); $pt_name = array_keys($parent_storage->template_types)[$pt_offset]; if (isset($template_standins->lower_bounds[$pt_name][$parent_class])) { $lower_bounds[$pt_name][$parent_class] = TemplateStandinTypeReplacer::getMostSpecificTypeFromBounds($template_standins->lower_bounds[$pt_name][$parent_class], $codebase); } } } $parent_class = $parent_storage->parent_class; } $template_result = new TemplateResult([], $lower_bounds); $guide_property_type = TemplateInferredTypeReplacer::replace($guide_property_type, $template_result, $codebase); $property_type = TemplateInferredTypeReplacer::replace($property_type, $template_result, $codebase); if ($guide_property_storage->readonly && UnionTypeComparator::isContainedBy($codebase, $property_type, $guide_property_type, \false, \false, null, \false, \false)) { // if the original property is readonly, it cannot be written // therefore invariance is not a problem, if the parent type contains the child type } elseif ($property_storage->location && !$property_type->equals($guide_property_type, \false) && $guide_class_storage->user_defined) { IssueBuffer::maybeAdd(new NonInvariantDocblockPropertyType('Property ' . $fq_class_name . '::$' . $property_name . ' has type ' . $property_type->getId() . ", not invariant with " . $guide_class_name . '::$' . $property_name . ' of type ' . $guide_property_type->getId(), $property_storage->location), $property_storage->suppressed_issues); } } } if ($property_storage->type) { $property_type = $property_storage->type; if (!$property_type->isMixed() && (!$property_storage->is_promoted || strtolower($fq_class_name) !== strtolower($property_class_name) && isset($storage->declaring_method_ids['__construct']) && strtolower($storage->declaring_method_ids['__construct']->fq_class_name) === strtolower($fq_class_name)) && !$property_storage->has_default && !($property_type->isNullable() && $property_type->from_docblock)) { $property_type = $property_type->setProperties(['initialized' => \false, 'from_property' => \true, 'from_static_property' => $property_storage->is_static === \true]); } } else { if (!$property_storage->has_default && (!$property_storage->is_promoted || strtolower($fq_class_name) !== strtolower($property_class_name) && isset($storage->declaring_method_ids['__construct']) && strtolower($storage->declaring_method_ids['__construct']->fq_class_name) === strtolower($fq_class_name))) { $property_type = new Union([new TMixed()], ['initialized' => \false, 'from_property' => \true, 'from_static_property' => $property_storage->is_static === \true]); } else { $property_type = Type::getMixed(); } } $property_type_location = $property_storage->type_location; $fleshed_out_type = !$property_type->isMixed() ? TypeExpander::expandUnion($codebase, $property_type, $fq_class_name, $fq_class_name, $parent_fq_class_name, \true, \false, $storage->final) : $property_type; $class_template_params = ClassTemplateParamCollector::collect($codebase, $property_class_storage, $storage, null, new TNamedObject($fq_class_name), \true); if ($class_template_params) { $this_object_type = self::getThisObjectType($storage, $fq_class_name); if (!$this_object_type instanceof TGenericObject) { $type_params = []; foreach ($class_template_params as $type_map) { $type_params[] = array_values($type_map)[0]; } $this_object_type = new TGenericObject($this_object_type->value, $type_params); } $fleshed_out_type = AtomicPropertyFetchAnalyzer::localizePropertyType($codebase, $fleshed_out_type, $this_object_type, $storage, $property_class_storage); } if ($property_type_location && !$fleshed_out_type->isMixed()) { $stmt = array_filter($stmts, static fn($stmt): bool => $stmt instanceof PhpParser\Node\Stmt\Property && isset($stmt->props[0]->name->name) && $stmt->props[0]->name->name === $property_name); $suppressed = []; if (count($stmt) > 0) { $stmt = array_pop($stmt); $docComment = $stmt->getDocComment(); if ($docComment) { try { $docBlock = DocComment::parsePreservingLength($docComment); $suppressed = $docBlock->tags['psalm-suppress'] ?? []; } catch (DocblockParseException $e) { // do nothing to keep original behavior } } } /** @psalm-suppress UnusedMethodCall This call actually has the side effect of creating issues */ $fleshed_out_type->check($statements_source, $property_type_location, $storage->suppressed_issues + $statements_source->getSuppressedIssues() + $suppressed, [], \false); if ($property_storage->signature_type) { $union_comparison_result = new TypeComparisonResult(); if (!UnionTypeComparator::isContainedBy($codebase, $fleshed_out_type, $property_storage->signature_type, \false, \false, $union_comparison_result) && !$union_comparison_result->type_coerced_from_mixed) { IssueBuffer::maybeAdd(new MismatchingDocblockPropertyType('Parameter ' . $property_class_name . '::$' . $property_name . ' has wrong type \'' . $fleshed_out_type . '\', should be \'' . $property_storage->signature_type . '\'', $property_type_location)); } } } if ($property_storage->is_static) { $property_id = $fq_class_name . '::$' . $property_name; $class_context->vars_in_scope[$property_id] = $fleshed_out_type; } else { $class_context->vars_in_scope['$this->' . $property_name] = $fleshed_out_type; } } foreach ($storage->pseudo_property_get_types as $property_name => $property_type) { $property_name = substr($property_name, 1); if (isset($class_context->vars_in_scope['$this->' . $property_name])) { $fleshed_out_type = !$property_type->isMixed() ? TypeExpander::expandUnion($codebase, $property_type, $fq_class_name, $fq_class_name, $parent_fq_class_name) : $property_type; $class_context->vars_in_scope['$this->' . $property_name] = $fleshed_out_type; } } } private function checkPropertyInitialization(Codebase $codebase, Config $config, ClassLikeStorage $storage, Context $class_context, ?Context $global_context = null, ?\Psalm\Internal\Analyzer\MethodAnalyzer $constructor_analyzer = null) : void { if (!$config->reportIssueInFile('PropertyNotSetInConstructor', $this->getFilePath())) { return; } if (!isset($storage->declaring_method_ids['__construct']) && !$config->reportIssueInFile('MissingConstructor', $this->getFilePath())) { return; } // abstract constructors do not have any code, therefore cannot set any properties either if (isset($storage->methods['__construct']) && $storage->methods['__construct']->abstract) { return; } $fq_class_name = $class_context->self ?: $this->fq_class_name; $fq_class_name_lc = strtolower($fq_class_name); $included_file_path = $this->getFilePath(); $method_already_analyzed = $codebase->analyzer->isMethodAlreadyAnalyzed($included_file_path, $fq_class_name_lc . '::__construct', \true); if ($method_already_analyzed && !$codebase->diff_methods) { // this can happen when re-analysing a class that has been include()d inside another return; } /** @var PhpParser\Node\Stmt\Class_ */ $class = $this->class; $classlike_storage_provider = $codebase->classlike_storage_provider; $class_storage = $classlike_storage_provider->get($fq_class_name_lc); $constructor_appearing_fqcln = $fq_class_name_lc; $uninitialized_variables = []; $uninitialized_properties = []; $uninitialized_typed_properties = []; $uninitialized_private_properties = \false; foreach ($storage->appearing_property_ids as $property_name => $appearing_property_id) { $property_class_name = $codebase->properties->getDeclaringClassForProperty($appearing_property_id, \true); if ($property_class_name === null) { continue; } $property_class_storage = $classlike_storage_provider->get($property_class_name); $property = $property_class_storage->properties[$property_name]; $property_is_initialized = isset($property_class_storage->initialized_properties[$property_name]); if ($property->is_static) { continue; } if ($property->is_promoted && strtolower($property_class_name) !== $fq_class_name_lc && isset($storage->declaring_method_ids['__construct']) && strtolower($storage->declaring_method_ids['__construct']->fq_class_name) === $fq_class_name_lc) { $property_is_initialized = \false; } if ($property->has_default || $property_is_initialized) { continue; } if ($property->type && $property->type->from_docblock && $property->type->isNullable()) { continue; } if ($codebase->diff_methods && $method_already_analyzed && $property->location) { [$start, $end] = $property->location->getSelectionBounds(); $existing_issues = $codebase->analyzer->getExistingIssuesForFile($this->getFilePath(), $start, $end, 'PropertyNotSetInConstructor'); if ($existing_issues) { IssueBuffer::addIssues([$this->getFilePath() => $existing_issues]); continue; } } if ($property->location) { $codebase->analyzer->removeExistingDataForFile($this->getFilePath(), $property->location->raw_file_start, $property->location->raw_file_end, 'PropertyNotSetInConstructor'); } $codebase->file_reference_provider->addMethodReferenceToMissingClassMember($fq_class_name_lc . '::__construct', strtolower($property_class_name) . '::$' . $property_name); if ($property->visibility === \Psalm\Internal\Analyzer\ClassLikeAnalyzer::VISIBILITY_PRIVATE) { $uninitialized_private_properties = \true; } $uninitialized_variables[] = '$this->' . $property_name; $uninitialized_properties[$property_class_name . '::$' . $property_name] = $property; if ($property->type) { // Complain about all natively typed properties and all non-mixed docblock typed properties if (!$property->type->from_docblock || !$property->type->isMixed()) { $uninitialized_typed_properties[$property_class_name . '::$' . $property_name] = $property; } } } if (!$uninitialized_properties) { return; } if (!$storage->abstract && !$constructor_analyzer && isset($storage->declaring_method_ids['__construct']) && isset($storage->appearing_method_ids['__construct']) && $class->extends) { $constructor_declaring_fqcln = $storage->declaring_method_ids['__construct']->fq_class_name; $constructor_appearing_fqcln = $storage->appearing_method_ids['__construct']->fq_class_name; $constructor_class_storage = $classlike_storage_provider->get($constructor_declaring_fqcln); // ignore oldstyle constructors and classes without any declared properties if ($constructor_class_storage->user_defined && !$constructor_class_storage->stubbed && isset($constructor_class_storage->methods['__construct'])) { $constructor_storage = $constructor_class_storage->methods['__construct']; $fake_constructor_params = array_map(static function (FunctionLikeParameter $param) : PhpParser\Node\Param { $fake_param = new PhpParser\Builder\Param($param->name); if ($param->signature_type) { $fake_param->setType((string) $param->signature_type); } $node = $fake_param->getNode(); $attributes = $param->location ? ['startFilePos' => $param->location->raw_file_start, 'endFilePos' => $param->location->raw_file_end, 'startLine' => $param->location->raw_line_number] : []; $node->setAttributes($attributes); return $node; }, $constructor_storage->params); $fake_constructor_stmt_args = array_map(static function (FunctionLikeParameter $param) : PhpParser\Node\Arg { $attributes = $param->location ? ['startFilePos' => $param->location->raw_file_start, 'endFilePos' => $param->location->raw_file_end, 'startLine' => $param->location->raw_line_number] : []; return new VirtualArg(new VirtualVariable($param->name, $attributes), \false, $param->is_variadic, $attributes); }, $constructor_storage->params); $fake_constructor_attributes = ['startLine' => $class->extends->getLine(), 'startFilePos' => $class->extends->getAttribute('startFilePos'), 'endFilePos' => $class->extends->getAttribute('endFilePos')]; $fake_call_attributes = $fake_constructor_attributes + ['comments' => [new PhpParser\Comment\Doc('/** @psalm-suppress InaccessibleMethod */', $class->extends->getLine(), (int) $class->extends->getAttribute('startFilePos'))]]; $fake_constructor_stmts = [new VirtualExpression(new VirtualStaticCall(new VirtualFullyQualified($constructor_declaring_fqcln), new VirtualIdentifier('__construct', $fake_constructor_attributes), $fake_constructor_stmt_args, $fake_call_attributes), $fake_call_attributes)]; $fake_stmt = new VirtualClassMethod(new VirtualIdentifier('__construct'), ['flags' => PhpParser\Node\Stmt\Class_::MODIFIER_PUBLIC, 'params' => $fake_constructor_params, 'stmts' => $fake_constructor_stmts], $fake_constructor_attributes); $codebase->analyzer->disableMixedCounts(); $was_collecting_initializations = $class_context->collect_initializations; $class_context->collect_initializations = \true; $class_context->collect_nonprivate_initializations = !$uninitialized_private_properties; $constructor_analyzer = $this->analyzeClassMethod($fake_stmt, $storage, $this, $class_context, $global_context, \true); $class_context->collect_initializations = $was_collecting_initializations; $codebase->analyzer->enableMixedCounts(); } } if ($constructor_analyzer) { $method_context = clone $class_context; $method_context->collect_initializations = \true; $method_context->collect_nonprivate_initializations = !$uninitialized_private_properties; $method_context->self = $fq_class_name; $this_atomic_object_type = new TNamedObject($fq_class_name, !$storage->final); $method_context->vars_in_scope['$this'] = new Union([$this_atomic_object_type]); $method_context->vars_possibly_in_scope['$this'] = \true; $method_context->calling_method_id = strtolower($fq_class_name) . '::__construct'; $constructor_analyzer->analyze($method_context, new NodeDataProvider(), $global_context, \true); foreach ($uninitialized_properties as $property_id => $property_storage) { [, $property_name] = explode('::$', $property_id); if (!isset($method_context->vars_in_scope['$this->' . $property_name])) { $end_type = new Union([new TVoid()], ['initialized' => \false]); } else { $end_type = $method_context->vars_in_scope['$this->' . $property_name]; } $constructor_class_property_storage = $property_storage; $error_location = $property_storage->location; if ($storage->declaring_property_ids[$property_name] !== $fq_class_name) { $error_location = $storage->location ?: $storage->stmt_location; } if ($fq_class_name_lc !== $constructor_appearing_fqcln && $property_storage->visibility === \Psalm\Internal\Analyzer\ClassLikeAnalyzer::VISIBILITY_PRIVATE) { $a_class_storage = $classlike_storage_provider->get($end_type->initialized_class ?: $constructor_appearing_fqcln); if (!isset($a_class_storage->declaring_property_ids[$property_name])) { $constructor_class_property_storage = null; } else { $declaring_property_class = $a_class_storage->declaring_property_ids[$property_name]; $constructor_class_property_storage = $classlike_storage_provider->get($declaring_property_class)->properties[$property_name]; } } if ($property_storage->location && $error_location && (!$end_type->initialized || $property_storage !== $constructor_class_property_storage)) { if ($property_storage->type) { $expected_visibility = $uninitialized_private_properties ? 'private or final ' : ''; IssueBuffer::maybeAdd(new PropertyNotSetInConstructor('Property ' . $class_storage->name . '::$' . $property_name . ' is not defined in constructor of ' . $this->fq_class_name . ' or in any ' . $expected_visibility . 'methods called in the constructor', $error_location, $property_id), $storage->suppressed_issues + $this->getSuppressedIssues()); } elseif (!$property_storage->has_default) { if (isset($this->inferred_property_types[$property_name])) { $this->inferred_property_types[$property_name] = $this->inferred_property_types[$property_name]->getBuilder()->addType(new TNull())->setFromDocblock(\true)->freeze(); } } } } $codebase->analyzer->setAnalyzedMethod($included_file_path, $fq_class_name_lc . '::__construct', \true); return; } if (!$storage->abstract && $uninitialized_typed_properties) { foreach ($uninitialized_typed_properties as $id => $uninitialized_property) { if ($uninitialized_property->location) { IssueBuffer::maybeAdd(new MissingConstructor($class_storage->name . ' has an uninitialized property ' . $id . ', but no constructor', $uninitialized_property->location, $class_storage->name . '::' . $uninitialized_variables[0]), $storage->suppressed_issues + $this->getSuppressedIssues()); } } } } /** * @return false|null */ private function analyzeTraitUse(Aliases $aliases, PhpParser\Node\Stmt\TraitUse $stmt, \Psalm\Internal\Analyzer\ProjectAnalyzer $project_analyzer, ClassLikeStorage $storage, Context $class_context, ?Context $global_context = null, ?\Psalm\Internal\Analyzer\MethodAnalyzer &$constructor_analyzer = null, ?\Psalm\Internal\Analyzer\TraitAnalyzer $previous_trait_analyzer = null) : ?bool { $codebase = $this->getCodebase(); $previous_context_include_location = $class_context->include_location; foreach ($stmt->traits as $trait_name) { $trait_location = new CodeLocation($this, $trait_name, null, \true); $class_context->include_location = new CodeLocation($this, $trait_name, null, \true); $fq_trait_name = self::getFQCLNFromNameObject($trait_name, $aliases); if (!$codebase->classlikes->hasFullyQualifiedTraitName($fq_trait_name, $trait_location)) { IssueBuffer::maybeAdd(new UndefinedTrait('Trait ' . $fq_trait_name . ' does not exist', new CodeLocation($previous_trait_analyzer ?? $this, $trait_name)), $storage->suppressed_issues + $this->getSuppressedIssues()); return \false; } if (!$codebase->traitHasCorrectCasing($fq_trait_name)) { if (IssueBuffer::accepts(new UndefinedTrait('Trait ' . $fq_trait_name . ' has wrong casing', new CodeLocation($previous_trait_analyzer ?? $this, $trait_name)), $storage->suppressed_issues + $this->getSuppressedIssues())) { return \false; } continue; } $fq_trait_name_resolved = $codebase->classlikes->getUnAliasedName($fq_trait_name); $trait_storage = $codebase->classlike_storage_provider->get($fq_trait_name_resolved); if ($trait_storage->deprecated) { IssueBuffer::maybeAdd(new DeprecatedTrait('Trait ' . $fq_trait_name . ' is deprecated', new CodeLocation($previous_trait_analyzer ?? $this, $trait_name)), $storage->suppressed_issues + $this->getSuppressedIssues()); } if ($trait_storage->extension_requirement !== null) { $extension_requirement = $codebase->classlikes->getUnAliasedName($trait_storage->extension_requirement); $extensionRequirementMet = in_array($extension_requirement, $storage->parent_classes); if (!$extensionRequirementMet) { IssueBuffer::maybeAdd(new ExtensionRequirementViolation($fq_trait_name . ' requires using class to extend ' . $extension_requirement . ', but ' . $storage->name . ' does not', new CodeLocation($previous_trait_analyzer ?? $this, $trait_name)), $storage->suppressed_issues + $this->getSuppressedIssues()); } } foreach ($trait_storage->implementation_requirements as $implementation_requirement) { $implementation_requirement = $codebase->classlikes->getUnAliasedName($implementation_requirement); $implementationRequirementMet = in_array($implementation_requirement, $storage->class_implements); if (!$implementationRequirementMet) { IssueBuffer::maybeAdd(new ImplementationRequirementViolation($fq_trait_name . ' requires using class to implement ' . $implementation_requirement . ', but ' . $storage->name . ' does not', new CodeLocation($previous_trait_analyzer ?? $this, $trait_name)), $storage->suppressed_issues + $this->getSuppressedIssues()); } } if ($storage->mutation_free && !$trait_storage->mutation_free) { IssueBuffer::maybeAdd(new MutableDependency($storage->name . ' is marked @psalm-immutable but ' . $fq_trait_name . ' is not', new CodeLocation($previous_trait_analyzer ?? $this, $trait_name)), $storage->suppressed_issues + $this->getSuppressedIssues()); } $trait_file_analyzer = $project_analyzer->getFileAnalyzerForClassLike($fq_trait_name_resolved); $trait_node = $codebase->classlikes->getTraitNode($fq_trait_name_resolved); $trait_aliases = $trait_storage->aliases; if ($trait_aliases === null) { continue; } $trait_analyzer = new \Psalm\Internal\Analyzer\TraitAnalyzer($trait_node, $trait_file_analyzer, $fq_trait_name_resolved, $trait_aliases); foreach ($trait_node->stmts as $trait_stmt) { if ($trait_stmt instanceof PhpParser\Node\Stmt\ClassMethod) { $trait_method_analyzer = $this->analyzeClassMethod($trait_stmt, $storage, $trait_analyzer, $class_context, $global_context); if ($trait_stmt->name->name === '__construct') { $constructor_analyzer = $trait_method_analyzer; } } elseif ($trait_stmt instanceof PhpParser\Node\Stmt\TraitUse) { if ($this->analyzeTraitUse($trait_aliases, $trait_stmt, $project_analyzer, $storage, $class_context, $global_context, $constructor_analyzer, $trait_analyzer) === \false) { return \false; } } } $trait_file_analyzer->clearSourceBeforeDestruction(); } $class_context->include_location = $previous_context_include_location; return null; } private function analyzeProperty(\Psalm\Internal\Analyzer\SourceAnalyzer $source, PhpParser\Node\Stmt\Property $stmt, Context $context) : void { $fq_class_name = $source->getFQCLN(); $property_name = $stmt->props[0]->name->name; $codebase = $this->getCodebase(); $property_id = $fq_class_name . '::$' . $property_name; $declaring_property_class = $codebase->properties->getDeclaringClassForProperty($property_id, \true); if (!$declaring_property_class) { return; } $fq_class_name = $declaring_property_class; // gets inherited property type $class_property_type = $codebase->properties->getPropertyType($property_id, \false, $source, $context); $class_storage = $codebase->classlike_storage_provider->get($fq_class_name); $property_storage = $class_storage->properties[$property_name]; \Psalm\Internal\Analyzer\AttributesAnalyzer::analyze($source, $context, $property_storage, $stmt->attrGroups, \Psalm\Internal\Analyzer\AttributesAnalyzer::TARGET_PROPERTY, $property_storage->suppressed_issues + $this->getSuppressedIssues()); if ($class_property_type && ($property_storage->type_location || !$codebase->alter_code)) { return; } $message = 'Property ' . $property_id . ' does not have a declared type'; $suggested_type = $property_storage->suggested_type; if (isset($this->inferred_property_types[$property_name])) { $suggested_type = Type::combineUnionTypes($suggested_type, $this->inferred_property_types[$property_name] ?? null, $codebase); } if ($suggested_type && !$property_storage->has_default && $property_storage->is_static) { $suggested_type = $suggested_type->getBuilder()->addType(new TNull())->freeze(); } if ($suggested_type && !$suggested_type->isNull()) { $message .= ' - consider ' . str_replace(['', ''], '', $suggested_type->getId(\false)); } $project_analyzer = \Psalm\Internal\Analyzer\ProjectAnalyzer::getInstance(); if ($codebase->alter_code && $source === $this && isset($project_analyzer->getIssuesToFix()['MissingPropertyType']) && !in_array('MissingPropertyType', $this->getSuppressedIssues()) && $suggested_type) { if ($suggested_type->hasMixed() || $suggested_type->isNull()) { return; } self::addOrUpdatePropertyType($project_analyzer, $stmt, $suggested_type, $this, $suggested_type->from_docblock); return; } IssueBuffer::maybeAdd(new MissingPropertyType($message, new CodeLocation($source, $stmt->props[0]->name), $property_id), $this->source->getSuppressedIssues() + $property_storage->suppressed_issues); } private static function addOrUpdatePropertyType(\Psalm\Internal\Analyzer\ProjectAnalyzer $project_analyzer, PhpParser\Node\Stmt\Property $property, Union $inferred_type, StatementsSource $source, bool $docblock_only = \false) : void { $manipulator = PropertyDocblockManipulator::getForProperty($project_analyzer, $source->getFilePath(), $property); $codebase = $project_analyzer->getCodebase(); $allow_native_type = !$docblock_only && $codebase->analysis_php_version_id >= 70400 && $codebase->allow_backwards_incompatible_changes && $inferred_type->getCallableTypes() === []; $manipulator->setType($allow_native_type ? (string) $inferred_type->toPhpString($source->getNamespace(), $source->getAliasedClassesFlipped(), $source->getFQCLN(), $codebase->analysis_php_version_id) : null, $inferred_type->toNamespacedString($source->getNamespace(), $source->getAliasedClassesFlipped(), $source->getFQCLN(), \false), $inferred_type->toNamespacedString($source->getNamespace(), $source->getAliasedClassesFlipped(), $source->getFQCLN(), \true), $inferred_type->canBeFullyExpressedInPhp($codebase->analysis_php_version_id)); } private function analyzeClassMethod(PhpParser\Node\Stmt\ClassMethod $stmt, ClassLikeStorage $class_storage, \Psalm\Internal\Analyzer\SourceAnalyzer $source, Context $class_context, ?Context $global_context = null, bool $is_fake = \false) : ?\Psalm\Internal\Analyzer\MethodAnalyzer { $config = Config::getInstance(); if ($stmt->stmts === null && !$stmt->isAbstract()) { IssueBuffer::maybeAdd(new ParseError('Non-abstract class method must have statements', new CodeLocation($this, $stmt))); return null; } try { $method_analyzer = new \Psalm\Internal\Analyzer\MethodAnalyzer($stmt, $source); } catch (UnexpectedValueException $e) { IssueBuffer::maybeAdd(new ParseError('Problem loading method: ' . $e->getMessage(), new CodeLocation($this, $stmt))); return null; } $actual_method_id = $method_analyzer->getMethodId(); $project_analyzer = $source->getProjectAnalyzer(); $codebase = $source->getCodebase(); $analyzed_method_id = $actual_method_id; $included_file_path = $source->getFilePath(); if ($class_context->self && strtolower($class_context->self) !== strtolower((string) $source->getFQCLN())) { $analyzed_method_id = $method_analyzer->getMethodId($class_context->self); $declaring_method_id = $codebase->methods->getDeclaringMethodId($analyzed_method_id); if ((string) $actual_method_id !== (string) $declaring_method_id) { // the method is an abstract trait method $declaring_method_storage = $method_analyzer->getFunctionLikeStorage(); if (!$declaring_method_storage instanceof MethodStorage) { throw new LogicException('This should never happen'); } if ($declaring_method_id && $declaring_method_storage->abstract) { $implementer_method_storage = $codebase->methods->getStorage($declaring_method_id); $declaring_storage = $codebase->classlike_storage_provider->get($actual_method_id->fq_class_name); \Psalm\Internal\Analyzer\MethodComparator::compare($codebase, null, $class_storage, $declaring_storage, $implementer_method_storage, $declaring_method_storage, $this->fq_class_name, $implementer_method_storage->visibility, new CodeLocation($source, $stmt), $implementer_method_storage->suppressed_issues, \false); } return null; } } $trait_safe_method_id = strtolower((string) $analyzed_method_id); $actual_method_id_str = strtolower((string) $actual_method_id); if ($actual_method_id_str !== $trait_safe_method_id) { $trait_safe_method_id .= '&' . $actual_method_id_str; } $method_already_analyzed = $codebase->analyzer->isMethodAlreadyAnalyzed($included_file_path, $trait_safe_method_id); $start = (int) $stmt->getAttribute('startFilePos'); $end = (int) $stmt->getAttribute('endFilePos'); $comments = $stmt->getComments(); if ($comments) { $start = $comments[0]->getStartFilePos(); } if ($codebase->diff_methods && $method_already_analyzed && !$class_context->collect_initializations && !$class_context->collect_mutations && !$is_fake) { $project_analyzer->progress->debug('Skipping analysis of pre-analyzed method ' . $analyzed_method_id . "\n"); $existing_issues = $codebase->analyzer->getExistingIssuesForFile($source->getFilePath(), $start, $end); IssueBuffer::addIssues([$source->getFilePath() => $existing_issues]); return $method_analyzer; } $codebase->analyzer->removeExistingDataForFile($source->getFilePath(), $start, $end); $method_context = clone $class_context; foreach ($method_context->vars_in_scope as $context_var_id => $context_type) { if ($context_type->from_property && $stmt->name->name !== '__construct') { $method_context->vars_in_scope[$context_var_id] = $method_context->vars_in_scope[$context_var_id]->setProperties(['initialized' => \true]); } } $method_context->collect_exceptions = $config->check_for_throws_docblock; $type_provider = new NodeDataProvider(); $method_analyzer->analyze($method_context, $type_provider, $global_context ? clone $global_context : null); if ($stmt->name->name !== '__construct' && $config->reportIssueInFile('InvalidReturnType', $source->getFilePath()) && $class_context->self) { self::analyzeClassMethodReturnType($stmt, $method_analyzer, $source, $type_provider, $codebase, $class_storage, $class_context->self, $analyzed_method_id, $actual_method_id, $method_context->has_returned); } if (!$method_already_analyzed && !$class_context->collect_initializations && !$class_context->collect_mutations && !$is_fake) { $codebase->analyzer->setAnalyzedMethod($included_file_path, $trait_safe_method_id); } return $method_analyzer; } private static function getThisObjectType(ClassLikeStorage $class_storage, string $original_fq_classlike_name) : TNamedObject { if ($class_storage->template_types) { $template_params = []; foreach ($class_storage->template_types as $param_name => $template_map) { $key = array_keys($template_map)[0]; $template_params[] = new Union([new TTemplateParam($param_name, reset($template_map), $key)]); } return new TGenericObject($original_fq_classlike_name, $template_params); } return new TNamedObject($original_fq_classlike_name); } public static function analyzeClassMethodReturnType(PhpParser\Node\Stmt\ClassMethod $stmt, \Psalm\Internal\Analyzer\MethodAnalyzer $method_analyzer, \Psalm\Internal\Analyzer\SourceAnalyzer $source, NodeDataProvider $type_provider, Codebase $codebase, ClassLikeStorage $class_storage, string $fq_classlike_name, MethodIdentifier $analyzed_method_id, MethodIdentifier $actual_method_id, bool $did_explicitly_return) : void { $secondary_return_type_location = null; $actual_method_storage = $codebase->methods->getStorage($actual_method_id); $return_type_location = $codebase->methods->getMethodReturnTypeLocation($actual_method_id, $secondary_return_type_location); $original_fq_classlike_name = $fq_classlike_name; $return_type = $codebase->methods->getMethodReturnType($analyzed_method_id, $fq_classlike_name, $method_analyzer); if ($return_type && $class_storage->template_extended_params) { $declaring_method_id = $codebase->methods->getDeclaringMethodId($analyzed_method_id); if ($declaring_method_id) { $declaring_class_name = $declaring_method_id->fq_class_name; $class_storage = $codebase->classlike_storage_provider->get($declaring_class_name); } $this_object_type = self::getThisObjectType($class_storage, $original_fq_classlike_name); $class_template_params = ClassTemplateParamCollector::collect($codebase, $class_storage, $codebase->classlike_storage_provider->get($original_fq_classlike_name), strtolower($stmt->name->name), $this_object_type) ?: []; $template_result = new TemplateResult($class_template_params ?: [], []); $return_type = TemplateStandinTypeReplacer::replace($return_type, $template_result, $codebase, null, null, null, $original_fq_classlike_name); } $overridden_method_ids = $class_storage->overridden_method_ids[strtolower($stmt->name->name)] ?? []; if (!$return_type && !$class_storage->is_interface && $overridden_method_ids) { foreach ($overridden_method_ids as $interface_method_id) { $interface_class = $interface_method_id->fq_class_name; if (!$codebase->classlikes->interfaceExists($interface_class)) { continue; } $interface_return_type = $codebase->methods->getMethodReturnType($interface_method_id, $interface_class); $interface_return_type_location = $codebase->methods->getMethodReturnTypeLocation($interface_method_id); ReturnTypeAnalyzer::verifyReturnType($stmt, $stmt->getStmts() ?: [], $source, $type_provider, $method_analyzer, $interface_return_type, $interface_class, $original_fq_classlike_name, $interface_return_type_location, [$analyzed_method_id->__toString()], $did_explicitly_return); } } $overridden_method_ids = array_map(static fn($method_id): string => $method_id->__toString(), $overridden_method_ids); if ($actual_method_storage->overridden_downstream) { $overridden_method_ids['overridden::downstream'] = 'overridden::downstream'; } ReturnTypeAnalyzer::verifyReturnType($stmt, $stmt->getStmts() ?: [], $source, $type_provider, $method_analyzer, $return_type, $fq_classlike_name, $original_fq_classlike_name, $return_type_location, $overridden_method_ids, $did_explicitly_return); } /** * @param PhpParser\Node\Stmt\Class_|PhpParser\Node\Stmt\Enum_ $class */ private function checkImplementedInterfaces(Context $class_context, PhpParser\Node\Stmt $class, Codebase $codebase, string $fq_class_name, ClassLikeStorage $storage) : bool { $classlike_storage_provider = $codebase->classlike_storage_provider; foreach ($class->implements as $interface_name) { $fq_interface_name = self::getFQCLNFromNameObject($interface_name, $this->source->getAliases()); $fq_interface_name_lc = strtolower($fq_interface_name); $codebase->analyzer->addNodeReference($this->getFilePath(), $interface_name, $codebase->classlikes->interfaceExists($fq_interface_name) ? $fq_interface_name : '*' . ($interface_name instanceof PhpParser\Node\Name\FullyQualified ? '\\' : $this->getNamespace() . '-') . $interface_name->toString()); $interface_location = new CodeLocation($this, $interface_name); if (self::checkFullyQualifiedClassLikeName($this, $fq_interface_name, $interface_location, null, null, $this->getSuppressedIssues()) === \false) { return \false; } if ($codebase->store_node_types && $fq_class_name) { $bounds = $interface_location->getSelectionBounds(); $codebase->analyzer->addOffsetReference($this->getFilePath(), $bounds[0], $bounds[1], $fq_interface_name); } $codebase->classlikes->handleClassLikeReferenceInMigration($codebase, $this, $interface_name, $fq_interface_name, null); try { $interface_storage = $classlike_storage_provider->get($fq_interface_name); } catch (InvalidArgumentException $e) { return \false; } $code_location = new CodeLocation($this, $interface_name, $class_context->include_location, \true); if (!$interface_storage->is_interface) { IssueBuffer::maybeAdd(new UndefinedInterface($fq_interface_name . ' is not an interface', $code_location, $fq_interface_name), $storage->suppressed_issues + $this->getSuppressedIssues()); } $this->checkTemplateParams($codebase, $storage, $interface_storage, $code_location, $storage->template_type_implements_count[$fq_interface_name_lc] ?? 0); } foreach ($storage->class_implements as $fq_interface_name_lc => $fq_interface_name) { try { $interface_storage = $classlike_storage_provider->get($fq_interface_name_lc); } catch (InvalidArgumentException $e) { return \false; } $code_location = new CodeLocation($this, $class->name ?? $class, $class_context->include_location, \true); if ($fq_interface_name_lc === 'traversable' && !$storage->abstract && !isset($storage->class_implements['iteratoraggregate']) && !isset($storage->class_implements['iterator']) && !isset($storage->parent_classes['pdostatement']) && !isset($storage->parent_classes['ds\\collection']) && !isset($storage->parent_classes['domnodelist']) && !isset($storage->parent_classes['dateperiod'])) { IssueBuffer::maybeAdd(new InvalidTraversableImplementation('Traversable should be implemented by implementing IteratorAggregate or Iterator', $code_location, $fq_class_name)); } if ($fq_interface_name_lc === 'throwable' && $codebase->analysis_php_version_id >= 70000 && !$storage->abstract && !isset($storage->parent_classes['exception']) && !isset($storage->parent_classes['error'])) { IssueBuffer::maybeAdd(new InvalidInterfaceImplementation('Classes implementing Throwable should extend Exception or Error', $code_location, $fq_class_name)); } if (($fq_interface_name_lc === 'unitenum' || $fq_interface_name_lc === 'backedenum') && !$storage->is_enum && $codebase->analysis_php_version_id >= 80100) { IssueBuffer::maybeAdd(new InvalidInterfaceImplementation($fq_interface_name . ' cannot be implemented by classes', $code_location, $fq_class_name)); } if ($interface_storage->deprecated) { IssueBuffer::maybeAdd(new DeprecatedInterface($fq_interface_name . ' is marked deprecated', $code_location, $fq_interface_name), $storage->suppressed_issues + $this->getSuppressedIssues()); } if ($interface_storage->external_mutation_free && !$storage->external_mutation_free) { IssueBuffer::maybeAdd(new MissingImmutableAnnotation($fq_interface_name . ' is marked @psalm-immutable, but ' . $fq_class_name . ' is not marked @psalm-immutable', $code_location), $storage->suppressed_issues + $this->getSuppressedIssues()); } foreach ($interface_storage->methods as $interface_method_name_lc => $interface_method_storage) { if ($interface_method_storage->visibility === self::VISIBILITY_PUBLIC) { $implementer_declaring_method_id = $codebase->methods->getDeclaringMethodId(new MethodIdentifier($this->fq_class_name, $interface_method_name_lc)); $implementer_method_storage = null; $implementer_classlike_storage = null; if ($implementer_declaring_method_id) { $implementer_fq_class_name = $implementer_declaring_method_id->fq_class_name; $implementer_method_storage = $codebase->methods->getStorage($implementer_declaring_method_id); $implementer_classlike_storage = $classlike_storage_provider->get($implementer_fq_class_name); } if ($storage->is_enum) { if ($interface_method_name_lc === 'cases') { continue; } if ($storage->enum_type && in_array($interface_method_name_lc, ['from', 'tryfrom'], \true)) { continue; } } if (!$implementer_method_storage) { IssueBuffer::maybeAdd(new UnimplementedInterfaceMethod('Method ' . $interface_method_name_lc . ' is not defined on class ' . $storage->name, $code_location), $storage->suppressed_issues + $this->getSuppressedIssues()); return \true; } $implementer_appearing_method_id = $codebase->methods->getAppearingMethodId(new MethodIdentifier($this->fq_class_name, $interface_method_name_lc)); $implementer_visibility = $implementer_method_storage->visibility; if ($implementer_appearing_method_id && $implementer_appearing_method_id !== $implementer_declaring_method_id) { $appearing_fq_class_name = $implementer_appearing_method_id->fq_class_name; $appearing_method_name = $implementer_appearing_method_id->method_name; $appearing_class_storage = $classlike_storage_provider->get($appearing_fq_class_name); if (isset($appearing_class_storage->trait_visibility_map[$appearing_method_name])) { $implementer_visibility = $appearing_class_storage->trait_visibility_map[$appearing_method_name]; } } if ($implementer_visibility !== self::VISIBILITY_PUBLIC) { IssueBuffer::maybeAdd(new InaccessibleMethod('Interface-defined method ' . $implementer_method_storage->cased_name . ' must be public in ' . $storage->name, $code_location), $storage->suppressed_issues + $this->getSuppressedIssues()); return \true; } if ($interface_method_storage->is_static && !$implementer_method_storage->is_static) { IssueBuffer::maybeAdd(new MethodSignatureMismatch('Method ' . $implementer_method_storage->cased_name . ' should be static like ' . $storage->name . '::' . $interface_method_storage->cased_name, $code_location), $implementer_method_storage->suppressed_issues); return \true; } if ($storage->abstract && $implementer_method_storage === $interface_method_storage) { continue; } \Psalm\Internal\Analyzer\MethodComparator::compare($codebase, null, $implementer_classlike_storage ?? $storage, $interface_storage, $implementer_method_storage, $interface_method_storage, $this->fq_class_name, $implementer_visibility, $code_location, $implementer_method_storage->suppressed_issues, \false); } } } return \true; } private function checkParentClass(Class_ $class, PhpParser\Node\Name $extended_class, string $fq_class_name, string $parent_fq_class_name, ClassLikeStorage $storage, Codebase $codebase, ?Context $class_context) : void { $classlike_storage_provider = $codebase->classlike_storage_provider; if (!$parent_fq_class_name) { throw new UnexpectedValueException('Parent class should be filled in for ' . $fq_class_name); } $parent_reference_location = new CodeLocation($this, $extended_class); if (self::checkFullyQualifiedClassLikeName($this->getSource(), $parent_fq_class_name, $parent_reference_location, null, null, $storage->suppressed_issues + $this->getSuppressedIssues()) === \false) { return; } if ($codebase->alter_code && $codebase->classes_to_move) { $codebase->classlikes->handleClassLikeReferenceInMigration($codebase, $this, $extended_class, $parent_fq_class_name, null); } try { $parent_class_storage = $classlike_storage_provider->get($parent_fq_class_name); $code_location = new CodeLocation($this, $extended_class, $class_context->include_location ?? null, \true); if ($parent_class_storage->is_trait || $parent_class_storage->is_interface) { IssueBuffer::maybeAdd(new UndefinedClass($parent_fq_class_name . ' is not a class', $code_location, $parent_fq_class_name . ' as class'), $storage->suppressed_issues + $this->getSuppressedIssues()); } if ($parent_class_storage->final) { IssueBuffer::maybeAdd(new InvalidExtendClass('Class ' . $fq_class_name . ' may not inherit from final class ' . $parent_fq_class_name, $code_location, $fq_class_name), $storage->suppressed_issues + $this->getSuppressedIssues()); } if ($parent_class_storage->readonly && !$storage->readonly) { IssueBuffer::maybeAdd(new InvalidExtendClass('Non-readonly class ' . $fq_class_name . ' may not inherit from ' . 'readonly class ' . $parent_fq_class_name, $code_location, $fq_class_name), $storage->suppressed_issues + $this->getSuppressedIssues()); } if ($parent_class_storage->deprecated) { IssueBuffer::maybeAdd(new DeprecatedClass($parent_fq_class_name . ' is marked deprecated', $code_location, $parent_fq_class_name), $storage->suppressed_issues + $this->getSuppressedIssues()); } if (!\Psalm\Internal\Analyzer\NamespaceAnalyzer::isWithinAny($fq_class_name, $parent_class_storage->internal)) { IssueBuffer::maybeAdd(new InternalClass($parent_fq_class_name . ' is internal to ' . InternalClass::listToPhrase($parent_class_storage->internal) . ' but called from ' . $fq_class_name, $code_location, $parent_fq_class_name), $storage->suppressed_issues + $this->getSuppressedIssues()); } if ($parent_class_storage->external_mutation_free && !$storage->external_mutation_free) { IssueBuffer::maybeAdd(new MissingImmutableAnnotation($parent_fq_class_name . ' is marked @psalm-immutable, but ' . $fq_class_name . ' is not marked @psalm-immutable', $code_location), $storage->suppressed_issues + $this->getSuppressedIssues()); } if ($storage->mutation_free && !$parent_class_storage->mutation_free) { IssueBuffer::maybeAdd(new MutableDependency($fq_class_name . ' is marked @psalm-immutable but ' . $parent_fq_class_name . ' is not', $code_location), $storage->suppressed_issues + $this->getSuppressedIssues()); } if ($codebase->store_node_types) { $codebase->analyzer->addNodeReference($this->getFilePath(), $extended_class, $codebase->classlikes->classExists($parent_fq_class_name) ? $parent_fq_class_name : '*' . ($extended_class instanceof PhpParser\Node\Name\FullyQualified ? '\\' : $this->getNamespace() . '-') . $extended_class->toString()); } $code_location = new CodeLocation($this, $class->name ?: $class, $class_context->include_location ?? null, \true); $this->checkTemplateParams($codebase, $storage, $parent_class_storage, $code_location, $storage->template_type_extends_count[$parent_fq_class_name] ?? 0); } catch (InvalidArgumentException $e) { // do nothing } } private function checkEnum() : void { $storage = $this->storage; $seen_values = []; foreach ($storage->enum_cases as $case_storage) { $case_value = $case_storage->getValue($this->getCodebase()->classlikes); if ($case_value !== null && $storage->enum_type === null) { IssueBuffer::maybeAdd(new InvalidEnumCaseValue('Case of a non-backed enum should not have a value', $case_storage->stmt_location, $storage->name)); } elseif ($case_value === null && $storage->enum_type !== null) { IssueBuffer::maybeAdd(new InvalidEnumCaseValue('Case of a backed enum should have a value', $case_storage->stmt_location, $storage->name)); } elseif ($case_value !== null) { if (is_int($case_value) && $storage->enum_type === 'string' || is_string($case_value) && $storage->enum_type === 'int') { IssueBuffer::maybeAdd(new InvalidEnumCaseValue('Enum case value type should be ' . $storage->enum_type, $case_storage->stmt_location, $storage->name)); } } if ($case_value !== null) { if (in_array($case_value, $seen_values, \true)) { IssueBuffer::maybeAdd(new DuplicateEnumCaseValue('Enum case values should be unique', $case_storage->stmt_location, $storage->name)); } else { $seen_values[] = $case_value; } } } } } source = $source; $this->file_analyzer = $source->getFileAnalyzer(); $this->aliases = $source->getAliases(); $this->class = $class; $this->fq_class_name = $fq_class_name; $codebase = $source->getCodebase(); $this->storage = $codebase->classlike_storage_provider->get($fq_class_name); $this->aliases = $aliases; } /** @psalm-mutation-free */ public function getNamespace() : ?string { return $this->aliases->namespace; } /** @psalm-mutation-free */ public function getAliases() : Aliases { return $this->aliases; } /** * @psalm-mutation-free * @return array */ public function getAliasedClassesFlipped() : array { return []; } /** * @psalm-mutation-free * @return array */ public function getAliasedClassesFlippedReplaceable() : array { return []; } public static function analyze(\Psalm\Internal\Analyzer\StatementsAnalyzer $statements_analyzer, Trait_ $stmt, Context $context) : void { assert($stmt->name !== null); $codebase = $statements_analyzer->getCodebase(); if (!$codebase->classlike_storage_provider->has($stmt->name->name)) { return; } $storage = $codebase->classlike_storage_provider->get($stmt->name->name); \Psalm\Internal\Analyzer\AttributesAnalyzer::analyze($statements_analyzer, $context, $storage, $stmt->attrGroups, \Psalm\Internal\Analyzer\AttributesAnalyzer::TARGET_CLASS, $storage->suppressed_issues + $statements_analyzer->getSuppressedIssues()); foreach ($storage->docblock_issues as $docblock_issue) { IssueBuffer::maybeAdd($docblock_issue); } } } */ final class ClosureAnalyzer extends \Psalm\Internal\Analyzer\FunctionLikeAnalyzer { /** * @param PhpParser\Node\Expr\Closure|PhpParser\Node\Expr\ArrowFunction $function */ public function __construct(PhpParser\Node\FunctionLike $function, \Psalm\Internal\Analyzer\SourceAnalyzer $source) { $codebase = $source->getCodebase(); $function_id = strtolower($source->getFilePath()) . ':' . $function->getLine() . ':' . (int) $function->getAttribute('startFilePos') . ':-:closure'; $storage = $codebase->getClosureStorage($source->getFilePath(), $function_id); parent::__construct($function, $source, $storage); } /** @psalm-mutation-free */ public function getTemplateTypeMap() : ?array { return $this->source->getTemplateTypeMap(); } /** * @return non-empty-lowercase-string */ public function getClosureId() : string { return strtolower($this->getFilePath()) . ':' . $this->function->getLine() . ':' . (int) $this->function->getAttribute('startFilePos') . ':-:closure'; } /** * @param PhpParser\Node\Expr\Closure|PhpParser\Node\Expr\ArrowFunction $stmt */ public static function analyzeExpression(\Psalm\Internal\Analyzer\StatementsAnalyzer $statements_analyzer, PhpParser\Node\FunctionLike $stmt, Context $context) : bool { $closure_analyzer = new \Psalm\Internal\Analyzer\ClosureAnalyzer($stmt, $statements_analyzer); if ($stmt instanceof PhpParser\Node\Expr\Closure && self::analyzeClosureUses($statements_analyzer, $stmt, $context) === \false) { return \false; } $use_context = new Context($context->self); $codebase = $statements_analyzer->getCodebase(); if (!$statements_analyzer->isStatic() && !$closure_analyzer->isStatic()) { if ($context->collect_mutations && $context->self && $codebase->classExtends($context->self, (string) $statements_analyzer->getFQCLN())) { /** @psalm-suppress PossiblyUndefinedStringArrayOffset */ $use_context->vars_in_scope['$this'] = $context->vars_in_scope['$this']; } elseif ($context->self) { $this_atomic = new TNamedObject($context->self, \true); $use_context->vars_in_scope['$this'] = new Union([$this_atomic]); } } foreach ($context->vars_in_scope as $var => $type) { if (strpos($var, '$this->') === 0) { $use_context->vars_in_scope[$var] = $type; } } if ($context->self) { $self_class_storage = $codebase->classlike_storage_provider->get($context->self); \Psalm\Internal\Analyzer\ClassAnalyzer::addContextProperties($statements_analyzer, $self_class_storage, $use_context, $context->self, $statements_analyzer->getParentFQCLN()); } foreach ($context->vars_possibly_in_scope as $var => $_) { if (strpos($var, '$this->') === 0) { $use_context->vars_possibly_in_scope[$var] = \true; } } if ($stmt instanceof PhpParser\Node\Expr\Closure) { foreach ($stmt->uses as $use) { if (!is_string($use->var->name)) { continue; } $use_var_id = '$' . $use->var->name; if ($statements_analyzer->data_flow_graph instanceof VariableUseGraph && $context->hasVariable($use_var_id)) { $parent_nodes = $context->vars_in_scope[$use_var_id]->parent_nodes; foreach ($parent_nodes as $parent_node) { $statements_analyzer->data_flow_graph->addPath($parent_node, new DataFlowNode('closure-use', 'closure use', null), 'closure-use'); } } $use_context->vars_in_scope[$use_var_id] = $context->hasVariable($use_var_id) ? $context->vars_in_scope[$use_var_id] : Type::getMixed(); if ($use->byRef) { $use_context->vars_in_scope[$use_var_id] = $use_context->vars_in_scope[$use_var_id]->setProperties(['by_ref' => \true]); $use_context->references_to_external_scope[$use_var_id] = \true; } $use_context->vars_possibly_in_scope[$use_var_id] = \true; foreach ($context->vars_in_scope as $var_id => $type) { if (preg_match('/^\\$' . $use->var->name . '[\\[\\-]/', $var_id)) { $use_context->vars_in_scope[$var_id] = $type; $use_context->vars_possibly_in_scope[$var_id] = \true; } } } } else { $traverser = new PhpParser\NodeTraverser(); $short_closure_visitor = new ShortClosureVisitor(); $traverser->addVisitor($short_closure_visitor); $traverser->traverse($stmt->getStmts()); foreach ($short_closure_visitor->getUsedVariables() as $use_var_id => $_) { if ($context->hasVariable($use_var_id)) { $use_context->vars_in_scope[$use_var_id] = $context->vars_in_scope[$use_var_id]; if ($statements_analyzer->data_flow_graph instanceof VariableUseGraph) { $parent_nodes = $context->vars_in_scope[$use_var_id]->parent_nodes; foreach ($parent_nodes as $parent_node) { $statements_analyzer->data_flow_graph->addPath($parent_node, new DataFlowNode('closure-use', 'closure use', null), 'closure-use'); } } } $use_context->vars_possibly_in_scope[$use_var_id] = \true; } } $use_context->calling_method_id = $context->calling_method_id; $use_context->phantom_classes = $context->phantom_classes; $byref_vars = []; $closure_analyzer->analyze($use_context, $statements_analyzer->node_data, $context, \false, $byref_vars); foreach ($byref_vars as $key => $value) { $context->vars_in_scope[$key] = $value; } if ($closure_analyzer->inferred_impure && $statements_analyzer->getSource() instanceof \Psalm\Internal\Analyzer\FunctionLikeAnalyzer) { $statements_analyzer->getSource()->inferred_impure = \true; } if ($closure_analyzer->inferred_has_mutation && $statements_analyzer->getSource() instanceof \Psalm\Internal\Analyzer\FunctionLikeAnalyzer) { $statements_analyzer->getSource()->inferred_has_mutation = \true; } if (!$statements_analyzer->node_data->getType($stmt)) { $statements_analyzer->node_data->setType($stmt, Type::getClosure()); } return \true; } /** * @return false|null */ private static function analyzeClosureUses(\Psalm\Internal\Analyzer\StatementsAnalyzer $statements_analyzer, PhpParser\Node\Expr\Closure $stmt, Context $context) : ?bool { $param_names = []; foreach ($stmt->params as $i => $param) { if ($param->var instanceof PhpParser\Node\Expr\Variable && is_string($param->var->name)) { $param_names[$i] = $param->var->name; } else { $param_names[$i] = ''; } } foreach ($stmt->uses as $use) { if (!is_string($use->var->name)) { continue; } $use_var_id = '$' . $use->var->name; if (in_array($use->var->name, $param_names)) { if (IssueBuffer::accepts(new DuplicateParam('Closure use duplicates param name ' . $use_var_id, new CodeLocation($statements_analyzer->getSource(), $use->var)), $statements_analyzer->getSuppressedIssues())) { return \false; } } if (!$context->hasVariable($use_var_id)) { if ($use_var_id === '$argv' || $use_var_id === '$argc') { continue; } if (!isset($context->vars_possibly_in_scope[$use_var_id])) { if ($context->check_variables) { if (IssueBuffer::accepts(new UndefinedVariable('Cannot find referenced variable ' . $use_var_id, new CodeLocation($statements_analyzer->getSource(), $use->var)), $statements_analyzer->getSuppressedIssues())) { return \false; } return null; } } $first_appearance = $statements_analyzer->getFirstAppearance($use_var_id); if ($first_appearance) { if (IssueBuffer::accepts(new PossiblyUndefinedVariable('Possibly undefined variable ' . $use_var_id . ', first seen on line ' . $first_appearance->getLineNumber(), new CodeLocation($statements_analyzer->getSource(), $use->var)), $statements_analyzer->getSuppressedIssues())) { return \false; } continue; } if ($context->check_variables) { if (IssueBuffer::accepts(new UndefinedVariable('Cannot find referenced variable ' . $use_var_id, new CodeLocation($statements_analyzer->getSource(), $use->var)), $statements_analyzer->getSuppressedIssues())) { return \false; } continue; } } } return null; } } class instanceof PhpParser\Node\Stmt\Interface_) { throw new LogicException('Something went badly wrong'); } $project_analyzer = $this->file_analyzer->project_analyzer; $codebase = $project_analyzer->getCodebase(); $config = $project_analyzer->getConfig(); $fq_interface_name = $this->getFQCLN(); if (!$fq_interface_name) { throw new UnexpectedValueException('bad'); } $class_storage = $codebase->classlike_storage_provider->get($fq_interface_name); if ($this->class->extends) { foreach ($this->class->extends as $extended_interface) { $extended_interface_name = self::getFQCLNFromNameObject($extended_interface, $this->getAliases()); $parent_reference_location = new CodeLocation($this, $extended_interface); if (!$codebase->classOrInterfaceExists($extended_interface_name, $parent_reference_location)) { // we should not normally get here return; } try { $extended_interface_storage = $codebase->classlike_storage_provider->get($extended_interface_name); } catch (InvalidArgumentException $e) { continue; } $code_location = new CodeLocation($this, $extended_interface); if (!$extended_interface_storage->is_interface) { IssueBuffer::maybeAdd(new UndefinedInterface($extended_interface_name . ' is not an interface', $code_location, $extended_interface_name), $this->getSuppressedIssues()); } if ($codebase->store_node_types && $extended_interface_name) { $bounds = $parent_reference_location->getSelectionBounds(); $codebase->analyzer->addOffsetReference($this->getFilePath(), $bounds[0], $bounds[1], $extended_interface_name); } $this->checkTemplateParams($codebase, $class_storage, $extended_interface_storage, $code_location, $class_storage->template_type_extends_count[$extended_interface_name] ?? 0); } } $class_union = new Union([new TNamedObject($fq_interface_name)]); foreach ($class_storage->direct_interface_parents as $parent_interface) { $parent_storage = $codebase->classlikes->getStorageFor($parent_interface); if ($parent_storage && $parent_storage->inheritors) { if (!UnionTypeComparator::isContainedBy($codebase, $class_union, $parent_storage->inheritors)) { IssueBuffer::maybeAdd(new InheritorViolation('Interface ' . $fq_interface_name . ' is not an allowed inheritor of parent interface ' . $parent_interface, new CodeLocation($this, $this->class)), $this->getSuppressedIssues()); } } } $fq_interface_name = $this->getFQCLN(); if (!$fq_interface_name) { throw new UnexpectedValueException('bad'); } $class_storage = $codebase->classlike_storage_provider->get($fq_interface_name); $interface_context = new Context($this->getFQCLN()); \Psalm\Internal\Analyzer\AttributesAnalyzer::analyze($this, $interface_context, $class_storage, $this->class->attrGroups, \Psalm\Internal\Analyzer\AttributesAnalyzer::TARGET_CLASS, $class_storage->suppressed_issues + $this->getSuppressedIssues()); foreach ($class_storage->docblock_issues as $docblock_issue) { IssueBuffer::maybeAdd($docblock_issue); } $member_stmts = []; foreach ($this->class->stmts as $stmt) { if ($stmt instanceof PhpParser\Node\Stmt\ClassMethod) { $method_analyzer = new \Psalm\Internal\Analyzer\MethodAnalyzer($stmt, $this); $type_provider = new NodeDataProvider(); $method_analyzer->analyze($interface_context, $type_provider); $actual_method_id = $method_analyzer->getMethodId(); if ($stmt->name->name !== '__construct' && $stmt->name->name !== '__destruct' && $config->reportIssueInFile('InvalidReturnType', $this->getFilePath())) { \Psalm\Internal\Analyzer\ClassAnalyzer::analyzeClassMethodReturnType($stmt, $method_analyzer, $this, $type_provider, $codebase, $class_storage, $fq_interface_name, $actual_method_id, $actual_method_id, \false); } } elseif ($stmt instanceof PhpParser\Node\Stmt\Property) { IssueBuffer::maybeAdd(new ParseError('Interfaces cannot have properties', new CodeLocation($this, $stmt))); return; } elseif ($stmt instanceof PhpParser\Node\Stmt\ClassConst) { $member_stmts[] = $stmt; foreach ($stmt->consts as $const) { $const_id = strtolower($this->fq_class_name) . '::' . $const->name; foreach ($codebase->class_constants_to_rename as $original_const_id => $new_const_name) { if ($const_id === $original_const_id) { $file_manipulations = [new FileManipulation((int) $const->name->getAttribute('startFilePos'), (int) $const->name->getAttribute('endFilePos') + 1, $new_const_name)]; FileManipulationBuffer::add($this->getFilePath(), $file_manipulations); } } } } } $statements_analyzer = new \Psalm\Internal\Analyzer\StatementsAnalyzer($this, new NodeDataProvider()); $statements_analyzer->analyze($member_stmts, $interface_context, null, \true); ClassConstAnalyzer::analyze($this->storage, $this->getCodebase()); } } */ protected array $suppressed_issues; protected bool $is_static = \false; /** * @var ?array */ protected ?array $return_vars_in_scope = []; /** * @var ?array */ protected ?array $return_vars_possibly_in_scope = []; private ?Union $local_return_type = null; /** * @var array */ protected static array $no_effects_hashes = []; public bool $track_mutations = \false; public bool $inferred_impure = \false; public bool $inferred_has_mutation = \false; /** * Holds param nodes for functions with func_get_args calls * * @var array */ public array $param_nodes = []; protected FunctionLikeStorage $storage; /** * @param TFunction $function */ public function __construct($function, \Psalm\Internal\Analyzer\SourceAnalyzer $source, FunctionLikeStorage $storage) { $this->function = $function; $this->source = $source; $this->suppressed_issues = $source->getSuppressedIssues(); $this->codebase = $source->getCodebase(); $this->storage = $storage; } /** * @param bool $add_mutations whether or not to add mutations to this method * @param array $byref_vars * @param-out array $byref_vars * @return false|null * @psalm-suppress PossiblyUnusedReturnValue unused but seems important * @psalm-suppress ComplexMethod Unavoidably complex */ public function analyze(Context $context, NodeDataProvider $type_provider, ?Context $global_context = null, bool $add_mutations = \false, array &$byref_vars = []) : ?bool { $storage = $this->storage; $function_stmts = $this->function->getStmts() ?: []; if ($this->function instanceof ArrowFunction && isset($function_stmts[0]) && $function_stmts[0] instanceof PhpParser\Node\Stmt\Return_ && $function_stmts[0]->expr) { $function_stmts[0]->setAttributes($function_stmts[0]->expr->getAttributes()); } if ($global_context) { foreach ($global_context->constants as $const_name => $var_type) { if (!$context->hasVariable($const_name)) { $context->vars_in_scope[$const_name] = $var_type; } } } $codebase = $this->codebase; $project_analyzer = $this->getProjectAnalyzer(); if ($codebase->track_unused_suppressions && !isset($storage->suppressed_issues[0])) { if (count($storage->suppressed_issues) === 1 || !in_array("UnusedPsalmSuppress", $storage->suppressed_issues)) { foreach ($storage->suppressed_issues as $offset => $issue_name) { IssueBuffer::addUnusedSuppression($storage->location !== null ? $storage->location->file_path : $this->getFilePath(), $offset, $issue_name); } } } foreach ($storage->docblock_issues as $docblock_issue) { IssueBuffer::maybeAdd($docblock_issue); } $function_information = $this->getFunctionInformation($context, $codebase, $type_provider, $storage, $add_mutations); if ($function_information === null) { return null; } [$real_method_id, $method_id, $appearing_class_storage, $hash, $cased_method_id, $overridden_method_ids] = $function_information; $this->suppressed_issues = $this->getSource()->getSuppressedIssues() + $storage->suppressed_issues; if ($appearing_class_storage) { $this->suppressed_issues += $appearing_class_storage->suppressed_issues; } if (($storage instanceof MethodStorage || $storage instanceof FunctionStorage) && $storage->is_static) { $this->is_static = \true; } $statements_analyzer = new \Psalm\Internal\Analyzer\StatementsAnalyzer($this, $type_provider); $byref_uses = []; if ($this instanceof \Psalm\Internal\Analyzer\ClosureAnalyzer && $this->function instanceof Closure) { foreach ($this->function->uses as $use) { if (!is_string($use->var->name)) { continue; } $use_var_id = '$' . $use->var->name; $use_location = new CodeLocation($this, $use); $use_assignment = null; if ($statements_analyzer->data_flow_graph) { $use_assignment = DataFlowNode::getForAssignment($use_var_id, $use_location); $statements_analyzer->data_flow_graph->addNode($use_assignment); $context->vars_in_scope[$use_var_id] = $context->vars_in_scope[$use_var_id]->addParentNodes([$use_assignment->id => $use_assignment]); } if ($use->byRef) { $byref_uses[$use_var_id] = \true; if ($statements_analyzer->data_flow_graph && $use_assignment) { $statements_analyzer->data_flow_graph->addPath($use_assignment, new DataFlowNode('closure-use', 'closure use', null), 'closure-use'); } } else { $statements_analyzer->registerVariable($use_var_id, $use_location, null); } } $statements_analyzer->setByRefUses($byref_uses); } if ($storage->template_types) { foreach ($storage->template_types as $param_name => $_) { $fq_classlike_name = Type::getFQCLNFromString($param_name, $this->getAliases()); if ($codebase->classOrInterfaceExists($fq_classlike_name)) { IssueBuffer::maybeAdd(new ReservedWord('Cannot use ' . $param_name . ' as template name since the class already exists', new CodeLocation($this, $this->function), 'resource'), $this->getSuppressedIssues()); } } } $template_types = $storage->template_types; if ($appearing_class_storage && $appearing_class_storage->template_types) { $template_types = array_merge($template_types ?: [], $appearing_class_storage->template_types); } $params = $storage->params; if ($codebase->alter_code) { $this->alterParams($codebase, $storage, $params, $context); } foreach ($codebase->methods_to_rename as $original_method_id => $new_method_name) { if ($this instanceof \Psalm\Internal\Analyzer\MethodAnalyzer && strtolower((string) $this->getMethodId()) === $original_method_id) { $file_manipulations = [new FileManipulation((int) $this->function->name->getAttribute('startFilePos'), (int) $this->function->name->getAttribute('endFilePos') + 1, $new_method_name)]; FileManipulationBuffer::add($this->getFilePath(), $file_manipulations); } } if ($storage instanceof MethodStorage && $method_id instanceof MethodIdentifier && $overridden_method_ids) { $params = $codebase->methods->getMethodParams($method_id, $this); } $check_stmts = $this->processParams($statements_analyzer, $storage, $cased_method_id, $params, array_values($this->function->params), $context, (bool) $template_types); if ($byref_uses) { $ref_context = clone $context; $var = '$__tmp_byref_closure_if__' . (int) $this->function->getAttribute('startFilePos'); $ref_context->vars_in_scope[$var] = Type::getBool(); $var = new VirtualVariable(substr($var, 1)); $virtual_while = new VirtualWhile($var, $function_stmts); $statements_analyzer->analyze([$virtual_while], $ref_context); foreach ($byref_uses as $var_id => $_) { $byref_vars[$var_id] = $ref_context->vars_in_scope[$var_id]; $context->vars_in_scope[$var_id] = $ref_context->vars_in_scope[$var_id]; } } if ($storage->pure) { $context->pure = \true; } if ($storage->mutation_free && $cased_method_id && !strpos($cased_method_id, '__construct') && !($storage instanceof MethodStorage && $storage->mutation_free_inferred)) { $context->mutation_free = \true; } if ($storage instanceof MethodStorage && $storage->external_mutation_free && !$storage->mutation_free_inferred) { $context->external_mutation_free = \true; } foreach ($storage->unused_docblock_parameters as $param_name => $param_location) { if ($storage->has_undertyped_native_parameters) { IssueBuffer::maybeAdd(new InvalidDocblockParamName('Incorrect param name $' . $param_name . ' in docblock for ' . $cased_method_id, $param_location)); } elseif ($codebase->find_unused_code) { IssueBuffer::maybeAdd(new UnusedDocblockParam('Docblock parameter $' . $param_name . ' in docblock for ' . $cased_method_id . ' does not have a counterpart in signature parameter list', $param_location)); } } if ($storage->signature_return_type && $storage->signature_return_type_location) { [$start, $end] = $storage->signature_return_type_location->getSelectionBounds(); $codebase->analyzer->addOffsetReference($this->getFilePath(), $start, $end, (string) $storage->signature_return_type); } if ($storage instanceof MethodStorage && $storage->location && !$storage->allow_named_arg_calls) { foreach ($overridden_method_ids as $overridden_method_id) { $overridden_storage = $codebase->methods->getStorage($overridden_method_id); if ($overridden_storage->allow_named_arg_calls) { IssueBuffer::maybeAdd(new MethodSignatureMismatch('Method ' . (string) $method_id . ' should accept named arguments ' . ' as ' . (string) $overridden_method_id . ' does', $storage->location)); } } } if (ReturnTypeAnalyzer::checkReturnType($this->function, $project_analyzer, $this, $storage, $context) === \false) { $check_stmts = \false; } if (!$check_stmts) { return \false; } if ($context->collect_initializations || $context->collect_mutations) { $statements_analyzer->addSuppressedIssues(['DocblockTypeContradiction', 'InvalidReturnStatement', 'RedundantCondition', 'RedundantConditionGivenDocblockType', 'TypeDoesNotContainNull', 'TypeDoesNotContainType', 'LoopInvalidation']); if ($context->collect_initializations) { $statements_analyzer->addSuppressedIssues(['UndefinedInterfaceMethod', 'UndefinedMethod', 'PossiblyUndefinedMethod']); } } elseif ($cased_method_id && strpos($cased_method_id, '__destruct')) { $statements_analyzer->addSuppressedIssues(['InvalidPropertyAssignmentValue', 'PossiblyNullPropertyAssignmentValue']); } $time = microtime(\true); $project_analyzer = $statements_analyzer->getProjectAnalyzer(); if ($codebase->alter_code && (isset($project_analyzer->getIssuesToFix()['MissingPureAnnotation']) || isset($project_analyzer->getIssuesToFix()['MissingImmutableAnnotation']))) { $this->track_mutations = \true; } elseif ($this->function instanceof Closure || $this->function instanceof ArrowFunction) { $this->track_mutations = \true; } if ($this->function instanceof ArrowFunction && (!$storage->return_type || $storage->return_type->isNever())) { // ArrowFunction perform a return implicitly so if the return type is never, we have to suppress the error // note: the never can only come from phpdoc. PHP will refuse short closures with never in signature $statements_analyzer->addSuppressedIssues(['NoValue']); } $statements_analyzer->analyze($function_stmts, $context, $global_context, \true); if ($codebase->alter_code && isset($project_analyzer->getIssuesToFix()['MissingPureAnnotation']) && !$this->inferred_impure && ($this->function instanceof Function_ || $this->function instanceof ClassMethod) && $storage->params && !$overridden_method_ids) { $manipulator = FunctionDocblockManipulator::getForFunction($project_analyzer, $this->source->getFilePath(), $this->function); $yield_types = []; $inferred_return_types = ReturnTypeCollector::getReturnTypes($codebase, $type_provider, $function_stmts, $yield_types, \true); $inferred_return_type = $inferred_return_types ? Type::combineUnionTypeArray($inferred_return_types, $codebase) : Type::getVoid(); if (!$inferred_return_type->isVoid() && !$inferred_return_type->isFalse() && !$inferred_return_type->isNull() && !$inferred_return_type->isSingleIntLiteral() && !$inferred_return_type->isSingleStringLiteral() && !$inferred_return_type->isTrue() && !$inferred_return_type->isEmptyArray()) { $manipulator->makePure(); } } if ($this->inferred_has_mutation && $context->self) { $this->codebase->analyzer->addMutableClass($context->self); } if (!$context->collect_initializations && !$context->collect_mutations && $project_analyzer->debug_performance && $cased_method_id) { $traverser = new PhpParser\NodeTraverser(); $node_counter = new NodeCounterVisitor(); $traverser->addVisitor($node_counter); $traverser->traverse($function_stmts); if ($node_counter->count > 5) { $time_taken = microtime(\true) - $time; $codebase->analyzer->addFunctionTiming($cased_method_id, $time_taken / $node_counter->count); } } $final_actions = \Psalm\Internal\Analyzer\ScopeAnalyzer::getControlActions($this->function->getStmts() ?: [], null, []); if ($final_actions !== [\Psalm\Internal\Analyzer\ScopeAnalyzer::ACTION_END]) { $this->examineParamTypes($statements_analyzer, $context, $codebase); } foreach ($params as $function_param) { // only complain if there's no type defined by a parent type if (!$function_param->type && $function_param->location) { if ($this->function instanceof Closure || $this->function instanceof ArrowFunction) { IssueBuffer::maybeAdd(new MissingClosureParamType('Parameter $' . $function_param->name . ' has no provided type', $function_param->location), $storage->suppressed_issues + $this->getSuppressedIssues()); } else { IssueBuffer::maybeAdd(new MissingParamType('Parameter $' . $function_param->name . ' has no provided type', $function_param->location), $storage->suppressed_issues + $this->getSuppressedIssues()); } } } if ($this->function instanceof Closure || $this->function instanceof ArrowFunction) { $this->verifyReturnType($function_stmts, $statements_analyzer, $storage->return_type, $this->source->getFQCLN(), $storage->return_type_location, $context->has_returned, $global_context && ($global_context->inside_call || $global_context->inside_return)); $closure_yield_types = []; $closure_return_types = ReturnTypeCollector::getReturnTypes($codebase, $type_provider, $function_stmts, $closure_yield_types, \true); $closure_return_type = $closure_return_types ? Type::combineUnionTypeArray($closure_return_types, $codebase) : Type::getVoid(); $closure_yield_type = $closure_yield_types ? Type::combineUnionTypeArray($closure_yield_types, $codebase) : null; if ($closure_yield_type) { $closure_return_type = $closure_yield_type; } if ($function_type = $statements_analyzer->node_data->getType($this->function)) { /** * @var TClosure */ $closure_atomic = $function_type->getSingleAtomic(); $new_closure_return_type = $closure_atomic->return_type; if ($storage->return_type === $storage->signature_return_type && (!$storage->return_type || $storage->return_type->hasMixed() || UnionTypeComparator::isContainedBy($codebase, $closure_return_type, $storage->return_type))) { $new_closure_return_type = $closure_return_type; } $new_closure_is_pure = !$this->inferred_impure; $statements_analyzer->node_data->setType($this->function, new Union([new TClosure($closure_atomic->value, $closure_atomic->params, $new_closure_return_type, $new_closure_is_pure, $closure_atomic->byref_uses, $closure_atomic->extra_types, $closure_atomic->from_docblock)])); } } if ($codebase->collect_references && !$context->collect_initializations && !$context->collect_mutations && $codebase->find_unused_variables && $context->check_variables) { $this->checkParamReferences($statements_analyzer, $storage, $appearing_class_storage, $context); } foreach ($storage->throws as $expected_exception => $_) { if (($expected_exception === 'self' || $expected_exception === 'static') && $context->self) { $expected_exception = $context->self; } if (isset($storage->throw_locations[$expected_exception])) { if (\Psalm\Internal\Analyzer\ClassLikeAnalyzer::checkFullyQualifiedClassLikeName($statements_analyzer, $expected_exception, $storage->throw_locations[$expected_exception], $context->self, $context->calling_method_id, $statements_analyzer->getSuppressedIssues(), new \Psalm\Internal\Analyzer\ClassLikeNameOptions(\false, \false, \true, \true, \true))) { $input_type = new Union([new TNamedObject($expected_exception)]); $container_type = new Union([new TNamedObject('Exception'), new TNamedObject('Throwable')]); if (!UnionTypeComparator::isContainedBy($codebase, $input_type, $container_type)) { IssueBuffer::maybeAdd(new InvalidThrow('Class supplied for @throws ' . $expected_exception . ' does not implement Throwable', $storage->throw_locations[$expected_exception], $expected_exception), $statements_analyzer->getSuppressedIssues()); } if ($codebase->alter_code) { $codebase->classlikes->handleDocblockTypeInMigration($codebase, $this, $input_type, $storage->throw_locations[$expected_exception], $context->calling_method_id); } } } } $missingThrowsDocblockErrors = []; foreach ($statements_analyzer->getUncaughtThrows($context) as $possibly_thrown_exception => $codelocations) { $is_expected = \false; foreach ($storage->throws as $expected_exception => $_) { if ($expected_exception === $possibly_thrown_exception || $codebase->classOrInterfaceExists($possibly_thrown_exception) && ($codebase->interfaceExtends($possibly_thrown_exception, $expected_exception) || $codebase->classExtendsOrImplements($possibly_thrown_exception, $expected_exception))) { $is_expected = \true; break; } } if (!$is_expected) { $missing_docblock_exception = new TNamedObject($possibly_thrown_exception); $missingThrowsDocblockErrors[] = $missing_docblock_exception->toNamespacedString($this->source->getNamespace(), $this->source->getAliasedClassesFlipped(), $this->source->getFQCLN(), \true); foreach ($codelocations as $codelocation) { // issues are suppressed in ThrowAnalyzer, CallAnalyzer, etc. IssueBuffer::maybeAdd(new MissingThrowsDocblock($possibly_thrown_exception . ' is thrown but not caught - please either catch' . ' or add a @throws annotation', $codelocation, $possibly_thrown_exception)); } } } if ($codebase->alter_code && isset($project_analyzer->getIssuesToFix()['MissingThrowsDocblock'])) { $manipulator = FunctionDocblockManipulator::getForFunction($project_analyzer, $this->source->getFilePath(), $this->function); $manipulator->addThrowsDocblock($missingThrowsDocblockErrors); } if ($codebase->taint_flow_graph && $this->function instanceof ClassMethod && $cased_method_id && $storage->specialize_call && isset($context->vars_in_scope['$this']) && $context->vars_in_scope['$this']->parent_nodes) { $method_source = DataFlowNode::getForMethodReturn((string) $method_id, $cased_method_id, $storage->location); $codebase->taint_flow_graph->addNode($method_source); foreach ($context->vars_in_scope['$this']->parent_nodes as $parent_node) { $codebase->taint_flow_graph->addPath($parent_node, $method_source, '$this'); } } if ($add_mutations) { if ($this->return_vars_in_scope !== null) { $context->vars_in_scope = \Psalm\Internal\Analyzer\TypeAnalyzer::combineKeyedTypes($context->vars_in_scope, $this->return_vars_in_scope); } if ($this->return_vars_possibly_in_scope !== null) { $context->vars_possibly_in_scope = array_merge($context->vars_possibly_in_scope, $this->return_vars_possibly_in_scope); } foreach ($context->vars_in_scope as $var => $_) { if (strpos($var, '$this->') !== 0 && $var !== '$this') { $context->removePossibleReference($var); } } foreach ($context->vars_possibly_in_scope as $var => $_) { if (strpos($var, '$this->') !== 0 && $var !== '$this') { unset($context->vars_possibly_in_scope[$var]); } } if ($hash && $real_method_id && $this instanceof \Psalm\Internal\Analyzer\MethodAnalyzer && !$context->collect_initializations) { $new_hash = md5($real_method_id . '::' . $context->getScopeSummary()); if ($new_hash === $hash) { self::$no_effects_hashes[$hash] = \true; } } } $event = new AfterFunctionLikeAnalysisEvent($this->function, $storage, $this, $codebase, [], $type_provider, $context); if ($codebase->config->eventDispatcher->dispatchAfterFunctionLikeAnalysis($event) === \false) { return \false; } $file_manipulations = $event->getFileReplacements(); if ($file_manipulations) { FileManipulationBuffer::add($this->getFilePath(), $file_manipulations); } \Psalm\Internal\Analyzer\AttributesAnalyzer::analyze($this, $context, $storage, $this->function->attrGroups, $storage instanceof MethodStorage ? \Psalm\Internal\Analyzer\AttributesAnalyzer::TARGET_METHOD : \Psalm\Internal\Analyzer\AttributesAnalyzer::TARGET_FUNCTION, $storage->suppressed_issues + $this->getSuppressedIssues()); return null; } private function checkParamReferences(\Psalm\Internal\Analyzer\StatementsAnalyzer $statements_analyzer, FunctionLikeStorage $storage, ?ClassLikeStorage $class_storage, Context $context) : void { $codebase = $statements_analyzer->getCodebase(); $unused_params = $this->detectUnusedParameters($statements_analyzer, $storage, $context); if (!$storage instanceof MethodStorage || !$storage->cased_name || $storage->visibility === \Psalm\Internal\Analyzer\ClassLikeAnalyzer::VISIBILITY_PRIVATE) { $last_unused_argument_position = $this->detectPreviousUnusedArgumentPosition($storage, count($storage->params) - 1); // Sort parameters in reverse order so that we can start from the end of parameters krsort($unused_params, SORT_NUMERIC); foreach ($unused_params as $unused_param_position => $unused_param_code_location) { $unused_param_var_name = $storage->params[$unused_param_position]->name; $unused_param_message = 'Param ' . $unused_param_var_name . ' is never referenced in this method'; // Remove the key as we already report the issue unset($unused_params[$unused_param_position]); // Do not report unused required parameters if ($unused_param_position !== $last_unused_argument_position) { break; } $last_unused_argument_position = $this->detectPreviousUnusedArgumentPosition($storage, $unused_param_position - 1); if ($this instanceof \Psalm\Internal\Analyzer\ClosureAnalyzer) { IssueBuffer::maybeAdd(new UnusedClosureParam($unused_param_message, $unused_param_code_location), $this->getSuppressedIssues()); continue; } IssueBuffer::maybeAdd(new UnusedParam($unused_param_message, $unused_param_code_location), $this->getSuppressedIssues()); } } if ($storage instanceof MethodStorage && $this instanceof \Psalm\Internal\Analyzer\MethodAnalyzer && $class_storage && $storage->cased_name && $storage->visibility !== \Psalm\Internal\Analyzer\ClassLikeAnalyzer::VISIBILITY_PRIVATE) { $method_id_lc = strtolower((string) $this->getMethodId()); foreach ($storage->params as $i => $_) { if (!isset($unused_params[$i])) { $codebase->file_reference_provider->addMethodParamUse($method_id_lc, $i, $method_id_lc); $method_name_lc = strtolower($storage->cased_name); if (!isset($class_storage->overridden_method_ids[$method_name_lc])) { continue; } foreach ($class_storage->overridden_method_ids[$method_name_lc] as $parent_method_id) { $codebase->file_reference_provider->addMethodParamUse(strtolower((string) $parent_method_id), $i, $method_id_lc); } } } } } /** * @param list $params * @param list $param_stmts */ private function processParams(\Psalm\Internal\Analyzer\StatementsAnalyzer $statements_analyzer, FunctionLikeStorage $storage, ?string $cased_method_id, array $params, array $param_stmts, Context $context, bool $has_template_types) : bool { $check_stmts = \true; $codebase = $statements_analyzer->getCodebase(); $project_analyzer = $statements_analyzer->getProjectAnalyzer(); foreach ($params as $offset => $function_param) { $function_param_id = '$' . $function_param->name; $signature_type = $function_param->signature_type; $signature_type_location = $function_param->signature_type_location; if ($signature_type && $signature_type_location && $signature_type->hasObjectType()) { $referenced_type = $signature_type; if ($referenced_type->isNullable()) { $referenced_type = $referenced_type->getBuilder(); $referenced_type->removeType('null'); $referenced_type = $referenced_type->freeze(); } [$start, $end] = $signature_type_location->getSelectionBounds(); $codebase->analyzer->addOffsetReference($this->getFilePath(), $start, $end, (string) $referenced_type); } if ($signature_type) { $signature_type = TypeExpander::expandUnion($codebase, $signature_type, $context->self, $context->self, $this->getParentFQCLN()); } $parent_nodes = []; if ($statements_analyzer->data_flow_graph && $function_param->location) { //don't add to taint flow graph if the type can't transmit taints if (!$statements_analyzer->data_flow_graph instanceof TaintFlowGraph || $function_param->type === null || !$function_param->type->isSingle() || !$function_param->type->isInt() && !$function_param->type->isFloat() && !$function_param->type->isBool()) { $param_assignment = DataFlowNode::getForAssignment($function_param_id, $function_param->location); $statements_analyzer->data_flow_graph->addNode($param_assignment); if ($cased_method_id) { $type_source = DataFlowNode::getForMethodArgument($cased_method_id, $cased_method_id, $offset, $function_param->location, null); $statements_analyzer->data_flow_graph->addPath($type_source, $param_assignment, 'param'); } if ($storage->variadic) { $this->param_nodes += [$param_assignment->id => $param_assignment]; } $parent_nodes = [$param_assignment->id => $param_assignment]; } } if ($function_param->type) { $param_type = $function_param->type; try { $param_type = TypeExpander::expandUnion($codebase, $param_type, $context->self, $context->self, $this->getParentFQCLN(), \true, \false, \false, \true, \false, \true); } catch (UnresolvableConstantException $e) { if ($function_param->type_location !== null) { IssueBuffer::maybeAdd(new UnresolvableConstant("Could not resolve constant {$e->class_name}::{$e->const_name}", $function_param->type_location), $storage->suppressed_issues, \true); } } if ($function_param->type_location) { if ($param_type->check($this, $function_param->type_location, $storage->suppressed_issues, [], \false, \false, $this->function instanceof ClassMethod && strtolower($this->function->name->name) !== '__construct', $context->calling_method_id) === \false) { $check_stmts = \false; } } $param_type = $param_type->addParentNodes($parent_nodes); } else { $param_type = new Union([new TMixed()], ['by_ref' => $function_param->by_ref, 'parent_nodes' => $parent_nodes]); } $var_type = $param_type; if ($function_param->is_variadic) { if ($storage->allow_named_arg_calls) { $var_type = new Union([new TArray([Type::getArrayKey(), $param_type])], ['by_ref' => $function_param->by_ref, 'parent_nodes' => $parent_nodes]); } else { $var_type = new Union([Type::getListAtomic($param_type)], ['by_ref' => $function_param->by_ref, 'parent_nodes' => $parent_nodes]); } } $context->vars_in_scope[$function_param_id] = $var_type; $context->vars_possibly_in_scope[$function_param_id] = \true; if ($function_param->by_ref) { $context->vars_in_scope[$function_param_id] = $context->vars_in_scope[$function_param_id]->setProperties(['by_ref' => \true]); $context->references_to_external_scope[$function_param_id] = \true; } $parser_param = $this->function->getParams()[$offset] ?? null; if ($function_param->location) { $statements_analyzer->registerVariable($function_param_id, $function_param->location, null); } if (!$function_param->type_location || !$function_param->location) { if ($parser_param && $parser_param->default) { ExpressionAnalyzer::analyze($statements_analyzer, $parser_param->default, $context); } continue; } if ($signature_type) { $union_comparison_result = new TypeComparisonResult(); if (!UnionTypeComparator::isContainedBy($codebase, $param_type, $signature_type, \false, \false, $union_comparison_result) && !$union_comparison_result->type_coerced_from_mixed) { if ($codebase->alter_code && isset($project_analyzer->getIssuesToFix()['MismatchingDocblockParamType'])) { $this->addOrUpdateParamType($project_analyzer, $function_param->name, $signature_type, \true); continue; } IssueBuffer::maybeAdd(new MismatchingDocblockParamType('Parameter ' . $function_param_id . ' has wrong type \'' . $param_type . '\', should be \'' . $signature_type . '\'', $function_param->type_location), $storage->suppressed_issues, \true); if ($signature_type->check($this, $function_param->type_location, $storage->suppressed_issues, [], \false) === \false) { $check_stmts = \false; } continue; } } if ($parser_param && $parser_param->default) { ExpressionAnalyzer::analyze($statements_analyzer, $parser_param->default, $context); $default_type = $statements_analyzer->node_data->getType($parser_param->default); if ($default_type && !$default_type->hasMixed() && !UnionTypeComparator::isContainedBy($codebase, $default_type, $param_type, \false, \false, null, \true)) { IssueBuffer::maybeAdd(new InvalidParamDefault('Default value type ' . $default_type->getId() . ' for argument ' . ($offset + 1) . ' of method ' . $cased_method_id . ' does not match the given type ' . $param_type->getId(), $function_param->type_location)); } if ($default_type && !$default_type->isNull() && $param_type->isSingleAndMaybeNullable() && $param_type->getCallableTypes()) { IssueBuffer::maybeAdd(new InvalidParamDefault('Default value type for ' . $param_type->getId() . ' argument ' . ($offset + 1) . ' of method ' . $cased_method_id . ' can only be null, ' . $default_type->getId() . ' specified', $function_param->type_location)); } } if ($has_template_types) { if ($param_type->check($this->source, $function_param->type_location, $this->suppressed_issues, [], \false) === \false) { $check_stmts = \false; } } else { if ($param_type->isVoid()) { IssueBuffer::maybeAdd(new ReservedWord('Parameter cannot be void', $function_param->type_location, 'void'), $this->suppressed_issues); } if ($param_type->isNever()) { IssueBuffer::maybeAdd(new ReservedWord('Parameter cannot be never', $function_param->type_location, 'never'), $this->suppressed_issues); } if ($param_type->check($this->source, $function_param->type_location, $this->suppressed_issues, [], \false) === \false) { $check_stmts = \false; } } if ($codebase->collect_locations) { if ($function_param->type_location !== $function_param->signature_type_location && $function_param->signature_type_location && $function_param->signature_type) { if ($function_param->signature_type->check($this->source, $function_param->signature_type_location, $this->suppressed_issues, [], \false) === \false) { $check_stmts = \false; } } } if ($function_param->by_ref) { // register by ref params as having been used, to avoid false positives // @todo change the assignment analysis *just* for byref params // so that we don't have to do this $context->hasVariable('$' . $function_param->name); } if (count($param_stmts) === count($params)) { \Psalm\Internal\Analyzer\AttributesAnalyzer::analyze($this, $context, $function_param, $param_stmts[$offset]->attrGroups, \Psalm\Internal\Analyzer\AttributesAnalyzer::TARGET_PARAMETER | ($function_param->promoted_property ? \Psalm\Internal\Analyzer\AttributesAnalyzer::TARGET_PROPERTY : 0), $storage->suppressed_issues + $this->getSuppressedIssues()); } } return $check_stmts; } /** * @param FunctionLikeParameter[] $params */ private function alterParams(Codebase $codebase, FunctionLikeStorage $storage, array $params, Context $context) : void { foreach ($this->function->params as $param) { $param_name_node = null; if ($param->type instanceof PhpParser\Node\Name) { $param_name_node = $param->type; } elseif ($param->type instanceof PhpParser\Node\NullableType && $param->type->type instanceof PhpParser\Node\Name) { $param_name_node = $param->type->type; } if ($param_name_node) { $resolved_name = \Psalm\Internal\Analyzer\ClassLikeAnalyzer::getFQCLNFromNameObject($param_name_node, $this->getAliases()); $parent_fqcln = $this->getParentFQCLN(); if ($resolved_name === 'self' && $context->self) { $resolved_name = $context->self; } elseif ($resolved_name === 'parent' && $parent_fqcln) { $resolved_name = $parent_fqcln; } $codebase->classlikes->handleClassLikeReferenceInMigration($codebase, $this, $param_name_node, $resolved_name, $context->calling_method_id, \false, \true); } } if ($this->function->returnType) { $return_name_node = null; if ($this->function->returnType instanceof PhpParser\Node\Name) { $return_name_node = $this->function->returnType; } elseif ($this->function->returnType instanceof PhpParser\Node\NullableType && $this->function->returnType->type instanceof PhpParser\Node\Name) { $return_name_node = $this->function->returnType->type; } if ($return_name_node) { $resolved_name = \Psalm\Internal\Analyzer\ClassLikeAnalyzer::getFQCLNFromNameObject($return_name_node, $this->getAliases()); $parent_fqcln = $this->getParentFQCLN(); if ($resolved_name === 'self' && $context->self) { $resolved_name = $context->self; } elseif ($resolved_name === 'parent' && $parent_fqcln) { $resolved_name = $parent_fqcln; } $codebase->classlikes->handleClassLikeReferenceInMigration($codebase, $this, $return_name_node, $resolved_name, $context->calling_method_id, \false, \true); } } if ($storage->return_type && $storage->return_type_location && $storage->return_type_location !== $storage->signature_return_type_location) { $replace_type = TypeExpander::expandUnion($codebase, $storage->return_type, $context->self, 'static', $this->getParentFQCLN(), \false); $codebase->classlikes->handleDocblockTypeInMigration($codebase, $this, $replace_type, $storage->return_type_location, $context->calling_method_id); } foreach ($params as $function_param) { if ($function_param->type && $function_param->type_location && $function_param->type_location !== $function_param->signature_type_location && $function_param->type_location->file_path === $this->getFilePath()) { $replace_type = TypeExpander::expandUnion($codebase, $function_param->type, $context->self, 'static', $this->getParentFQCLN(), \false); $codebase->classlikes->handleDocblockTypeInMigration($codebase, $this, $replace_type, $function_param->type_location, $context->calling_method_id); } } } /** * @param array $function_stmts */ public function verifyReturnType(array $function_stmts, \Psalm\Internal\Analyzer\StatementsAnalyzer $statements_analyzer, ?Union $return_type = null, ?string $fq_class_name = null, ?CodeLocation $return_type_location = null, bool $did_explicitly_return = \false, bool $closure_inside_call = \false) : void { ReturnTypeAnalyzer::verifyReturnType($this->function, $function_stmts, $statements_analyzer, $statements_analyzer->node_data, $this, $return_type, $fq_class_name, $fq_class_name, $return_type_location, [], $did_explicitly_return, $closure_inside_call); } public function addOrUpdateParamType(\Psalm\Internal\Analyzer\ProjectAnalyzer $project_analyzer, string $param_name, Union $inferred_return_type, bool $docblock_only = \false) : void { $manipulator = FunctionDocblockManipulator::getForFunction($project_analyzer, $this->source->getFilePath(), $this->function); $codebase = $project_analyzer->getCodebase(); $is_final = \true; $fqcln = $this->source->getFQCLN(); if ($fqcln !== null && $this instanceof \Psalm\Internal\Analyzer\MethodAnalyzer) { $class_storage = $codebase->classlike_storage_provider->get($fqcln); $is_final = $this->function->isFinal() || $class_storage->final; } $allow_native_type = !$docblock_only && $codebase->analysis_php_version_id >= 70000 && ($codebase->allow_backwards_incompatible_changes || $is_final || !$this instanceof \Psalm\Internal\Analyzer\MethodAnalyzer); $manipulator->setParamType($param_name, $allow_native_type ? $inferred_return_type->toPhpString($this->source->getNamespace(), $this->source->getAliasedClassesFlipped(), $this->source->getFQCLN(), $project_analyzer->getCodebase()->analysis_php_version_id) : null, $inferred_return_type->toNamespacedString($this->source->getNamespace(), $this->source->getAliasedClassesFlipped(), $this->source->getFQCLN(), \false), $inferred_return_type->toNamespacedString($this->source->getNamespace(), $this->source->getAliasedClassesFlipped(), $this->source->getFQCLN(), \true)); } /** * Adds return types for the given function */ public function addReturnTypes(Context $context) : void { if ($this->return_vars_in_scope !== null) { $this->return_vars_in_scope = \Psalm\Internal\Analyzer\TypeAnalyzer::combineKeyedTypes($context->vars_in_scope, $this->return_vars_in_scope); } else { $this->return_vars_in_scope = $context->vars_in_scope; } if ($this->return_vars_possibly_in_scope !== null) { $this->return_vars_possibly_in_scope = array_merge($context->vars_possibly_in_scope, $this->return_vars_possibly_in_scope); } else { $this->return_vars_possibly_in_scope = $context->vars_possibly_in_scope; } } public function examineParamTypes(\Psalm\Internal\Analyzer\StatementsAnalyzer $statements_analyzer, Context $context, Codebase $codebase, ?PhpParser\Node $stmt = null) : void { $storage = $this->getFunctionLikeStorage($statements_analyzer); foreach ($storage->params as $param) { if ($param->by_ref && isset($context->vars_in_scope['$' . $param->name]) && !$param->is_variadic) { $actual_type = $context->vars_in_scope['$' . $param->name]; $param_out_type = $param->out_type ?: $param->type; if ($param_out_type && !$actual_type->hasMixed() && $param->location) { if (!UnionTypeComparator::isContainedBy($codebase, $actual_type, $param_out_type, $actual_type->ignore_nullable_issues, $actual_type->ignore_falsable_issues)) { IssueBuffer::maybeAdd(new ReferenceConstraintViolation('Variable ' . '$' . $param->name . ' is limited to values of type ' . $param_out_type->getId() . ' because it is passed by reference, ' . $actual_type->getId() . ' type found. Use @param-out to specify ' . 'a different output type', $stmt ? new CodeLocation($this, $stmt) : $param->location), $statements_analyzer->getSuppressedIssues()); } } } } } public function getMethodName() : ?string { if ($this->function instanceof ClassMethod) { return (string) $this->function->name; } return null; } public function getCorrectlyCasedMethodId(?string $context_self = null) : string { if ($this->function instanceof ClassMethod) { $function_name = (string) $this->function->name; return ($context_self ?: $this->source->getFQCLN()) . '::' . $function_name; } if ($this->function instanceof Function_) { $namespace = $this->source->getNamespace(); return ($namespace ? $namespace . '\\' : '') . $this->function->name; } if (!$this instanceof \Psalm\Internal\Analyzer\ClosureAnalyzer) { throw new UnexpectedValueException('This is weird'); } return $this->getClosureId(); } public function getFunctionLikeStorage(?\Psalm\Internal\Analyzer\StatementsAnalyzer $statements_analyzer = null) : FunctionLikeStorage { $codebase = $this->codebase; if ($this->function instanceof ClassMethod && $this instanceof \Psalm\Internal\Analyzer\MethodAnalyzer) { $method_id = $this->getMethodId(); $codebase_methods = $codebase->methods; try { return $codebase_methods->getStorage($method_id); } catch (UnexpectedValueException $e) { $declaring_method_id = $codebase_methods->getDeclaringMethodId($method_id); if ($declaring_method_id === null) { throw new UnexpectedValueException('Cannot get storage for function that doesn‘t exist'); } // happens for fake constructors return $codebase_methods->getStorage($declaring_method_id); } } if ($this instanceof \Psalm\Internal\Analyzer\FunctionAnalyzer) { $function_id = $this->getFunctionId(); } elseif ($this instanceof \Psalm\Internal\Analyzer\ClosureAnalyzer) { $function_id = $this->getClosureId(); } else { throw new UnexpectedValueException('This is weird'); } return $codebase->functions->getStorage($statements_analyzer, $function_id); } /** @return non-empty-string */ public function getId() : string { if ($this instanceof \Psalm\Internal\Analyzer\MethodAnalyzer) { return (string) $this->getMethodId(); } if ($this instanceof \Psalm\Internal\Analyzer\FunctionAnalyzer) { return $this->getFunctionId(); } if ($this instanceof \Psalm\Internal\Analyzer\ClosureAnalyzer) { return $this->getClosureId(); } throw new UnexpectedValueException('This is weird'); } /** * @psalm-mutation-free * @return array */ public function getAliasedClassesFlipped() : array { if ($this->source instanceof \Psalm\Internal\Analyzer\NamespaceAnalyzer || $this->source instanceof \Psalm\Internal\Analyzer\FileAnalyzer || $this->source instanceof \Psalm\Internal\Analyzer\ClassLikeAnalyzer) { return $this->source->getAliasedClassesFlipped(); } return []; } /** * @psalm-mutation-free * @return array */ public function getAliasedClassesFlippedReplaceable() : array { if ($this->source instanceof \Psalm\Internal\Analyzer\NamespaceAnalyzer || $this->source instanceof \Psalm\Internal\Analyzer\FileAnalyzer || $this->source instanceof \Psalm\Internal\Analyzer\ClassLikeAnalyzer) { return $this->source->getAliasedClassesFlippedReplaceable(); } return []; } /** * @psalm-mutation-free * @return array>|null */ public function getTemplateTypeMap() : ?array { if ($this->source instanceof \Psalm\Internal\Analyzer\ClassLikeAnalyzer) { return ($this->source->getTemplateTypeMap() ?: []) + ($this->storage->template_types ?: []); } return $this->storage->template_types; } public function isStatic() : bool { return $this->is_static; } public function getCodebase() : Codebase { return $this->codebase; } /** * Get a list of suppressed issues * * @return array */ public function getSuppressedIssues() : array { return $this->suppressed_issues; } /** * @param array $new_issues */ public function addSuppressedIssues(array $new_issues) : void { if (isset($new_issues[0])) { $new_issues = array_combine($new_issues, $new_issues); } $this->suppressed_issues = $new_issues + $this->suppressed_issues; } /** * @param array $new_issues */ public function removeSuppressedIssues(array $new_issues) : void { if (isset($new_issues[0])) { $new_issues = array_combine($new_issues, $new_issues); } $this->suppressed_issues = array_diff_key($this->suppressed_issues, $new_issues); } /** * Adds a suppressed issue, useful when creating a method checker from scratch */ public function addSuppressedIssue(string $issue_name) : void { $this->suppressed_issues[] = $issue_name; } public static function clearCache() : void { self::$no_effects_hashes = []; } public function getLocalReturnType(Union $storage_return_type, bool $final = \false) : Union { if ($this->local_return_type) { return $this->local_return_type; } $this->local_return_type = TypeExpander::expandUnion($this->codebase, $storage_return_type, $this->getFQCLN(), $this->getFQCLN(), $this->getParentFQCLN(), \true, \true, $final); return $this->local_return_type; } /** * @return array{ * MethodIdentifier|null, * MethodIdentifier|null, * ClassLikeStorage|null, * ?string, * ?string, * array * }|null */ private function getFunctionInformation(Context $context, Codebase $codebase, NodeDataProvider $type_provider, FunctionLikeStorage $storage, bool $add_mutations) : ?array { $classlike_storage_provider = $codebase->classlike_storage_provider; $real_method_id = null; $method_id = null; $cased_method_id = null; $hash = null; $appearing_class_storage = null; $overridden_method_ids = []; if ($this instanceof \Psalm\Internal\Analyzer\MethodAnalyzer) { if (!$storage instanceof MethodStorage) { throw new UnexpectedValueException('$storage must be MethodStorage'); } $real_method_id = $this->getMethodId(); $method_id = $this->getMethodId($context->self); $fq_class_name = (string) $context->self; $appearing_class_storage = $classlike_storage_provider->get($fq_class_name); if ($add_mutations) { if (!$context->collect_initializations) { $hash = md5($real_method_id . '::' . $context->getScopeSummary()); // if we know that the function has no effects on vars, we don't bother rechecking if (isset(self::$no_effects_hashes[$hash])) { return null; } } } elseif ($context->self) { if ($appearing_class_storage->template_types) { $template_params = []; foreach ($appearing_class_storage->template_types as $param_name => $template_map) { $key = array_keys($template_map)[0]; $template_params[] = new Union([new TTemplateParam($param_name, reset($template_map), $key)]); } $this_object_type = new TGenericObject($context->self, $template_params, \false, !$storage->final); } else { $this_object_type = new TNamedObject($context->self, !$storage->final); } $props = []; if ($storage->external_mutation_free && !$storage->mutation_free_inferred) { $props = ['reference_free' => \true]; if ($this->function->name->name !== '__construct') { $props['allow_mutations'] = \false; } } if ($codebase->taint_flow_graph && $storage->specialize_call && $storage->location) { $new_parent_node = DataFlowNode::getForAssignment('$this in ' . $method_id, $storage->location); $codebase->taint_flow_graph->addNode($new_parent_node); $props['parent_nodes'] = [$new_parent_node->id => $new_parent_node]; } if ($this->storage instanceof MethodStorage && $this->storage->if_this_is_type) { $template_result = new TemplateResult($this->getTemplateTypeMap() ?? [], []); TemplateStandinTypeReplacer::fillTemplateResult(new Union([$this_object_type]), $template_result, $codebase, null, $this->storage->if_this_is_type); foreach ($context->vars_in_scope as $var_name => &$var_type) { if (0 === mb_strpos($var_name, '$this->')) { $var_type = TemplateInferredTypeReplacer::replace($var_type, $template_result, $codebase); } } $context->vars_in_scope['$this'] = $this->storage->if_this_is_type->setProperties($props); } else { $context->vars_in_scope['$this'] = new Union([$this_object_type], $props); } $context->vars_possibly_in_scope['$this'] = \true; } if ($appearing_class_storage->has_visitor_issues) { return null; } $cased_method_id = $fq_class_name . '::' . $storage->cased_name; $overridden_method_ids = $codebase->methods->getOverriddenMethodIds($method_id); $codeLocation = new CodeLocation($this, $this->function, null, \true); if ($codebase->analysis_php_version_id >= 80300) { $has_override_attribute = array_filter($storage->attributes, static fn(AttributeStorage $s): bool => $s->fq_class_name === 'Override'); if ($has_override_attribute && (!$overridden_method_ids || $storage->cased_name === '__construct')) { IssueBuffer::maybeAdd(new InvalidOverride('Method ' . $storage->cased_name . ' does not match any parent method', $codeLocation), $this->getSuppressedIssues()); } if (!$has_override_attribute && $codebase->config->ensure_override_attribute && $overridden_method_ids && $storage->cased_name !== '__construct' && ($storage->cased_name !== '__toString' || isset($appearing_class_storage->direct_class_interfaces['stringable']))) { IssueBuffer::maybeAdd(new MissingOverrideAttribute('Method ' . $storage->cased_name . ' should have the "Override" attribute', $codeLocation), $this->getSuppressedIssues()); } } if ($overridden_method_ids && !$context->collect_initializations && !$context->collect_mutations) { foreach ($overridden_method_ids as $overridden_method_id) { $parent_method_storage = $codebase->methods->getStorage($overridden_method_id); $overridden_fq_class_name = $overridden_method_id->fq_class_name; $parent_storage = $classlike_storage_provider->get($overridden_fq_class_name); if ($this->function->name->name === '__construct' && !$parent_storage->preserve_constructor_signature) { continue; } $implementer_visibility = $storage->visibility; $implementer_appearing_method_id = $codebase->methods->getAppearingMethodId($method_id); $implementer_declaring_method_id = $real_method_id; $declaring_class_storage = $appearing_class_storage; if ($implementer_appearing_method_id && $implementer_appearing_method_id !== $implementer_declaring_method_id) { $appearing_fq_class_name = $implementer_appearing_method_id->fq_class_name; $appearing_method_name = $implementer_appearing_method_id->method_name; $declaring_fq_class_name = $implementer_declaring_method_id->fq_class_name; $appearing_class_storage = $classlike_storage_provider->get($appearing_fq_class_name); $declaring_class_storage = $classlike_storage_provider->get($declaring_fq_class_name); if (isset($appearing_class_storage->trait_visibility_map[$appearing_method_name])) { $implementer_visibility = $appearing_class_storage->trait_visibility_map[$appearing_method_name]; } } // we've already checked this in the class checker if (!isset($appearing_class_storage->class_implements[strtolower($overridden_fq_class_name)])) { \Psalm\Internal\Analyzer\MethodComparator::compare($codebase, count($overridden_method_ids) === 1 ? $this->function : null, $declaring_class_storage, $parent_storage, $storage, $parent_method_storage, $fq_class_name, $implementer_visibility, $codeLocation, $storage->suppressed_issues); } } } \Psalm\Internal\Analyzer\MethodAnalyzer::checkMethodSignatureMustOmitReturnType($storage, $codeLocation); if ($appearing_class_storage->is_enum) { \Psalm\Internal\Analyzer\MethodAnalyzer::checkForbiddenEnumMethod($storage, $appearing_class_storage); } if (!$context->calling_method_id || !$context->collect_initializations) { $context->calling_method_id = strtolower((string) $method_id); } } elseif ($this instanceof \Psalm\Internal\Analyzer\FunctionAnalyzer) { $function_name = $this->function->name->name; $namespace_prefix = $this->getNamespace(); $cased_method_id = ($namespace_prefix !== null ? $namespace_prefix . '\\' : '') . $function_name; $context->calling_function_id = strtolower($cased_method_id); } elseif ($this instanceof \Psalm\Internal\Analyzer\ClosureAnalyzer) { if ($storage->return_type) { $closure_return_type = TypeExpander::expandUnion($codebase, $storage->return_type, $context->self, $context->self, $this->getParentFQCLN()); } else { $closure_return_type = Type::getMixed(); } $closure_type = new TClosure('Closure', $storage->params, $closure_return_type, $storage instanceof FunctionStorage ? $storage->pure : null, $storage instanceof FunctionStorage ? $storage->byref_uses : []); $type_provider->setType($this->function, new Union([$closure_type])); } else { throw new UnexpectedValueException('Impossible'); } return [$real_method_id, $method_id, $appearing_class_storage, $hash, $cased_method_id, $overridden_method_ids]; } /** * @return array */ private function detectUnusedParameters(\Psalm\Internal\Analyzer\StatementsAnalyzer $statements_analyzer, FunctionLikeStorage $storage, Context $context) : array { $codebase = $statements_analyzer->getCodebase(); $unused_params = []; foreach ($statements_analyzer->getUnusedVarLocations() as [$var_name, $original_location]) { if (!array_key_exists(substr($var_name, 1), $storage->param_lookup)) { continue; } if ($this->isIgnoredForUnusedParam($var_name)) { continue; } $position = array_search(substr($var_name, 1), array_keys($storage->param_lookup), \true); if ($position === \false) { throw new UnexpectedValueException('$position should not be false here'); } if ($storage->params[$position]->promoted_property) { continue; } $did_match_param = \false; foreach ($this->function->params as $param) { if ($param->var->getAttribute('endFilePos') === $original_location->raw_file_end) { $did_match_param = \true; break; } } if (!$did_match_param) { continue; } $assignment_node = DataFlowNode::getForAssignment($var_name, $original_location); if ($statements_analyzer->data_flow_graph instanceof VariableUseGraph && $statements_analyzer->data_flow_graph->isVariableUsed($assignment_node)) { continue; } if (!$storage instanceof MethodStorage || !$storage->cased_name || $storage->visibility === \Psalm\Internal\Analyzer\ClassLikeAnalyzer::VISIBILITY_PRIVATE) { $unused_params[$position] = $original_location; continue; } $fq_class_name = (string) $context->self; $class_storage = $codebase->classlike_storage_provider->get($fq_class_name); $method_name_lc = strtolower($storage->cased_name); if ($storage->abstract) { continue; } if (isset($class_storage->overridden_method_ids[$method_name_lc])) { $parent_method_id = end($class_storage->overridden_method_ids[$method_name_lc]); if ($parent_method_id) { $parent_method_storage = $codebase->methods->getStorage($parent_method_id); // if the parent method has a param at that position and isn't abstract if (!$parent_method_storage->abstract && isset($parent_method_storage->params[$position])) { continue; } } } $unused_params[$position] = $original_location; } return $unused_params; } private function detectPreviousUnusedArgumentPosition(FunctionLikeStorage $function, int $position) : int { $params = $function->params; krsort($params, SORT_NUMERIC); foreach ($params as $index => $param) { if ($index > $position) { continue; } if ($this->isIgnoredForUnusedParam($param->name)) { continue; } return $index; } return 0; } private function isIgnoredForUnusedParam(string $var_name) : bool { return strpos($var_name, '$_') === 0 || strpos($var_name, '$unused') === 0 && $var_name !== '$unused'; } } */ private array $required_file_paths = []; /** * @var array */ private array $parent_file_paths = []; /** * @var array */ private array $suppressed_issues = []; /** * @var array> */ private array $namespace_aliased_classes = []; /** * @var array> */ private array $namespace_aliased_classes_flipped = []; /** * @var array> */ private array $namespace_aliased_classes_flipped_replaceable = []; /** * @var array */ public array $interface_analyzers_to_analyze = []; /** * @var array */ public array $class_analyzers_to_analyze = []; public ?Context $context = null; public \Psalm\Internal\Analyzer\ProjectAnalyzer $project_analyzer; public Codebase $codebase; private int $first_statement_offset = -1; private ?NodeDataProvider $node_data = null; private ?Union $return_type = null; public function __construct(\Psalm\Internal\Analyzer\ProjectAnalyzer $project_analyzer, string $file_path, string $file_name) { $this->source = $this; $this->file_path = $file_path; $this->file_name = $file_name; $this->project_analyzer = $project_analyzer; $this->codebase = $project_analyzer->getCodebase(); } public function analyze(?Context $file_context = null, ?Context $global_context = null) : void { $codebase = $this->project_analyzer->getCodebase(); $file_storage = $codebase->file_storage_provider->get($this->file_path); if (!$file_storage->deep_scan && !$codebase->server_mode) { throw new UnpreparedAnalysisException('File ' . $this->file_path . ' has not been properly scanned'); } if ($file_storage->has_visitor_issues) { return; } if ($file_context) { $this->context = $file_context; } if (!$this->context) { $this->context = new Context(); } if ($codebase->config->useStrictTypesForFile($this->file_path)) { $this->context->strict_types = \true; } $this->context->is_global = \true; $this->context->defineGlobals(); $this->context->collect_exceptions = $codebase->config->check_for_throws_in_global_scope; try { $stmts = $codebase->getStatementsForFile($this->file_path); } catch (PhpParser\Error $e) { return; } $event = new BeforeFileAnalysisEvent($this, $this->context, $file_storage, $codebase, $stmts); $codebase->config->eventDispatcher->dispatchBeforeFileAnalysis($event); if ($codebase->alter_code) { foreach ($stmts as $stmt) { if (!$stmt instanceof PhpParser\Node\Stmt\Declare_) { $this->first_statement_offset = (int) $stmt->getAttribute('startFilePos'); break; } } } $leftover_stmts = $this->populateCheckers($stmts); $this->node_data = new NodeDataProvider(); $statements_analyzer = new \Psalm\Internal\Analyzer\StatementsAnalyzer($this, $this->node_data); foreach ($file_storage->docblock_issues as $docblock_issue) { IssueBuffer::maybeAdd($docblock_issue); } // if there are any leftover statements, evaluate them, // in turn causing the classes/interfaces be evaluated if ($leftover_stmts) { $statements_analyzer->analyze($leftover_stmts, $this->context, $global_context, \true); foreach ($leftover_stmts as $leftover_stmt) { if ($leftover_stmt instanceof PhpParser\Node\Stmt\Return_) { if ($leftover_stmt->expr) { $this->return_type = $statements_analyzer->node_data->getType($leftover_stmt->expr) ?? Type::getMixed(); } else { $this->return_type = Type::getVoid(); } break; } } } // check any leftover interfaces not already evaluated foreach ($this->interface_analyzers_to_analyze as $interface_analyzer) { $interface_analyzer->analyze(); } // check any leftover classes not already evaluated foreach ($this->class_analyzers_to_analyze as $class_analyzer) { $class_analyzer->analyze(null, $this->context); } if ($codebase->config->check_for_throws_in_global_scope) { $uncaught_throws = $statements_analyzer->getUncaughtThrows($this->context); foreach ($uncaught_throws as $possibly_thrown_exception => $codelocations) { foreach ($codelocations as $codelocation) { // issues are suppressed in ThrowAnalyzer, CallAnalyzer, etc. IssueBuffer::maybeAdd(new UncaughtThrowInGlobalScope($possibly_thrown_exception . ' is thrown but not caught in global scope', $codelocation)); } } } // validate type imports if ($file_storage->type_aliases) { foreach ($file_storage->type_aliases as $alias) { if ($alias instanceof LinkableTypeAlias) { $location = new DocblockTypeLocation($this->getSource(), $alias->start_offset, $alias->end_offset, $alias->line_number); $fq_source_classlike = $alias->declaring_fq_classlike_name; if (\Psalm\Internal\Analyzer\ClassLikeAnalyzer::checkFullyQualifiedClassLikeName($this->getSource(), $fq_source_classlike, $location, null, null, $this->suppressed_issues, new \Psalm\Internal\Analyzer\ClassLikeNameOptions(\true, \true, \true, \true, \true)) === \false) { continue; } $referenced_class_storage = $codebase->classlike_storage_provider->get($fq_source_classlike); if (!isset($referenced_class_storage->type_aliases[$alias->alias_name])) { IssueBuffer::maybeAdd(new InvalidTypeImport('Type alias ' . $alias->alias_name . ' imported from ' . $fq_source_classlike . ' is not defined on the source class', $location)); } } } } $event = new AfterFileAnalysisEvent($this, $this->context, $file_storage, $codebase, $stmts); $codebase->config->eventDispatcher->dispatchAfterFileAnalysis($event); $this->class_analyzers_to_analyze = []; $this->interface_analyzers_to_analyze = []; } /** * @param array $stmts * @return list */ public function populateCheckers(array $stmts) : array { $leftover_stmts = []; foreach ($stmts as $stmt) { if ($stmt instanceof PhpParser\Node\Stmt\Trait_) { $leftover_stmts[] = $stmt; } elseif ($stmt instanceof PhpParser\Node\Stmt\ClassLike) { $this->populateClassLikeAnalyzers($stmt); } elseif ($stmt instanceof PhpParser\Node\Stmt\Namespace_) { $namespace_name = $stmt->name ? $stmt->name->toString() : ''; $namespace_analyzer = new \Psalm\Internal\Analyzer\NamespaceAnalyzer($stmt, $this); $namespace_analyzer->collectAnalyzableInformation(); $this->namespace_aliased_classes[$namespace_name] = $namespace_analyzer->getAliases()->uses; $this->namespace_aliased_classes_flipped[$namespace_name] = $namespace_analyzer->getAliasedClassesFlipped(); $this->namespace_aliased_classes_flipped_replaceable[$namespace_name] = $namespace_analyzer->getAliasedClassesFlippedReplaceable(); } elseif ($stmt instanceof PhpParser\Node\Stmt\Use_) { $this->visitUse($stmt); } elseif ($stmt instanceof PhpParser\Node\Stmt\GroupUse) { $this->visitGroupUse($stmt); } else { if ($stmt instanceof PhpParser\Node\Stmt\If_) { foreach ($stmt->stmts as $if_stmt) { if ($if_stmt instanceof PhpParser\Node\Stmt\ClassLike) { $this->populateClassLikeAnalyzers($if_stmt); } } } $leftover_stmts[] = $stmt; } } return $leftover_stmts; } private function populateClassLikeAnalyzers(PhpParser\Node\Stmt\ClassLike $stmt) : void { if ($stmt instanceof PhpParser\Node\Stmt\Class_ || $stmt instanceof PhpParser\Node\Stmt\Enum_) { if (!$stmt->name) { return; } // this can happen when stubbing if (!$this->codebase->classExists($stmt->name->name) && !$this->codebase->classlikes->enumExists($stmt->name->name)) { return; } $class_analyzer = new \Psalm\Internal\Analyzer\ClassAnalyzer($stmt, $this, $stmt->name->name); $fq_class_name = $class_analyzer->getFQCLN(); $this->class_analyzers_to_analyze[strtolower($fq_class_name)] = $class_analyzer; } elseif ($stmt instanceof PhpParser\Node\Stmt\Interface_) { if (!$stmt->name) { return; } // this can happen when stubbing if (!$this->codebase->interfaceExists($stmt->name->name)) { return; } $class_analyzer = new \Psalm\Internal\Analyzer\InterfaceAnalyzer($stmt, $this, $stmt->name->name); $fq_class_name = $class_analyzer->getFQCLN(); $this->interface_analyzers_to_analyze[strtolower($fq_class_name)] = $class_analyzer; } } public function addNamespacedClassAnalyzer(string $fq_class_name, \Psalm\Internal\Analyzer\ClassAnalyzer $class_analyzer) : void { $this->class_analyzers_to_analyze[strtolower($fq_class_name)] = $class_analyzer; } public function addNamespacedInterfaceAnalyzer(string $fq_class_name, \Psalm\Internal\Analyzer\InterfaceAnalyzer $interface_analyzer) : void { $this->interface_analyzers_to_analyze[strtolower($fq_class_name)] = $interface_analyzer; } public function getMethodMutations(MethodIdentifier $method_id, Context $this_context, bool $from_project_analyzer = \false) : void { $fq_class_name = $method_id->fq_class_name; $method_name = $method_id->method_name; $fq_class_name_lc = strtolower($fq_class_name); if (isset($this->class_analyzers_to_analyze[$fq_class_name_lc])) { $class_analyzer_to_examine = $this->class_analyzers_to_analyze[$fq_class_name_lc]; } else { if (!$from_project_analyzer) { $this->project_analyzer->getMethodMutations($method_id, $this_context, $this->getRootFilePath(), $this->getRootFileName()); } return; } $call_context = new Context($this_context->self); $call_context->collect_mutations = $this_context->collect_mutations; $call_context->collect_initializations = $this_context->collect_initializations; $call_context->collect_nonprivate_initializations = $this_context->collect_nonprivate_initializations; $call_context->initialized_methods = $this_context->initialized_methods; $call_context->include_location = $this_context->include_location; $call_context->calling_method_id = $this_context->calling_method_id; foreach ($this_context->vars_possibly_in_scope as $var => $_) { if (strpos($var, '$this->') === 0) { $call_context->vars_possibly_in_scope[$var] = \true; } } foreach ($this_context->vars_in_scope as $var => $type) { if (strpos($var, '$this->') === 0) { $call_context->vars_in_scope[$var] = $type; } } if (!isset($this_context->vars_in_scope['$this'])) { throw new UnexpectedValueException('Should exist'); } $call_context->vars_in_scope['$this'] = $this_context->vars_in_scope['$this']; $class_analyzer_to_examine->getMethodMutations($method_name, $call_context); foreach ($call_context->vars_possibly_in_scope as $var => $_) { $this_context->vars_possibly_in_scope[$var] = \true; } foreach ($call_context->vars_in_scope as $var => $type) { $this_context->vars_in_scope[$var] = $type; } } public function getFunctionLikeAnalyzer(MethodIdentifier $method_id) : ?\Psalm\Internal\Analyzer\MethodAnalyzer { $fq_class_name = $method_id->fq_class_name; $method_name = $method_id->method_name; $fq_class_name_lc = strtolower($fq_class_name); if (!isset($this->class_analyzers_to_analyze[$fq_class_name_lc])) { return null; } $class_analyzer_to_examine = $this->class_analyzers_to_analyze[$fq_class_name_lc]; return $class_analyzer_to_examine->getFunctionLikeAnalyzer($method_name); } /** @psalm-mutation-free */ public function getNamespace() : ?string { return null; } /** * @psalm-mutation-free * @return array */ public function getAliasedClassesFlipped(?string $namespace_name = null) : array { if ($namespace_name && isset($this->namespace_aliased_classes_flipped[$namespace_name])) { return $this->namespace_aliased_classes_flipped[$namespace_name]; } return $this->aliased_classes_flipped; } /** * @psalm-mutation-free * @return array */ public function getAliasedClassesFlippedReplaceable(?string $namespace_name = null) : array { if ($namespace_name && isset($this->namespace_aliased_classes_flipped_replaceable[$namespace_name])) { return $this->namespace_aliased_classes_flipped_replaceable[$namespace_name]; } return $this->aliased_classes_flipped_replaceable; } public static function clearCache() : void { TypeTokenizer::clearCache(); Reflection::clearCache(); Functions::clearCache(); IssueBuffer::clearCache(); FileManipulationBuffer::clearCache(); \Psalm\Internal\Analyzer\FunctionLikeAnalyzer::clearCache(); ClassLikeStorageProvider::deleteAll(); FileStorageProvider::deleteAll(); FileReferenceProvider::clearCache(); InternalCallMapHandler::clearCache(); } /** @psalm-mutation-free */ public function getFileName() : string { return $this->file_name; } /** @psalm-mutation-free */ public function getFilePath() : string { return $this->file_path; } /** @psalm-mutation-free */ public function getRootFileName() : string { return $this->root_file_name ?: $this->file_name; } /** @psalm-mutation-free */ public function getRootFilePath() : string { return $this->root_file_path ?: $this->file_path; } public function setRootFilePath(string $file_path, string $file_name) : void { $this->root_file_name = $file_name; $this->root_file_path = $file_path; } public function addRequiredFilePath(string $file_path) : void { $this->required_file_paths[$file_path] = \true; } public function addParentFilePath(string $file_path) : void { $this->parent_file_paths[$file_path] = \true; } /** @psalm-mutation-free */ public function hasParentFilePath(string $file_path) : bool { return $this->file_path === $file_path || isset($this->parent_file_paths[$file_path]); } /** @psalm-mutation-free */ public function hasAlreadyRequiredFilePath(string $file_path) : bool { return isset($this->required_file_paths[$file_path]); } /** * @psalm-mutation-free * @return list */ public function getRequiredFilePaths() : array { return array_keys($this->required_file_paths); } /** * @psalm-mutation-free * @return list */ public function getParentFilePaths() : array { return array_keys($this->parent_file_paths); } /** @psalm-mutation-free */ public function getRequireNesting() : int { return count($this->parent_file_paths); } /** * @psalm-mutation-free * @return array */ public function getSuppressedIssues() : array { return $this->suppressed_issues; } /** * @param array $new_issues */ public function addSuppressedIssues(array $new_issues) : void { if (isset($new_issues[0])) { $new_issues = array_combine($new_issues, $new_issues); } $this->suppressed_issues = $new_issues + $this->suppressed_issues; } /** * @param array $new_issues */ public function removeSuppressedIssues(array $new_issues) : void { if (isset($new_issues[0])) { $new_issues = array_combine($new_issues, $new_issues); } $this->suppressed_issues = array_diff_key($this->suppressed_issues, $new_issues); } /** @psalm-mutation-free */ public function getFQCLN() : ?string { return null; } /** @psalm-mutation-free */ public function getParentFQCLN() : ?string { return null; } /** @psalm-mutation-free */ public function getClassName() : ?string { return null; } /** * @psalm-mutation-free * @return array>|null */ public function getTemplateTypeMap() : ?array { return null; } /** @psalm-mutation-free */ public function isStatic() : bool { return \false; } /** * @psalm-mutation-free */ public function getFileAnalyzer() : \Psalm\Internal\Analyzer\FileAnalyzer { return $this; } /** * @psalm-mutation-free */ public function getProjectAnalyzer() : \Psalm\Internal\Analyzer\ProjectAnalyzer { return $this->project_analyzer; } /** @psalm-mutation-free */ public function getCodebase() : Codebase { return $this->codebase; } /** @psalm-mutation-free */ public function getFirstStatementOffset() : int { return $this->first_statement_offset; } /** @psalm-mutation-free */ public function getNodeTypeProvider() : NodeTypeProvider { if (!$this->node_data) { throw new UnexpectedValueException('There should be a node type provider'); } return $this->node_data; } /** @psalm-mutation-free */ public function getReturnType() : ?Union { return $this->return_type; } public function clearSourceBeforeDestruction() : void { unset($this->source); } } */ final class MethodAnalyzer extends \Psalm\Internal\Analyzer\FunctionLikeAnalyzer { // https://github.com/php/php-src/blob/a83923044c48982c80804ae1b45e761c271966d3/Zend/zend_enum.c#L77-L95 private const FORBIDDEN_ENUM_METHODS = ['__construct', '__destruct', '__clone', '__get', '__set', '__unset', '__isset', '__tostring', '__debuginfo', '__serialize', '__unserialize', '__sleep', '__wakeup', '__set_state']; /** @psalm-external-mutation-free */ public function __construct(PhpParser\Node\Stmt\ClassMethod $function, \Psalm\Internal\Analyzer\SourceAnalyzer $source, ?MethodStorage $storage = null) { $codebase = $source->getCodebase(); $method_name_lc = strtolower((string) $function->name); $source_fqcln = (string) $source->getFQCLN(); $source_fqcln_lc = strtolower($source_fqcln); $method_id = new MethodIdentifier($source_fqcln, $method_name_lc); if (!$storage) { try { $storage = $codebase->methods->getStorage($method_id); } catch (UnexpectedValueException $e) { $class_storage = $codebase->classlike_storage_provider->get($source_fqcln_lc); if (!$class_storage->parent_classes) { throw $e; } $declaring_method_id = $codebase->methods->getDeclaringMethodId($method_id); if (!$declaring_method_id) { throw $e; } // happens for fake constructors $storage = $codebase->methods->getStorage($declaring_method_id); } } parent::__construct($function, $source, $storage); } /** * Determines whether a given method is static or not * * @param array $suppressed_issues */ public static function checkStatic(MethodIdentifier $method_id, bool $self_call, bool $is_context_dynamic, Codebase $codebase, CodeLocation $code_location, array $suppressed_issues, ?bool &$is_dynamic_this_method = \false) : void { $codebase_methods = $codebase->methods; if ($method_id->fq_class_name === 'Closure' && $method_id->method_name === 'fromcallable') { return; } $original_method_id = $method_id; $with_pseudo = \true; $method_id = $codebase_methods->getDeclaringMethodId($method_id, $with_pseudo); if (!$method_id) { if (InternalCallMapHandler::inCallMap((string) $original_method_id)) { return; } throw new LogicException('Declaring method for ' . $original_method_id . ' should not be null'); } $storage = $codebase_methods->getStorage($method_id, $with_pseudo); if (!$storage->is_static) { if ($self_call) { if (!$is_context_dynamic) { if (IssueBuffer::accepts(new NonStaticSelfCall('Method ' . $codebase_methods->getCasedMethodId($method_id) . ' is not static, but is called ' . 'using self::', $code_location), $suppressed_issues)) { return; } } else { $is_dynamic_this_method = \true; } } else { if (IssueBuffer::accepts(new InvalidStaticInvocation('Method ' . $codebase_methods->getCasedMethodId($method_id) . ' is not static, but is called ' . 'statically', $code_location), $suppressed_issues)) { return; } } } } /** * @param string[] $suppressed_issues * @param lowercase-string|null $calling_method_id */ public static function checkMethodExists(Codebase $codebase, MethodIdentifier $method_id, CodeLocation $code_location, array $suppressed_issues, ?string $calling_method_id = null, bool $with_pseudo = \false) : ?bool { if ($codebase->methods->methodExists($method_id, $calling_method_id, !$calling_method_id || $calling_method_id !== strtolower((string) $method_id) ? $code_location : null, null, $code_location->file_path, \true, \false, $with_pseudo)) { return \true; } if ($with_pseudo) { if (IssueBuffer::accepts(new UndefinedMagicMethod('Magic method ' . $method_id . ' does not exist', $code_location, (string) $method_id), $suppressed_issues)) { return \false; } } else { if (IssueBuffer::accepts(new UndefinedMethod('Method ' . $method_id . ' does not exist', $code_location, (string) $method_id), $suppressed_issues)) { return \false; } } return null; } public static function isMethodVisible(MethodIdentifier $method_id, Context $context, StatementsSource $source) : bool { $codebase = $source->getCodebase(); $fq_classlike_name = $method_id->fq_class_name; $method_name = $method_id->method_name; if ($codebase->methods->visibility_provider->has($fq_classlike_name)) { $method_visible = $codebase->methods->visibility_provider->isMethodVisible($source, $fq_classlike_name, $method_name, $context, null); if ($method_visible !== null) { return $method_visible; } } $declaring_method_id = $codebase->methods->getDeclaringMethodId($method_id); if (!$declaring_method_id) { // this can happen for methods in the callmap that were not reflected return \true; } $appearing_method_id = $codebase->methods->getAppearingMethodId($method_id); $appearing_method_class = null; if ($appearing_method_id) { $appearing_method_class = $appearing_method_id->fq_class_name; // if the calling class is the same, we know the method exists, so it must be visible if ($appearing_method_class === $context->self) { return \true; } } $declaring_method_class = $declaring_method_id->fq_class_name; if ($source->getSource() instanceof \Psalm\Internal\Analyzer\TraitAnalyzer && strtolower($declaring_method_class) === strtolower((string) $source->getFQCLN())) { return \true; } $storage = $codebase->methods->getStorage($declaring_method_id); switch ($storage->visibility) { case \Psalm\Internal\Analyzer\ClassLikeAnalyzer::VISIBILITY_PUBLIC: return \true; case \Psalm\Internal\Analyzer\ClassLikeAnalyzer::VISIBILITY_PRIVATE: return $context->self && $appearing_method_class === $context->self; case \Psalm\Internal\Analyzer\ClassLikeAnalyzer::VISIBILITY_PROTECTED: if (!$context->self) { return \false; } if ($appearing_method_class && $codebase->classExtends($appearing_method_class, $context->self)) { return \true; } if ($appearing_method_class && !$codebase->classExtends($context->self, $appearing_method_class)) { return \false; } } return \true; } /** * Check that __clone, __construct, and __destruct do not have a return type * hint in their signature. */ public static function checkMethodSignatureMustOmitReturnType(MethodStorage $method_storage, CodeLocation $code_location) : void { if ($method_storage->signature_return_type === null) { return; } if ($method_storage->cased_name === null) { return; } $method_name_lc = strtolower($method_storage->cased_name); $methodsOfInterest = ['__clone', '__construct', '__destruct']; if (in_array($method_name_lc, $methodsOfInterest, \true)) { IssueBuffer::maybeAdd(new MethodSignatureMustOmitReturnType('Method ' . $method_storage->cased_name . ' must not declare a return type', $code_location)); } } public function getMethodId(?string $context_self = null) : MethodIdentifier { $function_name = (string) $this->function->name; return new MethodIdentifier($context_self ?: (string) $this->source->getFQCLN(), strtolower($function_name)); } public static function checkForbiddenEnumMethod(MethodStorage $method_storage, ClassLikeStorage $enum_storage) : void { if ($method_storage->cased_name === null || $method_storage->location === null) { return; } $method_name_lc = strtolower($method_storage->cased_name); if (in_array($method_name_lc, self::FORBIDDEN_ENUM_METHODS, \true)) { IssueBuffer::maybeAdd(new InvalidEnumMethod('Enums cannot define ' . $method_storage->cased_name, $method_storage->location, $method_storage->defining_fqcln . '::' . $method_storage->cased_name)); } if ($method_name_lc === 'cases') { IssueBuffer::maybeAdd(new InvalidEnumMethod('Enums cannot define ' . $method_storage->cased_name, $method_storage->location, $method_storage->defining_fqcln . '::' . $method_storage->cased_name)); } if ($enum_storage->enum_type && ($method_name_lc === 'from' || $method_name_lc === 'tryfrom')) { IssueBuffer::maybeAdd(new InvalidEnumMethod('Enums cannot define ' . $method_storage->cased_name, $method_storage->location, $method_storage->defining_fqcln . '::' . $method_storage->cased_name)); } } } */ final class FunctionAnalyzer extends \Psalm\Internal\Analyzer\FunctionLikeAnalyzer { public function __construct(PhpParser\Node\Stmt\Function_ $function, \Psalm\Internal\Analyzer\SourceAnalyzer $source) { $codebase = $source->getCodebase(); $file_storage_provider = $codebase->file_storage_provider; $file_storage = $file_storage_provider->get($source->getFilePath()); $namespace = $source->getNamespace(); $function_id = ($namespace ? strtolower($namespace) . '\\' : '') . strtolower($function->name->name); if (!isset($file_storage->functions[$function_id])) { throw new UnexpectedValueException('Function ' . $function_id . ' should be defined in ' . $source->getFilePath()); } $storage = $file_storage->functions[$function_id]; parent::__construct($function, $source, $storage); } /** * @return non-empty-lowercase-string * @throws UnexpectedValueException if function is closure or arrow function. */ public function getFunctionId() : string { $namespace = $this->source->getNamespace(); /** @var non-empty-lowercase-string */ return ($namespace ? strtolower($namespace) . '\\' : '') . strtolower($this->function->name->name); } public static function analyzeStatement(\Psalm\Internal\Analyzer\StatementsAnalyzer $statements_analyzer, PhpParser\Node\Stmt\Function_ $stmt, Context $context) : void { foreach ($stmt->stmts as $function_stmt) { if ($function_stmt instanceof PhpParser\Node\Stmt\Global_) { foreach ($function_stmt->vars as $var) { if ($var instanceof PhpParser\Node\Expr\Variable) { if (is_string($var->name)) { $var_id = '$' . $var->name; // registers variable in global context $context->hasVariable($var_id); } } } } elseif (!$function_stmt instanceof PhpParser\Node\Stmt\Nop) { break; } } $codebase = $statements_analyzer->getCodebase(); if (!$codebase->register_stub_files && !$codebase->register_autoload_files) { $function_name = strtolower($stmt->name->name); if ($ns = $statements_analyzer->getNamespace()) { $fq_function_name = strtolower($ns) . '\\' . $function_name; } else { $fq_function_name = $function_name; } $function_context = new Context($context->self); $function_context->strict_types = $context->strict_types; $config = Config::getInstance(); $function_context->collect_exceptions = $config->check_for_throws_docblock; if ($function_analyzer = $statements_analyzer->getFunctionAnalyzer($fq_function_name)) { $function_analyzer->analyze($function_context, $statements_analyzer->node_data, $context); if ($config->reportIssueInFile('InvalidReturnType', $statements_analyzer->getFilePath())) { $method_id = $function_analyzer->getId(); $function_storage = $codebase->functions->getStorage($statements_analyzer, strtolower($method_id)); $return_type = $function_storage->return_type; $return_type_location = $function_storage->return_type_location; $function_analyzer->verifyReturnType($stmt->getStmts(), $statements_analyzer, $return_type, $statements_analyzer->getFQCLN(), $return_type_location, $function_context->has_returned); } } } } } getSuppressedIssues(); $codebase = $source->getCodebase(); $project_analyzer = $source->getProjectAnalyzer(); $function_like_storage = null; if ($source instanceof StatementsAnalyzer) { $function_like_storage = $function_like_analyzer->getFunctionLikeStorage($source); } elseif ($source instanceof ClassAnalyzer || $source instanceof TraitAnalyzer) { $function_like_storage = $function_like_analyzer->getFunctionLikeStorage(); } $cased_method_id = $function_like_analyzer->getCorrectlyCasedMethodId(); if (!$function->getStmts() && ($function instanceof ClassMethod && ($source instanceof InterfaceAnalyzer || $function->isAbstract()))) { if (!$return_type) { IssueBuffer::maybeAdd(new MissingReturnType('Method ' . $cased_method_id . ' does not have a return type', new CodeLocation($function_like_analyzer, $function->name, null, \true)), $suppressed_issues); } return null; } $is_to_string = $function instanceof ClassMethod && strtolower($function->name->name) === '__tostring'; if ($function instanceof ClassMethod && strpos($function->name->name, '__') === 0 && !$is_to_string && !$return_type) { // do not check __construct, __set, __get, __call etc. return null; } if (!$return_type_location) { $return_type_location = new CodeLocation($function_like_analyzer, $function instanceof Closure || $function instanceof ArrowFunction ? $function : $function->name); } $inferred_yield_types = []; $inferred_return_type_parts = \Psalm\Internal\Analyzer\FunctionLike\ReturnTypeCollector::getReturnTypes($codebase, $type_provider, $function_stmts, $inferred_yield_types, \true); if (!$inferred_return_type_parts) { $did_explicitly_return = \true; } if ((!$return_type || $return_type->from_docblock) && ScopeAnalyzer::getControlActions($function_stmts, $type_provider, []) !== [ScopeAnalyzer::ACTION_END] && !$inferred_yield_types && count($inferred_return_type_parts) && !$did_explicitly_return) { // only add null if we have a return statement elsewhere and it wasn't void or never foreach ($inferred_return_type_parts as $inferred_return_type_part) { if (!$inferred_return_type_part->isVoid() && !$inferred_return_type_part->isNever()) { $atomic_null = new TNull(\true); $inferred_return_type_parts[] = new Union([$atomic_null]); break; } } } $control_actions = ScopeAnalyzer::getControlActions($function_stmts, $type_provider, [], \false); $function_always_exits = $control_actions === [ScopeAnalyzer::ACTION_END]; $function_returns_implicitly = (bool) array_diff($control_actions, [ScopeAnalyzer::ACTION_END, ScopeAnalyzer::ACTION_RETURN]); /** @psalm-suppress PossiblyUndefinedStringArrayOffset */ if ($return_type && (!$return_type->from_docblock || $return_type->isNullable() && !$return_type->hasTemplate() && !$return_type->getAtomicTypes()['null']->from_docblock) && !$return_type->isVoid() && !$return_type->isNever() && !$inferred_yield_types && (!$function_like_storage || !$function_like_storage->has_yield) && $function_returns_implicitly) { if (IssueBuffer::accepts(new InvalidReturnType('Not all code paths of ' . $cased_method_id . ' end in a return statement, return type ' . $return_type . ' expected', $return_type_location), $suppressed_issues)) { return \false; } return null; } if ($return_type && $return_type->isNever() && !$inferred_yield_types && !$function_always_exits) { if (IssueBuffer::accepts(new InvalidReturnType($cased_method_id . ' is not expected to return, but it does, ' . 'either implicitly or explicitly', $return_type_location), $suppressed_issues)) { return \false; } return null; } // only now after non-implicit things are checked if ($function_returns_implicitly) { $inferred_return_type_parts[] = Type::getVoid(); } $inferred_return_type_parts_with_never = $inferred_return_type_parts; // we filter TNever that have no bearing on the return type if (count($inferred_return_type_parts) > 1) { $inferred_return_type_parts = array_filter($inferred_return_type_parts, static fn(Union $union_type): bool => !$union_type->isNever()); } $inferred_return_type_parts = array_values($inferred_return_type_parts); $inferred_return_type = $inferred_return_type_parts ? Type::combineUnionTypeArray($inferred_return_type_parts, $codebase) : Type::getVoid(); if ($function_always_exits) { $inferred_return_type = Type::getNever(); } // void + never = null, so we need to check this separately if (count($inferred_return_type_parts_with_never) > 1 && !$function_always_exits && $inferred_return_type_parts_with_never !== $inferred_return_type_parts) { /** * see https://github.com/vimeo/psalm/issues/9045 * * @psalm-suppress InvalidArgument */ $inferred_return_type_with_never = Type::combineUnionTypeArray($inferred_return_type_parts_with_never, $codebase); } else { $inferred_return_type_with_never = $inferred_return_type; } $inferred_yield_type = $inferred_yield_types ? Type::combineUnionTypeArray($inferred_yield_types, $codebase) : null; if ($inferred_yield_type) { $inferred_return_type = $inferred_yield_type; } $unsafe_return_type = \false; // prevent any return types that do not return a value from being used in PHP typehints if ($codebase->alter_code && $inferred_return_type->isNullable() && !$inferred_yield_types) { foreach ($inferred_return_type_parts as $inferred_return_type_part) { if ($inferred_return_type_part->isVoid()) { $unsafe_return_type = \true; break; } } } $inferred_return_type = TypeExpander::expandUnion($codebase, $inferred_return_type, $source->getFQCLN(), $source->getFQCLN(), $source->getParentFQCLN()); if ($is_to_string) { $union_comparison_results = new TypeComparisonResult(); if (!$inferred_return_type->hasMixed() && !UnionTypeComparator::isContainedBy($codebase, $inferred_return_type, Type::getString(), $inferred_return_type->ignore_nullable_issues, $inferred_return_type->ignore_falsable_issues, $union_comparison_results)) { if (IssueBuffer::accepts(new InvalidToString('__toString methods must return a string, ' . $inferred_return_type . ' returned', $return_type_location), $suppressed_issues)) { return \false; } } if ($union_comparison_results->to_string_cast) { IssueBuffer::maybeAdd(new ImplicitToStringCast('The declared return type for ' . $cased_method_id . ' expects string, ' . '\'' . $inferred_return_type . '\' provided with a __toString method', $return_type_location), $suppressed_issues); } return null; } if (!$return_type) { if ($function instanceof Closure || $function instanceof ArrowFunction) { if (!$closure_inside_call || $inferred_return_type->isMixed()) { if ($codebase->alter_code && isset($project_analyzer->getIssuesToFix()['MissingClosureReturnType']) && !in_array('MissingClosureReturnType', $suppressed_issues)) { if ($inferred_return_type->hasMixed() || $inferred_return_type->isNull()) { return null; } self::addOrUpdateReturnType($function, $project_analyzer, $inferred_return_type, $source, ($project_analyzer->only_replace_php_types_with_non_docblock_types || $unsafe_return_type) && $inferred_return_type->from_docblock, $function_like_storage); return null; } IssueBuffer::maybeAdd(new MissingClosureReturnType('Closure does not have a return type, expecting ' . $inferred_return_type->getId(), new CodeLocation($function_like_analyzer, $function, null, \true)), $suppressed_issues, !$inferred_return_type->hasMixed() && !$inferred_return_type->isNull()); } return null; } if ($codebase->alter_code && isset($project_analyzer->getIssuesToFix()['MissingReturnType']) && !in_array('MissingReturnType', $suppressed_issues)) { if ($inferred_return_type->hasMixed() || $inferred_return_type->isNull()) { return null; } self::addOrUpdateReturnType($function, $project_analyzer, $inferred_return_type, $source, $compatible_method_ids || !$did_explicitly_return || ($project_analyzer->only_replace_php_types_with_non_docblock_types || $unsafe_return_type) && $inferred_return_type->from_docblock, $function_like_storage); return null; } IssueBuffer::maybeAdd(new MissingReturnType('Method ' . $cased_method_id . ' does not have a return type' . (!$inferred_return_type->hasMixed() ? ', expecting ' . $inferred_return_type->getId() : ''), new CodeLocation($function_like_analyzer, $function->name, null, \true)), $suppressed_issues, !$inferred_return_type->hasMixed() && !$inferred_return_type->isNull()); return null; } $self_fq_class_name = $fq_class_name ?: $source->getFQCLN(); $parent_class = null; $classlike_storage = null; if ($self_fq_class_name) { $classlike_storage = $codebase->classlike_storage_provider->get($self_fq_class_name); $parent_class = $classlike_storage->parent_class; } // passing it through fleshOutTypes eradicates errant $ vars $declared_return_type = TypeExpander::expandUnion($codebase, $return_type, $self_fq_class_name, $static_fq_class_name, $parent_class, \true, \true, $function_like_storage instanceof MethodStorage && $function_like_storage->final || $classlike_storage && $classlike_storage->final); if ((!$inferred_return_type_parts || $inferred_return_type->isVoid() && $function_returns_implicitly && count($inferred_return_type_parts) === 1) && !$inferred_return_type->isNever() && !$inferred_yield_types && (!$function_like_storage || !$function_like_storage->has_yield)) { if ($declared_return_type->isVoid() || $declared_return_type->isNever()) { return null; } if (ScopeAnalyzer::onlyThrowsOrExits($type_provider, $function_stmts)) { // if there's a single throw statement, it's presumably an exception saying this method is not to be // used return null; } if ($codebase->alter_code && isset($project_analyzer->getIssuesToFix()['InvalidReturnType']) && !in_array('InvalidReturnType', $suppressed_issues)) { self::addOrUpdateReturnType($function, $project_analyzer, Type::getVoid(), $source, $compatible_method_ids || ($project_analyzer->only_replace_php_types_with_non_docblock_types || $unsafe_return_type) && $inferred_return_type->from_docblock); return null; } if (!$declared_return_type->from_docblock || !$declared_return_type->isNullable()) { if (IssueBuffer::accepts(new InvalidReturnType('No return statements were found for method ' . $cased_method_id . ' but return type \'' . $declared_return_type . '\' was expected', $return_type_location), $suppressed_issues, \true)) { return \false; } } return null; } if (!$declared_return_type->hasMixed()) { if ($inferred_return_type->isVoid() && ($declared_return_type->isVoid() || $function_like_storage && $function_like_storage->has_yield)) { return null; } if ($inferred_return_type->hasMixed()) { if (IssueBuffer::accepts(new MixedInferredReturnType('Could not verify return type \'' . $declared_return_type . '\' for ' . $cased_method_id, $return_type_location), $suppressed_issues)) { return \false; } return null; } $union_comparison_results = new TypeComparisonResult(); if ($declared_return_type->explicit_never === \true && $inferred_return_type_with_never->explicit_never === \false) { if (IssueBuffer::accepts(new MoreSpecificReturnType('The declared return type \'' . $declared_return_type->getId() . '|never\' for ' . $cased_method_id . ' is more specific than the inferred return type ' . '\'' . $inferred_return_type->getId() . '\'', $return_type_location), $suppressed_issues)) { return \false; } } if (!$declared_return_type->isNever() && $function_always_exits && ($declared_return_type->from_docblock || $codebase->analysis_php_version_id >= 81000) && !ScopeAnalyzer::onlyThrows($function_stmts)) { if ($codebase->alter_code && isset($project_analyzer->getIssuesToFix()['InvalidReturnType']) && !in_array('InvalidReturnType', $suppressed_issues)) { self::addOrUpdateReturnType($function, $project_analyzer, Type::getNever(), $source, ($project_analyzer->only_replace_php_types_with_non_docblock_types || $unsafe_return_type) && $inferred_return_type->from_docblock, $function_like_storage); return null; } if (IssueBuffer::accepts(new InvalidReturnType('The declared return type \'' . $declared_return_type->getId() . '\' for ' . $cased_method_id . ' is incorrect, got \'never\'', $return_type_location), $suppressed_issues, \true)) { return \false; } } if (!UnionTypeComparator::isContainedBy($codebase, $inferred_return_type, $declared_return_type, \true, \true, $union_comparison_results)) { // is the declared return type more specific than the inferred one? if ($union_comparison_results->type_coerced) { if ($union_comparison_results->type_coerced_from_mixed) { if (!$union_comparison_results->type_coerced_from_as_mixed) { if (IssueBuffer::accepts(new MixedReturnTypeCoercion('The declared return type \'' . $declared_return_type->getId() . '\' for ' . $cased_method_id . ' is more specific than the inferred return type ' . '\'' . $inferred_return_type->getId() . '\'', $return_type_location), $suppressed_issues)) { return \false; } } } else { if (IssueBuffer::accepts(new MoreSpecificReturnType('The declared return type \'' . $declared_return_type->getId() . '\' for ' . $cased_method_id . ' is more specific than the inferred return type ' . '\'' . $inferred_return_type->getId() . '\'', $return_type_location), $suppressed_issues)) { return \false; } } } elseif (($declared_return_type->explicit_never === \false || !$declared_return_type->isNull()) && (!$declared_return_type->isNullable() || $parent_class === null && $self_fq_class_name === $source->getFQCLN())) { if ($codebase->alter_code && isset($project_analyzer->getIssuesToFix()['InvalidReturnType']) && !in_array('InvalidReturnType', $suppressed_issues)) { self::addOrUpdateReturnType($function, $project_analyzer, $inferred_return_type, $source, ($project_analyzer->only_replace_php_types_with_non_docblock_types || $unsafe_return_type) && $inferred_return_type->from_docblock, $function_like_storage); return null; } if (IssueBuffer::accepts(new InvalidReturnType('The declared return type \'' . $declared_return_type->getId() . '\' for ' . $cased_method_id . ' is incorrect, got \'' . $inferred_return_type->getId() . '\'' . ($union_comparison_results->missing_shape_fields ? ' which is different due to additional array shape fields (' . implode(', ', $union_comparison_results->missing_shape_fields) . ')' : ''), $return_type_location), $suppressed_issues, \true)) { return \false; } } } elseif (!UnionTypeComparator::isContainedBy($codebase, $declared_return_type, $inferred_return_type, \false, \false)) { if ($codebase->alter_code) { if (isset($project_analyzer->getIssuesToFix()['LessSpecificReturnType']) && !in_array('LessSpecificReturnType', $suppressed_issues) && !($function_like_storage instanceof MethodStorage && $function_like_storage->inheritdoc)) { self::addOrUpdateReturnType($function, $project_analyzer, $inferred_return_type, $source, $compatible_method_ids || ($project_analyzer->only_replace_php_types_with_non_docblock_types || $unsafe_return_type) && $inferred_return_type->from_docblock, $function_like_storage); } } else { if ($function instanceof Function_ || $function instanceof Closure || $function instanceof ArrowFunction || $function->isPrivate()) { $check_for_less_specific_type = \true; } elseif ($source instanceof StatementsAnalyzer) { if ($function_like_storage instanceof MethodStorage) { $check_for_less_specific_type = !$function_like_storage->overridden_somewhere; } else { $check_for_less_specific_type = \false; } } else { $check_for_less_specific_type = \false; } if ($check_for_less_specific_type && (Config::getInstance()->restrict_return_types || !$inferred_return_type->isNullable() && $declared_return_type->isNullable() || !$inferred_return_type->isFalsable() && $declared_return_type->isFalsable())) { if (IssueBuffer::accepts(new LessSpecificReturnType('The inferred return type \'' . $inferred_return_type->getId() . '\' for ' . $cased_method_id . ' is more specific than the declared return type \'' . $declared_return_type->getId() . '\'', $return_type_location), $suppressed_issues, !($function_like_storage instanceof MethodStorage && $function_like_storage->inheritdoc))) { return \false; } } } } if ($union_comparison_results->to_string_cast) { IssueBuffer::maybeAdd(new ImplicitToStringCast('The declared return type for ' . $cased_method_id . ' expects \'' . $declared_return_type . '\', ' . '\'' . $inferred_return_type . '\' provided with a __toString method', $return_type_location), $suppressed_issues); } if (!$inferred_return_type->ignore_nullable_issues && $inferred_return_type->isNullable() && !$declared_return_type->isNullable() && !$declared_return_type->hasTemplate() && !$declared_return_type->isVoid()) { if ($codebase->alter_code && isset($project_analyzer->getIssuesToFix()['InvalidNullableReturnType']) && !in_array('InvalidNullableReturnType', $suppressed_issues) && !$inferred_return_type->isNull()) { self::addOrUpdateReturnType($function, $project_analyzer, $inferred_return_type, $source, ($project_analyzer->only_replace_php_types_with_non_docblock_types || $unsafe_return_type) && $inferred_return_type->from_docblock, $function_like_storage); return null; } if (IssueBuffer::accepts(new InvalidNullableReturnType('The declared return type \'' . $declared_return_type . '\' for ' . $cased_method_id . ' is not nullable, but \'' . $inferred_return_type . '\' contains null', $return_type_location), $suppressed_issues, !$inferred_return_type->isNull())) { return \false; } } if (!$inferred_return_type->ignore_falsable_issues && $inferred_return_type->isFalsable() && !$declared_return_type->isFalsable() && !$declared_return_type->hasBool() && !$declared_return_type->hasScalar()) { if ($codebase->alter_code && isset($project_analyzer->getIssuesToFix()['InvalidFalsableReturnType'])) { self::addOrUpdateReturnType($function, $project_analyzer, $inferred_return_type, $source, ($project_analyzer->only_replace_php_types_with_non_docblock_types || $unsafe_return_type) && $inferred_return_type->from_docblock, $function_like_storage); return null; } if (IssueBuffer::accepts(new InvalidFalsableReturnType('The declared return type \'' . $declared_return_type . '\' for ' . $cased_method_id . ' does not allow false, but \'' . $inferred_return_type . '\' contains false', $return_type_location), $suppressed_issues, \true)) { return \false; } } } return null; } /** * @param Closure|Function_|ClassMethod|ArrowFunction $function * @return false|null */ public static function checkReturnType(FunctionLike $function, ProjectAnalyzer $project_analyzer, FunctionLikeAnalyzer $function_like_analyzer, FunctionLikeStorage $storage, Context $context) : ?bool { $codebase = $project_analyzer->getCodebase(); if (!$storage->return_type || !$storage->return_type_location) { return null; } $parent_class = null; $classlike_storage = null; if ($context->self) { $classlike_storage = $codebase->classlike_storage_provider->get($context->self); $parent_class = $classlike_storage->parent_class; } if (!$storage->signature_return_type || $storage->signature_return_type === $storage->return_type) { foreach ($storage->return_type->getAtomicTypes() as $type) { if ($type instanceof TNamedObject && 'parent' === $type->value && null === $parent_class) { if (IssueBuffer::accepts(new InvalidParent('Cannot use parent as a return type when class has no parent', $storage->return_type_location), $storage->suppressed_issues)) { return \false; } return null; } } $fleshed_out_return_type = TypeExpander::expandUnion($codebase, $storage->return_type, $classlike_storage->name ?? null, $classlike_storage->name ?? null, $parent_class); /** @psalm-suppress UnusedMethodCall This call actually has the side effect of creating issues */ $fleshed_out_return_type->check($function_like_analyzer, $storage->return_type_location, $storage->suppressed_issues, [], \false, \false, \false, $context->calling_method_id); return null; } $fleshed_out_signature_type = TypeExpander::expandUnion($codebase, $storage->signature_return_type, $classlike_storage->name ?? null, $classlike_storage->name ?? null, $parent_class); if ($fleshed_out_signature_type->check($function_like_analyzer, $storage->signature_return_type_location ?: $storage->return_type_location, $storage->suppressed_issues, [], \false) === \false) { return \false; } if ($function instanceof Closure || $function instanceof ArrowFunction) { return null; } try { $fleshed_out_return_type = TypeExpander::expandUnion($codebase, $storage->return_type, $classlike_storage->name ?? null, $classlike_storage->name ?? null, $parent_class, \true, \true, \false, \false, \false, \true); } catch (UnresolvableConstantException $e) { IssueBuffer::maybeAdd(new UnresolvableConstant("Could not resolve constant {$e->class_name}::{$e->const_name}", $storage->return_type_location), $storage->suppressed_issues, \true); $fleshed_out_return_type = $storage->return_type; } if ($fleshed_out_return_type->check($function_like_analyzer, $storage->return_type_location, $storage->suppressed_issues, [], \false, $storage instanceof MethodStorage && $storage->inherited_return_type) === \false) { return \false; } if ($classlike_storage && $context->self) { $class_template_params = ClassTemplateParamCollector::collect($codebase, $classlike_storage, $codebase->classlike_storage_provider->get($context->self), strtolower($function->name->name), new TNamedObject($context->self), \true); $class_template_params = $class_template_params ?: []; if ($class_template_params) { $template_result = new TemplateResult($class_template_params, []); $fleshed_out_return_type = TemplateStandinTypeReplacer::replace($fleshed_out_return_type, $template_result, $codebase, null, null, null); } } $union_comparison_result = new TypeComparisonResult(); if (!UnionTypeComparator::isContainedBy($codebase, $fleshed_out_return_type, $fleshed_out_signature_type, \false, \false, $union_comparison_result) && !$union_comparison_result->type_coerced_from_mixed) { if ($codebase->alter_code && isset($project_analyzer->getIssuesToFix()['MismatchingDocblockReturnType'])) { self::addOrUpdateReturnType($function, $project_analyzer, $storage->signature_return_type, $function_like_analyzer->getSource()); return null; } if (IssueBuffer::accepts(new MismatchingDocblockReturnType('Docblock has incorrect return type \'' . $storage->return_type->getId() . '\', should be \'' . $storage->signature_return_type->getId() . '\'', $storage->return_type_location), $storage->suppressed_issues, \true)) { return \false; } } return null; } /** * @param Closure|Function_|ClassMethod|ArrowFunction $function */ private static function addOrUpdateReturnType(FunctionLike $function, ProjectAnalyzer $project_analyzer, Union $inferred_return_type, StatementsSource $source, bool $docblock_only = \false, ?FunctionLikeStorage $function_like_storage = null) : void { $manipulator = FunctionDocblockManipulator::getForFunction($project_analyzer, $source->getFilePath(), $function); $codebase = $project_analyzer->getCodebase(); $is_final = \true; $fqcln = $source->getFQCLN(); if ($fqcln !== null && $function instanceof ClassMethod) { $class_storage = $codebase->classlike_storage_provider->get($fqcln); $is_final = $function->isFinal() || $class_storage->final; } $allow_native_type = !$docblock_only && $codebase->analysis_php_version_id >= 70000 && ($codebase->allow_backwards_incompatible_changes || $is_final || !$function instanceof PhpParser\Node\Stmt\ClassMethod); $manipulator->setReturnType($allow_native_type ? (string) $inferred_return_type->toPhpString($source->getNamespace(), $source->getAliasedClassesFlipped(), $source->getFQCLN(), $codebase->analysis_php_version_id) : null, $inferred_return_type->toNamespacedString($source->getNamespace(), $source->getAliasedClassesFlipped(), $source->getFQCLN(), \false), $inferred_return_type->toNamespacedString($source->getNamespace(), $source->getAliasedClassesFlipped(), $source->getFQCLN(), \true), $inferred_return_type->canBeFullyExpressedInPhp($codebase->analysis_php_version_id), $function_like_storage->return_type_description ?? null); } } $stmts * @param list $yield_types * @return list a list of return types * @psalm-suppress ComplexMethod to be refactored */ public static function getReturnTypes(Codebase $codebase, NodeDataProvider $nodes, array $stmts, array &$yield_types, bool $collapse_types = \false) : array { $return_types = []; foreach ($stmts as $stmt) { if ($stmt instanceof PhpParser\Node\Stmt\Return_) { if (!$stmt->expr) { $return_types[] = Type::getVoid(); } elseif ($stmt_type = $nodes->getType($stmt)) { $return_types[] = $stmt_type; $yield_types = array_merge($yield_types, self::getYieldTypeFromExpression($stmt->expr, $nodes)); } elseif ($stmt->expr instanceof PhpParser\Node\Scalar\String_) { $return_types[] = Type::getString(); } elseif ($stmt->expr instanceof PhpParser\Node\Scalar\LNumber) { $return_types[] = Type::getInt(); } elseif ($stmt->expr instanceof PhpParser\Node\Expr\ConstFetch) { if ((string) $stmt->expr->name === 'true') { $return_types[] = Type::getTrue(); } elseif ((string) $stmt->expr->name === 'false') { $return_types[] = Type::getFalse(); } elseif ((string) $stmt->expr->name === 'null') { $return_types[] = Type::getNull(); } } else { $return_types[] = Type::getMixed(); } break; } if ($stmt instanceof PhpParser\Node\Stmt\Break_ || $stmt instanceof PhpParser\Node\Stmt\Continue_) { break; } if ($stmt instanceof PhpParser\Node\Stmt\Throw_) { $return_types[] = Type::getNever(); break; } if ($stmt instanceof PhpParser\Node\Stmt\Expression) { if ($stmt->expr instanceof PhpParser\Node\Expr\Exit_) { $return_types[] = Type::getNever(); break; } if ($stmt->expr instanceof PhpParser\Node\Expr\FuncCall || $stmt->expr instanceof PhpParser\Node\Expr\MethodCall || $stmt->expr instanceof PhpParser\Node\Expr\NullsafeMethodCall || $stmt->expr instanceof PhpParser\Node\Expr\StaticCall) { $stmt_type = $nodes->getType($stmt->expr); if ($stmt_type && ($stmt_type->isNever() || $stmt_type->explicit_never)) { $return_types[] = Type::getNever(); break; } } if ($stmt->expr instanceof PhpParser\Node\Expr\Assign) { $return_types = [...$return_types, ...self::getReturnTypes($codebase, $nodes, [$stmt->expr->expr], $yield_types)]; } $yield_types = array_merge($yield_types, self::getYieldTypeFromExpression($stmt->expr, $nodes)); } elseif ($stmt instanceof PhpParser\Node\Stmt\If_) { $return_types = [...$return_types, ...self::getReturnTypes($codebase, $nodes, $stmt->stmts, $yield_types)]; foreach ($stmt->elseifs as $elseif) { $return_types = [...$return_types, ...self::getReturnTypes($codebase, $nodes, $elseif->stmts, $yield_types)]; } if ($stmt->else) { $return_types = [...$return_types, ...self::getReturnTypes($codebase, $nodes, $stmt->else->stmts, $yield_types)]; } } elseif ($stmt instanceof PhpParser\Node\Stmt\TryCatch) { $return_types = [...$return_types, ...self::getReturnTypes($codebase, $nodes, $stmt->stmts, $yield_types)]; foreach ($stmt->catches as $catch) { $return_types = [...$return_types, ...self::getReturnTypes($codebase, $nodes, $catch->stmts, $yield_types)]; } if ($stmt->finally) { $return_types = [...$return_types, ...self::getReturnTypes($codebase, $nodes, $stmt->finally->stmts, $yield_types)]; } } elseif ($stmt instanceof PhpParser\Node\Stmt\For_) { $return_types = [...$return_types, ...self::getReturnTypes($codebase, $nodes, $stmt->stmts, $yield_types)]; } elseif ($stmt instanceof PhpParser\Node\Stmt\Foreach_) { $return_types = [...$return_types, ...self::getReturnTypes($codebase, $nodes, $stmt->stmts, $yield_types)]; } elseif ($stmt instanceof PhpParser\Node\Stmt\While_) { $yield_types = array_merge($yield_types, self::getYieldTypeFromExpression($stmt->cond, $nodes)); $return_types = [...$return_types, ...self::getReturnTypes($codebase, $nodes, $stmt->stmts, $yield_types)]; } elseif ($stmt instanceof PhpParser\Node\Stmt\Do_) { $return_types = [...$return_types, ...self::getReturnTypes($codebase, $nodes, $stmt->stmts, $yield_types)]; } elseif ($stmt instanceof PhpParser\Node\Stmt\Switch_) { foreach ($stmt->cases as $case) { $return_types = [...$return_types, ...self::getReturnTypes($codebase, $nodes, $case->stmts, $yield_types)]; } } } // if we're at the top level and we're not ending in a return, make sure to add possible null if ($collapse_types) { // if it's a generator, boil everything down to a single generator return type if ($yield_types) { $yield_types = self::processYieldTypes($codebase, $return_types, $yield_types); } } return $return_types; } /** * @param list $return_types * @param non-empty-list $yield_types * @return non-empty-list */ private static function processYieldTypes(Codebase $codebase, array $return_types, array $yield_types) : array { $key_type = null; $value_type = null; $yield_type = Type::combineUnionTypeArray($yield_types, null); foreach ($yield_type->getAtomicTypes() as $type) { if ($type instanceof TList) { $type = $type->getKeyedArray(); } if ($type instanceof TKeyedArray) { $type = $type->getGenericArrayType(); } if ($type instanceof TArray) { [$key_type_param, $value_type_param] = $type->type_params; $key_type = Type::combineUnionTypes($key_type_param, $key_type); $value_type = Type::combineUnionTypes($value_type_param, $value_type); } elseif ($type instanceof TIterable || $type instanceof TNamedObject) { ForeachAnalyzer::getKeyValueParamsForTraversableObject($type, $codebase, $key_type, $value_type); } } return [new Union([new TGenericObject('Generator', [$key_type ?? Type::getMixed(), $value_type ?? Type::getMixed(), Type::getMixed(), $return_types ? Type::combineUnionTypeArray($return_types, null) : Type::getVoid()])])]; } /** * @return list */ private static function getYieldTypeFromExpression(PhpParser\Node\Expr $stmt, NodeDataProvider $nodes) : array { $collector = new YieldTypeCollector($nodes); $traverser = new NodeTraverser(); $traverser->addVisitor($collector); $traverser->traverse([$stmt]); return $collector->getYieldTypes(); } } declares as $declaration) { $declaration_key = (string) $declaration->key; if ($declaration_key === 'strict_types') { if ($stmt->stmts !== null) { IssueBuffer::maybeAdd(new UnrecognizedStatement('strict_types declaration must not use block mode', new CodeLocation($statements_analyzer, $stmt)), $statements_analyzer->getSuppressedIssues()); } self::analyzeStrictTypesDeclaration($statements_analyzer, $declaration, $context); } elseif ($declaration_key === 'ticks') { self::analyzeTicksDeclaration($statements_analyzer, $declaration); } elseif ($declaration_key === 'encoding') { self::analyzeEncodingDeclaration($statements_analyzer, $declaration); } else { IssueBuffer::maybeAdd(new UnrecognizedStatement('Psalm does not understand the declare statement ' . $declaration->key, new CodeLocation($statements_analyzer, $declaration)), $statements_analyzer->getSuppressedIssues()); } } } private static function analyzeStrictTypesDeclaration(StatementsAnalyzer $statements_analyzer, PhpParser\Node\Stmt\DeclareDeclare $declaration, Context $context) : void { if (!$declaration->value instanceof PhpParser\Node\Scalar\LNumber || !in_array($declaration->value->value, [0, 1], \true)) { IssueBuffer::maybeAdd(new UnrecognizedStatement('strict_types declaration can only have 1 or 0 as a value', new CodeLocation($statements_analyzer, $declaration)), $statements_analyzer->getSuppressedIssues()); return; } if ($declaration->value->value === 1) { $context->strict_types = \true; } } private static function analyzeTicksDeclaration(StatementsAnalyzer $statements_analyzer, PhpParser\Node\Stmt\DeclareDeclare $declaration) : void { if (!$declaration->value instanceof PhpParser\Node\Scalar\LNumber) { IssueBuffer::maybeAdd(new UnrecognizedStatement('ticks declaration should have integer as a value', new CodeLocation($statements_analyzer, $declaration)), $statements_analyzer->getSuppressedIssues()); } } private static function analyzeEncodingDeclaration(StatementsAnalyzer $statements_analyzer, PhpParser\Node\Stmt\DeclareDeclare $declaration) : void { if (!$declaration->value instanceof PhpParser\Node\Scalar\String_) { IssueBuffer::maybeAdd(new UnrecognizedStatement('encoding declaration should have string as a value', new CodeLocation($statements_analyzer, $declaration)), $statements_analyzer->getSuppressedIssues()); } } } inside_unset = \true; foreach ($stmt->vars as $var) { $was_inside_general_use = $context->inside_general_use; $context->inside_general_use = \true; \Psalm\Internal\Analyzer\Statements\ExpressionAnalyzer::analyze($statements_analyzer, $var, $context); $context->inside_general_use = $was_inside_general_use; $var_id = ExpressionIdentifier::getExtendedVarId($var, $statements_analyzer->getFQCLN(), $statements_analyzer); if ($var_id) { $context->remove($var_id); unset($context->references_possibly_from_confusing_scope[$var_id]); } if ($var instanceof PhpParser\Node\Expr\ArrayDimFetch && $var->dim) { $root_var_id = ExpressionIdentifier::getExtendedVarId($var->var, $statements_analyzer->getFQCLN(), $statements_analyzer); $key_type = $statements_analyzer->node_data->getType($var->dim); if ($root_var_id && isset($context->vars_in_scope[$root_var_id]) && $key_type) { $root_types = []; foreach ($context->vars_in_scope[$root_var_id]->getAtomicTypes() as $atomic_root_type) { if ($atomic_root_type instanceof TList) { $atomic_root_type = $atomic_root_type->getKeyedArray(); } if ($atomic_root_type instanceof TKeyedArray) { $key_value = null; if ($key_type->isSingleIntLiteral()) { $key_value = $key_type->getSingleIntLiteral()->value; } elseif ($key_type->isSingleStringLiteral()) { $key_value = $key_type->getSingleStringLiteral()->value; } if ($key_value !== null) { $properties = $atomic_root_type->properties; $is_list = $atomic_root_type->is_list; $list_key = null; if ($atomic_root_type->fallback_params) { $is_list = \false; } elseif (isset($properties[$key_value])) { if ($is_list && $key_value !== count($properties) - 1) { $is_list = \false; } } unset($properties[$key_value]); if ($atomic_root_type->is_list && !$is_list && is_int($key_value)) { if ($key_value === 0) { $list_key = Type::getIntRange(1, null); } elseif ($key_value === 1) { $list_key = new Union([new TLiteralInt(0), new TIntRange(2, null)]); } else { $list_key = new Union([new TIntRange(0, $key_value - 1), new TIntRange($key_value + 1, null)]); } } if (!$properties) { if ($atomic_root_type->fallback_params) { $root_types[] = new TArray([$list_key ?? $atomic_root_type->fallback_params[0], $atomic_root_type->fallback_params[1]]); } else { $root_types[] = new TArray([new Union([new TNever()]), new Union([new TNever()])]); } } else { $root_types[] = new TKeyedArray($properties, null, $atomic_root_type->fallback_params ? [$list_key ?? $atomic_root_type->fallback_params[0], $atomic_root_type->fallback_params[1]] : null, $is_list); } } else { $properties = []; foreach ($atomic_root_type->properties as $key => $type) { $properties[$key] = $type->setPossiblyUndefined(\true); } $root_types[] = new TKeyedArray($properties, null, $atomic_root_type->fallback_params, \false); } } elseif ($atomic_root_type instanceof TNonEmptyArray) { $root_types[] = new TArray($atomic_root_type->type_params); } elseif ($atomic_root_type instanceof TNonEmptyMixed) { $root_types[] = new TMixed(); } else { $root_types[] = $atomic_root_type; } } $context->vars_in_scope[$root_var_id] = new Union($root_types); $context->removeVarFromConflictingClauses($root_var_id, $context->vars_in_scope[$root_var_id], $statements_analyzer); } } } $context->inside_unset = \false; } } num instanceof PhpParser\Node\Scalar\LNumber ? $stmt->num->value : 1; $loop_scope = $context->loop_scope; if ($count === 2 && isset($loop_scope->loop_parent_context->loop_scope)) { $loop_scope = $loop_scope->loop_parent_context->loop_scope; } if ($count === 3 && isset($loop_scope->loop_parent_context->loop_scope)) { $loop_scope = $loop_scope->loop_parent_context->loop_scope; } if ($loop_scope === null) { if (!$context->break_types) { if (IssueBuffer::accepts(new ContinueOutsideLoop('Continue call outside loop context', new CodeLocation($statements_analyzer, $stmt)), $statements_analyzer->getSource()->getSuppressedIssues())) { return; } } } else { if ($context->break_types && end($context->break_types) === 'switch' && $count < 2) { $loop_scope->final_actions[] = ScopeAnalyzer::ACTION_LEAVE_SWITCH; } else { $loop_scope->final_actions[] = ScopeAnalyzer::ACTION_CONTINUE; } $redefined_vars = $context->getRedefinedVars($loop_scope->loop_parent_context->vars_in_scope); foreach ($loop_scope->redefined_loop_vars as $redefined_var => $type) { if (!isset($redefined_vars[$redefined_var])) { unset($loop_scope->redefined_loop_vars[$redefined_var]); } else { $loop_scope->redefined_loop_vars[$redefined_var] = Type::combineUnionTypes($redefined_vars[$redefined_var], $type); } } foreach ($redefined_vars as $var => $type) { $loop_scope->possibly_redefined_loop_vars[$var] = Type::combineUnionTypes($type, $loop_scope->possibly_redefined_loop_vars[$var] ?? null); } if ($context->finally_scope) { foreach ($context->vars_in_scope as $var_id => &$type) { if (isset($context->finally_scope->vars_in_scope[$var_id])) { $context->finally_scope->vars_in_scope[$var_id] = Type::combineUnionTypes($context->finally_scope->vars_in_scope[$var_id], $type, $statements_analyzer->getCodebase()); } else { $type = $type->setPossiblyUndefined(\true, \true); $context->finally_scope->vars_in_scope[$var_id] = $type; } } } } $context->has_returned = \true; } } getDocComment(); $var_comments = []; $var_comment_type = null; $source = $statements_analyzer->getSource(); $codebase = $statements_analyzer->getCodebase(); if ($doc_comment && ($parsed_docblock = $statements_analyzer->getParsedDocblock())) { $file_storage_provider = $codebase->file_storage_provider; $file_storage = $file_storage_provider->get($statements_analyzer->getFilePath()); try { $var_comments = $codebase->config->disable_var_parsing ? [] : CommentAnalyzer::arrayToDocblocks($doc_comment, $parsed_docblock, $statements_analyzer->getSource(), $statements_analyzer->getAliases(), $statements_analyzer->getTemplateTypeMap(), $file_storage->type_aliases); } catch (DocblockParseException $e) { IssueBuffer::maybeAdd(new InvalidDocblock($e->getMessage(), new CodeLocation($source, $stmt))); } foreach ($var_comments as $var_comment) { if (!$var_comment->type) { continue; } $comment_type = TypeExpander::expandUnion($codebase, $var_comment->type, $context->self, $context->self, $statements_analyzer->getParentFQCLN()); if ($codebase->alter_code && $var_comment->type_start && $var_comment->type_end && $var_comment->line_number) { $type_location = new DocblockTypeLocation($statements_analyzer, $var_comment->type_start, $var_comment->type_end, $var_comment->line_number); $codebase->classlikes->handleDocblockTypeInMigration($codebase, $statements_analyzer, $comment_type, $type_location, $context->calling_method_id); } if (!$var_comment->var_id) { $var_comment_type = $comment_type; continue; } if (isset($context->vars_in_scope[$var_comment->var_id])) { $comment_type = $comment_type->setParentNodes($context->vars_in_scope[$var_comment->var_id]->parent_nodes); } $context->vars_in_scope[$var_comment->var_id] = $comment_type; } } if ($stmt->expr) { $context->inside_return = \true; if ($stmt->expr instanceof PhpParser\Node\Expr\Closure || $stmt->expr instanceof PhpParser\Node\Expr\ArrowFunction) { self::potentiallyInferTypesOnClosureFromParentReturnType($statements_analyzer, $stmt->expr, $context); } if (\Psalm\Internal\Analyzer\Statements\ExpressionAnalyzer::analyze($statements_analyzer, $stmt->expr, $context) === \false) { $context->inside_return = \false; $context->has_returned = \true; return; } $stmt_expr_type = $statements_analyzer->node_data->getType($stmt->expr); if ($var_comment_type) { $stmt_type = $var_comment_type; if ($stmt_expr_type && $stmt_expr_type->parent_nodes) { $stmt_type = $stmt_type->setParentNodes($stmt_expr_type->parent_nodes); } $statements_analyzer->node_data->setType($stmt, $var_comment_type); } elseif ($stmt_expr_type) { $stmt_type = $stmt_expr_type; if ($stmt_type->isNever()) { IssueBuffer::maybeAdd(new NoValue('All possible types for this return were invalidated - This may be dead code', new CodeLocation($source, $stmt)), $statements_analyzer->getSuppressedIssues()); $stmt_type = Type::getNever(); } if ($stmt_type->isVoid()) { $stmt_type = Type::getNull(); } } else { $stmt_type = Type::getMixed(); } $context->inside_return = \false; } else { $stmt_type = Type::getVoid(); } $statements_analyzer->node_data->setType($stmt, $stmt_type); if ($context->finally_scope) { foreach ($context->vars_in_scope as $var_id => &$type) { if (isset($context->finally_scope->vars_in_scope[$var_id])) { $context->finally_scope->vars_in_scope[$var_id] = Type::combineUnionTypes($context->finally_scope->vars_in_scope[$var_id], $type, $statements_analyzer->getCodebase()); } else { $type = $type->setPossiblyUndefined(\true, \true); $context->finally_scope->vars_in_scope[$var_id] = $type; } } } $context->has_returned = \true; if ($source instanceof FunctionLikeAnalyzer && !$source->getSource() instanceof TraitAnalyzer) { $source->addReturnTypes($context); $source->examineParamTypes($statements_analyzer, $context, $codebase, $stmt); $storage = $source->getFunctionLikeStorage($statements_analyzer); $cased_method_id = $source->getCorrectlyCasedMethodId(); if ($stmt->expr && $storage->location) { $inferred_type = TypeExpander::expandUnion($codebase, $stmt_type, $source->getFQCLN(), $source->getFQCLN(), $source->getParentFQCLN()); if ($statements_analyzer->data_flow_graph instanceof TaintFlowGraph) { self::handleTaints($statements_analyzer, $stmt, $cased_method_id, $inferred_type, $storage); } if ($storage instanceof MethodStorage && $context->self) { $self_class = $context->self; $declared_return_type = $codebase->methods->getMethodReturnType(MethodIdentifier::wrap($cased_method_id), $self_class, $statements_analyzer, null); [, $method_name] = explode('::', $cased_method_id); if ($method_name === '__construct') { IssueBuffer::maybeAdd(new InvalidReturnStatement('No return values are expected for ' . $cased_method_id, new CodeLocation($source, $stmt->expr)), $statements_analyzer->getSuppressedIssues()); return; } } else { $declared_return_type = $storage->return_type; } if ($declared_return_type && !$declared_return_type->hasMixed()) { $local_return_type = $source->getLocalReturnType($declared_return_type, $storage instanceof MethodStorage && $storage->final); if ($storage instanceof MethodStorage) { [$fq_class_name, $method_name] = explode('::', $cased_method_id); $class_storage = $codebase->classlike_storage_provider->get($fq_class_name); $found_generic_params = ClassTemplateParamCollector::collect($codebase, $class_storage, $class_storage, strtolower($method_name), null, \true); if ($found_generic_params) { foreach ($found_generic_params as $template_name => $_) { unset($found_generic_params[$template_name][$fq_class_name]); } $local_return_type = TemplateInferredTypeReplacer::replace($local_return_type, new TemplateResult([], $found_generic_params), $codebase); } } if ($local_return_type->isGenerator() && $storage->has_yield) { return; } if ($stmt_type->hasMixed()) { if ($local_return_type->isVoid() || $local_return_type->isNever()) { if (IssueBuffer::accepts(new InvalidReturnStatement('No return values are expected for ' . $cased_method_id, new CodeLocation($source, $stmt->expr)), $statements_analyzer->getSuppressedIssues())) { return; } } if (!$context->collect_initializations && !$context->collect_mutations && $statements_analyzer->getFilePath() === $statements_analyzer->getRootFilePath() && !$source->getSource() instanceof TraitAnalyzer) { $codebase->analyzer->incrementMixedCount($statements_analyzer->getFilePath()); } if ($stmt_type->isMixed()) { $origin_locations = []; if ($statements_analyzer->data_flow_graph instanceof VariableUseGraph) { foreach ($stmt_type->parent_nodes as $parent_node) { $origin_locations = [...$origin_locations, ...$statements_analyzer->data_flow_graph->getOriginLocations($parent_node)]; } } $origin_location = count($origin_locations) === 1 ? reset($origin_locations) : null; $return_location = new CodeLocation($source, $stmt->expr); if ($origin_location && $origin_location->getHash() === $return_location->getHash()) { $origin_location = null; } IssueBuffer::maybeAdd(new MixedReturnStatement('Could not infer a return type', $return_location, $origin_location), $statements_analyzer->getSuppressedIssues()); return; } IssueBuffer::maybeAdd(new MixedReturnStatement('Possibly-mixed return value', new CodeLocation($source, $stmt->expr)), $statements_analyzer->getSuppressedIssues()); } if ($local_return_type->isMixed()) { return; } if (!$context->collect_initializations && !$context->collect_mutations && $statements_analyzer->getFilePath() === $statements_analyzer->getRootFilePath() && !$source->getSource() instanceof TraitAnalyzer) { $codebase->analyzer->incrementNonMixedCount($statements_analyzer->getFilePath()); } if ($local_return_type->isVoid()) { IssueBuffer::maybeAdd(new InvalidReturnStatement('No return values are expected for ' . $cased_method_id, new CodeLocation($source, $stmt->expr)), $statements_analyzer->getSuppressedIssues()); return; } $union_comparison_results = new TypeComparisonResult(); if (!UnionTypeComparator::isContainedBy($codebase, $inferred_type, $local_return_type, \true, \true, $union_comparison_results)) { // is the declared return type more specific than the inferred one? if ($union_comparison_results->type_coerced) { if ($union_comparison_results->type_coerced_from_mixed) { if (!$union_comparison_results->type_coerced_from_as_mixed) { if ($inferred_type->hasMixed()) { IssueBuffer::maybeAdd(new MixedReturnStatement('Could not infer a return type', new CodeLocation($source, $stmt->expr)), $statements_analyzer->getSuppressedIssues()); } else { IssueBuffer::maybeAdd(new MixedReturnTypeCoercion('The type \'' . $stmt_type->getId() . '\' is more general than the' . ' declared return type \'' . $local_return_type->getId() . '\'' . ' for ' . $cased_method_id, new CodeLocation($source, $stmt->expr)), $statements_analyzer->getSuppressedIssues()); } } } else { IssueBuffer::maybeAdd(new LessSpecificReturnStatement('The type \'' . $stmt_type->getId() . '\' is more general than the' . ' declared return type \'' . $local_return_type->getId() . '\'' . ' for ' . $cased_method_id, new CodeLocation($source, $stmt->expr)), $statements_analyzer->getSuppressedIssues()); } foreach ($local_return_type->getAtomicTypes() as $local_type_part) { if ($local_type_part instanceof TClassString && $stmt->expr instanceof PhpParser\Node\Scalar\String_) { if (ClassLikeAnalyzer::checkFullyQualifiedClassLikeName($statements_analyzer, $stmt->expr->value, new CodeLocation($source, $stmt->expr), $context->self, $context->calling_method_id, $statements_analyzer->getSuppressedIssues(), new ClassLikeNameOptions(\true)) === \false) { return; } } elseif ($local_type_part instanceof TArray && $stmt->expr instanceof PhpParser\Node\Expr\Array_) { $value_param = $local_type_part->type_params[1]; foreach ($value_param->getAtomicTypes() as $local_array_type_part) { if ($local_array_type_part instanceof TClassString) { foreach ($stmt->expr->items as $item) { if ($item && $item->value instanceof PhpParser\Node\Scalar\String_) { if (ClassLikeAnalyzer::checkFullyQualifiedClassLikeName($statements_analyzer, $item->value->value, new CodeLocation($source, $item->value), $context->self, $context->calling_method_id, $statements_analyzer->getSuppressedIssues(), new ClassLikeNameOptions(\true)) === \false) { return; } } } } } } } } else { IssueBuffer::maybeAdd(new InvalidReturnStatement('The inferred type \'' . $inferred_type->getId() . '\' does not match the declared return ' . 'type \'' . $local_return_type->getId() . '\' for ' . $cased_method_id . ($union_comparison_results->missing_shape_fields ? ' due to additional array shape fields (' . implode(', ', $union_comparison_results->missing_shape_fields) . ')' : ''), new CodeLocation($source, $stmt->expr)), $statements_analyzer->getSuppressedIssues()); } } if (!$stmt_type->ignore_nullable_issues && $inferred_type->isNullable() && !$local_return_type->isNullable() && !$local_return_type->hasTemplate()) { IssueBuffer::maybeAdd(new NullableReturnStatement('The declared return type \'' . $local_return_type->getId() . '\' for ' . $cased_method_id . ' is not nullable, but the function returns \'' . $inferred_type->getId() . '\'', new CodeLocation($source, $stmt->expr)), $statements_analyzer->getSuppressedIssues()); } if (!$stmt_type->ignore_falsable_issues && $inferred_type->isFalsable() && !$local_return_type->isFalsable() && (!$local_return_type->hasBool() || $local_return_type->isTrue()) && !$local_return_type->hasScalar()) { IssueBuffer::maybeAdd(new FalsableReturnStatement('The declared return type \'' . $local_return_type . '\' for ' . $cased_method_id . ' does not allow false, but the function returns \'' . $inferred_type . '\'', new CodeLocation($source, $stmt->expr)), $statements_analyzer->getSuppressedIssues()); } } } else { if ($storage->signature_return_type && !$storage->signature_return_type->isVoid() && !$storage->has_yield) { IssueBuffer::maybeAdd(new InvalidReturnStatement('Empty return statement is not expected in ' . $cased_method_id, new CodeLocation($source, $stmt)), $statements_analyzer->getSuppressedIssues()); } } } } private static function handleTaints(StatementsAnalyzer $statements_analyzer, PhpParser\Node\Stmt\Return_ $stmt, string $cased_method_id, Union $inferred_type, FunctionLikeStorage $storage) : void { if (!$statements_analyzer->data_flow_graph instanceof TaintFlowGraph || !$stmt->expr || !$storage->location) { return; } $method_node = DataFlowNode::getForMethodReturn(strtolower($cased_method_id), $cased_method_id, $storage->signature_return_type_location ?: $storage->location); $statements_analyzer->data_flow_graph->addNode($method_node); if ($inferred_type->parent_nodes) { foreach ($inferred_type->parent_nodes as $parent_node) { $statements_analyzer->data_flow_graph->addPath($parent_node, $method_node, 'return', $storage->added_taints, $storage->removed_taints); } } } /** * If a function returns a closure, we try to infer the param/return types of * the inner closure. * * @see \Psalm\Tests\ReturnTypeTest:756 * @param PhpParser\Node\Expr\Closure|PhpParser\Node\Expr\ArrowFunction $expr */ private static function potentiallyInferTypesOnClosureFromParentReturnType(StatementsAnalyzer $statements_analyzer, PhpParser\Node\FunctionLike $expr, Context $context) : void { // if not returning from inside of a function, return if (!$context->calling_method_id && !$context->calling_function_id) { return; } $closure_id = (new ClosureAnalyzer($expr, $statements_analyzer))->getClosureId(); $closure_storage = $statements_analyzer->getCodebase()->getFunctionLikeStorage($statements_analyzer, $closure_id); $parent_fn_storage = $statements_analyzer->getCodebase()->getFunctionLikeStorage($statements_analyzer, $context->calling_function_id ?: $context->calling_method_id); if ($parent_fn_storage->return_type === null) { return; } // can't infer returned closure if the parent doesn't have a callable return type if (!$parent_fn_storage->return_type->hasCallableType()) { return; } // cannot infer if we have union/intersection types if (!$parent_fn_storage->return_type->isSingle()) { return; } /** @var TClosure|TCallable $parent_callable_return_type */ $parent_callable_return_type = $parent_fn_storage->return_type->getSingleAtomic(); if ($parent_callable_return_type->params === null && $parent_callable_return_type->return_type === null) { return; } foreach ($closure_storage->params as $key => $param) { $parent_param = $parent_callable_return_type->params[$key] ?? null; $param->type = self::inferInnerClosureTypeFromParent($statements_analyzer->getCodebase(), $param->type, $parent_param->type ?? null); } $closure_storage->return_type = self::inferInnerClosureTypeFromParent($statements_analyzer->getCodebase(), $closure_storage->return_type, $parent_callable_return_type->return_type); } /** * - If non parent type, do nothing * - If no return type, infer from parent * - If parent return type is more specific, infer from parent * - else, do nothing */ private static function inferInnerClosureTypeFromParent(Codebase $codebase, ?Union $return_type, ?Union $parent_return_type) : ?Union { if (!$parent_return_type) { return $return_type; } if (!$return_type || UnionTypeComparator::isContainedBy($codebase, $parent_return_type, $return_type)) { return $parent_return_type; } return $return_type; } } */ private array $removed_unref_vars = []; /** * @param array $stmts * @param array $var_loc_map */ public function findUnusedAssignment(Codebase $codebase, array $stmts, array $var_loc_map, string $var_id, CodeLocation $original_location) : void { $search_result = $this->findAssignStmt($stmts, $var_id, $original_location); [$assign_stmt, $assign_exp] = $search_result; $chain_assignment = \false; if ($assign_stmt !== null && $assign_exp !== null) { // Check if we have to remove assignment statement as expression (i.e. just "$var = ") // Consider chain of assignments $rhs_exp = $assign_exp->expr; if ($rhs_exp instanceof PhpParser\Node\Expr\Assign || $rhs_exp instanceof PhpParser\Node\Expr\AssignOp || $rhs_exp instanceof PhpParser\Node\Expr\AssignRef) { $chain_assignment = \true; $removable_stmt = $this->checkRemovableChainAssignment($assign_exp, $var_loc_map); } else { $removable_stmt = \true; } if ($removable_stmt) { $traverser = new PhpParser\NodeTraverser(); $visitor = new CheckTrivialExprVisitor(); $traverser->addVisitor($visitor); $traverser->traverse([$rhs_exp]); $rhs_exp_trivial = !$visitor->hasNonTrivialExpr(); if ($rhs_exp_trivial) { $treat_as_expr = \false; } else { $treat_as_expr = \true; } } else { $treat_as_expr = \true; } if ($treat_as_expr) { $is_assign_ref = $assign_exp instanceof PhpParser\Node\Expr\AssignRef; $new_file_manipulation = self::getPartialRemovalBounds($codebase, $original_location, $assign_stmt->getEndFilePos(), $is_assign_ref); $this->removed_unref_vars[$var_id] = $original_location; } else { // Remove whole assignment statement $new_file_manipulation = new FileManipulation($assign_stmt->getStartFilePos(), $assign_stmt->getEndFilePos() + 1, "", \false, \true); // If statement we are removing is a chain of assignments, mark other variables as removed if ($chain_assignment) { $this->markRemovedChainAssignVar($assign_exp, $var_loc_map); } else { $this->removed_unref_vars[$var_id] = $original_location; } } FileManipulationBuffer::add($original_location->file_path, [$new_file_manipulation]); } elseif ($assign_exp !== null) { $is_assign_ref = $assign_exp instanceof PhpParser\Node\Expr\AssignRef; $new_file_manipulation = self::getPartialRemovalBounds($codebase, $original_location, $assign_exp->getEndFilePos(), $is_assign_ref); FileManipulationBuffer::add($original_location->file_path, [$new_file_manipulation]); $this->removed_unref_vars[$var_id] = $original_location; } } private static function getPartialRemovalBounds(Codebase $codebase, CodeLocation $var_loc, int $end_bound, bool $assign_ref = \false) : FileManipulation { $var_start_loc = $var_loc->raw_file_start; $stmt_content = $codebase->file_provider->getContents($var_loc->file_path); $str_for_token = " $var_loc_map */ private function markRemovedChainAssignVar(PhpParser\Node\Expr $cur_assign, array $var_loc_map) : void { $var = $cur_assign->var; if ($var instanceof PhpParser\Node\Expr\Variable && is_string($var->name)) { $var_name = "\$" . $var->name; $var_loc = $var_loc_map[$var_name]; $this->removed_unref_vars[$var_name] = $var_loc; $rhs_exp = $cur_assign->expr; if ($rhs_exp instanceof PhpParser\Node\Expr\Assign || $rhs_exp instanceof PhpParser\Node\Expr\AssignOp || $rhs_exp instanceof PhpParser\Node\Expr\AssignRef) { $this->markRemovedChainAssignVar($rhs_exp, $var_loc_map); } } } /** * @param PhpParser\Node\Expr\Assign|PhpParser\Node\Expr\AssignOp|PhpParser\Node\Expr\AssignRef $cur_assign * @param array $var_loc_map */ private function checkRemovableChainAssignment(PhpParser\Node\Expr $cur_assign, array $var_loc_map) : bool { // Check if current assignment expr's variable is removable $var = $cur_assign->var; if ($var instanceof PhpParser\Node\Expr\Variable && is_string($var->name)) { $var_loc = $cur_assign->var->getStartFilePos(); $var_name = "\$" . $var->name; if (array_key_exists($var_name, $var_loc_map) && $var_loc_map[$var_name]->raw_file_start === $var_loc) { $curr_removable = \true; } else { $curr_removable = \false; } if ($curr_removable) { $rhs_exp = $cur_assign->expr; if ($rhs_exp instanceof PhpParser\Node\Expr\Assign || $rhs_exp instanceof PhpParser\Node\Expr\AssignOp || $rhs_exp instanceof PhpParser\Node\Expr\AssignRef) { return $this->checkRemovableChainAssignment($rhs_exp, $var_loc_map); } } return $curr_removable; } return \false; } /** * @param array $stmts * @return array{ * 0: PhpParser\Node\Stmt|null, * 1: PhpParser\Node\Expr\Assign|PhpParser\Node\Expr\AssignOp|PhpParser\Node\Expr\AssignRef|null * } */ private function findAssignStmt(array $stmts, string $var_id, CodeLocation $original_location) : array { $assign_stmt = null; $assign_exp = null; $assign_exp_found = \false; $i = 0; while ($i < count($stmts) && !$assign_exp_found) { $stmt = $stmts[$i]; if ($stmt instanceof PhpParser\Node\Stmt\Expression) { $search_result = $this->findAssignExp($stmt->expr, $var_id, $original_location->raw_file_start); [$target_exp, $levels_taken] = $search_result; if ($target_exp !== null) { $assign_exp_found = \true; $assign_exp = $target_exp; $assign_stmt = $levels_taken === 1 ? $stmt : null; } } elseif ($stmt instanceof PhpParser\Node\Stmt\TryCatch) { $search_result = $this->findAssignStmt($stmt->stmts, $var_id, $original_location); if ($search_result[0] && $search_result[1]) { return $search_result; } foreach ($stmt->catches as $catch_stmt) { $search_result = $this->findAssignStmt($catch_stmt->stmts, $var_id, $original_location); if ($search_result[0] && $search_result[1]) { return $search_result; } } } elseif ($stmt instanceof PhpParser\Node\Stmt\Do_ || $stmt instanceof PhpParser\Node\Stmt\While_) { $search_result = $this->findAssignStmt($stmt->stmts, $var_id, $original_location); if ($search_result[0] && $search_result[1]) { return $search_result; } } elseif ($stmt instanceof PhpParser\Node\Stmt\Foreach_) { $search_result = $this->findAssignStmt($stmt->stmts, $var_id, $original_location); if ($search_result[0] && $search_result[1]) { return $search_result; } } elseif ($stmt instanceof PhpParser\Node\Stmt\For_) { $search_result = $this->findAssignStmt($stmt->stmts, $var_id, $original_location); if ($search_result[0] && $search_result[1]) { return $search_result; } } elseif ($stmt instanceof PhpParser\Node\Stmt\If_) { $search_result = $this->findAssignStmt($stmt->stmts, $var_id, $original_location); if ($search_result[0] && $search_result[1]) { return $search_result; } foreach ($stmt->elseifs as $elseif_stmt) { $search_result = $this->findAssignStmt($elseif_stmt->stmts, $var_id, $original_location); if ($search_result[0] && $search_result[1]) { return $search_result; } } if ($stmt->else) { $search_result = $this->findAssignStmt($stmt->else->stmts, $var_id, $original_location); if ($search_result[0] && $search_result[1]) { return $search_result; } } } $i++; } return [$assign_stmt, $assign_exp]; } /** * @return array{ * 0: PhpParser\Node\Expr\Assign|PhpParser\Node\Expr\AssignOp|PhpParser\Node\Expr\AssignRef|null, * 1: int * } */ private function findAssignExp(PhpParser\Node\Expr $current_node, string $var_id, int $var_start_loc, int $search_level = 1) : array { if ($current_node instanceof PhpParser\Node\Expr\Assign || $current_node instanceof PhpParser\Node\Expr\AssignOp || $current_node instanceof PhpParser\Node\Expr\AssignRef) { $var = $current_node->var; if ($var instanceof PhpParser\Node\Expr\Variable && $var->name === substr($var_id, 1) && $var->getStartFilePos() === $var_start_loc) { return [$current_node, $search_level]; } $rhs_exp = $current_node->expr; $rhs_search_result = $this->findAssignExp($rhs_exp, $var_id, $var_start_loc, $search_level + 1); return [$rhs_search_result[0], $rhs_search_result[1]]; } return [null, $search_level]; } public function checkIfVarRemoved(string $var_id, CodeLocation $var_loc) : bool { return array_key_exists($var_id, $this->removed_unref_vars) && $this->removed_unref_vars[$var_id] === $var_loc; } } getCodebase(); foreach ($stmt->exprs as $i => $expr) { $context->inside_call = \true; \Psalm\Internal\Analyzer\Statements\ExpressionAnalyzer::analyze($statements_analyzer, $expr, $context); $context->inside_call = \false; $expr_type = $statements_analyzer->node_data->getType($expr); if ($statements_analyzer->data_flow_graph instanceof TaintFlowGraph) { if ($expr_type && $expr_type->hasObjectType()) { $expr_type = CastAnalyzer::castStringAttempt($statements_analyzer, $context, $expr_type, $expr, \false); } $call_location = new CodeLocation($statements_analyzer->getSource(), $stmt); $echo_param_sink = TaintSink::getForMethodArgument('echo', 'echo', (int) $i, null, $call_location); $echo_param_sink->taints = [TaintKind::INPUT_HTML, TaintKind::INPUT_HAS_QUOTES, TaintKind::USER_SECRET, TaintKind::SYSTEM_SECRET]; $statements_analyzer->data_flow_graph->addSink($echo_param_sink); } if (ArgumentAnalyzer::verifyType($statements_analyzer, $expr_type ?? Type::getMixed(), Type::getString(), null, 'echo', null, (int) $i, new CodeLocation($statements_analyzer->getSource(), $expr), $expr, $context, $echo_param, \false, null, \true, \true, new CodeLocation($statements_analyzer, $stmt)) === \false) { return \false; } } if (isset($codebase->config->forbidden_functions['echo'])) { IssueBuffer::maybeAdd(new ForbiddenCode('Use of echo', new CodeLocation($statements_analyzer, $stmt)), $statements_analyzer->getSource()->getSuppressedIssues()); } if (!$context->collect_initializations && !$context->collect_mutations) { if ($context->mutation_free || $context->external_mutation_free) { IssueBuffer::maybeAdd(new ImpureFunctionCall('Cannot call echo from a mutation-free context', new CodeLocation($statements_analyzer, $stmt)), $statements_analyzer->getSuppressedIssues()); } elseif ($statements_analyzer->getSource() instanceof FunctionLikeAnalyzer && $statements_analyzer->getSource()->track_mutations) { $statements_analyzer->getSource()->inferred_has_mutation = \true; $statements_analyzer->getSource()->inferred_impure = \true; } } return \true; } } assigned_var_ids; $context->assigned_var_ids = []; $init_var_types = []; foreach ($stmt->init as $init) { if (ExpressionAnalyzer::analyze($statements_analyzer, $init, $context) === \false) { return \false; } if ($init instanceof PhpParser\Node\Expr\Assign && $init->var instanceof PhpParser\Node\Expr\Variable && is_string($init->var->name) && ($init_var_type = $statements_analyzer->node_data->getType($init->expr))) { $init_var_types[$init->var->name] = $init_var_type; } } $assigned_var_ids = $context->assigned_var_ids; $context->assigned_var_ids = array_merge($pre_assigned_var_ids, $assigned_var_ids); $while_true = !$stmt->cond && !$stmt->init && !$stmt->loop; $pre_context = null; if ($while_true) { $pre_context = clone $context; } $for_context = clone $context; $for_context->inside_loop = \true; $for_context->break_types[] = 'loop'; $codebase = $statements_analyzer->getCodebase(); if ($codebase->alter_code) { $for_context->branch_point = $for_context->branch_point ?: (int) $stmt->getAttribute('startFilePos'); } $loop_scope = new LoopScope($for_context, $context); $loop_scope->protected_var_ids = array_merge($assigned_var_ids, $context->protected_var_ids); if (\Psalm\Internal\Analyzer\Statements\Block\LoopAnalyzer::analyze($statements_analyzer, $stmt->stmts, $stmt->cond, $stmt->loop, $loop_scope, $inner_loop_context) === \false) { return \false; } if (!$inner_loop_context) { throw new UnexpectedValueException('There should be an inner loop context'); } $always_enters_loop = \false; foreach ($stmt->cond as $cond) { if ($cond_type = $statements_analyzer->node_data->getType($cond)) { $always_enters_loop = $cond_type->isAlwaysTruthy(); } if (count($stmt->init) === 1 && count($stmt->cond) === 1 && $cond instanceof PhpParser\Node\Expr\BinaryOp && ($cond_value = $statements_analyzer->node_data->getType($cond->right)) && ($cond_value->isSingleIntLiteral() || $cond_value->isSingleStringLiteral()) && $cond->left instanceof PhpParser\Node\Expr\Variable && is_string($cond->left->name) && isset($init_var_types[$cond->left->name]) && $init_var_types[$cond->left->name]->isSingleIntLiteral()) { $init_value = $init_var_types[$cond->left->name]->getSingleLiteral()->value; $cond_value = $cond_value->getSingleLiteral()->value; if ($cond instanceof PhpParser\Node\Expr\BinaryOp\Smaller && $init_value < $cond_value) { $always_enters_loop = \true; break; } if ($cond instanceof PhpParser\Node\Expr\BinaryOp\SmallerOrEqual && $init_value <= $cond_value) { $always_enters_loop = \true; break; } if ($cond instanceof PhpParser\Node\Expr\BinaryOp\Greater && $init_value > $cond_value) { $always_enters_loop = \true; break; } if ($cond instanceof PhpParser\Node\Expr\BinaryOp\GreaterOrEqual && $init_value >= $cond_value) { $always_enters_loop = \true; break; } } } if ($while_true) { $always_enters_loop = \true; } $can_leave_loop = !$while_true || in_array(ScopeAnalyzer::ACTION_BREAK, $loop_scope->final_actions, \true); if ($always_enters_loop && $can_leave_loop) { foreach ($inner_loop_context->vars_in_scope as $var_id => $type) { // if there are break statements in the loop it's not certain // that the loop has finished executing, so the assertions at the end // the loop in the while conditional may not hold if (in_array(ScopeAnalyzer::ACTION_BREAK, $loop_scope->final_actions, \true) || in_array(ScopeAnalyzer::ACTION_CONTINUE, $loop_scope->final_actions, \true)) { if (isset($loop_scope->possibly_defined_loop_parent_vars[$var_id])) { $context->vars_in_scope[$var_id] = Type::combineUnionTypes($type, $loop_scope->possibly_defined_loop_parent_vars[$var_id]); } } else { $context->vars_in_scope[$var_id] = $type; } } } $for_context->loop_scope = null; if ($can_leave_loop) { $context->vars_possibly_in_scope = array_merge($context->vars_possibly_in_scope, $for_context->vars_possibly_in_scope); } elseif ($pre_context) { $context->vars_possibly_in_scope = $pre_context->vars_possibly_in_scope; } if ($context->collect_exceptions) { $context->mergeExceptions($for_context); } return null; } } getCodebase(); $was_inside_conditional = $context->inside_conditional; $context->inside_conditional = \true; if (ExpressionAnalyzer::analyze($statements_analyzer, $stmt->cond, $context) === \false) { $context->inside_conditional = $was_inside_conditional; return; } $context->inside_conditional = $was_inside_conditional; $switch_var_id = ExpressionIdentifier::getExtendedVarId($stmt->cond, null, $statements_analyzer); if (!$switch_var_id && ($stmt->cond instanceof PhpParser\Node\Expr\FuncCall || $stmt->cond instanceof PhpParser\Node\Expr\MethodCall || $stmt->cond instanceof PhpParser\Node\Expr\StaticCall)) { $switch_var_id = '$__tmp_switch__' . (int) $stmt->cond->getAttribute('startFilePos'); $condition_type = $statements_analyzer->node_data->getType($stmt->cond) ?? Type::getMixed(); $context->vars_in_scope[$switch_var_id] = $condition_type; } $original_context = clone $context; // the last statement always breaks, by default $last_case_exit_type = 'break'; $case_exit_types = new SplFixedArray(count($stmt->cases)); $has_default = \false; $case_action_map = []; // create a map of case statement -> ultimate exit type for ($i = count($stmt->cases) - 1; $i >= 0; --$i) { $case = $stmt->cases[$i]; $case_actions = $case_action_map[$i] = ScopeAnalyzer::getControlActions($case->stmts, $statements_analyzer->node_data, ['switch']); if (!in_array(ScopeAnalyzer::ACTION_NONE, $case_actions, \true)) { if ($case_actions === [ScopeAnalyzer::ACTION_END]) { $last_case_exit_type = 'return_throw'; } elseif ($case_actions === [ScopeAnalyzer::ACTION_CONTINUE]) { $last_case_exit_type = 'continue'; } elseif (in_array(ScopeAnalyzer::ACTION_LEAVE_SWITCH, $case_actions, \true)) { $last_case_exit_type = 'break'; } } elseif (count($case_actions) !== 1) { $last_case_exit_type = 'hybrid'; } $case_exit_types[$i] = $last_case_exit_type; } $switch_scope = new SwitchScope(); $was_caching_assertions = $statements_analyzer->node_data->cache_assertions; $statements_analyzer->node_data->cache_assertions = \false; $all_options_returned = \true; for ($i = 0, $l = count($stmt->cases); $i < $l; $i++) { $case = $stmt->cases[$i]; /** @var string */ $case_exit_type = $case_exit_types[$i]; if ($case_exit_type !== 'return_throw') { $all_options_returned = \false; } $case_actions = $case_action_map[$i]; if (!$case->cond) { $has_default = \true; } if (\Psalm\Internal\Analyzer\Statements\Block\SwitchCaseAnalyzer::analyze($statements_analyzer, $codebase, $stmt, $switch_var_id, $case, $context, $original_context, $case_exit_type, $case_actions, $i === $l - 1, $switch_scope) === \false) { return; } } $all_options_matched = $has_default; if (!$has_default && $switch_scope->negated_clauses && $switch_var_id) { $entry_clauses = Algebra::simplifyCNF([...$original_context->clauses, ...$switch_scope->negated_clauses]); $reconcilable_if_types = Algebra::getTruthsFromFormula($entry_clauses); // if the if has an || in the conditional, we cannot easily reason about it if ($reconcilable_if_types && isset($reconcilable_if_types[$switch_var_id])) { $changed_var_ids = []; [$case_vars_in_scope_reconciled, $_] = Reconciler::reconcileKeyedTypes($reconcilable_if_types, [], $original_context->vars_in_scope, $original_context->references_in_scope, $changed_var_ids, [], $statements_analyzer, [], $original_context->inside_loop); if (isset($case_vars_in_scope_reconciled[$switch_var_id]) && $case_vars_in_scope_reconciled[$switch_var_id]->isNever()) { $all_options_matched = \true; } } } if ($was_caching_assertions) { $statements_analyzer->node_data->cache_assertions = \true; } // only update vars if there is a default or all possible cases accounted for // if the default has a throw/return/continue, that should be handled above if ($all_options_matched) { if ($switch_scope->new_vars_in_scope) { $context->vars_in_scope = array_merge($context->vars_in_scope, $switch_scope->new_vars_in_scope); } if ($switch_scope->redefined_vars) { $context->vars_in_scope = array_merge($context->vars_in_scope, $switch_scope->redefined_vars); } if ($switch_scope->possibly_redefined_vars) { foreach ($switch_scope->possibly_redefined_vars as $var_id => $type) { if (!isset($switch_scope->redefined_vars[$var_id]) && !isset($switch_scope->new_vars_in_scope[$var_id]) && isset($context->vars_in_scope[$var_id])) { $context->vars_in_scope[$var_id] = Type::combineUnionTypes($type, $context->vars_in_scope[$var_id]); } } } $stmt->setAttribute('allMatched', \true); } elseif ($switch_scope->possibly_redefined_vars) { foreach ($switch_scope->possibly_redefined_vars as $var_id => $type) { if (isset($context->vars_in_scope[$var_id])) { $context->vars_in_scope[$var_id] = Type::combineUnionTypes($type, $context->vars_in_scope[$var_id]); } } } if ($switch_scope->new_assigned_var_ids) { $context->assigned_var_ids += $switch_scope->new_assigned_var_ids; } $context->vars_possibly_in_scope = array_merge($context->vars_possibly_in_scope, $switch_scope->new_vars_possibly_in_scope); //a switch can't return in all options without a default $context->has_returned = $all_options_returned && $has_default; } } negated_clauses) { $entry_clauses = [...$outer_context->clauses, ...$if_scope->negated_clauses]; $changed_var_ids = []; if ($if_scope->negated_types) { [$vars_reconciled, $references_reconciled] = Reconciler::reconcileKeyedTypes($if_scope->negated_types, [], $outer_context->vars_in_scope, $outer_context->references_in_scope, $changed_var_ids, [], $statements_analyzer, [], $outer_context->inside_loop, new CodeLocation($statements_analyzer->getSource(), $cond instanceof PhpParser\Node\Expr\BooleanNot ? $cond->expr : $cond, $outer_context->include_location, \false)); if ($changed_var_ids) { $outer_context = clone $outer_context; $outer_context->vars_in_scope = $vars_reconciled; $outer_context->references_in_scope = $references_reconciled; $entry_clauses = array_values(array_filter($entry_clauses, static fn(Clause $c): bool => count($c->possibilities) > 1 || $c->wedge || !isset($changed_var_ids[array_key_first($c->possibilities)]))); } } } // get the first expression in the if, which should be evaluated on its own // this allows us to update the context of $matches in // if (!preg_match('/a/', 'aa', $matches)) { // exit // } // echo $matches[0]; $externally_applied_if_cond_expr = self::getDefinitelyEvaluatedExpressionAfterIf($cond); $internally_applied_if_cond_expr = self::getDefinitelyEvaluatedExpressionInsideIf($cond); $pre_condition_vars_in_scope = $outer_context->vars_in_scope; $referenced_var_ids = $outer_context->cond_referenced_var_ids; $outer_context->cond_referenced_var_ids = []; $pre_assigned_var_ids = $outer_context->assigned_var_ids; $outer_context->assigned_var_ids = []; $if_context = null; if ($internally_applied_if_cond_expr !== $externally_applied_if_cond_expr) { $if_context = clone $outer_context; } $was_inside_conditional = $outer_context->inside_conditional; $outer_context->inside_conditional = \true; if (ExpressionAnalyzer::analyze($statements_analyzer, $externally_applied_if_cond_expr, $outer_context) === \false) { throw new ScopeAnalysisException(); } $first_cond_assigned_var_ids = $outer_context->assigned_var_ids; $outer_context->assigned_var_ids = array_merge($pre_assigned_var_ids, $first_cond_assigned_var_ids); $first_cond_referenced_var_ids = $outer_context->cond_referenced_var_ids; $outer_context->cond_referenced_var_ids = array_merge($referenced_var_ids, $first_cond_referenced_var_ids); $outer_context->inside_conditional = $was_inside_conditional; if (!$if_context) { $if_context = clone $outer_context; } $if_conditional_context = clone $if_context; // here we set up a context specifically for the statements in the first `if`, which can // be affected by statements in the if condition $if_conditional_context->if_body_context = $if_context; if ($codebase->alter_code) { $if_context->branch_point = $branch_point; } // we need to clone the current context so our ongoing updates // to $outer_context don't mess with elseif/else blocks $post_if_context = clone $outer_context; if ($internally_applied_if_cond_expr !== $cond || $externally_applied_if_cond_expr !== $cond) { $assigned_var_ids = $first_cond_assigned_var_ids; $if_conditional_context->assigned_var_ids = []; $referenced_var_ids = $first_cond_referenced_var_ids; $if_conditional_context->cond_referenced_var_ids = []; $was_inside_conditional = $if_conditional_context->inside_conditional; $if_conditional_context->inside_conditional = \true; if (ExpressionAnalyzer::analyze($statements_analyzer, $cond, $if_conditional_context) === \false) { throw new ScopeAnalysisException(); } $if_conditional_context->inside_conditional = $was_inside_conditional; /** @var array */ $more_cond_referenced_var_ids = $if_conditional_context->cond_referenced_var_ids; $if_conditional_context->cond_referenced_var_ids = array_merge($more_cond_referenced_var_ids, $referenced_var_ids); $cond_referenced_var_ids = array_merge($first_cond_referenced_var_ids, $more_cond_referenced_var_ids); /** @var array */ $more_cond_assigned_var_ids = $if_conditional_context->assigned_var_ids; $if_conditional_context->assigned_var_ids = array_merge($more_cond_assigned_var_ids, $assigned_var_ids); $assigned_in_conditional_var_ids = array_merge($first_cond_assigned_var_ids, $more_cond_assigned_var_ids); } else { $cond_referenced_var_ids = $first_cond_referenced_var_ids; $assigned_in_conditional_var_ids = $first_cond_assigned_var_ids; } $newish_var_ids = []; foreach (array_diff_key($if_conditional_context->vars_in_scope, $pre_condition_vars_in_scope, $cond_referenced_var_ids, $assigned_in_conditional_var_ids) as $name => $_value) { $newish_var_ids[$name] = \true; } self::handleParadoxicalCondition($statements_analyzer, $cond, \true); // get all the var ids that were referenced in the conditional, but not assigned in it $cond_referenced_var_ids = array_diff_key($cond_referenced_var_ids, $assigned_in_conditional_var_ids); $cond_referenced_var_ids = array_merge($newish_var_ids, $cond_referenced_var_ids); return new IfConditionalScope($if_context, $post_if_context, $cond_referenced_var_ids, $assigned_in_conditional_var_ids, $entry_clauses); } /** * Returns statements that are definitely evaluated before any statements after the end of the * if/elseif/else blocks */ private static function getDefinitelyEvaluatedExpressionAfterIf(PhpParser\Node\Expr $stmt) : PhpParser\Node\Expr { if ($stmt instanceof PhpParser\Node\Expr\BinaryOp\Equal || $stmt instanceof PhpParser\Node\Expr\BinaryOp\Identical) { if ($stmt->left instanceof PhpParser\Node\Expr\ConstFetch && $stmt->left->name->getParts() === ['true']) { return self::getDefinitelyEvaluatedExpressionAfterIf($stmt->right); } if ($stmt->right instanceof PhpParser\Node\Expr\ConstFetch && $stmt->right->name->getParts() === ['true']) { return self::getDefinitelyEvaluatedExpressionAfterIf($stmt->left); } } if ($stmt instanceof PhpParser\Node\Expr\BinaryOp) { if ($stmt instanceof PhpParser\Node\Expr\BinaryOp\BooleanAnd || $stmt instanceof PhpParser\Node\Expr\BinaryOp\LogicalAnd || $stmt instanceof PhpParser\Node\Expr\BinaryOp\LogicalXor) { return self::getDefinitelyEvaluatedExpressionAfterIf($stmt->left); } return $stmt; } if ($stmt instanceof PhpParser\Node\Expr\BooleanNot) { $inner_stmt = self::getDefinitelyEvaluatedExpressionInsideIf($stmt->expr); if ($inner_stmt !== $stmt->expr) { return $inner_stmt; } } return $stmt; } /** * Returns statements that are definitely evaluated before any statements inside * the if block */ private static function getDefinitelyEvaluatedExpressionInsideIf(PhpParser\Node\Expr $stmt) : PhpParser\Node\Expr { if ($stmt instanceof PhpParser\Node\Expr\BinaryOp\Equal || $stmt instanceof PhpParser\Node\Expr\BinaryOp\Identical) { if ($stmt->left instanceof PhpParser\Node\Expr\ConstFetch && $stmt->left->name->getParts() === ['true']) { return self::getDefinitelyEvaluatedExpressionInsideIf($stmt->right); } if ($stmt->right instanceof PhpParser\Node\Expr\ConstFetch && $stmt->right->name->getParts() === ['true']) { return self::getDefinitelyEvaluatedExpressionInsideIf($stmt->left); } } if ($stmt instanceof PhpParser\Node\Expr\BinaryOp) { if ($stmt instanceof PhpParser\Node\Expr\BinaryOp\BooleanOr || $stmt instanceof PhpParser\Node\Expr\BinaryOp\LogicalOr || $stmt instanceof PhpParser\Node\Expr\BinaryOp\LogicalXor) { return self::getDefinitelyEvaluatedExpressionInsideIf($stmt->left); } return $stmt; } if ($stmt instanceof PhpParser\Node\Expr\BooleanNot) { $inner_stmt = self::getDefinitelyEvaluatedExpressionAfterIf($stmt->expr); if ($inner_stmt !== $stmt->expr) { return $inner_stmt; } } return $stmt; } public static function handleParadoxicalCondition(StatementsAnalyzer $statements_analyzer, PhpParser\Node\Expr $stmt, bool $emit_redundant_with_assignation = \false) : void { $type = $statements_analyzer->node_data->getType($stmt); if ($type !== null) { if ($type->isAlwaysFalsy()) { if ($type->from_docblock) { IssueBuffer::maybeAdd(new DocblockTypeContradiction('Operand of type ' . $type->getId() . ' is always falsy', new CodeLocation($statements_analyzer, $stmt), $type->getId() . ' falsy'), $statements_analyzer->getSuppressedIssues()); } else { IssueBuffer::maybeAdd(new TypeDoesNotContainType('Operand of type ' . $type->getId() . ' is always falsy', new CodeLocation($statements_analyzer, $stmt), $type->getId() . ' falsy'), $statements_analyzer->getSuppressedIssues()); } } elseif ($type->isAlwaysTruthy() && (!$stmt instanceof PhpParser\Node\Expr\Assign || $emit_redundant_with_assignation)) { if ($type->from_docblock) { IssueBuffer::maybeAdd(new RedundantConditionGivenDocblockType('Operand of type ' . $type->getId() . ' is always truthy', new CodeLocation($statements_analyzer, $stmt), $type->getId() . ' falsy'), $statements_analyzer->getSuppressedIssues()); } else { IssueBuffer::maybeAdd(new RedundantCondition('Operand of type ' . $type->getId() . ' is always truthy', new CodeLocation($statements_analyzer, $stmt), $type->getId() . ' falsy'), $statements_analyzer->getSuppressedIssues()); } } elseif (!$stmt instanceof PhpParser\Node\Expr\BinaryOp\NotIdentical && !$stmt instanceof PhpParser\Node\Expr\BinaryOp\Identical && !$stmt instanceof PhpParser\Node\Expr\BooleanNot) { ExpressionAnalyzer::checkRiskyTruthyFalsyComparison($type, $statements_analyzer, $stmt); } } } } $stmts * @param list $pre_conditions * @param PhpParser\Node\Expr[] $post_expressions * @return false|null */ public static function analyze(StatementsAnalyzer $statements_analyzer, array $stmts, array $pre_conditions, array $post_expressions, LoopScope $loop_scope, ?Context &$continue_context = null, bool $is_do = \false, bool $always_enters_loop = \false) : ?bool { $traverser = new PhpParser\NodeTraverser(); $loop_context = $loop_scope->loop_context; $loop_parent_context = $loop_scope->loop_parent_context; $assignment_mapper = new AssignmentMapVisitor($loop_context->self); $traverser->addVisitor($assignment_mapper); $traverser->traverse(array_merge($pre_conditions, $stmts, $post_expressions)); $assignment_map = $assignment_mapper->getAssignmentMap(); $assignment_depth = 0; $always_assigned_before_loop_body_vars = []; $pre_condition_clauses = []; $original_protected_var_ids = $loop_parent_context->protected_var_ids; $codebase = $statements_analyzer->getCodebase(); $inner_do_context = null; if ($pre_conditions) { foreach ($pre_conditions as $i => $pre_condition) { $pre_condition_id = spl_object_id($pre_condition); $pre_condition_clauses[$i] = FormulaGenerator::getFormula($pre_condition_id, $pre_condition_id, $pre_condition, $loop_context->self, $statements_analyzer, $codebase); } } else { $always_assigned_before_loop_body_vars = Context::getNewOrUpdatedVarIds($loop_parent_context, $loop_context); } $final_actions = ScopeAnalyzer::getControlActions($stmts, $statements_analyzer->node_data, []); $does_always_break = $final_actions === [ScopeAnalyzer::ACTION_BREAK]; if ($assignment_map) { $first_var_id = array_keys($assignment_map)[0]; $assignment_depth = self::getAssignmentMapDepth($first_var_id, $assignment_map); } if ($assignment_depth === 0 || $does_always_break) { $continue_context = clone $loop_context; $continue_context->loop_scope = $loop_scope; foreach ($pre_conditions as $condition_offset => $pre_condition) { self::applyPreConditionToLoopContext($statements_analyzer, $pre_condition, $pre_condition_clauses[$condition_offset], $continue_context, $loop_parent_context, $is_do); } $continue_context->protected_var_ids = $loop_scope->protected_var_ids; $statements_analyzer->analyze($stmts, $continue_context); self::updateLoopScopeContexts($loop_scope, $loop_context, $continue_context, $loop_parent_context); foreach ($post_expressions as $post_expression) { if (ExpressionAnalyzer::analyze($statements_analyzer, $post_expression, $loop_context) === \false) { return \false; } } $loop_parent_context->vars_possibly_in_scope = array_merge($continue_context->vars_possibly_in_scope, $loop_parent_context->vars_possibly_in_scope); } else { $original_parent_context = clone $loop_parent_context; $analyzer = $statements_analyzer->getCodebase()->analyzer; $original_mixed_counts = $analyzer->getMixedCountsForFile($statements_analyzer->getFilePath()); // record all the vars that existed before we did the first pass through the loop $pre_loop_context = clone $loop_context; IssueBuffer::startRecording(); if (!$is_do) { foreach ($pre_conditions as $condition_offset => $pre_condition) { self::applyPreConditionToLoopContext($statements_analyzer, $pre_condition, $pre_condition_clauses[$condition_offset], $loop_context, $loop_parent_context, $is_do); } } $continue_context = clone $loop_context; $continue_context->loop_scope = $loop_scope; $continue_context->protected_var_ids = $loop_scope->protected_var_ids; $statements_analyzer->analyze($stmts, $continue_context); self::updateLoopScopeContexts($loop_scope, $loop_context, $continue_context, $original_parent_context); $continue_context->protected_var_ids = $original_protected_var_ids; if ($is_do) { $inner_do_context = clone $continue_context; foreach ($pre_conditions as $condition_offset => $pre_condition) { $always_assigned_before_loop_body_vars = [...self::applyPreConditionToLoopContext($statements_analyzer, $pre_condition, $pre_condition_clauses[$condition_offset], $continue_context, $loop_parent_context, $is_do), ...$always_assigned_before_loop_body_vars]; } } $always_assigned_before_loop_body_vars = array_unique($always_assigned_before_loop_body_vars); foreach ($post_expressions as $post_expression) { if (ExpressionAnalyzer::analyze($statements_analyzer, $post_expression, $continue_context) === \false) { return \false; } } $recorded_issues = IssueBuffer::clearRecordingLevel(); IssueBuffer::stopRecording(); for ($i = 0; $i < $assignment_depth; ++$i) { $vars_to_remove = []; $loop_scope->iteration_count++; $has_changes = \false; // reset the $continue_context to what it was before we started the analysis, // but union the types with what's in the loop scope foreach ($continue_context->vars_in_scope as $var_id => $type) { if (in_array($var_id, $always_assigned_before_loop_body_vars, \true)) { // set the vars to whatever the while/foreach loop expects them to be if (!isset($pre_loop_context->vars_in_scope[$var_id]) || !$type->equals($pre_loop_context->vars_in_scope[$var_id])) { $has_changes = \true; } } elseif (isset($original_parent_context->vars_in_scope[$var_id])) { if (!$type->equals($original_parent_context->vars_in_scope[$var_id])) { $has_changes = \true; // widen the foreach context type with the initial context type $continue_context->vars_in_scope[$var_id] = Type::combineUnionTypes($continue_context->vars_in_scope[$var_id], $original_parent_context->vars_in_scope[$var_id]); // if there's a change, invalidate related clauses $pre_loop_context->removeVarFromConflictingClauses($var_id); $loop_parent_context->possibly_assigned_var_ids[$var_id] = \true; } if (isset($loop_context->vars_in_scope[$var_id]) && !$type->equals($loop_context->vars_in_scope[$var_id])) { $has_changes = \true; // widen the foreach context type with the initial context type $continue_context->vars_in_scope[$var_id] = Type::combineUnionTypes($continue_context->vars_in_scope[$var_id], $loop_context->vars_in_scope[$var_id]); // if there's a change, invalidate related clauses $pre_loop_context->removeVarFromConflictingClauses($var_id); } } else { // give an opportunity to redeemed UndefinedVariable issues if ($recorded_issues) { $has_changes = \true; } // if we're in a do block we don't want to remove vars before evaluating // the where conditional if (!$is_do) { $vars_to_remove[] = $var_id; } } } $continue_context->has_returned = \false; $loop_parent_context->vars_possibly_in_scope = array_merge($continue_context->vars_possibly_in_scope, $loop_parent_context->vars_possibly_in_scope); // if there are no changes to the types, no need to re-examine if (!$has_changes) { break; } // remove vars that were defined in the foreach foreach ($vars_to_remove as $var_id) { $continue_context->removePossibleReference($var_id); } $continue_context->clauses = $pre_loop_context->clauses; $continue_context->byref_constraints = $pre_loop_context->byref_constraints; $analyzer->setMixedCountsForFile($statements_analyzer->getFilePath(), $original_mixed_counts); IssueBuffer::startRecording(); if (!$is_do) { foreach ($pre_conditions as $condition_offset => $pre_condition) { self::applyPreConditionToLoopContext($statements_analyzer, $pre_condition, $pre_condition_clauses[$condition_offset], $continue_context, $loop_parent_context, \false); } } foreach ($always_assigned_before_loop_body_vars as $var_id) { if (!isset($continue_context->vars_in_scope[$var_id]) || $continue_context->vars_in_scope[$var_id]->getId() !== $pre_loop_context->vars_in_scope[$var_id]->getId() || $continue_context->vars_in_scope[$var_id]->from_docblock !== $pre_loop_context->vars_in_scope[$var_id]->from_docblock) { if (isset($pre_loop_context->vars_in_scope[$var_id])) { $continue_context->vars_in_scope[$var_id] = $pre_loop_context->vars_in_scope[$var_id]; } else { $continue_context->removePossibleReference($var_id); } } } $continue_context->clauses = $pre_loop_context->clauses; $continue_context->protected_var_ids = $loop_scope->protected_var_ids; $traverser = new PhpParser\NodeTraverser(); $traverser->addVisitor(new NodeCleanerVisitor($statements_analyzer->node_data)); $traverser->traverse($stmts); $statements_analyzer->analyze($stmts, $continue_context); self::updateLoopScopeContexts($loop_scope, $loop_context, $continue_context, $original_parent_context); $continue_context->protected_var_ids = $original_protected_var_ids; if ($is_do) { $inner_do_context = clone $continue_context; foreach ($pre_conditions as $condition_offset => $pre_condition) { self::applyPreConditionToLoopContext($statements_analyzer, $pre_condition, $pre_condition_clauses[$condition_offset], $continue_context, $loop_parent_context, $is_do); } } foreach ($post_expressions as $post_expression) { if (ExpressionAnalyzer::analyze($statements_analyzer, $post_expression, $continue_context) === \false) { return \false; } } $recorded_issues = IssueBuffer::clearRecordingLevel(); IssueBuffer::stopRecording(); } if ($recorded_issues) { foreach ($recorded_issues as $recorded_issue) { // if we're not in any loops then this will just result in the issue being emitted IssueBuffer::bubbleUp($recorded_issue); } } } $does_sometimes_break = in_array(ScopeAnalyzer::ACTION_BREAK, $loop_scope->final_actions, \true); $does_always_break = $loop_scope->final_actions === [ScopeAnalyzer::ACTION_BREAK]; if ($does_sometimes_break) { foreach ($loop_scope->possibly_redefined_loop_parent_vars as $var => $type) { $loop_parent_context->vars_in_scope[$var] = Type::combineUnionTypes($type, $loop_parent_context->vars_in_scope[$var]); $loop_parent_context->possibly_assigned_var_ids[$var] = \true; } } foreach ($loop_parent_context->vars_in_scope as $var_id => $type) { if (!isset($loop_context->vars_in_scope[$var_id])) { continue; } if ($loop_context->vars_in_scope[$var_id]->getId() !== $type->getId()) { $loop_parent_context->vars_in_scope[$var_id] = Type::combineUnionTypes($loop_parent_context->vars_in_scope[$var_id], $loop_context->vars_in_scope[$var_id]); $loop_parent_context->removeVarFromConflictingClauses($var_id); } else { $loop_parent_context->vars_in_scope[$var_id] = $loop_parent_context->vars_in_scope[$var_id]->addParentNodes($loop_context->vars_in_scope[$var_id]->parent_nodes); } } if (!$does_always_break) { foreach ($loop_parent_context->vars_in_scope as $var_id => $type) { if (!isset($continue_context->vars_in_scope[$var_id])) { $loop_parent_context->removePossibleReference($var_id); continue; } if ($continue_context->vars_in_scope[$var_id]->hasMixed()) { $continue_context->vars_in_scope[$var_id] = $continue_context->vars_in_scope[$var_id]->addParentNodes($loop_parent_context->vars_in_scope[$var_id]->parent_nodes); $loop_parent_context->vars_in_scope[$var_id] = $continue_context->vars_in_scope[$var_id]; $loop_parent_context->removeVarFromConflictingClauses($var_id); continue; } if ($continue_context->vars_in_scope[$var_id]->getId() !== $type->getId()) { $loop_parent_context->vars_in_scope[$var_id] = Type::combineUnionTypes($loop_parent_context->vars_in_scope[$var_id], $continue_context->vars_in_scope[$var_id]); $loop_parent_context->removeVarFromConflictingClauses($var_id); } else { $loop_parent_context->vars_in_scope[$var_id] = $loop_parent_context->vars_in_scope[$var_id]->setParentNodes(array_merge($loop_parent_context->vars_in_scope[$var_id]->parent_nodes, $continue_context->vars_in_scope[$var_id]->parent_nodes)); } } } if ($pre_conditions && $pre_condition_clauses && !$does_sometimes_break) { // if the loop contains an assertion and there are no break statements, we can negate that assertion // and apply it to the current context try { $negated_pre_condition_clauses = Algebra::negateFormula(array_merge(...$pre_condition_clauses)); } catch (ComplicatedExpressionException $e) { $negated_pre_condition_clauses = []; } $negated_pre_condition_types = Algebra::getTruthsFromFormula($negated_pre_condition_clauses); if ($negated_pre_condition_types) { $changed_var_ids = []; [$vars_in_scope_reconciled, $_] = Reconciler::reconcileKeyedTypes($negated_pre_condition_types, [], $continue_context->vars_in_scope, $continue_context->references_in_scope, $changed_var_ids, [], $statements_analyzer, [], \true, new CodeLocation($statements_analyzer->getSource(), $pre_conditions[0])); foreach ($changed_var_ids as $var_id => $_) { if (isset($vars_in_scope_reconciled[$var_id]) && isset($loop_parent_context->vars_in_scope[$var_id])) { $loop_parent_context->vars_in_scope[$var_id] = $vars_in_scope_reconciled[$var_id]; } $loop_parent_context->removeVarFromConflictingClauses($var_id); } } } if ($always_enters_loop) { foreach ($continue_context->vars_in_scope as $var_id => $type) { // if there are break statements in the loop it's not certain // that the loop has finished executing, so the assertions at the end // the loop in the while conditional may not hold if (in_array(ScopeAnalyzer::ACTION_BREAK, $loop_scope->final_actions, \true) || in_array(ScopeAnalyzer::ACTION_CONTINUE, $loop_scope->final_actions, \true)) { if (isset($loop_scope->possibly_defined_loop_parent_vars[$var_id])) { $loop_parent_context->vars_in_scope[$var_id] = Type::combineUnionTypes($type, $loop_scope->possibly_defined_loop_parent_vars[$var_id]); } } else { $loop_parent_context->vars_in_scope[$var_id] = $type; } } } if ($inner_do_context) { $continue_context = $inner_do_context; } // Track references set in the loop to make sure they aren't reused later $loop_parent_context->updateReferencesPossiblyFromConfusingScope($continue_context, $statements_analyzer); return null; } private static function updateLoopScopeContexts(LoopScope $loop_scope, Context $loop_context, Context $continue_context, Context $pre_outer_context) : void { if (!in_array(ScopeAnalyzer::ACTION_CONTINUE, $loop_scope->final_actions, \true)) { $loop_context->vars_in_scope = $pre_outer_context->vars_in_scope; } else { $updated_loop_vars = []; foreach ($loop_scope->redefined_loop_vars as $var => $type) { $continue_context->vars_in_scope[$var] = $type; $updated_loop_vars[$var] = \true; } foreach ($loop_scope->possibly_redefined_loop_vars as $var => $type) { if ($continue_context->hasVariable($var)) { if (!isset($updated_loop_vars[$var])) { $continue_context->vars_in_scope[$var] = Type::combineUnionTypes($continue_context->vars_in_scope[$var], $type); } else { $continue_context->vars_in_scope[$var] = $continue_context->vars_in_scope[$var]->addParentNodes($type->parent_nodes); } } } } // merge vars possibly in scope at the end of each loop $loop_context->vars_possibly_in_scope = array_merge($loop_context->vars_possibly_in_scope, $loop_scope->vars_possibly_in_scope); } /** * @param list $pre_condition_clauses * @return list */ private static function applyPreConditionToLoopContext(StatementsAnalyzer $statements_analyzer, PhpParser\Node\Expr $pre_condition, array $pre_condition_clauses, Context $loop_context, Context $outer_context, bool $is_do) : array { $pre_referenced_var_ids = $loop_context->cond_referenced_var_ids; $loop_context->cond_referenced_var_ids = []; $was_inside_conditional = $loop_context->inside_conditional; $loop_context->inside_conditional = \true; if (ExpressionAnalyzer::analyze($statements_analyzer, $pre_condition, $loop_context) === \false) { $loop_context->inside_conditional = $was_inside_conditional; return []; } $loop_context->inside_conditional = $was_inside_conditional; $new_referenced_var_ids = $loop_context->cond_referenced_var_ids; $loop_context->cond_referenced_var_ids = array_merge($pre_referenced_var_ids, $new_referenced_var_ids); $always_assigned_before_loop_body_vars = Context::getNewOrUpdatedVarIds($outer_context, $loop_context); $loop_context->clauses = Algebra::simplifyCNF([...$outer_context->clauses, ...$pre_condition_clauses]); $active_while_types = []; $reconcilable_while_types = Algebra::getTruthsFromFormula($loop_context->clauses, spl_object_id($pre_condition), $new_referenced_var_ids, $active_while_types); $changed_var_ids = []; if ($reconcilable_while_types) { [$loop_context->vars_in_scope, $loop_context->references_in_scope] = Reconciler::reconcileKeyedTypes($reconcilable_while_types, $active_while_types, $loop_context->vars_in_scope, $loop_context->references_in_scope, $changed_var_ids, $new_referenced_var_ids, $statements_analyzer, [], \true, new CodeLocation($statements_analyzer->getSource(), $pre_condition)); } if ($is_do) { return []; } foreach ($always_assigned_before_loop_body_vars as $var_id) { $loop_context->clauses = Context::filterClauses($var_id, $loop_context->clauses, null, $statements_analyzer); } return $always_assigned_before_loop_body_vars; } /** * @param array> $assignment_map */ private static function getAssignmentMapDepth(string $first_var_id, array $assignment_map) : int { $max_depth = 0; $assignment_var_ids = $assignment_map[$first_var_id]; unset($assignment_map[$first_var_id]); foreach ($assignment_var_ids as $assignment_var_id => $_) { $depth = 1; if (isset($assignment_map[$assignment_var_id])) { $depth = 1 + self::getAssignmentMapDepth($assignment_var_id, $assignment_map); } if ($depth > $max_depth) { $max_depth = $depth; } } return $max_depth; } } getCodebase(); /** @var int $i */ foreach ($stmt->catches as $i => $catch) { $catch_actions[$i] = ScopeAnalyzer::getControlActions($catch->stmts, $statements_analyzer->node_data, []); $all_catches_leave = $all_catches_leave && !in_array(ScopeAnalyzer::ACTION_NONE, $catch_actions[$i], \true); } $existing_thrown_exceptions = $context->possibly_thrown_exceptions; /** * @var array> $context->possibly_thrown_exceptions */ $context->possibly_thrown_exceptions = []; $old_context = clone $context; $try_context = clone $context; if ($codebase->alter_code) { $try_context->branch_point = $try_context->branch_point ?: (int) $stmt->getAttribute('startFilePos'); } if ($stmt->finally) { $try_context->finally_scope = new FinallyScope($try_context->vars_in_scope); } $assigned_var_ids = $try_context->assigned_var_ids; $context->assigned_var_ids = []; $was_inside_try = $context->inside_try; $context->inside_try = \true; if ($statements_analyzer->analyze($stmt->stmts, $context) === \false) { return \false; } $context->inside_try = $was_inside_try; $context->has_returned = \false; $try_block_control_actions = ScopeAnalyzer::getControlActions($stmt->stmts, $statements_analyzer->node_data, []); /** @var array */ $newly_assigned_var_ids = $context->assigned_var_ids; $context->assigned_var_ids = array_merge($assigned_var_ids, $newly_assigned_var_ids); foreach ($context->vars_in_scope as $var_id => $type) { if (!isset($try_context->vars_in_scope[$var_id])) { $try_context->vars_in_scope[$var_id] = $type; $context->vars_in_scope[$var_id] = $type->setPossiblyUndefined(\true, \true); } else { $try_context->vars_in_scope[$var_id] = Type::combineUnionTypes($try_context->vars_in_scope[$var_id], $type); } } if ($try_context->finally_scope) { foreach ($context->vars_in_scope as $var_id => $type) { $try_context->finally_scope->vars_in_scope[$var_id] = Type::combineUnionTypes($try_context->finally_scope->vars_in_scope[$var_id] ?? null, $type, $statements_analyzer->getCodebase()); } } $try_context->vars_possibly_in_scope = $context->vars_possibly_in_scope; $try_context->possibly_thrown_exceptions = $context->possibly_thrown_exceptions; $try_leaves_loop = $context->loop_scope && $context->loop_scope->final_actions && !in_array(ScopeAnalyzer::ACTION_NONE, $context->loop_scope->final_actions, \true); if (!$all_catches_leave) { foreach ($newly_assigned_var_ids as $assigned_var_id => $_) { $context->removeVarFromConflictingClauses($assigned_var_id); } } else { foreach ($newly_assigned_var_ids as $assigned_var_id => $_) { $try_context->removeVarFromConflictingClauses($assigned_var_id); } } // at this point we have two contexts – $context, in which it is assumed that everything was fine, // and $try_context - which allows all variables to have the union of the values before and after // the try was applied $original_context = clone $try_context; $issues_to_suppress = ['RedundantCondition', 'RedundantConditionGivenDocblockType', 'TypeDoesNotContainNull', 'TypeDoesNotContainType']; $definitely_newly_assigned_var_ids = $newly_assigned_var_ids; /** @var int $i */ foreach ($stmt->catches as $i => $catch) { $catch_context = clone $original_context; $catch_context->has_returned = \false; foreach ($catch_context->vars_in_scope as $var_id => $type) { if (!isset($old_context->vars_in_scope[$var_id])) { $catch_context->vars_in_scope[$var_id] = $type->setPossiblyUndefined($catch_context->vars_in_scope[$var_id]->possibly_undefined, \true); } else { $catch_context->vars_in_scope[$var_id] = Type::combineUnionTypes($type, $old_context->vars_in_scope[$var_id]); } } $fq_catch_classes = []; if (!$catch->types) { throw new UnexpectedValueException('Very bad'); } foreach ($catch->types as $catch_type) { $fq_catch_class = ClassLikeAnalyzer::getFQCLNFromNameObject($catch_type, $statements_analyzer->getAliases()); $fq_catch_class = $codebase->classlikes->getUnAliasedName($fq_catch_class); if ($codebase->alter_code && $fq_catch_class) { $codebase->classlikes->handleClassLikeReferenceInMigration($codebase, $statements_analyzer, $catch_type, $fq_catch_class, $context->calling_method_id); } if ($original_context->check_classes) { ClassLikeAnalyzer::checkFullyQualifiedClassLikeName($statements_analyzer, $fq_catch_class, new CodeLocation($statements_analyzer->getSource(), $catch_type, $context->include_location), $context->self, $context->calling_method_id, $statements_analyzer->getSuppressedIssues(), new ClassLikeNameOptions(\true)); } if ($codebase->classExists($fq_catch_class) && strtolower($fq_catch_class) !== 'exception' && !($codebase->classExtends($fq_catch_class, 'Exception') || $codebase->classImplements($fq_catch_class, 'Throwable')) || $codebase->interfaceExists($fq_catch_class) && strtolower($fq_catch_class) !== 'throwable' && !$codebase->interfaceExtends($fq_catch_class, 'Throwable')) { IssueBuffer::maybeAdd(new InvalidCatch('Class/interface ' . $fq_catch_class . ' cannot be caught', new CodeLocation($statements_analyzer->getSource(), $stmt), $fq_catch_class), $statements_analyzer->getSuppressedIssues()); } $fq_catch_classes[] = $fq_catch_class; } if ($catch_context->collect_exceptions) { foreach ($fq_catch_classes as $fq_catch_class) { $fq_catch_class_lower = strtolower($fq_catch_class); foreach ($catch_context->possibly_thrown_exceptions as $exception_fqcln => $_) { $exception_fqcln_lower = strtolower($exception_fqcln); if ($exception_fqcln_lower === $fq_catch_class_lower || $codebase->classExists($exception_fqcln) && $codebase->classExtendsOrImplements($exception_fqcln, $fq_catch_class) || $codebase->interfaceExists($exception_fqcln) && $codebase->interfaceExtends($exception_fqcln, $fq_catch_class)) { unset($original_context->possibly_thrown_exceptions[$exception_fqcln]); unset($context->possibly_thrown_exceptions[$exception_fqcln]); unset($catch_context->possibly_thrown_exceptions[$exception_fqcln]); } } } $catch_context->possibly_thrown_exceptions = []; } // discard all clauses because crazy stuff may have happened in try block $catch_context->clauses = []; if ($catch->var && is_string($catch->var->name)) { $catch_var_id = '$' . $catch->var->name; $catch_context->vars_in_scope[$catch_var_id] = new Union(array_map(static fn(string $fq_catch_class): TNamedObject => new TNamedObject($fq_catch_class, \false, \false, strtolower($fq_catch_class) !== 'throwable' && $codebase->interfaceExists($fq_catch_class) && !$codebase->interfaceExtends($fq_catch_class, 'Throwable') ? ['Throwable' => new TNamedObject('Throwable')] : []), $fq_catch_classes)); // removes dependent vars from $context $catch_context->removeDescendents($catch_var_id, $catch_context->vars_in_scope[$catch_var_id], $catch_context->vars_in_scope[$catch_var_id], $statements_analyzer); $catch_context->vars_possibly_in_scope[$catch_var_id] = \true; $location = new CodeLocation($statements_analyzer->getSource(), $catch->var); if (!$statements_analyzer->hasVariable($catch_var_id)) { $statements_analyzer->registerVariable($catch_var_id, $location, $catch_context->branch_point); } else { $statements_analyzer->registerVariableAssignment($catch_var_id, $location); } if ($statements_analyzer->data_flow_graph) { $catch_var_node = DataFlowNode::getForAssignment($catch_var_id, $location); $catch_context->vars_in_scope[$catch_var_id] = $catch_context->vars_in_scope[$catch_var_id]->addParentNodes([$catch_var_node->id => $catch_var_node]); if ($statements_analyzer->data_flow_graph instanceof VariableUseGraph) { $statements_analyzer->data_flow_graph->addPath($catch_var_node, new DataFlowNode('variable-use', 'variable use', null), 'variable-use'); } } } $suppressed_issues = $statements_analyzer->getSuppressedIssues(); foreach ($issues_to_suppress as $issue_to_suppress) { if (!in_array($issue_to_suppress, $suppressed_issues, \true)) { $statements_analyzer->addSuppressedIssues([$issue_to_suppress]); } } $old_catch_assigned_var_ids = $catch_context->assigned_var_ids; $catch_context->assigned_var_ids = []; $statements_analyzer->analyze($catch->stmts, $catch_context); // recalculate in case there's a no-return clause $catch_actions[$i] = ScopeAnalyzer::getControlActions($catch->stmts, $statements_analyzer->node_data, []); foreach ($issues_to_suppress as $issue_to_suppress) { if (!in_array($issue_to_suppress, $suppressed_issues, \true)) { $statements_analyzer->removeSuppressedIssues([$issue_to_suppress]); } } /** @var array */ $new_catch_assigned_var_ids = $catch_context->assigned_var_ids; $catch_context->assigned_var_ids += $old_catch_assigned_var_ids; if ($catch_context->collect_exceptions) { $context->mergeExceptions($catch_context); } $catch_doesnt_leave_parent_scope = $catch_actions[$i] !== [ScopeAnalyzer::ACTION_END] && $catch_actions[$i] !== [ScopeAnalyzer::ACTION_CONTINUE] && $catch_actions[$i] !== [ScopeAnalyzer::ACTION_BREAK]; if ($catch_doesnt_leave_parent_scope) { $definitely_newly_assigned_var_ids = array_intersect_key($new_catch_assigned_var_ids, $definitely_newly_assigned_var_ids); foreach ($catch_context->vars_in_scope as $var_id => $type) { if ($try_block_control_actions === [ScopeAnalyzer::ACTION_END]) { $context->vars_in_scope[$var_id] = $type; } elseif (isset($context->vars_in_scope[$var_id])) { $context->vars_in_scope[$var_id] = Type::combineUnionTypes($context->vars_in_scope[$var_id], $type); } } $context->vars_possibly_in_scope = array_merge($catch_context->vars_possibly_in_scope, $context->vars_possibly_in_scope); } else { if ($stmt->finally) { $context->vars_possibly_in_scope = array_merge($catch_context->vars_possibly_in_scope, $context->vars_possibly_in_scope); } } if ($try_context->finally_scope) { foreach ($catch_context->vars_in_scope as $var_id => &$type) { if (isset($try_context->finally_scope->vars_in_scope[$var_id])) { if ($try_context->finally_scope->vars_in_scope[$var_id] !== $type) { $try_context->finally_scope->vars_in_scope[$var_id] = Type::combineUnionTypes($try_context->finally_scope->vars_in_scope[$var_id], $type, $statements_analyzer->getCodebase()); } } else { $try_context->finally_scope->vars_in_scope[$var_id] = $type->setPossiblyUndefined(\true, \true); } } unset($type); } } if ($context->loop_scope && !$try_leaves_loop && !in_array(ScopeAnalyzer::ACTION_NONE, $context->loop_scope->final_actions, \true)) { $context->loop_scope->final_actions[] = ScopeAnalyzer::ACTION_NONE; } $finally_has_returned = \false; if ($stmt->finally) { if ($try_context->finally_scope) { $finally_context = clone $context; $finally_context->assigned_var_ids = []; $finally_context->possibly_assigned_var_ids = []; $finally_context->vars_in_scope = $try_context->finally_scope->vars_in_scope; $statements_analyzer->analyze($stmt->finally->stmts, $finally_context); $finally_has_returned = $finally_context->has_returned; /** @var string $var_id */ foreach ($finally_context->assigned_var_ids as $var_id => $_) { if (isset($context->vars_in_scope[$var_id]) && isset($finally_context->vars_in_scope[$var_id])) { $possibly_undefined = $context->vars_in_scope[$var_id]->possibly_undefined && $context->vars_in_scope[$var_id]->possibly_undefined_from_try; $context->vars_in_scope[$var_id] = Type::combineUnionTypes($context->vars_in_scope[$var_id], $finally_context->vars_in_scope[$var_id], $codebase); if ($possibly_undefined) { /** @psalm-suppress InaccessibleProperty We just created this type */ $context->vars_in_scope[$var_id]->possibly_undefined = \false; /** @psalm-suppress InaccessibleProperty We just created this type */ $context->vars_in_scope[$var_id]->possibly_undefined_from_try = \false; } } elseif (isset($finally_context->vars_in_scope[$var_id])) { $context->vars_in_scope[$var_id] = $finally_context->vars_in_scope[$var_id]; } } } } foreach ($definitely_newly_assigned_var_ids as $var_id => $_) { if (isset($context->vars_in_scope[$var_id])) { if ($context->vars_in_scope[$var_id]->possibly_undefined_from_try) { $context->vars_in_scope[$var_id] = $context->vars_in_scope[$var_id]->setPossiblyUndefined(\false, \false); } } } foreach ($existing_thrown_exceptions as $possibly_thrown_exception => $codelocations) { foreach ($codelocations as $hash => $codelocation) { $context->possibly_thrown_exceptions[$possibly_thrown_exception][$hash] = $codelocation; } } $body_has_returned = !in_array(ScopeAnalyzer::ACTION_NONE, $try_block_control_actions, \true); $context->has_returned = $body_has_returned && $all_catches_leave || $finally_has_returned; return null; } } getDocComment(); $codebase = $statements_analyzer->getCodebase(); $file_path = $statements_analyzer->getRootFilePath(); $type_aliases = $codebase->file_storage_provider->get($file_path)->type_aliases; if ($doc_comment) { try { $var_comments = CommentAnalyzer::getTypeFromComment($doc_comment, $statements_analyzer->getSource(), $statements_analyzer->getSource()->getAliases(), $statements_analyzer->getTemplateTypeMap() ?: [], $type_aliases); } catch (DocblockParseException $e) { IssueBuffer::maybeAdd(new InvalidDocblock($e->getMessage(), new CodeLocation($statements_analyzer, $stmt))); } } $safe_var_ids = []; if ($stmt->keyVar instanceof PhpParser\Node\Expr\Variable && is_string($stmt->keyVar->name)) { $safe_var_ids['$' . $stmt->keyVar->name] = \true; } if ($stmt->valueVar instanceof PhpParser\Node\Expr\Variable && is_string($stmt->valueVar->name)) { $safe_var_ids['$' . $stmt->valueVar->name] = \true; $statements_analyzer->foreach_var_locations['$' . $stmt->valueVar->name][] = new CodeLocation($statements_analyzer, $stmt->valueVar); } elseif ($stmt->valueVar instanceof PhpParser\Node\Expr\List_) { foreach ($stmt->valueVar->items as $list_item) { if (!$list_item) { continue; } $list_item_key = $list_item->key; $list_item_value = $list_item->value; if ($list_item_value instanceof PhpParser\Node\Expr\Variable && is_string($list_item_value->name)) { $safe_var_ids['$' . $list_item_value->name] = \true; } if ($list_item_key instanceof PhpParser\Node\Expr\Variable && is_string($list_item_key->name)) { $safe_var_ids['$' . $list_item_key->name] = \true; } } } foreach ($var_comments as $var_comment) { if (!$var_comment->var_id || !$var_comment->type) { continue; } if (isset($safe_var_ids[$var_comment->var_id])) { continue; } $comment_type = TypeExpander::expandUnion($codebase, $var_comment->type, $context->self, $context->self, $statements_analyzer->getParentFQCLN()); $type_location = null; if ($var_comment->type_start && $var_comment->type_end && $var_comment->line_number) { $type_location = new DocblockTypeLocation($statements_analyzer, $var_comment->type_start, $var_comment->type_end, $var_comment->line_number); if ($codebase->alter_code) { $codebase->classlikes->handleDocblockTypeInMigration($codebase, $statements_analyzer, $comment_type, $type_location, $context->calling_method_id); } } if (isset($context->vars_in_scope[$var_comment->var_id]) || VariableFetchAnalyzer::isSuperGlobal($var_comment->var_id)) { if ($codebase->find_unused_variables && $doc_comment && $type_location && isset($context->vars_in_scope[$var_comment->var_id]) && $context->vars_in_scope[$var_comment->var_id]->getId() === $comment_type->getId() && !$comment_type->isMixed(\true)) { $project_analyzer = $statements_analyzer->getProjectAnalyzer(); if ($codebase->alter_code && isset($project_analyzer->getIssuesToFix()['UnnecessaryVarAnnotation'])) { FileManipulationBuffer::addVarAnnotationToRemove($type_location); } else { IssueBuffer::maybeAdd(new UnnecessaryVarAnnotation('The @var ' . $comment_type . ' annotation for ' . $var_comment->var_id . ' is unnecessary', $type_location), $statements_analyzer->getSuppressedIssues(), \true); } } if (isset($context->vars_in_scope[$var_comment->var_id])) { /** @psalm-suppress InaccessibleProperty We just created this type */ $comment_type->parent_nodes = $context->vars_in_scope[$var_comment->var_id]->parent_nodes; } $context->vars_in_scope[$var_comment->var_id] = $comment_type; } } $was_inside_general_use = $context->inside_general_use; $context->inside_general_use = \true; if (ExpressionAnalyzer::analyze($statements_analyzer, $stmt->expr, $context) === \false) { $context->inside_general_use = $was_inside_general_use; return \false; } $context->inside_general_use = $was_inside_general_use; $key_type = null; $value_type = null; $always_non_empty_array = \true; $var_id = ExpressionIdentifier::getVarId($stmt->expr, $statements_analyzer->getFQCLN(), $statements_analyzer); if ($stmt_expr_type = $statements_analyzer->node_data->getType($stmt->expr)) { $iterator_type = $stmt_expr_type; } elseif ($var_id && $context->hasVariable($var_id)) { $iterator_type = $context->vars_in_scope[$var_id]; } else { $iterator_type = null; } if ($iterator_type) { if (self::checkIteratorType($statements_analyzer, $stmt, $stmt->expr, $iterator_type, $codebase, $context, $key_type, $value_type, $always_non_empty_array) === \false) { return \false; } } $foreach_context = clone $context; if ($var_id && $foreach_context->hasVariable($var_id)) { // refine the type of the array variable we iterate over // if we entered loop body, the array cannot be empty $foreach_context->vars_in_scope[$var_id] = AssertionReconciler::reconcile( new Assertion\NonEmpty(), $foreach_context->vars_in_scope[$var_id], null, $statements_analyzer, \true, // inside loop ? $statements_analyzer->getTemplateTypeMap() ?? [] ); } $foreach_context->inside_loop = \true; $foreach_context->break_types[] = 'loop'; if ($codebase->alter_code) { $foreach_context->branch_point = $foreach_context->branch_point ?: (int) $stmt->getAttribute('startFilePos'); } if ($stmt->keyVar instanceof PhpParser\Node\Expr\Variable && is_string($stmt->keyVar->name)) { $key_type ??= Type::getMixed(); AssignmentAnalyzer::analyze($statements_analyzer, $stmt->keyVar, $stmt->expr, $key_type, $foreach_context, $doc_comment, ['$' . $stmt->keyVar->name => \true]); } if ($value_type !== null) { $value_type = $value_type->setProperties(['by_ref' => $stmt->byRef]); } else { $value_type = new Union([new TMixed()], ['by_ref' => $stmt->byRef]); } if ($stmt->byRef && $stmt->valueVar instanceof PhpParser\Node\Expr\Variable && is_string($stmt->valueVar->name)) { // When assigning as reference, it removes any previous // reference, so it's no longer from a previous confusing scope unset($foreach_context->references_possibly_from_confusing_scope['$' . $stmt->valueVar->name]); } AssignmentAnalyzer::analyze($statements_analyzer, $stmt->valueVar, $stmt->expr, $value_type, $foreach_context, $doc_comment, $stmt->valueVar instanceof PhpParser\Node\Expr\Variable && is_string($stmt->valueVar->name) ? ['$' . $stmt->valueVar->name => \true] : []); if ($stmt->byRef && $stmt->valueVar instanceof PhpParser\Node\Expr\Variable && is_string($stmt->valueVar->name)) { // TODO support references with destructuring $foreach_context->references_to_external_scope['$' . $stmt->valueVar->name] = \true; } foreach ($var_comments as $var_comment) { if (!$var_comment->var_id || !$var_comment->type) { continue; } $comment_type = TypeExpander::expandUnion($codebase, $var_comment->type, $context->self, $context->self, $statements_analyzer->getParentFQCLN()); if (isset($foreach_context->vars_in_scope[$var_comment->var_id])) { $existing_var_type = $foreach_context->vars_in_scope[$var_comment->var_id]; /** @psalm-suppress InaccessibleProperty We just created this type */ $comment_type->parent_nodes = $existing_var_type->parent_nodes; /** @psalm-suppress InaccessibleProperty We just created this type */ $comment_type->by_ref = $existing_var_type->by_ref; } $foreach_context->vars_in_scope[$var_comment->var_id] = $comment_type; } $loop_scope = new LoopScope($foreach_context, $context); $loop_scope->protected_var_ids = $context->protected_var_ids; if (\Psalm\Internal\Analyzer\Statements\Block\LoopAnalyzer::analyze($statements_analyzer, $stmt->stmts, [], [], $loop_scope, $inner_loop_context, \false, $always_non_empty_array) === \false) { return \false; } if (!$inner_loop_context) { throw new UnexpectedValueException('There should be an inner loop context'); } $foreach_context->loop_scope = null; $context->vars_possibly_in_scope = array_merge($foreach_context->vars_possibly_in_scope, $context->vars_possibly_in_scope); if ($context->collect_exceptions) { $context->mergeExceptions($foreach_context); } return null; } /** * @param PhpParser\Node\Stmt\Foreach_|PhpParser\Node\Expr\YieldFrom $stmt * @return false|null */ public static function checkIteratorType(StatementsAnalyzer $statements_analyzer, PhpParser\NodeAbstract $stmt, PhpParser\Node\Expr $expr, Union $iterator_type, Codebase $codebase, Context $context, ?Union &$key_type, ?Union &$value_type, bool &$always_non_empty_array) : ?bool { if ($iterator_type->isNull()) { IssueBuffer::maybeAdd(new NullIterator('Cannot iterate over null', new CodeLocation($statements_analyzer->getSource(), $expr)), $statements_analyzer->getSuppressedIssues()); return \false; } if ($iterator_type->isNullable() && !$iterator_type->ignore_nullable_issues) { IssueBuffer::maybeAdd(new PossiblyNullIterator('Cannot iterate over nullable var ' . $iterator_type, new CodeLocation($statements_analyzer->getSource(), $expr)), $statements_analyzer->getSuppressedIssues()); return null; } if ($iterator_type->isFalsable() && !$iterator_type->ignore_falsable_issues) { IssueBuffer::maybeAdd(new PossiblyFalseIterator('Cannot iterate over falsable var ' . $iterator_type, new CodeLocation($statements_analyzer->getSource(), $expr)), $statements_analyzer->getSuppressedIssues()); return null; } $has_valid_iterator = \false; $invalid_iterator_types = []; $raw_object_types = []; foreach ($iterator_type->getAtomicTypes() as $iterator_atomic_type) { if ($iterator_atomic_type instanceof TTemplateParam) { $iterator_atomic_type = $iterator_atomic_type->as->getSingleAtomic(); } // if it's an empty array, we cannot iterate over it if ($iterator_atomic_type instanceof TArray && $iterator_atomic_type->isEmptyArray()) { $always_non_empty_array = \false; $has_valid_iterator = \true; continue; } if ($iterator_atomic_type instanceof TNull || $iterator_atomic_type instanceof TFalse) { $always_non_empty_array = \false; continue; } if ($iterator_atomic_type instanceof TArray || $iterator_atomic_type instanceof TKeyedArray || $iterator_atomic_type instanceof TList) { if ($iterator_atomic_type instanceof TList) { $iterator_atomic_type = $iterator_atomic_type->getKeyedArray(); } if ($iterator_atomic_type instanceof TKeyedArray) { if (!$iterator_atomic_type->isNonEmpty()) { $always_non_empty_array = \false; } $iterator_atomic_type = $iterator_atomic_type->getGenericArrayType(\true, ExpressionIdentifier::getExtendedVarId($expr, $statements_analyzer->getFQCLN(), $statements_analyzer)); } elseif (!$iterator_atomic_type instanceof TNonEmptyArray) { $always_non_empty_array = \false; } $value_type = Type::combineUnionTypes($value_type, $iterator_atomic_type->type_params[1]); $key_type_part = $iterator_atomic_type->type_params[0]; $key_type = Type::combineUnionTypes($key_type, $key_type_part); ArrayFetchAnalyzer::taintArrayFetch($statements_analyzer, $expr, null, $value_type, $key_type); $has_valid_iterator = \true; continue; } $always_non_empty_array = \false; if ($iterator_atomic_type instanceof Scalar || $iterator_atomic_type instanceof TVoid) { $invalid_iterator_types[] = $iterator_atomic_type->getKey(); $value_type = Type::getMixed(); } elseif ($iterator_atomic_type instanceof TObject || $iterator_atomic_type instanceof TMixed || $iterator_atomic_type instanceof TNever) { $has_valid_iterator = \true; $value_type = Type::getMixed(); $key_type = Type::getMixed(); ArrayFetchAnalyzer::taintArrayFetch($statements_analyzer, $expr, null, $value_type, $key_type); if (!$context->pure) { if ($statements_analyzer->getSource() instanceof FunctionLikeAnalyzer && $statements_analyzer->getSource()->track_mutations) { $statements_analyzer->getSource()->inferred_has_mutation = \true; $statements_analyzer->getSource()->inferred_impure = \true; } } else { IssueBuffer::maybeAdd(new ImpureMethodCall('Cannot call a possibly-mutating iterator from a pure context', new CodeLocation($statements_analyzer, $stmt)), $statements_analyzer->getSuppressedIssues()); } } elseif ($iterator_atomic_type instanceof TIterable) { if ($iterator_atomic_type->extra_types) { $iterator_atomic_types = array_merge([$iterator_atomic_type->setIntersectionTypes([])], $iterator_atomic_type->extra_types); } else { $iterator_atomic_types = [$iterator_atomic_type]; } $intersection_value_type = null; $intersection_key_type = null; foreach ($iterator_atomic_types as $iat) { if (!$iat instanceof TIterable) { continue; } [$key_type_part, $value_type_part] = $iat->type_params; if (!$intersection_value_type) { $intersection_value_type = $value_type_part; } else { $intersection_value_type = Type::intersectUnionTypes($intersection_value_type, $value_type_part, $codebase) ?? Type::getMixed(); } if (!$intersection_key_type) { $intersection_key_type = $key_type_part; } else { $intersection_key_type = Type::intersectUnionTypes($intersection_key_type, $key_type_part, $codebase) ?? Type::getMixed(); } } if (!$intersection_value_type || !$intersection_key_type) { throw new UnexpectedValueException('Should not happen'); } $value_type = Type::combineUnionTypes($value_type, $intersection_value_type); $key_type = Type::combineUnionTypes($key_type, $intersection_key_type); ArrayFetchAnalyzer::taintArrayFetch($statements_analyzer, $expr, null, $value_type, $key_type); $has_valid_iterator = \true; if (!$context->pure) { if ($statements_analyzer->getSource() instanceof FunctionLikeAnalyzer && $statements_analyzer->getSource()->track_mutations) { $statements_analyzer->getSource()->inferred_has_mutation = \true; $statements_analyzer->getSource()->inferred_impure = \true; } } else { IssueBuffer::maybeAdd(new ImpureMethodCall('Cannot call a possibly-mutating Traversable::getIterator from a pure context', new CodeLocation($statements_analyzer, $stmt)), $statements_analyzer->getSuppressedIssues()); } } elseif ($iterator_atomic_type instanceof TNamedObject) { if ($iterator_atomic_type->value !== 'Traversable' && $iterator_atomic_type->value !== $statements_analyzer->getClassName()) { if (ClassLikeAnalyzer::checkFullyQualifiedClassLikeName($statements_analyzer, $iterator_atomic_type->value, new CodeLocation($statements_analyzer->getSource(), $expr), $context->self, $context->calling_method_id, $statements_analyzer->getSuppressedIssues(), new ClassLikeNameOptions(\true)) === \false) { return \false; } } if (AtomicTypeComparator::isContainedBy($codebase, $iterator_atomic_type, new TIterable([Type::getMixed(), Type::getMixed()]))) { self::handleIterable($statements_analyzer, $iterator_atomic_type, $expr, $codebase, $context, $key_type, $value_type, $has_valid_iterator, $invalid_iterator_types); } else { $raw_object_types[] = $iterator_atomic_type->value; } if (!$context->pure) { if ($statements_analyzer->getSource() instanceof FunctionLikeAnalyzer && $statements_analyzer->getSource()->track_mutations) { $statements_analyzer->getSource()->inferred_has_mutation = \true; $statements_analyzer->getSource()->inferred_impure = \true; } } else { IssueBuffer::maybeAdd(new ImpureMethodCall('Cannot call a possibly-mutating iterator from a pure context', new CodeLocation($statements_analyzer, $stmt)), $statements_analyzer->getSuppressedIssues()); } } } if ($raw_object_types) { if ($has_valid_iterator) { IssueBuffer::maybeAdd(new PossibleRawObjectIteration('Possibly undesired iteration over regular object ' . reset($raw_object_types), new CodeLocation($statements_analyzer->getSource(), $expr)), $statements_analyzer->getSuppressedIssues()); } else { IssueBuffer::maybeAdd(new RawObjectIteration('Possibly undesired iteration over regular object ' . reset($raw_object_types), new CodeLocation($statements_analyzer->getSource(), $expr)), $statements_analyzer->getSuppressedIssues()); } } if ($invalid_iterator_types) { if ($has_valid_iterator) { IssueBuffer::maybeAdd(new PossiblyInvalidIterator('Cannot iterate over ' . $invalid_iterator_types[0], new CodeLocation($statements_analyzer->getSource(), $expr)), $statements_analyzer->getSuppressedIssues()); } else { IssueBuffer::maybeAdd(new InvalidIterator('Cannot iterate over ' . $invalid_iterator_types[0], new CodeLocation($statements_analyzer->getSource(), $expr)), $statements_analyzer->getSuppressedIssues()); } } return null; } /** @param list $invalid_iterator_types */ public static function handleIterable(StatementsAnalyzer $statements_analyzer, TNamedObject $iterator_atomic_type, PhpParser\Node\Expr $foreach_expr, Codebase $codebase, Context $context, ?Union &$key_type, ?Union &$value_type, bool &$has_valid_iterator, array &$invalid_iterator_types = []) : void { if ($iterator_atomic_type->extra_types) { $iterator_atomic_types = array_merge([$iterator_atomic_type->setIntersectionTypes([])], $iterator_atomic_type->extra_types); } else { $iterator_atomic_types = [$iterator_atomic_type]; } foreach ($iterator_atomic_types as $iterator_atomic_type) { if ($iterator_atomic_type instanceof TTemplateParam || $iterator_atomic_type instanceof TObjectWithProperties || $iterator_atomic_type instanceof TCallableObject) { throw new UnexpectedValueException('Shouldn’t get a generic param here'); } if ($iterator_atomic_type instanceof TIterable || (strtolower($iterator_atomic_type->value) === 'traversable' || $codebase->classImplements($iterator_atomic_type->value, 'Traversable') || $codebase->interfaceExists($iterator_atomic_type->value) && $codebase->interfaceExtends($iterator_atomic_type->value, 'Traversable'))) { if (strtolower($iterator_atomic_type->value) === 'iteratoraggregate' || $codebase->classImplements($iterator_atomic_type->value, 'IteratorAggregate') || $codebase->interfaceExists($iterator_atomic_type->value) && $codebase->interfaceExtends($iterator_atomic_type->value, 'IteratorAggregate')) { $has_valid_iterator = \true; $old_data_provider = $statements_analyzer->node_data; $statements_analyzer->node_data = clone $statements_analyzer->node_data; $fake_method_call = new VirtualMethodCall($foreach_expr, new VirtualIdentifier('getIterator', $foreach_expr->getAttributes())); $suppressed_issues = $statements_analyzer->getSuppressedIssues(); if (!in_array('PossiblyInvalidMethodCall', $suppressed_issues, \true)) { $statements_analyzer->addSuppressedIssues(['PossiblyInvalidMethodCall']); } if (!in_array('PossiblyUndefinedMethod', $suppressed_issues, \true)) { $statements_analyzer->addSuppressedIssues(['PossiblyUndefinedMethod']); } $was_inside_call = $context->inside_call; $context->inside_call = \true; MethodCallAnalyzer::analyze($statements_analyzer, $fake_method_call, $context); $context->inside_call = $was_inside_call; if (!in_array('PossiblyInvalidMethodCall', $suppressed_issues, \true)) { $statements_analyzer->removeSuppressedIssues(['PossiblyInvalidMethodCall']); } if (!in_array('PossiblyUndefinedMethod', $suppressed_issues, \true)) { $statements_analyzer->removeSuppressedIssues(['PossiblyUndefinedMethod']); } $iterator_class_type = $statements_analyzer->node_data->getType($fake_method_call) ?? null; $statements_analyzer->node_data = $old_data_provider; if ($iterator_class_type) { foreach ($iterator_class_type->getAtomicTypes() as $array_atomic_type) { $key_type_part = null; $value_type_part = null; if ($array_atomic_type instanceof TArray || $array_atomic_type instanceof TKeyedArray) { if ($array_atomic_type instanceof TKeyedArray) { $array_atomic_type = $array_atomic_type->getGenericArrayType(); } [$key_type_part, $value_type_part] = $array_atomic_type->type_params; } else { if ($array_atomic_type instanceof TNamedObject && $codebase->classExists($array_atomic_type->value) && $codebase->classImplements($array_atomic_type->value, 'Traversable')) { $generic_storage = $codebase->classlike_storage_provider->get($array_atomic_type->value); // The collection might be an iterator, in which case // we want to call the iterator function /** @psalm-suppress PossiblyUndefinedStringArrayOffset */ if (!isset($generic_storage->template_extended_params['Traversable']) || $generic_storage->template_extended_params['Traversable']['TKey']->isMixed() && $generic_storage->template_extended_params['Traversable']['TValue']->isMixed()) { self::handleIterable($statements_analyzer, $array_atomic_type, $fake_method_call, $codebase, $context, $key_type, $value_type, $has_valid_iterator, $invalid_iterator_types); continue; } } if ($array_atomic_type instanceof TIterable || $array_atomic_type instanceof TNamedObject && ($array_atomic_type->value === 'Traversable' || $codebase->classOrInterfaceExists($array_atomic_type->value) && $codebase->classImplements($array_atomic_type->value, 'Traversable'))) { self::getKeyValueParamsForTraversableObject($array_atomic_type, $codebase, $key_type_part, $value_type_part); } } if (!$key_type_part || !$value_type_part) { break; } $key_type = Type::combineUnionTypes($key_type, $key_type_part); $value_type = Type::combineUnionTypes($value_type, $value_type_part); } } } elseif ($iterator_atomic_type instanceof TGenericObject && strtolower($iterator_atomic_type->value) === 'generator') { $type_params = $iterator_atomic_type->type_params; if (isset($type_params[2]) && !$type_params[2]->isNullable() && !$type_params[2]->isMixed()) { $invalid_iterator_types[] = $iterator_atomic_type->getKey(); } else { $has_valid_iterator = \true; } $iterator_value_type = self::getFakeMethodCallType($statements_analyzer, $foreach_expr, $context, 'current'); $iterator_key_type = self::getFakeMethodCallType($statements_analyzer, $foreach_expr, $context, 'key'); if ($iterator_value_type && !$iterator_value_type->isMixed()) { // remove null coming from current() to signify invalid iterations // we're in a foreach context, so we know we're not going iterate past the end if (isset($type_params[1]) && !$type_params[1]->isNullable()) { $iterator_value_type = $iterator_value_type->getBuilder(); $iterator_value_type->removeType('null'); $iterator_value_type = $iterator_value_type->freeze(); } $value_type = Type::combineUnionTypes($value_type, $iterator_value_type); } if ($iterator_key_type && !$iterator_key_type->isMixed()) { // remove null coming from key() to signify invalid iterations // we're in a foreach context, so we know we're not going iterate past the end if (isset($type_params[0]) && !$type_params[0]->isNullable()) { $iterator_key_type = $iterator_key_type->getBuilder(); $iterator_key_type->removeType('null'); $iterator_key_type = $iterator_key_type->freeze(); } $key_type = Type::combineUnionTypes($key_type, $iterator_key_type); } } elseif ($codebase->classImplements($iterator_atomic_type->value, 'Iterator') || $codebase->interfaceExists($iterator_atomic_type->value) && $codebase->interfaceExtends($iterator_atomic_type->value, 'Iterator')) { $has_valid_iterator = \true; $iterator_value_type = self::getFakeMethodCallType($statements_analyzer, $foreach_expr, $context, 'current'); $iterator_key_type = self::getFakeMethodCallType($statements_analyzer, $foreach_expr, $context, 'key'); if ($iterator_value_type && !$iterator_value_type->isMixed()) { $value_type = Type::combineUnionTypes($value_type, $iterator_value_type); } if ($iterator_key_type && !$iterator_key_type->isMixed()) { $key_type = Type::combineUnionTypes($key_type, $iterator_key_type); } } if (!$key_type && !$value_type) { self::getKeyValueParamsForTraversableObject($iterator_atomic_type, $codebase, $key_type, $value_type); } return; } if (!$codebase->classlikes->classOrInterfaceExists($iterator_atomic_type->value)) { return; } } } public static function getKeyValueParamsForTraversableObject(Atomic $iterator_atomic_type, Codebase $codebase, ?Union &$key_type, ?Union &$value_type) : void { if ($iterator_atomic_type instanceof TIterable || $iterator_atomic_type instanceof TGenericObject && strtolower($iterator_atomic_type->value) === 'traversable') { assert(isset($iterator_atomic_type->type_params[1])); $value_type = Type::combineUnionTypes($value_type, $iterator_atomic_type->type_params[1]); $key_type = Type::combineUnionTypes($key_type, $iterator_atomic_type->type_params[0]); return; } if ($iterator_atomic_type instanceof TNamedObject && ($codebase->classImplements($iterator_atomic_type->value, 'Traversable') || $codebase->interfaceExtends($iterator_atomic_type->value, 'Traversable'))) { $generic_storage = $codebase->classlike_storage_provider->get($iterator_atomic_type->value); if (!isset($generic_storage->template_extended_params['Traversable'])) { return; } if ($generic_storage->template_types || $iterator_atomic_type instanceof TGenericObject) { // if we're just being passed the non-generic class itself, assume // that it's inside the calling class $passed_type_params = $iterator_atomic_type instanceof TGenericObject ? $iterator_atomic_type->type_params : array_values(array_map( /** @param array $arr */ static fn(array $arr): Union => $arr[$iterator_atomic_type->value] ?? Type::getMixed(), $generic_storage->template_types )); } else { $passed_type_params = null; } $key_type = self::getExtendedType('TKey', 'Traversable', $generic_storage->name, $generic_storage->template_extended_params, $generic_storage->template_types, $passed_type_params); $value_type = self::getExtendedType('TValue', 'Traversable', $generic_storage->name, $generic_storage->template_extended_params, $generic_storage->template_types, $passed_type_params); return; } } private static function getFakeMethodCallType(StatementsAnalyzer $statements_analyzer, PhpParser\Node\Expr $foreach_expr, Context $context, string $method_name) : ?Union { $old_data_provider = $statements_analyzer->node_data; $statements_analyzer->node_data = clone $statements_analyzer->node_data; $fake_method_call = new VirtualMethodCall($foreach_expr, new VirtualIdentifier($method_name, $foreach_expr->getAttributes())); $suppressed_issues = $statements_analyzer->getSuppressedIssues(); if (!in_array('PossiblyInvalidMethodCall', $suppressed_issues, \true)) { $statements_analyzer->addSuppressedIssues(['PossiblyInvalidMethodCall']); } if (!in_array('PossiblyUndefinedMethod', $suppressed_issues, \true)) { $statements_analyzer->addSuppressedIssues(['PossiblyUndefinedMethod']); } $was_inside_call = $context->inside_call; $context->inside_call = \true; MethodCallAnalyzer::analyze($statements_analyzer, $fake_method_call, $context); $context->inside_call = $was_inside_call; if (!in_array('PossiblyInvalidMethodCall', $suppressed_issues, \true)) { $statements_analyzer->removeSuppressedIssues(['PossiblyInvalidMethodCall']); } if (!in_array('PossiblyUndefinedMethod', $suppressed_issues, \true)) { $statements_analyzer->removeSuppressedIssues(['PossiblyUndefinedMethod']); } $iterator_class_type = $statements_analyzer->node_data->getType($fake_method_call) ?? null; $statements_analyzer->node_data = $old_data_provider; return $iterator_class_type; } /** * @param array> $template_extended_params * @param array> $class_template_types * @param array $calling_type_params */ private static function getExtendedType(string $template_name, string $template_class, string $calling_class, array $template_extended_params, ?array $class_template_types = null, ?array $calling_type_params = null) : ?Union { if ($calling_class === $template_class) { if (isset($class_template_types[$template_name]) && $calling_type_params) { $offset = array_search($template_name, array_keys($class_template_types), \true); if ($offset !== \false && isset($calling_type_params[$offset])) { return $calling_type_params[$offset]; } } return null; } if (isset($template_extended_params[$template_class][$template_name])) { $extended_type = $template_extended_params[$template_class][$template_name]; $return_type = null; foreach ($extended_type->getAtomicTypes() as $extended_atomic_type) { if (!$extended_atomic_type instanceof TTemplateParam) { $return_type = Type::combineUnionTypes($return_type, $extended_type); continue; } $candidate_type = self::getExtendedType($extended_atomic_type->param_name, $extended_atomic_type->defining_class, $calling_class, $template_extended_params, $class_template_types, $calling_type_params); if ($candidate_type) { $return_type = Type::combineUnionTypes($return_type, $candidate_type); } } if ($return_type) { return $return_type; } } return null; } } getCodebase(); if (!$else && !$if_scope->negated_clauses && !$else_context->clauses) { $if_scope->final_actions = array_merge([ScopeAnalyzer::ACTION_NONE], $if_scope->final_actions); $if_scope->assigned_var_ids = []; $if_scope->new_vars = []; $if_scope->redefined_vars = []; $if_scope->reasonable_clauses = []; return null; } $else_context->clauses = Algebra::simplifyCNF([...$else_context->clauses, ...$if_scope->negated_clauses]); $else_types = Algebra::getTruthsFromFormula($else_context->clauses); $original_context = clone $else_context; if ($else_types) { $changed_var_ids = []; [$else_context->vars_in_scope, $else_context->references_in_scope] = Reconciler::reconcileKeyedTypes($else_types, [], $else_context->vars_in_scope, $else_context->references_in_scope, $changed_var_ids, [], $statements_analyzer, $statements_analyzer->getTemplateTypeMap() ?: [], $else_context->inside_loop, $else ? new CodeLocation($statements_analyzer->getSource(), $else, $outer_context->include_location) : null); $else_context->clauses = Context::removeReconciledClauses($else_context->clauses, $changed_var_ids)[0]; foreach ($changed_var_ids as $changed_var_id => $_) { foreach ($else_context->vars_in_scope as $var_id => $_) { if (preg_match('/' . preg_quote($changed_var_id, '/') . '[\\]\\[\\-]/', $var_id) && !array_key_exists($var_id, $changed_var_ids)) { $else_context->removePossibleReference($var_id); } } } } $old_else_context = clone $else_context; $pre_stmts_assigned_var_ids = $else_context->assigned_var_ids; $else_context->assigned_var_ids = []; $pre_possibly_assigned_var_ids = $else_context->possibly_assigned_var_ids; $else_context->possibly_assigned_var_ids = []; if ($else) { if ($statements_analyzer->analyze($else->stmts, $else_context) === \false) { return \false; } } foreach ($else_context->parent_remove_vars as $var_id => $_) { $outer_context->removeVarFromConflictingClauses($var_id); } /** @var array */ $new_assigned_var_ids = $else_context->assigned_var_ids; $else_context->assigned_var_ids += $pre_stmts_assigned_var_ids; /** @var array */ $new_possibly_assigned_var_ids = $else_context->possibly_assigned_var_ids; $else_context->possibly_assigned_var_ids += $pre_possibly_assigned_var_ids; if ($else) { foreach ($else_context->byref_constraints as $var_id => $byref_constraint) { if (isset($outer_context->byref_constraints[$var_id]) && ($outer_constraint_type = $outer_context->byref_constraints[$var_id]->type) && $byref_constraint->type && !UnionTypeComparator::isContainedBy($codebase, $byref_constraint->type, $outer_constraint_type)) { IssueBuffer::maybeAdd(new ConflictingReferenceConstraint('There is more than one pass-by-reference constraint on ' . $var_id, new CodeLocation($statements_analyzer, $else, $outer_context->include_location, \true)), $statements_analyzer->getSuppressedIssues()); } else { $outer_context->byref_constraints[$var_id] = $byref_constraint; } } } $final_actions = $else ? ScopeAnalyzer::getControlActions($else->stmts, $statements_analyzer->node_data, []) : [ScopeAnalyzer::ACTION_NONE]; // has a return/throw at end $has_ending_statements = $final_actions === [ScopeAnalyzer::ACTION_END]; $has_leaving_statements = $has_ending_statements || count($final_actions) && !in_array(ScopeAnalyzer::ACTION_NONE, $final_actions, \true); $has_break_statement = $final_actions === [ScopeAnalyzer::ACTION_BREAK]; $has_continue_statement = $final_actions === [ScopeAnalyzer::ACTION_CONTINUE]; $if_scope->final_actions = array_merge($final_actions, $if_scope->final_actions); // if it doesn't end in a return if (!$has_leaving_statements) { \Psalm\Internal\Analyzer\Statements\Block\IfElse\IfAnalyzer::updateIfScope($codebase, $if_scope, $else_context, $original_context, $new_assigned_var_ids, $new_possibly_assigned_var_ids, $if_scope->if_cond_changed_var_ids, \true); $if_scope->reasonable_clauses = []; } // update the parent context as necessary if ($if_scope->negatable_if_types) { $outer_context->update($old_else_context, $else_context, $has_leaving_statements, array_keys($if_scope->negatable_if_types), $if_scope->updated_vars); } if (!$has_ending_statements) { $vars_possibly_in_scope = array_diff_key($else_context->vars_possibly_in_scope, $outer_context->vars_possibly_in_scope); $possibly_assigned_var_ids = $new_possibly_assigned_var_ids; if ($has_leaving_statements) { if ($else_context->loop_scope) { if (!$has_continue_statement && !$has_break_statement) { $if_scope->new_vars_possibly_in_scope = array_merge($vars_possibly_in_scope, $if_scope->new_vars_possibly_in_scope); } $else_context->loop_scope->vars_possibly_in_scope = array_merge($vars_possibly_in_scope, $else_context->loop_scope->vars_possibly_in_scope); } } else { $if_scope->new_vars_possibly_in_scope = array_merge($vars_possibly_in_scope, $if_scope->new_vars_possibly_in_scope); $if_scope->possibly_assigned_var_ids = array_merge($possibly_assigned_var_ids, $if_scope->possibly_assigned_var_ids); } } if ($outer_context->collect_exceptions) { $outer_context->mergeExceptions($else_context); } // Track references set in the else to make sure they aren't reused later $outer_context->updateReferencesPossiblyFromConfusingScope($else_context, $statements_analyzer); return null; } } cond, $else_context, $codebase, $if_scope, $branch_point); $elseif_context = $if_conditional_scope->if_context; $cond_referenced_var_ids = $if_conditional_scope->cond_referenced_var_ids; $assigned_in_conditional_var_ids = $if_conditional_scope->assigned_in_conditional_var_ids; } catch (ScopeAnalysisException $e) { return \false; } $mixed_var_ids = []; foreach ($elseif_context->vars_in_scope as $var_id => $type) { if ($type->hasMixed()) { $mixed_var_ids[] = $var_id; } } $elseif_cond_id = spl_object_id($elseif->cond); $elseif_clauses = FormulaGenerator::getFormula($elseif_cond_id, $elseif_cond_id, $elseif->cond, $else_context->self, $statements_analyzer, $codebase); $elseif_clauses_handled = []; foreach ($elseif_clauses as $clause) { $keys = array_keys($clause->possibilities); $mixed_var_ids = array_diff($mixed_var_ids, $keys); foreach ($keys as $key) { foreach ($mixed_var_ids as $mixed_var_id) { if (preg_match('/^' . preg_quote($mixed_var_id, '/') . '(\\[|-)/', $key)) { $elseif_clauses_handled[] = new Clause([], $elseif_cond_id, $elseif_cond_id, \true); break 2; } } } $elseif_clauses_handled[] = $clause; } $elseif_clauses = $elseif_clauses_handled; $entry_clauses = []; foreach ($if_conditional_scope->entry_clauses as $c) { foreach ($c->possibilities as $key => $_value) { foreach ($assigned_in_conditional_var_ids as $conditional_assigned_var_id => $_) { if (preg_match('/^' . preg_quote($conditional_assigned_var_id, '/') . '(\\[|-|$)/', $key)) { $entry_clauses[] = new Clause([], $elseif_cond_id, $elseif_cond_id, \true); break 2; } } } $entry_clauses[] = $c; } // this will see whether any of the clauses in set A conflict with the clauses in set B AlgebraAnalyzer::checkForParadox($entry_clauses, $elseif_clauses, $statements_analyzer, $elseif->cond, $assigned_in_conditional_var_ids); $elseif_context_clauses = [...$entry_clauses, ...$elseif_clauses]; if ($elseif_context->reconciled_expression_clauses) { $reconciled_expression_clauses = $elseif_context->reconciled_expression_clauses; $elseif_context_clauses = array_values(array_filter($elseif_context_clauses, static fn(Clause $c): bool => !in_array($c->hash, $reconciled_expression_clauses, \true))); } $elseif_context->clauses = Algebra::simplifyCNF($elseif_context_clauses); $active_elseif_types = []; try { if (array_filter($entry_clauses, static fn(Clause $clause): bool => (bool) $clause->possibilities)) { $omit_keys = array_reduce( $entry_clauses, /** * @param array $carry * @return array */ static fn(array $carry, Clause $clause): array => array_merge($carry, array_keys($clause->possibilities)), [] ); $omit_keys = array_combine($omit_keys, $omit_keys); $omit_keys = array_diff_key($omit_keys, Algebra::getTruthsFromFormula($entry_clauses)); $cond_referenced_var_ids = array_diff_key($cond_referenced_var_ids, $omit_keys); } $reconcilable_elseif_types = Algebra::getTruthsFromFormula($elseif_context->clauses, spl_object_id($elseif->cond), $cond_referenced_var_ids, $active_elseif_types); $negated_elseif_types = Algebra::getTruthsFromFormula(Algebra::negateFormula($elseif_clauses)); } catch (ComplicatedExpressionException $e) { $reconcilable_elseif_types = []; $negated_elseif_types = []; } $all_negated_vars = array_unique([...array_keys($negated_elseif_types), ...array_keys($if_scope->negated_types)]); foreach ($all_negated_vars as $var_id) { if (isset($negated_elseif_types[$var_id])) { if (isset($if_scope->negated_types[$var_id])) { $if_scope->negated_types[$var_id] = [...$if_scope->negated_types[$var_id], ...$negated_elseif_types[$var_id]]; } else { $if_scope->negated_types[$var_id] = $negated_elseif_types[$var_id]; } } } $newly_reconciled_var_ids = []; // if the elseif has an || in the conditional, we cannot easily reason about it if ($reconcilable_elseif_types) { [$elseif_context->vars_in_scope, $elseif_context->references_in_scope] = Reconciler::reconcileKeyedTypes($reconcilable_elseif_types, $active_elseif_types, $elseif_context->vars_in_scope, $elseif_context->references_in_scope, $newly_reconciled_var_ids, $cond_referenced_var_ids, $statements_analyzer, $statements_analyzer->getTemplateTypeMap() ?: [], $elseif_context->inside_loop, new CodeLocation($statements_analyzer->getSource(), $elseif->cond instanceof PhpParser\Node\Expr\BooleanNot ? $elseif->cond->expr : $elseif->cond, $outer_context->include_location)); if ($newly_reconciled_var_ids) { $elseif_context->clauses = Context::removeReconciledClauses($elseif_context->clauses, $newly_reconciled_var_ids)[0]; foreach ($newly_reconciled_var_ids as $changed_var_id => $_) { foreach ($elseif_context->vars_in_scope as $var_id => $_) { if (preg_match('/' . preg_quote($changed_var_id, '/') . '[\\]\\[\\-]/', $var_id) && !array_key_exists($var_id, $newly_reconciled_var_ids) && !array_key_exists($var_id, $cond_referenced_var_ids)) { $elseif_context->removePossibleReference($var_id); } } } } } $pre_stmts_assigned_var_ids = $elseif_context->assigned_var_ids; $elseif_context->assigned_var_ids = []; $pre_stmts_possibly_assigned_var_ids = $elseif_context->possibly_assigned_var_ids; $elseif_context->possibly_assigned_var_ids = []; if ($statements_analyzer->analyze($elseif->stmts, $elseif_context) === \false) { return \false; } foreach ($elseif_context->parent_remove_vars as $var_id => $_) { $outer_context->removeVarFromConflictingClauses($var_id); } /** @var array */ $new_stmts_assigned_var_ids = $elseif_context->assigned_var_ids; $elseif_context->assigned_var_ids = $pre_stmts_assigned_var_ids + $new_stmts_assigned_var_ids; /** @var array */ $new_stmts_possibly_assigned_var_ids = $elseif_context->possibly_assigned_var_ids; $elseif_context->possibly_assigned_var_ids = $pre_stmts_possibly_assigned_var_ids + $new_stmts_possibly_assigned_var_ids; foreach ($elseif_context->byref_constraints as $var_id => $byref_constraint) { if (isset($outer_context->byref_constraints[$var_id]) && ($outer_constraint_type = $outer_context->byref_constraints[$var_id]->type) && $byref_constraint->type && !UnionTypeComparator::isContainedBy($codebase, $byref_constraint->type, $outer_constraint_type)) { IssueBuffer::maybeAdd(new ConflictingReferenceConstraint('There is more than one pass-by-reference constraint on ' . $var_id, new CodeLocation($statements_analyzer, $elseif, $outer_context->include_location, \true)), $statements_analyzer->getSuppressedIssues()); } else { $outer_context->byref_constraints[$var_id] = $byref_constraint; } } $final_actions = ScopeAnalyzer::getControlActions($elseif->stmts, $statements_analyzer->node_data, []); // has a return/throw at end $has_ending_statements = $final_actions === [ScopeAnalyzer::ACTION_END]; $has_leaving_statements = $has_ending_statements || count($final_actions) && !in_array(ScopeAnalyzer::ACTION_NONE, $final_actions, \true); $has_break_statement = $final_actions === [ScopeAnalyzer::ACTION_BREAK]; $has_continue_statement = $final_actions === [ScopeAnalyzer::ACTION_CONTINUE]; $if_scope->final_actions = array_merge($final_actions, $if_scope->final_actions); // update the parent context as necessary if (!$has_leaving_statements) { \Psalm\Internal\Analyzer\Statements\Block\IfElse\IfAnalyzer::updateIfScope($codebase, $if_scope, $elseif_context, $outer_context, array_merge($new_stmts_assigned_var_ids, $assigned_in_conditional_var_ids), $new_stmts_possibly_assigned_var_ids, $newly_reconciled_var_ids); $reasonable_clause_count = count($if_scope->reasonable_clauses); if ($reasonable_clause_count && $reasonable_clause_count < 20000 && $elseif_clauses) { $if_scope->reasonable_clauses = Algebra::combineOredClauses($if_scope->reasonable_clauses, $elseif_clauses, $elseif_cond_id); } else { $if_scope->reasonable_clauses = []; } } else { $if_scope->reasonable_clauses = []; } if ($negated_elseif_types) { if ($has_leaving_statements) { $newly_reconciled_var_ids = []; $implied_outer_context = clone $elseif_context; [$implied_outer_context->vars_in_scope, $implied_outer_context->references_in_scope] = Reconciler::reconcileKeyedTypes($negated_elseif_types, [], $pre_conditional_context->vars_in_scope, $pre_conditional_context->references_in_scope, $newly_reconciled_var_ids, [], $statements_analyzer, $statements_analyzer->getTemplateTypeMap() ?: [], $elseif_context->inside_loop, new CodeLocation($statements_analyzer->getSource(), $elseif, $outer_context->include_location)); } } if (!$has_ending_statements) { $vars_possibly_in_scope = array_diff_key($elseif_context->vars_possibly_in_scope, $outer_context->vars_possibly_in_scope); $possibly_assigned_var_ids = $new_stmts_possibly_assigned_var_ids; if ($has_leaving_statements && $elseif_context->loop_scope) { if (!$has_continue_statement && !$has_break_statement) { $if_scope->new_vars_possibly_in_scope = array_merge($vars_possibly_in_scope, $if_scope->new_vars_possibly_in_scope); $if_scope->possibly_assigned_var_ids = array_merge($possibly_assigned_var_ids, $if_scope->possibly_assigned_var_ids); } $elseif_context->loop_scope->vars_possibly_in_scope = array_merge($vars_possibly_in_scope, $elseif_context->loop_scope->vars_possibly_in_scope); } elseif (!$has_leaving_statements) { $if_scope->new_vars_possibly_in_scope = array_merge($vars_possibly_in_scope, $if_scope->new_vars_possibly_in_scope); $if_scope->possibly_assigned_var_ids = array_merge($possibly_assigned_var_ids, $if_scope->possibly_assigned_var_ids); } } if ($outer_context->collect_exceptions) { $outer_context->mergeExceptions($elseif_context); } try { $if_scope->negated_clauses = Algebra::simplifyCNF([...$if_scope->negated_clauses, ...Algebra::negateFormula($elseif_clauses)]); } catch (ComplicatedExpressionException $e) { $if_scope->negated_clauses = []; } // Track references set in the elseif to make sure they aren't reused later $outer_context->updateReferencesPossiblyFromConfusingScope($elseif_context, $statements_analyzer); return null; } } $pre_assignment_else_redefined_vars * @return false|null */ public static function analyze(StatementsAnalyzer $statements_analyzer, PhpParser\Node\Stmt\If_ $stmt, IfScope $if_scope, IfConditionalScope $if_conditional_scope, Context $if_context, Context $outer_context, array $pre_assignment_else_redefined_vars) : ?bool { $cond_referenced_var_ids = $if_conditional_scope->cond_referenced_var_ids; $active_if_types = []; $reconcilable_if_types = Algebra::getTruthsFromFormula($if_context->clauses, spl_object_id($stmt->cond), $cond_referenced_var_ids, $active_if_types); if (array_filter($outer_context->clauses, static fn(Clause $clause): bool => (bool) $clause->possibilities)) { $omit_keys = array_reduce( $outer_context->clauses, /** * @param array $carry * @return array */ static fn(array $carry, Clause $clause): array => array_merge($carry, array_keys($clause->possibilities)), [] ); $omit_keys = array_combine($omit_keys, $omit_keys); $omit_keys = array_diff_key($omit_keys, Algebra::getTruthsFromFormula($outer_context->clauses)); $cond_referenced_var_ids = array_diff_key($cond_referenced_var_ids, $omit_keys); } // if the if has an || in the conditional, we cannot easily reason about it if ($reconcilable_if_types) { $changed_var_ids = []; [$if_context->vars_in_scope, $if_context->references_in_scope] = Reconciler::reconcileKeyedTypes($reconcilable_if_types, $active_if_types, $if_context->vars_in_scope, $if_context->references_in_scope, $changed_var_ids, $cond_referenced_var_ids, $statements_analyzer, $statements_analyzer->getTemplateTypeMap() ?: [], $if_context->inside_loop, $outer_context->check_variables ? new CodeLocation($statements_analyzer->getSource(), $stmt->cond instanceof PhpParser\Node\Expr\BooleanNot ? $stmt->cond->expr : $stmt->cond, $outer_context->include_location) : null); foreach ($reconcilable_if_types as $var_id => $_) { $if_context->vars_possibly_in_scope[$var_id] = \true; } if ($changed_var_ids) { $if_context->clauses = Context::removeReconciledClauses($if_context->clauses, $changed_var_ids)[0]; foreach ($changed_var_ids as $changed_var_id => $_) { foreach ($if_context->vars_in_scope as $var_id => $_) { if (preg_match('/' . preg_quote($changed_var_id, '/') . '[\\]\\[\\-]/', $var_id) && !array_key_exists($var_id, $changed_var_ids) && !array_key_exists($var_id, $cond_referenced_var_ids)) { $if_context->removePossibleReference($var_id); } } } } $if_scope->if_cond_changed_var_ids = $changed_var_ids; } $if_context->reconciled_expression_clauses = []; $outer_context->vars_possibly_in_scope = array_merge($if_context->vars_possibly_in_scope, $outer_context->vars_possibly_in_scope); $old_if_context = clone $if_context; $codebase = $statements_analyzer->getCodebase(); $assigned_var_ids = $if_context->assigned_var_ids; $possibly_assigned_var_ids = $if_context->possibly_assigned_var_ids; $if_context->assigned_var_ids = []; $if_context->possibly_assigned_var_ids = []; if ($statements_analyzer->analyze($stmt->stmts, $if_context) === \false) { return \false; } foreach ($if_context->parent_remove_vars as $var_id => $_) { $outer_context->removeVarFromConflictingClauses($var_id); } $if_scope->if_actions = $final_actions = ScopeAnalyzer::getControlActions($stmt->stmts, $statements_analyzer->node_data, []); $has_ending_statements = $final_actions === [ScopeAnalyzer::ACTION_END]; $has_leaving_statements = $has_ending_statements || count($final_actions) && !in_array(ScopeAnalyzer::ACTION_NONE, $final_actions, \true); $has_break_statement = $final_actions === [ScopeAnalyzer::ACTION_BREAK]; $has_continue_statement = $final_actions === [ScopeAnalyzer::ACTION_CONTINUE]; $if_scope->if_actions = $final_actions; $if_scope->final_actions = $final_actions; /** @var array */ $new_assigned_var_ids = $if_context->assigned_var_ids; /** @var array */ $new_possibly_assigned_var_ids = $if_context->possibly_assigned_var_ids; $if_context->assigned_var_ids = array_merge($assigned_var_ids, $new_assigned_var_ids); $if_context->possibly_assigned_var_ids = array_merge($possibly_assigned_var_ids, $new_possibly_assigned_var_ids); foreach ($if_context->byref_constraints as $var_id => $byref_constraint) { if (isset($outer_context->byref_constraints[$var_id]) && $byref_constraint->type && ($outer_constraint_type = $outer_context->byref_constraints[$var_id]->type) && !UnionTypeComparator::isContainedBy($codebase, $byref_constraint->type, $outer_constraint_type)) { IssueBuffer::maybeAdd(new ConflictingReferenceConstraint('There is more than one pass-by-reference constraint on ' . $var_id . ' between ' . $byref_constraint->type->getId() . ' and ' . $outer_constraint_type->getId(), new CodeLocation($statements_analyzer, $stmt, $outer_context->include_location, \true)), $statements_analyzer->getSuppressedIssues()); } else { $outer_context->byref_constraints[$var_id] = $byref_constraint; } } if (!$has_leaving_statements) { self::updateIfScope($codebase, $if_scope, $if_context, $outer_context, $new_assigned_var_ids, $new_possibly_assigned_var_ids, $if_scope->if_cond_changed_var_ids); if ($if_scope->reasonable_clauses) { // remove all reasonable clauses that would be negated by the if stmts foreach ($new_assigned_var_ids as $var_id => $_) { $if_scope->reasonable_clauses = Context::filterClauses($var_id, $if_scope->reasonable_clauses, $if_context->vars_in_scope[$var_id] ?? null, $statements_analyzer); } } } else { if (!$has_break_statement) { $if_scope->reasonable_clauses = []; // If we're assigning inside if ($if_conditional_scope->assigned_in_conditional_var_ids && $if_scope->post_leaving_if_context) { self::addConditionallyAssignedVarsToContext($statements_analyzer, $stmt->cond, $if_scope->post_leaving_if_context, $outer_context, $if_conditional_scope->assigned_in_conditional_var_ids); } } } // update the parent context as necessary, but only if we can safely reason about type negation. // We only update vars that changed both at the start of the if block and then again by an assignment // in the if statement. if ($if_scope->negated_types) { $vars_to_update = array_intersect(array_keys($pre_assignment_else_redefined_vars), array_keys($if_scope->negated_types)); $outer_context->update($old_if_context, $if_context, $has_leaving_statements, $vars_to_update, $if_scope->updated_vars); } if (!$has_ending_statements) { $vars_possibly_in_scope = array_diff_key($if_context->vars_possibly_in_scope, $outer_context->vars_possibly_in_scope); if ($if_context->loop_scope) { if (!$has_continue_statement && !$has_break_statement) { $if_scope->new_vars_possibly_in_scope = $vars_possibly_in_scope; } $if_context->loop_scope->vars_possibly_in_scope = array_merge($vars_possibly_in_scope, $if_context->loop_scope->vars_possibly_in_scope); } elseif (!$has_leaving_statements) { $if_scope->new_vars_possibly_in_scope = $vars_possibly_in_scope; } } if ($outer_context->collect_exceptions) { $outer_context->mergeExceptions($if_context); } // Track references set in the if to make sure they aren't reused later $outer_context->updateReferencesPossiblyFromConfusingScope($if_context, $statements_analyzer); return null; } /** * @param array $assigned_in_conditional_var_ids */ public static function addConditionallyAssignedVarsToContext(StatementsAnalyzer $statements_analyzer, PhpParser\Node\Expr $cond, Context $post_leaving_if_context, Context $post_if_context, array $assigned_in_conditional_var_ids) : void { // this filters out coercions to expected types in ArgumentAnalyzer $assigned_in_conditional_var_ids = array_filter($assigned_in_conditional_var_ids); if (!$assigned_in_conditional_var_ids) { return; } $exprs = self::getDefinitelyEvaluatedOredExpressions($cond); // if there was no assignment in the first expression it's safe to proceed $old_node_data = $statements_analyzer->node_data; $statements_analyzer->node_data = clone $old_node_data; IssueBuffer::startRecording(); foreach ($exprs as $expr) { if ($expr instanceof PhpParser\Node\Expr\BinaryOp\BooleanAnd) { $fake_not = new VirtualBooleanOr(self::negateExpr($expr->left), self::negateExpr($expr->right), $expr->getAttributes()); } else { $fake_not = self::negateExpr($expr); } $fake_negated_expr = new VirtualFuncCall(new VirtualFullyQualified('assert'), [new VirtualArg($fake_not, \false, \false, $expr->getAttributes())], $expr->getAttributes()); $post_leaving_if_context->inside_negation = !$post_leaving_if_context->inside_negation; ExpressionAnalyzer::analyze($statements_analyzer, $fake_negated_expr, $post_leaving_if_context); $post_leaving_if_context->inside_negation = !$post_leaving_if_context->inside_negation; } IssueBuffer::clearRecordingLevel(); IssueBuffer::stopRecording(); $statements_analyzer->node_data = $old_node_data; foreach ($assigned_in_conditional_var_ids as $var_id => $_) { if (isset($post_leaving_if_context->vars_in_scope[$var_id])) { $post_if_context->vars_in_scope[$var_id] = $post_leaving_if_context->vars_in_scope[$var_id]; } } } /** * Returns all expressions inside an ored expression * * @return non-empty-list */ private static function getDefinitelyEvaluatedOredExpressions(PhpParser\Node\Expr $stmt) : array { if ($stmt instanceof PhpParser\Node\Expr\BinaryOp\BooleanOr || $stmt instanceof PhpParser\Node\Expr\BinaryOp\LogicalOr || $stmt instanceof PhpParser\Node\Expr\BinaryOp\LogicalXor) { return [...self::getDefinitelyEvaluatedOredExpressions($stmt->left), ...self::getDefinitelyEvaluatedOredExpressions($stmt->right)]; } return [$stmt]; } private static function negateExpr(PhpParser\Node\Expr $expr) : PhpParser\Node\Expr { if ($expr instanceof PhpParser\Node\Expr\BooleanNot) { return $expr->expr; } return new VirtualBooleanNot($expr, $expr->getAttributes()); } /** * @param array $assigned_var_ids * @param array $possibly_assigned_var_ids * @param array $newly_reconciled_var_ids */ public static function updateIfScope(Codebase $codebase, IfScope $if_scope, Context $if_context, Context $outer_context, array $assigned_var_ids, array $possibly_assigned_var_ids, array $newly_reconciled_var_ids, bool $update_new_vars = \true) : void { $redefined_vars = $if_context->getRedefinedVars($outer_context->vars_in_scope); if ($if_scope->new_vars === null) { if ($update_new_vars) { $if_scope->new_vars = array_diff_key($if_context->vars_in_scope, $outer_context->vars_in_scope); } } else { foreach ($if_scope->new_vars as $new_var => $type) { if (!$if_context->hasVariable($new_var)) { unset($if_scope->new_vars[$new_var]); } else { $if_scope->new_vars[$new_var] = Type::combineUnionTypes($type, $if_context->vars_in_scope[$new_var], $codebase); } } } $possibly_redefined_vars = $redefined_vars; foreach ($possibly_redefined_vars as $var_id => $_) { if (!isset($possibly_assigned_var_ids[$var_id]) && isset($newly_reconciled_var_ids[$var_id])) { unset($possibly_redefined_vars[$var_id]); } } if ($if_scope->assigned_var_ids === null) { $if_scope->assigned_var_ids = $assigned_var_ids; } else { $if_scope->assigned_var_ids = array_intersect_key($assigned_var_ids, $if_scope->assigned_var_ids); } $if_scope->possibly_assigned_var_ids += $possibly_assigned_var_ids; if ($if_scope->redefined_vars === null) { $if_scope->redefined_vars = $redefined_vars; $if_scope->possibly_redefined_vars = $possibly_redefined_vars; } else { foreach ($if_scope->redefined_vars as $redefined_var => $type) { if (!isset($redefined_vars[$redefined_var])) { unset($if_scope->redefined_vars[$redefined_var]); } else { $if_scope->redefined_vars[$redefined_var] = Type::combineUnionTypes($redefined_vars[$redefined_var], $type, $codebase); if (isset($outer_context->vars_in_scope[$redefined_var]) && $if_scope->redefined_vars[$redefined_var]->equals($outer_context->vars_in_scope[$redefined_var])) { unset($if_scope->redefined_vars[$redefined_var]); } } } foreach ($possibly_redefined_vars as $var => $type) { $if_scope->possibly_redefined_vars[$var] = Type::combineUnionTypes($type, $if_scope->possibly_redefined_vars[$var] ?? null, $codebase); } } } } alter_code) { $case_context->branch_point = $case_context->branch_point ?: (int) $stmt->getAttribute('startFilePos'); } $case_scope = $case_context->case_scope = new CaseScope($case_context); $case_equality_expr = null; $old_node_data = $statements_analyzer->node_data; $fake_switch_condition = \false; if ($switch_var_id && strpos($switch_var_id, '$__tmp_switch__') === 0) { $switch_condition = new VirtualVariable(substr($switch_var_id, 1), $stmt->cond->getAttributes()); $fake_switch_condition = \true; } else { $switch_condition = $stmt->cond; } if ($case->cond) { $was_inside_conditional = $case_context->inside_conditional; $case_context->inside_conditional = \true; if (ExpressionAnalyzer::analyze($statements_analyzer, $case->cond, $case_context) === \false) { unset($case_scope->parent_context); unset($case_context->case_scope); return \false; } $case_context->inside_conditional = $was_inside_conditional; $statements_analyzer->node_data = clone $statements_analyzer->node_data; $traverser = new PhpParser\NodeTraverser(); $traverser->addVisitor(new ConditionCloningVisitor($statements_analyzer->node_data)); /** @var PhpParser\Node\Expr */ $switch_condition = $traverser->traverse([$switch_condition])[0]; if ($fake_switch_condition) { $statements_analyzer->node_data->setType($switch_condition, $case_context->vars_in_scope[$switch_var_id] ?? Type::getMixed()); } if ($switch_condition instanceof PhpParser\Node\Expr\Variable && is_string($switch_condition->name) && isset($context->vars_in_scope['$' . $switch_condition->name])) { $switch_var_type = $context->vars_in_scope['$' . $switch_condition->name]; $type_statements = []; foreach ($switch_var_type->getAtomicTypes() as $type) { if ($type instanceof TDependentGetClass) { $type_statements[] = new VirtualFuncCall(new VirtualName(['get_class']), [new VirtualArg(new VirtualVariable(substr($type->typeof, 1), $stmt->cond->getAttributes()), \false, \false, $stmt->cond->getAttributes())], $stmt->cond->getAttributes()); } elseif ($type instanceof TDependentGetType) { $type_statements[] = new VirtualFuncCall(new VirtualName(['gettype']), [new VirtualArg(new VirtualVariable(substr($type->typeof, 1), $stmt->cond->getAttributes()), \false, \false, $stmt->cond->getAttributes())], $stmt->cond->getAttributes()); } elseif ($type instanceof TDependentGetDebugType) { $type_statements[] = new VirtualFuncCall(new VirtualName(['get_debug_type']), [new VirtualArg(new VirtualVariable(substr($type->typeof, 1), $stmt->cond->getAttributes()), \false, \false, $stmt->cond->getAttributes())], $stmt->cond->getAttributes()); } else { $type_statements = null; break; } } if ($type_statements && count($type_statements) === 1) { $switch_condition = $type_statements[0]; if ($fake_switch_condition) { $statements_analyzer->node_data->setType($switch_condition, $case_context->vars_in_scope[$switch_var_id] ?? Type::getMixed()); } } } if ($switch_condition instanceof PhpParser\Node\Expr\ConstFetch && $switch_condition->name->getParts() === ['true']) { $case_equality_expr = $case->cond; } elseif (($switch_condition_type = $statements_analyzer->node_data->getType($switch_condition)) && ($case_cond_type = $statements_analyzer->node_data->getType($case->cond)) && ($switch_condition_type->isString() && $case_cond_type->isString() || $switch_condition_type->isInt() && $case_cond_type->isInt() || $switch_condition_type->isFloat() && $case_cond_type->isFloat())) { $case_equality_expr = new VirtualIdentical($switch_condition, $case->cond, $case->cond->getAttributes()); } else { $case_equality_expr = new VirtualEqual($switch_condition, $case->cond, $case->cond->getAttributes()); } } $continue_case_equality_expr = \false; if ($case->stmts) { $case_stmts = array_merge($switch_scope->leftover_statements, $case->stmts); } else { $continue_case_equality_expr = count($switch_scope->leftover_statements) === 1; $case_stmts = $switch_scope->leftover_statements; } if (!$has_leaving_statements && !$is_last) { if (!$case_equality_expr) { $case_equality_expr = new VirtualFuncCall(new VirtualFullyQualified(['rand']), [new VirtualArg(new VirtualLNumber(0)), new VirtualArg(new VirtualLNumber(1))], $case->getAttributes()); } $switch_scope->leftover_case_equality_expr = $switch_scope->leftover_case_equality_expr ? new VirtualBooleanOr($switch_scope->leftover_case_equality_expr, $case_equality_expr, $case->cond ? $case->cond->getAttributes() : $case->getAttributes()) : $case_equality_expr; if ($continue_case_equality_expr && $switch_scope->leftover_statements[0] instanceof PhpParser\Node\Stmt\If_) { $case_if_stmt = $switch_scope->leftover_statements[0]; $case_if_stmt->cond = $switch_scope->leftover_case_equality_expr; } else { $case_if_stmt = new VirtualIf($switch_scope->leftover_case_equality_expr, ['stmts' => $case_stmts], $case->getAttributes()); $switch_scope->leftover_statements = [$case_if_stmt]; } unset($case_scope->parent_context); unset($case_context->case_scope); $statements_analyzer->node_data = $old_node_data; return null; } if ($switch_scope->leftover_case_equality_expr) { $case_or_default_equality_expr = $case_equality_expr; if (!$case_or_default_equality_expr) { $case_or_default_equality_expr = new VirtualFuncCall(new VirtualFullyQualified(['rand']), [new VirtualArg(new VirtualLNumber(0)), new VirtualArg(new VirtualLNumber(1))], $case->getAttributes()); } $case_equality_expr = new VirtualBooleanOr($switch_scope->leftover_case_equality_expr, $case_or_default_equality_expr, $case_or_default_equality_expr->getAttributes()); } if ($case_equality_expr && $switch_condition instanceof PhpParser\Node\Expr\Variable && is_string($switch_condition->name) && isset($context->vars_in_scope['$' . $switch_condition->name])) { $new_case_equality_expr = self::simplifyCaseEqualityExpression($case_equality_expr, $switch_condition); if ($new_case_equality_expr) { $was_inside_conditional = $case_context->inside_conditional; $case_context->inside_conditional = \true; ExpressionAnalyzer::analyze($statements_analyzer, $new_case_equality_expr->getArgs()[1]->value, $case_context); $case_context->inside_conditional = $was_inside_conditional; $case_equality_expr = $new_case_equality_expr; } } $case_context->break_types[] = 'switch'; $switch_scope->leftover_statements = []; $switch_scope->leftover_case_equality_expr = null; $case_clauses = []; if ($case_equality_expr) { $case_equality_expr_id = spl_object_id($case_equality_expr); $case_clauses = FormulaGenerator::getFormula($case_equality_expr_id, $case_equality_expr_id, $case_equality_expr, $context->self, $statements_analyzer, $codebase, \false, \false); } if ($switch_scope->negated_clauses && count($switch_scope->negated_clauses) < 50) { $entry_clauses = Algebra::simplifyCNF([...$original_context->clauses, ...$switch_scope->negated_clauses]); } else { $entry_clauses = $original_context->clauses; } if ($case_clauses && $case->cond) { // this will see whether any of the clauses in set A conflict with the clauses in set B AlgebraAnalyzer::checkForParadox($entry_clauses, $case_clauses, $statements_analyzer, $case->cond, []); if (count($entry_clauses) + count($case_clauses) < 50) { $case_context->clauses = Algebra::simplifyCNF([...$entry_clauses, ...$case_clauses]); } else { $case_context->clauses = [...$entry_clauses, ...$case_clauses]; } } else { $case_context->clauses = $entry_clauses; } $reconcilable_if_types = Algebra::getTruthsFromFormula($case_context->clauses); // if the if has an || in the conditional, we cannot easily reason about it if ($reconcilable_if_types) { $changed_var_ids = []; $suppressed_issues = $statements_analyzer->getSuppressedIssues(); if (!in_array('RedundantCondition', $suppressed_issues, \true)) { $statements_analyzer->addSuppressedIssues(['RedundantCondition']); } if (!in_array('RedundantConditionGivenDocblockType', $suppressed_issues, \true)) { $statements_analyzer->addSuppressedIssues(['RedundantConditionGivenDocblockType']); } [$case_vars_in_scope_reconciled, $case_references_in_scope_reconciled] = Reconciler::reconcileKeyedTypes($reconcilable_if_types, [], $case_context->vars_in_scope, $case_context->references_in_scope, $changed_var_ids, $case->cond && $switch_var_id ? [$switch_var_id => \true] : [], $statements_analyzer, [], $case_context->inside_loop, new CodeLocation($statements_analyzer->getSource(), $case->cond ?? $case, $context->include_location)); if (!in_array('RedundantCondition', $suppressed_issues, \true)) { $statements_analyzer->removeSuppressedIssues(['RedundantCondition']); } if (!in_array('RedundantConditionGivenDocblockType', $suppressed_issues, \true)) { $statements_analyzer->removeSuppressedIssues(['RedundantConditionGivenDocblockType']); } $case_context->vars_in_scope = $case_vars_in_scope_reconciled; $case_context->references_in_scope = $case_references_in_scope_reconciled; foreach ($reconcilable_if_types as $var_id => $_) { $case_context->vars_possibly_in_scope[$var_id] = \true; } if ($changed_var_ids) { $case_context->clauses = Context::removeReconciledClauses($case_context->clauses, $changed_var_ids)[0]; } } if ($case_clauses && $case_equality_expr) { try { $negated_case_clauses = Algebra::negateFormula($case_clauses); } catch (ComplicatedExpressionException $e) { $case_equality_expr_id = spl_object_id($case_equality_expr); try { $negated_case_clauses = FormulaGenerator::getFormula($case_equality_expr_id, $case_equality_expr_id, new VirtualBooleanNot($case_equality_expr), $context->self, $statements_analyzer, $codebase, \false, \false); } catch (ComplicatedExpressionException $e) { $negated_case_clauses = []; } } $switch_scope->negated_clauses = [...$switch_scope->negated_clauses, ...$negated_case_clauses]; } $statements_analyzer->analyze($case_stmts, $case_context); $traverser = new PhpParser\NodeTraverser(); $traverser->addVisitor(new TypeMappingVisitor($statements_analyzer->node_data, $old_node_data)); $traverser->traverse([$case]); $statements_analyzer->node_data = $old_node_data; if ($case_exit_type !== 'return_throw') { if (self::handleNonReturningCase($statements_analyzer, $switch_var_id, $case, $context, $case_context, $original_context, $case_exit_type, $switch_scope) === \false) { unset($case_scope->parent_context); unset($case_context->case_scope); return \false; } } // augment the information with data from break statements if ($case_scope->break_vars !== null) { if ($switch_scope->possibly_redefined_vars === null) { $switch_scope->possibly_redefined_vars = array_intersect_key($case_scope->break_vars, $context->vars_in_scope); } else { foreach ($case_scope->break_vars as $var_id => $type) { if (isset($context->vars_in_scope[$var_id])) { $switch_scope->possibly_redefined_vars[$var_id] = Type::combineUnionTypes($type, $switch_scope->possibly_redefined_vars[$var_id] ?? null); } } } if ($switch_scope->new_vars_in_scope !== null) { foreach ($switch_scope->new_vars_in_scope as $var_id => $type) { if (isset($case_scope->break_vars[$var_id])) { if (!isset($case_context->vars_in_scope[$var_id])) { unset($switch_scope->new_vars_in_scope[$var_id]); } else { $switch_scope->new_vars_in_scope[$var_id] = Type::combineUnionTypes($case_scope->break_vars[$var_id], $type); } } else { unset($switch_scope->new_vars_in_scope[$var_id]); } } } if ($switch_scope->redefined_vars !== null) { foreach ($switch_scope->redefined_vars as $var_id => $type) { if (isset($case_scope->break_vars[$var_id])) { $switch_scope->redefined_vars[$var_id] = Type::combineUnionTypes($case_scope->break_vars[$var_id], $type); } else { unset($switch_scope->redefined_vars[$var_id]); } } } } unset($case_scope->parent_context); unset($case_context->case_scope); return null; } /** * @return null|false */ private static function handleNonReturningCase(StatementsAnalyzer $statements_analyzer, ?string $switch_var_id, PhpParser\Node\Stmt\Case_ $case, Context $context, Context $case_context, Context $original_context, string $case_exit_type, SwitchScope $switch_scope) : ?bool { if (!$case->cond && $switch_var_id && isset($case_context->vars_in_scope[$switch_var_id]) && $case_context->vars_in_scope[$switch_var_id]->isNever()) { if (IssueBuffer::accepts(new ParadoxicalCondition('All possible case statements have been met, default is impossible here', new CodeLocation($statements_analyzer->getSource(), $case)), $statements_analyzer->getSuppressedIssues())) { return \false; } } // if we're leaving this block, add vars to outer for loop scope if ($case_exit_type === 'continue') { if (!$context->loop_scope) { if (IssueBuffer::accepts(new ContinueOutsideLoop('Continue called when not in loop', new CodeLocation($statements_analyzer->getSource(), $case)))) { return \false; } } } else { $case_redefined_vars = $case_context->getRedefinedVars($original_context->vars_in_scope); if ($switch_scope->possibly_redefined_vars === null) { $switch_scope->possibly_redefined_vars = $case_redefined_vars; } else { foreach ($case_redefined_vars as $var_id => $type) { $switch_scope->possibly_redefined_vars[$var_id] = Type::combineUnionTypes($type, $switch_scope->possibly_redefined_vars[$var_id] ?? null); } } if ($switch_scope->redefined_vars === null) { $switch_scope->redefined_vars = $case_redefined_vars; } else { foreach ($switch_scope->redefined_vars as $var_id => $type) { if (!isset($case_redefined_vars[$var_id])) { unset($switch_scope->redefined_vars[$var_id]); } else { $switch_scope->redefined_vars[$var_id] = Type::combineUnionTypes($type, $case_redefined_vars[$var_id]); } } } $context_new_vars = array_diff_key($case_context->vars_in_scope, $context->vars_in_scope); if ($switch_scope->new_vars_in_scope === null) { $switch_scope->new_vars_in_scope = $context_new_vars; $switch_scope->new_vars_possibly_in_scope = array_diff_key($case_context->vars_possibly_in_scope, $context->vars_possibly_in_scope); } else { foreach ($switch_scope->new_vars_in_scope as $new_var => $type) { if (!$case_context->hasVariable($new_var)) { unset($switch_scope->new_vars_in_scope[$new_var]); } else { $switch_scope->new_vars_in_scope[$new_var] = Type::combineUnionTypes($case_context->vars_in_scope[$new_var], $type); } } $switch_scope->new_vars_possibly_in_scope = array_merge(array_diff_key($case_context->vars_possibly_in_scope, $context->vars_possibly_in_scope), $switch_scope->new_vars_possibly_in_scope); } } if ($context->collect_exceptions) { $context->mergeExceptions($case_context); } return null; } private static function simplifyCaseEqualityExpression(PhpParser\Node\Expr $case_equality_expr, PhpParser\Node\Expr\Variable $var) : ?PhpParser\Node\Expr\FuncCall { if ($case_equality_expr instanceof PhpParser\Node\Expr\BinaryOp\BooleanOr) { $nested_or_options = self::getOptionsFromNestedOr($case_equality_expr, $var); if ($nested_or_options) { return new VirtualFuncCall(new VirtualFullyQualified(['in_array']), [new VirtualArg($var, \false, \false, $var->getAttributes()), new VirtualArg(new VirtualArray($nested_or_options, $case_equality_expr->getAttributes()), \false, \false, $case_equality_expr->getAttributes()), new VirtualArg(new VirtualConstFetch(new VirtualFullyQualified(['true'])))]); } } return null; } /** * @param array $in_array_values * @return ?array */ private static function getOptionsFromNestedOr(PhpParser\Node\Expr $case_equality_expr, PhpParser\Node\Expr\Variable $var, array $in_array_values = []) : ?array { if ($case_equality_expr instanceof PhpParser\Node\Expr\BinaryOp\Identical && $case_equality_expr->left instanceof PhpParser\Node\Expr\Variable && $case_equality_expr->left->name === $var->name) { $in_array_values[] = new VirtualArrayItem($case_equality_expr->right, null, \false, $case_equality_expr->right->getAttributes()); return $in_array_values; } if (!$case_equality_expr instanceof PhpParser\Node\Expr\BinaryOp\BooleanOr) { return null; } if (!$case_equality_expr->right instanceof PhpParser\Node\Expr\BinaryOp\Identical || !$case_equality_expr->right->left instanceof PhpParser\Node\Expr\Variable || $case_equality_expr->right->left->name !== $var->name) { return null; } $in_array_values[] = new VirtualArrayItem($case_equality_expr->right->right, null, \false, $case_equality_expr->right->right->getAttributes()); return self::getOptionsFromNestedOr($case_equality_expr->left, $var, $in_array_values); } } getCodebase(); $if_scope = new IfScope(); // We need to clone the original context for later use if we're exiting in this if conditional if ($stmt->cond instanceof PhpParser\Node\Expr\BinaryOp || $stmt->cond instanceof PhpParser\Node\Expr\BooleanNot && $stmt->cond->expr instanceof PhpParser\Node\Expr\BinaryOp) { $final_actions = ScopeAnalyzer::getControlActions($stmt->stmts, null, []); $has_leaving_statements = $final_actions === [ScopeAnalyzer::ACTION_END] || count($final_actions) && !in_array(ScopeAnalyzer::ACTION_NONE, $final_actions, \true); if ($has_leaving_statements) { $if_scope->post_leaving_if_context = clone $context; } } try { $if_conditional_scope = \Psalm\Internal\Analyzer\Statements\Block\IfConditionalAnalyzer::analyze($statements_analyzer, $stmt->cond, $context, $codebase, $if_scope, $context->branch_point ?: (int) $stmt->getAttribute('startFilePos')); // this is the context for stuff that happens within the `if` block $if_context = $if_conditional_scope->if_context; // this is the context for stuff that happens after the `if` block $post_if_context = $if_conditional_scope->post_if_context; $assigned_in_conditional_var_ids = $if_conditional_scope->assigned_in_conditional_var_ids; } catch (ScopeAnalysisException $e) { return \false; } $mixed_var_ids = []; foreach ($if_context->vars_in_scope as $var_id => $type) { if ($type->isMixed() && isset($context->vars_in_scope[$var_id])) { $mixed_var_ids[] = $var_id; } } $cond_object_id = spl_object_id($stmt->cond); $if_clauses = FormulaGenerator::getFormula($cond_object_id, $cond_object_id, $stmt->cond, $context->self, $statements_analyzer, $codebase); if (count($if_clauses) > 200) { $if_clauses = []; } $if_clauses_handled = []; foreach ($if_clauses as $clause) { $keys = array_keys($clause->possibilities); $mixed_var_ids = array_diff($mixed_var_ids, $keys); foreach ($keys as $key) { foreach ($mixed_var_ids as $mixed_var_id) { if (preg_match('/^' . preg_quote($mixed_var_id, '/') . '(\\[|-)/', $key)) { $clause = new Clause([], $cond_object_id, $cond_object_id, \true); break 2; } } } $if_clauses_handled[] = $clause; } $if_clauses = $if_clauses_handled; $entry_clauses = $context->clauses; // this will see whether any of the clauses in set A conflict with the clauses in set B AlgebraAnalyzer::checkForParadox($context->clauses, $if_clauses, $statements_analyzer, $stmt->cond, $assigned_in_conditional_var_ids); $if_clauses = Algebra::simplifyCNF($if_clauses); $if_context_clauses = [...$entry_clauses, ...$if_clauses]; $if_context->clauses = $entry_clauses ? Algebra::simplifyCNF($if_context_clauses) : $if_context_clauses; if ($if_context->reconciled_expression_clauses) { $reconciled_expression_clauses = $if_context->reconciled_expression_clauses; $if_context->clauses = array_values(array_filter($if_context->clauses, static fn(Clause $c): bool => !in_array($c->hash, $reconciled_expression_clauses))); if (count($if_context->clauses) === 1 && $if_context->clauses[0]->wedge && !$if_context->clauses[0]->possibilities) { $if_context->clauses = []; $if_context->reconciled_expression_clauses = []; } } // define this before we alter local clauses after reconciliation $if_scope->reasonable_clauses = $if_context->clauses; try { $if_scope->negated_clauses = Algebra::negateFormula($if_clauses); } catch (ComplicatedExpressionException $e) { try { $if_scope->negated_clauses = FormulaGenerator::getFormula($cond_object_id, $cond_object_id, new VirtualBooleanNot($stmt->cond), $context->self, $statements_analyzer, $codebase, \false); } catch (ComplicatedExpressionException $e) { $if_scope->negated_clauses = []; } } $if_scope->negated_types = Algebra::getTruthsFromFormula(Algebra::simplifyCNF([...$context->clauses, ...$if_scope->negated_clauses])); $temp_else_context = clone $post_if_context; $changed_var_ids = []; if ($if_scope->negated_types) { [$temp_else_context->vars_in_scope, $temp_else_context->references_in_scope] = Reconciler::reconcileKeyedTypes($if_scope->negated_types, [], $temp_else_context->vars_in_scope, $temp_else_context->references_in_scope, $changed_var_ids, [], $statements_analyzer, $statements_analyzer->getTemplateTypeMap() ?: [], $context->inside_loop, $context->check_variables ? new CodeLocation($statements_analyzer->getSource(), $stmt->cond instanceof PhpParser\Node\Expr\BooleanNot ? $stmt->cond->expr : $stmt->cond, $context->include_location) : null); } // we calculate the vars redefined in a hypothetical else statement to determine // which vars of the if we can safely change $pre_assignment_else_redefined_vars = array_intersect_key($temp_else_context->getRedefinedVars($context->vars_in_scope, \true), $changed_var_ids); // check the if if (IfAnalyzer::analyze($statements_analyzer, $stmt, $if_scope, $if_conditional_scope, $if_context, $context, $pre_assignment_else_redefined_vars) === \false) { return \false; } // this has to go on a separate line because the phar compactor messes with precedence $scope_to_clone = $if_scope->post_leaving_if_context ?? $post_if_context; $else_context = clone $scope_to_clone; $else_context->clauses = Algebra::simplifyCNF([...$else_context->clauses, ...$if_scope->negated_clauses]); // check the elseifs foreach ($stmt->elseifs as $elseif) { if (ElseIfAnalyzer::analyze($statements_analyzer, $elseif, $if_scope, $else_context, $context, $codebase, $else_context->branch_point ?: (int) $stmt->getAttribute('startFilePos')) === \false) { return \false; } } if ($stmt->else) { if ($codebase->alter_code) { $else_context->branch_point = $else_context->branch_point ?: (int) $stmt->getAttribute('startFilePos'); } } if (ElseAnalyzer::analyze($statements_analyzer, $stmt->else, $if_scope, $else_context, $context) === \false) { return \false; } if (count($if_scope->if_actions) && !in_array(ScopeAnalyzer::ACTION_NONE, $if_scope->if_actions, \true) && !$stmt->elseifs) { $context->clauses = $else_context->clauses; foreach ($else_context->vars_in_scope as $var_id => $type) { $context->vars_in_scope[$var_id] = $type; } foreach ($pre_assignment_else_redefined_vars as $var_id => $reconciled_type) { $first_appearance = $statements_analyzer->getFirstAppearance($var_id); if ($first_appearance && isset($post_if_context->vars_in_scope[$var_id]) && $post_if_context->vars_in_scope[$var_id]->hasMixed() && !$reconciled_type->hasMixed()) { if (!$post_if_context->collect_initializations && !$post_if_context->collect_mutations && $statements_analyzer->getFilePath() === $statements_analyzer->getRootFilePath()) { $parent_source = $statements_analyzer->getSource(); $functionlike_storage = $parent_source instanceof FunctionLikeAnalyzer ? $parent_source->getFunctionLikeStorage($statements_analyzer) : null; if (!$functionlike_storage || !$parent_source->getSource() instanceof TraitAnalyzer && !isset($functionlike_storage->param_lookup[substr($var_id, 1)])) { $codebase = $statements_analyzer->getCodebase(); $codebase->analyzer->decrementMixedCount($statements_analyzer->getFilePath()); } } IssueBuffer::remove($statements_analyzer->getFilePath(), 'MixedAssignment', $first_appearance->raw_file_start); } } } if ($context->loop_scope) { $context->loop_scope->final_actions = array_unique(array_merge($context->loop_scope->final_actions, $if_scope->final_actions)); } $context->vars_possibly_in_scope = array_merge($context->vars_possibly_in_scope, $if_scope->new_vars_possibly_in_scope); $context->possibly_assigned_var_ids = array_merge($context->possibly_assigned_var_ids, $if_scope->possibly_assigned_var_ids ?: []); // vars can only be defined/redefined if there was an else (defined in every block) $context->assigned_var_ids = array_merge($context->assigned_var_ids, $if_scope->assigned_var_ids ?: []); if ($if_scope->new_vars) { foreach ($if_scope->new_vars as $var_id => &$type) { if (isset($context->vars_possibly_in_scope[$var_id]) && $statements_analyzer->data_flow_graph) { $type = $type->addParentNodes($statements_analyzer->getParentNodesForPossiblyUndefinedVariable($var_id)); } $context->vars_in_scope[$var_id] = $type; } unset($type); } if ($if_scope->redefined_vars) { foreach ($if_scope->redefined_vars as $var_id => $type) { $context->vars_in_scope[$var_id] = $type; $if_scope->updated_vars[$var_id] = \true; if ($if_scope->reasonable_clauses) { $if_scope->reasonable_clauses = Context::filterClauses($var_id, $if_scope->reasonable_clauses, $context->vars_in_scope[$var_id] ?? null, $statements_analyzer); } } } if ($if_scope->reasonable_clauses && (count($if_scope->reasonable_clauses) > 1 || !$if_scope->reasonable_clauses[0]->wedge)) { $context->clauses = Algebra::simplifyCNF([...$if_scope->reasonable_clauses, ...$context->clauses]); } if ($if_scope->possibly_redefined_vars) { foreach ($if_scope->possibly_redefined_vars as $var_id => $type) { if (isset($context->vars_in_scope[$var_id])) { if (!$type->failed_reconciliation && !isset($if_scope->updated_vars[$var_id])) { $combined_type = Type::combineUnionTypes($context->vars_in_scope[$var_id], $type, $codebase); if (!$combined_type->equals($context->vars_in_scope[$var_id])) { $context->removeDescendents($var_id, $combined_type); } $context->vars_in_scope[$var_id] = $combined_type; } else { $context->vars_in_scope[$var_id] = $context->vars_in_scope[$var_id]->addParentNodes($type->parent_nodes); } } } } if (!in_array(ScopeAnalyzer::ACTION_NONE, $if_scope->final_actions, \true)) { $context->has_returned = \true; } return null; } } cond instanceof PhpParser\Node\Expr\ConstFetch && $stmt->cond->name->getParts() === ['true'] || ($t = $statements_analyzer->node_data->getType($stmt->cond)) && $t->isAlwaysTruthy(); $pre_context = null; if ($while_true) { $pre_context = clone $context; } $while_context = clone $context; $while_context->inside_loop = \true; $while_context->break_types[] = 'loop'; $codebase = $statements_analyzer->getCodebase(); if ($codebase->alter_code) { $while_context->branch_point = $while_context->branch_point ?: (int) $stmt->getAttribute('startFilePos'); } $loop_scope = new LoopScope($while_context, $context); $loop_scope->protected_var_ids = $context->protected_var_ids; if (\Psalm\Internal\Analyzer\Statements\Block\LoopAnalyzer::analyze($statements_analyzer, $stmt->stmts, self::getAndExpressions($stmt->cond), [], $loop_scope, $inner_loop_context) === \false) { return \false; } if (!$inner_loop_context) { throw new UnexpectedValueException('There should be an inner loop context'); } $always_enters_loop = \false; if ($stmt_cond_type = $statements_analyzer->node_data->getType($stmt->cond)) { $always_enters_loop = $stmt_cond_type->isAlwaysTruthy(); } if ($while_true) { $always_enters_loop = \true; } $can_leave_loop = !$while_true || in_array(ScopeAnalyzer::ACTION_BREAK, $loop_scope->final_actions, \true); if ($always_enters_loop && $can_leave_loop) { foreach ($inner_loop_context->vars_in_scope as $var_id => $type) { // if there are break statements in the loop it's not certain // that the loop has finished executing, so the assertions at the end // the loop in the while conditional may not hold if (in_array(ScopeAnalyzer::ACTION_BREAK, $loop_scope->final_actions, \true) || in_array(ScopeAnalyzer::ACTION_CONTINUE, $loop_scope->final_actions, \true)) { if (isset($loop_scope->possibly_defined_loop_parent_vars[$var_id])) { $context->vars_in_scope[$var_id] = Type::combineUnionTypes($type, $loop_scope->possibly_defined_loop_parent_vars[$var_id]); } } else { $context->vars_in_scope[$var_id] = $type; } } } $while_context->loop_scope = null; if ($can_leave_loop) { $context->vars_possibly_in_scope = array_merge($context->vars_possibly_in_scope, $while_context->vars_possibly_in_scope); } elseif ($pre_context) { $context->vars_possibly_in_scope = $pre_context->vars_possibly_in_scope; } if ($context->collect_exceptions) { $context->mergeExceptions($while_context); } return null; } /** * @return list */ public static function getAndExpressions(PhpParser\Node\Expr $expr) : array { if ($expr instanceof PhpParser\Node\Expr\BinaryOp\BooleanAnd) { return [...self::getAndExpressions($expr->left), ...self::getAndExpressions($expr->right)]; } return [$expr]; } } break_types[] = 'loop'; $do_context->inside_loop = \true; $codebase = $statements_analyzer->getCodebase(); if ($codebase->alter_code) { $do_context->branch_point = $do_context->branch_point ?: (int) $stmt->getAttribute('startFilePos'); } $loop_scope = new LoopScope($do_context, $context); $loop_scope->protected_var_ids = $context->protected_var_ids; self::analyzeDoNaively($statements_analyzer, $stmt, $do_context, $loop_scope); $mixed_var_ids = []; foreach ($do_context->vars_in_scope as $var_id => $type) { if ($type->hasMixed()) { $mixed_var_ids[] = $var_id; } } $cond_id = spl_object_id($stmt->cond); $while_clauses = FormulaGenerator::getFormula($cond_id, $cond_id, $stmt->cond, $context->self, $statements_analyzer, $codebase); $while_clauses = array_values(array_filter($while_clauses, static function (Clause $c) use($mixed_var_ids) : bool { $keys = array_keys($c->possibilities); $mixed_var_ids = array_diff($mixed_var_ids, $keys); foreach ($keys as $key) { foreach ($mixed_var_ids as $mixed_var_id) { if (preg_match('/^' . preg_quote($mixed_var_id, '/') . '(\\[|-)/', $key)) { return \false; } } } return \true; })); if (!$while_clauses) { $while_clauses = [new Clause([], $cond_id, $cond_id, \true)]; } if (\Psalm\Internal\Analyzer\Statements\Block\LoopAnalyzer::analyze($statements_analyzer, $stmt->stmts, \Psalm\Internal\Analyzer\Statements\Block\WhileAnalyzer::getAndExpressions($stmt->cond), [], $loop_scope, $inner_loop_context, \true, \true) === \false) { return \false; } // because it's a do {} while, inner loop vars belong to the main context if (!$inner_loop_context) { throw new UnexpectedValueException('There should be an inner loop context'); } $negated_while_clauses = Algebra::negateFormula($while_clauses); $negated_while_types = Algebra::getTruthsFromFormula(Algebra::simplifyCNF([...$context->clauses, ...$negated_while_clauses])); if ($negated_while_types) { $changed_var_ids = []; [$inner_loop_context->vars_in_scope, $inner_loop_context->references_in_scope] = Reconciler::reconcileKeyedTypes($negated_while_types, [], $inner_loop_context->vars_in_scope, $inner_loop_context->references_in_scope, $changed_var_ids, [], $statements_analyzer, [], \true, new CodeLocation($statements_analyzer->getSource(), $stmt->cond)); } foreach ($inner_loop_context->vars_in_scope as $var_id => $type) { // if there are break statements in the loop it's not certain // that the loop has finished executing, so the assertions at the end // the loop in the while conditional may not hold if (in_array(ScopeAnalyzer::ACTION_BREAK, $loop_scope->final_actions, \true)) { if (isset($loop_scope->possibly_defined_loop_parent_vars[$var_id])) { $context->vars_in_scope[$var_id] = Type::combineUnionTypes($type, $loop_scope->possibly_defined_loop_parent_vars[$var_id]); } } else { $context->vars_in_scope[$var_id] = $type; } } $do_context->loop_scope = null; $context->vars_possibly_in_scope = array_merge($context->vars_possibly_in_scope, $do_context->vars_possibly_in_scope); if ($context->collect_exceptions) { $context->mergeExceptions($inner_loop_context); } return null; } private static function analyzeDoNaively(StatementsAnalyzer $statements_analyzer, PhpParser\Node\Stmt\Do_ $stmt, Context $context, LoopScope $loop_scope) : void { $do_context = clone $context; $suppressed_issues = $statements_analyzer->getSuppressedIssues(); if (!in_array('RedundantCondition', $suppressed_issues, \true)) { $statements_analyzer->addSuppressedIssues(['RedundantCondition']); } if (!in_array('RedundantConditionGivenDocblockType', $suppressed_issues, \true)) { $statements_analyzer->addSuppressedIssues(['RedundantConditionGivenDocblockType']); } if (!in_array('TypeDoesNotContainType', $suppressed_issues, \true)) { $statements_analyzer->addSuppressedIssues(['TypeDoesNotContainType']); } $do_context->loop_scope = $loop_scope; $statements_analyzer->analyze($stmt->stmts, $do_context); if (!in_array('RedundantCondition', $suppressed_issues, \true)) { $statements_analyzer->removeSuppressedIssues(['RedundantCondition']); } if (!in_array('RedundantConditionGivenDocblockType', $suppressed_issues, \true)) { $statements_analyzer->removeSuppressedIssues(['RedundantConditionGivenDocblockType']); } if (!in_array('TypeDoesNotContainType', $suppressed_issues, \true)) { $statements_analyzer->removeSuppressedIssues(['TypeDoesNotContainType']); } } } inside_throw = \true; if (\Psalm\Internal\Analyzer\Statements\ExpressionAnalyzer::analyze($statements_analyzer, $stmt->expr, $context) === \false) { $context->has_returned = \true; return \false; } $context->inside_throw = \false; $context->has_returned = \true; if ($context->finally_scope) { foreach ($context->vars_in_scope as $var_id => &$type) { if (isset($context->finally_scope->vars_in_scope[$var_id])) { $context->finally_scope->vars_in_scope[$var_id] = Type::combineUnionTypes($context->finally_scope->vars_in_scope[$var_id], $type, $statements_analyzer->getCodebase()); } else { $type = $type->setPossiblyUndefined(\true, \true); $context->finally_scope->vars_in_scope[$var_id] = $type; } } } if ($context->check_classes && ($throw_type = $statements_analyzer->node_data->getType($stmt->expr)) && !$throw_type->hasMixed()) { $exception_type = new Union([new TNamedObject('Exception'), new TNamedObject('Throwable')]); $file_analyzer = $statements_analyzer->getFileAnalyzer(); $codebase = $statements_analyzer->getCodebase(); foreach ($throw_type->getAtomicTypes() as $throw_type_part) { $throw_type_candidate = new Union([$throw_type_part]); if (!UnionTypeComparator::isContainedBy($codebase, $throw_type_candidate, $exception_type)) { if (IssueBuffer::accepts(new InvalidThrow('Cannot throw ' . $throw_type_part . ' as it does not extend Exception or implement Throwable', new CodeLocation($file_analyzer, $stmt), (string) $throw_type_part), $statements_analyzer->getSuppressedIssues())) { return \false; } } elseif (!$context->isSuppressingExceptions($statements_analyzer)) { $codelocation = new CodeLocation($file_analyzer, $stmt); $hash = $codelocation->getHash(); foreach ($throw_type->getAtomicTypes() as $throw_atomic_type) { if ($throw_atomic_type instanceof TNamedObject) { $context->possibly_thrown_exceptions[$throw_atomic_type->value][$hash] = $codelocation; } } } } } if ($stmt instanceof PhpParser\Node\Expr\Throw_) { $statements_analyzer->node_data->setType($stmt, Type::getNever()); } return \true; } } getCodebase(); if ($context->mutation_free) { IssueBuffer::maybeAdd(new ImpureStaticVariable('Cannot use a static variable in a mutation-free context', new CodeLocation($statements_analyzer, $stmt)), $statements_analyzer->getSuppressedIssues()); } foreach ($stmt->vars as $var) { if (!is_string($var->var->name)) { continue; } $var_id = '$' . $var->var->name; $doc_comment = $stmt->getDocComment(); $comment_type = null; if ($doc_comment) { $var_comments = CommentAnalyzer::getVarComments($doc_comment, $statements_analyzer, $var->var); $comment_type = CommentAnalyzer::populateVarTypesFromDocblock($var_comments, $var->var, $context, $statements_analyzer); } if ($comment_type) { $context->byref_constraints[$var_id] = new ReferenceConstraint($comment_type); } if ($var->default) { if (\Psalm\Internal\Analyzer\Statements\ExpressionAnalyzer::analyze($statements_analyzer, $var->default, $context) === \false) { return; } if ($comment_type && ($var_default_type = $statements_analyzer->node_data->getType($var->default)) && !UnionTypeComparator::isContainedBy($codebase, $var_default_type, $comment_type)) { IssueBuffer::maybeAdd(new ReferenceConstraintViolation($var_id . ' of type ' . $comment_type->getId() . ' cannot be assigned type ' . $var_default_type->getId(), new CodeLocation($statements_analyzer, $var))); } } if ($context->check_variables) { $context->vars_in_scope[$var_id] = $comment_type ? $comment_type : Type::getMixed(); $context->vars_possibly_in_scope[$var_id] = \true; $context->assigned_var_ids[$var_id] = (int) $stmt->getAttribute('startFilePos'); $statements_analyzer->byref_uses[$var_id] = \true; $location = new CodeLocation($statements_analyzer, $var); $statements_analyzer->registerVariable($var_id, $location, $context->branch_point); } } } } node_data->getType($stmt->left); $stmt_right_type = $statements_analyzer->node_data->getType($stmt->right); if (!$stmt_left_type || !$stmt_right_type) { return; } if (($stmt instanceof PhpParser\Node\Expr\BinaryOp\BitwiseOr || $stmt instanceof PhpParser\Node\Expr\BinaryOp\BitwiseXor || $stmt instanceof PhpParser\Node\Expr\BinaryOp\BitwiseAnd) && $stmt_left_type->hasString() && $stmt_right_type->hasString()) { $stmt_type = Type::getString(); $statements_analyzer->node_data->setType($stmt, $stmt_type); BinaryOpAnalyzer::addDataFlow($statements_analyzer, $stmt, $stmt->left, $stmt->right, 'nondivop'); return; } if ($stmt instanceof PhpParser\Node\Expr\BinaryOp\Plus || $stmt instanceof PhpParser\Node\Expr\BinaryOp\Minus || $stmt instanceof PhpParser\Node\Expr\BinaryOp\Mod || $stmt instanceof PhpParser\Node\Expr\BinaryOp\Mul || $stmt instanceof PhpParser\Node\Expr\BinaryOp\Pow || $stmt instanceof PhpParser\Node\Expr\BinaryOp\BitwiseOr || $stmt instanceof PhpParser\Node\Expr\BinaryOp\BitwiseXor || $stmt instanceof PhpParser\Node\Expr\BinaryOp\BitwiseAnd || $stmt instanceof PhpParser\Node\Expr\BinaryOp\ShiftLeft || $stmt instanceof PhpParser\Node\Expr\BinaryOp\ShiftRight) { \Psalm\Internal\Analyzer\Statements\Expression\BinaryOp\ArithmeticOpAnalyzer::analyze($statements_analyzer, $statements_analyzer->node_data, $stmt->left, $stmt->right, $stmt, $result_type, $context); if (!$result_type) { $result_type = new Union([new TInt(), new TFloat()]); } $statements_analyzer->node_data->setType($stmt, $result_type); BinaryOpAnalyzer::addDataFlow($statements_analyzer, $stmt, $stmt->left, $stmt->right, 'nondivop'); return; } if ($stmt instanceof PhpParser\Node\Expr\BinaryOp\LogicalXor) { if ($stmt_left_type->hasBool() || $stmt_right_type->hasBool()) { $statements_analyzer->node_data->setType($stmt, Type::getBool()); } BinaryOpAnalyzer::addDataFlow($statements_analyzer, $stmt, $stmt->left, $stmt->right, 'xor'); return; } if ($stmt instanceof PhpParser\Node\Expr\BinaryOp\Div) { \Psalm\Internal\Analyzer\Statements\Expression\BinaryOp\ArithmeticOpAnalyzer::analyze($statements_analyzer, $statements_analyzer->node_data, $stmt->left, $stmt->right, $stmt, $result_type, $context); if (!$result_type) { $result_type = new Union([new TInt(), new TFloat()]); } $statements_analyzer->node_data->setType($stmt, $result_type); BinaryOpAnalyzer::addDataFlow($statements_analyzer, $stmt, $stmt->left, $stmt->right, 'div'); return; } } } getCodebase() : null; $left_type = $nodes->getType($left); $right_type = $nodes->getType($right); $config = Config::getInstance(); if ($left_type && $left_type->isNever()) { $left_type = $right_type; } elseif ($right_type && $right_type->isNever()) { $right_type = $left_type; } if ($left_type && $right_type) { if ($left_type->isNull()) { if ($statements_source) { IssueBuffer::maybeAdd(new NullOperand('Left operand cannot be null', new CodeLocation($statements_source, $left)), $statements_source->getSuppressedIssues()); } $result_type = Type::getMixed(); return; } if ($left_type->isNullable() && !$left_type->ignore_nullable_issues) { if ($statements_source) { IssueBuffer::maybeAdd(new PossiblyNullOperand('Left operand cannot be nullable, got ' . $left_type, new CodeLocation($statements_source, $left)), $statements_source->getSuppressedIssues()); } } if ($right_type->isNull()) { if ($statements_source) { IssueBuffer::maybeAdd(new NullOperand('Right operand cannot be null', new CodeLocation($statements_source, $right)), $statements_source->getSuppressedIssues()); } $result_type = Type::getMixed(); return; } if ($right_type->isNullable() && !$right_type->ignore_nullable_issues) { if ($statements_source) { IssueBuffer::maybeAdd(new PossiblyNullOperand('Right operand cannot be nullable, got ' . $right_type, new CodeLocation($statements_source, $right)), $statements_source->getSuppressedIssues()); } } if ($left_type->isFalse()) { if ($statements_source) { IssueBuffer::maybeAdd(new FalseOperand('Left operand cannot be false', new CodeLocation($statements_source, $left)), $statements_source->getSuppressedIssues()); } return; } if ($left_type->isFalsable() && !$left_type->ignore_falsable_issues) { if ($statements_source) { IssueBuffer::maybeAdd(new PossiblyFalseOperand('Left operand cannot be falsable, got ' . $left_type, new CodeLocation($statements_source, $left)), $statements_source->getSuppressedIssues()); } } if ($right_type->isFalse()) { if ($statements_source) { IssueBuffer::maybeAdd(new FalseOperand('Right operand cannot be false', new CodeLocation($statements_source, $right)), $statements_source->getSuppressedIssues()); } return; } if ($right_type->isFalsable() && !$right_type->ignore_falsable_issues) { if ($statements_source) { IssueBuffer::maybeAdd(new PossiblyFalseOperand('Right operand cannot be falsable, got ' . $right_type, new CodeLocation($statements_source, $right)), $statements_source->getSuppressedIssues()); } } $invalid_left_messages = []; $invalid_right_messages = []; $has_valid_left_operand = \false; $has_valid_right_operand = \false; $has_string_increment = \false; foreach ($left_type->getAtomicTypes() as $left_type_part) { foreach ($right_type->getAtomicTypes() as $right_type_part) { $candidate_result_type = self::analyzeOperands($statements_source, $codebase, $config, $context, $left, $right, $parent, $left_type_part, $right_type_part, $invalid_left_messages, $invalid_right_messages, $has_valid_left_operand, $has_valid_right_operand, $has_string_increment, $result_type); if ($candidate_result_type) { $result_type = $candidate_result_type; return; } } } if ($invalid_left_messages && $statements_source) { $first_left_message = $invalid_left_messages[0]; if ($has_valid_left_operand) { IssueBuffer::maybeAdd(new PossiblyInvalidOperand($first_left_message, new CodeLocation($statements_source, $left)), $statements_source->getSuppressedIssues()); } else { IssueBuffer::maybeAdd(new InvalidOperand($first_left_message, new CodeLocation($statements_source, $left)), $statements_source->getSuppressedIssues()); } } if ($invalid_right_messages && $statements_source) { $first_right_message = $invalid_right_messages[0]; if ($has_valid_right_operand) { IssueBuffer::maybeAdd(new PossiblyInvalidOperand($first_right_message, new CodeLocation($statements_source, $right)), $statements_source->getSuppressedIssues()); } else { IssueBuffer::maybeAdd(new InvalidOperand($first_right_message, new CodeLocation($statements_source, $right)), $statements_source->getSuppressedIssues()); } } if ($has_string_increment && $statements_source) { IssueBuffer::maybeAdd(new StringIncrement('Possibly unintended string increment', new CodeLocation($statements_source, $left)), $statements_source->getSuppressedIssues()); } } } /** * @param int|float $result */ private static function getNumericalType($result) : Union { if (is_int($result)) { return Type::getInt(\false, $result); } return Type::getFloat($result); } /** * @param string[] $invalid_left_messages * @param string[] $invalid_right_messages * @psalm-suppress ComplexMethod Unavoidably complex method. */ private static function analyzeOperands(?StatementsSource $statements_source, ?Codebase $codebase, Config $config, ?Context $context, PhpParser\Node\Expr $left, PhpParser\Node\Expr $right, PhpParser\Node $parent, Atomic $left_type_part, Atomic $right_type_part, array &$invalid_left_messages, array &$invalid_right_messages, bool &$has_valid_left_operand, bool &$has_valid_right_operand, bool &$has_string_increment, ?Union &$result_type = null) : ?Union { if (($left_type_part instanceof TLiteralInt || $left_type_part instanceof TLiteralFloat) && ($right_type_part instanceof TLiteralInt || $right_type_part instanceof TLiteralFloat) && ($context === null || $context->inside_loop === \false || !$left instanceof PhpParser\Node\Expr\Variable && !$right instanceof PhpParser\Node\Expr\Variable)) { // get_class is fine here because both classes are final. if ($statements_source !== null && $config->strict_binary_operands && get_class($left_type_part) !== get_class($right_type_part)) { IssueBuffer::maybeAdd(new InvalidOperand('Cannot process numeric types together in strict operands mode, ' . 'please cast explicitly', new CodeLocation($statements_source, $parent)), $statements_source->getSuppressedIssues()); } // time for some arithmetic! $calculated_type = self::arithmeticOperation($parent, $left_type_part->value, $right_type_part->value, \true); if ($calculated_type) { $result_type = Type::combineUnionTypes($calculated_type, $result_type); $has_valid_left_operand = \true; $has_valid_right_operand = \true; return null; } } if ($left_type_part instanceof TNull || $right_type_part instanceof TNull) { // null case is handled above return null; } if ($left_type_part instanceof TFalse || $right_type_part instanceof TFalse) { // null case is handled above return null; } if ($left_type_part instanceof TString && $right_type_part instanceof TInt && ($parent instanceof PhpParser\Node\Expr\PostInc || $parent instanceof PhpParser\Node\Expr\PreInc)) { if ($left_type_part instanceof TNumericString || $left_type_part instanceof TLiteralString && is_numeric($left_type_part->value)) { $new_result_type = new Union([new TFloat(), new TInt()], ['from_calculation' => \true]); } else { $new_result_type = Type::getNonEmptyString(); $has_string_increment = \true; } $result_type = Type::combineUnionTypes($new_result_type, $result_type); $has_valid_left_operand = \true; $has_valid_right_operand = \true; return null; } if ($left_type_part instanceof TTemplateParam && $right_type_part instanceof TTemplateParam) { $combined_type = Type::combineUnionTypes($left_type_part->as, $right_type_part->as); $combined_atomic_types = array_values($combined_type->getAtomicTypes()); if (count($combined_atomic_types) <= 2) { $left_type_part = $combined_atomic_types[0]; $right_type_part = $combined_atomic_types[1] ?? $combined_atomic_types[0]; } } if ($left_type_part instanceof TMixed || $right_type_part instanceof TMixed) { if ($statements_source && $codebase && $context) { if (!$context->collect_initializations && !$context->collect_mutations && $statements_source->getFilePath() === $statements_source->getRootFilePath() && (!($source = $statements_source->getSource()) instanceof FunctionLikeAnalyzer || !$source->getSource() instanceof TraitAnalyzer)) { $codebase->analyzer->incrementMixedCount($statements_source->getFilePath()); } } if ($left_type_part instanceof TMixed) { if ($statements_source) { IssueBuffer::maybeAdd(new MixedOperand('Left operand cannot be mixed', new CodeLocation($statements_source, $left)), $statements_source->getSuppressedIssues()); } } else { if ($statements_source) { IssueBuffer::maybeAdd(new MixedOperand('Right operand cannot be mixed', new CodeLocation($statements_source, $right)), $statements_source->getSuppressedIssues()); } } if ($left_type_part instanceof TMixed && $left_type_part->from_loop_isset && $parent instanceof PhpParser\Node\Expr\AssignOp\Plus && !$right_type_part instanceof TMixed) { $result_type = Type::combineUnionTypes(new Union([$right_type_part]), $result_type); return null; } $from_loop_isset = (!$left_type_part instanceof TMixed || $left_type_part->from_loop_isset) && (!$right_type_part instanceof TMixed || $right_type_part->from_loop_isset); $result_type = Type::getMixed($from_loop_isset); return $result_type; } if ($left_type_part instanceof TTemplateParam || $right_type_part instanceof TTemplateParam) { if ($left_type_part instanceof TTemplateParam && !$left_type_part->as->isInt() && !$left_type_part->as->isFloat()) { if ($statements_source) { IssueBuffer::maybeAdd(new MixedOperand('Left operand cannot be a non-numeric template', new CodeLocation($statements_source, $left)), $statements_source->getSuppressedIssues()); } } elseif ($right_type_part instanceof TTemplateParam && !$right_type_part->as->isInt() && !$right_type_part->as->isFloat()) { if ($statements_source) { IssueBuffer::maybeAdd(new MixedOperand('Right operand cannot be a non-numeric template', new CodeLocation($statements_source, $right)), $statements_source->getSuppressedIssues()); } } return null; } if ($statements_source && $codebase && $context) { if (!$context->collect_initializations && !$context->collect_mutations && $statements_source->getFilePath() === $statements_source->getRootFilePath() && (!($parent_source = $statements_source->getSource()) instanceof FunctionLikeAnalyzer || !$parent_source->getSource() instanceof TraitAnalyzer)) { $codebase->analyzer->incrementNonMixedCount($statements_source->getFilePath()); } } if ($left_type_part instanceof TArray || $right_type_part instanceof TArray || $left_type_part instanceof TKeyedArray || $right_type_part instanceof TKeyedArray || $left_type_part instanceof TList || $right_type_part instanceof TList) { if ($left_type_part instanceof TList) { $left_type_part = $left_type_part->getKeyedArray(); } if ($right_type_part instanceof TList) { $right_type_part = $right_type_part->getKeyedArray(); } if (!$right_type_part instanceof TArray && !$right_type_part instanceof TKeyedArray || !$left_type_part instanceof TArray && !$left_type_part instanceof TKeyedArray) { if (!$left_type_part instanceof TArray && !$left_type_part instanceof TKeyedArray) { $invalid_left_messages[] = 'Cannot add an array to a non-array ' . $left_type_part; } else { $invalid_right_messages[] = 'Cannot add an array to a non-array ' . $right_type_part; } if ($left_type_part instanceof TArray || $left_type_part instanceof TKeyedArray) { $has_valid_left_operand = \true; } elseif ($right_type_part instanceof TArray || $right_type_part instanceof TKeyedArray) { $has_valid_right_operand = \true; } return null; } if ($parent instanceof PhpParser\Node\Expr\BinaryOp\Plus) { $has_valid_right_operand = \true; $has_valid_left_operand = \true; if ($left_type_part instanceof TKeyedArray && $right_type_part instanceof TKeyedArray) { $definitely_existing_mixed_right_properties = array_diff_key($right_type_part->properties, $left_type_part->properties); $properties = $left_type_part->properties; foreach ($right_type_part->properties as $key => $type) { if (!isset($properties[$key])) { $properties[$key] = $type; } elseif ($properties[$key]->possibly_undefined) { $properties[$key] = Type::combineUnionTypes($properties[$key], $type, $codebase, \false, \true, 500, $type->possibly_undefined); } } if ($left_type_part->fallback_params !== null) { foreach ($definitely_existing_mixed_right_properties as $key => $type) { $properties[$key] = Type::combineUnionTypes(Type::getMixed(), $type); } } if ($left_type_part->fallback_params === null && $right_type_part->fallback_params === null) { $fallback_params = null; } elseif ($left_type_part->fallback_params !== null && $right_type_part->fallback_params !== null) { $fallback_params = [Type::combineUnionTypes($left_type_part->fallback_params[0], $right_type_part->fallback_params[0]), Type::combineUnionTypes($left_type_part->fallback_params[1], $right_type_part->fallback_params[1])]; } else { $fallback_params = $left_type_part->fallback_params ?: $right_type_part->fallback_params; } $new_keyed_array = new TKeyedArray($properties, null, $fallback_params); $result_type_member = new Union([$new_keyed_array]); } else { $result_type_member = TypeCombiner::combine([$left_type_part, $right_type_part], $codebase, \true); } $result_type = Type::combineUnionTypes($result_type_member, $result_type, $codebase, \true); if ($left instanceof PhpParser\Node\Expr\ArrayDimFetch && $context && $statements_source instanceof StatementsAnalyzer) { ArrayAssignmentAnalyzer::updateArrayType($statements_source, $left, $right, $result_type, $context); } return null; } } if ($left_type_part instanceof TNamedObject && strtolower($left_type_part->value) === 'gmp' || $right_type_part instanceof TNamedObject && strtolower($right_type_part->value) === 'gmp') { if ($left_type_part instanceof TNamedObject && strtolower($left_type_part->value) === 'gmp' && ($right_type_part instanceof TNamedObject && strtolower($right_type_part->value) === 'gmp' || ($right_type_part->isNumericType() || $right_type_part instanceof TMixed)) || $right_type_part instanceof TNamedObject && strtolower($right_type_part->value) === 'gmp' && ($left_type_part instanceof TNamedObject && strtolower($left_type_part->value) === 'gmp' || ($left_type_part->isNumericType() || $left_type_part instanceof TMixed))) { $result_type = Type::combineUnionTypes(new Union([new TNamedObject('GMP')]), $result_type); } else { if ($statements_source) { IssueBuffer::maybeAdd(new InvalidOperand('Cannot add GMP to non-numeric type', new CodeLocation($statements_source, $parent)), $statements_source->getSuppressedIssues()); } } return null; } if ($parent instanceof PhpParser\Node\Expr\BinaryOp\Plus || $parent instanceof PhpParser\Node\Expr\BinaryOp\Minus || $parent instanceof PhpParser\Node\Expr\BinaryOp\Mul || $parent instanceof PhpParser\Node\Expr\BinaryOp\Div || $parent instanceof PhpParser\Node\Expr\BinaryOp\Mod || $parent instanceof PhpParser\Node\Expr\BinaryOp\Pow) { $non_decimal_type = null; if ($left_type_part instanceof TNamedObject && strtolower($left_type_part->value) === "decimal\\decimal") { $non_decimal_type = $right_type_part; } elseif ($right_type_part instanceof TNamedObject && strtolower($right_type_part->value) === "decimal\\decimal") { $non_decimal_type = $left_type_part; } if ($non_decimal_type !== null) { if ($non_decimal_type instanceof TInt || $non_decimal_type instanceof TNumericString || $non_decimal_type instanceof TNamedObject && strtolower($non_decimal_type->value) === "decimal\\decimal") { $result_type = Type::combineUnionTypes(new Union([new TNamedObject("_HumbugBox7ff99e199a36\\Decimal\\Decimal")]), $result_type); } else { if ($statements_source) { IssueBuffer::maybeAdd(new InvalidOperand("Cannot add Decimal\\Decimal to {$non_decimal_type->getId()}", new CodeLocation($statements_source, $parent)), $statements_source->getSuppressedIssues()); } } return null; } } if ($left_type_part instanceof TLiteralString) { if (preg_match('/^\\-?\\d+$/', $left_type_part->value)) { $left_type_part = new TLiteralInt((int) $left_type_part->value); } elseif (preg_match('/^\\-?\\d?\\.\\d+$/', $left_type_part->value)) { $left_type_part = new TLiteralFloat((float) $left_type_part->value); } } if ($right_type_part instanceof TLiteralString) { if (preg_match('/^\\-?\\d+$/', $right_type_part->value)) { $right_type_part = new TLiteralInt((int) $right_type_part->value); } elseif (preg_match('/^\\-?\\d?\\.\\d+$/', $right_type_part->value)) { $right_type_part = new TLiteralFloat((float) $right_type_part->value); } } if ($left_type_part->isNumericType() || $right_type_part->isNumericType()) { if (($left_type_part instanceof TNumeric || $right_type_part instanceof TNumeric) && ($left_type_part->isNumericType() && $right_type_part->isNumericType())) { if ($config->strict_binary_operands) { if ($statements_source) { IssueBuffer::maybeAdd(new InvalidOperand('Cannot process different numeric types together in strict binary operands mode, ' . 'please cast explicitly', new CodeLocation($statements_source, $parent)), $statements_source->getSuppressedIssues()); } } if ($parent instanceof PhpParser\Node\Expr\BinaryOp\Mod) { $new_result_type = Type::getInt(); } else { $new_result_type = new Union([new TFloat(), new TInt()]); } $result_type = Type::combineUnionTypes($new_result_type, $result_type); $has_valid_right_operand = \true; $has_valid_left_operand = \true; return null; } if ($left_type_part instanceof TIntRange && $right_type_part instanceof TIntRange) { self::analyzeOperandsBetweenIntRange($parent, $result_type, $left_type_part, $right_type_part); return null; } if ($left_type_part instanceof TIntRange && $right_type_part instanceof TInt || $left_type_part instanceof TInt && $right_type_part instanceof TIntRange) { self::analyzeOperandsBetweenIntRangeAndInt($parent, $result_type, $left_type_part, $right_type_part); return null; } if ($left_type_part instanceof TInt && $right_type_part instanceof TInt) { if ($parent instanceof PhpParser\Node\Expr\BinaryOp\Div) { $result_type = new Union([new TInt(), new TFloat()]); } else { $left_is_positive = $left_type_part instanceof TLiteralInt && $left_type_part->value > 0 || $left_type_part instanceof TIntRange && $left_type_part->isPositive(); $right_is_positive = $right_type_part instanceof TLiteralInt && $right_type_part->value > 0 || $right_type_part instanceof TIntRange && $right_type_part->isPositive(); if ($parent instanceof PhpParser\Node\Expr\BinaryOp\Minus) { $always_positive = \false; } elseif ($left_is_positive && $right_is_positive) { if ($parent instanceof PhpParser\Node\Expr\BinaryOp\BitwiseXor || $parent instanceof PhpParser\Node\Expr\BinaryOp\BitwiseAnd || $parent instanceof PhpParser\Node\Expr\BinaryOp\ShiftLeft || $parent instanceof PhpParser\Node\Expr\BinaryOp\ShiftRight) { $always_positive = \false; } else { $always_positive = \true; } } elseif ($parent instanceof PhpParser\Node\Expr\BinaryOp\Plus && ($left_type_part instanceof TLiteralInt && $left_type_part->value === 0) && $right_is_positive) { $always_positive = \true; } elseif ($parent instanceof PhpParser\Node\Expr\BinaryOp\Plus && ($right_type_part instanceof TLiteralInt && $right_type_part->value === 0) && $left_is_positive) { $always_positive = \true; } else { $always_positive = \false; } if ($parent instanceof PhpParser\Node\Expr\BinaryOp\Mod) { if ($right_type_part instanceof TLiteralInt) { $literal_value_max = $right_type_part->value - 1; if ($always_positive) { $result_type = Type::getIntRange(0, $literal_value_max); } else { $result_type = Type::getIntRange(-$literal_value_max, $literal_value_max); } } else { if ($always_positive) { $result_type = Type::getListKey(); } else { $result_type = Type::getInt(); } } } else { $result_type = Type::combineUnionTypes($always_positive ? Type::getIntRange(1, null) : Type::getInt(\true), $result_type); } } $has_valid_right_operand = \true; $has_valid_left_operand = \true; return null; } if ($left_type_part instanceof TFloat && $right_type_part instanceof TFloat) { if ($parent instanceof PhpParser\Node\Expr\BinaryOp\Mod) { $result_type = Type::getInt(); } else { $result_type = Type::combineUnionTypes(Type::getFloat(), $result_type); } $has_valid_right_operand = \true; $has_valid_left_operand = \true; return null; } if ($left_type_part instanceof TFloat && $right_type_part instanceof TInt || $left_type_part instanceof TInt && $right_type_part instanceof TFloat) { if ($config->strict_binary_operands) { if ($statements_source) { IssueBuffer::maybeAdd(new InvalidOperand('Cannot process ints and floats in strict binary operands mode, ' . 'please cast explicitly', new CodeLocation($statements_source, $parent)), $statements_source->getSuppressedIssues()); } } if ($parent instanceof PhpParser\Node\Expr\BinaryOp\Mod) { $result_type = Type::getInt(); } else { $result_type = Type::combineUnionTypes(Type::getFloat(), $result_type); } $has_valid_right_operand = \true; $has_valid_left_operand = \true; return null; } if ($left_type_part->isNumericType() && $right_type_part->isNumericType()) { if ($config->strict_binary_operands) { if ($statements_source) { IssueBuffer::maybeAdd(new InvalidOperand('Cannot process numeric types together in strict operands mode, ' . 'please cast explicitly', new CodeLocation($statements_source, $parent)), $statements_source->getSuppressedIssues()); } } if ($parent instanceof PhpParser\Node\Expr\BinaryOp\Mod) { $result_type = Type::getInt(); } else { $result_type = new Union([new TInt(), new TFloat()]); } $has_valid_right_operand = \true; $has_valid_left_operand = \true; return null; } if (!$left_type_part->isNumericType()) { $invalid_left_messages[] = 'Cannot perform a numeric operation with a non-numeric type ' . $left_type_part; $has_valid_right_operand = \true; } else { $invalid_right_messages[] = 'Cannot perform a numeric operation with a non-numeric type ' . $right_type_part; $has_valid_left_operand = \true; } } else { $invalid_left_messages[] = 'Cannot perform a numeric operation with non-numeric types ' . $left_type_part . ' and ' . $right_type_part; } return null; } /** * @param float|int $operand1 * @param float|int $operand2 */ public static function arithmeticOperation(PhpParser\Node $operation, $operand1, $operand2, bool $allow_float_result) : ?Union { if ($operation instanceof PhpParser\Node\Expr\BinaryOp\Plus) { $result = $operand1 + $operand2; } elseif ($operation instanceof PhpParser\Node\Expr\BinaryOp\Minus) { $result = $operand1 - $operand2; } elseif ($operation instanceof PhpParser\Node\Expr\BinaryOp\Mod) { if ($operand2 === 0) { return Type::getNever(); } $result = $operand1 % $operand2; } elseif ($operation instanceof PhpParser\Node\Expr\BinaryOp\Mul) { $result = $operand1 * $operand2; } elseif ($operation instanceof PhpParser\Node\Expr\BinaryOp\Pow) { $result = $operand1 ** $operand2; } elseif ($operation instanceof PhpParser\Node\Expr\BinaryOp\BitwiseOr) { $result = $operand1 | $operand2; } elseif ($operation instanceof PhpParser\Node\Expr\BinaryOp\BitwiseAnd) { $result = $operand1 & $operand2; } elseif ($operation instanceof PhpParser\Node\Expr\BinaryOp\BitwiseXor) { $result = $operand1 ^ $operand2; } elseif ($operation instanceof PhpParser\Node\Expr\BinaryOp\ShiftLeft) { $result = $operand1 << $operand2; } elseif ($operation instanceof PhpParser\Node\Expr\BinaryOp\ShiftRight) { $result = $operand1 >> $operand2; } elseif ($operation instanceof PhpParser\Node\Expr\BinaryOp\Div) { if ($operand2 === 0 || $operand2 === 0.0) { return Type::getNever(); } $result = $operand1 / $operand2; } else { return null; } $calculated_type = self::getNumericalType($result); if (!$allow_float_result && $calculated_type->isFloat()) { return null; } return $calculated_type; } private static function analyzeOperandsBetweenIntRange(PhpParser\Node $parent, ?Union &$result_type, TIntRange $left_type_part, TIntRange $right_type_part) : void { if ($parent instanceof PhpParser\Node\Expr\BinaryOp\Div) { //can't assume an int range will stay int after division $result_type = Type::combineUnionTypes(new Union([new TInt(), new TFloat()]), $result_type); return; } if ($parent instanceof PhpParser\Node\Expr\BinaryOp\Mod) { self::analyzeModBetweenIntRange($result_type, $left_type_part, $right_type_part); return; } if ($parent instanceof PhpParser\Node\Expr\BinaryOp\BitwiseAnd || $parent instanceof PhpParser\Node\Expr\BinaryOp\BitwiseOr || $parent instanceof PhpParser\Node\Expr\BinaryOp\BitwiseXor) { //really complex to calculate $result_type = Type::combineUnionTypes(Type::getInt(), $result_type); return; } if ($parent instanceof PhpParser\Node\Expr\BinaryOp\ShiftLeft || $parent instanceof PhpParser\Node\Expr\BinaryOp\ShiftRight) { //really complex to calculate $result_type = Type::combineUnionTypes(new Union([new TInt()]), $result_type); return; } if ($parent instanceof PhpParser\Node\Expr\BinaryOp\Mul) { self::analyzeMulBetweenIntRange($parent, $result_type, $left_type_part, $right_type_part); return; } if ($parent instanceof PhpParser\Node\Expr\BinaryOp\Pow) { self::analyzePowBetweenIntRange($result_type, $left_type_part, $right_type_part); return; } if ($parent instanceof PhpParser\Node\Expr\BinaryOp\Minus) { //for Minus, we have to assume the min is the min from first range minus the max from the second $min_operand1 = $left_type_part->min_bound; $min_operand2 = $right_type_part->max_bound; //and the max is the max from first range minus the min from the second $max_operand1 = $left_type_part->max_bound; $max_operand2 = $right_type_part->min_bound; } else { $min_operand1 = $left_type_part->min_bound; $min_operand2 = $right_type_part->min_bound; $max_operand1 = $left_type_part->max_bound; $max_operand2 = $right_type_part->max_bound; } $calculated_min_type = null; if ($min_operand1 !== null && $min_operand2 !== null) { // when there are two valid numbers, make any operation $calculated_min_type = self::arithmeticOperation($parent, $min_operand1, $min_operand2, \false); } $calculated_max_type = null; if ($max_operand1 !== null && $max_operand2 !== null) { // when there are two valid numbers, make any operation $calculated_max_type = self::arithmeticOperation($parent, $max_operand1, $max_operand2, \false); } $min_value = $calculated_min_type !== null ? $calculated_min_type->getSingleIntLiteral()->value : null; $max_value = $calculated_max_type !== null ? $calculated_max_type->getSingleIntLiteral()->value : null; $new_result_type = Type::getIntRange($min_value, $max_value); $result_type = Type::combineUnionTypes($new_result_type, $result_type); } /** * @param TIntRange|TInt $left_type_part * @param TIntRange|TInt $right_type_part */ private static function analyzeOperandsBetweenIntRangeAndInt(PhpParser\Node $parent, ?Union &$result_type, Atomic $left_type_part, Atomic $right_type_part) : void { if (!$left_type_part instanceof TIntRange) { $left_type_part = TIntRange::convertToIntRange($left_type_part); } if (!$right_type_part instanceof TIntRange) { $right_type_part = TIntRange::convertToIntRange($right_type_part); } self::analyzeOperandsBetweenIntRange($parent, $result_type, $left_type_part, $right_type_part); } private static function analyzeMulBetweenIntRange(PhpParser\Node\Expr\BinaryOp\Mul $parent, ?Union &$result_type, TIntRange $left_type_part, TIntRange $right_type_part) : void { //Mul is a special case because of double negatives. We can only infer when we know both signs strictly if ($right_type_part->min_bound !== null && $right_type_part->max_bound !== null && $left_type_part->min_bound !== null && $left_type_part->max_bound !== null) { //everything is known, we can do calculations //[ x_1 , x_2 ] ⋆ [ y_1 , y_2 ] = // [ // min(x_1 ⋆ y_1 , x_1 ⋆ y_2 , x_2 ⋆ y_1 , x_2 ⋆ y_2), // max(x_1 ⋆ y_1 , x_1 ⋆ y_2 , x_2 ⋆ y_1 , x_2 ⋆ y_2) // ] $x_1 = $right_type_part->min_bound; $x_2 = $right_type_part->max_bound; $y_1 = $left_type_part->min_bound; $y_2 = $left_type_part->max_bound; $min_value = min($x_1 * $y_1, $x_1 * $y_2, $x_2 * $y_1, $x_2 * $y_2); $max_value = max($x_1 * $y_1, $x_1 * $y_2, $x_2 * $y_1, $x_2 * $y_2); $new_result_type = Type::getIntRange($min_value, $max_value); } elseif ($right_type_part->isPositiveOrZero() && $left_type_part->isPositiveOrZero()) { // both operands are positive, result will be only positive $min_operand1 = $left_type_part->min_bound; $min_operand2 = $right_type_part->min_bound; $max_operand1 = $left_type_part->max_bound; $max_operand2 = $right_type_part->max_bound; $calculated_min_type = null; if ($min_operand1 !== null && $min_operand2 !== null) { // when there are two valid numbers, make any operation $calculated_min_type = self::arithmeticOperation($parent, $min_operand1, $min_operand2, \false); } $calculated_max_type = null; if ($max_operand1 !== null && $max_operand2 !== null) { // when there are two valid numbers, make any operation $calculated_max_type = self::arithmeticOperation($parent, $max_operand1, $max_operand2, \false); } $min_value = $calculated_min_type !== null ? $calculated_min_type->getSingleIntLiteral()->value : null; $max_value = $calculated_max_type !== null ? $calculated_max_type->getSingleIntLiteral()->value : null; $new_result_type = Type::getIntRange($min_value, $max_value); } elseif ($right_type_part->isPositiveOrZero() && $left_type_part->isNegativeOrZero()) { // one operand is negative, result will be negative and we have to check min vs max $min_operand1 = $left_type_part->max_bound; $min_operand2 = $right_type_part->min_bound; $max_operand1 = $left_type_part->min_bound; $max_operand2 = $right_type_part->max_bound; $calculated_min_type = null; if ($min_operand1 !== null && $min_operand2 !== null) { // when there are two valid numbers, make any operation $calculated_min_type = self::arithmeticOperation($parent, $min_operand1, $min_operand2, \false); } $calculated_max_type = null; if ($max_operand1 !== null && $max_operand2 !== null) { // when there are two valid numbers, make any operation $calculated_max_type = self::arithmeticOperation($parent, $max_operand1, $max_operand2, \false); } $min_value = $calculated_min_type !== null ? $calculated_min_type->getSingleIntLiteral()->value : null; $max_value = $calculated_max_type !== null ? $calculated_max_type->getSingleIntLiteral()->value : null; if ($min_value > $max_value) { [$min_value, $max_value] = [$max_value, $min_value]; } $new_result_type = Type::getIntRange($min_value, $max_value); } elseif ($right_type_part->isNegativeOrZero() && $left_type_part->isPositiveOrZero()) { // one operand is negative, result will be negative and we have to check min vs max $min_operand1 = $left_type_part->min_bound; $min_operand2 = $right_type_part->max_bound; $max_operand1 = $left_type_part->max_bound; $max_operand2 = $right_type_part->min_bound; $calculated_min_type = null; if ($min_operand1 !== null && $min_operand2 !== null) { // when there are two valid numbers, make any operation $calculated_min_type = self::arithmeticOperation($parent, $min_operand1, $min_operand2, \false); } $calculated_max_type = null; if ($max_operand1 !== null && $max_operand2 !== null) { // when there are two valid numbers, make any operation $calculated_max_type = self::arithmeticOperation($parent, $max_operand1, $max_operand2, \false); } $min_value = $calculated_min_type !== null ? $calculated_min_type->getSingleIntLiteral()->value : null; $max_value = $calculated_max_type !== null ? $calculated_max_type->getSingleIntLiteral()->value : null; if ($min_value > $max_value) { [$min_value, $max_value] = [$max_value, $min_value]; } $new_result_type = Type::getIntRange($min_value, $max_value); } elseif ($right_type_part->isNegativeOrZero() && $left_type_part->isNegativeOrZero()) { // both operand are negative, result will be positive $min_operand1 = $left_type_part->max_bound; $min_operand2 = $right_type_part->max_bound; $max_operand1 = $left_type_part->min_bound; $max_operand2 = $right_type_part->min_bound; $calculated_min_type = null; if ($min_operand1 !== null && $min_operand2 !== null) { // when there are two valid numbers, make any operation $calculated_min_type = self::arithmeticOperation($parent, $min_operand1, $min_operand2, \false); } $calculated_max_type = null; if ($max_operand1 !== null && $max_operand2 !== null) { // when there are two valid numbers, make any operation $calculated_max_type = self::arithmeticOperation($parent, $max_operand1, $max_operand2, \false); } $min_value = $calculated_min_type !== null ? $calculated_min_type->getSingleIntLiteral()->value : null; $max_value = $calculated_max_type !== null ? $calculated_max_type->getSingleIntLiteral()->value : null; $new_result_type = Type::getIntRange($min_value, $max_value); } else { $new_result_type = Type::getInt(\true); } $result_type = Type::combineUnionTypes($new_result_type, $result_type); } private static function analyzePowBetweenIntRange(?Union &$result_type, TIntRange $left_type_part, TIntRange $right_type_part) : void { //If Pow first operand is negative, the result could be positive or negative, else it will be positive //If Pow second operand is negative, the result will be float, if it's 0, it will be 1/-1, else positive if ($left_type_part->isPositive()) { if ($right_type_part->isPositive()) { $new_result_type = Type::getIntRange(1, null); } elseif ($right_type_part->isNegative()) { $new_result_type = Type::getFloat(); } elseif ($right_type_part->min_bound === 0 && $right_type_part->max_bound === 0) { $new_result_type = Type::getInt(\true, 1); } else { //$right_type_part may be a mix of positive, negative and 0 $new_result_type = new Union([new TInt(), new TFloat()]); } } elseif ($left_type_part->isNegative()) { if ($right_type_part->isPositive()) { if ($right_type_part->min_bound === $right_type_part->max_bound) { if ($right_type_part->max_bound % 2 === 0) { $new_result_type = Type::getIntRange(1, null); } else { $new_result_type = Type::getIntRange(null, -1); } } else { $new_result_type = Type::getInt(\true); } } elseif ($right_type_part->isNegative()) { $new_result_type = Type::getFloat(); } elseif ($right_type_part->min_bound === 0 && $right_type_part->max_bound === 0) { $new_result_type = Type::getInt(\true, -1); } else { //$right_type_part may be a mix of positive, negative and 0 $new_result_type = new Union([new TInt(), new TFloat()]); } } elseif ($left_type_part->min_bound === 0 && $left_type_part->max_bound === 0) { if ($right_type_part->isPositive()) { $new_result_type = Type::getInt(\true, 0); } elseif ($right_type_part->min_bound === 0 && $right_type_part->max_bound === 0) { $new_result_type = Type::getInt(\true, 1); } elseif ($right_type_part->isNegative()) { $new_result_type = Type::getFloat(); } else { $new_result_type = new Union([new TFloat(), new TLiteralInt(0), new TLiteralInt(1)], ['from_calculation' => \true]); } } else { //$left_type_part may be a mix of positive, negative and 0 if ($right_type_part->isPositive()) { if ($right_type_part->min_bound === $right_type_part->max_bound && $right_type_part->max_bound % 2 === 0) { $new_result_type = Type::getIntRange(1, null); } else { $new_result_type = Type::getInt(\true); } } elseif ($right_type_part->isNegative()) { $new_result_type = Type::getFloat(); } elseif ($right_type_part->min_bound === 0 && $right_type_part->max_bound === 0) { $new_result_type = Type::getInt(\true, 1); } else { //$left_type_part may be a mix of positive, negative and 0 $new_result_type = new Union([new TInt(), new TFloat()]); } } $result_type = Type::combineUnionTypes($new_result_type, $result_type); } private static function analyzeModBetweenIntRange(?Union &$result_type, TIntRange $left_type_part, TIntRange $right_type_part) : void { //result of Mod is not directly dependant on the bounds of the range if ($right_type_part->min_bound !== null && $right_type_part->min_bound === $right_type_part->max_bound) { //if the second operand is a literal, we can be pretty detailed if ($right_type_part->max_bound === 0) { $new_result_type = Type::getNever(); } else { if ($left_type_part->isPositiveOrZero()) { if ($right_type_part->isPositive()) { $max = $right_type_part->min_bound - 1; $new_result_type = Type::getIntRange(0, $max); } else { $max = $right_type_part->min_bound + 1; $new_result_type = Type::getIntRange($max, 0); } } elseif ($left_type_part->isNegativeOrZero()) { if ($right_type_part->isPositive()) { $max = $right_type_part->min_bound - 1; $new_result_type = Type::getIntRange(-$max, 0); } else { $max = $right_type_part->min_bound + 1; $new_result_type = Type::getIntRange(-$max, 0); } } else { if ($right_type_part->isPositive()) { $max = $right_type_part->min_bound - 1; } else { $max = -$right_type_part->min_bound - 1; } $new_result_type = Type::getIntRange(-$max, $max); } } } elseif ($right_type_part->isPositive()) { if ($left_type_part->isPositiveOrZero()) { if ($right_type_part->max_bound !== null) { //we now that the result will be a range between 0 and $right->max - 1 $new_result_type = new Union([new TIntRange(0, $right_type_part->max_bound - 1)]); } else { $new_result_type = Type::getListKey(); } } elseif ($left_type_part->isNegativeOrZero()) { $new_result_type = Type::getIntRange(null, 0); } else { $new_result_type = Type::getInt(\true); } } elseif ($right_type_part->isNegative()) { if ($left_type_part->isPositiveOrZero()) { $new_result_type = Type::getIntRange(null, 0); } elseif ($left_type_part->isNegativeOrZero()) { $new_result_type = Type::getIntRange(null, 0); } else { $new_result_type = Type::getInt(\true); } } else { $new_result_type = Type::getInt(\true); } $result_type = Type::combineUnionTypes($new_result_type, $result_type); } } left, ['stmts' => [new VirtualExpression($stmt->right)]], $stmt->getAttributes()); return IfElseAnalyzer::analyze($statements_analyzer, $fake_if_stmt, $context) !== \false; } $pre_referenced_var_ids = $context->cond_referenced_var_ids; $pre_assigned_var_ids = $context->assigned_var_ids; $left_context = clone $context; $left_context->cond_referenced_var_ids = []; $left_context->assigned_var_ids = []; /** @var list $left_context->reconciled_expression_clauses */ $left_context->reconciled_expression_clauses = []; if (ExpressionAnalyzer::analyze($statements_analyzer, $stmt->left, $left_context) === \false) { return \false; } IfConditionalAnalyzer::handleParadoxicalCondition($statements_analyzer, $stmt->left); $codebase = $statements_analyzer->getCodebase(); $left_cond_id = spl_object_id($stmt->left); $left_clauses = FormulaGenerator::getFormula($left_cond_id, $left_cond_id, $stmt->left, $context->self, $statements_analyzer, $codebase); foreach ($left_context->vars_in_scope as $var_id => $type) { if (isset($left_context->assigned_var_ids[$var_id])) { $context->vars_in_scope[$var_id] = $type; } } /** @var array */ $left_referenced_var_ids = $left_context->cond_referenced_var_ids; $context->cond_referenced_var_ids = array_merge($pre_referenced_var_ids, $left_referenced_var_ids); $left_assigned_var_ids = array_diff_key($left_context->assigned_var_ids, $pre_assigned_var_ids); $left_referenced_var_ids = array_diff_key($left_referenced_var_ids, $left_assigned_var_ids); $context_clauses = array_merge($left_context->clauses, $left_clauses); if ($left_context->reconciled_expression_clauses) { $reconciled_expression_clauses = $left_context->reconciled_expression_clauses; $context_clauses = array_values(array_filter($context_clauses, static fn(Clause $c): bool => !in_array($c->hash, $reconciled_expression_clauses, \true))); if (count($context_clauses) === 1 && $context_clauses[0]->wedge && !$context_clauses[0]->possibilities) { $context_clauses = []; } } $simplified_clauses = Algebra::simplifyCNF($context_clauses); $active_left_assertions = []; $left_type_assertions = Algebra::getTruthsFromFormula($simplified_clauses, $left_cond_id, $left_referenced_var_ids, $active_left_assertions); $changed_var_ids = []; if ($left_type_assertions) { $right_context = clone $context; // while in an and, we allow scope to boil over to support // statements of the form if ($x && $x->foo()) [$right_context->vars_in_scope, $right_context->references_in_scope] = Reconciler::reconcileKeyedTypes($left_type_assertions, $active_left_assertions, $right_context->vars_in_scope, $context->references_in_scope, $changed_var_ids, $left_referenced_var_ids, $statements_analyzer, $statements_analyzer->getTemplateTypeMap() ?: [], $context->inside_loop, new CodeLocation($statements_analyzer->getSource(), $stmt->left), $context->inside_negation); } else { $right_context = clone $left_context; } $partitioned_clauses = Context::removeReconciledClauses([...$left_context->clauses, ...$left_clauses], $changed_var_ids); $right_context->clauses = $partitioned_clauses[0]; if (ExpressionAnalyzer::analyze($statements_analyzer, $stmt->right, $right_context) === \false) { return \false; } IfConditionalAnalyzer::handleParadoxicalCondition($statements_analyzer, $stmt->right); $context->cond_referenced_var_ids = array_merge($right_context->cond_referenced_var_ids, $left_context->cond_referenced_var_ids); if ($context->inside_conditional) { $context->updateChecks($right_context); $context->vars_possibly_in_scope = array_merge($right_context->vars_possibly_in_scope, $left_context->vars_possibly_in_scope); $context->assigned_var_ids = array_merge($left_context->assigned_var_ids, $right_context->assigned_var_ids); } if ($context->if_body_context && !$context->inside_negation) { $if_body_context = $context->if_body_context; $context->vars_in_scope = $right_context->vars_in_scope; $if_body_context->vars_in_scope = array_merge($if_body_context->vars_in_scope, $context->vars_in_scope); $if_body_context->cond_referenced_var_ids = array_merge($if_body_context->cond_referenced_var_ids, $context->cond_referenced_var_ids); $if_body_context->assigned_var_ids = array_merge($if_body_context->assigned_var_ids, $context->assigned_var_ids); $if_body_context->reconciled_expression_clauses = [...$if_body_context->reconciled_expression_clauses, ...array_map( /** @return string|int */ static fn(Clause $c) => $c->hash, $partitioned_clauses[1] )]; $if_body_context->vars_possibly_in_scope = array_merge($if_body_context->vars_possibly_in_scope, $context->vars_possibly_in_scope); $if_body_context->updateChecks($context); } else { $context->vars_in_scope = $left_context->vars_in_scope; } return \true; } } left; $root_expr = $left_expr; while ($root_expr instanceof PhpParser\Node\Expr\ArrayDimFetch || $root_expr instanceof PhpParser\Node\Expr\PropertyFetch) { $root_expr = $root_expr->var; } if ($root_expr instanceof PhpParser\Node\Expr\FuncCall || $root_expr instanceof PhpParser\Node\Expr\MethodCall || $root_expr instanceof PhpParser\Node\Expr\StaticCall || $root_expr instanceof PhpParser\Node\Expr\Cast || $root_expr instanceof PhpParser\Node\Expr\Match_ || $root_expr instanceof PhpParser\Node\Expr\NullsafePropertyFetch || $root_expr instanceof PhpParser\Node\Expr\NullsafeMethodCall || $root_expr instanceof PhpParser\Node\Expr\Ternary) { $left_var_id = '$' . (int) $left_expr->getAttribute('startFilePos'); $cloned = clone $context; $cloned->inside_isset = \true; ExpressionAnalyzer::analyze($statements_analyzer, $left_expr, $cloned); if ($root_expr !== $left_expr) { $condition_type = $statements_analyzer->node_data->getType($left_expr); if ($condition_type) { $condition_type = $condition_type->setPossiblyUndefined(\true); } else { $condition_type = new Union([new TMixed()], ['possibly_undefined' => \true]); } } else { $condition_type = $statements_analyzer->node_data->getType($left_expr) ?? Type::getMixed(); } $context->vars_in_scope[$left_var_id] = $condition_type; $left_expr = new VirtualVariable(substr($left_var_id, 1), $left_expr->getAttributes()); } $ternary = new VirtualTernary(new VirtualIsset([$left_expr], $stmt->left->getAttributes()), $left_expr, $stmt->right, $stmt->getAttributes()); $old_node_data = $statements_analyzer->node_data; $statements_analyzer->node_data = clone $statements_analyzer->node_data; ExpressionAnalyzer::analyze($statements_analyzer, $ternary, $context); $ternary_type = $statements_analyzer->node_data->getType($ternary) ?? Type::getMixed(); $statements_analyzer->node_data = $old_node_data; $statements_analyzer->node_data->setType($stmt, $ternary_type); return \true; } } getCodebase(); $left_type = $statements_analyzer->node_data->getType($left); $right_type = $statements_analyzer->node_data->getType($right); $config = Config::getInstance(); if ($left_type && $right_type) { $result_type = Type::getString(); if ($left_type->hasMixed() || $right_type->hasMixed()) { if (!$context->collect_initializations && !$context->collect_mutations && $statements_analyzer->getFilePath() === $statements_analyzer->getRootFilePath() && (!($parent_source = $statements_analyzer->getSource()) instanceof FunctionLikeAnalyzer || !$parent_source->getSource() instanceof TraitAnalyzer)) { $codebase->analyzer->incrementMixedCount($statements_analyzer->getFilePath()); } if ($left_type->hasMixed()) { $arg_location = new CodeLocation($statements_analyzer->getSource(), $left); $origin_locations = []; if ($statements_analyzer->data_flow_graph instanceof VariableUseGraph) { foreach ($left_type->parent_nodes as $parent_node) { $origin_locations = [...$origin_locations, ...$statements_analyzer->data_flow_graph->getOriginLocations($parent_node)]; } } $origin_location = count($origin_locations) === 1 ? reset($origin_locations) : null; if ($origin_location && $origin_location->getHash() === $arg_location->getHash()) { $origin_location = null; } IssueBuffer::maybeAdd(new MixedOperand('Left operand cannot be mixed', $arg_location, $origin_location), $statements_analyzer->getSuppressedIssues()); } else { $arg_location = new CodeLocation($statements_analyzer->getSource(), $right); $origin_locations = []; if ($statements_analyzer->data_flow_graph instanceof VariableUseGraph) { foreach ($right_type->parent_nodes as $parent_node) { $origin_locations = [...$origin_locations, ...$statements_analyzer->data_flow_graph->getOriginLocations($parent_node)]; } } $origin_location = count($origin_locations) === 1 ? reset($origin_locations) : null; if ($origin_location && $origin_location->getHash() === $arg_location->getHash()) { $origin_location = null; } IssueBuffer::maybeAdd(new MixedOperand('Right operand cannot be mixed', $arg_location, $origin_location), $statements_analyzer->getSuppressedIssues()); } return; } if (!$context->collect_initializations && !$context->collect_mutations && $statements_analyzer->getFilePath() === $statements_analyzer->getRootFilePath() && (!($parent_source = $statements_analyzer->getSource()) instanceof FunctionLikeAnalyzer || !$parent_source->getSource() instanceof TraitAnalyzer)) { $codebase->analyzer->incrementNonMixedCount($statements_analyzer->getFilePath()); } self::analyzeOperand($statements_analyzer, $left, $left_type, 'Left', $context); self::analyzeOperand($statements_analyzer, $right, $right_type, 'Right', $context); // If both types are specific literals, combine them into new literals $literal_concat = \false; if ($left_type->allSpecificLiterals() && $right_type->allSpecificLiterals()) { $left_type_parts = $left_type->getAtomicTypes(); $right_type_parts = $right_type->getAtomicTypes(); $combinations = count($left_type_parts) * count($right_type_parts); if ($combinations < self::MAX_LITERALS) { $literal_concat = \true; $result_type_parts = []; foreach ($left_type->getAtomicTypes() as $left_type_part) { foreach ($right_type->getAtomicTypes() as $right_type_part) { $literal = $left_type_part->value . $right_type_part->value; if (strlen($literal) >= $config->max_string_length) { // Literal too long, use non-literal type instead $literal_concat = \false; break 2; } $result_type_parts[] = Type::getAtomicStringFromLiteral($literal); } } if ($literal_concat) { // Bypass opcache bug: https://github.com/php/php-src/issues/10635 (function (int $_) : void { })($combinations); if (count($result_type_parts) === 0) { throw new AssertionError("The number of parts cannot be 0!"); } if (count($result_type_parts) !== $combinations) { throw new AssertionError("The number of parts does not match!"); } $result_type = new Union($result_type_parts); } } } if (!$literal_concat) { $numeric_type = new Union([new TNumericString(), new TInt(), new TFloat()]); $left_is_numeric = UnionTypeComparator::isContainedBy($codebase, $left_type, $numeric_type); $right_is_numeric = UnionTypeComparator::isContainedBy($codebase, $right_type, $numeric_type); $has_numeric_type = $left_is_numeric || $right_is_numeric; if ($left_is_numeric) { $right_uint = Type::getListKey(); $right_is_uint = UnionTypeComparator::isContainedBy($codebase, $right_type, $right_uint); if ($right_is_uint) { $result_type = Type::getNumericString(); return; } } $lowercase_type = $numeric_type->getBuilder()->addType(new TLowercaseString())->freeze(); $all_lowercase = UnionTypeComparator::isContainedBy($codebase, $left_type, $lowercase_type) && UnionTypeComparator::isContainedBy($codebase, $right_type, $lowercase_type); $non_empty_string = $numeric_type->getBuilder()->addType(new TNonEmptyString())->freeze(); $left_non_empty = UnionTypeComparator::isContainedBy($codebase, $left_type, $non_empty_string); $right_non_empty = UnionTypeComparator::isContainedBy($codebase, $right_type, $non_empty_string); $has_non_empty = $left_non_empty || $right_non_empty; $all_non_empty = $left_non_empty && $right_non_empty; $has_numeric_and_non_empty = $has_numeric_type && $has_non_empty; $non_falsy_string = $numeric_type->getBuilder()->addType(new TNonFalsyString())->freeze(); $left_non_falsy = UnionTypeComparator::isContainedBy($codebase, $left_type, $non_falsy_string); $right_non_falsy = UnionTypeComparator::isContainedBy($codebase, $right_type, $non_falsy_string); $all_literals = $left_type->allLiterals() && $right_type->allLiterals(); if ($has_non_empty) { if ($all_literals) { $result_type = new Union([new TNonEmptyNonspecificLiteralString()]); } elseif ($all_lowercase) { $result_type = Type::getNonEmptyLowercaseString(); } elseif ($all_non_empty || $has_numeric_and_non_empty || $left_non_falsy || $right_non_falsy) { $result_type = Type::getNonFalsyString(); } else { $result_type = Type::getNonEmptyString(); } } else { if ($all_literals) { $result_type = new Union([new TNonspecificLiteralString()]); } elseif ($all_lowercase) { $result_type = Type::getLowercaseString(); } else { $result_type = Type::getString(); } } } } elseif ($left_type || $right_type) { /** * @var Union $known_operand */ $known_operand = $right_type ?? $left_type; if ($known_operand->isSingle()) { $known_operands_atomic = $known_operand->getSingleAtomic(); if ($known_operands_atomic instanceof TNonEmptyString) { $result_type = Type::getNonEmptyString(); } if ($known_operands_atomic instanceof TNonFalsyString) { $result_type = Type::getNonFalsyString(); } if ($known_operands_atomic instanceof TLiteralString) { if ($known_operands_atomic->value) { $result_type = Type::getNonFalsyString(); } elseif ($known_operands_atomic->value !== '') { $result_type = Type::getNonEmptyString(); } } } } } private static function analyzeOperand(StatementsAnalyzer $statements_analyzer, PhpParser\Node\Expr $operand, Union $operand_type, string $side, Context $context) : void { $codebase = $statements_analyzer->getCodebase(); $config = Config::getInstance(); if ($operand_type->isNull()) { IssueBuffer::maybeAdd(new NullOperand('Cannot concatenate with a ' . $operand_type, new CodeLocation($statements_analyzer->getSource(), $operand)), $statements_analyzer->getSuppressedIssues()); return; } if ($operand_type->isFalse()) { IssueBuffer::maybeAdd(new FalseOperand('Cannot concatenate with a ' . $operand_type, new CodeLocation($statements_analyzer->getSource(), $operand)), $statements_analyzer->getSuppressedIssues()); return; } if ($operand_type->isNullable() && !$operand_type->ignore_nullable_issues) { IssueBuffer::maybeAdd(new PossiblyNullOperand('Cannot concatenate with a possibly null ' . $operand_type, new CodeLocation($statements_analyzer->getSource(), $operand)), $statements_analyzer->getSuppressedIssues()); } if ($operand_type->isFalsable() && !$operand_type->ignore_falsable_issues) { IssueBuffer::maybeAdd(new PossiblyFalseOperand('Cannot concatenate with a possibly false ' . $operand_type, new CodeLocation($statements_analyzer->getSource(), $operand)), $statements_analyzer->getSuppressedIssues()); } $operand_type_match = \true; $has_valid_operand = \false; $comparison_result = new TypeComparisonResult(); foreach ($operand_type->getAtomicTypes() as $operand_type_part) { if ($operand_type_part instanceof TTemplateParam && !$operand_type_part->as->isString()) { IssueBuffer::maybeAdd(new MixedOperand("{$side} operand cannot be a non-string template param", new CodeLocation($statements_analyzer->getSource(), $operand)), $statements_analyzer->getSuppressedIssues()); return; } if ($operand_type_part instanceof TNull || $operand_type_part instanceof TFalse) { continue; } $operand_type_part_match = AtomicTypeComparator::isContainedBy($codebase, $operand_type_part, new TString(), \false, \false, $comparison_result); $operand_type_match = $operand_type_match && $operand_type_part_match; $has_valid_operand = $has_valid_operand || $operand_type_part_match; if ($comparison_result->to_string_cast && $config->strict_binary_operands) { IssueBuffer::maybeAdd(new ImplicitToStringCast("{$side} side of concat op expects string, '{$operand_type}' provided with a __toString method", new CodeLocation($statements_analyzer->getSource(), $operand)), $statements_analyzer->getSuppressedIssues()); } foreach ($operand_type->getAtomicTypes() as $atomic_type) { if ($atomic_type instanceof TNamedObject) { $to_string_method_id = new MethodIdentifier($atomic_type->value, '__tostring'); if ($codebase->methods->methodExists($to_string_method_id, $context->calling_method_id, $codebase->collect_locations ? new CodeLocation($statements_analyzer->getSource(), $operand) : null, !$context->collect_initializations && !$context->collect_mutations ? $statements_analyzer : null, $statements_analyzer->getFilePath())) { try { $storage = $codebase->methods->getStorage($to_string_method_id); } catch (UnexpectedValueException $e) { continue; } if ($context->mutation_free && !$storage->mutation_free) { IssueBuffer::maybeAdd(new ImpureMethodCall('Cannot call a possibly-mutating method ' . $atomic_type->value . '::__toString from a pure context', new CodeLocation($statements_analyzer, $operand)), $statements_analyzer->getSuppressedIssues()); } elseif ($statements_analyzer->getSource() instanceof FunctionLikeAnalyzer && $statements_analyzer->getSource()->track_mutations) { $statements_analyzer->getSource()->inferred_has_mutation = \true; $statements_analyzer->getSource()->inferred_impure = \true; } } } } } if (!$operand_type_match && (!$comparison_result->scalar_type_match_found || $config->strict_binary_operands)) { if ($has_valid_operand) { IssueBuffer::maybeAdd(new PossiblyInvalidOperand('Cannot concatenate with a ' . $operand_type, new CodeLocation($statements_analyzer->getSource(), $operand)), $statements_analyzer->getSuppressedIssues()); } else { IssueBuffer::maybeAdd(new InvalidOperand('Cannot concatenate with a ' . $operand_type, new CodeLocation($statements_analyzer->getSource(), $operand)), $statements_analyzer->getSuppressedIssues()); } } } } left, $stmt->left->getAttributes()), ['stmts' => [new VirtualExpression($stmt->right)]], $stmt->getAttributes()); return IfElseAnalyzer::analyze($statements_analyzer, $fake_if_stmt, $context) !== \false; } $codebase = $statements_analyzer->getCodebase(); $post_leaving_if_context = null; // we cap this at max depth of 4 to prevent quadratic behaviour // when analysing || || || || if (!$stmt->left instanceof PhpParser\Node\Expr\BinaryOp\BooleanOr || !$stmt->left->left instanceof PhpParser\Node\Expr\BinaryOp\BooleanOr || !$stmt->left->left->left instanceof PhpParser\Node\Expr\BinaryOp\BooleanOr) { $if_scope = new IfScope(); try { $if_conditional_scope = IfConditionalAnalyzer::analyze($statements_analyzer, $stmt->left, $context, $codebase, $if_scope, $context->branch_point ?: (int) $stmt->getAttribute('startFilePos')); $left_context = $if_conditional_scope->if_context; $left_referenced_var_ids = $if_conditional_scope->cond_referenced_var_ids; $left_assigned_var_ids = $if_conditional_scope->assigned_in_conditional_var_ids; if ($stmt->left instanceof PhpParser\Node\Expr\BinaryOp\BooleanOr) { $post_leaving_if_context = clone $context; } } catch (ScopeAnalysisException $e) { return \false; } } else { $pre_referenced_var_ids = $context->cond_referenced_var_ids; $context->cond_referenced_var_ids = []; $pre_assigned_var_ids = $context->assigned_var_ids; $post_leaving_if_context = clone $context; $left_context = clone $context; $left_context->if_body_context = null; $left_context->assigned_var_ids = []; if (ExpressionAnalyzer::analyze($statements_analyzer, $stmt->left, $left_context) === \false) { return \false; } foreach ($left_context->parent_remove_vars as $var_id => $_) { $context->removeVarFromConflictingClauses($var_id); } IfConditionalAnalyzer::handleParadoxicalCondition($statements_analyzer, $stmt->left); foreach ($left_context->vars_in_scope as $var_id => $type) { if (!isset($context->vars_in_scope[$var_id])) { if (isset($left_context->assigned_var_ids[$var_id])) { $context->vars_in_scope[$var_id] = $type; } } else { $context->vars_in_scope[$var_id] = Type::combineUnionTypes($context->vars_in_scope[$var_id], $type, $codebase); } } $left_referenced_var_ids = $left_context->cond_referenced_var_ids; $left_context->cond_referenced_var_ids = array_merge($pre_referenced_var_ids, $left_referenced_var_ids); $left_assigned_var_ids = array_diff_key($left_context->assigned_var_ids, $pre_assigned_var_ids); $left_context->assigned_var_ids = array_merge($pre_assigned_var_ids, $left_context->assigned_var_ids); $left_referenced_var_ids = array_diff_key($left_referenced_var_ids, $left_assigned_var_ids); } $left_cond_id = spl_object_id($stmt->left); $left_clauses = FormulaGenerator::getFormula($left_cond_id, $left_cond_id, $stmt->left, $context->self, $statements_analyzer, $codebase); try { $negated_left_clauses = Algebra::negateFormula($left_clauses); } catch (ComplicatedExpressionException $e) { try { $negated_left_clauses = FormulaGenerator::getFormula($left_cond_id, $left_cond_id, new VirtualBooleanNot($stmt->left), $context->self, $statements_analyzer, $codebase, \false); } catch (ComplicatedExpressionException $e) { return \false; } } if ($left_context->reconciled_expression_clauses) { $reconciled_expression_clauses = $left_context->reconciled_expression_clauses; $negated_left_clauses = array_values(array_filter($negated_left_clauses, static fn(Clause $c): bool => !in_array($c->hash, $reconciled_expression_clauses))); if (count($negated_left_clauses) === 1 && $negated_left_clauses[0]->wedge && !$negated_left_clauses[0]->possibilities) { $negated_left_clauses = []; } } $clauses_for_right_analysis = Algebra::simplifyCNF([...$context->clauses, ...$negated_left_clauses]); $active_negated_type_assertions = []; $negated_type_assertions = Algebra::getTruthsFromFormula($clauses_for_right_analysis, $left_cond_id, $left_referenced_var_ids, $active_negated_type_assertions); $changed_var_ids = []; $right_context = clone $context; if ($stmt->left instanceof PhpParser\Node\Expr\BinaryOp\BooleanOr && $left_assigned_var_ids && $post_leaving_if_context) { IfAnalyzer::addConditionallyAssignedVarsToContext($statements_analyzer, $stmt->left, $post_leaving_if_context, $right_context, $left_assigned_var_ids); } if ($negated_type_assertions) { // while in an or, we allow scope to boil over to support // statements of the form if ($x === null || $x->foo()) [$right_context->vars_in_scope, $right_context->references_in_scope] = Reconciler::reconcileKeyedTypes($negated_type_assertions, $active_negated_type_assertions, $right_context->vars_in_scope, $right_context->references_in_scope, $changed_var_ids, $left_referenced_var_ids, $statements_analyzer, [], $left_context->inside_loop, new CodeLocation($statements_analyzer->getSource(), $stmt->left), !$context->inside_negation); } $right_context->clauses = $clauses_for_right_analysis; if ($changed_var_ids) { $partitioned_clauses = Context::removeReconciledClauses($right_context->clauses, $changed_var_ids); $right_context->clauses = $partitioned_clauses[0]; $right_context->reconciled_expression_clauses = $context->reconciled_expression_clauses; foreach ($partitioned_clauses[1] as $clause) { $right_context->reconciled_expression_clauses[] = $clause->hash; } $partitioned_clauses = Context::removeReconciledClauses($context->clauses, $changed_var_ids); $context->clauses = $partitioned_clauses[0]; foreach ($partitioned_clauses[1] as $clause) { $context->reconciled_expression_clauses[] = $clause->hash; } } $right_context->if_body_context = null; $pre_referenced_var_ids = $right_context->cond_referenced_var_ids; $right_context->cond_referenced_var_ids = []; $pre_assigned_var_ids = $right_context->assigned_var_ids; $right_context->assigned_var_ids = []; if (ExpressionAnalyzer::analyze($statements_analyzer, $stmt->right, $right_context) === \false) { return \false; } IfConditionalAnalyzer::handleParadoxicalCondition($statements_analyzer, $stmt->right); $right_referenced_var_ids = $right_context->cond_referenced_var_ids; $right_context->cond_referenced_var_ids = array_merge($pre_referenced_var_ids, $right_referenced_var_ids); $right_assigned_var_ids = $right_context->assigned_var_ids; $right_context->assigned_var_ids = array_merge($pre_assigned_var_ids, $right_assigned_var_ids); $right_cond_id = spl_object_id($stmt->right); $right_clauses = FormulaGenerator::getFormula($right_cond_id, $right_cond_id, $stmt->right, $context->self, $statements_analyzer, $codebase); $clauses_for_right_analysis = Context::removeReconciledClauses($clauses_for_right_analysis, $right_assigned_var_ids)[0]; $combined_right_clauses = Algebra::simplifyCNF([...$clauses_for_right_analysis, ...$right_clauses]); $active_right_type_assertions = []; $right_type_assertions = Algebra::getTruthsFromFormula($combined_right_clauses, $right_cond_id, $right_referenced_var_ids, $active_right_type_assertions); if ($right_type_assertions) { $right_changed_var_ids = []; Reconciler::reconcileKeyedTypes($right_type_assertions, $active_right_type_assertions, $right_context->vars_in_scope, $right_context->references_in_scope, $right_changed_var_ids, $right_referenced_var_ids, $statements_analyzer, [], $left_context->inside_loop, new CodeLocation($statements_analyzer->getSource(), $stmt->right), $context->inside_negation); } if (!$stmt->right instanceof PhpParser\Node\Expr\Exit_) { foreach ($right_context->vars_in_scope as $var_id => $type) { if (isset($context->vars_in_scope[$var_id])) { $context->vars_in_scope[$var_id] = Type::combineUnionTypes($context->vars_in_scope[$var_id], $type, $codebase); } } } elseif ($stmt->left instanceof PhpParser\Node\Expr\Assign) { $var_id = ExpressionIdentifier::getVarId($stmt->left->var, $context->self); if ($var_id && isset($left_context->vars_in_scope[$var_id])) { $left_inferred_reconciled = AssertionReconciler::reconcile(new Truthy(), $left_context->vars_in_scope[$var_id], '', $statements_analyzer, $context->inside_loop, [], new CodeLocation($statements_analyzer->getSource(), $stmt->left), $statements_analyzer->getSuppressedIssues()); $context->vars_in_scope[$var_id] = $left_inferred_reconciled; } } if ($context->inside_conditional) { $context->updateChecks($right_context); } $context->cond_referenced_var_ids = array_merge($right_context->cond_referenced_var_ids, $context->cond_referenced_var_ids); $context->assigned_var_ids = array_merge($context->assigned_var_ids, $right_context->assigned_var_ids); if ($context->if_body_context) { $if_body_context = $context->if_body_context; foreach ($right_context->vars_in_scope as $var_id => $type) { if (isset($if_body_context->vars_in_scope[$var_id])) { $if_body_context->vars_in_scope[$var_id] = Type::combineUnionTypes($type, $if_body_context->vars_in_scope[$var_id], $codebase); } elseif (isset($left_context->vars_in_scope[$var_id])) { $if_body_context->vars_in_scope[$var_id] = Type::combineUnionTypes($type, $left_context->vars_in_scope[$var_id], $codebase); } } $if_body_context->cond_referenced_var_ids = array_merge($context->cond_referenced_var_ids, $if_body_context->cond_referenced_var_ids); $if_body_context->assigned_var_ids = array_merge($context->assigned_var_ids, $if_body_context->assigned_var_ids); $if_body_context->updateChecks($context); } $context->vars_possibly_in_scope = array_merge($right_context->vars_possibly_in_scope, $context->vars_possibly_in_scope); return \true; } } expr, $context) === \false) { return \false; } if (!($stmt_expr_type = $statements_analyzer->node_data->getType($stmt->expr))) { $statements_analyzer->node_data->setType($stmt, new Union([new TInt(), new TString()])); } elseif ($stmt_expr_type->isMixed()) { $statements_analyzer->node_data->setType($stmt, Type::getMixed()); } else { $acceptable_types = []; $unacceptable_type = null; $has_valid_operand = \false; $stmt_expr_type = $stmt_expr_type->getBuilder(); foreach ($stmt_expr_type->getAtomicTypes() as $type_string => $type_part) { if ($type_part instanceof TInt || $type_part instanceof TString) { if ($type_part instanceof TLiteralInt) { $type_part = new TLiteralInt(~$type_part->value); } elseif ($type_part instanceof TLiteralString) { $type_part = Type::getAtomicStringFromLiteral(~$type_part->value); } $acceptable_types[] = $type_part; $has_valid_operand = \true; } elseif ($type_part instanceof TFloat) { $type_part = $type_part instanceof TLiteralFloat ? new TLiteralInt(~$type_part->value) : new TInt(); $stmt_expr_type->removeType($type_string); $stmt_expr_type->addType($type_part); $acceptable_types[] = $type_part; $has_valid_operand = \true; } elseif (!$unacceptable_type) { $unacceptable_type = $type_part; } } if ($unacceptable_type || !$acceptable_types) { $message = 'Cannot negate a non-numeric non-string type ' . $unacceptable_type; if ($has_valid_operand) { IssueBuffer::maybeAdd(new PossiblyInvalidOperand($message, new CodeLocation($statements_analyzer, $stmt)), $statements_analyzer->getSuppressedIssues()); } else { IssueBuffer::maybeAdd(new InvalidOperand($message, new CodeLocation($statements_analyzer, $stmt)), $statements_analyzer->getSuppressedIssues()); } $statements_analyzer->node_data->setType($stmt, Type::getMixed()); } else { $statements_analyzer->node_data->setType($stmt, new Union($acceptable_types)); } } self::addDataFlow($statements_analyzer, $stmt, $stmt->expr); return \true; } private static function addDataFlow(StatementsAnalyzer $statements_analyzer, PhpParser\Node\Expr $stmt, PhpParser\Node\Expr $value) : void { $result_type = $statements_analyzer->node_data->getType($stmt); if ($statements_analyzer->data_flow_graph instanceof VariableUseGraph && $result_type) { $var_location = new CodeLocation($statements_analyzer, $stmt); $stmt_value_type = $statements_analyzer->node_data->getType($value); $new_parent_node = DataFlowNode::getForAssignment('bitwisenot', $var_location); $statements_analyzer->data_flow_graph->addNode($new_parent_node); $result_type = $result_type->setParentNodes([$new_parent_node->id => $new_parent_node]); $statements_analyzer->node_data->setType($stmt, $result_type); if ($stmt_value_type && $stmt_value_type->parent_nodes) { foreach ($stmt_value_type->parent_nodes as $parent_node) { $statements_analyzer->data_flow_graph->addPath($parent_node, $new_parent_node, 'bitwisenot'); } } } } } 0) will be turned into an assertion to make psalm understand that in the * if block, $a is a positive-int */ final class AssertionFinder { public const ASSIGNMENT_TO_RIGHT = 1; public const ASSIGNMENT_TO_LEFT = -1; /** * Gets all the type assertions in a conditional * * @return list>>> */ public static function scrapeAssertions(PhpParser\Node\Expr $conditional, ?string $this_class_name, FileSource $source, ?Codebase $codebase = null, bool $inside_negation = \false, bool $cache = \true, bool $inside_conditional = \true) : array { $if_types = []; if ($conditional instanceof PhpParser\Node\Expr\Instanceof_) { return self::getAndCheckInstanceofAssertions($conditional, $codebase, $source, $this_class_name, $inside_negation); } if ($conditional instanceof PhpParser\Node\Expr\Assign) { $var_name = \Psalm\Internal\Analyzer\Statements\Expression\ExpressionIdentifier::getExtendedVarId($conditional->var, $this_class_name, $source); $candidate_if_types = $inside_conditional ? self::scrapeAssertions($conditional->expr, $this_class_name, $source, $codebase, $inside_negation, $cache, $inside_conditional) : []; if ($var_name) { if ($candidate_if_types) { $if_types[$var_name] = [[new NestedAssertions($candidate_if_types[0])]]; } else { $if_types[$var_name] = [[new Truthy()]]; } } return $if_types ? [$if_types] : []; } $var_name = \Psalm\Internal\Analyzer\Statements\Expression\ExpressionIdentifier::getExtendedVarId($conditional, $this_class_name, $source); if ($var_name) { $if_types[$var_name] = [[new Truthy()]]; if (!$conditional instanceof PhpParser\Node\Expr\MethodCall && !$conditional instanceof PhpParser\Node\Expr\StaticCall) { return [$if_types]; } } if ($conditional instanceof PhpParser\Node\Expr\BooleanNot) { return []; } if ($conditional instanceof PhpParser\Node\Expr\BinaryOp\Identical || $conditional instanceof PhpParser\Node\Expr\BinaryOp\Equal) { return self::scrapeEqualityAssertions($conditional, $this_class_name, $source, $codebase, $cache, $inside_conditional); } if ($conditional instanceof PhpParser\Node\Expr\BinaryOp\NotIdentical || $conditional instanceof PhpParser\Node\Expr\BinaryOp\NotEqual) { return self::scrapeInequalityAssertions($conditional, $this_class_name, $source, $codebase, $cache, $inside_conditional); } //A nullsafe method call basically adds an assertion !null for the checked variable if ($conditional instanceof PhpParser\Node\Expr\NullsafeMethodCall) { $if_types = []; $var_name = \Psalm\Internal\Analyzer\Statements\Expression\ExpressionIdentifier::getExtendedVarId($conditional->var, $this_class_name, $source); if ($var_name) { $if_types[$var_name] = [[new IsNotType(new TNull())]]; } //we may throw a RedundantNullsafeMethodCall here in the future if $var_name is never null return $if_types ? [$if_types] : []; } if ($conditional instanceof PhpParser\Node\Expr\BinaryOp\Greater || $conditional instanceof PhpParser\Node\Expr\BinaryOp\GreaterOrEqual) { return self::getGreaterAssertions($conditional, $source, $this_class_name); } if ($conditional instanceof PhpParser\Node\Expr\BinaryOp\Smaller || $conditional instanceof PhpParser\Node\Expr\BinaryOp\SmallerOrEqual) { return self::getSmallerAssertions($conditional, $source, $this_class_name); } if ($conditional instanceof PhpParser\Node\Expr\FuncCall && !$conditional->isFirstClassCallable()) { return self::processFunctionCall($conditional, $this_class_name, $source, $codebase, $inside_negation); } if (($conditional instanceof PhpParser\Node\Expr\MethodCall || $conditional instanceof PhpParser\Node\Expr\StaticCall) && !$conditional->isFirstClassCallable()) { $custom_assertions = self::processCustomAssertion($conditional, $this_class_name, $source); if ($custom_assertions) { return $custom_assertions; } return $if_types ? [$if_types] : []; } if ($conditional instanceof PhpParser\Node\Expr\Empty_) { $var_name = \Psalm\Internal\Analyzer\Statements\Expression\ExpressionIdentifier::getExtendedVarId($conditional->expr, $this_class_name, $source); if ($var_name) { if ($conditional->expr instanceof PhpParser\Node\Expr\Variable && $source instanceof StatementsAnalyzer && ($var_type = $source->node_data->getType($conditional->expr)) && !$var_type->isMixed() && !$var_type->possibly_undefined) { $if_types[$var_name] = [[new Falsy()]]; } else { $if_types[$var_name] = [[new Empty_()]]; } } return $if_types ? [$if_types] : []; } if ($conditional instanceof PhpParser\Node\Expr\Isset_) { foreach ($conditional->vars as $isset_var) { $var_name = \Psalm\Internal\Analyzer\Statements\Expression\ExpressionIdentifier::getExtendedVarId($isset_var, $this_class_name, $source); if ($var_name) { if ($isset_var instanceof PhpParser\Node\Expr\Variable && $source instanceof StatementsAnalyzer && ($var_type = $source->node_data->getType($isset_var)) && !$var_type->isMixed() && !$var_type->possibly_undefined && !$var_type->possibly_undefined_from_try) { $if_types[$var_name] = [[new IsNotType(new TNull())]]; } else { $if_types[$var_name] = [[new IsIsset()]]; } } else { // look for any variables we *can* use for an isset assertion $array_root = $isset_var; while ($array_root instanceof PhpParser\Node\Expr\ArrayDimFetch && !$var_name) { $array_root = $array_root->var; $var_name = \Psalm\Internal\Analyzer\Statements\Expression\ExpressionIdentifier::getExtendedVarId($array_root, $this_class_name, $source); } if ($var_name) { $if_types[$var_name] = [[new IsEqualIsset()]]; } } } return $if_types ? [$if_types] : []; } return []; } /** * @param PhpParser\Node\Expr\BinaryOp\Identical|PhpParser\Node\Expr\BinaryOp\Equal $conditional * @return list>>> */ private static function scrapeEqualityAssertions(PhpParser\Node\Expr\BinaryOp $conditional, ?string $this_class_name, FileSource $source, ?Codebase $codebase = null, bool $cache = \true, bool $inside_conditional = \true) : array { $null_position = self::hasNullVariable($conditional, $source); if ($null_position !== null) { return self::getNullEqualityAssertions($conditional, $this_class_name, $source, $codebase, $null_position); } $false_position = self::hasFalseVariable($conditional); if ($false_position) { return self::getFalseEqualityAssertions($conditional, $this_class_name, $source, $codebase, $false_position, $cache, $inside_conditional); } $true_position = self::hasTrueVariable($conditional); if ($true_position) { return self::getTrueEqualityAssertions($conditional, $this_class_name, $source, $codebase, $true_position, $cache, $inside_conditional); } $empty_array_position = self::hasEmptyArrayVariable($conditional); if ($empty_array_position !== null) { return self::getEmptyArrayEqualityAssertions($conditional, $this_class_name, $source, $codebase, $empty_array_position); } $gettype_position = self::hasGetTypeCheck($conditional); if ($gettype_position) { return self::getGettypeEqualityAssertions($conditional, $this_class_name, $source, $gettype_position); } $get_debug_type_position = self::hasGetDebugTypeCheck($conditional); if ($get_debug_type_position) { return self::getGetdebugtypeEqualityAssertions($conditional, $this_class_name, $source, $get_debug_type_position); } $count = null; $count_equality_position = self::hasCountEqualityCheck($conditional, $count); if ($count_equality_position) { $if_types = []; if ($count_equality_position === self::ASSIGNMENT_TO_RIGHT) { $count_expr = $conditional->left; } elseif ($count_equality_position === self::ASSIGNMENT_TO_LEFT) { $count_expr = $conditional->right; } else { throw new UnexpectedValueException('$count_equality_position value'); } /** @var PhpParser\Node\Expr\FuncCall $count_expr */ $var_name = \Psalm\Internal\Analyzer\Statements\Expression\ExpressionIdentifier::getExtendedVarId($count_expr->getArgs()[0]->value, $this_class_name, $source); if ($source instanceof StatementsAnalyzer) { $var_type = $source->node_data->getType($conditional->left); $other_type = $source->node_data->getType($conditional->right); if ($codebase && $other_type && $var_type && $conditional instanceof PhpParser\Node\Expr\BinaryOp\Identical) { self::handleParadoxicalAssertions($source, $var_type, $this_class_name, $other_type, $codebase, $conditional); } } if ($var_name) { if ($count > 0) { $if_types[$var_name] = [[new HasExactCount($count)]]; } else { $if_types[$var_name] = [[new NotNonEmptyCountable()]]; } } return $if_types ? [$if_types] : []; } if (!$source instanceof StatementsAnalyzer) { return []; } $getclass_position = self::hasGetClassCheck($conditional, $source); if ($getclass_position) { return self::getGetclassEqualityAssertions($conditional, $this_class_name, $source, $getclass_position); } $typed_value_position = self::hasTypedValueComparison($conditional, $source); if ($typed_value_position) { return self::getTypedValueEqualityAssertions($conditional, $this_class_name, $source, $codebase, $typed_value_position); } $var_type = $source->node_data->getType($conditional->left); $other_type = $source->node_data->getType($conditional->right); if ($codebase && $var_type && $other_type && $conditional instanceof PhpParser\Node\Expr\BinaryOp\Identical) { if (!UnionTypeComparator::canExpressionTypesBeIdentical($codebase, $var_type, $other_type)) { IssueBuffer::maybeAdd(new TypeDoesNotContainType($var_type->getId() . ' cannot be identical to ' . $other_type->getId(), new CodeLocation($source, $conditional), $var_type->getId() . ' ' . $other_type->getId()), $source->getSuppressedIssues()); } else { // both side of the Identical can be asserted to the intersection of both $intersection_type = Type::intersectUnionTypes($var_type, $other_type, $codebase, \false, \false); if ($intersection_type !== null) { $if_types = []; $var_name_left = \Psalm\Internal\Analyzer\Statements\Expression\ExpressionIdentifier::getExtendedVarId($conditional->left, $this_class_name, $source); $var_assertion_different = $var_type->getId() !== $intersection_type->getId(); $all_assertions = []; foreach ($intersection_type->getAtomicTypes() as $atomic_type) { $all_assertions[] = new IsIdentical($atomic_type); } if ($var_name_left && $var_assertion_different) { $if_types[$var_name_left] = [$all_assertions]; } $var_name_right = \Psalm\Internal\Analyzer\Statements\Expression\ExpressionIdentifier::getExtendedVarId($conditional->right, $this_class_name, $source); $other_assertion_different = $other_type->getId() !== $intersection_type->getId(); if ($var_name_right && $other_assertion_different) { $if_types[$var_name_right] = [$all_assertions]; } return $if_types ? [$if_types] : []; } } } return []; } /** * @param PhpParser\Node\Expr\BinaryOp\NotIdentical|PhpParser\Node\Expr\BinaryOp\NotEqual $conditional * @return list>>> */ private static function scrapeInequalityAssertions(PhpParser\Node\Expr\BinaryOp $conditional, ?string $this_class_name, FileSource $source, ?Codebase $codebase = null, bool $cache = \true, bool $inside_conditional = \true) : array { $null_position = self::hasNullVariable($conditional, $source); if ($null_position !== null) { return self::getNullInequalityAssertions($conditional, $source, $this_class_name, $codebase, $null_position); } $false_position = self::hasFalseVariable($conditional); if ($false_position) { return self::getFalseInequalityAssertions($conditional, $this_class_name, $source, $codebase, $false_position, $cache, $inside_conditional); } $true_position = self::hasTrueVariable($conditional); if ($true_position) { return self::getTrueInequalityAssertions($conditional, $this_class_name, $source, $codebase, $true_position, $cache, $inside_conditional); } $empty_array_position = self::hasEmptyArrayVariable($conditional); if ($empty_array_position !== null) { return self::getEmptyInequalityAssertions($conditional, $this_class_name, $source, $codebase, $empty_array_position); } $gettype_position = self::hasGetTypeCheck($conditional); if ($gettype_position) { return self::getGettypeInequalityAssertions($conditional, $this_class_name, $source, $gettype_position); } $get_debug_type_position = self::hasGetDebugTypeCheck($conditional); if ($get_debug_type_position) { return self::getGetdebugTypeInequalityAssertions($conditional, $this_class_name, $source, $get_debug_type_position); } $count = null; $count_inequality_position = self::hasCountEqualityCheck($conditional, $count); if ($count_inequality_position) { $if_types = []; if ($count_inequality_position === self::ASSIGNMENT_TO_RIGHT) { $count_expr = $conditional->left; } elseif ($count_inequality_position === self::ASSIGNMENT_TO_LEFT) { $count_expr = $conditional->right; } else { throw new UnexpectedValueException('$count_inequality_position value'); } /** @var PhpParser\Node\Expr\FuncCall $count_expr */ $var_name = \Psalm\Internal\Analyzer\Statements\Expression\ExpressionIdentifier::getExtendedVarId($count_expr->getArgs()[0]->value, $this_class_name, $source); if ($source instanceof StatementsAnalyzer) { $var_type = $source->node_data->getType($conditional->left); $other_type = $source->node_data->getType($conditional->right); if ($codebase && $other_type && $var_type && $conditional instanceof PhpParser\Node\Expr\BinaryOp\NotIdentical) { self::handleParadoxicalAssertions($source, $var_type, $this_class_name, $other_type, $codebase, $conditional); } } if ($var_name) { if ($count > 0) { $if_types[$var_name] = [[new DoesNotHaveExactCount($count)]]; } else { $if_types[$var_name] = [[new NonEmptyCountable(\true)]]; } } return $if_types ? [$if_types] : []; } if (!$source instanceof StatementsAnalyzer) { return []; } $getclass_position = self::hasGetClassCheck($conditional, $source); if ($getclass_position) { return self::getGetclassInequalityAssertions($conditional, $this_class_name, $source, $getclass_position); } $typed_value_position = self::hasTypedValueComparison($conditional, $source); if ($typed_value_position) { return self::getTypedValueInequalityAssertions($conditional, $this_class_name, $source, $codebase, $typed_value_position); } return []; } /** * @return list>>> */ public static function processFunctionCall(PhpParser\Node\Expr\FuncCall $expr, ?string $this_class_name, FileSource $source, ?Codebase $codebase = null, bool $negate = \false) : array { $first_var_name = isset($expr->getArgs()[0]->value) ? \Psalm\Internal\Analyzer\Statements\Expression\ExpressionIdentifier::getExtendedVarId($expr->getArgs()[0]->value, $this_class_name, $source) : null; $if_types = []; $first_var_type = isset($expr->getArgs()[0]->value) && $source instanceof StatementsAnalyzer ? $source->node_data->getType($expr->getArgs()[0]->value) : null; if ($tmp_if_types = self::handleIsTypeCheck($codebase, $source, $expr, $first_var_name, $first_var_type, $expr, $negate)) { $if_types = $tmp_if_types; } elseif ($source instanceof StatementsAnalyzer && self::hasIsACheck($expr, $source)) { return self::getIsaAssertions($expr, $source, $this_class_name, $first_var_name); } elseif (self::hasCallableCheck($expr)) { if ($first_var_name) { $if_types[$first_var_name] = [[new IsType(new TCallable())]]; } elseif ($expr->getArgs()[0]->value instanceof PhpParser\Node\Expr\Array_ && isset($expr->getArgs()[0]->value->items[0], $expr->getArgs()[0]->value->items[1]) && $expr->getArgs()[0]->value->items[1]->value instanceof PhpParser\Node\Scalar\String_) { $first_var_name_in_array_argument = \Psalm\Internal\Analyzer\Statements\Expression\ExpressionIdentifier::getExtendedVarId($expr->getArgs()[0]->value->items[0]->value, $this_class_name, $source); if ($first_var_name_in_array_argument) { $if_types[$first_var_name_in_array_argument] = [[new HasMethod($expr->getArgs()[0]->value->items[1]->value->value)]]; } } } elseif ($class_exists_check_type = self::hasClassExistsCheck($expr)) { if ($first_var_name) { $class_string_type = new TClassString('object', null, $class_exists_check_type === 1); $if_types[$first_var_name] = [[new IsType($class_string_type)]]; } } elseif ($class_exists_check_type = self::hasTraitExistsCheck($expr)) { if ($first_var_name) { if ($class_exists_check_type === 2) { $if_types[$first_var_name] = [[new IsType(new TTraitString())]]; } else { $if_types[$first_var_name] = [[new IsIdentical(new TTraitString())]]; } } } elseif (self::hasEnumExistsCheck($expr)) { if ($first_var_name) { $class_string = new TClassString('object', null, \false, \false, \true); $if_types[$first_var_name] = [[new IsType($class_string)]]; } } elseif (self::hasInterfaceExistsCheck($expr)) { if ($first_var_name) { $class_string = new TClassString('object', null, \false, \true, \false); $if_types[$first_var_name] = [[new IsType($class_string)]]; } } elseif (self::hasFunctionExistsCheck($expr)) { if ($first_var_name) { $if_types[$first_var_name] = [[new IsType(new TCallableString())]]; } } elseif ($expr->name instanceof PhpParser\Node\Name && strtolower($expr->name->getFirst()) === 'method_exists' && isset($expr->getArgs()[1]) && $expr->getArgs()[1]->value instanceof PhpParser\Node\Scalar\String_) { if ($first_var_name) { $if_types[$first_var_name] = [[new HasMethod($expr->getArgs()[1]->value->value)]]; } } elseif (self::hasInArrayCheck($expr) && $source instanceof StatementsAnalyzer) { return self::getInarrayAssertions($expr, $source, $first_var_name); } elseif (self::hasArrayKeyExistsCheck($expr)) { return self::getArrayKeyExistsAssertions($expr, $first_var_type, $first_var_name, $source, $this_class_name); } elseif (self::hasNonEmptyCountCheck($expr)) { if ($first_var_name) { $if_types[$first_var_name] = [[new NonEmptyCountable(\true)]]; } } else { return self::processCustomAssertion($expr, $this_class_name, $source); } return $if_types ? [$if_types] : []; } private static function processIrreconcilableFunctionCall(Union $first_var_type, Union $expected_type, PhpParser\Node\Expr $expr, StatementsAnalyzer $source, Codebase $codebase, bool $negate) : void { if ($first_var_type->hasMixed()) { return; } if (!UnionTypeComparator::isContainedBy($codebase, $first_var_type, $expected_type)) { return; } if (!$negate) { if ($first_var_type->from_docblock) { IssueBuffer::maybeAdd(new RedundantConditionGivenDocblockType('Docblock type ' . $first_var_type . ' always contains ' . $expected_type, new CodeLocation($source, $expr), $first_var_type . ' ' . $expected_type), $source->getSuppressedIssues()); } else { IssueBuffer::maybeAdd(new RedundantCondition($first_var_type . ' always contains ' . $expected_type, new CodeLocation($source, $expr), $first_var_type . ' ' . $expected_type), $source->getSuppressedIssues()); } } else { if ($first_var_type->from_docblock) { IssueBuffer::maybeAdd(new DocblockTypeContradiction('Docblock type !' . $first_var_type . ' does not contain ' . $expected_type, new CodeLocation($source, $expr), $first_var_type . ' ' . $expected_type), $source->getSuppressedIssues()); } else { IssueBuffer::maybeAdd(new TypeDoesNotContainType('!' . $first_var_type . ' does not contain ' . $expected_type, new CodeLocation($source, $expr), $first_var_type . ' ' . $expected_type), $source->getSuppressedIssues()); } } } /** * @param PhpParser\Node\Expr\FuncCall|PhpParser\Node\Expr\MethodCall|PhpParser\Node\Expr\StaticCall $expr * @return list>>> */ protected static function processCustomAssertion(PhpParser\Node\Expr $expr, ?string $this_class_name, FileSource $source) : array { if (!$source instanceof StatementsAnalyzer) { return []; } $if_true_assertions = $source->node_data->getIfTrueAssertions($expr); $if_false_assertions = $source->node_data->getIfFalseAssertions($expr); if ($if_true_assertions === null && $if_false_assertions === null) { return []; } $first_var_name = isset($expr->getArgs()[0]->value) ? \Psalm\Internal\Analyzer\Statements\Expression\ExpressionIdentifier::getExtendedVarId($expr->getArgs()[0]->value, $this_class_name, $source) : null; $anded_types = []; if ($if_true_assertions) { foreach ($if_true_assertions as $assertion) { $if_types = []; $newRules = []; foreach ($assertion->rule as $rule) { $rule_type = $rule->getAtomicType(); if ($rule_type instanceof TClassConstant) { $codebase = $source->getCodebase(); $newRules[] = $rule->setAtomicType(TypeExpander::expandAtomic($codebase, $rule_type, null, null, null)[0]); } else { $newRules[] = $rule; } } $assertion = new Possibilities($assertion->var_id, $newRules); if (is_int($assertion->var_id) && isset($expr->getArgs()[$assertion->var_id])) { if ($assertion->var_id === 0) { $var_name = $first_var_name; } else { $var_name = \Psalm\Internal\Analyzer\Statements\Expression\ExpressionIdentifier::getExtendedVarId($expr->getArgs()[$assertion->var_id]->value, $this_class_name, $source); } if ($var_name) { $if_types[$var_name] = [[$assertion->rule[0]]]; } } elseif ($assertion->var_id === '$this') { if (!$expr instanceof PhpParser\Node\Expr\MethodCall) { IssueBuffer::maybeAdd(new InvalidDocblock('Assertion of $this can be done only on method of a class', new CodeLocation($source, $expr))); continue; } $var_id = \Psalm\Internal\Analyzer\Statements\Expression\ExpressionIdentifier::getExtendedVarId($expr->var, $this_class_name, $source); if ($var_id) { $if_types[$var_id] = [[$assertion->rule[0]]]; } } elseif (is_string($assertion->var_id)) { $is_function = substr($assertion->var_id, -2) === '()'; $exploded_id = explode('->', $assertion->var_id); $var_id = $exploded_id[0] ?? null; $property = $exploded_id[1] ?? null; if (is_numeric($var_id) && null !== $property && !$is_function) { $var_id_int = (int) $var_id; assert($var_id_int >= 0); $args = $expr->getArgs(); if (!array_key_exists($var_id_int, $args)) { IssueBuffer::maybeAdd(new InvalidDocblock('Variable ' . $var_id . ' is not an argument so cannot be asserted', new CodeLocation($source, $expr))); continue; } $arg_value = $args[$var_id_int]->value; assert($arg_value instanceof PhpParser\Node\Expr\Variable); $arg_var_id = \Psalm\Internal\Analyzer\Statements\Expression\ExpressionIdentifier::getExtendedVarId($arg_value, null, $source); if (null === $arg_var_id) { IssueBuffer::maybeAdd(new InvalidDocblock('Variable being asserted as argument ' . ($var_id + 1) . ' cannot be found in local scope', new CodeLocation($source, $expr))); continue; } if (count($exploded_id) === 2) { $failedMessage = self::isPropertyImmutableOnArgument($property, $source->getNodeTypeProvider(), $source->getCodebase()->classlike_storage_provider, $arg_value); if (null !== $failedMessage) { IssueBuffer::maybeAdd(new InvalidDocblock($failedMessage, new CodeLocation($source, $expr))); continue; } } $assertion_var_id = str_replace($var_id, $arg_var_id, $assertion->var_id); } elseif (!$expr instanceof PhpParser\Node\Expr\FuncCall) { $assertion_var_id = $assertion->var_id; if (strpos($assertion_var_id, 'self::') === 0) { $assertion_var_id = $this_class_name . '::' . substr($assertion_var_id, 6); } } else { IssueBuffer::maybeAdd(new InvalidDocblock(sprintf('Assertion of variable "%s" cannot be recognized', $assertion->var_id), new CodeLocation($source, $expr))); continue; } $if_types[$assertion_var_id] = [[$assertion->rule[0]]]; } if ($if_types) { $anded_types[] = $if_types; } } } if ($if_false_assertions) { foreach ($if_false_assertions as $assertion) { $if_types = []; $newRules = []; foreach ($assertion->rule as $rule) { $rule_type = $rule->getAtomicType(); if ($rule_type instanceof TClassConstant) { $codebase = $source->getCodebase(); $newRules[] = $rule->setAtomicType(TypeExpander::expandAtomic($codebase, $rule_type, null, null, null)[0]); } else { $newRules[] = $rule; } } $assertion = new Possibilities($assertion->var_id, $newRules); if (is_int($assertion->var_id) && isset($expr->getArgs()[$assertion->var_id])) { if ($assertion->var_id === 0) { $var_name = $first_var_name; } else { $var_name = \Psalm\Internal\Analyzer\Statements\Expression\ExpressionIdentifier::getExtendedVarId($expr->getArgs()[$assertion->var_id]->value, $this_class_name, $source); } if ($var_name) { $if_types[$var_name] = [[$assertion->rule[0]->getNegation()]]; } } elseif ($assertion->var_id === '$this' && $expr instanceof PhpParser\Node\Expr\MethodCall) { $var_id = \Psalm\Internal\Analyzer\Statements\Expression\ExpressionIdentifier::getExtendedVarId($expr->var, $this_class_name, $source); if ($var_id) { $if_types[$var_id] = [[$assertion->rule[0]->getNegation()]]; } } elseif (is_string($assertion->var_id)) { $is_function = substr($assertion->var_id, -2) === '()'; $exploded_id = explode('->', $assertion->var_id); $var_id = $exploded_id[0] ?? null; $property = $exploded_id[1] ?? null; if (is_numeric($var_id) && null !== $property && !$is_function) { $args = $expr->getArgs(); $var_id_int = (int) $var_id; if (!array_key_exists($var_id_int, $args)) { IssueBuffer::maybeAdd(new InvalidDocblock('Variable ' . $var_id . ' is not an argument so cannot be asserted', new CodeLocation($source, $expr))); continue; } /** @var PhpParser\Node\Expr\Variable $arg_value */ $arg_value = $args[$var_id_int]->value; $arg_var_id = \Psalm\Internal\Analyzer\Statements\Expression\ExpressionIdentifier::getExtendedVarId($arg_value, null, $source); if (null === $arg_var_id) { IssueBuffer::maybeAdd(new InvalidDocblock('Variable being asserted as argument ' . ($var_id + 1) . ' cannot be found in local scope', new CodeLocation($source, $expr))); continue; } if (count($exploded_id) === 2) { $failedMessage = self::isPropertyImmutableOnArgument($property, $source->getNodeTypeProvider(), $source->getCodebase()->classlike_storage_provider, $arg_value); if (null !== $failedMessage) { IssueBuffer::maybeAdd(new InvalidDocblock($failedMessage, new CodeLocation($source, $expr))); continue; } } $rule = $assertion->rule[0]->getNegation(); $assertion_var_id = str_replace($var_id, $arg_var_id, $assertion->var_id); $if_types[$assertion_var_id] = [[$rule]]; } elseif (!$expr instanceof PhpParser\Node\Expr\FuncCall) { $var_id = $assertion->var_id; if (strpos($var_id, 'self::') === 0) { $var_id = $this_class_name . '::' . substr($var_id, 6); } $if_types[$var_id] = [[$assertion->rule[0]->getNegation()]]; } else { IssueBuffer::maybeAdd(new InvalidDocblock(sprintf('Assertion of variable "%s" cannot be recognized', $assertion->var_id), new CodeLocation($source, $expr))); } } if ($if_types) { $anded_types[] = $if_types; } } } return $anded_types; } /** * @return list */ protected static function getInstanceOfAssertions(PhpParser\Node\Expr\Instanceof_ $stmt, ?string $this_class_name, FileSource $source) : array { if ($stmt->class instanceof PhpParser\Node\Name) { if (!in_array(strtolower($stmt->class->getFirst()), ['self', 'static', 'parent'], \true)) { $instanceof_class = ClassLikeAnalyzer::getFQCLNFromNameObject($stmt->class, $source->getAliases()); if ($source instanceof StatementsAnalyzer) { $codebase = $source->getCodebase(); $instanceof_class = $codebase->classlikes->getUnAliasedName($instanceof_class); } return [new IsType(TNamedObject::createFromName($instanceof_class))]; } if ($this_class_name && in_array(strtolower($stmt->class->getFirst()), ['self', 'static'], \true)) { $is_static = $stmt->class->getFirst() === 'static'; $named_object = new TNamedObject($this_class_name, $is_static); if ($is_static) { return [new IsIdentical($named_object)]; } return [new IsType($named_object)]; } } elseif ($source instanceof StatementsAnalyzer) { $stmt_class_type = $source->node_data->getType($stmt->class); if ($stmt_class_type) { $literal_class_strings = []; foreach ($stmt_class_type->getAtomicTypes() as $atomic_type) { if ($atomic_type instanceof TLiteralClassString) { $literal_class_strings[] = new IsType(new TNamedObject($atomic_type->value)); } elseif ($atomic_type instanceof TTemplateParamClass) { $literal_class_strings[] = new IsType(new TTemplateParam($atomic_type->param_name, new Union([$atomic_type->as_type ?: new TObject()]), $atomic_type->defining_class)); } elseif ($atomic_type instanceof TClassString && $atomic_type->as !== 'object') { $literal_class_strings[] = new IsType($atomic_type->as_type ?: new TNamedObject($atomic_type->as)); } } return $literal_class_strings; } } return []; } /** * @param Identical|Equal|NotIdentical|NotEqual $conditional */ protected static function hasNullVariable(PhpParser\Node\Expr\BinaryOp $conditional, FileSource $source) : ?int { if ($conditional->right instanceof PhpParser\Node\Expr\ConstFetch && strtolower($conditional->right->name->getFirst()) === 'null') { return self::ASSIGNMENT_TO_RIGHT; } if ($conditional->left instanceof PhpParser\Node\Expr\ConstFetch && strtolower($conditional->left->name->getFirst()) === 'null') { return self::ASSIGNMENT_TO_LEFT; } if ($source instanceof StatementsAnalyzer && ($right_type = $source->node_data->getType($conditional->right)) && $right_type->isNull()) { return self::ASSIGNMENT_TO_RIGHT; } return null; } /** * @param Identical|Equal|NotIdentical|NotEqual $conditional */ public static function hasFalseVariable(PhpParser\Node\Expr\BinaryOp $conditional) : ?int { if ($conditional->right instanceof PhpParser\Node\Expr\ConstFetch && strtolower($conditional->right->name->getFirst()) === 'false') { return self::ASSIGNMENT_TO_RIGHT; } if ($conditional->left instanceof PhpParser\Node\Expr\ConstFetch && strtolower($conditional->left->name->getFirst()) === 'false') { return self::ASSIGNMENT_TO_LEFT; } return null; } /** * @param Identical|Equal|NotIdentical|NotEqual $conditional */ public static function hasTrueVariable(PhpParser\Node\Expr\BinaryOp $conditional) : ?int { if ($conditional->right instanceof PhpParser\Node\Expr\ConstFetch && strtolower($conditional->right->name->getFirst()) === 'true') { return self::ASSIGNMENT_TO_RIGHT; } if ($conditional->left instanceof PhpParser\Node\Expr\ConstFetch && strtolower($conditional->left->name->getFirst()) === 'true') { return self::ASSIGNMENT_TO_LEFT; } return null; } /** * @param Identical|Equal|NotIdentical|NotEqual $conditional */ protected static function hasEmptyArrayVariable(PhpParser\Node\Expr\BinaryOp $conditional) : ?int { if ($conditional->right instanceof PhpParser\Node\Expr\Array_ && !$conditional->right->items) { return self::ASSIGNMENT_TO_RIGHT; } if ($conditional->left instanceof PhpParser\Node\Expr\Array_ && !$conditional->left->items) { return self::ASSIGNMENT_TO_LEFT; } return null; } /** * @param Identical|Equal|NotIdentical|NotEqual $conditional * @return false|int */ protected static function hasGetTypeCheck(PhpParser\Node\Expr\BinaryOp $conditional) { if ($conditional->right instanceof PhpParser\Node\Expr\FuncCall && $conditional->right->name instanceof PhpParser\Node\Name && strtolower($conditional->right->name->getFirst()) === 'gettype' && $conditional->right->getArgs() && $conditional->left instanceof PhpParser\Node\Scalar\String_) { return self::ASSIGNMENT_TO_RIGHT; } if ($conditional->left instanceof PhpParser\Node\Expr\FuncCall && $conditional->left->name instanceof PhpParser\Node\Name && strtolower($conditional->left->name->getFirst()) === 'gettype' && $conditional->left->getArgs() && $conditional->right instanceof PhpParser\Node\Scalar\String_) { return self::ASSIGNMENT_TO_LEFT; } return \false; } /** * @param Identical|Equal|NotIdentical|NotEqual $conditional * @return false|int */ protected static function hasGetDebugTypeCheck(PhpParser\Node\Expr\BinaryOp $conditional) { if ($conditional->right instanceof PhpParser\Node\Expr\FuncCall && $conditional->right->name instanceof PhpParser\Node\Name && strtolower($conditional->right->name->getFirst()) === 'get_debug_type' && $conditional->right->getArgs() && ($conditional->left instanceof PhpParser\Node\Scalar\String_ || $conditional->left instanceof PhpParser\Node\Expr\ClassConstFetch)) { return self::ASSIGNMENT_TO_RIGHT; } if ($conditional->left instanceof PhpParser\Node\Expr\FuncCall && $conditional->left->name instanceof PhpParser\Node\Name && strtolower($conditional->left->name->getFirst()) === 'get_debug_type' && $conditional->left->getArgs() && ($conditional->right instanceof PhpParser\Node\Scalar\String_ || $conditional->right instanceof PhpParser\Node\Expr\ClassConstFetch)) { return self::ASSIGNMENT_TO_LEFT; } return \false; } /** * @param Identical|Equal|NotIdentical|NotEqual $conditional * @return false|int */ protected static function hasGetClassCheck(PhpParser\Node\Expr\BinaryOp $conditional, FileSource $source) { if (!$source instanceof StatementsAnalyzer) { return \false; } $right_get_class = $conditional->right instanceof PhpParser\Node\Expr\FuncCall && $conditional->right->name instanceof PhpParser\Node\Name && strtolower($conditional->right->name->getFirst()) === 'get_class'; $right_static_class = $conditional->right instanceof PhpParser\Node\Expr\ClassConstFetch && $conditional->right->class instanceof PhpParser\Node\Name && $conditional->right->class->getParts() === ['static'] && $conditional->right->name instanceof PhpParser\Node\Identifier && strtolower($conditional->right->name->name) === 'class'; $right_variable_class_const = $conditional->right instanceof PhpParser\Node\Expr\ClassConstFetch && $conditional->right->class instanceof PhpParser\Node\Expr\Variable && $conditional->right->name instanceof PhpParser\Node\Identifier && strtolower($conditional->right->name->name) === 'class'; $left_class_string = $conditional->left instanceof PhpParser\Node\Expr\ClassConstFetch && $conditional->left->class instanceof PhpParser\Node\Name && $conditional->left->name instanceof PhpParser\Node\Identifier && strtolower($conditional->left->name->name) === 'class'; $left_type = $source->node_data->getType($conditional->left); $left_class_string_t = \false; if ($left_type && $left_type->isSingle()) { foreach ($left_type->getAtomicTypes() as $type_part) { if ($type_part instanceof TClassString) { $left_class_string_t = \true; break; } } } if (($right_get_class || $right_static_class || $right_variable_class_const) && ($left_class_string || $left_class_string_t)) { return self::ASSIGNMENT_TO_RIGHT; } $left_get_class = $conditional->left instanceof PhpParser\Node\Expr\FuncCall && $conditional->left->name instanceof PhpParser\Node\Name && strtolower($conditional->left->name->getFirst()) === 'get_class'; $left_static_class = $conditional->left instanceof PhpParser\Node\Expr\ClassConstFetch && $conditional->left->class instanceof PhpParser\Node\Name && $conditional->left->class->getParts() === ['static'] && $conditional->left->name instanceof PhpParser\Node\Identifier && strtolower($conditional->left->name->name) === 'class'; $left_variable_class_const = $conditional->left instanceof PhpParser\Node\Expr\ClassConstFetch && $conditional->left->class instanceof PhpParser\Node\Expr\Variable && $conditional->left->name instanceof PhpParser\Node\Identifier && strtolower($conditional->left->name->name) === 'class'; $right_class_string = $conditional->right instanceof PhpParser\Node\Expr\ClassConstFetch && $conditional->right->class instanceof PhpParser\Node\Name && $conditional->right->name instanceof PhpParser\Node\Identifier && strtolower($conditional->right->name->name) === 'class'; $right_type = $source->node_data->getType($conditional->right); $right_class_string_t = \false; if ($right_type && $right_type->isSingle()) { foreach ($right_type->getAtomicTypes() as $type_part) { if ($type_part instanceof TClassString) { $right_class_string_t = \true; break; } } } if (($left_get_class || $left_static_class || $left_variable_class_const) && ($right_class_string || $right_class_string_t)) { return self::ASSIGNMENT_TO_LEFT; } return \false; } /** * @param Greater|GreaterOrEqual|Smaller|SmallerOrEqual $conditional * @return false|int */ protected static function hasNonEmptyCountEqualityCheck(PhpParser\Node\Expr\BinaryOp $conditional, ?int &$min_count) { if ($conditional->left instanceof PhpParser\Node\Expr\FuncCall && $conditional->left->name instanceof PhpParser\Node\Name && in_array(strtolower($conditional->left->name->getFirst()), ['count', 'sizeof']) && $conditional->left->getArgs() && ($conditional instanceof BinaryOp\Greater || $conditional instanceof BinaryOp\GreaterOrEqual)) { $assignment_to = self::ASSIGNMENT_TO_RIGHT; $compare_to = $conditional->right; $comparison_adjustment = $conditional instanceof BinaryOp\Greater ? 1 : 0; } elseif ($conditional->right instanceof PhpParser\Node\Expr\FuncCall && $conditional->right->name instanceof PhpParser\Node\Name && in_array(strtolower($conditional->right->name->getFirst()), ['count', 'sizeof']) && $conditional->right->getArgs() && ($conditional instanceof BinaryOp\Smaller || $conditional instanceof BinaryOp\SmallerOrEqual)) { $assignment_to = self::ASSIGNMENT_TO_LEFT; $compare_to = $conditional->left; $comparison_adjustment = $conditional instanceof BinaryOp\Smaller ? 1 : 0; } else { return \false; } // TODO get node type provider here somehow and check literal ints and int ranges if ($compare_to instanceof PhpParser\Node\Scalar\LNumber && $compare_to->value > -1 * $comparison_adjustment) { $min_count = $compare_to->value + $comparison_adjustment; return $assignment_to; } return \false; } /** * @param Greater|GreaterOrEqual|Smaller|SmallerOrEqual $conditional * @return false|int */ protected static function hasLessThanCountEqualityCheck(PhpParser\Node\Expr\BinaryOp $conditional, ?int &$max_count) { $left_count = $conditional->left instanceof PhpParser\Node\Expr\FuncCall && $conditional->left->name instanceof PhpParser\Node\Name && in_array(strtolower($conditional->left->name->getFirst()), ['count', 'sizeof']) && $conditional->left->getArgs(); $operator_less_than_or_equal = $conditional instanceof PhpParser\Node\Expr\BinaryOp\SmallerOrEqual || $conditional instanceof PhpParser\Node\Expr\BinaryOp\Smaller; if ($left_count && $operator_less_than_or_equal && $conditional->right instanceof PhpParser\Node\Scalar\LNumber) { $max_count = $conditional->right->value - ($conditional instanceof PhpParser\Node\Expr\BinaryOp\Smaller ? 1 : 0); return self::ASSIGNMENT_TO_RIGHT; } $right_count = $conditional->right instanceof PhpParser\Node\Expr\FuncCall && $conditional->right->name instanceof PhpParser\Node\Name && in_array(strtolower($conditional->right->name->getFirst()), ['count', 'sizeof']) && $conditional->right->getArgs(); $operator_greater_than_or_equal = $conditional instanceof PhpParser\Node\Expr\BinaryOp\GreaterOrEqual || $conditional instanceof PhpParser\Node\Expr\BinaryOp\Greater; if ($right_count && $operator_greater_than_or_equal && $conditional->left instanceof PhpParser\Node\Scalar\LNumber) { $max_count = $conditional->left->value - ($conditional instanceof PhpParser\Node\Expr\BinaryOp\Greater ? 1 : 0); return self::ASSIGNMENT_TO_LEFT; } return \false; } /** * @param Equal|Identical|NotEqual|NotIdentical $conditional * @return false|int */ protected static function hasCountEqualityCheck(PhpParser\Node\Expr\BinaryOp $conditional, ?int &$count) { $left_count = $conditional->left instanceof PhpParser\Node\Expr\FuncCall && $conditional->left->name instanceof PhpParser\Node\Name && in_array(strtolower($conditional->left->name->getFirst()), ['count', 'sizeof']) && $conditional->left->getArgs(); if ($left_count && $conditional->right instanceof PhpParser\Node\Scalar\LNumber) { $count = $conditional->right->value; return self::ASSIGNMENT_TO_RIGHT; } $right_count = $conditional->right instanceof PhpParser\Node\Expr\FuncCall && $conditional->right->name instanceof PhpParser\Node\Name && in_array(strtolower($conditional->right->name->getFirst()), ['count', 'sizeof']) && $conditional->right->getArgs(); if ($right_count && $conditional->left instanceof PhpParser\Node\Scalar\LNumber) { $count = $conditional->left->value; return self::ASSIGNMENT_TO_LEFT; } return \false; } /** * @param PhpParser\Node\Expr\BinaryOp\Greater|PhpParser\Node\Expr\BinaryOp\GreaterOrEqual $conditional * @return false|int */ protected static function hasSuperiorNumberCheck(FileSource $source, PhpParser\Node\Expr\BinaryOp $conditional, ?int &$literal_value_comparison) { $right_assignment = \false; $value_right = null; if ($source instanceof StatementsAnalyzer && ($type = $source->node_data->getType($conditional->right)) && $type->isSingleIntLiteral()) { $right_assignment = \true; $value_right = $type->getSingleIntLiteral()->value; } elseif ($conditional->right instanceof LNumber) { $right_assignment = \true; $value_right = $conditional->right->value; } elseif ($conditional->right instanceof UnaryMinus && $conditional->right->expr instanceof LNumber) { $right_assignment = \true; $value_right = -$conditional->right->expr->value; } elseif ($conditional->right instanceof UnaryPlus && $conditional->right->expr instanceof LNumber) { $right_assignment = \true; $value_right = $conditional->right->expr->value; } if ($right_assignment === \true && $value_right !== null) { $literal_value_comparison = $value_right; return self::ASSIGNMENT_TO_RIGHT; } $left_assignment = \false; $value_left = null; if ($source instanceof StatementsAnalyzer && ($type = $source->node_data->getType($conditional->left)) && $type->isSingleIntLiteral()) { $left_assignment = \true; $value_left = $type->getSingleIntLiteral()->value; } elseif ($conditional->left instanceof LNumber) { $left_assignment = \true; $value_left = $conditional->left->value; } elseif ($conditional->left instanceof UnaryMinus && $conditional->left->expr instanceof LNumber) { $left_assignment = \true; $value_left = -$conditional->left->expr->value; } elseif ($conditional->left instanceof UnaryPlus && $conditional->left->expr instanceof LNumber) { $left_assignment = \true; $value_left = $conditional->left->expr->value; } if ($left_assignment === \true && $value_left !== null) { $literal_value_comparison = $value_left; return self::ASSIGNMENT_TO_LEFT; } return \false; } /** * @param PhpParser\Node\Expr\BinaryOp\Smaller|PhpParser\Node\Expr\BinaryOp\SmallerOrEqual $conditional * @return false|int */ protected static function hasInferiorNumberCheck(FileSource $source, PhpParser\Node\Expr\BinaryOp $conditional, ?int &$literal_value_comparison) { $right_assignment = \false; $value_right = null; if ($source instanceof StatementsAnalyzer && ($type = $source->node_data->getType($conditional->right)) && $type->isSingleIntLiteral()) { $right_assignment = \true; $value_right = $type->getSingleIntLiteral()->value; } elseif ($conditional->right instanceof LNumber) { $right_assignment = \true; $value_right = $conditional->right->value; } elseif ($conditional->right instanceof UnaryMinus && $conditional->right->expr instanceof LNumber) { $right_assignment = \true; $value_right = -$conditional->right->expr->value; } elseif ($conditional->right instanceof UnaryPlus && $conditional->right->expr instanceof LNumber) { $right_assignment = \true; $value_right = $conditional->right->expr->value; } if ($right_assignment === \true && $value_right !== null) { $literal_value_comparison = $value_right; return self::ASSIGNMENT_TO_RIGHT; } $left_assignment = \false; $value_left = null; if ($source instanceof StatementsAnalyzer && ($type = $source->node_data->getType($conditional->left)) && $type->isSingleIntLiteral()) { $left_assignment = \true; $value_left = $type->getSingleIntLiteral()->value; } elseif ($conditional->left instanceof LNumber) { $left_assignment = \true; $value_left = $conditional->left->value; } elseif ($conditional->left instanceof UnaryMinus && $conditional->left->expr instanceof LNumber) { $left_assignment = \true; $value_left = -$conditional->left->expr->value; } elseif ($conditional->left instanceof UnaryPlus && $conditional->left->expr instanceof LNumber) { $left_assignment = \true; $value_left = $conditional->left->expr->value; } if ($left_assignment === \true && $value_left !== null) { $literal_value_comparison = $value_left; return self::ASSIGNMENT_TO_LEFT; } return \false; } /** * @param PhpParser\Node\Expr\BinaryOp\Greater|PhpParser\Node\Expr\BinaryOp\GreaterOrEqual $conditional * @return false|int */ protected static function hasReconcilableNonEmptyCountEqualityCheck(PhpParser\Node\Expr\BinaryOp $conditional) { $left_count = $conditional->left instanceof PhpParser\Node\Expr\FuncCall && $conditional->left->name instanceof PhpParser\Node\Name && in_array(strtolower($conditional->left->name->getFirst()), ['count', 'sizeof']); $right_number = $conditional->right instanceof PhpParser\Node\Scalar\LNumber && $conditional->right->value === ($conditional instanceof PhpParser\Node\Expr\BinaryOp\Greater ? 0 : 1); if ($left_count && $right_number) { return self::ASSIGNMENT_TO_RIGHT; } return \false; } /** * @param Identical|Equal|NotIdentical|NotEqual $conditional * @return false|int */ protected static function hasTypedValueComparison(PhpParser\Node\Expr\BinaryOp $conditional, FileSource $source) { if (!$source instanceof StatementsAnalyzer) { return \false; } if (($right_type = $source->node_data->getType($conditional->right)) && (!$conditional->right instanceof PhpParser\Node\Expr\Variable && !$conditional->right instanceof PhpParser\Node\Expr\PropertyFetch && !$conditional->right instanceof PhpParser\Node\Expr\StaticPropertyFetch || $conditional->left instanceof PhpParser\Node\Expr\Variable || $conditional->left instanceof PhpParser\Node\Expr\PropertyFetch || $conditional->left instanceof PhpParser\Node\Expr\StaticPropertyFetch) && count($right_type->getAtomicTypes()) === 1 && !$right_type->hasMixed()) { return self::ASSIGNMENT_TO_RIGHT; } if (($left_type = $source->node_data->getType($conditional->left)) && !$conditional->left instanceof PhpParser\Node\Expr\Variable && !$conditional->left instanceof PhpParser\Node\Expr\PropertyFetch && !$conditional->left instanceof PhpParser\Node\Expr\StaticPropertyFetch && count($left_type->getAtomicTypes()) === 1 && !$left_type->hasMixed()) { return self::ASSIGNMENT_TO_LEFT; } return \false; } protected static function hasIsACheck(PhpParser\Node\Expr\FuncCall $stmt, StatementsAnalyzer $source) : bool { if ($stmt->name instanceof PhpParser\Node\Name && (strtolower($stmt->name->getFirst()) === 'is_a' || strtolower($stmt->name->getFirst()) === 'is_subclass_of') && isset($stmt->getArgs()[1])) { $second_arg = $stmt->getArgs()[1]->value; if ($second_arg instanceof PhpParser\Node\Scalar\String_ || $second_arg instanceof PhpParser\Node\Expr\ClassConstFetch && $second_arg->class instanceof PhpParser\Node\Name && $second_arg->name instanceof PhpParser\Node\Identifier && strtolower($second_arg->name->name) === 'class' || ($second_arg_type = $source->node_data->getType($second_arg)) && $second_arg_type->hasString()) { return \true; } } return \false; } private static function getIsAssertion(string $function_name) : ?Assertion { switch ($function_name) { case 'is_string': return new IsType(new Atomic\TString()); case 'is_int': case 'is_integer': case 'is_long': return new IsType(new Atomic\TInt()); case 'is_float': case 'is_double': case 'is_real': return new IsType(new Atomic\TFloat()); case 'is_scalar': return new IsType(new Atomic\TScalar()); case 'is_bool': return new IsType(new Atomic\TBool()); case 'is_resource': return new IsType(new Atomic\TResource()); case 'is_object': return new IsType(new Atomic\TObject()); case 'array_is_list': return new IsType(Type::getListAtomic(Type::getMixed())); case 'is_array': return new IsType(new Atomic\TArray([Type::getArrayKey(), Type::getMixed()])); case 'is_numeric': return new IsType(new Atomic\TNumeric()); case 'is_null': return new IsType(new Atomic\TNull()); case 'is_iterable': return new IsType(new Atomic\TIterable()); case 'is_countable': return new IsCountable(); case 'ctype_digit': return new IsType(new Atomic\TNumericString()); case 'ctype_lower': return new IsType(new Atomic\TNonEmptyLowercaseString()); } return null; } /** * @return array>> */ private static function handleIsTypeCheck(?Codebase $codebase, FileSource $source, PhpParser\Node\Expr\FuncCall $stmt, ?string $first_var_name, ?Union $first_var_type, PhpParser\Node\Expr\FuncCall $expr, bool $negate) : array { $if_types = []; if ($stmt->name instanceof PhpParser\Node\Name && ($function_name = strtolower($stmt->name->getFirst())) && ($assertion_type = self::getIsAssertion($function_name)) && $source instanceof StatementsAnalyzer && ($source->getNamespace() === null || $stmt->name instanceof PhpParser\Node\Name\FullyQualified || isset($source->getAliases()->functions[$function_name]) || $codebase && !$codebase->functions->functionExists($source, strtolower($source->getNamespace() . "\\" . $function_name)))) { if ($first_var_name) { $if_types[$first_var_name] = [[$assertion_type]]; } elseif ($first_var_type && $codebase && $assertion_type instanceof IsType) { self::processIrreconcilableFunctionCall($first_var_type, new Union([$assertion_type->type]), $expr, $source, $codebase, $negate); } } return $if_types; } protected static function hasCallableCheck(PhpParser\Node\Expr\FuncCall $stmt) : bool { return $stmt->name instanceof PhpParser\Node\Name && strtolower($stmt->name->getFirst()) === 'is_callable'; } /** * @return Reconciler::RECONCILIATION_* */ protected static function hasClassExistsCheck(PhpParser\Node\Expr\FuncCall $stmt) : int { if ($stmt->name instanceof PhpParser\Node\Name && strtolower($stmt->name->getFirst()) === 'class_exists') { if (!isset($stmt->getArgs()[1])) { return 2; } $second_arg = $stmt->getArgs()[1]->value; if ($second_arg instanceof PhpParser\Node\Expr\ConstFetch && strtolower($second_arg->name->getFirst()) === 'true') { return 2; } return 1; } return 0; } /** * @return 0|1|2 */ protected static function hasTraitExistsCheck(PhpParser\Node\Expr\FuncCall $stmt) : int { if ($stmt->name instanceof PhpParser\Node\Name && strtolower($stmt->name->getFirst()) === 'trait_exists') { if (!isset($stmt->getArgs()[1])) { return 2; } $second_arg = $stmt->getArgs()[1]->value; if ($second_arg instanceof PhpParser\Node\Expr\ConstFetch && strtolower($second_arg->name->getFirst()) === 'true') { return 2; } return 1; } return 0; } protected static function hasEnumExistsCheck(PhpParser\Node\Expr\FuncCall $stmt) : bool { return $stmt->name instanceof PhpParser\Node\Name && strtolower($stmt->name->getFirst()) === 'enum_exists'; } protected static function hasInterfaceExistsCheck(PhpParser\Node\Expr\FuncCall $stmt) : bool { return $stmt->name instanceof PhpParser\Node\Name && strtolower($stmt->name->getFirst()) === 'interface_exists'; } protected static function hasFunctionExistsCheck(PhpParser\Node\Expr\FuncCall $stmt) : bool { return $stmt->name instanceof PhpParser\Node\Name && strtolower($stmt->name->getFirst()) === 'function_exists'; } protected static function hasInArrayCheck(PhpParser\Node\Expr\FuncCall $stmt) : bool { if ($stmt->name instanceof PhpParser\Node\Name && strtolower($stmt->name->getFirst()) === 'in_array' && isset($stmt->getArgs()[2])) { $second_arg = $stmt->getArgs()[2]->value; if ($second_arg instanceof PhpParser\Node\Expr\ConstFetch && strtolower($second_arg->name->getFirst()) === 'true') { return \true; } } return \false; } protected static function hasNonEmptyCountCheck(PhpParser\Node\Expr\FuncCall $stmt) : bool { return $stmt->name instanceof PhpParser\Node\Name && in_array(strtolower($stmt->name->getFirst()), ['count', 'sizeof']); } protected static function hasArrayKeyExistsCheck(PhpParser\Node\Expr\FuncCall $stmt) : bool { return $stmt->name instanceof PhpParser\Node\Name && (strtolower($stmt->name->getFirst()) === 'array_key_exists' || strtolower($stmt->name->getFirst()) === 'key_exists'); } /** * @param PhpParser\Node\Expr\BinaryOp\NotIdentical|PhpParser\Node\Expr\BinaryOp\NotEqual $conditional * @return list>>> */ private static function getNullInequalityAssertions(PhpParser\Node\Expr\BinaryOp $conditional, FileSource $source, ?string $this_class_name, ?Codebase $codebase, int $null_position) : array { $if_types = []; if ($null_position === self::ASSIGNMENT_TO_RIGHT) { $base_conditional = $conditional->left; } elseif ($null_position === self::ASSIGNMENT_TO_LEFT) { $base_conditional = $conditional->right; } else { throw new UnexpectedValueException('Bad null variable position'); } $var_name = \Psalm\Internal\Analyzer\Statements\Expression\ExpressionIdentifier::getExtendedVarId($base_conditional, $this_class_name, $source); if ($var_name) { if ($base_conditional instanceof PhpParser\Node\Expr\Assign) { $var_name = '=' . $var_name; } if ($conditional instanceof PhpParser\Node\Expr\BinaryOp\NotIdentical) { $if_types[$var_name] = [[new IsNotType(new TNull())]]; } else { $if_types[$var_name] = [[new Truthy()]]; } } if ($codebase && $source instanceof StatementsAnalyzer && ($var_type = $source->node_data->getType($base_conditional))) { if ($conditional instanceof PhpParser\Node\Expr\BinaryOp\NotIdentical) { $null_type = Type::getNull(); if (!UnionTypeComparator::isContainedBy($codebase, $var_type, $null_type) && !UnionTypeComparator::isContainedBy($codebase, $null_type, $var_type)) { if ($var_type->from_docblock) { IssueBuffer::maybeAdd(new RedundantConditionGivenDocblockType('Docblock-defined type ' . $var_type . ' can never contain null', new CodeLocation($source, $conditional), $var_type->getId() . ' null'), $source->getSuppressedIssues()); } else { IssueBuffer::maybeAdd(new RedundantCondition($var_type . ' can never contain null', new CodeLocation($source, $conditional), $var_type->getId() . ' null'), $source->getSuppressedIssues()); } } } } return $if_types ? [$if_types] : []; } /** * @param PhpParser\Node\Expr\BinaryOp\NotIdentical|PhpParser\Node\Expr\BinaryOp\NotEqual $conditional * @return list>>> */ private static function getFalseInequalityAssertions(PhpParser\Node\Expr\BinaryOp $conditional, ?string $this_class_name, FileSource $source, ?Codebase $codebase, int $false_position, bool $cache, bool $inside_conditional) : array { $if_types = []; if ($false_position === self::ASSIGNMENT_TO_RIGHT) { $base_conditional = $conditional->left; } elseif ($false_position === self::ASSIGNMENT_TO_LEFT) { $base_conditional = $conditional->right; } else { throw new UnexpectedValueException('Bad false variable position'); } $var_name = \Psalm\Internal\Analyzer\Statements\Expression\ExpressionIdentifier::getExtendedVarId($base_conditional, $this_class_name, $source); if ($var_name) { if ($conditional instanceof PhpParser\Node\Expr\BinaryOp\NotIdentical) { $if_types[$var_name] = [[new IsNotType(new TFalse())]]; } else { $if_types[$var_name] = [[new Truthy()]]; } $if_types = [$if_types]; } else { $if_types = null; if ($source instanceof StatementsAnalyzer && $cache) { $if_types = $source->node_data->getAssertions($base_conditional); } if ($if_types === null) { $if_types = self::scrapeAssertions($base_conditional, $this_class_name, $source, $codebase, \false, $cache, $inside_conditional); if ($source instanceof StatementsAnalyzer && $cache) { $source->node_data->setAssertions($base_conditional, $if_types); } } } if ($codebase && $source instanceof StatementsAnalyzer && ($var_type = $source->node_data->getType($base_conditional)) && $conditional instanceof PhpParser\Node\Expr\BinaryOp\NotIdentical) { $config = $source->getCodebase()->config; if ($config->strict_binary_operands && $var_type->isSingle() && $var_type->hasBool() && !$var_type->from_docblock && !$conditional instanceof VirtualNotIdentical) { IssueBuffer::maybeAdd(new RedundantIdentityWithTrue('The "!== false" part of this comparison is redundant', new CodeLocation($source, $conditional)), $source->getSuppressedIssues()); } $false_type = Type::getFalse(); if (!UnionTypeComparator::isContainedBy($codebase, $var_type, $false_type) && !UnionTypeComparator::isContainedBy($codebase, $false_type, $var_type)) { if ($var_type->from_docblock) { IssueBuffer::maybeAdd(new RedundantConditionGivenDocblockType('Docblock-defined type ' . $var_type . ' can never contain false', new CodeLocation($source, $conditional), $var_type->getId() . ' false'), $source->getSuppressedIssues()); } else { IssueBuffer::maybeAdd(new RedundantCondition($var_type . ' can never contain false', new CodeLocation($source, $conditional), $var_type->getId() . ' false'), $source->getSuppressedIssues()); } } } return $if_types; } /** * @psalm-suppress MoreSpecificReturnType * @param PhpParser\Node\Expr\BinaryOp\NotIdentical|PhpParser\Node\Expr\BinaryOp\NotEqual $conditional * @return list>>> */ private static function getTrueInequalityAssertions(PhpParser\Node\Expr\BinaryOp $conditional, ?string $this_class_name, FileSource $source, ?Codebase $codebase, int $true_position, bool $cache, bool $inside_conditional) : array { $if_types = []; if ($true_position === self::ASSIGNMENT_TO_RIGHT) { $base_conditional = $conditional->left; } elseif ($true_position === self::ASSIGNMENT_TO_LEFT) { $base_conditional = $conditional->right; } else { throw new UnexpectedValueException('Bad null variable position'); } if ($base_conditional instanceof PhpParser\Node\Expr\FuncCall) { $notif_types = self::processFunctionCall($base_conditional, $this_class_name, $source, $codebase, \true); } else { $var_name = \Psalm\Internal\Analyzer\Statements\Expression\ExpressionIdentifier::getExtendedVarId($base_conditional, $this_class_name, $source); if ($var_name) { if ($conditional instanceof PhpParser\Node\Expr\BinaryOp\NotIdentical) { $if_types[$var_name] = [[new IsNotType(new TTrue())]]; } else { $if_types[$var_name] = [[new Falsy()]]; } $notif_types = []; } else { $notif_types = null; if ($source instanceof StatementsAnalyzer && $cache) { $notif_types = $source->node_data->getAssertions($base_conditional); } if ($notif_types === null) { $notif_types = self::scrapeAssertions($base_conditional, $this_class_name, $source, $codebase, \false, $cache, $inside_conditional); if ($source instanceof StatementsAnalyzer && $cache) { $source->node_data->setAssertions($base_conditional, $notif_types); } } } } if (count($notif_types) === 1) { $notif_type = $notif_types[0]; if (count($notif_type) === 1) { $if_types = Algebra::negateTypes($notif_type); } } $if_types = $if_types ? [$if_types] : []; if ($if_types === [] && count($notif_types) === 2) { $check_var_assertion = null; $check_var = null; foreach ($notif_types as $notif_type) { foreach ($notif_type as $var => $assertions) { if (count($assertions) !== 1 || count($assertions[0]) !== 1) { $if_types = []; break 2; } $is_not_assertion = $assertions[0][0] instanceof IsNotType ? \true : \false; if (!isset($check_var)) { $check_var_assertion = $is_not_assertion; $check_var = $var; continue; } // only if we have 1 IsType and 1 IsNotType assertion for same variable if ($check_var !== $var || !isset($check_var_assertion) || $check_var_assertion === $is_not_assertion) { $if_types = []; break 2; } } $if_types[] = Algebra::negateTypes($notif_type); } } if ($codebase && $source instanceof StatementsAnalyzer && ($var_type = $source->node_data->getType($base_conditional))) { if ($conditional instanceof PhpParser\Node\Expr\BinaryOp\NotIdentical) { $true_type = Type::getTrue(); if (!UnionTypeComparator::isContainedBy($codebase, $var_type, $true_type) && !UnionTypeComparator::isContainedBy($codebase, $true_type, $var_type)) { if ($var_type->from_docblock) { IssueBuffer::maybeAdd(new RedundantConditionGivenDocblockType('Docblock-defined type ' . $var_type . ' can never contain true', new CodeLocation($source, $conditional), $var_type->getId() . ' true'), $source->getSuppressedIssues()); } else { IssueBuffer::maybeAdd(new RedundantCondition($var_type . ' can never contain ' . $true_type, new CodeLocation($source, $conditional), $var_type->getId() . ' true'), $source->getSuppressedIssues()); } } } } /** @psalm-suppress LessSpecificReturnStatement */ return $if_types; } /** * @param PhpParser\Node\Expr\BinaryOp\NotIdentical|PhpParser\Node\Expr\BinaryOp\NotEqual $conditional * @return list>>> */ private static function getEmptyInequalityAssertions(PhpParser\Node\Expr\BinaryOp $conditional, ?string $this_class_name, FileSource $source, ?Codebase $codebase, int $empty_array_position) : array { $if_types = []; if ($empty_array_position === self::ASSIGNMENT_TO_RIGHT) { $base_conditional = $conditional->left; } elseif ($empty_array_position === self::ASSIGNMENT_TO_LEFT) { $base_conditional = $conditional->right; } else { throw new UnexpectedValueException('Bad empty array variable position'); } $var_name = \Psalm\Internal\Analyzer\Statements\Expression\ExpressionIdentifier::getExtendedVarId($base_conditional, $this_class_name, $source); if ($var_name) { if ($conditional instanceof PhpParser\Node\Expr\BinaryOp\NotIdentical) { $if_types[$var_name] = [[new NonEmptyCountable(\true)]]; } else { $if_types[$var_name] = [[new Truthy()]]; } } if ($codebase && $source instanceof StatementsAnalyzer && ($var_type = $source->node_data->getType($base_conditional))) { if ($conditional instanceof PhpParser\Node\Expr\BinaryOp\NotIdentical) { $empty_array_type = Type::getEmptyArray(); if (!UnionTypeComparator::isContainedBy($codebase, $var_type, $empty_array_type) && !UnionTypeComparator::isContainedBy($codebase, $empty_array_type, $var_type)) { if ($var_type->from_docblock) { IssueBuffer::maybeAdd(new RedundantConditionGivenDocblockType('Docblock-defined type ' . $var_type->getId() . ' can never contain null', new CodeLocation($source, $conditional), $var_type->getId() . ' null'), $source->getSuppressedIssues()); } else { IssueBuffer::maybeAdd(new RedundantCondition($var_type->getId() . ' can never contain null', new CodeLocation($source, $conditional), $var_type->getId() . ' null'), $source->getSuppressedIssues()); } } } } return $if_types ? [$if_types] : []; } /** * @param PhpParser\Node\Expr\BinaryOp\NotIdentical|PhpParser\Node\Expr\BinaryOp\NotEqual $conditional * @return list>>> */ private static function getGettypeInequalityAssertions(PhpParser\Node\Expr\BinaryOp $conditional, ?string $this_class_name, FileSource $source, int $gettype_position) : array { $if_types = []; if ($gettype_position === self::ASSIGNMENT_TO_RIGHT) { $whichclass_expr = $conditional->left; $gettype_expr = $conditional->right; } elseif ($gettype_position === self::ASSIGNMENT_TO_LEFT) { $whichclass_expr = $conditional->right; $gettype_expr = $conditional->left; } else { throw new UnexpectedValueException('$gettype_position value'); } /** @var PhpParser\Node\Expr\FuncCall $gettype_expr */ $var_name = \Psalm\Internal\Analyzer\Statements\Expression\ExpressionIdentifier::getExtendedVarId($gettype_expr->getArgs()[0]->value, $this_class_name, $source); if ($whichclass_expr instanceof PhpParser\Node\Scalar\String_) { $var_type = $whichclass_expr->value; } elseif ($whichclass_expr instanceof PhpParser\Node\Expr\ClassConstFetch && $whichclass_expr->class instanceof PhpParser\Node\Name) { $var_type = ClassLikeAnalyzer::getFQCLNFromNameObject($whichclass_expr->class, $source->getAliases()); } else { throw new UnexpectedValueException('Shouldn’t get here'); } if (!isset(ClassLikeAnalyzer::GETTYPE_TYPES[$var_type])) { IssueBuffer::maybeAdd(new UnevaluatedCode('gettype cannot return this value', new CodeLocation($source, $whichclass_expr))); } else { if ($var_name && $var_type) { if ($var_type === 'class@anonymous') { $if_types[$var_name] = [[new IsNotIdentical(new TObject())]]; } elseif ($var_type === 'resource (closed)') { $if_types[$var_name] = [[new IsNotType(new TClosedResource())]]; } elseif (strpos($var_type, 'resource (') === 0) { $if_types[$var_name] = [[new IsNotIdentical(new TResource())]]; } else { $if_types[$var_name] = [[new IsNotType(Atomic::create($var_type))]]; } } } return $if_types ? [$if_types] : []; } /** * @param PhpParser\Node\Expr\BinaryOp\NotIdentical|PhpParser\Node\Expr\BinaryOp\NotEqual $conditional * @return list>>> */ private static function getGetdebugTypeInequalityAssertions(PhpParser\Node\Expr\BinaryOp $conditional, ?string $this_class_name, FileSource $source, int $get_debug_type_position) : array { $if_types = []; if ($get_debug_type_position === self::ASSIGNMENT_TO_RIGHT) { $whichclass_expr = $conditional->left; $get_debug_type_expr = $conditional->right; } elseif ($get_debug_type_position === self::ASSIGNMENT_TO_LEFT) { $whichclass_expr = $conditional->right; $get_debug_type_expr = $conditional->left; } else { throw new UnexpectedValueException('$gettype_position value'); } /** @var PhpParser\Node\Expr\FuncCall $get_debug_type_expr */ $var_name = \Psalm\Internal\Analyzer\Statements\Expression\ExpressionIdentifier::getExtendedVarId($get_debug_type_expr->getArgs()[0]->value, $this_class_name, $source); if ($whichclass_expr instanceof PhpParser\Node\Scalar\String_) { $var_type = $whichclass_expr->value; } elseif ($whichclass_expr instanceof PhpParser\Node\Expr\ClassConstFetch && $whichclass_expr->class instanceof PhpParser\Node\Name) { $var_type = ClassLikeAnalyzer::getFQCLNFromNameObject($whichclass_expr->class, $source->getAliases()); } else { throw new UnexpectedValueException('Shouldn’t get here'); } if ($var_name && $var_type) { if ($var_type === 'class@anonymous') { $if_types[$var_name] = [[new IsNotIdentical(new TObject())]]; } elseif ($var_type === 'resource (closed)') { $if_types[$var_name] = [[new IsNotType(new TClosedResource())]]; } elseif (strpos($var_type, 'resource (') === 0) { $if_types[$var_name] = [[new IsNotIdentical(new TResource())]]; } else { $if_types[$var_name] = [[new IsNotType(Atomic::create($var_type))]]; } } return $if_types ? [$if_types] : []; } /** * @param PhpParser\Node\Expr\BinaryOp\NotIdentical|PhpParser\Node\Expr\BinaryOp\NotEqual $conditional * @return list>>> */ private static function getGetclassInequalityAssertions(PhpParser\Node\Expr\BinaryOp $conditional, ?string $this_class_name, StatementsAnalyzer $source, int $getclass_position) : array { $if_types = []; if ($getclass_position === self::ASSIGNMENT_TO_RIGHT) { $whichclass_expr = $conditional->left; $getclass_expr = $conditional->right; } elseif ($getclass_position === self::ASSIGNMENT_TO_LEFT) { $whichclass_expr = $conditional->right; $getclass_expr = $conditional->left; } else { throw new UnexpectedValueException('$getclass_position value'); } if ($getclass_expr instanceof PhpParser\Node\Expr\FuncCall) { $var_name = \Psalm\Internal\Analyzer\Statements\Expression\ExpressionIdentifier::getExtendedVarId($getclass_expr->getArgs()[0]->value, $this_class_name, $source); } elseif ($getclass_expr instanceof PhpParser\Node\Expr\ClassConstFetch && $getclass_expr->class instanceof PhpParser\Node\Expr) { $var_name = \Psalm\Internal\Analyzer\Statements\Expression\ExpressionIdentifier::getExtendedVarId($getclass_expr->class, $this_class_name, $source); } else { $var_name = '$this'; } if ($whichclass_expr instanceof PhpParser\Node\Scalar\String_) { $var_type = $whichclass_expr->value; } elseif ($whichclass_expr instanceof PhpParser\Node\Expr\ClassConstFetch && $whichclass_expr->class instanceof PhpParser\Node\Name) { $var_type = ClassLikeAnalyzer::getFQCLNFromNameObject($whichclass_expr->class, $source->getAliases()); if ($var_type === 'self' || $var_type === 'static') { $var_type = $this_class_name; } elseif ($var_type === 'parent') { $var_type = null; } } else { $type = $source->node_data->getType($whichclass_expr); if ($type && $var_name) { foreach ($type->getAtomicTypes() as $type_part) { if ($type_part instanceof TTemplateParamClass) { $if_types[$var_name] = [[new IsNotIdentical(new TTemplateParam($type_part->param_name, new Union([$type_part->as_type ?: new TObject()]), $type_part->defining_class))]]; } } } return $if_types ? [$if_types] : []; } if (!$var_type || ClassLikeAnalyzer::checkFullyQualifiedClassLikeName($source, $var_type, new CodeLocation($source, $whichclass_expr), null, null, $source->getSuppressedIssues()) !== \false) { if ($var_name && $var_type) { $if_types[$var_name] = [[new IsClassNotEqual($var_type)]]; } } return $if_types ? [$if_types] : []; } /** * @param PhpParser\Node\Expr\BinaryOp\NotIdentical|PhpParser\Node\Expr\BinaryOp\NotEqual $conditional * @return list>>> */ private static function getTypedValueInequalityAssertions(PhpParser\Node\Expr\BinaryOp $conditional, ?string $this_class_name, StatementsAnalyzer $source, ?Codebase $codebase, int $typed_value_position) : array { $if_types = []; if ($typed_value_position === self::ASSIGNMENT_TO_RIGHT) { $var_name = \Psalm\Internal\Analyzer\Statements\Expression\ExpressionIdentifier::getExtendedVarId($conditional->left, $this_class_name, $source); $other_type = $source->node_data->getType($conditional->left); $var_type = $source->node_data->getType($conditional->right); } elseif ($typed_value_position === self::ASSIGNMENT_TO_LEFT) { $var_name = \Psalm\Internal\Analyzer\Statements\Expression\ExpressionIdentifier::getExtendedVarId($conditional->right, $this_class_name, $source); $var_type = $source->node_data->getType($conditional->left); $other_type = $source->node_data->getType($conditional->right); } else { throw new UnexpectedValueException('$typed_value_position value'); } if ($var_type) { if ($var_name) { $not_identical = $conditional instanceof PhpParser\Node\Expr\BinaryOp\NotIdentical || $other_type && ($var_type->isInt() && $other_type->isInt() || $var_type->isFloat() && $other_type->isFloat()); $anded_types = []; foreach ($var_type->getAtomicTypes() as $atomic_var_type) { if ($not_identical) { $anded_types[] = [new IsNotIdentical($atomic_var_type)]; } else { $anded_types[] = [new IsNotLooselyEqual($atomic_var_type)]; } } $if_types[$var_name] = $anded_types; } if ($codebase && $other_type && $conditional instanceof PhpParser\Node\Expr\BinaryOp\NotIdentical) { self::handleParadoxicalAssertions($source, $var_type, $this_class_name, $other_type, $codebase, $conditional); } } return $if_types ? [$if_types] : []; } /** * @param PhpParser\Node\Expr\BinaryOp\Identical|PhpParser\Node\Expr\BinaryOp\Equal $conditional * @return list>>> */ private static function getNullEqualityAssertions(PhpParser\Node\Expr\BinaryOp $conditional, ?string $this_class_name, FileSource $source, ?Codebase $codebase, int $null_position) : array { $if_types = []; if ($null_position === self::ASSIGNMENT_TO_RIGHT) { $base_conditional = $conditional->left; } elseif ($null_position === self::ASSIGNMENT_TO_LEFT) { $base_conditional = $conditional->right; } else { throw new UnexpectedValueException('$null_position value'); } $var_name = \Psalm\Internal\Analyzer\Statements\Expression\ExpressionIdentifier::getExtendedVarId($base_conditional, $this_class_name, $source); if ($var_name && $base_conditional instanceof PhpParser\Node\Expr\Assign) { $var_name = '=' . $var_name; } if ($var_name) { if ($conditional instanceof PhpParser\Node\Expr\BinaryOp\Identical) { $if_types[$var_name] = [[new IsType(new TNull())]]; } else { $if_types[$var_name] = [[new Falsy()]]; } } if ($codebase && $source instanceof StatementsAnalyzer && ($var_type = $source->node_data->getType($base_conditional)) && $conditional instanceof PhpParser\Node\Expr\BinaryOp\Identical) { $null_type = Type::getNull(); if (!UnionTypeComparator::isContainedBy($codebase, $var_type, $null_type) && !UnionTypeComparator::isContainedBy($codebase, $null_type, $var_type)) { if ($var_type->from_docblock) { IssueBuffer::maybeAdd(new DocblockTypeContradiction($var_type . ' does not contain null', new CodeLocation($source, $conditional), $var_type . ' null'), $source->getSuppressedIssues()); } else { IssueBuffer::maybeAdd(new TypeDoesNotContainNull($var_type . ' does not contain null', new CodeLocation($source, $conditional), $var_type->getId()), $source->getSuppressedIssues()); } } } return $if_types ? [$if_types] : []; } /** * @param PhpParser\Node\Expr\BinaryOp\Identical|PhpParser\Node\Expr\BinaryOp\Equal $conditional * @return list>>> */ private static function getTrueEqualityAssertions(PhpParser\Node\Expr\BinaryOp $conditional, ?string $this_class_name, FileSource $source, ?Codebase $codebase, int $true_position, bool $cache, bool $inside_conditional) : array { $if_types = []; if ($true_position === self::ASSIGNMENT_TO_RIGHT) { $base_conditional = $conditional->left; } elseif ($true_position === self::ASSIGNMENT_TO_LEFT) { $base_conditional = $conditional->right; } else { throw new UnexpectedValueException('Unrecognised position'); } if ($base_conditional instanceof PhpParser\Node\Expr\FuncCall) { $if_types = self::processFunctionCall($base_conditional, $this_class_name, $source, $codebase, \false); } else { $var_name = \Psalm\Internal\Analyzer\Statements\Expression\ExpressionIdentifier::getExtendedVarId($base_conditional, $this_class_name, $source); if ($var_name) { if ($conditional instanceof PhpParser\Node\Expr\BinaryOp\Identical) { $if_types[$var_name] = [[new IsType(new TTrue())]]; } else { $if_types[$var_name] = [[new Truthy()]]; } $if_types = [$if_types]; } else { $base_assertions = null; if ($source instanceof StatementsAnalyzer && $cache) { $base_assertions = $source->node_data->getAssertions($base_conditional); } if ($base_assertions === null) { $base_assertions = self::scrapeAssertions($base_conditional, $this_class_name, $source, $codebase, \false, $cache, $inside_conditional); if ($source instanceof StatementsAnalyzer && $cache) { $source->node_data->setAssertions($base_conditional, $base_assertions); } } $if_types = $base_assertions; } } if ($codebase && $source instanceof StatementsAnalyzer && ($var_type = $source->node_data->getType($base_conditional)) && $conditional instanceof PhpParser\Node\Expr\BinaryOp\Identical) { $config = $source->getCodebase()->config; if ($config->strict_binary_operands && $var_type->isSingle() && $var_type->hasBool() && !$var_type->from_docblock && !$conditional instanceof VirtualIdentical) { IssueBuffer::maybeAdd(new RedundantIdentityWithTrue('The "=== true" part of this comparison is redundant', new CodeLocation($source, $conditional)), $source->getSuppressedIssues()); } $true_type = Type::getTrue(); if (!UnionTypeComparator::canExpressionTypesBeIdentical($codebase, $true_type, $var_type)) { if ($var_type->from_docblock) { IssueBuffer::maybeAdd(new DocblockTypeContradiction($var_type . ' does not contain true', new CodeLocation($source, $conditional), $var_type . ' true'), $source->getSuppressedIssues()); } else { IssueBuffer::maybeAdd(new TypeDoesNotContainType($var_type . ' does not contain true', new CodeLocation($source, $conditional), $var_type . ' true'), $source->getSuppressedIssues()); } } } return $if_types; } /** * @psalm-suppress MoreSpecificReturnType * @param PhpParser\Node\Expr\BinaryOp\Identical|PhpParser\Node\Expr\BinaryOp\Equal $conditional * @return list>>> */ private static function getFalseEqualityAssertions(PhpParser\Node\Expr\BinaryOp $conditional, ?string $this_class_name, FileSource $source, ?Codebase $codebase, int $false_position, bool $cache, bool $inside_conditional) : array { $if_types = []; if ($false_position === self::ASSIGNMENT_TO_RIGHT) { $base_conditional = $conditional->left; } elseif ($false_position === self::ASSIGNMENT_TO_LEFT) { $base_conditional = $conditional->right; } else { throw new UnexpectedValueException('$false_position value'); } if ($base_conditional instanceof PhpParser\Node\Expr\FuncCall) { $notif_types = self::processFunctionCall($base_conditional, $this_class_name, $source, $codebase, \true); } else { $var_name = \Psalm\Internal\Analyzer\Statements\Expression\ExpressionIdentifier::getExtendedVarId($base_conditional, $this_class_name, $source); if ($var_name) { if ($conditional instanceof PhpParser\Node\Expr\BinaryOp\Identical) { $if_types[$var_name] = [[new IsType(new TFalse())]]; } else { $if_types[$var_name] = [[new Falsy()]]; } $notif_types = []; } else { $notif_types = null; if ($source instanceof StatementsAnalyzer && $cache) { $notif_types = $source->node_data->getAssertions($base_conditional); } if ($notif_types === null) { $notif_types = self::scrapeAssertions($base_conditional, $this_class_name, $source, $codebase, \false, $cache, $inside_conditional); if ($source instanceof StatementsAnalyzer && $cache) { $source->node_data->setAssertions($base_conditional, $notif_types); } } } } if (count($notif_types) === 1) { $notif_type = $notif_types[0]; if (count($notif_type) === 1) { $if_types = Algebra::negateTypes($notif_type); } } $if_types = $if_types ? [$if_types] : []; // @psalm-assert-if-true and @psalm-assert-if-false for same variable in same function, e.g. array/list cases // @todo optionally extend this to arbitrary number of assert-if cases of multiple variables in the function // same code above too if ($if_types === [] && count($notif_types) === 2) { $check_var_assertion = null; $check_var = null; foreach ($notif_types as $notif_type) { foreach ($notif_type as $var => $assertions) { if (count($assertions) !== 1 || count($assertions[0]) !== 1) { $if_types = []; break 2; } $is_not_assertion = $assertions[0][0] instanceof IsNotType ? \true : \false; if (!isset($check_var)) { $check_var_assertion = $is_not_assertion; $check_var = $var; continue; } // only if we have 1 IsType and 1 IsNotType assertion for same variable if ($check_var !== $var || !isset($check_var_assertion) || $check_var_assertion === $is_not_assertion) { $if_types = []; break 2; } } $if_types[] = Algebra::negateTypes($notif_type); } } if ($codebase && $source instanceof StatementsAnalyzer && ($var_type = $source->node_data->getType($base_conditional))) { if ($conditional instanceof PhpParser\Node\Expr\BinaryOp\Identical) { $false_type = Type::getFalse(); if (!UnionTypeComparator::canExpressionTypesBeIdentical($codebase, $false_type, $var_type)) { if ($var_type->from_docblock) { IssueBuffer::maybeAdd(new DocblockTypeContradiction($var_type . ' does not contain false', new CodeLocation($source, $conditional), $var_type . ' false'), $source->getSuppressedIssues()); } else { IssueBuffer::maybeAdd(new TypeDoesNotContainType($var_type . ' does not contain false', new CodeLocation($source, $conditional), $var_type . ' false'), $source->getSuppressedIssues()); } } } } /** @psalm-suppress LessSpecificReturnStatement */ return $if_types; } /** * @param PhpParser\Node\Expr\BinaryOp\Identical|PhpParser\Node\Expr\BinaryOp\Equal $conditional * @return list>>> */ private static function getEmptyArrayEqualityAssertions(PhpParser\Node\Expr\BinaryOp $conditional, ?string $this_class_name, FileSource $source, ?Codebase $codebase, int $empty_array_position) : array { $if_types = []; if ($empty_array_position === self::ASSIGNMENT_TO_RIGHT) { $base_conditional = $conditional->left; } elseif ($empty_array_position === self::ASSIGNMENT_TO_LEFT) { $base_conditional = $conditional->right; } else { throw new UnexpectedValueException('$empty_array_position value'); } $var_name = \Psalm\Internal\Analyzer\Statements\Expression\ExpressionIdentifier::getExtendedVarId($base_conditional, $this_class_name, $source); if ($var_name) { if ($conditional instanceof PhpParser\Node\Expr\BinaryOp\Identical) { $if_types[$var_name] = [[new NotNonEmptyCountable()]]; } else { $if_types[$var_name] = [[new Falsy()]]; } } if ($codebase && $source instanceof StatementsAnalyzer && ($var_type = $source->node_data->getType($base_conditional)) && $conditional instanceof PhpParser\Node\Expr\BinaryOp\Identical) { $empty_array_type = Type::getEmptyArray(); if (!UnionTypeComparator::canExpressionTypesBeIdentical($codebase, $empty_array_type, $var_type)) { if ($var_type->from_docblock) { IssueBuffer::maybeAdd(new DocblockTypeContradiction($var_type . ' does not contain an empty array', new CodeLocation($source, $conditional), $var_type . ' !== []'), $source->getSuppressedIssues()); } else { IssueBuffer::maybeAdd(new TypeDoesNotContainType($var_type . ' does not contain empty array', new CodeLocation($source, $conditional), $var_type . ' !== []'), $source->getSuppressedIssues()); } } } return $if_types ? [$if_types] : []; } /** * @param PhpParser\Node\Expr\BinaryOp\Identical|PhpParser\Node\Expr\BinaryOp\Equal $conditional * @return list>>> */ private static function getGettypeEqualityAssertions(PhpParser\Node\Expr\BinaryOp $conditional, ?string $this_class_name, FileSource $source, int $gettype_position) : array { $if_types = []; if ($gettype_position === self::ASSIGNMENT_TO_RIGHT) { $string_expr = $conditional->left; $gettype_expr = $conditional->right; } elseif ($gettype_position === self::ASSIGNMENT_TO_LEFT) { $string_expr = $conditional->right; $gettype_expr = $conditional->left; } else { throw new UnexpectedValueException('$gettype_position value'); } /** @var PhpParser\Node\Expr\FuncCall $gettype_expr */ $var_name = \Psalm\Internal\Analyzer\Statements\Expression\ExpressionIdentifier::getExtendedVarId($gettype_expr->getArgs()[0]->value, $this_class_name, $source); /** @var PhpParser\Node\Scalar\String_ $string_expr */ $var_type = $string_expr->value; if (!isset(ClassLikeAnalyzer::GETTYPE_TYPES[$var_type])) { IssueBuffer::maybeAdd(new UnevaluatedCode('gettype cannot return this value', new CodeLocation($source, $string_expr))); } else { if ($var_name && $var_type) { if ($var_type === 'class@anonymous') { $if_types[$var_name] = [[new IsIdentical(new TObject())]]; } elseif ($var_type === 'resource (closed)') { $if_types[$var_name] = [[new IsType(new TClosedResource())]]; } elseif (strpos($var_type, 'resource (') === 0) { $if_types[$var_name] = [[new IsIdentical(new TResource())]]; } elseif ($var_type === 'integer') { $if_types[$var_name] = [[new IsType(new Atomic\TInt())]]; } elseif ($var_type === 'double') { $if_types[$var_name] = [[new IsType(new Atomic\TFloat())]]; } elseif ($var_type === 'boolean') { $if_types[$var_name] = [[new IsType(new Atomic\TBool())]]; } else { $if_types[$var_name] = [[new IsType(Atomic::create($var_type))]]; } } } return $if_types ? [$if_types] : []; } /** * @param PhpParser\Node\Expr\BinaryOp\Identical|PhpParser\Node\Expr\BinaryOp\Equal $conditional * @return list>>> */ private static function getGetdebugtypeEqualityAssertions(PhpParser\Node\Expr\BinaryOp $conditional, ?string $this_class_name, FileSource $source, int $get_debug_type_position) : array { $if_types = []; if ($get_debug_type_position === self::ASSIGNMENT_TO_RIGHT) { $whichclass_expr = $conditional->left; $get_debug_type_expr = $conditional->right; } elseif ($get_debug_type_position === self::ASSIGNMENT_TO_LEFT) { $whichclass_expr = $conditional->right; $get_debug_type_expr = $conditional->left; } else { throw new UnexpectedValueException('$gettype_position value'); } /** @var PhpParser\Node\Expr\FuncCall $get_debug_type_expr */ $var_name = \Psalm\Internal\Analyzer\Statements\Expression\ExpressionIdentifier::getExtendedVarId($get_debug_type_expr->getArgs()[0]->value, $this_class_name, $source); if ($whichclass_expr instanceof PhpParser\Node\Scalar\String_) { $var_type = $whichclass_expr->value; } elseif ($whichclass_expr instanceof PhpParser\Node\Expr\ClassConstFetch && $whichclass_expr->class instanceof PhpParser\Node\Name) { $var_type = ClassLikeAnalyzer::getFQCLNFromNameObject($whichclass_expr->class, $source->getAliases()); } else { throw new UnexpectedValueException('Shouldn’t get here'); } if ($var_name && $var_type) { if ($var_type === 'class@anonymous') { $if_types[$var_name] = [[new IsIdentical(new TObject())]]; } elseif ($var_type === 'resource (closed)') { $if_types[$var_name] = [[new IsType(new TClosedResource())]]; } elseif (strpos($var_type, 'resource (') === 0) { $if_types[$var_name] = [[new IsIdentical(new TResource())]]; } elseif ($var_type === 'integer') { $if_types[$var_name] = [[new IsType(new Atomic\TInt())]]; } elseif ($var_type === 'double') { $if_types[$var_name] = [[new IsType(new Atomic\TFloat())]]; } elseif ($var_type === 'boolean') { $if_types[$var_name] = [[new IsType(new Atomic\TBool())]]; } else { $if_types[$var_name] = [[new IsType(Atomic::create($var_type))]]; } } return $if_types ? [$if_types] : []; } /** * @param PhpParser\Node\Expr\BinaryOp\Identical|PhpParser\Node\Expr\BinaryOp\Equal $conditional * @return list>>> */ private static function getGetclassEqualityAssertions(PhpParser\Node\Expr\BinaryOp $conditional, ?string $this_class_name, StatementsAnalyzer $source, int $getclass_position) : array { $if_types = []; if ($getclass_position === self::ASSIGNMENT_TO_RIGHT) { $whichclass_expr = $conditional->left; $getclass_expr = $conditional->right; } elseif ($getclass_position === self::ASSIGNMENT_TO_LEFT) { $whichclass_expr = $conditional->right; $getclass_expr = $conditional->left; } else { throw new UnexpectedValueException('$getclass_position value'); } if ($getclass_expr instanceof PhpParser\Node\Expr\FuncCall && isset($getclass_expr->getArgs()[0])) { $var_name = \Psalm\Internal\Analyzer\Statements\Expression\ExpressionIdentifier::getExtendedVarId($getclass_expr->getArgs()[0]->value, $this_class_name, $source); } elseif ($getclass_expr instanceof PhpParser\Node\Expr\ClassConstFetch && $getclass_expr->class instanceof PhpParser\Node\Expr) { $var_name = \Psalm\Internal\Analyzer\Statements\Expression\ExpressionIdentifier::getExtendedVarId($getclass_expr->class, $this_class_name, $source); } else { $var_name = '$this'; } if ($whichclass_expr instanceof PhpParser\Node\Expr\ClassConstFetch && $whichclass_expr->class instanceof PhpParser\Node\Name) { $var_type = ClassLikeAnalyzer::getFQCLNFromNameObject($whichclass_expr->class, $source->getAliases()); if ($var_type === 'self' || $var_type === 'static') { $var_type = $this_class_name; } elseif ($var_type === 'parent') { $var_type = null; } if ($var_type) { if (ClassLikeAnalyzer::checkFullyQualifiedClassLikeName($source, $var_type, new CodeLocation($source, $whichclass_expr), null, null, $source->getSuppressedIssues(), new ClassLikeNameOptions(\true)) === \false) { return []; } } if ($var_name && $var_type) { $if_types[$var_name] = [[new IsClassEqual($var_type)]]; } } else { $type = $source->node_data->getType($whichclass_expr); if ($type && $var_name) { foreach ($type->getAtomicTypes() as $type_part) { if ($type_part instanceof TTemplateParamClass) { $if_types[$var_name] = [[new IsIdentical(new TTemplateParam($type_part->param_name, $type_part->as_type ? new Union([$type_part->as_type]) : Type::getObject(), $type_part->defining_class))]]; } } } } return $if_types ? [$if_types] : []; } /** * @param PhpParser\Node\Expr\BinaryOp\Identical|PhpParser\Node\Expr\BinaryOp\Equal $conditional * @return list>>> */ private static function getTypedValueEqualityAssertions(PhpParser\Node\Expr\BinaryOp $conditional, ?string $this_class_name, StatementsAnalyzer $source, ?Codebase $codebase, int $typed_value_position) : array { $if_types = []; if ($typed_value_position === self::ASSIGNMENT_TO_RIGHT) { $var_name = \Psalm\Internal\Analyzer\Statements\Expression\ExpressionIdentifier::getExtendedVarId($conditional->left, $this_class_name, $source); $other_var_name = \Psalm\Internal\Analyzer\Statements\Expression\ExpressionIdentifier::getExtendedVarId($conditional->right, $this_class_name, $source); $other_type = $source->node_data->getType($conditional->left); $var_type = $source->node_data->getType($conditional->right); } elseif ($typed_value_position === self::ASSIGNMENT_TO_LEFT) { $var_name = \Psalm\Internal\Analyzer\Statements\Expression\ExpressionIdentifier::getExtendedVarId($conditional->right, $this_class_name, $source); $other_var_name = \Psalm\Internal\Analyzer\Statements\Expression\ExpressionIdentifier::getExtendedVarId($conditional->left, $this_class_name, $source); $var_type = $source->node_data->getType($conditional->left); $other_type = $source->node_data->getType($conditional->right); } else { throw new UnexpectedValueException('$typed_value_position value'); } //soit on a un === explicite, soit on compare des types strictement égaux $identical = $conditional instanceof PhpParser\Node\Expr\BinaryOp\Identical || $other_type && $var_type && ($var_type->isString(\true) && $other_type->isString(\true) || $var_type->isInt(\true) && $other_type->isInt(\true) || $var_type->isFloat() && $other_type->isFloat()); if ($var_name && $var_type && !$var_type->isMixed() && count($var_type->getAtomicTypes()) === 1) { $orred_types = []; foreach ($var_type->getAtomicTypes() as $atomic_var_type) { if ($identical) { $orred_types[] = new IsIdentical($atomic_var_type); } else { $orred_types[] = new IsLooselyEqual($atomic_var_type); } } $if_types[$var_name] = [$orred_types]; } if ($other_var_name && $other_type && !$other_type->isMixed() && count($other_type->getAtomicTypes()) === 1 && $other_var_name[0] === '$') { $orred_types = []; foreach ($other_type->getAtomicTypes() as $atomic_other_type) { if ($identical) { $orred_types[] = new IsIdentical($atomic_other_type); } else { $orred_types[] = new IsLooselyEqual($atomic_other_type); } } $if_types[$other_var_name] = [$orred_types]; } if ($codebase && $other_type && $var_type && $identical) { self::handleParadoxicalAssertions($source, $var_type, $this_class_name, $other_type, $codebase, $conditional); } return $if_types ? [$if_types] : []; } /** * @return list>>> */ private static function getIsaAssertions(PhpParser\Node\Expr\FuncCall $expr, StatementsAnalyzer $source, ?string $this_class_name, ?string $first_var_name) : array { $if_types = []; if ($expr->getArgs()[0]->value instanceof PhpParser\Node\Expr\ClassConstFetch && $expr->getArgs()[0]->value->name instanceof PhpParser\Node\Identifier && strtolower($expr->getArgs()[0]->value->name->name) === 'class' && $expr->getArgs()[0]->value->class instanceof PhpParser\Node\Name && count($expr->getArgs()[0]->value->class->getParts()) === 1 && strtolower($expr->getArgs()[0]->value->class->getFirst()) === 'static') { $first_var_name = '$this'; } if ($first_var_name) { $first_arg = $expr->getArgs()[0]->value; $second_arg = $expr->getArgs()[1]->value; $third_arg = $expr->getArgs()[2]->value ?? null; if ($third_arg instanceof PhpParser\Node\Expr\ConstFetch) { if (!in_array(strtolower($third_arg->name->getFirst()), ['true', 'false'])) { return []; } $third_arg_value = strtolower($third_arg->name->getFirst()); } else { $third_arg_value = $expr->name instanceof PhpParser\Node\Name && strtolower($expr->name->getFirst()) === 'is_subclass_of' ? 'true' : 'false'; } if (($first_arg_type = $source->node_data->getType($first_arg)) && $first_arg_type->isSingleStringLiteral() && $source->getSource()->getSource() instanceof TraitAnalyzer && $first_arg_type->getSingleStringLiteral()->value === $this_class_name) { // do nothing } else { if ($second_arg instanceof PhpParser\Node\Scalar\String_) { $fq_class_name = $second_arg->value; if ($fq_class_name[0] === '\\') { $fq_class_name = substr($fq_class_name, 1); } $obj = new TNamedObject($fq_class_name); $if_types[$first_var_name] = [[new IsAClass($obj, $third_arg_value === 'true')]]; } elseif ($second_arg instanceof PhpParser\Node\Expr\ClassConstFetch && $second_arg->class instanceof PhpParser\Node\Name && $second_arg->name instanceof PhpParser\Node\Identifier && strtolower($second_arg->name->name) === 'class') { $class_node = $second_arg->class; if ($class_node->getParts() === ['static']) { if ($this_class_name) { $object = new TNamedObject($this_class_name, \true); $if_types[$first_var_name] = [[new IsAClass($object, $third_arg_value === 'true')]]; } } elseif ($class_node->getParts() === ['self']) { if ($this_class_name) { $object = new TNamedObject($this_class_name); $if_types[$first_var_name] = [[new IsAClass($object, $third_arg_value === 'true')]]; } } elseif ($class_node->getParts() === ['parent']) { // do nothing } else { $object = new TNamedObject(ClassLikeAnalyzer::getFQCLNFromNameObject($class_node, $source->getAliases())); $if_types[$first_var_name] = [[new IsAClass($object, $third_arg_value === 'true')]]; } } elseif (($second_arg_type = $source->node_data->getType($second_arg)) && $second_arg_type->hasString()) { $vals = []; foreach ($second_arg_type->getAtomicTypes() as $second_arg_atomic_type) { if ($second_arg_atomic_type instanceof TTemplateParamClass) { $vals[] = [new IsAClass($second_arg_atomic_type, $third_arg_value === 'true')]; } } if ($vals) { $if_types[$first_var_name] = $vals; } } } } return $if_types ? [$if_types] : []; } /** * @return list>>> */ private static function getInarrayAssertions(PhpParser\Node\Expr\FuncCall $expr, StatementsAnalyzer $source, ?string $first_var_name) : array { $if_types = []; if ($first_var_name && ($second_arg_type = $source->node_data->getType($expr->getArgs()[1]->value)) && isset($expr->getArgs()[0]->value) && !$expr->getArgs()[0]->value instanceof PhpParser\Node\Expr\ClassConstFetch) { foreach ($second_arg_type->getAtomicTypes() as $atomic_type) { if ($atomic_type instanceof TList) { $atomic_type = $atomic_type->getKeyedArray(); } if ($atomic_type instanceof TArray || $atomic_type instanceof TKeyedArray) { $is_sealed = \false; if ($atomic_type instanceof TKeyedArray) { $value_type = $atomic_type->getGenericValueType(); $is_sealed = $atomic_type->fallback_params === null; } else { $value_type = $atomic_type->type_params[1]; } $assertions = []; if (!$is_sealed) { // `in-array-*` has special handling in the detection of paradoxical // conditions and the fact the negation doesn't imply anything. // // In the vast majority of cases, the negation of `in-array-*` // (`Algebra::negateType`) doesn't imply anything because: // - The array can be empty, or // - The array may have one of the types but not the others. // // NOTE: the negation of the negation is the original assertion. if ($value_type->getId() !== '' && !$value_type->isMixed() && !$value_type->hasTemplate()) { $assertions[] = new InArray($value_type); } } else { foreach ($value_type->getAtomicTypes() as $atomic_value_type) { if ($atomic_value_type instanceof TLiteralInt || $atomic_value_type instanceof TLiteralString || $atomic_value_type instanceof TLiteralFloat || $atomic_value_type instanceof TEnumCase) { $assertions[] = new IsIdentical($atomic_value_type); } elseif ($atomic_value_type instanceof TFalse || $atomic_value_type instanceof TTrue || $atomic_value_type instanceof TNull) { $assertions[] = new IsType($atomic_value_type); } elseif (!$atomic_value_type instanceof TMixed) { // mixed doesn't tell us anything and can be omitted. // // For the meaning of in-array, see the above comment. $assertions[] = new InArray($value_type); } } } if ($assertions !== []) { $if_types[$first_var_name] = [$assertions]; } } } } return $if_types ? [$if_types] : []; } /** * @return list>>> */ private static function getArrayKeyExistsAssertions(PhpParser\Node\Expr\FuncCall $expr, ?Union $first_var_type, ?string $first_var_name, FileSource $source, ?string $this_class_name) : array { $if_types = []; $literal_assertions = []; $safe_to_track_literals = \true; if (isset($expr->getArgs()[0]) && isset($expr->getArgs()[1]) && $first_var_type && $first_var_name !== null && !$expr->getArgs()[0]->value instanceof PhpParser\Node\Expr\ClassConstFetch && $source instanceof StatementsAnalyzer && ($second_var_type = $source->node_data->getType($expr->getArgs()[1]->value))) { foreach ($second_var_type->getAtomicTypes() as $atomic_type) { if ($atomic_type instanceof TList) { $atomic_type = $atomic_type->getKeyedArray(); } if ($atomic_type instanceof TArray || $atomic_type instanceof TKeyedArray) { if ($atomic_type instanceof TKeyedArray) { $key_type = $atomic_type->getGenericKeyType(!$atomic_type->allShapeKeysAlwaysDefined()); } else { $key_type = $atomic_type->type_params[0]; } if ($key_type->allStringLiterals() && !$key_type->possibly_undefined) { foreach ($key_type->getLiteralStrings() as $array_literal_type) { $string_to_int = \Psalm\Internal\Analyzer\Statements\Expression\ArrayAnalyzer::getLiteralArrayKeyInt($array_literal_type->value); if ($string_to_int === \false) { $literal_assertions[] = new IsIdentical($array_literal_type); } else { $literal_assertions[] = new IsLooselyEqual(new TLiteralInt($string_to_int)); } } } elseif ($key_type->allIntLiterals() && !$key_type->possibly_undefined) { foreach ($key_type->getLiteralInts() as $array_literal_type) { $literal_assertions[] = new IsLooselyEqual($array_literal_type); } } else { $safe_to_track_literals = \false; } } } } if ($literal_assertions && $first_var_name !== null && $safe_to_track_literals) { $if_types[$first_var_name] = [$literal_assertions]; } else { $array_root = isset($expr->getArgs()[1]->value) ? \Psalm\Internal\Analyzer\Statements\Expression\ExpressionIdentifier::getExtendedVarId($expr->getArgs()[1]->value, $this_class_name, $source) : null; if ($array_root && isset($expr->getArgs()[0])) { if ($first_var_name === null) { $first_arg = $expr->getArgs()[0]; if ($first_arg->value instanceof PhpParser\Node\Scalar\String_) { $string_to_int = \Psalm\Internal\Analyzer\Statements\Expression\ArrayAnalyzer::getLiteralArrayKeyInt($first_arg->value->value); $first_var_name = $string_to_int === \false ? '\'' . $first_arg->value->value . '\'' : (string) $string_to_int; } elseif ($first_arg->value instanceof PhpParser\Node\Scalar\LNumber) { $first_var_name = (string) $first_arg->value->value; } } if ($expr->getArgs()[0]->value instanceof PhpParser\Node\Expr\ClassConstFetch && $expr->getArgs()[0]->value->name instanceof PhpParser\Node\Identifier && $expr->getArgs()[0]->value->name->name !== 'class') { $const_type = null; if ($source instanceof StatementsAnalyzer) { $const_type = $source->node_data->getType($expr->getArgs()[0]->value); } if ($const_type) { if ($const_type->isSingleStringLiteral()) { $string_to_int = \Psalm\Internal\Analyzer\Statements\Expression\ArrayAnalyzer::getLiteralArrayKeyInt($const_type->getSingleStringLiteral()->value); $first_var_name = $string_to_int === \false ? '\'' . $const_type->getSingleStringLiteral()->value . '\'' : (string) $string_to_int; } elseif ($const_type->isSingleIntLiteral()) { $first_var_name = (string) $const_type->getSingleIntLiteral()->value; } else { $first_var_name = null; } } else { $first_var_name = null; } } elseif (($expr->getArgs()[0]->value instanceof PhpParser\Node\Expr\Variable || $expr->getArgs()[0]->value instanceof PhpParser\Node\Expr\PropertyFetch || $expr->getArgs()[0]->value instanceof PhpParser\Node\Expr\StaticPropertyFetch) && $source instanceof StatementsAnalyzer && ($first_var_type = $source->node_data->getType($expr->getArgs()[0]->value))) { foreach ($first_var_type->getLiteralStrings() as $array_literal_type) { $string_to_int = \Psalm\Internal\Analyzer\Statements\Expression\ArrayAnalyzer::getLiteralArrayKeyInt($array_literal_type->value); $literal_key = $string_to_int === \false ? "'" . $array_literal_type->value . "'" : $string_to_int; $if_types[$array_root . "[" . $literal_key . "]"] = [[new ArrayKeyExists()]]; } foreach ($first_var_type->getLiteralInts() as $array_literal_type) { $if_types[$array_root . "[" . $array_literal_type->value . "]"] = [[new ArrayKeyExists()]]; } } if ($first_var_name !== null && !strpos($first_var_name, '->') && !strpos($first_var_name, '[')) { $if_types[$array_root . '[' . $first_var_name . ']'] = [[new ArrayKeyExists()]]; } } } return $if_types ? [$if_types] : []; } /** * @param PhpParser\Node\Expr\BinaryOp\Greater|PhpParser\Node\Expr\BinaryOp\GreaterOrEqual $conditional * @return list>>> */ private static function getGreaterAssertions(PhpParser\Node\Expr $conditional, FileSource $source, ?string $this_class_name) : array { $if_types = []; $min_count = null; $count_equality_position = self::hasNonEmptyCountEqualityCheck($conditional, $min_count); $max_count = null; $count_inequality_position = self::hasLessThanCountEqualityCheck($conditional, $max_count); $superior_value_comparison = null; $superior_value_position = self::hasSuperiorNumberCheck($source, $conditional, $superior_value_comparison); if ($count_equality_position) { if ($count_equality_position === self::ASSIGNMENT_TO_RIGHT) { $counted_expr = $conditional->left; } else { throw new UnexpectedValueException('$count_equality_position value'); } /** @var PhpParser\Node\Expr\FuncCall $counted_expr */ $var_name = \Psalm\Internal\Analyzer\Statements\Expression\ExpressionIdentifier::getExtendedVarId($counted_expr->getArgs()[0]->value, $this_class_name, $source); if ($var_name) { if (self::hasReconcilableNonEmptyCountEqualityCheck($conditional)) { $if_types[$var_name] = [[new NonEmptyCountable(\true)]]; } else { if ($min_count > 0) { $if_types[$var_name] = [[new HasAtLeastCount($min_count)]]; } else { $if_types[$var_name] = [[new NonEmptyCountable(\false)]]; } } } return $if_types ? [$if_types] : []; } if ($count_inequality_position) { if ($count_inequality_position === self::ASSIGNMENT_TO_LEFT) { $count_expr = $conditional->right; } else { throw new UnexpectedValueException('$count_inequality_position value'); } /** @var PhpParser\Node\Expr\FuncCall $count_expr */ $var_name = \Psalm\Internal\Analyzer\Statements\Expression\ExpressionIdentifier::getExtendedVarId($count_expr->getArgs()[0]->value, $this_class_name, $source); if ($var_name) { if ($max_count > 0) { $if_types[$var_name] = [[new DoesNotHaveAtLeastCount($max_count + 1)]]; } else { $if_types[$var_name] = [[new NotNonEmptyCountable()]]; } } return $if_types ? [$if_types] : []; } if ($superior_value_position && $superior_value_comparison !== null) { if ($superior_value_position === self::ASSIGNMENT_TO_RIGHT) { $var_name = \Psalm\Internal\Analyzer\Statements\Expression\ExpressionIdentifier::getExtendedVarId($conditional->left, $this_class_name, $source); } else { $var_name = \Psalm\Internal\Analyzer\Statements\Expression\ExpressionIdentifier::getExtendedVarId($conditional->right, $this_class_name, $source); } if ($var_name !== null) { if ($superior_value_position === self::ASSIGNMENT_TO_RIGHT) { if ($conditional instanceof GreaterOrEqual) { $if_types[$var_name] = [[new IsGreaterThanOrEqualTo($superior_value_comparison)]]; } else { $if_types[$var_name] = [[new IsGreaterThan($superior_value_comparison)]]; } } else { if ($conditional instanceof GreaterOrEqual) { $if_types[$var_name] = [[new IsLessThanOrEqualTo($superior_value_comparison)]]; } else { $if_types[$var_name] = [[new IsLessThan($superior_value_comparison)]]; } } } return $if_types ? [$if_types] : []; } return []; } /** * @param PhpParser\Node\Expr\BinaryOp\Smaller|PhpParser\Node\Expr\BinaryOp\SmallerOrEqual $conditional * @return list>>> */ private static function getSmallerAssertions(PhpParser\Node\Expr $conditional, FileSource $source, ?string $this_class_name) : array { $if_types = []; $min_count = null; $count_equality_position = self::hasNonEmptyCountEqualityCheck($conditional, $min_count); $max_count = null; $count_inequality_position = self::hasLessThanCountEqualityCheck($conditional, $max_count); $inferior_value_comparison = null; $inferior_value_position = self::hasInferiorNumberCheck($source, $conditional, $inferior_value_comparison); if ($count_equality_position) { if ($count_equality_position === self::ASSIGNMENT_TO_LEFT) { $count_expr = $conditional->right; } else { throw new UnexpectedValueException('$count_equality_position value'); } /** @var PhpParser\Node\Expr\FuncCall $count_expr */ $var_name = \Psalm\Internal\Analyzer\Statements\Expression\ExpressionIdentifier::getExtendedVarId($count_expr->getArgs()[0]->value, $this_class_name, $source); if ($var_name) { if ($min_count > 0) { $if_types[$var_name] = [[new HasAtLeastCount($min_count)]]; } else { $if_types[$var_name] = [[new NonEmptyCountable(\false)]]; } } return $if_types ? [$if_types] : []; } if ($count_inequality_position) { if ($count_inequality_position === self::ASSIGNMENT_TO_RIGHT) { $count_expr = $conditional->left; } else { throw new UnexpectedValueException('$count_inequality_position value'); } /** @var PhpParser\Node\Expr\FuncCall $count_expr */ $var_name = \Psalm\Internal\Analyzer\Statements\Expression\ExpressionIdentifier::getExtendedVarId($count_expr->getArgs()[0]->value, $this_class_name, $source); if ($var_name) { if ($max_count > 0) { $if_types[$var_name] = [[new DoesNotHaveAtLeastCount($max_count + 1)]]; } else { $if_types[$var_name] = [[new NotNonEmptyCountable()]]; } } return $if_types ? [$if_types] : []; } if ($inferior_value_position) { if ($inferior_value_position === self::ASSIGNMENT_TO_RIGHT) { $var_name = \Psalm\Internal\Analyzer\Statements\Expression\ExpressionIdentifier::getExtendedVarId($conditional->left, $this_class_name, $source); } else { $var_name = \Psalm\Internal\Analyzer\Statements\Expression\ExpressionIdentifier::getExtendedVarId($conditional->right, $this_class_name, $source); } if ($var_name !== null && $inferior_value_comparison !== null) { if ($inferior_value_position === self::ASSIGNMENT_TO_RIGHT) { if ($conditional instanceof SmallerOrEqual) { $if_types[$var_name] = [[new IsLessThanOrEqualTo($inferior_value_comparison)]]; } else { $if_types[$var_name] = [[new IsLessThan($inferior_value_comparison)]]; } } else { if ($conditional instanceof SmallerOrEqual) { $if_types[$var_name] = [[new IsGreaterThanOrEqualTo($inferior_value_comparison)]]; } else { $if_types[$var_name] = [[new IsGreaterThan($inferior_value_comparison)]]; } } } return $if_types ? [$if_types] : []; } return []; } /** * @return list>>> */ private static function getAndCheckInstanceofAssertions(PhpParser\Node\Expr\Instanceof_ $conditional, ?Codebase $codebase, FileSource $source, ?string $this_class_name, bool $inside_negation) : array { $if_types = []; $instanceof_assertions = self::getInstanceOfAssertions($conditional, $this_class_name, $source); if ($instanceof_assertions) { $var_name = \Psalm\Internal\Analyzer\Statements\Expression\ExpressionIdentifier::getExtendedVarId($conditional->expr, $this_class_name, $source); if ($var_name) { $if_types[$var_name] = [$instanceof_assertions]; $var_type = $source instanceof StatementsAnalyzer ? $source->node_data->getType($conditional->expr) : null; foreach ($instanceof_assertions as $instanceof_assertion) { $instanceof_type = $instanceof_assertion->getAtomicType(); if (!$instanceof_type instanceof TNamedObject) { continue; } if ($codebase && $var_type && $inside_negation && $source instanceof StatementsAnalyzer) { if ($codebase->interfaceExists($instanceof_type->value)) { continue; } $instanceof_type = new Union([$instanceof_type]); if (!UnionTypeComparator::canExpressionTypesBeIdentical($codebase, $instanceof_type, $var_type)) { if ($var_type->from_docblock) { IssueBuffer::maybeAdd(new RedundantConditionGivenDocblockType($var_type->getId() . ' does not contain ' . $instanceof_type->getId(), new CodeLocation($source, $conditional), $var_type->getId() . ' ' . $instanceof_type->getId()), $source->getSuppressedIssues()); } else { IssueBuffer::maybeAdd(new RedundantCondition($var_type->getId() . ' cannot be identical to ' . $instanceof_type->getId(), new CodeLocation($source, $conditional), $var_type->getId() . ' ' . $instanceof_type->getId()), $source->getSuppressedIssues()); } } } } } } return $if_types ? [$if_types] : []; } /** * @param NotIdentical|NotEqual|Identical|Equal $conditional */ private static function handleParadoxicalAssertions(StatementsAnalyzer $source, Union $var_type, ?string $this_class_name, Union $other_type, Codebase $codebase, PhpParser\Node\Expr\BinaryOp $conditional) : void { $parent_source = $source->getSource(); if ($parent_source->getSource() instanceof TraitAnalyzer && ($var_type->isSingleStringLiteral() && $var_type->getSingleStringLiteral()->value === $this_class_name || $other_type->isSingleStringLiteral() && $other_type->getSingleStringLiteral()->value === $this_class_name)) { // do nothing } elseif (!UnionTypeComparator::canExpressionTypesBeIdentical($codebase, $other_type, $var_type)) { if ($var_type->from_docblock || $other_type->from_docblock) { IssueBuffer::maybeAdd(new DocblockTypeContradiction($var_type->getId() . ' does not contain ' . $other_type->getId(), new CodeLocation($source, $conditional), $var_type->getId() . ' ' . $other_type->getId()), $source->getSuppressedIssues()); } else { if ($conditional instanceof NotEqual || $conditional instanceof NotIdentical) { IssueBuffer::maybeAdd(new RedundantCondition($var_type->getId() . ' can never contain ' . $other_type->getId(), new CodeLocation($source, $conditional), $var_type->getId() . ' ' . $other_type->getId()), $source->getSuppressedIssues()); } else { IssueBuffer::maybeAdd(new TypeDoesNotContainType($var_type->getId() . ' cannot be identical to ' . $other_type->getId(), new CodeLocation($source, $conditional), $var_type->getId() . ' ' . $other_type->getId()), $source->getSuppressedIssues()); } } } } public static function isPropertyImmutableOnArgument(string $property, NodeDataProvider $node_provider, ClassLikeStorageProvider $class_provider, PhpParser\Node\Expr\Variable $arg_expr) : ?string { $type = $node_provider->getType($arg_expr); /** @var string $name */ $name = $arg_expr->name; if (null === $type) { return 'Cannot resolve a type of variable ' . $name; } foreach ($type->getAtomicTypes() as $type) { if (!$type instanceof TNamedObject) { return 'Variable ' . $name . ' is not an object so the assertion cannot be applied'; } $class_definition = $class_provider->get($type->value); $property_definition = $class_definition->properties[$property] ?? null; if (!$property_definition instanceof PropertyStorage) { $magic_type = $class_definition->pseudo_property_get_types['$' . $property] ?? null; if ($magic_type === null) { return sprintf('Property %s is not defined on variable %s so the assertion cannot be applied', $property, $name); } $magic_getter = $class_definition->methods['__get'] ?? null; if ($magic_getter === null || !$magic_getter->mutation_free) { return "{$class_definition->name}::__get is not mutation-free, so the assertion cannot be applied"; } } } return null; } } getFQCLN(), $statements_analyzer); // gets a variable id that *may* contain array keys $extended_var_id = \Psalm\Internal\Analyzer\Statements\Expression\ExpressionIdentifier::getExtendedVarId($assign_var, $statements_analyzer->getFQCLN(), $statements_analyzer); $var_comments = []; $comment_type = null; $comment_type_location = null; $was_in_assignment = $context->inside_assignment; $context->inside_assignment = \true; $codebase = $statements_analyzer->getCodebase(); $base_assign_value = $assign_value; while ($base_assign_value instanceof PhpParser\Node\Expr\Assign) { $base_assign_value = $base_assign_value->expr; } if ($base_assign_value !== $assign_value) { ExpressionAnalyzer::analyze($statements_analyzer, $base_assign_value, $context); $assign_value_type = $statements_analyzer->node_data->getType($base_assign_value) ?? $assign_value_type; } $removed_taints = []; if ($doc_comment) { $file_path = $statements_analyzer->getRootFilePath(); $file_storage_provider = $codebase->file_storage_provider; $file_storage = $file_storage_provider->get($file_path); $template_type_map = $statements_analyzer->getTemplateTypeMap(); try { $var_comments = $codebase->config->disable_var_parsing ? [] : CommentAnalyzer::getTypeFromComment($doc_comment, $statements_analyzer->getSource(), $statements_analyzer->getAliases(), $template_type_map, $file_storage->type_aliases); } catch (IncorrectDocblockException $e) { IssueBuffer::maybeAdd(new MissingDocblockType($e->getMessage(), new CodeLocation($statements_analyzer->getSource(), $assign_var))); } catch (DocblockParseException $e) { IssueBuffer::maybeAdd(new InvalidDocblock($e->getMessage(), new CodeLocation($statements_analyzer->getSource(), $assign_var))); } foreach ($var_comments as $var_comment) { if ($var_comment->removed_taints) { $removed_taints = $var_comment->removed_taints; } self::assignTypeFromVarDocblock($statements_analyzer, $assign_var, $var_comment, $context, $var_id, $comment_type, $comment_type_location, $not_ignored_docblock_var_ids, $var_id === $var_comment->var_id && $assign_value_type && $comment_type && $assign_value_type->by_ref); } } if ($extended_var_id) { unset($context->cond_referenced_var_ids[$extended_var_id]); $context->assigned_var_ids[$extended_var_id] = (int) $assign_var->getAttribute('startFilePos'); $context->possibly_assigned_var_ids[$extended_var_id] = \true; } if ($assign_value) { if ($var_id && $assign_value instanceof PhpParser\Node\Expr\Closure) { foreach ($assign_value->uses as $closure_use) { if ($closure_use->byRef && is_string($closure_use->var->name) && $var_id === '$' . $closure_use->var->name) { $context->vars_in_scope[$var_id] = Type::getClosure(); $context->vars_possibly_in_scope[$var_id] = \true; } } } $was_inside_general_use = $context->inside_general_use; $root_expr = $assign_var; while ($root_expr instanceof PhpParser\Node\Expr\ArrayDimFetch) { $root_expr = $root_expr->var; } // if we don't know where this data is going, treat as a dead-end usage if (!$root_expr instanceof PhpParser\Node\Expr\Variable || is_string($root_expr->name) && in_array('$' . $root_expr->name, VariableFetchAnalyzer::SUPER_GLOBALS, \true)) { $context->inside_general_use = \true; } if (ExpressionAnalyzer::analyze($statements_analyzer, $assign_value, $context) === \false) { $context->inside_general_use = $was_inside_general_use; if ($var_id) { if ($extended_var_id && isset($context->vars_in_scope[$extended_var_id])) { $context->removeDescendents($extended_var_id, $context->vars_in_scope[$extended_var_id], $assign_value_type); } // if we're not exiting immediately, make everything mixed $context->vars_in_scope[$var_id] = $comment_type ?? Type::getMixed(); } return \false; } $context->inside_general_use = $was_inside_general_use; } if ($comment_type && $comment_type_location) { $temp_assign_value_type = $assign_value_type ?? ($assign_value ? $statements_analyzer->node_data->getType($assign_value) : null); if ($codebase->find_unused_variables && $temp_assign_value_type && $extended_var_id && (!$not_ignored_docblock_var_ids || isset($not_ignored_docblock_var_ids[$extended_var_id])) && $temp_assign_value_type->getId() === $comment_type->getId() && !$comment_type->isMixed(\true)) { if ($codebase->alter_code && isset($statements_analyzer->getProjectAnalyzer()->getIssuesToFix()['UnnecessaryVarAnnotation'])) { FileManipulationBuffer::addVarAnnotationToRemove($comment_type_location); } else { IssueBuffer::maybeAdd(new UnnecessaryVarAnnotation('The @var ' . $comment_type . ' annotation for ' . $extended_var_id . ' is unnecessary', $comment_type_location), $statements_analyzer->getSuppressedIssues(), \true); } } $parent_nodes = $temp_assign_value_type->parent_nodes ?? []; $assign_value_type = $comment_type->setParentNodes($parent_nodes); } elseif (!$assign_value_type) { if ($assign_value) { $assign_value_type = $statements_analyzer->node_data->getType($assign_value); } if ($assign_value_type) { $assign_value_type = $assign_value_type->setProperties(['from_property' => \false, 'from_static_property' => \false, 'ignore_isset' => \false]); } else { $assign_value_type = Type::getMixed(); } } if ($statements_analyzer->data_flow_graph instanceof VariableUseGraph && !$assign_value_type->parent_nodes) { if ($extended_var_id) { $assignment_node = DataFlowNode::getForAssignment($extended_var_id, new CodeLocation($statements_analyzer->getSource(), $assign_var)); } else { $assignment_node = new DataFlowNode('unknown-origin', 'unknown origin', null); } $parent_nodes = [$assignment_node->id => $assignment_node]; if ($context->inside_try) { // Copy previous assignment's parent nodes inside a try. Since an exception could be thrown at any // point this is a workaround to ensure that use of a variable also uses all previous assignments. if (isset($context->vars_in_scope[$extended_var_id])) { $parent_nodes += $context->vars_in_scope[$extended_var_id]->parent_nodes; } } $assign_value_type = $assign_value_type->setParentNodes($parent_nodes); } if ($extended_var_id && isset($context->vars_in_scope[$extended_var_id])) { if ($context->vars_in_scope[$extended_var_id]->by_ref) { if ($context->mutation_free) { IssueBuffer::maybeAdd(new ImpureByReferenceAssignment('Variable ' . $extended_var_id . ' cannot be assigned to as it is passed by reference', new CodeLocation($statements_analyzer->getSource(), $assign_var))); } elseif ($statements_analyzer->getSource() instanceof FunctionLikeAnalyzer && $statements_analyzer->getSource()->track_mutations) { $statements_analyzer->getSource()->inferred_impure = \true; $statements_analyzer->getSource()->inferred_has_mutation = \true; } $assign_value_type = $assign_value_type->setByRef(\true); } // removes dependent vars from $context $context->removeDescendents($extended_var_id, $context->vars_in_scope[$extended_var_id], $assign_value_type, $statements_analyzer); } else { $root_var_id = \Psalm\Internal\Analyzer\Statements\Expression\ExpressionIdentifier::getRootVarId($assign_var, $statements_analyzer->getFQCLN(), $statements_analyzer); if ($root_var_id && isset($context->vars_in_scope[$root_var_id])) { $context->removeVarFromConflictingClauses($root_var_id, $context->vars_in_scope[$root_var_id], $statements_analyzer); } } $codebase = $statements_analyzer->getCodebase(); if ($assign_value_type->hasMixed()) { $root_var_id = \Psalm\Internal\Analyzer\Statements\Expression\ExpressionIdentifier::getRootVarId($assign_var, $statements_analyzer->getFQCLN(), $statements_analyzer); if (!$context->collect_initializations && !$context->collect_mutations && $statements_analyzer->getFilePath() === $statements_analyzer->getRootFilePath() && (!($parent_source = $statements_analyzer->getSource()) instanceof FunctionLikeAnalyzer || !$parent_source->getSource() instanceof TraitAnalyzer)) { $codebase->analyzer->incrementMixedCount($statements_analyzer->getFilePath()); } if (!$assign_var instanceof PhpParser\Node\Expr\PropertyFetch && !strpos($root_var_id ?? '', '->') && !$comment_type && strpos($var_id ?? '', '$_') !== 0) { $origin_locations = []; if ($statements_analyzer->data_flow_graph instanceof VariableUseGraph) { foreach ($assign_value_type->parent_nodes as $parent_node) { $origin_locations = [...$origin_locations, ...$statements_analyzer->data_flow_graph->getOriginLocations($parent_node)]; } } $origin_location = count($origin_locations) === 1 ? reset($origin_locations) : null; $message = $var_id ? 'Unable to determine the type that ' . $var_id . ' is being assigned to' : 'Unable to determine the type of this assignment'; $issue_location = new CodeLocation($statements_analyzer->getSource(), $assign_var); if ($origin_location && $origin_location->getHash() === $issue_location->getHash()) { $origin_location = null; } IssueBuffer::maybeAdd(new MixedAssignment($message, $issue_location, $origin_location), $statements_analyzer->getSuppressedIssues()); } } else { if (!$context->collect_initializations && !$context->collect_mutations && $statements_analyzer->getFilePath() === $statements_analyzer->getRootFilePath() && (!($parent_source = $statements_analyzer->getSource()) instanceof FunctionLikeAnalyzer || !$parent_source->getSource() instanceof TraitAnalyzer)) { $codebase->analyzer->incrementNonMixedCount($statements_analyzer->getFilePath()); } if ($var_id && isset($context->byref_constraints[$var_id]) && ($outer_constraint_type = $context->byref_constraints[$var_id]->type)) { if (!UnionTypeComparator::isContainedBy($codebase, $assign_value_type, $outer_constraint_type, $assign_value_type->ignore_nullable_issues, $assign_value_type->ignore_falsable_issues)) { IssueBuffer::maybeAdd(new ReferenceConstraintViolation('Variable ' . $var_id . ' is limited to values of type ' . $context->byref_constraints[$var_id]->type . ' because it is passed by reference, ' . $assign_value_type->getId() . ' type found', new CodeLocation($statements_analyzer->getSource(), $assign_var)), $statements_analyzer->getSuppressedIssues()); } } } if ($var_id === '$this' && IssueBuffer::accepts(new InvalidScope('Cannot re-assign ' . $var_id, new CodeLocation($statements_analyzer->getSource(), $assign_var)), $statements_analyzer->getSuppressedIssues())) { return \false; } if (isset($context->protected_var_ids[$var_id]) && $assign_value_type->hasLiteralInt()) { IssueBuffer::maybeAdd(new LoopInvalidation('Variable ' . $var_id . ' has already been assigned in a for/foreach loop', new CodeLocation($statements_analyzer->getSource(), $assign_var)), $statements_analyzer->getSuppressedIssues()); } if (self::analyzeAssignment($assign_var, $statements_analyzer, $codebase, $assign_value, $assign_value_type, $var_id, $context, $doc_comment, $extended_var_id, $var_comments, $removed_taints) === \false) { return \false; } if ($var_id && isset($context->vars_in_scope[$var_id])) { if ($context->vars_in_scope[$var_id]->isVoid()) { IssueBuffer::maybeAdd(new AssignmentToVoid('Cannot assign ' . $var_id . ' to type void', new CodeLocation($statements_analyzer->getSource(), $assign_var)), $statements_analyzer->getSuppressedIssues()); $context->vars_in_scope[$var_id] = Type::getNull(); $context->inside_assignment = $was_in_assignment; return $context->vars_in_scope[$var_id]; } if ($context->vars_in_scope[$var_id]->isNever()) { if (!IssueBuffer::accepts(new NoValue('All possible types for this assignment were invalidated - This may be dead code', new CodeLocation($statements_analyzer->getSource(), $assign_var)), $statements_analyzer->getSuppressedIssues())) { // if the error is suppressed, do not treat it as never anymore $new_mutable = $context->vars_in_scope[$var_id]->getBuilder()->addType(new TMixed()); $new_mutable->removeType('never'); $context->vars_in_scope[$var_id] = $new_mutable->freeze(); $context->has_returned = \false; } else { $context->inside_assignment = $was_in_assignment; return $context->vars_in_scope[$var_id]; } } if ($statements_analyzer->data_flow_graph) { $data_flow_graph = $statements_analyzer->data_flow_graph; if ($context->vars_in_scope[$var_id]->parent_nodes) { if ($data_flow_graph instanceof TaintFlowGraph && in_array('TaintedInput', $statements_analyzer->getSuppressedIssues())) { $context->vars_in_scope[$var_id] = $context->vars_in_scope[$var_id]->setParentNodes([]); } else { $var_location = new CodeLocation($statements_analyzer->getSource(), $assign_var); $event = new AddRemoveTaintsEvent($assign_var, $context, $statements_analyzer, $codebase); $added_taints = $codebase->config->eventDispatcher->dispatchAddTaints($event); $removed_taints = [...$removed_taints, ...$codebase->config->eventDispatcher->dispatchRemoveTaints($event)]; self::taintAssignment($context->vars_in_scope[$var_id], $data_flow_graph, $var_id, $var_location, $removed_taints, $added_taints); } if ($assign_expr) { $new_parent_node = DataFlowNode::getForAssignment('assignment_expr', new CodeLocation($statements_analyzer->getSource(), $assign_expr)); $data_flow_graph->addNode($new_parent_node); foreach ($context->vars_in_scope[$var_id]->parent_nodes as $old_parent_node) { $data_flow_graph->addPath($old_parent_node, $new_parent_node, '='); } $assign_value_type = $assign_value_type->setParentNodes([$new_parent_node->id => $new_parent_node]); } } } } $context->inside_assignment = $was_in_assignment; return $assign_value_type; } /** * @param list $var_comments * @param list $removed_taints * @return null|false */ private static function analyzeAssignment(Expr $assign_var, StatementsAnalyzer $statements_analyzer, Codebase $codebase, ?Expr $assign_value, Union $assign_value_type, ?string $var_id, Context $context, ?Doc $doc_comment, ?string $extended_var_id, array $var_comments, array $removed_taints) : ?bool { if ($assign_var instanceof PhpParser\Node\Expr\Variable) { self::analyzeAssignmentToVariable($statements_analyzer, $codebase, $assign_var, $assign_value, $assign_value_type, $var_id, $context); } elseif ($assign_var instanceof PhpParser\Node\Expr\List_ || $assign_var instanceof PhpParser\Node\Expr\Array_) { self::analyzeDestructuringAssignment($statements_analyzer, $codebase, $assign_var, $assign_value, $assign_value_type, $context, $doc_comment, $extended_var_id, $var_comments, $removed_taints); } elseif ($assign_var instanceof PhpParser\Node\Expr\ArrayDimFetch) { ArrayAssignmentAnalyzer::analyze($statements_analyzer, $assign_var, $context, $assign_value, $assign_value_type); } elseif ($assign_var instanceof PhpParser\Node\Expr\PropertyFetch) { self::analyzePropertyAssignment($statements_analyzer, $codebase, $assign_var, $context, $assign_value, $assign_value_type, $var_id); } elseif ($assign_var instanceof PhpParser\Node\Expr\StaticPropertyFetch && $assign_var->class instanceof PhpParser\Node\Name) { if (ExpressionAnalyzer::analyze($statements_analyzer, $assign_var, $context) === \false) { return \false; } if (StaticPropertyAssignmentAnalyzer::analyze($statements_analyzer, $assign_var, $assign_value, $assign_value_type, $context) === \false) { return \false; } if ($var_id) { $context->vars_possibly_in_scope[$var_id] = \true; } } return null; } public static function assignTypeFromVarDocblock(StatementsAnalyzer $statements_analyzer, PhpParser\Node $stmt, VarDocblockComment $var_comment, Context $context, ?string $var_id = null, ?Union &$comment_type = null, ?DocblockTypeLocation &$comment_type_location = null, array $not_ignored_docblock_var_ids = [], bool $by_ref = \false) : void { if (!$var_comment->type) { return; } $codebase = $statements_analyzer->getCodebase(); try { $var_comment_type = TypeExpander::expandUnion($codebase, $var_comment->type, $context->self, $context->self, $statements_analyzer->getParentFQCLN()); $var_comment_type = $var_comment_type->setProperties(['from_docblock' => \true, 'by_ref' => $by_ref]); /** @psalm-suppress UnusedMethodCall This actually has the side effect of generating issues */ $var_comment_type->check($statements_analyzer, new CodeLocation($statements_analyzer->getSource(), $stmt), $statements_analyzer->getSuppressedIssues(), [], \false, \false, \false, $context->calling_method_id); $type_location = null; if ($var_comment->type_start && $var_comment->type_end && $var_comment->line_number) { $type_location = new DocblockTypeLocation($statements_analyzer, $var_comment->type_start, $var_comment->type_end, $var_comment->line_number); if ($codebase->alter_code) { $codebase->classlikes->handleDocblockTypeInMigration($codebase, $statements_analyzer, $var_comment_type, $type_location, $context->calling_method_id); } } if (!$var_comment->var_id || $var_comment->var_id === $var_id) { $comment_type = $var_comment_type; $comment_type_location = $type_location; return; } $project_analyzer = $statements_analyzer->getProjectAnalyzer(); if ($codebase->find_unused_variables && $type_location && (!$not_ignored_docblock_var_ids || isset($not_ignored_docblock_var_ids[$var_comment->var_id])) && isset($context->vars_in_scope[$var_comment->var_id]) && $context->vars_in_scope[$var_comment->var_id]->getId() === $var_comment_type->getId() && !$var_comment_type->isMixed()) { if ($codebase->alter_code && isset($project_analyzer->getIssuesToFix()['UnnecessaryVarAnnotation'])) { FileManipulationBuffer::addVarAnnotationToRemove($type_location); } else { IssueBuffer::maybeAdd(new UnnecessaryVarAnnotation('The @var ' . $var_comment_type . ' annotation for ' . $var_comment->var_id . ' is unnecessary', $type_location), $statements_analyzer->getSuppressedIssues(), \true); } } $parent_nodes = $context->vars_in_scope[$var_comment->var_id]->parent_nodes ?? []; $var_comment_type = $var_comment_type->setParentNodes($parent_nodes); $context->vars_in_scope[$var_comment->var_id] = $var_comment_type; } catch (UnexpectedValueException $e) { IssueBuffer::maybeAdd(new InvalidDocblock($e->getMessage(), new CodeLocation($statements_analyzer->getSource(), $stmt))); } } /** * @param array $removed_taints * @param array $added_taints */ private static function taintAssignment(Union &$type, DataFlowGraph $data_flow_graph, string $var_id, CodeLocation $var_location, array $removed_taints, array $added_taints) : void { $parent_nodes = $type->parent_nodes; $new_parent_node = DataFlowNode::getForAssignment($var_id, $var_location); $data_flow_graph->addNode($new_parent_node); $new_parent_nodes = [$new_parent_node->id => $new_parent_node]; foreach ($parent_nodes as $parent_node) { $data_flow_graph->addPath($parent_node, $new_parent_node, '=', $added_taints, $removed_taints); } $type = $type->setParentNodes($new_parent_nodes, \false); } public static function analyzeAssignmentOperation(StatementsAnalyzer $statements_analyzer, PhpParser\Node\Expr\AssignOp $stmt, Context $context) : bool { if ($stmt instanceof PhpParser\Node\Expr\AssignOp\BitwiseAnd) { $operation = new VirtualBitwiseAnd($stmt->var, $stmt->expr, $stmt->getAttributes()); } elseif ($stmt instanceof PhpParser\Node\Expr\AssignOp\BitwiseOr) { $operation = new VirtualBitwiseOr($stmt->var, $stmt->expr, $stmt->getAttributes()); } elseif ($stmt instanceof PhpParser\Node\Expr\AssignOp\BitwiseXor) { $operation = new VirtualBitwiseXor($stmt->var, $stmt->expr, $stmt->getAttributes()); } elseif ($stmt instanceof PhpParser\Node\Expr\AssignOp\Coalesce) { $operation = new VirtualCoalesce($stmt->var, $stmt->expr, $stmt->getAttributes()); } elseif ($stmt instanceof PhpParser\Node\Expr\AssignOp\Concat) { $operation = new VirtualConcat($stmt->var, $stmt->expr, $stmt->getAttributes()); } elseif ($stmt instanceof PhpParser\Node\Expr\AssignOp\Div) { $operation = new VirtualDiv($stmt->var, $stmt->expr, $stmt->getAttributes()); } elseif ($stmt instanceof PhpParser\Node\Expr\AssignOp\Minus) { $operation = new VirtualMinus($stmt->var, $stmt->expr, $stmt->getAttributes()); } elseif ($stmt instanceof PhpParser\Node\Expr\AssignOp\Mod) { $operation = new VirtualMod($stmt->var, $stmt->expr, $stmt->getAttributes()); } elseif ($stmt instanceof PhpParser\Node\Expr\AssignOp\Mul) { $operation = new VirtualMul($stmt->var, $stmt->expr, $stmt->getAttributes()); } elseif ($stmt instanceof PhpParser\Node\Expr\AssignOp\Plus) { $operation = new VirtualPlus($stmt->var, $stmt->expr, $stmt->getAttributes()); } elseif ($stmt instanceof PhpParser\Node\Expr\AssignOp\Pow) { $operation = new VirtualPow($stmt->var, $stmt->expr, $stmt->getAttributes()); } elseif ($stmt instanceof PhpParser\Node\Expr\AssignOp\ShiftLeft) { $operation = new VirtualShiftLeft($stmt->var, $stmt->expr, $stmt->getAttributes()); } elseif ($stmt instanceof PhpParser\Node\Expr\AssignOp\ShiftRight) { $operation = new VirtualShiftRight($stmt->var, $stmt->expr, $stmt->getAttributes()); } else { throw new UnexpectedValueException('Unknown assign op'); } $fake_assignment = new VirtualAssign($stmt->var, $operation, $stmt->getAttributes()); $old_node_data = $statements_analyzer->node_data; $statements_analyzer->node_data = clone $statements_analyzer->node_data; if (ExpressionAnalyzer::analyze($statements_analyzer, $fake_assignment, $context) === \false) { return \false; } $old_node_data->setType($stmt, $statements_analyzer->node_data->getType($operation) ?? Type::getMixed()); $statements_analyzer->node_data = $old_node_data; return \true; } public static function analyzeAssignmentRef(StatementsAnalyzer $statements_analyzer, PhpParser\Node\Expr\AssignRef $stmt, Context $context) : bool { ExpressionAnalyzer::analyze($statements_analyzer, $stmt->expr, $context, \false, null, \false, null, \true); $lhs_var_id = \Psalm\Internal\Analyzer\Statements\Expression\ExpressionIdentifier::getExtendedVarId($stmt->var, $statements_analyzer->getFQCLN(), $statements_analyzer); $rhs_var_id = \Psalm\Internal\Analyzer\Statements\Expression\ExpressionIdentifier::getExtendedVarId($stmt->expr, $statements_analyzer->getFQCLN(), $statements_analyzer); $doc_comment = $stmt->getDocComment(); if ($doc_comment) { try { $var_comments = CommentAnalyzer::getTypeFromComment($doc_comment, $statements_analyzer->getSource(), $statements_analyzer->getAliases()); } catch (IncorrectDocblockException $e) { IssueBuffer::maybeAdd(new MissingDocblockType($e->getMessage(), new CodeLocation($statements_analyzer->getSource(), $stmt))); } catch (DocblockParseException $e) { IssueBuffer::maybeAdd(new InvalidDocblock($e->getMessage(), new CodeLocation($statements_analyzer->getSource(), $stmt))); } if (!empty($var_comments) && $var_comments[0]->type !== null && $var_comments[0]->var_id === null) { IssueBuffer::maybeAdd(new InvalidDocblock("Docblock type cannot be used for reference assignment", new CodeLocation($statements_analyzer->getSource(), $stmt))); } } if ($lhs_var_id === null || $rhs_var_id === null) { return \false; } if (!isset($context->vars_in_scope[$rhs_var_id])) { // Sometimes the $rhs_var_id isn't set in $vars_in_scope, for example if it's an unknown array offset. $context->vars_in_scope[$rhs_var_id] = $statements_analyzer->node_data->getType($stmt->expr) ?? Type::getMixed(); } if (isset($context->references_in_scope[$lhs_var_id])) { // Decrement old referenced variable's reference count $context->decrementReferenceCount($lhs_var_id); // Remove old reference parent node so previously referenced variable usage doesn't count as reference usage $old_type = $context->vars_in_scope[$lhs_var_id]; foreach ($old_type->parent_nodes as $old_parent_node_id => $_) { if (strpos($old_parent_node_id, "{$lhs_var_id}-") === 0) { unset($old_type->parent_nodes[$old_parent_node_id]); } } } // When assigning an existing reference as a reference it removes the // old reference, so it's no longer potentially from a confusing scope. unset($context->references_possibly_from_confusing_scope[$lhs_var_id]); $context->vars_in_scope[$lhs_var_id] =& $context->vars_in_scope[$rhs_var_id]; $context->hasVariable($lhs_var_id); $context->references_in_scope[$lhs_var_id] = $rhs_var_id; $context->referenced_counts[$rhs_var_id] = ($context->referenced_counts[$rhs_var_id] ?? 0) + 1; if (strpos($rhs_var_id, '[') !== \false) { // Reference to array item, we always consider array items to be an external scope for references // TODO handle differently so it's detected as unused if the array is unused? $context->references_to_external_scope[$lhs_var_id] = \true; } if (strpos($rhs_var_id, '->') !== \false) { IssueBuffer::maybeAdd(new UnsupportedPropertyReferenceUsage(new CodeLocation($statements_analyzer->getSource(), $stmt)), $statements_analyzer->getSuppressedIssues()); // Reference to object property, we always consider object properties to be an external scope for references // TODO handle differently so it's detected as unused if the object is unused? $context->references_to_external_scope[$lhs_var_id] = \true; } if (strpos($rhs_var_id, '::') !== \false) { IssueBuffer::maybeAdd(new UnsupportedPropertyReferenceUsage(new CodeLocation($statements_analyzer->getSource(), $stmt)), $statements_analyzer->getSuppressedIssues()); } $lhs_location = new CodeLocation($statements_analyzer->getSource(), $stmt->var); if (!$stmt->var instanceof ArrayDimFetch && !$stmt->var instanceof PropertyFetch) { // If left-hand-side is an array offset or object property, usage is too difficult to track, // so it's not registered as an unused variable (this mirrors behavior for non-references). $statements_analyzer->registerVariableAssignment($lhs_var_id, $lhs_location); } $lhs_node = DataFlowNode::getForAssignment($lhs_var_id, $lhs_location); $context->vars_in_scope[$lhs_var_id] = $context->vars_in_scope[$lhs_var_id]->addParentNodes([$lhs_node->id => $lhs_node]); if ($stmt->var instanceof ArrayDimFetch && $stmt->var->dim !== null) { // Analyze offset so that variables in the offset get marked as used $was_inside_general_use = $context->inside_general_use; $context->inside_general_use = \true; ExpressionAnalyzer::analyze($statements_analyzer, $stmt->var->dim, $context); $context->inside_general_use = $was_inside_general_use; } return \true; } public static function assignByRefParam(StatementsAnalyzer $statements_analyzer, PhpParser\Node\Expr $stmt, Union $by_ref_type, Union $by_ref_out_type, Context $context, bool $constrain_type = \true, bool $prevent_null = \false) : void { if ($stmt instanceof PhpParser\Node\Expr\PropertyFetch && $stmt->name instanceof PhpParser\Node\Identifier) { $prop_name = $stmt->name->name; InstancePropertyAssignmentAnalyzer::analyze($statements_analyzer, $stmt, $prop_name, null, $by_ref_out_type, $context); return; } $var_id = \Psalm\Internal\Analyzer\Statements\Expression\ExpressionIdentifier::getVarId($stmt, $statements_analyzer->getFQCLN(), $statements_analyzer); if ($var_id) { $var_not_in_scope = \false; if (!$by_ref_type->hasMixed() && $constrain_type) { $context->byref_constraints[$var_id] = new ReferenceConstraint($by_ref_type); } if (!$context->hasVariable($var_id)) { $context->vars_possibly_in_scope[$var_id] = \true; $location = new CodeLocation($statements_analyzer->getSource(), $stmt); if (!$statements_analyzer->hasVariable($var_id)) { if ($constrain_type && $prevent_null && !$by_ref_type->isMixed() && !$by_ref_type->isNullable() && !strpos($var_id, '->') && !strpos($var_id, '::')) { IssueBuffer::maybeAdd(new NullReference('Not expecting null argument passed by reference', $location), $statements_analyzer->getSuppressedIssues()); } if ($stmt instanceof PhpParser\Node\Expr\Variable) { $statements_analyzer->registerVariable($var_id, $location, $context->branch_point); if ($statements_analyzer->data_flow_graph instanceof VariableUseGraph) { $byref_node = DataFlowNode::getForAssignment($var_id, $location); $statements_analyzer->data_flow_graph->addPath($byref_node, new DataFlowNode('variable-use', 'variable use', null), 'variable-use'); } } $context->hasVariable($var_id); } else { $var_not_in_scope = \true; } } elseif ($var_id === '$this') { // don't allow changing $this return; } else { $existing_type = $context->vars_in_scope[$var_id]; // removes dependent vars from $context $context->removeDescendents($var_id, $existing_type, $by_ref_type, $statements_analyzer); $by_ref_out_type = $by_ref_out_type->addParentNodes($existing_type->parent_nodes); if (!$context->inside_conditional) { $context->vars_in_scope[$var_id] = $by_ref_out_type; if (!($stmt_type = $statements_analyzer->node_data->getType($stmt)) || $stmt_type->isNever()) { $statements_analyzer->node_data->setType($stmt, $by_ref_type); } return; } } $context->assigned_var_ids[$var_id] = (int) $stmt->getAttribute('startFilePos'); $context->vars_in_scope[$var_id] = $by_ref_out_type; $stmt_type = $statements_analyzer->node_data->getType($stmt); if (!$stmt_type || $stmt_type->isNever()) { $statements_analyzer->node_data->setType($stmt, $by_ref_type); } if ($var_not_in_scope && $stmt instanceof PhpParser\Node\Expr\Variable) { $statements_analyzer->registerPossiblyUndefinedVariable($var_id, $stmt); } } } /** * @param PhpParser\Node\Expr\List_|PhpParser\Node\Expr\Array_ $assign_var * @param list $var_comments * @param list $removed_taints */ private static function analyzeDestructuringAssignment(StatementsAnalyzer $statements_analyzer, Codebase $codebase, PhpParser\Node\Expr $assign_var, ?PhpParser\Node\Expr $assign_value, Union $assign_value_type, Context $context, ?PhpParser\Comment\Doc $doc_comment, ?string $extended_var_id, array $var_comments, array $removed_taints) : void { if (!$assign_value_type->hasArray() && !$assign_value_type->isMixed() && !$assign_value_type->hasArrayAccessInterface($codebase)) { IssueBuffer::maybeAdd(new InvalidArrayOffset('Cannot destructure non-array of type ' . $assign_value_type->getId(), new CodeLocation($statements_analyzer->getSource(), $assign_var)), $statements_analyzer->getSuppressedIssues()); } $can_be_empty = \true; foreach ($assign_var->items as $offset => $assign_var_item) { // $assign_var_item can be null e.g. list($a, ) = ['a', 'b'] if (!$assign_var_item) { continue; } $var = $assign_var_item->value; if ($assign_value instanceof PhpParser\Node\Expr\Array_ && $statements_analyzer->node_data->getType($assign_var_item->value)) { self::analyze($statements_analyzer, $var, $assign_var_item->value, null, $context, $doc_comment); continue; } $offset_value = null; if (!$assign_var_item->key) { $offset_value = $offset; } elseif ($assign_var_item->key instanceof PhpParser\Node\Scalar\String_) { $offset_value = $assign_var_item->key->value; } if ($offset_value !== null) { $string_to_int = \Psalm\Internal\Analyzer\Statements\Expression\ArrayAnalyzer::getLiteralArrayKeyInt($offset_value); if ($string_to_int !== \false) { $offset_value = $string_to_int; } } $list_var_id = \Psalm\Internal\Analyzer\Statements\Expression\ExpressionIdentifier::getExtendedVarId($var, $statements_analyzer->getFQCLN(), $statements_analyzer); $new_assign_type = null; $assigned = \false; $has_null = \false; foreach ($assign_value_type->getAtomicTypes() as $assign_value_atomic_type) { if ($assign_value_atomic_type instanceof TList) { $assign_value_atomic_type = $assign_value_atomic_type->getKeyedArray(); } if ($assign_value_atomic_type instanceof TKeyedArray && !$assign_var_item->key) { // if object-like has int offsets if ($offset_value !== null && isset($assign_value_atomic_type->properties[$offset_value])) { $value_type = $assign_value_atomic_type->properties[$offset_value]; if ($value_type->possibly_undefined) { IssueBuffer::maybeAdd(new PossiblyUndefinedArrayOffset('Possibly undefined array key', new CodeLocation($statements_analyzer->getSource(), $var)), $statements_analyzer->getSuppressedIssues()); $value_type = $value_type->setPossiblyUndefined(\false); } else { $can_be_empty = \false; } if ($statements_analyzer->data_flow_graph && $assign_value) { $assign_value_id = \Psalm\Internal\Analyzer\Statements\Expression\ExpressionIdentifier::getExtendedVarId($assign_value, $statements_analyzer->getFQCLN(), $statements_analyzer); $keyed_array_var_id = null; if ($assign_value_id) { $keyed_array_var_id = $assign_value_id . '[\'' . $offset_value . '\']'; } $temp = Type::getString((string) $offset_value); ArrayFetchAnalyzer::taintArrayFetch($statements_analyzer, $assign_value, $keyed_array_var_id, $value_type, $temp); } self::analyze($statements_analyzer, $var, null, $value_type, $context, $doc_comment); $assigned = \true; continue; } if ($assign_value_atomic_type->fallback_params === null) { IssueBuffer::maybeAdd(new InvalidArrayOffset('Cannot access value with offset ' . $offset, new CodeLocation($statements_analyzer->getSource(), $var)), $statements_analyzer->getSuppressedIssues()); } } if ($assign_value_atomic_type instanceof TMixed) { IssueBuffer::maybeAdd(new MixedArrayAccess('Cannot access array value on mixed variable ' . $extended_var_id, new CodeLocation($statements_analyzer->getSource(), $var)), $statements_analyzer->getSuppressedIssues()); } elseif ($assign_value_atomic_type instanceof TNull) { $has_null = \true; } elseif (!$assign_value_atomic_type instanceof TArray && !$assign_value_atomic_type instanceof TKeyedArray && !$assign_value_type->hasArrayAccessInterface($codebase)) { if ($assign_value_type->hasArray()) { if ($assign_value_atomic_type instanceof TFalse && $assign_value_type->ignore_falsable_issues) { // do nothing } else { IssueBuffer::maybeAdd(new PossiblyInvalidArrayAccess('Cannot access array value on non-array variable ' . $extended_var_id . ' of type ' . $assign_value_atomic_type->getId(), new CodeLocation($statements_analyzer->getSource(), $var)), $statements_analyzer->getSuppressedIssues()); } } else { IssueBuffer::maybeAdd(new InvalidArrayAccess('Cannot access array value on non-array variable ' . $extended_var_id . ' of type ' . $assign_value_atomic_type->getId(), new CodeLocation($statements_analyzer->getSource(), $var)), $statements_analyzer->getSuppressedIssues()); } } if ($var instanceof PhpParser\Node\Expr\List_ || $var instanceof PhpParser\Node\Expr\Array_) { if ($assign_value_atomic_type instanceof TKeyedArray) { $assign_value_atomic_type = $assign_value_atomic_type->getGenericArrayType(); } $array_value_type = $assign_value_atomic_type instanceof TArray ? $assign_value_atomic_type->type_params[1] : Type::getMixed(); self::analyze($statements_analyzer, $var, null, $array_value_type, $context, $doc_comment); continue; } if ($list_var_id) { $context->vars_possibly_in_scope[$list_var_id] = \true; $context->assigned_var_ids[$list_var_id] = (int) $var->getAttribute('startFilePos'); $context->possibly_assigned_var_ids[$list_var_id] = \true; $already_in_scope = isset($context->vars_in_scope[$list_var_id]); if (strpos($list_var_id, '-') === \false && strpos($list_var_id, '[') === \false) { $location = new CodeLocation($statements_analyzer, $var); if (!$statements_analyzer->hasVariable($list_var_id)) { $statements_analyzer->registerVariable($list_var_id, $location, $context->branch_point); } else { $statements_analyzer->registerVariableAssignment($list_var_id, $location); } if (isset($context->byref_constraints[$list_var_id])) { // something } } if ($assign_value_atomic_type instanceof TArray) { $new_assign_type = $assign_value_atomic_type->type_params[1]; if ($statements_analyzer->data_flow_graph && $assign_value) { $temp = Type::getArrayKey(); ArrayFetchAnalyzer::taintArrayFetch($statements_analyzer, $assign_value, null, $new_assign_type, $temp); } $can_be_empty = !$assign_value_atomic_type instanceof TNonEmptyArray; } elseif ($assign_value_atomic_type instanceof TKeyedArray) { if (($assign_var_item->key instanceof PhpParser\Node\Scalar\String_ || $assign_var_item->key instanceof PhpParser\Node\Scalar\LNumber) && isset($assign_value_atomic_type->properties[$assign_var_item->key->value])) { $new_assign_type = $assign_value_atomic_type->properties[$assign_var_item->key->value]; if ($new_assign_type->possibly_undefined) { IssueBuffer::maybeAdd(new PossiblyUndefinedArrayOffset('Possibly undefined array key', new CodeLocation($statements_analyzer->getSource(), $var)), $statements_analyzer->getSuppressedIssues()); $new_assign_type = $new_assign_type->setPossiblyUndefined(\false); } else { $can_be_empty = \false; } } elseif (!$assign_var_item->key instanceof PhpParser\Node\Scalar\String_ && $assign_value_atomic_type->is_list && $assign_value_atomic_type->fallback_params) { if ($codebase->config->ensure_array_int_offsets_exist) { IssueBuffer::maybeAdd(new PossiblyUndefinedIntArrayOffset('Possibly undefined array key', new CodeLocation($statements_analyzer->getSource(), $var)), $statements_analyzer->getSuppressedIssues()); } $new_assign_type = $assign_value_atomic_type->fallback_params[1]; } if ($statements_analyzer->data_flow_graph && $assign_value && $new_assign_type) { $temp = Type::getArrayKey(); ArrayFetchAnalyzer::taintArrayFetch($statements_analyzer, $assign_value, null, $new_assign_type, $temp); } } elseif ($assign_value_atomic_type->hasArrayAccessInterface($codebase)) { ForeachAnalyzer::getKeyValueParamsForTraversableObject($assign_value_atomic_type, $codebase, $array_access_key_type, $array_access_value_type); $new_assign_type = $array_access_value_type; } if ($already_in_scope) { // removes dependent vars from $context $context->removeDescendents($list_var_id, $context->vars_in_scope[$list_var_id], $new_assign_type, $statements_analyzer); } } } if (!$assigned) { if ($has_null) { IssueBuffer::maybeAdd(new PossiblyNullArrayAccess('Cannot access array value on null variable ' . $extended_var_id, new CodeLocation($statements_analyzer->getSource(), $var)), $statements_analyzer->getSuppressedIssues()); } foreach ($var_comments as $var_comment) { if (!$var_comment->type) { continue; } try { if ($var_comment->var_id === $list_var_id) { $var_comment_type = TypeExpander::expandUnion($codebase, $var_comment->type, $context->self, $context->self, $statements_analyzer->getParentFQCLN()); $var_comment_type = $var_comment_type->setFromDocblock(); $new_assign_type = $var_comment_type; break; } } catch (UnexpectedValueException $e) { IssueBuffer::maybeAdd(new InvalidDocblock($e->getMessage(), new CodeLocation($statements_analyzer->getSource(), $assign_var))); } } if ($list_var_id) { $context->vars_in_scope[$list_var_id] = $new_assign_type ?: Type::getMixed(); if ($statements_analyzer->data_flow_graph) { $data_flow_graph = $statements_analyzer->data_flow_graph; $var_location = new CodeLocation($statements_analyzer->getSource(), $var); if (!$context->vars_in_scope[$list_var_id]->parent_nodes) { $assignment_node = DataFlowNode::getForAssignment($list_var_id, $var_location); $context->vars_in_scope[$list_var_id] = $context->vars_in_scope[$list_var_id]->setParentNodes([$assignment_node->id => $assignment_node]); } else { if ($data_flow_graph instanceof TaintFlowGraph && in_array('TaintedInput', $statements_analyzer->getSuppressedIssues())) { $context->vars_in_scope[$list_var_id] = $context->vars_in_scope[$list_var_id]->setParentNodes([]); } else { $event = new AddRemoveTaintsEvent($var, $context, $statements_analyzer, $codebase); $added_taints = $codebase->config->eventDispatcher->dispatchAddTaints($event); $removed_taints = [...$removed_taints, ...$codebase->config->eventDispatcher->dispatchRemoveTaints($event)]; self::taintAssignment($context->vars_in_scope[$list_var_id], $data_flow_graph, $list_var_id, $var_location, $removed_taints, $added_taints); } } } } } if ($list_var_id) { if ($context->error_suppressing && ($offset || $can_be_empty) || $has_null) { $context->vars_in_scope[$list_var_id] = $context->vars_in_scope[$list_var_id]->getBuilder()->addType(new TNull())->freeze(); } } } } private static function analyzePropertyAssignment(StatementsAnalyzer $statements_analyzer, Codebase $codebase, PhpParser\Node\Expr\PropertyFetch $assign_var, Context $context, ?PhpParser\Node\Expr $assign_value, Union $assign_value_type, ?string $var_id) : void { if (!$assign_var->name instanceof PhpParser\Node\Identifier) { $was_inside_general_use = $context->inside_general_use; $context->inside_general_use = \true; // this can happen when the user actually means to type $this->, but there's // a variable on the next line if (ExpressionAnalyzer::analyze($statements_analyzer, $assign_var->var, $context) === \false) { $context->inside_general_use = $was_inside_general_use; return; } if (ExpressionAnalyzer::analyze($statements_analyzer, $assign_var->name, $context) === \false) { $context->inside_general_use = $was_inside_general_use; return; } $context->inside_general_use = $was_inside_general_use; } if ($assign_var->name instanceof PhpParser\Node\Identifier) { $prop_name = $assign_var->name->name; } elseif (($assign_var_name_type = $statements_analyzer->node_data->getType($assign_var->name)) && $assign_var_name_type->isSingleStringLiteral()) { $prop_name = $assign_var_name_type->getSingleStringLiteral()->value; } else { $prop_name = null; } if ($prop_name) { InstancePropertyAssignmentAnalyzer::analyze($statements_analyzer, $assign_var, $prop_name, $assign_value, $assign_value_type, $context); } else { if (ExpressionAnalyzer::analyze($statements_analyzer, $assign_var->var, $context) === \false) { return; } if (($assign_var_type = $statements_analyzer->node_data->getType($assign_var->var)) && !$context->ignore_variable_property) { $stmt_var_type = $assign_var_type; if ($stmt_var_type->hasObjectType()) { foreach ($stmt_var_type->getAtomicTypes() as $type) { if ($type instanceof TNamedObject) { $codebase->analyzer->addMixedMemberName(strtolower($type->value) . '::$', $context->calling_method_id ?: $statements_analyzer->getFileName()); } } } } } if ($var_id) { $context->vars_possibly_in_scope[$var_id] = \true; } $property_var_pure_compatible = $statements_analyzer->node_data->isPureCompatible($assign_var->var); // prevents writing to any properties in a mutation-free context if (!$property_var_pure_compatible && !$context->collect_mutations && !$context->collect_initializations) { if ($context->mutation_free || $context->external_mutation_free) { IssueBuffer::maybeAdd(new ImpurePropertyAssignment('Cannot assign to a property from a mutation-free context', new CodeLocation($statements_analyzer, $assign_var)), $statements_analyzer->getSuppressedIssues()); } elseif ($statements_analyzer->getSource() instanceof FunctionLikeAnalyzer && $statements_analyzer->getSource()->track_mutations) { if (!$assign_var->var instanceof PhpParser\Node\Expr\Variable || $assign_var->var->name !== 'this') { $statements_analyzer->getSource()->inferred_has_mutation = \true; } $statements_analyzer->getSource()->inferred_impure = \true; } } } private static function analyzeAssignmentToVariable(StatementsAnalyzer $statements_analyzer, Codebase $codebase, PhpParser\Node\Expr\Variable $assign_var, ?PhpParser\Node\Expr $assign_value, Union $assign_value_type, ?string $var_id, Context $context) : void { if (is_string($assign_var->name)) { if ($var_id) { $original_type = $context->vars_in_scope[$var_id] ?? null; $context->vars_in_scope[$var_id] = $assign_value_type; $context->vars_possibly_in_scope[$var_id] = \true; $location = new CodeLocation($statements_analyzer, $assign_var); if (!$statements_analyzer->hasVariable($var_id)) { $statements_analyzer->registerVariable($var_id, $location, $context->branch_point); } elseif (!$context->inside_isset) { $statements_analyzer->registerVariableAssignment($var_id, $location); } if ($codebase->store_node_types && !$context->collect_initializations && !$context->collect_mutations) { $location = new CodeLocation($statements_analyzer, $assign_var); $codebase->analyzer->addNodeReference($statements_analyzer->getFilePath(), $assign_var, $location->raw_file_start . '-' . $location->raw_file_end . ':' . $assign_value_type->getId()); } if (isset($context->byref_constraints[$var_id])) { $assign_value_type = $assign_value_type->setByRef(\true); } if ($statements_analyzer->data_flow_graph instanceof VariableUseGraph && $assign_value_type->parent_nodes) { if (isset($context->references_to_external_scope[$var_id]) || isset($context->references_in_scope[$var_id]) || isset($context->referenced_counts[$var_id]) && $context->referenced_counts[$var_id] > 0) { $location = new CodeLocation($statements_analyzer, $assign_var); $assignment_node = DataFlowNode::getForAssignment($var_id, $location); $parent_nodes = $assign_value_type->parent_nodes; if ($original_type !== null) { $parent_nodes += $original_type->parent_nodes; } foreach ($parent_nodes as $parent_node) { $statements_analyzer->data_flow_graph->addPath($parent_node, $assignment_node, '&='); } if (isset($context->references_to_external_scope[$var_id])) { // Mark reference to an external scope as used when a value is assigned to it $statements_analyzer->data_flow_graph->addPath($assignment_node, new DataFlowNode('variable-use', 'variable use', null), 'variable-use'); } } } if (isset($context->references_possibly_from_confusing_scope[$var_id])) { IssueBuffer::maybeAdd(new ReferenceReusedFromConfusingScope("{$var_id} is possibly a reference defined at" . " {$context->references_possibly_from_confusing_scope[$var_id]->getShortSummary()}." . " Reusing this variable may cause the referenced value to change.", new CodeLocation($statements_analyzer, $assign_var)), $statements_analyzer->getSuppressedIssues()); } if ($assign_value_type->getId() === 'bool' && ($assign_value instanceof PhpParser\Node\Expr\BinaryOp || $assign_value instanceof PhpParser\Node\Expr\BooleanNot && $assign_value->expr instanceof PhpParser\Node\Expr\BinaryOp)) { $var_object_id = spl_object_id($assign_var); $cond_object_id = spl_object_id($assign_value); $right_clauses = FormulaGenerator::getFormula($cond_object_id, $cond_object_id, $assign_value, $context->self, $statements_analyzer, $codebase); $right_clauses = Context::filterClauses($var_id, $right_clauses); $assignment_clauses = Algebra::combineOredClauses([new Clause([$var_id => ['falsy' => new Falsy()]], $var_object_id, $var_object_id)], $right_clauses, $cond_object_id); $context->clauses = [...$context->clauses, ...$assignment_clauses]; } } } else { $was_inside_general_use = $context->inside_general_use; $context->inside_general_use = \true; if (ExpressionAnalyzer::analyze($statements_analyzer, $assign_var->name, $context) === \false) { $context->inside_general_use = $was_inside_general_use; return; } $context->inside_general_use = $was_inside_general_use; if ($statements_analyzer->data_flow_graph instanceof VariableUseGraph && $assign_value_type->parent_nodes) { foreach ($assign_value_type->parent_nodes as $parent_node) { $statements_analyzer->data_flow_graph->addPath($parent_node, new DataFlowNode('variable-use', 'variable use', null), 'variable-use'); } } } } } inside_call; $context->inside_call = \true; ExpressionAnalyzer::analyze($statements_analyzer, $stmt->expr, $context); $context->inside_call = $was_inside_call; $codebase = $statements_analyzer->getCodebase(); $expr_type = $statements_analyzer->node_data->getType($stmt->expr); if ($expr_type) { if ($statements_analyzer->data_flow_graph instanceof TaintFlowGraph && $expr_type->parent_nodes && !in_array('TaintedInput', $statements_analyzer->getSuppressedIssues())) { $arg_location = new CodeLocation($statements_analyzer->getSource(), $stmt->expr); $eval_param_sink = TaintSink::getForMethodArgument('eval', 'eval', 0, $arg_location, $arg_location); $eval_param_sink->taints = [TaintKind::INPUT_EVAL]; $statements_analyzer->data_flow_graph->addSink($eval_param_sink); $codebase = $statements_analyzer->getCodebase(); $event = new AddRemoveTaintsEvent($stmt, $context, $statements_analyzer, $codebase); $added_taints = $codebase->config->eventDispatcher->dispatchAddTaints($event); $removed_taints = $codebase->config->eventDispatcher->dispatchRemoveTaints($event); foreach ($expr_type->parent_nodes as $parent_node) { $statements_analyzer->data_flow_graph->addPath($parent_node, $eval_param_sink, 'arg', $added_taints, $removed_taints); } } } if (isset($codebase->config->forbidden_functions['eval'])) { IssueBuffer::maybeAdd(new ForbiddenCode('You have forbidden the use of eval', new CodeLocation($statements_analyzer, $stmt)), $statements_analyzer->getSuppressedIssues()); } $context->check_classes = \false; $context->check_variables = \false; } } $args * @param array|null $function_params * @return false|null */ public static function analyze(StatementsAnalyzer $statements_analyzer, array $args, ?array $function_params, ?string $method_id, bool $allow_named_args, Context $context, ?TemplateResult $template_result = null) : ?bool { $last_param = $function_params ? $function_params[count($function_params) - 1] : null; // if this modifies the array type based on further args if (in_array($method_id, ['array_push', 'array_unshift'], \true) && $function_params && isset($args[0]) && isset($args[1])) { if (\Psalm\Internal\Analyzer\Statements\Expression\Call\ArrayFunctionArgumentsAnalyzer::handleAddition($statements_analyzer, $args, $context, $method_id) === \false) { return \false; } return null; } if ($method_id === 'array_splice' && $function_params && count($args) > 1) { if (\Psalm\Internal\Analyzer\Statements\Expression\Call\ArrayFunctionArgumentsAnalyzer::handleSplice($statements_analyzer, $args, $context) === \false) { return \false; } return null; } if ($method_id === 'array_map') { $args = array_reverse($args, \true); } foreach ($args as $argument_offset => $arg) { if ($function_params === null) { if (self::evaluateArbitraryParam($statements_analyzer, $arg, $context) === \false) { return \false; } continue; } $param = null; if ($arg->name && $allow_named_args) { foreach ($function_params as $candidate_param) { if ($candidate_param->name === $arg->name->name) { $param = $candidate_param; break; } } if ($last_param && $last_param->is_variadic) { $param = $last_param; } } elseif ($argument_offset < count($function_params)) { $param = $function_params[$argument_offset]; } elseif ($last_param && $last_param->is_variadic) { $param = $last_param; } $by_ref = $param && $param->by_ref; $by_ref_type = null; if ($by_ref) { $by_ref_type = $param->type ?: Type::getMixed(); } if ($by_ref && $by_ref_type && !($arg->value instanceof PhpParser\Node\Expr\Closure || $arg->value instanceof PhpParser\Node\Expr\ConstFetch || $arg->value instanceof PhpParser\Node\Expr\ClassConstFetch || $arg->value instanceof PhpParser\Node\Expr\FuncCall || $arg->value instanceof PhpParser\Node\Expr\MethodCall || $arg->value instanceof PhpParser\Node\Expr\StaticCall || $arg->value instanceof PhpParser\Node\Expr\New_ || $arg->value instanceof PhpParser\Node\Expr\Assign || $arg->value instanceof PhpParser\Node\Expr\Array_ || $arg->value instanceof PhpParser\Node\Expr\Ternary || $arg->value instanceof PhpParser\Node\Expr\BinaryOp)) { if (self::handleByRefFunctionArg($statements_analyzer, $method_id, $argument_offset, $arg, $context) === \false) { return \false; } continue; } $toggled_class_exists = \false; if (in_array($method_id, ['class_exists', 'interface_exists', 'enum_exists', 'trait_exists'], \true) && $argument_offset === 0 && !$context->inside_class_exists) { $context->inside_class_exists = \true; $toggled_class_exists = \true; } $high_order_template_result = null; $high_order_callable_info = $param ? \Psalm\Internal\Analyzer\Statements\Expression\Call\HighOrderFunctionArgHandler::getCallableArgInfo($context, $arg->value, $statements_analyzer, $param) : null; if ($param && $high_order_callable_info) { $high_order_template_result = \Psalm\Internal\Analyzer\Statements\Expression\Call\HighOrderFunctionArgHandler::remapLowerBounds($statements_analyzer, $template_result ?? new TemplateResult([], []), $high_order_callable_info, $param->type ?? Type::getMixed()); } elseif (($arg->value instanceof PhpParser\Node\Expr\Closure || $arg->value instanceof PhpParser\Node\Expr\ArrowFunction) && $param && !$arg->value->getDocComment()) { self::handleClosureArg($statements_analyzer, $args, $method_id, $context, $template_result ?? new TemplateResult([], []), $argument_offset, $arg, $param); } $was_inside_call = $context->inside_call; $context->inside_call = \true; $was_inside_isset = $context->inside_isset; $context->inside_isset = \false; if (ExpressionAnalyzer::analyze($statements_analyzer, $arg->value, $context, \false, null, \false, $high_order_template_result) === \false) { $context->inside_isset = $was_inside_isset; $context->inside_call = $was_inside_call; return \false; } $context->inside_isset = $was_inside_isset; $context->inside_call = $was_inside_call; if ($high_order_callable_info && $high_order_template_result) { \Psalm\Internal\Analyzer\Statements\Expression\Call\HighOrderFunctionArgHandler::enhanceCallableArgType($context, $arg->value, $statements_analyzer, $high_order_callable_info, $high_order_template_result); } if ($argument_offset === 0 && $method_id === 'array_filter' && count($args) === 2 || $argument_offset > 0 && $method_id === 'array_map' && count($args) >= 2) { self::handleArrayMapFilterArrayArg($statements_analyzer, $method_id, $argument_offset, $arg, $context, $template_result); } $inferred_arg_type = $statements_analyzer->node_data->getType($arg->value); if (null !== $inferred_arg_type && null !== $template_result && null !== $param && null !== $param->type && !$arg->unpack) { $codebase = $statements_analyzer->getCodebase(); TemplateStandinTypeReplacer::fillTemplateResult($param->type, $template_result, $codebase, $statements_analyzer, $inferred_arg_type, $argument_offset, $context->self, $context->calling_method_id ?: $context->calling_function_id); } if ($toggled_class_exists) { $context->inside_class_exists = \false; } } if ($method_id === "ReflectionClass::getattributes" || $method_id === "ReflectionClassConstant::getattributes" || $method_id === "ReflectionFunction::getattributes" || $method_id === "ReflectionMethod::getattributes" || $method_id === "ReflectionParameter::getattributes" || $method_id === "ReflectionProperty::getattributes") { AttributesAnalyzer::analyzeGetAttributes($statements_analyzer, $method_id, array_values($args)); } return null; } private static function handleArrayMapFilterArrayArg(StatementsAnalyzer $statements_analyzer, string $method_id, int $argument_offset, PhpParser\Node\Arg $arg, Context $context, ?TemplateResult &$template_result) : void { $codebase = $statements_analyzer->getCodebase(); $template_types = ['ArrayValue' . $argument_offset => [$method_id => Type::getMixed()]]; $replace_template_result = new TemplateResult($template_types, []); $existing_type = $statements_analyzer->node_data->getType($arg->value); TemplateStandinTypeReplacer::fillTemplateResult(new Union([new TArray([Type::getArrayKey(), new Union([new TTemplateParam('ArrayValue' . $argument_offset, Type::getMixed(), $method_id)])])]), $replace_template_result, $codebase, $statements_analyzer, $existing_type, $argument_offset, $context->self, $context->calling_method_id ?: $context->calling_function_id); if ($replace_template_result->lower_bounds) { if (!$template_result) { $template_result = new TemplateResult([], []); } $template_result->lower_bounds += $replace_template_result->lower_bounds; } } /** * @param array $args */ private static function handleClosureArg(StatementsAnalyzer $statements_analyzer, array $args, ?string $method_id, Context $context, TemplateResult $template_result, int $argument_offset, PhpParser\Node\Arg $arg, FunctionLikeParameter $param) : void { if (!$param->type) { return; } $codebase = $statements_analyzer->getCodebase(); if ($argument_offset === 1 && $method_id === 'array_filter' && count($args) === 2 || $argument_offset === 0 && $method_id === 'array_map' && count($args) >= 2) { $function_like_params = []; foreach ($template_result->lower_bounds as $template_name => $_) { $t = new Union([new TTemplateParam($template_name, Type::getMixed(), $method_id)]); $function_like_params[] = new FunctionLikeParameter('function', \false, $t, $t); } $replaced_type = new Union([new TCallable('callable', array_reverse($function_like_params))]); } else { $replaced_type = $param->type; } $replace_template_result = new TemplateResult(array_map(static fn(array $template_map): array => array_map(static fn(array $lower_bounds): Union => TemplateStandinTypeReplacer::getMostSpecificTypeFromBounds($lower_bounds, $codebase), $template_map), $template_result->lower_bounds), []); $replaced_type = TemplateStandinTypeReplacer::replace($replaced_type, $replace_template_result, $codebase, $statements_analyzer, null, null, null, $context->calling_method_id ?: $context->calling_function_id); $replaced_type = TemplateInferredTypeReplacer::replace($replaced_type, $replace_template_result, $codebase); $closure_id = strtolower($statements_analyzer->getFilePath()) . ':' . $arg->value->getLine() . ':' . (int) $arg->value->getAttribute('startFilePos') . ':-:closure'; try { $closure_storage = $codebase->getClosureStorage($statements_analyzer->getFilePath(), $closure_id); } catch (UnexpectedValueException $e) { return; } foreach ($closure_storage->params as $closure_param_offset => $param_storage) { $param_type_inferred = $param_storage->type_inferred; $newly_inferred_type = null; $has_different_docblock_type = \false; if ($param_storage->type && !$param_type_inferred) { if ($param_storage->type !== $param_storage->signature_type) { $has_different_docblock_type = \true; } } if (!$has_different_docblock_type) { foreach ($replaced_type->getAtomicTypes() as $replaced_type_part) { if ($replaced_type_part instanceof TCallable || $replaced_type_part instanceof TClosure) { if (isset($replaced_type_part->params[$closure_param_offset]->type)) { $replaced_param_type = $replaced_type_part->params[$closure_param_offset]->type; if ($replaced_param_type->hasTemplate()) { $replaced_param_type = TypeExpander::expandUnion($codebase, $replaced_param_type, null, null, null, \true, \false, \false, \true, \true); } if ($param_storage->type && !$param_type_inferred) { $type_match_found = UnionTypeComparator::isContainedBy($codebase, $replaced_param_type, $param_storage->type); if (!$type_match_found) { continue; } } $newly_inferred_type = Type::combineUnionTypes($newly_inferred_type, $replaced_param_type, $codebase); } } } } if ($newly_inferred_type) { $param_storage->type = $newly_inferred_type; $param_storage->type_inferred = \true; } if ($param_storage->type && ($method_id === 'array_map' || $method_id === 'array_filter')) { $temp = Type::getMixed(); ArrayFetchAnalyzer::taintArrayFetch($statements_analyzer, $args[1 - $argument_offset]->value, null, $param_storage->type, $temp); } } } /** * @param list $args * @param string|MethodIdentifier|null $method_id * @param array $function_params * @return false|null * @psalm-suppress ComplexMethod there's just not much that can be done about this */ public static function checkArgumentsMatch(StatementsAnalyzer $statements_analyzer, array $args, $method_id, array $function_params, ?FunctionLikeStorage $function_storage, ?ClassLikeStorage $class_storage, TemplateResult $template_result, CodeLocation $code_location, Context $context) : ?bool { $in_call_map = $method_id ? InternalCallMapHandler::inCallMap((string) $method_id) : \false; $cased_method_id = (string) $method_id; $is_variadic = \false; $fq_class_name = null; $codebase = $statements_analyzer->getCodebase(); if ($method_id) { if ($method_id instanceof MethodIdentifier) { $fq_class_name = $method_id->fq_class_name; } if ($function_storage) { $is_variadic = $function_storage->variadic; } elseif (is_string($method_id)) { $is_variadic = Functions::isVariadic($codebase, strtolower($method_id), $statements_analyzer->getRootFilePath()); } else { $is_variadic = $codebase->methods->isVariadic($method_id); } } if ($method_id instanceof MethodIdentifier) { $cased_method_id = $codebase->methods->getCasedMethodId($method_id); } elseif ($function_storage) { $cased_method_id = $function_storage->cased_name; } $calling_class_storage = $class_storage; $static_fq_class_name = $fq_class_name; $self_fq_class_name = $fq_class_name; if ($method_id instanceof MethodIdentifier) { $declaring_method_id = $codebase->methods->getDeclaringMethodId($method_id); if ($declaring_method_id && (string) $declaring_method_id !== (string) $method_id) { $self_fq_class_name = $declaring_method_id->fq_class_name; $class_storage = $codebase->classlike_storage_provider->get($self_fq_class_name); } $appearing_method_id = $codebase->methods->getAppearingMethodId($method_id); if ($appearing_method_id && $declaring_method_id !== $appearing_method_id) { $self_fq_class_name = $appearing_method_id->fq_class_name; } } if ($function_params && !$is_variadic) { foreach ($function_params as $function_param) { $is_variadic = $is_variadic || $function_param->is_variadic; } } $has_packed_var = \false; foreach ($args as $arg) { if ($arg->unpack) { $has_packed_var = \true; } } $last_param = $function_params ? $function_params[count($function_params) - 1] : null; $class_generic_params = []; foreach ($template_result->lower_bounds as $template_name => $type_map) { foreach ($type_map as $class => $lower_bounds) { if (count($lower_bounds) === 1) { $class_generic_params[$template_name][$class] = reset($lower_bounds)->type; } } } if ($function_storage) { $template_result = self::getProvisionalTemplateResultForFunctionLike($statements_analyzer, $codebase, $context, $class_storage, $self_fq_class_name, $calling_class_storage, $function_storage, $class_generic_params, $template_result, $args, $function_params, $last_param); } $function_param_count = count($function_params); if (count($function_params) > count($args) && !$has_packed_var) { for ($i = count($args), $iMax = count($function_params); $i < $iMax; $i++) { if ($function_params[$i]->default_type && $function_params[$i]->type && $function_params[$i]->type->hasTemplate()) { if ($function_params[$i]->default_type instanceof Union) { $default_type = $function_params[$i]->default_type; } else { $default_type_atomic = ConstantTypeResolver::resolve($codebase->classlikes, $function_params[$i]->default_type, $statements_analyzer); $default_type = new Union([$default_type_atomic]); } if ($default_type->hasLiteralValue()) { \Psalm\Internal\Analyzer\Statements\Expression\Call\ArgumentAnalyzer::checkArgumentMatches($statements_analyzer, $cased_method_id, $method_id instanceof MethodIdentifier ? $method_id : null, $self_fq_class_name, $static_fq_class_name, $code_location, $function_params[$i], $i, $i, $function_storage->allow_named_arg_calls ?? \true, new VirtualArg(StubsGenerator::getExpressionFromType($default_type)), $default_type, $context, $class_generic_params, $template_result, $function_storage->specialize_call ?? \true, $in_call_map); } } } } if (($method_id === 'preg_match_all' || $method_id === 'preg_match') && count($args) > 3) { $args = array_reverse($args, \true); } $arg_function_params = []; $matched_args = []; $named_args_was_used = \false; foreach ($args as $argument_offset => $arg) { if ($named_args_was_used && !$arg->name) { IssueBuffer::maybeAdd(new InvalidNamedArgument('Cannot use positional argument after named argument', new CodeLocation($statements_analyzer, $arg), (string) $method_id), $statements_analyzer->getSuppressedIssues()); } if ($arg->unpack) { if ($function_param_count > $argument_offset) { for ($i = $argument_offset; $i < $function_param_count; $i++) { $arg_function_params[$argument_offset][] = $function_params[$i]; } } if (($arg_value_type = $statements_analyzer->node_data->getType($arg->value)) && $arg_value_type->hasArray()) { /** * @var TArray|TKeyedArray */ $array_type = $arg_value_type->getArray(); if ($array_type instanceof TKeyedArray) { $array_type = $array_type->getGenericArrayType(); $key_types = $array_type->type_params[0]->getAtomicTypes(); foreach ($key_types as $key_type) { if (!$key_type instanceof TLiteralString || $function_storage && !$function_storage->allow_named_arg_calls) { continue; } $param_found = \false; foreach ($function_params as $candidate_param) { if ($candidate_param->name === $key_type->value || $candidate_param->is_variadic) { if ($candidate_param->name === $key_type->value) { if (isset($matched_args[$candidate_param->name])) { IssueBuffer::maybeAdd(new InvalidNamedArgument('Parameter $' . $key_type->value . ' has already been used in ' . ($cased_method_id ?: $method_id), new CodeLocation($statements_analyzer, $arg), (string) $method_id), $statements_analyzer->getSuppressedIssues()); } $matched_args[$candidate_param->name] = \true; } $param_found = \true; break; } } if (!$param_found) { IssueBuffer::maybeAdd(new InvalidNamedArgument('Parameter $' . $key_type->value . ' does not exist on function ' . ($cased_method_id ?: $method_id), new CodeLocation($statements_analyzer, $arg), (string) $method_id), $statements_analyzer->getSuppressedIssues()); } } } } } elseif ($arg->name && (!$function_storage || $function_storage->allow_named_arg_calls)) { $named_args_was_used = \true; foreach ($function_params as $candidate_param) { if ($candidate_param->name === $arg->name->name || $candidate_param->is_variadic) { if ($candidate_param->name === $arg->name->name) { if (isset($matched_args[$candidate_param->name])) { IssueBuffer::maybeAdd(new InvalidNamedArgument('Parameter $' . $arg->name->name . ' has already been used in ' . ($cased_method_id ?: $method_id), new CodeLocation($statements_analyzer, $arg->name), (string) $method_id), $statements_analyzer->getSuppressedIssues()); } $matched_args[$candidate_param->name] = \true; } $arg_function_params[$argument_offset] = [$candidate_param]; break; } } if (!isset($arg_function_params[$argument_offset])) { IssueBuffer::maybeAdd(new InvalidNamedArgument('Parameter $' . $arg->name->name . ' does not exist on function ' . ($cased_method_id ?: $method_id), new CodeLocation($statements_analyzer, $arg->name), (string) $method_id), $statements_analyzer->getSuppressedIssues()); } } elseif ($function_param_count > $argument_offset) { $arg_function_params[$argument_offset] = [$function_params[$argument_offset]]; $matched_args[$function_params[$argument_offset]->name] = \true; } elseif ($last_param && $last_param->is_variadic) { $arg_function_params[$argument_offset] = [$last_param]; $matched_args[$last_param->name] = \true; } } foreach ($args as $argument_offset => $arg) { if (!isset($arg_function_params[$argument_offset])) { continue; } if ($arg_function_params[$argument_offset][0]->by_ref && $method_id !== 'extract') { if (self::handlePossiblyMatchingByRefParam($statements_analyzer, $codebase, (string) $method_id, $cased_method_id, $last_param, $function_params, $argument_offset, $arg, $context, $template_result) === \false) { return null; } } $arg_value_type = $statements_analyzer->node_data->getType($arg->value); foreach ($arg_function_params[$argument_offset] as $i => $function_param) { if (\Psalm\Internal\Analyzer\Statements\Expression\Call\ArgumentAnalyzer::checkArgumentMatches($statements_analyzer, $cased_method_id, $method_id instanceof MethodIdentifier ? $method_id : null, $self_fq_class_name, $static_fq_class_name, $code_location, $function_param, $argument_offset + $i, $i, $function_storage->allow_named_arg_calls ?? \true, $arg, $arg_value_type, $context, $class_generic_params, $template_result, $function_storage->specialize_call ?? \true, $in_call_map) === \false) { return \false; } } } if ($statements_analyzer->data_flow_graph instanceof TaintFlowGraph && $cased_method_id) { foreach ($args as $argument_offset => $_) { if (!isset($arg_function_params[$argument_offset])) { continue; } foreach ($arg_function_params[$argument_offset] as $function_param) { if ($function_param->sinks) { if (!$function_storage || $function_storage->specialize_call) { $sink = TaintSink::getForMethodArgument($cased_method_id, $cased_method_id, $argument_offset, $function_param->location, $code_location); } else { $sink = TaintSink::getForMethodArgument($cased_method_id, $cased_method_id, $argument_offset, $function_param->location); } $sink->taints = $function_param->sinks; $statements_analyzer->data_flow_graph->addSink($sink); } } } } if ($method_id === 'array_map' || $method_id === 'array_filter') { if ($method_id === 'array_map' && count($args) < 2) { IssueBuffer::maybeAdd(new TooFewArguments('Too few arguments for ' . $method_id, $code_location, $method_id), $statements_analyzer->getSuppressedIssues()); } elseif ($method_id === 'array_filter' && count($args) < 1) { IssueBuffer::maybeAdd(new TooFewArguments('Too few arguments for ' . $method_id, $code_location, $method_id), $statements_analyzer->getSuppressedIssues()); } \Psalm\Internal\Analyzer\Statements\Expression\Call\ArrayFunctionArgumentsAnalyzer::checkArgumentsMatch($statements_analyzer, $context, $args, $method_id, $context->check_functions); return null; } if ($method_id === 'get_class' && $args === []) { //get_class without args only works when inside a class if (!$context->self) { IssueBuffer::maybeAdd(new TooFewArguments('Cannot call get_class() without argument outside of class scope', $code_location, $method_id), $statements_analyzer->getSuppressedIssues()); return null; } } self::checkArgCount($statements_analyzer, $codebase, $function_storage, $context, $template_result, $is_variadic, $args, $function_params, $in_call_map, $method_id, $cased_method_id, $code_location); return null; } /** * @param array $function_params * @return false|null */ private static function handlePossiblyMatchingByRefParam(StatementsAnalyzer $statements_analyzer, Codebase $codebase, string $method_id, ?string $cased_method_id, ?FunctionLikeParameter $last_param, array $function_params, int $argument_offset, PhpParser\Node\Arg $arg, Context $context, ?TemplateResult $template_result) : ?bool { if ($arg->value instanceof PhpParser\Node\Scalar || $arg->value instanceof PhpParser\Node\Expr\Cast || $arg->value instanceof PhpParser\Node\Expr\Array_ || $arg->value instanceof PhpParser\Node\Expr\ClassConstFetch || $arg->value instanceof PhpParser\Node\Expr\BinaryOp || $arg->value instanceof PhpParser\Node\Expr\Ternary || ($arg->value instanceof PhpParser\Node\Expr\ConstFetch || $arg->value instanceof PhpParser\Node\Expr\FuncCall || $arg->value instanceof PhpParser\Node\Expr\MethodCall || $arg->value instanceof PhpParser\Node\Expr\StaticCall) && (!($arg_value_type = $statements_analyzer->node_data->getType($arg->value)) || !$arg_value_type->by_ref)) { IssueBuffer::maybeAdd(new InvalidPassByReference('Parameter ' . ($argument_offset + 1) . ' of ' . $cased_method_id . ' expects a variable', new CodeLocation($statements_analyzer->getSource(), $arg->value)), $statements_analyzer->getSuppressedIssues()); return \false; } if (!in_array($method_id, ['ksort', 'asort', 'krsort', 'arsort', 'natcasesort', 'natsort', 'reset', 'end', 'next', 'prev', 'array_pop', 'array_shift', 'array_push', 'array_unshift', 'socket_select', 'array_splice'], \true)) { $by_ref_type = null; $by_ref_out_type = null; $check_null_ref = \true; if ($last_param) { if ($arg->name !== null) { $function_param = array_reduce($function_params, static function (?FunctionLikeParameter $function_param, FunctionLikeParameter $param) use($arg) { if ($param->name === $arg->name->name) { return $param; } return $function_param; }, null); if ($function_param === null) { return \false; } } elseif ($argument_offset < count($function_params)) { $function_param = $function_params[$argument_offset]; } else { $function_param = $last_param; } if ($function_param->type) { $by_ref_type = $function_param->type; } if ($function_param->out_type) { $by_ref_out_type = $function_param->out_type; } if ($by_ref_type && $by_ref_type->isNullable()) { $check_null_ref = \false; } if ($template_result && $by_ref_type) { $original_by_ref_type = $by_ref_type; $by_ref_type = TemplateStandinTypeReplacer::replace($by_ref_type, $template_result, $codebase, $statements_analyzer, $statements_analyzer->node_data->getType($arg->value), $argument_offset, $context->self, $context->calling_method_id ?: $context->calling_function_id); if ($template_result->lower_bounds) { $original_by_ref_type = TemplateInferredTypeReplacer::replace($original_by_ref_type, $template_result, $codebase); $by_ref_type = $original_by_ref_type; } } if ($template_result && $by_ref_out_type) { $original_by_ref_out_type = $by_ref_out_type; $by_ref_out_type = TemplateStandinTypeReplacer::replace($by_ref_out_type, $template_result, $codebase, $statements_analyzer, $statements_analyzer->node_data->getType($arg->value), $argument_offset, $context->self, $context->calling_method_id ?: $context->calling_function_id); if ($template_result->lower_bounds) { $original_by_ref_out_type = TemplateInferredTypeReplacer::replace($original_by_ref_out_type, $template_result, $codebase); $by_ref_out_type = $original_by_ref_out_type; } } if ($by_ref_type && $function_param->is_variadic && $arg->unpack) { $by_ref_type = new Union([new TArray([Type::getInt(), $by_ref_type])]); } } $by_ref_type = $by_ref_type ?: Type::getMixed(); AssignmentAnalyzer::assignByRefParam($statements_analyzer, $arg->value, $by_ref_type, $by_ref_out_type ?: $by_ref_type, $context, $method_id && (strpos($method_id, '::') !== \false || !InternalCallMapHandler::inCallMap($method_id)), $check_null_ref); } return null; } /** * @return false|null */ private static function evaluateArbitraryParam(StatementsAnalyzer $statements_analyzer, PhpParser\Node\Arg $arg, Context $context) : ?bool { // there are a bunch of things we want to evaluate even when we don't // know what function/method is being called if ($arg->value instanceof PhpParser\Node\Expr\Closure || $arg->value instanceof PhpParser\Node\Expr\ConstFetch || $arg->value instanceof PhpParser\Node\Expr\ClassConstFetch || $arg->value instanceof PhpParser\Node\Expr\FuncCall || $arg->value instanceof PhpParser\Node\Expr\MethodCall || $arg->value instanceof PhpParser\Node\Expr\StaticCall || $arg->value instanceof PhpParser\Node\Expr\ArrowFunction || $arg->value instanceof PhpParser\Node\Expr\New_ || $arg->value instanceof PhpParser\Node\Expr\Cast || $arg->value instanceof PhpParser\Node\Expr\Assign || $arg->value instanceof PhpParser\Node\Expr\ArrayDimFetch || $arg->value instanceof PhpParser\Node\Expr\PropertyFetch || $arg->value instanceof PhpParser\Node\Expr\Array_ || $arg->value instanceof PhpParser\Node\Expr\BinaryOp || $arg->value instanceof PhpParser\Node\Expr\Ternary || $arg->value instanceof PhpParser\Node\Scalar\Encapsed || $arg->value instanceof PhpParser\Node\Expr\PostInc || $arg->value instanceof PhpParser\Node\Expr\PostDec || $arg->value instanceof PhpParser\Node\Expr\PreInc || $arg->value instanceof PhpParser\Node\Expr\PreDec) { $was_inside_call = $context->inside_call; $context->inside_call = \true; if (ExpressionAnalyzer::analyze($statements_analyzer, $arg->value, $context) === \false) { $context->inside_call = $was_inside_call; return \false; } $context->inside_call = $was_inside_call; } if ($arg->value instanceof PhpParser\Node\Expr\PropertyFetch && $arg->value->name instanceof PhpParser\Node\Identifier) { $var_id = '$' . $arg->value->name->name; } else { $var_id = ExpressionIdentifier::getVarId($arg->value, $statements_analyzer->getFQCLN(), $statements_analyzer); } if ($var_id) { if ($arg->value instanceof PhpParser\Node\Expr\Variable) { $statements_analyzer->registerPossiblyUndefinedVariable($var_id, $arg->value); } if (!$context->hasVariable($var_id) || $context->vars_in_scope[$var_id]->isNull()) { if (!isset($context->vars_in_scope[$var_id]) && $arg->value instanceof PhpParser\Node\Expr\Variable) { IssueBuffer::maybeAdd(new PossiblyUndefinedVariable('Variable ' . $var_id . ' must be defined prior to use within an unknown function or method', new CodeLocation($statements_analyzer->getSource(), $arg->value)), $statements_analyzer->getSuppressedIssues()); } // we don't know if it exists, assume it's passed by reference $context->vars_in_scope[$var_id] = Type::getMixed(); $context->vars_possibly_in_scope[$var_id] = \true; } else { $was_inside_call = $context->inside_call; $context->inside_call = \true; ExpressionAnalyzer::analyze($statements_analyzer, $arg->value, $context); $context->inside_call = $was_inside_call; $context->removeVarFromConflictingClauses($var_id, $context->vars_in_scope[$var_id], $statements_analyzer); $t = $context->vars_in_scope[$var_id]->getBuilder(); foreach ($t->getAtomicTypes() as $type) { if ($type instanceof TArray && $type->isEmptyArray()) { $t->removeType('array'); $t->addType(new TArray([Type::getArrayKey(), Type::getMixed()])); } } $context->vars_in_scope[$var_id] = $t->freeze(); } } return null; } private static function handleByRefReadonlyArg(StatementsAnalyzer $statements_analyzer, Context $context, PhpParser\Node\Expr\PropertyFetch $stmt, string $fq_class_name, string $prop_name) : void { $property_id = $fq_class_name . '::$' . $prop_name; $codebase = $statements_analyzer->getCodebase(); $declaring_property_class = (string) $codebase->properties->getDeclaringClassForProperty($property_id, \true, $statements_analyzer); try { $declaring_class_storage = $codebase->classlike_storage_provider->get($declaring_property_class); } catch (InvalidArgumentException $_) { return; } if (isset($declaring_class_storage->properties[$prop_name])) { $property_storage = $declaring_class_storage->properties[$prop_name]; InstancePropertyAssignmentAnalyzer::trackPropertyImpurity($statements_analyzer, $stmt, $property_id, $property_storage, $declaring_class_storage, $context); } } /** * @return false|null */ private static function handleByRefFunctionArg(StatementsAnalyzer $statements_analyzer, ?string $method_id, int $argument_offset, PhpParser\Node\Arg $arg, Context $context) : ?bool { $var_id = ExpressionIdentifier::getVarId($arg->value, $statements_analyzer->getFQCLN(), $statements_analyzer); $builtin_array_functions = ['ksort', 'asort', 'krsort', 'arsort', 'natcasesort', 'natsort', 'reset', 'end', 'next', 'prev', 'array_pop', 'array_shift']; if ($arg->value instanceof PhpParser\Node\Expr\PropertyFetch && $arg->value->name instanceof PhpParser\Node\Identifier) { $prop_name = $arg->value->name->name; if (!empty($statements_analyzer->getFQCLN())) { $fq_class_name = $statements_analyzer->getFQCLN(); self::handleByRefReadonlyArg($statements_analyzer, $context, $arg->value, $fq_class_name, $prop_name); } else { // @todo atm only works for simple fetch, $a->foo, not $a->foo->bar // I guess there's a function to do this, but I couldn't locate it $var_id = ExpressionIdentifier::getVarId($arg->value->var, $statements_analyzer->getFQCLN(), $statements_analyzer); if ($var_id && isset($context->vars_in_scope[$var_id])) { foreach ($context->vars_in_scope[$var_id]->getAtomicTypes() as $atomic_type) { if ($atomic_type instanceof TNamedObject) { $fq_class_name = $atomic_type->value; self::handleByRefReadonlyArg($statements_analyzer, $context, $arg->value, $fq_class_name, $prop_name); } } } } } if ($var_id && isset($context->vars_in_scope[$var_id]) || $method_id && in_array($method_id, $builtin_array_functions, \true)) { $was_inside_assignment = $context->inside_assignment; $context->inside_assignment = \true; // if the variable is in scope, get or we're in a special array function, // figure out its type before proceeding if (ExpressionAnalyzer::analyze($statements_analyzer, $arg->value, $context) === \false) { $context->inside_assignment = $was_inside_assignment; return \false; } $context->inside_assignment = $was_inside_assignment; } // special handling for array sort if ($argument_offset === 0 && $method_id && in_array($method_id, $builtin_array_functions, \true)) { if (in_array($method_id, ['array_pop', 'array_shift'], \true)) { \Psalm\Internal\Analyzer\Statements\Expression\Call\ArrayFunctionArgumentsAnalyzer::handleByRefArrayAdjustment($statements_analyzer, $arg, $context, $method_id === 'array_shift'); return null; } // noops if (in_array($method_id, ['reset', 'end', 'next', 'prev', 'ksort'], \true)) { return null; } if (($arg_value_type = $statements_analyzer->node_data->getType($arg->value)) && $arg_value_type->hasArray()) { /** * @var TArray|TKeyedArray */ $array_type = $arg_value_type->getArray(); if ($array_type instanceof TKeyedArray) { $array_type = $array_type->getGenericArrayType(); } $by_ref_type = new Union([$array_type]); AssignmentAnalyzer::assignByRefParam($statements_analyzer, $arg->value, $by_ref_type, $by_ref_type, $context, \false); return null; } } if ($method_id === 'socket_select') { if (ExpressionAnalyzer::analyze($statements_analyzer, $arg->value, $context) === \false) { return \false; } } if (!$arg->value instanceof PhpParser\Node\Expr\Variable) { $suppressed_issues = $statements_analyzer->getSuppressedIssues(); if (!in_array('EmptyArrayAccess', $suppressed_issues, \true)) { $statements_analyzer->addSuppressedIssues(['EmptyArrayAccess']); } if (ExpressionAnalyzer::analyze($statements_analyzer, $arg->value, $context) === \false) { return \false; } if (!in_array('EmptyArrayAccess', $suppressed_issues, \true)) { $statements_analyzer->removeSuppressedIssues(['EmptyArrayAccess']); } } return null; } /** * @param list $args * @param array $function_params * @param array> $class_generic_params */ private static function getProvisionalTemplateResultForFunctionLike(StatementsAnalyzer $statements_analyzer, Codebase $codebase, Context $context, ?ClassLikeStorage $class_storage, ?string $self_fq_class_name, ?ClassLikeStorage $calling_class_storage, FunctionLikeStorage $function_storage, array $class_generic_params, ?TemplateResult $template_result, array $args, array $function_params, ?FunctionLikeParameter $last_param) : ?TemplateResult { $template_types = CallAnalyzer::getTemplateTypesForCall($codebase, $class_storage, $self_fq_class_name, $calling_class_storage, $function_storage->template_types ?: [], $class_generic_params); if (!$template_types) { return null; } if (!$template_result) { return new TemplateResult($template_types, []); } if (!$template_result->template_types) { $template_result->template_types = $template_types; } foreach ($args as $argument_offset => $arg) { $function_param = null; if ($arg->name && $function_storage->allow_named_arg_calls) { foreach ($function_params as $candidate_param) { if ($candidate_param->name === $arg->name->name) { $function_param = $candidate_param; break; } } } elseif ($argument_offset < count($function_params)) { $function_param = $function_params[$argument_offset]; } elseif ($last_param && $last_param->is_variadic) { $function_param = $last_param; } if (!$function_param || !$function_param->type) { continue; } $arg_value_type = $statements_analyzer->node_data->getType($arg->value); if (!$arg_value_type) { continue; } $fleshed_out_param_type = TypeExpander::expandUnion($codebase, $function_param->type, $class_storage->name ?? null, $calling_class_storage->name ?? null, null, \true, \false, $calling_class_storage->final ?? \false); TemplateStandinTypeReplacer::fillTemplateResult($fleshed_out_param_type, $template_result, $codebase, $statements_analyzer, $arg_value_type, $argument_offset, $context->self, $context->calling_method_id ?: $context->calling_function_id, \false); } return $template_result; } /** * @param array $args * @param string|MethodIdentifier|null $method_id * @param array $function_params */ private static function checkArgCount(StatementsAnalyzer $statements_analyzer, Codebase $codebase, ?FunctionLikeStorage $function_storage, Context $context, ?TemplateResult $template_result, bool $is_variadic, array $args, array $function_params, bool $in_call_map, $method_id, ?string $cased_method_id, CodeLocation $code_location) : void { if (!$is_variadic && count($args) > count($function_params) && (!count($function_params) || $function_params[count($function_params) - 1]->name !== '...=') && ($in_call_map || !$function_storage instanceof MethodStorage || $function_storage->is_static || $method_id instanceof MethodIdentifier && $method_id->method_name === '__construct')) { IssueBuffer::maybeAdd(new TooManyArguments('Too many arguments for ' . ($cased_method_id ?: $method_id) . ' - expecting ' . count($function_params) . ' but saw ' . count($args), $code_location, (string) $method_id), $statements_analyzer->getSuppressedIssues()); return; } if (count($args) < count($function_params)) { //we're gonna loop over given args and unset them from the function_params. // If some mandatory params are left at the end, we'll throw an error foreach ($args as $arg) { // when the argument is not named, we can remove the params in order if ($arg->name === null) { // if we're unpacking, we try to unset the exact number of params, if we can't we give up and return if ($arg->unpack) { $arg_value_type = $statements_analyzer->node_data->getType($arg->value); if (!$arg_value_type || !$arg_value_type->hasArray()) { return; } if ($arg_value_type->isSingle() && ($atomic_arg_type = $arg_value_type->getSingleAtomic()) && $atomic_arg_type instanceof TKeyedArray && !$atomic_arg_type->is_list) { //if we have a single shape, we'll check param names foreach ($atomic_arg_type->properties as $property_name => $_property_type) { foreach ($function_params as $k => $param) { if ($param->name === $property_name) { unset($function_params[$k]); } } } continue; } foreach ($arg_value_type->getAtomicTypes() as $atomic_arg_type) { if ($atomic_arg_type instanceof TList) { $atomic_arg_type = $atomic_arg_type->getKeyedArray(); } $packed_var_definite_args_tmp = []; if ($atomic_arg_type instanceof TCallableArray || $atomic_arg_type instanceof TCallableKeyedArray) { $packed_var_definite_args_tmp[] = 2; } elseif ($atomic_arg_type instanceof TKeyedArray) { if ($atomic_arg_type->fallback_params !== null) { return; } if (!$atomic_arg_type->allShapeKeysAlwaysDefined()) { return; } //we did not return. The number of packed params is the number of properties $packed_var_definite_args_tmp[] = count($atomic_arg_type->properties); } elseif ($atomic_arg_type instanceof TNonEmptyArray) { if ($atomic_arg_type->count === null) { return; } $packed_var_definite_args_tmp[] = $atomic_arg_type->count; } elseif ($atomic_arg_type instanceof TArray && $atomic_arg_type->type_params[1]->isNever()) { $packed_var_definite_args_tmp[] = 0; } else { return; } if (min($packed_var_definite_args_tmp) === max($packed_var_definite_args_tmp)) { //we have a stable number of params $packed_var_definite_args = $packed_var_definite_args_tmp[0]; } else { return; } } } else { //if we're not unpacking, we remove the first param $packed_var_definite_args = 1; } $function_params = array_slice($function_params, $packed_var_definite_args); continue; } foreach ($function_params as $k => $param) { if ($param->name === $arg->name->name) { unset($function_params[$k]); continue; } } } //we're now left with an array of params that were not passed. // If they're mandatory, throw an error. Otherwise, we compute the default value foreach ($function_params as $i => $param) { if (!$param->is_optional && !$param->is_variadic) { IssueBuffer::maybeAdd(new TooFewArguments('Too few arguments for ' . $cased_method_id . ' - expecting ' . $param->name . ' to be passed', $code_location, (string) $method_id), $statements_analyzer->getSuppressedIssues()); continue; } if ($param->type && $param->default_type && !$param->is_variadic && $template_result) { if ($param->default_type instanceof Union) { $default_type = $param->default_type; } else { $default_type_atomic = ConstantTypeResolver::resolve($codebase->classlikes, $param->default_type, $statements_analyzer); $default_type = new Union([$default_type_atomic]); } TemplateStandinTypeReplacer::fillTemplateResult($param->type, $template_result, $codebase, $statements_analyzer, $default_type, $i, $context->self, $context->calling_method_id ?: $context->calling_function_id, \true); } } } } } inside_call; $context->inside_call = \true; $existing_stmt_var_type = null; if (!$real_method_call) { $existing_stmt_var_type = $statements_analyzer->node_data->getType($stmt->var); } if ($existing_stmt_var_type) { $statements_analyzer->node_data->setType($stmt->var, $existing_stmt_var_type); } elseif (ExpressionAnalyzer::analyze($statements_analyzer, $stmt->var, $context) === \false) { $context->inside_call = $was_inside_call; return \false; } if (!$stmt->name instanceof PhpParser\Node\Identifier) { $context->inside_call = \true; if (ExpressionAnalyzer::analyze($statements_analyzer, $stmt->name, $context) === \false) { $context->inside_call = $was_inside_call; return \false; } } $context->inside_call = $was_inside_call; if ($stmt->var instanceof PhpParser\Node\Expr\Variable) { if (is_string($stmt->var->name) && $stmt->var->name === 'this' && !$statements_analyzer->getFQCLN()) { if (IssueBuffer::accepts(new InvalidScope('Use of $this in non-class context', new CodeLocation($statements_analyzer->getSource(), $stmt)), $statements_analyzer->getSuppressedIssues())) { return \false; } } if ($stmt->name instanceof PhpParser\Node\Identifier && strtolower($stmt->name->name) === '__construct') { IssueBuffer::maybeAdd(new DirectConstructorCall('Constructors should not be called directly', new CodeLocation($statements_analyzer->getSource(), $stmt)), $statements_analyzer->getSuppressedIssues()); } } $lhs_var_id = ExpressionIdentifier::getExtendedVarId($stmt->var, $statements_analyzer->getFQCLN(), $statements_analyzer); $class_type = $lhs_var_id && $context->hasVariable($lhs_var_id) ? $context->vars_in_scope[$lhs_var_id] : null; if ($stmt_var_type = $statements_analyzer->node_data->getType($stmt->var)) { $class_type = $stmt_var_type; } elseif (!$class_type) { $statements_analyzer->node_data->setType($stmt, Type::getMixed()); } if ($class_type && $stmt->name instanceof PhpParser\Node\Identifier && ($class_type->isNull() || $class_type->isVoid())) { return !IssueBuffer::accepts(new NullReference('Cannot call method ' . $stmt->name->name . ' on null value', new CodeLocation($statements_analyzer->getSource(), $stmt->name)), $statements_analyzer->getSuppressedIssues()); } if ($class_type && $stmt->name instanceof PhpParser\Node\Identifier && $class_type->isNullable() && !$class_type->ignore_nullable_issues && !($stmt->name->name === 'offsetGet' && $context->inside_isset) && !self::hasNullsafe($stmt->var)) { IssueBuffer::maybeAdd(new PossiblyNullReference('Cannot call method ' . $stmt->name->name . ' on possibly null value', new CodeLocation($statements_analyzer->getSource(), $stmt->name)), $statements_analyzer->getSuppressedIssues()); } if ($class_type && $stmt->name instanceof PhpParser\Node\Identifier && $class_type->isFalsable() && !$class_type->ignore_falsable_issues) { IssueBuffer::maybeAdd(new PossiblyFalseReference('Cannot call method ' . $stmt->name->name . ' on possibly false value', new CodeLocation($statements_analyzer->getSource(), $stmt->name)), $statements_analyzer->getSuppressedIssues()); } $codebase = $statements_analyzer->getCodebase(); $source = $statements_analyzer->getSource(); if (!$class_type) { $class_type = Type::getMixed(); } $lhs_types = $class_type->getAtomicTypes(); foreach ($lhs_types as $k => $lhs_type_part) { if ($lhs_type_part instanceof TConditional) { $lhs_types = array_merge($lhs_types, $lhs_type_part->if_type->getAtomicTypes(), $lhs_type_part->else_type->getAtomicTypes()); unset($lhs_types[$k]); } } $result = new AtomicMethodCallAnalysisResult(); $possible_new_class_types = []; foreach ($lhs_types as $lhs_type_part) { AtomicMethodCallAnalyzer::analyze($statements_analyzer, $stmt, $codebase, $context, $class_type, $lhs_type_part, $lhs_type_part instanceof TNamedObject || $lhs_type_part instanceof TTemplateParam ? $lhs_type_part : null, \false, $lhs_var_id, $result, $template_result); if (isset($context->vars_in_scope[$lhs_var_id]) && ($possible_new_class_type = $context->vars_in_scope[$lhs_var_id]) instanceof Union && !$possible_new_class_type->equals($class_type)) { $possible_new_class_types[] = $context->vars_in_scope[$lhs_var_id]; } } if (!$stmt->isFirstClassCallable() && !$stmt->getArgs() && $lhs_var_id && $stmt->name instanceof PhpParser\Node\Identifier) { if ($codebase->config->memoize_method_calls || $result->can_memoize) { $method_var_id = $lhs_var_id . '->' . strtolower($stmt->name->name) . '()'; if (isset($context->vars_in_scope[$method_var_id])) { $result->return_type = $context->vars_in_scope[$method_var_id]; } elseif ($result->return_type !== null) { $context->vars_in_scope[$method_var_id] = $result->return_type->setProperties(['has_mutations' => \false]); } if ($result->can_memoize) { $stmt->setAttribute('memoizable', \true); } } } if (count($possible_new_class_types) > 0) { $class_type = array_reduce($possible_new_class_types, static fn(?Union $type_1, Union $type_2): Union => Type::combineUnionTypes($type_1, $type_2, $codebase)); } if ($result->invalid_method_call_types) { $invalid_class_type = $result->invalid_method_call_types[0]; if ($result->has_valid_method_call_type || $result->has_mixed_method_call) { IssueBuffer::maybeAdd(new PossiblyInvalidMethodCall('Cannot call method on possible ' . $invalid_class_type . ' variable ' . $lhs_var_id, new CodeLocation($source, $stmt->name)), $statements_analyzer->getSuppressedIssues()); } else { IssueBuffer::maybeAdd(new InvalidMethodCall('Cannot call method on ' . $invalid_class_type . ' variable ' . $lhs_var_id, new CodeLocation($source, $stmt->name)), $statements_analyzer->getSuppressedIssues()); } } if ($result->non_existent_magic_method_ids) { if ($context->check_methods) { IssueBuffer::maybeAdd(new UndefinedMagicMethod('Magic method ' . $result->non_existent_magic_method_ids[0] . ' does not exist', new CodeLocation($source, $stmt->name), $result->non_existent_magic_method_ids[0]), $statements_analyzer->getSuppressedIssues()); } } if ($result->non_existent_class_method_ids) { if ($context->check_methods) { if ($result->existent_method_ids || $result->has_mixed_method_call) { IssueBuffer::maybeAdd(new PossiblyUndefinedMethod('Method ' . $result->non_existent_class_method_ids[0] . ' does not exist', new CodeLocation($source, $stmt->name), $result->non_existent_class_method_ids[0]), $statements_analyzer->getSuppressedIssues()); } else { IssueBuffer::maybeAdd(new UndefinedMethod('Method ' . $result->non_existent_class_method_ids[0] . ' does not exist', new CodeLocation($source, $stmt->name), $result->non_existent_class_method_ids[0]), $statements_analyzer->getSuppressedIssues()); } } return \true; } if ($result->non_existent_interface_method_ids) { if ($context->check_methods) { if ($result->existent_method_ids || $result->has_mixed_method_call) { IssueBuffer::maybeAdd(new PossiblyUndefinedMethod('Method ' . $result->non_existent_interface_method_ids[0] . ' does not exist', new CodeLocation($source, $stmt->name), $result->non_existent_interface_method_ids[0]), $statements_analyzer->getSuppressedIssues()); } else { IssueBuffer::maybeAdd(new UndefinedInterfaceMethod('Method ' . $result->non_existent_interface_method_ids[0] . ' does not exist', new CodeLocation($source, $stmt->name), $result->non_existent_interface_method_ids[0]), $statements_analyzer->getSuppressedIssues()); } } return \true; } if ($result->too_many_arguments && $result->too_many_arguments_method_ids) { $error_method_id = $result->too_many_arguments_method_ids[0]; IssueBuffer::maybeAdd(new TooManyArguments('Too many arguments for method ' . $error_method_id . ' - saw ' . count($stmt->getArgs()), new CodeLocation($source, $stmt->name), (string) $error_method_id), $statements_analyzer->getSuppressedIssues()); } if ($result->too_few_arguments && $result->too_few_arguments_method_ids) { $error_method_id = $result->too_few_arguments_method_ids[0]; IssueBuffer::maybeAdd(new TooFewArguments('Too few arguments for method ' . $error_method_id . ' saw ' . count($stmt->getArgs()), new CodeLocation($source, $stmt->name), (string) $error_method_id), $statements_analyzer->getSuppressedIssues()); } $stmt_type = $result->return_type; if ($stmt_type) { $statements_analyzer->node_data->setType($stmt, $stmt_type); if ($stmt_type->isNever()) { $context->has_returned = \true; } } if ($result->returns_by_ref) { if (!$stmt_type) { $stmt_type = Type::getMixed(); $statements_analyzer->node_data->setType($stmt, $stmt_type); } $stmt_type = $stmt_type->setByRef($result->returns_by_ref); } if ($codebase->store_node_types && !$context->collect_initializations && !$context->collect_mutations && $stmt_type) { $codebase->analyzer->addNodeType($statements_analyzer->getFilePath(), $stmt->name, $stmt_type->getId(), $stmt); } if (!$result->existent_method_ids) { return $stmt->isFirstClassCallable() || self::checkMethodArgs(null, $stmt->getArgs(), new TemplateResult([], []), $context, new CodeLocation($statements_analyzer->getSource(), $stmt), $statements_analyzer); } // if we called a method on this nullable variable, remove the nullable status here // because any further calls must have worked if ($lhs_var_id && !$class_type->isMixed() && $result->has_valid_method_call_type && !$result->has_mixed_method_call && !$result->invalid_method_call_types && ($class_type->from_docblock || $class_type->isNullable()) && $real_method_call) { $types = $class_type->getAtomicTypes(); foreach ($types as $key => &$type) { if (!$type instanceof TNamedObject && !$type instanceof TObject && !$type instanceof TConditional) { unset($types[$key]); } else { $type = $type->setFromDocblock(\false); } } if (!$types) { throw new AssertionError("We must have some types here!"); } $context->removeVarFromConflictingClauses($lhs_var_id, null, $statements_analyzer); $class_type = $class_type->getBuilder()->setTypes($types); $class_type->from_docblock = \false; $context->vars_in_scope[$lhs_var_id] = $class_type->freeze(); } return \true; } public static function hasNullsafe(PhpParser\Node\Expr $expr) : bool { if ($expr instanceof PhpParser\Node\Expr\MethodCall || $expr instanceof PhpParser\Node\Expr\PropertyFetch) { return self::hasNullsafe($expr->var); } return $expr instanceof PhpParser\Node\Expr\NullsafeMethodCall || $expr instanceof PhpParser\Node\Expr\NullsafePropertyFetch; } } */ public array $defined_constants = []; /** * @var array */ public array $global_variables = []; /** * @var ?array */ public ?array $function_params = null; public ?FunctionLikeStorage $function_storage = null; public ?PhpParser\Node\Name $new_function_name = null; public bool $allow_named_args = \true; public array $byref_uses = []; /** * @mutation-free */ public function hasByReferenceParameters() : bool { if (null === $this->function_params) { return \false; } foreach ($this->function_params as $value) { if ($value->by_ref) { return \true; } } return \false; } } file_provider->getContents($statements_analyzer->getFilePath()); // Find opening paren $first_argument = $stmt->getArgs()[0] ?? null; $first_argument_character = $first_argument !== null ? $first_argument->getStartFilePos() : $stmt->getEndFilePos(); $method_name_and_first_paren_source_code_length = $first_argument_character - $stmt->getStartFilePos(); // FIXME: There are weird ::__construct calls in the AST for `extends` if ($method_name_and_first_paren_source_code_length <= 0) { return; } $method_name_and_first_paren_source_code = substr($file_content, $stmt->getStartFilePos(), $method_name_and_first_paren_source_code_length); $method_name_and_first_paren_tokens = token_get_all('getStartFilePos()) { return; } // Record ranges of the source code that need to be tokenized to find commas /** @var array{0: int, 1: int}[] $ranges */ $ranges = []; // Add range between opening paren and first argument $first_argument = $stmt->getArgs()[0] ?? null; $first_argument_starting_position = $first_argument !== null ? $first_argument->getStartFilePos() : $stmt->getEndFilePos(); $first_range_starting_position = $opening_paren_position + 1; if ($first_range_starting_position !== $first_argument_starting_position) { $ranges[] = [$first_range_starting_position, $first_argument_starting_position]; } // Add range between arguments foreach ($stmt->getArgs() as $i => $argument) { $range_start = $argument->getEndFilePos() + 1; $next_argument = $stmt->getArgs()[$i + 1] ?? null; $range_end = $next_argument !== null ? $next_argument->getStartFilePos() : $stmt->getEndFilePos(); if ($range_start !== $range_end) { $ranges[] = [$range_start, $range_end]; } } $commas = []; foreach ($ranges as $range) { $position = $range[0]; $length = $range[1] - $position; if ($length > 0) { $range_source_code = substr($file_content, $position, $length); $range_tokens = token_get_all('analyzer->addNodeArgument($statements_analyzer->getFilePath(), $argument_start_position, $comma, $function_reference, $argument_number); ++$argument_number; $argument_start_position = $comma + 1; } $codebase->analyzer->addNodeArgument($statements_analyzer->getFilePath(), $argument_start_position, $stmt->getEndFilePos(), $function_reference, $argument_number); } } >|null * @psalm-suppress MoreSpecificReturnType * @psalm-suppress LessSpecificReturnStatement */ public static function collect(Codebase $codebase, ClassLikeStorage $class_storage, ClassLikeStorage $static_class_storage, ?string $method_name = null, ?Atomic $lhs_type_part = null, bool $self_call = \false) : ?array { $non_trait_class_storage = $class_storage->is_trait ? $static_class_storage : $class_storage; $template_types = $class_storage->template_types; $candidate_class_storages = [$class_storage]; if ($static_class_storage->template_extended_params && $method_name && !empty($non_trait_class_storage->overridden_method_ids[$method_name])) { foreach ($non_trait_class_storage->overridden_method_ids[$method_name] as $overridden_method_id) { $overridden_storage = $codebase->methods->getStorage($overridden_method_id); if (!$overridden_storage->return_type) { continue; } if ($overridden_storage->return_type->isNull()) { continue; } $fq_overridden_class = $overridden_method_id->fq_class_name; $overridden_class_storage = $codebase->classlike_storage_provider->get($fq_overridden_class); $overridden_template_types = $overridden_class_storage->template_types; if (!$template_types) { $template_types = $overridden_template_types; } elseif ($overridden_template_types) { foreach ($overridden_template_types as $template_name => $template_map) { if (isset($template_types[$template_name])) { $template_types[$template_name] = array_merge($template_types[$template_name], $template_map); } else { $template_types[$template_name] = $template_map; } } } $candidate_class_storages[] = $overridden_class_storage; } } if (!$template_types) { return null; } $class_template_params = []; $e = $static_class_storage->template_extended_params; if ($lhs_type_part instanceof TGenericObject) { if ($class_storage === $static_class_storage && $class_storage->template_types) { $i = 0; foreach ($class_storage->template_types as $type_name => $_) { if (isset($lhs_type_part->type_params[$i])) { $class_template_params[$type_name][$class_storage->name] = $lhs_type_part->type_params[$i]; } $i++; } } $template_result = null; if ($class_storage !== $static_class_storage && $static_class_storage->template_types) { $templates = self::collect($codebase, $static_class_storage, $static_class_storage, null, $lhs_type_part); if ($templates === null) { throw new AssertionError("Could not collect templates!"); } $template_result = new TemplateResult($static_class_storage->template_types, $templates); } foreach ($template_types as $type_name => $_) { if (isset($class_template_params[$type_name])) { continue; } if ($class_storage !== $static_class_storage && isset($e[$class_storage->name][$type_name])) { $input_type_extends = $e[$class_storage->name][$type_name]; $output_type_extends = self::resolveTemplateParam($codebase, $input_type_extends, $static_class_storage, $lhs_type_part, $template_result); $class_template_params[$type_name] = [$class_storage->name => $output_type_extends ?? Type::getMixed()]; } else { $class_template_params[$type_name] = [$class_storage->name => Type::getMixed()]; } } } foreach ($template_types as $type_name => $type_map) { foreach ($type_map as $type) { foreach ($candidate_class_storages as $candidate_class_storage) { if ($candidate_class_storage !== $static_class_storage && isset($e[$candidate_class_storage->name][$type_name]) && !isset($class_template_params[$type_name][$candidate_class_storage->name])) { $class_template_params[$type_name][$candidate_class_storage->name] = new Union(self::expandType($codebase, $e[$candidate_class_storage->name][$type_name], $e, $static_class_storage->name, $static_class_storage->template_types)); } } if (!$self_call) { if (!isset($class_template_params[$type_name])) { $class_template_params[$type_name][$class_storage->name] = $type; } } } } return $class_template_params; } private static function resolveTemplateParam(Codebase $codebase, Union $input_type_extends, ClassLikeStorage $static_class_storage, TGenericObject $lhs_type_part, ?TemplateResult $template_result = null) : ?Union { $output_type_extends = null; foreach ($input_type_extends->getAtomicTypes() as $type_extends_atomic) { if ($type_extends_atomic instanceof TTemplateParam) { if (isset($static_class_storage->template_types[$type_extends_atomic->param_name][$type_extends_atomic->defining_class])) { $mapped_offset = array_search($type_extends_atomic->param_name, array_keys($static_class_storage->template_types), \true); if ($mapped_offset !== \false && isset($lhs_type_part->type_params[$mapped_offset])) { $output_type_extends = Type::combineUnionTypes($lhs_type_part->type_params[$mapped_offset], $output_type_extends); } } elseif (isset($static_class_storage->template_extended_params[$type_extends_atomic->defining_class][$type_extends_atomic->param_name])) { $nested_output_type = self::resolveTemplateParam($codebase, $static_class_storage->template_extended_params[$type_extends_atomic->defining_class][$type_extends_atomic->param_name], $static_class_storage, $lhs_type_part, $template_result); if ($nested_output_type !== null) { $output_type_extends = Type::combineUnionTypes($nested_output_type, $output_type_extends); } } } else { if ($template_result !== null) { $type_extends_atomic = $type_extends_atomic->replaceTemplateTypesWithArgTypes($template_result, $codebase); } $output_type_extends = Type::combineUnionTypes(new Union([$type_extends_atomic]), $output_type_extends); } } return $output_type_extends; } /** * @param array> $e * @return non-empty-list */ private static function expandType(Codebase $codebase, Union $input_type_extends, array $e, string $static_fq_class_name, ?array $static_template_types) : array { $output_type_extends = []; foreach ($input_type_extends->getAtomicTypes() as $type_extends_atomic) { if ($type_extends_atomic instanceof TTemplateParam && ($static_fq_class_name !== $type_extends_atomic->defining_class || !isset($static_template_types[$type_extends_atomic->param_name])) && isset($e[$type_extends_atomic->defining_class][$type_extends_atomic->param_name])) { $output_type_extends = [...$output_type_extends, ...self::expandType($codebase, $e[$type_extends_atomic->defining_class][$type_extends_atomic->param_name], $e, $static_fq_class_name, $static_template_types)]; } elseif ($type_extends_atomic instanceof TClassConstant) { $expanded = TypeExpander::expandAtomic($codebase, $type_extends_atomic, $type_extends_atomic->fq_classlike_name, $type_extends_atomic->fq_classlike_name, null, \true, \true); foreach ($expanded as $type) { $output_type_extends[] = $type; } } else { $output_type_extends[] = $type_extends_atomic; } } return $output_type_extends; } } getCodebase(); $source = $statements_analyzer->getSource(); $config = $codebase->config; if ($stmt->class instanceof PhpParser\Node\Name) { if (count($stmt->class->getParts()) === 1 && in_array(strtolower($stmt->class->getFirst()), ['self', 'static', 'parent'], \true)) { if ($stmt->class->getFirst() === 'parent') { $child_fq_class_name = $context->self; $class_storage = $child_fq_class_name ? $codebase->classlike_storage_provider->get($child_fq_class_name) : null; if (!$class_storage || !$class_storage->parent_class) { return !IssueBuffer::accepts(new ParentNotFound('Cannot call method on parent as this class does not extend another', new CodeLocation($statements_analyzer->getSource(), $stmt)), $statements_analyzer->getSuppressedIssues()); } $fq_class_name = $class_storage->parent_class; $fq_class_name = $codebase->classlikes->getUnAliasedName($fq_class_name); $class_storage = $codebase->classlike_storage_provider->get($fq_class_name); $fq_class_name = $class_storage->name; if ($context->collect_initializations && isset($stmt->name->name) && $stmt->name->name === '__construct' && isset($class_storage->declaring_method_ids['__construct'])) { $construct_fq_class_name = $class_storage->declaring_method_ids['__construct']->fq_class_name; $construct_class_storage = $codebase->classlike_storage_provider->get($construct_fq_class_name); $construct_fq_class_name = $construct_class_storage->name; foreach ($construct_class_storage->properties as $property_name => $property_storage) { if ($property_storage->is_promoted && isset($context->vars_in_scope['$this->' . $property_name])) { $context_type = $context->vars_in_scope['$this->' . $property_name]; $context->vars_in_scope['$this->' . $property_name] = $context_type->setProperties(['initialized_class' => $construct_fq_class_name, 'initialized' => \true]); } } } } elseif ($context->self) { if ($stmt->class->getFirst() === 'static' && isset($context->vars_in_scope['$this'])) { $fq_class_name = (string) $context->vars_in_scope['$this']; $lhs_type = $context->vars_in_scope['$this']; } else { $fq_class_name = $context->self; } } else { return !IssueBuffer::accepts(new NonStaticSelfCall('Cannot use ' . $stmt->class->getFirst() . ' outside class context', new CodeLocation($statements_analyzer->getSource(), $stmt)), $statements_analyzer->getSuppressedIssues()); } if ($context->isPhantomClass($fq_class_name)) { return \true; } } else { $aliases = $statements_analyzer->getAliases(); if ($context->calling_method_id && !$stmt->class instanceof PhpParser\Node\Name\FullyQualified) { $codebase->file_reference_provider->addMethodReferenceToClassMember($context->calling_method_id, 'use:' . $stmt->class->getFirst() . ':' . md5($statements_analyzer->getFilePath()), \false); } $fq_class_name = ClassLikeAnalyzer::getFQCLNFromNameObject($stmt->class, $aliases); if ($context->isPhantomClass($fq_class_name)) { return \true; } $does_class_exist = \false; if ($context->self) { $self_storage = $codebase->classlike_storage_provider->get($context->self); if (isset($self_storage->used_traits[strtolower($fq_class_name)])) { $fq_class_name = $context->self; $does_class_exist = \true; } } if (!isset($context->phantom_classes[strtolower($fq_class_name)]) && !$does_class_exist) { $does_class_exist = ClassLikeAnalyzer::checkFullyQualifiedClassLikeName($statements_analyzer, $fq_class_name, new CodeLocation($source, $stmt->class), !$context->collect_initializations && !$context->collect_mutations ? $context->self : null, !$context->collect_initializations && !$context->collect_mutations ? $context->calling_method_id : null, $statements_analyzer->getSuppressedIssues(), new ClassLikeNameOptions(\false, \false, \false, \true), $context->check_classes); } if (!$does_class_exist) { return $does_class_exist !== \false; } } if ($codebase->store_node_types && $fq_class_name && !$context->collect_initializations && !$context->collect_mutations) { $codebase->analyzer->addNodeReference($statements_analyzer->getFilePath(), $stmt->class, $fq_class_name); } if ($fq_class_name && !$lhs_type) { $lhs_type = new Union([new TNamedObject($fq_class_name)]); } } else { $was_inside_general_use = $context->inside_general_use; $context->inside_general_use = \true; ExpressionAnalyzer::analyze($statements_analyzer, $stmt->class, $context); $context->inside_general_use = $was_inside_general_use; $lhs_type = $statements_analyzer->node_data->getType($stmt->class) ?? Type::getMixed(); } if (!$lhs_type) { if (\Psalm\Internal\Analyzer\Statements\Expression\Call\ArgumentsAnalyzer::analyze($statements_analyzer, $stmt->getArgs(), null, null, \true, $context) === \false) { return \false; } return \true; } $has_mock = \false; $moved_call = \false; $has_existing_method = \false; foreach ($lhs_type->getAtomicTypes() as $lhs_type_part) { AtomicStaticCallAnalyzer::analyze($statements_analyzer, $stmt, $context, $lhs_type_part, $lhs_type->ignore_nullable_issues, $moved_call, $has_mock, $has_existing_method, $template_result); } if (!$stmt->isFirstClassCallable() && !$has_existing_method) { return self::checkMethodArgs($method_id, $stmt->getArgs(), new TemplateResult([], []), $context, new CodeLocation($statements_analyzer->getSource(), $stmt), $statements_analyzer); } if (!$config->remember_property_assignments_after_call && !$context->collect_initializations) { $context->removeMutableObjectVars(); } if (!$statements_analyzer->node_data->getType($stmt)) { $statements_analyzer->node_data->setType($stmt, Type::getMixed()); } return \true; } public static function taintReturnType(StatementsAnalyzer $statements_analyzer, PhpParser\Node\Expr\StaticCall $stmt, MethodIdentifier $method_id, string $cased_method_id, Union &$return_type_candidate, ?MethodStorage $method_storage, ?TemplateResult $template_result, ?Context $context = null) : void { if (!$statements_analyzer->data_flow_graph) { return; } if ($statements_analyzer->data_flow_graph instanceof TaintFlowGraph && in_array('TaintedInput', $statements_analyzer->getSuppressedIssues())) { return; } $node_location = new CodeLocation($statements_analyzer->getSource(), $stmt); $method_location = $method_storage ? $statements_analyzer->data_flow_graph instanceof TaintFlowGraph ? $method_storage->signature_return_type_location ?: $method_storage->location : ($method_storage->return_type_location ?: $method_storage->location) : null; if ($method_storage && $method_storage->specialize_call) { $method_source = DataFlowNode::getForMethodReturn((string) $method_id, $cased_method_id, $method_location, $node_location); } else { $method_source = DataFlowNode::getForMethodReturn((string) $method_id, $cased_method_id, $method_location); } $statements_analyzer->data_flow_graph->addNode($method_source); $codebase = $statements_analyzer->getCodebase(); $conditionally_removed_taints = []; if ($method_storage && $template_result) { foreach ($method_storage->conditionally_removed_taints as $conditionally_removed_taint) { $conditionally_removed_taint = TemplateInferredTypeReplacer::replace($conditionally_removed_taint, $template_result, $codebase); $expanded_type = TypeExpander::expandUnion($statements_analyzer->getCodebase(), $conditionally_removed_taint, null, null, null, \true, \true); foreach ($expanded_type->getLiteralStrings() as $literal_string) { $conditionally_removed_taints[] = $literal_string->value; } } } $added_taints = []; $removed_taints = []; if ($context) { $event = new AddRemoveTaintsEvent($stmt, $context, $statements_analyzer, $codebase); $added_taints = $codebase->config->eventDispatcher->dispatchAddTaints($event); $removed_taints = $codebase->config->eventDispatcher->dispatchRemoveTaints($event); } if ($conditionally_removed_taints && $method_location) { $assignment_node = DataFlowNode::getForAssignment($method_id . '-escaped', $method_location, $method_source->specialization_key); $statements_analyzer->data_flow_graph->addPath($method_source, $assignment_node, 'conditionally-escaped', $added_taints, [...$conditionally_removed_taints, ...$removed_taints]); $return_type_candidate = $return_type_candidate->addParentNodes([$assignment_node->id => $assignment_node]); } else { $return_type_candidate = $return_type_candidate->setParentNodes([$method_source->id => $method_source]); } if ($method_storage && $method_storage->taint_source_types && $statements_analyzer->data_flow_graph instanceof TaintFlowGraph) { $method_node = TaintSource::getForMethodReturn((string) $method_id, $cased_method_id, $method_storage->signature_return_type_location ?: $method_storage->location); $method_node->taints = $method_storage->taint_source_types; $statements_analyzer->data_flow_graph->addSource($method_node); } if ($method_storage && $statements_analyzer->data_flow_graph instanceof TaintFlowGraph) { \Psalm\Internal\Analyzer\Statements\Expression\Call\FunctionCallReturnTypeFetcher::taintUsingFlows($statements_analyzer, $method_storage, $statements_analyzer->data_flow_graph, (string) $method_id, $stmt->getArgs(), $node_location, $method_source, array_merge($method_storage->removed_taints, $removed_taints), $added_taints); } } } getCodebase(); $config = $codebase->config; $can_extend = \false; $from_static = \false; if ($stmt->isFirstClassCallable()) { IssueBuffer::maybeAdd(new ParseError('First-class callables cannot be used in new', new CodeLocation($statements_analyzer->getSource(), $stmt))); return \false; } if ($stmt->class instanceof PhpParser\Node\Name) { if (!in_array(strtolower($stmt->class->getFirst()), ['self', 'static', 'parent'], \true)) { $aliases = $statements_analyzer->getAliases(); if ($context->calling_method_id && !$stmt->class instanceof PhpParser\Node\Name\FullyQualified) { $codebase->file_reference_provider->addMethodReferenceToClassMember($context->calling_method_id, 'use:' . $stmt->class->getFirst() . ':' . md5($statements_analyzer->getFilePath()), \false); } $fq_class_name = ClassLikeAnalyzer::getFQCLNFromNameObject($stmt->class, $aliases); $fq_class_name = $codebase->classlikes->getUnAliasedName($fq_class_name); } elseif ($context->self !== null) { switch ($stmt->class->getFirst()) { case 'self': $class_storage = $codebase->classlike_storage_provider->get($context->self); $fq_class_name = $class_storage->name; break; case 'parent': $fq_class_name = $context->parent; break; case 'static': // @todo maybe we can do better here $class_storage = $codebase->classlike_storage_provider->get($context->self); $fq_class_name = $class_storage->name; if (!$class_storage->final) { $can_extend = \true; $from_static = \true; } break; } } if ($codebase->store_node_types && $fq_class_name && !$context->collect_initializations && !$context->collect_mutations) { $codebase->analyzer->addNodeReference($statements_analyzer->getFilePath(), $stmt->class, $codebase->classlikes->classExists($fq_class_name) ? $fq_class_name : '*' . ($stmt->class instanceof PhpParser\Node\Name\FullyQualified ? '\\' : $statements_analyzer->getNamespace() . '-') . $stmt->class->toString()); } } elseif ($stmt->class instanceof PhpParser\Node\Stmt\Class_) { $statements_analyzer->analyze([$stmt->class], $context); $fq_class_name = ClassAnalyzer::getAnonymousClassName($stmt->class, $statements_analyzer->getAliases(), $statements_analyzer->getFilePath()); } else { self::analyzeConstructorExpression($statements_analyzer, $codebase, $context, $stmt, $stmt->class, $config, $fq_class_name, $can_extend); } if ($fq_class_name) { if ($codebase->alter_code && $stmt->class instanceof PhpParser\Node\Name && !in_array($stmt->class->getFirst(), ['parent', 'static'])) { $codebase->classlikes->handleClassLikeReferenceInMigration($codebase, $statements_analyzer, $stmt->class, $fq_class_name, $context->calling_method_id); } if ($context->check_classes) { if ($context->isPhantomClass($fq_class_name)) { \Psalm\Internal\Analyzer\Statements\Expression\Call\ArgumentsAnalyzer::analyze($statements_analyzer, $stmt->getArgs(), null, null, \true, $context); return \true; } if (ClassLikeAnalyzer::checkFullyQualifiedClassLikeName($statements_analyzer, $fq_class_name, new CodeLocation($statements_analyzer->getSource(), $stmt->class), $context->self, $context->calling_method_id, $statements_analyzer->getSuppressedIssues()) === \false) { \Psalm\Internal\Analyzer\Statements\Expression\Call\ArgumentsAnalyzer::analyze($statements_analyzer, $stmt->getArgs(), null, null, \true, $context); return \true; } if ($codebase->interfaceExists($fq_class_name)) { IssueBuffer::maybeAdd(new InterfaceInstantiation('Interface ' . $fq_class_name . ' cannot be instantiated', new CodeLocation($statements_analyzer->getSource(), $stmt->class)), $statements_analyzer->getSuppressedIssues()); return \true; } } if ($stmt->class instanceof PhpParser\Node\Stmt\Class_) { $extends = $stmt->class->extends ? (string) $stmt->class->extends : null; $result_atomic_type = new TAnonymousClassInstance($fq_class_name, \false, $extends); } else { //if the class is a Name, it can't represent a child $definite_class = $stmt->class instanceof PhpParser\Node\Name; $result_atomic_type = new TNamedObject($fq_class_name, $from_static, $definite_class); } $statements_analyzer->node_data->setType($stmt, new Union([$result_atomic_type])); if (strtolower($fq_class_name) === 'stdclass' && $stmt->getArgs() !== []) { IssueBuffer::maybeAdd(new TooManyArguments('stdClass::__construct() has no parameters', new CodeLocation($statements_analyzer->getSource(), $stmt), 'stdClass::__construct'), $statements_analyzer->getSuppressedIssues()); } if (strtolower($fq_class_name) !== 'stdclass' && $codebase->classlikes->classExists($fq_class_name)) { self::analyzeNamedConstructor($statements_analyzer, $codebase, $stmt, $context, $fq_class_name, $from_static, $can_extend, $template_result); } else { \Psalm\Internal\Analyzer\Statements\Expression\Call\ArgumentsAnalyzer::analyze($statements_analyzer, $stmt->getArgs(), null, null, \true, $context); if ($codebase->classlikes->enumExists($fq_class_name)) { IssueBuffer::maybeAdd(new UndefinedClass('Enums cannot be instantiated', new CodeLocation($statements_analyzer, $stmt), $fq_class_name)); } } } if (!$config->remember_property_assignments_after_call && !$context->collect_initializations) { $context->removeMutableObjectVars(); } return \true; } private static function analyzeNamedConstructor(StatementsAnalyzer $statements_analyzer, Codebase $codebase, PhpParser\Node\Expr\New_ $stmt, Context $context, string $fq_class_name, bool $from_static, bool $can_extend, ?TemplateResult $template_result = null) : void { $storage = $codebase->classlike_storage_provider->get($fq_class_name); if ($from_static) { if (!$storage->preserve_constructor_signature) { IssueBuffer::maybeAdd(new UnsafeInstantiation('Cannot safely instantiate class ' . $fq_class_name . ' with "new static" as' . ' its constructor might change in child classes', new CodeLocation($statements_analyzer->getSource(), $stmt)), $statements_analyzer->getSuppressedIssues()); } elseif ($storage->template_types && !$storage->enforce_template_inheritance) { $source = $statements_analyzer->getSource(); if ($source instanceof FunctionLikeAnalyzer) { $function_storage = $source->getFunctionLikeStorage($statements_analyzer); if ($function_storage->return_type && preg_match('/\\bstatic\\b/', $function_storage->return_type->getId())) { IssueBuffer::maybeAdd(new UnsafeGenericInstantiation('Cannot safely instantiate generic class ' . $fq_class_name . ' with "new static" as' . ' its generic parameters may be constrained in child classes.', new CodeLocation($statements_analyzer->getSource(), $stmt)), $statements_analyzer->getSuppressedIssues()); } } } } // if we're not calling this constructor via new static() if ($storage->abstract && !$can_extend) { if (IssueBuffer::accepts(new AbstractInstantiation('Unable to instantiate a abstract class ' . $fq_class_name, new CodeLocation($statements_analyzer->getSource(), $stmt)), $statements_analyzer->getSuppressedIssues())) { return; } } if ($storage->deprecated && strtolower($fq_class_name) !== strtolower((string) $context->self)) { IssueBuffer::maybeAdd(new DeprecatedClass($fq_class_name . ' is marked deprecated', new CodeLocation($statements_analyzer->getSource(), $stmt), $fq_class_name), $statements_analyzer->getSuppressedIssues()); } if ($context->self && !$context->collect_initializations && !$context->collect_mutations && !NamespaceAnalyzer::isWithinAny($context->self, $storage->internal)) { IssueBuffer::maybeAdd(new InternalClass($fq_class_name . ' is internal to ' . InternalClass::listToPhrase($storage->internal) . ' but called from ' . $context->self, new CodeLocation($statements_analyzer->getSource(), $stmt), $fq_class_name), $statements_analyzer->getSuppressedIssues()); } $method_id = new MethodIdentifier($fq_class_name, '__construct'); if ($codebase->methods->methodExists($method_id, $context->calling_method_id, $codebase->collect_locations ? new CodeLocation($statements_analyzer->getSource(), $stmt) : null, $statements_analyzer, $statements_analyzer->getFilePath())) { if ($codebase->store_node_types && !$context->collect_initializations && !$context->collect_mutations) { \Psalm\Internal\Analyzer\Statements\Expression\Call\ArgumentMapPopulator::recordArgumentPositions($statements_analyzer, $stmt, $codebase, (string) $method_id); } $template_result ??= new TemplateResult([], []); if (self::checkMethodArgs($method_id, $stmt->getArgs(), $template_result, $context, new CodeLocation($statements_analyzer->getSource(), $stmt), $statements_analyzer) === \false) { return; } if (MethodVisibilityAnalyzer::analyze($method_id, $context, $statements_analyzer->getSource(), new CodeLocation($statements_analyzer->getSource(), $stmt), $statements_analyzer->getSuppressedIssues()) === \false) { return; } $declaring_method_id = $codebase->methods->getDeclaringMethodId($method_id); $method_storage = null; if ($declaring_method_id) { $method_storage = $codebase->methods->getStorage($declaring_method_id); $caller_identifier = $statements_analyzer->getFullyQualifiedFunctionMethodOrNamespaceName() ?: ''; if (!NamespaceAnalyzer::isWithinAny($caller_identifier, $method_storage->internal)) { IssueBuffer::maybeAdd(new InternalMethod('Constructor ' . $codebase->methods->getCasedMethodId($declaring_method_id) . ' is internal to ' . InternalClass::listToPhrase($method_storage->internal) . ' but called from ' . ($caller_identifier ?: 'root namespace'), new CodeLocation($statements_analyzer, $stmt), (string) $method_id), $statements_analyzer->getSuppressedIssues()); } if (!$method_storage->external_mutation_free && !$context->inside_throw) { if ($context->pure) { IssueBuffer::maybeAdd(new ImpureMethodCall('Cannot call an impure constructor from a pure context', new CodeLocation($statements_analyzer, $stmt)), $statements_analyzer->getSuppressedIssues()); } elseif ($statements_analyzer->getSource() instanceof FunctionLikeAnalyzer && $statements_analyzer->getSource()->track_mutations) { $statements_analyzer->getSource()->inferred_has_mutation = \true; $statements_analyzer->getSource()->inferred_impure = \true; } } if ($method_storage->assertions && $stmt->class instanceof PhpParser\Node\Name) { self::applyAssertionsToContext($stmt->class, null, $method_storage->assertions, $stmt->getArgs(), $template_result, $context, $statements_analyzer); } if ($method_storage->if_true_assertions) { $statements_analyzer->node_data->setIfTrueAssertions($stmt, array_map(static fn(Possibilities $assertion): Possibilities => $assertion->getUntemplatedCopy($template_result, null, $codebase), $method_storage->if_true_assertions)); } if ($method_storage->if_false_assertions) { $statements_analyzer->node_data->setIfFalseAssertions($stmt, array_map(static fn(Possibilities $assertion): Possibilities => $assertion->getUntemplatedCopy($template_result, null, $codebase), $method_storage->if_false_assertions)); } } $generic_param_types = null; $self_out_candidate = null; if ($storage->template_types) { foreach ($storage->template_types as $template_name => $base_type) { if (isset($template_result->lower_bounds[$template_name][$fq_class_name])) { $generic_param_type = TemplateStandinTypeReplacer::getMostSpecificTypeFromBounds($template_result->lower_bounds[$template_name][$fq_class_name], $codebase); } elseif ($storage->template_extended_params && $template_result->lower_bounds) { $generic_param_type = self::getGenericParamForOffset($fq_class_name, $template_name, $storage->template_extended_params, array_map(static fn(array $type_map): array => array_map(static fn(array $bounds): Union => TemplateStandinTypeReplacer::getMostSpecificTypeFromBounds($bounds, $codebase), $type_map), $template_result->lower_bounds)); } else { if ($fq_class_name === 'SplObjectStorage') { $generic_param_type = Type::getNever(); } else { $generic_param_type = array_values($base_type)[0]; } } $generic_param_types[] = $generic_param_type->setProperties(['had_template' => \true]); } if ($method_storage && $method_storage->self_out_type) { $self_out_candidate = $method_storage->self_out_type; if ($template_result->lower_bounds) { $self_out_candidate = TypeExpander::expandUnion($codebase, $self_out_candidate, $fq_class_name, null, $storage->parent_class, \true, \false, \false, \true); } $self_out_candidate = MethodCallReturnTypeFetcher::replaceTemplateTypes($self_out_candidate, $template_result, $method_id, count($stmt->getArgs()), $codebase); $self_out_candidate = TypeExpander::expandUnion($codebase, $self_out_candidate, $fq_class_name, $fq_class_name, $storage->parent_class, \true, \false, \false, \true); $statements_analyzer->node_data->setType($stmt, $self_out_candidate); } } // XXX: what if we need both? if ($generic_param_types && !$self_out_candidate) { $result_atomic_type = new TGenericObject($fq_class_name, $generic_param_types, \false, $from_static); $statements_analyzer->node_data->setType($stmt, new Union([$result_atomic_type])); } } elseif ($stmt->getArgs()) { IssueBuffer::maybeAdd(new TooManyArguments('Class ' . $fq_class_name . ' has no __construct, but arguments were passed', new CodeLocation($statements_analyzer->getSource(), $stmt), $fq_class_name . '::__construct'), $statements_analyzer->getSuppressedIssues()); } elseif ($storage->template_types) { $result_atomic_type = new TGenericObject($fq_class_name, array_values(array_map(static fn($map) => reset($map), $storage->template_types)), \false, $from_static); $statements_analyzer->node_data->setType($stmt, new Union([$result_atomic_type])); } if ($storage->external_mutation_free) { $stmt->setAttribute('external_mutation_free', \true); $stmt_type = $statements_analyzer->node_data->getType($stmt); if ($stmt_type) { $stmt_type = $stmt_type->setProperties(['reference_free' => \true]); $statements_analyzer->node_data->setType($stmt, $stmt_type); } } if ($statements_analyzer->data_flow_graph instanceof TaintFlowGraph && !in_array('TaintedInput', $statements_analyzer->getSuppressedIssues()) && ($stmt_type = $statements_analyzer->node_data->getType($stmt))) { $code_location = new CodeLocation($statements_analyzer->getSource(), $stmt); $method_storage = null; $declaring_method_id = $codebase->methods->getDeclaringMethodId($method_id); if ($declaring_method_id) { $method_storage = $codebase->methods->getStorage($declaring_method_id); } if ($storage->external_mutation_free || $method_storage && $method_storage->specialize_call) { $method_source = DataFlowNode::getForMethodReturn((string) $method_id, $fq_class_name . '::__construct', $storage->location, $code_location); } else { $method_source = DataFlowNode::getForMethodReturn((string) $method_id, $fq_class_name . '::__construct', $storage->location); } $statements_analyzer->data_flow_graph->addNode($method_source); $stmt_type = $stmt_type->setParentNodes([$method_source->id => $method_source]); $statements_analyzer->node_data->setType($stmt, $stmt_type); } } private static function analyzeConstructorExpression(StatementsAnalyzer $statements_analyzer, Codebase $codebase, Context $context, PhpParser\Node\Expr\New_ $stmt, PhpParser\Node\Expr $stmt_class, Config $config, ?string &$fq_class_name, bool &$can_extend) : void { $was_inside_general_use = $context->inside_general_use; $context->inside_general_use = \true; ExpressionAnalyzer::analyze($statements_analyzer, $stmt_class, $context); $context->inside_general_use = $was_inside_general_use; $stmt_class_type = $statements_analyzer->node_data->getType($stmt_class); if (!$stmt_class_type) { \Psalm\Internal\Analyzer\Statements\Expression\Call\ArgumentsAnalyzer::analyze($statements_analyzer, $stmt->getArgs(), null, null, \true, $context); return; } $has_single_class = $stmt_class_type->isSingleStringLiteral(); if ($has_single_class) { $fq_class_name = $stmt_class_type->getSingleStringLiteral()->value; } else { if ($statements_analyzer->data_flow_graph instanceof TaintFlowGraph && $stmt_class_type->parent_nodes && !in_array('TaintedInput', $statements_analyzer->getSuppressedIssues())) { $arg_location = new CodeLocation($statements_analyzer->getSource(), $stmt_class); $custom_call_sink = TaintSink::getForMethodArgument('variable-call', 'variable-call', 0, $arg_location, $arg_location); $custom_call_sink->taints = [TaintKind::INPUT_CALLABLE]; $statements_analyzer->data_flow_graph->addSink($custom_call_sink); $event = new AddRemoveTaintsEvent($stmt, $context, $statements_analyzer, $codebase); $added_taints = $codebase->config->eventDispatcher->dispatchAddTaints($event); $removed_taints = $codebase->config->eventDispatcher->dispatchRemoveTaints($event); foreach ($stmt_class_type->parent_nodes as $parent_node) { $statements_analyzer->data_flow_graph->addPath($parent_node, $custom_call_sink, 'call', $added_taints, $removed_taints); } } if (self::checkMethodArgs(null, $stmt->getArgs(), new TemplateResult([], []), $context, new CodeLocation($statements_analyzer->getSource(), $stmt), $statements_analyzer) === \false) { return; } } $new_type = self::getNewType($statements_analyzer, $codebase, $context, $stmt, $stmt_class_type, $config, $can_extend); if (!$has_single_class) { if ($new_type) { $statements_analyzer->node_data->setType($stmt, $new_type); } \Psalm\Internal\Analyzer\Statements\Expression\Call\ArgumentsAnalyzer::analyze($statements_analyzer, $stmt->getArgs(), null, null, \true, $context); return; } } private static function getNewType(StatementsAnalyzer $statements_analyzer, Codebase $codebase, Context $context, PhpParser\Node\Expr\New_ $stmt, Union $stmt_class_type, Config $config, bool &$can_extend) : ?Union { $new_types = []; foreach ($stmt_class_type->getAtomicTypes() as $lhs_type_part) { if ($lhs_type_part instanceof TTemplateParam) { $as = self::getNewType($statements_analyzer, $codebase, $context, $stmt, $lhs_type_part->as, $config, $can_extend); if ($as) { $new_types[] = new Union([$lhs_type_part->replaceAs($as)]); } continue; } if ($lhs_type_part instanceof TTemplateParamClass) { if (!$statements_analyzer->node_data->getType($stmt)) { $new_type_part = new TTemplateParam($lhs_type_part->param_name, $lhs_type_part->as_type ? new Union([$lhs_type_part->as_type]) : Type::getObject(), $lhs_type_part->defining_class); if (!$lhs_type_part->as_type) { IssueBuffer::maybeAdd(new MixedMethodCall('Cannot call constructor on an unknown class', new CodeLocation($statements_analyzer->getSource(), $stmt)), $statements_analyzer->getSuppressedIssues()); } $new_types[] = new Union([$new_type_part]); if ($lhs_type_part->as_type && $codebase->classlikes->classExists($lhs_type_part->as_type->value)) { $as_storage = $codebase->classlike_storage_provider->get($lhs_type_part->as_type->value); if (!$as_storage->preserve_constructor_signature) { IssueBuffer::maybeAdd(new UnsafeInstantiation('Cannot safely instantiate class ' . $lhs_type_part->as_type->value . ' with "new $class_name" as' . ' its constructor might change in child classes', new CodeLocation($statements_analyzer->getSource(), $stmt)), $statements_analyzer->getSuppressedIssues()); } } } if ($lhs_type_part->as_type) { $codebase->methods->methodExists(new MethodIdentifier($lhs_type_part->as_type->value, '__construct'), $context->calling_method_id, $codebase->collect_locations ? new CodeLocation($statements_analyzer->getSource(), $stmt) : null, $statements_analyzer, $statements_analyzer->getFilePath()); } continue; } if ($lhs_type_part instanceof TLiteralClassString || $lhs_type_part instanceof TClassString || $lhs_type_part instanceof TDependentGetClass) { if (!$statements_analyzer->node_data->getType($stmt)) { if ($lhs_type_part instanceof TClassString) { $generated_type = $lhs_type_part->as_type ?? new TObject(); if ($lhs_type_part instanceof TUnknownClassString) { $generated_type = $lhs_type_part->as_unknown_type ?? $generated_type; } if ($lhs_type_part->as_type && $codebase->classlikes->classExists($lhs_type_part->as_type->value)) { $as_storage = $codebase->classlike_storage_provider->get($lhs_type_part->as_type->value); if (!$as_storage->preserve_constructor_signature) { IssueBuffer::maybeAdd(new UnsafeInstantiation('Cannot safely instantiate class ' . $lhs_type_part->as_type->value . ' with "new $class_name" as' . ' its constructor might change in child classes', new CodeLocation($statements_analyzer->getSource(), $stmt)), $statements_analyzer->getSuppressedIssues()); } } } elseif ($lhs_type_part instanceof TDependentGetClass) { $generated_type = new TObject(); if ($lhs_type_part->as_type->hasObjectType() && $lhs_type_part->as_type->isSingle()) { foreach ($lhs_type_part->as_type->getAtomicTypes() as $typeof_type_atomic) { if ($typeof_type_atomic instanceof TNamedObject) { $generated_type = new TNamedObject($typeof_type_atomic->value); } } } } else { $generated_type = new TNamedObject($lhs_type_part->value); } if ($lhs_type_part instanceof TClassString) { $can_extend = \true; } if ($generated_type instanceof TObject) { IssueBuffer::maybeAdd(new MixedMethodCall('Cannot call constructor on an unknown class', new CodeLocation($statements_analyzer->getSource(), $stmt)), $statements_analyzer->getSuppressedIssues()); } $new_types[] = new Union([$generated_type]); } continue; } if ($lhs_type_part instanceof TString) { if (!$config->allow_string_standin_for_class || $lhs_type_part instanceof TNumericString) { IssueBuffer::maybeAdd(new InvalidStringClass('String cannot be used as a class', new CodeLocation($statements_analyzer->getSource(), $stmt)), $statements_analyzer->getSuppressedIssues()); } } elseif ($lhs_type_part instanceof TMixed || $lhs_type_part instanceof TObject) { IssueBuffer::maybeAdd(new MixedMethodCall('Cannot call constructor on an unknown class', new CodeLocation($statements_analyzer->getSource(), $stmt)), $statements_analyzer->getSuppressedIssues()); } elseif ($lhs_type_part instanceof TFalse && $stmt_class_type->ignore_falsable_issues) { // do nothing } elseif ($lhs_type_part instanceof TNull && $stmt_class_type->ignore_nullable_issues) { // do nothing } elseif ($lhs_type_part instanceof TNamedObject) { $new_types[] = new Union([$lhs_type_part]); continue; } else { IssueBuffer::maybeAdd(new UndefinedClass('Type ' . $lhs_type_part . ' cannot be called as a class', new CodeLocation($statements_analyzer->getSource(), $stmt), (string) $lhs_type_part), $statements_analyzer->getSuppressedIssues()); } $new_types[] = Type::getObject(); } if ($new_types) { return Type::combineUnionTypeArray($new_types, $codebase); } return null; } } $_items * * param callable(A): B $_ab * * return list * function map(array $items, callable $ab): array { ... } * * // list * $numbers = [1, 2, 3]; * * $result = map($numbers, id()); * // $result is list because template T of id() was inferred by previous arg. * ``` */ public static function remapLowerBounds(StatementsAnalyzer $statements_analyzer, TemplateResult $inferred_template_result, \Psalm\Internal\Analyzer\Statements\Expression\Call\HighOrderFunctionArgInfo $input_function, Union $container_function_type) : TemplateResult { // Try to infer container callable by $inferred_template_result $container_type = TemplateInferredTypeReplacer::replace($container_function_type, $inferred_template_result, $statements_analyzer->getCodebase()); $input_function_type = $input_function->getFunctionType(); $input_function_template_result = $input_function->getTemplates(); // Traverse side by side 'container' params and 'input' params. // This maps 'input' templates to 'container' templates. // // Example: // 'input' => Closure(C:Bar, D:Bar): array{C:Bar, D:Bar} // 'container' => Closure(int, string): array{int, string} // // $remapped_lower_bounds will be: [ // 'C' => ['Bar' => [int]], // 'D' => ['Bar' => [string]] // ]. foreach ($input_function_type->getAtomicTypes() as $input_atomic) { if (!$input_atomic instanceof TClosure && !$input_atomic instanceof TCallable) { continue; } foreach ($container_type->getAtomicTypes() as $container_atomic) { if (!$container_atomic instanceof TClosure && !$container_atomic instanceof TCallable) { continue; } foreach ($input_atomic->params ?? [] as $offset => $input_param) { if (!isset($container_atomic->params[$offset])) { continue; } TemplateStandinTypeReplacer::fillTemplateResult($input_param->type ?? Type::getMixed(), $input_function_template_result, $statements_analyzer->getCodebase(), $statements_analyzer, $container_atomic->params[$offset]->type); } } } return $input_function_template_result; } public static function enhanceCallableArgType(Context $context, PhpParser\Node\Expr $arg_expr, StatementsAnalyzer $statements_analyzer, \Psalm\Internal\Analyzer\Statements\Expression\Call\HighOrderFunctionArgInfo $high_order_callable_info, TemplateResult $high_order_template_result) : void { // Psalm can infer simple callable/closure. // But can't infer first-class-callable or high-order function. if ($high_order_callable_info->getType() === \Psalm\Internal\Analyzer\Statements\Expression\Call\HighOrderFunctionArgInfo::TYPE_CALLABLE) { return; } $fully_inferred_callable_type = TemplateInferredTypeReplacer::replace($high_order_callable_info->getFunctionType(), $high_order_template_result, $statements_analyzer->getCodebase()); // Some templates may not have been replaced. // They expansion makes error message better. $expanded = TypeExpander::expandUnion($statements_analyzer->getCodebase(), $fully_inferred_callable_type, $context->self, $context->self, $context->parent, \true, \true, \false, \false, \true); $statements_analyzer->node_data->setType($arg_expr, $expanded); } public static function getCallableArgInfo(Context $context, PhpParser\Node\Expr $input_arg_expr, StatementsAnalyzer $statements_analyzer, FunctionLikeParameter $container_param) : ?\Psalm\Internal\Analyzer\Statements\Expression\Call\HighOrderFunctionArgInfo { if (!self::isSupported($container_param)) { return null; } $codebase = $statements_analyzer->getCodebase(); try { if ($input_arg_expr instanceof PhpParser\Node\Expr\FuncCall) { $function_id = strtolower((string) $input_arg_expr->name->getAttribute('resolvedName')); if (empty($function_id)) { return null; } $dynamic_storage = !$input_arg_expr->isFirstClassCallable() ? $codebase->functions->dynamic_storage_provider->getFunctionStorage($input_arg_expr, $statements_analyzer, $function_id, $context, new CodeLocation($statements_analyzer, $input_arg_expr)) : null; return new \Psalm\Internal\Analyzer\Statements\Expression\Call\HighOrderFunctionArgInfo($input_arg_expr->isFirstClassCallable() ? \Psalm\Internal\Analyzer\Statements\Expression\Call\HighOrderFunctionArgInfo::TYPE_FIRST_CLASS_CALLABLE : \Psalm\Internal\Analyzer\Statements\Expression\Call\HighOrderFunctionArgInfo::TYPE_CALLABLE, $dynamic_storage ?? $codebase->functions->getStorage($statements_analyzer, $function_id)); } if ($input_arg_expr instanceof PhpParser\Node\Expr\MethodCall && $input_arg_expr->var instanceof PhpParser\Node\Expr\Variable && $input_arg_expr->name instanceof PhpParser\Node\Identifier && is_string($input_arg_expr->var->name) && isset($context->vars_in_scope['$' . $input_arg_expr->var->name])) { $lhs_type = $context->vars_in_scope['$' . $input_arg_expr->var->name]->getSingleAtomic(); if (!$lhs_type instanceof Type\Atomic\TNamedObject) { return null; } $method_id = new MethodIdentifier($lhs_type->value, strtolower((string) $input_arg_expr->name)); return new \Psalm\Internal\Analyzer\Statements\Expression\Call\HighOrderFunctionArgInfo($input_arg_expr->isFirstClassCallable() ? \Psalm\Internal\Analyzer\Statements\Expression\Call\HighOrderFunctionArgInfo::TYPE_FIRST_CLASS_CALLABLE : \Psalm\Internal\Analyzer\Statements\Expression\Call\HighOrderFunctionArgInfo::TYPE_CALLABLE, $codebase->methods->getStorage($method_id)); } if ($input_arg_expr instanceof PhpParser\Node\Expr\StaticCall && $input_arg_expr->name instanceof PhpParser\Node\Identifier) { $method_id = new MethodIdentifier((string) $input_arg_expr->class->getAttribute('resolvedName'), strtolower($input_arg_expr->name->toString())); return new \Psalm\Internal\Analyzer\Statements\Expression\Call\HighOrderFunctionArgInfo($input_arg_expr->isFirstClassCallable() ? \Psalm\Internal\Analyzer\Statements\Expression\Call\HighOrderFunctionArgInfo::TYPE_FIRST_CLASS_CALLABLE : \Psalm\Internal\Analyzer\Statements\Expression\Call\HighOrderFunctionArgInfo::TYPE_CALLABLE, $codebase->methods->getStorage($method_id)); } if ($input_arg_expr instanceof PhpParser\Node\Scalar\String_) { return self::fromLiteralString(Type::getString($input_arg_expr->value), $statements_analyzer); } if ($input_arg_expr instanceof PhpParser\Node\Expr\ConstFetch) { $constant = $context->constants[$input_arg_expr->name->toString()] ?? null; return null !== $constant ? self::fromLiteralString($constant, $statements_analyzer) : null; } if ($input_arg_expr instanceof PhpParser\Node\Expr\ClassConstFetch && $input_arg_expr->name instanceof PhpParser\Node\Identifier) { $storage = $codebase->classlikes->getStorageFor((string) $input_arg_expr->class->getAttribute('resolvedName')); $constant = null !== $storage ? $storage->constants[$input_arg_expr->name->toString()] ?? null : null; return null !== $constant && null !== $constant->type ? self::fromLiteralString($constant->type, $statements_analyzer) : null; } if ($input_arg_expr instanceof PhpParser\Node\Expr\New_ && $input_arg_expr->class instanceof PhpParser\Node\Name) { $class_storage = $codebase->classlikes->getStorageFor((string) $input_arg_expr->class->getAttribute('resolvedName')); $invoke_storage = $class_storage && isset($class_storage->methods['__invoke']) ? $class_storage->methods['__invoke'] : null; if (!$invoke_storage) { return null; } return new \Psalm\Internal\Analyzer\Statements\Expression\Call\HighOrderFunctionArgInfo(\Psalm\Internal\Analyzer\Statements\Expression\Call\HighOrderFunctionArgInfo::TYPE_CLASS_CALLABLE, $invoke_storage, $class_storage); } } catch (UnexpectedValueException $e) { return null; } return null; } private static function isSupported(FunctionLikeParameter $container_param) : bool { if (!$container_param->type || !$container_param->type->hasCallableType()) { return \false; } foreach ($container_param->type->getAtomicTypes() as $a) { // must check null explicitly, since no params (empty array) would not be handled correctly otherwise if (($a instanceof TClosure || $a instanceof TCallable) && $a->params === null) { return \false; } if ($a instanceof Type\Atomic\TCallableArray || $a instanceof Type\Atomic\TCallableString || $a instanceof Type\Atomic\TCallableKeyedArray) { return \false; } } return \true; } private static function fromLiteralString(Union $constant, StatementsAnalyzer $statements_analyzer) : ?\Psalm\Internal\Analyzer\Statements\Expression\Call\HighOrderFunctionArgInfo { $literal = $constant->isSingle() ? $constant->getSingleAtomic() : null; if (!$literal instanceof Type\Atomic\TLiteralString || empty($literal->value)) { return null; } $codebase = $statements_analyzer->getCodebase(); return new \Psalm\Internal\Analyzer\Statements\Expression\Call\HighOrderFunctionArgInfo(\Psalm\Internal\Analyzer\Statements\Expression\Call\HighOrderFunctionArgInfo::TYPE_STRING_CALLABLE, strpos($literal->value, '::') !== \false ? $codebase->methods->getStorage(MethodIdentifier::wrap($literal->value)) : $codebase->functions->getStorage($statements_analyzer, strtolower($literal->value))); } } > $class_generic_params * @return false|null */ public static function checkArgumentMatches(StatementsAnalyzer $statements_analyzer, ?string $cased_method_id, ?MethodIdentifier $method_id, ?string $self_fq_class_name, ?string $static_fq_class_name, CodeLocation $function_call_location, ?FunctionLikeParameter $function_param, int $argument_offset, int $unpacked_argument_offset, bool $allow_named_args, PhpParser\Node\Arg $arg, ?Union $arg_value_type, Context $context, array $class_generic_params, ?TemplateResult $template_result, bool $specialize_taint, bool $in_call_map) : ?bool { $codebase = $statements_analyzer->getCodebase(); if (!$arg_value_type) { if ($function_param && !$function_param->by_ref) { if (!$context->collect_initializations && !$context->collect_mutations && $statements_analyzer->getFilePath() === $statements_analyzer->getRootFilePath() && (!($parent_source = $statements_analyzer->getSource()) instanceof FunctionLikeAnalyzer || !$parent_source->getSource() instanceof TraitAnalyzer)) { $codebase->analyzer->incrementMixedCount($statements_analyzer->getFilePath()); } $param_type = $function_param->type; if ($function_param->is_variadic && $param_type && $param_type->hasArray()) { $array_type = $param_type->getArray(); if ($array_type instanceof TKeyedArray && $array_type->is_list) { $param_type = $array_type->getGenericValueType(); } elseif ($array_type instanceof TArray) { $param_type = $array_type->type_params[1]; } } if ($param_type && !$param_type->hasMixed()) { IssueBuffer::maybeAdd(new MixedArgument('Argument ' . ($argument_offset + 1) . ' of ' . $cased_method_id . ' cannot be mixed, expecting ' . $param_type, new CodeLocation($statements_analyzer->getSource(), $arg->value), $cased_method_id), $statements_analyzer->getSuppressedIssues()); } } return null; } if (!$function_param) { return null; } if ($function_param->expect_variable && $arg_value_type->isSingleStringLiteral() && !$arg->value instanceof PhpParser\Node\Scalar\MagicConst && !$arg->value instanceof PhpParser\Node\Expr\ConstFetch && !$arg->value instanceof PhpParser\Node\Expr\ClassConstFetch) { $values = preg_split('//u', $arg_value_type->getSingleStringLiteral()->value, -1, PREG_SPLIT_NO_EMPTY); if ($values !== \false) { $prev_ord = 0; $gt_count = 0; foreach ($values as $value) { $ord = ord($value); if ($ord > $prev_ord) { $gt_count++; } $prev_ord = $ord; } if (substr_count($arg_value_type->getSingleStringLiteral()->value, DIRECTORY_SEPARATOR) <= 2 && (count($values) < 12 || $gt_count / count($values) < 0.8)) { IssueBuffer::maybeAdd(new InvalidLiteralArgument('Argument ' . ($argument_offset + 1) . ' of ' . $cased_method_id . ' expects a non-literal value, but ' . $arg_value_type->getId() . ' provided', new CodeLocation($statements_analyzer->getSource(), $arg->value), $cased_method_id), $statements_analyzer->getSuppressedIssues()); } } } if (self::checkFunctionLikeTypeMatches($statements_analyzer, $codebase, $cased_method_id, $method_id, $self_fq_class_name, $static_fq_class_name, $function_call_location, $function_param, $allow_named_args, $arg_value_type, $argument_offset, $unpacked_argument_offset, $arg, $context, $class_generic_params, $template_result, $specialize_taint, $in_call_map) === \false) { return \false; } return null; } /** * @param array> $class_generic_params * @return false|null */ private static function checkFunctionLikeTypeMatches(StatementsAnalyzer $statements_analyzer, Codebase $codebase, ?string $cased_method_id, ?MethodIdentifier $method_id, ?string $self_fq_class_name, ?string $static_fq_class_name, CodeLocation $function_call_location, FunctionLikeParameter $function_param, bool $allow_named_args, Union $arg_value_type, int $argument_offset, int $unpacked_argument_offset, PhpParser\Node\Arg $arg, Context $context, ?array $class_generic_params, ?TemplateResult $template_result, bool $specialize_taint, bool $in_call_map) : ?bool { if (!$function_param->type) { if (!$codebase->infer_types_from_usage && !$statements_analyzer->data_flow_graph) { return null; } $param_type = Type::getMixed(); } else { $param_type = $function_param->type; } $bindable_template_params = []; if ($template_result) { $bindable_template_params = $param_type->getTemplateTypes(); } $parent_class = null; $classlike_storage = null; $static_classlike_storage = null; if ($self_fq_class_name) { $classlike_storage = $codebase->classlike_storage_provider->get($self_fq_class_name); $parent_class = $classlike_storage->parent_class; $static_classlike_storage = $classlike_storage; if ($static_fq_class_name && $static_fq_class_name !== $self_fq_class_name) { $static_classlike_storage = $codebase->classlike_storage_provider->get($static_fq_class_name); } } $param_type = TypeExpander::expandUnion($codebase, $param_type, $classlike_storage->name ?? null, $static_classlike_storage->name ?? null, $parent_class, \true, \false, $static_classlike_storage->final ?? \false, \true); if ($class_generic_params) { // here we're replacing the param types and arg types with the bound // class template params. // // For example, if we're operating on a class Foo with params TKey and TValue, // and we're calling a method "add(TKey $key, TValue $value)" on an instance // of that class where we know that TKey is int and TValue is string, then we // want to substitute the expected parameters so it's as if we were actually // calling "add(int $key, string $value)" $readonly_template_result = new TemplateResult($class_generic_params, []); // This flag ensures that the template results will never be written to // It also supercedes the `$add_lower_bounds` flag so that closure params // don’t get overwritten $readonly_template_result->readonly = \true; $param_type = TemplateStandinTypeReplacer::replace($param_type, $readonly_template_result, $codebase, $statements_analyzer, $arg_value_type, $argument_offset, $context->self, $context->calling_function_id ?: $context->calling_method_id); $arg_value_type = TemplateStandinTypeReplacer::replace($arg_value_type, $readonly_template_result, $codebase, $statements_analyzer, $arg_value_type, $argument_offset, $context->self, $context->calling_function_id ?: $context->calling_method_id); } if ($template_result && $template_result->template_types) { $arg_type_param = $arg_value_type; if ($arg->unpack) { $arg_type_param = null; foreach ($arg_value_type->getAtomicTypes() as $arg_atomic_type) { if ($arg_atomic_type instanceof TList) { $arg_atomic_type = $arg_atomic_type->getKeyedArray(); } if ($arg_atomic_type instanceof TArray || $arg_atomic_type instanceof TKeyedArray) { if ($arg_atomic_type instanceof TKeyedArray) { $arg_type_param = $arg_atomic_type->getGenericValueType(); } else { $arg_type_param = $arg_atomic_type->type_params[1]; } } elseif ($arg_atomic_type instanceof TIterable) { $arg_type_param = $arg_atomic_type->type_params[1]; } elseif ($arg_atomic_type instanceof TNamedObject) { ForeachAnalyzer::getKeyValueParamsForTraversableObject($arg_atomic_type, $codebase, $key_type, $arg_type_param); } } if (!$arg_type_param) { $arg_type_param = new Union([new TMixed()], ['parent_nodes' => $arg_value_type->parent_nodes]); } } $param_type = TemplateStandinTypeReplacer::replace($param_type, $template_result, $codebase, $statements_analyzer, $arg_type_param, $argument_offset, !$statements_analyzer->isStatic() && (!$method_id || $method_id->method_name !== '__construct') ? $context->self : null, $context->calling_method_id ?: $context->calling_function_id); foreach ($bindable_template_params as $template_type) { if (!isset($template_result->lower_bounds[$template_type->param_name][$template_type->defining_class])) { if (isset($template_result->upper_bounds[$template_type->param_name][$template_type->defining_class])) { $template_result->lower_bounds[$template_type->param_name][$template_type->defining_class] = [new TemplateBound($template_result->upper_bounds[$template_type->param_name][$template_type->defining_class]->type)]; } else { $template_result->lower_bounds[$template_type->param_name][$template_type->defining_class] = [new TemplateBound($template_type->as)]; } } } $param_type = TypeExpander::expandUnion($codebase, $param_type, $classlike_storage->name ?? null, $static_classlike_storage->name ?? null, $parent_class, \true, \false, $static_classlike_storage->final ?? \false, \true); } $fleshed_out_signature_type = $function_param->signature_type ? TypeExpander::expandUnion($codebase, $function_param->signature_type, $classlike_storage->name ?? null, $static_classlike_storage->name ?? null, $parent_class) : null; $unpacked_atomic_array = null; if ($arg->unpack) { if ($arg_value_type->hasMixed()) { if (!$context->collect_initializations && !$context->collect_mutations && $statements_analyzer->getFilePath() === $statements_analyzer->getRootFilePath() && (!($parent_source = $statements_analyzer->getSource()) instanceof FunctionLikeAnalyzer || !$parent_source->getSource() instanceof TraitAnalyzer)) { $codebase->analyzer->incrementMixedCount($statements_analyzer->getFilePath()); } IssueBuffer::maybeAdd(new MixedArgument('Argument ' . ($argument_offset + 1) . ' of ' . $cased_method_id . ' cannot unpack ' . $arg_value_type->getId() . ', expecting iterable', new CodeLocation($statements_analyzer->getSource(), $arg->value), $cased_method_id), $statements_analyzer->getSuppressedIssues()); if ($cased_method_id) { $arg_location = new CodeLocation($statements_analyzer->getSource(), $arg->value); self::processTaintedness($statements_analyzer, $cased_method_id, $method_id, $argument_offset, $arg_location, $function_call_location, $function_param, $arg_value_type, $arg->value, $context, $specialize_taint); } return null; } if ($arg_value_type->hasArray()) { $unpacked_atomic_array = $arg_value_type->getArray(); $arg_key_allowed = \true; if ($unpacked_atomic_array instanceof TKeyedArray) { if (!$allow_named_args && !$unpacked_atomic_array->getGenericKeyType()->isInt()) { $arg_key_allowed = \false; } if ($function_param->is_variadic) { $arg_value_type = $unpacked_atomic_array->getGenericValueType(); } elseif ($codebase->analysis_php_version_id >= 80000 && $allow_named_args && isset($unpacked_atomic_array->properties[$function_param->name])) { $arg_value_type = $unpacked_atomic_array->properties[$function_param->name]; } elseif ($unpacked_atomic_array->is_list && isset($unpacked_atomic_array->properties[$unpacked_argument_offset])) { $arg_value_type = $unpacked_atomic_array->properties[$unpacked_argument_offset]; } elseif ($unpacked_atomic_array->fallback_params) { $arg_value_type = $unpacked_atomic_array->fallback_params[1]; } elseif ($function_param->is_optional && $function_param->default_type) { if ($function_param->default_type instanceof Union) { $arg_value_type = $function_param->default_type; } else { $arg_value_type_atomic = ConstantTypeResolver::resolve($codebase->classlikes, $function_param->default_type, $statements_analyzer); $arg_value_type = new Union([$arg_value_type_atomic]); } } else { $arg_value_type = Type::getMixed(); } } elseif ($unpacked_atomic_array instanceof TClassStringMap) { $arg_value_type = Type::getMixed(); } else { if (!$allow_named_args && !$unpacked_atomic_array->type_params[0]->isInt()) { $arg_key_allowed = \false; } $arg_value_type = $unpacked_atomic_array->type_params[1]; } if (!$arg_key_allowed) { IssueBuffer::maybeAdd(new NamedArgumentNotAllowed('Method ' . $cased_method_id . ' called with named unpacked array ' . $unpacked_atomic_array->getId() . ' (array with string keys)', new CodeLocation($statements_analyzer->getSource(), $arg->value), $cased_method_id), $statements_analyzer->getSuppressedIssues()); } } else { $non_iterable = \false; $invalid_key = \false; $invalid_string_key = \false; $possibly_matches = \false; foreach ($arg_value_type->getAtomicTypes() as $atomic_type) { if (!$atomic_type->isIterable($codebase)) { $non_iterable = \true; } else { $key_type = $codebase->getKeyValueParamsForTraversableObject($atomic_type)[0]; if (!UnionTypeComparator::isContainedBy($codebase, $key_type, Type::getArrayKey())) { $invalid_key = \true; continue; } if (($codebase->analysis_php_version_id < 80000 || !$allow_named_args) && !$key_type->isInt()) { $invalid_string_key = \true; continue; } $possibly_matches = \true; } } $issue_type = $possibly_matches ? PossiblyInvalidArgument::class : InvalidArgument::class; if ($non_iterable) { IssueBuffer::maybeAdd(new $issue_type('Tried to unpack non-iterable ' . $arg_value_type->getId(), new CodeLocation($statements_analyzer->getSource(), $arg->value), $cased_method_id), $statements_analyzer->getSuppressedIssues()); } if ($invalid_key) { IssueBuffer::maybeAdd(new $issue_type('Method ' . $cased_method_id . ' called with unpacked iterable ' . $arg_value_type->getId() . ' with invalid key (must be ' . ($codebase->analysis_php_version_id < 80000 ? 'int' : 'int|string') . ')', new CodeLocation($statements_analyzer->getSource(), $arg->value), $cased_method_id), $statements_analyzer->getSuppressedIssues()); } if ($invalid_string_key) { if ($codebase->analysis_php_version_id < 80000) { IssueBuffer::maybeAdd(new $issue_type('String keys not supported in unpacked arguments', new CodeLocation($statements_analyzer->getSource(), $arg->value), $cased_method_id), $statements_analyzer->getSuppressedIssues()); } else { IssueBuffer::maybeAdd(new NamedArgumentNotAllowed('Method ' . $cased_method_id . ' called with named unpacked iterable ' . $arg_value_type->getId() . ' (iterable with string keys)', new CodeLocation($statements_analyzer->getSource(), $arg->value), $cased_method_id), $statements_analyzer->getSuppressedIssues()); } } return null; } } else { if (!$allow_named_args && $arg->name !== null) { IssueBuffer::maybeAdd(new NamedArgumentNotAllowed('Method ' . $cased_method_id . ' called with named argument ' . $arg->name->name, new CodeLocation($statements_analyzer->getSource(), $arg->value), $cased_method_id), $statements_analyzer->getSuppressedIssues()); } } // bypass verifying argument types when collecting initialisations, // because the argument locations are not reliable (file names normally differ) // See https://github.com/vimeo/psalm/issues/5662 if ($arg instanceof VirtualArg && $context->collect_initializations) { return null; } if (self::verifyType($statements_analyzer, $arg_value_type, $param_type, $fleshed_out_signature_type, $cased_method_id, $method_id, $argument_offset, new CodeLocation($statements_analyzer->getSource(), $arg->value), $arg->value, $context, $function_param, $arg->unpack, $unpacked_atomic_array, $specialize_taint, $in_call_map, $function_call_location) === \false) { return \false; } return null; } /** * @param TKeyedArray|TArray|TClassStringMap|null $unpacked_atomic_array * @return null|false */ public static function verifyType(StatementsAnalyzer $statements_analyzer, Union $input_type, Union $param_type, ?Union $signature_param_type, ?string $cased_method_id, ?MethodIdentifier $method_id, int $argument_offset, CodeLocation $arg_location, PhpParser\Node\Expr $input_expr, Context $context, FunctionLikeParameter $function_param, bool $unpack, ?Atomic $unpacked_atomic_array, bool $specialize_taint, bool $in_call_map, CodeLocation $function_call_location) : ?bool { $codebase = $statements_analyzer->getCodebase(); if ($param_type->hasMixed()) { if ($codebase->infer_types_from_usage && !$input_type->hasMixed() && !$param_type->from_docblock && !$param_type->had_template && $method_id && strpos($method_id->method_name, '__') !== 0) { $declaring_method_id = $codebase->methods->getDeclaringMethodId($method_id); if ($declaring_method_id) { $id_lc = strtolower((string) $declaring_method_id); $codebase->analyzer->possible_method_param_types[$id_lc][$argument_offset] = Type::combineUnionTypes($codebase->analyzer->possible_method_param_types[$id_lc][$argument_offset] ?? null, $input_type, $codebase); } } if ($cased_method_id) { self::processTaintedness($statements_analyzer, $cased_method_id, $method_id, $argument_offset, $arg_location, $function_call_location, $function_param, $input_type, $input_expr, $context, $specialize_taint); } return null; } $method_identifier = $cased_method_id ? ' of ' . $cased_method_id : ''; if ($input_type->hasMixed()) { if (!$context->collect_initializations && !$context->collect_mutations && $statements_analyzer->getFilePath() === $statements_analyzer->getRootFilePath() && (!($parent_source = $statements_analyzer->getSource()) instanceof FunctionLikeAnalyzer || !$parent_source->getSource() instanceof TraitAnalyzer)) { $codebase->analyzer->incrementMixedCount($statements_analyzer->getFilePath()); } $origin_locations = []; if ($statements_analyzer->data_flow_graph instanceof VariableUseGraph) { foreach ($input_type->parent_nodes as $parent_node) { $origin_locations = [...$origin_locations, ...$statements_analyzer->data_flow_graph->getOriginLocations($parent_node)]; } } $origin_location = count($origin_locations) === 1 ? reset($origin_locations) : null; if ($origin_location && $origin_location->getHash() === $arg_location->getHash()) { $origin_location = null; } IssueBuffer::maybeAdd(new MixedArgument('Argument ' . ($argument_offset + 1) . $method_identifier . ' cannot be ' . $input_type->getId() . ', expecting ' . $param_type, $arg_location, $cased_method_id, $origin_location), $statements_analyzer->getSuppressedIssues()); if ($input_type->isMixed()) { if (!$function_param->by_ref && !($function_param->is_variadic xor $unpack) && $cased_method_id !== 'echo' && $cased_method_id !== 'print' && (!$in_call_map || $context->strict_types)) { self::coerceValueAfterGatekeeperArgument($statements_analyzer, $input_type, \false, $input_expr, $param_type, $signature_param_type, $context, $unpack, $unpacked_atomic_array); } } if ($cased_method_id) { self::processTaintedness($statements_analyzer, $cased_method_id, $method_id, $argument_offset, $arg_location, $function_call_location, $function_param, $input_type, $input_expr, $context, $specialize_taint); } if ($input_type->isMixed()) { return null; } } if ($input_type->isNever()) { if (!IssueBuffer::accepts(new NoValue('All possible types for this argument were invalidated - This may be dead code', $arg_location), $statements_analyzer->getSuppressedIssues())) { // if the error is suppressed, do not treat it as exited anymore $context->has_returned = \false; } return null; } if (!$context->collect_initializations && !$context->collect_mutations && $statements_analyzer->getFilePath() === $statements_analyzer->getRootFilePath() && (!($parent_source = $statements_analyzer->getSource()) instanceof FunctionLikeAnalyzer || !$parent_source->getSource() instanceof TraitAnalyzer)) { $codebase->analyzer->incrementNonMixedCount($statements_analyzer->getFilePath()); } if ($function_param->by_ref || $function_param->is_optional) { //if the param is optional or a ref, we'll allow the input to be possibly_undefined $param_type = $param_type->setPossiblyUndefined(\true); } if ($param_type->hasCallableType() && $param_type->isSingle()) { // we do this replacement early because later we don't have access to the // $statements_analyzer, which is necessary to understand string function names $input_type = $input_type->getBuilder(); foreach ($input_type->getAtomicTypes() as $key => $atomic_type) { $container_callable_type = $param_type->getSingleAtomic(); $container_callable_type = $container_callable_type instanceof TCallable ? $container_callable_type : null; $candidate_callable = CallableTypeComparator::getCallableFromAtomic($codebase, $atomic_type, $container_callable_type, $statements_analyzer, \true); if ($candidate_callable && $candidate_callable !== $atomic_type) { // if we had an array callable, mark it as used now, since it's not possible later $potential_method_id = null; if ($atomic_type instanceof TList) { $atomic_type = $atomic_type->getKeyedArray(); } if ($atomic_type instanceof TKeyedArray) { $potential_method_id = CallableTypeComparator::getCallableMethodIdFromTKeyedArray($atomic_type, $codebase, $context->calling_method_id, $statements_analyzer->getFilePath()); } elseif ($atomic_type instanceof TLiteralString && strpos($atomic_type->value, '::')) { $parts = explode('::', $atomic_type->value); $potential_method_id = new MethodIdentifier($parts[0], strtolower($parts[1])); } if ($potential_method_id && $potential_method_id !== 'not-callable') { $codebase->methods->methodExists($potential_method_id, $context->calling_method_id, $arg_location, $statements_analyzer, $statements_analyzer->getFilePath(), \true, $context->insideUse()); if (self::verifyCallableInContext($potential_method_id, $cased_method_id, $method_id, $atomic_type, $argument_offset, $arg_location, $context, $codebase, $statements_analyzer) === \false) { continue; } } $input_type->removeType($key); $input_type->addType($candidate_callable); } } $input_type = $input_type->freeze(); } $union_comparison_results = new TypeComparisonResult(); $type_match_found = UnionTypeComparator::isContainedBy($codebase, $input_type, $param_type, \true, !isset($param_type->getAtomicTypes()['true']), $union_comparison_results); $replace_input_type = \false; if ($union_comparison_results->replacement_union_type) { $replace_input_type = \true; $input_type = $union_comparison_results->replacement_union_type; } if ($cased_method_id) { self::processTaintedness($statements_analyzer, $cased_method_id, $method_id, $argument_offset, $arg_location, $function_call_location, $function_param, $input_type, $input_expr, $context, $specialize_taint); if ($function_param->assert_untainted) { $input_type = $input_type->setParentNodes([]); $replace_input_type = \true; } } if ($type_match_found && $param_type->hasCallableType()) { $potential_method_ids = []; $param_types_without_callable = array_filter($param_type->getAtomicTypes(), static fn(Atomic $atomic) => !$atomic instanceof Atomic\TCallableInterface); $param_type_without_callable = [] !== $param_types_without_callable ? new Union($param_types_without_callable) : null; foreach ($input_type->getAtomicTypes() as $input_type_part) { if ($input_type_part instanceof TList) { $input_type_part = $input_type_part->getKeyedArray(); } if ($input_type_part instanceof TKeyedArray) { // If the param accept an array, we don't report arrays as wrong callbacks. if (null !== $param_type_without_callable && UnionTypeComparator::isContainedBy($codebase, $input_type, $param_type_without_callable)) { continue; } $potential_method_id = CallableTypeComparator::getCallableMethodIdFromTKeyedArray($input_type_part, $codebase, $context->calling_method_id, $statements_analyzer->getFilePath()); if ($potential_method_id === null && $codebase->analysis_php_version_id >= 80200) { [$lhs] = $input_type_part->properties; if ($lhs->isSingleStringLiteral() && in_array(strtolower($lhs->getSingleStringLiteral()->value), ['self', 'parent', 'static'], \true)) { IssueBuffer::maybeAdd(new DeprecatedConstant('Use of "' . $lhs->getSingleStringLiteral()->value . '" in callables is deprecated', $arg_location), $statements_analyzer->getSuppressedIssues()); } } if ($potential_method_id && $potential_method_id !== 'not-callable') { if (self::verifyCallableInContext($potential_method_id, $cased_method_id, $method_id, $input_type_part, $argument_offset, $arg_location, $context, $codebase, $statements_analyzer) === \false) { continue; } $potential_method_ids[] = $potential_method_id; } } elseif ($input_type_part instanceof TLiteralString && strpos($input_type_part->value, '::')) { // If the param also accept a string, we don't report string as wrong callbacks. if (null !== $param_type_without_callable && UnionTypeComparator::isContainedBy($codebase, $input_type, $param_type_without_callable)) { continue; } $parts = explode('::', $input_type_part->value); /** @psalm-suppress PossiblyUndefinedIntArrayOffset */ $potential_method_id = new MethodIdentifier($parts[0], strtolower($parts[1])); if ($codebase->analysis_php_version_id >= 80200 && in_array(strtolower($potential_method_id->fq_class_name), ['self', 'parent', 'static'], \true)) { IssueBuffer::maybeAdd(new DeprecatedConstant('Use of "' . $potential_method_id->fq_class_name . '" in callables is deprecated', $arg_location), $statements_analyzer->getSuppressedIssues()); } if (self::verifyCallableInContext($potential_method_id, $cased_method_id, $method_id, $input_type_part, $argument_offset, $arg_location, $context, $codebase, $statements_analyzer) === \false) { continue; } $potential_method_ids[] = $potential_method_id; } } foreach ($potential_method_ids as $potential_method_id) { $codebase->methods->methodExists($potential_method_id, $context->calling_method_id, $arg_location, $statements_analyzer, $statements_analyzer->getFilePath(), \true, $context->insideUse()); } } if ($context->strict_types && !$input_type->hasArray() && !$param_type->from_docblock && $cased_method_id !== 'echo' && $cased_method_id !== 'print' && $cased_method_id !== 'sprintf') { $union_comparison_results->scalar_type_match_found = \false; if ($union_comparison_results->to_string_cast) { $union_comparison_results->to_string_cast = \false; $type_match_found = \false; } } if ($union_comparison_results->type_coerced && !$input_type->hasMixed()) { if ($union_comparison_results->type_coerced_from_mixed) { $origin_locations = []; if ($statements_analyzer->data_flow_graph instanceof VariableUseGraph) { foreach ($input_type->parent_nodes as $parent_node) { $origin_locations = [...$origin_locations, ...$statements_analyzer->data_flow_graph->getOriginLocations($parent_node)]; } } $origin_location = count($origin_locations) === 1 ? reset($origin_locations) : null; if ($origin_location && $origin_location->getHash() === $arg_location->getHash()) { $origin_location = null; } IssueBuffer::maybeAdd(new MixedArgumentTypeCoercion('Argument ' . ($argument_offset + 1) . $method_identifier . ' expects ' . $param_type->getId() . ', but parent type ' . $input_type->getId() . ' provided', $arg_location, $cased_method_id, $origin_location), $statements_analyzer->getSuppressedIssues()); } elseif ($cased_method_id !== 'echo' && $cased_method_id !== 'print') { IssueBuffer::maybeAdd(new ArgumentTypeCoercion('Argument ' . ($argument_offset + 1) . $method_identifier . ' expects ' . $param_type->getId() . ', but parent type ' . $input_type->getId() . ' provided', $arg_location, $cased_method_id), $statements_analyzer->getSuppressedIssues()); } } if ($union_comparison_results->to_string_cast && $cased_method_id !== 'echo' && $cased_method_id !== 'print') { IssueBuffer::maybeAdd(new ImplicitToStringCast('Argument ' . ($argument_offset + 1) . $method_identifier . ' expects ' . $param_type->getId() . ', but ' . $input_type->getId() . ' provided with a __toString method', $arg_location), $statements_analyzer->getSuppressedIssues()); } if (!$type_match_found && !$union_comparison_results->type_coerced) { $types_can_be_identical = UnionTypeComparator::canBeContainedBy($codebase, $input_type, $param_type, \true, \true); $type = ($input_type->possibly_undefined ? 'possibly undefined ' : '') . $input_type->getId(); if ($union_comparison_results->scalar_type_match_found) { if ($cased_method_id !== 'echo' && $cased_method_id !== 'print') { IssueBuffer::maybeAdd(new InvalidScalarArgument('Argument ' . ($argument_offset + 1) . $method_identifier . ' expects ' . $param_type->getId() . ', but ' . $type . ' provided', $arg_location, $cased_method_id), $statements_analyzer->getSuppressedIssues()); } } elseif ($types_can_be_identical) { IssueBuffer::maybeAdd(new PossiblyInvalidArgument('Argument ' . ($argument_offset + 1) . $method_identifier . ' expects ' . $param_type->getId() . ', but possibly different type ' . $type . ' provided', $arg_location, $cased_method_id), $statements_analyzer->getSuppressedIssues()); } else { IssueBuffer::maybeAdd(new InvalidArgument('Argument ' . ($argument_offset + 1) . $method_identifier . ' expects ' . $param_type->getId() . ', but ' . $type . ($union_comparison_results->missing_shape_fields ? ' with additional array shape fields (' . implode(', ', $union_comparison_results->missing_shape_fields) . ') was' : '') . ' provided', $arg_location, $cased_method_id), $statements_analyzer->getSuppressedIssues()); } return null; } if ($input_expr instanceof PhpParser\Node\Scalar\String_ || $input_expr instanceof PhpParser\Node\Expr\Array_ || $input_expr instanceof PhpParser\Node\Expr\BinaryOp\Concat) { self::verifyExplicitParam($statements_analyzer, $param_type, $arg_location, $input_expr, $context); return null; } if (!$param_type->isNullable() && $cased_method_id !== 'echo' && $cased_method_id !== 'print') { if ($input_type->isNull()) { IssueBuffer::maybeAdd(new NullArgument('Argument ' . ($argument_offset + 1) . $method_identifier . ' cannot be null, ' . 'null value provided to parameter with type ' . $param_type->getId(), $arg_location, $cased_method_id), $statements_analyzer->getSuppressedIssues()); return null; } if ($input_type->isNullable() && !$input_type->ignore_nullable_issues) { IssueBuffer::maybeAdd(new PossiblyNullArgument('Argument ' . ($argument_offset + 1) . $method_identifier . ' cannot be null, possibly ' . 'null value provided', $arg_location, $cased_method_id), $statements_analyzer->getSuppressedIssues()); } } if (!$param_type->isFalsable() && !$param_type->hasBool() && !$param_type->hasScalar() && $cased_method_id !== 'echo' && $cased_method_id !== 'print') { if ($input_type->isFalse()) { IssueBuffer::maybeAdd(new InvalidArgument('Argument ' . ($argument_offset + 1) . $method_identifier . ' cannot be false, ' . $param_type->getId() . ' value expected', $arg_location, $cased_method_id), $statements_analyzer->getSuppressedIssues()); return null; } if ($input_type->isFalsable() && !$input_type->ignore_falsable_issues) { IssueBuffer::maybeAdd(new PossiblyFalseArgument('Argument ' . ($argument_offset + 1) . $method_identifier . ' cannot be false, possibly ' . $param_type->getId() . ' value expected', $arg_location, $cased_method_id), $statements_analyzer->getSuppressedIssues()); } } if (($type_match_found || $input_type->hasMixed()) && !$function_param->by_ref && !($function_param->is_variadic xor $unpack) && $cased_method_id !== 'echo' && $cased_method_id !== 'print' && (!$in_call_map || $context->strict_types)) { self::coerceValueAfterGatekeeperArgument($statements_analyzer, $input_type, $replace_input_type, $input_expr, $param_type, $signature_param_type, $context, $unpack, $unpacked_atomic_array); } return null; } private static function verifyCallableInContext(MethodIdentifier $potential_method_id, ?string $cased_method_id, ?MethodIdentifier $method_id, Atomic $input_type_part, int $argument_offset, CodeLocation $arg_location, Context $context, Codebase $codebase, StatementsAnalyzer $statements_analyzer) : ?bool { $method_identifier = $cased_method_id !== null ? ' of ' . $cased_method_id : ''; if (!$method_id || $potential_method_id->fq_class_name !== $context->self || $method_id->fq_class_name !== $context->self) { if ($input_type_part instanceof TKeyedArray) { [$lhs] = $input_type_part->properties; } else { $lhs = Type::getString($potential_method_id->fq_class_name); } try { $method_storage = $codebase->methods->getStorage($potential_method_id); $lhs_atomic = $lhs->getSingleAtomic(); if ($lhs->isSingle() && $lhs->hasNamedObjectType() && ($lhs->isStaticObject() || $lhs_atomic instanceof TNamedObject && !$lhs_atomic->definite_class && $lhs_atomic->value === $context->self)) { // callable $this // some PHP-internal functions (e.g. array_filter) will call the callback within the current context // unlike user-defined functions which call the callback in their context // however this doesn't apply to all // e.g. header_register_callback will not throw an error immediately like user-land functions // however error log "Could not call the sapi_header_callback" if it's not public // this is NOT a complete list, but just what was easily available and to be extended $php_native_non_public_cb = ['array_diff_uassoc', 'array_diff_ukey', 'array_filter', 'array_intersect_uassoc', 'array_intersect_ukey', 'array_map', 'array_reduce', 'array_udiff', 'array_udiff_assoc', 'array_udiff_uassoc', 'array_uintersect', 'array_uintersect_assoc', 'array_uintersect_uassoc', 'array_walk', 'array_walk_recursive', 'preg_replace_callback', 'preg_replace_callback_array', 'call_user_func', 'call_user_func_array', 'forward_static_call', 'forward_static_call_array', 'is_callable', 'ob_start', 'register_shutdown_function', 'register_tick_function', 'session_set_save_handler', 'set_error_handler', 'set_exception_handler', 'spl_autoload_register', 'spl_autoload_unregister', 'uasort', 'uksort', 'usort']; if ($potential_method_id->fq_class_name !== $context->self || $cased_method_id !== null && !$method_id && !in_array($cased_method_id, $php_native_non_public_cb, \true) || $method_id && $method_id->fq_class_name !== $context->self && $method_id->fq_class_name !== 'Closure') { if ($method_storage->visibility !== ClassLikeAnalyzer::VISIBILITY_PUBLIC) { IssueBuffer::maybeAdd(new InvalidArgument('Argument ' . ($argument_offset + 1) . $method_identifier . ' expects a public callable, but a non-public callable provided', $arg_location, $cased_method_id), $statements_analyzer->getSuppressedIssues()); return \false; } } } elseif ($lhs->isSingle()) { // instance from e.g. new Foo() or static string like Foo::bar if (!$method_storage->is_static && !$lhs->hasNamedObjectType() || $method_storage->visibility !== ClassLikeAnalyzer::VISIBILITY_PUBLIC) { IssueBuffer::maybeAdd(new InvalidArgument('Argument ' . ($argument_offset + 1) . $method_identifier . ' expects a public static callable, but a ' . ($method_storage->visibility !== ClassLikeAnalyzer::VISIBILITY_PUBLIC ? 'non-public ' : '') . (!$method_storage->is_static ? 'non-static ' : '') . 'callable provided', $arg_location, $cased_method_id), $statements_analyzer->getSuppressedIssues()); return \false; } } } catch (UnexpectedValueException $e) { // do nothing } } return null; } /** * @param PhpParser\Node\Scalar\String_|PhpParser\Node\Expr\Array_|PhpParser\Node\Expr\BinaryOp\Concat $input_expr */ private static function verifyExplicitParam(StatementsAnalyzer $statements_analyzer, Union $param_type, CodeLocation $arg_location, PhpParser\Node\Expr $input_expr, Context $context) : void { $codebase = $statements_analyzer->getCodebase(); foreach ($param_type->getAtomicTypes() as $param_type_part) { if ($param_type_part instanceof TClassString && $input_expr instanceof PhpParser\Node\Scalar\String_ && $param_type->isSingle()) { if (ClassLikeAnalyzer::checkFullyQualifiedClassLikeName($statements_analyzer, $input_expr->value, $arg_location, $context->self, $context->calling_method_id, $statements_analyzer->getSuppressedIssues(), new ClassLikeNameOptions(\true)) === \false) { return; } } elseif ($param_type_part instanceof TArray && $input_expr instanceof PhpParser\Node\Expr\Array_) { foreach ($param_type_part->type_params[1]->getAtomicTypes() as $param_array_type_part) { if ($param_array_type_part instanceof TClassString) { foreach ($input_expr->items as $item) { if ($item && $item->value instanceof PhpParser\Node\Scalar\String_) { if (ClassLikeAnalyzer::checkFullyQualifiedClassLikeName($statements_analyzer, $item->value->value, $arg_location, $context->self, $context->calling_method_id, $statements_analyzer->getSuppressedIssues(), new ClassLikeNameOptions(\true)) === \false) { return; } } } } } } elseif ($param_type_part instanceof TCallable) { $can_be_callable_like_array = \false; if ($param_type->hasArray()) { $param_array_type = $param_type->getArray(); $row_type = null; if ($param_array_type instanceof TArray) { $row_type = $param_array_type->type_params[1]; } elseif ($param_array_type instanceof TKeyedArray) { $row_type = $param_array_type->getGenericValueType(); } if ($row_type && ($row_type->hasMixed() || $row_type->hasString())) { $can_be_callable_like_array = \true; } } if (!$can_be_callable_like_array) { $function_ids = CallAnalyzer::getFunctionIdsFromCallableArg($statements_analyzer, $input_expr); foreach ($function_ids as $function_id) { if (strpos($function_id, '::') !== \false) { if ($function_id[0] === '$') { $function_id = substr($function_id, 1); } $function_id_parts = explode('&', $function_id); $non_existent_method_ids = []; foreach ($function_id_parts as $function_id_part) { [$callable_fq_class_name, $method_name] = explode('::', $function_id_part); switch ($callable_fq_class_name) { case 'self': case 'static': case 'parent': $container_class = $statements_analyzer->getFQCLN(); if ($callable_fq_class_name === 'parent') { $container_class = $statements_analyzer->getParentFQCLN(); if ($container_class === null) { IssueBuffer::accepts(new ParentNotFound('Cannot call method on parent' . ' as this class does not extend another', $arg_location), $statements_analyzer->getSuppressedIssues()); } } if (!$container_class) { continue 2; } $callable_fq_class_name = $container_class; } if (ClassLikeAnalyzer::checkFullyQualifiedClassLikeName($statements_analyzer, $callable_fq_class_name, $arg_location, $context->self, $context->calling_method_id, $statements_analyzer->getSuppressedIssues(), new ClassLikeNameOptions(\true)) === \false) { return; } $function_id_part = new MethodIdentifier($callable_fq_class_name, strtolower($method_name)); $call_method_id = new MethodIdentifier($callable_fq_class_name, '__call'); if (!$codebase->classOrInterfaceOrEnumExists($callable_fq_class_name)) { return; } if (!$codebase->methods->methodExists($function_id_part) && !$codebase->methods->methodExists($call_method_id)) { $non_existent_method_ids[] = $function_id_part; } } if ($non_existent_method_ids && !$param_type->hasString() && !$param_type->hasArray()) { if (MethodAnalyzer::checkMethodExists($codebase, $non_existent_method_ids[0], $arg_location, $statements_analyzer->getSuppressedIssues()) === \false) { return; } } } else { if (!$param_type->hasString() && !$param_type->hasArray() && $context->check_functions && CallAnalyzer::checkFunctionExists($statements_analyzer, $function_id, $arg_location, \false) === \false) { return; } } } } } } } /** * @param TKeyedArray|TArray|TClassStringMap $unpacked_atomic_array */ private static function coerceValueAfterGatekeeperArgument(StatementsAnalyzer $statements_analyzer, Union $input_type, bool $input_type_changed, PhpParser\Node\Expr $input_expr, Union $param_type, ?Union $signature_param_type, Context $context, bool $unpack, ?Atomic $unpacked_atomic_array) : void { if ($param_type->hasMixed()) { return; } if (!$input_type_changed && $param_type->from_docblock && !$input_type->hasMixed()) { $types = $input_type->getAtomicTypes(); foreach ($param_type->getAtomicTypes() as $param_atomic_type) { if ($param_atomic_type instanceof TGenericObject) { foreach ($types as &$input_atomic_type) { if ($input_atomic_type instanceof TGenericObject && $input_atomic_type->value === $param_atomic_type->value) { $new_type_params = []; foreach ($input_atomic_type->type_params as $i => $type_param) { if ($type_param->isNever() && isset($param_atomic_type->type_params[$i])) { $input_type_changed = \true; $new_type_params[$i] = $param_atomic_type->type_params[$i]; } } if ($new_type_params) { $input_atomic_type = new TGenericObject($input_atomic_type->value, [...$input_atomic_type->type_params, ...$new_type_params], $input_atomic_type->remapped_params, \false, $input_atomic_type->extra_types); } } } unset($input_atomic_type); } } if (!$input_type_changed) { return; } $input_type = new Union($types); } $var_id = ExpressionIdentifier::getVarId($input_expr, $statements_analyzer->getFQCLN(), $statements_analyzer); if ($var_id) { $was_cloned = \false; if ($input_type->isNullable() && !$param_type->isNullable()) { $input_type = $input_type->getBuilder(); $was_cloned = \true; $input_type->removeType('null'); $input_type = $input_type->freeze(); } if ($input_type->getId() === $param_type->getId()) { if ($input_type->from_docblock) { $input_type = $input_type->setFromDocblock(\false); } } elseif ($input_type->hasMixed() && $signature_param_type) { $was_cloned = \true; $parent_nodes = $input_type->parent_nodes; $by_ref = $input_type->by_ref; $input_type = $signature_param_type->setProperties(['ignore_nullable_issues' => $signature_param_type->isNullable(), 'parent_nodes' => $parent_nodes, 'by_ref' => $by_ref]); } if ($context->inside_conditional && !isset($context->assigned_var_ids[$var_id])) { $context->assigned_var_ids[$var_id] = 0; } if ($was_cloned) { $context->removeVarFromConflictingClauses($var_id, null, $statements_analyzer); } if ($unpack) { if ($unpacked_atomic_array instanceof TArray) { $unpacked_atomic_array = $unpacked_atomic_array->setTypeParams([$unpacked_atomic_array->type_params[0], $input_type]); $context->vars_in_scope[$var_id] = new Union([$unpacked_atomic_array]); } elseif ($unpacked_atomic_array instanceof TKeyedArray && $unpacked_atomic_array->is_list) { if ($unpacked_atomic_array->isNonEmpty()) { $unpacked_atomic_array = Type::getNonEmptyListAtomic($input_type); } else { $unpacked_atomic_array = Type::getListAtomic($input_type); } $context->vars_in_scope[$var_id] = new Union([$unpacked_atomic_array]); } else { $context->vars_in_scope[$var_id] = new Union([new TArray([Type::getInt(), $input_type])]); } } else { $context->vars_in_scope[$var_id] = $input_type; } } } private static function processTaintedness(StatementsAnalyzer $statements_analyzer, string $cased_method_id, ?MethodIdentifier $method_id, int $argument_offset, CodeLocation $arg_location, CodeLocation $function_call_location, FunctionLikeParameter $function_param, Union $input_type, PhpParser\Node\Expr $expr, Context $context, bool $specialize_taint) : void { $codebase = $statements_analyzer->getCodebase(); if (!$statements_analyzer->data_flow_graph || $statements_analyzer->data_flow_graph instanceof TaintFlowGraph && in_array('TaintedInput', $statements_analyzer->getSuppressedIssues())) { return; } // literal data can’t be tainted if ($statements_analyzer->data_flow_graph instanceof TaintFlowGraph && $input_type->isSingle() && $input_type->hasLiteralValue()) { return; } // numeric types can't be tainted, neither can bool if ($statements_analyzer->data_flow_graph instanceof TaintFlowGraph && $input_type->isSingle() && ($input_type->isInt() || $input_type->isFloat() || $input_type->isBool())) { return; } $event = new AddRemoveTaintsEvent($expr, $context, $statements_analyzer, $codebase); $added_taints = $codebase->config->eventDispatcher->dispatchAddTaints($event); $removed_taints = $codebase->config->eventDispatcher->dispatchRemoveTaints($event); if ($function_param->type && $function_param->type->isString() && !$input_type->isString()) { $input_type = CastAnalyzer::castStringAttempt($statements_analyzer, $context, $input_type, $expr, \false); } if ($specialize_taint) { $method_node = DataFlowNode::getForMethodArgument($cased_method_id, $cased_method_id, $argument_offset, $statements_analyzer->data_flow_graph instanceof TaintFlowGraph ? $function_param->location : null, $function_call_location); } else { $method_node = DataFlowNode::getForMethodArgument($cased_method_id, $cased_method_id, $argument_offset, $statements_analyzer->data_flow_graph instanceof TaintFlowGraph ? $function_param->location : null); if ($statements_analyzer->data_flow_graph instanceof TaintFlowGraph && $method_id && $method_id->method_name !== '__construct') { $fq_classlike_name = $method_id->fq_class_name; $method_name = $method_id->method_name; $cased_method_name = explode('::', $cased_method_id)[1]; $class_storage = $codebase->classlike_storage_provider->get($fq_classlike_name); foreach ($class_storage->dependent_classlikes as $dependent_classlike_lc => $_) { $dependent_classlike_storage = $codebase->classlike_storage_provider->get($dependent_classlike_lc); $new_sink = DataFlowNode::getForMethodArgument($dependent_classlike_lc . '::' . $method_name, $dependent_classlike_storage->name . '::' . $cased_method_name, $argument_offset, $arg_location, null); $statements_analyzer->data_flow_graph->addNode($new_sink); $statements_analyzer->data_flow_graph->addPath($method_node, $new_sink, 'arg', $added_taints, $removed_taints); } } } if ($method_id && $statements_analyzer->data_flow_graph instanceof TaintFlowGraph) { $declaring_method_id = $codebase->methods->getDeclaringMethodId($method_id); if ($declaring_method_id && (string) $declaring_method_id !== (string) $method_id) { $new_sink = DataFlowNode::getForMethodArgument((string) $declaring_method_id, $codebase->methods->getCasedMethodId($declaring_method_id), $argument_offset, $arg_location, null); $statements_analyzer->data_flow_graph->addNode($new_sink); $statements_analyzer->data_flow_graph->addPath($method_node, $new_sink, 'arg', $added_taints, $removed_taints); } } $statements_analyzer->data_flow_graph->addNode($method_node); $argument_value_node = DataFlowNode::getForAssignment('call to ' . $cased_method_id, $arg_location); $statements_analyzer->data_flow_graph->addNode($argument_value_node); $statements_analyzer->data_flow_graph->addPath($argument_value_node, $method_node, 'arg', $added_taints, $removed_taints); foreach ($input_type->parent_nodes as $parent_node) { $statements_analyzer->data_flow_graph->addNode($method_node); $statements_analyzer->data_flow_graph->addPath($parent_node, $argument_value_node, 'arg', $added_taints, $removed_taints); } } } name; $codebase = $statements_analyzer->getCodebase(); $code_location = new CodeLocation($statements_analyzer->getSource(), $stmt); $config = $codebase->config; $is_first_class_callable = $stmt->isFirstClassCallable(); $real_stmt = $stmt; if ($function_name instanceof PhpParser\Node\Name && !$is_first_class_callable && isset($stmt->getArgs()[0]) && !$stmt->getArgs()[0]->unpack) { $original_function_id = implode('\\', $function_name->getParts()); if ($original_function_id === 'call_user_func') { $other_args = array_slice($stmt->getArgs(), 1); $function_name = $stmt->getArgs()[0]->value; $stmt = new VirtualFuncCall($function_name, $other_args, $stmt->getAttributes()); } if ($original_function_id === 'call_user_func_array' && isset($stmt->getArgs()[1])) { $function_name = $stmt->getArgs()[0]->value; $stmt = new VirtualFuncCall($function_name, [new VirtualArg($stmt->getArgs()[1]->value, \false, \true)], $stmt->getAttributes()); } } if ($function_name instanceof PhpParser\Node\Expr) { $function_call_info = self::getAnalyzeNamedExpression($statements_analyzer, $stmt, $real_stmt, $function_name, $context); if ($function_call_info->function_exists === \false) { return \true; } if ($function_call_info->new_function_name) { $function_name = $function_call_info->new_function_name; } } else { $function_call_info = self::handleNamedFunction($statements_analyzer, $stmt, $function_name, $context, $code_location); if (!$function_call_info->function_exists) { return \true; } } $set_inside_conditional = \false; if ($function_name instanceof PhpParser\Node\Name && $function_name->getParts() === ['assert'] && !$context->inside_conditional) { $context->inside_conditional = \true; $set_inside_conditional = \true; } if (!$template_result) { $template_result = new TemplateResult([], []); } if (!$is_first_class_callable) { if (isset($function_call_info->function_storage->template_types)) { $template_result->template_types += $function_call_info->function_storage->template_types ?: []; } \Psalm\Internal\Analyzer\Statements\Expression\Call\ArgumentsAnalyzer::analyze($statements_analyzer, $stmt->getArgs(), $function_call_info->function_params, $function_call_info->function_id, $function_call_info->allow_named_args, $context, $template_result); } if ($set_inside_conditional) { $context->inside_conditional = \false; } $function_callable = null; if (!$is_first_class_callable && $function_name instanceof PhpParser\Node\Name && $function_call_info->function_id) { if (!$function_call_info->is_stubbed && $function_call_info->in_call_map) { $function_callable = InternalCallMapHandler::getCallableFromCallMapById($codebase, $function_call_info->function_id, $stmt->getArgs(), $statements_analyzer->node_data); if (!$codebase->functions->params_provider->has($function_call_info->function_id)) { $function_call_info->function_params = $function_callable->params; } } } $already_inferred_lower_bounds = $template_result->lower_bounds; $template_result = new TemplateResult([], []); // do this here to allow closure param checks if (!$is_first_class_callable && $function_call_info->function_params !== null) { \Psalm\Internal\Analyzer\Statements\Expression\Call\ArgumentsAnalyzer::checkArgumentsMatch($statements_analyzer, $stmt->getArgs(), $function_call_info->function_id, $function_call_info->function_params, $function_call_info->function_storage, null, $template_result, $code_location, $context); } CallAnalyzer::checkTemplateResult($statements_analyzer, $template_result, $code_location, $function_call_info->function_id); $template_result->lower_bounds = array_merge($template_result->lower_bounds, $already_inferred_lower_bounds); if ($function_name instanceof PhpParser\Node\Name && $function_call_info->function_id) { $stmt_type = \Psalm\Internal\Analyzer\Statements\Expression\Call\FunctionCallReturnTypeFetcher::fetch($statements_analyzer, $codebase, $stmt, $function_name, $function_call_info->function_id, $function_call_info->in_call_map, $function_call_info->is_stubbed, $function_call_info->function_storage, $function_callable, $template_result, $context); $statements_analyzer->node_data->setType($real_stmt, $stmt_type); if ($stmt_type->isNever()) { $context->has_returned = \true; } $event = new AfterEveryFunctionCallAnalysisEvent($stmt, $function_call_info->function_id, $context, $statements_analyzer->getSource(), $codebase); $config->eventDispatcher->dispatchAfterEveryFunctionCallAnalysis($event); if ($is_first_class_callable) { return \true; } } if ($is_first_class_callable) { $type_provider = $statements_analyzer->getNodeTypeProvider(); $closure_types = []; if ($input_type = $type_provider->getType($function_name)) { foreach ($input_type->getAtomicTypes() as $atomic_type) { $candidate_callable = CallableTypeComparator::getCallableFromAtomic($codebase, $atomic_type, null, $statements_analyzer); if ($candidate_callable) { $closure_types[] = new TClosure('Closure', $candidate_callable->params, $candidate_callable->return_type, $candidate_callable->is_pure); } } } if ($closure_types) { $stmt_type = TypeCombiner::combine($closure_types, $codebase); } else { $stmt_type = Type::getClosure(); } $statements_analyzer->node_data->setType($real_stmt, $stmt_type); return \true; } foreach ($function_call_info->defined_constants as $const_name => $const_type) { $context->constants[$const_name] = $const_type; $context->vars_in_scope[$const_name] = $const_type; } foreach ($function_call_info->global_variables as $var_id => $_) { $context->vars_in_scope[$var_id] = Type::getMixed(); $context->vars_possibly_in_scope[$var_id] = \true; } if ($function_name instanceof PhpParser\Node\Name && $function_name->getParts() === ['assert'] && isset($stmt->getArgs()[0])) { self::processAssertFunctionEffects($statements_analyzer, $codebase, $stmt, $stmt->getArgs()[0], $context); } if ($codebase->store_node_types && !$context->collect_initializations && !$context->collect_mutations && ($stmt_type = $statements_analyzer->node_data->getType($real_stmt))) { $codebase->analyzer->addNodeType($statements_analyzer->getFilePath(), $stmt, $stmt_type->getId()); } self::checkFunctionCallPurity($statements_analyzer, $codebase, $stmt, $function_name, $function_call_info, $context); if ($function_call_info->function_storage) { if ($function_call_info->function_storage->assertions && $function_name instanceof PhpParser\Node\Name) { self::applyAssertionsToContext($function_name, null, $function_call_info->function_storage->assertions, $stmt->getArgs(), $template_result, $context, $statements_analyzer); } if ($function_call_info->function_storage->if_true_assertions) { $statements_analyzer->node_data->setIfTrueAssertions($stmt, array_map(static fn(Possibilities $assertion): Possibilities => $assertion->getUntemplatedCopy($template_result, null, $codebase), $function_call_info->function_storage->if_true_assertions)); } if ($function_call_info->function_storage->if_false_assertions) { $statements_analyzer->node_data->setIfFalseAssertions($stmt, array_map(static fn(Possibilities $assertion): Possibilities => $assertion->getUntemplatedCopy($template_result, null, $codebase), $function_call_info->function_storage->if_false_assertions)); } if ($function_call_info->function_storage->deprecated && $function_call_info->function_id) { IssueBuffer::maybeAdd(new DeprecatedFunction('The function ' . $function_call_info->function_id . ' has been marked as deprecated', $code_location, $function_call_info->function_id), $statements_analyzer->getSuppressedIssues()); } } if ($function_name instanceof PhpParser\Node\Name && $function_call_info->function_id) { \Psalm\Internal\Analyzer\Statements\Expression\Call\NamedFunctionCallHandler::handle($statements_analyzer, $codebase, $stmt, $real_stmt, $function_name, strtolower($function_call_info->function_id), $context); } if (!$statements_analyzer->node_data->getType($real_stmt)) { $statements_analyzer->node_data->setType($real_stmt, Type::getMixed()); } return \true; } private static function handleNamedFunction(StatementsAnalyzer $statements_analyzer, PhpParser\Node\Expr\FuncCall $stmt, PhpParser\Node\Name $function_name, Context $context, CodeLocation $code_location) : \Psalm\Internal\Analyzer\Statements\Expression\Call\FunctionCallInfo { $function_call_info = new \Psalm\Internal\Analyzer\Statements\Expression\Call\FunctionCallInfo(); $codebase = $statements_analyzer->getCodebase(); $codebase_functions = $codebase->functions; $original_function_id = $function_name->toString(); if (!$function_name instanceof PhpParser\Node\Name\FullyQualified) { $function_call_info->function_id = $codebase_functions->getFullyQualifiedFunctionNameFromString($original_function_id, $statements_analyzer); } else { $function_call_info->function_id = $original_function_id; } $namespaced_function_exists = $codebase_functions->functionExists($statements_analyzer, strtolower($function_call_info->function_id)); if (!$namespaced_function_exists && !$function_name instanceof PhpParser\Node\Name\FullyQualified) { $function_call_info->in_call_map = InternalCallMapHandler::inCallMap($original_function_id); $function_call_info->is_stubbed = $codebase_functions->hasStubbedFunction($original_function_id); if ($function_call_info->is_stubbed || $function_call_info->in_call_map) { $function_call_info->function_id = $original_function_id; } } else { $function_call_info->in_call_map = InternalCallMapHandler::inCallMap($function_call_info->function_id); $function_call_info->is_stubbed = $codebase_functions->hasStubbedFunction($function_call_info->function_id); } $function_call_info->function_exists = $function_call_info->is_stubbed || $function_call_info->in_call_map || $namespaced_function_exists; if ($function_call_info->function_exists && !$stmt->isFirstClassCallable() && $codebase->store_node_types && !$context->collect_initializations && !$context->collect_mutations) { \Psalm\Internal\Analyzer\Statements\Expression\Call\ArgumentMapPopulator::recordArgumentPositions($statements_analyzer, $stmt, $codebase, $function_call_info->function_id); } $is_predefined = \true; $is_maybe_root_function = !$function_name instanceof PhpParser\Node\Name\FullyQualified && count($function_name->getParts()) === 1; $args = $stmt->isFirstClassCallable() ? [] : $stmt->getArgs(); if (!$function_call_info->in_call_map) { $predefined_functions = $codebase->config->getPredefinedFunctions(); $is_predefined = isset($predefined_functions[strtolower($original_function_id)]) || isset($predefined_functions[strtolower($function_call_info->function_id)]); if ($context->check_functions) { if (self::checkFunctionExists($statements_analyzer, $function_call_info->function_id, $code_location, $is_maybe_root_function) === \false) { if ($args) { \Psalm\Internal\Analyzer\Statements\Expression\Call\ArgumentsAnalyzer::analyze($statements_analyzer, $args, null, null, \true, $context); } return $function_call_info; } $function_call_info->function_exists = \true; } } else { $function_call_info->function_exists = \true; } $function_call_info->function_params = null; $function_call_info->defined_constants = []; $function_call_info->global_variables = []; $args = $stmt->isFirstClassCallable() ? [] : $stmt->getArgs(); $dynamic_function_storage = null; if ($codebase->functions->dynamic_storage_provider->has($function_call_info->function_id)) { $dynamic_function_storage = $codebase->functions->dynamic_storage_provider->getFunctionStorage($stmt, $statements_analyzer, $function_call_info->function_id, $context, $code_location); } if ($function_call_info->function_exists) { if ($dynamic_function_storage) { $function_call_info->function_storage = $dynamic_function_storage; $function_call_info->function_params = $dynamic_function_storage->params; $function_call_info->allow_named_args = $dynamic_function_storage->allow_named_arg_calls; $function_call_info->defined_constants = $dynamic_function_storage->defined_constants; $function_call_info->global_variables = $dynamic_function_storage->global_variables; } elseif (!$function_call_info->in_call_map || $function_call_info->is_stubbed) { try { $function_call_info->function_storage = $function_storage = $codebase_functions->getStorage($statements_analyzer, strtolower($function_call_info->function_id)); $function_call_info->function_params = $function_call_info->function_storage->params; if (!$function_storage->allow_named_arg_calls) { $function_call_info->allow_named_args = \false; } if (!$is_predefined) { $function_call_info->defined_constants = $function_storage->defined_constants; $function_call_info->global_variables = $function_storage->global_variables; } } catch (UnexpectedValueException $e) { $function_call_info->function_params = [new FunctionLikeParameter('args', \false, null, null, null, null, \false, \false, \true)]; } } else { $function_callable = InternalCallMapHandler::getCallableFromCallMapById($codebase, $function_call_info->function_id, $args, $statements_analyzer->node_data); $function_call_info->function_params = $function_callable->params; } if ($codebase->functions->params_provider->has($function_call_info->function_id)) { $function_call_info->function_params = $codebase->functions->params_provider->getFunctionParams($statements_analyzer, $function_call_info->function_id, $args, $context, $code_location); } if ($codebase->store_node_types && !$context->collect_initializations && !$context->collect_mutations) { $codebase->analyzer->addNodeReference($statements_analyzer->getFilePath(), $function_name, $function_call_info->function_id . '()'); } } return $function_call_info; } private static function getAnalyzeNamedExpression(StatementsAnalyzer $statements_analyzer, PhpParser\Node\Expr\FuncCall $stmt, PhpParser\Node\Expr\FuncCall $real_stmt, PhpParser\Node\Expr $function_name, Context $context) : \Psalm\Internal\Analyzer\Statements\Expression\Call\FunctionCallInfo { $function_call_info = new \Psalm\Internal\Analyzer\Statements\Expression\Call\FunctionCallInfo(); $codebase = $statements_analyzer->getCodebase(); $was_in_call = $context->inside_call; $context->inside_call = \true; if (ExpressionAnalyzer::analyze($statements_analyzer, $function_name, $context) === \false) { $context->inside_call = $was_in_call; return $function_call_info; } $context->inside_call = $was_in_call; $function_call_info->byref_uses = []; if ($stmt_name_type = $statements_analyzer->node_data->getType($function_name)) { if ($stmt_name_type->isNull()) { IssueBuffer::maybeAdd(new NullFunctionCall('Cannot call function on null value', new CodeLocation($statements_analyzer->getSource(), $stmt)), $statements_analyzer->getSuppressedIssues()); return $function_call_info; } if ($stmt_name_type->isNullable()) { IssueBuffer::maybeAdd(new PossiblyNullFunctionCall('Cannot call function on possibly null value', new CodeLocation($statements_analyzer->getSource(), $stmt)), $statements_analyzer->getSuppressedIssues()); } $invalid_function_call_types = []; $has_valid_function_call_type = \false; $var_atomic_types = $stmt_name_type->getAtomicTypes(); while ($var_atomic_types) { $var_type_part = array_shift($var_atomic_types); if ($var_type_part instanceof TTemplateParam) { $var_atomic_types = array_merge($var_atomic_types, $var_type_part->as->getAtomicTypes()); continue; } if ($var_type_part instanceof TList) { $var_type_part = $var_type_part->getKeyedArray(); } if ($var_type_part instanceof TClosure || $var_type_part instanceof TCallable) { if (!$var_type_part->is_pure) { if ($context->pure || $context->mutation_free) { IssueBuffer::maybeAdd(new ImpureFunctionCall('Cannot call an impure function from a mutation-free context', new CodeLocation($statements_analyzer->getSource(), $stmt)), $statements_analyzer->getSuppressedIssues()); } if (!$function_call_info->function_storage) { $function_call_info->function_storage = new FunctionStorage(); } $function_call_info->function_storage->pure = \false; $function_call_info->function_storage->mutation_free = \false; } $function_call_info->function_params = $var_type_part->params; if (($stmt_type = $statements_analyzer->node_data->getType($real_stmt)) && $var_type_part->return_type) { $statements_analyzer->node_data->setType($real_stmt, Type::combineUnionTypes($stmt_type, $var_type_part->return_type)); } else { $statements_analyzer->node_data->setType($real_stmt, $var_type_part->return_type ?? Type::getMixed()); } if ($var_type_part instanceof TClosure) { $function_call_info->byref_uses += $var_type_part->byref_uses; } $function_call_info->function_exists = \true; $has_valid_function_call_type = \true; } elseif ($var_type_part instanceof TMixed) { $has_valid_function_call_type = \true; IssueBuffer::maybeAdd(new MixedFunctionCall('Cannot call function on ' . $var_type_part->getId(), new CodeLocation($statements_analyzer->getSource(), $stmt)), $statements_analyzer->getSuppressedIssues()); } elseif ($var_type_part instanceof TCallableObject) { $has_valid_function_call_type = \true; self::analyzeInvokeCall($statements_analyzer, $stmt, $real_stmt, $function_name, $context, $var_type_part); } elseif ($var_type_part instanceof TCallableString || $var_type_part instanceof TNamedObject && $var_type_part->value === 'Closure' || $var_type_part instanceof TObjectWithProperties && isset($var_type_part->methods['__invoke'])) { // this is fine $has_valid_function_call_type = \true; } elseif ($var_type_part instanceof TString || $var_type_part instanceof TArray || $var_type_part instanceof TKeyedArray && count($var_type_part->properties) === 2) { $potential_method_id = null; if ($var_type_part instanceof TKeyedArray) { $potential_method_id = CallableTypeComparator::getCallableMethodIdFromTKeyedArray($var_type_part, $codebase, $context->calling_method_id, $statements_analyzer->getFilePath()); if ($potential_method_id === 'not-callable') { $potential_method_id = null; } } elseif ($var_type_part instanceof TLiteralString) { if (!$var_type_part->value) { $invalid_function_call_types[] = '\'\''; continue; } if (strpos($var_type_part->value, '::')) { $parts = explode('::', strtolower($var_type_part->value)); $fq_class_name = $parts[0]; $fq_class_name = preg_replace('/^\\\\/', '', $fq_class_name, 1); $potential_method_id = new MethodIdentifier($fq_class_name, $parts[1]); } else { $function_call_info->new_function_name = new VirtualFullyQualified($var_type_part->value, $function_name->getAttributes()); } } if ($potential_method_id) { $codebase->methods->methodExists($potential_method_id, $context->calling_method_id, null, $statements_analyzer, $statements_analyzer->getFilePath()); } // this is also kind of fine $has_valid_function_call_type = \true; } elseif ($var_type_part instanceof TNull) { // handled above } elseif (!$var_type_part instanceof TNamedObject || !$codebase->classlikes->classOrInterfaceExists($var_type_part->value) || !$codebase->methods->methodExists(new MethodIdentifier($var_type_part->value, '__invoke'))) { $invalid_function_call_types[] = (string) $var_type_part; } else { self::analyzeInvokeCall($statements_analyzer, $stmt, $real_stmt, $function_name, $context, $var_type_part); } } if ($invalid_function_call_types) { $var_type_part = reset($invalid_function_call_types); if ($has_valid_function_call_type) { IssueBuffer::maybeAdd(new PossiblyInvalidFunctionCall('Cannot treat type ' . $var_type_part . ' as callable', new CodeLocation($statements_analyzer->getSource(), $stmt)), $statements_analyzer->getSuppressedIssues()); } else { IssueBuffer::maybeAdd(new InvalidFunctionCall('Cannot treat type ' . $var_type_part . ' as callable', new CodeLocation($statements_analyzer->getSource(), $stmt)), $statements_analyzer->getSuppressedIssues()); } return $function_call_info; } if ($statements_analyzer->data_flow_graph instanceof TaintFlowGraph && $stmt_name_type->parent_nodes && !in_array('TaintedInput', $statements_analyzer->getSuppressedIssues())) { $arg_location = new CodeLocation($statements_analyzer->getSource(), $function_name); $custom_call_sink = TaintSink::getForMethodArgument('variable-call', 'variable-call', 0, $arg_location, $arg_location); $custom_call_sink->taints = [TaintKind::INPUT_CALLABLE]; $statements_analyzer->data_flow_graph->addSink($custom_call_sink); $event = new AddRemoveTaintsEvent($stmt, $context, $statements_analyzer, $codebase); $added_taints = $codebase->config->eventDispatcher->dispatchAddTaints($event); $removed_taints = $codebase->config->eventDispatcher->dispatchRemoveTaints($event); foreach ($stmt_name_type->parent_nodes as $parent_node) { $statements_analyzer->data_flow_graph->addPath($parent_node, $custom_call_sink, 'call', $added_taints, $removed_taints); } } } if (!$statements_analyzer->node_data->getType($real_stmt)) { $statements_analyzer->node_data->setType($real_stmt, Type::getMixed()); } return $function_call_info; } private static function analyzeInvokeCall(StatementsAnalyzer $statements_analyzer, PhpParser\Node\Expr\FuncCall $stmt, PhpParser\Node\Expr\FuncCall $real_stmt, PhpParser\Node\Expr $function_name, Context $context, Atomic $atomic_type) : void { $old_data_provider = $statements_analyzer->node_data; $statements_analyzer->node_data = clone $statements_analyzer->node_data; $fake_method_call = new VirtualMethodCall($function_name, new VirtualIdentifier('__invoke', $function_name->getAttributes()), $stmt->args); $suppressed_issues = $statements_analyzer->getSuppressedIssues(); if (!in_array('InternalMethod', $suppressed_issues, \true)) { $statements_analyzer->addSuppressedIssues(['InternalMethod']); } $statements_analyzer->node_data->setType($function_name, new Union([$atomic_type])); \Psalm\Internal\Analyzer\Statements\Expression\Call\MethodCallAnalyzer::analyze($statements_analyzer, $fake_method_call, $context, \false); if (!in_array('InternalMethod', $suppressed_issues, \true)) { $statements_analyzer->removeSuppressedIssues(['InternalMethod']); } $fake_method_call_type = $statements_analyzer->node_data->getType($fake_method_call); $statements_analyzer->node_data = $old_data_provider; if ($stmt_type = $statements_analyzer->node_data->getType($real_stmt)) { $statements_analyzer->node_data->setType($real_stmt, Type::combineUnionTypes($fake_method_call_type ?? Type::getMixed(), $stmt_type)); } else { $statements_analyzer->node_data->setType($real_stmt, $fake_method_call_type ?? Type::getMixed()); } } private static function processAssertFunctionEffects(StatementsAnalyzer $statements_analyzer, Codebase $codebase, PhpParser\Node\Expr\FuncCall $stmt, PhpParser\Node\Arg $first_arg, Context $context) : void { $first_arg_value_id = spl_object_id($first_arg->value); $assert_clauses = FormulaGenerator::getFormula($first_arg_value_id, $first_arg_value_id, $first_arg->value, $context->self, $statements_analyzer, $codebase); AlgebraAnalyzer::checkForParadox($context->clauses, $assert_clauses, $statements_analyzer, $stmt, []); $simplified_clauses = Algebra::simplifyCNF([...$context->clauses, ...$assert_clauses]); $assert_type_assertions = Algebra::getTruthsFromFormula($simplified_clauses); $changed_var_ids = []; if ($assert_type_assertions) { // while in an and, we allow scope to boil over to support // statements of the form if ($x && $x->foo()) [$op_vars_in_scope, $op_references_in_scope] = Reconciler::reconcileKeyedTypes($assert_type_assertions, $assert_type_assertions, $context->vars_in_scope, $context->references_in_scope, $changed_var_ids, array_map(static fn($_): bool => \true, $assert_type_assertions), $statements_analyzer, $statements_analyzer->getTemplateTypeMap() ?: [], $context->inside_loop, new CodeLocation($statements_analyzer->getSource(), $stmt)); foreach ($changed_var_ids as $var_id => $_) { $first_appearance = $statements_analyzer->getFirstAppearance($var_id); if ($first_appearance && isset($context->vars_in_scope[$var_id]) && $context->vars_in_scope[$var_id]->hasMixed()) { if (!$context->collect_initializations && !$context->collect_mutations && $statements_analyzer->getFilePath() === $statements_analyzer->getRootFilePath() && (!($parent_source = $statements_analyzer->getSource()) instanceof FunctionLikeAnalyzer || !$parent_source->getSource() instanceof TraitAnalyzer)) { $codebase->analyzer->decrementMixedCount($statements_analyzer->getFilePath()); } IssueBuffer::remove($statements_analyzer->getFilePath(), 'MixedAssignment', $first_appearance->raw_file_start); } if (isset($op_vars_in_scope[$var_id])) { $op_vars_in_scope[$var_id] = $op_vars_in_scope[$var_id]->setProperties(['from_docblock' => \true]); } } $context->vars_in_scope = $op_vars_in_scope; $context->references_in_scope = $op_references_in_scope; } if ($changed_var_ids) { $simplified_clauses = Context::removeReconciledClauses($simplified_clauses, $changed_var_ids)[0]; } $context->clauses = $simplified_clauses; } private static function checkFunctionCallPurity(StatementsAnalyzer $statements_analyzer, Codebase $codebase, PhpParser\Node\Expr\FuncCall $stmt, PhpParser\Node $function_name, \Psalm\Internal\Analyzer\Statements\Expression\Call\FunctionCallInfo $function_call_info, Context $context) : void { $config = $codebase->config; if (!$context->collect_initializations && !$context->collect_mutations && ($context->mutation_free || $context->external_mutation_free || $codebase->find_unused_variables || !$config->remember_property_assignments_after_call || $statements_analyzer->getSource() instanceof FunctionLikeAnalyzer && $statements_analyzer->getSource()->track_mutations)) { $must_use = \true; $callmap_function_pure = $function_call_info->function_id && $function_call_info->in_call_map ? $codebase->functions->isCallMapFunctionPure($codebase, $statements_analyzer->node_data, $function_call_info->function_id, $stmt->isFirstClassCallable() ? [] : $stmt->getArgs(), $must_use) : null; if (!$function_call_info->in_call_map && $function_call_info->function_storage && !$function_call_info->function_storage->pure && !$function_call_info->function_storage->mutation_free || $callmap_function_pure === \false) { if ($context->mutation_free || $context->external_mutation_free) { IssueBuffer::maybeAdd(new ImpureFunctionCall('Cannot call an impure function from a mutation-free context', new CodeLocation($statements_analyzer, $function_name)), $statements_analyzer->getSuppressedIssues()); } elseif ($statements_analyzer->getSource() instanceof FunctionLikeAnalyzer && $statements_analyzer->getSource()->track_mutations) { $statements_analyzer->getSource()->inferred_has_mutation = \true; $statements_analyzer->getSource()->inferred_impure = \true; } if (!$config->remember_property_assignments_after_call) { $context->removeMutableObjectVars(); } } elseif ($function_call_info->function_id && ($function_call_info->function_storage && $function_call_info->function_storage->pure && !$function_call_info->function_storage->assertions && $must_use || $callmap_function_pure === \true && $must_use) && $codebase->find_unused_variables && !$context->inside_conditional && !$context->inside_unset) { /** * If a function is pure, and has the return type of 'no-return', * it's okay to dismiss it's return value. */ if (!$context->insideUse() && !self::callUsesByReferenceArguments($function_call_info, $stmt) && !($function_call_info->function_storage && $function_call_info->function_storage->return_type && $function_call_info->function_storage->return_type->isNever())) { IssueBuffer::maybeAdd(new UnusedFunctionCall('The call to ' . $function_call_info->function_id . ' is not used', new CodeLocation($statements_analyzer, $function_name), $function_call_info->function_id), $statements_analyzer->getSuppressedIssues()); } else { $stmt->setAttribute('pure', \true); } } } } private static function callUsesByReferenceArguments(\Psalm\Internal\Analyzer\Statements\Expression\Call\FunctionCallInfo $function_call_info, PhpParser\Node\Expr\FuncCall $stmt) : bool { // If the function doesn't have any by-reference parameters // we shouldn't look any further. if (!$function_call_info->hasByReferenceParameters() || null === $function_call_info->function_params) { return \false; } $parameters = $function_call_info->function_params; // If no arguments were passed if (0 === count($stmt->getArgs())) { return \false; } foreach ($stmt->getArgs() as $index => $argument) { $parameter = null; if (null !== $argument->name) { $argument_name = $argument->name->toString(); foreach ($parameters as $param) { if ($param->name === $argument_name) { $parameter = $param; break; } } } else { $parameter = $parameters[$index] ?? null; } if ($parameter && $parameter->by_ref) { return \true; } } return \false; } } $args */ public static function analyze(StatementsAnalyzer $statements_analyzer, PhpParser\Node\Expr\StaticCall $stmt, PhpParser\Node\Identifier $stmt_name, array $args, Context $context, Atomic $lhs_type_part, MethodIdentifier $method_id, string $cased_method_id, ClassLikeStorage $class_storage, bool &$moved_call, ?TemplateResult $inferred_template_result = null) : void { $fq_class_name = $method_id->fq_class_name; $method_name_lc = $method_id->method_name; $codebase = $statements_analyzer->getCodebase(); $config = $codebase->config; MethodCallProhibitionAnalyzer::analyze($codebase, $context, $method_id, $statements_analyzer->getFullyQualifiedFunctionMethodOrNamespaceName(), new CodeLocation($statements_analyzer->getSource(), $stmt), $statements_analyzer->getSuppressedIssues()); if ($class_storage->user_defined && $context->self && ($context->collect_mutations || $context->collect_initializations)) { $appearing_method_id = $codebase->methods->getAppearingMethodId($method_id); if (!$appearing_method_id) { return; } $appearing_method_class_name = $appearing_method_id->fq_class_name; if ($codebase->classExtends($context->self, $appearing_method_class_name)) { $old_context_include_location = $context->include_location; $old_self = $context->self; $context->include_location = new CodeLocation($statements_analyzer->getSource(), $stmt); $context->self = $appearing_method_class_name; $file_analyzer = $statements_analyzer->getFileAnalyzer(); if ($context->collect_mutations) { $file_analyzer->getMethodMutations($appearing_method_id, $context); } else { // collecting initializations $local_vars_in_scope = []; $local_vars_possibly_in_scope = []; foreach ($context->vars_in_scope as $var => $_) { if (strpos($var, '$this->') !== 0 && $var !== '$this') { $local_vars_in_scope[$var] = $context->vars_in_scope[$var]; } } foreach ($context->vars_possibly_in_scope as $var => $_) { if (strpos($var, '$this->') !== 0 && $var !== '$this') { $local_vars_possibly_in_scope[$var] = $context->vars_possibly_in_scope[$var]; } } if (!isset($context->initialized_methods[(string) $appearing_method_id])) { if ($context->initialized_methods === null) { $context->initialized_methods = []; } $context->initialized_methods[(string) $appearing_method_id] = \true; $file_analyzer->getMethodMutations($appearing_method_id, $context); foreach ($local_vars_in_scope as $var => $type) { $context->vars_in_scope[$var] = $type; } foreach ($local_vars_possibly_in_scope as $var => $type) { $context->vars_possibly_in_scope[$var] = $type; } } } $context->include_location = $old_context_include_location; $context->self = $old_self; } } $found_generic_params = ClassTemplateParamCollector::collect($codebase, $class_storage, $class_storage, $method_name_lc, $lhs_type_part, !$statements_analyzer->isStatic() && $method_id->fq_class_name === $context->self); if ($found_generic_params && $stmt->class instanceof PhpParser\Node\Name && $stmt->class->getParts() === ['parent'] && $context->self && ($self_class_storage = $codebase->classlike_storage_provider->get($context->self)) && $self_class_storage->template_extended_params) { foreach ($self_class_storage->template_extended_params as $template_fq_class_name => $extended_types) { foreach ($extended_types as $type_key => $extended_type) { if (isset($found_generic_params[$type_key][$template_fq_class_name])) { $found_generic_params[$type_key][$template_fq_class_name] = $extended_type; continue; } foreach ($extended_type->getAtomicTypes() as $t) { if ($t instanceof TTemplateParam && isset($found_generic_params[$t->param_name][$t->defining_class])) { $found_generic_params[$type_key][$template_fq_class_name] = $found_generic_params[$t->param_name][$t->defining_class]; } else { $found_generic_params[$type_key][$template_fq_class_name] = $extended_type; break; } } } } } $template_result = new TemplateResult([], $found_generic_params ?: []); if ($inferred_template_result) { $template_result->lower_bounds += $inferred_template_result->lower_bounds; } if (CallAnalyzer::checkMethodArgs($method_id, $args, $template_result, $context, new CodeLocation($statements_analyzer->getSource(), $stmt), $statements_analyzer) === \false) { return; } $fq_class_name = $stmt->class instanceof PhpParser\Node\Name && $stmt->class->getParts() === ['parent'] ? (string) $statements_analyzer->getFQCLN() : $fq_class_name; $self_fq_class_name = $fq_class_name; $return_type_candidate = null; if ($codebase->methods->return_type_provider->has($fq_class_name)) { $return_type_candidate = $codebase->methods->return_type_provider->getReturnType($statements_analyzer, $fq_class_name, $stmt_name->name, $stmt, $context, new CodeLocation($statements_analyzer->getSource(), $stmt_name)); } $declaring_method_id = $codebase->methods->getDeclaringMethodId($method_id); if (!$return_type_candidate && $declaring_method_id && (string) $declaring_method_id !== (string) $method_id) { $declaring_fq_class_name = $declaring_method_id->fq_class_name; $declaring_method_name = $declaring_method_id->method_name; if ($codebase->methods->return_type_provider->has($declaring_fq_class_name)) { $return_type_candidate = $codebase->methods->return_type_provider->getReturnType($statements_analyzer, $declaring_fq_class_name, $declaring_method_name, $stmt, $context, new CodeLocation($statements_analyzer->getSource(), $stmt_name), null, $fq_class_name, $stmt_name->name); } } if (!$return_type_candidate) { $return_type_candidate = self::getMethodReturnType($statements_analyzer, $codebase, $stmt, $method_id, $args, $template_result, $self_fq_class_name, $lhs_type_part, $context, $fq_class_name, $class_storage, $config); } $method_storage = $codebase->methods->getUserMethodStorage($method_id); if ($method_storage) { if ($method_storage->abstract && $stmt->class instanceof PhpParser\Node\Name && (!$context->self || !UnionTypeComparator::isContainedBy($codebase, $context->vars_in_scope['$this'] ?? new Union([new TNamedObject($context->self)]), new Union([new TNamedObject($method_id->fq_class_name)])))) { IssueBuffer::maybeAdd(new AbstractMethodCall('Cannot call an abstract static method ' . $method_id . ' directly', new CodeLocation($statements_analyzer->getSource(), $stmt)), $statements_analyzer->getSuppressedIssues()); } if (!$context->inside_throw) { if ($context->pure && !$method_storage->pure) { IssueBuffer::maybeAdd(new ImpureMethodCall('Cannot call an impure method from a pure context', new CodeLocation($statements_analyzer, $stmt_name)), $statements_analyzer->getSuppressedIssues()); } elseif ($context->mutation_free && !$method_storage->mutation_free) { IssueBuffer::maybeAdd(new ImpureMethodCall('Cannot call a possibly-mutating method from a mutation-free context', new CodeLocation($statements_analyzer, $stmt_name)), $statements_analyzer->getSuppressedIssues()); } elseif ($statements_analyzer->getSource() instanceof FunctionLikeAnalyzer && $statements_analyzer->getSource()->track_mutations && !$method_storage->pure) { if (!$method_storage->mutation_free) { $statements_analyzer->getSource()->inferred_has_mutation = \true; } $statements_analyzer->getSource()->inferred_impure = \true; } } $assertionsResolver = new AssertionsFromInheritanceResolver($codebase); $assertions = $assertionsResolver->resolve($method_storage, $class_storage); if ($assertions) { CallAnalyzer::applyAssertionsToContext($stmt_name, null, $assertions, $stmt->getArgs(), $template_result, $context, $statements_analyzer); } if ($method_storage->if_true_assertions) { $statements_analyzer->node_data->setIfTrueAssertions($stmt, array_map(static fn(Possibilities $assertion): Possibilities => $assertion->getUntemplatedCopy($template_result, null, $codebase), $method_storage->if_true_assertions)); } if ($method_storage->if_false_assertions) { $statements_analyzer->node_data->setIfFalseAssertions($stmt, array_map(static fn(Possibilities $assertion): Possibilities => $assertion->getUntemplatedCopy($template_result, null, $codebase), $method_storage->if_false_assertions)); } } if ($codebase->alter_code) { foreach ($codebase->call_transforms as $original_pattern => $transformation) { if ($declaring_method_id && strtolower((string) $declaring_method_id) . '\\((.*\\))' === $original_pattern) { if (strpos($transformation, '($1)') === strlen($transformation) - 4 && $stmt->class instanceof PhpParser\Node\Name) { $new_method_id = substr($transformation, 0, -4); $old_declaring_fq_class_name = $declaring_method_id->fq_class_name; [$new_fq_class_name, $new_method_name] = explode('::', $new_method_id); if ($codebase->classlikes->handleClassLikeReferenceInMigration($codebase, $statements_analyzer, $stmt->class, $new_fq_class_name, $context->calling_method_id, strtolower($old_declaring_fq_class_name) !== strtolower($new_fq_class_name), $stmt->class->getFirst() === 'self')) { $moved_call = \true; } $file_manipulations = []; $file_manipulations[] = new FileManipulation((int) $stmt_name->getAttribute('startFilePos'), (int) $stmt_name->getAttribute('endFilePos') + 1, $new_method_name); FileManipulationBuffer::add($statements_analyzer->getFilePath(), $file_manipulations); } } } } if ($config->eventDispatcher->hasAfterMethodCallAnalysisHandlers()) { $file_manipulations = []; $appearing_method_id = $codebase->methods->getAppearingMethodId($method_id); if ($appearing_method_id !== null && $declaring_method_id) { $event = new AfterMethodCallAnalysisEvent($stmt, (string) $method_id, (string) $appearing_method_id, (string) $declaring_method_id, $context, $statements_analyzer, $codebase, $file_manipulations, $return_type_candidate); $config->eventDispatcher->dispatchAfterMethodCallAnalysis($event); $file_manipulations = $event->getFileReplacements(); $return_type_candidate = $event->getReturnTypeCandidate(); } if ($file_manipulations) { FileManipulationBuffer::add($statements_analyzer->getFilePath(), $file_manipulations); } } $return_type_candidate ??= Type::getMixed(); StaticCallAnalyzer::taintReturnType($statements_analyzer, $stmt, $method_id, $cased_method_id, $return_type_candidate, $method_storage, $template_result, $context); $stmt_type = $statements_analyzer->node_data->getType($stmt); $statements_analyzer->node_data->setType($stmt, Type::combineUnionTypes($stmt_type, $return_type_candidate)); if ($codebase->store_node_types && !$context->collect_initializations && !$context->collect_mutations) { $codebase->analyzer->addNodeReference($statements_analyzer->getFilePath(), $stmt->name, $method_id . '()'); if ($stmt_type = $statements_analyzer->node_data->getType($stmt)) { $codebase->analyzer->addNodeType($statements_analyzer->getFilePath(), $stmt->name, $stmt_type->getId(), $stmt); } } } /** * @param list $args */ private static function getMethodReturnType(StatementsAnalyzer $statements_analyzer, Codebase $codebase, StaticCall $stmt, MethodIdentifier $method_id, array $args, TemplateResult $template_result, ?string &$self_fq_class_name, Atomic $lhs_type_part, Context $context, string $fq_class_name, ClassLikeStorage $class_storage, Config $config) : ?Union { $return_type_candidate = $codebase->methods->getMethodReturnType($method_id, $self_fq_class_name, $statements_analyzer, $args); if ($return_type_candidate) { if ($template_result->template_types) { $bindable_template_types = $return_type_candidate->getTemplateTypes(); foreach ($bindable_template_types as $template_type) { if (!isset($template_result->lower_bounds[$template_type->param_name][$template_type->defining_class])) { $template_result->lower_bounds[$template_type->param_name] = self::resolveTemplateResultLowerBound($codebase, $stmt, $class_storage, $method_id, $template_type); } } } $context_final = \false; if ($lhs_type_part instanceof TTemplateParam) { $static_type = $lhs_type_part; } elseif ($lhs_type_part instanceof TTemplateParamClass) { $static_type = new TTemplateParam($lhs_type_part->param_name, $lhs_type_part->as_type ? new Union([$lhs_type_part->as_type]) : Type::getObject(), $lhs_type_part->defining_class); } elseif ($stmt->class instanceof PhpParser\Node\Name && count($stmt->class->getParts()) === 1 && in_array(strtolower($stmt->class->getFirst()), ['self', 'static', 'parent'], \true) && $lhs_type_part instanceof TNamedObject && $context->self) { $static_type = $context->self; $context_final = $codebase->classlike_storage_provider->get($context->self)->final; } elseif ($context->calling_method_id !== null) { // differentiate between these cases: // 1. "static" comes from the CALLED static method - use $fq_class_name. // 2. "static" in return type comes from return type of the // method CALLING the currently analyzed static method - use $context->self. $static_type = self::hasStaticInType($return_type_candidate) ? $fq_class_name : $context->self; } else { $static_type = $fq_class_name; } if ($template_result->lower_bounds) { $return_type_candidate = TypeExpander::expandUnion($codebase, $return_type_candidate, null, null, null); $return_type_candidate = TemplateInferredTypeReplacer::replace($return_type_candidate, $template_result, $codebase); } $return_type_candidate = TypeExpander::expandUnion($codebase, $return_type_candidate, $self_fq_class_name, $static_type, $class_storage->parent_class, \true, \false, is_string($static_type) && ($static_type !== $context->self || $class_storage->final || $context_final)); $secondary_return_type_location = null; $return_type_location = $codebase->methods->getMethodReturnTypeLocation($method_id, $secondary_return_type_location); if ($secondary_return_type_location) { $return_type_location = $secondary_return_type_location; } // only check the type locally if it's defined externally if ($return_type_location && !$config->isInProjectDirs($return_type_location->file_path)) { /** @psalm-suppress UnusedMethodCall Actually generates issues */ $return_type_candidate->check($statements_analyzer, new CodeLocation($statements_analyzer, $stmt), $statements_analyzer->getSuppressedIssues(), $context->phantom_classes, \true, \false, \false, $context->calling_method_id); } } return $return_type_candidate; } /** * Dumb way to determine whether a type contains "static" somewhere inside. */ private static function hasStaticInType(Type\TypeNode $type) : bool { $visitor = new ContainsStaticVisitor(); $visitor->traverse($type); return $visitor->matches(); } /** * @return non-empty-array> */ private static function resolveTemplateResultLowerBound(Codebase $codebase, StaticCall $stmt, ClassLikeStorage $class_storage, MethodIdentifier $method_id, TTemplateParam $template_type) : array { if ($template_type->param_name === 'TFunctionArgCount') { return ['fn-' . strtolower((string) $method_id) => [new TemplateBound(Type::getInt(\false, count($stmt->getArgs())))]]; } if ($template_type->param_name === 'TPhpMajorVersion') { return ['fn-' . strtolower((string) $method_id) => [new TemplateBound(Type::getInt(\false, $codebase->getMajorAnalysisPhpVersion()))]]; } if ($template_type->param_name === 'TPhpVersionId') { return ['fn-' . strtolower((string) $method_id) => [new TemplateBound(Type::getInt(\false, $codebase->analysis_php_version_id))]]; } if (isset($class_storage->template_extended_params[$template_type->defining_class][$template_type->param_name])) { $extended_param_type = $class_storage->template_extended_params[$template_type->defining_class][$template_type->param_name]; return [$template_type->defining_class => [new TemplateBound($extended_param_type)]]; } return [$template_type->defining_class => [new TemplateBound(Type::getNever())]]; } } value; if (!ClassLikeAnalyzer::checkFullyQualifiedClassLikeName($statements_analyzer, $fq_class_name, new CodeLocation($statements_analyzer, $stmt->class), !$context->collect_initializations && !$context->collect_mutations ? $context->self : null, !$context->collect_initializations && !$context->collect_mutations ? $context->calling_method_id : null, $statements_analyzer->getSuppressedIssues(), new ClassLikeNameOptions($stmt->class instanceof PhpParser\Node\Name && count($stmt->class->getParts()) === 1 && in_array(strtolower($stmt->class->getFirst()), ['self', 'static'], \true)))) { return; } $intersection_types = $lhs_type_part->extra_types; } elseif ($lhs_type_part instanceof TClassString && $lhs_type_part->as_type) { $fq_class_name = $lhs_type_part->as_type->value; if (!ClassLikeAnalyzer::checkFullyQualifiedClassLikeName($statements_analyzer, $fq_class_name, new CodeLocation($statements_analyzer, $stmt->class), $context->self, $context->calling_method_id, $statements_analyzer->getSuppressedIssues())) { return; } $intersection_types = $lhs_type_part->as_type->extra_types; } elseif ($lhs_type_part instanceof TDependentGetClass && !$lhs_type_part->as_type->hasObject()) { $fq_class_name = 'object'; if ($lhs_type_part->as_type->hasObjectType() && $lhs_type_part->as_type->isSingle()) { foreach ($lhs_type_part->as_type->getAtomicTypes() as $typeof_type_atomic) { if ($typeof_type_atomic instanceof TNamedObject) { $fq_class_name = $typeof_type_atomic->value; } } } if ($fq_class_name === 'object') { return; } } elseif ($lhs_type_part instanceof TLiteralClassString) { $fq_class_name = $lhs_type_part->value; if (!ClassLikeAnalyzer::checkFullyQualifiedClassLikeName($statements_analyzer, $fq_class_name, new CodeLocation($statements_analyzer, $stmt->class), $context->self, $context->calling_method_id, $statements_analyzer->getSuppressedIssues())) { return; } } elseif ($lhs_type_part instanceof TTemplateParam && !$lhs_type_part->as->isMixed() && !$lhs_type_part->as->hasObject()) { $fq_class_name = null; foreach ($lhs_type_part->as->getAtomicTypes() as $generic_param_type) { if (!$generic_param_type instanceof TNamedObject) { return; } $fq_class_name = $generic_param_type->value; break; } if (!$fq_class_name) { IssueBuffer::maybeAdd(new UndefinedClass('Type ' . $lhs_type_part->as . ' cannot be called as a class', new CodeLocation($statements_analyzer->getSource(), $stmt), (string) $lhs_type_part), $statements_analyzer->getSuppressedIssues()); return; } } else { self::handleNonObjectCall($statements_analyzer, $stmt, $context, $lhs_type_part, $ignore_nullable_issues); return; } $codebase = $statements_analyzer->getCodebase(); $fq_class_name = $codebase->classlikes->getUnAliasedName($fq_class_name); $is_mock = ExpressionAnalyzer::isMock($fq_class_name); $has_mock = $has_mock || $is_mock; if ($stmt->name instanceof PhpParser\Node\Identifier && !$is_mock) { self::handleNamedCall($statements_analyzer, $stmt, $stmt->name, $context, $lhs_type_part, $intersection_types ?: [], $fq_class_name, $moved_call, $has_existing_method, $inferred_template_result); } else { if ($stmt->name instanceof PhpParser\Node\Expr) { $was_inside_general_use = $context->inside_general_use; $context->inside_general_use = \true; ExpressionAnalyzer::analyze($statements_analyzer, $stmt->name, $context); $context->inside_general_use = $was_inside_general_use; } if (!$context->ignore_variable_method) { $codebase->analyzer->addMixedMemberName(strtolower($fq_class_name) . '::', $context->calling_method_id ?: $statements_analyzer->getFileName()); } if ($stmt->isFirstClassCallable()) { $return_type_candidate = null; if (!$stmt->name instanceof PhpParser\Node\Identifier) { $method_name_type = $statements_analyzer->node_data->getType($stmt->name); if ($method_name_type && $method_name_type->isSingleStringLiteral()) { $method_identifier = new MethodIdentifier($fq_class_name, strtolower($method_name_type->getSingleStringLiteral()->value)); //the call to methodExists will register that the method was called from somewhere if ($codebase->methods->methodExists($method_identifier, $context->calling_method_id, null, $statements_analyzer, $statements_analyzer->getFilePath(), \true, $context->insideUse())) { $method_storage = $codebase->methods->getStorage($method_identifier); $return_type_candidate = new Union([new TClosure('Closure', $method_storage->params, $method_storage->return_type, $method_storage->pure)]); } } } $statements_analyzer->node_data->setType($stmt, $return_type_candidate ?? Type::getClosure()); return; } if (ArgumentsAnalyzer::analyze($statements_analyzer, $stmt->getArgs(), null, null, \true, $context) === \false) { return; } } if ($codebase->alter_code && $fq_class_name && !$moved_call && $stmt->class instanceof PhpParser\Node\Name && !in_array($stmt->class->getFirst(), ['parent', 'static'])) { $codebase->classlikes->handleClassLikeReferenceInMigration($codebase, $statements_analyzer, $stmt->class, $fq_class_name, $context->calling_method_id, \false, $stmt->class->getFirst() === 'self'); } } /** * @psalm-suppress UnusedReturnValue not used but seems important * @psalm-suppress ComplexMethod to be refactored */ private static function handleNamedCall(StatementsAnalyzer $statements_analyzer, PhpParser\Node\Expr\StaticCall $stmt, PhpParser\Node\Identifier $stmt_name, Context $context, Atomic $lhs_type_part, array $intersection_types, string $fq_class_name, bool &$moved_call, bool &$has_existing_method, ?TemplateResult $inferred_template_result = null) : bool { $codebase = $statements_analyzer->getCodebase(); $method_name_lc = strtolower($stmt_name->name); $method_id = new MethodIdentifier($fq_class_name, $method_name_lc); $cased_method_id = $fq_class_name . '::' . $stmt_name->name; if ($codebase->store_node_types && !$stmt->isFirstClassCallable() && !$context->collect_initializations && !$context->collect_mutations) { ArgumentMapPopulator::recordArgumentPositions($statements_analyzer, $stmt, $codebase, (string) $method_id); } if ($intersection_types && !$codebase->methods->methodExists($method_id)) { foreach ($intersection_types as $intersection_type) { if (!$intersection_type instanceof TNamedObject) { continue; } $intersection_method_id = new MethodIdentifier($intersection_type->value, $method_name_lc); if ($codebase->methods->methodExists($intersection_method_id)) { $method_id = $intersection_method_id; $cased_method_id = $intersection_type->value . '::' . $stmt_name->name; $fq_class_name = $intersection_type->value; break; } } } $class_storage = $codebase->classlike_storage_provider->get($fq_class_name); $naive_method_exists = $codebase->methods->methodExists($method_id, !$context->collect_initializations && !$context->collect_mutations ? $context->calling_method_id : null, $codebase->collect_locations ? new CodeLocation($statements_analyzer, $stmt_name) : null, $statements_analyzer, $statements_analyzer->getFilePath(), \false, $context->insideUse()); $fake_method_exists = \false; if (!$naive_method_exists && $codebase->methods->existence_provider->has($fq_class_name)) { $fake_method_exists = $codebase->methods->existence_provider->doesMethodExist($fq_class_name, $method_id->method_name, $statements_analyzer, null) ?? \false; } $args = $stmt->isFirstClassCallable() ? [] : $stmt->getArgs(); if (!$naive_method_exists && $class_storage->mixin_declaring_fqcln && $class_storage->namedMixins) { foreach ($class_storage->namedMixins as $mixin) { $new_method_id = new MethodIdentifier($mixin->value, $method_name_lc); if ($codebase->methods->methodExists($new_method_id, $context->calling_method_id, $codebase->collect_locations ? new CodeLocation($statements_analyzer, $stmt_name) : null, !$context->collect_initializations && !$context->collect_mutations ? $statements_analyzer : null, $statements_analyzer->getFilePath(), \true, $context->insideUse())) { $mixin_candidates = []; foreach ($class_storage->templatedMixins as $mixin_candidate) { $mixin_candidates[] = $mixin_candidate; } foreach ($class_storage->namedMixins as $mixin_candidate) { $mixin_candidates[] = $mixin_candidate; } $mixin_candidates_no_generic = array_filter($mixin_candidates, static fn(Atomic $check): bool => !$check instanceof TGenericObject); // $mixin_candidates_no_generic will only be empty when there are TGenericObject entries. // In that case, Union will be initialized with an empty array but // replaced with non-empty types in the following loop. /** @psalm-suppress ArgumentTypeCoercion */ $mixin_candidate_type = new Union($mixin_candidates_no_generic); foreach ($mixin_candidates as $tGenericMixin) { if (!$tGenericMixin instanceof TGenericObject) { continue; } $mixin_declaring_class_storage = $codebase->classlike_storage_provider->get($class_storage->mixin_declaring_fqcln); $new_mixin_candidate_type = AtomicPropertyFetchAnalyzer::localizePropertyType($codebase, new Union([$lhs_type_part]), $tGenericMixin, $class_storage, $mixin_declaring_class_storage)->getBuilder(); foreach ($mixin_candidate_type->getAtomicTypes() as $type) { $new_mixin_candidate_type->addType($type); } $mixin_candidate_type = $new_mixin_candidate_type->freeze(); } $new_lhs_type = TypeExpander::expandUnion($codebase, $mixin_candidate_type, $fq_class_name, $fq_class_name, $class_storage->parent_class, \true, \false, $class_storage->final); $mixin_context = clone $context; $mixin_context->vars_in_scope['$__tmp_mixin_var__'] = $new_lhs_type; return self::forwardCallToInstanceMethod($statements_analyzer, $stmt, $stmt_name, $mixin_context, '__tmp_mixin_var__', \true); } } } $config = $codebase->config; $found_method_and_class_storage = self::findPseudoMethodAndClassStorages($codebase, $class_storage, $method_name_lc); if ($stmt->isFirstClassCallable()) { if ($found_method_and_class_storage) { [$method_storage] = $found_method_and_class_storage; $return_type_candidate = new Union([new TClosure('Closure', $method_storage->params, $method_storage->return_type, $method_storage->pure)]); } else { $method_exists = $naive_method_exists || $fake_method_exists || isset($class_storage->methods[$method_name_lc]) || isset($class_storage->pseudo_static_methods[$method_name_lc]); if ($method_exists) { $declaring_method_id = $codebase->methods->getDeclaringMethodId($method_id) ?? $method_id; $return_type_candidate = new Union([new TClosure('Closure', array_values($codebase->getMethodParams($method_id)), $codebase->getMethodReturnType($method_id, $fq_class_name), $codebase->methods->getStorage($declaring_method_id)->pure)]); } elseif ($codebase->methodExists($call_static_method_id = new MethodIdentifier($method_id->fq_class_name, '__callstatic'), new CodeLocation($statements_analyzer, $stmt), null, null, \false)) { $return_type_candidate = new Union([new TClosure('Closure', null, $codebase->getMethodReturnType($call_static_method_id, $fq_class_name), $codebase->methods->getStorage($call_static_method_id)->pure)]); } else { if (IssueBuffer::accepts(new UndefinedMethod('Method ' . $method_id . ' does not exist', new CodeLocation($statements_analyzer, $stmt), (string) $method_id), $statements_analyzer->getSuppressedIssues())) { return \false; } $return_type_candidate = Type::getClosure(); } } $expanded_return_type = TypeExpander::expandUnion($codebase, $return_type_candidate, $context->self, $class_storage->name, $context->parent, \true, \false, \true); $statements_analyzer->node_data->setType($stmt, $expanded_return_type); return \true; } $callstatic_id = new MethodIdentifier($fq_class_name, '__callstatic'); $callstatic_method_exists = $codebase->methods->methodExists($callstatic_id); $with_pseudo = $callstatic_method_exists || $codebase->config->use_phpdoc_method_without_magic_or_parent; if ($codebase->methods->getDeclaringMethodId($method_id, $with_pseudo)) { if ((!$stmt->class instanceof PhpParser\Node\Name || $stmt->class->getFirst() !== 'parent' || $statements_analyzer->isStatic()) && (!$context->self || $statements_analyzer->isStatic() || !$codebase->classExtends($context->self, $fq_class_name))) { MethodAnalyzer::checkStatic($method_id, $stmt->class instanceof PhpParser\Node\Name && strtolower($stmt->class->getFirst()) === 'self' || $context->self === $fq_class_name, !$statements_analyzer->isStatic(), $codebase, new CodeLocation($statements_analyzer, $stmt), $statements_analyzer->getSuppressedIssues(), $is_dynamic_this_method); if ($is_dynamic_this_method) { return self::forwardCallToInstanceMethod($statements_analyzer, $stmt, $stmt_name, $context); } } } if (!$naive_method_exists || !MethodAnalyzer::isMethodVisible($method_id, $context, $statements_analyzer->getSource()) || $fake_method_exists || $found_method_and_class_storage) { if ($callstatic_method_exists) { $callstatic_declaring_id = $codebase->methods->getDeclaringMethodId($callstatic_id); assert($callstatic_declaring_id !== null); $callstatic_pure = \false; $callstatic_mutation_free = \false; if ($codebase->methods->hasStorage($callstatic_declaring_id)) { $callstatic_storage = $codebase->methods->getStorage($callstatic_declaring_id); $callstatic_pure = $callstatic_storage->pure; $callstatic_mutation_free = $callstatic_storage->mutation_free; } if ($codebase->methods->return_type_provider->has($fq_class_name)) { $return_type_candidate = $codebase->methods->return_type_provider->getReturnType($statements_analyzer, $method_id->fq_class_name, $method_id->method_name, $stmt, $context, new CodeLocation($statements_analyzer->getSource(), $stmt_name), null, null, strtolower($stmt_name->name)); if ($return_type_candidate) { CallAnalyzer::checkMethodArgs($method_id, $stmt->getArgs(), new TemplateResult([], []), $context, new CodeLocation($statements_analyzer->getSource(), $stmt), $statements_analyzer); $statements_analyzer->node_data->setType($stmt, $return_type_candidate); return \true; } } if ($found_method_and_class_storage) { [$pseudo_method_storage, $defining_class_storage] = $found_method_and_class_storage; if (self::checkPseudoMethod($statements_analyzer, $stmt, $method_id, $fq_class_name, $args, $defining_class_storage, $pseudo_method_storage, $context) === \false) { return \false; } if (!$context->inside_throw) { if ($context->pure && !$callstatic_pure) { IssueBuffer::maybeAdd(new ImpureMethodCall('Cannot call an impure method from a pure context', new CodeLocation($statements_analyzer, $stmt_name)), $statements_analyzer->getSuppressedIssues()); } elseif ($context->mutation_free && !$callstatic_mutation_free) { IssueBuffer::maybeAdd(new ImpureMethodCall('Cannot call a possibly-mutating method from a mutation-free context', new CodeLocation($statements_analyzer, $stmt_name)), $statements_analyzer->getSuppressedIssues()); } elseif ($statements_analyzer->getSource() instanceof FunctionLikeAnalyzer && $statements_analyzer->getSource()->track_mutations && !$callstatic_pure) { if (!$callstatic_mutation_free) { $statements_analyzer->getSource()->inferred_has_mutation = \true; } $statements_analyzer->getSource()->inferred_impure = \true; } } if ($pseudo_method_storage->return_type) { return \true; } } else { if (ArgumentsAnalyzer::analyze($statements_analyzer, $args, null, null, \true, $context) === \false) { return \false; } } } elseif ($found_method_and_class_storage && ($naive_method_exists || $with_pseudo)) { [$pseudo_method_storage, $defining_class_storage] = $found_method_and_class_storage; if (self::checkPseudoMethod($statements_analyzer, $stmt, $method_id, $fq_class_name, $args, $defining_class_storage, $pseudo_method_storage, $context) === \false) { return \false; } if ($pseudo_method_storage->return_type) { return \true; } } elseif ($stmt->class instanceof PhpParser\Node\Name && $stmt->class->getFirst() === 'parent' && !$codebase->methodExists($method_id) && !$statements_analyzer->isStatic()) { // In case of parent::xxx() call on instance method context (i.e. not static context) // with nonexistent method, we try to forward to instance method call for resolve pseudo method. // Use parent type as static type for the method call $tmp_context = clone $context; $tmp_context->vars_in_scope['$__tmp_parent_var__'] = new Union([$lhs_type_part]); if (self::forwardCallToInstanceMethod($statements_analyzer, $stmt, $stmt_name, $tmp_context, '__tmp_parent_var__') === \false) { return \false; } unset($tmp_context); // Resolve actual static return type according to caller (i.e. $this) static type if (isset($context->vars_in_scope['$this']) && ($method_call_type = $statements_analyzer->node_data->getType($stmt))) { $method_call_type = $method_call_type->getBuilder(); foreach ($method_call_type->getAtomicTypes() as $name => $type) { if ($type instanceof TNamedObject && $type->is_static && $type->value === $fq_class_name) { // Replace parent&static type to actual static type $method_call_type->removeType($name); $method_call_type->addType($context->vars_in_scope['$this']->getSingleAtomic()); } } $statements_analyzer->node_data->setType($stmt, $method_call_type->freeze()); } return \true; } if (!$context->check_methods) { if (ArgumentsAnalyzer::analyze($statements_analyzer, $stmt->getArgs(), null, null, \true, $context) === \false) { return \false; } return \true; } } if ($naive_method_exists || !$callstatic_method_exists || $class_storage->hasSealedMethods($config)) { $does_method_exist = MethodAnalyzer::checkMethodExists($codebase, $method_id, new CodeLocation($statements_analyzer, $stmt), $statements_analyzer->getSuppressedIssues(), $context->calling_method_id, $with_pseudo); } else { $does_method_exist = null; } if (!$does_method_exist) { if (ArgumentsAnalyzer::analyze($statements_analyzer, $stmt->getArgs(), null, null, \true, $context) === \false) { return \false; } if ($codebase->alter_code && $fq_class_name && !$moved_call) { $codebase->classlikes->handleClassLikeReferenceInMigration($codebase, $statements_analyzer, $stmt->class, $fq_class_name, $context->calling_method_id); } return \true; } $class_storage = $codebase->classlike_storage_provider->get($fq_class_name); if ($class_storage->deprecated && $fq_class_name !== $context->self) { IssueBuffer::maybeAdd(new DeprecatedClass($fq_class_name . ' is marked deprecated', new CodeLocation($statements_analyzer->getSource(), $stmt), $fq_class_name), $statements_analyzer->getSuppressedIssues()); } if ($context->self && !NamespaceAnalyzer::isWithinAny($context->self, $class_storage->internal)) { IssueBuffer::maybeAdd(new InternalClass($fq_class_name . ' is internal to ' . InternalClass::listToPhrase($class_storage->internal) . ' but called from ' . $context->self, new CodeLocation($statements_analyzer->getSource(), $stmt), $fq_class_name), $statements_analyzer->getSuppressedIssues()); } if (MethodVisibilityAnalyzer::analyze($method_id, $context, $statements_analyzer->getSource(), new CodeLocation($statements_analyzer, $stmt), $statements_analyzer->getSuppressedIssues()) === \false) { return \false; } $has_existing_method = \true; \Psalm\Internal\Analyzer\Statements\Expression\Call\StaticMethod\ExistingAtomicStaticCallAnalyzer::analyze($statements_analyzer, $stmt, $stmt_name, $args, $context, $lhs_type_part, $method_id, $cased_method_id, $class_storage, $moved_call, $inferred_template_result); return \true; } /** * @param list $args * @return false|null */ private static function checkPseudoMethod(StatementsAnalyzer $statements_analyzer, PhpParser\Node\Expr\StaticCall $stmt, MethodIdentifier $method_id, string $static_fq_class_name, array $args, ClassLikeStorage $class_storage, MethodStorage $pseudo_method_storage, Context $context) : ?bool { if (ArgumentsAnalyzer::analyze($statements_analyzer, $args, $pseudo_method_storage->params, (string) $method_id, \true, $context) === \false) { return \false; } $codebase = $statements_analyzer->getCodebase(); if (ArgumentsAnalyzer::checkArgumentsMatch($statements_analyzer, $args, $method_id, $pseudo_method_storage->params, $pseudo_method_storage, null, new TemplateResult([], []), new CodeLocation($statements_analyzer, $stmt), $context) === \false) { return \false; } $method_storage = null; if ($statements_analyzer->data_flow_graph) { try { $method_storage = $codebase->methods->getStorage($method_id); ArgumentsAnalyzer::analyze($statements_analyzer, $args, $method_storage->params, (string) $method_id, \true, $context); ArgumentsAnalyzer::checkArgumentsMatch($statements_analyzer, $args, $method_id, $method_storage->params, $method_storage, null, new TemplateResult([], []), new CodeLocation($statements_analyzer, $stmt), $context); } catch (Exception $e) { // do nothing } } if ($pseudo_method_storage->return_type) { $return_type_candidate = $pseudo_method_storage->return_type; $return_type_candidate = TypeExpander::expandUnion($statements_analyzer->getCodebase(), $return_type_candidate, $class_storage->name, $static_fq_class_name, $class_storage->parent_class); if ($method_storage) { StaticCallAnalyzer::taintReturnType($statements_analyzer, $stmt, $method_id, (string) $method_id, $return_type_candidate, $method_storage, null, $context); } $stmt_type = $statements_analyzer->node_data->getType($stmt); $statements_analyzer->node_data->setType($stmt, Type::combineUnionTypes($return_type_candidate, $stmt_type)); } return null; } public static function handleNonObjectCall(StatementsAnalyzer $statements_analyzer, PhpParser\Node\Expr\StaticCall $stmt, Context $context, Atomic $lhs_type_part, bool $ignore_nullable_issues) : void { $codebase = $statements_analyzer->getCodebase(); $config = $codebase->config; if ($lhs_type_part instanceof TMixed || $lhs_type_part instanceof TTemplateParam || $lhs_type_part instanceof TClassString || $lhs_type_part instanceof TObject) { if ($stmt->name instanceof PhpParser\Node\Identifier) { $codebase->analyzer->addMixedMemberName(strtolower($stmt->name->name), $context->calling_method_id ?: $statements_analyzer->getFileName()); } IssueBuffer::maybeAdd(new MixedMethodCall('Cannot call method on an unknown class', new CodeLocation($statements_analyzer->getSource(), $stmt)), $statements_analyzer->getSuppressedIssues()); return; } if ($lhs_type_part instanceof TString) { if ($config->allow_string_standin_for_class && !$lhs_type_part instanceof TNumericString) { return; } IssueBuffer::maybeAdd(new InvalidStringClass('String cannot be used as a class', new CodeLocation($statements_analyzer->getSource(), $stmt)), $statements_analyzer->getSuppressedIssues()); return; } if ($lhs_type_part instanceof TNull && $ignore_nullable_issues) { return; } IssueBuffer::maybeAdd(new UndefinedClass('Type ' . $lhs_type_part . ' cannot be called as a class', new CodeLocation($statements_analyzer->getSource(), $stmt), (string) $lhs_type_part), $statements_analyzer->getSuppressedIssues()); } /** * Try to find matching pseudo method over ancestors (including interfaces). * * Returns the pseudo method if exists, with its defining class storage. * If the method is not declared, null is returned. * * @param ClassLikeStorage $static_class_storage The called class * @param lowercase-string $method_name_lc * @return array{MethodStorage, ClassLikeStorage}|null */ private static function findPseudoMethodAndClassStorages(Codebase $codebase, ClassLikeStorage $static_class_storage, string $method_name_lc) : ?array { if ($pseudo_method_storage = $static_class_storage->pseudo_static_methods[$method_name_lc] ?? null) { return [$pseudo_method_storage, $static_class_storage]; } $ancestors = $static_class_storage->class_implements + $static_class_storage->parent_classes; foreach ($ancestors as $fq_class_name => $_) { $class_storage = $codebase->classlikes->getStorageFor($fq_class_name); if ($class_storage && isset($class_storage->pseudo_static_methods[$method_name_lc])) { return [$class_storage->pseudo_static_methods[$method_name_lc], $class_storage]; } } return null; } /** * Forward static call to instance call, using `VirtualMethodCall` and `MethodCallAnalyzer::analyze()` * The resolved method return type will be set as type of the $stmt node. * * @param string $virtual_var_name Temporary var name to use for create the fake MethodCall statement. * @param bool $always_set_node_type If true, when the method has no declared typed, mixed will be set on node. * @return bool Result of analysis. False if the call is invalid. * @see MethodCallAnalyzer::analyze() */ private static function forwardCallToInstanceMethod(StatementsAnalyzer $statements_analyzer, PhpParser\Node\Expr\StaticCall $stmt, PhpParser\Node\Identifier $stmt_name, Context $context, string $virtual_var_name = 'this', bool $always_set_node_type = \false) : bool { $old_data_provider = $statements_analyzer->node_data; $statements_analyzer->node_data = clone $statements_analyzer->node_data; $fake_method_call_expr = new VirtualMethodCall(new VirtualVariable($virtual_var_name, $stmt->class->getAttributes()), $stmt_name, $stmt->getArgs(), $stmt->getAttributes()); if (MethodCallAnalyzer::analyze($statements_analyzer, $fake_method_call_expr, $context) === \false) { return \false; } $fake_method_call_type = $statements_analyzer->node_data->getType($fake_method_call_expr); $statements_analyzer->node_data = $old_data_provider; if ($fake_method_call_type) { $statements_analyzer->node_data->setType($stmt, $fake_method_call_type); } elseif ($always_set_node_type) { $statements_analyzer->node_data->setType($stmt, Type::getMixed()); } return \true; } } config; if ($stmt->isFirstClassCallable()) { $candidate_callable = CallableTypeComparator::getCallableFromAtomic($codebase, Type::getAtomicStringFromLiteral($function_id), null, $statements_analyzer, \true); if ($candidate_callable) { $stmt_type = new Union([new TClosure('Closure', $candidate_callable->params, $candidate_callable->return_type, $candidate_callable->is_pure)]); } else { $stmt_type = Type::getClosure(); } } elseif ($codebase->functions->return_type_provider->has($function_id)) { $stmt_type = $codebase->functions->return_type_provider->getReturnType($statements_analyzer, $function_id, $stmt, $context, new CodeLocation($statements_analyzer->getSource(), $function_name)); } if (!$stmt_type) { if (!$in_call_map || $is_stubbed) { if ($function_storage && $function_storage->template_types) { foreach ($function_storage->template_types as $template_name => $_) { if (!isset($template_result->lower_bounds[$template_name])) { if ($template_name === 'TFunctionArgCount') { $template_result->lower_bounds[$template_name] = ['fn-' . $function_id => [new TemplateBound(Type::getInt(\false, count($stmt->getArgs())))]]; } elseif ($template_name === 'TPhpMajorVersion') { $template_result->lower_bounds[$template_name] = ['fn-' . $function_id => [new TemplateBound(Type::getInt(\false, $codebase->getMajorAnalysisPhpVersion()))]]; } elseif ($template_name === 'TPhpVersionId') { $template_result->lower_bounds[$template_name] = ['fn-' . $function_id => [new TemplateBound(Type::getInt(\false, $codebase->analysis_php_version_id))]]; } else { $template_result->lower_bounds[$template_name] = ['fn-' . $function_id => [new TemplateBound(Type::getNever())]]; } } } } if ($function_storage && !$context->isSuppressingExceptions($statements_analyzer)) { $context->mergeFunctionExceptions($function_storage, new CodeLocation($statements_analyzer->getSource(), $stmt)); } try { if ($function_storage && $function_storage->return_type) { $return_type = $function_storage->return_type; if ($template_result->lower_bounds && $function_storage->template_types) { $return_type = TypeExpander::expandUnion($codebase, $return_type, null, null, null); $return_type = TemplateInferredTypeReplacer::replace($return_type, $template_result, $codebase); } $return_type = TypeExpander::expandUnion($codebase, $return_type, null, null, null, \true, \false, \false, \true); $return_type_location = $function_storage->return_type_location; $event = new AfterFunctionCallAnalysisEvent($stmt, $function_id, $context, $statements_analyzer->getSource(), $codebase, $return_type, []); $config->eventDispatcher->dispatchAfterFunctionCallAnalysis($event); $file_manipulations = $event->getFileReplacements(); if ($file_manipulations) { FileManipulationBuffer::add($statements_analyzer->getFilePath(), $file_manipulations); } $return_type = $return_type->setByRef($function_storage->returns_by_ref); $stmt_type = $return_type; // only check the type locally if it's defined externally if ($return_type_location && !$is_stubbed && !$config->isInProjectDirs($return_type_location->file_path)) { /** @psalm-suppress UnusedMethodCall Actually generates issues */ $return_type->check($statements_analyzer, new CodeLocation($statements_analyzer->getSource(), $stmt), $statements_analyzer->getSuppressedIssues(), $context->phantom_classes, \true, \false, \false, $context->calling_method_id); } } } catch (InvalidArgumentException $e) { // this can happen when the function was defined in the Config startup script $stmt_type = Type::getMixed(); } } else { if (!$callmap_callable) { throw new UnexpectedValueException('We should have a callmap callable here'); } $stmt_type = self::getReturnTypeFromCallMapWithArgs($statements_analyzer, $function_id, $stmt->getArgs(), $callmap_callable, $context); } } if (!$stmt_type) { $stmt_type = Type::getMixed(); } if (!$statements_analyzer->data_flow_graph || !$function_storage) { return $stmt_type; } $return_node = self::taintReturnType($statements_analyzer, $stmt, $function_id, $function_storage, $stmt_type, $template_result, $context); if ($function_storage->proxy_calls !== null) { foreach ($function_storage->proxy_calls as $proxy_call) { $fake_call_arguments = []; foreach ($proxy_call['params'] as $i) { $fake_call_arguments[] = $stmt->getArgs()[$i]; } $fake_call_factory = new BuilderFactory(); if (strpos($proxy_call['fqn'], '::') !== \false) { [$fqcn, $method] = explode('::', $proxy_call['fqn']); $fake_call = $fake_call_factory->staticCall($fqcn, $method, $fake_call_arguments); } else { $fake_call = $fake_call_factory->funcCall($proxy_call['fqn'], $fake_call_arguments); } $old_node_data = $statements_analyzer->node_data; $statements_analyzer->node_data = clone $statements_analyzer->node_data; ExpressionAnalyzer::analyze($statements_analyzer, $fake_call, $context); $statements_analyzer->node_data = $old_node_data; if ($return_node && $proxy_call['return']) { $fake_call_type = $statements_analyzer->node_data->getType($fake_call); if (null !== $fake_call_type) { foreach ($fake_call_type->parent_nodes as $fake_call_node) { $statements_analyzer->data_flow_graph->addPath($fake_call_node, $return_node, 'return'); } } } } } return $stmt_type; } /** * @param list $call_args */ private static function getReturnTypeFromCallMapWithArgs(StatementsAnalyzer $statements_analyzer, string $function_id, array $call_args, TCallable $callmap_callable, Context $context) : Union { $call_map_key = strtolower($function_id); $codebase = $statements_analyzer->getCodebase(); if (!$call_args) { switch ($call_map_key) { case 'hrtime': $keyed_array = new TKeyedArray([Type::getInt(), Type::getInt()], null, null, \true); return new Union([$keyed_array]); case 'get_called_class': return new Union([new TClassString($context->self ?: 'object', $context->self ? new TNamedObject($context->self, \true) : null)]); case 'get_parent_class': if ($context->self && $codebase->classExists($context->self)) { $classlike_storage = $codebase->classlike_storage_provider->get($context->self); if ($classlike_storage->parent_classes) { return new Union([new TClassString(array_values($classlike_storage->parent_classes)[0])]); } } } } else { switch ($call_map_key) { case 'count': case 'sizeof': if ($first_arg_type = $statements_analyzer->node_data->getType($call_args[0]->value)) { $atomic_types = $first_arg_type->getAtomicTypes(); if (count($atomic_types) === 1) { if (isset($atomic_types['array'])) { if ($atomic_types['array'] instanceof TList) { $atomic_types['array'] = $atomic_types['array']->getKeyedArray(); } if ($atomic_types['array'] instanceof TCallableArray || $atomic_types['array'] instanceof TCallableKeyedArray) { return Type::getInt(\false, 2); } if ($atomic_types['array'] instanceof TNonEmptyArray) { return new Union([$atomic_types['array']->count !== null ? new TLiteralInt($atomic_types['array']->count) : new TIntRange(1, null)]); } if ($atomic_types['array'] instanceof TKeyedArray) { $min = $atomic_types['array']->getMinCount(); $max = $atomic_types['array']->getMaxCount(); if ($min === $max) { return new Union([new TLiteralInt($max)]); } return Type::getIntRange($min, $max); } if ($atomic_types['array'] instanceof TArray && $atomic_types['array']->isEmptyArray()) { return Type::getInt(\false, 0); } return new Union([new TIntRange(0, null)]); } } } break; case 'hrtime': if ($first_arg_type = $statements_analyzer->node_data->getType($call_args[0]->value)) { if ((string) $first_arg_type === 'true') { return Type::getInt(\true); } $keyed_array = new TKeyedArray([Type::getInt(), Type::getInt()], null, null, \true); if ((string) $first_arg_type === 'false') { return new Union([$keyed_array]); } return new Union([$keyed_array, new TInt()]); } return Type::getInt(\true); case 'min': case 'max': if (isset($call_args[0])) { $first_arg = $call_args[0]->value; if ($first_arg_type = $statements_analyzer->node_data->getType($first_arg)) { if ($first_arg_type->hasArray()) { $array_type = $first_arg_type->getArray(); if ($array_type instanceof TKeyedArray) { return $array_type->getGenericValueType(); } if ($array_type instanceof TArray) { return $array_type->type_params[1]; } } elseif ($first_arg_type->hasScalarType() && ($second_arg = $call_args[1]->value ?? null) && ($second_arg_type = $statements_analyzer->node_data->getType($second_arg)) && $second_arg_type->hasScalarType()) { return Type::combineUnionTypes($first_arg_type, $second_arg_type); } } } break; case 'get_parent_class': // this is unreliable, as it's hard to know exactly what's wanted - attempted this in // https://github.com/vimeo/psalm/commit/355ed831e1c69c96bbf9bf2654ef64786cbe9fd7 // but caused problems where it didn’t know exactly what level of child we // were receiving. // // Really this should only work on instances we've created with new Foo(), // but that requires more work break; case 'fgetcsv': $string_type = new Union([new TString(), new TNull()], ['ignore_nullable_issues' => \true]); $call_map_return_type = new Union([Type::getNonEmptyListAtomic($string_type), new TFalse(), new TNull()], ['ignore_nullable_issues' => $codebase->config->ignore_internal_nullable_issues, 'ignore_falsable_issues' => $codebase->config->ignore_internal_falsable_issues]); return $call_map_return_type; case 'mb_strtolower': $string_arg_type = $statements_analyzer->node_data->getType($call_args[0]->value); if ($string_arg_type !== null && $string_arg_type->isNonEmptyString()) { $returnType = Type::getNonEmptyLowercaseString(); } else { $returnType = Type::getLowercaseString(); } if (count($call_args) < 2) { return $returnType; } else { $second_arg_type = $statements_analyzer->node_data->getType($call_args[1]->value); if ($second_arg_type && $second_arg_type->isNull()) { return $returnType; } } if ($string_arg_type !== null && $string_arg_type->isNonEmptyString()) { return Type::getNonEmptyString(); } else { return Type::getString(); } } } $stmt_type = $callmap_callable->return_type ?: Type::getMixed(); switch ($function_id) { case 'mb_strpos': case 'mb_strrpos': case 'mb_stripos': case 'mb_strripos': case 'strpos': case 'strrpos': case 'stripos': case 'strripos': case 'strstr': case 'stristr': case 'strrchr': case 'strpbrk': case 'array_search': break; default: if ($stmt_type->isFalsable() && $codebase->config->ignore_internal_falsable_issues) { $stmt_type = $stmt_type->setProperties(['ignore_falsable_issues' => \true]); } } return $stmt_type; } private static function taintReturnType(StatementsAnalyzer $statements_analyzer, PhpParser\Node\Expr\FuncCall $stmt, string $function_id, FunctionLikeStorage $function_storage, Union &$stmt_type, TemplateResult $template_result, Context $context) : ?DataFlowNode { if (!$statements_analyzer->data_flow_graph) { return null; } if ($statements_analyzer->data_flow_graph instanceof TaintFlowGraph && in_array('TaintedInput', $statements_analyzer->getSuppressedIssues())) { return null; } $codebase = $statements_analyzer->getCodebase(); $event = new AddRemoveTaintsEvent($stmt, $context, $statements_analyzer, $codebase); $added_taints = $codebase->config->eventDispatcher->dispatchAddTaints($event); $removed_taints = $codebase->config->eventDispatcher->dispatchRemoveTaints($event); $node_location = new CodeLocation($statements_analyzer->getSource(), $stmt); $function_call_node = DataFlowNode::getForMethodReturn($function_id, $function_id, $statements_analyzer->data_flow_graph instanceof TaintFlowGraph ? $function_storage->signature_return_type_location ?: $function_storage->location : ($function_storage->return_type_location ?: $function_storage->location), $function_storage->specialize_call ? $node_location : null); $statements_analyzer->data_flow_graph->addNode($function_call_node); $codebase = $statements_analyzer->getCodebase(); $conditionally_removed_taints = []; foreach ($function_storage->conditionally_removed_taints as $conditionally_removed_taint) { $conditionally_removed_taint = TemplateInferredTypeReplacer::replace($conditionally_removed_taint, $template_result, $codebase); $expanded_type = TypeExpander::expandUnion($statements_analyzer->getCodebase(), $conditionally_removed_taint, null, null, null, \true, \true); if (!$expanded_type->isNullable()) { foreach ($expanded_type->getLiteralStrings() as $literal_string) { $conditionally_removed_taints[] = $literal_string->value; } } } if ($conditionally_removed_taints && $function_storage->location) { $assignment_node = DataFlowNode::getForAssignment($function_id . '-escaped', $function_storage->signature_return_type_location ?: $function_storage->location, $function_call_node->specialization_key); $statements_analyzer->data_flow_graph->addPath($function_call_node, $assignment_node, 'conditionally-escaped', $added_taints, [...$removed_taints, ...$conditionally_removed_taints]); $stmt_type = $stmt_type->addParentNodes([$assignment_node->id => $assignment_node]); } else { $stmt_type = $stmt_type->addParentNodes([$function_call_node->id => $function_call_node]); } if ($function_storage->return_source_params && $statements_analyzer->data_flow_graph instanceof TaintFlowGraph) { $removed_taints = $function_storage->removed_taints; if ($function_id === 'preg_replace' && count($stmt->getArgs()) > 2) { $first_stmt_type = $statements_analyzer->node_data->getType($stmt->getArgs()[0]->value); $second_stmt_type = $statements_analyzer->node_data->getType($stmt->getArgs()[1]->value); if ($first_stmt_type && $second_stmt_type && $first_stmt_type->isSingleStringLiteral() && $second_stmt_type->isSingleStringLiteral()) { $first_arg_value = $first_stmt_type->getSingleStringLiteral()->value; $pattern = substr($first_arg_value, 1, -1); if (strlen(trim($pattern)) > 0) { $pattern = trim($pattern); if ($pattern[0] === '[' && $pattern[1] === '^' && substr($pattern, -1) === ']') { $pattern = substr($pattern, 2, -1); if (self::simpleExclusion($pattern, $first_arg_value[0])) { $removed_taints[] = TaintKind::INPUT_HTML; $removed_taints[] = TaintKind::INPUT_HAS_QUOTES; $removed_taints[] = TaintKind::INPUT_SQL; } } } } } $event = new AddRemoveTaintsEvent($stmt, $context, $statements_analyzer, $codebase); $added_taints = $codebase->config->eventDispatcher->dispatchAddTaints($event); $removed_taints = array_merge($removed_taints, $codebase->config->eventDispatcher->dispatchRemoveTaints($event)); self::taintUsingFlows($statements_analyzer, $function_storage, $statements_analyzer->data_flow_graph, $function_id, $stmt->getArgs(), $node_location, $function_call_node, array_merge($removed_taints, $conditionally_removed_taints), $added_taints); } if ($function_storage->taint_source_types && $statements_analyzer->data_flow_graph instanceof TaintFlowGraph) { $method_node = TaintSource::getForMethodReturn($function_id, $function_id, $node_location); $method_node->taints = $function_storage->taint_source_types; $statements_analyzer->data_flow_graph->addSource($method_node); } return $function_call_node; } /** * @param array $args * @param array $removed_taints * @param array $added_taints */ public static function taintUsingFlows(StatementsAnalyzer $statements_analyzer, FunctionLikeStorage $function_storage, TaintFlowGraph $graph, string $function_id, array $args, CodeLocation $node_location, DataFlowNode $function_call_node, array $removed_taints, array $added_taints = []) : void { foreach ($function_storage->return_source_params as $i => $path_type) { if (!isset($args[$i])) { continue; } $current_arg_is_variadic = $function_storage->params[$i]->is_variadic; $taintable_arg_index = [$i]; if ($current_arg_is_variadic) { $max_params = count($args) - 1; for ($arg_index = $i + 1; $arg_index <= $max_params; $arg_index++) { $taintable_arg_index[] = $arg_index; } } foreach ($taintable_arg_index as $arg_index) { $arg_location = new CodeLocation($statements_analyzer, $args[$arg_index]->value); $function_param_sink = DataFlowNode::getForMethodArgument($function_id, $function_id, $arg_index, $arg_location, $function_storage->specialize_call ? $node_location : null); $graph->addNode($function_param_sink); $graph->addPath($function_param_sink, $function_call_node, $path_type, array_merge($added_taints, $function_storage->added_taints), $removed_taints); } } } /** * @psalm-pure */ private static function simpleExclusion(string $pattern, string $escape_char) : bool { $str_length = strlen($pattern); for ($i = 0; $i < $str_length; $i++) { $current = $pattern[$i]; $next = $pattern[$i + 1] ?? null; if ($current === '\\') { if ($next === null || $next === 'x' || $next === 'u') { return \false; } if ($next === '.' || $next === '(' || $next === ')' || $next === '[' || $next === ']' || $next === 's' || $next === 'w' || $next === $escape_char) { $i++; continue; } return \false; } if ($next !== '-') { if ($current === '_' || $current === '-' || $current === '|' || $current === ':' || $current === '#' || $current === '.' || $current === ' ') { continue; } return \false; } if ($current === ']') { return \false; } if (!isset($pattern[$i + 2])) { return \false; } if ($current === 'a' && $pattern[$i + 2] === 'z' || $current === 'a' && $pattern[$i + 2] === 'Z' || $current === 'A' && $pattern[$i + 2] === 'Z' || $current === '0' && $pattern[$i + 2] === '9') { $i += 2; continue; } return \false; } return \true; } } as->isMixed()) { $extra_types = $lhs_type_part->extra_types; $lhs_type_part = array_values($lhs_type_part->as->getAtomicTypes())[0]; if ($lhs_type_part instanceof TNamedObject) { $lhs_type_part = $lhs_type_part->setIntersectionTypes($extra_types)->setFromDocblock(\true); } elseif ($lhs_type_part instanceof TObject && $extra_types) { $lhs_type_part = array_shift($extra_types)->setFromDocblock(\true); if ($extra_types) { $lhs_type_part = $lhs_type_part->setIntersectionTypes($extra_types); } } else { $lhs_type_part = $lhs_type_part->setFromDocblock(\true); } $result->has_mixed_method_call = \true; } $source = $statements_analyzer->getSource(); if ($lhs_type_part instanceof TCallableObject) { self::handleCallableObject($statements_analyzer, $stmt, $context, $lhs_type_part->callable, $result, $inferred_template_result); return; } if (!$lhs_type_part instanceof TNamedObject) { self::handleInvalidClass($statements_analyzer, $codebase, $stmt, $lhs_type, $lhs_type_part, $lhs_var_id, $context, $is_intersection, $result); return; } if (!$context->collect_initializations && !$context->collect_mutations && $statements_analyzer->getFilePath() === $statements_analyzer->getRootFilePath() && (!($parent_source = $statements_analyzer->getSource()) instanceof FunctionLikeAnalyzer || !$parent_source->getSource() instanceof TraitAnalyzer)) { $codebase->analyzer->incrementNonMixedCount($statements_analyzer->getFilePath()); } $result->has_valid_method_call_type = \true; $fq_class_name = $lhs_type_part->value; $is_mock = ExpressionAnalyzer::isMock($fq_class_name); $result->has_mock = $result->has_mock || $is_mock; if ($fq_class_name === 'static') { $fq_class_name = (string) $context->self; } if ($is_mock || $context->isPhantomClass($fq_class_name)) { $result->return_type = Type::getMixed(); ArgumentsAnalyzer::analyze($statements_analyzer, $stmt->getArgs(), null, null, \true, $context); return; } if ($lhs_var_id === '$this') { $does_class_exist = \true; } else { $does_class_exist = ClassLikeAnalyzer::checkFullyQualifiedClassLikeName($statements_analyzer, $fq_class_name, new CodeLocation($source, $stmt->var), $context->self, $context->calling_method_id, $statements_analyzer->getSuppressedIssues(), new ClassLikeNameOptions(\true, \false, \true, \true, $lhs_type_part->from_docblock), $context->check_classes); } if (!$does_class_exist) { return; } $class_storage = $codebase->classlike_storage_provider->get($fq_class_name); $result->check_visibility = $result->check_visibility && !$class_storage->override_method_visibility; $intersection_types = $lhs_type_part->getIntersectionTypes(); if (!$stmt->name instanceof PhpParser\Node\Identifier) { if (!$context->ignore_variable_method) { $codebase->analyzer->addMixedMemberName(strtolower($fq_class_name) . '::', $context->calling_method_id ?: $statements_analyzer->getFileName()); } if ($stmt->isFirstClassCallable()) { $return_type_candidate = null; $method_name_type = $statements_analyzer->node_data->getType($stmt->name); if ($method_name_type && $method_name_type->isSingleStringLiteral()) { $method_identifier = new MethodIdentifier($fq_class_name, strtolower($method_name_type->getSingleStringLiteral()->value)); //the call to methodExists will register that the method was called from somewhere if ($codebase->methods->methodExists($method_identifier, $context->calling_method_id, null, $statements_analyzer, $statements_analyzer->getFilePath(), \true, $context->insideUse())) { $method_storage = $codebase->methods->getStorage($method_identifier); $return_type_candidate = new Union([new TClosure('Closure', $method_storage->params, $method_storage->return_type, $method_storage->pure)]); } } $statements_analyzer->node_data->setType($stmt, $return_type_candidate ?? Type::getClosure()); return; } ArgumentsAnalyzer::analyze($statements_analyzer, $stmt->getArgs(), null, null, \true, $context); $result->return_type = Type::getMixed(); return; } $method_name_lc = strtolower($stmt->name->name); $method_id = new MethodIdentifier($fq_class_name, $method_name_lc); $args = $stmt->isFirstClassCallable() ? [] : $stmt->getArgs(); $naive_method_id = $method_id; // this tells us whether or not we can stay on the happy path $naive_method_exists = $codebase->methods->methodExists($method_id, $context->calling_method_id, $codebase->collect_locations ? new CodeLocation($source, $stmt->name) : null, !$context->collect_initializations && !$context->collect_mutations ? $statements_analyzer : null, $statements_analyzer->getFilePath(), \false, $context->insideUse()); $fake_method_exists = \false; if (!$naive_method_exists) { // if the method doesn't exist we check for any method existence providers if ($codebase->methods->existence_provider->has($fq_class_name)) { $method_exists = $codebase->methods->existence_provider->doesMethodExist($fq_class_name, $method_id->method_name, $source, null); if ($method_exists) { $fake_method_exists = \true; } } $naive_method_exists = \false; // @mixin attributes are an absolute pain! Lots of complexity here, // as they can redefine the called class, method id etc. if ($class_storage->templatedMixins && $lhs_type_part instanceof TGenericObject && $class_storage->template_types) { [$lhs_type_part, $class_storage, $naive_method_exists, $method_id, $fq_class_name] = self::handleTemplatedMixins($class_storage, $lhs_type_part, $method_name_lc, $codebase, $context, $method_id, $source, $stmt, $statements_analyzer, $fq_class_name); } elseif ($class_storage->mixin_declaring_fqcln && $class_storage->namedMixins) { [$lhs_type_part, $class_storage, $naive_method_exists, $method_id, $fq_class_name] = self::handleRegularMixins($class_storage, $lhs_type_part, $method_name_lc, $codebase, $context, $method_id, $source, $stmt, $statements_analyzer, $fq_class_name, $lhs_var_id); } } $all_intersection_return_type = null; $all_intersection_existent_method_ids = []; // intersection types are also fun, they also complicate matters if ($intersection_types) { [$all_intersection_return_type, $all_intersection_existent_method_ids] = self::getIntersectionReturnType($statements_analyzer, $stmt, $codebase, $context, $lhs_type, $lhs_type_part, $lhs_var_id, $result, $intersection_types); } if ($fake_method_exists && $codebase->methods->methodExists(new MethodIdentifier($fq_class_name, '__call')) || !$naive_method_exists || !MethodAnalyzer::isMethodVisible($method_id, $context, $statements_analyzer->getSource())) { $interface_has_method = \false; if ($class_storage->abstract && $class_storage->class_implements) { foreach ($class_storage->class_implements as $interface_fqcln_lc => $_) { $interface_storage = $codebase->classlike_storage_provider->get($interface_fqcln_lc); if (isset($interface_storage->methods[$method_name_lc])) { $interface_has_method = \true; $fq_class_name = $interface_storage->name; $method_id = new MethodIdentifier($fq_class_name, $method_name_lc); break; } } } if (!$interface_has_method && $codebase->methods->methodExists(new MethodIdentifier($fq_class_name, '__call'), $context->calling_method_id, $codebase->collect_locations ? new CodeLocation($source, $stmt->name) : null, !$context->collect_initializations && !$context->collect_mutations ? $statements_analyzer : null, $statements_analyzer->getFilePath(), \true, $context->insideUse())) { $new_call_context = \Psalm\Internal\Analyzer\Statements\Expression\Call\Method\MissingMethodCallHandler::handleMagicMethod($statements_analyzer, $codebase, $stmt, $method_id, $class_storage, $context, $codebase->config, $all_intersection_return_type, $result, $lhs_type_part); if ($new_call_context) { if ($method_id === $new_call_context->method_id) { return; } $method_id = $new_call_context->method_id; $args = $new_call_context->args; } else { return; } } } $intersection_method_id = $intersection_types ? '(' . $lhs_type_part . ')' . '::' . $stmt->name->name : null; $cased_method_id = $fq_class_name . '::' . $stmt->name->name; if ($lhs_var_id === '$this' && $context->self && $fq_class_name !== $context->self && $codebase->methods->methodExists(new MethodIdentifier($context->self, $method_name_lc))) { $method_id = new MethodIdentifier($context->self, $method_name_lc); $cased_method_id = $context->self . '::' . $stmt->name->name; $fq_class_name = $context->self; } $source_method_id = $source instanceof FunctionLikeAnalyzer ? $source->getId() : null; $corrected_method_exists = $naive_method_exists && $method_id === $naive_method_id || $method_id !== $naive_method_id && $codebase->methods->methodExists($method_id, $context->calling_method_id, $codebase->collect_locations && $method_id !== $source_method_id ? new CodeLocation($source, $stmt->name) : null); if (!$corrected_method_exists || $codebase->config->use_phpdoc_method_without_magic_or_parent && isset($class_storage->pseudo_methods[$method_name_lc])) { \Psalm\Internal\Analyzer\Statements\Expression\Call\Method\MissingMethodCallHandler::handleMissingOrMagicMethod($statements_analyzer, $codebase, $stmt, $method_id, $codebase->interfaceExists($fq_class_name), $context, $codebase->config, $all_intersection_return_type, $all_intersection_existent_method_ids, $intersection_method_id, $cased_method_id, $result, $lhs_type_part); return; } $old_node_data = $statements_analyzer->node_data; $return_type_candidate = \Psalm\Internal\Analyzer\Statements\Expression\Call\Method\ExistingAtomicMethodCallAnalyzer::analyze($statements_analyzer, $stmt, $stmt->name, $args, $codebase, $context, $lhs_type_part, $static_type, $lhs_var_id, $method_id, $result, $inferred_template_result); $statements_analyzer->node_data = $old_node_data; $declaring_method_id = $codebase->methods->getDeclaringMethodId($method_id); $in_call_map = InternalCallMapHandler::inCallMap((string) ($declaring_method_id ?? $method_id)); if (!$in_call_map) { if ($result->check_visibility) { $name_code_location = new CodeLocation($statements_analyzer, $stmt->name); \Psalm\Internal\Analyzer\Statements\Expression\Call\Method\MethodVisibilityAnalyzer::analyze($method_id, $context, $statements_analyzer->getSource(), $name_code_location, $statements_analyzer->getSuppressedIssues()); } } self::updateResultReturnType($result, $return_type_candidate, $all_intersection_return_type, $codebase); } /** * @param TNamedObject|TTemplateParam $lhs_type_part * @param array $intersection_types * @return array{?Union, array} */ private static function getIntersectionReturnType(StatementsAnalyzer $statements_analyzer, PhpParser\Node\Expr\MethodCall $stmt, Codebase $codebase, Context $context, Union $lhs_type, Atomic $lhs_type_part, ?string $lhs_var_id, \Psalm\Internal\Analyzer\Statements\Expression\Call\Method\AtomicMethodCallAnalysisResult $result, array $intersection_types) : array { $all_intersection_return_type = null; $all_intersection_existent_method_ids = []; foreach ($intersection_types as $intersection_type) { $intersection_result = clone $result; /** @var ?Union $intersection_result->return_type */ $intersection_result->return_type = null; self::analyze($statements_analyzer, $stmt, $codebase, $context, $lhs_type, $intersection_type, $lhs_type_part, \true, $lhs_var_id, $intersection_result); $result->returns_by_ref = $intersection_result->returns_by_ref; $result->has_mock = $intersection_result->has_mock; $result->has_valid_method_call_type = $intersection_result->has_valid_method_call_type; $result->has_mixed_method_call = $intersection_result->has_mixed_method_call; $result->invalid_method_call_types = $intersection_result->invalid_method_call_types; $result->check_visibility = $intersection_result->check_visibility; $result->too_many_arguments = $intersection_result->too_many_arguments; $all_intersection_existent_method_ids = array_merge($all_intersection_existent_method_ids, $intersection_result->existent_method_ids); if ($intersection_result->return_type) { if (!$all_intersection_return_type || $all_intersection_return_type->isMixed()) { $all_intersection_return_type = $intersection_result->return_type; } else { $all_intersection_return_type = Type::intersectUnionTypes($all_intersection_return_type, $intersection_result->return_type, $codebase) ?? Type::getMixed(); } } } return [$all_intersection_return_type, $all_intersection_existent_method_ids]; } private static function updateResultReturnType(\Psalm\Internal\Analyzer\Statements\Expression\Call\Method\AtomicMethodCallAnalysisResult $result, Union $return_type_candidate, ?Union $all_intersection_return_type, Codebase $codebase) : void { if ($all_intersection_return_type) { $return_type_candidate = Type::intersectUnionTypes($all_intersection_return_type, $return_type_candidate, $codebase) ?? Type::getMixed(); } $result->return_type = Type::combineUnionTypes($return_type_candidate, $result->return_type); } private static function handleInvalidClass(StatementsAnalyzer $statements_analyzer, Codebase $codebase, PhpParser\Node\Expr\MethodCall $stmt, Union $lhs_type, Atomic $lhs_type_part, ?string $lhs_var_id, Context $context, bool $is_intersection, \Psalm\Internal\Analyzer\Statements\Expression\Call\Method\AtomicMethodCallAnalysisResult $result) : void { switch (get_class($lhs_type_part)) { case TNull::class: case TFalse::class: // handled above return; case TTemplateParam::class: case TEmptyMixed::class: case TNever::class: case TMixed::class: case TNonEmptyMixed::class: case TObject::class: case TObjectWithProperties::class: if (!$context->collect_initializations && !$context->collect_mutations && $statements_analyzer->getFilePath() === $statements_analyzer->getRootFilePath() && (!($parent_source = $statements_analyzer->getSource()) instanceof FunctionLikeAnalyzer || !$parent_source->getSource() instanceof TraitAnalyzer)) { $codebase->analyzer->incrementMixedCount($statements_analyzer->getFilePath()); } $result->has_mixed_method_call = \true; if ($lhs_type_part instanceof TObjectWithProperties && $stmt->name instanceof PhpParser\Node\Identifier && isset($lhs_type_part->methods[strtolower($stmt->name->name)])) { $method_id = $lhs_type_part->methods[strtolower($stmt->name->name)]; $result->existent_method_ids[$method_id] = \true; } elseif (!$is_intersection) { if ($stmt->name instanceof PhpParser\Node\Identifier) { $codebase->analyzer->addMixedMemberName(strtolower($stmt->name->name), $context->calling_method_id ?: $statements_analyzer->getFileName()); } if ($context->check_methods) { $message = 'Cannot determine the type of the object' . ' on the left hand side of this expression'; if ($lhs_var_id) { $message = 'Cannot determine the type of ' . $lhs_var_id; if ($stmt->name instanceof PhpParser\Node\Identifier) { $message .= ' when calling method ' . $stmt->name->name; } } $origin_locations = []; if ($statements_analyzer->data_flow_graph instanceof VariableUseGraph) { foreach ($lhs_type->parent_nodes as $parent_node) { $origin_locations = [...$origin_locations, ...$statements_analyzer->data_flow_graph->getOriginLocations($parent_node)]; } } $origin_location = count($origin_locations) === 1 ? reset($origin_locations) : null; $name_code_location = new CodeLocation($statements_analyzer, $stmt->name); if ($origin_location && $origin_location->getHash() === $name_code_location->getHash()) { $origin_location = null; } IssueBuffer::maybeAdd(new MixedMethodCall($message, $name_code_location, $origin_location), $statements_analyzer->getSuppressedIssues()); } } if ($stmt->isFirstClassCallable()) { $result->return_type = Type::getClosure(); } else { if (ArgumentsAnalyzer::analyze($statements_analyzer, $stmt->getArgs(), null, null, \true, $context) === \false) { return; } $result->return_type = Type::getMixed(); } return; default: $result->invalid_method_call_types[] = (string) $lhs_type_part; return; } } /** * @param lowercase-string $method_name_lc * @return array{TNamedObject, ClassLikeStorage, bool, MethodIdentifier, string} */ private static function handleTemplatedMixins(ClassLikeStorage $class_storage, TNamedObject $lhs_type_part, string $method_name_lc, Codebase $codebase, Context $context, MethodIdentifier $method_id, StatementsSource $source, PhpParser\Node\Expr\MethodCall $stmt, StatementsAnalyzer $statements_analyzer, string $fq_class_name) : array { $naive_method_exists = \false; if ($class_storage->templatedMixins && $lhs_type_part instanceof TGenericObject && $class_storage->template_types) { $template_type_keys = array_keys($class_storage->template_types); foreach ($class_storage->templatedMixins as $mixin) { $param_position = array_search($mixin->param_name, $template_type_keys, \true); if ($param_position !== \false && isset($lhs_type_part->type_params[$param_position])) { $current_type_param = $lhs_type_part->type_params[$param_position]; if ($current_type_param->isSingle()) { $lhs_type_part_new = array_values($current_type_param->getAtomicTypes())[0]; if ($lhs_type_part_new instanceof TNamedObject) { $new_method_id = new MethodIdentifier($lhs_type_part_new->value, $method_name_lc); $mixin_class_storage = $codebase->classlike_storage_provider->get($lhs_type_part_new->value); if ($codebase->methods->methodExists($new_method_id, $context->calling_method_id, $codebase->collect_locations ? new CodeLocation($source, $stmt->name) : null, !$context->collect_initializations && !$context->collect_mutations ? $statements_analyzer : null, $statements_analyzer->getFilePath(), \true, $context->insideUse())) { $lhs_type_part = $lhs_type_part_new; $class_storage = $mixin_class_storage; $naive_method_exists = \true; $method_id = $new_method_id; } elseif (isset($mixin_class_storage->pseudo_methods[$method_name_lc])) { $lhs_type_part = $lhs_type_part_new; $class_storage = $mixin_class_storage; $method_id = $new_method_id; } } } } } } return [$lhs_type_part, $class_storage, $naive_method_exists, $method_id, $fq_class_name]; } /** * @param lowercase-string $method_name_lc * @return array{TNamedObject, ClassLikeStorage, bool, MethodIdentifier, string} */ private static function handleRegularMixins(ClassLikeStorage $class_storage, TNamedObject $lhs_type_part, string $method_name_lc, Codebase $codebase, Context $context, MethodIdentifier $method_id, StatementsSource $source, PhpParser\Node\Expr\MethodCall $stmt, StatementsAnalyzer $statements_analyzer, string $fq_class_name, ?string $lhs_var_id) : array { $naive_method_exists = \false; foreach ($class_storage->namedMixins as $mixin) { if (!$class_storage->mixin_declaring_fqcln) { continue; } $new_method_id = new MethodIdentifier($mixin->value, $method_name_lc); if ($codebase->methods->methodExists($new_method_id, $context->calling_method_id, $codebase->collect_locations ? new CodeLocation($source, $stmt->name) : null, !$context->collect_initializations && !$context->collect_mutations ? $statements_analyzer : null, $statements_analyzer->getFilePath(), \true, $context->insideUse())) { $mixin_declaring_class_storage = $codebase->classlike_storage_provider->get($class_storage->mixin_declaring_fqcln); $mixin_class_template_params = ClassTemplateParamCollector::collect($codebase, $mixin_declaring_class_storage, $codebase->classlike_storage_provider->get($fq_class_name), null, $lhs_type_part, $lhs_var_id === '$this'); $lhs_type_part = $mixin->replaceTemplateTypesWithArgTypes(new TemplateResult([], $mixin_class_template_params ?: []), $codebase); $lhs_type_expanded = TypeExpander::expandUnion($codebase, new Union([$lhs_type_part]), $mixin_declaring_class_storage->name, $fq_class_name, $class_storage->parent_class, \true, \false, $class_storage->final); $new_lhs_type_part = $lhs_type_expanded->getSingleAtomic(); if ($new_lhs_type_part instanceof TNamedObject) { $lhs_type_part = $new_lhs_type_part; } $mixin_class_storage = $codebase->classlike_storage_provider->get($mixin->value); $fq_class_name = $mixin_class_storage->name; $mixin_class_storage->mixin_declaring_fqcln = $class_storage->mixin_declaring_fqcln; $class_storage = $mixin_class_storage; $naive_method_exists = \true; $method_id = $new_method_id; } } return [$lhs_type_part, $class_storage, $naive_method_exists, $method_id, $fq_class_name]; } private static function handleCallableObject(StatementsAnalyzer $statements_analyzer, PhpParser\Node\Expr\MethodCall $stmt, Context $context, ?TCallable $lhs_type_part_callable, \Psalm\Internal\Analyzer\Statements\Expression\Call\Method\AtomicMethodCallAnalysisResult $result, ?TemplateResult $inferred_template_result = null) : void { $method_id = 'object::__invoke'; $result->existent_method_ids[$method_id] = \true; $result->has_valid_method_call_type = \true; if ($lhs_type_part_callable !== null) { $result->return_type = $lhs_type_part_callable->return_type ?? Type::getMixed(); $callableArgumentCount = count($lhs_type_part_callable->params ?? []); $providedArgumentsCount = count($stmt->getArgs()); if ($callableArgumentCount > $providedArgumentsCount) { $result->too_few_arguments = \true; $result->too_few_arguments_method_ids[] = new MethodIdentifier('callable-object', '__invoke'); } elseif ($providedArgumentsCount > $callableArgumentCount) { $result->too_many_arguments = \true; $result->too_many_arguments_method_ids[] = new MethodIdentifier('callable-object', '__invoke'); } $template_result = $inferred_template_result ?? new TemplateResult([], []); ArgumentsAnalyzer::analyze($statements_analyzer, $stmt->getArgs(), $lhs_type_part_callable->params, $method_id, \false, $context, $template_result); ArgumentsAnalyzer::checkArgumentsMatch($statements_analyzer, $stmt->getArgs(), $method_id, $lhs_type_part_callable->params ?? [], null, null, $template_result, new CodeLocation($statements_analyzer->getSource(), $stmt), $context); } } } $args */ public static function fetch(StatementsAnalyzer $statements_analyzer, Codebase $codebase, PhpParser\Node\Expr\MethodCall $stmt, Context $context, MethodIdentifier $method_id, ?MethodIdentifier $declaring_method_id, MethodIdentifier $premixin_method_id, string $cased_method_id, Atomic $lhs_type_part, ?Atomic $static_type, array $args, \Psalm\Internal\Analyzer\Statements\Expression\Call\Method\AtomicMethodCallAnalysisResult $result, TemplateResult $template_result) : Union { $call_map_id = $declaring_method_id ?? $method_id; $fq_class_name = $method_id->fq_class_name; $method_name = $method_id->method_name; $class_storage = $codebase->methods->getClassLikeStorageForMethod($method_id); $method_storage = $class_storage->methods[$method_id->method_name] ?? null; if ($stmt->isFirstClassCallable()) { if ($method_storage) { return new Union([new TClosure('Closure', $method_storage->params, $method_storage->return_type, $method_storage->pure)]); } return Type::getClosure(); } if ($codebase->methods->return_type_provider->has($premixin_method_id->fq_class_name)) { $return_type_candidate = $codebase->methods->return_type_provider->getReturnType($statements_analyzer, $premixin_method_id->fq_class_name, $premixin_method_id->method_name, $stmt, $context, new CodeLocation($statements_analyzer->getSource(), $stmt->name), $lhs_type_part instanceof TGenericObject ? $lhs_type_part->type_params : null); if ($return_type_candidate) { return $return_type_candidate; } } if ($premixin_method_id->method_name === 'getcode' && $premixin_method_id->fq_class_name !== Exception::class && $premixin_method_id->fq_class_name !== RuntimeException::class && $premixin_method_id->fq_class_name !== PDOException::class && ($codebase->classImplements($premixin_method_id->fq_class_name, Throwable::class) || $codebase->interfaceExtends($premixin_method_id->fq_class_name, Throwable::class))) { return Type::getInt(); } if ($declaring_method_id && $declaring_method_id !== $method_id) { $declaring_fq_class_name = $declaring_method_id->fq_class_name; $declaring_method_name = $declaring_method_id->method_name; if ($codebase->methods->return_type_provider->has($declaring_fq_class_name)) { $return_type_candidate = $codebase->methods->return_type_provider->getReturnType($statements_analyzer, $declaring_fq_class_name, $declaring_method_name, $stmt, $context, new CodeLocation($statements_analyzer->getSource(), $stmt->name), $lhs_type_part instanceof TGenericObject ? $lhs_type_part->type_params : null, $fq_class_name, $method_name); if ($return_type_candidate) { return $return_type_candidate; } } } if (InternalCallMapHandler::inCallMap((string) $call_map_id)) { if (($template_result->lower_bounds || $class_storage->stubbed) && ($method_storage = $class_storage->methods[$method_id->method_name] ?? null) && $method_storage->return_type) { $return_type_candidate = $method_storage->return_type; $return_type_candidate = self::replaceTemplateTypes($return_type_candidate, $template_result, $method_id, count($stmt->getArgs()), $codebase); } else { $callmap_callables = InternalCallMapHandler::getCallablesFromCallMap((string) $call_map_id); if (!$callmap_callables || $callmap_callables[0]->return_type === null) { throw new UnexpectedValueException('Shouldn’t get here'); } $return_type_candidate = $callmap_callables[0]->return_type; } if ($return_type_candidate->isFalsable()) { $return_type_candidate = $return_type_candidate->setProperties(['ignore_falsable_issues' => \true]); } $return_type_candidate = TypeExpander::expandUnion($codebase, $return_type_candidate, $fq_class_name, $static_type, $class_storage->parent_class, \true, \false, \false, \true); } else { $self_fq_class_name = $fq_class_name; $return_type_candidate = $codebase->methods->getMethodReturnType($method_id, $self_fq_class_name, $statements_analyzer, $args, $template_result); if ($return_type_candidate) { if ($template_result->lower_bounds) { $return_type_candidate = TypeExpander::expandUnion($codebase, $return_type_candidate, $fq_class_name, null, $class_storage->parent_class, \true, \false, $static_type instanceof TNamedObject && $codebase->classlike_storage_provider->get($static_type->value)->final, \true); } $return_type_candidate = self::replaceTemplateTypes($return_type_candidate, $template_result, $method_id, count($stmt->getArgs()), $codebase); $return_type_candidate = TypeExpander::expandUnion($codebase, $return_type_candidate, $self_fq_class_name, $static_type, $class_storage->parent_class, \true, \false, $static_type instanceof TNamedObject && $codebase->classlike_storage_provider->get($static_type->value)->final, \true); $return_type_location = $codebase->methods->getMethodReturnTypeLocation($method_id, $secondary_return_type_location); if ($secondary_return_type_location) { $return_type_location = $secondary_return_type_location; } $config = Config::getInstance(); // only check the type locally if it's defined externally if ($return_type_location && !$config->isInProjectDirs($return_type_location->file_path)) { /** @psalm-suppress UnusedMethodCall Actually generates issues */ $return_type_candidate->check($statements_analyzer, new CodeLocation($statements_analyzer, $stmt), $statements_analyzer->getSuppressedIssues(), $context->phantom_classes, \true, \false, \false, $context->calling_method_id); } } else { $result->returns_by_ref = $result->returns_by_ref || $codebase->methods->getMethodReturnsByRef($method_id); } } if (!$return_type_candidate) { $return_type_candidate = $method_name === '__tostring' ? Type::getString() : Type::getMixed(); } self::taintMethodCallResult($statements_analyzer, $return_type_candidate, $stmt->name, $stmt->var, $args, $method_id, $declaring_method_id, $cased_method_id, $context); return $return_type_candidate; } /** * @param array $args */ public static function taintMethodCallResult(StatementsAnalyzer $statements_analyzer, Union &$return_type_candidate, PhpParser\Node $name_expr, PhpParser\Node\Expr $var_expr, array $args, MethodIdentifier $method_id, ?MethodIdentifier $declaring_method_id, string $cased_method_id, Context $context) : void { if (!$statements_analyzer->data_flow_graph || !$declaring_method_id) { return; } if ($statements_analyzer->data_flow_graph instanceof TaintFlowGraph && in_array('TaintedInput', $statements_analyzer->getSuppressedIssues())) { return; } $codebase = $statements_analyzer->getCodebase(); $event = new AddRemoveTaintsEvent($var_expr, $context, $statements_analyzer, $codebase); $added_taints = $codebase->config->eventDispatcher->dispatchAddTaints($event); $removed_taints = $codebase->config->eventDispatcher->dispatchRemoveTaints($event); $method_storage = $codebase->methods->getStorage($declaring_method_id); $node_location = new CodeLocation($statements_analyzer, $name_expr); $is_declaring = (string) $declaring_method_id === (string) $method_id; $var_id = ExpressionIdentifier::getExtendedVarId($var_expr, null, $statements_analyzer); if ($method_storage->specialize_call && $statements_analyzer->data_flow_graph instanceof TaintFlowGraph) { if ($var_id && isset($context->vars_in_scope[$var_id])) { $var_nodes = []; $parent_nodes = $context->vars_in_scope[$var_id]->parent_nodes; $unspecialized_parent_nodes = array_filter($parent_nodes, static fn(DataFlowNode $parent_node): bool => !$parent_node->specialization_key); $specialized_parent_nodes = array_filter($parent_nodes, static fn(DataFlowNode $parent_node): bool => (bool) $parent_node->specialization_key); $var_node = DataFlowNode::getForAssignment($var_id, new CodeLocation($statements_analyzer, $var_expr)); if ($method_storage->location) { $this_parent_node = DataFlowNode::getForAssignment('$this in ' . $method_id, $method_storage->location); foreach ($parent_nodes as $parent_node) { $statements_analyzer->data_flow_graph->addPath($parent_node, $this_parent_node, '=', $added_taints, $removed_taints); } } $var_nodes[$var_node->id] = $var_node; $method_call_nodes = []; if ($unspecialized_parent_nodes) { $method_call_node = DataFlowNode::getForMethodReturn((string) $method_id, $cased_method_id, $is_declaring ? $method_storage->signature_return_type_location ?: $method_storage->location : null, $node_location); $method_call_nodes[$method_call_node->id] = $method_call_node; } foreach ($specialized_parent_nodes as $parent_node) { $universal_method_call_node = DataFlowNode::getForMethodReturn((string) $method_id, $cased_method_id, $is_declaring ? $method_storage->signature_return_type_location ?: $method_storage->location : null, null); $method_call_node = new DataFlowNode(strtolower((string) $method_id), $cased_method_id, $is_declaring ? $method_storage->signature_return_type_location ?: $method_storage->location : null, $parent_node->specialization_key); $statements_analyzer->data_flow_graph->addPath($universal_method_call_node, $method_call_node, '=', $added_taints, $removed_taints); $method_call_nodes[$method_call_node->id] = $method_call_node; } if (!$method_call_nodes) { return; } foreach ($method_call_nodes as $method_call_node) { $statements_analyzer->data_flow_graph->addNode($method_call_node); foreach ($var_nodes as $var_node) { $statements_analyzer->data_flow_graph->addNode($var_node); $statements_analyzer->data_flow_graph->addPath($method_call_node, $var_node, 'method-call-' . $method_id->method_name, $added_taints, $removed_taints); } if (!$is_declaring) { $cased_declaring_method_id = $codebase->methods->getCasedMethodId($declaring_method_id); $declaring_method_call_node = new DataFlowNode(strtolower((string) $declaring_method_id), $cased_declaring_method_id, $method_storage->signature_return_type_location ?: $method_storage->location, $method_call_node->specialization_key); $statements_analyzer->data_flow_graph->addNode($declaring_method_call_node); $statements_analyzer->data_flow_graph->addPath($declaring_method_call_node, $method_call_node, 'parent', $added_taints, $removed_taints); } } $return_type_candidate = $return_type_candidate->setParentNodes($method_call_nodes); $stmt_var_type = $context->vars_in_scope[$var_id]->setParentNodes($var_nodes); $context->vars_in_scope[$var_id] = $stmt_var_type; } else { $method_call_node = DataFlowNode::getForMethodReturn((string) $method_id, $cased_method_id, $is_declaring ? $method_storage->signature_return_type_location ?: $method_storage->location : null, $node_location); if (!$is_declaring) { $cased_declaring_method_id = $codebase->methods->getCasedMethodId($declaring_method_id); $declaring_method_call_node = DataFlowNode::getForMethodReturn((string) $declaring_method_id, $cased_declaring_method_id, $method_storage->signature_return_type_location ?: $method_storage->location, $node_location); $statements_analyzer->data_flow_graph->addNode($declaring_method_call_node); $statements_analyzer->data_flow_graph->addPath($declaring_method_call_node, $method_call_node, 'parent', $added_taints, $removed_taints); } $statements_analyzer->data_flow_graph->addNode($method_call_node); $return_type_candidate = $return_type_candidate->setParentNodes([$method_call_node->id => $method_call_node]); } } else { $method_call_node = DataFlowNode::getForMethodReturn((string) $method_id, $cased_method_id, $is_declaring ? $statements_analyzer->data_flow_graph instanceof TaintFlowGraph ? $method_storage->signature_return_type_location ?: $method_storage->location : ($method_storage->return_type_location ?: $method_storage->location) : null, null); if (!$is_declaring) { $cased_declaring_method_id = $codebase->methods->getCasedMethodId($declaring_method_id); $declaring_method_call_node = DataFlowNode::getForMethodReturn((string) $declaring_method_id, $cased_declaring_method_id, $method_storage->signature_return_type_location ?: $method_storage->location, null); $statements_analyzer->data_flow_graph->addNode($declaring_method_call_node); $statements_analyzer->data_flow_graph->addPath($declaring_method_call_node, $method_call_node, 'parent', $added_taints, $removed_taints); } $statements_analyzer->data_flow_graph->addNode($method_call_node); $return_type_candidate = $return_type_candidate->setParentNodes([$method_call_node->id => $method_call_node]); } if (!$statements_analyzer->data_flow_graph instanceof TaintFlowGraph) { return; } if ($method_storage->taint_source_types) { $method_node = TaintSource::getForMethodReturn((string) $method_id, $cased_method_id, $method_storage->signature_return_type_location ?: $method_storage->location); $method_node->taints = $method_storage->taint_source_types; $statements_analyzer->data_flow_graph->addSource($method_node); } FunctionCallReturnTypeFetcher::taintUsingFlows($statements_analyzer, $method_storage, $statements_analyzer->data_flow_graph, (string) $method_id, $args, $node_location, $method_call_node, $method_storage->removed_taints); } public static function replaceTemplateTypes(Union $return_type_candidate, TemplateResult $template_result, MethodIdentifier $method_id, int $arg_count, Codebase $codebase) : Union { if ($template_result->template_types) { $bindable_template_types = $return_type_candidate->getTemplateTypes(); foreach ($bindable_template_types as $template_type) { if ($template_type->defining_class !== $method_id->fq_class_name && !isset($template_result->lower_bounds[$template_type->param_name][$template_type->defining_class])) { if ($template_type->param_name === 'TFunctionArgCount') { $template_result->lower_bounds[$template_type->param_name] = ['fn-' . strtolower((string) $method_id) => [new TemplateBound(Type::getInt(\false, $arg_count))]]; } elseif ($template_type->param_name === 'TPhpMajorVersion') { $template_result->lower_bounds[$template_type->param_name] = ['fn-' . strtolower((string) $method_id) => [new TemplateBound(Type::getInt(\false, $codebase->getMajorAnalysisPhpVersion()))]]; } elseif ($template_type->param_name === 'TPhpVersionId') { $template_result->lower_bounds[$template_type->param_name] = ['fn-' . strtolower((string) $method_id) => [new TemplateBound(Type::getInt(\false, $codebase->analysis_php_version_id))]]; } else { $template_result->lower_bounds[$template_type->param_name] = [$template_type->defining_class => [new TemplateBound(Type::getNever())]]; } } } } if ($template_result->lower_bounds) { $return_type_candidate = TypeExpander::expandUnion($codebase, $return_type_candidate, null, null, null); $return_type_candidate = TemplateInferredTypeReplacer::replace($return_type_candidate, $template_result, $codebase); } return $return_type_candidate; } } */ public array $args; /** @param list $args */ public function __construct(MethodIdentifier $method_id, array $args) { $this->method_id = $method_id; $this->args = $args; } } $args */ public static function analyze(StatementsAnalyzer $statements_analyzer, PhpParser\Node\Expr\MethodCall $stmt, PhpParser\Node\Identifier $stmt_name, array $args, Codebase $codebase, Context $context, TNamedObject $lhs_type_part, ?Atomic $static_type, ?string $lhs_var_id, MethodIdentifier $method_id, \Psalm\Internal\Analyzer\Statements\Expression\Call\Method\AtomicMethodCallAnalysisResult $result, ?TemplateResult $inferred_template_result = null) : Union { $config = $codebase->config; $fq_class_name = $lhs_type_part->value; if ($fq_class_name === 'static') { $fq_class_name = (string) $context->self; } $method_name_lc = $method_id->method_name; $cased_method_id = $fq_class_name . '::' . $stmt_name->name; $result->existent_method_ids[$method_id->__toString()] = \true; if ($context->collect_initializations && $context->calling_method_id) { [$calling_method_class] = explode('::', $context->calling_method_id); $codebase->file_reference_provider->addMethodReferenceToClassMember($calling_method_class . '::__construct', strtolower((string) $method_id), \false); } if ($codebase->store_node_types && !$stmt->isFirstClassCallable() && !$context->collect_initializations && !$context->collect_mutations) { ArgumentMapPopulator::recordArgumentPositions($statements_analyzer, $stmt, $codebase, (string) $method_id); } if ($fq_class_name === 'Closure' && $method_name_lc === '__invoke') { $statements_analyzer->node_data = clone $statements_analyzer->node_data; $fake_function_call = new VirtualFuncCall($stmt->var, $args, $stmt->getAttributes()); FunctionCallAnalyzer::analyze($statements_analyzer, $fake_function_call, $context); return $statements_analyzer->node_data->getType($fake_function_call) ?? Type::getMixed(); } $source = $statements_analyzer->getSource(); if ($codebase->store_node_types && !$context->collect_initializations && !$context->collect_mutations) { $codebase->analyzer->addNodeReference($statements_analyzer->getFilePath(), $stmt_name, $method_id . '()'); } if ($context->collect_initializations && $context->calling_method_id) { [$calling_method_class] = explode('::', $context->calling_method_id); $codebase->file_reference_provider->addMethodReferenceToClassMember($calling_method_class . '::__construct', strtolower((string) $method_id), \false); } if ($stmt->var instanceof PhpParser\Node\Expr\Variable && ($context->collect_initializations || $context->collect_mutations) && $stmt->var->name === 'this' && $source instanceof FunctionLikeAnalyzer) { self::collectSpecialInformation($source, $stmt_name->name, $context); } $fq_class_name = $codebase->classlikes->getUnAliasedName($fq_class_name); $class_storage = $codebase->classlike_storage_provider->get($fq_class_name); $parent_source = $statements_analyzer->getSource(); $class_template_params = ClassTemplateParamCollector::collect($codebase, $codebase->methods->getClassLikeStorageForMethod($method_id), $class_storage, $method_name_lc, $lhs_type_part, $lhs_var_id === '$this'); if ($lhs_var_id === '$this' && $parent_source instanceof FunctionLikeAnalyzer) { $grandparent_source = $parent_source->getSource(); if ($grandparent_source instanceof TraitAnalyzer) { $fq_trait_name = $grandparent_source->getFQCLN(); $fq_trait_name_lc = strtolower($fq_trait_name); $trait_storage = $codebase->classlike_storage_provider->get($fq_trait_name_lc); if (isset($trait_storage->methods[$method_name_lc])) { $trait_method_id = new MethodIdentifier($trait_storage->name, $method_name_lc); $class_template_params = ClassTemplateParamCollector::collect($codebase, $codebase->methods->getClassLikeStorageForMethod($trait_method_id), $class_storage, $method_name_lc, $lhs_type_part, \true); } } } $declaring_method_id = $codebase->methods->getDeclaringMethodId($method_id); try { $method_storage = $codebase->methods->getStorage($declaring_method_id ?? $method_id); } catch (UnexpectedValueException $e) { $method_storage = null; } $method_template_params = []; if ($method_storage && $method_storage->if_this_is_type) { $method_template_result = new TemplateResult($method_storage->template_types ?: [], []); TemplateStandinTypeReplacer::fillTemplateResult($method_storage->if_this_is_type, $method_template_result, $codebase, null, new Union([$lhs_type_part])); $method_template_params = $method_template_result->lower_bounds; } $template_result = new TemplateResult([], $class_template_params ?: []); $template_result->lower_bounds += $method_template_params; if ($inferred_template_result) { $template_result->lower_bounds += $inferred_template_result->lower_bounds; } if ($method_storage && $method_storage->template_types) { $template_result->template_types += $method_storage->template_types; } if ($codebase->store_node_types && !$stmt->isFirstClassCallable() && !$context->collect_initializations && !$context->collect_mutations) { ArgumentMapPopulator::recordArgumentPositions($statements_analyzer, $stmt, $codebase, (string) $method_id); } $is_first_class_callable = $stmt->isFirstClassCallable(); if (!$is_first_class_callable && self::checkMethodArgs($method_id, $args, $template_result, $context, new CodeLocation($source, $stmt_name), $statements_analyzer) === \false) { return Type::getMixed(); } $return_type_candidate = \Psalm\Internal\Analyzer\Statements\Expression\Call\Method\MethodCallReturnTypeFetcher::fetch($statements_analyzer, $codebase, $stmt, $context, $method_id, $declaring_method_id, $method_id, $cased_method_id, $lhs_type_part, $static_type, $args, $result, $template_result); if ($is_first_class_callable) { return $return_type_candidate; } $in_call_map = InternalCallMapHandler::inCallMap((string) ($declaring_method_id ?? $method_id)); if (!$in_call_map) { $name_code_location = new CodeLocation($statements_analyzer, $stmt_name); \Psalm\Internal\Analyzer\Statements\Expression\Call\Method\MethodCallProhibitionAnalyzer::analyze($codebase, $context, $method_id, $statements_analyzer->getFullyQualifiedFunctionMethodOrNamespaceName(), $name_code_location, $statements_analyzer->getSuppressedIssues()); $getter_return_type = self::getMagicGetterOrSetterProperty($statements_analyzer, $stmt, $stmt_name, $context, $fq_class_name); if ($getter_return_type) { $return_type_candidate = $getter_return_type; } } if ($method_storage) { if ($method_storage->if_this_is_type) { $class_type = new Union([$lhs_type_part]); $if_this_is_type = TemplateInferredTypeReplacer::replace($method_storage->if_this_is_type, $template_result, $codebase); if (!UnionTypeComparator::isContainedBy($codebase, $class_type, $if_this_is_type)) { IssueBuffer::maybeAdd(new IfThisIsMismatch('Class type must be ' . $method_storage->if_this_is_type->getId() . ' current type ' . $class_type->getId(), new CodeLocation($source, $stmt->name)), $statements_analyzer->getSuppressedIssues()); } } if ($method_storage->self_out_type && $lhs_var_id) { $self_out_candidate = $method_storage->self_out_type; if ($template_result->lower_bounds) { $self_out_candidate = TypeExpander::expandUnion($codebase, $self_out_candidate, $fq_class_name, null, $class_storage->parent_class, \true, \false, $static_type instanceof TNamedObject && $codebase->classlike_storage_provider->get($static_type->value)->final, \true); } $self_out_candidate = \Psalm\Internal\Analyzer\Statements\Expression\Call\Method\MethodCallReturnTypeFetcher::replaceTemplateTypes($self_out_candidate, $template_result, $method_id, count($args), $codebase); $self_out_candidate = TypeExpander::expandUnion($codebase, $self_out_candidate, $fq_class_name, $static_type, $class_storage->parent_class, \true, \false, $static_type instanceof TNamedObject && $codebase->classlike_storage_provider->get($static_type->value)->final, \true); $context->vars_in_scope[$lhs_var_id] = $self_out_candidate; } if (!$context->collect_mutations && !$context->collect_initializations) { \Psalm\Internal\Analyzer\Statements\Expression\Call\Method\MethodCallPurityAnalyzer::analyze($statements_analyzer, $codebase, $stmt, $lhs_var_id, $cased_method_id, $method_id, $method_storage, $class_storage, $context, $config, $result); } $has_packed_arg = \false; foreach ($args as $arg) { $has_packed_arg = $has_packed_arg || $arg->unpack; } if (!$has_packed_arg) { $has_variadic_param = $method_storage->variadic; foreach ($method_storage->params as $param) { $has_variadic_param = $has_variadic_param || $param->is_variadic; } for ($i = count($args), $j = count($method_storage->params); $i < $j; ++$i) { $param = $method_storage->params[$i]; if (!$param->is_optional && !$param->is_variadic && !$in_call_map) { $result->too_few_arguments = \true; $result->too_few_arguments_method_ids[] = $declaring_method_id ?? $method_id; } } if ($has_variadic_param || count($method_storage->params) >= count($args) || $in_call_map) { $result->too_many_arguments = \false; } else { $result->too_many_arguments_method_ids[] = $declaring_method_id ?? $method_id; } } $assertionsResolver = new AssertionsFromInheritanceResolver($codebase); $assertions = $assertionsResolver->resolve($method_storage, $class_storage); if ($assertions) { self::applyAssertionsToContext($stmt_name, ExpressionIdentifier::getExtendedVarId($stmt->var, null, $statements_analyzer), $assertions, $args, $template_result, $context, $statements_analyzer); } if ($method_storage->if_true_assertions) { $possibilities = array_map(static fn(Possibilities $assertion): Possibilities => $assertion->getUntemplatedCopy($template_result, $lhs_var_id, $codebase), $method_storage->if_true_assertions); if ($lhs_var_id === null) { $possibilities = array_filter($possibilities, static fn(Possibilities $assertion): bool => !(is_string($assertion->var_id) && strpos($assertion->var_id, '$this->') === 0)); } $statements_analyzer->node_data->setIfTrueAssertions($stmt, $possibilities); } if ($method_storage->if_false_assertions) { $possibilities = array_map(static fn(Possibilities $assertion): Possibilities => $assertion->getUntemplatedCopy($template_result, $lhs_var_id, $codebase), $method_storage->if_false_assertions); if ($lhs_var_id === null) { $possibilities = array_filter($possibilities, static fn(Possibilities $assertion): bool => !(is_string($assertion->var_id) && strpos($assertion->var_id, '$this->') === 0)); } $statements_analyzer->node_data->setIfFalseAssertions($stmt, $possibilities); } } if ($codebase->methods_to_rename) { $declaring_method_id = $codebase->methods->getDeclaringMethodId($method_id); foreach ($codebase->methods_to_rename as $original_method_id => $new_method_name) { if ($declaring_method_id && strtolower((string) $declaring_method_id) === $original_method_id) { $file_manipulations = [new FileManipulation((int) $stmt_name->getAttribute('startFilePos'), (int) $stmt_name->getAttribute('endFilePos') + 1, $new_method_name)]; FileManipulationBuffer::add($statements_analyzer->getFilePath(), $file_manipulations); } } } if ($config->eventDispatcher->hasAfterMethodCallAnalysisHandlers()) { $file_manipulations = []; $appearing_method_id = $codebase->methods->getAppearingMethodId($method_id); $declaring_method_id = $codebase->methods->getDeclaringMethodId($method_id); if ($appearing_method_id !== null && $declaring_method_id !== null) { $event = new AfterMethodCallAnalysisEvent($stmt, (string) $method_id, (string) $appearing_method_id, (string) $declaring_method_id, $context, $statements_analyzer, $codebase, $file_manipulations, $return_type_candidate); $config->eventDispatcher->dispatchAfterMethodCallAnalysis($event); $file_manipulations = $event->getFileReplacements(); $return_type_candidate = $event->getReturnTypeCandidate(); } if ($file_manipulations) { FileManipulationBuffer::add($statements_analyzer->getFilePath(), $file_manipulations); } } return $return_type_candidate ?? Type::getMixed(); } /** * Check properties accessed with magic getters and setters. * If `@psalm-seal-properties` is set, they must be defined. * If an `@property` annotation is specified, the setter must set something with the correct * type. */ private static function getMagicGetterOrSetterProperty(StatementsAnalyzer $statements_analyzer, PhpParser\Node\Expr\MethodCall $stmt, PhpParser\Node\Identifier $stmt_name, Context $context, string $fq_class_name) : ?Union { $method_name = strtolower($stmt_name->name); if (!in_array($method_name, ['__get', '__set'], \true)) { return null; } $codebase = $statements_analyzer->getCodebase(); $first_arg_value = $stmt->getArgs()[0]->value ?? null; if (!$first_arg_value instanceof PhpParser\Node\Scalar\String_) { return null; } $prop_name = $first_arg_value->value; $property_id = $fq_class_name . '::$' . $prop_name; $class_storage = $codebase->classlike_storage_provider->get($fq_class_name); $codebase->properties->propertyExists($property_id, $method_name === '__get', $statements_analyzer, $context, new CodeLocation($statements_analyzer->getSource(), $stmt)); switch ($method_name) { case '__set': // If `@psalm-seal-properties` is set, the property must be defined with // a `@property` annotation if ($class_storage->hasSealedProperties($codebase->config) && !isset($class_storage->pseudo_property_set_types['$' . $prop_name])) { IssueBuffer::maybeAdd(new UndefinedThisPropertyAssignment('Instance property ' . $property_id . ' is not defined', new CodeLocation($statements_analyzer->getSource(), $stmt), $property_id), $statements_analyzer->getSuppressedIssues()); } // If a `@property` annotation is set, the type of the value passed to the // magic setter must match the annotation. $second_arg_type = isset($stmt->getArgs()[1]) ? $statements_analyzer->node_data->getType($stmt->getArgs()[1]->value) : null; if (isset($class_storage->pseudo_property_set_types['$' . $prop_name]) && $second_arg_type) { $pseudo_set_type = TypeExpander::expandUnion($codebase, $class_storage->pseudo_property_set_types['$' . $prop_name], $fq_class_name, new TNamedObject($fq_class_name), $class_storage->parent_class); $union_comparison_results = new TypeComparisonResult(); $type_match_found = UnionTypeComparator::isContainedBy($codebase, $second_arg_type, $pseudo_set_type, $second_arg_type->ignore_nullable_issues, $second_arg_type->ignore_falsable_issues, $union_comparison_results); if ($union_comparison_results->type_coerced) { if ($union_comparison_results->type_coerced_from_mixed) { IssueBuffer::maybeAdd(new MixedPropertyTypeCoercion($prop_name . ' expects \'' . $pseudo_set_type->getId() . '\', ' . ' parent type `' . $second_arg_type . '` provided', new CodeLocation($statements_analyzer->getSource(), $stmt), $property_id), $statements_analyzer->getSuppressedIssues()); } else { IssueBuffer::maybeAdd(new PropertyTypeCoercion($prop_name . ' expects \'' . $pseudo_set_type->getId() . '\', ' . ' parent type `' . $second_arg_type . '` provided', new CodeLocation($statements_analyzer->getSource(), $stmt), $property_id), $statements_analyzer->getSuppressedIssues()); } } if (!$type_match_found && !$union_comparison_results->type_coerced_from_mixed) { if (UnionTypeComparator::canBeContainedBy($codebase, $second_arg_type, $pseudo_set_type)) { IssueBuffer::maybeAdd(new PossiblyInvalidPropertyAssignmentValue($prop_name . ' with declared type \'' . $pseudo_set_type . '\' cannot be assigned possibly different type \'' . $second_arg_type . '\'', new CodeLocation($statements_analyzer->getSource(), $stmt), $property_id), $statements_analyzer->getSuppressedIssues()); } else { IssueBuffer::maybeAdd(new InvalidPropertyAssignmentValue($prop_name . ' with declared type \'' . $pseudo_set_type . '\' cannot be assigned type \'' . $second_arg_type . '\'', new CodeLocation($statements_analyzer->getSource(), $stmt), $property_id), $statements_analyzer->getSuppressedIssues()); } } } break; case '__get': // If `@psalm-seal-properties` is set, the property must be defined with // a `@property` annotation if ($class_storage->hasSealedProperties($codebase->config) && !isset($class_storage->pseudo_property_get_types['$' . $prop_name])) { IssueBuffer::maybeAdd(new UndefinedThisPropertyFetch('Instance property ' . $property_id . ' is not defined', new CodeLocation($statements_analyzer->getSource(), $stmt), $property_id), $statements_analyzer->getSuppressedIssues()); } if (isset($class_storage->pseudo_property_get_types['$' . $prop_name])) { return $class_storage->pseudo_property_get_types['$' . $prop_name]; } break; } return null; } } methods; $method_id = $codebase_methods->getDeclaringMethodId($method_id); if ($method_id === null) { return; } $storage = $codebase_methods->getStorage($method_id); if ($storage->deprecated) { IssueBuffer::maybeAdd(new DeprecatedMethod('The method ' . $codebase_methods->getCasedMethodId($method_id) . ' has been marked as deprecated', $code_location, (string) $method_id), $suppressed_issues); } if (!$context->collect_initializations && !$context->collect_mutations) { if (!NamespaceAnalyzer::isWithinAny($caller_identifier ?? "", $storage->internal)) { IssueBuffer::maybeAdd(new InternalMethod('The method ' . $codebase_methods->getCasedMethodId($method_id) . ' is internal to ' . InternalClass::listToPhrase($storage->internal) . ' but called from ' . ($caller_identifier ?: 'root namespace'), $code_location, (string) $method_id), $suppressed_issues); } } } } external_mutation_free && $statements_analyzer->node_data->isPureCompatible($stmt->var); if ($context->pure && !$method_storage->mutation_free && !$method_pure_compatible) { IssueBuffer::maybeAdd(new ImpureMethodCall('Cannot call a non-mutation-free method ' . $cased_method_id . ' from a pure context', new CodeLocation($statements_analyzer, $stmt->name)), $statements_analyzer->getSuppressedIssues()); } elseif ($context->mutation_free && !$method_storage->mutation_free && !$method_pure_compatible) { IssueBuffer::maybeAdd(new ImpureMethodCall('Cannot call a possibly-mutating method ' . $cased_method_id . ' from a mutation-free context', new CodeLocation($statements_analyzer, $stmt->name)), $statements_analyzer->getSuppressedIssues()); } elseif ($context->external_mutation_free && !$method_storage->mutation_free && $method_id->fq_class_name !== $context->self && !$method_pure_compatible) { IssueBuffer::maybeAdd(new ImpureMethodCall('Cannot call a possibly-mutating method ' . $cased_method_id . ' from a mutation-free context', new CodeLocation($statements_analyzer, $stmt->name)), $statements_analyzer->getSuppressedIssues()); } elseif (($method_storage->mutation_free || $method_storage->external_mutation_free && ($stmt->var->getAttribute('external_mutation_free', \false) || $stmt->var->getAttribute('pure', \false))) && !$context->inside_unset) { if ($method_storage->mutation_free && (!$method_storage->mutation_free_inferred || $method_storage->final || $method_storage->visibility === ClassLikeAnalyzer::VISIBILITY_PRIVATE) && ($method_storage->immutable || $config->remember_property_assignments_after_call)) { if ($context->inside_conditional && !$method_storage->assertions && !$method_storage->if_true_assertions) { $stmt->setAttribute('memoizable', \true); if ($method_storage->immutable) { $stmt->setAttribute('pure', \true); } } $result->can_memoize = \true; } if ($codebase->find_unused_variables && !$context->inside_conditional && !$context->inside_general_use && !$context->inside_throw) { if (!$context->inside_assignment && !$context->inside_call && !$context->inside_return && !$method_storage->assertions && !$method_storage->if_true_assertions && !$method_storage->if_false_assertions && !$method_storage->throws) { IssueBuffer::maybeAdd(new UnusedMethodCall('The call to ' . $cased_method_id . ' is not used', new CodeLocation($statements_analyzer, $stmt->name), (string) $method_id), $statements_analyzer->getSuppressedIssues()); } elseif (!$method_storage->mutation_free_inferred) { $stmt->setAttribute('pure', \true); } } } if ($statements_analyzer->getSource() instanceof FunctionLikeAnalyzer && $statements_analyzer->getSource()->track_mutations && !$method_storage->mutation_free && !$method_pure_compatible) { $statements_analyzer->getSource()->inferred_has_mutation = \true; $statements_analyzer->getSource()->inferred_impure = \true; } if (!$config->remember_property_assignments_after_call && !$method_storage->mutation_free && !$method_pure_compatible) { $context->removeMutableObjectVars(); } elseif ($method_storage->this_property_mutations) { if (!$method_pure_compatible) { $context->removeMutableObjectVars(\true); } foreach ($method_storage->this_property_mutations as $name => $_) { $mutation_var_id = $lhs_var_id . '->' . $name; $this_property_didnt_exist = $lhs_var_id === '$this' && isset($context->vars_in_scope[$mutation_var_id]) && !isset($class_storage->declaring_property_ids[$name]); if ($this_property_didnt_exist) { unset($context->vars_in_scope[$mutation_var_id]); } else { $new_type = AssignmentAnalyzer::getExpandedPropertyType($codebase, $class_storage->name, $name, $class_storage) ?? Type::getMixed(); $context->vars_in_scope[$mutation_var_id] = $new_type; $context->possibly_assigned_var_ids[$mutation_var_id] = \true; } } } } } */ public array $invalid_method_call_types = []; /** * @var array */ public array $existent_method_ids = []; /** * @var array */ public array $non_existent_class_method_ids = []; /** * @var array */ public array $non_existent_interface_method_ids = []; /** * @var array */ public array $non_existent_magic_method_ids = []; public bool $check_visibility = \true; public bool $too_many_arguments = \true; /** * @var list */ public array $too_many_arguments_method_ids = []; public bool $too_few_arguments = \false; /** * @var list */ public array $too_few_arguments_method_ids = []; public bool $can_memoize = \false; } getCodebase(); $codebase_methods = $codebase->methods; $codebase_classlikes = $codebase->classlikes; $fq_classlike_name = $method_id->fq_class_name; $method_name = $method_id->method_name; $with_pseudo = \true; if ($codebase_methods->visibility_provider->has($fq_classlike_name)) { $method_visible = $codebase_methods->visibility_provider->isMethodVisible($source, $fq_classlike_name, $method_name, $context, $code_location); if ($method_visible === \false) { if (IssueBuffer::accepts(new InaccessibleMethod('Cannot access method ' . $codebase_methods->getCasedMethodId($method_id) . ' from context ' . $context->self, $code_location), $suppressed_issues)) { return \false; } } elseif ($method_visible === \true) { return \false; } } $declaring_method_id = $codebase_methods->getDeclaringMethodId($method_id, $with_pseudo); if (!$declaring_method_id) { if ($method_name === '__construct' || $method_id->fq_class_name === 'Closure' && ($method_id->method_name === 'fromcallable' || $method_id->method_name === '__invoke')) { return null; } if (InternalCallMapHandler::inCallMap((string) $method_id)) { return null; } throw new UnexpectedValueException('$declaring_method_id not expected to be null here'); } $appearing_method_id = $codebase_methods->getAppearingMethodId($method_id); $appearing_method_class = null; $appearing_class_storage = null; $appearing_method_name = null; if ($appearing_method_id) { $appearing_method_class = $appearing_method_id->fq_class_name; $appearing_method_name = $appearing_method_id->method_name; // if the calling class is the same, we know the method exists, so it must be visible if ($appearing_method_class === $context->self) { return null; } $appearing_class_storage = $codebase->classlike_storage_provider->get($appearing_method_class); } $declaring_method_class = $declaring_method_id->fq_class_name; if ($source->getSource() instanceof TraitAnalyzer && strtolower($declaring_method_class) === strtolower((string) $source->getFQCLN())) { return null; } $storage = $codebase->methods->getStorage($declaring_method_id, $with_pseudo); $visibility = $storage->visibility; if ($appearing_method_name && isset($appearing_class_storage->trait_visibility_map[$appearing_method_name])) { $visibility = $appearing_class_storage->trait_visibility_map[$appearing_method_name]; } // Get oldest ancestor declaring $method_id $overridden_method_ids = $codebase_methods->getOverriddenMethodIds($method_id); // Remove traits and interfaces while (($oldest_declaring_method_id = end($overridden_method_ids)) && !$codebase_classlikes->hasFullyQualifiedClassName($oldest_declaring_method_id->fq_class_name)) { array_pop($overridden_method_ids); } if (empty($overridden_method_ids)) { // We prefer appearing method id over declaring method id because declaring method id could be a trait $oldest_ancestor_declaring_method_id = $appearing_method_id; } else { // Oldest ancestor is at end of array $oldest_ancestor_declaring_method_id = array_pop($overridden_method_ids); } $oldest_ancestor_declaring_method_class = $oldest_ancestor_declaring_method_id->fq_class_name ?? null; switch ($visibility) { case ClassLikeAnalyzer::VISIBILITY_PUBLIC: return null; case ClassLikeAnalyzer::VISIBILITY_PRIVATE: if (!$context->self || $appearing_method_class !== $context->self) { if (IssueBuffer::accepts(new InaccessibleMethod('Cannot access private method ' . $codebase_methods->getCasedMethodId($method_id) . ' from context ' . $context->self, $code_location), $suppressed_issues)) { return \false; } } return null; case ClassLikeAnalyzer::VISIBILITY_PROTECTED: if (!$context->self) { if (IssueBuffer::accepts(new InaccessibleMethod('Cannot access protected method ' . $method_id, $code_location), $suppressed_issues)) { return \false; } return null; } if ($oldest_ancestor_declaring_method_class !== null && $codebase_classlikes->classExtends($oldest_ancestor_declaring_method_class, $context->self)) { return null; } if ($oldest_ancestor_declaring_method_class !== null && !$codebase_classlikes->classExtends($context->self, $oldest_ancestor_declaring_method_class) && !$codebase_classlikes->classExtends($declaring_method_class, $context->self)) { if (IssueBuffer::accepts(new InaccessibleMethod('Cannot access protected method ' . $codebase_methods->getCasedMethodId($method_id) . ' from context ' . $context->self, $code_location), $suppressed_issues)) { return \false; } } } return null; } } fq_class_name; $method_name_lc = $method_id->method_name; if ($stmt->isFirstClassCallable()) { if (isset($class_storage->pseudo_methods[$method_name_lc])) { $result->has_valid_method_call_type = \true; $result->existent_method_ids[$method_id->__toString()] = \true; $result->return_type = self::createFirstClassCallableReturnType($class_storage->pseudo_methods[$method_name_lc]); } else { $result->non_existent_magic_method_ids[] = $method_id->__toString(); $result->return_type = self::createFirstClassCallableReturnType(); } return null; } if ($codebase->methods->return_type_provider->has($fq_class_name)) { $return_type_candidate = $codebase->methods->return_type_provider->getReturnType($statements_analyzer, $method_id->fq_class_name, $method_id->method_name, $stmt, $context, new CodeLocation($statements_analyzer->getSource(), $stmt->name)); if ($return_type_candidate) { if ($all_intersection_return_type) { $return_type_candidate = Type::intersectUnionTypes($all_intersection_return_type, $return_type_candidate, $codebase) ?? Type::getMixed(); } $result->return_type = Type::combineUnionTypes($return_type_candidate, $result->return_type, $codebase); CallAnalyzer::checkMethodArgs($method_id, $stmt->getArgs(), new TemplateResult([], []), $context, new CodeLocation($statements_analyzer->getSource(), $stmt), $statements_analyzer); return null; } } $found_method_and_class_storage = self::findPseudoMethodAndClassStorages($codebase, $class_storage, $method_name_lc); if ($found_method_and_class_storage) { $result->has_valid_method_call_type = \true; $result->existent_method_ids[$method_id->__toString()] = \true; [$pseudo_method_storage, $defining_class_storage] = $found_method_and_class_storage; $found_generic_params = ClassTemplateParamCollector::collect($codebase, $defining_class_storage, $class_storage, $method_name_lc, $lhs_type_part, !$statements_analyzer->isStatic() && $method_id->fq_class_name === $context->self); ArgumentsAnalyzer::analyze($statements_analyzer, $stmt->getArgs(), $pseudo_method_storage->params, (string) $method_id, \true, $context, $found_generic_params ? new TemplateResult([], $found_generic_params) : null); ArgumentsAnalyzer::checkArgumentsMatch($statements_analyzer, $stmt->getArgs(), null, $pseudo_method_storage->params, $pseudo_method_storage, null, new TemplateResult([], $found_generic_params ?: []), new CodeLocation($statements_analyzer, $stmt), $context); if ($pseudo_method_storage->return_type) { $return_type_candidate = $pseudo_method_storage->return_type; if ($found_generic_params) { $return_type_candidate = TemplateInferredTypeReplacer::replace($return_type_candidate, new TemplateResult([], $found_generic_params), $codebase); } $return_type_candidate = TypeExpander::expandUnion($codebase, $return_type_candidate, $defining_class_storage->name, $lhs_type_part instanceof Atomic\TNamedObject ? $lhs_type_part : $fq_class_name, $defining_class_storage->parent_class); if ($all_intersection_return_type) { $return_type_candidate = Type::intersectUnionTypes($all_intersection_return_type, $return_type_candidate, $codebase) ?? Type::getMixed(); } $result->return_type = Type::combineUnionTypes($return_type_candidate, $result->return_type, $codebase); return null; } } elseif ($all_intersection_return_type === null) { ArgumentsAnalyzer::analyze($statements_analyzer, $stmt->getArgs(), null, null, \true, $context); if ($class_storage->hasSealedMethods($config)) { $result->non_existent_magic_method_ids[] = $method_id->__toString(); return null; } } $result->has_valid_method_call_type = \true; $result->existent_method_ids[$method_id->__toString()] = \true; $array_values = array_map(static fn(PhpParser\Node\Arg $arg): PhpParser\Node\Expr\ArrayItem => new VirtualArrayItem($arg->value, null, \false, $arg->getAttributes()), $stmt->getArgs()); $statements_analyzer->node_data = clone $statements_analyzer->node_data; return new \Psalm\Internal\Analyzer\Statements\Expression\Call\Method\AtomicCallContext(new MethodIdentifier($fq_class_name, '__call'), [new VirtualArg(new VirtualString($method_name_lc), \false, \false, $stmt->getAttributes()), new VirtualArg(new VirtualArray($array_values, $stmt->getAttributes()), \false, \false, $stmt->getAttributes())]); } /** * @param array $all_intersection_existent_method_ids */ public static function handleMissingOrMagicMethod(StatementsAnalyzer $statements_analyzer, Codebase $codebase, PhpParser\Node\Expr\MethodCall $stmt, MethodIdentifier $method_id, bool $is_interface, Context $context, Config $config, ?Union $all_intersection_return_type, array $all_intersection_existent_method_ids, ?string $intersection_method_id, string $cased_method_id, \Psalm\Internal\Analyzer\Statements\Expression\Call\Method\AtomicMethodCallAnalysisResult $result, ?Atomic $lhs_type_part) : void { $fq_class_name = $method_id->fq_class_name; $method_name_lc = $method_id->method_name; $class_storage = $codebase->classlike_storage_provider->get($fq_class_name); $found_method_and_class_storage = self::findPseudoMethodAndClassStorages($codebase, $class_storage, $method_name_lc); if (($is_interface || $config->use_phpdoc_method_without_magic_or_parent) && $found_method_and_class_storage) { $result->has_valid_method_call_type = \true; $result->existent_method_ids[$method_id->__toString()] = \true; [$pseudo_method_storage, $defining_class_storage] = $found_method_and_class_storage; if ($stmt->isFirstClassCallable()) { $result->return_type = self::createFirstClassCallableReturnType($pseudo_method_storage); return; } $found_generic_params = ClassTemplateParamCollector::collect($codebase, $defining_class_storage, $class_storage, $method_name_lc, $lhs_type_part, !$statements_analyzer->isStatic() && $method_id->fq_class_name === $context->self); if (ArgumentsAnalyzer::analyze($statements_analyzer, $stmt->getArgs(), $pseudo_method_storage->params, (string) $method_id, \true, $context, $found_generic_params ? new TemplateResult([], $found_generic_params) : null) === \false) { return; } if (ArgumentsAnalyzer::checkArgumentsMatch($statements_analyzer, $stmt->getArgs(), null, $pseudo_method_storage->params, $pseudo_method_storage, null, new TemplateResult([], $found_generic_params ?: []), new CodeLocation($statements_analyzer, $stmt->name), $context) === \false) { return; } if ($pseudo_method_storage->return_type) { $return_type_candidate = $pseudo_method_storage->return_type; if ($found_generic_params) { $return_type_candidate = TemplateInferredTypeReplacer::replace($return_type_candidate, new TemplateResult([], $found_generic_params), $codebase); } if ($all_intersection_return_type) { $return_type_candidate = Type::intersectUnionTypes($all_intersection_return_type, $return_type_candidate, $codebase) ?? Type::getMixed(); } $return_type_candidate = TypeExpander::expandUnion($codebase, $return_type_candidate, $defining_class_storage->name, $lhs_type_part instanceof Atomic\TNamedObject ? $lhs_type_part : $fq_class_name, $defining_class_storage->parent_class, \true, \false, $class_storage->final); $result->return_type = Type::combineUnionTypes($return_type_candidate, $result->return_type); return; } $result->return_type = Type::getMixed(); return; } if ($stmt->isFirstClassCallable()) { $result->non_existent_class_method_ids[] = $method_id->__toString(); $result->return_type = self::createFirstClassCallableReturnType(); return; } if (ArgumentsAnalyzer::analyze($statements_analyzer, $stmt->getArgs(), null, null, \true, $context) === \false) { return; } if ($all_intersection_return_type && $all_intersection_existent_method_ids) { $result->existent_method_ids = array_merge($result->existent_method_ids, $all_intersection_existent_method_ids); $result->return_type = Type::combineUnionTypes($all_intersection_return_type, $result->return_type); return; } if (!$is_interface && !$config->use_phpdoc_method_without_magic_or_parent || !isset($class_storage->pseudo_methods[$method_name_lc])) { if ($is_interface) { $result->non_existent_interface_method_ids[] = $intersection_method_id ?: $cased_method_id; } else { $result->non_existent_class_method_ids[] = $intersection_method_id ?: $cased_method_id; } } } private static function createFirstClassCallableReturnType(?MethodStorage $method_storage = null) : Union { if ($method_storage) { return new Union([new TClosure('Closure', $method_storage->params, $method_storage->return_type, $method_storage->pure)]); } return Type::getClosure(); } /** * Try to find matching pseudo method over ancestors (including interfaces). * * Returns the pseudo method if exists, with its defining class storage. * If the method is not declared, null is returned. * * @param ClassLikeStorage $static_class_storage The called class * @param lowercase-string $method_name_lc * @return array{MethodStorage, ClassLikeStorage} */ private static function findPseudoMethodAndClassStorages(Codebase $codebase, ClassLikeStorage $static_class_storage, string $method_name_lc) : ?array { if (isset($static_class_storage->declaring_pseudo_method_ids[$method_name_lc])) { $method_id = $static_class_storage->declaring_pseudo_method_ids[$method_name_lc]; $class_storage = $codebase->classlikes->getStorageFor($method_id->fq_class_name); if ($class_storage && isset($class_storage->pseudo_methods[$method_name_lc])) { return [$class_storage->pseudo_methods[$method_name_lc], $class_storage]; } } if ($pseudo_method_storage = $static_class_storage->pseudo_methods[$method_name_lc] ?? null) { return [$pseudo_method_storage, $static_class_storage]; } $ancestors = $static_class_storage->class_implements; foreach ($ancestors as $fq_class_name => $_) { $class_storage = $codebase->classlikes->getStorageFor($fq_class_name); if ($class_storage && isset($class_storage->pseudo_methods[$method_name_lc])) { return [$class_storage->pseudo_methods[$method_name_lc], $class_storage]; } } return null; } } $args */ public static function checkArgumentsMatch(StatementsAnalyzer $statements_analyzer, Context $context, array $args, string $method_id, bool $check_functions) : void { $closure_index = $method_id === 'array_map' ? 0 : 1; $array_arg_types = []; foreach ($args as $i => $arg) { if ($i === 0 && $method_id === 'array_map') { continue; } if ($i === 1 && $method_id === 'array_filter') { break; } /** * @var TKeyedArray|TArray|null */ $array_arg_type = ($arg_value_type = $statements_analyzer->node_data->getType($arg->value)) && $arg_value_type->hasArray() ? $arg_value_type->getArray() : null; if ($array_arg_type instanceof TKeyedArray) { $array_arg_type = $array_arg_type->getGenericArrayType(); } $array_arg_types[] = $array_arg_type; } $closure_arg = $args[$closure_index] ?? null; $closure_arg_type = null; if ($closure_arg) { $closure_arg_type = $statements_analyzer->node_data->getType($closure_arg->value); } if ($closure_arg && $closure_arg_type) { $min_closure_param_count = $max_closure_param_count = count($array_arg_types); if ($method_id === 'array_filter') { $max_closure_param_count = count($args) > 2 ? 2 : 1; } $new = []; foreach ($closure_arg_type->getAtomicTypes() as $closure_type) { self::checkClosureType($statements_analyzer, $context, $method_id, $closure_type, $closure_arg, $min_closure_param_count, $max_closure_param_count, $array_arg_types, $check_functions); $new[] = $closure_type; } $statements_analyzer->node_data->setType($closure_arg->value, $closure_arg_type->getBuilder()->setTypes($new)->freeze()); } } /** * @param list $args * @return false|null */ public static function handleAddition(StatementsAnalyzer $statements_analyzer, array $args, Context $context, string $method_id) : ?bool { $array_arg = $args[0]->value; $nb_args = count($args); $unpacked_args = array_filter($args, static fn(PhpParser\Node\Arg $arg): bool => $arg->unpack); if ($method_id === 'array_push' && !$unpacked_args) { for ($i = 1; $i < $nb_args; $i++) { $was_inside_assignment = $context->inside_assignment; $context->inside_assignment = \true; if (ExpressionAnalyzer::analyze($statements_analyzer, $args[$i]->value, $context) === \false) { $context->inside_assignment = $was_inside_assignment; return \false; } $context->inside_assignment = $was_inside_assignment; $old_node_data = $statements_analyzer->node_data; $statements_analyzer->node_data = clone $statements_analyzer->node_data; ArrayAssignmentAnalyzer::analyze($statements_analyzer, new VirtualArrayDimFetch($args[0]->value, null, $args[$i]->value->getAttributes()), $context, $args[$i]->value, $statements_analyzer->node_data->getType($args[$i]->value) ?? Type::getMixed()); $statements_analyzer->node_data = $old_node_data; } return null; } $context->inside_call = \true; if (ExpressionAnalyzer::analyze($statements_analyzer, $array_arg, $context) === \false) { return \false; } for ($i = 1; $i < $nb_args; $i++) { if (ExpressionAnalyzer::analyze($statements_analyzer, $args[$i]->value, $context) === \false) { return \false; } } if (($array_arg_type = $statements_analyzer->node_data->getType($array_arg)) && $array_arg_type->hasArray()) { $array_type = $array_arg_type->getArray(); $objectlike_list = null; if ($array_type instanceof TKeyedArray) { if ($array_type->is_list) { $objectlike_list = $array_type; } } $by_ref_type = new Union([$array_type]); foreach ($args as $argument_offset => $arg) { if ($argument_offset === 0) { continue; } if (ExpressionAnalyzer::analyze($statements_analyzer, $arg->value, $context) === \false) { return \false; } if ($method_id === 'array_unshift' && $nb_args === 2 && !$unpacked_args) { $new_offset_type = Type::getInt(\false, 0); } else { $new_offset_type = Type::getInt(); } if (!($arg_value_type = $statements_analyzer->node_data->getType($arg->value)) || $arg_value_type->hasMixed()) { $by_ref_type = Type::combineUnionTypes($by_ref_type, new Union([new TArray([$new_offset_type, Type::getMixed()])])); } elseif ($arg->unpack) { $arg_value_type = $arg_value_type->getBuilder(); foreach ($arg_value_type->getAtomicTypes() as $arg_value_atomic_type) { if ($arg_value_atomic_type instanceof TKeyedArray) { $was_list = $arg_value_atomic_type->is_list; $arg_value_atomic_type = $arg_value_atomic_type->getGenericArrayType(); if ($was_list) { if ($arg_value_atomic_type instanceof TNonEmptyArray) { $arg_value_atomic_type = Type::getNonEmptyListAtomic($arg_value_atomic_type->type_params[1]); } else { $arg_value_atomic_type = Type::getListAtomic($arg_value_atomic_type->type_params[1]); } } $arg_value_type->addType($arg_value_atomic_type); } } $arg_value_type = $arg_value_type->freeze(); $by_ref_type = Type::combineUnionTypes($by_ref_type, $arg_value_type); } else { if ($objectlike_list) { $properties = $objectlike_list->properties; array_unshift($properties, $arg_value_type); $by_ref_type = new Union([$objectlike_list->setProperties($properties)]); } elseif ($array_type instanceof TArray && $array_type->isEmptyArray()) { $by_ref_type = new Union([new TKeyedArray([$arg_value_type], null, null, \true)]); } else { $by_ref_type = Type::combineUnionTypes($by_ref_type, new Union([new TNonEmptyArray([$new_offset_type, $arg_value_type])]), null, \true); } } } AssignmentAnalyzer::assignByRefParam($statements_analyzer, $array_arg, $by_ref_type, $by_ref_type, $context, \false); } $context->inside_call = \false; return null; } /** * @param list $args * @return false|null */ public static function handleSplice(StatementsAnalyzer $statements_analyzer, array $args, Context $context) : ?bool { $context->inside_call = \true; $array_arg = $args[0]->value; if (ExpressionAnalyzer::analyze($statements_analyzer, $array_arg, $context) === \false) { return \false; } $array_type = null; $array_size = null; if (($array_arg_type = $statements_analyzer->node_data->getType($array_arg)) && $array_arg_type->hasArray()) { /** * @var TArray|TKeyedArray */ $array_type = $array_arg_type->getArray(); if ($generic_array_type = ArrayType::infer($array_type)) { $array_size = $generic_array_type->count; } if ($array_type instanceof TKeyedArray) { if ($array_type->is_list && isset($args[3])) { $array_type = Type::getNonEmptyListAtomic($array_type->getGenericValueType()); } else { $array_type = $array_type->getGenericArrayType(); } } if ($array_type instanceof TArray && $array_type->type_params[0]->hasInt() && !$array_type->type_params[0]->hasString()) { if ($array_type instanceof TNonEmptyArray && isset($args[3])) { $array_type = Type::getNonEmptyListAtomic($array_type->type_params[1]); } else { $array_type = Type::getListAtomic($array_type->type_params[1]); } } } $offset_arg = $args[1]->value; if (ExpressionAnalyzer::analyze($statements_analyzer, $offset_arg, $context) === \false) { return \false; } $offset_arg_is_zero = \false; if (($offset_arg_type = $statements_analyzer->node_data->getType($offset_arg)) && $offset_arg_type->hasLiteralValue() && $offset_arg_type->isSingleLiteral()) { $offset_literal_value = $offset_arg_type->getSingleLiteral()->value; $offset_arg_is_zero = is_numeric($offset_literal_value) && (int) $offset_literal_value === 0; } if (!isset($args[2])) { if ($offset_arg_is_zero) { $array_type = Type::getEmptyArray(); AssignmentAnalyzer::assignByRefParam($statements_analyzer, $array_arg, $array_type, $array_type, $context, \false); } elseif ($array_type) { AssignmentAnalyzer::assignByRefParam($statements_analyzer, $array_arg, new Union([$array_type]), new Union([$array_type]), $context, \false); } else { $default_array_type = Type::getArray(); AssignmentAnalyzer::assignByRefParam($statements_analyzer, $array_arg, $default_array_type, $default_array_type, $context, \false); } return null; } $length_arg = $args[2]->value; if (ExpressionAnalyzer::analyze($statements_analyzer, $length_arg, $context) === \false) { return \false; } $cover_whole_arr = \false; if ($offset_arg_is_zero && is_numeric($array_size)) { if (($length_arg_type = $statements_analyzer->node_data->getType($length_arg)) && $length_arg_type->hasLiteralValue()) { $length_min = null; if ($length_arg_type->isSingleLiteral()) { $length_literal = $length_arg_type->getSingleLiteral(); if ($length_literal->isNumericType()) { $length_min = (int) $length_literal->value; } } else { $literals = array_merge($length_arg_type->getLiteralStrings(), $length_arg_type->getLiteralInts(), $length_arg_type->getLiteralFloats()); foreach ($literals as $literal) { if ($literal->isNumericType() && ($literal_val = (int) $literal->value) && (isset($length_min) && $length_min > $literal_val || !isset($length_min))) { $length_min = $literal_val; } } } $cover_whole_arr = isset($length_min) && $length_min >= $array_size; } elseif ($length_arg_type && $length_arg_type->isNull()) { $cover_whole_arr = \true; } } if (!isset($args[3])) { if ($cover_whole_arr) { $array_type = Type::getEmptyArray(); AssignmentAnalyzer::assignByRefParam($statements_analyzer, $array_arg, $array_type, $array_type, $context, \false); } elseif ($array_type) { AssignmentAnalyzer::assignByRefParam($statements_analyzer, $array_arg, new Union([$array_type]), new Union([$array_type]), $context, \false); } else { $default_array_type = Type::getArray(); AssignmentAnalyzer::assignByRefParam($statements_analyzer, $array_arg, $default_array_type, $default_array_type, $context, \false); } return null; } $replacement_arg = $args[3]->value; if (ExpressionAnalyzer::analyze($statements_analyzer, $replacement_arg, $context) === \false) { return \false; } $context->inside_call = \false; $replacement_arg_type = $statements_analyzer->node_data->getType($replacement_arg); if ($replacement_arg_type && !$replacement_arg_type->hasArray() && $replacement_arg_type->hasString() && $replacement_arg_type->isSingle()) { $replacement_arg_type = new Union([new TArray([Type::getInt(), $replacement_arg_type])]); $statements_analyzer->node_data->setType($replacement_arg, $replacement_arg_type); } if ($array_type && $replacement_arg_type && $replacement_arg_type->hasArray()) { /** * @var TArray|TKeyedArray */ $replacement_array_type = $replacement_arg_type->getArray(); if (($replacement_array_type_generic = ArrayType::infer($replacement_array_type)) && $replacement_array_type_generic->count === 0 && $cover_whole_arr) { $empty_array_type = Type::getEmptyArray(); AssignmentAnalyzer::assignByRefParam($statements_analyzer, $array_arg, $empty_array_type, $empty_array_type, $context, \false); return null; } if ($replacement_array_type instanceof TKeyedArray) { $was_list = $replacement_array_type->is_list; $replacement_array_type = $replacement_array_type->getGenericArrayType(); if ($was_list) { if ($replacement_array_type instanceof TNonEmptyArray) { $replacement_array_type = Type::getNonEmptyListAtomic($replacement_array_type->type_params[1]); } else { $replacement_array_type = Type::getListAtomic($replacement_array_type->type_params[1]); } } } $by_ref_type = TypeCombiner::combine([$array_type, $replacement_array_type]); AssignmentAnalyzer::assignByRefParam($statements_analyzer, $array_arg, $by_ref_type, $by_ref_type, $context, \false); return null; } if ($array_type) { AssignmentAnalyzer::assignByRefParam($statements_analyzer, $array_arg, new Union([$array_type]), new Union([$array_type]), $context, \false); } else { $default_array_type = Type::getArray(); AssignmentAnalyzer::assignByRefParam($statements_analyzer, $array_arg, $default_array_type, $default_array_type, $context, \false); } return null; } public static function handleByRefArrayAdjustment(StatementsAnalyzer $statements_analyzer, PhpParser\Node\Arg $arg, Context $context, bool $is_array_shift) : void { $var_id = ExpressionIdentifier::getVarId($arg->value, $statements_analyzer->getFQCLN(), $statements_analyzer); if ($var_id) { $context->removeVarFromConflictingClauses($var_id, null, $statements_analyzer); if (isset($context->vars_in_scope[$var_id])) { $array_atomic_types = []; foreach ($context->vars_in_scope[$var_id]->getAtomicTypes() as $array_atomic_type) { if ($array_atomic_type instanceof TList) { $array_atomic_type = $array_atomic_type->getKeyedArray(); } if ($array_atomic_type instanceof TKeyedArray) { if ($is_array_shift && $array_atomic_type->is_list && !$context->inside_loop) { $array_properties = $array_atomic_type->properties; array_shift($array_properties); if (!$array_properties) { $array_atomic_types[] = $array_atomic_type->fallback_params ? Type::getListAtomic($array_atomic_type->fallback_params[1]) : Type::getEmptyArrayAtomic(); } else { $array_atomic_types[] = $array_atomic_type->setProperties($array_properties); } continue; } elseif (!$is_array_shift && $array_atomic_type->is_list && !$array_atomic_type->fallback_params && !$context->inside_loop) { $array_properties = $array_atomic_type->properties; array_pop($array_properties); if (!$array_properties) { $array_atomic_types[] = Type::getEmptyArrayAtomic(); } else { $array_atomic_types[] = $array_atomic_type->setProperties($array_properties); } continue; } $array_atomic_type = $array_atomic_type->is_list ? Type::getListAtomic($array_atomic_type->getGenericValueType()) : $array_atomic_type->getGenericArrayType(); } if ($array_atomic_type instanceof TNonEmptyArray) { if (!$context->inside_loop && $array_atomic_type->count !== null) { if ($array_atomic_type->count === 1) { $array_atomic_type = new TArray([Type::getNever(), Type::getNever()]); } else { $array_atomic_type = $array_atomic_type->setCount($array_atomic_type->count - 1); } } else { $array_atomic_type = new TArray($array_atomic_type->type_params); } $array_atomic_types[] = $array_atomic_type; } elseif ($array_atomic_type instanceof TKeyedArray && $array_atomic_type->is_list) { if (!$context->inside_loop && ($prop_count = $array_atomic_type->getMaxCount()) && $prop_count === $array_atomic_type->getMinCount()) { if ($prop_count === 1) { $array_atomic_type = new TArray([Type::getNever(), Type::getNever()]); } else { $properties = $array_atomic_type->properties; unset($properties[$prop_count - 1]); assert($properties !== []); $array_atomic_type = $array_atomic_type->setProperties($properties); } } else { $array_atomic_type = Type::getListAtomic($array_atomic_type->getGenericValueType()); } $array_atomic_types[] = $array_atomic_type; } else { $array_atomic_types[] = $array_atomic_type; } } if (!$array_atomic_types) { throw new AssertionError("We must have some types here!"); } $array_type = new Union($array_atomic_types); $context->removeDescendents($var_id, $array_type); $context->vars_in_scope[$var_id] = $array_type; } } } /** * @param (TArray|null)[] $array_arg_types */ private static function checkClosureType(StatementsAnalyzer $statements_analyzer, Context $context, string $method_id, Atomic &$closure_type, PhpParser\Node\Arg $closure_arg, int $min_closure_param_count, int $max_closure_param_count, array $array_arg_types, bool $check_functions) : void { $codebase = $statements_analyzer->getCodebase(); if (!$closure_type instanceof TClosure) { if ($method_id === 'array_map') { return; } if (!$closure_arg->value instanceof PhpParser\Node\Scalar\String_ && !$closure_arg->value instanceof PhpParser\Node\Expr\Array_ && !$closure_arg->value instanceof PhpParser\Node\Expr\BinaryOp\Concat) { return; } $function_ids = CallAnalyzer::getFunctionIdsFromCallableArg($statements_analyzer, $closure_arg->value); $closure_types = []; foreach ($function_ids as $function_id) { $function_id = strtolower($function_id); if (strpos($function_id, '::') !== \false) { if ($function_id[0] === '$') { $function_id = substr($function_id, 1); } $function_id_parts = explode('&', $function_id); foreach ($function_id_parts as $function_id_part) { [$callable_fq_class_name, $method_name] = explode('::', $function_id_part); switch ($callable_fq_class_name) { case 'self': case 'static': case 'parent': $container_class = $statements_analyzer->getFQCLN(); if ($callable_fq_class_name === 'parent') { $container_class = $statements_analyzer->getParentFQCLN(); } if (!$container_class) { continue 2; } $callable_fq_class_name = $container_class; } if (!$codebase->classOrInterfaceExists($callable_fq_class_name)) { return; } $function_id_part = new MethodIdentifier($callable_fq_class_name, strtolower($method_name)); try { $method_storage = $codebase->methods->getStorage($function_id_part); } catch (UnexpectedValueException $e) { // the method may not exist, but we're suppressing that issue continue; } $closure_types[] = new TClosure('Closure', $method_storage->params, $method_storage->return_type ?: Type::getMixed()); } } else { if (!$check_functions) { continue; } if (!$codebase->functions->functionExists($statements_analyzer, $function_id)) { continue; } $function_storage = $codebase->functions->getStorage($statements_analyzer, $function_id); if (InternalCallMapHandler::inCallMap($function_id)) { $callmap_callables = InternalCallMapHandler::getCallablesFromCallMap($function_id); if ($callmap_callables === null) { throw new UnexpectedValueException('This should not happen'); } $passing_callmap_callables = []; foreach ($callmap_callables as $callmap_callable) { $required_param_count = 0; assert($callmap_callable->params !== null); foreach ($callmap_callable->params as $i => $param) { if (!$param->is_optional && !$param->is_variadic) { $required_param_count = $i + 1; } } if ($required_param_count <= $max_closure_param_count) { $passing_callmap_callables[] = $callmap_callable; } } if ($passing_callmap_callables) { foreach ($passing_callmap_callables as $passing_callmap_callable) { $closure_types[] = $passing_callmap_callable; } } else { $closure_types[] = $callmap_callables[0]; } } else { $closure_types[] = new TClosure('Closure', $function_storage->params, $function_storage->return_type ?: Type::getMixed()); } } } } else { $closure_types = [&$closure_type]; } foreach ($closure_types as &$closure_type) { if ($closure_type->params === null) { continue; } self::checkClosureTypeArgs($statements_analyzer, $context, $method_id, $closure_type, $closure_arg, $min_closure_param_count, $max_closure_param_count, $array_arg_types); } unset($closure_type); } /** * @param TClosure|TCallable $closure_type * @param (TArray|null)[] $array_arg_types */ private static function checkClosureTypeArgs(StatementsAnalyzer $statements_analyzer, Context $context, string $method_id, Atomic &$closure_type, PhpParser\Node\Arg $closure_arg, int $min_closure_param_count, int $max_closure_param_count, array $array_arg_types) : void { $codebase = $statements_analyzer->getCodebase(); $closure_params = $closure_type->params; if ($closure_params === null) { throw new UnexpectedValueException('Closure params should not be null here'); } $required_param_count = 0; foreach ($closure_params as $i => $param) { if (!$param->is_optional && !$param->is_variadic) { $required_param_count = $i + 1; } } if (count($closure_params) < $min_closure_param_count) { $argument_text = $min_closure_param_count === 1 ? 'one argument' : $min_closure_param_count . ' arguments'; IssueBuffer::maybeAdd(new TooManyArguments('The callable passed to ' . $method_id . ' will be called with ' . $argument_text . ', expecting ' . $required_param_count, new CodeLocation($statements_analyzer->getSource(), $closure_arg), $method_id), $statements_analyzer->getSuppressedIssues()); return; } if ($required_param_count > $max_closure_param_count) { $argument_text = $max_closure_param_count === 1 ? 'one argument' : $max_closure_param_count . ' arguments'; IssueBuffer::maybeAdd(new TooFewArguments('The callable passed to ' . $method_id . ' will be called with ' . $argument_text . ', expecting ' . $required_param_count, new CodeLocation($statements_analyzer->getSource(), $closure_arg), $method_id), $statements_analyzer->getSuppressedIssues()); return; } // abandon attempt to validate closure params if we have an extra arg for ARRAY_FILTER if ($method_id === 'array_filter' && $max_closure_param_count > 1) { return; } foreach ($closure_params as $i => $closure_param) { if (!isset($array_arg_types[$i])) { continue; } $array_arg_type = $array_arg_types[$i]; $input_type = $array_arg_type->type_params[1]; if ($input_type->hasMixed()) { continue; } $closure_param_type = $closure_param->type; if (!$closure_param_type) { continue; } if ($method_id === 'array_map' && $i === 0 && $closure_type->return_type && $closure_param_type->hasTemplate()) { $template_result = new TemplateResult([], []); foreach ($closure_param_type->getTemplateTypes() as $template_type) { $template_result->template_types[$template_type->param_name] = [$template_type->defining_class => $template_type->as]; } $closure_param_type = TemplateStandinTypeReplacer::replace($closure_param_type, $template_result, $codebase, $statements_analyzer, $input_type, $i, $context->self, $context->calling_method_id ?: $context->calling_function_id); $closure_type = $closure_type->replaceTemplateTypesWithArgTypes($template_result, $codebase); } $closure_param_type = TypeExpander::expandUnion($codebase, $closure_param_type, $context->self, null, $statements_analyzer->getParentFQCLN()); $union_comparison_results = new TypeComparisonResult(); $type_match_found = UnionTypeComparator::isContainedBy($codebase, $input_type, $closure_param_type, $input_type->ignore_nullable_issues, $input_type->ignore_falsable_issues, $union_comparison_results); if ($union_comparison_results->type_coerced) { if ($union_comparison_results->type_coerced_from_mixed) { IssueBuffer::maybeAdd(new MixedArgumentTypeCoercion('Parameter ' . ($i + 1) . ' of closure passed to function ' . $method_id . ' expects ' . $closure_param_type->getId() . ', but parent type ' . $input_type->getId() . ' provided', new CodeLocation($statements_analyzer->getSource(), $closure_arg), $method_id), $statements_analyzer->getSuppressedIssues()); } else { IssueBuffer::maybeAdd(new ArgumentTypeCoercion('Parameter ' . ($i + 1) . ' of closure passed to function ' . $method_id . ' expects ' . $closure_param_type->getId() . ', but parent type ' . $input_type->getId() . ' provided', new CodeLocation($statements_analyzer->getSource(), $closure_arg), $method_id), $statements_analyzer->getSuppressedIssues()); } } if (!$union_comparison_results->type_coerced && !$type_match_found) { $types_can_be_identical = UnionTypeComparator::canExpressionTypesBeIdentical($codebase, $input_type, $closure_param_type); if ($union_comparison_results->scalar_type_match_found) { IssueBuffer::maybeAdd(new InvalidScalarArgument('Parameter ' . ($i + 1) . ' of closure passed to function ' . $method_id . ' expects ' . $closure_param_type->getId() . ', but ' . $input_type->getId() . ' provided', new CodeLocation($statements_analyzer->getSource(), $closure_arg), $method_id), $statements_analyzer->getSuppressedIssues()); } elseif ($types_can_be_identical) { IssueBuffer::maybeAdd(new PossiblyInvalidArgument('Parameter ' . ($i + 1) . ' of closure passed to function ' . $method_id . ' expects ' . $closure_param_type->getId() . ', but possibly different type ' . $input_type->getId() . ' provided', new CodeLocation($statements_analyzer->getSource(), $closure_arg), $method_id), $statements_analyzer->getSuppressedIssues()); } else { IssueBuffer::maybeAdd(new InvalidArgument('Parameter ' . ($i + 1) . ' of closure passed to function ' . $method_id . ' expects ' . $closure_param_type->getId() . ', but ' . $input_type->getId() . ' provided', new CodeLocation($statements_analyzer->getSource(), $closure_arg), $method_id), $statements_analyzer->getSuppressedIssues()); } } } } } type = $type; $this->function_storage = $function_storage; $this->class_storage = $class_storage; } public function getTemplates() : TemplateResult { $templates = $this->class_storage ? array_merge($this->function_storage->template_types ?? [], $this->class_storage->template_types ?? []) : $this->function_storage->template_types ?? []; return new TemplateResult($templates, []); } public function getType() : string { return $this->type; } public function getFunctionType() : Union { switch ($this->type) { case self::TYPE_FIRST_CLASS_CALLABLE: return new Union([new TClosure('Closure', $this->function_storage->params, $this->function_storage->return_type, $this->function_storage->pure)]); case self::TYPE_STRING_CALLABLE: case self::TYPE_CLASS_CALLABLE: return new Union([new TCallable('callable', $this->function_storage->params, $this->function_storage->return_type, $this->function_storage->pure)]); default: return $this->function_storage->return_type ?? Type::getMixed(); } } } isFirstClassCallable()) { return; } $first_arg = $stmt->getArgs()[0] ?? null; if ($function_id === 'method_exists') { $second_arg = $stmt->getArgs()[1] ?? null; if ($first_arg && $first_arg->value instanceof PhpParser\Node\Expr\Variable && $second_arg && $second_arg->value instanceof PhpParser\Node\Scalar\String_) { // do nothing } else { $context->check_methods = \false; } return; } if ($function_id === 'class_exists') { if ($first_arg) { if ($first_arg->value instanceof PhpParser\Node\Scalar\String_) { if (!$codebase->classlikes->classExists($first_arg->value->value)) { $context->phantom_classes[strtolower($first_arg->value->value)] = \true; } } elseif ($first_arg->value instanceof PhpParser\Node\Expr\ClassConstFetch && $first_arg->value->class instanceof PhpParser\Node\Name && $first_arg->value->name instanceof PhpParser\Node\Identifier && $first_arg->value->name->name === 'class') { $resolved_name = (string) $first_arg->value->class->getAttribute('resolvedName'); if (!$codebase->classlikes->classExists($resolved_name)) { $context->phantom_classes[strtolower($resolved_name)] = \true; } } } return; } if ($function_id === 'interface_exists') { if ($first_arg) { if ($first_arg->value instanceof PhpParser\Node\Scalar\String_) { if (!$codebase->classlikes->interfaceExists($first_arg->value->value)) { $context->phantom_classes[strtolower($first_arg->value->value)] = \true; } } elseif ($first_arg->value instanceof PhpParser\Node\Expr\ClassConstFetch && $first_arg->value->class instanceof PhpParser\Node\Name && $first_arg->value->name instanceof PhpParser\Node\Identifier && $first_arg->value->name->name === 'class') { $resolved_name = (string) $first_arg->value->class->getAttribute('resolvedName'); if (!$codebase->classlikes->interfaceExists($resolved_name)) { $context->phantom_classes[strtolower($resolved_name)] = \true; } } } return; } if ($function_id === 'enum_exists') { if ($first_arg) { if ($first_arg->value instanceof PhpParser\Node\Scalar\String_) { if (!$codebase->classlikes->enumExists($first_arg->value->value)) { $context->phantom_classes[strtolower($first_arg->value->value)] = \true; } } elseif ($first_arg->value instanceof PhpParser\Node\Expr\ClassConstFetch && $first_arg->value->class instanceof PhpParser\Node\Name && $first_arg->value->name instanceof PhpParser\Node\Identifier && $first_arg->value->name->name === 'class') { $resolved_name = (string) $first_arg->value->class->getAttribute('resolvedName'); if (!$codebase->classlikes->enumExists($resolved_name)) { $context->phantom_classes[strtolower($resolved_name)] = \true; } } } return; } if (in_array($function_id, ['is_file', 'file_exists']) && $first_arg) { $var_id = ExpressionIdentifier::getExtendedVarId($first_arg->value, null); if ($var_id) { $context->phantom_files[$var_id] = \true; return; } // literal string or (magic) const in file path $codebase = $statements_analyzer->getCodebase(); $config = $codebase->config; $path_to_file = IncludeAnalyzer::getPathTo($first_arg->value, $statements_analyzer->node_data, $statements_analyzer, $statements_analyzer->getFileName(), $config); if ($path_to_file) { $context->phantom_files[$path_to_file] = \true; } return; } if ($function_id === 'extension_loaded') { if ($first_arg && $first_arg->value instanceof PhpParser\Node\Scalar\String_) { if (@extension_loaded($first_arg->value->value)) { // do nothing } else { $context->check_classes = \false; } } return; } if ($function_id === 'function_exists') { $context->check_functions = \false; return; } if ($function_id === 'is_callable') { $context->check_methods = \false; $context->check_functions = \false; return; } if ($function_id === 'defined') { if ($first_arg && !$context->inside_negation) { $fq_const_name = ConstFetchAnalyzer::getConstName($first_arg->value, $statements_analyzer->node_data, $codebase, $statements_analyzer->getAliases()); if ($fq_const_name !== null) { $const_type = ConstFetchAnalyzer::getConstType($statements_analyzer, $fq_const_name, \true, $context); if (!$const_type) { ConstFetchAnalyzer::setConstType($statements_analyzer, $fq_const_name, Type::getMixed(), $context); $context->check_consts = \false; } } else { $context->check_consts = \false; } } else { $context->check_consts = \false; } return; } if ($function_id === 'extract') { $flag_value = \false; if (!isset($stmt->args[1])) { $flag_value = EXTR_OVERWRITE; } elseif (isset($stmt->args[1]->value) && $stmt->args[1]->value instanceof PhpParser\Node\Expr && ($flags_type = $statements_analyzer->node_data->getType($stmt->args[1]->value)) && $flags_type->hasLiteralInt() && count($flags_type->getAtomicTypes()) === 1) { $flag_type_value = $flags_type->getSingleIntLiteral()->value; if ($flag_type_value === EXTR_SKIP) { $flag_value = EXTR_SKIP; } elseif ($flag_type_value === EXTR_OVERWRITE) { $flag_value = EXTR_OVERWRITE; } // @todo add support for other flags } $is_unsealed = \true; $validated_var_ids = []; if ($flag_value !== \false && isset($stmt->args[0]->value) && $stmt->args[0]->value instanceof PhpParser\Node\Expr && ($array_type_union = $statements_analyzer->node_data->getType($stmt->args[0]->value)) && $array_type_union->isSingle()) { foreach ($array_type_union->getAtomicTypes() as $array_type) { if ($array_type instanceof TList) { $array_type = $array_type->getKeyedArray(); } if ($array_type instanceof TKeyedArray) { foreach ($array_type->properties as $key => $type) { // variables must start with letters or underscore if ($key === '' || is_numeric($key) || preg_match('/^[A-Za-z_]/', $key) !== 1) { continue; } $var_id = '$' . $key; $validated_var_ids[] = $var_id; if (isset($context->vars_in_scope[$var_id]) && $flag_value === EXTR_SKIP) { continue; } if (!isset($context->vars_in_scope[$var_id]) && $type->possibly_undefined === \true) { $context->possibly_assigned_var_ids[$var_id] = \true; } elseif (isset($context->vars_in_scope[$var_id]) && $type->possibly_undefined === \true && $flag_value === EXTR_OVERWRITE) { $type = Type::combineUnionTypes($context->vars_in_scope[$var_id], $type, $codebase, \false, \true, 500, \false); } $context->vars_in_scope[$var_id] = $type; $context->assigned_var_ids[$var_id] = (int) $stmt->getAttribute('startFilePos'); } if (!isset($array_type->fallback_params)) { $is_unsealed = \false; } } } } if ($flag_value === EXTR_OVERWRITE && $is_unsealed === \false) { return; } if ($flag_value === EXTR_SKIP && $is_unsealed === \false) { return; } $context->check_variables = \false; if ($flag_value === EXTR_SKIP) { return; } foreach ($context->vars_in_scope as $var_id => $_) { if ($var_id === '$this' || strpos($var_id, '[') || strpos($var_id, '>')) { continue; } if (in_array($var_id, $validated_var_ids, \true)) { continue; } $mixed_type = new Union([new TMixed()], ['parent_nodes' => $context->vars_in_scope[$var_id]->parent_nodes]); $context->vars_in_scope[$var_id] = $mixed_type; $context->assigned_var_ids[$var_id] = (int) $stmt->getAttribute('startFilePos'); $context->possibly_assigned_var_ids[$var_id] = \true; } return; } if ($function_id === 'compact') { $all_args_string_literals = \true; $new_items = []; foreach ($stmt->getArgs() as $arg) { $arg_type = $statements_analyzer->node_data->getType($arg->value); if (!$arg_type || !$arg_type->isSingleStringLiteral()) { $all_args_string_literals = \false; break; } $var_name = $arg_type->getSingleStringLiteral()->value; $new_items[] = new VirtualArrayItem(new VirtualVariable($var_name, $arg->value->getAttributes()), new VirtualString($var_name, $arg->value->getAttributes()), \false, $arg->getAttributes()); } if ($all_args_string_literals) { $arr = new VirtualArray($new_items, $stmt->getAttributes()); $old_node_data = $statements_analyzer->node_data; $statements_analyzer->node_data = clone $statements_analyzer->node_data; ExpressionAnalyzer::analyze($statements_analyzer, $arr, $context); $arr_type = $statements_analyzer->node_data->getType($arr); $statements_analyzer->node_data = $old_node_data; if ($arr_type) { $statements_analyzer->node_data->setType($stmt, $arr_type); } } return; } if ($function_id === 'func_get_args') { $source = $statements_analyzer->getSource(); if ($source instanceof FunctionLikeAnalyzer) { if ($statements_analyzer->data_flow_graph instanceof VariableUseGraph) { foreach ($source->param_nodes as $param_node) { $statements_analyzer->data_flow_graph->addPath($param_node, new DataFlowNode('variable-use', 'variable use', null), 'variable-use'); } } } return; } if ($function_id === 'var_dump' || $function_id === 'shell_exec') { IssueBuffer::maybeAdd(new ForbiddenCode('Unsafe ' . $function_id, new CodeLocation($statements_analyzer->getSource(), $stmt)), $statements_analyzer->getSuppressedIssues()); } if (isset($codebase->config->forbidden_functions[$function_id])) { IssueBuffer::maybeAdd(new ForbiddenCode('You have forbidden the use of ' . $function_id, new CodeLocation($statements_analyzer->getSource(), $stmt)), $statements_analyzer->getSuppressedIssues()); return; } if ($function_id === 'define') { if ($first_arg) { $fq_const_name = ConstFetchAnalyzer::getConstName($first_arg->value, $statements_analyzer->node_data, $codebase, $statements_analyzer->getAliases()); if ($fq_const_name !== null && isset($stmt->getArgs()[1])) { $second_arg = $stmt->getArgs()[1]; $was_in_call = $context->inside_call; $context->inside_call = \true; ExpressionAnalyzer::analyze($statements_analyzer, $second_arg->value, $context); $context->inside_call = $was_in_call; ConstFetchAnalyzer::setConstType($statements_analyzer, $fq_const_name, $statements_analyzer->node_data->getType($second_arg->value) ?? Type::getMixed(), $context); } } else { $context->check_consts = \false; } return; } if ($function_id === 'constant') { if ($first_arg) { $fq_const_name = ConstFetchAnalyzer::getConstName($first_arg->value, $statements_analyzer->node_data, $codebase, $statements_analyzer->getAliases()); if ($fq_const_name !== null) { $const_type = ConstFetchAnalyzer::getConstType($statements_analyzer, $fq_const_name, \true, $context); if ($const_type) { $statements_analyzer->node_data->setType($real_stmt, $const_type); } } } else { $context->check_consts = \false; } } if ($first_arg && $function_id && strpos($function_id, 'is_') === 0 && $function_id !== 'is_a' && !$context->inside_negation) { $stmt_assertions = $statements_analyzer->node_data->getAssertions($stmt); $anded_assertions = $stmt_assertions ?? AssertionFinder::processFunctionCall($stmt, $context->self, $statements_analyzer, $codebase, $context->inside_negation); $changed_vars = []; foreach ($anded_assertions as $assertions) { $referenced_var_ids = array_map(static fn(array $_): bool => \true, $assertions); Reconciler::reconcileKeyedTypes($assertions, $assertions, $context->vars_in_scope, $context->references_in_scope, $changed_vars, $referenced_var_ids, $statements_analyzer, [], $context->inside_loop, new CodeLocation($statements_analyzer->getSource(), $stmt)); } return; } if ($first_arg && ($function_id === 'array_values' || $function_id === 'ksort')) { $first_arg_type = $statements_analyzer->node_data->getType($first_arg->value); if ($first_arg_type && UnionTypeComparator::isContainedBy($codebase, $first_arg_type, Type::getList())) { if ($first_arg_type->from_docblock) { IssueBuffer::maybeAdd(new RedundantFunctionCallGivenDocblockType("The call to {$function_id} is unnecessary given the list docblock type {$first_arg_type}", new CodeLocation($statements_analyzer, $function_name)), $statements_analyzer->getSuppressedIssues()); } else { IssueBuffer::maybeAdd(new RedundantFunctionCall("The call to {$function_id} is unnecessary, {$first_arg_type} is already a list", new CodeLocation($statements_analyzer, $function_name)), $statements_analyzer->getSuppressedIssues()); } } } if ($first_arg && $function_id === 'strtolower') { $first_arg_type = $statements_analyzer->node_data->getType($first_arg->value); if ($first_arg_type && UnionTypeComparator::isContainedBy($codebase, $first_arg_type, new Union([new TLowercaseString()]))) { if ($first_arg_type->from_docblock) { IssueBuffer::maybeAdd(new RedundantFunctionCallGivenDocblockType('The call to strtolower is unnecessary given the docblock type', new CodeLocation($statements_analyzer, $function_name)), $statements_analyzer->getSuppressedIssues()); } else { IssueBuffer::maybeAdd(new RedundantFunctionCall('The call to strtolower is unnecessary', new CodeLocation($statements_analyzer, $function_name)), $statements_analyzer->getSuppressedIssues()); } } } if ($first_arg && ($function_id === 'array_walk' || $function_id === 'array_walk_recursive')) { $first_arg_type = $statements_analyzer->node_data->getType($first_arg->value); if ($first_arg_type && $first_arg_type->hasObjectType()) { if ($first_arg_type->isSingle()) { IssueBuffer::maybeAdd(new RawObjectIteration('Possibly undesired iteration over object properties', new CodeLocation($statements_analyzer, $function_name))); } else { IssueBuffer::maybeAdd(new PossibleRawObjectIteration('Possibly undesired iteration over object properties', new CodeLocation($statements_analyzer, $function_name))); } } } if ($first_arg && $function_id === 'is_a' && !$context->inside_conditional) { $first_arg_type = $statements_analyzer->node_data->getType($first_arg->value); if ($first_arg_type && $first_arg_type->isString()) { $third_arg = $stmt->getArgs()[2] ?? null; if ($third_arg) { $third_arg_type = $statements_analyzer->node_data->getType($third_arg->value); } else { $third_arg_type = Type::getFalse(); } if ($third_arg_type && $third_arg_type->isSingle() && $third_arg_type->isFalse()) { if ($first_arg_type->from_docblock) { IssueBuffer::maybeAdd(new RedundantFunctionCallGivenDocblockType('Call to is_a always return false when first argument is string ' . 'unless third argument is true', new CodeLocation($statements_analyzer, $function_name))); } else { IssueBuffer::maybeAdd(new RedundantFunctionCall('Call to is_a always return false when first argument is string ' . 'unless third argument is true', new CodeLocation($statements_analyzer, $function_name))); } } } } } private static function handleDependentTypeFunction(StatementsAnalyzer $statements_analyzer, PhpParser\Node\Expr\FuncCall $stmt, PhpParser\Node\Expr\FuncCall $real_stmt, string $function_id, Context $context) : void { $first_arg = $stmt->getArgs()[0] ?? null; if ($first_arg) { $var = $first_arg->value; if ($var instanceof PhpParser\Node\Expr\Variable && is_string($var->name)) { $var_id = '$' . $var->name; if (isset($context->vars_in_scope[$var_id])) { if (!$context->vars_in_scope[$var_id]->hasTemplate()) { if ($function_id === 'get_class') { $atomic_type = new TDependentGetClass($var_id, $context->vars_in_scope[$var_id]->hasMixed() ? Type::getObject() : $context->vars_in_scope[$var_id]); } elseif ($function_id === 'gettype') { $atomic_type = new TDependentGetType($var_id); } else { $atomic_type = new TDependentGetDebugType($var_id); } $statements_analyzer->node_data->setType($real_stmt, new Union([$atomic_type])); return; } } } if (($var_type = $statements_analyzer->node_data->getType($var)) && ($function_id === 'get_class' || $function_id === 'get_debug_type')) { $class_string_types = []; foreach ($var_type->getAtomicTypes() as $class_type) { if ($class_type instanceof TNamedObject) { $class_string_types[] = new TClassString($class_type->value, $class_type); } elseif ($class_type instanceof TTemplateParam && $class_type->as->isSingle()) { $as_atomic_type = $class_type->as->getSingleAtomic(); if ($as_atomic_type instanceof TObject) { $class_string_types[] = new TTemplateParamClass($class_type->param_name, 'object', null, $class_type->defining_class); } elseif ($as_atomic_type instanceof TNamedObject) { $class_string_types[] = new TTemplateParamClass($class_type->param_name, $as_atomic_type->value, $as_atomic_type, $class_type->defining_class); } } elseif ($function_id === 'get_class') { $class_string_types[] = new TClassString(); } else { if ($class_type instanceof TInt) { $class_string_types[] = Type::getAtomicStringFromLiteral('int'); } elseif ($class_type instanceof TString) { $class_string_types[] = Type::getAtomicStringFromLiteral('string'); } elseif ($class_type instanceof TFloat) { $class_string_types[] = Type::getAtomicStringFromLiteral('float'); } elseif ($class_type instanceof TBool) { $class_string_types[] = Type::getAtomicStringFromLiteral('bool'); } elseif ($class_type instanceof TClosedResource) { $class_string_types[] = Type::getAtomicStringFromLiteral('resource (closed)'); } elseif ($class_type instanceof TNull) { $class_string_types[] = Type::getAtomicStringFromLiteral('null'); } else { $class_string_types[] = new TString(); } } } if ($class_string_types) { $statements_analyzer->node_data->setType($real_stmt, new Union($class_string_types)); } } } elseif ($function_id === 'get_class' && ($get_class_name = $statements_analyzer->getFQCLN())) { $statements_analyzer->node_data->setType($real_stmt, new Union([new TClassString($get_class_name, new TNamedObject($get_class_name))])); } } } getCodebase(); $config = $codebase->config; if (!$config->allow_includes) { throw new FileIncludeException('File includes are not allowed per your Psalm config - check the allowFileIncludes flag.'); } $was_inside_call = $context->inside_call; $context->inside_call = \true; if (ExpressionAnalyzer::analyze($statements_analyzer, $stmt->expr, $context) === \false) { $context->inside_call = $was_inside_call; return \false; } $context->inside_call = $was_inside_call; $stmt_expr_type = $statements_analyzer->node_data->getType($stmt->expr); if ($stmt->expr instanceof PhpParser\Node\Scalar\String_ || $stmt_expr_type && $stmt_expr_type->isSingleStringLiteral()) { if ($stmt->expr instanceof PhpParser\Node\Scalar\String_) { $path_to_file = $stmt->expr->value; } else { $path_to_file = $stmt_expr_type->getSingleStringLiteral()->value; } $path_to_file = str_replace('/', DIRECTORY_SEPARATOR, $path_to_file); // attempts to resolve using get_include_path dirs $include_path = self::resolveIncludePath($path_to_file, dirname($statements_analyzer->getFilePath())); $path_to_file = $include_path ?: $path_to_file; if (Path::isRelative($path_to_file)) { $path_to_file = $config->base_dir . DIRECTORY_SEPARATOR . $path_to_file; } } else { $path_to_file = self::getPathTo($stmt->expr, $statements_analyzer->node_data, $statements_analyzer, $statements_analyzer->getFileName(), $config); } if ($stmt_expr_type && $statements_analyzer->data_flow_graph instanceof TaintFlowGraph && $stmt_expr_type->parent_nodes && !in_array('TaintedInput', $statements_analyzer->getSuppressedIssues())) { $arg_location = new CodeLocation($statements_analyzer->getSource(), $stmt->expr); $include_param_sink = TaintSink::getForMethodArgument('include', 'include', 0, $arg_location, $arg_location); $include_param_sink->taints = [TaintKind::INPUT_INCLUDE]; $statements_analyzer->data_flow_graph->addSink($include_param_sink); $codebase = $statements_analyzer->getCodebase(); $event = new AddRemoveTaintsEvent($stmt, $context, $statements_analyzer, $codebase); $added_taints = $codebase->config->eventDispatcher->dispatchAddTaints($event); $removed_taints = $codebase->config->eventDispatcher->dispatchRemoveTaints($event); foreach ($stmt_expr_type->parent_nodes as $parent_node) { $statements_analyzer->data_flow_graph->addPath($parent_node, $include_param_sink, 'arg', $added_taints, $removed_taints); } } if ($path_to_file) { $path_to_file = self::normalizeFilePath($path_to_file); // if the file is already included, we can't check much more if (in_array(realpath($path_to_file), get_included_files(), \true)) { return \true; } $current_file_analyzer = $statements_analyzer->getFileAnalyzer(); if ($current_file_analyzer->project_analyzer->fileExists($path_to_file) && !$current_file_analyzer->project_analyzer->isDirectory($path_to_file)) { if ($statements_analyzer->hasParentFilePath($path_to_file) || !$codebase->file_storage_provider->has($path_to_file) || $statements_analyzer->hasAlreadyRequiredFilePath($path_to_file) && !$codebase->file_storage_provider->get($path_to_file)->has_extra_statements) { return \true; } if ($config->mustBeIgnored($path_to_file)) { return \true; } $current_file_analyzer->addRequiredFilePath($path_to_file); $file_name = $config->shortenFileName($path_to_file); $nesting = $statements_analyzer->getRequireNesting() + 1; $current_file_analyzer->project_analyzer->progress->debug(str_repeat(' ', $nesting) . 'checking ' . $file_name . PHP_EOL); $include_file_analyzer = new FileAnalyzer($current_file_analyzer->project_analyzer, $path_to_file, $file_name); $include_file_analyzer->setRootFilePath($current_file_analyzer->getRootFilePath(), $current_file_analyzer->getRootFileName()); $include_file_analyzer->addParentFilePath($current_file_analyzer->getFilePath()); $include_file_analyzer->addRequiredFilePath($current_file_analyzer->getFilePath()); foreach ($current_file_analyzer->getRequiredFilePaths() as $required_file_path) { $include_file_analyzer->addRequiredFilePath($required_file_path); } foreach ($current_file_analyzer->getParentFilePaths() as $parent_file_path) { $include_file_analyzer->addParentFilePath($parent_file_path); } try { $include_file_analyzer->analyze($context, $global_context); } catch (UnpreparedAnalysisException $e) { if ($config->skip_checks_on_unresolvable_includes) { $context->check_classes = \false; $context->check_variables = \false; $context->check_functions = \false; } } $included_return_type = $include_file_analyzer->getReturnType(); if ($included_return_type) { $statements_analyzer->node_data->setType($stmt, $included_return_type); } $context->has_returned = \false; foreach ($include_file_analyzer->getRequiredFilePaths() as $required_file_path) { $current_file_analyzer->addRequiredFilePath($required_file_path); } $include_file_analyzer->clearSourceBeforeDestruction(); return \true; } if (isset($context->phantom_files[$path_to_file])) { return \true; } $var_id = \Psalm\Internal\Analyzer\Statements\Expression\ExpressionIdentifier::getExtendedVarId($stmt->expr, null); if ($var_id && isset($context->phantom_files[$var_id])) { return \true; } $source = $statements_analyzer->getSource(); IssueBuffer::maybeAdd(new MissingFile('Cannot find file ' . $path_to_file . ' to include', new CodeLocation($source, $stmt)), $source->getSuppressedIssues()); } else { $var_id = \Psalm\Internal\Analyzer\Statements\Expression\ExpressionIdentifier::getExtendedVarId($stmt->expr, null); if (!$var_id || !isset($context->phantom_files[$var_id])) { $source = $statements_analyzer->getSource(); IssueBuffer::maybeAdd(new UnresolvableInclude('Cannot resolve the given expression to a file path', new CodeLocation($source, $stmt)), $source->getSuppressedIssues()); } } if ($config->skip_checks_on_unresolvable_includes) { $context->check_classes = \false; $context->check_variables = \false; $context->check_functions = \false; } return \true; } /** * @psalm-suppress MixedAssignment */ public static function getPathTo(PhpParser\Node\Expr $stmt, ?NodeDataProvider $type_provider, ?StatementsAnalyzer $statements_analyzer, string $file_name, Config $config) : ?string { if (Path::isRelative($file_name)) { $file_name = $config->base_dir . DIRECTORY_SEPARATOR . $file_name; } if ($stmt instanceof PhpParser\Node\Scalar\String_) { if (DIRECTORY_SEPARATOR !== '/') { return str_replace('/', DIRECTORY_SEPARATOR, $stmt->value); } return $stmt->value; } $stmt_type = $type_provider ? $type_provider->getType($stmt) : null; if ($stmt_type && $stmt_type->isSingleStringLiteral()) { if (DIRECTORY_SEPARATOR !== '/') { return str_replace('/', DIRECTORY_SEPARATOR, $stmt_type->getSingleStringLiteral()->value); } return $stmt_type->getSingleStringLiteral()->value; } if ($stmt instanceof PhpParser\Node\Expr\ArrayDimFetch) { if ($stmt->var instanceof PhpParser\Node\Expr\Variable && $stmt->var->name === 'GLOBALS' && $stmt->dim instanceof PhpParser\Node\Scalar\String_) { if (isset($GLOBALS[$stmt->dim->value]) && is_string($GLOBALS[$stmt->dim->value])) { /** @var string */ return $GLOBALS[$stmt->dim->value]; } } } elseif ($stmt instanceof PhpParser\Node\Expr\BinaryOp\Concat) { $left_string = self::getPathTo($stmt->left, $type_provider, $statements_analyzer, $file_name, $config); $right_string = self::getPathTo($stmt->right, $type_provider, $statements_analyzer, $file_name, $config); if ($left_string && $right_string) { return $left_string . $right_string; } } elseif ($stmt instanceof PhpParser\Node\Expr\FuncCall && $stmt->name instanceof PhpParser\Node\Name && $stmt->name->getParts() === ['dirname']) { if ($stmt->getArgs()) { $dir_level = 1; if (isset($stmt->getArgs()[1])) { if ($stmt->getArgs()[1]->value instanceof PhpParser\Node\Scalar\LNumber) { $dir_level = $stmt->getArgs()[1]->value->value; } else { if ($statements_analyzer) { $t = $statements_analyzer->node_data->getType($stmt->getArgs()[1]->value); if ($t && $t->isSingleIntLiteral()) { $dir_level = $t->getSingleIntLiteral()->value; } else { return null; } } else { return null; } } } $evaled_path = self::getPathTo($stmt->getArgs()[0]->value, $type_provider, $statements_analyzer, $file_name, $config); if (!$evaled_path) { return null; } if ($dir_level < 1) { return null; } return dirname($evaled_path, $dir_level); } } elseif ($stmt instanceof PhpParser\Node\Expr\ConstFetch) { $const_name = implode('', $stmt->name->getParts()); if (defined($const_name)) { $constant_value = constant($const_name); if (is_string($constant_value)) { return $constant_value; } } } elseif ($stmt instanceof PhpParser\Node\Scalar\MagicConst\Dir) { return dirname($file_name); } elseif ($stmt instanceof PhpParser\Node\Scalar\MagicConst\File) { return $file_name; } return null; } public static function resolveIncludePath(string $file_name, string $current_directory) : ?string { if (!$current_directory) { return $file_name; } if (substr($file_name, 0, 2) === '.' . DIRECTORY_SEPARATOR || substr($file_name, 0, 3) === '..' . DIRECTORY_SEPARATOR) { $file = $current_directory . DIRECTORY_SEPARATOR . $file_name; if (file_exists($file)) { return $file; } return null; } $paths = PATH_SEPARATOR === ':' ? preg_split('#(?inside_general_use; $context->inside_general_use = \true; if (!$stmt->name instanceof PhpParser\Node\Identifier) { if (ExpressionAnalyzer::analyze($statements_analyzer, $stmt->name, $context) === \false) { return \false; } } if (ExpressionAnalyzer::analyze($statements_analyzer, $stmt->var, $context) === \false) { $context->inside_general_use = $was_inside_general_use; return \false; } $context->inside_general_use = $was_inside_general_use; if ($stmt->name instanceof PhpParser\Node\Identifier) { $prop_name = $stmt->name->name; } elseif (($stmt_name_type = $statements_analyzer->node_data->getType($stmt->name)) && $stmt_name_type->isSingleStringLiteral()) { $prop_name = $stmt_name_type->getSingleStringLiteral()->value; } else { $prop_name = null; } $codebase = $statements_analyzer->getCodebase(); $stmt_var_id = ExpressionIdentifier::getExtendedVarId($stmt->var, $statements_analyzer->getFQCLN(), $statements_analyzer); $var_id = ExpressionIdentifier::getExtendedVarId($stmt, $statements_analyzer->getFQCLN(), $statements_analyzer); if ($var_id && $context->hasVariable($var_id)) { self::handleScopedProperty($context, $var_id, $statements_analyzer, $stmt, $codebase, $stmt_var_id, $in_assignment); return \true; } if ($stmt_var_id && $context->hasVariable($stmt_var_id)) { $stmt_var_type = $context->vars_in_scope[$stmt_var_id]; } else { $stmt_var_type = $statements_analyzer->node_data->getType($stmt->var); } if (!$stmt_var_type) { return \true; } if ($stmt_var_type->isNull()) { return !IssueBuffer::accepts(new NullPropertyFetch('Cannot get property on null variable ' . $stmt_var_id, new CodeLocation($statements_analyzer->getSource(), $stmt)), $statements_analyzer->getSuppressedIssues()); } if ($stmt_var_type->isNever()) { return !IssueBuffer::accepts(new MixedPropertyFetch('Cannot fetch property on empty var ' . $stmt_var_id, new CodeLocation($statements_analyzer->getSource(), $stmt)), $statements_analyzer->getSuppressedIssues()); } if ($stmt_var_type->hasMixed()) { if (!$context->collect_initializations && !$context->collect_mutations && $statements_analyzer->getFilePath() === $statements_analyzer->getRootFilePath() && (!($parent_source = $statements_analyzer->getSource()) instanceof FunctionLikeAnalyzer || !$parent_source->getSource() instanceof TraitAnalyzer)) { $codebase->analyzer->incrementMixedCount($statements_analyzer->getFilePath()); } if ($stmt->name instanceof PhpParser\Node\Identifier) { $codebase->analyzer->addMixedMemberName('$' . $stmt->name->name, $context->calling_method_id ?: $statements_analyzer->getFileName()); } IssueBuffer::maybeAdd(new MixedPropertyFetch('Cannot fetch property on mixed var ' . $stmt_var_id, new CodeLocation($statements_analyzer->getSource(), $stmt)), $statements_analyzer->getSuppressedIssues()); $statements_analyzer->node_data->setType($stmt, Type::getMixed()); if ($codebase->store_node_types && !$context->collect_initializations && !$context->collect_mutations) { $codebase->analyzer->addNodeType($statements_analyzer->getFilePath(), $stmt->name, $stmt_var_type->getId()); } } if (!$context->collect_initializations && !$context->collect_mutations && $statements_analyzer->getFilePath() === $statements_analyzer->getRootFilePath() && (!($parent_source = $statements_analyzer->getSource()) instanceof FunctionLikeAnalyzer || !$parent_source->getSource() instanceof TraitAnalyzer)) { $codebase->analyzer->incrementNonMixedCount($statements_analyzer->getRootFilePath()); } if ($stmt_var_type->isNullable() && !$stmt_var_type->ignore_nullable_issues) { // we can only be sure that the variable is possibly null if we know the var_id if (!$context->inside_isset && $stmt->name instanceof PhpParser\Node\Identifier && !MethodCallAnalyzer::hasNullsafe($stmt->var)) { IssueBuffer::maybeAdd(new PossiblyNullPropertyFetch(rtrim('Cannot get property on possibly null variable ' . $stmt_var_id) . ' of type ' . $stmt_var_type, new CodeLocation($statements_analyzer->getSource(), $stmt)), $statements_analyzer->getSuppressedIssues()); } else { $statements_analyzer->node_data->setType($stmt, Type::getNull()); } } if (!$prop_name) { if ($stmt_var_type->hasObjectType() && !$context->ignore_variable_property) { foreach ($stmt_var_type->getAtomicTypes() as $type) { if ($type instanceof TNamedObject) { $codebase->analyzer->addMixedMemberName(strtolower($type->value) . '::$', $context->calling_method_id ?: $statements_analyzer->getFileName()); } } } $statements_analyzer->node_data->setType($stmt, Type::getMixed()); if ($codebase->store_node_types && !$context->collect_initializations && !$context->collect_mutations) { $codebase->analyzer->addNodeType($statements_analyzer->getFilePath(), $stmt->name, $stmt_var_type->getId()); } return \true; } $invalid_fetch_types = []; $has_valid_fetch_type = \false; $var_atomic_types = $stmt_var_type->getAtomicTypes(); while ($lhs_type_part = array_shift($var_atomic_types)) { if ($lhs_type_part instanceof TTemplateParam) { $var_atomic_types = array_merge($var_atomic_types, $lhs_type_part->as->getAtomicTypes()); continue; } \Psalm\Internal\Analyzer\Statements\Expression\Fetch\AtomicPropertyFetchAnalyzer::analyze($statements_analyzer, $stmt, $context, $in_assignment, $var_id, $stmt_var_id, $stmt_var_type, $lhs_type_part, $prop_name, $has_valid_fetch_type, $invalid_fetch_types, $is_static_access); } $stmt_type = $statements_analyzer->node_data->getType($stmt); if ($stmt_var_type->isNullable() && !$context->inside_isset && $stmt_type) { $stmt_type = $stmt_type->getBuilder()->addType(new TNull()); if ($stmt_var_type->ignore_nullable_issues) { $stmt_type->ignore_nullable_issues = \true; } $stmt_type = $stmt_type->freeze(); $statements_analyzer->node_data->setType($stmt, $stmt_type); } if ($codebase->store_node_types && !$context->collect_initializations && !$context->collect_mutations && ($stmt_type = $statements_analyzer->node_data->getType($stmt))) { $codebase->analyzer->addNodeType($statements_analyzer->getFilePath(), $stmt->name, $stmt_type->getId()); } if ($invalid_fetch_types) { $lhs_type_part = $invalid_fetch_types[0]; if ($has_valid_fetch_type) { IssueBuffer::maybeAdd(new PossiblyInvalidPropertyFetch('Cannot fetch property on possible non-object ' . $stmt_var_id . ' of type ' . $lhs_type_part, new CodeLocation($statements_analyzer->getSource(), $stmt)), $statements_analyzer->getSuppressedIssues()); } else { IssueBuffer::maybeAdd(new InvalidPropertyFetch('Cannot fetch property on non-object ' . $stmt_var_id . ' of type ' . $lhs_type_part, new CodeLocation($statements_analyzer->getSource(), $stmt)), $statements_analyzer->getSuppressedIssues()); } } if ($var_id) { $context->vars_in_scope[$var_id] = $statements_analyzer->node_data->getType($stmt) ?? Type::getMixed(); } return \true; } private static function handleScopedProperty(Context $context, string $var_id, StatementsAnalyzer $statements_analyzer, PhpParser\Node\Expr\PropertyFetch $stmt, Codebase $codebase, ?string $stmt_var_id, bool $in_assignment) : void { $stmt_type = $context->vars_in_scope[$var_id]; // we don't need to check anything $statements_analyzer->node_data->setType($stmt, $stmt_type); if (!$context->collect_initializations && !$context->collect_mutations && $statements_analyzer->getFilePath() === $statements_analyzer->getRootFilePath() && (!($parent_source = $statements_analyzer->getSource()) instanceof FunctionLikeAnalyzer || !$parent_source->getSource() instanceof TraitAnalyzer)) { $codebase->analyzer->incrementNonMixedCount($statements_analyzer->getFilePath()); } if ($codebase->store_node_types && !$context->collect_initializations && !$context->collect_mutations) { $codebase->analyzer->addNodeType($statements_analyzer->getFilePath(), $stmt->name, $stmt_type->getId()); } if ($stmt_var_id === '$this' && !$stmt_type->initialized && $context->collect_initializations && ($stmt_var_type = $statements_analyzer->node_data->getType($stmt->var)) && $stmt_var_type->hasObjectType() && $stmt->name instanceof PhpParser\Node\Identifier) { $source = $statements_analyzer->getSource(); $property_id = null; foreach ($stmt_var_type->getAtomicTypes() as $lhs_type_part) { if ($lhs_type_part instanceof TNamedObject) { if (!$codebase->classExists($lhs_type_part->value)) { continue; } $property_id = $lhs_type_part->value . '::$' . $stmt->name->name; } } if ($property_id && $source instanceof FunctionLikeAnalyzer && $source->getMethodName() === '__construct' && !$context->inside_unset) { if ($context->inside_isset || $context->inside_assignment && isset($context->vars_in_scope[$var_id]) && $context->vars_in_scope[$var_id]->isNullable()) { $stmt_type = $stmt_type->setProperties(['initialized' => \true]); $statements_analyzer->node_data->setType($stmt, $stmt_type); $context->vars_in_scope[$var_id] = $stmt_type; } else { IssueBuffer::maybeAdd(new UninitializedProperty('Cannot use uninitialized property ' . $var_id, new CodeLocation($statements_analyzer->getSource(), $stmt), $var_id), $statements_analyzer->getSuppressedIssues()); $stmt_type = $stmt_type->getBuilder()->addType(new TNull())->freeze(); $context->vars_in_scope[$var_id] = $stmt_type; $statements_analyzer->node_data->setType($stmt, $stmt_type); } } } if (($stmt_var_type = $statements_analyzer->node_data->getType($stmt->var)) && $stmt_var_type->hasObjectType() && $stmt->name instanceof PhpParser\Node\Identifier) { // log the appearance foreach ($stmt_var_type->getAtomicTypes() as $lhs_type_part) { if ($lhs_type_part instanceof TNamedObject) { if (!$codebase->classExists($lhs_type_part->value)) { continue; } $property_id = $lhs_type_part->value . '::$' . $stmt->name->name; $class_storage = $codebase->classlike_storage_provider->get($lhs_type_part->value); \Psalm\Internal\Analyzer\Statements\Expression\Fetch\AtomicPropertyFetchAnalyzer::processTaints($statements_analyzer, $stmt, $stmt_type, $property_id, $class_storage, $in_assignment); $context->vars_in_scope[$var_id] = $stmt_type; $statements_analyzer->node_data->setType($stmt, $stmt_type); $declaring_property_class = $codebase->properties->getDeclaringClassForProperty($property_id, \true, $statements_analyzer); if ($declaring_property_class) { \Psalm\Internal\Analyzer\Statements\Expression\Fetch\AtomicPropertyFetchAnalyzer::checkPropertyDeprecation($stmt->name->name, $declaring_property_class, $stmt, $statements_analyzer); } $codebase->properties->propertyExists($property_id, \true, $statements_analyzer, $context, $codebase->collect_locations ? new CodeLocation($statements_analyzer->getSource(), $stmt) : null); if ($codebase->store_node_types && !$context->collect_initializations && !$context->collect_mutations) { $codebase->analyzer->addNodeReference($statements_analyzer->getFilePath(), $stmt->name, $property_id); } if (!$context->collect_mutations && !$context->collect_initializations && !($class_storage->external_mutation_free && $stmt_type->allow_mutations)) { if ($context->pure) { IssueBuffer::maybeAdd(new ImpurePropertyFetch('Cannot access a property on a mutable object from a pure context', new CodeLocation($statements_analyzer, $stmt)), $statements_analyzer->getSuppressedIssues()); } elseif ($statements_analyzer->getSource() instanceof FunctionLikeAnalyzer && $statements_analyzer->getSource()->track_mutations) { $statements_analyzer->getSource()->inferred_impure = \true; } } } } } } } class instanceof PhpParser\Node\Name) { self::analyzeVariableStaticPropertyFetch($statements_analyzer, $stmt->class, $stmt, $context); return \true; } $codebase = $statements_analyzer->getCodebase(); if (count($stmt->class->getParts()) === 1 && in_array(strtolower($stmt->class->getFirst()), ['self', 'static', 'parent'], \true)) { if ($stmt->class->getFirst() === 'parent') { $fq_class_name = $statements_analyzer->getParentFQCLN(); if ($fq_class_name === null) { return !IssueBuffer::accepts(new ParentNotFound('Cannot check property fetch on parent as this class does not extend another', new CodeLocation($statements_analyzer->getSource(), $stmt)), $statements_analyzer->getSuppressedIssues()); } } else { $fq_class_name = (string) $context->self; } if ($context->isPhantomClass($fq_class_name)) { return \true; } } else { $aliases = $statements_analyzer->getAliases(); if ($context->calling_method_id && !$stmt->class instanceof PhpParser\Node\Name\FullyQualified) { $codebase->file_reference_provider->addMethodReferenceToClassMember($context->calling_method_id, 'use:' . $stmt->class->getFirst() . ':' . md5($statements_analyzer->getFilePath()), \false); } $fq_class_name = ClassLikeAnalyzer::getFQCLNFromNameObject($stmt->class, $aliases); if ($context->isPhantomClass($fq_class_name)) { return \true; } if ($context->check_classes) { if (ClassLikeAnalyzer::checkFullyQualifiedClassLikeName($statements_analyzer, $fq_class_name, new CodeLocation($statements_analyzer->getSource(), $stmt->class), $context->self, $context->calling_method_id, $statements_analyzer->getSuppressedIssues()) !== \true) { return \false; } } } if ($fq_class_name && $codebase->methods_to_move && $context->calling_method_id && isset($codebase->methods_to_move[$context->calling_method_id])) { $destination_method_id = $codebase->methods_to_move[$context->calling_method_id]; $codebase->classlikes->airliftClassLikeReference($fq_class_name, explode('::', $destination_method_id)[0], $statements_analyzer->getFilePath(), (int) $stmt->class->getAttribute('startFilePos'), (int) $stmt->class->getAttribute('endFilePos') + 1); } if ($fq_class_name) { $statements_analyzer->node_data->setType($stmt->class, new Union([new TNamedObject($fq_class_name)])); } if ($stmt->name instanceof PhpParser\Node\VarLikeIdentifier) { $prop_name = $stmt->name->name; } else { $was_inside_general_use = $context->inside_general_use; $context->inside_general_use = \true; if (ExpressionAnalyzer::analyze($statements_analyzer, $stmt->name, $context) === \false) { $context->inside_general_use = $was_inside_general_use; return \false; } $context->inside_general_use = $was_inside_general_use; if (($stmt_name_type = $statements_analyzer->node_data->getType($stmt->name)) && $stmt_name_type->isSingleStringLiteral()) { $prop_name = $stmt_name_type->getSingleStringLiteral()->value; } else { $prop_name = null; } } if (!$prop_name) { if ($fq_class_name) { $codebase->analyzer->addMixedMemberName(strtolower($fq_class_name) . '::$', $context->calling_method_id ?: $statements_analyzer->getFileName()); } return \true; } if (!$fq_class_name || !$context->check_variables || ExpressionAnalyzer::isMock($fq_class_name)) { return \true; } $var_id = ExpressionIdentifier::getVarId($stmt, $context->self ?: $statements_analyzer->getFQCLN(), $statements_analyzer); $property_id = $fq_class_name . '::$' . $prop_name; if ($codebase->store_node_types && !$context->collect_initializations && !$context->collect_mutations) { $codebase->analyzer->addNodeReference($statements_analyzer->getFilePath(), $stmt->name, $property_id); } if ($context->mutation_free) { IssueBuffer::maybeAdd(new ImpureStaticProperty('Cannot use a static property in a mutation-free context', new CodeLocation($statements_analyzer, $stmt)), $statements_analyzer->getSuppressedIssues()); } elseif ($statements_analyzer->getSource() instanceof FunctionLikeAnalyzer && $statements_analyzer->getSource()->track_mutations) { $statements_analyzer->getSource()->inferred_has_mutation = \true; $statements_analyzer->getSource()->inferred_impure = \true; } if ($var_id && $context->hasVariable($var_id)) { $stmt_type = $context->vars_in_scope[$var_id]; \Psalm\Internal\Analyzer\Statements\Expression\Fetch\AtomicPropertyFetchAnalyzer::processUnspecialTaints($statements_analyzer, $stmt, $stmt_type, $property_id, \false, [], []); $context->vars_in_scope[$var_id] = $stmt_type; $statements_analyzer->node_data->setType($stmt, $stmt_type); if ($codebase->collect_references) { // log the appearance $codebase->properties->propertyExists($property_id, \true, $statements_analyzer, $context, $codebase->collect_locations ? new CodeLocation($statements_analyzer->getSource(), $stmt) : null); } if ($codebase->store_node_types && !$context->collect_initializations && !$context->collect_mutations) { $codebase->analyzer->addNodeType($statements_analyzer->getFilePath(), $stmt->name, $stmt_type->getId()); } return \true; } if (!$codebase->properties->propertyExists($property_id, \true, $statements_analyzer, $context, $codebase->collect_locations ? new CodeLocation($statements_analyzer->getSource(), $stmt) : null)) { if ($context->inside_isset || !$context->check_classes) { return \true; } IssueBuffer::maybeAdd(new UndefinedPropertyFetch('Static property ' . $property_id . ' is not defined', new CodeLocation($statements_analyzer->getSource(), $stmt), $property_id), $statements_analyzer->getSuppressedIssues()); return \true; } $declaring_property_class = $codebase->properties->getDeclaringClassForProperty($fq_class_name . '::$' . $prop_name, \true, $statements_analyzer); if ($declaring_property_class === null) { return \false; } \Psalm\Internal\Analyzer\Statements\Expression\Fetch\AtomicPropertyFetchAnalyzer::checkPropertyDeprecation($prop_name, $declaring_property_class, $stmt, $statements_analyzer); $class_storage = $codebase->classlike_storage_provider->get($declaring_property_class); $property = $class_storage->properties[$prop_name]; if (!$property->is_static) { if ($context->inside_isset) { return \true; } if ($context->inside_assignment) { IssueBuffer::maybeAdd(new UndefinedPropertyAssignment('Static property ' . $property_id . ' is not defined', new CodeLocation($statements_analyzer->getSource(), $stmt), $property_id), $statements_analyzer->getSuppressedIssues()); } else { IssueBuffer::maybeAdd(new UndefinedPropertyFetch('Static property ' . $property_id . ' is not defined', new CodeLocation($statements_analyzer->getSource(), $stmt), $property_id), $statements_analyzer->getSuppressedIssues()); } return \true; } if (ClassLikeAnalyzer::checkPropertyVisibility($property_id, $context, $statements_analyzer, new CodeLocation($statements_analyzer->getSource(), $stmt), $statements_analyzer->getSuppressedIssues()) === \false) { return \false; } $declaring_property_id = strtolower($declaring_property_class) . '::$' . $prop_name; if ($codebase->alter_code) { $moved_class = $codebase->classlikes->handleClassLikeReferenceInMigration($codebase, $statements_analyzer, $stmt->class, $fq_class_name, $context->calling_method_id); if (!$moved_class) { foreach ($codebase->property_transforms as $original_pattern => $transformation) { if ($declaring_property_id === $original_pattern) { [$old_declaring_fq_class_name] = explode('::$', $declaring_property_id); [$new_fq_class_name, $new_property_name] = explode('::$', $transformation); $file_manipulations = []; if (strtolower($new_fq_class_name) !== $old_declaring_fq_class_name) { $file_manipulations[] = new FileManipulation((int) $stmt->class->getAttribute('startFilePos'), (int) $stmt->class->getAttribute('endFilePos') + 1, Type::getStringFromFQCLN($new_fq_class_name, $statements_analyzer->getNamespace(), $statements_analyzer->getAliasedClassesFlipped(), null)); } $file_manipulations[] = new FileManipulation((int) $stmt->name->getAttribute('startFilePos'), (int) $stmt->name->getAttribute('endFilePos') + 1, '$' . $new_property_name); FileManipulationBuffer::add($statements_analyzer->getFilePath(), $file_manipulations); } } } return \true; } if ($var_id) { if ($property->type) { $context->vars_in_scope[$var_id] = TypeExpander::expandUnion($codebase, $property->type, $class_storage->name, $class_storage->name, $class_storage->parent_class); } else { $context->vars_in_scope[$var_id] = Type::getMixed(); } $stmt_type = $context->vars_in_scope[$var_id]; \Psalm\Internal\Analyzer\Statements\Expression\Fetch\AtomicPropertyFetchAnalyzer::processUnspecialTaints($statements_analyzer, $stmt, $stmt_type, $property_id, \false, [], []); $context->vars_in_scope[$var_id] = $stmt_type; $statements_analyzer->node_data->setType($stmt, $stmt_type); if ($codebase->store_node_types && !$context->collect_initializations && !$context->collect_mutations) { $codebase->analyzer->addNodeType($statements_analyzer->getFilePath(), $stmt->name, $stmt_type->getId()); } } else { $statements_analyzer->node_data->setType($stmt, Type::getMixed()); } return \true; } private static function analyzeVariableStaticPropertyFetch(StatementsAnalyzer $statements_analyzer, PhpParser\Node\Expr $stmt_class, PhpParser\Node\Expr\StaticPropertyFetch $stmt, Context $context) : void { $was_inside_general_use = $context->inside_general_use; $context->inside_general_use = \true; ExpressionAnalyzer::analyze($statements_analyzer, $stmt_class, $context); $context->inside_general_use = $was_inside_general_use; $stmt_class_type = $statements_analyzer->node_data->getType($stmt_class) ?? Type::getMixed(); $old_data_provider = $statements_analyzer->node_data; $stmt_type = null; $codebase = $statements_analyzer->getCodebase(); foreach ($stmt_class_type->getAtomicTypes() as $class_atomic_type) { $statements_analyzer->node_data = clone $statements_analyzer->node_data; $string_type = $class_atomic_type instanceof TClassString && $class_atomic_type->as_type !== null ? $class_atomic_type->as_type->value : ($class_atomic_type instanceof TLiteralString ? $class_atomic_type->value : null); if ($string_type) { $new_stmt_name = new VirtualFullyQualified($string_type, $stmt_class->getAttributes()); $fake_static_property = new VirtualStaticPropertyFetch($new_stmt_name, $stmt->name, $stmt->getAttributes()); self::analyze($statements_analyzer, $fake_static_property, $context); $fake_stmt_type = $statements_analyzer->node_data->getType($fake_static_property) ?? Type::getMixed(); } else { $fake_var_name = '__fake_var_' . (string) $stmt->getAttribute('startFilePos'); $fake_var = new VirtualVariable($fake_var_name, $stmt_class->getAttributes()); $context->vars_in_scope['$' . $fake_var_name] = new Union([$class_atomic_type]); $fake_instance_property = new VirtualPropertyFetch($fake_var, $stmt->name, $stmt->getAttributes()); \Psalm\Internal\Analyzer\Statements\Expression\Fetch\InstancePropertyFetchAnalyzer::analyze($statements_analyzer, $fake_instance_property, $context, \false, \true); $fake_stmt_type = $statements_analyzer->node_data->getType($fake_instance_property) ?? Type::getMixed(); } $stmt_type = $stmt_type ? Type::combineUnionTypes($stmt_type, $fake_stmt_type, $codebase) : $fake_stmt_type; $statements_analyzer->node_data = $old_data_provider; } $statements_analyzer->node_data->setType($stmt, $stmt_type); } } $invalid_fetch_types $invalid_fetch_types * @psalm-suppress ComplexMethod Unavoidably complex method. */ public static function analyze(StatementsAnalyzer $statements_analyzer, PhpParser\Node\Expr\PropertyFetch $stmt, Context $context, bool $in_assignment, ?string $var_id, ?string $stmt_var_id, Union $stmt_var_type, Atomic $lhs_type_part, string $prop_name, bool &$has_valid_fetch_type, array &$invalid_fetch_types, bool $is_static_access = \false) : void { if ($lhs_type_part instanceof TNull) { return; } if ($lhs_type_part instanceof TMixed) { $statements_analyzer->node_data->setType($stmt, Type::getMixed()); return; } if ($lhs_type_part instanceof TFalse && $stmt_var_type->ignore_falsable_issues) { return; } if (!$lhs_type_part instanceof TNamedObject && !$lhs_type_part instanceof TObject) { $invalid_fetch_types[] = (string) $lhs_type_part; return; } if ($lhs_type_part instanceof TObjectWithProperties) { if (!isset($lhs_type_part->properties[$prop_name])) { return; } $has_valid_fetch_type = \true; $stmt_type = $statements_analyzer->node_data->getType($stmt); $statements_analyzer->node_data->setType($stmt, Type::combineUnionTypes(TypeExpander::expandUnion($statements_analyzer->getCodebase(), $lhs_type_part->properties[$prop_name], null, null, null, \true, \true, \false, \true, \false, \true), $stmt_type)); return; } $intersection_types = []; if (!$lhs_type_part instanceof TObject) { $intersection_types = $lhs_type_part->getIntersectionTypes(); } // stdClass and SimpleXMLElement are special cases where we cannot infer the return types // but we don't want to throw an error // Hack has a similar issue: https://github.com/facebook/hhvm/issues/5164 if ($lhs_type_part instanceof TObject || in_array(strtolower($lhs_type_part->value), Config::getInstance()->getUniversalObjectCrates(), \true) && $intersection_types === []) { $has_valid_fetch_type = \true; $statements_analyzer->node_data->setType($stmt, Type::getMixed()); return; } if (ExpressionAnalyzer::isMock($lhs_type_part->value)) { $statements_analyzer->node_data->setType($stmt, Type::getMixed()); return; } $fq_class_name = $lhs_type_part->value; $override_property_visibility = \false; $has_magic_getter = \false; $class_exists = \false; $codebase = $statements_analyzer->getCodebase(); if (!$codebase->classExists($lhs_type_part->value) && !$codebase->classlikes->enumExists($lhs_type_part->value)) { $interface_exists = \false; self::handleNonExistentClass($statements_analyzer, $codebase, $stmt, $lhs_type_part, $intersection_types, $class_exists, $interface_exists, $fq_class_name, $override_property_visibility); if (!$class_exists && !$interface_exists) { return; } } else { $class_exists = \true; } $class_storage = $codebase->classlike_storage_provider->get($fq_class_name); $config = $statements_analyzer->getProjectAnalyzer()->getConfig(); $property_id = $fq_class_name . '::$' . $prop_name; if ($class_storage->is_enum || in_array('UnitEnum', $codebase->getParentInterfaces($fq_class_name))) { if ($prop_name === 'value' && !$class_storage->is_enum) { $has_valid_fetch_type = \true; $statements_analyzer->node_data->setType($stmt, new Union([new TString(), new TInt()])); } elseif ($prop_name === 'value' && $class_storage->enum_type !== null && $class_storage->enum_cases) { $has_valid_fetch_type = \true; self::handleEnumValue($statements_analyzer, $stmt, $stmt_var_type, $class_storage); } elseif ($prop_name === 'name') { $has_valid_fetch_type = \true; self::handleEnumName($statements_analyzer, $stmt, $stmt_var_type, $class_storage); } else { self::handleNonExistentProperty($statements_analyzer, $codebase, $stmt, $context, $config, $class_storage, $prop_name, $lhs_type_part, $fq_class_name, $property_id, $in_assignment, $stmt_var_id, $has_magic_getter, $var_id, $has_valid_fetch_type); } return; } $naive_property_exists = $codebase->properties->propertyExists($property_id, !$in_assignment, $statements_analyzer, $context, $codebase->collect_locations ? new CodeLocation($statements_analyzer->getSource(), $stmt) : null); // add method before changing fq_class_name $get_method_id = new MethodIdentifier($fq_class_name, '__get'); if (!$naive_property_exists) { if ($class_storage->namedMixins) { foreach ($class_storage->namedMixins as $mixin) { $new_property_id = $mixin->value . '::$' . $prop_name; try { $new_class_storage = $codebase->classlike_storage_provider->get($mixin->value); } catch (InvalidArgumentException $e) { $new_class_storage = null; } if ($new_class_storage && ($codebase->properties->propertyExists($new_property_id, !$in_assignment, $statements_analyzer, $context, $codebase->collect_locations ? new CodeLocation($statements_analyzer->getSource(), $stmt) : null) || isset($new_class_storage->pseudo_property_get_types['$' . $prop_name]))) { $fq_class_name = $mixin->value; $lhs_type_part = $mixin; $class_storage = $new_class_storage; if (!isset($new_class_storage->pseudo_property_get_types['$' . $prop_name])) { $naive_property_exists = \true; } $property_id = $new_property_id; } } } elseif ($intersection_types !== [] && !$class_storage->final) { foreach ($intersection_types as $intersection_type) { self::analyze($statements_analyzer, $stmt, $context, $in_assignment, $var_id, $stmt_var_id, $stmt_var_type, $intersection_type, $prop_name, $has_valid_fetch_type, $invalid_fetch_types, $is_static_access); if ($has_valid_fetch_type) { return; } } } } $declaring_property_class = $codebase->properties->getDeclaringClassForProperty($property_id, \true, $statements_analyzer); if (self::propertyFetchCanBeAnalyzed($statements_analyzer, $codebase, $stmt, $context, $fq_class_name, $prop_name, $lhs_type_part, $property_id, $has_magic_getter, $stmt_var_id, $naive_property_exists, $override_property_visibility, $class_exists, $declaring_property_class, $class_storage, $get_method_id, $in_assignment) === \false) { return; } if ($codebase->store_node_types && !$context->collect_initializations && !$context->collect_mutations) { $codebase->analyzer->addNodeReference($statements_analyzer->getFilePath(), $stmt->name, $property_id); } if (!$naive_property_exists && $fq_class_name !== $context->self && $context->self && $codebase->classlikes->classExtends($fq_class_name, $context->self) && $codebase->properties->propertyExists($context->self . '::$' . $prop_name, \true, $statements_analyzer, $context, $codebase->collect_locations ? new CodeLocation($statements_analyzer->getSource(), $stmt) : null)) { $property_id = $context->self . '::$' . $prop_name; } elseif (!$naive_property_exists || !$is_static_access && $codebase->properties->hasStorage($property_id) && $codebase->properties->getStorage($property_id)->is_static) { self::handleNonExistentProperty($statements_analyzer, $codebase, $stmt, $context, $config, $class_storage, $prop_name, $lhs_type_part, $declaring_property_class, $property_id, $in_assignment, $stmt_var_id, $has_magic_getter, $var_id, $has_valid_fetch_type); return; } if (!$override_property_visibility) { if (ClassLikeAnalyzer::checkPropertyVisibility($property_id, $context, $statements_analyzer, new CodeLocation($statements_analyzer->getSource(), $stmt), $statements_analyzer->getSuppressedIssues()) === \false) { return; } } // FIXME: the following line look superfluous, but removing it makes // Psalm\Tests\PropertyTypeTest::testValidCode with data set "callInParentContext" // fail $declaring_property_class = $codebase->properties->getDeclaringClassForProperty($property_id, \true, $statements_analyzer); if ($declaring_property_class === null) { return; } if ($codebase->properties_to_rename) { $declaring_property_id = strtolower($declaring_property_class) . '::$' . $prop_name; foreach ($codebase->properties_to_rename as $original_property_id => $new_property_name) { if ($declaring_property_id === $original_property_id) { $file_manipulations = [new FileManipulation((int) $stmt->name->getAttribute('startFilePos'), (int) $stmt->name->getAttribute('endFilePos') + 1, $new_property_name)]; FileManipulationBuffer::add($statements_analyzer->getFilePath(), $file_manipulations); } } } $declaring_class_storage = $codebase->classlike_storage_provider->get($declaring_property_class); if (isset($declaring_class_storage->properties[$prop_name])) { self::checkPropertyDeprecation($prop_name, $declaring_property_class, $stmt, $statements_analyzer); $property_storage = $declaring_class_storage->properties[$prop_name]; if ($context->self && !NamespaceAnalyzer::isWithinAny($context->self, $property_storage->internal)) { IssueBuffer::maybeAdd(new InternalProperty($property_id . ' is internal to ' . InternalClass::listToPhrase($property_storage->internal) . ' but called from ' . $context->self, new CodeLocation($statements_analyzer->getSource(), $stmt), $property_id), $statements_analyzer->getSuppressedIssues()); } if ($context->inside_unset) { InstancePropertyAssignmentAnalyzer::trackPropertyImpurity($statements_analyzer, $stmt, $property_id, $property_storage, $declaring_class_storage, $context); } } $class_property_type = self::getClassPropertyType($statements_analyzer, $codebase, $config, $context, $stmt, $class_storage, $declaring_class_storage, $property_id, $fq_class_name, $prop_name, $lhs_type_part); if (!$context->collect_mutations && !$context->collect_initializations && !($class_storage->external_mutation_free && $class_property_type->allow_mutations)) { if ($context->pure) { IssueBuffer::maybeAdd(new ImpurePropertyFetch('Cannot access a property on a mutable object from a pure context', new CodeLocation($statements_analyzer, $stmt)), $statements_analyzer->getSuppressedIssues()); } elseif ($statements_analyzer->getSource() instanceof FunctionLikeAnalyzer && $statements_analyzer->getSource()->track_mutations) { $statements_analyzer->getSource()->inferred_impure = \true; } } self::processTaints($statements_analyzer, $stmt, $class_property_type, $property_id, $class_storage, $in_assignment, $context); if ($class_storage->mutation_free) { $class_property_type = $class_property_type->setProperties(['has_mutations' => \false]); } $stmt_type = $statements_analyzer->node_data->getType($stmt); $has_valid_fetch_type = \true; $statements_analyzer->node_data->setType($stmt, Type::combineUnionTypes($class_property_type, $stmt_type)); } /** * @param PropertyFetch|StaticPropertyFetch $stmt */ public static function checkPropertyDeprecation(string $prop_name, string $declaring_property_class, PhpParser\Node\Expr $stmt, StatementsAnalyzer $statements_analyzer) : void { $property_id = $declaring_property_class . '::$' . $prop_name; $codebase = $statements_analyzer->getCodebase(); $declaring_class_storage = $codebase->classlike_storage_provider->get($declaring_property_class); if (isset($declaring_class_storage->properties[$prop_name])) { $property_storage = $declaring_class_storage->properties[$prop_name]; if ($property_storage->deprecated) { IssueBuffer::maybeAdd(new DeprecatedProperty($property_id . ' is marked deprecated', new CodeLocation($statements_analyzer->getSource(), $stmt), $property_id), $statements_analyzer->getSuppressedIssues()); } } } private static function propertyFetchCanBeAnalyzed(StatementsAnalyzer $statements_analyzer, Codebase $codebase, PhpParser\Node\Expr\PropertyFetch $stmt, Context $context, string $fq_class_name, string $prop_name, TNamedObject $lhs_type_part, string &$property_id, bool &$has_magic_getter, ?string $stmt_var_id, bool $naive_property_exists, bool $override_property_visibility, bool $class_exists, ?string $declaring_property_class, ClassLikeStorage $class_storage, MethodIdentifier $get_method_id, bool $in_assignment) : bool { if ((!$naive_property_exists || $stmt_var_id !== '$this' && $fq_class_name !== $context->self && ClassLikeAnalyzer::checkPropertyVisibility($property_id, $context, $statements_analyzer, new CodeLocation($statements_analyzer->getSource(), $stmt), $statements_analyzer->getSuppressedIssues(), \false) !== \true) && $codebase->methods->methodExists($get_method_id, $context->calling_method_id, $codebase->collect_locations ? new CodeLocation($statements_analyzer->getSource(), $stmt) : null, !$context->collect_initializations && !$context->collect_mutations ? $statements_analyzer : null, $statements_analyzer->getFilePath())) { $has_magic_getter = \true; if (isset($class_storage->pseudo_property_get_types['$' . $prop_name])) { $stmt_type = TypeExpander::expandUnion($codebase, $class_storage->pseudo_property_get_types['$' . $prop_name], $class_storage->name, $class_storage->name, $class_storage->parent_class); if (count($template_types = $class_storage->getClassTemplateTypes()) !== 0) { if (!$lhs_type_part instanceof TGenericObject) { $lhs_type_part = new TGenericObject($lhs_type_part->value, $template_types); } $stmt_type = self::localizePropertyType($codebase, $stmt_type, $lhs_type_part, $class_storage, $declaring_property_class ? $codebase->classlike_storage_provider->get($declaring_property_class) : $class_storage); } self::processTaints($statements_analyzer, $stmt, $stmt_type, $property_id, $class_storage, $in_assignment, $context); $statements_analyzer->node_data->setType($stmt, $stmt_type); return \false; } $old_data_provider = $statements_analyzer->node_data; $statements_analyzer->node_data = clone $statements_analyzer->node_data; $statements_analyzer->node_data->setType($stmt->var, new Union([$lhs_type_part])); $fake_method_call = new VirtualMethodCall($stmt->var, new VirtualIdentifier('__get', $stmt->name->getAttributes()), [new VirtualArg(new VirtualString($prop_name, $stmt->name->getAttributes()))]); $suppressed_issues = $statements_analyzer->getSuppressedIssues(); if (!in_array('InternalMethod', $suppressed_issues, \true)) { $statements_analyzer->addSuppressedIssues(['InternalMethod']); } MethodCallAnalyzer::analyze($statements_analyzer, $fake_method_call, $context, \false); if (!in_array('InternalMethod', $suppressed_issues, \true)) { $statements_analyzer->removeSuppressedIssues(['InternalMethod']); } $fake_method_call_type = $statements_analyzer->node_data->getType($fake_method_call); $statements_analyzer->node_data = $old_data_provider; if ($fake_method_call_type) { $stmt_type = $statements_analyzer->node_data->getType($stmt); $statements_analyzer->node_data->setType($stmt, Type::combineUnionTypes($fake_method_call_type, $stmt_type)); } else { $statements_analyzer->node_data->setType($stmt, Type::getMixed()); } /* * If we have an explicit list of all allowed magic properties on the class, and we're * not in that list, fall through */ if (!$class_storage->hasSealedProperties($codebase->config) && !$override_property_visibility) { return \false; } if (!$class_exists) { $property_id = $lhs_type_part->value . '::$' . $prop_name; IssueBuffer::maybeAdd(new UndefinedMagicPropertyFetch('Magic instance property ' . $property_id . ' is not defined', new CodeLocation($statements_analyzer->getSource(), $stmt), $property_id), $statements_analyzer->getSuppressedIssues()); return \false; } } return \true; } public static function localizePropertyType(Codebase $codebase, Union $class_property_type, TGenericObject $lhs_type_part, ClassLikeStorage $property_class_storage, ClassLikeStorage $property_declaring_class_storage) : Union { $template_types = CallAnalyzer::getTemplateTypesForCall($codebase, $property_declaring_class_storage, $property_declaring_class_storage->name, $property_class_storage, $property_class_storage->template_types ?: []); $extended_types = $property_class_storage->template_extended_params; if ($template_types) { if ($property_class_storage->template_types) { foreach ($lhs_type_part->type_params as $param_offset => $lhs_param_type) { $i = -1; foreach ($property_class_storage->template_types as $calling_param_name => $_) { $i++; if ($i === $param_offset) { $template_types[$calling_param_name][$property_class_storage->name] = $lhs_param_type; break; } } } } foreach ($template_types as $type_name => $_) { if (isset($extended_types[$property_declaring_class_storage->name][$type_name])) { $mapped_type = $extended_types[$property_declaring_class_storage->name][$type_name]; foreach ($mapped_type->getAtomicTypes() as $mapped_type_atomic) { if (!$mapped_type_atomic instanceof TTemplateParam) { continue; } $param_name = $mapped_type_atomic->param_name; $position = \false; if (isset($property_class_storage->template_types[$param_name])) { $position = array_search($param_name, array_keys($property_class_storage->template_types), \true); } if ($position !== \false && isset($lhs_type_part->type_params[$position])) { $template_types[$type_name][$property_declaring_class_storage->name] = $lhs_type_part->type_params[$position]; } } } } $class_property_type = TemplateInferredTypeReplacer::replace($class_property_type, new TemplateResult([], $template_types), $codebase); } return $class_property_type; } public static function processTaints(StatementsAnalyzer $statements_analyzer, PhpParser\Node\Expr\PropertyFetch $stmt, Union &$type, string $property_id, ClassLikeStorage $class_storage, bool $in_assignment, ?Context $context = null) : void { if (!$statements_analyzer->data_flow_graph) { return; } $data_flow_graph = $statements_analyzer->data_flow_graph; $added_taints = []; $removed_taints = []; if ($context) { $codebase = $statements_analyzer->getCodebase(); $event = new AddRemoveTaintsEvent($stmt, $context, $statements_analyzer, $codebase); $added_taints = $codebase->config->eventDispatcher->dispatchAddTaints($event); $removed_taints = $codebase->config->eventDispatcher->dispatchRemoveTaints($event); } if ($class_storage->specialize_instance) { $var_id = ExpressionIdentifier::getExtendedVarId($stmt->var, null, $statements_analyzer); $var_property_id = ExpressionIdentifier::getExtendedVarId($stmt, null, $statements_analyzer); if ($var_id) { $var_type = $statements_analyzer->node_data->getType($stmt->var); if ($statements_analyzer->data_flow_graph instanceof TaintFlowGraph && $var_type && in_array('TaintedInput', $statements_analyzer->getSuppressedIssues())) { $statements_analyzer->node_data->setType($stmt->var, $var_type->setParentNodes([])); return; } $var_location = new CodeLocation($statements_analyzer->getSource(), $stmt->var); $property_location = new CodeLocation($statements_analyzer->getSource(), $stmt); $var_node = DataFlowNode::getForAssignment($var_id, $var_location); $data_flow_graph->addNode($var_node); $property_node = DataFlowNode::getForAssignment($var_property_id ?: $var_id . '->$property', $property_location); $data_flow_graph->addNode($property_node); $data_flow_graph->addPath($var_node, $property_node, 'property-fetch' . ($stmt->name instanceof PhpParser\Node\Identifier ? '-' . $stmt->name : ''), $added_taints, $removed_taints); if ($var_type && $var_type->parent_nodes) { foreach ($var_type->parent_nodes as $parent_node) { $data_flow_graph->addPath($parent_node, $var_node, '=', $added_taints, $removed_taints); } } $type = $type->setParentNodes([$property_node->id => $property_node], \true); } } else { self::processUnspecialTaints($statements_analyzer, $stmt, $type, $property_id, $in_assignment, $added_taints, $removed_taints); } } /** * @param ?array $added_taints * @param ?array $removed_taints */ public static function processUnspecialTaints(StatementsAnalyzer $statements_analyzer, PhpParser\Node\Expr $stmt, Union &$type, string $property_id, bool $in_assignment, ?array $added_taints, ?array $removed_taints) : void { if (!$statements_analyzer->data_flow_graph) { return; } $data_flow_graph = $statements_analyzer->data_flow_graph; $var_property_id = ExpressionIdentifier::getExtendedVarId($stmt, null, $statements_analyzer); $property_location = new CodeLocation($statements_analyzer->getSource(), $stmt); $localized_property_node = DataFlowNode::getForAssignment($var_property_id ?: $property_id, $property_location); $data_flow_graph->addNode($localized_property_node); $property_node = new DataFlowNode($property_id, $property_id, null, null); $data_flow_graph->addNode($property_node); if ($in_assignment) { $data_flow_graph->addPath($localized_property_node, $property_node, 'property-assignment', $added_taints, $removed_taints); } else { $data_flow_graph->addPath($property_node, $localized_property_node, 'property-fetch', $added_taints, $removed_taints); } $type = $type->setParentNodes([$localized_property_node->id => $localized_property_node], \true); } private static function handleEnumName(StatementsAnalyzer $statements_analyzer, PropertyFetch $stmt, Union $stmt_var_type, ClassLikeStorage $class_storage) : void { $relevant_enum_cases = array_filter($stmt_var_type->getAtomicTypes(), static fn(Atomic $type): bool => $type instanceof TEnumCase); $relevant_enum_case_names = array_map(static fn(TEnumCase $enumCase): string => $enumCase->case_name, $relevant_enum_cases); if (empty($relevant_enum_case_names)) { $relevant_enum_case_names = array_keys($class_storage->enum_cases); } $statements_analyzer->node_data->setType($stmt, empty($relevant_enum_case_names) ? Type::getNonEmptyString() : new Union(array_map(static fn(string $name): TString => Type::getAtomicStringFromLiteral($name), $relevant_enum_case_names))); } private static function handleEnumValue(StatementsAnalyzer $statements_analyzer, PropertyFetch $stmt, Union $stmt_var_type, ClassLikeStorage $class_storage) : void { $relevant_enum_cases = array_filter($stmt_var_type->getAtomicTypes(), static fn(Atomic $type): bool => $type instanceof TEnumCase); $relevant_enum_case_names = array_map(static fn(TEnumCase $enumCase): string => $enumCase->case_name, $relevant_enum_cases); $enum_cases = $class_storage->enum_cases; if (!empty($relevant_enum_case_names)) { // If we have a known subset of enum cases, include only those $enum_cases = array_filter($enum_cases, static fn(string $key) => in_array($key, $relevant_enum_case_names, \true), ARRAY_FILTER_USE_KEY); } $case_values = []; foreach ($enum_cases as $enum_case) { $case_value = $enum_case->getValue($statements_analyzer->getCodebase()->classlikes); if (is_string($case_value)) { $case_values[] = Type::getAtomicStringFromLiteral($case_value); } elseif (is_int($case_value)) { $case_values[] = new TLiteralInt($case_value); } else { // this should never happen $case_values[] = new TMixed(); } } /** @psalm-suppress ArgumentTypeCoercion */ $statements_analyzer->node_data->setType($stmt, new Union($case_values)); } private static function handleUndefinedProperty(Context $context, StatementsAnalyzer $statements_analyzer, PhpParser\Node\Expr\PropertyFetch $stmt, ?string $stmt_var_id, string $property_id, bool $has_magic_getter, ?string $var_id) : void { if ($context->inside_isset || $context->collect_initializations) { if ($context->pure) { IssueBuffer::maybeAdd(new ImpurePropertyFetch('Cannot access a property on a mutable object from a pure context', new CodeLocation($statements_analyzer, $stmt)), $statements_analyzer->getSuppressedIssues()); } elseif ($context->inside_isset && $statements_analyzer->getSource() instanceof FunctionLikeAnalyzer && $statements_analyzer->getSource()->track_mutations) { $statements_analyzer->getSource()->inferred_impure = \true; } return; } if ($stmt_var_id === '$this') { IssueBuffer::maybeAdd(new UndefinedThisPropertyFetch('Instance property ' . $property_id . ' is not defined', new CodeLocation($statements_analyzer->getSource(), $stmt), $property_id), $statements_analyzer->getSuppressedIssues()); } else { if ($has_magic_getter) { IssueBuffer::maybeAdd(new UndefinedMagicPropertyFetch('Magic instance property ' . $property_id . ' is not defined', new CodeLocation($statements_analyzer->getSource(), $stmt), $property_id), $statements_analyzer->getSuppressedIssues()); } else { IssueBuffer::maybeAdd(new UndefinedPropertyFetch('Instance property ' . $property_id . ' is not defined', new CodeLocation($statements_analyzer->getSource(), $stmt), $property_id), $statements_analyzer->getSuppressedIssues()); } } $stmt_type = Type::getMixed(); $statements_analyzer->node_data->setType($stmt, $stmt_type); if ($var_id) { $context->vars_in_scope[$var_id] = $stmt_type; } } /** * @param array $intersection_types */ private static function handleNonExistentClass(StatementsAnalyzer $statements_analyzer, Codebase $codebase, PhpParser\Node\Expr\PropertyFetch $stmt, TNamedObject $lhs_type_part, array $intersection_types, bool &$class_exists, bool &$interface_exists, string &$fq_class_name, bool &$override_property_visibility) : void { if ($codebase->interfaceExists($lhs_type_part->value)) { $interface_exists = \true; $interface_storage = $codebase->classlike_storage_provider->get($lhs_type_part->value); $override_property_visibility = $interface_storage->override_property_visibility; $intersects_with_enum = \false; foreach ($intersection_types as $intersection_type) { if ($intersection_type instanceof TNamedObject && $codebase->classExists($intersection_type->value)) { $fq_class_name = $intersection_type->value; $class_exists = \true; return; } if ($intersection_type instanceof TNamedObject && (in_array($intersection_type->value, ['UnitEnum', 'BackedEnum'], \true) || in_array('UnitEnum', $codebase->getParentInterfaces($intersection_type->value)))) { $intersects_with_enum = \true; } } if (!$class_exists && !in_array($fq_class_name, ['UnitEnum', 'BackedEnum'], \true) && !in_array('UnitEnum', $codebase->getParentInterfaces($fq_class_name)) && !$intersects_with_enum) { if (IssueBuffer::accepts(new NoInterfaceProperties('Interfaces cannot have properties', new CodeLocation($statements_analyzer->getSource(), $stmt), $lhs_type_part->value), $statements_analyzer->getSuppressedIssues())) { return; } if (!$codebase->methodExists($fq_class_name . '::__set')) { return; } } } if (!$class_exists && !$interface_exists) { if ($lhs_type_part->from_docblock) { IssueBuffer::maybeAdd(new UndefinedDocblockClass('Cannot get properties of undefined docblock class ' . $lhs_type_part->value, new CodeLocation($statements_analyzer->getSource(), $stmt), $lhs_type_part->value), $statements_analyzer->getSuppressedIssues()); } else { IssueBuffer::maybeAdd(new UndefinedClass('Cannot get properties of undefined class ' . $lhs_type_part->value, new CodeLocation($statements_analyzer->getSource(), $stmt), $lhs_type_part->value), $statements_analyzer->getSuppressedIssues()); } } } private static function handleNonExistentProperty(StatementsAnalyzer $statements_analyzer, Codebase $codebase, PhpParser\Node\Expr\PropertyFetch $stmt, Context $context, Config $config, ClassLikeStorage $class_storage, string $prop_name, TNamedObject $lhs_type_part, ?string $declaring_property_class, string $property_id, bool $in_assignment, ?string $stmt_var_id, bool $has_magic_getter, ?string $var_id, bool &$has_valid_fetch_type) : void { if (($config->use_phpdoc_property_without_magic_or_parent || $class_storage->hasAttributeIncludingParents('AllowDynamicProperties', $codebase)) && isset($class_storage->pseudo_property_get_types['$' . $prop_name])) { $stmt_type = $class_storage->pseudo_property_get_types['$' . $prop_name]; if (count($template_types = $class_storage->getClassTemplateTypes()) !== 0) { if (!$lhs_type_part instanceof TGenericObject) { $lhs_type_part = new TGenericObject($lhs_type_part->value, $template_types); } $stmt_type = self::localizePropertyType($codebase, $stmt_type, $lhs_type_part, $class_storage, $declaring_property_class ? $codebase->classlike_storage_provider->get($declaring_property_class) : $class_storage); } self::processTaints($statements_analyzer, $stmt, $stmt_type, $property_id, $class_storage, $in_assignment, $context); $has_valid_fetch_type = \true; $statements_analyzer->node_data->setType($stmt, $stmt_type); return; } if ($class_storage->is_interface) { return; } self::handleUndefinedProperty($context, $statements_analyzer, $stmt, $stmt_var_id, $property_id, $has_magic_getter, $var_id); } private static function getClassPropertyType(StatementsAnalyzer $statements_analyzer, Codebase $codebase, Config $config, Context $context, PhpParser\Node\Expr\PropertyFetch $stmt, ClassLikeStorage $class_storage, ClassLikeStorage $declaring_class_storage, string $property_id, string $fq_class_name, string $prop_name, TNamedObject $lhs_type_part) : Union { $class_property_type = $codebase->properties->getPropertyType($property_id, \false, $statements_analyzer, $context); if (!$class_property_type) { if ($declaring_class_storage->location && $config->isInProjectDirs($declaring_class_storage->location->file_path)) { IssueBuffer::maybeAdd(new MissingPropertyType('Property ' . $fq_class_name . '::$' . $prop_name . ' does not have a declared type', new CodeLocation($statements_analyzer->getSource(), $stmt), $property_id), $statements_analyzer->getSuppressedIssues()); } $class_property_type = Type::getMixed(); } else { $class_property_type = TypeExpander::expandUnion($codebase, $class_property_type, $declaring_class_storage->name, $declaring_class_storage->name, $declaring_class_storage->parent_class); if (count($template_types = $declaring_class_storage->getClassTemplateTypes()) !== 0) { if (!$lhs_type_part instanceof TGenericObject) { $lhs_type_part = new TGenericObject($lhs_type_part->value, $template_types); } $class_property_type = self::localizePropertyType($codebase, $class_property_type, $lhs_type_part, $class_storage, $declaring_class_storage); } elseif ($lhs_type_part instanceof TGenericObject) { $class_property_type = self::localizePropertyType($codebase, $class_property_type, $lhs_type_part, $class_storage, $declaring_class_storage); } } return $class_property_type; } } name->toString(); switch (strtolower($const_name)) { case 'null': $statements_analyzer->node_data->setType($stmt, Type::getNull()); break; case 'false': // false is a subtype of bool $statements_analyzer->node_data->setType($stmt, Type::getFalse()); break; case 'true': $statements_analyzer->node_data->setType($stmt, Type::getTrue()); break; case 'stdin': $statements_analyzer->node_data->setType($stmt, Type::getResource()); break; default: $const_type = self::getConstType($statements_analyzer, $const_name, $stmt->name instanceof PhpParser\Node\Name\FullyQualified, $context); $codebase = $statements_analyzer->getCodebase(); $aliased_constants = $statements_analyzer->getAliases()->constants; if (isset($aliased_constants[$const_name])) { $fq_const_name = $aliased_constants[$const_name]; } elseif ($stmt->name instanceof PhpParser\Node\Name\FullyQualified) { $fq_const_name = $const_name; } else { $fq_const_name = Type::getFQCLNFromString($const_name, $statements_analyzer->getAliases()); } $codebase->analyzer->addNodeReference($statements_analyzer->getFilePath(), $stmt, $const_type ? $fq_const_name : '*' . ($stmt->name instanceof PhpParser\Node\Name\FullyQualified ? '\\' : $statements_analyzer->getNamespace() . '-') . $const_name); if ($const_type) { $statements_analyzer->node_data->setType($stmt, $const_type); } elseif ($context->check_consts) { IssueBuffer::maybeAdd(new UndefinedConstant('Const ' . $const_name . ' is not defined', new CodeLocation($statements_analyzer->getSource(), $stmt)), $statements_analyzer->getSuppressedIssues()); } } } public static function getGlobalConstType(Codebase $codebase, string $fq_const_name, string $const_name) : ?Union { if ($const_name === 'STDERR' || $const_name === 'STDOUT' || $const_name === 'STDIN') { return Type::getResource(); } if ($fq_const_name) { $stubbed_const_type = $codebase->getStubbedConstantType($fq_const_name); if ($stubbed_const_type) { return $stubbed_const_type; } } $stubbed_const_type = $codebase->getStubbedConstantType($const_name); if ($stubbed_const_type) { return $stubbed_const_type; } $predefined_constants = $codebase->config->getPredefinedConstants(); if ($fq_const_name && array_key_exists($fq_const_name, $predefined_constants) || array_key_exists($const_name, $predefined_constants)) { switch ($const_name) { case 'PHP_VERSION': case 'DIRECTORY_SEPARATOR': case 'PATH_SEPARATOR': case 'PHP_EOL': return Type::getNonEmptyString(); case 'PEAR_EXTENSION_DIR': case 'PEAR_INSTALL_DIR': case 'PHP_BINARY': case 'PHP_BINDIR': case 'PHP_CONFIG_FILE_PATH': case 'PHP_CONFIG_FILE_SCAN_DIR': case 'PHP_DATADIR': case 'PHP_EXTENSION_DIR': case 'PHP_EXTRA_VERSION': case 'PHP_LIBDIR': case 'PHP_LOCALSTATEDIR': case 'PHP_MANDIR': case 'PHP_OS': case 'PHP_OS_FAMILY': case 'PHP_PREFIX': case 'PHP_SAPI': case 'PHP_SYSCONFDIR': return Type::getString(); case 'PHP_MAJOR_VERSION': case 'PHP_MINOR_VERSION': case 'PHP_RELEASE_VERSION': case 'PHP_DEBUG': case 'PHP_FLOAT_DIG': case 'PHP_INT_MIN': case 'PHP_ZTS': return Type::getInt(); case 'PHP_INT_MAX': case 'PHP_INT_SIZE': case 'PHP_MAXPATHLEN': case 'PHP_VERSION_ID': return Type::getIntRange(1, null); case 'PHP_FLOAT_EPSILON': case 'PHP_FLOAT_MAX': case 'PHP_FLOAT_MIN': return Type::getFloat(); } if ($fq_const_name && array_key_exists($fq_const_name, $predefined_constants)) { return ClassLikeAnalyzer::getTypeFromValue($predefined_constants[$fq_const_name]); } return ClassLikeAnalyzer::getTypeFromValue($predefined_constants[$const_name]); } return null; } public static function getConstType(StatementsAnalyzer $statements_analyzer, string $const_name, bool $is_fully_qualified, ?Context $context) : ?Union { $aliased_constants = $statements_analyzer->getAliases()->constants; if (isset($aliased_constants[$const_name])) { $fq_const_name = $aliased_constants[$const_name]; } elseif ($is_fully_qualified) { $fq_const_name = $const_name; } else { $fq_const_name = Type::getFQCLNFromString($const_name, $statements_analyzer->getAliases()); } if ($fq_const_name) { $const_name_parts = explode('\\', $fq_const_name); $const_name = array_pop($const_name_parts); $namespace_name = implode('\\', $const_name_parts); $namespace_constants = NamespaceAnalyzer::getConstantsForNamespace($namespace_name, ReflectionProperty::IS_PUBLIC); if (isset($namespace_constants[$const_name])) { return $namespace_constants[$const_name]; } } if ($context && $context->hasVariable($fq_const_name)) { return $context->vars_in_scope[$fq_const_name]; } $file_path = $statements_analyzer->getRootFilePath(); $codebase = $statements_analyzer->getCodebase(); $file_storage_provider = $codebase->file_storage_provider; $file_storage = $file_storage_provider->get($file_path); if (isset($file_storage->declaring_constants[$const_name])) { $constant_file_path = $file_storage->declaring_constants[$const_name]; return $file_storage_provider->get($constant_file_path)->constants[$const_name]; } if (isset($file_storage->declaring_constants[$fq_const_name])) { $constant_file_path = $file_storage->declaring_constants[$fq_const_name]; return $file_storage_provider->get($constant_file_path)->constants[$fq_const_name]; } return self::getGlobalConstType($codebase, $fq_const_name, $const_name) ?? self::getGlobalConstType($codebase, $const_name, $const_name); } public static function setConstType(StatementsAnalyzer $statements_analyzer, string $const_name, Union $const_type, Context $context) : void { $context->vars_in_scope[$const_name] = $const_type; $context->constants[$const_name] = $const_type; $source = $statements_analyzer->getSource(); if ($source instanceof NamespaceAnalyzer) { $source->setConstType($const_name, $const_type); } } public static function getConstName(PhpParser\Node\Expr $first_arg_value, NodeDataProvider $type_provider, Codebase $codebase, Aliases $aliases) : ?string { $const_name = null; if ($first_arg_value instanceof PhpParser\Node\Scalar\String_) { $const_name = $first_arg_value->value; } elseif ($first_arg_type = $type_provider->getType($first_arg_value)) { if ($first_arg_type->isSingleStringLiteral()) { $const_name = $first_arg_type->getSingleStringLiteral()->value; } } else { $simple_type = SimpleTypeInferer::infer($codebase, $type_provider, $first_arg_value, $aliases); if ($simple_type && $simple_type->isSingleStringLiteral()) { $const_name = $simple_type->getSingleStringLiteral()->value; } } return $const_name; } public static function analyzeConstAssignment(StatementsAnalyzer $statements_analyzer, PhpParser\Node\Stmt\Const_ $stmt, Context $context) : void { foreach ($stmt->consts as $const) { ExpressionAnalyzer::analyze($statements_analyzer, $const->value, $context); self::setConstType($statements_analyzer, $const->name->name, $statements_analyzer->node_data->getType($const->value) ?? Type::getMixed(), $context); } } } var, $statements_analyzer->getFQCLN(), $statements_analyzer); if ($stmt->dim) { $was_inside_general_use = $context->inside_general_use; $context->inside_general_use = \true; $was_inside_unset = $context->inside_unset; $context->inside_unset = \false; $was_inside_isset = $context->inside_isset; $context->inside_isset = \false; if (ExpressionAnalyzer::analyze($statements_analyzer, $stmt->dim, $context) === \false) { $context->inside_isset = $was_inside_isset; $context->inside_unset = $was_inside_unset; $context->inside_general_use = $was_inside_general_use; return \false; } $context->inside_isset = $was_inside_isset; $context->inside_unset = $was_inside_unset; $context->inside_general_use = $was_inside_general_use; } $keyed_array_var_id = ExpressionIdentifier::getExtendedVarId($stmt, $statements_analyzer->getFQCLN(), $statements_analyzer); $dim_var_id = null; $new_offset_type = null; if ($stmt->dim) { $used_key_type = $statements_analyzer->node_data->getType($stmt->dim) ?? Type::getMixed(); $dim_var_id = ExpressionIdentifier::getExtendedVarId($stmt->dim, $statements_analyzer->getFQCLN(), $statements_analyzer); } else { $used_key_type = Type::getInt(); } if (ExpressionAnalyzer::analyze($statements_analyzer, $stmt->var, $context) === \false) { return \false; } $stmt_var_type = $statements_analyzer->node_data->getType($stmt->var); $codebase = $statements_analyzer->getCodebase(); if ($keyed_array_var_id !== null && $context->hasVariable($keyed_array_var_id) && !$context->vars_in_scope[$keyed_array_var_id]->possibly_undefined && $stmt_var_type && !$stmt_var_type->hasClassStringMap()) { $stmt_type = $context->vars_in_scope[$keyed_array_var_id]; self::taintArrayFetch($statements_analyzer, $stmt->var, $keyed_array_var_id, $stmt_type, $used_key_type, $context); if ($stmt->dim && $statements_analyzer->node_data->getType($stmt->dim)) { $statements_analyzer->node_data->setType($stmt->dim, $used_key_type); } $statements_analyzer->node_data->setType($stmt, $stmt_type); return \true; } $can_store_result = \false; if ($stmt_var_type) { if ($stmt_var_type->isNull()) { if (!$context->inside_isset) { IssueBuffer::maybeAdd(new NullArrayAccess('Cannot access array value on null variable ' . $extended_var_id, new CodeLocation($statements_analyzer->getSource(), $stmt)), $statements_analyzer->getSuppressedIssues()); } $stmt_type = $statements_analyzer->node_data->getType($stmt); $statements_analyzer->node_data->setType($stmt, Type::combineUnionTypes($stmt_type, Type::getNull())); return \true; } $stmt_type = self::getArrayAccessTypeGivenOffset($statements_analyzer, $stmt, $stmt_var_type, $used_key_type, \false, $extended_var_id, $context, null); if ($stmt->dim && $stmt_var_type->hasArray()) { $array_type = $stmt_var_type->getArray(); if ($array_type instanceof TClassStringMap) { $array_value_type = Type::getMixed(); } elseif ($array_type instanceof TArray) { $array_value_type = $array_type->type_params[1]; } else { $array_value_type = $array_type->getGenericValueType(); } if ($context->inside_assignment || !$array_value_type->isMixed()) { $can_store_result = \true; } } if ($context->inside_isset && !$stmt_type->hasMixed()) { $stmt_type = Type::combineUnionTypes($stmt_type, Type::getNull()); } $statements_analyzer->node_data->setType($stmt, $stmt_type); if ($context->inside_isset && $stmt->dim && ($stmt_dim_type = $statements_analyzer->node_data->getType($stmt->dim)) && $stmt_var_type->hasArray() && ($stmt->var instanceof PhpParser\Node\Expr\ClassConstFetch || $stmt->var instanceof PhpParser\Node\Expr\ConstFetch)) { /** * @var TArray|TKeyedArray */ $array_type = $stmt_var_type->getArray(); if ($array_type instanceof TArray) { $const_array_key_type = $array_type->type_params[0]; } else { $const_array_key_type = $array_type->getGenericKeyType(); } if ($dim_var_id && !$const_array_key_type->hasMixed() && !$stmt_dim_type->hasMixed()) { $new_offset_type = $stmt_dim_type->getBuilder(); $const_array_key_atomic_types = $const_array_key_type->getAtomicTypes(); foreach ($new_offset_type->getAtomicTypes() as $offset_key => $offset_atomic_type) { if ($offset_atomic_type instanceof TString || $offset_atomic_type instanceof TInt) { if (!isset($const_array_key_atomic_types[$offset_key]) && !UnionTypeComparator::isContainedBy($codebase, new Union([$offset_atomic_type]), $const_array_key_type)) { $new_offset_type->removeType($offset_key); } } elseif (!UnionTypeComparator::isContainedBy($codebase, $const_array_key_type, new Union([$offset_atomic_type]))) { $new_offset_type->removeType($offset_key); } } $new_offset_type = $new_offset_type->freeze(); } } } if ($keyed_array_var_id !== null && $context->hasVariable($keyed_array_var_id) && (!($stmt_type = $statements_analyzer->node_data->getType($stmt)) || $stmt_type->isVanillaMixed())) { $statements_analyzer->node_data->setType($stmt, $context->vars_in_scope[$keyed_array_var_id]); } if (!($stmt_type = $statements_analyzer->node_data->getType($stmt))) { $stmt_type = Type::getMixed(); } else { if ($stmt_type->possibly_undefined && !$context->inside_isset && !$context->inside_unset && ($stmt_var_type && !$stmt_var_type->hasMixed())) { if (IssueBuffer::accepts(new PossiblyUndefinedArrayOffset('Possibly undefined array key ' . $keyed_array_var_id . ' on ' . $stmt_var_type->getId(), new CodeLocation($statements_analyzer->getSource(), $stmt)), $statements_analyzer->getSuppressedIssues())) { $stmt_type = $stmt_type->getBuilder()->addType(new TNull())->freeze(); } } elseif ($stmt_type->possibly_undefined) { $stmt_type = $stmt_type->getBuilder()->addType(new TNull())->freeze(); } $stmt_type = $stmt_type->setPossiblyUndefined(\false); } if ($context->inside_isset && $dim_var_id && $new_offset_type && !$new_offset_type->isUnionEmpty()) { $context->vars_in_scope[$dim_var_id] = $new_offset_type; } self::taintArrayFetch($statements_analyzer, $stmt->var, $keyed_array_var_id, $stmt_type, $used_key_type, $context); $statements_analyzer->node_data->setType($stmt, $stmt_type); if ($stmt->dim && $statements_analyzer->node_data->getType($stmt->dim)) { $statements_analyzer->node_data->setType($stmt->dim, $used_key_type); } if ($keyed_array_var_id && !$context->inside_isset && $can_store_result) { $context->vars_in_scope[$keyed_array_var_id] = $stmt_type; $context->vars_possibly_in_scope[$keyed_array_var_id] = \true; // reference the variable too $context->hasVariable($keyed_array_var_id); } return \true; } /** * Used to create a path between a variable $foo and $foo["a"] */ public static function taintArrayFetch(StatementsAnalyzer $statements_analyzer, PhpParser\Node\Expr $var, ?string $keyed_array_var_id, Union &$stmt_type, Union &$offset_type, ?Context $context = null) : void { if ($statements_analyzer->data_flow_graph && ($stmt_var_type = $statements_analyzer->node_data->getType($var)) && $stmt_var_type->parent_nodes) { if ($statements_analyzer->data_flow_graph instanceof TaintFlowGraph && in_array('TaintedInput', $statements_analyzer->getSuppressedIssues())) { $statements_analyzer->node_data->setType($var, $stmt_var_type->setParentNodes([])); return; } $added_taints = []; $removed_taints = []; if ($context) { $codebase = $statements_analyzer->getCodebase(); $event = new AddRemoveTaintsEvent($var, $context, $statements_analyzer, $codebase); $added_taints = $codebase->config->eventDispatcher->dispatchAddTaints($event); $removed_taints = $codebase->config->eventDispatcher->dispatchRemoveTaints($event); } $var_location = new CodeLocation($statements_analyzer->getSource(), $var); $new_parent_node = DataFlowNode::getForAssignment($keyed_array_var_id ?: 'arrayvalue-fetch', $var_location); $array_key_node = null; $statements_analyzer->data_flow_graph->addNode($new_parent_node); $dim_value = $offset_type->isSingleStringLiteral() ? $offset_type->getSingleStringLiteral()->value : ($offset_type->isSingleIntLiteral() ? $offset_type->getSingleIntLiteral()->value : null); if ($keyed_array_var_id === null && $dim_value === null) { $array_key_node = DataFlowNode::getForAssignment('arraykey-fetch', $var_location); $statements_analyzer->data_flow_graph->addNode($array_key_node); } foreach ($stmt_var_type->parent_nodes as $parent_node) { $statements_analyzer->data_flow_graph->addPath($parent_node, $new_parent_node, 'arrayvalue-fetch' . ($dim_value !== null ? '-\'' . $dim_value . '\'' : ''), $added_taints, $removed_taints); if ($stmt_type->by_ref) { $statements_analyzer->data_flow_graph->addPath($new_parent_node, $parent_node, 'arrayvalue-assignment' . ($dim_value !== null ? '-\'' . $dim_value . '\'' : ''), $added_taints, $removed_taints); } if ($array_key_node) { $statements_analyzer->data_flow_graph->addPath($parent_node, $array_key_node, 'arraykey-fetch', $added_taints, $removed_taints); } } $stmt_type = $stmt_type->setParentNodes([$new_parent_node->id => $new_parent_node]); if ($array_key_node) { $offset_type = $offset_type->setParentNodes([$array_key_node->id => $array_key_node]); } } } /** * @psalm-suppress ComplexMethod to be refactored. * Good type/bad type behaviour could be mutualised with ArrayAnalyzer */ public static function getArrayAccessTypeGivenOffset(StatementsAnalyzer $statements_analyzer, PhpParser\Node\Expr\ArrayDimFetch $stmt, Union &$array_type, Union &$offset_type_original, bool $in_assignment, ?string $extended_var_id, Context $context, ?PhpParser\Node\Expr $assign_value = null, ?Union $replacement_type = null) : Union { $offset_type = $offset_type_original->getBuilder(); $codebase = $statements_analyzer->getCodebase(); $has_array_access = \false; $non_array_types = []; $has_valid_expected_offset = \false; $expected_offset_types = []; $key_values = []; if ($codebase->store_node_types && !$context->collect_initializations && !$context->collect_mutations) { $codebase->analyzer->addNodeType($statements_analyzer->getFilePath(), $stmt->var, $array_type->getId()); } if ($stmt->dim instanceof PhpParser\Node\Scalar\String_) { $value_type = Type::getAtomicStringFromLiteral($stmt->dim->value); if ($value_type instanceof TLiteralString) { $key_values[] = $value_type; } } elseif ($stmt->dim instanceof PhpParser\Node\Scalar\LNumber) { $key_values[] = new TLiteralInt($stmt->dim->value); } elseif ($stmt->dim && ($stmt_dim_type = $statements_analyzer->node_data->getType($stmt->dim))) { $string_literals = $stmt_dim_type->getLiteralStrings(); $int_literals = $stmt_dim_type->getLiteralInts(); $all_atomic_types = $stmt_dim_type->getAtomicTypes(); if (count($string_literals) + count($int_literals) === count($all_atomic_types)) { foreach ($string_literals as $string_literal) { $key_values[] = $string_literal; } foreach ($int_literals as $int_literal) { $key_values[] = $int_literal; } } } $array_access_type = null; if ($offset_type->isNull()) { IssueBuffer::maybeAdd(new NullArrayOffset('Cannot access value on variable ' . $extended_var_id . ' using null offset', new CodeLocation($statements_analyzer->getSource(), $stmt)), $statements_analyzer->getSuppressedIssues()); if ($in_assignment) { $offset_type->removeType('null'); $offset_type->addType(Type::getAtomicStringFromLiteral('')); } } if ($offset_type->isNullable() && !$context->inside_isset) { if (!$offset_type->ignore_nullable_issues) { IssueBuffer::maybeAdd(new PossiblyNullArrayOffset('Cannot access value on variable ' . $extended_var_id . ' using possibly null offset ' . $offset_type, new CodeLocation($statements_analyzer->getSource(), $stmt->var)), $statements_analyzer->getSuppressedIssues()); } if ($in_assignment) { $offset_type->removeType('null'); if (!$offset_type->ignore_nullable_issues) { $offset_type->addType(Type::getAtomicStringFromLiteral('')); } } } if ($array_type->isArray()) { $has_valid_absolute_offset = self::checkArrayOffsetType($offset_type, $offset_type->getAtomicTypes(), $codebase); if ($has_valid_absolute_offset === \false) { //we didn't find a single type that could be valid $expected_offset_types[] = 'array-key'; } } else { //on not-arrays, the type is considered valid $has_valid_absolute_offset = \true; } $types = $array_type->getAtomicTypes(); $changed = \false; foreach ($types as $type_string => $type) { if ($type instanceof TList) { $type = $type->getKeyedArray(); } $original_type_real = $type; $original_type = $type; if ($type instanceof TMixed || $type instanceof TTemplateParam || $type instanceof TNever) { if (!$type instanceof TTemplateParam || $type->as->isMixed() || !$type->as->isSingle()) { $array_access_type = self::handleMixedArrayAccess($context, $statements_analyzer, $codebase, $in_assignment, $extended_var_id, $stmt, $array_access_type, $type); $has_valid_expected_offset = \true; continue; } $type = $type->as->getSingleAtomic(); $original_type = $type; } if ($type instanceof TNull) { if ($array_type->ignore_nullable_issues) { continue; } if ($in_assignment) { if ($replacement_type) { $array_access_type = Type::combineUnionTypes($array_access_type, $replacement_type); } else { IssueBuffer::maybeAdd(new PossiblyNullArrayAssignment('Cannot access array value on possibly null variable ' . $extended_var_id . ' of type ' . $array_type, new CodeLocation($statements_analyzer->getSource(), $stmt)), $statements_analyzer->getSuppressedIssues()); $array_access_type = new Union([new TNever()]); } } else { if (!$context->inside_isset && !MethodCallAnalyzer::hasNullsafe($stmt->var)) { IssueBuffer::maybeAdd(new PossiblyNullArrayAccess('Cannot access array value on possibly null variable ' . $extended_var_id . ' of type ' . $array_type, new CodeLocation($statements_analyzer->getSource(), $stmt)), $statements_analyzer->getSuppressedIssues()); } $array_access_type = Type::combineUnionTypes($array_access_type, Type::getNull()); } continue; } if ($type instanceof TArray || $type instanceof TKeyedArray || $type instanceof TClassStringMap) { self::handleArrayAccessOnArray($in_assignment, $type, $key_values, $array_type->hasMixed(), $stmt, $replacement_type, $offset_type, $original_type_real, $codebase, $extended_var_id, $context, $statements_analyzer, $expected_offset_types, $array_access_type, $has_array_access, $has_valid_expected_offset); if ($type !== $original_type) { $changed = \true; unset($types[$type_string]); $types[$type->getKey()] = $type; } continue; } if ($type instanceof TString) { self::handleArrayAccessOnString($statements_analyzer, $codebase, $stmt, $in_assignment, $context, $replacement_type, $type, $offset_type, $expected_offset_types, $array_access_type, $has_valid_expected_offset); continue; } if (!$context->collect_initializations && !$context->collect_mutations && $statements_analyzer->getFilePath() === $statements_analyzer->getRootFilePath() && (!($parent_source = $statements_analyzer->getSource()) instanceof FunctionLikeAnalyzer || !$parent_source->getSource() instanceof TraitAnalyzer)) { $codebase->analyzer->incrementNonMixedCount($statements_analyzer->getFilePath()); } if ($type instanceof TFalse && $array_type->ignore_falsable_issues) { continue; } if ($type instanceof TNamedObject) { self::handleArrayAccessOnNamedObject($statements_analyzer, $stmt, $type, $context, $in_assignment, $assign_value, $array_access_type, $has_array_access); } elseif (!$array_type->hasMixed()) { $non_array_types[] = (string) $type; } } if ($changed) { $array_type = $array_type->getBuilder()->setTypes($types)->freeze(); } if ($non_array_types) { if ($has_array_access) { if ($in_assignment) { IssueBuffer::maybeAdd(new PossiblyInvalidArrayAssignment('Cannot access array value on non-array variable ' . $extended_var_id . ' of type ' . $non_array_types[0], new CodeLocation($statements_analyzer->getSource(), $stmt)), $statements_analyzer->getSuppressedIssues()); } elseif (!$context->inside_isset) { IssueBuffer::maybeAdd(new PossiblyInvalidArrayAccess('Cannot access array value on non-array variable ' . $extended_var_id . ' of type ' . $non_array_types[0], new CodeLocation($statements_analyzer->getSource(), $stmt)), $statements_analyzer->getSuppressedIssues()); } } else { if ($in_assignment) { IssueBuffer::maybeAdd(new InvalidArrayAssignment('Cannot access array value on non-array variable ' . $extended_var_id . ' of type ' . $non_array_types[0], new CodeLocation($statements_analyzer->getSource(), $stmt)), $statements_analyzer->getSuppressedIssues()); } else { IssueBuffer::maybeAdd(new InvalidArrayAccess('Cannot access array value on non-array variable ' . $extended_var_id . ' of type ' . $non_array_types[0], new CodeLocation($statements_analyzer->getSource(), $stmt)), $statements_analyzer->getSuppressedIssues()); } $array_access_type = Type::getMixed(); } } if ($offset_type->hasMixed()) { if (!$context->collect_initializations && !$context->collect_mutations && $statements_analyzer->getFilePath() === $statements_analyzer->getRootFilePath() && (!($parent_source = $statements_analyzer->getSource()) instanceof FunctionLikeAnalyzer || !$parent_source->getSource() instanceof TraitAnalyzer)) { $codebase->analyzer->incrementMixedCount($statements_analyzer->getFilePath()); } IssueBuffer::maybeAdd(new MixedArrayOffset('Cannot access value on variable ' . $extended_var_id . ' using mixed offset', new CodeLocation($statements_analyzer->getSource(), $stmt)), $statements_analyzer->getSuppressedIssues()); } else { if (!$context->collect_initializations && !$context->collect_mutations && $statements_analyzer->getFilePath() === $statements_analyzer->getRootFilePath() && (!($parent_source = $statements_analyzer->getSource()) instanceof FunctionLikeAnalyzer || !$parent_source->getSource() instanceof TraitAnalyzer)) { $codebase->analyzer->incrementNonMixedCount($statements_analyzer->getFilePath()); } if ($expected_offset_types) { $invalid_offset_type = $expected_offset_types[0]; $used_offset = 'using a ' . $offset_type->getId() . ' offset'; if ($key_values) { $used_offset = "using offset value of '" . implode('|', array_map(static fn(Atomic $atomic_type) => $atomic_type->value, $key_values)) . "'"; } if ($has_valid_expected_offset && $has_valid_absolute_offset && $context->inside_isset) { // do nothing } elseif ($has_valid_expected_offset && $has_valid_absolute_offset) { if (!$context->inside_unset) { IssueBuffer::maybeAdd(new PossiblyInvalidArrayOffset('Cannot access value on variable ' . $extended_var_id . ' ' . $used_offset . ', expecting ' . $invalid_offset_type, new CodeLocation($statements_analyzer->getSource(), $stmt)), $statements_analyzer->getSuppressedIssues()); } } else { $good_types = []; $bad_types = []; foreach ($offset_type->getAtomicTypes() as $atomic_key_type) { if (!$atomic_key_type instanceof TString && !$atomic_key_type instanceof TInt && !$atomic_key_type instanceof TArrayKey && !$atomic_key_type instanceof TMixed && !$atomic_key_type instanceof TTemplateParam && !($atomic_key_type instanceof TObjectWithProperties && isset($atomic_key_type->methods['__tostring']))) { $bad_types[] = $atomic_key_type; if ($atomic_key_type instanceof TFalse) { $good_types[] = new TLiteralInt(0); } elseif ($atomic_key_type instanceof TTrue) { $good_types[] = new TLiteralInt(1); } elseif ($atomic_key_type instanceof TBool) { $good_types[] = new TLiteralInt(0); $good_types[] = new TLiteralInt(1); } elseif ($atomic_key_type instanceof TLiteralFloat) { $good_types[] = new TLiteralInt((int) $atomic_key_type->value); } elseif ($atomic_key_type instanceof TFloat) { $good_types[] = new TInt(); } else { $good_types[] = new TArrayKey(); } } } if ($bad_types && $good_types) { $offset_type->substitute(TypeCombiner::combine($bad_types, $codebase), TypeCombiner::combine($good_types, $codebase)); } IssueBuffer::maybeAdd(new InvalidArrayOffset('Cannot access value on variable ' . $extended_var_id . ' ' . $used_offset . ', expecting ' . $invalid_offset_type, new CodeLocation($statements_analyzer->getSource(), $stmt)), $statements_analyzer->getSuppressedIssues()); } } } $offset_type_original = $offset_type->freeze(); if ($array_access_type === null) { // shouldn’t happen, but don’t crash return Type::getMixed(); } if ($array_type->by_ref) { return $array_access_type->setByRef(\true); } return $array_access_type; } private static function checkLiteralIntArrayOffset(MutableUnion $offset_type, Union $expected_offset_type, ?string $extended_var_id, PhpParser\Node\Expr\ArrayDimFetch $stmt, Context $context, StatementsAnalyzer $statements_analyzer) : void { if ($context->inside_isset || $context->inside_unset) { return; } if ($offset_type->hasLiteralInt()) { $found_match = \false; foreach ($offset_type->getAtomicTypes() as $offset_type_part) { if ($extended_var_id && $offset_type_part instanceof TLiteralInt && isset($context->vars_in_scope[$extended_var_id . '[' . $offset_type_part->value . ']']) && !$context->vars_in_scope[$extended_var_id . '[' . $offset_type_part->value . ']']->possibly_undefined) { $found_match = \true; break; } } if (!$found_match) { IssueBuffer::maybeAdd(new PossiblyUndefinedIntArrayOffset('Possibly undefined array offset \'' . $offset_type->getId() . '\' ' . 'is risky given expected type \'' . $expected_offset_type->getId() . '\'.' . ' Consider using isset beforehand.', new CodeLocation($statements_analyzer->getSource(), $stmt)), $statements_analyzer->getSuppressedIssues()); } } } private static function checkLiteralStringArrayOffset(MutableUnion $offset_type, Union $expected_offset_type, ?string $extended_var_id, PhpParser\Node\Expr\ArrayDimFetch $stmt, Context $context, StatementsAnalyzer $statements_analyzer) : void { if ($context->inside_isset || $context->inside_unset) { return; } if ($offset_type->hasLiteralString() && !$expected_offset_type->hasLiteralClassString()) { $found_match = \false; foreach ($offset_type->getAtomicTypes() as $offset_type_part) { if ($extended_var_id === null || !$offset_type_part instanceof TLiteralString) { continue; } $string_to_int = ArrayAnalyzer::getLiteralArrayKeyInt($offset_type_part->value); $literal_access = $string_to_int === \false ? '\'' . $offset_type_part->value . '\'' : $string_to_int; if (isset($context->vars_in_scope[$extended_var_id . '[' . $literal_access . ']']) && !$context->vars_in_scope[$extended_var_id . '[' . $literal_access . ']']->possibly_undefined) { $found_match = \true; break; } } if (!$found_match) { IssueBuffer::maybeAdd(new PossiblyUndefinedStringArrayOffset('Possibly undefined array offset \'' . $offset_type->getId() . '\' ' . 'is risky given expected type \'' . $expected_offset_type->getId() . '\'.' . ' Consider using isset beforehand.', new CodeLocation($statements_analyzer->getSource(), $stmt)), $statements_analyzer->getSuppressedIssues()); } } } public static function replaceOffsetTypeWithInts(Union $offset_type) : Union { $offset_type = $offset_type->getBuilder(); $offset_types = $offset_type->getAtomicTypes(); foreach ($offset_types as $key => $offset_type_part) { if ($offset_type_part instanceof TLiteralString) { $string_to_int = ArrayAnalyzer::getLiteralArrayKeyInt($offset_type_part->value); if ($string_to_int !== \false) { $offset_type->addType(new TLiteralInt($string_to_int)); $offset_type->removeType($key); } } elseif ($offset_type_part instanceof TBool) { if ($offset_type_part instanceof TFalse) { if (!$offset_type->ignore_falsable_issues) { $offset_type->addType(new TLiteralInt(0)); $offset_type->removeType($key); } } elseif ($offset_type_part instanceof TTrue) { $offset_type->addType(new TLiteralInt(1)); $offset_type->removeType($key); } else { $offset_type->addType(new TLiteralInt(0)); $offset_type->addType(new TLiteralInt(1)); $offset_type->removeType($key); } } } return $offset_type->freeze(); } /** * @param TMixed|TTemplateParam|TNever $type */ public static function handleMixedArrayAccess(Context $context, StatementsAnalyzer $statements_analyzer, Codebase $codebase, bool $in_assignment, ?string $extended_var_id, PhpParser\Node\Expr\ArrayDimFetch $stmt, ?Union $array_access_type, Atomic $type) : Union { if (!$context->collect_initializations && !$context->collect_mutations && $statements_analyzer->getFilePath() === $statements_analyzer->getRootFilePath() && (!($parent_source = $statements_analyzer->getSource()) instanceof FunctionLikeAnalyzer || !$parent_source->getSource() instanceof TraitAnalyzer)) { $codebase->analyzer->incrementMixedCount($statements_analyzer->getFilePath()); } if (!$context->inside_isset) { if ($in_assignment) { IssueBuffer::maybeAdd(new MixedArrayAssignment('Cannot access array value on mixed variable ' . $extended_var_id, new CodeLocation($statements_analyzer->getSource(), $stmt)), $statements_analyzer->getSuppressedIssues()); } else { IssueBuffer::maybeAdd(new MixedArrayAccess('Cannot access array value on mixed variable ' . $extended_var_id, new CodeLocation($statements_analyzer->getSource(), $stmt)), $statements_analyzer->getSuppressedIssues()); } } if (($data_flow_graph = $statements_analyzer->data_flow_graph) && $data_flow_graph instanceof VariableUseGraph && ($stmt_var_type = $statements_analyzer->node_data->getType($stmt->var))) { if ($stmt_var_type->parent_nodes) { $var_location = new CodeLocation($statements_analyzer->getSource(), $stmt->var); $new_parent_node = DataFlowNode::getForAssignment('mixed-var-array-access', $var_location); $data_flow_graph->addNode($new_parent_node); foreach ($stmt_var_type->parent_nodes as $parent_node) { $data_flow_graph->addPath($parent_node, $new_parent_node, '='); $data_flow_graph->addPath($parent_node, new DataFlowNode('variable-use', 'variable use', null), 'variable-use'); } $statements_analyzer->node_data->setType($stmt->var, $stmt_var_type->setParentNodes([$new_parent_node->id => $new_parent_node])); } } return Type::combineUnionTypes($array_access_type, Type::getMixed($type instanceof TNever)); } /** * @param list $expected_offset_types * @param TArray|TKeyedArray|TClassStringMap $type * @param-out TArray|TKeyedArray|TClassStringMap $type * @param list $key_values * @psalm-suppress ConflictingReferenceConstraint Ignore */ private static function handleArrayAccessOnArray(bool $in_assignment, Atomic &$type, array &$key_values, bool $hasMixed, PhpParser\Node\Expr\ArrayDimFetch $stmt, ?Union $replacement_type, MutableUnion $offset_type, Atomic $original_type, Codebase $codebase, ?string $extended_var_id, Context $context, StatementsAnalyzer $statements_analyzer, array &$expected_offset_types, ?Union &$array_access_type, bool &$has_array_access, bool &$has_valid_offset) : void { $has_array_access = \true; if ($in_assignment) { if ($type instanceof TArray) { $from_empty_array = $type->isEmptyArray(); if (count($key_values) === 1) { $single_atomic = $key_values[0]; $from_mixed_array = $type->type_params[1]->isMixed(); // ok, type becomes an TKeyedArray $type = new TKeyedArray([$single_atomic->value => $from_mixed_array ? Type::getMixed() : Type::getNever()], $single_atomic instanceof TLiteralClassString ? [$single_atomic->value => \true] : null, $from_empty_array ? null : $type->type_params); } elseif (!$stmt->dim && $from_empty_array && $replacement_type) { $type = new TKeyedArray([$replacement_type], null, null, \true); return; } } elseif ($type instanceof TKeyedArray && $type->fallback_params !== null && $type->fallback_params[1]->isMixed() && count($key_values) === 1) { $properties = $type->properties; $properties[$key_values[0]->value] = Type::getMixed(); $type = $type->setProperties($properties); } } $offset_type = self::replaceOffsetTypeWithInts($offset_type->freeze())->getBuilder(); if ($type instanceof TKeyedArray && $type->is_list && ($in_assignment && $stmt->dim || $original_type instanceof TTemplateParam || !$offset_type->isInt())) { $temp = $type->getGenericArrayType(); self::handleArrayAccessOnTArray($statements_analyzer, $codebase, $context, $stmt, $hasMixed, $extended_var_id, $temp, $offset_type, $in_assignment, $expected_offset_types, $array_access_type, $original_type, $has_valid_offset); } elseif ($type instanceof TArray) { self::handleArrayAccessOnTArray($statements_analyzer, $codebase, $context, $stmt, $hasMixed, $extended_var_id, $type, $offset_type, $in_assignment, $expected_offset_types, $array_access_type, $original_type, $has_valid_offset); } elseif ($type instanceof TClassStringMap) { self::handleArrayAccessOnClassStringMap($codebase, $type, $offset_type, $replacement_type, $array_access_type); } else { self::handleArrayAccessOnKeyedArray($statements_analyzer, $codebase, $key_values, $replacement_type, $array_access_type, $in_assignment, $stmt, $offset_type, $extended_var_id, $context, $type, $hasMixed, $expected_offset_types, $has_valid_offset); } if ($context->inside_isset) { $offset_type->ignore_isset = \true; } } /** * @param list $expected_offset_types * @param-out TArray $type */ private static function handleArrayAccessOnTArray(StatementsAnalyzer $statements_analyzer, Codebase $codebase, Context $context, PhpParser\Node\Expr\ArrayDimFetch $stmt, bool $hasMixed, ?string $extended_var_id, TArray &$type, MutableUnion $offset_type, bool $in_assignment, array &$expected_offset_types, ?Union &$array_access_type, Atomic $original_type, bool &$has_valid_offset) : void { // if we're assigning to an empty array with a key offset, refashion that array if ($in_assignment) { if ($type->isEmptyArray()) { $type = $type->setTypeParams([$offset_type->isMixed() ? Type::getArrayKey() : $offset_type->freeze(), $type->type_params[1]]); } } elseif (!$type->isEmptyArray()) { $expected_offset_type = $type->type_params[0]->hasMixed() ? new Union([new TArrayKey()]) : $type->type_params[0]; $templated_offset_type = null; foreach ($offset_type->getAtomicTypes() as $offset_atomic_type) { if ($offset_atomic_type instanceof TTemplateParam) { $templated_offset_type = $offset_atomic_type; } } $union_comparison_results = new TypeComparisonResult(); if ($original_type instanceof TTemplateParam && $templated_offset_type) { foreach ($templated_offset_type->as->getAtomicTypes() as $offset_as) { if ($offset_as instanceof TTemplateKeyOf && $offset_as->param_name === $original_type->param_name && $offset_as->defining_class === $original_type->defining_class) { $type = $type->setTypeParams([$type->type_params[0], new Union([new TTemplateIndexedAccess($offset_as->param_name, $templated_offset_type->param_name, $offset_as->defining_class)])]); $has_valid_offset = \true; } } } else { $offset_type_contained_by_expected = UnionTypeComparator::isContainedBy($codebase, $offset_type->freeze(), $expected_offset_type, \true, $offset_type->ignore_falsable_issues, $union_comparison_results); if ($codebase->config->ensure_array_string_offsets_exist && $offset_type_contained_by_expected) { //we already know we found a match, so if the array is non-empty and the key is a literal, //then no need to check for PossiblyUndefinedStringArrayOffset if (!$type instanceof TNonEmptyArray || !$type->type_params[0]->isSingleStringLiteral()) { self::checkLiteralStringArrayOffset($offset_type, $expected_offset_type, $extended_var_id, $stmt, $context, $statements_analyzer); } } if ($codebase->config->ensure_array_int_offsets_exist && $offset_type_contained_by_expected) { self::checkLiteralIntArrayOffset($offset_type, $expected_offset_type, $extended_var_id, $stmt, $context, $statements_analyzer); } if (!$offset_type_contained_by_expected && !$union_comparison_results->type_coerced_from_scalar || $union_comparison_results->to_string_cast) { if ($union_comparison_results->type_coerced_from_mixed && !$offset_type->isMixed()) { IssueBuffer::maybeAdd(new MixedArrayTypeCoercion('Coercion from array offset type \'' . $offset_type->getId() . '\' ' . 'to the expected type \'' . $expected_offset_type->getId() . '\'', new CodeLocation($statements_analyzer->getSource(), $stmt)), $statements_analyzer->getSuppressedIssues()); } else { $expected_offset_types[] = $expected_offset_type->getId(); } if (UnionTypeComparator::canExpressionTypesBeIdentical($codebase, $offset_type->freeze(), $expected_offset_type)) { $has_valid_offset = \true; } } else { $has_valid_offset = \true; } } } if (!$stmt->dim) { if ($type instanceof TNonEmptyArray) { if ($type->count !== null) { $type = $type->setCount($type->count + 1); } } else { $type = new TNonEmptyArray($type->type_params, null, null, 'non-empty-array', $type->from_docblock); } } $array_access_type = Type::combineUnionTypes($array_access_type, $type->type_params[1]); if ($array_access_type->isNever() && !$hasMixed && !$in_assignment && !$context->inside_isset) { IssueBuffer::maybeAdd(new EmptyArrayAccess('Cannot access value on empty array variable ' . $extended_var_id, new CodeLocation($statements_analyzer->getSource(), $stmt)), $statements_analyzer->getSuppressedIssues()); if (!IssueBuffer::isRecording()) { $array_access_type = Type::getMixed(\true); } } } private static function handleArrayAccessOnClassStringMap(Codebase $codebase, TClassStringMap &$type, MutableUnion $offset_type, ?Union $replacement_type, ?Union &$array_access_type) : void { $offset_type_parts = array_values($offset_type->getAtomicTypes()); foreach ($offset_type_parts as $offset_type_part) { if ($offset_type_part instanceof TClassString) { if ($offset_type_part instanceof TTemplateParamClass) { $template_result_get = new TemplateResult([], [$type->param_name => ['class-string-map' => new Union([new TTemplateParam($offset_type_part->param_name, $offset_type_part->as_type ? new Union([$offset_type_part->as_type]) : Type::getObject(), $offset_type_part->defining_class)])]]); $template_result_set = new TemplateResult([], [$offset_type_part->param_name => [$offset_type_part->defining_class => new Union([new TTemplateParam($type->param_name, $type->as_type ? new Union([$type->as_type]) : Type::getObject(), 'class-string-map')])]]); } else { $template_result_get = new TemplateResult([], [$type->param_name => ['class-string-map' => new Union([$offset_type_part->as_type ?: new TObject()])]]); $template_result_set = new TemplateResult([], []); } $expected_value_param_get = TemplateInferredTypeReplacer::replace($type->value_param, $template_result_get, $codebase); if ($replacement_type) { $replacement_type = TemplateInferredTypeReplacer::replace($replacement_type, $template_result_set, $codebase); $type = new TClassStringMap($type->param_name, $type->as_type, Type::combineUnionTypes($replacement_type, $type->value_param, $codebase)); } $array_access_type = Type::combineUnionTypes($array_access_type, $expected_value_param_get, $codebase); } } } /** * @param list $expected_offset_types * @param list $key_values * @param-out TArray|TKeyedArray $type */ private static function handleArrayAccessOnKeyedArray(StatementsAnalyzer $statements_analyzer, Codebase $codebase, array &$key_values, ?Union $replacement_type, ?Union &$array_access_type, bool $in_assignment, PhpParser\Node\Expr\ArrayDimFetch $stmt, MutableUnion $offset_type, ?string $extended_var_id, Context $context, TKeyedArray &$type, bool $hasMixed, array &$expected_offset_types, bool &$has_valid_offset) : void { $generic_key_type = $type->getGenericKeyType(); if (!$stmt->dim && $type->fallback_params === null && $type->is_list) { $key_values[] = new TLiteralInt(count($type->properties)); } if ($key_values) { $properties = $type->properties; foreach ($key_values as $key_value) { $string_to_int = ArrayAnalyzer::getLiteralArrayKeyInt($key_value->value); $key_value = $string_to_int === \false ? $key_value : new TLiteralInt($string_to_int); if ($type->is_list && (!is_int($key_value->value) || $key_value->value < 0)) { $expected_offset_types[] = $type->getGenericKeyType(); $has_valid_offset = \false; } elseif (isset($properties[$key_value->value]) && !($key_value->value === 0 && AtomicTypeComparator::isLegacyTListLike($type)) || $replacement_type) { $has_valid_offset = \true; if ($replacement_type) { $properties[$key_value->value] = Type::combineUnionTypes($properties[$key_value->value] ?? null, $replacement_type); if (is_int($key_value->value) && !$stmt->dim && $type->is_list && $type->properties[$key_value->value - 1]->possibly_undefined) { $first = \true; for ($x = 0; $x < $key_value->value; $x++) { if (!$properties[$x]->possibly_undefined) { continue; } $properties[$x] = Type::combineUnionTypes($properties[$x], $replacement_type); if ($first) { $first = \false; $properties[$x] = $properties[$x]->setPossiblyUndefined(\false); } } $properties[$key_value->value] = $properties[$key_value->value]->setPossiblyUndefined(\true); } } $array_access_type = Type::combineUnionTypes($array_access_type, $properties[$key_value->value]); } elseif ($in_assignment) { $properties[$key_value->value] = new Union([new TNever()]); $array_access_type = Type::combineUnionTypes($array_access_type, $properties[$key_value->value]); } elseif ($type->fallback_params !== null) { if ($codebase->config->ensure_array_string_offsets_exist) { self::checkLiteralStringArrayOffset($offset_type, $type->getGenericKeyType(), $extended_var_id, $stmt, $context, $statements_analyzer); } if ($codebase->config->ensure_array_int_offsets_exist) { self::checkLiteralIntArrayOffset($offset_type, $type->getGenericKeyType(), $extended_var_id, $stmt, $context, $statements_analyzer); } $properties[$key_value->value] = $type->fallback_params[1]; $array_access_type = $type->fallback_params[1]; } elseif ($hasMixed) { $has_valid_offset = \true; $array_access_type = Type::getMixed(); } else { $object_like_keys = array_keys($properties); $last_key = array_pop($object_like_keys); $key_string = ''; if ($object_like_keys) { $formatted_keys = implode(', ', array_map( /** @param int|string $key */ static fn($key): string => is_int($key) ? "{$key}" : '\'' . $key . '\'', $object_like_keys )); $key_string = $formatted_keys . ' or '; } $key_string .= is_int($last_key) ? $last_key : '\'' . $last_key . '\''; $expected_offset_types[] = $key_string; $array_access_type = Type::getMixed(); } } $type = $type->setProperties($properties); } else { $key_type = $generic_key_type->hasMixed() ? Type::getArrayKey() : $generic_key_type; $union_comparison_results = new TypeComparisonResult(); $is_contained = UnionTypeComparator::isContainedBy($codebase, $offset_type->freeze(), $key_type, \true, $offset_type->ignore_falsable_issues, $union_comparison_results); if ($context->inside_isset && !$is_contained) { $is_contained = UnionTypeComparator::isContainedBy($codebase, $key_type, $offset_type->freeze(), \true, $offset_type->ignore_falsable_issues); } if (($is_contained || $union_comparison_results->type_coerced_from_scalar || $union_comparison_results->type_coerced_from_mixed || $in_assignment) && !$union_comparison_results->to_string_cast) { if ($replacement_type) { $generic_params = Type::combineUnionTypes($type->getGenericValueType(), $replacement_type); $new_key_type = Type::combineUnionTypes($generic_key_type, $offset_type->isMixed() ? Type::getArrayKey() : $offset_type->freeze()); if (!$stmt->dim) { if ($type->is_list) { $type = new TKeyedArray($type->properties, null, [$new_key_type, $generic_params], \true); } else { $type = new TNonEmptyArray([$new_key_type, $generic_params], null, $type->getMinCount() + 1); } } else { $min_count = $type->getMinCount(); if ($min_count) { $type = new TNonEmptyArray([$new_key_type, $generic_params], null, $min_count); } else { $type = new TArray([$new_key_type, $generic_params]); } } $array_access_type = Type::combineUnionTypes($array_access_type, $generic_params); } else { $array_access_type = Type::combineUnionTypes($array_access_type, $type->getGenericValueType()); } $has_valid_offset = \true; } else { if (!$context->inside_isset || $type->fallback_params === null && !$union_comparison_results->type_coerced) { $expected_offset_types[] = $generic_key_type->getId(); } $array_access_type = Type::getMixed(); } } } private static function handleArrayAccessOnNamedObject(StatementsAnalyzer $statements_analyzer, PhpParser\Node\Expr\ArrayDimFetch $stmt, TNamedObject $type, Context $context, bool $in_assignment, ?PhpParser\Node\Expr $assign_value, ?Union &$array_access_type, bool &$has_array_access) : void { $codebase = $statements_analyzer->getCodebase(); if (strtolower($type->value) === 'simplexmlelement' || $codebase->classExists($type->value) && $codebase->classExtendsOrImplements($type->value, 'SimpleXMLElement')) { $call_array_access_type = new Union([new TNull(), new TNamedObject('SimpleXMLElement')]); } elseif (strtolower($type->value) === 'domnodelist' && $stmt->dim) { $old_data_provider = $statements_analyzer->node_data; $statements_analyzer->node_data = clone $statements_analyzer->node_data; $fake_method_call = new VirtualMethodCall($stmt->var, new VirtualIdentifier('item', $stmt->var->getAttributes()), [new VirtualArg($stmt->dim)]); $suppressed_issues = $statements_analyzer->getSuppressedIssues(); if (!in_array('PossiblyInvalidMethodCall', $suppressed_issues, \true)) { $statements_analyzer->addSuppressedIssues(['PossiblyInvalidMethodCall']); } if (!in_array('MixedMethodCall', $suppressed_issues, \true)) { $statements_analyzer->addSuppressedIssues(['MixedMethodCall']); } MethodCallAnalyzer::analyze($statements_analyzer, $fake_method_call, $context); if (!in_array('PossiblyInvalidMethodCall', $suppressed_issues, \true)) { $statements_analyzer->removeSuppressedIssues(['PossiblyInvalidMethodCall']); } if (!in_array('MixedMethodCall', $suppressed_issues, \true)) { $statements_analyzer->removeSuppressedIssues(['MixedMethodCall']); } $call_array_access_type = $statements_analyzer->node_data->getType($fake_method_call) ?? Type::getMixed(); $statements_analyzer->node_data = $old_data_provider; } else { $suppressed_issues = $statements_analyzer->getSuppressedIssues(); if (!in_array('PossiblyInvalidMethodCall', $suppressed_issues, \true)) { $statements_analyzer->addSuppressedIssues(['PossiblyInvalidMethodCall']); } if (!in_array('MixedMethodCall', $suppressed_issues, \true)) { $statements_analyzer->addSuppressedIssues(['MixedMethodCall']); } if ($in_assignment) { $old_node_data = $statements_analyzer->node_data; $statements_analyzer->node_data = clone $statements_analyzer->node_data; $fake_set_method_call = new VirtualMethodCall($stmt->var, new VirtualIdentifier('offsetSet', $stmt->var->getAttributes()), [new VirtualArg($stmt->dim ?? new VirtualConstFetch(new VirtualName('null'), $stmt->var->getAttributes())), new VirtualArg($assign_value ?? new VirtualConstFetch(new VirtualName('null'), $stmt->var->getAttributes()))]); MethodCallAnalyzer::analyze($statements_analyzer, $fake_set_method_call, $context); $statements_analyzer->node_data = $old_node_data; } if ($stmt->dim) { $old_node_data = $statements_analyzer->node_data; $statements_analyzer->node_data = clone $statements_analyzer->node_data; $fake_get_method_call = new VirtualMethodCall($stmt->var, new VirtualIdentifier('offsetGet', $stmt->var->getAttributes()), [new VirtualArg($stmt->dim)]); MethodCallAnalyzer::analyze($statements_analyzer, $fake_get_method_call, $context); $call_array_access_type = $statements_analyzer->node_data->getType($fake_get_method_call) ?? Type::getMixed(); $statements_analyzer->node_data = $old_node_data; } else { $call_array_access_type = Type::getVoid(); } $has_array_access = \true; if (!in_array('PossiblyInvalidMethodCall', $suppressed_issues, \true)) { $statements_analyzer->removeSuppressedIssues(['PossiblyInvalidMethodCall']); } if (!in_array('MixedMethodCall', $suppressed_issues, \true)) { $statements_analyzer->removeSuppressedIssues(['MixedMethodCall']); } } $array_access_type = Type::combineUnionTypes($array_access_type, $call_array_access_type); } /** * @param list $expected_offset_types */ private static function handleArrayAccessOnString(StatementsAnalyzer $statements_analyzer, Codebase $codebase, PhpParser\Node\Expr\ArrayDimFetch $stmt, bool $in_assignment, Context $context, ?Union $replacement_type, TString $type, MutableUnion $offset_type, array &$expected_offset_types, ?Union &$array_access_type, bool &$has_valid_offset) : void { if ($in_assignment && $replacement_type) { if ($replacement_type->hasMixed()) { if (!$context->collect_initializations && !$context->collect_mutations && $statements_analyzer->getFilePath() === $statements_analyzer->getRootFilePath() && (!($parent_source = $statements_analyzer->getSource()) instanceof FunctionLikeAnalyzer || !$parent_source->getSource() instanceof TraitAnalyzer)) { $codebase->analyzer->incrementMixedCount($statements_analyzer->getFilePath()); } IssueBuffer::maybeAdd(new MixedStringOffsetAssignment('Right-hand-side of string offset assignment cannot be mixed', new CodeLocation($statements_analyzer->getSource(), $stmt)), $statements_analyzer->getSuppressedIssues()); } else { if (!$context->collect_initializations && !$context->collect_mutations && $statements_analyzer->getFilePath() === $statements_analyzer->getRootFilePath() && (!($parent_source = $statements_analyzer->getSource()) instanceof FunctionLikeAnalyzer || !$parent_source->getSource() instanceof TraitAnalyzer)) { $codebase->analyzer->incrementNonMixedCount($statements_analyzer->getFilePath()); } } } if ($type instanceof TSingleLetter) { $valid_offset_type = Type::getInt(\false, 0); } elseif ($type instanceof TLiteralString) { if ($type->value === '') { $valid_offset_type = Type::getNever(); } elseif (strlen($type->value) < 10) { $valid_offsets = []; for ($i = -strlen($type->value), $l = strlen($type->value); $i < $l; $i++) { $valid_offsets[] = new TLiteralInt($i); } if (!$valid_offsets) { throw new UnexpectedValueException('This is weird'); } $valid_offset_type = new Union($valid_offsets); } else { $valid_offset_type = Type::getInt(); } } else { $valid_offset_type = Type::getInt(); } if (!UnionTypeComparator::isContainedBy($codebase, $offset_type->freeze(), $valid_offset_type, \true)) { $expected_offset_types[] = $valid_offset_type->getId(); $array_access_type = Type::getMixed(); } else { $has_valid_offset = \true; $array_access_type = Type::combineUnionTypes($array_access_type, Type::getSingleLetter()); } } /** * @param Atomic[] $offset_types */ private static function checkArrayOffsetType(MutableUnion $offset_type, array $offset_types, Codebase $codebase) : bool { $has_valid_absolute_offset = \false; foreach ($offset_types as $atomic_offset_type) { if ($atomic_offset_type instanceof TClassConstant) { $expanded = TypeExpander::expandAtomic($codebase, $atomic_offset_type, $atomic_offset_type->fq_classlike_name, $atomic_offset_type->fq_classlike_name, null, \true, \true); $has_valid_absolute_offset = self::checkArrayOffsetType($offset_type, $expanded, $codebase); if ($has_valid_absolute_offset) { break; } } if ($atomic_offset_type instanceof TFalse && $offset_type->ignore_falsable_issues === \true) { //do nothing } elseif ($atomic_offset_type instanceof TNull && $offset_type->ignore_nullable_issues === \true) { //do nothing } elseif ($atomic_offset_type instanceof TString || $atomic_offset_type instanceof TInt || $atomic_offset_type instanceof TArrayKey || $atomic_offset_type instanceof TMixed) { $has_valid_absolute_offset = \true; break; } elseif ($atomic_offset_type instanceof TTemplateParam) { $has_valid_absolute_offset = self::checkArrayOffsetType($offset_type, $atomic_offset_type->as->getAtomicTypes(), $codebase); if ($has_valid_absolute_offset) { break; } } } return $has_valid_absolute_offset; } } getFileAnalyzer()->project_analyzer; $codebase = $statements_analyzer->getCodebase(); if ($stmt->name === 'this') { if ($statements_analyzer->isStatic()) { return !IssueBuffer::accepts(new InvalidScope('Invalid reference to $this in a static context', new CodeLocation($statements_analyzer->getSource(), $stmt)), $statements_analyzer->getSuppressedIssues()); } if (!isset($context->vars_in_scope['$this'])) { if (IssueBuffer::accepts(new InvalidScope('Invalid reference to $this in a non-class context', new CodeLocation($statements_analyzer->getSource(), $stmt)), $statements_analyzer->getSuppressedIssues())) { return \false; } $context->vars_in_scope['$this'] = Type::getMixed(); $context->vars_possibly_in_scope['$this'] = \true; return \true; } $statements_analyzer->node_data->setType($stmt, $context->vars_in_scope['$this']); if ($codebase->store_node_types && !$context->collect_initializations && !$context->collect_mutations && ($stmt_type = $statements_analyzer->node_data->getType($stmt))) { $codebase->analyzer->addNodeType($statements_analyzer->getFilePath(), $stmt, $stmt_type->getId()); } if (!$context->collect_mutations && !$context->collect_initializations) { if ($context->pure) { IssueBuffer::maybeAdd(new ImpureVariable('Cannot reference $this in a pure context', new CodeLocation($statements_analyzer->getSource(), $stmt)), $statements_analyzer->getSuppressedIssues()); } elseif ($statements_analyzer->getSource() instanceof FunctionLikeAnalyzer && $statements_analyzer->getSource()->track_mutations) { $statements_analyzer->getSource()->inferred_impure = \true; } } return \true; } if (!$context->check_variables) { if (is_string($stmt->name)) { $var_name = '$' . $stmt->name; if (!$context->hasVariable($var_name)) { $context->vars_in_scope[$var_name] = Type::getMixed(); $context->vars_possibly_in_scope[$var_name] = \true; $statements_analyzer->node_data->setType($stmt, Type::getMixed()); } else { $stmt_type = $context->vars_in_scope[$var_name]; self::addDataFlowToVariable($statements_analyzer, $stmt, $var_name, $stmt_type, $context); $context->vars_in_scope[$var_name] = $stmt_type; $statements_analyzer->node_data->setType($stmt, $stmt_type); } } else { $statements_analyzer->node_data->setType($stmt, Type::getMixed()); } return \true; } if (is_string($stmt->name) && self::isSuperGlobal('$' . $stmt->name)) { $var_name = '$' . $stmt->name; if (isset($context->vars_in_scope[$var_name])) { $type = $context->vars_in_scope[$var_name]; self::taintVariable($statements_analyzer, $var_name, $type, $stmt); $context->vars_in_scope[$var_name] = $type; $statements_analyzer->node_data->setType($stmt, $type); return \true; } $type = self::getGlobalType($var_name, $codebase->analysis_php_version_id); self::taintVariable($statements_analyzer, $var_name, $type, $stmt); $statements_analyzer->node_data->setType($stmt, $type); $context->vars_in_scope[$var_name] = $type; $context->vars_possibly_in_scope[$var_name] = \true; $codebase->analyzer->addNodeReference($statements_analyzer->getFilePath(), $stmt, $var_name); return \true; } if (!is_string($stmt->name)) { if ($context->pure) { IssueBuffer::maybeAdd(new ImpureVariable('Cannot reference an unknown variable in a pure context', new CodeLocation($statements_analyzer->getSource(), $stmt)), $statements_analyzer->getSuppressedIssues()); } elseif ($statements_analyzer->getSource() instanceof FunctionLikeAnalyzer && $statements_analyzer->getSource()->track_mutations) { $statements_analyzer->getSource()->inferred_impure = \true; } $was_inside_general_use = $context->inside_general_use; $context->inside_general_use = \true; $expr_result = ExpressionAnalyzer::analyze($statements_analyzer, $stmt->name, $context); $context->inside_general_use = $was_inside_general_use; return $expr_result; } if ($passed_by_reference && $by_ref_type) { AssignmentAnalyzer::assignByRefParam($statements_analyzer, $stmt, $by_ref_type, $by_ref_type, $context); return \true; } $var_name = '$' . $stmt->name; if (!$context->hasVariable($var_name)) { if (!isset($context->vars_possibly_in_scope[$var_name]) || !$statements_analyzer->getFirstAppearance($var_name)) { if ($array_assignment || $assigned_to_reference) { if ($array_assignment) { // if we're in an array assignment, let's assign the variable because PHP allows it $stmt_type = Type::getArray(); } else { // If a variable is assigned by reference to a variable that // does not exist, they are automatically initialized as `null` $stmt_type = Type::getNull(); } $context->vars_in_scope[$var_name] = $stmt_type; $context->vars_possibly_in_scope[$var_name] = \true; // it might have been defined first in another if/else branch if (!$statements_analyzer->hasVariable($var_name)) { $statements_analyzer->registerVariable($var_name, new CodeLocation($statements_analyzer, $stmt), $context->branch_point); } $statements_analyzer->node_data->setType($stmt, $stmt_type); if ($assigned_to_reference) { // Since this variable was created by being assigned to as a reference (ie for // `$a = &$b` this variable is $b), we need to analyze it as an assignment to null. AssignmentAnalyzer::analyze($statements_analyzer, $stmt, null, $stmt_type, $context, null); // Stop here, we don't want it to be considered possibly undefined like the array case. return \true; } } elseif (!$context->inside_isset || $statements_analyzer->getSource() instanceof FunctionLikeAnalyzer) { if ($context->is_global || $from_global) { IssueBuffer::maybeAdd(new UndefinedGlobalVariable('Cannot find referenced variable ' . $var_name . ' in global scope', new CodeLocation($statements_analyzer->getSource(), $stmt), $var_name), $statements_analyzer->getSuppressedIssues()); $statements_analyzer->node_data->setType($stmt, Type::getMixed()); return \true; } IssueBuffer::maybeAdd(new UndefinedVariable('Cannot find referenced variable ' . $var_name, new CodeLocation($statements_analyzer->getSource(), $stmt)), $statements_analyzer->getSuppressedIssues()); $statements_analyzer->node_data->setType($stmt, Type::getMixed()); return \true; } } $first_appearance = $statements_analyzer->getFirstAppearance($var_name); if ($first_appearance && !$context->inside_isset && !$context->inside_unset) { if ($context->is_global) { if ($codebase->alter_code) { if (!isset($project_analyzer->getIssuesToFix()['PossiblyUndefinedGlobalVariable'])) { return \true; } $branch_point = $statements_analyzer->getBranchPoint($var_name); if ($branch_point) { $statements_analyzer->addVariableInitialization($var_name, $branch_point); } return \true; } IssueBuffer::maybeAdd(new PossiblyUndefinedGlobalVariable('Possibly undefined global variable ' . $var_name . ', first seen on line ' . $first_appearance->getLineNumber(), new CodeLocation($statements_analyzer->getSource(), $stmt), $var_name), $statements_analyzer->getSuppressedIssues(), (bool) $statements_analyzer->getBranchPoint($var_name)); } else { if ($codebase->alter_code && isset($project_analyzer->getIssuesToFix()['PossiblyUndefinedVariable'])) { $branch_point = $statements_analyzer->getBranchPoint($var_name); if ($branch_point) { $statements_analyzer->addVariableInitialization($var_name, $branch_point); } return \true; } IssueBuffer::maybeAdd(new PossiblyUndefinedVariable('Possibly undefined variable ' . $var_name . ', first seen on line ' . $first_appearance->getLineNumber(), new CodeLocation($statements_analyzer->getSource(), $stmt)), $statements_analyzer->getSuppressedIssues(), (bool) $statements_analyzer->getBranchPoint($var_name)); } if ($codebase->store_node_types && !$context->collect_initializations && !$context->collect_mutations) { $codebase->analyzer->addNodeReference($statements_analyzer->getFilePath(), $stmt, $first_appearance->raw_file_start . '-' . $first_appearance->raw_file_end . ':mixed'); } $stmt_type = Type::getMixed(); self::addDataFlowToVariable($statements_analyzer, $stmt, $var_name, $stmt_type, $context); $statements_analyzer->node_data->setType($stmt, $stmt_type); $statements_analyzer->registerPossiblyUndefinedVariable($var_name, $stmt); return \true; } } else { $stmt_type = $context->vars_in_scope[$var_name]; self::addDataFlowToVariable($statements_analyzer, $stmt, $var_name, $stmt_type, $context); $context->vars_in_scope[$var_name] = $stmt_type; $statements_analyzer->node_data->setType($stmt, $stmt_type); if ($stmt_type->possibly_undefined_from_try && !$context->inside_isset) { if ($context->is_global) { IssueBuffer::maybeAdd(new PossiblyUndefinedGlobalVariable('Possibly undefined global variable ' . $var_name . ' defined in try block', new CodeLocation($statements_analyzer->getSource(), $stmt), $var_name), $statements_analyzer->getSuppressedIssues()); } else { IssueBuffer::maybeAdd(new PossiblyUndefinedVariable('Possibly undefined variable ' . $var_name . ' defined in try block', new CodeLocation($statements_analyzer->getSource(), $stmt)), $statements_analyzer->getSuppressedIssues()); } } if ($codebase->store_node_types && !$context->collect_initializations && !$context->collect_mutations) { $codebase->analyzer->addNodeType($statements_analyzer->getFilePath(), $stmt, $stmt_type->getId()); } if ($codebase->store_node_types && !$context->collect_initializations && !$context->collect_mutations) { $first_appearance = $statements_analyzer->getFirstAppearance($var_name); if ($first_appearance) { $codebase->analyzer->addNodeReference($statements_analyzer->getFilePath(), $stmt, $first_appearance->raw_file_start . '-' . $first_appearance->raw_file_end . ':' . $stmt_type->getId()); } } } return \true; } private static function addDataFlowToVariable(StatementsAnalyzer $statements_analyzer, PhpParser\Node\Expr\Variable $stmt, string $var_name, Union &$stmt_type, Context $context) : void { $codebase = $statements_analyzer->getCodebase(); if ($statements_analyzer->data_flow_graph && $codebase->find_unused_variables && ($context->inside_return || $context->inside_call || $context->inside_general_use || $context->inside_conditional || $context->inside_throw || $context->inside_isset)) { if (!$stmt_type->parent_nodes) { $assignment_node = DataFlowNode::getForAssignment($var_name, new CodeLocation($statements_analyzer->getSource(), $stmt)); $stmt_type = $stmt_type->setParentNodes([$assignment_node->id => $assignment_node]); } foreach ($stmt_type->parent_nodes as $parent_node) { if ($context->inside_call || $context->inside_return) { $statements_analyzer->data_flow_graph->addPath($parent_node, new DataFlowNode('variable-use', 'variable use', null), 'use-inside-call'); } elseif ($context->inside_conditional) { $statements_analyzer->data_flow_graph->addPath($parent_node, new DataFlowNode('variable-use', 'variable use', null), 'use-inside-conditional'); } elseif ($context->inside_isset) { $statements_analyzer->data_flow_graph->addPath($parent_node, new DataFlowNode('variable-use', 'variable use', null), 'use-inside-isset'); } else { $statements_analyzer->data_flow_graph->addPath($parent_node, new DataFlowNode('variable-use', 'variable use', null), 'variable-use'); } } } } private static function taintVariable(StatementsAnalyzer $statements_analyzer, string $var_name, Union &$type, PhpParser\Node\Expr\Variable $stmt) : void { if ($statements_analyzer->data_flow_graph instanceof TaintFlowGraph && !in_array('TaintedInput', $statements_analyzer->getSuppressedIssues())) { if ($var_name === '$_GET' || $var_name === '$_POST' || $var_name === '$_COOKIE' || $var_name === '$_REQUEST') { $taint_location = new CodeLocation($statements_analyzer->getSource(), $stmt); $server_taint_source = new TaintSource($var_name . ':' . $taint_location->file_name . ':' . $taint_location->raw_file_start, $var_name, null, null, TaintKindGroup::ALL_INPUT); $statements_analyzer->data_flow_graph->addSource($server_taint_source); $type = $type->setParentNodes([$server_taint_source->id => $server_taint_source]); } } } /** * @psalm-pure */ public static function isSuperGlobal(string $var_id) : bool { return in_array($var_id, self::SUPER_GLOBALS, \true); } /** @var array|'$_FILES full path'|'$argv'|'$argc', Union> */ private static array $globalCache = []; public static function getGlobalType(string $var_id, int $codebase_analysis_php_version_id) : Union { $config = Config::getInstance(); if (isset($config->globals[$var_id])) { return Type::parseString($config->globals[$var_id]); } if (!self::$globalCache) { foreach (self::SUPER_GLOBALS as $v) { self::$globalCache[$v] = self::getGlobalTypeInner($v); } self::$globalCache['$_FILES full path'] = self::getGlobalTypeInner('$_FILES', \true); self::$globalCache['$argv'] = self::getGlobalTypeInner('$argv'); self::$globalCache['$argc'] = self::getGlobalTypeInner('$argc'); } if ($codebase_analysis_php_version_id >= 80100 && $var_id === '$_FILES') { $var_id = '$_FILES full path'; } if (isset(self::$globalCache[$var_id])) { return self::$globalCache[$var_id]; } return Type::getMixed(); } /** * @param value-of|'$argv'|'$argc' $var_id */ private static function getGlobalTypeInner(string $var_id, bool $files_full_path = \false) : Union { if ($var_id === '$argv') { // only in CLI, null otherwise return new Union([Type::getNonEmptyListAtomic(Type::getString()), new TNull()], ['ignore_nullable_issues' => \true]); // use TNull explicitly instead of this // as it will cause weird errors due to ignore_nullable_issues true // e.g. InvalidPropertyAssignmentValue // $this->argv 'list' cannot be assigned type 'non-empty-list' } if ($var_id === '$argc') { // only in CLI, null otherwise return new Union([new TIntRange(1, null), new TNull()], ['ignore_nullable_issues' => \true]); } if ($var_id === '$http_response_header') { // $http_response_header exists only in the local scope after a successful network request return new Union([Type::getNonEmptyListAtomic(Type::getNonFalsyString())], ['possibly_undefined' => \true]); } if ($var_id === '$GLOBALS') { return new Union([new TNonEmptyArray([Type::getNonEmptyString(), Type::getMixed()])]); } if ($var_id === '$_COOKIE') { $type = new TArray([Type::getNonEmptyString(), Type::getString()]); return new Union([$type]); } if (in_array($var_id, array('$_GET', '$_POST', '$_REQUEST'), \true)) { $array_key = new Union([new TNonEmptyString(), new TInt()]); $array = new TNonEmptyArray([$array_key, new Union([new TString(), new TArray([$array_key, Type::getMixed()])])]); $type = new TArray([$array_key, new Union([new TString(), $array])]); return new Union([$type]); } if ($var_id === '$_SERVER' || $var_id === '$_ENV') { $string_helper = new Union([new TString()], ['possibly_undefined' => \true]); $non_empty_string_helper = new Union([new TNonEmptyString()], ['possibly_undefined' => \true]); $argv_helper = new Union([Type::getNonEmptyListAtomic(Type::getString())], ['possibly_undefined' => \true]); $argc_helper = new Union([new TIntRange(1, null)], ['possibly_undefined' => \true]); $request_time_helper = new Union([new TIntRange(time(), null)], ['possibly_undefined' => \true]); $request_time_float_helper = new Union([new TFloat()], ['possibly_undefined' => \true]); $bool_string_helper = new Union([new TBool(), new TString()], ['possibly_undefined' => \true]); $arr = [ // https://www.php.net/manual/en/reserved.variables.server.php 'PHP_SELF' => $non_empty_string_helper, 'GATEWAY_INTERFACE' => $non_empty_string_helper, 'SERVER_ADDR' => $non_empty_string_helper, 'SERVER_NAME' => $non_empty_string_helper, 'SERVER_SOFTWARE' => $non_empty_string_helper, 'SERVER_PROTOCOL' => $non_empty_string_helper, 'REQUEST_METHOD' => $non_empty_string_helper, 'REQUEST_TIME' => $request_time_helper, 'REQUEST_TIME_FLOAT' => $request_time_float_helper, 'QUERY_STRING' => $string_helper, 'DOCUMENT_ROOT' => $non_empty_string_helper, 'HTTP_ACCEPT' => $non_empty_string_helper, 'HTTP_ACCEPT_CHARSET' => $non_empty_string_helper, 'HTTP_ACCEPT_ENCODING' => $non_empty_string_helper, 'HTTP_ACCEPT_LANGUAGE' => $non_empty_string_helper, 'HTTP_CONNECTION' => $non_empty_string_helper, 'HTTP_HOST' => $non_empty_string_helper, 'HTTP_REFERER' => $non_empty_string_helper, 'HTTP_USER_AGENT' => $non_empty_string_helper, 'HTTPS' => $string_helper, 'REMOTE_ADDR' => $non_empty_string_helper, 'REMOTE_HOST' => $non_empty_string_helper, 'REMOTE_PORT' => $string_helper, 'REMOTE_USER' => $non_empty_string_helper, 'REDIRECT_REMOTE_USER' => $non_empty_string_helper, 'SCRIPT_FILENAME' => $non_empty_string_helper, 'SERVER_ADMIN' => $non_empty_string_helper, 'SERVER_PORT' => $non_empty_string_helper, 'SERVER_SIGNATURE' => $non_empty_string_helper, 'PATH_TRANSLATED' => $non_empty_string_helper, 'SCRIPT_NAME' => $non_empty_string_helper, 'REQUEST_URI' => $non_empty_string_helper, 'PHP_AUTH_DIGEST' => $non_empty_string_helper, 'PHP_AUTH_USER' => $non_empty_string_helper, 'PHP_AUTH_PW' => $non_empty_string_helper, 'AUTH_TYPE' => $non_empty_string_helper, 'PATH_INFO' => $non_empty_string_helper, 'ORIG_PATH_INFO' => $non_empty_string_helper, // misc from RFC not included above already http://www.faqs.org/rfcs/rfc3875.html 'CONTENT_LENGTH' => $string_helper, 'CONTENT_TYPE' => $string_helper, // common, misc stuff 'FCGI_ROLE' => $non_empty_string_helper, 'HOME' => $non_empty_string_helper, 'HTTP_CACHE_CONTROL' => $non_empty_string_helper, 'HTTP_COOKIE' => $non_empty_string_helper, 'HTTP_PRIORITY' => $non_empty_string_helper, 'PATH' => $non_empty_string_helper, 'REDIRECT_STATUS' => $non_empty_string_helper, 'REQUEST_SCHEME' => $non_empty_string_helper, 'USER' => $non_empty_string_helper, // common, misc headers 'HTTP_UPGRADE_INSECURE_REQUESTS' => $non_empty_string_helper, 'HTTP_X_FORWARDED_PROTO' => $non_empty_string_helper, 'HTTP_CLIENT_IP' => $non_empty_string_helper, 'HTTP_X_REAL_IP' => $non_empty_string_helper, 'HTTP_X_FORWARDED_FOR' => $non_empty_string_helper, 'HTTP_CF_CONNECTING_IP' => $non_empty_string_helper, 'HTTP_CF_IPCOUNTRY' => $non_empty_string_helper, 'HTTP_CF_VISITOR' => $non_empty_string_helper, 'HTTP_CDN_LOOP' => $non_empty_string_helper, // common, misc browser headers 'HTTP_DNT' => $non_empty_string_helper, 'HTTP_SEC_FETCH_DEST' => $non_empty_string_helper, 'HTTP_SEC_FETCH_USER' => $non_empty_string_helper, 'HTTP_SEC_FETCH_MODE' => $non_empty_string_helper, 'HTTP_SEC_FETCH_SITE' => $non_empty_string_helper, 'HTTP_SEC_CH_UA_PLATFORM' => $non_empty_string_helper, 'HTTP_SEC_CH_UA_MOBILE' => $non_empty_string_helper, 'HTTP_SEC_CH_UA' => $non_empty_string_helper, // phpunit 'APP_DEBUG' => $bool_string_helper, 'APP_ENV' => $string_helper, ]; if ($var_id === '$_SERVER') { $arr['argv'] = $argv_helper; $arr['argc'] = $argc_helper; } $detailed_type = new TKeyedArray($arr, null, [Type::getNonEmptyString(), Type::getString()]); return new Union([$detailed_type]); } if ($var_id === '$_FILES') { $str = Type::getString(); $values = ['name' => $str, 'type' => $str, 'tmp_name' => $str, 'size' => Type::getListKey(), 'error' => Type::getIntRange(0, 8)]; if ($files_full_path) { $values['full_path'] = $str; } $type = new Union([new TKeyedArray($values)]); $parent = new TArray([Type::getNonEmptyString(), $type]); return new Union([$parent]); } // $var_id === $_SESSION // keys must be string return new Union([new TArray([Type::getNonEmptyString(), Type::getMixed()])], ['possibly_undefined' => \true]); } } getCodebase(); $if_scope = new IfScope(); try { $if_conditional_scope = IfConditionalAnalyzer::analyze($statements_analyzer, $stmt->cond, $context, $codebase, $if_scope, $context->branch_point ?: (int) $stmt->getAttribute('startFilePos')); // this is the context for stuff that happens within the first operand of the ternary $if_context = $if_conditional_scope->if_context; $cond_referenced_var_ids = $if_conditional_scope->cond_referenced_var_ids; $assigned_in_conditional_var_ids = $if_conditional_scope->assigned_in_conditional_var_ids; } catch (ScopeAnalysisException $e) { return \false; } $cond_object_id = spl_object_id($stmt->cond); $if_clauses = FormulaGenerator::getFormula($cond_object_id, $cond_object_id, $stmt->cond, $context->self, $statements_analyzer, $codebase); if (count($if_clauses) > 200) { $if_clauses = []; } $mixed_var_ids = []; foreach ($context->vars_in_scope as $var_id => $type) { if ($type->hasMixed()) { $mixed_var_ids[] = $var_id; } } foreach ($context->vars_possibly_in_scope as $var_id => $_) { if (!isset($context->vars_in_scope[$var_id])) { $mixed_var_ids[] = $var_id; } } $if_clauses = array_map(static function (Clause $c) use($mixed_var_ids, $cond_object_id) : Clause { $keys = array_keys($c->possibilities); $mixed_var_ids = array_diff($mixed_var_ids, $keys); foreach ($keys as $key) { foreach ($mixed_var_ids as $mixed_var_id) { if (preg_match('/^' . preg_quote($mixed_var_id, '/') . '(\\[|-)/', $key)) { return new Clause([], $cond_object_id, $cond_object_id, \true); } } } return $c; }, $if_clauses); $entry_clauses = $context->clauses; // this will see whether any of the clauses in set A conflict with the clauses in set B AlgebraAnalyzer::checkForParadox($context->clauses, $if_clauses, $statements_analyzer, $stmt->cond, $assigned_in_conditional_var_ids); $if_clauses = Algebra::simplifyCNF($if_clauses); $ternary_context_clauses = $entry_clauses ? Algebra::simplifyCNF([...$entry_clauses, ...$if_clauses]) : $if_clauses; if ($if_context->reconciled_expression_clauses) { $reconciled_expression_clauses = $if_context->reconciled_expression_clauses; $ternary_context_clauses = array_values(array_filter($ternary_context_clauses, static fn(Clause $c): bool => !in_array($c->hash, $reconciled_expression_clauses))); if (count($if_context->clauses) === 1 && $if_context->clauses[0]->wedge && !$if_context->clauses[0]->possibilities) { $if_context->clauses = []; $if_context->reconciled_expression_clauses = []; } } try { $if_scope->negated_clauses = Algebra::negateFormula($if_clauses); } catch (ComplicatedExpressionException $e) { try { $if_scope->negated_clauses = FormulaGenerator::getFormula($cond_object_id, $cond_object_id, new VirtualBooleanNot($stmt->cond), $context->self, $statements_analyzer, $codebase, \false); } catch (ComplicatedExpressionException $e) { $if_scope->negated_clauses = []; } } $if_scope->negated_types = Algebra::getTruthsFromFormula(Algebra::simplifyCNF([...$context->clauses, ...$if_scope->negated_clauses])); $active_if_types = []; $reconcilable_if_types = Algebra::getTruthsFromFormula($ternary_context_clauses, $cond_object_id, $cond_referenced_var_ids, $active_if_types); $changed_var_ids = []; if ($reconcilable_if_types) { [$if_context->vars_in_scope, $if_context->references_in_scope] = Reconciler::reconcileKeyedTypes($reconcilable_if_types, $active_if_types, $if_context->vars_in_scope, $if_context->references_in_scope, $changed_var_ids, $cond_referenced_var_ids, $statements_analyzer, $statements_analyzer->getTemplateTypeMap() ?: [], $if_context->inside_loop, new CodeLocation($statements_analyzer->getSource(), $stmt->cond)); } $t_else_context = clone $context; if ($stmt->if) { if (ExpressionAnalyzer::analyze($statements_analyzer, $stmt->if, $if_context) === \false) { return \false; } $context->cond_referenced_var_ids = array_merge($context->cond_referenced_var_ids, $if_context->cond_referenced_var_ids); } $t_else_context->clauses = Algebra::simplifyCNF([...$t_else_context->clauses, ...$if_scope->negated_clauses]); $changed_var_ids = []; if ($if_scope->negated_types) { [$t_else_context->vars_in_scope, $t_else_context->references_in_scope] = Reconciler::reconcileKeyedTypes($if_scope->negated_types, $if_scope->negated_types, $t_else_context->vars_in_scope, $t_else_context->references_in_scope, $changed_var_ids, $cond_referenced_var_ids, $statements_analyzer, $statements_analyzer->getTemplateTypeMap() ?: [], $t_else_context->inside_loop, new CodeLocation($statements_analyzer->getSource(), $stmt->else)); $t_else_context->clauses = Context::removeReconciledClauses($t_else_context->clauses, $changed_var_ids)[0]; } if (ExpressionAnalyzer::analyze($statements_analyzer, $stmt->else, $t_else_context) === \false) { return \false; } $assign_var_ifs = $if_context->assigned_var_ids; $assign_var_else = $t_else_context->assigned_var_ids; $assign_all = array_intersect_key($assign_var_ifs, $assign_var_else); //if the same var was assigned in both branches foreach ($assign_all as $var_id => $_) { if (isset($if_context->vars_in_scope[$var_id]) && isset($t_else_context->vars_in_scope[$var_id])) { $context->vars_in_scope[$var_id] = Type::combineUnionTypes($if_context->vars_in_scope[$var_id], $t_else_context->vars_in_scope[$var_id]); } } $redef_var_ifs = array_keys($if_context->getRedefinedVars($context->vars_in_scope)); $redef_var_else = array_keys($t_else_context->getRedefinedVars($context->vars_in_scope)); $redef_all = array_intersect($redef_var_ifs, $redef_var_else); //these vars were changed in both branches foreach ($redef_all as $redef_var_id) { $context->vars_in_scope[$redef_var_id] = Type::combineUnionTypes($if_context->vars_in_scope[$redef_var_id], $t_else_context->vars_in_scope[$redef_var_id]); } //these vars were changed in the if and existed before foreach ($redef_var_ifs as $redef_var_ifs_id) { if (isset($context->vars_in_scope[$redef_var_ifs_id])) { $context->vars_in_scope[$redef_var_ifs_id] = Type::combineUnionTypes($context->vars_in_scope[$redef_var_ifs_id], $if_context->vars_in_scope[$redef_var_ifs_id]); } } //these vars were changed in the else and existed before foreach ($redef_var_else as $redef_var_else_id) { if (isset($context->vars_in_scope[$redef_var_else_id])) { $context->vars_in_scope[$redef_var_else_id] = Type::combineUnionTypes($context->vars_in_scope[$redef_var_else_id], $t_else_context->vars_in_scope[$redef_var_else_id]); } } $context->vars_possibly_in_scope = array_merge($context->vars_possibly_in_scope, $if_context->vars_possibly_in_scope, $t_else_context->vars_possibly_in_scope); $context->cond_referenced_var_ids = array_merge($context->cond_referenced_var_ids, $t_else_context->cond_referenced_var_ids); $lhs_type = null; $stmt_cond_type = $statements_analyzer->node_data->getType($stmt->cond); if ($stmt->if) { if ($stmt_if_type = $statements_analyzer->node_data->getType($stmt->if)) { $lhs_type = $stmt_if_type; } } elseif ($stmt_cond_type) { $if_return_type_reconciled = AssertionReconciler::reconcile(new Truthy(), $stmt_cond_type, '', $statements_analyzer, $context->inside_loop, [], new CodeLocation($statements_analyzer->getSource(), $stmt), $statements_analyzer->getSuppressedIssues()); $lhs_type = $if_return_type_reconciled; } if ($lhs_type && ($stmt_else_type = $statements_analyzer->node_data->getType($stmt->else))) { if ($stmt_cond_type !== null && $stmt_cond_type->isAlwaysFalsy()) { $statements_analyzer->node_data->setType($stmt, $stmt_else_type); } elseif ($stmt_cond_type !== null && $stmt_cond_type->isAlwaysTruthy()) { $statements_analyzer->node_data->setType($stmt, $lhs_type); } else { $statements_analyzer->node_data->setType($stmt, Type::combineUnionTypes($lhs_type, $stmt_else_type)); } } else { $statements_analyzer->node_data->setType($stmt, Type::getMixed()); } return \true; } } getCodebase(); if (ExpressionAnalyzer::analyze($statements_analyzer, $stmt->expr, $context) === \false) { return \false; } if ($statements_analyzer->data_flow_graph instanceof TaintFlowGraph) { $call_location = new CodeLocation($statements_analyzer->getSource(), $stmt); $print_param_sink = TaintSink::getForMethodArgument('print', 'print', 0, null, $call_location); $print_param_sink->taints = [TaintKind::INPUT_HTML, TaintKind::INPUT_HAS_QUOTES, TaintKind::USER_SECRET, TaintKind::SYSTEM_SECRET]; $statements_analyzer->data_flow_graph->addSink($print_param_sink); } if ($stmt_expr_type = $statements_analyzer->node_data->getType($stmt->expr)) { if (ArgumentAnalyzer::verifyType($statements_analyzer, $stmt_expr_type, Type::getString(), null, 'print', null, 0, new CodeLocation($statements_analyzer->getSource(), $stmt->expr), $stmt->expr, $context, new FunctionLikeParameter('var', \false), \false, null, \true, \true, new CodeLocation($statements_analyzer->getSource(), $stmt)) === \false) { return \false; } } if (isset($codebase->config->forbidden_functions['print'])) { IssueBuffer::maybeAdd(new ForbiddenCode('You have forbidden the use of print', new CodeLocation($statements_analyzer->getSource(), $stmt)), $statements_analyzer->getSuppressedIssues()); } if (!$context->collect_initializations && !$context->collect_mutations) { if ($context->mutation_free || $context->external_mutation_free) { IssueBuffer::maybeAdd(new ImpureFunctionCall('Cannot call print from a mutation-free context', new CodeLocation($statements_analyzer, $stmt)), $statements_analyzer->getSuppressedIssues()); } elseif ($statements_analyzer->getSource() instanceof FunctionLikeAnalyzer && $statements_analyzer->getSource()->track_mutations) { $statements_analyzer->getSource()->inferred_has_mutation = \true; $statements_analyzer->getSource()->inferred_impure = \true; } } $statements_analyzer->node_data->setType($stmt, Type::getInt(\false, 1)); return \true; } } vars as $isset_var) { if ($isset_var instanceof PhpParser\Node\Expr\PropertyFetch && $isset_var->var instanceof PhpParser\Node\Expr\Variable && $isset_var->var->name === 'this' && $isset_var->name instanceof PhpParser\Node\Identifier) { $var_id = '$this->' . $isset_var->name->name; if (!isset($context->vars_in_scope[$var_id])) { $context->vars_in_scope[$var_id] = Type::getMixed(); $context->vars_possibly_in_scope[$var_id] = \true; } } elseif (!self::isValidStatement($isset_var)) { IssueBuffer::maybeAdd(new InvalidArgument('Isset only works with variables and array elements', new CodeLocation($statements_analyzer->getSource(), $isset_var), 'empty'), $statements_analyzer->getSuppressedIssues()); } self::analyzeIssetVar($statements_analyzer, $isset_var, $context); } $statements_analyzer->node_data->setType($stmt, Type::getBool()); } public static function analyzeIssetVar(StatementsAnalyzer $statements_analyzer, PhpParser\Node\Expr $stmt, Context $context) : void { $context->inside_isset = \true; ExpressionAnalyzer::analyze($statements_analyzer, $stmt, $context); $context->inside_isset = \false; } private static function isValidStatement(PhpParser\Node\Expr $stmt) : bool { return $stmt instanceof PhpParser\Node\Expr\Variable || $stmt instanceof PhpParser\Node\Expr\ArrayDimFetch || $stmt instanceof PhpParser\Node\Expr\PropertyFetch || $stmt instanceof PhpParser\Node\Expr\StaticPropertyFetch || $stmt instanceof PhpParser\Node\Expr\NullsafePropertyFetch || $stmt instanceof PhpParser\Node\Expr\ClassConstFetch || $stmt instanceof PhpParser\Node\Expr\AssignRef; } } self, $statements_analyzer); $lhs_type = $statements_analyzer->node_data->getType($stmt->class); if (!$lhs_type) { return null; } $codebase = $statements_analyzer->getCodebase(); $prop_name = $stmt->name; foreach ($lhs_type->getAtomicTypes() as $lhs_atomic_type) { if ($lhs_atomic_type instanceof TClassString) { if (!$lhs_atomic_type->as_type) { continue; } $lhs_atomic_type = $lhs_atomic_type->as_type; } if (!$lhs_atomic_type instanceof TNamedObject) { continue; } $fq_class_name = $lhs_atomic_type->value; if (!$prop_name instanceof PhpParser\Node\Identifier) { $was_inside_general_use = $context->inside_general_use; $context->inside_general_use = \true; if (ExpressionAnalyzer::analyze($statements_analyzer, $prop_name, $context) === \false) { $context->inside_general_use = $was_inside_general_use; return \false; } $context->inside_general_use = $was_inside_general_use; if (!$context->ignore_variable_property) { $codebase->analyzer->addMixedMemberName(strtolower($fq_class_name) . '::$', $context->calling_method_id ?: $statements_analyzer->getFileName()); } return null; } $property_id = $fq_class_name . '::$' . $prop_name; if ($codebase->store_node_types && !$context->collect_initializations && !$context->collect_mutations) { $codebase->analyzer->addNodeReference($statements_analyzer->getFilePath(), $stmt->class, $fq_class_name); $codebase->analyzer->addNodeReference($statements_analyzer->getFilePath(), $stmt->name, $property_id); } if (!$codebase->properties->propertyExists($property_id, \false, $statements_analyzer, $context)) { IssueBuffer::maybeAdd(new UndefinedPropertyAssignment('Static property ' . $property_id . ' is not defined', new CodeLocation($statements_analyzer->getSource(), $stmt), $property_id), $statements_analyzer->getSuppressedIssues()); return null; } if (ClassLikeAnalyzer::checkPropertyVisibility($property_id, $context, $statements_analyzer, new CodeLocation($statements_analyzer->getSource(), $stmt), $statements_analyzer->getSuppressedIssues()) === \false) { return \false; } $declaring_property_class = (string) $codebase->properties->getDeclaringClassForProperty($fq_class_name . '::$' . $prop_name->name, \false); $declaring_property_id = strtolower($declaring_property_class) . '::$' . $prop_name; if ($codebase->alter_code && $stmt->class instanceof PhpParser\Node\Name) { $moved_class = $codebase->classlikes->handleClassLikeReferenceInMigration($codebase, $statements_analyzer, $stmt->class, $fq_class_name, $context->calling_method_id); if (!$moved_class) { foreach ($codebase->property_transforms as $original_pattern => $transformation) { if ($declaring_property_id === $original_pattern) { [$old_declaring_fq_class_name] = explode('::$', $declaring_property_id); [$new_fq_class_name, $new_property_name] = explode('::$', $transformation); $file_manipulations = []; if (strtolower($new_fq_class_name) !== $old_declaring_fq_class_name) { $file_manipulations[] = new FileManipulation((int) $stmt->class->getAttribute('startFilePos'), (int) $stmt->class->getAttribute('endFilePos') + 1, Type::getStringFromFQCLN($new_fq_class_name, $statements_analyzer->getNamespace(), $statements_analyzer->getAliasedClassesFlipped(), null)); } $file_manipulations[] = new FileManipulation((int) $stmt->name->getAttribute('startFilePos'), (int) $stmt->name->getAttribute('endFilePos') + 1, '$' . $new_property_name); FileManipulationBuffer::add($statements_analyzer->getFilePath(), $file_manipulations); } } } } $class_storage = $codebase->classlike_storage_provider->get($declaring_property_class); if ($var_id) { $context->vars_in_scope[$var_id] = $assignment_value_type; } \Psalm\Internal\Analyzer\Statements\Expression\Assignment\InstancePropertyAssignmentAnalyzer::taintUnspecializedProperty($statements_analyzer, $stmt, $property_id, $class_storage, $assignment_value_type, $context, null); $class_property_type = $codebase->properties->getPropertyType($property_id, \true, $statements_analyzer, $context); if (!$class_property_type) { $class_property_type = Type::getMixed(); $source_analyzer = $statements_analyzer->getSource()->getSource(); $prop_name_name = $prop_name->name; if ($source_analyzer instanceof ClassAnalyzer && $fq_class_name === $source_analyzer->getFQCLN()) { $source_analyzer->inferred_property_types[$prop_name_name] = Type::combineUnionTypes($assignment_value_type, $source_analyzer->inferred_property_types[$prop_name_name] ?? null); } } if ($assignment_value_type->hasMixed()) { return null; } if ($class_property_type->hasMixed()) { return null; } $class_property_type = TypeExpander::expandUnion($codebase, $class_property_type, $fq_class_name, $fq_class_name, $class_storage->parent_class); $union_comparison_results = new TypeComparisonResult(); $type_match_found = UnionTypeComparator::isContainedBy($codebase, $assignment_value_type, $class_property_type, \true, \true, $union_comparison_results); if ($union_comparison_results->type_coerced) { if ($union_comparison_results->type_coerced_from_mixed) { IssueBuffer::maybeAdd(new MixedPropertyTypeCoercion($var_id . ' expects \'' . $class_property_type->getId() . '\', ' . ' parent type `' . $assignment_value_type->getId() . '` provided', new CodeLocation($statements_analyzer->getSource(), $assignment_value ?? $stmt, $context->include_location), $property_id), $statements_analyzer->getSuppressedIssues()); } else { IssueBuffer::maybeAdd(new PropertyTypeCoercion($var_id . ' expects \'' . $class_property_type->getId() . '\', ' . ' parent type \'' . $assignment_value_type->getId() . '\' provided', new CodeLocation($statements_analyzer->getSource(), $assignment_value ?? $stmt, $context->include_location), $property_id), $statements_analyzer->getSuppressedIssues()); } } if ($union_comparison_results->to_string_cast) { IssueBuffer::maybeAdd(new ImplicitToStringCast($var_id . ' expects \'' . $class_property_type . '\', ' . '\'' . $assignment_value_type . '\' provided with a __toString method', new CodeLocation($statements_analyzer->getSource(), $assignment_value ?? $stmt, $context->include_location)), $statements_analyzer->getSuppressedIssues()); } if (!$type_match_found && !$union_comparison_results->type_coerced) { if (UnionTypeComparator::canBeContainedBy($codebase, $assignment_value_type, $class_property_type)) { if (IssueBuffer::accepts(new PossiblyInvalidPropertyAssignmentValue($var_id . ' with declared type \'' . $class_property_type->getId() . '\' cannot be assigned type \'' . $assignment_value_type->getId() . '\'', new CodeLocation($statements_analyzer->getSource(), $assignment_value ?? $stmt), $property_id), $statements_analyzer->getSuppressedIssues())) { return \false; } } else { if (IssueBuffer::accepts(new InvalidPropertyAssignmentValue($var_id . ' with declared type \'' . $class_property_type->getId() . '\' cannot be assigned type \'' . $assignment_value_type->getId() . '\'', new CodeLocation($statements_analyzer->getSource(), $assignment_value ?? $stmt), $property_id), $statements_analyzer->getSuppressedIssues())) { return \false; } } } if ($var_id) { $context->vars_in_scope[$var_id] = $assignment_value_type; } } return null; } } getCodebase(); if ($stmt instanceof PropertyProperty) { if (!$context->self || !$stmt->default) { return; } $property_id = $context->self . '::$' . $prop_name; $class_property_type = null; try { $class_property_type = $codebase->properties->getPropertyType($property_id, \true, $statements_analyzer, $context); } catch (UnexpectedValueException $e) { // do nothing } if ($class_property_type) { $class_storage = $codebase->classlike_storage_provider->get($context->self); $class_property_type = self::getExpandedPropertyType($codebase, $context->self, $prop_name, $class_storage); } $var_id = '$this->' . $prop_name; $assigned_properties = [new \Psalm\Internal\Analyzer\Statements\Expression\Assignment\AssignedProperty($class_property_type ?? Type::getMixed(), $property_id, $assignment_value_type)]; } else { $assigned_properties = self::analyzeRegularAssignment($statements_analyzer, $stmt, $assignment_value, $context, $direct_assignment, $codebase, $assignment_value_type, $prop_name, $var_id); } if (!$assigned_properties) { return; } if ($assignment_value_type->hasMixed()) { return; } $invalid_assignment_value_types = []; $has_valid_assignment_value_type = \false; if ($codebase->store_node_types && !$context->collect_initializations && !$context->collect_mutations && count($assigned_properties) === 1) { $codebase->analyzer->addNodeType($statements_analyzer->getFilePath(), $stmt->name, $assigned_properties[0]->property_type->getId()); } foreach ($assigned_properties as $assigned_property) { $class_property_type = $assigned_property->property_type; $assignment_type = $assigned_property->assignment_type; if ($class_property_type->hasMixed()) { continue; } $union_comparison_results = new TypeComparisonResult(); $type_match_found = UnionTypeComparator::isContainedBy($codebase, $assignment_type, $class_property_type, \true, \true, $union_comparison_results); if ($type_match_found && $union_comparison_results->replacement_union_type) { if ($var_id) { $context->vars_in_scope[$var_id] = $union_comparison_results->replacement_union_type; } } if ($union_comparison_results->type_coerced) { if ($union_comparison_results->type_coerced_from_mixed) { IssueBuffer::maybeAdd(new MixedPropertyTypeCoercion($var_id . ' expects \'' . $class_property_type->getId() . '\', ' . ' parent type `' . $assignment_type->getId() . '` provided', new CodeLocation($statements_analyzer->getSource(), $assignment_value ?? $stmt, $context->include_location), $assigned_property->id), $statements_analyzer->getSuppressedIssues()); } else { IssueBuffer::maybeAdd(new PropertyTypeCoercion($var_id . ' expects \'' . $class_property_type->getId() . '\', ' . ' parent type \'' . $assignment_type->getId() . '\' provided', new CodeLocation($statements_analyzer->getSource(), $assignment_value ?? $stmt, $context->include_location), $assigned_property->id), $statements_analyzer->getSuppressedIssues()); } } if ($union_comparison_results->to_string_cast) { IssueBuffer::maybeAdd(new ImplicitToStringCast($var_id . ' expects \'' . $class_property_type . '\', ' . '\'' . $assignment_type . '\' provided with a __toString method', new CodeLocation($statements_analyzer->getSource(), $assignment_value ?? $stmt, $context->include_location)), $statements_analyzer->getSuppressedIssues()); } if (!$type_match_found && !$union_comparison_results->type_coerced) { if (UnionTypeComparator::canBeContainedBy($codebase, $assignment_type, $class_property_type, \true, \true)) { $has_valid_assignment_value_type = \true; } $invalid_assignment_value_types[$assigned_property->id] = $class_property_type->getId(); } else { $has_valid_assignment_value_type = \true; } if ($type_match_found) { if (!$assignment_type->ignore_nullable_issues && $assignment_type->isNullable() && !$class_property_type->isNullable()) { if (IssueBuffer::accepts(new PossiblyNullPropertyAssignmentValue($var_id . ' with non-nullable declared type \'' . $class_property_type . '\' cannot be assigned nullable type \'' . $assignment_type . '\'', new CodeLocation($statements_analyzer->getSource(), $assignment_value ?? $stmt, $context->include_location), $assigned_property->id), $statements_analyzer->getSuppressedIssues())) { return; } } if (!$assignment_type->ignore_falsable_issues && $assignment_type->isFalsable() && !$class_property_type->hasBool() && !$class_property_type->hasScalar()) { if (IssueBuffer::accepts(new PossiblyFalsePropertyAssignmentValue($var_id . ' with non-falsable declared type \'' . $class_property_type . '\' cannot be assigned possibly false type \'' . $assignment_type . '\'', new CodeLocation($statements_analyzer->getSource(), $assignment_value ?? $stmt, $context->include_location), $assigned_property->id), $statements_analyzer->getSuppressedIssues())) { return; } } } } foreach ($invalid_assignment_value_types as $property_id => $invalid_class_property_type) { if (!$has_valid_assignment_value_type) { if (IssueBuffer::accepts(new InvalidPropertyAssignmentValue($var_id . ' with declared type \'' . $invalid_class_property_type . '\' cannot be assigned type \'' . $assignment_value_type->getId() . '\'', new CodeLocation($statements_analyzer->getSource(), $assignment_value ?? $stmt, $context->include_location), $property_id), $statements_analyzer->getSuppressedIssues())) { return; } } else { if (IssueBuffer::accepts(new PossiblyInvalidPropertyAssignmentValue($var_id . ' with declared type \'' . $invalid_class_property_type . '\' cannot be assigned possibly different type \'' . $assignment_value_type->getId() . '\'', new CodeLocation($statements_analyzer->getSource(), $assignment_value ?? $stmt, $context->include_location), $property_id), $statements_analyzer->getSuppressedIssues())) { return; } } } } public static function trackPropertyImpurity(StatementsAnalyzer $statements_analyzer, PhpParser\Node\Expr\PropertyFetch $stmt, string $property_id, PropertyStorage $property_storage, ClassLikeStorage $declaring_class_storage, Context $context) : void { $codebase = $statements_analyzer->getCodebase(); $stmt_var_type = $statements_analyzer->node_data->getType($stmt->var); $property_var_pure_compatible = $stmt_var_type && $stmt_var_type->reference_free && $stmt_var_type->allow_mutations; $appearing_property_class = $codebase->properties->getAppearingClassForProperty($property_id, \true); $project_analyzer = $statements_analyzer->getProjectAnalyzer(); if ($appearing_property_class && ($property_storage->readonly || $codebase->alter_code)) { $can_set_readonly_property = $context->self && $context->calling_method_id && ($appearing_property_class === $context->self || $codebase->classExtends($context->self, $appearing_property_class)) && (strpos($context->calling_method_id, '::__construct') || strpos($context->calling_method_id, '::unserialize') || strpos($context->calling_method_id, '::__unserialize') || strpos($context->calling_method_id, '::__clone') || $property_storage->allow_private_mutation || $property_var_pure_compatible); if (!$can_set_readonly_property) { if ($property_storage->readonly) { IssueBuffer::maybeAdd(new InaccessibleProperty($property_id . ' is marked readonly', new CodeLocation($statements_analyzer->getSource(), $stmt)), $statements_analyzer->getSuppressedIssues()); } elseif (!$declaring_class_storage->mutation_free && isset($project_analyzer->getIssuesToFix()['MissingImmutableAnnotation']) && $statements_analyzer->getSource() instanceof FunctionLikeAnalyzer) { $codebase->analyzer->addMutableClass($declaring_class_storage->name); } } } } public static function analyzeStatement(StatementsAnalyzer $statements_analyzer, PhpParser\Node\Stmt\Property $stmt, Context $context) : void { foreach ($stmt->props as $prop) { if ($prop->default) { if ($stmt->isReadonly()) { IssueBuffer::maybeAdd(new InvalidPropertyAssignment('Readonly property ' . $context->self . '::$' . $prop->name->name . ' cannot have a default', new CodeLocation($statements_analyzer->getSource(), $prop->default))); } ExpressionAnalyzer::analyze($statements_analyzer, $prop->default, $context); if ($prop_default_type = $statements_analyzer->node_data->getType($prop->default)) { self::analyze($statements_analyzer, $prop, $prop->name->name, $prop->default, $prop_default_type, $context); } } } } private static function taintProperty(StatementsAnalyzer $statements_analyzer, PhpParser\Node\Expr\PropertyFetch $stmt, string $property_id, ClassLikeStorage $class_storage, Union &$assignment_value_type, Context $context) : void { if (!$statements_analyzer->data_flow_graph) { return; } $codebase = $statements_analyzer->getCodebase(); $data_flow_graph = $statements_analyzer->data_flow_graph; if ($class_storage->specialize_instance) { $var_id = ExpressionIdentifier::getExtendedVarId($stmt->var, null, $statements_analyzer); $var_property_id = ExpressionIdentifier::getExtendedVarId($stmt, null, $statements_analyzer); if ($var_id) { if ($statements_analyzer->data_flow_graph instanceof TaintFlowGraph && in_array('TaintedInput', $statements_analyzer->getSuppressedIssues())) { $context->vars_in_scope[$var_id] = $context->vars_in_scope[$var_id]->setParentNodes([]); return; } $var_location = new CodeLocation($statements_analyzer->getSource(), $stmt->var); $var_node = DataFlowNode::getForAssignment($var_id, $var_location); $data_flow_graph->addNode($var_node); $property_location = new CodeLocation($statements_analyzer->getSource(), $stmt); $property_node = DataFlowNode::getForAssignment($var_property_id ?: $var_id . '->$property', $property_location); $data_flow_graph->addNode($property_node); $event = new AddRemoveTaintsEvent($stmt, $context, $statements_analyzer, $codebase); $added_taints = $codebase->config->eventDispatcher->dispatchAddTaints($event); $removed_taints = $codebase->config->eventDispatcher->dispatchRemoveTaints($event); $data_flow_graph->addPath($property_node, $var_node, 'property-assignment' . ($stmt->name instanceof PhpParser\Node\Identifier ? '-' . $stmt->name : ''), $added_taints, $removed_taints); if ($assignment_value_type->parent_nodes) { foreach ($assignment_value_type->parent_nodes as $parent_node) { $data_flow_graph->addPath($parent_node, $property_node, '=', $added_taints, $removed_taints); } } if (isset($context->vars_in_scope[$var_id])) { $stmt_var_type = $context->vars_in_scope[$var_id]->setParentNodes([$var_node->id => $var_node]); if ($context->vars_in_scope[$var_id]->parent_nodes) { foreach ($context->vars_in_scope[$var_id]->parent_nodes as $parent_node) { $data_flow_graph->addPath($parent_node, $var_node, '=', $added_taints, $removed_taints); } } $context->vars_in_scope[$var_id] = $stmt_var_type; } } } else { if ($statements_analyzer->data_flow_graph instanceof TaintFlowGraph && in_array('TaintedInput', $statements_analyzer->getSuppressedIssues())) { $assignment_value_type = $assignment_value_type->setParentNodes([]); return; } $var_property_id = ExpressionIdentifier::getExtendedVarId($stmt, null, $statements_analyzer); self::taintUnspecializedProperty($statements_analyzer, $stmt, $property_id, $class_storage, $assignment_value_type, $context, $var_property_id); } } public static function taintUnspecializedProperty(StatementsAnalyzer $statements_analyzer, PhpParser\Node\Expr $stmt, string $property_id, ClassLikeStorage $class_storage, Union $assignment_value_type, Context $context, ?string $var_property_id) : void { $codebase = $statements_analyzer->getCodebase(); $data_flow_graph = $statements_analyzer->data_flow_graph; if (!$data_flow_graph) { return; } $property_location = new CodeLocation($statements_analyzer->getSource(), $stmt); $localized_property_node = DataFlowNode::getForAssignment($var_property_id ?: $property_id, $property_location); $data_flow_graph->addNode($localized_property_node); $property_node = new DataFlowNode($property_id, $property_id, null, null); $data_flow_graph->addNode($property_node); $event = new AddRemoveTaintsEvent($stmt, $context, $statements_analyzer, $codebase); $added_taints = $codebase->config->eventDispatcher->dispatchAddTaints($event); $removed_taints = $codebase->config->eventDispatcher->dispatchRemoveTaints($event); $data_flow_graph->addPath($localized_property_node, $property_node, 'property-assignment', $added_taints, $removed_taints); if ($assignment_value_type->parent_nodes) { foreach ($assignment_value_type->parent_nodes as $parent_node) { $data_flow_graph->addPath($parent_node, $localized_property_node, '=', $added_taints, $removed_taints); } } $declaring_property_class = $codebase->properties->getDeclaringClassForProperty($property_id, \false, $statements_analyzer); if ($statements_analyzer->data_flow_graph instanceof TaintFlowGraph && $declaring_property_class && $declaring_property_class !== $class_storage->name && ($stmt instanceof PhpParser\Node\Expr\PropertyFetch || $stmt instanceof PhpParser\Node\Expr\StaticPropertyFetch) && $stmt->name instanceof PhpParser\Node\Identifier) { $declaring_property_node = new DataFlowNode($declaring_property_class . '::$' . $stmt->name, $declaring_property_class . '::$' . $stmt->name, null, null); $data_flow_graph->addNode($declaring_property_node); $data_flow_graph->addPath($property_node, $declaring_property_node, 'property-assignment', $added_taints, $removed_taints); } } /** * @return list */ private static function analyzeRegularAssignment(StatementsAnalyzer $statements_analyzer, PropertyFetch $stmt, ?PhpParser\Node\Expr $assignment_value, Context $context, bool $direct_assignment, Codebase $codebase, Union $assignment_value_type, string $prop_name, ?string &$var_id) : array { $was_inside_general_use = $context->inside_general_use; $context->inside_general_use = \true; ExpressionAnalyzer::analyze($statements_analyzer, $stmt->var, $context); $context->inside_general_use = $was_inside_general_use; $lhs_type = $statements_analyzer->node_data->getType($stmt->var); if ($lhs_type === null) { return []; } $lhs_var_id = ExpressionIdentifier::getVarId($stmt->var, $statements_analyzer->getFQCLN(), $statements_analyzer); $var_id = ExpressionIdentifier::getVarId($stmt, $statements_analyzer->getFQCLN(), $statements_analyzer); if ($var_id) { $context->assigned_var_ids[$var_id] = (int) $stmt->var->getAttribute('startFilePos'); if ($direct_assignment && isset($context->protected_var_ids[$var_id])) { IssueBuffer::maybeAdd(new LoopInvalidation('Variable ' . $var_id . ' has already been assigned in a for/foreach loop', new CodeLocation($statements_analyzer->getSource(), $stmt->var)), $statements_analyzer->getSuppressedIssues()); } } if ($lhs_type->hasMixed()) { if (!$context->collect_initializations && !$context->collect_mutations && $statements_analyzer->getFilePath() === $statements_analyzer->getRootFilePath() && (!($parent_source = $statements_analyzer->getSource()) instanceof FunctionLikeAnalyzer || !$parent_source->getSource() instanceof TraitAnalyzer)) { $codebase->analyzer->incrementMixedCount($statements_analyzer->getFilePath()); } if ($stmt->name instanceof PhpParser\Node\Identifier) { $codebase->analyzer->addMixedMemberName('$' . $stmt->name->name, $context->calling_method_id ?: $statements_analyzer->getFileName()); } IssueBuffer::maybeAdd(new MixedPropertyAssignment($lhs_var_id . ' of type mixed cannot be assigned to', new CodeLocation($statements_analyzer->getSource(), $stmt->var)), $statements_analyzer->getSuppressedIssues()); return []; } if (!$context->collect_initializations && !$context->collect_mutations && $statements_analyzer->getFilePath() === $statements_analyzer->getRootFilePath() && (!($parent_source = $statements_analyzer->getSource()) instanceof FunctionLikeAnalyzer || !$parent_source->getSource() instanceof TraitAnalyzer)) { $codebase->analyzer->incrementNonMixedCount($statements_analyzer->getFilePath()); } if ($lhs_type->isNull()) { IssueBuffer::maybeAdd(new NullPropertyAssignment($lhs_var_id . ' of type null cannot be assigned to', new CodeLocation($statements_analyzer->getSource(), $stmt->var)), $statements_analyzer->getSuppressedIssues()); return []; } if ($lhs_type->isNullable() && !$lhs_type->ignore_nullable_issues) { IssueBuffer::maybeAdd(new PossiblyNullPropertyAssignment($lhs_var_id . ' with possibly null type \'' . $lhs_type . '\' cannot be assigned to', new CodeLocation($statements_analyzer->getSource(), $stmt->var)), $statements_analyzer->getSuppressedIssues()); } $has_regular_setter = \false; $invalid_assignment_types = []; $has_valid_assignment_type = \false; $lhs_atomic_types = $lhs_type->getAtomicTypes(); $assigned_properties = []; $context_type = null; while ($lhs_atomic_types) { $lhs_type_part = array_pop($lhs_atomic_types); if ($lhs_type_part instanceof TTemplateParam) { $lhs_atomic_types = array_merge($lhs_atomic_types, $lhs_type_part->as->getAtomicTypes()); continue; } $assigned_property = self::analyzeAtomicAssignment($statements_analyzer, $codebase, $stmt, $assignment_value, $prop_name, $context, $lhs_type, $lhs_type_part, $invalid_assignment_types, $var_id, $assignment_value_type, $lhs_var_id, $has_valid_assignment_type, $has_regular_setter); if ($assigned_property) { $assigned_properties[] = $assigned_property; if ($context_type) { $context_type = Type::combineUnionTypes($context_type, $assigned_property->assignment_type, $codebase); } else { $context_type = $assigned_property->assignment_type; } } } if ($invalid_assignment_types) { $invalid_assignment_type = $invalid_assignment_types[0]; if (!$has_valid_assignment_type) { IssueBuffer::maybeAdd(new InvalidPropertyAssignment($lhs_var_id . ' with non-object type \'' . $invalid_assignment_type . '\' cannot treated as an object', new CodeLocation($statements_analyzer->getSource(), $stmt->var)), $statements_analyzer->getSuppressedIssues()); } else { IssueBuffer::maybeAdd(new PossiblyInvalidPropertyAssignment($lhs_var_id . ' with possible non-object type \'' . $invalid_assignment_type . '\' cannot treated as an object', new CodeLocation($statements_analyzer->getSource(), $stmt->var)), $statements_analyzer->getSuppressedIssues()); } } if (!$has_regular_setter) { return []; } $context_type = $context_type ?: $assignment_value_type; if ($var_id) { if ($context->collect_initializations && $lhs_var_id === '$this') { $context_type = $context_type->setProperties(['initialized_class' => $context->self]); } // because we don't want to be assigning for property declarations $context->vars_in_scope[$var_id] = $context_type; } return $assigned_properties; } /** * @param list $invalid_assignment_types * @psalm-suppress ComplexMethod Unavoidably complex method */ private static function analyzeAtomicAssignment(StatementsAnalyzer $statements_analyzer, Codebase $codebase, PropertyFetch $stmt, ?PhpParser\Node\Expr $assignment_value, string $prop_name, Context $context, Union $lhs_type, Atomic $lhs_type_part, array &$invalid_assignment_types, ?string $var_id, Union $assignment_value_type, ?string $lhs_var_id, bool &$has_valid_assignment_type, bool &$has_regular_setter) : ?\Psalm\Internal\Analyzer\Statements\Expression\Assignment\AssignedProperty { if ($lhs_type_part instanceof TNull) { return null; } if ($lhs_type_part instanceof TFalse && $lhs_type->ignore_falsable_issues && count($lhs_type->getAtomicTypes()) > 1) { return null; } if (!$lhs_type_part instanceof TObject && !$lhs_type_part instanceof TNamedObject) { $invalid_assignment_types[] = (string) $lhs_type_part; return null; } $has_valid_assignment_type = \true; // stdClass and SimpleXMLElement are special cases where we cannot infer the return types // but we don't want to throw an error // Hack has a similar issue: https://github.com/facebook/hhvm/issues/5164 if ($lhs_type_part instanceof TObject || in_array(strtolower($lhs_type_part->value), Config::getInstance()->getUniversalObjectCrates() + ['dateinterval', 'domdocument', 'domnode'], \true)) { if ($var_id) { if ($lhs_type_part instanceof TNamedObject && strtolower($lhs_type_part->value) === 'stdclass') { $context->vars_in_scope[$var_id] = $assignment_value_type; } else { $context->vars_in_scope[$var_id] = Type::getMixed(); } } return null; } if (ExpressionAnalyzer::isMock($lhs_type_part->value)) { if ($var_id) { $context->vars_in_scope[$var_id] = Type::getMixed(); } return null; } $intersection_types = $lhs_type_part->getIntersectionTypes() ?: []; $fq_class_name = $lhs_type_part->value; $override_property_visibility = \false; $class_exists = \false; $interface_exists = \false; if (!$codebase->classExists($lhs_type_part->value)) { if ($codebase->interfaceExists($lhs_type_part->value)) { $interface_exists = \true; $interface_storage = $codebase->classlike_storage_provider->get(strtolower($lhs_type_part->value)); $override_property_visibility = $interface_storage->override_property_visibility; foreach ($intersection_types as $intersection_type) { if ($intersection_type instanceof TNamedObject && $codebase->classExists($intersection_type->value)) { $fq_class_name = $intersection_type->value; $class_exists = \true; break; } } if (!$class_exists) { if (IssueBuffer::accepts(new NoInterfaceProperties('Interfaces cannot have properties', new CodeLocation($statements_analyzer->getSource(), $stmt), $lhs_type_part->value), $statements_analyzer->getSuppressedIssues())) { return null; } if (!$codebase->methods->methodExists(new MethodIdentifier($fq_class_name, '__set'))) { return null; } } } if (!$class_exists && !$interface_exists) { IssueBuffer::maybeAdd(new UndefinedClass('Cannot set properties of undefined class ' . $lhs_type_part->value, new CodeLocation($statements_analyzer->getSource(), $stmt), $lhs_type_part->value), $statements_analyzer->getSuppressedIssues()); return null; } } else { $class_exists = \true; } $property_id = $fq_class_name . '::$' . $prop_name; $has_magic_setter = \false; $set_method_id = new MethodIdentifier($fq_class_name, '__set'); if ((!$codebase->properties->propertyExists($property_id, \false, $statements_analyzer, $context) || $lhs_var_id !== '$this' && $fq_class_name !== $context->self && ClassLikeAnalyzer::checkPropertyVisibility($property_id, $context, $statements_analyzer, new CodeLocation($statements_analyzer->getSource(), $stmt), $statements_analyzer->getSuppressedIssues(), \false) !== \true) && $codebase->methods->methodExists($set_method_id, $context->calling_method_id, $codebase->collect_locations ? new CodeLocation($statements_analyzer->getSource(), $stmt) : null, !$context->collect_initializations && !$context->collect_mutations ? $statements_analyzer : null, $statements_analyzer->getFilePath())) { $has_magic_setter = \true; $class_storage = $codebase->classlike_storage_provider->get($fq_class_name); if ($var_id) { if (isset($class_storage->pseudo_property_set_types['$' . $prop_name])) { $class_property_type = TypeExpander::expandUnion($codebase, $class_storage->pseudo_property_set_types['$' . $prop_name], $fq_class_name, $fq_class_name, $class_storage->parent_class); $has_regular_setter = \true; if (!$context->collect_initializations && !$context->collect_mutations) { self::taintProperty($statements_analyzer, $stmt, $property_id, $class_storage, $assignment_value_type, $context); } return new \Psalm\Internal\Analyzer\Statements\Expression\Assignment\AssignedProperty($class_property_type, $property_id, $assignment_value_type); } } if ($assignment_value) { self::analyzeSetCall($var_id, $context, $statements_analyzer, $stmt, $prop_name, $assignment_value); } /* * If we have an explicit list of all allowed magic properties on the class, and we're * not in that list, fall through */ if (!$class_storage->hasSealedProperties($codebase->config)) { if (!$context->collect_initializations && !$context->collect_mutations) { self::taintProperty($statements_analyzer, $stmt, $property_id, $class_storage, $assignment_value_type, $context); } return null; } if (!$class_exists) { IssueBuffer::maybeAdd(new UndefinedMagicPropertyAssignment('Magic instance property ' . $property_id . ' is not defined', new CodeLocation($statements_analyzer->getSource(), $stmt), $property_id), $statements_analyzer->getSuppressedIssues()); } } if (!$class_exists) { return null; } $has_regular_setter = \true; if ($stmt->var instanceof PhpParser\Node\Expr\Variable && $stmt->var->name === 'this' && $context->self) { $self_property_id = $context->self . '::$' . $prop_name; if ($self_property_id !== $property_id && $codebase->properties->propertyExists($self_property_id, \false, $statements_analyzer, $context)) { $property_id = $self_property_id; } } if ($statements_analyzer->data_flow_graph && !$context->collect_initializations && !$context->collect_mutations) { $class_storage = $codebase->classlike_storage_provider->get($fq_class_name); self::taintProperty($statements_analyzer, $stmt, $property_id, $class_storage, $assignment_value_type, $context); } if (!$codebase->properties->propertyExists($property_id, \false, $statements_analyzer, $context, new CodeLocation($statements_analyzer->getSource(), $stmt)) || $codebase->properties->hasStorage($property_id) && $codebase->properties->getStorage($property_id)->is_static) { if ($stmt->var instanceof PhpParser\Node\Expr\Variable && $stmt->var->name === 'this') { // if this is a proper error, we'll see it on the first pass if ($context->collect_mutations) { return null; } IssueBuffer::maybeAdd(new UndefinedThisPropertyAssignment('Instance property ' . $property_id . ' is not defined', new CodeLocation($statements_analyzer->getSource(), $stmt), $property_id), $statements_analyzer->getSuppressedIssues()); } else { if ($has_magic_setter) { IssueBuffer::maybeAdd(new UndefinedMagicPropertyAssignment('Magic instance property ' . $property_id . ' is not defined', new CodeLocation($statements_analyzer->getSource(), $stmt), $property_id), $statements_analyzer->getSuppressedIssues()); } else { IssueBuffer::maybeAdd(new UndefinedPropertyAssignment('Instance property ' . $property_id . ' is not defined', new CodeLocation($statements_analyzer->getSource(), $stmt), $property_id), $statements_analyzer->getSuppressedIssues()); } } return null; } if ($codebase->store_node_types && !$context->collect_initializations && !$context->collect_mutations) { $codebase->analyzer->addNodeReference($statements_analyzer->getFilePath(), $stmt->name, $property_id); } if (!$override_property_visibility) { if (!$context->collect_mutations) { if (ClassLikeAnalyzer::checkPropertyVisibility($property_id, $context, $statements_analyzer, new CodeLocation($statements_analyzer->getSource(), $stmt), $statements_analyzer->getSuppressedIssues()) === \false) { return null; } } else { if (ClassLikeAnalyzer::checkPropertyVisibility($property_id, $context, $statements_analyzer, new CodeLocation($statements_analyzer->getSource(), $stmt), $statements_analyzer->getSuppressedIssues(), \false) !== \true) { return null; } } } $declaring_property_class = (string) $codebase->properties->getDeclaringClassForProperty($property_id, \false); self::handlePropertyRenames($codebase, $declaring_property_class, $prop_name, $stmt, $statements_analyzer->getFilePath()); $declaring_class_storage = $codebase->classlike_storage_provider->get($declaring_property_class); if (isset($declaring_class_storage->properties[$prop_name])) { $property_storage = $declaring_class_storage->properties[$prop_name]; if ($property_storage->deprecated) { IssueBuffer::maybeAdd(new DeprecatedProperty($property_id . ' is marked deprecated', new CodeLocation($statements_analyzer->getSource(), $stmt), $property_id), $statements_analyzer->getSuppressedIssues()); } if ($context->self && !NamespaceAnalyzer::isWithinAny($context->self, $property_storage->internal)) { IssueBuffer::maybeAdd(new InternalProperty($property_id . ' is internal to ' . InternalClass::listToPhrase($property_storage->internal) . ' but called from ' . $context->self, new CodeLocation($statements_analyzer->getSource(), $stmt), $property_id), $statements_analyzer->getSuppressedIssues()); } self::trackPropertyImpurity($statements_analyzer, $stmt, $property_id, $property_storage, $declaring_class_storage, $context); if (!$property_storage->readonly && !$context->collect_mutations && !$context->collect_initializations && isset($context->vars_in_scope[$lhs_var_id]) && !$context->vars_in_scope[$lhs_var_id]->allow_mutations) { if ($context->mutation_free) { IssueBuffer::maybeAdd(new ImpurePropertyAssignment('Cannot assign to a property from a mutation-free context', new CodeLocation($statements_analyzer, $stmt)), $statements_analyzer->getSuppressedIssues()); } elseif ($statements_analyzer->getSource() instanceof FunctionLikeAnalyzer && $statements_analyzer->getSource()->track_mutations) { $statements_analyzer->getSource()->inferred_impure = \true; } } if ($property_storage->getter_method) { $getter_id = $lhs_var_id . '->' . $property_storage->getter_method . '()'; unset($context->vars_in_scope[$getter_id]); } } $class_property_type = $codebase->properties->getPropertyType($property_id, \true, $statements_analyzer, $context); if (!$class_property_type || isset($declaring_class_storage->properties[$prop_name]) && !$declaring_class_storage->properties[$prop_name]->type_location) { if (!$class_property_type) { $class_property_type = Type::getMixed(); } $source_analyzer = $statements_analyzer->getSource()->getSource(); if ($lhs_var_id === '$this' && $source_analyzer instanceof ClassAnalyzer) { $source_analyzer->inferred_property_types[$prop_name] = Type::combineUnionTypes($assignment_value_type, $source_analyzer->inferred_property_types[$prop_name] ?? null); } } if (!$class_property_type->isMixed()) { $class_storage = $codebase->classlike_storage_provider->get($fq_class_name); $class_property_type = TypeExpander::expandUnion($codebase, $class_property_type, $fq_class_name, $lhs_type_part, $declaring_class_storage->parent_class, \true, \false, $class_storage->final); $class_property_type = Methods::localizeType($codebase, $class_property_type, $fq_class_name, $declaring_property_class); if ($lhs_type_part instanceof TGenericObject) { $class_property_type = AtomicPropertyFetchAnalyzer::localizePropertyType($codebase, $class_property_type, $lhs_type_part, $class_storage, $declaring_class_storage); } $assignment_value_type = Methods::localizeType($codebase, $assignment_value_type, $fq_class_name, $declaring_property_class); if (!$class_property_type->hasMixed() && $assignment_value_type->hasMixed()) { $origin_locations = []; if ($statements_analyzer->data_flow_graph instanceof VariableUseGraph) { foreach ($assignment_value_type->parent_nodes as $parent_node) { $origin_locations = [...$origin_locations, ...$statements_analyzer->data_flow_graph->getOriginLocations($parent_node)]; } } $origin_location = count($origin_locations) === 1 ? reset($origin_locations) : null; $message = $var_id ? 'Unable to determine the type that ' . $var_id . ' is being assigned to' : 'Unable to determine the type of this assignment'; if ($origin_location && $origin_location->getLineNumber() === $stmt->getLine()) { $origin_location = null; } IssueBuffer::maybeAdd(new MixedAssignment($message, new CodeLocation($statements_analyzer->getSource(), $stmt), $origin_location), $statements_analyzer->getSuppressedIssues()); } } return new \Psalm\Internal\Analyzer\Statements\Expression\Assignment\AssignedProperty($class_property_type, $property_id, $assignment_value_type); } private static function handlePropertyRenames(Codebase $codebase, string $declaring_property_class, string $prop_name, PropertyFetch $stmt, string $file_path) : void { if (!$codebase->properties_to_rename) { return; } $declaring_property_id = strtolower($declaring_property_class) . '::$' . $prop_name; foreach ($codebase->properties_to_rename as $original_property_id => $new_property_name) { if ($declaring_property_id === $original_property_id) { $file_manipulations = [new FileManipulation((int) $stmt->name->getAttribute('startFilePos'), (int) $stmt->name->getAttribute('endFilePos') + 1, $new_property_name)]; FileManipulationBuffer::add($file_path, $file_manipulations); } } } public static function getExpandedPropertyType(Codebase $codebase, string $fq_class_name, string $property_name, ClassLikeStorage $storage) : ?Union { $property_class_name = $codebase->properties->getDeclaringClassForProperty($fq_class_name . '::$' . $property_name, \true); if ($property_class_name === null) { return null; } $property_class_storage = $codebase->classlike_storage_provider->get($property_class_name); $property_storage = $property_class_storage->properties[$property_name]; if (!$property_storage->type) { return null; } $property_type = $property_storage->type; $fleshed_out_type = !$property_type->isMixed() ? TypeExpander::expandUnion($codebase, $property_type, $fq_class_name, $fq_class_name, $storage->parent_class, \true, \false, $storage->final) : $property_type; $class_template_params = ClassTemplateParamCollector::collect($codebase, $property_class_storage, $storage, null, new TNamedObject($fq_class_name), \true); $template_result = new TemplateResult($class_template_params ?: [], []); if ($class_template_params) { $fleshed_out_type = TemplateStandinTypeReplacer::replace($fleshed_out_type, $template_result, $codebase, null, null, null); } return $fleshed_out_type; } private static function analyzeSetCall(?string $var_id, Context $context, StatementsAnalyzer $statements_analyzer, PropertyFetch $stmt, string $prop_name, Expr $assignment_value) : void { if ($var_id) { $context->removeVarFromConflictingClauses($var_id, Type::getMixed(), $statements_analyzer); $context->removePossibleReference($var_id); } $old_data_provider = $statements_analyzer->node_data; $statements_analyzer->node_data = clone $statements_analyzer->node_data; $fake_method_call = new VirtualMethodCall($stmt->var, new VirtualIdentifier('__set', $stmt->name->getAttributes()), [new VirtualArg(new VirtualString($prop_name, $stmt->name->getAttributes())), new VirtualArg($assignment_value)]); $suppressed_issues = $statements_analyzer->getSuppressedIssues(); if (!in_array('PossiblyNullReference', $suppressed_issues, \true)) { $statements_analyzer->addSuppressedIssues(['PossiblyNullReference']); } MethodCallAnalyzer::analyze($statements_analyzer, $fake_method_call, $context, \false); if (!in_array('PossiblyNullReference', $suppressed_issues, \true)) { $statements_analyzer->removeSuppressedIssues(['PossiblyNullReference']); } $statements_analyzer->node_data = $old_data_provider; } } var, $statements_analyzer->getFQCLN(), $statements_analyzer, $nesting); self::updateArrayType($statements_analyzer, $stmt, $assign_value, $assignment_value_type, $context); if (!$statements_analyzer->node_data->getType($stmt->var) && $var_id) { $context->vars_in_scope[$var_id] = Type::getMixed(); } } /** * @return false|null * @psalm-suppress PossiblyUnusedReturnValue not used but seems important */ public static function updateArrayType(StatementsAnalyzer $statements_analyzer, PhpParser\Node\Expr\ArrayDimFetch $stmt, ?PhpParser\Node\Expr $assign_value, Union $assignment_type, Context $context) : ?bool { $root_array_expr = $stmt; $child_stmts = []; while ($root_array_expr->var instanceof PhpParser\Node\Expr\ArrayDimFetch) { $child_stmts[] = $root_array_expr; $root_array_expr = $root_array_expr->var; } $child_stmts[] = $root_array_expr; $root_array_expr = $root_array_expr->var; ExpressionAnalyzer::analyze($statements_analyzer, $root_array_expr, $context, \true); $codebase = $statements_analyzer->getCodebase(); $root_type = $statements_analyzer->node_data->getType($root_array_expr) ?? Type::getMixed(); if ($root_type->hasMixed()) { ExpressionAnalyzer::analyze($statements_analyzer, $stmt->var, $context, \true); if ($stmt->dim) { ExpressionAnalyzer::analyze($statements_analyzer, $stmt->dim, $context); } } $current_type = $root_type; $current_dim = $stmt->dim; // gets a variable id that *may* contain array keys $root_var_id = ExpressionIdentifier::getExtendedVarId($root_array_expr, $statements_analyzer->getFQCLN(), $statements_analyzer); $parent_var_id = null; $offset_already_existed = \false; self::analyzeNestedArrayAssignment($statements_analyzer, $codebase, $context, $assign_value, $assignment_type, $child_stmts, $root_var_id, $parent_var_id, $root_type, $current_type, $current_dim, $offset_already_existed); $root_is_string = $root_type->isString(); $key_values = []; if ($current_dim instanceof PhpParser\Node\Scalar\String_) { $value_type = Type::getAtomicStringFromLiteral($current_dim->value); if ($value_type instanceof TLiteralString) { $key_values[] = $value_type; } } elseif ($current_dim instanceof PhpParser\Node\Scalar\LNumber && !$root_is_string) { $key_values[] = new TLiteralInt($current_dim->value); } elseif ($current_dim && ($key_type = $statements_analyzer->node_data->getType($current_dim)) && !$root_is_string) { $string_literals = $key_type->getLiteralStrings(); $int_literals = $key_type->getLiteralInts(); $all_atomic_types = $key_type->getAtomicTypes(); if (count($string_literals) + count($int_literals) === count($all_atomic_types)) { foreach ($string_literals as $string_literal) { $key_values[] = $string_literal; } foreach ($int_literals as $int_literal) { $key_values[] = $int_literal; } } } if ($key_values) { $new_child_type = self::updateTypeWithKeyValues($codebase, $root_type, $current_type, $key_values); } elseif (!$root_is_string) { $new_child_type = self::updateArrayAssignmentChildType($statements_analyzer, $codebase, $current_dim, $context, $current_type, $root_type, $offset_already_existed, $parent_var_id); } else { $new_child_type = $root_type; } $new_child_type = $new_child_type->getBuilder(); $new_child_type->removeType('null'); $new_child_type = $new_child_type->freeze(); if (!$root_type->hasObjectType()) { $root_type = $new_child_type; } $statements_analyzer->node_data->setType($root_array_expr, $root_type); if ($root_array_expr instanceof PhpParser\Node\Expr\PropertyFetch) { if ($root_array_expr->name instanceof PhpParser\Node\Identifier) { \Psalm\Internal\Analyzer\Statements\Expression\Assignment\InstancePropertyAssignmentAnalyzer::analyze($statements_analyzer, $root_array_expr, $root_array_expr->name->name, null, $root_type, $context, \false); } else { if (ExpressionAnalyzer::analyze($statements_analyzer, $root_array_expr->name, $context) === \false) { return \false; } if (ExpressionAnalyzer::analyze($statements_analyzer, $root_array_expr->var, $context) === \false) { return \false; } } } elseif ($root_array_expr instanceof PhpParser\Node\Expr\StaticPropertyFetch && $root_array_expr->name instanceof PhpParser\Node\Identifier) { if (\Psalm\Internal\Analyzer\Statements\Expression\Assignment\StaticPropertyAssignmentAnalyzer::analyze($statements_analyzer, $root_array_expr, null, $root_type, $context) === \false) { return \false; } } elseif ($root_var_id) { $context->vars_in_scope[$root_var_id] = $root_type; } if ($root_array_expr instanceof PhpParser\Node\Expr\MethodCall || $root_array_expr instanceof PhpParser\Node\Expr\StaticCall || $root_array_expr instanceof PhpParser\Node\Expr\FuncCall) { if ($root_type->hasArray()) { IssueBuffer::maybeAdd(new InvalidArrayAssignment('Assigning to the output of a function has no effect', new CodeLocation($statements_analyzer->getSource(), $root_array_expr)), $statements_analyzer->getSuppressedIssues()); } } return null; } /** * @param non-empty-list $key_values */ private static function updateTypeWithKeyValues(Codebase $codebase, Union $child_stmt_type, Union $current_type, array $key_values) : Union { $has_matching_objectlike_property = \false; $has_matching_string = \false; $changed = \false; $types = []; foreach ($child_stmt_type->getAtomicTypes() as $type) { if ($type instanceof TList) { $type = $type->getKeyedArray(); } $old_type = $type; if ($type instanceof TTemplateParam) { $type = $type->replaceAs(self::updateTypeWithKeyValues($codebase, $type->as, $current_type, $key_values)); $has_matching_objectlike_property = \true; } elseif ($type instanceof TKeyedArray) { $properties = $type->properties; foreach ($key_values as $key_value) { if (isset($properties[$key_value->value])) { $has_matching_objectlike_property = \true; $properties[$key_value->value] = $current_type; } } $type = $type->setProperties($properties); } elseif ($type instanceof TString) { foreach ($key_values as $key_value) { if ($key_value instanceof TLiteralInt) { $has_matching_string = \true; if ($type instanceof TLiteralString && $current_type->isSingleStringLiteral()) { $new_char = $current_type->getSingleStringLiteral()->value; if (strlen($new_char) === 1 && $type->value[0] !== $new_char) { $v = $type->value; $v[0] = $new_char; $changed = \true; $type = Type::getAtomicStringFromLiteral($v); break; } } } } } $types[$type->getKey()] = $type; $changed = $changed || $old_type !== $type; } if ($changed) { $child_stmt_type = $child_stmt_type->getBuilder()->setTypes($types)->freeze(); } if (!$has_matching_objectlike_property && !$has_matching_string) { $properties = []; $classStrings = []; $current_type = $current_type->setPossiblyUndefined($current_type->possibly_undefined || count($key_values) > 1); foreach ($key_values as $key_value) { $properties[$key_value->value] = $current_type; if ($key_value instanceof TLiteralClassString) { $classStrings[$key_value->value] = \true; } } $object_like = new TKeyedArray($properties, $classStrings ?: null); $array_assignment_type = new Union([$object_like]); return Type::combineUnionTypes($child_stmt_type, $array_assignment_type, $codebase, \true, \false); } return $child_stmt_type; } /** * @param list $key_values $key_values */ private static function taintArrayAssignment(StatementsAnalyzer $statements_analyzer, PhpParser\Node\Expr\ArrayDimFetch $expr, Union &$stmt_type, Union $child_stmt_type, ?string $var_var_id, array $key_values) : void { if ($statements_analyzer->data_flow_graph && ($statements_analyzer->data_flow_graph instanceof VariableUseGraph || !in_array('TaintedInput', $statements_analyzer->getSuppressedIssues()))) { $var_location = new CodeLocation($statements_analyzer->getSource(), $expr->var); $parent_node = DataFlowNode::getForAssignment($var_var_id ?: 'assignment', $var_location); $statements_analyzer->data_flow_graph->addNode($parent_node); $old_parent_nodes = $stmt_type->parent_nodes; $stmt_type = $stmt_type->setParentNodes([$parent_node->id => $parent_node]); foreach ($old_parent_nodes as $old_parent_node) { $statements_analyzer->data_flow_graph->addPath($old_parent_node, $parent_node, '='); if ($stmt_type->by_ref) { $statements_analyzer->data_flow_graph->addPath($parent_node, $old_parent_node, '='); } } foreach ($stmt_type->parent_nodes as $parent_node) { foreach ($child_stmt_type->parent_nodes as $child_parent_node) { if ($key_values) { foreach ($key_values as $key_value) { $statements_analyzer->data_flow_graph->addPath($child_parent_node, $parent_node, 'arrayvalue-assignment-\'' . $key_value->value . '\''); } } else { $statements_analyzer->data_flow_graph->addPath($child_parent_node, $parent_node, 'arrayvalue-assignment'); } } } } } private static function updateArrayAssignmentChildType(StatementsAnalyzer $statements_analyzer, Codebase $codebase, ?PhpParser\Node\Expr $current_dim, Context $context, Union $value_type, Union $root_type, bool $offset_already_existed, ?string $parent_var_id) : Union { $templated_assignment = \false; $array_atomic_type_class_string = null; $array_atomic_type_array = null; $array_atomic_type_list = null; if ($current_dim) { $key_type = $statements_analyzer->node_data->getType($current_dim); if ($key_type) { if ($key_type->hasMixed()) { $key_type = Type::getArrayKey(); } if ($key_type->isSingle()) { $key_type_type = $key_type->getSingleAtomic(); if ($key_type_type instanceof TIntRange && $key_type_type->dependent_list_key === $parent_var_id || $key_type_type instanceof TDependentListKey && $key_type_type->var_id === $parent_var_id) { $offset_already_existed = \true; } if ($key_type_type instanceof TTemplateParam && $key_type_type->as->isSingle() && $root_type->isSingle() && $value_type->isSingle()) { $key_type_as_type = $key_type_type->as->getSingleAtomic(); $value_atomic_type = $value_type->getSingleAtomic(); $root_atomic_type = $root_type->getSingleAtomic(); if ($key_type_as_type instanceof TTemplateKeyOf && $root_atomic_type instanceof TTemplateParam && $value_atomic_type instanceof TTemplateIndexedAccess && $key_type_as_type->param_name === $root_atomic_type->param_name && $key_type_as_type->defining_class === $root_atomic_type->defining_class && $value_atomic_type->array_param_name === $root_atomic_type->param_name && $value_atomic_type->offset_param_name === $key_type_type->param_name && $value_atomic_type->defining_class === $root_atomic_type->defining_class) { $templated_assignment = \true; $offset_already_existed = \true; } } } $array_atomic_key_type = ArrayFetchAnalyzer::replaceOffsetTypeWithInts($key_type); } else { $array_atomic_key_type = Type::getArrayKey(); } if ($parent_var_id && ($parent_type = $context->vars_in_scope[$parent_var_id] ?? null)) { if ($offset_already_existed && $parent_type->hasList() && strpos($parent_var_id, '[') === \false) { $array_atomic_type_list = $value_type; } elseif ($parent_type->hasClassStringMap() && $key_type && $key_type->isTemplatedClassString()) { /** * @var TClassStringMap */ $class_string_map = $parent_type->getArray(); /** * @var TTemplateParamClass */ $offset_type_part = $key_type->getSingleAtomic(); $template_result = new TemplateResult([], [$offset_type_part->param_name => [$offset_type_part->defining_class => new Union([new TTemplateParam($class_string_map->param_name, $offset_type_part->as_type ? new Union([$offset_type_part->as_type]) : Type::getObject(), 'class-string-map')])]]); $value_type = TemplateInferredTypeReplacer::replace($value_type, $template_result, $codebase); $array_atomic_type_class_string = new TClassStringMap($class_string_map->param_name, $class_string_map->as_type, $value_type); } else { $array_atomic_type_array = [$array_atomic_key_type, $value_type]; } } else { $array_atomic_type_array = [$array_atomic_key_type, $value_type]; } } else { $array_atomic_type_list = $value_type; } $from_countable_object_like = \false; $new_child_type = null; $array_atomic_type = null; if (!$current_dim && !$context->inside_loop) { $atomic_root_types = $root_type->getAtomicTypes(); if (isset($atomic_root_types['array'])) { $atomic_root_type_array = $atomic_root_types['array']; if ($atomic_root_type_array instanceof TList) { $atomic_root_type_array = $atomic_root_type_array->getKeyedArray(); } if ($array_atomic_type_class_string) { $array_atomic_type = new TNonEmptyArray([$array_atomic_type_class_string->getStandinKeyParam(), $array_atomic_type_class_string->value_param]); } elseif ($atomic_root_type_array instanceof TKeyedArray && $atomic_root_type_array->is_list && $atomic_root_type_array->fallback_params === null) { $array_atomic_type = $atomic_root_type_array; } elseif ($atomic_root_type_array instanceof TNonEmptyArray || $atomic_root_type_array instanceof TKeyedArray && $atomic_root_type_array->is_list && $atomic_root_type_array->isNonEmpty()) { $prop_count = null; if ($atomic_root_type_array instanceof TNonEmptyArray) { $prop_count = $atomic_root_type_array->count; } else { $min_count = $atomic_root_type_array->getMinCount(); if ($min_count === $atomic_root_type_array->getMaxCount()) { $prop_count = $min_count; } } if ($array_atomic_type_array) { $array_atomic_type = new TNonEmptyArray($array_atomic_type_array, $prop_count); } elseif ($prop_count !== null) { assert($array_atomic_type_list !== null); $array_atomic_type = new TKeyedArray(array_fill(0, $prop_count, $array_atomic_type_list), null, [Type::getListKey(), $array_atomic_type_list], \true); } } elseif ($atomic_root_type_array instanceof TKeyedArray && $atomic_root_type_array->fallback_params === null) { if ($array_atomic_type_array) { $array_atomic_type = new TNonEmptyArray($array_atomic_type_array, count($atomic_root_type_array->properties)); } elseif ($atomic_root_type_array->is_list) { $array_atomic_type = $atomic_root_type_array; $new_child_type = new Union([$array_atomic_type], ['parent_nodes' => $root_type->parent_nodes]); } else { assert($array_atomic_type_list !== null); $array_atomic_type = array_fill($atomic_root_type_array->getMinCount(), count($atomic_root_type_array->properties) - 1, $array_atomic_type_list); assert(count($array_atomic_type) > 0); $array_atomic_type = new TKeyedArray($array_atomic_type, null, null, \true); } $from_countable_object_like = \true; } elseif ($array_atomic_type_list) { $array_atomic_type = Type::getNonEmptyListAtomic($array_atomic_type_list); } else { assert($array_atomic_type_array !== null); $array_atomic_type = new TNonEmptyArray($array_atomic_type_array); } } } $array_atomic_type ??= $array_atomic_type_class_string ?? ($array_atomic_type_list !== null ? Type::getNonEmptyListAtomic($array_atomic_type_list) : null) ?? ($array_atomic_type_array !== null ? new TNonEmptyArray($array_atomic_type_array) : null); assert($array_atomic_type !== null); $array_assignment_type = new Union([$array_atomic_type]); if (!$new_child_type) { if ($templated_assignment) { $new_child_type = $root_type; } else { $new_child_type = Type::combineUnionTypes($root_type, $array_assignment_type, $codebase, \true, \true); } } if ($from_countable_object_like) { $atomic_root_types = $new_child_type->getAtomicTypes(); if (isset($atomic_root_types['array'])) { $atomic_root_type_array = $atomic_root_types['array']; if ($atomic_root_type_array instanceof TList) { $atomic_root_type_array = $atomic_root_type_array->getKeyedArray(); } if ($atomic_root_type_array instanceof TNonEmptyArray && $atomic_root_type_array->count !== null) { $atomic_root_types['array'] = $atomic_root_type_array->setCount($atomic_root_type_array->count + 1); $new_child_type = new Union($atomic_root_types); } elseif ($atomic_root_type_array instanceof TKeyedArray && $atomic_root_type_array->is_list) { $properties = $atomic_root_type_array->properties; $had_undefined = \false; foreach ($properties as &$property) { if ($property->possibly_undefined) { $property = $property->setPossiblyUndefined(\true); $had_undefined = \true; break; } } if (!$had_undefined && $atomic_root_type_array->fallback_params) { $properties[] = $atomic_root_type_array->fallback_params[1]; } $atomic_root_types['array'] = $atomic_root_type_array->setProperties($properties); $new_child_type = new Union($atomic_root_types); } } } return $new_child_type; } /** * @param non-empty-list $child_stmts * @param-out PhpParser\Node\Expr $child_stmt */ private static function analyzeNestedArrayAssignment(StatementsAnalyzer $statements_analyzer, Codebase $codebase, Context $context, ?PhpParser\Node\Expr $assign_value, Union $assignment_type, array $child_stmts, ?string $root_var_id, ?string &$parent_var_id, Union &$root_type, Union &$current_type, ?PhpParser\Node\Expr &$current_dim, bool &$offset_already_existed) : void { $var_id_additions = []; $root_var = end($child_stmts)->var; // First go from the root element up, and go as far as we can to figure out what // array types there are foreach (array_reverse($child_stmts) as $i => $child_stmt) { $child_stmt_dim_type = null; $offset_type = null; if ($child_stmt->dim) { $was_inside_general_use = $context->inside_general_use; $context->inside_general_use = \true; if (ExpressionAnalyzer::analyze($statements_analyzer, $child_stmt->dim, $context) === \false) { $context->inside_general_use = $was_inside_general_use; return; } $context->inside_general_use = $was_inside_general_use; if (!($child_stmt_dim_type = $statements_analyzer->node_data->getType($child_stmt->dim))) { return; } [$offset_type, $var_id_addition, $full_var_id] = self::getArrayAssignmentOffsetType($statements_analyzer, $child_stmt, $child_stmt_dim_type); $var_id_additions[] = $var_id_addition; } else { $var_id_additions[] = ''; $full_var_id = \false; } if (!($array_type = $statements_analyzer->node_data->getType($child_stmt->var))) { return; } if ($array_type->isNever()) { $array_type = Type::getEmptyArray(); $statements_analyzer->node_data->setType($child_stmt->var, $array_type); } $extended_var_id = $root_var_id . implode('', $var_id_additions); if ($parent_var_id && isset($context->vars_in_scope[$parent_var_id])) { $array_type = $context->vars_in_scope[$parent_var_id]; $statements_analyzer->node_data->setType($child_stmt->var, $array_type); } $is_last = $i === count($child_stmts) - 1; $child_stmt_dim_type_or_int = $child_stmt_dim_type ?? Type::getInt(); $child_stmt_type = ArrayFetchAnalyzer::getArrayAccessTypeGivenOffset($statements_analyzer, $child_stmt, $array_type, $child_stmt_dim_type_or_int, \true, $extended_var_id, $context, $assign_value, !$is_last ? null : $assignment_type); if ($child_stmt->dim) { $statements_analyzer->node_data->setType($child_stmt->dim, $child_stmt_dim_type_or_int); } $statements_analyzer->node_data->setType($child_stmt, $child_stmt_type); if ($is_last) { // we need this slight hack as the type we're putting it has to be // different from the type we're getting out if ($array_type->isSingle() && $array_type->hasClassStringMap()) { $assignment_type = $child_stmt_type; } $child_stmt_type = $assignment_type; $statements_analyzer->node_data->setType($child_stmt, $assignment_type); if ($statements_analyzer->data_flow_graph) { self::taintArrayAssignment($statements_analyzer, $child_stmt, $array_type, $assignment_type, ExpressionIdentifier::getExtendedVarId($child_stmt->var, $statements_analyzer->getFQCLN(), $statements_analyzer), $offset_type !== null ? [$offset_type] : []); } } $statements_analyzer->node_data->setType($child_stmt->var, $array_type); if ($root_var_id) { if (!$parent_var_id) { $rooted_parent_id = $root_var_id; $root_type = $array_type; } else { $rooted_parent_id = $parent_var_id; } $context->vars_in_scope[$rooted_parent_id] = $array_type; $context->possibly_assigned_var_ids[$rooted_parent_id] = \true; } $current_type = $child_stmt_type; $current_dim = $child_stmt->dim; $parent_var_id = $extended_var_id; } if ($statements_analyzer->data_flow_graph instanceof VariableUseGraph && $root_var_id !== null && isset($context->references_to_external_scope[$root_var_id]) && $root_var instanceof Variable && is_string($root_var->name) && $root_var_id === '$' . $root_var->name) { // Array is a reference to an external scope, mark it as used $statements_analyzer->data_flow_graph->addPath(DataFlowNode::getForAssignment($root_var_id, new CodeLocation($statements_analyzer->getSource(), $root_var)), new DataFlowNode('variable-use', 'variable use', null), 'variable-use'); } if ($root_var_id && $full_var_id && ($child_stmt_var_type = $statements_analyzer->node_data->getType($child_stmt->var)) && !$child_stmt_var_type->hasObjectType()) { $extended_var_id = $root_var_id . implode('', $var_id_additions); $parent_var_id = $root_var_id . implode('', array_slice($var_id_additions, 0, -1)); if (isset($context->vars_in_scope[$extended_var_id]) && !$context->vars_in_scope[$extended_var_id]->possibly_undefined) { $offset_already_existed = \true; } $context->vars_in_scope[$extended_var_id] = $assignment_type; $context->possibly_assigned_var_ids[$extended_var_id] = \true; } array_shift($child_stmts); // only update as many child stmts are we were able to process above foreach ($child_stmts as $child_stmt) { $child_stmt_type = $statements_analyzer->node_data->getType($child_stmt); if (!$child_stmt_type) { throw new InvalidArgumentException('Should never get here'); } $key_values = $current_dim ? self::getDimKeyValues($statements_analyzer, $current_dim) : []; if ($key_values) { $new_child_type = self::updateTypeWithKeyValues($codebase, $child_stmt_type, $current_type, $key_values); } else { if (!$current_dim) { $array_assignment_type = Type::getList($current_type); } else { $key_type = $statements_analyzer->node_data->getType($current_dim); $array_assignment_type = new Union([new TArray([$key_type && !$key_type->hasMixed() ? $key_type : Type::getArrayKey(), $current_type])]); } $new_child_type = Type::combineUnionTypes($child_stmt_type, $array_assignment_type, $codebase, \true, \true); } if ($new_child_type->hasNull() || $new_child_type->possibly_undefined) { $new_child_type = $new_child_type->getBuilder(); $new_child_type->removeType('null'); $new_child_type->possibly_undefined = \false; $new_child_type = $new_child_type->freeze(); } if (!$child_stmt_type->hasObjectType()) { $child_stmt_type = $new_child_type; $statements_analyzer->node_data->setType($child_stmt, $new_child_type); } $current_type = $child_stmt_type; $current_dim = $child_stmt->dim; array_pop($var_id_additions); $parent_array_var_id = null; if ($root_var_id) { $extended_var_id = $root_var_id . implode('', $var_id_additions); $parent_array_var_id = $root_var_id . implode('', array_slice($var_id_additions, 0, -1)); $context->vars_in_scope[$extended_var_id] = $child_stmt_type; $context->possibly_assigned_var_ids[$extended_var_id] = \true; } if ($statements_analyzer->data_flow_graph) { $t_orig = $statements_analyzer->node_data->getType($child_stmt->var); $array_type = $t_orig ?? Type::getMixed(); self::taintArrayAssignment($statements_analyzer, $child_stmt, $array_type, $new_child_type, $parent_array_var_id, $child_stmt->dim ? self::getDimKeyValues($statements_analyzer, $child_stmt->dim) : []); if ($t_orig) { $statements_analyzer->node_data->setType($child_stmt->var, $array_type); } if ($root_var_id) { if ($parent_array_var_id === $root_var_id) { $rooted_parent_id = $root_var_id; $root_type = $array_type; } else { assert($parent_array_var_id !== null); $rooted_parent_id = $parent_array_var_id; } $context->vars_in_scope[$rooted_parent_id] = $array_type; } } } } /** * @return list */ private static function getDimKeyValues(StatementsAnalyzer $statements_analyzer, PhpParser\Node\Expr $dim) : array { $key_values = []; if ($dim instanceof PhpParser\Node\Scalar\String_) { $value_type = Type::getAtomicStringFromLiteral($dim->value); if ($value_type instanceof TLiteralString) { $key_values[] = $value_type; } } elseif ($dim instanceof PhpParser\Node\Scalar\LNumber) { $key_values[] = new TLiteralInt($dim->value); } else { $key_type = $statements_analyzer->node_data->getType($dim); if ($key_type) { $string_literals = $key_type->getLiteralStrings(); $int_literals = $key_type->getLiteralInts(); $all_atomic_types = $key_type->getAtomicTypes(); if (count($string_literals) + count($int_literals) === count($all_atomic_types)) { foreach ($string_literals as $string_literal) { $key_values[] = $string_literal; } foreach ($int_literals as $int_literal) { $key_values[] = $int_literal; } } } } return $key_values; } /** * @return array{TLiteralInt|TLiteralString|null, string, bool} */ private static function getArrayAssignmentOffsetType(StatementsAnalyzer $statements_analyzer, PhpParser\Node\Expr\ArrayDimFetch $child_stmt, Union $child_stmt_dim_type) : array { if ($child_stmt->dim instanceof PhpParser\Node\Scalar\String_ || ($child_stmt->dim instanceof PhpParser\Node\Expr\ConstFetch || $child_stmt->dim instanceof PhpParser\Node\Expr\ClassConstFetch) && $child_stmt_dim_type->isSingleStringLiteral()) { if ($child_stmt->dim instanceof PhpParser\Node\Scalar\String_) { $offset_type = Type::getAtomicStringFromLiteral($child_stmt->dim->value); if (!$offset_type instanceof TLiteralString) { return [null, '[string]', \false]; } } else { $offset_type = $child_stmt_dim_type->getSingleStringLiteral(); } $string_to_int = ArrayAnalyzer::getLiteralArrayKeyInt($offset_type->value); if ($string_to_int !== \false) { $var_id_addition = '[' . $string_to_int . ']'; } else { $var_id_addition = '[\'' . $offset_type->value . '\']'; } return [$offset_type, $var_id_addition, \true]; } if ($child_stmt->dim instanceof PhpParser\Node\Scalar\LNumber || ($child_stmt->dim instanceof PhpParser\Node\Expr\ConstFetch || $child_stmt->dim instanceof PhpParser\Node\Expr\ClassConstFetch) && $child_stmt_dim_type->isSingleIntLiteral()) { if ($child_stmt->dim instanceof PhpParser\Node\Scalar\LNumber) { $offset_type = new TLiteralInt($child_stmt->dim->value); } else { $offset_type = $child_stmt_dim_type->getSingleIntLiteral(); } $var_id_addition = '[' . $offset_type->value . ']'; return [$offset_type, $var_id_addition, \true]; } if ($child_stmt->dim instanceof PhpParser\Node\Expr\Variable && is_string($child_stmt->dim->name)) { $var_id_addition = '[$' . $child_stmt->dim->name . ']'; return [null, $var_id_addition, \true]; } if ($child_stmt->dim instanceof PhpParser\Node\Expr\PropertyFetch && $child_stmt->dim->name instanceof PhpParser\Node\Identifier) { $object_id = ExpressionIdentifier::getExtendedVarId($child_stmt->dim->var, $statements_analyzer->getFQCLN(), $statements_analyzer); if ($object_id) { $var_id_addition = '[' . $object_id . '->' . $child_stmt->dim->name->name . ']'; } else { $var_id_addition = '[' . $child_stmt_dim_type . ']'; } return [null, $var_id_addition, \true]; } if ($child_stmt->dim instanceof PhpParser\Node\Expr\ClassConstFetch && $child_stmt->dim->name instanceof PhpParser\Node\Identifier && $child_stmt->dim->class instanceof PhpParser\Node\Name) { $object_name = ClassLikeAnalyzer::getFQCLNFromNameObject($child_stmt->dim->class, $statements_analyzer->getAliases()); $var_id_addition = '[' . $object_name . '::' . $child_stmt->dim->name->name . ']'; return [null, $var_id_addition, \true]; } $var_id_addition = '[' . $child_stmt_dim_type . ']'; return [null, $var_id_addition, \false]; } } property_type = $property_type; $this->id = $id; $this->assignment_type = $assignment_type; } } expr, $context); $codebase = $statements_analyzer->getCodebase(); if (isset($codebase->config->forbidden_functions['empty'])) { IssueBuffer::maybeAdd(new ForbiddenCode('You have forbidden the use of empty', new CodeLocation($statements_analyzer->getSource(), $stmt)), $statements_analyzer->getSuppressedIssues()); } $expr_type = $statements_analyzer->node_data->getType($stmt->expr); if ($expr_type) { if ($expr_type->hasBool() && $expr_type->isSingle() && !$expr_type->from_docblock) { IssueBuffer::maybeAdd(new InvalidArgument('Calling empty on a boolean value is almost certainly unintended', new CodeLocation($statements_analyzer->getSource(), $stmt->expr), 'empty'), $statements_analyzer->getSuppressedIssues()); } if ($expr_type->isAlwaysTruthy() && $expr_type->possibly_undefined === \false) { $stmt_type = new TFalse($expr_type->from_docblock); } elseif ($expr_type->isAlwaysFalsy()) { $stmt_type = new TTrue($expr_type->from_docblock); } else { ExpressionAnalyzer::checkRiskyTruthyFalsyComparison($expr_type, $statements_analyzer, $stmt); $stmt_type = new TBool(); } $stmt_type = new Union([$stmt_type], ['parent_nodes' => $expr_type->parent_nodes]); } else { $stmt_type = Type::getBool(); } $statements_analyzer->node_data->setType($stmt, $stmt_type); } } inside_call; $context->inside_call = \true; if (ExpressionAnalyzer::analyze($statements_analyzer, $stmt->expr, $context) === \false) { $context->inside_call = $was_inside_call; return \false; } if ($stmt_expr_type = $statements_analyzer->node_data->getType($stmt->expr)) { $key_type = null; $value_type = null; $always_non_empty_array = \true; if (ForeachAnalyzer::checkIteratorType($statements_analyzer, $stmt, $stmt->expr, $stmt_expr_type, $statements_analyzer->getCodebase(), $context, $key_type, $value_type, $always_non_empty_array) === \false) { $context->inside_call = $was_inside_call; return \false; } $yield_from_type = null; foreach ($stmt_expr_type->getAtomicTypes() as $atomic_type) { if ($yield_from_type === null) { if ($atomic_type instanceof TGenericObject && strtolower($atomic_type->value) === 'generator' && isset($atomic_type->type_params[3])) { $yield_from_type = $atomic_type->type_params[3]; } elseif ($atomic_type instanceof TArray) { $yield_from_type = $atomic_type->type_params[1]; } elseif ($atomic_type instanceof TKeyedArray) { $yield_from_type = $atomic_type->getGenericValueType(); } } else { $yield_from_type = Type::getMixed(); } } // this should be whatever the generator above returns, but *not* the return type $statements_analyzer->node_data->setType($stmt, $yield_from_type ?: Type::getMixed()); } $context->inside_call = $was_inside_call; return \true; } } node_data->setType($stmt, Type::getIntRange(1, null)); } elseif ($stmt instanceof PhpParser\Node\Scalar\MagicConst\Class_) { $codebase = $statements_analyzer->getCodebase(); if (!$context->self) { IssueBuffer::maybeAdd(new UndefinedConstant('Cannot get __class__ outside a class', new CodeLocation($statements_analyzer->getSource(), $stmt)), $statements_analyzer->getSuppressedIssues()); $statements_analyzer->node_data->setType($stmt, Type::getClassString()); } else { if ($codebase->alter_code) { $codebase->classlikes->handleClassLikeReferenceInMigration($codebase, $statements_analyzer, $stmt, $context->self, $context->calling_method_id); } $statements_analyzer->node_data->setType($stmt, Type::getLiteralClassString($context->self)); } } elseif ($stmt instanceof PhpParser\Node\Scalar\MagicConst\Namespace_) { $namespace = $statements_analyzer->getNamespace(); if ($namespace === null) { IssueBuffer::maybeAdd(new UndefinedConstant('Cannot get __namespace__ outside a namespace', new CodeLocation($statements_analyzer->getSource(), $stmt)), $statements_analyzer->getSuppressedIssues()); } $statements_analyzer->node_data->setType($stmt, Type::getString($namespace)); } elseif ($stmt instanceof PhpParser\Node\Scalar\MagicConst\Method || $stmt instanceof PhpParser\Node\Scalar\MagicConst\Function_) { $source = $statements_analyzer->getSource(); if ($source instanceof MethodAnalyzer) { if ($stmt instanceof PhpParser\Node\Scalar\MagicConst\Function_) { $statements_analyzer->node_data->setType($stmt, Type::getString($source->getMethodName())); } else { $statements_analyzer->node_data->setType($stmt, Type::getString($source->getCorrectlyCasedMethodId())); } } elseif ($source instanceof FunctionAnalyzer) { $statements_analyzer->node_data->setType($stmt, Type::getString($source->getCorrectlyCasedMethodId())); } else { $statements_analyzer->node_data->setType($stmt, new Union([new TCallableString()])); } } elseif ($stmt instanceof PhpParser\Node\Scalar\MagicConst\Dir) { $statements_analyzer->node_data->setType($stmt, Type::getString(dirname($statements_analyzer->getSource()->getFilePath()))); } elseif ($stmt instanceof PhpParser\Node\Scalar\MagicConst\File) { $statements_analyzer->node_data->setType($stmt, Type::getString($statements_analyzer->getSource()->getFilePath())); } elseif ($stmt instanceof PhpParser\Node\Scalar\MagicConst\Trait_) { if ($statements_analyzer->getSource() instanceof TraitAnalyzer) { $statements_analyzer->node_data->setType($stmt, new Union([new TNonEmptyString()])); } else { $statements_analyzer->node_data->setType($stmt, Type::getString()); } } } } $existing_class_constants */ public static function infer(Codebase $codebase, NodeDataProvider $nodes, PhpParser\Node\Expr $stmt, Aliases $aliases, ?FileSource $file_source = null, ?array $existing_class_constants = null, ?string $fq_classlike_name = null) : ?Union { if ($stmt instanceof PhpParser\Node\Expr\BinaryOp) { if ($stmt instanceof PhpParser\Node\Expr\BinaryOp\Concat) { $left = self::infer($codebase, $nodes, $stmt->left, $aliases, $file_source, $existing_class_constants, $fq_classlike_name); $right = self::infer($codebase, $nodes, $stmt->right, $aliases, $file_source, $existing_class_constants, $fq_classlike_name); if ($left && $right) { if ($left->isSingleStringLiteral() && $right->isSingleStringLiteral()) { $result = $left->getSingleStringLiteral()->value . $right->getSingleStringLiteral()->value; return Type::getString($result); } if ($left->isSingle() && $left->getSingleAtomic() instanceof TNonEmptyString) { return new Union([new TNonEmptyString()]); } if ($right->isSingle() && $right->getSingleAtomic() instanceof TNonEmptyString) { return new Union([new TNonEmptyString()]); } } return Type::getString(); } if ($stmt instanceof PhpParser\Node\Expr\BinaryOp\BooleanAnd || $stmt instanceof PhpParser\Node\Expr\BinaryOp\BooleanOr || $stmt instanceof PhpParser\Node\Expr\BinaryOp\LogicalAnd || $stmt instanceof PhpParser\Node\Expr\BinaryOp\LogicalOr || $stmt instanceof PhpParser\Node\Expr\BinaryOp\Equal || $stmt instanceof PhpParser\Node\Expr\BinaryOp\NotEqual || $stmt instanceof PhpParser\Node\Expr\BinaryOp\Identical || $stmt instanceof PhpParser\Node\Expr\BinaryOp\NotIdentical || $stmt instanceof PhpParser\Node\Expr\BinaryOp\Greater || $stmt instanceof PhpParser\Node\Expr\BinaryOp\GreaterOrEqual || $stmt instanceof PhpParser\Node\Expr\BinaryOp\Smaller || $stmt instanceof PhpParser\Node\Expr\BinaryOp\SmallerOrEqual) { return Type::getBool(); } if ($stmt instanceof PhpParser\Node\Expr\BinaryOp\Coalesce) { return null; } if ($stmt instanceof PhpParser\Node\Expr\BinaryOp\Spaceship) { return new Union([new TLiteralInt(-1), new TLiteralInt(0), new TLiteralInt(1)]); } $stmt_left_type = self::infer($codebase, $nodes, $stmt->left, $aliases, $file_source, $existing_class_constants, $fq_classlike_name); if (!$stmt_left_type && $file_source instanceof StatementsAnalyzer && $stmt->left instanceof PhpParser\Node\Expr\ConstFetch) { $stmt_left_type = ConstFetchAnalyzer::getConstType($file_source, $stmt->left->name->toString(), \true, null); } $stmt_right_type = self::infer($codebase, $nodes, $stmt->right, $aliases, $file_source, $existing_class_constants, $fq_classlike_name); if (!$stmt_right_type && $file_source instanceof StatementsAnalyzer && $stmt->right instanceof PhpParser\Node\Expr\ConstFetch) { $stmt_right_type = ConstFetchAnalyzer::getConstType($file_source, $stmt->right->name->toString(), \true, null); } if (!$stmt_left_type || !$stmt_right_type) { return null; } $nodes->setType($stmt->left, $stmt_left_type); $nodes->setType($stmt->right, $stmt_right_type); if ($stmt instanceof PhpParser\Node\Expr\BinaryOp\Plus || $stmt instanceof PhpParser\Node\Expr\BinaryOp\Minus || $stmt instanceof PhpParser\Node\Expr\BinaryOp\Mod || $stmt instanceof PhpParser\Node\Expr\BinaryOp\Mul || $stmt instanceof PhpParser\Node\Expr\BinaryOp\Pow || $stmt instanceof PhpParser\Node\Expr\BinaryOp\ShiftRight || $stmt instanceof PhpParser\Node\Expr\BinaryOp\ShiftLeft || $stmt instanceof PhpParser\Node\Expr\BinaryOp\BitwiseXor || $stmt instanceof PhpParser\Node\Expr\BinaryOp\BitwiseOr || $stmt instanceof PhpParser\Node\Expr\BinaryOp\BitwiseAnd) { ArithmeticOpAnalyzer::analyze($file_source instanceof StatementsSource ? $file_source : null, $nodes, $stmt->left, $stmt->right, $stmt, $result_type); if ($result_type) { return $result_type; } return null; } if ($stmt instanceof PhpParser\Node\Expr\BinaryOp\Div && ($stmt_left_type->hasInt() || $stmt_left_type->hasFloat()) && ($stmt_right_type->hasInt() || $stmt_right_type->hasFloat())) { return Type::combineUnionTypes(Type::getFloat(), Type::getInt()); } } if ($stmt instanceof PhpParser\Node\Expr\BitwiseNot) { $stmt_expr_type = self::infer($codebase, $nodes, $stmt->expr, $aliases, $file_source, $existing_class_constants, $fq_classlike_name); if ($stmt_expr_type === null) { return null; } $invalidTypes = $stmt_expr_type->getBuilder(); $invalidTypes->removeType('string'); $invalidTypes->removeType('int'); $invalidTypes->removeType('float'); if (!$invalidTypes->isUnionEmpty()) { return null; } $types = []; if ($stmt_expr_type->hasString()) { $types[] = Type::getString(); } if ($stmt_expr_type->hasInt() || $stmt_expr_type->hasFloat()) { $types[] = Type::getInt(); } return $types ? Type::combineUnionTypeArray($types, null) : null; } if ($stmt instanceof PhpParser\Node\Expr\BooleanNot) { $stmt_expr_type = self::infer($codebase, $nodes, $stmt->expr, $aliases, $file_source, $existing_class_constants, $fq_classlike_name); if ($stmt_expr_type === null) { return null; } elseif ($stmt_expr_type->isAlwaysFalsy()) { return Type::getTrue(); } elseif ($stmt_expr_type->isAlwaysTruthy()) { return Type::getFalse(); } else { return Type::getBool(); } } if ($stmt instanceof PhpParser\Node\Expr\ConstFetch) { $name = $stmt->name->getFirst(); $name_lowercase = strtolower($name); if ($name_lowercase === 'false') { return Type::getFalse(); } if ($name_lowercase === 'true') { return Type::getTrue(); } if ($name_lowercase === 'null') { return Type::getNull(); } if ($name === '__NAMESPACE__') { return Type::getString($aliases->namespace); } if ($type = ConstFetchAnalyzer::getGlobalConstType($codebase, $name, $name)) { return $type; } return null; } if ($stmt instanceof PhpParser\Node\Scalar\MagicConst\Dir || $stmt instanceof PhpParser\Node\Scalar\MagicConst\File) { return new Union([new TNonEmptyString()]); } if ($stmt instanceof PhpParser\Node\Scalar\MagicConst\Line) { return Type::getIntRange(1, null); } if ($stmt instanceof PhpParser\Node\Scalar\MagicConst\Class_ || $stmt instanceof PhpParser\Node\Scalar\MagicConst\Method || $stmt instanceof PhpParser\Node\Scalar\MagicConst\Trait_ || $stmt instanceof PhpParser\Node\Scalar\MagicConst\Function_) { return Type::getString(); } if ($stmt instanceof PhpParser\Node\Scalar\MagicConst\Namespace_) { return Type::getString($aliases->namespace); } if ($stmt instanceof PhpParser\Node\Expr\ClassConstFetch) { if ($stmt->class instanceof PhpParser\Node\Name && $stmt->name instanceof PhpParser\Node\Identifier && $fq_classlike_name && $stmt->class->getParts() !== ['static'] && $stmt->class->getParts() !== ['parent']) { if (isset($existing_class_constants[$stmt->name->name]) && $existing_class_constants[$stmt->name->name]->type) { if ($stmt->class->getParts() === ['self']) { return $existing_class_constants[$stmt->name->name]->type; } } if ($stmt->class->getParts() === ['self']) { $const_fq_class_name = $fq_classlike_name; } else { $const_fq_class_name = ClassLikeAnalyzer::getFQCLNFromNameObject($stmt->class, $aliases); } if (strtolower($const_fq_class_name) === strtolower($fq_classlike_name) && isset($existing_class_constants[$stmt->name->name]) && $existing_class_constants[$stmt->name->name]->type) { return $existing_class_constants[$stmt->name->name]->type; } if (strtolower($stmt->name->name) === 'class') { return Type::getLiteralClassString($const_fq_class_name, \true); } if ($existing_class_constants === null || $existing_class_constants === [] && $file_source !== null) { try { $foreign_class_constant = $codebase->classlikes->getClassConstantType($const_fq_class_name, $stmt->name->name, ReflectionProperty::IS_PRIVATE, $file_source instanceof StatementsAnalyzer ? $file_source : null); if ($foreign_class_constant) { return $foreign_class_constant; } return null; } catch (InvalidArgumentException|CircularReferenceException $e) { return null; } } } if ($stmt->name instanceof PhpParser\Node\Identifier && strtolower($stmt->name->name) === 'class') { return Type::getClassString(); } return null; } if ($stmt instanceof PhpParser\Node\Scalar\String_) { return Type::getString($stmt->value); } if ($stmt instanceof PhpParser\Node\Scalar\LNumber) { return Type::getInt(\false, $stmt->value); } if ($stmt instanceof PhpParser\Node\Scalar\DNumber) { return Type::getFloat($stmt->value); } if ($stmt instanceof PhpParser\Node\Expr\Array_) { return self::inferArrayType($codebase, $nodes, $stmt, $aliases, $file_source, $existing_class_constants, $fq_classlike_name); } if ($stmt instanceof PhpParser\Node\Expr\Cast\Int_) { return Type::getInt(); } if ($stmt instanceof PhpParser\Node\Expr\Cast\Double) { return Type::getFloat(); } if ($stmt instanceof PhpParser\Node\Expr\Cast\Bool_) { return Type::getBool(); } if ($stmt instanceof PhpParser\Node\Expr\Cast\String_) { return Type::getString(); } if ($stmt instanceof PhpParser\Node\Expr\Cast\Object_) { return Type::getObject(); } if ($stmt instanceof PhpParser\Node\Expr\Cast\Array_) { return Type::getArray(); } if ($stmt instanceof PhpParser\Node\Expr\UnaryMinus || $stmt instanceof PhpParser\Node\Expr\UnaryPlus) { $type_to_invert = self::infer($codebase, $nodes, $stmt->expr, $aliases, $file_source, $existing_class_constants, $fq_classlike_name); if (!$type_to_invert) { return null; } $new_types = []; foreach ($type_to_invert->getAtomicTypes() as $type_part) { if ($type_part instanceof TLiteralInt && $stmt instanceof PhpParser\Node\Expr\UnaryMinus) { $new_types[] = new TLiteralInt(-$type_part->value); } elseif ($type_part instanceof TLiteralFloat && $stmt instanceof PhpParser\Node\Expr\UnaryMinus) { $new_types[] = new TLiteralFloat(-$type_part->value); } else { $new_types[] = $type_part; } } return new Union($new_types); } if ($stmt instanceof PhpParser\Node\Expr\ArrayDimFetch) { if ($stmt->var instanceof PhpParser\Node\Expr\ClassConstFetch && $stmt->dim) { $array_type = self::infer($codebase, $nodes, $stmt->var, $aliases, $file_source, $existing_class_constants, $fq_classlike_name); $dim_type = self::infer($codebase, $nodes, $stmt->dim, $aliases, $file_source, $existing_class_constants, $fq_classlike_name); if ($array_type !== null && $dim_type !== null) { if ($dim_type->isSingleStringLiteral()) { $dim_value = $dim_type->getSingleStringLiteral()->value; } elseif ($dim_type->isSingleIntLiteral()) { $dim_value = $dim_type->getSingleIntLiteral()->value; } else { return null; } foreach ($array_type->getAtomicTypes() as $array_atomic_type) { if ($array_atomic_type instanceof TKeyedArray) { if (isset($array_atomic_type->properties[$dim_value])) { return $array_atomic_type->properties[$dim_value]; } return null; } } } } } if ($stmt instanceof PhpParser\Node\Expr\New_) { $resolved_class_name = $stmt->class->getAttribute('resolvedName'); if (!is_string($resolved_class_name)) { return null; } return new Union([new Type\Atomic\TNamedObject($resolved_class_name)]); } return null; } /** * @param ?array $existing_class_constants */ private static function inferArrayType(Codebase $codebase, NodeDataProvider $nodes, PhpParser\Node\Expr\Array_ $stmt, Aliases $aliases, ?FileSource $file_source = null, ?array $existing_class_constants = null, ?string $fq_classlike_name = null) : ?Union { if (count($stmt->items) === 0) { return Type::getEmptyArray(); } $array_creation_info = new \Psalm\Internal\Analyzer\Statements\Expression\ArrayCreationInfo(); foreach ($stmt->items as $item) { if ($item === null) { continue; } if (!self::handleArrayItem($codebase, $nodes, $array_creation_info, $item, $aliases, $file_source, $existing_class_constants, $fq_classlike_name)) { return null; } } $item_key_type = null; if ($array_creation_info->item_key_atomic_types) { $item_key_type = TypeCombiner::combine($array_creation_info->item_key_atomic_types); } $item_value_type = null; if ($array_creation_info->item_value_atomic_types) { $item_value_type = TypeCombiner::combine($array_creation_info->item_value_atomic_types); } // if this array looks like an object-like array, let's return that instead if ($item_value_type && $item_key_type && ($item_key_type->hasString() || $item_key_type->hasInt()) && $array_creation_info->can_create_objectlike && $array_creation_info->property_types) { $objectlike = new TKeyedArray($array_creation_info->property_types, $array_creation_info->class_strings, null, $array_creation_info->all_list); return new Union([$objectlike]); } if (!$item_key_type || !$item_value_type) { return null; } if ($array_creation_info->all_list) { return Type::getNonEmptyList($item_value_type); } return new Union([new TNonEmptyArray([$item_key_type, $item_value_type])]); } /** * @param ?array $existing_class_constants */ private static function handleArrayItem(Codebase $codebase, NodeDataProvider $nodes, \Psalm\Internal\Analyzer\Statements\Expression\ArrayCreationInfo $array_creation_info, PhpParser\Node\Expr\ArrayItem $item, Aliases $aliases, ?FileSource $file_source = null, ?array $existing_class_constants = null, ?string $fq_classlike_name = null) : bool { if ($item->unpack) { $unpacked_array_type = self::infer($codebase, $nodes, $item->value, $aliases, $file_source, $existing_class_constants, $fq_classlike_name); if (!$unpacked_array_type) { return \false; } return self::handleUnpackedArray($array_creation_info, $unpacked_array_type); } $single_item_key_type = null; $item_is_list_item = \false; $item_key_value = null; if ($item->key) { $single_item_key_type = self::infer($codebase, $nodes, $item->key, $aliases, $file_source, $existing_class_constants, $fq_classlike_name); if ($single_item_key_type) { $key_type = $single_item_key_type; if ($key_type->isNull()) { $key_type = Type::getString(''); } if ($item->key instanceof PhpParser\Node\Scalar\String_ && \Psalm\Internal\Analyzer\Statements\Expression\ArrayAnalyzer::getLiteralArrayKeyInt($item->key->value) !== \false) { $key_type = Type::getInt(\false, (int) $item->key->value); } $array_creation_info->item_key_atomic_types = array_merge($array_creation_info->item_key_atomic_types, array_values($key_type->getAtomicTypes())); if ($key_type->isSingleStringLiteral()) { $item_key_literal_type = $key_type->getSingleStringLiteral(); $string_to_int = \Psalm\Internal\Analyzer\Statements\Expression\ArrayAnalyzer::getLiteralArrayKeyInt($item_key_literal_type->value); $item_key_value = $string_to_int === \false ? $item_key_literal_type->value : $string_to_int; if (is_string($item_key_value) && $item_key_literal_type instanceof TLiteralClassString) { $array_creation_info->class_strings[$item_key_value] = \true; } } elseif ($key_type->isSingleIntLiteral()) { $item_key_value = $key_type->getSingleIntLiteral()->value; if ($item_key_value <= PHP_INT_MAX && $item_key_value > $array_creation_info->int_offset) { if ($item_key_value - 1 === $array_creation_info->int_offset) { $item_is_list_item = \true; } $array_creation_info->int_offset = $item_key_value; } } } } else { if ($array_creation_info->int_offset === PHP_INT_MAX) { return \false; } $item_is_list_item = \true; $item_key_value = ++$array_creation_info->int_offset; $array_creation_info->item_key_atomic_types[] = new TLiteralInt($item_key_value); } $single_item_value_type = self::infer($codebase, $nodes, $item->value, $aliases, $file_source, $existing_class_constants, $fq_classlike_name); if (!$single_item_value_type) { return \false; } $config = $codebase->config; $array_creation_info->all_list = $array_creation_info->all_list && $item_is_list_item; if ($item->key instanceof PhpParser\Node\Scalar\String_ || $item->key instanceof PhpParser\Node\Scalar\LNumber || !$item->key) { if ($item_key_value !== null && count($array_creation_info->property_types) <= $config->max_shaped_array_size) { $array_creation_info->property_types[$item_key_value] = $single_item_value_type; } else { $array_creation_info->can_create_objectlike = \false; } } else { $dim_type = $single_item_key_type; if (!$dim_type) { return \false; } if (count($dim_type->getAtomicTypes()) > 1 || $dim_type->hasMixed() || count($array_creation_info->property_types) > $config->max_shaped_array_size) { $array_creation_info->can_create_objectlike = \false; } else { $atomic_type = $dim_type->getSingleAtomic(); if ($atomic_type instanceof TLiteralInt || $atomic_type instanceof TLiteralString) { if ($atomic_type instanceof TLiteralClassString) { $array_creation_info->class_strings[$atomic_type->value] = \true; } $array_creation_info->property_types[$atomic_type->value] = $single_item_value_type; } else { $array_creation_info->can_create_objectlike = \false; } } } $array_creation_info->item_value_atomic_types = array_merge($array_creation_info->item_value_atomic_types, array_values($single_item_value_type->getAtomicTypes())); return \true; } private static function handleUnpackedArray(\Psalm\Internal\Analyzer\Statements\Expression\ArrayCreationInfo $array_creation_info, Union $unpacked_array_type) : bool { foreach ($unpacked_array_type->getAtomicTypes() as $unpacked_atomic_type) { if ($unpacked_atomic_type instanceof TList) { $unpacked_atomic_type = $unpacked_atomic_type->getKeyedArray(); } if ($unpacked_atomic_type instanceof TKeyedArray) { foreach ($unpacked_atomic_type->properties as $key => $property_value) { if (is_string($key)) { $new_offset = $key; $array_creation_info->item_key_atomic_types[] = Type::getAtomicStringFromLiteral($new_offset); } else { if ($array_creation_info->int_offset === PHP_INT_MAX) { return \false; } $new_offset = ++$array_creation_info->int_offset; $array_creation_info->item_key_atomic_types[] = new TLiteralInt($new_offset); } $array_creation_info->item_value_atomic_types = array_merge($array_creation_info->item_value_atomic_types, array_values($property_value->getAtomicTypes())); $array_creation_info->array_keys[$new_offset] = \true; $array_creation_info->property_types[$new_offset] = $property_value; } if ($unpacked_atomic_type->fallback_params !== null) { // Not sure if this is needed //$array_creation_info->can_create_objectlike = false; if ($unpacked_atomic_type->fallback_params[0]->hasString()) { $array_creation_info->item_key_atomic_types[] = new TString(); } if ($unpacked_atomic_type->fallback_params[0]->hasInt()) { $array_creation_info->item_key_atomic_types[] = new TInt(); } $array_creation_info->item_value_atomic_types = array_merge($array_creation_info->item_value_atomic_types, array_values($unpacked_atomic_type->fallback_params[1]->getAtomicTypes())); } } elseif ($unpacked_atomic_type instanceof TArray) { if ($unpacked_atomic_type->isEmptyArray()) { continue; } $array_creation_info->can_create_objectlike = \false; if ($unpacked_atomic_type->type_params[0]->hasString()) { $array_creation_info->item_key_atomic_types[] = new TString(); } if ($unpacked_atomic_type->type_params[0]->hasInt()) { $array_creation_info->item_key_atomic_types[] = new TInt(); } $array_creation_info->item_value_atomic_types = array_merge($array_creation_info->item_value_atomic_types, array_values(isset($unpacked_atomic_type->type_params[1]) ? $unpacked_atomic_type->type_params[1]->getAtomicTypes() : [new TMixed()])); } } return \true; } } name)) { return '$' . $stmt->name; } if ($stmt instanceof PhpParser\Node\Expr\StaticPropertyFetch && $stmt->name instanceof PhpParser\Node\Identifier && $stmt->class instanceof PhpParser\Node\Name) { if (count($stmt->class->getParts()) === 1 && in_array(strtolower($stmt->class->getFirst()), ['self', 'static', 'parent'], \true)) { if (!$this_class_name) { $fq_class_name = $stmt->class->getFirst(); } else { $fq_class_name = $this_class_name; } } else { $fq_class_name = $source ? ClassLikeAnalyzer::getFQCLNFromNameObject($stmt->class, $source->getAliases()) : implode('\\', $stmt->class->getParts()); } return $fq_class_name . '::$' . $stmt->name->name; } if ($stmt instanceof PhpParser\Node\Expr\PropertyFetch && $stmt->name instanceof PhpParser\Node\Identifier) { $object_id = self::getVarId($stmt->var, $this_class_name, $source); if (!$object_id) { return null; } return $object_id . '->' . $stmt->name->name; } if ($stmt instanceof PhpParser\Node\Expr\ArrayDimFetch && $nesting !== null) { ++$nesting; return self::getVarId($stmt->var, $this_class_name, $source, $nesting); } return null; } public static function getRootVarId(PhpParser\Node\Expr $stmt, ?string $this_class_name, ?FileSource $source = null) : ?string { if ($stmt instanceof PhpParser\Node\Expr\Variable || $stmt instanceof PhpParser\Node\Expr\StaticPropertyFetch) { return self::getVarId($stmt, $this_class_name, $source); } if ($stmt instanceof PhpParser\Node\Expr\PropertyFetch && $stmt->name instanceof PhpParser\Node\Identifier) { $property_root = self::getRootVarId($stmt->var, $this_class_name, $source); if ($property_root) { return $property_root . '->' . $stmt->name->name; } } if ($stmt instanceof PhpParser\Node\Expr\ArrayDimFetch) { return self::getRootVarId($stmt->var, $this_class_name, $source); } return null; } public static function getExtendedVarId(PhpParser\Node\Expr $stmt, ?string $this_class_name, ?FileSource $source = null) : ?string { if ($stmt instanceof PhpParser\Node\Expr\Assign) { return self::getExtendedVarId($stmt->var, $this_class_name, $source); } if ($stmt instanceof PhpParser\Node\Expr\ArrayDimFetch) { $root_var_id = self::getExtendedVarId($stmt->var, $this_class_name, $source); $offset = null; if ($root_var_id) { if ($stmt->dim instanceof PhpParser\Node\Scalar\String_ || $stmt->dim instanceof PhpParser\Node\Scalar\LNumber) { $string_to_int = \Psalm\Internal\Analyzer\Statements\Expression\ArrayAnalyzer::getLiteralArrayKeyInt($stmt->dim->value); $offset = $string_to_int === \false ? '\'' . $stmt->dim->value . '\'' : (int) $stmt->dim->value; } elseif ($stmt->dim instanceof PhpParser\Node\Expr\Variable && is_string($stmt->dim->name)) { $offset = '$' . $stmt->dim->name; } elseif ($stmt->dim instanceof PhpParser\Node\Expr\ConstFetch) { $offset = implode('\\', $stmt->dim->name->getParts()); } elseif ($stmt->dim instanceof PhpParser\Node\Expr\PropertyFetch) { $object_id = self::getExtendedVarId($stmt->dim->var, $this_class_name, $source); if ($object_id && $stmt->dim->name instanceof PhpParser\Node\Identifier) { $offset = $object_id . '->' . $stmt->dim->name; } } elseif ($stmt->dim instanceof PhpParser\Node\Expr\ClassConstFetch && $stmt->dim->name instanceof PhpParser\Node\Identifier && $stmt->dim->class instanceof PhpParser\Node\Name && $stmt->dim->class->getFirst() === 'static') { $offset = 'static::' . $stmt->dim->name; } elseif ($stmt->dim && $source instanceof StatementsAnalyzer && ($stmt_dim_type = $source->node_data->getType($stmt->dim)) && (!$stmt->dim instanceof PhpParser\Node\Expr\ClassConstFetch || !$stmt->dim->name instanceof PhpParser\Node\Identifier || $stmt->dim->name->name !== 'class')) { if ($stmt_dim_type->isSingleStringLiteral()) { $string_to_int = \Psalm\Internal\Analyzer\Statements\Expression\ArrayAnalyzer::getLiteralArrayKeyInt($stmt_dim_type->getSingleStringLiteral()->value); $offset = $string_to_int === \false ? '\'' . $stmt_dim_type->getSingleStringLiteral()->value . '\'' : (int) $stmt_dim_type->getSingleStringLiteral()->value; } elseif ($stmt_dim_type->isSingleIntLiteral()) { $offset = $stmt_dim_type->getSingleIntLiteral()->value; } } elseif ($stmt->dim instanceof PhpParser\Node\Expr\ClassConstFetch && $stmt->dim->name instanceof PhpParser\Node\Identifier) { /** @var string|null */ $resolved_name = $stmt->dim->class->getAttribute('resolvedName'); if ($resolved_name) { $offset = $resolved_name . '::' . $stmt->dim->name; } } return $offset !== null ? $root_var_id . '[' . $offset . ']' : null; } } if ($stmt instanceof PhpParser\Node\Expr\PropertyFetch) { $object_id = self::getExtendedVarId($stmt->var, $this_class_name, $source); if (!$object_id) { return null; } if ($stmt->name instanceof PhpParser\Node\Identifier) { return $object_id . '->' . $stmt->name; } if ($source instanceof StatementsAnalyzer && ($stmt_name_type = $source->node_data->getType($stmt->name)) && $stmt_name_type->isSingleStringLiteral()) { return $object_id . '->' . $stmt_name_type->getSingleStringLiteral()->value; } return null; } if ($stmt instanceof PhpParser\Node\Expr\ClassConstFetch && $stmt->name instanceof PhpParser\Node\Identifier) { /** @var string|null */ $resolved_name = $stmt->class->getAttribute('resolvedName'); if ($resolved_name) { if (($resolved_name === 'self' || $resolved_name === 'static') && $this_class_name) { $resolved_name = $this_class_name; } return $resolved_name . '::' . $stmt->name; } } if ($stmt instanceof PhpParser\Node\Expr\MethodCall && $stmt->name instanceof PhpParser\Node\Identifier && !$stmt->isFirstClassCallable() && !$stmt->getArgs()) { $config = Config::getInstance(); if ($config->memoize_method_calls || $stmt->getAttribute('memoizable', \false)) { $lhs_var_name = self::getExtendedVarId($stmt->var, $this_class_name, $source); if (!$lhs_var_name) { return null; } return $lhs_var_name . '->' . strtolower($stmt->name->name) . '()'; } } return self::getVarId($stmt, $this_class_name, $source); } } expr, $context) === \false) { return \false; } $maybe_type = $statements_analyzer->node_data->getType($stmt->expr); if ($maybe_type) { if ($maybe_type->isInt()) { if (!$maybe_type->from_calculation) { self::handleRedundantCast($maybe_type, $statements_analyzer, $stmt); } } $type = self::castIntAttempt($statements_analyzer, $maybe_type, $stmt->expr, \true); } else { $type = Type::getInt(); } $statements_analyzer->node_data->setType($stmt, $type); return \true; } if ($stmt instanceof PhpParser\Node\Expr\Cast\Double) { if (ExpressionAnalyzer::analyze($statements_analyzer, $stmt->expr, $context) === \false) { return \false; } $maybe_type = $statements_analyzer->node_data->getType($stmt->expr); if ($maybe_type) { if ($maybe_type->isFloat()) { self::handleRedundantCast($maybe_type, $statements_analyzer, $stmt); } $type = self::castFloatAttempt($statements_analyzer, $maybe_type, $stmt->expr, \true); } else { $type = Type::getFloat(); } $statements_analyzer->node_data->setType($stmt, $type); return \true; } if ($stmt instanceof PhpParser\Node\Expr\Cast\Bool_) { if (ExpressionAnalyzer::analyze($statements_analyzer, $stmt->expr, $context) === \false) { return \false; } $maybe_type = $statements_analyzer->node_data->getType($stmt->expr); if ($maybe_type) { if ($maybe_type->isBool()) { self::handleRedundantCast($maybe_type, $statements_analyzer, $stmt); } } if ($statements_analyzer->data_flow_graph instanceof VariableUseGraph) { $type = new Union([new TBool()], ['parent_nodes' => $maybe_type->parent_nodes ?? []]); } else { $type = Type::getBool(); } $statements_analyzer->node_data->setType($stmt, $type); return \true; } if ($stmt instanceof PhpParser\Node\Expr\Cast\String_) { if (ExpressionAnalyzer::analyze($statements_analyzer, $stmt->expr, $context) === \false) { return \false; } $stmt_expr_type = $statements_analyzer->node_data->getType($stmt->expr); if ($stmt_expr_type) { if ($stmt_expr_type->isString()) { self::handleRedundantCast($stmt_expr_type, $statements_analyzer, $stmt); } $stmt_type = self::castStringAttempt($statements_analyzer, $context, $stmt_expr_type, $stmt->expr, \true); } else { $stmt_type = Type::getString(); } $statements_analyzer->node_data->setType($stmt, $stmt_type); return \true; } if ($stmt instanceof PhpParser\Node\Expr\Cast\Object_) { if (!self::checkExprGeneralUse($statements_analyzer, $stmt, $context)) { return \false; } $permissible_atomic_types = []; $all_permissible = \false; if ($stmt_expr_type = $statements_analyzer->node_data->getType($stmt->expr)) { if ($stmt_expr_type->isObjectType()) { self::handleRedundantCast($stmt_expr_type, $statements_analyzer, $stmt); } $all_permissible = \true; foreach ($stmt_expr_type->getAtomicTypes() as $type) { if ($type instanceof TList) { $type = $type->getKeyedArray(); } if ($type instanceof Scalar) { $objWithProps = new TObjectWithProperties(['scalar' => new Union([$type])]); $permissible_atomic_types[] = $objWithProps; } elseif ($type instanceof TKeyedArray) { $permissible_atomic_types[] = new TObjectWithProperties($type->properties); } else { $all_permissible = \false; break; } } } if ($permissible_atomic_types && $all_permissible) { $type = TypeCombiner::combine($permissible_atomic_types); } else { $type = Type::getObject(); } if ($statements_analyzer->data_flow_graph instanceof VariableUseGraph) { $type = $type->setParentNodes($stmt_expr_type->parent_nodes ?? []); } $statements_analyzer->node_data->setType($stmt, $type); return \true; } if ($stmt instanceof PhpParser\Node\Expr\Cast\Array_) { if (!self::checkExprGeneralUse($statements_analyzer, $stmt, $context)) { return \false; } $permissible_atomic_types = []; $all_permissible = \false; if ($stmt_expr_type = $statements_analyzer->node_data->getType($stmt->expr)) { if ($stmt_expr_type->isArray()) { self::handleRedundantCast($stmt_expr_type, $statements_analyzer, $stmt); } $all_permissible = \true; foreach ($stmt_expr_type->getAtomicTypes() as $type) { if ($type instanceof TList) { $type = $type->getKeyedArray(); } if ($type instanceof Scalar) { $keyed_array = new TKeyedArray([new Union([$type])], null, null, \true); $permissible_atomic_types[] = $keyed_array; } elseif ($type instanceof TNull) { $permissible_atomic_types[] = new TArray([Type::getNever(), Type::getNever()]); } elseif ($type instanceof TArray || $type instanceof TKeyedArray) { $permissible_atomic_types[] = $type; } elseif ($type instanceof TObjectWithProperties) { $array_type = $type->properties === [] ? new TArray([Type::getArrayKey(), Type::getMixed()]) : new TKeyedArray($type->properties, null, [Type::getArrayKey(), Type::getMixed()]); $permissible_atomic_types[] = $array_type; } else { $all_permissible = \false; break; } } } if ($permissible_atomic_types && $all_permissible) { $type = TypeCombiner::combine($permissible_atomic_types); } else { $type = Type::getArray(); } if ($statements_analyzer->data_flow_graph) { $type = $type->setParentNodes($stmt_expr_type->parent_nodes ?? []); } $statements_analyzer->node_data->setType($stmt, $type); return \true; } if ($stmt instanceof PhpParser\Node\Expr\Cast\Unset_ && $statements_analyzer->getCodebase()->analysis_php_version_id <= 70400) { if (ExpressionAnalyzer::analyze($statements_analyzer, $stmt->expr, $context) === \false) { return \false; } $statements_analyzer->node_data->setType($stmt, Type::getNull()); return \true; } IssueBuffer::maybeAdd(new UnrecognizedExpression('Psalm does not understand the cast ' . get_class($stmt), new CodeLocation($statements_analyzer->getSource(), $stmt)), $statements_analyzer->getSuppressedIssues()); return \false; } public static function castIntAttempt(StatementsAnalyzer $statements_analyzer, Union $stmt_type, PhpParser\Node\Expr $stmt, bool $explicit_cast = \false) : Union { $codebase = $statements_analyzer->getCodebase(); $risky_cast = []; $invalid_casts = []; $valid_ints = []; $castable_types = []; $atomic_types = $stmt_type->getAtomicTypes(); $parent_nodes = []; if ($statements_analyzer->data_flow_graph instanceof VariableUseGraph) { $parent_nodes = $stmt_type->parent_nodes; } while ($atomic_types) { $atomic_type = array_pop($atomic_types); if ($atomic_type instanceof TList) { $atomic_type = $atomic_type->getKeyedArray(); } if ($atomic_type instanceof TInt) { $valid_ints[] = $atomic_type; continue; } if ($atomic_type instanceof TFloat) { if ($atomic_type instanceof TLiteralFloat) { $valid_ints[] = new TLiteralInt((int) $atomic_type->value); } else { $castable_types[] = new TInt(); } continue; } if ($atomic_type instanceof TString) { if ($atomic_type instanceof TLiteralString) { $valid_ints[] = new TLiteralInt((int) $atomic_type->value); } elseif ($atomic_type instanceof TNumericString) { $castable_types[] = new TInt(); } else { // any normal string is technically $valid_int[] = new TLiteralInt(0); // however we cannot be certain that it's not inferred, therefore less strict $castable_types[] = new TInt(); } continue; } if ($atomic_type instanceof TNull || $atomic_type instanceof TFalse) { $valid_ints[] = new TLiteralInt(0); continue; } if ($atomic_type instanceof TTrue) { $valid_ints[] = new TLiteralInt(1); continue; } if ($atomic_type instanceof TBool) { // do NOT use TIntRange here, as it will cause invalid behavior, e.g. bitwiseAssignment $valid_ints[] = new TLiteralInt(0); $valid_ints[] = new TLiteralInt(1); continue; } // could be invalid, but allow it, as it is allowed for TString below too if ($atomic_type instanceof TMixed || $atomic_type instanceof TClosedResource || $atomic_type instanceof TResource || $atomic_type instanceof Scalar) { $castable_types[] = new TInt(); continue; } if ($atomic_type instanceof TNamedObject) { $intersection_types = [$atomic_type]; if ($atomic_type->extra_types) { $intersection_types = array_merge($intersection_types, $atomic_type->extra_types); } foreach ($intersection_types as $intersection_type) { if (!$intersection_type instanceof TNamedObject) { continue; } // prevent "Could not get class storage for mixed" if (!$codebase->classExists($intersection_type->value)) { continue; } foreach (self::PSEUDO_CASTABLE_CLASSES as $pseudo_castable_class) { if (strtolower($intersection_type->value) === strtolower($pseudo_castable_class) || $codebase->classExtends($intersection_type->value, $pseudo_castable_class)) { $castable_types[] = new TInt(); continue 3; } } } } if ($atomic_type instanceof TNonEmptyArray || $atomic_type instanceof TKeyedArray && $atomic_type->isNonEmpty()) { $risky_cast[] = $atomic_type->getId(); $valid_ints[] = new TLiteralInt(1); continue; } if ($atomic_type instanceof TArray || $atomic_type instanceof TKeyedArray) { // if type is not specific, it can be both 0 or 1, depending on whether the array has data or not // welcome to off-by-one hell if that happens :-) $risky_cast[] = $atomic_type->getId(); $valid_ints[] = new TLiteralInt(0); $valid_ints[] = new TLiteralInt(1); continue; } if ($atomic_type instanceof TTemplateParam) { $atomic_types = array_merge($atomic_types, $atomic_type->as->getAtomicTypes()); continue; } // always 1 for "error" cases $valid_ints[] = new TLiteralInt(1); $invalid_casts[] = $atomic_type->getId(); } if ($invalid_casts) { IssueBuffer::maybeAdd(new InvalidCast($invalid_casts[0] . ' cannot be cast to int', new CodeLocation($statements_analyzer->getSource(), $stmt)), $statements_analyzer->getSuppressedIssues()); } elseif ($risky_cast) { IssueBuffer::maybeAdd(new RiskyCast('Casting ' . $risky_cast[0] . ' to int has possibly unintended value of 0/1', new CodeLocation($statements_analyzer->getSource(), $stmt)), $statements_analyzer->getSuppressedIssues()); } elseif ($explicit_cast && !$castable_types) { // todo: emit error here } $valid_types = [...$valid_ints, ...$castable_types]; if (!$valid_types) { $int_type = Type::getInt(); } else { $int_type = TypeCombiner::combine($valid_types, $codebase); } if ($statements_analyzer->data_flow_graph) { $int_type = $int_type->setParentNodes($parent_nodes); } return $int_type; } public static function castFloatAttempt(StatementsAnalyzer $statements_analyzer, Union $stmt_type, PhpParser\Node\Expr $stmt, bool $explicit_cast = \false) : Union { $codebase = $statements_analyzer->getCodebase(); $risky_cast = []; $invalid_casts = []; $valid_floats = []; $castable_types = []; $atomic_types = $stmt_type->getAtomicTypes(); $parent_nodes = []; if ($statements_analyzer->data_flow_graph instanceof VariableUseGraph) { $parent_nodes = $stmt_type->parent_nodes; } while ($atomic_types) { $atomic_type = array_pop($atomic_types); if ($atomic_type instanceof TList) { $atomic_type = $atomic_type->getKeyedArray(); } if ($atomic_type instanceof TFloat) { $valid_floats[] = $atomic_type; continue; } if ($atomic_type instanceof TIntRange && $atomic_type->min_bound !== null && $atomic_type->max_bound !== null && $atomic_type->max_bound - $atomic_type->min_bound < 500) { foreach (range($atomic_type->min_bound, $atomic_type->max_bound) as $literal_int_value) { $valid_floats[] = new TLiteralFloat((float) $literal_int_value); } continue; } if ($atomic_type instanceof TInt) { if ($atomic_type instanceof TLiteralInt) { $valid_floats[] = new TLiteralFloat((float) $atomic_type->value); } else { $castable_types[] = new TFloat(); } continue; } if ($atomic_type instanceof TString) { if ($atomic_type instanceof TLiteralString) { $valid_floats[] = new TLiteralFloat((float) $atomic_type->value); } elseif ($atomic_type instanceof TNumericString) { $castable_types[] = new TFloat(); } else { // any normal string is technically $valid_floats[] = new TLiteralFloat(0.0); // however we cannot be certain that it's not inferred, therefore less strict $castable_types[] = new TFloat(); } continue; } if ($atomic_type instanceof TNull || $atomic_type instanceof TFalse) { $valid_floats[] = new TLiteralFloat(0.0); continue; } if ($atomic_type instanceof TTrue) { $valid_floats[] = new TLiteralFloat(1.0); continue; } if ($atomic_type instanceof TBool) { $valid_floats[] = new TLiteralFloat(0.0); $valid_floats[] = new TLiteralFloat(1.0); continue; } // could be invalid, but allow it, as it is allowed for TString below too if ($atomic_type instanceof TMixed || $atomic_type instanceof TClosedResource || $atomic_type instanceof TResource || $atomic_type instanceof Scalar) { $castable_types[] = new TFloat(); continue; } if ($atomic_type instanceof TNamedObject) { $intersection_types = [$atomic_type]; if ($atomic_type->extra_types) { $intersection_types = array_merge($intersection_types, $atomic_type->extra_types); } foreach ($intersection_types as $intersection_type) { if (!$intersection_type instanceof TNamedObject) { continue; } // prevent "Could not get class storage for mixed" if (!$codebase->classExists($intersection_type->value)) { continue; } foreach (self::PSEUDO_CASTABLE_CLASSES as $pseudo_castable_class) { if (strtolower($intersection_type->value) === strtolower($pseudo_castable_class) || $codebase->classExtends($intersection_type->value, $pseudo_castable_class)) { $castable_types[] = new TFloat(); continue 3; } } } } if ($atomic_type instanceof TNonEmptyArray || $atomic_type instanceof TKeyedArray && $atomic_type->isNonEmpty()) { $risky_cast[] = $atomic_type->getId(); $valid_floats[] = new TLiteralFloat(1.0); continue; } if ($atomic_type instanceof TArray || $atomic_type instanceof TKeyedArray) { // if type is not specific, it can be both 0 or 1, depending on whether the array has data or not // welcome to off-by-one hell if that happens :-) $risky_cast[] = $atomic_type->getId(); $valid_floats[] = new TLiteralFloat(0.0); $valid_floats[] = new TLiteralFloat(1.0); continue; } if ($atomic_type instanceof TTemplateParam) { $atomic_types = array_merge($atomic_types, $atomic_type->as->getAtomicTypes()); continue; } // always 1.0 for "error" cases $valid_floats[] = new TLiteralFloat(1.0); $invalid_casts[] = $atomic_type->getId(); } if ($invalid_casts) { IssueBuffer::maybeAdd(new InvalidCast($invalid_casts[0] . ' cannot be cast to float', new CodeLocation($statements_analyzer->getSource(), $stmt)), $statements_analyzer->getSuppressedIssues()); } elseif ($risky_cast) { IssueBuffer::maybeAdd(new RiskyCast('Casting ' . $risky_cast[0] . ' to float has possibly unintended value of 0.0/1.0', new CodeLocation($statements_analyzer->getSource(), $stmt)), $statements_analyzer->getSuppressedIssues()); } elseif ($explicit_cast && !$castable_types) { // todo: emit error here } $valid_types = [...$valid_floats, ...$castable_types]; if (!$valid_types) { $float_type = Type::getFloat(); } else { $float_type = TypeCombiner::combine($valid_types, $codebase); } if ($statements_analyzer->data_flow_graph) { $float_type = $float_type->setParentNodes($parent_nodes); } return $float_type; } public static function castStringAttempt(StatementsAnalyzer $statements_analyzer, Context $context, Union $stmt_type, PhpParser\Node\Expr $stmt, bool $explicit_cast = \false) : Union { $codebase = $statements_analyzer->getCodebase(); $invalid_casts = []; $valid_strings = []; $castable_types = []; $atomic_types = $stmt_type->getAtomicTypes(); $parent_nodes = []; if ($statements_analyzer->data_flow_graph) { $parent_nodes = $stmt_type->parent_nodes; } while ($atomic_types) { $atomic_type = array_pop($atomic_types); if ($atomic_type instanceof TFloat || $atomic_type instanceof TInt || $atomic_type instanceof TNumeric) { if ($atomic_type instanceof TLiteralInt || $atomic_type instanceof TLiteralFloat) { $valid_strings[] = Type::getAtomicStringFromLiteral((string) $atomic_type->value); } elseif ($atomic_type instanceof TNonspecificLiteralInt) { $castable_types[] = new TNonspecificLiteralString(); } elseif ($atomic_type instanceof TIntRange && $atomic_type->min_bound !== null && $atomic_type->max_bound !== null && $atomic_type->max_bound - $atomic_type->min_bound < 500) { foreach (range($atomic_type->min_bound, $atomic_type->max_bound) as $literal_int_value) { $valid_strings[] = Type::getAtomicStringFromLiteral((string) $literal_int_value); } } else { $castable_types[] = new TNumericString(); } continue; } if ($atomic_type instanceof TString) { $valid_strings[] = $atomic_type; continue; } if ($atomic_type instanceof TNull || $atomic_type instanceof TFalse) { $valid_strings[] = Type::getAtomicStringFromLiteral(''); continue; } if ($atomic_type instanceof TTrue) { $valid_strings[] = Type::getAtomicStringFromLiteral('1'); continue; } if ($atomic_type instanceof TBool) { $valid_strings[] = Type::getAtomicStringFromLiteral('1'); $valid_strings[] = Type::getAtomicStringFromLiteral(''); continue; } if ($atomic_type instanceof TClosedResource || $atomic_type instanceof TResource) { $castable_types[] = new TNonEmptyString(); continue; } if ($atomic_type instanceof TMixed || $atomic_type instanceof Scalar) { $castable_types[] = new TString(); continue; } if ($atomic_type instanceof TNamedObject || $atomic_type instanceof TObjectWithProperties) { $intersection_types = [$atomic_type]; if ($atomic_type->extra_types) { $intersection_types = array_merge($intersection_types, $atomic_type->extra_types); } foreach ($intersection_types as $intersection_type) { if ($intersection_type instanceof TNamedObject) { $intersection_method_id = new MethodIdentifier($intersection_type->value, '__tostring'); if ($codebase->methods->methodExists($intersection_method_id, $context->calling_method_id, new CodeLocation($statements_analyzer->getSource(), $stmt))) { $return_type = $codebase->methods->getMethodReturnType($intersection_method_id, $self_class) ?? Type::getString(); $declaring_method_id = $codebase->methods->getDeclaringMethodId($intersection_method_id); MethodCallReturnTypeFetcher::taintMethodCallResult($statements_analyzer, $return_type, $stmt, $stmt, [], $intersection_method_id, $declaring_method_id, $intersection_type->value . '::__toString', $context); if ($statements_analyzer->data_flow_graph) { $parent_nodes = array_merge($return_type->parent_nodes, $parent_nodes); } $castable_types = [...$castable_types, ...array_values($return_type->getAtomicTypes())]; continue 2; } } if ($intersection_type instanceof TObjectWithProperties && isset($intersection_type->methods['__tostring'])) { $castable_types[] = new TString(); continue 2; } } } if ($atomic_type instanceof TTemplateParam) { $atomic_types = array_merge($atomic_types, $atomic_type->as->getAtomicTypes()); continue; } $invalid_casts[] = $atomic_type->getId(); } if ($invalid_casts) { if ($valid_strings || $castable_types) { IssueBuffer::maybeAdd(new PossiblyInvalidCast($invalid_casts[0] . ' cannot be cast to string', new CodeLocation($statements_analyzer->getSource(), $stmt)), $statements_analyzer->getSuppressedIssues()); } else { IssueBuffer::maybeAdd(new InvalidCast($invalid_casts[0] . ' cannot be cast to string', new CodeLocation($statements_analyzer->getSource(), $stmt)), $statements_analyzer->getSuppressedIssues()); } } elseif ($explicit_cast && !$castable_types) { // todo: emit error here } $valid_types = [...$valid_strings, ...$castable_types]; if (!$valid_types) { $str_type = Type::getString(); } else { $str_type = TypeCombiner::combine($valid_types, $codebase); } if ($statements_analyzer->data_flow_graph) { $str_type = $str_type->setParentNodes($parent_nodes); } return $str_type; } private static function checkExprGeneralUse(StatementsAnalyzer $statements_analyzer, PhpParser\Node\Expr\Cast $stmt, Context $context) : bool { $was_inside_general_use = $context->inside_general_use; $context->inside_general_use = \true; $retVal = ExpressionAnalyzer::analyze($statements_analyzer, $stmt->expr, $context); $context->inside_general_use = $was_inside_general_use; return $retVal; } private static function handleRedundantCast(Union $maybe_type, StatementsAnalyzer $statements_analyzer, PhpParser\Node\Expr\Cast $stmt) : void { $codebase = $statements_analyzer->getCodebase(); $project_analyzer = $statements_analyzer->getProjectAnalyzer(); $file_manipulation = null; if ($maybe_type->from_docblock) { $issue = new RedundantCastGivenDocblockType('Redundant cast to ' . $maybe_type->getKey() . ' given docblock-provided type', new CodeLocation($statements_analyzer->getSource(), $stmt)); if ($codebase->alter_code && isset($project_analyzer->getIssuesToFix()['RedundantCastGivenDocblockType'])) { $file_manipulation = new FileManipulation((int) $stmt->getAttribute('startFilePos'), (int) $stmt->expr->getAttribute('startFilePos'), ''); } } else { $issue = new RedundantCast('Redundant cast to ' . $maybe_type->getKey(), new CodeLocation($statements_analyzer->getSource(), $stmt)); if ($codebase->alter_code && isset($project_analyzer->getIssuesToFix()['RedundantCast'])) { $file_manipulation = new FileManipulation((int) $stmt->getAttribute('startFilePos'), (int) $stmt->expr->getAttribute('startFilePos'), ''); } } if ($file_manipulation) { FileManipulationBuffer::add($statements_analyzer->getFilePath(), [$file_manipulation]); } IssueBuffer::maybeAdd($issue, $statements_analyzer->getSuppressedIssues()); } } expr, $context) === \false) { return \false; } if (!($stmt_expr_type = $statements_analyzer->node_data->getType($stmt->expr))) { $statements_analyzer->node_data->setType($stmt, new Union([new TInt(), new TFloat()])); } elseif ($stmt_expr_type->isMixed()) { $statements_analyzer->node_data->setType($stmt, Type::getMixed()); } else { $acceptable_types = []; foreach ($stmt_expr_type->getAtomicTypes() as $type_part) { if ($type_part instanceof TInt || $type_part instanceof TFloat) { if (!$stmt instanceof PhpParser\Node\Expr\UnaryMinus) { $acceptable_types[] = $type_part; continue; } if ($type_part instanceof TLiteralInt) { /** @var int|float $value */ $value = -$type_part->value; $type_part = is_int($value) ? new TLiteralInt($value) : new TLiteralFloat($value); } elseif ($type_part instanceof TLiteralFloat) { $type_part = new TLiteralFloat(-$type_part->value); } elseif ($type_part instanceof TIntRange) { //we'll have to inverse min and max bound and negate any literal $old_min_bound = $type_part->min_bound; $old_max_bound = $type_part->max_bound; if ($old_min_bound === null) { //min bound is null, max bound will be null $new_max_bound = null; } elseif ($old_min_bound === 0) { $new_max_bound = 0; } else { $new_max_bound = -$old_min_bound; } if ($old_max_bound === null) { //max bound is null, min bound will be null $new_min_bound = null; } elseif ($old_max_bound === 0) { $new_min_bound = 0; } else { $new_min_bound = -$old_max_bound; } $type_part = new TIntRange($new_min_bound, $new_max_bound); } $acceptable_types[] = $type_part; } elseif ($type_part instanceof TString) { $acceptable_types[] = new TInt(); $acceptable_types[] = new TFloat(); } else { $acceptable_types[] = new TInt(); } } if (!$acceptable_types) { throw new RuntimeException("Impossible!"); } $statements_analyzer->node_data->setType($stmt, new Union($acceptable_types)); } self::addDataFlow($statements_analyzer, $stmt, $stmt->expr, $stmt instanceof UnaryMinus ? 'unary-minus' : 'unary-plus'); return \true; } private static function addDataFlow(StatementsAnalyzer $statements_analyzer, PhpParser\Node\Expr $stmt, PhpParser\Node\Expr $value, string $type) : void { $result_type = $statements_analyzer->node_data->getType($stmt); if ($statements_analyzer->data_flow_graph instanceof VariableUseGraph && $result_type) { $var_location = new CodeLocation($statements_analyzer, $stmt); $stmt_value_type = $statements_analyzer->node_data->getType($value); $new_parent_node = DataFlowNode::getForAssignment($type, $var_location); $statements_analyzer->data_flow_graph->addNode($new_parent_node); $statements_analyzer->node_data->setType($stmt, $result_type->setParentNodes([$new_parent_node->id => $new_parent_node])); if ($stmt_value_type && $stmt_value_type->parent_nodes) { foreach ($stmt_value_type->parent_nodes as $parent_node) { $statements_analyzer->data_flow_graph->addPath($parent_node, $new_parent_node, $type); } } } } } class and * analyse the ::class int $stmt->name separately */ public static function analyzeFetch(StatementsAnalyzer $statements_analyzer, PhpParser\Node\Expr\ClassConstFetch $stmt, Context $context) : bool { $codebase = $statements_analyzer->getCodebase(); $statements_analyzer->node_data->setType($stmt, Type::getMixed()); if ($stmt->class instanceof PhpParser\Node\Name) { $first_part_lc = strtolower($stmt->class->getFirst()); if ($first_part_lc === 'self' || $first_part_lc === 'static') { if (!$context->self) { return !IssueBuffer::accepts(new NonStaticSelfCall('Cannot use ' . $first_part_lc . ' outside class context', new CodeLocation($statements_analyzer->getSource(), $stmt)), $statements_analyzer->getSuppressedIssues()); } $fq_class_name = $context->self; } elseif ($first_part_lc === 'parent') { $fq_class_name = $statements_analyzer->getParentFQCLN(); if ($fq_class_name === null) { return !IssueBuffer::accepts(new ParentNotFound('Cannot check property fetch on parent as this class does not extend another', new CodeLocation($statements_analyzer->getSource(), $stmt)), $statements_analyzer->getSuppressedIssues()); } } else { $fq_class_name = ClassLikeAnalyzer::getFQCLNFromNameObject($stmt->class, $statements_analyzer->getAliases()); if ($stmt->name instanceof PhpParser\Node\Identifier) { if ((!$context->inside_class_exists || $stmt->name->name !== 'class') && !isset($context->phantom_classes[strtolower($fq_class_name)])) { if (ClassLikeAnalyzer::checkFullyQualifiedClassLikeName($statements_analyzer, $fq_class_name, new CodeLocation($statements_analyzer->getSource(), $stmt->class), $context->self, $context->calling_method_id, $statements_analyzer->getSuppressedIssues(), new ClassLikeNameOptions(\false, \true)) === \false) { return \true; } } } } $fq_class_name_lc = strtolower($fq_class_name); $moved_class = \false; if ($codebase->alter_code && !in_array($stmt->class->getFirst(), ['parent', 'static'])) { $moved_class = $codebase->classlikes->handleClassLikeReferenceInMigration($codebase, $statements_analyzer, $stmt->class, $fq_class_name, $context->calling_method_id, \false, $stmt->class->getFirst() === 'self'); } if ($codebase->classlikes->classExists($fq_class_name)) { $fq_class_name = $codebase->classlikes->getUnAliasedName($fq_class_name); } if ($stmt->name instanceof PhpParser\Node\Identifier && $stmt->name->name === 'class') { if ($codebase->classlikes->classExists($fq_class_name)) { $const_class_storage = $codebase->classlike_storage_provider->get($fq_class_name); $fq_class_name = $const_class_storage->name; if ($const_class_storage->deprecated && $fq_class_name !== $context->self) { IssueBuffer::maybeAdd(new DeprecatedClass('Class ' . $fq_class_name . ' is deprecated', new CodeLocation($statements_analyzer->getSource(), $stmt), $fq_class_name), $statements_analyzer->getSuppressedIssues()); } } if ($first_part_lc === 'static') { $static_named_object = new TNamedObject($fq_class_name, \true); $statements_analyzer->node_data->setType($stmt, new Union([new TClassString($fq_class_name, $static_named_object)])); } else { $statements_analyzer->node_data->setType($stmt, Type::getLiteralClassString($fq_class_name, \true)); } if ($codebase->store_node_types && !$context->collect_initializations && !$context->collect_mutations) { $codebase->analyzer->addNodeReference($statements_analyzer->getFilePath(), $stmt->class, $fq_class_name); } return \true; } // if we're ignoring that the class doesn't exist, exit anyway if (!$codebase->classlikes->classOrInterfaceOrEnumExists($fq_class_name)) { return \true; } if ($codebase->store_node_types && !$context->collect_initializations && !$context->collect_mutations) { $codebase->analyzer->addNodeReference($statements_analyzer->getFilePath(), $stmt->class, $fq_class_name); } if (!$stmt->name instanceof PhpParser\Node\Identifier) { if ($codebase->analysis_php_version_id < 80300) { IssueBuffer::maybeAdd(new ParseError('Dynamically fetching class constants and enums requires PHP 8.3', new CodeLocation($statements_analyzer->getSource(), $stmt)), $statements_analyzer->getSuppressedIssues()); } $was_inside_general_use = $context->inside_general_use; $context->inside_general_use = \true; $ret = ExpressionAnalyzer::analyze($statements_analyzer, $stmt->name, $context); $context->inside_general_use = $was_inside_general_use; return $ret; } $const_id = $fq_class_name . '::' . $stmt->name; if ($codebase->store_node_types && !$context->collect_initializations && !$context->collect_mutations) { $codebase->analyzer->addNodeReference($statements_analyzer->getFilePath(), $stmt->name, $const_id); } $const_class_storage = $codebase->classlike_storage_provider->get($fq_class_name); if ($const_class_storage->is_enum) { $case = $const_class_storage->enum_cases[(string) $stmt->name] ?? null; if ($case && $case->deprecated) { IssueBuffer::maybeAdd(new DeprecatedConstant("Enum Case {$const_id} is marked as deprecated", new CodeLocation($statements_analyzer->getSource(), $stmt)), $statements_analyzer->getSuppressedIssues()); } } if ($fq_class_name === $context->self || $statements_analyzer->getSource()->getSource() instanceof TraitAnalyzer && $fq_class_name === $statements_analyzer->getSource()->getFQCLN()) { $class_visibility = ReflectionProperty::IS_PRIVATE; } elseif ($context->self && ($codebase->classlikes->classExtends($context->self, $fq_class_name) || $codebase->classlikes->classExtends($fq_class_name, $context->self))) { $class_visibility = ReflectionProperty::IS_PROTECTED; } else { $class_visibility = ReflectionProperty::IS_PUBLIC; } try { $class_constant_type = $codebase->classlikes->getClassConstantType($fq_class_name, $stmt->name->name, $class_visibility, $statements_analyzer, [], $stmt->class->getFirst() === "static"); } catch (InvalidArgumentException $_) { return \true; } catch (CircularReferenceException $e) { IssueBuffer::maybeAdd(new CircularReference('Constant ' . $const_id . ' contains a circular reference', new CodeLocation($statements_analyzer->getSource(), $stmt)), $statements_analyzer->getSuppressedIssues()); return \true; } if (!$class_constant_type) { if ($fq_class_name !== $context->self) { $class_constant_type = $codebase->classlikes->getClassConstantType($fq_class_name, $stmt->name->name, ReflectionProperty::IS_PRIVATE, $statements_analyzer); } if ($class_constant_type) { IssueBuffer::maybeAdd(new InaccessibleClassConstant('Constant ' . $const_id . ' is not visible in this context', new CodeLocation($statements_analyzer->getSource(), $stmt)), $statements_analyzer->getSuppressedIssues()); } elseif ($context->check_consts) { IssueBuffer::maybeAdd(new UndefinedConstant('Constant ' . $const_id . ' is not defined', new CodeLocation($statements_analyzer->getSource(), $stmt)), $statements_analyzer->getSuppressedIssues()); } return \true; } if ($context->calling_method_id) { $codebase->file_reference_provider->addMethodReferenceToClassMember($context->calling_method_id, $fq_class_name_lc . '::' . $stmt->name->name, \false); } $declaring_const_id = $fq_class_name_lc . '::' . $stmt->name->name; if ($codebase->alter_code && !$moved_class) { foreach ($codebase->class_constant_transforms as $original_pattern => $transformation) { if ($declaring_const_id === $original_pattern) { [$new_fq_class_name, $new_const_name] = explode('::', $transformation); $file_manipulations = []; if (strtolower($new_fq_class_name) !== $fq_class_name_lc) { $file_manipulations[] = new FileManipulation((int) $stmt->class->getAttribute('startFilePos'), (int) $stmt->class->getAttribute('endFilePos') + 1, Type::getStringFromFQCLN($new_fq_class_name, $statements_analyzer->getNamespace(), $statements_analyzer->getAliasedClassesFlipped(), null)); } $file_manipulations[] = new FileManipulation((int) $stmt->name->getAttribute('startFilePos'), (int) $stmt->name->getAttribute('endFilePos') + 1, $new_const_name); FileManipulationBuffer::add($statements_analyzer->getFilePath(), $file_manipulations); } } } if ($context->self && !$context->collect_initializations && !$context->collect_mutations && !NamespaceAnalyzer::isWithinAny($context->self, $const_class_storage->internal)) { IssueBuffer::maybeAdd(new InternalClass($fq_class_name . ' is internal to ' . InternalClass::listToPhrase($const_class_storage->internal) . ' but called from ' . $context->self, new CodeLocation($statements_analyzer->getSource(), $stmt), $fq_class_name), $statements_analyzer->getSuppressedIssues()); } if ($const_class_storage->deprecated && $fq_class_name !== $context->self) { IssueBuffer::maybeAdd(new DeprecatedClass('Class ' . $fq_class_name . ' is deprecated', new CodeLocation($statements_analyzer->getSource(), $stmt), $fq_class_name), $statements_analyzer->getSuppressedIssues()); } elseif (isset($const_class_storage->constants[$stmt->name->name]) && $const_class_storage->constants[$stmt->name->name]->deprecated) { IssueBuffer::maybeAdd(new DeprecatedConstant('Constant ' . $const_id . ' is deprecated', new CodeLocation($statements_analyzer->getSource(), $stmt)), $statements_analyzer->getSuppressedIssues()); } if ($first_part_lc !== 'static' || $const_class_storage->final || $class_constant_type->from_docblock || isset($const_class_storage->constants[$stmt->name->name]) && $const_class_storage->constants[$stmt->name->name]->final) { $stmt_type = $class_constant_type; $statements_analyzer->node_data->setType($stmt, $stmt_type); $context->vars_in_scope[$const_id] = $stmt_type; } return \true; } $was_inside_general_use = $context->inside_general_use; $context->inside_general_use = \true; if (ExpressionAnalyzer::analyze($statements_analyzer, $stmt->class, $context) === \false) { $context->inside_general_use = $was_inside_general_use; return \false; } $context->inside_general_use = $was_inside_general_use; $lhs_type = $statements_analyzer->node_data->getType($stmt->class); if ($lhs_type === null) { return \true; } if ($stmt->name instanceof PhpParser\Node\Identifier && $stmt->name->name === 'class') { $class_string_types = []; $has_mixed_or_object = \false; foreach ($lhs_type->getAtomicTypes() as $lhs_atomic_type) { if ($lhs_atomic_type instanceof TNamedObject) { $class_string_types[] = new TClassString($lhs_atomic_type->value, $lhs_atomic_type); } elseif ($lhs_atomic_type instanceof TTemplateParam && $lhs_atomic_type->as->isSingle()) { $as_atomic_type = $lhs_atomic_type->as->getSingleAtomic(); if ($as_atomic_type instanceof TObject) { $class_string_types[] = new TTemplateParamClass($lhs_atomic_type->param_name, 'object', null, $lhs_atomic_type->defining_class); } elseif ($as_atomic_type instanceof TNamedObject) { $class_string_types[] = new TTemplateParamClass($lhs_atomic_type->param_name, $as_atomic_type->value, $as_atomic_type, $lhs_atomic_type->defining_class); } } elseif ($lhs_atomic_type instanceof TObject || $lhs_atomic_type instanceof TMixed) { $has_mixed_or_object = \true; } } if ($has_mixed_or_object) { $statements_analyzer->node_data->setType($stmt, new Union([new TClassString()])); } elseif ($class_string_types) { $statements_analyzer->node_data->setType($stmt, new Union($class_string_types)); } return \true; } if ($stmt->class instanceof PhpParser\Node\Expr\Variable) { $fq_class_name = null; $lhs_type_definite_class = null; if ($lhs_type->isSingle()) { $atomic_type = $lhs_type->getSingleAtomic(); if ($atomic_type instanceof TNamedObject) { $fq_class_name = $atomic_type->value; $lhs_type_definite_class = $atomic_type->definite_class; } elseif ($atomic_type instanceof TLiteralClassString) { $fq_class_name = $atomic_type->value; $lhs_type_definite_class = $atomic_type->definite_class; } elseif ($atomic_type instanceof TString && !$atomic_type instanceof TClassString && !$codebase->config->allow_string_standin_for_class) { IssueBuffer::maybeAdd(new InvalidStringClass('String cannot be used as a class', new CodeLocation($statements_analyzer->getSource(), $stmt->class)), $statements_analyzer->getSuppressedIssues()); } } if ($fq_class_name === null || $lhs_type_definite_class === null) { return \true; } if ($codebase->classlikes->classExists($fq_class_name)) { $fq_class_name = $codebase->classlikes->getUnAliasedName($fq_class_name); } $moved_class = \false; if ($codebase->alter_code) { $moved_class = $codebase->classlikes->handleClassLikeReferenceInMigration($codebase, $statements_analyzer, $stmt->class, $fq_class_name, $context->calling_method_id); } // if we're ignoring that the class doesn't exist, exit anyway if (!$codebase->classlikes->classOrInterfaceOrEnumExists($fq_class_name)) { return \true; } if ($codebase->store_node_types && !$context->collect_initializations && !$context->collect_mutations) { $codebase->analyzer->addNodeReference($statements_analyzer->getFilePath(), $stmt->class, $fq_class_name); } if (!$stmt->name instanceof PhpParser\Node\Identifier) { return \true; } $const_id = $fq_class_name . '::' . $stmt->name; if ($codebase->store_node_types && !$context->collect_initializations && !$context->collect_mutations) { $codebase->analyzer->addNodeReference($statements_analyzer->getFilePath(), $stmt->name, $const_id); } $const_class_storage = $codebase->classlike_storage_provider->get($fq_class_name); if ($fq_class_name === $context->self || $statements_analyzer->getSource()->getSource() instanceof TraitAnalyzer && $fq_class_name === $statements_analyzer->getSource()->getFQCLN()) { $class_visibility = ReflectionProperty::IS_PRIVATE; } elseif ($context->self && ($codebase->classlikes->classExtends($context->self, $fq_class_name) || $codebase->classlikes->classExtends($fq_class_name, $context->self))) { $class_visibility = ReflectionProperty::IS_PROTECTED; } else { $class_visibility = ReflectionProperty::IS_PUBLIC; } try { $class_constant_type = $codebase->classlikes->getClassConstantType($fq_class_name, $stmt->name->name, $class_visibility, $statements_analyzer); } catch (InvalidArgumentException $_) { return \true; } catch (CircularReferenceException $e) { IssueBuffer::maybeAdd(new CircularReference('Constant ' . $const_id . ' contains a circular reference', new CodeLocation($statements_analyzer->getSource(), $stmt)), $statements_analyzer->getSuppressedIssues()); return \true; } if (!$class_constant_type) { if ($fq_class_name !== $context->self) { $class_constant_type = $codebase->classlikes->getClassConstantType($fq_class_name, $stmt->name->name, ReflectionProperty::IS_PRIVATE, $statements_analyzer); } if ($class_constant_type) { IssueBuffer::maybeAdd(new InaccessibleClassConstant('Constant ' . $const_id . ' is not visible in this context', new CodeLocation($statements_analyzer->getSource(), $stmt)), $statements_analyzer->getSuppressedIssues()); } elseif ($context->check_consts) { IssueBuffer::maybeAdd(new UndefinedConstant('Constant ' . $const_id . ' is not defined', new CodeLocation($statements_analyzer->getSource(), $stmt)), $statements_analyzer->getSuppressedIssues()); } return \true; } if ($context->calling_method_id) { $codebase->file_reference_provider->addMethodReferenceToClassMember($context->calling_method_id, strtolower($fq_class_name) . '::' . $stmt->name->name, \false); } $declaring_const_id = strtolower($fq_class_name) . '::' . $stmt->name->name; if ($codebase->alter_code && !$moved_class) { foreach ($codebase->class_constant_transforms as $original_pattern => $transformation) { if ($declaring_const_id === $original_pattern) { [, $new_const_name] = explode('::', $transformation); $file_manipulations = []; $file_manipulations[] = new FileManipulation((int) $stmt->name->getAttribute('startFilePos'), (int) $stmt->name->getAttribute('endFilePos') + 1, $new_const_name); FileManipulationBuffer::add($statements_analyzer->getFilePath(), $file_manipulations); } } } if ($context->self && !$context->collect_initializations && !$context->collect_mutations && !NamespaceAnalyzer::isWithinAny($context->self, $const_class_storage->internal)) { IssueBuffer::maybeAdd(new InternalClass($fq_class_name . ' is internal to ' . InternalClass::listToPhrase($const_class_storage->internal) . ' but called from ' . $context->self, new CodeLocation($statements_analyzer->getSource(), $stmt), $fq_class_name), $statements_analyzer->getSuppressedIssues()); } if ($const_class_storage->deprecated && $fq_class_name !== $context->self) { IssueBuffer::maybeAdd(new DeprecatedClass('Class ' . $fq_class_name . ' is deprecated', new CodeLocation($statements_analyzer->getSource(), $stmt), $fq_class_name), $statements_analyzer->getSuppressedIssues()); } elseif (isset($const_class_storage->constants[$stmt->name->name]) && $const_class_storage->constants[$stmt->name->name]->deprecated) { IssueBuffer::maybeAdd(new DeprecatedConstant('Constant ' . $const_id . ' is deprecated', new CodeLocation($statements_analyzer->getSource(), $stmt)), $statements_analyzer->getSuppressedIssues()); } if ($const_class_storage->final || $lhs_type_definite_class === \true) { $stmt_type = $class_constant_type; $statements_analyzer->node_data->setType($stmt, $stmt_type); $context->vars_in_scope[$const_id] = $stmt_type; } return \true; } return \true; } public static function analyzeAssignment(StatementsAnalyzer $statements_analyzer, PhpParser\Node\Stmt\ClassConst $stmt, Context $context) : void { assert($context->self !== null); $class_storage = $statements_analyzer->getCodebase()->classlike_storage_provider->get($context->self); foreach ($stmt->consts as $const) { ExpressionAnalyzer::analyze($statements_analyzer, $const->value, $context); $const_storage = $class_storage->constants[$const->name->name]; // Check assigned type matches docblock type if ($assigned_type = $statements_analyzer->node_data->getType($const->value)) { $const_storage_type = $const_storage->type; if ($const_storage_type !== null && $const_storage->stmt_location !== null && $assigned_type !== $const_storage_type && ($const_storage_type->from_docblock || $const_storage_type->from_property) && !UnionTypeComparator::isContainedBy($statements_analyzer->getCodebase(), $assigned_type, $const_storage_type)) { IssueBuffer::maybeAdd(new InvalidConstantAssignmentValue("{$class_storage->name}::{$const->name->name} with declared type " . "{$const_storage_type->getId()} cannot be assigned type {$assigned_type->getId()}", $const_storage->stmt_location, "{$class_storage->name}::{$const->name->name}"), $const_storage->suppressed_issues); } } } } public static function analyze(ClassLikeStorage $class_storage, Codebase $codebase) : void { foreach ($class_storage->constants as $const_name => $const_storage) { [$parent_classlike_storage, $parent_const_storage] = self::getOverriddenConstant($class_storage, $const_storage, $const_name, $codebase); $type_location = $const_storage->location ?? $const_storage->stmt_location; if ($type_location === null) { continue; } if ($parent_const_storage !== null) { assert($parent_classlike_storage !== null); // Check covariance if ($const_storage->type !== null && $parent_const_storage->type !== null && !UnionTypeComparator::isContainedBy($codebase, $const_storage->type, $parent_const_storage->type)) { if (UnionTypeComparator::isContainedBy($codebase, $parent_const_storage->type, $const_storage->type)) { // Contravariant IssueBuffer::maybeAdd(new LessSpecificClassConstantType("The type \"{$const_storage->type->getId()}\" for {$class_storage->name}::" . "{$const_name} is more general than the type " . "\"{$parent_const_storage->type->getId()}\" inherited from " . "{$parent_classlike_storage->name}::{$const_name}", $type_location, "{$class_storage->name}::{$const_name}"), $const_storage->suppressed_issues); } else { // Completely different IssueBuffer::maybeAdd(new InvalidClassConstantType("The type \"{$const_storage->type->getId()}\" for {$class_storage->name}::" . "{$const_name} does not satisfy the type " . "\"{$parent_const_storage->type->getId()}\" inherited from " . "{$parent_classlike_storage->name}::{$const_name}", $type_location, "{$class_storage->name}::{$const_name}"), $const_storage->suppressed_issues); } } // Check overridden final if ($parent_const_storage->final && $parent_const_storage !== $const_storage) { IssueBuffer::maybeAdd(new OverriddenFinalConstant("{$const_name} cannot be overridden because it is marked as final in " . $parent_classlike_storage->name, $type_location, "{$class_storage->name}::{$const_name}"), $const_storage->suppressed_issues); } } if ($const_storage->stmt_location !== null) { // Check final in PHP < 8.1 if ($codebase->analysis_php_version_id < 80100 && $const_storage->final) { IssueBuffer::maybeAdd(new ParseError("Class constants cannot be marked final before PHP 8.1", $const_storage->stmt_location), $const_storage->suppressed_issues); } } } } /** * Get the const storage from the parent or interface that this class is overriding. * * @return array{ClassLikeStorage, ClassConstantStorage}|null */ private static function getOverriddenConstant(ClassLikeStorage $class_storage, ClassConstantStorage $const_storage, string $const_name, Codebase $codebase) : ?array { $parent_classlike_storage = $interface_const_storage = $parent_const_storage = null; $interface_overrides = []; foreach ($class_storage->class_implements ?: $class_storage->direct_interface_parents as $interface) { $interface_storage = $codebase->classlike_storage_provider->get($interface); $parent_const_storage = $interface_storage->constants[$const_name] ?? null; if ($parent_const_storage !== null) { if ($const_storage->location && $const_storage !== $parent_const_storage && $codebase->analysis_php_version_id < 80100) { $interface_overrides[strtolower($interface)] = new OverriddenInterfaceConstant("{$class_storage->name}::{$const_name} cannot override constant from {$interface}", $const_storage->location, "{$class_storage->name}::{$const_name}"); } if ($interface_const_storage !== null && $const_storage->location !== null) { assert($parent_classlike_storage !== null); if (!isset($parent_classlike_storage->parent_interfaces[strtolower($interface)]) && !isset($interface_storage->parent_interfaces[strtolower($parent_classlike_storage->name)]) && $interface_const_storage !== $parent_const_storage) { IssueBuffer::maybeAdd(new AmbiguousConstantInheritance("Ambiguous inheritance of {$class_storage->name}::{$const_name} from {$interface} and " . $parent_classlike_storage->name, $const_storage->location, "{$class_storage->name}::{$const_name}"), $const_storage->suppressed_issues); } } $interface_const_storage = $parent_const_storage; $parent_classlike_storage = $interface_storage; } } foreach ($class_storage->parent_classes as $parent_class) { $parent_class_storage = $codebase->classlike_storage_provider->get($parent_class); $parent_const_storage = $parent_class_storage->constants[$const_name] ?? null; if ($parent_const_storage !== null) { if ($const_storage->location !== null && $interface_const_storage !== null) { assert($parent_classlike_storage !== null); if (!isset($parent_class_storage->class_implements[strtolower($parent_classlike_storage->name)])) { IssueBuffer::maybeAdd(new AmbiguousConstantInheritance("Ambiguous inheritance of {$class_storage->name}::{$const_name} from " . "{$parent_classlike_storage->name} and {$parent_class}", $const_storage->location, "{$class_storage->name}::{$const_name}"), $const_storage->suppressed_issues); } } foreach ($interface_overrides as $interface_lc => $_) { // If the parent is the one with the const that's overriding the interface const, and the parent // doesn't implement the interface, it's just an AmbiguousConstantInheritance, not an // OverriddenInterfaceConstant if (!isset($parent_class_storage->class_implements[$interface_lc]) && $parent_const_storage === $const_storage) { unset($interface_overrides[$interface_lc]); } } $parent_classlike_storage = $parent_class_storage; break; } } if ($parent_const_storage === null) { $parent_const_storage = $interface_const_storage; } foreach ($interface_overrides as $_ => $issue) { IssueBuffer::maybeAdd($issue, $const_storage->suppressed_issues); } if ($parent_classlike_storage !== null) { assert($parent_const_storage !== null); return [$parent_classlike_storage, $parent_const_storage]; } return null; } } getFQCLN(); $project_analyzer = $source->getFileAnalyzer()->project_analyzer; $codebase = $source->getCodebase(); if ($context->collect_mutations && $context->self && ($context->self === $fq_class_name || $codebase->classExtends($context->self, $fq_class_name))) { $method_id = new MethodIdentifier($fq_class_name, $method_name_lc); if ((string) $method_id !== $source->getId()) { if ($context->collect_initializations) { if (isset($context->initialized_methods[(string) $method_id])) { return; } if ($context->initialized_methods === null) { $context->initialized_methods = []; } $context->initialized_methods[(string) $method_id] = \true; } $project_analyzer->getMethodMutations($method_id, $context, $source->getRootFilePath(), $source->getRootFileName()); } } elseif ($context->collect_initializations && $context->self && ($context->self === $fq_class_name || $codebase->classlikes->classExtends($context->self, $fq_class_name)) && $source->getMethodName() !== $method_name) { $method_id = new MethodIdentifier($fq_class_name, $method_name_lc); $declaring_method_id = $codebase->methods->getDeclaringMethodId($method_id); if (isset($context->vars_in_scope['$this'])) { foreach ($context->vars_in_scope['$this']->getAtomicTypes() as $atomic_type) { if ($atomic_type instanceof TNamedObject) { if ($fq_class_name === $atomic_type->value) { $alt_declaring_method_id = $declaring_method_id; } else { $fq_class_name = $atomic_type->value; $method_id = new MethodIdentifier($fq_class_name, $method_name_lc); $alt_declaring_method_id = $codebase->methods->getDeclaringMethodId($method_id); } if ($alt_declaring_method_id) { $declaring_method_id = $alt_declaring_method_id; break; } if (!$atomic_type->extra_types) { continue; } foreach ($atomic_type->extra_types as $intersection_type) { if ($intersection_type instanceof TNamedObject) { $fq_class_name = $intersection_type->value; $method_id = new MethodIdentifier($fq_class_name, $method_name_lc); $alt_declaring_method_id = $codebase->methods->getDeclaringMethodId($method_id); if ($alt_declaring_method_id) { $declaring_method_id = $alt_declaring_method_id; break 2; } } } } } } if (!$declaring_method_id) { // can happen for __call return; } if (isset($context->initialized_methods[(string) $declaring_method_id])) { return; } if ($context->initialized_methods === null) { $context->initialized_methods = []; } $context->initialized_methods[(string) $declaring_method_id] = \true; $method_storage = $codebase->methods->getStorage($declaring_method_id); $class_analyzer = $source->getSource(); $is_final = $method_storage->final; if ($method_name !== $declaring_method_id->method_name) { $appearing_method_id = $codebase->methods->getAppearingMethodId($method_id); if ($appearing_method_id) { $appearing_class_storage = $codebase->classlike_storage_provider->get($appearing_method_id->fq_class_name); if (isset($appearing_class_storage->trait_final_map[$method_name_lc])) { $is_final = \true; } } } if ($class_analyzer instanceof ClassLikeAnalyzer && !$method_storage->is_static && ($context->collect_nonprivate_initializations || $method_storage->visibility === ClassLikeAnalyzer::VISIBILITY_PRIVATE || $is_final)) { $local_vars_in_scope = []; foreach ($context->vars_in_scope as $var_id => $type) { if (strpos($var_id, '$this->') === 0) { if ($type->initialized) { $local_vars_in_scope[$var_id] = $context->vars_in_scope[$var_id]; $context->remove($var_id, \false); } } elseif ($var_id !== '$this') { $local_vars_in_scope[$var_id] = $context->vars_in_scope[$var_id]; } } $local_vars_possibly_in_scope = $context->vars_possibly_in_scope; $old_calling_method_id = $context->calling_method_id; if ($fq_class_name === $source->getFQCLN()) { $class_analyzer->getMethodMutations($declaring_method_id->method_name, $context); } else { $declaring_fq_class_name = $declaring_method_id->fq_class_name; $old_self = $context->self; $context->self = $declaring_fq_class_name; $project_analyzer->getMethodMutations($declaring_method_id, $context, $source->getRootFilePath(), $source->getRootFileName()); $context->self = $old_self; } $context->calling_method_id = $old_calling_method_id; foreach ($local_vars_in_scope as $var => $type) { $context->vars_in_scope[$var] = $type; } foreach ($local_vars_possibly_in_scope as $var => $_) { $context->vars_possibly_in_scope[$var] = \true; } } } } /** * @param list $args */ public static function checkMethodArgs(?MethodIdentifier $method_id, array $args, TemplateResult $template_result, Context $context, CodeLocation $code_location, StatementsAnalyzer $statements_analyzer) : bool { $codebase = $statements_analyzer->getCodebase(); if (!$method_id) { return ArgumentsAnalyzer::analyze($statements_analyzer, $args, null, null, \true, $context, $template_result) !== \false; } $method_params = $codebase->methods->getMethodParams($method_id, $statements_analyzer, $args, $context); $fq_class_name = $method_id->fq_class_name; $method_name = $method_id->method_name; $fq_class_name = strtolower($codebase->classlikes->getUnAliasedName($fq_class_name)); $class_storage = $codebase->classlike_storage_provider->get($fq_class_name); $method_storage = null; if (isset($class_storage->declaring_method_ids[$method_name])) { $declaring_method_id = $class_storage->declaring_method_ids[$method_name]; $declaring_fq_class_name = $declaring_method_id->fq_class_name; $declaring_method_name = $declaring_method_id->method_name; if ($declaring_fq_class_name !== $fq_class_name) { $declaring_class_storage = $codebase->classlike_storage_provider->get($declaring_fq_class_name); } else { $declaring_class_storage = $class_storage; } if (!isset($declaring_class_storage->methods[$declaring_method_name])) { throw new UnexpectedValueException('Storage should not be empty here'); } $method_storage = $declaring_class_storage->methods[$declaring_method_name]; if ($declaring_class_storage->user_defined && !$method_storage->has_docblock_param_types && isset($declaring_class_storage->documenting_method_ids[$method_name])) { $documenting_method_id = $declaring_class_storage->documenting_method_ids[$method_name]; $documenting_method_storage = $codebase->methods->getStorage($documenting_method_id); if ($documenting_method_storage->template_types) { $method_storage = $documenting_method_storage; } } if (!$context->isSuppressingExceptions($statements_analyzer)) { $context->mergeFunctionExceptions($method_storage, $code_location); } } if (ArgumentsAnalyzer::analyze($statements_analyzer, $args, $method_params, (string) $method_id, $method_storage->allow_named_arg_calls ?? \true, $context, $template_result) === \false) { return \false; } if (ArgumentsAnalyzer::checkArgumentsMatch($statements_analyzer, $args, $method_id, $method_params, $method_storage, $class_storage, $template_result, $code_location, $context) === \false) { return \false; } if ($template_result->template_types) { self::checkTemplateResult($statements_analyzer, $template_result, $code_location, strtolower((string) $method_id)); } return \true; } /** * This gets all the template params (and their types) that we think * we'll need to know about * * @return array> * @param array> $existing_template_types * @param array> $class_template_params */ public static function getTemplateTypesForCall(Codebase $codebase, ?ClassLikeStorage $declaring_class_storage, ?string $appearing_class_name, ?ClassLikeStorage $calling_class_storage, array $existing_template_types = [], array $class_template_params = []) : array { $template_types = $existing_template_types; if ($declaring_class_storage) { if ($calling_class_storage && $declaring_class_storage !== $calling_class_storage && $calling_class_storage->template_extended_params) { foreach ($calling_class_storage->template_extended_params as $class_name => $type_map) { foreach ($type_map as $template_name => $type) { if ($class_name === $declaring_class_storage->name) { $output_type = null; foreach ($type->getAtomicTypes() as $atomic_type) { if ($atomic_type instanceof TTemplateParam) { $output_type_candidate = self::getGenericParamForOffset($atomic_type->defining_class, $atomic_type->param_name, $calling_class_storage->template_extended_params, $class_template_params + $template_types); } else { $output_type_candidate = new Union([$atomic_type]); } $output_type = Type::combineUnionTypes($output_type_candidate, $output_type); } $template_types[$template_name][$declaring_class_storage->name] = $output_type; } } } } elseif ($declaring_class_storage->template_types) { foreach ($declaring_class_storage->template_types as $template_name => $type_map) { foreach ($type_map as $key => $type) { $template_types[$template_name][$key] = $class_template_params[$template_name][$key] ?? $type; } } } } foreach ($template_types as $key => $type_map) { foreach ($type_map as $class => $type) { $template_types[$key][$class] = TypeExpander::expandUnion($codebase, $type, $appearing_class_name, $calling_class_storage->name ?? null, null, \true, \false, $calling_class_storage->final ?? \false); } } return $template_types; } /** * @param array> $template_extended_params * @param array> $found_generic_params */ public static function getGenericParamForOffset(string $fq_class_name, string $template_name, array $template_extended_params, array $found_generic_params) : Union { if (isset($found_generic_params[$template_name][$fq_class_name])) { return $found_generic_params[$template_name][$fq_class_name]; } foreach ($template_extended_params as $extended_class_name => $type_map) { foreach ($type_map as $extended_template_name => $extended_type) { foreach ($extended_type->getAtomicTypes() as $extended_atomic_type) { if ($extended_atomic_type instanceof TTemplateParam && $extended_atomic_type->param_name === $template_name && $extended_atomic_type->defining_class === $fq_class_name) { return self::getGenericParamForOffset($extended_class_name, $extended_template_name, $template_extended_params, $found_generic_params); } } } } return Type::getMixed(); } /** * @param PhpParser\Node\Scalar\String_|PhpParser\Node\Expr\Array_|PhpParser\Node\Expr\BinaryOp\Concat $callable_arg * @return list */ public static function getFunctionIdsFromCallableArg(FileSource $file_source, PhpParser\Node\Expr $callable_arg) : array { if ($callable_arg instanceof PhpParser\Node\Expr\BinaryOp\Concat) { if ($callable_arg->left instanceof PhpParser\Node\Expr\ClassConstFetch && $callable_arg->left->class instanceof Name && $callable_arg->left->name instanceof Identifier && strtolower($callable_arg->left->name->name) === 'class' && !in_array(strtolower($callable_arg->left->class->getFirst()), ['self', 'static', 'parent']) && $callable_arg->right instanceof PhpParser\Node\Scalar\String_ && preg_match('/^::[A-Za-z0-9]+$/', $callable_arg->right->value)) { $r = (string) $callable_arg->left->class->getAttribute('resolvedName') . $callable_arg->right->value; assert($r !== ''); return [$r]; } return []; } if ($callable_arg instanceof PhpParser\Node\Scalar\String_) { $potential_id = preg_replace('/^\\\\/', '', $callable_arg->value, 1); if (preg_match('/^[A-Za-z0-9_]+(\\\\[A-Za-z0-9_]+)*(::[A-Za-z0-9_]+)?$/', $potential_id)) { assert($potential_id !== ''); return [$potential_id]; } return []; } if (count($callable_arg->items) !== 2) { return []; } /** @psalm-suppress PossiblyNullPropertyFetch */ if ($callable_arg->items[0]->key || $callable_arg->items[1]->key) { return []; } if (!isset($callable_arg->items[0]) || !isset($callable_arg->items[1])) { throw new UnexpectedValueException('These should never be unset'); } $class_arg = $callable_arg->items[0]->value; $method_name_arg = $callable_arg->items[1]->value; if (!$method_name_arg instanceof PhpParser\Node\Scalar\String_) { return []; } if ($class_arg instanceof PhpParser\Node\Scalar\String_) { return [preg_replace('/^\\\\/', '', $class_arg->value, 1) . '::' . $method_name_arg->value]; } if ($class_arg instanceof PhpParser\Node\Expr\ClassConstFetch && $class_arg->name instanceof Identifier && strtolower($class_arg->name->name) === 'class' && $class_arg->class instanceof Name) { $fq_class_name = ClassLikeAnalyzer::getFQCLNFromNameObject($class_arg->class, $file_source->getAliases()); return [$fq_class_name . '::' . $method_name_arg->value]; } if (!$file_source instanceof StatementsAnalyzer || !($class_arg_type = $file_source->node_data->getType($class_arg))) { return []; } $method_ids = []; foreach ($class_arg_type->getAtomicTypes() as $type_part) { if ($type_part instanceof TNamedObject) { $method_id = $type_part->value . '::' . $method_name_arg->value; foreach ($type_part->extra_types as $extra_type) { if ($extra_type instanceof TTemplateParam || $extra_type instanceof TObjectWithProperties || $extra_type instanceof TCallableObject) { throw new UnexpectedValueException('Shouldn’t get a generic param here'); } $method_id .= '&' . $extra_type->value . '::' . $method_name_arg->value; } $method_ids[] = '$' . $method_id; } } return $method_ids; } /** * @param non-empty-string $function_id * @param bool $can_be_in_root_scope if true, the function can be shortened to the root version */ public static function checkFunctionExists(StatementsAnalyzer $statements_analyzer, string &$function_id, CodeLocation $code_location, bool $can_be_in_root_scope) : bool { $cased_function_id = $function_id; $function_id = strtolower($function_id); $codebase = $statements_analyzer->getCodebase(); if (!$codebase->functions->functionExists($statements_analyzer, $function_id)) { /** @var non-empty-lowercase-string */ $root_function_id = preg_replace('/.*\\\\/', '', $function_id); if ($can_be_in_root_scope && $function_id !== $root_function_id && $codebase->functions->functionExists($statements_analyzer, $root_function_id)) { $function_id = $root_function_id; } else { IssueBuffer::maybeAdd(new UndefinedFunction('Function ' . $cased_function_id . ' does not exist', $code_location, $function_id), $statements_analyzer->getSuppressedIssues()); return \false; } } return \true; } /** * @param Identifier|Name $expr * @param Possibilities[] $var_assertions * @param list $args */ public static function applyAssertionsToContext(PhpParser\NodeAbstract $expr, ?string $thisName, array $var_assertions, array $args, TemplateResult $template_result, Context $context, StatementsAnalyzer $statements_analyzer) : void { $type_assertions = []; $asserted_keys = []; foreach ($var_assertions as $var_possibilities) { $assertion_var_id = null; $arg_value = null; if (is_int($var_possibilities->var_id)) { if (!isset($args[$var_possibilities->var_id])) { continue; } $arg_value = $args[$var_possibilities->var_id]->value; $arg_var_id = \Psalm\Internal\Analyzer\Statements\Expression\ExpressionIdentifier::getExtendedVarId($arg_value, null, $statements_analyzer); if ($arg_var_id) { $assertion_var_id = $arg_var_id; } } elseif ($var_possibilities->var_id === '$this' && $thisName !== null) { $assertion_var_id = $thisName; } elseif (strpos($var_possibilities->var_id, '$this->') === 0 && $thisName !== null) { $assertion_var_id = $thisName . str_replace('$this->', '->', $var_possibilities->var_id); } elseif (strpos($var_possibilities->var_id, 'self::') === 0 && $context->self) { $assertion_var_id = $context->self . str_replace('self::', '::', $var_possibilities->var_id); } elseif (strpos($var_possibilities->var_id, '::$') !== \false) { // allow assertions to bring external static props into scope $assertion_var_id = $var_possibilities->var_id; } elseif (isset($context->vars_in_scope[$var_possibilities->var_id])) { $assertion_var_id = $var_possibilities->var_id; } elseif (strpos($var_possibilities->var_id, '->') !== \false) { $exploded = explode('->', $var_possibilities->var_id); if (count($exploded) < 2) { IssueBuffer::maybeAdd(new InvalidDocblock('Assert notation is malformed', new CodeLocation($statements_analyzer, $expr))); continue; } [$var_id, $property] = $exploded; $var_id = is_numeric($var_id) ? (int) $var_id : $var_id; if (!is_int($var_id) || !isset($args[$var_id])) { IssueBuffer::maybeAdd(new InvalidDocblock('Variable ' . $var_id . ' is not an argument so cannot be asserted', new CodeLocation($statements_analyzer, $expr))); continue; } /** @var PhpParser\Node\Expr\Variable $arg_value */ $arg_value = $args[$var_id]->value; $arg_var_id = \Psalm\Internal\Analyzer\Statements\Expression\ExpressionIdentifier::getExtendedVarId($arg_value, null, $statements_analyzer); if (!$arg_var_id) { IssueBuffer::maybeAdd(new InvalidDocblock('Variable being asserted as argument ' . ($var_id + 1) . ' cannot be found in local scope', new CodeLocation($statements_analyzer, $expr))); continue; } if (count($exploded) === 2) { $failedMessage = \Psalm\Internal\Analyzer\Statements\Expression\AssertionFinder::isPropertyImmutableOnArgument($property, $statements_analyzer->getNodeTypeProvider(), $statements_analyzer->getCodebase()->classlike_storage_provider, $arg_value); if (null !== $failedMessage) { IssueBuffer::maybeAdd(new InvalidDocblock($failedMessage, new CodeLocation($statements_analyzer, $expr))); continue; } } $assertion_var_id = str_replace((string) $var_id, $arg_var_id, $var_possibilities->var_id); } $codebase = $statements_analyzer->getCodebase(); if ($assertion_var_id) { $orred_rules = []; foreach ($var_possibilities->rule as $assertion_rule) { $assertion_type_atomic = $assertion_rule->getAtomicType(); if ($assertion_type_atomic) { $assertion_type = TemplateInferredTypeReplacer::replace(new Union([$assertion_type_atomic]), $template_result, $codebase); if (count($assertion_type->getAtomicTypes()) === 1) { foreach ($assertion_type->getAtomicTypes() as $atomic_type) { if ($assertion_type_atomic instanceof TTemplateParam && $assertion_type_atomic->as->getId() === $atomic_type->getId()) { continue; } $assertion_rule = $assertion_rule->setAtomicType($atomic_type); $orred_rules[] = $assertion_rule; } } elseif (isset($context->vars_in_scope[$assertion_var_id])) { $asserted_type = $context->vars_in_scope[$assertion_var_id]; if ($assertion_rule instanceof IsIdentical) { $intersection = Type::intersectUnionTypes($assertion_type, $asserted_type, $codebase); if ($intersection === null) { IssueBuffer::maybeAdd(new TypeDoesNotContainType($asserted_type->getId() . ' is not contained by ' . $assertion_type->getId(), new CodeLocation($statements_analyzer->getSource(), $expr), $asserted_type->getId() . ' ' . $assertion_type->getId()), $statements_analyzer->getSuppressedIssues()); $intersection = Type::getNever(); } elseif ($intersection->getId(\true) === $asserted_type->getId(\true)) { continue; } foreach ($intersection->getAtomicTypes() as $atomic_type) { $orred_rules[] = new IsIdentical($atomic_type); } } elseif ($assertion_rule instanceof IsType) { if (!UnionTypeComparator::canExpressionTypesBeIdentical($codebase, $assertion_type, $asserted_type)) { IssueBuffer::maybeAdd(new TypeDoesNotContainType($asserted_type->getId() . ' is not contained by ' . $assertion_type->getId(), new CodeLocation($statements_analyzer->getSource(), $expr), $asserted_type->getId() . ' ' . $assertion_type->getId()), $statements_analyzer->getSuppressedIssues()); } } else { // Ignore negations and loose assertions with union types } } } else { $orred_rules[] = $assertion_rule; } } if ($orred_rules) { if (isset($type_assertions[$assertion_var_id])) { $type_assertions[$assertion_var_id] = array_merge($type_assertions[$assertion_var_id], [$orred_rules]); } else { $type_assertions[$assertion_var_id] = [$orred_rules]; } } } elseif ($arg_value && count($var_possibilities->rule) === 1) { $assert_clauses = []; $single_rule = $var_possibilities->rule[0]; if ($single_rule instanceof Truthy) { $assert_clauses = FormulaGenerator::getFormula(spl_object_id($arg_value), spl_object_id($arg_value), $arg_value, $context->self, $statements_analyzer, $statements_analyzer->getCodebase()); } elseif ($single_rule instanceof Falsy) { $assert_clauses = Algebra::negateFormula(FormulaGenerator::getFormula(spl_object_id($arg_value), spl_object_id($arg_value), $arg_value, $context->self, $statements_analyzer, $codebase)); } elseif ($single_rule instanceof IsType && $single_rule->type instanceof TTrue) { $conditional = new VirtualIdentical($arg_value, new VirtualConstFetch(new VirtualName('true'))); $assert_clauses = FormulaGenerator::getFormula(mt_rand(0, 1000000), mt_rand(0, 1000000), $conditional, $context->self, $statements_analyzer, $codebase); } $simplified_clauses = Algebra::simplifyCNF([...$context->clauses, ...$assert_clauses]); $assert_type_assertions = Algebra::getTruthsFromFormula($simplified_clauses); $type_assertions = array_merge($type_assertions, $assert_type_assertions); } } $changed_var_ids = []; foreach ($type_assertions as $var_id => $_) { $asserted_keys[$var_id] = \true; } $codebase = $statements_analyzer->getCodebase(); if ($type_assertions) { $template_type_map = []; // while in an and, we allow scope to boil over to support // statements of the form if ($x && $x->foo()) [$op_vars_in_scope, $op_references_in_scope] = Reconciler::reconcileKeyedTypes($type_assertions, $type_assertions, $context->vars_in_scope, $context->references_in_scope, $changed_var_ids, $asserted_keys, $statements_analyzer, $template_type_map, $context->inside_loop, new CodeLocation($statements_analyzer->getSource(), $expr)); foreach ($changed_var_ids as $var_id => $_) { if (isset($op_vars_in_scope[$var_id])) { $first_appearance = $statements_analyzer->getFirstAppearance($var_id); if ($first_appearance && isset($context->vars_in_scope[$var_id]) && $context->vars_in_scope[$var_id]->hasMixed()) { if (!$context->collect_initializations && !$context->collect_mutations && $statements_analyzer->getFilePath() === $statements_analyzer->getRootFilePath() && (!($parent_source = $statements_analyzer->getSource()) instanceof FunctionLikeAnalyzer || !$parent_source->getSource() instanceof TraitAnalyzer)) { $codebase->analyzer->decrementMixedCount($statements_analyzer->getFilePath()); } IssueBuffer::remove($statements_analyzer->getFilePath(), 'MixedAssignment', $first_appearance->raw_file_start); } $op_vars_in_scope[$var_id] = $op_vars_in_scope[$var_id]->setFromDocblock(\true); } } $context->vars_in_scope = $op_vars_in_scope; $context->references_in_scope = $op_references_in_scope; } } /** * This method looks for problems with a generated TemplateResult. * * The TemplateResult object contains upper bounds and lower bounds for each template param. * * Those upper bounds represent a series of constraints like * * Lower bound: * T >: X (the type param T matches X, or is a supertype of X) * Upper bound: * T <: Y (the type param T matches Y, or is a subtype of Y) * Equality (currently represented as an upper bound with a special flag) * T = Z (the template T must match Z) * * This method attempts to reconcile those constraints. * * Valid constraints: * * T <: int|float, T >: int --- implies T is an int * T = int --- implies T is an int * * Invalid constraints: * * T <: int|string, T >: string|float --- implies T <: int and T >: float, which is impossible * T = int, T = string --- implies T is a string _and_ and int, which is impossible */ public static function checkTemplateResult(StatementsAnalyzer $statements_analyzer, TemplateResult $template_result, CodeLocation $code_location, ?string $function_id) : void { if ($template_result->lower_bounds && $template_result->upper_bounds) { foreach ($template_result->upper_bounds as $template_name => $defining_map) { foreach ($defining_map as $defining_id => $upper_bound) { if (isset($template_result->lower_bounds[$template_name][$defining_id])) { $lower_bound_type = TemplateStandinTypeReplacer::getMostSpecificTypeFromBounds($template_result->lower_bounds[$template_name][$defining_id], $statements_analyzer->getCodebase()); $upper_bound_type = $upper_bound->type; $union_comparison_result = new TypeComparisonResult(); if (count($template_result->upper_bounds_unintersectable_types) > 1) { [$lower_bound_type, $upper_bound_type] = $template_result->upper_bounds_unintersectable_types; } if (!UnionTypeComparator::isContainedBy($statements_analyzer->getCodebase(), $lower_bound_type, $upper_bound_type, \false, \false, $union_comparison_result)) { if ($union_comparison_result->type_coerced) { if ($union_comparison_result->type_coerced_from_mixed) { IssueBuffer::maybeAdd(new MixedArgumentTypeCoercion('Type ' . $lower_bound_type->getId() . ' should be a subtype of ' . $upper_bound_type->getId(), $code_location, $function_id), $statements_analyzer->getSuppressedIssues()); } else { IssueBuffer::maybeAdd(new ArgumentTypeCoercion('Type ' . $lower_bound_type->getId() . ' should be a subtype of ' . $upper_bound_type->getId(), $code_location, $function_id), $statements_analyzer->getSuppressedIssues()); } } elseif ($union_comparison_result->scalar_type_match_found) { IssueBuffer::maybeAdd(new InvalidScalarArgument('Type ' . $lower_bound_type->getId() . ' should be a subtype of ' . $upper_bound_type->getId(), $code_location, $function_id), $statements_analyzer->getSuppressedIssues()); } else { IssueBuffer::maybeAdd(new InvalidArgument('Type ' . $lower_bound_type->getId() . ' should be a subtype of ' . $upper_bound_type->getId(), $code_location, $function_id), $statements_analyzer->getSuppressedIssues()); } } } else { $template_result->lower_bounds[$template_name][$defining_id] = [new TemplateBound($upper_bound->type)]; } } } } // Attempt to identify invalid lower bounds foreach ($template_result->lower_bounds as $template_name => $lower_bounds) { foreach ($lower_bounds as $lower_bounds) { if (count($lower_bounds) > 1) { $bounds_with_equality = array_filter($lower_bounds, static fn($lower_bound): bool => (bool) $lower_bound->equality_bound_classlike); if (!$bounds_with_equality) { continue; } $equality_types = array_unique(array_map(static fn($bound_with_equality) => $bound_with_equality->type->getId(), $bounds_with_equality)); if (count($equality_types) > 1) { IssueBuffer::maybeAdd(new InvalidArgument('Incompatible types found for ' . $template_name . ' (must have only one of ' . implode(', ', $equality_types) . ')', $code_location, $function_id), $statements_analyzer->getSuppressedIssues()); } else { foreach ($lower_bounds as $lower_bound) { if ($lower_bound->equality_bound_classlike === null) { foreach ($bounds_with_equality as $bound_with_equality) { if (UnionTypeComparator::isContainedBy($statements_analyzer->getCodebase(), $lower_bound->type, $bound_with_equality->type)) { continue 2; } } IssueBuffer::maybeAdd(new InvalidArgument('Incompatible types found for ' . $template_name . ' (' . $lower_bound->type->getId() . ' is not in ' . implode(', ', $equality_types) . ')', $code_location, $function_id), $statements_analyzer->getSuppressedIssues()); } } } } } } } } getDocComment(); $var_comments = []; $var_comment_type = null; $codebase = $statements_analyzer->getCodebase(); if ($doc_comment) { try { $var_comments = CommentAnalyzer::getTypeFromComment($doc_comment, $statements_analyzer, $statements_analyzer->getAliases()); } catch (DocblockParseException $e) { IssueBuffer::maybeAdd(new InvalidDocblock($e->getMessage(), new CodeLocation($statements_analyzer->getSource(), $stmt))); } foreach ($var_comments as $var_comment) { if (!$var_comment->type) { continue; } $comment_type = TypeExpander::expandUnion($codebase, $var_comment->type, $context->self, $context->self ? new TNamedObject($context->self) : null, $statements_analyzer->getParentFQCLN()); $type_location = null; if ($var_comment->type_start && $var_comment->type_end && $var_comment->line_number) { $type_location = new DocblockTypeLocation($statements_analyzer, $var_comment->type_start, $var_comment->type_end, $var_comment->line_number); } if (!$var_comment->var_id) { $var_comment_type = $comment_type; continue; } if ($codebase->find_unused_variables && $type_location && isset($context->vars_in_scope[$var_comment->var_id]) && $context->vars_in_scope[$var_comment->var_id]->getId() === $comment_type->getId()) { $project_analyzer = $statements_analyzer->getProjectAnalyzer(); if ($codebase->alter_code && isset($project_analyzer->getIssuesToFix()['UnnecessaryVarAnnotation'])) { FileManipulationBuffer::addVarAnnotationToRemove($type_location); } else { IssueBuffer::maybeAdd(new UnnecessaryVarAnnotation('The @var annotation for ' . $var_comment->var_id . ' is unnecessary', $type_location), $statements_analyzer->getSuppressedIssues(), \true); } } if (isset($context->vars_in_scope[$var_comment->var_id])) { $comment_type = $comment_type->setParentNodes($context->vars_in_scope[$var_comment->var_id]->parent_nodes); } $context->vars_in_scope[$var_comment->var_id] = $comment_type; } } if ($stmt->key) { $context->inside_call = \true; if (ExpressionAnalyzer::analyze($statements_analyzer, $stmt->key, $context) === \false) { return \false; } $context->inside_call = \false; } if ($stmt->value) { $context->inside_call = \true; if (ExpressionAnalyzer::analyze($statements_analyzer, $stmt->value, $context) === \false) { return \false; } $context->inside_call = \false; if ($var_comment_type) { $expression_type = $var_comment_type; } elseif ($stmt_var_type = $statements_analyzer->node_data->getType($stmt->value)) { $expression_type = $stmt_var_type; } else { $expression_type = Type::getMixed(); } } else { $expression_type = Type::getNever(); } $yield_type = null; foreach ($expression_type->getAtomicTypes() as $expression_atomic_type) { if (!$expression_atomic_type instanceof TNamedObject) { continue; } if (!$codebase->classlikes->classOrInterfaceExists($expression_atomic_type->value)) { continue; } $classlike_storage = $codebase->classlike_storage_provider->get($expression_atomic_type->value); if (!$classlike_storage->yield) { continue; } $declaring_classlike_storage = $classlike_storage->declaring_yield_fqcn ? $codebase->classlike_storage_provider->get($classlike_storage->declaring_yield_fqcn) : $classlike_storage; $yield_candidate_type = $classlike_storage->yield; $yield_candidate_type = !$yield_candidate_type->isMixed() ? TypeExpander::expandUnion($codebase, $yield_candidate_type, $expression_atomic_type->value, $expression_atomic_type->value, null, \true, \false) : $yield_candidate_type; $class_template_params = ClassTemplateParamCollector::collect($codebase, $declaring_classlike_storage, $classlike_storage, null, $expression_atomic_type, \true); if ($class_template_params) { if (!$expression_atomic_type instanceof TGenericObject) { $type_params = []; foreach ($class_template_params as $type_map) { $type_params[] = array_values($type_map)[0]; } $expression_atomic_type = new TGenericObject($expression_atomic_type->value, $type_params); } $yield_candidate_type = AtomicPropertyFetchAnalyzer::localizePropertyType($codebase, $yield_candidate_type, $expression_atomic_type, $classlike_storage, $declaring_classlike_storage); } $yield_type = Type::combineUnionTypes($yield_type, $yield_candidate_type, $codebase); } if ($yield_type) { $expression_type = $expression_type->getBuilder()->substitute($expression_type, $yield_type)->freeze(); } $statements_analyzer->node_data->setType($stmt, $expression_type); $source = $statements_analyzer->getSource(); if ($source instanceof FunctionLikeAnalyzer && !$source->getSource() instanceof TraitAnalyzer) { $source->examineParamTypes($statements_analyzer, $context, $codebase, $stmt); $storage = $source->getFunctionLikeStorage($statements_analyzer); if ($storage->return_type && !$yield_type) { foreach ($storage->return_type->getAtomicTypes() as $atomic_return_type) { if ($atomic_return_type instanceof TNamedObject && $atomic_return_type->value === 'Generator') { if ($atomic_return_type instanceof TGenericObject) { if (!$atomic_return_type->type_params[2]->isVoid()) { $statements_analyzer->node_data->setType($stmt, $atomic_return_type->type_params[2]); } } else { $statements_analyzer->node_data->setType($stmt, Type::combineUnionTypes(Type::getMixed(), $expression_type)); } } } } } return \true; } } */ public array $item_key_atomic_types = []; /** * @var list */ public array $item_value_atomic_types = []; /** * @var array */ public array $property_types = []; /** * @var array */ public array $class_strings = []; public bool $can_create_objectlike = \true; /** * @var array */ public array $array_keys = []; /** * Holds the integer offset of the *last* element added * * -1 may mean no elements have been added yet, but can also mean there's an element with offset -1 */ public int $int_offset = -1; public bool $all_list = \true; /** * @var array */ public array $parent_taint_nodes = []; public bool $can_be_empty = \true; } inside_call; $context->inside_call = \true; $was_inside_conditional = $context->inside_conditional; $context->inside_conditional = \true; if (ExpressionAnalyzer::analyze($statements_analyzer, $stmt->cond, $context) === \false) { $context->inside_conditional = $was_inside_conditional; return \false; } $context->inside_conditional = $was_inside_conditional; $switch_var_id = \Psalm\Internal\Analyzer\Statements\Expression\ExpressionIdentifier::getExtendedVarId($stmt->cond, null, $statements_analyzer); $match_condition = $stmt->cond; if (!$switch_var_id) { if ($stmt->cond instanceof PhpParser\Node\Expr\FuncCall && $stmt->cond->name instanceof PhpParser\Node\Name && ($stmt->cond->name->getParts() === ['get_class'] || $stmt->cond->name->getParts() === ['gettype'] || $stmt->cond->name->getParts() === ['get_debug_type'] || $stmt->cond->name->getParts() === ['count'] || $stmt->cond->name->getParts() === ['sizeof']) && $stmt->cond->getArgs()) { $first_arg = $stmt->cond->getArgs()[0]; if (!$first_arg->value instanceof PhpParser\Node\Expr\Variable) { $switch_var_id = '$__tmp_switch__' . (int) $first_arg->value->getAttribute('startFilePos'); $condition_type = $statements_analyzer->node_data->getType($first_arg->value) ?? Type::getMixed(); $context->vars_in_scope[$switch_var_id] = $condition_type; $match_condition = new VirtualFuncCall($stmt->cond->name, [new VirtualArg(new VirtualVariable(substr($switch_var_id, 1), $first_arg->value->getAttributes()), \false, \false, $first_arg->getAttributes())], $stmt->cond->getAttributes()); } } elseif ($stmt->cond instanceof PhpParser\Node\Expr\ClassConstFetch && $stmt->cond->name instanceof PhpParser\Node\Identifier && $stmt->cond->name->toString() === 'class') { // do nothing } elseif ($stmt->cond instanceof PhpParser\Node\Expr\ConstFetch && $stmt->cond->name->toString() === 'true') { // do nothing } else { $switch_var_id = '$__tmp_switch__' . (int) $stmt->cond->getAttribute('startFilePos'); $condition_type = $statements_analyzer->node_data->getType($stmt->cond) ?? Type::getMixed(); $context->vars_in_scope[$switch_var_id] = $condition_type; $match_condition = new VirtualVariable(substr($switch_var_id, 1), $stmt->cond->getAttributes()); } } $arms = $stmt->arms; $flattened_arms = []; $last_arm = null; foreach ($arms as $arm) { if ($arm->conds === null) { $last_arm = $arm; continue; } foreach ($arm->conds as $cond) { $flattened_arms[] = new PhpParser\Node\MatchArm([$cond], $arm->body, $arm->getAttributes()); } } $arms = $flattened_arms; $arms = array_reverse($arms); $last_arm ??= array_shift($arms); if (!$last_arm) { IssueBuffer::maybeAdd(new UnhandledMatchCondition('This match expression does not match anything', new CodeLocation($statements_analyzer->getSource(), $match_condition)), $statements_analyzer->getSuppressedIssues()); return \false; } $old_node_data = $statements_analyzer->node_data; $statements_analyzer->node_data = clone $statements_analyzer->node_data; if (!$last_arm->conds) { $ternary = $last_arm->body; } else { $ternary = new VirtualTernary(self::convertCondsToConditional($last_arm->conds, $match_condition, $last_arm->getAttributes()), $last_arm->body, new VirtualThrow(new VirtualNew(new VirtualFullyQualified('UnhandledMatchError', $stmt->getAttributes()), [], $stmt->getAttributes())), $stmt->getAttributes()); } foreach ($arms as $arm) { if (!$arm->conds) { continue; } $ternary = new VirtualTernary(self::convertCondsToConditional($arm->conds, $match_condition, $arm->getAttributes()), $arm->body, $ternary, $arm->getAttributes()); } $suppressed_issues = $statements_analyzer->getSuppressedIssues(); if (!in_array('RedundantCondition', $suppressed_issues, \true)) { $statements_analyzer->addSuppressedIssues(['RedundantCondition']); } if (!in_array('RedundantConditionGivenDocblockType', $suppressed_issues, \true)) { $statements_analyzer->addSuppressedIssues(['RedundantConditionGivenDocblockType']); } if (ExpressionAnalyzer::analyze($statements_analyzer, $ternary, $context) === \false) { return \false; } if (!in_array('RedundantCondition', $suppressed_issues, \true)) { $statements_analyzer->removeSuppressedIssues(['RedundantCondition']); } if (!in_array('RedundantConditionGivenDocblockType', $suppressed_issues, \true)) { $statements_analyzer->removeSuppressedIssues(['RedundantConditionGivenDocblockType']); } if ($switch_var_id && $last_arm->conds) { $codebase = $statements_analyzer->getCodebase(); $all_conds = $last_arm->conds; foreach ($arms as $arm) { if (!$arm->conds) { throw new UnexpectedValueException('bad'); } $all_conds = array_merge($arm->conds, $all_conds); } $all_match_condition = self::convertCondsToConditional($all_conds, $match_condition, $match_condition->getAttributes()); ExpressionAnalyzer::analyze($statements_analyzer, $all_match_condition, $context); $clauses = FormulaGenerator::getFormula(spl_object_id($all_match_condition), spl_object_id($all_match_condition), $all_match_condition, $context->self, $statements_analyzer, $codebase, \false, \false); $reconcilable_types = Algebra::getTruthsFromFormula(Algebra::negateFormula($clauses)); // if the if has an || in the conditional, we cannot easily reason about it if ($reconcilable_types) { $changed_var_ids = []; [$vars_in_scope_reconciled, $_] = Reconciler::reconcileKeyedTypes($reconcilable_types, [], $context->vars_in_scope, $context->references_in_scope, $changed_var_ids, [], $statements_analyzer, [], $context->inside_loop, null); if (isset($vars_in_scope_reconciled[$switch_var_id])) { $array_literal_types = array_filter($vars_in_scope_reconciled[$switch_var_id]->getAtomicTypes(), static fn(Atomic $type): bool => $type instanceof TLiteralInt || $type instanceof TLiteralString || $type instanceof TLiteralFloat || $type instanceof TEnumCase); if ($array_literal_types) { IssueBuffer::maybeAdd(new UnhandledMatchCondition('This match expression is not exhaustive - consider values ' . $vars_in_scope_reconciled[$switch_var_id]->getId(), new CodeLocation($statements_analyzer->getSource(), $match_condition)), $statements_analyzer->getSuppressedIssues()); } } } } $stmt_expr_type = $statements_analyzer->node_data->getType($ternary); $old_node_data->setType($stmt, $stmt_expr_type ?? Type::getMixed()); $statements_analyzer->node_data = $old_node_data; $context->inside_call = $was_inside_call; return \true; } /** * @param non-empty-list $conds */ private static function convertCondsToConditional(array $conds, PhpParser\Node\Expr $match_condition, array $attributes) : PhpParser\Node\Expr { if (count($conds) === 1) { return new VirtualIdentical($match_condition, $conds[0], $attributes); } $array_items = array_map(static fn(PhpParser\Node\Expr $cond): PhpParser\Node\Expr\ArrayItem => new VirtualArrayItem($cond, null, \false, $cond->getAttributes()), $conds); return new VirtualFuncCall(new VirtualFullyQualified(['in_array']), [new VirtualArg($match_condition, \false, \false, $attributes), new VirtualArg(new VirtualArray($array_items, $attributes), \false, \false, $attributes), new VirtualArg(new VirtualConstFetch(new VirtualFullyQualified(['true']), $attributes), \false, \false, $attributes)], $attributes); } } getProjectAnalyzer()->getConfig(); $forbidden = null; if (isset($config->forbidden_functions['exit']) && $stmt->getAttribute('kind') === Exit_::KIND_EXIT) { $forbidden = 'exit'; } elseif (isset($config->forbidden_functions['die']) && $stmt->getAttribute('kind') === Exit_::KIND_DIE) { $forbidden = 'die'; } if ($forbidden) { IssueBuffer::maybeAdd(new ForbiddenCode('You have forbidden the use of ' . $forbidden, new CodeLocation($statements_analyzer, $stmt)), $statements_analyzer->getSuppressedIssues()); } if ($stmt->expr) { $context->inside_call = \true; if (ExpressionAnalyzer::analyze($statements_analyzer, $stmt->expr, $context) === \false) { return \false; } if ($statements_analyzer->data_flow_graph instanceof TaintFlowGraph) { $call_location = new CodeLocation($statements_analyzer->getSource(), $stmt); $echo_param_sink = TaintSink::getForMethodArgument('exit', 'exit', 0, null, $call_location); $echo_param_sink->taints = [TaintKind::INPUT_HTML, TaintKind::INPUT_HAS_QUOTES, TaintKind::USER_SECRET, TaintKind::SYSTEM_SECRET]; $statements_analyzer->data_flow_graph->addSink($echo_param_sink); } if ($expr_type = $statements_analyzer->node_data->getType($stmt->expr)) { $exit_param = new FunctionLikeParameter('var', \false); if (ArgumentAnalyzer::verifyType($statements_analyzer, $expr_type, new Union([new TInt(), new TString()]), null, 'exit', null, 0, new CodeLocation($statements_analyzer->getSource(), $stmt->expr), $stmt->expr, $context, $exit_param, \false, null, \true, \true, new CodeLocation($statements_analyzer, $stmt)) === \false) { return \false; } } $context->inside_call = \false; } if ($expr_type && !$expr_type->isInt() && !$context->collect_mutations && !$context->collect_initializations) { if ($context->mutation_free || $context->external_mutation_free) { $function_name = $stmt->getAttribute('kind') === Exit_::KIND_DIE ? 'die' : 'exit'; IssueBuffer::maybeAdd(new ImpureFunctionCall('Cannot call ' . $function_name . ' with a non-integer argument from a mutation-free context', new CodeLocation($statements_analyzer, $stmt)), $statements_analyzer->getSuppressedIssues()); } elseif ($statements_analyzer->getSource() instanceof FunctionLikeAnalyzer && $statements_analyzer->getSource()->track_mutations) { $statements_analyzer->getSource()->inferred_has_mutation = \true; $statements_analyzer->getSource()->inferred_impure = \true; } } $statements_analyzer->node_data->setType($stmt, Type::getNever()); $context->has_returned = \true; return \true; } } 100) { $statements_analyzer->node_data->setType($stmt, Type::getString()); // ignore deeply-nested string concatenation return \true; } if ($stmt instanceof PhpParser\Node\Expr\BinaryOp\BooleanAnd || $stmt instanceof PhpParser\Node\Expr\BinaryOp\LogicalAnd) { $was_inside_general_use = $context->inside_general_use; $context->inside_general_use = \true; $expr_result = AndAnalyzer::analyze($statements_analyzer, $stmt, $context, $from_stmt); $context->inside_general_use = $was_inside_general_use; $statements_analyzer->node_data->setType($stmt, Type::getBool()); return $expr_result; } if ($stmt instanceof PhpParser\Node\Expr\BinaryOp\BooleanOr || $stmt instanceof PhpParser\Node\Expr\BinaryOp\LogicalOr) { $was_inside_general_use = $context->inside_general_use; $context->inside_general_use = \true; $expr_result = OrAnalyzer::analyze($statements_analyzer, $stmt, $context, $from_stmt); $context->inside_general_use = $was_inside_general_use; $statements_analyzer->node_data->setType($stmt, Type::getBool()); return $expr_result; } if ($stmt instanceof PhpParser\Node\Expr\BinaryOp\Coalesce) { $expr_result = CoalesceAnalyzer::analyze($statements_analyzer, $stmt, $context); self::addDataFlow($statements_analyzer, $stmt, $stmt->left, $stmt->right, 'coalesce'); return $expr_result; } if ($stmt->left instanceof PhpParser\Node\Expr\BinaryOp) { if (self::analyze($statements_analyzer, $stmt->left, $context, $nesting + 1) === \false) { return \false; } } else { if (ExpressionAnalyzer::analyze($statements_analyzer, $stmt->left, $context) === \false) { return \false; } } if ($stmt->right instanceof PhpParser\Node\Expr\BinaryOp) { if (self::analyze($statements_analyzer, $stmt->right, $context, $nesting + 1) === \false) { return \false; } } else { if (ExpressionAnalyzer::analyze($statements_analyzer, $stmt->right, $context) === \false) { return \false; } } if ($stmt instanceof PhpParser\Node\Expr\BinaryOp\Concat) { $stmt_type = Type::getString(); ConcatAnalyzer::analyze($statements_analyzer, $stmt->left, $stmt->right, $context, $result_type); if ($result_type) { $stmt_type = $result_type; } if ($statements_analyzer->data_flow_graph && ($statements_analyzer->data_flow_graph instanceof VariableUseGraph || !in_array('TaintedInput', $statements_analyzer->getSuppressedIssues()))) { $stmt_left_type = $statements_analyzer->node_data->getType($stmt->left); $stmt_right_type = $statements_analyzer->node_data->getType($stmt->right); $var_location = new CodeLocation($statements_analyzer, $stmt); $new_parent_node = DataFlowNode::getForAssignment('concat', $var_location); $statements_analyzer->data_flow_graph->addNode($new_parent_node); $stmt_type = $stmt_type->setParentNodes([$new_parent_node->id => $new_parent_node]); $codebase = $statements_analyzer->getCodebase(); $event = new AddRemoveTaintsEvent($stmt, $context, $statements_analyzer, $codebase); $added_taints = $codebase->config->eventDispatcher->dispatchAddTaints($event); $removed_taints = $codebase->config->eventDispatcher->dispatchRemoveTaints($event); if ($stmt_left_type && $stmt_left_type->parent_nodes) { foreach ($stmt_left_type->parent_nodes as $parent_node) { $statements_analyzer->data_flow_graph->addPath($parent_node, $new_parent_node, 'concat', $added_taints, $removed_taints); } } if ($stmt_right_type && $stmt_right_type->parent_nodes) { foreach ($stmt_right_type->parent_nodes as $parent_node) { $statements_analyzer->data_flow_graph->addPath($parent_node, $new_parent_node, 'concat', $added_taints, $removed_taints); } } } $statements_analyzer->node_data->setType($stmt, $stmt_type); return \true; } if ($stmt instanceof PhpParser\Node\Expr\BinaryOp\Spaceship) { $statements_analyzer->node_data->setType($stmt, new Union([new TLiteralInt(-1), new TLiteralInt(0), new TLiteralInt(1)])); self::addDataFlow($statements_analyzer, $stmt, $stmt->left, $stmt->right, '<=>'); return \true; } if ($stmt instanceof PhpParser\Node\Expr\BinaryOp\Equal || $stmt instanceof PhpParser\Node\Expr\BinaryOp\NotEqual || $stmt instanceof PhpParser\Node\Expr\BinaryOp\Identical || $stmt instanceof PhpParser\Node\Expr\BinaryOp\NotIdentical || $stmt instanceof PhpParser\Node\Expr\BinaryOp\Greater || $stmt instanceof PhpParser\Node\Expr\BinaryOp\GreaterOrEqual || $stmt instanceof PhpParser\Node\Expr\BinaryOp\Smaller || $stmt instanceof PhpParser\Node\Expr\BinaryOp\SmallerOrEqual) { $statements_analyzer->node_data->setType($stmt, Type::getBool()); $stmt_left_type = $statements_analyzer->node_data->getType($stmt->left); $stmt_right_type = $statements_analyzer->node_data->getType($stmt->right); if (($stmt instanceof PhpParser\Node\Expr\BinaryOp\Greater || $stmt instanceof PhpParser\Node\Expr\BinaryOp\GreaterOrEqual || $stmt instanceof PhpParser\Node\Expr\BinaryOp\Smaller || $stmt instanceof PhpParser\Node\Expr\BinaryOp\SmallerOrEqual) && $statements_analyzer->getCodebase()->config->strict_binary_operands && $stmt_left_type && $stmt_right_type && ($stmt_left_type->isSingle() && $stmt_left_type->hasBool() || $stmt_right_type->isSingle() && $stmt_right_type->hasBool())) { IssueBuffer::maybeAdd(new InvalidOperand('Cannot compare ' . $stmt_left_type->getId() . ' to ' . $stmt_right_type->getId(), new CodeLocation($statements_analyzer, $stmt)), $statements_analyzer->getSuppressedIssues()); } if (($stmt instanceof PhpParser\Node\Expr\BinaryOp\Equal || $stmt instanceof PhpParser\Node\Expr\BinaryOp\NotEqual || $stmt instanceof PhpParser\Node\Expr\BinaryOp\Identical || $stmt instanceof PhpParser\Node\Expr\BinaryOp\NotIdentical) && $stmt->left instanceof PhpParser\Node\Expr\FuncCall && $stmt->left->name instanceof PhpParser\Node\Name && $stmt->left->name->getParts() === ['substr'] && isset($stmt->left->getArgs()[1]) && $stmt_right_type && $stmt_right_type->hasLiteralString()) { $from_type = $statements_analyzer->node_data->getType($stmt->left->getArgs()[1]->value); $length_type = isset($stmt->left->getArgs()[2]) ? $statements_analyzer->node_data->getType($stmt->left->getArgs()[2]->value) ?? Type::getMixed() : null; $string_length = null; if ($from_type && $from_type->isSingleIntLiteral() && $length_type === null) { $string_length = -$from_type->getSingleIntLiteral()->value; } elseif ($length_type && $length_type->isSingleIntLiteral()) { $string_length = $length_type->getSingleIntLiteral()->value; } if ($string_length > 0) { foreach ($stmt_right_type->getAtomicTypes() as $atomic_right_type) { if ($atomic_right_type instanceof TLiteralString) { if (strlen($atomic_right_type->value) !== $string_length) { if ($stmt instanceof PhpParser\Node\Expr\BinaryOp\Equal || $stmt instanceof PhpParser\Node\Expr\BinaryOp\Identical) { if ($atomic_right_type->from_docblock) { IssueBuffer::maybeAdd(new DocblockTypeContradiction($atomic_right_type . ' string length is not ' . $string_length, new CodeLocation($statements_analyzer, $stmt), "strlen({$atomic_right_type}) !== {$string_length}"), $statements_analyzer->getSuppressedIssues()); } else { IssueBuffer::maybeAdd(new TypeDoesNotContainType($atomic_right_type . ' string length is not ' . $string_length, new CodeLocation($statements_analyzer, $stmt), "strlen({$atomic_right_type}) !== {$string_length}"), $statements_analyzer->getSuppressedIssues()); } } else { if ($atomic_right_type->from_docblock) { IssueBuffer::maybeAdd(new RedundantConditionGivenDocblockType($atomic_right_type . ' string length is never ' . $string_length, new CodeLocation($statements_analyzer, $stmt), "strlen({$atomic_right_type}) !== {$string_length}"), $statements_analyzer->getSuppressedIssues()); } else { IssueBuffer::maybeAdd(new RedundantCondition($atomic_right_type . ' string length is never ' . $string_length, new CodeLocation($statements_analyzer, $stmt), "strlen({$atomic_right_type}) !== {$string_length}"), $statements_analyzer->getSuppressedIssues()); } } } } } } } $codebase = $statements_analyzer->getCodebase(); if ($stmt instanceof PhpParser\Node\Expr\BinaryOp\Equal && $stmt_left_type && $stmt_right_type && ($context->mutation_free || $codebase->alter_code)) { self::checkForImpureEqualityComparison($statements_analyzer, $stmt, $stmt_left_type, $stmt_right_type); } self::addDataFlow($statements_analyzer, $stmt, $stmt->left, $stmt->right, 'comparison'); return \true; } NonComparisonOpAnalyzer::analyze($statements_analyzer, $stmt, $context); return \true; } public static function addDataFlow(StatementsAnalyzer $statements_analyzer, PhpParser\Node\Expr $stmt, PhpParser\Node\Expr $left, PhpParser\Node\Expr $right, string $type = 'binaryop') : void { if ($stmt->getLine() === -1) { throw new UnexpectedValueException('bad'); } $result_type = $statements_analyzer->node_data->getType($stmt); if (!$result_type) { return; } if ($statements_analyzer->data_flow_graph instanceof TaintFlowGraph && $stmt instanceof PhpParser\Node\Expr\BinaryOp && !$stmt instanceof PhpParser\Node\Expr\BinaryOp\Concat && !$stmt instanceof PhpParser\Node\Expr\BinaryOp\Coalesce && (!$stmt instanceof PhpParser\Node\Expr\BinaryOp\Plus || !$result_type->hasArray())) { //among BinaryOp, only Concat and Coalesce can pass tainted value to the result. Also Plus on arrays only return; } if ($statements_analyzer->data_flow_graph) { $stmt_left_type = $statements_analyzer->node_data->getType($left); $stmt_right_type = $statements_analyzer->node_data->getType($right); $var_location = new CodeLocation($statements_analyzer, $stmt); $new_parent_node = DataFlowNode::getForAssignment($type, $var_location); $statements_analyzer->data_flow_graph->addNode($new_parent_node); $result_type = $result_type->setParentNodes([$new_parent_node->id => $new_parent_node]); $statements_analyzer->node_data->setType($stmt, $result_type); if ($stmt_left_type && $stmt_left_type->parent_nodes) { foreach ($stmt_left_type->parent_nodes as $parent_node) { $statements_analyzer->data_flow_graph->addPath($parent_node, $new_parent_node, $type); } } if ($stmt_right_type && $stmt_right_type->parent_nodes) { foreach ($stmt_right_type->parent_nodes as $parent_node) { $statements_analyzer->data_flow_graph->addPath($parent_node, $new_parent_node, $type); } } if ($stmt instanceof PhpParser\Node\Expr\AssignOp && $statements_analyzer->data_flow_graph instanceof VariableUseGraph) { $root_expr = $left; while ($root_expr instanceof PhpParser\Node\Expr\ArrayDimFetch) { $root_expr = $root_expr->var; } if ($left instanceof PhpParser\Node\Expr\PropertyFetch) { $statements_analyzer->data_flow_graph->addPath($new_parent_node, new DataFlowNode('variable-use', 'variable use', null), 'used-by-instance-property'); } if ($left instanceof PhpParser\Node\Expr\StaticPropertyFetch) { $statements_analyzer->data_flow_graph->addPath($new_parent_node, new DataFlowNode('variable-use', 'variable use', null), 'use-in-static-property'); } elseif (!$left instanceof PhpParser\Node\Expr\Variable) { $statements_analyzer->data_flow_graph->addPath($new_parent_node, new DataFlowNode('variable-use', 'variable use', null), 'variable-use'); } } } } private static function checkForImpureEqualityComparison(StatementsAnalyzer $statements_analyzer, PhpParser\Node\Expr\BinaryOp\Equal $stmt, Union $stmt_left_type, Union $stmt_right_type) : void { $codebase = $statements_analyzer->getCodebase(); if ($stmt_left_type->hasString() && $stmt_right_type->hasObjectType()) { foreach ($stmt_right_type->getAtomicTypes() as $atomic_type) { if ($atomic_type instanceof TNamedObject) { try { $storage = $codebase->methods->getStorage(new MethodIdentifier($atomic_type->value, '__tostring')); } catch (UnexpectedValueException $e) { continue; } if (!$storage->mutation_free) { if ($statements_analyzer->getSource() instanceof FunctionLikeAnalyzer && $statements_analyzer->getSource()->track_mutations) { $statements_analyzer->getSource()->inferred_has_mutation = \true; $statements_analyzer->getSource()->inferred_impure = \true; } else { IssueBuffer::maybeAdd(new ImpureMethodCall('Cannot call a possibly-mutating method ' . $atomic_type->value . '::__toString from a pure context', new CodeLocation($statements_analyzer, $stmt)), $statements_analyzer->getSuppressedIssues()); } } } } } elseif ($stmt_right_type->hasString() && $stmt_left_type->hasObjectType()) { foreach ($stmt_left_type->getAtomicTypes() as $atomic_type) { if ($atomic_type instanceof TNamedObject) { try { $storage = $codebase->methods->getStorage(new MethodIdentifier($atomic_type->value, '__tostring')); } catch (UnexpectedValueException $e) { continue; } if (!$storage->mutation_free) { if ($statements_analyzer->getSource() instanceof FunctionLikeAnalyzer && $statements_analyzer->getSource()->track_mutations) { $statements_analyzer->getSource()->inferred_has_mutation = \true; $statements_analyzer->getSource()->inferred_impure = \true; } else { IssueBuffer::maybeAdd(new ImpureMethodCall('Cannot call a possibly-mutating method ' . $atomic_type->value . '::__toString from a pure context', new CodeLocation($statements_analyzer, $stmt)), $statements_analyzer->getSuppressedIssues()); } } } } } } } getCodebase(); $codebase_methods = $codebase->methods; if (ExpressionAnalyzer::analyze($statements_analyzer, $stmt->expr, $context) === \false) { return \false; } $location = new CodeLocation($statements_analyzer->getSource(), $stmt); $stmt_expr_type = $statements_analyzer->node_data->getType($stmt->expr); if ($stmt_expr_type) { $clone_type = $stmt_expr_type; $immutable_cloned = \false; $invalid_clones = []; $mixed_clone = \false; $possibly_valid = \false; $atomic_types = $clone_type->getAtomicTypes(); while ($atomic_types) { $clone_type_part = array_pop($atomic_types); if ($clone_type_part instanceof TMixed) { $mixed_clone = \true; } elseif ($clone_type_part instanceof TObject) { $possibly_valid = \true; } elseif ($clone_type_part instanceof TNamedObject) { if (!$codebase->classlikes->classOrInterfaceExists($clone_type_part->value)) { $invalid_clones[] = $clone_type_part->getId(); } else { $clone_method_id = new MethodIdentifier($clone_type_part->value, '__clone'); $does_method_exist = $codebase_methods->methodExists($clone_method_id, $context->calling_method_id, $location); $is_method_visible = MethodAnalyzer::isMethodVisible($clone_method_id, $context, $statements_analyzer->getSource()); if ($does_method_exist && !$is_method_visible) { $invalid_clones[] = $clone_type_part->getId(); } else { MethodCallProhibitionAnalyzer::analyze($codebase, $context, $clone_method_id, $statements_analyzer->getNamespace(), $location, $statements_analyzer->getSuppressedIssues()); $possibly_valid = \true; $immutable_cloned = \true; } } } elseif ($clone_type_part instanceof TTemplateParam) { $atomic_types = array_merge($atomic_types, $clone_type_part->as->getAtomicTypes()); } else { if ($clone_type_part instanceof TFalse && $clone_type->ignore_falsable_issues) { continue; } if ($clone_type_part instanceof TNull && $clone_type->ignore_nullable_issues) { continue; } $invalid_clones[] = $clone_type_part->getId(); } } if ($mixed_clone) { IssueBuffer::maybeAdd(new MixedClone('Cannot clone mixed', $location), $statements_analyzer->getSuppressedIssues()); } if ($invalid_clones) { if ($possibly_valid) { IssueBuffer::maybeAdd(new PossiblyInvalidClone('Cannot clone ' . $invalid_clones[0], $location), $statements_analyzer->getSuppressedIssues()); } else { IssueBuffer::maybeAdd(new InvalidClone('Cannot clone ' . $invalid_clones[0], $location), $statements_analyzer->getSuppressedIssues()); } return \true; } if ($immutable_cloned) { $stmt_expr_type = $stmt_expr_type->setProperties(['reference_free' => \true, 'allow_mutations' => \true]); } $statements_analyzer->node_data->setType($stmt, $stmt_expr_type); } return \true; } } var instanceof PhpParser\Node\Expr\Variable) { $was_inside_general_use = $context->inside_general_use; $context->inside_general_use = \true; ExpressionAnalyzer::analyze($statements_analyzer, $stmt->var, $context); $context->inside_general_use = $was_inside_general_use; $tmp_name = '__tmp_nullsafe__' . (int) $stmt->var->getAttribute('startFilePos'); $condition_type = $statements_analyzer->node_data->getType($stmt->var); if ($condition_type) { $context->vars_in_scope['$' . $tmp_name] = $condition_type; $tmp_var = new VirtualVariable($tmp_name, $stmt->var->getAttributes()); } else { $tmp_var = $stmt->var; } } else { $tmp_var = $stmt->var; } $old_node_data = $statements_analyzer->node_data; $statements_analyzer->node_data = clone $statements_analyzer->node_data; $null_value1 = new VirtualConstFetch(new VirtualName('null'), $stmt->var->getAttributes()); $null_comparison = new VirtualIdentical($tmp_var, $null_value1, $stmt->var->getAttributes()); $null_value2 = new VirtualConstFetch(new VirtualName('null'), $stmt->var->getAttributes()); if ($stmt instanceof PhpParser\Node\Expr\NullsafePropertyFetch) { $ternary = new VirtualTernary($null_comparison, $null_value2, new VirtualPropertyFetch($tmp_var, $stmt->name, $stmt->getAttributes()), $stmt->getAttributes()); } else { $ternary = new VirtualTernary($null_comparison, $null_value2, new VirtualMethodCall($tmp_var, $stmt->name, $stmt->args, $stmt->getAttributes()), $stmt->getAttributes()); } ExpressionAnalyzer::analyze($statements_analyzer, $ternary, $context); $ternary_type = $statements_analyzer->node_data->getType($ternary); $statements_analyzer->node_data = $old_node_data; $statements_analyzer->node_data->setType($stmt, $ternary_type ?? Type::getMixed()); return \true; } } inside_negation; $context->inside_negation = !$inside_negation; $result = ExpressionAnalyzer::analyze($statements_analyzer, $stmt->expr, $context); $context->inside_negation = $inside_negation; $expr_type = $statements_analyzer->node_data->getType($stmt->expr); if ($expr_type) { if ($expr_type->isAlwaysTruthy()) { $stmt_type = new TFalse($expr_type->from_docblock); } elseif ($expr_type->isAlwaysFalsy()) { $stmt_type = new TTrue($expr_type->from_docblock); } else { ExpressionAnalyzer::checkRiskyTruthyFalsyComparison($expr_type, $statements_analyzer, $stmt); $stmt_type = new TBool(); } $stmt_type = new Union([$stmt_type], ['parent_nodes' => $expr_type->parent_nodes]); } else { $stmt_type = Type::getBool(); } $statements_analyzer->node_data->setType($stmt, $stmt_type); return $result; } } inside_general_use; $context->inside_general_use = \true; if (ExpressionAnalyzer::analyze($statements_analyzer, $stmt->expr, $context) === \false) { $context->inside_general_use = $was_inside_general_use; return \false; } $context->inside_general_use = $was_inside_general_use; if ($stmt->class instanceof PhpParser\Node\Expr) { if (ExpressionAnalyzer::analyze($statements_analyzer, $stmt->class, $context) === \false) { return \false; } } elseif (!in_array(strtolower($stmt->class->getFirst()), ['self', 'static', 'parent'], \true)) { if ($context->check_classes) { $codebase = $statements_analyzer->getCodebase(); $fq_class_name = ClassLikeAnalyzer::getFQCLNFromNameObject($stmt->class, $statements_analyzer->getAliases()); if ($codebase->store_node_types && $fq_class_name && !$context->collect_initializations && !$context->collect_mutations) { $codebase->analyzer->addNodeReference($statements_analyzer->getFilePath(), $stmt->class, $codebase->classlikes->classOrInterfaceOrEnumExists($fq_class_name) ? $fq_class_name : '*' . ($stmt->class instanceof PhpParser\Node\Name\FullyQualified ? '\\' : $statements_analyzer->getNamespace() . '-') . implode('\\', $stmt->class->getParts())); } if (!isset($context->phantom_classes[strtolower($fq_class_name)])) { if (ClassLikeAnalyzer::checkFullyQualifiedClassLikeName($statements_analyzer, $fq_class_name, new CodeLocation($statements_analyzer->getSource(), $stmt->class), $context->self, $context->calling_method_id, $statements_analyzer->getSuppressedIssues()) === \false) { return \false; } } if ($codebase->alter_code) { $codebase->classlikes->handleClassLikeReferenceInMigration($codebase, $statements_analyzer, $stmt->class, $fq_class_name, $context->calling_method_id); } } } $statements_analyzer->node_data->setType($stmt, Type::getBool()); return \true; } } items) === 0) { $statements_analyzer->node_data->setType($stmt, Type::getEmptyArray()); return \true; } $codebase = $statements_analyzer->getCodebase(); $array_creation_info = new \Psalm\Internal\Analyzer\Statements\Expression\ArrayCreationInfo(); foreach ($stmt->items as $item) { if ($item === null) { IssueBuffer::maybeAdd(new ParseError('Array element cannot be empty', new CodeLocation($statements_analyzer, $stmt))); return \false; } self::analyzeArrayItem($statements_analyzer, $context, $array_creation_info, $item, $codebase); } if (count($array_creation_info->item_key_atomic_types) !== 0) { $item_key_type = TypeCombiner::combine($array_creation_info->item_key_atomic_types, $codebase); } else { $item_key_type = null; } if (count($array_creation_info->item_value_atomic_types) !== 0) { $item_value_type = TypeCombiner::combine($array_creation_info->item_value_atomic_types, $codebase); } else { $item_value_type = null; } // if this array looks like an object-like array, let's return that instead if (count($array_creation_info->property_types) !== 0) { $atomic_type = new TKeyedArray($array_creation_info->property_types, $array_creation_info->class_strings, $array_creation_info->can_create_objectlike ? null : [$item_key_type ?? Type::getArrayKey(), $item_value_type ?? Type::getMixed()], $array_creation_info->all_list); $stmt_type = new Union([$atomic_type], ['parent_nodes' => $array_creation_info->parent_taint_nodes]); $statements_analyzer->node_data->setType($stmt, $stmt_type); return \true; } if ($item_key_type === null && $item_value_type === null) { $statements_analyzer->node_data->setType($stmt, Type::getEmptyArray()); return \true; } if ($array_creation_info->all_list) { if ($array_creation_info->can_be_empty) { $array_type = Type::getListAtomic($item_value_type ?? Type::getMixed()); } else { $array_type = Type::getNonEmptyListAtomic($item_value_type ?? Type::getMixed()); } $stmt_type = new Union([$array_type], ['parent_nodes' => $array_creation_info->parent_taint_nodes]); $statements_analyzer->node_data->setType($stmt, $stmt_type); return \true; } if ($item_key_type) { $bad_types = []; $good_types = []; foreach ($item_key_type->getAtomicTypes() as $atomic_key_type) { if ($atomic_key_type instanceof TMixed) { IssueBuffer::maybeAdd(new MixedArrayOffset('Cannot create mixed offset – expecting array-key', new CodeLocation($statements_analyzer->getSource(), $stmt)), $statements_analyzer->getSuppressedIssues()); $bad_types[] = $atomic_key_type; $good_types[] = new TArrayKey(); continue; } if (!$atomic_key_type instanceof TString && !$atomic_key_type instanceof TInt && !$atomic_key_type instanceof TArrayKey && !$atomic_key_type instanceof TTemplateParam && !($atomic_key_type instanceof TObjectWithProperties && isset($atomic_key_type->methods['__tostring']))) { IssueBuffer::maybeAdd(new InvalidArrayOffset('Cannot create offset of type ' . $item_key_type->getKey() . ', expecting array-key', new CodeLocation($statements_analyzer->getSource(), $stmt)), $statements_analyzer->getSuppressedIssues()); $bad_types[] = $atomic_key_type; if ($atomic_key_type instanceof TFalse) { $good_types[] = new TLiteralInt(0); } elseif ($atomic_key_type instanceof TTrue) { $good_types[] = new TLiteralInt(1); } elseif ($atomic_key_type instanceof TBool) { $good_types[] = new TLiteralInt(0); $good_types[] = new TLiteralInt(1); } elseif ($atomic_key_type instanceof TLiteralFloat) { $good_types[] = new TLiteralInt((int) $atomic_key_type->value); } elseif ($atomic_key_type instanceof TFloat) { $good_types[] = new TInt(); } else { $good_types[] = new TArrayKey(); } } } if ($bad_types && $good_types) { $item_key_type = $item_key_type->getBuilder()->substitute(TypeCombiner::combine($bad_types, $codebase), TypeCombiner::combine($good_types, $codebase))->freeze(); } } $array_args = [$item_key_type && !$item_key_type->hasMixed() ? $item_key_type : Type::getArrayKey(), $item_value_type ?? Type::getMixed()]; $array_type = $array_creation_info->can_be_empty ? new TArray($array_args) : new TNonEmptyArray($array_args); $stmt_type = new Union([$array_type], ['parent_nodes' => $array_creation_info->parent_taint_nodes]); $statements_analyzer->node_data->setType($stmt, $stmt_type); return \true; } /** * @param string|int $literal_array_key * @return false|int * @psalm-assert-if-false !numeric $literal_array_key */ public static function getLiteralArrayKeyInt($literal_array_key) { if (is_int($literal_array_key)) { return $literal_array_key; } if (!is_numeric($literal_array_key)) { return \false; } // PHP 8 values with whitespace after number are counted as numeric // and filter_var treats them as such too // ensures that '15 ' will stay '15 ' if (trim($literal_array_key) !== $literal_array_key) { return \false; } // '+5' will pass the filter_var check but won't be changed in keys if ($literal_array_key[0] === '+') { return \false; } // e.g. 015 is numeric but won't be typecast as it's not a valid int return filter_var($literal_array_key, FILTER_VALIDATE_INT); } private static function analyzeArrayItem(StatementsAnalyzer $statements_analyzer, Context $context, \Psalm\Internal\Analyzer\Statements\Expression\ArrayCreationInfo $array_creation_info, PhpParser\Node\Expr\ArrayItem $item, Codebase $codebase) : void { if ($item->unpack) { if (ExpressionAnalyzer::analyze($statements_analyzer, $item->value, $context) === \false) { return; } $unpacked_array_type = $statements_analyzer->node_data->getType($item->value); if (!$unpacked_array_type) { return; } self::handleUnpackedArray($statements_analyzer, $array_creation_info, $item, $unpacked_array_type, $codebase); if (($data_flow_graph = $statements_analyzer->data_flow_graph) && $data_flow_graph instanceof VariableUseGraph && $unpacked_array_type->parent_nodes) { $var_location = new CodeLocation($statements_analyzer->getSource(), $item->value); $new_parent_node = DataFlowNode::getForAssignment('array', $var_location); $data_flow_graph->addNode($new_parent_node); foreach ($unpacked_array_type->parent_nodes as $parent_node) { $data_flow_graph->addPath($parent_node, $new_parent_node, 'arrayvalue-assignment'); } $array_creation_info->parent_taint_nodes += [$new_parent_node->id => $new_parent_node]; } return; } $item_key_value = null; $item_key_type = null; $item_is_list_item = \false; $array_creation_info->can_be_empty = \false; if ($item->key) { $was_inside_general_use = $context->inside_general_use; $context->inside_general_use = \true; if (ExpressionAnalyzer::analyze($statements_analyzer, $item->key, $context) === \false) { $context->inside_general_use = $was_inside_general_use; return; } $context->inside_general_use = $was_inside_general_use; if ($item_key_type = $statements_analyzer->node_data->getType($item->key)) { $key_type = $item_key_type; if ($key_type->isNull()) { $key_type = Type::getString(''); } if ($item->key instanceof PhpParser\Node\Scalar\String_ && self::getLiteralArrayKeyInt($item->key->value) !== \false) { $key_type = Type::getInt(\false, (int) $item->key->value); } if ($key_type->isSingleStringLiteral()) { $item_key_literal_type = $key_type->getSingleStringLiteral(); $string_to_int = self::getLiteralArrayKeyInt($item_key_literal_type->value); $item_key_value = $string_to_int === \false ? $item_key_literal_type->value : $string_to_int; if (is_string($item_key_value) && $item_key_literal_type instanceof TLiteralClassString) { $array_creation_info->class_strings[$item_key_value] = \true; } } elseif ($key_type->isSingleIntLiteral()) { $item_key_value = $key_type->getSingleIntLiteral()->value; if ($item_key_value <= PHP_INT_MAX && $item_key_value > $array_creation_info->int_offset) { if ($item_key_value - 1 === $array_creation_info->int_offset) { $item_is_list_item = \true; } $array_creation_info->int_offset = $item_key_value; } } } else { $key_type = Type::getArrayKey(); } } else { if ($array_creation_info->int_offset === PHP_INT_MAX) { IssueBuffer::maybeAdd(new InvalidArrayOffset('Cannot add an item with an offset beyond PHP_INT_MAX', new CodeLocation($statements_analyzer->getSource(), $item))); return; } $item_is_list_item = \true; $item_key_value = ++$array_creation_info->int_offset; $key_atomic_type = new TLiteralInt($item_key_value); $array_creation_info->item_key_atomic_types[] = $key_atomic_type; $key_type = new Union([$key_atomic_type]); } if (ExpressionAnalyzer::analyze($statements_analyzer, $item->value, $context) === \false) { return; } $array_creation_info->all_list = $array_creation_info->all_list && $item_is_list_item; if ($item_key_value !== null) { if (isset($array_creation_info->array_keys[$item_key_value])) { IssueBuffer::maybeAdd(new DuplicateArrayKey('Key \'' . $item_key_value . '\' already exists on array', new CodeLocation($statements_analyzer->getSource(), $item)), $statements_analyzer->getSuppressedIssues()); } $array_creation_info->array_keys[$item_key_value] = \true; } if (($data_flow_graph = $statements_analyzer->data_flow_graph) && ($data_flow_graph instanceof VariableUseGraph || !in_array('TaintedInput', $statements_analyzer->getSuppressedIssues()))) { if ($item_value_type = $statements_analyzer->node_data->getType($item->value)) { if ($item_value_type->parent_nodes && !($item_value_type->isSingle() && $item_value_type->hasLiteralValue() && $data_flow_graph instanceof TaintFlowGraph)) { $var_location = new CodeLocation($statements_analyzer->getSource(), $item); $new_parent_node = DataFlowNode::getForAssignment('array' . ($item_key_value !== null ? '[\'' . $item_key_value . '\']' : ''), $var_location); $data_flow_graph->addNode($new_parent_node); $event = new AddRemoveTaintsEvent($item, $context, $statements_analyzer, $codebase); $added_taints = $codebase->config->eventDispatcher->dispatchAddTaints($event); $removed_taints = $codebase->config->eventDispatcher->dispatchRemoveTaints($event); foreach ($item_value_type->parent_nodes as $parent_node) { $data_flow_graph->addPath($parent_node, $new_parent_node, 'arrayvalue-assignment' . ($item_key_value !== null ? '-\'' . $item_key_value . '\'' : ''), $added_taints, $removed_taints); } $array_creation_info->parent_taint_nodes += [$new_parent_node->id => $new_parent_node]; } if ($item_key_type && $item_key_type->parent_nodes && $item_key_value === null && !($item_key_type->isSingle() && $item_key_type->hasLiteralValue() && $data_flow_graph instanceof TaintFlowGraph)) { $var_location = new CodeLocation($statements_analyzer->getSource(), $item); $new_parent_node = DataFlowNode::getForAssignment('array', $var_location); $data_flow_graph->addNode($new_parent_node); $event = new AddRemoveTaintsEvent($item, $context, $statements_analyzer, $codebase); $added_taints = $codebase->config->eventDispatcher->dispatchAddTaints($event); $removed_taints = $codebase->config->eventDispatcher->dispatchRemoveTaints($event); foreach ($item_key_type->parent_nodes as $parent_node) { $data_flow_graph->addPath($parent_node, $new_parent_node, 'arraykey-assignment', $added_taints, $removed_taints); } $array_creation_info->parent_taint_nodes += [$new_parent_node->id => $new_parent_node]; } } } if ($item->byRef) { $var_id = \Psalm\Internal\Analyzer\Statements\Expression\ExpressionIdentifier::getExtendedVarId($item->value, $statements_analyzer->getFQCLN(), $statements_analyzer); if ($var_id) { if (isset($context->vars_in_scope[$var_id])) { $context->removeDescendents($var_id, $context->vars_in_scope[$var_id], null, $statements_analyzer); } $context->vars_in_scope[$var_id] = Type::getMixed(); } } $config = $codebase->config; if ($item_value_type = $statements_analyzer->node_data->getType($item->value)) { if ($item_key_value !== null && count($array_creation_info->property_types) <= $config->max_shaped_array_size) { $array_creation_info->property_types[$item_key_value] = $item_value_type; } else { $array_creation_info->can_create_objectlike = \false; $array_creation_info->item_key_atomic_types = array_merge($array_creation_info->item_key_atomic_types, array_values($key_type->getAtomicTypes())); $array_creation_info->item_value_atomic_types = array_merge($array_creation_info->item_value_atomic_types, array_values($item_value_type->getAtomicTypes())); } } else { if ($item_key_value !== null && count($array_creation_info->property_types) <= $config->max_shaped_array_size) { $array_creation_info->property_types[$item_key_value] = Type::getMixed(); } else { $array_creation_info->can_create_objectlike = \false; $array_creation_info->item_key_atomic_types = array_merge($array_creation_info->item_key_atomic_types, array_values($key_type->getAtomicTypes())); $array_creation_info->item_value_atomic_types[] = new TMixed(); } } } private static function handleUnpackedArray(StatementsAnalyzer $statements_analyzer, \Psalm\Internal\Analyzer\Statements\Expression\ArrayCreationInfo $array_creation_info, PhpParser\Node\Expr\ArrayItem $item, Union $unpacked_array_type, Codebase $codebase) : void { $all_non_empty = \true; $has_possibly_undefined = \false; foreach ($unpacked_array_type->getAtomicTypes() as $unpacked_atomic_type) { if ($unpacked_atomic_type instanceof TList) { $unpacked_atomic_type = $unpacked_atomic_type->getKeyedArray(); } if ($unpacked_atomic_type instanceof TKeyedArray) { foreach ($unpacked_atomic_type->properties as $key => $property_value) { if ($property_value->possibly_undefined) { $has_possibly_undefined = \true; continue; } if (is_string($key)) { if ($codebase->analysis_php_version_id <= 80000) { IssueBuffer::maybeAdd(new DuplicateArrayKey('String keys are not supported in unpacked arrays', new CodeLocation($statements_analyzer->getSource(), $item->value)), $statements_analyzer->getSuppressedIssues()); continue 2; } $new_offset = $key; $array_creation_info->item_key_atomic_types[] = Type::getAtomicStringFromLiteral($new_offset); $array_creation_info->all_list = \false; } else { if ($array_creation_info->int_offset === PHP_INT_MAX) { IssueBuffer::maybeAdd(new InvalidArrayOffset('Cannot add an item with an offset beyond PHP_INT_MAX', new CodeLocation($statements_analyzer->getSource(), $item->value)), $statements_analyzer->getSuppressedIssues()); continue 2; } $new_offset = ++$array_creation_info->int_offset; $array_creation_info->item_key_atomic_types[] = new TLiteralInt($new_offset); } $array_creation_info->array_keys[$new_offset] = \true; $array_creation_info->property_types[$new_offset] = $property_value; } if (!$unpacked_atomic_type->isNonEmpty()) { $all_non_empty = \false; } if ($has_possibly_undefined) { $unpacked_atomic_type = $unpacked_atomic_type->getGenericArrayType(); } elseif (!$unpacked_atomic_type->fallback_params) { continue; } } elseif (!$unpacked_atomic_type instanceof TNonEmptyArray) { $all_non_empty = \false; } $codebase = $statements_analyzer->getCodebase(); if (!$unpacked_atomic_type->isIterable($codebase)) { $array_creation_info->can_create_objectlike = \false; $array_creation_info->item_key_atomic_types[] = new TArrayKey(); $array_creation_info->item_value_atomic_types[] = new TMixed(); IssueBuffer::maybeAdd(new InvalidOperand("Cannot use spread operator on non-iterable type {$unpacked_array_type->getId()}", new CodeLocation($statements_analyzer->getSource(), $item->value)), $statements_analyzer->getSuppressedIssues()); continue; } $iterable_type = $unpacked_atomic_type->getIterable($codebase); if ($iterable_type->type_params[0]->isNever()) { continue; } $array_creation_info->can_create_objectlike = \false; if (!UnionTypeComparator::isContainedBy($codebase, $iterable_type->type_params[0], Type::getArrayKey())) { IssueBuffer::maybeAdd(new InvalidOperand("Cannot use spread operator on iterable with key type " . $iterable_type->type_params[0]->getId(), new CodeLocation($statements_analyzer->getSource(), $item->value)), $statements_analyzer->getSuppressedIssues()); continue; } if ($iterable_type->type_params[0]->hasString()) { if ($codebase->analysis_php_version_id <= 80000) { IssueBuffer::maybeAdd(new DuplicateArrayKey('String keys are not supported in unpacked arrays', new CodeLocation($statements_analyzer->getSource(), $item->value)), $statements_analyzer->getSuppressedIssues()); continue; } $array_creation_info->all_list = \false; } // Unpacked array might overwrite known properties, so values are merged when the keys intersect. foreach ($array_creation_info->property_types as $prop_key_val => $prop_val) { $prop_key = new Union([ConstantTypeResolver::getLiteralTypeFromScalarValue($prop_key_val)]); // Since $prop_key is a single literal type, the types intersect iff $prop_key is contained by the // template type (ie $prop_key cannot overlap with the template type without being contained by it). if (UnionTypeComparator::isContainedBy($codebase, $prop_key, $iterable_type->type_params[0])) { $new_prop_val = Type::combineUnionTypes($prop_val, $iterable_type->type_params[1]); $array_creation_info->property_types[$prop_key_val] = $new_prop_val; } } $array_creation_info->item_key_atomic_types = array_merge($array_creation_info->item_key_atomic_types, array_values($iterable_type->type_params[0]->getAtomicTypes())); $array_creation_info->item_value_atomic_types = array_merge($array_creation_info->item_value_atomic_types, array_values($iterable_type->type_params[1]->getAtomicTypes())); } if ($all_non_empty) { $array_creation_info->can_be_empty = \false; } } } inside_assignment; $context->inside_assignment = \true; if (ExpressionAnalyzer::analyze($statements_analyzer, $stmt->var, $context) === \false) { $context->inside_assignment = $was_inside_assignment; return \false; } $context->inside_assignment = $was_inside_assignment; $stmt_var_type = $statements_analyzer->node_data->getType($stmt->var); if ($stmt instanceof PostInc || $stmt instanceof PostDec) { $statements_analyzer->node_data->setType($stmt, $stmt_var_type ?? Type::getMixed()); } if (($stmt_var_type = $statements_analyzer->node_data->getType($stmt->var)) && $stmt_var_type->hasString() && ($stmt instanceof PostInc || $stmt instanceof PreInc)) { $return_type = null; $fake_right_expr = new VirtualLNumber(1, $stmt->getAttributes()); $statements_analyzer->node_data->setType($fake_right_expr, Type::getInt()); ArithmeticOpAnalyzer::analyze($statements_analyzer, $statements_analyzer->node_data, $stmt->var, $fake_right_expr, $stmt, $return_type, $context); $result_type = $return_type ?? Type::getMixed(); $statements_analyzer->node_data->setType($stmt, $result_type); \Psalm\Internal\Analyzer\Statements\Expression\BinaryOpAnalyzer::addDataFlow($statements_analyzer, $stmt, $stmt->var, $fake_right_expr, 'inc'); $var_id = \Psalm\Internal\Analyzer\Statements\Expression\ExpressionIdentifier::getExtendedVarId($stmt->var, null); $codebase = $statements_analyzer->getCodebase(); if ($var_id && isset($context->vars_in_scope[$var_id])) { $context->vars_in_scope[$var_id] = $result_type; if ($codebase->find_unused_variables && $stmt->var instanceof PhpParser\Node\Expr\Variable) { $context->assigned_var_ids[$var_id] = (int) $stmt->var->getAttribute('startFilePos'); $context->possibly_assigned_var_ids[$var_id] = \true; } // removes dependent vars from $context $context->removeDescendents($var_id, $context->vars_in_scope[$var_id], $return_type, $statements_analyzer); } } else { $fake_right_expr = new VirtualLNumber(1, $stmt->getAttributes()); $operation = $stmt instanceof PostInc || $stmt instanceof PreInc ? new VirtualPlus($stmt->var, $fake_right_expr, $stmt->var->getAttributes()) : new VirtualMinus($stmt->var, $fake_right_expr, $stmt->var->getAttributes()); $fake_assignment = new VirtualAssign($stmt->var, $operation, $stmt->getAttributes()); $old_node_data = $statements_analyzer->node_data; $statements_analyzer->node_data = clone $statements_analyzer->node_data; if (ExpressionAnalyzer::analyze($statements_analyzer, $fake_assignment, $context) === \false) { return \false; } if ($stmt instanceof PreInc || $stmt instanceof PreDec) { $old_node_data->setType($stmt, $statements_analyzer->node_data->getType($fake_assignment) ?? Type::getMixed()); } $statements_analyzer->node_data = $old_node_data; } return \true; } } parts as $part) { if (ExpressionAnalyzer::analyze($statements_analyzer, $part, $context) === \false) { return \false; } if ($part instanceof EncapsedStringPart) { if ($literal_string !== null) { $literal_string .= $part->value; } $non_empty = $non_empty || $part->value !== ""; } elseif ($part_type = $statements_analyzer->node_data->getType($part)) { $casted_part_type = \Psalm\Internal\Analyzer\Statements\Expression\CastAnalyzer::castStringAttempt($statements_analyzer, $context, $part_type, $part); if (!$casted_part_type->allLiterals()) { $all_literals = \false; } elseif (!$non_empty) { // Check if all literals are nonempty $non_empty = \true; foreach ($casted_part_type->getAtomicTypes() as $atomic_literal) { if (!$atomic_literal instanceof TLiteralInt && !$atomic_literal instanceof TNonspecificLiteralInt && !$atomic_literal instanceof TLiteralFloat && !$atomic_literal instanceof TNonEmptyNonspecificLiteralString && !($atomic_literal instanceof TLiteralString && $atomic_literal->value !== "")) { $non_empty = \false; break; } } } if ($literal_string !== null) { if ($casted_part_type->isSingleLiteral()) { $literal_string .= $casted_part_type->getSingleLiteral()->value; } else { $literal_string = null; } } if ($statements_analyzer->data_flow_graph && !in_array('TaintedInput', $statements_analyzer->getSuppressedIssues())) { $var_location = new CodeLocation($statements_analyzer, $part); $new_parent_node = DataFlowNode::getForAssignment('concat', $var_location); $statements_analyzer->data_flow_graph->addNode($new_parent_node); $parent_nodes[$new_parent_node->id] = $new_parent_node; $codebase = $statements_analyzer->getCodebase(); $event = new AddRemoveTaintsEvent($stmt, $context, $statements_analyzer, $codebase); $added_taints = $codebase->config->eventDispatcher->dispatchAddTaints($event); $removed_taints = $codebase->config->eventDispatcher->dispatchRemoveTaints($event); if ($casted_part_type->parent_nodes) { foreach ($casted_part_type->parent_nodes as $parent_node) { $statements_analyzer->data_flow_graph->addPath($parent_node, $new_parent_node, 'concat', $added_taints, $removed_taints); } } } } else { $all_literals = \false; $literal_string = null; } } if ($non_empty) { if ($literal_string !== null) { $stmt_type = new Union([Type::getAtomicStringFromLiteral($literal_string)], ['parent_nodes' => $parent_nodes]); } elseif ($all_literals) { $stmt_type = new Union([new TNonEmptyNonspecificLiteralString()], ['parent_nodes' => $parent_nodes]); } else { $stmt_type = new Union([new TNonEmptyString()], ['parent_nodes' => $parent_nodes]); } } elseif ($all_literals) { $stmt_type = new Union([new TNonspecificLiteralString()], ['parent_nodes' => $parent_nodes]); } else { $stmt_type = new Union([new TString()], ['parent_nodes' => $parent_nodes]); } $statements_analyzer->node_data->setType($stmt, $stmt_type); return \true; } } getCodebase(); if (self::handleExpression($statements_analyzer, $stmt, $context, $array_assignment, $global_context, $from_stmt, $template_result, $assigned_to_reference) === \false) { return \false; } if (!$context->inside_conditional && ($stmt instanceof PhpParser\Node\Expr\BinaryOp || $stmt instanceof PhpParser\Node\Expr\Instanceof_ || $stmt instanceof PhpParser\Node\Expr\Assign || $stmt instanceof PhpParser\Node\Expr\BooleanNot || $stmt instanceof PhpParser\Node\Expr\Empty_ || $stmt instanceof PhpParser\Node\Expr\Isset_ || $stmt instanceof PhpParser\Node\Expr\FuncCall)) { $assertions = $statements_analyzer->node_data->getAssertions($stmt); if ($assertions === null) { $negate = $context->inside_negation; while ($stmt instanceof PhpParser\Node\Expr\BooleanNot) { $stmt = $stmt->expr; $negate = !$negate; } AssertionFinder::scrapeAssertions($stmt, $context->self, $statements_analyzer, $codebase, $negate, \true, \false); } } if (self::dispatchAfterExpressionAnalysis($stmt, $context, $statements_analyzer) === \false) { return \false; } return \true; } public static function checkRiskyTruthyFalsyComparison(Type\Union $type, StatementsAnalyzer $statements_analyzer, PhpParser\Node\Expr $stmt) : void { if (count($type->getAtomicTypes()) > 1) { $has_truthy_or_falsy_exclusive_type = \false; $both_types = $type->getBuilder(); foreach ($both_types->getAtomicTypes() as $key => $atomic_type) { if ($atomic_type->isTruthy() || $atomic_type->isFalsy() || $atomic_type instanceof TBool) { $both_types->removeType($key); $has_truthy_or_falsy_exclusive_type = \true; } } if (count($both_types->getAtomicTypes()) > 0 && $has_truthy_or_falsy_exclusive_type) { $both_types = $both_types->freeze(); IssueBuffer::maybeAdd(new RiskyTruthyFalsyComparison('Operand of type ' . $type->getId() . ' contains ' . 'type' . (count($both_types->getAtomicTypes()) > 1 ? 's' : '') . ' ' . $both_types->getId() . ', which can be falsy and truthy. ' . 'This can cause possibly unexpected behavior. Use strict comparison instead.', new CodeLocation($statements_analyzer, $stmt), $type->getId()), $statements_analyzer->getSuppressedIssues()); } } } /** * @param bool $assigned_to_reference This is set to true when the expression being analyzed * here is being assigned to another variable by reference. */ private static function handleExpression(StatementsAnalyzer $statements_analyzer, PhpParser\Node\Expr $stmt, Context $context, bool $array_assignment, ?Context $global_context, bool $from_stmt, ?TemplateResult $template_result = null, bool $assigned_to_reference = \false) : bool { if ($stmt instanceof PhpParser\Node\Expr\Variable) { return VariableFetchAnalyzer::analyze($statements_analyzer, $stmt, $context, \false, null, $array_assignment, \false, $assigned_to_reference); } if ($stmt instanceof PhpParser\Node\Expr\Assign) { return self::analyzeAssignment($statements_analyzer, $stmt, $context, $from_stmt); } if ($stmt instanceof PhpParser\Node\Expr\AssignOp) { return AssignmentAnalyzer::analyzeAssignmentOperation($statements_analyzer, $stmt, $context); } if ($stmt instanceof PhpParser\Node\Expr\MethodCall) { return MethodCallAnalyzer::analyze($statements_analyzer, $stmt, $context, \true, $template_result); } if ($stmt instanceof PhpParser\Node\Expr\StaticCall) { return StaticCallAnalyzer::analyze($statements_analyzer, $stmt, $context, $template_result); } if ($stmt instanceof PhpParser\Node\Expr\ConstFetch) { ConstFetchAnalyzer::analyze($statements_analyzer, $stmt, $context); return \true; } if ($stmt instanceof PhpParser\Node\Scalar\String_) { $statements_analyzer->node_data->setType($stmt, Type::getString($stmt->value)); return \true; } if ($stmt instanceof PhpParser\Node\Scalar\EncapsedStringPart) { return \true; } if ($stmt instanceof PhpParser\Node\Scalar\MagicConst) { MagicConstAnalyzer::analyze($statements_analyzer, $stmt, $context); return \true; } if ($stmt instanceof PhpParser\Node\Scalar\LNumber) { $statements_analyzer->node_data->setType($stmt, Type::getInt(\false, $stmt->value)); return \true; } if ($stmt instanceof PhpParser\Node\Scalar\DNumber) { $statements_analyzer->node_data->setType($stmt, Type::getFloat($stmt->value)); return \true; } if ($stmt instanceof PhpParser\Node\Expr\UnaryMinus || $stmt instanceof PhpParser\Node\Expr\UnaryPlus) { return UnaryPlusMinusAnalyzer::analyze($statements_analyzer, $stmt, $context); } if ($stmt instanceof PhpParser\Node\Expr\Isset_) { IssetAnalyzer::analyze($statements_analyzer, $stmt, $context); $statements_analyzer->node_data->setType($stmt, Type::getBool()); return \true; } if ($stmt instanceof PhpParser\Node\Expr\ClassConstFetch) { return ClassConstAnalyzer::analyzeFetch($statements_analyzer, $stmt, $context); } if ($stmt instanceof PhpParser\Node\Expr\PropertyFetch) { return InstancePropertyFetchAnalyzer::analyze($statements_analyzer, $stmt, $context, $array_assignment); } if ($stmt instanceof PhpParser\Node\Expr\StaticPropertyFetch) { return StaticPropertyFetchAnalyzer::analyze($statements_analyzer, $stmt, $context); } if ($stmt instanceof PhpParser\Node\Expr\BitwiseNot) { return BitwiseNotAnalyzer::analyze($statements_analyzer, $stmt, $context); } if ($stmt instanceof PhpParser\Node\Expr\BinaryOp) { return BinaryOpAnalyzer::analyze($statements_analyzer, $stmt, $context, 0, $from_stmt); } if ($stmt instanceof PhpParser\Node\Expr\PostInc || $stmt instanceof PhpParser\Node\Expr\PostDec || $stmt instanceof PhpParser\Node\Expr\PreInc || $stmt instanceof PhpParser\Node\Expr\PreDec) { return IncDecExpressionAnalyzer::analyze($statements_analyzer, $stmt, $context); } if ($stmt instanceof PhpParser\Node\Expr\New_) { return NewAnalyzer::analyze($statements_analyzer, $stmt, $context, $template_result); } if ($stmt instanceof PhpParser\Node\Expr\Array_) { return ArrayAnalyzer::analyze($statements_analyzer, $stmt, $context); } if ($stmt instanceof PhpParser\Node\Scalar\Encapsed) { return EncapsulatedStringAnalyzer::analyze($statements_analyzer, $stmt, $context); } if ($stmt instanceof PhpParser\Node\Expr\FuncCall) { return FunctionCallAnalyzer::analyze($statements_analyzer, $stmt, $context, $template_result); } if ($stmt instanceof PhpParser\Node\Expr\Ternary) { return TernaryAnalyzer::analyze($statements_analyzer, $stmt, $context); } if ($stmt instanceof PhpParser\Node\Expr\BooleanNot) { return BooleanNotAnalyzer::analyze($statements_analyzer, $stmt, $context); } if ($stmt instanceof PhpParser\Node\Expr\Empty_) { EmptyAnalyzer::analyze($statements_analyzer, $stmt, $context); return \true; } if ($stmt instanceof PhpParser\Node\Expr\Closure || $stmt instanceof PhpParser\Node\Expr\ArrowFunction) { return ClosureAnalyzer::analyzeExpression($statements_analyzer, $stmt, $context); } if ($stmt instanceof PhpParser\Node\Expr\ArrayDimFetch) { return ArrayFetchAnalyzer::analyze($statements_analyzer, $stmt, $context); } if ($stmt instanceof PhpParser\Node\Expr\Cast) { return CastAnalyzer::analyze($statements_analyzer, $stmt, $context); } if ($stmt instanceof PhpParser\Node\Expr\Clone_) { return CloneAnalyzer::analyze($statements_analyzer, $stmt, $context); } if ($stmt instanceof PhpParser\Node\Expr\Instanceof_) { return InstanceofAnalyzer::analyze($statements_analyzer, $stmt, $context); } if ($stmt instanceof PhpParser\Node\Expr\Exit_) { return ExitAnalyzer::analyze($statements_analyzer, $stmt, $context); } if ($stmt instanceof PhpParser\Node\Expr\Include_) { return IncludeAnalyzer::analyze($statements_analyzer, $stmt, $context, $global_context); } if ($stmt instanceof PhpParser\Node\Expr\Eval_) { EvalAnalyzer::analyze($statements_analyzer, $stmt, $context); return \true; } if ($stmt instanceof PhpParser\Node\Expr\AssignRef) { if (!AssignmentAnalyzer::analyzeAssignmentRef($statements_analyzer, $stmt, $context)) { IssueBuffer::maybeAdd(new UnsupportedReferenceUsage("This reference cannot be analyzed by Psalm", new CodeLocation($statements_analyzer->getSource(), $stmt)), $statements_analyzer->getSuppressedIssues()); // Analyze as if it were a normal assignent and just pretend the reference doesn't exist return self::analyzeAssignment($statements_analyzer, $stmt, $context, $from_stmt); } return \true; } if ($stmt instanceof PhpParser\Node\Expr\ErrorSuppress) { $context->error_suppressing = \true; if (self::analyze($statements_analyzer, $stmt->expr, $context) === \false) { return \false; } $context->error_suppressing = \false; $expr_type = $statements_analyzer->node_data->getType($stmt->expr); if ($expr_type) { $statements_analyzer->node_data->setType($stmt, $expr_type); } return \true; } if ($stmt instanceof PhpParser\Node\Expr\ShellExec) { $concat = new VirtualEncapsed($stmt->parts, $stmt->getAttributes()); $virtual_call = new VirtualFuncCall(new VirtualName(['shell_exec']), [new VirtualArg($concat)], $stmt->getAttributes()); return self::handleExpression($statements_analyzer, $virtual_call, $context, $array_assignment, $global_context, $from_stmt, $template_result, $assigned_to_reference); } if ($stmt instanceof PhpParser\Node\Expr\Print_) { $was_inside_call = $context->inside_call; $context->inside_call = \true; if (PrintAnalyzer::analyze($statements_analyzer, $stmt, $context) === \false) { $context->inside_call = $was_inside_call; return \false; } $context->inside_call = $was_inside_call; return \true; } if ($stmt instanceof PhpParser\Node\Expr\Yield_) { return YieldAnalyzer::analyze($statements_analyzer, $stmt, $context); } if ($stmt instanceof PhpParser\Node\Expr\YieldFrom) { return YieldFromAnalyzer::analyze($statements_analyzer, $stmt, $context); } $codebase = $statements_analyzer->getCodebase(); $analysis_php_version_id = $codebase->analysis_php_version_id; if ($stmt instanceof PhpParser\Node\Expr\Match_ && $analysis_php_version_id >= 80000) { return MatchAnalyzer::analyze($statements_analyzer, $stmt, $context); } if ($stmt instanceof PhpParser\Node\Expr\Throw_ && $analysis_php_version_id >= 80000) { return \Psalm\Internal\Analyzer\Statements\ThrowAnalyzer::analyze($statements_analyzer, $stmt, $context); } if (($stmt instanceof PhpParser\Node\Expr\NullsafePropertyFetch || $stmt instanceof PhpParser\Node\Expr\NullsafeMethodCall) && $analysis_php_version_id >= 80000) { return NullsafeAnalyzer::analyze($statements_analyzer, $stmt, $context); } if ($stmt instanceof PhpParser\Node\Expr\Error) { // do nothing return \true; } IssueBuffer::maybeAdd(new UnrecognizedExpression('Psalm does not understand ' . get_class($stmt) . ' for PHP ' . $codebase->getMajorAnalysisPhpVersion() . '.' . $codebase->getMinorAnalysisPhpVersion(), new CodeLocation($statements_analyzer->getSource(), $stmt)), $statements_analyzer->getSuppressedIssues()); return \false; } public static function isMock(string $fq_class_name) : bool { return in_array(strtolower($fq_class_name), Config::getInstance()->getMockClasses(), \true); } /** * @param PhpParser\Node\Expr\Assign|PhpParser\Node\Expr\AssignRef $stmt */ private static function analyzeAssignment(StatementsAnalyzer $statements_analyzer, PhpParser\Node\Expr $stmt, Context $context, bool $from_stmt) : bool { $assignment_type = AssignmentAnalyzer::analyze($statements_analyzer, $stmt->var, $stmt->expr, null, $context, $stmt->getDocComment(), [], !$from_stmt ? $stmt : null); if ($assignment_type === \false) { return \false; } if (!$from_stmt) { $statements_analyzer->node_data->setType($stmt, $assignment_type); } return \true; } private static function dispatchBeforeExpressionAnalysis(PhpParser\Node\Expr $expr, Context $context, StatementsAnalyzer $statements_analyzer) : ?bool { $codebase = $statements_analyzer->getCodebase(); $event = new BeforeExpressionAnalysisEvent($expr, $context, $statements_analyzer, $codebase, []); if ($codebase->config->eventDispatcher->dispatchBeforeExpressionAnalysis($event) === \false) { return \false; } $file_manipulations = $event->getFileReplacements(); if ($file_manipulations !== []) { FileManipulationBuffer::add($statements_analyzer->getFilePath(), $file_manipulations); } return null; } private static function dispatchAfterExpressionAnalysis(PhpParser\Node\Expr $expr, Context $context, StatementsAnalyzer $statements_analyzer) : ?bool { $codebase = $statements_analyzer->getCodebase(); $event = new AfterExpressionAnalysisEvent($expr, $context, $statements_analyzer, $codebase, []); if ($codebase->config->eventDispatcher->dispatchAfterExpressionAnalysis($event) === \false) { return \false; } $file_manipulations = $event->getFileReplacements(); if ($file_manipulations !== []) { FileManipulationBuffer::add($statements_analyzer->getFilePath(), $file_manipulations); } return null; } } collect_initializations && !$global_context) { IssueBuffer::maybeAdd(new InvalidGlobal('Cannot use global scope here (unless this file is included from a non-global scope)', new CodeLocation($statements_analyzer, $stmt)), $statements_analyzer->getSource()->getSuppressedIssues()); } $codebase = $statements_analyzer->getCodebase(); $source = $statements_analyzer->getSource(); $function_storage = $source instanceof FunctionLikeAnalyzer ? $source->getFunctionLikeStorage($statements_analyzer) : null; foreach ($stmt->vars as $var) { if (!$var instanceof PhpParser\Node\Expr\Variable) { continue; } if (!is_string($var->name)) { continue; } $var_id = '$' . $var->name; $doc_comment = $stmt->getDocComment(); $comment_type = null; if ($doc_comment) { $var_comments = CommentAnalyzer::getVarComments($doc_comment, $statements_analyzer, $var); $comment_type = CommentAnalyzer::populateVarTypesFromDocblock($var_comments, $var, $context, $statements_analyzer); } if ($comment_type) { $context->vars_in_scope[$var_id] = $comment_type; $context->vars_possibly_in_scope[$var_id] = \true; $context->byref_constraints[$var_id] = new ReferenceConstraint($comment_type); } else { if ($var->name === 'argv' || $var->name === 'argc') { $context->vars_in_scope[$var_id] = VariableFetchAnalyzer::getGlobalType($var_id, $codebase->analysis_php_version_id); } elseif (isset($function_storage->global_types[$var_id])) { $context->vars_in_scope[$var_id] = $function_storage->global_types[$var_id]; $context->vars_possibly_in_scope[$var_id] = \true; } else { $context->vars_in_scope[$var_id] = $global_context && $global_context->hasVariable($var_id) ? $global_context->vars_in_scope[$var_id] : VariableFetchAnalyzer::getGlobalType($var_id, $codebase->analysis_php_version_id); $context->vars_possibly_in_scope[$var_id] = \true; $context->byref_constraints[$var_id] = new ReferenceConstraint(); } } $assignment_node = DataFlowNode::getForAssignment($var_id, new CodeLocation($statements_analyzer, $var)); $context->vars_in_scope[$var_id] = $context->vars_in_scope[$var_id]->setParentNodes([$assignment_node->id => $assignment_node]); $context->references_to_external_scope[$var_id] = \true; if (isset($context->references_in_scope[$var_id])) { // Global shadows existing reference $context->decrementReferenceCount($var_id); unset($context->references_in_scope[$var_id]); } $statements_analyzer->registerVariable($var_id, new CodeLocation($statements_analyzer, $var), $context->branch_point); $statements_analyzer->getCodebase()->analyzer->addNodeReference($statements_analyzer->getFilePath(), $var, $var_id); if ($global_context !== null && $global_context->hasVariable($var_id)) { $global_context->referenced_globals[$var_id] = \true; } } } } loop_scope; $leaving_switch = \true; if ($loop_scope) { if ($context->break_types && end($context->break_types) === 'switch' && (!$stmt->num instanceof PhpParser\Node\Scalar\LNumber || $stmt->num->value < 2)) { $loop_scope->final_actions[] = ScopeAnalyzer::ACTION_LEAVE_SWITCH; } else { $leaving_switch = \false; $loop_scope->final_actions[] = ScopeAnalyzer::ACTION_BREAK; } $redefined_vars = $context->getRedefinedVars($loop_scope->loop_parent_context->vars_in_scope); foreach ($redefined_vars as $var => $type) { $loop_scope->possibly_redefined_loop_parent_vars[$var] = Type::combineUnionTypes($type, $loop_scope->possibly_redefined_loop_parent_vars[$var] ?? null); } if ($loop_scope->iteration_count === 0) { foreach ($context->vars_in_scope as $var_id => $type) { if (!isset($loop_scope->loop_parent_context->vars_in_scope[$var_id])) { $loop_scope->possibly_defined_loop_parent_vars[$var_id] = Type::combineUnionTypes($type, $loop_scope->possibly_defined_loop_parent_vars[$var_id] ?? null); } } } if ($context->finally_scope) { foreach ($context->vars_in_scope as $var_id => &$type) { if (isset($context->finally_scope->vars_in_scope[$var_id])) { $context->finally_scope->vars_in_scope[$var_id] = Type::combineUnionTypes($context->finally_scope->vars_in_scope[$var_id], $type, $statements_analyzer->getCodebase()); } else { $type = $type->setPossiblyUndefined(\true, \true); $context->finally_scope->vars_in_scope[$var_id] = $type; } } unset($type); } } $case_scope = $context->case_scope; if ($case_scope && $leaving_switch) { foreach ($context->vars_in_scope as $var_id => $type) { if ($case_scope->break_vars === null) { $case_scope->break_vars = []; } $case_scope->break_vars[$var_id] = Type::combineUnionTypes($type, $case_scope->break_vars[$var_id] ?? null); } } $context->has_returned = \true; } } \\[\\]\\-\\{\\}:|?\\\\]*|\\$[a-zA-Z_0-9_]+)'; /** * @param array>|null $template_type_map * @param array $type_aliases * @throws DocblockParseException if there was a problem parsing the docblock * @return list */ public static function getTypeFromComment(PhpParser\Comment\Doc $comment, FileSource $source, Aliases $aliases, ?array $template_type_map = null, ?array $type_aliases = null) : array { $parsed_docblock = DocComment::parsePreservingLength($comment); return self::arrayToDocblocks($comment, $parsed_docblock, $source, $aliases, $template_type_map, $type_aliases); } /** * @param array>|null $template_type_map * @param array $type_aliases * @return list * @throws DocblockParseException if there was a problem parsing the docblock */ public static function arrayToDocblocks(PhpParser\Comment\Doc $comment, ParsedDocblock $parsed_docblock, FileSource $source, Aliases $aliases, ?array $template_type_map = null, ?array $type_aliases = null) : array { $var_id = null; $var_type_tokens = null; $original_type = null; $var_comments = []; $comment_text = $comment->getText(); $var_line_number = $comment->getStartLine(); if (isset($parsed_docblock->combined_tags['var'])) { foreach ($parsed_docblock->combined_tags['var'] as $offset => $var_line) { $var_line = trim($var_line); if (!$var_line) { continue; } $type_start = null; $type_end = null; $line_parts = self::splitDocLine($var_line); $line_number = $comment->getStartLine() + substr_count($comment_text, "\n", 0, $offset - $comment->getStartFilePos()); $description = $parsed_docblock->description; if ($line_parts[0]) { $type_start = $offset; $type_end = $type_start + strlen($line_parts[0]); $line_parts[0] = self::sanitizeDocblockType($line_parts[0]); if ($line_parts[0] === '' || $line_parts[0][0] === '$' && !preg_match('/^\\$this(\\||$)/', $line_parts[0])) { throw new IncorrectDocblockException('Misplaced variable'); } try { $var_type_tokens = TypeTokenizer::getFullyQualifiedTokens($line_parts[0], $aliases, $template_type_map, $type_aliases); } catch (TypeParseTreeException $e) { throw new DocblockParseException($line_parts[0] . ' is not a valid type'); } $original_type = $line_parts[0]; $var_line_number = $line_number; if (count($line_parts) > 1) { if ($line_parts[1][0] === '$') { $var_id = $line_parts[1]; $description = trim(substr($var_line, strlen($line_parts[0]) + strlen($line_parts[1]) + 2)); } else { $description = trim(substr($var_line, strlen($line_parts[0]) + 1)); } $description = preg_replace('/\\n \\*\\s+/um', ' ', $description); } } if (!$var_type_tokens || !$original_type) { continue; } try { $defined_type = TypeParser::parseTokens($var_type_tokens, null, $template_type_map ?: [], $type_aliases ?: [], \true); } catch (TypeParseTreeException $e) { throw new DocblockParseException($line_parts[0] . ' is not a valid type' . ' (' . $e->getMessage() . ' in ' . $source->getFilePath() . ':' . $comment->getStartLine() . ')'); } $var_comment = new VarDocblockComment(); $var_comment->type = $defined_type; $var_comment->var_id = $var_id; $var_comment->line_number = $var_line_number; $var_comment->type_start = $type_start; $var_comment->type_end = $type_end; $var_comment->description = $description; self::decorateVarDocblockComment($var_comment, $parsed_docblock); $var_comments[] = $var_comment; } } if (!$var_comments && (isset($parsed_docblock->tags['deprecated']) || isset($parsed_docblock->tags['internal']) || isset($parsed_docblock->tags['readonly']) || isset($parsed_docblock->tags['psalm-readonly']) || isset($parsed_docblock->tags['psalm-readonly-allow-private-mutation']) || isset($parsed_docblock->tags['psalm-allow-private-mutation']) || isset($parsed_docblock->tags['psalm-taint-escape']) || isset($parsed_docblock->tags['psalm-internal']) || isset($parsed_docblock->tags['psalm-suppress']) || $parsed_docblock->description)) { $var_comment = new VarDocblockComment(); self::decorateVarDocblockComment($var_comment, $parsed_docblock); $var_comments[] = $var_comment; } return $var_comments; } private static function decorateVarDocblockComment(VarDocblockComment $var_comment, ParsedDocblock $parsed_docblock) : void { $var_comment->deprecated = isset($parsed_docblock->tags['deprecated']); $var_comment->internal = isset($parsed_docblock->tags['internal']); $var_comment->readonly = isset($parsed_docblock->tags['readonly']) || isset($parsed_docblock->tags['psalm-readonly']) || isset($parsed_docblock->tags['psalm-readonly-allow-private-mutation']); $var_comment->allow_private_mutation = isset($parsed_docblock->tags['psalm-allow-private-mutation']) || isset($parsed_docblock->tags['psalm-readonly-allow-private-mutation']); if (!$var_comment->description) { $var_comment->description = $parsed_docblock->description; } if (isset($parsed_docblock->tags['psalm-taint-escape'])) { foreach ($parsed_docblock->tags['psalm-taint-escape'] as $param) { $param = trim($param); $var_comment->removed_taints[] = $param; } } if (count($var_comment->psalm_internal = DocblockParser::handlePsalmInternal($parsed_docblock)) !== 0) { $var_comment->internal = \true; } if (isset($parsed_docblock->tags['psalm-suppress'])) { foreach ($parsed_docblock->tags['psalm-suppress'] as $offset => $suppress_entry) { foreach (DocComment::parseSuppressList($suppress_entry) as $issue_offset => $suppressed_issue) { $var_comment->suppressed_issues[$issue_offset + $offset] = $suppressed_issue; } } } } /** * @psalm-pure */ public static function sanitizeDocblockType(string $docblock_type) : string { $docblock_type = preg_replace('@^[ \\t]*\\*@m', '', $docblock_type); $docblock_type = preg_replace('/,\\n\\s+}/', '}', $docblock_type); return str_replace("\n", '', $docblock_type); } /** * @throws DocblockParseException if an invalid string is found * @return non-empty-list * @psalm-pure */ public static function splitDocLine(string $return_block) : array { $brackets = ''; $type = ''; $expects_callable_return = \false; $return_block = str_replace("\t", ' ', $return_block); $quote_char = null; $escaped = \false; for ($i = 0, $l = strlen($return_block); $i < $l; ++$i) { $char = $return_block[$i]; $next_char = $i < $l - 1 ? $return_block[$i + 1] : null; $last_char = $i > 0 ? $return_block[$i - 1] : null; if ($quote_char) { if ($char === $quote_char && !$escaped) { $quote_char = null; $type .= $char; continue; } if ($char === '\\' && !$escaped && ($next_char === $quote_char || $next_char === '\\')) { $escaped = \true; $type .= $char; continue; } $escaped = \false; $type .= $char; continue; } if ($char === '"' || $char === '\'') { $quote_char = $char; $type .= $char; continue; } if ($char === ':' && $last_char === ')') { $expects_callable_return = \true; $type .= $char; continue; } if ($char === '/' && $next_char === '/') { // Ignore the rest of the current line $i = strpos($return_block, "\n", $i); if ($i === \false) { throw new IncorrectDocblockException('Comment lines must be terminated with a new line character (\\n).'); } // Remove trailing whitespaces (needed for `sanitizeDocblockType`) $type = rtrim($type); $type .= "\n"; continue; } if ($char === '[' || $char === '{' || $char === '(' || $char === '<') { $brackets .= $char; } elseif ($char === ']' || $char === '}' || $char === ')' || $char === '>') { $last_bracket = substr($brackets, -1); $brackets = substr($brackets, 0, -1); if ($char === ']' && $last_bracket !== '[' || $char === '}' && $last_bracket !== '{' || $char === ')' && $last_bracket !== '(' || $char === '>' && $last_bracket !== '<') { throw new DocblockParseException('Invalid string ' . $return_block); } } elseif ($char === ' ') { if ($brackets) { $expects_callable_return = \false; $type .= ' '; continue; } if ($next_char === '{') { $type .= ' '; continue; } if ($next_char === '|' || $next_char === '&') { $nexter_char = $i < $l - 2 ? $return_block[$i + 2] : null; if ($nexter_char === ' ') { ++$i; $type .= $next_char . ' '; continue; } } if ($last_char === '|' || $last_char === '&') { $type .= ' '; continue; } if ($next_char === ':') { ++$i; $type .= ' :'; $expects_callable_return = \true; continue; } if ($expects_callable_return) { $type .= ' '; $expects_callable_return = \false; continue; } $remaining = trim(preg_replace('@^[ \\t]*\\* *@m', ' ', substr($return_block, $i + 1))); if ($remaining) { return [rtrim($type), ...preg_split('/\\s+/', $remaining) ?: []]; } return [$type]; } $expects_callable_return = \false; $type .= $char; } return [$type]; } /** @return list */ public static function getVarComments(PhpParser\Comment\Doc $doc_comment, \Psalm\Internal\Analyzer\StatementsAnalyzer $statements_analyzer, PhpParser\Node\Expr\Variable $var) : array { $codebase = $statements_analyzer->getCodebase(); $parsed_docblock = $statements_analyzer->getParsedDocblock(); if (!$parsed_docblock) { return []; } $var_comments = []; try { $var_comments = $codebase->config->disable_var_parsing ? [] : self::arrayToDocblocks($doc_comment, $parsed_docblock, $statements_analyzer->getSource(), $statements_analyzer->getSource()->getAliases(), $statements_analyzer->getSource()->getTemplateTypeMap()); } catch (IncorrectDocblockException $e) { IssueBuffer::maybeAdd(new MissingDocblockType($e->getMessage(), new CodeLocation($statements_analyzer, $var))); } catch (DocblockParseException $e) { IssueBuffer::maybeAdd(new InvalidDocblock($e->getMessage(), new CodeLocation($statements_analyzer->getSource(), $var))); } return $var_comments; } /** * @param list $var_comments */ public static function populateVarTypesFromDocblock(array $var_comments, PhpParser\Node\Expr\Variable $var, Context $context, \Psalm\Internal\Analyzer\StatementsAnalyzer $statements_analyzer) : ?Union { if (!is_string($var->name)) { return null; } $codebase = $statements_analyzer->getCodebase(); $comment_type = null; $var_id = '$' . $var->name; foreach ($var_comments as $var_comment) { if (!$var_comment->type) { continue; } try { $var_comment_type = TypeExpander::expandUnion($codebase, $var_comment->type, $context->self, $context->self, $statements_analyzer->getParentFQCLN()); $var_comment_type = $var_comment_type->setFromDocblock(); /** @psalm-suppress UnusedMethodCall */ $var_comment_type->check($statements_analyzer, new CodeLocation($statements_analyzer->getSource(), $var), $statements_analyzer->getSuppressedIssues()); if ($codebase->alter_code && $var_comment->type_start && $var_comment->type_end && $var_comment->line_number) { $type_location = new DocblockTypeLocation($statements_analyzer, $var_comment->type_start, $var_comment->type_end, $var_comment->line_number); $codebase->classlikes->handleDocblockTypeInMigration($codebase, $statements_analyzer, $var_comment_type, $type_location, $context->calling_method_id); } if (!$var_comment->var_id || $var_comment->var_id === $var_id) { $comment_type = $var_comment_type; continue; } $context->vars_in_scope[$var_comment->var_id] = $var_comment_type; } catch (UnexpectedValueException $e) { IssueBuffer::maybeAdd(new InvalidDocblock($e->getMessage(), new CodeLocation($statements_analyzer, $var))); } } return $comment_type; } } */ public ?array $taint_trace = null; /** * @var ?list */ public ?array $other_references = null; /** * @readonly */ public ?string $dupe_key = null; /** * @param self::SEVERITY_* $severity * @param ?list $taint_trace * @param ?list $other_references */ public function __construct(string $severity, int $line_from, int $line_to, string $type, string $message, string $file_name, string $file_path, string $snippet, string $selected_text, int $from, int $to, int $snippet_from, int $snippet_to, int $column_from, int $column_to, int $shortcode = 0, int $error_level = -1, ?array $taint_trace = null, ?array $other_references = null, ?string $dupe_key = null) { $this->severity = $severity; $this->line_from = $line_from; $this->line_to = $line_to; $this->type = $type; $this->message = $message; $this->file_name = $file_name; $this->file_path = $file_path; $this->snippet = $snippet; $this->selected_text = $selected_text; $this->from = $from; $this->to = $to; $this->snippet_from = $snippet_from; $this->snippet_to = $snippet_to; $this->column_from = $column_from; $this->column_to = $column_to; $this->shortcode = $shortcode; $this->error_level = $error_level; $this->link = $shortcode ? 'https://psalm.dev/' . str_pad((string) $shortcode, 3, "0", STR_PAD_LEFT) : ''; $this->taint_trace = $taint_trace; $this->other_references = $other_references; $this->dupe_key = $dupe_key; } } inferred = $inferred; $this->allow_trait = $allow_trait; $this->allow_interface = $allow_interface; $this->allow_enum = $allow_enum; $this->from_docblock = $from_docblock; $this->from_attribute = $from_attribute; } } name, strtolower($guide_method_storage->cased_name ?: '')); $implementer_declaring_method_id = $codebase->methods->getDeclaringMethodId($implementer_method_id); $cased_implementer_method_id = $implementer_classlike_storage->name . '::' . $implementer_method_storage->cased_name; $cased_guide_method_id = $guide_classlike_storage->name . '::' . $guide_method_storage->cased_name; $codebase->methods->file_reference_provider->addMethodDependencyToClassMember(strtolower((string) ($implementer_declaring_method_id ?? $implementer_method_id)), strtolower($guide_classlike_storage->name . '::' . $guide_method_storage->cased_name)); self::checkForObviousMethodMismatches($guide_classlike_storage, $implementer_classlike_storage, $guide_method_storage, $implementer_method_storage, $guide_method_storage->visibility, $implementer_visibility, $cased_guide_method_id, $cased_implementer_method_id, $prevent_method_signature_mismatch, $prevent_abstract_override, $codebase->analysis_php_version_id >= 80000, $code_location, $suppressed_issues); if ($guide_method_storage->signature_return_type && $prevent_method_signature_mismatch) { self::compareMethodSignatureReturnTypes($codebase, $guide_classlike_storage, $implementer_classlike_storage, $guide_method_storage, $implementer_method_storage, $guide_method_storage->signature_return_type, $cased_guide_method_id, $implementer_called_class_name, $cased_implementer_method_id, $code_location, $suppressed_issues); } // CallMapHandler needed due to https://github.com/vimeo/psalm/issues/10378 if (!$guide_classlike_storage->user_defined && $implementer_classlike_storage->user_defined && $codebase->analysis_php_version_id >= 80100 && ($guide_method_storage->return_type && InternalCallMapHandler::inCallMap($cased_guide_method_id) || $guide_method_storage->signature_return_type) && !$implementer_method_storage->signature_return_type && !array_filter($implementer_method_storage->attributes, static fn(AttributeStorage $s): bool => $s->fq_class_name === 'ReturnTypeWillChange')) { IssueBuffer::maybeAdd(new MethodSignatureMustProvideReturnType('Method ' . $cased_implementer_method_id . ' must have a return type signature', $implementer_method_storage->location ?: $code_location), $suppressed_issues + $implementer_classlike_storage->suppressed_issues); } if ($guide_method_storage->return_type && $implementer_method_storage->return_type && !$implementer_method_storage->inherited_return_type && ($guide_method_storage->signature_return_type !== $guide_method_storage->return_type || $implementer_method_storage->signature_return_type !== $implementer_method_storage->return_type) && $implementer_classlike_storage->user_defined && (!$guide_classlike_storage->stubbed || $guide_classlike_storage->template_types)) { self::compareMethodDocblockReturnTypes($codebase, $guide_classlike_storage, $implementer_classlike_storage, $implementer_method_storage, $guide_method_storage->return_type, $implementer_method_storage->return_type, $cased_guide_method_id, $implementer_called_class_name, $implementer_declaring_method_id, $code_location, $suppressed_issues); } foreach ($guide_method_storage->params as $i => $guide_param) { if (!isset($implementer_method_storage->params[$i])) { if (!$prevent_abstract_override && $i >= $guide_method_storage->required_param_count) { continue; } if (IssueBuffer::accepts(new MethodSignatureMismatch('Method ' . $cased_implementer_method_id . ' has fewer parameters than parent method ' . $cased_guide_method_id, $code_location), $suppressed_issues + $implementer_classlike_storage->suppressed_issues)) { return \false; } return null; } self::compareMethodParams($codebase, $stmt, $implementer_classlike_storage, $guide_classlike_storage, $implementer_called_class_name, $guide_method_storage, $implementer_method_storage, $guide_param, $implementer_method_storage->params[$i], $i, $cased_guide_method_id, $cased_implementer_method_id, $prevent_method_signature_mismatch, $code_location, $suppressed_issues); } if (($guide_classlike_storage->is_interface || $guide_classlike_storage->preserve_constructor_signature || $implementer_method_storage->cased_name !== '__construct') && $implementer_method_storage->required_param_count > $guide_method_storage->required_param_count) { if ($implementer_method_storage->cased_name !== '__construct') { if (IssueBuffer::accepts(new MethodSignatureMismatch('Method ' . $cased_implementer_method_id . ' has more required parameters than parent method ' . $cased_guide_method_id, $code_location), $suppressed_issues + $implementer_classlike_storage->suppressed_issues)) { return \false; } } else { if (IssueBuffer::accepts(new ConstructorSignatureMismatch('Method ' . $cased_implementer_method_id . ' has more required parameters than parent method ' . $cased_guide_method_id, $code_location), $suppressed_issues + $implementer_classlike_storage->suppressed_issues)) { return \false; } } return null; } return null; } /** * @param string[] $suppressed_issues */ private static function checkForObviousMethodMismatches(ClassLikeStorage $guide_classlike_storage, ClassLikeStorage $implementer_classlike_storage, MethodStorage $guide_method_storage, MethodStorage $implementer_method_storage, int $guide_visibility, int $implementer_visibility, string $cased_guide_method_id, string $cased_implementer_method_id, bool $prevent_method_signature_mismatch, bool $prevent_abstract_override, bool $trait_mismatches_are_fatal, CodeLocation $code_location, array $suppressed_issues) : void { if ($implementer_visibility > $guide_visibility) { if ($trait_mismatches_are_fatal || $guide_classlike_storage->is_trait === $implementer_classlike_storage->is_trait || !in_array($guide_classlike_storage->name, $implementer_classlike_storage->used_traits) || $implementer_method_storage->defining_fqcln !== $implementer_classlike_storage->name || !$implementer_method_storage->abstract && !$guide_method_storage->abstract) { IssueBuffer::maybeAdd(new OverriddenMethodAccess('Method ' . $cased_implementer_method_id . ' has different access level than ' . $cased_guide_method_id, $code_location), $suppressed_issues + $implementer_classlike_storage->suppressed_issues); } else { IssueBuffer::maybeAdd(new TraitMethodSignatureMismatch('Method ' . $cased_implementer_method_id . ' has different access level than ' . $cased_guide_method_id, $code_location), $suppressed_issues + $implementer_classlike_storage->suppressed_issues); } } if ($guide_method_storage->final && $prevent_method_signature_mismatch && $prevent_abstract_override) { IssueBuffer::maybeAdd(new MethodSignatureMismatch('Method ' . $cased_guide_method_id . ' is declared final and cannot be overridden', $code_location), $guide_method_storage->final_from_docblock ? $suppressed_issues + $implementer_classlike_storage->suppressed_issues : []); } if ($prevent_abstract_override && !$guide_method_storage->abstract && $implementer_method_storage->abstract && !$guide_classlike_storage->abstract && !$guide_classlike_storage->is_interface) { IssueBuffer::maybeAdd(new MethodSignatureMismatch('Method ' . $cased_implementer_method_id . ' cannot be abstract when inherited method ' . $cased_guide_method_id . ' is non-abstract', $code_location), $suppressed_issues + $implementer_classlike_storage->suppressed_issues); } if ($guide_method_storage->returns_by_ref && !$implementer_method_storage->returns_by_ref) { IssueBuffer::maybeAdd(new MethodSignatureMismatch('Method ' . $cased_implementer_method_id . ' must return by-reference', $code_location), $suppressed_issues + $implementer_classlike_storage->suppressed_issues); } if ($guide_method_storage->external_mutation_free && !$implementer_method_storage->external_mutation_free && !$guide_method_storage->mutation_free_inferred && $prevent_method_signature_mismatch) { IssueBuffer::maybeAdd(new MissingImmutableAnnotation($cased_guide_method_id . ' is marked @psalm-external-mutation-free, but ' . $implementer_classlike_storage->name . '::' . ($guide_method_storage->cased_name ?: '') . ' is not marked @psalm-external-mutation-free', $code_location), $suppressed_issues + $implementer_classlike_storage->suppressed_issues); } } /** * @param string[] $suppressed_issues */ private static function compareMethodParams(Codebase $codebase, ?ClassMethod $stmt, ClassLikeStorage $implementer_classlike_storage, ClassLikeStorage $guide_classlike_storage, string $implementer_called_class_name, MethodStorage $guide_method_storage, MethodStorage $implementer_method_storage, FunctionLikeParameter $guide_param, FunctionLikeParameter $implementer_param, int $i, string $cased_guide_method_id, string $cased_implementer_method_id, bool $prevent_method_signature_mismatch, CodeLocation $code_location, array $suppressed_issues) : void { // ignore errors from stubbed/out of project files $config = Config::getInstance(); if (!$implementer_classlike_storage->user_defined && (!$implementer_param->location || !$config->isInProjectDirs($implementer_param->location->file_path))) { return; } if ($prevent_method_signature_mismatch) { if (!$guide_classlike_storage->user_defined && $guide_param->type) { $implementer_param_type = $implementer_param->signature_type; $guide_param_signature_type = $guide_param->type; $or_null_guide_param_signature_type = $guide_param->signature_type ? $guide_param->signature_type->getBuilder() : null; if ($or_null_guide_param_signature_type) { $or_null_guide_param_signature_type->addType(new TNull()); } if ($cased_guide_method_id === 'Serializable::unserialize') { $guide_param_signature_type = null; $or_null_guide_param_signature_type = null; } if (!$guide_param->type->hasMixed() && !$guide_param->type->from_docblock && ($implementer_param_type || $guide_param_signature_type)) { if ($implementer_param_type && (!$guide_param_signature_type || strtolower($implementer_param_type->getId()) !== strtolower($guide_param_signature_type->getId())) && (!$or_null_guide_param_signature_type || strtolower($implementer_param_type->getId()) !== strtolower($or_null_guide_param_signature_type->getId()))) { if ($implementer_method_storage->cased_name === '__construct') { IssueBuffer::maybeAdd(new ConstructorSignatureMismatch('Argument ' . ($i + 1) . ' of ' . $cased_implementer_method_id . ' has wrong type \'' . $implementer_param_type . '\', expecting \'' . $guide_param_signature_type . '\' as defined by ' . $cased_guide_method_id, $implementer_param->location && $config->isInProjectDirs($implementer_param->location->file_path) ? $implementer_param->location : $code_location), $suppressed_issues + $implementer_classlike_storage->suppressed_issues); } else { IssueBuffer::maybeAdd(new MethodSignatureMismatch('Argument ' . ($i + 1) . ' of ' . $cased_implementer_method_id . ' has wrong type \'' . $implementer_param_type . '\', expecting \'' . $guide_param_signature_type . '\' as defined by ' . $cased_guide_method_id, $implementer_param->location && $config->isInProjectDirs($implementer_param->location->file_path) ? $implementer_param->location : $code_location), $suppressed_issues + $implementer_classlike_storage->suppressed_issues); } return; } } } if ($guide_param->name !== $implementer_param->name && $guide_method_storage->allow_named_arg_calls && $implementer_classlike_storage->user_defined && $implementer_param->location && $guide_method_storage->cased_name && (strpos($guide_method_storage->cased_name, '__') !== 0 || $guide_classlike_storage->preserve_constructor_signature && $guide_method_storage->cased_name === '__construct') && $config->isInProjectDirs($implementer_param->location->file_path)) { // even if it's just a single arg, it needs to be renamed in case it's called with a single named arg if ($config->allow_named_arg_calls || $guide_classlike_storage->location && !$config->isInProjectDirs($guide_classlike_storage->location->file_path)) { if ($codebase->alter_code) { $project_analyzer = \Psalm\Internal\Analyzer\ProjectAnalyzer::getInstance(); if ($stmt && isset($project_analyzer->getIssuesToFix()['ParamNameMismatch'])) { $param_replacer = new ParamReplacementVisitor($implementer_param->name, $guide_param->name); $traverser = new NodeTraverser(); $traverser->addVisitor($param_replacer); $traverser->traverse([$stmt]); if ($replacements = $param_replacer->getReplacements()) { FileManipulationBuffer::add($implementer_param->location->file_path, $replacements); } } } else { IssueBuffer::maybeAdd(new ParamNameMismatch('Argument ' . ($i + 1) . ' of ' . $cased_implementer_method_id . ' has wrong name $' . $implementer_param->name . ', expecting $' . $guide_param->name . ' as defined by ' . $cased_guide_method_id, $implementer_param->location), $suppressed_issues + $implementer_classlike_storage->suppressed_issues); } } } if ($implementer_param->signature_type) { self::compareMethodSignatureParams($codebase, $i, $guide_classlike_storage, $implementer_classlike_storage, $guide_method_storage, $implementer_method_storage, $guide_param, $implementer_param->signature_type, $cased_guide_method_id, $cased_implementer_method_id, $code_location, $suppressed_issues); } } if ($implementer_param->type && $guide_param->type && $implementer_param->type->getId() !== $guide_param->type->getId()) { self::compareMethodDocblockParams($codebase, $i, $guide_classlike_storage, $implementer_classlike_storage, $implementer_called_class_name, $guide_method_storage, $implementer_method_storage, $cased_guide_method_id, $cased_implementer_method_id, $guide_param->type, $implementer_param->type, $code_location, $suppressed_issues); } if ($implementer_param->by_ref !== $guide_param->by_ref) { IssueBuffer::maybeAdd(new MethodSignatureMismatch('Argument ' . ($i + 1) . ' of ' . $cased_implementer_method_id . ' is' . ($implementer_param->by_ref ? '' : ' not') . ' passed by reference, but argument ' . ($i + 1) . ' of ' . $cased_guide_method_id . ' is' . ($guide_param->by_ref ? '' : ' not'), $implementer_param->location && $config->isInProjectDirs($implementer_param->location->file_path) ? $implementer_param->location : $code_location), $suppressed_issues + $implementer_classlike_storage->suppressed_issues); } } /** * @param string[] $suppressed_issues */ private static function compareMethodSignatureParams(Codebase $codebase, int $i, ClassLikeStorage $guide_classlike_storage, ClassLikeStorage $implementer_classlike_storage, MethodStorage $guide_method_storage, MethodStorage $implementer_method_storage, FunctionLikeParameter $guide_param, Union $implementer_param_signature_type, string $cased_guide_method_id, string $cased_implementer_method_id, CodeLocation $code_location, array $suppressed_issues) : void { $guide_param_signature_type = $guide_param->signature_type ? TypeExpander::expandUnion($codebase, $guide_param->signature_type, $guide_classlike_storage->is_trait && $guide_method_storage->abstract ? $implementer_classlike_storage->name : $guide_classlike_storage->name, $guide_classlike_storage->is_trait && $guide_method_storage->abstract ? $implementer_classlike_storage->name : $guide_classlike_storage->name, $guide_classlike_storage->is_trait && $guide_method_storage->abstract ? $implementer_classlike_storage->parent_class : $guide_classlike_storage->parent_class) : null; // CallMapHandler needed due to https://github.com/vimeo/psalm/issues/10378 if (!$guide_param->signature_type && $guide_param->type && InternalCallMapHandler::inCallMap($cased_guide_method_id)) { $guide_method_storage_param_type = TypeExpander::expandUnion($codebase, $guide_param->type, $guide_classlike_storage->is_trait && $guide_method_storage->abstract ? $implementer_classlike_storage->name : $guide_classlike_storage->name, $guide_classlike_storage->is_trait && $guide_method_storage->abstract ? $implementer_classlike_storage->name : $guide_classlike_storage->name, $guide_classlike_storage->is_trait && $guide_method_storage->abstract ? $implementer_classlike_storage->parent_class : $guide_classlike_storage->parent_class); $builder = $guide_method_storage_param_type->getBuilder(); foreach ($builder->getAtomicTypes() as $k => $t) { if ($t instanceof TTemplateParam) { $builder->removeType($k); foreach ($t->as->getAtomicTypes() as $as_t) { $builder->addType($as_t); } } } if ($builder->hasMixed()) { foreach ($builder->getAtomicTypes() as $k => $_) { if ($k !== 'mixed') { $builder->removeType($k); } } } $guide_method_storage_param_type = $builder->freeze(); unset($builder); if (!$guide_method_storage_param_type->hasMixed() || $codebase->analysis_php_version_id >= 80000) { $guide_param_signature_type = $guide_method_storage_param_type; } } $implementer_param_signature_type = TypeExpander::expandUnion($codebase, $implementer_param_signature_type, $implementer_classlike_storage->name, $implementer_classlike_storage->name, $implementer_classlike_storage->parent_class); $is_contained_by = $codebase->analysis_php_version_id >= 70400 && $guide_param_signature_type ? UnionTypeComparator::isContainedBy($codebase, $guide_param_signature_type, $implementer_param_signature_type) : UnionTypeComparator::isContainedByInPhp($guide_param_signature_type, $implementer_param_signature_type); if (!$is_contained_by) { $config = Config::getInstance(); if ($codebase->analysis_php_version_id >= 80000 || $guide_classlike_storage->is_trait === $implementer_classlike_storage->is_trait || !in_array($guide_classlike_storage->name, $implementer_classlike_storage->used_traits) || $implementer_method_storage->defining_fqcln !== $implementer_classlike_storage->name || !$implementer_method_storage->abstract && !$guide_method_storage->abstract) { if ($implementer_method_storage->cased_name === '__construct') { IssueBuffer::maybeAdd(new ConstructorSignatureMismatch('Argument ' . ($i + 1) . ' of ' . $cased_implementer_method_id . ' has wrong type \'' . $implementer_param_signature_type . '\', expecting \'' . $guide_param_signature_type . '\' as defined by ' . $cased_guide_method_id, $implementer_method_storage->params[$i]->location && $config->isInProjectDirs($implementer_method_storage->params[$i]->location->file_path) ? $implementer_method_storage->params[$i]->location : $code_location), $suppressed_issues + $implementer_classlike_storage->suppressed_issues); } else { IssueBuffer::maybeAdd(new MethodSignatureMismatch('Argument ' . ($i + 1) . ' of ' . $cased_implementer_method_id . ' has wrong type \'' . $implementer_param_signature_type . '\', expecting \'' . $guide_param_signature_type . '\' as defined by ' . $cased_guide_method_id, $implementer_method_storage->params[$i]->location && $config->isInProjectDirs($implementer_method_storage->params[$i]->location->file_path) ? $implementer_method_storage->params[$i]->location : $code_location), $suppressed_issues + $implementer_classlike_storage->suppressed_issues); } } else { IssueBuffer::maybeAdd(new TraitMethodSignatureMismatch('Argument ' . ($i + 1) . ' of ' . $cased_implementer_method_id . ' has wrong type \'' . $implementer_param_signature_type . '\', expecting \'' . $guide_param_signature_type . '\' as defined by ' . $cased_guide_method_id, $implementer_method_storage->params[$i]->location && $config->isInProjectDirs($implementer_method_storage->params[$i]->location->file_path) ? $implementer_method_storage->params[$i]->location : $code_location), $suppressed_issues + $implementer_classlike_storage->suppressed_issues); } } } /** * @param string[] $suppressed_issues */ private static function compareMethodDocblockParams(Codebase $codebase, int $i, ClassLikeStorage $guide_classlike_storage, ClassLikeStorage $implementer_classlike_storage, string $implementer_called_class_name, MethodStorage $guide_method_storage, MethodStorage $implementer_method_storage, string $cased_guide_method_id, string $cased_implementer_method_id, Union $guide_param_type, Union $implementer_param_type, CodeLocation $code_location, array $suppressed_issues) : void { $implementer_method_storage_param_type = TypeExpander::expandUnion($codebase, $implementer_param_type, $implementer_classlike_storage->name, $implementer_called_class_name, $implementer_classlike_storage->parent_class); $guide_method_storage_param_type = TypeExpander::expandUnion($codebase, $guide_param_type, $guide_classlike_storage->is_trait && $guide_method_storage->abstract ? $implementer_classlike_storage->name : $guide_classlike_storage->name, $guide_classlike_storage->is_trait && $guide_method_storage->abstract ? $implementer_classlike_storage->name : $guide_classlike_storage->name, $guide_classlike_storage->is_trait && $guide_method_storage->abstract ? $implementer_classlike_storage->parent_class : $guide_classlike_storage->parent_class); $guide_class_name = $guide_classlike_storage->name; if ($implementer_classlike_storage->is_trait) { $implementer_called_class_storage = $codebase->classlike_storage_provider->get($implementer_called_class_name); if (isset($implementer_called_class_storage->template_extended_params[$implementer_classlike_storage->name])) { self::transformTemplates($implementer_called_class_storage->template_extended_params, $implementer_classlike_storage->name, $implementer_method_storage_param_type, $codebase); self::transformTemplates($implementer_called_class_storage->template_extended_params, $guide_class_name, $guide_method_storage_param_type, $codebase); } } $builder = $implementer_method_storage_param_type->getBuilder(); foreach ($builder->getAtomicTypes() as $k => $t) { if ($t instanceof TTemplateParam && strpos($t->defining_class, 'fn-') === 0) { $builder->removeType($k); foreach ($t->as->getAtomicTypes() as $as_t) { $builder->addType($as_t); } } } $implementer_method_storage_param_type = $builder->freeze(); $builder = $guide_method_storage_param_type->getBuilder(); foreach ($builder->getAtomicTypes() as $k => $t) { if ($t instanceof TTemplateParam && strpos($t->defining_class, 'fn-') === 0) { $builder->removeType($k); foreach ($t->as->getAtomicTypes() as $as_t) { $builder->addType($as_t); } } } $guide_method_storage_param_type = $builder->freeze(); unset($builder); if ($implementer_classlike_storage->template_extended_params) { self::transformTemplates($implementer_classlike_storage->template_extended_params, $guide_class_name, $guide_method_storage_param_type, $codebase); } $union_comparison_results = new TypeComparisonResult(); if (!UnionTypeComparator::isContainedBy($codebase, $guide_method_storage_param_type, $implementer_method_storage_param_type, !$guide_classlike_storage->user_defined, !$guide_classlike_storage->user_defined, $union_comparison_results)) { // is the declared return type more specific than the inferred one? if ($union_comparison_results->type_coerced) { if ($guide_classlike_storage->user_defined) { IssueBuffer::maybeAdd(new MoreSpecificImplementedParamType('Argument ' . ($i + 1) . ' of ' . $cased_implementer_method_id . ' has the more specific type \'' . $implementer_method_storage_param_type->getId() . '\', expecting \'' . $guide_method_storage_param_type->getId() . '\' as defined by ' . $cased_guide_method_id, $implementer_method_storage->params[$i]->location ?: $code_location), $suppressed_issues + $implementer_classlike_storage->suppressed_issues); } } else { if (UnionTypeComparator::isContainedBy($codebase, $implementer_method_storage_param_type, $guide_method_storage_param_type, !$guide_classlike_storage->user_defined, !$guide_classlike_storage->user_defined)) { IssueBuffer::maybeAdd(new MoreSpecificImplementedParamType('Argument ' . ($i + 1) . ' of ' . $cased_implementer_method_id . ' has the more specific type \'' . $implementer_method_storage_param_type->getId() . '\', expecting \'' . $guide_method_storage_param_type->getId() . '\' as defined by ' . $cased_guide_method_id, $implementer_method_storage->params[$i]->location ?: $code_location), $suppressed_issues + $implementer_classlike_storage->suppressed_issues); } else { IssueBuffer::maybeAdd(new ImplementedParamTypeMismatch('Argument ' . ($i + 1) . ' of ' . $cased_implementer_method_id . ' has wrong type \'' . $implementer_method_storage_param_type->getId() . '\', expecting \'' . $guide_method_storage_param_type->getId() . '\' as defined by ' . $cased_guide_method_id, $implementer_method_storage->params[$i]->location ?: $code_location), $suppressed_issues + $implementer_classlike_storage->suppressed_issues); } } } } /** * @param string[] $suppressed_issues */ private static function compareMethodSignatureReturnTypes(Codebase $codebase, ClassLikeStorage $guide_classlike_storage, ClassLikeStorage $implementer_classlike_storage, MethodStorage $guide_method_storage, MethodStorage $implementer_method_storage, Union $guide_signature_return_type, string $cased_guide_method_id, string $implementer_called_class_name, string $cased_implementer_method_id, CodeLocation $code_location, array $suppressed_issues) : void { $guide_signature_return_type = TypeExpander::expandUnion($codebase, $guide_signature_return_type, $guide_classlike_storage->is_trait && $guide_method_storage->abstract ? $implementer_classlike_storage->name : $guide_classlike_storage->name, $guide_classlike_storage->is_trait && $guide_method_storage->abstract || $guide_classlike_storage->final ? $implementer_classlike_storage->name : $guide_classlike_storage->name, $guide_classlike_storage->is_trait && $guide_method_storage->abstract ? $implementer_classlike_storage->parent_class : $guide_classlike_storage->parent_class, \true, \true, $implementer_method_storage->final); $implementer_signature_return_type = $implementer_method_storage->signature_return_type ? TypeExpander::expandUnion($codebase, $implementer_method_storage->signature_return_type, $implementer_classlike_storage->is_trait ? $implementer_called_class_name : $implementer_classlike_storage->name, $implementer_classlike_storage->is_trait ? $implementer_called_class_name : $implementer_classlike_storage->name, $implementer_classlike_storage->parent_class) : null; $is_contained_by = $codebase->analysis_php_version_id >= 70400 && $implementer_signature_return_type ? UnionTypeComparator::isContainedBy($codebase, $implementer_signature_return_type, $guide_signature_return_type) : UnionTypeComparator::isContainedByInPhp($implementer_signature_return_type, $guide_signature_return_type); if (!$is_contained_by) { if ($implementer_signature_return_type === null && array_filter($implementer_method_storage->attributes, static fn(AttributeStorage $s): bool => $s->fq_class_name === 'ReturnTypeWillChange')) { // no error if return type will change and no signature set at all } elseif ($codebase->analysis_php_version_id >= 80000 || $guide_classlike_storage->is_trait === $implementer_classlike_storage->is_trait || !in_array($guide_classlike_storage->name, $implementer_classlike_storage->used_traits) || $implementer_method_storage->defining_fqcln !== $implementer_classlike_storage->name || !$implementer_method_storage->abstract && !$guide_method_storage->abstract) { IssueBuffer::maybeAdd(new MethodSignatureMismatch('Method ' . $cased_implementer_method_id . ' with return type \'' . $implementer_signature_return_type . '\' is different to return type \'' . $guide_signature_return_type . '\' of inherited method ' . $cased_guide_method_id, $code_location), $suppressed_issues + $implementer_classlike_storage->suppressed_issues); } else { IssueBuffer::maybeAdd(new TraitMethodSignatureMismatch('Method ' . $cased_implementer_method_id . ' with return type \'' . $implementer_signature_return_type . '\' is different to return type \'' . $guide_signature_return_type . '\' of inherited method ' . $cased_guide_method_id, $code_location), $suppressed_issues + $implementer_classlike_storage->suppressed_issues); } } } /** * @param string[] $suppressed_issues */ private static function compareMethodDocblockReturnTypes(Codebase $codebase, ClassLikeStorage $guide_classlike_storage, ClassLikeStorage $implementer_classlike_storage, MethodStorage $implementer_method_storage, Union $guide_return_type, Union $implementer_return_type, string $cased_guide_method_id, string $implementer_called_class_name, ?MethodIdentifier $implementer_declaring_method_id, CodeLocation $code_location, array $suppressed_issues) : void { $implementer_method_storage_return_type = TypeExpander::expandUnion($codebase, $implementer_return_type, $implementer_classlike_storage->is_trait ? $implementer_called_class_name : $implementer_classlike_storage->name, $implementer_called_class_name, $implementer_classlike_storage->parent_class); $guide_method_storage_return_type = TypeExpander::expandUnion($codebase, $guide_return_type, $guide_classlike_storage->is_trait ? $implementer_classlike_storage->name : $guide_classlike_storage->name, $guide_classlike_storage->is_trait || $implementer_method_storage->final ? $implementer_called_class_name : $guide_classlike_storage->name, $guide_classlike_storage->parent_class, \true, \true, $implementer_method_storage->final); $guide_class_name = $guide_classlike_storage->name; if ($implementer_classlike_storage->template_extended_params) { self::transformTemplates($implementer_classlike_storage->template_extended_params, $guide_class_name, $guide_method_storage_return_type, $codebase); if ($implementer_method_storage->defining_fqcln) { self::transformTemplates($implementer_classlike_storage->template_extended_params, $implementer_method_storage->defining_fqcln, $implementer_method_storage_return_type, $codebase); } } if ($implementer_classlike_storage->is_trait) { $implementer_called_class_storage = $codebase->classlike_storage_provider->get($implementer_called_class_name); if ($implementer_called_class_storage->template_extended_params) { self::transformTemplates($implementer_called_class_storage->template_extended_params, $implementer_classlike_storage->name, $implementer_method_storage_return_type, $codebase); self::transformTemplates($implementer_called_class_storage->template_extended_params, $guide_class_name, $guide_method_storage_return_type, $codebase); } } // treat void as null when comparing against docblock implementer if ($implementer_method_storage_return_type->isVoid()) { $implementer_method_storage_return_type = Type::getNull(); } if ($guide_method_storage_return_type->isVoid()) { $guide_method_storage_return_type = Type::getNull(); } $union_comparison_results = new TypeComparisonResult(); if (!UnionTypeComparator::isContainedBy($codebase, $implementer_method_storage_return_type, $guide_method_storage_return_type, \false, \false, $union_comparison_results)) { // is the declared return type more specific than the inferred one? if ($union_comparison_results->type_coerced) { IssueBuffer::maybeAdd(new LessSpecificImplementedReturnType('The inherited return type \'' . $guide_method_storage_return_type->getId() . '\' for ' . $cased_guide_method_id . ' is more specific than the implemented ' . 'return type for ' . $implementer_declaring_method_id . ' \'' . $implementer_method_storage_return_type->getId() . '\'', $implementer_method_storage->return_type_location ?: $code_location), $suppressed_issues + $implementer_classlike_storage->suppressed_issues); } else { IssueBuffer::maybeAdd(new ImplementedReturnTypeMismatch('The inherited return type \'' . $guide_method_storage_return_type->getId() . '\' for ' . $cased_guide_method_id . ' is different to the implemented ' . 'return type for ' . $implementer_declaring_method_id . ' \'' . $implementer_method_storage_return_type->getId() . '\'', $implementer_method_storage->return_type_location ?: $code_location), $suppressed_issues + $implementer_classlike_storage->suppressed_issues); } } } /** * @param array> $template_extended_params */ private static function transformTemplates(array $template_extended_params, string $base_class_name, Union &$templated_type, Codebase $codebase) : void { if (isset($template_extended_params[$base_class_name])) { $map = $template_extended_params[$base_class_name]; $template_types = []; foreach ($map as $key => $mapped_type) { $new_bases = []; foreach ($mapped_type->getTemplateTypes() as $mapped_atomic_type) { if ($mapped_atomic_type->defining_class === $base_class_name) { continue; } $new_bases[] = $mapped_atomic_type->defining_class; } if ($new_bases) { foreach ($new_bases as $new_base_class_name) { self::transformTemplates($template_extended_params, $new_base_class_name, $mapped_type, $codebase); } } $template_types[$key][$base_class_name] = $mapped_type; } $template_result = new TemplateResult([], $template_types); $templated_type = TemplateInferredTypeReplacer::replace($templated_type, $template_result, $codebase); } } } label = $label; $this->line_from = $line_from; $this->line_to = $line_to; $this->file_name = $file_name; $this->file_path = $file_path; $this->snippet = $snippet; $this->from = $from; $this->to = $to; $this->snippet_from = $snippet_from; $this->column_from = $column_from; $this->column_to = $column_to; } } 'class', 2 => 'function', 4 => 'method', 8 => 'property', 16 => 'class constant', 32 => 'function/method parameter', 40 => 'promoted property']; // Copied from Attribute class since that class might not exist at runtime public const TARGET_CLASS = 1; public const TARGET_FUNCTION = 2; public const TARGET_METHOD = 4; public const TARGET_PROPERTY = 8; public const TARGET_CLASS_CONSTANT = 16; public const TARGET_PARAMETER = 32; public const TARGET_ALL = 63; public const IS_REPEATABLE = 64; /** * @param array $attribute_groups * @param key-of $target * @param array $suppressed_issues */ public static function analyze(\Psalm\Internal\Analyzer\SourceAnalyzer $source, Context $context, HasAttributesInterface $storage, array $attribute_groups, int $target, array $suppressed_issues) : void { $codebase = $source->getCodebase(); $appearing_non_repeatable_attributes = []; foreach (self::iterateAttributeNodes($attribute_groups) as $attribute) { if ($attribute->name instanceof FullyQualified) { $fq_attribute_name = (string) $attribute->name; } else { $fq_attribute_name = \Psalm\Internal\Analyzer\ClassLikeAnalyzer::getFQCLNFromNameObject($attribute->name, $source->getAliases()); } $attribute_name = (string) $attribute->name; $attribute_name_location = new CodeLocation($source, $attribute->name); $attribute_class_storage = $codebase->classlikes->classExists($fq_attribute_name) ? $codebase->classlike_storage_provider->get($fq_attribute_name) : null; $attribute_class_flags = self::getAttributeClassFlags($source, $attribute_name, $fq_attribute_name, $attribute_name_location, $attribute_class_storage, $suppressed_issues); self::analyzeAttributeConstruction($source, $context, $fq_attribute_name, $attribute, $suppressed_issues, $storage instanceof ClassLikeStorage ? $storage : null); if (($attribute_class_flags & self::IS_REPEATABLE) === 0) { // Not IS_REPEATABLE if (isset($appearing_non_repeatable_attributes[$fq_attribute_name])) { IssueBuffer::maybeAdd(new InvalidAttribute("Attribute {$attribute_name} is not repeatable", $attribute_name_location), $suppressed_issues); } $appearing_non_repeatable_attributes[$fq_attribute_name] = \true; } if (($attribute_class_flags & $target) === 0) { IssueBuffer::maybeAdd(new InvalidAttribute("Attribute {$attribute_name} cannot be used on a " . self::TARGET_DESCRIPTIONS[$target], $attribute_name_location), $suppressed_issues); } } } /** * @param array $suppressed_issues */ private static function analyzeAttributeConstruction(\Psalm\Internal\Analyzer\SourceAnalyzer $source, Context $context, string $fq_attribute_name, Attribute $attribute, array $suppressed_issues, ?ClassLikeStorage $classlike_storage = null) : void { $attribute_name_location = new CodeLocation($source, $attribute->name); if (\Psalm\Internal\Analyzer\ClassLikeAnalyzer::checkFullyQualifiedClassLikeName($source, $fq_attribute_name, $attribute_name_location, null, null, $suppressed_issues, new \Psalm\Internal\Analyzer\ClassLikeNameOptions(\false, \false, \false, \false, \false, \true)) === \false) { return; } if (strtolower($fq_attribute_name) === 'attribute' && $classlike_storage) { if ($classlike_storage->is_trait) { IssueBuffer::maybeAdd(new InvalidAttribute('Traits cannot act as attribute classes', $attribute_name_location), $suppressed_issues); } elseif ($classlike_storage->is_interface) { IssueBuffer::maybeAdd(new InvalidAttribute('Interfaces cannot act as attribute classes', $attribute_name_location), $suppressed_issues); } elseif ($classlike_storage->abstract) { IssueBuffer::maybeAdd(new InvalidAttribute('Abstract classes cannot act as attribute classes', $attribute_name_location), $suppressed_issues); } elseif (isset($classlike_storage->methods['__construct']) && $classlike_storage->methods['__construct']->visibility !== \Psalm\Internal\Analyzer\ClassLikeAnalyzer::VISIBILITY_PUBLIC) { IssueBuffer::maybeAdd(new InvalidAttribute('Classes with protected/private constructors cannot act as attribute classes', $attribute_name_location), $suppressed_issues); } elseif ($classlike_storage->is_enum) { IssueBuffer::maybeAdd(new InvalidAttribute('Enums cannot act as attribute classes', $attribute_name_location), $suppressed_issues); } } $statements_analyzer = new StatementsAnalyzer($source, new NodeDataProvider()); $statements_analyzer->addSuppressedIssues(array_values($suppressed_issues)); $had_returned = $context->has_returned; $context->has_returned = \false; IssueBuffer::startRecording(); $statements_analyzer->analyze( [new Expression(new New_($attribute->name, $attribute->args, $attribute->getAttributes()))], // Use a new Context for the Attribute attribute so that it can't access `self` strtolower($fq_attribute_name) === "attribute" ? new Context() : $context ); $context->has_returned = $had_returned; $issues = IssueBuffer::clearRecordingLevel(); IssueBuffer::stopRecording(); foreach ($issues as $issue) { if ($issue instanceof UndefinedClass && $issue->fq_classlike_name === $fq_attribute_name) { // Remove UndefinedClass for the attribute, since we already added UndefinedAttribute continue; } IssueBuffer::bubbleUp($issue); } } /** * @param array $suppressed_issues */ private static function getAttributeClassFlags(\Psalm\Internal\Analyzer\SourceAnalyzer $source, string $attribute_name, string $fq_attribute_name, CodeLocation $attribute_name_location, ?ClassLikeStorage $attribute_class_storage, array $suppressed_issues) : int { if (strtolower($fq_attribute_name) === "attribute") { // We override this here because we still want to analyze attributes // for PHP 7.4 when the Attribute class doesn't yet exist. return self::TARGET_CLASS; } if ($attribute_class_storage === null) { return self::TARGET_ALL; // Defaults to TARGET_ALL } foreach ($attribute_class_storage->attributes as $attribute_attribute) { if ($attribute_attribute->fq_class_name === 'Attribute') { if (!$attribute_attribute->args) { return self::TARGET_ALL; // Defaults to TARGET_ALL } $first_arg = reset($attribute_attribute->args); $first_arg_type = $first_arg->type; if ($first_arg_type instanceof UnresolvedConstantComponent) { $first_arg_type = new Union([ConstantTypeResolver::resolve($source->getCodebase()->classlikes, $first_arg_type, $source instanceof StatementsAnalyzer ? $source : null)]); } if (!$first_arg_type->isSingleIntLiteral()) { return self::TARGET_ALL; // Fall back to default if it's invalid } return $first_arg_type->getSingleIntLiteral()->value; } } IssueBuffer::maybeAdd(new InvalidAttribute("The class {$attribute_name} doesn't have the Attribute attribute", $attribute_name_location), $suppressed_issues); return self::TARGET_ALL; // Fall back to default if it's invalid } /** * @param iterable $attribute_groups * @return Generator */ private static function iterateAttributeNodes(iterable $attribute_groups) : Generator { foreach ($attribute_groups as $attribute_group) { foreach ($attribute_group->attrs as $attribute) { (yield $attribute); } } } /** * Analyze Reflection getAttributes method calls. * @param list $args */ public static function analyzeGetAttributes(StatementsAnalyzer $statements_analyzer, string $method_id, array $args) : void { if (count($args) !== 1) { // We skip this analysis if $flags is specified on getAttributes, since the only option // is ReflectionAttribute::IS_INSTANCEOF, which causes getAttributes to return children. // When returning children we don't want to limit this since a child could add a target. return; } switch ($method_id) { case "ReflectionClass::getattributes": $target = self::TARGET_CLASS; break; case "ReflectionFunction::getattributes": $target = self::TARGET_FUNCTION; break; case "ReflectionMethod::getattributes": $target = self::TARGET_METHOD; break; case "ReflectionProperty::getattributes": $target = self::TARGET_PROPERTY; break; case "ReflectionClassConstant::getattributes": $target = self::TARGET_CLASS_CONSTANT; break; case "ReflectionParameter::getattributes": $target = self::TARGET_PARAMETER; break; default: return; } $arg = $args[0]; if ($arg->name !== null) { for (; !empty($args) && ($arg->name->name ?? null) !== "name"; $arg = array_shift($args)) { } if ($arg->name->name ?? null !== "name") { // No named argument for "name" parameter return; } } $arg_type = $statements_analyzer->getNodeTypeProvider()->getType($arg->value); if ($arg_type === null || !$arg_type->isSingle() || !$arg_type->hasLiteralString()) { return; } $class_string = $arg_type->getSingleAtomic(); assert($class_string instanceof TLiteralString); $codebase = $statements_analyzer->getCodebase(); if (!$codebase->classExists($class_string->value)) { return; } $class_storage = $codebase->classlike_storage_provider->get($class_string->value); $arg_location = new CodeLocation($statements_analyzer, $arg); $class_attribute_target = self::getAttributeClassFlags($statements_analyzer, $class_string->value, $class_string->value, $arg_location, $class_storage, $statements_analyzer->getSuppressedIssues()); if (($class_attribute_target & $target) === 0) { IssueBuffer::maybeAdd(new InvalidAttribute("Attribute {$class_string->value} cannot be used on a " . self::TARGET_DESCRIPTIONS[$target], $arg_location), $statements_analyzer->getSuppressedIssues()); } } } 'int', 'string' => 'string', 'float' => 'float', 'bool' => 'bool', 'false' => 'false', 'object' => 'object', 'never' => 'never', 'callable' => 'callable', 'array' => 'array', 'iterable' => 'iterable', 'null' => 'null', 'mixed' => 'mixed']; public const GETTYPE_TYPES = ['boolean' => \true, 'integer' => \true, 'double' => \true, 'string' => \true, 'array' => \true, 'object' => \true, 'resource' => \true, 'resource (closed)' => \true, 'NULL' => \true, 'unknown type' => \true]; protected PhpParser\Node\Stmt\ClassLike $class; public \Psalm\Internal\Analyzer\FileAnalyzer $file_analyzer; protected string $fq_class_name; /** * The parent class */ protected ?string $parent_fq_class_name = null; protected ClassLikeStorage $storage; public function __construct(PhpParser\Node\Stmt\ClassLike $class, \Psalm\Internal\Analyzer\SourceAnalyzer $source, string $fq_class_name) { $this->class = $class; $this->source = $source; $this->file_analyzer = $source->getFileAnalyzer(); $this->fq_class_name = $fq_class_name; $codebase = $source->getCodebase(); $this->storage = $codebase->classlike_storage_provider->get($fq_class_name); } public function __destruct() { unset($this->source); unset($this->file_analyzer); } public function getMethodMutations(string $method_name, Context $context) : void { $project_analyzer = $this->getFileAnalyzer()->project_analyzer; $codebase = $project_analyzer->getCodebase(); foreach ($this->class->stmts as $stmt) { if ($stmt instanceof PhpParser\Node\Stmt\ClassMethod && strtolower($stmt->name->name) === strtolower($method_name)) { $method_analyzer = new \Psalm\Internal\Analyzer\MethodAnalyzer($stmt, $this); $method_analyzer->analyze($context, new NodeDataProvider(), null, \true); $context->clauses = []; } elseif ($stmt instanceof PhpParser\Node\Stmt\TraitUse) { foreach ($stmt->traits as $trait) { $fq_trait_name = self::getFQCLNFromNameObject($trait, $this->source->getAliases()); $trait_file_analyzer = $project_analyzer->getFileAnalyzerForClassLike($fq_trait_name); $trait_node = $codebase->classlikes->getTraitNode($fq_trait_name); $trait_storage = $codebase->classlike_storage_provider->get($fq_trait_name); $trait_aliases = $trait_storage->aliases; if ($trait_aliases === null) { continue; } $trait_analyzer = new \Psalm\Internal\Analyzer\TraitAnalyzer($trait_node, $trait_file_analyzer, $fq_trait_name, $trait_aliases); foreach ($trait_node->stmts as $trait_stmt) { if ($trait_stmt instanceof PhpParser\Node\Stmt\ClassMethod && strtolower($trait_stmt->name->name) === strtolower($method_name)) { $method_analyzer = new \Psalm\Internal\Analyzer\MethodAnalyzer($trait_stmt, $trait_analyzer); $actual_method_id = $method_analyzer->getMethodId(); if ($context->self && $context->self !== $this->fq_class_name) { $analyzed_method_id = $method_analyzer->getMethodId($context->self); $declaring_method_id = $codebase->methods->getDeclaringMethodId($analyzed_method_id); if ((string) $actual_method_id !== (string) $declaring_method_id) { break; } } $method_analyzer->analyze($context, new NodeDataProvider(), null, \true); } } $trait_file_analyzer->clearSourceBeforeDestruction(); } } } } public function getFunctionLikeAnalyzer(string $method_name) : ?\Psalm\Internal\Analyzer\MethodAnalyzer { foreach ($this->class->stmts as $stmt) { if ($stmt instanceof PhpParser\Node\Stmt\ClassMethod && strtolower($stmt->name->name) === strtolower($method_name)) { return new \Psalm\Internal\Analyzer\MethodAnalyzer($stmt, $this); } } return null; } /** * @param array $suppressed_issues */ public static function checkFullyQualifiedClassLikeName(StatementsSource $statements_source, string $fq_class_name, CodeLocation $code_location, ?string $calling_fq_class_name, ?string $calling_method_id, array $suppressed_issues, ?\Psalm\Internal\Analyzer\ClassLikeNameOptions $options = null, bool $check_classes = \true) : ?bool { if ($options === null) { $options = new \Psalm\Internal\Analyzer\ClassLikeNameOptions(); } $codebase = $statements_source->getCodebase(); if ($fq_class_name === '') { if (IssueBuffer::accepts(new UndefinedClass('Class or interface does not exist', $code_location, 'empty string'), $suppressed_issues)) { return \false; } return null; } $fq_class_name = preg_replace('/^\\\\/', '', $fq_class_name, 1); if (in_array($fq_class_name, ['callable', 'iterable', 'self', 'static', 'parent'], \true)) { return \true; } if (preg_match('/(^|\\\\)(int|float|bool|string|void|null|false|true|object|mixed)$/i', $fq_class_name) || strtolower($fq_class_name) === 'resource') { $class_name_parts = explode('\\', $fq_class_name); $class_name = array_pop($class_name_parts); IssueBuffer::maybeAdd(new ReservedWord($class_name . ' is a reserved word', $code_location, $class_name), $suppressed_issues); return null; } $class_exists = $codebase->classlikes->classExists($fq_class_name, !$options->inferred ? $code_location : null, $calling_fq_class_name, $calling_method_id); $interface_exists = $codebase->classlikes->interfaceExists($fq_class_name, !$options->inferred ? $code_location : null, $calling_fq_class_name, $calling_method_id); $enum_exists = $codebase->classlikes->enumExists($fq_class_name, !$options->inferred ? $code_location : null, $calling_fq_class_name, $calling_method_id); if (!$class_exists && !($interface_exists && $options->allow_interface) && !($enum_exists && $options->allow_enum)) { if (!$check_classes) { return null; } if (!$options->allow_trait || !$codebase->classlikes->traitExists($fq_class_name, $code_location)) { if ($options->from_docblock) { if (IssueBuffer::accepts(new UndefinedDocblockClass('Docblock-defined class, interface or enum named ' . $fq_class_name . ' does not exist', $code_location, $fq_class_name), $suppressed_issues)) { return \false; } } elseif ($options->from_attribute) { if (IssueBuffer::accepts(new UndefinedAttributeClass('Attribute class ' . $fq_class_name . ' does not exist', $code_location, $fq_class_name), $suppressed_issues)) { return \false; } } else { if (IssueBuffer::accepts(new UndefinedClass('Class, interface or enum named ' . $fq_class_name . ' does not exist', $code_location, $fq_class_name), $suppressed_issues)) { return \false; } } } return null; } $aliased_name = $codebase->classlikes->getUnAliasedName($fq_class_name); try { $class_storage = $codebase->classlike_storage_provider->get($aliased_name); } catch (InvalidArgumentException $e) { if (!$options->inferred) { throw $e; } return null; } foreach ($class_storage->invalid_dependencies as $dependency_class_name => $_) { // if the implemented/extended class is stubbed, it may not yet have // been hydrated if ($codebase->classlike_storage_provider->has($dependency_class_name)) { continue; } if (IssueBuffer::accepts(new MissingDependency($fq_class_name . ' depends on class or interface ' . $dependency_class_name . ' that does not exist', $code_location, $fq_class_name), $suppressed_issues)) { return \false; } } if (!$options->inferred) { if ($class_exists && !$codebase->classHasCorrectCasing($fq_class_name) || $interface_exists && !$codebase->interfaceHasCorrectCasing($fq_class_name) || $enum_exists && !$codebase->classlikes->enumHasCorrectCasing($fq_class_name)) { IssueBuffer::maybeAdd(new InvalidClass('Class, interface or enum ' . $fq_class_name . ' has wrong casing', $code_location, $fq_class_name), $suppressed_issues); } } if (!$options->inferred) { $event = new AfterClassLikeExistenceCheckEvent($fq_class_name, $code_location, $statements_source, $codebase, []); $codebase->config->eventDispatcher->dispatchAfterClassLikeExistenceCheck($event); $file_manipulations = $event->getFileReplacements(); if ($file_manipulations) { FileManipulationBuffer::add($code_location->file_path, $file_manipulations); } } return \true; } /** * Gets the fully-qualified class name from a Name object */ public static function getFQCLNFromNameObject(PhpParser\Node\Name $class_name, Aliases $aliases) : string { /** @var string|null */ $resolved_name = $class_name->getAttribute('resolvedName'); if ($resolved_name) { return $resolved_name; } if ($class_name instanceof PhpParser\Node\Name\FullyQualified) { return $class_name->toString(); } if (in_array($class_name->getFirst(), ['self', 'static', 'parent'], \true)) { return $class_name->getFirst(); } return Type::getFQCLNFromString($class_name->toString(), $aliases); } /** * @psalm-mutation-free * @return array */ public function getAliasedClassesFlipped() : array { if ($this->source instanceof \Psalm\Internal\Analyzer\NamespaceAnalyzer || $this->source instanceof \Psalm\Internal\Analyzer\FileAnalyzer) { return $this->source->getAliasedClassesFlipped(); } return []; } /** * @psalm-mutation-free * @return array */ public function getAliasedClassesFlippedReplaceable() : array { if ($this->source instanceof \Psalm\Internal\Analyzer\NamespaceAnalyzer || $this->source instanceof \Psalm\Internal\Analyzer\FileAnalyzer) { return $this->source->getAliasedClassesFlippedReplaceable(); } return []; } /** @psalm-mutation-free */ public function getFQCLN() : string { return $this->fq_class_name; } /** @psalm-mutation-free */ public function getClassName() : ?string { return $this->class->name->name ?? null; } /** * @psalm-mutation-free * @return array>|null */ public function getTemplateTypeMap() : ?array { return $this->storage->template_types; } /** @psalm-mutation-free */ public function getParentFQCLN() : ?string { return $this->parent_fq_class_name; } /** @psalm-mutation-free */ public function isStatic() : bool { return \false; } /** * Gets the Psalm type from a particular value * * @param mixed $value */ public static function getTypeFromValue($value) : Union { switch (gettype($value)) { case 'boolean': if ($value) { return Type::getTrue(); } return Type::getFalse(); case 'integer': return Type::getInt(\false, $value); case 'double': return Type::getFloat($value); case 'string': return Type::getString($value); case 'array': return Type::getArray(); case 'NULL': return Type::getNull(); default: return Type::getMixed(); } } /** * @param string[] $suppressed_issues */ public static function checkPropertyVisibility(string $property_id, Context $context, \Psalm\Internal\Analyzer\SourceAnalyzer $source, CodeLocation $code_location, array $suppressed_issues, bool $emit_issues = \true) : ?bool { [$fq_class_name, $property_name] = explode('::$', $property_id); $codebase = $source->getCodebase(); if ($codebase->properties->property_visibility_provider->has($fq_class_name)) { $property_visible = $codebase->properties->property_visibility_provider->isPropertyVisible($source, $fq_class_name, $property_name, \true, $context, $code_location); if ($property_visible !== null) { return $property_visible; } } $declaring_property_class = $codebase->properties->getDeclaringClassForProperty($property_id, \true); $appearing_property_class = $codebase->properties->getAppearingClassForProperty($property_id, \true); if (!$declaring_property_class || !$appearing_property_class) { throw new UnexpectedValueException('Appearing/Declaring classes are not defined for ' . $property_id); } // if the calling class is the same, we know the property exists, so it must be visible if ($appearing_property_class === $context->self) { return $emit_issues ? null : \true; } if ($source->getSource() instanceof \Psalm\Internal\Analyzer\TraitAnalyzer && strtolower($declaring_property_class) === strtolower((string) $source->getFQCLN())) { return $emit_issues ? null : \true; } $class_storage = $codebase->classlike_storage_provider->get($declaring_property_class); if (!isset($class_storage->properties[$property_name])) { throw new UnexpectedValueException('$storage should not be null for ' . $property_id); } $storage = $class_storage->properties[$property_name]; switch ($storage->visibility) { case self::VISIBILITY_PUBLIC: return $emit_issues ? null : \true; case self::VISIBILITY_PRIVATE: if ($emit_issues) { IssueBuffer::maybeAdd(new InaccessibleProperty('Cannot access private property ' . $property_id . ' from context ' . $context->self, $code_location), $suppressed_issues); } return null; case self::VISIBILITY_PROTECTED: if (!$context->self) { if ($emit_issues) { IssueBuffer::maybeAdd(new InaccessibleProperty('Cannot access protected property ' . $property_id, $code_location), $suppressed_issues); } return null; } if ($codebase->classExtends($appearing_property_class, $context->self)) { return $emit_issues ? null : \true; } if (!$codebase->classExtends($context->self, $appearing_property_class)) { if ($emit_issues) { IssueBuffer::maybeAdd(new InaccessibleProperty('Cannot access protected property ' . $property_id . ' from context ' . $context->self, $code_location), $suppressed_issues); } return null; } } return $emit_issues ? null : \true; } protected function checkTemplateParams(Codebase $codebase, ClassLikeStorage $storage, ClassLikeStorage $parent_storage, CodeLocation $code_location, int $given_param_count) : void { $expected_param_count = $parent_storage->template_types === null ? 0 : count($parent_storage->template_types); if ($expected_param_count > $given_param_count) { IssueBuffer::maybeAdd(new MissingTemplateParam($storage->name . ' has missing template params when extending ' . $parent_storage->name . ', expecting ' . $expected_param_count, $code_location), $storage->suppressed_issues + $this->getSuppressedIssues()); } elseif ($expected_param_count < $given_param_count) { IssueBuffer::maybeAdd(new TooManyTemplateParams($storage->name . ' has too many template params when extending ' . $parent_storage->name . ', expecting ' . $expected_param_count, $code_location), $storage->suppressed_issues + $this->getSuppressedIssues()); } $storage_param_count = $storage->template_types ? count($storage->template_types) : 0; if ($parent_storage->enforce_template_inheritance && $expected_param_count !== $storage_param_count) { if ($expected_param_count > $storage_param_count) { IssueBuffer::maybeAdd(new MissingTemplateParam($storage->name . ' requires the same number of template params as ' . $parent_storage->name . ' but saw ' . $storage_param_count, $code_location), $storage->suppressed_issues + $this->getSuppressedIssues()); } else { IssueBuffer::maybeAdd(new TooManyTemplateParams($storage->name . ' requires the same number of template params as ' . $parent_storage->name . ' but saw ' . $storage_param_count, $code_location), $storage->suppressed_issues + $this->getSuppressedIssues()); } } if ($parent_storage->template_types && $storage->template_extended_params) { $i = 0; $previous_extended = []; foreach ($parent_storage->template_types as $template_name => $type_map) { // declares the variables foreach ($type_map as $declaring_class => $template_type) { } if (isset($storage->template_extended_params[$parent_storage->name][$template_name])) { $extended_type = $storage->template_extended_params[$parent_storage->name][$template_name]; if (isset($parent_storage->template_covariants[$i]) && !$parent_storage->template_covariants[$i]) { foreach ($extended_type->getAtomicTypes() as $t) { if ($t instanceof TTemplateParam && $storage->template_types && $storage->template_covariants && ($local_offset = array_search($t->param_name, array_keys($storage->template_types), \true)) !== \false && !empty($storage->template_covariants[$local_offset])) { IssueBuffer::maybeAdd(new InvalidTemplateParam('Cannot extend an invariant template param ' . $template_name . ' into a covariant context', $code_location), $storage->suppressed_issues + $this->getSuppressedIssues()); } } } if ($parent_storage->enforce_template_inheritance) { foreach ($extended_type->getAtomicTypes() as $t) { if (!$t instanceof TTemplateParam || !isset($storage->template_types[$t->param_name])) { IssueBuffer::maybeAdd(new InvalidTemplateParam('Cannot extend a strictly-enforced parent template param ' . $template_name . ' with a non-template type', $code_location), $storage->suppressed_issues + $this->getSuppressedIssues()); } elseif ($storage->template_types[$t->param_name][$storage->name]->getId() !== $template_type->getId()) { IssueBuffer::maybeAdd(new InvalidTemplateParam('Cannot extend a strictly-enforced parent template param ' . $template_name . ' with constraint ' . $template_type->getId() . ' with a child template param ' . $t->param_name . ' with different constraint ' . $storage->template_types[$t->param_name][$storage->name]->getId(), $code_location), $storage->suppressed_issues + $this->getSuppressedIssues()); } } } if (!$template_type->isMixed()) { $template_result = new TemplateResult($previous_extended ?: [], []); $template_type_copy = TemplateStandinTypeReplacer::replace($template_type, $template_result, $codebase, null, $extended_type, null, null); if (!UnionTypeComparator::isContainedBy($codebase, $extended_type, $template_type_copy)) { IssueBuffer::maybeAdd(new InvalidTemplateParam('Extended template param ' . $template_name . ' expects type ' . $template_type_copy->getId() . ', type ' . $extended_type->getId() . ' given', $code_location), $storage->suppressed_issues + $this->getSuppressedIssues()); } else { $previous_extended[$template_name] = [$declaring_class => $extended_type]; } } else { $previous_extended[$template_name] = [$declaring_class => $extended_type]; } } $i++; } } } /** * @return array */ public static function getClassesForFile(Codebase $codebase, string $file_path) : array { try { return $codebase->file_storage_provider->get($file_path)->classlikes_in_file; } catch (InvalidArgumentException $e) { return []; } } public function getFileAnalyzer() : \Psalm\Internal\Analyzer\FileAnalyzer { return $this->file_analyzer; } } */ private array $issues_to_fix = []; public bool $dry_run = \false; public bool $full_run = \false; public bool $only_replace_php_types_with_non_docblock_types = \false; public ?int $onchange_line_limit = null; public bool $provide_completion = \false; /** * @var list */ public array $check_paths_files = []; /** * @var array */ private array $project_files = []; /** * @var array */ private array $extra_files = []; /** * @var array */ private array $to_refactor = []; public ?ReportOptions $stdout_report_options = null; /** * @var array */ public array $generated_report_options; /** * @var array> */ private const SUPPORTED_ISSUES_TO_FIX = [InvalidFalsableReturnType::class, InvalidNullableReturnType::class, InvalidReturnType::class, LessSpecificReturnType::class, MismatchingDocblockParamType::class, MismatchingDocblockReturnType::class, MissingClosureReturnType::class, MissingParamType::class, MissingPropertyType::class, MissingReturnType::class, ParamNameMismatch::class, PossiblyUndefinedGlobalVariable::class, PossiblyUndefinedVariable::class, PossiblyUnusedMethod::class, PossiblyUnusedProperty::class, RedundantCast::class, RedundantCastGivenDocblockType::class, UnusedMethod::class, UnusedProperty::class, UnusedVariable::class, UnnecessaryVarAnnotation::class]; private const PHP_VERSION_REGEX = '^(0|[1-9]\\d*)\\.(0|[1-9]\\d*)(?:\\..*)?$'; private const PHP_SUPPORTED_VERSIONS_REGEX = '^(5\\.[456]|7\\.[01234]|8\\.[0123])(\\..*)?$'; /** * @param array $generated_report_options */ public function __construct(Config $config, Providers $providers, ?ReportOptions $stdout_report_options = null, array $generated_report_options = [], int $threads = 1, ?Progress $progress = null, ?Codebase $codebase = null) { if ($progress === null) { $progress = new VoidProgress(); } if ($codebase === null) { $codebase = new Codebase($config, $providers, $progress); } $this->parser_cache_provider = $providers->parser_cache_provider; $this->project_cache_provider = $providers->project_cache_provider; $this->file_provider = $providers->file_provider; $this->classlike_storage_provider = $providers->classlike_storage_provider; $this->file_reference_provider = $providers->file_reference_provider; $this->progress = $progress; $this->threads = $threads; $this->config = $config; $this->clearCacheDirectoryIfConfigOrComposerLockfileChanged(); $this->codebase = $codebase; $this->stdout_report_options = $stdout_report_options; $this->generated_report_options = $generated_report_options; $this->config->processPluginFileExtensions($this); $file_extensions = $this->config->getFileExtensions(); foreach ($this->config->getProjectDirectories() as $dir_name) { $file_paths = $this->file_provider->getFilesInDir($dir_name, $file_extensions, [$this->config, 'isInProjectDirs']); foreach ($file_paths as $file_path) { $this->addProjectFile($file_path); } } foreach ($this->config->getExtraDirectories() as $dir_name) { $file_paths = $this->file_provider->getFilesInDir($dir_name, $file_extensions, [$this->config, 'isInExtraDirs']); foreach ($file_paths as $file_path) { $this->addExtraFile($file_path); } } foreach ($this->config->getProjectFiles() as $file_path) { $this->addProjectFile($file_path); } self::$instance = $this; } private function clearCacheDirectoryIfConfigOrComposerLockfileChanged() : void { $cache_directory = $this->config->getCacheDirectory(); if ($cache_directory === null) { return; } if ($this->project_cache_provider && $this->project_cache_provider->hasLockfileChanged()) { // we only clear the cache if it actually exists // if it's not populated yet, we don't clear anything but populate the cache instead clearstatcache(\true, $cache_directory); if (is_dir($cache_directory)) { $this->progress->debug('Composer lockfile change detected, clearing cache directory ' . $cache_directory . "\n"); Config::removeCacheDirectory($cache_directory); } if ($this->file_reference_provider->cache) { $this->file_reference_provider->cache->setConfigHashCache(); } $this->project_cache_provider->updateComposerLockHash(); } elseif ($this->file_reference_provider->cache && $this->file_reference_provider->cache->hasConfigChanged()) { clearstatcache(\true, $cache_directory); if (is_dir($cache_directory)) { $this->progress->debug('Config change detected, clearing cache directory ' . $cache_directory . "\n"); Config::removeCacheDirectory($cache_directory); } $this->file_reference_provider->cache->setConfigHashCache(); if ($this->project_cache_provider) { $this->project_cache_provider->updateComposerLockHash(); } } } /** * @param array $report_file_paths * @return list */ public static function getFileReportOptions(array $report_file_paths, bool $show_info = \true) : array { $report_options = []; $mapping = Report::getMapping(); foreach ($report_file_paths as $report_file_path) { foreach ($mapping as $extension => $type) { if (substr($report_file_path, -strlen($extension)) === $extension) { $o = new ReportOptions(); $o->format = $type; $o->show_info = $show_info; $o->output_path = $report_file_path; $o->use_color = \false; $report_options[] = $o; continue 2; } } throw new UnexpectedValueException('Unknown report format ' . $report_file_path); } return $report_options; } private function visitAutoloadFiles() : void { $start_time = microtime(\true); $this->config->visitComposerAutoloadFiles($this, $this->progress); $now_time = microtime(\true); $this->progress->debug('Visiting autoload files took ' . number_format($now_time - $start_time, 3) . 's' . "\n"); } public function serverMode(LanguageServer $server) : void { $server->logInfo("Initializing: Visiting Autoload Files..."); $this->visitAutoloadFiles(); $this->codebase->diff_methods = \true; $server->logInfo("Initializing: Loading Reference Cache..."); $this->file_reference_provider->loadReferenceCache(); $this->codebase->enterServerMode(); $cpu_count = self::getCpuCount(); // let's not go crazy $usable_cpus = $cpu_count - 2; if ($usable_cpus > 1) { $this->threads = $usable_cpus; } $server->logInfo("Initializing: Initialize Plugins..."); $this->config->initializePlugins($this); foreach ($this->config->getProjectDirectories() as $dir_name) { $this->checkDirWithConfig($dir_name, $this->config); } } /** @psalm-mutation-free */ public static function getInstance() : \Psalm\Internal\Analyzer\ProjectAnalyzer { /** @psalm-suppress ImpureStaticProperty */ return self::$instance; } /** @psalm-mutation-free */ public function canReportIssues(string $file_path) : bool { return isset($this->project_files[$file_path]); } private function generatePHPVersionMessage() : string { $codebase = $this->codebase; switch ($codebase->php_version_source) { case 'cli': $source = '(set by CLI argument)'; break; case 'config': $source = '(set by config file)'; break; case 'composer': $source = '(inferred from composer.json)'; break; case 'tests': $source = '(set by tests)'; break; case 'runtime': $source = '(inferred from current PHP version)'; break; } $unsupported_php_extensions = array_diff(array_keys($codebase->config->php_extensions_not_supported), $codebase->config->php_extensions_supported_by_psalm_callmaps); $message = sprintf("Target PHP version: %d.%d %s", $codebase->getMajorAnalysisPhpVersion(), $codebase->getMinorAnalysisPhpVersion(), $source); $enabled_extensions_names = array_keys(array_filter($codebase->config->php_extensions)); if (count($enabled_extensions_names) > 0) { $message .= ' Enabled extensions: ' . implode(', ', $enabled_extensions_names); } if (count($unsupported_php_extensions) > 0) { $message .= ' (unsupported extensions: ' . implode(', ', $unsupported_php_extensions) . ')'; } return "{$message}.\n"; } public function check(string $base_dir, bool $is_diff = \false) : void { $start_checks = (int) microtime(\true); if (!$base_dir) { throw new InvalidArgumentException('Cannot work with empty base_dir'); } $diff_files = null; $deleted_files = null; $this->full_run = \true; $reference_cache = $this->file_reference_provider->loadReferenceCache(\true); $this->codebase->diff_methods = $is_diff; if ($is_diff && $reference_cache && $this->project_cache_provider && $this->project_cache_provider->canDiffFiles()) { $deleted_files = $this->file_reference_provider->getDeletedReferencedFiles(); $diff_files = [...$deleted_files, ...$this->getDiffFiles()]; } $this->progress->write($this->generatePHPVersionMessage()); $this->progress->startScanningFiles(); $diff_no_files = \false; if ($diff_files === null || $deleted_files === null || count($diff_files) > 200) { $this->config->visitPreloadedStubFiles($this->codebase, $this->progress); $this->visitAutoloadFiles(); $this->codebase->scanner->addFilesToShallowScan($this->extra_files); $this->codebase->scanner->addFilesToDeepScan($this->project_files); $this->codebase->analyzer->addFilesToAnalyze($this->project_files); $this->config->initializePlugins($this); $this->codebase->scanFiles($this->threads); $this->codebase->infer_types_from_usage = \true; } else { $this->progress->debug(count($diff_files) . ' changed files: ' . "\n"); $this->progress->debug(' ' . implode("\n ", $diff_files) . "\n"); $this->codebase->analyzer->addFilesToShowResults($this->project_files); if ($diff_files) { $file_list = $this->getReferencedFilesFromDiff($diff_files); // strip out deleted files $file_list = array_diff($file_list, $deleted_files); if ($file_list) { $this->config->visitPreloadedStubFiles($this->codebase, $this->progress); $this->visitAutoloadFiles(); $this->checkDiffFilesWithConfig($this->config, $file_list); $this->config->initializePlugins($this); $this->codebase->scanFiles($this->threads); } else { $diff_no_files = \true; } } else { $diff_no_files = \true; } } if (!$diff_no_files) { $this->config->visitStubFiles($this->codebase, $this->progress); $event = new AfterCodebasePopulatedEvent($this->codebase); $this->config->eventDispatcher->dispatchAfterCodebasePopulated($event); } $this->progress->startAnalyzingFiles(); $this->codebase->analyzer->analyzeFiles($this, $this->threads, $this->codebase->alter_code, \true); if ($this->parser_cache_provider && !$is_diff) { $removed_parser_files = $this->parser_cache_provider->deleteOldParserCaches($start_checks); if ($removed_parser_files) { $this->progress->debug('Removed ' . $removed_parser_files . ' old parser caches' . "\n"); } } } public function consolidateAnalyzedData() : void { $this->codebase->classlikes->consolidateAnalyzedData($this->codebase->methods, $this->progress, (bool) $this->codebase->find_unused_code); } public function trackTaintedInputs() : void { $this->codebase->taint_flow_graph = new TaintFlowGraph(); } public function trackUnusedSuppressions() : void { $this->codebase->track_unused_suppressions = \true; } public function interpretRefactors() : void { if (!$this->codebase->alter_code) { throw new UnexpectedValueException('Should not be checking references'); } // interpret wildcards foreach ($this->to_refactor as $source => $destination) { if (($source_pos = strpos($source, '*')) && ($destination_pos = strpos($destination, '*')) && $source_pos === strlen($source) - 1 && $destination_pos === strlen($destination) - 1) { foreach ($this->codebase->classlike_storage_provider->getAll() as $class_storage) { if (strpos($source, substr($class_storage->name, 0, $source_pos)) === 0) { $this->to_refactor[$class_storage->name] = substr($destination, 0, -1) . substr($class_storage->name, $source_pos); } } unset($this->to_refactor[$source]); } } foreach ($this->to_refactor as $source => $destination) { $source_parts = explode('::', $source); $destination_parts = explode('::', $destination); if (!$this->codebase->classlikes->hasFullyQualifiedClassName($source_parts[0])) { throw new RefactorException('Source class ' . $source_parts[0] . ' doesn’t exist'); } if (count($source_parts) === 1 && count($destination_parts) === 1) { if ($this->codebase->classlikes->hasFullyQualifiedClassName($destination_parts[0])) { throw new RefactorException('Destination class ' . $destination_parts[0] . ' already exists'); } $source_class_storage = $this->codebase->classlike_storage_provider->get($source_parts[0]); $destination_parts = explode('\\', $destination, -1); $destination_ns = implode('\\', $destination_parts); $this->codebase->classes_to_move[strtolower($source)] = $destination; $destination_class_storage = $this->codebase->classlike_storage_provider->create($destination); $destination_class_storage->name = $destination; if ($source_class_storage->aliases) { $destination_class_storage->aliases = clone $source_class_storage->aliases; $destination_class_storage->aliases->namespace = $destination_ns; } $destination_class_storage->location = $source_class_storage->location; $destination_class_storage->stmt_location = $source_class_storage->stmt_location; $destination_class_storage->populated = \true; $this->codebase->class_transforms[strtolower($source)] = $destination; continue; } $source_method_id = new MethodIdentifier($source_parts[0], strtolower($source_parts[1])); if ($this->codebase->methods->methodExists($source_method_id)) { if ($this->codebase->methods->methodExists(new MethodIdentifier($destination_parts[0], strtolower($destination_parts[1])))) { throw new RefactorException('Destination method ' . $destination . ' already exists'); } if (!$this->codebase->classlikes->classExists($destination_parts[0])) { throw new RefactorException('Destination class ' . $destination_parts[0] . ' doesn’t exist'); } $source_lc = strtolower($source); if (strtolower($source_parts[0]) !== strtolower($destination_parts[0])) { $source_method_storage = $this->codebase->methods->getStorage($source_method_id); $destination_class_storage = $this->codebase->classlike_storage_provider->get($destination_parts[0]); if (!$source_method_storage->is_static && !isset($destination_class_storage->parent_classes[strtolower($source_method_id->fq_class_name)])) { throw new RefactorException('Cannot move non-static method ' . $source . ' into unrelated class ' . $destination_parts[0]); } $this->codebase->methods_to_move[$source_lc] = $destination; } else { $this->codebase->methods_to_rename[$source_lc] = $destination_parts[1]; } $this->codebase->call_transforms[$source_lc . '\\((.*\\))'] = $destination . '($1)'; continue; } if ($source_parts[1][0] === '$') { if ($destination_parts[1][0] !== '$') { throw new RefactorException('Destination property must be of the form Foo::$bar'); } if (!$this->codebase->properties->propertyExists($source, \true)) { throw new RefactorException('Property ' . $source . ' does not exist'); } if ($this->codebase->properties->propertyExists($destination, \true)) { throw new RefactorException('Destination property ' . $destination . ' already exists'); } if (!$this->codebase->classlikes->classExists($destination_parts[0])) { throw new RefactorException('Destination class ' . $destination_parts[0] . ' doesn’t exist'); } $source_id = strtolower($source_parts[0]) . '::' . $source_parts[1]; if (strtolower($source_parts[0]) !== strtolower($destination_parts[0])) { $source_storage = $this->codebase->properties->getStorage($source); if (!$source_storage->is_static) { throw new RefactorException('Cannot move non-static property ' . $source); } $this->codebase->properties_to_move[$source_id] = $destination; } else { $this->codebase->properties_to_rename[$source_id] = substr($destination_parts[1], 1); } $this->codebase->property_transforms[$source_id] = $destination; continue; } $source_class_constants = $this->codebase->classlikes->getConstantsForClass($source_parts[0], ReflectionProperty::IS_PRIVATE); if (isset($source_class_constants[$source_parts[1]])) { if (!$this->codebase->classlikes->hasFullyQualifiedClassName($destination_parts[0])) { throw new RefactorException('Destination class ' . $destination_parts[0] . ' doesn’t exist'); } $destination_class_constants = $this->codebase->classlikes->getConstantsForClass($destination_parts[0], ReflectionProperty::IS_PRIVATE); if (isset($destination_class_constants[$destination_parts[1]])) { throw new RefactorException('Destination constant ' . $destination . ' already exists'); } $source_id = strtolower($source_parts[0]) . '::' . $source_parts[1]; if (strtolower($source_parts[0]) !== strtolower($destination_parts[0])) { $this->codebase->class_constants_to_move[$source_id] = $destination; } else { $this->codebase->class_constants_to_rename[$source_id] = $destination_parts[1]; } $this->codebase->class_constant_transforms[$source_id] = $destination; continue; } throw new RefactorException('Psalm cannot locate ' . $source); } } public function prepareMigration() : void { if (!$this->codebase->alter_code) { throw new UnexpectedValueException('Should not be checking references'); } $this->codebase->classlikes->moveMethods($this->codebase->methods, $this->progress); $this->codebase->classlikes->moveProperties($this->codebase->properties, $this->progress); $this->codebase->classlikes->moveClassConstants($this->progress); } public function migrateCode() : void { if (!$this->codebase->alter_code) { throw new UnexpectedValueException('Should not be checking references'); } $migration_manipulations = FileManipulationBuffer::getMigrationManipulations($this->codebase->file_provider); if ($migration_manipulations) { foreach ($migration_manipulations as $file_path => $file_manipulations) { usort($file_manipulations, static function (FileManipulation $a, FileManipulation $b) : int { if ($a->start === $b->start) { if ($b->end === $a->end) { return $b->insertion_text > $a->insertion_text ? 1 : -1; } return $b->end > $a->end ? 1 : -1; } return $b->start > $a->start ? 1 : -1; }); $existing_contents = $this->codebase->file_provider->getContents($file_path); foreach ($file_manipulations as $manipulation) { $existing_contents = $manipulation->transform($existing_contents); } $this->codebase->file_provider->setContents($file_path, $existing_contents); } } if ($this->codebase->classes_to_move) { foreach ($this->codebase->classes_to_move as $source => $destination) { $source_class_storage = $this->codebase->classlike_storage_provider->get($source); if (!$source_class_storage->location) { continue; } $potential_file_path = $this->config->getPotentialComposerFilePathForClassLike($destination); if ($potential_file_path && !file_exists($potential_file_path)) { $containing_dir = dirname($potential_file_path); if (!file_exists($containing_dir)) { mkdir($containing_dir, 0777, \true); } rename($source_class_storage->location->file_path, $potential_file_path); } } } } public function findReferencesTo(string $symbol) : void { if (!$this->stdout_report_options) { throw new UnexpectedValueException('Not expecting to emit output'); } $locations = $this->codebase->findReferencesToSymbol($symbol); foreach ($locations as $location) { $snippet = $location->getSnippet(); $snippet_bounds = $location->getSnippetBounds(); $selection_bounds = $location->getSelectionBounds(); $selection_start = $selection_bounds[0] - $snippet_bounds[0]; $selection_length = $selection_bounds[1] - $selection_bounds[0]; echo $location->file_name . ':' . $location->getLineNumber() . "\n" . ($this->stdout_report_options->use_color ? substr($snippet, 0, $selection_start) . "\x1b[97;42m" . substr($snippet, $selection_start, $selection_length) . "\x1b[0m" . substr($snippet, $selection_length + $selection_start) : $snippet) . "\n" . "\n"; } } public function checkDir(string $dir_name) : void { $this->file_reference_provider->loadReferenceCache(); $this->config->visitPreloadedStubFiles($this->codebase, $this->progress); $this->checkDirWithConfig($dir_name, $this->config, \true); $this->progress->write($this->generatePHPVersionMessage()); $this->progress->startScanningFiles(); $this->config->initializePlugins($this); $this->codebase->scanFiles($this->threads); $this->config->visitStubFiles($this->codebase, $this->progress); $this->progress->startAnalyzingFiles(); $this->codebase->analyzer->analyzeFiles($this, $this->threads, $this->codebase->alter_code, $this->codebase->find_unused_code === 'always'); } private function checkDirWithConfig(string $dir_name, Config $config, bool $allow_non_project_files = \false) : void { $file_extensions = $config->getFileExtensions(); $filter = $allow_non_project_files ? null : [$this->config, 'isInProjectDirs']; $file_paths = $this->file_provider->getFilesInDir($dir_name, $file_extensions, $filter); $files_to_scan = []; foreach ($file_paths as $file_path) { $files_to_scan[$file_path] = $file_path; } $this->codebase->addFilesToAnalyze($files_to_scan); } public function addProjectFile(string $file_path) : void { $this->project_files[$file_path] = $file_path; } public function addExtraFile(string $file_path) : void { $this->extra_files[$file_path] = $file_path; } /** * @return list */ protected function getDiffFiles() : array { if (!$this->parser_cache_provider || !$this->project_cache_provider) { throw new UnexpectedValueException('Parser cache provider cannot be null here'); } $diff_files = []; $last_run = $this->project_cache_provider->getLastRun(PSALM_VERSION); foreach ($this->project_files as $file_path) { if ($this->file_provider->getModifiedTime($file_path) >= $last_run && $this->parser_cache_provider->loadExistingFileContentsFromCache($file_path) !== $this->file_provider->getContents($file_path)) { $diff_files[] = $file_path; } } return $diff_files; } /** * @param array $file_list */ private function checkDiffFilesWithConfig(Config $config, array $file_list = []) : void { $files_to_scan = []; foreach ($file_list as $file_path) { if (!$this->file_provider->fileExists($file_path)) { continue; } if (!$config->isInProjectDirs($file_path)) { $this->progress->debug('skipping ' . $file_path . "\n"); continue; } $files_to_scan[$file_path] = $file_path; } $this->codebase->addFilesToAnalyze($files_to_scan); } public function checkFile(string $file_path) : void { $this->progress->debug('Checking ' . $file_path . "\n"); $this->config->visitPreloadedStubFiles($this->codebase, $this->progress); $this->config->hide_external_errors = $this->config->isInProjectDirs($file_path); $this->codebase->addFilesToAnalyze([$file_path => $file_path]); $this->file_reference_provider->loadReferenceCache(); $this->progress->write($this->generatePHPVersionMessage()); $this->progress->startScanningFiles(); $this->config->initializePlugins($this); $this->codebase->scanFiles($this->threads); $this->config->visitStubFiles($this->codebase, $this->progress); $this->progress->startAnalyzingFiles(); $this->codebase->analyzer->analyzeFiles($this, $this->threads, $this->codebase->alter_code, $this->codebase->find_unused_code === 'always'); } /** * @param string[] $paths_to_check */ public function checkPaths(array $paths_to_check) : void { $this->config->visitPreloadedStubFiles($this->codebase, $this->progress); $this->visitAutoloadFiles(); $this->codebase->scanner->addFilesToShallowScan($this->extra_files); foreach ($paths_to_check as $path) { $this->progress->debug('Checking ' . $path . "\n"); if (is_dir($path)) { $this->checkDirWithConfig($path, $this->config, \true); } elseif (is_file($path)) { $this->check_paths_files[] = $path; $this->codebase->addFilesToAnalyze([$path => $path]); $this->config->hide_external_errors = $this->config->isInProjectDirs($path); } } $this->file_reference_provider->loadReferenceCache(); $this->progress->write($this->generatePHPVersionMessage()); $this->progress->startScanningFiles(); $this->config->initializePlugins($this); $this->codebase->scanFiles($this->threads); $this->config->visitStubFiles($this->codebase, $this->progress); $event = new AfterCodebasePopulatedEvent($this->codebase); $this->config->eventDispatcher->dispatchAfterCodebasePopulated($event); $this->progress->startAnalyzingFiles(); $this->codebase->analyzer->analyzeFiles($this, $this->threads, $this->codebase->alter_code, $this->codebase->find_unused_code === 'always'); if ($this->stdout_report_options && in_array($this->stdout_report_options->format, [Report::TYPE_CONSOLE, Report::TYPE_PHP_STORM]) && $this->codebase->collect_references) { fwrite(STDERR, PHP_EOL . 'To whom it may concern: Psalm cannot detect unused classes, methods and properties' . PHP_EOL . 'when analyzing individual files and folders. Run on the full project to enable' . PHP_EOL . 'complete unused code detection.' . PHP_EOL); } } public function finish(float $start_time, string $psalm_version) : void { $this->codebase->file_reference_provider->removeDeletedFilesFromReferences(); if ($this->project_cache_provider) { $this->project_cache_provider->processSuccessfulRun($start_time, $psalm_version); } } public function getConfig() : Config { return $this->config; } /** * @param array $diff_files * @return array */ public function getReferencedFilesFromDiff(array $diff_files, bool $include_referencing_files = \true) : array { $all_inherited_files_to_check = $diff_files; while ($diff_files) { $diff_file = array_shift($diff_files); $dependent_files = $this->file_reference_provider->getFilesInheritingFromFile($diff_file); $new_dependent_files = array_diff($dependent_files, $all_inherited_files_to_check); $all_inherited_files_to_check = array_merge($all_inherited_files_to_check, $new_dependent_files); $diff_files = array_merge($diff_files, $new_dependent_files); } $all_files_to_check = $all_inherited_files_to_check; if ($include_referencing_files) { foreach ($all_inherited_files_to_check as $file_name) { $dependent_files = $this->file_reference_provider->getFilesReferencingFile($file_name); $all_files_to_check = array_merge($dependent_files, $all_files_to_check); } } return array_combine($all_files_to_check, $all_files_to_check); } public function fileExists(string $file_path) : bool { return $this->file_provider->fileExists($file_path); } public function isDirectory(string $file_path) : bool { return $this->file_provider->isDirectory($file_path); } public function alterCodeAfterCompletion(bool $dry_run = \false, bool $safe_types = \false) : void { $this->codebase->alter_code = \true; $this->codebase->infer_types_from_usage = \true; $this->show_issues = \false; $this->dry_run = $dry_run; $this->only_replace_php_types_with_non_docblock_types = $safe_types; } /** * @param array $to_refactor */ public function refactorCodeAfterCompletion(array $to_refactor) : void { $this->to_refactor = $to_refactor; $this->codebase->alter_code = \true; $this->show_issues = \false; } /** * @param 'cli'|'config'|'composer'|'tests' $source */ public function setPhpVersion(string $version, string $source) : void { if (!preg_match('/' . self::PHP_VERSION_REGEX . '/', $version)) { throw new UnexpectedValueException('Expecting a version number in the format x.y or x.y.z'); } if (!preg_match('/' . self::PHP_SUPPORTED_VERSIONS_REGEX . '/', $version)) { throw new UnexpectedValueException('Psalm supports PHP version ">=5.4". The specified version ' . $version . " is either not supported or doesn't exist."); } [$php_major_version, $php_minor_version] = explode('.', $version); $php_major_version = (int) $php_major_version; $php_minor_version = (int) $php_minor_version; $analysis_php_version_id = $php_major_version * 10000 + $php_minor_version * 100; if ($this->codebase->analysis_php_version_id !== $analysis_php_version_id) { // reset lexer and parser when php version changes StatementsProvider::clearLexer(); StatementsProvider::clearParser(); } $this->codebase->analysis_php_version_id = $analysis_php_version_id; $this->codebase->php_version_source = $source; } /** * @param array $issues * @throws UnsupportedIssueToFixException */ public function setIssuesToFix(array $issues) : void { $supported_issues_to_fix = static::getSupportedIssuesToFix(); $supported_issues_to_fix[] = 'MissingImmutableAnnotation'; $supported_issues_to_fix[] = 'MissingPureAnnotation'; $supported_issues_to_fix[] = 'MissingThrowsDocblock'; $unsupportedIssues = array_diff(array_keys($issues), $supported_issues_to_fix); if (!empty($unsupportedIssues)) { throw new UnsupportedIssueToFixException('Psalm doesn\'t know how to fix issue(s): ' . implode(', ', $unsupportedIssues) . PHP_EOL . 'Supported issues to fix are: ' . implode(',', $supported_issues_to_fix)); } $this->issues_to_fix = $issues; } public function setAllIssuesToFix() : void { $keyed_issues = array_fill_keys(static::getSupportedIssuesToFix(), \true); $this->setIssuesToFix($keyed_issues); } /** * @return array */ public function getIssuesToFix() : array { return $this->issues_to_fix; } public function getCodebase() : Codebase { return $this->codebase; } public function getFileAnalyzerForClassLike(string $fq_class_name) : \Psalm\Internal\Analyzer\FileAnalyzer { $fq_class_name_lc = strtolower($fq_class_name); $file_path = $this->codebase->scanner->getClassLikeFilePath($fq_class_name_lc); return new \Psalm\Internal\Analyzer\FileAnalyzer($this, $file_path, $this->config->shortenFileName($file_path)); } public function getMethodMutations(MethodIdentifier $original_method_id, Context $this_context, string $root_file_path, string $root_file_name) : void { $fq_class_name = $original_method_id->fq_class_name; $appearing_method_id = $this->codebase->methods->getAppearingMethodId($original_method_id); if (!$appearing_method_id) { // this can happen for some abstract classes implementing (but not fully) interfaces return; } $appearing_fq_class_name = $appearing_method_id->fq_class_name; $appearing_class_storage = $this->classlike_storage_provider->get($appearing_fq_class_name); if (!$appearing_class_storage->user_defined) { return; } $file_analyzer = $this->getFileAnalyzerForClassLike($fq_class_name); $file_analyzer->setRootFilePath($root_file_path, $root_file_name); if ($appearing_fq_class_name !== $fq_class_name) { $file_analyzer = $this->getFileAnalyzerForClassLike($appearing_fq_class_name); } $stmts = $this->codebase->getStatementsForFile($file_analyzer->getFilePath()); $file_analyzer->populateCheckers($stmts); if (!$this_context->self) { $this_context->self = $fq_class_name; $this_context->vars_in_scope['$this'] = Type::parseString($fq_class_name); } $file_analyzer->getMethodMutations($appearing_method_id, $this_context, \true); $file_analyzer->class_analyzers_to_analyze = []; $file_analyzer->interface_analyzers_to_analyze = []; $file_analyzer->clearSourceBeforeDestruction(); } public function getFunctionLikeAnalyzer(MethodIdentifier $method_id, string $file_path) : ?\Psalm\Internal\Analyzer\FunctionLikeAnalyzer { $file_analyzer = new \Psalm\Internal\Analyzer\FileAnalyzer($this, $file_path, $this->config->shortenFileName($file_path)); $stmts = $this->codebase->getStatementsForFile($file_analyzer->getFilePath()); $file_analyzer->populateCheckers($stmts); $function_analyzer = $file_analyzer->getFunctionLikeAnalyzer($method_id); $file_analyzer->class_analyzers_to_analyze = []; $file_analyzer->interface_analyzers_to_analyze = []; return $function_analyzer; } /** * Adapted from https://gist.github.com/divinity76/01ef9ca99c111565a72d3a8a6e42f7fb * returns number of cpu cores * Copyleft 2018, license: WTFPL * * @throws NumberOfCpuCoreNotFound */ public static function getCpuCount() : int { if (defined('PHP_WINDOWS_VERSION_MAJOR')) { // No support desired for Windows at the moment return 1; } if (!extension_loaded('pcntl')) { // Psalm requires pcntl for multi-threads support return 1; } return (new CpuCoreCounter())->getCount(); } /** * @return array * @psalm-pure */ public static function getSupportedIssuesToFix() : array { return array_map( /** @param class-string $issue_class */ static function (string $issue_class) : string { $parts = explode('\\', $issue_class); return end($parts); }, self::SUPPORTED_ISSUES_TO_FIX ); } } $stmts * @param list<'loop'|'switch'> $break_types * @param bool $return_is_exit Exit and Throw statements are treated differently from return if this is false * @return list * @psalm-suppress ComplexMethod nothing much we can do */ public static function getControlActions(array $stmts, ?NodeDataProvider $nodes, array $break_types, bool $return_is_exit = \true) : array { if (empty($stmts)) { return [self::ACTION_NONE]; } $control_actions = []; foreach ($stmts as $stmt) { if ($stmt instanceof PhpParser\Node\Stmt\Return_ || $stmt instanceof PhpParser\Node\Stmt\Throw_ || $stmt instanceof PhpParser\Node\Stmt\Expression && $stmt->expr instanceof PhpParser\Node\Expr\Exit_) { if (!$return_is_exit && $stmt instanceof PhpParser\Node\Stmt\Return_) { $stmt_return_type = null; if ($nodes && $stmt->expr) { $stmt_return_type = $nodes->getType($stmt->expr); } // don't consider a return if the expression never returns (e.g. a throw inside a short closure) if ($stmt_return_type && $stmt_return_type->isNever()) { return array_values(array_unique([...$control_actions, ...[self::ACTION_END]])); } return array_values(array_unique([...$control_actions, ...[self::ACTION_RETURN]])); } return array_values(array_unique([...$control_actions, ...[self::ACTION_END]])); } if ($stmt instanceof PhpParser\Node\Stmt\Expression) { // This allows calls to functions that always exit to act as exit statements themselves if ($nodes && ($stmt_expr_type = $nodes->getType($stmt->expr)) && $stmt_expr_type->isNever()) { return array_values(array_unique([...$control_actions, ...[self::ACTION_END]])); } continue; } if ($stmt instanceof PhpParser\Node\Stmt\Continue_) { $count = !$stmt->num ? 1 : ($stmt->num instanceof PhpParser\Node\Scalar\LNumber ? $stmt->num->value : null); if ($break_types && $count !== null && count($break_types) >= $count) { /** @psalm-suppress InvalidArrayOffset Some int-range improvements are needed */ if ($break_types[count($break_types) - $count] === 'switch') { return [...$control_actions, ...[self::ACTION_LEAVE_SWITCH]]; } return array_values($control_actions); } return array_values(array_unique([...$control_actions, ...[self::ACTION_CONTINUE]])); } if ($stmt instanceof PhpParser\Node\Stmt\Break_) { $count = !$stmt->num ? 1 : ($stmt->num instanceof PhpParser\Node\Scalar\LNumber ? $stmt->num->value : null); if ($break_types && $count !== null && count($break_types) >= $count) { /** @psalm-suppress InvalidArrayOffset Some int-range improvements are needed */ if ($break_types[count($break_types) - $count] === 'switch') { return [...$control_actions, ...[self::ACTION_LEAVE_SWITCH]]; } /** @psalm-suppress InvalidArrayOffset Some int-range improvements are needed */ if ($break_types[count($break_types) - $count] === 'loop') { return [...$control_actions, ...[self::ACTION_LEAVE_LOOP]]; } return array_values($control_actions); } return array_values(array_unique([...$control_actions, ...[self::ACTION_BREAK]])); } if ($stmt instanceof PhpParser\Node\Stmt\If_) { $if_statement_actions = self::getControlActions($stmt->stmts, $nodes, $break_types, $return_is_exit); $all_leave = !array_filter($if_statement_actions, static fn(string $action): bool => $action === self::ACTION_NONE); $else_statement_actions = $stmt->else ? self::getControlActions($stmt->else->stmts, $nodes, $break_types, $return_is_exit) : []; $all_leave = $all_leave && $else_statement_actions && !array_filter($else_statement_actions, static fn(string $action): bool => $action === self::ACTION_NONE); $all_elseif_actions = []; if ($stmt->elseifs) { foreach ($stmt->elseifs as $elseif) { $elseif_control_actions = self::getControlActions($elseif->stmts, $nodes, $break_types, $return_is_exit); $all_leave = $all_leave && !array_filter($elseif_control_actions, static fn(string $action): bool => $action === self::ACTION_NONE); $all_elseif_actions = [...$elseif_control_actions, ...$all_elseif_actions]; } } if ($all_leave) { return array_values(array_unique([...$control_actions, ...$if_statement_actions, ...$else_statement_actions, ...$all_elseif_actions])); } $control_actions = array_filter([...$control_actions, ...$if_statement_actions, ...$else_statement_actions, ...$all_elseif_actions], static fn(string $action): bool => $action !== self::ACTION_NONE); } if ($stmt instanceof PhpParser\Node\Stmt\Switch_) { $has_ended = \false; $has_non_breaking_default = \false; $has_default_terminator = \false; $all_case_actions = []; // iterate backwards in a case statement for ($d = count($stmt->cases) - 1; $d >= 0; --$d) { $case = $stmt->cases[$d]; $case_actions = self::getControlActions($case->stmts, $nodes, [...$break_types, ...['switch']], $return_is_exit); if (array_intersect([self::ACTION_LEAVE_SWITCH, self::ACTION_BREAK, self::ACTION_CONTINUE], $case_actions)) { continue 2; } if (!$case->cond) { $has_non_breaking_default = \true; } $case_does_end = !array_diff($control_actions, [self::ACTION_END, self::ACTION_RETURN]); if ($case_does_end) { $has_ended = \true; } $all_case_actions = [...$all_case_actions, ...$case_actions]; if (!$case_does_end && !$has_ended) { continue 2; } if ($has_non_breaking_default && $case_does_end) { $has_default_terminator = \true; } } $all_case_actions = array_filter($all_case_actions, static fn(string $action): bool => $action !== self::ACTION_NONE); if ($has_default_terminator || $stmt->getAttribute('allMatched', \false)) { return array_values(array_unique([...$control_actions, ...$all_case_actions])); } $control_actions = [...$control_actions, ...$all_case_actions]; } if ($stmt instanceof PhpParser\Node\Stmt\Do_ || $stmt instanceof PhpParser\Node\Stmt\While_ || $stmt instanceof PhpParser\Node\Stmt\Foreach_ || $stmt instanceof PhpParser\Node\Stmt\For_) { $loop_actions = self::getControlActions($stmt->stmts, $nodes, [...$break_types, ...['loop']], $return_is_exit); $control_actions = array_filter([...$control_actions, ...$loop_actions], static fn(string $action): bool => $action !== self::ACTION_NONE); if (($stmt instanceof PhpParser\Node\Stmt\While_ || $stmt instanceof PhpParser\Node\Stmt\Do_) && $nodes && ($stmt_expr_type = $nodes->getType($stmt->cond)) && $stmt_expr_type->isAlwaysTruthy() && !in_array(self::ACTION_LEAVE_LOOP, $control_actions, \true)) { //infinite while loop that only return don't have an exit path $have_exit_path = (bool) array_diff($control_actions, [self::ACTION_END, self::ACTION_RETURN]); if (!$have_exit_path) { return array_values(array_unique($control_actions)); } } if ($stmt instanceof PhpParser\Node\Stmt\For_ && $nodes && !in_array(self::ACTION_LEAVE_LOOP, $control_actions, \true)) { $is_infinite_loop = \true; if ($stmt->cond) { foreach ($stmt->cond as $cond) { $stmt_expr_type = $nodes->getType($cond); if (!$stmt_expr_type || !$stmt_expr_type->isAlwaysTruthy()) { $is_infinite_loop = \false; } } } if ($is_infinite_loop) { //infinite while loop that only return don't have an exit path $have_exit_path = (bool) array_diff($control_actions, [self::ACTION_END, self::ACTION_RETURN]); if (!$have_exit_path) { return array_values(array_unique($control_actions)); } } } $control_actions = array_filter($control_actions, static fn(string $action): bool => $action !== self::ACTION_LEAVE_LOOP); } if ($stmt instanceof PhpParser\Node\Stmt\TryCatch) { $try_statement_actions = self::getControlActions($stmt->stmts, $nodes, $break_types, $return_is_exit); $try_leaves = !array_filter($try_statement_actions, static fn(string $action): bool => $action === self::ACTION_NONE); $all_catch_actions = []; if ($stmt->catches) { $all_leave = $try_leaves; foreach ($stmt->catches as $catch) { $catch_actions = self::getControlActions($catch->stmts, $nodes, $break_types, $return_is_exit); $all_leave = $all_leave && !array_filter($catch_actions, static fn(string $action): bool => $action === self::ACTION_NONE); if (!$all_leave) { $control_actions = [...$control_actions, ...$catch_actions]; } else { $all_catch_actions = [...$all_catch_actions, ...$catch_actions]; } } if ($all_leave && $try_statement_actions !== [self::ACTION_NONE]) { return array_values(array_unique([...$control_actions, ...$try_statement_actions, ...$all_catch_actions])); } } elseif ($try_leaves) { return array_values(array_unique([...$control_actions, ...$try_statement_actions])); } if ($stmt->finally && $stmt->finally->stmts) { $finally_statement_actions = self::getControlActions($stmt->finally->stmts, $nodes, $break_types, $return_is_exit); if (!in_array(self::ACTION_NONE, $finally_statement_actions, \true)) { return [...array_filter($control_actions, static fn(string $action): bool => $action !== self::ACTION_NONE), ...$finally_statement_actions]; } } $control_actions = array_filter([...$control_actions, ...$try_statement_actions], static fn(string $action): bool => $action !== self::ACTION_NONE); } } $control_actions[] = self::ACTION_NONE; return array_values(array_unique($control_actions)); } /** * @param array $stmts */ public static function onlyThrowsOrExits(NodeTypeProvider $type_provider, array $stmts) : bool { if (empty($stmts)) { return \false; } for ($i = count($stmts) - 1; $i >= 0; --$i) { $stmt = $stmts[$i]; if ($stmt instanceof PhpParser\Node\Stmt\Throw_ || $stmt instanceof PhpParser\Node\Stmt\Expression && $stmt->expr instanceof PhpParser\Node\Expr\Exit_) { return \true; } if ($stmt instanceof PhpParser\Node\Stmt\Expression) { $stmt_type = $type_provider->getType($stmt->expr); if ($stmt_type && $stmt_type->isNever()) { return \true; } } } return \false; } /** * @param array $stmts */ public static function onlyThrows(array $stmts) : bool { $stmts_count = count($stmts); if ($stmts_count !== 1) { return \false; } foreach ($stmts as $stmt) { if ($stmt instanceof PhpParser\Node\Stmt\Throw_) { return \true; } } return \false; } } */ private array $all_vars = []; /** * @var array */ private array $var_branch_points = []; /** * Possibly undefined variables should be initialised if we're altering code * * @var array|null */ private ?array $vars_to_initialize = null; /** * @var array */ private array $function_analyzers = []; /** * @var array */ private array $unused_var_locations = []; /** * @var array */ public array $byref_uses = []; private ?ParsedDocblock $parsed_docblock = null; private ?string $fake_this_class = null; public NodeDataProvider $node_data; public ?DataFlowGraph $data_flow_graph = null; /** * Locations of foreach values * * Used to discern ordinary UnusedVariables from UnusedForeachValues * * @var array> * @psalm-internal Psalm\Internal\Analyzer */ public array $foreach_var_locations = []; public function __construct(\Psalm\Internal\Analyzer\SourceAnalyzer $source, NodeDataProvider $node_data) { $this->source = $source; $this->file_analyzer = $source->getFileAnalyzer(); $this->codebase = $source->getCodebase(); $this->node_data = $node_data; if ($this->codebase->taint_flow_graph) { $this->data_flow_graph = new TaintFlowGraph(); } elseif ($this->codebase->find_unused_variables) { $this->data_flow_graph = new VariableUseGraph(); } } /** * Checks an array of statements for validity * * @param array $stmts * @return null|false */ public function analyze(array $stmts, Context $context, ?Context $global_context = null, bool $root_scope = \false) : ?bool { if (!$stmts) { return null; } // hoist functions to the top $this->hoistFunctions($stmts, $context); $project_analyzer = $this->getFileAnalyzer()->project_analyzer; $codebase = $project_analyzer->getCodebase(); if ($codebase->config->hoist_constants) { self::hoistConstants($this, $stmts, $context); } foreach ($stmts as $stmt) { if (self::analyzeStatement($this, $stmt, $context, $global_context) === \false) { return \false; } } if ($root_scope && !$context->collect_initializations && !$context->collect_mutations && $codebase->find_unused_variables && $context->check_variables) { $this->checkUnreferencedVars($stmts, $context); } if ($codebase->alter_code && $root_scope && $this->vars_to_initialize) { $file_contents = $codebase->getFileContents($this->getFilePath()); foreach ($this->vars_to_initialize as $var_id => $branch_point) { $newline_pos = (int) strrpos($file_contents, "\n", $branch_point - strlen($file_contents)) + 1; $indentation = substr($file_contents, $newline_pos, $branch_point - $newline_pos); FileManipulationBuffer::add($this->getFilePath(), [new FileManipulation($branch_point, $branch_point, $var_id . ' = null;' . "\n" . $indentation)]); } } if ($root_scope && $this->data_flow_graph instanceof TaintFlowGraph && $this->codebase->taint_flow_graph && $codebase->config->trackTaintsInPath($this->getFilePath())) { $this->codebase->taint_flow_graph->addGraph($this->data_flow_graph); } return null; } /** * @param array $stmts */ private function hoistFunctions(array $stmts, Context $context) : void { foreach ($stmts as $stmt) { if ($stmt instanceof PhpParser\Node\Stmt\Function_) { $function_name = strtolower($stmt->name->name); if ($ns = $this->getNamespace()) { $fq_function_name = strtolower($ns) . '\\' . $function_name; } else { $fq_function_name = $function_name; } if ($this->data_flow_graph && $this->codebase->find_unused_variables) { foreach ($stmt->stmts as $function_stmt) { if ($function_stmt instanceof PhpParser\Node\Stmt\Global_) { foreach ($function_stmt->vars as $var) { if (!$var instanceof PhpParser\Node\Expr\Variable || !is_string($var->name)) { continue; } $var_id = '$' . $var->name; if ($var_id !== '$argv' && $var_id !== '$argc') { $context->byref_constraints[$var_id] = new ReferenceConstraint(); } } } } } try { $function_analyzer = new \Psalm\Internal\Analyzer\FunctionAnalyzer($stmt, $this->source); $this->function_analyzers[$fq_function_name] = $function_analyzer; } catch (UnexpectedValueException $e) { // do nothing } } } } /** * @param array $stmts */ private static function hoistConstants(\Psalm\Internal\Analyzer\StatementsAnalyzer $statements_analyzer, array $stmts, Context $context) : void { $codebase = $statements_analyzer->getCodebase(); foreach ($stmts as $stmt) { if ($stmt instanceof PhpParser\Node\Stmt\Const_) { foreach ($stmt->consts as $const) { ConstFetchAnalyzer::setConstType($statements_analyzer, $const->name->name, SimpleTypeInferer::infer($codebase, $statements_analyzer->node_data, $const->value, $statements_analyzer->getAliases(), $statements_analyzer) ?? Type::getMixed(), $context); } } elseif ($stmt instanceof PhpParser\Node\Stmt\Expression && $stmt->expr instanceof PhpParser\Node\Expr\FuncCall && $stmt->expr->name instanceof PhpParser\Node\Name && $stmt->expr->name->getParts() === ['define'] && isset($stmt->expr->getArgs()[1])) { $const_name = ConstFetchAnalyzer::getConstName($stmt->expr->getArgs()[0]->value, $statements_analyzer->node_data, $codebase, $statements_analyzer->getAliases()); if ($const_name !== null) { ConstFetchAnalyzer::setConstType($statements_analyzer, $const_name, SimpleTypeInferer::infer($codebase, $statements_analyzer->node_data, $stmt->expr->getArgs()[1]->value, $statements_analyzer->getAliases(), $statements_analyzer) ?? Type::getMixed(), $context); } } } } /** * @return false|null */ private static function analyzeStatement(\Psalm\Internal\Analyzer\StatementsAnalyzer $statements_analyzer, PhpParser\Node\Stmt $stmt, Context $context, ?Context $global_context) : ?bool { if (self::dispatchBeforeStatementAnalysis($stmt, $context, $statements_analyzer) === \false) { return \false; } $ignore_variable_property = \false; $ignore_variable_method = \false; $codebase = $statements_analyzer->getCodebase(); if ($statements_analyzer->getProjectAnalyzer()->debug_lines) { fwrite(STDERR, $statements_analyzer->getFilePath() . ':' . $stmt->getLine() . "\n"); } $new_issues = null; $traced_variables = []; $checked_types = []; if ($docblock = $stmt->getDocComment()) { $statements_analyzer->parseStatementDocblock($docblock, $stmt, $context); if (isset($statements_analyzer->parsed_docblock->tags['psalm-trace'])) { foreach ($statements_analyzer->parsed_docblock->tags['psalm-trace'] as $traced_variable_line) { $possible_traced_variable_names = preg_split('/(?:\\s*,\\s*|\\s+)/', $traced_variable_line, -1, PREG_SPLIT_NO_EMPTY); if ($possible_traced_variable_names) { $traced_variables = [...$traced_variables, ...$possible_traced_variable_names]; } } } foreach ($statements_analyzer->parsed_docblock->tags['psalm-check-type'] ?? [] as $inexact_check) { $checked_types[] = [$inexact_check, \false]; } foreach ($statements_analyzer->parsed_docblock->tags['psalm-check-type-exact'] ?? [] as $exact_check) { $checked_types[] = [$exact_check, \true]; } if (isset($statements_analyzer->parsed_docblock->tags['psalm-ignore-variable-method'])) { $context->ignore_variable_method = $ignore_variable_method = \true; } if (isset($statements_analyzer->parsed_docblock->tags['psalm-ignore-variable-property'])) { $context->ignore_variable_property = $ignore_variable_property = \true; } if (isset($statements_analyzer->parsed_docblock->tags['psalm-suppress'])) { $suppressed = $statements_analyzer->parsed_docblock->tags['psalm-suppress']; if ($suppressed) { $new_issues = []; foreach ($suppressed as $offset => $suppress_entry) { foreach (DocComment::parseSuppressList($suppress_entry) as $issue_offset => $issue_type) { $new_issues[$issue_offset + $offset] = $issue_type; } } if ($codebase->track_unused_suppressions && (count($new_issues) === 1 || !in_array("UnusedPsalmSuppress", $new_issues))) { foreach ($new_issues as $offset => $issue_type) { if ($issue_type === 'InaccessibleMethod') { continue; } IssueBuffer::addUnusedSuppression($statements_analyzer->getFilePath(), $offset, $issue_type); } } $statements_analyzer->addSuppressedIssues($new_issues); } } if (isset($statements_analyzer->parsed_docblock->combined_tags['var']) && !($stmt instanceof PhpParser\Node\Stmt\Expression && $stmt->expr instanceof PhpParser\Node\Expr\Assign) && !$stmt instanceof PhpParser\Node\Stmt\Foreach_ && !$stmt instanceof PhpParser\Node\Stmt\Return_) { $file_path = $statements_analyzer->getRootFilePath(); $file_storage_provider = $codebase->file_storage_provider; $file_storage = $file_storage_provider->get($file_path); $template_type_map = $statements_analyzer->getTemplateTypeMap(); $var_comments = []; try { $var_comments = $codebase->config->disable_var_parsing ? [] : \Psalm\Internal\Analyzer\CommentAnalyzer::arrayToDocblocks($docblock, $statements_analyzer->parsed_docblock, $statements_analyzer->getSource(), $statements_analyzer->getAliases(), $template_type_map, $file_storage->type_aliases); } catch (IncorrectDocblockException $e) { IssueBuffer::maybeAdd(new MissingDocblockType($e->getMessage(), new CodeLocation($statements_analyzer->getSource(), $stmt))); } catch (DocblockParseException $e) { IssueBuffer::maybeAdd(new InvalidDocblock($e->getMessage(), new CodeLocation($statements_analyzer->getSource(), $stmt))); } foreach ($var_comments as $var_comment) { AssignmentAnalyzer::assignTypeFromVarDocblock($statements_analyzer, $stmt, $var_comment, $context); if ($var_comment->var_id === '$this' && $var_comment->type && $codebase->classExists((string) $var_comment->type)) { $statements_analyzer->setFQCLN((string) $var_comment->type); } } } } else { $statements_analyzer->parsed_docblock = null; } if ($context->has_returned && !$context->collect_initializations && !$context->collect_mutations && !$stmt instanceof PhpParser\Node\Stmt\Nop && !$stmt instanceof PhpParser\Node\Stmt\Function_ && !$stmt instanceof PhpParser\Node\Stmt\Class_ && !$stmt instanceof PhpParser\Node\Stmt\Interface_ && !$stmt instanceof PhpParser\Node\Stmt\Trait_ && !$stmt instanceof PhpParser\Node\Stmt\HaltCompiler && !$stmt instanceof PhpParser\Node\Stmt\Declare_) { if ($codebase->find_unused_variables) { IssueBuffer::maybeAdd(new UnevaluatedCode('Expressions after return/throw/continue', new CodeLocation($statements_analyzer->source, $stmt)), $statements_analyzer->source->getSuppressedIssues()); } return null; } if ($stmt instanceof PhpParser\Node\Stmt\If_) { if (IfElseAnalyzer::analyze($statements_analyzer, $stmt, $context) === \false) { return \false; } } elseif ($stmt instanceof PhpParser\Node\Stmt\TryCatch) { if (TryAnalyzer::analyze($statements_analyzer, $stmt, $context) === \false) { return \false; } } elseif ($stmt instanceof PhpParser\Node\Stmt\For_) { if (ForAnalyzer::analyze($statements_analyzer, $stmt, $context) === \false) { return \false; } } elseif ($stmt instanceof PhpParser\Node\Stmt\Foreach_) { if (ForeachAnalyzer::analyze($statements_analyzer, $stmt, $context) === \false) { return \false; } } elseif ($stmt instanceof PhpParser\Node\Stmt\While_) { if (WhileAnalyzer::analyze($statements_analyzer, $stmt, $context) === \false) { return \false; } } elseif ($stmt instanceof PhpParser\Node\Stmt\Do_) { if (DoAnalyzer::analyze($statements_analyzer, $stmt, $context) === \false) { return \false; } } elseif ($stmt instanceof PhpParser\Node\Stmt\Const_) { ConstFetchAnalyzer::analyzeConstAssignment($statements_analyzer, $stmt, $context); } elseif ($stmt instanceof PhpParser\Node\Stmt\Unset_) { UnsetAnalyzer::analyze($statements_analyzer, $stmt, $context); } elseif ($stmt instanceof PhpParser\Node\Stmt\Return_) { ReturnAnalyzer::analyze($statements_analyzer, $stmt, $context); } elseif ($stmt instanceof PhpParser\Node\Stmt\Throw_) { ThrowAnalyzer::analyze($statements_analyzer, $stmt, $context); } elseif ($stmt instanceof PhpParser\Node\Stmt\Switch_) { SwitchAnalyzer::analyze($statements_analyzer, $stmt, $context); } elseif ($stmt instanceof PhpParser\Node\Stmt\Break_) { BreakAnalyzer::analyze($statements_analyzer, $stmt, $context); } elseif ($stmt instanceof PhpParser\Node\Stmt\Continue_) { ContinueAnalyzer::analyze($statements_analyzer, $stmt, $context); } elseif ($stmt instanceof PhpParser\Node\Stmt\Static_) { StaticAnalyzer::analyze($statements_analyzer, $stmt, $context); } elseif ($stmt instanceof PhpParser\Node\Stmt\Echo_) { if (EchoAnalyzer::analyze($statements_analyzer, $stmt, $context) === \false) { return \false; } } elseif ($stmt instanceof PhpParser\Node\Stmt\Function_) { \Psalm\Internal\Analyzer\FunctionAnalyzer::analyzeStatement($statements_analyzer, $stmt, $context); } elseif ($stmt instanceof PhpParser\Node\Stmt\Expression) { if (ExpressionAnalyzer::analyze($statements_analyzer, $stmt->expr, $context, \false, $global_context, \true) === \false) { return \false; } } elseif ($stmt instanceof PhpParser\Node\Stmt\InlineHTML) { // do nothing } elseif ($stmt instanceof PhpParser\Node\Stmt\Global_) { GlobalAnalyzer::analyze($statements_analyzer, $stmt, $context, $global_context); } elseif ($stmt instanceof PhpParser\Node\Stmt\Property) { InstancePropertyAssignmentAnalyzer::analyzeStatement($statements_analyzer, $stmt, $context); } elseif ($stmt instanceof PhpParser\Node\Stmt\ClassConst) { ClassConstAnalyzer::analyzeAssignment($statements_analyzer, $stmt, $context); } elseif ($stmt instanceof PhpParser\Node\Stmt\Class_) { try { $class_analyzer = new \Psalm\Internal\Analyzer\ClassAnalyzer($stmt, $statements_analyzer->source, $stmt->name->name ?? null); $class_analyzer->analyze(null, $global_context); } catch (InvalidArgumentException $e) { // disregard this exception, we'll likely see it elsewhere in the form // of an issue } } elseif ($stmt instanceof PhpParser\Node\Stmt\Trait_) { \Psalm\Internal\Analyzer\TraitAnalyzer::analyze($statements_analyzer, $stmt, $context); } elseif ($stmt instanceof PhpParser\Node\Stmt\Nop) { // do nothing } elseif ($stmt instanceof PhpParser\Node\Stmt\Goto_) { // do nothing } elseif ($stmt instanceof PhpParser\Node\Stmt\Label) { // do nothing } elseif ($stmt instanceof PhpParser\Node\Stmt\Declare_) { DeclareAnalyzer::analyze($statements_analyzer, $stmt, $context); } elseif ($stmt instanceof PhpParser\Node\Stmt\HaltCompiler) { $context->has_returned = \true; } else { if (IssueBuffer::accepts(new UnrecognizedStatement('Psalm does not understand ' . get_class($stmt), new CodeLocation($statements_analyzer->source, $stmt)), $statements_analyzer->getSuppressedIssues())) { return \false; } } if (self::dispatchAfterStatementAnalysis($stmt, $context, $statements_analyzer) === \false) { return \false; } if ($new_issues) { $statements_analyzer->removeSuppressedIssues($new_issues); } if ($ignore_variable_property) { $context->ignore_variable_property = \false; } if ($ignore_variable_method) { $context->ignore_variable_method = \false; } foreach ($traced_variables as $traced_variable) { if (isset($context->vars_in_scope[$traced_variable])) { IssueBuffer::maybeAdd(new Trace($traced_variable . ': ' . $context->vars_in_scope[$traced_variable]->getId(), new CodeLocation($statements_analyzer->source, $stmt)), $statements_analyzer->getSuppressedIssues()); } else { IssueBuffer::maybeAdd(new UndefinedTrace('Attempt to trace undefined variable ' . $traced_variable, new CodeLocation($statements_analyzer->source, $stmt)), $statements_analyzer->getSuppressedIssues()); } } foreach ($checked_types as [$check_type_line, $is_exact]) { [$checked_var, $check_type_string] = array_map('trim', explode('=', $check_type_line, 2)) + ['', '']; if ($check_type_string === '' || $checked_var === '') { IssueBuffer::maybeAdd(new InvalidDocblock("Invalid format for @psalm-check-type" . ($is_exact ? "-exact" : ""), new CodeLocation($statements_analyzer->source, $stmt)), $statements_analyzer->getSuppressedIssues()); } else { $checked_var_id = $checked_var; $possibly_undefined = strrpos($checked_var_id, "?") === strlen($checked_var_id) - 1; if ($possibly_undefined) { $checked_var_id = substr($checked_var_id, 0, strlen($checked_var_id) - 1); } if (!isset($context->vars_in_scope[$checked_var_id])) { IssueBuffer::maybeAdd(new InvalidDocblock("Attempt to check undefined variable {$checked_var_id}", new CodeLocation($statements_analyzer->source, $stmt)), $statements_analyzer->getSuppressedIssues()); } else { try { $checked_type = $context->vars_in_scope[$checked_var_id]; $path = $statements_analyzer->getRootFilePath(); $file_storage = $codebase->file_storage_provider->get($path); $check_tokens = TypeTokenizer::getFullyQualifiedTokens($check_type_string, $statements_analyzer->getAliases(), $statements_analyzer->getTemplateTypeMap(), $file_storage->type_aliases); $check_type = TypeParser::parseTokens($check_tokens, null, $statements_analyzer->getTemplateTypeMap() ?? [], $file_storage->type_aliases, \true); /** @psalm-suppress InaccessibleProperty We just created this type */ $check_type->possibly_undefined = $possibly_undefined; if ($check_type->possibly_undefined !== $checked_type->possibly_undefined || !UnionTypeComparator::isContainedBy($codebase, $checked_type, $check_type) || $is_exact && !UnionTypeComparator::isContainedBy($codebase, $check_type, $checked_type)) { $check_var = $checked_var_id . ($checked_type->possibly_undefined ? "?" : ""); IssueBuffer::maybeAdd(new CheckType("Checked variable {$checked_var} = {$check_type->getId()} does not match " . "{$check_var} = {$checked_type->getId()}", new CodeLocation($statements_analyzer->source, $stmt)), $statements_analyzer->getSuppressedIssues()); } } catch (TypeParseTreeException $e) { IssueBuffer::maybeAdd(new InvalidDocblock($e->getMessage(), new CodeLocation($statements_analyzer->source, $stmt)), $statements_analyzer->getSuppressedIssues()); } } } } return null; } private static function dispatchAfterStatementAnalysis(PhpParser\Node\Stmt $stmt, Context $context, \Psalm\Internal\Analyzer\StatementsAnalyzer $statements_analyzer) : ?bool { $codebase = $statements_analyzer->getCodebase(); $event = new AfterStatementAnalysisEvent($stmt, $context, $statements_analyzer, $codebase, []); if ($codebase->config->eventDispatcher->dispatchAfterStatementAnalysis($event) === \false) { return \false; } $file_manipulations = $event->getFileReplacements(); if ($file_manipulations) { FileManipulationBuffer::add($statements_analyzer->getFilePath(), $file_manipulations); } return null; } private static function dispatchBeforeStatementAnalysis(PhpParser\Node\Stmt $stmt, Context $context, \Psalm\Internal\Analyzer\StatementsAnalyzer $statements_analyzer) : ?bool { $codebase = $statements_analyzer->getCodebase(); $event = new BeforeStatementAnalysisEvent($stmt, $context, $statements_analyzer, $codebase, []); if ($codebase->config->eventDispatcher->dispatchBeforeStatementAnalysis($event) === \false) { return \false; } $file_manipulations = $event->getFileReplacements(); if ($file_manipulations) { FileManipulationBuffer::add($statements_analyzer->getFilePath(), $file_manipulations); } return null; } private function parseStatementDocblock(PhpParser\Comment\Doc $docblock, PhpParser\Node\Stmt $stmt, Context $context) : void { $codebase = $this->getCodebase(); try { $this->parsed_docblock = DocComment::parsePreservingLength($docblock); } catch (DocblockParseException $e) { IssueBuffer::maybeAdd(new InvalidDocblock($e->getMessage(), new CodeLocation($this->getSource(), $stmt, null, \true))); $this->parsed_docblock = null; } if ($this->parsed_docblock === null) { try { $this->parsed_docblock = DocComment::parsePreservingLength($docblock, \true); } catch (DocblockParseException $e) { // already reported above } } $comments = $this->parsed_docblock; if (isset($comments->tags['psalm-scope-this'])) { $trimmed = trim(reset($comments->tags['psalm-scope-this'])); $scope_fqcn = Type::getFQCLNFromString($trimmed, $this->getAliases()); if (!$codebase->classExists($scope_fqcn)) { IssueBuffer::maybeAdd(new UndefinedDocblockClass('Scope class ' . $scope_fqcn . ' does not exist', new CodeLocation($this->getSource(), $stmt, null, \true), $scope_fqcn)); } else { $this_type = Type::parseString($scope_fqcn); $context->self = $scope_fqcn; $context->vars_in_scope['$this'] = $this_type; $this->setFQCLN($scope_fqcn); } } } /** * @param array $stmts */ public function checkUnreferencedVars(array $stmts, Context $context) : void { $source = $this->getSource(); $codebase = $source->getCodebase(); $function_storage = $source instanceof \Psalm\Internal\Analyzer\FunctionLikeAnalyzer ? $source->getFunctionLikeStorage($this) : null; $var_list = array_column($this->unused_var_locations, 0); $loc_list = array_column($this->unused_var_locations, 1); $project_analyzer = $this->getProjectAnalyzer(); $unused_var_remover = new UnusedAssignmentRemover(); if ($this->data_flow_graph instanceof VariableUseGraph && $codebase->config->limit_method_complexity && $source instanceof \Psalm\Internal\Analyzer\FunctionLikeAnalyzer && !$source instanceof \Psalm\Internal\Analyzer\ClosureAnalyzer && $function_storage && $function_storage->location) { [$count, , $unique_destinations, $mean] = $this->data_flow_graph->getEdgeStats(); $average_destination_branches_converging = $unique_destinations > 0 ? $count / $unique_destinations : 0; if ($count > $codebase->config->max_graph_size && $mean > $codebase->config->max_avg_path_length && $average_destination_branches_converging > 1.1) { if ($source instanceof \Psalm\Internal\Analyzer\FunctionAnalyzer) { IssueBuffer::maybeAdd(new ComplexFunction('This function’s complexity is greater than the project limit' . ' (method graph size = ' . $count . ', average path length = ' . round($mean) . ')', $function_storage->location), $this->getSuppressedIssues()); } elseif ($source instanceof \Psalm\Internal\Analyzer\MethodAnalyzer) { IssueBuffer::maybeAdd(new ComplexMethod('This method’s complexity is greater than the project limit' . ' (method graph size = ' . $count . ', average path length = ' . round($mean) . ')', $function_storage->location), $this->getSuppressedIssues()); } } } foreach ($this->unused_var_locations as [$var_id, $original_location]) { if (strpos($var_id, '$_') === 0) { continue; } if ($function_storage) { $param_index = array_search(substr($var_id, 1), array_keys($function_storage->param_lookup), \true); if ($param_index !== \false) { $param = $function_storage->params[$param_index]; if ($param->location && ($original_location->raw_file_end === $param->location->raw_file_end || $param->by_ref)) { continue; } } } $assignment_node = DataFlowNode::getForAssignment($var_id, $original_location); if (!isset($this->byref_uses[$var_id]) && !isset($context->referenced_globals[$var_id]) && !VariableFetchAnalyzer::isSuperGlobal($var_id) && $this->data_flow_graph instanceof VariableUseGraph && !$this->data_flow_graph->isVariableUsed($assignment_node)) { $is_foreach_var = \false; if (isset($this->foreach_var_locations[$var_id])) { foreach ($this->foreach_var_locations[$var_id] as $location) { if ($location->raw_file_start === $original_location->raw_file_start) { $is_foreach_var = \true; break; } } } if ($is_foreach_var) { $issue = new UnusedForeachValue($var_id . ' is never referenced or the value is not used', $original_location); } else { $issue = new UnusedVariable($var_id . ' is never referenced or the value is not used', $original_location); } if ($codebase->alter_code && $issue instanceof UnusedVariable && !$unused_var_remover->checkIfVarRemoved($var_id, $original_location) && isset($project_analyzer->getIssuesToFix()['UnusedVariable']) && !IssueBuffer::isSuppressed($issue, $this->getSuppressedIssues())) { $unused_var_remover->findUnusedAssignment($this->getCodebase(), $stmts, array_combine($var_list, $loc_list), $var_id, $original_location); } IssueBuffer::maybeAdd($issue, $this->getSuppressedIssues(), $issue instanceof UnusedVariable); } } } public function hasVariable(string $var_name) : bool { return isset($this->all_vars[$var_name]); } public function registerVariable(string $var_id, CodeLocation $location, ?int $branch_point) : void { $this->all_vars[$var_id] = $location; if ($branch_point) { $this->var_branch_points[$var_id] = $branch_point; } $this->registerVariableAssignment($var_id, $location); } public function registerVariableAssignment(string $var_id, CodeLocation $location) : void { $this->unused_var_locations[$location->getHash()] = [$var_id, $location]; } /** * @return array */ public function getUnusedVarLocations() : array { return $this->unused_var_locations; } public function registerPossiblyUndefinedVariable(string $undefined_var_id, PhpParser\Node\Expr\Variable $stmt) : void { if (!$this->data_flow_graph) { return; } $use_location = new CodeLocation($this->getSource(), $stmt); $use_node = DataFlowNode::getForAssignment($undefined_var_id, $use_location); $stmt_type = $this->node_data->getType($stmt); if ($stmt_type) { $stmt_type = $stmt_type->addParentNodes([$use_node->id => $use_node]); $this->node_data->setType($stmt, $stmt_type); } foreach ($this->unused_var_locations as [$var_id, $original_location]) { if ($var_id === $undefined_var_id) { $parent_node = DataFlowNode::getForAssignment($var_id, $original_location); $this->data_flow_graph->addPath($parent_node, $use_node, '='); } } } /** * @return array */ public function getParentNodesForPossiblyUndefinedVariable(string $undefined_var_id) : array { if (!$this->data_flow_graph) { return []; } $parent_nodes = []; foreach ($this->unused_var_locations as [$var_id, $original_location]) { if ($var_id === $undefined_var_id) { $assignment_node = DataFlowNode::getForAssignment($var_id, $original_location); $parent_nodes[$assignment_node->id] = $assignment_node; } } return $parent_nodes; } /** * The first appearance of the variable in this set of statements being evaluated */ public function getFirstAppearance(string $var_id) : ?CodeLocation { return $this->all_vars[$var_id] ?? null; } public function getBranchPoint(string $var_id) : ?int { return $this->var_branch_points[$var_id] ?? null; } public function addVariableInitialization(string $var_id, int $branch_point) : void { $this->vars_to_initialize[$var_id] = $branch_point; } public function getFileAnalyzer() : \Psalm\Internal\Analyzer\FileAnalyzer { return $this->file_analyzer; } public function getCodebase() : Codebase { return $this->codebase; } /** * @return array */ public function getFunctionAnalyzers() : array { return $this->function_analyzers; } /** * @param array $byref_uses */ public function setByRefUses(array $byref_uses) : void { $this->byref_uses = $byref_uses; } /** * @return array> */ public function getUncaughtThrows(Context $context) : array { $uncaught_throws = []; if ($context->collect_exceptions) { if ($context->possibly_thrown_exceptions) { $config = $this->codebase->config; $ignored_exceptions = array_change_key_case($context->is_global ? $config->ignored_exceptions_in_global_scope : $config->ignored_exceptions); $ignored_exceptions_and_descendants = array_change_key_case($context->is_global ? $config->ignored_exceptions_and_descendants_in_global_scope : $config->ignored_exceptions_and_descendants); foreach ($context->possibly_thrown_exceptions as $possibly_thrown_exception => $codelocations) { if (isset($ignored_exceptions[strtolower($possibly_thrown_exception)])) { continue; } $is_expected = \false; foreach ($ignored_exceptions_and_descendants as $expected_exception => $_) { try { if ($expected_exception === strtolower($possibly_thrown_exception) || $this->codebase->classExtends($possibly_thrown_exception, $expected_exception) || $this->codebase->interfaceExtends($possibly_thrown_exception, $expected_exception)) { $is_expected = \true; break; } } catch (InvalidArgumentException $e) { $is_expected = \true; break; } } if (!$is_expected) { $uncaught_throws[$possibly_thrown_exception] = $codelocations; } } } } return $uncaught_throws; } public function getFunctionAnalyzer(string $function_id) : ?\Psalm\Internal\Analyzer\FunctionAnalyzer { return $this->function_analyzers[$function_id] ?? null; } public function getParsedDocblock() : ?ParsedDocblock { return $this->parsed_docblock; } /** @psalm-mutation-free */ public function getFQCLN() : ?string { if ($this->fake_this_class) { return $this->fake_this_class; } return parent::getFQCLN(); } public function setFQCLN(string $fake_this_class) : void { $this->fake_this_class = $fake_this_class; } /** * @return NodeDataProvider */ public function getNodeTypeProvider() : NodeTypeProvider { return $this->node_data; } public function getFullyQualifiedFunctionMethodOrNamespaceName() : ?string { if ($this->source instanceof \Psalm\Internal\Analyzer\MethodAnalyzer) { $fqcn = $this->getFQCLN(); $method_name = $this->source->getFunctionLikeStorage($this)->cased_name; assert($fqcn !== null && $method_name !== null); return "{$fqcn}::{$method_name}"; } if ($this->source instanceof \Psalm\Internal\Analyzer\FunctionAnalyzer) { $namespace = $this->getNamespace(); $namespace = $namespace === "" ? "" : "{$namespace}\\"; $function_name = $this->source->getFunctionLikeStorage($this)->cased_name; assert($function_name !== null); return "{$namespace}{$function_name}"; } return $this->getNamespace(); } } */ private array $aliased_classes = []; /** * @var array */ private array $aliased_class_locations = []; /** * @var array */ private array $aliased_classes_flipped = []; /** * @var array */ private array $aliased_classes_flipped_replaceable = []; /** * @var array */ private array $aliased_functions = []; /** * @var array */ private array $aliased_constants = []; public function visitUse(PhpParser\Node\Stmt\Use_ $stmt) : void { $codebase = $this->getCodebase(); foreach ($stmt->uses as $use) { $use_path = $use->name->toString(); $use_path_lc = strtolower($use_path); $use_alias = $use->alias->name ?? $use->name->getLast(); $use_alias_lc = strtolower($use_alias); switch ($use->type !== PhpParser\Node\Stmt\Use_::TYPE_UNKNOWN ? $use->type : $stmt->type) { case PhpParser\Node\Stmt\Use_::TYPE_FUNCTION: $this->aliased_functions[$use_alias_lc] = $use_path; break; case PhpParser\Node\Stmt\Use_::TYPE_CONSTANT: $this->aliased_constants[$use_alias] = $use_path; break; case PhpParser\Node\Stmt\Use_::TYPE_NORMAL: $codebase->analyzer->addOffsetReference($this->getFilePath(), (int) $use->getAttribute('startFilePos'), (int) $use->getAttribute('endFilePos'), $use_path); if ($codebase->collect_locations) { // register the path $codebase->use_referencing_locations[$use_path_lc][] = new CodeLocation($this, $use); } if ($codebase->alter_code) { if (isset($codebase->class_transforms[$use_path_lc])) { $new_fq_class_name = $codebase->class_transforms[$use_path_lc]; $file_manipulations = []; $file_manipulations[] = new FileManipulation((int) $use->getAttribute('startFilePos'), (int) $use->getAttribute('endFilePos') + 1, $new_fq_class_name . ($use->alias ? ' as ' . $use_alias : '')); FileManipulationBuffer::add($this->getFilePath(), $file_manipulations); } $this->aliased_classes_flipped_replaceable[$use_path_lc] = $use_alias; } $this->aliased_classes[$use_alias_lc] = $use_path; $this->aliased_class_locations[$use_alias_lc] = new CodeLocation($this, $stmt); $this->aliased_classes_flipped[$use_path_lc] = $use_alias; break; } } } public function visitGroupUse(PhpParser\Node\Stmt\GroupUse $stmt) : void { $use_prefix = $stmt->prefix->toString(); $codebase = $this->getCodebase(); foreach ($stmt->uses as $use) { $use_path = $use_prefix . '\\' . $use->name->toString(); $use_alias = $use->alias->name ?? $use->name->getLast(); switch ($use->type !== PhpParser\Node\Stmt\Use_::TYPE_UNKNOWN ? $use->type : $stmt->type) { case PhpParser\Node\Stmt\Use_::TYPE_FUNCTION: $this->aliased_functions[strtolower($use_alias)] = $use_path; break; case PhpParser\Node\Stmt\Use_::TYPE_CONSTANT: $this->aliased_constants[$use_alias] = $use_path; break; case PhpParser\Node\Stmt\Use_::TYPE_NORMAL: if ($codebase->collect_locations) { // register the path $codebase->use_referencing_locations[strtolower($use_path)][] = new CodeLocation($this, $use); } $this->aliased_classes[strtolower($use_alias)] = $use_path; $this->aliased_classes_flipped[strtolower($use_path)] = $use_alias; break; } } } /** * @psalm-mutation-free * @return array */ public function getAliasedClassesFlipped() : array { return $this->aliased_classes_flipped; } /** * @psalm-mutation-free * @return array */ public function getAliasedClassesFlippedReplaceable() : array { return $this->aliased_classes_flipped_replaceable; } /** @psalm-mutation-free */ public function getAliases() : Aliases { return new Aliases($this->getNamespace(), $this->aliased_classes, $this->aliased_functions, $this->aliased_constants); } } $formula_1 * @param list $formula_2 * @param array $new_assigned_var_ids */ public static function checkForParadox(array $formula_1, array $formula_2, \Psalm\Internal\Analyzer\StatementsAnalyzer $statements_analyzer, PhpParser\Node $stmt, array $new_assigned_var_ids) : void { try { $negated_formula2 = Algebra::negateFormula($formula_2); } catch (ComplicatedExpressionException $e) { return; } $formula_1_hashes = []; foreach ($formula_1 as $formula_1_clause) { $formula_1_hashes[$formula_1_clause->hash] = \true; } $formula_2_hashes = []; foreach ($formula_2 as $formula_2_clause) { $hash = $formula_2_clause->hash; if (!$formula_2_clause->generated && !$formula_2_clause->wedge && $formula_2_clause->reconcilable && (isset($formula_1_hashes[$hash]) || isset($formula_2_hashes[$hash])) && !array_intersect_key($new_assigned_var_ids, $formula_2_clause->possibilities)) { IssueBuffer::maybeAdd(new RedundantCondition($formula_2_clause . ' has already been asserted', new CodeLocation($statements_analyzer, $stmt), 'already asserted ' . $formula_2_clause), $statements_analyzer->getSuppressedIssues()); } $formula_2_hashes[$hash] = \true; } // remove impossible types foreach ($negated_formula2 as $negated_clause_2) { if (!$negated_clause_2->reconcilable || $negated_clause_2->wedge) { continue; } foreach ($formula_1 as $clause_1) { if ($negated_clause_2 === $clause_1 || !$clause_1->reconcilable || $clause_1->wedge) { continue; } $negated_clause_2_contains_1_possibilities = \true; foreach ($clause_1->possibilities as $key => $keyed_possibilities) { if (!isset($negated_clause_2->possibilities[$key])) { $negated_clause_2_contains_1_possibilities = \false; break; } if ($negated_clause_2->possibilities[$key] != $keyed_possibilities) { $negated_clause_2_contains_1_possibilities = \false; break; } foreach ($keyed_possibilities as $possibility) { if ($possibility instanceof InArray || $possibility instanceof NotInArray) { $negated_clause_2_contains_1_possibilities = \false; break; } } } if ($negated_clause_2_contains_1_possibilities) { $mini_formula_2 = Algebra::negateFormula([$negated_clause_2]); if (!$mini_formula_2[0]->wedge) { if (count($mini_formula_2) > 1) { $paradox_message = 'Condition ((' . implode(') && (', $mini_formula_2) . '))' . ' contradicts a previously-established condition (' . $clause_1 . ')'; } else { $paradox_message = 'Condition (' . $mini_formula_2[0] . ')' . ' contradicts a previously-established condition (' . $clause_1 . ')'; } } else { $paradox_message = 'Condition not(' . $negated_clause_2 . ')' . ' contradicts a previously-established condition (' . $clause_1 . ')'; } IssueBuffer::maybeAdd(new ParadoxicalCondition($paradox_message, new CodeLocation($statements_analyzer, $stmt)), $statements_analyzer->getSuppressedIssues()); return; } } } } } $new_types * @param array $existing_types * @return array */ public static function combineKeyedTypes(array $new_types, array $existing_types) : array { $keys = [...array_keys($new_types), ...array_keys($existing_types)]; $keys = array_unique($keys); $result_types = []; if (empty($new_types)) { return $existing_types; } if (empty($existing_types)) { return $new_types; } foreach ($keys as $key) { if (!isset($existing_types[$key])) { $result_types[$key] = $new_types[$key]; continue; } if (!isset($new_types[$key])) { $result_types[$key] = $existing_types[$key]; continue; } $existing_var_types = $existing_types[$key]; $new_var_types = $new_types[$key]; if ($new_var_types->getId() === $existing_var_types->getId()) { $result_types[$key] = $new_var_types; } else { $result_types[$key] = Type::combineUnionTypes($new_var_types, $existing_var_types); } } return $result_types; } } */ public ?array $unescaped_taints = null; /** @var ?array */ public ?array $escaped_taints = null; public int $length; /** * @param ?array $unescaped_taints * @param ?array $escaped_taints */ public function __construct(string $type, int $length, ?array $unescaped_taints = null, ?array $escaped_taints = null) { $this->type = $type; $this->length = $length; $this->unescaped_taints = $unescaped_taints; $this->escaped_taints = $escaped_taints; } } */ public array $taints; /** @var ?self */ public ?\Psalm\Internal\DataFlow\DataFlowNode $previous = null; /** @var list */ public array $path_types = []; /** * @var array> */ public array $specialized_calls = []; /** * @param array $taints */ public function __construct(string $id, string $label, ?CodeLocation $code_location, ?string $specialization_key = null, array $taints = []) { $this->id = $id; if ($specialization_key) { $this->unspecialized_id = $id; $this->id .= '-' . $specialization_key; } $this->label = $label; $this->code_location = $code_location; $this->specialization_key = $specialization_key; $this->taints = $taints; } /** * @return static */ public static final function getForMethodArgument(string $method_id, string $cased_method_id, int $argument_offset, ?CodeLocation $arg_location, ?CodeLocation $code_location = null) : self { $arg_id = strtolower($method_id) . '#' . ($argument_offset + 1); $label = $cased_method_id . '#' . ($argument_offset + 1); $specialization_key = null; if ($code_location) { $specialization_key = strtolower($code_location->file_name) . ':' . $code_location->raw_file_start; } return new static($arg_id, $label, $arg_location, $specialization_key); } /** * @return static */ public static final function getForAssignment(string $var_id, CodeLocation $assignment_location, ?string $specialization_key = null) : self { $id = $var_id . '-' . $assignment_location->file_name . ':' . $assignment_location->raw_file_start . '-' . $assignment_location->raw_file_end; return new static($id, $var_id, $assignment_location, $specialization_key); } /** * @return static */ public static final function getForMethodReturn(string $method_id, string $cased_method_id, ?CodeLocation $code_location, ?CodeLocation $function_location = null) : self { $specialization_key = null; if ($function_location) { $specialization_key = strtolower($function_location->file_name) . ':' . $function_location->raw_file_start; } return new static(strtolower($method_id), $cased_method_id, $code_location, $specialization_key); } public function __toString() : string { return $this->id; } } file_start = (int) $error->getAttributes()['startFilePos']; /** @psalm-suppress PossiblyUndefinedStringArrayOffset, ImpureMethodCall */ $this->file_end = (int) $error->getAttributes()['endFilePos']; $this->raw_file_start = $this->file_start; $this->raw_file_end = $this->file_end; $this->file_path = $file_path; $this->file_name = $file_name; $this->single_line = \false; $this->preview_start = $this->file_start; $this->raw_line_number = substr_count(substr($file_contents, 0, $this->file_start), "\n") + 1; } } file_start = $file_start; // matches how CodeLocation works $this->file_end = $file_end - 1; $this->raw_file_start = $file_start; $this->raw_file_end = $file_end; $this->raw_line_number = $line_number; $this->file_path = $file_source->getFilePath(); $this->file_name = $file_source->getFileName(); $this->single_line = \false; $this->preview_start = $this->file_start; $this->docblock_line_number = $line_number; } } file_start = $file_start; $this->file_end = $file_end; $this->raw_file_start = $this->file_start; $this->raw_file_end = $this->file_end; $this->file_path = $file_path; $this->file_name = $file_name; $this->single_line = \false; $this->preview_start = $this->file_start; $this->raw_line_number = substr_count(substr($file_contents, 0, $this->file_start), "\n") + 1; } } '; /** * @return non-empty-string */ public static function getContents(string $current_dir, ?string $suggested_dir, int $level, string $vendor_dir) : string { $paths = self::getPaths($current_dir, $suggested_dir); $template = str_replace('', implode("\n ", $paths), self::TEMPLATE); if (is_dir($current_dir . DIRECTORY_SEPARATOR . $vendor_dir)) { $template = str_replace('', '', $template); } else { $template = str_replace('', '', $template); } /** @var non-empty-string */ return str_replace('errorLevel="1"', 'errorLevel="' . $level . '"', $template); } public static function createBareConfig(string $current_dir, ?string $suggested_dir, string $vendor_dir) : Config { $config_contents = self::getContents($current_dir, $suggested_dir, 1, $vendor_dir); return Config::loadFromXML($current_dir, $config_contents); } /** * @param array $issues */ public static function getLevel(array $issues, int $counted_types) : int { if ($counted_types === 0) { $counted_types = 1; } $issues_at_level = []; foreach ($issues as $issue) { $issue_type = $issue->type; $issue_level = $issue->error_level; if ($issue_level < 1) { continue; } // exclude some directories that are probably ignorable if (strpos($issue->file_path, 'vendor') || strpos($issue->file_path, 'stub')) { continue; } if (!isset($issues_at_level[$issue_level][$issue_type])) { $issues_at_level[$issue_level][$issue_type] = 0; } $issues_at_level[$issue_level][$issue_type] += 100 / $counted_types; } foreach ($issues_at_level as $level => $issues) { ksort($issues); // remove any issues where < 0.1% of expressions are affected $filtered_issues = array_filter($issues, static fn($amount): bool => $amount > 0.1); if (array_sum($filtered_issues) > 0.5) { $issues_at_level[$level] = $filtered_issues; } else { unset($issues_at_level[$level]); } } if (!$issues_at_level) { return 1; } if (count($issues_at_level) === 1) { return array_keys($issues_at_level)[0] + 1; } return max(...array_keys($issues_at_level)) + 1; } /** * @return non-empty-list */ public static function getPaths(string $current_dir, ?string $suggested_dir) : array { $replacements = []; if ($suggested_dir) { if (is_dir($current_dir . DIRECTORY_SEPARATOR . $suggested_dir)) { $replacements[] = ''; } else { $bad_dir_path = $current_dir . DIRECTORY_SEPARATOR . $suggested_dir; throw new ConfigCreationException('The given path "' . $bad_dir_path . '" does not appear to be a directory'); } } elseif (is_dir($current_dir . DIRECTORY_SEPARATOR . 'src')) { $replacements[] = ''; } else { $composer_json_location = Composer::getJsonFilePath($current_dir); if (!file_exists($composer_json_location)) { throw new ConfigCreationException('Problem during source autodiscovery - could not find composer.json during initialization. ' . 'If your project doesn\'t use Composer autoloader you will need to run ' . '`psalm --init source_folder`, e.g. `psalm --init library` if your source files ' . 'reside in `library` folder'); } try { $composer_json = json_decode(file_get_contents($composer_json_location), \true, 512, JSON_THROW_ON_ERROR); } catch (JsonException $e) { throw new ConfigCreationException('Invalid composer.json at ' . $composer_json_location . ': ' . $e->getMessage()); } if (!$composer_json) { throw new ConfigCreationException('Invalid composer.json at ' . $composer_json_location); } if (!is_array($composer_json)) { throw new ConfigCreationException('Invalid composer.json at ' . $composer_json_location); } $replacements = self::getPsr4Or0Paths($current_dir, $composer_json); if (!$replacements) { throw new ConfigCreationException('Could not located any PSR-0 or PSR-4-compatible paths in ' . $composer_json_location); } } return $replacements; } /** * @return list * @psalm-suppress MixedAssignment * @psalm-suppress MixedArgument */ private static function getPsr4Or0Paths(string $current_dir, array $composer_json) : array { $psr_paths = array_merge($composer_json['autoload']['psr-4'] ?? [], $composer_json['autoload']['psr-0'] ?? []); if (!$psr_paths) { return self::guessPhpFileDirs($current_dir); } $nodes = []; foreach ($psr_paths as $paths) { if (!is_array($paths)) { $paths = [$paths]; } foreach ($paths as $path) { if (!is_string($path)) { continue; } if ($path === '') { $nodes = [...$nodes, ...self::guessPhpFileDirs($current_dir)]; continue; } $path = preg_replace('@[/\\\\]$@', '', $path, 1); if ($path !== 'tests') { $nodes[] = ''; } } } $nodes = array_unique($nodes); sort($nodes); return $nodes; } /** * @return list */ private static function guessPhpFileDirs(string $current_dir) : array { $nodes = []; /** @var string[] */ $php_files = array_merge(glob($current_dir . DIRECTORY_SEPARATOR . '*.php', GLOB_NOSORT), glob($current_dir . DIRECTORY_SEPARATOR . '**/*.php', GLOB_NOSORT), glob($current_dir . DIRECTORY_SEPARATOR . '**/**/*.php', GLOB_NOSORT)); foreach ($php_files as $php_file) { $php_file = str_replace($current_dir . DIRECTORY_SEPARATOR, '', $php_file); $parts = explode(DIRECTORY_SEPARATOR, $php_file); if (!$parts[0]) { array_shift($parts); } if ($parts[0] === 'vendor' || $parts[0] === 'tests') { continue; } if (count($parts) === 1) { $nodes[] = ''; } else { $nodes[] = ''; } } return array_values(array_unique($nodes)); } } */ protected $directories = []; /** * @var array */ protected $files = []; /** * @var array */ protected $fq_classlike_names = []; /** * @var array */ protected $fq_classlike_patterns = []; /** * @var array */ protected $method_ids = []; /** * @var array */ protected $property_ids = []; /** * @var array */ protected $class_constant_ids = []; /** * @var array */ protected $var_names = []; /** * @var array */ protected $files_lowercase = []; /** * @var bool */ protected $inclusive; /** * @var array */ protected $ignore_type_stats = []; /** * @var array */ protected $declare_strict_types = []; public function __construct(bool $inclusive) { $this->inclusive = $inclusive; } /** * @return static */ public static function loadFromArray(array $config, string $base_dir, bool $inclusive) { $allow_missing_files = ($config['allowMissingFiles'] ?? \false) === \true; $filter = new static($inclusive); if (isset($config['directory']) && is_iterable($config['directory'])) { /** @var array $directory */ foreach ($config['directory'] as $directory) { $directory_path = (string) ($directory['name'] ?? ''); $ignore_type_stats = (bool) ($directory['ignoreTypeStats'] ?? \false); $resolve_symlinks = (bool) ($directory['resolveSymlinks'] ?? \false); $declare_strict_types = (bool) ($directory['useStrictTypes'] ?? \false); if (Path::isAbsolute($directory_path)) { /** @var non-empty-string */ $prospective_directory_path = $directory_path; } else { $prospective_directory_path = $base_dir . DIRECTORY_SEPARATOR . $directory_path; } if (strpos($prospective_directory_path, '*') !== \false) { // Strip meaningless trailing recursive wildcard like "path/**/" or "path/**" $prospective_directory_path = preg_replace('#(\\/\\*\\*)+\\/?$#', '/', $prospective_directory_path); // Split by /**/, allow duplicated wildcards like "path/**/**/path" and any leading dir separator. /** @var non-empty-list $path_parts */ $path_parts = preg_split('#(\\/|\\\\)(\\*\\*\\/)+#', $prospective_directory_path); $globs = self::recursiveGlob($path_parts, \true); if (empty($globs)) { if ($allow_missing_files) { continue; } throw new ConfigException('Could not resolve config path to ' . $base_dir . DIRECTORY_SEPARATOR . $directory_path); } foreach ($globs as $glob_index => $glob_directory_path) { if (!$glob_directory_path) { if ($allow_missing_files) { continue; } throw new ConfigException('Could not resolve config path to ' . $base_dir . DIRECTORY_SEPARATOR . $directory_path . ':' . $glob_index); } if ($ignore_type_stats && $filter instanceof \Psalm\Config\ProjectFileFilter) { $filter->ignore_type_stats[$glob_directory_path] = \true; } if ($declare_strict_types && $filter instanceof \Psalm\Config\ProjectFileFilter) { $filter->declare_strict_types[$glob_directory_path] = \true; } $filter->addDirectory($glob_directory_path); } continue; } $directory_path = realpath($prospective_directory_path); if (!$directory_path) { if ($allow_missing_files) { continue; } throw new ConfigException('Could not resolve config path to ' . $prospective_directory_path); } if (!is_dir($directory_path)) { throw new ConfigException($base_dir . DIRECTORY_SEPARATOR . $directory_path . ' is not a directory'); } if ($resolve_symlinks) { /** @var RecursiveDirectoryIterator */ $iterator = new RecursiveIteratorIterator(new RecursiveDirectoryIterator($directory_path, FilesystemIterator::SKIP_DOTS)); $iterator->rewind(); while ($iterator->valid()) { if ($iterator->isLink()) { $linked_path = readlink($iterator->getPathname()); if (stripos($linked_path, $directory_path) !== 0) { if ($ignore_type_stats && $filter instanceof \Psalm\Config\ProjectFileFilter) { $filter->ignore_type_stats[$directory_path] = \true; } if ($declare_strict_types && $filter instanceof \Psalm\Config\ProjectFileFilter) { $filter->declare_strict_types[$directory_path] = \true; } if (is_dir($linked_path)) { $filter->addDirectory($linked_path); } } } $iterator->next(); } $iterator->next(); } if ($ignore_type_stats && $filter instanceof \Psalm\Config\ProjectFileFilter) { $filter->ignore_type_stats[$directory_path] = \true; } if ($declare_strict_types && $filter instanceof \Psalm\Config\ProjectFileFilter) { $filter->declare_strict_types[$directory_path] = \true; } $filter->addDirectory($directory_path); } } if (isset($config['file']) && is_iterable($config['file'])) { /** @var array $file */ foreach ($config['file'] as $file) { $file_path = (string) ($file['name'] ?? ''); if (Path::isAbsolute($file_path)) { /** @var non-empty-string */ $prospective_file_path = $file_path; } else { $prospective_file_path = $base_dir . DIRECTORY_SEPARATOR . $file_path; } if (strpos($prospective_file_path, '*') !== \false) { // Split by /**/, allow duplicated wildcards like "path/**/**/path" and any leading dir separator. /** @var non-empty-list $path_parts */ $path_parts = preg_split('#(\\/|\\\\)(\\*\\*\\/)+#', $prospective_file_path); $globs = self::recursiveGlob($path_parts, \false); if (empty($globs)) { if ($allow_missing_files) { continue; } throw new ConfigException('Could not resolve config path to ' . $base_dir . DIRECTORY_SEPARATOR . $file_path); } foreach ($globs as $glob_index => $glob_file_path) { if (!$glob_file_path) { if ($allow_missing_files) { continue; } throw new ConfigException('Could not resolve config path to ' . $base_dir . DIRECTORY_SEPARATOR . $file_path . ':' . $glob_index); } $filter->addFile($glob_file_path); } continue; } $file_path = realpath($prospective_file_path); if (!$file_path && !$allow_missing_files) { throw new ConfigException('Could not resolve config path to ' . $prospective_file_path); } $filter->addFile($file_path); } } if (isset($config['referencedClass']) && is_iterable($config['referencedClass'])) { /** @var array $referenced_class */ foreach ($config['referencedClass'] as $referenced_class) { $class_name = strtolower((string) ($referenced_class['name'] ?? '')); if (strpos($class_name, '*') !== \false) { $regex = '/' . str_replace('*', '.*', str_replace('\\', '\\\\', $class_name)) . '/i'; $filter->fq_classlike_patterns[] = $regex; } else { $filter->fq_classlike_names[] = $class_name; } } } if (isset($config['referencedMethod']) && is_iterable($config['referencedMethod'])) { /** @var array $referenced_method */ foreach ($config['referencedMethod'] as $referenced_method) { $method_id = $referenced_method['name'] ?? ''; if (!is_string($method_id) || !preg_match('/^[^:]+::[^:]+$/', $method_id) && !static::isRegularExpression($method_id)) { throw new ConfigException('Invalid referencedMethod ' . (string) $method_id); } if ($method_id === '') { continue; } $filter->method_ids[] = strtolower($method_id); } } if (isset($config['referencedFunction']) && is_iterable($config['referencedFunction'])) { /** @var array $referenced_function */ foreach ($config['referencedFunction'] as $referenced_function) { $function_id = $referenced_function['name'] ?? ''; if (!is_string($function_id) || !preg_match('/^[a-zA-Z_\\x80-\\xff](?:[\\\\]?[a-zA-Z0-9_\\x80-\\xff]+)*$/', $function_id) && !preg_match('/^[^:]+::[^:]+$/', $function_id) && !static::isRegularExpression($function_id)) { throw new ConfigException('Invalid referencedFunction ' . (string) $function_id); } if ($function_id === '') { continue; } $filter->method_ids[] = strtolower($function_id); } } if (isset($config['referencedProperty']) && is_iterable($config['referencedProperty'])) { /** @var array $referenced_property */ foreach ($config['referencedProperty'] as $referenced_property) { $filter->property_ids[] = strtolower((string) ($referenced_property['name'] ?? '')); } } if (isset($config['referencedConstant']) && is_iterable($config['referencedConstant'])) { /** @var array $referenced_constant */ foreach ($config['referencedConstant'] as $referenced_constant) { $filter->class_constant_ids[] = strtolower((string) ($referenced_constant['name'] ?? '')); } } if (isset($config['referencedVariable']) && is_iterable($config['referencedVariable'])) { /** @var array $referenced_variable */ foreach ($config['referencedVariable'] as $referenced_variable) { $filter->var_names[] = strtolower((string) ($referenced_variable['name'] ?? '')); } } return $filter; } /** * @return static */ public static function loadFromXMLElement(SimpleXMLElement $e, string $base_dir, bool $inclusive) { $config = []; $config['allowMissingFiles'] = (string) $e['allowMissingFiles'] === 'true'; if ($e->directory) { $config['directory'] = []; foreach ($e->directory as $directory) { $config['directory'][] = ['name' => (string) $directory['name'], 'ignoreTypeStats' => strtolower((string) ($directory['ignoreTypeStats'] ?? '')) === 'true', 'resolveSymlinks' => strtolower((string) ($directory['resolveSymlinks'] ?? '')) === 'true', 'useStrictTypes' => strtolower((string) ($directory['useStrictTypes'] ?? '')) === 'true']; } } if ($e->file) { $config['file'] = []; foreach ($e->file as $file) { $config['file'][]['name'] = (string) $file['name']; } } if ($e->referencedClass) { $config['referencedClass'] = []; foreach ($e->referencedClass as $referenced_class) { $config['referencedClass'][]['name'] = strtolower((string) $referenced_class['name']); } } if ($e->referencedMethod) { $config['referencedMethod'] = []; foreach ($e->referencedMethod as $referenced_method) { $config['referencedMethod'][]['name'] = (string) $referenced_method['name']; } } if ($e->referencedFunction) { $config['referencedFunction'] = []; foreach ($e->referencedFunction as $referenced_function) { $config['referencedFunction'][]['name'] = strtolower((string) $referenced_function['name']); } } if ($e->referencedProperty) { $config['referencedProperty'] = []; foreach ($e->referencedProperty as $referenced_property) { $config['referencedProperty'][]['name'] = strtolower((string) $referenced_property['name']); } } if ($e->referencedConstant) { $config['referencedConstant'] = []; foreach ($e->referencedConstant as $referenced_constant) { $config['referencedConstant'][]['name'] = strtolower((string) $referenced_constant['name']); } } if ($e->referencedVariable) { $config['referencedVariable'] = []; foreach ($e->referencedVariable as $referenced_variable) { $config['referencedVariable'][]['name'] = strtolower((string) $referenced_variable['name']); } } return self::loadFromArray($config, $base_dir, $inclusive); } /** * @psalm-assert-if-true non-empty-string $string */ private static function isRegularExpression(string $string) : bool { if ($string === '') { return \false; } set_error_handler(static fn(): bool => \true, E_WARNING); $is_regexp = preg_match($string, '') !== \false; restore_error_handler(); return $is_regexp; } /** * @mutation-free * @param non-empty-list $parts * @return array */ private static function recursiveGlob(array $parts, bool $only_dir) : array { if (count($parts) < 2) { if ($only_dir) { $list = glob($parts[0], GLOB_ONLYDIR | GLOB_NOSORT) ?: []; } else { $list = array_filter(glob($parts[0], GLOB_NOSORT) ?: [], 'file_exists'); } return array_map('realpath', $list); } $first_dir = self::slashify($parts[0]); $paths = glob($first_dir . '*', GLOB_ONLYDIR | GLOB_NOSORT); $result = []; foreach ($paths as $path) { $parts[0] = $path; $result = array_merge($result, self::recursiveGlob($parts, $only_dir)); } array_shift($parts); $parts[0] = $first_dir . $parts[0]; return array_merge($result, self::recursiveGlob($parts, $only_dir)); } /** * @psalm-pure */ protected static function slashify(string $str) : string { return rtrim($str, DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR; } public function allows(string $file_name, bool $case_sensitive = \false) : bool { if ($this->inclusive) { foreach ($this->directories as $include_dir) { if ($case_sensitive) { if (strpos($file_name, $include_dir) === 0) { return \true; } } else { if (stripos($file_name, $include_dir) === 0) { return \true; } } } if ($case_sensitive) { if (in_array($file_name, $this->files, \true)) { return \true; } } else { if (in_array(strtolower($file_name), $this->files_lowercase, \true)) { return \true; } } return \false; } // exclusive foreach ($this->directories as $exclude_dir) { if ($case_sensitive) { if (strpos($file_name, $exclude_dir) === 0) { return \false; } } else { if (stripos($file_name, $exclude_dir) === 0) { return \false; } } } if ($case_sensitive) { if (in_array($file_name, $this->files, \true)) { return \false; } } else { if (in_array(strtolower($file_name), $this->files_lowercase, \true)) { return \false; } } return \true; } public function allowsClass(string $fq_classlike_name) : bool { if ($this->fq_classlike_patterns) { foreach ($this->fq_classlike_patterns as $pattern) { if (preg_match($pattern, $fq_classlike_name)) { return \true; } } } return in_array(strtolower($fq_classlike_name), $this->fq_classlike_names, \true); } public function allowsMethod(string $method_id) : bool { if (!$this->method_ids) { return \false; } if (preg_match('/^[^:]+::[^:]+$/', $method_id)) { $method_stub = '*::' . explode('::', $method_id)[1]; foreach ($this->method_ids as $config_method_id) { if ($config_method_id === $method_id) { return \true; } if ($config_method_id === $method_stub) { return \true; } if ($config_method_id[0] === '/' && preg_match($config_method_id, $method_id)) { return \true; } } return \false; } return in_array($method_id, $this->method_ids, \true); } public function allowsProperty(string $property_id) : bool { return in_array(strtolower($property_id), $this->property_ids, \true); } public function allowsClassConstant(string $constant_id) : bool { return in_array(strtolower($constant_id), $this->class_constant_ids, \true); } public function allowsVariable(string $var_name) : bool { return in_array(strtolower($var_name), $this->var_names, \true); } /** * @return array */ public function getDirectories() : array { return $this->directories; } /** * @return array */ public function getFiles() : array { return $this->files; } public function addFile(string $file_name) : void { $this->files[] = $file_name; $this->files_lowercase[] = strtolower($file_name); } public function addDirectory(string $dir_name) : void { $this->directories[] = self::slashify($dir_name); } } error_level = (string) $config['type']; if (!in_array($filter->error_level, Config::$ERROR_LEVELS, \true)) { throw new ConfigException('Unexpected error level ' . $filter->error_level); } } else { throw new ConfigException(' element expects a level'); } return $filter; } /** * @return static */ public static function loadFromXMLElement(SimpleXMLElement $e, string $base_dir, bool $inclusive) : \Psalm\Config\ErrorLevelFileFilter { $filter = parent::loadFromXMLElement($e, $base_dir, $inclusive); if (isset($e['type'])) { $filter->error_level = (string) $e['type']; if (!in_array($filter->error_level, Config::$ERROR_LEVELS, \true)) { throw new ConfigException('Unexpected error level ' . $filter->error_level); } } else { throw new ConfigException(' element expects a level'); } return $filter; } public function getErrorLevel() : string { return $this->error_level; } } ignoreFiles)) { if (!$inclusive) { throw new ConfigException('Cannot nest ignoreFiles inside itself'); } $filter->file_filter = static::loadFromXMLElement($e->ignoreFiles, $base_dir, \false); } return $filter; } public function allows(string $file_name, bool $case_sensitive = \false) : bool { if ($this->inclusive && $this->file_filter) { if (!$this->file_filter->allows($file_name, $case_sensitive)) { return \false; } } return parent::allows($file_name, $case_sensitive); } public function forbids(string $file_name, bool $case_sensitive = \false) : bool { if ($this->inclusive && $this->file_filter) { if (!$this->file_filter->allows($file_name, $case_sensitive)) { return \true; } } return \false; } public function reportTypeStats(string $file_name, bool $case_sensitive = \false) : bool { foreach ($this->ignore_type_stats as $exclude_dir => $_) { if ($case_sensitive) { if (strpos($file_name, $exclude_dir) === 0) { return \false; } } else { if (stripos($file_name, $exclude_dir) === 0) { return \false; } } } return \true; } public function useStrictTypes(string $file_name, bool $case_sensitive = \false) : bool { foreach ($this->declare_strict_types as $exclude_dir => $_) { if ($case_sensitive) { if (strpos($file_name, $exclude_dir) === 0) { return \true; } } else { if (stripos($file_name, $exclude_dir) === 0) { return \true; } } } return \false; } } */ private array $custom_levels = []; public static function loadFromXMLElement(SimpleXMLElement $e, string $base_dir) : \Psalm\Config\IssueHandler { $handler = new self(); if (isset($e['errorLevel'])) { $handler->error_level = (string) $e['errorLevel']; if (!in_array($handler->error_level, Config::$ERROR_LEVELS, \true)) { throw new ConfigException('Unexpected error level ' . $handler->error_level); } } if (isset($e->errorLevel)) { foreach ($e->errorLevel as $error_level) { $handler->custom_levels[] = \Psalm\Config\ErrorLevelFileFilter::loadFromXMLElement($error_level, $base_dir, \true); } } return $handler; } public function setCustomLevels(array $customLevels, string $base_dir) : void { /** @var array $customLevel */ foreach ($customLevels as $customLevel) { $this->custom_levels[] = \Psalm\Config\ErrorLevelFileFilter::loadFromArray($customLevel, $base_dir, \true); } } public function setErrorLevel(string $error_level) : void { if (!in_array($error_level, Config::$ERROR_LEVELS, \true)) { throw new ConfigException('Unexpected error level ' . $error_level); } $this->error_level = $error_level; } public function getReportingLevelForFile(string $file_path) : string { foreach ($this->custom_levels as $custom_level) { if ($custom_level->allows($file_path)) { return $custom_level->getErrorLevel(); } } return $this->error_level; } public function getReportingLevelForClass(string $fq_classlike_name) : ?string { foreach ($this->custom_levels as $custom_level) { if ($custom_level->allowsClass($fq_classlike_name)) { return $custom_level->getErrorLevel(); } } return null; } public function getReportingLevelForMethod(string $method_id) : ?string { foreach ($this->custom_levels as $custom_level) { if ($custom_level->allowsMethod(strtolower($method_id))) { return $custom_level->getErrorLevel(); } } return null; } public function getReportingLevelForFunction(string $function_id) : ?string { foreach ($this->custom_levels as $custom_level) { if ($custom_level->allowsMethod(strtolower($function_id))) { return $custom_level->getErrorLevel(); } } return null; } public function getReportingLevelForArgument(string $function_id) : ?string { foreach ($this->custom_levels as $custom_level) { if ($custom_level->allowsMethod(strtolower($function_id))) { return $custom_level->getErrorLevel(); } } return null; } public function getReportingLevelForProperty(string $property_id) : ?string { foreach ($this->custom_levels as $custom_level) { if ($custom_level->allowsProperty($property_id)) { return $custom_level->getErrorLevel(); } } return null; } public function getReportingLevelForClassConstant(string $constant_id) : ?string { foreach ($this->custom_levels as $custom_level) { if ($custom_level->allowsClassConstant($constant_id)) { return $custom_level->getErrorLevel(); } } return null; } public function getReportingLevelForVariable(string $var_name) : ?string { foreach ($this->custom_levels as $custom_level) { if ($custom_level->allowsVariable($var_name)) { return $custom_level->getErrorLevel(); } } return null; } /** * @return array */ public static function getAllIssueTypes() : array { return array_filter(array_map(static fn(string $file_name): string => substr($file_name, 0, -4), scandir(dirname(__DIR__) . '/Issue', SCANDIR_SORT_NONE)), static fn(string $issue_name): bool => $issue_name !== '' && $issue_name !== 'MethodIssue' && $issue_name !== 'PropertyIssue' && $issue_name !== 'ClassConstantIssue' && $issue_name !== 'FunctionIssue' && $issue_name !== 'ArgumentIssue' && $issue_name !== 'VariableIssue' && $issue_name !== 'ClassIssue' && $issue_name !== 'CodeIssue' && $issue_name !== 'PsalmInternalError' && $issue_name !== 'ParseError' && $issue_name !== 'PluginIssue' && $issue_name !== 'MixedIssue' && $issue_name !== 'MixedIssueTrait'); } } config = $config; $this->codebase = $codebase; } public function addStubFile(string $file_name) : void { $this->config->addStubFile($file_name); } public function registerHooksFromClass(string $handler) : void { if (!class_exists($handler, \false)) { throw new InvalidArgumentException('Plugins must be loaded before registration'); } $this->config->eventDispatcher->registerClass($handler); if (is_subclass_of($handler, PropertyExistenceProviderInterface::class)) { $this->codebase->properties->property_existence_provider->registerClass($handler); } if (is_subclass_of($handler, PropertyVisibilityProviderInterface::class)) { $this->codebase->properties->property_visibility_provider->registerClass($handler); } if (is_subclass_of($handler, PropertyTypeProviderInterface::class)) { $this->codebase->properties->property_type_provider->registerClass($handler); } if (is_subclass_of($handler, MethodExistenceProviderInterface::class)) { $this->codebase->methods->existence_provider->registerClass($handler); } if (is_subclass_of($handler, MethodVisibilityProviderInterface::class)) { $this->codebase->methods->visibility_provider->registerClass($handler); } if (is_subclass_of($handler, MethodReturnTypeProviderInterface::class)) { $this->codebase->methods->return_type_provider->registerClass($handler); } if (is_subclass_of($handler, MethodParamsProviderInterface::class)) { $this->codebase->methods->params_provider->registerClass($handler); } if (is_subclass_of($handler, FunctionExistenceProviderInterface::class)) { $this->codebase->functions->existence_provider->registerClass($handler); } if (is_subclass_of($handler, FunctionParamsProviderInterface::class)) { $this->codebase->functions->params_provider->registerClass($handler); } if (is_subclass_of($handler, FunctionReturnTypeProviderInterface::class)) { $this->codebase->functions->return_type_provider->registerClass($handler); } if (is_subclass_of($handler, DynamicFunctionStorageProviderInterface::class)) { $this->codebase->functions->dynamic_storage_provider->registerClass($handler); } } } > */ private array $additionalFileTypeScanners = []; /** * @var array> */ private array $additionalFileTypeAnalyzers = []; /** * @var list */ private array $additionalFileExtensions = []; /** * @internal */ public function __construct(\Psalm\Config $config) { $this->config = $config; } /** * @param string $fileExtension e.g. `'html'` * @param class-string $className */ public function addFileTypeScanner(string $fileExtension, string $className) : void { if (!class_exists($className) || !is_a($className, FileScanner::class, \true)) { throw new LogicException(sprintf('Class %s must be of type %s', $className, FileScanner::class), 1622727271); } if (isset($this->config->getFiletypeScanners()[$fileExtension]) || isset($this->additionalFileTypeScanners[$fileExtension])) { throw new LogicException(sprintf('Cannot redeclare scanner for file-type %s', $fileExtension), 1622727272); } $this->additionalFileTypeScanners[$fileExtension] = $className; $this->addFileExtension($fileExtension); } /** * @return array> */ public function getAdditionalFileTypeScanners() : array { return $this->additionalFileTypeScanners; } /** * @param string $fileExtension e.g. `'html'` * @param class-string $className */ public function addFileTypeAnalyzer(string $fileExtension, string $className) : void { if (!class_exists($className) || !is_a($className, FileAnalyzer::class, \true)) { throw new LogicException(sprintf('Class %s must be of type %s', $className, FileAnalyzer::class), 1622727281); } if (isset($this->config->getFiletypeAnalyzers()[$fileExtension]) || isset($this->additionalFileTypeAnalyzers[$fileExtension])) { throw new LogicException(sprintf('Cannot redeclare analyzer for file-type %s', $fileExtension), 1622727282); } $this->additionalFileTypeAnalyzers[$fileExtension] = $className; $this->addFileExtension($fileExtension); } /** * @return array> */ public function getAdditionalFileTypeAnalyzers() : array { return $this->additionalFileTypeAnalyzers; } /** * @return list e.g. `['html', 'perl']` */ public function getAdditionalFileExtensions() : array { return $this->additionalFileExtensions; } /** * @param string $fileExtension e.g. `'html'` */ private function addFileExtension(string $fileExtension) : void { /** @psalm-suppress RedundantCondition */ if (!in_array($fileExtension, $this->additionalFileExtensions, \true) && !in_array($fileExtension, $this->config->getFileExtensions(), \true)) { $this->additionalFileExtensions[] = $fileExtension; } } } */ public $byref_uses = []; /** * @var bool * @todo lift this property to FunctionLikeStorage in Psalm 6 */ public $is_static = \false; } value = $value; $this->stmt_location = $location; } /** @return int|string|null */ public function getValue(ClassLikes $classlikes) { $case_value = $this->value; if ($case_value instanceof UnresolvedConstantComponent) { $case_value = ConstantTypeResolver::resolve($classlikes, $case_value); if ($case_value instanceof TLiteralString) { $case_value = $case_value->value; } elseif ($case_value instanceof TLiteralInt) { $case_value = $case_value->value; } else { throw new UnexpectedValueException('Failed to infer case value'); } } return $case_value; } } */ public $params = []; /** * @psalm-readonly-allow-private-mutation * @var array */ public $param_lookup = []; /** * @var Union|null */ public $return_type; /** * @var CodeLocation|null */ public $return_type_location; /** * @var Union|null */ public $signature_return_type; /** * @var CodeLocation|null */ public $signature_return_type_location; /** * @var ?string */ public $cased_name; /** * @var array */ public $suppressed_issues = []; /** * @var ?bool */ public $deprecated; /** * @var list */ public $internal = []; /** * @var bool */ public $variadic = \false; /** * @var bool */ public $returns_by_ref = \false; /** * @var ?int */ public $required_param_count; /** * @var array */ public $defined_constants = []; /** * @var array */ public $global_variables = []; /** * @var array */ public $global_types = []; /** * An array holding the class template "as" types. * * It's the de-facto list of all templates on a given class. * * The name of the template is the first key. The nested array is keyed by a unique * function identifier. This allows operations with the same-named template defined * across multiple classes and/or functions to not run into trouble. * * @var array>|null */ public $template_types; /** * @var array */ public $assertions = []; /** * @var array */ public $if_true_assertions = []; /** * @var array */ public $if_false_assertions = []; /** * @var bool */ public $has_visitor_issues = \false; /** * @var list */ public $docblock_issues = []; /** * @var array */ public $throws = []; /** * @var array */ public $throw_locations = []; /** * @var bool */ public $has_yield = \false; /** * @var bool */ public $mutation_free = \false; /** * @var string|null */ public $return_type_description; /** * @psalm-suppress PossiblyUnusedProperty * @var array|null * @deprecated will be removed in Psalm 6. use {@see FunctionLikeStorage::$unused_docblock_parameters} instead */ public $unused_docblock_params; /** * @var array */ public array $unused_docblock_parameters = []; public bool $has_undertyped_native_parameters = \false; /** * @var bool */ public $pure = \false; /** * Whether or not the function output is dependent solely on input - a function can be * impure but still have this property (e.g. var_export). Useful for taint analysis. * * @var bool */ public $specialize_call = \false; /** * @var array */ public $taint_source_types = []; /** * @var array */ public $added_taints = []; /** * @var array */ public $removed_taints = []; /** * @var array */ public $conditionally_removed_taints = []; /** * @var array */ public $return_source_params = []; /** * @var bool */ public $allow_named_arg_calls = \true; /** * @var list */ public $attributes = []; /** * @var list, return: bool}>|null */ public $proxy_calls = []; /** * @var ?string */ public $description; public bool $public_api = \false; /** * Used in the Language Server */ public function getHoverMarkdown() : string { $params = count($this->params) > 0 ? "\n" . implode(",\n", array_map(static function (\Psalm\Storage\FunctionLikeParameter $param) : string { $realType = $param->type ?: 'mixed'; return " {$realType} \${$param->name}"; }, $this->params)) . "\n" : ''; $return_type = $this->return_type ?: 'mixed'; $symbol_text = "function {$this->cased_name}({$params}): {$return_type}"; if (!$this instanceof \Psalm\Storage\MethodStorage) { return $symbol_text; } switch ($this->visibility) { case ClassLikeAnalyzer::VISIBILITY_PRIVATE: $visibility_text = 'private'; break; case ClassLikeAnalyzer::VISIBILITY_PROTECTED: $visibility_text = 'protected'; break; default: $visibility_text = 'public'; } return $visibility_text . ' ' . $symbol_text; } public function getCompletionSignature() : string { $symbol_text = 'function ' . $this->cased_name . '(' . implode(',', array_map(static fn(\Psalm\Storage\FunctionLikeParameter $param): string => ($param->type ?: 'mixed') . ' $' . $param->name, $this->params)) . ') : ' . ($this->return_type ?: 'mixed'); if (!$this instanceof \Psalm\Storage\MethodStorage) { return $symbol_text; } switch ($this->visibility) { case ClassLikeAnalyzer::VISIBILITY_PRIVATE: $visibility_text = 'private'; break; case ClassLikeAnalyzer::VISIBILITY_PROTECTED: $visibility_text = 'protected'; break; default: $visibility_text = 'public'; } return $visibility_text . ' ' . $symbol_text; } /** * @internal * @param list $params */ public function setParams(array $params) : void { $this->params = $params; $param_names = array_column($params, 'name'); $this->param_lookup = array_fill_keys($param_names, \true); } /** * @internal */ public function addParam(\Psalm\Storage\FunctionLikeParameter $param, ?bool $lookup_value = null) : void { $this->params[] = $param; $this->param_lookup[$param->name] = $lookup_value ?? \true; } /** * @return list */ public function getAttributeStorages() : array { return $this->attributes; } public function __toString() : string { return $this->getCompletionSignature(); } /** * @deprecated will be removed in Psalm 6. use {@see FunctionLikeStorage::getCompletionSignature()} instead * @psalm-suppress PossiblyUnusedParam, PossiblyUnusedMethod */ public function getSignature(bool $allow_newlines) : string { return $this->getCompletionSignature(); } } */ public $this_property_mutations; /** * @var Union|null */ public $self_out_type; /** * @var Union|null */ public $if_this_is_type = null; /** * @var bool */ public $stubbed = \false; /** * @var bool */ public $probably_fluent = \false; } the rule being asserted */ public $rule; /** * @var int|string the id of the property/variable, or * the parameter offset of the affected arg */ public $var_id; /** * @param string|int $var_id * @param list $rule */ public function __construct($var_id, array $rule) { $this->rule = $rule; $this->var_id = $var_id; } public function getUntemplatedCopy(TemplateResult $template_result, ?string $this_var_id, ?Codebase $codebase) : self { $assertion_rules = []; foreach ($this->rule as $assertion) { $assertion_type = $assertion->getAtomicType(); if ($assertion_type) { $union = new Union([$assertion_type]); $union = TemplateInferredTypeReplacer::replace($union, $template_result, $codebase); foreach ($union->getAtomicTypes() as $atomic_type) { $assertion = $assertion->setAtomicType($atomic_type); $assertion_rules[] = $assertion; } } else { $assertion_rules[] = $assertion; } } return new \Psalm\Storage\Possibilities(is_string($this->var_id) && $this_var_id ? str_replace('$this->', $this_var_id . '->', $this->var_id) : $this->var_id, $assertion_rules); } } |null */ public $sinks; /** * @var bool */ public $assert_untainted = \false; /** * @var bool */ public $type_inferred = \false; /** * @var bool */ public $expect_variable = \false; /** * @var bool */ public $promoted_property = \false; /** * @var list */ public $attributes = []; /** * @var ?string */ public $description; /** * @psalm-external-mutation-free * @param Union|UnresolvedConstantComponent|null $default_type */ public function __construct(string $name, bool $by_ref, ?Union $type = null, ?Union $signature_type = null, ?CodeLocation $location = null, ?CodeLocation $type_location = null, bool $is_optional = \true, bool $is_nullable = \false, bool $is_variadic = \false, $default_type = null, ?Union $out_type = null) { $this->name = $name; $this->by_ref = $by_ref; $this->type = $type; $this->signature_type = $signature_type; $this->is_optional = $is_optional; $this->is_nullable = $is_nullable; $this->is_variadic = $is_variadic; $this->location = $location; $this->type_location = $type_location; $this->signature_type_location = $type_location; $this->default_type = $default_type; $this->out_type = $out_type; } /** @psalm-mutation-free */ public function getId() : string { return ($this->type ? $this->type->getId() : 'mixed') . ($this->is_variadic ? '...' : '') . ($this->is_optional ? '=' : ''); } /** @psalm-mutation-free */ public function setType(Union $type) : self { if ($this->type === $type) { return $this; } $cloned = clone $this; $cloned->type = $type; return $cloned; } /** * @internal Should only be used by the MutableTypeVisitor. * @psalm-mutation-free */ public function visit(TypeVisitor $visitor) : bool { if ($this->type && !$visitor->traverse($this->type)) { return \false; } if ($this->signature_type && !$visitor->traverse($this->signature_type)) { return \false; } if ($this->out_type && !$visitor->traverse($this->out_type)) { return \false; } if ($this->default_type instanceof Union && !$visitor->traverse($this->default_type)) { return \false; } return \true; } /** * @phpcsSuppress SlevomatCodingStandard.TypeHints.ParameterTypeHint.MissingAnyTypeHint */ public static function visitMutable(MutableTypeVisitor $visitor, &$node, bool $cloned) : bool { foreach (['type', 'signature_type', 'out_type', 'default_type'] as $key) { if (!$node->{$key} instanceof TypeNode) { continue; } /** @var TypeNode */ $value = $node->{$key}; $value_orig = $value; $result = $visitor->traverse($value); if ($value !== $value_orig) { if (!$cloned) { $node = clone $node; $cloned = \true; } $node->{$key} = $value; } if (!$result) { return \false; } } return \true; } /** * @psalm-mutation-free * @return list */ public function getAttributeStorages() : array { return $this->attributes; } } * @psalm-suppress PossiblyUnusedMethod part of public API */ public function getAttributeStorages() : array; } $value) { $this->{$key} = $value; } } } */ public $constants = []; /** * Aliases to help Psalm understand constant refs * * @var ?Aliases */ public $aliases; /** * @var bool */ public $populated = \false; /** * @var bool */ public $stubbed = \false; /** * @var bool */ public $deprecated = \false; /** * @var list */ public $internal = []; /** * @var TTemplateParam[] */ public $templatedMixins = []; /** * @var list */ public $namedMixins = []; /** * @var ?string */ public $mixin_declaring_fqcln; /** * @var ?bool */ public $sealed_properties = null; /** * @var ?bool */ public $sealed_methods = null; /** * @var bool */ public $override_property_visibility = \false; /** * @var bool */ public $override_method_visibility = \false; /** * @var array */ public $suppressed_issues = []; /** * @var string */ public $name; /** * Is this class user-defined * * @var bool */ public $user_defined = \false; /** * Interfaces this class implements directly * * @var array */ public $direct_class_interfaces = []; /** * Interfaces this class implements explicitly and implicitly * * @var array */ public $class_implements = []; /** * Parent interfaces listed explicitly * * @var array */ public $direct_interface_parents = []; /** * Parent interfaces * * @var array */ public $parent_interfaces = []; /** * There can only be one direct parent class * * @var ?string */ public $parent_class; /** * Parent classes * * @var array */ public $parent_classes = []; /** * @var CodeLocation|null */ public $location; /** * @var CodeLocation|null */ public $stmt_location; /** * @var CodeLocation|null */ public $namespace_name_location; /** * @var bool */ public $abstract = \false; /** * @var bool */ public $final = \false; /** * @var bool */ public $final_from_docblock = \false; /** * @var array */ public $used_traits = []; /** * @var array */ public $trait_alias_map = []; /** * @var array */ public array $trait_alias_map_cased = []; /** * @var array */ public $trait_final_map = []; /** * @var array */ public $trait_visibility_map = []; /** * @var bool */ public $is_trait = \false; /** * @var bool */ public $is_interface = \false; /** * @var bool */ public $is_enum = \false; /** * @var bool */ public $external_mutation_free = \false; /** * @var bool */ public $mutation_free = \false; /** * @var bool */ public $specialize_instance = \false; /** * @var array */ public $methods = []; /** * @var array */ public $pseudo_methods = []; /** * @var array */ public $pseudo_static_methods = []; /** * Maps pseudo method names to the original declaring method identifier * The key is the method name in lowercase, and the value is the original `MethodIdentifier` instance * * This property contains all pseudo methods declared on ancestors. * * @var array */ public $declaring_pseudo_method_ids = []; /** * @var array */ public $declaring_method_ids = []; /** * @var array */ public $appearing_method_ids = []; /** * Map from lowercase method name to list of declarations in order from parent, to grandparent, to * great-grandparent, etc **including traits and interfaces**. Ancestors that don't have their own declaration are * skipped. * * @var array> */ public $overridden_method_ids = []; /** * @var array */ public $documenting_method_ids = []; /** * @var array */ public $inheritable_method_ids = []; /** * @var array> */ public $potential_declaring_method_ids = []; /** * @var array */ public $properties = []; /** * @var array */ public $pseudo_property_set_types = []; /** * @var array */ public $pseudo_property_get_types = []; /** * @var array */ public $declaring_property_ids = []; /** * @var array */ public $appearing_property_ids = []; /** * @var ?Union */ public $inheritors = null; /** * @var array */ public $inheritable_property_ids = []; /** * @var array> */ public $overridden_property_ids = []; /** * An array holding the class template "as" types. * * It's the de-facto list of all templates on a given class. * * The name of the template is the first key. The nested array is keyed by the defining class * (i.e. the same as the class name). This allows operations with the same-named template defined * across multiple classes to not run into trouble. * * @var array>|null */ public $template_types; /** * @var array|null */ public $template_covariants; /** * A map of which generic classlikes are extended or implemented by this class or interface. * * This is only used in the populator, which poulates the $template_extended_params property below. * * @internal * @var array>|null */ public $template_extended_offsets; /** * A map of which generic classlikes are extended or implemented by this class or interface. * * The annotation "@extends Traversable" would generate an entry of * * [ * "Traversable" => [ * "TKey" => new Union([new TNamedObject("SomeClass")]), * "TValue" => new Union([new TNamedObject("SomeOtherClass")]) * ] * ] * * @var array>|null */ public $template_extended_params; /** * @var array|null */ public $template_type_extends_count; /** * @var array|null */ public $template_type_implements_count; /** * @var ?Union */ public $yield; /** @var ?string */ public $declaring_yield_fqcn; /** * @var array|null */ public $template_type_uses_count; /** * @var array */ public $initialized_properties = []; /** * @var array */ public $invalid_dependencies = []; /** * @var array */ public $dependent_classlikes = []; /** * A hash of the source file's name, contents, and this file's modified on date * * @var string */ public $hash = ''; /** * @var bool */ public $has_visitor_issues = \false; /** * @var list */ public $docblock_issues = []; /** * @var array */ public $type_aliases = []; /** * @var bool */ public $preserve_constructor_signature = \false; /** * @var bool */ public $enforce_template_inheritance = \false; /** * @var null|string */ public $extension_requirement; /** * @var array */ public $implementation_requirements = []; /** * @var list */ public $attributes = []; /** * @var array */ public $enum_cases = []; /** * @var 'int'|'string'|null */ public $enum_type; /** * @var ?string */ public $description; public bool $public_api = \false; public bool $readonly = \false; public function __construct(string $name) { $this->name = $name; } /** * @return list */ public function getAttributeStorages() : array { return $this->attributes; } public function hasAttributeIncludingParents(string $fq_class_name, Codebase $codebase) : bool { if ($this->hasAttribute($fq_class_name)) { return \true; } foreach ($this->parent_classes as $parent_class) { // skip missing dependencies if (!$codebase->classlike_storage_provider->has($parent_class)) { continue; } $parent_class_storage = $codebase->classlike_storage_provider->get($parent_class); if ($parent_class_storage->hasAttribute($fq_class_name)) { return \true; } } return \false; } /** * Get the template constraint types for the class. * * @return list */ public function getClassTemplateTypes() : array { $type_params = []; foreach ($this->template_types ?? [] as $type_map) { $type_params[] = array_values($type_map)[0]; } return $type_params; } public function hasSealedProperties(Config $config) : bool { return $this->sealed_properties ?? $config->seal_all_properties; } public function hasSealedMethods(Config $config) : bool { return $this->sealed_methods ?? $config->seal_all_methods; } private function hasAttribute(string $fq_class_name) : bool { foreach ($this->attributes as $attribute) { if ($fq_class_name === $attribute->fq_class_name) { return \true; } } return \false; } /** * @return array */ public function getSuppressedIssuesForTemplateExtendParams() : array { $allowed_issue_types = [DeprecatedClass::getIssueType()]; $suppressed_issues_for_template_extend_params = []; foreach ($this->suppressed_issues as $offset => $suppressed_issue) { if (!in_array($suppressed_issue, $allowed_issue_types, \true)) { continue; } $suppressed_issues_for_template_extend_params[$offset] = $suppressed_issue; } return $suppressed_issues_for_template_extend_params; } } */ public $args; /** * @var CodeLocation * @psalm-suppress PossiblyUnusedProperty part of public API */ public $location; /** * @var CodeLocation * @psalm-suppress PossiblyUnusedProperty part of public API */ public $name_location; /** * @param list $args */ public function __construct(string $fq_class_name, array $args, CodeLocation $location, CodeLocation $name_location) { $this->fq_class_name = $fq_class_name; $this->args = $args; $this->location = $location; $this->name_location = $name_location; } } */ public array $attributes = []; /** * @var array */ public array $suppressed_issues = []; public ?string $description; /** * @param ClassLikeAnalyzer::VISIBILITY_* $visibility * @param list $attributes * @param array $suppressed_issues */ public function __construct(?Union $type, ?Union $inferred_type, int $visibility, ?CodeLocation $location, ?CodeLocation $type_location = null, ?CodeLocation $stmt_location = null, bool $deprecated = \false, bool $final = \false, ?UnresolvedConstantComponent $unresolved_node = null, array $attributes = [], array $suppressed_issues = [], ?string $description = null) { $this->visibility = $visibility; $this->location = $location; $this->type = $type; $this->inferred_type = $inferred_type; $this->type_location = $type_location; $this->stmt_location = $stmt_location; $this->deprecated = $deprecated; $this->final = $final; $this->unresolved_node = $unresolved_node; $this->attributes = $attributes; $this->suppressed_issues = $suppressed_issues; $this->description = $description; } /** * Used in the Language Server */ public function getHoverMarkdown(string $const) : string { switch ($this->visibility) { case ClassLikeAnalyzer::VISIBILITY_PRIVATE: $visibility_text = 'private'; break; case ClassLikeAnalyzer::VISIBILITY_PROTECTED: $visibility_text = 'protected'; break; default: $visibility_text = 'public'; } $value = ''; if ($this->type) { $types = $this->type->getAtomicTypes(); $type = array_values($types)[0]; if (property_exists($type, 'value')) { /** @psalm-suppress UndefinedPropertyFetch */ $value = " = {$type->value};"; } } return "{$visibility_text} const {$const}{$value}"; } } type = $type; $this->allow_string = $allow_string; } public function isNegation() : bool { return \true; } public function getNegation() : Assertion { return new \Psalm\Storage\Assertion\IsAClass($this->type, $this->allow_string); } public function getAtomicType() : Atomic { return $this->type; } public function __toString() : string { return 'isa-' . ($this->allow_string ? 'string-' : '') . $this->type; } public function isNegationOf(Assertion $assertion) : bool { return $assertion instanceof \Psalm\Storage\Assertion\IsAClass && $this->type === $assertion->type && $this->allow_string === $assertion->allow_string; } } value = $value; } public function isNegation() : bool { return \true; } public function getNegation() : Assertion { return new \Psalm\Storage\Assertion\IsLessThan($this->value); } public function __toString() : string { return '!<' . $this->value; } public function isNegationOf(Assertion $assertion) : bool { return $assertion instanceof \Psalm\Storage\Assertion\IsLessThan && $this->value === $assertion->value; } public function doesFilterNullOrFalse() : bool { return $this->value !== 0; } } key = $key; } public function getNegation() : Assertion { throw new UnexpectedValueException('This should never be called'); } public function __toString() : string { return 'has-array-key-' . $this->key; } public function isNegationOf(Assertion $assertion) : bool { return \false; } } is_negatable; } } type = $type; } public function getNegation() : Assertion { return new \Psalm\Storage\Assertion\IsNotIdentical($this->type); } public function __toString() : string { return '=' . $this->type->getAssertionString(); } public function hasEquality() : bool { return \true; } public function getAtomicType() : ?Atomic { return $this->type; } /** * @return static */ public function setAtomicType(Atomic $type) : self { return new static($type); } public function isNegationOf(Assertion $assertion) : bool { return $assertion instanceof \Psalm\Storage\Assertion\IsNotIdentical && $this->type->getId() === $assertion->type->getId(); } } value = $value; } public function getNegation() : Assertion { return new \Psalm\Storage\Assertion\IsGreaterThan($this->value); } public function isNegation() : bool { return \true; } public function __toString() : string { return '!>' . $this->value; } public function isNegationOf(Assertion $assertion) : bool { return $assertion instanceof \Psalm\Storage\Assertion\IsGreaterThan && $this->value === $assertion->value; } public function doesFilterNullOrFalse() : bool { return \false; } } is_negatable; } } >> */ public array $assertions; /** @param array>> $assertions */ public function __construct(array $assertions) { $this->assertions = $assertions; } public function getNegation() : Assertion { return new \Psalm\Storage\Assertion\NotNestedAssertions($this->assertions); } public function __toString() : string { return '@' . json_encode($this->assertions, JSON_THROW_ON_ERROR); } public function isNegationOf(Assertion $assertion) : bool { return \false; } } is_negatable = $is_negatable; } public function isNegation() : bool { return \true; } public function getNegation() : Assertion { return new \Psalm\Storage\Assertion\IsCountable(); } public function __toString() : string { return '!countable'; } public function isNegationOf(Assertion $assertion) : bool { return $assertion instanceof \Psalm\Storage\Assertion\IsCountable; } } method = $method; } public function getNegation() : Assertion { return new \Psalm\Storage\Assertion\DoesNotHaveMethod($this->method); } public function __toString() : string { return 'method-exists-' . $this->method; } public function isNegationOf(Assertion $assertion) : bool { return $assertion instanceof \Psalm\Storage\Assertion\DoesNotHaveMethod && $this->method === $assertion->method; } } is_negatable = $is_negatable; } public function getNegation() : Assertion { return $this->is_negatable ? new \Psalm\Storage\Assertion\NotNonEmptyCountable() : new \Psalm\Storage\Assertion\Any(); } public function hasEquality() : bool { return !$this->is_negatable; } public function __toString() : string { return ($this->is_negatable ? '' : '=') . 'non-empty-countable'; } public function isNegationOf(Assertion $assertion) : bool { return $this->is_negatable && $assertion instanceof \Psalm\Storage\Assertion\NotNonEmptyCountable; } } type = $type; } public function isNegation() : bool { return \true; } public function getNegation() : Assertion { return new \Psalm\Storage\Assertion\IsLooselyEqual($this->type); } public function hasEquality() : bool { return \true; } public function __toString() : string { return '!~' . $this->type->getAssertionString(); } public function getAtomicType() : ?Atomic { return $this->type; } /** * @return static */ public function setAtomicType(Atomic $type) : self { return new static($type); } public function isNegationOf(Assertion $assertion) : bool { return $assertion instanceof \Psalm\Storage\Assertion\IsLooselyEqual && $this->type->getId() === $assertion->type->getId(); } } type = $type; } public function isNegation() : bool { return \true; } public function getNegation() : Assertion { return new \Psalm\Storage\Assertion\IsType($this->type); } public function __toString() : string { return '!' . $this->type->getId(); } public function getAtomicType() : ?Atomic { return $this->type; } /** * @return static */ public function setAtomicType(Atomic $type) : self { return new static($type); } public function isNegationOf(Assertion $assertion) : bool { return $assertion instanceof \Psalm\Storage\Assertion\IsType && $this->type->getId() === $assertion->type->getId(); } } count = $count; } public function getNegation() : Assertion { return new \Psalm\Storage\Assertion\DoesNotHaveExactCount($this->count); } public function hasEquality() : bool { return \true; } public function __toString() : string { return '=has-exact-count-' . $this->count; } public function isNegationOf(Assertion $assertion) : bool { return $assertion instanceof \Psalm\Storage\Assertion\DoesNotHaveExactCount && $this->count === $assertion->count; } } type = $type; } public function getNegation() : Assertion { return new \Psalm\Storage\Assertion\IsClassNotEqual($this->type); } public function hasEquality() : bool { return \true; } public function __toString() : string { return '=get-class-' . $this->type; } public function isNegationOf(Assertion $assertion) : bool { return $assertion instanceof \Psalm\Storage\Assertion\IsClassNotEqual && $this->type === $assertion->type; } } count = $count; } public function getNegation() : Assertion { return new \Psalm\Storage\Assertion\HasAtLeastCount($this->count); } public function isNegation() : bool { return \true; } public function __toString() : string { return '!has-at-least-' . $this->count; } public function isNegationOf(Assertion $assertion) : bool { return $assertion instanceof \Psalm\Storage\Assertion\HasAtLeastCount && $this->count === $assertion->count; } } value = $value; } public function getNegation() : Assertion { return new \Psalm\Storage\Assertion\IsGreaterThanOrEqualTo($this->value); } public function __toString() : string { return '<' . $this->value; } public function isNegationOf(Assertion $assertion) : bool { return $assertion instanceof \Psalm\Storage\Assertion\IsGreaterThanOrEqualTo && $this->value === $assertion->value; } public function doesFilterNullOrFalse() : bool { return $this->value === 0; } } type = $type; } public function getNegation() : Assertion { return new \Psalm\Storage\Assertion\IsNotLooselyEqual($this->type); } public function __toString() : string { return '~' . $this->type->getAssertionString(); } public function getAtomicType() : ?Atomic { return $this->type; } public function hasEquality() : bool { return \true; } /** * @return static */ public function setAtomicType(Atomic $type) : self { return new static($type); } public function isNegationOf(Assertion $assertion) : bool { return $assertion instanceof \Psalm\Storage\Assertion\IsNotLooselyEqual && $this->type->getId() === $assertion->type->getId(); } } count = $count; } public function getNegation() : Assertion { return new \Psalm\Storage\Assertion\DoesNotHaveAtLeastCount($this->count); } public function __toString() : string { return 'has-at-least-' . $this->count; } public function isNegationOf(Assertion $assertion) : bool { return $assertion instanceof \Psalm\Storage\Assertion\DoesNotHaveAtLeastCount && $this->count === $assertion->count; } } type = $type; $this->allow_string = $allow_string; } public function getNegation() : Assertion { return new \Psalm\Storage\Assertion\IsNotAClass($this->type, $this->allow_string); } public function getAtomicType() : Atomic { return $this->type; } public function __toString() : string { return 'isa-' . ($this->allow_string ? 'string-' : '') . $this->type; } public function isNegationOf(Assertion $assertion) : bool { return $assertion instanceof \Psalm\Storage\Assertion\IsNotAClass && $this->type === $assertion->type && $this->allow_string === $assertion->allow_string; } } type = $type; } public function isNegation() : bool { return \true; } public function getNegation() : Assertion { return new \Psalm\Storage\Assertion\IsClassEqual($this->type); } public function __toString() : string { return '!=get-class-' . $this->type; } public function isNegationOf(Assertion $assertion) : bool { return $assertion instanceof \Psalm\Storage\Assertion\IsClassEqual && $this->type === $assertion->type; } } count = $count; } public function isNegation() : bool { return \true; } public function getNegation() : Assertion { return new \Psalm\Storage\Assertion\HasExactCount($this->count); } public function __toString() : string { return '!has-exact-count-' . $this->count; } public function isNegationOf(Assertion $assertion) : bool { return $assertion instanceof \Psalm\Storage\Assertion\HasExactCount && $assertion->count === $this->count; } } type = $type; } public function isNegation() : bool { return \true; } public function getNegation() : Assertion { return new \Psalm\Storage\Assertion\IsIdentical($this->type); } public function hasEquality() : bool { return \true; } public function __toString() : string { return '!=' . $this->type->getAssertionString(); } public function getAtomicType() : ?Atomic { return $this->type; } /** * @return static */ public function setAtomicType(Atomic $type) : self { return new static($type); } public function isNegationOf(Assertion $assertion) : bool { return $assertion instanceof \Psalm\Storage\Assertion\IsIdentical && $this->type->getId() === $assertion->type->getId(); } } value = $value; } public function getNegation() : Assertion { return new \Psalm\Storage\Assertion\IsLessThanOrEqualTo($this->value); } public function __toString() : string { return '>' . $this->value; } public function isNegationOf(Assertion $assertion) : bool { return $assertion instanceof \Psalm\Storage\Assertion\IsLessThanOrEqualTo && $this->value === $assertion->value; } public function doesFilterNullOrFalse() : bool { return \true; } } type = $type; } public function getNegation() : Assertion { return new \Psalm\Storage\Assertion\IsNotType($this->type); } public function __toString() : string { return $this->type->getId(); } public function getAtomicType() : ?Atomic { return $this->type; } /** * @return static */ public function setAtomicType(Atomic $type) : self { return new static($type); } public function isNegationOf(Assertion $assertion) : bool { return $assertion instanceof \Psalm\Storage\Assertion\IsNotType && $this->type->getId() === $assertion->type->getId(); } } type = $type; } public function getNegation() : Assertion { return new \Psalm\Storage\Assertion\NotInArray($this->type); } public function __toString() : string { return 'in-array-' . $this->type->getId(); } public function isNegationOf(Assertion $assertion) : bool { return $assertion instanceof \Psalm\Storage\Assertion\NotInArray && $this->type->getId() === $assertion->type->getId(); } } type = $type; } public function getNegation() : Assertion { return new \Psalm\Storage\Assertion\InArray($this->type); } public function __toString() : string { return '!in-array-' . $this->type; } public function isNegation() : bool { return \true; } public function isNegationOf(Assertion $assertion) : bool { return $assertion instanceof \Psalm\Storage\Assertion\InArray && $this->type->getId() === $assertion->type->getId(); } } >> */ public array $assertions; /** @param array>> $assertions */ public function __construct(array $assertions) { $this->assertions = $assertions; } public function isNegation() : bool { return \true; } public function getNegation() : Assertion { return new \Psalm\Storage\Assertion\NestedAssertions($this->assertions); } public function __toString() : string { return '!@' . json_encode($this->assertions, JSON_THROW_ON_ERROR); } public function isNegationOf(Assertion $assertion) : bool { return \false; } } method = $method; } public function isNegation() : bool { return \true; } public function getNegation() : Assertion { return new \Psalm\Storage\Assertion\HasMethod($this->method); } public function __toString() : string { return '!method-exists-' . $this->method; } public function isNegationOf(Assertion $assertion) : bool { return $assertion instanceof \Psalm\Storage\Assertion\HasMethod && $assertion->method === $this->method; } } name = $name; $this->type = $type; $this->location = $location; } } */ public $internal = []; /** * @var ?string */ public $getter_method; /** * @var bool */ public $is_promoted = \false; /** * @var list */ public $attributes = []; /** * @var array */ public $suppressed_issues = []; /** * @var ?string */ public $description; public function getInfo() : string { switch ($this->visibility) { case ClassLikeAnalyzer::VISIBILITY_PRIVATE: $visibility_text = 'private'; break; case ClassLikeAnalyzer::VISIBILITY_PROTECTED: $visibility_text = 'protected'; break; default: $visibility_text = 'public'; } return $visibility_text . ' ' . ($this->type ? $this->type->getId() : 'mixed'); } /** * @return list */ public function getAttributeStorages() : array { return $this->attributes; } } */ public $custom_metadata = []; } */ public $classlikes_in_file = []; /** * @var array */ public $referenced_classlikes = []; /** * @var array */ public $required_classes = []; /** * @var array */ public $required_interfaces = []; /** @var string */ public $file_path; /** * @var array */ public $functions = []; /** @var array */ public $declaring_function_ids = []; /** * @var array */ public $constants = []; /** @var array */ public $declaring_constants = []; /** @var array */ public $required_file_paths = []; /** @var array */ public $required_by_file_paths = []; /** @var bool */ public $populated = \false; /** @var bool */ public $deep_scan = \false; /** @var bool */ public $has_extra_statements = \false; /** * @var string */ public $hash = ''; /** * @var bool */ public $has_visitor_issues = \false; /** * @var list */ public $docblock_issues = []; /** * @var array */ public $type_aliases = []; /** * @var array */ public $classlike_aliases = []; /** @var ?Aliases */ public $aliases; /** @var Aliases[] */ public $namespace_aliases = []; public function __construct(string $file_path) { $this->file_path = $file_path; } } > */ public $use_referencing_locations = []; /** * @var FileStorageProvider */ public $file_storage_provider; /** * @var ClassLikeStorageProvider */ public $classlike_storage_provider; /** * @var bool */ public $collect_references = \false; /** * @var bool */ public $collect_locations = \false; /** * @var null|'always'|'auto' */ public $find_unused_code; /** * @var FileProvider */ public $file_provider; /** * @var FileReferenceProvider */ public $file_reference_provider; /** * @var StatementsProvider */ public $statements_provider; private Progress $progress; /** * @var array */ private static $stubbed_constants = []; /** * Whether to register autoloaded information * * @var bool */ public $register_autoload_files = \false; /** * Whether to log functions just at the file level or globally (for stubs) * * @var bool */ public $register_stub_files = \false; /** * @var bool */ public $find_unused_variables = \false; /** * @var Scanner */ public $scanner; /** * @var Analyzer */ public $analyzer; /** * @var Functions */ public $functions; /** * @var ClassLikes */ public $classlikes; /** * @var Methods */ public $methods; /** * @var Properties */ public $properties; /** * @var Populator */ public $populator; /** * @var ?TaintFlowGraph */ public $taint_flow_graph; /** * @var bool */ public $server_mode = \false; /** * @var bool */ public $store_node_types = \false; /** * Whether or not to infer types from usage. Computationally expensive, so turned off by default * * @var bool */ public $infer_types_from_usage = \false; /** * @var bool */ public $alter_code = \false; /** * @var bool */ public $diff_methods = \false; /** * @var array */ public $methods_to_move = []; /** * @var array */ public $methods_to_rename = []; /** * @var array */ public $properties_to_move = []; /** * @var array */ public $properties_to_rename = []; /** * @var array */ public $class_constants_to_move = []; /** * @var array */ public $class_constants_to_rename = []; /** * @var array */ public $classes_to_move = []; /** * @var array */ public $call_transforms = []; /** * @var array */ public $property_transforms = []; /** * @var array */ public $class_constant_transforms = []; /** * @var array */ public $class_transforms = []; /** * @var bool */ public $allow_backwards_incompatible_changes = \true; /** @var int */ public $analysis_php_version_id = PHP_VERSION_ID; /** @var 'cli'|'config'|'composer'|'tests'|'runtime' */ public $php_version_source = 'runtime'; /** * @var bool */ public $track_unused_suppressions = \false; /** @internal */ public function __construct(\Psalm\Config $config, Providers $providers, ?Progress $progress = null) { if ($progress === null) { $progress = new VoidProgress(); } $this->config = $config; $this->file_storage_provider = $providers->file_storage_provider; $this->classlike_storage_provider = $providers->classlike_storage_provider; $this->progress = $progress; $this->file_provider = $providers->file_provider; $this->file_reference_provider = $providers->file_reference_provider; $this->statements_provider = $providers->statements_provider; self::$stubbed_constants = []; $reflection = new Reflection($providers->classlike_storage_provider, $this); $this->scanner = new Scanner($this, $config, $providers->file_storage_provider, $providers->file_provider, $reflection, $providers->file_reference_provider, $progress); $this->loadAnalyzer(); $this->functions = new Functions($providers->file_storage_provider, $reflection); $this->classlikes = new ClassLikes($this->config, $providers->classlike_storage_provider, $providers->file_reference_provider, $providers->statements_provider, $this->scanner); $this->properties = new Properties($providers->classlike_storage_provider, $providers->file_reference_provider, $this->classlikes); $this->methods = new Methods($providers->classlike_storage_provider, $providers->file_reference_provider, $this->classlikes); $this->populator = new Populator($providers->classlike_storage_provider, $providers->file_storage_provider, $this->classlikes, $providers->file_reference_provider, $progress); $this->loadAnalyzer(); } private function loadAnalyzer() : void { $this->analyzer = new Analyzer($this->config, $this->file_provider, $this->file_storage_provider, $this->progress); } /** * @param array $candidate_files */ public function reloadFiles(ProjectAnalyzer $project_analyzer, array $candidate_files, bool $force = \false) : void { $this->loadAnalyzer(); if ($force) { FileReferenceProvider::clearCache(); } $this->file_reference_provider->loadReferenceCache(\false); FunctionLikeAnalyzer::clearCache(); if ($force || !$this->statements_provider->parser_cache_provider) { $diff_files = $candidate_files; } else { $diff_files = []; $parser_cache_provider = $this->statements_provider->parser_cache_provider; foreach ($candidate_files as $candidate_file_path) { if ($parser_cache_provider->loadExistingFileContentsFromCache($candidate_file_path) !== $this->file_provider->getContents($candidate_file_path)) { $diff_files[] = $candidate_file_path; } } } $referenced_files = $project_analyzer->getReferencedFilesFromDiff($diff_files, \false); foreach ($diff_files as $diff_file_path) { $this->invalidateInformationForFile($diff_file_path); } foreach ($referenced_files as $referenced_file_path) { if (in_array($referenced_file_path, $diff_files, \true)) { continue; } $file_storage = $this->file_storage_provider->get($referenced_file_path); foreach ($file_storage->classlikes_in_file as $fq_classlike_name) { $this->classlike_storage_provider->remove($fq_classlike_name); $this->classlikes->removeClassLike($fq_classlike_name); } $this->file_storage_provider->remove($referenced_file_path); $this->scanner->removeFile($referenced_file_path); } $referenced_files = array_combine($referenced_files, $referenced_files); $this->scanner->addFilesToDeepScan($referenced_files); $this->addFilesToAnalyze(array_combine($candidate_files, $candidate_files)); $this->scanner->scanFiles($this->classlikes); $this->file_reference_provider->updateReferenceCache($this, $referenced_files); $this->populator->populateCodebase(); } public function enterServerMode() : void { $this->server_mode = \true; $this->store_node_types = \true; } public function collectLocations() : void { $this->collect_locations = \true; $this->classlikes->collect_locations = \true; $this->methods->collect_locations = \true; $this->properties->collect_locations = \true; } /** * @param 'always'|'auto' $find_unused_code */ public function reportUnusedCode(string $find_unused_code = 'auto') : void { $this->collect_references = \true; $this->classlikes->collect_references = \true; $this->find_unused_code = $find_unused_code; $this->find_unused_variables = \true; } public function reportUnusedVariables() : void { $this->collect_references = \true; $this->find_unused_variables = \true; } /** * @param array $files_to_analyze */ public function addFilesToAnalyze(array $files_to_analyze) : void { $this->scanner->addFilesToDeepScan($files_to_analyze); $this->analyzer->addFilesToAnalyze($files_to_analyze); } /** * Scans all files their related files */ public function scanFiles(int $threads = 1) : void { $has_changes = $this->scanner->scanFiles($this->classlikes, $threads); if ($has_changes) { $this->populator->populateCodebase(); } } public function getFileContents(string $file_path) : string { return $this->file_provider->getContents($file_path); } /** * @return list */ public function getStatementsForFile(string $file_path) : array { return $this->statements_provider->getStatementsForFile($file_path, $this->analysis_php_version_id, $this->progress); } public function createClassLikeStorage(string $fq_classlike_name) : ClassLikeStorage { return $this->classlike_storage_provider->create($fq_classlike_name); } public function cacheClassLikeStorage(ClassLikeStorage $classlike_storage, string $file_path) : void { if (!$this->classlike_storage_provider->cache) { return; } $file_contents = $this->file_provider->getContents($file_path); $this->classlike_storage_provider->cache->writeToCache($classlike_storage, $file_path, $file_contents); } public function exhumeClassLikeStorage(string $fq_classlike_name, string $file_path) : void { $file_contents = $this->file_provider->getContents($file_path); $storage = $this->classlike_storage_provider->exhume($fq_classlike_name, $file_path, $file_contents); if ($storage->is_trait) { $this->classlikes->addFullyQualifiedTraitName($storage->name, $file_path); } elseif ($storage->is_interface) { $this->classlikes->addFullyQualifiedInterfaceName($storage->name, $file_path); } elseif ($storage->is_enum) { $this->classlikes->addFullyQualifiedEnumName($storage->name, $file_path); } else { $this->classlikes->addFullyQualifiedClassName($storage->name, $file_path); } } public static function getPsalmTypeFromReflection(?ReflectionType $type) : Union { return Reflection::getPsalmTypeFromReflectionType($type); } public function createFileStorageForPath(string $file_path) : FileStorage { return $this->file_storage_provider->create($file_path); } /** * @return array */ public function findReferencesToSymbol(string $symbol) : array { if (!$this->collect_locations) { throw new UnexpectedValueException('Should not be checking references'); } if (strpos($symbol, '::$') !== \false) { return $this->findReferencesToProperty($symbol); } if (strpos($symbol, '::') !== \false) { return $this->findReferencesToMethod($symbol); } return $this->findReferencesToClassLike($symbol); } /** * @return array */ public function findReferencesToMethod(string $method_id) : array { return $this->file_reference_provider->getClassMethodLocations(strtolower($method_id)); } /** * @return array */ public function findReferencesToProperty(string $property_id) : array { /** @psalm-suppress PossiblyUndefinedIntArrayOffset */ [$fq_class_name, $property_name] = explode('::', $property_id); return $this->file_reference_provider->getClassPropertyLocations(strtolower($fq_class_name) . '::' . $property_name); } /** * @return CodeLocation[] * @psalm-return array */ public function findReferencesToClassLike(string $fq_class_name) : array { $fq_class_name_lc = strtolower($fq_class_name); $locations = $this->file_reference_provider->getClassLocations($fq_class_name_lc); if (isset($this->use_referencing_locations[$fq_class_name_lc])) { $locations = [...$locations, ...$this->use_referencing_locations[$fq_class_name_lc]]; } return $locations; } public function getClosureStorage(string $file_path, string $closure_id) : FunctionStorage { $file_storage = $this->file_storage_provider->get($file_path); // closures can be returned here if (isset($file_storage->functions[$closure_id])) { return $file_storage->functions[$closure_id]; } throw new UnexpectedValueException('Expecting ' . $closure_id . ' to have storage in ' . $file_path); } public function addGlobalConstantType(string $const_id, Union $type) : void { self::$stubbed_constants[$const_id] = $type; } public function getStubbedConstantType(string $const_id) : ?Union { return self::$stubbed_constants[$const_id] ?? null; } /** * @return array */ public function getAllStubbedConstants() : array { return self::$stubbed_constants; } public function fileExists(string $file_path) : bool { return $this->file_provider->fileExists($file_path); } /** * Check whether a class/interface exists */ public function classOrInterfaceExists(string $fq_class_name, ?\Psalm\CodeLocation $code_location = null, ?string $calling_fq_class_name = null, ?string $calling_method_id = null) : bool { return $this->classlikes->classOrInterfaceExists($fq_class_name, $code_location, $calling_fq_class_name, $calling_method_id); } /** * Check whether a class/interface exists * * @psalm-assert-if-true class-string|interface-string|enum-string $fq_class_name */ public function classOrInterfaceOrEnumExists(string $fq_class_name, ?\Psalm\CodeLocation $code_location = null, ?string $calling_fq_class_name = null, ?string $calling_method_id = null) : bool { return $this->classlikes->classOrInterfaceOrEnumExists($fq_class_name, $code_location, $calling_fq_class_name, $calling_method_id); } /** @psalm-mutation-free */ public function classExtendsOrImplements(string $fq_class_name, string $possible_parent) : bool { return $this->classlikes->classExtends($fq_class_name, $possible_parent) || $this->classlikes->classImplements($fq_class_name, $possible_parent); } /** * Determine whether or not a given class exists */ public function classExists(string $fq_class_name, ?\Psalm\CodeLocation $code_location = null, ?string $calling_fq_class_name = null, ?string $calling_method_id = null) : bool { return $this->classlikes->classExists($fq_class_name, $code_location, $calling_fq_class_name, $calling_method_id); } /** * Determine whether or not a class extends a parent * * @throws UnpopulatedClasslikeException when called on unpopulated class * @throws InvalidArgumentException when class does not exist */ public function classExtends(string $fq_class_name, string $possible_parent) : bool { return $this->classlikes->classExtends($fq_class_name, $possible_parent, \true); } /** * Check whether a class implements an interface */ public function classImplements(string $fq_class_name, string $interface) : bool { return $this->classlikes->classImplements($fq_class_name, $interface); } public function interfaceExists(string $fq_interface_name, ?\Psalm\CodeLocation $code_location = null, ?string $calling_fq_class_name = null, ?string $calling_method_id = null) : bool { return $this->classlikes->interfaceExists($fq_interface_name, $code_location, $calling_fq_class_name, $calling_method_id); } public function interfaceExtends(string $interface_name, string $possible_parent) : bool { return $this->classlikes->interfaceExtends($interface_name, $possible_parent); } /** * @return array all interfaces extended by $interface_name */ public function getParentInterfaces(string $fq_interface_name) : array { return $this->classlikes->getParentInterfaces($this->classlikes->getUnAliasedName($fq_interface_name)); } /** * Determine whether or not a class has the correct casing */ public function classHasCorrectCasing(string $fq_class_name) : bool { return $this->classlikes->classHasCorrectCasing($fq_class_name); } public function interfaceHasCorrectCasing(string $fq_interface_name) : bool { return $this->classlikes->interfaceHasCorrectCasing($fq_interface_name); } public function traitHasCorrectCasing(string $fq_trait_name) : bool { return $this->classlikes->traitHasCorrectCasing($fq_trait_name); } /** * Given a function id, return the function like storage for * a method, closure, or function. * * @param non-empty-string $function_id * @return FunctionStorage|MethodStorage */ public function getFunctionLikeStorage(StatementsAnalyzer $statements_analyzer, string $function_id) : FunctionLikeStorage { $doesMethodExist = MethodIdentifier::isValidMethodIdReference($function_id) && $this->methodExists($function_id); if ($doesMethodExist) { $method_id = MethodIdentifier::wrap($function_id); $declaring_method_id = $this->methods->getDeclaringMethodId($method_id); if (!$declaring_method_id) { throw new UnexpectedValueException('Declaring method for ' . $method_id . ' cannot be found'); } return $this->methods->getStorage($declaring_method_id); } return $this->functions->getStorage($statements_analyzer, strtolower($function_id)); } /** * Whether or not a given method exists * * @param string|MethodIdentifier $method_id * @param string|MethodIdentifier|null $calling_method_id */ public function methodExists($method_id, ?\Psalm\CodeLocation $code_location = null, $calling_method_id = null, ?string $file_path = null, bool $is_used = \true) : bool { return $this->methods->methodExists(MethodIdentifier::wrap($method_id), is_string($calling_method_id) ? strtolower($calling_method_id) : strtolower((string) $calling_method_id), $code_location, null, $file_path, \true, $is_used); } /** * @param string|MethodIdentifier $method_id * @return array */ public function getMethodParams($method_id) : array { return $this->methods->getMethodParams(MethodIdentifier::wrap($method_id)); } /** * @param string|MethodIdentifier $method_id */ public function isVariadic($method_id) : bool { return $this->methods->isVariadic(MethodIdentifier::wrap($method_id)); } /** * @param string|MethodIdentifier $method_id * @param list $call_args */ public function getMethodReturnType($method_id, ?string &$self_class, array $call_args = []) : ?Union { return $this->methods->getMethodReturnType(MethodIdentifier::wrap($method_id), $self_class, null, $call_args); } /** * @param string|MethodIdentifier $method_id */ public function getMethodReturnsByRef($method_id) : bool { return $this->methods->getMethodReturnsByRef(MethodIdentifier::wrap($method_id)); } /** * @param string|MethodIdentifier $method_id */ public function getMethodReturnTypeLocation($method_id, ?\Psalm\CodeLocation &$defined_location = null) : ?\Psalm\CodeLocation { return $this->methods->getMethodReturnTypeLocation(MethodIdentifier::wrap($method_id), $defined_location); } /** * @param string|MethodIdentifier $method_id */ public function getDeclaringMethodId($method_id) : ?string { $new_method_id = $this->methods->getDeclaringMethodId(MethodIdentifier::wrap($method_id)); return $new_method_id ? (string) $new_method_id : null; } /** * Get the class this method appears in (vs is declared in, which could give a trait) * * @param string|MethodIdentifier $method_id */ public function getAppearingMethodId($method_id) : ?string { $new_method_id = $this->methods->getAppearingMethodId(MethodIdentifier::wrap($method_id)); return $new_method_id ? (string) $new_method_id : null; } /** * @param string|MethodIdentifier $method_id * @return array */ public function getOverriddenMethodIds($method_id) : array { return $this->methods->getOverriddenMethodIds(MethodIdentifier::wrap($method_id)); } /** * @param string|MethodIdentifier $method_id */ public function getCasedMethodId($method_id) : string { return $this->methods->getCasedMethodId(MethodIdentifier::wrap($method_id)); } public function invalidateInformationForFile(string $file_path) : void { $this->scanner->removeFile($file_path); try { $file_storage = $this->file_storage_provider->get($file_path); } catch (InvalidArgumentException $e) { return; } foreach ($file_storage->classlikes_in_file as $fq_classlike_name) { $this->classlike_storage_provider->remove($fq_classlike_name); $this->classlikes->removeClassLike($fq_classlike_name); } $this->file_storage_provider->remove($file_path); } public function getFunctionStorageForSymbol(string $file_path, string $symbol) : ?FunctionLikeStorage { if (strpos($symbol, '::')) { $symbol = substr($symbol, 0, -2); /** @psalm-suppress ArgumentTypeCoercion */ $method_id = new MethodIdentifier(...explode('::', $symbol)); $declaring_method_id = $this->methods->getDeclaringMethodId($method_id); if (!$declaring_method_id) { return null; } return $this->methods->getStorage($declaring_method_id); } $function_id = strtolower(substr($symbol, 0, -2)); $file_storage = $this->file_storage_provider->get($file_path); if (isset($file_storage->functions[$function_id])) { return $file_storage->functions[$function_id]; } if (!$function_id) { return null; } return $this->functions->getStorage(null, $function_id); } /** * Get Markup content from Reference */ public function getMarkupContentForSymbolByReference(Reference $reference) : ?PHPMarkdownContent { //Direct Assignment if (is_numeric($reference->symbol[0])) { return new PHPMarkdownContent(preg_replace('/^[^:]*:/', '', $reference->symbol)); } //Class if (strpos($reference->symbol, '::')) { //Class Method if (strpos($reference->symbol, '()')) { $symbol = substr($reference->symbol, 0, -2); /** @psalm-suppress ArgumentTypeCoercion */ $method_id = new MethodIdentifier(...explode('::', $symbol)); $declaring_method_id = $this->methods->getDeclaringMethodId($method_id); if (!$declaring_method_id) { return null; } $storage = $this->methods->getStorage($declaring_method_id); return new PHPMarkdownContent($storage->getHoverMarkdown(), "{$storage->defining_fqcln}::{$storage->cased_name}", $storage->description); } /** @psalm-suppress PossiblyUndefinedIntArrayOffset */ [, $symbol_name] = explode('::', $reference->symbol); //Class Property if (strpos($reference->symbol, '$') !== \false) { $property_id = preg_replace('/^\\\\/', '', $reference->symbol); /** @psalm-suppress PossiblyUndefinedIntArrayOffset */ [$fq_class_name, $property_name] = explode('::$', $property_id); $class_storage = $this->classlikes->getStorageFor($fq_class_name); //Get Real Properties if (isset($class_storage->declaring_property_ids[$property_name])) { $declaring_property_class = $class_storage->declaring_property_ids[$property_name]; $declaring_class_storage = $this->classlike_storage_provider->get($declaring_property_class); if (isset($declaring_class_storage->properties[$property_name])) { $storage = $declaring_class_storage->properties[$property_name]; return new PHPMarkdownContent("{$storage->getInfo()} {$symbol_name}", $reference->symbol, $storage->description); } } //Get Docblock properties if (isset($class_storage->pseudo_property_set_types['$' . $property_name])) { return new PHPMarkdownContent('public ' . (string) $class_storage->pseudo_property_set_types['$' . $property_name] . ' $' . $property_name, $reference->symbol); } //Get Docblock properties if (isset($class_storage->pseudo_property_get_types['$' . $property_name])) { return new PHPMarkdownContent('public ' . (string) $class_storage->pseudo_property_get_types['$' . $property_name] . ' $' . $property_name, $reference->symbol); } return null; } /** @psalm-suppress PossiblyUndefinedIntArrayOffset */ [$fq_classlike_name, $const_name] = explode('::', $reference->symbol); $class_constants = $this->classlikes->getConstantsForClass($fq_classlike_name, ReflectionProperty::IS_PRIVATE); if (!isset($class_constants[$const_name])) { return null; } //Class Constant return new PHPMarkdownContent($class_constants[$const_name]->getHoverMarkdown($const_name), $fq_classlike_name . '::' . $const_name, $class_constants[$const_name]->description); } //Procedural Function if (strpos($reference->symbol, '()')) { $function_id = strtolower(substr($reference->symbol, 0, -2)); $file_storage = $this->file_storage_provider->get($reference->file_path); if (isset($file_storage->functions[$function_id])) { $function_storage = $file_storage->functions[$function_id]; return new PHPMarkdownContent($function_storage->getHoverMarkdown(), $function_id, $function_storage->description); } if (!$function_id) { return null; } $function = $this->functions->getStorage(null, $function_id); return new PHPMarkdownContent($function->getHoverMarkdown(), $function_id, $function->description); } //Procedural Variable if (strpos($reference->symbol, '$') === 0) { $type = VariableFetchAnalyzer::getGlobalType($reference->symbol, $this->analysis_php_version_id); if (!$type->isMixed()) { return new PHPMarkdownContent((string) $type, $reference->symbol); } } try { $storage = $this->classlike_storage_provider->get($reference->symbol); return new PHPMarkdownContent(($storage->abstract ? 'abstract ' : '') . 'class ' . $storage->name, $storage->name, $storage->description); } catch (InvalidArgumentException $e) { //continue on as normal } if (strpos($reference->symbol, '\\')) { $const_name_parts = explode('\\', $reference->symbol); $const_name = array_pop($const_name_parts); $namespace_name = implode('\\', $const_name_parts); $namespace_constants = NamespaceAnalyzer::getConstantsForNamespace($namespace_name, ReflectionProperty::IS_PUBLIC); //Namespace Constant if (isset($namespace_constants[$const_name])) { $type = $namespace_constants[$const_name]; return new PHPMarkdownContent($reference->symbol . ' ' . $type, $reference->symbol); } } else { $file_storage = $this->file_storage_provider->get($reference->file_path); // ? if (isset($file_storage->constants[$reference->symbol])) { return new PHPMarkdownContent('const ' . $reference->symbol . ' ' . $file_storage->constants[$reference->symbol], $reference->symbol); } $type = ConstFetchAnalyzer::getGlobalConstType($this, $reference->symbol, $reference->symbol); //Global Constant if ($type) { return new PHPMarkdownContent('const ' . $reference->symbol . ' ' . $type, $reference->symbol); } } return new PHPMarkdownContent($reference->symbol); } /** * @psalm-suppress PossiblyUnusedMethod * @deprecated will be removed in Psalm 6. use {@see Codebase::getSymbolLocationByReference()} instead */ public function getSymbolInformation(string $file_path, string $symbol) : ?array { if (is_numeric($symbol[0])) { return ['type' => preg_replace('/^[^:]*:/', '', $symbol)]; } try { if (strpos($symbol, '::')) { if (strpos($symbol, '()')) { $symbol = substr($symbol, 0, -2); /** @psalm-suppress ArgumentTypeCoercion */ $method_id = new MethodIdentifier(...explode('::', $symbol)); $declaring_method_id = $this->methods->getDeclaringMethodId($method_id); if (!$declaring_method_id) { return null; } $storage = $this->methods->getStorage($declaring_method_id); return ['type' => 'getCompletionSignature(), 'description' => $storage->description]; } [, $symbol_name] = explode('::', $symbol); if (strpos($symbol, '$') !== \false) { $storage = $this->properties->getStorage($symbol); return ['type' => 'getInfo() . ' ' . $symbol_name, 'description' => $storage->description]; } [$fq_classlike_name, $const_name] = explode('::', $symbol); $class_constants = $this->classlikes->getConstantsForClass($fq_classlike_name, ReflectionProperty::IS_PRIVATE); if (!isset($class_constants[$const_name])) { return null; } return ['type' => ' $class_constants[$const_name]->description]; } if (strpos($symbol, '()')) { $function_id = strtolower(substr($symbol, 0, -2)); $file_storage = $this->file_storage_provider->get($file_path); if (isset($file_storage->functions[$function_id])) { $function_storage = $file_storage->functions[$function_id]; return ['type' => 'getCompletionSignature(), 'description' => $function_storage->description]; } if (!$function_id) { return null; } $function = $this->functions->getStorage(null, $function_id); return ['type' => 'getCompletionSignature(), 'description' => $function->description]; } if (strpos($symbol, '$') === 0) { $type = VariableFetchAnalyzer::getGlobalType($symbol, $this->analysis_php_version_id); if (!$type->isMixed()) { return ['type' => 'classlike_storage_provider->get($symbol); return ['type' => 'abstract ? 'abstract ' : '') . 'class ' . $storage->name, 'description' => $storage->description]; } catch (InvalidArgumentException $e) { } if (strpos($symbol, '\\')) { $const_name_parts = explode('\\', $symbol); $const_name = array_pop($const_name_parts); $namespace_name = implode('\\', $const_name_parts); $namespace_constants = NamespaceAnalyzer::getConstantsForNamespace($namespace_name, ReflectionProperty::IS_PUBLIC); if (isset($namespace_constants[$const_name])) { $type = $namespace_constants[$const_name]; return ['type' => 'file_storage_provider->get($file_path); if (isset($file_storage->constants[$symbol])) { return ['type' => 'constants[$symbol]]; } $constant = ConstFetchAnalyzer::getGlobalConstType($this, $symbol, $symbol); if ($constant) { return ['type' => 'getMessage()); return null; } } /** * @psalm-suppress PossiblyUnusedMethod * @deprecated will be removed in Psalm 6. use {@see Codebase::getSymbolLocationByReference()} instead */ public function getSymbolLocation(string $file_path, string $symbol) : ?\Psalm\CodeLocation { if (is_numeric($symbol[0])) { $symbol = preg_replace('/:.*/', '', $symbol); $symbol_parts = explode('-', $symbol); $file_contents = $this->getFileContents($file_path); return new Raw($file_contents, $file_path, $this->config->shortenFileName($file_path), (int) $symbol_parts[0], (int) $symbol_parts[1]); } try { if (strpos($symbol, '::')) { if (strpos($symbol, '()')) { $symbol = substr($symbol, 0, -2); /** @psalm-suppress ArgumentTypeCoercion */ $method_id = new MethodIdentifier(...explode('::', $symbol)); $declaring_method_id = $this->methods->getDeclaringMethodId($method_id); if (!$declaring_method_id) { return null; } $storage = $this->methods->getStorage($declaring_method_id); return $storage->location; } if (strpos($symbol, '$') !== \false) { $storage = $this->properties->getStorage($symbol); return $storage->location; } [$fq_classlike_name, $const_name] = explode('::', $symbol); $class_constants = $this->classlikes->getConstantsForClass($fq_classlike_name, ReflectionProperty::IS_PRIVATE); if (!isset($class_constants[$const_name])) { return null; } return $class_constants[$const_name]->location; } if (strpos($symbol, '()')) { $file_storage = $this->file_storage_provider->get($file_path); $function_id = strtolower(substr($symbol, 0, -2)); if (isset($file_storage->functions[$function_id])) { return $file_storage->functions[$function_id]->location; } if (!$function_id) { return null; } return $this->functions->getStorage(null, $function_id)->location; } return $this->classlike_storage_provider->get($symbol)->location; } catch (UnexpectedValueException $e) { error_log($e->getMessage()); return null; } catch (InvalidArgumentException $e) { return null; } } public function getSymbolLocationByReference(Reference $reference) : ?\Psalm\CodeLocation { if (is_numeric($reference->symbol[0])) { $symbol = preg_replace('/:.*/', '', $reference->symbol); $symbol_parts = explode('-', $symbol); if (!isset($symbol_parts[0]) || !isset($symbol_parts[1])) { return null; } $file_contents = $this->getFileContents($reference->file_path); return new Raw($file_contents, $reference->file_path, $this->config->shortenFileName($reference->file_path), (int) $symbol_parts[0], (int) $symbol_parts[1]); } try { if (strpos($reference->symbol, '::')) { if (strpos($reference->symbol, '()')) { $symbol = substr($reference->symbol, 0, -2); /** @psalm-suppress ArgumentTypeCoercion */ $method_id = new MethodIdentifier(...explode('::', $symbol)); $declaring_method_id = $this->methods->getDeclaringMethodId($method_id); if (!$declaring_method_id) { return null; } $storage = $this->methods->getStorage($declaring_method_id); return $storage->location; } if (strpos($reference->symbol, '$') !== \false) { $storage = $this->properties->getStorage($reference->symbol); return $storage->location; } /** @psalm-suppress PossiblyUndefinedIntArrayOffset */ [$fq_classlike_name, $const_name] = explode('::', $reference->symbol); $class_constants = $this->classlikes->getConstantsForClass($fq_classlike_name, ReflectionProperty::IS_PRIVATE); if (!isset($class_constants[$const_name])) { return null; } return $class_constants[$const_name]->location; } if (strpos($reference->symbol, '()')) { $file_storage = $this->file_storage_provider->get($reference->file_path); $function_id = strtolower(substr($reference->symbol, 0, -2)); if (isset($file_storage->functions[$function_id])) { return $file_storage->functions[$function_id]->location; } if (!$function_id) { return null; } return $this->functions->getStorage(null, $function_id)->location; } return $this->classlike_storage_provider->get($reference->symbol)->location; } catch (UnexpectedValueException $e) { error_log($e->getMessage()); return null; } catch (InvalidArgumentException $e) { return null; } } /** * @psalm-suppress PossiblyUnusedMethod * @return array{0: string, 1: Range}|null */ public function getReferenceAtPosition(string $file_path, Position $position) : ?array { $ref = $this->getReferenceAtPositionAsReference($file_path, $position); if ($ref === null) { return null; } return [$ref->symbol, $ref->range]; } /** * Get Reference from Position */ public function getReferenceAtPositionAsReference(string $file_path, Position $position) : ?Reference { $is_open = $this->file_provider->isOpen($file_path); if (!$is_open) { throw new UnanalyzedFileException($file_path . ' is not open'); } $file_contents = $this->getFileContents($file_path); $offset = $position->toOffset($file_contents); $reference_maps = $this->analyzer->getMapsForFile($file_path); $reference_start_pos = null; $reference_end_pos = null; $symbol = null; foreach ($reference_maps as $reference_map) { ksort($reference_map); foreach ($reference_map as $start_pos => [$end_pos, $possible_reference]) { if ($offset < $start_pos) { break; } if ($offset > $end_pos) { continue; } $reference_start_pos = $start_pos; $reference_end_pos = $end_pos; $symbol = $possible_reference; } if ($symbol !== null && $reference_start_pos !== null && $reference_end_pos !== null) { break; } } if ($symbol === null || $reference_start_pos === null || $reference_end_pos === null) { return null; } $range = new Range(self::getPositionFromOffset($reference_start_pos, $file_contents), self::getPositionFromOffset($reference_end_pos, $file_contents)); return new Reference($file_path, $symbol, $range); } /** * @return array{0: non-empty-string, 1: int, 2: Range}|null */ public function getFunctionArgumentAtPosition(string $file_path, Position $position) : ?array { $is_open = $this->file_provider->isOpen($file_path); if (!$is_open) { throw new UnanalyzedFileException($file_path . ' is not open'); } $file_contents = $this->getFileContents($file_path); $offset = $position->toOffset($file_contents); [, , $argument_map] = $this->analyzer->getMapsForFile($file_path); $reference = null; $argument_number = null; if (!$argument_map) { return null; } $start_pos = null; $end_pos = null; ksort($argument_map); foreach ($argument_map as $start_pos => [$end_pos, $possible_reference, $possible_argument_number]) { if ($offset < $start_pos) { break; } if ($offset > $end_pos) { continue; } $reference = $possible_reference; $argument_number = $possible_argument_number; } if ($reference === null || $start_pos === null || $end_pos === null || $argument_number === null) { return null; } $range = new Range(self::getPositionFromOffset($start_pos, $file_contents), self::getPositionFromOffset($end_pos, $file_contents)); return [$reference, $argument_number, $range]; } /** * @param non-empty-string $function_symbol */ public function getSignatureInformation(string $function_symbol, ?string $file_path = null) : ?SignatureInformation { $signature_label = ''; $signature_documentation = null; if (strpos($function_symbol, '::') !== \false) { /** @psalm-suppress ArgumentTypeCoercion */ $method_id = new MethodIdentifier(...explode('::', $function_symbol)); $declaring_method_id = $this->methods->getDeclaringMethodId($method_id); if ($declaring_method_id === null) { return null; } $method_storage = $this->methods->getStorage($declaring_method_id); $params = $method_storage->params; $signature_label = $method_storage->cased_name; $signature_documentation = $method_storage->description; } else { try { if ($file_path) { $function_storage = $this->functions->getStorage(null, strtolower($function_symbol), dirname($file_path), $file_path); } else { $function_storage = $this->functions->getStorage(null, strtolower($function_symbol)); } $params = $function_storage->params; $signature_label = $function_storage->cased_name; $signature_documentation = $function_storage->description; } catch (Exception $exception) { if (InternalCallMapHandler::inCallMap($function_symbol)) { $callables = InternalCallMapHandler::getCallablesFromCallMap($function_symbol); if (!$callables || !isset($callables[0]->params)) { return null; } $params = $callables[0]->params; } else { return null; } } } $signature_label .= '('; $parameters = []; foreach ($params as $i => $param) { $parameter_label = ($param->type ?: 'mixed') . ' $' . $param->name; $parameters[] = new ParameterInformation([strlen($signature_label), strlen($signature_label) + strlen($parameter_label)], $param->description ?? null); $signature_label .= $parameter_label; if ($i < count($params) - 1) { $signature_label .= ', '; } } $signature_label .= ')'; return new SignatureInformation($signature_label, $parameters, $signature_documentation); } /** * @return array{0: string, 1: '->'|'::'|'['|'symbol', 2: int}|null */ public function getCompletionDataAtPosition(string $file_path, Position $position) : ?array { $is_open = $this->file_provider->isOpen($file_path); if (!$is_open) { throw new UnanalyzedFileException($file_path . ' is not open'); } $file_contents = $this->getFileContents($file_path); $offset = $position->toOffset($file_contents); $literal_part = $this->getBeginedLiteralPart($file_path, $position); $begin_literal_offset = $offset - strlen($literal_part); [$reference_map, $type_map] = $this->analyzer->getMapsForFile($file_path); if (!$reference_map && !$type_map) { return null; } krsort($type_map); foreach ($type_map as $start_pos => [$end_pos_excluding_whitespace, $possible_type]) { if ($offset < $start_pos) { continue; } /** @psalm-suppress PossiblyUndefinedIntArrayOffset */ $num_whitespace_bytes = preg_match('/\\G\\s+/', $file_contents, $matches, 0, $end_pos_excluding_whitespace) ? strlen($matches[0]) : 0; $end_pos = $end_pos_excluding_whitespace + $num_whitespace_bytes; if ($offset - $end_pos === 1) { $candidate_gap = substr($file_contents, $end_pos, 1); if ($candidate_gap === '[') { $gap = $candidate_gap; $recent_type = $possible_type; if ($recent_type === 'mixed') { return null; } return [$recent_type, $gap, $offset]; } } if ($begin_literal_offset - $end_pos === 2) { $candidate_gap = substr($file_contents, $end_pos, 2); if ($candidate_gap === '->' || $candidate_gap === '::') { $gap = $candidate_gap; $recent_type = $possible_type; if ($recent_type === 'mixed') { return null; } return [$recent_type, $gap, $offset]; } } } foreach ($reference_map as $start_pos => [$end_pos, $possible_reference]) { if ($offset < $start_pos) { continue; } // If the reference precedes a "::" then treat it as a class reference. if ($offset - $end_pos === 2 && substr($file_contents, $end_pos, 2) === '::') { return [$possible_reference, '::', $offset]; } if ($offset <= $end_pos && substr($file_contents, $begin_literal_offset - 2, 2) === '::') { $class_name = explode('::', $possible_reference)[0]; return [$class_name, '::', $offset]; } // Only continue for references that are partial / don't exist. if ($possible_reference[0] !== '*') { continue; } if ($offset - $end_pos === 0) { $recent_type = $possible_reference; return [$recent_type, 'symbol', $offset]; } } return null; } public function getBeginedLiteralPart(string $file_path, Position $position) : string { $is_open = $this->file_provider->isOpen($file_path); if (!$is_open) { throw new UnanalyzedFileException($file_path . ' is not open'); } $file_contents = $this->getFileContents($file_path); $offset = $position->toOffset($file_contents); preg_match('/\\$?\\w+$/', substr($file_contents, 0, $offset), $matches); return $matches[0] ?? ''; } public function getTypeContextAtPosition(string $file_path, Position $position) : ?Union { $file_contents = $this->getFileContents($file_path); $offset = $position->toOffset($file_contents); [$reference_map, $type_map, $argument_map] = $this->analyzer->getMapsForFile($file_path); if (!$reference_map && !$type_map && !$argument_map) { return null; } foreach ($argument_map as $start_pos => [$end_pos, $function, $argument_num]) { if ($offset < $start_pos || $offset > $end_pos) { continue; } // First parameter to a function-like $function_storage = $this->getFunctionStorageForSymbol($file_path, $function . '()'); if (!$function_storage || !$function_storage->params || !isset($function_storage->params[$argument_num])) { return null; } return $function_storage->params[$argument_num]->type; } return null; } /** * @param list $allow_visibilities * @param list $ignore_fq_class_names * @return list */ public function getCompletionItemsForClassishThing(string $type_string, string $gap, bool $snippets_supported = \false, ?array $allow_visibilities = null, array $ignore_fq_class_names = []) : array { if ($allow_visibilities === null) { $allow_visibilities = [ClassLikeAnalyzer::VISIBILITY_PUBLIC, ClassLikeAnalyzer::VISIBILITY_PROTECTED, ClassLikeAnalyzer::VISIBILITY_PRIVATE]; } $allow_visibilities[] = null; $completion_items = []; $type = \Psalm\Type::parseString($type_string); foreach ($type->getAtomicTypes() as $atomic_type) { if ($atomic_type instanceof TNamedObject) { try { $class_storage = $this->classlike_storage_provider->get($atomic_type->value); $method_storages = []; foreach ($class_storage->declaring_method_ids as $declaring_method_id) { try { $method_storages[] = $this->methods->getStorage($declaring_method_id); } catch (UnexpectedValueException $e) { error_log($e->getMessage()); } } if ($gap === '->') { $method_storages += $class_storage->pseudo_methods; } if ($gap === '::') { $method_storages += $class_storage->pseudo_static_methods; } foreach ($method_storages as $method_storage) { if (!in_array($method_storage->visibility, $allow_visibilities)) { continue; } if ($method_storage->is_static || $gap === '->') { $completion_item = new CompletionItem($method_storage->cased_name, CompletionItemKind::METHOD, $method_storage->getCompletionSignature(), $method_storage->description, (string) $method_storage->visibility, $method_storage->cased_name, $method_storage->cased_name, null, null, new Command('Trigger parameter hints', 'editor.action.triggerParameterHints'), null, 2); if ($snippets_supported && count($method_storage->params) > 0) { $completion_item->insertText .= '($0)'; $completion_item->insertTextFormat = InsertTextFormat::SNIPPET; } else { $completion_item->insertText .= '()'; } $completion_items[] = $completion_item; } } if ($gap === '->') { $pseudo_property_types = []; foreach ($class_storage->pseudo_property_get_types as $property_name => $type) { $pseudo_property_types[$property_name] = new CompletionItem( str_replace('$', '', $property_name), CompletionItemKind::PROPERTY, $type->__toString(), null, '1', //sort text str_replace('$', '', $property_name), str_replace('$', '', $property_name) ); } foreach ($class_storage->pseudo_property_set_types as $property_name => $type) { $pseudo_property_types[$property_name] = new CompletionItem(str_replace('$', '', $property_name), CompletionItemKind::PROPERTY, $type->__toString(), null, '1', str_replace('$', '', $property_name), str_replace('$', '', $property_name)); } $completion_items = [...$completion_items, ...array_values($pseudo_property_types)]; } foreach ($class_storage->declaring_property_ids as $property_name => $declaring_class) { try { $property_storage = $this->properties->getStorage($declaring_class . '::$' . $property_name); } catch (UnexpectedValueException $e) { error_log($e->getMessage()); continue; } if (!in_array($property_storage->visibility, $allow_visibilities)) { continue; } if ($property_storage->is_static === ($gap === '::')) { $completion_items[] = new CompletionItem($property_name, CompletionItemKind::PROPERTY, $property_storage->getInfo(), $property_storage->description, (string) $property_storage->visibility, $property_name, ($gap === '::' ? '$' : '') . $property_name); } } foreach ($class_storage->constants as $const_name => $const) { $completion_items[] = new CompletionItem($const_name, CompletionItemKind::VARIABLE, 'const ' . $const_name, $const->description, null, $const_name, $const_name); } if ($gap === '->') { foreach ($class_storage->namedMixins as $mixin) { if (in_array($mixin->value, $ignore_fq_class_names)) { continue; } $mixin_completion_items = $this->getCompletionItemsForClassishThing($mixin->value, $gap, $snippets_supported, [ClassLikeAnalyzer::VISIBILITY_PUBLIC], [$type_string, ...$ignore_fq_class_names]); $completion_items = [...$completion_items, ...$mixin_completion_items]; } } } catch (Exception $e) { error_log($e->getMessage()); continue; } } } return $completion_items; } /** * @param list $items * @return list * @deprecated to be removed in Psalm 6 * @api fix deprecation problem "PossiblyUnusedMethod: Cannot find any calls to method" */ public function filterCompletionItemsByBeginLiteralPart(array $items, string $literal_part) : array { if (!$literal_part) { return $items; } $res = []; foreach ($items as $item) { if ($item->insertText && strpos($item->insertText, $literal_part) === 0) { $res[] = $item; } } return $res; } /** * @return list */ public function getCompletionItemsForPartialSymbol(string $type_string, int $offset, string $file_path) : array { $fq_suggestion = \false; if (($type_string[1] ?? '') === '\\') { $fq_suggestion = \true; } $matching_classlike_names = $this->classlikes->getMatchingClassLikeNames($type_string); $completion_items = []; $file_storage = $this->file_storage_provider->get($file_path); $aliases = null; foreach ($file_storage->classlikes_in_file as $fq_class_name => $_) { try { $class_storage = $this->classlike_storage_provider->get($fq_class_name); } catch (Exception $e) { continue; } if (!$class_storage->stmt_location) { continue; } if ($offset > $class_storage->stmt_location->raw_file_start && $offset < $class_storage->stmt_location->raw_file_end) { $aliases = $class_storage->aliases; break; } } if (!$aliases) { foreach ($file_storage->namespace_aliases as $namespace_start => $namespace_aliases) { if ($namespace_start < $offset) { $aliases = $namespace_aliases; break; } } if (!$aliases) { $aliases = $file_storage->aliases; } } foreach ($matching_classlike_names as $fq_class_name) { $extra_edits = []; $insertion_text = \Psalm\Type::getStringFromFQCLN($fq_class_name, $aliases && $aliases->namespace ? $aliases->namespace : null, $aliases->uses_flipped ?? [], null); if ($aliases && !$fq_suggestion && $aliases->namespace && $insertion_text === '\\' . $fq_class_name && $aliases->namespace_first_stmt_start) { $file_contents = $this->getFileContents($file_path); $class_name = preg_replace('/^.*\\\\/', '', $fq_class_name, 1); if ($aliases->uses_end) { $position = self::getPositionFromOffset($aliases->uses_end, $file_contents); $extra_edits[] = new TextEdit(new Range($position, $position), "\n" . 'use ' . $fq_class_name . ';'); } else { $position = self::getPositionFromOffset($aliases->namespace_first_stmt_start, $file_contents); $extra_edits[] = new TextEdit(new Range($position, $position), 'use ' . $fq_class_name . ';' . "\n" . "\n"); } $insertion_text = $class_name; } try { $class_storage = $this->classlike_storage_provider->get($fq_class_name); $description = $class_storage->description; } catch (Exception $e) { $description = null; } $completion_items[] = new CompletionItem($fq_class_name, CompletionItemKind::CLASS_, null, $description, null, $fq_class_name, $insertion_text, null, $extra_edits); } $functions = $this->functions->getMatchingFunctionNames($type_string, $offset, $file_path, $this); $namespace_map = []; if ($aliases) { $namespace_map += $aliases->uses_flipped; if ($aliases->namespace) { $namespace_map[$aliases->namespace] = ''; } } // Sort the map by longest first, so we replace most specific // used namespaces first. ksort($namespace_map); $namespace_map = array_reverse($namespace_map); foreach ($functions as $function_lowercase => $function) { // Transform FQFN relative to all uses namespaces $function_name = $function->cased_name; if (!$function_name) { continue; } $in_namespace_map = \false; foreach ($namespace_map as $namespace_name => $namespace_alias) { if (strpos($function_lowercase, $namespace_name . '\\') === 0) { $function_name = $namespace_alias . '\\' . substr($function_name, strlen($namespace_name) + 1); $in_namespace_map = \true; } } // If the function is not use'd, and it's not a global function // prepend it with a backslash. if (!$in_namespace_map && strpos($function_name, '\\') !== \false) { $function_name = '\\' . $function_name; } $completion_items[] = new CompletionItem($function_name, CompletionItemKind::FUNCTION, $function->getCompletionSignature(), $function->description, null, $function_name, $function_name . (count($function->params) !== 0 ? '($0)' : '()'), null, null, new Command('Trigger parameter hints', 'editor.action.triggerParameterHints'), null, 2); } return $completion_items; } /** * @return list */ public function getCompletionItemsForType(Union $type) : array { $completion_items = []; foreach ($type->getAtomicTypes() as $atomic_type) { if ($atomic_type instanceof TBool) { $bools = (string) $atomic_type === 'bool' ? ['true', 'false'] : [(string) $atomic_type]; foreach ($bools as $property_name) { $completion_items[] = new CompletionItem($property_name, CompletionItemKind::VALUE, 'bool', null, null, null, $property_name); } } elseif ($atomic_type instanceof TLiteralString) { $completion_items[] = new CompletionItem($atomic_type->value, CompletionItemKind::VALUE, $atomic_type->getId(), null, null, null, "'{$atomic_type->value}'"); } elseif ($atomic_type instanceof TLiteralInt) { $completion_items[] = new CompletionItem((string) $atomic_type->value, CompletionItemKind::VALUE, $atomic_type->getId(), null, null, null, (string) $atomic_type->value); } elseif ($atomic_type instanceof TClassConstant) { $const = $atomic_type->fq_classlike_name . '::' . $atomic_type->const_name; $completion_items[] = new CompletionItem($const, CompletionItemKind::VALUE, $atomic_type->getId(), null, null, null, $const); } } return $completion_items; } /** * @return list */ public function getCompletionItemsForArrayKeys(string $type_string) : array { $completion_items = []; $type = \Psalm\Type::parseString($type_string); foreach ($type->getAtomicTypes() as $atomic_type) { if ($atomic_type instanceof TKeyedArray) { foreach ($atomic_type->properties as $property_name => $property) { $completion_items[] = new CompletionItem((string) $property_name, CompletionItemKind::PROPERTY, (string) $property, null, null, null, "'{$property_name}'"); } } } return $completion_items; } private static function getPositionFromOffset(int $offset, string $file_contents) : Position { $file_contents = substr($file_contents, 0, $offset); $offsetLength = $offset - strlen($file_contents); //PHP 8.0: Argument #3 ($offset) must be contained in argument #1 ($haystack) if (($textlen = strlen($file_contents)) < $offsetLength) { $offsetLength = $textlen; } $before_newline_count = strrpos($file_contents, "\n", $offsetLength); return new Position(substr_count($file_contents, "\n"), $offset - (int) $before_newline_count - 1); } public function addTemporaryFileChanges(string $file_path, string $new_content, ?int $version = null) : void { $this->file_provider->addTemporaryFileChanges($file_path, $new_content, $version); } public function removeTemporaryFileChanges(string $file_path) : void { $this->file_provider->removeTemporaryFileChanges($file_path); } /** * Checks if type is a subtype of other * * Given two types, checks if `$input_type` is a subtype of `$container_type`. * If you consider `Union` as a set of types, this will tell you * if `$input_type` is fully contained in `$container_type`, * * $input_type ⊆ $container_type * * Useful for emitting issues like InvalidArgument, where argument at the call site * should be a subset of the function parameter type. */ public function isTypeContainedByType(Union $input_type, Union $container_type, bool $ignore_null = \false, bool $ignore_false = \false, bool $allow_interface_equality = \false, bool $allow_float_int_equality = \true) : bool { return UnionTypeComparator::isContainedBy($this, $input_type, $container_type, $ignore_null, $ignore_false, null, $allow_interface_equality, $allow_float_int_equality); } /** * Checks if type has any part that is a subtype of other * * Given two types, checks if *any part* of `$input_type` is a subtype of `$container_type`. * If you consider `Union` as a set of types, this will tell you if intersection * of `$input_type` with `$container_type` is not empty. * * $input_type ∩ $container_type ≠ ∅ , e.g. they are not disjoint. * * Useful for emitting issues like PossiblyInvalidArgument, where argument at the call * site should be a subtype of the function parameter type, but it's has some types that are * not a subtype of the required type. */ public function canTypeBeContainedByType(Union $input_type, Union $container_type) : bool { return UnionTypeComparator::canBeContainedBy($this, $input_type, $container_type); } /** * Extracts key and value types from a traversable object (or iterable) * * Given an iterable type (*but not TArray*) returns a tuple of it's key/value types. * First element of the tuple holds key type, second has the value type. * * Example: * ```php * $codebase->getKeyValueParamsForTraversableObject(Type::parseString('iterable')) * // returns [Union(TInt), Union(TString)] * ``` * * @return array{Union, Union} */ public function getKeyValueParamsForTraversableObject(Atomic $type) : array { $key_type = null; $value_type = null; ForeachAnalyzer::getKeyValueParamsForTraversableObject($type, $this, $key_type, $value_type); return [$key_type ?? \Psalm\Type::getMixed(), $value_type ?? \Psalm\Type::getMixed()]; } /** * @param array $phantom_classes */ public function queueClassLikeForScanning(string $fq_classlike_name, bool $analyze_too = \false, bool $store_failure = \true, array $phantom_classes = []) : void { $this->scanner->queueClassLikeForScanning($fq_classlike_name, $analyze_too, $store_failure, $phantom_classes); } /** * @param array $taints * @psalm-suppress PossiblyUnusedMethod */ public function addTaintSource(Union $expr_type, string $taint_id, array $taints = TaintKindGroup::ALL_INPUT, ?\Psalm\CodeLocation $code_location = null) : Union { if (!$this->taint_flow_graph) { return $expr_type; } $source = new TaintSource($taint_id, $taint_id, $code_location, null, $taints); $this->taint_flow_graph->addSource($source); return $expr_type->addParentNodes([$source->id => $source]); } /** * @param array $taints * @psalm-suppress PossiblyUnusedMethod */ public function addTaintSink(string $taint_id, array $taints = TaintKindGroup::ALL_INPUT, ?\Psalm\CodeLocation $code_location = null) : void { if (!$this->taint_flow_graph) { return; } $sink = new TaintSink($taint_id, $taint_id, $code_location, null, $taints); $this->taint_flow_graph->addSink($sink); } public function getMinorAnalysisPhpVersion() : int { return self::transformPhpVersionId($this->analysis_php_version_id % 10000, 100); } public function getMajorAnalysisPhpVersion() : int { return self::transformPhpVersionId($this->analysis_php_version_id, 10000); } public static function transformPhpVersionId(int $php_version_id, int $div) : int { return intdiv($php_version_id, $div); } } > $template_type_map */ public static function parseString(string $type_string, ?int $analysis_php_version_id = null, array $template_type_map = []) : Union { return TypeParser::parseTokens(TypeTokenizer::tokenize($type_string), $analysis_php_version_id, $template_type_map); } public static function getFQCLNFromString(string $class, \Psalm\Aliases $aliases) : string { if ($class === '') { throw new InvalidArgumentException('$class cannot be empty'); } if ($class[0] === '\\') { return substr($class, 1); } $imported_namespaces = $aliases->uses; if (strpos($class, '\\') !== \false) { $class_parts = explode('\\', $class); $first_namespace = array_shift($class_parts); if (isset($imported_namespaces[strtolower($first_namespace)])) { return $imported_namespaces[strtolower($first_namespace)] . '\\' . implode('\\', $class_parts); } } elseif (isset($imported_namespaces[strtolower($class)])) { return $imported_namespaces[strtolower($class)]; } $namespace = $aliases->namespace; return ($namespace ? $namespace . '\\' : '') . $class; } /** * @param array $aliased_classes * @psalm-pure */ public static function getStringFromFQCLN(string $value, ?string $namespace, array $aliased_classes, ?string $this_class, bool $allow_self = \false, bool $is_static = \false) : string { if ($allow_self && $value === $this_class) { if ($is_static) { return 'static'; } return 'self'; } if (isset($aliased_classes[strtolower($value)])) { return $aliased_classes[strtolower($value)]; } if ($namespace && stripos($value, $namespace . '\\') === 0) { $candidate = preg_replace('/^' . preg_quote($namespace . '\\') . '/i', '', $value); $candidate_parts = explode('\\', $candidate); if (!isset($aliased_classes[strtolower($candidate_parts[0])])) { return $candidate; } } elseif (!$namespace && strpos($value, '\\') === \false) { return $value; } if (strpos($value, '\\')) { $parts = explode('\\', $value); $suffix = array_pop($parts); while ($parts) { $left = implode('\\', $parts); if (isset($aliased_classes[strtolower($left)])) { return $aliased_classes[strtolower($left)] . '\\' . $suffix; } $suffix = array_pop($parts) . '\\' . $suffix; } } return '\\' . $value; } /** * @psalm-pure */ public static function getInt(bool $from_calculation = \false, ?int $value = null) : Union { if ($value !== null) { return new Union([new TLiteralInt($value)], ['from_calculation' => $from_calculation]); } return new Union([new TInt()], ['from_calculation' => $from_calculation]); } /** * @psalm-pure */ public static function getIntRange(?int $min, ?int $max) : Union { return new Union([new TIntRange($min, $max)]); } /** * @psalm-pure */ public static function getLowercaseString() : Union { $type = new TLowercaseString(); return new Union([$type]); } /** * @psalm-pure */ public static function getNonEmptyLowercaseString() : Union { $type = new TNonEmptyLowercaseString(); return new Union([$type]); } /** * @psalm-pure */ public static function getNonEmptyString() : Union { $type = new TNonEmptyString(); return new Union([$type]); } /** * @psalm-pure */ public static function getNonFalsyString() : Union { $type = new TNonFalsyString(); return new Union([$type]); } /** * @psalm-pure */ public static function getNumeric() : Union { $type = new TNumeric(); return new Union([$type]); } /** * @psalm-pure */ public static function getNumericString() : Union { $type = new TNumericString(); return new Union([$type]); } /** * @param int|string $value * @return TLiteralString|TLiteralInt */ public static function getLiteral($value) : Atomic { if (is_int($value)) { return new TLiteralInt($value); } return TLiteralString::make($value); } public static function getString(?string $value = null) : Union { return new Union([$value === null ? new TString() : self::getAtomicStringFromLiteral($value)]); } /** @return TLiteralString|TNonEmptyString|TNonFalsyString */ public static function getAtomicStringFromLiteral(string $value, bool $from_docblock = \false) : TString { $config = \Psalm\Config::getInstance(); $event = new StringInterpreterEvent($value, ProjectAnalyzer::getInstance()->getCodebase()); $type = $config->eventDispatcher->dispatchStringInterpreter($event); if (!$type) { if ($value === '' || strlen($value) < $config->max_string_length) { $type = new TLiteralString($value, $from_docblock); } elseif ($value === '0') { $type = new TNonEmptyString($from_docblock); } else { $type = new TNonFalsyString($from_docblock); } } return $type; } /** * @psalm-pure */ public static function getSingleLetter() : Union { $type = new TSingleLetter(); return new Union([$type]); } /** * @psalm-pure */ public static function getClassString(string $extends = 'object') : Union { return new Union([new TClassString($extends, $extends === 'object' ? null : new TNamedObject($extends))]); } /** * @psalm-pure */ public static function getLiteralClassString(string $class_type, bool $definite_class = \false) : Union { $type = new TLiteralClassString($class_type, $definite_class); return new Union([$type]); } /** * @psalm-pure */ public static function getNull(bool $from_docblock = \false) : Union { $type = new TNull($from_docblock); return new Union([$type]); } /** * @psalm-pure */ public static function getMixed(bool $from_loop_isset = \false, bool $from_docblock = \false) : Union { $type = new TMixed($from_loop_isset, $from_docblock); return new Union([$type]); } /** * @psalm-pure */ public static function getScalar(bool $from_docblock = \false) : Union { $type = new TScalar($from_docblock); return new Union([$type]); } /** * @psalm-pure */ public static function getNever(bool $from_docblock = \false) : Union { $type = new TNever($from_docblock); return new Union([$type]); } /** * @psalm-pure */ public static function getBool(bool $from_docblock = \false) : Union { $type = new TBool($from_docblock); return new Union([$type]); } /** * @psalm-pure */ public static function getFloat(?float $value = null, bool $from_docblock = \false) : Union { if ($value !== null) { $type = new TLiteralFloat($value, $from_docblock); } else { $type = new TFloat($from_docblock); } return new Union([$type]); } /** * @psalm-pure */ public static function getObject() : Union { $type = new TObject(); return new Union([$type]); } /** * @psalm-pure */ public static function getClosure() : Union { $type = new TClosure('Closure'); return new Union([$type]); } /** * @psalm-pure */ public static function getArrayKey(bool $from_docblock = \false) : Union { $type = new TArrayKey($from_docblock); return new Union([$type]); } /** * @psalm-pure */ public static function getArray() : Union { $type = new TArray([new Union([new TArrayKey()]), new Union([new TMixed()])]); return new Union([$type]); } /** * @psalm-pure */ public static function getEmptyArray() : Union { return new Union([self::getEmptyArrayAtomic()]); } /** * @psalm-pure */ public static function getEmptyArrayAtomic() : TArray { return new TArray([new Union([new TNever()]), new Union([new TNever()])]); } /** * @psalm-pure */ public static function getList(?Union $of = null, bool $from_docblock = \false) : Union { return new Union([self::getListAtomic($of ?? self::getMixed($from_docblock), $from_docblock)]); } /** * @psalm-pure */ public static function getNonEmptyList(?Union $of = null, bool $from_docblock = \false) : Union { return new Union([self::getNonEmptyListAtomic($of ?? self::getMixed($from_docblock), $from_docblock)]); } /** * @psalm-pure */ public static function getListAtomic(Union $of, bool $from_docblock = \false) : TKeyedArray { return new TKeyedArray([$of->setPossiblyUndefined(\true)], null, [self::getListKey(), $of], \true, $from_docblock); } /** * @psalm-pure */ public static function getNonEmptyListAtomic(Union $of, bool $from_docblock = \false) : TKeyedArray { return new TKeyedArray([$of->setPossiblyUndefined(\false)], null, [self::getListKey(), $of], \true, $from_docblock); } private static ?Union $listKey = null; private static ?Union $listKeyFromDocblock = null; /** * @psalm-pure * @psalm-suppress ImpureStaticProperty Used for caching */ public static function getListKey(bool $from_docblock = \false) : Union { if ($from_docblock) { return self::$listKeyFromDocblock ??= new Union([new TIntRange(0, null, \true)]); } return self::$listKey ??= self::getIntRange(0, null); } /** * @psalm-pure */ public static function getVoid(bool $from_docblock = \false) : Union { $type = new TVoid($from_docblock); return new Union([$type]); } /** * @psalm-pure */ public static function getFalse(bool $from_docblock = \false) : Union { $type = new TFalse($from_docblock); return new Union([$type]); } /** * @psalm-pure */ public static function getTrue(bool $from_docblock = \false) : Union { $type = new TTrue($from_docblock); return new Union([$type]); } /** * @psalm-pure */ public static function getResource(bool $from_docblock = \false) : Union { return new Union([new TResource($from_docblock)]); } /** * @psalm-external-mutation-free * @param non-empty-list $union_types */ public static function combineUnionTypeArray(array $union_types, ?\Psalm\Codebase $codebase) : Union { $first_type = array_pop($union_types); foreach ($union_types as $type) { $first_type = self::combineUnionTypes($first_type, $type, $codebase); } return $first_type; } /** * Combines two union types into one * * @param int $literal_limit any greater number of literal types than this * will be merged to a scalar * @psalm-external-mutation-free * @psalm-suppress ImpurePropertyAssignment We're not mutating external instances * @psalm-suppress InaccessibleProperty We're not mutating external instances */ public static function combineUnionTypes(?Union $type_1, ?Union $type_2, ?\Psalm\Codebase $codebase = null, bool $overwrite_empty_array = \false, bool $allow_mixed_union = \true, int $literal_limit = 500, ?bool $possibly_undefined = null) : Union { if ($type_2 === null && $type_1 === null) { throw new UnexpectedValueException('At least one type must be provided to combine'); } if ($type_1 === null) { if ($possibly_undefined !== null) { return $type_2->setPossiblyUndefined($possibly_undefined); } return $type_2; } if ($type_2 === null) { if ($possibly_undefined !== null) { return $type_1->setPossiblyUndefined($possibly_undefined); } return $type_1; } if ($type_1 === $type_2) { if ($possibly_undefined !== null) { return $type_1->setPossiblyUndefined($possibly_undefined); } return $type_1; } if ($type_1->isVanillaMixed() && $type_2->isVanillaMixed()) { $combined_type = self::getMixed(); } else { $both_failed_reconciliation = \false; if ($type_1->failed_reconciliation) { if ($type_2->failed_reconciliation) { $both_failed_reconciliation = \true; } else { return $type_2->setProperties(['parent_nodes' => array_merge($type_2->parent_nodes, $type_1->parent_nodes), 'possibly_undefined' => $possibly_undefined ?? $type_2->possibly_undefined]); } } elseif ($type_2->failed_reconciliation) { return $type_1->setProperties(['parent_nodes' => array_merge($type_1->parent_nodes, $type_2->parent_nodes), 'possibly_undefined' => $possibly_undefined ?? $type_1->possibly_undefined]); } $combined_type = TypeCombiner::combine(array_merge(array_values($type_1->getAtomicTypes()), array_values($type_2->getAtomicTypes())), $codebase, $overwrite_empty_array, $allow_mixed_union, $literal_limit); if (!$type_1->initialized || !$type_2->initialized) { $combined_type->initialized = \false; } if ($type_1->from_docblock || $type_2->from_docblock) { $combined_type->from_docblock = \true; } if ($type_1->from_calculation || $type_2->from_calculation) { $combined_type->from_calculation = \true; } if ($type_1->ignore_nullable_issues || $type_2->ignore_nullable_issues) { $combined_type->ignore_nullable_issues = \true; } if ($type_1->ignore_falsable_issues || $type_2->ignore_falsable_issues) { $combined_type->ignore_falsable_issues = \true; } if ($type_1->explicit_never || $type_2->explicit_never) { $combined_type->explicit_never = \true; } if ($type_1->had_template && $type_2->had_template) { $combined_type->had_template = \true; } if ($type_1->reference_free && $type_2->reference_free) { $combined_type->reference_free = \true; } if ($both_failed_reconciliation) { $combined_type->failed_reconciliation = \true; } } if ($possibly_undefined !== null) { $combined_type->possibly_undefined = $possibly_undefined; } elseif ($type_1->possibly_undefined || $type_2->possibly_undefined) { $combined_type->possibly_undefined = \true; } if ($type_1->possibly_undefined_from_try || $type_2->possibly_undefined_from_try) { $combined_type->possibly_undefined_from_try = \true; } if ($type_1->parent_nodes || $type_2->parent_nodes) { $combined_type->parent_nodes = $type_1->parent_nodes + $type_2->parent_nodes; } if ($type_1->by_ref || $type_2->by_ref) { $combined_type->by_ref = \true; } return $combined_type; } /** * Combines two union types into one via an intersection */ public static function intersectUnionTypes(?Union $type_1, ?Union $type_2, \Psalm\Codebase $codebase, bool $allow_interface_equality = \false, bool $allow_float_int_equality = \true) : ?Union { if ($type_2 === null && $type_1 === null) { throw new UnexpectedValueException('At least one type must be provided to combine'); } if ($type_1 === null) { return $type_2; } if ($type_2 === null) { return $type_1; } if ($type_1 === $type_2) { return $type_1; } $intersection_performed = \false; $type_1_mixed = $type_1->isMixed(); $type_2_mixed = $type_2->isMixed(); $possibly_undefined = $type_1->possibly_undefined && $type_2->possibly_undefined; if ($type_1_mixed && $type_2_mixed) { $combined_type = new Union([new TMixed()], ['possibly_undefined' => $possibly_undefined]); } else { $both_failed_reconciliation = \false; if ($type_1->failed_reconciliation) { if ($type_2->failed_reconciliation) { $both_failed_reconciliation = \true; } else { return $type_2; } } elseif ($type_2->failed_reconciliation) { return $type_1; } if ($type_1_mixed) { $combined_type = $type_2->getBuilder(); $intersection_performed = \true; } elseif ($type_2_mixed) { $combined_type = $type_1->getBuilder(); $intersection_performed = \true; } else { $combined_type = null; foreach ($type_1->getAtomicTypes() as $type_1_atomic) { foreach ($type_2->getAtomicTypes() as $type_2_atomic) { $intersection_atomic = self::intersectAtomicTypes($type_1_atomic, $type_2_atomic, $codebase, $intersection_performed, $allow_interface_equality, $allow_float_int_equality); if (null !== $intersection_atomic) { if (null === $combined_type) { $combined_type = new MutableUnion([$intersection_atomic]); } else { $combined_type->addType($intersection_atomic); } } } } } //if a type is contained by the other, the intersection is the narrowest type if (!$intersection_performed) { $type_1_in_2 = UnionTypeComparator::isContainedBy($codebase, $type_1, $type_2); $type_2_in_1 = UnionTypeComparator::isContainedBy($codebase, $type_2, $type_1); if ($type_1_in_2) { $intersection_performed = \true; $combined_type = $type_1->getBuilder(); } elseif ($type_2_in_1) { $intersection_performed = \true; $combined_type = $type_2->getBuilder(); } } if ($combined_type !== null) { if (!$type_1->initialized && !$type_2->initialized) { $combined_type->initialized = \false; } if ($type_1->possibly_undefined_from_try && $type_2->possibly_undefined_from_try) { $combined_type->possibly_undefined_from_try = \true; } if ($type_1->from_docblock && $type_2->from_docblock) { $combined_type->from_docblock = \true; } if ($type_1->from_calculation && $type_2->from_calculation) { $combined_type->from_calculation = \true; } if ($type_1->ignore_nullable_issues && $type_2->ignore_nullable_issues) { $combined_type->ignore_nullable_issues = \true; } if ($type_1->ignore_falsable_issues && $type_2->ignore_falsable_issues) { $combined_type->ignore_falsable_issues = \true; } if ($both_failed_reconciliation) { $combined_type->failed_reconciliation = \true; } $combined_type->possibly_undefined = $possibly_undefined; $combined_type = $combined_type->freeze(); } } if (!$intersection_performed && $type_1->getId() !== $type_2->getId()) { return null; } return $combined_type; } private static function intersectAtomicTypes(Atomic $type_1_atomic, Atomic $type_2_atomic, \Psalm\Codebase $codebase, bool &$intersection_performed, bool $allow_interface_equality = \false, bool $allow_float_int_equality = \true) : ?Atomic { $intersection_atomic = null; $wider_type = null; if ($type_1_atomic instanceof TNamedObject && $type_2_atomic instanceof TNamedObject) { if ($type_1_atomic->value === $type_2_atomic->value && get_class($type_1_atomic) === TNamedObject::class && get_class($type_2_atomic) !== TNamedObject::class) { $intersection_atomic = $type_2_atomic; $wider_type = $type_1_atomic; $intersection_performed = \true; } elseif ($type_1_atomic->value === $type_2_atomic->value && get_class($type_2_atomic) === TNamedObject::class && get_class($type_1_atomic) !== TNamedObject::class) { $intersection_atomic = $type_1_atomic; $wider_type = $type_2_atomic; $intersection_performed = \true; } } if ($type_1_atomic instanceof TInt && $type_2_atomic instanceof TInt) { $int_intersection = TIntRange::intersectIntRanges(TIntRange::convertToIntRange($type_1_atomic), TIntRange::convertToIntRange($type_2_atomic)); if ($int_intersection && ($int_intersection->min_bound !== null || $int_intersection->max_bound !== null)) { $intersection_performed = \true; if ($int_intersection->min_bound !== null && $int_intersection->min_bound === $int_intersection->max_bound) { return new TLiteralInt($int_intersection->min_bound); } return $int_intersection; } } if (null === $intersection_atomic) { try { if (AtomicTypeComparator::isContainedBy($codebase, $type_2_atomic, $type_1_atomic, $allow_interface_equality, $allow_float_int_equality)) { $intersection_atomic = $type_2_atomic; $wider_type = $type_1_atomic; $intersection_performed = \true; } elseif (AtomicTypeComparator::isContainedBy($codebase, $type_1_atomic, $type_2_atomic, $allow_interface_equality, $allow_float_int_equality)) { $intersection_atomic = $type_1_atomic; $wider_type = $type_2_atomic; $intersection_performed = \true; } if ($intersection_atomic && !self::hasIntersection($type_1_atomic) && !self::hasIntersection($type_2_atomic)) { return $intersection_atomic; } } catch (InvalidArgumentException $e) { // Ignore non-existing classes during initial scan } } if (self::mayHaveIntersection($type_1_atomic, $codebase) && self::mayHaveIntersection($type_2_atomic, $codebase)) { /** @psalm-suppress TypeDoesNotContainType */ if ($type_1_atomic instanceof TNamedObject && $type_2_atomic instanceof TNamedObject) { try { $first = $codebase->classlike_storage_provider->get($type_1_atomic->value); $second = $codebase->classlike_storage_provider->get($type_2_atomic->value); $first_is_class = !$first->is_interface && !$first->is_trait; $second_is_class = !$second->is_interface && !$second->is_trait; if ($first_is_class && $second_is_class) { return $intersection_atomic; } } catch (InvalidArgumentException $e) { // Ignore non-existing classes during initial scan } } if ($intersection_atomic === null && $wider_type === null) { $intersection_atomic = $type_1_atomic; $wider_type = $type_2_atomic; } if ($intersection_atomic === null || $wider_type === null) { throw new LogicException('$intersection_atomic and $wider_type should be both set or null.' . ' Check the preceding code for errors.' . ' Did you forget to assign one of the variables?'); } if (!self::mayHaveIntersection($intersection_atomic, $codebase) || !self::mayHaveIntersection($wider_type, $codebase)) { throw new LogicException('$intersection_atomic and $wider_type should be both support intersection.' . ' Check the preceding code for errors.'); } $intersection_performed = \true; $wider_type_clone = $wider_type->setIntersectionTypes([]); $final_intersection = array_merge([$wider_type_clone->getKey() => $wider_type_clone], $intersection_atomic->getIntersectionTypes()); $wider_type_intersection_types = $wider_type->getIntersectionTypes(); foreach ($wider_type_intersection_types as $wider_type_intersection_type) { $final_intersection[$wider_type_intersection_type->getKey()] = $wider_type_intersection_type; } return $intersection_atomic->setIntersectionTypes($final_intersection); } return $intersection_atomic; } /** * @psalm-assert-if-true TIterable|TNamedObject|TTemplateParam|TObjectWithProperties $type */ private static function mayHaveIntersection(Atomic $type, \Psalm\Codebase $codebase) : bool { if ($type instanceof TIterable || $type instanceof TTemplateParam || $type instanceof TObjectWithProperties) { return \true; } if (!$type instanceof TNamedObject) { return \false; } try { $storage = $codebase->classlike_storage_provider->get($type->value); } catch (InvalidArgumentException $e) { // Ignore non-existing classes during initial scan return \true; } return !$storage->final; } private static function hasIntersection(Atomic $type) : bool { return self::isIntersectionType($type) && $type->extra_types; } /** * @psalm-assert-if-true TNamedObject|TTemplateParam|TIterable|TObjectWithProperties|TCallableObject $type */ public static function isIntersectionType(Atomic $type) : bool { return $type instanceof TNamedObject || $type instanceof TTemplateParam || $type instanceof TIterable || $type instanceof TObjectWithProperties || $type instanceof TCallableObject; } } */ public $vars_in_scope = []; /** * @var array */ public $vars_possibly_in_scope = []; /** * Keeps track of how many times a var_in_scope has been referenced. May not be set for all $vars_in_scope. * * @var array> */ public $referenced_counts = []; /** * Maps references to referenced variables for the current scope. * With `$b = &$a`, this will contain `['$b' => '$a']`. * * All keys and values in this array are guaranteed to be set in $vars_in_scope. * * To check if a variable was passed or returned by reference, or * references an object property or array item, see Union::$by_ref. * * @var array */ public $references_in_scope = []; /** * Set of references to variables in another scope. These references will be marked as used if they are assigned to. * * @var array */ public $references_to_external_scope = []; /** * A set of globals that are referenced somewhere. * * @var array */ public $referenced_globals = []; /** * A set of references that might still be in scope from a scope likely to cause confusion. This applies * to references set inside a loop or if statement, since it's easy to forget about PHP's weird scope * rules, and assinging to a reference will change the referenced variable rather than shadowing it. * * @var array */ public $references_possibly_from_confusing_scope = []; /** * Whether or not we're inside the conditional of an if/where etc. * * This changes whether or not the context is cloned * * @var bool */ public $inside_conditional = \false; /** * Whether or not we're inside an isset call * * Inside issets Psalm is more lenient about certain things * * @var bool */ public $inside_isset = \false; /** * Whether or not we're inside an unset call, where * we don't care about possibly undefined variables * * @var bool */ public $inside_unset = \false; /** * Whether or not we're inside an class_exists call, where * we don't care about possibly undefined classes * * @var bool */ public $inside_class_exists = \false; /** * Whether or not we're inside a function/method call * * @var bool */ public $inside_call = \false; /** * Whether or not we're inside any other situation that treats a variable as used * * @var bool */ public $inside_general_use = \false; /** * Whether or not we're inside a return expression * * @var bool */ public $inside_return = \false; /** * Whether or not we're inside a throw * * @var bool */ public $inside_throw = \false; /** * Whether or not we're inside an assignment * * @var bool */ public $inside_assignment = \false; /** * Whether or not we're inside a try block. * * @var bool */ public $inside_try = \false; /** * @var null|CodeLocation */ public $include_location; /** * @var string|null * The name of the current class. Null if outside a class. */ public $self; /** * @var string|null */ public $parent; /** * @var bool */ public $check_classes = \true; /** * @var bool */ public $check_variables = \true; /** * @var bool */ public $check_methods = \true; /** * @var bool */ public $check_consts = \true; /** * @var bool */ public $check_functions = \true; /** * A list of classes checked with class_exists * * @var array */ public $phantom_classes = []; /** * A list of files checked with file_exists * * @var array */ public $phantom_files = []; /** * A list of clauses in Conjunctive Normal Form * * @var list */ public $clauses = []; /** * A list of hashed clauses that have already been factored in * * @var list */ public $reconciled_expression_clauses = []; /** * Whether or not to do a deep analysis and collect mutations to this context * * @var bool */ public $collect_mutations = \false; /** * Whether or not to do a deep analysis and collect initializations from private or final methods * * @var bool */ public $collect_initializations = \false; /** * Whether or not to do a deep analysis and collect initializations from public non-final methods * * @var bool */ public $collect_nonprivate_initializations = \false; /** * Stored to prevent re-analysing methods when checking for initialised properties * * @var array|null */ public $initialized_methods; /** * @var array */ public $constants = []; /** * Whether or not to track exceptions * * @var bool */ public $collect_exceptions = \false; /** * A list of variables that have been referenced in conditionals * * @var array */ public $cond_referenced_var_ids = []; /** * A list of variables that have been passed by reference (where we know their type) * * @var array */ public $byref_constraints = []; /** * A list of vars that have been assigned to * * @var array */ public $assigned_var_ids = []; /** * A list of vars that have been may have been assigned to * * @var array */ public $possibly_assigned_var_ids = []; /** * A list of classes or interfaces that may have been thrown * * @var array> */ public $possibly_thrown_exceptions = []; /** * @var bool */ public $is_global = \false; /** * @var array */ public $protected_var_ids = []; /** * If we've branched from the main scope, a byte offset for where that branch happened * * @var int|null */ public $branch_point; /** * What does break mean in this context? * * 'loop' means we're breaking out of a loop, * 'switch' means we're breaking out of a switch * * @var list<'loop'|'switch'> */ public $break_types = []; /** * @var bool */ public $inside_loop = \false; /** * @var LoopScope|null */ public $loop_scope; /** * @var CaseScope|null */ public $case_scope; /** * @var FinallyScope|null */ public $finally_scope; /** * @var Context|null */ public $if_body_context; /** * @var bool */ public $strict_types = \false; /** * @var string|null */ public $calling_function_id; /** * @var lowercase-string|null */ public $calling_method_id; /** * @var bool */ public $inside_negation = \false; /** * @var bool */ public $ignore_variable_property = \false; /** * @var bool */ public $ignore_variable_method = \false; /** * @var bool */ public $pure = \false; /** * @var bool * Set by @psalm-immutable */ public $mutation_free = \false; /** * @var bool * Set by @psalm-external-mutation-free */ public $external_mutation_free = \false; /** * @var bool */ public $error_suppressing = \false; /** * @var bool */ public $has_returned = \false; /** * @var array */ public $parent_remove_vars = []; /** @internal */ public function __construct(?string $self = null) { $this->self = $self; } public function __destruct() { $this->case_scope = null; } /** * Updates the parent context, looking at the changes within a block and then applying those changes, where * necessary, to the parent context * * @param bool $has_leaving_statements whether or not the parent scope is abandoned between * $start_context and $end_context * @param array $updated_vars */ public function update(\Psalm\Context $start_context, \Psalm\Context $end_context, bool $has_leaving_statements, array $vars_to_update, array &$updated_vars) : void { foreach ($start_context->vars_in_scope as $var_id => $old_type) { // this is only true if there was some sort of type negation if (in_array($var_id, $vars_to_update, \true)) { // if we're leaving, we're effectively deleting the possibility of the if types $new_type = !$has_leaving_statements && $end_context->hasVariable($var_id) ? $end_context->vars_in_scope[$var_id] : null; $existing_type = $this->vars_in_scope[$var_id] ?? null; if (!$existing_type) { if ($new_type) { $this->vars_in_scope[$var_id] = $new_type; $updated_vars[$var_id] = \true; } continue; } // if the type changed within the block of statements, process the replacement // also never allow ourselves to remove all types from a union if ((!$new_type || !$old_type->equals($new_type)) && ($new_type || count($existing_type->getAtomicTypes()) > 1)) { $existing_type = $existing_type->getBuilder()->substitute($old_type, $new_type); if ($new_type && $new_type->from_docblock) { $existing_type = $existing_type->setFromDocblock(); } $existing_type = $existing_type->freeze(); $updated_vars[$var_id] = \true; } $this->vars_in_scope[$var_id] = $existing_type; } } } /** * Updates the list of possible references from a confusing scope, * such as a reference created in an if that might later be reused. */ public function updateReferencesPossiblyFromConfusingScope(\Psalm\Context $confusing_scope_context, StatementsAnalyzer $statements_analyzer) : void { $references = $confusing_scope_context->references_in_scope + $confusing_scope_context->references_to_external_scope; foreach ($references as $reference_id => $_) { if (!isset($this->references_in_scope[$reference_id]) && !isset($this->references_to_external_scope[$reference_id]) && ($reference_location = $statements_analyzer->getFirstAppearance($reference_id))) { $this->references_possibly_from_confusing_scope[$reference_id] = $reference_location; } } $this->references_possibly_from_confusing_scope += $confusing_scope_context->references_possibly_from_confusing_scope; } /** * @param array $new_vars_in_scope * @return array */ public function getRedefinedVars(array $new_vars_in_scope, bool $include_new_vars = \false) : array { $redefined_vars = []; foreach ($this->vars_in_scope as $var_id => $this_type) { if (!isset($new_vars_in_scope[$var_id])) { if ($include_new_vars) { $redefined_vars[$var_id] = $this_type; } continue; } $new_type = $new_vars_in_scope[$var_id]; if (!$this_type->equals($new_type, \true, !($this_type->propagate_parent_nodes || $new_type->propagate_parent_nodes))) { $redefined_vars[$var_id] = $this_type; } } return $redefined_vars; } /** * @return list */ public static function getNewOrUpdatedVarIds(\Psalm\Context $original_context, \Psalm\Context $new_context) : array { $redefined_var_ids = []; foreach ($new_context->vars_in_scope as $var_id => $context_type) { if (!isset($original_context->vars_in_scope[$var_id]) || ($original_context->assigned_var_ids[$var_id] ?? 0) !== ($new_context->assigned_var_ids[$var_id] ?? 0) || !$original_context->vars_in_scope[$var_id]->equals($context_type)) { $redefined_var_ids[] = $var_id; } } return $redefined_var_ids; } public function remove(string $remove_var_id, bool $removeDescendents = \true) : void { if (isset($this->vars_in_scope[$remove_var_id])) { $existing_type = $this->vars_in_scope[$remove_var_id]; unset($this->vars_in_scope[$remove_var_id]); if ($removeDescendents) { $this->removeDescendents($remove_var_id, $existing_type); } } $this->removePossibleReference($remove_var_id); unset($this->vars_possibly_in_scope[$remove_var_id]); } /** * Remove a variable from the context which might be a reference to another variable, or * referenced by another variable. Leaves the variable as possibly-in-scope, unlike remove(). */ public function removePossibleReference(string $remove_var_id) : void { if (isset($this->referenced_counts[$remove_var_id]) && $this->referenced_counts[$remove_var_id] > 0) { // If a referenced variable goes out of scope, we need to update the references. // All of the references to this variable are still references to the same value, // so we pick the first one and make the rest of the references point to it. $references = []; foreach ($this->references_in_scope as $reference => $referenced) { if ($referenced === $remove_var_id) { $references[] = $reference; unset($this->references_in_scope[$reference]); } } assert(!empty($references)); $first_reference = array_shift($references); if (!empty($references)) { $this->referenced_counts[$first_reference] = count($references); foreach ($references as $reference) { $this->references_in_scope[$reference] = $first_reference; } } } if (isset($this->references_in_scope[$remove_var_id])) { $this->decrementReferenceCount($remove_var_id); } unset($this->vars_in_scope[$remove_var_id], $this->cond_referenced_var_ids[$remove_var_id], $this->referenced_counts[$remove_var_id], $this->references_in_scope[$remove_var_id], $this->references_to_external_scope[$remove_var_id]); } /** * Decrement the reference count of the variable that $ref_id is referring to. This needs to * be done before $ref_id is changed to no longer reference its currently referenced variable, * for example by unsetting, reassigning to another reference, or being shadowed by a global. */ public function decrementReferenceCount(string $ref_id) : void { if (!isset($this->referenced_counts[$this->references_in_scope[$ref_id]])) { throw new InvalidArgumentException("{$ref_id} is not a reference"); } $reference_count = $this->referenced_counts[$this->references_in_scope[$ref_id]]; if ($reference_count < 1) { throw new RuntimeException("Incorrect referenced count found"); } --$reference_count; $this->referenced_counts[$this->references_in_scope[$ref_id]] = $reference_count; } /** * @param Clause[] $clauses * @param array $changed_var_ids * @return array{list, list} * @psalm-pure */ public static function removeReconciledClauses(array $clauses, array $changed_var_ids) : array { $included_clauses = []; $rejected_clauses = []; foreach ($clauses as $c) { if ($c->wedge) { $included_clauses[] = $c; continue; } foreach ($c->possibilities as $key => $_) { if (isset($changed_var_ids[$key])) { $rejected_clauses[] = $c; continue 2; } } $included_clauses[] = $c; } return [$included_clauses, $rejected_clauses]; } /** * @param Clause[] $clauses * @return list */ public static function filterClauses(string $remove_var_id, array $clauses, ?Union $new_type = null, ?StatementsAnalyzer $statements_analyzer = null) : array { $new_type_string = $new_type ? $new_type->getId() : ''; $clauses_to_keep = []; foreach ($clauses as $clause) { $clause = $clause->calculateNegation(); $quoted_remove_var_id = preg_quote($remove_var_id, '/'); foreach ($clause->possibilities as $var_id => $_) { if (preg_match('/' . $quoted_remove_var_id . '[\\]\\[\\-]/', $var_id)) { break 2; } } if (!isset($clause->possibilities[$remove_var_id]) || count($clause->possibilities[$remove_var_id]) === 1 && array_keys($clause->possibilities[$remove_var_id])[0] === $new_type_string) { $clauses_to_keep[] = $clause; } elseif ($statements_analyzer && $new_type && !$new_type->hasMixed()) { $type_changed = \false; // if the clause contains any possibilities that would be altered // by the new type foreach ($clause->possibilities[$remove_var_id] as $assertion) { // if we're negating a type, we generally don't need the clause anymore if ($assertion->isNegation()) { $type_changed = \true; break; } $result_type = AssertionReconciler::reconcile($assertion, $new_type, null, $statements_analyzer, \false, [], null, [], $failed_reconciliation); if ($result_type->getId() !== $new_type_string) { $type_changed = \true; break; } } if (!$type_changed) { $clauses_to_keep[] = $clause; } } } return $clauses_to_keep; } public function removeVarFromConflictingClauses(string $remove_var_id, ?Union $new_type = null, ?StatementsAnalyzer $statements_analyzer = null) : void { $this->clauses = self::filterClauses($remove_var_id, $this->clauses, $new_type, $statements_analyzer); $this->parent_remove_vars[$remove_var_id] = \true; } /** * This method is used after assignments to variables to remove any existing * items in $vars_in_scope that are now made redundant by an update to some data */ public function removeDescendents(string $remove_var_id, Union $existing_type, ?Union $new_type = null, ?StatementsAnalyzer $statements_analyzer = null) : void { $this->removeVarFromConflictingClauses($remove_var_id, $existing_type->hasMixed() || $new_type && $existing_type->from_docblock !== $new_type->from_docblock ? null : $new_type, $statements_analyzer); foreach ($this->vars_in_scope as $var_id => &$type) { if (preg_match('/' . preg_quote($remove_var_id, '/') . '[\\]\\[\\-]/', $var_id)) { $this->remove($var_id, \false); } $builder = null; foreach ($type->getAtomicTypes() as $atomic_type) { if ($atomic_type instanceof DependentType && $atomic_type->getVarId() === $remove_var_id) { $builder ??= $type->getBuilder(); $builder->addType($atomic_type->getReplacement()); } } if ($builder) { $type = $builder->freeze(); } } } public function removeMutableObjectVars(bool $methods_only = \false) : void { $vars_to_remove = []; foreach ($this->vars_in_scope as $var_id => $type) { if ($type->has_mutations && (strpos($var_id, '->') !== \false || strpos($var_id, '::') !== \false) && (!$methods_only || strpos($var_id, '()'))) { $vars_to_remove[] = $var_id; } } if (!$vars_to_remove) { return; } foreach ($vars_to_remove as $var_id) { $this->remove($var_id, \false); } $clauses_to_keep = []; foreach ($this->clauses as $clause) { $abandon_clause = \false; foreach (array_keys($clause->possibilities) as $key) { if ((strpos($key, '->') !== \false || strpos($key, '::') !== \false) && (!$methods_only || strpos($key, '()'))) { $abandon_clause = \true; break; } } if (!$abandon_clause) { $clauses_to_keep[] = $clause; } } $this->clauses = $clauses_to_keep; } public function updateChecks(\Psalm\Context $op_context) : void { $this->check_classes = $this->check_classes && $op_context->check_classes; $this->check_variables = $this->check_variables && $op_context->check_variables; $this->check_methods = $this->check_methods && $op_context->check_methods; $this->check_functions = $this->check_functions && $op_context->check_functions; $this->check_consts = $this->check_consts && $op_context->check_consts; } public function isPhantomClass(string $class_name) : bool { return isset($this->phantom_classes[strtolower($class_name)]); } public function hasVariable(string $var_name) : bool { if (!$var_name) { return \false; } $stripped_var = preg_replace('/(->|\\[).*$/', '', $var_name, 1); if ($stripped_var !== '$this' || $var_name !== $stripped_var) { $this->cond_referenced_var_ids[$var_name] = \true; } return isset($this->vars_in_scope[$var_name]); } public function getScopeSummary() : string { $summary = []; foreach ($this->vars_possibly_in_scope as $k => $_) { $summary[$k] = \true; } foreach ($this->vars_in_scope as $k => $v) { $summary[$k] = $v->getId(); } return json_encode($summary, JSON_THROW_ON_ERROR); } public function defineGlobals() : void { $globals = [ // not sure why this is declared here again, see VariableFetchAnalyzer '$argv' => new Union([\Psalm\Type::getNonEmptyListAtomic(\Psalm\Type::getString()), new TNull()], ['ignore_nullable_issues' => \true]), '$argc' => new Union([new TIntRange(1, null), new TNull()], ['ignore_nullable_issues' => \true]), ]; $config = \Psalm\Config::getInstance(); foreach ($config->globals as $global_id => $type_string) { $globals[$global_id] = \Psalm\Type::parseString($type_string); } foreach ($globals as $global_id => $type) { $this->vars_in_scope[$global_id] = $type; $this->vars_possibly_in_scope[$global_id] = \true; } } public function mergeExceptions(\Psalm\Context $other_context) : void { foreach ($other_context->possibly_thrown_exceptions as $possibly_thrown_exception => $codelocations) { foreach ($codelocations as $hash => $codelocation) { $this->possibly_thrown_exceptions[$possibly_thrown_exception][$hash] = $codelocation; } } } public function isSuppressingExceptions(StatementsAnalyzer $statements_analyzer) : bool { if (!$this->collect_exceptions) { return \true; } $issue_type = $this->is_global ? 'UncaughtThrowInGlobalScope' : 'MissingThrowsDocblock'; $suppressed_issues = $statements_analyzer->getSuppressedIssues(); $suppressed_issue_position = array_search($issue_type, $suppressed_issues, \true); if ($suppressed_issue_position !== \false) { if (is_int($suppressed_issue_position)) { $file = $statements_analyzer->getFileAnalyzer()->getFilePath(); \Psalm\IssueBuffer::addUsedSuppressions([$file => [$suppressed_issue_position => \true]]); } return \true; } return \false; } public function mergeFunctionExceptions(FunctionLikeStorage $function_storage, \Psalm\CodeLocation $codelocation) : void { $hash = $codelocation->getHash(); foreach ($function_storage->throws as $possibly_thrown_exception => $_) { $this->possibly_thrown_exceptions[$possibly_thrown_exception][$hash] = $codelocation; } } public function insideUse() : bool { return $this->inside_assignment || $this->inside_return || $this->inside_call || $this->inside_general_use || $this->inside_conditional || $this->inside_throw || $this->inside_isset; } } */ final class RemoteInfo { /** * Remote name. * * @var null|string */ protected $name; /** * Remote URL. * * @var null|string */ protected $url; public function toArray() : array { return ['name' => $this->name, 'url' => $this->url]; } // accessor /** * Set remote name. * * @param string $name remote name * @return $this */ public function setName(string $name) : \Psalm\SourceControl\Git\RemoteInfo { $this->name = $name; return $this; } /** * Return remote name. */ public function getName() : ?string { return $this->name; } /** * Set remote URL. * * @param string $url remote URL * @return $this */ public function setUrl(string $url) : \Psalm\SourceControl\Git\RemoteInfo { $this->url = $url; return $this; } /** * Return remote URL. */ public function getUrl() : ?string { return $this->url; } } */ final class CommitInfo { /** * Commit ID. * * @var null|string */ protected $id; /** * Author name. * * @var null|string */ protected $author_name; /** * Author email. * * @var null|string */ protected $author_email; /** * Committer name. * * @var null|string */ protected $committer_name; /** * Committer email. * * @var null|string */ protected $committer_email; /** * Commit message. * * @var null|string */ protected $message; /** * Commit message. * * @var null|int */ protected $date; public function toArray() : array { return ['id' => $this->id, 'author_name' => $this->author_name, 'author_email' => $this->author_email, 'committer_name' => $this->committer_name, 'committer_email' => $this->committer_email, 'message' => $this->message, 'date' => $this->date]; } // accessor /** * Set commit ID. */ public function setId(string $id) : self { $this->id = $id; return $this; } /** * Return commit ID. */ public function getId() : ?string { return $this->id; } /** * Set author name. */ public function setAuthorName(string $author_name) : self { $this->author_name = $author_name; return $this; } /** * Return author name. */ public function getAuthorName() : ?string { return $this->author_name; } /** * Set author email. */ public function setAuthorEmail(string $author_email) : self { $this->author_email = $author_email; return $this; } /** * Return author email. */ public function getAuthorEmail() : ?string { return $this->author_email; } /** * Set committer name. */ public function setCommitterName(string $committer_name) : self { $this->committer_name = $committer_name; return $this; } /** * Return committer name. */ public function getCommitterName() : ?string { return $this->committer_name; } /** * Set committer email. */ public function setCommitterEmail(string $committer_email) : self { $this->committer_email = $committer_email; return $this; } /** * Return committer email. */ public function getCommitterEmail() : ?string { return $this->committer_email; } /** * Set commit message. */ public function setMessage(string $message) : self { $this->message = $message; return $this; } /** * Return commit message. */ public function getMessage() : ?string { return $this->message; } /** * Set commit date */ public function setDate(int $date) : self { $this->date = $date; return $this; } /** * Return commit date. */ public function getDate() : ?int { return $this->date; } } */ final class GitInfo extends SourceControlInfo { /** * Branch name. * * @var string */ protected $branch; /** * Head. * * @var CommitInfo */ protected $head; /** * Remote. * * @var RemoteInfo[] */ protected $remotes; /** * Constructor. * * @param string $branch branch name * @param CommitInfo $head HEAD commit * @param RemoteInfo[] $remotes remote repositories */ public function __construct(string $branch, \Psalm\SourceControl\Git\CommitInfo $head, array $remotes) { $this->branch = $branch; $this->head = $head; $this->remotes = $remotes; } public function toArray() : array { $remotes = []; foreach ($this->remotes as $remote) { $remotes[] = $remote->toArray(); } return ['branch' => $this->branch, 'head' => $this->head->toArray(), 'remotes' => $remotes]; } // accessor /** * Return branch name. */ public function getBranch() : string { return $this->branch; } /** * Return HEAD commit. */ public function getHead() : \Psalm\SourceControl\Git\CommitInfo { return $this->head; } /** * Return remote repositories. * * @return RemoteInfo[] */ public function getRemotes() : array { return $this->remotes; } } > */ protected static $issues_data = []; /** * @var array */ protected static $console_issues = []; /** * @var array */ protected static $fixable_issue_counts = []; /** * @var int */ protected static $error_count = 0; /** * @var array */ protected static $emitted = []; /** @var int */ protected static $recording_level = 0; /** @var array> */ protected static $recorded_issues = []; /** * @var array> */ protected static $unused_suppressions = []; /** * @var array> */ protected static $used_suppressions = []; /** @var array */ private static array $server = []; /** * This will add an issue to be emitted if it's not suppressed and return if it has been added * * @param string[] $suppressed_issues */ public static function accepts(CodeIssue $e, array $suppressed_issues = [], bool $is_fixable = \false) : bool { $config = \Psalm\Config::getInstance(); $project_analyzer = ProjectAnalyzer::getInstance(); $codebase = $project_analyzer->getCodebase(); $event = new BeforeAddIssueEvent($e, $is_fixable, $codebase); if ($config->eventDispatcher->dispatchBeforeAddIssue($event) === \false) { return \false; } if (self::isSuppressed($e, $suppressed_issues)) { return \false; } return self::add($e, $is_fixable); } /** * This will add an issue to be emitted if it's not suppressed * * @param string[] $suppressed_issues */ public static function maybeAdd(CodeIssue $e, array $suppressed_issues = [], bool $is_fixable = \false) : void { self::accepts($e, $suppressed_issues, $is_fixable); } /** * This is part of the findUnusedPsalmSuppress feature */ public static function addUnusedSuppression(string $file_path, int $offset, string $issue_type) : void { if (strpos($issue_type, 'Tainted') === 0) { return; } if (isset(self::$used_suppressions[$file_path][$offset])) { return; } if (!isset(self::$unused_suppressions[$file_path])) { self::$unused_suppressions[$file_path] = []; } self::$unused_suppressions[$file_path][$offset] = $offset + strlen($issue_type) - 1; } /** * This will return false if an issue is ready to be added for emission. Reasons for not returning false include: * - The issue is suppressed in config * - We're in a recording state * - The issue is included in the list of issues to be suppressed in param * * @param string[] $suppressed_issues */ public static function isSuppressed(CodeIssue $e, array $suppressed_issues = []) : bool { $config = \Psalm\Config::getInstance(); $fqcn_parts = explode('\\', get_class($e)); $issue_type = array_pop($fqcn_parts); $file_path = $e->getFilePath(); if (!$e instanceof ConfigIssue && !$config->reportIssueInFile($issue_type, $file_path)) { return \true; } $suppressed_issue_position = array_search($issue_type, $suppressed_issues, \true); if ($suppressed_issue_position !== \false) { if (is_int($suppressed_issue_position)) { self::$used_suppressions[$file_path][$suppressed_issue_position] = \true; } return \true; } $parent_issue_type = \Psalm\Config::getParentIssueType($issue_type); if ($parent_issue_type) { $suppressed_issue_position = array_search($parent_issue_type, $suppressed_issues, \true); if ($suppressed_issue_position !== \false) { if (is_int($suppressed_issue_position)) { self::$used_suppressions[$file_path][$suppressed_issue_position] = \true; } return \true; } } $suppress_all_position = $config->disable_suppress_all ? \false : array_search('all', $suppressed_issues, \true); if ($suppress_all_position !== \false) { if (is_int($suppress_all_position)) { self::$used_suppressions[$file_path][$suppress_all_position] = \true; } return \true; } $reporting_level = $config->getReportingLevelForIssue($e); if ($reporting_level === \Psalm\Config::REPORT_SUPPRESS) { return \true; } if ($e->code_location->getLineNumber() === -1) { return \true; } if (self::$recording_level > 0) { self::$recorded_issues[self::$recording_level][] = $e; return \true; } return \false; } /** * Add an issue to be emitted. This method should normally not be used! Use IssueBuffer::maybeAdd instead. * * @psalm-internal Psalm\IssueBuffer * @psalm-internal Psalm\Type\Reconciler::getValueForKey * @throws CodeException */ public static function add(CodeIssue $e, bool $is_fixable = \false) : bool { $config = \Psalm\Config::getInstance(); $project_analyzer = ProjectAnalyzer::getInstance(); $codebase = $project_analyzer->getCodebase(); $fqcn_parts = explode('\\', get_class($e)); $issue_type = array_pop($fqcn_parts); if (!$project_analyzer->show_issues) { return \false; } $is_tainted = strpos($issue_type, 'Tainted') === 0; if ($codebase->taint_flow_graph && !$is_tainted) { return \false; } $reporting_level = $config->getReportingLevelForIssue($e); if ($reporting_level === \Psalm\Config::REPORT_SUPPRESS) { return \false; } if ($config->debug_emitted_issues) { ob_start(); debug_print_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS); $trace = ob_get_clean(); fwrite(STDERR, "\nEmitting {$e->getShortLocation()} {$issue_type} {$e->message}\n{$trace}\n"); } // Make issue type for trace variable specific ("Trace" => "Trace~$var"). $trace_var = $issue_type === 'Trace' && preg_match('/^(\\$.+?):/', $e->message, $m) === 1 && isset($m[1]) ? '~' . $m[1] : ''; $emitted_key = $issue_type . $trace_var . '-' . $e->getShortLocation() . ':' . $e->code_location->getColumn() . ' ' . ($e->dupe_key ?? $e->message); if ($reporting_level === \Psalm\Config::REPORT_INFO) { if ($is_tainted || !self::alreadyEmitted($emitted_key)) { self::$issues_data[$e->getFilePath()][] = $e->toIssueData(IssueData::SEVERITY_INFO); if ($is_fixable) { self::addFixableIssue($issue_type); } } return \false; } if ($config->throw_exception) { FileAnalyzer::clearCache(); $message = $e instanceof TaintedInput ? $e->getJourneyMessage() : ($e instanceof MixedIssue ? $e->getMixedOriginMessage() : $e->message); throw new CodeException($issue_type . ' - ' . $e->getShortLocationWithPrevious() . ':' . $e->code_location->getColumn() . ' - ' . $message); } if ($is_tainted || !self::alreadyEmitted($emitted_key)) { ++self::$error_count; self::$issues_data[$e->getFilePath()][] = $e->toIssueData(IssueData::SEVERITY_ERROR); if ($is_fixable) { self::addFixableIssue($issue_type); } } return \true; } private static function removeRecordedIssue(string $issue_type, int $file_offset) : void { $recorded_issues = self::$recorded_issues[self::$recording_level]; $filtered_issues = []; foreach ($recorded_issues as $issue) { [$from] = $issue->code_location->getSelectionBounds(); if ($issue::getIssueType() !== $issue_type || $from !== $file_offset) { $filtered_issues[] = $issue; } } self::$recorded_issues[self::$recording_level] = $filtered_issues; } /** * This will try to remove an issue that has been added for emission */ public static function remove(string $file_path, string $issue_type, int $file_offset) : void { if (self::$recording_level > 0) { self::removeRecordedIssue($issue_type, $file_offset); } if (!isset(self::$issues_data[$file_path])) { return; } $filtered_issues = []; foreach (self::$issues_data[$file_path] as $issue) { if ($issue->type !== $issue_type || $issue->from !== $file_offset) { $filtered_issues[] = $issue; } } if (empty($filtered_issues)) { unset(self::$issues_data[$file_path]); } else { self::$issues_data[$file_path] = $filtered_issues; } } public static function addFixableIssue(string $issue_type) : void { if (isset(self::$fixable_issue_counts[$issue_type])) { self::$fixable_issue_counts[$issue_type]++; } else { self::$fixable_issue_counts[$issue_type] = 1; } } /** * @return array> */ public static function getIssuesData() : array { return self::$issues_data; } /** * @return list */ public static function getIssuesDataForFile(string $file_path) : array { return self::$issues_data[$file_path] ?? []; } /** * @return array */ public static function getFixableIssues() : array { return self::$fixable_issue_counts; } /** * @param array $fixable_issue_counts */ public static function addFixableIssues(array $fixable_issue_counts) : void { foreach ($fixable_issue_counts as $issue_type => $count) { if (isset(self::$fixable_issue_counts[$issue_type])) { self::$fixable_issue_counts[$issue_type] += $count; } else { self::$fixable_issue_counts[$issue_type] = $count; } } } /** * @return array> */ public static function getUnusedSuppressions() : array { return self::$unused_suppressions; } /** * @return array> */ public static function getUsedSuppressions() : array { return self::$used_suppressions; } /** * @param array> $unused_suppressions */ public static function addUnusedSuppressions(array $unused_suppressions) : void { self::$unused_suppressions += $unused_suppressions; } /** * @param array> $used_suppressions */ public static function addUsedSuppressions(array $used_suppressions) : void { foreach ($used_suppressions as $file => $offsets) { if (!isset(self::$used_suppressions[$file])) { self::$used_suppressions[$file] = $offsets; } else { self::$used_suppressions[$file] += $offsets; } } } public static function processUnusedSuppressions(FileProvider $file_provider) : void { $config = \Psalm\Config::getInstance(); foreach (self::$unused_suppressions as $file_path => $offsets) { if (!$offsets) { continue; } if (!$config->isInProjectDirs($file_path)) { continue; } $file_contents = $file_provider->getContents($file_path); foreach ($offsets as $start => $end) { if (isset(self::$used_suppressions[$file_path][$start])) { continue; } self::add(new UnusedPsalmSuppress('This suppression is never used', new Raw($file_contents, $file_path, $config->shortenFileName($file_path), $start, $end))); } } } public static function getErrorCount() : int { return self::$error_count; } /** * @param array> $issues_data */ public static function addIssues(array $issues_data) : void { foreach ($issues_data as $file_path => $file_issues) { foreach ($file_issues as $issue) { $emitted_key = $issue->type . '-' . $issue->file_name . ':' . $issue->line_from . ':' . $issue->column_from . ' ' . ($issue->dupe_key ?? $issue->message); if (!self::alreadyEmitted($emitted_key)) { self::$issues_data[$file_path][] = $issue; } } } } /** * @param array}>> $issue_baseline */ public static function finish(ProjectAnalyzer $project_analyzer, bool $is_full, float $start_time, bool $add_stats = \false, array $issue_baseline = []) : void { if (!$project_analyzer->stdout_report_options) { throw new UnexpectedValueException('Cannot finish without stdout report options'); } $codebase = $project_analyzer->getCodebase(); foreach ($codebase->config->config_issues as $issue) { self::maybeAdd($issue); } $error_count = 0; $info_count = 0; $issues_data = []; if (self::$issues_data) { if (in_array($project_analyzer->stdout_report_options->format, [\Psalm\Report::TYPE_CONSOLE, \Psalm\Report::TYPE_PHP_STORM])) { echo "\n"; } ksort(self::$issues_data); foreach (self::$issues_data as $file_path => $file_issues) { usort($file_issues, static fn(IssueData $d1, IssueData $d2): int => [$d1->file_path, $d1->line_from, $d1->column_from] <=> [$d2->file_path, $d2->line_from, $d2->column_from]); self::$issues_data[$file_path] = $file_issues; } // make a copy so what gets saved in cache is unaffected by baseline $issues_data = self::$issues_data; } if (!empty($issue_baseline)) { // Set severity for issues in baseline to INFO foreach ($issues_data as $file_path => $file_issues) { foreach ($file_issues as $key => $issue_data) { $file = $issue_data->file_name; $file = str_replace('\\', '/', $file); $type = $issue_data->type; if (isset($issue_baseline[$file][$type]) && $issue_baseline[$file][$type]['o'] > 0) { if ($issue_baseline[$file][$type]['o'] === count($issue_baseline[$file][$type]['s'])) { $position = array_search(str_replace("\r\n", "\n", trim($issue_data->selected_text)), $issue_baseline[$file][$type]['s'], \true); if ($position !== \false) { $issue_data->severity = IssueData::SEVERITY_INFO; array_splice($issue_baseline[$file][$type]['s'], $position, 1); $issue_baseline[$file][$type]['o']--; } } else { $issue_baseline[$file][$type]['s'] = []; $issue_data->severity = IssueData::SEVERITY_INFO; $issue_baseline[$file][$type]['o']--; } } $issues_data[$file_path][$key] = $issue_data; } } if ($codebase->config->find_unused_baseline_entry) { foreach ($issue_baseline as $file_path => $issues) { foreach ($issues as $issue_name => $issue) { if ($issue['o'] !== 0) { $issues_data[$file_path][] = new IssueData(IssueData::SEVERITY_ERROR, 0, 0, UnusedBaselineEntry::getIssueType(), sprintf('Baseline for issue "%s" has %d extra %s.', $issue_name, $issue['o'], $issue['o'] === 1 ? 'entry' : 'entries'), $file_path, '', '', '', 0, 0, 0, 0, 0, 0, UnusedBaselineEntry::SHORTCODE, UnusedBaselineEntry::ERROR_LEVEL); } } } } } echo self::getOutput($issues_data, $project_analyzer->stdout_report_options, $codebase->analyzer->getTotalTypeCoverage($codebase)); foreach ($issues_data as $file_issues) { foreach ($file_issues as $issue_data) { if ($issue_data->severity === \Psalm\Config::REPORT_ERROR) { ++$error_count; } else { ++$info_count; } } } if ($codebase->config->eventDispatcher->after_analysis) { $source_control_info = null; $build_info = (new BuildInfoCollector(self::$server))->collect(); try { $source_control_info = (new GitInfoCollector())->collect(); } catch (RuntimeException $e) { // do nothing } /** @psalm-suppress ArgumentTypeCoercion due to Psalm bug */ $event = new AfterAnalysisEvent($codebase, $issues_data, $build_info, $source_control_info); $codebase->config->eventDispatcher->dispatchAfterAnalysis($event); } foreach ($project_analyzer->generated_report_options as $report_options) { if (!$report_options->output_path) { throw new UnexpectedValueException('Output path should not be null here'); } $folder = dirname($report_options->output_path); if (!is_dir($folder) && !mkdir($folder, 0777, \true) && !is_dir($folder)) { throw new RuntimeException(sprintf('Directory "%s" was not created', $folder)); } file_put_contents($report_options->output_path, self::getOutput($issues_data, $report_options, $codebase->analyzer->getTotalTypeCoverage($codebase))); } if (in_array($project_analyzer->stdout_report_options->format, [\Psalm\Report::TYPE_CONSOLE, \Psalm\Report::TYPE_PHP_STORM, \Psalm\Report::TYPE_GITHUB_ACTIONS])) { echo str_repeat('-', 30) . "\n"; if ($error_count) { echo ($project_analyzer->stdout_report_options->use_color ? "\x1b[0;31m" . $error_count . " errors\x1b[0m" : $error_count . ' errors') . ' found' . "\n"; } else { self::printSuccessMessage($project_analyzer); } $show_info = $project_analyzer->stdout_report_options->show_info; $show_suggestions = $project_analyzer->stdout_report_options->show_suggestions; if ($info_count && ($show_info || $show_suggestions)) { echo str_repeat('-', 30) . "\n"; echo $info_count . ' other issues found.' . "\n"; if (!$show_info) { echo 'You can display them with ' . ($project_analyzer->stdout_report_options->use_color ? "\x1b[30;48;5;195m--show-info=true\x1b[0m" : '--show-info=true') . "\n"; } } if (self::$fixable_issue_counts && $show_suggestions && !$codebase->taint_flow_graph) { echo str_repeat('-', 30) . "\n"; $total_count = array_sum(self::$fixable_issue_counts); $command = '--alter --issues=' . implode(',', array_keys(self::$fixable_issue_counts)); $command .= ' --dry-run'; echo 'Psalm can automatically fix ' . $total_count . ($show_info ? ' issues' : ' of these issues') . ".\n" . 'Run Psalm again with ' . "\n" . ($project_analyzer->stdout_report_options->use_color ? "\x1b[30;48;5;195m" . $command . "\x1b[0m" : $command) . "\n" . 'to see what it can fix.' . "\n"; } echo str_repeat('-', 30) . "\n" . "\n"; if ($start_time) { echo 'Checks took ' . number_format(microtime(\true) - $start_time, 2) . ' seconds'; echo ' and used ' . number_format(memory_get_peak_usage() / (1024 * 1024), 3) . 'MB of memory' . "\n"; $analysis_summary = $codebase->analyzer->getTypeInferenceSummary($codebase); echo $analysis_summary . "\n"; if ($add_stats) { echo '-----------------' . "\n"; echo $codebase->analyzer->getNonMixedStats(); echo "\n"; } if ($project_analyzer->debug_performance) { echo '-----------------' . "\n"; echo 'Slow-to-analyze functions' . "\n"; echo '-----------------' . "\n\n"; $function_timings = $codebase->analyzer->getFunctionTimings(); arsort($function_timings); $i = 0; foreach ($function_timings as $function_id => $time) { if (++$i > 10) { break; } echo $function_id . ': ' . round(1000 * $time, 2) . 'ms per node' . "\n"; } echo "\n"; } } } if ($is_full && $start_time) { $project_analyzer->finish($start_time, PSALM_VERSION); } if ($error_count && !($codebase->taint_flow_graph && $project_analyzer->generated_report_options && isset($_SERVER['GITHUB_WORKFLOW']))) { exit(2); } } public static function printSuccessMessage(ProjectAnalyzer $project_analyzer) : void { if (!$project_analyzer->stdout_report_options) { throw new UnexpectedValueException('Cannot print success message without stdout report options'); } // this message will be printed $message = "No errors found!"; // color block will contain this amount of characters $blockSize = 30; // message with prepended and appended whitespace to be same as $blockSize $messageWithPadding = str_repeat(' ', 7) . $message . str_repeat(' ', 7); // top side of the color block $paddingTop = str_repeat(' ', $blockSize); // bottom side of the color block $paddingBottom = str_repeat(' ', $blockSize); // background color, 42 = green $background = "42"; // foreground/text color, 30 = black $foreground = "30"; // text style, 1 = bold $style = "2"; if ($project_analyzer->stdout_report_options->use_color) { echo "\x1b[{$background};{$style}m{$paddingTop}\x1b[0m" . "\n"; echo "\x1b[{$background};{$foreground};{$style}m{$messageWithPadding}\x1b[0m" . "\n"; echo "\x1b[{$background};{$style}m{$paddingBottom}\x1b[0m" . "\n"; } else { echo "\n"; echo "{$messageWithPadding}\n"; echo "\n"; } } /** * @param array> $issues_data * @param array{int, int} $mixed_counts */ public static function getOutput(array $issues_data, ReportOptions $report_options, array $mixed_counts = [0, 0]) : string { $total_expression_count = $mixed_counts[0] + $mixed_counts[1]; $mixed_expression_count = $mixed_counts[0]; $normalized_data = $issues_data === [] ? [] : array_merge(...array_values($issues_data)); $format = $report_options->format; switch ($format) { case \Psalm\Report::TYPE_COMPACT: $output = new CompactReport($normalized_data, self::$fixable_issue_counts, $report_options); break; case \Psalm\Report::TYPE_EMACS: $output = new EmacsReport($normalized_data, self::$fixable_issue_counts, $report_options); break; case \Psalm\Report::TYPE_TEXT: $output = new TextReport($normalized_data, self::$fixable_issue_counts, $report_options); break; case \Psalm\Report::TYPE_JSON: $output = new JsonReport($normalized_data, self::$fixable_issue_counts, $report_options); break; case \Psalm\Report::TYPE_BY_ISSUE_LEVEL: $output = new ByIssueLevelAndTypeReport($normalized_data, self::$fixable_issue_counts, $report_options); break; case \Psalm\Report::TYPE_JSON_SUMMARY: $output = new JsonSummaryReport($normalized_data, self::$fixable_issue_counts, $report_options, $mixed_expression_count, $total_expression_count); break; case \Psalm\Report::TYPE_SONARQUBE: $output = new SonarqubeReport($normalized_data, self::$fixable_issue_counts, $report_options); break; case \Psalm\Report::TYPE_PYLINT: $output = new PylintReport($normalized_data, self::$fixable_issue_counts, $report_options); break; case \Psalm\Report::TYPE_CHECKSTYLE: $output = new CheckstyleReport($normalized_data, self::$fixable_issue_counts, $report_options); break; case \Psalm\Report::TYPE_XML: $output = new XmlReport($normalized_data, self::$fixable_issue_counts, $report_options); break; case \Psalm\Report::TYPE_JUNIT: $output = new JunitReport($normalized_data, self::$fixable_issue_counts, $report_options); break; case \Psalm\Report::TYPE_CONSOLE: $output = new ConsoleReport($normalized_data, self::$fixable_issue_counts, $report_options); break; case \Psalm\Report::TYPE_GITHUB_ACTIONS: $output = new GithubActionsReport($normalized_data, self::$fixable_issue_counts, $report_options); break; case \Psalm\Report::TYPE_PHP_STORM: $output = new PhpStormReport($normalized_data, self::$fixable_issue_counts, $report_options); break; case \Psalm\Report::TYPE_SARIF: $output = new SarifReport($normalized_data, self::$fixable_issue_counts, $report_options); break; case \Psalm\Report::TYPE_CODECLIMATE: $output = new CodeClimateReport($normalized_data, self::$fixable_issue_counts, $report_options); break; case \Psalm\Report::TYPE_COUNT: $output = new CountReport($normalized_data, self::$fixable_issue_counts, $report_options); break; default: throw new RuntimeException('Unexpected report format: ' . $report_options->format); } return $output->create(); } protected static function alreadyEmitted(string $message) : bool { $sham = sha1($message); if (isset(self::$emitted[$sham])) { return \true; } self::$emitted[$sham] = \true; return \false; } public static function clearCache() : void { self::$issues_data = []; self::$emitted = []; self::$error_count = 0; self::$recording_level = 0; self::$recorded_issues = []; self::$console_issues = []; self::$unused_suppressions = []; self::$used_suppressions = []; } /** * @return array> */ public static function clear() : array { $current_data = self::$issues_data; self::$issues_data = []; self::$emitted = []; return $current_data; } /** * Return whether or not we're in a recording state regarding startRecording/stopRecording status */ public static function isRecording() : bool { return self::$recording_level > 0; } /** * Increase the recording level in order to start recording issues instead of adding them while in a loop */ public static function startRecording() : void { ++self::$recording_level; self::$recorded_issues[self::$recording_level] = []; } /** * Decrease the recording level after leaving a loop * * @see startRecording */ public static function stopRecording() : void { if (self::$recording_level === 0) { throw new UnexpectedValueException('Cannot stop recording - already at base level'); } --self::$recording_level; } /** * This will return the recorded issues for the current recording level * * @return array */ public static function clearRecordingLevel() : array { if (self::$recording_level === 0) { throw new UnexpectedValueException('Not currently recording'); } $recorded_issues = self::$recorded_issues[self::$recording_level]; self::$recorded_issues[self::$recording_level] = []; return $recorded_issues; } /** * This will try to add issues that has been retrieved through clearRecordingLevel or record them at a lower level */ public static function bubbleUp(CodeIssue $e) : void { if (self::$recording_level === 0) { self::add($e); return; } self::$recorded_issues[self::$recording_level][] = $e; } /** * @internal * @param array $server */ public static final function captureServer(array $server) : void { self::$server = $server; } } */ public function getAliasedClassesFlipped() : array; /** * @return array */ public function getAliasedClassesFlippedReplaceable() : array; public function getFQCLN() : ?string; public function getClassName() : ?string; public function getParentFQCLN() : ?string; /** * @return array>|null */ public function getTemplateTypeMap() : ?array; public function setRootFilePath(string $file_path, string $file_name) : void; public function hasParentFilePath(string $file_path) : bool; public function hasAlreadyRequiredFilePath(string $file_path) : bool; public function getRequireNesting() : int; public function isStatic() : bool; public function getSource() : \Psalm\StatementsSource; public function getCodebase() : \Psalm\Codebase; /** * Get a list of suppressed issues * * @return array */ public function getSuppressedIssues() : array; /** * @param list $new_issues */ public function addSuppressedIssues(array $new_issues) : void; /** * @param list $new_issues */ public function removeSuppressedIssues(array $new_issues) : void; public function getNodeTypeProvider() : \Psalm\NodeTypeProvider; } }>> $existingIssues * @psalm-pure */ public static function countTotalIssues(array $existingIssues) : int { $totalIssues = 0; foreach ($existingIssues as $existingIssue) { $totalIssues += array_reduce( $existingIssue, /** * @param array{o:int, s:array} $existingIssue */ static fn(int $carry, array $existingIssue): int => $carry + $existingIssue['o'], 0 ); } return $totalIssues; } /** * @param array> $issues */ public static function create(FileProvider $fileProvider, string $baselineFile, array $issues, bool $include_php_versions) : void { $groupedIssues = self::countIssueTypesByFile($issues); self::writeToFile($fileProvider, $baselineFile, $groupedIssues, $include_php_versions); } /** * @return array}>> * @throws ConfigException */ public static function read(FileProvider $fileProvider, string $baselineFile) : array { if (!$fileProvider->fileExists($baselineFile)) { throw new ConfigException("{$baselineFile} does not exist or is not readable"); } $xmlSource = $fileProvider->getContents($baselineFile); if ($xmlSource === '') { throw new ConfigException('Baseline file is empty'); } $baselineDoc = new DOMDocument(); $baselineDoc->loadXML($xmlSource, LIBXML_NOBLANKS); $filesElement = $baselineDoc->getElementsByTagName('files'); if ($filesElement->length === 0) { throw new ConfigException('Baseline file does not contain '); } $files = []; /** @var DOMElement $filesElement */ $filesElement = $filesElement[0]; foreach ($filesElement->getElementsByTagName('file') as $file) { $fileName = $file->getAttribute('src'); $fileName = str_replace('\\', '/', $fileName); $files[$fileName] = []; foreach ($file->childNodes as $issue) { if (!$issue instanceof DOMElement) { continue; } $issueType = $issue->tagName; $files[$fileName][$issueType] = ['o' => 0, 's' => []]; $codeSamples = $issue->getElementsByTagName('code'); foreach ($codeSamples as $codeSample) { $files[$fileName][$issueType]['o'] += 1; $files[$fileName][$issueType]['s'][] = str_replace("\r\n", "\n", trim($codeSample->textContent)); } // TODO: Remove in Psalm 6 $occurrencesAttr = $issue->getAttribute('occurrences'); if ($occurrencesAttr !== '') { $files[$fileName][$issueType]['o'] = (int) $occurrencesAttr; } } } return $files; } /** * @param array> $issues * @return array}>> * @throws ConfigException */ public static function update(FileProvider $fileProvider, string $baselineFile, array $issues, bool $include_php_versions) : array { $existingIssues = self::read($fileProvider, $baselineFile); $newIssues = self::countIssueTypesByFile($issues); foreach ($existingIssues as $file => &$existingIssuesCount) { if (!isset($newIssues[$file])) { unset($existingIssues[$file]); continue; } foreach ($existingIssuesCount as $issueType => $existingIssueType) { if (!isset($newIssues[$file][$issueType])) { unset($existingIssuesCount[$issueType]); continue; } $existingIssuesCount[$issueType]['o'] = min($existingIssueType['o'], $newIssues[$file][$issueType]['o']); $existingIssuesCount[$issueType]['s'] = array_intersect($existingIssueType['s'], $newIssues[$file][$issueType]['s']); } } $groupedIssues = array_filter($existingIssues); self::writeToFile($fileProvider, $baselineFile, $groupedIssues, $include_php_versions); return $groupedIssues; } /** * @param array> $issues * @return array}>> */ private static function countIssueTypesByFile(array $issues) : array { if ($issues === []) { return []; } $groupedIssues = array_reduce( array_merge(...array_values($issues)), /** * @param array}>> $carry * @return array}>> */ static function (array $carry, IssueData $issue) : array { if ($issue->severity !== \Psalm\Config::REPORT_ERROR) { return $carry; } $fileName = $issue->file_name; $fileName = str_replace('\\', '/', $fileName); $issueType = $issue->type; if (!isset($carry[$fileName])) { $carry[$fileName] = []; } if (!isset($carry[$fileName][$issueType])) { $carry[$fileName][$issueType] = ['o' => 0, 's' => []]; } ++$carry[$fileName][$issueType]['o']; $carry[$fileName][$issueType]['s'][] = $issue->selected_text; return $carry; }, [] ); // Sort files first ksort($groupedIssues); foreach ($groupedIssues as &$issues) { ksort($issues); } unset($issues); return $groupedIssues; } /** * @param array}>> $groupedIssues */ private static function writeToFile(FileProvider $fileProvider, string $baselineFile, array $groupedIssues, bool $include_php_versions) : void { $baselineDoc = new DOMDocument('1.0', 'UTF-8'); $filesNode = $baselineDoc->createElement('files'); $filesNode->setAttribute('psalm-version', \PSALM_VERSION); if ($include_php_versions) { $extensions = [...get_loaded_extensions(), ...get_loaded_extensions(\true)]; usort($extensions, 'strnatcasecmp'); $filesNode->setAttribute('php-version', implode(';' . "\n\t", [...['php:' . PHP_VERSION], ...array_map(static fn(string $extension): string => $extension . ':' . phpversion($extension), $extensions)])); } foreach ($groupedIssues as $file => $issueTypes) { $fileNode = $baselineDoc->createElement('file'); $fileNode->setAttribute('src', $file); foreach ($issueTypes as $issueType => $existingIssueType) { $issueNode = $baselineDoc->createElement($issueType); sort($existingIssueType['s']); foreach ($existingIssueType['s'] as $selection) { $codeNode = $baselineDoc->createElement('code'); $textContent = trim($selection); $codeNode->appendChild($baselineDoc->createCDATASection($textContent)); $issueNode->appendChild($codeNode); } $fileNode->appendChild($issueNode); } $filesNode->appendChild($fileNode); } $baselineDoc->appendChild($filesNode); $baselineDoc->formatOutput = \true; $xml = preg_replace_callback( '/)\\n/', /** * @param string[] $matches */ static fn(array $matches): string => sprintf("saveXML() ); if ($xml === null) { throw new RuntimeException('Failed to reformat opening attributes!'); } $fileProvider->setContents($baselineFile, $xml); } } 'file_path', 'file_name' => 'file_name', 'raw_line_number' => 'raw_line_number', "\x00" . self::class . "\x00" . 'end_line_number' => 'end_line_number', 'raw_file_start' => 'raw_file_start', 'raw_file_end' => 'raw_file_end', "\x00*\x00" . 'file_start' => 'file_start', "\x00*\x00" . 'file_end' => 'file_end', "\x00*\x00" . 'single_line' => 'single_line', "\x00*\x00" . 'preview_start' => 'preview_start', "\x00" . self::class . "\x00" . 'preview_end' => 'preview_end', "\x00" . self::class . "\x00" . 'selection_start' => 'selection_start', "\x00" . self::class . "\x00" . 'selection_end' => 'selection_end', "\x00" . self::class . "\x00" . 'column_from' => 'column_from', "\x00" . self::class . "\x00" . 'column_to' => 'column_to', "\x00" . self::class . "\x00" . 'snippet' => 'snippet', "\x00" . self::class . "\x00" . 'text' => 'text', 'docblock_start' => 'docblock_start', "\x00" . self::class . "\x00" . 'docblock_start_line_number' => 'docblock_start_line_number', "\x00*\x00" . 'docblock_line_number' => 'docblock_line_number', "\x00" . self::class . "\x00" . 'regex_type' => 'regex_type', "\x00" . self::class . "\x00" . 'have_recalculated' => 'have_recalculated', 'previous_location' => 'previous_location']; public function __construct(\Psalm\FileSource $file_source, PhpParser\Node $stmt, ?\Psalm\CodeLocation $previous_location = null, bool $single_line = \false, ?int $regex_type = null, ?string $selected_text = null, ?int $comment_line = null) { /** @psalm-suppress ImpureMethodCall Actually mutation-free just not marked */ $this->file_start = (int) $stmt->getAttribute('startFilePos'); /** @psalm-suppress ImpureMethodCall Actually mutation-free just not marked */ $this->file_end = (int) $stmt->getAttribute('endFilePos'); $this->raw_file_start = $this->file_start; $this->raw_file_end = $this->file_end; $this->file_path = $file_source->getFilePath(); $this->file_name = $file_source->getFileName(); $this->single_line = $single_line; $this->regex_type = $regex_type; $this->previous_location = $previous_location; $this->text = $selected_text; /** @psalm-suppress ImpureMethodCall Actually mutation-free just not marked */ $doc_comment = $stmt->getDocComment(); $this->docblock_start = $doc_comment ? $doc_comment->getStartFilePos() : null; $this->docblock_start_line_number = $doc_comment ? $doc_comment->getStartLine() : null; $this->preview_start = $this->docblock_start ?: $this->file_start; /** @psalm-suppress ImpureMethodCall Actually mutation-free just not marked */ $this->raw_line_number = $stmt->getStartLine(); $this->docblock_line_number = $comment_line; } /** * Suppresses memory usage when unserializing objects. * * @see \Psalm\Storage\UnserializeMemoryUsageSuppressionTrait */ public function __unserialize(array $properties) : void { foreach (self::PROPERTY_KEYS_FOR_UNSERIALIZE as $key => $property_name) { /** @psalm-suppress PossiblyUndefinedStringArrayOffset */ $this->{$property_name} = $properties[$key]; } } /** * @psalm-suppress PossiblyUnusedMethod Part of public API * @return static */ public function setCommentLine(?int $line) : self { if ($line === $this->docblock_line_number) { return $this; } $cloned = clone $this; $cloned->docblock_line_number = $line; return $cloned; } /** * @psalm-external-mutation-free * @psalm-suppress InaccessibleProperty Mainly used for caching */ private function calculateRealLocation() : void { if ($this->have_recalculated) { return; } $this->have_recalculated = \true; $this->selection_start = $this->file_start; $this->selection_end = $this->file_end + 1; $project_analyzer = ProjectAnalyzer::getInstance(); $codebase = $project_analyzer->getCodebase(); /** @psalm-suppress ImpureMethodCall */ $file_contents = $codebase->getFileContents($this->file_path); $file_length = strlen($file_contents); $search_limit = $this->single_line ? $this->selection_start : $this->selection_end; if ($search_limit <= $file_length) { $preview_end = strpos($file_contents, "\n", $search_limit); } else { $preview_end = \false; } // if the string didn't contain a newline if ($preview_end === \false) { $preview_end = $this->selection_end; } $this->preview_end = $preview_end; if ($this->docblock_line_number && $this->docblock_start_line_number && $this->preview_start < $this->selection_start) { $preview_lines = explode("\n", mb_strcut($file_contents, $this->preview_start, $this->selection_start - $this->preview_start - 1)); $preview_offset = 0; $comment_line_offset = $this->docblock_line_number - $this->docblock_start_line_number; for ($i = 0; $i < $comment_line_offset; ++$i) { $preview_offset += strlen($preview_lines[$i]) + 1; } if (!isset($preview_lines[$i])) { throw new Exception('Should have offset'); } $key_line = $preview_lines[$i]; $indentation = (int) strpos($key_line, '@'); $key_line = trim(preg_replace('@\\**/\\s*@', '', mb_strcut($key_line, $indentation))); $this->selection_start = $preview_offset + $indentation + $this->preview_start; $this->selection_end = $this->selection_start + strlen($key_line); } if ($this->regex_type !== null) { switch ($this->regex_type) { case self::VAR_TYPE: $regex = '/@(?:psalm-)?var[ \\t]+' . CommentAnalyzer::TYPE_REGEX . '/'; break; case self::FUNCTION_RETURN_TYPE: $regex = '/\\:\\s+(\\??\\s*[A-Za-z0-9_\\\\\\[\\]]+)/'; break; case self::FUNCTION_PARAM_TYPE: $regex = '/^(\\??\\s*[A-Za-z0-9_\\\\\\[\\]]+)\\s/'; break; case self::FUNCTION_PHPDOC_RETURN_TYPE: $regex = '/@(?:psalm-)?return[ \\t]+' . CommentAnalyzer::TYPE_REGEX . '/'; break; case self::FUNCTION_PHPDOC_METHOD: $regex = '/@(?:psalm-)?method[ \\t]+(.*)/'; break; case self::FUNCTION_PHPDOC_PARAM_TYPE: $regex = '/@(?:psalm-)?param[ \\t]+' . CommentAnalyzer::TYPE_REGEX . '/'; break; case self::FUNCTION_PARAM_VAR: $regex = '/(\\$[^ ]*)/'; break; case self::CATCH_VAR: $regex = '/(\\$[^ ^\\)]*)/'; break; default: throw new UnexpectedValueException('Unrecognised regex type ' . $this->regex_type); } $preview_snippet = mb_strcut($file_contents, $this->selection_start, $this->selection_end - $this->selection_start); if ($this->text) { $regex = '/(' . str_replace(',', ',[ ]*', preg_quote($this->text, '/')) . ')/'; } if (preg_match($regex, $preview_snippet, $matches, PREG_OFFSET_CAPTURE)) { if (!isset($matches[1]) || $matches[1][1] === -1) { throw new LogicException("Failed to match anything to 1st capturing group, " . "or regex doesn't contain 1st capturing group, regex type " . $this->regex_type); } $this->selection_start = $this->selection_start + $matches[1][1]; $this->selection_end = $this->selection_start + strlen($matches[1][0]); } } // reset preview start to beginning of line $this->preview_start = (int) strrpos($file_contents, "\n", min($this->preview_start, $this->selection_start) - strlen($file_contents)) + 1; $this->selection_start = max($this->preview_start, $this->selection_start); $this->selection_end = min($this->preview_end, $this->selection_end); if ($this->preview_end - $this->selection_end > 200) { $this->preview_end = (int) strrpos($file_contents, "\n", $this->selection_end + 200 - strlen($file_contents)); // if the line is over 200 characters long if ($this->preview_end < $this->selection_end) { $this->preview_end = $this->selection_end + 50; } } $this->snippet = mb_strcut($file_contents, $this->preview_start, $this->preview_end - $this->preview_start); // text is within snippet. It's 50% faster to cut it from the snippet than from the full text $selection_length = $this->selection_end - $this->selection_start; $this->text = mb_strcut($this->snippet, $this->selection_start - $this->preview_start, $selection_length); // reset preview start to beginning of line if ($file_contents !== '') { $this->column_from = $this->selection_start - (int) strrpos($file_contents, "\n", $this->selection_start - strlen($file_contents)); } else { $this->column_from = $this->selection_start; } $newlines = substr_count($this->text, "\n"); if ($newlines) { $last_newline_pos = strrpos($file_contents, "\n", $this->selection_end - strlen($file_contents) - 1); $this->column_to = $this->selection_end - (int) $last_newline_pos; } else { $this->column_to = $this->column_from + strlen($this->text); } $this->end_line_number = $this->getLineNumber() + $newlines; } public function getLineNumber() : int { return $this->docblock_line_number ?: $this->raw_line_number; } public function getEndLineNumber() : int { $this->calculateRealLocation(); return $this->end_line_number; } public function getSnippet() : string { $this->calculateRealLocation(); return $this->snippet; } public function getSelectedText() : string { $this->calculateRealLocation(); return (string) $this->text; } public function getColumn() : int { $this->calculateRealLocation(); return $this->column_from; } public function getEndColumn() : int { $this->calculateRealLocation(); return $this->column_to; } /** * @return array{0: int, 1: int} */ public function getSelectionBounds() : array { $this->calculateRealLocation(); return [$this->selection_start, $this->selection_end]; } /** * @return array{0: int, 1: int} */ public function getSnippetBounds() : array { $this->calculateRealLocation(); return [$this->preview_start, $this->preview_end]; } public function getHash() : string { return $this->file_name . ' ' . $this->raw_file_start . $this->raw_file_end; } public function getShortSummary() : string { return $this->file_name . ':' . $this->getLineNumber() . ':' . $this->getColumn(); } } issues_data as $issue_data) { $output .= sprintf('%s:%s:%s:%s - %s: %s (see %s)', $issue_data->file_path, $issue_data->line_from, $issue_data->column_from, $issue_data->severity === IssueData::SEVERITY_ERROR ? 'error' : 'warning', $issue_data->type, $issue_data->message, $issue_data->link) . "\n"; } return $output; } } issues_data as $issue_data) { if (array_key_exists($issue_data->type, $issue_type_counts)) { $issue_type_counts[$issue_data->type]++; } else { $issue_type_counts[$issue_data->type] = 1; } } uksort($issue_type_counts, static function (string $a, string $b) use($issue_type_counts) : int { $cmp_result = $issue_type_counts[$a] <=> $issue_type_counts[$b]; if ($cmp_result === 0) { return $a <=> $b; } else { return $cmp_result; } }); $output = ''; foreach ($issue_type_counts as $issue_type => $count) { $output .= "{$issue_type}: {$count}\n"; } return $output; } } sortIssuesByLevelAndType(); $output = <<